diff --git a/examples/pikapython/.gitignore b/examples/pikapython/.gitignore new file mode 100644 index 00000000..18ebb0f1 --- /dev/null +++ b/examples/pikapython/.gitignore @@ -0,0 +1 @@ +**/pikascript-api diff --git a/examples/pikapython/CMakeLists.txt b/examples/pikapython/CMakeLists.txt index 552eab3f..4d9d6f34 100644 --- a/examples/pikapython/CMakeLists.txt +++ b/examples/pikapython/CMakeLists.txt @@ -12,6 +12,16 @@ sdk_add_include_directories(.) sdk_add_include_directories(pikapython/pikascript-core) sdk_add_include_directories(pikapython/pikascript-api) +sdk_add_compile_definitions( + PIKA_CONFIG_ENABLE=1 + # LWIP_DNS=1 + LV_LVGL_H_INCLUDE_SIMPLE=1 + PIKASCRIPT=1 +) + sdk_set_main_file(main.c) +set(APP_LDFLAGS_HEAD "-Wl,--whole-archive") +set(APP_LDFLAGS_TAIL "-Wl,--no-whole-archive") + project(pikapython) diff --git a/examples/pikapython/FreeRTOSConfig.h b/examples/pikapython/FreeRTOSConfig.h new file mode 100755 index 00000000..24c39f26 --- /dev/null +++ b/examples/pikapython/FreeRTOSConfig.h @@ -0,0 +1,125 @@ +/* + * FreeRTOS Kernel V10.2.1 + * Copyright (C) 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * 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. + * + * http://www.FreeRTOS.org + * http://aws.amazon.com/freertos + * + * 1 tab == 4 spaces! + */ +#ifndef FREERTOS_CONFIG_H +#define FREERTOS_CONFIG_H +/*----------------------------------------------------------- + * Application specific definitions. + * + * These definitions should be adjusted for your particular hardware and + * application requirements. + * + * THESE PARAMETERS ARE DESCRIBED WITHIN THE 'CONFIGURATION' SECTION OF THE + * FreeRTOS API DOCUMENTATION AVAILABLE ON THE FreeRTOS.org WEB SITE. + * + * See http://www.freertos.org/a00110.html. + *----------------------------------------------------------*/ +#if defined(BL602) || defined(BL702) || defined(BL702L) +#define configMTIME_BASE_ADDRESS (0x02000000UL + 0xBFF8UL) +#define configMTIMECMP_BASE_ADDRESS (0x02000000UL + 0x4000UL) +#else +#if __riscv_xlen == 64 +#define configMTIME_BASE_ADDRESS (0) +#define configMTIMECMP_BASE_ADDRESS ((0xE4000000UL) + 0x4000UL) +#else +#define configMTIME_BASE_ADDRESS ((0xE0000000UL) + 0xBFF8UL) +#define configMTIMECMP_BASE_ADDRESS ((0xE0000000UL) + 0x4000UL) +#endif +#endif +#define configSUPPORT_STATIC_ALLOCATION 1 +#define configUSE_PREEMPTION 1 +#define configUSE_IDLE_HOOK 0 +#define configUSE_TICK_HOOK 0 +#define configCPU_CLOCK_HZ ((uint32_t)(1 * 1000 * 1000)) +#define configTICK_RATE_HZ (1000) +#define configMAX_PRIORITIES (7) +#define configMINIMAL_STACK_SIZE ((unsigned short)128) /* Only needs to be this high as some demo tasks also use this constant. In production only the idle task would use this. */ +#define configTOTAL_HEAP_SIZE ((size_t)128 * 1024) +#define configMAX_TASK_NAME_LEN (16) +#define configUSE_TRACE_FACILITY 1 +#define configUSE_STATS_FORMATTING_FUNCTIONS 1 +#define configUSE_16_BIT_TICKS 0 +#define configIDLE_SHOULD_YIELD 0 +#define configUSE_MUTEXES 1 +#define configQUEUE_REGISTRY_SIZE 8 +#define configCHECK_FOR_STACK_OVERFLOW 2 +#define configUSE_RECURSIVE_MUTEXES 1 +#define configUSE_MALLOC_FAILED_HOOK 1 +#define configUSE_APPLICATION_TASK_TAG 1 +#define configUSE_COUNTING_SEMAPHORES 1 +#define configGENERATE_RUN_TIME_STATS 0 +#define configUSE_PORT_OPTIMISED_TASK_SELECTION 1 +#define configUSE_TICKLESS_IDLE 0 +#define configUSE_POSIX_ERRNO 1 + +/* Co-routine definitions. */ +#define configUSE_CO_ROUTINES 0 +#define configMAX_CO_ROUTINE_PRIORITIES (2) + +/* Software timer definitions. */ +#define configUSE_TIMERS 1 +#define configTIMER_TASK_PRIORITY (configMAX_PRIORITIES - 1) +#define configTIMER_QUEUE_LENGTH 4 +#define configTIMER_TASK_STACK_DEPTH (configMINIMAL_STACK_SIZE) +/* Task priorities. Allow these to be overridden. */ +#ifndef uartPRIMARY_PRIORITY +#define uartPRIMARY_PRIORITY (configMAX_PRIORITIES - 3) +#endif +/* Set the following definitions to 1 to include the API function, or zero +to exclude the API function. */ +#define INCLUDE_vTaskPrioritySet 1 +#define INCLUDE_uxTaskPriorityGet 1 +#define INCLUDE_vTaskDelete 1 +#define INCLUDE_vTaskCleanUpResources 1 +#define INCLUDE_vTaskSuspend 1 +#define INCLUDE_vTaskDelayUntil 1 +#define INCLUDE_vTaskDelay 1 +#define INCLUDE_eTaskGetState 1 +#define INCLUDE_xTimerPendFunctionCall 1 +#define INCLUDE_xTaskAbortDelay 1 +#define INCLUDE_xTaskGetHandle 1 +#define INCLUDE_xSemaphoreGetMutexHolder 1 +/* Normal assert() semantics without relying on the provision of an assert.h +header file. */ +void vApplicationMallocFailedHook(void); +void vAssertCalled(void); + +#include + +#define configASSERT(x) \ + if ((x) == 0) { \ + printf("file [%s]\r\n", __FILE__); \ + printf("func [%s]\r\n", __FUNCTION__); \ + printf("line [%d]\r\n", __LINE__); \ + printf("%s\r\n", (const char *)(#x)); \ + vAssertCalled(); \ + } +#if (configUSE_TICKLESS_IDLE != 0) +void vApplicationSleep(uint32_t xExpectedIdleTime); +#define portSUPPRESS_TICKS_AND_SLEEP(xExpectedIdleTime) vApplicationSleep(xExpectedIdleTime) +#endif +// #define portUSING_MPU_WRAPPERS +#endif /* FREERTOS_CONFIG_H */ \ No newline at end of file diff --git a/examples/pikapython/Makefile b/examples/pikapython/Makefile index b6fa1597..7bf391b2 100644 --- a/examples/pikapython/Makefile +++ b/examples/pikapython/Makefile @@ -3,8 +3,9 @@ BL_SDK_BASE ?= $(SDK_DEMO_PATH)/../.. export BL_SDK_BASE -CHIP ?= bl602 -BOARD ?= bl602dk +CHIP ?= bl808 +BOARD ?= bl808dk +CPU_ID ?=m0 CROSS_COMPILE ?= riscv64-unknown-elf- # add custom cmake definition diff --git a/examples/pikapython/lv_conf.h b/examples/pikapython/lv_conf.h new file mode 100755 index 00000000..98a6a127 --- /dev/null +++ b/examples/pikapython/lv_conf.h @@ -0,0 +1,780 @@ +/** + * @file lv_conf.h + * Configuration file for v8.2.0 + */ + +/* + * Copy this file as `lv_conf.h` + * 1. simply next to the `lvgl` folder + * 2. or any other places and + * - define `LV_CONF_INCLUDE_SIMPLE` + * - add the path as include path + */ + +/* clang-format off */ +#if 1 /*Set it to "1" to enable content*/ + +#ifndef LV_CONF_H +#define LV_CONF_H + +#include + +#include "lcd.h" + +/*==================== + COLOR SETTINGS + *====================*/ + +/*Color depth: 1 (1 byte per pixel), 8 (RGB332), 16 (RGB565), 32 (ARGB8888)*/ +#define LV_COLOR_DEPTH LCD_COLOR_DEPTH + +/*Swap the 2 bytes of RGB565 color. Useful if the display has an 8-bit interface (e.g. SPI)*/ +#define LV_COLOR_16_SWAP 0 + +/*Enable features to draw on transparent background. + *It's required if opa, and transform_* style properties are used. + *Can be also used if the UI is above another layer, e.g. an OSD menu or video player.*/ +#define LV_COLOR_SCREEN_TRANSP 1 + +/* Adjust color mix functions rounding. GPUs might calculate color mix (blending) differently. + * 0: round down, 64: round up from x.75, 128: round up from half, 192: round up from x.25, 254: round up */ +#define LV_COLOR_MIX_ROUND_OFS 0 + +/*Images pixels with this color will not be drawn if they are chroma keyed)*/ +#define LV_COLOR_CHROMA_KEY lv_color_hex(0x00ff00) /*pure green*/ + +/*========================= + MEMORY SETTINGS + *=========================*/ + +/*1: use custom malloc/free, 0: use the built-in `lv_mem_alloc()` and `lv_mem_free()`*/ +#define LV_MEM_CUSTOM 1 +#if LV_MEM_CUSTOM == 0 + /*Size of the memory available for `lv_mem_alloc()` in bytes (>= 2kB)*/ + #define LV_MEM_SIZE (48U * 1024U) /*[bytes]*/ + + /*Set an address for the memory pool instead of allocating it as a normal array. Can be in external SRAM too.*/ + #define LV_MEM_ADR 0 /*0: unused*/ + /*Instead of an address give a memory allocator that will be called to get a memory pool for LVGL. E.g. my_malloc*/ + #if LV_MEM_ADR == 0 + #undef LV_MEM_POOL_INCLUDE + #undef LV_MEM_POOL_ALLOC + #endif + +#else /*LV_MEM_CUSTOM*/ + #define LV_MEM_CUSTOM_INCLUDE /*Header for the dynamic memory function*/ + #define LV_MEM_CUSTOM_ALLOC malloc + #define LV_MEM_CUSTOM_FREE free + #define LV_MEM_CUSTOM_REALLOC realloc +#endif /*LV_MEM_CUSTOM*/ + +/*Number of the intermediate memory buffer used during rendering and other internal processing mechanisms. + *You will see an error log message if there wasn't enough buffers. */ +#define LV_MEM_BUF_MAX_NUM 16 + +/*Use the standard `memcpy` and `memset` instead of LVGL's own functions. (Might or might not be faster).*/ +#define LV_MEMCPY_MEMSET_STD 0 + +/*==================== + HAL SETTINGS + *====================*/ + +/*Default display refresh period. LVG will redraw changed areas with this period time*/ +#define LV_DISP_DEF_REFR_PERIOD 20 /*[ms]*/ + +/*Input device read period in milliseconds*/ +#define LV_INDEV_DEF_READ_PERIOD 20 /*[ms]*/ + +/*Use a custom tick source that tells the elapsed time in milliseconds. + *It removes the need to manually update the tick with `lv_tick_inc()`)*/ +#define LV_TICK_CUSTOM 1 +#if LV_TICK_CUSTOM + #define LV_TICK_CUSTOM_INCLUDE "bflb_mtimer.h" /*Header for the system time function*/ + #define LV_TICK_CUSTOM_SYS_TIME_EXPR ((uint32_t)bflb_mtimer_get_time_ms()) /*Expression evaluating to current system time in ms*/ +#endif /*LV_TICK_CUSTOM*/ + +/*Default Dot Per Inch. Used to initialize default sizes such as widgets sized, style paddings. + *(Not so important, you can adjust it to modify default sizes and spaces)*/ +#define LV_DPI_DEF 130 /*[px/inch]*/ + +/*======================= + * FEATURE CONFIGURATION + *=======================*/ + +/*------------- + * Drawing + *-----------*/ + +/*Enable complex draw engine. + *Required to draw shadow, gradient, rounded corners, circles, arc, skew lines, image transformations or any masks*/ +#define LV_DRAW_COMPLEX 1 +#if LV_DRAW_COMPLEX != 0 + + /*Allow buffering some shadow calculation. + *LV_SHADOW_CACHE_SIZE is the max. shadow size to buffer, where shadow size is `shadow_width + radius` + *Caching has LV_SHADOW_CACHE_SIZE^2 RAM cost*/ + #define LV_SHADOW_CACHE_SIZE 0 + + /* Set number of maximally cached circle data. + * The circumference of 1/4 circle are saved for anti-aliasing + * radius * 4 bytes are used per circle (the most often used radiuses are saved) + * 0: to disable caching */ + #define LV_CIRCLE_CACHE_SIZE 4 +#endif /*LV_DRAW_COMPLEX*/ + +/** + * "Simple layers" are used when a widget has `style_opa < 255` to buffer the widget into a layer + * and blend it as an image with the given opacity. + * Note that `bg_opa`, `text_opa` etc don't require buffering into layer) + * The widget can be buffered in smaller chunks to avoid using large buffers. + * + * - LV_LAYER_SIMPLE_BUF_SIZE: [bytes] the optimal target buffer size. LVGL will try to allocate it + * - LV_LAYER_SIMPLE_FALLBACK_BUF_SIZE: [bytes] used if `LV_LAYER_SIMPLE_BUF_SIZE` couldn't be allocated. + * + * Both buffer sizes are in bytes. + * "Transformed layers" (where transform_angle/zoom properties are used) use larger buffers + * and can't be drawn in chunks. So these settings affects only widgets with opacity. + */ +#define LV_LAYER_SIMPLE_BUF_SIZE (24 * 1024) +#define LV_LAYER_SIMPLE_FALLBACK_BUF_SIZE (3 * 1024) + +/*Default image cache size. Image caching keeps the images opened. + *If only the built-in image formats are used there is no real advantage of caching. (I.e. if no new image decoder is added) + *With complex image decoders (e.g. PNG or JPG) caching can save the continuous open/decode of images. + *However the opened images might consume additional RAM. + *0: to disable caching*/ +#define LV_IMG_CACHE_DEF_SIZE 0 + +/*Number of stops allowed per gradient. Increase this to allow more stops. + *This adds (sizeof(lv_color_t) + 1) bytes per additional stop*/ +#define LV_GRADIENT_MAX_STOPS 2 + +/*Default gradient buffer size. + *When LVGL calculates the gradient "maps" it can save them into a cache to avoid calculating them again. + *LV_GRAD_CACHE_DEF_SIZE sets the size of this cache in bytes. + *If the cache is too small the map will be allocated only while it's required for the drawing. + *0 mean no caching.*/ +#define LV_GRAD_CACHE_DEF_SIZE 0 + +/*Allow dithering the gradients (to achieve visual smooth color gradients on limited color depth display) + *LV_DITHER_GRADIENT implies allocating one or two more lines of the object's rendering surface + *The increase in memory consumption is (32 bits * object width) plus 24 bits * object width if using error diffusion */ +#define LV_DITHER_GRADIENT 0 +#if LV_DITHER_GRADIENT + /*Add support for error diffusion dithering. + *Error diffusion dithering gets a much better visual result, but implies more CPU consumption and memory when drawing. + *The increase in memory consumption is (24 bits * object's width)*/ + #define LV_DITHER_ERROR_DIFFUSION 0 +#endif + +/*Maximum buffer size to allocate for rotation. + *Only used if software rotation is enabled in the display driver.*/ +#define LV_DISP_ROT_MAX_BUF (10*1024) + +/*------------- + * GPU + *-----------*/ + +/*Use Arm's 2D acceleration library Arm-2D */ +#define LV_USE_GPU_ARM2D 0 + +/*Use STM32's DMA2D (aka Chrom Art) GPU*/ +#define LV_USE_GPU_STM32_DMA2D 0 +#if LV_USE_GPU_STM32_DMA2D + /*Must be defined to include path of CMSIS header of target processor + e.g. "stm32f769xx.h" or "stm32f429xx.h"*/ + #define LV_GPU_DMA2D_CMSIS_INCLUDE +#endif + +/*Use SWM341's DMA2D GPU*/ +#define LV_USE_GPU_SWM341_DMA2D 0 +#if LV_USE_GPU_SWM341_DMA2D + #define LV_GPU_SWM341_DMA2D_INCLUDE "SWM341.h" +#endif + +/*Use NXP's PXP GPU iMX RTxxx platforms*/ +#define LV_USE_GPU_NXP_PXP 0 +#if LV_USE_GPU_NXP_PXP + /*1: Add default bare metal and FreeRTOS interrupt handling routines for PXP (lv_gpu_nxp_pxp_osa.c) + * and call lv_gpu_nxp_pxp_init() automatically during lv_init(). Note that symbol SDK_OS_FREE_RTOS + * has to be defined in order to use FreeRTOS OSA, otherwise bare-metal implementation is selected. + *0: lv_gpu_nxp_pxp_init() has to be called manually before lv_init() + */ + #define LV_USE_GPU_NXP_PXP_AUTO_INIT 0 +#endif + +/*Use NXP's VG-Lite GPU iMX RTxxx platforms*/ +#define LV_USE_GPU_NXP_VG_LITE 0 + +/*Use SDL renderer API*/ +#define LV_USE_GPU_SDL 0 +#if LV_USE_GPU_SDL + #define LV_GPU_SDL_INCLUDE_PATH + /*Texture cache size, 8MB by default*/ + #define LV_GPU_SDL_LRU_SIZE (1024 * 1024 * 8) + /*Custom blend mode for mask drawing, disable if you need to link with older SDL2 lib*/ + #define LV_GPU_SDL_CUSTOM_BLEND_MODE (SDL_VERSION_ATLEAST(2, 0, 6)) +#endif + +#if (defined(BL808) || defined(BL606P)) + + #define LV_USE_GPU_LB_DMA2D 0 + #define LV_USE_GPU_LB_DMA2D_AUTO_INIT 1 + + #if defined(CPU_D0) && (LV_COLOR_DEPTH != 16 || LV_COLOR_SCREEN_TRANSP == 0) + #define LV_USE_RV_VECTOR_EXT 1 + #else + #define LV_USE_RV_VECTOR_EXT 0 + #endif +#else + #define LV_USE_GPU_LB_DMA2D 0 + #define LV_USE_GPU_LB_DMA2D_AUTO_INIT 0 + #define LV_USE_RV_VECTOR_EXT 0 + +#endif + +/*------------- + * Logging + *-----------*/ + +/*Enable the log module*/ +#define LV_USE_LOG 1 +#if LV_USE_LOG + + /*How important log should be added: + *LV_LOG_LEVEL_TRACE A lot of logs to give detailed information + *LV_LOG_LEVEL_INFO Log important events + *LV_LOG_LEVEL_WARN Log if something unwanted happened but didn't cause a problem + *LV_LOG_LEVEL_ERROR Only critical issue, when the system may fail + *LV_LOG_LEVEL_USER Only logs added by the user + *LV_LOG_LEVEL_NONE Do not log anything*/ + #define LV_LOG_LEVEL LV_LOG_LEVEL_WARN + + /*1: Print the log with 'printf'; + *0: User need to register a callback with `lv_log_register_print_cb()`*/ + #define LV_LOG_PRINTF 0 + + /*Enable/disable LV_LOG_TRACE in modules that produces a huge number of logs*/ + #define LV_LOG_TRACE_MEM 1 + #define LV_LOG_TRACE_TIMER 1 + #define LV_LOG_TRACE_INDEV 1 + #define LV_LOG_TRACE_DISP_REFR 1 + #define LV_LOG_TRACE_EVENT 1 + #define LV_LOG_TRACE_OBJ_CREATE 1 + #define LV_LOG_TRACE_LAYOUT 1 + #define LV_LOG_TRACE_ANIM 1 + +#endif /*LV_USE_LOG*/ + +/*------------- + * Asserts + *-----------*/ + +/*Enable asserts if an operation is failed or an invalid data is found. + *If LV_USE_LOG is enabled an error message will be printed on failure*/ +#define LV_USE_ASSERT_NULL 1 /*Check if the parameter is NULL. (Very fast, recommended)*/ +#define LV_USE_ASSERT_MALLOC 1 /*Checks is the memory is successfully allocated or no. (Very fast, recommended)*/ +#define LV_USE_ASSERT_STYLE 0 /*Check if the styles are properly initialized. (Very fast, recommended)*/ +#define LV_USE_ASSERT_MEM_INTEGRITY 0 /*Check the integrity of `lv_mem` after critical operations. (Slow)*/ +#define LV_USE_ASSERT_OBJ 0 /*Check the object's type and existence (e.g. not deleted). (Slow)*/ + +/*Add a custom handler when assert happens e.g. to restart the MCU*/ +#define LV_ASSERT_HANDLER_INCLUDE +#define LV_ASSERT_HANDLER while(1); /*Halt by default*/ + +/*------------- + * Others + *-----------*/ + +/*1: Show CPU usage and FPS count*/ +#define LV_USE_PERF_MONITOR 1 +#if LV_USE_PERF_MONITOR + #define LV_USE_PERF_MONITOR_POS LV_ALIGN_BOTTOM_RIGHT +#endif + +/*1: Show the used memory and the memory fragmentation + * Requires LV_MEM_CUSTOM = 0*/ +#define LV_USE_MEM_MONITOR 0 +#if LV_USE_MEM_MONITOR + #define LV_USE_MEM_MONITOR_POS LV_ALIGN_BOTTOM_LEFT +#endif + +/*1: Draw random colored rectangles over the redrawn areas*/ +#define LV_USE_REFR_DEBUG 0 + +/*Change the built in (v)snprintf functions*/ +#define LV_SPRINTF_CUSTOM 0 +#if LV_SPRINTF_CUSTOM + #define LV_SPRINTF_INCLUDE + #define lv_snprintf snprintf + #define lv_vsnprintf vsnprintf +#else /*LV_SPRINTF_CUSTOM*/ + #define LV_SPRINTF_USE_FLOAT 0 +#endif /*LV_SPRINTF_CUSTOM*/ + +#define LV_USE_USER_DATA 1 + +/*Garbage Collector settings + *Used if lvgl is bound to higher level language and the memory is managed by that language*/ +#define LV_ENABLE_GC 0 +#if LV_ENABLE_GC != 0 + #define LV_GC_INCLUDE "gc.h" /*Include Garbage Collector related things*/ +#endif /*LV_ENABLE_GC*/ + +/*===================== + * COMPILER SETTINGS + *====================*/ + +/*For big endian systems set to 1*/ +#define LV_BIG_ENDIAN_SYSTEM 0 + +/*Define a custom attribute to `lv_tick_inc` function*/ +#define LV_ATTRIBUTE_TICK_INC + +/*Define a custom attribute to `lv_timer_handler` function*/ +#define LV_ATTRIBUTE_TIMER_HANDLER + +/*Define a custom attribute to `lv_disp_flush_ready` function*/ +#define LV_ATTRIBUTE_FLUSH_READY + +/*Required alignment size for buffers*/ +#define LV_ATTRIBUTE_MEM_ALIGN_SIZE 1 + +/*Will be added where memories needs to be aligned (with -Os data might not be aligned to boundary by default). + * E.g. __attribute__((aligned(4)))*/ +#define LV_ATTRIBUTE_MEM_ALIGN + +/*Attribute to mark large constant arrays for example font's bitmaps*/ +#define LV_ATTRIBUTE_LARGE_CONST + +/*Compiler prefix for a big array declaration in RAM*/ +#define LV_ATTRIBUTE_LARGE_RAM_ARRAY + +/*Place performance critical functions into a faster memory (e.g RAM)*/ +#define LV_ATTRIBUTE_FAST_MEM + +/*Prefix variables that are used in GPU accelerated operations, often these need to be placed in RAM sections that are DMA accessible*/ +#define LV_ATTRIBUTE_DMA + +/*Export integer constant to binding. This macro is used with constants in the form of LV_ that + *should also appear on LVGL binding API such as Micropython.*/ +#define LV_EXPORT_CONST_INT(int_value) struct _silence_gcc_warning /*The default value just prevents GCC warning*/ + +/*Extend the default -32k..32k coordinate range to -4M..4M by using int32_t for coordinates instead of int16_t*/ +#define LV_USE_LARGE_COORD 0 + +/*================== + * FONT USAGE + *===================*/ + +/*Montserrat fonts with ASCII range and some symbols using bpp = 4 + *https://fonts.google.com/specimen/Montserrat*/ +#define LV_FONT_MONTSERRAT_8 0 +#define LV_FONT_MONTSERRAT_10 0 +#define LV_FONT_MONTSERRAT_12 0 +#define LV_FONT_MONTSERRAT_14 1 +#define LV_FONT_MONTSERRAT_16 0 +#define LV_FONT_MONTSERRAT_18 0 +#define LV_FONT_MONTSERRAT_20 0 +#define LV_FONT_MONTSERRAT_22 0 +#define LV_FONT_MONTSERRAT_24 0 +#define LV_FONT_MONTSERRAT_26 0 +#define LV_FONT_MONTSERRAT_28 0 +#define LV_FONT_MONTSERRAT_30 0 +#define LV_FONT_MONTSERRAT_32 0 +#define LV_FONT_MONTSERRAT_34 0 +#define LV_FONT_MONTSERRAT_36 0 +#define LV_FONT_MONTSERRAT_38 0 +#define LV_FONT_MONTSERRAT_40 0 +#define LV_FONT_MONTSERRAT_42 0 +#define LV_FONT_MONTSERRAT_44 0 +#define LV_FONT_MONTSERRAT_46 0 +#define LV_FONT_MONTSERRAT_48 0 + +/*Demonstrate special features*/ +#define LV_FONT_MONTSERRAT_12_SUBPX 0 +#define LV_FONT_MONTSERRAT_28_COMPRESSED 0 /*bpp = 3*/ +#define LV_FONT_DEJAVU_16_PERSIAN_HEBREW 0 /*Hebrew, Arabic, Persian letters and all their forms*/ +#define LV_FONT_SIMSUN_16_CJK 0 /*1000 most common CJK radicals*/ + +/*Pixel perfect monospace fonts*/ +#define LV_FONT_UNSCII_8 0 +#define LV_FONT_UNSCII_16 0 + +/*Optionally declare custom fonts here. + *You can use these fonts as default font too and they will be available globally. + *E.g. #define LV_FONT_CUSTOM_DECLARE LV_FONT_DECLARE(my_font_1) LV_FONT_DECLARE(my_font_2)*/ +#define LV_FONT_CUSTOM_DECLARE + +/*Always set a default font*/ +#define LV_FONT_DEFAULT &lv_font_montserrat_14 + +/*Enable handling large font and/or fonts with a lot of characters. + *The limit depends on the font size, font face and bpp. + *Compiler error will be triggered if a font needs it.*/ +#define LV_FONT_FMT_TXT_LARGE 0 + +/*Enables/disables support for compressed fonts.*/ +#define LV_USE_FONT_COMPRESSED 1 + +/*Enable subpixel rendering*/ +#define LV_USE_FONT_SUBPX 1 +#if LV_USE_FONT_SUBPX + /*Set the pixel order of the display. Physical order of RGB channels. Doesn't matter with "normal" fonts.*/ + #define LV_FONT_SUBPX_BGR 0 /*0: RGB; 1:BGR order*/ +#endif + +/*================= + * TEXT SETTINGS + *=================*/ + +/** + * Select a character encoding for strings. + * Your IDE or editor should have the same character encoding + * - LV_TXT_ENC_UTF8 + * - LV_TXT_ENC_ASCII + */ +#define LV_TXT_ENC LV_TXT_ENC_UTF8 + +/*Can break (wrap) texts on these chars*/ +#define LV_TXT_BREAK_CHARS " ,.;:-_" + +/*If a word is at least this long, will break wherever "prettiest" + *To disable, set to a value <= 0*/ +#define LV_TXT_LINE_BREAK_LONG_LEN 0 + +/*Minimum number of characters in a long word to put on a line before a break. + *Depends on LV_TXT_LINE_BREAK_LONG_LEN.*/ +#define LV_TXT_LINE_BREAK_LONG_PRE_MIN_LEN 3 + +/*Minimum number of characters in a long word to put on a line after a break. + *Depends on LV_TXT_LINE_BREAK_LONG_LEN.*/ +#define LV_TXT_LINE_BREAK_LONG_POST_MIN_LEN 3 + +/*The control character to use for signalling text recoloring.*/ +#define LV_TXT_COLOR_CMD "#" + +/*Support bidirectional texts. Allows mixing Left-to-Right and Right-to-Left texts. + *The direction will be processed according to the Unicode Bidirectional Algorithm: + *https://www.w3.org/International/articles/inline-bidi-markup/uba-basics*/ +#define LV_USE_BIDI 0 +#if LV_USE_BIDI + /*Set the default direction. Supported values: + *`LV_BASE_DIR_LTR` Left-to-Right + *`LV_BASE_DIR_RTL` Right-to-Left + *`LV_BASE_DIR_AUTO` detect texts base direction*/ + #define LV_BIDI_BASE_DIR_DEF LV_BASE_DIR_AUTO +#endif + +/*Enable Arabic/Persian processing + *In these languages characters should be replaced with an other form based on their position in the text*/ +#define LV_USE_ARABIC_PERSIAN_CHARS 0 + +/*================== + * WIDGET USAGE + *================*/ + +/*Documentation of the widgets: https://docs.lvgl.io/latest/en/html/widgets/index.html*/ + +#define LV_USE_ARC 1 + +#define LV_USE_BAR 1 + +#define LV_USE_BTN 1 + +#define LV_USE_BTNMATRIX 1 + +#define LV_USE_CANVAS 1 + +#define LV_USE_CHECKBOX 1 + +#define LV_USE_DROPDOWN 1 /*Requires: lv_label*/ + +#define LV_USE_IMG 1 /*Requires: lv_label*/ + +#define LV_USE_LABEL 1 +#if LV_USE_LABEL + #define LV_LABEL_TEXT_SELECTION 1 /*Enable selecting text of the label*/ + #define LV_LABEL_LONG_TXT_HINT 1 /*Store some extra info in labels to speed up drawing of very long texts*/ +#endif + +#define LV_USE_LINE 1 + +#define LV_USE_ROLLER 1 /*Requires: lv_label*/ +#if LV_USE_ROLLER + #define LV_ROLLER_INF_PAGES 7 /*Number of extra "pages" when the roller is infinite*/ +#endif + +#define LV_USE_SLIDER 1 /*Requires: lv_bar*/ + +#define LV_USE_SWITCH 1 + +#define LV_USE_TEXTAREA 1 /*Requires: lv_label*/ +#if LV_USE_TEXTAREA != 0 + #define LV_TEXTAREA_DEF_PWD_SHOW_TIME 1500 /*ms*/ +#endif + +#define LV_USE_TABLE 1 + +/*================== + * EXTRA COMPONENTS + *==================*/ + +/*----------- + * Widgets + *----------*/ +#define LV_USE_ANIMIMG 1 + +#define LV_USE_CALENDAR 1 +#if LV_USE_CALENDAR + #define LV_CALENDAR_WEEK_STARTS_MONDAY 0 + #if LV_CALENDAR_WEEK_STARTS_MONDAY + #define LV_CALENDAR_DEFAULT_DAY_NAMES {"Mo", "Tu", "We", "Th", "Fr", "Sa", "Su"} + #else + #define LV_CALENDAR_DEFAULT_DAY_NAMES {"Su", "Mo", "Tu", "We", "Th", "Fr", "Sa"} + #endif + + #define LV_CALENDAR_DEFAULT_MONTH_NAMES {"January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"} + #define LV_USE_CALENDAR_HEADER_ARROW 1 + #define LV_USE_CALENDAR_HEADER_DROPDOWN 1 +#endif /*LV_USE_CALENDAR*/ + +#define LV_USE_CHART 1 + +#define LV_USE_COLORWHEEL 1 + +#define LV_USE_IMGBTN 1 + +#define LV_USE_KEYBOARD 1 + +#define LV_USE_LED 1 + +#define LV_USE_LIST 1 + +#define LV_USE_MENU 1 + +#define LV_USE_METER 1 + +#define LV_USE_MSGBOX 1 + +#define LV_USE_SPAN 1 +#if LV_USE_SPAN + /*A line text can contain maximum num of span descriptor */ + #define LV_SPAN_SNIPPET_STACK_SIZE 64 +#endif + +#define LV_USE_SPINBOX 1 + +#define LV_USE_SPINNER 1 + +#define LV_USE_TABVIEW 1 + +#define LV_USE_TILEVIEW 1 + +#define LV_USE_WIN 1 + +/*----------- + * Themes + *----------*/ + +/*A simple, impressive and very complete theme*/ +#define LV_USE_THEME_DEFAULT 1 +#if LV_USE_THEME_DEFAULT + + /*0: Light mode; 1: Dark mode*/ + #define LV_THEME_DEFAULT_DARK 0 + + /*1: Enable grow on press*/ + #define LV_THEME_DEFAULT_GROW 1 + + /*Default transition time in [ms]*/ + #define LV_THEME_DEFAULT_TRANSITION_TIME 80 +#endif /*LV_USE_THEME_DEFAULT*/ + +/*A very simple theme that is a good starting point for a custom theme*/ +#define LV_USE_THEME_BASIC 1 + +/*A theme designed for monochrome displays*/ +#define LV_USE_THEME_MONO 1 + +/*----------- + * Layouts + *----------*/ + +/*A layout similar to Flexbox in CSS.*/ +#define LV_USE_FLEX 1 + +/*A layout similar to Grid in CSS.*/ +#define LV_USE_GRID 1 + +/*--------------------- + * 3rd party libraries + *--------------------*/ + +/*File system interfaces for common APIs */ + +/*API for fopen, fread, etc*/ +#define LV_USE_FS_STDIO 0 +#if LV_USE_FS_STDIO + #define LV_FS_STDIO_LETTER '\0' /*Set an upper cased letter on which the drive will accessible (e.g. 'A')*/ + #define LV_FS_STDIO_PATH "" /*Set the working directory. File/directory paths will be appended to it.*/ + #define LV_FS_STDIO_CACHE_SIZE 0 /*>0 to cache this number of bytes in lv_fs_read()*/ +#endif + +/*API for open, read, etc*/ +#define LV_USE_FS_POSIX 0 +#if LV_USE_FS_POSIX + #define LV_FS_POSIX_LETTER '\0' /*Set an upper cased letter on which the drive will accessible (e.g. 'A')*/ + #define LV_FS_POSIX_PATH "" /*Set the working directory. File/directory paths will be appended to it.*/ + #define LV_FS_POSIX_CACHE_SIZE 0 /*>0 to cache this number of bytes in lv_fs_read()*/ +#endif + +/*API for CreateFile, ReadFile, etc*/ +#define LV_USE_FS_WIN32 0 +#if LV_USE_FS_WIN32 + #define LV_FS_WIN32_LETTER '\0' /*Set an upper cased letter on which the drive will accessible (e.g. 'A')*/ + #define LV_FS_WIN32_PATH "" /*Set the working directory. File/directory paths will be appended to it.*/ + #define LV_FS_WIN32_CACHE_SIZE 0 /*>0 to cache this number of bytes in lv_fs_read()*/ +#endif + +/*API for FATFS (needs to be added separately). Uses f_open, f_read, etc*/ +#if defined(BL808) || defined(BL606P) || defined(BL616) +#define LV_USE_FS_FATFS 0 +#else +#define LV_USE_FS_FATFS 0 +#endif + +#if LV_USE_FS_FATFS + #define LV_FS_FATFS_LETTER 'S' /*Set an upper cased letter on which the drive will accessible (e.g. 'A')*/ + #define LV_FS_FATFS_CACHE_SIZE 0 /*>0 to cache this number of bytes in lv_fs_read()*/ +#endif + +/*PNG decoder library*/ +#define LV_USE_PNG 1 + +/*BMP decoder library*/ +#define LV_USE_BMP 1 + +/* JPG + split JPG decoder library. + * Split JPG is a custom format optimized for embedded systems. */ +#define LV_USE_SJPG 0 + +/*GIF decoder library*/ +#define LV_USE_GIF 0 + +/*QR code library*/ +#define LV_USE_QRCODE 0 + +/*FreeType library*/ +#define LV_USE_FREETYPE 0 +#if LV_USE_FREETYPE + /*Memory used by FreeType to cache characters [bytes] (-1: no caching)*/ + #define LV_FREETYPE_CACHE_SIZE (16 * 1024) + #if LV_FREETYPE_CACHE_SIZE >= 0 + /* 1: bitmap cache use the sbit cache, 0:bitmap cache use the image cache. */ + /* sbit cache:it is much more memory efficient for small bitmaps(font size < 256) */ + /* if font size >= 256, must be configured as image cache */ + #define LV_FREETYPE_SBIT_CACHE 0 + /* Maximum number of opened FT_Face/FT_Size objects managed by this cache instance. */ + /* (0:use system defaults) */ + #define LV_FREETYPE_CACHE_FT_FACES 0 + #define LV_FREETYPE_CACHE_FT_SIZES 0 + #endif +#endif + +/*Rlottie library*/ +#define LV_USE_RLOTTIE 0 + +/*FFmpeg library for image decoding and playing videos + *Supports all major image formats so do not enable other image decoder with it*/ +#define LV_USE_FFMPEG 0 +#if LV_USE_FFMPEG + /*Dump input information to stderr*/ + #define LV_FFMPEG_DUMP_FORMAT 0 +#endif + +/*----------- + * Others + *----------*/ + +/*1: Enable API to take snapshot for object*/ +#define LV_USE_SNAPSHOT 0 + +/*1: Enable Monkey test*/ +#define LV_USE_MONKEY 0 + +/*1: Enable grid navigation*/ +#define LV_USE_GRIDNAV 0 + +/*1: Enable lv_obj fragment*/ +#define LV_USE_FRAGMENT 0 + +/*1: Support using images as font in label or span widgets */ +#define LV_USE_IMGFONT 0 + +/*1: Enable a published subscriber based messaging system */ +#define LV_USE_MSG 0 + +/*1: Enable Pinyin input method*/ +/*Requires: lv_keyboard*/ +#define LV_USE_IME_PINYIN 0 +#if LV_USE_IME_PINYIN + /*1: Use default thesaurus*/ + /*If you do not use the default thesaurus, be sure to use `lv_ime_pinyin` after setting the thesauruss*/ + #define LV_IME_PINYIN_USE_DEFAULT_DICT 1 + /*Set the maximum number of candidate panels that can be displayed*/ + /*This needs to be adjusted according to the size of the screen*/ + #define LV_IME_PINYIN_CAND_TEXT_NUM 6 + + /*Use 9 key input(k9)*/ + #define LV_IME_PINYIN_USE_K9_MODE 1 + #if LV_IME_PINYIN_USE_K9_MODE == 1 + #define LV_IME_PINYIN_K9_CAND_TEXT_NUM 3 + #endif // LV_IME_PINYIN_USE_K9_MODE +#endif + +/*================== +* EXAMPLES +*==================*/ + +/*Enable the examples to be built with the library*/ +#define LV_BUILD_EXAMPLES 1 + +/*=================== + * DEMO USAGE + ====================*/ + +/*Show some widget. It might be required to increase `LV_MEM_SIZE` */ +#define LV_USE_DEMO_WIDGETS 0 +#if LV_USE_DEMO_WIDGETS +#define LV_DEMO_WIDGETS_SLIDESHOW 0 +#endif + +/*Demonstrate the usage of encoder and keyboard*/ +#define LV_USE_DEMO_KEYPAD_AND_ENCODER 0 + +/*Benchmark your system*/ +#define LV_USE_DEMO_BENCHMARK 1 +#if LV_USE_DEMO_BENCHMARK +/*Use RGB565A8 images with 16 bit color depth instead of ARGB8565*/ +#define LV_DEMO_BENCHMARK_RGB565A8 0 +#endif + +/*Stress test for LVGL*/ +#define LV_USE_DEMO_STRESS 0 + +/*Music player demo*/ +#define LV_USE_DEMO_MUSIC 0 +#if LV_USE_DEMO_MUSIC + #define LV_DEMO_MUSIC_SQUARE 0 + #define LV_DEMO_MUSIC_LANDSCAPE 0 + #define LV_DEMO_MUSIC_ROUND 0 + #define LV_DEMO_MUSIC_LARGE 0 + #define LV_DEMO_MUSIC_AUTO_PLAY 0 +#endif + +/*--END OF LV_CONF_H--*/ + +#endif /*LV_CONF_H*/ + +#endif /*End of "Content enable"*/ diff --git a/examples/pikapython/main.c b/examples/pikapython/main.c index 8d97563b..c213a1e7 100644 --- a/examples/pikapython/main.c +++ b/examples/pikapython/main.c @@ -1,11 +1,193 @@ +#include #include +#include "./pikapython/pikascript-lib/PikaStdDevice/pika_hal.h" +#include "FreeRTOS.h" +#include "bflb_flash.h" +#include "bflb_gpio.h" +#include "bflb_uart.h" #include "board.h" -#include "ff.h" #include "log.h" +// #include "lwip/init.h" #include "pikaScript.h" -#include "vlibc_stdio.h" +#include "task.h" + +#if defined(BL616) +#include "bl616_glb.h" +#elif defined(BL602) +#include "bl602_glb.h" +#elif defined(BL702) +#include "bl702_glb.h" +#elif defined(BL808) +#include "bl808_glb.h" +#endif + +struct bflb_device_s* uartx = NULL; +// static uint8_t freertos_heap[configTOTAL_HEAP_SIZE]; + +volatile FILE g_pika_app_flash_file = {0}; +volatile int g_pika_app_flash_pos = 0; +#define _PIKA_APP_FLASH_ADDR 0x100000 // 1M +#define _PIKA_APP_FLASH_SIZE 32 * 1024 // 32K + +#define _PIKA_APP_FLASH_INITED 0xFE +#define _PIKA_APP_FLASH_VOID 0xFF +#define _PIKA_APP_FLASH_SAVED 0x0F + +// static HeapRegion_t xHeapRegions[] = { +// {(uint8_t*)freertos_heap, 0}, +// {NULL, 0}, /* Terminates the array. */ +// {NULL, 0} /* Terminates the array. */ +// }; + +static int _pika_app_check(void) { + uint8_t buf = {0}; + FILE* f = pika_platform_fopen("app.pika", "rb"); + pika_platform_fread(&buf, 1, 1, f); + if (buf == _PIKA_APP_FLASH_SAVED) { + return 1; + } + return 0; +} + +uint8_t _pika_app_buf[_PIKA_APP_FLASH_SIZE] = {0}; +static void consumer_task(void* pvParameters) { + PikaObj* root = newRootObj("root", New_PikaMain); + if (_pika_app_check()) { + printf("Load app.pika from flash\r\n"); + FILE* f = pika_platform_fopen("app.pika", "rb"); + pika_platform_fread(_pika_app_buf, 1, _PIKA_APP_FLASH_SIZE, f); + obj_linkLibrary(root, (uint8_t*)_pika_app_buf); + obj_runModule(root, "main"); + } else { + printf("Load app.pika from flash failed\r\n"); + extern unsigned char pikaModules_py_a[]; + obj_linkLibrary(root, pikaModules_py_a); + obj_runModule(root, "main"); + } + pikaScriptShell(root); + while (1) { + } +} + +static void _erise_app_task(void* pvParameters) { + struct bflb_device_s* gpio = bflb_device_get_by_name("gpio"); + bflb_gpio_init(gpio, GPIO_PIN_2, + GPIO_INPUT | GPIO_FLOAT | GPIO_SMT_EN | GPIO_DRV_0); + int time = 0; + while (1) { + if (bflb_gpio_read(gpio, GPIO_PIN_2) == 1) { + time++; + if (time > 100) { + printf("Erasing app.pika...\r\n"); + printf("Please release the button\r\n"); + for (uint32_t i = 1; i < (_PIKA_APP_FLASH_SIZE / 1024); i++) { + bflb_flash_erase(_PIKA_APP_FLASH_ADDR + (i - 1) * 1024, + i * 1024); + } + printf("Erase app.pika done\r\n"); + pika_platform_reboot(); + } + } else { + time = 0; + } + vTaskDelay(10); + } +} int main(void) { board_init(); - pikaScriptInit(); + uartx = bflb_device_get_by_name("uart0"); + bflb_uart_feature_control(uartx, UART_CMD_SET_BAUD_RATE, 115200); + // xHeapRegions[0].xSizeInBytes = configTOTAL_HEAP_SIZE; + // vPortDefineHeapRegions(xHeapRegions); + // printf("Heap size: %d\r\n", configTOTAL_HEAP_SIZE); + + xTaskCreate(_erise_app_task, (char*)"erise_app_task", 8192, NULL, + configMAX_PRIORITIES - 1, NULL); + xTaskCreate(consumer_task, (char*)"consumer_task", 8192, NULL, 3, NULL); + vTaskStartScheduler(); + + while (1) { + } +} + +/* Platform Porting */ + +char pika_platform_getchar(void) { + while (1) { + int c = bflb_uart_getchar(uartx); + if (c != -1) { + return c; + } + } +} + +int pika_platform_putchar(char ch) { + bflb_uart_putchar(uartx, ch); + return 0; +} + +void pika_platform_reboot(void) { + GLB_SW_System_Reset(); +} + +void* pika_platform_malloc(size_t size) { + return pvPortMalloc(size); +} + +void pika_platform_free(void* ptr) { + return vPortFree(ptr); +} + +/* fopen */ +FILE* pika_platform_fopen(const char* filename, const char* modes) { + if (strcmp("app.pika", filename) == 0) { + g_pika_app_flash_pos = 0; + FILE* fp = (FILE*)&g_pika_app_flash_file; + if (strchr(modes, 'w') == NULL) { + return fp; + } + for (uint32_t i = 1; i < (_PIKA_APP_FLASH_SIZE / 1024); i++) { + bflb_flash_erase(_PIKA_APP_FLASH_ADDR + (i - 1) * 1024, i * 1024); + } + return fp; + } + return NULL; +} + +/* fwrite */ +size_t pika_platform_fwrite(const void* ptr, + size_t size, + size_t n, + FILE* stream) { + if (stream == (FILE*)&g_pika_app_flash_file) { + bflb_flash_write(_PIKA_APP_FLASH_ADDR + g_pika_app_flash_pos, + (uint8_t*)ptr, size * n); + g_pika_app_flash_pos += size * n; + return size * n; + } + return 0; +} + +/* fread */ +size_t pika_platform_fread(void* ptr, size_t size, size_t n, FILE* stream) { + if (stream == (FILE*)&g_pika_app_flash_file) { + bflb_flash_read(_PIKA_APP_FLASH_ADDR + g_pika_app_flash_pos, + (uint8_t*)ptr, size * n); + g_pika_app_flash_pos += size * n; + return size * n; + } + return 0; +} + +/* fclose */ +int pika_platform_fclose(FILE* stream) { + if (stream == (FILE*)&g_pika_app_flash_file) { + for (uint32_t i = 1; i < 32; i++) { + /* add EOF */ + pika_platform_fwrite("\0", 1, 1, stream); + } + return 0; + } + return -1; } diff --git a/examples/pikapython/make.sh b/examples/pikapython/make.sh new file mode 100755 index 00000000..c00acffa --- /dev/null +++ b/examples/pikapython/make.sh @@ -0,0 +1,14 @@ +if [ $# == 0 ] ; then + CMD="" +fi +if [ $# == 1 ] ; then + if [ $1 == "bl618" ] ; then + CMD="CHIP=bl616 BOARD=bl616dk" + fi + if [ $1 == "bl616" ] ; then + CMD="CHIP=bl616 BOARD=bl616dk" + fi +fi +cd pikapython && wine rust-msc-latest-win10.exe && cd - +make -j $CMD +cp build/build_out/*.bin /mnt/d diff --git a/examples/pikapython/make_bl616.sh b/examples/pikapython/make_bl616.sh new file mode 100755 index 00000000..8626bf51 --- /dev/null +++ b/examples/pikapython/make_bl616.sh @@ -0,0 +1 @@ +bash make.sh bl618 diff --git a/examples/pikapython/make_bl618.sh b/examples/pikapython/make_bl618.sh new file mode 100755 index 00000000..8626bf51 --- /dev/null +++ b/examples/pikapython/make_bl618.sh @@ -0,0 +1 @@ +bash make.sh bl618 diff --git a/examples/pikapython/pika_config.h b/examples/pikapython/pika_config.h new file mode 100755 index 00000000..a781afc8 --- /dev/null +++ b/examples/pikapython/pika_config.h @@ -0,0 +1,5 @@ +#define PIKA_LWIP_ENABLE 1 +#define PIKA_FREERTOS_ENABLE 1 +#define PIKA_THREAD_STACK_SIZE 4096 +#define PIKA_SHELL_SAVE_APP_ENABLE 1 +#define PIKA_STACK_BUFF_SIZE 512 \ No newline at end of file diff --git a/examples/pikapython/pikapython/BLMCU.pyi b/examples/pikapython/pikapython/BLMCU.pyi new file mode 100755 index 00000000..e69de29b diff --git a/examples/pikapython/pikapython/PikaMath.pyi b/examples/pikapython/pikapython/PikaMath.pyi new file mode 100755 index 00000000..104ae9f2 --- /dev/null +++ b/examples/pikapython/pikapython/PikaMath.pyi @@ -0,0 +1,157 @@ +from PikaObj import * + + +class Operator(TinyObj): + def plusInt(self, num1: int, num2: int) -> int: ... + def plusFloat(self, num1: float, num2: float) -> float: ... + def minusInt(self, num1: int, num2: int) -> int: ... + def minusFloat(self, num1: float, num2: float) -> float: ... + def equalInt(self, num1: int, num2: int) -> int: ... + def equalFloat(self, num1: float, num2: float) -> int: ... + def graterThanInt(self, num1: int, num2: int) -> int: ... + def graterThanFloat(self, num1: float, num2: float) -> int: ... + def lessThanInt(self, num1: int, num2: int) -> int: ... + def lessThanFloat(self, num1: float, num2: float) -> int: ... + def AND(self, flag1: int, flag2: int) -> int: ... + def OR(self, flag1: int, flag2: int) -> int: ... + def NOT(self, flag: int) -> int: ... + def __str__(self) -> str: ... + def __del__(self): ... + + +class Math(TinyObj): + pi: float + e: float + + def __init__(self): + pass + + def ceil(self, x: float) -> int: + pass + + def fabs(self, x: float) -> float: + pass + + def floor(self, x: float) -> int: + pass + + def fmod(self, x: float, y: float) -> float: + pass + + def remainder(self, x: float, y: float) -> float: + pass + + def trunc(self, x: float) -> float: + pass + + # 幂函数和对数函数 + + def exp(self, x: float) -> float: + pass + + def log(self, x: float) -> float: + pass + + def log2(self, x: float) -> float: + pass + + def log10(self, x: float) -> float: + pass + + def pow(self, x: float, y: float) -> float: + pass + + def sqrt(self, x: float) -> float: + pass + + # 三角函数 + def acos(self, x: float) -> float: + pass + + def asin(self, x: float) -> float: + pass + + def atan(self, x: float) -> float: + pass + + def atan2(self, x: float, y: float) -> float: + pass + + def cos(self, x: float) -> float: + pass + + def sin(self, x: float) -> float: + pass + + def tan(self, x: float) -> float: + pass + + # 角度转换 + def degrees(self, x: float) -> float: + pass + + def radians(self, x: float) -> float: + pass + + # 双曲函数 + def cosh(self, x: float) -> float: + pass + + def sinh(self, x: float) -> float: + pass + + def tanh(self, x: float) -> float: + pass + + +class Quaternion(TinyObj): + def __init__(self): + pass + + def set(self, x: float, y: float, z: float, w: float): + "xi+yj+zk+w" + pass + + def get(self, key: int) -> float: + pass + + def add(self, quat: Quaternion): + pass + + def sub(self, quat: Quaternion): + pass + + def mul(self, quat: Quaternion): + pass + + def magnituded(self) -> float: + pass + + def magnitudedsquare(self) -> float: + pass + + def reverse(self): + pass + + def inverse(self): + pass + + def normalize(self): + pass + + def isnormalize(self) -> int: + pass + + def dot(self, quat: Quaternion) -> float: + pass + + def crossproduct(self, quat: Quaternion): + pass + + def fromEuler(self, yaw: float, pitch: float, roll: float, mode: int): + "mode=1 is deg and mode=0 is rad" + pass + + def toEuler(self) -> list: + "Z-Y-X" + pass diff --git a/examples/pikapython/pikapython/PikaStdDevice.pyi b/examples/pikapython/pikapython/PikaStdDevice.pyi new file mode 100755 index 00000000..99ea267c --- /dev/null +++ b/examples/pikapython/pikapython/PikaStdDevice.pyi @@ -0,0 +1,490 @@ +""" +PikaStdDevice is a standard and abstract device module for PikaScript. + +PikaStdDevice supplies the standard device API for users. + +Document: https://pikadoc.readthedocs.io/en/latest/PikaStdDevice%20%E6%A0%87%E5%87%86%E8%AE%BE%E5%A4%87.html + +""" +from PikaObj import * + + +class GPIO(BaseDev): + def __init__(self): ... + + def setPin(self, pinName: str): + """ + Use the name of the pin to select the GPIO pin. + + example: `"PA0"`, `"PA1"` ... + """ + + def setId(self, id: int): + """ + Use the id of the pin to select the GPIO pin. + + example: 0, 1 ... + """ + + def getId(self) -> int: + """ + Get the id of the pin. + """ + + def getPin(self) -> str: + """ + Get the name of the pin. + """ + + def setMode(self, mode: str): + """ + Set the mode of the pin. + example: "in", "out" ... + """ + + def getMode(self) -> str: + """ + Get the mode of the pin. + """ + + def setPull(self, pull: str): + """ + Set the pull of the pin. + example: `"up"`, `"down"`, `"none"` ... + """ + + def enable(self): + """Enable the pin.""" + + def disable(self): + """Disable the pin.""" + + def high(self): + """Set the pin to high.""" + + def low(self): + """Set the pin to low.""" + + def read(self) -> int: + """Read the pin value.""" + + + SIGNAL_RISING: int + SIGNAL_FALLING: int + SIGNAL_ANY: int + + def setCallBack(self, eventCallBack: any, filter: int): + """ + Add a callback function to the pin. + Example: + ``` python + def cb1(signal): + print("cb1", signal) + io.setCallBack(cb1, io.SIGNAL_RISING) + ``` + """ + + def close(self): ... + + def platformHigh(self): ... + + def platformLow(self): ... + + def platformEnable(self): ... + + def platformDisable(self): ... + + def platformSetMode(self): ... + + def platformRead(self): ... + + +def Time() -> time: + """ # use time module instead """ + + +class ADC(BaseDev): + def __init__(self): ... + + def setPin(self, pin: str): + """ + Use the name of the pin to select the ADC pin. + example: `"PA0"`, `"PA1"` ... + """ + + def enable(self): + """Enable the ADC.""" + + def disable(self): + """Disable the ADC.""" + + def read(self) -> float: + """Read the ADC value.""" + + def close(self): ... + + @abstractmethod + def platformEnable(self): ... + + @abstractmethod + def platformRead(self): ... + + @abstractmethod + def platformDisable(self): ... + + +class DAC(BaseDev): + def __init__(self): ... + + def setPin(self, pin: str): + """ + Use the name of the pin to select the DAC pin. + example: `"PA0"`, `"PA1"` ... + """ + + def enable(self): + """Enable the DAC.""" + + def disable(self): + """Disable the DAC.""" + + def write(self, val: float): + """write the DAC value.""" + + def close(self): ... + + +class UART: + def __init__(self): ... + + def setBaudRate(self, baudRate: int): + """Set the baud rate.""" + + def setId(self, id: int): + """Set the id of the UART.""" + + FLOW_CONTROL_NONE: int + FLOW_CONTROL_RTS: int + FLOW_CONTROL_CTS: int + FLOW_CONTROL_RTS_CTS: int + + def setFlowControl(self, flowControl: int): + """Set the flow control of the UART.""" + + def enable(self): + """Enable the UART.""" + + def disable(self): + """Disable the UART.""" + + def write(self, data: str): + """Write string to the UART.""" + + def writeBytes(self, data: bytes, length: int): + """Write bytes to the UART.""" + + def read(self, length: int) -> str: + """Read string from the UART.""" + + def readBytes(self, length: int) -> bytes: + """Read bytes from the UART.""" + + def setPinTX(self, pin: str): + """ + Remap the TX pin. + """ + + def setPinRX(self, pin: str): + """ + Remap the RX pin. + """ + + def setPinCTS(self, pin: str): + """ + Remap the CTS pin. + """ + + def setPinRTS(self, pin: str): + """ + Remap the RTS pin. + """ + + def close(self): ... + + SIGNAL_RX: int + SIGNAL_TX: int + + def setCallBack(self, eventCallBack: any, filter: int): + """ + Add a callback function to the pin. + Example: + ``` python + def cb1(signal): + print(uart.read(-1)) + io.setCallBack(cb1, uart.SIGNAL_RX) + ``` + """ + + @abstractmethod + def platformEnable(self): ... + + @abstractmethod + def platformWrite(self): ... + + @abstractmethod + def platformWriteBytes(self): ... + + @abstractmethod + def platformRead(self): ... + + @abstractmethod + def platformReadBytes(self): ... + + @abstractmethod + def platformDisable(self): ... + + +class IIC(BaseDev): + def __init__(self): ... + + def setPinSCL(self, pin: str): + """Set the SCL pin.""" + + def setPinSDA(self, pin: str): + """Set the SDA pin.""" + + def setDeviceAddr(self, addr: int): + """Set the device address.""" + + def enable(self): + """Enable the IIC.""" + + def disable(self): + """Disable the IIC.""" + + def write(self, addr: int, data: str): + """Write string to the IIC.""" + + def writeBytes(self, addr: int, data: bytes, length: int): + """Write bytes to the IIC.""" + + def read(self, addr: int, length: int) -> str: + """Read string from the IIC.""" + + def readBytes(self, addr: int, length: int) -> bytes: + """Read bytes from the IIC.""" + + @abstractmethod + def platformEnable(self): ... + + @abstractmethod + def platformWrite(self): ... + + @abstractmethod + def platformWriteBytes(self): ... + + @abstractmethod + def platformRead(self): ... + + @abstractmethod + def platformReadBytes(self): ... + + @abstractmethod + def platformDisable(self): ... + + +class PWM(BaseDev): + def __init__(self): ... + + def setName(self, name: str): + """Use the device name to select the PWM pin. + exmpale: `"PWM0"`, `"PWM1"` ... + """ + + def getName(self) -> str: + """Get the device name.""" + + def setChannel(self, ch: int): + """Set the channel.""" + + def getChannel(self) -> int: + """Get the channel.""" + + def setPin(self, pin: str): + """Use the name of the pin to select the PWM pin. + example: `"PA0"`, `"PA1"` ... + """ + + def setFrequency(self, freq: int): + """Set the frequency.""" + + def setFreq(self, freq: int): + """Set the frequency.""" + + def setDuty(self, duty: float): + """Set the duty.""" + + def enable(self): + """Enable the PWM.""" + + def disable(self): + """Disable the PWM.""" + + def getFrequency(self) -> int: + """Get the frequency.""" + + def getDuty(self) -> float: + """Get the duty.""" + + def close(self): ... + + @abstractmethod + def platformEnable(self): ... + + @abstractmethod + def platformSetFrequency(self): ... + + @abstractmethod + def platformSetDuty(self): ... + + @abstractmethod + def platformDisable(self): ... + + +class SPI(BaseDev): + def __init__(self): ... + + def setPinSCK(self, pin: str): + """Set the SCK pin.""" + + def setPinMOSI(self, pin: str): + """Set the MOSI pin.""" + + def setPinMISO(self, pin: str): + """Set the MISO pin.""" + + def setName(self, name: str): + """Use the device name to select the SPI pin. + exmpale: `"SPI0"`, `"SPI1"` ... + """ + + def setId(self, id: int): + """Set the id of the SPI. + example: `0`, `1` ... + """ + + def setPolarity(self, polarity: int): + """Set the polarity.""" + + def setPhase(self, phase: int): + """Set the phase.""" + + def setBaudRate(self, baudRate: int): + """Set the baud rate.""" + + def enable(self): + """Enable the SPI.""" + + def disable(self): + """Disable the SPI.""" + + def write(self, data: str): + """Write string to the SPI.""" + + def writeBytes(self, data: bytes, length: int): + """Write bytes to the SPI.""" + + def read(self, length: int) -> str: + """Read string from the SPI.""" + + def readBytes(self, length: int) -> bytes: + """Read bytes from the SPI.""" + + @abstractmethod + def platformEnable(self): ... + + @abstractmethod + def platformWrite(self): ... + + @abstractmethod + def platformWriteBytes(self): ... + + @abstractmethod + def platformRead(self): ... + + @abstractmethod + def platformReadBytes(self): ... + + @abstractmethod + def platformDisable(self): ... + + +class CAN(BaseDev): + def __init__(self): ... + + def setName(self, name: str): + """Use the device name to select the CAN pin. + exmpale: `"CAN0"`, `"CAN1"` ... + """ + + def setId(self, id: int): + """Use the id to select the CAN pin. + example: `0`, `1` ... + """ + + def setBaudRate(self, baudRate: int): + """Set the baud rate.""" + + def setMode(self, mode: str): + """Set the mode. + example: `"normal"`, `"loopback"`, `"silent"`, `"silent_loopback"` + """ + + def enable(self): + """Enable the CAN.""" + + def disable(self): + """Disable the CAN.""" + + def write(self, data: str): + """Write string to the CAN.""" + + def writeBytes(self, data: bytes, length: int): + """Write bytes to the CAN.""" + + def read(self, length: int) -> str: + """Read string from the CAN.""" + + def readBytes(self, length: int) -> bytes: + """Read bytes from the CAN.""" + + def addFilter(self, id: int, ide: int, rtr: int, mode: int, mask: int, hdr: int): + """Add a filter.""" + + @abstractmethod + def platformEnable(self): ... + + @abstractmethod + def platformWrite(self): ... + + @abstractmethod + def platformWriteBytes(self): ... + + @abstractmethod + def platformRead(self): ... + + @abstractmethod + def platformReadBytes(self): ... + + @abstractmethod + def platformDisable(self): ... + + +class BaseDev: + @PIKA_C_MACRO_IF("PIKA_EVENT_ENABLE") + def addEventCallBack(self, eventCallback: any): + """ Add an event callback. """ + + @abstractmethod + @PIKA_C_MACRO_IF("PIKA_EVENT_ENABLE") + def platformGetEventId(self): ... diff --git a/examples/pikapython/pikapython/PikaStdLib.pyi b/examples/pikapython/pikapython/PikaStdLib.pyi index a84b5ad2..4e702519 100644 --- a/examples/pikapython/pikapython/PikaStdLib.pyi +++ b/examples/pikapython/pikapython/PikaStdLib.pyi @@ -19,6 +19,9 @@ class SysObj: @staticmethod def int(arg: any) -> int: ... + @staticmethod + def bool(arg: any) -> bool: ... + @staticmethod def float(arg: any) -> float: ... @@ -55,6 +58,10 @@ class SysObj: @PIKA_C_MACRO_IF("PIKA_BUILTIN_STRUCT_ENABLE") def dict(*val) -> any: ... + @staticmethod + @PIKA_C_MACRO_IF("PIKA_BUILTIN_STRUCT_ENABLE") + def tuple(arg: any) -> any: ... + @staticmethod @PIKA_C_MACRO_IF("!PIKA_NANO_ENABLE") def hex(val: int) -> str: ... @@ -85,7 +92,7 @@ class SysObj: @staticmethod @PIKA_C_MACRO_IF("!PIKA_NANO_ENABLE") - def dir(obj: object) -> list: ... + def dir(obj: any) -> list: ... @staticmethod @PIKA_C_MACRO_IF("PIKA_EXEC_ENABLE") @@ -119,6 +126,10 @@ class SysObj: @PIKA_C_MACRO_IF("!PIKA_NANO_ENABLE") def help(name: str): ... + @staticmethod + @PIKA_C_MACRO_IF("!PIKA_NANO_ENABLE") + def reboot(): ... + @PIKA_C_MACRO_IF("0") class RangeObj: diff --git a/examples/pikapython/pikapython/_modbus.pyi b/examples/pikapython/pikapython/_modbus.pyi new file mode 100755 index 00000000..dbac725e --- /dev/null +++ b/examples/pikapython/pikapython/_modbus.pyi @@ -0,0 +1,32 @@ +class _ModBus: + def setSlave(self, slave: int): ... + + def serializeReadBits(self, addr: int, nb: int) -> int: ... + def serializeReadInputBits(self, addr: int, nb: int) -> int: ... + def serializeReadRegisters(self, addr: int, nb: int) -> int: ... + def serializeReadInputRegisters(self, addr: int, nb: int) -> int: ... + def serializeWriteBit(self, addr: int, status: int) -> int: ... + def serializeWriteRegister(self, addr: int, value: int) -> int: ... + def serializeMaskWriteRegister(self, addr: int, andMask: int, orMask: int) -> int: ... + def serializeReportSlaveId(self) -> int: ... + + def serializeWriteAndReadRegisters(self, writeAddr: int, writeNb: int, src: bytes, readAddr: int, readNb: int) -> int: ... + def serializeWriteBits(self, addr: int, nb: int, src: bytes) -> int: ... + def serializeWriteRegisters(self, addr: int, nb: int, src: bytes) -> int: ... + + def deserializeWriteBit(self, msgLength: int) -> int: ... + def deserializeWriteRegister(self, msgLength: int) -> int: ... + def deserializeWriteBits(self, msgLength: int) -> int: ... + def deserializeWriteRegisters(self, msgLength: int) -> int: ... + def deserializeMaskWriteRegister(self, msgLength: int) -> int: ... + def deserializeReadBits(self, msgLength: int) -> bytes: ... + def deserializeReadInputBits(self, msgLength: int) -> bytes: ... + def deserializeReadRegisters(self, msgLength: int) -> bytes: ... + def deserializeReadInputRegisters(self, msgLength: int) -> bytes: ... + def deserializeWriteAndReadRegisters(self, msgLength: int) -> bytes: ... + def deserializeReportSlaveId(self, msgLength: int, maxDest: int) -> bytes: ... + + def getSendBuff(self) -> bytes: ... + def getReadBuff(self) -> bytes: ... + def __init__rtu(self, sendBuffSize: int, readBuffSize: int): ... + def __init__tcp(self, sendBuffSize: int, readBuffSize: int): ... diff --git a/examples/pikapython/pikapython/_thread.pyi b/examples/pikapython/pikapython/_thread.pyi new file mode 100755 index 00000000..7df51cf3 --- /dev/null +++ b/examples/pikapython/pikapython/_thread.pyi @@ -0,0 +1,2 @@ + +def start_new_thread(function: any, args_: any): ... diff --git a/examples/pikapython/pikapython/_time.pyi b/examples/pikapython/pikapython/_time.pyi new file mode 100755 index 00000000..bfd9f855 --- /dev/null +++ b/examples/pikapython/pikapython/_time.pyi @@ -0,0 +1,52 @@ +from PikaObj import * + + +def __init__(self): ... + + +@PIKA_C_MACRO_IF("PIKA_STD_DEVICE_UNIX_TIME_ENABLE") +def time(self) -> float: + """Get the current time.""" + + +@PIKA_C_MACRO_IF("PIKA_STD_DEVICE_UNIX_TIME_ENABLE") +def time_ns(self) -> int: + """Get the current time in nanoseconds.""" + + +@PIKA_C_MACRO_IF("PIKA_STD_DEVICE_UNIX_TIME_ENABLE") +def gmtime(self, unix_time: float): + """Convert unix time to struct_time.""" + + +@PIKA_C_MACRO_IF("PIKA_STD_DEVICE_UNIX_TIME_ENABLE") +def localtime(self, unix_time: float): + """Convert unix time to struct_time.""" + + +@PIKA_C_MACRO_IF("PIKA_STD_DEVICE_UNIX_TIME_ENABLE") +def mktime(self) -> int: + """Convert struct_time to unix time.""" + + +@PIKA_C_MACRO_IF("PIKA_STD_DEVICE_UNIX_TIME_ENABLE") +def asctime(self): + """Convert struct_time to string.""" + + +@PIKA_C_MACRO_IF("PIKA_STD_DEVICE_UNIX_TIME_ENABLE") +def ctime(self, unix_time: float): + """Convert unix time to string.""" + + +@abstractmethod +def sleep_s(self, s: int): ... + + +@abstractmethod +def sleep_ms(self, ms: int): ... + + +@abstractmethod +@PIKA_C_MACRO_IF("PIKA_STD_DEVICE_UNIX_TIME_ENABLE") +def platformGetTick(): ... diff --git a/examples/pikapython/pikapython/binascii.pyi b/examples/pikapython/pikapython/binascii.pyi new file mode 100755 index 00000000..29378862 --- /dev/null +++ b/examples/pikapython/pikapython/binascii.pyi @@ -0,0 +1,2 @@ +def b2a_hex(val: any) -> bytes: ... +def a2b_hex(val: str) -> bytes: ... diff --git a/examples/pikapython/pikapython/configparser.py b/examples/pikapython/pikapython/configparser.py new file mode 100755 index 00000000..7eddd5aa --- /dev/null +++ b/examples/pikapython/pikapython/configparser.py @@ -0,0 +1,110 @@ + +class ConfigParser(): + content = '' + config_dict = {} + + def _parse(self): + self.content = self.content.replace('\r', '') + content = self.content + lines = content.split('\n') + for line in lines: + if line.startswith('#'): + continue + if line.startswith(';'): + continue + if line.startswith('['): + section = line.replace('[', '') + section = section.replace(']', '') + self.config_dict[section] = {} + continue + + if line.strip() == '': + continue + + stmt = line.split('=') + key = stmt[0].strip() + value = _getvalue(stmt).strip() + section_dict = self.config_dict[section] + section_dict[key] = value + + def sections(self): + section_keys = self.config_dict.keys() + sections = [] + for section_item in section_keys: + sections.append(section_item) + return sections + + def options(self, section): + section_dict = self.config_dict[section] + option_keys = section_dict.keys() + options = [] + for option_item in option_keys: + options.append(option_item) + return options + + def get(self, section, option): + section_dict = self.config_dict[section] + return section_dict[option] + + def set(self, section, option, value): + section_dict = self.config_dict[section] + section_dict[option] = value + + # support config[key] = val + def __setitem__(self, __key, __val): + self.config_dict[__key] = __val + + # support val = config[key] + def __getitem__(self, __key): + return self.config_dict[__key] + + def items(self, section): + section_dict = self.config_dict[section] + section_keys = section_dict.keys() + items = [] + for key in section_keys: + val = section_dict[key] + items.append([key, val]) + return items + + def __str__(self): + content = '' + section_keys = self.config_dict.keys() + for section_item in section_keys: + content += '[' + section_item + ']\n' + section_dict = self.config_dict[section_item] + section_keys = section_dict.keys() + for key in section_keys: + val = section_dict[key] + content += key + ' = ' + val + '\n' + content += '\n' + return content + + def write(self, file_name): + print('Error: write() method not implemented') + raise + self.content = self.__str__(self) + print(self.content) + + def read_string(self, content): + self.content = content + self._parse() + + def read(self, file_name): + print('Error: read() method not implemented') + raise + content = '' + self.content = content + self._parse() + +def _getvalue(stmt): + index = 0 + val = '' + for item in stmt: + if index > 0: + if val != '': + val += ('=' + item) + else: + val += item + index = index + 1 + return val diff --git a/examples/pikapython/pikapython/example.py b/examples/pikapython/pikapython/example.py new file mode 100755 index 00000000..9edd2d16 --- /dev/null +++ b/examples/pikapython/pikapython/example.py @@ -0,0 +1,18 @@ +import machine +import time + +def led_blink(): + led0 = machine.LED(0) + led1 = machine.LED(1) + for i in range(10): + led0.on() + led1.off() + time.sleep(0.1) + led0.off() + led1.on() + time.sleep(0.1) + led0.off() + led1.off() + led0.close() + led1.close() + diff --git a/examples/pikapython/pikapython/json.py b/examples/pikapython/pikapython/json.py new file mode 100755 index 00000000..dc71012e --- /dev/null +++ b/examples/pikapython/pikapython/json.py @@ -0,0 +1,72 @@ +import pika_cjson as cjson + + +def _cjson_encode(cjson: cjson.cJSON): + if cjson == None: + return None + elif cjson.isInvalid(): + return None + elif cjson.isFalse(): + return False + elif cjson.isTrue(): + return True + elif cjson.isNull(): + return None + elif cjson.isNumber(): + return cjson.getValueDouble() + elif cjson.isString(): + return cjson.getValueString() + elif cjson.isArray(): + res = [] + for i in range(cjson.getArraySize()): + res.append(_cjson_encode(cjson.getArrayItem(i))) + return res + elif cjson.isObject(): + res = {} + child = cjson.getChild() + for i in range(cjson.getArraySize()): + key = child.getString() + res[key] = _cjson_encode(child) + child = child.getNext() + return res + elif cjson.isRaw(): + return cjson.getString() + else: + return None + + +def loads(json: str) -> dict: + cj = cjson.Parse(json) + return _cjson_encode(cj) + + +def _cjson_decode(d: dict): + if d == None: + return cjson.Null() + elif type(d) == int: + return cjson.Number(d) + elif type(d) == float: + return cjson.Number(d) + elif type(d) == bool: + if d: + return cjson.True_() + else: + return cjson.False_() + elif type(d) == str: + return cjson.String(d) + elif type(d) == list: + res = cjson.Array() + for i in d: + res.addItemToArray(_cjson_decode(i)) + return res + elif type(d) == dict: + res = cjson.Object() + for k, v in d.items(): + res.addItemToObject(k, _cjson_decode(v)) + return res + else: + return cjson.Null() + + +def dumps(d: dict) -> str: + return _cjson_decode(d).print() diff --git a/examples/pikapython/pikapython/machine.py b/examples/pikapython/pikapython/machine.py new file mode 100755 index 00000000..84c13545 --- /dev/null +++ b/examples/pikapython/pikapython/machine.py @@ -0,0 +1,37 @@ +import PikaStdDevice + + +class UART(PikaStdDevice.UART): + pass + + +class GPIO(PikaStdDevice.GPIO): + pass + + +class ADC(PikaStdDevice.ADC): + pass + + +class DAC(PikaStdDevice.DAC): + pass + + +class LED(GPIO): + pin: str = None + + def __init__(self, id: int): + super().__init__() + if id == 0: + self.pin = 'P27' + elif id == 1: + self.pin = 'P28' + self.setMode('out') + self.enable() + self.high() + + def on(self): + self.low() + + def off(self): + self.high() diff --git a/examples/pikapython/pikapython/main.py b/examples/pikapython/pikapython/main.py index c31a56ca..6f34e67f 100644 --- a/examples/pikapython/pikapython/main.py +++ b/examples/pikapython/pikapython/main.py @@ -1 +1,17 @@ +import PikaStdLib +import random +import PikaStdData +import configparser +import pika_cjson +import PikaMath +import unittest +import re +import binascii +import modbus +import time +import pika_lvgl +import _thread +import machine +import example +import json print('hello PikaPython!') diff --git a/examples/pikapython/pikapython/modbus.py b/examples/pikapython/pikapython/modbus.py new file mode 100755 index 00000000..c0f020e7 --- /dev/null +++ b/examples/pikapython/pikapython/modbus.py @@ -0,0 +1,99 @@ +import _modbus + + +class ModBus(_modbus._ModBus): + + def serializeWriteBits(self, addr: int, src: list) -> bytes: + lenth = super().serializeWriteBits(addr, len(list), bytes(src)) + return self.sendBuff[0:lenth] + + def serializeWriteRegisters(self, addr: int, src: list) -> bytes: + _src = bytes(2 * len(src)) + for i in range(len(src)): + _src[2 * i] = src[i] % 256 + _src[2 * i + 1] = src[i] // 256 + lenth = super().serializeWriteRegisters(addr, len(src), _src) + return self.sendBuff[0:lenth] + + def serializeReadBits(self, addr: int, nb: int) -> bytes: + lenth = super().serializeReadBits(addr, nb) + return self.sendBuff[0:lenth] + + def serializeReadInputBits(self, addr: int, nb: int) -> bytes: + lenth = super().serializeReadInputBits(addr, nb) + return self.sendBuff[0:lenth] + + def serializeReadRegisters(self, addr: int, nb: int) -> bytes: + lenth = super().serializeReadRegisters(addr, nb) + return self.sendBuff[0:lenth] + + def serializeReadInputRegisters(self, addr: int, nb: int) -> bytes: + lenth = super().serializeReadInputRegisters(addr, nb) + return self.sendBuff[0:lenth] + + def serializeWriteBit(self, addr: int, status: int) -> bytes: + lenth = super().serializeWriteBit(addr, status) + return self.sendBuff[0:lenth] + + def serializeWriteRegister(self, addr: int, value: int) -> bytes: + lenth = super().serializeWriteRegister(addr, value) + return self.sendBuff[0:lenth] + + def serializeMaskWriteRegister(self, + addr: int, + andMask: int, + orMask: int) -> bytes: + lenth = super().serializeMaskWriteRegister(addr, andMask, orMask) + return self.sendBuff[0:lenth] + + def serializeReportSlaveId(self) -> int: + lenth = super().serializeReportSlaveId() + return self.sendBuff[0:lenth] + + def deserializeReadRegisters(self, msg: bytes) -> list: + self.readBuff = msg + dest = super().deserializeReadRegisters(len(msg)) + ret = [] + for i in range(0, len(dest), 2): + ret.append(int(dest[i]) + int(dest[i + 1]) * 256) + return ret + + def deserializeReadBits(self, msg: bytes) -> list: + self.readBuff = msg + length = len(msg) + dest = super().deserializeReadBits(length) + return list(dest) + + def deserializeReadInputBits(self, msg: bytes) -> list: + self.readBuff = msg + length = len(msg) + dest = super().deserializeReadInputBits(length) + return list(dest) + + def deserializeReadInputRegisters(self, msg: bytes) -> list: + self.readBuff = msg + length = len(msg) + dest = super().deserializeReadInputRegisters(length) + ret = [] + for i in range(0, len(dest), 2): + ret.append(int(dest[i]) + int(dest[i + 1]) * 256) + return ret + + def deserializeWriteAndReadRegisters(self, msg: bytes) -> list: + self.readBuff = msg + length = len(msg) + dest = super().deserializeWriteAndReadRegisters(length) + ret = [] + for i in range(0, len(dest), 2): + ret.append(int(dest[i]) + int(dest[i + 1]) * 256) + return ret + + +class ModBusRTU(ModBus): + def __init__(self, sendBuffSize: int, readBuffSize: int): + self.__init__rtu(sendBuffSize, readBuffSize) + + +class ModBusTCP(ModBus): + def __init__(self, sendBuffSize: int, readBuffSize: int): + self.__init__tcp(sendBuffSize, readBuffSize) diff --git a/examples/pikapython/pikapython/pika_cjson.pyi b/examples/pikapython/pikapython/pika_cjson.pyi new file mode 100755 index 00000000..5285e222 --- /dev/null +++ b/examples/pikapython/pikapython/pika_cjson.pyi @@ -0,0 +1,91 @@ +from PikaObj import * + + +class cJSON(TinyObj): + cJSON_Invalid: int + cJSON_False: int + cJSON_True: int + cJSON_NULL: int + cJSON_Number: int + cJSON_String: int + cJSON_Array: int + cJSON_Object: int + cJSON_Raw: int + def print(self) -> str: ... + def __del__(self): ... + def __init__(self): ... + def getObjectItem(self, string: str) -> cJSON: ... + def getArrayItem(self, index: int) -> cJSON: ... + def getArraySize(self) -> int: ... + def getType(self) -> int: ... + def getNext(self) -> cJSON: ... + def getPrev(self) -> cJSON: ... + def getChild(self) -> cJSON: ... + def getValueString(self) -> str: ... + def getValueInt(self) -> int: ... + def getValueDouble(self) -> float: ... + def getString(self) -> str: ... + def getValue(self) -> any: ... + def isInvalid(self) -> int: ... + def isFalse(self) -> int: ... + def isTrue(self) -> int: ... + def isBool(self) -> int: ... + def isNull(self) -> int: ... + def isNumber(self) -> int: ... + def isString(self) -> int: ... + def isArray(self) -> int: ... + def isObject(self) -> int: ... + def isRaw(self) -> int: ... + def addItemToArray(self, item: cJSON): ... + def addItemToObject(self, string: str, item: cJSON): ... + + +def Parse(value: str) -> cJSON: ... + + +class Null(cJSON): + def __init__(self): ... + + +class True_(cJSON): + def __init__(self): ... + + +class False_(cJSON): + def __init__(self): ... + + +class Bool(cJSON): + def __init__(self, bolean: int): ... + + +class Number(cJSON): + def __init__(self, num: float): ... + + +class String(cJSON): + def __init__(self, string: str): ... + + +class Raw(cJSON): + def __init__(self, raw: str): ... + + +class Array(cJSON): + def __init__(self): ... + + +class Object(cJSON): + def __init__(self): ... + + +class StringReference(cJSON): + def __init__(self, string: str): ... + + +class ObjectReference(cJSON): + def __init__(self, child: cJSON): ... + + +class ArrayReference(cJSON): + def __init__(self, child: cJSON): ... diff --git a/examples/pikapython/pikapython/pika_lvgl.pyi b/examples/pikapython/pikapython/pika_lvgl.pyi new file mode 100755 index 00000000..59493766 --- /dev/null +++ b/examples/pikapython/pikapython/pika_lvgl.pyi @@ -0,0 +1,574 @@ +from tkinter import HIDDEN +from PikaObj import * + + +def __init__(): ... + + +class EVENT: + ALL: int + PRESSED: int + PRESSING: int + PRESS_LOST: int + SHORT_CLICKED: int + LONG_PRESSED: int + LONG_PRESSED_REPEAT: int + CLICKED: int + RELEASED: int + SCROLL_BEGIN: int + SCROLL_END: int + SCROLL: int + GESTURE: int + KEY: int + FOCUSED: int + DEFOCUSED: int + LEAVE: int + HIT_TEST: int + COVER_CHECK: int + REFR_EXT_DRAW_SIZE: int + DRAW_MAIN_BEGIN: int + DRAW_MAIN: int + DRAW_MAIN_END: int + DRAW_POST_BEGIN: int + DRAW_POST: int + DRAW_POST_END: int + DRAW_PART_BEGIN: int + DRAW_PART_END: int + VALUE_CHANGED: int + INSERT: int + REFRESH: int + READY: int + CANCEL: int + DELETE: int + CHILD_CHANGED: int + CHILD_CREATED: int + CHILD_DELETED: int + SCREEN_UNLOAD_START: int + SCREEN_LOAD_START: int + SCREEN_LOADED: int + SCREEN_UNLOADED: int + SIZE_CHANGED: int + STYLE_CHANGED: int + LAYOUT_CHANGED: int + GET_SELF_SIZE: int + PREPROCESS: int + def __init__(self): ... + + +class ALIGN: + DEFAULT: int + TOP_LEFT: int + TOP_MID: int + TOP_RIGHT: int + BOTTOM_LEFT: int + BOTTOM_MID: int + BOTTOM_RIGHT: int + LEFT_MID: int + RIGHT_MID: int + CENTER: int + OUT_TOP_LEFT: int + OUT_TOP_MID: int + OUT_TOP_RIGHT: int + OUT_BOTTOM_LEFT: int + OUT_BOTTOM_MID: int + OUT_BOTTOM_RIGHT: int + OUT_LEFT_TOP: int + OUT_LEFT_MID: int + OUT_LEFT_BOTTOM: int + OUT_RIGHT_TOP: int + OUT_RIGHT_MID: int + OUT_RIGHT_BOTTOM: int + def __init__(self): ... + + +class PALETTE: + RED: int + PINK: int + PURPLE: int + DEEP_PURPLE: int + INDIGO: int + BLUE: int + LIGHT_BLUE: int + CYAN: int + TEAL: int + GREEN: int + LIGHT_GREEN: int + LIME: int + YELLOW: int + AMBER: int + ORANGE: int + DEEP_ORANGE: int + BROWN: int + BLUE_GREY: int + GREY: int + NONE: int + def __init__(self): ... + + +class OPA: + TRANSP: int + COVER: int + def __init__(self): ... + + +class ANIM: + OFF: int + ON: int + def __init__(self): ... + + +class STATE: + DEFAULT: int + CHECKED: int + FOCUSED: int + FOCUS_KEY: int + EDITED: int + HOVERED: int + PRESSED: int + SCROLLED: int + DISABLED: int + USER_1: int + USER_2: int + USER_3: int + USER_4: int + ANY: int + def __init__(self): ... + + +class TEXT_DECOR: + NONE: int + UNDERLINE: int + STRIKETHROUGH: int + def __init__(self): ... + + +class lv_event: + def get_code(self) -> int: ... + def get_target(self) -> lv_obj: ... + + +class lv_color_t: + ... + + +def lv_color_hex(hex: int64) -> lv_color_t: ... + + +class lv_timer_t: + def set_period(period: int): ... + def set_cb(cb: any): ... + def _del(self): ... + + +def palette_lighten(p: int, lvl: int) -> lv_color_t: ... +def palette_main(p: int) -> lv_color_t: ... + + +class style_t: + def __init__(self): ... + def init(self): ... + def set_width(self, value: int): ... + def set_min_width(self, value: int): ... + def set_max_width(self, value: int): ... + def set_height(self, value: int): ... + def set_min_height(self, value: int): ... + def set_max_height(self, value: int): ... + def set_x(self, value: int): ... + def set_y(self, value: int): ... + def set_align(self, value: int): ... + def set_transform_width(self, value: int): ... + def set_transform_height(self, value: int): ... + def set_translate_x(self, value: int): ... + def set_translate_y(self, value: int): ... + def set_transform_zoom(self, value: int): ... + def set_transform_angle(self, value: int): ... + def set_transform_pivot_x(self, value: int): ... + def set_transform_pivot_y(self, value: int): ... + def set_pad_top(self, value: int): ... + def set_pad_bottom(self, value: int): ... + def set_pad_left(self, value: int): ... + def set_pad_right(self, value: int): ... + def set_pad_row(self, value: int): ... + def set_pad_column(self, value: int): ... + def set_bg_color(self, value: lv_color_t): ... + def set_bg_opa(self, value: int): ... + def set_bg_grad_color(self, value: lv_color_t): ... + def set_bg_grad_dir(self, value: int): ... + def set_bg_main_stop(self, value: int): ... + def set_bg_grad_stop(self, value: int): ... + # def set_bg_grad(self, value: lv_grad_dsc_t):... + def set_bg_dither_mode(self, value: int): ... + def set_bg_img_src(self, value: bytes): ... + def set_bg_img_opa(self, value: int): ... + def set_bg_img_recolor(self, value: lv_color_t): ... + def set_bg_img_recolor_opa(self, value: int): ... + def set_bg_img_tiled(self, value: int): ... + def set_border_color(self, value: lv_color_t): ... + def set_border_opa(self, value: int): ... + def set_border_width(self, value: int): ... + def set_border_side(self, value: int): ... + def set_border_post(self, value: int): ... + def set_outline_width(self, value: int): ... + def set_outline_color(self, value: lv_color_t): ... + def set_outline_opa(self, value: int): ... + def set_outline_pad(self, value: int): ... + def set_shadow_width(self, value: int): ... + def set_shadow_ofs_x(self, value: int): ... + def set_shadow_ofs_y(self, value: int): ... + def set_shadow_spread(self, value: int): ... + def set_shadow_color(self, value: lv_color_t): ... + def set_shadow_opa(self, value: int): ... + def set_img_opa(self, value: int): ... + def set_img_recolor(self, value: lv_color_t): ... + def set_img_recolor_opa(self, value: int): ... + def set_line_width(self, value: int): ... + def set_line_dash_width(self, value: int): ... + def set_line_dash_gap(self, value: int): ... + def set_line_rounded(self, value: int): ... + def set_line_color(self, value: lv_color_t): ... + def set_line_opa(self, value: int): ... + def set_arc_width(self, value: int): ... + def set_arc_rounded(self, value: int): ... + def set_arc_color(self, value: lv_color_t): ... + def set_arc_opa(self, value: int): ... + def set_arc_img_src(self, value: bytes): ... + def set_text_color(self, value: lv_color_t): ... + def set_text_opa(self, value: int): ... + # def set_text_font(self, value: lv_font_t): ... + def set_text_letter_space(self, value: int): ... + def set_text_line_space(self, value: int): ... + def set_text_decor(self, value: int): ... + def set_text_align(self, value: int): ... + def set_radius(self, value: int): ... + def set_clip_corner(self, value: int): ... + def set_opa(self, value: int): ... + # def set_color_filter_dsc(self, value: lv_color_filter_dsc_t): ... + def set_color_filter_opa(self, value: int): ... + # def set_anim(self, value: lv_anim_t): ... + def set_anim_time(self, value: int): ... + def set_anim_speed(self, value: int): ... + # def set_transition(self, value: lv_style_transition_dsc_t): ... + def set_blend_mode(self, value: int): ... + def set_layout(self, value: int): ... + def set_base_dir(self, value: int): ... + def reset(self): ... + def register_prop(self, flag: int) -> int: ... + def get_num_custom_props(self) -> int: ... + def remove_prop(self, prop: int) -> int: ... + # def set_prop(self, prop: int, value: lv_style_value_t): ... + # def set_prop_meta(self, prop: int, meta: int): ... + # def get_prop(self, prop: int, value: lv_style_value_t) -> int: ... + # def transition_dsc_init(self, tr: lv_style_transition_dsc_t, props: int, path_cb: int, time: int, delay: int, user_data: int): ... + # def prop_get_default(self, prop: int) -> lv_style_value_t: ... + def is_empty(self) -> int: ... + def set_size(self, value: int): ... + def set_pad_all(self, value: int): ... + def set_pad_hor(self, value: int): ... + def set_pad_ver(self, value: int): ... + def set_pad_gap(self, value: int): ... + def prop_has_flag(self, prop: int, flag: int) -> int: ... + def set_flex_flow(self, value: int): ... + def set_flex_main_place(self, value: int): ... + def set_flex_cross_place(self, value: int): ... + def set_flex_track_place(self, value: int): ... + def set_flex_grow(self, value: int): ... + + +class LAYOUT_FLEX: + value: int + def __init__(self): ... + + +class SIZE: + CONTENT: int + def __init__(self): ... + + +class flag_t: + HIDDEN: int + CLICKABLE: int + CLICK_FOCUSABLE: int + CHECKABLE: int + SCROLLABLE: int + SCROLL_ELASTIC: int + SCROLL_MOMENTUM: int + SCROLL_ONE: int + SCROLL_CHAIN_HOR: int + SCROLL_CHAIN_VER: int + SCROLL_CHAIN: int + SCROLL_ON_FOCUS: int + SCROLL_WITH_ARROW: int + SNAPPABLE: int + PRESS_LOCK: int + EVENT_BUBBLE: int + GESTURE_BUBBLE: int + ADV_HITTEST: int + IGNORE_LAYOUT: int + FLOATING: int + OVERFLOW_VISIBLE: int + LAYOUT_1: int + LAYOUT_2: int + WIDGET_1: int + WIDGET_2: int + USER_1: int + USER_2: int + USER_3: int + USER_4: int + def __init__(self): ... + + +class FLEX_FLOW: + ROW: int + COLUMN: int + ROW_WRAP: int + ROW_REVERSE: int + ROW_WRAP_REVERSE: int + COLUMN_WRAP: int + COLUMN_REVERSE: int + COLUMN_WRAP_REVERSE: int + def __init__(self): ... + + +class lv_obj: + def __init__(self, parent: lv_obj): ... + def add_state(self, state: int): ... + def add_flag(self, flag: int): ... + def clear_flag(self, flag: int): ... + def add_event_cb(self, event_cb: any, filter: int, user_data: pointer): ... + def add_style(self, style: style_t, selector: int): ... + def set_pos(self, x: int, y: int): ... + def set_x(self, x: int): ... + def set_y(self, y: int): ... + def set_size(self, w: int, h: int): ... + def refr_size(self) -> int: ... + def set_width(self, w: int): ... + def set_height(self, h: int): ... + def set_content_width(self, w: int): ... + def set_content_height(self, h: int): ... + def set_layout(self, layout: int): ... + def is_layout_positioned(self) -> int: ... + def mark_layout_as_dirty(self): ... + def update_layout(self): ... + def set_align(self, align: int): ... + def align(self, align: int, x_ofs: int, y_ofs: int): ... + def align_to(self, base: lv_obj, align: int, x_ofs: int, y_ofs: int): ... + def center(self): ... + # def get_coords(self, coords: lv_area_t): ... + def get_x(self) -> int: ... + def get_x2(self) -> int: ... + def get_y(self) -> int: ... + def get_y2(self) -> int: ... + def get_x_aligned(self) -> int: ... + def get_y_aligned(self) -> int: ... + def get_width(self) -> int: ... + def get_height(self) -> int: ... + def get_content_width(self) -> int: ... + def get_content_height(self) -> int: ... + # def get_content_coords(self, area: lv_area_t): ... + def get_self_width(self) -> int: ... + def get_self_height(self) -> int: ... + def refresh_self_size(self) -> int: ... + def refr_pos(self): ... + def move_to(self, x: int, y: int): ... + def move_children_by(self, x_diff: int, y_diff: int, + ignore_floating: int): ... + + def transform_point(self, p: point_t, recursive: int, inv: int): ... + # def get_transformed_area(self, area: lv_area_t, recursive: int, inv: int): ... + # def invalidate_area(self, area: lv_area_t): ... + def invalidate(self): ... + # def area_is_visible(self, area: lv_area_t) -> int: ... + def is_visible(self) -> int: ... + def set_ext_click_area(self, size: int): ... + # def get_click_area(self, area: lv_area_t): ... + def hit_test(self, point: point_t) -> int: ... + def set_flex_flow(self, flow: int): ... + def set_flex_grow(self, value: int): ... + def set_flex_align(self, main_place: int, + cross_place: int, align: int): ... + + def set_id(self, id: str): ... + def get_id(self) -> str: ... + def clean(self): ... + + +class indev_t: + def get_vect(self, point: point_t): ... + + +class FLEX_ALIGN: + START: int + END: int + CENTER: int + SPACE_EVENLY: int + SPACE_AROUND: int + SPACE_BETWEEN: int + def __init__(self): ... + + +class obj(lv_obj): + FLAG: flag_t + def __init__(self, *parent): ... + + +def indev_get_act() -> indev_t: ... + + +class point_t: + def __init__(self): ... + + +class arc(lv_obj): + MODE_NORMAL: int + MODE_SYMMETRICAL: int + MODE_REVERSE: int + def __init__(self, parent: lv_obj): ... + def set_start_angle(self, start: int): ... + def set_end_angle(self, angle: int): ... + def set_angles(self, start: int, end: int): ... + def set_bg_start_angle(self, start: int): ... + def set_bg_end_angle(self, angle: int): ... + def set_bg_angles(self, start: int, end: int): ... + def set_rotation(self, rotation: int): ... + def set_mode(self, mode: int): ... + def set_value(self, value: int): ... + def set_range(self, min: int, max: int): ... + def set_change_rate(self, rate: int): ... + def get_angle_start(self) -> int: ... + def get_angle_end(self) -> int: ... + def get_bg_angle_start(self) -> int: ... + def get_bg_angle_end(self) -> int: ... + def get_value(self) -> int: ... + def get_min_value(self) -> int: ... + def get_max_value(self) -> int: ... + def get_mode(self) -> int: ... + # def get_rotation(self) -> int: ... + + +class bar(lv_obj): + def __init__(self, parent: lv_obj): ... + def set_value(self, value: int, anim: int): ... + def set_start_value(self, start_value: int, anim: int): ... + def set_range(self, min: int, max: int): ... + def set_mode(self, mode: int): ... + def get_value(self) -> int: ... + def get_start_value(self) -> int: ... + def get_min_value(self) -> int: ... + def get_max_value(self) -> int: ... + def get_mode(self) -> int: ... + + +class btn(lv_obj): + def __init__(self, parent: lv_obj): ... + + +class checkbox(lv_obj): + def __init__(self, parent: lv_obj): ... + def set_text(self, txt: str): ... + def set_text_static(self, txt: str): ... + def get_text(self) -> str: ... + + +class dropdown(lv_obj): + def __init__(self, parent: lv_obj): ... + def set_text(self, txt: str): ... + def set_options(self, options: str): ... + def add_option(self, option: str, pos: int): ... + def clear_options(self): ... + def set_selected(self, sel_opt: int): ... + def set_dir(self, dir: int): ... + def set_symbol(self, symbol: str): ... + def set_selected_hightlight(self, en: int): ... + # def get_list(self) -> lv_obj: ... + def get_text(self) -> str: ... + def get_options(self) -> str: ... + def get_selected(self) -> int: ... + def get_option_cnt(self) -> int: ... + def get_selected_str(self) -> str: ... + def get_option_index(self, option: str) -> int: ... + def get_symbol(self) -> str: ... + def get_selected_highlight(self) -> int: ... + def get_dir(self) -> int: ... + def open(self): ... + def close(self): ... + def is_open(self) -> int: ... + + +class label(lv_obj): + def __init__(self, parent: lv_obj): ... + def set_text(self, txt: str): ... + def set_long_mode(self, mode: int): ... + def set_recolor(self, en: int): ... + def set_style_text_align(self, value: int, selector: int): ... + + +class roller(lv_obj): + def __init__(self, parent: lv_obj): ... + def set_options(self, options: str, mode: int): ... + def set_visible_row_count(self, row_cnt: int): ... + + +class slider(lv_obj): + def __init__(self, parent: lv_obj): ... + + +class switch(lv_obj): + def __init__(self, parent: lv_obj): ... + + +class table(lv_obj): + def __init__(self, parent: lv_obj): ... + def set_cell_value(self, row: int, col: int, txt: str): ... + + +class img_dsc_t: + def __init__(self, dsc_dict: dict): ... + + +class img(lv_obj): + def __init__(self, parent: lv_obj): ... + """ + void lv_img_set_src(lv_obj_t * obj, const void * src); + void lv_img_set_offset_x(lv_obj_t * obj, lv_coord_t x); + void lv_img_set_offset_y(lv_obj_t * obj, lv_coord_t y); + void lv_img_set_angle(lv_obj_t * obj, int16_t angle); + void lv_img_set_pivot(lv_obj_t * obj, lv_coord_t x, lv_coord_t y); + void lv_img_set_zoom(lv_obj_t * obj, uint16_t zoom); + void lv_img_set_antialias(lv_obj_t * obj, bool antialias); + void lv_img_set_size_mode(lv_obj_t * obj, lv_img_size_mode_t mode); + const void * lv_img_get_src(lv_obj_t * obj); + lv_coord_t lv_img_get_offset_x(lv_obj_t * obj); + lv_coord_t lv_img_get_offset_y(lv_obj_t * obj); + uint16_t lv_img_get_angle(lv_obj_t * obj); + void lv_img_get_pivot(lv_obj_t * obj, lv_point_t * pivot); + uint16_t lv_img_get_zoom(lv_obj_t * obj); + bool lv_img_get_antialias(lv_obj_t * obj); + lv_img_size_mode_t lv_img_get_size_mode(lv_obj_t * obj); + """ + + def set_src(self, src: img_dsc_t): ... + def set_offset_x(self, x: int): ... + def set_offset_y(self, y: int): ... + def set_angle(self, angle: int): ... + def set_pivot(self, x: int, y: int): ... + def set_zoom(self, zoom: int): ... + def set_antialias(self, antialias: int): ... + def set_size_mode(self, mode: int): ... + def get_src(self) -> img_dsc_t: ... + def get_offset_x(self) -> int: ... + def get_offset_y(self) -> int: ... + def get_angle(self) -> int: ... + # def get_pivot(self) -> lv_point: ... + def get_zoom(self) -> int: ... + def get_antialias(self) -> int: ... + def get_size_mode(self) -> int: ... + + +class textarea(lv_obj): + def __init__(self, parent: lv_obj): ... + def set_one_line(en: int): ... + + +def scr_act() -> lv_obj: ... +def pct(x: int) -> int: ... +def timer_create_basic() -> lv_timer_t: ... diff --git a/examples/pikapython/pikapython/pikascript-api/PikaDebug.h b/examples/pikapython/pikapython/pikascript-api/PikaDebug.h deleted file mode 100644 index 384668c7..00000000 --- a/examples/pikapython/pikapython/pikascript-api/PikaDebug.h +++ /dev/null @@ -1,22 +0,0 @@ -/* - * [Warning!] This file is auto-generated by pika compiler. - * Do not edit it manually. - * The source code is *.pyi file. - * More details: - * English Doc: - * https://pikadoc.readthedocs.io/en/latest/PikaScript%20%E6%A8%A1%E5%9D%97%E6%A6%82%E8%BF%B0.html - * Chinese Doc: - * https://pikadoc.readthedocs.io/zh/latest/PikaScript%20%E6%A8%A1%E5%9D%97%E6%A6%82%E8%BF%B0.html - */ - -#ifndef __PikaDebug__H -#define __PikaDebug__H -#include -#include -#include "PikaObj.h" - -PikaObj *New_PikaDebug(Args *args); - -Arg* PikaDebug_Debuger(PikaObj *self); - -#endif diff --git a/examples/pikapython/pikapython/pikascript-api/PikaDebug_Debuger.h b/examples/pikapython/pikapython/pikascript-api/PikaDebug_Debuger.h deleted file mode 100644 index 5a8f1b0d..00000000 --- a/examples/pikapython/pikapython/pikascript-api/PikaDebug_Debuger.h +++ /dev/null @@ -1,23 +0,0 @@ -/* - * [Warning!] This file is auto-generated by pika compiler. - * Do not edit it manually. - * The source code is *.pyi file. - * More details: - * English Doc: - * https://pikadoc.readthedocs.io/en/latest/PikaScript%20%E6%A8%A1%E5%9D%97%E6%A6%82%E8%BF%B0.html - * Chinese Doc: - * https://pikadoc.readthedocs.io/zh/latest/PikaScript%20%E6%A8%A1%E5%9D%97%E6%A6%82%E8%BF%B0.html - */ - -#ifndef __PikaDebug_Debuger__H -#define __PikaDebug_Debuger__H -#include -#include -#include "PikaObj.h" - -PikaObj *New_PikaDebug_Debuger(Args *args); - -void PikaDebug_Debuger___init__(PikaObj *self); -void PikaDebug_Debuger_set_trace(PikaObj *self); - -#endif diff --git a/examples/pikapython/pikapython/pikascript-api/PikaMain.h b/examples/pikapython/pikapython/pikascript-api/PikaMain.h deleted file mode 100644 index 38fa53ba..00000000 --- a/examples/pikapython/pikapython/pikascript-api/PikaMain.h +++ /dev/null @@ -1,21 +0,0 @@ -/* - * [Warning!] This file is auto-generated by pika compiler. - * Do not edit it manually. - * The source code is *.pyi file. - * More details: - * English Doc: - * https://pikadoc.readthedocs.io/en/latest/PikaScript%20%E6%A8%A1%E5%9D%97%E6%A6%82%E8%BF%B0.html - * Chinese Doc: - * https://pikadoc.readthedocs.io/zh/latest/PikaScript%20%E6%A8%A1%E5%9D%97%E6%A6%82%E8%BF%B0.html - */ - -#ifndef __PikaMain__H -#define __PikaMain__H -#include -#include -#include "PikaObj.h" - -PikaObj *New_PikaMain(Args *args); - - -#endif diff --git a/examples/pikapython/pikapython/pikascript-api/PikaStdData.h b/examples/pikapython/pikapython/pikascript-api/PikaStdData.h deleted file mode 100644 index 637de8e9..00000000 --- a/examples/pikapython/pikapython/pikascript-api/PikaStdData.h +++ /dev/null @@ -1,30 +0,0 @@ -/* - * [Warning!] This file is auto-generated by pika compiler. - * Do not edit it manually. - * The source code is *.pyi file. - * More details: - * English Doc: - * https://pikadoc.readthedocs.io/en/latest/PikaScript%20%E6%A8%A1%E5%9D%97%E6%A6%82%E8%BF%B0.html - * Chinese Doc: - * https://pikadoc.readthedocs.io/zh/latest/PikaScript%20%E6%A8%A1%E5%9D%97%E6%A6%82%E8%BF%B0.html - */ - -#ifndef __PikaStdData__H -#define __PikaStdData__H -#include -#include -#include "PikaObj.h" - -PikaObj *New_PikaStdData(Args *args); - -Arg* PikaStdData_ByteArray(PikaObj *self); -Arg* PikaStdData_Dict(PikaObj *self); -Arg* PikaStdData_FILEIO(PikaObj *self); -Arg* PikaStdData_List(PikaObj *self); -Arg* PikaStdData_String(PikaObj *self); -Arg* PikaStdData_Tuple(PikaObj *self); -Arg* PikaStdData_Utils(PikaObj *self); -Arg* PikaStdData_dict_items(PikaObj *self); -Arg* PikaStdData_dict_keys(PikaObj *self); - -#endif diff --git a/examples/pikapython/pikapython/pikascript-api/PikaStdData_ByteArray.h b/examples/pikapython/pikapython/pikascript-api/PikaStdData_ByteArray.h deleted file mode 100644 index 9f4ee428..00000000 --- a/examples/pikapython/pikapython/pikascript-api/PikaStdData_ByteArray.h +++ /dev/null @@ -1,28 +0,0 @@ -/* - * [Warning!] This file is auto-generated by pika compiler. - * Do not edit it manually. - * The source code is *.pyi file. - * More details: - * English Doc: - * https://pikadoc.readthedocs.io/en/latest/PikaScript%20%E6%A8%A1%E5%9D%97%E6%A6%82%E8%BF%B0.html - * Chinese Doc: - * https://pikadoc.readthedocs.io/zh/latest/PikaScript%20%E6%A8%A1%E5%9D%97%E6%A6%82%E8%BF%B0.html - */ - -#ifndef __PikaStdData_ByteArray__H -#define __PikaStdData_ByteArray__H -#include -#include -#include "PikaObj.h" - -PikaObj *New_PikaStdData_ByteArray(Args *args); - -int PikaStdData_ByteArray___getitem__(PikaObj *self, int __key); -void PikaStdData_ByteArray___init__(PikaObj *self, Arg* bytes); -Arg* PikaStdData_ByteArray___iter__(PikaObj *self); -Arg* PikaStdData_ByteArray___next__(PikaObj *self); -void PikaStdData_ByteArray___setitem__(PikaObj *self, int __key, int __val); -char* PikaStdData_ByteArray___str__(PikaObj *self); -char* PikaStdData_ByteArray_decode(PikaObj *self); - -#endif diff --git a/examples/pikapython/pikapython/pikascript-api/PikaStdData_Dict.h b/examples/pikapython/pikapython/pikascript-api/PikaStdData_Dict.h deleted file mode 100644 index 61f8d767..00000000 --- a/examples/pikapython/pikapython/pikascript-api/PikaStdData_Dict.h +++ /dev/null @@ -1,36 +0,0 @@ -/* - * [Warning!] This file is auto-generated by pika compiler. - * Do not edit it manually. - * The source code is *.pyi file. - * More details: - * English Doc: - * https://pikadoc.readthedocs.io/en/latest/PikaScript%20%E6%A8%A1%E5%9D%97%E6%A6%82%E8%BF%B0.html - * Chinese Doc: - * https://pikadoc.readthedocs.io/zh/latest/PikaScript%20%E6%A8%A1%E5%9D%97%E6%A6%82%E8%BF%B0.html - */ - -#ifndef __PikaStdData_Dict__H -#define __PikaStdData_Dict__H -#include -#include -#include "PikaObj.h" - -PikaObj *New_PikaStdData_Dict(Args *args); - -int PikaStdData_Dict___contains__(PikaObj *self, Arg* val); -void PikaStdData_Dict___del__(PikaObj *self); -Arg* PikaStdData_Dict___getitem__(PikaObj *self, Arg* __key); -void PikaStdData_Dict___init__(PikaObj *self); -Arg* PikaStdData_Dict___iter__(PikaObj *self); -int PikaStdData_Dict___len__(PikaObj *self); -Arg* PikaStdData_Dict___next__(PikaObj *self); -void PikaStdData_Dict___setitem__(PikaObj *self, Arg* __key, Arg* __val); -char* PikaStdData_Dict___str__(PikaObj *self); -Arg* PikaStdData_Dict_get(PikaObj *self, char* key); -PikaObj* PikaStdData_Dict_items(PikaObj *self); -PikaObj* PikaStdData_Dict_keys(PikaObj *self); -void PikaStdData_Dict_remove(PikaObj *self, char* key); -void PikaStdData_Dict_set(PikaObj *self, char* key, Arg* arg); -void PikaStdData_Dict_update(PikaObj *self, PikaObj* other); - -#endif diff --git a/examples/pikapython/pikapython/pikascript-api/PikaStdData_FILEIO.h b/examples/pikapython/pikapython/pikascript-api/PikaStdData_FILEIO.h deleted file mode 100644 index 5477e0b3..00000000 --- a/examples/pikapython/pikapython/pikascript-api/PikaStdData_FILEIO.h +++ /dev/null @@ -1,30 +0,0 @@ -/* - * [Warning!] This file is auto-generated by pika compiler. - * Do not edit it manually. - * The source code is *.pyi file. - * More details: - * English Doc: - * https://pikadoc.readthedocs.io/en/latest/PikaScript%20%E6%A8%A1%E5%9D%97%E6%A6%82%E8%BF%B0.html - * Chinese Doc: - * https://pikadoc.readthedocs.io/zh/latest/PikaScript%20%E6%A8%A1%E5%9D%97%E6%A6%82%E8%BF%B0.html - */ - -#ifndef __PikaStdData_FILEIO__H -#define __PikaStdData_FILEIO__H -#include -#include -#include "PikaObj.h" - -PikaObj *New_PikaStdData_FILEIO(Args *args); - -void PikaStdData_FILEIO_close(PikaObj *self); -int PikaStdData_FILEIO_init(PikaObj *self, char* path, char* mode); -Arg* PikaStdData_FILEIO_read(PikaObj *self, PikaTuple* size); -char* PikaStdData_FILEIO_readline(PikaObj *self); -PikaObj* PikaStdData_FILEIO_readlines(PikaObj *self); -int PikaStdData_FILEIO_seek(PikaObj *self, int offset, PikaTuple* fromwhere); -int PikaStdData_FILEIO_tell(PikaObj *self); -int PikaStdData_FILEIO_write(PikaObj *self, Arg* s); -void PikaStdData_FILEIO_writelines(PikaObj *self, PikaObj* lines); - -#endif diff --git a/examples/pikapython/pikapython/pikascript-api/PikaStdData_List.h b/examples/pikapython/pikapython/pikascript-api/PikaStdData_List.h deleted file mode 100644 index 3fe8840f..00000000 --- a/examples/pikapython/pikapython/pikascript-api/PikaStdData_List.h +++ /dev/null @@ -1,31 +0,0 @@ -/* - * [Warning!] This file is auto-generated by pika compiler. - * Do not edit it manually. - * The source code is *.pyi file. - * More details: - * English Doc: - * https://pikadoc.readthedocs.io/en/latest/PikaScript%20%E6%A8%A1%E5%9D%97%E6%A6%82%E8%BF%B0.html - * Chinese Doc: - * https://pikadoc.readthedocs.io/zh/latest/PikaScript%20%E6%A8%A1%E5%9D%97%E6%A6%82%E8%BF%B0.html - */ - -#ifndef __PikaStdData_List__H -#define __PikaStdData_List__H -#include -#include -#include "PikaObj.h" - -PikaObj *New_PikaStdData_List(Args *args); - -PikaObj* PikaStdData_List___add__(PikaObj *self, PikaObj* others); -void PikaStdData_List___init__(PikaObj *self); -void PikaStdData_List___setitem__(PikaObj *self, Arg* __key, Arg* __val); -char* PikaStdData_List___str__(PikaObj *self); -void PikaStdData_List_append(PikaObj *self, Arg* arg); -void PikaStdData_List_insert(PikaObj *self, int i, Arg* arg); -Arg* PikaStdData_List_pop(PikaObj *self); -void PikaStdData_List_remove(PikaObj *self, Arg* val); -void PikaStdData_List_reverse(PikaObj *self); -void PikaStdData_List_set(PikaObj *self, int i, Arg* arg); - -#endif diff --git a/examples/pikapython/pikapython/pikascript-api/PikaStdData_String.h b/examples/pikapython/pikapython/pikascript-api/PikaStdData_String.h deleted file mode 100644 index f061a5a0..00000000 --- a/examples/pikapython/pikapython/pikascript-api/PikaStdData_String.h +++ /dev/null @@ -1,42 +0,0 @@ -/* - * [Warning!] This file is auto-generated by pika compiler. - * Do not edit it manually. - * The source code is *.pyi file. - * More details: - * English Doc: - * https://pikadoc.readthedocs.io/en/latest/PikaScript%20%E6%A8%A1%E5%9D%97%E6%A6%82%E8%BF%B0.html - * Chinese Doc: - * https://pikadoc.readthedocs.io/zh/latest/PikaScript%20%E6%A8%A1%E5%9D%97%E6%A6%82%E8%BF%B0.html - */ - -#ifndef __PikaStdData_String__H -#define __PikaStdData_String__H -#include -#include -#include "PikaObj.h" - -PikaObj *New_PikaStdData_String(Args *args); - -Arg* PikaStdData_String___getitem__(PikaObj *self, Arg* __key); -void PikaStdData_String___init__(PikaObj *self, char* s); -Arg* PikaStdData_String___iter__(PikaObj *self); -int PikaStdData_String___len__(PikaObj *self); -Arg* PikaStdData_String___next__(PikaObj *self); -void PikaStdData_String___setitem__(PikaObj *self, Arg* __key, Arg* __val); -char* PikaStdData_String___str__(PikaObj *self); -Arg* PikaStdData_String_encode(PikaObj *self, PikaTuple* encoding); -int PikaStdData_String_endswith(PikaObj *self, char* suffix); -char* PikaStdData_String_format(PikaObj *self, PikaTuple* vars); -char* PikaStdData_String_get(PikaObj *self); -int PikaStdData_String_isalnum(PikaObj *self); -int PikaStdData_String_isalpha(PikaObj *self); -int PikaStdData_String_isdigit(PikaObj *self); -int PikaStdData_String_islower(PikaObj *self); -int PikaStdData_String_isspace(PikaObj *self); -char* PikaStdData_String_replace(PikaObj *self, char* old, char* new); -void PikaStdData_String_set(PikaObj *self, char* s); -PikaObj* PikaStdData_String_split(PikaObj *self, char* s); -int PikaStdData_String_startswith(PikaObj *self, char* prefix); -char* PikaStdData_String_strip(PikaObj *self, PikaTuple* chrs); - -#endif diff --git a/examples/pikapython/pikapython/pikascript-api/PikaStdData_Tuple.h b/examples/pikapython/pikapython/pikascript-api/PikaStdData_Tuple.h deleted file mode 100644 index c09be162..00000000 --- a/examples/pikapython/pikapython/pikascript-api/PikaStdData_Tuple.h +++ /dev/null @@ -1,31 +0,0 @@ -/* - * [Warning!] This file is auto-generated by pika compiler. - * Do not edit it manually. - * The source code is *.pyi file. - * More details: - * English Doc: - * https://pikadoc.readthedocs.io/en/latest/PikaScript%20%E6%A8%A1%E5%9D%97%E6%A6%82%E8%BF%B0.html - * Chinese Doc: - * https://pikadoc.readthedocs.io/zh/latest/PikaScript%20%E6%A8%A1%E5%9D%97%E6%A6%82%E8%BF%B0.html - */ - -#ifndef __PikaStdData_Tuple__H -#define __PikaStdData_Tuple__H -#include -#include -#include "PikaObj.h" - -PikaObj *New_PikaStdData_Tuple(Args *args); - -int PikaStdData_Tuple___contains__(PikaObj *self, Arg* val); -void PikaStdData_Tuple___del__(PikaObj *self); -Arg* PikaStdData_Tuple___getitem__(PikaObj *self, Arg* __key); -void PikaStdData_Tuple___init__(PikaObj *self); -Arg* PikaStdData_Tuple___iter__(PikaObj *self); -int PikaStdData_Tuple___len__(PikaObj *self); -Arg* PikaStdData_Tuple___next__(PikaObj *self); -char* PikaStdData_Tuple___str__(PikaObj *self); -Arg* PikaStdData_Tuple_get(PikaObj *self, int i); -int PikaStdData_Tuple_len(PikaObj *self); - -#endif diff --git a/examples/pikapython/pikapython/pikascript-api/PikaStdData_Utils.h b/examples/pikapython/pikapython/pikascript-api/PikaStdData_Utils.h deleted file mode 100644 index 892f8498..00000000 --- a/examples/pikapython/pikapython/pikascript-api/PikaStdData_Utils.h +++ /dev/null @@ -1,22 +0,0 @@ -/* - * [Warning!] This file is auto-generated by pika compiler. - * Do not edit it manually. - * The source code is *.pyi file. - * More details: - * English Doc: - * https://pikadoc.readthedocs.io/en/latest/PikaScript%20%E6%A8%A1%E5%9D%97%E6%A6%82%E8%BF%B0.html - * Chinese Doc: - * https://pikadoc.readthedocs.io/zh/latest/PikaScript%20%E6%A8%A1%E5%9D%97%E6%A6%82%E8%BF%B0.html - */ - -#ifndef __PikaStdData_Utils__H -#define __PikaStdData_Utils__H -#include -#include -#include "PikaObj.h" - -PikaObj *New_PikaStdData_Utils(Args *args); - -Arg* PikaStdData_Utils_int_to_bytes(PikaObj *self, int val); - -#endif diff --git a/examples/pikapython/pikapython/pikascript-api/PikaStdData_dict_items.h b/examples/pikapython/pikapython/pikascript-api/PikaStdData_dict_items.h deleted file mode 100644 index 35640ad7..00000000 --- a/examples/pikapython/pikapython/pikascript-api/PikaStdData_dict_items.h +++ /dev/null @@ -1,25 +0,0 @@ -/* - * [Warning!] This file is auto-generated by pika compiler. - * Do not edit it manually. - * The source code is *.pyi file. - * More details: - * English Doc: - * https://pikadoc.readthedocs.io/en/latest/PikaScript%20%E6%A8%A1%E5%9D%97%E6%A6%82%E8%BF%B0.html - * Chinese Doc: - * https://pikadoc.readthedocs.io/zh/latest/PikaScript%20%E6%A8%A1%E5%9D%97%E6%A6%82%E8%BF%B0.html - */ - -#ifndef __PikaStdData_dict_items__H -#define __PikaStdData_dict_items__H -#include -#include -#include "PikaObj.h" - -PikaObj *New_PikaStdData_dict_items(Args *args); - -Arg* PikaStdData_dict_items___iter__(PikaObj *self); -int PikaStdData_dict_items___len__(PikaObj *self); -Arg* PikaStdData_dict_items___next__(PikaObj *self); -char* PikaStdData_dict_items___str__(PikaObj *self); - -#endif diff --git a/examples/pikapython/pikapython/pikascript-api/PikaStdData_dict_keys.h b/examples/pikapython/pikapython/pikascript-api/PikaStdData_dict_keys.h deleted file mode 100644 index 832d293b..00000000 --- a/examples/pikapython/pikapython/pikascript-api/PikaStdData_dict_keys.h +++ /dev/null @@ -1,25 +0,0 @@ -/* - * [Warning!] This file is auto-generated by pika compiler. - * Do not edit it manually. - * The source code is *.pyi file. - * More details: - * English Doc: - * https://pikadoc.readthedocs.io/en/latest/PikaScript%20%E6%A8%A1%E5%9D%97%E6%A6%82%E8%BF%B0.html - * Chinese Doc: - * https://pikadoc.readthedocs.io/zh/latest/PikaScript%20%E6%A8%A1%E5%9D%97%E6%A6%82%E8%BF%B0.html - */ - -#ifndef __PikaStdData_dict_keys__H -#define __PikaStdData_dict_keys__H -#include -#include -#include "PikaObj.h" - -PikaObj *New_PikaStdData_dict_keys(Args *args); - -Arg* PikaStdData_dict_keys___iter__(PikaObj *self); -int PikaStdData_dict_keys___len__(PikaObj *self); -Arg* PikaStdData_dict_keys___next__(PikaObj *self); -char* PikaStdData_dict_keys___str__(PikaObj *self); - -#endif diff --git a/examples/pikapython/pikapython/pikascript-api/PikaStdLib.h b/examples/pikapython/pikapython/pikascript-api/PikaStdLib.h deleted file mode 100644 index d0ac36ec..00000000 --- a/examples/pikapython/pikapython/pikascript-api/PikaStdLib.h +++ /dev/null @@ -1,25 +0,0 @@ -/* - * [Warning!] This file is auto-generated by pika compiler. - * Do not edit it manually. - * The source code is *.pyi file. - * More details: - * English Doc: - * https://pikadoc.readthedocs.io/en/latest/PikaScript%20%E6%A8%A1%E5%9D%97%E6%A6%82%E8%BF%B0.html - * Chinese Doc: - * https://pikadoc.readthedocs.io/zh/latest/PikaScript%20%E6%A8%A1%E5%9D%97%E6%A6%82%E8%BF%B0.html - */ - -#ifndef __PikaStdLib__H -#define __PikaStdLib__H -#include -#include -#include "PikaObj.h" - -PikaObj *New_PikaStdLib(Args *args); - -Arg* PikaStdLib_MemChecker(PikaObj *self); -Arg* PikaStdLib_RangeObj(PikaObj *self); -Arg* PikaStdLib_StringObj(PikaObj *self); -Arg* PikaStdLib_SysObj(PikaObj *self); - -#endif diff --git a/examples/pikapython/pikapython/pikascript-api/PikaStdLib_MemChecker.h b/examples/pikapython/pikapython/pikascript-api/PikaStdLib_MemChecker.h deleted file mode 100644 index 7e835e6e..00000000 --- a/examples/pikapython/pikapython/pikascript-api/PikaStdLib_MemChecker.h +++ /dev/null @@ -1,26 +0,0 @@ -/* - * [Warning!] This file is auto-generated by pika compiler. - * Do not edit it manually. - * The source code is *.pyi file. - * More details: - * English Doc: - * https://pikadoc.readthedocs.io/en/latest/PikaScript%20%E6%A8%A1%E5%9D%97%E6%A6%82%E8%BF%B0.html - * Chinese Doc: - * https://pikadoc.readthedocs.io/zh/latest/PikaScript%20%E6%A8%A1%E5%9D%97%E6%A6%82%E8%BF%B0.html - */ - -#ifndef __PikaStdLib_MemChecker__H -#define __PikaStdLib_MemChecker__H -#include -#include -#include "PikaObj.h" - -PikaObj *New_PikaStdLib_MemChecker(Args *args); - -pika_float PikaStdLib_MemChecker_getMax(PikaObj *self); -pika_float PikaStdLib_MemChecker_getNow(PikaObj *self); -void PikaStdLib_MemChecker_max(PikaObj *self); -void PikaStdLib_MemChecker_now(PikaObj *self); -void PikaStdLib_MemChecker_resetMax(PikaObj *self); - -#endif diff --git a/examples/pikapython/pikapython/pikascript-api/PikaStdLib_RangeObj.h b/examples/pikapython/pikapython/pikascript-api/PikaStdLib_RangeObj.h deleted file mode 100644 index 317f7b4c..00000000 --- a/examples/pikapython/pikapython/pikascript-api/PikaStdLib_RangeObj.h +++ /dev/null @@ -1,22 +0,0 @@ -/* - * [Warning!] This file is auto-generated by pika compiler. - * Do not edit it manually. - * The source code is *.pyi file. - * More details: - * English Doc: - * https://pikadoc.readthedocs.io/en/latest/PikaScript%20%E6%A8%A1%E5%9D%97%E6%A6%82%E8%BF%B0.html - * Chinese Doc: - * https://pikadoc.readthedocs.io/zh/latest/PikaScript%20%E6%A8%A1%E5%9D%97%E6%A6%82%E8%BF%B0.html - */ - -#ifndef __PikaStdLib_RangeObj__H -#define __PikaStdLib_RangeObj__H -#include -#include -#include "PikaObj.h" - -PikaObj *New_PikaStdLib_RangeObj(Args *args); - -Arg* PikaStdLib_RangeObj___next__(PikaObj *self); - -#endif diff --git a/examples/pikapython/pikapython/pikascript-api/PikaStdLib_StringObj.h b/examples/pikapython/pikapython/pikascript-api/PikaStdLib_StringObj.h deleted file mode 100644 index 290bd9f3..00000000 --- a/examples/pikapython/pikapython/pikascript-api/PikaStdLib_StringObj.h +++ /dev/null @@ -1,22 +0,0 @@ -/* - * [Warning!] This file is auto-generated by pika compiler. - * Do not edit it manually. - * The source code is *.pyi file. - * More details: - * English Doc: - * https://pikadoc.readthedocs.io/en/latest/PikaScript%20%E6%A8%A1%E5%9D%97%E6%A6%82%E8%BF%B0.html - * Chinese Doc: - * https://pikadoc.readthedocs.io/zh/latest/PikaScript%20%E6%A8%A1%E5%9D%97%E6%A6%82%E8%BF%B0.html - */ - -#ifndef __PikaStdLib_StringObj__H -#define __PikaStdLib_StringObj__H -#include -#include -#include "PikaObj.h" - -PikaObj *New_PikaStdLib_StringObj(Args *args); - -Arg* PikaStdLib_StringObj___next__(PikaObj *self); - -#endif diff --git a/examples/pikapython/pikapython/pikascript-api/PikaStdLib_SysObj.h b/examples/pikapython/pikapython/pikascript-api/PikaStdLib_SysObj.h deleted file mode 100644 index 00d3e337..00000000 --- a/examples/pikapython/pikapython/pikascript-api/PikaStdLib_SysObj.h +++ /dev/null @@ -1,49 +0,0 @@ -/* - * [Warning!] This file is auto-generated by pika compiler. - * Do not edit it manually. - * The source code is *.pyi file. - * More details: - * English Doc: - * https://pikadoc.readthedocs.io/en/latest/PikaScript%20%E6%A8%A1%E5%9D%97%E6%A6%82%E8%BF%B0.html - * Chinese Doc: - * https://pikadoc.readthedocs.io/zh/latest/PikaScript%20%E6%A8%A1%E5%9D%97%E6%A6%82%E8%BF%B0.html - */ - -#ifndef __PikaStdLib_SysObj__H -#define __PikaStdLib_SysObj__H -#include -#include -#include "PikaObj.h" - -PikaObj *New_PikaStdLib_SysObj(Args *args); - -Arg* PikaStdLib_SysObj___getitem__(PikaObj *self, Arg* obj, Arg* key); -Arg* PikaStdLib_SysObj___setitem__(PikaObj *self, Arg* obj, Arg* key, Arg* val); -Arg* PikaStdLib_SysObj_bytes(PikaObj *self, Arg* val); -char* PikaStdLib_SysObj_cformat(PikaObj *self, char* fmt, PikaTuple* var); -char* PikaStdLib_SysObj_chr(PikaObj *self, int val); -Arg* PikaStdLib_SysObj_dict(PikaObj *self, PikaTuple* val); -PikaObj* PikaStdLib_SysObj_dir(PikaObj *self, PikaObj* obj); -Arg* PikaStdLib_SysObj_eval(PikaObj *self, char* code); -void PikaStdLib_SysObj_exec(PikaObj *self, char* code); -void PikaStdLib_SysObj_exit(PikaObj *self); -pika_float PikaStdLib_SysObj_float(PikaObj *self, Arg* arg); -Arg* PikaStdLib_SysObj_getattr(PikaObj *self, PikaObj* obj, char* name); -int PikaStdLib_SysObj_hasattr(PikaObj *self, PikaObj* obj, char* name); -void PikaStdLib_SysObj_help(PikaObj *self, char* name); -char* PikaStdLib_SysObj_hex(PikaObj *self, int val); -int PikaStdLib_SysObj_id(PikaObj *self, Arg* obj); -char* PikaStdLib_SysObj_input(PikaObj *self, PikaTuple* info); -int PikaStdLib_SysObj_int(PikaObj *self, Arg* arg); -Arg* PikaStdLib_SysObj_iter(PikaObj *self, Arg* arg); -int PikaStdLib_SysObj_len(PikaObj *self, Arg* arg); -Arg* PikaStdLib_SysObj_list(PikaObj *self, PikaTuple* val); -PikaObj* PikaStdLib_SysObj_open(PikaObj *self, char* path, char* mode); -int PikaStdLib_SysObj_ord(PikaObj *self, char* val); -void PikaStdLib_SysObj_print(PikaObj *self, PikaTuple* val, PikaDict* ops); -Arg* PikaStdLib_SysObj_range(PikaObj *self, PikaTuple* ax); -void PikaStdLib_SysObj_setattr(PikaObj *self, PikaObj* obj, char* name, Arg* val); -char* PikaStdLib_SysObj_str(PikaObj *self, Arg* arg); -Arg* PikaStdLib_SysObj_type(PikaObj *self, Arg* arg); - -#endif diff --git a/examples/pikapython/pikapython/pikascript-api/PikaStdTask.h b/examples/pikapython/pikapython/pikascript-api/PikaStdTask.h deleted file mode 100644 index 0d621eda..00000000 --- a/examples/pikapython/pikapython/pikascript-api/PikaStdTask.h +++ /dev/null @@ -1,22 +0,0 @@ -/* - * [Warning!] This file is auto-generated by pika compiler. - * Do not edit it manually. - * The source code is *.pyi file. - * More details: - * English Doc: - * https://pikadoc.readthedocs.io/en/latest/PikaScript%20%E6%A8%A1%E5%9D%97%E6%A6%82%E8%BF%B0.html - * Chinese Doc: - * https://pikadoc.readthedocs.io/zh/latest/PikaScript%20%E6%A8%A1%E5%9D%97%E6%A6%82%E8%BF%B0.html - */ - -#ifndef __PikaStdTask__H -#define __PikaStdTask__H -#include -#include -#include "PikaObj.h" - -PikaObj *New_PikaStdTask(Args *args); - -Arg* PikaStdTask_Task(PikaObj *self); - -#endif diff --git a/examples/pikapython/pikapython/pikascript-api/PikaStdTask_Task.h b/examples/pikapython/pikapython/pikascript-api/PikaStdTask_Task.h deleted file mode 100644 index a4a6e360..00000000 --- a/examples/pikapython/pikapython/pikascript-api/PikaStdTask_Task.h +++ /dev/null @@ -1,29 +0,0 @@ -/* - * [Warning!] This file is auto-generated by pika compiler. - * Do not edit it manually. - * The source code is *.pyi file. - * More details: - * English Doc: - * https://pikadoc.readthedocs.io/en/latest/PikaScript%20%E6%A8%A1%E5%9D%97%E6%A6%82%E8%BF%B0.html - * Chinese Doc: - * https://pikadoc.readthedocs.io/zh/latest/PikaScript%20%E6%A8%A1%E5%9D%97%E6%A6%82%E8%BF%B0.html - */ - -#ifndef __PikaStdTask_Task__H -#define __PikaStdTask_Task__H -#include -#include -#include "PikaObj.h" - -PikaObj *New_PikaStdTask_Task(Args *args); - -void PikaStdTask_Task___init__(PikaObj *self); -void PikaStdTask_Task_call_always(PikaObj *self, Arg* fun_todo); -void PikaStdTask_Task_call_period_ms(PikaObj *self, Arg* fun_todo, int period_ms); -void PikaStdTask_Task_call_when(PikaObj *self, Arg* fun_todo, Arg* fun_when); -void PikaStdTask_Task_platformGetTick(PikaObj *self); -void PikaStdTask_Task_run_forever(PikaObj *self); -void PikaStdTask_Task_run_once(PikaObj *self); -void PikaStdTask_Task_run_until_ms(PikaObj *self, int until_ms); - -#endif diff --git a/examples/pikapython/pikapython/pikascript-api/__asset_pikaModules_py_a.c b/examples/pikapython/pikapython/pikascript-api/__asset_pikaModules_py_a.c deleted file mode 100644 index 44c5daf9..00000000 --- a/examples/pikapython/pikapython/pikascript-api/__asset_pikaModules_py_a.c +++ /dev/null @@ -1,14 +0,0 @@ -#include "PikaPlatform.h" -/* warning: auto generated file, please do not modify */ -PIKA_BYTECODE_ALIGN const unsigned char pikaModules_py_a[] = { - 0x7f, 0x70, 0x79, 0x61, 0x02, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x6d, 0x61, 0x69, 0x6e, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x2c, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x10, 0x83, 0x01, 0x00, - 0x00, 0x02, 0x13, 0x00, 0x19, 0x00, 0x00, 0x00, 0x00, 0x68, 0x65, 0x6c, - 0x6c, 0x6f, 0x20, 0x50, 0x69, 0x6b, 0x61, 0x50, 0x79, 0x74, 0x68, 0x6f, - 0x6e, 0x21, 0x00, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x00, 0x00, 0x00, 0x00, - 0x00, -}; diff --git a/examples/pikapython/pikapython/pikascript-api/__pikaBinding.c b/examples/pikapython/pikapython/pikascript-api/__pikaBinding.c deleted file mode 100644 index 4f5e9835..00000000 --- a/examples/pikapython/pikapython/pikascript-api/__pikaBinding.c +++ /dev/null @@ -1,1888 +0,0 @@ -/* - * [Warning!] This file is auto-generated by pika compiler. - * Do not edit it manually. - * The source code is *.pyi file. - * More details: - * English Doc: - * https://pikadoc.readthedocs.io/en/latest/PikaScript%20%E6%A8%A1%E5%9D%97%E6%A6%82%E8%BF%B0.html - * Chinese Doc: - * https://pikadoc.readthedocs.io/zh/latest/PikaScript%20%E6%A8%A1%E5%9D%97%E6%A6%82%E8%BF%B0.html - */ - -#include -#include -#include "BaseObj.h" -#include "PikaDebug.h" -#include "TinyObj.h" -#include "PikaDebug_Debuger.h" -#include "TinyObj.h" -#include "PikaMain.h" -#include "PikaStdLib_SysObj.h" -#include "PikaStdData.h" -#include "TinyObj.h" -#include "PikaStdData_ByteArray.h" -#include "TinyObj.h" -#include "PikaStdData_Dict.h" -#include "TinyObj.h" -#include "PikaStdData_FILEIO.h" -#include "TinyObj.h" -#include "PikaStdData_List.h" -#include "PikaStdData_Tuple.h" -#include "PikaStdData_String.h" -#include "TinyObj.h" -#include "PikaStdData_Tuple.h" -#include "TinyObj.h" -#include "PikaStdData_Utils.h" -#include "TinyObj.h" -#include "PikaStdData_dict_items.h" -#include "TinyObj.h" -#include "PikaStdData_dict_keys.h" -#include "TinyObj.h" -#include "PikaStdLib.h" -#include "TinyObj.h" -#include "PikaStdLib_MemChecker.h" -#include "TinyObj.h" -#include "PikaStdLib_RangeObj.h" -#include "TinyObj.h" -#include "PikaStdLib_StringObj.h" -#include "TinyObj.h" -#include "PikaStdLib_SysObj.h" -#include "TinyObj.h" -#include "PikaStdTask.h" -#include "TinyObj.h" -#include "PikaStdTask_Task.h" -#include "PikaStdLib_SysObj.h" -#include "PikaStdData_List.h" - -#ifndef PIKA_MODULE_PIKADEBUG_DISABLE -void PikaDebug_DebugerMethod(PikaObj *self, Args *args){ - Arg* res = PikaDebug_Debuger(self); - method_returnArg(args, res); -} -method_typedef( - PikaDebug_Debuger, - "Debuger", "" -); - -class_def(PikaDebug){ - __BEFORE_MOETHOD_DEF - constructor_def(PikaDebug_Debuger, 1761613187), -}; -class_inhert(PikaDebug, TinyObj); - -PikaObj *New_PikaDebug(Args *args){ - PikaObj *self = New_TinyObj(args); - obj_setClass(self, PikaDebug); - return self; -} -#endif - -#ifndef PIKA_MODULE_PIKADEBUG_DISABLE -void PikaDebug_Debuger___init__Method(PikaObj *self, Args *args){ - PikaDebug_Debuger___init__(self); -} -method_typedef( - PikaDebug_Debuger___init__, - "__init__", "" -); - -void PikaDebug_Debuger_set_traceMethod(PikaObj *self, Args *args){ - PikaDebug_Debuger_set_trace(self); -} -method_typedef( - PikaDebug_Debuger_set_trace, - "set_trace", "" -); - -class_def(PikaDebug_Debuger){ - __BEFORE_MOETHOD_DEF - method_def(PikaDebug_Debuger___init__, 904762485), - method_def(PikaDebug_Debuger_set_trace, 1131228543), -}; -class_inhert(PikaDebug_Debuger, TinyObj); - -PikaObj *New_PikaDebug_Debuger(Args *args){ - PikaObj *self = New_TinyObj(args); - obj_setClass(self, PikaDebug_Debuger); - return self; -} - -Arg *PikaDebug_Debuger(PikaObj *self){ - return obj_newObjInPackage(New_PikaDebug_Debuger); -} -#endif - -#ifndef PIKA_MODULE_MAIN_DISABLE -class_def(PikaMain){ - __BEFORE_MOETHOD_DEF -}; -class_inhert(PikaMain, PikaStdLib_SysObj); - -PikaObj *New_PikaMain(Args *args){ - PikaObj *self = New_PikaStdLib_SysObj(args); - obj_setClass(self, PikaMain); - return self; -} - -Arg *PikaMain(PikaObj *self){ - return obj_newObjInPackage(New_PikaMain); -} -#endif - -#ifndef PIKA_MODULE_PIKASTDDATA_DISABLE -void PikaStdData_ByteArrayMethod(PikaObj *self, Args *args){ - Arg* res = PikaStdData_ByteArray(self); - method_returnArg(args, res); -} -method_typedef( - PikaStdData_ByteArray, - "ByteArray", "" -); - -void PikaStdData_DictMethod(PikaObj *self, Args *args){ - Arg* res = PikaStdData_Dict(self); - method_returnArg(args, res); -} -method_typedef( - PikaStdData_Dict, - "Dict", "" -); - -void PikaStdData_FILEIOMethod(PikaObj *self, Args *args){ - Arg* res = PikaStdData_FILEIO(self); - method_returnArg(args, res); -} -method_typedef( - PikaStdData_FILEIO, - "FILEIO", "" -); - -void PikaStdData_ListMethod(PikaObj *self, Args *args){ - Arg* res = PikaStdData_List(self); - method_returnArg(args, res); -} -method_typedef( - PikaStdData_List, - "List", "" -); - -void PikaStdData_StringMethod(PikaObj *self, Args *args){ - Arg* res = PikaStdData_String(self); - method_returnArg(args, res); -} -method_typedef( - PikaStdData_String, - "String", "" -); - -void PikaStdData_TupleMethod(PikaObj *self, Args *args){ - Arg* res = PikaStdData_Tuple(self); - method_returnArg(args, res); -} -method_typedef( - PikaStdData_Tuple, - "Tuple", "" -); - -void PikaStdData_UtilsMethod(PikaObj *self, Args *args){ - Arg* res = PikaStdData_Utils(self); - method_returnArg(args, res); -} -method_typedef( - PikaStdData_Utils, - "Utils", "" -); - -void PikaStdData_dict_itemsMethod(PikaObj *self, Args *args){ - Arg* res = PikaStdData_dict_items(self); - method_returnArg(args, res); -} -method_typedef( - PikaStdData_dict_items, - "dict_items", "" -); - -void PikaStdData_dict_keysMethod(PikaObj *self, Args *args){ - Arg* res = PikaStdData_dict_keys(self); - method_returnArg(args, res); -} -method_typedef( - PikaStdData_dict_keys, - "dict_keys", "" -); - -class_def(PikaStdData){ - __BEFORE_MOETHOD_DEF - constructor_def(PikaStdData_Tuple, 238099855), - constructor_def(PikaStdData_Utils, 239242230), - constructor_def(PikaStdData_FILEIO, 813431197), - constructor_def(PikaStdData_dict_keys, 872966404), - constructor_def(PikaStdData_dict_items, 888749258), - constructor_def(PikaStdData_String, 1374591964), - constructor_def(PikaStdData_ByteArray, 1998882840), - constructor_def(PikaStdData_Dict, 2089035049), - constructor_def(PikaStdData_List, 2089323073), -}; -class_inhert(PikaStdData, TinyObj); - -PikaObj *New_PikaStdData(Args *args){ - PikaObj *self = New_TinyObj(args); - obj_setClass(self, PikaStdData); - return self; -} -#endif - -#ifndef PIKA_MODULE_PIKASTDDATA_DISABLE -void PikaStdData_ByteArray___getitem__Method(PikaObj *self, Args *args){ - int __key = args_getInt(args, "__key"); - int res = PikaStdData_ByteArray___getitem__(self, __key); - method_returnInt(args, res); -} -method_typedef( - PikaStdData_ByteArray___getitem__, - "__getitem__", "__key" -); - -void PikaStdData_ByteArray___init__Method(PikaObj *self, Args *args){ - Arg* bytes = args_getArg(args, "bytes"); - PikaStdData_ByteArray___init__(self, bytes); -} -method_typedef( - PikaStdData_ByteArray___init__, - "__init__", "bytes" -); - -void PikaStdData_ByteArray___iter__Method(PikaObj *self, Args *args){ - Arg* res = PikaStdData_ByteArray___iter__(self); - method_returnArg(args, res); -} -method_typedef( - PikaStdData_ByteArray___iter__, - "__iter__", "" -); - -void PikaStdData_ByteArray___next__Method(PikaObj *self, Args *args){ - Arg* res = PikaStdData_ByteArray___next__(self); - method_returnArg(args, res); -} -method_typedef( - PikaStdData_ByteArray___next__, - "__next__", "" -); - -void PikaStdData_ByteArray___setitem__Method(PikaObj *self, Args *args){ - int __key = args_getInt(args, "__key"); - int __val = args_getInt(args, "__val"); - PikaStdData_ByteArray___setitem__(self, __key, __val); -} -method_typedef( - PikaStdData_ByteArray___setitem__, - "__setitem__", "__key,__val" -); - -void PikaStdData_ByteArray___str__Method(PikaObj *self, Args *args){ - char* res = PikaStdData_ByteArray___str__(self); - method_returnStr(args, res); -} -method_typedef( - PikaStdData_ByteArray___str__, - "__str__", "" -); - -void PikaStdData_ByteArray_decodeMethod(PikaObj *self, Args *args){ - char* res = PikaStdData_ByteArray_decode(self); - method_returnStr(args, res); -} -method_typedef( - PikaStdData_ByteArray_decode, - "decode", "" -); - -class_def(PikaStdData_ByteArray){ - __BEFORE_MOETHOD_DEF - method_def(PikaStdData_ByteArray___init__, 904762485), - method_def(PikaStdData_ByteArray___iter__, 911732085), - method_def(PikaStdData_ByteArray___next__, 1090305216), - method_def(PikaStdData_ByteArray___setitem__, 1364865276), - method_def(PikaStdData_ByteArray___getitem__, 1535436016), - method_def(PikaStdData_ByteArray_decode, 2021571977), - method_def(PikaStdData_ByteArray___str__, 2056834106), -}; -class_inhert(PikaStdData_ByteArray, TinyObj); - -PikaObj *New_PikaStdData_ByteArray(Args *args){ - PikaObj *self = New_TinyObj(args); - obj_setClass(self, PikaStdData_ByteArray); - return self; -} - -Arg *PikaStdData_ByteArray(PikaObj *self){ - return obj_newObjInPackage(New_PikaStdData_ByteArray); -} -#endif - -#ifndef PIKA_MODULE_PIKASTDDATA_DISABLE -void PikaStdData_Dict___contains__Method(PikaObj *self, Args *args){ - Arg* val = args_getArg(args, "val"); - int res = PikaStdData_Dict___contains__(self, val); - method_returnInt(args, res); -} -method_typedef( - PikaStdData_Dict___contains__, - "__contains__", "val" -); - -void PikaStdData_Dict___del__Method(PikaObj *self, Args *args){ - PikaStdData_Dict___del__(self); -} -method_typedef( - PikaStdData_Dict___del__, - "__del__", "" -); - -void PikaStdData_Dict___getitem__Method(PikaObj *self, Args *args){ - Arg* __key = args_getArg(args, "__key"); - Arg* res = PikaStdData_Dict___getitem__(self, __key); - method_returnArg(args, res); -} -method_typedef( - PikaStdData_Dict___getitem__, - "__getitem__", "__key" -); - -void PikaStdData_Dict___init__Method(PikaObj *self, Args *args){ - PikaStdData_Dict___init__(self); -} -method_typedef( - PikaStdData_Dict___init__, - "__init__", "" -); - -void PikaStdData_Dict___iter__Method(PikaObj *self, Args *args){ - Arg* res = PikaStdData_Dict___iter__(self); - method_returnArg(args, res); -} -method_typedef( - PikaStdData_Dict___iter__, - "__iter__", "" -); - -void PikaStdData_Dict___len__Method(PikaObj *self, Args *args){ - int res = PikaStdData_Dict___len__(self); - method_returnInt(args, res); -} -method_typedef( - PikaStdData_Dict___len__, - "__len__", "" -); - -void PikaStdData_Dict___next__Method(PikaObj *self, Args *args){ - Arg* res = PikaStdData_Dict___next__(self); - method_returnArg(args, res); -} -method_typedef( - PikaStdData_Dict___next__, - "__next__", "" -); - -void PikaStdData_Dict___setitem__Method(PikaObj *self, Args *args){ - Arg* __key = args_getArg(args, "__key"); - Arg* __val = args_getArg(args, "__val"); - PikaStdData_Dict___setitem__(self, __key, __val); -} -method_typedef( - PikaStdData_Dict___setitem__, - "__setitem__", "__key,__val" -); - -void PikaStdData_Dict___str__Method(PikaObj *self, Args *args){ - char* res = PikaStdData_Dict___str__(self); - method_returnStr(args, res); -} -method_typedef( - PikaStdData_Dict___str__, - "__str__", "" -); - -void PikaStdData_Dict_getMethod(PikaObj *self, Args *args){ - char* key = args_getStr(args, "key"); - Arg* res = PikaStdData_Dict_get(self, key); - method_returnArg(args, res); -} -method_typedef( - PikaStdData_Dict_get, - "get", "key" -); - -void PikaStdData_Dict_itemsMethod(PikaObj *self, Args *args){ - PikaObj* res = PikaStdData_Dict_items(self); - method_returnObj(args, res); -} -method_typedef( - PikaStdData_Dict_items, - "items", "" -); - -void PikaStdData_Dict_keysMethod(PikaObj *self, Args *args){ - PikaObj* res = PikaStdData_Dict_keys(self); - method_returnObj(args, res); -} -method_typedef( - PikaStdData_Dict_keys, - "keys", "" -); - -void PikaStdData_Dict_removeMethod(PikaObj *self, Args *args){ - char* key = args_getStr(args, "key"); - PikaStdData_Dict_remove(self, key); -} -method_typedef( - PikaStdData_Dict_remove, - "remove", "key" -); - -void PikaStdData_Dict_setMethod(PikaObj *self, Args *args){ - char* key = args_getStr(args, "key"); - Arg* arg = args_getArg(args, "arg"); - PikaStdData_Dict_set(self, key, arg); -} -method_typedef( - PikaStdData_Dict_set, - "set", "key,arg" -); - -void PikaStdData_Dict_updateMethod(PikaObj *self, Args *args){ - PikaObj* other = args_getPtr(args, "other"); - PikaStdData_Dict_update(self, other); -} -method_typedef( - PikaStdData_Dict_update, - "update", "other" -); - -class_def(PikaStdData_Dict){ - __BEFORE_MOETHOD_DEF - method_def(PikaStdData_Dict_get, 193492613), - method_def(PikaStdData_Dict_set, 193505681), - method_def(PikaStdData_Dict_items, 262956327), - method_def(PikaStdData_Dict_remove, 422343795), - method_def(PikaStdData_Dict_update, 552456360), - method_def(PikaStdData_Dict___init__, 904762485), - method_def(PikaStdData_Dict___iter__, 911732085), - method_def(PikaStdData_Dict___next__, 1090305216), - method_def(PikaStdData_Dict___setitem__, 1364865276), - method_def(PikaStdData_Dict___getitem__, 1535436016), - method_def(PikaStdData_Dict___contains__, 1644201824), - method_def(PikaStdData_Dict___del__, 2038499702), - method_def(PikaStdData_Dict___len__, 2047989248), - method_def(PikaStdData_Dict___str__, 2056834106), - method_def(PikaStdData_Dict_keys, 2090432961), -}; -class_inhert(PikaStdData_Dict, TinyObj); - -PikaObj *New_PikaStdData_Dict(Args *args){ - PikaObj *self = New_TinyObj(args); - obj_setClass(self, PikaStdData_Dict); - return self; -} - -Arg *PikaStdData_Dict(PikaObj *self){ - return obj_newObjInPackage(New_PikaStdData_Dict); -} -#endif - -#ifndef PIKA_MODULE_PIKASTDDATA_DISABLE -void PikaStdData_FILEIO_closeMethod(PikaObj *self, Args *args){ - PikaStdData_FILEIO_close(self); -} -method_typedef( - PikaStdData_FILEIO_close, - "close", "" -); - -void PikaStdData_FILEIO_initMethod(PikaObj *self, Args *args){ - char* path = args_getStr(args, "path"); - char* mode = args_getStr(args, "mode"); - int res = PikaStdData_FILEIO_init(self, path, mode); - method_returnInt(args, res); -} -method_typedef( - PikaStdData_FILEIO_init, - "init", "path,mode" -); - -void PikaStdData_FILEIO_readMethod(PikaObj *self, Args *args){ - PikaTuple* size = args_getTuple(args, "size"); - Arg* res = PikaStdData_FILEIO_read(self, size); - method_returnArg(args, res); -} -method_typedef( - PikaStdData_FILEIO_read, - "read", "*size" -); - -void PikaStdData_FILEIO_readlineMethod(PikaObj *self, Args *args){ - char* res = PikaStdData_FILEIO_readline(self); - method_returnStr(args, res); -} -method_typedef( - PikaStdData_FILEIO_readline, - "readline", "" -); - -void PikaStdData_FILEIO_readlinesMethod(PikaObj *self, Args *args){ - PikaObj* res = PikaStdData_FILEIO_readlines(self); - method_returnObj(args, res); -} -method_typedef( - PikaStdData_FILEIO_readlines, - "readlines", "" -); - -void PikaStdData_FILEIO_seekMethod(PikaObj *self, Args *args){ - int offset = args_getInt(args, "offset"); - PikaTuple* fromwhere = args_getTuple(args, "fromwhere"); - int res = PikaStdData_FILEIO_seek(self, offset, fromwhere); - method_returnInt(args, res); -} -method_typedef( - PikaStdData_FILEIO_seek, - "seek", "offset,*fromwhere" -); - -void PikaStdData_FILEIO_tellMethod(PikaObj *self, Args *args){ - int res = PikaStdData_FILEIO_tell(self); - method_returnInt(args, res); -} -method_typedef( - PikaStdData_FILEIO_tell, - "tell", "" -); - -void PikaStdData_FILEIO_writeMethod(PikaObj *self, Args *args){ - Arg* s = args_getArg(args, "s"); - int res = PikaStdData_FILEIO_write(self, s); - method_returnInt(args, res); -} -method_typedef( - PikaStdData_FILEIO_write, - "write", "s" -); - -void PikaStdData_FILEIO_writelinesMethod(PikaObj *self, Args *args){ - PikaObj* lines = args_getPtr(args, "lines"); - PikaStdData_FILEIO_writelines(self, lines); -} -method_typedef( - PikaStdData_FILEIO_writelines, - "writelines", "lines" -); - -class_def(PikaStdData_FILEIO){ - __BEFORE_MOETHOD_DEF - method_def(PikaStdData_FILEIO_close, 255564379), - method_def(PikaStdData_FILEIO_write, 279491920), - method_def(PikaStdData_FILEIO_readlines, 594708860), - method_def(PikaStdData_FILEIO_writelines, 836522731), - method_def(PikaStdData_FILEIO_readline, 2035354601), - method_def(PikaStdData_FILEIO_init, 2090370361), - method_def(PikaStdData_FILEIO_read, 2090683713), - method_def(PikaStdData_FILEIO_seek, 2090719789), - method_def(PikaStdData_FILEIO_tell, 2090755958), -}; -class_inhert(PikaStdData_FILEIO, TinyObj); - -PikaObj *New_PikaStdData_FILEIO(Args *args){ - PikaObj *self = New_TinyObj(args); - obj_setClass(self, PikaStdData_FILEIO); - return self; -} - -Arg *PikaStdData_FILEIO(PikaObj *self){ - return obj_newObjInPackage(New_PikaStdData_FILEIO); -} -#endif - -#ifndef PIKA_MODULE_PIKASTDDATA_DISABLE -void PikaStdData_List___add__Method(PikaObj *self, Args *args){ - PikaObj* others = args_getPtr(args, "others"); - PikaObj* res = PikaStdData_List___add__(self, others); - method_returnObj(args, res); -} -method_typedef( - PikaStdData_List___add__, - "__add__", "others" -); - -void PikaStdData_List___init__Method(PikaObj *self, Args *args){ - PikaStdData_List___init__(self); -} -method_typedef( - PikaStdData_List___init__, - "__init__", "" -); - -void PikaStdData_List___setitem__Method(PikaObj *self, Args *args){ - Arg* __key = args_getArg(args, "__key"); - Arg* __val = args_getArg(args, "__val"); - PikaStdData_List___setitem__(self, __key, __val); -} -method_typedef( - PikaStdData_List___setitem__, - "__setitem__", "__key,__val" -); - -void PikaStdData_List___str__Method(PikaObj *self, Args *args){ - char* res = PikaStdData_List___str__(self); - method_returnStr(args, res); -} -method_typedef( - PikaStdData_List___str__, - "__str__", "" -); - -void PikaStdData_List_appendMethod(PikaObj *self, Args *args){ - Arg* arg = args_getArg(args, "arg"); - PikaStdData_List_append(self, arg); -} -method_typedef( - PikaStdData_List_append, - "append", "arg" -); - -void PikaStdData_List_insertMethod(PikaObj *self, Args *args){ - int i = args_getInt(args, "i"); - Arg* arg = args_getArg(args, "arg"); - PikaStdData_List_insert(self, i, arg); -} -method_typedef( - PikaStdData_List_insert, - "insert", "i,arg" -); - -void PikaStdData_List_popMethod(PikaObj *self, Args *args){ - Arg* res = PikaStdData_List_pop(self); - method_returnArg(args, res); -} -method_typedef( - PikaStdData_List_pop, - "pop", "" -); - -void PikaStdData_List_removeMethod(PikaObj *self, Args *args){ - Arg* val = args_getArg(args, "val"); - PikaStdData_List_remove(self, val); -} -method_typedef( - PikaStdData_List_remove, - "remove", "val" -); - -void PikaStdData_List_reverseMethod(PikaObj *self, Args *args){ - PikaStdData_List_reverse(self); -} -method_typedef( - PikaStdData_List_reverse, - "reverse", "" -); - -void PikaStdData_List_setMethod(PikaObj *self, Args *args){ - int i = args_getInt(args, "i"); - Arg* arg = args_getArg(args, "arg"); - PikaStdData_List_set(self, i, arg); -} -method_typedef( - PikaStdData_List_set, - "set", "i,arg" -); - -class_def(PikaStdData_List){ - __BEFORE_MOETHOD_DEF - method_def(PikaStdData_List_insert, 81003162), - method_def(PikaStdData_List_pop, 193502740), - method_def(PikaStdData_List_set, 193505681), - method_def(PikaStdData_List_remove, 422343795), - method_def(PikaStdData_List___init__, 904762485), - method_def(PikaStdData_List_reverse, 1062753473), - method_def(PikaStdData_List___setitem__, 1364865276), - method_def(PikaStdData_List_append, 1917667549), - method_def(PikaStdData_List___add__, 2034897290), - method_def(PikaStdData_List___str__, 2056834106), -}; -class_inhert(PikaStdData_List, PikaStdData_Tuple); - -PikaObj *New_PikaStdData_List(Args *args){ - PikaObj *self = New_PikaStdData_Tuple(args); - obj_setClass(self, PikaStdData_List); - return self; -} - -Arg *PikaStdData_List(PikaObj *self){ - return obj_newObjInPackage(New_PikaStdData_List); -} -#endif - -#ifndef PIKA_MODULE_PIKASTDDATA_DISABLE -void PikaStdData_String___getitem__Method(PikaObj *self, Args *args){ - Arg* __key = args_getArg(args, "__key"); - Arg* res = PikaStdData_String___getitem__(self, __key); - method_returnArg(args, res); -} -method_typedef( - PikaStdData_String___getitem__, - "__getitem__", "__key" -); - -void PikaStdData_String___init__Method(PikaObj *self, Args *args){ - char* s = args_getStr(args, "s"); - PikaStdData_String___init__(self, s); -} -method_typedef( - PikaStdData_String___init__, - "__init__", "s" -); - -void PikaStdData_String___iter__Method(PikaObj *self, Args *args){ - Arg* res = PikaStdData_String___iter__(self); - method_returnArg(args, res); -} -method_typedef( - PikaStdData_String___iter__, - "__iter__", "" -); - -void PikaStdData_String___len__Method(PikaObj *self, Args *args){ - int res = PikaStdData_String___len__(self); - method_returnInt(args, res); -} -method_typedef( - PikaStdData_String___len__, - "__len__", "" -); - -void PikaStdData_String___next__Method(PikaObj *self, Args *args){ - Arg* res = PikaStdData_String___next__(self); - method_returnArg(args, res); -} -method_typedef( - PikaStdData_String___next__, - "__next__", "" -); - -void PikaStdData_String___setitem__Method(PikaObj *self, Args *args){ - Arg* __key = args_getArg(args, "__key"); - Arg* __val = args_getArg(args, "__val"); - PikaStdData_String___setitem__(self, __key, __val); -} -method_typedef( - PikaStdData_String___setitem__, - "__setitem__", "__key,__val" -); - -void PikaStdData_String___str__Method(PikaObj *self, Args *args){ - char* res = PikaStdData_String___str__(self); - method_returnStr(args, res); -} -method_typedef( - PikaStdData_String___str__, - "__str__", "" -); - -void PikaStdData_String_encodeMethod(PikaObj *self, Args *args){ - PikaTuple* encoding = args_getTuple(args, "encoding"); - Arg* res = PikaStdData_String_encode(self, encoding); - method_returnArg(args, res); -} -method_typedef( - PikaStdData_String_encode, - "encode", "*encoding" -); - -void PikaStdData_String_endswithMethod(PikaObj *self, Args *args){ - char* suffix = args_getStr(args, "suffix"); - int res = PikaStdData_String_endswith(self, suffix); - method_returnInt(args, res); -} -method_typedef( - PikaStdData_String_endswith, - "endswith", "suffix" -); - -void PikaStdData_String_formatMethod(PikaObj *self, Args *args){ - PikaTuple* vars = args_getTuple(args, "vars"); - char* res = PikaStdData_String_format(self, vars); - method_returnStr(args, res); -} -method_typedef( - PikaStdData_String_format, - "format", "*vars" -); - -void PikaStdData_String_getMethod(PikaObj *self, Args *args){ - char* res = PikaStdData_String_get(self); - method_returnStr(args, res); -} -method_typedef( - PikaStdData_String_get, - "get", "" -); - -void PikaStdData_String_isalnumMethod(PikaObj *self, Args *args){ - int res = PikaStdData_String_isalnum(self); - method_returnInt(args, res); -} -method_typedef( - PikaStdData_String_isalnum, - "isalnum", "" -); - -void PikaStdData_String_isalphaMethod(PikaObj *self, Args *args){ - int res = PikaStdData_String_isalpha(self); - method_returnInt(args, res); -} -method_typedef( - PikaStdData_String_isalpha, - "isalpha", "" -); - -void PikaStdData_String_isdigitMethod(PikaObj *self, Args *args){ - int res = PikaStdData_String_isdigit(self); - method_returnInt(args, res); -} -method_typedef( - PikaStdData_String_isdigit, - "isdigit", "" -); - -void PikaStdData_String_islowerMethod(PikaObj *self, Args *args){ - int res = PikaStdData_String_islower(self); - method_returnInt(args, res); -} -method_typedef( - PikaStdData_String_islower, - "islower", "" -); - -void PikaStdData_String_isspaceMethod(PikaObj *self, Args *args){ - int res = PikaStdData_String_isspace(self); - method_returnInt(args, res); -} -method_typedef( - PikaStdData_String_isspace, - "isspace", "" -); - -void PikaStdData_String_replaceMethod(PikaObj *self, Args *args){ - char* old = args_getStr(args, "old"); - char* new = args_getStr(args, "new"); - char* res = PikaStdData_String_replace(self, old, new); - method_returnStr(args, res); -} -method_typedef( - PikaStdData_String_replace, - "replace", "old,new" -); - -void PikaStdData_String_setMethod(PikaObj *self, Args *args){ - char* s = args_getStr(args, "s"); - PikaStdData_String_set(self, s); -} -method_typedef( - PikaStdData_String_set, - "set", "s" -); - -void PikaStdData_String_splitMethod(PikaObj *self, Args *args){ - char* s = args_getStr(args, "s"); - PikaObj* res = PikaStdData_String_split(self, s); - method_returnObj(args, res); -} -method_typedef( - PikaStdData_String_split, - "split", "s" -); - -void PikaStdData_String_startswithMethod(PikaObj *self, Args *args){ - char* prefix = args_getStr(args, "prefix"); - int res = PikaStdData_String_startswith(self, prefix); - method_returnInt(args, res); -} -method_typedef( - PikaStdData_String_startswith, - "startswith", "prefix" -); - -void PikaStdData_String_stripMethod(PikaObj *self, Args *args){ - PikaTuple* chrs = args_getTuple(args, "chrs"); - char* res = PikaStdData_String_strip(self, chrs); - method_returnStr(args, res); -} -method_typedef( - PikaStdData_String_strip, - "strip", "*chrs" -); - -class_def(PikaStdData_String){ - __BEFORE_MOETHOD_DEF - method_def(PikaStdData_String_get, 193492613), - method_def(PikaStdData_String_set, 193505681), - method_def(PikaStdData_String_split, 274679281), - method_def(PikaStdData_String_strip, 274829559), - method_def(PikaStdData_String_isalnum, 700198430), - method_def(PikaStdData_String_isalpha, 700200167), - method_def(PikaStdData_String_isdigit, 703640370), - method_def(PikaStdData_String_islower, 713360650), - method_def(PikaStdData_String_isspace, 721673997), - method_def(PikaStdData_String_startswith, 841709250), - method_def(PikaStdData_String___init__, 904762485), - method_def(PikaStdData_String___iter__, 911732085), - method_def(PikaStdData_String_endswith, 920277419), - method_def(PikaStdData_String_replace, 1055870465), - method_def(PikaStdData_String___next__, 1090305216), - method_def(PikaStdData_String___setitem__, 1364865276), - method_def(PikaStdData_String___getitem__, 1535436016), - method_def(PikaStdData_String___len__, 2047989248), - method_def(PikaStdData_String___str__, 2056834106), - method_def(PikaStdData_String_encode, 2071380659), - method_def(PikaStdData_String_format, 2112238766), -}; -class_inhert(PikaStdData_String, TinyObj); - -PikaObj *New_PikaStdData_String(Args *args){ - PikaObj *self = New_TinyObj(args); - obj_setClass(self, PikaStdData_String); - return self; -} - -Arg *PikaStdData_String(PikaObj *self){ - return obj_newObjInPackage(New_PikaStdData_String); -} -#endif - -#ifndef PIKA_MODULE_PIKASTDDATA_DISABLE -void PikaStdData_Tuple___contains__Method(PikaObj *self, Args *args){ - Arg* val = args_getArg(args, "val"); - int res = PikaStdData_Tuple___contains__(self, val); - method_returnInt(args, res); -} -method_typedef( - PikaStdData_Tuple___contains__, - "__contains__", "val" -); - -void PikaStdData_Tuple___del__Method(PikaObj *self, Args *args){ - PikaStdData_Tuple___del__(self); -} -method_typedef( - PikaStdData_Tuple___del__, - "__del__", "" -); - -void PikaStdData_Tuple___getitem__Method(PikaObj *self, Args *args){ - Arg* __key = args_getArg(args, "__key"); - Arg* res = PikaStdData_Tuple___getitem__(self, __key); - method_returnArg(args, res); -} -method_typedef( - PikaStdData_Tuple___getitem__, - "__getitem__", "__key" -); - -void PikaStdData_Tuple___init__Method(PikaObj *self, Args *args){ - PikaStdData_Tuple___init__(self); -} -method_typedef( - PikaStdData_Tuple___init__, - "__init__", "" -); - -void PikaStdData_Tuple___iter__Method(PikaObj *self, Args *args){ - Arg* res = PikaStdData_Tuple___iter__(self); - method_returnArg(args, res); -} -method_typedef( - PikaStdData_Tuple___iter__, - "__iter__", "" -); - -void PikaStdData_Tuple___len__Method(PikaObj *self, Args *args){ - int res = PikaStdData_Tuple___len__(self); - method_returnInt(args, res); -} -method_typedef( - PikaStdData_Tuple___len__, - "__len__", "" -); - -void PikaStdData_Tuple___next__Method(PikaObj *self, Args *args){ - Arg* res = PikaStdData_Tuple___next__(self); - method_returnArg(args, res); -} -method_typedef( - PikaStdData_Tuple___next__, - "__next__", "" -); - -void PikaStdData_Tuple___str__Method(PikaObj *self, Args *args){ - char* res = PikaStdData_Tuple___str__(self); - method_returnStr(args, res); -} -method_typedef( - PikaStdData_Tuple___str__, - "__str__", "" -); - -void PikaStdData_Tuple_getMethod(PikaObj *self, Args *args){ - int i = args_getInt(args, "i"); - Arg* res = PikaStdData_Tuple_get(self, i); - method_returnArg(args, res); -} -method_typedef( - PikaStdData_Tuple_get, - "get", "i" -); - -void PikaStdData_Tuple_lenMethod(PikaObj *self, Args *args){ - int res = PikaStdData_Tuple_len(self); - method_returnInt(args, res); -} -method_typedef( - PikaStdData_Tuple_len, - "len", "" -); - -class_def(PikaStdData_Tuple){ - __BEFORE_MOETHOD_DEF - method_def(PikaStdData_Tuple_get, 193492613), - method_def(PikaStdData_Tuple_len, 193498052), - method_def(PikaStdData_Tuple___init__, 904762485), - method_def(PikaStdData_Tuple___iter__, 911732085), - method_def(PikaStdData_Tuple___next__, 1090305216), - method_def(PikaStdData_Tuple___getitem__, 1535436016), - method_def(PikaStdData_Tuple___contains__, 1644201824), - method_def(PikaStdData_Tuple___del__, 2038499702), - method_def(PikaStdData_Tuple___len__, 2047989248), - method_def(PikaStdData_Tuple___str__, 2056834106), -}; -class_inhert(PikaStdData_Tuple, TinyObj); - -PikaObj *New_PikaStdData_Tuple(Args *args){ - PikaObj *self = New_TinyObj(args); - obj_setClass(self, PikaStdData_Tuple); - return self; -} - -Arg *PikaStdData_Tuple(PikaObj *self){ - return obj_newObjInPackage(New_PikaStdData_Tuple); -} -#endif - -#ifndef PIKA_MODULE_PIKASTDDATA_DISABLE -void PikaStdData_Utils_int_to_bytesMethod(PikaObj *self, Args *args){ - int val = args_getInt(args, "val"); - Arg* res = PikaStdData_Utils_int_to_bytes(self, val); - method_returnArg(args, res); -} -method_typedef( - PikaStdData_Utils_int_to_bytes, - "int_to_bytes", "val" -); - -class_def(PikaStdData_Utils){ - __BEFORE_MOETHOD_DEF - method_def(PikaStdData_Utils_int_to_bytes, 476200216), -}; -class_inhert(PikaStdData_Utils, TinyObj); - -PikaObj *New_PikaStdData_Utils(Args *args){ - PikaObj *self = New_TinyObj(args); - obj_setClass(self, PikaStdData_Utils); - return self; -} - -Arg *PikaStdData_Utils(PikaObj *self){ - return obj_newObjInPackage(New_PikaStdData_Utils); -} -#endif - -#ifndef PIKA_MODULE_PIKASTDDATA_DISABLE -void PikaStdData_dict_items___iter__Method(PikaObj *self, Args *args){ - Arg* res = PikaStdData_dict_items___iter__(self); - method_returnArg(args, res); -} -method_typedef( - PikaStdData_dict_items___iter__, - "__iter__", "" -); - -void PikaStdData_dict_items___len__Method(PikaObj *self, Args *args){ - int res = PikaStdData_dict_items___len__(self); - method_returnInt(args, res); -} -method_typedef( - PikaStdData_dict_items___len__, - "__len__", "" -); - -void PikaStdData_dict_items___next__Method(PikaObj *self, Args *args){ - Arg* res = PikaStdData_dict_items___next__(self); - method_returnArg(args, res); -} -method_typedef( - PikaStdData_dict_items___next__, - "__next__", "" -); - -void PikaStdData_dict_items___str__Method(PikaObj *self, Args *args){ - char* res = PikaStdData_dict_items___str__(self); - method_returnStr(args, res); -} -method_typedef( - PikaStdData_dict_items___str__, - "__str__", "" -); - -class_def(PikaStdData_dict_items){ - __BEFORE_MOETHOD_DEF - method_def(PikaStdData_dict_items___iter__, 911732085), - method_def(PikaStdData_dict_items___next__, 1090305216), - method_def(PikaStdData_dict_items___len__, 2047989248), - method_def(PikaStdData_dict_items___str__, 2056834106), -}; -class_inhert(PikaStdData_dict_items, TinyObj); - -PikaObj *New_PikaStdData_dict_items(Args *args){ - PikaObj *self = New_TinyObj(args); - obj_setClass(self, PikaStdData_dict_items); - return self; -} - -Arg *PikaStdData_dict_items(PikaObj *self){ - return obj_newObjInPackage(New_PikaStdData_dict_items); -} -#endif - -#ifndef PIKA_MODULE_PIKASTDDATA_DISABLE -void PikaStdData_dict_keys___iter__Method(PikaObj *self, Args *args){ - Arg* res = PikaStdData_dict_keys___iter__(self); - method_returnArg(args, res); -} -method_typedef( - PikaStdData_dict_keys___iter__, - "__iter__", "" -); - -void PikaStdData_dict_keys___len__Method(PikaObj *self, Args *args){ - int res = PikaStdData_dict_keys___len__(self); - method_returnInt(args, res); -} -method_typedef( - PikaStdData_dict_keys___len__, - "__len__", "" -); - -void PikaStdData_dict_keys___next__Method(PikaObj *self, Args *args){ - Arg* res = PikaStdData_dict_keys___next__(self); - method_returnArg(args, res); -} -method_typedef( - PikaStdData_dict_keys___next__, - "__next__", "" -); - -void PikaStdData_dict_keys___str__Method(PikaObj *self, Args *args){ - char* res = PikaStdData_dict_keys___str__(self); - method_returnStr(args, res); -} -method_typedef( - PikaStdData_dict_keys___str__, - "__str__", "" -); - -class_def(PikaStdData_dict_keys){ - __BEFORE_MOETHOD_DEF - method_def(PikaStdData_dict_keys___iter__, 911732085), - method_def(PikaStdData_dict_keys___next__, 1090305216), - method_def(PikaStdData_dict_keys___len__, 2047989248), - method_def(PikaStdData_dict_keys___str__, 2056834106), -}; -class_inhert(PikaStdData_dict_keys, TinyObj); - -PikaObj *New_PikaStdData_dict_keys(Args *args){ - PikaObj *self = New_TinyObj(args); - obj_setClass(self, PikaStdData_dict_keys); - return self; -} - -Arg *PikaStdData_dict_keys(PikaObj *self){ - return obj_newObjInPackage(New_PikaStdData_dict_keys); -} -#endif - -#ifndef PIKA_MODULE_PIKASTDLIB_DISABLE -void PikaStdLib_MemCheckerMethod(PikaObj *self, Args *args){ - Arg* res = PikaStdLib_MemChecker(self); - method_returnArg(args, res); -} -method_typedef( - PikaStdLib_MemChecker, - "MemChecker", "" -); - -void PikaStdLib_RangeObjMethod(PikaObj *self, Args *args){ - Arg* res = PikaStdLib_RangeObj(self); - method_returnArg(args, res); -} -method_typedef( - PikaStdLib_RangeObj, - "RangeObj", "" -); - -void PikaStdLib_StringObjMethod(PikaObj *self, Args *args){ - Arg* res = PikaStdLib_StringObj(self); - method_returnArg(args, res); -} -method_typedef( - PikaStdLib_StringObj, - "StringObj", "" -); - -void PikaStdLib_SysObjMethod(PikaObj *self, Args *args){ - Arg* res = PikaStdLib_SysObj(self); - method_returnArg(args, res); -} -method_typedef( - PikaStdLib_SysObj, - "SysObj", "" -); - -class_def(PikaStdLib){ - __BEFORE_MOETHOD_DEF -#if 0 - constructor_def(PikaStdLib_StringObj, 145144695), -#endif - constructor_def(PikaStdLib_MemChecker, 426635353), - constructor_def(PikaStdLib_SysObj, 1380528799), -#if 0 - constructor_def(PikaStdLib_RangeObj, 1538428845), -#endif -}; -class_inhert(PikaStdLib, TinyObj); - -PikaObj *New_PikaStdLib(Args *args){ - PikaObj *self = New_TinyObj(args); - obj_setClass(self, PikaStdLib); - return self; -} -#endif - -#ifndef PIKA_MODULE_PIKASTDLIB_DISABLE -void PikaStdLib_MemChecker_getMaxMethod(PikaObj *self, Args *args){ - pika_float res = PikaStdLib_MemChecker_getMax(self); - method_returnFloat(args, res); -} -method_typedef( - PikaStdLib_MemChecker_getMax, - "getMax", "" -); - -void PikaStdLib_MemChecker_getNowMethod(PikaObj *self, Args *args){ - pika_float res = PikaStdLib_MemChecker_getNow(self); - method_returnFloat(args, res); -} -method_typedef( - PikaStdLib_MemChecker_getNow, - "getNow", "" -); - -void PikaStdLib_MemChecker_maxMethod(PikaObj *self, Args *args){ - PikaStdLib_MemChecker_max(self); -} -method_typedef( - PikaStdLib_MemChecker_max, - "max", "" -); - -void PikaStdLib_MemChecker_nowMethod(PikaObj *self, Args *args){ - PikaStdLib_MemChecker_now(self); -} -method_typedef( - PikaStdLib_MemChecker_now, - "now", "" -); - -void PikaStdLib_MemChecker_resetMaxMethod(PikaObj *self, Args *args){ - PikaStdLib_MemChecker_resetMax(self); -} -method_typedef( - PikaStdLib_MemChecker_resetMax, - "resetMax", "" -); - -class_def(PikaStdLib_MemChecker){ - __BEFORE_MOETHOD_DEF - method_def(PikaStdLib_MemChecker_max, 193499019), - method_def(PikaStdLib_MemChecker_now, 193500569), -#if !PIKA_NANO_ENABLE - method_def(PikaStdLib_MemChecker_resetMax, 593750542), -#endif -#if !PIKA_NANO_ENABLE - method_def(PikaStdLib_MemChecker_getMax, 2139551979), -#endif -#if !PIKA_NANO_ENABLE - method_def(PikaStdLib_MemChecker_getNow, 2139553529), -#endif -}; -class_inhert(PikaStdLib_MemChecker, TinyObj); - -PikaObj *New_PikaStdLib_MemChecker(Args *args){ - PikaObj *self = New_TinyObj(args); - obj_setClass(self, PikaStdLib_MemChecker); - return self; -} - -Arg *PikaStdLib_MemChecker(PikaObj *self){ - return obj_newObjInPackage(New_PikaStdLib_MemChecker); -} -#endif - -#ifndef PIKA_MODULE_PIKASTDLIB_DISABLE -void PikaStdLib_RangeObj___next__Method(PikaObj *self, Args *args){ - Arg* res = PikaStdLib_RangeObj___next__(self); - method_returnArg(args, res); -} -method_typedef( - PikaStdLib_RangeObj___next__, - "__next__", "" -); - -class_def(PikaStdLib_RangeObj){ - __BEFORE_MOETHOD_DEF - method_def(PikaStdLib_RangeObj___next__, 1090305216), -}; -class_inhert(PikaStdLib_RangeObj, TinyObj); - -PikaObj *New_PikaStdLib_RangeObj(Args *args){ - PikaObj *self = New_TinyObj(args); - obj_setClass(self, PikaStdLib_RangeObj); - return self; -} - -Arg *PikaStdLib_RangeObj(PikaObj *self){ - return obj_newObjInPackage(New_PikaStdLib_RangeObj); -} -#endif - -#ifndef PIKA_MODULE_PIKASTDLIB_DISABLE -void PikaStdLib_StringObj___next__Method(PikaObj *self, Args *args){ - Arg* res = PikaStdLib_StringObj___next__(self); - method_returnArg(args, res); -} -method_typedef( - PikaStdLib_StringObj___next__, - "__next__", "" -); - -class_def(PikaStdLib_StringObj){ - __BEFORE_MOETHOD_DEF - method_def(PikaStdLib_StringObj___next__, 1090305216), -}; -class_inhert(PikaStdLib_StringObj, TinyObj); - -PikaObj *New_PikaStdLib_StringObj(Args *args){ - PikaObj *self = New_TinyObj(args); - obj_setClass(self, PikaStdLib_StringObj); - return self; -} - -Arg *PikaStdLib_StringObj(PikaObj *self){ - return obj_newObjInPackage(New_PikaStdLib_StringObj); -} -#endif - -#ifndef PIKA_MODULE_PIKASTDLIB_DISABLE -void PikaStdLib_SysObj___getitem__Method(PikaObj *self, Args *args){ - Arg* obj = args_getArg(args, "obj"); - Arg* key = args_getArg(args, "key"); - Arg* res = PikaStdLib_SysObj___getitem__(self, obj, key); - method_returnArg(args, res); -} -method_typedef( - PikaStdLib_SysObj___getitem__, - "__getitem__", "obj,key" -); - -void PikaStdLib_SysObj___setitem__Method(PikaObj *self, Args *args){ - Arg* obj = args_getArg(args, "obj"); - Arg* key = args_getArg(args, "key"); - Arg* val = args_getArg(args, "val"); - Arg* res = PikaStdLib_SysObj___setitem__(self, obj, key, val); - method_returnArg(args, res); -} -method_typedef( - PikaStdLib_SysObj___setitem__, - "__setitem__", "obj,key,val" -); - -void PikaStdLib_SysObj_bytesMethod(PikaObj *self, Args *args){ - Arg* val = args_getArg(args, "val"); - Arg* res = PikaStdLib_SysObj_bytes(self, val); - method_returnArg(args, res); -} -method_typedef( - PikaStdLib_SysObj_bytes, - "bytes", "val" -); - -void PikaStdLib_SysObj_cformatMethod(PikaObj *self, Args *args){ - char* fmt = args_getStr(args, "fmt"); - PikaTuple* var = args_getTuple(args, "var"); - char* res = PikaStdLib_SysObj_cformat(self, fmt, var); - method_returnStr(args, res); -} -method_typedef( - PikaStdLib_SysObj_cformat, - "cformat", "fmt,*var" -); - -void PikaStdLib_SysObj_chrMethod(PikaObj *self, Args *args){ - int val = args_getInt(args, "val"); - char* res = PikaStdLib_SysObj_chr(self, val); - method_returnStr(args, res); -} -method_typedef( - PikaStdLib_SysObj_chr, - "chr", "val" -); - -void PikaStdLib_SysObj_dictMethod(PikaObj *self, Args *args){ - PikaTuple* val = args_getTuple(args, "val"); - Arg* res = PikaStdLib_SysObj_dict(self, val); - method_returnArg(args, res); -} -method_typedef( - PikaStdLib_SysObj_dict, - "dict", "*val" -); - -void PikaStdLib_SysObj_dirMethod(PikaObj *self, Args *args){ - PikaObj* obj = args_getPtr(args, "obj"); - PikaObj* res = PikaStdLib_SysObj_dir(self, obj); - method_returnObj(args, res); -} -method_typedef( - PikaStdLib_SysObj_dir, - "dir", "obj" -); - -void PikaStdLib_SysObj_evalMethod(PikaObj *self, Args *args){ - char* code = args_getStr(args, "code"); - Arg* res = PikaStdLib_SysObj_eval(self, code); - method_returnArg(args, res); -} -method_typedef( - PikaStdLib_SysObj_eval, - "eval", "code" -); - -void PikaStdLib_SysObj_execMethod(PikaObj *self, Args *args){ - char* code = args_getStr(args, "code"); - PikaStdLib_SysObj_exec(self, code); -} -method_typedef( - PikaStdLib_SysObj_exec, - "exec", "code" -); - -void PikaStdLib_SysObj_exitMethod(PikaObj *self, Args *args){ - PikaStdLib_SysObj_exit(self); -} -method_typedef( - PikaStdLib_SysObj_exit, - "exit", "" -); - -void PikaStdLib_SysObj_floatMethod(PikaObj *self, Args *args){ - Arg* arg = args_getArg(args, "arg"); - pika_float res = PikaStdLib_SysObj_float(self, arg); - method_returnFloat(args, res); -} -method_typedef( - PikaStdLib_SysObj_float, - "float", "arg" -); - -void PikaStdLib_SysObj_getattrMethod(PikaObj *self, Args *args){ - PikaObj* obj = args_getPtr(args, "obj"); - char* name = args_getStr(args, "name"); - Arg* res = PikaStdLib_SysObj_getattr(self, obj, name); - method_returnArg(args, res); -} -method_typedef( - PikaStdLib_SysObj_getattr, - "getattr", "obj,name" -); - -void PikaStdLib_SysObj_hasattrMethod(PikaObj *self, Args *args){ - PikaObj* obj = args_getPtr(args, "obj"); - char* name = args_getStr(args, "name"); - int res = PikaStdLib_SysObj_hasattr(self, obj, name); - method_returnInt(args, res); -} -method_typedef( - PikaStdLib_SysObj_hasattr, - "hasattr", "obj,name" -); - -void PikaStdLib_SysObj_helpMethod(PikaObj *self, Args *args){ - char* name = args_getStr(args, "name"); - PikaStdLib_SysObj_help(self, name); -} -method_typedef( - PikaStdLib_SysObj_help, - "help", "name" -); - -void PikaStdLib_SysObj_hexMethod(PikaObj *self, Args *args){ - int val = args_getInt(args, "val"); - char* res = PikaStdLib_SysObj_hex(self, val); - method_returnStr(args, res); -} -method_typedef( - PikaStdLib_SysObj_hex, - "hex", "val" -); - -void PikaStdLib_SysObj_idMethod(PikaObj *self, Args *args){ - Arg* obj = args_getArg(args, "obj"); - int res = PikaStdLib_SysObj_id(self, obj); - method_returnInt(args, res); -} -method_typedef( - PikaStdLib_SysObj_id, - "id", "obj" -); - -void PikaStdLib_SysObj_inputMethod(PikaObj *self, Args *args){ - PikaTuple* info = args_getTuple(args, "info"); - char* res = PikaStdLib_SysObj_input(self, info); - method_returnStr(args, res); -} -method_typedef( - PikaStdLib_SysObj_input, - "input", "*info" -); - -void PikaStdLib_SysObj_intMethod(PikaObj *self, Args *args){ - Arg* arg = args_getArg(args, "arg"); - int res = PikaStdLib_SysObj_int(self, arg); - method_returnInt(args, res); -} -method_typedef( - PikaStdLib_SysObj_int, - "int", "arg" -); - -void PikaStdLib_SysObj_iterMethod(PikaObj *self, Args *args){ - Arg* arg = args_getArg(args, "arg"); - Arg* res = PikaStdLib_SysObj_iter(self, arg); - method_returnArg(args, res); -} -method_typedef( - PikaStdLib_SysObj_iter, - "iter", "arg" -); - -void PikaStdLib_SysObj_lenMethod(PikaObj *self, Args *args){ - Arg* arg = args_getArg(args, "arg"); - int res = PikaStdLib_SysObj_len(self, arg); - method_returnInt(args, res); -} -method_typedef( - PikaStdLib_SysObj_len, - "len", "arg" -); - -void PikaStdLib_SysObj_listMethod(PikaObj *self, Args *args){ - PikaTuple* val = args_getTuple(args, "val"); - Arg* res = PikaStdLib_SysObj_list(self, val); - method_returnArg(args, res); -} -method_typedef( - PikaStdLib_SysObj_list, - "list", "*val" -); - -void PikaStdLib_SysObj_openMethod(PikaObj *self, Args *args){ - char* path = args_getStr(args, "path"); - char* mode = args_getStr(args, "mode"); - PikaObj* res = PikaStdLib_SysObj_open(self, path, mode); - method_returnObj(args, res); -} -method_typedef( - PikaStdLib_SysObj_open, - "open", "path,mode" -); - -void PikaStdLib_SysObj_ordMethod(PikaObj *self, Args *args){ - char* val = args_getStr(args, "val"); - int res = PikaStdLib_SysObj_ord(self, val); - method_returnInt(args, res); -} -method_typedef( - PikaStdLib_SysObj_ord, - "ord", "val" -); - -void PikaStdLib_SysObj_printMethod(PikaObj *self, Args *args){ - PikaTuple* val = args_getTuple(args, "val"); - PikaDict* ops = args_getDict(args, "ops"); - PikaStdLib_SysObj_print(self, val, ops); -} -method_typedef( - PikaStdLib_SysObj_print, - "print", "*val,**ops" -); - -void PikaStdLib_SysObj_rangeMethod(PikaObj *self, Args *args){ - PikaTuple* ax = args_getTuple(args, "ax"); - Arg* res = PikaStdLib_SysObj_range(self, ax); - method_returnArg(args, res); -} -method_typedef( - PikaStdLib_SysObj_range, - "range", "*ax" -); - -void PikaStdLib_SysObj_setattrMethod(PikaObj *self, Args *args){ - PikaObj* obj = args_getPtr(args, "obj"); - char* name = args_getStr(args, "name"); - Arg* val = args_getArg(args, "val"); - PikaStdLib_SysObj_setattr(self, obj, name, val); -} -method_typedef( - PikaStdLib_SysObj_setattr, - "setattr", "obj,name,val" -); - -void PikaStdLib_SysObj_strMethod(PikaObj *self, Args *args){ - Arg* arg = args_getArg(args, "arg"); - char* res = PikaStdLib_SysObj_str(self, arg); - method_returnStr(args, res); -} -method_typedef( - PikaStdLib_SysObj_str, - "str", "arg" -); - -void PikaStdLib_SysObj_typeMethod(PikaObj *self, Args *args){ - Arg* arg = args_getArg(args, "arg"); - Arg* res = PikaStdLib_SysObj_type(self, arg); - method_returnArg(args, res); -} -method_typedef( - PikaStdLib_SysObj_type, - "type", "arg" -); - -class_def(PikaStdLib_SysObj){ - __BEFORE_MOETHOD_DEF -#if !PIKA_NANO_ENABLE - method_def(PikaStdLib_SysObj_id, 5863474), -#endif -#if !PIKA_NANO_ENABLE - method_def(PikaStdLib_SysObj_chr, 193488354), -#endif -#if !PIKA_NANO_ENABLE - method_def(PikaStdLib_SysObj_dir, 193489476), -#endif -#if !PIKA_NANO_ENABLE - method_def(PikaStdLib_SysObj_hex, 193493706), -#endif - method_def(PikaStdLib_SysObj_int, 193495088), - method_def(PikaStdLib_SysObj_len, 193498052), -#if !PIKA_NANO_ENABLE - method_def(PikaStdLib_SysObj_ord, 193501738), -#endif - method_def(PikaStdLib_SysObj_str, 193506174), -#if !PIKA_NANO_ENABLE - method_def(PikaStdLib_SysObj_setattr, 204224428), -#endif -#if !PIKA_NANO_ENABLE - method_def(PikaStdLib_SysObj_bytes, 254850636), -#endif - method_def(PikaStdLib_SysObj_float, 259121563), -#if !PIKA_NANO_ENABLE - method_def(PikaStdLib_SysObj_input, 262752949), -#endif - method_def(PikaStdLib_SysObj_print, 271190290), - method_def(PikaStdLib_SysObj_range, 272956402), -#if !PIKA_NANO_ENABLE - method_def(PikaStdLib_SysObj_hasattr, 872734812), -#endif -#if PIKA_SYNTAX_FORMAT_ENABLE - method_def(PikaStdLib_SysObj_cformat, 1049381873), -#endif - method_def(PikaStdLib_SysObj___setitem__, 1364865276), - method_def(PikaStdLib_SysObj___getitem__, 1535436016), -#if !PIKA_NANO_ENABLE - method_def(PikaStdLib_SysObj_getattr, 1886477984), -#endif -#if PIKA_BUILTIN_STRUCT_ENABLE - method_def(PikaStdLib_SysObj_dict, 2090185033), -#endif -#if PIKA_EXEC_ENABLE - method_def(PikaStdLib_SysObj_eval, 2090235053), -#endif -#if PIKA_EXEC_ENABLE - method_def(PikaStdLib_SysObj_exec, 2090237354), -#endif -#if !PIKA_NANO_ENABLE - method_def(PikaStdLib_SysObj_exit, 2090237503), -#endif -#if !PIKA_NANO_ENABLE - method_def(PikaStdLib_SysObj_help, 2090324718), -#endif - method_def(PikaStdLib_SysObj_iter, 2090376761), -#if PIKA_BUILTIN_STRUCT_ENABLE - method_def(PikaStdLib_SysObj_list, 2090473057), -#endif -#if PIKA_FILEIO_ENABLE - method_def(PikaStdLib_SysObj_open, 2090588023), -#endif -#if !PIKA_NANO_ENABLE - method_def(PikaStdLib_SysObj_type, 2090777863), -#endif -}; -class_inhert(PikaStdLib_SysObj, TinyObj); - -PikaObj *New_PikaStdLib_SysObj(Args *args){ - PikaObj *self = New_TinyObj(args); - obj_setClass(self, PikaStdLib_SysObj); - return self; -} - -Arg *PikaStdLib_SysObj(PikaObj *self){ - return obj_newObjInPackage(New_PikaStdLib_SysObj); -} -#endif - -#ifndef PIKA_MODULE_PIKASTDTASK_DISABLE -void PikaStdTask_TaskMethod(PikaObj *self, Args *args){ - Arg* res = PikaStdTask_Task(self); - method_returnArg(args, res); -} -method_typedef( - PikaStdTask_Task, - "Task", "" -); - -class_def(PikaStdTask){ - __BEFORE_MOETHOD_DEF - constructor_def(PikaStdTask_Task, 2089601848), -}; -class_inhert(PikaStdTask, TinyObj); - -PikaObj *New_PikaStdTask(Args *args){ - PikaObj *self = New_TinyObj(args); - obj_setClass(self, PikaStdTask); - return self; -} -#endif - -#ifndef PIKA_MODULE_PIKASTDTASK_DISABLE -void PikaStdTask_Task___init__Method(PikaObj *self, Args *args){ - PikaStdTask_Task___init__(self); -} -method_typedef( - PikaStdTask_Task___init__, - "__init__", "" -); - -void PikaStdTask_Task_call_alwaysMethod(PikaObj *self, Args *args){ - Arg* fun_todo = args_getArg(args, "fun_todo"); - PikaStdTask_Task_call_always(self, fun_todo); -} -method_typedef( - PikaStdTask_Task_call_always, - "call_always", "fun_todo" -); - -void PikaStdTask_Task_call_period_msMethod(PikaObj *self, Args *args){ - Arg* fun_todo = args_getArg(args, "fun_todo"); - int period_ms = args_getInt(args, "period_ms"); - PikaStdTask_Task_call_period_ms(self, fun_todo, period_ms); -} -method_typedef( - PikaStdTask_Task_call_period_ms, - "call_period_ms", "fun_todo,period_ms" -); - -void PikaStdTask_Task_call_whenMethod(PikaObj *self, Args *args){ - Arg* fun_todo = args_getArg(args, "fun_todo"); - Arg* fun_when = args_getArg(args, "fun_when"); - PikaStdTask_Task_call_when(self, fun_todo, fun_when); -} -method_typedef( - PikaStdTask_Task_call_when, - "call_when", "fun_todo,fun_when" -); - -void PikaStdTask_Task_platformGetTickMethod(PikaObj *self, Args *args){ - PikaStdTask_Task_platformGetTick(self); -} -method_typedef( - PikaStdTask_Task_platformGetTick, - "platformGetTick", "" -); - -void PikaStdTask_Task_run_foreverMethod(PikaObj *self, Args *args){ - PikaStdTask_Task_run_forever(self); -} -method_typedef( - PikaStdTask_Task_run_forever, - "run_forever", "" -); - -void PikaStdTask_Task_run_onceMethod(PikaObj *self, Args *args){ - PikaStdTask_Task_run_once(self); -} -method_typedef( - PikaStdTask_Task_run_once, - "run_once", "" -); - -void PikaStdTask_Task_run_until_msMethod(PikaObj *self, Args *args){ - int until_ms = args_getInt(args, "until_ms"); - PikaStdTask_Task_run_until_ms(self, until_ms); -} -method_typedef( - PikaStdTask_Task_run_until_ms, - "run_until_ms", "until_ms" -); - -class_def(PikaStdTask_Task){ - __BEFORE_MOETHOD_DEF - method_def(PikaStdTask_Task_run_forever, 408322738), - method_def(PikaStdTask_Task_run_until_ms, 854930212), - method_def(PikaStdTask_Task___init__, 904762485), - method_def(PikaStdTask_Task_call_always, 1368427953), - method_def(PikaStdTask_Task_call_period_ms, 1674236450), - method_def(PikaStdTask_Task_run_once, 1726949022), - method_def(PikaStdTask_Task_platformGetTick, 1897947957), - method_def(PikaStdTask_Task_call_when, 2141638002), -}; -class_inhert(PikaStdTask_Task, PikaStdLib_SysObj); - -PikaObj *New_PikaStdTask_Task(Args *args){ - PikaObj *self = New_PikaStdLib_SysObj(args); - obj_newObj(self, "calls", "PikaStdData_List", New_PikaStdData_List); - obj_setClass(self, PikaStdTask_Task); - return self; -} - -Arg *PikaStdTask_Task(PikaObj *self){ - return obj_newObjInPackage(New_PikaStdTask_Task); -} -#endif - diff --git a/examples/pikapython/pikapython/pikascript-api/main.py.o b/examples/pikapython/pikapython/pikascript-api/main.py.o deleted file mode 100644 index fb89147f..00000000 Binary files a/examples/pikapython/pikapython/pikascript-api/main.py.o and /dev/null differ diff --git a/examples/pikapython/pikapython/pikascript-api/pikaModules.py.a b/examples/pikapython/pikapython/pikascript-api/pikaModules.py.a deleted file mode 100644 index 2f7f6a2f..00000000 Binary files a/examples/pikapython/pikapython/pikascript-api/pikaModules.py.a and /dev/null differ diff --git a/examples/pikapython/pikapython/pikascript-api/pikaScript.c b/examples/pikapython/pikapython/pikascript-api/pikaScript.c deleted file mode 100644 index ab85744c..00000000 --- a/examples/pikapython/pikapython/pikascript-api/pikaScript.c +++ /dev/null @@ -1,35 +0,0 @@ -/* - * [Warning!] This file is auto-generated by pika compiler. - * Do not edit it manually. - * The source code is *.pyi file. - * More details: - * English Doc: - * https://pikadoc.readthedocs.io/en/latest/PikaScript%20%E6%A8%A1%E5%9D%97%E6%A6%82%E8%BF%B0.html - * Chinese Doc: - * https://pikadoc.readthedocs.io/zh/latest/PikaScript%20%E6%A8%A1%E5%9D%97%E6%A6%82%E8%BF%B0.html - */ - -#include "PikaMain.h" -#include -#include - -volatile PikaObj *__pikaMain; -PikaObj *pikaScriptInit(void){ - __platform_printf("======[pikascript packages installed]======\r\n"); - pks_printVersion(); - __platform_printf("PikaStdLib==v1.12.0\r\n"); - __platform_printf("===========================================\r\n"); - PikaObj* pikaMain = newRootObj("pikaMain", New_PikaMain); - __pikaMain = pikaMain; - extern unsigned char pikaModules_py_a[]; - obj_linkLibrary(pikaMain, pikaModules_py_a); -#if PIKA_INIT_STRING_ENABLE - obj_run(pikaMain, - "print('hello PikaPython!')\n" - "\n"); -#else - obj_runModule((PikaObj*)pikaMain, "main"); -#endif - return pikaMain; -} - diff --git a/examples/pikapython/pikapython/pikascript-api/pikaScript.h b/examples/pikapython/pikapython/pikascript-api/pikaScript.h deleted file mode 100644 index 3b5c169f..00000000 --- a/examples/pikapython/pikapython/pikascript-api/pikaScript.h +++ /dev/null @@ -1,13 +0,0 @@ -/* ******************************** */ -/* Warning! Don't modify this file! */ -/* ******************************** */ -#ifndef __pikaScript__H -#define __pikaScript__H -#include -#include -#include "PikaObj.h" -#include "PikaMain.h" - -PikaObj * pikaScriptInit(void); - -#endif diff --git a/examples/pikapython/pikapython/pikascript-core/PikaCompiler.c b/examples/pikapython/pikapython/pikascript-core/PikaCompiler.c index 212687fb..e18b5300 100644 --- a/examples/pikapython/pikapython/pikascript-core/PikaCompiler.c +++ b/examples/pikapython/pikapython/pikascript-core/PikaCompiler.c @@ -35,6 +35,11 @@ const char magic_code_pyo[] = {0x0f, 'p', 'y', 'o'}; +/* + * @brief check magic code of pyo file + * @param bytecode + * @return PIKA_TRUE or PIKA_FALSE + */ static PIKA_BOOL _check_magic_code_pyo(uint8_t* bytecode) { char* data = (char*)bytecode; if (data[0] == magic_code_pyo[0] && data[1] == magic_code_pyo[1] && @@ -44,6 +49,11 @@ static PIKA_BOOL _check_magic_code_pyo(uint8_t* bytecode) { return PIKA_FALSE; } +/* + * @brief get bytecode from bytes arg + * @param self bytes arg + * @return bytecode + */ static uint8_t* arg_getBytecode(Arg* self) { uint8_t* bytecode_file = arg_getBytes(self); if (_check_magic_code_pyo(bytecode_file)) { @@ -52,6 +62,11 @@ static uint8_t* arg_getBytecode(Arg* self) { return bytecode_file; } +/* + * @brief get bytecode size from bytes arg + * @param self bytes arg + * @return bytecode size + */ static size_t arg_getBytecodeSize(Arg* self) { size_t size_all = arg_getBytesSize(self); uint8_t* bytecode_file = arg_getBytes(self); @@ -98,7 +113,8 @@ PIKA_RES pikaCompile(char* output_file_name, char* py_lines) { char void_ = 0; FILE* bytecode_f = pika_platform_fopen(output_file_name, "wb+"); if (NULL == bytecode_f) { - pika_platform_printf("Error: open file %s failed.\r\n", output_file_name); + pika_platform_printf("Error: open file %s failed.\r\n", + output_file_name); res = PIKA_RES_ERR_IO_ERROR; goto exit; } @@ -118,8 +134,7 @@ PIKA_RES pikaCompile(char* output_file_name, char* py_lines) { const_pool_size = bytecode_frame.const_pool.size; instruct_array_size = bytecode_frame.instruct_array.size; bytecode_size = const_pool_size + instruct_array_size + - sizeof(const_pool_size) + - sizeof(instruct_array_size); + sizeof(const_pool_size) + sizeof(instruct_array_size); byteCodeFrame_deinit(&bytecode_frame); /* step 2, write instruct array to file */ @@ -129,7 +144,7 @@ PIKA_RES pikaCompile(char* output_file_name, char* py_lines) { pika_platform_fwrite(&bytecode_size, 1, sizeof(bytecode_size), bytecode_f); /* write ins array size */ pika_platform_fwrite(&instruct_array_size, 1, sizeof(instruct_array_size), - bytecode_f); + bytecode_f); byteCodeFrame_init(&bytecode_frame); bytecode_frame.const_pool.output_f = bytecode_f; bytecode_frame.instruct_array.output_f = bytecode_f; @@ -140,7 +155,8 @@ PIKA_RES pikaCompile(char* output_file_name, char* py_lines) { byteCodeFrame_deinit(&bytecode_frame); /* step 3, write const pool to file */ - pika_platform_fwrite(&const_pool_size, 1, sizeof(const_pool_size), bytecode_f); + pika_platform_fwrite(&const_pool_size, 1, sizeof(const_pool_size), + bytecode_f); void_ = 0; /* add \0 at the start */ pika_platform_fwrite(&void_, 1, 1, bytecode_f); @@ -225,7 +241,14 @@ void LibObj_dynamicLink(LibObj* self, char* module_name, uint8_t* bytecode) { obj_setPtr(module_obj, "bytecode", bytecode); } -/* add bytecode to lib, and copy the bytecode to the buff in the lib */ +/* + * @brief add bytecode to lib, and copy the bytecode to the buff in the lib + * @param self the lib obj + * @param module_name the module name + * @param bytecode the bytecode + * @param size the size of the bytecode + * @return error code + */ int LibObj_staticLink(LibObj* self, char* module_name, uint8_t* bytecode, @@ -316,14 +339,26 @@ static int32_t __foreach_handler_libWriteIndex(Arg* argEach, Args* context) { module_name = strsReplace(&buffs, module_name, "|", "."); // pika_platform_printf(" %s:%d\r\n", module_name, bytecode_size); pika_platform_memcpy(buff, module_name, strGetSize(module_name)); - pika_platform_fwrite(buff, 1, LIB_INFO_BLOCK_SIZE - sizeof(bytecode_size), - out_file); - pika_platform_fwrite(&bytecode_size, 1, sizeof(bytecode_size), out_file); + pika_platform_fwrite( + buff, 1, LIB_INFO_BLOCK_SIZE - sizeof(bytecode_size), out_file); + pika_platform_fwrite(&bytecode_size, 1, sizeof(bytecode_size), + out_file); } strsDeinit(&buffs); return 0; } +static int32_t __foreach_handler_libSumSize(Arg* argEach, Args* context) { + if (argType_isObject(arg_getType(argEach))) { + PikaObj* module_obj = arg_getPtr(argEach); + uint32_t bytecode_size = obj_getBytesSize(module_obj, "buff"); + bytecode_size = aline_by(bytecode_size, sizeof(uint32_t)); + args_setInt(context, "sum_size", + args_getInt(context, "sum_size") + bytecode_size); + } + return 0; +} + static int32_t __foreach_handler_getModuleNum(Arg* argEach, Args* context) { if (argType_isObject(arg_getType(argEach))) { args_setInt(context, "module_num", @@ -338,25 +373,41 @@ int LibObj_saveLibraryFile(LibObj* self, char* output_file_name) { Args context = {0}; args_setPtr(&context, "out_file", out_file); args_setInt(&context, "module_num", 0); + args_setInt(&context, "sum_size", 0); /* write meta information */ char buff[LIB_INFO_BLOCK_SIZE] = {0}; args_foreach(self->list, __foreach_handler_getModuleNum, &context); + /* get sum size of pya */ + args_foreach(self->list, __foreach_handler_libSumSize, &context); + /* meta info */ - char magic_code[] = {0x7f, 'p', 'y', 'a'}; + char magic_code[] = {0x0f, 'p', 'y', 'a'}; uint32_t version_num = LIB_VERSION_NUMBER; uint32_t module_num = args_getInt(&context, "module_num"); + uint32_t modules_size = args_getInt(&context, "sum_size") + + (module_num + 1) * LIB_INFO_BLOCK_SIZE - + sizeof(uint32_t) * 2; /* write meta info */ - const uint32_t magic_code_offset = sizeof(uint32_t) * 0; - const uint32_t version_offset = sizeof(uint32_t) * 1; - const uint32_t module_num_offset = sizeof(uint32_t) * 2; + const uint32_t magic_code_offset = + sizeof(uint32_t) * PIKA_APP_MAGIC_CODE_OFFSET; + const uint32_t modules_size_offset = + sizeof(uint32_t) * PIKA_APP_MODULE_SIZE_OFFSET; + const uint32_t version_offset = sizeof(uint32_t) * PIKA_APP_VERSION_OFFSET; + const uint32_t module_num_offset = + sizeof(uint32_t) * PIKA_APP_MODULE_NUM_OFFSET; - pika_platform_memcpy(buff + magic_code_offset, &magic_code, sizeof(uint32_t)); + pika_platform_memcpy(buff + magic_code_offset, &magic_code, + sizeof(uint32_t)); pika_platform_memcpy(buff + version_offset, &version_num, sizeof(uint32_t)); /* write module_num to the file */ - pika_platform_memcpy(buff + module_num_offset, &module_num, sizeof(uint32_t)); + pika_platform_memcpy(buff + module_num_offset, &module_num, + sizeof(uint32_t)); + /* write modules_size to the file */ + pika_platform_memcpy(buff + modules_size_offset, &modules_size, + sizeof(uint32_t)); /* aline to 32 bytes */ pika_platform_fwrite(buff, 1, LIB_INFO_BLOCK_SIZE, out_file); /* write module index to file */ @@ -378,11 +429,11 @@ static int _getModuleNum(uint8_t* library_bytes) { char* magic_code = (char*)library_bytes; uint32_t* library_info = (uint32_t*)library_bytes; - uint32_t version_num = library_info[1]; - uint32_t module_num = library_info[2]; + uint32_t version_num = library_info[PIKA_APP_VERSION_OFFSET]; + uint32_t module_num = library_info[PIKA_APP_MODULE_NUM_OFFSET]; /* check magic_code */ - if (!((magic_code[0] == 0x7f) && (magic_code[1] == 'p') && + if (!((magic_code[0] == 0x0f) && (magic_code[1] == 'p') && (magic_code[2] == 'y') && (magic_code[3] == 'a'))) { pika_platform_printf("Error: invalid magic code.\r\n"); return PIKA_RES_ERR_ILLEGAL_MAGIC_CODE; @@ -479,14 +530,14 @@ int LibObj_loadLibraryFile(LibObj* self, char* lib_file_name) { Arg* file_arg = arg_loadFile(NULL, lib_file_name); if (NULL == file_arg) { pika_platform_printf("Error: Could not load library file '%s'\n", - lib_file_name); + lib_file_name); return PIKA_RES_ERR_IO_ERROR; } /* save file_arg as @lib_buf to libObj */ obj_setArg_noCopy(self, "@lib_buf", file_arg); if (0 != LibObj_loadLibrary(self, arg_getBytes(file_arg))) { pika_platform_printf("Error: Could not load library from '%s'\n", - lib_file_name); + lib_file_name); return PIKA_RES_ERR_OPERATION_FAILED; } return PIKA_RES_OK; @@ -503,7 +554,7 @@ int Lib_loadLibraryFileToArray(char* origin_file_name, char* out_folder) { int res = 0; if (NULL == file_arg) { pika_platform_printf("Error: Could not load file '%s'\n", - origin_file_name); + origin_file_name); return 1; } char* output_file_name = NULL; @@ -512,8 +563,7 @@ int Lib_loadLibraryFileToArray(char* origin_file_name, char* out_folder) { output_file_name = strsReplace(&buffs, output_file_name, ".", "_"); output_file_name = strsAppend(&buffs, output_file_name, ".c"); - char* output_file_path = strsAppend(&buffs, out_folder, "/"); - output_file_path = strsAppend(&buffs, output_file_path, output_file_name); + char* output_file_path = strsPathJoin(&buffs, out_folder, output_file_name); FILE* fp = pika_platform_fopen(output_file_path, "wb+"); char* array_name = strsGetLastToken(&buffs, origin_file_name, '/'); @@ -551,13 +601,13 @@ static PIKA_RES __Maker_compileModuleWithInfo(PikaMaker* self, Args buffs = {0}; char* input_file_name = strsAppend(&buffs, module_name, ".py"); char* input_file_path = - strsAppend(&buffs, obj_getStr(self, "pwd"), input_file_name); + strsPathJoin(&buffs, obj_getStr(self, "pwd"), input_file_name); pika_platform_printf(" compiling %s...\r\n", input_file_name); char* output_file_name = strsAppend(&buffs, module_name, ".py.o"); char* output_file_path = NULL; output_file_path = - strsAppend(&buffs, obj_getStr(self, "pwd"), "pikascript-api/"); - output_file_path = strsAppend(&buffs, output_file_path, output_file_name); + strsPathJoin(&buffs, obj_getStr(self, "pwd"), "pikascript-api"); + output_file_path = strsPathJoin(&buffs, output_file_path, output_file_name); PIKA_RES res = pikaCompileFileWithOutputName(output_file_path, input_file_path); strsDeinit(&buffs); @@ -573,16 +623,34 @@ PikaMaker* New_PikaMaker(void) { return self; } +/* + * @brief: deinit PikaMaker + * @param: self PikaMaker + * @return: void + */ void pikaMaker_deinit(PikaMaker* self) { LibObj* lib = obj_getPtr(self, "lib"); LibObj_deinit(lib); obj_deinit(self); } +/* + * @brief: set pwd + * @param: self PikaMaker + * @param: pwd + * @return: void + */ void pikaMaker_setPWD(PikaMaker* self, char* pwd) { obj_setStr(self, "pwd", pwd); } +/* + * @brief: set state + * @param: self PikaMaker + * @param: module_name + * @param: state + * @return: void + */ void pikaMaker_setState(PikaMaker* self, char* module_name, char* state) { obj_newMetaObj(self, module_name, New_TinyObj); PikaObj* module_obj = obj_getObj(self, module_name); @@ -590,6 +658,12 @@ void pikaMaker_setState(PikaMaker* self, char* module_name, char* state) { obj_setStr(module_obj, "state", state); } +/* + * @brief: compile module + * @param: self PikaMaker + * @param: module_name + * @return: PIKA_RES + */ PIKA_RES pikaMaker_compileModule(PikaMaker* self, char* module_name) { PIKA_RES res = __Maker_compileModuleWithInfo(self, module_name); /* update compile info */ @@ -609,8 +683,8 @@ int pikaMaker_getDependencies(PikaMaker* self, char* module_name) { ConstPool* const_pool = NULL; InstructArray* ins_array = NULL; char* module_path = - strsAppend(&buffs, obj_getStr(self, "pwd"), "pikascript-api/"); - module_path = strsAppend(&buffs, module_path, module_name); + strsPathJoin(&buffs, obj_getStr(self, "pwd"), "pikascript-api/"); + module_path = strsPathJoin(&buffs, module_path, module_name); char* file_path = strsAppend(&buffs, module_path, ".py.o"); Arg* file_arg = arg_loadFile(NULL, file_path); uint8_t offset_befor = 0; @@ -633,7 +707,7 @@ int pikaMaker_getDependencies(PikaMaker* self, char* module_name) { char* imp_module_name = constPool_getByOffset(const_pool, ins_unit->const_pool_index); char* imp_module_path = - strsAppend(&buffs, obj_getStr(self, "pwd"), imp_module_name); + strsPathJoin(&buffs, obj_getStr(self, "pwd"), imp_module_name); /* check if compiled the module */ if (obj_isArgExist(self, imp_module_name)) { /* module info is exist, do nothing */ @@ -648,15 +722,16 @@ int pikaMaker_getDependencies(PikaMaker* self, char* module_name) { strsAppend(&buffs, imp_module_path, ".py.o"), "rb"); if (NULL != imp_file_pyo) { pika_platform_printf(" loading %s.py.o...\r\n", - imp_module_path); + imp_module_path); /* found *.py.o, push to compiled list */ pikaMaker_setState(self, imp_module_name, "compiled"); - char* imp_api_path = strsAppend( + char* imp_api_path = strsPathJoin( &buffs, obj_getStr(self, "pwd"), "pikascript-api/"); imp_api_path = - strsAppend(&buffs, imp_api_path, imp_module_name); + strsPathJoin(&buffs, imp_api_path, imp_module_name); FILE* imp_file_pyo_api = pika_platform_fopen( strsAppend(&buffs, imp_api_path, ".py.o"), "wb+"); + pika_assert(imp_file_pyo_api != NULL); /* copy imp_file_pyo to imp_api_path */ uint8_t* buff = (uint8_t*)pika_platform_malloc(128); size_t read_size = 0; @@ -665,7 +740,7 @@ int pikaMaker_getDependencies(PikaMaker* self, char* module_name) { pika_platform_fread(buff, 1, 128, imp_file_pyo); if (read_size > 0) { pika_platform_fwrite(buff, 1, read_size, - imp_file_pyo_api); + imp_file_pyo_api); } else { break; } @@ -712,7 +787,7 @@ int32_t __foreach_handler_printStates(Arg* argEach, Args* context) { if (argType_isObject(arg_getType(argEach))) { PikaObj* module_obj = arg_getPtr(argEach); pika_platform_printf("%s: %s\r\n", obj_getStr(module_obj, "name"), - obj_getStr(module_obj, "state")); + obj_getStr(module_obj, "state")); } return 0; } @@ -752,6 +827,12 @@ char* pikaMaker_getFirstNocompiled(PikaMaker* self) { return obj_getStr(self, "res"); } +/* + * @brief compile module with depends + * @param self PikaMaker + * @param module_name + * @return PIKA_RES + */ PIKA_RES pikaMaker_compileModuleWithDepends(PikaMaker* self, char* module_name) { PIKA_RES res = PIKA_RES_OK; @@ -787,10 +868,10 @@ int32_t __foreach_handler_linkCompiledModules(Arg* argEach, Args* context) { char* state = obj_getStr(module_obj, "state"); if (strEqu(state, "compiled")) { char* pwd = obj_getStr(maker, "pwd"); - char* folder_path = strsAppend(&buffs, pwd, "pikascript-api/"); + char* folder_path = strsPathJoin(&buffs, pwd, "pikascript-api/"); char* module_file_name = strsAppend(&buffs, module_name, ".py.o"); char* module_file_path = - strsAppend(&buffs, folder_path, module_file_name); + strsPathJoin(&buffs, folder_path, module_file_name); LibObj_staticLinkFile(lib, module_file_path); } } @@ -798,8 +879,9 @@ int32_t __foreach_handler_linkCompiledModules(Arg* argEach, Args* context) { return 0; } -PIKA_RES pikaMaker_linkCompiledModulesFullPath(PikaMaker* self, - char* lib_path) { +PIKA_RES _do_pikaMaker_linkCompiledModulesFullPath(PikaMaker* self, + char* lib_path, + PIKA_BOOL gen_c_array) { PIKA_RES compile_err = (PIKA_RES)obj_getInt(self, "err"); if (PIKA_RES_OK != compile_err) { pika_platform_printf(" Error: compile failed, link aborted.\r\n"); @@ -814,27 +896,108 @@ PIKA_RES pikaMaker_linkCompiledModulesFullPath(PikaMaker* self, args_foreach(self->list, __foreach_handler_linkCompiledModules, &context); args_deinit_stack(&context); char* pwd = obj_getStr(self, "pwd"); - char* lib_path_folder = strsCopy(&buffs, lib_path); - strPopLastToken(lib_path_folder, '/'); - char* folder_path = strsAppend(&buffs, pwd, lib_path_folder); - folder_path = strsAppend(&buffs, folder_path, "/"); - char* lib_file_path = strsAppend(&buffs, pwd, lib_path); + char* lib_path_folder = strsPathGetFolder(&buffs, lib_path); + char* folder_path = strsPathJoin(&buffs, pwd, lib_path_folder); + char* lib_file_path = strsPathJoin(&buffs, pwd, lib_path); LibObj_saveLibraryFile(lib, lib_file_path); - Lib_loadLibraryFileToArray(lib_file_path, folder_path); + if (gen_c_array) { + Lib_loadLibraryFileToArray(lib_file_path, folder_path); + } strsDeinit(&buffs); return PIKA_RES_OK; } -PIKA_RES pikaMaker_linkCompiledModules(PikaMaker* self, char* lib_name) { +PIKA_RES pikaMaker_linkCompiledModulesFullPath(PikaMaker* self, + char* lib_path) { + return _do_pikaMaker_linkCompiledModulesFullPath(self, lib_path, PIKA_TRUE); +} + +PIKA_RES _do_pikaMaker_linkCompiledModules(PikaMaker* self, + char* lib_name, + PIKA_BOOL gen_c_array) { Args buffs = {0}; - char* lib_file_path = strsAppend(&buffs, "pikascript-api/", lib_name); - PIKA_RES res = pikaMaker_linkCompiledModulesFullPath(self, lib_file_path); + char* lib_file_path = strsPathJoin(&buffs, "pikascript-api/", lib_name); + PIKA_RES res = _do_pikaMaker_linkCompiledModulesFullPath( + self, lib_file_path, gen_c_array); strsDeinit(&buffs); return res; } +PIKA_RES pikaMaker_linkCompiledModules(PikaMaker* self, char* lib_name) { + return _do_pikaMaker_linkCompiledModules(self, lib_name, PIKA_TRUE); +} + +/* + * @brief link raw file to library + * @param self PikaMaker + * @param file_path + * @return PIKA_RES + */ PIKA_RES pikaMaker_linkRaw(PikaMaker* self, char* file_path) { LibObj* lib = obj_getPtr(self, "lib"); LibObj_staticLinkFile(lib, file_path); return PIKA_RES_OK; } + +/* + * @brief open file from library + * @param file_name + * @param mode "r" or "rb" + * @return pikafs_FILE* or NULL if failed + */ +pikafs_FILE* pikafs_fopen(char* file_name, char* mode) { + pikafs_FILE* f = (pikafs_FILE*)pikaMalloc(sizeof(pikafs_FILE)); + memset(f, 0, sizeof(pikafs_FILE)); + extern volatile PikaObj* __pikaMain; + uint8_t* library_bytes = obj_getPtr((PikaObj*)__pikaMain, "@libraw"); + if (NULL == library_bytes) { + return NULL; + } + if (PIKA_RES_OK != + _loadModuleDataWithName(library_bytes, file_name, &f->addr, &f->size)) { + return NULL; + } + return f; +} + +/* + * @brief read file + * @param buf the buffer to read + * @param size size of each item + * @param count count of items + * @param f file + * @return read count + */ +int pikafs_fread(void* buf, size_t size, size_t count, pikafs_FILE* f) { + if (f->pos >= f->size) { + return 0; + } + if (f->pos + size * count > f->size) { + count = (f->size - f->pos) / size; + } + __platform_memcpy(buf, f->addr + f->pos, size * count); + f->pos += size * count; + return count; +} + +/* + * @brief write file + * @param buf the buffer to write + * @param size size of each item + * @param count count of items + * @param f file + * @return write count or -1 if failed + */ +int pikafs_fwrite(void* buf, size_t size, size_t count, pikafs_FILE* file) { + return -1; +} + +/* + * @brief close file + * @param f file + * @return 0 if success + */ +int pikafs_fclose(pikafs_FILE* file) { + pikaFree(file, sizeof(pikafs_FILE)); + return 0; +} diff --git a/examples/pikapython/pikapython/pikascript-core/PikaCompiler.h b/examples/pikapython/pikapython/pikascript-core/PikaCompiler.h index e84a03ce..8f4dadfb 100644 --- a/examples/pikapython/pikapython/pikascript-core/PikaCompiler.h +++ b/examples/pikapython/pikapython/pikascript-core/PikaCompiler.h @@ -29,6 +29,9 @@ char* pikaMaker_getFirstNocompiled(PikaMaker* self); PIKA_RES pikaMaker_compileModuleWithDepends(PikaMaker* self, char* module_name); PIKA_RES pikaMaker_linkCompiledModulesFullPath(PikaMaker* self, char* lib_path); PIKA_RES pikaMaker_linkCompiledModules(PikaMaker* self, char* lib_name); +PIKA_RES _do_pikaMaker_linkCompiledModules(PikaMaker* self, + char* lib_name, + PIKA_BOOL gen_c_array); int LibObj_loadLibrary(LibObj* self, uint8_t* library_bytes); void LibObj_printModules(LibObj* self); void pikaMaker_deinit(PikaMaker* self); @@ -38,7 +41,22 @@ PIKA_RES _loadModuleDataWithName(uint8_t* library_bytes, uint8_t** addr_p, size_t* size_p); -#define LIB_VERSION_NUMBER 2 +#define LIB_VERSION_NUMBER 3 #define LIB_INFO_BLOCK_SIZE 32 +#define PIKA_APP_MAGIC_CODE_OFFSET 0 +#define PIKA_APP_MODULE_SIZE_OFFSET 1 +#define PIKA_APP_VERSION_OFFSET 2 +#define PIKA_APP_MODULE_NUM_OFFSET 3 + +typedef struct { + uint8_t* addr; + size_t size; + size_t pos; +} pikafs_FILE; + +pikafs_FILE* pikafs_fopen(char* file_name, char* mode); +int pikafs_fread(void* buf, size_t size, size_t count, pikafs_FILE* file); +int pikafs_fwrite(void* buf, size_t size, size_t count, pikafs_FILE* file); +int pikafs_fclose(pikafs_FILE* file); #endif diff --git a/examples/pikapython/pikapython/pikascript-core/PikaObj.c b/examples/pikapython/pikapython/pikascript-core/PikaObj.c index fe307806..d1b4d1cf 100644 --- a/examples/pikapython/pikapython/pikascript-core/PikaObj.c +++ b/examples/pikapython/pikapython/pikascript-core/PikaObj.c @@ -5,6 +5,7 @@ * MIT License * * Copyright (c) 2021 lyon 李昂 liang6516@outlook.com + * Copyright (c) 2023 Gorgon Meducer embedded_zhuroan@hotmail.com * * 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,6 +33,7 @@ #include "PikaPlatform.h" #include "dataArgs.h" #include "dataMemory.h" +#include "dataQueue.h" #include "dataString.h" #include "dataStrs.h" @@ -113,6 +115,15 @@ static int32_t obj_deinit_no_del(PikaObj* self) { return 0; } +int obj_GC(PikaObj* self) { + obj_refcntDec(self); + int ref_cnt = obj_refcntNow(self); + if (ref_cnt <= 0) { + obj_deinit(self); + } + return 0; +} + int32_t obj_deinit(PikaObj* self) { Arg* del = obj_getMethodArg(self, "__del__"); if (NULL != del) { @@ -219,13 +230,23 @@ PIKA_RES obj_setBytes(PikaObj* self, char* argPath, uint8_t* src, size_t size) { int64_t obj_getInt(PikaObj* self, char* argPath) { PikaObj* obj = obj_getHostObj(self, argPath); if (NULL == obj) { - return -999999999; + return _PIKA_INT_ERR; } char* argName = strPointToLastToken(argPath, '.'); int64_t res = args_getInt(obj->list, argName); return res; } +PIKA_BOOL obj_getBool(PikaObj* self, char* argPath) { + PikaObj* obj = obj_getHostObj(self, argPath); + if (NULL == obj) { + return PIKA_FALSE; + } + char* argName = strPointToLastToken(argPath, '.'); + PIKA_BOOL res = args_getBool(obj->list, argName); + return res; +} + Arg* obj_getArg(PikaObj* self, char* argPath) { PIKA_BOOL is_temp = PIKA_FALSE; PikaObj* obj = obj_getHostObjWithIsTemp(self, argPath, &is_temp); @@ -675,9 +696,9 @@ Method methodArg_getPtr(Arg* method_arg) { } char* methodArg_getTypeList(Arg* method_arg, char* buffs, size_t size) { - MethodProp* method_store = (MethodProp*)arg_getContent(method_arg); - if (NULL != method_store->type_list) { - return strcpy(buffs, method_store->type_list); + MethodProp* prop = (MethodProp*)arg_getContent(method_arg); + if (NULL != prop->type_list) { + return strcpy(buffs, prop->type_list); } char* method_dec = methodArg_getDec(method_arg); pika_assert(strGetSize(method_dec) <= size); @@ -692,6 +713,21 @@ char* methodArg_getTypeList(Arg* method_arg, char* buffs, size_t size) { return res; } +PikaObj* methodArg_getHostObj(Arg* method_arg) { + MethodProp* prop = (MethodProp*)arg_getContent(method_arg); + return prop->host_obj; +} + +int methodArg_setHostObj(Arg* method_arg, PikaObj* host_obj) { + MethodProp* prop = (MethodProp*)arg_getContent(method_arg); + if (prop->host_obj == NULL) { + prop->host_obj = host_obj; + // obj_refcntInc(host_obj); + return 0; + } + return 0; +} + char* methodArg_getName(Arg* method_arg, char* buffs, size_t size) { MethodProp* method_store = (MethodProp*)arg_getContent(method_arg); if (NULL != method_store->name) { @@ -764,6 +800,7 @@ static void obj_saveMethodInfo(PikaObj* self, MethodInfo* method_info) { .bytecode_frame = method_info->bytecode_frame, .def_context = method_info->def_context, .declareation = method_info->dec, // const + .host_obj = NULL, }; char* name = method_info->name; if (NULL == method_info->name) { @@ -951,9 +988,174 @@ static void _putc_cmd(char KEY_POS, int pos) { } } -enum shellCTRL _do_obj_runChar(PikaObj* self, - char inputChar, - ShellConfig* shell) { +#if PIKA_SHELL_FILTER_ENABLE +typedef enum { + __FILTER_NO_RESULT, + __FILTER_FAIL_DROP_ONE, + __FILTER_SUCCESS_GET_ALL_PEEKED, + __FILTER_SUCCESS_DROP_ALL_PEEKED +} FilterReturn; + +PIKA_BOOL _filter_msg_hi_pika_handler(FilterItem* msg, + PikaObj* self, + ShellConfig* shell) { + pika_platform_printf("Yes, I am here\r\n"); + return PIKA_TRUE; +} + +PIKA_BOOL _filter_msg_bye_pika_handler(FilterItem* msg, + PikaObj* self, + ShellConfig* shell) { + pika_platform_printf("OK, see you\r\n"); + return PIKA_TRUE; +} + +#define __MSG_DECLARE +#include "__default_filter_msg_table.h" + +static const FilterItem g_default_filter_messages[] = { +#define __MSG_TABLE +#include "__default_filter_msg_table.h" +}; + +static FilterReturn _do_message_filter(PikaObj* self, + ShellConfig* shell, + FilterItem* msg, + uint_fast16_t count) { + pika_assert(NULL != msg); + pika_assert(count > 0); + ByteQueue* queue = &shell->filter_fifo.queue; + FilterReturn result = __FILTER_FAIL_DROP_ONE; + + do { + do { + if (msg->ignore_mask & shell->filter_fifo.ignore_mask) { + /* this message should be ignored */ + break; + } + + if (NULL == msg->message) { + break; + } + + uint_fast16_t message_size = msg->size; + if (!message_size) { + break; + } + + byteQueue_resetPeek(queue); + + /* do message comparison */ + uint8_t* src = (uint8_t*)msg->message; + + if (msg->is_case_insensitive) { + do { + uint8_t byte; + if (!byteQueue_peekOne(queue, &byte)) { + result = __FILTER_NO_RESULT; + break; + } + char letter = *src++; + + if (letter >= 'A' && letter <= 'Z') { + letter += 'a' - 'A'; + } + + if (byte >= 'A' && byte <= 'Z') { + byte += 'a' - 'A'; + } + + if (letter != byte) { + break; + } + } while (--message_size); + } else { + do { + uint8_t byte; + if (!byteQueue_peekOne(queue, &byte)) { + result = __FILTER_NO_RESULT; + break; + } + if (*src++ != byte) { + break; + } + } while (--message_size); + } + + if (0 == message_size) { + /* message match */ + if (NULL != msg->handler) { + if (!msg->handler(msg, self, shell)) { + break; + } + } + /* message is handled */ + if (msg->is_visible) { + return __FILTER_SUCCESS_GET_ALL_PEEKED; + } + return __FILTER_SUCCESS_DROP_ALL_PEEKED; + } + } while (0); + + msg++; + } while (--count); + + return result; +} + +#ifndef dimof +#define dimof(__array) (sizeof(__array) / sizeof(__array[0])) +#endif + +int16_t _do_stream_filter(PikaObj* self, ShellConfig* shell) { + ByteQueue* queue = &shell->filter_fifo.queue; + + FilterReturn result = + _do_message_filter(self, shell, (FilterItem*)g_default_filter_messages, + dimof(g_default_filter_messages)); + int16_t drop_count = 0; + + switch (result) { + case __FILTER_NO_RESULT: + break; + case __FILTER_FAIL_DROP_ONE: + drop_count = 1; + break; + case __FILTER_SUCCESS_DROP_ALL_PEEKED: + byteQueue_dropAllPeeked(queue); + return 0; + case __FILTER_SUCCESS_GET_ALL_PEEKED: + drop_count = byteQueue_getPeekedNumber(queue); + return drop_count; + } + + /* user registered message filter */ + if (NULL != shell->messages && shell->message_count) { + result = _do_message_filter(self, shell, shell->messages, + shell->message_count); + switch (result) { + case __FILTER_NO_RESULT: + break; + case __FILTER_FAIL_DROP_ONE: + drop_count = 1; + break; + case __FILTER_SUCCESS_DROP_ALL_PEEKED: + byteQueue_dropAllPeeked(&shell->filter_fifo.queue); + return 0; + case __FILTER_SUCCESS_GET_ALL_PEEKED: + drop_count = + byteQueue_getPeekedNumber(&shell->filter_fifo.queue); + return drop_count; + } + } + + return drop_count; +} +#endif + +enum shellCTRL _inner_do_obj_runChar(PikaObj* self, + char inputChar, + ShellConfig* shell) { char* input_line = NULL; enum shellCTRL ctrl = SHELL_CTRL_CONTINUE; #if !(defined(__linux) || defined(_WIN32)) @@ -1055,7 +1257,7 @@ enum shellCTRL _do_obj_runChar(PikaObj* self, goto exit; } if ((inputChar == '\r') || (inputChar == '\n')) { -#if !(defined(__linux) || defined(_WIN32)) +#if !(defined(__linux) || defined(_WIN32) || PIKA_SHELL_NO_NEWLINE) pika_platform_printf("\r\n"); #endif /* still in block */ @@ -1108,6 +1310,48 @@ exit: return ctrl; } +PIKA_WEAK +enum shellCTRL _do_obj_runChar(PikaObj* self, + char inputChar, + ShellConfig* shell) { +#if PIKA_SHELL_FILTER_ENABLE + ByteQueue* queue = &(shell->filter_fifo.queue); + + /* validation */ + if (NULL == queue->buffer) { + /* need initialize first */ + byteQueue_init(queue, &shell->filter_fifo.buffer, + sizeof(shell->filter_fifo.buffer), PIKA_FALSE); + } + + PIKA_BOOL result = byteQueue_writeOne(queue, inputChar); + pika_assert(result != PIKA_FALSE); + + int16_t byte_count; + do { + if (0 == byteQueue_peekAvailableCount(queue)) { + break; + } + byte_count = _do_stream_filter(self, shell); + int16_t n = byte_count; + + while (n--) { + PIKA_BOOL result = byteQueue_readOne(queue, (uint8_t*)&inputChar); + pika_assert(result != PIKA_FALSE); + + if (SHELL_CTRL_EXIT == + _inner_do_obj_runChar(self, inputChar, shell)) { + return SHELL_CTRL_EXIT; + } + } + } while (byte_count); + + return SHELL_CTRL_CONTINUE; +#else + return _inner_do_obj_runChar(self, inputChar, shell); +#endif +} + enum shellCTRL obj_runChar(PikaObj* self, char inputChar) { ShellConfig* shell = args_getStruct(self->list, "@shcfg"); if (NULL == shell) { @@ -1124,6 +1368,22 @@ enum shellCTRL obj_runChar(PikaObj* self, char inputChar) { return _do_obj_runChar(self, inputChar, shell); } +static void _save_file(char* file_name, uint8_t* buff, size_t size) { + pika_platform_printf("[ Info] Saving file to '%s'...\r\n", file_name); + FILE* fp = pika_platform_fopen(file_name, "wb+"); + if (NULL == fp) { + pika_platform_printf("[ Error] Open file '%s' error!\r\n", file_name); + pika_platform_fclose(fp); + } else { + pika_platform_fwrite(buff, 1, size, fp); + pika_platform_printf("[ Info] Writing %d bytes to '%s'...\r\n", + (int)(size), file_name); + pika_platform_fclose(fp); + pika_platform_printf("[ OK ] Writing to '%s' succeed!\r\n", + file_name); + } +} + void _do_pikaScriptShell(PikaObj* self, ShellConfig* cfg) { /* init the shell */ _obj_runChar_beforeRun(self, cfg); @@ -1186,23 +1446,7 @@ void _do_pikaScriptShell(PikaObj* self, ShellConfig* cfg) { (int)PIKA_READ_FILE_BUFF_SIZE, ((float)len / (float)PIKA_READ_FILE_BUFF_SIZE)); #if PIKA_SHELL_SAVE_FILE_ENABLE - char* file_name = PIKA_SHELL_SAVE_FILE_NAME; - pika_platform_printf("[ Info] Saving file to '%s'...\r\n", - file_name); - FILE* fp = pika_platform_fopen(file_name, "w+"); - if (NULL == fp) { - pika_platform_printf("[ Error] Open file '%s' error!\r\n", - file_name); - pika_platform_fclose(fp); - } else { - pika_platform_fwrite(buff, 1, len, fp); - pika_platform_printf( - "[ Info] Writing %d bytes to '%s'...\r\n", (int)(len), - file_name); - pika_platform_fclose(fp); - pika_platform_printf("[ OK ] Writing to '%s' succeed!\r\n", - file_name); - } + _save_file(PIKA_SHELL_SAVE_FILE_PATH, (uint8_t*)buff, len); #endif pika_platform_printf("=============== [ Run] ===============\r\n"); obj_run(self, (char*)buff); @@ -1219,26 +1463,45 @@ void _do_pikaScriptShell(PikaObj* self, ShellConfig* cfg) { /* run xx.py.o */ if (inputChar[0] == 'p' && inputChar[1] == 0x0f) { + uint8_t magic_code[4] = {0x0f, 'p', 0x00, 0x00}; for (int i = 0; i < 2; i++) { /* eat 'yo' */ - cfg->fn_getchar(); + magic_code[2 + i] = cfg->fn_getchar(); } uint32_t size = 0; for (int i = 0; i < 4; i++) { uint8_t* size_byte = (uint8_t*)&size; size_byte[i] = cfg->fn_getchar(); } + size += sizeof(uint32_t) * 2; uint8_t* buff = pikaMalloc(size); - for (uint32_t i = 0; i < size; i++) { + /* save magic code and size */ + memcpy(buff, magic_code, sizeof(magic_code)); + memcpy(buff + sizeof(magic_code), &size, sizeof(size)); + + for (uint32_t i = sizeof(uint32_t) * 2; i < size; i++) { buff[i] = cfg->fn_getchar(); } + pika_platform_printf( - "\r\n=============== [Code] ===============\r\n"); - pika_platform_printf("[ Info] Bytecode size: %d\r\n", size); - pika_platform_printf("=============== [ RUN] ===============\r\n"); - pikaVM_runByteCodeInconstant(self, buff); - pikaFree(buff, size); - return; + "\r\n=============== [File] ===============\r\n"); + pika_platform_printf("[ Info] Recived size: %d\r\n", size); + if (magic_code[3] == 'o') { +#if PIKA_SHELL_SAVE_BYTECODE_ENABLE + _save_file(PIKA_SHELL_SAVE_BYTECODE_PATH, (uint8_t*)buff, size); +#endif + pika_platform_printf( + "=============== [ RUN] ===============\r\n"); + pikaVM_runByteCodeInconstant(self, buff); + pikaFree(buff, size); + return; + } + if (magic_code[3] == 'a') { + _save_file(PIKA_SHELL_SAVE_APP_PATH, (uint8_t*)buff, size); + pika_platform_printf( + "=============== [REBOOT] ===============\r\n"); + pika_platform_reboot(); + } } #endif if (SHELL_CTRL_EXIT == _do_obj_runChar(self, inputChar[0], cfg)) { @@ -1337,6 +1600,13 @@ void method_returnInt(Args* args, int64_t val) { args_pushArg_name(args, "@rt", arg_newInt(val)); } +void method_returnBool(Args* args, PIKA_BOOL val) { + if (val == _PIKA_BOOL_ERR) { + return; + } + args_pushArg_name(args, "@rt", arg_newBool(val)); +} + void method_returnFloat(Args* args, pika_float val) { args_pushArg_name(args, "@rt", arg_newFloat(val)); } diff --git a/examples/pikapython/pikapython/pikascript-core/PikaObj.h b/examples/pikapython/pikapython/pikascript-core/PikaObj.h index fe4ecf2f..1e4637ce 100644 --- a/examples/pikapython/pikapython/pikascript-core/PikaObj.h +++ b/examples/pikapython/pikapython/pikascript-core/PikaObj.h @@ -5,6 +5,7 @@ * MIT License * * Copyright (c) 2021 lyon 李昂 liang6516@outlook.com + * Copyright (c) 2023 Gorgon Meducer embedded_zhuroan@hotmail.com * * 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,6 +33,7 @@ #include "dataLink.h" #include "dataMemory.h" #include "dataStrs.h" +#include "dataQueue.h" typedef struct InstructUnit InstructUnit; struct InstructUnit { @@ -135,6 +137,7 @@ typedef struct MethodProp { char* name; ByteCodeFrame* bytecode_frame; PikaObj* def_context; + PikaObj* host_obj; char* declareation; } MethodProp; @@ -151,6 +154,7 @@ typedef PikaObj PikaMaker; /* operation */ int32_t obj_deinit(PikaObj* self); +int obj_GC(PikaObj* self); int32_t obj_init(PikaObj* self, Args* args); int32_t obj_update(PikaObj* self); int32_t obj_enable(PikaObj* self); @@ -171,6 +175,7 @@ void* obj_getPtr(PikaObj* self, char* argPath); pika_float obj_getFloat(PikaObj* self, char* argPath); char* obj_getStr(PikaObj* self, char* argPath); int64_t obj_getInt(PikaObj* self, char* argPath); +PIKA_BOOL obj_getBool(PikaObj* self, char* argPath); Arg* obj_getArg(PikaObj* self, char* argPath); uint8_t* obj_getBytes(PikaObj* self, char* argPath); size_t obj_getBytesSize(PikaObj* self, char* argPath); @@ -245,6 +250,7 @@ uint8_t obj_getAnyArg(PikaObj* self, void method_returnStr(Args* args, char* val); void method_returnInt(Args* args, int64_t val); +void method_returnBool(Args* args, PIKA_BOOL val); void method_returnFloat(Args* args, pika_float val); void method_returnPtr(Args* args, void* val); void method_returnObj(Args* args, void* val); @@ -255,6 +261,8 @@ void method_returnArg(Args* args, Arg* arg); char* methodArg_getDec(Arg* method_arg); char* methodArg_getTypeList(Arg* method_arg, char* buffs, size_t size); char* methodArg_getName(Arg* method_arg, char* buffs, size_t size); +int methodArg_setHostObj(Arg* method_arg, PikaObj* host_obj); +PikaObj* methodArg_getHostObj(Arg* method_arg); ByteCodeFrame* methodArg_getBytecodeFrame(Arg* method_arg); Method methodArg_getPtr(Arg* method_arg); @@ -273,7 +281,40 @@ typedef struct ShellConfig ShellConfig; typedef enum shellCTRL (*sh_handler)(PikaObj*, char*, ShellConfig*); typedef char (*sh_getchar)(void); + +#if PIKA_SHELL_FILTER_ENABLE +typedef struct FilterFIFO { + ByteQueue queue; + uint8_t ignore_mask; + uint8_t buffer[PIKA_SHELL_FILTER_FIFO_SIZE]; +} FilterFIFO; + +typedef struct FilterItem FilterItem; + +typedef PIKA_BOOL FilterMessageHandler( FilterItem *msg, + PikaObj* self, + ShellConfig* shell); + +struct FilterItem { + FilterMessageHandler *handler; + const uint8_t *message; + uint16_t size; + uint8_t is_visible : 1; + uint8_t is_case_insensitive : 1; + uint8_t : 6; + uint8_t ignore_mask; + uintptr_t target; +}; + +#endif + struct ShellConfig { +#if PIKA_SHELL_FILTER_ENABLE + FilterFIFO filter_fifo; + FilterItem *messages; + uint16_t message_count; + uint16_t : 16; /* padding to suppress warning*/ +#endif char* prefix; sh_handler handler; void* context; @@ -306,11 +347,11 @@ Arg* arg_setRef(Arg* self, char* name, PikaObj* obj); Arg* arg_setObj(Arg* self, char* name, PikaObj* obj); static inline Arg* arg_newObj(PikaObj* obj) { - return arg_setObj(NULL, "", (obj)); + return arg_setObj(NULL, (char*)"", (obj)); } static inline Arg* arg_newRef(PikaObj* obj) { - return arg_setRef(NULL, "", (obj)); + return arg_setRef(NULL, (char*)"", (obj)); } PikaObj* obj_importModuleWithByteCodeFrame(PikaObj* self, @@ -389,14 +430,14 @@ static inline uint8_t obj_refcntNow(PikaObj* self) { #define obj_setStruct(PikaObj_p_self, char_p_name, struct_) \ args_setStruct(((PikaObj_p_self)->list), char_p_name, struct_) -#define ABSTRACT_METHOD_NEED_OVERRIDE_ERROR(_) \ - obj_setErrorCode(self, 1); \ +#define ABSTRACT_METHOD_NEED_OVERRIDE_ERROR(_) \ + obj_setErrorCode(self, 1); \ pika_platform_printf("Error: abstract method `%s()` need override.\r\n", \ - __FUNCTION__) + __FUNCTION__) char* obj_cacheStr(PikaObj* self, char* str); PikaObj* _arg_to_obj(Arg* self, PIKA_BOOL* pIsTemp); -char* __printBytes(PikaObj* self, Arg* arg); +Arg* arg_toStrArg(Arg* arg); #define PIKASCRIPT_VERSION_TO_NUM(majer, minor, micro) \ majer * 100 * 100 + minor * 100 + micro @@ -516,5 +557,16 @@ Arg* pks_eventListener_sendSignalAwaitResult(PikaEventListener* self, int eventSignal); void obj_printModules(PikaObj* self); +#if PIKA_DEBUG_ENABLE +#define pika_debug(fmt, ...) \ + pika_platform_printf("PikaDBG: " fmt "\r\n", ##__VA_ARGS__) +#else +#define pika_debug(...) \ + do { \ + } while (0) +#endif + +int pika_GIL_EXIT(void); +int pika_GIL_ENTER(void); #endif diff --git a/examples/pikapython/pikapython/pikascript-core/PikaParser.c b/examples/pikapython/pikapython/pikascript-core/PikaParser.c index 5e3ce0ab..69c0fac1 100644 --- a/examples/pikapython/pikapython/pikascript-core/PikaParser.c +++ b/examples/pikapython/pikapython/pikascript-core/PikaParser.c @@ -55,8 +55,9 @@ void Cursor_iterEnd(struct Cursor* cs); void Cursor_deinit(struct Cursor* cs); /* Cursor high level api */ -char* Cursor_popToken(Args* buffs, char** stmt, char* devide); +char* Cursor_popToken(Args* buffs, char** pStmt, char* devide); PIKA_BOOL Cursor_isContain(char* stmt, TokenType type, char* pyload); +char* Cursor_splitCollect(Args* buffs, char* stmt, char* devide, int index); char* Parser_linesToAsm(Args* outBuffs, char* multiLine); uint16_t TokenStream_getSize(char* tokenStream) { @@ -66,15 +67,12 @@ uint16_t TokenStream_getSize(char* tokenStream) { return strCountSign(tokenStream, 0x1F) + 1; } -char* strsPopTokenWithSkip_byStr(Args* outBuffs, - char* stmts, - char* str, - char skipStart, - char skipEnd) { +char* Cursor_popLastToken(Args* outBuffs, char** pStmt, char* str) { + char* stmts = *pStmt; uint8_t divider_index = 0; Arg* keeped_arg = arg_newStr(""); Arg* poped_arg = arg_newStr(""); - Cursor_forEachToken(cs, stmts) { + Cursor_forEach(cs, stmts) { Cursor_iterStart(&cs); if (cs.branket_deepth == 0) { if (strEqu(str, cs.token1.pyload)) { @@ -84,7 +82,7 @@ char* strsPopTokenWithSkip_byStr(Args* outBuffs, Cursor_iterEnd(&cs); } Cursor_deinit(&cs); - Cursor_forEachTokenExistPs(cs, stmts) { + Cursor_forEachExistPs(cs, stmts) { Cursor_iterStart(&cs); if (cs.iter_index < divider_index) { poped_arg = arg_strAppend(poped_arg, cs.token1.pyload); @@ -95,21 +93,21 @@ char* strsPopTokenWithSkip_byStr(Args* outBuffs, Cursor_iterEnd(&cs); } Cursor_deinit(&cs); - char* keeped = arg_getStr(keeped_arg); - char* poped = strsCopy(outBuffs, arg_getStr(poped_arg)); - pika_platform_memcpy(stmts, keeped, strGetSize(keeped) + 1); + char* keeped = strsCopy(outBuffs, arg_getStr(keeped_arg)); + char* poped = arg_getStr(poped_arg); + pika_platform_memcpy(stmts, poped, strGetSize(poped) + 1); arg_deinit(poped_arg); arg_deinit(keeped_arg); - return poped; + return keeped; } -char* strsGetCleanCmd(Args* outBuffs, char* cmd) { +char* Cursor_getCleanStmt(Args* outBuffs, char* cmd) { pika_assert(cmd != NULL); int32_t size = strGetSize(cmd); /* lexer may generate more chars than input */ char* strOut = args_getBuff(outBuffs, size * 2); int32_t iOut = 0; - Cursor_forEachToken(cs, cmd) { + Cursor_forEach(cs, cmd) { Cursor_iterStart(&cs); for (uint16_t k = 0; k < strGetSize(cs.token1.pyload); k++) { strOut[iOut] = cs.token1.pyload[k]; @@ -144,7 +142,7 @@ static char* Cursor_removeTokensBetween(Args* outBuffs, Args buffs = {0}; uint8_t block_deepth = 0; char* output = ""; - Cursor_forEachToken(cs, input) { + Cursor_forEach(cs, input) { Cursor_iterStart(&cs); if (strEqu(token_pyload1, cs.token1.pyload)) { if (block_deepth == 0) { @@ -193,7 +191,7 @@ static enum StmtType Lexer_matchStmtType(char* right) { PIKA_BOOL is_get_dict = PIKA_FALSE; PIKA_BOOL is_get_import = PIKA_FALSE; PIKA_BOOL is_get_chain = PIKA_FALSE; - Cursor_forEachToken(cs, rightWithoutSubStmt) { + Cursor_forEach(cs, rightWithoutSubStmt) { Cursor_iterStart(&cs); /* collect type */ if (strEqu(cs.token1.pyload, " import ")) { @@ -798,7 +796,7 @@ static char* _solveEqualLevelOperator(Args* buffs, char* op2, char* stmt) { if ((strEqu(operator, op1)) || (strEqu(operator, op2))) { - Cursor_forEachToken(cs, stmt) { + Cursor_forEach(cs, stmt) { Cursor_iterStart(&cs); if (strEqu(cs.token1.pyload, op1)) { operator= strsCopy(buffs, op1); @@ -826,7 +824,7 @@ char* Lexer_getOperator(Args* outBuffs, char* stmt) { // use parse state foreach to get operator for (uint32_t i = 0; i < sizeof(operators) / 9; i++) { - Cursor_forEachToken(cs, tokenStream) { + Cursor_forEach(cs, tokenStream) { Cursor_iterStart(&cs); // get operator if (strEqu(cs.token2.pyload, (char*)operators[i])) { @@ -842,7 +840,7 @@ char* Lexer_getOperator(Args* outBuffs, char* stmt) { /* solve the iuuse of "~-1" */ if (strEqu(operator, "-")) { - Cursor_forEachToken(cs, stmt) { + Cursor_forEach(cs, stmt) { Cursor_iterStart(&cs); if (strEqu(cs.token2.pyload, "-")) { if (cs.token1.type == TOKEN_operator) { @@ -980,11 +978,11 @@ PIKA_BOOL Cursor_isContain(char* stmt, TokenType type, char* pyload) { return res; } -char* Cursor_popToken(Args* buffs, char** tokenStream, char* devide) { +char* Cursor_popToken(Args* buffs, char** pStmt, char* devide) { Arg* out_item = arg_newStr(""); Arg* tokenStream_after = arg_newStr(""); PIKA_BOOL is_find_devide = PIKA_FALSE; - Cursor_forEachToken(cs, *tokenStream) { + Cursor_forEach(cs, *pStmt) { Cursor_iterStart(&cs); if (!is_find_devide) { if ((cs.branket_deepth == 0 && strEqu(cs.token1.pyload, devide)) || @@ -1010,10 +1008,39 @@ char* Cursor_popToken(Args* buffs, char** tokenStream, char* devide) { char* token_after_str = strsCopy(buffs, arg_getStr(tokenStream_after)); arg_deinit(tokenStream_after); /* update tokenStream */ - *tokenStream = token_after_str; + *pStmt = token_after_str; return out_item_str; } +char* Cursor_splitCollect(Args* buffs, char* stmt, char* devide, int index) { + Arg* aOut = arg_newStr(""); + int expect_branket = 0; + if (devide[0] == '(' || devide[0] == '[' || devide[0] == '{') { + expect_branket = 1; + } + int i = 0; + Cursor_forEach(cs, stmt) { + Cursor_iterStart(&cs); + if (cs.branket_deepth == expect_branket && + strEqu(cs.token1.pyload, devide)) { + i++; + Cursor_iterEnd(&cs); + continue; + } + if (i == index) { + aOut = arg_strAppend(aOut, cs.token1.pyload); + } + Cursor_iterEnd(&cs); + } + Cursor_deinit(&cs); + /* if not found, return origin string */ + if (i == 0) { + arg_deinit(aOut); + aOut = arg_newStr(stmt); + } + return strsCacheArg(buffs, aOut); +} + static void Slice_getPars(Args* outBuffs, char* inner, char** pStart, @@ -1029,7 +1056,7 @@ static void Slice_getPars(Args* outBuffs, /* slice */ uint8_t colon_i = 0; - Cursor_forEachToken(cs, inner) { + Cursor_forEach(cs, inner) { Cursor_iterStart(&cs); if (strEqu(cs.token1.pyload, ":") && cs.branket_deepth == 0) { colon_i++; @@ -1093,7 +1120,7 @@ char* Suger_leftSlice(Args* outBuffs, char* right, char** left_p) { /* exit when not match (symble|iteral)'[' */ - Cursor_forEachToken(cs, left) { + Cursor_forEach(cs, left) { Cursor_iterStart(&cs); if (strEqu(cs.token2.pyload, "[")) { if (TOKEN_symbol == cs.token1.type || @@ -1114,7 +1141,7 @@ char* Suger_leftSlice(Args* outBuffs, char* right, char** left_p) { } /* matched [] */ - Cursor_forEachTokenExistPs(cs, left) { + Cursor_forEachExistPs(cs, left) { Cursor_iterStart(&cs); /* found '[' */ if ((TOKEN_devider == cs.token2.type) && @@ -1188,7 +1215,7 @@ char* Suger_format(Args* outBuffs, char* right) { } PIKA_BOOL is_format = PIKA_FALSE; - Cursor_forEachToken(ps1, right) { + Cursor_forEach(ps1, right) { Cursor_iterStart(&ps1); if (ps1.branket_deepth == 0 && strEqu(ps1.token1.pyload, "%")) { is_format = PIKA_TRUE; @@ -1208,7 +1235,7 @@ char* Suger_format(Args* outBuffs, char* right) { PIKA_BOOL is_out_vars = PIKA_FALSE; Args buffs = {0}; char* fmt = NULL; - Cursor_forEachToken(cs, right) { + Cursor_forEach(cs, right) { char* item = ""; Cursor_iterStart(&cs); if (PIKA_FALSE == is_in_format) { @@ -1311,7 +1338,7 @@ uint8_t Suger_selfOperator(Args* outbuffs, } /* found self operator */ is_left_exist = 1; - Cursor_forEachToken(cs, stmt) { + Cursor_forEach(cs, stmt) { Cursor_iterStart(&cs); if ((strEqu(cs.token1.pyload, "*=")) || (strEqu(cs.token1.pyload, "/=")) || @@ -1384,7 +1411,7 @@ char* Parser_popSubStmt(Args* outbuffs, char** stmt_p, char* delimiter) { char* stmt = *stmt_p; PIKA_BOOL is_get_substmt = PIKA_FALSE; Args buffs = {0}; - Cursor_forEachToken(cs, stmt) { + Cursor_forEach(cs, stmt) { Cursor_iterStart(&cs); if (is_get_substmt) { /* get new stmt */ @@ -1421,7 +1448,7 @@ char* Parser_popSubStmt(Args* outbuffs, char** stmt_p, char* delimiter) { char* Parser_popLastSubStmt(Args* outbuffs, char** stmt_p, char* delimiter) { uint8_t last_stmt_i = 0; char* stmt = *stmt_p; - Cursor_forEachToken(cs, stmt) { + Cursor_forEach(cs, stmt) { Cursor_iterStart(&cs); if (strIsStartWith(cs.token1.pyload, delimiter)) { /* found delimiter */ @@ -1447,7 +1474,7 @@ char* Parser_popLastSubStmt(Args* outbuffs, char** stmt_p, char* delimiter) { Arg* mainStmt = arg_newStr(""); Arg* lastStmt = arg_newStr(""); { - Cursor_forEachToken(cs, stmt) { + Cursor_forEach(cs, stmt) { Cursor_iterStart(&cs); if (cs.iter_index < last_stmt_i) { mainStmt = arg_strAppend(mainStmt, cs.token1.pyload); @@ -1548,7 +1575,7 @@ char* Suger_not_in(Args* out_buffs, char* line) { } /* stmt1 not in stmt2 => not stmt1 in stmt2 */ - Cursor_forEachToken(cs, line) { + Cursor_forEach(cs, line) { Cursor_iterStart(&cs); if (!got_not_in) { if (strEqu(cs.token1.pyload, " not ") && @@ -1583,7 +1610,7 @@ __exit: AST* AST_parseStmt(AST* ast, char* stmt) { Args buffs = {0}; - char* assignment = strsGetFirstToken(&buffs, stmt, '('); + char* assignment = Cursor_splitCollect(&buffs, stmt, "(", 0); char* method = NULL; char* ref = NULL; char* str = NULL; @@ -1601,7 +1628,7 @@ AST* AST_parseStmt(AST* ast, char* stmt) { left = strsCopy(&buffs, ""); right = strsCopy(&buffs, ""); uint8_t is_meet_equ = 0; - Cursor_forEachToken(cs, stmt) { + Cursor_forEach(cs, stmt) { Cursor_iterStart(&cs); if (!is_meet_equ && strEqu(cs.token1.pyload, "=") && cs.token1.type == TOKEN_operator) { @@ -1630,7 +1657,8 @@ AST* AST_parseStmt(AST* ast, char* stmt) { /* set left */ if (isLeftExist) { - AST_setNodeAttr(ast, (char*)"left", left); + char* left_without_hint = Cursor_splitCollect(&buffs, left, ":", 0); + AST_setNodeAttr(ast, (char*)"left", left_without_hint); } /* match statment type */ enum StmtType stmtType = Lexer_matchStmtType(right); @@ -1649,9 +1677,8 @@ AST* AST_parseStmt(AST* ast, char* stmt) { } AST_setNodeAttr(ast, (char*)"operator", operator); char* rightBuff = strsCopy(&buffs, right); - char* subStmt1 = - strsPopTokenWithSkip_byStr(&buffs, rightBuff, operator, '(', ')'); - char* subStmt2 = rightBuff; + char* subStmt2 = Cursor_popLastToken(&buffs, &rightBuff, operator); + char* subStmt1 = rightBuff; AST_parseSubStmt(ast, subStmt1); AST_parseSubStmt(ast, subStmt2); goto exit; @@ -1689,7 +1716,10 @@ AST* AST_parseStmt(AST* ast, char* stmt) { method = strsGetFirstToken(&buffs, right, '('); AST_setNodeAttr(ast, (char*)"method", method); char* subStmts = strsCut(&buffs, right, '(', ')'); - pika_assert(NULL != subStmts); + if (NULL == subStmts) { + result = PIKA_RES_ERR_SYNTAX_ERROR; + goto exit; + } /* add ',' at the end */ subStmts = strsAppend(&buffs, subStmts, ","); while (1) { @@ -1751,21 +1781,25 @@ exit: return ast; } -static int32_t Parser_getPyLineBlockDeepth(char* line) { +static int32_t _getSpaceNum(char* line) { uint32_t size = strGetSize(line); for (uint32_t i = 0; i < size; i++) { if (line[i] != ' ') { - uint32_t spaceNum = i; - if (0 == spaceNum % 4) { - return spaceNum / 4; - } - /* space Num is not 4N, error*/ - return -1; + return i; } } return 0; } +static int32_t Parser_getPyLineBlockDeepth(char* line) { + int32_t spaceNum = _getSpaceNum(line); + if (0 == spaceNum % 4) { + return spaceNum / 4; + } + /* space Num is not 4N, error*/ + return -1; +} + char* Parser_removeAnnotation(char* line) { uint8_t is_annotation_exit = 0; uint8_t is_in_single_quotes = 0; @@ -1805,50 +1839,59 @@ char* Parser_removeAnnotation(char* line) { return line; } -char* _defGetDefault(Args* outBuffs, char** dec_out) { +char* _defGetDefault(Args* outBuffs, char** psDeclearOut) { #if PIKA_NANO_ENABLE return ""; #endif Args buffs = {0}; - char* dec_str = strsCopy(&buffs, *dec_out); - char* fn_name = strsGetFirstToken(&buffs, dec_str, '('); - Arg* dec_arg = arg_strAppend(arg_newStr(fn_name), "("); - Arg* default_arg = arg_newStr(""); - char* arg_list = strsCut(&buffs, dec_str, '(', ')'); - char* default_out = NULL; - pika_assert(NULL != arg_list); - int arg_num = strCountSign(arg_list, ',') + 1; - for (int i = 0; i < arg_num; i++) { - char* arg_str = strsPopToken(&buffs, &arg_list, ','); + char* sDeclear = strsCopy(&buffs, *psDeclearOut); + char* sFnName = strsGetFirstToken(&buffs, sDeclear, '('); + Arg* aDeclear = arg_strAppend(arg_newStr(sFnName), "("); + Arg* aDefault = arg_newStr(""); + char* sArgList = strsCut(&buffs, sDeclear, '(', ')'); + char* sDefaultOut = NULL; + pika_assert(NULL != sArgList); + int argNum = strCountSign(sArgList, ',') + 1; + for (int i = 0; i < argNum; i++) { + char* sItem = strsPopToken(&buffs, &sArgList, ','); + char* sDefaultVal = NULL; + char* sDefaultKey = NULL; int is_default = 0; - if (strIsContain(arg_str, '=')) { - default_arg = arg_strAppend(default_arg, arg_str); - default_arg = arg_strAppend(default_arg, ","); - arg_str = strsPopToken(&buffs, &arg_str, '='); + if (strIsContain(sItem, '=')) { + /* has default value */ + sDefaultVal = Cursor_splitCollect(&buffs, sItem, "=", 1); + sDefaultKey = Cursor_splitCollect(&buffs, sItem, "=", 0); + sDefaultKey = Cursor_splitCollect(&buffs, sDefaultKey, ":", 0); + aDefault = arg_strAppend(aDefault, sDefaultKey); + aDefault = arg_strAppend(aDefault, "="); + aDefault = arg_strAppend(aDefault, sDefaultVal); + aDefault = arg_strAppend(aDefault, ","); is_default = 1; + } else { + sDefaultKey = sItem; } - dec_arg = arg_strAppend(dec_arg, arg_str); + aDeclear = arg_strAppend(aDeclear, sDefaultKey); if (is_default) { - dec_arg = arg_strAppend(dec_arg, "="); + aDeclear = arg_strAppend(aDeclear, "="); } - dec_arg = arg_strAppend(dec_arg, ","); + aDeclear = arg_strAppend(aDeclear, ","); } - strPopLastToken(arg_getStr(dec_arg), ','); - dec_arg = arg_strAppend(dec_arg, ")"); - *dec_out = strsCopy(outBuffs, arg_getStr(dec_arg)); - default_out = strsCopy(outBuffs, arg_getStr(default_arg)); - strPopLastToken(default_out, ','); - arg_deinit(dec_arg); - arg_deinit(default_arg); + strPopLastToken(arg_getStr(aDeclear), ','); + aDeclear = arg_strAppend(aDeclear, ")"); + *psDeclearOut = strsCopy(outBuffs, arg_getStr(aDeclear)); + sDefaultOut = strsCopy(outBuffs, arg_getStr(aDefault)); + strPopLastToken(sDefaultOut, ','); + arg_deinit(aDeclear); + arg_deinit(aDefault); strsDeinit(&buffs); - return default_out; + return sDefaultOut; } static char* Suger_multiReturn(Args* out_buffs, char* line) { #if PIKA_NANO_ENABLE return line; #endif - Cursor_forEachToken(cs, line) { + Cursor_forEach(cs, line) { Cursor_iterStart(&cs); if (cs.branket_deepth == 0 && strEqu(cs.token1.pyload, ",")) { line = strsFormat(out_buffs, strGetSize(line) + 3, "(%s)", line); @@ -1950,7 +1993,7 @@ AST* AST_parseLine_withBlockStack_withBlockDeepth(char* line, if (strIsStartWith(line_start, "for ")) { Args* list_buffs = New_strBuff(); char* line_buff = strsCopy(list_buffs, line_start + 4); - line_buff = strsGetCleanCmd(list_buffs, line_buff); + line_buff = Cursor_getCleanStmt(list_buffs, line_buff); if (strCountSign(line_buff, ':') < 1) { args_deinit(list_buffs); obj_deinit(ast); @@ -2054,7 +2097,7 @@ AST* AST_parseLine_withBlockStack_withBlockDeepth(char* line, if (strIsStartWith(line_start, "global ")) { stmt = ""; char* global_list = line_start + 7; - global_list = strsGetCleanCmd(&buffs, global_list); + global_list = Cursor_getCleanStmt(&buffs, global_list); AST_setNodeAttr(ast, "global", global_list); goto block_matched; } @@ -2067,7 +2110,7 @@ AST* AST_parseLine_withBlockStack_withBlockDeepth(char* line, } else { del_dir = line_start + sizeof("del ") - 1; } - del_dir = strsGetCleanCmd(&buffs, del_dir); + del_dir = Cursor_getCleanStmt(&buffs, del_dir); AST_setNodeAttr(ast, "del", del_dir); goto block_matched; } @@ -2079,7 +2122,7 @@ AST* AST_parseLine_withBlockStack_withBlockDeepth(char* line, ast = NULL; goto exit; } - declare = strsGetCleanCmd(&buffs, declare); + declare = Cursor_getCleanStmt(&buffs, declare); if (!strIsContain(declare, '(') || !strIsContain(declare, ')')) { obj_deinit(ast); ast = NULL; @@ -2102,7 +2145,7 @@ AST* AST_parseLine_withBlockStack_withBlockDeepth(char* line, ast = NULL; goto exit; } - declare = strsGetCleanCmd(&buffs, declare); + declare = Cursor_getCleanStmt(&buffs, declare); AST_setNodeBlock(ast, "class"); AST_setNodeAttr(ast, "declare", declare); stack_pushStr(block_stack, "class"); @@ -2115,7 +2158,7 @@ block_matched: ast = NULL; goto exit; } - stmt = strsGetCleanCmd(&buffs, stmt); + stmt = Cursor_getCleanStmt(&buffs, stmt); ast = AST_parseStmt(ast, stmt); goto exit; exit: @@ -2178,7 +2221,7 @@ static PIKA_BOOL _check_is_multi_assign(char* arg_list) { return PIKA_FALSE; #endif PIKA_BOOL res = PIKA_FALSE; - Cursor_forEachToken(cs, arg_list) { + Cursor_forEach(cs, arg_list) { Cursor_iterStart(&cs); if ((cs.branket_deepth == 0 && strEqu(cs.token1.pyload, ","))) { res = PIKA_TRUE; @@ -2195,6 +2238,7 @@ static char* Suger_multiAssign(Args* out_buffs, char* line) { #endif Args buffs = {0}; char* line_out = line; + int space_num = _getSpaceNum(line); PIKA_BOOL is_assign = PIKA_FALSE; Arg* stmt = arg_newStr(""); Arg* out_list = arg_newStr(""); @@ -2203,7 +2247,7 @@ static char* Suger_multiAssign(Args* out_buffs, char* line) { char* line_item = NULL; char* out_list_str = NULL; int out_num = 0; - Cursor_forEachToken(cs, line) { + Cursor_forEach(cs, line) { Cursor_iterStart(&cs); if (cs.branket_deepth == 0 && strEqu(cs.token1.pyload, "=")) { is_assign = PIKA_TRUE; @@ -2231,6 +2275,11 @@ static char* Suger_multiAssign(Args* out_buffs, char* line) { line_item = strsFormat(&buffs, PIKA_LINE_BUFF_SIZE, "$tmp= %s\n", arg_getStr(stmt)); + + /* add space */ + for (int i = 0; i < space_num; i++) { + line_out_arg = arg_strAppend(line_out_arg, " "); + } line_out_arg = arg_strAppend(line_out_arg, line_item); out_list_str = arg_getStr(out_list); @@ -2241,9 +2290,17 @@ static char* Suger_multiAssign(Args* out_buffs, char* line) { } char* line_item = strsFormat(&buffs, PIKA_LINE_BUFF_SIZE, "%s = $tmp[%d]\n", item, out_num); + /* add space */ + for (int i = 0; i < space_num; i++) { + line_out_arg = arg_strAppend(line_out_arg, " "); + } line_out_arg = arg_strAppend(line_out_arg, line_item); out_num++; } + /* add space */ + for (int i = 0; i < space_num; i++) { + line_out_arg = arg_strAppend(line_out_arg, " "); + } line_out_arg = arg_strAppend(line_out_arg, "del $tmp"); line_out = strsCopy(out_buffs, arg_getStr(line_out_arg)); @@ -2503,7 +2560,7 @@ static char* _Parser_linesToBytesOrAsm(Args* outBuffs, line_connection_arg = arg_strAppend(line_connection_arg, line); goto next_line; } - Cursor_forEachToken(c, line) { + Cursor_forEach(c, line) { Cursor_iterStart(&c); Cursor_iterEnd(&c); } @@ -2774,10 +2831,6 @@ char* AST_genAsm(AST* ast, Args* outBuffs) { pikaAsm = strsAppend(outBuffs, pikaAsm, (char*)"0 GER \n"); pikaAsm = strsAppend(outBuffs, pikaAsm, (char*)"0 JEZ 2\n"); } - - if (strEqu(block_type, "except")) { - pikaAsm = strsAppend(outBuffs, pikaAsm, (char*)"0 SER 0\n"); - } #endif /* goto the while start when exit while block */ if (strEqu(block_type, "for")) { diff --git a/examples/pikapython/pikapython/pikascript-core/PikaParser.h b/examples/pikapython/pikapython/pikascript-core/PikaParser.h index 6f5b0881..aa227acc 100644 --- a/examples/pikapython/pikapython/pikascript-core/PikaParser.h +++ b/examples/pikapython/pikapython/pikascript-core/PikaParser.h @@ -106,19 +106,19 @@ char* Parser_linesToArray(char* lines); char* instructUnit_fromAsmLine(Args* outBuffs, char* pikaAsm); ByteCodeFrame* byteCodeFrame_appendFromAsm(ByteCodeFrame* bf, char* pikaAsm); -#define Cursor_forEach(cursor) \ +#define _Cursor_forEach(cursor) \ _Cursor_beforeIter(&cursor); \ for (int __i = 0; __i < cursor.length; __i++) -#define Cursor_forEachTokenExistPs(cursor, tokenStream) \ +#define Cursor_forEachExistPs(cursor, stmt) \ /* init parserStage */ \ _Cursor_init(&cursor); \ - _Cursor_parse(&cursor, tokenStream); \ - Cursor_forEach(cursor) + _Cursor_parse(&cursor, stmt); \ + _Cursor_forEach(cursor) -#define Cursor_forEachToken(cursor, tokenStream) \ +#define Cursor_forEach(cursor, stmt) \ struct Cursor cursor; \ - Cursor_forEachTokenExistPs(cursor, tokenStream) + Cursor_forEachExistPs(cursor, stmt) uint16_t TokenStream_getSize(char* tokenStream); diff --git a/examples/pikapython/pikapython/pikascript-core/PikaPlatform.c b/examples/pikapython/pikapython/pikascript-core/PikaPlatform.c index 9325f837..4f961ac1 100644 --- a/examples/pikapython/pikapython/pikascript-core/PikaPlatform.c +++ b/examples/pikapython/pikapython/pikascript-core/PikaPlatform.c @@ -1,4 +1,4 @@ -/* +/* * This file is part of the PikaScript project. * http://github.com/pikastech/pikascript * @@ -28,6 +28,12 @@ #include "PikaPlatform.h" #include #include +#if defined(_WIN32) && !defined(CROSS_BUILD) +#include +#endif + +void pikaFree(void* mem, uint32_t size); +void* pikaMalloc(uint32_t size); PIKA_WEAK void pika_platform_disable_irq_handle(void) { /* disable irq to support thread */ @@ -74,8 +80,29 @@ PIKA_WEAK uint8_t pika_is_locked_pikaMemory(void) { return 0; } -PIKA_WEAK int64_t pika_platform_getTick(void) { +#if PIKA_FREERTOS_ENABLE +static uint32_t platform_uptime_ms(void) { +#if (configTICK_RATE_HZ == 1000) + return (uint32_t)xTaskGetTickCount(); +#else + TickType_t tick = 0u; + + tick = xTaskGetTickCount() * 1000; + return (uint32_t)((tick + configTICK_RATE_HZ - 1) / configTICK_RATE_HZ); +#endif +} +#endif + +PIKA_WEAK int64_t pika_platform_get_tick(void) { +#if PIKA_FREERTOS_ENABLE + return platform_uptime_ms(); +#elif defined(__linux) + struct timespec ts; + clock_gettime(CLOCK_MONOTONIC, &ts); + return (ts.tv_sec * 1000 + ts.tv_nsec / 1000000); +#else return -1; +#endif } PIKA_WEAK int pika_platform_vsprintf(char* buff, char* fmt, va_list args) { @@ -215,6 +242,7 @@ PIKA_WEAK size_t pika_platform_fwrite(const void* ptr, size_t size, size_t n, FILE* stream) { + pika_assert(NULL != stream); #if defined(__linux) || defined(_WIN32) return fwrite(ptr, size, n, stream); #else @@ -270,21 +298,26 @@ PIKA_WEAK PIKA_BOOL pika_hook_arg_cache_filter(void* self) { } PIKA_WEAK void pika_platform_thread_delay(void) { +#if defined(__linux) || defined(_WIN32) return; +#elif PIKA_FREERTOS_ENABLE + vTaskDelay(1); +#else + return; +#endif } PIKA_WEAK void pika_platform_sleep_ms(uint32_t ms) { +#if defined(__linux) + usleep(ms * 1000); +#elif defined(_WIN32) && !defined(CROSS_BUILD) + Sleep(ms); +#else pika_platform_printf( "Error: pika_platform_sleep_ms need implementation!\r\n"); while (1) { } -} - -PIKA_WEAK void pika_platform_sleep_s(uint32_t s) { - pika_platform_printf( - "Error: pika_platform_sleep_s need implementation!\r\n"); - while (1) { - } +#endif } /* Thread Support */ @@ -301,11 +334,11 @@ PIKA_WEAK pika_platform_thread_t* pika_platform_thread_init( void* (*thread_entry)(void*); thread_entry = (void* (*)(void*))entry; - thread = pika_platform_malloc(sizeof(pika_platform_thread_t)); + thread = pikaMalloc(sizeof(pika_platform_thread_t)); res = pthread_create(&thread->thread, NULL, thread_entry, param); if (res != 0) { - pika_platform_free(thread); + pikaFree(thread, sizeof(pika_platform_thread_t)); } thread->mutex = (pthread_mutex_t)PTHREAD_MUTEX_INITIALIZER; @@ -316,14 +349,14 @@ PIKA_WEAK pika_platform_thread_t* pika_platform_thread_init( BaseType_t err; pika_platform_thread_t* thread; - thread = pika_platform_malloc(sizeof(pika_platform_thread_t)); + thread = pikaMalloc(sizeof(pika_platform_thread_t)); (void)tick; err = xTaskCreate(entry, name, stack_size, param, priority, thread->thread); if (pdPASS != err) { - pika_platform_free(thread); + pikaFree(thread, sizeof(pika_platform_thread_t)); return NULL; } @@ -334,6 +367,17 @@ PIKA_WEAK pika_platform_thread_t* pika_platform_thread_init( #endif } +uint64_t pika_platform_thread_self(void) { +#ifdef __linux + return (uint64_t)pthread_self(); +#elif PIKA_FREERTOS_ENABLE + return (uint64_t)xTaskGetCurrentTaskHandle(); +#else + WEAK_FUNCTION_NEED_OVERRIDE_ERROR(); + return 0; +#endif +} + PIKA_WEAK void pika_platform_thread_startup(pika_platform_thread_t* thread) { (void)thread; } @@ -366,13 +410,28 @@ PIKA_WEAK void pika_platform_thread_destroy(pika_platform_thread_t* thread) { #ifdef __linux if (NULL != thread) { pthread_detach(thread->thread); - pika_platform_free(thread); + pikaFree(thread, sizeof(pika_platform_thread_t)); thread = NULL; + return; } #elif PIKA_FREERTOS_ENABLE - if (NULL != thread) + if (NULL != thread) { vTaskDelete(thread->thread); - pika_platform_memory_free(thread); + pikaFree(thread, sizeof(pika_platform_thread_t)); + return; + } +#else + WEAK_FUNCTION_NEED_OVERRIDE_ERROR(); +#endif +} + +PIKA_WEAK void pika_platform_thread_exit(pika_platform_thread_t* thread) { +#ifdef __linux + return pika_platform_thread_destroy(thread); +#elif PIKA_FREERTOS_ENABLE + vTaskDelete(NULL); // test on esp32c3 + // vTaskDelete(thread->thread); + return; #else WEAK_FUNCTION_NEED_OVERRIDE_ERROR(); #endif @@ -438,20 +497,7 @@ PIKA_WEAK int pika_platform_thread_mutex_destroy( #endif } -#if PIKA_FREERTOS_ENABLE -static uint32_t platform_uptime_ms(void) { -#if (configTICK_RATE_HZ == 1000) - return (uint32_t)xTaskGetTickCount(); -#else - TickType_t tick = 0u; - - tick = xTaskGetTickCount() * 1000; - return (uint32_t)((tick + configTICK_RATE_HZ - 1) / configTICK_RATE_HZ); -#endif -} -#endif - -PIKA_WEAK void pika_platform_timer_init(pika_platform_timer_t* timer) { +PIKA_WEAK void pika_platform_thread_timer_init(pika_platform_timer_t* timer) { #ifdef __linux timer->time = (struct timeval){0, 0}; #elif PIKA_FREERTOS_ENABLE @@ -461,8 +507,8 @@ PIKA_WEAK void pika_platform_timer_init(pika_platform_timer_t* timer) { #endif } -PIKA_WEAK void pika_platform_timer_cutdown(pika_platform_timer_t* timer, - unsigned int timeout) { +PIKA_WEAK void pika_platform_thread_timer_cutdown(pika_platform_timer_t* timer, + unsigned int timeout) { #ifdef __linux struct timeval now; gettimeofday(&now, NULL); @@ -476,7 +522,8 @@ PIKA_WEAK void pika_platform_timer_cutdown(pika_platform_timer_t* timer, #endif } -PIKA_WEAK char pika_platform_timer_is_expired(pika_platform_timer_t* timer) { +PIKA_WEAK char pika_platform_thread_timer_is_expired( + pika_platform_timer_t* timer) { #ifdef __linux struct timeval now, res; gettimeofday(&now, NULL); @@ -490,7 +537,7 @@ PIKA_WEAK char pika_platform_timer_is_expired(pika_platform_timer_t* timer) { #endif } -PIKA_WEAK int pika_platform_timer_remain(pika_platform_timer_t* timer) { +PIKA_WEAK int pika_platform_thread_timer_remain(pika_platform_timer_t* timer) { #ifdef __linux struct timeval now, res; gettimeofday(&now, NULL); @@ -509,7 +556,7 @@ PIKA_WEAK int pika_platform_timer_remain(pika_platform_timer_t* timer) { #endif } -PIKA_WEAK unsigned long pika_platform_timer_now(void) { +PIKA_WEAK unsigned long pika_platform_thread_timer_now(void) { #ifdef __linux return (unsigned long)time(NULL); #elif PIKA_FREERTOS_ENABLE @@ -520,7 +567,7 @@ PIKA_WEAK unsigned long pika_platform_timer_now(void) { #endif } -PIKA_WEAK void pika_platform_timer_usleep(unsigned long usec) { +PIKA_WEAK void pika_platform_thread_timer_usleep(unsigned long usec) { #ifdef __linux usleep(usec); #elif PIKA_FREERTOS_ENABLE @@ -536,3 +583,7 @@ PIKA_WEAK void pika_platform_timer_usleep(unsigned long usec) { WEAK_FUNCTION_NEED_OVERRIDE_ERROR(); #endif } + +PIKA_WEAK void pika_platform_reboot(void) { + WEAK_FUNCTION_NEED_OVERRIDE_ERROR(); +} diff --git a/examples/pikapython/pikapython/pikascript-core/PikaPlatform.h b/examples/pikapython/pikapython/pikascript-core/PikaPlatform.h index 4a8422d5..e2b5c8fb 100644 --- a/examples/pikapython/pikapython/pikascript-core/PikaPlatform.h +++ b/examples/pikapython/pikapython/pikascript-core/PikaPlatform.h @@ -1,4 +1,4 @@ -/* +/* * This file is part of the PikaScript project. * http://github.com/pikastech/pikascript * @@ -44,7 +44,7 @@ #if PIKA_ASSERT_ENABLE #define pika_assert(expr) \ if(!(expr)) { \ - pika_platform_printf("Assertion \"%s\" failed, in function: %s(). \r\n (at %s:%d)\n", #expr, __FUNCTION__, __FILE__, __LINE__); \ + pika_platform_printf((char*)"Assertion \"%s\" failed, in function: %s(). \r\n (at %s:%d)\n", #expr, __FUNCTION__, __FILE__, __LINE__); \ abort(); \ } #else @@ -101,15 +101,19 @@ typedef enum { PIKA_RES_ERR_ASSERT = -16, PIKA_RES_ERR_SIGNAL_EVENT_FULL = -17, PIKA_RES_ERR_SIGNAL_EVENT_EMPTY = -18, + PIKA_RES_ERR_INDEX = -19, } PIKA_RES; /* clang-format off */ /* pikascript bool type */ -typedef enum { - PIKA_TRUE = 1, - PIKA_FALSE = 0, -} PIKA_BOOL; +#define PIKA_BOOL int64_t +#define PIKA_TRUE 1 +#define PIKA_FALSE 0 +#define _PIKA_BOOL_ERR -1 + +#define _PIKA_INT_ERR (-999999999) +#define _PIKA_FLOAT_ERR (-999999999.0) /* clang-format on */ @@ -175,11 +179,9 @@ void pika_platform_error_handle(void); /* panic */ void pika_platform_panic_handle(void); -void pika_platform_thread_delay(void); -int64_t pika_platform_getTick(void); +int64_t pika_platform_get_tick(void); void pika_platform_sleep_ms(uint32_t ms); -void pika_platform_sleep_s(uint32_t s); void pika_hook_instruct(void); PIKA_BOOL pika_hook_arg_cache_filter(void* self); @@ -206,8 +208,8 @@ typedef struct pika_platform_thread { pthread_cond_t cond; } pika_platform_thread_t; #elif PIKA_FREERTOS_ENABLE -#include "freertos/FreeRTOS.h" -#include "freertos/task.h" +#include "FreeRTOS.h" +#include "task.h" typedef struct pika_platform_thread { TaskHandle_t thread; } pika_platform_thread_t; @@ -223,25 +225,34 @@ pika_platform_thread_t* pika_platform_thread_init(const char* name, unsigned int stack_size, unsigned int priority, unsigned int tick); +uint64_t pika_platform_thread_self(void); +void pika_platform_thread_delay(void); void pika_platform_thread_startup(pika_platform_thread_t* thread); void pika_platform_thread_stop(pika_platform_thread_t* thread); void pika_platform_thread_start(pika_platform_thread_t* thread); void pika_platform_thread_destroy(pika_platform_thread_t* thread); +void pika_platform_thread_exit(pika_platform_thread_t* thread); #ifdef __linux #include typedef struct pika_platform_thread_mutex { pthread_mutex_t mutex; + volatile int is_init; + volatile int is_first_lock; } pika_platform_thread_mutex_t; #elif PIKA_FREERTOS_ENABLE -#include "freertos/FreeRTOS.h" -#include "freertos/semphr.h" +#include "FreeRTOS.h" +#include "semphr.h" typedef struct pika_platform_thread_mutex { SemaphoreHandle_t mutex; + volatile int is_init; + volatile int is_first_lock; } pika_platform_thread_mutex_t; #else typedef struct pika_platform_thread_mutex { void* platform_data; + volatile int is_init; + volatile int is_first_lock; } pika_platform_thread_mutex_t; #endif @@ -257,8 +268,8 @@ typedef struct pika_platform_timer { struct timeval time; } pika_platform_timer_t; #elif PIKA_FREERTOS_ENABLE -#include "freertos/FreeRTOS.h" -#include "freertos/task.h" +#include "FreeRTOS.h" +#include "task.h" typedef struct pika_platform_timer { uint32_t time; } pika_platform_timer_t; @@ -268,13 +279,14 @@ typedef struct pika_platform_timer { } pika_platform_timer_t; #endif -void pika_platform_timer_init(pika_platform_timer_t* timer); -void pika_platform_timer_cutdown(pika_platform_timer_t* timer, - unsigned int timeout); -char pika_platform_timer_is_expired(pika_platform_timer_t* timer); -int pika_platform_timer_remain(pika_platform_timer_t* timer); -unsigned long pika_platform_timer_now(void); -void pika_platform_timer_usleep(unsigned long usec); +void pika_platform_thread_timer_init(pika_platform_timer_t* timer); +void pika_platform_thread_timer_cutdown(pika_platform_timer_t* timer, + unsigned int timeout); +char pika_platform_thread_timer_is_expired(pika_platform_timer_t* timer); +int pika_platform_thread_timer_remain(pika_platform_timer_t* timer); +unsigned long pika_platform_thread_timer_now(void); +void pika_platform_thread_timer_usleep(unsigned long usec); +void pika_platform_reboot(void); #define WEAK_FUNCTION_NEED_OVERRIDE_ERROR(_) \ pika_platform_printf("Error: weak function `%s()` need override.\r\n", \ diff --git a/examples/pikapython/pikapython/pikascript-core/PikaVM.c b/examples/pikapython/pikapython/pikascript-core/PikaVM.c index 6f24cbbb..cab260eb 100644 --- a/examples/pikapython/pikapython/pikascript-core/PikaVM.c +++ b/examples/pikapython/pikapython/pikascript-core/PikaVM.c @@ -1,4 +1,4 @@ -/* +/* * This file is part of the PikaScript project. * http://github.com/pikastech/pikascript * @@ -48,20 +48,112 @@ volatile VMSignal PikaVMSignal = {.signal_ctrl = VM_SIGNAL_CTRL_NONE, #endif }; +static pika_platform_thread_mutex_t pikavm_global_lock = {0}; + +int pika_GIL_ENTER(void) { + if (!pikavm_global_lock.is_init) { + return 0; + } + int ret = pika_platform_thread_mutex_lock(&pikavm_global_lock); + pika_debug("pika_GIL_ENTER"); + if (!pikavm_global_lock.is_first_lock) { + pikavm_global_lock.is_first_lock = 1; + } + return ret; +} + +int pika_GIL_EXIT(void) { + if (!pikavm_global_lock.is_init) { + return 0; + } + pika_debug("pika_GIL_EXIT"); + return pika_platform_thread_mutex_unlock(&pikavm_global_lock); +} + +int _VM_lock_init(void) { + if (pikavm_global_lock.is_init) { + return 0; + } + int ret = pika_platform_thread_mutex_init(&pikavm_global_lock); + if (0 == ret) { + pikavm_global_lock.is_init = 1; + } + return ret; +} + +int _VM_is_first_lock(void) { + return pikavm_global_lock.is_first_lock; +} + int _VMEvent_getVMCnt(void) { return PikaVMSignal.vm_cnt; } #if PIKA_EVENT_ENABLE -static PIKA_BOOL _cq_isEmpty(volatile EventCQ* cq) { +static PIKA_BOOL _ecq_isEmpty(volatile EventCQ* cq) { return (PIKA_BOOL)(cq->head == cq->tail); } -static PIKA_BOOL _cq_isFull(volatile EventCQ* cq) { +static PIKA_BOOL _ecq_isFull(volatile EventCQ* cq) { return (PIKA_BOOL)((cq->tail + 1) % PIKA_EVENT_LIST_SIZE == cq->head); } #endif +#if PIKA_SETJMP_ENABLE + +static PIKA_BOOL _jcq_isEmpty(volatile JmpBufCQ* cq) { + return (PIKA_BOOL)(cq->head == cq->tail); +} + +static PIKA_BOOL _jcq_isFull(volatile JmpBufCQ* cq) { + return (PIKA_BOOL)((cq->tail + 1) % PIKA_JMP_BUF_LIST_SIZE == cq->head); +} + +static jmp_buf* _jcq_pop(volatile JmpBufCQ* cq) { + if (_jcq_isEmpty(cq)) { + return NULL; + } + jmp_buf* buf = cq->buf[cq->head]; + cq->head = (cq->head + 1) % PIKA_JMP_BUF_LIST_SIZE; + return buf; +} + +static jmp_buf* _jcq_check_pop(volatile JmpBufCQ* cq) { + if (_jcq_isEmpty(cq)) { + return NULL; + } + return cq->buf[cq->head]; +} + +static PIKA_RES _jcq_push(volatile JmpBufCQ* cq, jmp_buf* pos) { + if (_jcq_isFull(cq)) { + return -1; + } + cq->buf[cq->tail] = pos; + cq->tail = (cq->tail + 1) % PIKA_JMP_BUF_LIST_SIZE; + return PIKA_RES_OK; +} + +static PIKA_RES _jcq_remove(volatile JmpBufCQ* cq, jmp_buf* pos) { + if (_jcq_isEmpty(cq)) { + return -1; + } + for (int i = cq->head; i != cq->tail; + i = (i + 1) % PIKA_JMP_BUF_LIST_SIZE) { + if (cq->buf[i] == pos) { + /* move */ + for (int j = i; j != cq->tail; + j = (j + 1) % PIKA_JMP_BUF_LIST_SIZE) { + cq->buf[j] = cq->buf[(j + 1) % PIKA_JMP_BUF_LIST_SIZE]; + } + cq->tail = (cq->tail - 1) % PIKA_JMP_BUF_LIST_SIZE; + return PIKA_RES_OK; + } + } + return -1; +} +#endif + void _VMEvent_deinit(void) { #if !PIKA_EVENT_ENABLE pika_platform_printf("PIKA_EVENT_ENABLE is not enable"); @@ -88,7 +180,7 @@ PIKA_RES __eventListener_pushEvent(PikaEventListener* lisener, pika_platform_panic_handle(); #else /* push to event_cq_buff */ - if (_cq_isFull(&PikaVMSignal.cq)) { + if (_ecq_isFull(&PikaVMSignal.cq)) { arg_deinit(eventData); return PIKA_RES_ERR_SIGNAL_EVENT_FULL; } @@ -120,7 +212,7 @@ PIKA_RES __eventListener_popEvent(PikaEventListener** lisener_p, pika_platform_panic_handle(); #else /* pop from event_cq_buff */ - if (_cq_isEmpty(&PikaVMSignal.cq)) { + if (_ecq_isEmpty(&PikaVMSignal.cq)) { return PIKA_RES_ERR_SIGNAL_EVENT_EMPTY; } *id = PikaVMSignal.cq.id[PikaVMSignal.cq.head]; @@ -134,7 +226,7 @@ PIKA_RES __eventListener_popEvent(PikaEventListener** lisener_p, void _VMEvent_pickupEvent(void) { #if !PIKA_EVENT_ENABLE - pika_platform_printf("PIKA_EVENT_ENABLE is not enable"); + pika_platform_printf("PIKA_EVENT_ENABLE is not enable\r\n"); pika_platform_panic_handle(); #else PikaObj* event_lisener; @@ -205,18 +297,31 @@ static int VMState_getInvokeDeepthNow(VMState* vm) { static int32_t VMState_getAddrOffsetOfJmpBack(VMState* vm) { int offset = 0; - int loop_deepth = -1; + int blockDeepthGot = -1; + int blockDeepthNow = VMState_getBlockDeepthNow(vm); /* find loop deepth */ while (1) { offset -= instructUnit_getSize(); - InstructUnit* ins_unit_now = + InstructUnit* insUnitThis = VMState_getInstructUnitWithOffset(vm, offset); - uint16_t invoke_deepth = instructUnit_getInvokeDeepth(ins_unit_now); - enum Instruct ins = instructUnit_getInstruct(ins_unit_now); - char* data = VMState_getConstWithInstructUnit(vm, ins_unit_now); - if ((0 == invoke_deepth) && (JEZ == ins) && data[0] == '2') { - loop_deepth = instructUnit_getBlockDeepth(ins_unit_now); + uint16_t invokeDeepth = instructUnit_getInvokeDeepth(insUnitThis); + enum Instruct ins = instructUnit_getInstruct(insUnitThis); + char* data = VMState_getConstWithInstructUnit(vm, insUnitThis); + if ((0 == invokeDeepth) && (JEZ == ins) && data[0] == '2') { + InstructUnit* insUnitLast = VMState_getInstructUnitWithOffset( + vm, offset - instructUnit_getSize()); + enum Instruct insLast = instructUnit_getInstruct(insUnitLast); + /* skip try stmt */ + if (GER == insLast) { + continue; + } + /* skip inner break */ + int blockDeepthThis = instructUnit_getBlockDeepth(insUnitThis); + if (blockDeepthThis >= blockDeepthNow) { + continue; + } + blockDeepthGot = instructUnit_getBlockDeepth(insUnitThis); break; } } @@ -224,12 +329,12 @@ static int32_t VMState_getAddrOffsetOfJmpBack(VMState* vm) { offset = 0; while (1) { offset += instructUnit_getSize(); - InstructUnit* ins_unit_now = + InstructUnit* insUnitThis = VMState_getInstructUnitWithOffset(vm, offset); - enum Instruct ins = instructUnit_getInstruct(ins_unit_now); - char* data = VMState_getConstWithInstructUnit(vm, ins_unit_now); - int block_deepth_now = instructUnit_getBlockDeepth(ins_unit_now); - if ((block_deepth_now == loop_deepth) && (JMP == ins) && + enum Instruct ins = instructUnit_getInstruct(insUnitThis); + char* data = VMState_getConstWithInstructUnit(vm, insUnitThis); + int blockDeepthThis = instructUnit_getBlockDeepth(insUnitThis); + if ((blockDeepthThis == blockDeepthGot) && (JMP == ins) && data[0] == '-' && data[1] == '1') { return offset; } @@ -404,6 +509,7 @@ Arg* __vm_get(VMState* vm, PikaObj* self, Arg* key, Arg* obj) { arg_obj = arg_getPtr(obj); } obj_setArg(arg_obj, "__key", key); + obj_removeArg(arg_obj, "__res"); /* clang-format off */ PIKA_PYTHON( __res = __getitem__(__key) @@ -486,8 +592,8 @@ Arg* _vm_slice(VMState* vm, if (start_i < 0) { start_i += len; } - /* magit code, to the end */ - if (end_i == -99999) { + /* megic code, to the end */ + if (end_i == VM_PC_EXIT) { end_i = len; } if (end_i < 0) { @@ -587,6 +693,7 @@ static Arg* VM_instruction_handler_EXP(PikaObj* self, VMState* vm, char* data, Arg* arg_ret_reg) { + vm->try_error_code = 0; return NULL; } @@ -667,7 +774,7 @@ static Arg* VM_instruction_handler_REF(PikaObj* self, VMState* vm, char* data, Arg* arg_ret_reg) { - PikaObj* host_object = NULL; + PikaObj* host_obj = NULL; char* arg_path = data; char* arg_name = strPointToLastToken(arg_path, '.'); PIKA_BOOL is_temp = PIKA_FALSE; @@ -675,12 +782,12 @@ static Arg* VM_instruction_handler_REF(PikaObj* self, switch (data[0]) { case 'T': if (strEqu(arg_path, (char*)"True")) { - return arg_setInt(arg_ret_reg, "", 1); + return arg_setBool(arg_ret_reg, "", PIKA_TRUE); } break; case 'F': if (strEqu(arg_path, (char*)"False")) { - return arg_setInt(arg_ret_reg, "", 0); + return arg_setBool(arg_ret_reg, "", PIKA_FALSE); } break; case 'N': @@ -698,51 +805,44 @@ static Arg* VM_instruction_handler_REF(PikaObj* self, Arg* res = NULL; if (arg_path[0] == '.') { /* find host from stack */ - Arg* host_obj = stack_popArg_alloc(&(vm->stack)); - if (argType_isObject(arg_getType(host_obj))) { - host_object = arg_getPtr(host_obj); - res = arg_copy_noalloc(obj_getArg(host_object, arg_path + 1), + Arg* host_arg = stack_popArg_alloc(&(vm->stack)); + if (argType_isObject(arg_getType(host_arg))) { + host_obj = arg_getPtr(host_arg); + res = arg_copy_noalloc(obj_getArg(host_obj, arg_path + 1), arg_ret_reg); } - arg_deinit(host_obj); + arg_deinit(host_arg); goto exit; } - /* host_object is self */ - if (NULL == host_object) { - if (!strIsContain(arg_path, '.')) { - host_object = vm->locals; - } - } - /* find in local list first */ - if (NULL == host_object) { - host_object = obj_getHostObjWithIsTemp(vm->locals, arg_path, &is_temp); + if (NULL == host_obj) { + host_obj = obj_getHostObjWithIsTemp(vm->locals, arg_path, &is_temp); } /* find in global list */ - if (NULL == host_object) { - host_object = obj_getHostObjWithIsTemp(vm->globals, arg_path, &is_temp); + if (NULL == host_obj) { + host_obj = obj_getHostObjWithIsTemp(vm->globals, arg_path, &is_temp); } /* error cannot found host_object */ - if (NULL == host_object) { + if (NULL == host_obj) { goto exit; } /* proxy */ if (NULL == res) { - res = _proxy_getattribute(host_object, arg_name); + res = _proxy_getattribute(host_obj, arg_name); } /* find res in host */ if (NULL == res) { - res = args_getArg(host_object->list, arg_name); + res = args_getArg(host_obj->list, arg_name); } /* find res in host prop */ if (NULL == res) { - res = _obj_getProp(host_object, arg_name); + res = _obj_getProp(host_obj, arg_name); } /* find res in globlas */ @@ -750,21 +850,28 @@ static Arg* VM_instruction_handler_REF(PikaObj* self, res = args_getArg(vm->globals->list, arg_name); } - /* proxy */ + /* find res in globals prop */ if (NULL == res) { - res = _proxy_getattr(host_object, arg_name); + res = _obj_getProp(vm->globals, arg_name); } + /* proxy */ + if (NULL == res) { + res = _proxy_getattr(host_obj, arg_name); + } exit: if (NULL == res) { VMState_setErrorCode(vm, PIKA_RES_ERR_ARG_NO_FOUND); pika_platform_printf("NameError: name '%s' is not defined\r\n", arg_path); } else { + if (arg_getType(res) == ARG_TYPE_METHOD_OBJECT) { + methodArg_setHostObj(res, host_obj); + } res = arg_copy_noalloc(res, arg_ret_reg); } if (is_temp) { - obj_deinit(host_object); + obj_GC(host_obj); } return res; } @@ -861,29 +968,40 @@ Arg* obj_runMethodArg(PikaObj* self, &run_state); } -static char* _kw_to_default_all(FunctionArgsInfo* f, - char* arg_name, - int* argc, - Arg* argv[], - Arg* call_arg) { -#if PIKA_NANO +static char* _kw_pos_to_default_all(FunctionArgsInfo* f, + char* arg_name, + int* argc, + Arg* argv[], + Arg* call_arg) { +#if PIKA_NANO_ENABLE return arg_name; #endif + int n_default_skip = 0; + int n_default_skiped = 0; + if (f->i_arg == f->n_arg) { + n_default_skip = f->n_default - f->n_arg; + } while (strIsContain(arg_name, '=')) { strPopLastToken(arg_name, '='); - Arg* default_arg = NULL; + Arg* kw_arg = NULL; /* load default arg from kws */ if (f->kw != NULL) { - default_arg = pikaDict_getArg(f->kw, arg_name); - if (default_arg != NULL) { - Arg* arg_new = arg_copy(default_arg); + kw_arg = pikaDict_getArg(f->kw, arg_name); + if (kw_arg != NULL) { + Arg* arg_new = arg_copy(kw_arg); argv[(*argc)++] = arg_new; - pikaDict_removeArg(f->kw, default_arg); + pikaDict_removeArg(f->kw, kw_arg); } } - if (f->kw == NULL || default_arg == NULL) { + if (f->kw == NULL || kw_arg == NULL) { /* can not load defalut from kw */ if (NULL != call_arg && f->is_default) { + /* load pos to default with right order */ + if (n_default_skiped < n_default_skip) { + n_default_skiped++; + arg_name = strPopLastToken(f->type_list, ','); + continue; + } /* load default from pos */ if (f->i_arg > f->n_positional) { arg_setNameHash(call_arg, @@ -932,6 +1050,7 @@ static void _kw_to_pos_all(FunctionArgsInfo* f, int* argc, Arg* argv[]) { static void _loadLocalsFromArgv(Args* locals, int argc, Arg* argv[]) { for (int i = 0; i < argc; i++) { Arg* arg = argv[i]; + pika_assert(arg != NULL); args_setArg(locals, arg); } } @@ -1012,7 +1131,7 @@ static void _load_call_arg(VMState* vm, } char* arg_name = strPopLastToken(f->type_list, ','); /* load default from kw */ - arg_name = _kw_to_default_all(f, arg_name, argc, argv, call_arg); + arg_name = _kw_pos_to_default_all(f, arg_name, argc, argv, call_arg); if (((char*)1) == arg_name) { /* load default from pos */ return; @@ -1028,15 +1147,16 @@ static void _load_call_arg(VMState* vm, } /*load pos from pos */ arg_setNameHash(call_arg, hash_time33EndWith(arg_name, ':')); + pika_assert(call_arg != NULL); argv[(*argc)++] = call_arg; (f->n_positional_got)++; } -static int _get_n_input_with_unpack(VMState* vm) { +static int _get_n_input_with_unpack(VMState* vm, int n_used) { #if PIKA_NANO_ENABLE return VMState_getInputArgNum(vm); #else - int n_input = VMState_getInputArgNum(vm); + int n_input = VMState_getInputArgNum(vm) - n_used; int get_star = 0; int unpack_num = 0; for (int i = 0; i < n_input; i++) { @@ -1168,7 +1288,7 @@ static int VMState_loadArgsFromMethodArg(VMState* vm, f.n_positional--; } - f.n_input = _get_n_input_with_unpack(vm); + f.n_input = _get_n_input_with_unpack(vm, n_used); /* check arg num */ if (f.method_type == ARG_TYPE_METHOD_NATIVE_CONSTRUCTOR || @@ -1258,7 +1378,7 @@ static int VMState_loadArgsFromMethodArg(VMState* vm, #if !PIKA_NANO_ENABLE if (strIsContain(f.type_list, '=')) { char* arg_name = strPopLastToken(f.type_list, ','); - _kw_to_default_all(&f, arg_name, &argc, argv, NULL); + _kw_pos_to_default_all(&f, arg_name, &argc, argv, NULL); } /* load kw to pos */ _kw_to_pos_all(&f, &argc, argv); @@ -1290,7 +1410,12 @@ static int VMState_loadArgsFromMethodArg(VMState* vm, /* load 'self' as the first arg when call object method */ if (f.method_type == ARG_TYPE_METHOD_OBJECT) { - Arg* call_arg = arg_setRef(NULL, "self", method_host_obj); + PikaObj* method_self = methodArg_getHostObj(method_arg); + if (NULL == method_self) { + method_self = method_host_obj; + } + Arg* call_arg = arg_setRef(NULL, "self", method_self); + pika_assert(call_arg != NULL); argv[argc++] = call_arg; } _loadLocalsFromArgv(locals, argc, argv); @@ -1497,8 +1622,8 @@ static Arg* VM_instruction_handler_RUN(PikaObj* self, } /* tuple or single arg */ - if (run_path[0] == 0) { - if (VMState_getInputArgNum(vm) < 2) { + if (NULL == run_path || run_path[0] == 0) { + if (VMState_getInputArgNum(vm) == 1) { /* return arg directly */ return_arg = stack_popArg(&(vm->stack), arg_ret_reg); goto exit; @@ -1567,7 +1692,7 @@ static Arg* VM_instruction_handler_RUN(PikaObj* self, method_host = obj_getHostObjWithIsTemp(vm->locals, run_path, &is_temp); } - /* get method host obj from local scope */ + /* get method host obj from global scope */ if (NULL == method_host) { method_host = obj_getHostObjWithIsTemp(vm->globals, run_path, &is_temp); } @@ -1606,6 +1731,9 @@ static Arg* VM_instruction_handler_RUN(PikaObj* self, /* get method in global */ if (NULL == method) { method = obj_getMethodArg_noalloc(vm->globals, run_path, &arg_reg1); + if (method != NULL) { + obj_this = vm->globals; + } } /* assert method exist */ @@ -1709,7 +1837,7 @@ exit: } if (NULL != method_host && is_temp) { /* class method */ - obj_deinit(method_host); + obj_GC(method_host); } return return_arg; @@ -2074,6 +2202,9 @@ void operatorInfo_init(OperatorInfo* info, } else if (info->t1 == ARG_TYPE_FLOAT) { info->f1 = arg_getFloat(info->a1); info->i1 = (int64_t)info->f1; + } else if (info->t1 == ARG_TYPE_BOOL) { + info->i1 = arg_getBool(info->a1); + info->f1 = (pika_float)info->i1; } } info->t2 = arg_getType(info->a2); @@ -2084,6 +2215,9 @@ void operatorInfo_init(OperatorInfo* info, } else if (info->t2 == ARG_TYPE_FLOAT) { info->f2 = arg_getFloat(info->a2); info->i2 = (int64_t)info->f2; + } else if (info->t2 == ARG_TYPE_BOOL) { + info->i2 = arg_getBool(info->a2); + info->f2 = (pika_float)info->i2; } } @@ -2263,14 +2397,18 @@ static void _OPT_EQU(OperatorInfo* op) { } goto exit; } - /* default: int and float */ + if (argType_isCallable(op->t1) && argType_isCallable(op->t2)) { + is_equ = (arg_getPtr(op->a1) == arg_getPtr(op->a2)); + goto exit; + } + /* default: int bool, and float */ is_equ = ((op->f1 - op->f2) * (op->f1 - op->f2) < (pika_float)0.000001); goto exit; exit: if (op->opt[0] == '=') { - op->res = arg_setInt(op->res, "", is_equ); + op->res = arg_setBool(op->res, "", is_equ); } else { - op->res = arg_setInt(op->res, "", !is_equ); + op->res = arg_setBool(op->res, "", !is_equ); } return; } @@ -2354,7 +2492,7 @@ static Arg* VM_instruction_handler_OPT(PikaObj* self, if (data[1] == 0) { switch (data[0]) { case '<': - op.res = arg_setInt(op.res, "", op.f1 < op.f2); + op.res = arg_setBool(op.res, "", op.f1 < op.f2); goto exit; case '*': if (op.num == 1) { @@ -2416,9 +2554,9 @@ static Arg* VM_instruction_handler_OPT(PikaObj* self, if (data[1] == 'i' && data[2] == 'n') { if (op.t1 == ARG_TYPE_STRING && op.t2 == ARG_TYPE_STRING) { if (strstr(arg_getStr(op.a2), arg_getStr(op.a1))) { - op.res = arg_setInt(op.res, "", 1); + op.res = arg_setBool(op.res, "", PIKA_TRUE); } else { - op.res = arg_setInt(op.res, "", 0); + op.res = arg_setBool(op.res, "", PIKA_FALSE); } goto exit; } @@ -2446,7 +2584,7 @@ static Arg* VM_instruction_handler_OPT(PikaObj* self, 0x00, /* const pool */ }; pikaVM_runByteCode(obj2, (uint8_t*)bytes); - op.res = arg_setInt(op.res, "", obj_getInt(obj2, "__res")); + op.res = arg_setBool(op.res, "", obj_getInt(obj2, "__res")); goto exit; } } @@ -2490,14 +2628,14 @@ static Arg* VM_instruction_handler_OPT(PikaObj* self, goto exit; } if (data[0] == '>' && data[1] == '=') { - op.res = arg_setInt( + op.res = arg_setBool( op.res, "", (op.f1 > op.f2) || ((op.f1 - op.f2) * (op.f1 - op.f2) < (pika_float)0.000001)); goto exit; } if (data[0] == '<' && data[1] == '=') { - op.res = arg_setInt( + op.res = arg_setBool( op.res, "", (op.f1 < op.f2) || ((op.f1 - op.f2) * (op.f1 - op.f2) < (pika_float)0.000001)); @@ -2527,17 +2665,17 @@ static Arg* VM_instruction_handler_OPT(PikaObj* self, } if (data[0] == ' ' && data[1] == 'a' && data[2] == 'n' && data[3] == 'd' && data[4] == ' ') { - op.res = arg_setInt(op.res, "", op.i1 && op.i2); + op.res = arg_setBool(op.res, "", op.i1 && op.i2); goto exit; } if (data[0] == ' ' && data[1] == 'o' && data[2] == 'r' && data[3] == ' ' && data[4] == 0) { - op.res = arg_setInt(op.res, "", op.i1 || op.i2); + op.res = arg_setBool(op.res, "", op.i1 || op.i2); goto exit; } if (data[0] == ' ' && data[1] == 'n' && data[2] == 'o' && data[3] == 't' && data[4] == ' ' && data[5] == 0) { - op.res = arg_setInt(op.res, "", !op.i2); + op.res = arg_setBool(op.res, "", !op.i2); goto exit; } exit: @@ -2647,7 +2785,9 @@ static Arg* VM_instruction_handler_ASS(PikaObj* self, arg1 = stack_popArg(&vm->stack, ®1); } /* assert failed */ - if (arg_getType(arg1) == ARG_TYPE_INT && arg_getInt(arg1) == 0) { + if ((arg_getType(arg1) == ARG_TYPE_INT && arg_getInt(arg1) == 0) || + (arg_getType(arg1) == ARG_TYPE_BOOL && + arg_getBool(arg1) == PIKA_FALSE)) { stack_pushArg(&vm->stack, arg_newInt(PIKA_RES_ERR_ASSERT)); res = VM_instruction_handler_RIS(self, vm, data, arg_ret_reg); if (vm->run_state->try_state == TRY_STATE_NONE) { @@ -2784,12 +2924,12 @@ static Arg* VM_instruction_handler_IMP(PikaObj* self, const VM_instruct_handler VM_instruct_handler_table[__INSTRCUTION_CNT] = { #define __INS_TABLE -#include "__instruction_table.cfg" +#include "__instruction_table.h" }; enum Instruct pikaVM_getInstructFromAsm(char* ins_str) { #define __INS_COMPIRE -#include "__instruction_table.cfg" +#include "__instruction_table.h" return NON; } @@ -3214,6 +3354,7 @@ void _do_byteCodeFrame_loadByteCode(ByteCodeFrame* self, self->const_pool.content_start = arg_getBytes(self->const_pool.arg_buff); } + pika_assert(NULL != self->const_pool.content_start); } void byteCodeFrame_loadByteCode(ByteCodeFrame* self, uint8_t* bytes) { @@ -3280,7 +3421,7 @@ InstructUnit* instructArray_getNext(InstructArray* self) { static char* instructUnit_getInstructStr(InstructUnit* self) { #define __INS_GET_INS_STR -#include "__instruction_table.cfg" +#include "__instruction_table.h" return "NON"; } @@ -3393,7 +3534,7 @@ void VMState_solveUnusedStack(VMState* vm) { arg_deinit(arg); continue; } - arg_singlePrint(arg, PIKA_TRUE, "\r\n"); + arg_print(arg, PIKA_TRUE, "\r\n"); arg_deinit(arg); } } @@ -3408,21 +3549,19 @@ static VMParameters* __pikaVM_runByteCodeFrameWithState( pika_assert(NULL != run_state); int size = bytecode_frame->instruct_array.size; /* locals is the local scope */ - VMState vm = { - .bytecode_frame = bytecode_frame, - .locals = locals, - .globals = globals, - .jmp = 0, - .pc = pc, - .loop_deepth = 0, - .error_code = PIKA_RES_OK, - .line_error_code = PIKA_RES_OK, - .try_error_code = PIKA_RES_OK, - .run_state = run_state, - .ins_cnt = 0, - .in_super = PIKA_FALSE, - .super_invoke_deepth = 0, - }; + VMState vm = {.bytecode_frame = bytecode_frame, + .locals = locals, + .globals = globals, + .jmp = 0, + .pc = pc, + .loop_deepth = 0, + .error_code = PIKA_RES_OK, + .line_error_code = PIKA_RES_OK, + .try_error_code = PIKA_RES_OK, + .run_state = run_state, + .ins_cnt = 0, + .in_super = PIKA_FALSE, + .super_invoke_deepth = 0}; stack_init(&(vm.stack)); VMState_initReg(&vm); if (PikaVMSignal.vm_cnt == 0) { @@ -3448,9 +3587,7 @@ static VMParameters* __pikaVM_runByteCodeFrameWithState( pika_hook_instruct(); } #endif -#if PIKA_EVENT_ENABLE - _VMEvent_pickupEvent(); -#endif + _pikaVM_yield(); if (0 != vm.error_code) { vm.line_error_code = vm.error_code; InstructUnit* head_ins_unit = this_ins_unit; @@ -3544,19 +3681,31 @@ void byteCodeFrame_printAsArray(ByteCodeFrame* self) { PikaObj* pikaVM_runFile(PikaObj* self, char* file_name) { Args buffs = {0}; - char* module_name = strsCopy(&buffs, file_name); + char* module_name = strsPathGetFileName(&buffs, file_name); strPopLastToken(module_name, '.'); - + char* pwd = strsPathGetFolder(&buffs, file_name); pika_platform_printf("(pikascript) pika compiler:\r\n"); PikaMaker* maker = New_PikaMaker(); + pikaMaker_setPWD(maker, pwd); pikaMaker_compileModuleWithDepends(maker, module_name); - pikaMaker_linkCompiledModules(maker, "pikaModules_cache.py.a"); + _do_pikaMaker_linkCompiledModules(maker, "pikaModules_cache.py.a", + PIKA_FALSE); pikaMaker_deinit(maker); pika_platform_printf("(pikascript) all succeed.\r\n\r\n"); pikaMemMaxReset(); - obj_linkLibraryFile(self, "pikascript-api/pikaModules_cache.py.a"); + char* libfile_path = + strsPathJoin(&buffs, pwd, "pikascript-api/pikaModules_cache.py.a"); + obj_linkLibraryFile(self, libfile_path); self = pikaVM_runSingleFile(self, file_name); strsDeinit(&buffs); return self; } + +void _pikaVM_yield(void) { +#if PIKA_EVENT_ENABLE + _VMEvent_pickupEvent(); +#endif + pika_GIL_EXIT(); + pika_GIL_ENTER(); +} diff --git a/examples/pikapython/pikapython/pikascript-core/PikaVM.h b/examples/pikapython/pikapython/pikascript-core/PikaVM.h index c267ae3b..8ce8268a 100644 --- a/examples/pikapython/pikapython/pikascript-core/PikaVM.h +++ b/examples/pikapython/pikapython/pikascript-core/PikaVM.h @@ -31,10 +31,13 @@ #include "dataQueue.h" #include "dataQueueObj.h" #include "dataStack.h" +#if PIKA_SETJMP_ENABLE +#include +#endif enum Instruct { #define __INS_ENUM -#include "__instruction_table.cfg" +#include "__instruction_table.h" __INSTRCUTION_CNT, }; @@ -45,7 +48,7 @@ typedef enum { VM_JMP_RAISE = -996, } VM_JMP; -typedef enum { VM_PC_EXIT = -99999 } VM_PC; +#define VM_PC_EXIT (-99999) typedef enum { TRY_STATE_NONE = 0, @@ -132,6 +135,14 @@ typedef struct EventCQ { int tail; } EventCQ; +#if PIKA_SETJMP_ENABLE +typedef struct JmpBufCQ { + jmp_buf* buf[PIKA_JMP_BUF_LIST_SIZE]; + int head; + int tail; +} JmpBufCQ; +#endif + typedef struct VMSignal VMSignal; struct VMSignal { VM_SIGNAL_CTRL signal_ctrl; @@ -313,4 +324,7 @@ PIKA_RES __eventListener_pushEvent(PikaEventListener* lisener, Arg* eventData); int _VMEvent_getVMCnt(void); void _VMEvent_pickupEvent(void); +void _pikaVM_yield(void); +int _VM_lock_init(void); +int _VM_is_first_lock(void); #endif diff --git a/examples/pikapython/pikapython/pikascript-core/PikaVersion.h b/examples/pikapython/pikapython/pikascript-core/PikaVersion.h index 0a961d53..832ed432 100644 --- a/examples/pikapython/pikapython/pikascript-core/PikaVersion.h +++ b/examples/pikapython/pikapython/pikascript-core/PikaVersion.h @@ -2,4 +2,4 @@ #define PIKA_VERSION_MINOR 12 #define PIKA_VERSION_MICRO 0 -#define PIKA_EDIT_TIME "2022/12/29 18:05:17" +#define PIKA_EDIT_TIME "2023/02/18 20:34:52" diff --git a/examples/pikapython/pikapython/pikascript-core/__default_filter_msg_def.h b/examples/pikapython/pikapython/pikascript-core/__default_filter_msg_def.h new file mode 100755 index 00000000..859096fa --- /dev/null +++ b/examples/pikapython/pikapython/pikascript-core/__default_filter_msg_def.h @@ -0,0 +1,69 @@ +/* + * This file is part of the PikaScript project. + * http://github.com/pikastech/pikascript + * + * MIT License + * + * Copyright (c) 2023 GorgonMeducer ?? embedded_zhuoran@hotmail.com + * + * 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. + */ + +#undef add_filter_msg +#undef add_filter_item +#undef __add_filter_msg +#undef __add_filter_item +#undef __NO_FILTER_HANLDER__ + + +#if defined(__MSG_TABLE) + #define __add_filter_msg(__name, __msg, ...) \ + { \ + .message = (const uint8_t []){__msg}, \ + .size = sizeof((const uint8_t []){__msg}) - 1, \ + .handler = _filter_msg_##__name##_handler, \ + __VA_ARGS__ \ + }, + #define __add_filter_item(__name, ...) \ + { \ + .handler = _filter_msg_##__name##_handler, \ + __VA_ARGS__ \ + }, +#endif + +#if defined(__MSG_DECLARE) + #define __add_filter_msg(__name, __msg, ...) \ + PIKA_BOOL _filter_msg_##__name##_handler( FilterItem *msg, \ + PikaObj* self, \ + ShellConfig* shell); + #define __add_filter_item(__name, ...) \ + PIKA_BOOL _filter_msg_##__name##_handler( FilterItem *msg, \ + PikaObj* self, \ + ShellConfig* shell); +#endif + +#undef __MSG_TABLE +#undef __MSG_DECLARE + + +#define add_filter_msg(__name, __msg, ...) \ + __add_filter_msg(__name, __msg, ##__VA_ARGS__) +#define add_filter_item(__name, ...) \ + __add_filter_item(__name, ##__VA_ARGS__) +#define __NO_FILTER_HANLDER__ .handler = NULL diff --git a/examples/pikapython/pikapython/pikascript-core/__default_filter_msg_table.h b/examples/pikapython/pikapython/pikascript-core/__default_filter_msg_table.h new file mode 100755 index 00000000..7bde1b37 --- /dev/null +++ b/examples/pikapython/pikapython/pikascript-core/__default_filter_msg_table.h @@ -0,0 +1,74 @@ +/* + * This file is part of the PikaScript project. + * http://github.com/pikastech/pikascript + * + * MIT License + * + * Copyright (c) 2023 GorgonMeducer ?? embedded_zhuoran@hotmail.com + * + * 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 "__default_filter_msg_def.h" +#if defined(__clang__) +# pragma clang diagnostic push +# pragma clang diagnostic ignored "-Wunknown-warning-option" +# pragma clang diagnostic ignored "-Winitializer-overrides" +#endif + +/* add your own message filter here with syntax: + * + * add_filter_msg( + * , + * , + * [.is_visible = PIKA_TRUE,] + * [.is_case_insensitive = PIKA_TRUE,] + * [.ignore_mask = mask value,] + * [.target = your own object address/value,] + * ) + */ + +add_filter_msg(hi_pika, "###Hi Pika") +add_filter_msg(bye_pika, "###bye pika", .is_case_insensitive = PIKA_TRUE) + +/* add your own message item here with syntax: + * + * add_filter_item( + * , + * .message = (const uint8_t []){< num0, num1, ... >}, + * .size = , + * [.is_visible = PIKA_TRUE,] + * [.is_case_insensitive = PIKA_TRUE,] + * [.ignore_mask = mask value,] + * [.target = your own object address/value,] + * ) + * + * for example: + * + * add_filter_item( + * example_array, + * .message = (const uint8_t []){'a','b','c'}, + * .size = 3, + * __NO_FILTER_HANLDER__, + * ) + */ + +#if defined(__clang__) +# pragma clang diagnostic pop +#endif \ No newline at end of file diff --git a/examples/pikapython/pikapython/pikascript-core/__instruction_table.h b/examples/pikapython/pikapython/pikascript-core/__instruction_table.h new file mode 100755 index 00000000..e69baf28 --- /dev/null +++ b/examples/pikapython/pikapython/pikascript-core/__instruction_table.h @@ -0,0 +1,98 @@ +/* + * This file is part of the PikaScript project. + * http://github.com/pikastech/pikascript + * + * MIT License + * + * Copyright (c) 2021 GorgonMeducer ?? embedded_zhuoran@hotmail.com + * + * 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 "__instruction_def.h" + +//! just append ins to the end, insert ins would brake the pre-compiled +//! bytecode. + +/* none */ +def_ins(NON) +/* get referance */ +def_ins(REF) +/* run function */ +def_ins(RUN) +/* string */ +def_ins(STR) +/* output */ +def_ins(OUT) +/* number */ +def_ins(NUM) +/* jump */ +def_ins(JMP) +/* jump qual zero */ +def_ins(JEZ) +/* operator */ +def_ins(OPT) +/* define */ +def_ins(DEF) +/* return */ +def_ins(RET) +/* not equal */ +def_ins(NEL) +/* delete */ +def_ins(DEL) +/* exist */ +def_ins(EST) +/* break */ +def_ins(BRK) +/* continue */ +def_ins(CTN) +/* global */ +def_ins(GLB) +/* run as */ +def_ins(RAS) +/* new */ +def_ins(NEW) +/* class */ +def_ins(CLS) +/* bytes */ +def_ins(BYT) +/* list */ +def_ins(LST) +/* import */ +def_ins(IMP) +/* try */ +def_ins(TRY) +/* not try */ +def_ins(NTR) +/* raise */ +def_ins(RIS) +/* get error code */ +def_ins(GER) +/* set error code */ +def_ins(SER) +/* dict */ +def_ins(DCT) +/* slice */ +def_ins(SLC) +/* assert */ +def_ins(ASS) +/* expect */ +def_ins(EXP) +/* jump no zero */ +def_ins(JNZ) diff --git a/examples/pikapython/pikapython/pikascript-core/__pika_ooc.h b/examples/pikapython/pikapython/pikascript-core/__pika_ooc.h index 91c5c379..abf2e238 100644 --- a/examples/pikapython/pikapython/pikascript-core/__pika_ooc.h +++ b/examples/pikapython/pikapython/pikascript-core/__pika_ooc.h @@ -26,11 +26,16 @@ * SOFTWARE. */ + #ifndef __PIKA_OOC_H__ #define __PIKA_OOC_H__ - #if PIKA_PLOOC_ENABLE - #include "../pikascript-lib/PLOOC/plooc_class.h" - #else - #define private_member(X) X + /* non-reentrant part */ + #if !defined(PIKA_PLOOC_ENABLE) || !PIKA_PLOOC_ENABLE + #define private_member(...) __VA_ARGS__ #endif #endif + +/* plooc_class.h should support reentrant */ +#if PIKA_PLOOC_ENABLE + #include "../pikascript-lib/PLOOC/plooc_class.h" +#endif diff --git a/examples/pikapython/pikapython/pikascript-core/dataArg.c b/examples/pikapython/pikapython/pikascript-core/dataArg.c index 35a0dcc7..ad28b0d8 100644 --- a/examples/pikapython/pikapython/pikascript-core/dataArg.c +++ b/examples/pikapython/pikapython/pikascript-core/dataArg.c @@ -142,7 +142,7 @@ static Arg* _arg_set_hash(Arg* self, pika_platform_memcpy(arg_getContent(self), content, size); } else { pika_platform_memset(arg_getContent(self), 0, - aline_by(size, sizeof(uint32_t))); + aline_by(size, sizeof(uint32_t))); } pika_assert(self->flag < ARG_FLAG_MAX); return self; @@ -243,7 +243,8 @@ Arg* arg_setBytes(Arg* self, char* name, uint8_t* src, size_t size) { /* set init value */ if (NULL != src) { - pika_platform_memcpy((void*)((uintptr_t)dir + sizeof(size_t)), src, size); + pika_platform_memcpy((void*)((uintptr_t)dir + sizeof(size_t)), src, + size); } pika_assert(self->flag < ARG_FLAG_MAX); return self; @@ -258,67 +259,98 @@ uint8_t* arg_getBytes(Arg* self) { return arg_getContent(self) + sizeof(size_t); } -char* __printBytes(PikaObj* self, Arg* arg) { - Args buffs = {0}; - size_t bytes_size = arg_getBytesSize(arg); - uint8_t* bytes = arg_getBytes(arg); - Arg* str_arg = arg_newStr("b\'"); - for (size_t i = 0; i < bytes_size; i++) { - char* str_item = strsFormat(&buffs, 16, "\\x%02x", bytes[i]); - str_arg = arg_strAppend(str_arg, str_item); - } - str_arg = arg_strAppend(str_arg, "\'"); - char* str_res = obj_cacheStr(self, arg_getStr(str_arg)); - strsDeinit(&buffs); - arg_deinit(str_arg); - return str_res; -} - -void arg_printBytes(Arg* self, char* end) { - PikaObj* obj = New_PikaObj(); - pika_platform_printf("%s%s", __printBytes(obj, self), end); - obj_deinit(obj); -} - -void arg_singlePrint(Arg* self, PIKA_BOOL in_REPL, char* end) { - ArgType type = arg_getType(self); - if (ARG_TYPE_NONE == type) { - pika_platform_printf("None%s", end); - return; - } - if (argType_isObject(type)) { - char* res = obj_toStr(arg_getPtr(self)); - pika_platform_printf("%s%s", res, end); - return; +Arg* arg_toStrArg(Arg* arg) { + ArgType type = arg_getType(arg); + char buff[PIKA_SPRINTF_BUFF_SIZE] = {0}; + if (type == ARG_TYPE_BYTES) { + char buff_item[16] = {0}; + size_t bytes_size = arg_getBytesSize(arg); + uint8_t* bytes = arg_getBytes(arg); + Arg* str_arg = arg_newStr("b\'"); + for (size_t i = 0; i < bytes_size; i++) { + pika_platform_snprintf(buff_item, 16, "\\x%02x", bytes[i]); + char* str_item = (char*)buff_item; + str_arg = arg_strAppend(str_arg, str_item); + } + str_arg = arg_strAppend(str_arg, "\'"); + return str_arg; } if (type == ARG_TYPE_INT) { #if PIKA_PRINT_LLD_ENABLE - pika_platform_printf("%lld%s", (long long int)arg_getInt(self), end); + pika_platform_snprintf(buff, PIKA_SPRINTF_BUFF_SIZE, "%lld", + (long long int)arg_getInt(arg)); #else - pika_platform_printf("%d%s", (int)arg_getInt(self), end); + pika_platform_snprintf(buff, PIKA_SPRINTF_BUFF_SIZE, "%d", + (int)arg_getInt(arg)); #endif - return; + return arg_newStr(buff); + } + if (type == ARG_TYPE_BOOL) { + if (arg_getBool(arg)) { + return arg_newStr("True"); + } + return arg_newStr("False"); } if (type == ARG_TYPE_FLOAT) { - pika_platform_printf("%f%s", arg_getFloat(self), end); - return; + pika_platform_snprintf(buff, PIKA_SPRINTF_BUFF_SIZE, "%f", + arg_getFloat(arg)); + return arg_newStr(buff); } if (type == ARG_TYPE_STRING) { - if (in_REPL) { - pika_platform_printf("'%s'%s", arg_getStr(self), end); - return; + return arg_newStr(arg_getStr(arg)); + } + if (type == ARG_TYPE_POINTER) { + pika_platform_snprintf(buff, PIKA_SPRINTF_BUFF_SIZE, "%p", + arg_getPtr(arg)); + return arg_newStr(buff); + } + if (argType_isCallable(type)) { + /* support basic type */ + if (type == ARG_TYPE_METHOD_NATIVE) { + MethodProp* method_store = (MethodProp*)arg_getContent(arg); + if (strEqu(method_store->name, "int") || + strEqu(method_store->name, "bool") || + strEqu(method_store->name, "float") || + strEqu(method_store->name, "str") || + strEqu(method_store->name, "bytes") || + strEqu(method_store->name, "list") || + strEqu(method_store->name, "dict") || + strEqu(method_store->name, "tuple")) { + pika_platform_snprintf(buff, PIKA_SPRINTF_BUFF_SIZE, + "", method_store->name); + } + return arg_newStr(buff); } - pika_platform_printf("%s%s", arg_getStr(self), end); + pika_platform_snprintf(buff, PIKA_SPRINTF_BUFF_SIZE, + ""); + return arg_newStr(buff); + } + if (type == ARG_TYPE_NONE) { + return arg_newStr("None"); + } + if (argType_isObject(type)) { + return arg_newStr(obj_toStr(arg_getPtr(arg))); + } + if (type == ARG_TYPE_OBJECT_META) { + pika_platform_snprintf(buff, PIKA_SPRINTF_BUFF_SIZE, + "", arg_getPtr(arg)); + return arg_newStr(buff); + } + return NULL; +} + +void arg_print(Arg* self, PIKA_BOOL in_REPL, char* end) { + /* use arg_toStrArg() */ + Arg* str_arg = arg_toStrArg(self); + if (NULL == str_arg) { return; } - if (type == ARG_TYPE_BYTES) { - arg_printBytes(self, end); - return; - } - if (ARG_TYPE_POINTER == type || ARG_TYPE_METHOD_NATIVE_CONSTRUCTOR) { - pika_platform_printf("%p%s", arg_getPtr(self), end); - return; + if (in_REPL && arg_getType(self) == ARG_TYPE_STRING) { + pika_platform_printf("'%s'%s", arg_getStr(str_arg), end); + } else { + pika_platform_printf("%s%s", arg_getStr(str_arg), end); } + arg_deinit(str_arg); return; } @@ -370,6 +402,10 @@ Arg* arg_setInt(Arg* self, char* name, int64_t val) { return arg_set(self, name, ARG_TYPE_INT, (uint8_t*)&val, sizeof(val)); } +Arg* arg_setBool(Arg* self, char* name, PIKA_BOOL val) { + return arg_set(self, name, ARG_TYPE_BOOL, (uint8_t*)&val, sizeof(val)); +} + Arg* arg_setNull(Arg* self) { return arg_set(self, "", ARG_TYPE_NONE, NULL, 0); } @@ -401,11 +437,19 @@ Arg* arg_setStr(Arg* self, char* name, char* string) { int64_t arg_getInt(Arg* self) { pika_assert(NULL != self); if (NULL == arg_getContent(self)) { - return -999999; + return _PIKA_INT_ERR; } return *(int64_t*)arg_getContent(self); } +PIKA_BOOL arg_getBool(Arg* self) { + pika_assert(NULL != self); + if (NULL == arg_getContent(self)) { + return _PIKA_BOOL_ERR; + } + return *(PIKA_BOOL*)arg_getContent(self); +} + void* arg_getPtr(Arg* self) { if (arg_getType(self) == ARG_TYPE_NONE) { return NULL; @@ -427,15 +471,24 @@ Arg* New_arg(void* voidPointer) { return NULL; } +static void _arg_refcnt_fix(Arg* self) { + ArgType arg_type = arg_getType(self); + if (ARG_TYPE_OBJECT == arg_type) { + obj_refcntInc((PikaObj*)arg_getPtr(self)); + } + // if (ARG_TYPE_METHOD_OBJECT == arg_type) { + // if (NULL != methodArg_getHostObj(self)) { + // obj_refcntInc((PikaObj*)arg_getPtr(self)); + // } + // } +} + Arg* arg_copy(Arg* arg_src) { if (NULL == arg_src) { return NULL; } pika_assert(arg_src->flag < ARG_FLAG_MAX); - ArgType arg_type = arg_getType(arg_src); - if (ARG_TYPE_OBJECT == arg_type) { - obj_refcntInc((PikaObj*)arg_getPtr(arg_src)); - } + _arg_refcnt_fix(arg_src); Arg* arg_dict = New_arg(NULL); arg_dict = arg_setContent(arg_dict, arg_getContent(arg_src), arg_getContentSize(arg_src)); @@ -457,10 +510,7 @@ Arg* arg_copy_noalloc(Arg* arg_src, Arg* arg_dict) { if (arg_getSize(arg_src) > arg_getSize(arg_dict)) { return arg_copy(arg_src); } - ArgType arg_type = arg_getType(arg_src); - if (ARG_TYPE_OBJECT == arg_type) { - obj_refcntInc((PikaObj*)arg_getPtr(arg_src)); - } + _arg_refcnt_fix(arg_src); arg_setSerialized(arg_dict, PIKA_FALSE); arg_dict = arg_setContent(arg_dict, arg_getContent(arg_src), arg_getContentSize(arg_src)); @@ -497,7 +547,7 @@ Arg* arg_append(Arg* self, void* new_content, size_t new_size) { } /* copy new content */ pika_platform_memcpy(arg_getContent(new_arg) + old_size, new_content, - new_size); + new_size); if (self != new_arg) { arg_deinit(self); } @@ -524,13 +574,15 @@ void arg_deinitHeap(Arg* self) { /* deinit sub object */ if (ARG_TYPE_OBJECT == type) { PikaObj* subObj = arg_getPtr(self); - obj_refcntDec(subObj); - int ref_cnt = obj_refcntNow(subObj); - if (ref_cnt <= 0) { - obj_deinit(subObj); - } + obj_GC(subObj); return; } + // if (ARG_TYPE_METHOD_OBJECT == type) { + // PikaObj* hostObj = methodArg_getHostObj(self); + // if (NULL != hostObj) { + // obj_GC(hostObj); + // } + // } } /* load file as byte array */ @@ -592,7 +644,7 @@ PIKA_BOOL arg_isEqual(Arg* self, Arg* other) { } } if (0 != pika_platform_memcmp(arg_getContent(self), arg_getContent(other), - arg_getContentSize(self))) { + arg_getContentSize(self))) { return PIKA_FALSE; } return PIKA_TRUE; diff --git a/examples/pikapython/pikapython/pikascript-core/dataArg.h b/examples/pikapython/pikapython/pikascript-core/dataArg.h index c3d4c167..67c363ec 100644 --- a/examples/pikapython/pikapython/pikascript-core/dataArg.h +++ b/examples/pikapython/pikapython/pikascript-core/dataArg.h @@ -1,4 +1,4 @@ -/* +/* * This file is part of the PikaScript project. * http://github.com/pikastech/pikascript * @@ -36,6 +36,7 @@ typedef enum { ARG_TYPE_UNDEF = 0, ARG_TYPE_NONE, ARG_TYPE_INT, + ARG_TYPE_BOOL, ARG_TYPE_FLOAT, ARG_TYPE_STRING, ARG_TYPE_BYTES, @@ -100,10 +101,12 @@ static inline void arg_setType(Arg* self, ArgType type) { } static inline Hash arg_getNameHash(Arg* self) { + pika_assert(self != 0); return self->name_hash; } static inline ArgType arg_getType(Arg* self) { + pika_assert(self != 0); return (ArgType)self->type; } @@ -111,6 +114,7 @@ uint32_t arg_getContentSize(Arg* self); Hash hash_time33(char* str); Arg* arg_setInt(Arg* self, char* name, int64_t val); +Arg* arg_setBool(Arg* self, char* name, PIKA_BOOL val); Arg* arg_setFloat(Arg* self, char* name, pika_float val); Arg* arg_setPtr(Arg* self, char* name, ArgType type, void* pointer); Arg* arg_setStr(Arg* self, char* name, char* string); @@ -118,19 +122,23 @@ Arg* arg_setNull(Arg* self); Arg* arg_setBytes(Arg* self, char* name, uint8_t* src, size_t size); static inline Arg* arg_newInt(int64_t val) { - return arg_setInt(NULL, "", (val)); + return arg_setInt(NULL, (char*)"", (val)); +} + +static inline Arg* arg_newBool(PIKA_BOOL val) { + return arg_setBool(NULL, (char*)"", (val)); } static inline Arg* arg_newFloat(pika_float val) { - return arg_setFloat(NULL, "", (val)); + return arg_setFloat(NULL, (char*)"", (val)); } static inline Arg* arg_newPtr(ArgType type, void* pointer) { - return arg_setPtr(NULL, "", (type), (pointer)); + return arg_setPtr(NULL, (char*)"", (type), (pointer)); } static inline Arg* arg_newStr(char* string) { - return arg_setStr(NULL, "", (string)); + return arg_setStr(NULL, (char*)"", (string)); } static inline Arg* arg_newNull() { @@ -138,10 +146,11 @@ static inline Arg* arg_newNull() { } static inline Arg* arg_newBytes(uint8_t* src, size_t size) { - return arg_setBytes(NULL, "", (src), (size)); + return arg_setBytes(NULL, (char*)"", (src), (size)); } int64_t arg_getInt(Arg* self); +PIKA_BOOL arg_getBool(Arg* self); pika_float arg_getFloat(Arg* self); void* arg_getPtr(Arg* self); char* arg_getStr(Arg* self); @@ -165,8 +174,8 @@ Arg* arg_setHeapStruct(Arg* self, void* struct_deinit_fun); void* arg_getHeapStruct(Arg* self); void arg_deinitHeap(Arg* self); -void arg_printBytes(Arg* self, char* end); -void arg_singlePrint(Arg* self, PIKA_BOOL in_REPL, char* end); +Arg* arg_toStrArg(Arg* arg); +void arg_print(Arg* self, PIKA_BOOL in_REPL, char* end); Arg* arg_loadFile(Arg* self, char* filename); #define ARG_FLAG_SERIALIZED 0x01 diff --git a/examples/pikapython/pikapython/pikascript-core/dataArgs.c b/examples/pikapython/pikapython/pikascript-core/dataArgs.c index 64585c41..72476254 100644 --- a/examples/pikapython/pikapython/pikascript-core/dataArgs.c +++ b/examples/pikapython/pikapython/pikascript-core/dataArgs.c @@ -188,15 +188,29 @@ PIKA_RES args_setInt(Args* self, char* name, int64_t val) { int64_t args_getInt(Args* self, char* name) { Arg* arg = args_getArg(self, name); if (NULL == arg) { - return -999999999; + return _PIKA_INT_ERR; } ArgType arg_type = arg_getType(arg); if (arg_type == ARG_TYPE_INT) { return arg_getInt(arg); } else if (arg_type == ARG_TYPE_FLOAT) { return (int)arg_getFloat(arg); + } else if (arg_type == ARG_TYPE_BOOL) { + return arg_getBool(arg); } - return -999999999; + return _PIKA_INT_ERR; +} + +PIKA_BOOL args_getBool(Args* self, char* name) { + Arg* arg = args_getArg(self, name); + if (NULL == arg) { + return _PIKA_BOOL_ERR; + } + ArgType arg_type = arg_getType(arg); + if (arg_type == ARG_TYPE_BOOL) { + return arg_getBool(arg); + } + return _PIKA_BOOL_ERR; } int32_t args_getSize(Args* self) { @@ -215,7 +229,7 @@ ArgType args_getType(Args* self, char* name) { pika_float args_getFloat(Args* self, char* name) { Arg* arg = args_getArg(self, name); if (NULL == arg) { - return -999999999.0; + return _PIKA_FLOAT_ERR; } ArgType arg_type = arg_getType(arg); if (arg_type == ARG_TYPE_FLOAT) { @@ -223,7 +237,7 @@ pika_float args_getFloat(Args* self, char* name) { } else if (arg_type == ARG_TYPE_INT) { return (pika_float)arg_getInt(arg); } - return -999999999.0; + return _PIKA_FLOAT_ERR; } PIKA_RES args_copyArg(Args* self, Arg* argToBeCopy) { @@ -298,6 +312,8 @@ int32_t args_isArgExist(Args* self, char* name) { } PIKA_RES __updateArg(Args* self, Arg* argNew) { + pika_assert(NULL != self); + pika_assert(NULL != argNew); LinkNode* nodeToUpdate = NULL; LinkNode* nodeNow = self->firstNode; LinkNode* priorNode = NULL; @@ -345,6 +361,8 @@ exit: } PIKA_RES args_setArg(Args* self, Arg* arg) { + pika_assert(NULL != self); + pika_assert(NULL != arg); if (PIKA_RES_OK == __updateArg(self, arg)) { return PIKA_RES_OK; } diff --git a/examples/pikapython/pikapython/pikascript-core/dataArgs.h b/examples/pikapython/pikapython/pikascript-core/dataArgs.h index 7239f955..36683939 100644 --- a/examples/pikapython/pikapython/pikascript-core/dataArgs.h +++ b/examples/pikapython/pikapython/pikascript-core/dataArgs.h @@ -71,6 +71,7 @@ void* args_getPtr(Args* self, char* name); PIKA_RES args_setInt(Args* self, char* name, int64_t int64In); int64_t args_getInt(Args* self, char* name); +PIKA_BOOL args_getBool(Args* self, char* name); char* args_print(Args* self, char* name); diff --git a/examples/pikapython/pikapython/pikascript-core/dataMemory.h b/examples/pikapython/pikapython/pikascript-core/dataMemory.h index 449bc32b..fda21859 100644 --- a/examples/pikapython/pikapython/pikascript-core/dataMemory.h +++ b/examples/pikapython/pikapython/pikascript-core/dataMemory.h @@ -31,7 +31,7 @@ #include "PikaPlatform.h" #include "PikaVersion.h" -/*! \NOTE: Make sure #include "plooc_class.h" is close to the class definition +/*! \NOTE: Make sure #include "__pika_ooc.h" is close to the class definition */ #if defined(__DATA_MEMORY_CLASS_IMPLEMENT__) #define __PLOOC_CLASS_IMPLEMENT__ diff --git a/examples/pikapython/pikapython/pikascript-core/dataQueue.c b/examples/pikapython/pikapython/pikascript-core/dataQueue.c index 87a0cd49..88d72093 100644 --- a/examples/pikapython/pikapython/pikascript-core/dataQueue.c +++ b/examples/pikapython/pikapython/pikascript-core/dataQueue.c @@ -5,6 +5,7 @@ * MIT License * * Copyright (c) 2021 lyon 李昂 liang6516@outlook.com + * Copyright (c) 2023 Gorgon Meducer embedded_zhuroan@hotmail.com * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -24,7 +25,7 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ - +#define __DATA_QUEUE_CLASS_IMPLEMENT__ #include "dataQueue.h" #include "PikaPlatform.h" #include "dataArgs.h" @@ -94,3 +95,132 @@ int32_t queue_pushStr(Queue* queue, char* str) { char* queue_popStr(Queue* queue) { return arg_getStr(__queue_popArg_noRmoveArg(queue)); } + +ByteQueue* byteQueue_init(ByteQueue* queue, + void* buffer, + uint_fast16_t size, + PIKA_BOOL is_queue_full) { + pika_assert(NULL != queue); + pika_assert(NULL != buffer); + pika_assert(size > 0); + + pika_platform_memset(queue, 0, sizeof(ByteQueue)); + + queue->buffer = buffer; + queue->buffer_size = size; + if (is_queue_full) { + queue->count = size; + queue->peek_count = size; + } + + return queue; +} + +PIKA_BOOL byteQueue_readOne(ByteQueue* queue, uint8_t* byte_ptr) { + pika_assert(NULL != queue); + uint8_t byte; + PIKA_BOOL result = PIKA_FALSE; + + /* ------------------atomicity sensitive start---------------- */ + do { + if ((queue->head == queue->tail) && (0 == queue->count)) { + /* empty */ + break; + } + + byte = queue->buffer[queue->head++]; + queue->count--; + if (queue->head >= queue->buffer_size) { + queue->head = 0; + } + + /* reset peek */ + queue->peek_count = queue->count; + queue->peek = queue->head; + + if (NULL != byte_ptr) { + *byte_ptr = byte; + } + result = PIKA_TRUE; + } while (0); + /* ------------------atomicity sensitive end ---------------- */ + + return result; +} + +PIKA_BOOL byteQueue_peekOne(ByteQueue* queue, uint8_t* byte_ptr) { + pika_assert(NULL != queue); + uint8_t byte; + PIKA_BOOL result = PIKA_FALSE; + + /* ------------------atomicity sensitive start---------------- */ + do { + if ((queue->peek == queue->tail) && (0 == queue->peek_count)) { + /* empty */ + break; + } + + byte = queue->buffer[queue->peek++]; + queue->peek_count--; + if (queue->peek >= queue->buffer_size) { + queue->peek = 0; + } + + if (NULL != byte_ptr) { + *byte_ptr = byte; + } + result = PIKA_TRUE; + } while (0); + /* ------------------atomicity sensitive end ---------------- */ + + return result; +} + +void byteQueue_resetPeek(ByteQueue* queue) { + pika_assert(NULL != queue); + /* ------------------atomicity sensitive start---------------- */ + queue->peek_count = queue->count; + queue->peek = queue->head; + /* ------------------atomicity sensitive end ---------------- */ +} + +uint_fast16_t byteQueue_getPeekedNumber(ByteQueue* queue) { + return queue->count - queue->peek_count; +} + +uint_fast16_t byteQueue_peekAvailableCount(ByteQueue* queue) { + return queue->peek_count; +} + +void byteQueue_dropAllPeeked(ByteQueue* queue) { + pika_assert(NULL != queue); + /* ------------------atomicity sensitive start---------------- */ + queue->count = queue->peek_count; + queue->head = queue->peek; + /* ------------------atomicity sensitive end ---------------- */ +} + +PIKA_BOOL byteQueue_writeOne(ByteQueue* queue, uint8_t byte) { + pika_assert(NULL != queue); + PIKA_BOOL result = PIKA_FALSE; + + /* ------------------atomicity sensitive start---------------- */ + do { + if ((queue->head == queue->tail) && (0 != queue->count)) { + /* full */ + break; + } + + queue->buffer[queue->tail++] = byte; + queue->count++; + queue->peek_count++; + if (queue->tail >= queue->buffer_size) { + queue->tail = 0; + } + + result = PIKA_TRUE; + } while (0); + /* ------------------atomicity sensitive end ---------------- */ + + return result; +} diff --git a/examples/pikapython/pikapython/pikascript-core/dataQueue.h b/examples/pikapython/pikapython/pikascript-core/dataQueue.h index c32d1728..28ad28c9 100644 --- a/examples/pikapython/pikapython/pikascript-core/dataQueue.h +++ b/examples/pikapython/pikapython/pikascript-core/dataQueue.h @@ -5,6 +5,7 @@ * MIT License * * Copyright (c) 2021 lyon 李昂 liang6516@outlook.com + * Copyright (c) 2023 Gorgon Meducer embedded_zhuroan@hotmail.comByte * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -29,6 +30,29 @@ #define __DATA_QUEUE__H #include "dataArgs.h" +/*! \NOTE: Make sure #include "__pika_ooc.h" is close to the class definition + */ +#if defined(__DATA_QUEUE_CLASS_IMPLEMENT__) + #define __PLOOC_CLASS_IMPLEMENT__ + #undef __DATA_QUEUE_CLASS_IMPLEMENT__ +#endif +#include "__pika_ooc.h" + +typedef struct ByteQueue ByteQueue; +struct ByteQueue { +private_member( + uint8_t *buffer; + uint16_t buffer_size; + + uint16_t head; + uint16_t tail; + uint16_t peek; + + uint16_t count; + uint16_t peek_count; +) +}; + typedef Args Queue; Queue* New_queue(void); @@ -46,4 +70,17 @@ Arg* queue_popArg(Queue* queue); Arg* queue_popArg_notDeinitArg(Queue* queue); int32_t queue_deinit_stack(Queue* queue); void queue_init(Queue* queue); + +ByteQueue *byteQueue_init( ByteQueue *queue, + void *buffer, + uint_fast16_t size, + PIKA_BOOL is_queue_full); +PIKA_BOOL byteQueue_readOne(ByteQueue *queue, uint8_t *byte_ptr); +PIKA_BOOL byteQueue_peekOne(ByteQueue *queue, uint8_t *byte_ptr); +void byteQueue_resetPeek(ByteQueue *queue); +void byteQueue_dropAllPeeked(ByteQueue *queue); +uint_fast16_t byteQueue_getPeekedNumber(ByteQueue *queue); +uint_fast16_t byteQueue_peekAvailableCount(ByteQueue *queue); +PIKA_BOOL byteQueue_writeOne(ByteQueue *queue, uint8_t byte); + #endif diff --git a/examples/pikapython/pikapython/pikascript-core/dataString.c b/examples/pikapython/pikapython/pikascript-core/dataString.c index 206e2bce..f44874ac 100644 --- a/examples/pikapython/pikapython/pikascript-core/dataString.c +++ b/examples/pikapython/pikapython/pikascript-core/dataString.c @@ -27,6 +27,7 @@ #include "dataString.h" #include "PikaPlatform.h" +#include "dataMemory.h" char* strCut(char* strOut, char* strIn, char startSign, char endSign) { int32_t Size = strGetSize(strIn); @@ -280,3 +281,97 @@ char* strGetLastLine(char* strOut, char* strIn) { strOut[size - beginIndex + 1] = 0; return strOut; } + +int strPathFormat(char* input, char* output) { + int len = strlen(input); + int i = 0; + int j = 0; + for (i = 0; i < len; i++) { + if (input[i] == '\\') { + output[j++] = '/'; + } else { + output[j++] = input[i]; + } + } + output[j] = '\0'; + return j; +} + +int strPathJoin(char* input1, char* input2, char* output) { + /* format */ + size_t input1_len = strlen(input1); + size_t input2_len = strlen(input2); + /* if input1 is all space */ + if (input1_len == 0) { + strPathFormat(input2, output); + return 0; + } + char* input1_format = (char*)pikaMalloc(input1_len + 1); + char* input2_format = (char*)pikaMalloc(input2_len + 1); + strPathFormat(input1, input1_format); + strPathFormat(input2, input2_format); + /* join */ + int len1 = strlen(input1_format); + int len2 = strlen(input2_format); + int i = 0; + int j = 0; + for (i = 0; i < len1; i++) { + output[j++] = input1_format[i]; + } + if (input1_format[len1 - 1] != '/') { + output[j++] = '/'; + } + if (input2_format[0] == '/') { + i = 1; + } else { + i = 0; + } + for (; i < len2; i++) { + output[j++] = input2_format[i]; + } + output[j] = '\0'; + /* free */ + pikaFree(input1_format, input1_len + 1); + pikaFree(input2_format, input2_len + 1); + return j; +} + +int strPathGetFolder(char* input, char* output) { + size_t input_len = strlen(input); + char* input_format = (char*)pikaMalloc(input_len + 1); + strPathFormat(input, input_format); + int len = strlen(input_format); + int i = 0; + int j = 0; + for (i = 0; i < len; i++) { + if (input_format[i] == '/') { + j = i; + } + } + for (i = 0; i < j; i++) { + output[i] = input_format[i]; + } + output[i] = '\0'; + pikaFree(input_format, input_len + 1); + return i; +} + +int strPathGetFileName(char* input, char* output) { + size_t input_len = strlen(input); + char* input_format = (char*)pikaMalloc(input_len + 1); + strPathFormat(input, input_format); + int len = strlen(input_format); + int i = 0; + int j = 0; + for (i = 0; i < len; i++) { + if (input_format[i] == '/') { + j = i; + } + } + for (i = j + 1; i < len; i++) { + output[i - j - 1] = input_format[i]; + } + output[i - j - 1] = '\0'; + pikaFree(input_format, input_len + 1); + return i - j - 1; +} diff --git a/examples/pikapython/pikapython/pikascript-core/dataString.h b/examples/pikapython/pikapython/pikascript-core/dataString.h index d64984a2..38dfeedf 100644 --- a/examples/pikapython/pikapython/pikascript-core/dataString.h +++ b/examples/pikapython/pikapython/pikascript-core/dataString.h @@ -63,4 +63,9 @@ char* strPopLastToken(char* strIn, char sign); char* strGetLastLine(char* strOut, char* strIn); char* strReplaceChar(char* strIn, char src, char dst); +int strPathFormat(char* input, char* output); +int strPathJoin(char* input1, char* input2, char* output); +int strPathGetFolder(char* input, char* output); +int strPathGetFileName(char* input, char* output); + #endif diff --git a/examples/pikapython/pikapython/pikascript-core/dataStrs.c b/examples/pikapython/pikapython/pikascript-core/dataStrs.c index 3f940380..e2ea2bd2 100644 --- a/examples/pikapython/pikapython/pikascript-core/dataStrs.c +++ b/examples/pikapython/pikapython/pikascript-core/dataStrs.c @@ -200,3 +200,31 @@ char* strsGetLine(Args* buffs_p, char* code) { void strsDeinit(Args* buffs_p) { link_deinit_stack(buffs_p); } + +char* strsPathFormat(Args* buffs_p, char* input) { + int32_t size = strGetSize(input); + char* buff = args_getBuff(buffs_p, size); + strPathFormat(input, buff); + return buff; +} + +char* strsPathJoin(Args* buffs_p, char* input1, char* input2) { + int32_t size = strGetSize(input1) + strGetSize(input2) + 1; + char* buff = args_getBuff(buffs_p, size); + strPathJoin(input1, input2, buff); + return buff; +} + +char* strsPathGetFolder(Args* buffs_p, char* input) { + int32_t size = strGetSize(input); + char* buff = args_getBuff(buffs_p, size); + strPathGetFolder(input, buff); + return buff; +} + +char* strsPathGetFileName(Args* buffs_p, char* input) { + int32_t size = strGetSize(input); + char* buff = args_getBuff(buffs_p, size); + strPathGetFileName(input, buff); + return buff; +} diff --git a/examples/pikapython/pikapython/pikascript-core/dataStrs.h b/examples/pikapython/pikapython/pikascript-core/dataStrs.h index 1e2404a6..3d1bdb97 100644 --- a/examples/pikapython/pikapython/pikascript-core/dataStrs.h +++ b/examples/pikapython/pikapython/pikascript-core/dataStrs.h @@ -45,4 +45,10 @@ char* strsGetLine(Args* buffs, char* code); void strsDeinit(Args* buffs); char* strsCacheArg(Args* buffs_p, Arg* arg); char* strsReturnOut(Args* buffs, Args* outbuffs, char* str); + +char* strsPathGetFileName(Args* buffs_p, char* input); +char* strsPathGetFolder(Args* buffs_p, char* input); +char* strsPathJoin(Args* buffs_p, char* input1, char* input2); +char* strsPathFormat(Args* buffs_p, char* input); + #endif diff --git a/examples/pikapython/pikapython/pikascript-core/pika_adapter_old_api.h b/examples/pikapython/pikapython/pikascript-core/pika_adapter_old_api.h index bf76fcd7..642d4888 100644 --- a/examples/pikapython/pikapython/pikascript-core/pika_adapter_old_api.h +++ b/examples/pikapython/pikapython/pikascript-core/pika_adapter_old_api.h @@ -39,7 +39,8 @@ #define __platform_error_handle pika_platform_error_handle #define __platform_panic_handle pika_platform_panic_handle #define __platform_thread_delay pika_platform_thread_delay -#define __platform_getTick pika_platform_getTick +#define __platform_getTick pika_platform_get_tick +#define pika_platform_getTick pika_platform_get_tick #define __platform_sleep_ms pika_platform_sleep_ms #define __platform_sleep_s pika_platform_sleep_s @@ -72,6 +73,13 @@ #define pks_eventLisener_deinit pks_eventListener_deinit #define pks_eventLicener_removeEvent pks_eventListener_removeEvent +#define pika_platform_timer_init pika_platform_thread_timer_init +#define pika_platform_timer_cutdown pika_platform_thread_timer_cutdown +#define pika_platform_timer_is_expired pika_platform_thread_timer_is_expired +#define pika_platform_timer_remain pika_platform_thread_timer_remain +#define pika_platform_timer_now pika_platform_thread_timer_now +#define pika_platform_timer_usleep pika_platform_thread_timer_usleep + #endif #endif diff --git a/examples/pikapython/pikapython/pikascript-core/pika_config_valid.h b/examples/pikapython/pikapython/pikascript-core/pika_config_valid.h index cb380317..7ce1862c 100644 --- a/examples/pikapython/pikapython/pikascript-core/pika_config_valid.h +++ b/examples/pikapython/pikapython/pikascript-core/pika_config_valid.h @@ -65,11 +65,14 @@ #define PIKA_SYNTAX_LEVEL PIKA_SYNTAX_LEVEL_MINIMAL #endif - #ifndef PIKA_STRING_UTF8_ENABLE #define PIKA_STRING_UTF8_ENABLE 0 #endif + #ifndef PIKA_SHELL_FILTER_ENABLE + #define PIKA_SHELL_FILTER_ENABLE 0 + #endif + #endif /* default optimize */ @@ -328,8 +331,32 @@ #define PIKA_SHELL_SAVE_FILE_ENABLE 0 #endif - #ifndef PIKA_SHELL_SAVE_FILE_NAME - #define PIKA_SHELL_SAVE_FILE_NAME "pika_shell_save.py" + #ifndef PIKA_SHELL_SAVE_FILE_PATH + #define PIKA_SHELL_SAVE_FILE_PATH "app.py" + #endif + + #ifndef PIKA_SHELL_SAVE_BYTECODE_ENABLE + #define PIKA_SHELL_SAVE_BYTECODE_ENABLE 0 + #endif + + #ifndef PIKA_SHELL_SAVE_BYTECODE_PATH + #define PIKA_SHELL_SAVE_BYTECODE_PATH "app.py.o" + #endif + + #ifndef PIKA_SHELL_SAVE_APP_ENABLE + #define PIKA_SHELL_SAVE_APP_ENABLE 0 + #endif + + #ifndef PIKA_SHELL_SAVE_APP_PATH + #define PIKA_SHELL_SAVE_APP_PATH "app.pika" + #endif + + #ifndef PIKA_SHELL_FILTER_ENABLE + #define PIKA_SHELL_FILTER_ENABLE 1 + #endif + + #ifndef PIKA_SHELL_FILTER_FIFO_SIZE + #define PIKA_SHELL_FILTER_FIFO_SIZE 32 #endif #ifndef PIKA_EVENT_LIST_SIZE @@ -352,6 +379,30 @@ #define PIKA_LWIP_ENABLE 0 #endif + #ifndef PIKA_SHELL_NO_NEWLINE + #define PIKA_SHELL_NO_NEWLINE 0 + #endif + + #ifndef PIKA_SETJMP_ENABLE + #define PIKA_SETJMP_ENABLE 0 + #endif + + #ifndef PIKA_JMP_BUF_LIST_SIZE + #define PIKA_JMP_BUF_LIST_SIZE 16 + #endif + + #ifndef PIKA_THREAD_STACK_SIZE + #define PIKA_THREAD_STACK_SIZE 2048 + #endif + + #ifndef PIKA_THREAD_PRIO + #define PIKA_THREAD_PRIO 5 + #endif + + #ifndef PIKA_THREAD_TICK + #define PIKA_THREAD_TICK 50 + #endif + /* configuration validation */ #endif diff --git a/examples/pikapython/pikapython/pikascript-lib/BLMCU/pika_hal_BLMCU_ADC.c b/examples/pikapython/pikapython/pikascript-lib/BLMCU/pika_hal_BLMCU_ADC.c new file mode 100644 index 00000000..4ae1f376 --- /dev/null +++ b/examples/pikapython/pikapython/pikascript-lib/BLMCU/pika_hal_BLMCU_ADC.c @@ -0,0 +1,147 @@ +#include "../PikaStdDevice/pika_hal.h" +#include "bflb_adc.h" + +static int8_t _pin2ch(uint32_t pin) { + switch (pin) { + case 0: + return ADC_CHANNEL_9; + case 1: + return ADC_CHANNEL_8; + case 2: + return ADC_CHANNEL_2; + case 3: + return ADC_CHANNEL_3; + case 10: + return ADC_CHANNEL_7; + case 12: + return ADC_CHANNEL_6; + case 13: + return ADC_CHANNEL_5; + case 14: + return ADC_CHANNEL_4; + case 19: + return ADC_CHANNEL_1; + case 20: + return ADC_CHANNEL_0; + case 27: + return ADC_CHANNEL_10; + case 28: + return ADC_CHANNEL_11; + default: + return -1; + } +} + +typedef struct platform_adc_t { + struct bflb_device_s* device; + struct bflb_adc_config_s config; + struct bflb_adc_channel_s channel; +} platform_adc_t; + +int pika_hal_platform_ADC_open(pika_dev* dev, char* name) { + /* Support P1/P2 ... */ + if (name[0] == 'P') { + int8_t ch = _pin2ch(fast_atoi(name + 1)); + if (ch < 0) { + pika_platform_printf("ADC channel not support: %s \r\n", name); + return -1; + } + platform_adc_t* platform_adc = + (platform_adc_t*)pikaMalloc(sizeof(platform_adc_t)); + memset(platform_adc, 0, sizeof(platform_adc_t)); + dev->platform_data = platform_adc; + platform_adc->channel.pos_chan = ch; + platform_adc->channel.neg_chan = ADC_CHANNEL_GND; + return 0; + } + return -1; +} + +int pika_hal_platform_ADC_close(pika_dev* dev) { + platform_adc_t* platform_adc = (platform_adc_t*)dev->platform_data; + if (NULL != platform_adc) { + pikaFree(platform_adc, sizeof(platform_adc_t)); + dev->platform_data = NULL; + } + return 0; +} + +int pika_hal_platform_ADC_ioctl_config(pika_dev* dev, + pika_hal_ADC_config* cfg) { + platform_adc_t* platform_adc = (platform_adc_t*)dev->platform_data; + platform_adc->config.clk_div = ADC_CLK_DIV_32; + platform_adc->config.scan_conv_mode = true; + platform_adc->config.vref = ADC_VREF_3P2V; + switch (cfg->continue_or_single) { + case PIKA_HAL_ADC_CONTINUOU: + platform_adc->config.continuous_conv_mode = true; + break; + case PIKA_HAL_ADC_SINGLE: + platform_adc->config.continuous_conv_mode = false; + break; + default: + platform_adc->config.continuous_conv_mode = false; + break; + } + switch (cfg->sampling_resolution) { + case PIKA_HAL_ADC_RESOLUTION_12: + platform_adc->config.resolution = ADC_RESOLUTION_12B; + break; + case PIKA_HAL_ADC_RESOLUTION_14: + platform_adc->config.resolution = ADC_RESOLUTION_14B; + break; + case PIKA_HAL_ADC_RESOLUTION_16: + platform_adc->config.resolution = ADC_RESOLUTION_16B; + break; + default: + platform_adc->config.resolution = ADC_RESOLUTION_16B; + break; + } + cfg->max = 3200; + cfg->vref = (pika_float)3.3; + return 0; +} + +int pika_hal_platform_ADC_read(pika_dev* dev, void* buf, size_t count) { + int ret = 0; + platform_adc_t* platform_adc = (platform_adc_t*)dev->platform_data; + bflb_adc_start_conversion(platform_adc->device); + while (bflb_adc_get_count(platform_adc->device) < 1) { + bflb_mtimer_delay_ms(1); + } + uint32_t raw_data = bflb_adc_read_raw(platform_adc->device); + bflb_adc_stop_conversion(platform_adc->device); + struct bflb_adc_result_s result; + bflb_adc_parse_result(platform_adc->device, &raw_data, &result, 1); + ret = result.millivolt; + if (ret < 0) { + return ret; + } + *(uint32_t*)buf = ret; + return 0; +} + +int pika_hal_platform_ADC_write(pika_dev* dev, void* buf, size_t count) { + /* Not support */ + return -1; +} + +int pika_hal_platform_ADC_ioctl_enable(pika_dev* dev) { + platform_adc_t* platform_adc = (platform_adc_t*)dev->platform_data; + if (!dev->is_enabled) { + bflb_adc_init(platform_adc->device, &platform_adc->config); + bflb_adc_channel_config(platform_adc->device, &platform_adc->channel, + 1); + return 0; + } + return -1; +} + +int pika_hal_platform_ADC_ioctl_disable(pika_dev* dev) { + platform_adc_t* platform_adc = (platform_adc_t*)dev->platform_data; + if (dev->is_enabled) { + bflb_adc_deinit(platform_adc->device); + return 0; + } + return -1; +} diff --git a/examples/pikapython/pikapython/pikascript-lib/BLMCU/pika_hal_BLMCU_DAC.c b/examples/pikapython/pikapython/pikascript-lib/BLMCU/pika_hal_BLMCU_DAC.c new file mode 100644 index 00000000..91422922 --- /dev/null +++ b/examples/pikapython/pikapython/pikascript-lib/BLMCU/pika_hal_BLMCU_DAC.c @@ -0,0 +1,80 @@ +#include "../PikaStdDevice/pika_hal.h" +#include "bflb_dac.h" + +static int8_t _pin2ch(uint32_t pin) { + switch (pin) { + case 3: + return DAC_CHANNEL_A; + default: + return -1; + } +} + +typedef struct platform_dac_t { + struct bflb_device_s* device; + uint8_t channel; + uint8_t clk_div; +} platform_dac_t; + +int pika_hal_platform_DAC_open(pika_dev* dev, char* name) { + /* Support P1/P2 ... */ + if (name[0] == 'P') { + int pin = fast_atoi(name + 1); + int8_t ch = _pin2ch(pin); + if (ch < 0) { + pika_platform_printf("DAC channel not support: %s \r\n", name); + return -1; + } + platform_dac_t* platform_dac = pikaMalloc(sizeof(platform_dac_t)); + memset(platform_dac, 0, sizeof(platform_dac_t)); + dev->platform_data = platform_dac; + platform_dac->device = bflb_device_get_by_name("dac"); + platform_dac->channel = ch; + return 0; + } + return -1; +} + +int pika_hal_platform_DAC_close(pika_dev* dev) { + if (dev->platform_data) { + pikaFree(dev->platform_data, sizeof(platform_dac_t)); + dev->platform_data = NULL; + } + return 0; +} + +int pika_hal_platform_DAC_ioctl_config(pika_dev* dev, + pika_hal_DAC_config* cfg) { + platform_dac_t* platform_dac = (platform_dac_t*)dev->platform_data; + platform_dac->clk_div = DAC_CLK_DIV_16; + cfg->max = 3300000; + cfg->vref = (pika_float)3.3; + return 0; +} + +int pika_hal_platform_DAC_ioctl_enable(pika_dev* dev) { + platform_dac_t* platform_dac = (platform_dac_t*)dev->platform_data; + if (!dev->is_enabled) { + bflb_dac_init(platform_dac->device, platform_dac->clk_div); + bflb_dac_channel_enable(platform_dac->device, platform_dac->channel); + return 0; + } + return -1; +} + +int pika_hal_platform_DAC_read(pika_dev* dev, void* buf, size_t count) { + return -1; +} + +int pika_hal_platform_DAC_write(pika_dev* dev, void* buf, size_t count) { + platform_dac_t* platform_dac = (platform_dac_t*)dev->platform_data; + uint32_t value = *(uint32_t*)buf; + bflb_dac_set_value(platform_dac->device, platform_dac->channel, value); + return 0; +} + +int pika_hal_platform_DAC_ioctl_disable(pika_dev* dev) { + platform_dac_t* platform_dac = (platform_dac_t*)dev->platform_data; + bflb_dac_channel_disable(platform_dac->device, platform_dac->channel); + return 0; +} diff --git a/examples/pikapython/pikapython/pikascript-lib/BLMCU/pika_hal_BLMCU_GPIO.c b/examples/pikapython/pikapython/pikascript-lib/BLMCU/pika_hal_BLMCU_GPIO.c new file mode 100755 index 00000000..bdfd65e0 --- /dev/null +++ b/examples/pikapython/pikapython/pikascript-lib/BLMCU/pika_hal_BLMCU_GPIO.c @@ -0,0 +1,124 @@ +#include "../pikascript-lib/PikaStdDevice/pika_hal.h" +#include "bflb_gpio.h" + +typedef struct platform_gpio_t { + struct bflb_device_s* device; + uint8_t pin; + uint32_t config; +} platform_gpio_t; + +int pika_hal_platform_GPIO_open(pika_dev* dev, char* name) { + dev->platform_data = pikaMalloc(sizeof(platform_gpio_t)); + memset(dev->platform_data, 0, sizeof(platform_gpio_t)); + platform_gpio_t* gpio = (platform_gpio_t*)dev->platform_data; + /* Support P1/P2 ... */ + gpio->device = bflb_device_get_by_name("gpio"); + gpio->pin = fast_atoi(name + 1); + return 0; +} + +int pika_hal_platform_GPIO_close(pika_dev* dev) { + pikaFree(dev->platform_data, sizeof(platform_gpio_t)); + return 0; +} + +int pika_hal_platform_GPIO_read(pika_dev* dev, void* buf, size_t count) { + platform_gpio_t* gpio = (platform_gpio_t*)dev->platform_data; + bool val = bflb_gpio_read(gpio->device, gpio->pin); + *(uint32_t*)buf = val; + return 0; +} + +int pika_hal_platform_GPIO_write(pika_dev* dev, void* buf, size_t count) { + platform_gpio_t* gpio = (platform_gpio_t*)dev->platform_data; + bool val = *(uint32_t*)buf; + if (val) { + bflb_gpio_set(gpio->device, gpio->pin); + } else { + bflb_gpio_reset(gpio->device, gpio->pin); + } + return 0; +} + +int pika_hal_platform_GPIO_ioctl_enable(pika_dev* dev) { + platform_gpio_t* gpio = (platform_gpio_t*)dev->platform_data; + bflb_gpio_init(gpio->device, gpio->pin, gpio->config); + return 0; +} + +int pika_hal_platform_GPIO_ioctl_disable(pika_dev* dev) { + platform_gpio_t* gpio = (platform_gpio_t*)dev->platform_data; + bflb_gpio_deinit(gpio->device, gpio->pin); + return 0; +} + +static void _gpio_irq_hanlder(int irq, void* arg) { + static int i = 0; + // get the device + pika_dev* dev = (pika_dev*)arg; + // get the gpio + platform_gpio_t* gpio = (platform_gpio_t*)dev->platform_data; + // get the config + pika_hal_GPIO_config* cfg = (pika_hal_GPIO_config*)dev->ioctl_config; + // get the int status + bool intstatus = bflb_gpio_get_intstatus(gpio->device, gpio->pin); + if (intstatus) { + // call the callback + cfg->event_callback(dev, cfg->event_callback_filter); + // clear the int status + bflb_gpio_int_clear(gpio->device, gpio->pin); + } +} + +int pika_hal_platform_GPIO_ioctl_config(pika_dev* dev, + pika_hal_GPIO_config* cfg) { + platform_gpio_t* gpio = (platform_gpio_t*)dev->platform_data; + switch (cfg->dir) { + case PIKA_HAL_GPIO_DIR_IN: + gpio->config |= GPIO_INPUT; + break; + case PIKA_HAL_GPIO_DIR_OUT: + gpio->config |= GPIO_OUTPUT; + break; + default: + return -1; + } + switch (cfg->pull) { + case PIKA_HAL_GPIO_PULL_NONE: + gpio->config |= GPIO_FLOAT; + break; + case PIKA_HAL_GPIO_PULL_UP: + gpio->config |= GPIO_PULLUP; + break; + case PIKA_HAL_GPIO_PULL_DOWN: + gpio->config |= GPIO_PULLDOWN; + break; + default: + return -1; + } + + /* support event callback */ + if (NULL != cfg->event_callback && + PIKA_HAL_EVENT_CALLBACK_ENA_ENABLE == cfg->event_callback_ena) { + switch (cfg->event_callback_filter) { + case PIKA_HAL_GPIO_EVENT_SIGNAL_RISING: + gpio->config |= GPIO_INT_TRIG_MODE_SYNC_RISING_EDGE; + break; + case PIKA_HAL_GPIO_EVENT_SIGNAL_FALLING: + gpio->config |= GPIO_INT_TRIG_MODE_SYNC_FALLING_EDGE; + break; + + default: + __platform_printf( + "Error: not supported event callback filter %d\r\n", + cfg->event_callback_filter); + return -1; + } + /* register the irq */ + bflb_gpio_int_mask(gpio->device, gpio->pin, false); + bflb_irq_attach(gpio->device->irq_num, _gpio_irq_hanlder, dev); + bflb_irq_enable(gpio->device->irq_num); + } + + return 0; +} diff --git a/examples/pikapython/pikapython/pikascript-lib/BLMCU/pika_hal_BLMCU_UART.c b/examples/pikapython/pikapython/pikascript-lib/BLMCU/pika_hal_BLMCU_UART.c new file mode 100755 index 00000000..7cc0b883 --- /dev/null +++ b/examples/pikapython/pikapython/pikascript-lib/BLMCU/pika_hal_BLMCU_UART.c @@ -0,0 +1,153 @@ +#include "../pikascript-lib/PikaStdDevice/pika_hal.h" +#include "bflb_uart.h" + +typedef struct platform_uart_t { + struct bflb_device_s* device; + struct bflb_uart_config_s config; +} platform_uart_t; + +int pika_hal_platform_UART_open(pika_dev* dev, char* name) { + if (name[0] == 'U' && name[1] == 'A' && name[2] == 'R' && name[3] == 'T') { + int UART_num = fast_atoi(name + 4); + platform_uart_t* uart = pikaMalloc(sizeof(platform_uart_t)); + uart->device = bflb_device_get_by_id(BFLB_DEVICE_TYPE_UART, UART_num); + dev->platform_data = uart; + return 0; + } + return -1; +} + +int pika_hal_platform_UART_close(pika_dev* dev) { + pikaFree(dev->platform_data, sizeof(platform_uart_t)); + return 0; +} + +static void _uart_irq_handler(int irq, void* arg) { + pika_dev* dev = (pika_dev*)arg; + platform_uart_t* uart = (platform_uart_t*)dev->platform_data; + pika_hal_UART_config* cfg = (pika_hal_UART_config*)dev->ioctl_config; + uint32_t intstatus = bflb_uart_get_intstatus(uart->device); + if (intstatus) { + cfg->event_callback(dev, cfg->event_callback_filter); + bflb_uart_int_clear(uart->device, intstatus); + } +} + +int pika_hal_platform_UART_ioctl_config(pika_dev* dev, + pika_hal_UART_config* cfg) { + platform_uart_t* uart = (platform_uart_t*)dev->platform_data; + uart->config.baudrate = cfg->baudrate; + switch (cfg->data_bits) { + case PIKA_HAL_UART_DATA_BITS_5: + uart->config.data_bits = UART_DATA_BITS_5; + break; + case PIKA_HAL_UART_DATA_BITS_6: + uart->config.data_bits = UART_DATA_BITS_6; + break; + case PIKA_HAL_UART_DATA_BITS_7: + uart->config.data_bits = UART_DATA_BITS_7; + break; + case PIKA_HAL_UART_DATA_BITS_8: + uart->config.data_bits = UART_DATA_BITS_8; + break; + default: + uart->config.data_bits = UART_DATA_BITS_8; + break; + } + switch (cfg->parity) { + case PIKA_HAL_UART_PARITY_NONE: + uart->config.parity = UART_PARITY_NONE; + break; + case PIKA_HAL_UART_PARITY_ODD: + uart->config.parity = UART_PARITY_ODD; + break; + case PIKA_HAL_UART_PARITY_EVEN: + uart->config.parity = UART_PARITY_EVEN; + break; + default: + uart->config.parity = UART_PARITY_NONE; + break; + } + switch (cfg->stop_bits) { + case PIKA_HAL_UART_STOP_BITS_1: + uart->config.stop_bits = UART_STOP_BITS_1; + break; + case PIKA_HAL_UART_STOP_BITS_2: + uart->config.stop_bits = UART_STOP_BITS_2; + break; + case PIKA_HAL_UART_STOP_BITS_1_5: + uart->config.stop_bits = UART_STOP_BITS_1_5; + break; + default: + uart->config.stop_bits = UART_STOP_BITS_1; + break; + } + + switch (cfg->flow_control) { + case PIKA_HAL_UART_FLOW_CONTROL_NONE: + uart->config.flow_ctrl = UART_FLOWCTRL_NONE; + break; + case PIKA_HAL_UART_FLOW_CONTROL_CTS: + uart->config.flow_ctrl = UART_FLOWCTRL_CTS; + break; + case PIKA_HAL_UART_FLOW_CONTROL_RTS: + uart->config.flow_ctrl = UART_FLOWCTRL_RTS; + break; + case PIKA_HAL_UART_FLOW_CONTROL_RTS_CTS: + uart->config.flow_ctrl = UART_FLOWCTRL_RTS_CTS; + break; + default: + uart->config.flow_ctrl = UART_FLOWCTRL_NONE; + break; + } + + /* support event callback */ + if (NULL != cfg->event_callback && + PIKA_HAL_EVENT_CALLBACK_ENA_ENABLE == cfg->event_callback_ena) { + switch (cfg->event_callback_filter) { + /* Configure UART to interrupt mode */ + case PIKA_HAL_UART_EVENT_SIGNAL_RX: + bflb_uart_rxint_mask(uart->device, false); + break; + case PIKA_HAL_UART_EVENT_SIGNAL_TX: + bflb_uart_txint_mask(uart->device, false); + break; + default: + __platform_printf( + "Error: not supported event callback filter %d\r\n", + cfg->event_callback_filter); + return -1; + } + bflb_irq_attach(uart->device->irq_num, _uart_irq_handler, dev); + bflb_irq_enable(uart->device->irq_num); + } + return 0; +} + +int pika_hal_platform_UART_ioctl_enable(pika_dev* dev) { + if (!dev->is_enabled) { + platform_uart_t* uart = (platform_uart_t*)dev->platform_data; + bflb_uart_init(uart->device, &uart->config); + return 0; + } + return -1; +} + +int pika_hal_platform_UART_ioctl_disable(pika_dev* dev) { + if (dev->is_enabled) { + platform_uart_t* uart = (platform_uart_t*)dev->platform_data; + bflb_uart_deinit(uart->device); + return 0; + } + return -1; +} + +int pika_hal_platform_UART_write(pika_dev* dev, void* buf, size_t count) { + platform_uart_t* uart = (platform_uart_t*)dev->platform_data; + return bflb_uart_put(uart->device, buf, count); +} + +int pika_hal_platform_UART_read(pika_dev* dev, void* buf, size_t count) { + platform_uart_t* uart = (platform_uart_t*)dev->platform_data; + return bflb_uart_get(uart->device, buf, count); +} diff --git a/examples/pikapython/pikapython/pikascript-lib/PikaMath/PikaMath_Math.c b/examples/pikapython/pikapython/pikascript-lib/PikaMath/PikaMath_Math.c new file mode 100755 index 00000000..1f63c9a0 --- /dev/null +++ b/examples/pikapython/pikapython/pikascript-lib/PikaMath/PikaMath_Math.c @@ -0,0 +1,108 @@ +#include "PikaMath_Math.h" +#include + +#define PI (3.141592653589793115997963468544185161590576171875l) +#define E (2.718281828459045090795598298427648842334747314453125l) +//初始化,填入π和e的值 +void PikaMath_Math___init__(PikaObj *self) +{ + obj_setFloat(self, "pi", PI); + obj_setFloat(self, "e", PI); +} + +pika_float PikaMath_Math_acos(PikaObj *self, pika_float x) +{ + return acos(x); +} +pika_float PikaMath_Math_asin(PikaObj *self, pika_float x) +{ + return asin(x); +} +pika_float PikaMath_Math_atan(PikaObj *self, pika_float x) +{ + return atan(x); +} +pika_float PikaMath_Math_atan2(PikaObj *self, pika_float x, pika_float y) +{ + return atan2(x,y); +} +int PikaMath_Math_ceil(PikaObj *self, pika_float x) +{ + return ceil(x); +} +pika_float PikaMath_Math_cos(PikaObj *self, pika_float x) +{ + return cos(x); +} +pika_float PikaMath_Math_cosh(PikaObj *self, pika_float x) +{ + return cosh(x); +} +pika_float PikaMath_Math_degrees(PikaObj *self, pika_float x) +{ + return x*180.0/PI; +} +pika_float PikaMath_Math_exp(PikaObj *self, pika_float x) +{ + return exp(x); +} +pika_float PikaMath_Math_fabs(PikaObj *self, pika_float x) +{ + return fabs(x); +} +int PikaMath_Math_floor(PikaObj *self, pika_float x) +{ + return floor(x); +} +pika_float PikaMath_Math_fmod(PikaObj *self, pika_float x, pika_float y) +{ + return fmod(x,y); +} +pika_float PikaMath_Math_log(PikaObj *self, pika_float x) +{ + return log(x); +} +pika_float PikaMath_Math_log10(PikaObj *self, pika_float x) +{ + return log10(x); +} +pika_float PikaMath_Math_log2(PikaObj *self, pika_float x) +{ + return log2(x); +} +pika_float PikaMath_Math_pow(PikaObj *self, pika_float x, pika_float y) +{ + return pow(x,y); +} +pika_float PikaMath_Math_radians(PikaObj *self, pika_float x) +{ + return x*PI/180.0; +} +pika_float PikaMath_Math_remainder(PikaObj *self, pika_float x, pika_float y) +{ + return remainder(x,y); +} +pika_float PikaMath_Math_sin(PikaObj *self, pika_float x) +{ + return sin(x); +} +pika_float PikaMath_Math_sinh(PikaObj *self, pika_float x) +{ + return sinh(x); +} +pika_float PikaMath_Math_sqrt(PikaObj *self, pika_float x) +{ + return sqrt(x); +} +pika_float PikaMath_Math_tan(PikaObj *self, pika_float x) +{ + return tan(x); +} +pika_float PikaMath_Math_tanh(PikaObj *self, pika_float x) +{ + return tanh(x); +} +pika_float PikaMath_Math_trunc(PikaObj *self, pika_float x) +{ + return trunc(x); +} \ No newline at end of file diff --git a/examples/pikapython/pikapython/pikascript-lib/PikaMath/PikaMath_Operator.c b/examples/pikapython/pikapython/pikascript-lib/PikaMath/PikaMath_Operator.c new file mode 100755 index 00000000..9d4ecf31 --- /dev/null +++ b/examples/pikapython/pikapython/pikascript-lib/PikaMath/PikaMath_Operator.c @@ -0,0 +1,54 @@ +#include "PikaMath_Operator.h" + +int PikaMath_Operator_AND(PikaObj* self, int flag1, int flag2) { + return flag1 && flag2; +} +int PikaMath_Operator_NOT(PikaObj* self, int flag) { + return !flag; +} +int PikaMath_Operator_OR(PikaObj* self, int flag1, int flag2) { + return flag1 || flag2; +} +int PikaMath_Operator_equalFloat(PikaObj* self, pika_float num1, pika_float num2) { + return num1 == num2; +} +int PikaMath_Operator_equalInt(PikaObj* self, int num1, int num2) { + return num1 == num2; +} +int PikaMath_Operator_graterThanFloat(PikaObj* self, pika_float num1, pika_float num2) { + return num1 > num2; +} +int PikaMath_Operator_graterThanInt(PikaObj* self, int num1, int num2) { + return num1 > num2; +} +int PikaMath_Operator_lessThanFloat(PikaObj* self, pika_float num1, pika_float num2) { + return num1 < num2; +} +int PikaMath_Operator_lessThanInt(PikaObj* self, int num1, int num2) { + return num1 < num2; +} +pika_float PikaMath_Operator_minusFloat(PikaObj* self, pika_float num1, pika_float num2) { + return num1 - num2; +} +int PikaMath_Operator_minusInt(PikaObj* self, int num1, int num2) { + return num1 - num2; +} + +pika_float PikaMath_Operator_plusFloat(PikaObj* self, pika_float num1, pika_float num2) { + return num1 + num2; +} + +int PikaMath_Operator_plusInt(PikaObj* self, int num1, int num2) { + return num1 + num2; +} + +char* PikaMath_Operator___str__(PikaObj *self){ + obj_setStr(self, "__buf", "test"); + return obj_getStr(self, "__buf"); +} + +void PikaMath_Operator___del__(PikaObj *self){ + __platform_printf("del operator...\r\n"); +} + + diff --git a/examples/pikapython/pikapython/pikascript-lib/PikaMath/PikaMath_Quaternion.c b/examples/pikapython/pikapython/pikascript-lib/PikaMath/PikaMath_Quaternion.c new file mode 100755 index 00000000..3dd3ceb9 --- /dev/null +++ b/examples/pikapython/pikapython/pikascript-lib/PikaMath/PikaMath_Quaternion.c @@ -0,0 +1,274 @@ +#include "PikaMath_Quaternion.h" +#include "PikaStdData_List.h" +#include "math.h" + +void PikaMath_Quaternion___init__(PikaObj* self) { + obj_setFloat(self, "x", 0.0); + obj_setFloat(self, "y", 0.0); + obj_setFloat(self, "z", 0.0); + obj_setFloat(self, "w", 1.0); +} + +void PikaMath_Quaternion_set(PikaObj* self, + pika_float x, + pika_float y, + pika_float z, + pika_float w) { + obj_setFloat(self, "x", x); + obj_setFloat(self, "y", y); + obj_setFloat(self, "z", z); + obj_setFloat(self, "w", w); +} + +pika_float PikaMath_Quaternion_get(PikaObj* self, int key) { + if (key == 0) { + return obj_getFloat(self, "x"); + } + if (key == 1) { + return obj_getFloat(self, "y"); + } + if (key == 2) { + return obj_getFloat(self, "z"); + } + if (key == 3) { + return obj_getFloat(self, "w"); + } else { + obj_setErrorCode(self, 1); + return 0.0; + } +} + +void PikaMath_Quaternion_add(PikaObj* self, PikaObj* quat) { + float x_ = obj_getFloat(quat, "x"); + float y_ = obj_getFloat(quat, "y"); + float z_ = obj_getFloat(quat, "z"); + float w_ = obj_getFloat(quat, "w"); + + float x = obj_getFloat(self, "x"); + float y = obj_getFloat(self, "y"); + float z = obj_getFloat(self, "z"); + float w = obj_getFloat(self, "w"); + + float x_sum = x + x_; + float y_sum = y + y_; + float z_sum = z + z_; + float w_sum = w + w_; + + obj_setFloat(self, "x", x_sum); + obj_setFloat(self, "y", y_sum); + obj_setFloat(self, "z", z_sum); + obj_setFloat(self, "w", w_sum); +} + +void PikaMath_Quaternion_sub(PikaObj* self, PikaObj* quat) { + float x_ = obj_getFloat(quat, "x"); + float y_ = obj_getFloat(quat, "y"); + float z_ = obj_getFloat(quat, "z"); + float w_ = obj_getFloat(quat, "w"); + + float x = obj_getFloat(self, "x"); + float y = obj_getFloat(self, "y"); + float z = obj_getFloat(self, "z"); + float w = obj_getFloat(self, "w"); + + float x_sub = x - x_; + float y_sub = y - y_; + float z_sub = z - z_; + float w_sub = w - w_; + + obj_setFloat(self, "x", x_sub); + obj_setFloat(self, "y", y_sub); + obj_setFloat(self, "z", z_sub); + obj_setFloat(self, "w", w_sub); +} + +void PikaMath_Quaternion_mul(PikaObj* self, PikaObj* quat) { + float x_ = obj_getFloat(quat, "x"); + float y_ = obj_getFloat(quat, "y"); + float z_ = obj_getFloat(quat, "z"); + float w_ = obj_getFloat(quat, "w"); + + float x = obj_getFloat(self, "x"); + float y = obj_getFloat(self, "y"); + float z = obj_getFloat(self, "z"); + float w = obj_getFloat(self, "w"); + + float x_mul = w * x_ + x * w_ - y * z_ + z * y_; + float y_mul = w * y_ + y * w_ + x * z_ - z * x_; + float z_mul = w * z_ + z * w_ - x * y_ + y * x_; + float w_mul = w * w_ - x * x_ - y * y_ - z * z_; + + obj_setFloat(self, "x", x_mul); + obj_setFloat(self, "y", y_mul); + obj_setFloat(self, "z", z_mul); + obj_setFloat(self, "w", w_mul); +} +pika_float PikaMath_Quaternion_magnituded(PikaObj* self) { + float magnituded = PikaMath_Quaternion_magnitudedsquare(self); + + return pow(magnituded, 0.5); +} +pika_float PikaMath_Quaternion_magnitudedsquare(PikaObj* self) { + float x = obj_getFloat(self, "x"); + float y = obj_getFloat(self, "y"); + float z = obj_getFloat(self, "z"); + float w = obj_getFloat(self, "w"); + + float magnitudedsquare = pow(x, 2) + pow(y, 2) + pow(z, 2) + pow(w, 2); + + return magnitudedsquare; +} + +void PikaMath_Quaternion_reverse(PikaObj* self) { + float x = obj_getFloat(self, "x"); + float y = obj_getFloat(self, "y"); + float z = obj_getFloat(self, "z"); + float w = obj_getFloat(self, "w"); + + obj_setFloat(self, "x", -x); + obj_setFloat(self, "y", -y); + obj_setFloat(self, "z", -z); + obj_setFloat(self, "w", w); +} + +void PikaMath_Quaternion_inverse(PikaObj* self) { + float x = obj_getFloat(self, "x"); + float y = obj_getFloat(self, "y"); + float z = obj_getFloat(self, "z"); + float w = obj_getFloat(self, "w"); + + float mag = PikaMath_Quaternion_magnitudedsquare(self); + if (mag > 0.0001) { + obj_setFloat(self, "x", -x / mag); + obj_setFloat(self, "y", -y / mag); + obj_setFloat(self, "z", -z / mag); + obj_setFloat(self, "w", w / mag); + } else { + obj_setFloat(self, "x", 0.0); + obj_setFloat(self, "y", 0.0); + obj_setFloat(self, "z", 0.0); + obj_setFloat(self, "w", 1.0); + } +} + +void PikaMath_Quaternion_crossproduct(PikaObj* self, PikaObj* quat) { + float x_ = obj_getFloat(quat, "x"); + float y_ = obj_getFloat(quat, "y"); + float z_ = obj_getFloat(quat, "z"); + + float x = obj_getFloat(self, "x"); + float y = obj_getFloat(self, "y"); + float z = obj_getFloat(self, "z"); + + float x_cross = y * z_ - z * y_; + float y_cross = z * x_ - x * z_; + float z_cross = x * y_ - y * x_; + + obj_setFloat(self, "x", x_cross); + obj_setFloat(self, "y", y_cross); + obj_setFloat(self, "z", z_cross); + obj_setFloat(self, "w", 0.0); +} + +pika_float PikaMath_Quaternion_dot(PikaObj* self, PikaObj* quat) { + float x_ = obj_getFloat(quat, "x"); + float y_ = obj_getFloat(quat, "y"); + float z_ = obj_getFloat(quat, "z"); + float w_ = obj_getFloat(quat, "w"); + + float x = obj_getFloat(self, "x"); + float y = obj_getFloat(self, "y"); + float z = obj_getFloat(self, "z"); + float w = obj_getFloat(self, "w"); + + return (x_ * x + y_ * y + z_ * z + w_ * w); +} + +void PikaMath_Quaternion_normalize(PikaObj* self) { + float x = obj_getFloat(self, "x"); + float y = obj_getFloat(self, "y"); + float z = obj_getFloat(self, "z"); + float w = obj_getFloat(self, "w"); + + float mag = PikaMath_Quaternion_magnituded(self); + if (mag > 0.0001) { + obj_setFloat(self, "x", x / mag); + obj_setFloat(self, "y", y / mag); + obj_setFloat(self, "z", z / mag); + obj_setFloat(self, "w", w / mag); + } else { + obj_setFloat(self, "x", 0.0); + obj_setFloat(self, "y", 0.0); + obj_setFloat(self, "z", 0.0); + obj_setFloat(self, "w", 1.0); + } +} + +int PikaMath_Quaternion_isnormalize(PikaObj* self) { + float mag = PikaMath_Quaternion_magnituded(self); + + if (1.0 == mag) { + return 1; + } else { + return 0; + } +} + +#define PI_DIV_180 (0.017453292519943296) +#define DegToRad(x) ((x)*PI_DIV_180) + +void PikaMath_Quaternion_fromEuler(PikaObj* self, + pika_float yaw, + pika_float pitch, + pika_float roll, + int mode) { + if (mode) { + pitch = DegToRad(pitch); + roll = DegToRad(roll); + yaw = DegToRad(yaw); + } + + float sinp = sin(pitch / 2); + float siny = sin(yaw / 2); + float sinr = sin(roll / 2); + + float cosp = cos(pitch / 2); + float cosy = cos(yaw / 2); + float cosr = cos(roll / 2); + + float x = sinr * cosp * cosy - cosr * sinp * siny; + float y = cosr * sinp * cosy + sinr * cosp * siny; + float z = cosr * cosp * siny - sinr * sinp * cosy; + float w = cosr * cosp * cosy + sinr * sinp * siny; + + obj_setFloat(self, "x", x); + obj_setFloat(self, "y", y); + obj_setFloat(self, "z", z); + obj_setFloat(self, "w", w); +} + +PikaObj* PikaMath_Quaternion_toEuler(PikaObj* self) { + float x = obj_getFloat(self, "x"); + float y = obj_getFloat(self, "y"); + float z = obj_getFloat(self, "z"); + float w = obj_getFloat(self, "w"); + + float roll = atan2(2 * (w * x + y * z), 1 - 2 * (x * x + y * y)); + float pitch = asin(2 * (w * y - z * x)); + float yaw = atan2(2 * (w * z + x * y), 1 - 2 * (y * y + z * z)); + + float rpy[3] = {roll, pitch, yaw}; + + PikaObj* list = newNormalObj(New_PikaStdData_List); + PikaStdData_List___init__(list); + + for (int i = 0; i < 3; i++) { + Arg* token_arg = arg_newFloat(rpy[i]); + /* 添加到 list 对象 */ + PikaStdData_List_append(list, token_arg); + /* 销毁 arg */ + arg_deinit(token_arg); + } + + return list; +} \ No newline at end of file diff --git a/examples/pikapython/pikapython/pikascript-lib/PikaStdDevice/PikaStdDevice_ADC.c b/examples/pikapython/pikapython/pikascript-lib/PikaStdDevice/PikaStdDevice_ADC.c new file mode 100755 index 00000000..2749d909 --- /dev/null +++ b/examples/pikapython/pikapython/pikascript-lib/PikaStdDevice/PikaStdDevice_ADC.c @@ -0,0 +1,73 @@ +#include "PikaStdDevice_ADC.h" +#include "PikaStdDevice_common.h" + +void PikaStdDevice_ADC_enable(PikaObj* self) { + obj_runNativeMethod(self, "platformEnable", NULL); +} + +void PikaStdDevice_ADC_disable(PikaObj* self) { + obj_runNativeMethod(self, "platformDisable", NULL); +} + +void PikaStdDevice_ADC_init(PikaObj* self) { + obj_setStr(self, "pin", "PA0"); +} + +void PikaStdDevice_ADC___init__(PikaObj* self) { + PikaStdDevice_ADC_init(self); +} + +pika_float PikaStdDevice_ADC_read(PikaObj* self) { + obj_runNativeMethod(self, "platformRead", NULL); + return obj_getFloat(self, "val"); +} + +void PikaStdDevice_ADC_setPin(PikaObj* self, char* pin) { + obj_setStr(self, "pin", pin); +} + +static pika_dev* _get_dev(PikaObj* self) { + pika_dev* dev = obj_getPtr(self, "pika_dev"); + if (NULL != dev) { + return dev; + } + dev = pika_hal_open(PIKA_HAL_ADC, obj_getStr(self, "pin")); + if (NULL == dev) { + __platform_printf("Error: open ADC '%s' failed.\r\n", + obj_getStr(self, "pin")); + } + obj_setPtr(self, "pika_dev", dev); + return dev; +} + +void PikaStdDevice_ADC_platformEnable(PikaObj* self) { + pika_dev* dev = _get_dev(self); + if (NULL == dev) { + __platform_printf("Error: open ADC '%s' failed.\r\n", + obj_getStr(self, "pin")); + return; + } + pika_hal_ADC_config cfg = {0}; + cfg.continue_or_single = PIKA_HAL_ADC_SINGLE; + pika_hal_ioctl(dev, PIKA_HAL_IOCTL_CONFIG, &cfg); + pika_hal_ioctl(dev, PIKA_HAL_IOCTL_ENABLE); +} + +void PikaStdDevice_ADC_platformDisable(PikaObj* self) { + pika_dev* dev = _get_dev(self); + pika_hal_ioctl(dev, PIKA_HAL_IOCTL_DISABLE); +} + +void PikaStdDevice_ADC_platformRead(PikaObj* self) { + pika_dev* dev = _get_dev(self); + pika_hal_ADC_config* cfg = (pika_hal_ADC_config*)dev->ioctl_config; + uint32_t val_i = 0; + pika_hal_read(dev, &val_i, sizeof(val_i)); + pika_float val = (pika_float)val_i / (pika_float)cfg->max * cfg->vref; + val = val_i * obj_setFloat(self, "val", val); +} + +void PikaStdDevice_ADC_close(PikaObj* self) { + pika_dev* dev = _get_dev(self); + pika_hal_close(dev); +} diff --git a/examples/pikapython/pikapython/pikascript-lib/PikaStdDevice/PikaStdDevice_BaseDev.c b/examples/pikapython/pikapython/pikascript-lib/PikaStdDevice/PikaStdDevice_BaseDev.c new file mode 100755 index 00000000..88da8bce --- /dev/null +++ b/examples/pikapython/pikapython/pikascript-lib/PikaStdDevice/PikaStdDevice_BaseDev.c @@ -0,0 +1,32 @@ +#include "PikaStdDevice_BaseDev.h" +#include "PikaStdDevice_common.h" + +#if !PIKASCRIPT_VERSION_REQUIRE_MINIMUN(1, 10, 4) +#error "This library requires PikaScript version 1.10.4 or higher" +#endif + +PikaEventListener* g_pika_device_event_listener; + +void PikaStdDevice_BaseDev_addEventCallBack(PikaObj* self, Arg* eventCallBack) { +#if PIKA_EVENT_ENABLE + obj_setArg(self, "eventCallBack", eventCallBack); + /* init event_listener for the first time */ + if (NULL == g_pika_device_event_listener) { + pks_eventListener_init(&g_pika_device_event_listener); + } + if (PIKA_RES_OK != obj_runNativeMethod(self, "platformGetEventId", NULL)) { + obj_setErrorCode(self, 1); + __platform_printf("Error: Method %s no found.\r\n", + "platformGetEventId"); + } + uint32_t eventId = obj_getInt(self, "eventId"); + pks_eventListener_registEvent(g_pika_device_event_listener, eventId, self); +#else + obj_setErrorCode(self, 1); + obj_setSysOut(self, "[error] PIKA_EVENT_ENABLE is disabled."); +#endif +} + +void PikaStdDevice_BaseDev_platformGetEventId(PikaObj* self) { + ABSTRACT_METHOD_NEED_OVERRIDE_ERROR(); +} diff --git a/examples/pikapython/pikapython/pikascript-lib/PikaStdDevice/PikaStdDevice_CAN.c b/examples/pikapython/pikapython/pikascript-lib/PikaStdDevice/PikaStdDevice_CAN.c new file mode 100755 index 00000000..830c45b7 --- /dev/null +++ b/examples/pikapython/pikapython/pikascript-lib/PikaStdDevice/PikaStdDevice_CAN.c @@ -0,0 +1,84 @@ +#include "PikaStdDevice_CAN.h" +#include "PikaStdDevice_common.h" + +void PikaStdDevice_CAN___init__(PikaObj* self) {} + +void PikaStdDevice_CAN_addFilter(PikaObj* self, + int hdr, + int id, + int ide, + int mask, + int mode, + int rtr) { + ABSTRACT_METHOD_NEED_OVERRIDE_ERROR(); +} + +void PikaStdDevice_CAN_disable(PikaObj* self) { + obj_runNativeMethod(self, "platformDisable", NULL); +} + +void PikaStdDevice_CAN_enable(PikaObj* self) { + obj_runNativeMethod(self, "platformEnable", NULL); +} + +void PikaStdDevice_CAN_setId(PikaObj* self, int id) { + obj_setInt(self, "id", id); +} + +void PikaStdDevice_CAN_setMode(PikaObj* self, char* mode) { + obj_setStr(self, "mode", mode); +} + +void PikaStdDevice_CAN_setName(PikaObj* self, char* name) { + obj_setStr(self, "name", name); +} + +void PikaStdDevice_CAN_setBaudRate(PikaObj* self, int baudRate) { + obj_setInt(self, "baudRate", baudRate); +} + +char* PikaStdDevice_CAN_read(PikaObj* self, int length) { + obj_setInt(self, "length", length); + obj_runNativeMethod(self, "platformRead", NULL); + return obj_getStr(self, "readData"); +} + +Arg* PikaStdDevice_CAN_readBytes(PikaObj *self, int length){ + obj_setInt(self, "length", length); + obj_runNativeMethod(self, "platformReadBytes", NULL); + return arg_copy(obj_getArg(self, "readData")); +} + +void PikaStdDevice_CAN_write(PikaObj* self, char* data) { + obj_setStr(self, "writeData", data); + obj_runNativeMethod(self, "platformWrite", NULL); +} + +void PikaStdDevice_CAN_writeBytes(PikaObj *self, uint8_t* data, int length){ + obj_setBytes(self, "writeData", data, length); + obj_runNativeMethod(self, "platformWriteBytes", NULL); +} + +void PikaStdDevice_CAN_platformDisable(PikaObj* self) { + ABSTRACT_METHOD_NEED_OVERRIDE_ERROR(); +} + +void PikaStdDevice_CAN_platformEnable(PikaObj* self) { + ABSTRACT_METHOD_NEED_OVERRIDE_ERROR(); +} + +void PikaStdDevice_CAN_platformRead(PikaObj* self) { + ABSTRACT_METHOD_NEED_OVERRIDE_ERROR(); +} + +void PikaStdDevice_CAN_platformWrite(PikaObj* self) { + ABSTRACT_METHOD_NEED_OVERRIDE_ERROR(); +} + +void PikaStdDevice_CAN_platformReadBytes(PikaObj *self){ + ABSTRACT_METHOD_NEED_OVERRIDE_ERROR(); +} + +void PikaStdDevice_CAN_platformWriteBytes(PikaObj *self){ + ABSTRACT_METHOD_NEED_OVERRIDE_ERROR(); +} diff --git a/examples/pikapython/pikapython/pikascript-lib/PikaStdDevice/PikaStdDevice_DAC.c b/examples/pikapython/pikapython/pikascript-lib/PikaStdDevice/PikaStdDevice_DAC.c new file mode 100755 index 00000000..6f8b833c --- /dev/null +++ b/examples/pikapython/pikapython/pikascript-lib/PikaStdDevice/PikaStdDevice_DAC.c @@ -0,0 +1,52 @@ +#include "PikaStdDevice_DAC.h" +#include "PikaStdDevice_common.h" + +static pika_dev* _get_dev(PikaObj* self) { + pika_dev* dev = obj_getPtr(self, "pika_dev"); + if (NULL != dev) { + return dev; + } + dev = pika_hal_open(PIKA_HAL_DAC, obj_getStr(self, "pin")); + if (NULL == dev) { + __platform_printf("Error: open DAC '%s' failed.\r\n", + obj_getStr(self, "pin")); + } + obj_setPtr(self, "pika_dev", dev); + return dev; +} + +void PikaStdDevice_DAC_enable(PikaObj* self) { + pika_dev* dev = _get_dev(self); + pika_hal_DAC_config cfg = {0}; + pika_hal_ioctl(dev, PIKA_HAL_IOCTL_CONFIG, &cfg); + pika_hal_ioctl(dev, PIKA_HAL_IOCTL_ENABLE); +} + +void PikaStdDevice_DAC_setPin(PikaObj* self, char* pin) { + obj_setStr(self, "pin", pin); +} + +void PikaStdDevice_DAC_disable(PikaObj* self) { + pika_dev* dev = _get_dev(self); + pika_hal_ioctl(dev, PIKA_HAL_IOCTL_DISABLE); +} + +void PikaStdDevice_DAC_init(PikaObj* self) { + obj_setStr(self, "pin", "PA0"); +} + +void PikaStdDevice_DAC___init__(PikaObj* self) { + PikaStdDevice_DAC_init(self); +} + +void PikaStdDevice_DAC_write(PikaObj* self, pika_float val) { + pika_dev* dev = _get_dev(self); + pika_hal_DAC_config* cfg = (pika_hal_DAC_config*)dev->ioctl_config; + uint32_t val_i = (val / cfg->vref) * cfg->max; + pika_hal_write(dev, &val_i, sizeof val_i); +} + +void PikaStdDevice_DAC_close(PikaObj* self) { + pika_dev* dev = _get_dev(self); + pika_hal_close(dev); +} diff --git a/examples/pikapython/pikapython/pikascript-lib/PikaStdDevice/PikaStdDevice_GPIO.c b/examples/pikapython/pikapython/pikascript-lib/PikaStdDevice/PikaStdDevice_GPIO.c new file mode 100755 index 00000000..65d97a61 --- /dev/null +++ b/examples/pikapython/pikapython/pikascript-lib/PikaStdDevice/PikaStdDevice_GPIO.c @@ -0,0 +1,172 @@ +#include "PikaStdDevice_GPIO.h" +#include "PikaStdDevice_common.h" + +void PikaStdDevice_GPIO_init(PikaObj* self) { + obj_setInt(self, "isEnable", 0); + obj_setStr(self, "pin", "none"); + obj_setStr(self, "mode", "out"); + obj_setInt(self, "isOn", 0); + obj_setStr(self, "pull", "none"); + obj_setInt(self, "id", -999); + obj_setPtr(self, "pika_dev", NULL); +} + +int PikaStdDevice_GPIO_getId(PikaObj* self) { + return obj_getInt(self, "id"); +} + +void PikaStdDevice_GPIO_setId(PikaObj* self, int id) { + obj_setInt(self, "id", id); +} + +void PikaStdDevice_GPIO___init__(PikaObj* self) { + PikaStdDevice_GPIO_init(self); + obj_setInt(self, "SIGNAL_RISING", PIKA_HAL_GPIO_EVENT_SIGNAL_RISING); + obj_setInt(self, "SIGNAL_FALLING", PIKA_HAL_GPIO_EVENT_SIGNAL_FALLING); + obj_setInt(self, "SIGNAL_ANY", PIKA_HAL_GPIO_EVENT_SIGNAL_ANY); +} + +void PikaStdDevice_GPIO_disable(PikaObj* self) { + obj_setInt(self, "isEnable", 0); + obj_runNativeMethod(self, "platformDisable", NULL); +} + +void PikaStdDevice_GPIO_enable(PikaObj* self) { + obj_setInt(self, "isEnable", 1); + obj_runNativeMethod(self, "platformEnable", NULL); +} + +char* PikaStdDevice_GPIO_getMode(PikaObj* self) { + return obj_getStr(self, "mode"); +} + +char* PikaStdDevice_GPIO_getPin(PikaObj* self) { + return obj_getStr(self, "pin"); +} + +void PikaStdDevice_GPIO_low(PikaObj* self) { + obj_setInt(self, "isOn", 0); + obj_runNativeMethod(self, "platformLow", NULL); +} + +void PikaStdDevice_GPIO_high(PikaObj* self) { + obj_setInt(self, "isOn", 1); + obj_runNativeMethod(self, "platformHigh", NULL); +} + +int PikaStdDevice_GPIO_read(PikaObj* self) { + obj_runNativeMethod(self, "platformRead", NULL); + return obj_getInt(self, "readBuff"); +} + +void PikaStdDevice_GPIO_setMode(PikaObj* self, char* mode) { + if (strEqu(mode, "out") || strEqu(mode, "in")) { + obj_setStr(self, "mode", mode); + obj_runNativeMethod(self, "platformSetMode", NULL); + } else { + obj_setErrorCode(self, 1); + obj_setSysOut(self, "[error] GPIO mode should be 'out' or 'in'."); + } +} + +void PikaStdDevice_GPIO_setPull(PikaObj* self, char* pull) { + if (strEqu(pull, "up") || strEqu(pull, "down") || strEqu(pull, "none")) { + obj_setStr(self, "pull", pull); + } else { + obj_setErrorCode(self, 1); + obj_setSysOut(self, + "[error] GPIO pull should be 'up', 'down' or 'none'."); + } +} + +static pika_dev* _get_dev(PikaObj* self) { + pika_dev* dev = obj_getPtr(self, "pika_dev"); + if (NULL != dev) { + return dev; + } + dev = pika_hal_open(PIKA_HAL_GPIO, obj_getStr(self, "pin")); + if (NULL == dev) { + __platform_printf("Error: open GPIO '%s' failed.\r\n", + obj_getStr(self, "pin")); + } + obj_setPtr(self, "pika_dev", dev); + return dev; +} + +void PikaStdDevice_GPIO_setPin(PikaObj* self, char* pinName) { + obj_setStr(self, "pin", pinName); +} + +void PikaStdDevice_GPIO_platformDisable(PikaObj* self) { + pika_dev* dev = _get_dev(self); + pika_hal_ioctl(dev, PIKA_HAL_IOCTL_DISABLE); +} + +void PikaStdDevice_GPIO_platformEnable(PikaObj* self) { + pika_dev* dev = _get_dev(self); + pika_hal_ioctl(dev, PIKA_HAL_IOCTL_ENABLE); +} + +void PikaStdDevice_GPIO_platformLow(PikaObj* self) { + pika_dev* dev = _get_dev(self); + uint32_t val = 0; + pika_hal_write(dev, &val, sizeof(val)); +} + +void PikaStdDevice_GPIO_platformHigh(PikaObj* self) { + pika_dev* dev = _get_dev(self); + uint32_t val = 1; + pika_hal_write(dev, &val, sizeof(val)); +} + +void PikaStdDevice_GPIO_platformSetMode(PikaObj* self) { + char* mode = obj_getStr(self, "mode"); + pika_hal_GPIO_config cfg = {0}; + if (strEqu(mode, "in")) { + cfg.dir = PIKA_HAL_GPIO_DIR_IN; + } else { + cfg.dir = PIKA_HAL_GPIO_DIR_OUT; + } + pika_dev* dev = _get_dev(self); + char* pull = obj_getStr(self, "pull"); + if (strEqu(pull, "up")) { + cfg.pull = PIKA_HAL_GPIO_PULL_UP; + } + if (strEqu(pull, "down")) { + cfg.pull = PIKA_HAL_GPIO_PULL_DOWN; + } + if (strEqu(pull, "none")) { + cfg.pull = PIKA_HAL_GPIO_PULL_NONE; + } + pika_hal_ioctl(dev, PIKA_HAL_IOCTL_CONFIG, &cfg); +} + +void PikaStdDevice_GPIO_platformRead(PikaObj* self) { + pika_dev* dev = _get_dev(self); + uint32_t val = 0; + pika_hal_read(dev, &val, sizeof(val)); + obj_setInt(self, "readBuff", val); +} + +void PikaStdDevice_GPIO_setCallBack(PikaObj* self, + Arg* eventCallback, + int filter) { + pika_dev* dev = _get_dev(self); +#if PIKA_EVENT_ENABLE + _PikaStdDevice_setCallBack(self, eventCallback, (uintptr_t)dev); + /* regist event to pika_hal */ + pika_hal_GPIO_config cfg_cb = {0}; + cfg_cb.event_callback = (void*)_PikaStdDevice_event_handler; + cfg_cb.event_callback_filter = filter; + cfg_cb.event_callback_ena = PIKA_HAL_EVENT_CALLBACK_ENA_ENABLE; + pika_hal_ioctl(dev, PIKA_HAL_IOCTL_CONFIG, &cfg_cb); +#else + obj_setErrorCode(self, 1); + obj_setSysOut(self, "[error] PIKA_EVENT_ENABLE is disabled."); +#endif +} + +void PikaStdDevice_GPIO_close(PikaObj *self){ + pika_dev* dev = _get_dev(self); + pika_hal_close(dev); +} diff --git a/examples/pikapython/pikapython/pikascript-lib/PikaStdDevice/PikaStdDevice_IIC.c b/examples/pikapython/pikapython/pikascript-lib/PikaStdDevice/PikaStdDevice_IIC.c new file mode 100755 index 00000000..332d896e --- /dev/null +++ b/examples/pikapython/pikapython/pikascript-lib/PikaStdDevice/PikaStdDevice_IIC.c @@ -0,0 +1,85 @@ +#include "PikaStdDevice_IIC.h" +#include "PikaStdDevice_common.h" + +void PikaStdDevice_IIC_init(PikaObj* self) { + obj_setInt(self, "deviceAddr", 0); + obj_setStr(self, "SCLpin", "PA0"); + obj_setStr(self, "SDApin", "PA1"); +} + +void PikaStdDevice_IIC___init__(PikaObj* self) { + PikaStdDevice_IIC_init(self); +} + +void PikaStdDevice_IIC_enable(PikaObj* self) { + obj_runNativeMethod(self, "platformEnable", NULL); +} + +void PikaStdDevice_IIC_disable(PikaObj* self) { + obj_runNativeMethod(self, "platformDisable", NULL); +} + +void PikaStdDevice_IIC_setDeviceAddr(PikaObj* self, int addr) { + obj_setInt(self, "deviceAddr", addr); +} + +void PikaStdDevice_IIC_setPinSCL(PikaObj* self, char* pin) { + obj_setStr(self, "SCLpin", pin); +} + +void PikaStdDevice_IIC_setPinSDA(PikaObj* self, char* pin) { + obj_setStr(self, "SDApin", pin); +} + +void PikaStdDevice_IIC_write(PikaObj* self, int addr, char* data) { + obj_setStr(self, "writeData", data); + obj_setInt(self, "writeAddr", addr); + obj_runNativeMethod(self, "platformWrite", NULL); +} + +void PikaStdDevice_IIC_writeBytes(PikaObj* self, + int addr, + uint8_t* data, + int length) { + obj_setBytes(self, "writeData", data, length); + obj_setInt(self, "writeAddr", addr); + obj_runNativeMethod(self, "platformWriteBytes", NULL); +} + +char* PikaStdDevice_IIC_read(PikaObj* self, int addr, int length) { + obj_setInt(self, "length", length); + obj_setInt(self, "readAddr", addr); + obj_runNativeMethod(self, "platformRead", NULL); + return obj_getStr(self, "readData"); +} + +Arg* PikaStdDevice_IIC_readBytes(PikaObj* self, int addr, int length) { + obj_setInt(self, "length", length); + obj_setInt(self, "readAddr", addr); + obj_runNativeMethod(self, "platformReadBytes", NULL); + return arg_copy(obj_getArg(self, "readData")); +} + +void PikaStdDevice_IIC_platformWrite(PikaObj* self) { + ABSTRACT_METHOD_NEED_OVERRIDE_ERROR(); +} + +void PikaStdDevice_IIC_platformEnable(PikaObj* self) { + ABSTRACT_METHOD_NEED_OVERRIDE_ERROR(); +} + +void PikaStdDevice_IIC_platformDisable(PikaObj* self) { + ABSTRACT_METHOD_NEED_OVERRIDE_ERROR(); +} + +void PikaStdDevice_IIC_platformRead(PikaObj* self) { + ABSTRACT_METHOD_NEED_OVERRIDE_ERROR(); +} + +void PikaStdDevice_IIC_platformReadBytes(PikaObj* self) { + ABSTRACT_METHOD_NEED_OVERRIDE_ERROR(); +} + +void PikaStdDevice_IIC_platformWriteBytes(PikaObj* self) { + ABSTRACT_METHOD_NEED_OVERRIDE_ERROR(); +} diff --git a/examples/pikapython/pikapython/pikascript-lib/PikaStdDevice/PikaStdDevice_PWM.c b/examples/pikapython/pikapython/pikascript-lib/PikaStdDevice/PikaStdDevice_PWM.c new file mode 100755 index 00000000..1bffbdd4 --- /dev/null +++ b/examples/pikapython/pikapython/pikascript-lib/PikaStdDevice/PikaStdDevice_PWM.c @@ -0,0 +1,112 @@ +#include "PikaStdDevice_PWM.h" +#include "PikaStdDevice_common.h" + +void PikaStdDevice_PWM_init(PikaObj* self) { + obj_setStr(self, "pin", "none"); + obj_setStr(self, "name", "none"); + obj_setInt(self, "freq", 1000); + obj_setInt(self, "ch", 0); + obj_setFloat(self, "duty", 0.5f); +} + +void PikaStdDevice_PWM___init__(PikaObj* self) { + PikaStdDevice_PWM_init(self); +} + +void PikaStdDevice_PWM_setPin(PikaObj* self, char* pin) { + obj_setStr(self, "pin", pin); +} + +void PikaStdDevice_PWM_setFrequency(PikaObj* self, int freq) { + obj_setInt(self, "freq", freq); + obj_runNativeMethod(self, "platformSetFrequency", NULL); +} + +void PikaStdDevice_PWM_setDuty(PikaObj* self, pika_float duty) { + obj_setFloat(self, "duty", duty); + obj_runNativeMethod(self, "platformSetDuty", NULL); +} + +void PikaStdDevice_PWM_enable(PikaObj* self) { + obj_runNativeMethod(self, "platformEnable", NULL); +} + +void PikaStdDevice_PWM_disable(PikaObj* self) { + obj_runNativeMethod(self, "platformDisable", NULL); +} + +pika_float PikaStdDevice_PWM_getDuty(PikaObj* self) { + return obj_getFloat(self, "duty"); +} + +int PikaStdDevice_PWM_getFrequency(PikaObj* self) { + return obj_getInt(self, "freq"); +} + +char* PikaStdDevice_PWM_getName(PikaObj* self) { + return obj_getStr(self, "name"); +} + +void PikaStdDevice_PWM_setName(PikaObj* self, char* name) { + obj_setStr(self, "name", name); +} + +void PikaStdDevice_PWM_setChannel(PikaObj* self, int ch) { + obj_setInt(self, "ch", ch); +} + +int PikaStdDevice_PWM_getChannel(PikaObj* self) { + return obj_getInt(self, "ch"); +} + +void PikaStdDevice_PWM_setFreq(PikaObj* self, int freq) { + PikaStdDevice_PWM_setFrequency(self, freq); +} + +static pika_dev* _get_dev(PikaObj* self) { + pika_dev* dev = obj_getPtr(self, "pika_dev"); + if (NULL != dev) { + return dev; + } + dev = pika_hal_open(PIKA_HAL_PWM, obj_getStr(self, "pin")); + if (NULL == dev) { + __platform_printf("Error: open PWM '%s' failed.\r\n", + obj_getStr(self, "pin")); + } + obj_setPtr(self, "pika_dev", dev); + return dev; +} + +void PikaStdDevice_PWM_platformEnable(PikaObj* self) { + pika_dev* dev = _get_dev(self); + pika_hal_ioctl(dev, PIKA_HAL_IOCTL_ENABLE); +} + +void PikaStdDevice_PWM_platformSetDuty(PikaObj* self) { + pika_float duty = obj_getFloat(self, "duty"); // 0.0 ~ 1.0 + uint32_t freq = obj_getInt(self, "freq"); // Hz + pika_hal_PWM_config cfg = {0}; + /* ns */ + cfg.duty = (uint32_t)(1000000000.0f / freq * duty); + pika_hal_ioctl(_get_dev(self), PIKA_HAL_IOCTL_CONFIG, &cfg); +} + +void PikaStdDevice_PWM_platformSetFrequency(PikaObj* self) { + uint32_t freq = obj_getInt(self, "freq"); // Hz + pika_float duty = obj_getFloat(self, "duty"); // 0.0 ~ 1.0 + pika_hal_PWM_config cfg = {0}; + /* ns */ + cfg.period = (uint32_t)(1000000000.0f / freq); + cfg.duty = (uint32_t)(1000000000.0f / freq * duty); + pika_hal_ioctl(_get_dev(self), PIKA_HAL_IOCTL_CONFIG, &cfg); +} + +void PikaStdDevice_PWM_platformDisable(PikaObj* self) { + pika_dev* dev = _get_dev(self); + pika_hal_ioctl(dev, PIKA_HAL_IOCTL_DISABLE); +} + +void PikaStdDevice_PWM_close(PikaObj* self) { + pika_dev* dev = _get_dev(self); + pika_hal_close(dev); +} diff --git a/examples/pikapython/pikapython/pikascript-lib/PikaStdDevice/PikaStdDevice_SPI.c b/examples/pikapython/pikapython/pikascript-lib/PikaStdDevice/PikaStdDevice_SPI.c new file mode 100755 index 00000000..fe55ddf1 --- /dev/null +++ b/examples/pikapython/pikapython/pikascript-lib/PikaStdDevice/PikaStdDevice_SPI.c @@ -0,0 +1,99 @@ +#include "PikaStdDevice_SPI.h" +#include "PikaStdDevice_common.h" + +void PikaStdDevice_SPI___init__(PikaObj* self) { + obj_setInt(self, "baudRate", 1000); + obj_setInt(self, "id", 0); + obj_setStr(self, "name", "none"); + obj_setInt(self, "phase", 0); + obj_setStr(self, "MISOpin", "none"); + obj_setStr(self, "MOSIpin", "none"); + obj_setStr(self, "SCKpin", "none"); + obj_setInt(self, "polarity", 0); +} + +void PikaStdDevice_SPI_disable(PikaObj* self) { + obj_runNativeMethod(self, "platformDisable", NULL); +} + +void PikaStdDevice_SPI_enable(PikaObj* self) { + obj_runNativeMethod(self, "platformEnable", NULL); +} + +void PikaStdDevice_SPI_write(PikaObj* self, char* data) { + obj_setStr(self, "writeData", data); + obj_runNativeMethod(self, "platformWrite", NULL); +} + +void PikaStdDevice_SPI_writeBytes(PikaObj* self, uint8_t* data, int length) { + obj_setBytes(self, "writeData", data, length); + obj_runNativeMethod(self, "platformWriteBytes", NULL); +} + +char* PikaStdDevice_SPI_read(PikaObj* self, int length) { + obj_setInt(self, "length", length); + obj_runNativeMethod(self, "platformRead", NULL); + return obj_getStr(self, "readData"); +} + +Arg* PikaStdDevice_SPI_readBytes(PikaObj* self, int length) { + obj_setInt(self, "length", length); + obj_runNativeMethod(self, "platformReadBytes", NULL); + return arg_copy(obj_getArg(self, "readData")); +} + +void PikaStdDevice_SPI_setBaudRate(PikaObj* self, int baudRate) { + obj_setInt(self, "baudRate", baudRate); +} + +void PikaStdDevice_SPI_setId(PikaObj* self, int id) { + obj_setInt(self, "id", id); +} + +void PikaStdDevice_SPI_setName(PikaObj* self, char* name) { + obj_setStr(self, "name", name); +} + +void PikaStdDevice_SPI_setPhase(PikaObj* self, int phase) { + obj_setInt(self, "phase", phase); +} + +void PikaStdDevice_SPI_setPinMISO(PikaObj* self, char* pin) { + obj_setStr(self, "MISOpin", pin); +} + +void PikaStdDevice_SPI_setPinMOSI(PikaObj* self, char* pin) { + obj_setStr(self, "MOSIpin", pin); +} + +void PikaStdDevice_SPI_setPinSCK(PikaObj* self, char* pin) { + obj_setStr(self, "SCKpin", pin); +} + +void PikaStdDevice_SPI_setPolarity(PikaObj* self, int polarity) { + obj_setInt(self, "polarity", polarity); +} + +void PikaStdDevice_SPI_platformDisable(PikaObj* self) { + ABSTRACT_METHOD_NEED_OVERRIDE_ERROR(); +} + +void PikaStdDevice_SPI_platformEnable(PikaObj* self) { + ABSTRACT_METHOD_NEED_OVERRIDE_ERROR(); +} + +void PikaStdDevice_SPI_platformWrite(PikaObj* self) { + ABSTRACT_METHOD_NEED_OVERRIDE_ERROR(); +} + +void PikaStdDevice_SPI_platformRead(PikaObj* self) { + ABSTRACT_METHOD_NEED_OVERRIDE_ERROR(); +} + +void PikaStdDevice_SPI_platformWriteBytes(PikaObj* self) { + ABSTRACT_METHOD_NEED_OVERRIDE_ERROR(); +} + +void PikaStdDevice_SPI_platformReadBytes(PikaObj* self) { + ABSTRACT_METHOD_NEED_OVERRIDE_ERROR(); +} diff --git a/examples/pikapython/pikapython/pikascript-lib/PikaStdDevice/PikaStdDevice_UART.c b/examples/pikapython/pikapython/pikascript-lib/PikaStdDevice/PikaStdDevice_UART.c new file mode 100755 index 00000000..af27e504 --- /dev/null +++ b/examples/pikapython/pikapython/pikascript-lib/PikaStdDevice/PikaStdDevice_UART.c @@ -0,0 +1,236 @@ +#include "PikaStdDevice_UART.h" +#include "PikaStdDevice_common.h" + +void PikaStdDevice_UART_enable(PikaObj* self) { + obj_runNativeMethod(self, "platformEnable", NULL); +} + +void PikaStdDevice_UART_disable(PikaObj* self) { + obj_runNativeMethod(self, "platformDisable", NULL); +} + +void PikaStdDevice_UART_init(PikaObj* self) { + /* const */ + obj_setInt(self, "FLOW_CONTROL_NONE", PIKA_HAL_UART_FLOW_CONTROL_NONE); + obj_setInt(self, "FLOW_CONTROL_RTS", PIKA_HAL_UART_FLOW_CONTROL_RTS); + obj_setInt(self, "FLOW_CONTROL_CTS", PIKA_HAL_UART_FLOW_CONTROL_CTS); + obj_setInt(self, "FLOW_CONTROL_RTS_CTS", + PIKA_HAL_UART_FLOW_CONTROL_RTS_CTS); + + obj_setInt(self, "SIGNAL_RX", PIKA_HAL_UART_EVENT_SIGNAL_RX); + obj_setInt(self, "SIGNAL_TX", PIKA_HAL_UART_EVENT_SIGNAL_TX); + + obj_setInt(self, "baudRate", 115200); + obj_setInt(self, "id", 1); + obj_setStr(self, "readBuff", ""); + obj_setInt(self, "flowControl", PIKA_HAL_UART_FLOW_CONTROL_NONE); + obj_setStr(self, "TXpin", "none"); + obj_setStr(self, "RXpin", "none"); + obj_setStr(self, "RTSpin", "none"); + obj_setStr(self, "CTSpin", "none"); +} + +void PikaStdDevice_UART___init__(PikaObj* self) { + PikaStdDevice_UART_init(self); +} + +char* PikaStdDevice_UART_read(PikaObj* self, int length) { + obj_setInt(self, "length", length); + obj_runNativeMethod(self, "platformRead", NULL); + return obj_getStr(self, "readData"); +} + +Arg* PikaStdDevice_UART_readBytes(PikaObj* self, int length) { + obj_setInt(self, "length", length); + obj_runNativeMethod(self, "platformReadBytes", NULL); + return arg_copy(obj_getArg(self, "readData")); +} + +void PikaStdDevice_UART_setBaudRate(PikaObj* self, int baudRate) { + obj_setInt(self, "baudRate", baudRate); +} + +void PikaStdDevice_UART_setFlowControl(PikaObj* self, int flowControl) { + obj_setInt(self, "flowControl", flowControl); +} + +void PikaStdDevice_UART_setId(PikaObj* self, int id) { + obj_setInt(self, "id", id); +} + +void PikaStdDevice_UART_write(PikaObj* self, char* data) { + obj_setStr(self, "writeData", data); + obj_runNativeMethod(self, "platformWrite", NULL); +} + +void PikaStdDevice_UART_writeBytes(PikaObj* self, uint8_t* data, int length) { + obj_setBytes(self, "writeData", data, length); + obj_runNativeMethod(self, "platformWriteBytes", NULL); +} + +static pika_dev* _get_dev(PikaObj* self) { + pika_dev* dev = obj_getPtr(self, "pika_dev"); + if (NULL != dev) { + return dev; + } + int id = obj_getInt(self, "id"); + char id_str[32] = {0}; + sprintf(id_str, "UART%d", id); + dev = pika_hal_open(PIKA_HAL_UART, id_str); + if (NULL == dev) { + __platform_printf("Error: open UART '%s' failed.\r\n", id_str); + } + obj_setPtr(self, "pika_dev", dev); + return dev; +} + +void PikaStdDevice_UART_platformEnable(PikaObj* self) { + pika_dev* dev = _get_dev(self); + if (NULL == dev) { + __platform_printf("Error: open UART '%d' failed.\r\n", + (int)obj_getInt(self, "id")); + return; + } + pika_hal_UART_config cfg = {0}; + cfg.baudrate = obj_getInt(self, "baudRate"); + cfg.flow_control = obj_getInt(self, "flowControl"); + if (!strEqu(obj_getStr(self, "TXpin"), "none")) { + cfg.TX = pika_hal_open(PIKA_HAL_GPIO, obj_getStr(self, "TXpin")); + if (NULL == cfg.TX) { + __platform_printf("Error: open GPIO '%s' failed.\r\n", + obj_getStr(self, "TXpin")); + } + } + if (!strEqu(obj_getStr(self, "RXpin"), "none")) { + cfg.RX = pika_hal_open(PIKA_HAL_GPIO, obj_getStr(self, "RXpin")); + if (NULL == cfg.RX) { + __platform_printf("Error: open GPIO '%s' failed.\r\n", + obj_getStr(self, "RXpin")); + } + } + if (!strEqu(obj_getStr(self, "RTSpin"), "none")) { + cfg.RTS = pika_hal_open(PIKA_HAL_GPIO, obj_getStr(self, "RTSpin")); + if (NULL == cfg.RTS) { + __platform_printf("Error: open GPIO '%s' failed.\r\n", + obj_getStr(self, "RTSpin")); + } + } + if (!strEqu(obj_getStr(self, "CTSpin"), "none")) { + cfg.CTS = pika_hal_open(PIKA_HAL_GPIO, obj_getStr(self, "CTSpin")); + if (NULL == cfg.CTS) { + __platform_printf("Error: open GPIO '%s' failed.\r\n", + obj_getStr(self, "CTSpin")); + } + } + int err = -1; + err = pika_hal_ioctl(dev, PIKA_HAL_IOCTL_CONFIG, &cfg); + if (err != 0) { + __platform_printf("Error: config UART '%d' failed.\r\n", + (int)obj_getInt(self, "id")); + return; + } + err = pika_hal_ioctl(dev, PIKA_HAL_IOCTL_ENABLE); + if (err != 0) { + __platform_printf("Error: enable UART '%d' failed.\r\n", + (int)obj_getInt(self, "id")); + return; + } +} + +void PikaStdDevice_UART_platformRead(PikaObj* self) { + int len = obj_getInt(self, "length"); + obj_setBytes(self, "_readData", NULL, len + 1); + char* buff = (char*)obj_getBytes(self, "_readData"); + pika_dev* dev = _get_dev(self); + int len_get = pika_hal_read(dev, buff, len); + buff[len_get] = 0; + obj_setStr(self, "readData", buff); +} + +void PikaStdDevice_UART_platformWrite(PikaObj* self) { + char* data = obj_getStr(self, "writeData"); + pika_dev* dev = _get_dev(self); + pika_hal_write(dev, data, strlen(data)); +} + +void PikaStdDevice_UART_platformDisable(PikaObj* self) { + pika_dev* dev = _get_dev(self); + if (NULL == dev) { + __platform_printf("Error: open UART '%d' failed.\r\n", + (int)obj_getInt(self, "id")); + return; + } + pika_hal_ioctl(dev, PIKA_HAL_IOCTL_DISABLE); +} + +void PikaStdDevice_UART_platformReadBytes(PikaObj* self) { + int len = obj_getInt(self, "length"); + obj_setBytes(self, "_readData", NULL, len + 1); + uint8_t* buff = obj_getBytes(self, "_readData"); + pika_dev* dev = _get_dev(self); + int len_get = pika_hal_read(dev, buff, len); + obj_setBytes(self, "readData", buff, len_get); +} + +void PikaStdDevice_UART_platformWriteBytes(PikaObj* self) { + uint8_t* data = obj_getBytes(self, "writeData"); + int len = obj_getBytesSize(self, "writeData"); + pika_dev* dev = _get_dev(self); + pika_hal_write(dev, data, len); +} + +void PikaStdDevice_UART_setCallBack(PikaObj* self, + Arg* eventCallBack, + int filter) { + pika_dev* dev = _get_dev(self); +#if PIKA_EVENT_ENABLE + _PikaStdDevice_setCallBack(self, eventCallBack, (uintptr_t)dev); + /* regist event to pika_hal */ + pika_hal_UART_config cfg_cb = {0}; + cfg_cb.event_callback = (void*)_PikaStdDevice_event_handler; + cfg_cb.event_callback_filter = filter; + cfg_cb.event_callback_ena = PIKA_HAL_EVENT_CALLBACK_ENA_ENABLE; + pika_hal_ioctl(dev, PIKA_HAL_IOCTL_CONFIG, &cfg_cb); +#else + obj_setErrorCode(self, 1); + obj_setSysOut(self, "[error] PIKA_EVENT_ENABLE is disabled."); +#endif +} + +void PikaStdDevice_UART_close(PikaObj* self) { + pika_dev* dev = _get_dev(self); + pika_hal_UART_config* cfg = (pika_hal_UART_config*)dev->ioctl_config; + if (NULL != cfg->TX) { + pika_hal_close(cfg->TX); + cfg->TX = NULL; + } + if (NULL != cfg->RX) { + pika_hal_close(cfg->RX); + cfg->RX = NULL; + } + if (NULL != cfg->RTS) { + pika_hal_close(cfg->RTS); + cfg->RTS = NULL; + } + if (NULL != cfg->CTS) { + pika_hal_close(cfg->CTS); + cfg->CTS = NULL; + } + pika_hal_close(dev); +} + +void PikaStdDevice_UART_setPinCTS(PikaObj* self, char* pin) { + obj_setStr(self, "CTSpin", pin); +} + +void PikaStdDevice_UART_setPinRTS(PikaObj* self, char* pin) { + obj_setStr(self, "RTSpin", pin); +} + +void PikaStdDevice_UART_setPinRX(PikaObj* self, char* pin) { + obj_setStr(self, "RXpin", pin); +} + +void PikaStdDevice_UART_setPinTX(PikaObj* self, char* pin) { + obj_setStr(self, "TXpin", pin); +} diff --git a/examples/pikapython/pikapython/pikascript-lib/PikaStdDevice/PikaStdDevice_common.c b/examples/pikapython/pikapython/pikascript-lib/PikaStdDevice/PikaStdDevice_common.c new file mode 100755 index 00000000..46e73440 --- /dev/null +++ b/examples/pikapython/pikapython/pikascript-lib/PikaStdDevice/PikaStdDevice_common.c @@ -0,0 +1,31 @@ +#include "PikaStdDevice_common.h" + +extern PikaEventListener* g_pika_device_event_listener; +void _PikaStdDevice_event_handler(pika_dev* dev, int signal) { + pks_eventListener_sendSignal(g_pika_device_event_listener, (uintptr_t)dev, + signal); +} + +void _PikaStdDevice_setCallBack(PikaObj* self, + Arg* eventCallback, + uint32_t eventId) { + obj_setArg(self, "eventCallBack", eventCallback); + /* init event_listener for the first time */ + if (NULL == g_pika_device_event_listener) { + pks_eventListener_init(&g_pika_device_event_listener); + } + /* regist event to event listener */ + pks_eventListener_registEvent(g_pika_device_event_listener, eventId, self); +} + +extern volatile PikaObj* __pikaMain; +PikaObj* PikaStdDevice_Time(PikaObj* self) { + PikaObj* time = obj_getPtr((PikaObj*)__pikaMain, "time"); + if(NULL == time){ + obj_setErrorCode(self, -1); + obj_setSysOut(self, "Error: please install and import 'time' module"); + return NULL; + } + obj_refcntInc(time); + return time; +} diff --git a/examples/pikapython/pikapython/pikascript-lib/PikaStdDevice/PikaStdDevice_common.h b/examples/pikapython/pikapython/pikascript-lib/PikaStdDevice/PikaStdDevice_common.h new file mode 100755 index 00000000..a8a19a86 --- /dev/null +++ b/examples/pikapython/pikapython/pikascript-lib/PikaStdDevice/PikaStdDevice_common.h @@ -0,0 +1,12 @@ +#ifndef _PIKA_STDDEVICE_COMMON_H +#define _PIKA_STDDEVICE_COMMON_H +#include "PikaObj.h" +#include "PikaVM.h" +#include "pika_hal.h" +void _PikaStdDevice_setCallBack(PikaObj* self, + Arg* eventCallback, + uint32_t eventId); + +void _PikaStdDevice_event_handler(pika_dev* dev, int signal); + +#endif diff --git a/examples/pikapython/pikapython/pikascript-lib/PikaStdDevice/pika_hal.c b/examples/pikapython/pikapython/pikascript-lib/PikaStdDevice/pika_hal.c new file mode 100755 index 00000000..117897e8 --- /dev/null +++ b/examples/pikapython/pikapython/pikascript-lib/PikaStdDevice/pika_hal.c @@ -0,0 +1,310 @@ +#include "pika_hal.h" +#include "PikaObj.h" + +#define PIKA_HAL_TABLE_FILE_API +#include "pika_hal_table.h" + +static const pika_dev_impl pika_dev_impl_list[] = { +#define PIKA_HAL_TABLE_IMPL +#include "pika_hal_table.h" +}; + +#define _PIKA_DEV_TYPE_MAX \ + (sizeof pika_dev_impl_list / sizeof pika_dev_impl_list[0]) + +static pika_dev_impl* _pika_dev_get_impl(PIKA_HAL_DEV_TYPE type) { + if (type >= _PIKA_DEV_TYPE_MAX) { + return NULL; + } + return (pika_dev_impl*)&pika_dev_impl_list[type]; +} + +static size_t _pika_hal_dev_config_size(PIKA_HAL_DEV_TYPE dev_type) { +#define PIKA_HAL_TABLE_DEV_CONFIG_SIZE +#include "pika_hal_table.h" + return 0; +} + +pika_dev* pika_hal_open(PIKA_HAL_DEV_TYPE dev_type, char* name) { + if (NULL == name) { + __platform_printf("Error: dev_open name is NULL.\r\n"); + return NULL; + } + int ret = -1; + pika_dev* dev = NULL; + if (dev_type >= _PIKA_DEV_TYPE_MAX) { + __platform_printf("Error: dev_type invalied.\r\n"); + goto __exit; + } + pika_dev_impl* impl = _pika_dev_get_impl(dev_type); + dev = (pika_dev*)pikaMalloc(sizeof(pika_dev)); + if (dev == NULL) { + goto __exit; + } + memset(dev, 0, sizeof(pika_dev)); + dev->type = dev_type; + dev->ioctl_config = pikaMalloc(_pika_hal_dev_config_size(dev_type)); + if (dev->ioctl_config == NULL) { + goto __exit; + } + memset(dev->ioctl_config, 0, _pika_hal_dev_config_size(dev_type)); + ret = impl->open(dev, name); +__exit: + if (0 == ret) { + return dev; + } + /* error */ + __platform_printf("Error: dev_open failed.\r\n"); + if (dev->ioctl_config) { + pikaFree(dev->ioctl_config, _pika_hal_dev_config_size(dev_type)); + dev->ioctl_config = NULL; + } + if (dev) { + pikaFree(dev, sizeof(pika_dev)); + } + return NULL; +} + +int pika_hal_close(pika_dev* dev) { + int ret = -1; + if (dev == NULL) { + goto __exit; + } + pika_dev_impl* impl = _pika_dev_get_impl(dev->type); + if (impl->close == NULL) { + goto __exit; + } + ret = impl->close(dev); +__exit: + if (NULL != dev->ioctl_config) { + pikaFree(dev->ioctl_config, _pika_hal_dev_config_size(dev->type)); + dev->ioctl_config = NULL; + } + if (NULL != dev) { + pikaFree(dev, sizeof(pika_dev)); + } + return ret; +} + +int pika_hal_read(pika_dev* dev, void* buf, size_t len) { + if (dev == NULL) { + return -1; + } + pika_dev_impl* impl = _pika_dev_get_impl(dev->type); + if (impl->read == NULL) { + return -1; + } + return impl->read(dev, buf, len); +} + +int pika_hal_write(pika_dev* dev, void* buf, size_t len) { + if (dev == NULL) { + return -1; + } + pika_dev_impl* impl = _pika_dev_get_impl(dev->type); + if (impl->write == NULL) { + return -1; + } + return impl->write(dev, buf, len); +} + +static const int _pika_hal_cmd_arg_cnt[] = { + [PIKA_HAL_IOCTL_CONFIG] = 1, + [PIKA_HAL_IOCTL_ENABLE] = 0, + [PIKA_HAL_IOCTL_DISABLE] = 0, +}; + +#define _PIKA_HAL_CMD_ARG_CNT_MAX \ + (sizeof _pika_hal_cmd_arg_cnt / sizeof _pika_hal_cmd_arg_cnt[0]) + +static int _pika_hal_get_arg_cnt(PIKA_HAL_IOCTL_CMD cmd) { + return _pika_hal_cmd_arg_cnt[PIKA_HAL_IOCTL_CONFIG]; +} + +int _pika_hal_ioctl_merge_config(pika_dev* dev, void* config_in) { +#define PIKA_HAL_TABLE_IOCTL_MERGE_CONFIG +#include "pika_hal_table.h" + return -1; +} + +int pika_hal_ioctl(pika_dev* dev, PIKA_HAL_IOCTL_CMD cmd, ...) { + int ret = -1; + PIKA_HAL_IOCTL_CMD cmd_origin = cmd; + if (dev == NULL) { + return -1; + } + cmd = _pika_hal_get_arg_cnt(cmd_origin); + if (cmd < 0) { + return -1; + } + pika_dev_impl* impl = _pika_dev_get_impl(dev->type); + if (impl->ioctl == NULL) { + return -1; + } + void* arg_in = NULL; + if (cmd != 0) { + va_list args; + va_start(args, cmd); + arg_in = va_arg(args, void*); + if (cmd_origin == PIKA_HAL_IOCTL_CONFIG) { + ret = _pika_hal_ioctl_merge_config(dev, arg_in); + } else { + ret = 0; + } + va_end(args); + if (0 != ret) { + return ret; + } + } + if (cmd_origin == PIKA_HAL_IOCTL_CONFIG) { + ret = impl->ioctl(dev, cmd_origin, dev->ioctl_config); + } else { + ret = impl->ioctl(dev, cmd_origin, arg_in); + } + if (ret == 0) { + if (cmd_origin == PIKA_HAL_IOCTL_ENABLE) { + dev->is_enabled = 1; + } + if (cmd_origin == PIKA_HAL_IOCTL_DISABLE) { + dev->is_enabled = 0; + } + } + return ret; +} + +#define _IOCTL_CONFIG_USE_DEFAULT(item, default) \ + if (src->item == 0) { \ + if (dst->item == 0) { \ + /* use default value */ \ + dst->item = default; \ + } else { \ + /* keep exist value */ \ + } \ + } else { \ + /* use input value */ \ + dst->item = src->item; \ + } + +#define _IOCTL_CONFIG_USE_DEFAULT_STR(item, default) \ + if (src->item[0] == '\0') { \ + if (dst->item[0] == '\0') { \ + /* use default value */ \ + strcpy(dst->item, default); \ + } else { \ + /* keep exist value */ \ + } \ + } else { \ + /* use input value */ \ + strcpy(dst->item, src->item); \ + } + +int pika_hal_GPIO_ioctl_merge_config(pika_hal_GPIO_config* dst, + pika_hal_GPIO_config* src) { + // printf("before merge: dst->dir=%d, src->dir=%d\r\n", dst->dir, src->dir); + _IOCTL_CONFIG_USE_DEFAULT(dir, PIKA_HAL_GPIO_DIR_IN); + // printf("after merge: dst->dir=%d, src->dir=%d\r\n", dst->dir, src->dir); + _IOCTL_CONFIG_USE_DEFAULT(pull, PIKA_HAL_GPIO_PULL_NONE); + _IOCTL_CONFIG_USE_DEFAULT(speed, PIKA_HAL_GPIO_SPEED_10M); + _IOCTL_CONFIG_USE_DEFAULT(event_callback, NULL); + _IOCTL_CONFIG_USE_DEFAULT(event_callback_filter, + PIKA_HAL_GPIO_EVENT_SIGNAL_RISING); + _IOCTL_CONFIG_USE_DEFAULT(event_callback_ena, + PIKA_HAL_EVENT_CALLBACK_ENA_ENABLE); + return 0; +} + +int pika_hal_UART_ioctl_merge_config(pika_hal_UART_config* dst, + pika_hal_UART_config* src) { + _IOCTL_CONFIG_USE_DEFAULT(baudrate, PIKA_HAL_UART_BAUDRATE_115200); + _IOCTL_CONFIG_USE_DEFAULT(data_bits, PIKA_HAL_UART_DATA_BITS_8); + _IOCTL_CONFIG_USE_DEFAULT(stop_bits, PIKA_HAL_UART_STOP_BITS_1); + _IOCTL_CONFIG_USE_DEFAULT(parity, PIKA_HAL_UART_PARITY_NONE); + _IOCTL_CONFIG_USE_DEFAULT(flow_control, PIKA_HAL_UART_FLOW_CONTROL_NONE); + _IOCTL_CONFIG_USE_DEFAULT(event_callback, NULL); + _IOCTL_CONFIG_USE_DEFAULT(event_callback_filter, + PIKA_HAL_UART_EVENT_SIGNAL_RX); + _IOCTL_CONFIG_USE_DEFAULT(event_callback_ena, + PIKA_HAL_EVENT_CALLBACK_ENA_ENABLE); + _IOCTL_CONFIG_USE_DEFAULT(TX, NULL); + _IOCTL_CONFIG_USE_DEFAULT(RX, NULL); + _IOCTL_CONFIG_USE_DEFAULT(RTS, NULL); + _IOCTL_CONFIG_USE_DEFAULT(CTS, NULL); + return 0; +} + +int pika_hal_SPI_ioctl_merge_config(pika_hal_SPI_config* dst, + pika_hal_SPI_config* src) { + _IOCTL_CONFIG_USE_DEFAULT(lsb_or_msb, PIKA_HAL_SPI_MSB); + _IOCTL_CONFIG_USE_DEFAULT(master_or_slave, PIKA_HAL_SPI_MASTER); + _IOCTL_CONFIG_USE_DEFAULT(mode, PIKA_HAL_SPI_MODE_0); + _IOCTL_CONFIG_USE_DEFAULT(data_width, PIKA_HAL_SPI_DATA_WIDTH_8); + _IOCTL_CONFIG_USE_DEFAULT(speed, PIKA_HAL_SPI_SPEED_2M); + _IOCTL_CONFIG_USE_DEFAULT(timeout, PIKA_HAL_SPI_TIMEOUT_1000MS); + return 0; +} + +int pika_hal_SOFT_SPI_ioctl_merge_config(pika_hal_SOFT_SPI_config* dst, + pika_hal_SOFT_SPI_config* src) { + _IOCTL_CONFIG_USE_DEFAULT(lsb_or_msb, PIKA_HAL_SPI_MSB); + _IOCTL_CONFIG_USE_DEFAULT(master_or_slave, PIKA_HAL_SPI_MASTER); + _IOCTL_CONFIG_USE_DEFAULT(mode, PIKA_HAL_SPI_MODE_0); + _IOCTL_CONFIG_USE_DEFAULT(data_width, PIKA_HAL_SPI_DATA_WIDTH_8); + _IOCTL_CONFIG_USE_DEFAULT(speed, PIKA_HAL_SPI_SPEED_2M); + _IOCTL_CONFIG_USE_DEFAULT(timeout, PIKA_HAL_SPI_TIMEOUT_1000MS); + _IOCTL_CONFIG_USE_DEFAULT(CS, NULL); + _IOCTL_CONFIG_USE_DEFAULT(SCK, NULL); + _IOCTL_CONFIG_USE_DEFAULT(MOSI, NULL); + _IOCTL_CONFIG_USE_DEFAULT(MISO, NULL); + return 0; +} + +int pika_hal_IIC_ioctl_merge_config(pika_hal_IIC_config* dst, + pika_hal_IIC_config* src) { + _IOCTL_CONFIG_USE_DEFAULT(address_width, PIKA_HAL_IIC_ADDRESS_WIDTH_7BIT); + _IOCTL_CONFIG_USE_DEFAULT(master_or_slave, PIKA_HAL_IIC_MASTER); + _IOCTL_CONFIG_USE_DEFAULT(slave_addr, 0); + _IOCTL_CONFIG_USE_DEFAULT(mem_addr_ena, PIKA_HAL_IIC_MEM_ADDR_ENA_DISABLE); + _IOCTL_CONFIG_USE_DEFAULT(mem_addr_size, PIKA_HAL_IIC_MEM_ADDR_SIZE_8BIT); + dst->mem_addr = src->mem_addr; + _IOCTL_CONFIG_USE_DEFAULT(speed, PIKA_HAL_IIC_SPEED_100K); + _IOCTL_CONFIG_USE_DEFAULT(timeout, PIKA_HAL_IIC_TIMEOUT_1000MS); + return 0; +} + +int pika_hal_PWM_ioctl_merge_config(pika_hal_PWM_config* dst, + pika_hal_PWM_config* src) { + _IOCTL_CONFIG_USE_DEFAULT(period, PIKA_HAL_PWM_PERIOD_1MS * 10); + // _IOCTL_CONFIG_USE_DEFAULT(duty, 0); + dst->duty = src->duty; + return 0; +} + +int pika_hal_ADC_ioctl_merge_config(pika_hal_ADC_config* dst, + pika_hal_ADC_config* src) { + _IOCTL_CONFIG_USE_DEFAULT(sampling_resolution, PIKA_HAL_ADC_RESOLUTION_12); + _IOCTL_CONFIG_USE_DEFAULT(sampling_freq, PIKA_HAL_ADC_SAMPLING_FREQ_100); + _IOCTL_CONFIG_USE_DEFAULT(continue_or_single, PIKA_HAL_ADC_SINGLE); + _IOCTL_CONFIG_USE_DEFAULT(vref, (pika_float)3.3); + _IOCTL_CONFIG_USE_DEFAULT(max, 8192); + return 0; +} + +int pika_hal_DAC_ioctl_merge_config(pika_hal_DAC_config* dst, + pika_hal_DAC_config* src) { + _IOCTL_CONFIG_USE_DEFAULT(speed, PIKA_HAL_DAC_SPEED_1K * 8); + _IOCTL_CONFIG_USE_DEFAULT(sampling_resolution, PIKA_HAL_DAC_RESOLUTION_12); + _IOCTL_CONFIG_USE_DEFAULT(vref, (pika_float)3.3); + _IOCTL_CONFIG_USE_DEFAULT(max, 3300000); + return 0; +} + +int pika_hal_WIFI_ioctl_merge_config(pika_hal_WIFI_config* dst, + pika_hal_WIFI_config* src) { + _IOCTL_CONFIG_USE_DEFAULT(mode, PIKA_HAL_WIFI_MODE_STA); + _IOCTL_CONFIG_USE_DEFAULT(channel, PIKA_HAL_WIFI_CHANNEL_0); + _IOCTL_CONFIG_USE_DEFAULT(max_connection, PIKA_HAL_WIFI_MAX_CONNECTION_4); + _IOCTL_CONFIG_USE_DEFAULT_STR(ap_ssid, "pikapython.com"); + _IOCTL_CONFIG_USE_DEFAULT_STR(ap_bssid, ""); + _IOCTL_CONFIG_USE_DEFAULT_STR(ap_password, "pikapython.com"); + return 0; +} diff --git a/examples/pikapython/pikapython/pikascript-lib/PikaStdDevice/pika_hal.h b/examples/pikapython/pikapython/pikascript-lib/PikaStdDevice/pika_hal.h new file mode 100755 index 00000000..b2df4bd9 --- /dev/null +++ b/examples/pikapython/pikapython/pikascript-lib/PikaStdDevice/pika_hal.h @@ -0,0 +1,486 @@ +#ifndef _PIKA_DEV_HAL_H +#define _PIKA_DEV_HAL_H +#include +#include +#include "PikaObj.h" + +/* + * pika_hal is a C Device HAL lib for PikaScript modules. + * the API of pika_hal is similar to the posix file API. + */ + +typedef enum { +#define PIKA_HAL_TABLE_DEV_TYPE +#include "pika_hal_table.h" +} PIKA_HAL_DEV_TYPE; + +typedef struct { + PIKA_HAL_DEV_TYPE type; + PIKA_BOOL is_enabled; + void* ioctl_config; + void* platform_data; +} pika_dev; + +typedef enum { + PIKA_HAL_IOCTL_CONFIG, + PIKA_HAL_IOCTL_ENABLE, + PIKA_HAL_IOCTL_DISABLE, + PIKA_HAL_IOCTL_WIFI_GET_ACTIVE, + PIKA_HAL_IOCTL_WIFI_GET_STATUS, + PIKA_HAL_IOCTL_WIFI_SCAN, + PIKA_HAL_IOCTL_WIFI_CONNECT, + PIKA_HAL_IOCTL_WIFI_DISCONNECT, + PIKA_HAL_IOCTL_WIFI_SET_IFCONFIG, + PIKA_HAL_IOCTL_WIFI_GET_IFCONFIG, + _ = 0xFFFFFFFF, // make sure it is 4 byte width +} PIKA_HAL_IOCTL_CMD; + +/* posix file like API */ +pika_dev* pika_hal_open(PIKA_HAL_DEV_TYPE dev_type, char* name); +int pika_hal_close(pika_dev* dev); +int pika_hal_read(pika_dev* dev, void* buf, size_t len); +int pika_hal_write(pika_dev* dev, void* buf, size_t len); +int pika_hal_ioctl(pika_dev* dev, PIKA_HAL_IOCTL_CMD cmd, ...); + +typedef enum { + _PIKA_HAL_GPIO_DIR_UNUSED = 0, + PIKA_HAL_GPIO_DIR_IN, + PIKA_HAL_GPIO_DIR_OUT, +} PIKA_HAL_GPIO_DIR; + +typedef enum { + _PIKA_HAL_GPIO_PULL_UNUSED = 0, + PIKA_HAL_GPIO_PULL_NONE, + PIKA_HAL_GPIO_PULL_UP, + PIKA_HAL_GPIO_PULL_DOWN, +} PIKA_HAL_GPIO_PULL; + +typedef enum { + _PIKA_HAL_GPIO_SPEED_UNUSED = 0, + PIKA_HAL_GPIO_SPEED_1M = 1000000, + PIKA_HAL_GPIO_SPEED_2M = 2000000, + PIKA_HAL_GPIO_SPEED_5M = 5000000, + PIKA_HAL_GPIO_SPEED_10M = 10000000, + PIKA_HAL_GPIO_SPEED_20M = 20000000, + PIKA_HAL_GPIO_SPEED_50M = 50000000, + PIKA_HAL_GPIO_SPEED_100M = 100000000, +} PIKA_HAL_GPIO_SPEED; + +typedef enum { + _PIKA_HAL_EVENT_CALLBACK_ENA_UNUSED = 0, + PIKA_HAL_EVENT_CALLBACK_ENA_ENABLE, + PIKA_HAL_EVENT_CALLBACK_ENA_DISABLE, +} PIKA_HAL_EVENT_CALLBACK_ENA; + +typedef enum { + _PIKA_HAL_GPIO_EVENT_SIGNAL_UNUSED = 0, + PIKA_HAL_GPIO_EVENT_SIGNAL_RISING, + PIKA_HAL_GPIO_EVENT_SIGNAL_FALLING, + PIKA_HAL_GPIO_EVENT_SIGNAL_ANY, +} PIKA_HAL_GPIO_EVENT_SIGNAL; + +typedef struct { + PIKA_HAL_GPIO_DIR dir; + PIKA_HAL_GPIO_PULL pull; + PIKA_HAL_GPIO_SPEED speed; + void (*event_callback)(pika_dev* dev, PIKA_HAL_GPIO_EVENT_SIGNAL signal); + PIKA_HAL_GPIO_EVENT_SIGNAL event_callback_filter; + PIKA_HAL_EVENT_CALLBACK_ENA event_callback_ena; +} pika_hal_GPIO_config; + +typedef enum { + _PIKA_HAL_UART_BAUDRATE_UNUSED = 0, + PIKA_HAL_UART_BAUDRATE_9600 = 9600, + PIKA_HAL_UART_BAUDRATE_19200 = 19200, + PIKA_HAL_UART_BAUDRATE_38400 = 38400, + PIKA_HAL_UART_BAUDRATE_57600 = 57600, + PIKA_HAL_UART_BAUDRATE_115200 = 115200, + PIKA_HAL_UART_BAUDRATE_2000000 = 2000000, + PIKA_HAL_UART_BAUDRATE_10000000 = 10000000, +} PIKA_HAL_UART_BAUDRATE; + +typedef enum { + _PIKA_HAL_UART_DATA_BITS_UNUSED = 0, + PIKA_HAL_UART_DATA_BITS_5 = 5, + PIKA_HAL_UART_DATA_BITS_6 = 6, + PIKA_HAL_UART_DATA_BITS_7 = 7, + PIKA_HAL_UART_DATA_BITS_8 = 8, +} PIKA_HAL_UART_DATA_BITS; + +typedef enum { + _PIKA_HAL_UART_STOP_BITS_UNUSED = 0, + PIKA_HAL_UART_STOP_BITS_1 = 1, + PIKA_HAL_UART_STOP_BITS_2 = 2, + PIKA_HAL_UART_STOP_BITS_1_5 = 3, +} PIKA_HAL_UART_STOP_BITS; + +typedef enum { + _PIKA_HAL_UART_PARITY_UNUSED = 0, + PIKA_HAL_UART_PARITY_NONE, + PIKA_HAL_UART_PARITY_ODD, + PIKA_HAL_UART_PARITY_EVEN, +} PIKA_HAL_UART_PARITY; + +typedef enum { + _PIKA_HAL_UART_EVENT_SIGNAL_UNUSED = 0, + PIKA_HAL_UART_EVENT_SIGNAL_RX, + PIKA_HAL_UART_EVENT_SIGNAL_TX, + PIKA_HAL_UART_EVENT_SIGNAL_ANY, +} PIKA_HAL_UART_EVENT_SIGNAL; + +typedef enum { + _PIKA_HAL_UART_FLOW_CONTROL_UNUSED = 0, + PIKA_HAL_UART_FLOW_CONTROL_NONE, + PIKA_HAL_UART_FLOW_CONTROL_RTS, + PIKA_HAL_UART_FLOW_CONTROL_CTS, + PIKA_HAL_UART_FLOW_CONTROL_RTS_CTS, +} PIKA_HAL_UART_FLOW_CONTROL; + +typedef struct { + PIKA_HAL_UART_BAUDRATE baudrate; + PIKA_HAL_UART_DATA_BITS data_bits; + PIKA_HAL_UART_STOP_BITS stop_bits; + PIKA_HAL_UART_PARITY parity; + PIKA_HAL_UART_FLOW_CONTROL flow_control; + void (*event_callback)(pika_dev* dev, PIKA_HAL_UART_EVENT_SIGNAL signal); + PIKA_HAL_UART_EVENT_SIGNAL event_callback_filter; + PIKA_HAL_EVENT_CALLBACK_ENA event_callback_ena; + pika_dev* TX; + pika_dev* RX; + pika_dev* RTS; + pika_dev* CTS; +} pika_hal_UART_config; + +typedef uint32_t PIKA_HAL_IIC_SLAVE_ADDR; +typedef uint32_t PIKA_HAL_IIC_MEM_ADDR; + +typedef enum PIKA_HAL_IIC_MEM_ADDR_SIZE { + _PIKA_HAL_IIC_MEM_ADDR_SIZE_UNUSED = 0, + PIKA_HAL_IIC_MEM_ADDR_SIZE_8BIT = 1, + PIKA_HAL_IIC_MEM_ADDR_SIZE_16BIT = 2, + PIKA_HAL_IIC_MEM_ADDR_SIZE_24BIT = 3, + PIKA_HAL_IIC_MEM_ADDR_SIZE_32BIT = 4, +} PIKA_HAL_IIC_MEM_ADDR_SIZE; + +typedef enum PIKA_HAL_IIC_MEM_ADDR_ENA { + _PIKA_HAL_IIC_MEM_ADDR_ENA_UNUSED = 0, + PIKA_HAL_IIC_MEM_ADDR_ENA_DISABLE, + PIKA_HAL_IIC_MEM_ADDR_ENA_ENABLE, +} PIKA_HAL_IIC_MEM_ADDR_ENA; + +typedef enum { + _PIKA_HAL_IIC_SPEED_UNUSED = 0, + PIKA_HAL_IIC_SPEED_100K = 100000, + PIKA_HAL_IIC_SPEED_400K = 400000, + PIKA_HAL_IIC_SPEED_1M = 1000000, +} PIKA_HAL_IIC_SPEED; + +typedef enum PIKA_HAL_IIC_MASTER_OR_SLAVE { + _PIKA_HAL_IIC_MASTER_OR_SLAVE_UNUSED = 0, + PIKA_HAL_IIC_MASTER, + PIKA_HAL_IIC_SLAVE, +} PIKA_HAL_IIC_MASTER_OR_SLAVE; + +typedef enum PIKA_HAL_IIC_ADDRESS_WIDTH { + _PIKA_HAL_IIC_ADDRESS_WIDTH_UNUSED = 0, + PIKA_HAL_IIC_ADDRESS_WIDTH_7BIT = 7, + PIKA_HAL_IIC_ADDRESS_WIDTH_10BIT = 10, +} PIKA_HAL_IIC_ADDRESS_WIDTH; + +typedef enum PIKA_HAL_IIC_TIMEOUT { + _PIKA_HAL_IIC_TIMEOUT_UNUSED = 0, + PIKA_HAL_IIC_TIMEOUT_1MS = 1, + PIKA_HAL_IIC_TIMEOUT_2MS = 2, + PIKA_HAL_IIC_TIMEOUT_5MS = 5, + PIKA_HAL_IIC_TIMEOUT_10MS = 10, + PIKA_HAL_IIC_TIMEOUT_20MS = 20, + PIKA_HAL_IIC_TIMEOUT_50MS = 50, + PIKA_HAL_IIC_TIMEOUT_100MS = 100, + PIKA_HAL_IIC_TIMEOUT_200MS = 200, + PIKA_HAL_IIC_TIMEOUT_500MS = 500, + PIKA_HAL_IIC_TIMEOUT_1000MS = 1000, +} PIKA_HAL_IIC_TIMEOUT; + +typedef struct { + PIKA_HAL_IIC_ADDRESS_WIDTH address_width; + PIKA_HAL_IIC_MASTER_OR_SLAVE master_or_slave; + PIKA_HAL_IIC_SLAVE_ADDR slave_addr; + PIKA_HAL_IIC_MEM_ADDR_ENA mem_addr_ena; + PIKA_HAL_IIC_MEM_ADDR mem_addr; + PIKA_HAL_IIC_MEM_ADDR_SIZE mem_addr_size; + PIKA_HAL_IIC_SPEED speed; + PIKA_HAL_IIC_TIMEOUT timeout; +} pika_hal_IIC_config; + +typedef enum PIKA_HAL_SPI_TIMEOUT { + _PIKA_HAL_SPI_TIMEOUT_UNUSED = 0, + PIKA_HAL_SPI_TIMEOUT_1MS = 1, + PIKA_HAL_SPI_TIMEOUT_2MS = 2, + PIKA_HAL_SPI_TIMEOUT_5MS = 5, + PIKA_HAL_SPI_TIMEOUT_10MS = 10, + PIKA_HAL_SPI_TIMEOUT_20MS = 20, + PIKA_HAL_SPI_TIMEOUT_50MS = 50, + PIKA_HAL_SPI_TIMEOUT_100MS = 100, + PIKA_HAL_SPI_TIMEOUT_200MS = 200, + PIKA_HAL_SPI_TIMEOUT_500MS = 500, + PIKA_HAL_SPI_TIMEOUT_1000MS = 1000, +} PIKA_HAL_SPI_TIMEOUT; + +typedef enum { + _PIKA_HAL_SPI_LSB_OR_MSB_UNUSED = 0, + PIKA_HAL_SPI_LSB, + PIKA_HAL_SPI_MSB, +} PIKA_HAL_SPI_LSB_OR_MSB; + +typedef enum { + _PIKA_HAL_SPI_MASTER_OR_SLAVE_UNUSED = 0, + PIKA_HAL_SPI_MASTER, + PIKA_HAL_SPI_SLAVE, +} PIKA_HAL_SPI_MASTER_OR_SLAVE; + +typedef enum { + _PIKA_HAL_SPI_MODE_UNUSED = 0, + PIKA_HAL_SPI_MODE_0, + PIKA_HAL_SPI_MODE_1, + PIKA_HAL_SPI_MODE_2, + PIKA_HAL_SPI_MODE_3, +} PIKA_HAL_SPI_MODE; + +typedef enum { + _PIKA_HAL_SPI_DATA_UNUSED = 0, + PIKA_HAL_SPI_DATA_WIDTH_8 = 8, + PIKA_HAL_SPI_DATA_WIDTH_16 = 16, +} PIKA_HAL_SPI_DATA_WIDTH; + +typedef enum { + _PIKA_HAL_SPI_SPEED_UNUSED = 0, + PIKA_HAL_SPI_SPEED_1M = 1000000, + PIKA_HAL_SPI_SPEED_2M = 2000000, + PIKA_HAL_SPI_SPEED_5M = 5000000, + PIKA_HAL_SPI_SPEED_10M = 10000000, + PIKA_HAL_SPI_SPEED_20M = 20000000, + PIKA_HAL_SPI_SPEED_50M = 50000000, + PIKA_HAL_SPI_SPEED_100M = 100000000, +} PIKA_HAL_SPI_SPEED; + +typedef struct { + PIKA_HAL_SPI_LSB_OR_MSB lsb_or_msb; + PIKA_HAL_SPI_MASTER_OR_SLAVE master_or_slave; + PIKA_HAL_SPI_MODE mode; + PIKA_HAL_SPI_DATA_WIDTH data_width; + PIKA_HAL_SPI_SPEED speed; + PIKA_HAL_SPI_TIMEOUT timeout; +} pika_hal_SPI_config; + +typedef struct { + PIKA_HAL_SPI_LSB_OR_MSB lsb_or_msb; + PIKA_HAL_SPI_MASTER_OR_SLAVE master_or_slave; + PIKA_HAL_SPI_MODE mode; + PIKA_HAL_SPI_DATA_WIDTH data_width; + PIKA_HAL_SPI_SPEED speed; + PIKA_HAL_SPI_TIMEOUT timeout; + pika_dev* CS; + pika_dev* SCK; + pika_dev* MOSI; + pika_dev* MISO; +} pika_hal_SOFT_SPI_config; + +typedef enum { + _PIKA_HAL_ADC_RESOLUTION_UNUSED = 0, + PIKA_HAL_ADC_RESOLUTION_8 = 8, + PIKA_HAL_ADC_RESOLUTION_10 = 10, + PIKA_HAL_ADC_RESOLUTION_12 = 12, + PIKA_HAL_ADC_RESOLUTION_14 = 14, + PIKA_HAL_ADC_RESOLUTION_16 = 16, +} PIKA_HAL_ADC_RESOLUTION; + +typedef enum PIKA_HAL_ADC_SAMPLING_FREQ { + _PIKA_HAL_ADC_SAMPLING_FREQ_UNUSED = 0, + PIKA_HAL_ADC_SAMPLING_FREQ_100 = 100, + PIKA_HAL_ADC_SAMPLING_FREQ_1K = 1000, + PIKA_HAL_ADC_SAMPLING_FREQ_10K = 10000, + PIKA_HAL_ADC_SAMPLING_FREQ_100K = 100000, + PIKA_HAL_ADC_SAMPLING_FREQ_1M = 1000000, + PIKA_HAL_ADC_SAMPLING_FREQ_10M = 10000000, +} PIKA_HAL_ADC_SAMPLING_FREQ; + +typedef enum PIKA_HAL_ADC_CONTINUOU_OR_SINGLE { + _PIKA_HAL_ADC_CONTINUOU_OR_SINGLE_UNUSED = 0, + PIKA_HAL_ADC_SINGLE, + PIKA_HAL_ADC_CONTINUOU, +} PIKA_HAL_ADC_CONTINUOU_OR_SINGLE; + +typedef pika_float PIKA_HAL_ADC_VREF; +typedef uint32_t PIKA_HAL_ADC_MAX; + +typedef struct { + PIKA_HAL_ADC_RESOLUTION sampling_resolution; + PIKA_HAL_ADC_SAMPLING_FREQ sampling_freq; + PIKA_HAL_ADC_CONTINUOU_OR_SINGLE continue_or_single; + PIKA_HAL_ADC_MAX max; + PIKA_HAL_ADC_VREF vref; +} pika_hal_ADC_config; + +typedef enum { + _PIKA_HAL_DAC_RESOLUTION_UNUSED = 0, + PIKA_HAL_DAC_RESOLUTION_8 = 8, + PIKA_HAL_DAC_RESOLUTION_10 = 10, + PIKA_HAL_DAC_RESOLUTION_12 = 12, + PIKA_HAL_DAC_RESOLUTION_14 = 14, + PIKA_HAL_DAC_RESOLUTION_16 = 16, +} PIKA_HAL_DAC_RESOLUTION; + +typedef enum PIKA_HAL_DAC_SPEED { + _PIKA_HAL_DAC_SPEED_UNUSED = 0, + PIKA_HAL_DAC_SPEED_100 = 100, + PIKA_HAL_DAC_SPEED_1K = 1000, + PIKA_HAL_DAC_SPEED_10K = 10000, + PIKA_HAL_DAC_SPEED_100K = 100000, + PIKA_HAL_DAC_SPEED_1M = 1000000, + PIKA_HAL_DAC_SPEED_10M = 10000000, + PIKA_HAL_DAC_SPEED_20M = 20000000, + PIKA_HAL_DAC_SPEED_50M = 50000000, + PIKA_HAL_DAC_SPEED_100M = 100000000, +} PIKA_HAL_DAC_SPEED; + +typedef pika_float PIKA_HAL_DAC_VREF; +typedef uint32_t PIKA_HAL_DAC_MAX; + +typedef struct pika_hal_DAC_config { + PIKA_HAL_DAC_RESOLUTION sampling_resolution; + PIKA_HAL_DAC_SPEED speed; + PIKA_HAL_DAC_MAX max; + PIKA_HAL_DAC_VREF vref; +} pika_hal_DAC_config; + +typedef enum { + _PIKA_HAL_DAC_UNUSED = 0, + PIKA_HAL_PWM_CHANNEL_0, + PIKA_HAL_PWM_CHANNEL_1, + PIKA_HAL_PWM_CHANNEL_2, + PIKA_HAL_PWM_CHANNEL_3, + PIKA_HAL_PWM_CHANNEL_4, + PIKA_HAL_PWM_CHANNEL_5, + PIKA_HAL_PWM_CHANNEL_6, + PIKA_HAL_PWM_CHANNEL_7, +} PIKA_HAL_PWM_CHANNEL; + +typedef enum { + PIKA_HAL_PWM_PERIOD_1NS = 1, + PIKA_HAL_PWM_PERIOD_1US = 1000, + PIKA_HAL_PWM_PERIOD_1MS = 1000000, + PIKA_HAL_PWM_PERIOD_1S = 1000000000, +} PIKA_HAL_PWM_PERIOD; + +typedef enum { + PIKA_HAL_PWM_DUTY_1NS = 1, + PIKA_HAL_PWM_DUTY_1US = 1000, + PIKA_HAL_PWM_DUTY_1MS = 1000000, + PIKA_HAL_PWM_DUTY_1S = 1000000000, +} PIKA_HAL_PWM_DUTY; + +typedef struct { + PIKA_HAL_PWM_PERIOD period; + PIKA_HAL_PWM_DUTY duty; +} pika_hal_PWM_config; + +typedef enum { + _PIKA_HAL_WIFI_MODE_UNUSED = 0, + PIKA_HAL_WIFI_MODE_STA, + PIKA_HAL_WIFI_MODE_AP, +} PIKA_HAL_WIFI_MODE; + +typedef enum { + _PIKA_HAL_WIFI_STATUS_UNUSED = 0, + PIKA_HAL_WIFI_STATUS_IDLE, + PIKA_HAL_WIFI_STATUS_CONNECTING, + PIKA_HAL_WIFI_STATUS_WRONG_PASSWORD, + PIKA_HAL_WIFI_STATUS_NO_AP_FOUND, + PIKA_HAL_WIFI_STATUS_CONNECT_FAIL, + PIKA_HAL_WIFI_STATUS_GOT_IP, +} PIKA_HAL_WIFI_STATUS; + +typedef enum { + _PIKA_HAL_WIFI_CHANNEL_UNUSED = 0, + PIKA_HAL_WIFI_CHANNEL_0, + PIKA_HAL_WIFI_CHANNEL_1, + PIKA_HAL_WIFI_CHANNEL_2, + PIKA_HAL_WIFI_CHANNEL_3, + PIKA_HAL_WIFI_CHANNEL_4, + PIKA_HAL_WIFI_CHANNEL_5, + PIKA_HAL_WIFI_CHANNEL_6, + PIKA_HAL_WIFI_CHANNEL_7, + PIKA_HAL_WIFI_CHANNEL_8, + PIKA_HAL_WIFI_CHANNEL_9, + PIKA_HAL_WIFI_CHANNEL_10, + PIKA_HAL_WIFI_CHANNEL_11, +} PIKA_HAL_WIFI_CHANNEL; + +typedef enum { + _PIKA_HAL_WIFI_MAX_CONNECTION = 0, + PIKA_HAL_WIFI_MAX_CONNECTION_1, + PIKA_HAL_WIFI_MAX_CONNECTION_2, + PIKA_HAL_WIFI_MAX_CONNECTION_3, + PIKA_HAL_WIFI_MAX_CONNECTION_4, + PIKA_HAL_WIFI_MAX_CONNECTION_5, + PIKA_HAL_WIFI_MAX_CONNECTION_6, + PIKA_HAL_WIFI_MAX_CONNECTION_7, + PIKA_HAL_WIFI_MAX_CONNECTION_8, + PIKA_HAL_WIFI_MAX_CONNECTION_9, + PIKA_HAL_WIFI_MAX_CONNECTION_10 +} PIKA_HAL_WIFI_MAX_CONNECTION; + +#define PIKA_HAL_WIFI_PARAM_MAX_LEN 32 +typedef struct pika_hal_WIFI_config { + PIKA_HAL_WIFI_MODE mode; + PIKA_HAL_WIFI_CHANNEL channel; + PIKA_HAL_WIFI_MAX_CONNECTION max_connection; + char ap_ssid[PIKA_HAL_WIFI_PARAM_MAX_LEN]; + char ap_bssid[PIKA_HAL_WIFI_PARAM_MAX_LEN]; + char ap_password[PIKA_HAL_WIFI_PARAM_MAX_LEN]; +} pika_hal_WIFI_config; + +typedef struct pika_hal_WIFI_connect_config { + char ssid[PIKA_HAL_WIFI_PARAM_MAX_LEN]; + char bssid[PIKA_HAL_WIFI_PARAM_MAX_LEN]; + char password[PIKA_HAL_WIFI_PARAM_MAX_LEN]; +} pika_hal_WIFI_connect_config; + +typedef struct pika_hal_WIFI_ifconfig { + char ip[PIKA_HAL_WIFI_PARAM_MAX_LEN]; + char netmask[PIKA_HAL_WIFI_PARAM_MAX_LEN]; + char gateway[PIKA_HAL_WIFI_PARAM_MAX_LEN]; + char dns[PIKA_HAL_WIFI_PARAM_MAX_LEN]; +} pika_hal_WIFI_ifconfig; + +typedef struct pika_hal_WIFI_record { + char ssid[PIKA_HAL_WIFI_PARAM_MAX_LEN]; + uint8_t bssid[PIKA_HAL_WIFI_PARAM_MAX_LEN]; + size_t bssid_len; + int channel; + int rssi; + int authmode; +} pika_hal_WIFI_record; + +typedef struct pika_hal_WIFI_scan_result { + int count; + pika_hal_WIFI_record records[]; +} pika_hal_WIFI_scan_result; + +typedef struct pika_dev_impl { + int (*open)(pika_dev* dev, char* name); + int (*close)(pika_dev* dev); + int (*read)(pika_dev* dev, void* buf, size_t count); + int (*write)(pika_dev* dev, void* buf, size_t count); + int (*ioctl)(pika_dev* dev, PIKA_HAL_IOCTL_CMD cmd, void* cfg); +} pika_dev_impl; + +/* platform API */ +#define PIKA_HAL_TABLE_PLATFORM_API +#include "pika_hal_table.h" + +/* config merge headers */ +#define PIKA_HAL_TABLE_IOCTL_MERGE_CONFIG_HEADER +#include "pika_hal_table.h" + +#endif diff --git a/examples/pikapython/pikapython/pikascript-lib/PikaStdDevice/pika_hal_SOFT_SPI.c b/examples/pikapython/pikapython/pikascript-lib/PikaStdDevice/pika_hal_SOFT_SPI.c new file mode 100755 index 00000000..d34d2bfb --- /dev/null +++ b/examples/pikapython/pikapython/pikascript-lib/PikaStdDevice/pika_hal_SOFT_SPI.c @@ -0,0 +1,155 @@ +#include "../PikaStdDevice/pika_hal.h" + +static int _GPIO_write(pika_dev* dev, uint32_t val) { + return pika_hal_write(dev, &val, sizeof(val)); +} + +static uint32_t _GPIO_read(pika_dev* dev) { + uint32_t val = 0; + pika_hal_read(dev, &val, sizeof(val)); + return val; +} + +int pika_hal_platform_SOFT_SPI_open(pika_dev* dev, char* name) { + return 0; +} + +int pika_hal_platform_SOFT_SPI_close(pika_dev* dev) { + pika_hal_SOFT_SPI_config* cfg = + (pika_hal_SOFT_SPI_config*)dev->ioctl_config; + if (cfg->CS != NULL) { + pika_hal_close(cfg->CS); + } + if (cfg->SCK != NULL) { + pika_hal_close(cfg->SCK); + } + if (cfg->MOSI != NULL) { + pika_hal_close(cfg->MOSI); + } + if (cfg->MISO != NULL) { + pika_hal_close(cfg->MISO); + } + return 0; +} + +int pika_hal_platform_SOFT_SPI_ioctl_config(pika_dev* dev, + pika_hal_SOFT_SPI_config* cfg) { + if (cfg->SCK == NULL || cfg->MOSI == NULL) { + __platform_printf( + "Error: SOFT SPI config error, CS, SCK, MOSI, MISO must be " + "set\r\n"); + return -1; + } + return 0; +} + +int pika_hal_platform_SOFT_SPI_ioctl_enable(pika_dev* dev) { + pika_hal_SOFT_SPI_config* cfg = + (pika_hal_SOFT_SPI_config*)dev->ioctl_config; + if (cfg->SCK == NULL || cfg->MOSI == NULL) { + __platform_printf( + "Error: SOFT SPI config error, CS, SCK, MOSI, MISO must be " + "set\r\n"); + return -1; + } + pika_hal_GPIO_config cfg_CS = {0}; + pika_hal_GPIO_config cfg_SCK = {0}; + pika_hal_GPIO_config cfg_MOSI = {0}; + pika_hal_GPIO_config cfg_MISO = {0}; + cfg_CS.dir = PIKA_HAL_GPIO_DIR_OUT; + cfg_SCK.dir = PIKA_HAL_GPIO_DIR_OUT; + cfg_MOSI.dir = PIKA_HAL_GPIO_DIR_OUT; + cfg_MISO.dir = PIKA_HAL_GPIO_DIR_IN; + + if (NULL != cfg->CS) { + pika_hal_ioctl(cfg->CS, PIKA_HAL_IOCTL_CONFIG, &cfg_CS); + } + pika_hal_ioctl(cfg->SCK, PIKA_HAL_IOCTL_CONFIG, &cfg_SCK); + pika_hal_ioctl(cfg->MOSI, PIKA_HAL_IOCTL_CONFIG, &cfg_MOSI); + if (NULL != cfg->MISO) { + pika_hal_ioctl(cfg->MISO, PIKA_HAL_IOCTL_CONFIG, &cfg_MISO); + } + + if (NULL != cfg->CS) { + pika_hal_ioctl(cfg->CS, PIKA_HAL_IOCTL_ENABLE); + } + pika_hal_ioctl(cfg->SCK, PIKA_HAL_IOCTL_ENABLE); + pika_hal_ioctl(cfg->MOSI, PIKA_HAL_IOCTL_ENABLE); + if (NULL != cfg->MISO) { + pika_hal_ioctl(cfg->MISO, PIKA_HAL_IOCTL_ENABLE); + } + + if (NULL != cfg->CS) { + _GPIO_write(cfg->CS, 1); + } + _GPIO_write(cfg->SCK, 1); + _GPIO_write(cfg->MOSI, 1); + return 0; +} + +int pika_hal_platform_SOFT_SPI_ioctl_disable(pika_dev* dev) { + pika_hal_SOFT_SPI_config* cfg = + (pika_hal_SOFT_SPI_config*)dev->ioctl_config; + if (NULL != cfg->CS) { + pika_hal_ioctl(cfg->CS, PIKA_HAL_IOCTL_DISABLE); + } + pika_hal_ioctl(cfg->SCK, PIKA_HAL_IOCTL_DISABLE); + pika_hal_ioctl(cfg->MOSI, PIKA_HAL_IOCTL_DISABLE); + if (NULL != cfg->MISO) { + pika_hal_ioctl(cfg->MISO, PIKA_HAL_IOCTL_DISABLE); + } + return 0; +} + +static inline int SPIv_WriteData(pika_hal_SOFT_SPI_config* cfg, uint8_t Data) { + unsigned char i = 0; + for (i = 8; i > 0; i--) { + if (Data & 0x80) + _GPIO_write(cfg->MOSI, 1); + else + _GPIO_write(cfg->MOSI, 0); + _GPIO_write(cfg->SCK, 0); + _GPIO_write(cfg->SCK, 1); + Data <<= 1; + } + return 0; +} + +int pika_hal_platform_SOFT_SPI_write(pika_dev* dev, void* buf, size_t count) { + pika_hal_SOFT_SPI_config* cfg = + (pika_hal_SOFT_SPI_config*)dev->ioctl_config; + uint8_t* data = (uint8_t*)buf; + if (NULL != cfg->CS) { + _GPIO_write(cfg->CS, 0); + } + for (int i = 0; i < count; i++) { + SPIv_WriteData(cfg, data[i]); + } + if (NULL != cfg->CS) { + _GPIO_write(cfg->CS, 1); + } + return count; +} + +int pika_hal_platform_SOFT_SPI_read(pika_dev* dev, void* buf, size_t count) { + pika_hal_SOFT_SPI_config* cfg = + (pika_hal_SOFT_SPI_config*)dev->ioctl_config; + if (NULL == cfg->MISO) { + __platform_printf("Error: SOFT SPI config error, MISO must be set\r\n"); + return -1; + } + uint8_t* data = (uint8_t*)buf; + if (NULL != cfg->CS) { + _GPIO_write(cfg->CS, 0); + } + for (int i = 0; i < count; i++) { + data[i] = 0; + for (int j = 0; j < 8; j++) { + _GPIO_write(cfg->SCK, 0); + _GPIO_write(cfg->SCK, 1); + data[i] |= (_GPIO_read(cfg->MISO) << (7 - j)); + } + } + _GPIO_write(cfg->CS, 1); + return count; +} diff --git a/examples/pikapython/pikapython/pikascript-lib/PikaStdDevice/pika_hal_table.h b/examples/pikapython/pikapython/pikascript-lib/PikaStdDevice/pika_hal_table.h new file mode 100755 index 00000000..682558bf --- /dev/null +++ b/examples/pikapython/pikapython/pikascript-lib/PikaStdDevice/pika_hal_table.h @@ -0,0 +1,14 @@ +#include "pika_hal_table_rule.h" + +/* clang-format off */ + +pika_hal_table_add(GPIO) +pika_hal_table_add(UART) +pika_hal_table_add(IIC) +pika_hal_table_add(SPI) +pika_hal_table_add(ADC) +pika_hal_table_add(DAC) +pika_hal_table_add(PWM) +pika_hal_table_add(SOFT_SPI) +pika_hal_table_add(WIFI) + diff --git a/examples/pikapython/pikapython/pikascript-lib/PikaStdDevice/pika_hal_table_rule.h b/examples/pikapython/pikapython/pikascript-lib/PikaStdDevice/pika_hal_table_rule.h new file mode 100755 index 00000000..70a7cef5 --- /dev/null +++ b/examples/pikapython/pikapython/pikascript-lib/PikaStdDevice/pika_hal_table_rule.h @@ -0,0 +1,121 @@ +#undef pika_hal_table_add +#if defined(PIKA_HAL_TABLE_FILE_API) +#define pika_hal_table_add(dev_name) \ + PIKA_WEAK int pika_hal_platform_##dev_name##_open(pika_dev* dev, \ + char* name) { \ + WEAK_FUNCTION_NEED_OVERRIDE_ERROR() \ + return -1; \ + } \ + PIKA_WEAK int pika_hal_platform_##dev_name##_close(pika_dev* dev) { \ + WEAK_FUNCTION_NEED_OVERRIDE_ERROR() \ + return -1; \ + } \ + PIKA_WEAK int pika_hal_platform_##dev_name##_read(pika_dev* dev, \ + void* buf, size_t len) { \ + WEAK_FUNCTION_NEED_OVERRIDE_ERROR() \ + return -1; \ + } \ + PIKA_WEAK int pika_hal_platform_##dev_name##_write( \ + pika_dev* dev, void* buf, size_t len) { \ + WEAK_FUNCTION_NEED_OVERRIDE_ERROR() \ + return -1; \ + } \ + PIKA_WEAK int pika_hal_platform_##dev_name##_ioctl_enable(pika_dev* dev) { \ + WEAK_FUNCTION_NEED_OVERRIDE_ERROR() \ + return -1; \ + } \ + PIKA_WEAK int pika_hal_platform_##dev_name##_ioctl_disable( \ + pika_dev* dev) { \ + WEAK_FUNCTION_NEED_OVERRIDE_ERROR() \ + return -1; \ + } \ + PIKA_WEAK int pika_hal_platform_##dev_name##_ioctl_config( \ + pika_dev* dev, pika_hal_##dev_name##_config* cfg) { \ + WEAK_FUNCTION_NEED_OVERRIDE_ERROR() \ + return -1; \ + } \ + PIKA_WEAK int pika_hal_platform_##dev_name##_ioctl_others( \ + pika_dev* dev, PIKA_HAL_IOCTL_CMD cmd, void* arg) { \ + WEAK_FUNCTION_NEED_OVERRIDE_ERROR() \ + return -1; \ + } \ + int pika_hal_##dev_name##_ioctl(pika_dev* dev, PIKA_HAL_IOCTL_CMD cmd, \ + void* arg) { \ + if (NULL == dev) { \ + return -1; \ + } \ + switch (cmd) { \ + case PIKA_HAL_IOCTL_ENABLE: \ + return pika_hal_platform_##dev_name##_ioctl_enable(dev); \ + case PIKA_HAL_IOCTL_DISABLE: \ + return pika_hal_platform_##dev_name##_ioctl_disable(dev); \ + case PIKA_HAL_IOCTL_CONFIG: \ + return pika_hal_platform_##dev_name##_ioctl_config( \ + dev, (pika_hal_##dev_name##_config*)arg); \ + default: \ + return pika_hal_platform_##dev_name##_ioctl_others(dev, cmd, \ + arg); \ + } \ + } + +#endif + +#if defined(PIKA_HAL_TABLE_DEV_TYPE) +#define pika_hal_table_add(dev_name) PIKA_HAL_##dev_name, +#endif + +#if defined(PIKA_HAL_TABLE_IMPL) +#define pika_hal_table_add(dev_name) \ + [PIKA_HAL_##dev_name] = { \ + .open = pika_hal_platform_##dev_name##_open, \ + .close = pika_hal_platform_##dev_name##_close, \ + .read = pika_hal_platform_##dev_name##_read, \ + .write = pika_hal_platform_##dev_name##_write, \ + .ioctl = pika_hal_##dev_name##_ioctl, \ + }, +#endif + +#if defined(PIKA_HAL_TABLE_PLATFORM_API) +#define pika_hal_table_add(dev_name) \ + int pika_hal_platform_##dev_name##_open(pika_dev* dev, char* name); \ + int pika_hal_platform_##dev_name##_close(pika_dev* dev); \ + int pika_hal_platform_##dev_name##_read(pika_dev* dev, void* buf, \ + size_t len); \ + int pika_hal_platform_##dev_name##_write(pika_dev* dev, void* buf, \ + size_t len); \ + int pika_hal_platform_##dev_name##_ioctl_enable(pika_dev* dev); \ + int pika_hal_platform_##dev_name##_ioctl_disable(pika_dev* dev); \ + int pika_hal_platform_##dev_name##_ioctl_config( \ + pika_dev* dev, pika_hal_##dev_name##_config* cfg); \ + int pika_hal_platform_##dev_name##_ioctl_others( \ + pika_dev* dev, PIKA_HAL_IOCTL_CMD cmd, void* arg); +#endif + +#if defined(PIKA_HAL_TABLE_DEV_CONFIG_SIZE) +#define pika_hal_table_add(dev_name) \ + if (dev_type == PIKA_HAL_##dev_name) { \ + return sizeof(pika_hal_##dev_name##_config); \ + } +#endif + +#if defined(PIKA_HAL_TABLE_IOCTL_MERGE_CONFIG) +#define pika_hal_table_add(dev_name) \ + if (dev->type == PIKA_HAL_##dev_name) { \ + return pika_hal_##dev_name##_ioctl_merge_config(dev->ioctl_config, \ + config_in); \ + } +#endif + +#if defined(PIKA_HAL_TABLE_IOCTL_MERGE_CONFIG_HEADER) +#define pika_hal_table_add(dev_name) \ + int pika_hal_##dev_name##_ioctl_merge_config( \ + pika_hal_##dev_name##_config* dst, pika_hal_##dev_name##_config* src); +#endif + +#undef PIKA_HAL_TABLE_FILE_API +#undef PIKA_HAL_TABLE_DEV_TYPE +#undef PIKA_HAL_TABLE_IMPL +#undef PIKA_HAL_TABLE_PLATFORM_API +#undef PIKA_HAL_TABLE_DEV_CONFIG_SIZE +#undef PIKA_HAL_TABLE_IOCTL_MERGE_CONFIG +#undef PIKA_HAL_TABLE_IOCTL_MERGE_CONFIG_HEADER diff --git a/examples/pikapython/pikapython/pikascript-lib/PikaStdLib/PikaStdData_FILEIO.c b/examples/pikapython/pikapython/pikascript-lib/PikaStdLib/PikaStdData_FILEIO.c index 38b54a9f..6ebb7139 100644 --- a/examples/pikapython/pikapython/pikascript-lib/PikaStdLib/PikaStdData_FILEIO.c +++ b/examples/pikapython/pikapython/pikascript-lib/PikaStdLib/PikaStdData_FILEIO.c @@ -3,30 +3,13 @@ #include "PikaCompiler.h" #include "PikaStdData_List.h" -typedef struct { - uint8_t* addr; - size_t size; - size_t pos; -} PIKAFS_FILE; - int PikaStdData_FILEIO_init(PikaObj* self, char* path, char* mode) { if (obj_isArgExist(self, "_f")) { /* already initialized */ return 0; } if (strIsStartWith(path, "pikafs/")) { - PIKAFS_FILE* f = (PIKAFS_FILE*)pikaMalloc(sizeof(PIKAFS_FILE)); - memset(f, 0, sizeof(PIKAFS_FILE)); - extern volatile PikaObj* __pikaMain; - uint8_t* library_bytes = obj_getPtr((PikaObj*)__pikaMain, "@libraw"); - if (NULL == library_bytes) { - return 1; - } - char* file_name = path + 7; - if (PIKA_RES_OK != _loadModuleDataWithName(library_bytes, file_name, - &f->addr, &f->size)) { - return 1; - } + pikafs_FILE* f = pikafs_fopen(path + 7, "rb"); obj_setInt(self, "pikafs", PIKA_TRUE); obj_setPtr(self, "_f", f); obj_setStr(self, "_mode", mode); @@ -43,11 +26,11 @@ int PikaStdData_FILEIO_init(PikaObj* self, char* path, char* mode) { void PikaStdData_FILEIO_close(PikaObj* self) { if (PIKA_TRUE == obj_getInt(self, "pikafs")) { - PIKAFS_FILE* f = obj_getPtr(self, "_f"); + pikafs_FILE* f = obj_getPtr(self, "_f"); if (NULL == f) { return; } - pikaFree(f, sizeof(PIKAFS_FILE)); + pikafs_fclose(f); obj_setPtr(self, "_f", NULL); return; } @@ -59,18 +42,6 @@ void PikaStdData_FILEIO_close(PikaObj* self) { obj_setPtr(self, "_f", NULL); } -size_t _pikafs_fread(void* buf, size_t size, size_t count, PIKAFS_FILE* f) { - if (f->pos >= f->size) { - return 0; - } - if (f->pos + size * count > f->size) { - count = (f->size - f->pos) / size; - } - __platform_memcpy(buf, f->addr + f->pos, size * count); - f->pos += size * count; - return count; -} - Arg* PikaStdData_FILEIO_read(PikaObj* self, PikaTuple* size_) { int size = 0; if (pikaTuple_getSize(size_) == 0) { @@ -87,11 +58,11 @@ Arg* PikaStdData_FILEIO_read(PikaObj* self, PikaTuple* size_) { int n = 0; /* read */ if (PIKA_TRUE == obj_getInt(self, "pikafs")) { - PIKAFS_FILE* f = obj_getPtr(self, "_f"); + pikafs_FILE* f = obj_getPtr(self, "_f"); if (NULL == f) { return NULL; } - n = _pikafs_fread(buf, 1, size, f); + n = pikafs_fread(buf, 1, size, f); } else { FILE* f = obj_getPtr(self, "_f"); if (f == NULL) { diff --git a/examples/pikapython/pikapython/pikascript-lib/PikaStdLib/PikaStdData_String.c b/examples/pikapython/pikapython/pikascript-lib/PikaStdLib/PikaStdData_String.c index 6dc463ef..a8d7391d 100644 --- a/examples/pikapython/pikapython/pikascript-lib/PikaStdLib/PikaStdData_String.c +++ b/examples/pikapython/pikapython/pikascript-lib/PikaStdLib/PikaStdData_String.c @@ -2,6 +2,7 @@ #include "PikaStdData_List.h" #include "PikaStdData_String_Util.h" #include "dataStrs.h" +#include "PikaVM.h" char* _strlwr(char* str); static int string_len(char* str); @@ -87,7 +88,7 @@ char* string_slice(Args* outBuffs, char* str, int start, int end) { start += string_len(str); } /* magic code, to the end */ - if (end == -99999) { + if (end == VM_PC_EXIT) { end = string_len(str); } if (end < 0) { @@ -251,19 +252,26 @@ PikaObj* PikaStdData_String_split(PikaObj* self, char* s) { Args buffs = {0}; char* str = strsCopy(&buffs, obj_getStr(self, "str")); - char sign = s[0]; - int token_num = strCountSign(str, sign) + 1; + /* split str with s by strstr() */ - for (int i = 0; i < token_num; i++) { - char* token = strsPopToken(&buffs, &str, sign); - /* 用 arg_set 的 api 创建 arg */ - Arg* token_arg = arg_newStr(token); - /* 添加到 list 对象 */ - PikaStdData_List_append(list, token_arg); - /* 销毁 arg */ - arg_deinit(token_arg); + size_t spliter_len = strGetSize(s); + char* p = str; + while (1) { + char* q = strstr(p, s); + if (q == NULL) { + break; + } + *q = '\0'; + Arg* arg_item = arg_newStr(p); + PikaStdData_List_append(list, arg_item); + arg_deinit(arg_item); + p = q + spliter_len; + } + if (*p != '\0') { + Arg* arg_item = arg_newStr(p); + PikaStdData_List_append(list, arg_item); + arg_deinit(arg_item); } - strsDeinit(&buffs); return list; } diff --git a/examples/pikapython/pikapython/pikascript-lib/PikaStdLib/PikaStdData_Tuple.c b/examples/pikapython/pikapython/pikascript-lib/PikaStdLib/PikaStdData_Tuple.c index 93f047cf..6a2f63e9 100644 --- a/examples/pikapython/pikapython/pikascript-lib/PikaStdLib/PikaStdData_Tuple.c +++ b/examples/pikapython/pikapython/pikascript-lib/PikaStdLib/PikaStdData_Tuple.c @@ -32,7 +32,14 @@ Arg* PikaStdData_Tuple___next__(PikaObj* self) { } Arg* PikaStdData_Tuple___getitem__(PikaObj* self, Arg* __key) { - return PikaStdData_Tuple_get(self, arg_getInt(__key)); + int i = arg_getInt(__key); + PikaList* list = obj_getPtr(self, "list"); + if (i < 0 || i >= pikaList_getSize(list)) { + obj_setErrorCode(self, PIKA_RES_ERR_INDEX); + obj_setSysOut(self, "IndexError: index out of range"); + return NULL; + } + return PikaStdData_Tuple_get(self, i); } void PikaStdData_Tuple___del__(PikaObj* self) { diff --git a/examples/pikapython/pikapython/pikascript-lib/PikaStdLib/PikaStdLib_SysObj.c b/examples/pikapython/pikapython/pikascript-lib/PikaStdLib/PikaStdLib_SysObj.c index e1f7e024..ee226e2d 100644 --- a/examples/pikapython/pikapython/pikascript-lib/PikaStdLib/PikaStdLib_SysObj.c +++ b/examples/pikapython/pikapython/pikascript-lib/PikaStdLib/PikaStdLib_SysObj.c @@ -28,25 +28,34 @@ Arg* PikaStdLib_SysObj_type(PikaObj* self, Arg* arg) { } ArgType type = arg_getType(arg); if (ARG_TYPE_INT == type) { - return arg_newStr(""); + return arg_copy(obj_getMethodArg(self, "int")); } if (ARG_TYPE_FLOAT == type) { - return arg_newStr(""); + return arg_copy(obj_getMethodArg(self, "float")); } if (ARG_TYPE_STRING == type) { - return arg_newStr(""); + return arg_copy(obj_getMethodArg(self, "str")); + } + if (ARG_TYPE_BOOL == type) { + return arg_copy(obj_getMethodArg(self, "bool")); } if (argType_isObject(type)) { PikaObj* obj = arg_getPtr(arg); NewFun clsptr = obj_getClass(obj); PikaObj* New_PikaStdData_List(Args * args); + /* list */ if (clsptr == New_PikaStdData_List) { - return arg_newStr(""); + return arg_copy(obj_getMethodArg(self, "list")); } /* dict */ PikaObj* New_PikaStdData_Dict(Args * args); if (clsptr == New_PikaStdData_Dict) { - return arg_newStr(""); + return arg_copy(obj_getMethodArg(self, "dict")); + } + /* tuple */ + PikaObj* New_PikaStdData_Tuple(Args * args); + if (clsptr == New_PikaStdData_Tuple) { + return arg_copy(obj_getMethodArg(self, "tuple")); } return arg_newStr(""); } @@ -82,77 +91,82 @@ pika_float PikaStdLib_SysObj_float(PikaObj* self, Arg* arg) { if (ARG_TYPE_STRING == type) { return strtod(arg_getStr(arg), NULL); } + if (ARG_TYPE_BOOL == type) { + return (float)arg_getBool(arg); + } obj_setSysOut(self, "[error] convert to pika_float type failed."); obj_setErrorCode(self, 1); - return -99999.99999; + return _PIKA_FLOAT_ERR; } -int PikaStdLib_SysObj_int(PikaObj* self, Arg* arg) { +PIKA_RES _transeInt(Arg* arg, int* res) { ArgType type = arg_getType(arg); if (ARG_TYPE_INT == type) { - return (int)arg_getInt(arg); + *res = (int)arg_getInt(arg); + return PIKA_RES_OK; + } + if (ARG_TYPE_BOOL == type) { + *res = (int)arg_getBool(arg); + return PIKA_RES_OK; } if (ARG_TYPE_FLOAT == type) { - return (int)arg_getFloat(arg); + *res = (int)arg_getFloat(arg); + return PIKA_RES_OK; } if (ARG_TYPE_STRING == type) { - return (int)fast_atoi(arg_getStr(arg)); + *res = (int)fast_atoi(arg_getStr(arg)); + return PIKA_RES_OK; } if (ARG_TYPE_BYTES == type) { size_t size = arg_getBytesSize(arg); if (size != 1) { - obj_setSysOut(self, "ValueError: invalid literal for int()"); - obj_setErrorCode(self, 1); - return -999999999; + return PIKA_RES_ERR_INVALID_PARAM; } uint8_t val = *arg_getBytes(arg); - return val; + *res = val; + return PIKA_RES_OK; } - obj_setSysOut(self, "[error] convert to int type failed."); + return PIKA_RES_ERR_INVALID_PARAM; +} + +int PikaStdLib_SysObj_int(PikaObj* self, Arg* arg) { + int res = 0; + if (_transeInt(arg, &res) == PIKA_RES_OK) { + return res; + } + obj_setSysOut(self, "ValueError: invalid literal for int()"); obj_setErrorCode(self, 1); - return -999999999; + return _PIKA_INT_ERR; +} + +PIKA_BOOL PikaStdLib_SysObj_bool(PikaObj* self, Arg* arg) { + int res = 0; + if (_transeInt(arg, &res) == PIKA_RES_OK) { + return res ? PIKA_TRUE : PIKA_FALSE; + } + obj_setSysOut(self, "ValueError: invalid literal for bool()"); + obj_setErrorCode(self, 1); + return _PIKA_BOOL_ERR; } char* PikaStdLib_SysObj_str(PikaObj* self, Arg* arg) { - obj_removeArg(self, "__buf"); - ArgType type = arg_getType(arg); - Args buffs = {0}; - char* res = ""; - if (ARG_TYPE_INT == type) { - int val = arg_getInt(arg); - res = strsFormat(&buffs, 11, "%d", val); - goto exit; + // if (arg_getType(arg) == ARG_TYPE_BYTES) { + // return obj_cacheStr(self, (char*)arg_getBytes(arg)); + // } + Arg* arg_str = arg_toStrArg(arg); + if (NULL == arg_str) { + obj_setSysOut(self, "Error: convert to str type failed."); + obj_setErrorCode(self, 1); + return NULL; } - if (ARG_TYPE_FLOAT == type) { - pika_float val = arg_getFloat(arg); - res = strsFormat(&buffs, 11, "%f", val); - goto exit; - } - if (ARG_TYPE_BYTES == type) { - res = (char*)arg_getBytes(arg); - goto exit; - } - if (ARG_TYPE_STRING == type) { - res = arg_getStr(arg); - } - if (ARG_TYPE_NONE == type) { - res = "None"; - } - if (argType_isObject(type)) { - res = obj_toStr(arg_getPtr(arg)); - if (NULL != res) { - goto exit; - } - } -exit: - obj_setStr(self, "__buf", res); - strsDeinit(&buffs); - return obj_getStr(self, "__buf"); + char* str = obj_cacheStr(self, arg_getStr(arg_str)); + arg_deinit(arg_str); + return str; } Arg* PikaStdLib_SysObj_iter(PikaObj* self, Arg* arg) { /* object */ - PIKA_BOOL is_temp = 0; + PIKA_BOOL is_temp = PIKA_FALSE; PikaObj* arg_obj = _arg_to_obj(arg, &is_temp); NewFun _clsptr = (NewFun)arg_obj->constructor; if (_clsptr == New_PikaStdLib_RangeObj) { @@ -343,8 +357,8 @@ Arg* PikaStdLib_SysObj_list(PikaObj* self, PikaTuple* val) { #else obj_setErrorCode(self, 1); __platform_printf("[Error] built-in list is not enabled.\r\n"); -#endif return arg_newNull(); +#endif } Arg* PikaStdLib_SysObj_dict(PikaObj* self, PikaTuple* val) { @@ -358,6 +372,18 @@ Arg* PikaStdLib_SysObj_dict(PikaObj* self, PikaTuple* val) { #endif } +Arg* PikaStdLib_SysObj_tuple(PikaObj* self, Arg* val) { +#if PIKA_BUILTIN_STRUCT_ENABLE + obj_setErrorCode(self, 1); + __platform_printf("Error: tuple() is not supported.\r\n"); + return arg_newNull(); +#else + obj_setErrorCode(self, 1); + __platform_printf("[Error] built-in tuple is not enabled.\r\n"); + return arg_newNull(); +#endif +} + char* PikaStdLib_SysObj_hex(PikaObj* self, int val) { char buff[PIKA_SPRINTF_BUFF_SIZE] = {0}; if (val >= 0) { @@ -422,61 +448,6 @@ Arg* PikaStdLib_SysObj_bytes(PikaObj* self, Arg* val) { return arg_newNull(); } -static char* __print_arg(PikaObj* self, Arg* val) { - Args buffs = {0}; - char* res = NULL; - if (NULL == val) { - goto __exit; - } - ArgType arg_type = arg_getType(val); - if (arg_type == ARG_TYPE_BYTES) { - res = __printBytes(self, val); - goto __exit; - } - if (arg_type == ARG_TYPE_STRING) { - res = arg_getStr(val); - goto __exit; - } - if (arg_type == ARG_TYPE_NONE) { - res = "None"; - goto __exit; - } - if (arg_type == ARG_TYPE_INT) { - int64_t value = arg_getInt(val); -#if PIKA_PRINT_LLD_ENABLE - res = strsFormat(&buffs, 32, "%lld", value); -#else - res = strsFormat(&buffs, 32, "%d", value); -#endif - goto __exit; - } - if (arg_type == ARG_TYPE_FLOAT) { - pika_float value = arg_getFloat(val); - res = strsFormat(&buffs, 32, "%f", value); - goto __exit; - } - if (arg_type == ARG_TYPE_POINTER || - arg_type == ARG_TYPE_METHOD_NATIVE_CONSTRUCTOR) { - void* value = arg_getPtr(val); - res = strsFormat(&buffs, 32, "%p", value); - goto __exit; - } - if (argType_isObject(arg_type)) { - res = obj_toStr(arg_getPtr(val)); - goto __exit; - } -__exit: - if (NULL == res) { - obj_setSysOut(self, "Error: can not print val"); - obj_setErrorCode(self, 1); - } - if (NULL != res) { - res = obj_cacheStr(self, res); - } - strsDeinit(&buffs); - return res; -} - void PikaStdLib_SysObj_print(PikaObj* self, PikaTuple* val, PikaDict* ops) { int arg_size = pikaTuple_getSize(val); char* end = pikaDict_getStr(ops, "end"); @@ -485,23 +456,25 @@ void PikaStdLib_SysObj_print(PikaObj* self, PikaTuple* val, PikaDict* ops) { end = "\r\n"; } if (arg_size == 1) { - arg_singlePrint(pikaTuple_getArg(val, 0), PIKA_FALSE, end); + arg_print(pikaTuple_getArg(val, 0), PIKA_FALSE, end); return; } Arg* print_out_arg = NULL; PIKA_BOOL is_get_print = PIKA_FALSE; for (int i = 0; i < arg_size; i++) { Arg* arg = pikaTuple_getArg(val, i); - char* item = __print_arg(self, arg); - if (NULL != item) { + Arg* item_arg_str = arg_toStrArg(arg); + if (NULL != item_arg_str) { is_get_print = PIKA_TRUE; if (NULL == print_out_arg) { print_out_arg = arg_newStr(""); } - print_out_arg = arg_strAppend(print_out_arg, item); + print_out_arg = + arg_strAppend(print_out_arg, arg_getStr(item_arg_str)); if (i < arg_size - 1) { print_out_arg = arg_strAppend(print_out_arg, " "); } + arg_deinit(item_arg_str); } } if (PIKA_TRUE == is_get_print) { @@ -559,7 +532,7 @@ PikaObj* PikaStdLib_SysObj_open(PikaObj* self, char* path, char* mode) { int32_t __dir_each(Arg* argEach, Args* context) { PikaObj* list = args_getPtr(context, "list"); if (argType_isCallable(arg_getType(argEach))) { - char name_buff[PIKA_LINE_BUFF_SIZE / 2] = {0}; + char name_buff[PIKA_LINE_BUFF_SIZE] = {0}; char* method_name = methodArg_getName(argEach, name_buff, sizeof(name_buff)); Arg* arg_str = arg_newStr(method_name); @@ -569,7 +542,13 @@ int32_t __dir_each(Arg* argEach, Args* context) { return 0; } -PikaObj* PikaStdLib_SysObj_dir(PikaObj* self, PikaObj* obj) { +PikaObj* PikaStdLib_SysObj_dir(PikaObj* self, Arg* arg) { + if (!argType_isObject(arg_getType(arg))) { + obj_setErrorCode(self, 1); + __platform_printf("[Error] dir: not support type.\r\n"); + return NULL; + } + PikaObj* obj = arg_getPtr(arg); PikaObj* New_PikaStdData_List(Args * args); PikaObj* list = newNormalObj(New_PikaStdData_List); __vm_List___init__(list); @@ -682,3 +661,7 @@ void PikaStdLib_SysObj_help(PikaObj* self, char* name) { obj_printModules((PikaObj*)__pikaMain); } } + +void PikaStdLib_SysObj_reboot(PikaObj* self) { + pika_platform_reboot(); +} diff --git a/examples/pikapython/pikapython/pikascript-lib/_thread/_thread.c b/examples/pikapython/pikapython/pikascript-lib/_thread/_thread.c new file mode 100755 index 00000000..df1c0d32 --- /dev/null +++ b/examples/pikapython/pikapython/pikascript-lib/_thread/_thread.c @@ -0,0 +1,59 @@ +#include "_thread.h" +#include "PikaVM.h" + +typedef struct pika_thread_info { + Arg* function; + Arg* args; + pika_platform_thread_t* thread; +} pika_thread_info; + +static void _thread_func(void* arg) { + pika_debug("waiting for first lock"); + while (!_VM_is_first_lock()) { + pika_platform_thread_delay(); + } + pika_debug("thread start"); + pika_GIL_ENTER(); + PikaObj* ctx = New_PikaObj(); + pika_thread_info* info = (pika_thread_info*)arg; + obj_setArg(ctx, "args", info->args); + obj_setArg(ctx, "thread", info->function); + /* clang-format off */ + PIKA_PYTHON( + thread(*args) + ) + /* clang-format on */ + const uint8_t bytes[] = { + 0x0c, 0x00, 0x00, 0x00, /* instruct array size */ + 0x20, 0x81, 0x01, 0x00, 0x10, 0x08, 0x06, 0x00, 0x00, 0x02, 0x08, 0x00, + /* instruct array */ + 0x0f, 0x00, 0x00, 0x00, /* const pool size */ + 0x00, 0x61, 0x72, 0x67, 0x73, 0x00, 0x2a, 0x00, 0x74, 0x68, 0x72, 0x65, + 0x61, 0x64, 0x00, /* const pool */ + }; + pikaVM_runByteCode(ctx, (uint8_t*)bytes); + obj_deinit(ctx); + arg_deinit(info->function); + arg_deinit(info->args); + pika_debug("thread exiting"); + pika_platform_thread_t* thread = info->thread; + pikaFree(info, sizeof(pika_thread_info)); + pika_GIL_EXIT(); +#if PIKA_FREERTOS_ENABLE + pikaFree(thread, sizeof(pika_platform_thread_t)); + pika_platform_thread_exit(NULL); +#else + pika_platform_thread_exit(thread); +#endif +} + +void _thread_start_new_thread(PikaObj* self, Arg* function, Arg* args_) { + pika_thread_info* info = + (pika_thread_info*)pikaMalloc(sizeof(pika_thread_info)); + info->function = arg_copy(function); + info->args = arg_copy(args_); + _VM_lock_init(); + info->thread = pika_platform_thread_init( + "pika_thread", _thread_func, info, PIKA_THREAD_STACK_SIZE, + PIKA_THREAD_PRIO, PIKA_THREAD_TICK); +} diff --git a/examples/pikapython/pikapython/pikascript-lib/binascii/binascii.c b/examples/pikapython/pikapython/pikascript-lib/binascii/binascii.c new file mode 100755 index 00000000..6b82a53a --- /dev/null +++ b/examples/pikapython/pikapython/pikascript-lib/binascii/binascii.c @@ -0,0 +1,45 @@ +#include "binascii.h" + +static int hex2int(char c) { + if (c >= '0' && c <= '9') + return c - '0'; + if (c >= 'a' && c <= 'f') + return c - 'a' + 10; + if (c >= 'A' && c <= 'F') + return c - 'A' + 10; + return -1; +} + +Arg* binascii_a2b_hex(PikaObj* self, char* val) { + /* a2b_hex */ + int len = strGetSize(val); + Arg* ret = arg_setBytes(NULL, "", NULL, len / 2); + uint8_t* res_hex = arg_getBytes(ret); + for (int i = 0; i < len; i += 2) { + res_hex[i / 2] = (hex2int(val[i]) << 4) | hex2int(val[i + 1]); + } + return ret; +} + +Arg* binascii_b2a_hex(PikaObj* self, Arg* val) { + /* assert val is bytes */ + if (arg_getType(val) != ARG_TYPE_BYTES) { + obj_setErrorCode(self, PIKA_RES_ERR_RUNTIME_ERROR); + __platform_printf("TypeError: cannot convert value to bytes\r\n"); + return arg_setNull(NULL); + } + + /* b2a_hex */ + Arg* hex_str = arg_setStr(NULL, "", ""); + for (int i = 0; i < (int)arg_getBytesSize(val); i++) { + uint8_t* bytes = arg_getBytes(val); + uint8_t byte = bytes[i]; + char hex_byte[3] = {0}; + __platform_sprintf(hex_byte, "%02X", byte); + hex_str = arg_strAppend(hex_str, hex_byte); + } + Arg* hex_bytes = arg_setBytes(NULL, "", (uint8_t*)arg_getStr(hex_str), + strGetSize(arg_getStr(hex_str))); + arg_deinit(hex_str); + return hex_bytes; +} diff --git a/examples/pikapython/pikapython/pikascript-lib/configparser/README.md b/examples/pikapython/pikapython/pikascript-lib/configparser/README.md new file mode 100755 index 00000000..b7d70a16 --- /dev/null +++ b/examples/pikapython/pikapython/pikascript-lib/configparser/README.md @@ -0,0 +1 @@ +# configparser diff --git a/examples/pikapython/pikapython/pikascript-lib/json/README.md b/examples/pikapython/pikapython/pikascript-lib/json/README.md new file mode 100755 index 00000000..d41d128c --- /dev/null +++ b/examples/pikapython/pikapython/pikascript-lib/json/README.md @@ -0,0 +1,4 @@ +# json + +## Dependency +- pika_cjson \ No newline at end of file diff --git a/examples/pikapython/pikapython/pikascript-lib/modbus/LICENSE b/examples/pikapython/pikapython/pikascript-lib/modbus/LICENSE new file mode 100755 index 00000000..261eeb9e --- /dev/null +++ b/examples/pikapython/pikapython/pikascript-lib/modbus/LICENSE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/examples/pikapython/pikapython/pikascript-lib/modbus/_modbus.c b/examples/pikapython/pikapython/pikascript-lib/modbus/_modbus.c new file mode 100755 index 00000000..7444e0a2 --- /dev/null +++ b/examples/pikapython/pikapython/pikascript-lib/modbus/_modbus.c @@ -0,0 +1,216 @@ +#include "_modbus__ModBus.h" +#include "agile_modbus.h" + +#if !PIKASCRIPT_VERSION_REQUIRE_MINIMUN(1, 11, 1) +#error "pikascript version must be greater than 1.11.1" +#endif + +void _modbus__ModBus___init__rtu(PikaObj* self, + int sendBUffSize, + int readBuffSize) { + agile_modbus_rtu_t ctx_rtu = {0}; + obj_setBytes(self, "sendBuff", NULL, sendBUffSize); + obj_setBytes(self, "readBuff", NULL, readBuffSize); + agile_modbus_rtu_init(&ctx_rtu, obj_getBytes(self, "sendBuff"), + sendBUffSize, obj_getBytes(self, "readBuff"), + readBuffSize); + obj_setStruct(self, "ctx_rtu", ctx_rtu); + agile_modbus_rtu_t* ctx_rtu_heap = obj_getStruct(self, "ctx_rtu"); + obj_setPtr(self, "ctx", &ctx_rtu_heap->_ctx); +} + +void _modbus__ModBus_setSlave(PikaObj* self, int slave) { + agile_modbus_t* ctx = obj_getPtr(self, "ctx"); + agile_modbus_set_slave(ctx, slave); +} + +void _modbus__ModBus___init__tcp(PikaObj* self, + int sendBuffSize, + int readBuffSize) { + agile_modbus_tcp_t ctx_tcp = {0}; + obj_setBytes(self, "sendBuff", NULL, sendBuffSize); + obj_setBytes(self, "readBuff", NULL, readBuffSize); + agile_modbus_tcp_init(&ctx_tcp, obj_getBytes(self, "sendBuff"), + sendBuffSize, obj_getBytes(self, "readBuff"), + readBuffSize); + obj_setStruct(self, "ctx_tcp", ctx_tcp); + agile_modbus_tcp_t* ctx_tcp_heap = obj_getStruct(self, "ctx_tcp"); + obj_setPtr(self, "ctx", &ctx_tcp_heap->_ctx); +} + +int _modbus__ModBus_deserializeMaskWriteRegister(PikaObj* self, int msgLength) { + agile_modbus_t* ctx = obj_getPtr(self, "ctx"); + return agile_modbus_deserialize_mask_write_register(ctx, msgLength); +} + +Arg* _modbus__ModBus_deserializeReadRegisters(PikaObj* self, int msgLength) { + uint16_t buff[128] = {0}; + agile_modbus_t* ctx = obj_getPtr(self, "ctx"); + int len = agile_modbus_deserialize_read_registers(ctx, msgLength, + (uint16_t*)buff); + if (len < 0) { + return NULL; + } + return arg_newBytes((uint8_t*)buff, len * 2); +} + +Arg* _modbus__ModBus_deserializeReadBits(PikaObj* self, int msgLength) { + uint8_t buff[128] = {0}; + agile_modbus_t* ctx = obj_getPtr(self, "ctx"); + int len = agile_modbus_deserialize_read_bits(ctx, msgLength, buff); + if (len < 0) { + return NULL; + } + return arg_newBytes(buff, len); +} + +Arg* _modbus__ModBus_deserializeReadInputBits(PikaObj* self, int msgLength) { + uint8_t buff[128] = {0}; + agile_modbus_t* ctx = obj_getPtr(self, "ctx"); + int len = agile_modbus_deserialize_read_input_bits(ctx, msgLength, buff); + if (len < 0) { + return NULL; + } + return arg_newBytes(buff, len); +} + +Arg* _modbus__ModBus_deserializeReadInputRegisters(PikaObj* self, + int msgLength) { + uint16_t buff[128] = {0}; + agile_modbus_t* ctx = obj_getPtr(self, "ctx"); + int len = agile_modbus_deserialize_read_input_registers(ctx, msgLength, + (uint16_t*)buff); + if (len < 0) { + return NULL; + } + return arg_newBytes((uint8_t*)buff, len * 2); +} + +Arg* _modbus__ModBus_deserializeReportSlaveId(PikaObj* self, + int msgLength, + int maxDest) { + uint8_t buff[128] = {0}; + agile_modbus_t* ctx = obj_getPtr(self, "ctx"); + int len = agile_modbus_deserialize_report_slave_id(ctx, msgLength, maxDest, + (uint8_t*)buff); + if (len < 0) { + return NULL; + } + return arg_newBytes(buff, len); +} + +Arg* _modbus__ModBus_deserializeWriteAndReadRegisters(PikaObj* self, + int msgLength) { + uint16_t buff[128] = {0}; + agile_modbus_t* ctx = obj_getPtr(self, "ctx"); + int len = agile_modbus_deserialize_write_and_read_registers( + ctx, msgLength, (uint16_t*)buff); + if (len < 0) { + return NULL; + } + return arg_newBytes((uint8_t*)buff, len * 2); +} + +int _modbus__ModBus_deserializeWriteBit(PikaObj* self, int msgLength) { + agile_modbus_t* ctx = obj_getPtr(self, "ctx"); + return agile_modbus_deserialize_write_bit(ctx, msgLength); +} + +int _modbus__ModBus_deserializeWriteBits(PikaObj* self, int msgLength) { + agile_modbus_t* ctx = obj_getPtr(self, "ctx"); + return agile_modbus_deserialize_write_bits(ctx, msgLength); +} + +int _modbus__ModBus_deserializeWriteRegister(PikaObj* self, int msgLength) { + agile_modbus_t* ctx = obj_getPtr(self, "ctx"); + return agile_modbus_deserialize_write_register(ctx, msgLength); +} + +int _modbus__ModBus_deserializeWriteRegisters(PikaObj* self, int msgLength) { + agile_modbus_t* ctx = obj_getPtr(self, "ctx"); + return agile_modbus_deserialize_write_registers(ctx, msgLength); +} + +int _modbus__ModBus_serializeMaskWriteRegister(PikaObj* self, + int addr, + int andMask, + int orMask) { + agile_modbus_t* ctx = obj_getPtr(self, "ctx"); + return agile_modbus_serialize_mask_write_register(ctx, addr, andMask, + orMask); +} + +int _modbus__ModBus_serializeReadBits(PikaObj* self, int addr, int nb) { + agile_modbus_t* ctx = obj_getPtr(self, "ctx"); + return agile_modbus_serialize_read_bits(ctx, addr, nb); +} + +int _modbus__ModBus_serializeReadInputBits(PikaObj* self, int addr, int nb) { + agile_modbus_t* ctx = obj_getPtr(self, "ctx"); + return agile_modbus_serialize_read_input_bits(ctx, addr, nb); +} + +int _modbus__ModBus_serializeReadInputRegisters(PikaObj* self, + int addr, + int nb) { + agile_modbus_t* ctx = obj_getPtr(self, "ctx"); + return agile_modbus_serialize_read_input_registers(ctx, addr, nb); +} + +int _modbus__ModBus_serializeReadRegisters(PikaObj* self, int addr, int nb) { + agile_modbus_t* ctx = obj_getPtr(self, "ctx"); + return agile_modbus_serialize_read_registers(ctx, addr, nb); +} + +int _modbus__ModBus_serializeReportSlaveId(PikaObj* self) { + agile_modbus_t* ctx = obj_getPtr(self, "ctx"); + return agile_modbus_serialize_report_slave_id(ctx); +} + +int _modbus__ModBus_serializeWriteAndReadRegisters(PikaObj* self, + int writeAddr, + int writeNb, + uint8_t* src, + int readAddr, + int readNb) { + agile_modbus_t* ctx = obj_getPtr(self, "ctx"); + return agile_modbus_serialize_write_and_read_registers( + ctx, writeAddr, writeNb, (uint16_t*)src, readAddr, readNb); +} + +int _modbus__ModBus_serializeWriteBit(PikaObj* self, int addr, int status) { + agile_modbus_t* ctx = obj_getPtr(self, "ctx"); + return agile_modbus_serialize_write_bit(ctx, addr, status); +} + +int _modbus__ModBus_serializeWriteBits(PikaObj* self, + int addr, + int nb, + uint8_t* src) { + agile_modbus_t* ctx = obj_getPtr(self, "ctx"); + return agile_modbus_serialize_write_bits(ctx, addr, nb, src); +} + +int _modbus__ModBus_serializeWriteRegister(PikaObj* self, int addr, int value) { + agile_modbus_t* ctx = obj_getPtr(self, "ctx"); + return agile_modbus_serialize_write_register(ctx, addr, value); +} + +int _modbus__ModBus_serializeWriteRegisters(PikaObj* self, + int addr, + int nb, + uint8_t* src) { + agile_modbus_t* ctx = obj_getPtr(self, "ctx"); + return agile_modbus_serialize_write_registers(ctx, addr, nb, + (uint16_t*)src); +} + +Arg* _modbus__ModBus_getSendBuff(PikaObj* self) { + agile_modbus_t* ctx = obj_getPtr(self, "ctx"); + return arg_newBytes(ctx->send_buf, ctx->send_bufsz); +} + +Arg* _modbus__ModBus_getReadBuff(PikaObj* self) { + agile_modbus_t* ctx = obj_getPtr(self, "ctx"); + return arg_newBytes(ctx->read_buf, ctx->read_bufsz); +} diff --git a/examples/pikapython/pikapython/pikascript-lib/modbus/agile_modbus.c b/examples/pikapython/pikapython/pikascript-lib/modbus/agile_modbus.c new file mode 100755 index 00000000..81ff4042 --- /dev/null +++ b/examples/pikapython/pikapython/pikascript-lib/modbus/agile_modbus.c @@ -0,0 +1,1519 @@ +/** + * @file agile_modbus.c + * @brief Agile Modbus 软件包通用源文件 + * @author 马龙伟 (2544047213@qq.com) + * @date 2022-07-28 + * + @verbatim + 使用: + 用户需要实现硬件接口的 `发送数据` 、 `等待数据接收结束` 、 `清空接收缓存` 函数 + + - 主机: + 1. `agile_modbus_rtu_init` / `agile_modbus_tcp_init` 初始化 `RTU/TCP` 环境 + 2. `agile_modbus_set_slave` 设置从机地址 + 3. `清空接收缓存` + 4. `agile_modbus_serialize_xxx` 打包请求数据 + 5. `发送数据` + 6. `等待数据接收结束` + 7. `agile_modbus_deserialize_xxx` 解析响应数据 + 8. 用户处理得到的数据 + + - 从机: + 1. 实现 `agile_modbus_slave_callback_t` 类型回调函数 + 2. `agile_modbus_rtu_init` / `agile_modbus_tcp_init` 初始化 `RTU/TCP` 环境 + 3. `agile_modbus_set_slave` 设置从机地址 + 4. `等待数据接收结束` + 5. `agile_modbus_slave_handle` 处理请求数据 + 6. `清空接收缓存` (可选) + 7. `发送数据` + + @endverbatim + * + * @attention + * + *

© Copyright (c) 2021 Ma Longwei. + * All rights reserved.

+ * + */ + +#include "agile_modbus.h" +#include + +/** @defgroup COMMON Common + * @{ + */ + +/** @defgroup COMMON_Private_Constants Common Private Constants + * @{ + */ +#define AGILE_MODBUS_MSG_LENGTH_UNDEFINED -1 /**< 对应功能码数据长度未定义 */ +/** + * @} + */ + +/** @defgroup COMMON_Private_Functions Common Private Functions + * @{ + */ + +/** + * @brief 计算功能码后要接收的数据元长度 + @verbatim + ---------- Request Indication ---------- + | Client | ---------------------->| Server | + ---------- Confirmation Response ---------- + + 以 03 功能码请求报文举例 + + ---------- ------ --------------- --------- + | header | | 03 | | 00 00 00 01 | | CRC16 | + ---------- ------ --------------- --------- + + ---------- + | header | + ---------- + RTU: 设备地址 + TCP: | 事务处理标识 协议标识 长度 单元标识符 | + + --------------- + | 00 00 00 01 | + --------------- + 数据元: 与功能码相关的数据,如 03 功能码数据元中包含寄存器起始地址和寄存器长度 + + @endverbatim + * @param ctx modbus 句柄 + * @param function 功能码 + * @param msg_type 消息类型 + * @return 数据元长度 + */ +static uint8_t agile_modbus_compute_meta_length_after_function(agile_modbus_t *ctx, int function, agile_modbus_msg_type_t msg_type) +{ + int length; + + if (msg_type == AGILE_MODBUS_MSG_INDICATION) { + if (function <= AGILE_MODBUS_FC_WRITE_SINGLE_REGISTER) { + length = 4; + } else if (function == AGILE_MODBUS_FC_WRITE_MULTIPLE_COILS || + function == AGILE_MODBUS_FC_WRITE_MULTIPLE_REGISTERS) { + length = 5; + } else if (function == AGILE_MODBUS_FC_MASK_WRITE_REGISTER) { + length = 6; + } else if (function == AGILE_MODBUS_FC_WRITE_AND_READ_REGISTERS) { + length = 9; + } else { + /* MODBUS_FC_READ_EXCEPTION_STATUS, MODBUS_FC_REPORT_SLAVE_ID */ + length = 0; + if (ctx->compute_meta_length_after_function) + length = ctx->compute_meta_length_after_function(ctx, function, msg_type); + } + } else { + /* MSG_CONFIRMATION */ + switch (function) { + case AGILE_MODBUS_FC_READ_COILS: + case AGILE_MODBUS_FC_READ_DISCRETE_INPUTS: + case AGILE_MODBUS_FC_READ_HOLDING_REGISTERS: + case AGILE_MODBUS_FC_READ_INPUT_REGISTERS: + case AGILE_MODBUS_FC_REPORT_SLAVE_ID: + case AGILE_MODBUS_FC_WRITE_AND_READ_REGISTERS: + length = 1; + break; + + case AGILE_MODBUS_FC_WRITE_SINGLE_COIL: + case AGILE_MODBUS_FC_WRITE_SINGLE_REGISTER: + case AGILE_MODBUS_FC_WRITE_MULTIPLE_COILS: + case AGILE_MODBUS_FC_WRITE_MULTIPLE_REGISTERS: + length = 4; + break; + + case AGILE_MODBUS_FC_MASK_WRITE_REGISTER: + length = 6; + break; + + default: + length = 1; + if (ctx->compute_meta_length_after_function) + length = ctx->compute_meta_length_after_function(ctx, function, msg_type); + } + } + + return length; +} + +/** + * @brief 计算数据元之后要接收的数据长度 + @verbatim + ---------- Request Indication ---------- + | Client | ---------------------->| Server | + ---------- Confirmation Response ---------- + + 以 03 功能码响应报文举例 + + ---------- ------ ------ --------- --------- + | header | | 03 | | 02 | | 00 00 | | CRC16 | + ---------- ------ ------ --------- --------- + + ---------- + | header | + ---------- + RTU: 设备地址 + TCP: | 事务处理标识 协议标识 长度 单元标识符 | + + ------ + | 02 | + ------ + 数据元: 两个字节数据 + + --------- + | 00 00 | + --------- + 数据 + + @endverbatim + * @param ctx modbus 句柄 + * @param msg 消息指针 + * @param msg_length 消息长度 + * @param msg_type 消息类型 + * @return 数据长度 + */ +static int agile_modbus_compute_data_length_after_meta(agile_modbus_t *ctx, uint8_t *msg, int msg_length, agile_modbus_msg_type_t msg_type) +{ + int function = msg[ctx->backend->header_length]; + int length; + + if (msg_type == AGILE_MODBUS_MSG_INDICATION) { + switch (function) { + case AGILE_MODBUS_FC_WRITE_MULTIPLE_COILS: + case AGILE_MODBUS_FC_WRITE_MULTIPLE_REGISTERS: + length = msg[ctx->backend->header_length + 5]; + break; + + case AGILE_MODBUS_FC_WRITE_AND_READ_REGISTERS: + length = msg[ctx->backend->header_length + 9]; + break; + + default: + length = 0; + if (ctx->compute_data_length_after_meta) + length = ctx->compute_data_length_after_meta(ctx, msg, msg_length, msg_type); + } + } else { + /* MSG_CONFIRMATION */ + if (function <= AGILE_MODBUS_FC_READ_INPUT_REGISTERS || + function == AGILE_MODBUS_FC_REPORT_SLAVE_ID || + function == AGILE_MODBUS_FC_WRITE_AND_READ_REGISTERS) { + length = msg[ctx->backend->header_length + 1]; + } else { + length = 0; + if (ctx->compute_data_length_after_meta) + length = ctx->compute_data_length_after_meta(ctx, msg, msg_length, msg_type); + } + } + + length += ctx->backend->checksum_length; + + return length; +} + +/** + * @brief 检验接收数据正确性 + * @param ctx modbus 句柄 + * @param msg 消息指针 + * @param msg_length 消息长度 + * @param msg_type 消息类型 + * @return >0:正确,modbus 数据帧长度; 其他:异常 + */ +static int agile_modbus_receive_msg_judge(agile_modbus_t *ctx, uint8_t *msg, int msg_length, agile_modbus_msg_type_t msg_type) +{ + int remain_len = msg_length; + + remain_len -= (ctx->backend->header_length + 1); + if (remain_len < 0) + return -1; + remain_len -= agile_modbus_compute_meta_length_after_function(ctx, msg[ctx->backend->header_length], msg_type); + if (remain_len < 0) + return -1; + remain_len -= agile_modbus_compute_data_length_after_meta(ctx, msg, msg_length, msg_type); + if (remain_len < 0) + return -1; + + return ctx->backend->check_integrity(ctx, msg, msg_length - remain_len); +} + +/** + * @} + */ + +/** @defgroup COMMON_Exported_Functions Common Exported Functions + * @{ + */ + +/** + * @brief 初始化 modbus 句柄 + * @param ctx modbus 句柄 + * @param send_buf 发送缓冲区 + * @param send_bufsz 发送缓冲区大小 + * @param read_buf 接收缓冲区 + * @param read_bufsz 接收缓冲区大小 + */ +void agile_modbus_common_init(agile_modbus_t *ctx, uint8_t *send_buf, int send_bufsz, uint8_t *read_buf, int read_bufsz) +{ + memset(ctx, 0, sizeof(agile_modbus_t)); + ctx->slave = -1; + ctx->send_buf = send_buf; + ctx->send_bufsz = send_bufsz; + ctx->read_buf = read_buf; + ctx->read_bufsz = read_bufsz; +} + +/** + * @brief 设置地址 + * @param ctx modbus 句柄 + * @param slave 地址 + * @return 0:成功 + */ +int agile_modbus_set_slave(agile_modbus_t *ctx, int slave) +{ + return ctx->backend->set_slave(ctx, slave); +} + +/** + * @brief 设置 modbus 对象的计算功能码后要接收的数据元长度回调函数 + * @param ctx modbus 句柄 + * @param cb 计算功能码后要接收的数据元长度回调函数 + * @see agile_modbus_compute_meta_length_after_function + */ +void agile_modbus_set_compute_meta_length_after_function_cb(agile_modbus_t *ctx, + uint8_t (*cb)(agile_modbus_t *ctx, int function, + agile_modbus_msg_type_t msg_type)) +{ + ctx->compute_meta_length_after_function = cb; +} + +/** + * @brief 设置 modbus 对象的计算数据元之后要接收的数据长度回调函数 + * @param ctx modbus 句柄 + * @param cb 计算数据元之后要接收的数据长度回调函数 + * @see agile_modbus_compute_data_length_after_meta + */ +void agile_modbus_set_compute_data_length_after_meta_cb(agile_modbus_t *ctx, + int (*cb)(agile_modbus_t *ctx, uint8_t *msg, + int msg_length, agile_modbus_msg_type_t msg_type)) +{ + ctx->compute_data_length_after_meta = cb; +} + +/** + * @brief 校验接收数据正确性 + * @note 该 API 返回的是 modbus 数据帧长度,比如 8 个字节的 modbus 数据帧 + 2 个字节的脏数据,返回 8 + * @param ctx modbus 句柄 + * @param msg_length 接收数据长度 + * @param msg_type 消息类型 + * @return >0:正确,modbus 数据帧长度; 其他:异常 + */ +int agile_modbus_receive_judge(agile_modbus_t *ctx, int msg_length, agile_modbus_msg_type_t msg_type) +{ + if ((msg_length <= 0) || (msg_length > ctx->read_bufsz)) + return -1; + + int rc = agile_modbus_receive_msg_judge(ctx, ctx->read_buf, msg_length, msg_type); + + return rc; +} + +/** + * @} + */ + +/** @defgroup Modbus_Master Modbus Master + * @{ + */ + +/** @defgroup Master_Private_Functions Master Private Functions + * @{ + */ + +/** + * @brief 计算预期响应数据长度 + * @note 如果是特殊的功能码,返回 AGILE_MODBUS_MSG_LENGTH_UNDEFINED ,但这不代表异常。 + * agile_modbus_check_confirmation 调用该 API 处理时认为 AGILE_MODBUS_MSG_LENGTH_UNDEFINED 返回值也是有效的。 + * @param ctx modbus 句柄 + * @param req 请求数据指针 + * @return 预期响应数据长度 + */ +static int agile_modbus_compute_response_length_from_request(agile_modbus_t *ctx, uint8_t *req) +{ + int length; + const int offset = ctx->backend->header_length; + + switch (req[offset]) { + case AGILE_MODBUS_FC_READ_COILS: + case AGILE_MODBUS_FC_READ_DISCRETE_INPUTS: { + /* Header + nb values (code from write_bits) */ + int nb = (req[offset + 3] << 8) | req[offset + 4]; + length = 2 + (nb / 8) + ((nb % 8) ? 1 : 0); + } break; + + case AGILE_MODBUS_FC_WRITE_AND_READ_REGISTERS: + case AGILE_MODBUS_FC_READ_HOLDING_REGISTERS: + case AGILE_MODBUS_FC_READ_INPUT_REGISTERS: + /* Header + 2 * nb values */ + length = 2 + 2 * (req[offset + 3] << 8 | req[offset + 4]); + break; + + case AGILE_MODBUS_FC_WRITE_SINGLE_COIL: + case AGILE_MODBUS_FC_WRITE_SINGLE_REGISTER: + case AGILE_MODBUS_FC_WRITE_MULTIPLE_COILS: + case AGILE_MODBUS_FC_WRITE_MULTIPLE_REGISTERS: + length = 5; + break; + + case AGILE_MODBUS_FC_MASK_WRITE_REGISTER: + length = 7; + break; + + default: + /* The response is device specific (the header provides the + length) */ + return AGILE_MODBUS_MSG_LENGTH_UNDEFINED; + } + + return offset + length + ctx->backend->checksum_length; +} + +/** + * @brief 检查确认从机响应的数据 + * @param ctx modbus 句柄 + * @param req 请求数据指针 + * @param rsp 响应数据指针 + * @param rsp_length 响应数据长度 + * @return >=0:对应功能码响应对象的长度(如 03 功能码,值代表寄存器个数); + * 其他:异常 (-1:报文错误;其他:可根据 `-128 - $返回值` 得到异常码) + */ +static int agile_modbus_check_confirmation(agile_modbus_t *ctx, uint8_t *req, + uint8_t *rsp, int rsp_length) +{ + int rc; + int rsp_length_computed; + const int offset = ctx->backend->header_length; + const int function = rsp[offset]; + + if (ctx->backend->pre_check_confirmation) { + rc = ctx->backend->pre_check_confirmation(ctx, req, rsp, rsp_length); + if (rc < 0) + return -1; + } + + rsp_length_computed = agile_modbus_compute_response_length_from_request(ctx, req); + + /* Exception code */ + if (function >= 0x80) { + if (rsp_length == (offset + 2 + (int)ctx->backend->checksum_length) && req[offset] == (rsp[offset] - 0x80)) + return (-128 - rsp[offset + 1]); + else + return -1; + } + + /* Check length */ + if ((rsp_length == rsp_length_computed || rsp_length_computed == AGILE_MODBUS_MSG_LENGTH_UNDEFINED) && function < 0x80) { + int req_nb_value; + int rsp_nb_value; + + /* Check function code */ + if (function != req[offset]) + return -1; + + /* Check the number of values is corresponding to the request */ + switch (function) { + case AGILE_MODBUS_FC_READ_COILS: + case AGILE_MODBUS_FC_READ_DISCRETE_INPUTS: + /* Read functions, 8 values in a byte (nb + * of values in the request and byte count in + * the response. */ + req_nb_value = (req[offset + 3] << 8) + req[offset + 4]; + req_nb_value = (req_nb_value / 8) + ((req_nb_value % 8) ? 1 : 0); + rsp_nb_value = rsp[offset + 1]; + break; + + case AGILE_MODBUS_FC_WRITE_AND_READ_REGISTERS: + case AGILE_MODBUS_FC_READ_HOLDING_REGISTERS: + case AGILE_MODBUS_FC_READ_INPUT_REGISTERS: + /* Read functions 1 value = 2 bytes */ + req_nb_value = (req[offset + 3] << 8) + req[offset + 4]; + rsp_nb_value = (rsp[offset + 1] / 2); + break; + + case AGILE_MODBUS_FC_WRITE_MULTIPLE_COILS: + case AGILE_MODBUS_FC_WRITE_MULTIPLE_REGISTERS: + /* N Write functions */ + req_nb_value = (req[offset + 3] << 8) + req[offset + 4]; + rsp_nb_value = (rsp[offset + 3] << 8) | rsp[offset + 4]; + break; + + case AGILE_MODBUS_FC_REPORT_SLAVE_ID: + /* Report slave ID (bytes received) */ + req_nb_value = rsp_nb_value = rsp[offset + 1]; + break; + + default: + /* 1 Write functions & others */ + req_nb_value = rsp_nb_value = 1; + } + + if (req_nb_value == rsp_nb_value) + rc = rsp_nb_value; + else + rc = -1; + } else + rc = -1; + + return rc; +} + +/** + * @} + */ + +/** @defgroup Master_Common_Operation_Functions Master Common Operation Functions + * @brief 常用 modbus 主机操作函数 + @verbatim + API 形式如下: + - agile_modbus_serialize_xxx 打包请求数据 + 返回值: + >0:请求数据长度 + 其他:异常 + + - agile_modbus_deserialize_xxx 解析响应数据 + 返回值: + >=0:对应功能码响应对象的长度(如 03 功能码,值代表寄存器个数) + 其他:异常 (-1:报文错误;其他:可根据 `-128 - $返回值` 得到异常码) + + @endverbatim + * @{ + */ + +int agile_modbus_serialize_read_bits(agile_modbus_t *ctx, int addr, int nb) +{ + int min_req_length = ctx->backend->header_length + 5 + ctx->backend->checksum_length; + if (ctx->send_bufsz < min_req_length) + return -1; + + if (nb > AGILE_MODBUS_MAX_READ_BITS) + return -1; + + int req_length = 0; + req_length = ctx->backend->build_request_basis(ctx, AGILE_MODBUS_FC_READ_COILS, addr, nb, ctx->send_buf); + req_length = ctx->backend->send_msg_pre(ctx->send_buf, req_length); + + return req_length; +} + +int agile_modbus_deserialize_read_bits(agile_modbus_t *ctx, int msg_length, uint8_t *dest) +{ + int min_req_length = ctx->backend->header_length + 5 + ctx->backend->checksum_length; + if (ctx->send_bufsz < min_req_length) + return -1; + if ((msg_length <= 0) || (msg_length > ctx->read_bufsz)) + return -1; + + int rc = agile_modbus_receive_msg_judge(ctx, ctx->read_buf, msg_length, AGILE_MODBUS_MSG_CONFIRMATION); + if (rc < 0) + return -1; + + rc = agile_modbus_check_confirmation(ctx, ctx->send_buf, ctx->read_buf, rc); + if (rc < 0) + return rc; + + int i, temp, bit; + int pos = 0; + int offset; + int offset_end; + int nb; + + offset = ctx->backend->header_length + 2; + offset_end = offset + rc; + nb = (ctx->send_buf[ctx->backend->header_length + 3] << 8) + ctx->send_buf[ctx->backend->header_length + 4]; + + for (i = offset; i < offset_end; i++) { + /* Shift reg hi_byte to temp */ + temp = ctx->read_buf[i]; + + for (bit = 0x01; (bit & 0xff) && (pos < nb);) { + dest[pos++] = (temp & bit) ? 1 : 0; + bit = bit << 1; + } + } + + return nb; +} + +int agile_modbus_serialize_read_input_bits(agile_modbus_t *ctx, int addr, int nb) +{ + int min_req_length = ctx->backend->header_length + 5 + ctx->backend->checksum_length; + if (ctx->send_bufsz < min_req_length) + return -1; + + if (nb > AGILE_MODBUS_MAX_READ_BITS) + return -1; + + int req_length = 0; + req_length = ctx->backend->build_request_basis(ctx, AGILE_MODBUS_FC_READ_DISCRETE_INPUTS, addr, nb, ctx->send_buf); + req_length = ctx->backend->send_msg_pre(ctx->send_buf, req_length); + + return req_length; +} + +int agile_modbus_deserialize_read_input_bits(agile_modbus_t *ctx, int msg_length, uint8_t *dest) +{ + int min_req_length = ctx->backend->header_length + 5 + ctx->backend->checksum_length; + if (ctx->send_bufsz < min_req_length) + return -1; + if ((msg_length <= 0) || (msg_length > ctx->read_bufsz)) + return -1; + + int rc = agile_modbus_receive_msg_judge(ctx, ctx->read_buf, msg_length, AGILE_MODBUS_MSG_CONFIRMATION); + if (rc < 0) + return -1; + + rc = agile_modbus_check_confirmation(ctx, ctx->send_buf, ctx->read_buf, rc); + if (rc < 0) + return rc; + + int i, temp, bit; + int pos = 0; + int offset; + int offset_end; + int nb; + + offset = ctx->backend->header_length + 2; + offset_end = offset + rc; + nb = (ctx->send_buf[ctx->backend->header_length + 3] << 8) + ctx->send_buf[ctx->backend->header_length + 4]; + + for (i = offset; i < offset_end; i++) { + /* Shift reg hi_byte to temp */ + temp = ctx->read_buf[i]; + + for (bit = 0x01; (bit & 0xff) && (pos < nb);) { + dest[pos++] = (temp & bit) ? 1 : 0; + bit = bit << 1; + } + } + + return nb; +} + +int agile_modbus_serialize_read_registers(agile_modbus_t *ctx, int addr, int nb) +{ + int min_req_length = ctx->backend->header_length + 5 + ctx->backend->checksum_length; + if (ctx->send_bufsz < min_req_length) + return -1; + + if (nb > AGILE_MODBUS_MAX_READ_REGISTERS) + return -1; + + int req_length = 0; + req_length = ctx->backend->build_request_basis(ctx, AGILE_MODBUS_FC_READ_HOLDING_REGISTERS, addr, nb, ctx->send_buf); + req_length = ctx->backend->send_msg_pre(ctx->send_buf, req_length); + + return req_length; +} + +int agile_modbus_deserialize_read_registers(agile_modbus_t *ctx, int msg_length, uint16_t *dest) +{ + int min_req_length = ctx->backend->header_length + 5 + ctx->backend->checksum_length; + if (ctx->send_bufsz < min_req_length) + return -1; + if ((msg_length <= 0) || (msg_length > ctx->read_bufsz)) + return -1; + + int rc = agile_modbus_receive_msg_judge(ctx, ctx->read_buf, msg_length, AGILE_MODBUS_MSG_CONFIRMATION); + if (rc < 0) + return -1; + + rc = agile_modbus_check_confirmation(ctx, ctx->send_buf, ctx->read_buf, rc); + if (rc < 0) + return rc; + + int offset; + int i; + + offset = ctx->backend->header_length; + for (i = 0; i < rc; i++) { + /* shift reg hi_byte to temp OR with lo_byte */ + dest[i] = (ctx->read_buf[offset + 2 + (i << 1)] << 8) | ctx->read_buf[offset + 3 + (i << 1)]; + } + + return rc; +} + +int agile_modbus_serialize_read_input_registers(agile_modbus_t *ctx, int addr, int nb) +{ + int min_req_length = ctx->backend->header_length + 5 + ctx->backend->checksum_length; + if (ctx->send_bufsz < min_req_length) + return -1; + + if (nb > AGILE_MODBUS_MAX_READ_REGISTERS) + return -1; + + int req_length = 0; + req_length = ctx->backend->build_request_basis(ctx, AGILE_MODBUS_FC_READ_INPUT_REGISTERS, addr, nb, ctx->send_buf); + req_length = ctx->backend->send_msg_pre(ctx->send_buf, req_length); + + return req_length; +} + +int agile_modbus_deserialize_read_input_registers(agile_modbus_t *ctx, int msg_length, uint16_t *dest) +{ + int min_req_length = ctx->backend->header_length + 5 + ctx->backend->checksum_length; + if (ctx->send_bufsz < min_req_length) + return -1; + if ((msg_length <= 0) || (msg_length > ctx->read_bufsz)) + return -1; + + int rc = agile_modbus_receive_msg_judge(ctx, ctx->read_buf, msg_length, AGILE_MODBUS_MSG_CONFIRMATION); + if (rc < 0) + return -1; + + rc = agile_modbus_check_confirmation(ctx, ctx->send_buf, ctx->read_buf, rc); + if (rc < 0) + return rc; + + int offset; + int i; + + offset = ctx->backend->header_length; + for (i = 0; i < rc; i++) { + /* shift reg hi_byte to temp OR with lo_byte */ + dest[i] = (ctx->read_buf[offset + 2 + (i << 1)] << 8) | ctx->read_buf[offset + 3 + (i << 1)]; + } + + return rc; +} + +int agile_modbus_serialize_write_bit(agile_modbus_t *ctx, int addr, int status) +{ + int min_req_length = ctx->backend->header_length + 5 + ctx->backend->checksum_length; + if (ctx->send_bufsz < min_req_length) + return -1; + + int req_length = 0; + req_length = ctx->backend->build_request_basis(ctx, AGILE_MODBUS_FC_WRITE_SINGLE_COIL, addr, status ? 0xFF00 : 0, ctx->send_buf); + req_length = ctx->backend->send_msg_pre(ctx->send_buf, req_length); + + return req_length; +} + +int agile_modbus_deserialize_write_bit(agile_modbus_t *ctx, int msg_length) +{ + int min_req_length = ctx->backend->header_length + 5 + ctx->backend->checksum_length; + if (ctx->send_bufsz < min_req_length) + return -1; + if ((msg_length <= 0) || (msg_length > ctx->read_bufsz)) + return -1; + + int rc = agile_modbus_receive_msg_judge(ctx, ctx->read_buf, msg_length, AGILE_MODBUS_MSG_CONFIRMATION); + if (rc < 0) + return -1; + + rc = agile_modbus_check_confirmation(ctx, ctx->send_buf, ctx->read_buf, rc); + + return rc; +} + +int agile_modbus_serialize_write_register(agile_modbus_t *ctx, int addr, const uint16_t value) +{ + int min_req_length = ctx->backend->header_length + 5 + ctx->backend->checksum_length; + if (ctx->send_bufsz < min_req_length) + return -1; + + int req_length = 0; + req_length = ctx->backend->build_request_basis(ctx, AGILE_MODBUS_FC_WRITE_SINGLE_REGISTER, addr, (int)value, ctx->send_buf); + req_length = ctx->backend->send_msg_pre(ctx->send_buf, req_length); + + return req_length; +} + +int agile_modbus_deserialize_write_register(agile_modbus_t *ctx, int msg_length) +{ + int min_req_length = ctx->backend->header_length + 5 + ctx->backend->checksum_length; + if (ctx->send_bufsz < min_req_length) + return -1; + if ((msg_length <= 0) || (msg_length > ctx->read_bufsz)) + return -1; + + int rc = agile_modbus_receive_msg_judge(ctx, ctx->read_buf, msg_length, AGILE_MODBUS_MSG_CONFIRMATION); + if (rc < 0) + return -1; + + rc = agile_modbus_check_confirmation(ctx, ctx->send_buf, ctx->read_buf, rc); + + return rc; +} + +int agile_modbus_serialize_write_bits(agile_modbus_t *ctx, int addr, int nb, const uint8_t *src) +{ + int min_req_length = ctx->backend->header_length + 5 + ctx->backend->checksum_length; + if (ctx->send_bufsz < min_req_length) + return -1; + + if (nb > AGILE_MODBUS_MAX_WRITE_BITS) + return -1; + + int i; + int byte_count; + int req_length; + int bit_check = 0; + int pos = 0; + + req_length = ctx->backend->build_request_basis(ctx, AGILE_MODBUS_FC_WRITE_MULTIPLE_COILS, addr, nb, ctx->send_buf); + byte_count = (nb / 8) + ((nb % 8) ? 1 : 0); + + min_req_length += (1 + byte_count); + if (ctx->send_bufsz < min_req_length) + return -1; + + ctx->send_buf[req_length++] = byte_count; + for (i = 0; i < byte_count; i++) { + int bit; + + bit = 0x01; + ctx->send_buf[req_length] = 0; + + while ((bit & 0xFF) && (bit_check++ < nb)) { + if (src[pos++]) + ctx->send_buf[req_length] |= bit; + else + ctx->send_buf[req_length] &= ~bit; + + bit = bit << 1; + } + req_length++; + } + + req_length = ctx->backend->send_msg_pre(ctx->send_buf, req_length); + + return req_length; +} + +int agile_modbus_deserialize_write_bits(agile_modbus_t *ctx, int msg_length) +{ + int min_req_length = ctx->backend->header_length + 5 + ctx->backend->checksum_length; + if (ctx->send_bufsz < min_req_length) + return -1; + if ((msg_length <= 0) || (msg_length > ctx->read_bufsz)) + return -1; + + int rc = agile_modbus_receive_msg_judge(ctx, ctx->read_buf, msg_length, AGILE_MODBUS_MSG_CONFIRMATION); + if (rc < 0) + return -1; + + rc = agile_modbus_check_confirmation(ctx, ctx->send_buf, ctx->read_buf, rc); + + return rc; +} + +int agile_modbus_serialize_write_registers(agile_modbus_t *ctx, int addr, int nb, const uint16_t *src) +{ + int min_req_length = ctx->backend->header_length + 5 + ctx->backend->checksum_length; + if (ctx->send_bufsz < min_req_length) + return -1; + + if (nb > AGILE_MODBUS_MAX_WRITE_REGISTERS) + return -1; + + int i; + int req_length; + int byte_count; + + req_length = ctx->backend->build_request_basis(ctx, AGILE_MODBUS_FC_WRITE_MULTIPLE_REGISTERS, addr, nb, ctx->send_buf); + byte_count = nb * 2; + + min_req_length += (1 + byte_count); + if (ctx->send_bufsz < min_req_length) + return -1; + + ctx->send_buf[req_length++] = byte_count; + for (i = 0; i < nb; i++) { + ctx->send_buf[req_length++] = src[i] >> 8; + ctx->send_buf[req_length++] = src[i] & 0x00FF; + } + + req_length = ctx->backend->send_msg_pre(ctx->send_buf, req_length); + + return req_length; +} + +int agile_modbus_deserialize_write_registers(agile_modbus_t *ctx, int msg_length) +{ + int min_req_length = ctx->backend->header_length + 5 + ctx->backend->checksum_length; + if (ctx->send_bufsz < min_req_length) + return -1; + if ((msg_length <= 0) || (msg_length > ctx->read_bufsz)) + return -1; + + int rc = agile_modbus_receive_msg_judge(ctx, ctx->read_buf, msg_length, AGILE_MODBUS_MSG_CONFIRMATION); + if (rc < 0) + return -1; + + rc = agile_modbus_check_confirmation(ctx, ctx->send_buf, ctx->read_buf, rc); + + return rc; +} + +int agile_modbus_serialize_mask_write_register(agile_modbus_t *ctx, int addr, uint16_t and_mask, uint16_t or_mask) +{ + int min_req_length = ctx->backend->header_length + 5 + ctx->backend->checksum_length + 2; + if (ctx->send_bufsz < min_req_length) + return -1; + + int req_length = 0; + req_length = ctx->backend->build_request_basis(ctx, AGILE_MODBUS_FC_MASK_WRITE_REGISTER, addr, 0, ctx->send_buf); + + /* HACKISH, count is not used */ + req_length -= 2; + + ctx->send_buf[req_length++] = and_mask >> 8; + ctx->send_buf[req_length++] = and_mask & 0x00ff; + ctx->send_buf[req_length++] = or_mask >> 8; + ctx->send_buf[req_length++] = or_mask & 0x00ff; + + req_length = ctx->backend->send_msg_pre(ctx->send_buf, req_length); + + return req_length; +} + +int agile_modbus_deserialize_mask_write_register(agile_modbus_t *ctx, int msg_length) +{ + int min_req_length = ctx->backend->header_length + 5 + ctx->backend->checksum_length; + if (ctx->send_bufsz < min_req_length) + return -1; + if ((msg_length <= 0) || (msg_length > ctx->read_bufsz)) + return -1; + + int rc = agile_modbus_receive_msg_judge(ctx, ctx->read_buf, msg_length, AGILE_MODBUS_MSG_CONFIRMATION); + if (rc < 0) + return -1; + + rc = agile_modbus_check_confirmation(ctx, ctx->send_buf, ctx->read_buf, rc); + + return rc; +} + +int agile_modbus_serialize_write_and_read_registers(agile_modbus_t *ctx, + int write_addr, int write_nb, + const uint16_t *src, + int read_addr, int read_nb) +{ + int min_req_length = ctx->backend->header_length + 5 + ctx->backend->checksum_length; + if (ctx->send_bufsz < min_req_length) + return -1; + + if (write_nb > AGILE_MODBUS_MAX_WR_WRITE_REGISTERS) + return -1; + + if (read_nb > AGILE_MODBUS_MAX_WR_READ_REGISTERS) + return -1; + + int req_length; + int i; + int byte_count; + + req_length = ctx->backend->build_request_basis(ctx, AGILE_MODBUS_FC_WRITE_AND_READ_REGISTERS, read_addr, read_nb, ctx->send_buf); + byte_count = write_nb * 2; + + min_req_length += (5 + byte_count); + if (ctx->send_bufsz < min_req_length) + return -1; + + ctx->send_buf[req_length++] = write_addr >> 8; + ctx->send_buf[req_length++] = write_addr & 0x00ff; + ctx->send_buf[req_length++] = write_nb >> 8; + ctx->send_buf[req_length++] = write_nb & 0x00ff; + ctx->send_buf[req_length++] = byte_count; + for (i = 0; i < write_nb; i++) { + ctx->send_buf[req_length++] = src[i] >> 8; + ctx->send_buf[req_length++] = src[i] & 0x00FF; + } + + req_length = ctx->backend->send_msg_pre(ctx->send_buf, req_length); + + return req_length; +} + +int agile_modbus_deserialize_write_and_read_registers(agile_modbus_t *ctx, int msg_length, uint16_t *dest) +{ + int min_req_length = ctx->backend->header_length + 5 + ctx->backend->checksum_length; + if (ctx->send_bufsz < min_req_length) + return -1; + if ((msg_length <= 0) || (msg_length > ctx->read_bufsz)) + return -1; + + int rc = agile_modbus_receive_msg_judge(ctx, ctx->read_buf, msg_length, AGILE_MODBUS_MSG_CONFIRMATION); + if (rc < 0) + return -1; + + rc = agile_modbus_check_confirmation(ctx, ctx->send_buf, ctx->read_buf, rc); + if (rc < 0) + return rc; + + int offset; + int i; + + offset = ctx->backend->header_length; + for (i = 0; i < rc; i++) { + /* shift reg hi_byte to temp OR with lo_byte */ + dest[i] = (ctx->read_buf[offset + 2 + (i << 1)] << 8) | ctx->read_buf[offset + 3 + (i << 1)]; + } + + return rc; +} + +int agile_modbus_serialize_report_slave_id(agile_modbus_t *ctx) +{ + int min_req_length = ctx->backend->header_length + 5 + ctx->backend->checksum_length; + if (ctx->send_bufsz < min_req_length) + return -1; + + int req_length = 0; + req_length = ctx->backend->build_request_basis(ctx, AGILE_MODBUS_FC_REPORT_SLAVE_ID, 0, 0, ctx->send_buf); + /* HACKISH, addr and count are not used */ + req_length -= 4; + req_length = ctx->backend->send_msg_pre(ctx->send_buf, req_length); + + return req_length; +} + +int agile_modbus_deserialize_report_slave_id(agile_modbus_t *ctx, int msg_length, int max_dest, uint8_t *dest) +{ + int min_req_length = ctx->backend->header_length + 5 + ctx->backend->checksum_length; + if (ctx->send_bufsz < min_req_length) + return -1; + if ((msg_length <= 0) || (msg_length > ctx->read_bufsz)) + return -1; + if (max_dest <= 0) + return -1; + + int rc = agile_modbus_receive_msg_judge(ctx, ctx->read_buf, msg_length, AGILE_MODBUS_MSG_CONFIRMATION); + if (rc < 0) + return -1; + + rc = agile_modbus_check_confirmation(ctx, ctx->send_buf, ctx->read_buf, rc); + if (rc < 0) + return rc; + + int i; + int offset; + + offset = ctx->backend->header_length + 2; + + /* Byte count, slave id, run indicator status and + additional data. Truncate copy to max_dest. */ + for (i = 0; i < rc && i < max_dest; i++) { + dest[i] = ctx->read_buf[offset + i]; + } + + return rc; +} + +/** + * @} + */ + +/** @defgroup Master_Raw_Operation_Functions Master Raw Operation Functions + * @{ + */ + +/** + * @brief 将原始数据打包成请求报文 + * @param ctx modbus 句柄 + * @param raw_req 原始报文(PDU + Slave address) + * @param raw_req_length 原始报文长度 + * @return >0:请求数据长度; 其他:异常 + */ +int agile_modbus_serialize_raw_request(agile_modbus_t *ctx, const uint8_t *raw_req, int raw_req_length) +{ + if (raw_req_length < 2) { + /* The raw request must contain function and slave at least and + must not be longer than the maximum pdu length plus the slave + address. */ + + return -1; + } + + int min_req_length = ctx->backend->header_length + 1 + ctx->backend->checksum_length + raw_req_length - 2; + if (ctx->send_bufsz < min_req_length) + return -1; + + agile_modbus_sft_t sft; + int req_length; + + sft.slave = raw_req[0]; + sft.function = raw_req[1]; + /* The t_id is left to zero */ + sft.t_id = 0; + /* This response function only set the header so it's convenient here */ + req_length = ctx->backend->build_response_basis(&sft, ctx->send_buf); + + if (raw_req_length > 2) { + /* Copy data after function code */ + memcpy(ctx->send_buf + req_length, raw_req + 2, raw_req_length - 2); + req_length += raw_req_length - 2; + } + + req_length = ctx->backend->send_msg_pre(ctx->send_buf, req_length); + + return req_length; +} + +/** + * @brief 解析响应原始数据 + * @param ctx modbus 句柄 + * @param msg_length 接收数据长度 + * @return >=0:对应功能码响应对象的长度(如 03 功能码,值代表寄存器个数); + * 其他:异常 (-1:报文错误;其他:可根据 `-128 - $返回值` 得到异常码) + */ +int agile_modbus_deserialize_raw_response(agile_modbus_t *ctx, int msg_length) +{ + int min_req_length = ctx->backend->header_length + 5 + ctx->backend->checksum_length; + if (ctx->send_bufsz < min_req_length) + return -1; + if ((msg_length <= 0) || (msg_length > ctx->read_bufsz)) + return -1; + + int rc = agile_modbus_receive_msg_judge(ctx, ctx->read_buf, msg_length, AGILE_MODBUS_MSG_CONFIRMATION); + if (rc < 0) + return -1; + + rc = agile_modbus_check_confirmation(ctx, ctx->send_buf, ctx->read_buf, rc); + + return rc; +} + +/** + * @} + */ + +/** + * @} + */ + +/** @defgroup Modbus_Slave Modbus Slave + * @{ + */ + +/** @defgroup Slave_Private_Functions Slave Private Functions + * @{ + */ + +/** + * @brief 打包异常响应数据 + * @param ctx modbus 句柄 + * @param sft modbus 信息头 + * @param exception_code 异常码 + * @return 响应数据长度 + */ +static int agile_modbus_serialize_response_exception(agile_modbus_t *ctx, agile_modbus_sft_t *sft, int exception_code) +{ + int rsp_length; + + /* Build exception response */ + sft->function = sft->function + 0x80; + rsp_length = ctx->backend->build_response_basis(sft, ctx->send_buf); + ctx->send_buf[rsp_length++] = exception_code; + + return rsp_length; +} + +/** + * @} + */ + +/** @defgroup Slave_Operation_Functions Slave Operation Functions + * @{ + */ + +/** + * @brief 从机 IO 设置 + * @param buf 存放 IO 数据区 + * @param index IO 索引(第几个 IO) + * @param status IO 状态 + */ +void agile_modbus_slave_io_set(uint8_t *buf, int index, int status) +{ + int offset = index / 8; + int shift = index % 8; + + if (status) + buf[offset] |= (0x01 << shift); + else + buf[offset] &= ~(0x01 << shift); +} + +/** + * @brief 读取从机 IO 状态 + * @param buf IO 数据区域 + * @param index IO 索引(第几个 IO) + * @return IO 状态(1/0) + */ +uint8_t agile_modbus_slave_io_get(uint8_t *buf, int index) +{ + int offset = index / 8; + int shift = index % 8; + + uint8_t status = (buf[offset] & (0x01 << shift)) ? 1 : 0; + + return status; +} + +/** + * @brief 从机寄存器设置 + * @param buf 存放数据区 + * @param index 寄存器索引(第几个寄存器) + * @param data 寄存器数据 + */ +void agile_modbus_slave_register_set(uint8_t *buf, int index, uint16_t data) +{ + buf[index * 2] = data >> 8; + buf[index * 2 + 1] = data & 0xFF; +} + +/** + * @brief 读取从机寄存器数据 + * @param buf 寄存器数据区域 + * @param index 寄存器索引(第几个寄存器) + * @return 寄存器数据 + */ +uint16_t agile_modbus_slave_register_get(uint8_t *buf, int index) +{ + uint16_t data = (buf[index * 2] << 8) + buf[index * 2 + 1]; + + return data; +} + +/** + * @brief 从机数据处理 + * @param ctx modbus 句柄 + * @param msg_length 接收数据长度 + * @param slave_strict 从机地址严格检查标志 + * @arg 0: 不比对从机地址 + * @arg 1: 比对从机地址 + * @param slave_cb 从机回调函数 + * @param slave_data 从机回调函数私有数据 + * @param frame_length 存放 modbus 数据帧长度 + * @return >=0:要响应的数据长度; 其他:异常 + */ +int agile_modbus_slave_handle(agile_modbus_t *ctx, int msg_length, uint8_t slave_strict, + agile_modbus_slave_callback_t slave_cb, const void *slave_data, int *frame_length) +{ + int min_rsp_length = ctx->backend->header_length + 5 + ctx->backend->checksum_length; + if (ctx->send_bufsz < min_rsp_length) + return -1; + + int req_length = agile_modbus_receive_judge(ctx, msg_length, AGILE_MODBUS_MSG_INDICATION); + if (req_length < 0) + return -1; + if (frame_length) + *frame_length = req_length; + + int offset; + int slave; + int function; + uint16_t address; + int rsp_length = 0; + int exception_code = 0; + agile_modbus_sft_t sft; + uint8_t *req = ctx->read_buf; + uint8_t *rsp = ctx->send_buf; + + memset(rsp, 0, ctx->send_bufsz); + offset = ctx->backend->header_length; + slave = req[offset - 1]; + function = req[offset]; + address = (req[offset + 1] << 8) + req[offset + 2]; + + sft.slave = slave; + sft.function = function; + sft.t_id = ctx->backend->prepare_response_tid(req, &req_length); + + struct agile_modbus_slave_info slave_info = {0}; + slave_info.sft = &sft; + slave_info.rsp_length = &rsp_length; + slave_info.address = address; + + if (slave_strict) { + if ((slave != ctx->slave) && (slave != AGILE_MODBUS_BROADCAST_ADDRESS)) + return 0; + } + + switch (function) { + case AGILE_MODBUS_FC_READ_COILS: + case AGILE_MODBUS_FC_READ_DISCRETE_INPUTS: { + int nb = (req[offset + 3] << 8) + req[offset + 4]; + if (nb < 1 || AGILE_MODBUS_MAX_READ_BITS < nb) { + exception_code = AGILE_MODBUS_EXCEPTION_ILLEGAL_DATA_VALUE; + break; + } + + int end_address = (int)address + nb - 1; + if (end_address > 0xFFFF) { + exception_code = AGILE_MODBUS_EXCEPTION_ILLEGAL_DATA_ADDRESS; + break; + } + + rsp_length = ctx->backend->build_response_basis(&sft, rsp); + slave_info.nb = (nb / 8) + ((nb % 8) ? 1 : 0); + rsp[rsp_length++] = slave_info.nb; + slave_info.send_index = rsp_length; + rsp_length += slave_info.nb; + slave_info.nb = nb; + if (ctx->send_bufsz < (int)(rsp_length + ctx->backend->checksum_length)) { + exception_code = AGILE_MODBUS_EXCEPTION_NEGATIVE_ACKNOWLEDGE; + break; + } + } break; + + case AGILE_MODBUS_FC_READ_HOLDING_REGISTERS: + case AGILE_MODBUS_FC_READ_INPUT_REGISTERS: { + int nb = (req[offset + 3] << 8) + req[offset + 4]; + if (nb < 1 || AGILE_MODBUS_MAX_READ_REGISTERS < nb) { + exception_code = AGILE_MODBUS_EXCEPTION_ILLEGAL_DATA_VALUE; + break; + } + + int end_address = (int)address + nb - 1; + if (end_address > 0xFFFF) { + exception_code = AGILE_MODBUS_EXCEPTION_ILLEGAL_DATA_ADDRESS; + break; + } + + rsp_length = ctx->backend->build_response_basis(&sft, rsp); + slave_info.nb = nb << 1; + rsp[rsp_length++] = slave_info.nb; + slave_info.send_index = rsp_length; + rsp_length += slave_info.nb; + slave_info.nb = nb; + if (ctx->send_bufsz < (int)(rsp_length + ctx->backend->checksum_length)) { + exception_code = AGILE_MODBUS_EXCEPTION_NEGATIVE_ACKNOWLEDGE; + break; + } + } break; + + case AGILE_MODBUS_FC_WRITE_SINGLE_COIL: { + //! warning: comparison is always false due to limited range of data type [-Wtype-limits] + #if 0 + if (address > 0xFFFF) { + exception_code = AGILE_MODBUS_EXCEPTION_ILLEGAL_DATA_ADDRESS; + break; + } + #endif + + int data = (req[offset + 3] << 8) + req[offset + 4]; + if (data == 0xFF00 || data == 0x0) + data = data ? 1 : 0; + else { + exception_code = AGILE_MODBUS_EXCEPTION_ILLEGAL_DATA_VALUE; + break; + } + + slave_info.buf = (uint8_t *)&data; + rsp_length = req_length; + if (ctx->send_bufsz < (int)(rsp_length + ctx->backend->checksum_length)) { + exception_code = AGILE_MODBUS_EXCEPTION_NEGATIVE_ACKNOWLEDGE; + break; + } + memcpy(rsp, req, req_length); + } break; + + case AGILE_MODBUS_FC_WRITE_SINGLE_REGISTER: { + //! warning: comparison is always false due to limited range of data type [-Wtype-limits] + #if 0 + if (address > 0xFFFF) { + exception_code = AGILE_MODBUS_EXCEPTION_ILLEGAL_DATA_ADDRESS; + break; + } + #endif + + int data = (req[offset + 3] << 8) + req[offset + 4]; + + slave_info.buf = (uint8_t *)&data; + rsp_length = req_length; + if (ctx->send_bufsz < (int)(rsp_length + ctx->backend->checksum_length)) { + exception_code = AGILE_MODBUS_EXCEPTION_NEGATIVE_ACKNOWLEDGE; + break; + } + memcpy(rsp, req, req_length); + } break; + + case AGILE_MODBUS_FC_WRITE_MULTIPLE_COILS: { + int nb = (req[offset + 3] << 8) + req[offset + 4]; + int nb_bits = req[offset + 5]; + if (nb < 1 || AGILE_MODBUS_MAX_WRITE_BITS < nb || nb_bits * 8 < nb) { + exception_code = AGILE_MODBUS_EXCEPTION_ILLEGAL_DATA_VALUE; + break; + } + + int end_address = (int)address + nb - 1; + if (end_address > 0xFFFF) { + exception_code = AGILE_MODBUS_EXCEPTION_ILLEGAL_DATA_ADDRESS; + break; + } + + rsp_length = ctx->backend->build_response_basis(&sft, rsp); + slave_info.nb = nb; + slave_info.buf = &req[offset + 6]; + if (ctx->send_bufsz < (int)(rsp_length + ctx->backend->checksum_length + 4)) { + exception_code = AGILE_MODBUS_EXCEPTION_NEGATIVE_ACKNOWLEDGE; + break; + } + /* 4 to copy the bit address (2) and the quantity of bits */ + memcpy(rsp + rsp_length, req + rsp_length, 4); + rsp_length += 4; + } break; + + case AGILE_MODBUS_FC_WRITE_MULTIPLE_REGISTERS: { + int nb = (req[offset + 3] << 8) + req[offset + 4]; + int nb_bytes = req[offset + 5]; + if (nb < 1 || AGILE_MODBUS_MAX_WRITE_REGISTERS < nb || nb_bytes != nb * 2) { + exception_code = AGILE_MODBUS_EXCEPTION_ILLEGAL_DATA_VALUE; + break; + } + + int end_address = (int)address + nb - 1; + if (end_address > 0xFFFF) { + exception_code = AGILE_MODBUS_EXCEPTION_ILLEGAL_DATA_ADDRESS; + break; + } + + rsp_length = ctx->backend->build_response_basis(&sft, rsp); + slave_info.nb = nb; + slave_info.buf = &req[offset + 6]; + if (ctx->send_bufsz < (int)(rsp_length + ctx->backend->checksum_length + 4)) { + exception_code = AGILE_MODBUS_EXCEPTION_NEGATIVE_ACKNOWLEDGE; + break; + } + /* 4 to copy the address (2) and the no. of registers */ + memcpy(rsp + rsp_length, req + rsp_length, 4); + rsp_length += 4; + + } break; + + case AGILE_MODBUS_FC_REPORT_SLAVE_ID: { + int str_len; + int byte_count_pos; + + slave_cb = NULL; + rsp_length = ctx->backend->build_response_basis(&sft, rsp); + /* Skip byte count for now */ + byte_count_pos = rsp_length++; + rsp[rsp_length++] = ctx->slave; + /* Run indicator status to ON */ + rsp[rsp_length++] = 0xFF; + + str_len = strlen(AGILE_MODBUS_VERSION_STRING); + if (ctx->send_bufsz < (int)(rsp_length + ctx->backend->checksum_length + str_len)) { + exception_code = AGILE_MODBUS_EXCEPTION_NEGATIVE_ACKNOWLEDGE; + break; + } + memcpy(rsp + rsp_length, AGILE_MODBUS_VERSION_STRING, str_len); + rsp_length += str_len; + rsp[byte_count_pos] = rsp_length - byte_count_pos - 1; + } break; + + case AGILE_MODBUS_FC_READ_EXCEPTION_STATUS: + exception_code = AGILE_MODBUS_EXCEPTION_ILLEGAL_FUNCTION; + break; + + case AGILE_MODBUS_FC_MASK_WRITE_REGISTER: { + //! warning: comparison is always false due to limited range of data type [-Wtype-limits] + #if 0 + if (address > 0xFFFF) { + exception_code = AGILE_MODBUS_EXCEPTION_ILLEGAL_DATA_ADDRESS; + break; + } + #endif + + slave_info.buf = &req[offset + 3]; + rsp_length = req_length; + if (ctx->send_bufsz < (int)(rsp_length + ctx->backend->checksum_length)) { + exception_code = AGILE_MODBUS_EXCEPTION_NEGATIVE_ACKNOWLEDGE; + break; + } + memcpy(rsp, req, req_length); + } break; + + case AGILE_MODBUS_FC_WRITE_AND_READ_REGISTERS: { + int nb = (req[offset + 3] << 8) + req[offset + 4]; + uint16_t address_write = (req[offset + 5] << 8) + req[offset + 6]; + int nb_write = (req[offset + 7] << 8) + req[offset + 8]; + int nb_write_bytes = req[offset + 9]; + if (nb_write < 1 || AGILE_MODBUS_MAX_WR_WRITE_REGISTERS < nb_write || + nb < 1 || AGILE_MODBUS_MAX_WR_READ_REGISTERS < nb || + nb_write_bytes != nb_write * 2) { + exception_code = AGILE_MODBUS_EXCEPTION_ILLEGAL_DATA_VALUE; + break; + } + + int end_address = (int)address + nb - 1; + int end_address_write = (int)address_write + nb_write - 1; + if (end_address > 0xFFFF || end_address_write > 0xFFFF) { + exception_code = AGILE_MODBUS_EXCEPTION_ILLEGAL_DATA_ADDRESS; + break; + } + + rsp_length = ctx->backend->build_response_basis(&sft, rsp); + rsp[rsp_length++] = nb << 1; + slave_info.buf = &req[offset + 3]; + slave_info.send_index = rsp_length; + rsp_length += (nb << 1); + if (ctx->send_bufsz < (int)(rsp_length + ctx->backend->checksum_length)) { + exception_code = AGILE_MODBUS_EXCEPTION_NEGATIVE_ACKNOWLEDGE; + break; + } + } break; + + default: { + if (slave_cb == NULL) + exception_code = AGILE_MODBUS_EXCEPTION_ILLEGAL_FUNCTION; + else { + rsp_length = ctx->backend->build_response_basis(&sft, rsp); + slave_info.send_index = rsp_length; + slave_info.buf = &req[offset + 1]; + slave_info.nb = req_length - offset - 1; + } + } break; + } + + if (exception_code) + rsp_length = agile_modbus_serialize_response_exception(ctx, &sft, exception_code); + else { + if (slave_cb) { + int ret = slave_cb(ctx, &slave_info, slave_data); + + if (ret < 0) { + if (ret == -AGILE_MODBUS_EXCEPTION_UNKNOW) + rsp_length = 0; + else + rsp_length = agile_modbus_serialize_response_exception(ctx, &sft, -ret); + } + } + } + + if (rsp_length) { + if ((ctx->backend->backend_type == AGILE_MODBUS_BACKEND_TYPE_RTU) && (slave == AGILE_MODBUS_BROADCAST_ADDRESS)) + return 0; + + rsp_length = ctx->backend->send_msg_pre(rsp, rsp_length); + } + + return rsp_length; +} + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ diff --git a/examples/pikapython/pikapython/pikascript-lib/modbus/agile_modbus.h b/examples/pikapython/pikapython/pikascript-lib/modbus/agile_modbus.h new file mode 100755 index 00000000..4be7429b --- /dev/null +++ b/examples/pikapython/pikapython/pikascript-lib/modbus/agile_modbus.h @@ -0,0 +1,359 @@ +/** + * @file agile_modbus.h + * @brief Agile Modbus 软件包通用头文件 + * @author 马龙伟 (2544047213@qq.com) + * @date 2022-07-28 + * + * @attention + * + *

© Copyright (c) 2021 Ma Longwei. + * All rights reserved.

+ * + */ + +#ifndef __PKG_AGILE_MODBUS_H +#define __PKG_AGILE_MODBUS_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include + +/** @addtogroup COMMON + * @{ + */ + +/** @defgroup COMMON_Exported_Constants Common Exported Constants + * @{ + */ + +/** @defgroup Modbus_Function_Codes Modbus Function Codes + * @{ + */ +#define AGILE_MODBUS_FC_READ_COILS 0x01 +#define AGILE_MODBUS_FC_READ_DISCRETE_INPUTS 0x02 +#define AGILE_MODBUS_FC_READ_HOLDING_REGISTERS 0x03 +#define AGILE_MODBUS_FC_READ_INPUT_REGISTERS 0x04 +#define AGILE_MODBUS_FC_WRITE_SINGLE_COIL 0x05 +#define AGILE_MODBUS_FC_WRITE_SINGLE_REGISTER 0x06 +#define AGILE_MODBUS_FC_READ_EXCEPTION_STATUS 0x07 +#define AGILE_MODBUS_FC_WRITE_MULTIPLE_COILS 0x0F +#define AGILE_MODBUS_FC_WRITE_MULTIPLE_REGISTERS 0x10 +#define AGILE_MODBUS_FC_REPORT_SLAVE_ID 0x11 +#define AGILE_MODBUS_FC_MASK_WRITE_REGISTER 0x16 +#define AGILE_MODBUS_FC_WRITE_AND_READ_REGISTERS 0x17 +/** + * @} + */ + +/** @defgroup Modbus_Constants Modbus Constants + * @{ + */ +#define AGILE_MODBUS_VERSION_STRING "AMB_1.1.0" /**< Agile Modbus 版本号 */ + +#define AGILE_MODBUS_BROADCAST_ADDRESS 0 /**< Modbus 广播地址 */ + +/** @name Quantity limit of Coils + @verbatim + Modbus_Application_Protocol_V1_1b.pdf (chapter 6 section 1 page 12) + Quantity of Coils to read (2 bytes): 1 to 2000 (0x7D0) + (chapter 6 section 11 page 29) + Quantity of Coils to write (2 bytes): 1 to 1968 (0x7B0) + + @endverbatim + * @{ + */ +#define AGILE_MODBUS_MAX_READ_BITS 2000 +#define AGILE_MODBUS_MAX_WRITE_BITS 1968 +/** + * @} + */ + +/** @name Quantity limit of Registers + @verbatim + Modbus_Application_Protocol_V1_1b.pdf (chapter 6 section 3 page 15) + Quantity of Registers to read (2 bytes): 1 to 125 (0x7D) + (chapter 6 section 12 page 31) + Quantity of Registers to write (2 bytes) 1 to 123 (0x7B) + (chapter 6 section 17 page 38) + Quantity of Registers to write in R/W registers (2 bytes) 1 to 121 (0x79) + + @endverbatim + * @{ + */ +#define AGILE_MODBUS_MAX_READ_REGISTERS 125 +#define AGILE_MODBUS_MAX_WRITE_REGISTERS 123 +#define AGILE_MODBUS_MAX_WR_WRITE_REGISTERS 121 +#define AGILE_MODBUS_MAX_WR_READ_REGISTERS 125 +/** + * @} + */ + +/** + @verbatim + The size of the MODBUS PDU is limited by the size constraint inherited from + the first MODBUS implementation on Serial Line network (max. RS485 ADU = 256 + bytes). Therefore, MODBUS PDU for serial line communication = 256 - Server + address (1 byte) - CRC (2 bytes) = 253 bytes. + + @endverbatim + */ +#define AGILE_MODBUS_MAX_PDU_LENGTH 253 + +/** + @verbatim + Consequently: + - RTU MODBUS ADU = 253 bytes + Server address (1 byte) + CRC (2 bytes) = 256 + bytes. + - TCP MODBUS ADU = 253 bytes + MBAP (7 bytes) = 260 bytes. + so the maximum of both backend in 260 bytes. This size can used to allocate + an array of bytes to store responses and it will be compatible with the two + backends. + + @endverbatim + */ +#define AGILE_MODBUS_MAX_ADU_LENGTH 260 +/** + * @} + */ + +/** + * @} + */ + +/** @defgroup COMMON_Exported_Types Common Exported Types + * @{ + */ + +/** + * @brief Modbus 异常码 + */ +enum { + AGILE_MODBUS_EXCEPTION_ILLEGAL_FUNCTION = 0x01, + AGILE_MODBUS_EXCEPTION_ILLEGAL_DATA_ADDRESS, + AGILE_MODBUS_EXCEPTION_ILLEGAL_DATA_VALUE, + AGILE_MODBUS_EXCEPTION_SLAVE_OR_SERVER_FAILURE, + AGILE_MODBUS_EXCEPTION_ACKNOWLEDGE, + AGILE_MODBUS_EXCEPTION_SLAVE_OR_SERVER_BUSY, + AGILE_MODBUS_EXCEPTION_NEGATIVE_ACKNOWLEDGE, + AGILE_MODBUS_EXCEPTION_MEMORY_PARITY, + AGILE_MODBUS_EXCEPTION_NOT_DEFINED, + AGILE_MODBUS_EXCEPTION_GATEWAY_PATH, + AGILE_MODBUS_EXCEPTION_GATEWAY_TARGET, + AGILE_MODBUS_EXCEPTION_UNKNOW = 0xff +}; + +/** + * @brief Modbus 后端类型 + */ +typedef enum { + AGILE_MODBUS_BACKEND_TYPE_RTU = 0, /**< RTU */ + AGILE_MODBUS_BACKEND_TYPE_TCP /**< TCP */ +} agile_modbus_backend_type_t; + +/** + * @brief Modbus 收到消息类型 + * + @verbatim + ---------- Request Indication ---------- + | Client | ---------------------->| Server | + ---------- Confirmation Response ---------- + + @endverbatim + */ +typedef enum { + AGILE_MODBUS_MSG_INDICATION, /**< 主机端的请求消息 */ + AGILE_MODBUS_MSG_CONFIRMATION /**< 服务器端的请求消息 */ +} agile_modbus_msg_type_t; + +/** + * @brief 包含 modbus 头部参数结构体 + */ +typedef struct agile_modbus_sft { + int slave; /**< 从机地址 */ + int function; /**< 功能码 */ + int t_id; /**< 事务标识符 */ +} agile_modbus_sft_t; + +typedef struct agile_modbus agile_modbus_t; /**< Agile Modbus 结构体 */ + +/** + * @brief Agile Modbus 后端接口结构体 + */ +typedef struct agile_modbus_backend { + uint32_t backend_type; /**< 后端类型 */ + uint32_t header_length; /**< 头部长度,不包含功能码 */ + uint32_t checksum_length; /**< 校验数据长度 */ + uint32_t max_adu_length; /**< 后端 ADU 长度 */ + int (*set_slave)(agile_modbus_t *ctx, int slave); /**< 设置地址接口 */ + int (*build_request_basis)(agile_modbus_t *ctx, int function, int addr, + int nb, uint8_t *req); /**< 构建基础请求报文接口 */ + int (*build_response_basis)(agile_modbus_sft_t *sft, uint8_t *rsp); /**< 构建基础响应报文接口 */ + int (*prepare_response_tid)(const uint8_t *req, int *req_length); /**< 准备响应接口 */ + int (*send_msg_pre)(uint8_t *req, int req_length); /**< 预发送数据接口 */ + int (*check_integrity)(agile_modbus_t *ctx, uint8_t *msg, const int msg_length); /**< 检查接收数据完整性接口 */ + int (*pre_check_confirmation)(agile_modbus_t *ctx, const uint8_t *req, + const uint8_t *rsp, int rsp_length); /**< 预检查确认接口 */ +} agile_modbus_backend_t; + +/** + * @brief Agile Modbus 结构体 + */ +struct agile_modbus { + int slave; /**< 从机地址 */ + uint8_t *send_buf; /**< 发送缓冲区 */ + int send_bufsz; /**< 发送缓冲区大小 */ + uint8_t *read_buf; /**< 接收缓冲区 */ + int read_bufsz; /**< 接收缓冲区大小 */ + uint8_t (*compute_meta_length_after_function)(agile_modbus_t *ctx, int function, + agile_modbus_msg_type_t msg_type); /**< 自定义计算数据元长度接口 */ + int (*compute_data_length_after_meta)(agile_modbus_t *ctx, uint8_t *msg, + int msg_length, agile_modbus_msg_type_t msg_type); /**< 自定义计算数据长度接口 */ + const agile_modbus_backend_t *backend; /**< 后端接口 */ + void *backend_data; /**< 后端数据,指向 RTU 或 TCP 结构体 */ +}; + +/** + * @} + */ + +/** @addtogroup Modbus_Slave + * @{ + */ + +/** @defgroup Slave_Exported_Types Slave Exported Types + * @{ + */ + +/** + * @brief Agile Modbus 从机信息结构体 + */ +struct agile_modbus_slave_info { + agile_modbus_sft_t *sft; /**< sft 结构体指针 */ + int *rsp_length; /**< 响应数据长度指针 */ + int address; /**< 寄存器地址 */ + int nb; /**< 数目 */ + uint8_t *buf; /**< 不同功能码需要使用的数据域 */ + int send_index; /**< 发送缓冲区当前索引 */ +}; + +/** + * @brief 从机回调函数 + * @param ctx modbus 句柄 + * @param slave_info 从机信息体 + * @param data 私有数据 + * @return =0:正常; + * <0:异常 + * (-AGILE_MODBUS_EXCEPTION_UNKNOW(-255): 未知异常,从机不会打包响应数据) + * (其他负数异常码: 从机会打包异常响应数据) + */ +typedef int (*agile_modbus_slave_callback_t)(agile_modbus_t *ctx, struct agile_modbus_slave_info *slave_info, const void *data); + +/** + * @} + */ + +/** + * @} + */ + +/** @addtogroup COMMON_Exported_Functions + * @{ + */ +void agile_modbus_common_init(agile_modbus_t *ctx, uint8_t *send_buf, int send_bufsz, uint8_t *read_buf, int read_bufsz); +int agile_modbus_set_slave(agile_modbus_t *ctx, int slave); +void agile_modbus_set_compute_meta_length_after_function_cb(agile_modbus_t *ctx, + uint8_t (*cb)(agile_modbus_t *ctx, int function, + agile_modbus_msg_type_t msg_type)); +void agile_modbus_set_compute_data_length_after_meta_cb(agile_modbus_t *ctx, + int (*cb)(agile_modbus_t *ctx, uint8_t *msg, + int msg_length, agile_modbus_msg_type_t msg_type)); +int agile_modbus_receive_judge(agile_modbus_t *ctx, int msg_length, agile_modbus_msg_type_t msg_type); +/** + * @} + */ + +/** @addtogroup Modbus_Master + * @{ + */ + +/** @addtogroup Master_Common_Operation_Functions + * @{ + */ +int agile_modbus_serialize_read_bits(agile_modbus_t *ctx, int addr, int nb); +int agile_modbus_deserialize_read_bits(agile_modbus_t *ctx, int msg_length, uint8_t *dest); +int agile_modbus_serialize_read_input_bits(agile_modbus_t *ctx, int addr, int nb); +int agile_modbus_deserialize_read_input_bits(agile_modbus_t *ctx, int msg_length, uint8_t *dest); +int agile_modbus_serialize_read_registers(agile_modbus_t *ctx, int addr, int nb); +int agile_modbus_deserialize_read_registers(agile_modbus_t *ctx, int msg_length, uint16_t *dest); +int agile_modbus_serialize_read_input_registers(agile_modbus_t *ctx, int addr, int nb); +int agile_modbus_deserialize_read_input_registers(agile_modbus_t *ctx, int msg_length, uint16_t *dest); +int agile_modbus_serialize_write_bit(agile_modbus_t *ctx, int addr, int status); +int agile_modbus_deserialize_write_bit(agile_modbus_t *ctx, int msg_length); +int agile_modbus_serialize_write_register(agile_modbus_t *ctx, int addr, const uint16_t value); +int agile_modbus_deserialize_write_register(agile_modbus_t *ctx, int msg_length); +int agile_modbus_serialize_write_bits(agile_modbus_t *ctx, int addr, int nb, const uint8_t *src); +int agile_modbus_deserialize_write_bits(agile_modbus_t *ctx, int msg_length); +int agile_modbus_serialize_write_registers(agile_modbus_t *ctx, int addr, int nb, const uint16_t *src); +int agile_modbus_deserialize_write_registers(agile_modbus_t *ctx, int msg_length); +int agile_modbus_serialize_mask_write_register(agile_modbus_t *ctx, int addr, uint16_t and_mask, uint16_t or_mask); +int agile_modbus_deserialize_mask_write_register(agile_modbus_t *ctx, int msg_length); +int agile_modbus_serialize_write_and_read_registers(agile_modbus_t *ctx, + int write_addr, int write_nb, + const uint16_t *src, + int read_addr, int read_nb); +int agile_modbus_deserialize_write_and_read_registers(agile_modbus_t *ctx, int msg_length, uint16_t *dest); +int agile_modbus_serialize_report_slave_id(agile_modbus_t *ctx); +int agile_modbus_deserialize_report_slave_id(agile_modbus_t *ctx, int msg_length, int max_dest, uint8_t *dest); +/** + * @} + */ + +/** @addtogroup Master_Raw_Operation_Functions + * @{ + */ +int agile_modbus_serialize_raw_request(agile_modbus_t *ctx, const uint8_t *raw_req, int raw_req_length); +int agile_modbus_deserialize_raw_response(agile_modbus_t *ctx, int msg_length); +/** + * @} + */ + +/** + * @} + */ + +/** @addtogroup Modbus_Slave + * @{ + */ + +/** @addtogroup Slave_Operation_Functions + * @{ + */ +int agile_modbus_slave_handle(agile_modbus_t *ctx, int msg_length, uint8_t slave_strict, + agile_modbus_slave_callback_t slave_cb, const void *slave_data, int *frame_length); +void agile_modbus_slave_io_set(uint8_t *buf, int index, int status); +uint8_t agile_modbus_slave_io_get(uint8_t *buf, int index); +void agile_modbus_slave_register_set(uint8_t *buf, int index, uint16_t data); +uint16_t agile_modbus_slave_register_get(uint8_t *buf, int index); +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +/* Include RTU and TCP module */ +#include "agile_modbus_rtu.h" +#include "agile_modbus_tcp.h" + +#ifdef __cplusplus +} +#endif + +#endif /* __PKG_AGILE_MODBUS_H */ diff --git a/examples/pikapython/pikapython/pikascript-lib/modbus/agile_modbus_rtu.c b/examples/pikapython/pikapython/pikascript-lib/modbus/agile_modbus_rtu.c new file mode 100755 index 00000000..95b24cf0 --- /dev/null +++ b/examples/pikapython/pikapython/pikascript-lib/modbus/agile_modbus_rtu.c @@ -0,0 +1,291 @@ +/** + * @file agile_modbus_rtu.c + * @brief Agile Modbus 软件包 RTU 源文件 + * @author 马龙伟 (2544047213@qq.com) + * @date 2021-12-02 + * + * @attention + * + *

© Copyright (c) 2021 Ma Longwei. + * All rights reserved.

+ * + */ + +#include "agile_modbus.h" +#include "agile_modbus_rtu.h" + +/** @defgroup RTU RTU + * @{ + */ + +/** @defgroup RTU_Private_Constants RTU Private Constants + * @{ + */ +/** Table of CRC values for high-order byte */ +static const uint8_t _table_crc_hi[] = + { + 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, + 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, + 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, + 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, + 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, + 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, + 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, + 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, + 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, + 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, + 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, + 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, + 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, + 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, + 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, + 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, + 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, + 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, + 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, + 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, + 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, + 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, + 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, + 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, + 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, + 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40}; + +/** Table of CRC values for low-order byte */ +static const uint8_t _table_crc_lo[] = + { + 0x00, 0xC0, 0xC1, 0x01, 0xC3, 0x03, 0x02, 0xC2, 0xC6, 0x06, + 0x07, 0xC7, 0x05, 0xC5, 0xC4, 0x04, 0xCC, 0x0C, 0x0D, 0xCD, + 0x0F, 0xCF, 0xCE, 0x0E, 0x0A, 0xCA, 0xCB, 0x0B, 0xC9, 0x09, + 0x08, 0xC8, 0xD8, 0x18, 0x19, 0xD9, 0x1B, 0xDB, 0xDA, 0x1A, + 0x1E, 0xDE, 0xDF, 0x1F, 0xDD, 0x1D, 0x1C, 0xDC, 0x14, 0xD4, + 0xD5, 0x15, 0xD7, 0x17, 0x16, 0xD6, 0xD2, 0x12, 0x13, 0xD3, + 0x11, 0xD1, 0xD0, 0x10, 0xF0, 0x30, 0x31, 0xF1, 0x33, 0xF3, + 0xF2, 0x32, 0x36, 0xF6, 0xF7, 0x37, 0xF5, 0x35, 0x34, 0xF4, + 0x3C, 0xFC, 0xFD, 0x3D, 0xFF, 0x3F, 0x3E, 0xFE, 0xFA, 0x3A, + 0x3B, 0xFB, 0x39, 0xF9, 0xF8, 0x38, 0x28, 0xE8, 0xE9, 0x29, + 0xEB, 0x2B, 0x2A, 0xEA, 0xEE, 0x2E, 0x2F, 0xEF, 0x2D, 0xED, + 0xEC, 0x2C, 0xE4, 0x24, 0x25, 0xE5, 0x27, 0xE7, 0xE6, 0x26, + 0x22, 0xE2, 0xE3, 0x23, 0xE1, 0x21, 0x20, 0xE0, 0xA0, 0x60, + 0x61, 0xA1, 0x63, 0xA3, 0xA2, 0x62, 0x66, 0xA6, 0xA7, 0x67, + 0xA5, 0x65, 0x64, 0xA4, 0x6C, 0xAC, 0xAD, 0x6D, 0xAF, 0x6F, + 0x6E, 0xAE, 0xAA, 0x6A, 0x6B, 0xAB, 0x69, 0xA9, 0xA8, 0x68, + 0x78, 0xB8, 0xB9, 0x79, 0xBB, 0x7B, 0x7A, 0xBA, 0xBE, 0x7E, + 0x7F, 0xBF, 0x7D, 0xBD, 0xBC, 0x7C, 0xB4, 0x74, 0x75, 0xB5, + 0x77, 0xB7, 0xB6, 0x76, 0x72, 0xB2, 0xB3, 0x73, 0xB1, 0x71, + 0x70, 0xB0, 0x50, 0x90, 0x91, 0x51, 0x93, 0x53, 0x52, 0x92, + 0x96, 0x56, 0x57, 0x97, 0x55, 0x95, 0x94, 0x54, 0x9C, 0x5C, + 0x5D, 0x9D, 0x5F, 0x9F, 0x9E, 0x5E, 0x5A, 0x9A, 0x9B, 0x5B, + 0x99, 0x59, 0x58, 0x98, 0x88, 0x48, 0x49, 0x89, 0x4B, 0x8B, + 0x8A, 0x4A, 0x4E, 0x8E, 0x8F, 0x4F, 0x8D, 0x4D, 0x4C, 0x8C, + 0x44, 0x84, 0x85, 0x45, 0x87, 0x47, 0x46, 0x86, 0x82, 0x42, + 0x43, 0x83, 0x41, 0x81, 0x80, 0x40}; +/** + * @} + */ + +/** @defgroup RTU_Private_Functions RTU Private Functions + * @{ + */ + +/** + * @brief RTU CRC16 计算 + * @param buffer 数据指针 + * @param buffer_length 数据长度 + * @return CRC16 值 + */ +static uint16_t agile_modbus_rtu_crc16(uint8_t *buffer, uint16_t buffer_length) +{ + uint8_t crc_hi = 0xFF; /* high CRC byte initialized */ + uint8_t crc_lo = 0xFF; /* low CRC byte initialized */ + unsigned int i; /* will index into CRC lookup */ + + /* pass through message buffer */ + while (buffer_length--) { + i = crc_hi ^ *buffer++; /* calculate the CRC */ + crc_hi = crc_lo ^ _table_crc_hi[i]; + crc_lo = _table_crc_lo[i]; + } + + return (crc_hi << 8 | crc_lo); +} + +/** + * @brief RTU 设置地址接口 + * @param ctx modbus 句柄 + * @param slave 从机地址 + * @return 0:成功 + */ +static int agile_modbus_rtu_set_slave(agile_modbus_t *ctx, int slave) +{ + ctx->slave = slave; + return 0; +} + +/** + * @brief RTU 构建基础请求报文接口(头部报文) + * @param ctx modbus 句柄 + * @param function 功能码 + * @param addr 寄存器地址 + * @param nb 寄存器数目 + * @param req 数据存放指针 + * @return 数据长度 + */ +static int agile_modbus_rtu_build_request_basis(agile_modbus_t *ctx, int function, + int addr, int nb, + uint8_t *req) +{ + req[0] = ctx->slave; + req[1] = function; + req[2] = addr >> 8; + req[3] = addr & 0x00ff; + req[4] = nb >> 8; + req[5] = nb & 0x00ff; + + return AGILE_MODBUS_RTU_PRESET_REQ_LENGTH; +} + +/** + * @brief RTU 构建基础响应报文接口(头部报文) + * @param sft modbus 头部参数结构体指针 + * @param rsp 数据存放指针 + * @return 数据长度 + */ +static int agile_modbus_rtu_build_response_basis(agile_modbus_sft_t *sft, uint8_t *rsp) +{ + rsp[0] = sft->slave; + rsp[1] = sft->function; + + return AGILE_MODBUS_RTU_PRESET_RSP_LENGTH; +} + +/** + * @brief RTU 准备响应接口 + * @note 该 API 会将 req_length 自动减去 AGILE_MODBUS_RTU_CHECKSUM_LENGTH 长度 + * @param req 请求数据指针 + * @param req_length 请求数据长度 + * @return 0 (RTU 没有事务标识符) + */ +static int agile_modbus_rtu_prepare_response_tid(const uint8_t *req, int *req_length) +{ + (*req_length) -= AGILE_MODBUS_RTU_CHECKSUM_LENGTH; + /* No TID */ + return 0; +} + +/** + * @brief RTU 预发送数据接口 + * @note 该 API 会计算 CRC16 并自动填入尾部 + * @param req 数据存放指针 + * @param req_length 已有数据长度 + * @return 数据长度 + */ +static int agile_modbus_rtu_send_msg_pre(uint8_t *req, int req_length) +{ + uint16_t crc = agile_modbus_rtu_crc16(req, req_length); + req[req_length++] = crc >> 8; + req[req_length++] = crc & 0x00FF; + + return req_length; +} + +/** + * @brief RTU 检查接收数据完整性接口(CRC16 对比) + * @param ctx modbus 句柄 + * @param msg 接收数据指针 + * @param msg_length 有效数据长度 + * @return >0:有效数据长度; 其他:异常 + */ +static int agile_modbus_rtu_check_integrity(agile_modbus_t *ctx, uint8_t *msg, const int msg_length) +{ + uint16_t crc_calculated; + uint16_t crc_received; + + crc_calculated = agile_modbus_rtu_crc16(msg, msg_length - 2); + crc_received = (msg[msg_length - 2] << 8) | msg[msg_length - 1]; + + /* Check CRC of msg */ + if (crc_calculated == crc_received) + return msg_length; + + return -1; +} + +/** + * @brief RTU 预检查确认接口(请求响应地址对比) + * @note 如果请求地址是广播地址0,返回成功 + * @param ctx modbus 句柄 + * @param req 请求数据指针 + * @param rsp 响应数据指针 + * @param rsp_length 响应数据长度 + * @return 0:成功; 其他:异常 + */ +static int agile_modbus_rtu_pre_check_confirmation(agile_modbus_t *ctx, const uint8_t *req, + const uint8_t *rsp, int rsp_length) +{ + /* Check responding slave is the slave we requested (except for broacast + * request) */ + if (req[0] != rsp[0] && req[0] != AGILE_MODBUS_BROADCAST_ADDRESS) + return -1; + + return 0; +} + +/** + * @} + */ + +/** @addtogroup RTU_Private_Constants + * @{ + */ + +/** + * @brief RTU 后端接口 + */ +static const agile_modbus_backend_t agile_modbus_rtu_backend = + { + AGILE_MODBUS_BACKEND_TYPE_RTU, + AGILE_MODBUS_RTU_HEADER_LENGTH, + AGILE_MODBUS_RTU_CHECKSUM_LENGTH, + AGILE_MODBUS_RTU_MAX_ADU_LENGTH, + agile_modbus_rtu_set_slave, + agile_modbus_rtu_build_request_basis, + agile_modbus_rtu_build_response_basis, + agile_modbus_rtu_prepare_response_tid, + agile_modbus_rtu_send_msg_pre, + agile_modbus_rtu_check_integrity, + agile_modbus_rtu_pre_check_confirmation}; + +/** + * @} + */ + +/** @defgroup RTU_Exported_Functions RTU Exported Functions + * @{ + */ + +/** + * @brief RTU 初始化 + * @param ctx RTU 句柄 + * @param send_buf 发送缓冲区 + * @param send_bufsz 发送缓冲区大小 + * @param read_buf 接收缓冲区 + * @param read_bufsz 接收缓冲区大小 + * @return 0:成功 + */ +int agile_modbus_rtu_init(agile_modbus_rtu_t *ctx, uint8_t *send_buf, int send_bufsz, uint8_t *read_buf, int read_bufsz) +{ + agile_modbus_common_init(&(ctx->_ctx), send_buf, send_bufsz, read_buf, read_bufsz); + ctx->_ctx.backend = &agile_modbus_rtu_backend; + ctx->_ctx.backend_data = ctx; + + return 0; +} + +/** + * @} + */ + +/** + * @} + */ diff --git a/examples/pikapython/pikapython/pikascript-lib/modbus/agile_modbus_rtu.h b/examples/pikapython/pikapython/pikascript-lib/modbus/agile_modbus_rtu.h new file mode 100755 index 00000000..062aa84a --- /dev/null +++ b/examples/pikapython/pikapython/pikascript-lib/modbus/agile_modbus_rtu.h @@ -0,0 +1,79 @@ +/** + * @file agile_modbus_rtu.h + * @brief Agile Modbus 软件包 RTU 头文件 + * @author 马龙伟 (2544047213@qq.com) + * @date 2021-12-02 + * + * @attention + * + *

© Copyright (c) 2021 Ma Longwei. + * All rights reserved.

+ * + */ + +#ifndef __PKG_AGILE_MODBUS_RTU_H +#define __PKG_AGILE_MODBUS_RTU_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include + +/** @addtogroup RTU + * @{ + */ + +/** @defgroup RTU_Exported_Constants RTU Exported Constants + * @{ + */ +#define AGILE_MODBUS_RTU_HEADER_LENGTH 1 +#define AGILE_MODBUS_RTU_PRESET_REQ_LENGTH 6 +#define AGILE_MODBUS_RTU_PRESET_RSP_LENGTH 2 + +#define AGILE_MODBUS_RTU_CHECKSUM_LENGTH 2 + +/** + @verbatim + Modbus_Application_Protocol_V1_1b.pdf Chapter 4 Section 1 Page 5 + RS232 / RS485 ADU = 253 bytes + slave (1 byte) + CRC (2 bytes) = 256 bytes + + @endverbatim + */ +#define AGILE_MODBUS_RTU_MAX_ADU_LENGTH 256 +/** + * @} + */ + +/** @defgroup RTU_Exported_Types RTU Exported Types + * @{ + */ + +/** + * @brief RTU 结构体 + */ +typedef struct agile_modbus_rtu { + agile_modbus_t _ctx; /**< modbus 句柄 */ +} agile_modbus_rtu_t; + +/** + * @} + */ + +/** @addtogroup RTU_Exported_Functions + * @{ + */ +int agile_modbus_rtu_init(agile_modbus_rtu_t *ctx, uint8_t *send_buf, int send_bufsz, uint8_t *read_buf, int read_bufsz); +/** + * @} + */ + +/** + * @} + */ + +#ifdef __cplusplus +} +#endif + +#endif /* __PKG_AGILE_MODBUS_RTU_H */ diff --git a/examples/pikapython/pikapython/pikascript-lib/modbus/agile_modbus_tcp.c b/examples/pikapython/pikapython/pikascript-lib/modbus/agile_modbus_tcp.c new file mode 100755 index 00000000..47804599 --- /dev/null +++ b/examples/pikapython/pikapython/pikascript-lib/modbus/agile_modbus_tcp.c @@ -0,0 +1,226 @@ +/** + * @file agile_modbus_tcp.c + * @brief Agile Modbus 软件包 TCP 源文件 + * @author 马龙伟 (2544047213@qq.com) + * @date 2021-12-02 + * + * @attention + * + *

© Copyright (c) 2021 Ma Longwei. + * All rights reserved.

+ * + */ + +#include "agile_modbus.h" +#include "agile_modbus_tcp.h" + +/** @defgroup TCP TCP + * @{ + */ + +/** @defgroup TCP_Private_Functions TCP Private Functions + * @{ + */ + +/** + * @brief TCP 设置地址接口 + * @param ctx modbus 句柄 + * @param slave 从机地址 + * @return 0:成功 + */ +static int agile_modbus_tcp_set_slave(agile_modbus_t *ctx, int slave) +{ + ctx->slave = slave; + return 0; +} + +/** + * @brief TCP 构建基础请求报文接口(头部报文) + * @param ctx modbus 句柄 + * @param function 功能码 + * @param addr 寄存器地址 + * @param nb 寄存器数目 + * @param req 数据存放指针 + * @return 数据长度 + */ +static int agile_modbus_tcp_build_request_basis(agile_modbus_t *ctx, int function, + int addr, int nb, + uint8_t *req) +{ + agile_modbus_tcp_t *ctx_tcp = ctx->backend_data; + + /* Increase transaction ID */ + if (ctx_tcp->t_id < UINT16_MAX) + ctx_tcp->t_id++; + else + ctx_tcp->t_id = 0; + req[0] = ctx_tcp->t_id >> 8; + req[1] = ctx_tcp->t_id & 0x00ff; + + /* Protocol Modbus */ + req[2] = 0; + req[3] = 0; + + /* Length will be defined later by set_req_length_tcp at offsets 4 + and 5 */ + + req[6] = ctx->slave; + req[7] = function; + req[8] = addr >> 8; + req[9] = addr & 0x00ff; + req[10] = nb >> 8; + req[11] = nb & 0x00ff; + + return AGILE_MODBUS_TCP_PRESET_REQ_LENGTH; +} + +/** + * @brief TCP 构建基础响应报文接口(头部报文) + * @param sft modbus 头部参数结构体指针 + * @param rsp 数据存放指针 + * @return 数据长度 + */ +static int agile_modbus_tcp_build_response_basis(agile_modbus_sft_t *sft, uint8_t *rsp) +{ + /* Extract from MODBUS Messaging on TCP/IP Implementation + Guide V1.0b (page 23/46): + The transaction identifier is used to associate the future + response with the request. */ + rsp[0] = sft->t_id >> 8; + rsp[1] = sft->t_id & 0x00ff; + + /* Protocol Modbus */ + rsp[2] = 0; + rsp[3] = 0; + + /* Length will be set later by send_msg (4 and 5) */ + + /* The slave ID is copied from the indication */ + rsp[6] = sft->slave; + rsp[7] = sft->function; + + return AGILE_MODBUS_TCP_PRESET_RSP_LENGTH; +} + +/** + * @brief TCP 准备响应接口 + * @param req 请求数据指针 + * @param req_length 请求数据长度 + * @return 事务标识符 + */ +static int agile_modbus_tcp_prepare_response_tid(const uint8_t *req, int *req_length) +{ + return (req[0] << 8) + req[1]; +} + +/** + * @brief TCP 预发送数据接口(计算长度字段的值并存入) + * @param req 数据存放指针 + * @param req_length 已有数据长度 + * @return 数据长度 + */ +static int agile_modbus_tcp_send_msg_pre(uint8_t *req, int req_length) +{ + /* Substract the header length to the message length */ + int mbap_length = req_length - 6; + + req[4] = mbap_length >> 8; + req[5] = mbap_length & 0x00FF; + + return req_length; +} + +/** + * @brief TCP 检查接收数据完整性接口 + * @param ctx modbus 句柄 + * @param msg 接收数据指针 + * @param msg_length 有效数据长度 + * @return 有效数据长度 + */ +static int agile_modbus_tcp_check_integrity(agile_modbus_t *ctx, uint8_t *msg, const int msg_length) +{ + return msg_length; +} + +/** + * @brief TCP 预检查确认接口(对比事务标识符和协议标识符) + * @param ctx modbus 句柄 + * @param req 请求数据指针 + * @param rsp 响应数据指针 + * @param rsp_length 响应数据长度 + * @return 0:成功; 其他:异常 + */ +static int agile_modbus_tcp_pre_check_confirmation(agile_modbus_t *ctx, const uint8_t *req, + const uint8_t *rsp, int rsp_length) +{ + /* Check transaction ID */ + if (req[0] != rsp[0] || req[1] != rsp[1]) + return -1; + + /* Check protocol ID */ + if (rsp[2] != 0x0 && rsp[3] != 0x0) + return -1; + + return 0; +} + +/** + * @} + */ + +/** @defgroup TCP_Private_Constants TCP Private Constants + * @{ + */ + +/** + * @brief TCP 后端接口 + */ +static const agile_modbus_backend_t agile_modbus_tcp_backend = + { + AGILE_MODBUS_BACKEND_TYPE_TCP, + AGILE_MODBUS_TCP_HEADER_LENGTH, + AGILE_MODBUS_TCP_CHECKSUM_LENGTH, + AGILE_MODBUS_TCP_MAX_ADU_LENGTH, + agile_modbus_tcp_set_slave, + agile_modbus_tcp_build_request_basis, + agile_modbus_tcp_build_response_basis, + agile_modbus_tcp_prepare_response_tid, + agile_modbus_tcp_send_msg_pre, + agile_modbus_tcp_check_integrity, + agile_modbus_tcp_pre_check_confirmation}; + +/** + * @} + */ + +/** @defgroup TCP_Exported_Functions TCP Exported Functions + * @{ + */ + +/** + * @brief TCP 初始化 + * @param ctx TCP 句柄 + * @param send_buf 发送缓冲区 + * @param send_bufsz 发送缓冲区大小 + * @param read_buf 接收缓冲区 + * @param read_bufsz 接收缓冲区大小 + * @return 0:成功 + */ +int agile_modbus_tcp_init(agile_modbus_tcp_t *ctx, uint8_t *send_buf, int send_bufsz, uint8_t *read_buf, int read_bufsz) +{ + agile_modbus_common_init(&(ctx->_ctx), send_buf, send_bufsz, read_buf, read_bufsz); + ctx->_ctx.backend = &agile_modbus_tcp_backend; + ctx->_ctx.backend_data = ctx; + + ctx->t_id = 0; + + return 0; +} + +/** + * @} + */ + +/** + * @} + */ diff --git a/examples/pikapython/pikapython/pikascript-lib/modbus/agile_modbus_tcp.h b/examples/pikapython/pikapython/pikascript-lib/modbus/agile_modbus_tcp.h new file mode 100755 index 00000000..50475e07 --- /dev/null +++ b/examples/pikapython/pikapython/pikascript-lib/modbus/agile_modbus_tcp.h @@ -0,0 +1,83 @@ +/** + * @file agile_modbus_tcp.h + * @brief Agile Modbus 软件包 TCP 头文件 + * @author 马龙伟 (2544047213@qq.com) + * @date 2021-12-02 + * + * @attention + * + *

© Copyright (c) 2021 Ma Longwei. + * All rights reserved.

+ * + */ + +#ifndef __PKG_AGILE_MODBUS_TCP_H +#define __PKG_AGILE_MODBUS_TCP_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include + +/** @addtogroup TCP + * @{ + */ + +/** @defgroup TCP_Exported_Constants TCP Exported Constants + * @{ + */ +#define AGILE_MODBUS_TCP_HEADER_LENGTH 7 +#define AGILE_MODBUS_TCP_PRESET_REQ_LENGTH 12 +#define AGILE_MODBUS_TCP_PRESET_RSP_LENGTH 8 + +#define AGILE_MODBUS_TCP_CHECKSUM_LENGTH 0 + +/** + @verbatim + Modbus_Application_Protocol_V1_1b.pdf Chapter 4 Section 1 Page 5 + TCP MODBUS ADU = 253 bytes + MBAP (7 bytes) = 260 bytes + + @endverbatim + */ +#define AGILE_MODBUS_TCP_MAX_ADU_LENGTH 260 +/** + * @} + */ + +/** @defgroup TCP_Exported_Types TCP Exported Types + * @{ + */ + +/** + * @brief TCP 结构体 + */ +typedef struct agile_modbus_tcp { + agile_modbus_t _ctx; /**< modbus 句柄 */ + uint16_t t_id; /**< Extract from MODBUS Messaging on TCP/IP Implementation Guide V1.0b + (page 23/46): + The transaction identifier is used to associate the future response + with the request. This identifier is unique on each TCP connection. */ +} agile_modbus_tcp_t; + +/** + * @} + */ + +/** @addtogroup TCP_Exported_Functions + * @{ + */ +int agile_modbus_tcp_init(agile_modbus_tcp_t *ctx, uint8_t *send_buf, int send_bufsz, uint8_t *read_buf, int read_bufsz); +/** + * @} + */ + +/** + * @} + */ + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/examples/pikapython/pikapython/pikascript-lib/pika_cjson/cJSON.c b/examples/pikapython/pikapython/pikascript-lib/pika_cjson/cJSON.c new file mode 100755 index 00000000..3b4ad9ea --- /dev/null +++ b/examples/pikapython/pikapython/pikascript-lib/pika_cjson/cJSON.c @@ -0,0 +1,3110 @@ +/* + Copyright (c) 2009-2017 Dave Gamble and cJSON contributors + + 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. +*/ + +/* cJSON */ +/* JSON parser in C. */ + +/* disable warnings about old C89 functions in MSVC */ +#if !defined(_CRT_SECURE_NO_DEPRECATE) && defined(_MSC_VER) +#define _CRT_SECURE_NO_DEPRECATE +#endif + +#ifdef __GNUC__ +#pragma GCC visibility push(default) +#endif +#if defined(_MSC_VER) +#pragma warning (push) +/* disable warning about single line comments in system headers */ +#pragma warning (disable : 4001) +#endif + +#include +#include +#include +#include +#include +#include +#include + +#ifdef ENABLE_LOCALES +#include +#endif + +#if defined(_MSC_VER) +#pragma warning (pop) +#endif +#ifdef __GNUC__ +#pragma GCC visibility pop +#endif + +#include "cJSON.h" + +/* define our own boolean type */ +#ifdef true +#undef true +#endif +#define true ((cJSON_bool)1) + +#ifdef false +#undef false +#endif +#define false ((cJSON_bool)0) + +/* define isnan and isinf for ANSI C, if in C99 or above, isnan and isinf has been defined in math.h */ +#ifndef isinf +#define isinf(d) (isnan((d - d)) && !isnan(d)) +#endif +#ifndef isnan +#define isnan(d) (d != d) +#endif + +#ifndef NAN +#ifdef _WIN32 +#define NAN sqrt(-1.0) +#else +#define NAN 0.0/0.0 +#endif +#endif + +typedef struct { + const unsigned char *json; + size_t position; +} error; +static error global_error = { NULL, 0 }; + +CJSON_PUBLIC(const char *) cJSON_GetErrorPtr(void) +{ + return (const char*) (global_error.json + global_error.position); +} + +CJSON_PUBLIC(char *) cJSON_GetStringValue(const cJSON * const item) +{ + if (!cJSON_IsString(item)) + { + return NULL; + } + + return item->valuestring; +} + +CJSON_PUBLIC(double) cJSON_GetNumberValue(const cJSON * const item) +{ + if (!cJSON_IsNumber(item)) + { + return (double) NAN; + } + + return item->valuedouble; +} + +/* This is a safeguard to prevent copy-pasters from using incompatible C and header files */ +#if (CJSON_VERSION_MAJOR != 1) || (CJSON_VERSION_MINOR != 7) || (CJSON_VERSION_PATCH != 15) + #error cJSON.h and cJSON.c have different versions. Make sure that both have the same. +#endif + +CJSON_PUBLIC(const char*) cJSON_Version(void) +{ + static char version[15]; + sprintf(version, "%i.%i.%i", CJSON_VERSION_MAJOR, CJSON_VERSION_MINOR, CJSON_VERSION_PATCH); + + return version; +} + +/* Case insensitive string comparison, doesn't consider two NULL pointers equal though */ +static int case_insensitive_strcmp(const unsigned char *string1, const unsigned char *string2) +{ + if ((string1 == NULL) || (string2 == NULL)) + { + return 1; + } + + if (string1 == string2) + { + return 0; + } + + for(; tolower(*string1) == tolower(*string2); (void)string1++, string2++) + { + if (*string1 == '\0') + { + return 0; + } + } + + return tolower(*string1) - tolower(*string2); +} + +typedef struct internal_hooks +{ + void *(CJSON_CDECL *allocate)(size_t size); + void (CJSON_CDECL *deallocate)(void *pointer); + void *(CJSON_CDECL *reallocate)(void *pointer, size_t size); +} internal_hooks; + +#if defined(_MSC_VER) +/* work around MSVC error C2322: '...' address of dllimport '...' is not static */ +static void * CJSON_CDECL internal_malloc(size_t size) +{ + return malloc(size); +} +static void CJSON_CDECL internal_free(void *pointer) +{ + free(pointer); +} +static void * CJSON_CDECL internal_realloc(void *pointer, size_t size) +{ + return realloc(pointer, size); +} +#else +#define internal_malloc malloc +#define internal_free free +#define internal_realloc realloc +#endif + +/* strlen of character literals resolved at compile time */ +#define static_strlen(string_literal) (sizeof(string_literal) - sizeof("")) + +static internal_hooks global_hooks = { internal_malloc, internal_free, internal_realloc }; + +static unsigned char* cJSON_strdup(const unsigned char* string, const internal_hooks * const hooks) +{ + size_t length = 0; + unsigned char *copy = NULL; + + if (string == NULL) + { + return NULL; + } + + length = strlen((const char*)string) + sizeof(""); + copy = (unsigned char*)hooks->allocate(length); + if (copy == NULL) + { + return NULL; + } + memcpy(copy, string, length); + + return copy; +} + +CJSON_PUBLIC(void) cJSON_InitHooks(cJSON_Hooks* hooks) +{ + if (hooks == NULL) + { + /* Reset hooks */ + global_hooks.allocate = malloc; + global_hooks.deallocate = free; + global_hooks.reallocate = realloc; + return; + } + + global_hooks.allocate = malloc; + if (hooks->malloc_fn != NULL) + { + global_hooks.allocate = hooks->malloc_fn; + } + + global_hooks.deallocate = free; + if (hooks->free_fn != NULL) + { + global_hooks.deallocate = hooks->free_fn; + } + + /* use realloc only if both free and malloc are used */ + global_hooks.reallocate = NULL; + if ((global_hooks.allocate == malloc) && (global_hooks.deallocate == free)) + { + global_hooks.reallocate = realloc; + } +} + +/* Internal constructor. */ +static cJSON *cJSON_New_Item(const internal_hooks * const hooks) +{ + cJSON* node = (cJSON*)hooks->allocate(sizeof(cJSON)); + if (node) + { + memset(node, '\0', sizeof(cJSON)); + } + + return node; +} + +/* Delete a cJSON structure. */ +CJSON_PUBLIC(void) cJSON_Delete(cJSON *item) +{ + cJSON *next = NULL; + while (item != NULL) + { + next = item->next; + if (!(item->type & cJSON_IsReference) && (item->child != NULL)) + { + cJSON_Delete(item->child); + } + if (!(item->type & cJSON_IsReference) && (item->valuestring != NULL)) + { + global_hooks.deallocate(item->valuestring); + } + if (!(item->type & cJSON_StringIsConst) && (item->string != NULL)) + { + global_hooks.deallocate(item->string); + } + global_hooks.deallocate(item); + item = next; + } +} + +/* get the decimal point character of the current locale */ +static unsigned char get_decimal_point(void) +{ +#ifdef ENABLE_LOCALES + struct lconv *lconv = localeconv(); + return (unsigned char) lconv->decimal_point[0]; +#else + return '.'; +#endif +} + +typedef struct +{ + const unsigned char *content; + size_t length; + size_t offset; + size_t depth; /* How deeply nested (in arrays/objects) is the input at the current offset. */ + internal_hooks hooks; +} parse_buffer; + +/* check if the given size is left to read in a given parse buffer (starting with 1) */ +#define can_read(buffer, size) ((buffer != NULL) && (((buffer)->offset + size) <= (buffer)->length)) +/* check if the buffer can be accessed at the given index (starting with 0) */ +#define can_access_at_index(buffer, index) ((buffer != NULL) && (((buffer)->offset + index) < (buffer)->length)) +#define cannot_access_at_index(buffer, index) (!can_access_at_index(buffer, index)) +/* get a pointer to the buffer at the position */ +#define buffer_at_offset(buffer) ((buffer)->content + (buffer)->offset) + +/* Parse the input text to generate a number, and populate the result into item. */ +static cJSON_bool parse_number(cJSON * const item, parse_buffer * const input_buffer) +{ + double number = 0; + unsigned char *after_end = NULL; + unsigned char number_c_string[64]; + unsigned char decimal_point = get_decimal_point(); + size_t i = 0; + + if ((input_buffer == NULL) || (input_buffer->content == NULL)) + { + return false; + } + + /* copy the number into a temporary buffer and replace '.' with the decimal point + * of the current locale (for strtod) + * This also takes care of '\0' not necessarily being available for marking the end of the input */ + for (i = 0; (i < (sizeof(number_c_string) - 1)) && can_access_at_index(input_buffer, i); i++) + { + switch (buffer_at_offset(input_buffer)[i]) + { + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + case '+': + case '-': + case 'e': + case 'E': + number_c_string[i] = buffer_at_offset(input_buffer)[i]; + break; + + case '.': + number_c_string[i] = decimal_point; + break; + + default: + goto loop_end; + } + } +loop_end: + number_c_string[i] = '\0'; + + number = strtod((const char*)number_c_string, (char**)&after_end); + if (number_c_string == after_end) + { + return false; /* parse_error */ + } + + item->valuedouble = number; + + /* use saturation in case of overflow */ + if (number >= INT_MAX) + { + item->valueint = INT_MAX; + } + else if (number <= (double)INT_MIN) + { + item->valueint = INT_MIN; + } + else + { + item->valueint = (int)number; + } + + item->type = cJSON_Number; + + input_buffer->offset += (size_t)(after_end - number_c_string); + return true; +} + +/* don't ask me, but the original cJSON_SetNumberValue returns an integer or double */ +CJSON_PUBLIC(double) cJSON_SetNumberHelper(cJSON *object, double number) +{ + if (number >= INT_MAX) + { + object->valueint = INT_MAX; + } + else if (number <= (double)INT_MIN) + { + object->valueint = INT_MIN; + } + else + { + object->valueint = (int)number; + } + + return object->valuedouble = number; +} + +CJSON_PUBLIC(char*) cJSON_SetValuestring(cJSON *object, const char *valuestring) +{ + char *copy = NULL; + /* if object's type is not cJSON_String or is cJSON_IsReference, it should not set valuestring */ + if (!(object->type & cJSON_String) || (object->type & cJSON_IsReference)) + { + return NULL; + } + if (strlen(valuestring) <= strlen(object->valuestring)) + { + strcpy(object->valuestring, valuestring); + return object->valuestring; + } + copy = (char*) cJSON_strdup((const unsigned char*)valuestring, &global_hooks); + if (copy == NULL) + { + return NULL; + } + if (object->valuestring != NULL) + { + cJSON_free(object->valuestring); + } + object->valuestring = copy; + + return copy; +} + +typedef struct +{ + unsigned char *buffer; + size_t length; + size_t offset; + size_t depth; /* current nesting depth (for formatted printing) */ + cJSON_bool noalloc; + cJSON_bool format; /* is this print a formatted print */ + internal_hooks hooks; +} printbuffer; + +/* realloc printbuffer if necessary to have at least "needed" bytes more */ +static unsigned char* ensure(printbuffer * const p, size_t needed) +{ + unsigned char *newbuffer = NULL; + size_t newsize = 0; + + if ((p == NULL) || (p->buffer == NULL)) + { + return NULL; + } + + if ((p->length > 0) && (p->offset >= p->length)) + { + /* make sure that offset is valid */ + return NULL; + } + + if (needed > INT_MAX) + { + /* sizes bigger than INT_MAX are currently not supported */ + return NULL; + } + + needed += p->offset + 1; + if (needed <= p->length) + { + return p->buffer + p->offset; + } + + if (p->noalloc) { + return NULL; + } + + /* calculate new buffer size */ + if (needed > (INT_MAX / 2)) + { + /* overflow of int, use INT_MAX if possible */ + if (needed <= INT_MAX) + { + newsize = INT_MAX; + } + else + { + return NULL; + } + } + else + { + newsize = needed * 2; + } + + if (p->hooks.reallocate != NULL) + { + /* reallocate with realloc if available */ + newbuffer = (unsigned char*)p->hooks.reallocate(p->buffer, newsize); + if (newbuffer == NULL) + { + p->hooks.deallocate(p->buffer); + p->length = 0; + p->buffer = NULL; + + return NULL; + } + } + else + { + /* otherwise reallocate manually */ + newbuffer = (unsigned char*)p->hooks.allocate(newsize); + if (!newbuffer) + { + p->hooks.deallocate(p->buffer); + p->length = 0; + p->buffer = NULL; + + return NULL; + } + + memcpy(newbuffer, p->buffer, p->offset + 1); + p->hooks.deallocate(p->buffer); + } + p->length = newsize; + p->buffer = newbuffer; + + return newbuffer + p->offset; +} + +/* calculate the new length of the string in a printbuffer and update the offset */ +static void update_offset(printbuffer * const buffer) +{ + const unsigned char *buffer_pointer = NULL; + if ((buffer == NULL) || (buffer->buffer == NULL)) + { + return; + } + buffer_pointer = buffer->buffer + buffer->offset; + + buffer->offset += strlen((const char*)buffer_pointer); +} + +/* securely comparison of floating-point variables */ +static cJSON_bool compare_double(double a, double b) +{ + double maxVal = fabs(a) > fabs(b) ? fabs(a) : fabs(b); + return (fabs(a - b) <= maxVal * DBL_EPSILON); +} + +/* Render the number nicely from the given item into a string. */ +static cJSON_bool print_number(const cJSON * const item, printbuffer * const output_buffer) +{ + unsigned char *output_pointer = NULL; + double d = item->valuedouble; + int length = 0; + size_t i = 0; + unsigned char number_buffer[26] = {0}; /* temporary buffer to print the number into */ + unsigned char decimal_point = get_decimal_point(); + double test = 0.0; + + if (output_buffer == NULL) + { + return false; + } + + /* This checks for NaN and Infinity */ + if (isnan(d) || isinf(d)) + { + length = sprintf((char*)number_buffer, "null"); + } + else + { + /* Try 15 decimal places of precision to avoid nonsignificant nonzero digits */ + length = sprintf((char*)number_buffer, "%1.15g", d); + + /* Check whether the original double can be recovered */ + if ((sscanf((char*)number_buffer, "%lg", &test) != 1) || !compare_double((double)test, d)) + { + /* If not, print with 17 decimal places of precision */ + length = sprintf((char*)number_buffer, "%1.17g", d); + } + } + + /* sprintf failed or buffer overrun occurred */ + if ((length < 0) || (length > (int)(sizeof(number_buffer) - 1))) + { + return false; + } + + /* reserve appropriate space in the output */ + output_pointer = ensure(output_buffer, (size_t)length + sizeof("")); + if (output_pointer == NULL) + { + return false; + } + + /* copy the printed number to the output and replace locale + * dependent decimal point with '.' */ + for (i = 0; i < ((size_t)length); i++) + { + if (number_buffer[i] == decimal_point) + { + output_pointer[i] = '.'; + continue; + } + + output_pointer[i] = number_buffer[i]; + } + output_pointer[i] = '\0'; + + output_buffer->offset += (size_t)length; + + return true; +} + +/* parse 4 digit hexadecimal number */ +static unsigned parse_hex4(const unsigned char * const input) +{ + unsigned int h = 0; + size_t i = 0; + + for (i = 0; i < 4; i++) + { + /* parse digit */ + if ((input[i] >= '0') && (input[i] <= '9')) + { + h += (unsigned int) input[i] - '0'; + } + else if ((input[i] >= 'A') && (input[i] <= 'F')) + { + h += (unsigned int) 10 + input[i] - 'A'; + } + else if ((input[i] >= 'a') && (input[i] <= 'f')) + { + h += (unsigned int) 10 + input[i] - 'a'; + } + else /* invalid */ + { + return 0; + } + + if (i < 3) + { + /* shift left to make place for the next nibble */ + h = h << 4; + } + } + + return h; +} + +/* converts a UTF-16 literal to UTF-8 + * A literal can be one or two sequences of the form \uXXXX */ +static unsigned char utf16_literal_to_utf8(const unsigned char * const input_pointer, const unsigned char * const input_end, unsigned char **output_pointer) +{ + long unsigned int codepoint = 0; + unsigned int first_code = 0; + const unsigned char *first_sequence = input_pointer; + unsigned char utf8_length = 0; + unsigned char utf8_position = 0; + unsigned char sequence_length = 0; + unsigned char first_byte_mark = 0; + + if ((input_end - first_sequence) < 6) + { + /* input ends unexpectedly */ + goto fail; + } + + /* get the first utf16 sequence */ + first_code = parse_hex4(first_sequence + 2); + + /* check that the code is valid */ + if (((first_code >= 0xDC00) && (first_code <= 0xDFFF))) + { + goto fail; + } + + /* UTF16 surrogate pair */ + if ((first_code >= 0xD800) && (first_code <= 0xDBFF)) + { + const unsigned char *second_sequence = first_sequence + 6; + unsigned int second_code = 0; + sequence_length = 12; /* \uXXXX\uXXXX */ + + if ((input_end - second_sequence) < 6) + { + /* input ends unexpectedly */ + goto fail; + } + + if ((second_sequence[0] != '\\') || (second_sequence[1] != 'u')) + { + /* missing second half of the surrogate pair */ + goto fail; + } + + /* get the second utf16 sequence */ + second_code = parse_hex4(second_sequence + 2); + /* check that the code is valid */ + if ((second_code < 0xDC00) || (second_code > 0xDFFF)) + { + /* invalid second half of the surrogate pair */ + goto fail; + } + + + /* calculate the unicode codepoint from the surrogate pair */ + codepoint = 0x10000 + (((first_code & 0x3FF) << 10) | (second_code & 0x3FF)); + } + else + { + sequence_length = 6; /* \uXXXX */ + codepoint = first_code; + } + + /* encode as UTF-8 + * takes at maximum 4 bytes to encode: + * 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx */ + if (codepoint < 0x80) + { + /* normal ascii, encoding 0xxxxxxx */ + utf8_length = 1; + } + else if (codepoint < 0x800) + { + /* two bytes, encoding 110xxxxx 10xxxxxx */ + utf8_length = 2; + first_byte_mark = 0xC0; /* 11000000 */ + } + else if (codepoint < 0x10000) + { + /* three bytes, encoding 1110xxxx 10xxxxxx 10xxxxxx */ + utf8_length = 3; + first_byte_mark = 0xE0; /* 11100000 */ + } + else if (codepoint <= 0x10FFFF) + { + /* four bytes, encoding 1110xxxx 10xxxxxx 10xxxxxx 10xxxxxx */ + utf8_length = 4; + first_byte_mark = 0xF0; /* 11110000 */ + } + else + { + /* invalid unicode codepoint */ + goto fail; + } + + /* encode as utf8 */ + for (utf8_position = (unsigned char)(utf8_length - 1); utf8_position > 0; utf8_position--) + { + /* 10xxxxxx */ + (*output_pointer)[utf8_position] = (unsigned char)((codepoint | 0x80) & 0xBF); + codepoint >>= 6; + } + /* encode first byte */ + if (utf8_length > 1) + { + (*output_pointer)[0] = (unsigned char)((codepoint | first_byte_mark) & 0xFF); + } + else + { + (*output_pointer)[0] = (unsigned char)(codepoint & 0x7F); + } + + *output_pointer += utf8_length; + + return sequence_length; + +fail: + return 0; +} + +/* Parse the input text into an unescaped cinput, and populate item. */ +static cJSON_bool parse_string(cJSON * const item, parse_buffer * const input_buffer) +{ + const unsigned char *input_pointer = buffer_at_offset(input_buffer) + 1; + const unsigned char *input_end = buffer_at_offset(input_buffer) + 1; + unsigned char *output_pointer = NULL; + unsigned char *output = NULL; + + /* not a string */ + if (buffer_at_offset(input_buffer)[0] != '\"') + { + goto fail; + } + + { + /* calculate approximate size of the output (overestimate) */ + size_t allocation_length = 0; + size_t skipped_bytes = 0; + while (((size_t)(input_end - input_buffer->content) < input_buffer->length) && (*input_end != '\"')) + { + /* is escape sequence */ + if (input_end[0] == '\\') + { + if ((size_t)(input_end + 1 - input_buffer->content) >= input_buffer->length) + { + /* prevent buffer overflow when last input character is a backslash */ + goto fail; + } + skipped_bytes++; + input_end++; + } + input_end++; + } + if (((size_t)(input_end - input_buffer->content) >= input_buffer->length) || (*input_end != '\"')) + { + goto fail; /* string ended unexpectedly */ + } + + /* This is at most how much we need for the output */ + allocation_length = (size_t) (input_end - buffer_at_offset(input_buffer)) - skipped_bytes; + output = (unsigned char*)input_buffer->hooks.allocate(allocation_length + sizeof("")); + if (output == NULL) + { + goto fail; /* allocation failure */ + } + } + + output_pointer = output; + /* loop through the string literal */ + while (input_pointer < input_end) + { + if (*input_pointer != '\\') + { + *output_pointer++ = *input_pointer++; + } + /* escape sequence */ + else + { + unsigned char sequence_length = 2; + if ((input_end - input_pointer) < 1) + { + goto fail; + } + + switch (input_pointer[1]) + { + case 'b': + *output_pointer++ = '\b'; + break; + case 'f': + *output_pointer++ = '\f'; + break; + case 'n': + *output_pointer++ = '\n'; + break; + case 'r': + *output_pointer++ = '\r'; + break; + case 't': + *output_pointer++ = '\t'; + break; + case '\"': + case '\\': + case '/': + *output_pointer++ = input_pointer[1]; + break; + + /* UTF-16 literal */ + case 'u': + sequence_length = utf16_literal_to_utf8(input_pointer, input_end, &output_pointer); + if (sequence_length == 0) + { + /* failed to convert UTF16-literal to UTF-8 */ + goto fail; + } + break; + + default: + goto fail; + } + input_pointer += sequence_length; + } + } + + /* zero terminate the output */ + *output_pointer = '\0'; + + item->type = cJSON_String; + item->valuestring = (char*)output; + + input_buffer->offset = (size_t) (input_end - input_buffer->content); + input_buffer->offset++; + + return true; + +fail: + if (output != NULL) + { + input_buffer->hooks.deallocate(output); + } + + if (input_pointer != NULL) + { + input_buffer->offset = (size_t)(input_pointer - input_buffer->content); + } + + return false; +} + +/* Render the cstring provided to an escaped version that can be printed. */ +static cJSON_bool print_string_ptr(const unsigned char * const input, printbuffer * const output_buffer) +{ + const unsigned char *input_pointer = NULL; + unsigned char *output = NULL; + unsigned char *output_pointer = NULL; + size_t output_length = 0; + /* numbers of additional characters needed for escaping */ + size_t escape_characters = 0; + + if (output_buffer == NULL) + { + return false; + } + + /* empty string */ + if (input == NULL) + { + output = ensure(output_buffer, sizeof("\"\"")); + if (output == NULL) + { + return false; + } + strcpy((char*)output, "\"\""); + + return true; + } + + /* set "flag" to 1 if something needs to be escaped */ + for (input_pointer = input; *input_pointer; input_pointer++) + { + switch (*input_pointer) + { + case '\"': + case '\\': + case '\b': + case '\f': + case '\n': + case '\r': + case '\t': + /* one character escape sequence */ + escape_characters++; + break; + default: + if (*input_pointer < 32) + { + /* UTF-16 escape sequence uXXXX */ + escape_characters += 5; + } + break; + } + } + output_length = (size_t)(input_pointer - input) + escape_characters; + + output = ensure(output_buffer, output_length + sizeof("\"\"")); + if (output == NULL) + { + return false; + } + + /* no characters have to be escaped */ + if (escape_characters == 0) + { + output[0] = '\"'; + memcpy(output + 1, input, output_length); + output[output_length + 1] = '\"'; + output[output_length + 2] = '\0'; + + return true; + } + + output[0] = '\"'; + output_pointer = output + 1; + /* copy the string */ + for (input_pointer = input; *input_pointer != '\0'; (void)input_pointer++, output_pointer++) + { + if ((*input_pointer > 31) && (*input_pointer != '\"') && (*input_pointer != '\\')) + { + /* normal character, copy */ + *output_pointer = *input_pointer; + } + else + { + /* character needs to be escaped */ + *output_pointer++ = '\\'; + switch (*input_pointer) + { + case '\\': + *output_pointer = '\\'; + break; + case '\"': + *output_pointer = '\"'; + break; + case '\b': + *output_pointer = 'b'; + break; + case '\f': + *output_pointer = 'f'; + break; + case '\n': + *output_pointer = 'n'; + break; + case '\r': + *output_pointer = 'r'; + break; + case '\t': + *output_pointer = 't'; + break; + default: + /* escape and print as unicode codepoint */ + sprintf((char*)output_pointer, "u%04x", *input_pointer); + output_pointer += 4; + break; + } + } + } + output[output_length + 1] = '\"'; + output[output_length + 2] = '\0'; + + return true; +} + +/* Invoke print_string_ptr (which is useful) on an item. */ +static cJSON_bool print_string(const cJSON * const item, printbuffer * const p) +{ + return print_string_ptr((unsigned char*)item->valuestring, p); +} + +/* Predeclare these prototypes. */ +static cJSON_bool parse_value(cJSON * const item, parse_buffer * const input_buffer); +static cJSON_bool print_value(const cJSON * const item, printbuffer * const output_buffer); +static cJSON_bool parse_array(cJSON * const item, parse_buffer * const input_buffer); +static cJSON_bool print_array(const cJSON * const item, printbuffer * const output_buffer); +static cJSON_bool parse_object(cJSON * const item, parse_buffer * const input_buffer); +static cJSON_bool print_object(const cJSON * const item, printbuffer * const output_buffer); + +/* Utility to jump whitespace and cr/lf */ +static parse_buffer *buffer_skip_whitespace(parse_buffer * const buffer) +{ + if ((buffer == NULL) || (buffer->content == NULL)) + { + return NULL; + } + + if (cannot_access_at_index(buffer, 0)) + { + return buffer; + } + + while (can_access_at_index(buffer, 0) && (buffer_at_offset(buffer)[0] <= 32)) + { + buffer->offset++; + } + + if (buffer->offset == buffer->length) + { + buffer->offset--; + } + + return buffer; +} + +/* skip the UTF-8 BOM (byte order mark) if it is at the beginning of a buffer */ +static parse_buffer *skip_utf8_bom(parse_buffer * const buffer) +{ + if ((buffer == NULL) || (buffer->content == NULL) || (buffer->offset != 0)) + { + return NULL; + } + + if (can_access_at_index(buffer, 4) && (strncmp((const char*)buffer_at_offset(buffer), "\xEF\xBB\xBF", 3) == 0)) + { + buffer->offset += 3; + } + + return buffer; +} + +CJSON_PUBLIC(cJSON *) cJSON_ParseWithOpts(const char *value, const char **return_parse_end, cJSON_bool require_null_terminated) +{ + size_t buffer_length; + + if (NULL == value) + { + return NULL; + } + + /* Adding null character size due to require_null_terminated. */ + buffer_length = strlen(value) + sizeof(""); + + return cJSON_ParseWithLengthOpts(value, buffer_length, return_parse_end, require_null_terminated); +} + +/* Parse an object - create a new root, and populate. */ +CJSON_PUBLIC(cJSON *) cJSON_ParseWithLengthOpts(const char *value, size_t buffer_length, const char **return_parse_end, cJSON_bool require_null_terminated) +{ + parse_buffer buffer = { 0, 0, 0, 0, { 0, 0, 0 } }; + cJSON *item = NULL; + + /* reset error position */ + global_error.json = NULL; + global_error.position = 0; + + if (value == NULL || 0 == buffer_length) + { + goto fail; + } + + buffer.content = (const unsigned char*)value; + buffer.length = buffer_length; + buffer.offset = 0; + buffer.hooks = global_hooks; + + item = cJSON_New_Item(&global_hooks); + if (item == NULL) /* memory fail */ + { + goto fail; + } + + if (!parse_value(item, buffer_skip_whitespace(skip_utf8_bom(&buffer)))) + { + /* parse failure. ep is set. */ + goto fail; + } + + /* if we require null-terminated JSON without appended garbage, skip and then check for a null terminator */ + if (require_null_terminated) + { + buffer_skip_whitespace(&buffer); + if ((buffer.offset >= buffer.length) || buffer_at_offset(&buffer)[0] != '\0') + { + goto fail; + } + } + if (return_parse_end) + { + *return_parse_end = (const char*)buffer_at_offset(&buffer); + } + + return item; + +fail: + if (item != NULL) + { + cJSON_Delete(item); + } + + if (value != NULL) + { + error local_error; + local_error.json = (const unsigned char*)value; + local_error.position = 0; + + if (buffer.offset < buffer.length) + { + local_error.position = buffer.offset; + } + else if (buffer.length > 0) + { + local_error.position = buffer.length - 1; + } + + if (return_parse_end != NULL) + { + *return_parse_end = (const char*)local_error.json + local_error.position; + } + + global_error = local_error; + } + + return NULL; +} + +/* Default options for cJSON_Parse */ +CJSON_PUBLIC(cJSON *) cJSON_Parse(const char *value) +{ + return cJSON_ParseWithOpts(value, 0, 0); +} + +CJSON_PUBLIC(cJSON *) cJSON_ParseWithLength(const char *value, size_t buffer_length) +{ + return cJSON_ParseWithLengthOpts(value, buffer_length, 0, 0); +} + +#define cjson_min(a, b) (((a) < (b)) ? (a) : (b)) + +static unsigned char *print(const cJSON * const item, cJSON_bool format, const internal_hooks * const hooks) +{ + static const size_t default_buffer_size = 256; + printbuffer buffer[1]; + unsigned char *printed = NULL; + + memset(buffer, 0, sizeof(buffer)); + + /* create buffer */ + buffer->buffer = (unsigned char*) hooks->allocate(default_buffer_size); + buffer->length = default_buffer_size; + buffer->format = format; + buffer->hooks = *hooks; + if (buffer->buffer == NULL) + { + goto fail; + } + + /* print the value */ + if (!print_value(item, buffer)) + { + goto fail; + } + update_offset(buffer); + + /* check if reallocate is available */ + if (hooks->reallocate != NULL) + { + printed = (unsigned char*) hooks->reallocate(buffer->buffer, buffer->offset + 1); + if (printed == NULL) { + goto fail; + } + buffer->buffer = NULL; + } + else /* otherwise copy the JSON over to a new buffer */ + { + printed = (unsigned char*) hooks->allocate(buffer->offset + 1); + if (printed == NULL) + { + goto fail; + } + memcpy(printed, buffer->buffer, cjson_min(buffer->length, buffer->offset + 1)); + printed[buffer->offset] = '\0'; /* just to be sure */ + + /* free the buffer */ + hooks->deallocate(buffer->buffer); + } + + return printed; + +fail: + if (buffer->buffer != NULL) + { + hooks->deallocate(buffer->buffer); + } + + if (printed != NULL) + { + hooks->deallocate(printed); + } + + return NULL; +} + +/* Render a cJSON item/entity/structure to text. */ +CJSON_PUBLIC(char *) cJSON_Print(const cJSON *item) +{ + return (char*)print(item, true, &global_hooks); +} + +CJSON_PUBLIC(char *) cJSON_PrintUnformatted(const cJSON *item) +{ + return (char*)print(item, false, &global_hooks); +} + +CJSON_PUBLIC(char *) cJSON_PrintBuffered(const cJSON *item, int prebuffer, cJSON_bool fmt) +{ + printbuffer p = { 0, 0, 0, 0, 0, 0, { 0, 0, 0 } }; + + if (prebuffer < 0) + { + return NULL; + } + + p.buffer = (unsigned char*)global_hooks.allocate((size_t)prebuffer); + if (!p.buffer) + { + return NULL; + } + + p.length = (size_t)prebuffer; + p.offset = 0; + p.noalloc = false; + p.format = fmt; + p.hooks = global_hooks; + + if (!print_value(item, &p)) + { + global_hooks.deallocate(p.buffer); + return NULL; + } + + return (char*)p.buffer; +} + +CJSON_PUBLIC(cJSON_bool) cJSON_PrintPreallocated(cJSON *item, char *buffer, const int length, const cJSON_bool format) +{ + printbuffer p = { 0, 0, 0, 0, 0, 0, { 0, 0, 0 } }; + + if ((length < 0) || (buffer == NULL)) + { + return false; + } + + p.buffer = (unsigned char*)buffer; + p.length = (size_t)length; + p.offset = 0; + p.noalloc = true; + p.format = format; + p.hooks = global_hooks; + + return print_value(item, &p); +} + +/* Parser core - when encountering text, process appropriately. */ +static cJSON_bool parse_value(cJSON * const item, parse_buffer * const input_buffer) +{ + if ((input_buffer == NULL) || (input_buffer->content == NULL)) + { + return false; /* no input */ + } + + /* parse the different types of values */ + /* null */ + if (can_read(input_buffer, 4) && (strncmp((const char*)buffer_at_offset(input_buffer), "null", 4) == 0)) + { + item->type = cJSON_NULL; + input_buffer->offset += 4; + return true; + } + /* false */ + if (can_read(input_buffer, 5) && (strncmp((const char*)buffer_at_offset(input_buffer), "false", 5) == 0)) + { + item->type = cJSON_False; + input_buffer->offset += 5; + return true; + } + /* true */ + if (can_read(input_buffer, 4) && (strncmp((const char*)buffer_at_offset(input_buffer), "true", 4) == 0)) + { + item->type = cJSON_True; + item->valueint = 1; + input_buffer->offset += 4; + return true; + } + /* string */ + if (can_access_at_index(input_buffer, 0) && (buffer_at_offset(input_buffer)[0] == '\"')) + { + return parse_string(item, input_buffer); + } + /* number */ + if (can_access_at_index(input_buffer, 0) && ((buffer_at_offset(input_buffer)[0] == '-') || ((buffer_at_offset(input_buffer)[0] >= '0') && (buffer_at_offset(input_buffer)[0] <= '9')))) + { + return parse_number(item, input_buffer); + } + /* array */ + if (can_access_at_index(input_buffer, 0) && (buffer_at_offset(input_buffer)[0] == '[')) + { + return parse_array(item, input_buffer); + } + /* object */ + if (can_access_at_index(input_buffer, 0) && (buffer_at_offset(input_buffer)[0] == '{')) + { + return parse_object(item, input_buffer); + } + + return false; +} + +/* Render a value to text. */ +static cJSON_bool print_value(const cJSON * const item, printbuffer * const output_buffer) +{ + unsigned char *output = NULL; + + if ((item == NULL) || (output_buffer == NULL)) + { + return false; + } + + switch ((item->type) & 0xFF) + { + case cJSON_NULL: + output = ensure(output_buffer, 5); + if (output == NULL) + { + return false; + } + strcpy((char*)output, "null"); + return true; + + case cJSON_False: + output = ensure(output_buffer, 6); + if (output == NULL) + { + return false; + } + strcpy((char*)output, "false"); + return true; + + case cJSON_True: + output = ensure(output_buffer, 5); + if (output == NULL) + { + return false; + } + strcpy((char*)output, "true"); + return true; + + case cJSON_Number: + return print_number(item, output_buffer); + + case cJSON_Raw: + { + size_t raw_length = 0; + if (item->valuestring == NULL) + { + return false; + } + + raw_length = strlen(item->valuestring) + sizeof(""); + output = ensure(output_buffer, raw_length); + if (output == NULL) + { + return false; + } + memcpy(output, item->valuestring, raw_length); + return true; + } + + case cJSON_String: + return print_string(item, output_buffer); + + case cJSON_Array: + return print_array(item, output_buffer); + + case cJSON_Object: + return print_object(item, output_buffer); + + default: + return false; + } +} + +/* Build an array from input text. */ +static cJSON_bool parse_array(cJSON * const item, parse_buffer * const input_buffer) +{ + cJSON *head = NULL; /* head of the linked list */ + cJSON *current_item = NULL; + + if (input_buffer->depth >= CJSON_NESTING_LIMIT) + { + return false; /* to deeply nested */ + } + input_buffer->depth++; + + if (buffer_at_offset(input_buffer)[0] != '[') + { + /* not an array */ + goto fail; + } + + input_buffer->offset++; + buffer_skip_whitespace(input_buffer); + if (can_access_at_index(input_buffer, 0) && (buffer_at_offset(input_buffer)[0] == ']')) + { + /* empty array */ + goto success; + } + + /* check if we skipped to the end of the buffer */ + if (cannot_access_at_index(input_buffer, 0)) + { + input_buffer->offset--; + goto fail; + } + + /* step back to character in front of the first element */ + input_buffer->offset--; + /* loop through the comma separated array elements */ + do + { + /* allocate next item */ + cJSON *new_item = cJSON_New_Item(&(input_buffer->hooks)); + if (new_item == NULL) + { + goto fail; /* allocation failure */ + } + + /* attach next item to list */ + if (head == NULL) + { + /* start the linked list */ + current_item = head = new_item; + } + else + { + /* add to the end and advance */ + current_item->next = new_item; + new_item->prev = current_item; + current_item = new_item; + } + + /* parse next value */ + input_buffer->offset++; + buffer_skip_whitespace(input_buffer); + if (!parse_value(current_item, input_buffer)) + { + goto fail; /* failed to parse value */ + } + buffer_skip_whitespace(input_buffer); + } + while (can_access_at_index(input_buffer, 0) && (buffer_at_offset(input_buffer)[0] == ',')); + + if (cannot_access_at_index(input_buffer, 0) || buffer_at_offset(input_buffer)[0] != ']') + { + goto fail; /* expected end of array */ + } + +success: + input_buffer->depth--; + + if (head != NULL) { + head->prev = current_item; + } + + item->type = cJSON_Array; + item->child = head; + + input_buffer->offset++; + + return true; + +fail: + if (head != NULL) + { + cJSON_Delete(head); + } + + return false; +} + +/* Render an array to text */ +static cJSON_bool print_array(const cJSON * const item, printbuffer * const output_buffer) +{ + unsigned char *output_pointer = NULL; + size_t length = 0; + cJSON *current_element = item->child; + + if (output_buffer == NULL) + { + return false; + } + + /* Compose the output array. */ + /* opening square bracket */ + output_pointer = ensure(output_buffer, 1); + if (output_pointer == NULL) + { + return false; + } + + *output_pointer = '['; + output_buffer->offset++; + output_buffer->depth++; + + while (current_element != NULL) + { + if (!print_value(current_element, output_buffer)) + { + return false; + } + update_offset(output_buffer); + if (current_element->next) + { + length = (size_t) (output_buffer->format ? 2 : 1); + output_pointer = ensure(output_buffer, length + 1); + if (output_pointer == NULL) + { + return false; + } + *output_pointer++ = ','; + if(output_buffer->format) + { + *output_pointer++ = ' '; + } + *output_pointer = '\0'; + output_buffer->offset += length; + } + current_element = current_element->next; + } + + output_pointer = ensure(output_buffer, 2); + if (output_pointer == NULL) + { + return false; + } + *output_pointer++ = ']'; + *output_pointer = '\0'; + output_buffer->depth--; + + return true; +} + +/* Build an object from the text. */ +static cJSON_bool parse_object(cJSON * const item, parse_buffer * const input_buffer) +{ + cJSON *head = NULL; /* linked list head */ + cJSON *current_item = NULL; + + if (input_buffer->depth >= CJSON_NESTING_LIMIT) + { + return false; /* to deeply nested */ + } + input_buffer->depth++; + + if (cannot_access_at_index(input_buffer, 0) || (buffer_at_offset(input_buffer)[0] != '{')) + { + goto fail; /* not an object */ + } + + input_buffer->offset++; + buffer_skip_whitespace(input_buffer); + if (can_access_at_index(input_buffer, 0) && (buffer_at_offset(input_buffer)[0] == '}')) + { + goto success; /* empty object */ + } + + /* check if we skipped to the end of the buffer */ + if (cannot_access_at_index(input_buffer, 0)) + { + input_buffer->offset--; + goto fail; + } + + /* step back to character in front of the first element */ + input_buffer->offset--; + /* loop through the comma separated array elements */ + do + { + /* allocate next item */ + cJSON *new_item = cJSON_New_Item(&(input_buffer->hooks)); + if (new_item == NULL) + { + goto fail; /* allocation failure */ + } + + /* attach next item to list */ + if (head == NULL) + { + /* start the linked list */ + current_item = head = new_item; + } + else + { + /* add to the end and advance */ + current_item->next = new_item; + new_item->prev = current_item; + current_item = new_item; + } + + /* parse the name of the child */ + input_buffer->offset++; + buffer_skip_whitespace(input_buffer); + if (!parse_string(current_item, input_buffer)) + { + goto fail; /* failed to parse name */ + } + buffer_skip_whitespace(input_buffer); + + /* swap valuestring and string, because we parsed the name */ + current_item->string = current_item->valuestring; + current_item->valuestring = NULL; + + if (cannot_access_at_index(input_buffer, 0) || (buffer_at_offset(input_buffer)[0] != ':')) + { + goto fail; /* invalid object */ + } + + /* parse the value */ + input_buffer->offset++; + buffer_skip_whitespace(input_buffer); + if (!parse_value(current_item, input_buffer)) + { + goto fail; /* failed to parse value */ + } + buffer_skip_whitespace(input_buffer); + } + while (can_access_at_index(input_buffer, 0) && (buffer_at_offset(input_buffer)[0] == ',')); + + if (cannot_access_at_index(input_buffer, 0) || (buffer_at_offset(input_buffer)[0] != '}')) + { + goto fail; /* expected end of object */ + } + +success: + input_buffer->depth--; + + if (head != NULL) { + head->prev = current_item; + } + + item->type = cJSON_Object; + item->child = head; + + input_buffer->offset++; + return true; + +fail: + if (head != NULL) + { + cJSON_Delete(head); + } + + return false; +} + +/* Render an object to text. */ +static cJSON_bool print_object(const cJSON * const item, printbuffer * const output_buffer) +{ + unsigned char *output_pointer = NULL; + size_t length = 0; + cJSON *current_item = item->child; + + if (output_buffer == NULL) + { + return false; + } + + /* Compose the output: */ + length = (size_t) (output_buffer->format ? 2 : 1); /* fmt: {\n */ + output_pointer = ensure(output_buffer, length + 1); + if (output_pointer == NULL) + { + return false; + } + + *output_pointer++ = '{'; + output_buffer->depth++; + if (output_buffer->format) + { + *output_pointer++ = '\n'; + } + output_buffer->offset += length; + + while (current_item) + { + if (output_buffer->format) + { + size_t i; + output_pointer = ensure(output_buffer, output_buffer->depth); + if (output_pointer == NULL) + { + return false; + } + for (i = 0; i < output_buffer->depth; i++) + { + *output_pointer++ = '\t'; + } + output_buffer->offset += output_buffer->depth; + } + + /* print key */ + if (!print_string_ptr((unsigned char*)current_item->string, output_buffer)) + { + return false; + } + update_offset(output_buffer); + + length = (size_t) (output_buffer->format ? 2 : 1); + output_pointer = ensure(output_buffer, length); + if (output_pointer == NULL) + { + return false; + } + *output_pointer++ = ':'; + if (output_buffer->format) + { + *output_pointer++ = '\t'; + } + output_buffer->offset += length; + + /* print value */ + if (!print_value(current_item, output_buffer)) + { + return false; + } + update_offset(output_buffer); + + /* print comma if not last */ + length = ((size_t)(output_buffer->format ? 1 : 0) + (size_t)(current_item->next ? 1 : 0)); + output_pointer = ensure(output_buffer, length + 1); + if (output_pointer == NULL) + { + return false; + } + if (current_item->next) + { + *output_pointer++ = ','; + } + + if (output_buffer->format) + { + *output_pointer++ = '\n'; + } + *output_pointer = '\0'; + output_buffer->offset += length; + + current_item = current_item->next; + } + + output_pointer = ensure(output_buffer, output_buffer->format ? (output_buffer->depth + 1) : 2); + if (output_pointer == NULL) + { + return false; + } + if (output_buffer->format) + { + size_t i; + for (i = 0; i < (output_buffer->depth - 1); i++) + { + *output_pointer++ = '\t'; + } + } + *output_pointer++ = '}'; + *output_pointer = '\0'; + output_buffer->depth--; + + return true; +} + +/* Get Array size/item / object item. */ +CJSON_PUBLIC(int) cJSON_GetArraySize(const cJSON *array) +{ + cJSON *child = NULL; + size_t size = 0; + + if (array == NULL) + { + return 0; + } + + child = array->child; + + while(child != NULL) + { + size++; + child = child->next; + } + + /* FIXME: Can overflow here. Cannot be fixed without breaking the API */ + + return (int)size; +} + +static cJSON* get_array_item(const cJSON *array, size_t index) +{ + cJSON *current_child = NULL; + + if (array == NULL) + { + return NULL; + } + + current_child = array->child; + while ((current_child != NULL) && (index > 0)) + { + index--; + current_child = current_child->next; + } + + return current_child; +} + +CJSON_PUBLIC(cJSON *) cJSON_GetArrayItem(const cJSON *array, int index) +{ + if (index < 0) + { + return NULL; + } + + return get_array_item(array, (size_t)index); +} + +static cJSON *get_object_item(const cJSON * const object, const char * const name, const cJSON_bool case_sensitive) +{ + cJSON *current_element = NULL; + + if ((object == NULL) || (name == NULL)) + { + return NULL; + } + + current_element = object->child; + if (case_sensitive) + { + while ((current_element != NULL) && (current_element->string != NULL) && (strcmp(name, current_element->string) != 0)) + { + current_element = current_element->next; + } + } + else + { + while ((current_element != NULL) && (case_insensitive_strcmp((const unsigned char*)name, (const unsigned char*)(current_element->string)) != 0)) + { + current_element = current_element->next; + } + } + + if ((current_element == NULL) || (current_element->string == NULL)) { + return NULL; + } + + return current_element; +} + +CJSON_PUBLIC(cJSON *) cJSON_GetObjectItem(const cJSON * const object, const char * const string) +{ + return get_object_item(object, string, false); +} + +CJSON_PUBLIC(cJSON *) cJSON_GetObjectItemCaseSensitive(const cJSON * const object, const char * const string) +{ + return get_object_item(object, string, true); +} + +CJSON_PUBLIC(cJSON_bool) cJSON_HasObjectItem(const cJSON *object, const char *string) +{ + return cJSON_GetObjectItem(object, string) ? 1 : 0; +} + +/* Utility for array list handling. */ +static void suffix_object(cJSON *prev, cJSON *item) +{ + prev->next = item; + item->prev = prev; +} + +/* Utility for handling references. */ +static cJSON *create_reference(const cJSON *item, const internal_hooks * const hooks) +{ + cJSON *reference = NULL; + if (item == NULL) + { + return NULL; + } + + reference = cJSON_New_Item(hooks); + if (reference == NULL) + { + return NULL; + } + + memcpy(reference, item, sizeof(cJSON)); + reference->string = NULL; + reference->type |= cJSON_IsReference; + reference->next = reference->prev = NULL; + return reference; +} + +static cJSON_bool add_item_to_array(cJSON *array, cJSON *item) +{ + cJSON *child = NULL; + + if ((item == NULL) || (array == NULL) || (array == item)) + { + return false; + } + + child = array->child; + /* + * To find the last item in array quickly, we use prev in array + */ + if (child == NULL) + { + /* list is empty, start new one */ + array->child = item; + item->prev = item; + item->next = NULL; + } + else + { + /* append to the end */ + if (child->prev) + { + suffix_object(child->prev, item); + array->child->prev = item; + } + } + + return true; +} + +/* Add item to array/object. */ +CJSON_PUBLIC(cJSON_bool) cJSON_AddItemToArray(cJSON *array, cJSON *item) +{ + return add_item_to_array(array, item); +} + +#if defined(__clang__) || (defined(__GNUC__) && ((__GNUC__ > 4) || ((__GNUC__ == 4) && (__GNUC_MINOR__ > 5)))) + #pragma GCC diagnostic push +#endif +#ifdef __GNUC__ +#pragma GCC diagnostic ignored "-Wcast-qual" +#endif +/* helper function to cast away const */ +static void* cast_away_const(const void* string) +{ + return (void*)string; +} +#if defined(__clang__) || (defined(__GNUC__) && ((__GNUC__ > 4) || ((__GNUC__ == 4) && (__GNUC_MINOR__ > 5)))) + #pragma GCC diagnostic pop +#endif + + +static cJSON_bool add_item_to_object(cJSON * const object, const char * const string, cJSON * const item, const internal_hooks * const hooks, const cJSON_bool constant_key) +{ + char *new_key = NULL; + int new_type = cJSON_Invalid; + + if ((object == NULL) || (string == NULL) || (item == NULL) || (object == item)) + { + return false; + } + + if (constant_key) + { + new_key = (char*)cast_away_const(string); + new_type = item->type | cJSON_StringIsConst; + } + else + { + new_key = (char*)cJSON_strdup((const unsigned char*)string, hooks); + if (new_key == NULL) + { + return false; + } + + new_type = item->type & ~cJSON_StringIsConst; + } + + if (!(item->type & cJSON_StringIsConst) && (item->string != NULL)) + { + hooks->deallocate(item->string); + } + + item->string = new_key; + item->type = new_type; + + return add_item_to_array(object, item); +} + +CJSON_PUBLIC(cJSON_bool) cJSON_AddItemToObject(cJSON *object, const char *string, cJSON *item) +{ + return add_item_to_object(object, string, item, &global_hooks, false); +} + +/* Add an item to an object with constant string as key */ +CJSON_PUBLIC(cJSON_bool) cJSON_AddItemToObjectCS(cJSON *object, const char *string, cJSON *item) +{ + return add_item_to_object(object, string, item, &global_hooks, true); +} + +CJSON_PUBLIC(cJSON_bool) cJSON_AddItemReferenceToArray(cJSON *array, cJSON *item) +{ + if (array == NULL) + { + return false; + } + + return add_item_to_array(array, create_reference(item, &global_hooks)); +} + +CJSON_PUBLIC(cJSON_bool) cJSON_AddItemReferenceToObject(cJSON *object, const char *string, cJSON *item) +{ + if ((object == NULL) || (string == NULL)) + { + return false; + } + + return add_item_to_object(object, string, create_reference(item, &global_hooks), &global_hooks, false); +} + +CJSON_PUBLIC(cJSON*) cJSON_AddNullToObject(cJSON * const object, const char * const name) +{ + cJSON *null = cJSON_CreateNull(); + if (add_item_to_object(object, name, null, &global_hooks, false)) + { + return null; + } + + cJSON_Delete(null); + return NULL; +} + +CJSON_PUBLIC(cJSON*) cJSON_AddTrueToObject(cJSON * const object, const char * const name) +{ + cJSON *true_item = cJSON_CreateTrue(); + if (add_item_to_object(object, name, true_item, &global_hooks, false)) + { + return true_item; + } + + cJSON_Delete(true_item); + return NULL; +} + +CJSON_PUBLIC(cJSON*) cJSON_AddFalseToObject(cJSON * const object, const char * const name) +{ + cJSON *false_item = cJSON_CreateFalse(); + if (add_item_to_object(object, name, false_item, &global_hooks, false)) + { + return false_item; + } + + cJSON_Delete(false_item); + return NULL; +} + +CJSON_PUBLIC(cJSON*) cJSON_AddBoolToObject(cJSON * const object, const char * const name, const cJSON_bool boolean) +{ + cJSON *bool_item = cJSON_CreateBool(boolean); + if (add_item_to_object(object, name, bool_item, &global_hooks, false)) + { + return bool_item; + } + + cJSON_Delete(bool_item); + return NULL; +} + +CJSON_PUBLIC(cJSON*) cJSON_AddNumberToObject(cJSON * const object, const char * const name, const double number) +{ + cJSON *number_item = cJSON_CreateNumber(number); + if (add_item_to_object(object, name, number_item, &global_hooks, false)) + { + return number_item; + } + + cJSON_Delete(number_item); + return NULL; +} + +CJSON_PUBLIC(cJSON*) cJSON_AddStringToObject(cJSON * const object, const char * const name, const char * const string) +{ + cJSON *string_item = cJSON_CreateString(string); + if (add_item_to_object(object, name, string_item, &global_hooks, false)) + { + return string_item; + } + + cJSON_Delete(string_item); + return NULL; +} + +CJSON_PUBLIC(cJSON*) cJSON_AddRawToObject(cJSON * const object, const char * const name, const char * const raw) +{ + cJSON *raw_item = cJSON_CreateRaw(raw); + if (add_item_to_object(object, name, raw_item, &global_hooks, false)) + { + return raw_item; + } + + cJSON_Delete(raw_item); + return NULL; +} + +CJSON_PUBLIC(cJSON*) cJSON_AddObjectToObject(cJSON * const object, const char * const name) +{ + cJSON *object_item = cJSON_CreateObject(); + if (add_item_to_object(object, name, object_item, &global_hooks, false)) + { + return object_item; + } + + cJSON_Delete(object_item); + return NULL; +} + +CJSON_PUBLIC(cJSON*) cJSON_AddArrayToObject(cJSON * const object, const char * const name) +{ + cJSON *array = cJSON_CreateArray(); + if (add_item_to_object(object, name, array, &global_hooks, false)) + { + return array; + } + + cJSON_Delete(array); + return NULL; +} + +CJSON_PUBLIC(cJSON *) cJSON_DetachItemViaPointer(cJSON *parent, cJSON * const item) +{ + if ((parent == NULL) || (item == NULL)) + { + return NULL; + } + + if (item != parent->child) + { + /* not the first element */ + item->prev->next = item->next; + } + if (item->next != NULL) + { + /* not the last element */ + item->next->prev = item->prev; + } + + if (item == parent->child) + { + /* first element */ + parent->child = item->next; + } + else if (item->next == NULL) + { + /* last element */ + parent->child->prev = item->prev; + } + + /* make sure the detached item doesn't point anywhere anymore */ + item->prev = NULL; + item->next = NULL; + + return item; +} + +CJSON_PUBLIC(cJSON *) cJSON_DetachItemFromArray(cJSON *array, int which) +{ + if (which < 0) + { + return NULL; + } + + return cJSON_DetachItemViaPointer(array, get_array_item(array, (size_t)which)); +} + +CJSON_PUBLIC(void) cJSON_DeleteItemFromArray(cJSON *array, int which) +{ + cJSON_Delete(cJSON_DetachItemFromArray(array, which)); +} + +CJSON_PUBLIC(cJSON *) cJSON_DetachItemFromObject(cJSON *object, const char *string) +{ + cJSON *to_detach = cJSON_GetObjectItem(object, string); + + return cJSON_DetachItemViaPointer(object, to_detach); +} + +CJSON_PUBLIC(cJSON *) cJSON_DetachItemFromObjectCaseSensitive(cJSON *object, const char *string) +{ + cJSON *to_detach = cJSON_GetObjectItemCaseSensitive(object, string); + + return cJSON_DetachItemViaPointer(object, to_detach); +} + +CJSON_PUBLIC(void) cJSON_DeleteItemFromObject(cJSON *object, const char *string) +{ + cJSON_Delete(cJSON_DetachItemFromObject(object, string)); +} + +CJSON_PUBLIC(void) cJSON_DeleteItemFromObjectCaseSensitive(cJSON *object, const char *string) +{ + cJSON_Delete(cJSON_DetachItemFromObjectCaseSensitive(object, string)); +} + +/* Replace array/object items with new ones. */ +CJSON_PUBLIC(cJSON_bool) cJSON_InsertItemInArray(cJSON *array, int which, cJSON *newitem) +{ + cJSON *after_inserted = NULL; + + if (which < 0) + { + return false; + } + + after_inserted = get_array_item(array, (size_t)which); + if (after_inserted == NULL) + { + return add_item_to_array(array, newitem); + } + + newitem->next = after_inserted; + newitem->prev = after_inserted->prev; + after_inserted->prev = newitem; + if (after_inserted == array->child) + { + array->child = newitem; + } + else + { + newitem->prev->next = newitem; + } + return true; +} + +CJSON_PUBLIC(cJSON_bool) cJSON_ReplaceItemViaPointer(cJSON * const parent, cJSON * const item, cJSON * replacement) +{ + if ((parent == NULL) || (replacement == NULL) || (item == NULL)) + { + return false; + } + + if (replacement == item) + { + return true; + } + + replacement->next = item->next; + replacement->prev = item->prev; + + if (replacement->next != NULL) + { + replacement->next->prev = replacement; + } + if (parent->child == item) + { + if (parent->child->prev == parent->child) + { + replacement->prev = replacement; + } + parent->child = replacement; + } + else + { /* + * To find the last item in array quickly, we use prev in array. + * We can't modify the last item's next pointer where this item was the parent's child + */ + if (replacement->prev != NULL) + { + replacement->prev->next = replacement; + } + if (replacement->next == NULL) + { + parent->child->prev = replacement; + } + } + + item->next = NULL; + item->prev = NULL; + cJSON_Delete(item); + + return true; +} + +CJSON_PUBLIC(cJSON_bool) cJSON_ReplaceItemInArray(cJSON *array, int which, cJSON *newitem) +{ + if (which < 0) + { + return false; + } + + return cJSON_ReplaceItemViaPointer(array, get_array_item(array, (size_t)which), newitem); +} + +static cJSON_bool replace_item_in_object(cJSON *object, const char *string, cJSON *replacement, cJSON_bool case_sensitive) +{ + if ((replacement == NULL) || (string == NULL)) + { + return false; + } + + /* replace the name in the replacement */ + if (!(replacement->type & cJSON_StringIsConst) && (replacement->string != NULL)) + { + cJSON_free(replacement->string); + } + replacement->string = (char*)cJSON_strdup((const unsigned char*)string, &global_hooks); + replacement->type &= ~cJSON_StringIsConst; + + return cJSON_ReplaceItemViaPointer(object, get_object_item(object, string, case_sensitive), replacement); +} + +CJSON_PUBLIC(cJSON_bool) cJSON_ReplaceItemInObject(cJSON *object, const char *string, cJSON *newitem) +{ + return replace_item_in_object(object, string, newitem, false); +} + +CJSON_PUBLIC(cJSON_bool) cJSON_ReplaceItemInObjectCaseSensitive(cJSON *object, const char *string, cJSON *newitem) +{ + return replace_item_in_object(object, string, newitem, true); +} + +/* Create basic types: */ +CJSON_PUBLIC(cJSON *) cJSON_CreateNull(void) +{ + cJSON *item = cJSON_New_Item(&global_hooks); + if(item) + { + item->type = cJSON_NULL; + } + + return item; +} + +CJSON_PUBLIC(cJSON *) cJSON_CreateTrue(void) +{ + cJSON *item = cJSON_New_Item(&global_hooks); + if(item) + { + item->type = cJSON_True; + } + + return item; +} + +CJSON_PUBLIC(cJSON *) cJSON_CreateFalse(void) +{ + cJSON *item = cJSON_New_Item(&global_hooks); + if(item) + { + item->type = cJSON_False; + } + + return item; +} + +CJSON_PUBLIC(cJSON *) cJSON_CreateBool(cJSON_bool boolean) +{ + cJSON *item = cJSON_New_Item(&global_hooks); + if(item) + { + item->type = boolean ? cJSON_True : cJSON_False; + } + + return item; +} + +CJSON_PUBLIC(cJSON *) cJSON_CreateNumber(double num) +{ + cJSON *item = cJSON_New_Item(&global_hooks); + if(item) + { + item->type = cJSON_Number; + item->valuedouble = num; + + /* use saturation in case of overflow */ + if (num >= INT_MAX) + { + item->valueint = INT_MAX; + } + else if (num <= (double)INT_MIN) + { + item->valueint = INT_MIN; + } + else + { + item->valueint = (int)num; + } + } + + return item; +} + +CJSON_PUBLIC(cJSON *) cJSON_CreateString(const char *string) +{ + cJSON *item = cJSON_New_Item(&global_hooks); + if(item) + { + item->type = cJSON_String; + item->valuestring = (char*)cJSON_strdup((const unsigned char*)string, &global_hooks); + if(!item->valuestring) + { + cJSON_Delete(item); + return NULL; + } + } + + return item; +} + +CJSON_PUBLIC(cJSON *) cJSON_CreateStringReference(const char *string) +{ + cJSON *item = cJSON_New_Item(&global_hooks); + if (item != NULL) + { + item->type = cJSON_String | cJSON_IsReference; + item->valuestring = (char*)cast_away_const(string); + } + + return item; +} + +CJSON_PUBLIC(cJSON *) cJSON_CreateObjectReference(const cJSON *child) +{ + cJSON *item = cJSON_New_Item(&global_hooks); + if (item != NULL) { + item->type = cJSON_Object | cJSON_IsReference; + item->child = (cJSON*)cast_away_const(child); + } + + return item; +} + +CJSON_PUBLIC(cJSON *) cJSON_CreateArrayReference(const cJSON *child) { + cJSON *item = cJSON_New_Item(&global_hooks); + if (item != NULL) { + item->type = cJSON_Array | cJSON_IsReference; + item->child = (cJSON*)cast_away_const(child); + } + + return item; +} + +CJSON_PUBLIC(cJSON *) cJSON_CreateRaw(const char *raw) +{ + cJSON *item = cJSON_New_Item(&global_hooks); + if(item) + { + item->type = cJSON_Raw; + item->valuestring = (char*)cJSON_strdup((const unsigned char*)raw, &global_hooks); + if(!item->valuestring) + { + cJSON_Delete(item); + return NULL; + } + } + + return item; +} + +CJSON_PUBLIC(cJSON *) cJSON_CreateArray(void) +{ + cJSON *item = cJSON_New_Item(&global_hooks); + if(item) + { + item->type=cJSON_Array; + } + + return item; +} + +CJSON_PUBLIC(cJSON *) cJSON_CreateObject(void) +{ + cJSON *item = cJSON_New_Item(&global_hooks); + if (item) + { + item->type = cJSON_Object; + } + + return item; +} + +/* Create Arrays: */ +CJSON_PUBLIC(cJSON *) cJSON_CreateIntArray(const int *numbers, int count) +{ + size_t i = 0; + cJSON *n = NULL; + cJSON *p = NULL; + cJSON *a = NULL; + + if ((count < 0) || (numbers == NULL)) + { + return NULL; + } + + a = cJSON_CreateArray(); + + for(i = 0; a && (i < (size_t)count); i++) + { + n = cJSON_CreateNumber(numbers[i]); + if (!n) + { + cJSON_Delete(a); + return NULL; + } + if(!i) + { + a->child = n; + } + else + { + suffix_object(p, n); + } + p = n; + } + + if (a && a->child) { + a->child->prev = n; + } + + return a; +} + +CJSON_PUBLIC(cJSON *) cJSON_CreateFloatArray(const double *numbers, int count) +{ + size_t i = 0; + cJSON *n = NULL; + cJSON *p = NULL; + cJSON *a = NULL; + + if ((count < 0) || (numbers == NULL)) + { + return NULL; + } + + a = cJSON_CreateArray(); + + for(i = 0; a && (i < (size_t)count); i++) + { + n = cJSON_CreateNumber((double)numbers[i]); + if(!n) + { + cJSON_Delete(a); + return NULL; + } + if(!i) + { + a->child = n; + } + else + { + suffix_object(p, n); + } + p = n; + } + + if (a && a->child) { + a->child->prev = n; + } + + return a; +} + +CJSON_PUBLIC(cJSON *) cJSON_CreateDoubleArray(const double *numbers, int count) +{ + size_t i = 0; + cJSON *n = NULL; + cJSON *p = NULL; + cJSON *a = NULL; + + if ((count < 0) || (numbers == NULL)) + { + return NULL; + } + + a = cJSON_CreateArray(); + + for(i = 0; a && (i < (size_t)count); i++) + { + n = cJSON_CreateNumber(numbers[i]); + if(!n) + { + cJSON_Delete(a); + return NULL; + } + if(!i) + { + a->child = n; + } + else + { + suffix_object(p, n); + } + p = n; + } + + if (a && a->child) { + a->child->prev = n; + } + + return a; +} + +CJSON_PUBLIC(cJSON *) cJSON_CreateStringArray(const char *const *strings, int count) +{ + size_t i = 0; + cJSON *n = NULL; + cJSON *p = NULL; + cJSON *a = NULL; + + if ((count < 0) || (strings == NULL)) + { + return NULL; + } + + a = cJSON_CreateArray(); + + for (i = 0; a && (i < (size_t)count); i++) + { + n = cJSON_CreateString(strings[i]); + if(!n) + { + cJSON_Delete(a); + return NULL; + } + if(!i) + { + a->child = n; + } + else + { + suffix_object(p,n); + } + p = n; + } + + if (a && a->child) { + a->child->prev = n; + } + + return a; +} + +/* Duplication */ +CJSON_PUBLIC(cJSON *) cJSON_Duplicate(const cJSON *item, cJSON_bool recurse) +{ + cJSON *newitem = NULL; + cJSON *child = NULL; + cJSON *next = NULL; + cJSON *newchild = NULL; + + /* Bail on bad ptr */ + if (!item) + { + goto fail; + } + /* Create new item */ + newitem = cJSON_New_Item(&global_hooks); + if (!newitem) + { + goto fail; + } + /* Copy over all vars */ + newitem->type = item->type & (~cJSON_IsReference); + newitem->valueint = item->valueint; + newitem->valuedouble = item->valuedouble; + if (item->valuestring) + { + newitem->valuestring = (char*)cJSON_strdup((unsigned char*)item->valuestring, &global_hooks); + if (!newitem->valuestring) + { + goto fail; + } + } + if (item->string) + { + newitem->string = (item->type&cJSON_StringIsConst) ? item->string : (char*)cJSON_strdup((unsigned char*)item->string, &global_hooks); + if (!newitem->string) + { + goto fail; + } + } + /* If non-recursive, then we're done! */ + if (!recurse) + { + return newitem; + } + /* Walk the ->next chain for the child. */ + child = item->child; + while (child != NULL) + { + newchild = cJSON_Duplicate(child, true); /* Duplicate (with recurse) each item in the ->next chain */ + if (!newchild) + { + goto fail; + } + if (next != NULL) + { + /* If newitem->child already set, then crosswire ->prev and ->next and move on */ + next->next = newchild; + newchild->prev = next; + next = newchild; + } + else + { + /* Set newitem->child and move to it */ + newitem->child = newchild; + next = newchild; + } + child = child->next; + } + if (newitem && newitem->child) + { + newitem->child->prev = newchild; + } + + return newitem; + +fail: + if (newitem != NULL) + { + cJSON_Delete(newitem); + } + + return NULL; +} + +static void skip_oneline_comment(char **input) +{ + *input += static_strlen("//"); + + for (; (*input)[0] != '\0'; ++(*input)) + { + if ((*input)[0] == '\n') { + *input += static_strlen("\n"); + return; + } + } +} + +static void skip_multiline_comment(char **input) +{ + *input += static_strlen("/*"); + + for (; (*input)[0] != '\0'; ++(*input)) + { + if (((*input)[0] == '*') && ((*input)[1] == '/')) + { + *input += static_strlen("*/"); + return; + } + } +} + +static void minify_string(char **input, char **output) { + (*output)[0] = (*input)[0]; + *input += static_strlen("\""); + *output += static_strlen("\""); + + + for (; (*input)[0] != '\0'; (void)++(*input), ++(*output)) { + (*output)[0] = (*input)[0]; + + if ((*input)[0] == '\"') { + (*output)[0] = '\"'; + *input += static_strlen("\""); + *output += static_strlen("\""); + return; + } else if (((*input)[0] == '\\') && ((*input)[1] == '\"')) { + (*output)[1] = (*input)[1]; + *input += static_strlen("\""); + *output += static_strlen("\""); + } + } +} + +CJSON_PUBLIC(void) cJSON_Minify(char *json) +{ + char *into = json; + + if (json == NULL) + { + return; + } + + while (json[0] != '\0') + { + switch (json[0]) + { + case ' ': + case '\t': + case '\r': + case '\n': + json++; + break; + + case '/': + if (json[1] == '/') + { + skip_oneline_comment(&json); + } + else if (json[1] == '*') + { + skip_multiline_comment(&json); + } else { + json++; + } + break; + + case '\"': + minify_string(&json, (char**)&into); + break; + + default: + into[0] = json[0]; + json++; + into++; + } + } + + /* and null-terminate. */ + *into = '\0'; +} + +CJSON_PUBLIC(cJSON_bool) cJSON_IsInvalid(const cJSON * const item) +{ + if (item == NULL) + { + return false; + } + + return (item->type & 0xFF) == cJSON_Invalid; +} + +CJSON_PUBLIC(cJSON_bool) cJSON_IsFalse(const cJSON * const item) +{ + if (item == NULL) + { + return false; + } + + return (item->type & 0xFF) == cJSON_False; +} + +CJSON_PUBLIC(cJSON_bool) cJSON_IsTrue(const cJSON * const item) +{ + if (item == NULL) + { + return false; + } + + return (item->type & 0xff) == cJSON_True; +} + + +CJSON_PUBLIC(cJSON_bool) cJSON_IsBool(const cJSON * const item) +{ + if (item == NULL) + { + return false; + } + + return (item->type & (cJSON_True | cJSON_False)) != 0; +} +CJSON_PUBLIC(cJSON_bool) cJSON_IsNull(const cJSON * const item) +{ + if (item == NULL) + { + return false; + } + + return (item->type & 0xFF) == cJSON_NULL; +} + +CJSON_PUBLIC(cJSON_bool) cJSON_IsNumber(const cJSON * const item) +{ + if (item == NULL) + { + return false; + } + + return (item->type & 0xFF) == cJSON_Number; +} + +CJSON_PUBLIC(cJSON_bool) cJSON_IsString(const cJSON * const item) +{ + if (item == NULL) + { + return false; + } + + return (item->type & 0xFF) == cJSON_String; +} + +CJSON_PUBLIC(cJSON_bool) cJSON_IsArray(const cJSON * const item) +{ + if (item == NULL) + { + return false; + } + + return (item->type & 0xFF) == cJSON_Array; +} + +CJSON_PUBLIC(cJSON_bool) cJSON_IsObject(const cJSON * const item) +{ + if (item == NULL) + { + return false; + } + + return (item->type & 0xFF) == cJSON_Object; +} + +CJSON_PUBLIC(cJSON_bool) cJSON_IsRaw(const cJSON * const item) +{ + if (item == NULL) + { + return false; + } + + return (item->type & 0xFF) == cJSON_Raw; +} + +CJSON_PUBLIC(cJSON_bool) cJSON_Compare(const cJSON * const a, const cJSON * const b, const cJSON_bool case_sensitive) +{ + if ((a == NULL) || (b == NULL) || ((a->type & 0xFF) != (b->type & 0xFF))) + { + return false; + } + + /* check if type is valid */ + switch (a->type & 0xFF) + { + case cJSON_False: + case cJSON_True: + case cJSON_NULL: + case cJSON_Number: + case cJSON_String: + case cJSON_Raw: + case cJSON_Array: + case cJSON_Object: + break; + + default: + return false; + } + + /* identical objects are equal */ + if (a == b) + { + return true; + } + + switch (a->type & 0xFF) + { + /* in these cases and equal type is enough */ + case cJSON_False: + case cJSON_True: + case cJSON_NULL: + return true; + + case cJSON_Number: + if (compare_double(a->valuedouble, b->valuedouble)) + { + return true; + } + return false; + + case cJSON_String: + case cJSON_Raw: + if ((a->valuestring == NULL) || (b->valuestring == NULL)) + { + return false; + } + if (strcmp(a->valuestring, b->valuestring) == 0) + { + return true; + } + + return false; + + case cJSON_Array: + { + cJSON *a_element = a->child; + cJSON *b_element = b->child; + + for (; (a_element != NULL) && (b_element != NULL);) + { + if (!cJSON_Compare(a_element, b_element, case_sensitive)) + { + return false; + } + + a_element = a_element->next; + b_element = b_element->next; + } + + /* one of the arrays is longer than the other */ + if (a_element != b_element) { + return false; + } + + return true; + } + + case cJSON_Object: + { + cJSON *a_element = NULL; + cJSON *b_element = NULL; + cJSON_ArrayForEach(a_element, a) + { + /* TODO This has O(n^2) runtime, which is horrible! */ + b_element = get_object_item(b, a_element->string, case_sensitive); + if (b_element == NULL) + { + return false; + } + + if (!cJSON_Compare(a_element, b_element, case_sensitive)) + { + return false; + } + } + + /* doing this twice, once on a and b to prevent true comparison if a subset of b + * TODO: Do this the proper way, this is just a fix for now */ + cJSON_ArrayForEach(b_element, b) + { + a_element = get_object_item(a, b_element->string, case_sensitive); + if (a_element == NULL) + { + return false; + } + + if (!cJSON_Compare(b_element, a_element, case_sensitive)) + { + return false; + } + } + + return true; + } + + default: + return false; + } +} + +CJSON_PUBLIC(void *) cJSON_malloc(size_t size) +{ + return global_hooks.allocate(size); +} + +CJSON_PUBLIC(void) cJSON_free(void *object) +{ + global_hooks.deallocate(object); +} diff --git a/examples/pikapython/pikapython/pikascript-lib/pika_cjson/cJSON.h b/examples/pikapython/pikapython/pikascript-lib/pika_cjson/cJSON.h new file mode 100755 index 00000000..32776861 --- /dev/null +++ b/examples/pikapython/pikapython/pikascript-lib/pika_cjson/cJSON.h @@ -0,0 +1,293 @@ +/* + Copyright (c) 2009-2017 Dave Gamble and cJSON contributors + + 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 cJSON__h +#define cJSON__h + +#ifdef __cplusplus +extern "C" +{ +#endif + +#if !defined(__WINDOWS__) && (defined(WIN32) || defined(WIN64) || defined(_MSC_VER) || defined(_WIN32)) +#define __WINDOWS__ +#endif + +#ifdef __WINDOWS__ + +/* When compiling for windows, we specify a specific calling convention to avoid issues where we are being called from a project with a different default calling convention. For windows you have 3 define options: + +CJSON_HIDE_SYMBOLS - Define this in the case where you don't want to ever dllexport symbols +CJSON_EXPORT_SYMBOLS - Define this on library build when you want to dllexport symbols (default) +CJSON_IMPORT_SYMBOLS - Define this if you want to dllimport symbol + +For *nix builds that support visibility attribute, you can define similar behavior by + +setting default visibility to hidden by adding +-fvisibility=hidden (for gcc) +or +-xldscope=hidden (for sun cc) +to CFLAGS + +then using the CJSON_API_VISIBILITY flag to "export" the same symbols the way CJSON_EXPORT_SYMBOLS does + +*/ + +#define CJSON_CDECL __cdecl +#define CJSON_STDCALL __stdcall + +/* export symbols by default, this is necessary for copy pasting the C and header file */ +#if !defined(CJSON_HIDE_SYMBOLS) && !defined(CJSON_IMPORT_SYMBOLS) && !defined(CJSON_EXPORT_SYMBOLS) +#define CJSON_EXPORT_SYMBOLS +#endif + +#if defined(CJSON_HIDE_SYMBOLS) +#define CJSON_PUBLIC(type) type CJSON_STDCALL +#elif defined(CJSON_EXPORT_SYMBOLS) +#define CJSON_PUBLIC(type) __declspec(dllexport) type CJSON_STDCALL +#elif defined(CJSON_IMPORT_SYMBOLS) +#define CJSON_PUBLIC(type) __declspec(dllimport) type CJSON_STDCALL +#endif +#else /* !__WINDOWS__ */ +#define CJSON_CDECL +#define CJSON_STDCALL + +#if (defined(__GNUC__) || defined(__SUNPRO_CC) || defined (__SUNPRO_C)) && defined(CJSON_API_VISIBILITY) +#define CJSON_PUBLIC(type) __attribute__((visibility("default"))) type +#else +#define CJSON_PUBLIC(type) type +#endif +#endif + +/* project version */ +#define CJSON_VERSION_MAJOR 1 +#define CJSON_VERSION_MINOR 7 +#define CJSON_VERSION_PATCH 15 + +#include + +/* cJSON Types: */ +#define cJSON_Invalid (0) +#define cJSON_False (1 << 0) +#define cJSON_True (1 << 1) +#define cJSON_NULL (1 << 2) +#define cJSON_Number (1 << 3) +#define cJSON_String (1 << 4) +#define cJSON_Array (1 << 5) +#define cJSON_Object (1 << 6) +#define cJSON_Raw (1 << 7) /* raw json */ + +#define cJSON_IsReference 256 +#define cJSON_StringIsConst 512 + +/* The cJSON structure: */ +typedef struct cJSON +{ + /* next/prev allow you to walk array/object chains. Alternatively, use GetArraySize/GetArrayItem/GetObjectItem */ + struct cJSON *next; + struct cJSON *prev; + /* An array or object item will have a child pointer pointing to a chain of the items in the array/object. */ + struct cJSON *child; + + /* The type of the item, as above. */ + int type; + + /* The item's string, if type==cJSON_String and type == cJSON_Raw */ + char *valuestring; + /* writing to valueint is DEPRECATED, use cJSON_SetNumberValue instead */ + int valueint; + /* The item's number, if type==cJSON_Number */ + double valuedouble; + + /* The item's name string, if this item is the child of, or is in the list of subitems of an object. */ + char *string; +} cJSON; + +typedef struct cJSON_Hooks +{ + /* malloc/free are CDECL on Windows regardless of the default calling convention of the compiler, so ensure the hooks allow passing those functions directly. */ + void *(CJSON_CDECL *malloc_fn)(size_t sz); + void (CJSON_CDECL *free_fn)(void *ptr); +} cJSON_Hooks; + +typedef int cJSON_bool; + +/* Limits how deeply nested arrays/objects can be before cJSON rejects to parse them. + * This is to prevent stack overflows. */ +#ifndef CJSON_NESTING_LIMIT +#define CJSON_NESTING_LIMIT 1000 +#endif + +/* returns the version of cJSON as a string */ +CJSON_PUBLIC(const char*) cJSON_Version(void); + +/* Supply malloc, realloc and free functions to cJSON */ +CJSON_PUBLIC(void) cJSON_InitHooks(cJSON_Hooks* hooks); + +/* Memory Management: the caller is always responsible to free the results from all variants of cJSON_Parse (with cJSON_Delete) and cJSON_Print (with stdlib free, cJSON_Hooks.free_fn, or cJSON_free as appropriate). The exception is cJSON_PrintPreallocated, where the caller has full responsibility of the buffer. */ +/* Supply a block of JSON, and this returns a cJSON object you can interrogate. */ +CJSON_PUBLIC(cJSON *) cJSON_Parse(const char *value); +CJSON_PUBLIC(cJSON *) cJSON_ParseWithLength(const char *value, size_t buffer_length); +/* ParseWithOpts allows you to require (and check) that the JSON is null terminated, and to retrieve the pointer to the final byte parsed. */ +/* If you supply a ptr in return_parse_end and parsing fails, then return_parse_end will contain a pointer to the error so will match cJSON_GetErrorPtr(). */ +CJSON_PUBLIC(cJSON *) cJSON_ParseWithOpts(const char *value, const char **return_parse_end, cJSON_bool require_null_terminated); +CJSON_PUBLIC(cJSON *) cJSON_ParseWithLengthOpts(const char *value, size_t buffer_length, const char **return_parse_end, cJSON_bool require_null_terminated); + +/* Render a cJSON entity to text for transfer/storage. */ +CJSON_PUBLIC(char *) cJSON_Print(const cJSON *item); +/* Render a cJSON entity to text for transfer/storage without any formatting. */ +CJSON_PUBLIC(char *) cJSON_PrintUnformatted(const cJSON *item); +/* Render a cJSON entity to text using a buffered strategy. prebuffer is a guess at the final size. guessing well reduces reallocation. fmt=0 gives unformatted, =1 gives formatted */ +CJSON_PUBLIC(char *) cJSON_PrintBuffered(const cJSON *item, int prebuffer, cJSON_bool fmt); +/* Render a cJSON entity to text using a buffer already allocated in memory with given length. Returns 1 on success and 0 on failure. */ +/* NOTE: cJSON is not always 100% accurate in estimating how much memory it will use, so to be safe allocate 5 bytes more than you actually need */ +CJSON_PUBLIC(cJSON_bool) cJSON_PrintPreallocated(cJSON *item, char *buffer, const int length, const cJSON_bool format); +/* Delete a cJSON entity and all subentities. */ +CJSON_PUBLIC(void) cJSON_Delete(cJSON *item); + +/* Returns the number of items in an array (or object). */ +CJSON_PUBLIC(int) cJSON_GetArraySize(const cJSON *array); +/* Retrieve item number "index" from array "array". Returns NULL if unsuccessful. */ +CJSON_PUBLIC(cJSON *) cJSON_GetArrayItem(const cJSON *array, int index); +/* Get item "string" from object. Case insensitive. */ +CJSON_PUBLIC(cJSON *) cJSON_GetObjectItem(const cJSON * const object, const char * const string); +CJSON_PUBLIC(cJSON *) cJSON_GetObjectItemCaseSensitive(const cJSON * const object, const char * const string); +CJSON_PUBLIC(cJSON_bool) cJSON_HasObjectItem(const cJSON *object, const char *string); +/* For analysing failed parses. This returns a pointer to the parse error. You'll probably need to look a few chars back to make sense of it. Defined when cJSON_Parse() returns 0. 0 when cJSON_Parse() succeeds. */ +CJSON_PUBLIC(const char *) cJSON_GetErrorPtr(void); + +/* Check item type and return its value */ +CJSON_PUBLIC(char *) cJSON_GetStringValue(const cJSON * const item); +CJSON_PUBLIC(double) cJSON_GetNumberValue(const cJSON * const item); + +/* These functions check the type of an item */ +CJSON_PUBLIC(cJSON_bool) cJSON_IsInvalid(const cJSON * const item); +CJSON_PUBLIC(cJSON_bool) cJSON_IsFalse(const cJSON * const item); +CJSON_PUBLIC(cJSON_bool) cJSON_IsTrue(const cJSON * const item); +CJSON_PUBLIC(cJSON_bool) cJSON_IsBool(const cJSON * const item); +CJSON_PUBLIC(cJSON_bool) cJSON_IsNull(const cJSON * const item); +CJSON_PUBLIC(cJSON_bool) cJSON_IsNumber(const cJSON * const item); +CJSON_PUBLIC(cJSON_bool) cJSON_IsString(const cJSON * const item); +CJSON_PUBLIC(cJSON_bool) cJSON_IsArray(const cJSON * const item); +CJSON_PUBLIC(cJSON_bool) cJSON_IsObject(const cJSON * const item); +CJSON_PUBLIC(cJSON_bool) cJSON_IsRaw(const cJSON * const item); + +/* These calls create a cJSON item of the appropriate type. */ +CJSON_PUBLIC(cJSON *) cJSON_CreateNull(void); +CJSON_PUBLIC(cJSON *) cJSON_CreateTrue(void); +CJSON_PUBLIC(cJSON *) cJSON_CreateFalse(void); +CJSON_PUBLIC(cJSON *) cJSON_CreateBool(cJSON_bool boolean); +CJSON_PUBLIC(cJSON *) cJSON_CreateNumber(double num); +CJSON_PUBLIC(cJSON *) cJSON_CreateString(const char *string); +/* raw json */ +CJSON_PUBLIC(cJSON *) cJSON_CreateRaw(const char *raw); +CJSON_PUBLIC(cJSON *) cJSON_CreateArray(void); +CJSON_PUBLIC(cJSON *) cJSON_CreateObject(void); + +/* Create a string where valuestring references a string so + * it will not be freed by cJSON_Delete */ +CJSON_PUBLIC(cJSON *) cJSON_CreateStringReference(const char *string); +/* Create an object/array that only references it's elements so + * they will not be freed by cJSON_Delete */ +CJSON_PUBLIC(cJSON *) cJSON_CreateObjectReference(const cJSON *child); +CJSON_PUBLIC(cJSON *) cJSON_CreateArrayReference(const cJSON *child); + +/* These utilities create an Array of count items. + * The parameter count cannot be greater than the number of elements in the number array, otherwise array access will be out of bounds.*/ +CJSON_PUBLIC(cJSON *) cJSON_CreateIntArray(const int *numbers, int count); +CJSON_PUBLIC(cJSON *) cJSON_CreateFloatArray(const double *numbers, int count); +CJSON_PUBLIC(cJSON *) cJSON_CreateDoubleArray(const double *numbers, int count); +CJSON_PUBLIC(cJSON *) cJSON_CreateStringArray(const char *const *strings, int count); + +/* Append item to the specified array/object. */ +CJSON_PUBLIC(cJSON_bool) cJSON_AddItemToArray(cJSON *array, cJSON *item); +CJSON_PUBLIC(cJSON_bool) cJSON_AddItemToObject(cJSON *object, const char *string, cJSON *item); +/* Use this when string is definitely const (i.e. a literal, or as good as), and will definitely survive the cJSON object. + * WARNING: When this function was used, make sure to always check that (item->type & cJSON_StringIsConst) is zero before + * writing to `item->string` */ +CJSON_PUBLIC(cJSON_bool) cJSON_AddItemToObjectCS(cJSON *object, const char *string, cJSON *item); +/* Append reference to item to the specified array/object. Use this when you want to add an existing cJSON to a new cJSON, but don't want to corrupt your existing cJSON. */ +CJSON_PUBLIC(cJSON_bool) cJSON_AddItemReferenceToArray(cJSON *array, cJSON *item); +CJSON_PUBLIC(cJSON_bool) cJSON_AddItemReferenceToObject(cJSON *object, const char *string, cJSON *item); + +/* Remove/Detach items from Arrays/Objects. */ +CJSON_PUBLIC(cJSON *) cJSON_DetachItemViaPointer(cJSON *parent, cJSON * const item); +CJSON_PUBLIC(cJSON *) cJSON_DetachItemFromArray(cJSON *array, int which); +CJSON_PUBLIC(void) cJSON_DeleteItemFromArray(cJSON *array, int which); +CJSON_PUBLIC(cJSON *) cJSON_DetachItemFromObject(cJSON *object, const char *string); +CJSON_PUBLIC(cJSON *) cJSON_DetachItemFromObjectCaseSensitive(cJSON *object, const char *string); +CJSON_PUBLIC(void) cJSON_DeleteItemFromObject(cJSON *object, const char *string); +CJSON_PUBLIC(void) cJSON_DeleteItemFromObjectCaseSensitive(cJSON *object, const char *string); + +/* Update array items. */ +CJSON_PUBLIC(cJSON_bool) cJSON_InsertItemInArray(cJSON *array, int which, cJSON *newitem); /* Shifts pre-existing items to the right. */ +CJSON_PUBLIC(cJSON_bool) cJSON_ReplaceItemViaPointer(cJSON * const parent, cJSON * const item, cJSON * replacement); +CJSON_PUBLIC(cJSON_bool) cJSON_ReplaceItemInArray(cJSON *array, int which, cJSON *newitem); +CJSON_PUBLIC(cJSON_bool) cJSON_ReplaceItemInObject(cJSON *object,const char *string,cJSON *newitem); +CJSON_PUBLIC(cJSON_bool) cJSON_ReplaceItemInObjectCaseSensitive(cJSON *object,const char *string,cJSON *newitem); + +/* Duplicate a cJSON item */ +CJSON_PUBLIC(cJSON *) cJSON_Duplicate(const cJSON *item, cJSON_bool recurse); +/* Duplicate will create a new, identical cJSON item to the one you pass, in new memory that will + * need to be released. With recurse!=0, it will duplicate any children connected to the item. + * The item->next and ->prev pointers are always zero on return from Duplicate. */ +/* Recursively compare two cJSON items for equality. If either a or b is NULL or invalid, they will be considered unequal. + * case_sensitive determines if object keys are treated case sensitive (1) or case insensitive (0) */ +CJSON_PUBLIC(cJSON_bool) cJSON_Compare(const cJSON * const a, const cJSON * const b, const cJSON_bool case_sensitive); + +/* Minify a strings, remove blank characters(such as ' ', '\t', '\r', '\n') from strings. + * The input pointer json cannot point to a read-only address area, such as a string constant, + * but should point to a readable and writable address area. */ +CJSON_PUBLIC(void) cJSON_Minify(char *json); + +/* Helper functions for creating and adding items to an object at the same time. + * They return the added item or NULL on failure. */ +CJSON_PUBLIC(cJSON*) cJSON_AddNullToObject(cJSON * const object, const char * const name); +CJSON_PUBLIC(cJSON*) cJSON_AddTrueToObject(cJSON * const object, const char * const name); +CJSON_PUBLIC(cJSON*) cJSON_AddFalseToObject(cJSON * const object, const char * const name); +CJSON_PUBLIC(cJSON*) cJSON_AddBoolToObject(cJSON * const object, const char * const name, const cJSON_bool boolean); +CJSON_PUBLIC(cJSON*) cJSON_AddNumberToObject(cJSON * const object, const char * const name, const double number); +CJSON_PUBLIC(cJSON*) cJSON_AddStringToObject(cJSON * const object, const char * const name, const char * const string); +CJSON_PUBLIC(cJSON*) cJSON_AddRawToObject(cJSON * const object, const char * const name, const char * const raw); +CJSON_PUBLIC(cJSON*) cJSON_AddObjectToObject(cJSON * const object, const char * const name); +CJSON_PUBLIC(cJSON*) cJSON_AddArrayToObject(cJSON * const object, const char * const name); + +/* When assigning an integer value, it needs to be propagated to valuedouble too. */ +#define cJSON_SetIntValue(object, number) ((object) ? (object)->valueint = (object)->valuedouble = (number) : (number)) +/* helper for the cJSON_SetNumberValue macro */ +CJSON_PUBLIC(double) cJSON_SetNumberHelper(cJSON *object, double number); +#define cJSON_SetNumberValue(object, number) ((object != NULL) ? cJSON_SetNumberHelper(object, (double)number) : (number)) +/* Change the valuestring of a cJSON_String object, only takes effect when type of object is cJSON_String */ +CJSON_PUBLIC(char*) cJSON_SetValuestring(cJSON *object, const char *valuestring); + +/* Macro for iterating over an array or object */ +#define cJSON_ArrayForEach(element, array) for(element = (array != NULL) ? (array)->child : NULL; element != NULL; element = element->next) + +/* malloc/free objects using the malloc/free functions that have been set with cJSON_InitHooks */ +CJSON_PUBLIC(void *) cJSON_malloc(size_t size); +CJSON_PUBLIC(void) cJSON_free(void *object); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/examples/pikapython/pikapython/pikascript-lib/pika_cjson/pika_cjson.c b/examples/pikapython/pikapython/pikascript-lib/pika_cjson/pika_cjson.c new file mode 100755 index 00000000..09f75906 --- /dev/null +++ b/examples/pikapython/pikapython/pikascript-lib/pika_cjson/pika_cjson.c @@ -0,0 +1,16 @@ +#include "pika_cjson.h" +#include "cJSON.h" +#include "pika_cjson_cJSON.h" + +PikaObj* pika_cjson_Parse(PikaObj* self, char* value) { + cJSON* item = cJSON_Parse(value); + if (NULL == item) { + // obj_setErrorCode(self, 3); + __platform_printf("Error: cJSON parse failed.\r\n"); + return NULL; + } + PikaObj* cjson_obj = newNormalObj(New_pika_cjson_cJSON); + obj_setPtr(cjson_obj, "item", item); + obj_setInt(cjson_obj, "needfree", 1); + return cjson_obj; +} diff --git a/examples/pikapython/pikapython/pikascript-lib/pika_cjson/pika_cjson_cJSON.c b/examples/pikapython/pikapython/pikascript-lib/pika_cjson/pika_cjson_cJSON.c new file mode 100755 index 00000000..3550347b --- /dev/null +++ b/examples/pikapython/pikapython/pikascript-lib/pika_cjson/pika_cjson_cJSON.c @@ -0,0 +1,235 @@ +#include "pika_cjson_cJSON.h" +#include "cJSON.h" + +char* pika_cjson_cJSON_print(PikaObj* self) { + cJSON* item = obj_getPtr(self, "item"); + char* res = cJSON_Print(item); + obj_setStr(self, "_buf", res); + cJSON_free(res); + return obj_getStr(self, "_buf"); +} + +void pika_cjson_cJSON___del__(PikaObj* self) { + cJSON* item = obj_getPtr(self, "item"); + if (obj_getInt(self, "needfree") == 1) { + cJSON_Delete(item); + } +} + +PikaObj* pika_cjson_cJSON_getObjectItem(PikaObj* self, char* string) { + cJSON* item = obj_getPtr(self, "item"); + cJSON* subItem = cJSON_GetObjectItem(item, string); + if (NULL == subItem) { + return NULL; + } + + /* create subCJSON */ + PikaObj* subCJSON = newNormalObj(New_pika_cjson_cJSON); + + /* init the subCJSON */ + obj_setPtr(subCJSON, "item", subItem); + obj_setInt(subCJSON, "needfree", 0); + + return subCJSON; +} + +void pika_cjson_cJSON___init__(PikaObj* self) { + /* const value */ + obj_setInt(self, "cJSON_Invalid", cJSON_Invalid); + obj_setInt(self, "cJSON_False", cJSON_False); + obj_setInt(self, "cJSON_True", cJSON_True); + obj_setInt(self, "cJSON_NULL", cJSON_NULL); + obj_setInt(self, "cJSON_Number", cJSON_Number); + obj_setInt(self, "cJSON_String", cJSON_String); + obj_setInt(self, "cJSON_Array", cJSON_Array); + obj_setInt(self, "cJSON_Object", cJSON_Object); + obj_setInt(self, "cJSON_Raw", cJSON_Raw); +} + +PikaObj* pika_cjson_cJSON_getChild(PikaObj* self) { + cJSON* item = obj_getPtr(self, "item"); + cJSON* resItem = item->child; + if (NULL == resItem) { + return NULL; + } + + /* create subCJSON */ + PikaObj* resCJSON = newNormalObj(New_pika_cjson_cJSON); + + /* init the subCJSON */ + obj_setPtr(resCJSON, "item", resItem); + obj_setInt(resCJSON, "needfree", 0); + + return resCJSON; +} + +PikaObj* pika_cjson_cJSON_getNext(PikaObj* self) { + cJSON* item = obj_getPtr(self, "item"); + cJSON* resItem = item->next; + if (NULL == resItem) { + return NULL; + } + + /* create subCJSON */ + PikaObj* resCJSON = newNormalObj(New_pika_cjson_cJSON); + + /* init the subCJSON */ + obj_setPtr(resCJSON, "item", resItem); + obj_setInt(resCJSON, "needfree", 0); + + return resCJSON; +} + +PikaObj* pika_cjson_cJSON_getPrev(PikaObj* self) { + cJSON* item = obj_getPtr(self, "item"); + cJSON* resItem = item->prev; + if (NULL == resItem) { + return NULL; + } + + /* create subCJSON */ + PikaObj* resCJSON = newNormalObj(New_pika_cjson_cJSON); + + /* init the subCJSON */ + obj_setPtr(resCJSON, "item", resItem); + obj_setInt(resCJSON, "needfree", 0); + + return resCJSON; +} + +char* pika_cjson_cJSON_getString(PikaObj* self) { + cJSON* item = obj_getPtr(self, "item"); + return item->string; +} + +int pika_cjson_cJSON_getType(PikaObj* self) { + cJSON* item = obj_getPtr(self, "item"); + return item->type; +} + +pika_float pika_cjson_cJSON_getValueDouble(PikaObj* self) { + cJSON* item = obj_getPtr(self, "item"); + return item->valuedouble; +} + +int pika_cjson_cJSON_getValueInt(PikaObj* self) { + cJSON* item = obj_getPtr(self, "item"); + return item->valueint; +} + +char* pika_cjson_cJSON_getValueString(PikaObj* self) { + cJSON* item = obj_getPtr(self, "item"); + return item->valuestring; +} + +Arg* pika_cjson_cJSON_getValue(PikaObj* self) { + cJSON* item = obj_getPtr(self, "item"); + int type = item->type; + if (type == cJSON_Invalid) { + return arg_newNull(); + } + if (type == cJSON_False) { + return arg_newInt(0); + } + if (type == cJSON_True) { + return arg_newInt(1); + } + if (type == cJSON_NULL) { + return arg_newNull(); + } + if (type == cJSON_Number) { + return arg_newFloat(item->valuedouble); + } + if (type == cJSON_String) { + return arg_newStr(item->valuestring); + } + return arg_newNull(); +} + +PikaObj* pika_cjson_cJSON_getArrayItem(PikaObj* self, int index) { + cJSON* item = obj_getPtr(self, "item"); + cJSON* subItem = cJSON_GetArrayItem(item, index); + if (NULL == subItem) { + return NULL; + } + + /* create subCJSON */ + PikaObj* subCJSON = newNormalObj(New_pika_cjson_cJSON); + + /* init the subCJSON */ + obj_setPtr(subCJSON, "item", subItem); + obj_setInt(subCJSON, "needfree", 0); + + return subCJSON; +} + +int pika_cjson_cJSON_getArraySize(PikaObj* self) { + cJSON* item = obj_getPtr(self, "item"); + return cJSON_GetArraySize(item); +} + +int pika_cjson_cJSON_isArray(PikaObj* self) { + cJSON* item = obj_getPtr(self, "item"); + return cJSON_IsArray(item); +} + +int pika_cjson_cJSON_isBool(PikaObj* self) { + cJSON* item = obj_getPtr(self, "item"); + return cJSON_IsBool(item); +} + +int pika_cjson_cJSON_isFalse(PikaObj* self) { + cJSON* item = obj_getPtr(self, "item"); + return cJSON_IsFalse(item); +} + +int pika_cjson_cJSON_isInvalid(PikaObj* self) { + cJSON* item = obj_getPtr(self, "item"); + return cJSON_IsInvalid(item); +} + +int pika_cjson_cJSON_isNull(PikaObj* self) { + cJSON* item = obj_getPtr(self, "item"); + return cJSON_IsNull(item); +} + +int pika_cjson_cJSON_isNumber(PikaObj* self) { + cJSON* item = obj_getPtr(self, "item"); + return cJSON_IsNumber(item); +} + +int pika_cjson_cJSON_isObject(PikaObj* self) { + cJSON* item = obj_getPtr(self, "item"); + return cJSON_IsObject(item); +} + +int pika_cjson_cJSON_isRaw(PikaObj* self) { + cJSON* item = obj_getPtr(self, "item"); + return cJSON_IsRaw(item); +} + +int pika_cjson_cJSON_isString(PikaObj* self) { + cJSON* item = obj_getPtr(self, "item"); + return cJSON_IsString(item); +} + +int pika_cjson_cJSON_isTrue(PikaObj* self) { + cJSON* item = obj_getPtr(self, "item"); + return cJSON_IsTrue(item); +} + +void pika_cjson_cJSON_addItemToArray(PikaObj* self, PikaObj* item) { + cJSON* self_item = obj_getPtr(self, "item"); + cJSON* item_item = obj_getPtr(item, "item"); + cJSON_AddItemToArray(self_item, item_item); + obj_setInt(item, "needfree", 0); +} + +void pika_cjson_cJSON_addItemToObject(PikaObj* self, + char* string, + PikaObj* item) { + cJSON* self_item = obj_getPtr(self, "item"); + cJSON* item_item = obj_getPtr(item, "item"); + cJSON_AddItemToObject(self_item, string, item_item); + obj_setInt(item, "needfree", 0); +} diff --git a/examples/pikapython/pikapython/pikascript-lib/pika_cjson/pika_cjson_item.c b/examples/pikapython/pikapython/pikascript-lib/pika_cjson/pika_cjson_item.c new file mode 100755 index 00000000..8c47fe59 --- /dev/null +++ b/examples/pikapython/pikapython/pikascript-lib/pika_cjson/pika_cjson_item.c @@ -0,0 +1,100 @@ +#include "cJSON.h" +#include "pika_cjson_Array.h" +#include "pika_cjson_ArrayReference.h" +#include "pika_cjson_Bool.h" +#include "pika_cjson_False_.h" +#include "pika_cjson_Null.h" +#include "pika_cjson_Number.h" +#include "pika_cjson_Object.h" +#include "pika_cjson_ObjectReference.h" +#include "pika_cjson_Raw.h" +#include "pika_cjson_String.h" +#include "pika_cjson_StringReference.h" +#include "pika_cjson_True_.h" +#include "pika_cjson_cJSON.h" + +void pika_cjson_False____init__(PikaObj* self) { + pika_cjson_cJSON___init__(self); + cJSON* item = cJSON_CreateFalse(); + obj_setPtr(self, "item", item); + obj_setInt(self, "needfree", 1); +} + +void pika_cjson_Null___init__(PikaObj* self) { + pika_cjson_cJSON___init__(self); + cJSON* item = cJSON_CreateNull(); + obj_setPtr(self, "item", item); + obj_setInt(self, "needfree", 1); +} + +void pika_cjson_True____init__(PikaObj* self) { + pika_cjson_cJSON___init__(self); + cJSON* item = cJSON_CreateTrue(); + obj_setPtr(self, "item", item); + obj_setInt(self, "needfree", 1); +} + +void pika_cjson_Bool___init__(PikaObj* self, int bolean) { + pika_cjson_cJSON___init__(self); + cJSON* item = cJSON_CreateBool(bolean); + obj_setPtr(self, "item", item); + obj_setInt(self, "needfree", 1); +} + +void pika_cjson_Number___init__(PikaObj* self, pika_float num) { + pika_cjson_cJSON___init__(self); + cJSON* item = cJSON_CreateNumber(num); + obj_setPtr(self, "item", item); + obj_setInt(self, "needfree", 1); +} + +void pika_cjson_String___init__(PikaObj* self, char* string) { + pika_cjson_cJSON___init__(self); + cJSON* item = cJSON_CreateString(string); + obj_setPtr(self, "item", item); + obj_setInt(self, "needfree", 1); +} + +void pika_cjson_Raw___init__(PikaObj* self, char* raw) { + pika_cjson_cJSON___init__(self); + cJSON* item = cJSON_CreateRaw(raw); + obj_setPtr(self, "item", item); + obj_setInt(self, "needfree", 1); +} + +void pika_cjson_Array___init__(PikaObj* self) { + pika_cjson_cJSON___init__(self); + cJSON* item = cJSON_CreateArray(); + obj_setPtr(self, "item", item); + obj_setInt(self, "needfree", 1); +} + +void pika_cjson_Object___init__(PikaObj* self) { + pika_cjson_cJSON___init__(self); + cJSON* item = cJSON_CreateObject(); + obj_setPtr(self, "item", item); + obj_setInt(self, "needfree", 1); +} + +void pika_cjson_StringReference___init__(PikaObj* self, char* string) { + pika_cjson_cJSON___init__(self); + cJSON* item = cJSON_CreateStringReference(string); + obj_setPtr(self, "item", item); + obj_setInt(self, "needfree", 1); +} + +void pika_cjson_ObjectReference___init__(PikaObj* self, PikaObj* child) { + pika_cjson_cJSON___init__(self); + cJSON* child_item = obj_getPtr(child, "item"); + cJSON* item = cJSON_CreateObjectReference(child_item); + obj_setPtr(self, "item", item); + obj_setInt(self, "needfree", 1); +} + +void pika_cjson_ArrayReference___init__(PikaObj* self, PikaObj* child) { + pika_cjson_cJSON___init__(self); + cJSON* child_item = obj_getPtr(child, "item"); + cJSON* item = cJSON_CreateArrayReference(child_item); + obj_setPtr(self, "item", item); + obj_setInt(self, "needfree", 1); +} diff --git a/examples/pikapython/pikapython/pikascript-lib/pika_lvgl/README.md b/examples/pikapython/pikapython/pikascript-lib/pika_lvgl/README.md new file mode 100755 index 00000000..bfbd2669 --- /dev/null +++ b/examples/pikapython/pikapython/pikascript-lib/pika_lvgl/README.md @@ -0,0 +1,9 @@ +# PikaPython LVGL package + +## Dependency + +- lvgl v8.3.1 + +## Global Macro + +- PIKASCRIPT=1 \ No newline at end of file diff --git a/examples/pikapython/pikapython/pikascript-lib/pika_lvgl/pika_lv_point_t.c b/examples/pikapython/pikapython/pikascript-lib/pika_lvgl/pika_lv_point_t.c new file mode 100755 index 00000000..7fe31cbe --- /dev/null +++ b/examples/pikapython/pikapython/pikascript-lib/pika_lvgl/pika_lv_point_t.c @@ -0,0 +1,16 @@ +#if defined(LV_LVGL_H_INCLUDE_SIMPLE) +#include "lvgl.h" +#else +#include "../../lvgl.h" +#endif + +#ifdef PIKASCRIPT + +#include "pika_lvgl_point_t.h" + +void pika_lvgl_point_t___init__(PikaObj* self) { + lv_point_t lv_point = {0}; + args_setStruct(self->list, "lv_point_struct", lv_point); + obj_setPtr(self, "lv_point", args_getStruct(self->list, "lv_point_struct")); +} +#endif diff --git a/examples/pikapython/pikapython/pikascript-lib/pika_lvgl/pika_lv_timer_t.c b/examples/pikapython/pikapython/pikascript-lib/pika_lvgl/pika_lv_timer_t.c new file mode 100755 index 00000000..88c1ce3f --- /dev/null +++ b/examples/pikapython/pikapython/pikascript-lib/pika_lvgl/pika_lv_timer_t.c @@ -0,0 +1,43 @@ +#if defined(LV_LVGL_H_INCLUDE_SIMPLE) +#include "lvgl.h" +#else +#include "../../lvgl.h" +#endif + +#ifdef PIKASCRIPT + +#include "pika_lvgl_lv_timer_t.h" + +PikaEventListener* g_pika_lv_timer_event_listener; +void __pika_timer_cb(lv_timer_t* timer) { + PikaObj* eventHandleObj = pks_eventLisener_getEventHandleObj( + g_pika_lv_timer_event_listener, (uint32_t)timer); + obj_newDirectObj(eventHandleObj, "timer", New_pika_lvgl_lv_timer_t); + obj_setPtr(obj_getPtr(eventHandleObj, "timer"), "lv_timer", timer); + obj_run(eventHandleObj, "eventCallBack(timer)"); +} + +void pika_lvgl_lv_timer_t_set_period(PikaObj* self, int period) { + lv_timer_t* lv_timer = obj_getPtr(self, "lv_timer"); + lv_timer_set_period(lv_timer, period); +} + +void pika_lvgl_lv_timer_t_set_cb(PikaObj* self, Arg* cb) { + lv_timer_t* lv_timer = obj_getPtr(self, "lv_timer"); + lv_timer_set_cb(lv_timer, __pika_timer_cb); + + obj_setArg(self, "eventCallBack", cb); + /* init event_listener for the first time */ + if (NULL == g_pika_lv_timer_event_listener) { + pks_eventLisener_init(&g_pika_lv_timer_event_listener); + } + pks_eventLicener_registEvent(g_pika_lv_timer_event_listener, + (uint32_t)lv_timer, self); + +} + +void pika_lvgl_lv_timer_t__del(PikaObj* self) { + lv_timer_t* lv_timer = obj_getPtr(self, "lv_timer"); + lv_timer_del(lv_timer); +} +#endif diff --git a/examples/pikapython/pikapython/pikascript-lib/pika_lvgl/pika_lv_wegit.c b/examples/pikapython/pikapython/pikascript-lib/pika_lvgl/pika_lv_wegit.c new file mode 100755 index 00000000..87b02aab --- /dev/null +++ b/examples/pikapython/pikapython/pikascript-lib/pika_lvgl/pika_lv_wegit.c @@ -0,0 +1,474 @@ +#if defined(LV_LVGL_H_INCLUDE_SIMPLE) +#include "lvgl.h" +#else +#include "../../lvgl.h" +#endif + +#ifdef PIKASCRIPT +#include "BaseObj.h" +#include "PikaStdData_Dict.h" +#include "pika_lvgl.h" +#include "pika_lvgl_arc.h" +#include "pika_lvgl_bar.h" +#include "pika_lvgl_btn.h" +#include "pika_lvgl_checkbox.h" +#include "pika_lvgl_dropdown.h" +#include "pika_lvgl_img.h" +#include "pika_lvgl_img_dsc_t.h" +#include "pika_lvgl_label.h" +#include "pika_lvgl_lv_obj.h" +#include "pika_lvgl_roller.h" +#include "pika_lvgl_slider.h" +#include "pika_lvgl_switch.h" +#include "pika_lvgl_table.h" +#include "pika_lvgl_textarea.h" + +void pika_lvgl_arc___init__(PikaObj* self, PikaObj* parent) { + lv_obj_t* lv_parent = obj_getPtr(parent, "lv_obj"); + lv_obj_t* lv_obj = lv_arc_create(lv_parent); + obj_setPtr(self, "lv_obj", lv_obj); + obj_setInt(self, "MODE_NORMAL", LV_ARC_MODE_NORMAL); + obj_setInt(self, "MODE_SYMMETRICAL", LV_ARC_MODE_SYMMETRICAL); + obj_setInt(self, "MODE_REVERSE", LV_ARC_MODE_REVERSE); +} + +void pika_lvgl_arc_set_end_angle(PikaObj* self, int angle) { + lv_obj_t* lv_obj = obj_getPtr(self, "lv_obj"); + lv_arc_set_end_angle(lv_obj, angle); +} + +void pika_lvgl_arc_set_bg_angles(PikaObj* self, int start, int end) { + lv_obj_t* lv_obj = obj_getPtr(self, "lv_obj"); + lv_arc_set_bg_angles(lv_obj, start, end); +} + +void pika_lvgl_arc_set_angles(PikaObj* self, int start, int end) { + lv_obj_t* lv_obj = obj_getPtr(self, "lv_obj"); + lv_arc_set_angles(lv_obj, start, end); +} + +int pika_lvgl_arc_get_angle_end(PikaObj* self) { + lv_obj_t* lv_obj = obj_getPtr(self, "lv_obj"); + return lv_arc_get_angle_end(lv_obj); +} +int pika_lvgl_arc_get_angle_start(PikaObj* self) { + lv_obj_t* lv_obj = obj_getPtr(self, "lv_obj"); + return lv_arc_get_angle_start(lv_obj); +} +int pika_lvgl_arc_get_bg_angle_end(PikaObj* self) { + lv_obj_t* lv_obj = obj_getPtr(self, "lv_obj"); + return lv_arc_get_bg_angle_end(lv_obj); +} +int pika_lvgl_arc_get_bg_angle_start(PikaObj* self) { + lv_obj_t* lv_obj = obj_getPtr(self, "lv_obj"); + return lv_arc_get_bg_angle_start(lv_obj); +} +int pika_lvgl_arc_get_max_value(PikaObj* self) { + lv_obj_t* lv_obj = obj_getPtr(self, "lv_obj"); + return lv_arc_get_max_value(lv_obj); +} +int pika_lvgl_arc_get_min_value(PikaObj* self) { + lv_obj_t* lv_obj = obj_getPtr(self, "lv_obj"); + return lv_arc_get_min_value(lv_obj); +} +int pika_lvgl_arc_get_mode(PikaObj* self) { + lv_obj_t* lv_obj = obj_getPtr(self, "lv_obj"); + return lv_arc_get_mode(lv_obj); +} +// int pika_lvgl_arc_get_rotation(PikaObj *self){ +// lv_obj_t* lv_obj = obj_getPtr(self, "lv_obj"); +// return lv_arc_get_rotation(lv_obj); +// } +int pika_lvgl_arc_get_value(PikaObj* self) { + lv_obj_t* lv_obj = obj_getPtr(self, "lv_obj"); + return lv_arc_get_value(lv_obj); +} +void pika_lvgl_arc_set_mode(PikaObj* self, int mode) { + lv_obj_t* lv_obj = obj_getPtr(self, "lv_obj"); + lv_arc_set_mode(lv_obj, mode); +} +void pika_lvgl_arc_set_range(PikaObj* self, int min, int max) { + lv_obj_t* lv_obj = obj_getPtr(self, "lv_obj"); + lv_arc_set_range(lv_obj, min, max); +} +void pika_lvgl_arc_set_rotation(PikaObj* self, int rotation) { + lv_obj_t* lv_obj = obj_getPtr(self, "lv_obj"); + lv_arc_set_rotation(lv_obj, rotation); +} +void pika_lvgl_arc_set_start_angle(PikaObj* self, int start) { + lv_obj_t* lv_obj = obj_getPtr(self, "lv_obj"); + lv_arc_set_start_angle(lv_obj, start); +} +void pika_lvgl_arc_set_value(PikaObj* self, int value) { + lv_obj_t* lv_obj = obj_getPtr(self, "lv_obj"); + lv_arc_set_value(lv_obj, value); +} +void pika_lvgl_arc_set_bg_end_angle(PikaObj* self, int angle) { + lv_obj_t* lv_obj = obj_getPtr(self, "lv_obj"); + lv_arc_set_bg_end_angle(lv_obj, angle); +} +void pika_lvgl_arc_set_bg_start_angle(PikaObj* self, int start) { + lv_obj_t* lv_obj = obj_getPtr(self, "lv_obj"); + lv_arc_set_bg_start_angle(lv_obj, start); +} + +void pika_lvgl_arc_set_change_rate(PikaObj* self, int rate) { + lv_obj_t* lv_obj = obj_getPtr(self, "lv_obj"); + lv_arc_set_change_rate(lv_obj, rate); +} + +void pika_lvgl_bar___init__(PikaObj* self, PikaObj* parent) { + lv_obj_t* lv_parent = obj_getPtr(parent, "lv_obj"); + lv_obj_t* lv_obj = lv_bar_create(lv_parent); + obj_setPtr(self, "lv_obj", lv_obj); +} + +void pika_lvgl_bar_set_value(PikaObj* self, int value, int anim) { + lv_obj_t* lv_obj = obj_getPtr(self, "lv_obj"); + lv_bar_set_value(lv_obj, value, anim); +} + +int pika_lvgl_bar_get_max_value(PikaObj* self) { + lv_obj_t* lv_obj = obj_getPtr(self, "lv_obj"); + return lv_bar_get_max_value(lv_obj); +} +int pika_lvgl_bar_get_min_value(PikaObj* self) { + lv_obj_t* lv_obj = obj_getPtr(self, "lv_obj"); + return lv_bar_get_min_value(lv_obj); +} +int pika_lvgl_bar_get_mode(PikaObj* self) { + lv_obj_t* lv_obj = obj_getPtr(self, "lv_obj"); + return lv_bar_get_mode(lv_obj); +} +int pika_lvgl_bar_get_start_value(PikaObj* self) { + lv_obj_t* lv_obj = obj_getPtr(self, "lv_obj"); + return lv_bar_get_start_value(lv_obj); +} +int pika_lvgl_bar_get_value(PikaObj* self) { + lv_obj_t* lv_obj = obj_getPtr(self, "lv_obj"); + return lv_bar_get_value(lv_obj); +} +void pika_lvgl_bar_set_mode(PikaObj* self, int mode) { + lv_obj_t* lv_obj = obj_getPtr(self, "lv_obj"); + lv_bar_set_mode(lv_obj, mode); +} +void pika_lvgl_bar_set_range(PikaObj* self, int min, int max) { + lv_obj_t* lv_obj = obj_getPtr(self, "lv_obj"); + lv_bar_set_range(lv_obj, min, max); +} +void pika_lvgl_bar_set_start_value(PikaObj* self, int start_value, int anim) { + lv_obj_t* lv_obj = obj_getPtr(self, "lv_obj"); + lv_bar_set_start_value(lv_obj, start_value, anim); +} + +void pika_lvgl_btn___init__(PikaObj* self, PikaObj* parent) { + lv_obj_t* lv_parent = obj_getPtr(parent, "lv_obj"); + lv_obj_t* lv_obj = lv_btn_create(lv_parent); + obj_setPtr(self, "lv_obj", lv_obj); +} + +void pika_lvgl_checkbox___init__(PikaObj* self, PikaObj* parent) { + lv_obj_t* lv_parent = obj_getPtr(parent, "lv_obj"); + lv_obj_t* lv_obj = lv_checkbox_create(lv_parent); + obj_setPtr(self, "lv_obj", lv_obj); +} + +void pika_lvgl_checkbox_set_text(PikaObj* self, char* txt) { + lv_obj_t* lv_obj = obj_getPtr(self, "lv_obj"); + lv_checkbox_set_text(lv_obj, txt); +} + +void pika_lvgl_checkbox_set_text_static(PikaObj* self, char* txt) { + lv_obj_t* lv_obj = obj_getPtr(self, "lv_obj"); + lv_checkbox_set_text_static(lv_obj, txt); +} + +char* pika_lvgl_checkbox_get_text(PikaObj* self) { + lv_obj_t* lv_obj = obj_getPtr(self, "lv_obj"); + return (char*)lv_checkbox_get_text(lv_obj); +} + +void pika_lvgl_dropdown___init__(PikaObj* self, PikaObj* parent) { + lv_obj_t* lv_parent = obj_getPtr(parent, "lv_obj"); + lv_obj_t* lv_obj = lv_dropdown_create(lv_parent); + obj_setPtr(self, "lv_obj", lv_obj); +} + +void pika_lvgl_dropdown_set_options(PikaObj* self, char* options) { + lv_obj_t* lv_obj = obj_getPtr(self, "lv_obj"); + lv_dropdown_set_options(lv_obj, options); +} + +void pika_lvgl_dropdown_add_option(PikaObj* self, char* options, int pos) { + lv_obj_t* lv_obj = obj_getPtr(self, "lv_obj"); + lv_dropdown_add_option(lv_obj, options, pos); +} +void pika_lvgl_dropdown_clear_options(PikaObj* self) { + lv_obj_t* lv_obj = obj_getPtr(self, "lv_obj"); + lv_dropdown_clear_options(lv_obj); +} +void pika_lvgl_dropdown_close(PikaObj* self) { + lv_obj_t* lv_obj = obj_getPtr(self, "lv_obj"); + lv_dropdown_close(lv_obj); +} +int pika_lvgl_dropdown_get_dir(PikaObj* self) { + lv_obj_t* lv_obj = obj_getPtr(self, "lv_obj"); + return lv_dropdown_get_dir(lv_obj); +} +// PikaObj* pika_lvgl_dropdown_get_list(PikaObj *self){ +// lv_obj_t* lv_obj = obj_getPtr(self, "lv_obj"); +// return obj_getObj(lv_dropdown_get_list(lv_obj)); +// } +int pika_lvgl_dropdown_get_option_cnt(PikaObj* self) { + lv_obj_t* lv_obj = obj_getPtr(self, "lv_obj"); + return lv_dropdown_get_option_cnt(lv_obj); +} +int pika_lvgl_dropdown_get_option_index(PikaObj* self, char* txt) { + lv_obj_t* lv_obj = obj_getPtr(self, "lv_obj"); + return lv_dropdown_get_option_index(lv_obj, txt); +} +char* pika_lvgl_dropdown_get_options(PikaObj* self) { + lv_obj_t* lv_obj = obj_getPtr(self, "lv_obj"); + return (char*)lv_dropdown_get_options(lv_obj); +} +int pika_lvgl_dropdown_get_selected(PikaObj* self) { + lv_obj_t* lv_obj = obj_getPtr(self, "lv_obj"); + return lv_dropdown_get_selected(lv_obj); +} +int pika_lvgl_dropdown_get_selected_highlight(PikaObj* self) { + lv_obj_t* lv_obj = obj_getPtr(self, "lv_obj"); + return lv_dropdown_get_selected_highlight(lv_obj); +} + +char* pika_lvgl_dropdown_get_selected_str(PikaObj* self) { + lv_obj_t* lv_obj = obj_getPtr(self, "lv_obj"); + obj_setBytes(self, "_buff", NULL, 128); + char* _buff = (char*)obj_getBytes(self, "_buff"); + lv_dropdown_get_selected_str(lv_obj, _buff, 128); + return _buff; +} +char* pika_lvgl_dropdown_get_symbol(PikaObj* self) { + lv_obj_t* lv_obj = obj_getPtr(self, "lv_obj"); + return (char*)lv_dropdown_get_symbol(lv_obj); +} +char* pika_lvgl_dropdown_get_text(PikaObj* self) { + lv_obj_t* lv_obj = obj_getPtr(self, "lv_obj"); + return (char*)lv_dropdown_get_text(lv_obj); +} +int pika_lvgl_dropdown_is_open(PikaObj* self) { + lv_obj_t* lv_obj = obj_getPtr(self, "lv_obj"); + return lv_dropdown_is_open(lv_obj); +} +void pika_lvgl_dropdown_open(PikaObj* self) { + lv_obj_t* lv_obj = obj_getPtr(self, "lv_obj"); + lv_dropdown_open(lv_obj); +} +void pika_lvgl_dropdown_set_dir(PikaObj* self, int dir) { + lv_obj_t* lv_obj = obj_getPtr(self, "lv_obj"); + lv_dropdown_set_dir(lv_obj, dir); +} +void pika_lvgl_dropdown_set_selected(PikaObj* self, int sel_opt) { + lv_obj_t* lv_obj = obj_getPtr(self, "lv_obj"); + lv_dropdown_set_selected(lv_obj, sel_opt); +} +void pika_lvgl_dropdown_set_selected_hightlight(PikaObj* self, int en) { + lv_obj_t* lv_obj = obj_getPtr(self, "lv_obj"); + lv_dropdown_set_selected_highlight(lv_obj, en); +} +void pika_lvgl_dropdown_set_symbol(PikaObj* self, char* symbol) { + lv_obj_t* lv_obj = obj_getPtr(self, "lv_obj"); + lv_dropdown_set_symbol(lv_obj, symbol); +} +void pika_lvgl_dropdown_set_text(PikaObj* self, char* txt) { + lv_obj_t* lv_obj = obj_getPtr(self, "lv_obj"); + lv_dropdown_set_text(lv_obj, txt); +} + +void pika_lvgl_label___init__(PikaObj* self, PikaObj* parent) { + lv_obj_t* lv_parent = obj_getPtr(parent, "lv_obj"); + lv_obj_t* lv_obj = lv_label_create(lv_parent); + obj_setPtr(self, "lv_obj", lv_obj); +} + +void pika_lvgl_label_set_long_mode(PikaObj* self, int mode) { + lv_obj_t* lv_obj = obj_getPtr(self, "lv_obj"); + lv_label_set_long_mode(lv_obj, mode); +} + +void pika_lvgl_label_set_recolor(PikaObj* self, int en) { + lv_obj_t* lv_obj = obj_getPtr(self, "lv_obj"); + lv_label_set_recolor(lv_obj, en); +} + +void pika_lvgl_label_set_text(PikaObj* self, char* txt) { + lv_obj_t* lv_obj = obj_getPtr(self, "lv_obj"); + lv_label_set_text(lv_obj, txt); +} + +void pika_lvgl_label_set_style_text_align(PikaObj* self, + int value, + int selector) { + lv_obj_t* lv_obj = obj_getPtr(self, "lv_obj"); + lv_obj_set_style_text_align(lv_obj, value, selector); +} + +void pika_lvgl_roller___init__(PikaObj* self, PikaObj* parent) { + lv_obj_t* lv_parent = obj_getPtr(parent, "lv_obj"); + lv_obj_t* lv_obj = lv_roller_create(lv_parent); + obj_setPtr(self, "lv_obj", lv_obj); +} + +void pika_lvgl_roller_set_options(PikaObj* self, char* options, int mode) { + lv_obj_t* lv_obj = obj_getPtr(self, "lv_obj"); + lv_roller_set_options(lv_obj, options, mode); +} + +void pika_lvgl_roller_set_visible_row_count(PikaObj* self, int row_cnt) { + lv_obj_t* lv_obj = obj_getPtr(self, "lv_obj"); + lv_roller_set_visible_row_count(lv_obj, row_cnt); +} + +void pika_lvgl_slider___init__(PikaObj* self, PikaObj* parent) { + lv_obj_t* lv_parent = obj_getPtr(parent, "lv_obj"); + lv_obj_t* lv_obj = lv_slider_create(lv_parent); + obj_setPtr(self, "lv_obj", lv_obj); +} + +void pika_lvgl_switch___init__(PikaObj* self, PikaObj* parent) { + lv_obj_t* lv_parent = obj_getPtr(parent, "lv_obj"); + lv_obj_t* lv_obj = lv_switch_create(lv_parent); + obj_setPtr(self, "lv_obj", lv_obj); +} + +void pika_lvgl_table___init__(PikaObj* self, PikaObj* parent) { + lv_obj_t* lv_parent = obj_getPtr(parent, "lv_obj"); + lv_obj_t* lv_obj = lv_table_create(lv_parent); + obj_setPtr(self, "lv_obj", lv_obj); +} + +void pika_lvgl_table_set_cell_value(PikaObj* self, + int row, + int col, + char* txt) { + lv_obj_t* lv_obj = obj_getPtr(self, "lv_obj"); + lv_table_set_cell_value(lv_obj, row, col, txt); +} + +void pika_lvgl_textarea___init__(PikaObj* self, PikaObj* parent) { + lv_obj_t* lv_parent = obj_getPtr(parent, "lv_obj"); + lv_obj_t* lv_obj = lv_textarea_create(lv_parent); + obj_setPtr(self, "lv_obj", lv_obj); +} + +void pika_lvgl_textarea_set_one_line(PikaObj* self, int en) { + lv_obj_t* lv_obj = obj_getPtr(self, "lv_obj"); + lv_textarea_set_one_line(lv_obj, en); +} + +void pika_lvgl_img___init__(PikaObj* self, PikaObj* parent) { + lv_obj_t* lv_parent = obj_getPtr(parent, "lv_obj"); + lv_obj_t* lv_obj = lv_img_create(lv_parent); + obj_setPtr(self, "lv_obj", lv_obj); +} + +int pika_lvgl_img_get_angle(PikaObj* self) { + lv_obj_t* lv_obj = obj_getPtr(self, "lv_obj"); + return lv_img_get_angle(lv_obj); +} + +int pika_lvgl_img_get_antialias(PikaObj* self) { + lv_obj_t* lv_obj = obj_getPtr(self, "lv_obj"); + return lv_img_get_antialias(lv_obj); +} + +int pika_lvgl_img_get_offset_x(PikaObj* self) { + lv_obj_t* lv_obj = obj_getPtr(self, "lv_obj"); + return lv_img_get_offset_x(lv_obj); +} + +int pika_lvgl_img_get_offset_y(PikaObj* self) { + lv_obj_t* lv_obj = obj_getPtr(self, "lv_obj"); + return lv_img_get_offset_y(lv_obj); +} + +int pika_lvgl_img_get_size_mode(PikaObj* self) { + lv_obj_t* lv_obj = obj_getPtr(self, "lv_obj"); + return lv_img_get_size_mode(lv_obj); +} + +int pika_lvgl_img_get_zoom(PikaObj* self) { + lv_obj_t* lv_obj = obj_getPtr(self, "lv_obj"); + return lv_img_get_zoom(lv_obj); +} + +void pika_lvgl_img_set_angle(PikaObj* self, int angle) { + lv_obj_t* lv_obj = obj_getPtr(self, "lv_obj"); + lv_img_set_angle(lv_obj, angle); +} + +void pika_lvgl_img_set_antialias(PikaObj* self, int antialias) { + lv_obj_t* lv_obj = obj_getPtr(self, "lv_obj"); + lv_img_set_antialias(lv_obj, antialias); +} + +void pika_lvgl_img_set_offset_x(PikaObj* self, int x) { + lv_obj_t* lv_obj = obj_getPtr(self, "lv_obj"); + lv_img_set_offset_x(lv_obj, x); +} + +void pika_lvgl_img_set_offset_y(PikaObj* self, int y) { + lv_obj_t* lv_obj = obj_getPtr(self, "lv_obj"); + lv_img_set_offset_y(lv_obj, y); +} + +void pika_lvgl_img_set_pivot(PikaObj* self, int x, int y) { + lv_obj_t* lv_obj = obj_getPtr(self, "lv_obj"); + lv_img_set_pivot(lv_obj, x, y); +} + +void pika_lvgl_img_set_size_mode(PikaObj* self, int mode) { + lv_obj_t* lv_obj = obj_getPtr(self, "lv_obj"); + lv_img_set_size_mode(lv_obj, mode); +} + +void pika_lvgl_img_dsc_t___init__(PikaObj* self, PikaObj* dsc_dict) { + obj_setRef(self, "dsc_dict", dsc_dict); + PikaDict* dsc_dict_ = obj_getPtr(dsc_dict, "dict"); + uint8_t* data = pikaDict_getBytes(dsc_dict_, "data"); + unsigned char wtmp[4] = {'0'}; + unsigned char htmp[4] = {'0'}; + memcpy(&wtmp, data + 16, 4); + memcpy(&htmp, data + 20, 4); + int w = ((int)(unsigned char)wtmp[2]) * 256 + (int)(unsigned char)wtmp[3]; + int h = ((int)(unsigned char)htmp[2]) * 256 + (int)(unsigned char)htmp[3]; + lv_img_dsc_t img_dsc = { + .data = data, + .data_size = pikaDict_getInt(dsc_dict_, "data_size"), + .header = + { + .always_zero = 0, + .cf = LV_IMG_CF_RAW_ALPHA, + .w = w, + .h = h, + }, + }; + obj_setStruct(self, "img_dsc", img_dsc); +} + +void pika_lvgl_img_set_src(PikaObj* self, PikaObj* src) { + obj_setRef(self, "src", src); + lv_obj_t* lv_obj = obj_getPtr(self, "lv_obj"); + lv_img_dsc_t* img_dsc = obj_getStruct(src, "img_dsc"); + lv_img_set_src(lv_obj, img_dsc); +} + +PikaObj* pika_lvgl_img_get_src(PikaObj* self) { + return obj_getPtr(self, "src"); +} + +void pika_lvgl_img_set_zoom(PikaObj* self, int zoom) { + lv_obj_t* lv_obj = obj_getPtr(self, "lv_obj"); + lv_img_set_zoom(lv_obj, zoom); +} + +#endif diff --git a/examples/pikapython/pikapython/pikascript-lib/pika_lvgl/pika_lvgl.c b/examples/pikapython/pikapython/pikascript-lib/pika_lvgl/pika_lvgl.c new file mode 100755 index 00000000..3e2617f0 --- /dev/null +++ b/examples/pikapython/pikapython/pikascript-lib/pika_lvgl/pika_lvgl.c @@ -0,0 +1,300 @@ +#if defined(LV_LVGL_H_INCLUDE_SIMPLE) +#include "lvgl.h" +#else +#include "../../lvgl.h" +#endif + +#ifdef PIKASCRIPT +#include "BaseObj.h" +#include "pika_lvgl.h" +#include "pika_lvgl_ALIGN.h" +#include "pika_lvgl_ANIM.h" +#include "pika_lvgl_EVENT.h" +#include "pika_lvgl_FLEX_ALIGN.h" +#include "pika_lvgl_FLEX_FLOW.h" +#include "pika_lvgl_LAYOUT_FLEX.h" +#include "pika_lvgl_SIZE.h" +#include "pika_lvgl_OPA.h" +#include "pika_lvgl_PALETTE.h" +#include "pika_lvgl_STATE.h" +#include "pika_lvgl_TEXT_DECOR.h" +#include "pika_lvgl_arc.h" +#include "pika_lvgl_flag_t.h" +#include "pika_lvgl_indev_t.h" +#include "pika_lvgl_lv_color_t.h" +#include "pika_lvgl_lv_obj.h" +#include "pika_lvgl_lv_timer_t.h" + +PikaObj* pika_lv_event_listener_g; +Args* pika_lv_id_register_g; + +#if !PIKASCRIPT_VERSION_REQUIRE_MINIMUN(1, 11, 7) +#error "pikascript version must be greater than 1.11.7" +#endif + +void pika_lvgl_STATE___init__(PikaObj* self) { + obj_setInt(self, "DEFAULT", LV_STATE_DEFAULT); + obj_setInt(self, "CHECKED", LV_STATE_CHECKED); + obj_setInt(self, "FOCUSED", LV_STATE_FOCUSED); + obj_setInt(self, "FOCUS_KEY", LV_STATE_FOCUS_KEY); + obj_setInt(self, "EDITED", LV_STATE_EDITED); + obj_setInt(self, "HOVERED", LV_STATE_HOVERED); + obj_setInt(self, "PRESSED", LV_STATE_PRESSED); + obj_setInt(self, "SCROLLED", LV_STATE_SCROLLED); + obj_setInt(self, "DISABLED", LV_STATE_DISABLED); + obj_setInt(self, "USER_1", LV_STATE_USER_1); + obj_setInt(self, "USER_2", LV_STATE_USER_2); + obj_setInt(self, "USER_3", LV_STATE_USER_3); + obj_setInt(self, "USER_4", LV_STATE_USER_4); + obj_setInt(self, "ANY", LV_STATE_ANY); +} + +void pika_lvgl_flag_t___init__(PikaObj* self) { + obj_setInt(self, "HIDDEN", LV_OBJ_FLAG_HIDDEN); + obj_setInt(self, "CLICKABLE", LV_OBJ_FLAG_CLICKABLE); + obj_setInt(self, "CLICK_FOCUSABLE", LV_OBJ_FLAG_CLICK_FOCUSABLE); + obj_setInt(self, "CHECKABLE", LV_OBJ_FLAG_CHECKABLE); + obj_setInt(self, "SCROLLABLE", LV_OBJ_FLAG_SCROLLABLE); + obj_setInt(self, "SCROLL_ELASTIC", LV_OBJ_FLAG_SCROLL_ELASTIC); + obj_setInt(self, "SCROLL_MOMENTUM", LV_OBJ_FLAG_SCROLL_MOMENTUM); + obj_setInt(self, "SCROLL_ONE", LV_OBJ_FLAG_SCROLL_ONE); + obj_setInt(self, "SCROLL_CHAIN_HOR", LV_OBJ_FLAG_SCROLL_CHAIN_HOR); + obj_setInt(self, "SCROLL_CHAIN_VER", LV_OBJ_FLAG_SCROLL_CHAIN_VER); + obj_setInt(self, "SCROLL_CHAIN", LV_OBJ_FLAG_SCROLL_CHAIN); + obj_setInt(self, "SCROLL_ON_FOCUS", LV_OBJ_FLAG_SCROLL_ON_FOCUS); + obj_setInt(self, "SCROLL_WITH_ARROW", LV_OBJ_FLAG_SCROLL_WITH_ARROW); + obj_setInt(self, "SNAPPABLE", LV_OBJ_FLAG_SNAPPABLE); + obj_setInt(self, "PRESS_LOCK", LV_OBJ_FLAG_PRESS_LOCK); + obj_setInt(self, "EVENT_BUBBLE", LV_OBJ_FLAG_EVENT_BUBBLE); + obj_setInt(self, "GESTURE_BUBBLE", LV_OBJ_FLAG_GESTURE_BUBBLE); + obj_setInt(self, "ADV_HITTEST", LV_OBJ_FLAG_ADV_HITTEST); + obj_setInt(self, "IGNORE_LAYOUT", LV_OBJ_FLAG_IGNORE_LAYOUT); + obj_setInt(self, "FLOATING", LV_OBJ_FLAG_FLOATING); + obj_setInt(self, "OVERFLOW_VISIBLE", LV_OBJ_FLAG_OVERFLOW_VISIBLE); + obj_setInt(self, "LAYOUT_1", LV_OBJ_FLAG_LAYOUT_1); + obj_setInt(self, "LAYOUT_2", LV_OBJ_FLAG_LAYOUT_2); + obj_setInt(self, "WIDGET_1", LV_OBJ_FLAG_WIDGET_1); + obj_setInt(self, "WIDGET_2", LV_OBJ_FLAG_WIDGET_2); + obj_setInt(self, "USER_1", LV_OBJ_FLAG_USER_1); + obj_setInt(self, "USER_2", LV_OBJ_FLAG_USER_2); + obj_setInt(self, "USER_3", LV_OBJ_FLAG_USER_3); + obj_setInt(self, "USER_4", LV_OBJ_FLAG_USER_4); +} + +void pika_lvgl_TEXT_DECOR___init__(PikaObj* self) { + obj_setInt(self, "NONE", LV_TEXT_DECOR_NONE); + obj_setInt(self, "UNDERLINE", LV_TEXT_DECOR_UNDERLINE); + obj_setInt(self, "STRIKETHROUGH", LV_TEXT_DECOR_STRIKETHROUGH); +} + +void pika_lvgl_ANIM___init__(PikaObj* self) { + obj_setInt(self, "ON", LV_ANIM_ON); + obj_setInt(self, "OFF", LV_ANIM_OFF); +} + +void pika_lvgl_ALIGN___init__(PikaObj* self) { + obj_setInt(self, "CENTER", LV_ALIGN_CENTER); + obj_setInt(self, "DEFAULT", LV_ALIGN_DEFAULT); + obj_setInt(self, "TOP_LEFT", LV_ALIGN_TOP_LEFT); + obj_setInt(self, "TOP_MID", LV_ALIGN_TOP_MID); + obj_setInt(self, "TOP_RIGHT", LV_ALIGN_TOP_RIGHT); + obj_setInt(self, "BOTTOM_LEFT", LV_ALIGN_BOTTOM_LEFT); + obj_setInt(self, "BOTTOM_MID", LV_ALIGN_BOTTOM_MID); + obj_setInt(self, "BOTTOM_RIGHT", LV_ALIGN_BOTTOM_RIGHT); + obj_setInt(self, "LEFT_MID", LV_ALIGN_LEFT_MID); + obj_setInt(self, "RIGHT_MID", LV_ALIGN_RIGHT_MID); + obj_setInt(self, "OUT_TOP_LEFT", LV_ALIGN_OUT_TOP_LEFT); + obj_setInt(self, "OUT_TOP_MID", LV_ALIGN_OUT_TOP_MID); + obj_setInt(self, "OUT_TOP_RIGHT", LV_ALIGN_OUT_TOP_RIGHT); + obj_setInt(self, "OUT_BOTTOM_LEFT", LV_ALIGN_OUT_BOTTOM_LEFT); + obj_setInt(self, "OUT_BOTTOM_MID", LV_ALIGN_OUT_BOTTOM_MID); + obj_setInt(self, "OUT_BOTTOM_RIGHT", LV_ALIGN_OUT_BOTTOM_RIGHT); + obj_setInt(self, "OUT_LEFT_TOP", LV_ALIGN_OUT_LEFT_TOP); + obj_setInt(self, "OUT_LEFT_MID", LV_ALIGN_OUT_LEFT_MID); + obj_setInt(self, "OUT_LEFT_BOTTOM", LV_ALIGN_OUT_LEFT_BOTTOM); + obj_setInt(self, "OUT_RIGHT_TOP", LV_ALIGN_OUT_RIGHT_TOP); + obj_setInt(self, "OUT_RIGHT_MID", LV_ALIGN_OUT_RIGHT_MID); + obj_setInt(self, "OUT_RIGHT_BOTTOM", LV_ALIGN_OUT_RIGHT_BOTTOM); +} + +void pika_lvgl_EVENT___init__(PikaObj* self) { + obj_setInt(self, "ALL", LV_EVENT_ALL); + obj_setInt(self, "PRESSED", LV_EVENT_PRESSED); + obj_setInt(self, "PRESSING", LV_EVENT_PRESSING); + obj_setInt(self, "PRESS_LOST", LV_EVENT_PRESS_LOST); + obj_setInt(self, "SHORT_CLICKED", LV_EVENT_SHORT_CLICKED); + obj_setInt(self, "LONG_PRESSED", LV_EVENT_LONG_PRESSED); + obj_setInt(self, "LONG_PRESSED_REPEAT", LV_EVENT_LONG_PRESSED_REPEAT); + obj_setInt(self, "CLICKED", LV_EVENT_CLICKED); + obj_setInt(self, "RELEASED", LV_EVENT_RELEASED); + obj_setInt(self, "SCROLL_BEGIN", LV_EVENT_SCROLL_BEGIN); + obj_setInt(self, "SCROLL_END", LV_EVENT_SCROLL_END); + obj_setInt(self, "SCROLL", LV_EVENT_SCROLL); + obj_setInt(self, "GESTURE", LV_EVENT_GESTURE); + obj_setInt(self, "KEY", LV_EVENT_KEY); + obj_setInt(self, "FOCUSED", LV_EVENT_FOCUSED); + obj_setInt(self, "DEFOCUSED", LV_EVENT_DEFOCUSED); + obj_setInt(self, "LEAVE", LV_EVENT_LEAVE); + obj_setInt(self, "HIT_TEST", LV_EVENT_HIT_TEST); + obj_setInt(self, "COVER_CHECK", LV_EVENT_COVER_CHECK); + obj_setInt(self, "REFR_EXT_DRAW_SIZE", LV_EVENT_REFR_EXT_DRAW_SIZE); + obj_setInt(self, "DRAW_MAIN_BEGIN", LV_EVENT_DRAW_MAIN_BEGIN); + obj_setInt(self, "DRAW_MAIN", LV_EVENT_DRAW_MAIN); + obj_setInt(self, "DRAW_MAIN_END", LV_EVENT_DRAW_MAIN_END); + obj_setInt(self, "DRAW_POST_BEGIN", LV_EVENT_DRAW_POST_BEGIN); + obj_setInt(self, "DRAW_POST", LV_EVENT_DRAW_POST); + obj_setInt(self, "DRAW_POST_END", LV_EVENT_DRAW_POST_END); + obj_setInt(self, "DRAW_PART_BEGIN", LV_EVENT_DRAW_PART_BEGIN); + obj_setInt(self, "DRAW_PART_END", LV_EVENT_DRAW_PART_END); + obj_setInt(self, "VALUE_CHANGED", LV_EVENT_VALUE_CHANGED); + obj_setInt(self, "INSERT", LV_EVENT_INSERT); + obj_setInt(self, "REFRESH", LV_EVENT_REFRESH); + obj_setInt(self, "READY", LV_EVENT_READY); + obj_setInt(self, "CANCEL", LV_EVENT_CANCEL); + obj_setInt(self, "DELETE", LV_EVENT_DELETE); + obj_setInt(self, "CHILD_CHANGED", LV_EVENT_CHILD_CHANGED); + obj_setInt(self, "CHILD_CREATED", LV_EVENT_CHILD_CREATED); + obj_setInt(self, "CHILD_DELETED", LV_EVENT_CHILD_DELETED); + obj_setInt(self, "SCREEN_UNLOAD_START", LV_EVENT_SCREEN_UNLOAD_START); + obj_setInt(self, "SCREEN_LOAD_START", LV_EVENT_SCREEN_LOAD_START); + obj_setInt(self, "SCREEN_LOADED", LV_EVENT_SCREEN_LOADED); + obj_setInt(self, "SCREEN_UNLOADED", LV_EVENT_SCREEN_UNLOADED); + obj_setInt(self, "SIZE_CHANGED", LV_EVENT_SIZE_CHANGED); + obj_setInt(self, "STYLE_CHANGED", LV_EVENT_STYLE_CHANGED); + obj_setInt(self, "LAYOUT_CHANGED", LV_EVENT_LAYOUT_CHANGED); + obj_setInt(self, "GET_SELF_SIZE", LV_EVENT_GET_SELF_SIZE); + obj_setInt(self, "PREPROCESS", LV_EVENT_PREPROCESS); +} + +void pika_lvgl_OPA___init__(PikaObj* self) { + obj_setInt(self, "TRANSP", LV_OPA_TRANSP); + obj_setInt(self, "COVER", LV_OPA_COVER); +} + +void pika_lvgl_PALETTE___init__(PikaObj* self) { + obj_setInt(self, "RED", LV_PALETTE_RED); + obj_setInt(self, "PINK", LV_PALETTE_PINK); + obj_setInt(self, "PURPLE", LV_PALETTE_PURPLE); + obj_setInt(self, "DEEP_PURPLE", LV_PALETTE_DEEP_PURPLE); + obj_setInt(self, "INDIGO", LV_PALETTE_INDIGO); + obj_setInt(self, "BLUE", LV_PALETTE_BLUE); + obj_setInt(self, "LIGHT_BLUE", LV_PALETTE_LIGHT_BLUE); + obj_setInt(self, "CYAN", LV_PALETTE_CYAN); + obj_setInt(self, "TEAL", LV_PALETTE_TEAL); + obj_setInt(self, "GREEN", LV_PALETTE_GREEN); + obj_setInt(self, "LIGHT_GREEN", LV_PALETTE_LIGHT_GREEN); + obj_setInt(self, "LIME", LV_PALETTE_LIME); + obj_setInt(self, "YELLOW", LV_PALETTE_YELLOW); + obj_setInt(self, "AMBER", LV_PALETTE_AMBER); + obj_setInt(self, "ORANGE", LV_PALETTE_ORANGE); + obj_setInt(self, "DEEP_ORANGE", LV_PALETTE_DEEP_ORANGE); + obj_setInt(self, "BROWN", LV_PALETTE_BROWN); + obj_setInt(self, "BLUE_GREY", LV_PALETTE_BLUE_GREY); + obj_setInt(self, "GREY", LV_PALETTE_GREY); + obj_setInt(self, "NONE", LV_PALETTE_NONE); +} + +PikaObj* pika_lvgl_scr_act(PikaObj* self) { + PikaObj* new_obj = newNormalObj(New_pika_lvgl_lv_obj); + lv_obj_t* lv_obj = lv_scr_act(); + obj_setPtr(new_obj, "lv_obj", lv_obj); + return new_obj; +} + +void pika_lvgl___init__(PikaObj* self) { + obj_newDirectObj(self, "lv_event_listener", New_TinyObj); + pika_lv_event_listener_g = obj_getObj(self, "lv_event_listener"); + pika_lv_id_register_g = New_args(NULL); + lv_png_init(); +} + +void pika_lvgl_obj___init__(PikaObj* self, PikaTuple* parent) { + PikaObj* parent_obj = NULL; + if (NULL == parent) { + void pika_lvgl_flag_tMethod(PikaObj * self, Args * args); + class_defineConstructor(self, "FLAG", "", pika_lvgl_flag_tMethod); + return; + } + if (pikaTuple_getSize(parent) == 1) { + parent_obj = pikaTuple_getPtr(parent, 0); + lv_obj_t* lv_parent = obj_getPtr(parent_obj, "lv_obj"); + lv_obj_t* lv_obj = lv_obj_create(lv_parent); + obj_setPtr(self, "lv_obj", lv_obj); + return; + } +} + +PikaObj* pika_lvgl_palette_lighten(PikaObj* self, int p, int lvl) { + PikaObj* new_obj = newNormalObj(New_pika_lvgl_lv_color_t); + lv_color_t lv_color = lv_palette_lighten(p, lvl); + args_setStruct(new_obj->list, "lv_color_struct", lv_color); + lv_color_t* plv_color = args_getStruct(new_obj->list, "lv_color_struct"); + obj_setPtr(new_obj, "lv_color", plv_color); + return new_obj; +} + +PikaObj* pika_lvgl_lv_color_hex(PikaObj* self, int64_t hex) { + PikaObj* new_obj = newNormalObj(New_pika_lvgl_lv_color_t); + lv_color_t lv_color = lv_color_hex(hex); + args_setStruct(new_obj->list, "lv_color_struct", lv_color); + lv_color_t* plv_color = args_getStruct(new_obj->list, "lv_color_struct"); + obj_setPtr(new_obj, "lv_color", plv_color); + return new_obj; +} + +PikaObj* pika_lvgl_palette_main(PikaObj* self, int p) { + PikaObj* new_obj = newNormalObj(New_pika_lvgl_lv_color_t); + lv_color_t lv_color = lv_palette_main(p); + args_setStruct(new_obj->list, "lv_color_struct", lv_color); + obj_setPtr(new_obj, "lv_color", + args_getStruct(new_obj->list, "lv_color_struct")); + return new_obj; +} + +PikaObj* pika_lvgl_indev_get_act(PikaObj* self) { + PikaObj* new_obj = newNormalObj(New_pika_lvgl_indev_t); + lv_indev_t* lv_indev = lv_indev_get_act(); + obj_setPtr(new_obj, "lv_indev", lv_indev); + return new_obj; +} + +PikaObj* pika_lvgl_timer_create_basic(PikaObj* self) { + PikaObj* new_obj = newNormalObj(New_pika_lvgl_lv_timer_t); + lv_timer_t* lv_timer = lv_timer_create_basic(); + obj_setPtr(new_obj, "lv_timer", lv_timer); + return new_obj; +} + +void pika_lvgl_FLEX_FLOW___init__(PikaObj* self) { + obj_setInt(self, "ROW", LV_FLEX_FLOW_ROW); + obj_setInt(self, "COLUMN", LV_FLEX_FLOW_COLUMN); + obj_setInt(self, "ROW_WRAP", LV_FLEX_FLOW_ROW_WRAP); + obj_setInt(self, "ROW_REVERSE", LV_FLEX_FLOW_ROW_REVERSE); + obj_setInt(self, "ROW_WRAP_REVERSE", LV_FLEX_FLOW_ROW_WRAP_REVERSE); + obj_setInt(self, "COLUMN_WRAP", LV_FLEX_FLOW_COLUMN_WRAP); + obj_setInt(self, "COLUMN_REVERSE", LV_FLEX_FLOW_COLUMN_REVERSE); + obj_setInt(self, "COLUMN_WRAP_REVERSE", LV_FLEX_FLOW_COLUMN_WRAP_REVERSE); +} + +void pika_lvgl_FLEX_ALIGN___init__(PikaObj* self) { + obj_setInt(self, "START", LV_FLEX_ALIGN_START); + obj_setInt(self, "END", LV_FLEX_ALIGN_END); + obj_setInt(self, "CENTER", LV_FLEX_ALIGN_CENTER); + obj_setInt(self, "SPACE_EVENLY", LV_FLEX_ALIGN_SPACE_EVENLY); + obj_setInt(self, "SPACE_AROUND", LV_FLEX_ALIGN_SPACE_AROUND); + obj_setInt(self, "SPACE_BETWEEN", LV_FLEX_ALIGN_SPACE_BETWEEN); +} + +void pika_lvgl_LAYOUT_FLEX___init__(PikaObj* self) { + obj_setInt(self, "value", LV_LAYOUT_FLEX); +} + +void pika_lvgl_SIZE___init__(PikaObj *self){ + obj_setInt(self, "CONTENT", LV_SIZE_CONTENT); +} + +int pika_lvgl_pct(PikaObj *self, int x){ + return LV_PCT(x); +} + +#endif diff --git a/examples/pikapython/pikapython/pikascript-lib/pika_lvgl/pika_lvgl_indev_t.c b/examples/pikapython/pikapython/pikascript-lib/pika_lvgl/pika_lvgl_indev_t.c new file mode 100755 index 00000000..591ee8a6 --- /dev/null +++ b/examples/pikapython/pikapython/pikascript-lib/pika_lvgl/pika_lvgl_indev_t.c @@ -0,0 +1,18 @@ +#if defined(LV_LVGL_H_INCLUDE_SIMPLE) +#include "lvgl.h" +#else +#include "../../lvgl.h" +#endif + +#ifdef PIKASCRIPT + +#include "pika_lvgl_indev_t.h" + +void pika_lvgl_indev_t_get_vect(PikaObj* self, PikaObj* point) { + lv_indev_t* lv_indev = obj_getPtr(self, "lv_indev"); + lv_point_t* lv_point = obj_getPtr(point, "lv_point"); + lv_indev_get_vect(lv_indev, lv_point); + obj_setInt(point, "x", lv_point->x); + obj_setInt(point, "y", lv_point->y); +} +#endif diff --git a/examples/pikapython/pikapython/pikascript-lib/pika_lvgl/pika_lvgl_lv_event.c b/examples/pikapython/pikapython/pikascript-lib/pika_lvgl/pika_lvgl_lv_event.c new file mode 100755 index 00000000..575cf164 --- /dev/null +++ b/examples/pikapython/pikapython/pikascript-lib/pika_lvgl/pika_lvgl_lv_event.c @@ -0,0 +1,24 @@ +#if defined(LV_LVGL_H_INCLUDE_SIMPLE) +#include "lvgl.h" +#else +#include "../../lvgl.h" +#endif + +#ifdef PIKASCRIPT + +#include "pika_lvgl_lv_event.h" + +int pika_lvgl_lv_event_get_code(PikaObj *self){ + lv_event_t *lv_event = obj_getPtr(self, "lv_event"); + return lv_event_get_code(lv_event); +} + +PikaObj *New_pika_lvgl_lv_obj(Args *args); +PikaObj* pika_lvgl_lv_event_get_target(PikaObj *self){ + lv_event_t *lv_event = obj_getPtr(self, "lv_event"); + lv_obj_t* lv_obj = lv_event_get_target(lv_event); + PikaObj* new_obj = newNormalObj(New_pika_lvgl_lv_obj); + obj_setPtr(new_obj, "lv_obj", lv_obj); + return new_obj; +} +#endif diff --git a/examples/pikapython/pikapython/pikascript-lib/pika_lvgl/pika_lvgl_lv_obj.c b/examples/pikapython/pikapython/pikascript-lib/pika_lvgl/pika_lvgl_lv_obj.c new file mode 100755 index 00000000..5be0460a --- /dev/null +++ b/examples/pikapython/pikapython/pikascript-lib/pika_lvgl/pika_lvgl_lv_obj.c @@ -0,0 +1,336 @@ +#if defined(LV_LVGL_H_INCLUDE_SIMPLE) +#include "lvgl.h" +#else +#include "../../lvgl.h" +#endif + +#ifdef PIKASCRIPT + +#include "BaseObj.h" +#include "dataStrs.h" +#include "pika_lvgl.h" +#include "pika_lvgl_arc.h" +#include "pika_lvgl_lv_event.h" +#include "pika_lvgl_lv_obj.h" + +extern PikaObj* pika_lv_event_listener_g; + +void pika_lvgl_lv_obj___init__(PikaObj* self, PikaObj* parent) { + lv_obj_t* lv_parent = obj_getPtr(parent, "lv_obj"); + lv_obj_t* lv_obj = lv_obj_create(lv_parent); + obj_setPtr(self, "lv_obj", lv_obj); +} + +void pika_lvgl_lv_obj_center(PikaObj* self) { + lv_obj_t* lv_obj = obj_getPtr(self, "lv_obj"); + lv_obj_center(lv_obj); +} + +void pika_lvgl_lv_obj_set_size(PikaObj* self, int w, int h) { + lv_obj_t* lv_obj = obj_getPtr(self, "lv_obj"); + lv_obj_set_size(lv_obj, w, h); +} + +void pika_lvgl_lv_obj_align(PikaObj* self, int align, int x_ofs, int y_ofs) { + lv_obj_t* lv_obj = obj_getPtr(self, "lv_obj"); + lv_obj_align(lv_obj, align, x_ofs, y_ofs); +} + +void pika_lvgl_lv_obj_set_height(PikaObj* self, int h) { + lv_obj_t* lv_obj = obj_getPtr(self, "lv_obj"); + lv_obj_set_height(lv_obj, h); +} + +void pika_lvgl_lv_obj_update_layout(PikaObj* self) { + lv_obj_t* lv_obj = obj_getPtr(self, "lv_obj"); + lv_obj_update_layout(lv_obj); +} + +void pika_lvgl_lv_obj_set_width(PikaObj* self, int w) { + lv_obj_t* lv_obj = obj_getPtr(self, "lv_obj"); + lv_obj_set_width(lv_obj, w); +} + +void pika_lvgl_lv_obj_add_state(PikaObj* self, int state) { + lv_obj_t* lv_obj = obj_getPtr(self, "lv_obj"); + lv_obj_add_state(lv_obj, state); +} + +PikaObj* eventLisener_getHandler(PikaObj* self, uintptr_t event_id) { + Args buffs = {0}; + char* event_name = + strsFormat(&buffs, PIKA_SPRINTF_BUFF_SIZE, "%d", event_id); + PikaObj* event_item = obj_getObj(self, event_name); + PikaObj* event_handler = obj_getPtr(event_item, "handler"); + strsDeinit(&buffs); + return event_handler; +} + +static void __pika_event_cb(lv_event_t* e) { + lv_obj_t* target = lv_event_get_target(e); + PikaObj* event_handler = + eventLisener_getHandler(pika_lv_event_listener_g, (uintptr_t)target); + PikaObj* evt = obj_getObj(event_handler, "_event_evt"); + obj_setPtr(evt, "lv_event", e); + obj_run(event_handler, "_event_cb(_event_evt)"); +} + +void eventLicener_registEvent(PikaObj* self, + uintptr_t event_id, + PikaObj* event_handler) { + Args buffs = {0}; + char* event_name = + strsFormat(&buffs, PIKA_SPRINTF_BUFF_SIZE, "%d", event_id); + obj_newDirectObj(self, event_name, New_TinyObj); + PikaObj* event_item = obj_getObj(self, event_name); + obj_setRef(event_item, "handler", event_handler); + strsDeinit(&buffs); +} + +void pika_lvgl_lv_obj_add_event_cb(PikaObj* self, + Arg* event_cb, + int filter, + void* user_data) { + lv_obj_t* lv_obj = obj_getPtr(self, "lv_obj"); + lv_obj_add_event_cb(lv_obj, __pika_event_cb, filter, NULL); + obj_setArg(self, "_event_cb", event_cb); + obj_setPtr(self, "_event_user_data", user_data); + obj_newDirectObj(self, "_event_evt", New_pika_lvgl_lv_event); + eventLicener_registEvent(pika_lv_event_listener_g, (uintptr_t)lv_obj, self); +} + +void pika_lvgl_lv_obj_add_style(PikaObj* self, PikaObj* style, int selector) { + lv_obj_t* lv_obj = obj_getPtr(self, "lv_obj"); + lv_style_t* lv_style = obj_getPtr(style, "lv_style"); + lv_obj_add_style(lv_obj, lv_style, selector); + char sytle_ref_name[] = "_stylex"; + sytle_ref_name[sizeof(sytle_ref_name) - 2] = '0' + lv_obj->style_cnt; + obj_setRef(self, sytle_ref_name, style); +} + +int pika_lvgl_lv_obj_get_x(PikaObj* self) { + lv_obj_t* lv_obj = obj_getPtr(self, "lv_obj"); + return lv_obj_get_x(lv_obj); +} + +int pika_lvgl_lv_obj_get_y(PikaObj* self) { + lv_obj_t* lv_obj = obj_getPtr(self, "lv_obj"); + return lv_obj_get_y(lv_obj); +} + +void pika_lvgl_lv_obj_set_pos(PikaObj* self, int x, int y) { + lv_obj_t* lv_obj = obj_getPtr(self, "lv_obj"); + lv_obj_set_pos(lv_obj, x, y); +} + +void pika_lvgl_lv_obj_align_to(PikaObj* self, + PikaObj* base, + int align, + int x_ofs, + int y_ofs) { + lv_obj_t* lv_obj = obj_getPtr(self, "lv_obj"); + lv_obj_t* lv_base = obj_getPtr(base, "lv_obj"); + lv_obj_align_to(lv_obj, lv_base, align, x_ofs, y_ofs); +} + +int pika_lvgl_lv_obj_get_content_height(PikaObj* self) { + lv_obj_t* lv_obj = obj_getPtr(self, "lv_obj"); + return lv_obj_get_content_height(lv_obj); +} + +int pika_lvgl_lv_obj_get_content_width(PikaObj* self) { + lv_obj_t* lv_obj = obj_getPtr(self, "lv_obj"); + return lv_obj_get_content_width(lv_obj); +} + +int pika_lvgl_lv_obj_get_height(PikaObj* self) { + lv_obj_t* lv_obj = obj_getPtr(self, "lv_obj"); + return lv_obj_get_height(lv_obj); +} + +int pika_lvgl_lv_obj_get_self_height(PikaObj* self) { + lv_obj_t* lv_obj = obj_getPtr(self, "lv_obj"); + return lv_obj_get_self_height(lv_obj); +} + +int pika_lvgl_lv_obj_get_self_width(PikaObj* self) { + lv_obj_t* lv_obj = obj_getPtr(self, "lv_obj"); + return lv_obj_get_self_width(lv_obj); +} + +int pika_lvgl_lv_obj_get_width(PikaObj* self) { + lv_obj_t* lv_obj = obj_getPtr(self, "lv_obj"); + return lv_obj_get_width(lv_obj); +} + +int pika_lvgl_lv_obj_get_x2(PikaObj* self) { + lv_obj_t* lv_obj = obj_getPtr(self, "lv_obj"); + return lv_obj_get_x2(lv_obj); +} + +int pika_lvgl_lv_obj_get_x_aligned(PikaObj* self) { + lv_obj_t* lv_obj = obj_getPtr(self, "lv_obj"); + return lv_obj_get_x_aligned(lv_obj); +} + +int pika_lvgl_lv_obj_get_y2(PikaObj* self) { + lv_obj_t* lv_obj = obj_getPtr(self, "lv_obj"); + return lv_obj_get_y2(lv_obj); +} + +int pika_lvgl_lv_obj_get_y_aligned(PikaObj* self) { + lv_obj_t* lv_obj = obj_getPtr(self, "lv_obj"); + return lv_obj_get_y_aligned(lv_obj); +} + +int pika_lvgl_lv_obj_hit_test(PikaObj* self, PikaObj* point) { + lv_obj_t* lv_obj = obj_getPtr(self, "lv_obj"); + lv_point_t* lv_point = obj_getPtr(point, "lv_point"); + return lv_obj_hit_test(lv_obj, lv_point); +} + +void pika_lvgl_lv_obj_invalidate(PikaObj* self) { + lv_obj_t* lv_obj = obj_getPtr(self, "lv_obj"); + lv_obj_invalidate(lv_obj); +} + +int pika_lvgl_lv_obj_is_layout_positioned(PikaObj* self) { + lv_obj_t* lv_obj = obj_getPtr(self, "lv_obj"); + return lv_obj_is_layout_positioned(lv_obj); +} + +int pika_lvgl_lv_obj_is_visible(PikaObj* self) { + lv_obj_t* lv_obj = obj_getPtr(self, "lv_obj"); + return lv_obj_is_visible(lv_obj); +} + +void pika_lvgl_lv_obj_mark_layout_as_dirty(PikaObj* self) { + lv_obj_t* lv_obj = obj_getPtr(self, "lv_obj"); + lv_obj_mark_layout_as_dirty(lv_obj); +} + +void pika_lvgl_lv_obj_move_to(PikaObj* self, int x, int y) { + lv_obj_t* lv_obj = obj_getPtr(self, "lv_obj"); + lv_obj_move_to(lv_obj, x, y); +} + +void pika_lvgl_lv_obj_move_children_by(PikaObj* self, + int x_diff, + int y_diff, + int ignore_floating) { + lv_obj_t* lv_obj = obj_getPtr(self, "lv_obj"); + lv_obj_move_children_by(lv_obj, x_diff, y_diff, ignore_floating); +} + +void pika_lvgl_lv_obj_refr_pos(PikaObj* self) { + lv_obj_t* lv_obj = obj_getPtr(self, "lv_obj"); + lv_obj_refr_pos(lv_obj); +} + +int pika_lvgl_lv_obj_refr_size(PikaObj* self) { + lv_obj_t* lv_obj = obj_getPtr(self, "lv_obj"); + return lv_obj_refr_size(lv_obj); +} + +int pika_lvgl_lv_obj_refresh_self_size(PikaObj* self) { + lv_obj_t* lv_obj = obj_getPtr(self, "lv_obj"); + return lv_obj_refresh_self_size(lv_obj); +} + +void pika_lvgl_lv_obj_set_align(PikaObj* self, int align) { + lv_obj_t* lv_obj = obj_getPtr(self, "lv_obj"); + lv_obj_set_align(lv_obj, align); +} + +void pika_lvgl_lv_obj_set_content_height(PikaObj* self, int h) { + lv_obj_t* lv_obj = obj_getPtr(self, "lv_obj"); + lv_obj_set_content_height(lv_obj, h); +} + +void pika_lvgl_lv_obj_set_content_width(PikaObj* self, int w) { + lv_obj_t* lv_obj = obj_getPtr(self, "lv_obj"); + lv_obj_set_content_width(lv_obj, w); +} + +void pika_lvgl_lv_obj_set_ext_click_area(PikaObj* self, int size) { + lv_obj_t* lv_obj = obj_getPtr(self, "lv_obj"); + lv_obj_set_ext_click_area(lv_obj, size); +} + +void pika_lvgl_lv_obj_set_layout(PikaObj* self, int layout) { + lv_obj_t* lv_obj = obj_getPtr(self, "lv_obj"); + lv_obj_set_layout(lv_obj, layout); +} + +void pika_lvgl_lv_obj_set_x(PikaObj* self, int x) { + lv_obj_t* lv_obj = obj_getPtr(self, "lv_obj"); + lv_obj_set_x(lv_obj, x); +} + +void pika_lvgl_lv_obj_set_y(PikaObj* self, int y) { + lv_obj_t* lv_obj = obj_getPtr(self, "lv_obj"); + lv_obj_set_y(lv_obj, y); +} + +void pika_lvgl_lv_obj_transform_point(PikaObj* self, + PikaObj* p, + int recursive, + int inv) { + lv_obj_t* lv_obj = obj_getPtr(self, "lv_obj"); + lv_point_t* lv_point = obj_getPtr(p, "lv_point"); + lv_obj_transform_point(lv_obj, lv_point, recursive, inv); +} + +void pika_lvgl_lv_obj_add_flag(PikaObj* self, int flag) { + lv_obj_t* lv_obj = obj_getPtr(self, "lv_obj"); + lv_obj_add_flag(lv_obj, flag); +} + +void pika_lvgl_lv_obj_clear_flag(PikaObj* self, int flag) { + lv_obj_t* lv_obj = obj_getPtr(self, "lv_obj"); + lv_obj_clear_flag(lv_obj, flag); +} + +void pika_lvgl_lv_obj_set_flex_align(PikaObj* self, + int main_place, + int cross_place, + int align) { + lv_obj_t* lv_obj = obj_getPtr(self, "lv_obj"); + lv_obj_set_flex_align(lv_obj, main_place, cross_place, align); +} + +void pika_lvgl_lv_obj_set_flex_flow(PikaObj* self, int flow) { + lv_obj_t* lv_obj = obj_getPtr(self, "lv_obj"); + lv_obj_set_flex_flow(lv_obj, flow); +} + +extern Args* pika_lv_id_register_g; +void pika_lvgl_lv_obj_set_id(PikaObj* self, char* id) { + lv_obj_t* lv_obj = obj_getPtr(self, "lv_obj"); + uintptr_t id_key = (uintptr_t)lv_obj; + Arg* id_arg = arg_newStr(id); + id_arg->name_hash = (Hash)id_key; + args_setArg(pika_lv_id_register_g, id_arg); +} + +char* pika_lvgl_lv_obj_get_id(PikaObj* self) { + lv_obj_t* lv_obj = obj_getPtr(self, "lv_obj"); + uintptr_t id_key = (uintptr_t)lv_obj; + Arg* id_arg = args_getArg_hash(pika_lv_id_register_g, (Hash)id_key); + if (NULL == id_arg) { + return NULL; + } + return arg_getStr(id_arg); +} + +void pika_lvgl_lv_obj_set_flex_grow(PikaObj *self, int value){ + lv_obj_t* lv_obj = obj_getPtr(self, "lv_obj"); + lv_obj_set_flex_grow(lv_obj, value); +} + +void pika_lvgl_lv_obj_clean(PikaObj *self){ + lv_obj_t* lv_obj = obj_getPtr(self, "lv_obj"); + lv_obj_clean(lv_obj); +} + +#endif diff --git a/examples/pikapython/pikapython/pikascript-lib/pika_lvgl/pika_lvgl_lv_style_t.c b/examples/pikapython/pikapython/pikascript-lib/pika_lvgl/pika_lvgl_lv_style_t.c new file mode 100755 index 00000000..54feaf3f --- /dev/null +++ b/examples/pikapython/pikapython/pikascript-lib/pika_lvgl/pika_lvgl_lv_style_t.c @@ -0,0 +1,500 @@ +#if defined(LV_LVGL_H_INCLUDE_SIMPLE) +#include "lvgl.h" +#else +#include "../../lvgl.h" +#endif + +#ifdef PIKASCRIPT + +#include "pika_lvgl_style_t.h" + +void pika_lvgl_style_t_init(PikaObj* self) { + lv_style_t* lv_style = obj_getPtr(self, "lv_style"); + lv_style_init(lv_style); +} + +void pika_lvgl_style_t___init__(PikaObj* self) { + lv_style_t lv_style_stack = {0}; + args_setStruct(self->list, "lv_style_struct", lv_style_stack); + lv_style_t* lv_style = args_getStruct(self->list, "lv_style_struct"); + obj_setPtr(self, "lv_style", lv_style); +} + +void pika_lvgl_style_t_set_align(PikaObj* self, int value) { + lv_style_t* lv_style = obj_getPtr(self, "lv_style"); + lv_style_set_align(lv_style, value); +} + +void pika_lvgl_style_t_set_anim_speed(PikaObj* self, int value) { + lv_style_t* lv_style = obj_getPtr(self, "lv_style"); + lv_style_set_anim_speed(lv_style, value); +} + +void pika_lvgl_style_t_set_anim_time(PikaObj* self, int value) { + lv_style_t* lv_style = obj_getPtr(self, "lv_style"); + lv_style_set_anim_time(lv_style, value); +} + +void pika_lvgl_style_t_set_arc_color(PikaObj* self, PikaObj* value) { + lv_style_t* lv_style = obj_getPtr(self, "lv_style"); + lv_color_t* lv_color = obj_getPtr(value, "lv_color"); + lv_style_set_arc_color(lv_style, *lv_color); +} + +void pika_lvgl_style_t_set_arc_img_src(PikaObj* self, uint8_t* value) { + lv_style_t* lv_style = obj_getPtr(self, "lv_style"); + lv_style_set_arc_img_src(lv_style, value); +} + +void pika_lvgl_style_t_set_arc_opa(PikaObj* self, int value) { + lv_style_t* lv_style = obj_getPtr(self, "lv_style"); + lv_style_set_arc_opa(lv_style, value); +} + +void pika_lvgl_style_t_set_arc_rounded(PikaObj* self, int value) { + lv_style_t* lv_style = obj_getPtr(self, "lv_style"); + lv_style_set_arc_rounded(lv_style, value); +} + +void pika_lvgl_style_t_set_arc_width(PikaObj* self, int value) { + lv_style_t* lv_style = obj_getPtr(self, "lv_style"); + lv_style_set_arc_width(lv_style, value); +} + +void pika_lvgl_style_t_set_base_dir(PikaObj* self, int value) { + lv_style_t* lv_style = obj_getPtr(self, "lv_style"); + lv_style_set_base_dir(lv_style, value); +} + +void pika_lvgl_style_t_set_bg_color(PikaObj* self, PikaObj* value) { + lv_style_t* lv_style = obj_getPtr(self, "lv_style"); + lv_color_t* lv_color = obj_getPtr(value, "lv_color"); + lv_style_set_bg_color(lv_style, *lv_color); +} + +void pika_lvgl_style_t_set_bg_dither_mode(PikaObj* self, int value) { + lv_style_t* lv_style = obj_getPtr(self, "lv_style"); + lv_style_set_bg_dither_mode(lv_style, value); +} + +void pika_lvgl_style_t_set_bg_grad_color(PikaObj* self, PikaObj* value) { + lv_style_t* lv_style = obj_getPtr(self, "lv_style"); + lv_color_t* lv_color = obj_getPtr(value, "lv_color"); + lv_style_set_bg_grad_color(lv_style, *lv_color); +} + +void pika_lvgl_style_t_set_bg_grad_dir(PikaObj* self, int value) { + lv_style_t* lv_style = obj_getPtr(self, "lv_style"); + lv_style_set_bg_grad_dir(lv_style, value); +} + +void pika_lvgl_style_t_set_bg_grad_stop(PikaObj* self, int value) { + lv_style_t* lv_style = obj_getPtr(self, "lv_style"); + lv_style_set_bg_grad_stop(lv_style, value); +} + +void pika_lvgl_style_t_set_bg_img_opa(PikaObj* self, int value) { + lv_style_t* lv_style = obj_getPtr(self, "lv_style"); + lv_style_set_bg_img_opa(lv_style, value); +} + +void pika_lvgl_style_t_set_bg_img_recolor(PikaObj* self, PikaObj* value) { + lv_style_t* lv_style = obj_getPtr(self, "lv_style"); + lv_color_t* lv_color = obj_getPtr(value, "lv_color"); + lv_style_set_bg_img_recolor(lv_style, *lv_color); +} + +void pika_lvgl_style_t_set_bg_img_recolor_opa(PikaObj* self, int value) { + lv_style_t* lv_style = obj_getPtr(self, "lv_style"); + lv_style_set_bg_img_recolor_opa(lv_style, value); +} + +void pika_lvgl_style_t_set_bg_img_src(PikaObj* self, uint8_t* value) { + lv_style_t* lv_style = obj_getPtr(self, "lv_style"); + lv_style_set_bg_img_src(lv_style, value); +} + +void pika_lvgl_style_t_set_bg_img_tiled(PikaObj* self, int value) { + lv_style_t* lv_style = obj_getPtr(self, "lv_style"); + lv_style_set_bg_img_tiled(lv_style, value); +} + +void pika_lvgl_style_t_set_bg_main_stop(PikaObj* self, int value) { + lv_style_t* lv_style = obj_getPtr(self, "lv_style"); + lv_style_set_bg_main_stop(lv_style, value); +} + +void pika_lvgl_style_t_set_bg_opa(PikaObj* self, int value) { + lv_style_t* lv_style = obj_getPtr(self, "lv_style"); + lv_style_set_bg_opa(lv_style, value); +} + +void pika_lvgl_style_t_set_blend_mode(PikaObj* self, int value) { + lv_style_t* lv_style = obj_getPtr(self, "lv_style"); + lv_style_set_blend_mode(lv_style, value); +} + +void pika_lvgl_style_t_set_border_color(PikaObj* self, PikaObj* value) { + lv_style_t* lv_style = obj_getPtr(self, "lv_style"); + lv_color_t* lv_color = obj_getPtr(value, "lv_color"); + lv_style_set_border_color(lv_style, *lv_color); +} + +void pika_lvgl_style_t_set_border_opa(PikaObj* self, int value) { + lv_style_t* lv_style = obj_getPtr(self, "lv_style"); + lv_style_set_border_opa(lv_style, value); +} + +void pika_lvgl_style_t_set_border_post(PikaObj* self, int value) { + lv_style_t* lv_style = obj_getPtr(self, "lv_style"); + lv_style_set_border_post(lv_style, value); +} + +void pika_lvgl_style_t_set_border_side(PikaObj* self, int value) { + lv_style_t* lv_style = obj_getPtr(self, "lv_style"); + lv_style_set_border_side(lv_style, value); +} + +void pika_lvgl_style_t_set_border_width(PikaObj* self, int value) { + lv_style_t* lv_style = obj_getPtr(self, "lv_style"); + lv_style_set_border_width(lv_style, value); +} + +void pika_lvgl_style_t_set_clip_corner(PikaObj* self, int value) { + lv_style_t* lv_style = obj_getPtr(self, "lv_style"); + lv_style_set_clip_corner(lv_style, value); +} + +void pika_lvgl_style_t_set_color_filter_opa(PikaObj* self, int value) { + lv_style_t* lv_style = obj_getPtr(self, "lv_style"); + lv_style_set_color_filter_opa(lv_style, value); +} + +void pika_lvgl_style_t_set_height(PikaObj* self, int value) { + lv_style_t* lv_style = obj_getPtr(self, "lv_style"); + lv_style_set_height(lv_style, value); +} + +void pika_lvgl_style_t_set_img_opa(PikaObj* self, int value) { + lv_style_t* lv_style = obj_getPtr(self, "lv_style"); + lv_style_set_img_opa(lv_style, value); +} + +void pika_lvgl_style_t_set_img_recolor(PikaObj* self, PikaObj* value) { + lv_style_t* lv_style = obj_getPtr(self, "lv_style"); + lv_color_t* lv_color = obj_getPtr(value, "lv_color"); + lv_style_set_img_recolor(lv_style, *lv_color); +} + +void pika_lvgl_style_t_set_img_recolor_opa(PikaObj* self, int value) { + lv_style_t* lv_style = obj_getPtr(self, "lv_style"); + lv_style_set_img_recolor_opa(lv_style, value); +} + +void pika_lvgl_style_t_set_layout(PikaObj* self, int value) { + lv_style_t* lv_style = obj_getPtr(self, "lv_style"); + lv_style_set_layout(lv_style, value); +} + +void pika_lvgl_style_t_set_line_color(PikaObj* self, PikaObj* value) { + lv_style_t* lv_style = obj_getPtr(self, "lv_style"); + lv_color_t* lv_color = obj_getPtr(value, "lv_color"); + lv_style_set_line_color(lv_style, *lv_color); +} + +void pika_lvgl_style_t_set_line_dash_gap(PikaObj* self, int value) { + lv_style_t* lv_style = obj_getPtr(self, "lv_style"); + lv_style_set_line_dash_gap(lv_style, value); +} + +void pika_lvgl_style_t_set_line_dash_width(PikaObj* self, int value) { + lv_style_t* lv_style = obj_getPtr(self, "lv_style"); + lv_style_set_line_dash_width(lv_style, value); +} + +void pika_lvgl_style_t_set_line_opa(PikaObj* self, int value) { + lv_style_t* lv_style = obj_getPtr(self, "lv_style"); + lv_style_set_line_opa(lv_style, value); +} + +void pika_lvgl_style_t_set_line_rounded(PikaObj* self, int value) { + lv_style_t* lv_style = obj_getPtr(self, "lv_style"); + lv_style_set_line_rounded(lv_style, value); +} + +void pika_lvgl_style_t_set_line_width(PikaObj* self, int value) { + lv_style_t* lv_style = obj_getPtr(self, "lv_style"); + lv_style_set_line_width(lv_style, value); +} + +void pika_lvgl_style_t_set_max_height(PikaObj* self, int value) { + lv_style_t* lv_style = obj_getPtr(self, "lv_style"); + lv_style_set_max_height(lv_style, value); +} + +void pika_lvgl_style_t_set_max_width(PikaObj* self, int value) { + lv_style_t* lv_style = obj_getPtr(self, "lv_style"); + lv_style_set_max_width(lv_style, value); +} + +void pika_lvgl_style_t_set_min_height(PikaObj* self, int value) { + lv_style_t* lv_style = obj_getPtr(self, "lv_style"); + lv_style_set_min_height(lv_style, value); +} + +void pika_lvgl_style_t_set_min_width(PikaObj* self, int value) { + lv_style_t* lv_style = obj_getPtr(self, "lv_style"); + lv_style_set_min_width(lv_style, value); +} + +void pika_lvgl_style_t_set_opa(PikaObj* self, int value) { + lv_style_t* lv_style = obj_getPtr(self, "lv_style"); + lv_style_set_opa(lv_style, value); +} + +void pika_lvgl_style_t_set_outline_color(PikaObj* self, PikaObj* value) { + lv_style_t* lv_style = obj_getPtr(self, "lv_style"); + lv_color_t* lv_color = obj_getPtr(value, "lv_color"); + lv_style_set_outline_color(lv_style, *lv_color); +} + +void pika_lvgl_style_t_set_outline_opa(PikaObj* self, int value) { + lv_style_t* lv_style = obj_getPtr(self, "lv_style"); + lv_style_set_outline_opa(lv_style, value); +} + +void pika_lvgl_style_t_set_outline_pad(PikaObj* self, int value) { + lv_style_t* lv_style = obj_getPtr(self, "lv_style"); + lv_style_set_outline_pad(lv_style, value); +} + +void pika_lvgl_style_t_set_outline_width(PikaObj* self, int value) { + lv_style_t* lv_style = obj_getPtr(self, "lv_style"); + lv_style_set_outline_width(lv_style, value); +} + +void pika_lvgl_style_t_set_pad_bottom(PikaObj* self, int value) { + lv_style_t* lv_style = obj_getPtr(self, "lv_style"); + lv_style_set_pad_bottom(lv_style, value); +} + +void pika_lvgl_style_t_set_pad_column(PikaObj* self, int value) { + lv_style_t* lv_style = obj_getPtr(self, "lv_style"); + lv_style_set_pad_column(lv_style, value); +} + +void pika_lvgl_style_t_set_pad_left(PikaObj* self, int value) { + lv_style_t* lv_style = obj_getPtr(self, "lv_style"); + lv_style_set_pad_left(lv_style, value); +} + +void pika_lvgl_style_t_set_pad_right(PikaObj* self, int value) { + lv_style_t* lv_style = obj_getPtr(self, "lv_style"); + lv_style_set_pad_right(lv_style, value); +} + +void pika_lvgl_style_t_set_pad_row(PikaObj* self, int value) { + lv_style_t* lv_style = obj_getPtr(self, "lv_style"); + lv_style_set_pad_row(lv_style, value); +} + +void pika_lvgl_style_t_set_pad_top(PikaObj* self, int value) { + lv_style_t* lv_style = obj_getPtr(self, "lv_style"); + lv_style_set_pad_top(lv_style, value); +} + +void pika_lvgl_style_t_set_radius(PikaObj* self, int value) { + lv_style_t* lv_style = obj_getPtr(self, "lv_style"); + lv_style_set_radius(lv_style, value); +} + +void pika_lvgl_style_t_set_shadow_color(PikaObj* self, PikaObj* value) { + lv_style_t* lv_style = obj_getPtr(self, "lv_style"); + lv_color_t* lv_color = obj_getPtr(value, "lv_color"); + lv_style_set_shadow_color(lv_style, *lv_color); +} + +void pika_lvgl_style_t_set_shadow_ofs_x(PikaObj* self, int value) { + lv_style_t* lv_style = obj_getPtr(self, "lv_style"); + lv_style_set_shadow_ofs_x(lv_style, value); +} + +void pika_lvgl_style_t_set_shadow_ofs_y(PikaObj* self, int value) { + lv_style_t* lv_style = obj_getPtr(self, "lv_style"); + lv_style_set_shadow_ofs_y(lv_style, value); +} + +void pika_lvgl_style_t_set_shadow_opa(PikaObj* self, int value) { + lv_style_t* lv_style = obj_getPtr(self, "lv_style"); + lv_style_set_shadow_opa(lv_style, value); +} + +void pika_lvgl_style_t_set_shadow_spread(PikaObj* self, int value) { + lv_style_t* lv_style = obj_getPtr(self, "lv_style"); + lv_style_set_shadow_spread(lv_style, value); +} + +void pika_lvgl_style_t_set_shadow_width(PikaObj* self, int value) { + lv_style_t* lv_style = obj_getPtr(self, "lv_style"); + lv_style_set_shadow_width(lv_style, value); +} + +void pika_lvgl_style_t_set_text_align(PikaObj* self, int value) { + lv_style_t* lv_style = obj_getPtr(self, "lv_style"); + lv_style_set_text_align(lv_style, value); +} + +void pika_lvgl_style_t_set_text_color(PikaObj* self, PikaObj* value) { + lv_style_t* lv_style = obj_getPtr(self, "lv_style"); + lv_color_t* lv_color = obj_getPtr(value, "lv_color"); + lv_style_set_text_color(lv_style, *lv_color); +} + +void pika_lvgl_style_t_set_text_decor(PikaObj* self, int value) { + lv_style_t* lv_style = obj_getPtr(self, "lv_style"); + lv_style_set_text_decor(lv_style, value); +} + +void pika_lvgl_style_t_set_text_letter_space(PikaObj* self, int value) { + lv_style_t* lv_style = obj_getPtr(self, "lv_style"); + lv_style_set_text_letter_space(lv_style, value); +} + +void pika_lvgl_style_t_set_text_line_space(PikaObj* self, int value) { + lv_style_t* lv_style = obj_getPtr(self, "lv_style"); + lv_style_set_text_line_space(lv_style, value); +} + +void pika_lvgl_style_t_set_text_opa(PikaObj* self, int value) { + lv_style_t* lv_style = obj_getPtr(self, "lv_style"); + lv_style_set_text_opa(lv_style, value); +} + +void pika_lvgl_style_t_set_transform_angle(PikaObj* self, int value) { + lv_style_t* lv_style = obj_getPtr(self, "lv_style"); + lv_style_set_transform_angle(lv_style, value); +} + +void pika_lvgl_style_t_set_transform_height(PikaObj* self, int value) { + lv_style_t* lv_style = obj_getPtr(self, "lv_style"); + lv_style_set_transform_height(lv_style, value); +} + +void pika_lvgl_style_t_set_transform_pivot_x(PikaObj* self, int value) { + lv_style_t* lv_style = obj_getPtr(self, "lv_style"); + lv_style_set_transform_pivot_x(lv_style, value); +} + +void pika_lvgl_style_t_set_transform_pivot_y(PikaObj* self, int value) { + lv_style_t* lv_style = obj_getPtr(self, "lv_style"); + lv_style_set_transform_pivot_y(lv_style, value); +} + +void pika_lvgl_style_t_set_transform_width(PikaObj* self, int value) { + lv_style_t* lv_style = obj_getPtr(self, "lv_style"); + lv_style_set_transform_width(lv_style, value); +} + +void pika_lvgl_style_t_set_transform_zoom(PikaObj* self, int value) { + lv_style_t* lv_style = obj_getPtr(self, "lv_style"); + lv_style_set_transform_zoom(lv_style, value); +} + +void pika_lvgl_style_t_set_translate_x(PikaObj* self, int value) { + lv_style_t* lv_style = obj_getPtr(self, "lv_style"); + lv_style_set_translate_x(lv_style, value); +} + +void pika_lvgl_style_t_set_translate_y(PikaObj* self, int value) { + lv_style_t* lv_style = obj_getPtr(self, "lv_style"); + lv_style_set_translate_y(lv_style, value); +} + +void pika_lvgl_style_t_set_width(PikaObj* self, int value) { + lv_style_t* lv_style = obj_getPtr(self, "lv_style"); + lv_style_set_width(lv_style, value); +} + +void pika_lvgl_style_t_set_x(PikaObj* self, int value) { + lv_style_t* lv_style = obj_getPtr(self, "lv_style"); + lv_style_set_x(lv_style, value); +} + +void pika_lvgl_style_t_set_y(PikaObj* self, int value) { + lv_style_t* lv_style = obj_getPtr(self, "lv_style"); + lv_style_set_y(lv_style, value); +} + +int pika_lvgl_style_t_get_num_custom_props(PikaObj* self) { + return lv_style_get_num_custom_props(); +} + +int pika_lvgl_style_t_prop_has_flag(PikaObj* self, int prop, int flag) { + return lv_style_prop_has_flag(prop, flag); +} +int pika_lvgl_style_t_is_empty(PikaObj* self) { + lv_style_t* lv_style = obj_getPtr(self, "lv_style"); + return lv_style_is_empty(lv_style); +} +int pika_lvgl_style_t_register_prop(PikaObj* self, int flag) { + return lv_style_register_prop(flag); +} +int pika_lvgl_style_t_remove_prop(PikaObj* self, int prop) { + lv_style_t* lv_style = obj_getPtr(self, "lv_style"); + return lv_style_remove_prop(lv_style, prop); +} +void pika_lvgl_style_t_reset(PikaObj* self) { + lv_style_t* lv_style = obj_getPtr(self, "lv_style"); + lv_style_reset(lv_style); +} +void pika_lvgl_style_t_set_pad_all(PikaObj* self, int value) { + lv_style_t* lv_style = obj_getPtr(self, "lv_style"); + lv_style_set_pad_all(lv_style, value); +} +void pika_lvgl_style_t_set_pad_gap(PikaObj* self, int value) { + lv_style_t* lv_style = obj_getPtr(self, "lv_style"); + lv_style_set_pad_gap(lv_style, value); +} +void pika_lvgl_style_t_set_pad_hor(PikaObj* self, int value) { + lv_style_t* lv_style = obj_getPtr(self, "lv_style"); + lv_style_set_pad_hor(lv_style, value); +} +void pika_lvgl_style_t_set_pad_ver(PikaObj* self, int value) { + lv_style_t* lv_style = obj_getPtr(self, "lv_style"); + lv_style_set_pad_ver(lv_style, value); +} +// void pika_lvgl_style_t_set_prop_meta(PikaObj* self, int prop, int meta) { +// lv_style_t* lv_style = obj_getPtr(self, "lv_style"); +// lv_style_set_prop_meta(lv_style, prop, meta); +//} +void pika_lvgl_style_t_set_size(PikaObj* self, int value) { + lv_style_t* lv_style = obj_getPtr(self, "lv_style"); + lv_style_set_size(lv_style, value); +} + +void pika_lvgl_style_t_set_flex_cross_place(PikaObj* self, int value) { + lv_style_t* lv_style = obj_getPtr(self, "lv_style"); + lv_style_set_flex_cross_place(lv_style, value); +} + +void pika_lvgl_style_t_set_flex_flow(PikaObj* self, int value) { + lv_style_t* lv_style = obj_getPtr(self, "lv_style"); + lv_style_set_flex_flow(lv_style, value); +} + +void pika_lvgl_style_t_set_flex_grow(PikaObj* self, int value) { + lv_style_t* lv_style = obj_getPtr(self, "lv_style"); + lv_style_set_flex_grow(lv_style, value); +} + +void pika_lvgl_style_t_set_flex_main_place(PikaObj* self, int value) { + lv_style_t* lv_style = obj_getPtr(self, "lv_style"); + lv_style_set_flex_main_place(lv_style, value); +} + +void pika_lvgl_style_t_set_flex_track_place(PikaObj* self, int value) { + lv_style_t* lv_style = obj_getPtr(self, "lv_style"); + lv_style_set_flex_track_place(lv_style, value); +} + +#endif diff --git a/examples/pikapython/pikapython/pikascript-lib/random/random.c b/examples/pikapython/pikapython/pikascript-lib/random/random.c new file mode 100755 index 00000000..65286518 --- /dev/null +++ b/examples/pikapython/pikapython/pikascript-lib/random/random.c @@ -0,0 +1,33 @@ +#include "random.h" +#include +#include + +void random___init__(PikaObj *self){ + srand(pika_platform_getTick()); +} + +int random_randint(PikaObj *self, int a, int b){ + return rand() % (b - a + 1) + a; +} + +pika_float random_random(PikaObj *self){ + return rand() / (pika_float)RAND_MAX; +} + +int random_randrange(PikaObj *self, int start, int stop, int step){ + if (step == 0) { + return random_randint(self, start, stop); + } + int n = (stop - start + step) / step; + int r = random_randint(self, 0, n - 1); + return start + r * step; +} + +PikaObj* random_seed(PikaObj *self, int a){ + srand(a); + return NULL; +} + +pika_float random_uniform(PikaObj *self, pika_float a, pika_float b){ + return (b - a) * random_random(self) + a; +} diff --git a/examples/pikapython/pikapython/pikascript-lib/re/LICENCE b/examples/pikapython/pikapython/pikascript-lib/re/LICENCE new file mode 100755 index 00000000..803b4119 --- /dev/null +++ b/examples/pikapython/pikapython/pikascript-lib/re/LICENCE @@ -0,0 +1,93 @@ +PCRE LICENCE +------------ + +PCRE is a library of functions to support regular expressions whose syntax +and semantics are as close as possible to those of the Perl 5 language. + +Release 8 of PCRE is distributed under the terms of the "BSD" licence, as +specified below. The documentation for PCRE, supplied in the "doc" +directory, is distributed under the same terms as the software itself. The data +in the testdata directory is not copyrighted and is in the public domain. + +The basic library functions are written in C and are freestanding. Also +included in the distribution is a set of C++ wrapper functions, and a +just-in-time compiler that can be used to optimize pattern matching. These +are both optional features that can be omitted when the library is built. + + +THE BASIC LIBRARY FUNCTIONS +--------------------------- + +Written by: Philip Hazel +Email local part: Philip.Hazel +Email domain: gmail.com + +University of Cambridge Computing Service, +Cambridge, England. + +Copyright (c) 1997-2021 University of Cambridge +All rights reserved. + + +PCRE JUST-IN-TIME COMPILATION SUPPORT +------------------------------------- + +Written by: Zoltan Herczeg +Email local part: hzmester +Email domain: freemail.hu + +Copyright(c) 2010-2021 Zoltan Herczeg +All rights reserved. + + +STACK-LESS JUST-IN-TIME COMPILER +-------------------------------- + +Written by: Zoltan Herczeg +Email local part: hzmester +Email domain: freemail.hu + +Copyright(c) 2009-2021 Zoltan Herczeg +All rights reserved. + + +THE C++ WRAPPER FUNCTIONS +------------------------- + +Contributed by: Google Inc. + +Copyright (c) 2007-2012, Google Inc. +All rights reserved. + + +THE "BSD" LICENCE +----------------- + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + * Neither the name of the University of Cambridge nor the name of Google + Inc. nor the names of their contributors may be used to endorse or + promote products derived from this software without specific prior + written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. + +End diff --git a/examples/pikapython/pikapython/pikascript-lib/re/cre.c b/examples/pikapython/pikapython/pikascript-lib/re/cre.c new file mode 100755 index 00000000..20c601ca --- /dev/null +++ b/examples/pikapython/pikapython/pikascript-lib/re/cre.c @@ -0,0 +1,641 @@ +/* +* +* Generally additional utility functions. +* L flag, also known as re.LOCALE in Python is not available here. +* Wrong results may be returned in re_sub likes funcitones when 'repl' contains '\', '\\\\1' for example. +* +* 4/9/2022 +*/ +#include +#include +#include "pcre.h" +#include "cre.h" + +int *_re_get_vec_table(pcre *re, int *out_groups_number) +{ + int brackets_number = 0; + pcre_fullinfo(re, NULL, PCRE_INFO_CAPTURECOUNT, &brackets_number); + brackets_number++; + + if (out_groups_number) + *out_groups_number = brackets_number; + + brackets_number *= 3; + + int *vec = (int *)malloc(brackets_number * sizeof(int)); + return vec; +} + +int *pcre_match(const char *_pat, const char *s, int len, int *out_vec_number, int opt) +{ + int *vec = NULL; + pcre *re = re_get_match_re(_pat, opt); + if (!re) + return NULL; + + vec = re_match2(re, s, len, out_vec_number, opt); + pcre_free(re); + return vec; +} +int *re_match2(pcre *re, const char *s, int len, int *out_vec_number, int opt) +{ + int *vec = NULL; + int group_n = 0; + int rc; + int start_offset = 0; + vec = _re_get_vec_table(re, &group_n); + if (out_vec_number) + *out_vec_number = group_n; + group_n *= 3; + + if (!vec) + goto e_er; +match: + rc = pcre_exec(re, NULL, s, len, start_offset, 0, vec, group_n); + if (rc == PCRE_ERROR_NOMATCH) + { + free(vec); + return NULL; + } + if (rc <= 0) + goto e_er; + if (vec[0] == vec[1]) + { + start_offset++; + if (start_offset >= len) + goto e_er; + goto match; + } + return vec; +e_er: + if (vec) + free(vec); + return NULL; +} + +int *pcre_fullmatch(const char *_pat, const char *s, int len, int *out_vec_number, int opt) +{ + int *vec = NULL; + opt &= ~PCRE_MULTILINE; + pcre *re = re_get_fullmatch_re(_pat, opt); + if (!re) + return NULL; + vec = re_fullmatch2(re, s, len, out_vec_number, opt); + pcre_free(re); + return vec; +} +int *re_fullmatch2(pcre *re, const char *s, int len, int *out_vec_number, int opt) +{ + int *vec = NULL; + int group_n = 0; + int rc; + int start_offset = 0; + vec = _re_get_vec_table(re, &group_n); + if (out_vec_number) + *out_vec_number = group_n; + group_n *= 3; + + if (!vec) + goto e_er; + // opt &= ~PCRE_MULTILINE; +match: + rc = pcre_exec(re, NULL, s, len, start_offset, 0, vec, group_n); + if (rc == PCRE_ERROR_NOMATCH) + { + free(vec); + return NULL; + } + if (rc <= 0) + goto e_er; + if (vec[0] == vec[1]) + { + start_offset++; + if (start_offset >= len) + goto e_er; + goto match; + } + return vec; +e_er: + if (vec) + free(vec); + return NULL; +} + +pcre *re_get_match_re(const char *_pat, int opt) +{ + const char *pat = _pat; + if (!*pat) + { + return NULL; + } + if (*pat != '^') + { + int pat_len = strlen(_pat); + char *p = (char *)pcre_malloc(pat_len + 2); + if (!p) + return NULL; + *p = '^'; + memcpy(p + 1, _pat, pat_len + 1); + pat = p; + } + const char *error; + int erroffset; + pcre *re = pcre_compile(pat, opt, &error, &erroffset, NULL); + if (pat != _pat) + free((void *)pat); + + return re; +} +pcre *re_get_fullmatch_re(const char *_pat, int opt) +{ + const char *pat = _pat; + if (!*pat) + { + return NULL; + } + int prefix = 0, suffix = 0; + + if (*pat != '^') + { + prefix = 1; + } + int pat_len = strlen(_pat); + if (_pat[pat_len - 1] != '$') + suffix = 1; + else + { + int n = pat_len - 2; + int i = 0; + while (_pat[n] == '\\') + { + i++; + n--; + } + if (i % 2) + { + suffix = 1; + } + } + int dn = prefix + suffix; + if (dn) + { + char *q = (char *)malloc(pat_len + dn + 1); + if (!q) + return NULL; + pat = q; + if (prefix) + { + *q = '^'; + q++; + } + memcpy(q, _pat, pat_len); + q += pat_len; + if (suffix) + { + *q = '$'; + q++; + } + *q = '\0'; + } + + const char *error; + int erroffset; + pcre *re = pcre_compile(pat, opt, &error, &erroffset, NULL); + if (pat != _pat) + free((void *)pat); + return re; +} + +/* the following functions return (a) vector/table in heap, which means it need to be freed after using*/ + +int *pcre_search(const char *pat, const char *s, int len, int *out_vec_number, int opt) +{ + const char *error; + int erroffset; + pcre *re = pcre_compile(pat, opt, &error, &erroffset, NULL); + if (!re) + return NULL; + int *res = re_search2(re, s, len, out_vec_number, opt); + pcre_free(re); + return res; +} +int *re_search2(pcre *re, const char *s, int len, int *out_vec_number, int opt) +{ + int *vec = NULL; + int group_n = 0; + int rc; + int start_offset = 0; + vec = _re_get_vec_table(re, &group_n); + if (out_vec_number) + *out_vec_number = group_n; + group_n *= 3; + + if (!vec) + goto e_er; +match: + rc = pcre_exec(re, NULL, s, len, start_offset, 0, vec, group_n); + if (rc == PCRE_ERROR_NOMATCH) + { + free(vec); + return NULL; + } + if (rc <= 0) + goto e_er; + if (vec[0] == vec[1]) + { + start_offset++; + if (start_offset >= len) + goto e_er; + goto match; + } + return vec; +e_er: + if (vec) + free(vec); + return NULL; +} + +int **re_searchall(const char *pat, const char *s, int len, int *out_number, int *out_vec_number, int opt) +{ + const char *error; + int erroffset; + pcre *re = pcre_compile(pat, opt, &error, &erroffset, NULL); + if (!re) + return NULL; + int **res = re_searchall2(re, s, len, out_number, out_vec_number, opt); + pcre_free(re); + return res; +} +int **re_searchall2(pcre *re, const char *s, int len, int *out_number, int *out_vec_number, int opt) +{ + int start_offset = 0; + int **vecs = NULL; + int vec_cap = 4; + int vec_n = 0; + int *vec = NULL; + int group_n = 0; + + while (1) + { + if (group_n) + vec = (int *)malloc(group_n * sizeof(int)); + else + { + vec = _re_get_vec_table(re, &group_n); + if (out_vec_number) + *out_vec_number = group_n; + group_n *= 3; + } + if (!vec) + { + goto e_er; + } + int rc; + match: + rc = pcre_exec(re, NULL, s, len, start_offset, 0, vec, group_n); + if (rc == PCRE_ERROR_NOMATCH) + { + if (out_number) + *out_number = vec_n; + free(vec); + return vecs; + } + if (rc <= 0) + goto e_er; + if (vec[0] == vec[1]) + { + start_offset++; + if (start_offset >= len) + goto e_er; + goto match; + } + if (!vecs) + { + vecs = (int **)malloc(sizeof(int *) * vec_cap); + if (!vecs) + goto e_er; + } + + if (vec_n >= vec_cap) + { + vec_cap *= 2; + void *p = realloc(vecs, vec_cap * sizeof(int *)); + if (!p) + goto e_er; + vecs = (int **)p; + } + vecs[vec_n++] = vec; + start_offset = vec[1]; + } +e_er: + if (vec) + free(vec); + if (!vecs) + return NULL; + for (int j = 0; j < vec_n; j++) + { + if (vecs[j]) + free((void *)(vecs[j])); + } + free(vecs); + return NULL; +} +void re_free_searchall(int **vecs, int n) +{ + if (!vecs) + return; + for (int j = 0; j < n; j++) + { + if (vecs[j]) + free((void *)(vecs[j])); + } + free(vecs); +} + +/* the following functions return (a) string in heap, which means it need to be freed after using*/ +char **_re_extract_substring(const char *s, int **vecs, int n) +{ + if (!vecs) + return NULL; + int c = 0; + char **res = (char **)pcre_malloc(sizeof(char *) * n); + if (!res) + return NULL; + for (int j = 0; j < n; j++) + { + int *v = vecs[j]; + int len = v[1] - v[0]; + char *p = (char *)pcre_malloc(len + 1); + if (!p) + goto e_er; + res[c++] = p; + memcpy(p, s + v[0], len); + p[len] = 0; + } + return res; +e_er: + if (!res) + return NULL; + for (int i = 0; i < c; i++) + { + free(res[i]); + } + free(res); + return NULL; +} + +char *re_find(const char *pat, const char *s, int len, int opt) +{ + const char *error; + int erroffset; + pcre *re = pcre_compile(pat, opt, &error, &erroffset, NULL); + if (!re) + return NULL; + char *res = re_find2(re, s, len, opt); + pcre_free(re); + return res; +} +char *re_find2(pcre *re, const char *s, int len, int opt) +{ + int *vec = NULL; + int group_n = 0; + int rc; + int start_offset = 0; + char *res_s = NULL; + vec = _re_get_vec_table(re, &group_n); + + if (!vec) + goto e_er; + group_n *= 3; +match: + rc = pcre_exec(re, NULL, s, len, start_offset, 0, vec, group_n); + if (rc == PCRE_ERROR_NOMATCH) + { + free(vec); + return NULL; + } + if (rc <= 0) + goto e_er; + if (vec[0] == vec[1]) + { + start_offset++; + if (start_offset >= len) + goto e_er; + goto match; + } + len = vec[1] - vec[0]; + if (!len) + goto e_er; + res_s = (char *)malloc(len + 1); + if (!res_s) + goto e_er; + memcpy(res_s, s + vec[0], len); + res_s[len] = 0; + if (vec) + free(vec); + return res_s; +e_er: + if (vec) + free(vec); + return NULL; +} + +char **pcre_findall(const char *pat, const char *s, int len, int *out_number, int opt) +{ + const char *error; + int erroffset; + pcre *re = pcre_compile(pat, opt, &error, &erroffset, NULL); + if (!re) + return NULL; + char **res = re_findall2(re, s, len, out_number, opt); + pcre_free(re); + return res; +} +char **re_findall2(pcre *re, const char *s, int len, int *out_number, int opt) +{ + int out_vec_number; + int **vecs; + char **res; + vecs = re_searchall2(re, s, len, out_number, &out_vec_number, opt); + if (!vecs) + goto e_er; + res = _re_extract_substring(s, vecs, *out_number); + if (!res) + goto e_er; + re_free_searchall(vecs, *out_number); + return res; +e_er: + if (vecs) + re_free_searchall(vecs, *out_number); + return NULL; +} +void re_free_findall(char **ss, int n) +{ + if (!ss) + return; + for (int j = 0; j < n; j++) + { + if (ss[j]) + free((void *)(ss[j])); + } + free(ss); +} + +char *pcre_sub(const char *pat, const char *to, const char *s, int len, int opt) +{ + const char *error; + int erroffset; + pcre *re = pcre_compile(pat, opt, &error, &erroffset, NULL); + if (!re) + return NULL; + char *res = re_sub2(re, to, s, len, opt); + pcre_free(re); + return res; +} +char *pcre_subn(const char *pat, const char *to, const char *s, int len, int n, int opt, int *out_repl_times) +{ + const char *error; + int erroffset; + pcre *re = pcre_compile(pat, opt, &error, &erroffset, NULL); + if (!re) + return NULL; + char *res = re_subn2(re, to, s, len, n, opt, out_repl_times); + pcre_free(re); + return res; +} +char *re_subn2(pcre *re, const char *to, const char *s, int len, int n, int opt, int *out_repl_times) +{ + int group_n = 0; + pcre *re2 = NULL; + int vcs1_n = 0, vcs2_n = 0; + int **vcs1 = re_searchall2(re, s, len, &vcs1_n, &group_n, opt); + int **vcs2 = NULL; + int match_limit = 0; + if (!vcs1_n) + { + return (char *)s; + } + const char *p2 = "(\\\\\\\\|\\\\\\d{1,2})"; + int erroffset; + const char *error; + int len_to, remain_size, remain_length2, pi = 0, qi = 0; + char *new_s = NULL; + + re2 = pcre_compile(p2, 0, &error, &erroffset, NULL); + if (!re2) + goto exit_error; + len_to = strlen(to); + vcs2 = re_searchall2(re2, to, len_to, &vcs2_n, NULL, 0); + pcre_free(re2); + re2 = NULL; + remain_length2 = len_to; + for (int i = 0; i < vcs2_n; i++) + { + int *vc = vcs2[i]; + int vc0 = vc[0] + 1; + if (to[vc0] == '\\') + { + vc[2] = 0; + remain_length2 -= 2; + } + else + { + int wanted_number = 0; + int l_n = vc[1] - vc0; + if (l_n == 1) + { + wanted_number = to[vc0] - '0'; + remain_length2 -= 2; + } + else + { + wanted_number = (to[vc0] - '0') * 10 + to[vc0 + 1] - '0'; + remain_length2 -= 3; + } + if (wanted_number <= 0 || wanted_number >= group_n) + goto exit_error; + vc[2] = wanted_number; + } + } + + match_limit = n ? (n <= vcs1_n ? n : vcs1_n) : vcs1_n; + remain_size = len + remain_length2 * match_limit; + for (int i = 0; i < match_limit; i++) + { + int *vc = vcs1[i]; + remain_size -= vc[1] - vc[0]; + for (int j = 0; j < vcs2_n; j++) + { + int *v2 = vcs2[j]; + if (v2[2]) + { + remain_size += GetGroupLen(vc, v2[2]); + } + else + { + remain_size++; + } + } + } + new_s = (char *)malloc(remain_size + 1); + if (!new_s) + goto exit_error; + for (int i = 0; i < match_limit; i++) + { + int *vc = vcs1[i]; + memcpy(new_s + pi, s + qi, vc[0] - qi); + pi += vc[0] - qi; + int m_start = 0, m_len = 0; + for (int j = 0; j < vcs2_n; j++) + { + int *v2 = vcs2[j]; + m_len = v2[0] - m_start; + memcpy(new_s + pi, to + m_start, m_len); + pi += m_len; + + int to_group = v2[2]; + if (to_group) + { + int to_group_at = vc[to_group * 2]; + int to_group_end = vc[to_group * 2 + 1]; + int g_l = to_group_end - to_group_at; + memcpy(new_s + pi, s + to_group_at, g_l); + pi += g_l; + } + else + { + new_s[pi++] = '\\'; + } + m_start = v2[1]; + } + m_len = len_to - m_start; + memcpy(new_s + pi, to + m_start, m_len); + pi += m_len; + qi = vc[1]; + } + if (out_repl_times) + *out_repl_times = match_limit; + if (vcs1) + re_free_searchall(vcs1, vcs1_n); + if (vcs2) + re_free_searchall(vcs2, vcs2_n); + len -= qi; + if (len) + memcpy(new_s + pi, s + qi, len); + pi += len; + new_s[pi] = '\0'; + return new_s; + +exit_error: + if (vcs1) + re_free_searchall(vcs1, vcs1_n); + if (vcs2) + re_free_searchall(vcs2, vcs2_n); + if (re2) + pcre_free(re2); + return NULL; +} +char *re_sub2(pcre *re, const char *to, const char *s, int len, int opt) +{ + return re_subn2(re, to, s, len, 0, opt, NULL); +} diff --git a/examples/pikapython/pikapython/pikascript-lib/re/cre.h b/examples/pikapython/pikapython/pikascript-lib/re/cre.h new file mode 100755 index 00000000..9aa6dfe3 --- /dev/null +++ b/examples/pikapython/pikapython/pikascript-lib/re/cre.h @@ -0,0 +1,50 @@ +#ifndef CRE_H +#define CRE_H + +#include "pcre.h" +#define GetGroupLen(vc, n) (vc[(n)*2 + 1] - vc[(n)*2]) + +int *_re_get_vec_table(pcre *re, int *out_groups_number); + +int *pcre_match(const char *_pat, const char *s, int len, int *out_vec_number, int opt); + +int *re_match2(pcre *re, const char *s, int len, int *out_vec_number, int opt); + +int *pcre_fullmatch(const char *_pat, const char *s, int len, int *out_vec_number, int opt); + +int *re_fullmatch2(pcre *re, const char *s, int len, int *out_vec_number, int opt); + +pcre *re_get_match_re(const char *_pat, int opt); + +pcre *re_get_fullmatch_re(const char *_pat, int opt); + +int *pcre_search(const char *pat, const char *s, int len, int *out_vec_number, int opt); + +int *re_search2(pcre *re, const char *s, int len, int *out_vec_number, int opt); + +int **re_searchall(const char *pat, const char *s, int len, int *out_number, int *out_vec_number, int opt); + +int **re_searchall2(pcre *re, const char *s, int len, int *out_number, int *out_vec_number, int opt); + +void re_free_searchall(int **vecs, int n); + +char **_re_extract_substring(const char *s, int **vecs, int n); + +char *re_find(const char *pat, const char *s, int len, int opt); + +char *re_find2(pcre *re, const char *s, int len, int opt); + +char **pcre_findall(const char *pat, const char *s, int len, int *out_number, int opt); + +char **re_findall2(pcre *re, const char *s, int len, int *out_number, int opt); + +void re_free_findall(char **ss, int n); + +char *pcre_sub(const char *pat, const char *to, const char *s, int len, int opt); + +char *pcre_subn(const char *pat, const char *to, const char *s, int len, int n, int opt, int *out_repl_times); + +char *re_subn2(pcre *re, const char *to, const char *s, int len, int n, int opt, int *out_repl_times); + +char *re_sub2(pcre *re, const char *to, const char *s, int len, int opt); +#endif \ No newline at end of file diff --git a/examples/pikapython/pikapython/pikascript-lib/re/pcre.h b/examples/pikapython/pikapython/pikascript-lib/re/pcre.h new file mode 100755 index 00000000..1b15b66a --- /dev/null +++ b/examples/pikapython/pikapython/pikascript-lib/re/pcre.h @@ -0,0 +1,208 @@ + +#ifndef _PCRE_H +#define _PCRE_H + +/* When an application links to a PCRE DLL in Windows, the symbols that are +imported have to be identified as such. When building PCRE, the appropriate +export setting is defined in pcre_internal.h, which includes this file. So we +don't change existing definitions of PCRE_EXP_DECL and PCRECPP_EXP_DECL. */ + +#if defined(_WIN32) && !defined(PCRE_STATIC) +# ifndef PCRE_EXP_DECL +# define PCRE_EXP_DECL extern __declspec(dllimport) +# endif +# ifdef __cplusplus +# ifndef PCRECPP_EXP_DECL +# define PCRECPP_EXP_DECL extern __declspec(dllimport) +# endif +# ifndef PCRECPP_EXP_DEFN +# define PCRECPP_EXP_DEFN __declspec(dllimport) +# endif +# endif +#endif + +/* By default, we use the standard "extern" declarations. */ + +#ifndef PCRE_EXP_DECL +# ifdef __cplusplus +# define PCRE_EXP_DECL extern "C" +# else +# define PCRE_EXP_DECL extern +# endif +#endif + +#ifdef __cplusplus +# ifndef PCRECPP_EXP_DECL +# define PCRECPP_EXP_DECL extern +# endif +# ifndef PCRECPP_EXP_DEFN +# define PCRECPP_EXP_DEFN +# endif +#endif + +/* Have to include stdlib.h in order to ensure that size_t is defined; +it is needed here for malloc. */ + +#include + + +#ifdef __cplusplus +extern "C" { +#endif + + +#define PCRE_CASELESS 0x00000001 +#define PCRE_MULTILINE 0x00000002 +#define PCRE_DOTALL 0x00000004 +#define PCRE_EXTENDED 0x00000008 +#define PCRE_ANCHORED 0x00000010 +#define PCRE_DOLLAR_ENDONLY 0x00000020 +#define PCRE_EXTRA 0x00000040 +#define PCRE_NOTBOL 0x00000080 +#define PCRE_NOTEOL 0x00000100 +#define PCRE_UNGREEDY 0x00000200 +#define PCRE_NOTEMPTY 0x00000400 +#define PCRE_UTF8 0x00000800 +#define PCRE_NO_AUTO_CAPTURE 0x00001000 +#define PCRE_NO_UTF8_CHECK 0x00002000 +#define PCRE_AUTO_CALLOUT 0x00004000 +#define PCRE_PARTIAL 0x00008000 +#define PCRE_DFA_SHORTEST 0x00010000 +#define PCRE_DFA_RESTART 0x00020000 +#define PCRE_FIRSTLINE 0x00040000 +#define PCRE_DUPNAMES 0x00080000 +#define PCRE_NEWLINE_CR 0x00100000 +#define PCRE_NEWLINE_LF 0x00200000 +#define PCRE_NEWLINE_CRLF 0x00300000 +#define PCRE_NEWLINE_ANY 0x00400000 +#define PCRE_NEWLINE_ANYCRLF 0x00500000 +#define PCRE_BSR_ANYCRLF 0x00800000 +#define PCRE_BSR_UNICODE 0x01000000 +#define PCRE_ONLY_ASCII 0x02000000 + + +#define PCRE_ERROR_NOMATCH (-1) +#define PCRE_ERROR_NULL (-2) +#define PCRE_ERROR_BADOPTION (-3) +#define PCRE_ERROR_BADMAGIC (-4) +#define PCRE_ERROR_UNKNOWN_OPCODE (-5) +#define PCRE_ERROR_UNKNOWN_NODE (-5) +#define PCRE_ERROR_NOMEMORY (-6) +#define PCRE_ERROR_NOSUBSTRING (-7) +#define PCRE_ERROR_MATCHLIMIT (-8) +#define PCRE_ERROR_CALLOUT (-9) +#define PCRE_ERROR_BADUTF8 (-10) +#define PCRE_ERROR_BADUTF8_OFFSET (-11) +#define PCRE_ERROR_PARTIAL (-12) +#define PCRE_ERROR_BADPARTIAL (-13) +#define PCRE_ERROR_INTERNAL (-14) +#define PCRE_ERROR_BADCOUNT (-15) +#define PCRE_ERROR_DFA_UITEM (-16) +#define PCRE_ERROR_DFA_UCOND (-17) +#define PCRE_ERROR_DFA_UMLIMIT (-18) +#define PCRE_ERROR_DFA_WSSIZE (-19) +#define PCRE_ERROR_DFA_RECURSE (-20) +#define PCRE_ERROR_RECURSIONLIMIT (-21) +#define PCRE_ERROR_NULLWSLIMIT (-22) +#define PCRE_ERROR_BADNEWLINE (-23) + + +#define PCRE_INFO_OPTIONS 0 +#define PCRE_INFO_SIZE 1 +#define PCRE_INFO_CAPTURECOUNT 2 +#define PCRE_INFO_BACKREFMAX 3 +#define PCRE_INFO_FIRSTBYTE 4 +#define PCRE_INFO_FIRSTCHAR 4 +#define PCRE_INFO_FIRSTTABLE 5 +#define PCRE_INFO_LASTLITERAL 6 +#define PCRE_INFO_NAMEENTRYSIZE 7 +#define PCRE_INFO_NAMECOUNT 8 +#define PCRE_INFO_NAMETABLE 9 +#define PCRE_INFO_STUDYSIZE 10 +#define PCRE_INFO_DEFAULT_TABLES 11 +#define PCRE_INFO_OKPARTIAL 12 +#define PCRE_INFO_JCHANGED 13 +#define PCRE_INFO_HASCRORLF 14 + + +#define PCRE_CONFIG_UTF8 0 +#define PCRE_CONFIG_NEWLINE 1 +#define PCRE_CONFIG_LINK_SIZE 2 +#define PCRE_CONFIG_POSIX_MALLOC_THRESHOLD 3 +#define PCRE_CONFIG_MATCH_LIMIT 4 +#define PCRE_CONFIG_STACKRECURSE 5 +#define PCRE_CONFIG_UNICODE_PROPERTIES 6 +#define PCRE_CONFIG_MATCH_LIMIT_RECURSION 7 +#define PCRE_CONFIG_BSR 8 + + +#define PCRE_EXTRA_STUDY_DATA 0x0001 +#define PCRE_EXTRA_MATCH_LIMIT 0x0002 +#define PCRE_EXTRA_CALLOUT_DATA 0x0004 +#define PCRE_EXTRA_TABLES 0x0008 +#define PCRE_EXTRA_MATCH_LIMIT_RECURSION 0x0010 + + +struct real_pcre; /* declaration; the definition is private */ +typedef struct real_pcre pcre; + + +#ifndef PCRE_SPTR +#define PCRE_SPTR const char * +#endif + + +typedef struct pcre_extra { + unsigned long int flags; + void *study_data; + unsigned long int match_limit; + void *callout_data; + const unsigned char *tables; + unsigned long int match_limit_recursion; +} pcre_extra; + + +typedef struct pcre_callout_block { + int version; + int callout_number; + int *offset_vector; + PCRE_SPTR subject; + int subject_length; + int start_match; + int current_position; + int capture_top; + int capture_last; + void *callout_data; + int pattern_position; + int next_item_length; +} pcre_callout_block; + + +#ifndef VPCOMPAT +PCRE_EXP_DECL void *(*pcre_malloc)(size_t); +PCRE_EXP_DECL void (*pcre_free)(void *); +PCRE_EXP_DECL void *(*pcre_stack_malloc)(size_t); +PCRE_EXP_DECL void (*pcre_stack_free)(void *); +PCRE_EXP_DECL int (*pcre_callout)(pcre_callout_block *); +#else +PCRE_EXP_DECL void *pcre_malloc(size_t); +PCRE_EXP_DECL void pcre_free(void *); +PCRE_EXP_DECL void *pcre_stack_malloc(size_t); +PCRE_EXP_DECL void pcre_stack_free(void *); +PCRE_EXP_DECL int pcre_callout(pcre_callout_block *); +#endif + +pcre *pcre_compile(const char *, int, const char **, int *, + const unsigned char *); +pcre *pcre_compile2(const char *, int, int *, const char **, + int *, const unsigned char *); +int pcre_exec(const pcre *, const pcre_extra *, PCRE_SPTR, + int, int, int, int *, int); +int pcre_fullinfo(const pcre *, const pcre_extra *, int, + void *); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/examples/pikapython/pikapython/pikascript-lib/re/pcre_chartables.c b/examples/pikapython/pikapython/pikascript-lib/re/pcre_chartables.c new file mode 100755 index 00000000..736adc51 --- /dev/null +++ b/examples/pikapython/pikapython/pikascript-lib/re/pcre_chartables.c @@ -0,0 +1,173 @@ +#include "re_config.h" +#include "pcre_internal.h" + +const unsigned char _pcre_default_tables[] = { + +/* This table is a lower casing table. */ + + 0, 1, 2, 3, 4, 5, 6, 7, + 8, 9, 10, 11, 12, 13, 14, 15, + 16, 17, 18, 19, 20, 21, 22, 23, + 24, 25, 26, 27, 28, 29, 30, 31, + 32, 33, 34, 35, 36, 37, 38, 39, + 40, 41, 42, 43, 44, 45, 46, 47, + 48, 49, 50, 51, 52, 53, 54, 55, + 56, 57, 58, 59, 60, 61, 62, 63, + 64, 97, 98, 99,100,101,102,103, + 104,105,106,107,108,109,110,111, + 112,113,114,115,116,117,118,119, + 120,121,122, 91, 92, 93, 94, 95, + 96, 97, 98, 99,100,101,102,103, + 104,105,106,107,108,109,110,111, + 112,113,114,115,116,117,118,119, + 120,121,122,123,124,125,126,127, + 128,129,130,131,132,133,134,135, + 136,137,138,139,140,141,142,143, + 144,145,146,147,148,149,150,151, + 152,153,154,155,156,157,158,159, + 160,161,162,163,164,165,166,167, + 168,169,170,171,172,173,174,175, + 176,177,178,179,180,181,182,183, + 184,185,186,187,188,189,190,191, + 192,193,194,195,196,197,198,199, + 200,201,202,203,204,205,206,207, + 208,209,210,211,212,213,214,215, + 216,217,218,219,220,221,222,223, + 224,225,226,227,228,229,230,231, + 232,233,234,235,236,237,238,239, + 240,241,242,243,244,245,246,247, + 248,249,250,251,252,253,254,255, + +/* This table is a case flipping table. */ + + 0, 1, 2, 3, 4, 5, 6, 7, + 8, 9, 10, 11, 12, 13, 14, 15, + 16, 17, 18, 19, 20, 21, 22, 23, + 24, 25, 26, 27, 28, 29, 30, 31, + 32, 33, 34, 35, 36, 37, 38, 39, + 40, 41, 42, 43, 44, 45, 46, 47, + 48, 49, 50, 51, 52, 53, 54, 55, + 56, 57, 58, 59, 60, 61, 62, 63, + 64, 97, 98, 99,100,101,102,103, + 104,105,106,107,108,109,110,111, + 112,113,114,115,116,117,118,119, + 120,121,122, 91, 92, 93, 94, 95, + 96, 65, 66, 67, 68, 69, 70, 71, + 72, 73, 74, 75, 76, 77, 78, 79, + 80, 81, 82, 83, 84, 85, 86, 87, + 88, 89, 90,123,124,125,126,127, + 128,129,130,131,132,133,134,135, + 136,137,138,139,140,141,142,143, + 144,145,146,147,148,149,150,151, + 152,153,154,155,156,157,158,159, + 160,161,162,163,164,165,166,167, + 168,169,170,171,172,173,174,175, + 176,177,178,179,180,181,182,183, + 184,185,186,187,188,189,190,191, + 192,193,194,195,196,197,198,199, + 200,201,202,203,204,205,206,207, + 208,209,210,211,212,213,214,215, + 216,217,218,219,220,221,222,223, + 224,225,226,227,228,229,230,231, + 232,233,234,235,236,237,238,239, + 240,241,242,243,244,245,246,247, + 248,249,250,251,252,253,254,255, + +/* This table contains bit maps for various character classes. Each map is 32 +bytes long and the bits run from the least significant end of each byte. The +classes that have their own maps are: space, xdigit, digit, upper, lower, word, +graph, print, punct, and cntrl. Other classes are built from combinations. */ + + 0x00,0x3e,0x00,0x00,0x01,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + + 0x00,0x00,0x00,0x00,0x00,0x00,0xff,0x03, + 0x7e,0x00,0x00,0x00,0x7e,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + + 0x00,0x00,0x00,0x00,0x00,0x00,0xff,0x03, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0xfe,0xff,0xff,0x07,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0xfe,0xff,0xff,0x07, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + + 0x00,0x00,0x00,0x00,0x00,0x00,0xff,0x03, + 0xfe,0xff,0xff,0x87,0xfe,0xff,0xff,0x07, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + + 0x00,0x00,0x00,0x00,0xfe,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x7f, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + + 0x00,0x00,0x00,0x00,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x7f, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + + 0x00,0x00,0x00,0x00,0xfe,0xff,0x00,0xfc, + 0x01,0x00,0x00,0xf8,0x01,0x00,0x00,0x78, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + + 0xff,0xff,0xff,0xff,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + +/* This table identifies various classes of character by individual bits: + 0x01 white space character + 0x02 letter + 0x04 decimal digit + 0x08 hexadecimal digit + 0x10 alphanumeric or '_' + 0x80 regular expression metacharacter or binary zero +*/ + + 0x80,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 0- 7 */ + 0x00,0x01,0x01,0x00,0x01,0x01,0x00,0x00, /* 8- 15 */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 16- 23 */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 24- 31 */ + 0x01,0x00,0x00,0x00,0x80,0x00,0x00,0x00, /* - ' */ + 0x80,0x80,0x80,0x80,0x00,0x00,0x80,0x00, /* ( - / */ + 0x1c,0x1c,0x1c,0x1c,0x1c,0x1c,0x1c,0x1c, /* 0 - 7 */ + 0x1c,0x1c,0x00,0x00,0x00,0x00,0x00,0x80, /* 8 - ? */ + 0x00,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x12, /* @ - G */ + 0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12, /* H - O */ + 0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12, /* P - W */ + 0x12,0x12,0x12,0x80,0x80,0x00,0x80,0x10, /* X - _ */ + 0x00,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x12, /* ` - g */ + 0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12, /* h - o */ + 0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12, /* p - w */ + 0x12,0x12,0x12,0x80,0x80,0x00,0x00,0x00, /* x -127 */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 128-135 */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 136-143 */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 144-151 */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 152-159 */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 160-167 */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 168-175 */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 176-183 */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 184-191 */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 192-199 */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 200-207 */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 208-215 */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 216-223 */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 224-231 */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 232-239 */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 240-247 */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};/* 248-255 */ + +/* End of pcre_chartables.c */ diff --git a/examples/pikapython/pikapython/pikascript-lib/re/pcre_compile.c b/examples/pikapython/pikapython/pikascript-lib/re/pcre_compile.c new file mode 100755 index 00000000..63d0783f --- /dev/null +++ b/examples/pikapython/pikapython/pikascript-lib/re/pcre_compile.c @@ -0,0 +1,6180 @@ + +/* This module contains the external function pcre_compile(), along with +supporting internal functions that are not used by other modules. */ + + +#include "re_config.h" +#include "PikaObj.h" +#define NLBLOCK cd /* Block containing newline information */ +#define PSSTART start_pattern /* Field containing processed string start */ +#define PSEND end_pattern /* Field containing processed string end */ + +#include "pcre_internal.h" + + +/* When DEBUG is defined, we need the pcre_printint() function, which is also +used by pcretest. DEBUG is not defined when building a production library. */ + +#ifdef DEBUG +#include "pcre_printint.src" +#endif + + +/* Macro for setting individual bits in class bitmaps. */ + +#define SETBIT(a,b) a[b/8] |= (1 << (b%8)) + +/* Maximum length value to check against when making sure that the integer that +holds the compiled pattern length does not overflow. We make it a bit less than +INT_MAX to allow for adding in group terminating bytes, so that we don't have +to check them every time. */ + +#define OFLOW_MAX (INT_MAX - 20) + + +/************************************************* +* Code parameters and static tables * +*************************************************/ + +/* This value specifies the size of stack workspace that is used during the +first pre-compile phase that determines how much memory is required. The regex +is partly compiled into this space, but the compiled parts are discarded as +soon as they can be, so that hopefully there will never be an overrun. The code +does, however, check for an overrun. The largest amount I've seen used is 218, +so this number is very generous. + +The same workspace is used during the second, actual compile phase for +remembering forward references to groups so that they can be filled in at the +end. Each entry in this list occupies LINK_SIZE bytes, so even when LINK_SIZE +is 4 there is plenty of room. */ + +#define COMPILE_WORK_SIZE (4096) + + +/* Table for handling escaped characters in the range '0'-'z'. Positive returns +are simple data values; negative values are for special things like \d and so +on. Zero means further processing is needed (for things like \x), or the escape +is invalid. */ + +#ifndef EBCDIC /* This is the "normal" table for ASCII systems */ +static const short int escapes[] = { + 0, 0, 0, 0, 0, 0, 0, 0, /* 0 - 7 */ + 0, 0, ':', ';', '<', '=', '>', '?', /* 8 - ? */ + '@', -ESC_A, -ESC_B, -ESC_C, -ESC_D, -ESC_E, 0, -ESC_G, /* @ - G */ +-ESC_H, 0, 0, -ESC_K, 0, 0, 0, 0, /* H - O */ +-ESC_P, -ESC_Q, -ESC_R, -ESC_S, 0, 0, -ESC_V, -ESC_W, /* P - W */ +-ESC_X, 0, -ESC_Z, '[', '\\', ']', '^', '_', /* X - _ */ + '`', 7, -ESC_b, 0, -ESC_d, ESC_e, ESC_f, 0, /* ` - g */ +-ESC_h, 0, 0, -ESC_k, 0, 0, ESC_n, 0, /* h - o */ +-ESC_p, 0, ESC_r, -ESC_s, ESC_tee, 0, -ESC_v, -ESC_w, /* p - w */ + 0, 0, -ESC_z /* x - z */ +}; + +#else /* This is the "abnormal" table for EBCDIC systems */ +static const short int escapes[] = { +/* 48 */ 0, 0, 0, '.', '<', '(', '+', '|', +/* 50 */ '&', 0, 0, 0, 0, 0, 0, 0, +/* 58 */ 0, 0, '!', '$', '*', ')', ';', '~', +/* 60 */ '-', '/', 0, 0, 0, 0, 0, 0, +/* 68 */ 0, 0, '|', ',', '%', '_', '>', '?', +/* 70 */ 0, 0, 0, 0, 0, 0, 0, 0, +/* 78 */ 0, '`', ':', '#', '@', '\'', '=', '"', +/* 80 */ 0, 7, -ESC_b, 0, -ESC_d, ESC_e, ESC_f, 0, +/* 88 */-ESC_h, 0, 0, '{', 0, 0, 0, 0, +/* 90 */ 0, 0, -ESC_k, 'l', 0, ESC_n, 0, -ESC_p, +/* 98 */ 0, ESC_r, 0, '}', 0, 0, 0, 0, +/* A0 */ 0, '~', -ESC_s, ESC_tee, 0,-ESC_v, -ESC_w, 0, +/* A8 */ 0,-ESC_z, 0, 0, 0, '[', 0, 0, +/* B0 */ 0, 0, 0, 0, 0, 0, 0, 0, +/* B8 */ 0, 0, 0, 0, 0, ']', '=', '-', +/* C0 */ '{',-ESC_A, -ESC_B, -ESC_C, -ESC_D,-ESC_E, 0, -ESC_G, +/* C8 */-ESC_H, 0, 0, 0, 0, 0, 0, 0, +/* D0 */ '}', 0, -ESC_K, 0, 0, 0, 0, -ESC_P, +/* D8 */-ESC_Q,-ESC_R, 0, 0, 0, 0, 0, 0, +/* E0 */ '\\', 0, -ESC_S, 0, 0,-ESC_V, -ESC_W, -ESC_X, +/* E8 */ 0,-ESC_Z, 0, 0, 0, 0, 0, 0, +/* F0 */ 0, 0, 0, 0, 0, 0, 0, 0, +/* F8 */ 0, 0, 0, 0, 0, 0, 0, 0 +}; +#endif + + +/* Table of special "verbs" like (*PRUNE). This is a short table, so it is +searched linearly. Put all the names into a single string, in order to reduce +the number of relocations when a shared library is dynamically linked. */ + +typedef struct verbitem { + int len; + int op; +} verbitem; + +static const char verbnames[] = + "ACCEPT\0" + "COMMIT\0" + "F\0" + "FAIL\0" + "PRUNE\0" + "SKIP\0" + "THEN"; + +static verbitem verbs[] = { + { 6, OP_ACCEPT }, + { 6, OP_COMMIT }, + { 1, OP_FAIL }, + { 4, OP_FAIL }, + { 5, OP_PRUNE }, + { 4, OP_SKIP }, + { 4, OP_THEN } +}; + +static int verbcount = sizeof(verbs)/sizeof(verbitem); + + +/* Tables of names of POSIX character classes and their lengths. The names are +now all in a single string, to reduce the number of relocations when a shared +library is dynamically loaded. The list of lengths is terminated by a zero +length entry. The first three must be alpha, lower, upper, as this is assumed +for handling case independence. */ + +static const char posix_names[] = + "alpha\0" "lower\0" "upper\0" "alnum\0" "ascii\0" "blank\0" + "cntrl\0" "digit\0" "graph\0" "print\0" "punct\0" "space\0" + "word\0" "xdigit"; + +static const uschar posix_name_lengths[] = { + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 4, 6, 0 }; + +/* Table of class bit maps for each POSIX class. Each class is formed from a +base map, with an optional addition or removal of another map. Then, for some +classes, there is some additional tweaking: for [:blank:] the vertical space +characters are removed, and for [:alpha:] and [:alnum:] the underscore +character is removed. The triples in the table consist of the base map offset, +second map offset or -1 if no second map, and a non-negative value for map +addition or a negative value for map subtraction (if there are two maps). The +absolute value of the third field has these meanings: 0 => no tweaking, 1 => +remove vertical space characters, 2 => remove underscore. */ + +static const int posix_class_maps[] = { + cbit_word, cbit_digit, -2, /* alpha */ + cbit_lower, -1, 0, /* lower */ + cbit_upper, -1, 0, /* upper */ + cbit_word, -1, 2, /* alnum - word without underscore */ + cbit_print, cbit_cntrl, 0, /* ascii */ + cbit_space, -1, 1, /* blank - a GNU extension */ + cbit_cntrl, -1, 0, /* cntrl */ + cbit_digit, -1, 0, /* digit */ + cbit_graph, -1, 0, /* graph */ + cbit_print, -1, 0, /* print */ + cbit_punct, -1, 0, /* punct */ + cbit_space, -1, 0, /* space */ + cbit_word, -1, 0, /* word - a Perl extension */ + cbit_xdigit,-1, 0 /* xdigit */ +}; + + +#define STRING(a) # a +#define XSTRING(s) STRING(s) + +/* The texts of compile-time error messages. These are "char *" because they +are passed to the outside world. Do not ever re-use any error number, because +they are documented. Always add a new error instead. Messages marked DEAD below +are no longer used. This used to be a table of strings, but in order to reduce +the number of relocations needed when a shared library is loaded dynamically, +it is now one long string. We cannot use a table of offsets, because the +lengths of inserts such as XSTRING(MAX_NAME_SIZE) are not known. Instead, we +simply count through to the one we want - this isn't a performance issue +because these strings are used only when there is a compilation error. */ + +static const char error_texts[] = + "no error\0" + "\\ at end of pattern\0" + "\\c at end of pattern\0" + "unrecognized character follows \\\0" + "numbers out of order in {} quantifier\0" + /* 5 */ + "number too big in {} quantifier\0" + "missing terminating ] for character class\0" + "invalid escape sequence in character class\0" + "range out of order in character class\0" + "nothing to repeat\0" + /* 10 */ + "operand of unlimited repeat could match the empty string\0" /** DEAD **/ + "internal error: unexpected repeat\0" + "unrecognized character after (? or (?-\0" + "POSIX named classes are supported only within a class\0" + "missing )\0" + /* 15 */ + "reference to non-existent subpattern\0" + "erroffset passed as NULL\0" + "unknown option bit(s) set\0" + "missing ) after comment\0" + "parentheses nested too deeply\0" /** DEAD **/ + /* 20 */ + "regular expression is too large\0" + "failed to get memory\0" + "unmatched parentheses\0" + "internal error: code overflow\0" + "unrecognized character after (?<\0" + /* 25 */ + "lookbehind assertion is not fixed length\0" + "malformed number or name after (?(\0" + "conditional group contains more than two branches\0" + "assertion expected after (?(\0" + "(?R or (?[+-]digits must be followed by )\0" + /* 30 */ + "unknown POSIX class name\0" + "POSIX collating elements are not supported\0" + "this version of PCRE is not compiled with PCRE_UTF8 support\0" + "spare error\0" /** DEAD **/ + "character value in \\x{...} sequence is too large\0" + /* 35 */ + "invalid condition (?(0)\0" + "\\C not allowed in lookbehind assertion\0" + "PCRE does not support \\L, \\l, \\N, \\U, or \\u\0" + "number after (?C is > 255\0" + "closing ) for (?C expected\0" + /* 40 */ + "recursive call could loop indefinitely\0" + "unrecognized character after (?P\0" + "syntax error in subpattern name (missing terminator)\0" + "two named subpatterns have the same name\0" + "invalid UTF-8 string\0" + /* 45 */ + "support for \\P, \\p, and \\X has not been compiled\0" + "malformed \\P or \\p sequence\0" + "unknown property name after \\P or \\p\0" + "subpattern name is too long (maximum " XSTRING(MAX_NAME_SIZE) " characters)\0" + "too many named subpatterns (maximum " XSTRING(MAX_NAME_COUNT) ")\0" + /* 50 */ + "repeated subpattern is too long\0" /** DEAD **/ + "octal value is greater than \\377 (not in UTF-8 mode)\0" + "internal error: overran compiling workspace\0" + "internal error: previously-checked referenced subpattern not found\0" + "DEFINE group contains more than one branch\0" + /* 55 */ + "repeating a DEFINE group is not allowed\0" + "inconsistent NEWLINE options\0" + "\\g is not followed by a braced name or an optionally braced non-zero number\0" + "(?+ or (?- or (?(+ or (?(- must be followed by a non-zero number\0" + "(*VERB) with an argument is not supported\0" + /* 60 */ + "(*VERB) not recognized\0" + "number is too big\0" + "subpattern name expected\0" + "digit expected after (?+"; + + +/* Table to identify digits and hex digits. This is used when compiling +patterns. Note that the tables in chartables are dependent on the locale, and +may mark arbitrary characters as digits - but the PCRE compiling code expects +to handle only 0-9, a-z, and A-Z as digits when compiling. That is why we have +a private table here. It costs 256 bytes, but it is a lot faster than doing +character value tests (at least in some simple cases I timed), and in some +applications one wants PCRE to compile efficiently as well as match +efficiently. + +For convenience, we use the same bit definitions as in chartables: + + 0x04 decimal digit + 0x08 hexadecimal digit + +Then we can use ctype_digit and ctype_xdigit in the code. */ + +#ifndef EBCDIC /* This is the "normal" case, for ASCII systems */ +static const unsigned char digitab[] = + { + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 0- 7 */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 8- 15 */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 16- 23 */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 24- 31 */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* - ' */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* ( - / */ + 0x0c,0x0c,0x0c,0x0c,0x0c,0x0c,0x0c,0x0c, /* 0 - 7 */ + 0x0c,0x0c,0x00,0x00,0x00,0x00,0x00,0x00, /* 8 - ? */ + 0x00,0x08,0x08,0x08,0x08,0x08,0x08,0x00, /* @ - G */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* H - O */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* P - W */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* X - _ */ + 0x00,0x08,0x08,0x08,0x08,0x08,0x08,0x00, /* ` - g */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* h - o */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* p - w */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* x -127 */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 128-135 */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 136-143 */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 144-151 */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 152-159 */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 160-167 */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 168-175 */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 176-183 */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 184-191 */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 192-199 */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 200-207 */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 208-215 */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 216-223 */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 224-231 */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 232-239 */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 240-247 */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};/* 248-255 */ + +#else /* This is the "abnormal" case, for EBCDIC systems */ +static const unsigned char digitab[] = + { + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 0- 7 0 */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 8- 15 */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 16- 23 10 */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 24- 31 */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 32- 39 20 */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 40- 47 */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 48- 55 30 */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 56- 63 */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* - 71 40 */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 72- | */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* & - 87 50 */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 88- 95 */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* - -103 60 */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 104- ? */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 112-119 70 */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 120- " */ + 0x00,0x08,0x08,0x08,0x08,0x08,0x08,0x00, /* 128- g 80 */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* h -143 */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 144- p 90 */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* q -159 */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 160- x A0 */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* y -175 */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* ^ -183 B0 */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 184-191 */ + 0x00,0x08,0x08,0x08,0x08,0x08,0x08,0x00, /* { - G C0 */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* H -207 */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* } - P D0 */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* Q -223 */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* \ - X E0 */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* Y -239 */ + 0x0c,0x0c,0x0c,0x0c,0x0c,0x0c,0x0c,0x0c, /* 0 - 7 F0 */ + 0x0c,0x0c,0x00,0x00,0x00,0x00,0x00,0x00};/* 8 -255 */ + +static const unsigned char ebcdic_chartab[] = { /* chartable partial dup */ + 0x80,0x00,0x00,0x00,0x00,0x01,0x00,0x00, /* 0- 7 */ + 0x00,0x00,0x00,0x00,0x01,0x01,0x00,0x00, /* 8- 15 */ + 0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x00, /* 16- 23 */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 24- 31 */ + 0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x00, /* 32- 39 */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 40- 47 */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 48- 55 */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 56- 63 */ + 0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* - 71 */ + 0x00,0x00,0x00,0x80,0x00,0x80,0x80,0x80, /* 72- | */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* & - 87 */ + 0x00,0x00,0x00,0x80,0x80,0x80,0x00,0x00, /* 88- 95 */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* - -103 */ + 0x00,0x00,0x00,0x00,0x00,0x10,0x00,0x80, /* 104- ? */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 112-119 */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 120- " */ + 0x00,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x12, /* 128- g */ + 0x12,0x12,0x00,0x00,0x00,0x00,0x00,0x00, /* h -143 */ + 0x00,0x12,0x12,0x12,0x12,0x12,0x12,0x12, /* 144- p */ + 0x12,0x12,0x00,0x00,0x00,0x00,0x00,0x00, /* q -159 */ + 0x00,0x00,0x12,0x12,0x12,0x12,0x12,0x12, /* 160- x */ + 0x12,0x12,0x00,0x00,0x00,0x00,0x00,0x00, /* y -175 */ + 0x80,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* ^ -183 */ + 0x00,0x00,0x80,0x00,0x00,0x00,0x00,0x00, /* 184-191 */ + 0x80,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x12, /* { - G */ + 0x12,0x12,0x00,0x00,0x00,0x00,0x00,0x00, /* H -207 */ + 0x00,0x12,0x12,0x12,0x12,0x12,0x12,0x12, /* } - P */ + 0x12,0x12,0x00,0x00,0x00,0x00,0x00,0x00, /* Q -223 */ + 0x00,0x00,0x12,0x12,0x12,0x12,0x12,0x12, /* \ - X */ + 0x12,0x12,0x00,0x00,0x00,0x00,0x00,0x00, /* Y -239 */ + 0x1c,0x1c,0x1c,0x1c,0x1c,0x1c,0x1c,0x1c, /* 0 - 7 */ + 0x1c,0x1c,0x00,0x00,0x00,0x00,0x00,0x00};/* 8 -255 */ +#endif + + +/* Definition to allow mutual recursion */ + +static BOOL + compile_regex(int, int, uschar **, const uschar **, int *, BOOL, BOOL, int, + int *, int *, branch_chain *, compile_data *, int *); + + + +/************************************************* +* Find an error text * +*************************************************/ + +/* The error texts are now all in one long string, to save on relocations. As +some of the text is of unknown length, we can't use a table of offsets. +Instead, just count through the strings. This is not a performance issue +because it happens only when there has been a compilation error. + +Argument: the error number +Returns: pointer to the error string +*/ + +static const char * +find_error_text(int n) +{ +const char *s = error_texts; +for (; n > 0; n--) while (*s++ != 0); +return s; +} + + +/************************************************* +* Handle escapes * +*************************************************/ + +/* This function is called when a \ has been encountered. It either returns a +positive value for a simple escape such as \n, or a negative value which +encodes one of the more complicated things such as \d. A backreference to group +n is returned as -(ESC_REF + n); ESC_REF is the highest ESC_xxx macro. When +UTF-8 is enabled, a positive value greater than 255 may be returned. On entry, +ptr is pointing at the \. On exit, it is on the final character of the escape +sequence. + +Arguments: + ptrptr points to the pattern position pointer + errorcodeptr points to the errorcode variable + bracount number of previous extracting brackets + options the options bits + isclass TRUE if inside a character class + +Returns: zero or positive => a data character + negative => a special escape sequence + on error, errorcodeptr is set +*/ + +static int +check_escape(const uschar **ptrptr, int *errorcodeptr, int bracount, + int options, BOOL isclass) +{ +BOOL utf8 = (options & PCRE_UTF8) != 0; +const uschar *ptr = *ptrptr + 1; +int c, i; + +GETCHARINCTEST(c, ptr); /* Get character value, increment pointer */ +ptr--; /* Set pointer back to the last byte */ + +/* If backslash is at the end of the pattern, it's an error. */ + +if (c == 0) *errorcodeptr = ERR1; + +/* Non-alphanumerics are literals. For digits or letters, do an initial lookup +in a table. A non-zero result is something that can be returned immediately. +Otherwise further processing may be required. */ + +#ifndef EBCDIC /* ASCII coding */ +else if (c < '0' || c > 'z') {} /* Not alphanumeric */ +else if ((i = escapes[c - '0']) != 0) c = i; + +#else /* EBCDIC coding */ +else if (c < 'a' || (ebcdic_chartab[c] & 0x0E) == 0) {} /* Not alphanumeric */ +else if ((i = escapes[c - 0x48]) != 0) c = i; +#endif + +/* Escapes that need further processing, or are illegal. */ + +else + { + const uschar *oldptr; + BOOL braced, negated; + + switch (c) + { + /* A number of Perl escapes are not handled by PCRE. We give an explicit + error. */ + + case 'l': + case 'L': + case 'N': + case 'u': + case 'U': + *errorcodeptr = ERR37; + break; + + /* \g must be followed by a number, either plain or braced. If positive, it + is an absolute backreference. If negative, it is a relative backreference. + This is a Perl 5.10 feature. Perl 5.10 also supports \g{name} as a + reference to a named group. This is part of Perl's movement towards a + unified syntax for back references. As this is synonymous with \k{name}, we + fudge it up by pretending it really was \k. */ + + case 'g': + if (ptr[1] == '{') + { + const uschar *p; + for (p = ptr+2; *p != 0 && *p != '}'; p++) + if (*p != '-' && (digitab[*p] & ctype_digit) == 0) break; + if (*p != 0 && *p != '}') + { + c = -ESC_k; + break; + } + braced = TRUE; + ptr++; + } + else braced = FALSE; + + if (ptr[1] == '-') + { + negated = TRUE; + ptr++; + } + else negated = FALSE; + + c = 0; + while ((digitab[ptr[1]] & ctype_digit) != 0) + c = c * 10 + *(++ptr) - '0'; + + if (c < 0) + { + *errorcodeptr = ERR61; + break; + } + + if (c == 0 || (braced && *(++ptr) != '}')) + { + *errorcodeptr = ERR57; + break; + } + + if (negated) + { + if (c > bracount) + { + *errorcodeptr = ERR15; + break; + } + c = bracount - (c - 1); + } + + c = -(ESC_REF + c); + break; + + /* The handling of escape sequences consisting of a string of digits + starting with one that is not zero is not straightforward. By experiment, + the way Perl works seems to be as follows: + + Outside a character class, the digits are read as a decimal number. If the + number is less than 10, or if there are that many previous extracting + left brackets, then it is a back reference. Otherwise, up to three octal + digits are read to form an escaped byte. Thus \123 is likely to be octal + 123 (cf \0123, which is octal 012 followed by the literal 3). If the octal + value is greater than 377, the least significant 8 bits are taken. Inside a + character class, \ followed by a digit is always an octal number. */ + + case '1': case '2': case '3': case '4': case '5': + case '6': case '7': case '8': case '9': + + if (!isclass) + { + oldptr = ptr; + c -= '0'; + while ((digitab[ptr[1]] & ctype_digit) != 0) + c = c * 10 + *(++ptr) - '0'; + if (c < 0) + { + *errorcodeptr = ERR61; + break; + } + if (c < 10 || c <= bracount) + { + c = -(ESC_REF + c); + break; + } + ptr = oldptr; /* Put the pointer back and fall through */ + } + + /* Handle an octal number following \. If the first digit is 8 or 9, Perl + generates a binary zero byte and treats the digit as a following literal. + Thus we have to pull back the pointer by one. */ + + if ((c = *ptr) >= '8') + { + ptr--; + c = 0; + break; + } + + /* \0 always starts an octal number, but we may drop through to here with a + larger first octal digit. The original code used just to take the least + significant 8 bits of octal numbers (I think this is what early Perls used + to do). Nowadays we allow for larger numbers in UTF-8 mode, but no more + than 3 octal digits. */ + + case '0': + c -= '0'; + while(i++ < 2 && ptr[1] >= '0' && ptr[1] <= '7') + c = c * 8 + *(++ptr) - '0'; + if (!utf8 && c > 255) *errorcodeptr = ERR51; + break; + + /* \x is complicated. \x{ddd} is a character number which can be greater + than 0xff in utf8 mode, but only if the ddd are hex digits. If not, { is + treated as a data character. */ + + case 'x': + if (ptr[1] == '{') + { + const uschar *pt = ptr + 2; + int count = 0; + + c = 0; + while ((digitab[*pt] & ctype_xdigit) != 0) + { + register int cc = *pt++; + if (c == 0 && cc == '0') continue; /* Leading zeroes */ + count++; + +#ifndef EBCDIC /* ASCII coding */ + if (cc >= 'a') cc -= 32; /* Convert to upper case */ + c = (c << 4) + cc - ((cc < 'A')? '0' : ('A' - 10)); +#else /* EBCDIC coding */ + if (cc >= 'a' && cc <= 'z') cc += 64; /* Convert to upper case */ + c = (c << 4) + cc - ((cc >= '0')? '0' : ('A' - 10)); +#endif + } + + if (*pt == '}') + { + if (c < 0 || count > (utf8? 8 : 2)) *errorcodeptr = ERR34; + ptr = pt; + break; + } + + /* If the sequence of hex digits does not end with '}', then we don't + recognize this construct; fall through to the normal \x handling. */ + } + + /* Read just a single-byte hex-defined char */ + + c = 0; + while (i++ < 2 && (digitab[ptr[1]] & ctype_xdigit) != 0) + { + int cc; /* Some compilers don't like ++ */ + cc = *(++ptr); /* in initializers */ +#ifndef EBCDIC /* ASCII coding */ + if (cc >= 'a') cc -= 32; /* Convert to upper case */ + c = c * 16 + cc - ((cc < 'A')? '0' : ('A' - 10)); +#else /* EBCDIC coding */ + if (cc <= 'z') cc += 64; /* Convert to upper case */ + c = c * 16 + cc - ((cc >= '0')? '0' : ('A' - 10)); +#endif + } + break; + + /* For \c, a following letter is upper-cased; then the 0x40 bit is flipped. + This coding is ASCII-specific, but then the whole concept of \cx is + ASCII-specific. (However, an EBCDIC equivalent has now been added.) */ + + case 'c': + c = *(++ptr); + if (c == 0) + { + *errorcodeptr = ERR2; + break; + } + +#ifndef EBCDIC /* ASCII coding */ + if (c >= 'a' && c <= 'z') c -= 32; + c ^= 0x40; +#else /* EBCDIC coding */ + if (c >= 'a' && c <= 'z') c += 64; + c ^= 0xC0; +#endif + break; + + /* PCRE_EXTRA enables extensions to Perl in the matter of escapes. Any + other alphanumeric following \ is an error if PCRE_EXTRA was set; + otherwise, for Perl compatibility, it is a literal. This code looks a bit + odd, but there used to be some cases other than the default, and there may + be again in future, so I haven't "optimized" it. */ + + default: + if ((options & PCRE_EXTRA) != 0) switch(c) + { + default: + *errorcodeptr = ERR3; + break; + } + break; + } + } + +*ptrptr = ptr; +return c; +} + + + +#ifdef SUPPORT_UCP +/************************************************* +* Handle \P and \p * +*************************************************/ + +/* This function is called after \P or \p has been encountered, provided that +PCRE is compiled with support for Unicode properties. On entry, ptrptr is +pointing at the P or p. On exit, it is pointing at the final character of the +escape sequence. + +Argument: + ptrptr points to the pattern position pointer + negptr points to a boolean that is set TRUE for negation else FALSE + dptr points to an int that is set to the detailed property value + errorcodeptr points to the error code variable + +Returns: type value from ucp_type_table, or -1 for an invalid type +*/ + +static int +get_ucp(const uschar **ptrptr, BOOL *negptr, int *dptr, int *errorcodeptr) +{ +int c, i, bot, top; +const uschar *ptr = *ptrptr; +char name[32]; + +c = *(++ptr); +if (c == 0) goto ERROR_RETURN; + +*negptr = FALSE; + +/* \P or \p can be followed by a name in {}, optionally preceded by ^ for +negation. */ + +if (c == '{') + { + if (ptr[1] == '^') + { + *negptr = TRUE; + ptr++; + } + for (i = 0; i < (int)sizeof(name) - 1; i++) + { + c = *(++ptr); + if (c == 0) goto ERROR_RETURN; + if (c == '}') break; + name[i] = c; + } + if (c !='}') goto ERROR_RETURN; + name[i] = 0; + } + +/* Otherwise there is just one following character */ + +else + { + name[0] = c; + name[1] = 0; + } + +*ptrptr = ptr; + +/* Search for a recognized property name using binary chop */ + +bot = 0; +top = _pcre_utt_size; + +while (bot < top) + { + i = (bot + top) >> 1; + c = strcmp(name, _pcre_utt_names + _pcre_utt[i].name_offset); + if (c == 0) + { + *dptr = _pcre_utt[i].value; + return _pcre_utt[i].type; + } + if (c > 0) bot = i + 1; else top = i; + } + +*errorcodeptr = ERR47; +*ptrptr = ptr; +return -1; + +ERROR_RETURN: +*errorcodeptr = ERR46; +*ptrptr = ptr; +return -1; +} +#endif + + + + +/************************************************* +* Check for counted repeat * +*************************************************/ + +/* This function is called when a '{' is encountered in a place where it might +start a quantifier. It looks ahead to see if it really is a quantifier or not. +It is only a quantifier if it is one of the forms {ddd} {ddd,} or {ddd,ddd} +where the ddds are digits. + +Arguments: + p pointer to the first char after '{' + +Returns: TRUE or FALSE +*/ + +static BOOL +is_counted_repeat(const uschar *p) +{ +if ((digitab[*p++] & ctype_digit) == 0) return FALSE; +while ((digitab[*p] & ctype_digit) != 0) p++; +if (*p == '}') return TRUE; + +if (*p++ != ',') return FALSE; +if (*p == '}') return TRUE; + +if ((digitab[*p++] & ctype_digit) == 0) return FALSE; +while ((digitab[*p] & ctype_digit) != 0) p++; + +return (*p == '}'); +} + + + +/************************************************* +* Read repeat counts * +*************************************************/ + +/* Read an item of the form {n,m} and return the values. This is called only +after is_counted_repeat() has confirmed that a repeat-count quantifier exists, +so the syntax is guaranteed to be correct, but we need to check the values. + +Arguments: + p pointer to first char after '{' + minp pointer to int for min + maxp pointer to int for max + returned as -1 if no max + errorcodeptr points to error code variable + +Returns: pointer to '}' on success; + current ptr on error, with errorcodeptr set non-zero +*/ + +static const uschar * +read_repeat_counts(const uschar *p, int *minp, int *maxp, int *errorcodeptr) +{ +int min = 0; +int max = -1; + +/* Read the minimum value and do a paranoid check: a negative value indicates +an integer overflow. */ + +while ((digitab[*p] & ctype_digit) != 0) min = min * 10 + *p++ - '0'; +if (min < 0 || min > 65535) + { + *errorcodeptr = ERR5; + return p; + } + +/* Read the maximum value if there is one, and again do a paranoid on its size. +Also, max must not be less than min. */ + +if (*p == '}') max = min; else + { + if (*(++p) != '}') + { + max = 0; + while((digitab[*p] & ctype_digit) != 0) max = max * 10 + *p++ - '0'; + if (max < 0 || max > 65535) + { + *errorcodeptr = ERR5; + return p; + } + if (max < min) + { + *errorcodeptr = ERR4; + return p; + } + } + } + +/* Fill in the required variables, and pass back the pointer to the terminating +'}'. */ + +*minp = min; +*maxp = max; +return p; +} + + + +/************************************************* +* Find forward referenced subpattern * +*************************************************/ + +/* This function scans along a pattern's text looking for capturing +subpatterns, and counting them. If it finds a named pattern that matches the +name it is given, it returns its number. Alternatively, if the name is NULL, it +returns when it reaches a given numbered subpattern. This is used for forward +references to subpatterns. We know that if (?P< is encountered, the name will +be terminated by '>' because that is checked in the first pass. + +Arguments: + ptr current position in the pattern + count current count of capturing parens so far encountered + name name to seek, or NULL if seeking a numbered subpattern + lorn name length, or subpattern number if name is NULL + xmode TRUE if we are in /x mode + +Returns: the number of the named subpattern, or -1 if not found +*/ + +static int +find_parens(const uschar *ptr, int count, const uschar *name, int lorn, + BOOL xmode) +{ +const uschar *thisname; + +for (; *ptr != 0; ptr++) + { + int term; + + /* Skip over backslashed characters and also entire \Q...\E */ + + if (*ptr == '\\') + { + if (*(++ptr) == 0) return -1; + if (*ptr == 'Q') for (;;) + { + while (*(++ptr) != 0 && *ptr != '\\'); + if (*ptr == 0) return -1; + if (*(++ptr) == 'E') break; + } + continue; + } + + /* Skip over character classes */ + + if (*ptr == '[') + { + while (*(++ptr) != ']') + { + if (*ptr == 0) return -1; + if (*ptr == '\\') + { + if (*(++ptr) == 0) return -1; + if (*ptr == 'Q') for (;;) + { + while (*(++ptr) != 0 && *ptr != '\\'); + if (*ptr == 0) return -1; + if (*(++ptr) == 'E') break; + } + continue; + } + } + continue; + } + + /* Skip comments in /x mode */ + + if (xmode && *ptr == '#') + { + while (*(++ptr) != 0 && *ptr != '\n'); + if (*ptr == 0) return -1; + continue; + } + + /* An opening parens must now be a real metacharacter */ + + if (*ptr != '(') continue; + if (ptr[1] != '?' && ptr[1] != '*') + { + count++; + if (name == NULL && count == lorn) return count; + continue; + } + + ptr += 2; + if (*ptr == 'P') ptr++; /* Allow optional P */ + + /* We have to disambiguate (? */ + + if ((*ptr != '<' || ptr[1] == '!' || ptr[1] == '=') && + *ptr != '\'') + continue; + + count++; + + if (name == NULL && count == lorn) return count; + term = *ptr++; + if (term == '<') term = '>'; + thisname = ptr; + while (*ptr != term) ptr++; + if (name != NULL && lorn == ptr - thisname && + strncmp((const char *)name, (const char *)thisname, lorn) == 0) + return count; + } + +return -1; +} + + + +/************************************************* +* Find first significant op code * +*************************************************/ + +/* This is called by several functions that scan a compiled expression looking +for a fixed first character, or an anchoring op code etc. It skips over things +that do not influence this. For some calls, a change of option is important. +For some calls, it makes sense to skip negative forward and all backward +assertions, and also the \b assertion; for others it does not. + +Arguments: + code pointer to the start of the group + options pointer to external options + optbit the option bit whose changing is significant, or + zero if none are + skipassert TRUE if certain assertions are to be skipped + +Returns: pointer to the first significant opcode +*/ + +static const uschar* +first_significant_code(const uschar *code, int *options, int optbit, + BOOL skipassert) +{ +for (;;) + { + switch ((int)*code) + { + case OP_OPT: + if (optbit > 0 && ((int)code[1] & optbit) != (*options & optbit)) + *options = (int)code[1]; + code += 2; + break; + + case OP_ASSERT_NOT: + case OP_ASSERTBACK: + case OP_ASSERTBACK_NOT: + if (!skipassert) return code; + do code += GET(code, 1); while (*code == OP_ALT); + code += _pcre_OP_lengths[*code]; + break; + + case OP_WORD_BOUNDARY: + case OP_NOT_WORD_BOUNDARY: + if (!skipassert) return code; + /* Fall through */ + + case OP_CALLOUT: + case OP_CREF: + case OP_RREF: + case OP_DEF: + code += _pcre_OP_lengths[*code]; + break; + + default: + return code; + } + } +/* Control never reaches here */ +} + + + + +/************************************************* +* Find the fixed length of a pattern * +*************************************************/ + +/* Scan a pattern and compute the fixed length of subject that will match it, +if the length is fixed. This is needed for dealing with backward assertions. +In UTF8 mode, the result is in characters rather than bytes. + +Arguments: + code points to the start of the pattern (the bracket) + options the compiling options + +Returns: the fixed length, or -1 if there is no fixed length, + or -2 if \C was encountered +*/ + +static int +find_fixedlength(uschar *code, int options) +{ +int length = -1; + +register int branchlength = 0; +register uschar *cc = code + 1 + LINK_SIZE; + +/* Scan along the opcodes for this branch. If we get to the end of the +branch, check the length against that of the other branches. */ + +for (;;) + { + int d; + register int op = *cc; + switch (op) + { + case OP_CBRA: + case OP_BRA: + case OP_ONCE: + case OP_COND: + d = find_fixedlength(cc + ((op == OP_CBRA)? 2:0), options); + if (d < 0) return d; + branchlength += d; + do cc += GET(cc, 1); while (*cc == OP_ALT); + cc += 1 + LINK_SIZE; + break; + + /* Reached end of a branch; if it's a ket it is the end of a nested + call. If it's ALT it is an alternation in a nested call. If it is + END it's the end of the outer call. All can be handled by the same code. */ + + case OP_ALT: + case OP_KET: + case OP_KETRMAX: + case OP_KETRMIN: + case OP_END: + if (length < 0) length = branchlength; + else if (length != branchlength) return -1; + if (*cc != OP_ALT) return length; + cc += 1 + LINK_SIZE; + branchlength = 0; + break; + + /* Skip over assertive subpatterns */ + + case OP_ASSERT: + case OP_ASSERT_NOT: + case OP_ASSERTBACK: + case OP_ASSERTBACK_NOT: + do cc += GET(cc, 1); while (*cc == OP_ALT); + /* Fall through */ + + /* Skip over things that don't match chars */ + + case OP_REVERSE: + case OP_CREF: + case OP_RREF: + case OP_DEF: + case OP_OPT: + case OP_CALLOUT: + case OP_SOD: + case OP_SOM: + case OP_EOD: + case OP_EODN: + case OP_CIRC: + case OP_DOLL: + case OP_NOT_WORD_BOUNDARY: + case OP_WORD_BOUNDARY: + cc += _pcre_OP_lengths[*cc]; + break; + + /* Handle literal characters */ + + case OP_CHAR: + case OP_CHARNC: + case OP_NOT: + branchlength++; + cc += 2; +#ifdef SUPPORT_UTF8 + if ((options & PCRE_UTF8) != 0) + { + while ((*cc & 0xc0) == 0x80) cc++; + } +#endif + break; + + /* Handle exact repetitions. The count is already in characters, but we + need to skip over a multibyte character in UTF8 mode. */ + + case OP_EXACT: + branchlength += GET2(cc,1); + cc += 4; +#ifdef SUPPORT_UTF8 + if ((options & PCRE_UTF8) != 0) + { + while((*cc & 0x80) == 0x80) cc++; + } +#endif + break; + + case OP_TYPEEXACT: + branchlength += GET2(cc,1); + if (cc[3] == OP_PROP || cc[3] == OP_NOTPROP) cc += 2; + cc += 4; + break; + + /* Handle single-char matchers */ + + case OP_PROP: + case OP_NOTPROP: + cc += 2; + /* Fall through */ + + case OP_NOT_DIGIT: + case OP_DIGIT: + case OP_NOT_WHITESPACE: + case OP_WHITESPACE: + case OP_NOT_WORDCHAR: + case OP_WORDCHAR: + case OP_ANY: + branchlength++; + cc++; + break; + + /* The single-byte matcher isn't allowed */ + + case OP_ANYBYTE: + return -2; + + /* Check a class for variable quantification */ + +#ifdef SUPPORT_UTF8 + case OP_XCLASS: + cc += GET(cc, 1) - 33; + /* Fall through */ +#endif + + case OP_CLASS: + case OP_NCLASS: + cc += 33; + + switch (*cc) + { + case OP_CRSTAR: + case OP_CRMINSTAR: + case OP_CRQUERY: + case OP_CRMINQUERY: + return -1; + + case OP_CRRANGE: + case OP_CRMINRANGE: + if (GET2(cc,1) != GET2(cc,3)) return -1; + branchlength += GET2(cc,1); + cc += 5; + break; + + default: + branchlength++; + } + break; + + /* Anything else is variable length */ + + default: + return -1; + } + } +/* Control never gets here */ +} + + + + +/************************************************* +* Scan compiled regex for numbered bracket * +*************************************************/ + +/* This little function scans through a compiled pattern until it finds a +capturing bracket with the given number. + +Arguments: + code points to start of expression + utf8 TRUE in UTF-8 mode + number the required bracket number + +Returns: pointer to the opcode for the bracket, or NULL if not found +*/ + +static const uschar * +find_bracket(const uschar *code, BOOL utf8, int number) +{ +for (;;) + { + register int c = *code; + if (c == OP_END) return NULL; + + /* XCLASS is used for classes that cannot be represented just by a bit + map. This includes negated single high-valued characters. The length in + the table is zero; the actual length is stored in the compiled code. */ + + if (c == OP_XCLASS) code += GET(code, 1); + + /* Handle capturing bracket */ + + else if (c == OP_CBRA) + { + int n = GET2(code, 1+LINK_SIZE); + if (n == number) return (uschar *)code; + code += _pcre_OP_lengths[c]; + } + + /* Otherwise, we can get the item's length from the table, except that for + repeated character types, we have to test for \p and \P, which have an extra + two bytes of parameters. */ + + else + { + switch(c) + { + case OP_TYPESTAR: + case OP_TYPEMINSTAR: + case OP_TYPEPLUS: + case OP_TYPEMINPLUS: + case OP_TYPEQUERY: + case OP_TYPEMINQUERY: + case OP_TYPEPOSSTAR: + case OP_TYPEPOSPLUS: + case OP_TYPEPOSQUERY: + if (code[1] == OP_PROP || code[1] == OP_NOTPROP) code += 2; + break; + + case OP_TYPEUPTO: + case OP_TYPEMINUPTO: + case OP_TYPEEXACT: + case OP_TYPEPOSUPTO: + if (code[3] == OP_PROP || code[3] == OP_NOTPROP) code += 2; + break; + } + + /* Add in the fixed length from the table */ + + code += _pcre_OP_lengths[c]; + + /* In UTF-8 mode, opcodes that are followed by a character may be followed by + a multi-byte character. The length in the table is a minimum, so we have to + arrange to skip the extra bytes. */ + +#ifdef SUPPORT_UTF8 + if (utf8) switch(c) + { + case OP_CHAR: + case OP_CHARNC: + case OP_EXACT: + case OP_UPTO: + case OP_MINUPTO: + case OP_POSUPTO: + case OP_STAR: + case OP_MINSTAR: + case OP_POSSTAR: + case OP_PLUS: + case OP_MINPLUS: + case OP_POSPLUS: + case OP_QUERY: + case OP_MINQUERY: + case OP_POSQUERY: + if (code[-1] >= 0xc0) code += _pcre_utf8_table4[code[-1] & 0x3f]; + break; + } +#endif + } + } +} + + + +/************************************************* +* Scan compiled regex for recursion reference * +*************************************************/ + +/* This little function scans through a compiled pattern until it finds an +instance of OP_RECURSE. + +Arguments: + code points to start of expression + utf8 TRUE in UTF-8 mode + +Returns: pointer to the opcode for OP_RECURSE, or NULL if not found +*/ + +static const uschar * +find_recurse(const uschar *code, BOOL utf8) +{ +for (;;) + { + register int c = *code; + if (c == OP_END) return NULL; + if (c == OP_RECURSE) return code; + + /* XCLASS is used for classes that cannot be represented just by a bit + map. This includes negated single high-valued characters. The length in + the table is zero; the actual length is stored in the compiled code. */ + + if (c == OP_XCLASS) code += GET(code, 1); + + /* Otherwise, we can get the item's length from the table, except that for + repeated character types, we have to test for \p and \P, which have an extra + two bytes of parameters. */ + + else + { + switch(c) + { + case OP_TYPESTAR: + case OP_TYPEMINSTAR: + case OP_TYPEPLUS: + case OP_TYPEMINPLUS: + case OP_TYPEQUERY: + case OP_TYPEMINQUERY: + case OP_TYPEPOSSTAR: + case OP_TYPEPOSPLUS: + case OP_TYPEPOSQUERY: + if (code[1] == OP_PROP || code[1] == OP_NOTPROP) code += 2; + break; + + case OP_TYPEPOSUPTO: + case OP_TYPEUPTO: + case OP_TYPEMINUPTO: + case OP_TYPEEXACT: + if (code[3] == OP_PROP || code[3] == OP_NOTPROP) code += 2; + break; + } + + /* Add in the fixed length from the table */ + + code += _pcre_OP_lengths[c]; + + /* In UTF-8 mode, opcodes that are followed by a character may be followed + by a multi-byte character. The length in the table is a minimum, so we have + to arrange to skip the extra bytes. */ + +#ifdef SUPPORT_UTF8 + if (utf8) switch(c) + { + case OP_CHAR: + case OP_CHARNC: + case OP_EXACT: + case OP_UPTO: + case OP_MINUPTO: + case OP_POSUPTO: + case OP_STAR: + case OP_MINSTAR: + case OP_POSSTAR: + case OP_PLUS: + case OP_MINPLUS: + case OP_POSPLUS: + case OP_QUERY: + case OP_MINQUERY: + case OP_POSQUERY: + if (code[-1] >= 0xc0) code += _pcre_utf8_table4[code[-1] & 0x3f]; + break; + } +#endif + } + } +} + + + +/************************************************* +* Scan compiled branch for non-emptiness * +*************************************************/ + +/* This function scans through a branch of a compiled pattern to see whether it +can match the empty string or not. It is called from could_be_empty() +below and from compile_branch() when checking for an unlimited repeat of a +group that can match nothing. Note that first_significant_code() skips over +backward and negative forward assertions when its final argument is TRUE. If we +hit an unclosed bracket, we return "empty" - this means we've struck an inner +bracket whose current branch will already have been scanned. + +Arguments: + code points to start of search + endcode points to where to stop + utf8 TRUE if in UTF8 mode + +Returns: TRUE if what is matched could be empty +*/ + +static BOOL +could_be_empty_branch(const uschar *code, const uschar *endcode, BOOL utf8) +{ +register int c; +for (code = first_significant_code(code + _pcre_OP_lengths[*code], NULL, 0, TRUE); + code < endcode; + code = first_significant_code(code + _pcre_OP_lengths[c], NULL, 0, TRUE)) + { + const uschar *ccode; + + c = *code; + + /* Skip over forward assertions; the other assertions are skipped by + first_significant_code() with a TRUE final argument. */ + + if (c == OP_ASSERT) + { + do code += GET(code, 1); while (*code == OP_ALT); + c = *code; + continue; + } + + /* Groups with zero repeats can of course be empty; skip them. */ + + if (c == OP_BRAZERO || c == OP_BRAMINZERO) + { + code += _pcre_OP_lengths[c]; + do code += GET(code, 1); while (*code == OP_ALT); + c = *code; + continue; + } + + /* For other groups, scan the branches. */ + + if (c == OP_BRA || c == OP_CBRA || c == OP_ONCE || c == OP_COND) + { + BOOL empty_branch; + if (GET(code, 1) == 0) return TRUE; /* Hit unclosed bracket */ + + /* Scan a closed bracket */ + + empty_branch = FALSE; + do + { + if (!empty_branch && could_be_empty_branch(code, endcode, utf8)) + empty_branch = TRUE; + code += GET(code, 1); + } + while (*code == OP_ALT); + if (!empty_branch) return FALSE; /* All branches are non-empty */ + c = *code; + continue; + } + + /* Handle the other opcodes */ + + switch (c) + { + /* Check for quantifiers after a class. XCLASS is used for classes that + cannot be represented just by a bit map. This includes negated single + high-valued characters. The length in _pcre_OP_lengths[] is zero; the + actual length is stored in the compiled code, so we must update "code" + here. */ + +#ifdef SUPPORT_UTF8 + case OP_XCLASS: + ccode = code += GET(code, 1); + goto CHECK_CLASS_REPEAT; +#endif + + case OP_CLASS: + case OP_NCLASS: + ccode = code + 33; + +#ifdef SUPPORT_UTF8 + CHECK_CLASS_REPEAT: +#endif + + switch (*ccode) + { + case OP_CRSTAR: /* These could be empty; continue */ + case OP_CRMINSTAR: + case OP_CRQUERY: + case OP_CRMINQUERY: + break; + + default: /* Non-repeat => class must match */ + case OP_CRPLUS: /* These repeats aren't empty */ + case OP_CRMINPLUS: + return FALSE; + + case OP_CRRANGE: + case OP_CRMINRANGE: + if (GET2(ccode, 1) > 0) return FALSE; /* Minimum > 0 */ + break; + } + break; + + /* Opcodes that must match a character */ + + case OP_PROP: + case OP_NOTPROP: + case OP_EXTUNI: + case OP_NOT_DIGIT: + case OP_DIGIT: + case OP_NOT_WHITESPACE: + case OP_WHITESPACE: + case OP_NOT_WORDCHAR: + case OP_WORDCHAR: + case OP_ANY: + case OP_ANYBYTE: + case OP_CHAR: + case OP_CHARNC: + case OP_NOT: + case OP_PLUS: + case OP_MINPLUS: + case OP_POSPLUS: + case OP_EXACT: + case OP_NOTPLUS: + case OP_NOTMINPLUS: + case OP_NOTPOSPLUS: + case OP_NOTEXACT: + case OP_TYPEPLUS: + case OP_TYPEMINPLUS: + case OP_TYPEPOSPLUS: + case OP_TYPEEXACT: + return FALSE; + + /* These are going to continue, as they may be empty, but we have to + fudge the length for the \p and \P cases. */ + + case OP_TYPESTAR: + case OP_TYPEMINSTAR: + case OP_TYPEPOSSTAR: + case OP_TYPEQUERY: + case OP_TYPEMINQUERY: + case OP_TYPEPOSQUERY: + if (code[1] == OP_PROP || code[1] == OP_NOTPROP) code += 2; + break; + + /* Same for these */ + + case OP_TYPEUPTO: + case OP_TYPEMINUPTO: + case OP_TYPEPOSUPTO: + if (code[3] == OP_PROP || code[3] == OP_NOTPROP) code += 2; + break; + + /* End of branch */ + + case OP_KET: + case OP_KETRMAX: + case OP_KETRMIN: + case OP_ALT: + return TRUE; + + /* In UTF-8 mode, STAR, MINSTAR, POSSTAR, QUERY, MINQUERY, POSQUERY, UPTO, + MINUPTO, and POSUPTO may be followed by a multibyte character */ + +#ifdef SUPPORT_UTF8 + case OP_STAR: + case OP_MINSTAR: + case OP_POSSTAR: + case OP_QUERY: + case OP_MINQUERY: + case OP_POSQUERY: + case OP_UPTO: + case OP_MINUPTO: + case OP_POSUPTO: + if (utf8) while ((code[2] & 0xc0) == 0x80) code++; + break; +#endif + } + } + +return TRUE; +} + + + +/************************************************* +* Scan compiled regex for non-emptiness * +*************************************************/ + +/* This function is called to check for left recursive calls. We want to check +the current branch of the current pattern to see if it could match the empty +string. If it could, we must look outwards for branches at other levels, +stopping when we pass beyond the bracket which is the subject of the recursion. + +Arguments: + code points to start of the recursion + endcode points to where to stop (current RECURSE item) + bcptr points to the chain of current (unclosed) branch starts + utf8 TRUE if in UTF-8 mode + +Returns: TRUE if what is matched could be empty +*/ + +static BOOL +could_be_empty(const uschar *code, const uschar *endcode, branch_chain *bcptr, + BOOL utf8) +{ +while (bcptr != NULL && bcptr->current >= code) + { + if (!could_be_empty_branch(bcptr->current, endcode, utf8)) return FALSE; + bcptr = bcptr->outer; + } +return TRUE; +} + + + +/************************************************* +* Check for POSIX class syntax * +*************************************************/ + +/* This function is called when the sequence "[:" or "[." or "[=" is +encountered in a character class. It checks whether this is followed by a +sequence of characters terminated by a matching ":]" or ".]" or "=]". If we +reach an unescaped ']' without the special preceding character, return FALSE. + +Originally, this function only recognized a sequence of letters between the +terminators, but it seems that Perl recognizes any sequence of characters, +though of course unknown POSIX names are subsequently rejected. Perl gives an +"Unknown POSIX class" error for [:f\oo:] for example, where previously PCRE +didn't consider this to be a POSIX class. Likewise for [:1234:]. + +The problem in trying to be exactly like Perl is in the handling of escapes. We +have to be sure that [abc[:x\]pqr] is *not* treated as containing a POSIX +class, but [abc[:x\]pqr:]] is (so that an error can be generated). The code +below handles the special case of \], but does not try to do any other escape +processing. This makes it different from Perl for cases such as [:l\ower:] +where Perl recognizes it as the POSIX class "lower" but PCRE does not recognize +"l\ower". This is a lesser evil that not diagnosing bad classes when Perl does, +I think. + +Arguments: + ptr pointer to the initial [ + endptr where to return the end pointer + +Returns: TRUE or FALSE +*/ + +static BOOL +check_posix_syntax(const uschar *ptr, const uschar **endptr) +{ +int terminator; /* Don't combine these lines; the Solaris cc */ +terminator = *(++ptr); /* compiler warns about "non-constant" initializer. */ +for (++ptr; *ptr != 0; ptr++) + { + if (*ptr == '\\' && ptr[1] == ']') ptr++; else + { + if (*ptr == ']') return FALSE; + if (*ptr == terminator && ptr[1] == ']') + { + *endptr = ptr; + return TRUE; + } + } + } +return FALSE; +} + + + + +/************************************************* +* Check POSIX class name * +*************************************************/ + +/* This function is called to check the name given in a POSIX-style class entry +such as [:alnum:]. + +Arguments: + ptr points to the first letter + len the length of the name + +Returns: a value representing the name, or -1 if unknown +*/ + +static int +check_posix_name(const uschar *ptr, int len) +{ +const char *pn = posix_names; +register int yield = 0; +while (posix_name_lengths[yield] != 0) + { + if (len == posix_name_lengths[yield] && + strncmp((const char *)ptr, pn, len) == 0) return yield; + pn += posix_name_lengths[yield] + 1; + yield++; + } +return -1; +} + + +/************************************************* +* Adjust OP_RECURSE items in repeated group * +*************************************************/ + +/* OP_RECURSE items contain an offset from the start of the regex to the group +that is referenced. This means that groups can be replicated for fixed +repetition simply by copying (because the recursion is allowed to refer to +earlier groups that are outside the current group). However, when a group is +optional (i.e. the minimum quantifier is zero), OP_BRAZERO is inserted before +it, after it has been compiled. This means that any OP_RECURSE items within it +that refer to the group itself or any contained groups have to have their +offsets adjusted. That one of the jobs of this function. Before it is called, +the partially compiled regex must be temporarily terminated with OP_END. + +This function has been extended with the possibility of forward references for +recursions and subroutine calls. It must also check the list of such references +for the group we are dealing with. If it finds that one of the recursions in +the current group is on this list, it adjusts the offset in the list, not the +value in the reference (which is a group number). + +Arguments: + group points to the start of the group + adjust the amount by which the group is to be moved + utf8 TRUE in UTF-8 mode + cd contains pointers to tables etc. + save_hwm the hwm forward reference pointer at the start of the group + +Returns: nothing +*/ + +static void +adjust_recurse(uschar *group, int adjust, BOOL utf8, compile_data *cd, + uschar *save_hwm) +{ +uschar *ptr = group; + +while ((ptr = (uschar *)find_recurse(ptr, utf8)) != NULL) + { + int offset; + uschar *hc; + + /* See if this recursion is on the forward reference list. If so, adjust the + reference. */ + + for (hc = save_hwm; hc < cd->hwm; hc += LINK_SIZE) + { + offset = GET(hc, 0); + if (cd->start_code + offset == ptr + 1) + { + PUT(hc, 0, offset + adjust); + break; + } + } + + /* Otherwise, adjust the recursion offset if it's after the start of this + group. */ + + if (hc >= cd->hwm) + { + offset = GET(ptr, 1); + if (cd->start_code + offset >= group) PUT(ptr, 1, offset + adjust); + } + + ptr += 1 + LINK_SIZE; + } +} + + + +/************************************************* +* Insert an automatic callout point * +*************************************************/ + +/* This function is called when the PCRE_AUTO_CALLOUT option is set, to insert +callout points before each pattern item. + +Arguments: + code current code pointer + ptr current pattern pointer + cd pointers to tables etc + +Returns: new code pointer +*/ + +static uschar * +auto_callout(uschar *code, const uschar *ptr, compile_data *cd) +{ +*code++ = OP_CALLOUT; +*code++ = 255; +PUT(code, 0, ptr - cd->start_pattern); /* Pattern offset */ +PUT(code, LINK_SIZE, 0); /* Default length */ +return code + 2*LINK_SIZE; +} + + + +/************************************************* +* Complete a callout item * +*************************************************/ + +/* A callout item contains the length of the next item in the pattern, which +we can't fill in till after we have reached the relevant point. This is used +for both automatic and manual callouts. + +Arguments: + previous_callout points to previous callout item + ptr current pattern pointer + cd pointers to tables etc + +Returns: nothing +*/ + +static void +complete_callout(uschar *previous_callout, const uschar *ptr, compile_data *cd) +{ +int length = ptr - cd->start_pattern - GET(previous_callout, 2); +PUT(previous_callout, 2 + LINK_SIZE, length); +} + + + +#ifdef SUPPORT_UCP +/************************************************* +* Get othercase range * +*************************************************/ + +/* This function is passed the start and end of a class range, in UTF-8 mode +with UCP support. It searches up the characters, looking for internal ranges of +characters in the "other" case. Each call returns the next one, updating the +start address. + +Arguments: + cptr points to starting character value; updated + d end value + ocptr where to put start of othercase range + odptr where to put end of othercase range + +Yield: TRUE when range returned; FALSE when no more +*/ + +static BOOL +get_othercase_range(unsigned int *cptr, unsigned int d, unsigned int *ocptr, + unsigned int *odptr) +{ +unsigned int c, othercase, next; + +for (c = *cptr; c <= d; c++) + { if ((othercase = _pcre_ucp_othercase(c)) != NOTACHAR) break; } + +if (c > d) return FALSE; + +*ocptr = othercase; +next = othercase + 1; + +for (++c; c <= d; c++) + { + if (_pcre_ucp_othercase(c) != next) break; + next++; + } + +*odptr = next - 1; +*cptr = c; + +return TRUE; +} +#endif /* SUPPORT_UCP */ + + + +/************************************************* +* Check if auto-possessifying is possible * +*************************************************/ + +/* This function is called for unlimited repeats of certain items, to see +whether the next thing could possibly match the repeated item. If not, it makes +sense to automatically possessify the repeated item. + +Arguments: + op_code the repeated op code + this data for this item, depends on the opcode + utf8 TRUE in UTF-8 mode + utf8_char used for utf8 character bytes, NULL if not relevant + ptr next character in pattern + options options bits + cd contains pointers to tables etc. + +Returns: TRUE if possessifying is wanted +*/ + +static BOOL +check_auto_possessive(int op_code, int item, BOOL utf8, uschar *utf8_char, + const uschar *ptr, int options, compile_data *cd) +{ +int next; + +/* Skip whitespace and comments in extended mode */ + +if ((options & PCRE_EXTENDED) != 0) + { + for (;;) + { + while ((cd->ctypes[*ptr] & ctype_space) != 0) ptr++; + if (*ptr == '#') + { + while (*(++ptr) != 0) + if (IS_NEWLINE(ptr)) { ptr += cd->nllen; break; } + } + else break; + } + } + +/* If the next item is one that we can handle, get its value. A non-negative +value is a character, a negative value is an escape value. */ + +if (*ptr == '\\') + { + int temperrorcode = 0; + next = check_escape(&ptr, &temperrorcode, cd->bracount, options, FALSE); + if (temperrorcode != 0) return FALSE; + ptr++; /* Point after the escape sequence */ + } + +else if ((cd->ctypes[*ptr] & ctype_meta) == 0) + { +#ifdef SUPPORT_UTF8 + if (utf8) { GETCHARINC(next, ptr); } else +#endif + next = *ptr++; + } + +else return FALSE; + +/* Skip whitespace and comments in extended mode */ + +if ((options & PCRE_EXTENDED) != 0) + { + for (;;) + { + while ((cd->ctypes[*ptr] & ctype_space) != 0) ptr++; + if (*ptr == '#') + { + while (*(++ptr) != 0) + if (IS_NEWLINE(ptr)) { ptr += cd->nllen; break; } + } + else break; + } + } + +/* If the next thing is itself optional, we have to give up. */ + +if (*ptr == '*' || *ptr == '?' || strncmp((char *)ptr, "{0,", 3) == 0) + return FALSE; + +/* Now compare the next item with the previous opcode. If the previous is a +positive single character match, "item" either contains the character or, if +"item" is greater than 127 in utf8 mode, the character's bytes are in +utf8_char. */ + + +/* Handle cases when the next item is a character. */ + +if (next >= 0) switch(op_code) + { + case OP_CHAR: +#ifdef SUPPORT_UTF8 + if (utf8 && item > 127) { GETCHAR(item, utf8_char); } +#endif + return item != next; + + /* For CHARNC (caseless character) we must check the other case. If we have + Unicode property support, we can use it to test the other case of + high-valued characters. */ + + case OP_CHARNC: +#ifdef SUPPORT_UTF8 + if (utf8 && item > 127) { GETCHAR(item, utf8_char); } +#endif + if (item == next) return FALSE; +#ifdef SUPPORT_UTF8 + if (utf8) + { + unsigned int othercase; + if (next < 128) othercase = cd->fcc[next]; else +#ifdef SUPPORT_UCP + othercase = _pcre_ucp_othercase((unsigned int)next); +#else + othercase = NOTACHAR; +#endif + return (unsigned int)item != othercase; + } + else +#endif /* SUPPORT_UTF8 */ + return (item != cd->fcc[next]); /* Non-UTF-8 mode */ + + /* For OP_NOT, "item" must be a single-byte character. */ + + case OP_NOT: + if (next < 0) return FALSE; /* Not a character */ + if (item == next) return TRUE; + if ((options & PCRE_CASELESS) == 0) return FALSE; +#ifdef SUPPORT_UTF8 + if (utf8) + { + unsigned int othercase; + if (next < 128) othercase = cd->fcc[next]; else +#ifdef SUPPORT_UCP + othercase = _pcre_ucp_othercase(next); +#else + othercase = NOTACHAR; +#endif + return (unsigned int)item == othercase; + } + else +#endif /* SUPPORT_UTF8 */ + return (item == cd->fcc[next]); /* Non-UTF-8 mode */ + + case OP_DIGIT: + return next > 127 || (cd->ctypes[next] & ctype_digit) == 0; + + case OP_NOT_DIGIT: + return next <= 127 && (cd->ctypes[next] & ctype_digit) != 0; + + case OP_WHITESPACE: + return next > 127 || (cd->ctypes[next] & ctype_space) == 0; + + case OP_NOT_WHITESPACE: + return next <= 127 && (cd->ctypes[next] & ctype_space) != 0; + + case OP_WORDCHAR: + return next > 127 || (cd->ctypes[next] & ctype_word) == 0; + + case OP_NOT_WORDCHAR: + return next <= 127 && (cd->ctypes[next] & ctype_word) != 0; + + case OP_HSPACE: + case OP_NOT_HSPACE: + switch(next) + { + case 0x09: + case 0x20: + case 0xa0: + case 0x1680: + case 0x180e: + case 0x2000: + case 0x2001: + case 0x2002: + case 0x2003: + case 0x2004: + case 0x2005: + case 0x2006: + case 0x2007: + case 0x2008: + case 0x2009: + case 0x200A: + case 0x202f: + case 0x205f: + case 0x3000: + return op_code != OP_HSPACE; + default: + return op_code == OP_HSPACE; + } + + case OP_VSPACE: + case OP_NOT_VSPACE: + switch(next) + { + case 0x0a: + case 0x0b: + case 0x0c: + case 0x0d: + case 0x85: + case 0x2028: + case 0x2029: + return op_code != OP_VSPACE; + default: + return op_code == OP_VSPACE; + } + + default: + return FALSE; + } + + +/* Handle the case when the next item is \d, \s, etc. */ + +switch(op_code) + { + case OP_CHAR: + case OP_CHARNC: +#ifdef SUPPORT_UTF8 + if (utf8 && item > 127) { GETCHAR(item, utf8_char); } +#endif + switch(-next) + { + case ESC_d: + return item > 127 || (cd->ctypes[item] & ctype_digit) == 0; + + case ESC_D: + return item <= 127 && (cd->ctypes[item] & ctype_digit) != 0; + + case ESC_s: + return item > 127 || (cd->ctypes[item] & ctype_space) == 0; + + case ESC_S: + return item <= 127 && (cd->ctypes[item] & ctype_space) != 0; + + case ESC_w: + return item > 127 || (cd->ctypes[item] & ctype_word) == 0; + + case ESC_W: + return item <= 127 && (cd->ctypes[item] & ctype_word) != 0; + + case ESC_h: + case ESC_H: + switch(item) + { + case 0x09: + case 0x20: + case 0xa0: + case 0x1680: + case 0x180e: + case 0x2000: + case 0x2001: + case 0x2002: + case 0x2003: + case 0x2004: + case 0x2005: + case 0x2006: + case 0x2007: + case 0x2008: + case 0x2009: + case 0x200A: + case 0x202f: + case 0x205f: + case 0x3000: + return -next != ESC_h; + default: + return -next == ESC_h; + } + + case ESC_v: + case ESC_V: + switch(item) + { + case 0x0a: + case 0x0b: + case 0x0c: + case 0x0d: + case 0x85: + case 0x2028: + case 0x2029: + return -next != ESC_v; + default: + return -next == ESC_v; + } + + default: + return FALSE; + } + + case OP_DIGIT: + return next == -ESC_D || next == -ESC_s || next == -ESC_W || + next == -ESC_h || next == -ESC_v; + + case OP_NOT_DIGIT: + return next == -ESC_d; + + case OP_WHITESPACE: + return next == -ESC_S || next == -ESC_d || next == -ESC_w; + + case OP_NOT_WHITESPACE: + return next == -ESC_s || next == -ESC_h || next == -ESC_v; + + case OP_HSPACE: + return next == -ESC_S || next == -ESC_H || next == -ESC_d || next == -ESC_w; + + case OP_NOT_HSPACE: + return next == -ESC_h; + + /* Can't have \S in here because VT matches \S (Perl anomaly) */ + case OP_VSPACE: + return next == -ESC_V || next == -ESC_d || next == -ESC_w; + + case OP_NOT_VSPACE: + return next == -ESC_v; + + case OP_WORDCHAR: + return next == -ESC_W || next == -ESC_s || next == -ESC_h || next == -ESC_v; + + case OP_NOT_WORDCHAR: + return next == -ESC_w || next == -ESC_d; + + default: + return FALSE; + } + +/* Control does not reach here */ +} + + + +/************************************************* +* Compile one branch * +*************************************************/ + +/* Scan the pattern, compiling it into the a vector. If the options are +changed during the branch, the pointer is used to change the external options +bits. This function is used during the pre-compile phase when we are trying +to find out the amount of memory needed, as well as during the real compile +phase. The value of lengthptr distinguishes the two phases. + +Arguments: + optionsptr pointer to the option bits + codeptr points to the pointer to the current code point + ptrptr points to the current pattern pointer + errorcodeptr points to error code variable + firstbyteptr set to initial literal character, or < 0 (REQ_UNSET, REQ_NONE) + reqbyteptr set to the last literal character required, else < 0 + bcptr points to current branch chain + cd contains pointers to tables etc. + lengthptr NULL during the real compile phase + points to length accumulator during pre-compile phase + +Returns: TRUE on success + FALSE, with *errorcodeptr set non-zero on error +*/ + +static BOOL +compile_branch(int *optionsptr, uschar **codeptr, const uschar **ptrptr, + int *errorcodeptr, int *firstbyteptr, int *reqbyteptr, branch_chain *bcptr, + compile_data *cd, int *lengthptr) +{ +int repeat_type, op_type; +int repeat_min = 0, repeat_max = 0; /* To please picky compilers */ +int bravalue = 0; +int greedy_default, greedy_non_default; +int firstbyte, reqbyte; +int zeroreqbyte, zerofirstbyte; +int req_caseopt, reqvary, tempreqvary; +int options = *optionsptr; +int after_manual_callout = 0; +int length_prevgroup = 0; +register int c; +register uschar *code = *codeptr; +uschar *last_code = code; +uschar *orig_code = code; +uschar *tempcode; +BOOL inescq = FALSE; +BOOL groupsetfirstbyte = FALSE; +const uschar *ptr = *ptrptr; +const uschar *tempptr; +uschar *previous = NULL; +uschar *previous_callout = NULL; +uschar *save_hwm = NULL; +uschar classbits[32]; + +#ifdef SUPPORT_UTF8 +BOOL class_utf8; +BOOL utf8 = (options & PCRE_UTF8) != 0; +uschar *class_utf8data; +uschar *class_utf8data_base; +uschar utf8_char[6]; +#else +BOOL utf8 = FALSE; +uschar *utf8_char = NULL; +#endif + +#ifdef DEBUG +if (lengthptr != NULL) DPRINTF((">> start branch\n")); +#endif + +/* Set up the default and non-default settings for greediness */ + +greedy_default = ((options & PCRE_UNGREEDY) != 0); +greedy_non_default = greedy_default ^ 1; + +/* Initialize no first byte, no required byte. REQ_UNSET means "no char +matching encountered yet". It gets changed to REQ_NONE if we hit something that +matches a non-fixed char first char; reqbyte just remains unset if we never +find one. + +When we hit a repeat whose minimum is zero, we may have to adjust these values +to take the zero repeat into account. This is implemented by setting them to +zerofirstbyte and zeroreqbyte when such a repeat is encountered. The individual +item types that can be repeated set these backoff variables appropriately. */ + +firstbyte = reqbyte = zerofirstbyte = zeroreqbyte = REQ_UNSET; + +/* The variable req_caseopt contains either the REQ_CASELESS value or zero, +according to the current setting of the caseless flag. REQ_CASELESS is a bit +value > 255. It is added into the firstbyte or reqbyte variables to record the +case status of the value. This is used only for ASCII characters. */ + +req_caseopt = ((options & PCRE_CASELESS) != 0)? REQ_CASELESS : 0; + +/* Switch on next character until the end of the branch */ + +for (;; ptr++) + { + BOOL negate_class; + BOOL should_flip_negation; + BOOL possessive_quantifier; + BOOL is_quantifier; + BOOL is_recurse; + BOOL reset_bracount; + int class_charcount; + int class_lastchar; + int newoptions; + int recno; + int refsign; + int skipbytes; + int subreqbyte; + int subfirstbyte; + int terminator; + int mclength; + uschar mcbuffer[8]; + + /* Get next byte in the pattern */ + + c = *ptr; + + /* If we are in the pre-compile phase, accumulate the length used for the + previous cycle of this loop. */ + + if (lengthptr != NULL) + { +#ifdef DEBUG + if (code > cd->hwm) cd->hwm = code; /* High water info */ +#endif + if (code > cd->start_workspace + COMPILE_WORK_SIZE) /* Check for overrun */ + { + *errorcodeptr = ERR52; + goto FAILED; + } + + /* There is at least one situation where code goes backwards: this is the + case of a zero quantifier after a class (e.g. [ab]{0}). At compile time, + the class is simply eliminated. However, it is created first, so we have to + allow memory for it. Therefore, don't ever reduce the length at this point. + */ + + if (code < last_code) code = last_code; + + /* Paranoid check for integer overflow */ + + if (OFLOW_MAX - *lengthptr < code - last_code) + { + *errorcodeptr = ERR20; + goto FAILED; + } + + *lengthptr += code - last_code; + DPRINTF(("length=%d added %d c=%c\n", *lengthptr, code - last_code, c)); + + /* If "previous" is set and it is not at the start of the work space, move + it back to there, in order to avoid filling up the work space. Otherwise, + if "previous" is NULL, reset the current code pointer to the start. */ + + if (previous != NULL) + { + if (previous > orig_code) + { + memmove(orig_code, previous, code - previous); + code -= previous - orig_code; + previous = orig_code; + } + } + else code = orig_code; + + /* Remember where this code item starts so we can pick up the length + next time round. */ + + last_code = code; + } + + /* In the real compile phase, just check the workspace used by the forward + reference list. */ + + else if (cd->hwm > cd->start_workspace + COMPILE_WORK_SIZE) + { + *errorcodeptr = ERR52; + goto FAILED; + } + + /* If in \Q...\E, check for the end; if not, we have a literal */ + + if (inescq && c != 0) + { + if (c == '\\' && ptr[1] == 'E') + { + inescq = FALSE; + ptr++; + continue; + } + else + { + if (previous_callout != NULL) + { + if (lengthptr == NULL) /* Don't attempt in pre-compile phase */ + complete_callout(previous_callout, ptr, cd); + previous_callout = NULL; + } + if ((options & PCRE_AUTO_CALLOUT) != 0) + { + previous_callout = code; + code = auto_callout(code, ptr, cd); + } + goto NORMAL_CHAR; + } + } + + /* Fill in length of a previous callout, except when the next thing is + a quantifier. */ + + is_quantifier = c == '*' || c == '+' || c == '?' || + (c == '{' && is_counted_repeat(ptr+1)); + + if (!is_quantifier && previous_callout != NULL && + after_manual_callout-- <= 0) + { + if (lengthptr == NULL) /* Don't attempt in pre-compile phase */ + complete_callout(previous_callout, ptr, cd); + previous_callout = NULL; + } + + /* In extended mode, skip white space and comments */ + + if ((options & PCRE_EXTENDED) != 0) + { + if ((cd->ctypes[c] & ctype_space) != 0) continue; + if (c == '#') + { + while (*(++ptr) != 0) + { + if (IS_NEWLINE(ptr)) { ptr += cd->nllen - 1; break; } + } + if (*ptr != 0) continue; + + /* Else fall through to handle end of string */ + c = 0; + } + } + + /* No auto callout for quantifiers. */ + + if ((options & PCRE_AUTO_CALLOUT) != 0 && !is_quantifier) + { + previous_callout = code; + code = auto_callout(code, ptr, cd); + } + + switch(c) + { + /* ===================================================================*/ + case 0: /* The branch terminates at string end */ + case '|': /* or | or ) */ + case ')': + *firstbyteptr = firstbyte; + *reqbyteptr = reqbyte; + *codeptr = code; + *ptrptr = ptr; + if (lengthptr != NULL) + { + if (OFLOW_MAX - *lengthptr < code - last_code) + { + *errorcodeptr = ERR20; + goto FAILED; + } + *lengthptr += code - last_code; /* To include callout length */ + DPRINTF((">> end branch\n")); + } + return TRUE; + + + /* ===================================================================*/ + /* Handle single-character metacharacters. In multiline mode, ^ disables + the setting of any following char as a first character. */ + + case '^': + if ((options & PCRE_MULTILINE) != 0) + { + if (firstbyte == REQ_UNSET) firstbyte = REQ_NONE; + } + previous = NULL; + *code++ = OP_CIRC; + break; + + case '$': + previous = NULL; + *code++ = OP_DOLL; + break; + + /* There can never be a first char if '.' is first, whatever happens about + repeats. The value of reqbyte doesn't change either. */ + + case '.': + if (firstbyte == REQ_UNSET) firstbyte = REQ_NONE; + zerofirstbyte = firstbyte; + zeroreqbyte = reqbyte; + previous = code; + *code++ = OP_ANY; + break; + + + /* ===================================================================*/ + /* Character classes. If the included characters are all < 256, we build a + 32-byte bitmap of the permitted characters, except in the special case + where there is only one such character. For negated classes, we build the + map as usual, then invert it at the end. However, we use a different opcode + so that data characters > 255 can be handled correctly. + + If the class contains characters outside the 0-255 range, a different + opcode is compiled. It may optionally have a bit map for characters < 256, + but those above are are explicitly listed afterwards. A flag byte tells + whether the bitmap is present, and whether this is a negated class or not. + */ + + case '[': + previous = code; + + /* PCRE supports POSIX class stuff inside a class. Perl gives an error if + they are encountered at the top level, so we'll do that too. */ + + if ((ptr[1] == ':' || ptr[1] == '.' || ptr[1] == '=') && + check_posix_syntax(ptr, &tempptr)) + { + *errorcodeptr = (ptr[1] == ':')? ERR13 : ERR31; + goto FAILED; + } + + /* If the first character is '^', set the negation flag and skip it. Also, + if the first few characters (either before or after ^) are \Q\E or \E we + skip them too. This makes for compatibility with Perl. */ + + negate_class = FALSE; + for (;;) + { + c = *(++ptr); + if (c == '\\') + { + if (ptr[1] == 'E') ptr++; + else if (strncmp((const char *)ptr+1, "Q\\E", 3) == 0) ptr += 3; + else break; + } + else if (!negate_class && c == '^') + negate_class = TRUE; + else break; + } + + /* If a class contains a negative special such as \S, we need to flip the + negation flag at the end, so that support for characters > 255 works + correctly (they are all included in the class). */ + + should_flip_negation = FALSE; + + /* Keep a count of chars with values < 256 so that we can optimize the case + of just a single character (as long as it's < 256). However, For higher + valued UTF-8 characters, we don't yet do any optimization. */ + + class_charcount = 0; + class_lastchar = -1; + + /* Initialize the 32-char bit map to all zeros. We build the map in a + temporary bit of memory, in case the class contains only 1 character (less + than 256), because in that case the compiled code doesn't use the bit map. + */ + + memset(classbits, 0, 32 * sizeof(uschar)); + +#ifdef SUPPORT_UTF8 + class_utf8 = FALSE; /* No chars >= 256 */ + class_utf8data = code + LINK_SIZE + 2; /* For UTF-8 items */ + class_utf8data_base = class_utf8data; /* For resetting in pass 1 */ +#endif + + /* Process characters until ] is reached. By writing this as a "do" it + means that an initial ] is taken as a data character. At the start of the + loop, c contains the first byte of the character. */ + + if (c != 0) do + { + const uschar *oldptr; + +#ifdef SUPPORT_UTF8 + if (utf8 && c > 127) + { /* Braces are required because the */ + GETCHARLEN(c, ptr, ptr); /* macro generates multiple statements */ + } + + /* In the pre-compile phase, accumulate the length of any UTF-8 extra + data and reset the pointer. This is so that very large classes that + contain a zillion UTF-8 characters no longer overwrite the work space + (which is on the stack). */ + + if (lengthptr != NULL) + { + *lengthptr += class_utf8data - class_utf8data_base; + class_utf8data = class_utf8data_base; + } + +#endif + + /* Inside \Q...\E everything is literal except \E */ + + if (inescq) + { + if (c == '\\' && ptr[1] == 'E') /* If we are at \E */ + { + inescq = FALSE; /* Reset literal state */ + ptr++; /* Skip the 'E' */ + continue; /* Carry on with next */ + } + goto CHECK_RANGE; /* Could be range if \E follows */ + } + + /* Handle POSIX class names. Perl allows a negation extension of the + form [:^name:]. A square bracket that doesn't match the syntax is + treated as a literal. We also recognize the POSIX constructions + [.ch.] and [=ch=] ("collating elements") and fault them, as Perl + 5.6 and 5.8 do. */ + + if (c == '[' && + (ptr[1] == ':' || ptr[1] == '.' || ptr[1] == '=') && + check_posix_syntax(ptr, &tempptr)) + { + BOOL local_negate = FALSE; + int posix_class, taboffset, tabopt; + register const uschar *cbits = cd->cbits; + uschar pbits[32]; + + if (ptr[1] != ':') + { + *errorcodeptr = ERR31; + goto FAILED; + } + + ptr += 2; + if (*ptr == '^') + { + local_negate = TRUE; + should_flip_negation = TRUE; /* Note negative special */ + ptr++; + } + + posix_class = check_posix_name(ptr, tempptr - ptr); + if (posix_class < 0) + { + *errorcodeptr = ERR30; + goto FAILED; + } + + /* If matching is caseless, upper and lower are converted to + alpha. This relies on the fact that the class table starts with + alpha, lower, upper as the first 3 entries. */ + + if ((options & PCRE_CASELESS) != 0 && posix_class <= 2) + posix_class = 0; + + /* We build the bit map for the POSIX class in a chunk of local store + because we may be adding and subtracting from it, and we don't want to + subtract bits that may be in the main map already. At the end we or the + result into the bit map that is being built. */ + + posix_class *= 3; + + /* Copy in the first table (always present) */ + + memcpy(pbits, cbits + posix_class_maps[posix_class], + 32 * sizeof(uschar)); + + /* If there is a second table, add or remove it as required. */ + + taboffset = posix_class_maps[posix_class + 1]; + tabopt = posix_class_maps[posix_class + 2]; + + if (taboffset >= 0) + { + if (tabopt >= 0) + for (c = 0; c < 32; c++) pbits[c] |= cbits[c + taboffset]; + else + for (c = 0; c < 32; c++) pbits[c] &= ~cbits[c + taboffset]; + } + + /* Not see if we need to remove any special characters. An option + value of 1 removes vertical space and 2 removes underscore. */ + + if (tabopt < 0) tabopt = -tabopt; + if (tabopt == 1) pbits[1] &= ~0x3c; + else if (tabopt == 2) pbits[11] &= 0x7f; + + /* Add the POSIX table or its complement into the main table that is + being built and we are done. */ + + if (local_negate) + for (c = 0; c < 32; c++) classbits[c] |= ~pbits[c]; + else + for (c = 0; c < 32; c++) classbits[c] |= pbits[c]; + + ptr = tempptr + 1; + class_charcount = 10; /* Set > 1; assumes more than 1 per class */ + continue; /* End of POSIX syntax handling */ + } + + /* Backslash may introduce a single character, or it may introduce one + of the specials, which just set a flag. The sequence \b is a special + case. Inside a class (and only there) it is treated as backspace. + Elsewhere it marks a word boundary. Other escapes have preset maps ready + to 'or' into the one we are building. We assume they have more than one + character in them, so set class_charcount bigger than one. */ + + if (c == '\\') + { + c = check_escape(&ptr, errorcodeptr, cd->bracount, options, TRUE); + if (*errorcodeptr != 0) goto FAILED; + + if (-c == ESC_b) c = '\b'; /* \b is backspace in a class */ + else if (-c == ESC_X) c = 'X'; /* \X is literal X in a class */ + else if (-c == ESC_R) c = 'R'; /* \R is literal R in a class */ + else if (-c == ESC_Q) /* Handle start of quoted string */ + { + if (ptr[1] == '\\' && ptr[2] == 'E') + { + ptr += 2; /* avoid empty string */ + } + else inescq = TRUE; + continue; + } + else if (-c == ESC_E) continue; /* Ignore orphan \E */ + + if (c < 0) + { + register const uschar *cbits = cd->cbits; + class_charcount += 2; /* Greater than 1 is what matters */ + + /* Save time by not doing this in the pre-compile phase. */ + + if (lengthptr == NULL) switch (-c) + { + case ESC_d: + for (c = 0; c < 32; c++) classbits[c] |= cbits[c+cbit_digit]; + continue; + + case ESC_D: + should_flip_negation = TRUE; + for (c = 0; c < 32; c++) classbits[c] |= ~cbits[c+cbit_digit]; + continue; + + case ESC_w: + for (c = 0; c < 32; c++) classbits[c] |= cbits[c+cbit_word]; + continue; + + case ESC_W: + should_flip_negation = TRUE; + for (c = 0; c < 32; c++) classbits[c] |= ~cbits[c+cbit_word]; + continue; + + case ESC_s: + for (c = 0; c < 32; c++) classbits[c] |= cbits[c+cbit_space]; + classbits[1] &= ~0x08; /* Perl 5.004 onwards omits VT from \s */ + continue; + + case ESC_S: + should_flip_negation = TRUE; + for (c = 0; c < 32; c++) classbits[c] |= ~cbits[c+cbit_space]; + classbits[1] |= 0x08; /* Perl 5.004 onwards omits VT from \s */ + continue; + + default: /* Not recognized; fall through */ + break; /* Need "default" setting to stop compiler warning. */ + } + + /* In the pre-compile phase, just do the recognition. */ + + else if (c == -ESC_d || c == -ESC_D || c == -ESC_w || + c == -ESC_W || c == -ESC_s || c == -ESC_S) continue; + + /* We need to deal with \H, \h, \V, and \v in both phases because + they use extra memory. */ + + if (-c == ESC_h) + { + SETBIT(classbits, 0x09); /* VT */ + SETBIT(classbits, 0x20); /* SPACE */ + SETBIT(classbits, 0xa0); /* NSBP */ +#ifdef SUPPORT_UTF8 + if (utf8) + { + class_utf8 = TRUE; + *class_utf8data++ = XCL_SINGLE; + class_utf8data += _pcre_ord2utf8(0x1680, class_utf8data); + *class_utf8data++ = XCL_SINGLE; + class_utf8data += _pcre_ord2utf8(0x180e, class_utf8data); + *class_utf8data++ = XCL_RANGE; + class_utf8data += _pcre_ord2utf8(0x2000, class_utf8data); + class_utf8data += _pcre_ord2utf8(0x200A, class_utf8data); + *class_utf8data++ = XCL_SINGLE; + class_utf8data += _pcre_ord2utf8(0x202f, class_utf8data); + *class_utf8data++ = XCL_SINGLE; + class_utf8data += _pcre_ord2utf8(0x205f, class_utf8data); + *class_utf8data++ = XCL_SINGLE; + class_utf8data += _pcre_ord2utf8(0x3000, class_utf8data); + } +#endif + continue; + } + + if (-c == ESC_H) + { + for (c = 0; c < 32; c++) + { + int x = 0xff; + switch (c) + { + case 0x09/8: x ^= 1 << (0x09%8); break; + case 0x20/8: x ^= 1 << (0x20%8); break; + case 0xa0/8: x ^= 1 << (0xa0%8); break; + default: break; + } + classbits[c] |= x; + } + +#ifdef SUPPORT_UTF8 + if (utf8) + { + class_utf8 = TRUE; + *class_utf8data++ = XCL_RANGE; + class_utf8data += _pcre_ord2utf8(0x0100, class_utf8data); + class_utf8data += _pcre_ord2utf8(0x167f, class_utf8data); + *class_utf8data++ = XCL_RANGE; + class_utf8data += _pcre_ord2utf8(0x1681, class_utf8data); + class_utf8data += _pcre_ord2utf8(0x180d, class_utf8data); + *class_utf8data++ = XCL_RANGE; + class_utf8data += _pcre_ord2utf8(0x180f, class_utf8data); + class_utf8data += _pcre_ord2utf8(0x1fff, class_utf8data); + *class_utf8data++ = XCL_RANGE; + class_utf8data += _pcre_ord2utf8(0x200B, class_utf8data); + class_utf8data += _pcre_ord2utf8(0x202e, class_utf8data); + *class_utf8data++ = XCL_RANGE; + class_utf8data += _pcre_ord2utf8(0x2030, class_utf8data); + class_utf8data += _pcre_ord2utf8(0x205e, class_utf8data); + *class_utf8data++ = XCL_RANGE; + class_utf8data += _pcre_ord2utf8(0x2060, class_utf8data); + class_utf8data += _pcre_ord2utf8(0x2fff, class_utf8data); + *class_utf8data++ = XCL_RANGE; + class_utf8data += _pcre_ord2utf8(0x3001, class_utf8data); + class_utf8data += _pcre_ord2utf8(0x7fffffff, class_utf8data); + } +#endif + continue; + } + + if (-c == ESC_v) + { + SETBIT(classbits, 0x0a); /* LF */ + SETBIT(classbits, 0x0b); /* VT */ + SETBIT(classbits, 0x0c); /* FF */ + SETBIT(classbits, 0x0d); /* CR */ + SETBIT(classbits, 0x85); /* NEL */ +#ifdef SUPPORT_UTF8 + if (utf8) + { + class_utf8 = TRUE; + *class_utf8data++ = XCL_RANGE; + class_utf8data += _pcre_ord2utf8(0x2028, class_utf8data); + class_utf8data += _pcre_ord2utf8(0x2029, class_utf8data); + } +#endif + continue; + } + + if (-c == ESC_V) + { + for (c = 0; c < 32; c++) + { + int x = 0xff; + switch (c) + { + case 0x0a/8: x ^= 1 << (0x0a%8); + x ^= 1 << (0x0b%8); + x ^= 1 << (0x0c%8); + x ^= 1 << (0x0d%8); + break; + case 0x85/8: x ^= 1 << (0x85%8); break; + default: break; + } + classbits[c] |= x; + } + +#ifdef SUPPORT_UTF8 + if (utf8) + { + class_utf8 = TRUE; + *class_utf8data++ = XCL_RANGE; + class_utf8data += _pcre_ord2utf8(0x0100, class_utf8data); + class_utf8data += _pcre_ord2utf8(0x2027, class_utf8data); + *class_utf8data++ = XCL_RANGE; + class_utf8data += _pcre_ord2utf8(0x2029, class_utf8data); + class_utf8data += _pcre_ord2utf8(0x7fffffff, class_utf8data); + } +#endif + continue; + } + + /* We need to deal with \P and \p in both phases. */ + +#ifdef SUPPORT_UCP + if (-c == ESC_p || -c == ESC_P) + { + BOOL negated; + int pdata; + int ptype = get_ucp(&ptr, &negated, &pdata, errorcodeptr); + if (ptype < 0) goto FAILED; + class_utf8 = TRUE; + *class_utf8data++ = ((-c == ESC_p) != negated)? + XCL_PROP : XCL_NOTPROP; + *class_utf8data++ = ptype; + *class_utf8data++ = pdata; + class_charcount -= 2; /* Not a < 256 character */ + continue; + } +#endif + /* Unrecognized escapes are faulted if PCRE is running in its + strict mode. By default, for compatibility with Perl, they are + treated as literals. */ + + if ((options & PCRE_EXTRA) != 0) + { + *errorcodeptr = ERR7; + goto FAILED; + } + + class_charcount -= 2; /* Undo the default count from above */ + c = *ptr; /* Get the final character and fall through */ + } + + /* Fall through if we have a single character (c >= 0). This may be + greater than 256 in UTF-8 mode. */ + + } /* End of backslash handling */ + + /* A single character may be followed by '-' to form a range. However, + Perl does not permit ']' to be the end of the range. A '-' character + at the end is treated as a literal. Perl ignores orphaned \E sequences + entirely. The code for handling \Q and \E is messy. */ + + CHECK_RANGE: + while (ptr[1] == '\\' && ptr[2] == 'E') + { + inescq = FALSE; + ptr += 2; + } + + oldptr = ptr; + + /* Remember \r or \n */ + + if (c == '\r' || c == '\n') cd->external_flags |= PCRE_HASCRORLF; + + /* Check for range */ + + if (!inescq && ptr[1] == '-') + { + int d; + ptr += 2; + while (*ptr == '\\' && ptr[1] == 'E') ptr += 2; + + /* If we hit \Q (not followed by \E) at this point, go into escaped + mode. */ + + while (*ptr == '\\' && ptr[1] == 'Q') + { + ptr += 2; + if (*ptr == '\\' && ptr[1] == 'E') { ptr += 2; continue; } + inescq = TRUE; + break; + } + + if (*ptr == 0 || (!inescq && *ptr == ']')) + { + ptr = oldptr; + goto LONE_SINGLE_CHARACTER; + } + +#ifdef SUPPORT_UTF8 + if (utf8) + { /* Braces are required because the */ + GETCHARLEN(d, ptr, ptr); /* macro generates multiple statements */ + } + else +#endif + d = *ptr; /* Not UTF-8 mode */ + + /* The second part of a range can be a single-character escape, but + not any of the other escapes. Perl 5.6 treats a hyphen as a literal + in such circumstances. */ + + if (!inescq && d == '\\') + { + d = check_escape(&ptr, errorcodeptr, cd->bracount, options, TRUE); + if (*errorcodeptr != 0) goto FAILED; + + /* \b is backspace; \X is literal X; \R is literal R; any other + special means the '-' was literal */ + + if (d < 0) + { + if (d == -ESC_b) d = '\b'; + else if (d == -ESC_X) d = 'X'; + else if (d == -ESC_R) d = 'R'; else + { + ptr = oldptr; + goto LONE_SINGLE_CHARACTER; /* A few lines below */ + } + } + } + + /* Check that the two values are in the correct order. Optimize + one-character ranges */ + + if (d < c) + { + *errorcodeptr = ERR8; + goto FAILED; + } + + if (d == c) goto LONE_SINGLE_CHARACTER; /* A few lines below */ + + /* Remember \r or \n */ + + if (d == '\r' || d == '\n') cd->external_flags |= PCRE_HASCRORLF; + + /* In UTF-8 mode, if the upper limit is > 255, or > 127 for caseless + matching, we have to use an XCLASS with extra data items. Caseless + matching for characters > 127 is available only if UCP support is + available. */ + +#ifdef SUPPORT_UTF8 + if (utf8 && (d > 255 || ((options & PCRE_CASELESS) != 0 && d > 127))) + { + class_utf8 = TRUE; + + /* With UCP support, we can find the other case equivalents of + the relevant characters. There may be several ranges. Optimize how + they fit with the basic range. */ + +#ifdef SUPPORT_UCP + if ((options & PCRE_CASELESS) != 0) + { + unsigned int occ, ocd; + unsigned int cc = c; + unsigned int origd = d; + while (get_othercase_range(&cc, origd, &occ, &ocd)) + { + if (occ >= (unsigned int)c && + ocd <= (unsigned int)d) + continue; /* Skip embedded ranges */ + + if (occ < (unsigned int)c && + ocd >= (unsigned int)c - 1) /* Extend the basic range */ + { /* if there is overlap, */ + c = occ; /* noting that if occ < c */ + continue; /* we can't have ocd > d */ + } /* because a subrange is */ + if (ocd > (unsigned int)d && + occ <= (unsigned int)d + 1) /* always shorter than */ + { /* the basic range. */ + d = ocd; + continue; + } + + if (occ == ocd) + { + *class_utf8data++ = XCL_SINGLE; + } + else + { + *class_utf8data++ = XCL_RANGE; + class_utf8data += _pcre_ord2utf8(occ, class_utf8data); + } + class_utf8data += _pcre_ord2utf8(ocd, class_utf8data); + } + } +#endif /* SUPPORT_UCP */ + + /* Now record the original range, possibly modified for UCP caseless + overlapping ranges. */ + + *class_utf8data++ = XCL_RANGE; + class_utf8data += _pcre_ord2utf8(c, class_utf8data); + class_utf8data += _pcre_ord2utf8(d, class_utf8data); + + /* With UCP support, we are done. Without UCP support, there is no + caseless matching for UTF-8 characters > 127; we can use the bit map + for the smaller ones. */ + +#ifdef SUPPORT_UCP + continue; /* With next character in the class */ +#else + if ((options & PCRE_CASELESS) == 0 || c > 127) continue; + + /* Adjust upper limit and fall through to set up the map */ + + d = 127; + +#endif /* SUPPORT_UCP */ + } +#endif /* SUPPORT_UTF8 */ + + /* We use the bit map for all cases when not in UTF-8 mode; else + ranges that lie entirely within 0-127 when there is UCP support; else + for partial ranges without UCP support. */ + + class_charcount += d - c + 1; + class_lastchar = d; + + /* We can save a bit of time by skipping this in the pre-compile. */ + + if (lengthptr == NULL) for (; c <= d; c++) + { + classbits[c/8] |= (1 << (c&7)); + if ((options & PCRE_CASELESS) != 0) + { + int uc = cd->fcc[c]; /* flip case */ + classbits[uc/8] |= (1 << (uc&7)); + } + } + + continue; /* Go get the next char in the class */ + } + + /* Handle a lone single character - we can get here for a normal + non-escape char, or after \ that introduces a single character or for an + apparent range that isn't. */ + + LONE_SINGLE_CHARACTER: + + /* Handle a character that cannot go in the bit map */ + +#ifdef SUPPORT_UTF8 + if (utf8 && (c > 255 || ((options & PCRE_CASELESS) != 0 && c > 127))) + { + class_utf8 = TRUE; + *class_utf8data++ = XCL_SINGLE; + class_utf8data += _pcre_ord2utf8(c, class_utf8data); + +#ifdef SUPPORT_UCP + if ((options & PCRE_CASELESS) != 0) + { + unsigned int othercase; + if ((othercase = _pcre_ucp_othercase(c)) != NOTACHAR) + { + *class_utf8data++ = XCL_SINGLE; + class_utf8data += _pcre_ord2utf8(othercase, class_utf8data); + } + } +#endif /* SUPPORT_UCP */ + + } + else +#endif /* SUPPORT_UTF8 */ + + /* Handle a single-byte character */ + { + classbits[c/8] |= (1 << (c&7)); + if ((options & PCRE_CASELESS) != 0) + { + c = cd->fcc[c]; /* flip case */ + classbits[c/8] |= (1 << (c&7)); + } + class_charcount++; + class_lastchar = c; + } + } + + /* Loop until ']' reached. This "while" is the end of the "do" above. */ + + while ((c = *(++ptr)) != 0 && (c != ']' || inescq)); + + if (c == 0) /* Missing terminating ']' */ + { + *errorcodeptr = ERR6; + goto FAILED; + } + + +/* This code has been disabled because it would mean that \s counts as +an explicit \r or \n reference, and that's not really what is wanted. Now +we set the flag only if there is a literal "\r" or "\n" in the class. */ + +#if 0 + /* Remember whether \r or \n are in this class */ + + if (negate_class) + { + if ((classbits[1] & 0x24) != 0x24) cd->external_flags |= PCRE_HASCRORLF; + } + else + { + if ((classbits[1] & 0x24) != 0) cd->external_flags |= PCRE_HASCRORLF; + } +#endif + + + /* If class_charcount is 1, we saw precisely one character whose value is + less than 256. As long as there were no characters >= 128 and there was no + use of \p or \P, in other words, no use of any XCLASS features, we can + optimize. + + In UTF-8 mode, we can optimize the negative case only if there were no + characters >= 128 because OP_NOT and the related opcodes like OP_NOTSTAR + operate on single-bytes only. This is an historical hangover. Maybe one day + we can tidy these opcodes to handle multi-byte characters. + + The optimization throws away the bit map. We turn the item into a + 1-character OP_CHAR[NC] if it's positive, or OP_NOT if it's negative. Note + that OP_NOT does not support multibyte characters. In the positive case, it + can cause firstbyte to be set. Otherwise, there can be no first char if + this item is first, whatever repeat count may follow. In the case of + reqbyte, save the previous value for reinstating. */ + +#ifdef SUPPORT_UTF8 + if (class_charcount == 1 && !class_utf8 && + (!utf8 || !negate_class || class_lastchar < 128)) +#else + if (class_charcount == 1) +#endif + { + zeroreqbyte = reqbyte; + + /* The OP_NOT opcode works on one-byte characters only. */ + + if (negate_class) + { + if (firstbyte == REQ_UNSET) firstbyte = REQ_NONE; + zerofirstbyte = firstbyte; + *code++ = OP_NOT; + *code++ = class_lastchar; + break; + } + + /* For a single, positive character, get the value into mcbuffer, and + then we can handle this with the normal one-character code. */ + +#ifdef SUPPORT_UTF8 + if (utf8 && class_lastchar > 127) + mclength = _pcre_ord2utf8(class_lastchar, mcbuffer); + else +#endif + { + mcbuffer[0] = class_lastchar; + mclength = 1; + } + goto ONE_CHAR; + } /* End of 1-char optimization */ + + /* The general case - not the one-char optimization. If this is the first + thing in the branch, there can be no first char setting, whatever the + repeat count. Any reqbyte setting must remain unchanged after any kind of + repeat. */ + + if (firstbyte == REQ_UNSET) firstbyte = REQ_NONE; + zerofirstbyte = firstbyte; + zeroreqbyte = reqbyte; + + /* If there are characters with values > 255, we have to compile an + extended class, with its own opcode, unless there was a negated special + such as \S in the class, because in that case all characters > 255 are in + the class, so any that were explicitly given as well can be ignored. If + (when there are explicit characters > 255 that must be listed) there are no + characters < 256, we can omit the bitmap in the actual compiled code. */ + +#ifdef SUPPORT_UTF8 + if (class_utf8 && !should_flip_negation) + { + *class_utf8data++ = XCL_END; /* Marks the end of extra data */ + *code++ = OP_XCLASS; + code += LINK_SIZE; + *code = negate_class? XCL_NOT : 0; + + /* If the map is required, move up the extra data to make room for it; + otherwise just move the code pointer to the end of the extra data. */ + + if (class_charcount > 0) + { + *code++ |= XCL_MAP; + memmove(code + 32, code, class_utf8data - code); + memcpy(code, classbits, 32); + code = class_utf8data + 32; + } + else code = class_utf8data; + + /* Now fill in the complete length of the item */ + + PUT(previous, 1, code - previous); + break; /* End of class handling */ + } +#endif + + /* If there are no characters > 255, set the opcode to OP_CLASS or + OP_NCLASS, depending on whether the whole class was negated and whether + there were negative specials such as \S in the class. Then copy the 32-byte + map into the code vector, negating it if necessary. */ + + *code++ = (negate_class == should_flip_negation) ? OP_CLASS : OP_NCLASS; + if (negate_class) + { + if (lengthptr == NULL) /* Save time in the pre-compile phase */ + for (c = 0; c < 32; c++) code[c] = ~classbits[c]; + } + else + { + memcpy(code, classbits, 32); + } + code += 32; + break; + + + /* ===================================================================*/ + /* Various kinds of repeat; '{' is not necessarily a quantifier, but this + has been tested above. */ + + case '{': + if (!is_quantifier) goto NORMAL_CHAR; + ptr = read_repeat_counts(ptr+1, &repeat_min, &repeat_max, errorcodeptr); + if (*errorcodeptr != 0) goto FAILED; + goto REPEAT; + + case '*': + repeat_min = 0; + repeat_max = -1; + goto REPEAT; + + case '+': + repeat_min = 1; + repeat_max = -1; + goto REPEAT; + + case '?': + repeat_min = 0; + repeat_max = 1; + + REPEAT: + if (previous == NULL) + { + *errorcodeptr = ERR9; + goto FAILED; + } + + if (repeat_min == 0) + { + firstbyte = zerofirstbyte; /* Adjust for zero repeat */ + reqbyte = zeroreqbyte; /* Ditto */ + } + + /* Remember whether this is a variable length repeat */ + + reqvary = (repeat_min == repeat_max)? 0 : REQ_VARY; + + op_type = 0; /* Default single-char op codes */ + possessive_quantifier = FALSE; /* Default not possessive quantifier */ + + /* Save start of previous item, in case we have to move it up to make space + for an inserted OP_ONCE for the additional '+' extension. */ + + tempcode = previous; + + /* If the next character is '+', we have a possessive quantifier. This + implies greediness, whatever the setting of the PCRE_UNGREEDY option. + If the next character is '?' this is a minimizing repeat, by default, + but if PCRE_UNGREEDY is set, it works the other way round. We change the + repeat type to the non-default. */ + + if (ptr[1] == '+') + { + repeat_type = 0; /* Force greedy */ + possessive_quantifier = TRUE; + ptr++; + } + else if (ptr[1] == '?') + { + repeat_type = greedy_non_default; + ptr++; + } + else repeat_type = greedy_default; + + /* If previous was a character match, abolish the item and generate a + repeat item instead. If a char item has a minumum of more than one, ensure + that it is set in reqbyte - it might not be if a sequence such as x{3} is + the first thing in a branch because the x will have gone into firstbyte + instead. */ + + if (*previous == OP_CHAR || *previous == OP_CHARNC) + { + /* Deal with UTF-8 characters that take up more than one byte. It's + easier to write this out separately than try to macrify it. Use c to + hold the length of the character in bytes, plus 0x80 to flag that it's a + length rather than a small character. */ + +#ifdef SUPPORT_UTF8 + if (utf8 && (code[-1] & 0x80) != 0) + { + uschar *lastchar = code - 1; + while((*lastchar & 0xc0) == 0x80) lastchar--; + c = code - lastchar; /* Length of UTF-8 character */ + memcpy(utf8_char, lastchar, c); /* Save the char */ + c |= 0x80; /* Flag c as a length */ + } + else +#endif + + /* Handle the case of a single byte - either with no UTF8 support, or + with UTF-8 disabled, or for a UTF-8 character < 128. */ + + { + c = code[-1]; + if (repeat_min > 1) reqbyte = c | req_caseopt | cd->req_varyopt; + } + + /* If the repetition is unlimited, it pays to see if the next thing on + the line is something that cannot possibly match this character. If so, + automatically possessifying this item gains some performance in the case + where the match fails. */ + + if (!possessive_quantifier && + repeat_max < 0 && + check_auto_possessive(*previous, c, utf8, utf8_char, ptr + 1, + options, cd)) + { + repeat_type = 0; /* Force greedy */ + possessive_quantifier = TRUE; + } + + goto OUTPUT_SINGLE_REPEAT; /* Code shared with single character types */ + } + + /* If previous was a single negated character ([^a] or similar), we use + one of the special opcodes, replacing it. The code is shared with single- + character repeats by setting opt_type to add a suitable offset into + repeat_type. We can also test for auto-possessification. OP_NOT is + currently used only for single-byte chars. */ + + else if (*previous == OP_NOT) + { + op_type = OP_NOTSTAR - OP_STAR; /* Use "not" opcodes */ + c = previous[1]; + if (!possessive_quantifier && + repeat_max < 0 && + check_auto_possessive(OP_NOT, c, utf8, NULL, ptr + 1, options, cd)) + { + repeat_type = 0; /* Force greedy */ + possessive_quantifier = TRUE; + } + goto OUTPUT_SINGLE_REPEAT; + } + + /* If previous was a character type match (\d or similar), abolish it and + create a suitable repeat item. The code is shared with single-character + repeats by setting op_type to add a suitable offset into repeat_type. Note + the the Unicode property types will be present only when SUPPORT_UCP is + defined, but we don't wrap the little bits of code here because it just + makes it horribly messy. */ + + else if (*previous < OP_EODN) + { + uschar *oldcode; + int prop_type, prop_value; + op_type = OP_TYPESTAR - OP_STAR; /* Use type opcodes */ + c = *previous; + + if (!possessive_quantifier && + repeat_max < 0 && + check_auto_possessive(c, 0, utf8, NULL, ptr + 1, options, cd)) + { + repeat_type = 0; /* Force greedy */ + possessive_quantifier = TRUE; + } + + OUTPUT_SINGLE_REPEAT: + if (*previous == OP_PROP || *previous == OP_NOTPROP) + { + prop_type = previous[1]; + prop_value = previous[2]; + } + else prop_type = prop_value = -1; + + oldcode = code; + code = previous; /* Usually overwrite previous item */ + + /* If the maximum is zero then the minimum must also be zero; Perl allows + this case, so we do too - by simply omitting the item altogether. */ + + if (repeat_max == 0) goto END_REPEAT; + + /* All real repeats make it impossible to handle partial matching (maybe + one day we will be able to remove this restriction). */ + + if (repeat_max != 1) cd->external_flags |= PCRE_NOPARTIAL; + + /* Combine the op_type with the repeat_type */ + + repeat_type += op_type; + + /* A minimum of zero is handled either as the special case * or ?, or as + an UPTO, with the maximum given. */ + + if (repeat_min == 0) + { + if (repeat_max == -1) *code++ = OP_STAR + repeat_type; + else if (repeat_max == 1) *code++ = OP_QUERY + repeat_type; + else + { + *code++ = OP_UPTO + repeat_type; + PUT2INC(code, 0, repeat_max); + } + } + + /* A repeat minimum of 1 is optimized into some special cases. If the + maximum is unlimited, we use OP_PLUS. Otherwise, the original item is + left in place and, if the maximum is greater than 1, we use OP_UPTO with + one less than the maximum. */ + + else if (repeat_min == 1) + { + if (repeat_max == -1) + *code++ = OP_PLUS + repeat_type; + else + { + code = oldcode; /* leave previous item in place */ + if (repeat_max == 1) goto END_REPEAT; + *code++ = OP_UPTO + repeat_type; + PUT2INC(code, 0, repeat_max - 1); + } + } + + /* The case {n,n} is just an EXACT, while the general case {n,m} is + handled as an EXACT followed by an UPTO. */ + + else + { + *code++ = OP_EXACT + op_type; /* NB EXACT doesn't have repeat_type */ + PUT2INC(code, 0, repeat_min); + + /* If the maximum is unlimited, insert an OP_STAR. Before doing so, + we have to insert the character for the previous code. For a repeated + Unicode property match, there are two extra bytes that define the + required property. In UTF-8 mode, long characters have their length in + c, with the 0x80 bit as a flag. */ + + if (repeat_max < 0) + { +#ifdef SUPPORT_UTF8 + if (utf8 && c >= 128) + { + memcpy(code, utf8_char, c & 7); + code += c & 7; + } + else +#endif + { + *code++ = c; + if (prop_type >= 0) + { + *code++ = prop_type; + *code++ = prop_value; + } + } + *code++ = OP_STAR + repeat_type; + } + + /* Else insert an UPTO if the max is greater than the min, again + preceded by the character, for the previously inserted code. If the + UPTO is just for 1 instance, we can use QUERY instead. */ + + else if (repeat_max != repeat_min) + { +#ifdef SUPPORT_UTF8 + if (utf8 && c >= 128) + { + memcpy(code, utf8_char, c & 7); + code += c & 7; + } + else +#endif + *code++ = c; + if (prop_type >= 0) + { + *code++ = prop_type; + *code++ = prop_value; + } + repeat_max -= repeat_min; + + if (repeat_max == 1) + { + *code++ = OP_QUERY + repeat_type; + } + else + { + *code++ = OP_UPTO + repeat_type; + PUT2INC(code, 0, repeat_max); + } + } + } + + /* The character or character type itself comes last in all cases. */ + +#ifdef SUPPORT_UTF8 + if (utf8 && c >= 128) + { + memcpy(code, utf8_char, c & 7); + code += c & 7; + } + else +#endif + *code++ = c; + + /* For a repeated Unicode property match, there are two extra bytes that + define the required property. */ + +#ifdef SUPPORT_UCP + if (prop_type >= 0) + { + *code++ = prop_type; + *code++ = prop_value; + } +#endif + } + + /* If previous was a character class or a back reference, we put the repeat + stuff after it, but just skip the item if the repeat was {0,0}. */ + + else if (*previous == OP_CLASS || + *previous == OP_NCLASS || +#ifdef SUPPORT_UTF8 + *previous == OP_XCLASS || +#endif + *previous == OP_REF) + { + if (repeat_max == 0) + { + code = previous; + goto END_REPEAT; + } + + /* All real repeats make it impossible to handle partial matching (maybe + one day we will be able to remove this restriction). */ + + if (repeat_max != 1) cd->external_flags |= PCRE_NOPARTIAL; + + if (repeat_min == 0 && repeat_max == -1) + *code++ = OP_CRSTAR + repeat_type; + else if (repeat_min == 1 && repeat_max == -1) + *code++ = OP_CRPLUS + repeat_type; + else if (repeat_min == 0 && repeat_max == 1) + *code++ = OP_CRQUERY + repeat_type; + else + { + *code++ = OP_CRRANGE + repeat_type; + PUT2INC(code, 0, repeat_min); + if (repeat_max == -1) repeat_max = 0; /* 2-byte encoding for max */ + PUT2INC(code, 0, repeat_max); + } + } + + /* If previous was a bracket group, we may have to replicate it in certain + cases. */ + + else if (*previous == OP_BRA || *previous == OP_CBRA || + *previous == OP_ONCE || *previous == OP_COND) + { + register int i; + int ketoffset = 0; + int len = code - previous; + uschar *bralink = NULL; + + /* Repeating a DEFINE group is pointless */ + + if (*previous == OP_COND && previous[LINK_SIZE+1] == OP_DEF) + { + *errorcodeptr = ERR55; + goto FAILED; + } + + /* If the maximum repeat count is unlimited, find the end of the bracket + by scanning through from the start, and compute the offset back to it + from the current code pointer. There may be an OP_OPT setting following + the final KET, so we can't find the end just by going back from the code + pointer. */ + + if (repeat_max == -1) + { + register uschar *ket = previous; + do ket += GET(ket, 1); while (*ket != OP_KET); + ketoffset = code - ket; + } + + /* The case of a zero minimum is special because of the need to stick + OP_BRAZERO in front of it, and because the group appears once in the + data, whereas in other cases it appears the minimum number of times. For + this reason, it is simplest to treat this case separately, as otherwise + the code gets far too messy. There are several special subcases when the + minimum is zero. */ + + if (repeat_min == 0) + { + /* If the maximum is also zero, we just omit the group from the output + altogether. */ + + if (repeat_max == 0) + { + code = previous; + goto END_REPEAT; + } + + /* If the maximum is 1 or unlimited, we just have to stick in the + BRAZERO and do no more at this point. However, we do need to adjust + any OP_RECURSE calls inside the group that refer to the group itself or + any internal or forward referenced group, because the offset is from + the start of the whole regex. Temporarily terminate the pattern while + doing this. */ + + if (repeat_max <= 1) + { + *code = OP_END; + adjust_recurse(previous, 1, utf8, cd, save_hwm); + memmove(previous+1, previous, len); + code++; + *previous++ = OP_BRAZERO + repeat_type; + } + + /* If the maximum is greater than 1 and limited, we have to replicate + in a nested fashion, sticking OP_BRAZERO before each set of brackets. + The first one has to be handled carefully because it's the original + copy, which has to be moved up. The remainder can be handled by code + that is common with the non-zero minimum case below. We have to + adjust the value or repeat_max, since one less copy is required. Once + again, we may have to adjust any OP_RECURSE calls inside the group. */ + + else + { + int offset; + *code = OP_END; + adjust_recurse(previous, 2 + LINK_SIZE, utf8, cd, save_hwm); + memmove(previous + 2 + LINK_SIZE, previous, len); + code += 2 + LINK_SIZE; + *previous++ = OP_BRAZERO + repeat_type; + *previous++ = OP_BRA; + + /* We chain together the bracket offset fields that have to be + filled in later when the ends of the brackets are reached. */ + + offset = (bralink == NULL)? 0 : previous - bralink; + bralink = previous; + PUTINC(previous, 0, offset); + } + + repeat_max--; + } + + /* If the minimum is greater than zero, replicate the group as many + times as necessary, and adjust the maximum to the number of subsequent + copies that we need. If we set a first char from the group, and didn't + set a required char, copy the latter from the former. If there are any + forward reference subroutine calls in the group, there will be entries on + the workspace list; replicate these with an appropriate increment. */ + + else + { + if (repeat_min > 1) + { + /* In the pre-compile phase, we don't actually do the replication. We + just adjust the length as if we had. Do some paranoid checks for + potential integer overflow. */ + + if (lengthptr != NULL) + { + int delta = (repeat_min - 1)*length_prevgroup; + if ((pika_float)(repeat_min - 1)*(pika_float)length_prevgroup > + (pika_float)INT_MAX || + OFLOW_MAX - *lengthptr < delta) + { + *errorcodeptr = ERR20; + goto FAILED; + } + *lengthptr += delta; + } + + /* This is compiling for real */ + + else + { + if (groupsetfirstbyte && reqbyte < 0) reqbyte = firstbyte; + for (i = 1; i < repeat_min; i++) + { + uschar *hc; + uschar *this_hwm = cd->hwm; + memcpy(code, previous, len); + for (hc = save_hwm; hc < this_hwm; hc += LINK_SIZE) + { + PUT(cd->hwm, 0, GET(hc, 0) + len); + cd->hwm += LINK_SIZE; + } + save_hwm = this_hwm; + code += len; + } + } + } + + if (repeat_max > 0) repeat_max -= repeat_min; + } + + /* This code is common to both the zero and non-zero minimum cases. If + the maximum is limited, it replicates the group in a nested fashion, + remembering the bracket starts on a stack. In the case of a zero minimum, + the first one was set up above. In all cases the repeat_max now specifies + the number of additional copies needed. Again, we must remember to + replicate entries on the forward reference list. */ + + if (repeat_max >= 0) + { + /* In the pre-compile phase, we don't actually do the replication. We + just adjust the length as if we had. For each repetition we must add 1 + to the length for BRAZERO and for all but the last repetition we must + add 2 + 2*LINKSIZE to allow for the nesting that occurs. Do some + paranoid checks to avoid integer overflow. */ + + if (lengthptr != NULL && repeat_max > 0) + { + int delta = repeat_max * (length_prevgroup + 1 + 2 + 2*LINK_SIZE) - + 2 - 2*LINK_SIZE; /* Last one doesn't nest */ + if ((pika_float)repeat_max * + (pika_float)(length_prevgroup + 1 + 2 + 2*LINK_SIZE) + > (pika_float)INT_MAX || + OFLOW_MAX - *lengthptr < delta) + { + *errorcodeptr = ERR20; + goto FAILED; + } + *lengthptr += delta; + } + + /* This is compiling for real */ + + else for (i = repeat_max - 1; i >= 0; i--) + { + uschar *hc; + uschar *this_hwm = cd->hwm; + + *code++ = OP_BRAZERO + repeat_type; + + /* All but the final copy start a new nesting, maintaining the + chain of brackets outstanding. */ + + if (i != 0) + { + int offset; + *code++ = OP_BRA; + offset = (bralink == NULL)? 0 : code - bralink; + bralink = code; + PUTINC(code, 0, offset); + } + + memcpy(code, previous, len); + for (hc = save_hwm; hc < this_hwm; hc += LINK_SIZE) + { + PUT(cd->hwm, 0, GET(hc, 0) + len + ((i != 0)? 2+LINK_SIZE : 1)); + cd->hwm += LINK_SIZE; + } + save_hwm = this_hwm; + code += len; + } + + /* Now chain through the pending brackets, and fill in their length + fields (which are holding the chain links pro tem). */ + + while (bralink != NULL) + { + int oldlinkoffset; + int offset = code - bralink + 1; + uschar *bra = code - offset; + oldlinkoffset = GET(bra, 1); + bralink = (oldlinkoffset == 0)? NULL : bralink - oldlinkoffset; + *code++ = OP_KET; + PUTINC(code, 0, offset); + PUT(bra, 1, offset); + } + } + + /* If the maximum is unlimited, set a repeater in the final copy. We + can't just offset backwards from the current code point, because we + don't know if there's been an options resetting after the ket. The + correct offset was computed above. + + Then, when we are doing the actual compile phase, check to see whether + this group is a non-atomic one that could match an empty string. If so, + convert the initial operator to the S form (e.g. OP_BRA -> OP_SBRA) so + that runtime checking can be done. [This check is also applied to + atomic groups at runtime, but in a different way.] */ + + else + { + uschar *ketcode = code - ketoffset; + uschar *bracode = ketcode - GET(ketcode, 1); + *ketcode = OP_KETRMAX + repeat_type; + if (lengthptr == NULL && *bracode != OP_ONCE) + { + uschar *scode = bracode; + do + { + if (could_be_empty_branch(scode, ketcode, utf8)) + { + *bracode += OP_SBRA - OP_BRA; + break; + } + scode += GET(scode, 1); + } + while (*scode == OP_ALT); + } + } + } + + /* Else there's some kind of shambles */ + + else + { + *errorcodeptr = ERR11; + goto FAILED; + } + + /* If the character following a repeat is '+', or if certain optimization + tests above succeeded, possessive_quantifier is TRUE. For some of the + simpler opcodes, there is an special alternative opcode for this. For + anything else, we wrap the entire repeated item inside OP_ONCE brackets. + The '+' notation is just syntactic sugar, taken from Sun's Java package, + but the special opcodes can optimize it a bit. The repeated item starts at + tempcode, not at previous, which might be the first part of a string whose + (former) last char we repeated. + + Possessifying an 'exact' quantifier has no effect, so we can ignore it. But + an 'upto' may follow. We skip over an 'exact' item, and then test the + length of what remains before proceeding. */ + + if (possessive_quantifier) + { + int len; + if (*tempcode == OP_EXACT || *tempcode == OP_TYPEEXACT || + *tempcode == OP_NOTEXACT) + tempcode += _pcre_OP_lengths[*tempcode] + + ((*tempcode == OP_TYPEEXACT && + (tempcode[3] == OP_PROP || tempcode[3] == OP_NOTPROP))? 2:0); + len = code - tempcode; + if (len > 0) switch (*tempcode) + { + case OP_STAR: *tempcode = OP_POSSTAR; break; + case OP_PLUS: *tempcode = OP_POSPLUS; break; + case OP_QUERY: *tempcode = OP_POSQUERY; break; + case OP_UPTO: *tempcode = OP_POSUPTO; break; + + case OP_TYPESTAR: *tempcode = OP_TYPEPOSSTAR; break; + case OP_TYPEPLUS: *tempcode = OP_TYPEPOSPLUS; break; + case OP_TYPEQUERY: *tempcode = OP_TYPEPOSQUERY; break; + case OP_TYPEUPTO: *tempcode = OP_TYPEPOSUPTO; break; + + case OP_NOTSTAR: *tempcode = OP_NOTPOSSTAR; break; + case OP_NOTPLUS: *tempcode = OP_NOTPOSPLUS; break; + case OP_NOTQUERY: *tempcode = OP_NOTPOSQUERY; break; + case OP_NOTUPTO: *tempcode = OP_NOTPOSUPTO; break; + + default: + memmove(tempcode + 1+LINK_SIZE, tempcode, len); + code += 1 + LINK_SIZE; + len += 1 + LINK_SIZE; + tempcode[0] = OP_ONCE; + *code++ = OP_KET; + PUTINC(code, 0, len); + PUT(tempcode, 1, len); + break; + } + } + + /* In all case we no longer have a previous item. We also set the + "follows varying string" flag for subsequently encountered reqbytes if + it isn't already set and we have just passed a varying length item. */ + + END_REPEAT: + previous = NULL; + cd->req_varyopt |= reqvary; + break; + + + /* ===================================================================*/ + /* Start of nested parenthesized sub-expression, or comment or lookahead or + lookbehind or option setting or condition or all the other extended + parenthesis forms. */ + + case '(': + newoptions = options; + skipbytes = 0; + bravalue = OP_CBRA; + save_hwm = cd->hwm; + reset_bracount = FALSE; + + /* First deal with various "verbs" that can be introduced by '*'. */ + + if (*(++ptr) == '*' && (cd->ctypes[ptr[1]] & ctype_letter) != 0) + { + int i, namelen; + const char *vn = verbnames; + const uschar *name = ++ptr; + previous = NULL; + while ((cd->ctypes[*++ptr] & ctype_letter) != 0); + if (*ptr == ':') + { + *errorcodeptr = ERR59; /* Not supported */ + goto FAILED; + } + if (*ptr != ')') + { + *errorcodeptr = ERR60; + goto FAILED; + } + namelen = ptr - name; + for (i = 0; i < verbcount; i++) + { + if (namelen == verbs[i].len && + strncmp((char *)name, vn, namelen) == 0) + { + *code = verbs[i].op; + if (*code++ == OP_ACCEPT) cd->had_accept = TRUE; + break; + } + vn += verbs[i].len + 1; + } + if (i < verbcount) continue; + *errorcodeptr = ERR60; + goto FAILED; + } + + /* Deal with the extended parentheses; all are introduced by '?', and the + appearance of any of them means that this is not a capturing group. */ + + else if (*ptr == '?') + { + int i, set, unset, namelen; + int *optset; + const uschar *name; + uschar *slot; + + switch (*(++ptr)) + { + case '#': /* Comment; skip to ket */ + ptr++; + while (*ptr != 0 && *ptr != ')') ptr++; + if (*ptr == 0) + { + *errorcodeptr = ERR18; + goto FAILED; + } + continue; + + + /* ------------------------------------------------------------ */ + case '|': /* Reset capture count for each branch */ + reset_bracount = TRUE; + /* Fall through */ + + /* ------------------------------------------------------------ */ + case ':': /* Non-capturing bracket */ + bravalue = OP_BRA; + ptr++; + break; + + + /* ------------------------------------------------------------ */ + case '(': + bravalue = OP_COND; /* Conditional group */ + + /* A condition can be an assertion, a number (referring to a numbered + group), a name (referring to a named group), or 'R', referring to + recursion. R and R&name are also permitted for recursion tests. + + There are several syntaxes for testing a named group: (?(name)) is used + by Python; Perl 5.10 onwards uses (?() or (?('name')). + + There are two unfortunate ambiguities, caused by history. (a) 'R' can + be the recursive thing or the name 'R' (and similarly for 'R' followed + by digits), and (b) a number could be a name that consists of digits. + In both cases, we look for a name first; if not found, we try the other + cases. */ + + /* For conditions that are assertions, check the syntax, and then exit + the switch. This will take control down to where bracketed groups, + including assertions, are processed. */ + + if (ptr[1] == '?' && (ptr[2] == '=' || ptr[2] == '!' || ptr[2] == '<')) + break; + + /* Most other conditions use OP_CREF (a couple change to OP_RREF + below), and all need to skip 3 bytes at the start of the group. */ + + code[1+LINK_SIZE] = OP_CREF; + skipbytes = 3; + refsign = -1; + + /* Check for a test for recursion in a named group. */ + + if (ptr[1] == 'R' && ptr[2] == '&') + { + terminator = -1; + ptr += 2; + code[1+LINK_SIZE] = OP_RREF; /* Change the type of test */ + } + + /* Check for a test for a named group's having been set, using the Perl + syntax (?() or (?('name') */ + + else if (ptr[1] == '<') + { + terminator = '>'; + ptr++; + } + else if (ptr[1] == '\'') + { + terminator = '\''; + ptr++; + } + else + { + terminator = 0; + if (ptr[1] == '-' || ptr[1] == '+') refsign = *(++ptr); + } + + /* We now expect to read a name; any thing else is an error */ + + if ((cd->ctypes[ptr[1]] & ctype_word) == 0) + { + ptr += 1; /* To get the right offset */ + *errorcodeptr = ERR28; + goto FAILED; + } + + /* Read the name, but also get it as a number if it's all digits */ + + recno = 0; + name = ++ptr; + while ((cd->ctypes[*ptr] & ctype_word) != 0) + { + if (recno >= 0) + recno = ((digitab[*ptr] & ctype_digit) != 0)? + recno * 10 + *ptr - '0' : -1; + ptr++; + } + namelen = ptr - name; + + if ((terminator > 0 && *ptr++ != terminator) || *ptr++ != ')') + { + ptr--; /* Error offset */ + *errorcodeptr = ERR26; + goto FAILED; + } + + /* Do no further checking in the pre-compile phase. */ + + if (lengthptr != NULL) break; + + /* In the real compile we do the work of looking for the actual + reference. If the string started with "+" or "-" we require the rest to + be digits, in which case recno will be set. */ + + if (refsign > 0) + { + if (recno <= 0) + { + *errorcodeptr = ERR58; + goto FAILED; + } + recno = (refsign == '-')? + cd->bracount - recno + 1 : recno +cd->bracount; + if (recno <= 0 || recno > cd->final_bracount) + { + *errorcodeptr = ERR15; + goto FAILED; + } + PUT2(code, 2+LINK_SIZE, recno); + break; + } + + /* Otherwise (did not start with "+" or "-"), start by looking for the + name. */ + + slot = cd->name_table; + for (i = 0; i < cd->names_found; i++) + { + if (strncmp((char *)name, (char *)slot+2, namelen) == 0) break; + slot += cd->name_entry_size; + } + + /* Found a previous named subpattern */ + + if (i < cd->names_found) + { + recno = GET2(slot, 0); + PUT2(code, 2+LINK_SIZE, recno); + } + + /* Search the pattern for a forward reference */ + + else if ((i = find_parens(ptr, cd->bracount, name, namelen, + (options & PCRE_EXTENDED) != 0)) > 0) + { + PUT2(code, 2+LINK_SIZE, i); + } + + /* If terminator == 0 it means that the name followed directly after + the opening parenthesis [e.g. (?(abc)...] and in this case there are + some further alternatives to try. For the cases where terminator != 0 + [things like (?(... or (?('name')... or (?(R&name)... ] we have + now checked all the possibilities, so give an error. */ + + else if (terminator != 0) + { + *errorcodeptr = ERR15; + goto FAILED; + } + + /* Check for (?(R) for recursion. Allow digits after R to specify a + specific group number. */ + + else if (*name == 'R') + { + recno = 0; + for (i = 1; i < namelen; i++) + { + if ((digitab[name[i]] & ctype_digit) == 0) + { + *errorcodeptr = ERR15; + goto FAILED; + } + recno = recno * 10 + name[i] - '0'; + } + if (recno == 0) recno = RREF_ANY; + code[1+LINK_SIZE] = OP_RREF; /* Change test type */ + PUT2(code, 2+LINK_SIZE, recno); + } + + /* Similarly, check for the (?(DEFINE) "condition", which is always + false. */ + + else if (namelen == 6 && strncmp((char *)name, "DEFINE", 6) == 0) + { + code[1+LINK_SIZE] = OP_DEF; + skipbytes = 1; + } + + /* Check for the "name" actually being a subpattern number. We are + in the second pass here, so final_bracount is set. */ + + else if (recno > 0 && recno <= cd->final_bracount) + { + PUT2(code, 2+LINK_SIZE, recno); + } + + /* Either an unidentified subpattern, or a reference to (?(0) */ + + else + { + *errorcodeptr = (recno == 0)? ERR35: ERR15; + goto FAILED; + } + break; + + + /* ------------------------------------------------------------ */ + case '=': /* Positive lookahead */ + bravalue = OP_ASSERT; + ptr++; + break; + + + /* ------------------------------------------------------------ */ + case '!': /* Negative lookahead */ + ptr++; + if (*ptr == ')') /* Optimize (?!) */ + { + *code++ = OP_FAIL; + previous = NULL; + continue; + } + bravalue = OP_ASSERT_NOT; + break; + + + /* ------------------------------------------------------------ */ + case '<': /* Lookbehind or named define */ + switch (ptr[1]) + { + case '=': /* Positive lookbehind */ + bravalue = OP_ASSERTBACK; + ptr += 2; + break; + + case '!': /* Negative lookbehind */ + bravalue = OP_ASSERTBACK_NOT; + ptr += 2; + break; + + default: /* Could be name define, else bad */ + if ((cd->ctypes[ptr[1]] & ctype_word) != 0) goto DEFINE_NAME; + ptr++; /* Correct offset for error */ + *errorcodeptr = ERR24; + goto FAILED; + } + break; + + + /* ------------------------------------------------------------ */ + case '>': /* One-time brackets */ + bravalue = OP_ONCE; + ptr++; + break; + + + /* ------------------------------------------------------------ */ + case 'C': /* Callout - may be followed by digits; */ + previous_callout = code; /* Save for later completion */ + after_manual_callout = 1; /* Skip one item before completing */ + *code++ = OP_CALLOUT; + { + int n = 0; + while ((digitab[*(++ptr)] & ctype_digit) != 0) + n = n * 10 + *ptr - '0'; + if (*ptr != ')') + { + *errorcodeptr = ERR39; + goto FAILED; + } + if (n > 255) + { + *errorcodeptr = ERR38; + goto FAILED; + } + *code++ = n; + PUT(code, 0, ptr - cd->start_pattern + 1); /* Pattern offset */ + PUT(code, LINK_SIZE, 0); /* Default length */ + code += 2 * LINK_SIZE; + } + previous = NULL; + continue; + + + /* ------------------------------------------------------------ */ + case 'P': /* Python-style named subpattern handling */ + if (*(++ptr) == '=' || *ptr == '>') /* Reference or recursion */ + { + is_recurse = *ptr == '>'; + terminator = ')'; + goto NAMED_REF_OR_RECURSE; + } + else if (*ptr != '<') /* Test for Python-style definition */ + { + *errorcodeptr = ERR41; + goto FAILED; + } + /* Fall through to handle (?P< as (?< is handled */ + + + /* ------------------------------------------------------------ */ + DEFINE_NAME: /* Come here from (?< handling */ + case '\'': + { + terminator = (*ptr == '<')? '>' : '\''; + name = ++ptr; + + while ((cd->ctypes[*ptr] & ctype_word) != 0) ptr++; + namelen = ptr - name; + + /* In the pre-compile phase, just do a syntax check. */ + + if (lengthptr != NULL) + { + if (*ptr != terminator) + { + *errorcodeptr = ERR42; + goto FAILED; + } + if (cd->names_found >= MAX_NAME_COUNT) + { + *errorcodeptr = ERR49; + goto FAILED; + } + if (namelen + 3 > cd->name_entry_size) + { + cd->name_entry_size = namelen + 3; + if (namelen > MAX_NAME_SIZE) + { + *errorcodeptr = ERR48; + goto FAILED; + } + } + } + + /* In the real compile, create the entry in the table */ + + else + { + slot = cd->name_table; + for (i = 0; i < cd->names_found; i++) + { + int crc = memcmp(name, slot+2, namelen); + if (crc == 0) + { + if (slot[2+namelen] == 0) + { + if ((options & PCRE_DUPNAMES) == 0) + { + *errorcodeptr = ERR43; + goto FAILED; + } + } + else crc = -1; /* Current name is substring */ + } + if (crc < 0) + { + memmove(slot + cd->name_entry_size, slot, + (cd->names_found - i) * cd->name_entry_size); + break; + } + slot += cd->name_entry_size; + } + + PUT2(slot, 0, cd->bracount + 1); + memcpy(slot + 2, name, namelen); + slot[2+namelen] = 0; + } + } + + /* In both cases, count the number of names we've encountered. */ + + ptr++; /* Move past > or ' */ + cd->names_found++; + goto NUMBERED_GROUP; + + + /* ------------------------------------------------------------ */ + case '&': /* Perl recursion/subroutine syntax */ + terminator = ')'; + is_recurse = TRUE; + /* Fall through */ + + /* We come here from the Python syntax above that handles both + references (?P=name) and recursion (?P>name), as well as falling + through from the Perl recursion syntax (?&name). We also come here from + the Perl \k or \k'name' back reference syntax and the \k{name} + .NET syntax. */ + + NAMED_REF_OR_RECURSE: + name = ++ptr; + while ((cd->ctypes[*ptr] & ctype_word) != 0) ptr++; + namelen = ptr - name; + + /* In the pre-compile phase, do a syntax check and set a dummy + reference number. */ + + if (lengthptr != NULL) + { + if (namelen == 0) + { + *errorcodeptr = ERR62; + goto FAILED; + } + if (*ptr != terminator) + { + *errorcodeptr = ERR42; + goto FAILED; + } + if (namelen > MAX_NAME_SIZE) + { + *errorcodeptr = ERR48; + goto FAILED; + } + recno = 0; + } + + /* In the real compile, seek the name in the table. We check the name + first, and then check that we have reached the end of the name in the + table. That way, if the name that is longer than any in the table, + the comparison will fail without reading beyond the table entry. */ + + else + { + slot = cd->name_table; + for (i = 0; i < cd->names_found; i++) + { + if (strncmp((char *)name, (char *)slot+2, namelen) == 0 && + slot[2+namelen] == 0) + break; + slot += cd->name_entry_size; + } + + if (i < cd->names_found) /* Back reference */ + { + recno = GET2(slot, 0); + } + else if ((recno = /* Forward back reference */ + find_parens(ptr, cd->bracount, name, namelen, + (options & PCRE_EXTENDED) != 0)) <= 0) + { + *errorcodeptr = ERR15; + goto FAILED; + } + } + + /* In both phases, we can now go to the code than handles numerical + recursion or backreferences. */ + + if (is_recurse) goto HANDLE_RECURSION; + else goto HANDLE_REFERENCE; + + + /* ------------------------------------------------------------ */ + case 'R': /* Recursion */ + ptr++; /* Same as (?0) */ + /* Fall through */ + + + /* ------------------------------------------------------------ */ + case '-': case '+': + case '0': case '1': case '2': case '3': case '4': /* Recursion or */ + case '5': case '6': case '7': case '8': case '9': /* subroutine */ + { + const uschar *called; + + if ((refsign = *ptr) == '+') + { + ptr++; + if ((digitab[*ptr] & ctype_digit) == 0) + { + *errorcodeptr = ERR63; + goto FAILED; + } + } + else if (refsign == '-') + { + if ((digitab[ptr[1]] & ctype_digit) == 0) + goto OTHER_CHAR_AFTER_QUERY; + ptr++; + } + + recno = 0; + while((digitab[*ptr] & ctype_digit) != 0) + recno = recno * 10 + *ptr++ - '0'; + + if (*ptr != ')') + { + *errorcodeptr = ERR29; + goto FAILED; + } + + if (refsign == '-') + { + if (recno == 0) + { + *errorcodeptr = ERR58; + goto FAILED; + } + recno = cd->bracount - recno + 1; + if (recno <= 0) + { + *errorcodeptr = ERR15; + goto FAILED; + } + } + else if (refsign == '+') + { + if (recno == 0) + { + *errorcodeptr = ERR58; + goto FAILED; + } + recno += cd->bracount; + } + + /* Come here from code above that handles a named recursion */ + + HANDLE_RECURSION: + + previous = code; + called = cd->start_code; + + /* When we are actually compiling, find the bracket that is being + referenced. Temporarily end the regex in case it doesn't exist before + this point. If we end up with a forward reference, first check that + the bracket does occur later so we can give the error (and position) + now. Then remember this forward reference in the workspace so it can + be filled in at the end. */ + + if (lengthptr == NULL) + { + *code = OP_END; + if (recno != 0) called = find_bracket(cd->start_code, utf8, recno); + + /* Forward reference */ + + if (called == NULL) + { + if (find_parens(ptr, cd->bracount, NULL, recno, + (options & PCRE_EXTENDED) != 0) < 0) + { + *errorcodeptr = ERR15; + goto FAILED; + } + called = cd->start_code + recno; + PUTINC(cd->hwm, 0, code + 2 + LINK_SIZE - cd->start_code); + } + + /* If not a forward reference, and the subpattern is still open, + this is a recursive call. We check to see if this is a left + recursion that could loop for ever, and diagnose that case. */ + + else if (GET(called, 1) == 0 && + could_be_empty(called, code, bcptr, utf8)) + { + *errorcodeptr = ERR40; + goto FAILED; + } + } + + /* Insert the recursion/subroutine item, automatically wrapped inside + "once" brackets. Set up a "previous group" length so that a + subsequent quantifier will work. */ + + *code = OP_ONCE; + PUT(code, 1, 2 + 2*LINK_SIZE); + code += 1 + LINK_SIZE; + + *code = OP_RECURSE; + PUT(code, 1, called - cd->start_code); + code += 1 + LINK_SIZE; + + *code = OP_KET; + PUT(code, 1, 2 + 2*LINK_SIZE); + code += 1 + LINK_SIZE; + + length_prevgroup = 3 + 3*LINK_SIZE; + } + + /* Can't determine a first byte now */ + + if (firstbyte == REQ_UNSET) firstbyte = REQ_NONE; + continue; + + + /* ------------------------------------------------------------ */ + default: /* Other characters: check option setting */ + OTHER_CHAR_AFTER_QUERY: + set = unset = 0; + optset = &set; + + while (*ptr != ')' && *ptr != ':') + { + switch (*ptr++) + { + case '-': optset = &unset; break; + + case 'J': /* Record that it changed in the external options */ + *optset |= PCRE_DUPNAMES; + cd->external_flags |= PCRE_JCHANGED; + break; + + case 'i': *optset |= PCRE_CASELESS; break; + case 'm': *optset |= PCRE_MULTILINE; break; + case 's': *optset |= PCRE_DOTALL; break; + case 'x': *optset |= PCRE_EXTENDED; break; + case 'U': *optset |= PCRE_UNGREEDY; break; + case 'X': *optset |= PCRE_EXTRA; break; + + default: *errorcodeptr = ERR12; + ptr--; /* Correct the offset */ + goto FAILED; + } + } + + /* Set up the changed option bits, but don't change anything yet. */ + + newoptions = (options | set) & (~unset); + + /* If the options ended with ')' this is not the start of a nested + group with option changes, so the options change at this level. If this + item is right at the start of the pattern, the options can be + abstracted and made external in the pre-compile phase, and ignored in + the compile phase. This can be helpful when matching -- for instance in + caseless checking of required bytes. + + If the code pointer is not (cd->start_code + 1 + LINK_SIZE), we are + definitely *not* at the start of the pattern because something has been + compiled. In the pre-compile phase, however, the code pointer can have + that value after the start, because it gets reset as code is discarded + during the pre-compile. However, this can happen only at top level - if + we are within parentheses, the starting BRA will still be present. At + any parenthesis level, the length value can be used to test if anything + has been compiled at that level. Thus, a test for both these conditions + is necessary to ensure we correctly detect the start of the pattern in + both phases. + + If we are not at the pattern start, compile code to change the ims + options if this setting actually changes any of them. We also pass the + new setting back so that it can be put at the start of any following + branches, and when this group ends (if we are in a group), a resetting + item can be compiled. */ + + if (*ptr == ')') + { + if (code == cd->start_code + 1 + LINK_SIZE && + (lengthptr == NULL || *lengthptr == 2 + 2*LINK_SIZE)) + { + cd->external_options = newoptions; + options = newoptions; + } + else + { + if ((options & PCRE_IMS) != (newoptions & PCRE_IMS)) + { + *code++ = OP_OPT; + *code++ = newoptions & PCRE_IMS; + } + + /* Change options at this level, and pass them back for use + in subsequent branches. Reset the greedy defaults and the case + value for firstbyte and reqbyte. */ + + *optionsptr = options = newoptions; + greedy_default = ((newoptions & PCRE_UNGREEDY) != 0); + greedy_non_default = greedy_default ^ 1; + req_caseopt = ((options & PCRE_CASELESS) != 0)? REQ_CASELESS : 0; + } + + previous = NULL; /* This item can't be repeated */ + continue; /* It is complete */ + } + + /* If the options ended with ':' we are heading into a nested group + with possible change of options. Such groups are non-capturing and are + not assertions of any kind. All we need to do is skip over the ':'; + the newoptions value is handled below. */ + + bravalue = OP_BRA; + ptr++; + } /* End of switch for character following (? */ + } /* End of (? handling */ + + /* Opening parenthesis not followed by '?'. If PCRE_NO_AUTO_CAPTURE is set, + all unadorned brackets become non-capturing and behave like (?:...) + brackets. */ + + else if ((options & PCRE_NO_AUTO_CAPTURE) != 0) + { + bravalue = OP_BRA; + } + + /* Else we have a capturing group. */ + + else + { + NUMBERED_GROUP: + cd->bracount += 1; + PUT2(code, 1+LINK_SIZE, cd->bracount); + skipbytes = 2; + } + + /* Process nested bracketed regex. Assertions may not be repeated, but + other kinds can be. All their opcodes are >= OP_ONCE. We copy code into a + non-register variable in order to be able to pass its address because some + compilers complain otherwise. Pass in a new setting for the ims options if + they have changed. */ + + previous = (bravalue >= OP_ONCE)? code : NULL; + *code = bravalue; + tempcode = code; + tempreqvary = cd->req_varyopt; /* Save value before bracket */ + length_prevgroup = 0; /* Initialize for pre-compile phase */ + + if (!compile_regex( + newoptions, /* The complete new option state */ + options & PCRE_IMS, /* The previous ims option state */ + &tempcode, /* Where to put code (updated) */ + &ptr, /* Input pointer (updated) */ + errorcodeptr, /* Where to put an error message */ + (bravalue == OP_ASSERTBACK || + bravalue == OP_ASSERTBACK_NOT), /* TRUE if back assert */ + reset_bracount, /* True if (?| group */ + skipbytes, /* Skip over bracket number */ + &subfirstbyte, /* For possible first char */ + &subreqbyte, /* For possible last char */ + bcptr, /* Current branch chain */ + cd, /* Tables block */ + (lengthptr == NULL)? NULL : /* Actual compile phase */ + &length_prevgroup /* Pre-compile phase */ + )) + goto FAILED; + + /* At the end of compiling, code is still pointing to the start of the + group, while tempcode has been updated to point past the end of the group + and any option resetting that may follow it. The pattern pointer (ptr) + is on the bracket. */ + + /* If this is a conditional bracket, check that there are no more than + two branches in the group, or just one if it's a DEFINE group. We do this + in the real compile phase, not in the pre-pass, where the whole group may + not be available. */ + + if (bravalue == OP_COND && lengthptr == NULL) + { + uschar *tc = code; + int condcount = 0; + + do { + condcount++; + tc += GET(tc,1); + } + while (*tc != OP_KET); + + /* A DEFINE group is never obeyed inline (the "condition" is always + false). It must have only one branch. */ + + if (code[LINK_SIZE+1] == OP_DEF) + { + if (condcount > 1) + { + *errorcodeptr = ERR54; + goto FAILED; + } + bravalue = OP_DEF; /* Just a flag to suppress char handling below */ + } + + /* A "normal" conditional group. If there is just one branch, we must not + make use of its firstbyte or reqbyte, because this is equivalent to an + empty second branch. */ + + else + { + if (condcount > 2) + { + *errorcodeptr = ERR27; + goto FAILED; + } + if (condcount == 1) subfirstbyte = subreqbyte = REQ_NONE; + } + } + + /* Error if hit end of pattern */ + + if (*ptr != ')') + { + *errorcodeptr = ERR14; + goto FAILED; + } + + /* In the pre-compile phase, update the length by the length of the group, + less the brackets at either end. Then reduce the compiled code to just a + set of non-capturing brackets so that it doesn't use much memory if it is + duplicated by a quantifier.*/ + + if (lengthptr != NULL) + { + if (OFLOW_MAX - *lengthptr < length_prevgroup - 2 - 2*LINK_SIZE) + { + *errorcodeptr = ERR20; + goto FAILED; + } + *lengthptr += length_prevgroup - 2 - 2*LINK_SIZE; + *code++ = OP_BRA; + PUTINC(code, 0, 1 + LINK_SIZE); + *code++ = OP_KET; + PUTINC(code, 0, 1 + LINK_SIZE); + break; /* No need to waste time with special character handling */ + } + + /* Otherwise update the main code pointer to the end of the group. */ + + code = tempcode; + + /* For a DEFINE group, required and first character settings are not + relevant. */ + + if (bravalue == OP_DEF) break; + + /* Handle updating of the required and first characters for other types of + group. Update for normal brackets of all kinds, and conditions with two + branches (see code above). If the bracket is followed by a quantifier with + zero repeat, we have to back off. Hence the definition of zeroreqbyte and + zerofirstbyte outside the main loop so that they can be accessed for the + back off. */ + + zeroreqbyte = reqbyte; + zerofirstbyte = firstbyte; + groupsetfirstbyte = FALSE; + + if (bravalue >= OP_ONCE) + { + /* If we have not yet set a firstbyte in this branch, take it from the + subpattern, remembering that it was set here so that a repeat of more + than one can replicate it as reqbyte if necessary. If the subpattern has + no firstbyte, set "none" for the whole branch. In both cases, a zero + repeat forces firstbyte to "none". */ + + if (firstbyte == REQ_UNSET) + { + if (subfirstbyte >= 0) + { + firstbyte = subfirstbyte; + groupsetfirstbyte = TRUE; + } + else firstbyte = REQ_NONE; + zerofirstbyte = REQ_NONE; + } + + /* If firstbyte was previously set, convert the subpattern's firstbyte + into reqbyte if there wasn't one, using the vary flag that was in + existence beforehand. */ + + else if (subfirstbyte >= 0 && subreqbyte < 0) + subreqbyte = subfirstbyte | tempreqvary; + + /* If the subpattern set a required byte (or set a first byte that isn't + really the first byte - see above), set it. */ + + if (subreqbyte >= 0) reqbyte = subreqbyte; + } + + /* For a forward assertion, we take the reqbyte, if set. This can be + helpful if the pattern that follows the assertion doesn't set a different + char. For example, it's useful for /(?=abcde).+/. We can't set firstbyte + for an assertion, however because it leads to incorrect effect for patterns + such as /(?=a)a.+/ when the "real" "a" would then become a reqbyte instead + of a firstbyte. This is overcome by a scan at the end if there's no + firstbyte, looking for an asserted first char. */ + + else if (bravalue == OP_ASSERT && subreqbyte >= 0) reqbyte = subreqbyte; + break; /* End of processing '(' */ + + + /* ===================================================================*/ + /* Handle metasequences introduced by \. For ones like \d, the ESC_ values + are arranged to be the negation of the corresponding OP_values. For the + back references, the values are ESC_REF plus the reference number. Only + back references and those types that consume a character may be repeated. + We can test for values between ESC_b and ESC_Z for the latter; this may + have to change if any new ones are ever created. */ + + case '\\': + tempptr = ptr; + c = check_escape(&ptr, errorcodeptr, cd->bracount, options, FALSE); + if (*errorcodeptr != 0) goto FAILED; + + if (c < 0) + { + if (-c == ESC_Q) /* Handle start of quoted string */ + { + if (ptr[1] == '\\' && ptr[2] == 'E') ptr += 2; /* avoid empty string */ + else inescq = TRUE; + continue; + } + + if (-c == ESC_E) continue; /* Perl ignores an orphan \E */ + + /* For metasequences that actually match a character, we disable the + setting of a first character if it hasn't already been set. */ + + if (firstbyte == REQ_UNSET && -c > ESC_b && -c < ESC_Z) + firstbyte = REQ_NONE; + + /* Set values to reset to if this is followed by a zero repeat. */ + + zerofirstbyte = firstbyte; + zeroreqbyte = reqbyte; + + /* \k or \k'name' is a back reference by name (Perl syntax). + We also support \k{name} (.NET syntax) */ + + if (-c == ESC_k && (ptr[1] == '<' || ptr[1] == '\'' || ptr[1] == '{')) + { + is_recurse = FALSE; + terminator = (*(++ptr) == '<')? '>' : (*ptr == '\'')? '\'' : '}'; + goto NAMED_REF_OR_RECURSE; + } + + /* Back references are handled specially; must disable firstbyte if + not set to cope with cases like (?=(\w+))\1: which would otherwise set + ':' later. */ + + if (-c >= ESC_REF) + { + recno = -c - ESC_REF; + + HANDLE_REFERENCE: /* Come here from named backref handling */ + if (firstbyte == REQ_UNSET) firstbyte = REQ_NONE; + previous = code; + *code++ = OP_REF; + PUT2INC(code, 0, recno); + cd->backref_map |= (recno < 32)? (1 << recno) : 1; + if (recno > cd->top_backref) cd->top_backref = recno; + } + + /* So are Unicode property matches, if supported. */ + +#ifdef SUPPORT_UCP + else if (-c == ESC_P || -c == ESC_p) + { + BOOL negated; + int pdata; + int ptype = get_ucp(&ptr, &negated, &pdata, errorcodeptr); + if (ptype < 0) goto FAILED; + previous = code; + *code++ = ((-c == ESC_p) != negated)? OP_PROP : OP_NOTPROP; + *code++ = ptype; + *code++ = pdata; + } +#else + + /* If Unicode properties are not supported, \X, \P, and \p are not + allowed. */ + + else if (-c == ESC_X || -c == ESC_P || -c == ESC_p) + { + *errorcodeptr = ERR45; + goto FAILED; + } +#endif + + /* For the rest (including \X when Unicode properties are supported), we + can obtain the OP value by negating the escape value. */ + + else + { + previous = (-c > ESC_b && -c < ESC_Z)? code : NULL; + *code++ = -c; + } + continue; + } + + /* We have a data character whose value is in c. In UTF-8 mode it may have + a value > 127. We set its representation in the length/buffer, and then + handle it as a data character. */ + +#ifdef SUPPORT_UTF8 + if (utf8 && c > 127) + mclength = _pcre_ord2utf8(c, mcbuffer); + else +#endif + + { + mcbuffer[0] = c; + mclength = 1; + } + goto ONE_CHAR; + + + /* ===================================================================*/ + /* Handle a literal character. It is guaranteed not to be whitespace or # + when the extended flag is set. If we are in UTF-8 mode, it may be a + multi-byte literal character. */ + + default: + NORMAL_CHAR: + mclength = 1; + mcbuffer[0] = c; + +#ifdef SUPPORT_UTF8 + if (utf8 && c >= 0xc0) + { + while ((ptr[1] & 0xc0) == 0x80) + mcbuffer[mclength++] = *(++ptr); + } +#endif + + /* At this point we have the character's bytes in mcbuffer, and the length + in mclength. When not in UTF-8 mode, the length is always 1. */ + + ONE_CHAR: + previous = code; + *code++ = ((options & PCRE_CASELESS) != 0)? OP_CHARNC : OP_CHAR; + for (c = 0; c < mclength; c++) *code++ = mcbuffer[c]; + + /* Remember if \r or \n were seen */ + + if (mcbuffer[0] == '\r' || mcbuffer[0] == '\n') + cd->external_flags |= PCRE_HASCRORLF; + + /* Set the first and required bytes appropriately. If no previous first + byte, set it from this character, but revert to none on a zero repeat. + Otherwise, leave the firstbyte value alone, and don't change it on a zero + repeat. */ + + if (firstbyte == REQ_UNSET) + { + zerofirstbyte = REQ_NONE; + zeroreqbyte = reqbyte; + + /* If the character is more than one byte long, we can set firstbyte + only if it is not to be matched caselessly. */ + + if (mclength == 1 || req_caseopt == 0) + { + firstbyte = mcbuffer[0] | req_caseopt; + if (mclength != 1) reqbyte = code[-1] | cd->req_varyopt; + } + else firstbyte = reqbyte = REQ_NONE; + } + + /* firstbyte was previously set; we can set reqbyte only the length is + 1 or the matching is caseful. */ + + else + { + zerofirstbyte = firstbyte; + zeroreqbyte = reqbyte; + if (mclength == 1 || req_caseopt == 0) + reqbyte = code[-1] | req_caseopt | cd->req_varyopt; + } + + break; /* End of literal character handling */ + } + } /* end of big loop */ + + +/* Control never reaches here by falling through, only by a goto for all the +error states. Pass back the position in the pattern so that it can be displayed +to the user for diagnosing the error. */ + +FAILED: +*ptrptr = ptr; +return FALSE; +} + + + + +/************************************************* +* Compile sequence of alternatives * +*************************************************/ + +/* On entry, ptr is pointing past the bracket character, but on return it +points to the closing bracket, or vertical bar, or end of string. The code +variable is pointing at the byte into which the BRA operator has been stored. +If the ims options are changed at the start (for a (?ims: group) or during any +branch, we need to insert an OP_OPT item at the start of every following branch +to ensure they get set correctly at run time, and also pass the new options +into every subsequent branch compile. + +This function is used during the pre-compile phase when we are trying to find +out the amount of memory needed, as well as during the real compile phase. The +value of lengthptr distinguishes the two phases. + +Arguments: + options option bits, including any changes for this subpattern + oldims previous settings of ims option bits + codeptr -> the address of the current code pointer + ptrptr -> the address of the current pattern pointer + errorcodeptr -> pointer to error code variable + lookbehind TRUE if this is a lookbehind assertion + reset_bracount TRUE to reset the count for each branch + skipbytes skip this many bytes at start (for brackets and OP_COND) + firstbyteptr place to put the first required character, or a negative number + reqbyteptr place to put the last required character, or a negative number + bcptr pointer to the chain of currently open branches + cd points to the data block with tables pointers etc. + lengthptr NULL during the real compile phase + points to length accumulator during pre-compile phase + +Returns: TRUE on success +*/ + +static BOOL +compile_regex(int options, int oldims, uschar **codeptr, const uschar **ptrptr, + int *errorcodeptr, BOOL lookbehind, BOOL reset_bracount, int skipbytes, + int *firstbyteptr, int *reqbyteptr, branch_chain *bcptr, compile_data *cd, + int *lengthptr) +{ +const uschar *ptr = *ptrptr; +uschar *code = *codeptr; +uschar *last_branch = code; +uschar *start_bracket = code; +uschar *reverse_count = NULL; +int firstbyte, reqbyte; +int branchfirstbyte, branchreqbyte; +int length; +int orig_bracount; +int max_bracount; +branch_chain bc; + +bc.outer = bcptr; +bc.current = code; + +firstbyte = reqbyte = REQ_UNSET; + +/* Accumulate the length for use in the pre-compile phase. Start with the +length of the BRA and KET and any extra bytes that are required at the +beginning. We accumulate in a local variable to save frequent testing of +lenthptr for NULL. We cannot do this by looking at the value of code at the +start and end of each alternative, because compiled items are discarded during +the pre-compile phase so that the work space is not exceeded. */ + +length = 2 + 2*LINK_SIZE + skipbytes; + +/* WARNING: If the above line is changed for any reason, you must also change +the code that abstracts option settings at the start of the pattern and makes +them global. It tests the value of length for (2 + 2*LINK_SIZE) in the +pre-compile phase to find out whether anything has yet been compiled or not. */ + +/* Offset is set zero to mark that this bracket is still open */ + +PUT(code, 1, 0); +code += 1 + LINK_SIZE + skipbytes; + +/* Loop for each alternative branch */ + +orig_bracount = max_bracount = cd->bracount; +for (;;) + { + /* For a (?| group, reset the capturing bracket count so that each branch + uses the same numbers. */ + + if (reset_bracount) cd->bracount = orig_bracount; + + /* Handle a change of ims options at the start of the branch */ + + if ((options & PCRE_IMS) != oldims) + { + *code++ = OP_OPT; + *code++ = options & PCRE_IMS; + length += 2; + } + + /* Set up dummy OP_REVERSE if lookbehind assertion */ + + if (lookbehind) + { + *code++ = OP_REVERSE; + reverse_count = code; + PUTINC(code, 0, 0); + length += 1 + LINK_SIZE; + } + + /* Now compile the branch; in the pre-compile phase its length gets added + into the length. */ + + if (!compile_branch(&options, &code, &ptr, errorcodeptr, &branchfirstbyte, + &branchreqbyte, &bc, cd, (lengthptr == NULL)? NULL : &length)) + { + *ptrptr = ptr; + return FALSE; + } + + /* Keep the highest bracket count in case (?| was used and some branch + has fewer than the rest. */ + + if (cd->bracount > max_bracount) max_bracount = cd->bracount; + + /* In the real compile phase, there is some post-processing to be done. */ + + if (lengthptr == NULL) + { + /* If this is the first branch, the firstbyte and reqbyte values for the + branch become the values for the regex. */ + + if (*last_branch != OP_ALT) + { + firstbyte = branchfirstbyte; + reqbyte = branchreqbyte; + } + + /* If this is not the first branch, the first char and reqbyte have to + match the values from all the previous branches, except that if the + previous value for reqbyte didn't have REQ_VARY set, it can still match, + and we set REQ_VARY for the regex. */ + + else + { + /* If we previously had a firstbyte, but it doesn't match the new branch, + we have to abandon the firstbyte for the regex, but if there was + previously no reqbyte, it takes on the value of the old firstbyte. */ + + if (firstbyte >= 0 && firstbyte != branchfirstbyte) + { + if (reqbyte < 0) reqbyte = firstbyte; + firstbyte = REQ_NONE; + } + + /* If we (now or from before) have no firstbyte, a firstbyte from the + branch becomes a reqbyte if there isn't a branch reqbyte. */ + + if (firstbyte < 0 && branchfirstbyte >= 0 && branchreqbyte < 0) + branchreqbyte = branchfirstbyte; + + /* Now ensure that the reqbytes match */ + + if ((reqbyte & ~REQ_VARY) != (branchreqbyte & ~REQ_VARY)) + reqbyte = REQ_NONE; + else reqbyte |= branchreqbyte; /* To "or" REQ_VARY */ + } + + /* If lookbehind, check that this branch matches a fixed-length string, and + put the length into the OP_REVERSE item. Temporarily mark the end of the + branch with OP_END. */ + + if (lookbehind) + { + int fixed_length; + *code = OP_END; + fixed_length = find_fixedlength(last_branch, options); + DPRINTF(("fixed length = %d\n", fixed_length)); + if (fixed_length < 0) + { + *errorcodeptr = (fixed_length == -2)? ERR36 : ERR25; + *ptrptr = ptr; + return FALSE; + } + PUT(reverse_count, 0, fixed_length); + } + } + + /* Reached end of expression, either ')' or end of pattern. In the real + compile phase, go back through the alternative branches and reverse the chain + of offsets, with the field in the BRA item now becoming an offset to the + first alternative. If there are no alternatives, it points to the end of the + group. The length in the terminating ket is always the length of the whole + bracketed item. If any of the ims options were changed inside the group, + compile a resetting op-code following, except at the very end of the pattern. + Return leaving the pointer at the terminating char. */ + + if (*ptr != '|') + { + if (lengthptr == NULL) + { + int branch_length = code - last_branch; + do + { + int prev_length = GET(last_branch, 1); + PUT(last_branch, 1, branch_length); + branch_length = prev_length; + last_branch -= branch_length; + } + while (branch_length > 0); + } + + /* Fill in the ket */ + + *code = OP_KET; + PUT(code, 1, code - start_bracket); + code += 1 + LINK_SIZE; + + /* Resetting option if needed */ + + if ((options & PCRE_IMS) != oldims && *ptr == ')') + { + *code++ = OP_OPT; + *code++ = oldims; + length += 2; + } + + /* Retain the highest bracket number, in case resetting was used. */ + + cd->bracount = max_bracount; + + /* Set values to pass back */ + + *codeptr = code; + *ptrptr = ptr; + *firstbyteptr = firstbyte; + *reqbyteptr = reqbyte; + if (lengthptr != NULL) + { + if (OFLOW_MAX - *lengthptr < length) + { + *errorcodeptr = ERR20; + return FALSE; + } + *lengthptr += length; + } + return TRUE; + } + + /* Another branch follows. In the pre-compile phase, we can move the code + pointer back to where it was for the start of the first branch. (That is, + pretend that each branch is the only one.) + + In the real compile phase, insert an ALT node. Its length field points back + to the previous branch while the bracket remains open. At the end the chain + is reversed. It's done like this so that the start of the bracket has a + zero offset until it is closed, making it possible to detect recursion. */ + + if (lengthptr != NULL) + { + code = *codeptr + 1 + LINK_SIZE + skipbytes; + length += 1 + LINK_SIZE; + } + else + { + *code = OP_ALT; + PUT(code, 1, code - last_branch); + bc.current = last_branch = code; + code += 1 + LINK_SIZE; + } + + ptr++; + } +/* Control never reaches here */ +} + + + + +/************************************************* +* Check for anchored expression * +*************************************************/ + +/* Try to find out if this is an anchored regular expression. Consider each +alternative branch. If they all start with OP_SOD or OP_CIRC, or with a bracket +all of whose alternatives start with OP_SOD or OP_CIRC (recurse ad lib), then +it's anchored. However, if this is a multiline pattern, then only OP_SOD +counts, since OP_CIRC can match in the middle. + +We can also consider a regex to be anchored if OP_SOM starts all its branches. +This is the code for \G, which means "match at start of match position, taking +into account the match offset". + +A branch is also implicitly anchored if it starts with .* and DOTALL is set, +because that will try the rest of the pattern at all possible matching points, +so there is no point trying again.... er .... + +.... except when the .* appears inside capturing parentheses, and there is a +subsequent back reference to those parentheses. We haven't enough information +to catch that case precisely. + +At first, the best we could do was to detect when .* was in capturing brackets +and the highest back reference was greater than or equal to that level. +However, by keeping a bitmap of the first 31 back references, we can catch some +of the more common cases more precisely. + +Arguments: + code points to start of expression (the bracket) + options points to the options setting + bracket_map a bitmap of which brackets we are inside while testing; this + handles up to substring 31; after that we just have to take + the less precise approach + backref_map the back reference bitmap + +Returns: TRUE or FALSE +*/ + +static BOOL +is_anchored(register const uschar *code, int *options, unsigned int bracket_map, + unsigned int backref_map) +{ +do { + const uschar *scode = first_significant_code(code + _pcre_OP_lengths[*code], + options, PCRE_MULTILINE, FALSE); + register int op = *scode; + + /* Non-capturing brackets */ + + if (op == OP_BRA) + { + if (!is_anchored(scode, options, bracket_map, backref_map)) return FALSE; + } + + /* Capturing brackets */ + + else if (op == OP_CBRA) + { + int n = GET2(scode, 1+LINK_SIZE); + int new_map = bracket_map | ((n < 32)? (1 << n) : 1); + if (!is_anchored(scode, options, new_map, backref_map)) return FALSE; + } + + /* Other brackets */ + + else if (op == OP_ASSERT || op == OP_ONCE || op == OP_COND) + { + if (!is_anchored(scode, options, bracket_map, backref_map)) return FALSE; + } + + /* .* is not anchored unless DOTALL is set and it isn't in brackets that + are or may be referenced. */ + + else if ((op == OP_TYPESTAR || op == OP_TYPEMINSTAR || + op == OP_TYPEPOSSTAR) && + (*options & PCRE_DOTALL) != 0) + { + if (scode[1] != OP_ANY || (bracket_map & backref_map) != 0) return FALSE; + } + + /* Check for explicit anchoring */ + + else if (op != OP_SOD && op != OP_SOM && + ((*options & PCRE_MULTILINE) != 0 || op != OP_CIRC)) + return FALSE; + code += GET(code, 1); + } +while (*code == OP_ALT); /* Loop for each alternative */ +return TRUE; +} + + + +/************************************************* +* Check for starting with ^ or .* * +*************************************************/ + +/* This is called to find out if every branch starts with ^ or .* so that +"first char" processing can be done to speed things up in multiline +matching and for non-DOTALL patterns that start with .* (which must start at +the beginning or after \n). As in the case of is_anchored() (see above), we +have to take account of back references to capturing brackets that contain .* +because in that case we can't make the assumption. + +Arguments: + code points to start of expression (the bracket) + bracket_map a bitmap of which brackets we are inside while testing; this + handles up to substring 31; after that we just have to take + the less precise approach + backref_map the back reference bitmap + +Returns: TRUE or FALSE +*/ + +static BOOL +is_startline(const uschar *code, unsigned int bracket_map, + unsigned int backref_map) +{ +do { + const uschar *scode = first_significant_code(code + _pcre_OP_lengths[*code], + NULL, 0, FALSE); + register int op = *scode; + + /* Non-capturing brackets */ + + if (op == OP_BRA) + { + if (!is_startline(scode, bracket_map, backref_map)) return FALSE; + } + + /* Capturing brackets */ + + else if (op == OP_CBRA) + { + int n = GET2(scode, 1+LINK_SIZE); + int new_map = bracket_map | ((n < 32)? (1 << n) : 1); + if (!is_startline(scode, new_map, backref_map)) return FALSE; + } + + /* Other brackets */ + + else if (op == OP_ASSERT || op == OP_ONCE || op == OP_COND) + { if (!is_startline(scode, bracket_map, backref_map)) return FALSE; } + + /* .* means "start at start or after \n" if it isn't in brackets that + may be referenced. */ + + else if (op == OP_TYPESTAR || op == OP_TYPEMINSTAR || op == OP_TYPEPOSSTAR) + { + if (scode[1] != OP_ANY || (bracket_map & backref_map) != 0) return FALSE; + } + + /* Check for explicit circumflex */ + + else if (op != OP_CIRC) return FALSE; + + /* Move on to the next alternative */ + + code += GET(code, 1); + } +while (*code == OP_ALT); /* Loop for each alternative */ +return TRUE; +} + + + +/************************************************* +* Check for asserted fixed first char * +*************************************************/ + +/* During compilation, the "first char" settings from forward assertions are +discarded, because they can cause conflicts with actual literals that follow. +However, if we end up without a first char setting for an unanchored pattern, +it is worth scanning the regex to see if there is an initial asserted first +char. If all branches start with the same asserted char, or with a bracket all +of whose alternatives start with the same asserted char (recurse ad lib), then +we return that char, otherwise -1. + +Arguments: + code points to start of expression (the bracket) + options pointer to the options (used to check casing changes) + inassert TRUE if in an assertion + +Returns: -1 or the fixed first char +*/ + +static int +find_firstassertedchar(const uschar *code, int *options, BOOL inassert) +{ +register int c = -1; +do { + int d; + const uschar *scode = + first_significant_code(code + 1+LINK_SIZE, options, PCRE_CASELESS, TRUE); + register int op = *scode; + + switch(op) + { + default: + return -1; + + case OP_BRA: + case OP_CBRA: + case OP_ASSERT: + case OP_ONCE: + case OP_COND: + if ((d = find_firstassertedchar(scode, options, op == OP_ASSERT)) < 0) + return -1; + if (c < 0) c = d; else if (c != d) return -1; + break; + + case OP_EXACT: /* Fall through */ + scode += 2; + + case OP_CHAR: + case OP_CHARNC: + case OP_PLUS: + case OP_MINPLUS: + case OP_POSPLUS: + if (!inassert) return -1; + if (c < 0) + { + c = scode[1]; + if ((*options & PCRE_CASELESS) != 0) c |= REQ_CASELESS; + } + else if (c != scode[1]) return -1; + break; + } + + code += GET(code, 1); + } +while (*code == OP_ALT); +return c; +} + + + +/************************************************* +* Compile a Regular Expression * +*************************************************/ + +/* This function takes a string and returns a pointer to a block of store +holding a compiled version of the expression. The original API for this +function had no error code return variable; it is retained for backwards +compatibility. The new function is given a new name. + +Arguments: + pattern the regular expression + options various option bits + errorcodeptr pointer to error code variable (pcre_compile2() only) + can be NULL if you don't want a code value + errorptr pointer to pointer to error text + erroroffset ptr offset in pattern where error was detected + tables pointer to character tables or NULL + +Returns: pointer to compiled data block, or NULL on error, + with errorptr and erroroffset set +*/ + +pcre * +pcre_compile(const char *pattern, int options, const char **errorptr, + int *erroroffset, const unsigned char *tables) +{ +return pcre_compile2(pattern, options, NULL, errorptr, erroroffset, tables); +} + + +pcre * +pcre_compile2(const char *pattern, int options, int *errorcodeptr, + const char **errorptr, int *erroroffset, const unsigned char *tables) +{ +real_pcre *re; +int length = 1; /* For final END opcode */ +int firstbyte, reqbyte, newline; +int errorcode = 0; +int skipatstart = 0; +#ifdef SUPPORT_UTF8 +BOOL utf8; +#endif +size_t size; +uschar *code; +const uschar *codestart; +const uschar *ptr; +compile_data compile_block; +compile_data *cd = &compile_block; + +/* This space is used for "compiling" into during the first phase, when we are +computing the amount of memory that is needed. Compiled items are thrown away +as soon as possible, so that a fairly large buffer should be sufficient for +this purpose. The same space is used in the second phase for remembering where +to fill in forward references to subpatterns. */ + +uschar cworkspace[COMPILE_WORK_SIZE]; + +/* Set this early so that early errors get offset 0. */ + +ptr = (const uschar *)pattern; + +/* We can't pass back an error message if errorptr is NULL; I guess the best we +can do is just return NULL, but we can set a code value if there is a code +pointer. */ + +if (errorptr == NULL) + { + if (errorcodeptr != NULL) *errorcodeptr = 99; + return NULL; + } + +*errorptr = NULL; +if (errorcodeptr != NULL) *errorcodeptr = ERR0; + +/* However, we can give a message for this error */ + +if (erroroffset == NULL) + { + errorcode = ERR16; + goto PCRE_EARLY_ERROR_RETURN2; + } + +*erroroffset = 0; + +/* Can't support UTF8 unless PCRE has been compiled to include the code. */ + +#ifdef SUPPORT_UTF8 +utf8 = (options & PCRE_UTF8) != 0; +if (utf8 && (options & PCRE_NO_UTF8_CHECK) == 0 && + (*erroroffset = _pcre_valid_utf8((uschar *)pattern, -1)) >= 0) + { + errorcode = ERR44; + goto PCRE_EARLY_ERROR_RETURN2; + } +#else +if ((options & PCRE_UTF8) != 0) + { + errorcode = ERR32; + goto PCRE_EARLY_ERROR_RETURN; + } +#endif + +if ((options & ~PUBLIC_OPTIONS) != 0) + { + errorcode = ERR17; + goto PCRE_EARLY_ERROR_RETURN; + } + +/* Set up pointers to the individual character tables */ + +if (tables == NULL) tables = _pcre_default_tables; +cd->lcc = tables + lcc_offset; +cd->fcc = tables + fcc_offset; +cd->cbits = tables + cbits_offset; +cd->ctypes = tables + ctypes_offset; + +/* Check for global one-time settings at the start of the pattern, and remember +the offset for later. */ + +while (ptr[skipatstart] == '(' && ptr[skipatstart+1] == '*') + { + int newnl = 0; + int newbsr = 0; + + if (strncmp((char *)(ptr+skipatstart+2), "CR)", 3) == 0) + { skipatstart += 5; newnl = PCRE_NEWLINE_CR; } + else if (strncmp((char *)(ptr+skipatstart+2), "LF)", 3) == 0) + { skipatstart += 5; newnl = PCRE_NEWLINE_LF; } + else if (strncmp((char *)(ptr+skipatstart+2), "CRLF)", 5) == 0) + { skipatstart += 7; newnl = PCRE_NEWLINE_CR + PCRE_NEWLINE_LF; } + else if (strncmp((char *)(ptr+skipatstart+2), "ANY)", 4) == 0) + { skipatstart += 6; newnl = PCRE_NEWLINE_ANY; } + else if (strncmp((char *)(ptr+skipatstart+2), "ANYCRLF)", 8) == 0) + { skipatstart += 10; newnl = PCRE_NEWLINE_ANYCRLF; } + + else if (strncmp((char *)(ptr+skipatstart+2), "BSR_ANYCRLF)", 12) == 0) + { skipatstart += 14; newbsr = PCRE_BSR_ANYCRLF; } + else if (strncmp((char *)(ptr+skipatstart+2), "BSR_UNICODE)", 12) == 0) + { skipatstart += 14; newbsr = PCRE_BSR_UNICODE; } + + if (newnl != 0) + options = (options & ~PCRE_NEWLINE_BITS) | newnl; + else if (newbsr != 0) + options = (options & ~(PCRE_BSR_ANYCRLF|PCRE_BSR_UNICODE)) | newbsr; + else break; + } + +/* Check validity of \R options. */ + +switch (options & (PCRE_BSR_ANYCRLF|PCRE_BSR_UNICODE)) + { + case 0: + case PCRE_BSR_ANYCRLF: + case PCRE_BSR_UNICODE: + break; + default: errorcode = ERR56; goto PCRE_EARLY_ERROR_RETURN; + } + +/* Handle different types of newline. The three bits give seven cases. The +current code allows for fixed one- or two-byte sequences, plus "any" and +"anycrlf". */ + +switch (options & PCRE_NEWLINE_BITS) + { + case 0: newline = NEWLINE; break; /* Build-time default */ + case PCRE_NEWLINE_CR: newline = '\r'; break; + case PCRE_NEWLINE_LF: newline = '\n'; break; + case PCRE_NEWLINE_CR+ + PCRE_NEWLINE_LF: newline = ('\r' << 8) | '\n'; break; + case PCRE_NEWLINE_ANY: newline = -1; break; + case PCRE_NEWLINE_ANYCRLF: newline = -2; break; + default: errorcode = ERR56; goto PCRE_EARLY_ERROR_RETURN; + } + +if (newline == -2) + { + cd->nltype = NLTYPE_ANYCRLF; + } +else if (newline < 0) + { + cd->nltype = NLTYPE_ANY; + } +else + { + cd->nltype = NLTYPE_FIXED; + if (newline > 255) + { + cd->nllen = 2; + cd->nl[0] = (newline >> 8) & 255; + cd->nl[1] = newline & 255; + } + else + { + cd->nllen = 1; + cd->nl[0] = newline; + } + } + +/* Maximum back reference and backref bitmap. The bitmap records up to 31 back +references to help in deciding whether (.*) can be treated as anchored or not. +*/ + +cd->top_backref = 0; +cd->backref_map = 0; + +/* Reflect pattern for debugging output */ + +DPRINTF(("------------------------------------------------------------------\n")); +DPRINTF(("%s\n", pattern)); + +/* Pretend to compile the pattern while actually just accumulating the length +of memory required. This behaviour is triggered by passing a non-NULL final +argument to compile_regex(). We pass a block of workspace (cworkspace) for it +to compile parts of the pattern into; the compiled code is discarded when it is +no longer needed, so hopefully this workspace will never overflow, though there +is a test for its doing so. */ + +cd->bracount = cd->final_bracount = 0; +cd->names_found = 0; +cd->name_entry_size = 0; +cd->name_table = NULL; +cd->start_workspace = cworkspace; +cd->start_code = cworkspace; +cd->hwm = cworkspace; +cd->start_pattern = (const uschar *)pattern; +cd->end_pattern = (const uschar *)(pattern + strlen(pattern)); +cd->req_varyopt = 0; +cd->external_options = options; +cd->external_flags = 0; + +/* Now do the pre-compile. On error, errorcode will be set non-zero, so we +don't need to look at the result of the function here. The initial options have +been put into the cd block so that they can be changed if an option setting is +found within the regex right at the beginning. Bringing initial option settings +outside can help speed up starting point checks. */ + +ptr += skipatstart; +code = cworkspace; +*code = OP_BRA; +(void)compile_regex(cd->external_options, cd->external_options & PCRE_IMS, + &code, &ptr, &errorcode, FALSE, FALSE, 0, &firstbyte, &reqbyte, NULL, cd, + &length); +if (errorcode != 0) goto PCRE_EARLY_ERROR_RETURN; + +DPRINTF(("end pre-compile: length=%d workspace=%d\n", length, + cd->hwm - cworkspace)); + +if (length > MAX_PATTERN_SIZE) + { + errorcode = ERR20; + goto PCRE_EARLY_ERROR_RETURN; + } + +/* Compute the size of data block needed and get it, either from malloc or +externally provided function. Integer overflow should no longer be possible +because nowadays we limit the maximum value of cd->names_found and +cd->name_entry_size. */ + +size = length + sizeof(real_pcre) + cd->names_found * (cd->name_entry_size + 3); +re = (real_pcre *)(pcre_malloc)(size); + +if (re == NULL) + { + errorcode = ERR21; + goto PCRE_EARLY_ERROR_RETURN; + } + +/* Put in the magic number, and save the sizes, initial options, internal +flags, and character table pointer. NULL is used for the default character +tables. The nullpad field is at the end; it's there to help in the case when a +regex compiled on a system with 4-byte pointers is run on another with 8-byte +pointers. */ + +re->magic_number = MAGIC_NUMBER; +re->size = size; +re->options = cd->external_options; +re->flags = cd->external_flags; +re->dummy1 = 0; +re->first_byte = 0; +re->req_byte = 0; +re->name_table_offset = sizeof(real_pcre); +re->name_entry_size = cd->name_entry_size; +re->name_count = cd->names_found; +re->ref_count = 0; +re->tables = (tables == _pcre_default_tables)? NULL : tables; +re->nullpad = NULL; + +/* The starting points of the name/number translation table and of the code are +passed around in the compile data block. The start/end pattern and initial +options are already set from the pre-compile phase, as is the name_entry_size +field. Reset the bracket count and the names_found field. Also reset the hwm +field; this time it's used for remembering forward references to subpatterns. +*/ + +cd->final_bracount = cd->bracount; /* Save for checking forward references */ +cd->bracount = 0; +cd->names_found = 0; +cd->name_table = (uschar *)re + re->name_table_offset; +codestart = cd->name_table + re->name_entry_size * re->name_count; +cd->start_code = codestart; +cd->hwm = cworkspace; +cd->req_varyopt = 0; +cd->had_accept = FALSE; + +/* Set up a starting, non-extracting bracket, then compile the expression. On +error, errorcode will be set non-zero, so we don't need to look at the result +of the function here. */ + +ptr = (const uschar *)pattern + skipatstart; +code = (uschar *)codestart; +*code = OP_BRA; +(void)compile_regex(re->options, re->options & PCRE_IMS, &code, &ptr, + &errorcode, FALSE, FALSE, 0, &firstbyte, &reqbyte, NULL, cd, NULL); +re->top_bracket = cd->bracount; +re->top_backref = cd->top_backref; +re->flags = cd->external_flags; + +if (cd->had_accept) reqbyte = -1; /* Must disable after (*ACCEPT) */ + +/* If not reached end of pattern on success, there's an excess bracket. */ + +if (errorcode == 0 && *ptr != 0) errorcode = ERR22; + +/* Fill in the terminating state and check for disastrous overflow, but +if debugging, leave the test till after things are printed out. */ + +*code++ = OP_END; + +#ifndef DEBUG +if (code - codestart > length) errorcode = ERR23; +#endif + +/* Fill in any forward references that are required. */ + +while (errorcode == 0 && cd->hwm > cworkspace) + { + int offset, recno; + const uschar *groupptr; + cd->hwm -= LINK_SIZE; + offset = GET(cd->hwm, 0); + recno = GET(codestart, offset); + groupptr = find_bracket(codestart, (re->options & PCRE_UTF8) != 0, recno); + if (groupptr == NULL) errorcode = ERR53; + else PUT(((uschar *)codestart), offset, groupptr - codestart); + } + +/* Give an error if there's back reference to a non-existent capturing +subpattern. */ + +if (errorcode == 0 && re->top_backref > re->top_bracket) errorcode = ERR15; + +/* Failed to compile, or error while post-processing */ + +if (errorcode != 0) + { + (pcre_free)(re); + PCRE_EARLY_ERROR_RETURN: + *erroroffset = ptr - (const uschar *)pattern; + PCRE_EARLY_ERROR_RETURN2: + *errorptr = find_error_text(errorcode); + if (errorcodeptr != NULL) *errorcodeptr = errorcode; + return NULL; + } + +/* If the anchored option was not passed, set the flag if we can determine that +the pattern is anchored by virtue of ^ characters or \A or anything else (such +as starting with .* when DOTALL is set). + +Otherwise, if we know what the first byte has to be, save it, because that +speeds up unanchored matches no end. If not, see if we can set the +PCRE_STARTLINE flag. This is helpful for multiline matches when all branches +start with ^. and also when all branches start with .* for non-DOTALL matches. +*/ + +if ((re->options & PCRE_ANCHORED) == 0) + { + int temp_options = re->options; /* May get changed during these scans */ + if (is_anchored(codestart, &temp_options, 0, cd->backref_map)) + re->options |= PCRE_ANCHORED; + else + { + if (firstbyte < 0) + firstbyte = find_firstassertedchar(codestart, &temp_options, FALSE); + if (firstbyte >= 0) /* Remove caseless flag for non-caseable chars */ + { + int ch = firstbyte & 255; + re->first_byte = ((firstbyte & REQ_CASELESS) != 0 && + cd->fcc[ch] == ch)? ch : firstbyte; + re->flags |= PCRE_FIRSTSET; + } + else if (is_startline(codestart, 0, cd->backref_map)) + re->flags |= PCRE_STARTLINE; + } + } + +/* For an anchored pattern, we use the "required byte" only if it follows a +variable length item in the regex. Remove the caseless flag for non-caseable +bytes. */ + +if (reqbyte >= 0 && + ((re->options & PCRE_ANCHORED) == 0 || (reqbyte & REQ_VARY) != 0)) + { + int ch = reqbyte & 255; + re->req_byte = ((reqbyte & REQ_CASELESS) != 0 && + cd->fcc[ch] == ch)? (reqbyte & ~REQ_CASELESS) : reqbyte; + re->flags |= PCRE_REQCHSET; + } + +/* Print out the compiled data if debugging is enabled. This is never the +case when building a production library. */ + +#ifdef DEBUG + +printf("Length = %d top_bracket = %d top_backref = %d\n", + length, re->top_bracket, re->top_backref); + +printf("Options=%08x\n", re->options); + +if ((re->flags & PCRE_FIRSTSET) != 0) + { + int ch = re->first_byte & 255; + const char *caseless = ((re->first_byte & REQ_CASELESS) == 0)? + "" : " (caseless)"; + if (isprint(ch)) printf("First char = %c%s\n", ch, caseless); + else printf("First char = \\x%02x%s\n", ch, caseless); + } + +if ((re->flags & PCRE_REQCHSET) != 0) + { + int ch = re->req_byte & 255; + const char *caseless = ((re->req_byte & REQ_CASELESS) == 0)? + "" : " (caseless)"; + if (isprint(ch)) printf("Req char = %c%s\n", ch, caseless); + else printf("Req char = \\x%02x%s\n", ch, caseless); + } + +pcre_printint(re, stdout, TRUE); + +/* This check is done here in the debugging case so that the code that +was compiled can be seen. */ + +if (code - codestart > length) + { + (pcre_free)(re); + *errorptr = find_error_text(ERR23); + *erroroffset = ptr - (uschar *)pattern; + if (errorcodeptr != NULL) *errorcodeptr = ERR23; + return NULL; + } +#endif /* DEBUG */ + +return (pcre *)re; +} + +/* End of pcre_compile.c */ diff --git a/examples/pikapython/pikapython/pikascript-lib/re/pcre_exec.c b/examples/pikapython/pikapython/pikascript-lib/re/pcre_exec.c new file mode 100755 index 00000000..e7a8143a --- /dev/null +++ b/examples/pikapython/pikapython/pikascript-lib/re/pcre_exec.c @@ -0,0 +1,4898 @@ + +/* This module contains pcre_exec(), the externally visible function that does +pattern matching using an NFA algorithm, trying to mimic Perl as closely as +possible. There are also some static supporting functions. */ + +#include "re_config.h" +#define NLBLOCK md /* Block containing newline information */ +#define PSSTART start_subject /* Field containing processed string start */ +#define PSEND end_subject /* Field containing processed string end */ + +#include "pcre_internal.h" + +/* Undefine some potentially clashing cpp symbols */ + +#undef min +#undef max + +/* Flag bits for the match() function */ + +#define match_condassert 0x01 /* Called to check a condition assertion */ +#define match_cbegroup 0x02 /* Could-be-empty unlimited repeat group */ + +/* Non-error returns from the match() function. Error returns are externally +defined PCRE_ERROR_xxx codes, which are all negative. */ + +#define MATCH_MATCH 1 +#define MATCH_NOMATCH 0 + +/* Special internal returns from the match() function. Make them sufficiently +negative to avoid the external error codes. */ + +#define MATCH_COMMIT (-999) +#define MATCH_PRUNE (-998) +#define MATCH_SKIP (-997) +#define MATCH_THEN (-996) + +/* Maximum number of ints of offset to save on the stack for recursive calls. +If the offset vector is bigger, malloc is used. This should be a multiple of 3, +because the offset vector is always a multiple of 3 long. */ + +#define REC_STACK_SAVE_MAX 30 + +/* Min and max values for the common repeats; for the maxima, 0 => infinity */ + +static const char rep_min[] = { 0, 0, 1, 1, 0, 0 }; +static const char rep_max[] = { 0, 0, 0, 0, 1, 1 }; + + + +#ifdef DEBUG +/************************************************* +* Debugging function to print chars * +*************************************************/ + +/* Print a sequence of chars in printable format, stopping at the end of the +subject if the requested. + +Arguments: + p points to characters + length number to print + is_subject TRUE if printing from within md->start_subject + md pointer to matching data block, if is_subject is TRUE + +Returns: nothing +*/ + +static void +pchars(const uschar *p, int length, BOOL is_subject, match_data *md) +{ +unsigned int c; +if (is_subject && length > md->end_subject - p) length = md->end_subject - p; +while (length-- > 0) + if (isprint(c = *(p++))) printf("%c", c); else printf("\\x%02x", c); +} +#endif + + + +/************************************************* +* Match a back-reference * +*************************************************/ + +/* If a back reference hasn't been set, the length that is passed is greater +than the number of characters left in the string, so the match fails. + +Arguments: + offset index into the offset vector + eptr points into the subject + length length to be matched + md points to match data block + ims the ims flags + +Returns: TRUE if matched +*/ + +static BOOL +match_ref(int offset, register USPTR eptr, int length, match_data *md, + unsigned long int ims) +{ +USPTR p = md->start_subject + md->offset_vector[offset]; + +#ifdef DEBUG +if (eptr >= md->end_subject) + printf("matching subject "); +else + { + printf("matching subject "); + pchars(eptr, length, TRUE, md); + } +printf(" against backref "); +pchars(p, length, FALSE, md); +printf("\n"); +#endif + +/* Always fail if not enough characters left */ + +if (length > md->end_subject - eptr) return FALSE; + +/* Separate the caselesss case for speed */ + +if ((ims & PCRE_CASELESS) != 0) + { + while (length-- > 0) + if (md->lcc[*p++] != md->lcc[*eptr++]) return FALSE; + } +else + { while (length-- > 0) if (*p++ != *eptr++) return FALSE; } + +return TRUE; +} + + + +/*************************************************************************** +**************************************************************************** + RECURSION IN THE match() FUNCTION + +The match() function is highly recursive, though not every recursive call +increases the recursive depth. Nevertheless, some regular expressions can cause +it to recurse to a great depth. I was writing for Unix, so I just let it call +itself recursively. This uses the stack for saving everything that has to be +saved for a recursive call. On Unix, the stack can be large, and this works +fine. + +It turns out that on some non-Unix-like systems there are problems with +programs that use a lot of stack. (This despite the fact that every last chip +has oodles of memory these days, and techniques for extending the stack have +been known for decades.) So.... + +There is a fudge, triggered by defining NO_RECURSE, which avoids recursive +calls by keeping local variables that need to be preserved in blocks of memory +obtained from malloc() instead instead of on the stack. Macros are used to +achieve this so that the actual code doesn't look very different to what it +always used to. + +The original heap-recursive code used longjmp(). However, it seems that this +can be very slow on some operating systems. Following a suggestion from Stan +Switzer, the use of longjmp() has been abolished, at the cost of having to +provide a unique number for each call to RMATCH. There is no way of generating +a sequence of numbers at compile time in C. I have given them names, to make +them stand out more clearly. + +Crude tests on x86 Linux show a small speedup of around 5-8%. However, on +FreeBSD, avoiding longjmp() more than halves the time taken to run the standard +tests. Furthermore, not using longjmp() means that local dynamic variables +don't have indeterminate values; this has meant that the frame size can be +reduced because the result can be "passed back" by straight setting of the +variable instead of being passed in the frame. +**************************************************************************** +***************************************************************************/ + +/* Numbers for RMATCH calls. When this list is changed, the code at HEAP_RETURN +below must be updated in sync. */ + +enum { RM1=1, RM2, RM3, RM4, RM5, RM6, RM7, RM8, RM9, RM10, + RM11, RM12, RM13, RM14, RM15, RM16, RM17, RM18, RM19, RM20, + RM21, RM22, RM23, RM24, RM25, RM26, RM27, RM28, RM29, RM30, + RM31, RM32, RM33, RM34, RM35, RM36, RM37, RM38, RM39, RM40, + RM41, RM42, RM43, RM44, RM45, RM46, RM47, RM48, RM49, RM50, + RM51, RM52, RM53, RM54 }; + +/* These versions of the macros use the stack, as normal. There are debugging +versions and production versions. Note that the "rw" argument of RMATCH isn't +actuall used in this definition. */ + +#ifndef NO_RECURSE +#define REGISTER register + +#ifdef DEBUG +#define RMATCH(ra,rb,rc,rd,re,rf,rg,rw) \ + { \ + printf("match() called in line %d\n", __LINE__); \ + rrc = match(ra,rb,mstart,rc,rd,re,rf,rg,rdepth+1); \ + printf("to line %d\n", __LINE__); \ + } +#define RRETURN(ra) \ + { \ + printf("match() returned %d from line %d ", ra, __LINE__); \ + return ra; \ + } +#else +#define RMATCH(ra,rb,rc,rd,re,rf,rg,rw) \ + rrc = match(ra,rb,mstart,rc,rd,re,rf,rg,rdepth+1) +#define RRETURN(ra) return ra +#endif + +#else + + +/* These versions of the macros manage a private stack on the heap. Note that +the "rd" argument of RMATCH isn't actually used in this definition. It's the md +argument of match(), which never changes. */ + +#define REGISTER + +#define RMATCH(ra,rb,rc,rd,re,rf,rg,rw)\ + {\ + heapframe *newframe = (pcre_stack_malloc)(sizeof(heapframe));\ + frame->Xwhere = rw; \ + newframe->Xeptr = ra;\ + newframe->Xecode = rb;\ + newframe->Xmstart = mstart;\ + newframe->Xoffset_top = rc;\ + newframe->Xims = re;\ + newframe->Xeptrb = rf;\ + newframe->Xflags = rg;\ + newframe->Xrdepth = frame->Xrdepth + 1;\ + newframe->Xprevframe = frame;\ + frame = newframe;\ + DPRINTF(("restarting from line %d\n", __LINE__));\ + goto HEAP_RECURSE;\ + L_##rw:\ + DPRINTF(("jumped back to line %d\n", __LINE__));\ + } + +#define RRETURN(ra)\ + {\ + heapframe *newframe = frame;\ + frame = newframe->Xprevframe;\ + (pcre_stack_free)(newframe);\ + if (frame != NULL)\ + {\ + rrc = ra;\ + goto HEAP_RETURN;\ + }\ + return ra;\ + } + + +/* Structure for remembering the local variables in a private frame */ + +typedef struct heapframe { + struct heapframe *Xprevframe; + + /* Function arguments that may change */ + + const uschar *Xeptr; + const uschar *Xecode; + const uschar *Xmstart; + int Xoffset_top; + long int Xims; + eptrblock *Xeptrb; + int Xflags; + unsigned int Xrdepth; + + /* Function local variables */ + + const uschar *Xcallpat; + const uschar *Xcharptr; + const uschar *Xdata; + const uschar *Xnext; + const uschar *Xpp; + const uschar *Xprev; + const uschar *Xsaved_eptr; + + recursion_info Xnew_recursive; + + BOOL Xcur_is_word; + BOOL Xcondition; + BOOL Xprev_is_word; + + unsigned long int Xoriginal_ims; + +#ifdef SUPPORT_UCP + int Xprop_type; + int Xprop_value; + int Xprop_fail_result; + int Xprop_category; + int Xprop_chartype; + int Xprop_script; + int Xoclength; + uschar Xocchars[8]; +#endif + + int Xctype; + unsigned int Xfc; + int Xfi; + int Xlength; + int Xmax; + int Xmin; + int Xnumber; + int Xoffset; + int Xop; + int Xsave_capture_last; + int Xsave_offset1, Xsave_offset2, Xsave_offset3; + int Xstacksave[REC_STACK_SAVE_MAX]; + + eptrblock Xnewptrb; + + /* Where to jump back to */ + + int Xwhere; + +} heapframe; + +#endif + + +/*************************************************************************** +***************************************************************************/ + + + +/************************************************* +* Match from current position * +*************************************************/ + +/* This function is called recursively in many circumstances. Whenever it +returns a negative (error) response, the outer incarnation must also return the +same response. + +Performance note: It might be tempting to extract commonly used fields from the +md structure (e.g. utf8, end_subject) into individual variables to improve +performance. Tests using gcc on a SPARC disproved this; in the first case, it +made performance worse. + +Arguments: + eptr pointer to current character in subject + ecode pointer to current position in compiled code + mstart pointer to the current match start position (can be modified + by encountering \K) + offset_top current top pointer + md pointer to "static" info for the match + ims current /i, /m, and /s options + eptrb pointer to chain of blocks containing eptr at start of + brackets - for testing for empty matches + flags can contain + match_condassert - this is an assertion condition + match_cbegroup - this is the start of an unlimited repeat + group that can match an empty string + rdepth the recursion depth + +Returns: MATCH_MATCH if matched ) these values are >= 0 + MATCH_NOMATCH if failed to match ) + a negative PCRE_ERROR_xxx value if aborted by an error condition + (e.g. stopped by repeated call or recursion limit) +*/ + +static int +match(REGISTER USPTR eptr, REGISTER const uschar *ecode, const uschar *mstart, + int offset_top, match_data *md, unsigned long int ims, eptrblock *eptrb, + int flags, unsigned int rdepth) +{ +/* These variables do not need to be preserved over recursion in this function, +so they can be ordinary variables in all cases. Mark some of them with +"register" because they are used a lot in loops. */ + +register int rrc; /* Returns from recursive calls */ +register int i; /* Used for loops not involving calls to RMATCH() */ +register unsigned int c; /* Character values not kept over RMATCH() calls */ +register BOOL utf8; /* Local copy of UTF-8 flag for speed */ + +BOOL minimize, possessive; /* Quantifier options */ + +/* When recursion is not being used, all "local" variables that have to be +preserved over calls to RMATCH() are part of a "frame" which is obtained from +heap storage. Set up the top-level frame here; others are obtained from the +heap whenever RMATCH() does a "recursion". See the macro definitions above. */ + +#ifdef NO_RECURSE +heapframe *frame = (pcre_stack_malloc)(sizeof(heapframe)); +frame->Xprevframe = NULL; /* Marks the top level */ + +/* Copy in the original argument variables */ + +frame->Xeptr = eptr; +frame->Xecode = ecode; +frame->Xmstart = mstart; +frame->Xoffset_top = offset_top; +frame->Xims = ims; +frame->Xeptrb = eptrb; +frame->Xflags = flags; +frame->Xrdepth = rdepth; + +/* This is where control jumps back to to effect "recursion" */ + +HEAP_RECURSE: + +/* Macros make the argument variables come from the current frame */ + +#define eptr frame->Xeptr +#define ecode frame->Xecode +#define mstart frame->Xmstart +#define offset_top frame->Xoffset_top +#define ims frame->Xims +#define eptrb frame->Xeptrb +#define flags frame->Xflags +#define rdepth frame->Xrdepth + +/* Ditto for the local variables */ + +#ifdef SUPPORT_UTF8 +#define charptr frame->Xcharptr +#endif +#define callpat frame->Xcallpat +#define data frame->Xdata +#define next frame->Xnext +#define pp frame->Xpp +#define prev frame->Xprev +#define saved_eptr frame->Xsaved_eptr + +#define new_recursive frame->Xnew_recursive + +#define cur_is_word frame->Xcur_is_word +#define condition frame->Xcondition +#define prev_is_word frame->Xprev_is_word + +#define original_ims frame->Xoriginal_ims + +#ifdef SUPPORT_UCP +#define prop_type frame->Xprop_type +#define prop_value frame->Xprop_value +#define prop_fail_result frame->Xprop_fail_result +#define prop_category frame->Xprop_category +#define prop_chartype frame->Xprop_chartype +#define prop_script frame->Xprop_script +#define oclength frame->Xoclength +#define occhars frame->Xocchars +#endif + +#define ctype frame->Xctype +#define fc frame->Xfc +#define fi frame->Xfi +#define length frame->Xlength +#define max frame->Xmax +#define min frame->Xmin +#define number frame->Xnumber +#define offset frame->Xoffset +#define op frame->Xop +#define save_capture_last frame->Xsave_capture_last +#define save_offset1 frame->Xsave_offset1 +#define save_offset2 frame->Xsave_offset2 +#define save_offset3 frame->Xsave_offset3 +#define stacksave frame->Xstacksave + +#define newptrb frame->Xnewptrb + +/* When recursion is being used, local variables are allocated on the stack and +get preserved during recursion in the normal way. In this environment, fi and +i, and fc and c, can be the same variables. */ + +#else /* NO_RECURSE not defined */ +#define fi i +#define fc c + + +#ifdef SUPPORT_UTF8 /* Many of these variables are used only */ +const uschar *charptr; /* in small blocks of the code. My normal */ +#endif /* style of coding would have declared */ +const uschar *callpat; /* them within each of those blocks. */ +const uschar *data; /* However, in order to accommodate the */ +const uschar *next; /* version of this code that uses an */ +USPTR pp; /* external "stack" implemented on the */ +const uschar *prev; /* heap, it is easier to declare them all */ +USPTR saved_eptr; /* here, so the declarations can be cut */ + /* out in a block. The only declarations */ +recursion_info new_recursive; /* within blocks below are for variables */ + /* that do not have to be preserved over */ +BOOL cur_is_word; /* a recursive call to RMATCH(). */ +BOOL condition; +BOOL prev_is_word; + +unsigned long int original_ims; + +#ifdef SUPPORT_UCP +int prop_type; +int prop_value; +int prop_fail_result; +int prop_category; +int prop_chartype; +int prop_script; +int oclength; +uschar occhars[8]; +#endif + +int ctype; +int length; +int max; +int min; +int number; +int offset; +int op; +int save_capture_last; +int save_offset1, save_offset2, save_offset3; +int stacksave[REC_STACK_SAVE_MAX]; + +eptrblock newptrb; +#endif /* NO_RECURSE */ + +/* These statements are here to stop the compiler complaining about unitialized +variables. */ + +#ifdef SUPPORT_UCP +prop_value = 0; +prop_fail_result = 0; +#endif + + +/* This label is used for tail recursion, which is used in a few cases even +when NO_RECURSE is not defined, in order to reduce the amount of stack that is +used. Thanks to Ian Taylor for noticing this possibility and sending the +original patch. */ + +TAIL_RECURSE: + +/* OK, now we can get on with the real code of the function. Recursive calls +are specified by the macro RMATCH and RRETURN is used to return. When +NO_RECURSE is *not* defined, these just turn into a recursive call to match() +and a "return", respectively (possibly with some debugging if DEBUG is +defined). However, RMATCH isn't like a function call because it's quite a +complicated macro. It has to be used in one particular way. This shouldn't, +however, impact performance when true recursion is being used. */ + +#ifdef SUPPORT_UTF8 +utf8 = md->utf8; /* Local copy of the flag */ +#else +utf8 = FALSE; +#endif + +/* First check that we haven't called match() too many times, or that we +haven't exceeded the recursive call limit. */ + +if (md->match_call_count++ >= md->match_limit) RRETURN(PCRE_ERROR_MATCHLIMIT); +if (rdepth >= md->match_limit_recursion) RRETURN(PCRE_ERROR_RECURSIONLIMIT); + +original_ims = ims; /* Save for resetting on ')' */ + +/* At the start of a group with an unlimited repeat that may match an empty +string, the match_cbegroup flag is set. When this is the case, add the current +subject pointer to the chain of such remembered pointers, to be checked when we +hit the closing ket, in order to break infinite loops that match no characters. +When match() is called in other circumstances, don't add to the chain. The +match_cbegroup flag must NOT be used with tail recursion, because the memory +block that is used is on the stack, so a new one may be required for each +match(). */ + +if ((flags & match_cbegroup) != 0) + { + newptrb.epb_saved_eptr = eptr; + newptrb.epb_prev = eptrb; + eptrb = &newptrb; + } + +/* Now start processing the opcodes. */ + +for (;;) + { + minimize = possessive = FALSE; + op = *ecode; + + /* For partial matching, remember if we ever hit the end of the subject after + matching at least one subject character. */ + + if (md->partial && + eptr >= md->end_subject && + eptr > mstart) + md->hitend = TRUE; + + switch(op) + { + case OP_FAIL: + RRETURN(MATCH_NOMATCH); + + case OP_PRUNE: + RMATCH(eptr, ecode + _pcre_OP_lengths[*ecode], offset_top, md, + ims, eptrb, flags, RM51); + if (rrc != MATCH_NOMATCH) RRETURN(rrc); + RRETURN(MATCH_PRUNE); + + case OP_COMMIT: + RMATCH(eptr, ecode + _pcre_OP_lengths[*ecode], offset_top, md, + ims, eptrb, flags, RM52); + if (rrc != MATCH_NOMATCH) RRETURN(rrc); + RRETURN(MATCH_COMMIT); + + case OP_SKIP: + RMATCH(eptr, ecode + _pcre_OP_lengths[*ecode], offset_top, md, + ims, eptrb, flags, RM53); + if (rrc != MATCH_NOMATCH) RRETURN(rrc); + md->start_match_ptr = eptr; /* Pass back current position */ + RRETURN(MATCH_SKIP); + + case OP_THEN: + RMATCH(eptr, ecode + _pcre_OP_lengths[*ecode], offset_top, md, + ims, eptrb, flags, RM54); + if (rrc != MATCH_NOMATCH) RRETURN(rrc); + RRETURN(MATCH_THEN); + + /* Handle a capturing bracket. If there is space in the offset vector, save + the current subject position in the working slot at the top of the vector. + We mustn't change the current values of the data slot, because they may be + set from a previous iteration of this group, and be referred to by a + reference inside the group. + + If the bracket fails to match, we need to restore this value and also the + values of the final offsets, in case they were set by a previous iteration + of the same bracket. + + If there isn't enough space in the offset vector, treat this as if it were + a non-capturing bracket. Don't worry about setting the flag for the error + case here; that is handled in the code for KET. */ + + case OP_CBRA: + case OP_SCBRA: + number = GET2(ecode, 1+LINK_SIZE); + offset = number << 1; + +#ifdef DEBUG + printf("start bracket %d\n", number); + printf("subject="); + pchars(eptr, 16, TRUE, md); + printf("\n"); +#endif + + if (offset < md->offset_max) + { + save_offset1 = md->offset_vector[offset]; + save_offset2 = md->offset_vector[offset+1]; + save_offset3 = md->offset_vector[md->offset_end - number]; + save_capture_last = md->capture_last; + + DPRINTF(("saving %d %d %d\n", save_offset1, save_offset2, save_offset3)); + md->offset_vector[md->offset_end - number] = eptr - md->start_subject; + + flags = (op == OP_SCBRA)? match_cbegroup : 0; + do + { + RMATCH(eptr, ecode + _pcre_OP_lengths[*ecode], offset_top, md, + ims, eptrb, flags, RM1); + if (rrc != MATCH_NOMATCH && rrc != MATCH_THEN) RRETURN(rrc); + md->capture_last = save_capture_last; + ecode += GET(ecode, 1); + } + while (*ecode == OP_ALT); + + DPRINTF(("bracket %d failed\n", number)); + + md->offset_vector[offset] = save_offset1; + md->offset_vector[offset+1] = save_offset2; + md->offset_vector[md->offset_end - number] = save_offset3; + + RRETURN(MATCH_NOMATCH); + } + + /* FALL THROUGH ... Insufficient room for saving captured contents. Treat + as a non-capturing bracket. */ + + /* VVVVVVVVVVVVVVVVVVVVVVVVV */ + /* VVVVVVVVVVVVVVVVVVVVVVVVV */ + + DPRINTF(("insufficient capture room: treat as non-capturing\n")); + + /* VVVVVVVVVVVVVVVVVVVVVVVVV */ + /* VVVVVVVVVVVVVVVVVVVVVVVVV */ + + /* Non-capturing bracket. Loop for all the alternatives. When we get to the + final alternative within the brackets, we would return the result of a + recursive call to match() whatever happened. We can reduce stack usage by + turning this into a tail recursion, except in the case when match_cbegroup + is set.*/ + + case OP_BRA: + case OP_SBRA: + DPRINTF(("start non-capturing bracket\n")); + flags = (op >= OP_SBRA)? match_cbegroup : 0; + for (;;) + { + if (ecode[GET(ecode, 1)] != OP_ALT) /* Final alternative */ + { + if (flags == 0) /* Not a possibly empty group */ + { + ecode += _pcre_OP_lengths[*ecode]; + DPRINTF(("bracket 0 tail recursion\n")); + goto TAIL_RECURSE; + } + + /* Possibly empty group; can't use tail recursion. */ + + RMATCH(eptr, ecode + _pcre_OP_lengths[*ecode], offset_top, md, ims, + eptrb, flags, RM48); + RRETURN(rrc); + } + + /* For non-final alternatives, continue the loop for a NOMATCH result; + otherwise return. */ + + RMATCH(eptr, ecode + _pcre_OP_lengths[*ecode], offset_top, md, ims, + eptrb, flags, RM2); + if (rrc != MATCH_NOMATCH && rrc != MATCH_THEN) RRETURN(rrc); + ecode += GET(ecode, 1); + } + /* Control never reaches here. */ + + /* Conditional group: compilation checked that there are no more than + two branches. If the condition is false, skipping the first branch takes us + past the end if there is only one branch, but that's OK because that is + exactly what going to the ket would do. As there is only one branch to be + obeyed, we can use tail recursion to avoid using another stack frame. */ + + case OP_COND: + case OP_SCOND: + if (ecode[LINK_SIZE+1] == OP_RREF) /* Recursion test */ + { + offset = GET2(ecode, LINK_SIZE + 2); /* Recursion group number*/ + condition = md->recursive != NULL && + (offset == RREF_ANY || offset == md->recursive->group_num); + ecode += condition? 3 : GET(ecode, 1); + } + + else if (ecode[LINK_SIZE+1] == OP_CREF) /* Group used test */ + { + offset = GET2(ecode, LINK_SIZE+2) << 1; /* Doubled ref number */ + condition = offset < offset_top && md->offset_vector[offset] >= 0; + ecode += condition? 3 : GET(ecode, 1); + } + + else if (ecode[LINK_SIZE+1] == OP_DEF) /* DEFINE - always false */ + { + condition = FALSE; + ecode += GET(ecode, 1); + } + + /* The condition is an assertion. Call match() to evaluate it - setting + the final argument match_condassert causes it to stop at the end of an + assertion. */ + + else + { + RMATCH(eptr, ecode + 1 + LINK_SIZE, offset_top, md, ims, NULL, + match_condassert, RM3); + if (rrc == MATCH_MATCH) + { + condition = TRUE; + ecode += 1 + LINK_SIZE + GET(ecode, LINK_SIZE + 2); + while (*ecode == OP_ALT) ecode += GET(ecode, 1); + } + else if (rrc != MATCH_NOMATCH && rrc != MATCH_THEN) + { + RRETURN(rrc); /* Need braces because of following else */ + } + else + { + condition = FALSE; + ecode += GET(ecode, 1); + } + } + + /* We are now at the branch that is to be obeyed. As there is only one, + we can use tail recursion to avoid using another stack frame, except when + match_cbegroup is required for an unlimited repeat of a possibly empty + group. If the second alternative doesn't exist, we can just plough on. */ + + if (condition || *ecode == OP_ALT) + { + ecode += 1 + LINK_SIZE; + if (op == OP_SCOND) /* Possibly empty group */ + { + RMATCH(eptr, ecode, offset_top, md, ims, eptrb, match_cbegroup, RM49); + RRETURN(rrc); + } + else /* Group must match something */ + { + flags = 0; + goto TAIL_RECURSE; + } + } + else /* Condition false & no 2nd alternative */ + { + ecode += 1 + LINK_SIZE; + } + break; + + + /* End of the pattern, either real or forced. If we are in a top-level + recursion, we should restore the offsets appropriately and continue from + after the call. */ + + case OP_ACCEPT: + case OP_END: + if (md->recursive != NULL && md->recursive->group_num == 0) + { + recursion_info *rec = md->recursive; + DPRINTF(("End of pattern in a (?0) recursion\n")); + md->recursive = rec->prevrec; + memmove(md->offset_vector, rec->offset_save, + rec->saved_max * sizeof(int)); + mstart = rec->save_start; + ims = original_ims; + ecode = rec->after_call; + break; + } + + /* Otherwise, if PCRE_NOTEMPTY is set, fail if we have matched an empty + string - backtracking will then try other alternatives, if any. */ + + if (md->notempty && eptr == mstart) RRETURN(MATCH_NOMATCH); + md->end_match_ptr = eptr; /* Record where we ended */ + md->end_offset_top = offset_top; /* and how many extracts were taken */ + md->start_match_ptr = mstart; /* and the start (\K can modify) */ + RRETURN(MATCH_MATCH); + + /* Change option settings */ + + case OP_OPT: + ims = ecode[1]; + ecode += 2; + DPRINTF(("ims set to %02lx\n", ims)); + break; + + /* Assertion brackets. Check the alternative branches in turn - the + matching won't pass the KET for an assertion. If any one branch matches, + the assertion is true. Lookbehind assertions have an OP_REVERSE item at the + start of each branch to move the current point backwards, so the code at + this level is identical to the lookahead case. */ + + case OP_ASSERT: + case OP_ASSERTBACK: + do + { + RMATCH(eptr, ecode + 1 + LINK_SIZE, offset_top, md, ims, NULL, 0, + RM4); + if (rrc == MATCH_MATCH) break; + if (rrc != MATCH_NOMATCH && rrc != MATCH_THEN) RRETURN(rrc); + ecode += GET(ecode, 1); + } + while (*ecode == OP_ALT); + if (*ecode == OP_KET) RRETURN(MATCH_NOMATCH); + + /* If checking an assertion for a condition, return MATCH_MATCH. */ + + if ((flags & match_condassert) != 0) RRETURN(MATCH_MATCH); + + /* Continue from after the assertion, updating the offsets high water + mark, since extracts may have been taken during the assertion. */ + + do ecode += GET(ecode,1); while (*ecode == OP_ALT); + ecode += 1 + LINK_SIZE; + offset_top = md->end_offset_top; + continue; + + /* Negative assertion: all branches must fail to match */ + + case OP_ASSERT_NOT: + case OP_ASSERTBACK_NOT: + do + { + RMATCH(eptr, ecode + 1 + LINK_SIZE, offset_top, md, ims, NULL, 0, + RM5); + if (rrc == MATCH_MATCH) RRETURN(MATCH_NOMATCH); + if (rrc != MATCH_NOMATCH && rrc != MATCH_THEN) RRETURN(rrc); + ecode += GET(ecode,1); + } + while (*ecode == OP_ALT); + + if ((flags & match_condassert) != 0) RRETURN(MATCH_MATCH); + + ecode += 1 + LINK_SIZE; + continue; + + /* Move the subject pointer back. This occurs only at the start of + each branch of a lookbehind assertion. If we are too close to the start to + move back, this match function fails. When working with UTF-8 we move + back a number of characters, not bytes. */ + + case OP_REVERSE: +#ifdef SUPPORT_UTF8 + if (utf8) + { + i = GET(ecode, 1); + while (i-- > 0) + { + eptr--; + if (eptr < md->start_subject) RRETURN(MATCH_NOMATCH); + BACKCHAR(eptr); + } + } + else +#endif + + /* No UTF-8 support, or not in UTF-8 mode: count is byte count */ + + { + eptr -= GET(ecode, 1); + if (eptr < md->start_subject) RRETURN(MATCH_NOMATCH); + } + + /* Skip to next op code */ + + ecode += 1 + LINK_SIZE; + break; + + /* The callout item calls an external function, if one is provided, passing + details of the match so far. This is mainly for debugging, though the + function is able to force a failure. */ + + case OP_CALLOUT: + if (pcre_callout != NULL) + { + pcre_callout_block cb; + cb.version = 1; /* Version 1 of the callout block */ + cb.callout_number = ecode[1]; + cb.offset_vector = md->offset_vector; + cb.subject = (PCRE_SPTR)md->start_subject; + cb.subject_length = md->end_subject - md->start_subject; + cb.start_match = mstart - md->start_subject; + cb.current_position = eptr - md->start_subject; + cb.pattern_position = GET(ecode, 2); + cb.next_item_length = GET(ecode, 2 + LINK_SIZE); + cb.capture_top = offset_top/2; + cb.capture_last = md->capture_last; + cb.callout_data = md->callout_data; + if ((rrc = (*pcre_callout)(&cb)) > 0) RRETURN(MATCH_NOMATCH); + if (rrc < 0) RRETURN(rrc); + } + ecode += 2 + 2*LINK_SIZE; + break; + + /* Recursion either matches the current regex, or some subexpression. The + offset data is the offset to the starting bracket from the start of the + whole pattern. (This is so that it works from duplicated subpatterns.) + + If there are any capturing brackets started but not finished, we have to + save their starting points and reinstate them after the recursion. However, + we don't know how many such there are (offset_top records the completed + total) so we just have to save all the potential data. There may be up to + 65535 such values, which is too large to put on the stack, but using malloc + for small numbers seems expensive. As a compromise, the stack is used when + there are no more than REC_STACK_SAVE_MAX values to store; otherwise malloc + is used. A problem is what to do if the malloc fails ... there is no way of + returning to the top level with an error. Save the top REC_STACK_SAVE_MAX + values on the stack, and accept that the rest may be wrong. + + There are also other values that have to be saved. We use a chained + sequence of blocks that actually live on the stack. Thanks to Robin Houston + for the original version of this logic. */ + + case OP_RECURSE: + { + callpat = md->start_code + GET(ecode, 1); + new_recursive.group_num = (callpat == md->start_code)? 0 : + GET2(callpat, 1 + LINK_SIZE); + + /* Add to "recursing stack" */ + + new_recursive.prevrec = md->recursive; + md->recursive = &new_recursive; + + /* Find where to continue from afterwards */ + + ecode += 1 + LINK_SIZE; + new_recursive.after_call = ecode; + + /* Now save the offset data. */ + + new_recursive.saved_max = md->offset_end; + if (new_recursive.saved_max <= REC_STACK_SAVE_MAX) + new_recursive.offset_save = stacksave; + else + { + new_recursive.offset_save = + (int *)(pcre_malloc)(new_recursive.saved_max * sizeof(int)); + if (new_recursive.offset_save == NULL) RRETURN(PCRE_ERROR_NOMEMORY); + } + + memcpy(new_recursive.offset_save, md->offset_vector, + new_recursive.saved_max * sizeof(int)); + new_recursive.save_start = mstart; + mstart = eptr; + + /* OK, now we can do the recursion. For each top-level alternative we + restore the offset and recursion data. */ + + DPRINTF(("Recursing into group %d\n", new_recursive.group_num)); + flags = (*callpat >= OP_SBRA)? match_cbegroup : 0; + do + { + RMATCH(eptr, callpat + _pcre_OP_lengths[*callpat], offset_top, + md, ims, eptrb, flags, RM6); + if (rrc == MATCH_MATCH) + { + DPRINTF(("Recursion matched\n")); + md->recursive = new_recursive.prevrec; + if (new_recursive.offset_save != stacksave) + (pcre_free)(new_recursive.offset_save); + RRETURN(MATCH_MATCH); + } + else if (rrc != MATCH_NOMATCH && rrc != MATCH_THEN) + { + DPRINTF(("Recursion gave error %d\n", rrc)); + RRETURN(rrc); + } + + md->recursive = &new_recursive; + memcpy(md->offset_vector, new_recursive.offset_save, + new_recursive.saved_max * sizeof(int)); + callpat += GET(callpat, 1); + } + while (*callpat == OP_ALT); + + DPRINTF(("Recursion didn't match\n")); + md->recursive = new_recursive.prevrec; + if (new_recursive.offset_save != stacksave) + (pcre_free)(new_recursive.offset_save); + RRETURN(MATCH_NOMATCH); + } + /* Control never reaches here */ + + /* "Once" brackets are like assertion brackets except that after a match, + the point in the subject string is not moved back. Thus there can never be + a move back into the brackets. Friedl calls these "atomic" subpatterns. + Check the alternative branches in turn - the matching won't pass the KET + for this kind of subpattern. If any one branch matches, we carry on as at + the end of a normal bracket, leaving the subject pointer. */ + + case OP_ONCE: + prev = ecode; + saved_eptr = eptr; + + do + { + RMATCH(eptr, ecode + 1 + LINK_SIZE, offset_top, md, ims, eptrb, 0, RM7); + if (rrc == MATCH_MATCH) break; + if (rrc != MATCH_NOMATCH && rrc != MATCH_THEN) RRETURN(rrc); + ecode += GET(ecode,1); + } + while (*ecode == OP_ALT); + + /* If hit the end of the group (which could be repeated), fail */ + + if (*ecode != OP_ONCE && *ecode != OP_ALT) RRETURN(MATCH_NOMATCH); + + /* Continue as from after the assertion, updating the offsets high water + mark, since extracts may have been taken. */ + + do ecode += GET(ecode, 1); while (*ecode == OP_ALT); + + offset_top = md->end_offset_top; + eptr = md->end_match_ptr; + + /* For a non-repeating ket, just continue at this level. This also + happens for a repeating ket if no characters were matched in the group. + This is the forcible breaking of infinite loops as implemented in Perl + 5.005. If there is an options reset, it will get obeyed in the normal + course of events. */ + + if (*ecode == OP_KET || eptr == saved_eptr) + { + ecode += 1+LINK_SIZE; + break; + } + + /* The repeating kets try the rest of the pattern or restart from the + preceding bracket, in the appropriate order. The second "call" of match() + uses tail recursion, to avoid using another stack frame. We need to reset + any options that changed within the bracket before re-running it, so + check the next opcode. */ + + if (ecode[1+LINK_SIZE] == OP_OPT) + { + ims = (ims & ~PCRE_IMS) | ecode[4]; + DPRINTF(("ims set to %02lx at group repeat\n", ims)); + } + + if (*ecode == OP_KETRMIN) + { + RMATCH(eptr, ecode + 1 + LINK_SIZE, offset_top, md, ims, eptrb, 0, RM8); + if (rrc != MATCH_NOMATCH) RRETURN(rrc); + ecode = prev; + flags = 0; + goto TAIL_RECURSE; + } + else /* OP_KETRMAX */ + { + RMATCH(eptr, prev, offset_top, md, ims, eptrb, match_cbegroup, RM9); + if (rrc != MATCH_NOMATCH) RRETURN(rrc); + ecode += 1 + LINK_SIZE; + flags = 0; + goto TAIL_RECURSE; + } + /* Control never gets here */ + + /* An alternation is the end of a branch; scan along to find the end of the + bracketed group and go to there. */ + + case OP_ALT: + do ecode += GET(ecode,1); while (*ecode == OP_ALT); + break; + + /* BRAZERO and BRAMINZERO occur just before a bracket group, indicating + that it may occur zero times. It may repeat infinitely, or not at all - + i.e. it could be ()* or ()? in the pattern. Brackets with fixed upper + repeat limits are compiled as a number of copies, with the optional ones + preceded by BRAZERO or BRAMINZERO. */ + + case OP_BRAZERO: + { + next = ecode+1; + RMATCH(eptr, next, offset_top, md, ims, eptrb, 0, RM10); + if (rrc != MATCH_NOMATCH) RRETURN(rrc); + do next += GET(next,1); while (*next == OP_ALT); + ecode = next + 1 + LINK_SIZE; + } + break; + + case OP_BRAMINZERO: + { + next = ecode+1; + do next += GET(next, 1); while (*next == OP_ALT); + RMATCH(eptr, next + 1+LINK_SIZE, offset_top, md, ims, eptrb, 0, RM11); + if (rrc != MATCH_NOMATCH) RRETURN(rrc); + ecode++; + } + break; + + /* End of a group, repeated or non-repeating. */ + + case OP_KET: + case OP_KETRMIN: + case OP_KETRMAX: + prev = ecode - GET(ecode, 1); + + /* If this was a group that remembered the subject start, in order to break + infinite repeats of empty string matches, retrieve the subject start from + the chain. Otherwise, set it NULL. */ + + if (*prev >= OP_SBRA) + { + saved_eptr = eptrb->epb_saved_eptr; /* Value at start of group */ + eptrb = eptrb->epb_prev; /* Backup to previous group */ + } + else saved_eptr = NULL; + + /* If we are at the end of an assertion group, stop matching and return + MATCH_MATCH, but record the current high water mark for use by positive + assertions. Do this also for the "once" (atomic) groups. */ + + if (*prev == OP_ASSERT || *prev == OP_ASSERT_NOT || + *prev == OP_ASSERTBACK || *prev == OP_ASSERTBACK_NOT || + *prev == OP_ONCE) + { + md->end_match_ptr = eptr; /* For ONCE */ + md->end_offset_top = offset_top; + RRETURN(MATCH_MATCH); + } + + /* For capturing groups we have to check the group number back at the start + and if necessary complete handling an extraction by setting the offsets and + bumping the high water mark. Note that whole-pattern recursion is coded as + a recurse into group 0, so it won't be picked up here. Instead, we catch it + when the OP_END is reached. Other recursion is handled here. */ + + if (*prev == OP_CBRA || *prev == OP_SCBRA) + { + number = GET2(prev, 1+LINK_SIZE); + offset = number << 1; + +#ifdef DEBUG + printf("end bracket %d", number); + printf("\n"); +#endif + + md->capture_last = number; + if (offset >= md->offset_max) md->offset_overflow = TRUE; else + { + md->offset_vector[offset] = + md->offset_vector[md->offset_end - number]; + md->offset_vector[offset+1] = eptr - md->start_subject; + if (offset_top <= offset) offset_top = offset + 2; + } + + /* Handle a recursively called group. Restore the offsets + appropriately and continue from after the call. */ + + if (md->recursive != NULL && md->recursive->group_num == number) + { + recursion_info *rec = md->recursive; + DPRINTF(("Recursion (%d) succeeded - continuing\n", number)); + md->recursive = rec->prevrec; + mstart = rec->save_start; + memcpy(md->offset_vector, rec->offset_save, + rec->saved_max * sizeof(int)); + ecode = rec->after_call; + ims = original_ims; + break; + } + } + + /* For both capturing and non-capturing groups, reset the value of the ims + flags, in case they got changed during the group. */ + + ims = original_ims; + DPRINTF(("ims reset to %02lx\n", ims)); + + /* For a non-repeating ket, just continue at this level. This also + happens for a repeating ket if no characters were matched in the group. + This is the forcible breaking of infinite loops as implemented in Perl + 5.005. If there is an options reset, it will get obeyed in the normal + course of events. */ + + if (*ecode == OP_KET || eptr == saved_eptr) + { + ecode += 1 + LINK_SIZE; + break; + } + + /* The repeating kets try the rest of the pattern or restart from the + preceding bracket, in the appropriate order. In the second case, we can use + tail recursion to avoid using another stack frame, unless we have an + unlimited repeat of a group that can match an empty string. */ + + flags = (*prev >= OP_SBRA)? match_cbegroup : 0; + + if (*ecode == OP_KETRMIN) + { + RMATCH(eptr, ecode + 1 + LINK_SIZE, offset_top, md, ims, eptrb, 0, RM12); + if (rrc != MATCH_NOMATCH) RRETURN(rrc); + if (flags != 0) /* Could match an empty string */ + { + RMATCH(eptr, prev, offset_top, md, ims, eptrb, flags, RM50); + RRETURN(rrc); + } + ecode = prev; + goto TAIL_RECURSE; + } + else /* OP_KETRMAX */ + { + RMATCH(eptr, prev, offset_top, md, ims, eptrb, flags, RM13); + if (rrc != MATCH_NOMATCH) RRETURN(rrc); + ecode += 1 + LINK_SIZE; + flags = 0; + goto TAIL_RECURSE; + } + /* Control never gets here */ + + /* Start of subject unless notbol, or after internal newline if multiline */ + + case OP_CIRC: + if (md->notbol && eptr == md->start_subject) RRETURN(MATCH_NOMATCH); + if ((ims & PCRE_MULTILINE) != 0) + { + if (eptr != md->start_subject && + (eptr == md->end_subject || !WAS_NEWLINE(eptr))) + RRETURN(MATCH_NOMATCH); + ecode++; + break; + } + /* ... else fall through */ + + /* Start of subject assertion */ + + case OP_SOD: + if (eptr != md->start_subject) RRETURN(MATCH_NOMATCH); + ecode++; + break; + + /* Start of match assertion */ + + case OP_SOM: + if (eptr != md->start_subject + md->start_offset) RRETURN(MATCH_NOMATCH); + ecode++; + break; + + /* Reset the start of match point */ + + case OP_SET_SOM: + mstart = eptr; + ecode++; + break; + + /* Assert before internal newline if multiline, or before a terminating + newline unless endonly is set, else end of subject unless noteol is set. */ + + case OP_DOLL: + if ((ims & PCRE_MULTILINE) != 0) + { + if (eptr < md->end_subject) + { if (!IS_NEWLINE(eptr)) RRETURN(MATCH_NOMATCH); } + else + { if (md->noteol) RRETURN(MATCH_NOMATCH); } + ecode++; + break; + } + else + { + if (md->noteol) RRETURN(MATCH_NOMATCH); + if (!md->endonly) + { + if (eptr != md->end_subject && + (!IS_NEWLINE(eptr) || eptr != md->end_subject - md->nllen)) + RRETURN(MATCH_NOMATCH); + ecode++; + break; + } + } + /* ... else fall through for endonly */ + + /* End of subject assertion (\z) */ + + case OP_EOD: + if (eptr < md->end_subject) RRETURN(MATCH_NOMATCH); + ecode++; + break; + + /* End of subject or ending \n assertion (\Z) */ + + case OP_EODN: + if (eptr != md->end_subject && + (!IS_NEWLINE(eptr) || eptr != md->end_subject - md->nllen)) + RRETURN(MATCH_NOMATCH); + ecode++; + break; + + /* Word boundary assertions */ + + case OP_NOT_WORD_BOUNDARY: + case OP_WORD_BOUNDARY: + { + + /* Find out if the previous and current characters are "word" characters. + It takes a bit more work in UTF-8 mode. Characters > 255 are assumed to + be "non-word" characters. */ + +#ifdef SUPPORT_UTF8 + if (utf8) + { + if (eptr == md->start_subject) prev_is_word = FALSE; else + { + const uschar *lastptr = eptr - 1; + while((*lastptr & 0xc0) == 0x80) lastptr--; + GETCHAR(c, lastptr); + prev_is_word = c < 256 && (md->ctypes[c] & ctype_word) != 0; + } + if (eptr >= md->end_subject) cur_is_word = FALSE; else + { + GETCHAR(c, eptr); + cur_is_word = c < 256 && (md->ctypes[c] & ctype_word) != 0; + } + } + else +#endif + + /* More streamlined when not in UTF-8 mode */ + + { + prev_is_word = (eptr != md->start_subject) && + ((md->ctypes[eptr[-1]] & ctype_word) != 0); + cur_is_word = (eptr < md->end_subject) && + ((md->ctypes[*eptr] & ctype_word) != 0); + } + + /* Now see if the situation is what we want */ + + if ((*ecode++ == OP_WORD_BOUNDARY)? + cur_is_word == prev_is_word : cur_is_word != prev_is_word) + RRETURN(MATCH_NOMATCH); + } + break; + + /* Match a single character type; inline for speed */ + + case OP_ANY: + if ((ims & PCRE_DOTALL) == 0) + { + if (IS_NEWLINE(eptr)) RRETURN(MATCH_NOMATCH); + } + if (eptr++ >= md->end_subject) RRETURN(MATCH_NOMATCH); + if (utf8) + while (eptr < md->end_subject && (*eptr & 0xc0) == 0x80) eptr++; + ecode++; + break; + + /* Match a single byte, even in UTF-8 mode. This opcode really does match + any byte, even newline, independent of the setting of PCRE_DOTALL. */ + + case OP_ANYBYTE: + if (eptr++ >= md->end_subject) RRETURN(MATCH_NOMATCH); + ecode++; + break; + + case OP_NOT_DIGIT: + if (eptr >= md->end_subject) RRETURN(MATCH_NOMATCH); + GETCHARINCTEST(c, eptr); + if ( +#ifdef SUPPORT_UTF8 + c < 256 && +#endif + (md->ctypes[c] & ctype_digit) != 0 + ) + RRETURN(MATCH_NOMATCH); + ecode++; + break; + + case OP_DIGIT: + if (eptr >= md->end_subject) RRETURN(MATCH_NOMATCH); + GETCHARINCTEST(c, eptr); + if ( +#ifdef SUPPORT_UTF8 + c >= 256 || +#endif + (md->ctypes[c] & ctype_digit) == 0 + ) + RRETURN(MATCH_NOMATCH); + ecode++; + break; + + case OP_NOT_WHITESPACE: + if (eptr >= md->end_subject) RRETURN(MATCH_NOMATCH); + GETCHARINCTEST(c, eptr); + if ( +#ifdef SUPPORT_UTF8 + c < 256 && +#endif + (md->ctypes[c] & ctype_space) != 0 + ) + RRETURN(MATCH_NOMATCH); + ecode++; + break; + + case OP_WHITESPACE: + if (eptr >= md->end_subject) RRETURN(MATCH_NOMATCH); + GETCHARINCTEST(c, eptr); + if ( +#ifdef SUPPORT_UTF8 + c >= 256 || +#endif + (md->ctypes[c] & ctype_space) == 0 + ) + RRETURN(MATCH_NOMATCH); + ecode++; + break; + + case OP_NOT_WORDCHAR: + if (eptr >= md->end_subject) RRETURN(MATCH_NOMATCH); + GETCHARINCTEST(c, eptr); + if ( +#ifdef SUPPORT_UTF8 + c < 256 && +#endif + (md->ctypes[c] & ctype_word) != 0 + ) + RRETURN(MATCH_NOMATCH); + ecode++; + break; + + case OP_WORDCHAR: + if (eptr >= md->end_subject) RRETURN(MATCH_NOMATCH); + GETCHARINCTEST(c, eptr); + if ( +#ifdef SUPPORT_UTF8 + c >= 256 || +#endif + (md->ctypes[c] & ctype_word) == 0 + ) + RRETURN(MATCH_NOMATCH); + ecode++; + break; + + case OP_ANYNL: + if (eptr >= md->end_subject) RRETURN(MATCH_NOMATCH); + GETCHARINCTEST(c, eptr); + switch(c) + { + default: RRETURN(MATCH_NOMATCH); + case 0x000d: + if (eptr < md->end_subject && *eptr == 0x0a) eptr++; + break; + + case 0x000a: + break; + + case 0x000b: + case 0x000c: + case 0x0085: + case 0x2028: + case 0x2029: + if (md->bsr_anycrlf) RRETURN(MATCH_NOMATCH); + break; + } + ecode++; + break; + + case OP_NOT_HSPACE: + if (eptr >= md->end_subject) RRETURN(MATCH_NOMATCH); + GETCHARINCTEST(c, eptr); + switch(c) + { + default: break; + case 0x09: /* HT */ + case 0x20: /* SPACE */ + case 0xa0: /* NBSP */ + case 0x1680: /* OGHAM SPACE MARK */ + case 0x180e: /* MONGOLIAN VOWEL SEPARATOR */ + case 0x2000: /* EN QUAD */ + case 0x2001: /* EM QUAD */ + case 0x2002: /* EN SPACE */ + case 0x2003: /* EM SPACE */ + case 0x2004: /* THREE-PER-EM SPACE */ + case 0x2005: /* FOUR-PER-EM SPACE */ + case 0x2006: /* SIX-PER-EM SPACE */ + case 0x2007: /* FIGURE SPACE */ + case 0x2008: /* PUNCTUATION SPACE */ + case 0x2009: /* THIN SPACE */ + case 0x200A: /* HAIR SPACE */ + case 0x202f: /* NARROW NO-BREAK SPACE */ + case 0x205f: /* MEDIUM MATHEMATICAL SPACE */ + case 0x3000: /* IDEOGRAPHIC SPACE */ + RRETURN(MATCH_NOMATCH); + } + ecode++; + break; + + case OP_HSPACE: + if (eptr >= md->end_subject) RRETURN(MATCH_NOMATCH); + GETCHARINCTEST(c, eptr); + switch(c) + { + default: RRETURN(MATCH_NOMATCH); + case 0x09: /* HT */ + case 0x20: /* SPACE */ + case 0xa0: /* NBSP */ + case 0x1680: /* OGHAM SPACE MARK */ + case 0x180e: /* MONGOLIAN VOWEL SEPARATOR */ + case 0x2000: /* EN QUAD */ + case 0x2001: /* EM QUAD */ + case 0x2002: /* EN SPACE */ + case 0x2003: /* EM SPACE */ + case 0x2004: /* THREE-PER-EM SPACE */ + case 0x2005: /* FOUR-PER-EM SPACE */ + case 0x2006: /* SIX-PER-EM SPACE */ + case 0x2007: /* FIGURE SPACE */ + case 0x2008: /* PUNCTUATION SPACE */ + case 0x2009: /* THIN SPACE */ + case 0x200A: /* HAIR SPACE */ + case 0x202f: /* NARROW NO-BREAK SPACE */ + case 0x205f: /* MEDIUM MATHEMATICAL SPACE */ + case 0x3000: /* IDEOGRAPHIC SPACE */ + break; + } + ecode++; + break; + + case OP_NOT_VSPACE: + if (eptr >= md->end_subject) RRETURN(MATCH_NOMATCH); + GETCHARINCTEST(c, eptr); + switch(c) + { + default: break; + case 0x0a: /* LF */ + case 0x0b: /* VT */ + case 0x0c: /* FF */ + case 0x0d: /* CR */ + case 0x85: /* NEL */ + case 0x2028: /* LINE SEPARATOR */ + case 0x2029: /* PARAGRAPH SEPARATOR */ + RRETURN(MATCH_NOMATCH); + } + ecode++; + break; + + case OP_VSPACE: + if (eptr >= md->end_subject) RRETURN(MATCH_NOMATCH); + GETCHARINCTEST(c, eptr); + switch(c) + { + default: RRETURN(MATCH_NOMATCH); + case 0x0a: /* LF */ + case 0x0b: /* VT */ + case 0x0c: /* FF */ + case 0x0d: /* CR */ + case 0x85: /* NEL */ + case 0x2028: /* LINE SEPARATOR */ + case 0x2029: /* PARAGRAPH SEPARATOR */ + break; + } + ecode++; + break; + +#ifdef SUPPORT_UCP + /* Check the next character by Unicode property. We will get here only + if the support is in the binary; otherwise a compile-time error occurs. */ + + case OP_PROP: + case OP_NOTPROP: + if (eptr >= md->end_subject) RRETURN(MATCH_NOMATCH); + GETCHARINCTEST(c, eptr); + { + int chartype, script; + int category = _pcre_ucp_findprop(c, &chartype, &script); + + switch(ecode[1]) + { + case PT_ANY: + if (op == OP_NOTPROP) RRETURN(MATCH_NOMATCH); + break; + + case PT_LAMP: + if ((chartype == ucp_Lu || + chartype == ucp_Ll || + chartype == ucp_Lt) == (op == OP_NOTPROP)) + RRETURN(MATCH_NOMATCH); + break; + + case PT_GC: + if ((ecode[2] != category) == (op == OP_PROP)) + RRETURN(MATCH_NOMATCH); + break; + + case PT_PC: + if ((ecode[2] != chartype) == (op == OP_PROP)) + RRETURN(MATCH_NOMATCH); + break; + + case PT_SC: + if ((ecode[2] != script) == (op == OP_PROP)) + RRETURN(MATCH_NOMATCH); + break; + + default: + RRETURN(PCRE_ERROR_INTERNAL); + } + + ecode += 3; + } + break; + + /* Match an extended Unicode sequence. We will get here only if the support + is in the binary; otherwise a compile-time error occurs. */ + + case OP_EXTUNI: + if (eptr >= md->end_subject) RRETURN(MATCH_NOMATCH); + GETCHARINCTEST(c, eptr); + { + int chartype, script; + int category = _pcre_ucp_findprop(c, &chartype, &script); + if (category == ucp_M) RRETURN(MATCH_NOMATCH); + while (eptr < md->end_subject) + { + int len = 1; + if (!utf8) c = *eptr; else + { + GETCHARLEN(c, eptr, len); + } + category = _pcre_ucp_findprop(c, &chartype, &script); + if (category != ucp_M) break; + eptr += len; + } + } + ecode++; + break; +#endif + + + /* Match a back reference, possibly repeatedly. Look past the end of the + item to see if there is repeat information following. The code is similar + to that for character classes, but repeated for efficiency. Then obey + similar code to character type repeats - written out again for speed. + However, if the referenced string is the empty string, always treat + it as matched, any number of times (otherwise there could be infinite + loops). */ + + case OP_REF: + { + offset = GET2(ecode, 1) << 1; /* Doubled ref number */ + ecode += 3; /* Advance past item */ + + /* If the reference is unset, set the length to be longer than the amount + of subject left; this ensures that every attempt at a match fails. We + can't just fail here, because of the possibility of quantifiers with zero + minima. */ + + length = (offset >= offset_top || md->offset_vector[offset] < 0)? + md->end_subject - eptr + 1 : + md->offset_vector[offset+1] - md->offset_vector[offset]; + + /* Set up for repetition, or handle the non-repeated case */ + + switch (*ecode) + { + case OP_CRSTAR: + case OP_CRMINSTAR: + case OP_CRPLUS: + case OP_CRMINPLUS: + case OP_CRQUERY: + case OP_CRMINQUERY: + c = *ecode++ - OP_CRSTAR; + minimize = (c & 1) != 0; + min = rep_min[c]; /* Pick up values from tables; */ + max = rep_max[c]; /* zero for max => infinity */ + if (max == 0) max = INT_MAX; + break; + + case OP_CRRANGE: + case OP_CRMINRANGE: + minimize = (*ecode == OP_CRMINRANGE); + min = GET2(ecode, 1); + max = GET2(ecode, 3); + if (max == 0) max = INT_MAX; + ecode += 5; + break; + + default: /* No repeat follows */ + if (!match_ref(offset, eptr, length, md, ims)) RRETURN(MATCH_NOMATCH); + eptr += length; + continue; /* With the main loop */ + } + + /* If the length of the reference is zero, just continue with the + main loop. */ + + if (length == 0) continue; + + /* First, ensure the minimum number of matches are present. We get back + the length of the reference string explicitly rather than passing the + address of eptr, so that eptr can be a register variable. */ + + for (i = 1; i <= min; i++) + { + if (!match_ref(offset, eptr, length, md, ims)) RRETURN(MATCH_NOMATCH); + eptr += length; + } + + /* If min = max, continue at the same level without recursion. + They are not both allowed to be zero. */ + + if (min == max) continue; + + /* If minimizing, keep trying and advancing the pointer */ + + if (minimize) + { + for (fi = min;; fi++) + { + RMATCH(eptr, ecode, offset_top, md, ims, eptrb, 0, RM14); + if (rrc != MATCH_NOMATCH) RRETURN(rrc); + if (fi >= max || !match_ref(offset, eptr, length, md, ims)) + RRETURN(MATCH_NOMATCH); + eptr += length; + } + /* Control never gets here */ + } + + /* If maximizing, find the longest string and work backwards */ + + else + { + pp = eptr; + for (i = min; i < max; i++) + { + if (!match_ref(offset, eptr, length, md, ims)) break; + eptr += length; + } + while (eptr >= pp) + { + RMATCH(eptr, ecode, offset_top, md, ims, eptrb, 0, RM15); + if (rrc != MATCH_NOMATCH) RRETURN(rrc); + eptr -= length; + } + RRETURN(MATCH_NOMATCH); + } + } + /* Control never gets here */ + + + + /* Match a bit-mapped character class, possibly repeatedly. This op code is + used when all the characters in the class have values in the range 0-255, + and either the matching is caseful, or the characters are in the range + 0-127 when UTF-8 processing is enabled. The only difference between + OP_CLASS and OP_NCLASS occurs when a data character outside the range is + encountered. + + First, look past the end of the item to see if there is repeat information + following. Then obey similar code to character type repeats - written out + again for speed. */ + + case OP_NCLASS: + case OP_CLASS: + { + data = ecode + 1; /* Save for matching */ + ecode += 33; /* Advance past the item */ + + switch (*ecode) + { + case OP_CRSTAR: + case OP_CRMINSTAR: + case OP_CRPLUS: + case OP_CRMINPLUS: + case OP_CRQUERY: + case OP_CRMINQUERY: + c = *ecode++ - OP_CRSTAR; + minimize = (c & 1) != 0; + min = rep_min[c]; /* Pick up values from tables; */ + max = rep_max[c]; /* zero for max => infinity */ + if (max == 0) max = INT_MAX; + break; + + case OP_CRRANGE: + case OP_CRMINRANGE: + minimize = (*ecode == OP_CRMINRANGE); + min = GET2(ecode, 1); + max = GET2(ecode, 3); + if (max == 0) max = INT_MAX; + ecode += 5; + break; + + default: /* No repeat follows */ + min = max = 1; + break; + } + + /* First, ensure the minimum number of matches are present. */ + +#ifdef SUPPORT_UTF8 + /* UTF-8 mode */ + if (utf8) + { + for (i = 1; i <= min; i++) + { + if (eptr >= md->end_subject) RRETURN(MATCH_NOMATCH); + GETCHARINC(c, eptr); + if (c > 255) + { + if (op == OP_CLASS) RRETURN(MATCH_NOMATCH); + } + else + { + if ((data[c/8] & (1 << (c&7))) == 0) RRETURN(MATCH_NOMATCH); + } + } + } + else +#endif + /* Not UTF-8 mode */ + { + for (i = 1; i <= min; i++) + { + if (eptr >= md->end_subject) RRETURN(MATCH_NOMATCH); + c = *eptr++; + if ((data[c/8] & (1 << (c&7))) == 0) RRETURN(MATCH_NOMATCH); + } + } + + /* If max == min we can continue with the main loop without the + need to recurse. */ + + if (min == max) continue; + + /* If minimizing, keep testing the rest of the expression and advancing + the pointer while it matches the class. */ + + if (minimize) + { +#ifdef SUPPORT_UTF8 + /* UTF-8 mode */ + if (utf8) + { + for (fi = min;; fi++) + { + RMATCH(eptr, ecode, offset_top, md, ims, eptrb, 0, RM16); + if (rrc != MATCH_NOMATCH) RRETURN(rrc); + if (fi >= max || eptr >= md->end_subject) RRETURN(MATCH_NOMATCH); + GETCHARINC(c, eptr); + if (c > 255) + { + if (op == OP_CLASS) RRETURN(MATCH_NOMATCH); + } + else + { + if ((data[c/8] & (1 << (c&7))) == 0) RRETURN(MATCH_NOMATCH); + } + } + } + else +#endif + /* Not UTF-8 mode */ + { + for (fi = min;; fi++) + { + RMATCH(eptr, ecode, offset_top, md, ims, eptrb, 0, RM17); + if (rrc != MATCH_NOMATCH) RRETURN(rrc); + if (fi >= max || eptr >= md->end_subject) RRETURN(MATCH_NOMATCH); + c = *eptr++; + if ((data[c/8] & (1 << (c&7))) == 0) RRETURN(MATCH_NOMATCH); + } + } + /* Control never gets here */ + } + + /* If maximizing, find the longest possible run, then work backwards. */ + + else + { + pp = eptr; + +#ifdef SUPPORT_UTF8 + /* UTF-8 mode */ + if (utf8) + { + for (i = min; i < max; i++) + { + int len = 1; + if (eptr >= md->end_subject) break; + GETCHARLEN(c, eptr, len); + if (c > 255) + { + if (op == OP_CLASS) break; + } + else + { + if ((data[c/8] & (1 << (c&7))) == 0) break; + } + eptr += len; + } + for (;;) + { + RMATCH(eptr, ecode, offset_top, md, ims, eptrb, 0, RM18); + if (rrc != MATCH_NOMATCH) RRETURN(rrc); + if (eptr-- == pp) break; /* Stop if tried at original pos */ + BACKCHAR(eptr); + } + } + else +#endif + /* Not UTF-8 mode */ + { + for (i = min; i < max; i++) + { + if (eptr >= md->end_subject) break; + c = *eptr; + if ((data[c/8] & (1 << (c&7))) == 0) break; + eptr++; + } + while (eptr >= pp) + { + RMATCH(eptr, ecode, offset_top, md, ims, eptrb, 0, RM19); + if (rrc != MATCH_NOMATCH) RRETURN(rrc); + eptr--; + } + } + + RRETURN(MATCH_NOMATCH); + } + } + /* Control never gets here */ + + + /* Match an extended character class. This opcode is encountered only + in UTF-8 mode, because that's the only time it is compiled. */ + +#ifdef SUPPORT_UTF8 + case OP_XCLASS: + { + data = ecode + 1 + LINK_SIZE; /* Save for matching */ + ecode += GET(ecode, 1); /* Advance past the item */ + + switch (*ecode) + { + case OP_CRSTAR: + case OP_CRMINSTAR: + case OP_CRPLUS: + case OP_CRMINPLUS: + case OP_CRQUERY: + case OP_CRMINQUERY: + c = *ecode++ - OP_CRSTAR; + minimize = (c & 1) != 0; + min = rep_min[c]; /* Pick up values from tables; */ + max = rep_max[c]; /* zero for max => infinity */ + if (max == 0) max = INT_MAX; + break; + + case OP_CRRANGE: + case OP_CRMINRANGE: + minimize = (*ecode == OP_CRMINRANGE); + min = GET2(ecode, 1); + max = GET2(ecode, 3); + if (max == 0) max = INT_MAX; + ecode += 5; + break; + + default: /* No repeat follows */ + min = max = 1; + break; + } + + /* First, ensure the minimum number of matches are present. */ + + for (i = 1; i <= min; i++) + { + if (eptr >= md->end_subject) RRETURN(MATCH_NOMATCH); + GETCHARINC(c, eptr); + if (!_pcre_xclass(c, data)) RRETURN(MATCH_NOMATCH); + } + + /* If max == min we can continue with the main loop without the + need to recurse. */ + + if (min == max) continue; + + /* If minimizing, keep testing the rest of the expression and advancing + the pointer while it matches the class. */ + + if (minimize) + { + for (fi = min;; fi++) + { + RMATCH(eptr, ecode, offset_top, md, ims, eptrb, 0, RM20); + if (rrc != MATCH_NOMATCH) RRETURN(rrc); + if (fi >= max || eptr >= md->end_subject) RRETURN(MATCH_NOMATCH); + GETCHARINC(c, eptr); + if (!_pcre_xclass(c, data)) RRETURN(MATCH_NOMATCH); + } + /* Control never gets here */ + } + + /* If maximizing, find the longest possible run, then work backwards. */ + + else + { + pp = eptr; + for (i = min; i < max; i++) + { + int len = 1; + if (eptr >= md->end_subject) break; + GETCHARLEN(c, eptr, len); + if (!_pcre_xclass(c, data)) break; + eptr += len; + } + for(;;) + { + RMATCH(eptr, ecode, offset_top, md, ims, eptrb, 0, RM21); + if (rrc != MATCH_NOMATCH) RRETURN(rrc); + if (eptr-- == pp) break; /* Stop if tried at original pos */ + if (utf8) BACKCHAR(eptr); + } + RRETURN(MATCH_NOMATCH); + } + + /* Control never gets here */ + } +#endif /* End of XCLASS */ + + /* Match a single character, casefully */ + + case OP_CHAR: +#ifdef SUPPORT_UTF8 + if (utf8) + { + length = 1; + ecode++; + GETCHARLEN(fc, ecode, length); + if (length > md->end_subject - eptr) RRETURN(MATCH_NOMATCH); + while (length-- > 0) if (*ecode++ != *eptr++) RRETURN(MATCH_NOMATCH); + } + else +#endif + + /* Non-UTF-8 mode */ + { + if (md->end_subject - eptr < 1) RRETURN(MATCH_NOMATCH); + if (ecode[1] != *eptr++) RRETURN(MATCH_NOMATCH); + ecode += 2; + } + break; + + /* Match a single character, caselessly */ + + case OP_CHARNC: +#ifdef SUPPORT_UTF8 + if (utf8) + { + length = 1; + ecode++; + GETCHARLEN(fc, ecode, length); + + if (length > md->end_subject - eptr) RRETURN(MATCH_NOMATCH); + + /* If the pattern character's value is < 128, we have only one byte, and + can use the fast lookup table. */ + + if (fc < 128) + { + if (md->lcc[*ecode++] != md->lcc[*eptr++]) RRETURN(MATCH_NOMATCH); + } + + /* Otherwise we must pick up the subject character */ + + else + { + unsigned int dc; + GETCHARINC(dc, eptr); + ecode += length; + + /* If we have Unicode property support, we can use it to test the other + case of the character, if there is one. */ + + if (fc != dc) + { +#ifdef SUPPORT_UCP + if (dc != _pcre_ucp_othercase(fc)) +#endif + RRETURN(MATCH_NOMATCH); + } + } + } + else +#endif /* SUPPORT_UTF8 */ + + /* Non-UTF-8 mode */ + { + if (md->end_subject - eptr < 1) RRETURN(MATCH_NOMATCH); + if (md->lcc[ecode[1]] != md->lcc[*eptr++]) RRETURN(MATCH_NOMATCH); + ecode += 2; + } + break; + + /* Match a single character repeatedly. */ + + case OP_EXACT: + min = max = GET2(ecode, 1); + ecode += 3; + goto REPEATCHAR; + + case OP_POSUPTO: + possessive = TRUE; + /* Fall through */ + + case OP_UPTO: + case OP_MINUPTO: + min = 0; + max = GET2(ecode, 1); + minimize = *ecode == OP_MINUPTO; + ecode += 3; + goto REPEATCHAR; + + case OP_POSSTAR: + possessive = TRUE; + min = 0; + max = INT_MAX; + ecode++; + goto REPEATCHAR; + + case OP_POSPLUS: + possessive = TRUE; + min = 1; + max = INT_MAX; + ecode++; + goto REPEATCHAR; + + case OP_POSQUERY: + possessive = TRUE; + min = 0; + max = 1; + ecode++; + goto REPEATCHAR; + + case OP_STAR: + case OP_MINSTAR: + case OP_PLUS: + case OP_MINPLUS: + case OP_QUERY: + case OP_MINQUERY: + c = *ecode++ - OP_STAR; + minimize = (c & 1) != 0; + min = rep_min[c]; /* Pick up values from tables; */ + max = rep_max[c]; /* zero for max => infinity */ + if (max == 0) max = INT_MAX; + + /* Common code for all repeated single-character matches. We can give + up quickly if there are fewer than the minimum number of characters left in + the subject. */ + + REPEATCHAR: +#ifdef SUPPORT_UTF8 + if (utf8) + { + length = 1; + charptr = ecode; + GETCHARLEN(fc, ecode, length); + if (min * length > md->end_subject - eptr) RRETURN(MATCH_NOMATCH); + ecode += length; + + /* Handle multibyte character matching specially here. There is + support for caseless matching if UCP support is present. */ + + if (length > 1) + { +#ifdef SUPPORT_UCP + unsigned int othercase; + if ((ims & PCRE_CASELESS) != 0 && + (othercase = _pcre_ucp_othercase(fc)) != NOTACHAR) + oclength = _pcre_ord2utf8(othercase, occhars); + else oclength = 0; +#endif /* SUPPORT_UCP */ + + for (i = 1; i <= min; i++) + { + if (memcmp(eptr, charptr, length) == 0) eptr += length; +#ifdef SUPPORT_UCP + /* Need braces because of following else */ + else if (oclength == 0) { RRETURN(MATCH_NOMATCH); } + else + { + if (memcmp(eptr, occhars, oclength) != 0) RRETURN(MATCH_NOMATCH); + eptr += oclength; + } +#else /* without SUPPORT_UCP */ + else { RRETURN(MATCH_NOMATCH); } +#endif /* SUPPORT_UCP */ + } + + if (min == max) continue; + + if (minimize) + { + for (fi = min;; fi++) + { + RMATCH(eptr, ecode, offset_top, md, ims, eptrb, 0, RM22); + if (rrc != MATCH_NOMATCH) RRETURN(rrc); + if (fi >= max || eptr >= md->end_subject) RRETURN(MATCH_NOMATCH); + if (memcmp(eptr, charptr, length) == 0) eptr += length; +#ifdef SUPPORT_UCP + /* Need braces because of following else */ + else if (oclength == 0) { RRETURN(MATCH_NOMATCH); } + else + { + if (memcmp(eptr, occhars, oclength) != 0) RRETURN(MATCH_NOMATCH); + eptr += oclength; + } +#else /* without SUPPORT_UCP */ + else { RRETURN (MATCH_NOMATCH); } +#endif /* SUPPORT_UCP */ + } + /* Control never gets here */ + } + + else /* Maximize */ + { + pp = eptr; + for (i = min; i < max; i++) + { + if (eptr > md->end_subject - length) break; + if (memcmp(eptr, charptr, length) == 0) eptr += length; +#ifdef SUPPORT_UCP + else if (oclength == 0) break; + else + { + if (memcmp(eptr, occhars, oclength) != 0) break; + eptr += oclength; + } +#else /* without SUPPORT_UCP */ + else break; +#endif /* SUPPORT_UCP */ + } + + if (possessive) continue; + for(;;) + { + RMATCH(eptr, ecode, offset_top, md, ims, eptrb, 0, RM23); + if (rrc != MATCH_NOMATCH) RRETURN(rrc); + if (eptr == pp) RRETURN(MATCH_NOMATCH); +#ifdef SUPPORT_UCP + eptr--; + BACKCHAR(eptr); +#else /* without SUPPORT_UCP */ + eptr -= length; +#endif /* SUPPORT_UCP */ + } + } + /* Control never gets here */ + } + + /* If the length of a UTF-8 character is 1, we fall through here, and + obey the code as for non-UTF-8 characters below, though in this case the + value of fc will always be < 128. */ + } + else +#endif /* SUPPORT_UTF8 */ + + /* When not in UTF-8 mode, load a single-byte character. */ + { + if (min > md->end_subject - eptr) RRETURN(MATCH_NOMATCH); + fc = *ecode++; + } + + /* The value of fc at this point is always less than 256, though we may or + may not be in UTF-8 mode. The code is duplicated for the caseless and + caseful cases, for speed, since matching characters is likely to be quite + common. First, ensure the minimum number of matches are present. If min = + max, continue at the same level without recursing. Otherwise, if + minimizing, keep trying the rest of the expression and advancing one + matching character if failing, up to the maximum. Alternatively, if + maximizing, find the maximum number of characters and work backwards. */ + + DPRINTF(("matching %c{%d,%d} against subject %.*s\n", fc, min, max, + max, eptr)); + + if ((ims & PCRE_CASELESS) != 0) + { + fc = md->lcc[fc]; + for (i = 1; i <= min; i++) + if (fc != md->lcc[*eptr++]) RRETURN(MATCH_NOMATCH); + if (min == max) continue; + if (minimize) + { + for (fi = min;; fi++) + { + RMATCH(eptr, ecode, offset_top, md, ims, eptrb, 0, RM24); + if (rrc != MATCH_NOMATCH) RRETURN(rrc); + if (fi >= max || eptr >= md->end_subject || + fc != md->lcc[*eptr++]) + RRETURN(MATCH_NOMATCH); + } + /* Control never gets here */ + } + else /* Maximize */ + { + pp = eptr; + for (i = min; i < max; i++) + { + if (eptr >= md->end_subject || fc != md->lcc[*eptr]) break; + eptr++; + } + if (possessive) continue; + while (eptr >= pp) + { + RMATCH(eptr, ecode, offset_top, md, ims, eptrb, 0, RM25); + eptr--; + if (rrc != MATCH_NOMATCH) RRETURN(rrc); + } + RRETURN(MATCH_NOMATCH); + } + /* Control never gets here */ + } + + /* Caseful comparisons (includes all multi-byte characters) */ + + else + { + for (i = 1; i <= min; i++) if (fc != *eptr++) RRETURN(MATCH_NOMATCH); + if (min == max) continue; + if (minimize) + { + for (fi = min;; fi++) + { + RMATCH(eptr, ecode, offset_top, md, ims, eptrb, 0, RM26); + if (rrc != MATCH_NOMATCH) RRETURN(rrc); + if (fi >= max || eptr >= md->end_subject || fc != *eptr++) + RRETURN(MATCH_NOMATCH); + } + /* Control never gets here */ + } + else /* Maximize */ + { + pp = eptr; + for (i = min; i < max; i++) + { + if (eptr >= md->end_subject || fc != *eptr) break; + eptr++; + } + if (possessive) continue; + while (eptr >= pp) + { + RMATCH(eptr, ecode, offset_top, md, ims, eptrb, 0, RM27); + eptr--; + if (rrc != MATCH_NOMATCH) RRETURN(rrc); + } + RRETURN(MATCH_NOMATCH); + } + } + /* Control never gets here */ + + /* Match a negated single one-byte character. The character we are + checking can be multibyte. */ + + case OP_NOT: + if (eptr >= md->end_subject) RRETURN(MATCH_NOMATCH); + ecode++; + GETCHARINCTEST(c, eptr); + if ((ims & PCRE_CASELESS) != 0) + { +#ifdef SUPPORT_UTF8 + if (c < 256) +#endif + c = md->lcc[c]; + if (md->lcc[*ecode++] == c) RRETURN(MATCH_NOMATCH); + } + else + { + if (*ecode++ == c) RRETURN(MATCH_NOMATCH); + } + break; + + /* Match a negated single one-byte character repeatedly. This is almost a + repeat of the code for a repeated single character, but I haven't found a + nice way of commoning these up that doesn't require a test of the + positive/negative option for each character match. Maybe that wouldn't add + very much to the time taken, but character matching *is* what this is all + about... */ + + case OP_NOTEXACT: + min = max = GET2(ecode, 1); + ecode += 3; + goto REPEATNOTCHAR; + + case OP_NOTUPTO: + case OP_NOTMINUPTO: + min = 0; + max = GET2(ecode, 1); + minimize = *ecode == OP_NOTMINUPTO; + ecode += 3; + goto REPEATNOTCHAR; + + case OP_NOTPOSSTAR: + possessive = TRUE; + min = 0; + max = INT_MAX; + ecode++; + goto REPEATNOTCHAR; + + case OP_NOTPOSPLUS: + possessive = TRUE; + min = 1; + max = INT_MAX; + ecode++; + goto REPEATNOTCHAR; + + case OP_NOTPOSQUERY: + possessive = TRUE; + min = 0; + max = 1; + ecode++; + goto REPEATNOTCHAR; + + case OP_NOTPOSUPTO: + possessive = TRUE; + min = 0; + max = GET2(ecode, 1); + ecode += 3; + goto REPEATNOTCHAR; + + case OP_NOTSTAR: + case OP_NOTMINSTAR: + case OP_NOTPLUS: + case OP_NOTMINPLUS: + case OP_NOTQUERY: + case OP_NOTMINQUERY: + c = *ecode++ - OP_NOTSTAR; + minimize = (c & 1) != 0; + min = rep_min[c]; /* Pick up values from tables; */ + max = rep_max[c]; /* zero for max => infinity */ + if (max == 0) max = INT_MAX; + + /* Common code for all repeated single-byte matches. We can give up quickly + if there are fewer than the minimum number of bytes left in the + subject. */ + + REPEATNOTCHAR: + if (min > md->end_subject - eptr) RRETURN(MATCH_NOMATCH); + fc = *ecode++; + + /* The code is duplicated for the caseless and caseful cases, for speed, + since matching characters is likely to be quite common. First, ensure the + minimum number of matches are present. If min = max, continue at the same + level without recursing. Otherwise, if minimizing, keep trying the rest of + the expression and advancing one matching character if failing, up to the + maximum. Alternatively, if maximizing, find the maximum number of + characters and work backwards. */ + + DPRINTF(("negative matching %c{%d,%d} against subject %.*s\n", fc, min, max, + max, eptr)); + + if ((ims & PCRE_CASELESS) != 0) + { + fc = md->lcc[fc]; + +#ifdef SUPPORT_UTF8 + /* UTF-8 mode */ + if (utf8) + { + register unsigned int d; + for (i = 1; i <= min; i++) + { + GETCHARINC(d, eptr); + if (d < 256) d = md->lcc[d]; + if (fc == d) RRETURN(MATCH_NOMATCH); + } + } + else +#endif + + /* Not UTF-8 mode */ + { + for (i = 1; i <= min; i++) + if (fc == md->lcc[*eptr++]) RRETURN(MATCH_NOMATCH); + } + + if (min == max) continue; + + if (minimize) + { +#ifdef SUPPORT_UTF8 + /* UTF-8 mode */ + if (utf8) + { + register unsigned int d; + for (fi = min;; fi++) + { + RMATCH(eptr, ecode, offset_top, md, ims, eptrb, 0, RM28); + if (rrc != MATCH_NOMATCH) RRETURN(rrc); + GETCHARINC(d, eptr); + if (d < 256) d = md->lcc[d]; + if (fi >= max || eptr >= md->end_subject || fc == d) + RRETURN(MATCH_NOMATCH); + } + } + else +#endif + /* Not UTF-8 mode */ + { + for (fi = min;; fi++) + { + RMATCH(eptr, ecode, offset_top, md, ims, eptrb, 0, RM29); + if (rrc != MATCH_NOMATCH) RRETURN(rrc); + if (fi >= max || eptr >= md->end_subject || fc == md->lcc[*eptr++]) + RRETURN(MATCH_NOMATCH); + } + } + /* Control never gets here */ + } + + /* Maximize case */ + + else + { + pp = eptr; + +#ifdef SUPPORT_UTF8 + /* UTF-8 mode */ + if (utf8) + { + register unsigned int d; + for (i = min; i < max; i++) + { + int len = 1; + if (eptr >= md->end_subject) break; + GETCHARLEN(d, eptr, len); + if (d < 256) d = md->lcc[d]; + if (fc == d) break; + eptr += len; + } + if (possessive) continue; + for(;;) + { + RMATCH(eptr, ecode, offset_top, md, ims, eptrb, 0, RM30); + if (rrc != MATCH_NOMATCH) RRETURN(rrc); + if (eptr-- == pp) break; /* Stop if tried at original pos */ + BACKCHAR(eptr); + } + } + else +#endif + /* Not UTF-8 mode */ + { + for (i = min; i < max; i++) + { + if (eptr >= md->end_subject || fc == md->lcc[*eptr]) break; + eptr++; + } + if (possessive) continue; + while (eptr >= pp) + { + RMATCH(eptr, ecode, offset_top, md, ims, eptrb, 0, RM31); + if (rrc != MATCH_NOMATCH) RRETURN(rrc); + eptr--; + } + } + + RRETURN(MATCH_NOMATCH); + } + /* Control never gets here */ + } + + /* Caseful comparisons */ + + else + { +#ifdef SUPPORT_UTF8 + /* UTF-8 mode */ + if (utf8) + { + register unsigned int d; + for (i = 1; i <= min; i++) + { + GETCHARINC(d, eptr); + if (fc == d) RRETURN(MATCH_NOMATCH); + } + } + else +#endif + /* Not UTF-8 mode */ + { + for (i = 1; i <= min; i++) + if (fc == *eptr++) RRETURN(MATCH_NOMATCH); + } + + if (min == max) continue; + + if (minimize) + { +#ifdef SUPPORT_UTF8 + /* UTF-8 mode */ + if (utf8) + { + register unsigned int d; + for (fi = min;; fi++) + { + RMATCH(eptr, ecode, offset_top, md, ims, eptrb, 0, RM32); + if (rrc != MATCH_NOMATCH) RRETURN(rrc); + GETCHARINC(d, eptr); + if (fi >= max || eptr >= md->end_subject || fc == d) + RRETURN(MATCH_NOMATCH); + } + } + else +#endif + /* Not UTF-8 mode */ + { + for (fi = min;; fi++) + { + RMATCH(eptr, ecode, offset_top, md, ims, eptrb, 0, RM33); + if (rrc != MATCH_NOMATCH) RRETURN(rrc); + if (fi >= max || eptr >= md->end_subject || fc == *eptr++) + RRETURN(MATCH_NOMATCH); + } + } + /* Control never gets here */ + } + + /* Maximize case */ + + else + { + pp = eptr; + +#ifdef SUPPORT_UTF8 + /* UTF-8 mode */ + if (utf8) + { + register unsigned int d; + for (i = min; i < max; i++) + { + int len = 1; + if (eptr >= md->end_subject) break; + GETCHARLEN(d, eptr, len); + if (fc == d) break; + eptr += len; + } + if (possessive) continue; + for(;;) + { + RMATCH(eptr, ecode, offset_top, md, ims, eptrb, 0, RM34); + if (rrc != MATCH_NOMATCH) RRETURN(rrc); + if (eptr-- == pp) break; /* Stop if tried at original pos */ + BACKCHAR(eptr); + } + } + else +#endif + /* Not UTF-8 mode */ + { + for (i = min; i < max; i++) + { + if (eptr >= md->end_subject || fc == *eptr) break; + eptr++; + } + if (possessive) continue; + while (eptr >= pp) + { + RMATCH(eptr, ecode, offset_top, md, ims, eptrb, 0, RM35); + if (rrc != MATCH_NOMATCH) RRETURN(rrc); + eptr--; + } + } + + RRETURN(MATCH_NOMATCH); + } + } + /* Control never gets here */ + + /* Match a single character type repeatedly; several different opcodes + share code. This is very similar to the code for single characters, but we + repeat it in the interests of efficiency. */ + + case OP_TYPEEXACT: + min = max = GET2(ecode, 1); + minimize = TRUE; + ecode += 3; + goto REPEATTYPE; + + case OP_TYPEUPTO: + case OP_TYPEMINUPTO: + min = 0; + max = GET2(ecode, 1); + minimize = *ecode == OP_TYPEMINUPTO; + ecode += 3; + goto REPEATTYPE; + + case OP_TYPEPOSSTAR: + possessive = TRUE; + min = 0; + max = INT_MAX; + ecode++; + goto REPEATTYPE; + + case OP_TYPEPOSPLUS: + possessive = TRUE; + min = 1; + max = INT_MAX; + ecode++; + goto REPEATTYPE; + + case OP_TYPEPOSQUERY: + possessive = TRUE; + min = 0; + max = 1; + ecode++; + goto REPEATTYPE; + + case OP_TYPEPOSUPTO: + possessive = TRUE; + min = 0; + max = GET2(ecode, 1); + ecode += 3; + goto REPEATTYPE; + + case OP_TYPESTAR: + case OP_TYPEMINSTAR: + case OP_TYPEPLUS: + case OP_TYPEMINPLUS: + case OP_TYPEQUERY: + case OP_TYPEMINQUERY: + c = *ecode++ - OP_TYPESTAR; + minimize = (c & 1) != 0; + min = rep_min[c]; /* Pick up values from tables; */ + max = rep_max[c]; /* zero for max => infinity */ + if (max == 0) max = INT_MAX; + + /* Common code for all repeated single character type matches. Note that + in UTF-8 mode, '.' matches a character of any length, but for the other + character types, the valid characters are all one-byte long. */ + + REPEATTYPE: + ctype = *ecode++; /* Code for the character type */ + +#ifdef SUPPORT_UCP + if (ctype == OP_PROP || ctype == OP_NOTPROP) + { + prop_fail_result = ctype == OP_NOTPROP; + prop_type = *ecode++; + prop_value = *ecode++; + } + else prop_type = -1; +#endif + + /* First, ensure the minimum number of matches are present. Use inline + code for maximizing the speed, and do the type test once at the start + (i.e. keep it out of the loop). Also we can test that there are at least + the minimum number of bytes before we start. This isn't as effective in + UTF-8 mode, but it does no harm. Separate the UTF-8 code completely as that + is tidier. Also separate the UCP code, which can be the same for both UTF-8 + and single-bytes. */ + + if (min > md->end_subject - eptr) RRETURN(MATCH_NOMATCH); + if (min > 0) + { +#ifdef SUPPORT_UCP + if (prop_type >= 0) + { + switch(prop_type) + { + case PT_ANY: + if (prop_fail_result) RRETURN(MATCH_NOMATCH); + for (i = 1; i <= min; i++) + { + if (eptr >= md->end_subject) RRETURN(MATCH_NOMATCH); + GETCHARINCTEST(c, eptr); + } + break; + + case PT_LAMP: + for (i = 1; i <= min; i++) + { + if (eptr >= md->end_subject) RRETURN(MATCH_NOMATCH); + GETCHARINCTEST(c, eptr); + prop_category = _pcre_ucp_findprop(c, &prop_chartype, &prop_script); + if ((prop_chartype == ucp_Lu || + prop_chartype == ucp_Ll || + prop_chartype == ucp_Lt) == prop_fail_result) + RRETURN(MATCH_NOMATCH); + } + break; + + case PT_GC: + for (i = 1; i <= min; i++) + { + if (eptr >= md->end_subject) RRETURN(MATCH_NOMATCH); + GETCHARINCTEST(c, eptr); + prop_category = _pcre_ucp_findprop(c, &prop_chartype, &prop_script); + if ((prop_category == prop_value) == prop_fail_result) + RRETURN(MATCH_NOMATCH); + } + break; + + case PT_PC: + for (i = 1; i <= min; i++) + { + if (eptr >= md->end_subject) RRETURN(MATCH_NOMATCH); + GETCHARINCTEST(c, eptr); + prop_category = _pcre_ucp_findprop(c, &prop_chartype, &prop_script); + if ((prop_chartype == prop_value) == prop_fail_result) + RRETURN(MATCH_NOMATCH); + } + break; + + case PT_SC: + for (i = 1; i <= min; i++) + { + if (eptr >= md->end_subject) RRETURN(MATCH_NOMATCH); + GETCHARINCTEST(c, eptr); + prop_category = _pcre_ucp_findprop(c, &prop_chartype, &prop_script); + if ((prop_script == prop_value) == prop_fail_result) + RRETURN(MATCH_NOMATCH); + } + break; + + default: + RRETURN(PCRE_ERROR_INTERNAL); + } + } + + /* Match extended Unicode sequences. We will get here only if the + support is in the binary; otherwise a compile-time error occurs. */ + + else if (ctype == OP_EXTUNI) + { + for (i = 1; i <= min; i++) + { + GETCHARINCTEST(c, eptr); + prop_category = _pcre_ucp_findprop(c, &prop_chartype, &prop_script); + if (prop_category == ucp_M) RRETURN(MATCH_NOMATCH); + while (eptr < md->end_subject) + { + int len = 1; + if (!utf8) c = *eptr; else + { + GETCHARLEN(c, eptr, len); + } + prop_category = _pcre_ucp_findprop(c, &prop_chartype, &prop_script); + if (prop_category != ucp_M) break; + eptr += len; + } + } + } + + else +#endif /* SUPPORT_UCP */ + +/* Handle all other cases when the coding is UTF-8 */ + +#ifdef SUPPORT_UTF8 + if (utf8) switch(ctype) + { + case OP_ANY: + for (i = 1; i <= min; i++) + { + if (eptr >= md->end_subject || + ((ims & PCRE_DOTALL) == 0 && IS_NEWLINE(eptr))) + RRETURN(MATCH_NOMATCH); + eptr++; + while (eptr < md->end_subject && (*eptr & 0xc0) == 0x80) eptr++; + } + break; + + case OP_ANYBYTE: + eptr += min; + break; + + case OP_ANYNL: + for (i = 1; i <= min; i++) + { + if (eptr >= md->end_subject) RRETURN(MATCH_NOMATCH); + GETCHARINC(c, eptr); + switch(c) + { + default: RRETURN(MATCH_NOMATCH); + case 0x000d: + if (eptr < md->end_subject && *eptr == 0x0a) eptr++; + break; + + case 0x000a: + break; + + case 0x000b: + case 0x000c: + case 0x0085: + case 0x2028: + case 0x2029: + if (md->bsr_anycrlf) RRETURN(MATCH_NOMATCH); + break; + } + } + break; + + case OP_NOT_HSPACE: + for (i = 1; i <= min; i++) + { + if (eptr >= md->end_subject) RRETURN(MATCH_NOMATCH); + GETCHARINC(c, eptr); + switch(c) + { + default: break; + case 0x09: /* HT */ + case 0x20: /* SPACE */ + case 0xa0: /* NBSP */ + case 0x1680: /* OGHAM SPACE MARK */ + case 0x180e: /* MONGOLIAN VOWEL SEPARATOR */ + case 0x2000: /* EN QUAD */ + case 0x2001: /* EM QUAD */ + case 0x2002: /* EN SPACE */ + case 0x2003: /* EM SPACE */ + case 0x2004: /* THREE-PER-EM SPACE */ + case 0x2005: /* FOUR-PER-EM SPACE */ + case 0x2006: /* SIX-PER-EM SPACE */ + case 0x2007: /* FIGURE SPACE */ + case 0x2008: /* PUNCTUATION SPACE */ + case 0x2009: /* THIN SPACE */ + case 0x200A: /* HAIR SPACE */ + case 0x202f: /* NARROW NO-BREAK SPACE */ + case 0x205f: /* MEDIUM MATHEMATICAL SPACE */ + case 0x3000: /* IDEOGRAPHIC SPACE */ + RRETURN(MATCH_NOMATCH); + } + } + break; + + case OP_HSPACE: + for (i = 1; i <= min; i++) + { + if (eptr >= md->end_subject) RRETURN(MATCH_NOMATCH); + GETCHARINC(c, eptr); + switch(c) + { + default: RRETURN(MATCH_NOMATCH); + case 0x09: /* HT */ + case 0x20: /* SPACE */ + case 0xa0: /* NBSP */ + case 0x1680: /* OGHAM SPACE MARK */ + case 0x180e: /* MONGOLIAN VOWEL SEPARATOR */ + case 0x2000: /* EN QUAD */ + case 0x2001: /* EM QUAD */ + case 0x2002: /* EN SPACE */ + case 0x2003: /* EM SPACE */ + case 0x2004: /* THREE-PER-EM SPACE */ + case 0x2005: /* FOUR-PER-EM SPACE */ + case 0x2006: /* SIX-PER-EM SPACE */ + case 0x2007: /* FIGURE SPACE */ + case 0x2008: /* PUNCTUATION SPACE */ + case 0x2009: /* THIN SPACE */ + case 0x200A: /* HAIR SPACE */ + case 0x202f: /* NARROW NO-BREAK SPACE */ + case 0x205f: /* MEDIUM MATHEMATICAL SPACE */ + case 0x3000: /* IDEOGRAPHIC SPACE */ + break; + } + } + break; + + case OP_NOT_VSPACE: + for (i = 1; i <= min; i++) + { + if (eptr >= md->end_subject) RRETURN(MATCH_NOMATCH); + GETCHARINC(c, eptr); + switch(c) + { + default: break; + case 0x0a: /* LF */ + case 0x0b: /* VT */ + case 0x0c: /* FF */ + case 0x0d: /* CR */ + case 0x85: /* NEL */ + case 0x2028: /* LINE SEPARATOR */ + case 0x2029: /* PARAGRAPH SEPARATOR */ + RRETURN(MATCH_NOMATCH); + } + } + break; + + case OP_VSPACE: + for (i = 1; i <= min; i++) + { + if (eptr >= md->end_subject) RRETURN(MATCH_NOMATCH); + GETCHARINC(c, eptr); + switch(c) + { + default: RRETURN(MATCH_NOMATCH); + case 0x0a: /* LF */ + case 0x0b: /* VT */ + case 0x0c: /* FF */ + case 0x0d: /* CR */ + case 0x85: /* NEL */ + case 0x2028: /* LINE SEPARATOR */ + case 0x2029: /* PARAGRAPH SEPARATOR */ + break; + } + } + break; + + case OP_NOT_DIGIT: + for (i = 1; i <= min; i++) + { + if (eptr >= md->end_subject) RRETURN(MATCH_NOMATCH); + GETCHARINC(c, eptr); + if (c < 128 && (md->ctypes[c] & ctype_digit) != 0) + RRETURN(MATCH_NOMATCH); + } + break; + + case OP_DIGIT: + for (i = 1; i <= min; i++) + { + if (eptr >= md->end_subject || + *eptr >= 128 || (md->ctypes[*eptr++] & ctype_digit) == 0) + RRETURN(MATCH_NOMATCH); + /* No need to skip more bytes - we know it's a 1-byte character */ + } + break; + + case OP_NOT_WHITESPACE: + for (i = 1; i <= min; i++) + { + if (eptr >= md->end_subject || + (*eptr < 128 && (md->ctypes[*eptr] & ctype_space) != 0)) + RRETURN(MATCH_NOMATCH); + while (++eptr < md->end_subject && (*eptr & 0xc0) == 0x80); + } + break; + + case OP_WHITESPACE: + for (i = 1; i <= min; i++) + { + if (eptr >= md->end_subject || + *eptr >= 128 || (md->ctypes[*eptr++] & ctype_space) == 0) + RRETURN(MATCH_NOMATCH); + /* No need to skip more bytes - we know it's a 1-byte character */ + } + break; + + case OP_NOT_WORDCHAR: + for (i = 1; i <= min; i++) + { + if (eptr >= md->end_subject || + (*eptr < 128 && (md->ctypes[*eptr] & ctype_word) != 0)) + RRETURN(MATCH_NOMATCH); + while (++eptr < md->end_subject && (*eptr & 0xc0) == 0x80); + } + break; + + case OP_WORDCHAR: + for (i = 1; i <= min; i++) + { + if (eptr >= md->end_subject || + *eptr >= 128 || (md->ctypes[*eptr++] & ctype_word) == 0) + RRETURN(MATCH_NOMATCH); + /* No need to skip more bytes - we know it's a 1-byte character */ + } + break; + + default: + RRETURN(PCRE_ERROR_INTERNAL); + } /* End switch(ctype) */ + + else +#endif /* SUPPORT_UTF8 */ + + /* Code for the non-UTF-8 case for minimum matching of operators other + than OP_PROP and OP_NOTPROP. We can assume that there are the minimum + number of bytes present, as this was tested above. */ + + switch(ctype) + { + case OP_ANY: + if ((ims & PCRE_DOTALL) == 0) + { + for (i = 1; i <= min; i++) + { + if (IS_NEWLINE(eptr)) RRETURN(MATCH_NOMATCH); + eptr++; + } + } + else eptr += min; + break; + + case OP_ANYBYTE: + eptr += min; + break; + + /* Because of the CRLF case, we can't assume the minimum number of + bytes are present in this case. */ + + case OP_ANYNL: + for (i = 1; i <= min; i++) + { + if (eptr >= md->end_subject) RRETURN(MATCH_NOMATCH); + switch(*eptr++) + { + default: RRETURN(MATCH_NOMATCH); + case 0x000d: + if (eptr < md->end_subject && *eptr == 0x0a) eptr++; + break; + case 0x000a: + break; + + case 0x000b: + case 0x000c: + case 0x0085: + if (md->bsr_anycrlf) RRETURN(MATCH_NOMATCH); + break; + } + } + break; + + case OP_NOT_HSPACE: + for (i = 1; i <= min; i++) + { + if (eptr >= md->end_subject) RRETURN(MATCH_NOMATCH); + switch(*eptr++) + { + default: break; + case 0x09: /* HT */ + case 0x20: /* SPACE */ + case 0xa0: /* NBSP */ + RRETURN(MATCH_NOMATCH); + } + } + break; + + case OP_HSPACE: + for (i = 1; i <= min; i++) + { + if (eptr >= md->end_subject) RRETURN(MATCH_NOMATCH); + switch(*eptr++) + { + default: RRETURN(MATCH_NOMATCH); + case 0x09: /* HT */ + case 0x20: /* SPACE */ + case 0xa0: /* NBSP */ + break; + } + } + break; + + case OP_NOT_VSPACE: + for (i = 1; i <= min; i++) + { + if (eptr >= md->end_subject) RRETURN(MATCH_NOMATCH); + switch(*eptr++) + { + default: break; + case 0x0a: /* LF */ + case 0x0b: /* VT */ + case 0x0c: /* FF */ + case 0x0d: /* CR */ + case 0x85: /* NEL */ + RRETURN(MATCH_NOMATCH); + } + } + break; + + case OP_VSPACE: + for (i = 1; i <= min; i++) + { + if (eptr >= md->end_subject) RRETURN(MATCH_NOMATCH); + switch(*eptr++) + { + default: RRETURN(MATCH_NOMATCH); + case 0x0a: /* LF */ + case 0x0b: /* VT */ + case 0x0c: /* FF */ + case 0x0d: /* CR */ + case 0x85: /* NEL */ + break; + } + } + break; + + case OP_NOT_DIGIT: + for (i = 1; i <= min; i++) + if ((md->ctypes[*eptr++] & ctype_digit) != 0) RRETURN(MATCH_NOMATCH); + break; + + case OP_DIGIT: + for (i = 1; i <= min; i++) + if ((md->ctypes[*eptr++] & ctype_digit) == 0) RRETURN(MATCH_NOMATCH); + break; + + case OP_NOT_WHITESPACE: + for (i = 1; i <= min; i++) + if ((md->ctypes[*eptr++] & ctype_space) != 0) RRETURN(MATCH_NOMATCH); + break; + + case OP_WHITESPACE: + for (i = 1; i <= min; i++) + if ((md->ctypes[*eptr++] & ctype_space) == 0) RRETURN(MATCH_NOMATCH); + break; + + case OP_NOT_WORDCHAR: + for (i = 1; i <= min; i++) + if ((md->ctypes[*eptr++] & ctype_word) != 0) + RRETURN(MATCH_NOMATCH); + break; + + case OP_WORDCHAR: + for (i = 1; i <= min; i++) + if ((md->ctypes[*eptr++] & ctype_word) == 0) + RRETURN(MATCH_NOMATCH); + break; + + default: + RRETURN(PCRE_ERROR_INTERNAL); + } + } + + /* If min = max, continue at the same level without recursing */ + + if (min == max) continue; + + /* If minimizing, we have to test the rest of the pattern before each + subsequent match. Again, separate the UTF-8 case for speed, and also + separate the UCP cases. */ + + if (minimize) + { +#ifdef SUPPORT_UCP + if (prop_type >= 0) + { + switch(prop_type) + { + case PT_ANY: + for (fi = min;; fi++) + { + RMATCH(eptr, ecode, offset_top, md, ims, eptrb, 0, RM36); + if (rrc != MATCH_NOMATCH) RRETURN(rrc); + if (fi >= max || eptr >= md->end_subject) RRETURN(MATCH_NOMATCH); + GETCHARINC(c, eptr); + if (prop_fail_result) RRETURN(MATCH_NOMATCH); + } + /* Control never gets here */ + + case PT_LAMP: + for (fi = min;; fi++) + { + RMATCH(eptr, ecode, offset_top, md, ims, eptrb, 0, RM37); + if (rrc != MATCH_NOMATCH) RRETURN(rrc); + if (fi >= max || eptr >= md->end_subject) RRETURN(MATCH_NOMATCH); + GETCHARINC(c, eptr); + prop_category = _pcre_ucp_findprop(c, &prop_chartype, &prop_script); + if ((prop_chartype == ucp_Lu || + prop_chartype == ucp_Ll || + prop_chartype == ucp_Lt) == prop_fail_result) + RRETURN(MATCH_NOMATCH); + } + /* Control never gets here */ + + case PT_GC: + for (fi = min;; fi++) + { + RMATCH(eptr, ecode, offset_top, md, ims, eptrb, 0, RM38); + if (rrc != MATCH_NOMATCH) RRETURN(rrc); + if (fi >= max || eptr >= md->end_subject) RRETURN(MATCH_NOMATCH); + GETCHARINC(c, eptr); + prop_category = _pcre_ucp_findprop(c, &prop_chartype, &prop_script); + if ((prop_category == prop_value) == prop_fail_result) + RRETURN(MATCH_NOMATCH); + } + /* Control never gets here */ + + case PT_PC: + for (fi = min;; fi++) + { + RMATCH(eptr, ecode, offset_top, md, ims, eptrb, 0, RM39); + if (rrc != MATCH_NOMATCH) RRETURN(rrc); + if (fi >= max || eptr >= md->end_subject) RRETURN(MATCH_NOMATCH); + GETCHARINC(c, eptr); + prop_category = _pcre_ucp_findprop(c, &prop_chartype, &prop_script); + if ((prop_chartype == prop_value) == prop_fail_result) + RRETURN(MATCH_NOMATCH); + } + /* Control never gets here */ + + case PT_SC: + for (fi = min;; fi++) + { + RMATCH(eptr, ecode, offset_top, md, ims, eptrb, 0, RM40); + if (rrc != MATCH_NOMATCH) RRETURN(rrc); + if (fi >= max || eptr >= md->end_subject) RRETURN(MATCH_NOMATCH); + GETCHARINC(c, eptr); + prop_category = _pcre_ucp_findprop(c, &prop_chartype, &prop_script); + if ((prop_script == prop_value) == prop_fail_result) + RRETURN(MATCH_NOMATCH); + } + /* Control never gets here */ + + default: + RRETURN(PCRE_ERROR_INTERNAL); + } + } + + /* Match extended Unicode sequences. We will get here only if the + support is in the binary; otherwise a compile-time error occurs. */ + + else if (ctype == OP_EXTUNI) + { + for (fi = min;; fi++) + { + RMATCH(eptr, ecode, offset_top, md, ims, eptrb, 0, RM41); + if (rrc != MATCH_NOMATCH) RRETURN(rrc); + if (fi >= max || eptr >= md->end_subject) RRETURN(MATCH_NOMATCH); + GETCHARINCTEST(c, eptr); + prop_category = _pcre_ucp_findprop(c, &prop_chartype, &prop_script); + if (prop_category == ucp_M) RRETURN(MATCH_NOMATCH); + while (eptr < md->end_subject) + { + int len = 1; + if (!utf8) c = *eptr; else + { + GETCHARLEN(c, eptr, len); + } + prop_category = _pcre_ucp_findprop(c, &prop_chartype, &prop_script); + if (prop_category != ucp_M) break; + eptr += len; + } + } + } + + else +#endif /* SUPPORT_UCP */ + +#ifdef SUPPORT_UTF8 + /* UTF-8 mode */ + if (utf8) + { + for (fi = min;; fi++) + { + RMATCH(eptr, ecode, offset_top, md, ims, eptrb, 0, RM42); + if (rrc != MATCH_NOMATCH) RRETURN(rrc); + if (fi >= max || eptr >= md->end_subject || + (ctype == OP_ANY && (ims & PCRE_DOTALL) == 0 && + IS_NEWLINE(eptr))) + RRETURN(MATCH_NOMATCH); + + GETCHARINC(c, eptr); + switch(ctype) + { + case OP_ANY: /* This is the DOTALL case */ + break; + + case OP_ANYBYTE: + break; + + case OP_ANYNL: + switch(c) + { + default: RRETURN(MATCH_NOMATCH); + case 0x000d: + if (eptr < md->end_subject && *eptr == 0x0a) eptr++; + break; + case 0x000a: + break; + + case 0x000b: + case 0x000c: + case 0x0085: + case 0x2028: + case 0x2029: + if (md->bsr_anycrlf) RRETURN(MATCH_NOMATCH); + break; + } + break; + + case OP_NOT_HSPACE: + switch(c) + { + default: break; + case 0x09: /* HT */ + case 0x20: /* SPACE */ + case 0xa0: /* NBSP */ + case 0x1680: /* OGHAM SPACE MARK */ + case 0x180e: /* MONGOLIAN VOWEL SEPARATOR */ + case 0x2000: /* EN QUAD */ + case 0x2001: /* EM QUAD */ + case 0x2002: /* EN SPACE */ + case 0x2003: /* EM SPACE */ + case 0x2004: /* THREE-PER-EM SPACE */ + case 0x2005: /* FOUR-PER-EM SPACE */ + case 0x2006: /* SIX-PER-EM SPACE */ + case 0x2007: /* FIGURE SPACE */ + case 0x2008: /* PUNCTUATION SPACE */ + case 0x2009: /* THIN SPACE */ + case 0x200A: /* HAIR SPACE */ + case 0x202f: /* NARROW NO-BREAK SPACE */ + case 0x205f: /* MEDIUM MATHEMATICAL SPACE */ + case 0x3000: /* IDEOGRAPHIC SPACE */ + RRETURN(MATCH_NOMATCH); + } + break; + + case OP_HSPACE: + switch(c) + { + default: RRETURN(MATCH_NOMATCH); + case 0x09: /* HT */ + case 0x20: /* SPACE */ + case 0xa0: /* NBSP */ + case 0x1680: /* OGHAM SPACE MARK */ + case 0x180e: /* MONGOLIAN VOWEL SEPARATOR */ + case 0x2000: /* EN QUAD */ + case 0x2001: /* EM QUAD */ + case 0x2002: /* EN SPACE */ + case 0x2003: /* EM SPACE */ + case 0x2004: /* THREE-PER-EM SPACE */ + case 0x2005: /* FOUR-PER-EM SPACE */ + case 0x2006: /* SIX-PER-EM SPACE */ + case 0x2007: /* FIGURE SPACE */ + case 0x2008: /* PUNCTUATION SPACE */ + case 0x2009: /* THIN SPACE */ + case 0x200A: /* HAIR SPACE */ + case 0x202f: /* NARROW NO-BREAK SPACE */ + case 0x205f: /* MEDIUM MATHEMATICAL SPACE */ + case 0x3000: /* IDEOGRAPHIC SPACE */ + break; + } + break; + + case OP_NOT_VSPACE: + switch(c) + { + default: break; + case 0x0a: /* LF */ + case 0x0b: /* VT */ + case 0x0c: /* FF */ + case 0x0d: /* CR */ + case 0x85: /* NEL */ + case 0x2028: /* LINE SEPARATOR */ + case 0x2029: /* PARAGRAPH SEPARATOR */ + RRETURN(MATCH_NOMATCH); + } + break; + + case OP_VSPACE: + switch(c) + { + default: RRETURN(MATCH_NOMATCH); + case 0x0a: /* LF */ + case 0x0b: /* VT */ + case 0x0c: /* FF */ + case 0x0d: /* CR */ + case 0x85: /* NEL */ + case 0x2028: /* LINE SEPARATOR */ + case 0x2029: /* PARAGRAPH SEPARATOR */ + break; + } + break; + + case OP_NOT_DIGIT: + if (c < 256 && (md->ctypes[c] & ctype_digit) != 0) + RRETURN(MATCH_NOMATCH); + break; + + case OP_DIGIT: + if (c >= 256 || (md->ctypes[c] & ctype_digit) == 0) + RRETURN(MATCH_NOMATCH); + break; + + case OP_NOT_WHITESPACE: + if (c < 256 && (md->ctypes[c] & ctype_space) != 0) + RRETURN(MATCH_NOMATCH); + break; + + case OP_WHITESPACE: + if (c >= 256 || (md->ctypes[c] & ctype_space) == 0) + RRETURN(MATCH_NOMATCH); + break; + + case OP_NOT_WORDCHAR: + if (c < 256 && (md->ctypes[c] & ctype_word) != 0) + RRETURN(MATCH_NOMATCH); + break; + + case OP_WORDCHAR: + if (c >= 256 || (md->ctypes[c] & ctype_word) == 0) + RRETURN(MATCH_NOMATCH); + break; + + default: + RRETURN(PCRE_ERROR_INTERNAL); + } + } + } + else +#endif + /* Not UTF-8 mode */ + { + for (fi = min;; fi++) + { + RMATCH(eptr, ecode, offset_top, md, ims, eptrb, 0, RM43); + if (rrc != MATCH_NOMATCH) RRETURN(rrc); + if (fi >= max || eptr >= md->end_subject || + ((ims & PCRE_DOTALL) == 0 && IS_NEWLINE(eptr))) + RRETURN(MATCH_NOMATCH); + + c = *eptr++; + switch(ctype) + { + case OP_ANY: /* This is the DOTALL case */ + break; + + case OP_ANYBYTE: + break; + + case OP_ANYNL: + switch(c) + { + default: RRETURN(MATCH_NOMATCH); + case 0x000d: + if (eptr < md->end_subject && *eptr == 0x0a) eptr++; + break; + + case 0x000a: + break; + + case 0x000b: + case 0x000c: + case 0x0085: + if (md->bsr_anycrlf) RRETURN(MATCH_NOMATCH); + break; + } + break; + + case OP_NOT_HSPACE: + switch(c) + { + default: break; + case 0x09: /* HT */ + case 0x20: /* SPACE */ + case 0xa0: /* NBSP */ + RRETURN(MATCH_NOMATCH); + } + break; + + case OP_HSPACE: + switch(c) + { + default: RRETURN(MATCH_NOMATCH); + case 0x09: /* HT */ + case 0x20: /* SPACE */ + case 0xa0: /* NBSP */ + break; + } + break; + + case OP_NOT_VSPACE: + switch(c) + { + default: break; + case 0x0a: /* LF */ + case 0x0b: /* VT */ + case 0x0c: /* FF */ + case 0x0d: /* CR */ + case 0x85: /* NEL */ + RRETURN(MATCH_NOMATCH); + } + break; + + case OP_VSPACE: + switch(c) + { + default: RRETURN(MATCH_NOMATCH); + case 0x0a: /* LF */ + case 0x0b: /* VT */ + case 0x0c: /* FF */ + case 0x0d: /* CR */ + case 0x85: /* NEL */ + break; + } + break; + + case OP_NOT_DIGIT: + if ((md->ctypes[c] & ctype_digit) != 0) RRETURN(MATCH_NOMATCH); + break; + + case OP_DIGIT: + if ((md->ctypes[c] & ctype_digit) == 0) RRETURN(MATCH_NOMATCH); + break; + + case OP_NOT_WHITESPACE: + if ((md->ctypes[c] & ctype_space) != 0) RRETURN(MATCH_NOMATCH); + break; + + case OP_WHITESPACE: + if ((md->ctypes[c] & ctype_space) == 0) RRETURN(MATCH_NOMATCH); + break; + + case OP_NOT_WORDCHAR: + if ((md->ctypes[c] & ctype_word) != 0) RRETURN(MATCH_NOMATCH); + break; + + case OP_WORDCHAR: + if ((md->ctypes[c] & ctype_word) == 0) RRETURN(MATCH_NOMATCH); + break; + + default: + RRETURN(PCRE_ERROR_INTERNAL); + } + } + } + /* Control never gets here */ + } + + /* If maximizing, it is worth using inline code for speed, doing the type + test once at the start (i.e. keep it out of the loop). Again, keep the + UTF-8 and UCP stuff separate. */ + + else + { + pp = eptr; /* Remember where we started */ + +#ifdef SUPPORT_UCP + if (prop_type >= 0) + { + switch(prop_type) + { + case PT_ANY: + for (i = min; i < max; i++) + { + int len = 1; + if (eptr >= md->end_subject) break; + GETCHARLEN(c, eptr, len); + if (prop_fail_result) break; + eptr+= len; + } + break; + + case PT_LAMP: + for (i = min; i < max; i++) + { + int len = 1; + if (eptr >= md->end_subject) break; + GETCHARLEN(c, eptr, len); + prop_category = _pcre_ucp_findprop(c, &prop_chartype, &prop_script); + if ((prop_chartype == ucp_Lu || + prop_chartype == ucp_Ll || + prop_chartype == ucp_Lt) == prop_fail_result) + break; + eptr+= len; + } + break; + + case PT_GC: + for (i = min; i < max; i++) + { + int len = 1; + if (eptr >= md->end_subject) break; + GETCHARLEN(c, eptr, len); + prop_category = _pcre_ucp_findprop(c, &prop_chartype, &prop_script); + if ((prop_category == prop_value) == prop_fail_result) + break; + eptr+= len; + } + break; + + case PT_PC: + for (i = min; i < max; i++) + { + int len = 1; + if (eptr >= md->end_subject) break; + GETCHARLEN(c, eptr, len); + prop_category = _pcre_ucp_findprop(c, &prop_chartype, &prop_script); + if ((prop_chartype == prop_value) == prop_fail_result) + break; + eptr+= len; + } + break; + + case PT_SC: + for (i = min; i < max; i++) + { + int len = 1; + if (eptr >= md->end_subject) break; + GETCHARLEN(c, eptr, len); + prop_category = _pcre_ucp_findprop(c, &prop_chartype, &prop_script); + if ((prop_script == prop_value) == prop_fail_result) + break; + eptr+= len; + } + break; + } + + /* eptr is now past the end of the maximum run */ + + if (possessive) continue; + for(;;) + { + RMATCH(eptr, ecode, offset_top, md, ims, eptrb, 0, RM44); + if (rrc != MATCH_NOMATCH) RRETURN(rrc); + if (eptr-- == pp) break; /* Stop if tried at original pos */ + if (utf8) BACKCHAR(eptr); + } + } + + /* Match extended Unicode sequences. We will get here only if the + support is in the binary; otherwise a compile-time error occurs. */ + + else if (ctype == OP_EXTUNI) + { + for (i = min; i < max; i++) + { + if (eptr >= md->end_subject) break; + GETCHARINCTEST(c, eptr); + prop_category = _pcre_ucp_findprop(c, &prop_chartype, &prop_script); + if (prop_category == ucp_M) break; + while (eptr < md->end_subject) + { + int len = 1; + if (!utf8) c = *eptr; else + { + GETCHARLEN(c, eptr, len); + } + prop_category = _pcre_ucp_findprop(c, &prop_chartype, &prop_script); + if (prop_category != ucp_M) break; + eptr += len; + } + } + + /* eptr is now past the end of the maximum run */ + + if (possessive) continue; + for(;;) + { + RMATCH(eptr, ecode, offset_top, md, ims, eptrb, 0, RM45); + if (rrc != MATCH_NOMATCH) RRETURN(rrc); + if (eptr-- == pp) break; /* Stop if tried at original pos */ + for (;;) /* Move back over one extended */ + { + int len = 1; + if (!utf8) c = *eptr; else + { + BACKCHAR(eptr); + GETCHARLEN(c, eptr, len); + } + prop_category = _pcre_ucp_findprop(c, &prop_chartype, &prop_script); + if (prop_category != ucp_M) break; + eptr--; + } + } + } + + else +#endif /* SUPPORT_UCP */ + +#ifdef SUPPORT_UTF8 + /* UTF-8 mode */ + + if (utf8) + { + switch(ctype) + { + case OP_ANY: + if (max < INT_MAX) + { + if ((ims & PCRE_DOTALL) == 0) + { + for (i = min; i < max; i++) + { + if (eptr >= md->end_subject || IS_NEWLINE(eptr)) break; + eptr++; + while (eptr < md->end_subject && (*eptr & 0xc0) == 0x80) eptr++; + } + } + else + { + for (i = min; i < max; i++) + { + if (eptr >= md->end_subject) break; + eptr++; + while (eptr < md->end_subject && (*eptr & 0xc0) == 0x80) eptr++; + } + } + } + + /* Handle unlimited UTF-8 repeat */ + + else + { + if ((ims & PCRE_DOTALL) == 0) + { + for (i = min; i < max; i++) + { + if (eptr >= md->end_subject || IS_NEWLINE(eptr)) break; + eptr++; + while (eptr < md->end_subject && (*eptr & 0xc0) == 0x80) eptr++; + } + } + else + { + eptr = md->end_subject; + } + } + break; + + /* The byte case is the same as non-UTF8 */ + + case OP_ANYBYTE: + c = max - min; + if (c > (unsigned int)(md->end_subject - eptr)) + c = md->end_subject - eptr; + eptr += c; + break; + + case OP_ANYNL: + for (i = min; i < max; i++) + { + int len = 1; + if (eptr >= md->end_subject) break; + GETCHARLEN(c, eptr, len); + if (c == 0x000d) + { + if (++eptr >= md->end_subject) break; + if (*eptr == 0x000a) eptr++; + } + else + { + if (c != 0x000a && + (md->bsr_anycrlf || + (c != 0x000b && c != 0x000c && + c != 0x0085 && c != 0x2028 && c != 0x2029))) + break; + eptr += len; + } + } + break; + + case OP_NOT_HSPACE: + case OP_HSPACE: + for (i = min; i < max; i++) + { + BOOL gotspace; + int len = 1; + if (eptr >= md->end_subject) break; + GETCHARLEN(c, eptr, len); + switch(c) + { + default: gotspace = FALSE; break; + case 0x09: /* HT */ + case 0x20: /* SPACE */ + case 0xa0: /* NBSP */ + case 0x1680: /* OGHAM SPACE MARK */ + case 0x180e: /* MONGOLIAN VOWEL SEPARATOR */ + case 0x2000: /* EN QUAD */ + case 0x2001: /* EM QUAD */ + case 0x2002: /* EN SPACE */ + case 0x2003: /* EM SPACE */ + case 0x2004: /* THREE-PER-EM SPACE */ + case 0x2005: /* FOUR-PER-EM SPACE */ + case 0x2006: /* SIX-PER-EM SPACE */ + case 0x2007: /* FIGURE SPACE */ + case 0x2008: /* PUNCTUATION SPACE */ + case 0x2009: /* THIN SPACE */ + case 0x200A: /* HAIR SPACE */ + case 0x202f: /* NARROW NO-BREAK SPACE */ + case 0x205f: /* MEDIUM MATHEMATICAL SPACE */ + case 0x3000: /* IDEOGRAPHIC SPACE */ + gotspace = TRUE; + break; + } + if (gotspace == (ctype == OP_NOT_HSPACE)) break; + eptr += len; + } + break; + + case OP_NOT_VSPACE: + case OP_VSPACE: + for (i = min; i < max; i++) + { + BOOL gotspace; + int len = 1; + if (eptr >= md->end_subject) break; + GETCHARLEN(c, eptr, len); + switch(c) + { + default: gotspace = FALSE; break; + case 0x0a: /* LF */ + case 0x0b: /* VT */ + case 0x0c: /* FF */ + case 0x0d: /* CR */ + case 0x85: /* NEL */ + case 0x2028: /* LINE SEPARATOR */ + case 0x2029: /* PARAGRAPH SEPARATOR */ + gotspace = TRUE; + break; + } + if (gotspace == (ctype == OP_NOT_VSPACE)) break; + eptr += len; + } + break; + + case OP_NOT_DIGIT: + for (i = min; i < max; i++) + { + int len = 1; + if (eptr >= md->end_subject) break; + GETCHARLEN(c, eptr, len); + if (c < 256 && (md->ctypes[c] & ctype_digit) != 0) break; + eptr+= len; + } + break; + + case OP_DIGIT: + for (i = min; i < max; i++) + { + int len = 1; + if (eptr >= md->end_subject) break; + GETCHARLEN(c, eptr, len); + if (c >= 256 ||(md->ctypes[c] & ctype_digit) == 0) break; + eptr+= len; + } + break; + + case OP_NOT_WHITESPACE: + for (i = min; i < max; i++) + { + int len = 1; + if (eptr >= md->end_subject) break; + GETCHARLEN(c, eptr, len); + if (c < 256 && (md->ctypes[c] & ctype_space) != 0) break; + eptr+= len; + } + break; + + case OP_WHITESPACE: + for (i = min; i < max; i++) + { + int len = 1; + if (eptr >= md->end_subject) break; + GETCHARLEN(c, eptr, len); + if (c >= 256 ||(md->ctypes[c] & ctype_space) == 0) break; + eptr+= len; + } + break; + + case OP_NOT_WORDCHAR: + for (i = min; i < max; i++) + { + int len = 1; + if (eptr >= md->end_subject) break; + GETCHARLEN(c, eptr, len); + if (c < 256 && (md->ctypes[c] & ctype_word) != 0) break; + eptr+= len; + } + break; + + case OP_WORDCHAR: + for (i = min; i < max; i++) + { + int len = 1; + if (eptr >= md->end_subject) break; + GETCHARLEN(c, eptr, len); + if (c >= 256 || (md->ctypes[c] & ctype_word) == 0) break; + eptr+= len; + } + break; + + default: + RRETURN(PCRE_ERROR_INTERNAL); + } + + /* eptr is now past the end of the maximum run */ + + if (possessive) continue; + for(;;) + { + RMATCH(eptr, ecode, offset_top, md, ims, eptrb, 0, RM46); + if (rrc != MATCH_NOMATCH) RRETURN(rrc); + if (eptr-- == pp) break; /* Stop if tried at original pos */ + BACKCHAR(eptr); + } + } + else +#endif /* SUPPORT_UTF8 */ + + /* Not UTF-8 mode */ + { + switch(ctype) + { + case OP_ANY: + if ((ims & PCRE_DOTALL) == 0) + { + for (i = min; i < max; i++) + { + if (eptr >= md->end_subject || IS_NEWLINE(eptr)) break; + eptr++; + } + break; + } + /* For DOTALL case, fall through and treat as \C */ + + case OP_ANYBYTE: + c = max - min; + if (c > (unsigned int)(md->end_subject - eptr)) + c = md->end_subject - eptr; + eptr += c; + break; + + case OP_ANYNL: + for (i = min; i < max; i++) + { + if (eptr >= md->end_subject) break; + c = *eptr; + if (c == 0x000d) + { + if (++eptr >= md->end_subject) break; + if (*eptr == 0x000a) eptr++; + } + else + { + if (c != 0x000a && + (md->bsr_anycrlf || + (c != 0x000b && c != 0x000c && c != 0x0085))) + break; + eptr++; + } + } + break; + + case OP_NOT_HSPACE: + for (i = min; i < max; i++) + { + if (eptr >= md->end_subject) break; + c = *eptr; + if (c == 0x09 || c == 0x20 || c == 0xa0) break; + eptr++; + } + break; + + case OP_HSPACE: + for (i = min; i < max; i++) + { + if (eptr >= md->end_subject) break; + c = *eptr; + if (c != 0x09 && c != 0x20 && c != 0xa0) break; + eptr++; + } + break; + + case OP_NOT_VSPACE: + for (i = min; i < max; i++) + { + if (eptr >= md->end_subject) break; + c = *eptr; + if (c == 0x0a || c == 0x0b || c == 0x0c || c == 0x0d || c == 0x85) + break; + eptr++; + } + break; + + case OP_VSPACE: + for (i = min; i < max; i++) + { + if (eptr >= md->end_subject) break; + c = *eptr; + if (c != 0x0a && c != 0x0b && c != 0x0c && c != 0x0d && c != 0x85) + break; + eptr++; + } + break; + + case OP_NOT_DIGIT: + for (i = min; i < max; i++) + { + if (eptr >= md->end_subject || (md->ctypes[*eptr] & ctype_digit) != 0) + break; + eptr++; + } + break; + + case OP_DIGIT: + for (i = min; i < max; i++) + { + if (eptr >= md->end_subject || (md->ctypes[*eptr] & ctype_digit) == 0) + break; + eptr++; + } + break; + + case OP_NOT_WHITESPACE: + for (i = min; i < max; i++) + { + if (eptr >= md->end_subject || (md->ctypes[*eptr] & ctype_space) != 0) + break; + eptr++; + } + break; + + case OP_WHITESPACE: + for (i = min; i < max; i++) + { + if (eptr >= md->end_subject || (md->ctypes[*eptr] & ctype_space) == 0) + break; + eptr++; + } + break; + + case OP_NOT_WORDCHAR: + for (i = min; i < max; i++) + { + if (eptr >= md->end_subject || (md->ctypes[*eptr] & ctype_word) != 0) + break; + eptr++; + } + break; + + case OP_WORDCHAR: + for (i = min; i < max; i++) + { + if (eptr >= md->end_subject || (md->ctypes[*eptr] & ctype_word) == 0) + break; + eptr++; + } + break; + + default: + RRETURN(PCRE_ERROR_INTERNAL); + } + + /* eptr is now past the end of the maximum run */ + + if (possessive) continue; + while (eptr >= pp) + { + RMATCH(eptr, ecode, offset_top, md, ims, eptrb, 0, RM47); + eptr--; + if (rrc != MATCH_NOMATCH) RRETURN(rrc); + } + } + + /* Get here if we can't make it match with any permitted repetitions */ + + RRETURN(MATCH_NOMATCH); + } + /* Control never gets here */ + + /* There's been some horrible disaster. Arrival here can only mean there is + something seriously wrong in the code above or the OP_xxx definitions. */ + + default: + DPRINTF(("Unknown opcode %d\n", *ecode)); + RRETURN(PCRE_ERROR_UNKNOWN_OPCODE); + } + + /* Do not stick any code in here without much thought; it is assumed + that "continue" in the code above comes out to here to repeat the main + loop. */ + + } /* End of main loop */ +/* Control never reaches here */ + + +/* When compiling to use the heap rather than the stack for recursive calls to +match(), the RRETURN() macro jumps here. The number that is saved in +frame->Xwhere indicates which label we actually want to return to. */ + +#ifdef NO_RECURSE +#define LBL(val) case val: goto L_RM##val; +HEAP_RETURN: +switch (frame->Xwhere) + { + LBL( 1) LBL( 2) LBL( 3) LBL( 4) LBL( 5) LBL( 6) LBL( 7) LBL( 8) + LBL( 9) LBL(10) LBL(11) LBL(12) LBL(13) LBL(14) LBL(15) LBL(17) + LBL(19) LBL(24) LBL(25) LBL(26) LBL(27) LBL(29) LBL(31) LBL(33) + LBL(35) LBL(43) LBL(47) LBL(48) LBL(49) LBL(50) LBL(51) LBL(52) + LBL(53) LBL(54) +#ifdef SUPPORT_UTF8 + LBL(16) LBL(18) LBL(20) LBL(21) LBL(22) LBL(23) LBL(28) LBL(30) + LBL(32) LBL(34) LBL(42) LBL(46) +#ifdef SUPPORT_UCP + LBL(36) LBL(37) LBL(38) LBL(39) LBL(40) LBL(41) LBL(44) LBL(45) +#endif /* SUPPORT_UCP */ +#endif /* SUPPORT_UTF8 */ + default: + DPRINTF(("jump error in pcre match: label %d non-existent\n", frame->Xwhere)); + return PCRE_ERROR_INTERNAL; + } +#undef LBL +#endif /* NO_RECURSE */ +} + + +/*************************************************************************** +**************************************************************************** + RECURSION IN THE match() FUNCTION + +Undefine all the macros that were defined above to handle this. */ + +#ifdef NO_RECURSE +#undef eptr +#undef ecode +#undef mstart +#undef offset_top +#undef ims +#undef eptrb +#undef flags + +#undef callpat +#undef charptr +#undef data +#undef next +#undef pp +#undef prev +#undef saved_eptr + +#undef new_recursive + +#undef cur_is_word +#undef condition +#undef prev_is_word + +#undef original_ims + +#undef ctype +#undef length +#undef max +#undef min +#undef number +#undef offset +#undef op +#undef save_capture_last +#undef save_offset1 +#undef save_offset2 +#undef save_offset3 +#undef stacksave + +#undef newptrb + +#endif + +/* These two are defined as macros in both cases */ + +#undef fc +#undef fi + +/*************************************************************************** +***************************************************************************/ + + + +/************************************************* +* Execute a Regular Expression * +*************************************************/ + +/* This function applies a compiled re to a subject string and picks out +portions of the string if it matches. Two elements in the vector are set for +each substring: the offsets to the start and end of the substring. + +Arguments: + argument_re points to the compiled expression + extra_data points to extra data or is NULL + subject points to the subject string + length length of subject string (may contain binary zeros) + start_offset where to start in the subject string + options option bits + offsets points to a vector of ints to be filled in with offsets + offsetcount the number of elements in the vector + +Returns: > 0 => success; value is the number of elements filled in + = 0 => success, but offsets is not big enough + -1 => failed to match + < -1 => some kind of unexpected problem +*/ + +int +pcre_exec(const pcre *argument_re, const pcre_extra *extra_data, + PCRE_SPTR subject, int length, int start_offset, int options, int *offsets, + int offsetcount) +{ +int rc, resetcount, ocount; +int first_byte = -1; +int req_byte = -1; +int req_byte2 = -1; +int newline; +unsigned long int ims; +BOOL using_temporary_offsets = FALSE; +BOOL anchored; +BOOL startline; +BOOL firstline; +BOOL first_byte_caseless = FALSE; +BOOL req_byte_caseless = FALSE; +BOOL utf8; +match_data match_block; +match_data *md = &match_block; +const uschar *tables; +const uschar *start_bits = NULL; +USPTR start_match = (USPTR)subject + start_offset; +USPTR end_subject; +USPTR req_byte_ptr = start_match - 1; + +pcre_study_data internal_study; +const pcre_study_data *study; + +real_pcre internal_re; +const real_pcre *external_re = (const real_pcre *)argument_re; +const real_pcre *re = external_re; + +/* Plausibility checks */ + +if ((options & ~PUBLIC_EXEC_OPTIONS) != 0) return PCRE_ERROR_BADOPTION; +if (re == NULL || subject == NULL || + (offsets == NULL && offsetcount > 0)) return PCRE_ERROR_NULL; +if (offsetcount < 0) return PCRE_ERROR_BADCOUNT; + +/* Fish out the optional data from the extra_data structure, first setting +the default values. */ + +study = NULL; +md->match_limit = MATCH_LIMIT; +md->match_limit_recursion = MATCH_LIMIT_RECURSION; +md->callout_data = NULL; + +/* The table pointer is always in native byte order. */ + +tables = external_re->tables; + +if (extra_data != NULL) + { + register unsigned int flags = extra_data->flags; + if ((flags & PCRE_EXTRA_STUDY_DATA) != 0) + study = (const pcre_study_data *)extra_data->study_data; + if ((flags & PCRE_EXTRA_MATCH_LIMIT) != 0) + md->match_limit = extra_data->match_limit; + if ((flags & PCRE_EXTRA_MATCH_LIMIT_RECURSION) != 0) + md->match_limit_recursion = extra_data->match_limit_recursion; + if ((flags & PCRE_EXTRA_CALLOUT_DATA) != 0) + md->callout_data = extra_data->callout_data; + if ((flags & PCRE_EXTRA_TABLES) != 0) tables = extra_data->tables; + } + +/* If the exec call supplied NULL for tables, use the inbuilt ones. This +is a feature that makes it possible to save compiled regex and re-use them +in other programs later. */ + +if (tables == NULL) tables = _pcre_default_tables; + +/* Check that the first field in the block is the magic number. If it is not, +test for a regex that was compiled on a host of opposite endianness. If this is +the case, flipped values are put in internal_re and internal_study if there was +study data too. */ + +if (re->magic_number != MAGIC_NUMBER) + { + re = _pcre_try_flipped(re, &internal_re, study, &internal_study); + if (re == NULL) return PCRE_ERROR_BADMAGIC; + if (study != NULL) study = &internal_study; + } + +/* Set up other data */ + +anchored = ((re->options | options) & PCRE_ANCHORED) != 0; +startline = (re->flags & PCRE_STARTLINE) != 0; +firstline = (re->options & PCRE_FIRSTLINE) != 0; + +/* The code starts after the real_pcre block and the capture name table. */ + +md->start_code = (const uschar *)external_re + re->name_table_offset + + re->name_count * re->name_entry_size; + +md->start_subject = (USPTR)subject; +md->start_offset = start_offset; +md->end_subject = md->start_subject + length; +end_subject = md->end_subject; + +md->endonly = (re->options & PCRE_DOLLAR_ENDONLY) != 0; +utf8 = md->utf8 = (re->options & PCRE_UTF8) != 0; + +md->notbol = (options & PCRE_NOTBOL) != 0; +md->noteol = (options & PCRE_NOTEOL) != 0; +md->notempty = (options & PCRE_NOTEMPTY) != 0; +md->partial = (options & PCRE_PARTIAL) != 0; +md->hitend = FALSE; + +md->recursive = NULL; /* No recursion at top level */ + +md->lcc = tables + lcc_offset; +md->ctypes = tables + ctypes_offset; + +/* Handle different \R options. */ + +switch (options & (PCRE_BSR_ANYCRLF|PCRE_BSR_UNICODE)) + { + case 0: + if ((re->options & (PCRE_BSR_ANYCRLF|PCRE_BSR_UNICODE)) != 0) + md->bsr_anycrlf = (re->options & PCRE_BSR_ANYCRLF) != 0; + else +#ifdef BSR_ANYCRLF + md->bsr_anycrlf = TRUE; +#else + md->bsr_anycrlf = FALSE; +#endif + break; + + case PCRE_BSR_ANYCRLF: + md->bsr_anycrlf = TRUE; + break; + + case PCRE_BSR_UNICODE: + md->bsr_anycrlf = FALSE; + break; + + default: return PCRE_ERROR_BADNEWLINE; + } + +/* Handle different types of newline. The three bits give eight cases. If +nothing is set at run time, whatever was used at compile time applies. */ + +switch ((((options & PCRE_NEWLINE_BITS) == 0)? re->options : + (pcre_uint32)options) & PCRE_NEWLINE_BITS) + { + case 0: newline = NEWLINE; break; /* Compile-time default */ + case PCRE_NEWLINE_CR: newline = '\r'; break; + case PCRE_NEWLINE_LF: newline = '\n'; break; + case PCRE_NEWLINE_CR+ + PCRE_NEWLINE_LF: newline = ('\r' << 8) | '\n'; break; + case PCRE_NEWLINE_ANY: newline = -1; break; + case PCRE_NEWLINE_ANYCRLF: newline = -2; break; + default: return PCRE_ERROR_BADNEWLINE; + } + +if (newline == -2) + { + md->nltype = NLTYPE_ANYCRLF; + } +else if (newline < 0) + { + md->nltype = NLTYPE_ANY; + } +else + { + md->nltype = NLTYPE_FIXED; + if (newline > 255) + { + md->nllen = 2; + md->nl[0] = (newline >> 8) & 255; + md->nl[1] = newline & 255; + } + else + { + md->nllen = 1; + md->nl[0] = newline; + } + } + +/* Partial matching is supported only for a restricted set of regexes at the +moment. */ + +if (md->partial && (re->flags & PCRE_NOPARTIAL) != 0) + return PCRE_ERROR_BADPARTIAL; + +/* Check a UTF-8 string if required. Unfortunately there's no way of passing +back the character offset. */ + +#ifdef SUPPORT_UTF8 +if (utf8 && (options & PCRE_NO_UTF8_CHECK) == 0) + { + if (_pcre_valid_utf8((uschar *)subject, length) >= 0) + return PCRE_ERROR_BADUTF8; + if (start_offset > 0 && start_offset < length) + { + int tb = ((uschar *)subject)[start_offset]; + if (tb > 127) + { + tb &= 0xc0; + if (tb != 0 && tb != 0xc0) return PCRE_ERROR_BADUTF8_OFFSET; + } + } + } +#endif + +/* The ims options can vary during the matching as a result of the presence +of (?ims) items in the pattern. They are kept in a local variable so that +restoring at the exit of a group is easy. */ + +ims = re->options & (PCRE_CASELESS|PCRE_MULTILINE|PCRE_DOTALL); + +/* If the expression has got more back references than the offsets supplied can +hold, we get a temporary chunk of working store to use during the matching. +Otherwise, we can use the vector supplied, rounding down its size to a multiple +of 3. */ + +ocount = offsetcount - (offsetcount % 3); + +if (re->top_backref > 0 && re->top_backref >= ocount/3) + { + ocount = re->top_backref * 3 + 3; + md->offset_vector = (int *)(pcre_malloc)(ocount * sizeof(int)); + if (md->offset_vector == NULL) return PCRE_ERROR_NOMEMORY; + using_temporary_offsets = TRUE; + DPRINTF(("Got memory to hold back references\n")); + } +else md->offset_vector = offsets; + +md->offset_end = ocount; +md->offset_max = (2*ocount)/3; +md->offset_overflow = FALSE; +md->capture_last = -1; + +/* Compute the minimum number of offsets that we need to reset each time. Doing +this makes a huge difference to execution time when there aren't many brackets +in the pattern. */ + +resetcount = 2 + re->top_bracket * 2; +if (resetcount > offsetcount) resetcount = ocount; + +/* Reset the working variable associated with each extraction. These should +never be used unless previously set, but they get saved and restored, and so we +initialize them to avoid reading uninitialized locations. */ + +if (md->offset_vector != NULL) + { + register int *iptr = md->offset_vector + ocount; + register int *iend = iptr - resetcount/2 + 1; + while (--iptr >= iend) *iptr = -1; + } + +/* Set up the first character to match, if available. The first_byte value is +never set for an anchored regular expression, but the anchoring may be forced +at run time, so we have to test for anchoring. The first char may be unset for +an unanchored pattern, of course. If there's no first char and the pattern was +studied, there may be a bitmap of possible first characters. */ + +if (!anchored) + { + if ((re->flags & PCRE_FIRSTSET) != 0) + { + first_byte = re->first_byte & 255; + if ((first_byte_caseless = ((re->first_byte & REQ_CASELESS) != 0)) == TRUE) + first_byte = md->lcc[first_byte]; + } + else + if (!startline && study != NULL && + (study->options & PCRE_STUDY_MAPPED) != 0) + start_bits = study->start_bits; + } + +/* For anchored or unanchored matches, there may be a "last known required +character" set. */ + +if ((re->flags & PCRE_REQCHSET) != 0) + { + req_byte = re->req_byte & 255; + req_byte_caseless = (re->req_byte & REQ_CASELESS) != 0; + req_byte2 = (tables + fcc_offset)[req_byte]; /* case flipped */ + } + + +/* ==========================================================================*/ + +/* Loop for handling unanchored repeated matching attempts; for anchored regexs +the loop runs just once. */ + +for(;;) + { + USPTR save_end_subject = end_subject; + USPTR new_start_match; + + /* Reset the maximum number of extractions we might see. */ + + if (md->offset_vector != NULL) + { + register int *iptr = md->offset_vector; + register int *iend = iptr + resetcount; + while (iptr < iend) *iptr++ = -1; + } + + /* Advance to a unique first char if possible. If firstline is TRUE, the + start of the match is constrained to the first line of a multiline string. + That is, the match must be before or at the first newline. Implement this by + temporarily adjusting end_subject so that we stop scanning at a newline. If + the match fails at the newline, later code breaks this loop. */ + + if (firstline) + { + USPTR t = start_match; + while (t < md->end_subject && !IS_NEWLINE(t)) t++; + end_subject = t; + } + + /* Now test for a unique first byte */ + + if (first_byte >= 0) + { + if (first_byte_caseless) + while (start_match < end_subject && + md->lcc[*start_match] != first_byte) + { NEXTCHAR(start_match); } + else + while (start_match < end_subject && *start_match != first_byte) + { NEXTCHAR(start_match); } + } + + /* Or to just after a linebreak for a multiline match if possible */ + + else if (startline) + { + if (start_match > md->start_subject + start_offset) + { + while (start_match <= end_subject && !WAS_NEWLINE(start_match)) + { NEXTCHAR(start_match); } + + /* If we have just passed a CR and the newline option is ANY or ANYCRLF, + and we are now at a LF, advance the match position by one more character. + */ + + if (start_match[-1] == '\r' && + (md->nltype == NLTYPE_ANY || md->nltype == NLTYPE_ANYCRLF) && + start_match < end_subject && + *start_match == '\n') + start_match++; + } + } + + /* Or to a non-unique first char after study */ + + else if (start_bits != NULL) + { + while (start_match < end_subject) + { + register unsigned int c = *start_match; + if ((start_bits[c/8] & (1 << (c&7))) == 0) + { NEXTCHAR(start_match); } + else break; + } + } + + /* Restore fudged end_subject */ + + end_subject = save_end_subject; + +#ifdef DEBUG /* Sigh. Some compilers never learn. */ + printf(">>>> Match against: "); + pchars(start_match, end_subject - start_match, TRUE, md); + printf("\n"); +#endif + + /* If req_byte is set, we know that that character must appear in the subject + for the match to succeed. If the first character is set, req_byte must be + later in the subject; otherwise the test starts at the match point. This + optimization can save a huge amount of backtracking in patterns with nested + unlimited repeats that aren't going to match. Writing separate code for + cased/caseless versions makes it go faster, as does using an autoincrement + and backing off on a match. + + HOWEVER: when the subject string is very, very long, searching to its end can + take a long time, and give bad performance on quite ordinary patterns. This + showed up when somebody was matching something like /^\d+C/ on a 32-megabyte + string... so we don't do this when the string is sufficiently long. + + ALSO: this processing is disabled when partial matching is requested. + */ + + if (req_byte >= 0 && + end_subject - start_match < REQ_BYTE_MAX && + !md->partial) + { + register USPTR p = start_match + ((first_byte >= 0)? 1 : 0); + + /* We don't need to repeat the search if we haven't yet reached the + place we found it at last time. */ + + if (p > req_byte_ptr) + { + if (req_byte_caseless) + { + while (p < end_subject) + { + register int pp = *p++; + if (pp == req_byte || pp == req_byte2) { p--; break; } + } + } + else + { + while (p < end_subject) + { + if (*p++ == req_byte) { p--; break; } + } + } + + /* If we can't find the required character, break the matching loop, + forcing a match failure. */ + + if (p >= end_subject) + { + rc = MATCH_NOMATCH; + break; + } + + /* If we have found the required character, save the point where we + found it, so that we don't search again next time round the loop if + the start hasn't passed this character yet. */ + + req_byte_ptr = p; + } + } + + /* OK, we can now run the match. */ + + md->start_match_ptr = start_match; + md->match_call_count = 0; + rc = match(start_match, md->start_code, start_match, 2, md, ims, NULL, 0, 0); + + switch(rc) + { + /* NOMATCH and PRUNE advance by one character. THEN at this level acts + exactly like PRUNE. */ + + case MATCH_NOMATCH: + case MATCH_PRUNE: + case MATCH_THEN: + new_start_match = start_match + 1; +#ifdef SUPPORT_UTF8 + if (utf8) + while(new_start_match < end_subject && (*new_start_match & 0xc0) == 0x80) + new_start_match++; +#endif + break; + + /* SKIP passes back the next starting point explicitly. */ + + case MATCH_SKIP: + new_start_match = md->start_match_ptr; + break; + + /* COMMIT disables the bumpalong, but otherwise behaves as NOMATCH. */ + + case MATCH_COMMIT: + rc = MATCH_NOMATCH; + goto ENDLOOP; + + /* Any other return is some kind of error. */ + + default: + goto ENDLOOP; + } + + /* Control reaches here for the various types of "no match at this point" + result. Reset the code to MATCH_NOMATCH for subsequent checking. */ + + rc = MATCH_NOMATCH; + + /* If PCRE_FIRSTLINE is set, the match must happen before or at the first + newline in the subject (though it may continue over the newline). Therefore, + if we have just failed to match, starting at a newline, do not continue. */ + + if (firstline && IS_NEWLINE(start_match)) break; + + /* Advance to new matching position */ + + start_match = new_start_match; + + /* Break the loop if the pattern is anchored or if we have passed the end of + the subject. */ + + if (anchored || start_match > end_subject) break; + + /* If we have just passed a CR and we are now at a LF, and the pattern does + not contain any explicit matches for \r or \n, and the newline option is CRLF + or ANY or ANYCRLF, advance the match position by one more character. */ + + if (start_match[-1] == '\r' && + start_match < end_subject && + *start_match == '\n' && + (re->flags & PCRE_HASCRORLF) == 0 && + (md->nltype == NLTYPE_ANY || + md->nltype == NLTYPE_ANYCRLF || + md->nllen == 2)) + start_match++; + + } /* End of for(;;) "bumpalong" loop */ + +/* ==========================================================================*/ + +/* We reach here when rc is not MATCH_NOMATCH, or if one of the stopping +conditions is true: + +(1) The pattern is anchored or the match was failed by (*COMMIT); + +(2) We are past the end of the subject; + +(3) PCRE_FIRSTLINE is set and we have failed to match at a newline, because + this option requests that a match occur at or before the first newline in + the subject. + +When we have a match and the offset vector is big enough to deal with any +backreferences, captured substring offsets will already be set up. In the case +where we had to get some local store to hold offsets for backreference +processing, copy those that we can. In this case there need not be overflow if +certain parts of the pattern were not used, even though there are more +capturing parentheses than vector slots. */ + +ENDLOOP: + +if (rc == MATCH_MATCH) + { + if (using_temporary_offsets) + { + if (offsetcount >= 4) + { + memcpy(offsets + 2, md->offset_vector + 2, + (offsetcount - 2) * sizeof(int)); + DPRINTF(("Copied offsets from temporary memory\n")); + } + if (md->end_offset_top > offsetcount) md->offset_overflow = TRUE; + DPRINTF(("Freeing temporary memory\n")); + (pcre_free)(md->offset_vector); + } + + /* Set the return code to the number of captured strings, or 0 if there are + too many to fit into the vector. */ + + rc = md->offset_overflow? 0 : md->end_offset_top/2; + + /* If there is space, set up the whole thing as substring 0. The value of + md->start_match_ptr might be modified if \K was encountered on the success + matching path. */ + + if (offsetcount < 2) rc = 0; else + { + offsets[0] = md->start_match_ptr - md->start_subject; + offsets[1] = md->end_match_ptr - md->start_subject; + } + + DPRINTF((">>>> returning %d\n", rc)); + return rc; + } + +/* Control gets here if there has been an error, or if the overall match +attempt has failed at all permitted starting positions. */ + +if (using_temporary_offsets) + { + DPRINTF(("Freeing temporary memory\n")); + (pcre_free)(md->offset_vector); + } + +if (rc != MATCH_NOMATCH) + { + DPRINTF((">>>> error: returning %d\n", rc)); + return rc; + } +else if (md->partial && md->hitend) + { + DPRINTF((">>>> returning PCRE_ERROR_PARTIAL\n")); + return PCRE_ERROR_PARTIAL; + } +else + { + DPRINTF((">>>> returning PCRE_ERROR_NOMATCH\n")); + return PCRE_ERROR_NOMATCH; + } +} + +/* End of pcre_exec.c */ diff --git a/examples/pikapython/pikapython/pikascript-lib/re/pcre_fullinfo.c b/examples/pikapython/pikapython/pikascript-lib/re/pcre_fullinfo.c new file mode 100755 index 00000000..9144f2ec --- /dev/null +++ b/examples/pikapython/pikapython/pikascript-lib/re/pcre_fullinfo.c @@ -0,0 +1,123 @@ + +/* This module contains the external function pcre_fullinfo(), which returns +information about a compiled pattern. */ + + +#include "re_config.h" +#include "pcre_internal.h" + + +/************************************************* +* Return info about compiled pattern * +*************************************************/ + +/* This is a newer "info" function which has an extensible interface so +that additional items can be added compatibly. + +Arguments: + argument_re points to compiled code + extra_data points extra data, or NULL + what what information is required + where where to put the information + +Returns: 0 if data returned, negative on error +*/ + +int +pcre_fullinfo(const pcre *argument_re, const pcre_extra *extra_data, int what, + void *where) +{ +real_pcre internal_re; +pcre_study_data internal_study; +const real_pcre *re = (const real_pcre *)argument_re; +const pcre_study_data *study = NULL; + +if (re == NULL || where == NULL) return PCRE_ERROR_NULL; + +if (extra_data != NULL && (extra_data->flags & PCRE_EXTRA_STUDY_DATA) != 0) + study = (const pcre_study_data *)extra_data->study_data; + +if (re->magic_number != MAGIC_NUMBER) + { + re = _pcre_try_flipped(re, &internal_re, study, &internal_study); + if (re == NULL) return PCRE_ERROR_BADMAGIC; + if (study != NULL) study = &internal_study; + } + +switch (what) + { + case PCRE_INFO_OPTIONS: + *((unsigned long int *)where) = re->options & PUBLIC_OPTIONS; + break; + + case PCRE_INFO_SIZE: + *((size_t *)where) = re->size; + break; + + case PCRE_INFO_STUDYSIZE: + *((size_t *)where) = (study == NULL)? 0 : study->size; + break; + + case PCRE_INFO_CAPTURECOUNT: + *((int *)where) = re->top_bracket; + break; + + case PCRE_INFO_BACKREFMAX: + *((int *)where) = re->top_backref; + break; + + case PCRE_INFO_FIRSTBYTE: + *((int *)where) = + ((re->flags & PCRE_FIRSTSET) != 0)? re->first_byte : + ((re->flags & PCRE_STARTLINE) != 0)? -1 : -2; + break; + + /* Make sure we pass back the pointer to the bit vector in the external + block, not the internal copy (with flipped integer fields). */ + + case PCRE_INFO_FIRSTTABLE: + *((const uschar **)where) = + (study != NULL && (study->options & PCRE_STUDY_MAPPED) != 0)? + ((const pcre_study_data *)extra_data->study_data)->start_bits : NULL; + break; + + case PCRE_INFO_LASTLITERAL: + *((int *)where) = + ((re->flags & PCRE_REQCHSET) != 0)? re->req_byte : -1; + break; + + case PCRE_INFO_NAMEENTRYSIZE: + *((int *)where) = re->name_entry_size; + break; + + case PCRE_INFO_NAMECOUNT: + *((int *)where) = re->name_count; + break; + + case PCRE_INFO_NAMETABLE: + *((const uschar **)where) = (const uschar *)re + re->name_table_offset; + break; + + case PCRE_INFO_DEFAULT_TABLES: + *((const uschar **)where) = (const uschar *)(_pcre_default_tables); + break; + + case PCRE_INFO_OKPARTIAL: + *((int *)where) = (re->flags & PCRE_NOPARTIAL) == 0; + break; + + case PCRE_INFO_JCHANGED: + *((int *)where) = (re->flags & PCRE_JCHANGED) != 0; + break; + + case PCRE_INFO_HASCRORLF: + *((int *)where) = (re->flags & PCRE_HASCRORLF) != 0; + break; + + default: return PCRE_ERROR_BADOPTION; + } + +return 0; +} + +/* End of pcre_fullinfo.c */ diff --git a/examples/pikapython/pikapython/pikascript-lib/re/pcre_globals.c b/examples/pikapython/pikapython/pikascript-lib/re/pcre_globals.c new file mode 100755 index 00000000..02c03906 --- /dev/null +++ b/examples/pikapython/pikapython/pikascript-lib/re/pcre_globals.c @@ -0,0 +1,21 @@ + +/* This module contains global variables that are exported by the PCRE library. +PCRE is thread-clean and doesn't use any global variables in the normal sense. +However, it calls memory allocation and freeing functions via the four +indirections below, and it can optionally do callouts, using the fifth +indirection. These values can be changed by the caller, but are shared between +all threads. However, when compiling for Virtual Pascal, things are done +differently, and global variables are not used (see pcre.in). */ + +#include "re_config.h" +#include "pcre_internal.h" + +#ifndef VPCOMPAT +void *(*pcre_malloc)(size_t) = malloc; +void (*pcre_free)(void *) = free; +void *(*pcre_stack_malloc)(size_t) = malloc; +void (*pcre_stack_free)(void *) = free; +int (*pcre_callout)(pcre_callout_block *) = NULL; +#endif + +/* End of pcre_globals.c */ diff --git a/examples/pikapython/pikapython/pikascript-lib/re/pcre_internal.h b/examples/pikapython/pikapython/pikascript-lib/re/pcre_internal.h new file mode 100755 index 00000000..f75a669b --- /dev/null +++ b/examples/pikapython/pikapython/pikascript-lib/re/pcre_internal.h @@ -0,0 +1,861 @@ + +#ifndef PCRE_INTERNAL_H +#define PCRE_INTERNAL_H + + +#if 0 +#define DEBUG +#endif + +#undef DPRINTF +#ifdef DEBUG +#define DPRINTF(p) printf p +#else +#define DPRINTF(p) +#endif + + +#include +#include +#include +#include +#include +#include +#include +#include + + +#if USHRT_MAX == 65535 + typedef unsigned short pcre_uint16; +#elif UINT_MAX == 65535 + typedef unsigned int pcre_uint16; +#else + #error Cannot determine a type for 16-bit unsigned integers +#endif + +#if UINT_MAX == 4294967295 + typedef unsigned int pcre_uint32; +#elif ULONG_MAX == 4294967295 + typedef unsigned long int pcre_uint32; +#else + #error Cannot determine a type for 32-bit unsigned integers +#endif + + +typedef unsigned char uschar; + + +#define NOTACHAR 0xffffffff + + +#define NLTYPE_FIXED 0 +#define NLTYPE_ANY 1 +#define NLTYPE_ANYCRLF 2 + + +#define IS_NEWLINE(p) \ + ((NLBLOCK->nltype != NLTYPE_FIXED)? \ + ((p) < NLBLOCK->PSEND && \ + _pcre_is_newline((p), NLBLOCK->nltype, NLBLOCK->PSEND, &(NLBLOCK->nllen),\ + utf8)) \ + : \ + ((p) <= NLBLOCK->PSEND - NLBLOCK->nllen && \ + (p)[0] == NLBLOCK->nl[0] && \ + (NLBLOCK->nllen == 1 || (p)[1] == NLBLOCK->nl[1]) \ + ) \ + ) + + +#define WAS_NEWLINE(p) \ + ((NLBLOCK->nltype != NLTYPE_FIXED)? \ + ((p) > NLBLOCK->PSSTART && \ + _pcre_was_newline((p), NLBLOCK->nltype, NLBLOCK->PSSTART, \ + &(NLBLOCK->nllen), utf8)) \ + : \ + ((p) >= NLBLOCK->PSSTART + NLBLOCK->nllen && \ + (p)[-NLBLOCK->nllen] == NLBLOCK->nl[0] && \ + (NLBLOCK->nllen == 1 || (p)[-NLBLOCK->nllen+1] == NLBLOCK->nl[1]) \ + ) \ + ) + + +#ifdef CUSTOM_SUBJECT_PTR +#define PCRE_SPTR CUSTOM_SUBJECT_PTR +#define USPTR CUSTOM_SUBJECT_PTR +#else +#define PCRE_SPTR const char * +#define USPTR const unsigned char * +#endif + + +#include "pcre.h" + + +#ifdef VPCOMPAT +#define strlen(s) _strlen(s) +#define strncmp(s1,s2,m) _strncmp(s1,s2,m) +#define memcmp(s,c,n) _memcmp(s,c,n) +#define memcpy(d,s,n) _memcpy(d,s,n) +#define memmove(d,s,n) _memmove(d,s,n) +#define memset(s,c,n) _memset(s,c,n) +#else + + +#ifndef HAVE_MEMMOVE +#undef memmove +#ifdef HAVE_BCOPY +#define memmove(a, b, c) bcopy(b, a, c) +#else +static void * +pcre_memmove(void *d, const void *s, size_t n) +{ +size_t i; +unsigned char *dest = (unsigned char *)d; +const unsigned char *src = (const unsigned char *)s; +if (dest > src) + { + dest += n; + src += n; + for (i = 0; i < n; ++i) *(--dest) = *(--src); + return (void *)dest; + } +else + { + for (i = 0; i < n; ++i) *dest++ = *src++; + return (void *)(dest - n); + } +} +#define memmove(a, b, c) pcre_memmove(a, b, c) +#endif +#endif +#endif + + +#if LINK_SIZE == 2 + +#define PUT(a,n,d) \ + (a[n] = (d) >> 8), \ + (a[(n)+1] = (d) & 255) + +#define GET(a,n) \ + (((a)[n] << 8) | (a)[(n)+1]) + +#define MAX_PATTERN_SIZE (1 << 16) + + +#elif LINK_SIZE == 3 + +#define PUT(a,n,d) \ + (a[n] = (d) >> 16), \ + (a[(n)+1] = (d) >> 8), \ + (a[(n)+2] = (d) & 255) + +#define GET(a,n) \ + (((a)[n] << 16) | ((a)[(n)+1] << 8) | (a)[(n)+2]) + +#define MAX_PATTERN_SIZE (1 << 24) + + +#elif LINK_SIZE == 4 + +#define PUT(a,n,d) \ + (a[n] = (d) >> 24), \ + (a[(n)+1] = (d) >> 16), \ + (a[(n)+2] = (d) >> 8), \ + (a[(n)+3] = (d) & 255) + +#define GET(a,n) \ + (((a)[n] << 24) | ((a)[(n)+1] << 16) | ((a)[(n)+2] << 8) | (a)[(n)+3]) + +#define MAX_PATTERN_SIZE (1 << 30) + + +#else +#error LINK_SIZE must be either 2, 3, or 4 +#endif + + +#define PUTINC(a,n,d) PUT(a,n,d), a += LINK_SIZE + + +#define PUT2(a,n,d) \ + a[n] = (d) >> 8; \ + a[(n)+1] = (d) & 255 + +#define GET2(a,n) \ + (((a)[n] << 8) | (a)[(n)+1]) + +#define PUT2INC(a,n,d) PUT2(a,n,d), a += 2 + + +#ifndef SUPPORT_UTF8 +#define NEXTCHAR(p) p++; +#define GETCHAR(c, eptr) c = *eptr; +#define GETCHARTEST(c, eptr) c = *eptr; +#define GETCHARINC(c, eptr) c = *eptr++; +#define GETCHARINCTEST(c, eptr) c = *eptr++; +#define GETCHARLEN(c, eptr, len) c = *eptr; + + +#else + + +#define NEXTCHAR(p) \ + p++; \ + if (utf8) { while((*p & 0xc0) == 0x80) p++; } + + +#define GETCHAR(c, eptr) \ + c = *eptr; \ + if (c >= 0xc0) \ + { \ + int gcii; \ + int gcaa = _pcre_utf8_table4[c & 0x3f]; \ + int gcss = 6*gcaa; \ + c = (c & _pcre_utf8_table3[gcaa]) << gcss; \ + for (gcii = 1; gcii <= gcaa; gcii++) \ + { \ + gcss -= 6; \ + c |= (eptr[gcii] & 0x3f) << gcss; \ + } \ + } + + +#define GETCHARTEST(c, eptr) \ + c = *eptr; \ + if (utf8 && c >= 0xc0) \ + { \ + int gcii; \ + int gcaa = _pcre_utf8_table4[c & 0x3f]; \ + int gcss = 6*gcaa; \ + c = (c & _pcre_utf8_table3[gcaa]) << gcss; \ + for (gcii = 1; gcii <= gcaa; gcii++) \ + { \ + gcss -= 6; \ + c |= (eptr[gcii] & 0x3f) << gcss; \ + } \ + } + + +#define GETCHARINC(c, eptr) \ + c = *eptr++; \ + if (c >= 0xc0) \ + { \ + int gcaa = _pcre_utf8_table4[c & 0x3f]; \ + int gcss = 6*gcaa; \ + c = (c & _pcre_utf8_table3[gcaa]) << gcss; \ + while (gcaa-- > 0) \ + { \ + gcss -= 6; \ + c |= (*eptr++ & 0x3f) << gcss; \ + } \ + } + + +#define GETCHARINCTEST(c, eptr) \ + c = *eptr++; \ + if (utf8 && c >= 0xc0) \ + { \ + int gcaa = _pcre_utf8_table4[c & 0x3f]; \ + int gcss = 6*gcaa; \ + c = (c & _pcre_utf8_table3[gcaa]) << gcss; \ + while (gcaa-- > 0) \ + { \ + gcss -= 6; \ + c |= (*eptr++ & 0x3f) << gcss; \ + } \ + } + + +#define GETCHARLEN(c, eptr, len) \ + c = *eptr; \ + if (c >= 0xc0) \ + { \ + int gcii; \ + int gcaa = _pcre_utf8_table4[c & 0x3f]; \ + int gcss = 6*gcaa; \ + c = (c & _pcre_utf8_table3[gcaa]) << gcss; \ + for (gcii = 1; gcii <= gcaa; gcii++) \ + { \ + gcss -= 6; \ + c |= (eptr[gcii] & 0x3f) << gcss; \ + } \ + len += gcaa; \ + } + + +#define BACKCHAR(eptr) while((*eptr & 0xc0) == 0x80) eptr-- + +#endif + + +#ifndef offsetof +#define offsetof(p_type,field) ((size_t)&(((p_type *)0)->field)) +#endif + + +#define PCRE_IMS (PCRE_CASELESS|PCRE_MULTILINE|PCRE_DOTALL) + + +#define PCRE_NOPARTIAL 0x0001 +#define PCRE_FIRSTSET 0x0002 +#define PCRE_REQCHSET 0x0004 +#define PCRE_STARTLINE 0x0008 +#define PCRE_JCHANGED 0x0010 +#define PCRE_HASCRORLF 0x0020 + + +#define PCRE_STUDY_MAPPED 0x01 + + +#define PCRE_NEWLINE_BITS (PCRE_NEWLINE_CR|PCRE_NEWLINE_LF|PCRE_NEWLINE_ANY| \ + PCRE_NEWLINE_ANYCRLF) + +#define PUBLIC_OPTIONS \ + (PCRE_CASELESS|PCRE_EXTENDED|PCRE_ANCHORED|PCRE_MULTILINE| \ + PCRE_DOTALL|PCRE_DOLLAR_ENDONLY|PCRE_EXTRA|PCRE_UNGREEDY|PCRE_UTF8| \ + PCRE_NO_AUTO_CAPTURE|PCRE_NO_UTF8_CHECK|PCRE_AUTO_CALLOUT|PCRE_FIRSTLINE| \ + PCRE_DUPNAMES|PCRE_NEWLINE_BITS|PCRE_BSR_ANYCRLF|PCRE_BSR_UNICODE) + +#define PUBLIC_EXEC_OPTIONS \ + (PCRE_ANCHORED|PCRE_NOTBOL|PCRE_NOTEOL|PCRE_NOTEMPTY|PCRE_NO_UTF8_CHECK| \ + PCRE_PARTIAL|PCRE_NEWLINE_BITS|PCRE_BSR_ANYCRLF|PCRE_BSR_UNICODE) + +#define PUBLIC_DFA_EXEC_OPTIONS \ + (PCRE_ANCHORED|PCRE_NOTBOL|PCRE_NOTEOL|PCRE_NOTEMPTY|PCRE_NO_UTF8_CHECK| \ + PCRE_PARTIAL|PCRE_DFA_SHORTEST|PCRE_DFA_RESTART|PCRE_NEWLINE_BITS| \ + PCRE_BSR_ANYCRLF|PCRE_BSR_UNICODE) + +#define PUBLIC_STUDY_OPTIONS 0 + + +#define MAGIC_NUMBER 0x50435245UL + + +#define REQ_UNSET (-2) +#define REQ_NONE (-1) + + +#define REQ_BYTE_MAX 1000 + +/* Flags added to firstbyte or reqbyte; a "non-literal" item is either a +variable-length repeat, or a anything other than literal characters. */ + +#define REQ_CASELESS 0x0100 +#define REQ_VARY 0x0200 + + +typedef int BOOL; + +#define FALSE 0 +#define TRUE 1 + + +#ifndef ESC_e +#define ESC_e 27 +#endif + +#ifndef ESC_f +#define ESC_f '\f' +#endif + +#ifndef ESC_n +#define ESC_n '\n' +#endif + +#ifndef ESC_r +#define ESC_r '\r' +#endif + + +#ifndef ESC_tee +#define ESC_tee '\t' +#endif + + +#define PT_ANY 0 +#define PT_LAMP 1 +#define PT_GC 2 +#define PT_PC 3 +#define PT_SC 4 + + +#define XCL_NOT 0x01 +#define XCL_MAP 0x02 + +#define XCL_END 0 +#define XCL_SINGLE 1 +#define XCL_RANGE 2 +#define XCL_PROP 3 +#define XCL_NOTPROP 4 + +/* These are escaped items that aren't just an encoding of a particular data +value such as \n. They must have non-zero values, as check_escape() returns +their negation. Also, they must appear in the same order as in the opcode +definitions below, up to ESC_z. There's a dummy for OP_ANY because it +corresponds to "." rather than an escape sequence. The final one must be +ESC_REF as subsequent values are used for backreferences (\1, \2, \3, etc). +There are two tests in the code for an escape greater than ESC_b and less than +ESC_Z to detect the types that may be repeated. These are the types that +consume characters. If any new escapes are put in between that don't consume a +character, that code will have to change. */ + +enum { ESC_A = 1, ESC_G, ESC_K, ESC_B, ESC_b, ESC_D, ESC_d, ESC_S, ESC_s, + ESC_W, ESC_w, ESC_dum1, ESC_C, ESC_P, ESC_p, ESC_R, ESC_H, ESC_h, + ESC_V, ESC_v, ESC_X, ESC_Z, ESC_z, ESC_E, ESC_Q, ESC_k, ESC_REF }; + + +/* Opcode table: Starting from 1 (i.e. after OP_END), the values up to +OP_EOD must correspond in order to the list of escapes immediately above. + +*** NOTE NOTE NOTE *** Whenever this list is updated, the two macro definitions +that follow must also be updated to match. There is also a table called +"coptable" in pcre_dfa_exec.c that must be updated. */ + +enum { + OP_END, + + + + OP_SOD, + OP_SOM, + OP_SET_SOM, + OP_NOT_WORD_BOUNDARY, + OP_WORD_BOUNDARY, + OP_NOT_DIGIT, + OP_DIGIT, + OP_NOT_WHITESPACE, + OP_WHITESPACE, + OP_NOT_WORDCHAR, + OP_WORDCHAR, + OP_ANY, + OP_ANYBYTE, + OP_NOTPROP, + OP_PROP, + OP_ANYNL, + OP_NOT_HSPACE, + OP_HSPACE, + OP_NOT_VSPACE, + OP_VSPACE, + OP_EXTUNI, + OP_EODN, + OP_EOD, + + OP_OPT, + OP_CIRC, + OP_DOLL, + OP_CHAR, + OP_CHARNC, + OP_NOT, + + OP_STAR, + OP_MINSTAR, + OP_PLUS, + OP_MINPLUS, + OP_QUERY, + OP_MINQUERY, + + OP_UPTO, + OP_MINUPTO, + OP_EXACT, + + OP_POSSTAR, + OP_POSPLUS, + OP_POSQUERY, + OP_POSUPTO, + + OP_NOTSTAR, + OP_NOTMINSTAR, + OP_NOTPLUS, + OP_NOTMINPLUS, + OP_NOTQUERY, + OP_NOTMINQUERY, + + OP_NOTUPTO, + OP_NOTMINUPTO, + OP_NOTEXACT, + + OP_NOTPOSSTAR, + OP_NOTPOSPLUS, + OP_NOTPOSQUERY, + OP_NOTPOSUPTO, + + OP_TYPESTAR, + OP_TYPEMINSTAR, + OP_TYPEPLUS, + OP_TYPEMINPLUS, + OP_TYPEQUERY, + OP_TYPEMINQUERY, + + OP_TYPEUPTO, + OP_TYPEMINUPTO, + OP_TYPEEXACT, + + OP_TYPEPOSSTAR, + OP_TYPEPOSPLUS, + OP_TYPEPOSQUERY, + OP_TYPEPOSUPTO, + + OP_CRSTAR, + OP_CRMINSTAR, + OP_CRPLUS, + OP_CRMINPLUS, + OP_CRQUERY, + OP_CRMINQUERY, + OP_CRRANGE, + OP_CRMINRANGE, + + OP_CLASS, + OP_NCLASS, /* 78 Same, but the bitmap was created from a negative + class - the difference is relevant only when a UTF-8 + character > 255 is encountered. */ + + OP_XCLASS, + + OP_REF, + OP_RECURSE, + OP_CALLOUT, + + OP_ALT, + OP_KET, + OP_KETRMAX, + OP_KETRMIN, + + + + OP_ASSERT, + OP_ASSERT_NOT, + OP_ASSERTBACK, + OP_ASSERTBACK_NOT, + OP_REVERSE, + + /* ONCE, BRA, CBRA, and COND must come after the assertions, with ONCE first, + as there's a test for >= ONCE for a subpattern that isn't an assertion. */ + + OP_ONCE, + OP_BRA, + OP_CBRA, + OP_COND, + + /* These three must follow the previous three, in the same order. There's a + check for >= SBRA to distinguish the two sets. */ + + OP_SBRA, + OP_SCBRA, + OP_SCOND, + + OP_CREF, + OP_RREF, + OP_DEF, + + OP_BRAZERO, + OP_BRAMINZERO, + + + + OP_PRUNE, + OP_SKIP, + OP_THEN, + OP_COMMIT, + + + + OP_FAIL, + OP_ACCEPT +}; + + +#define OP_NAME_LIST \ + "End", "\\A", "\\G", "\\K", "\\B", "\\b", "\\D", "\\d", \ + "\\S", "\\s", "\\W", "\\w", "Any", "Anybyte", \ + "notprop", "prop", "\\R", "\\H", "\\h", "\\V", "\\v", \ + "extuni", "\\Z", "\\z", \ + "Opt", "^", "$", "char", "charnc", "not", \ + "*", "*?", "+", "+?", "?", "??", "{", "{", "{", \ + "*+","++", "?+", "{", \ + "*", "*?", "+", "+?", "?", "??", "{", "{", "{", \ + "*+","++", "?+", "{", \ + "*", "*?", "+", "+?", "?", "??", "{", "{", "{", \ + "*+","++", "?+", "{", \ + "*", "*?", "+", "+?", "?", "??", "{", "{", \ + "class", "nclass", "xclass", "Ref", "Recurse", "Callout", \ + "Alt", "Ket", "KetRmax", "KetRmin", "Assert", "Assert not", \ + "AssertB", "AssertB not", "Reverse", \ + "Once", "Bra", "CBra", "Cond", "SBra", "SCBra", "SCond", \ + "Cond ref", "Cond rec", "Cond def", "Brazero", "Braminzero", \ + "*PRUNE", "*SKIP", "*THEN", "*COMMIT", "*FAIL", "*ACCEPT" + + +#define OP_LENGTHS \ + 1, \ + 1, 1, 1, 1, 1, \ + 1, 1, 1, 1, 1, 1, \ + 1, 1, \ + 3, 3, 1, \ + 1, 1, 1, 1, 1, \ + 1, 1, 2, 1, 1, \ + 2, \ + 2, \ + 2, \ + \ + 2, 2, 2, 2, 2, 2, \ + 4, 4, 4, \ + 2, 2, 2, 4, \ + \ + 2, 2, 2, 2, 2, 2, \ + 4, 4, 4, \ + 2, 2, 2, 4, \ + \ + 2, 2, 2, 2, 2, 2, \ + 4, 4, 4, \ + 2, 2, 2, 4, \ + \ + 1, 1, 1, 1, 1, 1, \ + 5, 5, \ + 33, \ + 33, \ + 0, \ + 3, \ + 1+LINK_SIZE, \ + 2+2*LINK_SIZE, \ + 1+LINK_SIZE, \ + 1+LINK_SIZE, \ + 1+LINK_SIZE, \ + 1+LINK_SIZE, \ + 1+LINK_SIZE, \ + 1+LINK_SIZE, \ + 1+LINK_SIZE, \ + 1+LINK_SIZE, \ + 1+LINK_SIZE, \ + 1+LINK_SIZE, \ + 1+LINK_SIZE, \ + 3+LINK_SIZE, \ + 1+LINK_SIZE, \ + 1+LINK_SIZE, \ + 3+LINK_SIZE, \ + 1+LINK_SIZE, \ + 3, \ + 3, \ + 1, \ + 1, 1, \ + 1, 1, 1, 1, \ + 1, 1 + + +#define RREF_ANY 0xffff + + +enum { ERR0, ERR1, ERR2, ERR3, ERR4, ERR5, ERR6, ERR7, ERR8, ERR9, + ERR10, ERR11, ERR12, ERR13, ERR14, ERR15, ERR16, ERR17, ERR18, ERR19, + ERR20, ERR21, ERR22, ERR23, ERR24, ERR25, ERR26, ERR27, ERR28, ERR29, + ERR30, ERR31, ERR32, ERR33, ERR34, ERR35, ERR36, ERR37, ERR38, ERR39, + ERR40, ERR41, ERR42, ERR43, ERR44, ERR45, ERR46, ERR47, ERR48, ERR49, + ERR50, ERR51, ERR52, ERR53, ERR54, ERR55, ERR56, ERR57, ERR58, ERR59, + ERR60, ERR61, ERR62, ERR63 }; + +/* The real format of the start of the pcre block; the index of names and the +code vector run on as long as necessary after the end. We store an explicit +offset to the name table so that if a regex is compiled on one host, saved, and +then run on another where the size of pointers is different, all might still +be well. For the case of compiled-on-4 and run-on-8, we include an extra +pointer that is always NULL. For future-proofing, a few dummy fields were +originally included - even though you can never get this planning right - but +there is only one left now. + +NOTE NOTE NOTE: +Because people can now save and re-use compiled patterns, any additions to this +structure should be made at the end, and something earlier (e.g. a new +flag in the options or one of the dummy fields) should indicate that the new +fields are present. Currently PCRE always sets the dummy fields to zero. +NOTE NOTE NOTE: +*/ + +typedef struct real_pcre { + pcre_uint32 magic_number; + pcre_uint32 size; + pcre_uint32 options; + pcre_uint16 flags; + pcre_uint16 dummy1; + pcre_uint16 top_bracket; + pcre_uint16 top_backref; + pcre_uint16 first_byte; + pcre_uint16 req_byte; + pcre_uint16 name_table_offset; + pcre_uint16 name_entry_size; + pcre_uint16 name_count; + pcre_uint16 ref_count; + + const unsigned char *tables; + const unsigned char *nullpad; +} real_pcre; + + +typedef struct pcre_study_data { + pcre_uint32 size; + pcre_uint32 options; + uschar start_bits[32]; +} pcre_study_data; + + +typedef struct compile_data { + const uschar *lcc; + const uschar *fcc; + const uschar *cbits; + const uschar *ctypes; + const uschar *start_workspace; + const uschar *start_code; + const uschar *start_pattern; + const uschar *end_pattern; + uschar *hwm; + uschar *name_table; + int names_found; + int name_entry_size; + int bracount; + int final_bracount; + int top_backref; + unsigned int backref_map; + int external_options; + int external_flags; + int req_varyopt; + BOOL had_accept; + int nltype; + int nllen; + uschar nl[4]; +} compile_data; + + +typedef struct branch_chain { + struct branch_chain *outer; + uschar *current; +} branch_chain; + + +typedef struct recursion_info { + struct recursion_info *prevrec; + int group_num; + const uschar *after_call; + USPTR save_start; + int *offset_save; + int saved_max; +} recursion_info; + + +typedef struct eptrblock { + struct eptrblock *epb_prev; + USPTR epb_saved_eptr; +} eptrblock; + + +typedef struct match_data { + unsigned long int match_call_count; + unsigned long int match_limit; + unsigned long int match_limit_recursion; + int *offset_vector; + int offset_end; + int offset_max; + int nltype; + int nllen; + uschar nl[4]; + const uschar *lcc; + const uschar *ctypes; + BOOL offset_overflow; + BOOL notbol; + BOOL noteol; + BOOL utf8; + BOOL endonly; + BOOL notempty; + BOOL partial; + BOOL hitend; + BOOL bsr_anycrlf; + const uschar *start_code; + USPTR start_subject; + USPTR end_subject; + USPTR start_match_ptr; + USPTR end_match_ptr; + int end_offset_top; + int capture_last; + int start_offset; + eptrblock *eptrchain; + int eptrn; + recursion_info *recursive; + void *callout_data; +} match_data; + + +typedef struct dfa_match_data { + const uschar *start_code; + const uschar *start_subject; + const uschar *end_subject; + const uschar *tables; + int moptions; + int poptions; + int nltype; + int nllen; + uschar nl[4]; + void *callout_data; +} dfa_match_data; + + +#define ctype_space 0x01 +#define ctype_letter 0x02 +#define ctype_digit 0x04 +#define ctype_xdigit 0x08 +#define ctype_word 0x10 +#define ctype_meta 0x80 + + +#define cbit_space 0 +#define cbit_xdigit 32 +#define cbit_digit 64 +#define cbit_upper 96 +#define cbit_lower 128 +#define cbit_word 160 +#define cbit_graph 192 +#define cbit_print 224 +#define cbit_punct 256 +#define cbit_cntrl 288 +#define cbit_length 320 + + +#define lcc_offset 0 +#define fcc_offset 256 +#define cbits_offset 512 +#define ctypes_offset (cbits_offset + cbit_length) +#define tables_length (ctypes_offset + 256) + + +typedef struct { + pcre_uint16 name_offset; + pcre_uint16 type; + pcre_uint16 value; +} ucp_type_table; + + +extern const int _pcre_utf8_table1[]; +extern const int _pcre_utf8_table2[]; +extern const int _pcre_utf8_table3[]; +extern const uschar _pcre_utf8_table4[]; + +extern const int _pcre_utf8_table1_size; + +extern const ucp_type_table _pcre_utt[]; +extern const int _pcre_utt_size; + +extern const uschar _pcre_default_tables[]; + +extern const uschar _pcre_OP_lengths[]; + + +extern BOOL _pcre_is_newline(const uschar *, int, const uschar *, + int *, BOOL); +extern int _pcre_ord2utf8(int, uschar *); +extern real_pcre *_pcre_try_flipped(const real_pcre *, real_pcre *, + const pcre_study_data *, pcre_study_data *); +extern int _pcre_valid_utf8(const uschar *, int); +extern BOOL _pcre_was_newline(const uschar *, int, const uschar *, + int *, BOOL); +extern BOOL _pcre_xclass(int, const uschar *); + +#endif + + diff --git a/examples/pikapython/pikapython/pikascript-lib/re/pcre_newline.c b/examples/pikapython/pikapython/pikascript-lib/re/pcre_newline.c new file mode 100755 index 00000000..38170598 --- /dev/null +++ b/examples/pikapython/pikapython/pikascript-lib/re/pcre_newline.c @@ -0,0 +1,112 @@ +#include "re_config.h" +#include "pcre_internal.h" + + + +/************************************************* +* Check for newline at given position * +*************************************************/ + +/* It is guaranteed that the initial value of ptr is less than the end of the +string that is being processed. + +Arguments: + ptr pointer to possible newline + type the newline type + endptr pointer to the end of the string + lenptr where to return the length + utf8 TRUE if in utf8 mode + +Returns: TRUE or FALSE +*/ + +BOOL +_pcre_is_newline(const uschar *ptr, int type, const uschar *endptr, + int *lenptr, BOOL utf8) +{ +int c; +if (utf8) { GETCHAR(c, ptr); } else c = *ptr; + +if (type == NLTYPE_ANYCRLF) switch(c) + { + case 0x000a: *lenptr = 1; return TRUE; /* LF */ + case 0x000d: *lenptr = (ptr < endptr - 1 && ptr[1] == 0x0a)? 2 : 1; + return TRUE; /* CR */ + default: return FALSE; + } + +/* NLTYPE_ANY */ + +else switch(c) + { + case 0x000a: /* LF */ + case 0x000b: /* VT */ + case 0x000c: *lenptr = 1; return TRUE; /* FF */ + case 0x000d: *lenptr = (ptr < endptr - 1 && ptr[1] == 0x0a)? 2 : 1; + return TRUE; /* CR */ + case 0x0085: *lenptr = utf8? 2 : 1; return TRUE; /* NEL */ + case 0x2028: /* LS */ + case 0x2029: *lenptr = 3; return TRUE; /* PS */ + default: return FALSE; + } +} + + + +/************************************************* +* Check for newline at previous position * +*************************************************/ + +/* It is guaranteed that the initial value of ptr is greater than the start of +the string that is being processed. + +Arguments: + ptr pointer to possible newline + type the newline type + startptr pointer to the start of the string + lenptr where to return the length + utf8 TRUE if in utf8 mode + +Returns: TRUE or FALSE +*/ + +BOOL +_pcre_was_newline(const uschar *ptr, int type, const uschar *startptr, + int *lenptr, BOOL utf8) +{ +int c; +ptr--; +#ifdef SUPPORT_UTF8 +if (utf8) + { + BACKCHAR(ptr); + GETCHAR(c, ptr); + } +else c = *ptr; +#else /* no UTF-8 support */ +c = *ptr; +#endif /* SUPPORT_UTF8 */ + +if (type == NLTYPE_ANYCRLF) switch(c) + { + case 0x000a: *lenptr = (ptr > startptr && ptr[-1] == 0x0d)? 2 : 1; + return TRUE; /* LF */ + case 0x000d: *lenptr = 1; return TRUE; /* CR */ + default: return FALSE; + } + +else switch(c) + { + case 0x000a: *lenptr = (ptr > startptr && ptr[-1] == 0x0d)? 2 : 1; + return TRUE; /* LF */ + case 0x000b: /* VT */ + case 0x000c: /* FF */ + case 0x000d: *lenptr = 1; return TRUE; /* CR */ + case 0x0085: *lenptr = utf8? 2 : 1; return TRUE; /* NEL */ + case 0x2028: /* LS */ + case 0x2029: *lenptr = 3; return TRUE; /* PS */ + default: return FALSE; + } +} + +/* End of pcre_newline.c */ diff --git a/examples/pikapython/pikapython/pikascript-lib/re/pcre_ord2utf8.c b/examples/pikapython/pikapython/pikascript-lib/re/pcre_ord2utf8.c new file mode 100755 index 00000000..ace40064 --- /dev/null +++ b/examples/pikapython/pikapython/pikascript-lib/re/pcre_ord2utf8.c @@ -0,0 +1,39 @@ +#include "re_config.h" +#include "pcre_internal.h" + + +/************************************************* +* Convert character value to UTF-8 * +*************************************************/ + +/* This function takes an integer value in the range 0 - 0x7fffffff +and encodes it as a UTF-8 character in 0 to 6 bytes. + +Arguments: + cvalue the character value + buffer pointer to buffer for result - at least 6 bytes long + +Returns: number of characters placed in the buffer +*/ + +int +_pcre_ord2utf8(int cvalue, uschar *buffer) +{ +#ifdef SUPPORT_UTF8 +register int i, j; +for (i = 0; i < _pcre_utf8_table1_size; i++) + if (cvalue <= _pcre_utf8_table1[i]) break; +buffer += i; +for (j = i; j > 0; j--) + { + *buffer-- = 0x80 | (cvalue & 0x3f); + cvalue >>= 6; + } +*buffer = _pcre_utf8_table2[i] | cvalue; +return i + 1; +#else +return 0; /* Keep compiler happy; this function won't ever be */ +#endif /* called when SUPPORT_UTF8 is not defined. */ +} + +/* End of pcre_ord2utf8.c */ diff --git a/examples/pikapython/pikapython/pikascript-lib/re/pcre_tables.c b/examples/pikapython/pikapython/pikascript-lib/re/pcre_tables.c new file mode 100755 index 00000000..b7bd9fb5 --- /dev/null +++ b/examples/pikapython/pikapython/pikascript-lib/re/pcre_tables.c @@ -0,0 +1,41 @@ + +#include "re_config.h" +#include "pcre_internal.h" + + +/* Table of sizes for the fixed-length opcodes. It's defined in a macro so that +the definition is next to the definition of the opcodes in pcre_internal.h. */ + +const uschar _pcre_OP_lengths[] = { OP_LENGTHS }; + + + +/************************************************* +* Tables for UTF-8 support * +*************************************************/ + +/* These are the breakpoints for different numbers of bytes in a UTF-8 +character. */ + +#ifdef SUPPORT_UTF8 + +const int _pcre_utf8_table1[] = + { 0x7f, 0x7ff, 0xffff, 0x1fffff, 0x3ffffff, 0x7fffffff}; + +const int _pcre_utf8_table1_size = sizeof(_pcre_utf8_table1)/sizeof(int); + +/* These are the indicator bits and the mask for the data bits to set in the +first byte of a character, indexed by the number of additional bytes. */ + +const int _pcre_utf8_table2[] = { 0, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc}; +const int _pcre_utf8_table3[] = { 0xff, 0x1f, 0x0f, 0x07, 0x03, 0x01}; + +/* Table of the number of extra bytes, indexed by the first byte masked with +0x3f. The highest number for a valid UTF-8 first byte is in fact 0x3d. */ + +const uschar _pcre_utf8_table4[] = { + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 3,3,3,3,3,3,3,3,4,4,4,4,5,5,5,5 }; +#endif diff --git a/examples/pikapython/pikapython/pikascript-lib/re/pcre_try_flipped.c b/examples/pikapython/pikapython/pikascript-lib/re/pcre_try_flipped.c new file mode 100755 index 00000000..a60506d2 --- /dev/null +++ b/examples/pikapython/pikapython/pikascript-lib/re/pcre_try_flipped.c @@ -0,0 +1,90 @@ + +#include "re_config.h" +#include "pcre_internal.h" + + +/************************************************* +* Flip bytes in an integer * +*************************************************/ + +/* This function is called when the magic number in a regex doesn't match, in +order to flip its bytes to see if we are dealing with a pattern that was +compiled on a host of different endianness. If so, this function is used to +flip other byte values. + +Arguments: + value the number to flip + n the number of bytes to flip (assumed to be 2 or 4) + +Returns: the flipped value +*/ + +static unsigned long int +byteflip(unsigned long int value, int n) +{ +if (n == 2) return ((value & 0x00ff) << 8) | ((value & 0xff00) >> 8); +return ((value & 0x000000ff) << 24) | + ((value & 0x0000ff00) << 8) | + ((value & 0x00ff0000) >> 8) | + ((value & 0xff000000) >> 24); +} + + + +/************************************************* +* Test for a byte-flipped compiled regex * +*************************************************/ + +/* This function is called from pcre_exec(), pcre_dfa_exec(), and also from +pcre_fullinfo(). Its job is to test whether the regex is byte-flipped - that +is, it was compiled on a system of opposite endianness. The function is called +only when the native MAGIC_NUMBER test fails. If the regex is indeed flipped, +we flip all the relevant values into a different data block, and return it. + +Arguments: + re points to the regex + study points to study data, or NULL + internal_re points to a new regex block + internal_study points to a new study block + +Returns: the new block if is is indeed a byte-flipped regex + NULL if it is not +*/ + +real_pcre * +_pcre_try_flipped(const real_pcre *re, real_pcre *internal_re, + const pcre_study_data *study, pcre_study_data *internal_study) +{ +if (byteflip(re->magic_number, sizeof(re->magic_number)) != MAGIC_NUMBER) + return NULL; + +*internal_re = *re; /* To copy other fields */ +internal_re->size = byteflip(re->size, sizeof(re->size)); +internal_re->options = byteflip(re->options, sizeof(re->options)); +internal_re->flags = (pcre_uint16)byteflip(re->flags, sizeof(re->flags)); +internal_re->top_bracket = + (pcre_uint16)byteflip(re->top_bracket, sizeof(re->top_bracket)); +internal_re->top_backref = + (pcre_uint16)byteflip(re->top_backref, sizeof(re->top_backref)); +internal_re->first_byte = + (pcre_uint16)byteflip(re->first_byte, sizeof(re->first_byte)); +internal_re->req_byte = + (pcre_uint16)byteflip(re->req_byte, sizeof(re->req_byte)); +internal_re->name_table_offset = + (pcre_uint16)byteflip(re->name_table_offset, sizeof(re->name_table_offset)); +internal_re->name_entry_size = + (pcre_uint16)byteflip(re->name_entry_size, sizeof(re->name_entry_size)); +internal_re->name_count = + (pcre_uint16)byteflip(re->name_count, sizeof(re->name_count)); + +if (study != NULL) + { + *internal_study = *study; /* To copy other fields */ + internal_study->size = byteflip(study->size, sizeof(study->size)); + internal_study->options = byteflip(study->options, sizeof(study->options)); + } + +return internal_re; +} + +/* End of pcre_tryflipped.c */ diff --git a/examples/pikapython/pikapython/pikascript-lib/re/pcre_valid_utf8.c b/examples/pikapython/pikapython/pikascript-lib/re/pcre_valid_utf8.c new file mode 100755 index 00000000..0755e4aa --- /dev/null +++ b/examples/pikapython/pikapython/pikascript-lib/re/pcre_valid_utf8.c @@ -0,0 +1,116 @@ +#include +#include "re_config.h" +#include "pcre_internal.h" + + +/************************************************* +* Validate a UTF-8 string * +*************************************************/ + +/* This function is called (optionally) at the start of compile or match, to +validate that a supposed UTF-8 string is actually valid. The early check means +that subsequent code can assume it is dealing with a valid string. The check +can be turned off for maximum performance, but the consequences of supplying +an invalid string are then undefined. + +Originally, this function checked according to RFC 2279, allowing for values in +the range 0 to 0x7fffffff, up to 6 bytes long, but ensuring that they were in +the canonical format. Once somebody had pointed out RFC 3629 to me (it +obsoletes 2279), additional restrictions were applied. The values are now +limited to be between 0 and 0x0010ffff, no more than 4 bytes long, and the +subrange 0xd000 to 0xdfff is excluded. + +Arguments: + string points to the string + length length of string, or -1 if the string is zero-terminated + +Returns: < 0 if the string is a valid UTF-8 string + >= 0 otherwise; the value is the offset of the bad byte +*/ + +int +_pcre_valid_utf8(const uschar *string, int length) +{ +#ifdef SUPPORT_UTF8 +register const uschar *p; + +if (length < 0) + { + for (p = string; *p != 0; p++); + length = (uintptr_t)p - (uintptr_t)string; + } + +for (p = string; length-- > 0; p++) + { + register int ab; + register int c = *p; + if (c < 128) continue; + if (c < 0xc0) return (uintptr_t)p - (uintptr_t)string; + ab = _pcre_utf8_table4[c & 0x3f]; /* Number of additional bytes */ + if (length < ab || ab > 3) return (uintptr_t)p - (uintptr_t)string; + length -= ab; + + /* Check top bits in the second byte */ + if ((*(++p) & 0xc0) != 0x80) return (uintptr_t)p - (uintptr_t)string; + + /* Check for overlong sequences for each different length, and for the + excluded range 0xd000 to 0xdfff. */ + + switch (ab) + { + /* Check for xx00 000x (overlong sequence) */ + + case 1: + if ((c & 0x3e) == 0) return (uintptr_t)p - (uintptr_t)string; + continue; /* We know there aren't any more bytes to check */ + + /* Check for 1110 0000, xx0x xxxx (overlong sequence) or + 1110 1101, 1010 xxxx (0xd000 - 0xdfff) */ + + case 2: + if ((c == 0xe0 && (*p & 0x20) == 0) || + (c == 0xed && *p >= 0xa0)) + return (uintptr_t)p - (uintptr_t)string; + break; + + /* Check for 1111 0000, xx00 xxxx (overlong sequence) or + greater than 0x0010ffff (f4 8f bf bf) */ + + case 3: + if ((c == 0xf0 && (*p & 0x30) == 0) || + (c > 0xf4 ) || + (c == 0xf4 && *p > 0x8f)) + return (uintptr_t)p - (uintptr_t)string; + break; + +#if 0 + /* These cases can no longer occur, as we restrict to a maximum of four + bytes nowadays. Leave the code here in case we ever want to add an option + for longer sequences. */ + + /* Check for 1111 1000, xx00 0xxx */ + case 4: + if (c == 0xf8 && (*p & 0x38) == 0) return (uintptr_t)p - (uintptr_t)string; + break; + + /* Check for leading 0xfe or 0xff, and then for 1111 1100, xx00 00xx */ + case 5: + if (c == 0xfe || c == 0xff || + (c == 0xfc && (*p & 0x3c) == 0)) return (uintptr_t)p - (uintptr_t)string; + break; +#endif + + } + + /* Check for valid bytes after the 2nd, if any; all must start 10 */ + while (--ab > 0) + { + if ((*(++p) & 0xc0) != 0x80) return (uintptr_t)p - (uintptr_t)string; + } + } +#endif + +return -1; +} + +/* End of pcre_valid_utf8.c */ diff --git a/examples/pikapython/pikapython/pikascript-lib/re/pcre_xclass.c b/examples/pikapython/pikapython/pikascript-lib/re/pcre_xclass.c new file mode 100755 index 00000000..39184a62 --- /dev/null +++ b/examples/pikapython/pikapython/pikascript-lib/re/pcre_xclass.c @@ -0,0 +1,101 @@ + +#include "re_config.h" +#include "pcre_internal.h" + + +/************************************************* +* Match character against an XCLASS * +*************************************************/ + +/* This function is called to match a character against an extended class that +might contain values > 255. + +Arguments: + c the character + data points to the flag byte of the XCLASS data + +Returns: TRUE if character matches, else FALSE +*/ + +BOOL +_pcre_xclass(int c, const uschar *data) +{ +int t; +BOOL negated = (*data & XCL_NOT) != 0; + +/* Character values < 256 are matched against a bitmap, if one is present. If +not, we still carry on, because there may be ranges that start below 256 in the +additional data. */ + +if (c < 256) + { + if ((*data & XCL_MAP) != 0 && (data[1 + c/8] & (1 << (c&7))) != 0) + return !negated; /* char found */ + } + +/* First skip the bit map if present. Then match against the list of Unicode +properties or large chars or ranges that end with a large char. We won't ever +encounter XCL_PROP or XCL_NOTPROP when UCP support is not compiled. */ + +if ((*data++ & XCL_MAP) != 0) data += 32; + +while ((t = *data++) != XCL_END) + { + int x, y; + if (t == XCL_SINGLE) + { + GETCHARINC(x, data); + if (c == x) return !negated; + } + else if (t == XCL_RANGE) + { + GETCHARINC(x, data); + GETCHARINC(y, data); + if (c >= x && c <= y) return !negated; + } + +#ifdef SUPPORT_UCP + else /* XCL_PROP & XCL_NOTPROP */ + { + int chartype, script; + int category = _pcre_ucp_findprop(c, &chartype, &script); + + switch(*data) + { + case PT_ANY: + if (t == XCL_PROP) return !negated; + break; + + case PT_LAMP: + if ((chartype == ucp_Lu || chartype == ucp_Ll || chartype == ucp_Lt) == + (t == XCL_PROP)) return !negated; + break; + + case PT_GC: + if ((data[1] == category) == (t == XCL_PROP)) return !negated; + break; + + case PT_PC: + if ((data[1] == chartype) == (t == XCL_PROP)) return !negated; + break; + + case PT_SC: + if ((data[1] == script) == (t == XCL_PROP)) return !negated; + break; + + /* This should never occur, but compilers may mutter if there is no + default. */ + + default: + return FALSE; + } + + data += 2; + } +#endif /* SUPPORT_UCP */ + } + +return negated; /* char did not match */ +} + +/* End of pcre_xclass.c */ diff --git a/examples/pikapython/pikapython/pikascript-lib/re/re-api-adapter.c b/examples/pikapython/pikapython/pikascript-lib/re/re-api-adapter.c new file mode 100755 index 00000000..ef5f8e8c --- /dev/null +++ b/examples/pikapython/pikapython/pikascript-lib/re/re-api-adapter.c @@ -0,0 +1,1008 @@ +#include +#include +#include "BaseObj.h" +#include "TinyObj.h" +#include "re.h" + +#include +#include +#include +#include "PikaStdData_List.h" +#include "PikaStdData_Tuple.h" +#include "cre.h" + +#include "re_Match.h" +#include "re_Pattern.h" + +#if !PIKASCRIPT_VERSION_REQUIRE_MINIMUN(1, 10, 5) +#error PikaScript version 1.10.5 or later is required. +#endif + +#define raise_error \ + { \ + obj_setErrorCode(self, -__LINE__); \ + } + +#define tu_getNew(name, obj_name) \ + PikaTuple *name = New_pikaTuple(); \ + Any obj_name = newNormalObj(New_PikaStdData_Tuple); \ + obj_setPtr(obj_name, "list", name); + +#define tu_append(tup, val, type) \ + { \ + Arg *_arg = arg_new##type(val); \ + pikaList_append(&(tup)->super, _arg); \ + arg_deinit(_arg); \ + } +#define li_append(list, val, type) \ + { \ + Arg *_arg = arg_new##type(val); \ + PikaStdData_List_append(list, _arg); \ + arg_deinit(_arg); \ + } + +typedef PikaObj *Any; + +void re_Match___init__args(PikaObj *self, char *sub, int *vec, int ven); +int _get_flags(PikaTuple *val); +PikaObj *__split(void *pattern__or__re, + char *subject, + int max_split, + int flags, + int mode_re); +PikaObj *__findall(void *pattern__or__re, + char *subject, + int flags, + int mode_re); +PikaObj *__subn(void *pattern__or__re, + char *repl, + char *subjet, + int count, + int flags, + int mode_re); +void re___init__(PikaObj *self) +{ + obj_setInt(self, "A", PCRE_ONLY_ASCII); + obj_setInt(self, "I", PCRE_CASELESS); + obj_setInt(self, "M", PCRE_MULTILINE); + obj_setInt(self, "S", PCRE_DOTALL); + obj_setInt(self, "ASCII", PCRE_ONLY_ASCII); + obj_setInt(self, "IGNORECASE", PCRE_CASELESS); + obj_setInt(self, "MULTILINE", PCRE_MULTILINE); + obj_setInt(self, "DOTALL", PCRE_DOTALL); +} + +PikaObj *re_findall(PikaObj *self, + char *pattern, + char *subject, + PikaTuple *val) +{ + int flags = 0; + flags = _get_flags(val); + if (flags < 0) + { + obj_setErrorCode(self, __LINE__); + return NULL; + } + Any list = __findall(pattern, subject, flags, 0); + if (!list) + raise_error; + return list; +} +PikaObj *re_match(PikaObj *self, char *pattern, char *subject, PikaTuple *val) +{ + int flags = 0; + flags = _get_flags(val); + if (flags < 0) + { + obj_setErrorCode(self, __LINE__); + return NULL; + } + int ven = -1; + int *vec = pcre_match(pattern, subject, strlen(subject), &ven, flags); + if (!vec) + { + if (ven < 0) + obj_setErrorCode(self, -__LINE__); + return NULL; + } + Any m = newNormalObj(New_re_Match); + re_Match___init__args(m, subject, vec, ven); + return m; +} +PikaObj *re_fullmatch(PikaObj *self, + char *pattern, + char *subject, + PikaTuple *val) +{ + int flags = 0; + flags = _get_flags(val); + if (flags < 0) + { + obj_setErrorCode(self, __LINE__); + return NULL; + } + int ven = -1; + + int *vec = pcre_fullmatch(pattern, subject, strlen(subject), &ven, flags); + if (!vec) + { + if (ven < 0) + obj_setErrorCode(self, -__LINE__); + return NULL; + } + Any m = newNormalObj(New_re_Match); + re_Match___init__args(m, subject, vec, ven); + return m; +} +PikaObj *re_search(PikaObj *self, + char *pattern, + char *subject, + PikaTuple *val) +{ + int flags = 0; + flags = _get_flags(val); + if (flags < 0) + { + obj_setErrorCode(self, __LINE__); + return NULL; + } + int ven = -1; + int *vec = pcre_search(pattern, subject, strlen(subject), &ven, flags); + if (!vec) + { + if (ven < 0) + obj_setErrorCode(self, -__LINE__); + return NULL; + } + Any m = newNormalObj(New_re_Match); + re_Match___init__args(m, subject, vec, ven); + return m; +} +char *re_sub(PikaObj *self, + char *pattern, + char *repl, + char *subjet, + PikaTuple *val) +{ + int flags = PCRE_UTF8; + int count = 0; + int argn = pikaTuple_getSize(val); + if (argn >= 1) + { + Arg *arg_i = pikaTuple_getArg(val, 0); + if (arg_getType(arg_i) != ARG_TYPE_INT) + { + obj_setErrorCode(self, -__LINE__); + return NULL; + } + count = arg_getInt(arg_i); + } + if (argn >= 2) + { + Arg *arg_i = pikaTuple_getArg(val, 1); + if (arg_getType(arg_i) != ARG_TYPE_INT) + { + obj_setErrorCode(self, -__LINE__); + return NULL; + } + flags = arg_getInt(arg_i); + if (flags | PCRE_ONLY_ASCII) + { + flags &= ~(PCRE_ONLY_ASCII | PCRE_UTF8); + } + } + int length = strlen(subjet); + + char *s = pcre_subn(pattern, repl, subjet, length, count, flags, NULL); + if (!s) + { + obj_setErrorCode(self, -__LINE__); + return NULL; + } + if (s == subjet) + { + obj_setStr(self, "_b", subjet); + return obj_getStr(self, "_b"); + } + + int len = strlen(s); + char *b = (char *)malloc(len + 1); + if (!b) + { + free(s); + return NULL; + } + memcpy(b, s, len); + b[len] = 0; + obj_setStr(self, "_b", b); + free(b); + free(s); + return obj_getStr(self, "_b"); +} +PikaObj *re_subn(PikaObj *self, + char *pattern, + char *repl, + char *subjet, + PikaTuple *val) +{ + int flags = PCRE_UTF8; + int count = 0; + int argn = pikaTuple_getSize(val); + if (argn >= 1) + { + Arg *arg_i = pikaTuple_getArg(val, 0); + if (arg_getType(arg_i) != ARG_TYPE_INT) + { + obj_setErrorCode(self, -__LINE__); + return NULL; + } + count = arg_getInt(arg_i); + } + if (argn >= 2) + { + Arg *arg_i = pikaTuple_getArg(val, 1); + if (arg_getType(arg_i) != ARG_TYPE_INT) + { + obj_setErrorCode(self, -__LINE__); + return NULL; + } + flags = arg_getInt(arg_i); + if (flags | PCRE_ONLY_ASCII) + { + flags &= ~(PCRE_ONLY_ASCII | PCRE_UTF8); + } + } + Any res = __subn(pattern, repl, subjet, count, flags, 0); + if (!res) + { + raise_error; + } + return res; +} +PikaObj *re_compile(PikaObj *self, char *pattern, PikaTuple *val) +{ + const char *error; + int erroffset; + int flags = _get_flags(val); + if (flags < 0) + { + raise_error; + return NULL; + } + pcre *re = pcre_compile(pattern, flags, &error, &erroffset, NULL); + if (!re) + { + obj_setErrorCode(self, erroffset); + return NULL; + } + + Any m = newNormalObj(New_re_Pattern); + obj_setPtr(m, "_re", re); + return m; +} +PikaObj *re_split(PikaObj *self, char *pattern, char *subject, PikaTuple *val) +{ + int flags = PCRE_UTF8; + int max_split = 0; + int argn = pikaTuple_getSize(val); + if (argn >= 1) + { + Arg *arg_i = pikaTuple_getArg(val, 0); + if (arg_getType(arg_i) != ARG_TYPE_INT) + { + obj_setErrorCode(self, -__LINE__); + return NULL; + } + max_split = arg_getInt(arg_i); + } + if (argn >= 2) + { + Arg *arg_i = pikaTuple_getArg(val, 1); + if (arg_getType(arg_i) != ARG_TYPE_INT) + { + obj_setErrorCode(self, -__LINE__); + return NULL; + } + flags = arg_getInt(arg_i); + if (flags | PCRE_ONLY_ASCII) + { + flags &= ~(PCRE_ONLY_ASCII | PCRE_UTF8); + } + } + Any list = __split(pattern, subject, max_split, flags, 0); + if (!list) + raise_error; + return list; +} + +char *re_escape(PikaObj *self, char *pattern) +{ + const char *special_chars = "()[]{}?*+-|^$\\.&~# \t\n\r\v\f"; + const int special_chars_len = 25; + if (!pattern) + return NULL; + int n = strlen(pattern); + int after_size = n; + for (int i = 0; i < n; i++) + { + for (int j = 0; j < special_chars_len; j++) + { + if (pattern[i] != special_chars[j]) + continue; + after_size++; + break; + } + } + char *new_s = (char *)malloc(after_size + 1); + if (!new_s) + return NULL; + int at = 0; + while (*pattern) + { + char c = *pattern; + int j = 0; + for (; j < special_chars_len; j++) + { + if (c != special_chars[j]) + continue; + new_s[at++] = '\\'; + break; + } + new_s[at++] = c; + pattern++; + } + new_s[at++] = 0; + obj_setStr(self, "_b", new_s); + free(new_s); + return obj_getStr(self, "_b"); +} + +void re_Match___del__(PikaObj *self) +{ + void *vec = obj_getPtr(self, "_vec"); + if (!vec) + return; + free(vec); +} +void re_Match___init__(PikaObj *self) +{ + if (!obj_isArgExist(self, "_vec")) + { + obj_setPtr(self, "_vec", NULL); + obj_setStr(self, "_b", ""); + obj_setInt(self, "_ven", 0); + obj_setStr(self, "_s", ""); + } +} +void re_Match___init__args(PikaObj *self, char *sub, int *vec, int ven) +{ + obj_setPtr(self, "_vec", vec); + obj_setStr(self, "_b", ""); + obj_setInt(self, "_ven", ven); + obj_setStr(self, "_s", sub); +} +char *re_Match_group(PikaObj *self, PikaTuple *val) +{ + int n = 0; + int argn = pikaTuple_getSize(val); + if (argn >= 1) + { + Arg *arg_i = pikaTuple_getArg(val, 0); + if (arg_getType(arg_i) != ARG_TYPE_INT) + { + obj_setErrorCode(self, -__LINE__); + return NULL; + } + n = arg_getInt(arg_i); + } + + int *vec = obj_getPtr(self, "_vec"); + if (!vec) + return NULL; + char *s = obj_getStr(self, "_s"); + if (!s) + return NULL; + int ven = obj_getInt(self, "_ven"); + if (n >= ven || n < 0) + { + obj_setErrorCode(self, -__LINE__); + return NULL; + } + int len = vec[n * 2 + 1] - vec[n * 2]; + if (!len) + return ""; + char *b = (char *)malloc(len + 1); + if (!b) + return NULL; + memcpy(b, s + vec[n * 2], len); + b[len] = 0; + obj_setStr(self, "_b", b); + free(b); + return obj_getStr(self, "_b"); +} +PikaObj *re_Match_groups(PikaObj *self) +{ + int *vec = obj_getPtr(self, "_vec"); + if (!vec) + return NULL; + char *s = obj_getStr(self, "_s"); + if (!s) + return NULL; + int ven = obj_getInt(self, "_ven"); + if (!ven) + return NULL; + tu_getNew(tup, tup_obj); + + for (int i = 1; i < ven; i++) + { + Arg *str_arg1; + int len = vec[i * 2 + 1] - vec[i * 2]; + if (len) + { + char *b = (char *)malloc(len + 1); + if (!b) + return NULL; + memcpy(b, s + vec[i * 2], len); + b[len] = 0; + str_arg1 = arg_newStr(b); + free(b); + } + else + { + str_arg1 = arg_newStr(""); + } + pikaList_append(&(tup)->super, str_arg1); + arg_deinit(str_arg1); + } + return tup_obj; +} +PikaObj *re_Match_span(PikaObj *self, PikaTuple *val) +{ + int group_n = 0; + int argn = pikaTuple_getSize(val); + if (argn >= 1) + { + Arg *arg_i = pikaTuple_getArg(val, 0); + if (arg_getType(arg_i) != ARG_TYPE_INT) + { + obj_setErrorCode(self, -__LINE__); + return NULL; + } + group_n = arg_getInt(arg_i); + } + int *vec = obj_getPtr(self, "_vec"); + if (!vec) + raise_error; + int ven = obj_getInt(self, "_ven"); + if (!ven || group_n >= ven) + { + obj_setErrorCode(self, -__LINE__); + return NULL; + } + tu_getNew(tu, tu_obj); + tu_append(tu, vec[group_n * 2], Int); + tu_append(tu, vec[group_n * 2 + 1], Int); + return tu_obj; +} + +void re_Pattern___del__(PikaObj *self) +{ + void *_re = obj_getPtr(self, "_re"); + if (!_re) + return; + pcre *re = (pcre *)_re; + pcre_free(re); +} + +void re_Pattern___init__(PikaObj *self) +{ + if (!obj_isArgExist(self, "_re")) + { + obj_setPtr(self, "_re", NULL); + obj_setStr(self, "_b", ""); + obj_setInt(self, "_n", -1); + } +} +PikaObj *re_Pattern_findall(PikaObj *self, char *subject, PikaTuple *val) +{ + int flags = 0; + flags = _get_flags(val); + if (flags < 0) + { + obj_setErrorCode(self, __LINE__); + return NULL; + } + if (!obj_isArgExist(self, "_re")) + return NULL; + pcre *re = obj_getPtr(self, "_re"); + Any list = __findall(re, subject, flags, 1); + if (!list) + raise_error; + return list; +} +PikaObj *re_Pattern_match(PikaObj *self, char *subject, PikaTuple *val) +{ + int flags = 0; + flags = _get_flags(val); + if (flags < 0) + { + obj_setErrorCode(self, __LINE__); + return NULL; + } + if (!obj_isArgExist(self, "_re")) + return NULL; + pcre *re = obj_getPtr(self, "_re"); + int ven = -1; + int *vec = re_match2(re, subject, strlen(subject), &ven, flags); + if (!vec) + { + if (ven < 0) + obj_setErrorCode(self, -__LINE__); + + return NULL; + } + Any m = newNormalObj(New_re_Match); + re_Match___init__args(m, subject, vec, ven); + return m; +} +PikaObj *re_Pattern_fullmatch(PikaObj *self, char *subject, PikaTuple *val) +{ + int flags = 0; + flags = _get_flags(val); + if (flags < 0) + { + obj_setErrorCode(self, __LINE__); + return NULL; + } + if (!obj_isArgExist(self, "_re")) + return NULL; + pcre *re = obj_getPtr(self, "_re"); + int ven = -1; + int *vec = re_fullmatch2(re, subject, strlen(subject), &ven, flags); + if (!vec) + { + if (ven < 0) + obj_setErrorCode(self, -__LINE__); + return NULL; + } + Any m = newNormalObj(New_re_Match); + re_Match___init__args(m, subject, vec, ven); + return m; +} +PikaObj *re_Pattern_search(PikaObj *self, char *subject, PikaTuple *val) +{ + int flags = 0; + flags = _get_flags(val); + if (flags < 0) + { + obj_setErrorCode(self, __LINE__); + return NULL; + } + if (!obj_isArgExist(self, "_re")) + return NULL; + pcre *re = obj_getPtr(self, "_re"); + Any m = newNormalObj(New_re_Match); + int ven = -1; + + int *vec = re_search2(re, subject, strlen(subject), &ven, flags); + if (!vec) + { + if (ven < 0) + obj_setErrorCode(self, -__LINE__); + return NULL; + } + re_Match___init__args(m, subject, vec, ven); + return m; +} +char *re_Pattern_sub(PikaObj *self, char *repl, char *subjet, PikaTuple *val) +{ + int flags = 0; + int count = 0; + int argn = pikaTuple_getSize(val); + if (argn >= 1) + { + Arg *arg_i = pikaTuple_getArg(val, 0); + if (arg_getType(arg_i) != ARG_TYPE_INT) + { + obj_setErrorCode(self, -__LINE__); + return NULL; + } + count = arg_getInt(arg_i); + } + if (argn >= 2) + { + Arg *arg_i = pikaTuple_getArg(val, 1); + if (arg_getType(arg_i) != ARG_TYPE_INT) + { + obj_setErrorCode(self, -__LINE__); + return NULL; + } + flags = arg_getInt(arg_i); + if (flags | PCRE_ONLY_ASCII) + { + flags &= ~(PCRE_ONLY_ASCII | PCRE_UTF8); + } + } + + if (!obj_isArgExist(self, "_re")) + return NULL; + pcre *re = obj_getPtr(self, "_re"); + int length = strlen(subjet); + int matched_times = 0; + char *s = re_subn2(re, repl, subjet, length, count, flags, &matched_times); + obj_setInt(self, "_n", matched_times); + + if (!s) + { + obj_setErrorCode(self, -__LINE__); + return NULL; + } + if (s == subjet) + { + obj_setStr(self, "_b", subjet); + return obj_getStr(self, "_b"); + } + + int len = strlen(s); + char *b = (char *)malloc(len + 1); + if (!b) + { + free(s); + return NULL; + } + memcpy(b, s, len); + b[len] = 0; + obj_setStr(self, "_b", b); + free(b); + free(s); + return obj_getStr(self, "_b"); +} +PikaObj *re_Pattern_subn(PikaObj *self, char *repl, char *subjet, PikaTuple *val) +{ + if (!obj_isArgExist(self, "_re")) + return NULL; + int flags = 0; + int count = 0; + int argn = pikaTuple_getSize(val); + if (argn >= 1) + { + Arg *arg_i = pikaTuple_getArg(val, 0); + if (arg_getType(arg_i) != ARG_TYPE_INT) + { + obj_setErrorCode(self, -__LINE__); + return NULL; + } + count = arg_getInt(arg_i); + } + if (argn >= 2) + { + Arg *arg_i = pikaTuple_getArg(val, 1); + if (arg_getType(arg_i) != ARG_TYPE_INT) + { + obj_setErrorCode(self, -__LINE__); + return NULL; + } + flags = arg_getInt(arg_i); + if (flags | PCRE_ONLY_ASCII) + { + flags &= ~(PCRE_ONLY_ASCII | PCRE_UTF8); + } + } + pcre *re = obj_getPtr(self, "_re"); + Any res = __subn(re, repl, subjet, count, flags, 1); + if (!res) + raise_error; + return res; +} +PikaObj *re_Pattern_split(PikaObj *self, char *subject, PikaTuple *val) +{ + if (!obj_isArgExist(self, "_re")) + return NULL; + pcre *re = obj_getPtr(self, "_re"); + int flags = PCRE_UTF8; + int max_split = 0; + int argn = pikaTuple_getSize(val); + if (argn >= 1) + { + Arg *arg_i = pikaTuple_getArg(val, 0); + if (arg_getType(arg_i) != ARG_TYPE_INT) + { + obj_setErrorCode(self, -__LINE__); + return NULL; + } + max_split = arg_getInt(arg_i); + } + if (argn >= 2) + { + Arg *arg_i = pikaTuple_getArg(val, 1); + if (arg_getType(arg_i) != ARG_TYPE_INT) + { + obj_setErrorCode(self, -__LINE__); + return NULL; + } + flags = arg_getInt(arg_i); + if (flags | PCRE_ONLY_ASCII) + { + flags &= ~(PCRE_ONLY_ASCII | PCRE_UTF8); + } + } + Any list = __split(re, subject, max_split, flags, 1); + if (!list) + raise_error; + return list; +} + +int _get_flags(PikaTuple *val) +{ + int flags = PCRE_UTF8; + int argn = pikaTuple_getSize(val); + if (argn >= 1) + { + Arg *arg_i = pikaTuple_getArg(val, 0); + if (arg_getType(arg_i) != ARG_TYPE_INT) + { + return -1; + } + flags |= arg_getInt(arg_i); + if (flags & PCRE_ONLY_ASCII) + { + flags &= ~(PCRE_ONLY_ASCII | PCRE_UTF8); + } + } + return flags; +} + +PikaObj *__split(void *pattern__or__re, + char *subject, + int max_split, + int flags, + int mode_re) + +{ + int sub_length = strlen(subject); + int j2 = 0; + int _m_n = 0, m_n = 0; + int brackets = -1; + int **vcs; + if (mode_re) + vcs = re_searchall2((pcre *)pattern__or__re, subject, sub_length, &_m_n, &brackets, flags); + else + vcs = re_searchall((char *)pattern__or__re, subject, sub_length, &_m_n, &brackets, flags); + m_n = _m_n; + char *b = NULL; + Arg *str_arg1; + // Arg *sub_arg; + if (!vcs) + { + return NULL; + } + if (max_split && max_split < m_n) + m_n = max_split; + Any list = newNormalObj(New_PikaStdData_List); + PikaStdData_List___init__(list); + int start = 0; + + if (brackets == 1) + { + for (int i = 0; i < m_n; i++) + { + int *v = vcs[i]; + int length = v[0] - start; + if (length) + { + b = malloc(length + 1); + if (!b) + goto e_er; + b[length] = 0; + memcpy(b, subject + start, length); + } + else + { + b = (char *)""; + } + str_arg1 = arg_newStr(b); + PikaStdData_List_append(list, str_arg1); + arg_deinit(str_arg1); + if (length) + free(b); + start = v[1]; + } + if (start <= sub_length) + { + str_arg1 = arg_newStr(subject + start); + PikaStdData_List_append(list, str_arg1); + arg_deinit(str_arg1); + } + goto exit; + } + + for (int i = 0; i < m_n; i++) + { + int *v = vcs[i]; + int length = v[0] - start; + b = malloc(length + 1); + if (!b) + goto e_er; + memcpy(b, subject + start, length); + b[length] = 0; + str_arg1 = arg_newStr(b); + PikaStdData_List_append(list, str_arg1); + arg_deinit(str_arg1); + + for (int j = 1; j < brackets; j++) + { + j2 = j * 2; + int length2 = v[j2 + 1] - v[j2]; + if (length2 > length) + { + free(b); + length = length2; + b = malloc(length + 1); + if (!b) + goto e_er; + } + b[length2] = 0; + memcpy(b, subject + v[j2], length2); + + str_arg1 = arg_newStr(b); + PikaStdData_List_append(list, str_arg1); + arg_deinit(str_arg1); + } + start = v[1]; + free(b); + } + if (start <= sub_length) + { + str_arg1 = arg_newStr(subject + start); + PikaStdData_List_append(list, str_arg1); + arg_deinit(str_arg1); + } + goto exit; +e_er: + if (list) + { + obj_deinit(list); + list = NULL; + } +exit: + if (vcs) + re_free_searchall(vcs, _m_n); + return list; +} + +PikaObj *__findall(void *pattern__or__re, + char *subject, + int flags, + int mode_re) +{ + int length = strlen(subject); + int j2 = 0; + int m_n = -1; + int brackets = -1; + int **vcs; + if (mode_re) + vcs = re_searchall2((pcre *)pattern__or__re, subject, length, &m_n, &brackets, flags); + else + vcs = re_searchall((char *)pattern__or__re, subject, length, &m_n, &brackets, flags); + + char *b = NULL; + Arg *str_arg1; + Arg *sub_arg; + if (!vcs) + { + if (m_n < 0) + return NULL; + Any list = newNormalObj(New_PikaStdData_List); + PikaStdData_List___init__(list); + + return list; + } + Any list = newNormalObj(New_PikaStdData_List); + PikaStdData_List___init__(list); + PikaTuple *tu; + Any sub_list = NULL; + if (brackets == 1) + { + for (int i = 0; i < m_n; i++) + { + int *v = vcs[i]; + length = v[1] - v[0]; + if (length) + { + b = malloc(length + 1); + if (!b) + goto e_er; + b[length] = 0; + memcpy(b, subject + v[0], length); + } + else + { + b = (char *)""; + } + str_arg1 = arg_newStr(b); + PikaStdData_List_append(list, str_arg1); + arg_deinit(str_arg1); + if (length) + free(b); + } + goto exit; + } + + for (int i = 0; i < m_n; i++) + { + int *v = vcs[i]; + length = v[1] - v[0]; + b = malloc(length + 1); + if (!b) + goto e_er; + tu = New_pikaTuple(); + + for (int j = 1; j < brackets; j++) + { + j2 = j * 2; + length = v[j2 + 1] - v[j2]; + b[length] = 0; + memcpy(b, subject + v[j2], length); + tu_append(tu, b, Str); + } + sub_list = newNormalObj(New_PikaStdData_Tuple); + obj_setPtr(sub_list, "list", tu); + sub_arg = arg_newObj(sub_list); + PikaStdData_List_append(list, sub_arg); + arg_deinit(sub_arg); + free(b); + } + goto exit; +e_er: + if (list) + { + obj_deinit(list); + list = NULL; + } +exit: + if (vcs) + re_free_searchall(vcs, m_n); + return list; +} + +PikaObj *__subn(void *pattern__or__re, + char *repl, + char *subjet, + int count, + int flags, + int mode_re) +{ + int length = strlen(subjet); + int matched_times = 0; + char *s; + if (mode_re) + s = re_subn2((pcre *)pattern__or__re, repl, subjet, length, count, flags, &matched_times); + else + s = pcre_subn((char *)pattern__or__re, repl, subjet, length, count, flags, &matched_times); + + if (!s) + { + return NULL; + } + if (s == subjet) + { + PikaTuple *yup = New_pikaTuple(); + tu_append(yup, s, Str); + tu_append(yup, 0, Int); + + Any tuple_obj = newNormalObj(New_PikaStdData_Tuple); + obj_setPtr(tuple_obj, "list", yup); + return tuple_obj; + } + + PikaTuple *yup = New_pikaTuple(); + tu_append(yup, s, Str); + free(s); + + tu_append(yup, matched_times, Int); + + Any tuple_obj = newNormalObj(New_PikaStdData_Tuple); + obj_setPtr(tuple_obj, "list", yup); + return tuple_obj; +} \ No newline at end of file diff --git a/examples/pikapython/pikapython/pikascript-lib/re/re_config.h b/examples/pikapython/pikapython/pikascript-lib/re/re_config.h new file mode 100755 index 00000000..b4d6bfb0 --- /dev/null +++ b/examples/pikapython/pikapython/pikascript-lib/re/re_config.h @@ -0,0 +1,214 @@ + + +/* Define to 1 if you have the `bcopy' function. */ +#ifndef HAVE_BCOPY +#define HAVE_BCOPY 0 +#endif + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_BITS_TYPE_TRAITS_H */ + +/* Define to 1 if you have the header file. */ +#ifndef HAVE_BZLIB_H +#define HAVE_BZLIB_H 0 +#endif + +/* Define to 1 if you have the header file. */ +#ifndef HAVE_DIRENT_H +#define HAVE_DIRENT_H 0 +#endif + +/* Define to 1 if you have the header file. */ +#ifndef HAVE_DLFCN_H +#define HAVE_DLFCN_H 0 +#endif + +/* Define to 1 if you have the header file. */ +#ifndef HAVE_INTTYPES_H +#define HAVE_INTTYPES_H 1 +#endif + +/* Define to 1 if you have the header file. */ +#ifndef HAVE_LIMITS_H +#define HAVE_LIMITS_H 1 +#endif + +/* Define to 1 if the system has the type `long long'. */ +#ifndef HAVE_LONG_LONG +#define HAVE_LONG_LONG 1 +#endif + +/* Define to 1 if you have the `memmove' function. */ +#ifndef HAVE_MEMMOVE +#define HAVE_MEMMOVE 1 +#endif + +/* Define to 1 if you have the header file. */ +#ifndef HAVE_MEMORY_H +#define HAVE_MEMORY_H 1 +#endif + +/* Define to 1 if you have the header file. */ +#ifndef HAVE_READLINE_HISTORY_H +#define HAVE_READLINE_HISTORY_H 0 +#endif + +/* Define to 1 if you have the header file. */ +#ifndef HAVE_READLINE_READLINE_H +#define HAVE_READLINE_READLINE_H 0 +#endif + +/* Define to 1 if you have the header file. */ +#ifndef HAVE_STDINT_H +#define HAVE_STDINT_H 1 +#endif + +/* Define to 1 if you have the header file. */ +#ifndef HAVE_STDLIB_H +#define HAVE_STDLIB_H 1 +#endif + +/* Define to 1 if you have the `strerror' function. */ +#ifndef HAVE_STRERROR +#define HAVE_STRERROR 1 +#endif + +/* Define to 1 if you have the header file. */ +#ifndef HAVE_STRING +#define HAVE_STRING 0 +#endif + +/* Define to 1 if you have the header file. */ +#ifndef HAVE_STRINGS_H +#define HAVE_STRINGS_H 0 +#endif + +/* Define to 1 if you have the header file. */ +#ifndef HAVE_STRING_H +#define HAVE_STRING_H 1 +#endif + +/* Define to 1 if you have the `strtoll' function. */ +#ifndef HAVE_STRTOLL +#define HAVE_STRTOLL 1 +#endif + +/* Define to 1 if you have the `strtoq' function. */ +#ifndef HAVE_STRTOQ +#define HAVE_STRTOQ 0 +#endif + +/* Define to 1 if you have the header file. */ +#ifndef HAVE_SYS_STAT_H +#define HAVE_SYS_STAT_H 0 +#endif + +/* Define to 1 if you have the header file. */ +#ifndef HAVE_SYS_TYPES_H +#define HAVE_SYS_TYPES_H 0 +#endif + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_TYPE_TRAITS_H */ + +/* Define to 1 if you have the header file. */ +#ifndef HAVE_UNISTD_H +#define HAVE_UNISTD_H 0 +#endif + +/* Define to 1 if the system has the type `unsigned long long'. */ +#ifndef HAVE_UNSIGNED_LONG_LONG +#define HAVE_UNSIGNED_LONG_LONG 1 +#endif + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_WINDOWS_H */ + +/* Define to 1 if you have the header file. */ +#ifndef HAVE_ZLIB_H +#define HAVE_ZLIB_H 0 +#endif + +/* Define to 1 if you have the `_strtoi64' function. */ +/* #undef HAVE__STRTOI64 */ + +/* The value of LINK_SIZE determines the number of bytes used to store links + as offsets within the compiled regex. The default is 2, which allows for + compiled patterns up to 64K long. This covers the vast majority of cases. + However, PCRE can also be compiled to use 3 or 4 bytes instead. This allows + for longer patterns in extreme cases. On systems that support it, + "configure" can be used to override this default. */ +#ifndef LINK_SIZE +#define LINK_SIZE 2 +#endif + +/* The value of MATCH_LIMIT determines the default number of times the + internal match() function can be called during a single execution of + pcre_exec(). There is a runtime interface for setting a different limit. + The limit exists in order to catch runaway regular expressions that take + for ever to determine that they do not match. The default is set very large + so that it does not accidentally catch legitimate cases. On systems that + support it, "configure" can be used to override this default default. */ +#ifndef MATCH_LIMIT +#define MATCH_LIMIT 10000000 +#endif + +/* The above limit applies to all calls of match(), whether or not they + increase the recursion depth. In some environments it is desirable to limit + the depth of recursive calls of match() more strictly, in order to restrict + the maximum amount of stack (or heap, if NO_RECURSE is defined) that is + used. The value of MATCH_LIMIT_RECURSION applies only to recursive calls of + match(). To have any useful effect, it must be less than the value of + MATCH_LIMIT. The default is to use the same value as MATCH_LIMIT. There is + a runtime method for setting a different limit. On systems that support it, + "configure" can be used to override the default. */ +#ifndef MATCH_LIMIT_RECURSION +#define MATCH_LIMIT_RECURSION MATCH_LIMIT +#endif + +/* This limit is parameterized just in case anybody ever wants to change it. + Care must be taken if it is increased, because it guards against integer + overflow caused by enormously large patterns. */ +#ifndef MAX_NAME_COUNT +#define MAX_NAME_COUNT 10000 +#endif + +/* This limit is parameterized just in case anybody ever wants to change it. + Care must be taken if it is increased, because it guards against integer + overflow caused by enormously large patterns. */ +#ifndef MAX_NAME_SIZE +#define MAX_NAME_SIZE 32 +#endif + +/* The value of NEWLINE determines the newline character sequence. On systems + that support it, "configure" can be used to override the default, which is + 10. The possible values are 10 (LF), 13 (CR), 3338 (CRLF), -1 (ANY), or -2 + (ANYCRLF). */ +#ifndef NEWLINE +#define NEWLINE 10 +#endif + +/* When calling PCRE via the POSIX interface, additional working storage is + required for holding the pointers to capturing substrings because PCRE + requires three integers per substring, whereas the POSIX interface provides + only two. If the number of expected substrings is small, the wrapper + function uses space on the stack, because this is faster than using + malloc() for each call. The threshold above which the stack is no longer + used is defined by POSIX_MALLOC_THRESHOLD. On systems that support it, + "configure" can be used to override this default. */ +#ifndef POSIX_MALLOC_THRESHOLD +#define POSIX_MALLOC_THRESHOLD 10 +#endif + +/* Define to 1 if you have the ANSI C header files. */ +#ifndef STDC_HEADERS +#define STDC_HEADERS 1 +#endif + +/* Define to enable support for the UTF-8 Unicode encoding. */ +/* #undef SUPPORT_UTF8 */ +#define SUPPORT_UTF8 + + +/* Define to `unsigned int' if does not define. */ +/* #undef size_t */ diff --git a/examples/pikapython/pikapython/pikascript-lib/re/readme.md b/examples/pikapython/pikapython/pikascript-lib/re/readme.md new file mode 100755 index 00000000..79e9a3bd --- /dev/null +++ b/examples/pikapython/pikapython/pikascript-lib/re/readme.md @@ -0,0 +1,164 @@ +# re for pikaScript + +This module is made for pikaScript, aiming at providing the same usage as the re module in Python. + +## import module + +``` python +import re +``` + +## usage + +The functions in this module have almost the same name and usage as the functions in the re module in python, but some features in the python.re module are not avaliable here, pikaScript does not support default arguments for example. + +Here we provide some demonstration programs. + +### match + +``` python +import re + +line = "Cats are smarter than dogs" + +m = re.match( '(.*) are (.*?) .*', line, re.M|re.I) + +if m: + print("matchObj.group(0) : ", m.group(0)) + print("matchObj.group(1) : ", m.group(1)) + print("matchObj.group(2) : ", m.group(2)) +else: + print("No match!!") + +'''>> runing output +matchObj.group(0) : Cats are smarter than dogs +matchObj.group(1) : Cats +matchObj.group(2) : smarter +''' +``` + +### search + +``` python + +print(re.search('www', 'www.runoob.com').span(0)) +print(re.search('com', 'www.runoob.com').span(0)) + +'''>> running output +[0, 3] +[11, 14] +''' +``` + +### sub + +```python + +phone = "2004-959-559 # this is a phone number" +num = re.sub('#.*$', "", phone) +print("the phone number is: ", num) +num = re.sub('\\D', "", phone) +print("the phone number is: ", num) + +'''>> running output +the phone number is: 2004-959-559 +the phone number is: 2004959559 +''' + +``` + +### findall + +``` python +# year-month-day +pattern = re.compile('(\\d{4})-([1-9]|1[0-2])-([1-9]|[1-2][0-9]|3[01])\\b') +s = 'date: 2020-1-1, 2022-12-22, 2018-3-31. Wrong format: 2031-13-31, 2032-12-33 ...' +result1 = pattern.findall(s) +print(result1) +result2 = pattern.sub('\\1',s) +print(result2) + +'''>> running output +[['2020-1-1', '2020', '1', '1'], ['2022-12-22', '2022', '12', '22'], ['2018-3-31', '2018', '3', '31']] +date: 2020, 2022, 2018. Wrong format: 2031-13-31, 2032-12-33 ... + +''' +``` + +## the API + +This module prototype are likes this: + +``` python + +# flags + +A: int +ASCII: int +I: int +IGNORECASE: int +M: int +MULTILINE: int +S: int +DOTALL: int + +class Pattern: + def __init__(self): + pass + + def __del__(self): + pass + + def findall(self, subject: str, *flags) -> list: + pass + + def sub(self, repl: str, subjet: str, *count__flags) -> str: + pass + + def subn(self, repl: str, subjet: str, *count__flags) -> list: + pass + + def match(self, subject: str, *flags) -> Match: + pass + + def fullmatch(self, subject: str, *flags) -> Match: + pass + + def search(self, subject: str, *flags) -> Match: + pass + + def split(self, subject: str, *maxsplit__flags) -> list: + pass + + +class Match: + def __init__(self): + pass + + def __del__(self): + pass + + def group(self, *n) -> str: + pass + + def groups(self) -> list: + pass + + def span(self, *group_n) -> list: + pass + + +def findall(pattern: str, subject: str, *flags) -> list: ... +# def sub(pattern, repl, string, count=0, flags=0) +def sub(pattern: str, repl: str, subjet: str, *count__flags) -> str: ... +def match(pattern: str, subject: str, *flags) -> Match: ... +def fullmatch(pattern: str, subject: str, *flags) -> Match: ... +def search(pattern: str, subject: str, *flags) -> Match: ... +def compile(pattern: str, *flags) -> Pattern: ... +def escape(pattern: str) -> str: ... +# def subn(pattern, repl, string, count=0, flags=0) +def subn(pattern: str, repl: str, subjet: str, *count__flags) -> list: ... +# def finditer(pattern: str, subject: str, *flags): +def split(pattern: str, subject: str, *maxsplit__flags) -> list: ... + +``` diff --git a/examples/pikapython/pikapython/pikascript-lib/time/_time.c b/examples/pikapython/pikapython/pikascript-lib/time/_time.c new file mode 100755 index 00000000..cb6389eb --- /dev/null +++ b/examples/pikapython/pikapython/pikascript-lib/time/_time.c @@ -0,0 +1,719 @@ +#include "_time.h" +#include "PikaVM.h" +#if defined(__linux) +#include +#endif +#if defined(_WIN32) +#include +#endif + +void (*global_do_sleep_ms)(uint32_t); + +static void _do_sleep_ms_tick(uint32_t ms) { + uint32_t tick = pika_platform_get_tick(); + while (pika_platform_get_tick() - tick < ms) { +#if PIKA_EVENT_ENABLE + // _VMEvent_pickupEvent(); + //! can not pickup event in this function, because it will cause the GIL + //! lock error. +#endif + pika_platform_thread_delay(); + } +} + +void _time_sleep_ms(PikaObj* self, int ms) { + pika_GIL_EXIT(); + global_do_sleep_ms(ms); + pika_GIL_ENTER(); +} + +void _time_sleep_s(PikaObj* self, int s) { + pika_GIL_EXIT(); + for (int i = 0; i < s; i++) { + global_do_sleep_ms(1000); + } + pika_GIL_ENTER(); +} + +void _time_platformGetTick(PikaObj* self) { + obj_setInt(self, "tick", __platform_getTick()); +} + +/* + * @Author: Once day + * @LastEditTime: 2022-06-04 12:10:52 + * Encoder=utf-8,Email:once_day@qq.com + */ + +#include "stdint.h" +#include "stdio.h" + +// 结构体时间类型定义(来源c标准库corect_wtime.h) +// 无论是16位整数还是32位整数都满足需求 +typedef struct _tm { + int tm_sec; // seconds after the minute - [0, 60] including leap second + int tm_min; // minutes after the hour - [0, 59] + int tm_hour; // hours since midnight - [0, 23] + int tm_mday; // day of the month - [1, 31] + int tm_mon; // months since January - [0, 11] + int tm_year; // years since 1900 + int tm_wday; // days since Sunday - [0, 6] + int tm_yday; // days since January 1 - [0, 365] + int tm_isdst; // daylight savings time flag +} _tm; + +// 时间戳时间类型定义(来源c标准库time.h) +// 直接支持64位秒数时间,附加时间精度为ns,根据设备决定,需要1GHz及以上时钟频率才能支持1ns级别时间精度 +// 内部时间比对数据类型,传递给外界的时候会使用浮点数,所以精度会降低 +// 但内部使用复合数据类型比对,以实现平台支持的最小时间精度比较 +typedef struct { + int64_t tv_sec; // Seconds - >= 0 + int32_t tv_nsec; // Nanoseconds - [0, 999999999] +} _timespec; + +// 错误处理 +typedef int status; + +#define TIME_OK 0 +#define TIME_ERROR -1 +#define TIME_GET_TIME_FAIL 1 +#define TIME_GET_TICK_FAIL 2 +#define TIME_LESS_THAN_ZERO 3 +#define TIME_OVER_3200 4 +#define TIME_LESS_THAN_1970 5 +#define TIME_ERROR_STRUCT_TIME 6 + +// 错误状态处理函数 +void status_deal(status s) { +// 输出异常信息 +#define time_printf(...) __platform_printf(__VA_ARGS__) + + time_printf("\n[Error-info]Checking a exception : "); + switch (s) { + case TIME_ERROR: + time_printf("Unknow error!!!\n"); + break; + case TIME_GET_TIME_FAIL: + time_printf("Fail to get Unix-time from hardware !\n"); + break; + case TIME_GET_TICK_FAIL: + time_printf("Fail to get Tick-time from hardware !\n"); + break; + case TIME_LESS_THAN_ZERO: + time_printf("Input a negative Unix timestamp !\n"); + break; + case TIME_OVER_3200: + time_printf("The time point exceeds 3200 AD !\n"); + break; + case TIME_LESS_THAN_1970: + time_printf("The time point less-than 1970 AD !\n"); + break; + case TIME_ERROR_STRUCT_TIME: + time_printf("The struct-time's range is wrong !\n"); + break; + default: + break; + } + time_printf("\n"); +} + +// 获取硬件平台的Unix时间戳,时间精度为1s级别, +status time_get_unix_time(PikaObj* self, _timespec* this_timespec) { + this_timespec->tv_sec = (int64_t)(obj_getInt(self, "tick") / 1000); + return TIME_OK; +} + +// 获取硬件平台的Tick时间,时间精度为1s级别以下 +// 即1s的小数部分 +status time_get_tick_ns(PikaObj* self, _timespec* this_timespec) { + this_timespec->tv_nsec = (obj_getInt(self, "tick") % 1000) * 1000000; + return TIME_OK; +} + +// 标准time()方法,返回以浮点数表示的从 epoch 开始的秒数的时间值。 +// epoch 是 1970 年 1 月 1 日 00:00:00 (UTC), +pika_float time_time(PikaObj* self) { + status res = 0; // 状态响应 + _timespec temp_timespec = {0}; + // 调用硬件平台函数,获取当前时间 + res = time_get_unix_time(self, &temp_timespec); + if (res) { + status_deal(res); + } // 异常处理 + res = time_get_tick_ns(self, &temp_timespec); + if (res) { + status_deal(res); + } // 异常处理 + // 以浮点数返回时间,float + return temp_timespec.tv_sec + + (pika_float)temp_timespec.tv_nsec / 1000000000; +} + +// 标准time_ns()方法,返回以整数表示的从 epoch 开始的纳秒数的时间值。 +// epoch 是 1970 年 1 月 1 日 00:00:00 (UTC), +int64_t time_time_ns(PikaObj* self) { + status res = 0; // 状态响应 + _timespec temp_timespec = {0}; + // 调用硬件平台函数,获取当前时间 + res = time_get_unix_time(self, &temp_timespec); + if (res) { + status_deal(res); + } // 异常处理 + res = time_get_tick_ns(self, &temp_timespec); + if (res) { + status_deal(res); + } // 异常处理 + // 以浮点数返回时间,float + return temp_timespec.tv_sec * 1000000000 + temp_timespec.tv_nsec; +} + +// 利用基姆拉尔森计算公式计算星期 +int time_get_week(const _tm* this_tm) { + // 月份要+1 + int month = this_tm->tm_mon + 1; + int year = this_tm->tm_year; + int day = this_tm->tm_mday; + int w; + if (month == 1 || month == 2) { + month += 12; + year -= 1; + w = day + 2 * month + 3 * (month + 1) / 5 + year + year / 4 - + year / 100 + year / 400 + 1; // 0~6,星期日 ~ 星期六 + w = w % 7; + } else { + w = day + 2 * month + 3 * (month + 1) / 5 + year + year / 4 - + year / 100 + year / 400 + 1; // 0~6,星期日 ~ 星期六 + w = w % 7; + } + return w; +} + +// 由Unix时间戳计算标准UTC时间 +status unix_time_to_utc_struct_time(_tm* this_tm, int64_t unix_time) { + int32_t total_day; + int32_t extra_second; + int year_400, year_100, year_4, year_1; + int february_offset, temp; // 二月偏移量,零时变量 + + // 判断是否输入小于0的时间戳 + if (unix_time < 0) { + // 暂不支持小于0的时间戳 + return TIME_LESS_THAN_ZERO; + } + +// Unix时间戳每天秒数是固定的 62*60*24 +#define DAY_SECOND (86400) + + total_day = unix_time / DAY_SECOND; + extra_second = unix_time - total_day * DAY_SECOND; + +// 为了减少额外闰年判断,把时间往前推到1600年,即闰年最大的一次公倍数开始计算判断 +// 1970-1600 = 370 年 ,370/4 -(370/100-1)=90 个闰年 +// 1600 DAY_OFFSET 365*(1970-1600)+90 = 135140,7为修正天数 +#define YEAR_START (1600) // 初始年份 +#define DAY_OFFSET (135140) // 时间偏移量 + + total_day += DAY_OFFSET; + +// 从1600年到3200年有1600/4-(1600/100-1600/400)=388个闰年 +// 即 MAX_DAY 1600*365+388=584388 day +#define MAX_DAY (584388) // 最大可判断时间天数 + + if (total_day > MAX_DAY) { + // 超过3200年的换算暂不支持 + return TIME_OVER_3200; + } else { +// 从1600年开始,天数都要多减一天,因为1600年是闰年 +// 但是由于日期不包含当天时间,即2月2号,实际是2月1号+时:分:秒 +// 所以算出来的日期要加上一天 +// 两者配合,无需加减 + +// 从400年,100年,4年逐渐缩小范围 +// 400个公历年天数为365*400+97=146097天 +// 400年内的100个公历年天数为365*100+24=36524天 +// 100年内的4年365*4+1=1461天 +#define DAY_OF_400Y (146097) +#define DAY_OF_100Y (36524) +#define DAY_OF_4Y (1461) +#define DAY_OF_1Y (365) + // 400年也要注意,要实际401年才可 + year_400 = (total_day - 366) / DAY_OF_400Y; + total_day -= year_400 * DAY_OF_400Y; + // 计算400年内的情况 + year_100 = (total_day - 1) / DAY_OF_100Y; + total_day -= year_100 * DAY_OF_100Y; + // 计算100年内的情况,要到第二年的第一天才算,即365+1 + year_4 = (total_day - 366) / DAY_OF_4Y; + // 计算4年,需要格外注意0-5-8年,才会计算一个闰年,因为它才包含了4这个闰年,但并不包含8 + total_day -= year_4 * DAY_OF_4Y; + // 计算4年内的情况 + // 需要减去1天,因为当天是不存在的 + // 需要注意闰年会多一天 + // 所有闰年都放在这里来考虑,即只要当前是闰年,那么这里就会剩下第一年闰年和第四年闰年两种情况 + if (year_100 == 4) { + // 第一年是闰年,此时为400*n+1年内 + year_1 = 0; + february_offset = 1; + } else if (total_day <= DAY_OF_1Y * 4) { + // 100*n+(4,8,...96)+1年,都是从第二年算起,非闰年 + // 非闰年,需要减去1天,因为当天是不存在的 + year_1 = (total_day - 1) / DAY_OF_1Y; + total_day -= year_1 * DAY_OF_1Y; + february_offset = 0; + } else { + // 第四年是闰年 + year_1 = 4; + total_day -= year_1 * DAY_OF_1Y; + february_offset = 1; + } + + // 计算出当前年份 + this_tm->tm_year = + (year_400 * 400 + year_100 * 100 + year_4 * 4 + year_1) + + YEAR_START; + // 保存一年的天数 + this_tm->tm_yday = total_day; + + // 剩下的天数为1年内的天数,直接计算月和日 + // 根据当前是否为闰年设置二月偏移量是否为1 + // 能被4整除且不被100整除或者能被400整除 + + // 闰年需要减去一天再计算 + total_day -= february_offset; + // 使用二分法快速定位月份,使用平年计算,在月份确定到2月时,再考虑闰年 + // 判断是否在1-6月里面 + // 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 + if (total_day <= 181) { + // 判断是否在1-3月里面 + if (total_day <= 90) { + // 判断是否在1-2月里面 + if (total_day <= 59) { + total_day += february_offset; // 去掉二月的偏置 + if (total_day <= 31) { + // 1月 + temp = 0; + } else { + total_day -= 31; + // 2月 + temp = 1; + } + } else { + total_day -= 59; + // 3月 + temp = 2; + } + } else { + // 4-6月 + total_day -= 90; + // 是否在4月里面 + if (total_day <= 30) { + // 4月 + temp = 3; + } else { + // 5-6月 + total_day -= 30; + if (total_day <= 31) { + // 5月 + temp = 4; + } else { + total_day -= 31; + // 6月 + temp = 5; + } + } + } + } else { + total_day -= 181; + // 判断是否在7-9月里面 + if (total_day <= 92) { + // 是否在7-8月 + if (total_day <= 62) { + if (total_day <= 31) { + // 7月 + temp = 6; + } else { + total_day -= 31; + // 8月 + temp = 7; + } + } else { + // 9月 + total_day -= 62; + temp = 8; + } + } else { + // 10-12月 + total_day -= 92; + // 是否在10-11月 + if (total_day <= 61) { + if (total_day <= 31) { + // 10月 + temp = 9; + } else { + // 11 月 + total_day -= 31; + temp = 10; + } + } else { + // 12月 + total_day -= 61; + temp = 11; + } + } + } + + // 记录当前月份和天数 + this_tm->tm_mon = temp; // 月份 [0,11] + this_tm->tm_mday = total_day; // 天数 + + // 利用额外秒数计算时-分-秒 + temp = extra_second / 3600; + this_tm->tm_hour = temp; + extra_second = extra_second - temp * 3600; + + temp = extra_second / 60; + this_tm->tm_min = temp; + extra_second = extra_second - temp * 60; + + this_tm->tm_sec = extra_second; + + // 计算出当前日期的星期数 + this_tm->tm_wday = time_get_week(this_tm); + + // 夏令时不明 + this_tm->tm_isdst = -1; + } + return TIME_OK; +} + +// 由标准UTC时间生成Unix时间戳 +status utc_struct_time_to_unix_time(const _tm* this_tm, int64_t* unix_time) { + int32_t total_day, total_leap_year, dyear; + int february_offset; // 二月偏移量,零时变量 + // 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 + // 每个月份对应前面所有月的天数 + const int month_day[] = {0, 31, 59, 90, 120, 151, + 181, 212, 243, 273, 304, 334}; + + // 每天总秒数一定,将UTC时间(年月)转换成天数 + // 为了减少额外闰年判断,把时间往前推到1600年,即闰年最大的一次公倍数开始计算判断 + // 1970-1600 = 370 年 ,370/4 -(370/100-1)=90 个闰年 + // 1600 DAY_OFFSET 365*(1970-1600)+90 = 135140,7为修正天数 + + if (this_tm->tm_year < 1970) { + // 暂不支持1970之前的时间 + *unix_time = 0; + return TIME_LESS_THAN_1970; + } + if (this_tm->tm_year >= 3200) { + // 暂不支持3200及以后的时间 + *unix_time = 0; + return TIME_OVER_3200; + } + + // 计算总年数要去掉尾巴,如年数20年,那么实际应该4个闰年,因为20这一年没有包含在里面 + // 要减去一年来算闰年次数 + // 先计算到相对1600年的天数,再转换到1970年 + dyear = this_tm->tm_year - YEAR_START - 1; + total_leap_year = dyear / 4 - (dyear / 100 - dyear / 400 - 1); + // 恢复减去的一年 + dyear += 1; + total_day = dyear * 365 + total_leap_year; + + // 减去1970到1600的总天数 + total_day -= DAY_OFFSET; + + // 增加月和日的总天数 + // 判断是否是闰年 + // 能被4整除且不被100整除或者能被400整除 + if (((dyear % 4 == 0) && (dyear % 100 != 0)) || (dyear % 400 == 0)) { + // 闰年 + february_offset = 1; + } else { + february_offset = 0; + } + + // 计算含月和日的总天数,日期要减去当天 + total_day += month_day[this_tm->tm_mon] + this_tm->tm_mday - 1; + // 二月以上需要加上偏移量 + if (this_tm->tm_mon > 1) { + total_day += february_offset; + } + + // 根据天数以及时分秒计算Unix时间戳 + *unix_time = (int64_t)total_day * DAY_SECOND + this_tm->tm_hour * 3600 + + this_tm->tm_min * 60 + this_tm->tm_sec; + + return TIME_OK; +} + +void time_struct_format(const _tm* this_tm, char* str) { + sprintf(str, + "time.struct_time(tm_year=%d, tm_mon=%d,tm_mday=%d, tm_hour=%d, " + "tm_min=%d, tm_sec=%d, tm_wday=%d,tm_yday=%d, tm_isdst=%d)", + this_tm->tm_year, this_tm->tm_mon + 1, this_tm->tm_mday, + this_tm->tm_hour, this_tm->tm_min, this_tm->tm_sec, + this_tm->tm_wday, this_tm->tm_yday, this_tm->tm_isdst); +} + +// 标准库函数gmtime,将以自 epoch 开始的秒数表示的时间转换为 UTC 的 struct_time +void time_gmtime(pika_float unix_time, _tm* this_tm) { + status res; + // 转化时间 + res = unix_time_to_utc_struct_time(this_tm, (int64_t)unix_time); + if (res) { + status_deal(res); // 异常情况处理 + // 返回默认值 + // note: 异常情况返回默认时间起始点 + unix_time_to_utc_struct_time(this_tm, (int64_t)0); + } +} + +// 标准库函数localtime,将以自 epoch 开始的秒数表示的时间转换为当地时间的 +// struct_time +void time_localtime(pika_float unix_time, _tm* this_tm, int locale) { + status res; + int local_offset; + + // 获取本地时间偏移量(小时) + local_offset = locale * 60 * 60; + + // 转化时间 + res = unix_time_to_utc_struct_time(this_tm, + (int64_t)unix_time + local_offset); + if (res) { + status_deal(res); // 异常情况处理 + // 这里处理的策略和标准库不同,标准库最初始的时间是1970-1-1,00:00:00,对于不同时区来说,其值是不一样的 + // 但本函数是要求各时区的起始时间不超过1970-1-1,00:00:00,实际上UTC时间可以更前,可靠的最早时间可到1600年 + // 对于西时区来说,时间会缺失 + unix_time_to_utc_struct_time(this_tm, (int64_t)0); + } +} + +// 检测结构体时间是否在合适的范围内,但不检查它的正确性 +status time_check_struct_time(const _tm* this_tm) { + if (this_tm->tm_sec < 0 || this_tm->tm_sec > 60) { + return TIME_ERROR_STRUCT_TIME; + } + if (this_tm->tm_min < 0 || this_tm->tm_min > 59) { + return TIME_ERROR_STRUCT_TIME; + } + if (this_tm->tm_hour < 0 || this_tm->tm_hour > 23) { + return TIME_ERROR_STRUCT_TIME; + } + if (this_tm->tm_mday < 1 || this_tm->tm_mday > 31) { + return TIME_ERROR_STRUCT_TIME; + } + if (this_tm->tm_mon < 0 || this_tm->tm_mon > 11) { + return TIME_ERROR_STRUCT_TIME; + } + if (this_tm->tm_wday < 0 || this_tm->tm_wday > 6) { + return TIME_ERROR_STRUCT_TIME; + } + if (this_tm->tm_yday < 0 || this_tm->tm_yday > 366) { + return TIME_ERROR_STRUCT_TIME; + } + return TIME_OK; +} + +// 标准库函数mktime(t),将当地时间的 +// struct_time转换为以自epoch开始的秒数表示的时间 +int64_t time_mktime(const _tm* this_tm, int locale) { + status res; + int local_offset; + int64_t unix_time; + + // 获取本地时间偏移量(小时) + local_offset = locale * 60 * 60; + + // 检测时间结构体范围正确性 + res = time_check_struct_time(this_tm); + if (res) { + status_deal(res); + return 0; + } // 异常情况返回时间零点 + + // 转化时间 + res = utc_struct_time_to_unix_time(this_tm, &unix_time); + if (res) { + status_deal(res); + return 0; + } // 异常情况返回时间零点 + // 减去本地偏移时间 + // 可能出现负数,严格来说,这不影响什么! + unix_time -= local_offset; + + // 显示出来 + // time_printf("%I64d\n",unix_time); + + // 返回数据 + return unix_time; +} + +// 标准库函数asctime() +// 把结构化时间struct_time元组表示为以下形式的字符串: `'Sun Jun 20 23:21:05 +// 1993'`。 +void time_asctime(const _tm* this_tm) { + // 星期缩写,python标准库是三个字母,这里并不相同 + const char* week[] = {"Sun", "Mon", "Tues", "Wed", "Thur", "Fri", "Sat"}; + // 月份缩写 + const char* month[] = {"Jan", "Feb", "Mar", "Apr", "May", "Jun", + "Jul", "Aug", "Sept", "Oct", "Nov", "Dec"}; + + char str[100]; + + sprintf(str, "%s %s %d %02d:%02d:%02d %d", week[this_tm->tm_wday], + month[this_tm->tm_mon], this_tm->tm_mday, this_tm->tm_hour, + this_tm->tm_min, this_tm->tm_sec, this_tm->tm_year); + time_printf("%s\n", str); +} + +pika_float _time_time(PikaObj* self) { + /* run platformGetTick() */ + PIKA_PYTHON_BEGIN + /* clang-format off */ + PIKA_PYTHON( + platformGetTick() + ) + /* clang-format on */ + const uint8_t bytes[] = { + 0x04, 0x00, 0x00, 0x00, /* instruct array size */ + 0x00, 0x82, 0x01, 0x00, /* instruct array */ + 0x11, 0x00, 0x00, 0x00, /* const pool size */ + 0x00, 0x70, 0x6c, 0x61, 0x74, 0x66, 0x6f, 0x72, 0x6d, + 0x47, 0x65, 0x74, 0x54, 0x69, 0x63, 0x6b, 0x00, /* const pool */ + }; + PIKA_PYTHON_END + pikaVM_runByteCode(self, (uint8_t*)bytes); + return time_time(self); +} + +int _time_time_ns(PikaObj* self) { + return time_time_ns(self); +} + +void time_set_tm_value(PikaObj* self, const _tm* this_tm) { +#if !PIKA_STD_DEVICE_UNIX_TIME_ENABLE + obj_setErrorCode(self, 1); + obj_setSysOut( + self, "[error] PIKA_STD_DEVICE_UNIX_TIME_ENABLE need to be enable."); +#else + + obj_setInt(self, "tm_sec", this_tm->tm_sec); + obj_setInt(self, "tm_min", this_tm->tm_min); + obj_setInt(self, "tm_hour", this_tm->tm_hour); + obj_setInt(self, "tm_mday", this_tm->tm_mday); + obj_setInt(self, "tm_mon", this_tm->tm_mon); + obj_setInt(self, "tm_year", this_tm->tm_year); + obj_setInt(self, "tm_wday", this_tm->tm_wday); + obj_setInt(self, "tm_yday", this_tm->tm_yday); + obj_setInt(self, "tm_isdst", this_tm->tm_isdst); + +#endif +} + +void _time_gmtime(PikaObj* self, pika_float unix_time) { +#if !PIKA_STD_DEVICE_UNIX_TIME_ENABLE + obj_setErrorCode(self, 1); + obj_setSysOut( + self, "[error] PIKA_STD_DEVICE_UNIX_TIME_ENABLE need to be enable."); +#else + _tm this_tm; + char str[200]; + time_gmtime(unix_time, &this_tm); + time_set_tm_value(self, &this_tm); + // 格式化字符 + time_struct_format(&this_tm, str); + // 显示出来 + time_printf("%s\n", str); +#endif +} + +void _time_localtime(PikaObj* self, pika_float unix_time) { +#if !PIKA_STD_DEVICE_UNIX_TIME_ENABLE + obj_setErrorCode(self, 1); + obj_setSysOut( + self, "[error] PIKA_STD_DEVICE_UNIX_TIME_ENABLE need to be enable."); +#else + _tm this_tm; + char str[200]; + int locale = obj_getInt(self, "locale"); + time_localtime(unix_time, &this_tm, locale); + time_set_tm_value(self, &this_tm); + // 格式化字符 + time_struct_format(&this_tm, str); + // 显示出来 + time_printf("%s\n", str); +#endif +} + +void time_get_tm_value(PikaObj* self, _tm* this_tm) { +#if !PIKA_STD_DEVICE_UNIX_TIME_ENABLE + obj_setErrorCode(self, 1); + obj_setSysOut( + self, "[error] PIKA_STD_DEVICE_UNIX_TIME_ENABLE need to be enable."); +#else + this_tm->tm_sec = obj_getInt(self, "tm_sec"); + this_tm->tm_min = obj_getInt(self, "tm_min"); + this_tm->tm_hour = obj_getInt(self, "tm_hour"); + this_tm->tm_mday = obj_getInt(self, "tm_mday"); + this_tm->tm_mon = obj_getInt(self, "tm_mon"); + this_tm->tm_year = obj_getInt(self, "tm_year"); + this_tm->tm_wday = obj_getInt(self, "tm_wday"); + this_tm->tm_yday = obj_getInt(self, "tm_yday"); + this_tm->tm_isdst = obj_getInt(self, "tm_isdst"); +#endif +} + +int _time_mktime(PikaObj* self) { +#if !PIKA_STD_DEVICE_UNIX_TIME_ENABLE + obj_setErrorCode(self, 1); + obj_setSysOut( + self, "[error] PIKA_STD_DEVICE_UNIX_TIME_ENABLE need to be enable."); + return 0; +#else + _tm this_tm; + int locale = obj_getInt(self, "locale"); + time_get_tm_value(self, &this_tm); + return time_mktime(&this_tm, locale); +#endif +} + +void _time_asctime(PikaObj* self) { +#if !PIKA_STD_DEVICE_UNIX_TIME_ENABLE + obj_setErrorCode(self, 1); + obj_setSysOut( + self, "[error] PIKA_STD_DEVICE_UNIX_TIME_ENABLE need to be enable."); +#else + _tm this_tm; + time_get_tm_value(self, &this_tm); + time_asctime(&this_tm); +#endif +} +void _time_ctime(PikaObj* self, pika_float unix_time) { +#if !PIKA_STD_DEVICE_UNIX_TIME_ENABLE + obj_setErrorCode(self, 1); + obj_setSysOut( + self, "[error] PIKA_STD_DEVICE_UNIX_TIME_ENABLE need to be enable."); +#else + _tm this_tm; + int locale = obj_getInt(self, "locale"); + time_localtime(unix_time, &this_tm, locale); + time_asctime(&this_tm); +#endif +} + +void _time___init__(PikaObj* self) { + if (-1 == pika_platform_get_tick()) { + global_do_sleep_ms = pika_platform_sleep_ms; + } else { + global_do_sleep_ms = _do_sleep_ms_tick; + } +#if !PIKA_STD_DEVICE_UNIX_TIME_ENABLE +#else + _tm this_tm; + obj_setInt(self, "locale", 8); + time_localtime(0.0, &this_tm, 8); + time_set_tm_value(self, &this_tm); +#endif +} diff --git a/examples/pikapython/pikapython/pikascript-lib/unittest/README.md b/examples/pikapython/pikapython/pikascript-lib/unittest/README.md new file mode 100755 index 00000000..7d9d6e06 --- /dev/null +++ b/examples/pikapython/pikapython/pikascript-lib/unittest/README.md @@ -0,0 +1 @@ +# unittest diff --git a/examples/pikapython/pikapython/random.pyi b/examples/pikapython/pikapython/random.pyi new file mode 100755 index 00000000..4761de5a --- /dev/null +++ b/examples/pikapython/pikapython/random.pyi @@ -0,0 +1,30 @@ +def __init__(self): + """ + Initialize the random number generator. + """ + +def random() -> float: + """ + Return a random float in the range [0.0, 1.0). + """ + +def randint(a: int, b: int) -> int: + """ + Return a random integer in the range [a, b], including both end points. + """ + +def randrange(start: int, stop: int, step: int) -> int: + """ + Return a randomly-selected element from range(start, stop, step). + """ + +def seed(a: int) -> None: + """ + Initialize the random number generator. + """ + +def uniform(a: float, b: float) -> float: + """ + Return a random float in the range [a, b). + """ + diff --git a/examples/pikapython/pikapython/re.pyi b/examples/pikapython/pikapython/re.pyi new file mode 100755 index 00000000..58f6ff62 --- /dev/null +++ b/examples/pikapython/pikapython/re.pyi @@ -0,0 +1,77 @@ +from PikaObj import * + +A: int +ASCII: int +I: int +IGNORECASE: int +M: int +MULTILINE: int +S: int +DOTALL: int +# here, not as in python, there is no 'UNICODE' flags, +# cause this version only support UTF-8 characters + + +def __init__(): ... + + +class Pattern: + def __init__(self): + pass + + def __del__(self): + pass + + def findall(self, subject: str, *flags) -> list: + pass + + def sub(self, repl: str, subjet: str, *count__flags) -> str: + pass + + def subn(self, repl: str, subjet: str, *count__flags) -> list: + pass + + def match(self, subject: str, *flags) -> Match: + pass + + def fullmatch(self, subject: str, *flags) -> Match: + pass + + def search(self, subject: str, *flags) -> Match: + pass + + def split(self, subject: str, *maxsplit__flags) -> list: + pass + + +class Match: + def __init__(self): + pass + + def __del__(self): + pass + + def group(self, *n) -> str: + pass + + def groups(self) -> list: + pass + # ! may returns wrong offset when subject contains widechar, like Chinese + # this function returns exactly memory offset between the begin of string and the target substring + def span(self, *group_n) -> list: + pass + + +def findall(pattern: str, subject: str, *flags) -> list: ... +# def sub(pattern, repl, string, count=0, flags=0) +def sub(pattern: str, repl: str, subjet: str, *count__flags) -> str: ... +def match(pattern: str, subject: str, *flags) -> Match: ... +def fullmatch(pattern: str, subject: str, *flags) -> Match: ... +def search(pattern: str, subject: str, *flags) -> Match: ... +def compile(pattern: str, *flags) -> Pattern: ... + +def escape(pattern: str) -> str: ... +# def subn(pattern, repl, string, count=0, flags=0) +def subn(pattern: str, repl: str, subjet: str, *count__flags) -> list: ... +# def finditer(pattern: str, subject: str, *flags): +def split(pattern: str, subject: str, *maxsplit__flags) -> list: ... diff --git a/examples/pikapython/pikapython/requestment.txt b/examples/pikapython/pikapython/requestment.txt index cc568171..0e28e69b 100644 --- a/examples/pikapython/pikapython/requestment.txt +++ b/examples/pikapython/pikapython/requestment.txt @@ -1,2 +1,15 @@ -pikascript-core==v1.12.0 -PikaStdLib==v1.12.0 \ No newline at end of file +pikascript-core==latest +PikaStdLib==latest +PikaStdDevice==v2.3.5 +configparser==v0.2.1 +pika_cjson==v1.2.1 +json==v0.1.1 +PikaMath==v0.2.1 +unittest==v0.1.2 +re==v0.1.1 +binascii==v0.0.1 +modbus==v0.0.3 +time==v0.1.3 +pika_lvgl==v0.4.3 +_thread==v0.0.2 +random==v0.1.1 \ No newline at end of file diff --git a/examples/pikapython/pikapython/rust-msc-latest-win10.exe b/examples/pikapython/pikapython/rust-msc-latest-win10.exe index e9d36d4d..612ef8c3 100755 Binary files a/examples/pikapython/pikapython/rust-msc-latest-win10.exe and b/examples/pikapython/pikapython/rust-msc-latest-win10.exe differ diff --git a/examples/pikapython/pikapython/time.py b/examples/pikapython/pikapython/time.py new file mode 100755 index 00000000..8c6392a7 --- /dev/null +++ b/examples/pikapython/pikapython/time.py @@ -0,0 +1,43 @@ +import _time + + +def sleep(s: float): + for i in range(int(s)): + _time.sleep_s(1) + _time.sleep_ms(int((s - int(s)) * 1000)) + + +def sleep_s(s: int): + return _time.sleep_s(s) + + +def sleep_ms(ms: int): + return _time.sleep_ms(ms) + + +def time() -> float: + return _time.time() + + +def time_ns() -> int: + return _time.time_ns() + + +def gmtime(unix_time: float): + return _time.gmtime(unix_time) + + +def localtime(unix_time: float): + return _time.localtime(unix_time) + + +def mktime() -> int: + return _time.mktime() + + +def asctime() -> str: + return _time.asctime() + + +def ctime(unix_time: float) -> str: + return _time.ctime(unix_time) diff --git a/examples/pikapython/pikapython/unittest.py b/examples/pikapython/pikapython/unittest.py new file mode 100755 index 00000000..48a0f20e --- /dev/null +++ b/examples/pikapython/pikapython/unittest.py @@ -0,0 +1,121 @@ +import PikaStdLib +mem = PikaStdLib.MemChecker() + +class TestResult: + def __init__(self): + self.errorsNum = 0 + self.failuresNum = 0 + self.skippedNum = 0 + self.testsRun = 0 + self.errors = [] + self.failures = [] + self.skipped = [] + self._newFailures = 0 + + def wasSuccessful(self): + return self.errorsNum == 0 and self.failuresNum == 0 + + def __str__(self): + # Format is compatible with CPython. + return "" % ( + self.testsRun, self.errorsNum, self.failuresNum, self.skippedNum) + + +class TestCase: + def assertEqual(self, x, y): + msg = "%r vs (expected) %r" % (x, y) + assert x == y, msg + + def assertNotEqual(self, x, y): + msg = "%r not expected to be equal %r" % (x, y) + assert x != y, msg + + def assertLessEqual(self, x, y): + msg = "%r is expected to be <= %r" % (x, y) + assert x <= y, msg + + def assertGreaterEqual(self, x, y): + msg = "%r is expected to be >= %r" % (x, y) + assert x >= y, msg + + def assertTrue(self, x): + msg = "Expected %r to be True" % x + assert x, msg + + def assertFalse(self, x): + msg = "Expected %r to be False" % x + assert not x, msg + + def assertIs(self, x, y): + msg = "%r is not %r" % (x, y) + assert x is y, msg + + def assertIsNot(self, x, y): + msg = "%r is %r" % (x, y) + assert x is not y, msg + + def assertIsNone(self, x): + msg = "%r is not None" % x + assert x is None, msg + + def assertIsNotNone(self, x): + msg = "%r is None" % x + assert x is not None, msg + + def assertIn(self, x, y): + msg = "Expected %r to be in %r" % (x, y) + assert x in y, msg + + def run(self, result: TestResult, suite_name): + for name in dir(self): + if name.startswith("test"): + result.testsRun += 1 + self.test_fn = getattr(self, name) + print("[ RUN ] %s.%s" % (suite_name, name)) + try: + mem_before = 0.0 + mem_after = 0.0 + mem_before = mem.getNow() + self.test_fn() + mem_after = mem.getNow() + print("[ OK ] %s.%s" % (suite_name, name)) + if mem_after != mem_before: + print("[ MEM LACK ]", mem_after - mem_before) + except: + print("[ FAILED ] %s.%s" % (suite_name, name)) + result.errorsNum += 1 + + +class TestSuite: + def __init__(self, name): + self._tests = [] + self.name = name + + def addTest(self, case): + self._tests.append(case) + + def run(self, result: TestResult): + for case in self._tests: + case.run(result, self.name) + return result + + +class TextTestRunner: + def run(self, suite: TestSuite): + res = TestResult() + print("[----------] tests from %s" % suite.name) + _ = suite.run(res) + print("[----------] %d tests from %s" % res.testsRun, suite.name) + print('') + print('[==========]') + if res.failuresNum > 0 or res.errorsNum > 0: + print("[ FAILED ] (%d errors, %d failures)" % ( + res.errorsNum, res.failuresNum)) + else: + msg = "" + if res.skippedNum > 0: + msg += " (skipped=%d)" % res.skippedNum + print(msg) + print("[ PASSED ] %d tests" % res.testsRun) + + return res diff --git a/examples/pikapython/proj.conf b/examples/pikapython/proj.conf index 38cabb5f..0c90cb3b 100644 --- a/examples/pikapython/proj.conf +++ b/examples/pikapython/proj.conf @@ -1,8 +1,11 @@ -set(CONFIG_VLIBC 1) -set(CONFIG_VLIBC_FATFS 1) +set(CONFIG_VLIBC 0) -set(CONFIG_BFLOG 1) +set(CONFIG_VSNPRINTF_FLOAT 1) +set(CONFIG_VSNPRINTF_FLOAT_EX 1) +set(CONFIG_VSNPRINTF_LONG_LONG 1) +set(CONFIG_FREERTOS 1) +# set(CONFIG_LWIP 1) set(CONFIG_FATFS 1) - -set(CONFIG_BSP_SDH_SDCARD 1) -set(CONFIG_BSP_FATFS_SDH_SDCARD 1) \ No newline at end of file +set(CONFIG_LVGL 1) +set(CONFIG_BSP_LCD 1) +set(CONFIG_BSP_TOUCH 1) \ No newline at end of file