mirror of
https://github.com/nodemcu/nodemcu-firmware.git
synced 2025-01-30 21:12:55 +08:00
merge from dev
This commit is contained in:
commit
d5731dd9bd
100
README.md
100
README.md
@ -7,6 +7,7 @@ version 0.9.5
|
||||
###A lua based firmware for wifi-soc esp8266
|
||||
Build on [ESP8266 sdk 0.9.5](http://bbs.espressif.com/viewtopic.php?f=5&t=154)<br />
|
||||
Lua core based on [eLua project](http://www.eluaproject.net/)<br />
|
||||
cjson based on [lua-cjson](https://github.com/mpx/lua-cjson)<br />
|
||||
File system based on [spiffs](https://github.com/pellepl/spiffs)<br />
|
||||
Open source development kit for NodeMCU [nodemcu-devkit](https://github.com/nodemcu/nodemcu-devkit)<br />
|
||||
Flash tool for NodeMCU [nodemcu-flasher](https://github.com/nodemcu/nodemcu-flasher)<br />
|
||||
@ -22,8 +23,9 @@ Tencent QQ group: 309957875<br />
|
||||
- Easy to access wireless router
|
||||
- Based on Lua 5.1.4 (without *debug, os* module.)
|
||||
- Event-Drive programming preferred.
|
||||
- Build-in file, timer, pwm, i2c, spi, 1-wire, net, mqtt, coap, gpio, wifi, adc, uart and system api.
|
||||
- Build-in json, file, timer, pwm, i2c, spi, 1-wire, net, mqtt, coap, gpio, wifi, adc, uart and system api.
|
||||
- GPIO pin re-mapped, use the index to access gpio, i2c, pwm.
|
||||
- Both Integer(less memory usage) and Float version firmware provided.
|
||||
|
||||
# To Do List (pull requests are very welcomed)
|
||||
- loadable c module
|
||||
@ -34,6 +36,14 @@ Tencent QQ group: 309957875<br />
|
||||
- cross compiler (done)
|
||||
|
||||
# Change log
|
||||
2015-03-18<br />
|
||||
update u8glib.<br />
|
||||
merge everything to master.
|
||||
|
||||
2015-03-17<br />
|
||||
add cjson module, only cjson.encode() and cjson.decode() is implemented.<br />
|
||||
read doc [here](https://github.com/nodemcu/nodemcu-firmware/blob/master/app/cjson/manual.txt)
|
||||
|
||||
2015-03-15<br />
|
||||
bugs fixed: #239, #273.<br />
|
||||
reduce coap module memory usage, add coap module to default built.
|
||||
@ -58,32 +68,6 @@ raise internal LUA_BUFFERSIZE from 1024 to 4096.<br />
|
||||
lua require("mod") will load "mod.lc" file first if exist.<br />
|
||||
build latest pre_build bin.
|
||||
|
||||
2015-02-12<br />
|
||||
fix float print.<br />
|
||||
update spiffs, add file.rename api to file module.<br />
|
||||
fix some file system bug. need more tests.<br />
|
||||
add support to 8Mbyte, 16Mbyte flash.<br />
|
||||
remove node.led() and node.key() api.<br />
|
||||
some update to lua_modules and examples.<br />
|
||||
build latest pre_build bin.
|
||||
|
||||
2015-01-27<br />
|
||||
support floating point LUA.<br />
|
||||
use macro LUA_NUMBER_INTEGRAL in user_config.h control this feature.<br />
|
||||
LUA_NUMBER_INTEGRAL to disable floating point support,<br />
|
||||
// LUA_NUMBER_INTEGRAL to enable floating point support.<br />
|
||||
fix tmr.time(). #132<br />
|
||||
fix filesystem length. #113<br />
|
||||
fix ssl reboots. #134<br />
|
||||
build pre_build bin.
|
||||
|
||||
2015-01-26<br />
|
||||
applied sdk095_patch1 to sdk 0.9.5.<br />
|
||||
added LUA examples and modules [by dvv](https://github.com/dvv). <br />
|
||||
added node.readvdd33() API [by alonewolfx2](https://github.com/alonewolfx2).<br />
|
||||
build pre_build bin.
|
||||
|
||||
|
||||
[more change log](https://github.com/nodemcu/nodemcu-firmware/wiki)<br />
|
||||
|
||||
##GPIO NEW TABLE ( Build 20141219 and later)
|
||||
@ -149,9 +133,10 @@ build pre_build bin.
|
||||
#define LUA_USE_MODULES_OW
|
||||
#define LUA_USE_MODULES_BIT
|
||||
#define LUA_USE_MODULES_MQTT
|
||||
// #define LUA_USE_MODULES_COAP // need about 4k more ram for now
|
||||
// #define LUA_USE_MODULES_COAP
|
||||
#define LUA_USE_MODULES_U8G
|
||||
#define LUA_USE_MODULES_WS2812
|
||||
#define LUA_USE_MODULES_CJSON
|
||||
#endif /* LUA_USE_MODULES */
|
||||
```
|
||||
|
||||
@ -364,24 +349,51 @@ The integration in nodemcu is developed for SSD1306 based display attached via t
|
||||
U8glib v1.17
|
||||
|
||||
#####I2C connection
|
||||
Hook up SDA and SCL to any free GPIOs. Eg. [lua_examples/graphics_test.lua](https://github.com/devsaurus/nodemcu-firmware/blob/dev/lua_examples/graphics_test.lua) expects SDA=5 (GPIO14) and SCL=6 (GPIO12). They are used to set up nodemcu's I2C driver before accessing the display:
|
||||
Hook up SDA and SCL to any free GPIOs. Eg. `lua_examples/u8glib/graphics_test.lua` expects SDA=5 (GPIO14) and SCL=6 (GPIO12). They are used to set up nodemcu's I2C driver before accessing the display:
|
||||
```lua
|
||||
sda = 5
|
||||
scl = 6
|
||||
i2c.setup(0, sda, scl, i2c.SLOW)
|
||||
```
|
||||
|
||||
#####SPI connection
|
||||
The HSPI module is used, so certain pins are fixed:
|
||||
* HSPI CLK = GPIO14
|
||||
* HSPI MOSI = GPIO13
|
||||
* HSPI MISO = GPIO12 (not used)
|
||||
|
||||
All other pins can be assigned to any available GPIO:
|
||||
* CS
|
||||
* D/C
|
||||
* RES (optional for some displays)
|
||||
|
||||
Also refer to the initialization sequence eg in `lua_examples/u8glib/graphics_test.lua`:
|
||||
```lua
|
||||
spi.setup(1, spi.MASTER, spi.CPOL_LOW, spi.CPHA_LOW, spi.DATABITS_8, 0)
|
||||
```
|
||||
|
||||
|
||||
#####Library usage
|
||||
The Lua bindings for this library closely follow u8glib's object oriented C++ API. Based on the u8g class, you create an object for your display type:
|
||||
The Lua bindings for this library closely follow u8glib's object oriented C++ API. Based on the u8g class, you create an object for your display type.
|
||||
|
||||
SSD1306 via I2C:
|
||||
```lua
|
||||
sla = 0x3c
|
||||
disp = u8g.ssd1306_128x64_i2c(sla)
|
||||
```
|
||||
SSD1306 via SPI:
|
||||
```lua
|
||||
cs = 8 -- GPIO15, pull-down 10k to GND
|
||||
dc = 4 -- GPIO2
|
||||
res = 0 -- GPIO16, RES is optional YMMV
|
||||
disp = u8g.ssd1306_128x64_spi(cs, dc, res)
|
||||
```
|
||||
|
||||
This object provides all of u8glib's methods to control the display.
|
||||
Again, refer to [lua_examples/graphics_test.lua](https://github.com/devsaurus/nodemcu-firmware/blob/dev/lua_examples/u8g_graphics_test.lua) to get an impression how this is achieved with Lua code. Visit the [u8glib homepage](https://code.google.com/p/u8glib/) for technical details.
|
||||
Again, refer to `lua_examples/u8glib/graphics_test.lua` to get an impression how this is achieved with Lua code. Visit the [u8glib homepage](https://code.google.com/p/u8glib/) for technical details.
|
||||
|
||||
#####Fonts
|
||||
u8glib comes with a wide range of fonts for small displays. Since they need to be compiled into the firmware image, you'd need to include them in [app/include/user_config.h](https://github.com/devsaurus/nodemcu-firmware/blob/dev/app/include/user_config.h) and recompile. Simply add the desired fonts to the font table:
|
||||
u8glib comes with a wide range of fonts for small displays. Since they need to be compiled into the firmware image, you'd need to include them in `app/include/u8g_config.h` and recompile. Simply add the desired fonts to the font table:
|
||||
```c
|
||||
#define U8G_FONT_TABLE \
|
||||
U8G_FONT_TABLE_ENTRY(font_6x10) \
|
||||
@ -389,6 +401,9 @@ u8glib comes with a wide range of fonts for small displays. Since they need to b
|
||||
```
|
||||
They'll be available as `u8g.<font_name>` in Lua.
|
||||
|
||||
#####Bitmaps
|
||||
Bitmaps and XBMs are supplied as strings to `drawBitmap()` and `drawXBM()`. This off-loads all data handling from the u8g module to generic methods for binary files. See `lua_examples/u8glib/u8g_bitmaps.lua`. Binary files can be uploaded with [nodemcu-uploader.py](https://github.com/kmpm/nodemcu-uploader).
|
||||
|
||||
#####Unimplemented functions
|
||||
- [ ] Cursor handling
|
||||
- [ ] disableCursor()
|
||||
@ -397,12 +412,7 @@ They'll be available as `u8g.<font_name>` in Lua.
|
||||
- [ ] setCursorFont()
|
||||
- [ ] setCursorPos()
|
||||
- [ ] setCursorStyle()
|
||||
- [ ] Bitmaps
|
||||
- [ ] drawBitmap()
|
||||
- [ ] drawXBM()
|
||||
- [ ] General functions
|
||||
- [x] begin()
|
||||
- [ ] print()
|
||||
- [ ] setContrast()
|
||||
- [ ] setPrintPos()
|
||||
- [ ] setHardwareBackup()
|
||||
@ -439,4 +449,18 @@ cs:func("myfun") -- post coap://192.168.18.103:5683/v1/f/myfun will call myfun
|
||||
cc = coap.Client()
|
||||
cc:get(coap.CON, "coap://192.168.18.100:5683/.well-known/core")
|
||||
cc:post(coap.NON, "coap://192.168.18.100:5683/", "Hello")
|
||||
```
|
||||
```
|
||||
|
||||
####cjson
|
||||
|
||||
```lua
|
||||
-- Translate Lua value to/from JSON
|
||||
-- text = cjson.encode(value)
|
||||
-- value = cjson.decode(text)
|
||||
json_text = '[ true, { "foo": "bar" } ]'
|
||||
value = cjson.decode(json_text)
|
||||
-- Returns: { true, { foo = "bar" } }
|
||||
value = { true, { foo = "bar" } }
|
||||
json_text = cjson.encode(value)
|
||||
-- Returns: '[true,{"foo":"bar"}]'
|
||||
```
|
||||
|
@ -36,7 +36,8 @@ SUBDIRS= \
|
||||
smart \
|
||||
wofs \
|
||||
modules \
|
||||
spiffs
|
||||
spiffs \
|
||||
cjson
|
||||
|
||||
endif # } PDIR
|
||||
|
||||
@ -84,6 +85,7 @@ COMPONENTS_eagle.app.v6 = \
|
||||
smart/smart.a \
|
||||
wofs/wofs.a \
|
||||
spiffs/spiffs.a \
|
||||
cjson/libcjson.a \
|
||||
modules/libmodules.a
|
||||
|
||||
LINKFLAGS_eagle.app.v6 = \
|
||||
|
76
app/cjson/CMakeLists.txt
Normal file
76
app/cjson/CMakeLists.txt
Normal file
@ -0,0 +1,76 @@
|
||||
# If Lua is installed in a non-standard location, please set the LUA_DIR
|
||||
# environment variable to point to prefix for the install. Eg:
|
||||
# Unix: export LUA_DIR=/home/user/pkg
|
||||
# Windows: set LUA_DIR=c:\lua51
|
||||
|
||||
project(lua-cjson C)
|
||||
cmake_minimum_required(VERSION 2.6)
|
||||
|
||||
option(USE_INTERNAL_FPCONV "Use internal strtod() / g_fmt() code for performance")
|
||||
option(MULTIPLE_THREADS "Support multi-threaded apps with internal fpconv - recommended" ON)
|
||||
|
||||
if(NOT CMAKE_BUILD_TYPE)
|
||||
set(CMAKE_BUILD_TYPE Release CACHE STRING
|
||||
"Choose the type of build, options are: None Debug Release RelWithDebInfo MinSizeRel."
|
||||
FORCE)
|
||||
endif()
|
||||
|
||||
find_package(Lua51 REQUIRED)
|
||||
include_directories(${LUA_INCLUDE_DIR})
|
||||
|
||||
if(NOT USE_INTERNAL_FPCONV)
|
||||
# Use libc number conversion routines (strtod(), sprintf())
|
||||
set(FPCONV_SOURCES fpconv.c)
|
||||
else()
|
||||
# Use internal number conversion routines
|
||||
add_definitions(-DUSE_INTERNAL_FPCONV)
|
||||
set(FPCONV_SOURCES g_fmt.c dtoa.c)
|
||||
|
||||
include(TestBigEndian)
|
||||
TEST_BIG_ENDIAN(IEEE_BIG_ENDIAN)
|
||||
if(IEEE_BIG_ENDIAN)
|
||||
add_definitions(-DIEEE_BIG_ENDIAN)
|
||||
endif()
|
||||
|
||||
if(MULTIPLE_THREADS)
|
||||
set(CMAKE_THREAD_PREFER_PTHREAD TRUE)
|
||||
find_package(Threads REQUIRED)
|
||||
if(NOT CMAKE_USE_PTHREADS_INIT)
|
||||
message(FATAL_ERROR
|
||||
"Pthreads not found - required by MULTIPLE_THREADS option")
|
||||
endif()
|
||||
add_definitions(-DMULTIPLE_THREADS)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
# Handle platforms missing isinf() macro (Eg, some Solaris systems).
|
||||
include(CheckSymbolExists)
|
||||
CHECK_SYMBOL_EXISTS(isinf math.h HAVE_ISINF)
|
||||
if(NOT HAVE_ISINF)
|
||||
add_definitions(-DUSE_INTERNAL_ISINF)
|
||||
endif()
|
||||
|
||||
set(_MODULE_LINK "${CMAKE_THREAD_LIBS_INIT}")
|
||||
get_filename_component(_lua_lib_dir ${LUA_LIBRARY} PATH)
|
||||
|
||||
if(APPLE)
|
||||
set(CMAKE_SHARED_MODULE_CREATE_C_FLAGS
|
||||
"${CMAKE_SHARED_MODULE_CREATE_C_FLAGS} -undefined dynamic_lookup")
|
||||
endif()
|
||||
|
||||
if(WIN32)
|
||||
# Win32 modules need to be linked to the Lua library.
|
||||
set(_MODULE_LINK ${LUA_LIBRARY} ${_MODULE_LINK})
|
||||
set(_lua_module_dir "${_lua_lib_dir}")
|
||||
# Windows sprintf()/strtod() handle NaN/inf differently. Not supported.
|
||||
add_definitions(-DDISABLE_INVALID_NUMBERS)
|
||||
else()
|
||||
set(_lua_module_dir "${_lua_lib_dir}/lua/5.1")
|
||||
endif()
|
||||
|
||||
add_library(cjson MODULE lua_cjson.c strbuf.c ${FPCONV_SOURCES})
|
||||
set_target_properties(cjson PROPERTIES PREFIX "")
|
||||
target_link_libraries(cjson ${_MODULE_LINK})
|
||||
install(TARGETS cjson DESTINATION "${_lua_module_dir}")
|
||||
|
||||
# vi:ai et sw=4 ts=4:
|
21
app/cjson/LICENSE
Normal file
21
app/cjson/LICENSE
Normal file
@ -0,0 +1,21 @@
|
||||
Copyright (c) 2010-2012 Mark Pulford <mark@kyne.com.au>
|
||||
2015 Zeroday Hong <zeroday@nodemcu.com> nodemcu.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.
|
47
app/cjson/Makefile
Normal file
47
app/cjson/Makefile
Normal file
@ -0,0 +1,47 @@
|
||||
|
||||
#############################################################
|
||||
# Required variables for each makefile
|
||||
# Discard this section from all parent makefiles
|
||||
# Expected variables (with automatic defaults):
|
||||
# CSRCS (all "C" files in the dir)
|
||||
# SUBDIRS (all subdirs with a Makefile)
|
||||
# GEN_LIBS - list of libs to be generated ()
|
||||
# GEN_IMAGES - list of images to be generated ()
|
||||
# COMPONENTS_xxx - a list of libs/objs in the form
|
||||
# subdir/lib to be extracted and rolled up into
|
||||
# a generated lib/image xxx.a ()
|
||||
#
|
||||
ifndef PDIR
|
||||
|
||||
GEN_LIBS = libcjson.a
|
||||
|
||||
endif
|
||||
|
||||
|
||||
#############################################################
|
||||
# Configuration i.e. compile options etc.
|
||||
# Target specific stuff (defines etc.) goes in here!
|
||||
# Generally values applying to a tree are captured in the
|
||||
# makefile at its root level - these are then overridden
|
||||
# for a subtree within the makefile rooted therein
|
||||
#
|
||||
#DEFINES +=
|
||||
|
||||
#############################################################
|
||||
# Recursion Magic - Don't touch this!!
|
||||
#
|
||||
# Each subtree potentially has an include directory
|
||||
# corresponding to the common APIs applicable to modules
|
||||
# rooted at that subtree. Accordingly, the INCLUDE PATH
|
||||
# of a module can only contain the include directories up
|
||||
# its parent path, and not its siblings
|
||||
#
|
||||
# Required for each makefile to inherit from the parent
|
||||
#
|
||||
|
||||
INCLUDES := $(INCLUDES) -I $(PDIR)include
|
||||
INCLUDES += -I ./
|
||||
INCLUDES += -I ../libc
|
||||
PDIR := ../$(PDIR)
|
||||
sinclude $(PDIR)Makefile
|
||||
|
9
app/cjson/THANKS
Normal file
9
app/cjson/THANKS
Normal file
@ -0,0 +1,9 @@
|
||||
The following people have helped with bug reports, testing and/or
|
||||
suggestions:
|
||||
|
||||
- Louis-Philippe Perron (@loopole)
|
||||
- Ondřej Jirman
|
||||
- Steve Donovan <steve.j.donovan@gmail.com>
|
||||
- Zhang "agentzh" Yichun <agentzh@gmail.com>
|
||||
|
||||
Thanks!
|
50
app/cjson/devel/json_parser_outline.txt
Normal file
50
app/cjson/devel/json_parser_outline.txt
Normal file
@ -0,0 +1,50 @@
|
||||
parser:
|
||||
- call parse_value
|
||||
- next_token
|
||||
? <EOF> nop.
|
||||
|
||||
parse_value:
|
||||
- next_token
|
||||
? <OBJ_BEGIN> call parse_object.
|
||||
? <ARR_BEGIN> call parse_array.
|
||||
? <STRING> push. return.
|
||||
? <BOOLEAN> push. return.
|
||||
? <NULL> push. return.
|
||||
? <NUMBER> push. return.
|
||||
|
||||
parse_object:
|
||||
- push table
|
||||
- next_token
|
||||
? <STRING> push.
|
||||
- next_token
|
||||
? <COLON> nop.
|
||||
- call parse_value
|
||||
- set table
|
||||
- next_token
|
||||
? <OBJ_END> return.
|
||||
? <COMMA> loop parse_object.
|
||||
|
||||
parse_array:
|
||||
- push table
|
||||
- call parse_value
|
||||
- table append
|
||||
- next_token
|
||||
? <COMMA> loop parse_array.
|
||||
? ] return.
|
||||
|
||||
next_token:
|
||||
- check next character
|
||||
? { return <OBJ_BEGIN>
|
||||
? } return <OBJ_END>
|
||||
? [ return <ARR_BEGIN>
|
||||
? ] return <ARR_END>
|
||||
? , return <COMMA>
|
||||
? : return <COLON>
|
||||
? [-0-9] gobble number. return <NUMBER>
|
||||
? " gobble string. return <STRING>
|
||||
? [ \t\n] eat whitespace.
|
||||
? n Check "null". return <NULL> or <UNKNOWN>
|
||||
? t Check "true". return <BOOLEAN> or <UNKNOWN>
|
||||
? f Check "false". return <BOOLEAN> or <UNKNOWN>
|
||||
? . return <UNKNOWN>
|
||||
? \0 return <END>
|
4359
app/cjson/dtoa.c
Normal file
4359
app/cjson/dtoa.c
Normal file
File diff suppressed because it is too large
Load Diff
74
app/cjson/dtoa_config.h
Normal file
74
app/cjson/dtoa_config.h
Normal file
@ -0,0 +1,74 @@
|
||||
#ifndef _DTOA_CONFIG_H
|
||||
#define _DTOA_CONFIG_H
|
||||
#if 0
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
|
||||
/* Ensure dtoa.c does not USE_LOCALE. Lua CJSON must not use locale
|
||||
* aware conversion routines. */
|
||||
#undef USE_LOCALE
|
||||
|
||||
/* dtoa.c should not touch errno, Lua CJSON does not use it, and it
|
||||
* may not be threadsafe */
|
||||
#define NO_ERRNO
|
||||
|
||||
#define Long int32_t
|
||||
#define ULong uint32_t
|
||||
#define Llong int64_t
|
||||
#define ULLong uint64_t
|
||||
|
||||
#ifdef IEEE_BIG_ENDIAN
|
||||
#define IEEE_MC68k
|
||||
#else
|
||||
#define IEEE_8087
|
||||
#endif
|
||||
|
||||
#define MALLOC(n) xmalloc(n)
|
||||
|
||||
static void *xmalloc(size_t size)
|
||||
{
|
||||
void *p;
|
||||
|
||||
p = malloc(size);
|
||||
if (!p) {
|
||||
fprintf(stderr, "Out of memory");
|
||||
abort();
|
||||
}
|
||||
|
||||
return p;
|
||||
}
|
||||
|
||||
#ifdef MULTIPLE_THREADS
|
||||
|
||||
/* Enable locking to support multi-threaded applications */
|
||||
|
||||
#include <pthread.h>
|
||||
|
||||
static pthread_mutex_t private_dtoa_lock[2] = {
|
||||
PTHREAD_MUTEX_INITIALIZER,
|
||||
PTHREAD_MUTEX_INITIALIZER
|
||||
};
|
||||
|
||||
#define ACQUIRE_DTOA_LOCK(n) do { \
|
||||
int r = pthread_mutex_lock(&private_dtoa_lock[n]); \
|
||||
if (r) { \
|
||||
fprintf(stderr, "pthread_mutex_lock failed with %d\n", r); \
|
||||
abort(); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#define FREE_DTOA_LOCK(n) do { \
|
||||
int r = pthread_mutex_unlock(&private_dtoa_lock[n]); \
|
||||
if (r) { \
|
||||
fprintf(stderr, "pthread_mutex_unlock failed with %d\n", r);\
|
||||
abort(); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#endif /* MULTIPLE_THREADS */
|
||||
#endif
|
||||
#endif /* _DTOA_CONFIG_H */
|
||||
|
||||
/* vi:ai et sw=4 ts=4:
|
||||
*/
|
209
app/cjson/fpconv.c
Normal file
209
app/cjson/fpconv.c
Normal file
@ -0,0 +1,209 @@
|
||||
/* fpconv - Floating point conversion routines
|
||||
*
|
||||
* Copyright (c) 2011-2012 Mark Pulford <mark@kyne.com.au>
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/* JSON uses a '.' decimal separator. strtod() / sprintf() under C libraries
|
||||
* with locale support will break when the decimal separator is a comma.
|
||||
*
|
||||
* fpconv_* will around these issues with a translation buffer if required.
|
||||
*/
|
||||
|
||||
#include "c_stdio.h"
|
||||
#include "c_stdlib.h"
|
||||
// #include <assert.h>
|
||||
#include "c_string.h"
|
||||
|
||||
#include "fpconv.h"
|
||||
|
||||
#if 0
|
||||
/* Lua CJSON assumes the locale is the same for all threads within a
|
||||
* process and doesn't change after initialisation.
|
||||
*
|
||||
* This avoids the need for per thread storage or expensive checks
|
||||
* for call. */
|
||||
static char locale_decimal_point = '.';
|
||||
|
||||
/* In theory multibyte decimal_points are possible, but
|
||||
* Lua CJSON only supports UTF-8 and known locales only have
|
||||
* single byte decimal points ([.,]).
|
||||
*
|
||||
* localconv() may not be thread safe (=>crash), and nl_langinfo() is
|
||||
* not supported on some platforms. Use sprintf() instead - if the
|
||||
* locale does change, at least Lua CJSON won't crash. */
|
||||
static void fpconv_update_locale()
|
||||
{
|
||||
char buf[8];
|
||||
|
||||
c_sprintf(buf, "%g", 0.5);
|
||||
|
||||
/* Failing this test might imply the platform has a buggy dtoa
|
||||
* implementation or wide characters */
|
||||
if (buf[0] != '0' || buf[2] != '5' || buf[3] != 0) {
|
||||
NODE_ERR("Error: wide characters found or printf() bug.");
|
||||
return;
|
||||
}
|
||||
|
||||
locale_decimal_point = buf[1];
|
||||
}
|
||||
|
||||
/* Check for a valid number character: [-+0-9a-yA-Y.]
|
||||
* Eg: -0.6e+5, infinity, 0xF0.F0pF0
|
||||
*
|
||||
* Used to find the probable end of a number. It doesn't matter if
|
||||
* invalid characters are counted - strtod() will find the valid
|
||||
* number if it exists. The risk is that slightly more memory might
|
||||
* be allocated before a parse error occurs. */
|
||||
static inline int valid_number_character(char ch)
|
||||
{
|
||||
char lower_ch;
|
||||
|
||||
if ('0' <= ch && ch <= '9')
|
||||
return 1;
|
||||
if (ch == '-' || ch == '+' || ch == '.')
|
||||
return 1;
|
||||
|
||||
/* Hex digits, exponent (e), base (p), "infinity",.. */
|
||||
lower_ch = ch | 0x20;
|
||||
if ('a' <= lower_ch && lower_ch <= 'y')
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Calculate the size of the buffer required for a strtod locale
|
||||
* conversion. */
|
||||
static int strtod_buffer_size(const char *s)
|
||||
{
|
||||
const char *p = s;
|
||||
|
||||
while (valid_number_character(*p))
|
||||
p++;
|
||||
|
||||
return p - s;
|
||||
}
|
||||
|
||||
/* Similar to strtod(), but must be passed the current locale's decimal point
|
||||
* character. Guaranteed to be called at the start of any valid number in a string */
|
||||
double fpconv_strtod(const char *nptr, char **endptr)
|
||||
{
|
||||
char localbuf[FPCONV_G_FMT_BUFSIZE];
|
||||
char *buf, *endbuf, *dp;
|
||||
int buflen;
|
||||
double value;
|
||||
|
||||
/* System strtod() is fine when decimal point is '.' */
|
||||
if (locale_decimal_point == '.')
|
||||
return c_strtod(nptr, endptr);
|
||||
|
||||
buflen = strtod_buffer_size(nptr);
|
||||
if (!buflen) {
|
||||
/* No valid characters found, standard strtod() return */
|
||||
*endptr = (char *)nptr;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Duplicate number into buffer */
|
||||
if (buflen >= FPCONV_G_FMT_BUFSIZE) {
|
||||
/* Handle unusually large numbers */
|
||||
buf = c_malloc(buflen + 1);
|
||||
if (!buf) {
|
||||
NODE_ERR("not enough memory\n");
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
/* This is the common case.. */
|
||||
buf = localbuf;
|
||||
}
|
||||
c_memcpy(buf, nptr, buflen);
|
||||
buf[buflen] = 0;
|
||||
|
||||
/* Update decimal point character if found */
|
||||
dp = c_strchr(buf, '.');
|
||||
if (dp)
|
||||
*dp = locale_decimal_point;
|
||||
|
||||
value = c_strtod(buf, &endbuf);
|
||||
*endptr = (char *)&nptr[endbuf - buf];
|
||||
if (buflen >= FPCONV_G_FMT_BUFSIZE)
|
||||
c_free(buf);
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
/* "fmt" must point to a buffer of at least 6 characters */
|
||||
static void set_number_format(char *fmt, int precision)
|
||||
{
|
||||
int d1, d2, i;
|
||||
|
||||
if(!(1 <= precision && precision <= 14)) return;
|
||||
|
||||
/* Create printf format (%.14g) from precision */
|
||||
d1 = precision / 10;
|
||||
d2 = precision % 10;
|
||||
fmt[0] = '%';
|
||||
fmt[1] = '.';
|
||||
i = 2;
|
||||
if (d1) {
|
||||
fmt[i++] = '0' + d1;
|
||||
}
|
||||
fmt[i++] = '0' + d2;
|
||||
fmt[i++] = 'g';
|
||||
fmt[i] = 0;
|
||||
}
|
||||
|
||||
/* Assumes there is always at least 32 characters available in the target buffer */
|
||||
int fpconv_g_fmt(char *str, double num, int precision)
|
||||
{
|
||||
char buf[FPCONV_G_FMT_BUFSIZE];
|
||||
char fmt[6];
|
||||
int len;
|
||||
char *b;
|
||||
|
||||
set_number_format(fmt, precision);
|
||||
|
||||
/* Pass through when decimal point character is dot. */
|
||||
if (locale_decimal_point == '.'){
|
||||
c_sprintf(str, fmt, num);
|
||||
return c_strlen(str);
|
||||
}
|
||||
|
||||
/* snprintf() to a buffer then translate for other decimal point characters */
|
||||
c_sprintf(buf, fmt, num);
|
||||
len = c_strlen(buf);
|
||||
|
||||
/* Copy into target location. Translate decimal point if required */
|
||||
b = buf;
|
||||
do {
|
||||
*str++ = (*b == locale_decimal_point ? '.' : *b);
|
||||
} while(*b++);
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
void fpconv_init()
|
||||
{
|
||||
fpconv_update_locale();
|
||||
}
|
||||
#endif
|
||||
/* vi:ai et sw=4 ts=4:
|
||||
*/
|
22
app/cjson/fpconv.h
Normal file
22
app/cjson/fpconv.h
Normal file
@ -0,0 +1,22 @@
|
||||
/* Lua CJSON floating point conversion routines */
|
||||
|
||||
/* Buffer required to store the largest string representation of a double.
|
||||
*
|
||||
* Longest double printed with %.14g is 21 characters long:
|
||||
* -1.7976931348623e+308 */
|
||||
# define FPCONV_G_FMT_BUFSIZE 32
|
||||
|
||||
#ifdef USE_INTERNAL_FPCONV
|
||||
static inline void fpconv_init()
|
||||
{
|
||||
/* Do nothing - not required */
|
||||
}
|
||||
#else
|
||||
extern inline void fpconv_init();
|
||||
#endif
|
||||
|
||||
extern int fpconv_g_fmt(char*, double, int);
|
||||
extern double fpconv_strtod(const char*, char**);
|
||||
|
||||
/* vi:ai et sw=4 ts=4:
|
||||
*/
|
112
app/cjson/g_fmt.c
Normal file
112
app/cjson/g_fmt.c
Normal file
@ -0,0 +1,112 @@
|
||||
/****************************************************************
|
||||
*
|
||||
* The author of this software is David M. Gay.
|
||||
*
|
||||
* Copyright (c) 1991, 1996 by Lucent Technologies.
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software for any
|
||||
* purpose without fee is hereby granted, provided that this entire notice
|
||||
* is included in all copies of any software which is or includes a copy
|
||||
* or modification of this software and in all copies of the supporting
|
||||
* documentation for such software.
|
||||
*
|
||||
* THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
|
||||
* WARRANTY. IN PARTICULAR, NEITHER THE AUTHOR NOR LUCENT MAKES ANY
|
||||
* REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
|
||||
* OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
|
||||
*
|
||||
***************************************************************/
|
||||
|
||||
/* g_fmt(buf,x) stores the closest decimal approximation to x in buf;
|
||||
* it suffices to declare buf
|
||||
* char buf[32];
|
||||
*/
|
||||
#if 0
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
extern char *dtoa(double, int, int, int *, int *, char **);
|
||||
extern int g_fmt(char *, double, int);
|
||||
extern void freedtoa(char*);
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
int
|
||||
fpconv_g_fmt(char *b, double x, int precision)
|
||||
{
|
||||
register int i, k;
|
||||
register char *s;
|
||||
int decpt, j, sign;
|
||||
char *b0, *s0, *se;
|
||||
|
||||
b0 = b;
|
||||
#ifdef IGNORE_ZERO_SIGN
|
||||
if (!x) {
|
||||
*b++ = '0';
|
||||
*b = 0;
|
||||
goto done;
|
||||
}
|
||||
#endif
|
||||
s = s0 = dtoa(x, 2, precision, &decpt, &sign, &se);
|
||||
if (sign)
|
||||
*b++ = '-';
|
||||
if (decpt == 9999) /* Infinity or Nan */ {
|
||||
while((*b++ = *s++));
|
||||
/* "b" is used to calculate the return length. Decrement to exclude the
|
||||
* Null terminator from the length */
|
||||
b--;
|
||||
goto done0;
|
||||
}
|
||||
if (decpt <= -4 || decpt > precision) {
|
||||
*b++ = *s++;
|
||||
if (*s) {
|
||||
*b++ = '.';
|
||||
while((*b = *s++))
|
||||
b++;
|
||||
}
|
||||
*b++ = 'e';
|
||||
/* sprintf(b, "%+.2d", decpt - 1); */
|
||||
if (--decpt < 0) {
|
||||
*b++ = '-';
|
||||
decpt = -decpt;
|
||||
}
|
||||
else
|
||||
*b++ = '+';
|
||||
for(j = 2, k = 10; 10*k <= decpt; j++, k *= 10);
|
||||
for(;;) {
|
||||
i = decpt / k;
|
||||
*b++ = i + '0';
|
||||
if (--j <= 0)
|
||||
break;
|
||||
decpt -= i*k;
|
||||
decpt *= 10;
|
||||
}
|
||||
*b = 0;
|
||||
}
|
||||
else if (decpt <= 0) {
|
||||
*b++ = '0';
|
||||
*b++ = '.';
|
||||
for(; decpt < 0; decpt++)
|
||||
*b++ = '0';
|
||||
while((*b++ = *s++));
|
||||
b--;
|
||||
}
|
||||
else {
|
||||
while((*b = *s++)) {
|
||||
b++;
|
||||
if (--decpt == 0 && *s)
|
||||
*b++ = '.';
|
||||
}
|
||||
for(; decpt > 0; decpt--)
|
||||
*b++ = '0';
|
||||
*b = 0;
|
||||
}
|
||||
done0:
|
||||
freedtoa(s0);
|
||||
#ifdef IGNORE_ZERO_SIGN
|
||||
done:
|
||||
#endif
|
||||
return b - b0;
|
||||
}
|
||||
#endif
|
271
app/cjson/lua/cjson/util.lua
Normal file
271
app/cjson/lua/cjson/util.lua
Normal file
@ -0,0 +1,271 @@
|
||||
local json = require "cjson"
|
||||
|
||||
-- Various common routines used by the Lua CJSON package
|
||||
--
|
||||
-- Mark Pulford <mark@kyne.com.au>
|
||||
|
||||
-- Determine with a Lua table can be treated as an array.
|
||||
-- Explicitly returns "not an array" for very sparse arrays.
|
||||
-- Returns:
|
||||
-- -1 Not an array
|
||||
-- 0 Empty table
|
||||
-- >0 Highest index in the array
|
||||
local function is_array(table)
|
||||
local max = 0
|
||||
local count = 0
|
||||
for k, v in pairs(table) do
|
||||
if type(k) == "number" then
|
||||
if k > max then max = k end
|
||||
count = count + 1
|
||||
else
|
||||
return -1
|
||||
end
|
||||
end
|
||||
if max > count * 2 then
|
||||
return -1
|
||||
end
|
||||
|
||||
return max
|
||||
end
|
||||
|
||||
local serialise_value
|
||||
|
||||
local function serialise_table(value, indent, depth)
|
||||
local spacing, spacing2, indent2
|
||||
if indent then
|
||||
spacing = "\n" .. indent
|
||||
spacing2 = spacing .. " "
|
||||
indent2 = indent .. " "
|
||||
else
|
||||
spacing, spacing2, indent2 = " ", " ", false
|
||||
end
|
||||
depth = depth + 1
|
||||
if depth > 50 then
|
||||
return "Cannot serialise any further: too many nested tables"
|
||||
end
|
||||
|
||||
local max = is_array(value)
|
||||
|
||||
local comma = false
|
||||
local fragment = { "{" .. spacing2 }
|
||||
if max > 0 then
|
||||
-- Serialise array
|
||||
for i = 1, max do
|
||||
if comma then
|
||||
table.insert(fragment, "," .. spacing2)
|
||||
end
|
||||
table.insert(fragment, serialise_value(value[i], indent2, depth))
|
||||
comma = true
|
||||
end
|
||||
elseif max < 0 then
|
||||
-- Serialise table
|
||||
for k, v in pairs(value) do
|
||||
if comma then
|
||||
table.insert(fragment, "," .. spacing2)
|
||||
end
|
||||
table.insert(fragment,
|
||||
("[%s] = %s"):format(serialise_value(k, indent2, depth),
|
||||
serialise_value(v, indent2, depth)))
|
||||
comma = true
|
||||
end
|
||||
end
|
||||
table.insert(fragment, spacing .. "}")
|
||||
|
||||
return table.concat(fragment)
|
||||
end
|
||||
|
||||
function serialise_value(value, indent, depth)
|
||||
if indent == nil then indent = "" end
|
||||
if depth == nil then depth = 0 end
|
||||
|
||||
if value == json.null then
|
||||
return "json.null"
|
||||
elseif type(value) == "string" then
|
||||
return ("%q"):format(value)
|
||||
elseif type(value) == "nil" or type(value) == "number" or
|
||||
type(value) == "boolean" then
|
||||
return tostring(value)
|
||||
elseif type(value) == "table" then
|
||||
return serialise_table(value, indent, depth)
|
||||
else
|
||||
return "\"<" .. type(value) .. ">\""
|
||||
end
|
||||
end
|
||||
|
||||
local function file_load(filename)
|
||||
local file
|
||||
if filename == nil then
|
||||
file = io.stdin
|
||||
else
|
||||
local err
|
||||
file, err = io.open(filename, "rb")
|
||||
if file == nil then
|
||||
error(("Unable to read '%s': %s"):format(filename, err))
|
||||
end
|
||||
end
|
||||
local data = file:read("*a")
|
||||
|
||||
if filename ~= nil then
|
||||
file:close()
|
||||
end
|
||||
|
||||
if data == nil then
|
||||
error("Failed to read " .. filename)
|
||||
end
|
||||
|
||||
return data
|
||||
end
|
||||
|
||||
local function file_save(filename, data)
|
||||
local file
|
||||
if filename == nil then
|
||||
file = io.stdout
|
||||
else
|
||||
local err
|
||||
file, err = io.open(filename, "wb")
|
||||
if file == nil then
|
||||
error(("Unable to write '%s': %s"):format(filename, err))
|
||||
end
|
||||
end
|
||||
file:write(data)
|
||||
if filename ~= nil then
|
||||
file:close()
|
||||
end
|
||||
end
|
||||
|
||||
local function compare_values(val1, val2)
|
||||
local type1 = type(val1)
|
||||
local type2 = type(val2)
|
||||
if type1 ~= type2 then
|
||||
return false
|
||||
end
|
||||
|
||||
-- Check for NaN
|
||||
if type1 == "number" and val1 ~= val1 and val2 ~= val2 then
|
||||
return true
|
||||
end
|
||||
|
||||
if type1 ~= "table" then
|
||||
return val1 == val2
|
||||
end
|
||||
|
||||
-- check_keys stores all the keys that must be checked in val2
|
||||
local check_keys = {}
|
||||
for k, _ in pairs(val1) do
|
||||
check_keys[k] = true
|
||||
end
|
||||
|
||||
for k, v in pairs(val2) do
|
||||
if not check_keys[k] then
|
||||
return false
|
||||
end
|
||||
|
||||
if not compare_values(val1[k], val2[k]) then
|
||||
return false
|
||||
end
|
||||
|
||||
check_keys[k] = nil
|
||||
end
|
||||
for k, _ in pairs(check_keys) do
|
||||
-- Not the same if any keys from val1 were not found in val2
|
||||
return false
|
||||
end
|
||||
return true
|
||||
end
|
||||
|
||||
local test_count_pass = 0
|
||||
local test_count_total = 0
|
||||
|
||||
local function run_test_summary()
|
||||
return test_count_pass, test_count_total
|
||||
end
|
||||
|
||||
local function run_test(testname, func, input, should_work, output)
|
||||
local function status_line(name, status, value)
|
||||
local statusmap = { [true] = ":success", [false] = ":error" }
|
||||
if status ~= nil then
|
||||
name = name .. statusmap[status]
|
||||
end
|
||||
print(("[%s] %s"):format(name, serialise_value(value, false)))
|
||||
end
|
||||
|
||||
local result = { pcall(func, unpack(input)) }
|
||||
local success = table.remove(result, 1)
|
||||
|
||||
local correct = false
|
||||
if success == should_work and compare_values(result, output) then
|
||||
correct = true
|
||||
test_count_pass = test_count_pass + 1
|
||||
end
|
||||
test_count_total = test_count_total + 1
|
||||
|
||||
local teststatus = { [true] = "PASS", [false] = "FAIL" }
|
||||
print(("==> Test [%d] %s: %s"):format(test_count_total, testname,
|
||||
teststatus[correct]))
|
||||
|
||||
status_line("Input", nil, input)
|
||||
if not correct then
|
||||
status_line("Expected", should_work, output)
|
||||
end
|
||||
status_line("Received", success, result)
|
||||
print()
|
||||
|
||||
return correct, result
|
||||
end
|
||||
|
||||
local function run_test_group(tests)
|
||||
local function run_helper(name, func, input)
|
||||
if type(name) == "string" and #name > 0 then
|
||||
print("==> " .. name)
|
||||
end
|
||||
-- Not a protected call, these functions should never generate errors.
|
||||
func(unpack(input or {}))
|
||||
print()
|
||||
end
|
||||
|
||||
for _, v in ipairs(tests) do
|
||||
-- Run the helper if "should_work" is missing
|
||||
if v[4] == nil then
|
||||
run_helper(unpack(v))
|
||||
else
|
||||
run_test(unpack(v))
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- Run a Lua script in a separate environment
|
||||
local function run_script(script, env)
|
||||
local env = env or {}
|
||||
local func
|
||||
|
||||
-- Use setfenv() if it exists, otherwise assume Lua 5.2 load() exists
|
||||
if _G.setfenv then
|
||||
func = loadstring(script)
|
||||
if func then
|
||||
setfenv(func, env)
|
||||
end
|
||||
else
|
||||
func = load(script, nil, nil, env)
|
||||
end
|
||||
|
||||
if func == nil then
|
||||
error("Invalid syntax.")
|
||||
end
|
||||
func()
|
||||
|
||||
return env
|
||||
end
|
||||
|
||||
-- Export functions
|
||||
return {
|
||||
serialise_value = serialise_value,
|
||||
file_load = file_load,
|
||||
file_save = file_save,
|
||||
compare_values = compare_values,
|
||||
run_test_summary = run_test_summary,
|
||||
run_test = run_test,
|
||||
run_test_group = run_test_group,
|
||||
run_script = run_script
|
||||
}
|
||||
|
||||
-- vi:ai et sw=4 ts=4:
|
14
app/cjson/lua/json2lua.lua
Normal file
14
app/cjson/lua/json2lua.lua
Normal file
@ -0,0 +1,14 @@
|
||||
#!/usr/bin/env lua
|
||||
|
||||
-- usage: json2lua.lua [json_file]
|
||||
--
|
||||
-- Eg:
|
||||
-- echo '[ "testing" ]' | ./json2lua.lua
|
||||
-- ./json2lua.lua test.json
|
||||
|
||||
local json = require "cjson"
|
||||
local util = require "cjson.util"
|
||||
|
||||
local json_text = util.file_load(arg[1])
|
||||
local t = json.decode(json_text)
|
||||
print(util.serialise_value(t))
|
20
app/cjson/lua/lua2json.lua
Normal file
20
app/cjson/lua/lua2json.lua
Normal file
@ -0,0 +1,20 @@
|
||||
#!/usr/bin/env lua
|
||||
|
||||
-- usage: lua2json.lua [lua_file]
|
||||
--
|
||||
-- Eg:
|
||||
-- echo '{ "testing" }' | ./lua2json.lua
|
||||
-- ./lua2json.lua test.lua
|
||||
|
||||
local json = require "cjson"
|
||||
local util = require "cjson.util"
|
||||
|
||||
local env = {
|
||||
json = { null = json.null },
|
||||
null = json.null
|
||||
}
|
||||
|
||||
local t = util.run_script("data = " .. util.file_load(arg[1]), env)
|
||||
print(json.encode(t.data))
|
||||
|
||||
-- vi:ai et sw=4 ts=4:
|
168
app/cjson/manual.txt
Normal file
168
app/cjson/manual.txt
Normal file
@ -0,0 +1,168 @@
|
||||
= Lua CJSON 2.1devel Manual =
|
||||
Mark Pulford <mark@kyne.com.au>
|
||||
:revdate: 1st March 2012
|
||||
|
||||
Overview
|
||||
--------
|
||||
|
||||
The Lua CJSON module provides JSON support for Lua.
|
||||
|
||||
*Features*::
|
||||
- Fast, standards compliant encoding/parsing routines
|
||||
- Full support for JSON with UTF-8, including decoding surrogate pairs
|
||||
- Optional run-time support for common exceptions to the JSON
|
||||
specification (infinity, NaN,..)
|
||||
- No dependencies on other libraries
|
||||
|
||||
*Caveats*::
|
||||
- UTF-16 and UTF-32 are not supported
|
||||
|
||||
Lua CJSON is covered by the MIT license. Review the file +LICENSE+ for
|
||||
details.
|
||||
|
||||
API (Functions)
|
||||
---------------
|
||||
|
||||
Synopsis
|
||||
~~~~~~~~
|
||||
|
||||
[source,lua]
|
||||
------------
|
||||
|
||||
-- Translate Lua value to/from JSON
|
||||
text = cjson.encode(value)
|
||||
value = cjson.decode(text)
|
||||
|
||||
|
||||
Module Instantiation
|
||||
~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
decode
|
||||
~~~~~~
|
||||
|
||||
[source,lua]
|
||||
------------
|
||||
value = cjson.decode(json_text)
|
||||
------------
|
||||
|
||||
+cjson.decode+ will deserialise any UTF-8 JSON string into a Lua value
|
||||
or table.
|
||||
|
||||
UTF-16 and UTF-32 JSON strings are not supported.
|
||||
|
||||
+cjson.decode+ requires that any NULL (ASCII 0) and double quote (ASCII
|
||||
34) characters are escaped within strings. All escape codes will be
|
||||
decoded and other bytes will be passed transparently. UTF-8 characters
|
||||
are not validated during decoding and should be checked elsewhere if
|
||||
required.
|
||||
|
||||
JSON +null+ will be converted to a NULL +lightuserdata+ value. This can
|
||||
be compared with +cjson.null+ for convenience.
|
||||
|
||||
By default, numbers incompatible with the JSON specification (infinity,
|
||||
NaN, hexadecimal) can be decoded. This default can be changed with
|
||||
<<decode_invalid_numbers,+cjson.decode_invalid_numbers+>>.
|
||||
|
||||
.Example: Decoding
|
||||
[source,lua]
|
||||
json_text = '[ true, { "foo": "bar" } ]'
|
||||
value = cjson.decode(json_text)
|
||||
-- Returns: { true, { foo = "bar" } }
|
||||
|
||||
[CAUTION]
|
||||
Care must be taken after decoding JSON objects with numeric keys. Each
|
||||
numeric key will be stored as a Lua +string+. Any subsequent code
|
||||
assuming type +number+ may break.
|
||||
|
||||
|
||||
[[encode]]
|
||||
encode
|
||||
~~~~~~
|
||||
|
||||
[source,lua]
|
||||
------------
|
||||
json_text = cjson.encode(value)
|
||||
------------
|
||||
|
||||
+cjson.encode+ will serialise a Lua value into a string containing the
|
||||
JSON representation.
|
||||
|
||||
+cjson.encode+ supports the following types:
|
||||
|
||||
- +boolean+
|
||||
- +lightuserdata+ (NULL value only)
|
||||
- +nil+
|
||||
- +number+
|
||||
- +string+
|
||||
- +table+
|
||||
|
||||
The remaining Lua types will generate an error:
|
||||
|
||||
- +function+
|
||||
- +lightuserdata+ (non-NULL values)
|
||||
- +thread+
|
||||
- +userdata+
|
||||
|
||||
By default, numbers are encoded with 14 significant digits. Refer to
|
||||
<<encode_number_precision,+cjson.encode_number_precision+>> for details.
|
||||
|
||||
Lua CJSON will escape the following characters within each UTF-8 string:
|
||||
|
||||
- Control characters (ASCII 0 - 31)
|
||||
- Double quote (ASCII 34)
|
||||
- Forward slash (ASCII 47)
|
||||
- Blackslash (ASCII 92)
|
||||
- Delete (ASCII 127)
|
||||
|
||||
All other bytes are passed transparently.
|
||||
|
||||
[CAUTION]
|
||||
=========
|
||||
Lua CJSON will successfully encode/decode binary strings, but this is
|
||||
technically not supported by JSON and may not be compatible with other
|
||||
JSON libraries. To ensure the output is valid JSON, applications should
|
||||
ensure all Lua strings passed to +cjson.encode+ are UTF-8.
|
||||
|
||||
Base64 is commonly used to encode binary data as the most efficient
|
||||
encoding under UTF-8 can only reduce the encoded size by a further
|
||||
~8%. Lua Base64 routines can be found in the
|
||||
http://w3.impa.br/%7Ediego/software/luasocket/[LuaSocket] and
|
||||
http://www.tecgraf.puc-rio.br/%7Elhf/ftp/lua/#lbase64[lbase64] packages.
|
||||
=========
|
||||
|
||||
Lua CJSON uses a heuristic to determine whether to encode a Lua table as
|
||||
a JSON array or an object. A Lua table with only positive integer keys
|
||||
of type +number+ will be encoded as a JSON array. All other tables will
|
||||
be encoded as a JSON object.
|
||||
|
||||
Lua CJSON does not use metamethods when serialising tables.
|
||||
|
||||
- +rawget+ is used to iterate over Lua arrays
|
||||
- +next+ is used to iterate over Lua objects
|
||||
|
||||
Lua arrays with missing entries (_sparse arrays_) may optionally be
|
||||
encoded in several different ways. Refer to
|
||||
<<encode_sparse_array,+cjson.encode_sparse_array+>> for details.
|
||||
|
||||
JSON object keys are always strings. Hence +cjson.encode+ only supports
|
||||
table keys which are type +number+ or +string+. All other types will
|
||||
generate an error.
|
||||
|
||||
[NOTE]
|
||||
Standards compliant JSON must be encapsulated in either an object (+{}+)
|
||||
or an array (+[]+). If strictly standards compliant JSON is desired, a
|
||||
table must be passed to +cjson.encode+.
|
||||
|
||||
By default, encoding the following Lua values will generate errors:
|
||||
|
||||
- Numbers incompatible with the JSON specification (infinity, NaN)
|
||||
- Tables nested more than 1000 levels deep
|
||||
- Excessively sparse Lua arrays
|
||||
|
||||
.Example: Encoding
|
||||
[source,lua]
|
||||
value = { true, { foo = "bar" } }
|
||||
json_text = cjson.encode(value)
|
||||
-- Returns: '[true,{"foo":"bar"}]'
|
||||
|
||||
// vi:ft=asciidoc tw=72:
|
563
app/cjson/rfc4627.txt
Normal file
563
app/cjson/rfc4627.txt
Normal file
@ -0,0 +1,563 @@
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
Network Working Group D. Crockford
|
||||
Request for Comments: 4627 JSON.org
|
||||
Category: Informational July 2006
|
||||
|
||||
|
||||
The application/json Media Type for JavaScript Object Notation (JSON)
|
||||
|
||||
Status of This Memo
|
||||
|
||||
This memo provides information for the Internet community. It does
|
||||
not specify an Internet standard of any kind. Distribution of this
|
||||
memo is unlimited.
|
||||
|
||||
Copyright Notice
|
||||
|
||||
Copyright (C) The Internet Society (2006).
|
||||
|
||||
Abstract
|
||||
|
||||
JavaScript Object Notation (JSON) is a lightweight, text-based,
|
||||
language-independent data interchange format. It was derived from
|
||||
the ECMAScript Programming Language Standard. JSON defines a small
|
||||
set of formatting rules for the portable representation of structured
|
||||
data.
|
||||
|
||||
1. Introduction
|
||||
|
||||
JavaScript Object Notation (JSON) is a text format for the
|
||||
serialization of structured data. It is derived from the object
|
||||
literals of JavaScript, as defined in the ECMAScript Programming
|
||||
Language Standard, Third Edition [ECMA].
|
||||
|
||||
JSON can represent four primitive types (strings, numbers, booleans,
|
||||
and null) and two structured types (objects and arrays).
|
||||
|
||||
A string is a sequence of zero or more Unicode characters [UNICODE].
|
||||
|
||||
An object is an unordered collection of zero or more name/value
|
||||
pairs, where a name is a string and a value is a string, number,
|
||||
boolean, null, object, or array.
|
||||
|
||||
An array is an ordered sequence of zero or more values.
|
||||
|
||||
The terms "object" and "array" come from the conventions of
|
||||
JavaScript.
|
||||
|
||||
JSON's design goals were for it to be minimal, portable, textual, and
|
||||
a subset of JavaScript.
|
||||
|
||||
|
||||
|
||||
Crockford Informational [Page 1]
|
||||
|
||||
RFC 4627 JSON July 2006
|
||||
|
||||
|
||||
1.1. Conventions Used in This Document
|
||||
|
||||
The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT",
|
||||
"SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this
|
||||
document are to be interpreted as described in [RFC2119].
|
||||
|
||||
The grammatical rules in this document are to be interpreted as
|
||||
described in [RFC4234].
|
||||
|
||||
2. JSON Grammar
|
||||
|
||||
A JSON text is a sequence of tokens. The set of tokens includes six
|
||||
structural characters, strings, numbers, and three literal names.
|
||||
|
||||
A JSON text is a serialized object or array.
|
||||
|
||||
JSON-text = object / array
|
||||
|
||||
These are the six structural characters:
|
||||
|
||||
begin-array = ws %x5B ws ; [ left square bracket
|
||||
|
||||
begin-object = ws %x7B ws ; { left curly bracket
|
||||
|
||||
end-array = ws %x5D ws ; ] right square bracket
|
||||
|
||||
end-object = ws %x7D ws ; } right curly bracket
|
||||
|
||||
name-separator = ws %x3A ws ; : colon
|
||||
|
||||
value-separator = ws %x2C ws ; , comma
|
||||
|
||||
Insignificant whitespace is allowed before or after any of the six
|
||||
structural characters.
|
||||
|
||||
ws = *(
|
||||
%x20 / ; Space
|
||||
%x09 / ; Horizontal tab
|
||||
%x0A / ; Line feed or New line
|
||||
%x0D ; Carriage return
|
||||
)
|
||||
|
||||
2.1. Values
|
||||
|
||||
A JSON value MUST be an object, array, number, or string, or one of
|
||||
the following three literal names:
|
||||
|
||||
false null true
|
||||
|
||||
|
||||
|
||||
Crockford Informational [Page 2]
|
||||
|
||||
RFC 4627 JSON July 2006
|
||||
|
||||
|
||||
The literal names MUST be lowercase. No other literal names are
|
||||
allowed.
|
||||
|
||||
value = false / null / true / object / array / number / string
|
||||
|
||||
false = %x66.61.6c.73.65 ; false
|
||||
|
||||
null = %x6e.75.6c.6c ; null
|
||||
|
||||
true = %x74.72.75.65 ; true
|
||||
|
||||
2.2. Objects
|
||||
|
||||
An object structure is represented as a pair of curly brackets
|
||||
surrounding zero or more name/value pairs (or members). A name is a
|
||||
string. A single colon comes after each name, separating the name
|
||||
from the value. A single comma separates a value from a following
|
||||
name. The names within an object SHOULD be unique.
|
||||
|
||||
object = begin-object [ member *( value-separator member ) ]
|
||||
end-object
|
||||
|
||||
member = string name-separator value
|
||||
|
||||
2.3. Arrays
|
||||
|
||||
An array structure is represented as square brackets surrounding zero
|
||||
or more values (or elements). Elements are separated by commas.
|
||||
|
||||
array = begin-array [ value *( value-separator value ) ] end-array
|
||||
|
||||
2.4. Numbers
|
||||
|
||||
The representation of numbers is similar to that used in most
|
||||
programming languages. A number contains an integer component that
|
||||
may be prefixed with an optional minus sign, which may be followed by
|
||||
a fraction part and/or an exponent part.
|
||||
|
||||
Octal and hex forms are not allowed. Leading zeros are not allowed.
|
||||
|
||||
A fraction part is a decimal point followed by one or more digits.
|
||||
|
||||
An exponent part begins with the letter E in upper or lowercase,
|
||||
which may be followed by a plus or minus sign. The E and optional
|
||||
sign are followed by one or more digits.
|
||||
|
||||
Numeric values that cannot be represented as sequences of digits
|
||||
(such as Infinity and NaN) are not permitted.
|
||||
|
||||
|
||||
|
||||
Crockford Informational [Page 3]
|
||||
|
||||
RFC 4627 JSON July 2006
|
||||
|
||||
|
||||
number = [ minus ] int [ frac ] [ exp ]
|
||||
|
||||
decimal-point = %x2E ; .
|
||||
|
||||
digit1-9 = %x31-39 ; 1-9
|
||||
|
||||
e = %x65 / %x45 ; e E
|
||||
|
||||
exp = e [ minus / plus ] 1*DIGIT
|
||||
|
||||
frac = decimal-point 1*DIGIT
|
||||
|
||||
int = zero / ( digit1-9 *DIGIT )
|
||||
|
||||
minus = %x2D ; -
|
||||
|
||||
plus = %x2B ; +
|
||||
|
||||
zero = %x30 ; 0
|
||||
|
||||
2.5. Strings
|
||||
|
||||
The representation of strings is similar to conventions used in the C
|
||||
family of programming languages. A string begins and ends with
|
||||
quotation marks. All Unicode characters may be placed within the
|
||||
quotation marks except for the characters that must be escaped:
|
||||
quotation mark, reverse solidus, and the control characters (U+0000
|
||||
through U+001F).
|
||||
|
||||
Any character may be escaped. If the character is in the Basic
|
||||
Multilingual Plane (U+0000 through U+FFFF), then it may be
|
||||
represented as a six-character sequence: a reverse solidus, followed
|
||||
by the lowercase letter u, followed by four hexadecimal digits that
|
||||
encode the character's code point. The hexadecimal letters A though
|
||||
F can be upper or lowercase. So, for example, a string containing
|
||||
only a single reverse solidus character may be represented as
|
||||
"\u005C".
|
||||
|
||||
Alternatively, there are two-character sequence escape
|
||||
representations of some popular characters. So, for example, a
|
||||
string containing only a single reverse solidus character may be
|
||||
represented more compactly as "\\".
|
||||
|
||||
To escape an extended character that is not in the Basic Multilingual
|
||||
Plane, the character is represented as a twelve-character sequence,
|
||||
encoding the UTF-16 surrogate pair. So, for example, a string
|
||||
containing only the G clef character (U+1D11E) may be represented as
|
||||
"\uD834\uDD1E".
|
||||
|
||||
|
||||
|
||||
Crockford Informational [Page 4]
|
||||
|
||||
RFC 4627 JSON July 2006
|
||||
|
||||
|
||||
string = quotation-mark *char quotation-mark
|
||||
|
||||
char = unescaped /
|
||||
escape (
|
||||
%x22 / ; " quotation mark U+0022
|
||||
%x5C / ; \ reverse solidus U+005C
|
||||
%x2F / ; / solidus U+002F
|
||||
%x62 / ; b backspace U+0008
|
||||
%x66 / ; f form feed U+000C
|
||||
%x6E / ; n line feed U+000A
|
||||
%x72 / ; r carriage return U+000D
|
||||
%x74 / ; t tab U+0009
|
||||
%x75 4HEXDIG ) ; uXXXX U+XXXX
|
||||
|
||||
escape = %x5C ; \
|
||||
|
||||
quotation-mark = %x22 ; "
|
||||
|
||||
unescaped = %x20-21 / %x23-5B / %x5D-10FFFF
|
||||
|
||||
3. Encoding
|
||||
|
||||
JSON text SHALL be encoded in Unicode. The default encoding is
|
||||
UTF-8.
|
||||
|
||||
Since the first two characters of a JSON text will always be ASCII
|
||||
characters [RFC0020], it is possible to determine whether an octet
|
||||
stream is UTF-8, UTF-16 (BE or LE), or UTF-32 (BE or LE) by looking
|
||||
at the pattern of nulls in the first four octets.
|
||||
|
||||
00 00 00 xx UTF-32BE
|
||||
00 xx 00 xx UTF-16BE
|
||||
xx 00 00 00 UTF-32LE
|
||||
xx 00 xx 00 UTF-16LE
|
||||
xx xx xx xx UTF-8
|
||||
|
||||
4. Parsers
|
||||
|
||||
A JSON parser transforms a JSON text into another representation. A
|
||||
JSON parser MUST accept all texts that conform to the JSON grammar.
|
||||
A JSON parser MAY accept non-JSON forms or extensions.
|
||||
|
||||
An implementation may set limits on the size of texts that it
|
||||
accepts. An implementation may set limits on the maximum depth of
|
||||
nesting. An implementation may set limits on the range of numbers.
|
||||
An implementation may set limits on the length and character contents
|
||||
of strings.
|
||||
|
||||
|
||||
|
||||
|
||||
Crockford Informational [Page 5]
|
||||
|
||||
RFC 4627 JSON July 2006
|
||||
|
||||
|
||||
5. Generators
|
||||
|
||||
A JSON generator produces JSON text. The resulting text MUST
|
||||
strictly conform to the JSON grammar.
|
||||
|
||||
6. IANA Considerations
|
||||
|
||||
The MIME media type for JSON text is application/json.
|
||||
|
||||
Type name: application
|
||||
|
||||
Subtype name: json
|
||||
|
||||
Required parameters: n/a
|
||||
|
||||
Optional parameters: n/a
|
||||
|
||||
Encoding considerations: 8bit if UTF-8; binary if UTF-16 or UTF-32
|
||||
|
||||
JSON may be represented using UTF-8, UTF-16, or UTF-32. When JSON
|
||||
is written in UTF-8, JSON is 8bit compatible. When JSON is
|
||||
written in UTF-16 or UTF-32, the binary content-transfer-encoding
|
||||
must be used.
|
||||
|
||||
Security considerations:
|
||||
|
||||
Generally there are security issues with scripting languages. JSON
|
||||
is a subset of JavaScript, but it is a safe subset that excludes
|
||||
assignment and invocation.
|
||||
|
||||
A JSON text can be safely passed into JavaScript's eval() function
|
||||
(which compiles and executes a string) if all the characters not
|
||||
enclosed in strings are in the set of characters that form JSON
|
||||
tokens. This can be quickly determined in JavaScript with two
|
||||
regular expressions and calls to the test and replace methods.
|
||||
|
||||
var my_JSON_object = !(/[^,:{}\[\]0-9.\-+Eaeflnr-u \n\r\t]/.test(
|
||||
text.replace(/"(\\.|[^"\\])*"/g, ''))) &&
|
||||
eval('(' + text + ')');
|
||||
|
||||
Interoperability considerations: n/a
|
||||
|
||||
Published specification: RFC 4627
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
Crockford Informational [Page 6]
|
||||
|
||||
RFC 4627 JSON July 2006
|
||||
|
||||
|
||||
Applications that use this media type:
|
||||
|
||||
JSON has been used to exchange data between applications written
|
||||
in all of these programming languages: ActionScript, C, C#,
|
||||
ColdFusion, Common Lisp, E, Erlang, Java, JavaScript, Lua,
|
||||
Objective CAML, Perl, PHP, Python, Rebol, Ruby, and Scheme.
|
||||
|
||||
Additional information:
|
||||
|
||||
Magic number(s): n/a
|
||||
File extension(s): .json
|
||||
Macintosh file type code(s): TEXT
|
||||
|
||||
Person & email address to contact for further information:
|
||||
Douglas Crockford
|
||||
douglas@crockford.com
|
||||
|
||||
Intended usage: COMMON
|
||||
|
||||
Restrictions on usage: none
|
||||
|
||||
Author:
|
||||
Douglas Crockford
|
||||
douglas@crockford.com
|
||||
|
||||
Change controller:
|
||||
Douglas Crockford
|
||||
douglas@crockford.com
|
||||
|
||||
7. Security Considerations
|
||||
|
||||
See Security Considerations in Section 6.
|
||||
|
||||
8. Examples
|
||||
|
||||
This is a JSON object:
|
||||
|
||||
{
|
||||
"Image": {
|
||||
"Width": 800,
|
||||
"Height": 600,
|
||||
"Title": "View from 15th Floor",
|
||||
"Thumbnail": {
|
||||
"Url": "http://www.example.com/image/481989943",
|
||||
"Height": 125,
|
||||
"Width": "100"
|
||||
},
|
||||
"IDs": [116, 943, 234, 38793]
|
||||
|
||||
|
||||
|
||||
Crockford Informational [Page 7]
|
||||
|
||||
RFC 4627 JSON July 2006
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
Its Image member is an object whose Thumbnail member is an object
|
||||
and whose IDs member is an array of numbers.
|
||||
|
||||
This is a JSON array containing two objects:
|
||||
|
||||
[
|
||||
{
|
||||
"precision": "zip",
|
||||
"Latitude": 37.7668,
|
||||
"Longitude": -122.3959,
|
||||
"Address": "",
|
||||
"City": "SAN FRANCISCO",
|
||||
"State": "CA",
|
||||
"Zip": "94107",
|
||||
"Country": "US"
|
||||
},
|
||||
{
|
||||
"precision": "zip",
|
||||
"Latitude": 37.371991,
|
||||
"Longitude": -122.026020,
|
||||
"Address": "",
|
||||
"City": "SUNNYVALE",
|
||||
"State": "CA",
|
||||
"Zip": "94085",
|
||||
"Country": "US"
|
||||
}
|
||||
]
|
||||
|
||||
9. References
|
||||
|
||||
9.1. Normative References
|
||||
|
||||
[ECMA] European Computer Manufacturers Association, "ECMAScript
|
||||
Language Specification 3rd Edition", December 1999,
|
||||
<http://www.ecma-international.org/publications/files/
|
||||
ecma-st/ECMA-262.pdf>.
|
||||
|
||||
[RFC0020] Cerf, V., "ASCII format for network interchange", RFC 20,
|
||||
October 1969.
|
||||
|
||||
[RFC2119] Bradner, S., "Key words for use in RFCs to Indicate
|
||||
Requirement Levels", BCP 14, RFC 2119, March 1997.
|
||||
|
||||
[RFC4234] Crocker, D. and P. Overell, "Augmented BNF for Syntax
|
||||
Specifications: ABNF", RFC 4234, October 2005.
|
||||
|
||||
|
||||
|
||||
Crockford Informational [Page 8]
|
||||
|
||||
RFC 4627 JSON July 2006
|
||||
|
||||
|
||||
[UNICODE] The Unicode Consortium, "The Unicode Standard Version 4.0",
|
||||
2003, <http://www.unicode.org/versions/Unicode4.1.0/>.
|
||||
|
||||
Author's Address
|
||||
|
||||
Douglas Crockford
|
||||
JSON.org
|
||||
EMail: douglas@crockford.com
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
Crockford Informational [Page 9]
|
||||
|
||||
RFC 4627 JSON July 2006
|
||||
|
||||
|
||||
Full Copyright Statement
|
||||
|
||||
Copyright (C) The Internet Society (2006).
|
||||
|
||||
This document is subject to the rights, licenses and restrictions
|
||||
contained in BCP 78, and except as set forth therein, the authors
|
||||
retain all their rights.
|
||||
|
||||
This document and the information contained herein are provided on an
|
||||
"AS IS" basis and THE CONTRIBUTOR, THE ORGANIZATION HE/SHE REPRESENTS
|
||||
OR IS SPONSORED BY (IF ANY), THE INTERNET SOCIETY AND THE INTERNET
|
||||
ENGINEERING TASK FORCE DISCLAIM ALL WARRANTIES, EXPRESS OR IMPLIED,
|
||||
INCLUDING BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE
|
||||
INFORMATION HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
|
||||
|
||||
Intellectual Property
|
||||
|
||||
The IETF takes no position regarding the validity or scope of any
|
||||
Intellectual Property Rights or other rights that might be claimed to
|
||||
pertain to the implementation or use of the technology described in
|
||||
this document or the extent to which any license under such rights
|
||||
might or might not be available; nor does it represent that it has
|
||||
made any independent effort to identify any such rights. Information
|
||||
on the procedures with respect to rights in RFC documents can be
|
||||
found in BCP 78 and BCP 79.
|
||||
|
||||
Copies of IPR disclosures made to the IETF Secretariat and any
|
||||
assurances of licenses to be made available, or the result of an
|
||||
attempt made to obtain a general license or permission for the use of
|
||||
such proprietary rights by implementers or users of this
|
||||
specification can be obtained from the IETF on-line IPR repository at
|
||||
http://www.ietf.org/ipr.
|
||||
|
||||
The IETF invites any interested party to bring to its attention any
|
||||
copyrights, patents or patent applications, or other proprietary
|
||||
rights that may cover technology that may be required to implement
|
||||
this standard. Please address the information to the IETF at
|
||||
ietf-ipr@ietf.org.
|
||||
|
||||
Acknowledgement
|
||||
|
||||
Funding for the RFC Editor function is provided by the IETF
|
||||
Administrative Support Activity (IASA).
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
Crockford Informational [Page 10]
|
||||
|
252
app/cjson/strbuf.c
Normal file
252
app/cjson/strbuf.c
Normal file
@ -0,0 +1,252 @@
|
||||
/* strbuf - String buffer routines
|
||||
*
|
||||
* Copyright (c) 2010-2012 Mark Pulford <mark@kyne.com.au>
|
||||
*
|
||||
* 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 "c_stdio.h"
|
||||
#include "c_stdlib.h"
|
||||
#include "c_stdarg.h"
|
||||
#include "c_string.h"
|
||||
|
||||
#include "strbuf.h"
|
||||
|
||||
int strbuf_init(strbuf_t *s, int len)
|
||||
{
|
||||
int size;
|
||||
|
||||
if (len <= 0)
|
||||
size = STRBUF_DEFAULT_SIZE;
|
||||
else
|
||||
size = len + 1; /* \0 terminator */
|
||||
|
||||
s->buf = NULL;
|
||||
s->size = size;
|
||||
s->length = 0;
|
||||
s->increment = STRBUF_DEFAULT_INCREMENT;
|
||||
s->dynamic = 0;
|
||||
s->reallocs = 0;
|
||||
s->debug = 0;
|
||||
|
||||
s->buf = c_malloc(size);
|
||||
if (!s->buf){
|
||||
NODE_ERR("not enough memory\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
strbuf_ensure_null(s);
|
||||
return 0;
|
||||
}
|
||||
|
||||
strbuf_t *strbuf_new(int len)
|
||||
{
|
||||
strbuf_t *s;
|
||||
|
||||
s = c_malloc(sizeof(strbuf_t));
|
||||
if (!s){
|
||||
NODE_ERR("not enough memory\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
strbuf_init(s, len);
|
||||
|
||||
/* Dynamic strbuf allocation / deallocation */
|
||||
s->dynamic = 1;
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
int strbuf_set_increment(strbuf_t *s, int increment)
|
||||
{
|
||||
/* Increment > 0: Linear buffer growth rate
|
||||
* Increment < -1: Exponential buffer growth rate */
|
||||
if (increment == 0 || increment == -1){
|
||||
NODE_ERR("BUG: Invalid string increment");
|
||||
return -1;
|
||||
}
|
||||
|
||||
s->increment = increment;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline void debug_stats(strbuf_t *s)
|
||||
{
|
||||
if (s->debug) {
|
||||
NODE_ERR("strbuf(%lx) reallocs: %d, length: %d, size: %d\n",
|
||||
(long)s, s->reallocs, s->length, s->size);
|
||||
}
|
||||
}
|
||||
|
||||
/* If strbuf_t has not been dynamically allocated, strbuf_free() can
|
||||
* be called any number of times strbuf_init() */
|
||||
void strbuf_free(strbuf_t *s)
|
||||
{
|
||||
debug_stats(s);
|
||||
|
||||
if (s->buf) {
|
||||
c_free(s->buf);
|
||||
s->buf = NULL;
|
||||
}
|
||||
if (s->dynamic)
|
||||
c_free(s);
|
||||
}
|
||||
|
||||
char *strbuf_free_to_string(strbuf_t *s, int *len)
|
||||
{
|
||||
char *buf;
|
||||
|
||||
debug_stats(s);
|
||||
|
||||
strbuf_ensure_null(s);
|
||||
|
||||
buf = s->buf;
|
||||
if (len)
|
||||
*len = s->length;
|
||||
|
||||
if (s->dynamic)
|
||||
c_free(s);
|
||||
|
||||
return buf;
|
||||
}
|
||||
|
||||
static int calculate_new_size(strbuf_t *s, int len)
|
||||
{
|
||||
int reqsize, newsize;
|
||||
|
||||
if (len <= 0){
|
||||
NODE_ERR("BUG: Invalid strbuf length requested");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Ensure there is room for optional NULL termination */
|
||||
reqsize = len + 1;
|
||||
|
||||
/* If the user has requested to shrink the buffer, do it exactly */
|
||||
if (s->size > reqsize)
|
||||
return reqsize;
|
||||
|
||||
newsize = s->size;
|
||||
if (s->increment < 0) {
|
||||
/* Exponential sizing */
|
||||
while (newsize < reqsize)
|
||||
newsize *= -s->increment;
|
||||
} else {
|
||||
/* Linear sizing */
|
||||
newsize = ((newsize + s->increment - 1) / s->increment) * s->increment;
|
||||
}
|
||||
|
||||
return newsize;
|
||||
}
|
||||
|
||||
|
||||
/* Ensure strbuf can handle a string length bytes long (ignoring NULL
|
||||
* optional termination). */
|
||||
int strbuf_resize(strbuf_t *s, int len)
|
||||
{
|
||||
int newsize;
|
||||
|
||||
newsize = calculate_new_size(s, len);
|
||||
|
||||
if (s->debug > 1) {
|
||||
NODE_ERR("strbuf(%lx) resize: %d => %d\n",
|
||||
(long)s, s->size, newsize);
|
||||
}
|
||||
|
||||
s->buf = (char *)c_realloc(s->buf, newsize);
|
||||
if (!s->buf){
|
||||
NODE_ERR("not enough memory");
|
||||
return -1;
|
||||
}
|
||||
s->size = newsize;
|
||||
s->reallocs++;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void strbuf_append_string(strbuf_t *s, const char *str)
|
||||
{
|
||||
int space, i;
|
||||
|
||||
space = strbuf_empty_length(s);
|
||||
|
||||
for (i = 0; str[i]; i++) {
|
||||
if (space < 1) {
|
||||
strbuf_resize(s, s->length + 1);
|
||||
space = strbuf_empty_length(s);
|
||||
}
|
||||
|
||||
s->buf[s->length] = str[i];
|
||||
s->length++;
|
||||
space--;
|
||||
}
|
||||
}
|
||||
#if 0
|
||||
/* strbuf_append_fmt() should only be used when an upper bound
|
||||
* is known for the output string. */
|
||||
void strbuf_append_fmt(strbuf_t *s, int len, const char *fmt, ...)
|
||||
{
|
||||
va_list arg;
|
||||
int fmt_len;
|
||||
|
||||
strbuf_ensure_empty_length(s, len);
|
||||
|
||||
va_start(arg, fmt);
|
||||
fmt_len = vsnprintf(s->buf + s->length, len, fmt, arg);
|
||||
va_end(arg);
|
||||
|
||||
if (fmt_len < 0)
|
||||
die("BUG: Unable to convert number"); /* This should never happen.. */
|
||||
|
||||
s->length += fmt_len;
|
||||
}
|
||||
|
||||
/* strbuf_append_fmt_retry() can be used when the there is no known
|
||||
* upper bound for the output string. */
|
||||
void strbuf_append_fmt_retry(strbuf_t *s, const char *fmt, ...)
|
||||
{
|
||||
va_list arg;
|
||||
int fmt_len, try;
|
||||
int empty_len;
|
||||
|
||||
/* If the first attempt to append fails, resize the buffer appropriately
|
||||
* and try again */
|
||||
for (try = 0; ; try++) {
|
||||
va_start(arg, fmt);
|
||||
/* Append the new formatted string */
|
||||
/* fmt_len is the length of the string required, excluding the
|
||||
* trailing NULL */
|
||||
empty_len = strbuf_empty_length(s);
|
||||
/* Add 1 since there is also space to store the terminating NULL. */
|
||||
fmt_len = vsnprintf(s->buf + s->length, empty_len + 1, fmt, arg);
|
||||
va_end(arg);
|
||||
|
||||
if (fmt_len <= empty_len)
|
||||
break; /* SUCCESS */
|
||||
if (try > 0)
|
||||
die("BUG: length of formatted string changed");
|
||||
|
||||
strbuf_resize(s, s->length + fmt_len);
|
||||
}
|
||||
|
||||
s->length += fmt_len;
|
||||
}
|
||||
#endif
|
||||
/* vi:ai et sw=4 ts=4:
|
||||
*/
|
154
app/cjson/strbuf.h
Normal file
154
app/cjson/strbuf.h
Normal file
@ -0,0 +1,154 @@
|
||||
/* strbuf - String buffer routines
|
||||
*
|
||||
* Copyright (c) 2010-2012 Mark Pulford <mark@kyne.com.au>
|
||||
*
|
||||
* 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 "c_stdlib.h"
|
||||
#include "c_stdarg.h"
|
||||
|
||||
/* Size: Total bytes allocated to *buf
|
||||
* Length: String length, excluding optional NULL terminator.
|
||||
* Increment: Allocation increments when resizing the string buffer.
|
||||
* Dynamic: True if created via strbuf_new()
|
||||
*/
|
||||
|
||||
typedef struct {
|
||||
char *buf;
|
||||
int size;
|
||||
int length;
|
||||
int increment;
|
||||
int dynamic;
|
||||
int reallocs;
|
||||
int debug;
|
||||
} strbuf_t;
|
||||
|
||||
#ifndef STRBUF_DEFAULT_SIZE
|
||||
#define STRBUF_DEFAULT_SIZE 1023
|
||||
#endif
|
||||
#ifndef STRBUF_DEFAULT_INCREMENT
|
||||
#define STRBUF_DEFAULT_INCREMENT -2
|
||||
#endif
|
||||
|
||||
/* Initialise */
|
||||
extern strbuf_t *strbuf_new(int len);
|
||||
extern int strbuf_init(strbuf_t *s, int len);
|
||||
extern int strbuf_set_increment(strbuf_t *s, int increment);
|
||||
|
||||
/* Release */
|
||||
extern void strbuf_free(strbuf_t *s);
|
||||
extern char *strbuf_free_to_string(strbuf_t *s, int *len);
|
||||
|
||||
/* Management */
|
||||
extern int strbuf_resize(strbuf_t *s, int len);
|
||||
static int strbuf_empty_length(strbuf_t *s);
|
||||
static int strbuf_length(strbuf_t *s);
|
||||
static char *strbuf_string(strbuf_t *s, int *len);
|
||||
static void strbuf_ensure_empty_length(strbuf_t *s, int len);
|
||||
static char *strbuf_empty_ptr(strbuf_t *s);
|
||||
static void strbuf_extend_length(strbuf_t *s, int len);
|
||||
|
||||
/* Update */
|
||||
extern void strbuf_append_fmt(strbuf_t *s, int len, const char *fmt, ...);
|
||||
extern void strbuf_append_fmt_retry(strbuf_t *s, const char *format, ...);
|
||||
static void strbuf_append_mem(strbuf_t *s, const char *c, int len);
|
||||
extern void strbuf_append_string(strbuf_t *s, const char *str);
|
||||
static void strbuf_append_char(strbuf_t *s, const char c);
|
||||
static void strbuf_ensure_null(strbuf_t *s);
|
||||
|
||||
/* Reset string for before use */
|
||||
static inline void strbuf_reset(strbuf_t *s)
|
||||
{
|
||||
s->length = 0;
|
||||
}
|
||||
|
||||
static inline int strbuf_allocated(strbuf_t *s)
|
||||
{
|
||||
return s->buf != NULL;
|
||||
}
|
||||
|
||||
/* Return bytes remaining in the string buffer
|
||||
* Ensure there is space for a NULL terminator. */
|
||||
static inline int strbuf_empty_length(strbuf_t *s)
|
||||
{
|
||||
return s->size - s->length - 1;
|
||||
}
|
||||
|
||||
static inline void strbuf_ensure_empty_length(strbuf_t *s, int len)
|
||||
{
|
||||
if (len > strbuf_empty_length(s))
|
||||
strbuf_resize(s, s->length + len);
|
||||
}
|
||||
|
||||
static inline char *strbuf_empty_ptr(strbuf_t *s)
|
||||
{
|
||||
return s->buf + s->length;
|
||||
}
|
||||
|
||||
static inline void strbuf_extend_length(strbuf_t *s, int len)
|
||||
{
|
||||
s->length += len;
|
||||
}
|
||||
|
||||
static inline int strbuf_length(strbuf_t *s)
|
||||
{
|
||||
return s->length;
|
||||
}
|
||||
|
||||
static inline void strbuf_append_char(strbuf_t *s, const char c)
|
||||
{
|
||||
strbuf_ensure_empty_length(s, 1);
|
||||
s->buf[s->length++] = c;
|
||||
}
|
||||
|
||||
static inline void strbuf_append_char_unsafe(strbuf_t *s, const char c)
|
||||
{
|
||||
s->buf[s->length++] = c;
|
||||
}
|
||||
|
||||
static inline void strbuf_append_mem(strbuf_t *s, const char *c, int len)
|
||||
{
|
||||
strbuf_ensure_empty_length(s, len);
|
||||
c_memcpy(s->buf + s->length, c, len);
|
||||
s->length += len;
|
||||
}
|
||||
|
||||
static inline void strbuf_append_mem_unsafe(strbuf_t *s, const char *c, int len)
|
||||
{
|
||||
c_memcpy(s->buf + s->length, c, len);
|
||||
s->length += len;
|
||||
}
|
||||
|
||||
static inline void strbuf_ensure_null(strbuf_t *s)
|
||||
{
|
||||
s->buf[s->length] = 0;
|
||||
}
|
||||
|
||||
static inline char *strbuf_string(strbuf_t *s, int *len)
|
||||
{
|
||||
if (len)
|
||||
*len = s->length;
|
||||
|
||||
return s->buf;
|
||||
}
|
||||
|
||||
/* vi:ai et sw=4 ts=4:
|
||||
*/
|
4
app/cjson/tests/README
Normal file
4
app/cjson/tests/README
Normal file
@ -0,0 +1,4 @@
|
||||
These JSON examples were taken from the JSON website
|
||||
(http://json.org/example.html) and RFC 4627.
|
||||
|
||||
Used with permission.
|
131
app/cjson/tests/bench.lua
Normal file
131
app/cjson/tests/bench.lua
Normal file
@ -0,0 +1,131 @@
|
||||
#!/usr/bin/env lua
|
||||
|
||||
-- This benchmark script measures wall clock time and should be
|
||||
-- run on an unloaded system.
|
||||
--
|
||||
-- Your Mileage May Vary.
|
||||
--
|
||||
-- Mark Pulford <mark@kyne.com.au>
|
||||
|
||||
local json_module = os.getenv("JSON_MODULE") or "cjson"
|
||||
|
||||
require "socket"
|
||||
local json = require(json_module)
|
||||
local util = require "cjson.util"
|
||||
|
||||
local function find_func(mod, funcnames)
|
||||
for _, v in ipairs(funcnames) do
|
||||
if mod[v] then
|
||||
return mod[v]
|
||||
end
|
||||
end
|
||||
|
||||
return nil
|
||||
end
|
||||
|
||||
local json_encode = find_func(json, { "encode", "Encode", "to_string", "stringify", "json" })
|
||||
local json_decode = find_func(json, { "decode", "Decode", "to_value", "parse" })
|
||||
|
||||
local function average(t)
|
||||
local total = 0
|
||||
for _, v in ipairs(t) do
|
||||
total = total + v
|
||||
end
|
||||
return total / #t
|
||||
end
|
||||
|
||||
function benchmark(tests, seconds, rep)
|
||||
local function bench(func, iter)
|
||||
-- Use socket.gettime() to measure microsecond resolution
|
||||
-- wall clock time.
|
||||
local t = socket.gettime()
|
||||
for i = 1, iter do
|
||||
func(i)
|
||||
end
|
||||
t = socket.gettime() - t
|
||||
|
||||
-- Don't trust any results when the run lasted for less than a
|
||||
-- millisecond - return nil.
|
||||
if t < 0.001 then
|
||||
return nil
|
||||
end
|
||||
|
||||
return (iter / t)
|
||||
end
|
||||
|
||||
-- Roughly calculate the number of interations required
|
||||
-- to obtain a particular time period.
|
||||
local function calc_iter(func, seconds)
|
||||
local iter = 1
|
||||
local rate
|
||||
-- Warm up the bench function first.
|
||||
func()
|
||||
while not rate do
|
||||
rate = bench(func, iter)
|
||||
iter = iter * 10
|
||||
end
|
||||
return math.ceil(seconds * rate)
|
||||
end
|
||||
|
||||
local test_results = {}
|
||||
for name, func in pairs(tests) do
|
||||
-- k(number), v(string)
|
||||
-- k(string), v(function)
|
||||
-- k(number), v(function)
|
||||
if type(func) == "string" then
|
||||
name = func
|
||||
func = _G[name]
|
||||
end
|
||||
|
||||
local iter = calc_iter(func, seconds)
|
||||
|
||||
local result = {}
|
||||
for i = 1, rep do
|
||||
result[i] = bench(func, iter)
|
||||
end
|
||||
|
||||
-- Remove the slowest half (round down) of the result set
|
||||
table.sort(result)
|
||||
for i = 1, math.floor(#result / 2) do
|
||||
table.remove(result, 1)
|
||||
end
|
||||
|
||||
test_results[name] = average(result)
|
||||
end
|
||||
|
||||
return test_results
|
||||
end
|
||||
|
||||
function bench_file(filename)
|
||||
local data_json = util.file_load(filename)
|
||||
local data_obj = json_decode(data_json)
|
||||
|
||||
local function test_encode()
|
||||
json_encode(data_obj)
|
||||
end
|
||||
local function test_decode()
|
||||
json_decode(data_json)
|
||||
end
|
||||
|
||||
local tests = {}
|
||||
if json_encode then tests.encode = test_encode end
|
||||
if json_decode then tests.decode = test_decode end
|
||||
|
||||
return benchmark(tests, 0.1, 5)
|
||||
end
|
||||
|
||||
-- Optionally load any custom configuration required for this module
|
||||
local success, data = pcall(util.file_load, ("bench-%s.lua"):format(json_module))
|
||||
if success then
|
||||
util.run_script(data, _G)
|
||||
configure(json)
|
||||
end
|
||||
|
||||
for i = 1, #arg do
|
||||
local results = bench_file(arg[i])
|
||||
for k, v in pairs(results) do
|
||||
print(("%s\t%s\t%d"):format(arg[i], k, v))
|
||||
end
|
||||
end
|
||||
|
||||
-- vi:ai et sw=4 ts=4:
|
22
app/cjson/tests/example1.json
Normal file
22
app/cjson/tests/example1.json
Normal file
@ -0,0 +1,22 @@
|
||||
{
|
||||
"glossary": {
|
||||
"title": "example glossary",
|
||||
"GlossDiv": {
|
||||
"title": "S",
|
||||
"GlossList": {
|
||||
"GlossEntry": {
|
||||
"ID": "SGML",
|
||||
"SortAs": "SGML",
|
||||
"GlossTerm": "Standard Generalized Mark up Language",
|
||||
"Acronym": "SGML",
|
||||
"Abbrev": "ISO 8879:1986",
|
||||
"GlossDef": {
|
||||
"para": "A meta-markup language, used to create markup languages such as DocBook.",
|
||||
"GlossSeeAlso": ["GML", "XML"]
|
||||
},
|
||||
"GlossSee": "markup"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
11
app/cjson/tests/example2.json
Normal file
11
app/cjson/tests/example2.json
Normal file
@ -0,0 +1,11 @@
|
||||
{"menu": {
|
||||
"id": "file",
|
||||
"value": "File",
|
||||
"popup": {
|
||||
"menuitem": [
|
||||
{"value": "New", "onclick": "CreateNewDoc()"},
|
||||
{"value": "Open", "onclick": "OpenDoc()"},
|
||||
{"value": "Close", "onclick": "CloseDoc()"}
|
||||
]
|
||||
}
|
||||
}}
|
26
app/cjson/tests/example3.json
Normal file
26
app/cjson/tests/example3.json
Normal file
@ -0,0 +1,26 @@
|
||||
{"widget": {
|
||||
"debug": "on",
|
||||
"window": {
|
||||
"title": "Sample Konfabulator Widget",
|
||||
"name": "main_window",
|
||||
"width": 500,
|
||||
"height": 500
|
||||
},
|
||||
"image": {
|
||||
"src": "Images/Sun.png",
|
||||
"name": "sun1",
|
||||
"hOffset": 250,
|
||||
"vOffset": 250,
|
||||
"alignment": "center"
|
||||
},
|
||||
"text": {
|
||||
"data": "Click Here",
|
||||
"size": 36,
|
||||
"style": "bold",
|
||||
"name": "text1",
|
||||
"hOffset": 250,
|
||||
"vOffset": 100,
|
||||
"alignment": "center",
|
||||
"onMouseUp": "sun1.opacity = (sun1.opacity / 100) * 90;"
|
||||
}
|
||||
}}
|
88
app/cjson/tests/example4.json
Normal file
88
app/cjson/tests/example4.json
Normal file
@ -0,0 +1,88 @@
|
||||
{"web-app": {
|
||||
"servlet": [
|
||||
{
|
||||
"servlet-name": "cofaxCDS",
|
||||
"servlet-class": "org.cofax.cds.CDSServlet",
|
||||
"init-param": {
|
||||
"configGlossary:installationAt": "Philadelphia, PA",
|
||||
"configGlossary:adminEmail": "ksm@pobox.com",
|
||||
"configGlossary:poweredBy": "Cofax",
|
||||
"configGlossary:poweredByIcon": "/images/cofax.gif",
|
||||
"configGlossary:staticPath": "/content/static",
|
||||
"templateProcessorClass": "org.cofax.WysiwygTemplate",
|
||||
"templateLoaderClass": "org.cofax.FilesTemplateLoader",
|
||||
"templatePath": "templates",
|
||||
"templateOverridePath": "",
|
||||
"defaultListTemplate": "listTemplate.htm",
|
||||
"defaultFileTemplate": "articleTemplate.htm",
|
||||
"useJSP": false,
|
||||
"jspListTemplate": "listTemplate.jsp",
|
||||
"jspFileTemplate": "articleTemplate.jsp",
|
||||
"cachePackageTagsTrack": 200,
|
||||
"cachePackageTagsStore": 200,
|
||||
"cachePackageTagsRefresh": 60,
|
||||
"cacheTemplatesTrack": 100,
|
||||
"cacheTemplatesStore": 50,
|
||||
"cacheTemplatesRefresh": 15,
|
||||
"cachePagesTrack": 200,
|
||||
"cachePagesStore": 100,
|
||||
"cachePagesRefresh": 10,
|
||||
"cachePagesDirtyRead": 10,
|
||||
"searchEngineListTemplate": "forSearchEnginesList.htm",
|
||||
"searchEngineFileTemplate": "forSearchEngines.htm",
|
||||
"searchEngineRobotsDb": "WEB-INF/robots.db",
|
||||
"useDataStore": true,
|
||||
"dataStoreClass": "org.cofax.SqlDataStore",
|
||||
"redirectionClass": "org.cofax.SqlRedirection",
|
||||
"dataStoreName": "cofax",
|
||||
"dataStoreDriver": "com.microsoft.jdbc.sqlserver.SQLServerDriver",
|
||||
"dataStoreUrl": "jdbc:microsoft:sqlserver://LOCALHOST:1433;DatabaseName=goon",
|
||||
"dataStoreUser": "sa",
|
||||
"dataStorePassword": "dataStoreTestQuery",
|
||||
"dataStoreTestQuery": "SET NOCOUNT ON;select test='test';",
|
||||
"dataStoreLogFile": "/usr/local/tomcat/logs/datastore.log",
|
||||
"dataStoreInitConns": 10,
|
||||
"dataStoreMaxConns": 100,
|
||||
"dataStoreConnUsageLimit": 100,
|
||||
"dataStoreLogLevel": "debug",
|
||||
"maxUrlLength": 500}},
|
||||
{
|
||||
"servlet-name": "cofaxEmail",
|
||||
"servlet-class": "org.cofax.cds.EmailServlet",
|
||||
"init-param": {
|
||||
"mailHost": "mail1",
|
||||
"mailHostOverride": "mail2"}},
|
||||
{
|
||||
"servlet-name": "cofaxAdmin",
|
||||
"servlet-class": "org.cofax.cds.AdminServlet"},
|
||||
|
||||
{
|
||||
"servlet-name": "fileServlet",
|
||||
"servlet-class": "org.cofax.cds.FileServlet"},
|
||||
{
|
||||
"servlet-name": "cofaxTools",
|
||||
"servlet-class": "org.cofax.cms.CofaxToolsServlet",
|
||||
"init-param": {
|
||||
"templatePath": "toolstemplates/",
|
||||
"log": 1,
|
||||
"logLocation": "/usr/local/tomcat/logs/CofaxTools.log",
|
||||
"logMaxSize": "",
|
||||
"dataLog": 1,
|
||||
"dataLogLocation": "/usr/local/tomcat/logs/dataLog.log",
|
||||
"dataLogMaxSize": "",
|
||||
"removePageCache": "/content/admin/remove?cache=pages&id=",
|
||||
"removeTemplateCache": "/content/admin/remove?cache=templates&id=",
|
||||
"fileTransferFolder": "/usr/local/tomcat/webapps/content/fileTransferFolder",
|
||||
"lookInContext": 1,
|
||||
"adminGroupID": 4,
|
||||
"betaServer": true}}],
|
||||
"servlet-mapping": {
|
||||
"cofaxCDS": "/",
|
||||
"cofaxEmail": "/cofaxutil/aemail/*",
|
||||
"cofaxAdmin": "/admin/*",
|
||||
"fileServlet": "/static/*",
|
||||
"cofaxTools": "/tools/*"},
|
||||
|
||||
"taglib": {
|
||||
"taglib-uri": "cofax.tld",
|
||||
"taglib-location": "/WEB-INF/tlds/cofax.tld"}}}
|
27
app/cjson/tests/example5.json
Normal file
27
app/cjson/tests/example5.json
Normal file
@ -0,0 +1,27 @@
|
||||
{"menu": {
|
||||
"header": "SVG Viewer",
|
||||
"items": [
|
||||
{"id": "Open"},
|
||||
{"id": "OpenNew", "label": "Open New"},
|
||||
null,
|
||||
{"id": "ZoomIn", "label": "Zoom In"},
|
||||
{"id": "ZoomOut", "label": "Zoom Out"},
|
||||
{"id": "OriginalView", "label": "Original View"},
|
||||
null,
|
||||
{"id": "Quality"},
|
||||
{"id": "Pause"},
|
||||
{"id": "Mute"},
|
||||
null,
|
||||
{"id": "Find", "label": "Find..."},
|
||||
{"id": "FindAgain", "label": "Find Again"},
|
||||
{"id": "Copy"},
|
||||
{"id": "CopyAgain", "label": "Copy Again"},
|
||||
{"id": "CopySVG", "label": "Copy SVG"},
|
||||
{"id": "ViewSVG", "label": "View SVG"},
|
||||
{"id": "ViewSource", "label": "View Source"},
|
||||
{"id": "SaveAs", "label": "Save As"},
|
||||
null,
|
||||
{"id": "Help"},
|
||||
{"id": "About", "label": "About Adobe CVG Viewer..."}
|
||||
]
|
||||
}}
|
23
app/cjson/tests/genutf8.pl
Normal file
23
app/cjson/tests/genutf8.pl
Normal file
@ -0,0 +1,23 @@
|
||||
#!/usr/bin/env perl
|
||||
|
||||
# Create test comparison data using a different UTF-8 implementation.
|
||||
|
||||
# The generated utf8.dat file must have the following MD5 sum:
|
||||
# cff03b039d850f370a7362f3313e5268
|
||||
|
||||
use strict;
|
||||
|
||||
# 0xD800 - 0xDFFF are used to encode supplementary codepoints
|
||||
# 0x10000 - 0x10FFFF are supplementary codepoints
|
||||
my (@codepoints) = (0 .. 0xD7FF, 0xE000 .. 0x10FFFF);
|
||||
|
||||
my $utf8 = pack("U*", @codepoints);
|
||||
defined($utf8) or die "Unable create UTF-8 string\n";
|
||||
|
||||
open(FH, ">:utf8", "utf8.dat")
|
||||
or die "Unable to open utf8.dat: $!\n";
|
||||
print FH $utf8
|
||||
or die "Unable to write utf8.dat\n";
|
||||
close(FH);
|
||||
|
||||
# vi:ai et sw=4 ts=4:
|
7
app/cjson/tests/numbers.json
Normal file
7
app/cjson/tests/numbers.json
Normal file
@ -0,0 +1,7 @@
|
||||
[ 0.110001,
|
||||
0.12345678910111,
|
||||
0.412454033640,
|
||||
2.6651441426902,
|
||||
2.718281828459,
|
||||
3.1415926535898,
|
||||
2.1406926327793 ]
|
1
app/cjson/tests/octets-escaped.dat
Normal file
1
app/cjson/tests/octets-escaped.dat
Normal file
@ -0,0 +1 @@
|
||||
"\u0000\u0001\u0002\u0003\u0004\u0005\u0006\u0007\b\t\n\u000b\f\r\u000e\u000f\u0010\u0011\u0012\u0013\u0014\u0015\u0016\u0017\u0018\u0019\u001a\u001b\u001c\u001d\u001e\u001f !\"#$%&'()*+,-.\/0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~\u007f<37><66><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>"
|
13
app/cjson/tests/rfc-example1.json
Normal file
13
app/cjson/tests/rfc-example1.json
Normal file
@ -0,0 +1,13 @@
|
||||
{
|
||||
"Image": {
|
||||
"Width": 800,
|
||||
"Height": 600,
|
||||
"Title": "View from 15th Floor",
|
||||
"Thumbnail": {
|
||||
"Url": "http://www.example.com/image/481989943",
|
||||
"Height": 125,
|
||||
"Width": "100"
|
||||
},
|
||||
"IDs": [116, 943, 234, 38793]
|
||||
}
|
||||
}
|
22
app/cjson/tests/rfc-example2.json
Normal file
22
app/cjson/tests/rfc-example2.json
Normal file
@ -0,0 +1,22 @@
|
||||
[
|
||||
{
|
||||
"precision": "zip",
|
||||
"Latitude": 37.7668,
|
||||
"Longitude": -122.3959,
|
||||
"Address": "",
|
||||
"City": "SAN FRANCISCO",
|
||||
"State": "CA",
|
||||
"Zip": "94107",
|
||||
"Country": "US"
|
||||
},
|
||||
{
|
||||
"precision": "zip",
|
||||
"Latitude": 37.371991,
|
||||
"Longitude": -122.026020,
|
||||
"Address": "",
|
||||
"City": "SUNNYVALE",
|
||||
"State": "CA",
|
||||
"Zip": "94085",
|
||||
"Country": "US"
|
||||
}
|
||||
]
|
425
app/cjson/tests/test.lua
Normal file
425
app/cjson/tests/test.lua
Normal file
@ -0,0 +1,425 @@
|
||||
#!/usr/bin/env lua
|
||||
|
||||
-- Lua CJSON tests
|
||||
--
|
||||
-- Mark Pulford <mark@kyne.com.au>
|
||||
--
|
||||
-- Note: The output of this script is easier to read with "less -S"
|
||||
|
||||
local json = require "cjson"
|
||||
local json_safe = require "cjson.safe"
|
||||
local util = require "cjson.util"
|
||||
|
||||
local function gen_raw_octets()
|
||||
local chars = {}
|
||||
for i = 0, 255 do chars[i + 1] = string.char(i) end
|
||||
return table.concat(chars)
|
||||
end
|
||||
|
||||
-- Generate every UTF-16 codepoint, including supplementary codes
|
||||
local function gen_utf16_escaped()
|
||||
-- Create raw table escapes
|
||||
local utf16_escaped = {}
|
||||
local count = 0
|
||||
|
||||
local function append_escape(code)
|
||||
local esc = ('\\u%04X'):format(code)
|
||||
table.insert(utf16_escaped, esc)
|
||||
end
|
||||
|
||||
table.insert(utf16_escaped, '"')
|
||||
for i = 0, 0xD7FF do
|
||||
append_escape(i)
|
||||
end
|
||||
-- Skip 0xD800 - 0xDFFF since they are used to encode supplementary
|
||||
-- codepoints
|
||||
for i = 0xE000, 0xFFFF do
|
||||
append_escape(i)
|
||||
end
|
||||
-- Append surrogate pair for each supplementary codepoint
|
||||
for high = 0xD800, 0xDBFF do
|
||||
for low = 0xDC00, 0xDFFF do
|
||||
append_escape(high)
|
||||
append_escape(low)
|
||||
end
|
||||
end
|
||||
table.insert(utf16_escaped, '"')
|
||||
|
||||
return table.concat(utf16_escaped)
|
||||
end
|
||||
|
||||
function load_testdata()
|
||||
local data = {}
|
||||
|
||||
-- Data for 8bit raw <-> escaped octets tests
|
||||
data.octets_raw = gen_raw_octets()
|
||||
data.octets_escaped = util.file_load("octets-escaped.dat")
|
||||
|
||||
-- Data for \uXXXX -> UTF-8 test
|
||||
data.utf16_escaped = gen_utf16_escaped()
|
||||
|
||||
-- Load matching data for utf16_escaped
|
||||
local utf8_loaded
|
||||
utf8_loaded, data.utf8_raw = pcall(util.file_load, "utf8.dat")
|
||||
if not utf8_loaded then
|
||||
data.utf8_raw = "Failed to load utf8.dat - please run genutf8.pl"
|
||||
end
|
||||
|
||||
data.table_cycle = {}
|
||||
data.table_cycle[1] = data.table_cycle
|
||||
|
||||
local big = {}
|
||||
for i = 1, 1100 do
|
||||
big = { { 10, false, true, json.null }, "string", a = big }
|
||||
end
|
||||
data.deeply_nested_data = big
|
||||
|
||||
return data
|
||||
end
|
||||
|
||||
function test_decode_cycle(filename)
|
||||
local obj1 = json.decode(util.file_load(filename))
|
||||
local obj2 = json.decode(json.encode(obj1))
|
||||
return util.compare_values(obj1, obj2)
|
||||
end
|
||||
|
||||
-- Set up data used in tests
|
||||
local Inf = math.huge;
|
||||
local NaN = math.huge * 0;
|
||||
|
||||
local testdata = load_testdata()
|
||||
|
||||
local cjson_tests = {
|
||||
-- Test API variables
|
||||
{ "Check module name, version",
|
||||
function () return json._NAME, json._VERSION end, { },
|
||||
true, { "cjson", "2.1devel" } },
|
||||
|
||||
-- Test decoding simple types
|
||||
{ "Decode string",
|
||||
json.decode, { '"test string"' }, true, { "test string" } },
|
||||
{ "Decode numbers",
|
||||
json.decode, { '[ 0.0, -5e3, -1, 0.3e-3, 1023.2, 0e10 ]' },
|
||||
true, { { 0.0, -5000, -1, 0.0003, 1023.2, 0 } } },
|
||||
{ "Decode null",
|
||||
json.decode, { 'null' }, true, { json.null } },
|
||||
{ "Decode true",
|
||||
json.decode, { 'true' }, true, { true } },
|
||||
{ "Decode false",
|
||||
json.decode, { 'false' }, true, { false } },
|
||||
{ "Decode object with numeric keys",
|
||||
json.decode, { '{ "1": "one", "3": "three" }' },
|
||||
true, { { ["1"] = "one", ["3"] = "three" } } },
|
||||
{ "Decode object with string keys",
|
||||
json.decode, { '{ "a": "a", "b": "b" }' },
|
||||
true, { { a = "a", b = "b" } } },
|
||||
{ "Decode array",
|
||||
json.decode, { '[ "one", null, "three" ]' },
|
||||
true, { { "one", json.null, "three" } } },
|
||||
|
||||
-- Test decoding errors
|
||||
{ "Decode UTF-16BE [throw error]",
|
||||
json.decode, { '\0"\0"' },
|
||||
false, { "JSON parser does not support UTF-16 or UTF-32" } },
|
||||
{ "Decode UTF-16LE [throw error]",
|
||||
json.decode, { '"\0"\0' },
|
||||
false, { "JSON parser does not support UTF-16 or UTF-32" } },
|
||||
{ "Decode UTF-32BE [throw error]",
|
||||
json.decode, { '\0\0\0"' },
|
||||
false, { "JSON parser does not support UTF-16 or UTF-32" } },
|
||||
{ "Decode UTF-32LE [throw error]",
|
||||
json.decode, { '"\0\0\0' },
|
||||
false, { "JSON parser does not support UTF-16 or UTF-32" } },
|
||||
{ "Decode partial JSON [throw error]",
|
||||
json.decode, { '{ "unexpected eof": ' },
|
||||
false, { "Expected value but found T_END at character 21" } },
|
||||
{ "Decode with extra comma [throw error]",
|
||||
json.decode, { '{ "extra data": true }, false' },
|
||||
false, { "Expected the end but found T_COMMA at character 23" } },
|
||||
{ "Decode invalid escape code [throw error]",
|
||||
json.decode, { [[ { "bad escape \q code" } ]] },
|
||||
false, { "Expected object key string but found invalid escape code at character 16" } },
|
||||
{ "Decode invalid unicode escape [throw error]",
|
||||
json.decode, { [[ { "bad unicode \u0f6 escape" } ]] },
|
||||
false, { "Expected object key string but found invalid unicode escape code at character 17" } },
|
||||
{ "Decode invalid keyword [throw error]",
|
||||
json.decode, { ' [ "bad barewood", test ] ' },
|
||||
false, { "Expected value but found invalid token at character 20" } },
|
||||
{ "Decode invalid number #1 [throw error]",
|
||||
json.decode, { '[ -+12 ]' },
|
||||
false, { "Expected value but found invalid number at character 3" } },
|
||||
{ "Decode invalid number #2 [throw error]",
|
||||
json.decode, { '-v' },
|
||||
false, { "Expected value but found invalid number at character 1" } },
|
||||
{ "Decode invalid number exponent [throw error]",
|
||||
json.decode, { '[ 0.4eg10 ]' },
|
||||
false, { "Expected comma or array end but found invalid token at character 6" } },
|
||||
|
||||
-- Test decoding nested arrays / objects
|
||||
{ "Set decode_max_depth(5)",
|
||||
json.decode_max_depth, { 5 }, true, { 5 } },
|
||||
{ "Decode array at nested limit",
|
||||
json.decode, { '[[[[[ "nested" ]]]]]' },
|
||||
true, { {{{{{ "nested" }}}}} } },
|
||||
{ "Decode array over nested limit [throw error]",
|
||||
json.decode, { '[[[[[[ "nested" ]]]]]]' },
|
||||
false, { "Found too many nested data structures (6) at character 6" } },
|
||||
{ "Decode object at nested limit",
|
||||
json.decode, { '{"a":{"b":{"c":{"d":{"e":"nested"}}}}}' },
|
||||
true, { {a={b={c={d={e="nested"}}}}} } },
|
||||
{ "Decode object over nested limit [throw error]",
|
||||
json.decode, { '{"a":{"b":{"c":{"d":{"e":{"f":"nested"}}}}}}' },
|
||||
false, { "Found too many nested data structures (6) at character 26" } },
|
||||
{ "Set decode_max_depth(1000)",
|
||||
json.decode_max_depth, { 1000 }, true, { 1000 } },
|
||||
{ "Decode deeply nested array [throw error]",
|
||||
json.decode, { string.rep("[", 1100) .. '1100' .. string.rep("]", 1100)},
|
||||
false, { "Found too many nested data structures (1001) at character 1001" } },
|
||||
|
||||
-- Test encoding nested tables
|
||||
{ "Set encode_max_depth(5)",
|
||||
json.encode_max_depth, { 5 }, true, { 5 } },
|
||||
{ "Encode nested table as array at nested limit",
|
||||
json.encode, { {{{{{"nested"}}}}} }, true, { '[[[[["nested"]]]]]' } },
|
||||
{ "Encode nested table as array after nested limit [throw error]",
|
||||
json.encode, { { {{{{{"nested"}}}}} } },
|
||||
false, { "Cannot serialise, excessive nesting (6)" } },
|
||||
{ "Encode nested table as object at nested limit",
|
||||
json.encode, { {a={b={c={d={e="nested"}}}}} },
|
||||
true, { '{"a":{"b":{"c":{"d":{"e":"nested"}}}}}' } },
|
||||
{ "Encode nested table as object over nested limit [throw error]",
|
||||
json.encode, { {a={b={c={d={e={f="nested"}}}}}} },
|
||||
false, { "Cannot serialise, excessive nesting (6)" } },
|
||||
{ "Encode table with cycle [throw error]",
|
||||
json.encode, { testdata.table_cycle },
|
||||
false, { "Cannot serialise, excessive nesting (6)" } },
|
||||
{ "Set encode_max_depth(1000)",
|
||||
json.encode_max_depth, { 1000 }, true, { 1000 } },
|
||||
{ "Encode deeply nested data [throw error]",
|
||||
json.encode, { testdata.deeply_nested_data },
|
||||
false, { "Cannot serialise, excessive nesting (1001)" } },
|
||||
|
||||
-- Test encoding simple types
|
||||
{ "Encode null",
|
||||
json.encode, { json.null }, true, { 'null' } },
|
||||
{ "Encode true",
|
||||
json.encode, { true }, true, { 'true' } },
|
||||
{ "Encode false",
|
||||
json.encode, { false }, true, { 'false' } },
|
||||
{ "Encode empty object",
|
||||
json.encode, { { } }, true, { '{}' } },
|
||||
{ "Encode integer",
|
||||
json.encode, { 10 }, true, { '10' } },
|
||||
{ "Encode string",
|
||||
json.encode, { "hello" }, true, { '"hello"' } },
|
||||
{ "Encode Lua function [throw error]",
|
||||
json.encode, { function () end },
|
||||
false, { "Cannot serialise function: type not supported" } },
|
||||
|
||||
-- Test decoding invalid numbers
|
||||
{ "Set decode_invalid_numbers(true)",
|
||||
json.decode_invalid_numbers, { true }, true, { true } },
|
||||
{ "Decode hexadecimal",
|
||||
json.decode, { '0x6.ffp1' }, true, { 13.9921875 } },
|
||||
{ "Decode numbers with leading zero",
|
||||
json.decode, { '[ 0123, 00.33 ]' }, true, { { 123, 0.33 } } },
|
||||
{ "Decode +-Inf",
|
||||
json.decode, { '[ +Inf, Inf, -Inf ]' }, true, { { Inf, Inf, -Inf } } },
|
||||
{ "Decode +-Infinity",
|
||||
json.decode, { '[ +Infinity, Infinity, -Infinity ]' },
|
||||
true, { { Inf, Inf, -Inf } } },
|
||||
{ "Decode +-NaN",
|
||||
json.decode, { '[ +NaN, NaN, -NaN ]' }, true, { { NaN, NaN, NaN } } },
|
||||
{ "Decode Infrared (not infinity) [throw error]",
|
||||
json.decode, { 'Infrared' },
|
||||
false, { "Expected the end but found invalid token at character 4" } },
|
||||
{ "Decode Noodle (not NaN) [throw error]",
|
||||
json.decode, { 'Noodle' },
|
||||
false, { "Expected value but found invalid token at character 1" } },
|
||||
{ "Set decode_invalid_numbers(false)",
|
||||
json.decode_invalid_numbers, { false }, true, { false } },
|
||||
{ "Decode hexadecimal [throw error]",
|
||||
json.decode, { '0x6' },
|
||||
false, { "Expected value but found invalid number at character 1" } },
|
||||
{ "Decode numbers with leading zero [throw error]",
|
||||
json.decode, { '[ 0123, 00.33 ]' },
|
||||
false, { "Expected value but found invalid number at character 3" } },
|
||||
{ "Decode +-Inf [throw error]",
|
||||
json.decode, { '[ +Inf, Inf, -Inf ]' },
|
||||
false, { "Expected value but found invalid token at character 3" } },
|
||||
{ "Decode +-Infinity [throw error]",
|
||||
json.decode, { '[ +Infinity, Infinity, -Infinity ]' },
|
||||
false, { "Expected value but found invalid token at character 3" } },
|
||||
{ "Decode +-NaN [throw error]",
|
||||
json.decode, { '[ +NaN, NaN, -NaN ]' },
|
||||
false, { "Expected value but found invalid token at character 3" } },
|
||||
{ 'Set decode_invalid_numbers("on")',
|
||||
json.decode_invalid_numbers, { "on" }, true, { true } },
|
||||
|
||||
-- Test encoding invalid numbers
|
||||
{ "Set encode_invalid_numbers(false)",
|
||||
json.encode_invalid_numbers, { false }, true, { false } },
|
||||
{ "Encode NaN [throw error]",
|
||||
json.encode, { NaN },
|
||||
false, { "Cannot serialise number: must not be NaN or Infinity" } },
|
||||
{ "Encode Infinity [throw error]",
|
||||
json.encode, { Inf },
|
||||
false, { "Cannot serialise number: must not be NaN or Infinity" } },
|
||||
{ "Set encode_invalid_numbers(\"null\")",
|
||||
json.encode_invalid_numbers, { "null" }, true, { "null" } },
|
||||
{ "Encode NaN as null",
|
||||
json.encode, { NaN }, true, { "null" } },
|
||||
{ "Encode Infinity as null",
|
||||
json.encode, { Inf }, true, { "null" } },
|
||||
{ "Set encode_invalid_numbers(true)",
|
||||
json.encode_invalid_numbers, { true }, true, { true } },
|
||||
{ "Encode NaN",
|
||||
json.encode, { NaN }, true, { "NaN" } },
|
||||
{ "Encode +Infinity",
|
||||
json.encode, { Inf }, true, { "Infinity" } },
|
||||
{ "Encode -Infinity",
|
||||
json.encode, { -Inf }, true, { "-Infinity" } },
|
||||
{ 'Set encode_invalid_numbers("off")',
|
||||
json.encode_invalid_numbers, { "off" }, true, { false } },
|
||||
|
||||
-- Test encoding tables
|
||||
{ "Set encode_sparse_array(true, 2, 3)",
|
||||
json.encode_sparse_array, { true, 2, 3 }, true, { true, 2, 3 } },
|
||||
{ "Encode sparse table as array #1",
|
||||
json.encode, { { [3] = "sparse test" } },
|
||||
true, { '[null,null,"sparse test"]' } },
|
||||
{ "Encode sparse table as array #2",
|
||||
json.encode, { { [1] = "one", [4] = "sparse test" } },
|
||||
true, { '["one",null,null,"sparse test"]' } },
|
||||
{ "Encode sparse array as object",
|
||||
json.encode, { { [1] = "one", [5] = "sparse test" } },
|
||||
true, { '{"1":"one","5":"sparse test"}' } },
|
||||
{ "Encode table with numeric string key as object",
|
||||
json.encode, { { ["2"] = "numeric string key test" } },
|
||||
true, { '{"2":"numeric string key test"}' } },
|
||||
{ "Set encode_sparse_array(false)",
|
||||
json.encode_sparse_array, { false }, true, { false, 2, 3 } },
|
||||
{ "Encode table with incompatible key [throw error]",
|
||||
json.encode, { { [false] = "wrong" } },
|
||||
false, { "Cannot serialise boolean: table key must be a number or string" } },
|
||||
|
||||
-- Test escaping
|
||||
{ "Encode all octets (8-bit clean)",
|
||||
json.encode, { testdata.octets_raw }, true, { testdata.octets_escaped } },
|
||||
{ "Decode all escaped octets",
|
||||
json.decode, { testdata.octets_escaped }, true, { testdata.octets_raw } },
|
||||
{ "Decode single UTF-16 escape",
|
||||
json.decode, { [["\uF800"]] }, true, { "\239\160\128" } },
|
||||
{ "Decode all UTF-16 escapes (including surrogate combinations)",
|
||||
json.decode, { testdata.utf16_escaped }, true, { testdata.utf8_raw } },
|
||||
{ "Decode swapped surrogate pair [throw error]",
|
||||
json.decode, { [["\uDC00\uD800"]] },
|
||||
false, { "Expected value but found invalid unicode escape code at character 2" } },
|
||||
{ "Decode duplicate high surrogate [throw error]",
|
||||
json.decode, { [["\uDB00\uDB00"]] },
|
||||
false, { "Expected value but found invalid unicode escape code at character 2" } },
|
||||
{ "Decode duplicate low surrogate [throw error]",
|
||||
json.decode, { [["\uDB00\uDB00"]] },
|
||||
false, { "Expected value but found invalid unicode escape code at character 2" } },
|
||||
{ "Decode missing low surrogate [throw error]",
|
||||
json.decode, { [["\uDB00"]] },
|
||||
false, { "Expected value but found invalid unicode escape code at character 2" } },
|
||||
{ "Decode invalid low surrogate [throw error]",
|
||||
json.decode, { [["\uDB00\uD"]] },
|
||||
false, { "Expected value but found invalid unicode escape code at character 2" } },
|
||||
|
||||
-- Test locale support
|
||||
--
|
||||
-- The standard Lua interpreter is ANSI C online doesn't support locales
|
||||
-- by default. Force a known problematic locale to test strtod()/sprintf().
|
||||
{ "Set locale to cs_CZ (comma separator)", function ()
|
||||
os.setlocale("cs_CZ")
|
||||
json.new()
|
||||
end },
|
||||
{ "Encode number under comma locale",
|
||||
json.encode, { 1.5 }, true, { '1.5' } },
|
||||
{ "Decode number in array under comma locale",
|
||||
json.decode, { '[ 10, "test" ]' }, true, { { 10, "test" } } },
|
||||
{ "Revert locale to POSIX", function ()
|
||||
os.setlocale("C")
|
||||
json.new()
|
||||
end },
|
||||
|
||||
-- Test encode_keep_buffer() and enable_number_precision()
|
||||
{ "Set encode_keep_buffer(false)",
|
||||
json.encode_keep_buffer, { false }, true, { false } },
|
||||
{ "Set encode_number_precision(3)",
|
||||
json.encode_number_precision, { 3 }, true, { 3 } },
|
||||
{ "Encode number with precision 3",
|
||||
json.encode, { 1/3 }, true, { "0.333" } },
|
||||
{ "Set encode_number_precision(14)",
|
||||
json.encode_number_precision, { 14 }, true, { 14 } },
|
||||
{ "Set encode_keep_buffer(true)",
|
||||
json.encode_keep_buffer, { true }, true, { true } },
|
||||
|
||||
-- Test config API errors
|
||||
-- Function is listed as '?' due to pcall
|
||||
{ "Set encode_number_precision(0) [throw error]",
|
||||
json.encode_number_precision, { 0 },
|
||||
false, { "bad argument #1 to '?' (expected integer between 1 and 14)" } },
|
||||
{ "Set encode_number_precision(\"five\") [throw error]",
|
||||
json.encode_number_precision, { "five" },
|
||||
false, { "bad argument #1 to '?' (number expected, got string)" } },
|
||||
{ "Set encode_keep_buffer(nil, true) [throw error]",
|
||||
json.encode_keep_buffer, { nil, true },
|
||||
false, { "bad argument #2 to '?' (found too many arguments)" } },
|
||||
{ "Set encode_max_depth(\"wrong\") [throw error]",
|
||||
json.encode_max_depth, { "wrong" },
|
||||
false, { "bad argument #1 to '?' (number expected, got string)" } },
|
||||
{ "Set decode_max_depth(0) [throw error]",
|
||||
json.decode_max_depth, { "0" },
|
||||
false, { "bad argument #1 to '?' (expected integer between 1 and 2147483647)" } },
|
||||
{ "Set encode_invalid_numbers(-2) [throw error]",
|
||||
json.encode_invalid_numbers, { -2 },
|
||||
false, { "bad argument #1 to '?' (invalid option '-2')" } },
|
||||
{ "Set decode_invalid_numbers(true, false) [throw error]",
|
||||
json.decode_invalid_numbers, { true, false },
|
||||
false, { "bad argument #2 to '?' (found too many arguments)" } },
|
||||
{ "Set encode_sparse_array(\"not quite on\") [throw error]",
|
||||
json.encode_sparse_array, { "not quite on" },
|
||||
false, { "bad argument #1 to '?' (invalid option 'not quite on')" } },
|
||||
|
||||
{ "Reset Lua CJSON configuration", function () json = json.new() end },
|
||||
-- Wrap in a function to ensure the table returned by json.new() is used
|
||||
{ "Check encode_sparse_array()",
|
||||
function (...) return json.encode_sparse_array(...) end, { },
|
||||
true, { false, 2, 10 } },
|
||||
|
||||
{ "Encode (safe) simple value",
|
||||
json_safe.encode, { true },
|
||||
true, { "true" } },
|
||||
{ "Encode (safe) argument validation [throw error]",
|
||||
json_safe.encode, { "arg1", "arg2" },
|
||||
false, { "bad argument #1 to '?' (expected 1 argument)" } },
|
||||
{ "Decode (safe) error generation",
|
||||
json_safe.decode, { "Oops" },
|
||||
true, { nil, "Expected value but found invalid token at character 1" } },
|
||||
{ "Decode (safe) error generation after new()",
|
||||
function(...) return json_safe.new().decode(...) end, { "Oops" },
|
||||
true, { nil, "Expected value but found invalid token at character 1" } },
|
||||
}
|
||||
|
||||
print(("==> Testing Lua CJSON version %s\n"):format(json._VERSION))
|
||||
|
||||
util.run_test_group(cjson_tests)
|
||||
|
||||
for _, filename in ipairs(arg) do
|
||||
util.run_test("Decode cycle " .. filename, test_decode_cycle, { filename },
|
||||
true, { true })
|
||||
end
|
||||
|
||||
local pass, total = util.run_test_summary()
|
||||
|
||||
if pass == total then
|
||||
print("==> Summary: all tests succeeded")
|
||||
else
|
||||
print(("==> Summary: %d/%d tests failed"):format(total - pass, total))
|
||||
os.exit(1)
|
||||
end
|
||||
|
||||
-- vi:ai et sw=4 ts=4:
|
1
app/cjson/tests/types.json
Normal file
1
app/cjson/tests/types.json
Normal file
@ -0,0 +1 @@
|
||||
{ "array": [ 10, true, null ] }
|
21
app/include/u8g_config.h
Normal file
21
app/include/u8g_config.h
Normal file
@ -0,0 +1,21 @@
|
||||
#ifndef __U8G_CONFIG_H__
|
||||
#define __U8G_CONFIG_H__
|
||||
|
||||
|
||||
// Configure U8glib fonts
|
||||
// add a U8G_FONT_TABLE_ENTRY for each font you want to compile into the image
|
||||
#define U8G_FONT_TABLE_ENTRY(font)
|
||||
#define U8G_FONT_TABLE \
|
||||
U8G_FONT_TABLE_ENTRY(font_6x10) \
|
||||
U8G_FONT_TABLE_ENTRY(font_chikita)
|
||||
#undef U8G_FONT_TABLE_ENTRY
|
||||
|
||||
|
||||
// Enable display drivers
|
||||
#define U8G_SSD1306_128x64_I2C
|
||||
#define U8G_SSD1306_128x64_SPI
|
||||
// untested
|
||||
#undef U8G_PCD8544_84x48
|
||||
|
||||
|
||||
#endif /* __U8G_CONFIG_H__ */
|
@ -66,12 +66,4 @@
|
||||
#define LED_LOW_COUNT_DEFAULT 0
|
||||
#endif
|
||||
|
||||
// Configure U8glib fonts
|
||||
// add a U8G_FONT_TABLE_ENTRY for each font you want to compile into the image
|
||||
#define U8G_FONT_TABLE_ENTRY(font)
|
||||
#define U8G_FONT_TABLE \
|
||||
U8G_FONT_TABLE_ENTRY(font_6x10) \
|
||||
U8G_FONT_TABLE_ENTRY(font_chikita)
|
||||
#undef U8G_FONT_TABLE_ENTRY
|
||||
|
||||
#endif /* __USER_CONFIG_H__ */
|
||||
|
@ -30,6 +30,7 @@
|
||||
#define LUA_USE_MODULES_COAP
|
||||
#define LUA_USE_MODULES_U8G
|
||||
#define LUA_USE_MODULES_WS2812
|
||||
#define LUA_USE_MODULES_CJSON
|
||||
#endif /* LUA_USE_MODULES */
|
||||
|
||||
#endif /* __USER_MODULES_H__ */
|
||||
|
@ -7,6 +7,6 @@
|
||||
#define NODE_VERSION_INTERNAL 0U
|
||||
|
||||
#define NODE_VERSION "NodeMCU 0.9.6"
|
||||
#define BUILD_DATE "build 20150315"
|
||||
#define BUILD_DATE "build 20150318"
|
||||
|
||||
#endif /* __USER_VERSION_H__ */
|
||||
|
@ -25,7 +25,7 @@
|
||||
#define c_strncmp os_strncmp
|
||||
#define c_strncpy os_strncpy
|
||||
// #define c_strstr os_strstr
|
||||
#define c_strncasecmp c_strcmp
|
||||
#define c_strncasecmp c_strncmp
|
||||
|
||||
#define c_strstr strstr
|
||||
#define c_strncat strncat
|
||||
|
@ -21,6 +21,7 @@
|
||||
#define LNUMKEY LRO_NUMKEY
|
||||
#define LNILKEY LRO_NILKEY
|
||||
#define LFUNCVAL LRO_FUNCVAL
|
||||
#define LUDATA LRO_LUDATA
|
||||
#define LNUMVAL LRO_NUMVAL
|
||||
#define LROVAL LRO_ROVAL
|
||||
#define LNILVAL LRO_NILVAL
|
||||
|
@ -11,6 +11,7 @@
|
||||
/* Macros one can use to define rotable entries */
|
||||
#ifndef LUA_PACK_VALUE
|
||||
#define LRO_FUNCVAL(v) {{.p = v}, LUA_TLIGHTFUNCTION}
|
||||
#define LRO_LUDATA(v) {{.p = v}, LUA_TLIGHTUSERDATA}
|
||||
#define LRO_NUMVAL(v) {{.n = v}, LUA_TNUMBER}
|
||||
#define LRO_ROVAL(v) {{.p = (void*)v}, LUA_TROTABLE}
|
||||
#define LRO_NILVAL {{.p = NULL}, LUA_TNIL}
|
||||
@ -18,10 +19,12 @@
|
||||
#define LRO_NUMVAL(v) {.value.n = v}
|
||||
#ifdef ELUA_ENDIAN_LITTLE
|
||||
#define LRO_FUNCVAL(v) {{(int)v, add_sig(LUA_TLIGHTFUNCTION)}}
|
||||
#define LRO_LUDATA(v) {{(int)v, add_sig(LUA_TLIGHTUSERDATA)}}
|
||||
#define LRO_ROVAL(v) {{(int)v, add_sig(LUA_TROTABLE)}}
|
||||
#define LRO_NILVAL {{0, add_sig(LUA_TNIL)}}
|
||||
#else // #ifdef ELUA_ENDIAN_LITTLE
|
||||
#define LRO_FUNCVAL(v) {{add_sig(LUA_TLIGHTFUNCTION), (int)v}}
|
||||
#define LRO_LUDATA(v) {{add_sig(LUA_TLIGHTUSERDATA), (int)v}}
|
||||
#define LRO_ROVAL(v) {{add_sig(LUA_TROTABLE), (int)v}}
|
||||
#define LRO_NILVAL {{add_sig(LUA_TNIL), 0}}
|
||||
#endif // #ifdef ELUA_ENDIAN_LITTLE
|
||||
|
@ -47,6 +47,7 @@ INCLUDES += -I ../platform
|
||||
INCLUDES += -I ../wofs
|
||||
INCLUDES += -I ../spiffs
|
||||
INCLUDES += -I ../smart
|
||||
INCLUDES += -I ../cjson
|
||||
PDIR := ../$(PDIR)
|
||||
sinclude $(PDIR)Makefile
|
||||
|
||||
|
@ -79,6 +79,9 @@ LUALIB_API int ( luaopen_file )( lua_State *L );
|
||||
#define AUXLIB_OW "ow"
|
||||
LUALIB_API int ( luaopen_ow )( lua_State *L );
|
||||
|
||||
#define AUXLIB_CJSON "cjson"
|
||||
LUALIB_API int ( luaopen_ow )( lua_State *L );
|
||||
|
||||
// Helper macros
|
||||
#define MOD_CHECK_ID( mod, id )\
|
||||
if( !platform_ ## mod ## _exists( id ) )\
|
||||
@ -98,5 +101,9 @@ LUALIB_API int ( luaopen_ow )( lua_State *L );
|
||||
lua_pushnumber( L, val );\
|
||||
lua_setfield( L, -2, name )
|
||||
|
||||
#define MOD_REG_LUDATA( L, name, val )\
|
||||
lua_pushlightuserdata( L, val );\
|
||||
lua_setfield( L, -2, name )
|
||||
|
||||
#endif
|
||||
|
||||
|
1645
app/modules/cjson.c
Normal file
1645
app/modules/cjson.c
Normal file
File diff suppressed because it is too large
Load Diff
@ -338,7 +338,7 @@ LUALIB_API int luaopen_file( lua_State *L )
|
||||
#if LUA_OPTIMIZE_MEMORY > 0
|
||||
return 0;
|
||||
#else // #if LUA_OPTIMIZE_MEMORY > 0
|
||||
luaL_register( L, AUXLIB_NODE, file_map );
|
||||
luaL_register( L, AUXLIB_FILE, file_map );
|
||||
// Add constants
|
||||
|
||||
return 1;
|
||||
|
@ -141,6 +141,13 @@
|
||||
#define ROM_MODULES_WS2812
|
||||
#endif
|
||||
|
||||
#if defined(LUA_USE_MODULES_CJSON)
|
||||
#define MODULES_CJSON "cjson"
|
||||
#define ROM_MODULES_CJSON \
|
||||
_ROM(MODULES_CJSON, luaopen_cjson, cjson_map)
|
||||
#else
|
||||
#define ROM_MODULES_CJSON
|
||||
#endif
|
||||
|
||||
#define LUA_MODULES_ROM \
|
||||
ROM_MODULES_GPIO \
|
||||
@ -159,7 +166,8 @@
|
||||
ROM_MODULES_UART \
|
||||
ROM_MODULES_OW \
|
||||
ROM_MODULES_BIT \
|
||||
ROM_MODULES_WS2812
|
||||
ROM_MODULES_WS2812 \
|
||||
ROM_MODULES_CJSON
|
||||
|
||||
#endif
|
||||
|
||||
|
@ -25,6 +25,9 @@
|
||||
#include "flash_fs.h"
|
||||
#include "user_version.h"
|
||||
|
||||
#define CPU80MHZ 80
|
||||
#define CPU160MHZ 160
|
||||
|
||||
// Lua: restart()
|
||||
static int node_restart( lua_State* L )
|
||||
{
|
||||
@ -392,6 +395,24 @@ static int node_compile( lua_State* L )
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Lua: setcpufreq(mhz)
|
||||
// mhz is either CPU80MHZ od CPU160MHZ
|
||||
static int node_setcpufreq(lua_State* L)
|
||||
{
|
||||
// http://www.esp8266.com/viewtopic.php?f=21&t=1369
|
||||
uint32_t new_freq = luaL_checkinteger(L, 1);
|
||||
if (new_freq == CPU160MHZ){
|
||||
REG_SET_BIT(0x3ff00014, BIT(0));
|
||||
os_update_cpu_frequency(CPU160MHZ);
|
||||
} else {
|
||||
REG_CLR_BIT(0x3ff00014, BIT(0));
|
||||
os_update_cpu_frequency(CPU80MHZ);
|
||||
}
|
||||
new_freq = ets_get_cpu_frequency();
|
||||
lua_pushinteger(L, new_freq);
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Module function map
|
||||
#define MIN_OPT_LEVEL 2
|
||||
#include "lrodefs.h"
|
||||
@ -412,6 +433,9 @@ const LUA_REG_TYPE node_map[] =
|
||||
{ LSTRKEY( "output" ), LFUNCVAL( node_output ) },
|
||||
{ LSTRKEY( "readvdd33" ), LFUNCVAL( node_readvdd33) },
|
||||
{ LSTRKEY( "compile" ), LFUNCVAL( node_compile) },
|
||||
{ LSTRKEY( "CPU80MHZ" ), LNUMVAL( CPU80MHZ ) },
|
||||
{ LSTRKEY( "CPU160MHZ" ), LNUMVAL( CPU160MHZ ) },
|
||||
{ LSTRKEY( "setcpufreq" ), LFUNCVAL( node_setcpufreq) },
|
||||
// Combined to dsleep(us, option)
|
||||
// { LSTRKEY( "dsleepsetoption" ), LFUNCVAL( node_deepsleep_setoption) },
|
||||
#if LUA_OPTIMIZE_MEMORY > 0
|
||||
@ -429,5 +453,5 @@ LUALIB_API int luaopen_node( lua_State *L )
|
||||
// Add constants
|
||||
|
||||
return 1;
|
||||
#endif // #if LUA_OPTIMIZE_MEMORY > 0
|
||||
#endif // #if LUA_OPTIMIZE_MEMORY > 0
|
||||
}
|
||||
|
@ -1,6 +1,5 @@
|
||||
// Module for U8glib
|
||||
|
||||
//#include "lua.h"
|
||||
#include "lualib.h"
|
||||
#include "lauxlib.h"
|
||||
#include "platform.h"
|
||||
@ -8,25 +7,24 @@
|
||||
#include "lrotable.h"
|
||||
|
||||
//#include "c_string.h"
|
||||
//#include "c_stdlib.h"
|
||||
#include "c_stdlib.h"
|
||||
|
||||
#include "u8g.h"
|
||||
|
||||
typedef u8g_t lu8g_userdata_t;
|
||||
#include "u8g_config.h"
|
||||
|
||||
|
||||
// Font look-up array
|
||||
static const u8g_fntpgm_uint8_t *font_array[] =
|
||||
struct _lu8g_userdata_t
|
||||
{
|
||||
#undef U8G_FONT_TABLE_ENTRY
|
||||
#define U8G_FONT_TABLE_ENTRY(font) u8g_ ## font ,
|
||||
U8G_FONT_TABLE
|
||||
NULL
|
||||
u8g_t u8g;
|
||||
u8g_pb_t pb;
|
||||
u8g_dev_t dev;
|
||||
};
|
||||
|
||||
typedef struct _lu8g_userdata_t lu8g_userdata_t;
|
||||
|
||||
// shorthand macro for the u8g structure inside the userdata
|
||||
#define LU8G (&(lud->u8g))
|
||||
|
||||
static uint32_t *u8g_pgm_cached_iadr = NULL;
|
||||
static uint32_t u8g_pgm_cached_data;
|
||||
|
||||
// function to read 4-byte aligned from program memory AKA irom0
|
||||
u8g_pgm_uint8_t ICACHE_FLASH_ATTR u8g_pgm_read(const u8g_pgm_uint8_t *adr)
|
||||
@ -34,19 +32,9 @@ u8g_pgm_uint8_t ICACHE_FLASH_ATTR u8g_pgm_read(const u8g_pgm_uint8_t *adr)
|
||||
uint32_t iadr = (uint32_t)adr;
|
||||
// set up pointer to 4-byte aligned memory location
|
||||
uint32_t *ptr = (uint32_t *)(iadr & ~0x3);
|
||||
uint32_t pgm_data;
|
||||
|
||||
if (ptr == u8g_pgm_cached_iadr)
|
||||
{
|
||||
pgm_data = u8g_pgm_cached_data;
|
||||
}
|
||||
else
|
||||
{
|
||||
// read 4-byte aligned
|
||||
pgm_data = *ptr;
|
||||
u8g_pgm_cached_iadr = ptr;
|
||||
u8g_pgm_cached_data = pgm_data;
|
||||
}
|
||||
// read 4-byte aligned
|
||||
uint32_t pgm_data = *ptr;
|
||||
|
||||
// return the correct byte within the retrieved 32bit word
|
||||
return pgm_data >> ((iadr % 4) * 8);
|
||||
@ -79,7 +67,7 @@ static int lu8g_begin( lua_State *L )
|
||||
if ((lud = get_lud( L )) == NULL)
|
||||
return 0;
|
||||
|
||||
u8g_Begin( lud );
|
||||
u8g_Begin( LU8G );
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -92,9 +80,9 @@ static int lu8g_setFont( lua_State *L )
|
||||
if ((lud = get_lud( L )) == NULL)
|
||||
return 0;
|
||||
|
||||
lua_Integer fontnr = luaL_checkinteger( L, 2 );
|
||||
if ((fontnr >= 0) && (fontnr < (sizeof( font_array ) / sizeof( u8g_fntpgm_uint8_t ))))
|
||||
u8g_SetFont( lud, font_array[fontnr] );
|
||||
u8g_fntpgm_uint8_t *font = (u8g_fntpgm_uint8_t *)lua_touserdata( L, 2 );
|
||||
if (font != NULL)
|
||||
u8g_SetFont( LU8G, font );
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -107,7 +95,7 @@ static int lu8g_setFontRefHeightAll( lua_State *L )
|
||||
if ((lud = get_lud( L )) == NULL)
|
||||
return 0;
|
||||
|
||||
u8g_SetFontRefHeightAll( lud );
|
||||
u8g_SetFontRefHeightAll( LU8G );
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -120,7 +108,7 @@ static int lu8g_setFontRefHeightExtendedText( lua_State *L )
|
||||
if ((lud = get_lud( L )) == NULL)
|
||||
return 0;
|
||||
|
||||
u8g_SetFontRefHeightExtendedText( lud );
|
||||
u8g_SetFontRefHeightExtendedText( LU8G );
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -133,7 +121,7 @@ static int lu8g_setFontRefHeightText( lua_State *L )
|
||||
if ((lud = get_lud( L )) == NULL)
|
||||
return 0;
|
||||
|
||||
u8g_SetFontRefHeightText( lud );
|
||||
u8g_SetFontRefHeightText( LU8G );
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -146,7 +134,7 @@ static int lu8g_setDefaultBackgroundColor( lua_State *L )
|
||||
if ((lud = get_lud( L )) == NULL)
|
||||
return 0;
|
||||
|
||||
u8g_SetDefaultBackgroundColor( lud );
|
||||
u8g_SetDefaultBackgroundColor( LU8G );
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -159,7 +147,7 @@ static int lu8g_setDefaultForegroundColor( lua_State *L )
|
||||
if ((lud = get_lud( L )) == NULL)
|
||||
return 0;
|
||||
|
||||
u8g_SetDefaultForegroundColor( lud );
|
||||
u8g_SetDefaultForegroundColor( LU8G );
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -172,7 +160,7 @@ static int lu8g_setFontPosBaseline( lua_State *L )
|
||||
if ((lud = get_lud( L )) == NULL)
|
||||
return 0;
|
||||
|
||||
u8g_SetFontPosBaseline( lud );
|
||||
u8g_SetFontPosBaseline( LU8G );
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -185,7 +173,7 @@ static int lu8g_setFontPosBottom( lua_State *L )
|
||||
if ((lud = get_lud( L )) == NULL)
|
||||
return 0;
|
||||
|
||||
u8g_SetFontPosBottom( lud );
|
||||
u8g_SetFontPosBottom( LU8G );
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -198,7 +186,7 @@ static int lu8g_setFontPosCenter( lua_State *L )
|
||||
if ((lud = get_lud( L )) == NULL)
|
||||
return 0;
|
||||
|
||||
u8g_SetFontPosCenter( lud );
|
||||
u8g_SetFontPosCenter( LU8G );
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -211,7 +199,7 @@ static int lu8g_setFontPosTop( lua_State *L )
|
||||
if ((lud = get_lud( L )) == NULL)
|
||||
return 0;
|
||||
|
||||
u8g_SetFontPosTop( lud );
|
||||
u8g_SetFontPosTop( LU8G );
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -224,7 +212,7 @@ static int lu8g_getFontAscent( lua_State *L )
|
||||
if ((lud = get_lud( L )) == NULL)
|
||||
return 0;
|
||||
|
||||
lua_pushinteger( L, u8g_GetFontAscent( lud ) );
|
||||
lua_pushinteger( L, u8g_GetFontAscent( LU8G ) );
|
||||
|
||||
return 1;
|
||||
}
|
||||
@ -237,7 +225,7 @@ static int lu8g_getFontDescent( lua_State *L )
|
||||
if ((lud = get_lud( L )) == NULL)
|
||||
return 0;
|
||||
|
||||
lua_pushinteger( L, u8g_GetFontDescent( lud ) );
|
||||
lua_pushinteger( L, u8g_GetFontDescent( LU8G ) );
|
||||
|
||||
return 1;
|
||||
}
|
||||
@ -250,7 +238,7 @@ static int lu8g_getFontLineSpacing( lua_State *L )
|
||||
if ((lud = get_lud( L )) == NULL)
|
||||
return 0;
|
||||
|
||||
lua_pushinteger( L, u8g_GetFontLineSpacing( lud ) );
|
||||
lua_pushinteger( L, u8g_GetFontLineSpacing( LU8G ) );
|
||||
|
||||
return 1;
|
||||
}
|
||||
@ -263,7 +251,7 @@ static int lu8g_getMode( lua_State *L )
|
||||
if ((lud = get_lud( L )) == NULL)
|
||||
return 0;
|
||||
|
||||
lua_pushinteger( L, u8g_GetMode( lud ) );
|
||||
lua_pushinteger( L, u8g_GetMode( LU8G ) );
|
||||
|
||||
return 1;
|
||||
}
|
||||
@ -276,7 +264,7 @@ static int lu8g_setColorIndex( lua_State *L )
|
||||
if ((lud = get_lud( L )) == NULL)
|
||||
return 0;
|
||||
|
||||
u8g_SetColorIndex( lud, luaL_checkinteger( L, 2 ) );
|
||||
u8g_SetColorIndex( LU8G, luaL_checkinteger( L, 2 ) );
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -289,7 +277,7 @@ static int lu8g_getColorIndex( lua_State *L )
|
||||
if ((lud = get_lud( L )) == NULL)
|
||||
return 0;
|
||||
|
||||
lua_pushinteger( L, u8g_GetColorIndex( lud ) );
|
||||
lua_pushinteger( L, u8g_GetColorIndex( LU8G ) );
|
||||
|
||||
return 1;
|
||||
}
|
||||
@ -311,16 +299,16 @@ static int lu8g_generic_drawStr( lua_State *L, uint8_t rot )
|
||||
switch (rot)
|
||||
{
|
||||
case 1:
|
||||
lua_pushinteger( L, u8g_DrawStr90( lud, args[0], args[1], s ) );
|
||||
lua_pushinteger( L, u8g_DrawStr90( LU8G, args[0], args[1], s ) );
|
||||
break;
|
||||
case 2:
|
||||
lua_pushinteger( L, u8g_DrawStr180( lud, args[0], args[1], s ) );
|
||||
lua_pushinteger( L, u8g_DrawStr180( LU8G, args[0], args[1], s ) );
|
||||
break;
|
||||
case 3:
|
||||
lua_pushinteger( L, u8g_DrawStr270( lud, args[0], args[1], s ) );
|
||||
lua_pushinteger( L, u8g_DrawStr270( LU8G, args[0], args[1], s ) );
|
||||
break;
|
||||
default:
|
||||
lua_pushinteger( L, u8g_DrawStr( lud, args[0], args[1], s ) );
|
||||
lua_pushinteger( L, u8g_DrawStr( LU8G, args[0], args[1], s ) );
|
||||
break;
|
||||
}
|
||||
|
||||
@ -371,7 +359,7 @@ static int lu8g_drawLine( lua_State *L )
|
||||
u8g_uint_t args[4];
|
||||
lu8g_get_int_args( L, 2, 4, args );
|
||||
|
||||
u8g_DrawLine( lud, args[0], args[1], args[2], args[3] );
|
||||
u8g_DrawLine( LU8G, args[0], args[1], args[2], args[3] );
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -387,7 +375,7 @@ static int lu8g_drawTriangle( lua_State *L )
|
||||
u8g_uint_t args[6];
|
||||
lu8g_get_int_args( L, 2, 6, args );
|
||||
|
||||
u8g_DrawTriangle( lud, args[0], args[1], args[2], args[3], args[4], args[5] );
|
||||
u8g_DrawTriangle( LU8G, args[0], args[1], args[2], args[3], args[4], args[5] );
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -403,7 +391,7 @@ static int lu8g_drawBox( lua_State *L )
|
||||
u8g_uint_t args[4];
|
||||
lu8g_get_int_args( L, 2, 4, args );
|
||||
|
||||
u8g_DrawBox( lud, args[0], args[1], args[2], args[3] );
|
||||
u8g_DrawBox( LU8G, args[0], args[1], args[2], args[3] );
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -419,7 +407,7 @@ static int lu8g_drawRBox( lua_State *L )
|
||||
u8g_uint_t args[5];
|
||||
lu8g_get_int_args( L, 2, 5, args );
|
||||
|
||||
u8g_DrawRBox( lud, args[0], args[1], args[2], args[3], args[4] );
|
||||
u8g_DrawRBox( LU8G, args[0], args[1], args[2], args[3], args[4] );
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -435,7 +423,7 @@ static int lu8g_drawFrame( lua_State *L )
|
||||
u8g_uint_t args[4];
|
||||
lu8g_get_int_args( L, 2, 4, args );
|
||||
|
||||
u8g_DrawFrame( lud, args[0], args[1], args[2], args[3] );
|
||||
u8g_DrawFrame( LU8G, args[0], args[1], args[2], args[3] );
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -451,7 +439,7 @@ static int lu8g_drawRFrame( lua_State *L )
|
||||
u8g_uint_t args[5];
|
||||
lu8g_get_int_args( L, 2, 5, args );
|
||||
|
||||
u8g_DrawRFrame( lud, args[0], args[1], args[2], args[3], args[4] );
|
||||
u8g_DrawRFrame( LU8G, args[0], args[1], args[2], args[3], args[4] );
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -469,7 +457,7 @@ static int lu8g_drawDisc( lua_State *L )
|
||||
|
||||
u8g_uint_t opt = luaL_optinteger( L, (1+3) + 1, U8G_DRAW_ALL );
|
||||
|
||||
u8g_DrawDisc( lud, args[0], args[1], args[2], opt );
|
||||
u8g_DrawDisc( LU8G, args[0], args[1], args[2], opt );
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -487,7 +475,7 @@ static int lu8g_drawCircle( lua_State *L )
|
||||
|
||||
u8g_uint_t opt = luaL_optinteger( L, (1+3) + 1, U8G_DRAW_ALL );
|
||||
|
||||
u8g_DrawCircle( lud, args[0], args[1], args[2], opt );
|
||||
u8g_DrawCircle( LU8G, args[0], args[1], args[2], opt );
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -505,7 +493,7 @@ static int lu8g_drawEllipse( lua_State *L )
|
||||
|
||||
u8g_uint_t opt = luaL_optinteger( L, (1+4) + 1, U8G_DRAW_ALL );
|
||||
|
||||
u8g_DrawEllipse( lud, args[0], args[1], args[2], args[3], opt );
|
||||
u8g_DrawEllipse( LU8G, args[0], args[1], args[2], args[3], opt );
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -523,7 +511,7 @@ static int lu8g_drawFilledEllipse( lua_State *L )
|
||||
|
||||
u8g_uint_t opt = luaL_optinteger( L, (1+4) + 1, U8G_DRAW_ALL );
|
||||
|
||||
u8g_DrawFilledEllipse( lud, args[0], args[1], args[2], args[3], opt );
|
||||
u8g_DrawFilledEllipse( LU8G, args[0], args[1], args[2], args[3], opt );
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -539,7 +527,7 @@ static int lu8g_drawPixel( lua_State *L )
|
||||
u8g_uint_t args[2];
|
||||
lu8g_get_int_args( L, 2, 2, args );
|
||||
|
||||
u8g_DrawPixel( lud, args[0], args[1] );
|
||||
u8g_DrawPixel( LU8G, args[0], args[1] );
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -555,7 +543,7 @@ static int lu8g_drawHLine( lua_State *L )
|
||||
u8g_uint_t args[3];
|
||||
lu8g_get_int_args( L, 2, 3, args );
|
||||
|
||||
u8g_DrawHLine( lud, args[0], args[1], args[2] );
|
||||
u8g_DrawHLine( LU8G, args[0], args[1], args[2] );
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -571,7 +559,47 @@ static int lu8g_drawVLine( lua_State *L )
|
||||
u8g_uint_t args[3];
|
||||
lu8g_get_int_args( L, 2, 3, args );
|
||||
|
||||
u8g_DrawVLine( lud, args[0], args[1], args[2] );
|
||||
u8g_DrawVLine( LU8G, args[0], args[1], args[2] );
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Lua: u8g.drawXBM( self, x, y, width, height, data )
|
||||
static int lu8g_drawXBM( lua_State *L )
|
||||
{
|
||||
lu8g_userdata_t *lud;
|
||||
|
||||
if ((lud = get_lud( L )) == NULL)
|
||||
return 0;
|
||||
|
||||
u8g_uint_t args[4];
|
||||
lu8g_get_int_args( L, 2, 4, args );
|
||||
|
||||
const char *xbm_data = luaL_checkstring( L, (1+4) + 1 );
|
||||
if (xbm_data == NULL)
|
||||
return 0;
|
||||
|
||||
u8g_DrawXBM( LU8G, args[0], args[1], args[2], args[3], (const uint8_t *)xbm_data );
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Lua: u8g.drawBitmap( self, x, y, count, height, data )
|
||||
static int lu8g_drawBitmap( lua_State *L )
|
||||
{
|
||||
lu8g_userdata_t *lud;
|
||||
|
||||
if ((lud = get_lud( L )) == NULL)
|
||||
return 0;
|
||||
|
||||
u8g_uint_t args[4];
|
||||
lu8g_get_int_args( L, 2, 4, args );
|
||||
|
||||
const char *bm_data = luaL_checkstring( L, (1+4) + 1 );
|
||||
if (bm_data == NULL)
|
||||
return 0;
|
||||
|
||||
u8g_DrawBitmap( LU8G, args[0], args[1], args[2], args[3], (const uint8_t *)bm_data );
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -584,7 +612,7 @@ static int lu8g_setScale2x2( lua_State *L )
|
||||
if ((lud = get_lud( L )) == NULL)
|
||||
return 0;
|
||||
|
||||
u8g_SetScale2x2( lud );
|
||||
u8g_SetScale2x2( LU8G );
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -597,7 +625,7 @@ static int lu8g_undoScale( lua_State *L )
|
||||
if ((lud = get_lud( L )) == NULL)
|
||||
return 0;
|
||||
|
||||
u8g_UndoScale( lud );
|
||||
u8g_UndoScale( LU8G );
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -610,7 +638,7 @@ static int lu8g_firstPage( lua_State *L )
|
||||
if ((lud = get_lud( L )) == NULL)
|
||||
return 0;
|
||||
|
||||
u8g_FirstPage( lud );
|
||||
u8g_FirstPage( LU8G );
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -623,7 +651,7 @@ static int lu8g_nextPage( lua_State *L )
|
||||
if ((lud = get_lud( L )) == NULL)
|
||||
return 0;
|
||||
|
||||
lua_pushboolean( L, u8g_NextPage( lud ) );
|
||||
lua_pushboolean( L, u8g_NextPage( LU8G ) );
|
||||
|
||||
return 1;
|
||||
}
|
||||
@ -636,7 +664,7 @@ static int lu8g_sleepOn( lua_State *L )
|
||||
if ((lud = get_lud( L )) == NULL)
|
||||
return 0;
|
||||
|
||||
u8g_SleepOn( lud );
|
||||
u8g_SleepOn( LU8G );
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -649,7 +677,7 @@ static int lu8g_sleepOff( lua_State *L )
|
||||
if ((lud = get_lud( L )) == NULL)
|
||||
return 0;
|
||||
|
||||
u8g_SleepOff( lud );
|
||||
u8g_SleepOff( LU8G );
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -662,7 +690,7 @@ static int lu8g_setRot90( lua_State *L )
|
||||
if ((lud = get_lud( L )) == NULL)
|
||||
return 0;
|
||||
|
||||
u8g_SetRot90( lud );
|
||||
u8g_SetRot90( LU8G );
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -675,7 +703,7 @@ static int lu8g_setRot180( lua_State *L )
|
||||
if ((lud = get_lud( L )) == NULL)
|
||||
return 0;
|
||||
|
||||
u8g_SetRot180( lud );
|
||||
u8g_SetRot180( LU8G );
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -688,7 +716,7 @@ static int lu8g_setRot270( lua_State *L )
|
||||
if ((lud = get_lud( L )) == NULL)
|
||||
return 0;
|
||||
|
||||
u8g_SetRot270( lud );
|
||||
u8g_SetRot270( LU8G );
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -701,7 +729,7 @@ static int lu8g_undoRotation( lua_State *L )
|
||||
if ((lud = get_lud( L )) == NULL)
|
||||
return 0;
|
||||
|
||||
u8g_UndoRotation( lud );
|
||||
u8g_UndoRotation( LU8G );
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -714,7 +742,7 @@ static int lu8g_getWidth( lua_State *L )
|
||||
if ((lud = get_lud( L )) == NULL)
|
||||
return 0;
|
||||
|
||||
lua_pushinteger( L, u8g_GetWidth( lud ) );
|
||||
lua_pushinteger( L, u8g_GetWidth( LU8G ) );
|
||||
|
||||
return 1;
|
||||
}
|
||||
@ -727,7 +755,7 @@ static int lu8g_getHeight( lua_State *L )
|
||||
if ((lud = get_lud( L )) == NULL)
|
||||
return 0;
|
||||
|
||||
lua_pushinteger( L, u8g_GetHeight( lud ) );
|
||||
lua_pushinteger( L, u8g_GetHeight( LU8G ) );
|
||||
|
||||
return 1;
|
||||
}
|
||||
@ -776,6 +804,83 @@ static uint8_t u8g_com_esp8266_ssd_start_sequence(u8g_t *u8g)
|
||||
}
|
||||
|
||||
|
||||
static void lu8g_digital_write( u8g_t *u8g, uint8_t pin_index, uint8_t value )
|
||||
{
|
||||
uint8_t pin;
|
||||
|
||||
pin = u8g->pin_list[pin_index];
|
||||
if ( pin != U8G_PIN_NONE )
|
||||
platform_gpio_write( pin, value );
|
||||
}
|
||||
|
||||
uint8_t u8g_com_esp8266_hw_spi_fn(u8g_t *u8g, uint8_t msg, uint8_t arg_val, void *arg_ptr)
|
||||
{
|
||||
switch(msg)
|
||||
{
|
||||
case U8G_COM_MSG_STOP:
|
||||
break;
|
||||
|
||||
case U8G_COM_MSG_INIT:
|
||||
// we assume that the SPI interface was already initialized
|
||||
// just care for the /CS and D/C pins
|
||||
lu8g_digital_write( u8g, U8G_PI_CS, PLATFORM_GPIO_HIGH );
|
||||
platform_gpio_mode( u8g->pin_list[U8G_PI_CS], PLATFORM_GPIO_OUTPUT, PLATFORM_GPIO_FLOAT );
|
||||
platform_gpio_mode( u8g->pin_list[U8G_PI_A0], PLATFORM_GPIO_OUTPUT, PLATFORM_GPIO_FLOAT );
|
||||
break;
|
||||
|
||||
case U8G_COM_MSG_ADDRESS: /* define cmd (arg_val = 0) or data mode (arg_val = 1) */
|
||||
lu8g_digital_write( u8g, U8G_PI_A0, arg_val == 0 ? PLATFORM_GPIO_LOW : PLATFORM_GPIO_HIGH );
|
||||
break;
|
||||
|
||||
case U8G_COM_MSG_CHIP_SELECT:
|
||||
if (arg_val == 0)
|
||||
{
|
||||
/* disable */
|
||||
lu8g_digital_write( u8g, U8G_PI_CS, PLATFORM_GPIO_HIGH );
|
||||
}
|
||||
else
|
||||
{
|
||||
/* enable */
|
||||
//u8g_com_arduino_digital_write(u8g, U8G_PI_SCK, LOW);
|
||||
lu8g_digital_write( u8g, U8G_PI_CS, PLATFORM_GPIO_LOW );
|
||||
}
|
||||
break;
|
||||
|
||||
case U8G_COM_MSG_RESET:
|
||||
if ( u8g->pin_list[U8G_PI_RESET] != U8G_PIN_NONE )
|
||||
lu8g_digital_write( u8g, U8G_PI_RESET, arg_val == 0 ? PLATFORM_GPIO_LOW : PLATFORM_GPIO_HIGH );
|
||||
break;
|
||||
|
||||
case U8G_COM_MSG_WRITE_BYTE:
|
||||
platform_spi_send_recv( 1, arg_val );
|
||||
break;
|
||||
|
||||
case U8G_COM_MSG_WRITE_SEQ:
|
||||
{
|
||||
register uint8_t *ptr = arg_ptr;
|
||||
while( arg_val > 0 )
|
||||
{
|
||||
platform_spi_send_recv( 1, *ptr++ );
|
||||
arg_val--;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case U8G_COM_MSG_WRITE_SEQ_P:
|
||||
{
|
||||
register uint8_t *ptr = arg_ptr;
|
||||
while( arg_val > 0 )
|
||||
{
|
||||
platform_spi_send_recv( 1, u8g_pgm_read(ptr) );
|
||||
ptr++;
|
||||
arg_val--;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
uint8_t u8g_com_esp8266_ssd_i2c_fn(u8g_t *u8g, uint8_t msg, uint8_t arg_val, void *arg_ptr)
|
||||
{
|
||||
switch(msg)
|
||||
@ -811,7 +916,7 @@ uint8_t u8g_com_esp8266_ssd_i2c_fn(u8g_t *u8g, uint8_t msg, uint8_t arg_val, voi
|
||||
case U8G_COM_MSG_WRITE_BYTE:
|
||||
//u8g->pin_list[U8G_PI_SET_A0] = 1;
|
||||
if ( u8g_com_esp8266_ssd_start_sequence(u8g) == 0 )
|
||||
return platform_i2c_stop( ESP_I2C_ID ), 0;
|
||||
return platform_i2c_send_stop( ESP_I2C_ID ), 0;
|
||||
// ignore return value -> tolerate missing ACK
|
||||
if ( platform_i2c_send_byte( ESP_I2C_ID, arg_val) == 0 )
|
||||
; //return platform_i2c_send_stop( ESP_I2C_ID ), 0;
|
||||
@ -865,10 +970,29 @@ uint8_t u8g_com_esp8266_ssd_i2c_fn(u8g_t *u8g, uint8_t msg, uint8_t arg_val, voi
|
||||
|
||||
|
||||
|
||||
// device destructor
|
||||
static int lu8g_close_display( lua_State *L )
|
||||
{
|
||||
lu8g_userdata_t *lud;
|
||||
|
||||
if ((lud = get_lud( L )) == NULL)
|
||||
return 0;
|
||||
|
||||
// free up allocated page buffer
|
||||
if (lud->pb.buf != NULL)
|
||||
{
|
||||
c_free( lud->pb.buf );
|
||||
lud->pb.buf = NULL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
// device constructors
|
||||
|
||||
// Lua: speed = u8g.ssd1306_128x64_i2c( i2c_addr )
|
||||
uint8_t u8g_dev_ssd1306_128x64_fn(u8g_t *u8g, u8g_dev_t *dev, uint8_t msg, void *arg);
|
||||
// Lua: object = u8g.ssd1306_128x64_i2c( i2c_addr )
|
||||
static int lu8g_ssd1306_128x64_i2c( lua_State *L )
|
||||
{
|
||||
unsigned addr = luaL_checkinteger( L, 1 );
|
||||
@ -878,9 +1002,127 @@ static int lu8g_ssd1306_128x64_i2c( lua_State *L )
|
||||
|
||||
lu8g_userdata_t *lud = (lu8g_userdata_t *) lua_newuserdata( L, sizeof( lu8g_userdata_t ) );
|
||||
|
||||
lud->i2c_addr = (uint8_t)addr;
|
||||
lud->u8g.i2c_addr = (uint8_t)addr;
|
||||
|
||||
u8g_InitI2C( lud, &u8g_dev_ssd1306_128x64_i2c, U8G_I2C_OPT_NONE);
|
||||
// Don't use the pre-defined device structure for u8g_dev_ssd1306_128x64_i2c here
|
||||
// Reason: linking the pre-defined structures allocates RAM for the device/comm structure
|
||||
// *before* the display is constructed (especially the page buffers)
|
||||
// this consumes heap even when the device is not used at all
|
||||
#if 1
|
||||
// build device entry
|
||||
lud->dev = (u8g_dev_t){ u8g_dev_ssd1306_128x64_fn, &(lud->pb), U8G_COM_SSD_I2C };
|
||||
|
||||
// populate and allocate page buffer
|
||||
// constants taken from u8g_dev_ssd1306_128x64.c:
|
||||
// PAGE_HEIGHT
|
||||
// | Height
|
||||
// | | WIDTH
|
||||
// | | |
|
||||
lud->pb = (u8g_pb_t){ { 8, 64, 0, 0, 0 }, 128, NULL };
|
||||
//
|
||||
if ((lud->pb.buf = (void *)c_zalloc(lud->pb.width)) == NULL)
|
||||
return luaL_error( L, "out of memory" );
|
||||
|
||||
// and finally init device using specific interface init function
|
||||
u8g_InitI2C( LU8G, &(lud->dev), U8G_I2C_OPT_NONE);
|
||||
#else
|
||||
u8g_InitI2C( LU8G, &u8g_dev_ssd1306_128x64_i2c, U8G_I2C_OPT_NONE);
|
||||
#endif
|
||||
|
||||
|
||||
// set its metatable
|
||||
luaL_getmetatable(L, "u8g.display");
|
||||
lua_setmetatable(L, -2);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Lua: object = u8g.ssd1306_128x64_spi( cs, dc, [res] )
|
||||
static int lu8g_ssd1306_128x64_spi( lua_State *L )
|
||||
{
|
||||
unsigned cs = luaL_checkinteger( L, 1 );
|
||||
if (cs == 0)
|
||||
return luaL_error( L, "CS pin required" );
|
||||
unsigned dc = luaL_checkinteger( L, 2 );
|
||||
if (dc == 0)
|
||||
return luaL_error( L, "D/C pin required" );
|
||||
unsigned res = luaL_optinteger( L, 3, U8G_PIN_NONE );
|
||||
|
||||
lu8g_userdata_t *lud = (lu8g_userdata_t *) lua_newuserdata( L, sizeof( lu8g_userdata_t ) );
|
||||
|
||||
// Don't use the pre-defined device structure for u8g_dev_ssd1306_128x64_spi here
|
||||
// Reason: linking the pre-defined structures allocates RAM for the device/comm structure
|
||||
// *before* the display is constructed (especially the page buffers)
|
||||
// this consumes heap even when the device is not used at all
|
||||
#if 1
|
||||
// build device entry
|
||||
lud->dev = (u8g_dev_t){ u8g_dev_ssd1306_128x64_fn, &(lud->pb), U8G_COM_HW_SPI };
|
||||
|
||||
// populate and allocate page buffer
|
||||
// constants taken from u8g_dev_ssd1306_128x64.c:
|
||||
// PAGE_HEIGHT
|
||||
// | Height
|
||||
// | | WIDTH
|
||||
// | | |
|
||||
lud->pb = (u8g_pb_t){ { 8, 64, 0, 0, 0 }, 128, NULL };
|
||||
//
|
||||
if ((lud->pb.buf = (void *)c_zalloc(lud->pb.width)) == NULL)
|
||||
return luaL_error( L, "out of memory" );
|
||||
|
||||
// and finally init device using specific interface init function
|
||||
u8g_InitHWSPI( LU8G, &(lud->dev), cs, dc, res );
|
||||
#else
|
||||
u8g_InitHWSPI( LU8G, &u8g_dev_ssd1306_128x64_spi, cs, dc, res );
|
||||
#endif
|
||||
|
||||
|
||||
// set its metatable
|
||||
luaL_getmetatable(L, "u8g.display");
|
||||
lua_setmetatable(L, -2);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
uint8_t u8g_dev_pcd8544_fn(u8g_t *u8g, u8g_dev_t *dev, uint8_t msg, void *arg);
|
||||
// Lua: object = u8g.pcd8544_84x48( sce, dc, res )
|
||||
static int lu8g_pcd8544_84x48( lua_State *L )
|
||||
{
|
||||
unsigned sce = luaL_checkinteger( L, 1 );
|
||||
if (sce == 0)
|
||||
return luaL_error( L, "SCE pin required" );
|
||||
unsigned dc = luaL_checkinteger( L, 2 );
|
||||
if (dc == 0)
|
||||
return luaL_error( L, "D/C pin required" );
|
||||
unsigned res = luaL_checkinteger( L, 3 );
|
||||
if (res == 0)
|
||||
return luaL_error( L, "RES pin required" );
|
||||
|
||||
lu8g_userdata_t *lud = (lu8g_userdata_t *) lua_newuserdata( L, sizeof( lu8g_userdata_t ) );
|
||||
|
||||
// Don't use the pre-defined device structure for u8g_dev_pcd8544_84x48_hw_spi here
|
||||
// Reason: linking the pre-defined structures allocates RAM for the device/comm structure
|
||||
// *before* the display is constructed (especially the page buffers)
|
||||
// this consumes heap even when the device is not used at all
|
||||
#if 1
|
||||
// build device entry
|
||||
lud->dev = (u8g_dev_t){ u8g_dev_pcd8544_fn, &(lud->pb), U8G_COM_HW_SPI };
|
||||
|
||||
// populate and allocate page buffer
|
||||
// constants taken from u8g_dev_pcd8544_84x48.c:
|
||||
// PAGE_HEIGHT
|
||||
// | Height
|
||||
// | | WIDTH
|
||||
// | | |
|
||||
lud->pb = (u8g_pb_t){ { 8, 48, 0, 0, 0 }, 84, NULL };
|
||||
//
|
||||
if ((lud->pb.buf = (void *)c_zalloc(lud->pb.width)) == NULL)
|
||||
return luaL_error( L, "out of memory" );
|
||||
|
||||
// and finally init device using specific interface init function
|
||||
u8g_InitHWSPI( LU8G, &(lud->dev), sce, dc, res );
|
||||
#else
|
||||
u8g_InitHWSPI( LU8G, &u8g_dev_pcd8544_84x48_hw_spi, sce, dc, res );
|
||||
#endif
|
||||
|
||||
|
||||
// set its metatable
|
||||
@ -931,6 +1173,8 @@ static const LUA_REG_TYPE lu8g_display_map[] =
|
||||
{ LSTRKEY( "drawPixel" ), LFUNCVAL( lu8g_drawPixel ) },
|
||||
{ LSTRKEY( "drawHLine" ), LFUNCVAL( lu8g_drawHLine ) },
|
||||
{ LSTRKEY( "drawVLine" ), LFUNCVAL( lu8g_drawVLine ) },
|
||||
{ LSTRKEY( "drawBitmap" ), LFUNCVAL( lu8g_drawBitmap ) },
|
||||
{ LSTRKEY( "drawXBM" ), LFUNCVAL( lu8g_drawXBM ) },
|
||||
{ LSTRKEY( "setScale2x2" ), LFUNCVAL( lu8g_setScale2x2 ) },
|
||||
{ LSTRKEY( "undoScale" ), LFUNCVAL( lu8g_undoScale ) },
|
||||
{ LSTRKEY( "firstPage" ), LFUNCVAL( lu8g_firstPage ) },
|
||||
@ -943,6 +1187,7 @@ static const LUA_REG_TYPE lu8g_display_map[] =
|
||||
{ LSTRKEY( "undoRotation" ), LFUNCVAL( lu8g_undoRotation ) },
|
||||
{ LSTRKEY( "getWidth" ), LFUNCVAL( lu8g_getWidth ) },
|
||||
{ LSTRKEY( "getHeight" ), LFUNCVAL( lu8g_getHeight ) },
|
||||
{ LSTRKEY( "__gc" ), LFUNCVAL( lu8g_close_display ) },
|
||||
#if LUA_OPTIMIZE_MEMORY > 0
|
||||
{ LSTRKEY( "__index" ), LROVAL ( lu8g_display_map ) },
|
||||
#endif
|
||||
@ -951,12 +1196,21 @@ static const LUA_REG_TYPE lu8g_display_map[] =
|
||||
|
||||
const LUA_REG_TYPE lu8g_map[] =
|
||||
{
|
||||
#ifdef U8G_SSD1306_128x64_I2C
|
||||
{ LSTRKEY( "ssd1306_128x64_i2c" ), LFUNCVAL ( lu8g_ssd1306_128x64_i2c ) },
|
||||
#endif
|
||||
#ifdef U8G_SSD1306_128x64_I2C
|
||||
{ LSTRKEY( "ssd1306_128x64_spi" ), LFUNCVAL ( lu8g_ssd1306_128x64_spi ) },
|
||||
#endif
|
||||
#ifdef U8G_PCD8544_84x48
|
||||
{ LSTRKEY( "pcd8544_84x48" ), LFUNCVAL ( lu8g_pcd8544_84x48 ) },
|
||||
#endif
|
||||
|
||||
#if LUA_OPTIMIZE_MEMORY > 0
|
||||
|
||||
// Register fonts
|
||||
#undef U8G_FONT_TABLE_ENTRY
|
||||
#define U8G_FONT_TABLE_ENTRY(font) { LSTRKEY( #font ), LNUMVAL( __COUNTER__ ) },
|
||||
#define U8G_FONT_TABLE_ENTRY(font) { LSTRKEY( #font ), LUDATA( (void *)(u8g_ ## font) ) },
|
||||
U8G_FONT_TABLE
|
||||
|
||||
// Options for circle/ ellipse drwing
|
||||
@ -992,7 +1246,7 @@ LUALIB_API int luaopen_u8g( lua_State *L )
|
||||
|
||||
// Register fonts
|
||||
#undef U8G_FONT_TABLE_ENTRY
|
||||
#define U8G_FONT_TABLE_ENTRY(font) MOD_REG_NUMBER( L, #font, __COUNTER__ );
|
||||
#define U8G_FONT_TABLE_ENTRY(font) MOD_REG_LUDATA( L, #font, (void *)(u8g_ ## font) );
|
||||
U8G_FONT_TABLE
|
||||
|
||||
// Options for circle/ ellipse drawing
|
||||
|
@ -127,11 +127,19 @@ int smart_check(uint8_t *nibble, uint16_t len, uint8_t *dst, uint8_t *got){
|
||||
return res;
|
||||
}
|
||||
|
||||
void detect(uint8 *buf, uint16 len){
|
||||
void detect(uint8 *arg, uint16 len){
|
||||
uint16_t seq;
|
||||
int16_t seq_delta = 0;
|
||||
uint16_t byte_num = 0, bit_num = 0;
|
||||
int16_t c = 0;
|
||||
uint8 *buf = NULL;
|
||||
if( len == 12 ){
|
||||
return;
|
||||
} else if (len >= 64){
|
||||
buf = arg + sizeof(struct RxControl);
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
if( ( (buf[0]) & TYPE_SUBTYPE_MASK) != TYPE_SUBTYPE_QOS_DATA){
|
||||
return;
|
||||
}
|
||||
|
@ -59,6 +59,40 @@ extern "C" {
|
||||
|
||||
#define STATION_CHECK_TIME (2*1000)
|
||||
|
||||
struct RxControl{
|
||||
signed rssi:8;//表示该包的信号强度
|
||||
unsigned rate:4;
|
||||
unsigned is_group:1;
|
||||
unsigned:1;
|
||||
unsigned sig_mode:2;//表示该包是否是11n 的包,0 表示非11n,非0 表示11n
|
||||
unsigned legacy_length:12;//如果不是11n 的包,它表示包的长度
|
||||
unsigned damatch0:1;
|
||||
unsigned damatch1:1;
|
||||
unsigned bssidmatch0:1;
|
||||
unsigned bssidmatch1:1;
|
||||
unsigned MCS:7;//如果是11n 的包,它表示包的调制编码序列,有效值:0-76
|
||||
unsigned CWB:1;//如果是11n 的包,它表示是否为HT40 的包
|
||||
unsigned HT_length:16;//如果是11n 的包,它表示包的长度
|
||||
unsigned Smoothing:1;
|
||||
unsigned Not_Sounding:1;
|
||||
unsigned:1;
|
||||
unsigned Aggregation:1;
|
||||
unsigned STBC:2;
|
||||
unsigned FEC_CODING:1;//如果是11n 的包,它表示是否为LDPC 的包
|
||||
unsigned SGI:1;
|
||||
unsigned rxend_state:8;
|
||||
unsigned ampdu_cnt:8;
|
||||
unsigned channel:4;//表示该包所在的信道
|
||||
unsigned:12;
|
||||
};
|
||||
|
||||
struct sniffer_buf{
|
||||
struct RxControl rx_ctrl; // 12-bytes
|
||||
u8 buf[48];//包含ieee80211 包头
|
||||
u16 cnt;//包的个数
|
||||
u16 len[1];//包的长度
|
||||
};
|
||||
|
||||
struct _my_addr_map {
|
||||
uint8 addr[ADDR_LENGTH*3];
|
||||
uint8_t addr_len;
|
||||
|
@ -395,13 +395,11 @@ typedef struct __attribute(( packed )) {
|
||||
// common page header
|
||||
spiffs_page_header p_hdr;
|
||||
// alignment
|
||||
u8_t _align[4 - (sizeof(spiffs_page_header)&3)==0 ? 4 : (sizeof(spiffs_page_header)&3)];
|
||||
u8_t _align[4 - ((sizeof(spiffs_page_header)+sizeof(spiffs_obj_type)+SPIFFS_OBJ_NAME_LEN)&3)==0 ? 4 : ((sizeof(spiffs_page_header)+sizeof(spiffs_obj_type)+SPIFFS_OBJ_NAME_LEN)&3)];
|
||||
// size of object
|
||||
u32_t size;
|
||||
// type of object
|
||||
spiffs_obj_type type;
|
||||
// alignment2
|
||||
u8_t _align2[4 - (sizeof(spiffs_obj_type)&3)==0 ? 4 : (sizeof(spiffs_obj_type)&3)];
|
||||
// name of object
|
||||
u8_t name[SPIFFS_OBJ_NAME_LEN];
|
||||
} spiffs_page_object_ix_header;
|
||||
|
@ -654,6 +654,7 @@ uint8_t u8g_com_arduino_port_d_wr_fn(u8g_t *u8g, uint8_t msg, uint8_t arg_val, v
|
||||
uint8_t u8g_com_arduino_no_en_parallel_fn(u8g_t *u8g, uint8_t msg, uint8_t arg_val, void *arg_ptr); /* u8g_com_arduino_no_en_parallel.c */
|
||||
uint8_t u8g_com_arduino_ssd_i2c_fn(u8g_t *u8g, uint8_t msg, uint8_t arg_val, void *arg_ptr); /* u8g_com_arduino_ssd_i2c.c */
|
||||
uint8_t u8g_com_esp8266_ssd_i2c_fn(u8g_t *u8g, uint8_t msg, uint8_t arg_val, void *arg_ptr); /* u8g.c */
|
||||
uint8_t u8g_com_esp8266_hw_spi_fn(u8g_t *u8g, uint8_t msg, uint8_t arg_val, void *arg_ptr); /* u8g.c */
|
||||
uint8_t u8g_com_arduino_uc_i2c_fn(u8g_t *u8g, uint8_t msg, uint8_t arg_val, void *arg_ptr);
|
||||
uint8_t u8g_com_arduino_t6963_fn(u8g_t *u8g, uint8_t msg, uint8_t arg_val, void *arg_ptr); /* u8g_com_arduino_t6963.c */
|
||||
|
||||
@ -723,6 +724,10 @@ defined(__18CXX) || defined(__PIC32MX)
|
||||
#define U8G_COM_HW_SPI u8g_com_atmega_hw_spi_fn
|
||||
#define U8G_COM_ST7920_HW_SPI u8g_com_atmega_st7920_hw_spi_fn
|
||||
#endif
|
||||
#if defined(__XTENSA__)
|
||||
#define U8G_COM_HW_SPI u8g_com_esp8266_hw_spi_fn
|
||||
#define U8G_COM_ST7920_HW_SPI u8g_com_null_fn
|
||||
#endif
|
||||
#endif
|
||||
#ifndef U8G_COM_HW_SPI
|
||||
#define U8G_COM_HW_SPI u8g_com_null_fn
|
||||
|
@ -1,7 +1,7 @@
|
||||
pwm.setup(0,500,50) pwm.setup(1,500,50) pwm.setup(2,500,50)
|
||||
pwm.start(0) pwm.start(1) pwm.start(2)
|
||||
function led(r,g,b) pwm.setduty(0,g) pwm.setduty(1,b) pwm.setduty(2,r) end
|
||||
wifi.station.autoconnect(1)
|
||||
wifi.sta.autoconnect(1)
|
||||
a=0
|
||||
tmr.alarm( 1000,1,function() if a==0 then a=1 led(50,50,50) else a=0 led(0,0,0) end end)
|
||||
|
||||
|
120
lua_examples/email/read_email_imap.lua
Normal file
120
lua_examples/email/read_email_imap.lua
Normal file
@ -0,0 +1,120 @@
|
||||
---
|
||||
-- Working Example: https://www.youtube.com/watch?v=PDxTR_KJLhc
|
||||
-- @author Miguel (AllAboutEE.com)
|
||||
-- @description This example will read the first email in your inbox using IMAP and
|
||||
-- display it through serial. The email server must provided unecrypted access. The code
|
||||
-- was tested with an AOL and Time Warner cable email accounts (GMail and other services who do
|
||||
-- not support no SSL access will not work).
|
||||
|
||||
require("imap")
|
||||
|
||||
local IMAP_USERNAME = "email@domain.com"
|
||||
local IMAP_PASSWORD = "password"
|
||||
|
||||
-- find out your unencrypted imap server and port
|
||||
-- from your email provided i.e. google "[my email service] imap settings" for example
|
||||
local IMAP_SERVER = "imap.service.com"
|
||||
local IMAP_PORT = "143"
|
||||
|
||||
local IMAP_TAG = "t1" -- You do not need to change this
|
||||
local IMAP_DEBUG = true -- change to true if you would like to see the entire conversation between
|
||||
-- the ESP8266 and IMAP server
|
||||
|
||||
local SSID = "ssid"
|
||||
local SSID_PASSWORD = "password"
|
||||
|
||||
|
||||
local count = 0 -- we will send several IMAP commands/requests, this variable helps keep track of which one to send
|
||||
|
||||
-- configure the ESP8266 as a station
|
||||
wifi.setmode(wifi.STATION)
|
||||
wifi.sta.config(SSID,SSID_PASSWORD)
|
||||
wifi.sta.autoconnect(1)
|
||||
|
||||
-- create an unencrypted connection
|
||||
local imap_socket = net.createConnection(net.TCP,0)
|
||||
|
||||
|
||||
---
|
||||
-- @name setup
|
||||
-- @description A call back function used to begin reading email
|
||||
-- upon sucessfull connection to the IMAP server
|
||||
function setup(sck)
|
||||
-- Set the email user name and password, IMAP tag, and if debugging output is needed
|
||||
imap.config(IMAP_USERNAME,
|
||||
IMAP_PASSWORD,
|
||||
IMAP_TAG,
|
||||
IMAP_DEBUG)
|
||||
|
||||
imap.login(sck)
|
||||
end
|
||||
|
||||
imap_socket:on("connection",setup) -- call setup() upon connection
|
||||
imap_socket:connect(IMAP_PORT,IMAP_SERVER) -- connect to the IMAP server
|
||||
|
||||
local subject = ""
|
||||
local from = ""
|
||||
local message = ""
|
||||
|
||||
---
|
||||
-- @name do_next
|
||||
-- @description A call back function for a timer alarm used to check if the previous
|
||||
-- IMAP command reply has been processed. If the IMAP reply has been processed
|
||||
-- this function will call the next IMAP command function necessary to read the email
|
||||
function do_next()
|
||||
|
||||
-- Check if the IMAP reply was processed
|
||||
if(imap.response_processed() == true) then
|
||||
|
||||
-- The IMAP reply was processed
|
||||
|
||||
if (count == 0) then
|
||||
-- After logging in we need to select the email folder from which we wish to read
|
||||
-- in this case the INBOX folder
|
||||
imap.examine(imap_socket,"INBOX")
|
||||
count = count + 1
|
||||
elseif (count == 1) then
|
||||
-- After examining/selecting the INBOX folder we can begin to retrieve emails.
|
||||
imap.fetch_header(imap_socket,imap.get_most_recent_num(),"SUBJECT") -- Retrieve the SUBJECT of the first/newest email
|
||||
count = count + 1
|
||||
elseif (count == 2) then
|
||||
subject = imap.get_header() -- store the SUBJECT response in subject
|
||||
imap.fetch_header(imap_socket,imap.get_most_recent_num(),"FROM") -- Retrieve the FROM of the first/newest email
|
||||
count = count + 1
|
||||
elseif (count == 3) then
|
||||
from = imap.get_header() -- store the FROM response in from
|
||||
imap.fetch_body_plain_text(imap_socket,imap.get_most_recent_num()) -- Retrieve the BODY of the first/newest email
|
||||
count = count + 1
|
||||
elseif (count == 4) then
|
||||
body = imap.get_body() -- store the BODY response in body
|
||||
imap.logout(imap_socket) -- Logout of the email account
|
||||
count = count + 1
|
||||
else
|
||||
-- display the email contents
|
||||
|
||||
-- create patterns to strip away IMAP protocl text from actual message
|
||||
pattern1 = "(\*.+\}\r\n)" -- to remove "* n command (BODY[n] {n}"
|
||||
pattern2 = "(%)\r\n.+)" -- to remove ") t1 OK command completed"
|
||||
|
||||
from = string.gsub(from,pattern1,"")
|
||||
from = string.gsub(from,pattern2,"")
|
||||
print(from)
|
||||
|
||||
subject = string.gsub(subject,pattern1,"")
|
||||
subject = string.gsub(subject,pattern2,"")
|
||||
print(subject)
|
||||
|
||||
body = string.gsub(body,pattern1,"")
|
||||
body = string.gsub(body,pattern2,"")
|
||||
print("Message: " .. body)
|
||||
|
||||
tmr.stop(0) -- Stop the timer alarm
|
||||
imap_socket:close() -- close the IMAP socket
|
||||
collectgarbage() -- clean up
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
-- A timer alarm is sued to check if an IMAP reply has been processed
|
||||
tmr.alarm(0,1000,1, do_next)
|
129
lua_examples/email/send_email_smtp.lua
Normal file
129
lua_examples/email/send_email_smtp.lua
Normal file
@ -0,0 +1,129 @@
|
||||
---
|
||||
-- Working Example: https://www.youtube.com/watch?v=CcRbFIJ8aeU
|
||||
-- @description a basic SMTP email example. You must use an account which can provide unencrypted authenticated access.
|
||||
-- This example was tested with an AOL and Time Warner email accounts. GMail does not offer unecrypted authenticated access.
|
||||
-- To obtain your email's SMTP server and port simply Google it e.g. [my email domain] SMTP settings
|
||||
-- For example for timewarner you'll get to this page http://www.timewarnercable.com/en/support/faqs/faqs-internet/e-mailacco/incoming-outgoing-server-addresses.html
|
||||
-- To Learn more about SMTP email visit:
|
||||
-- SMTP Commands Reference - http://www.samlogic.net/articles/smtp-commands-reference.htm
|
||||
-- See "SMTP transport example" in this page http://en.wikipedia.org/wiki/Simple_Mail_Transfer_Protocol
|
||||
-- @author Miguel
|
||||
|
||||
require("base64")
|
||||
|
||||
-- The email and password from the account you want to send emails from
|
||||
local MY_EMAIL = "esp8266@domain.com"
|
||||
local EMAIL_PASSWORD = "123456"
|
||||
|
||||
-- The SMTP server and port of your email provider.
|
||||
-- If you don't know it google [my email provider] SMTP settings
|
||||
local SMTP_SERVER = "smtp.server.com"
|
||||
local SMTP_PORT = "587"
|
||||
|
||||
-- The account you want to send email to
|
||||
local mail_to = "to_email@domain.com"
|
||||
|
||||
-- Your access point's SSID and password
|
||||
local SSID = "ssid"
|
||||
local SSID_PASSWORD = "password"
|
||||
|
||||
-- configure ESP as a station
|
||||
wifi.setmode(wifi.STATION)
|
||||
wifi.sta.config(SSID,SSID_PASSWORD)
|
||||
wifi.sta.autoconnect(1)
|
||||
|
||||
-- These are global variables. Don't change their values
|
||||
-- they will be changed in the functions below
|
||||
local email_subject = ""
|
||||
local email_body = ""
|
||||
local count = 0
|
||||
|
||||
|
||||
local smtp_socket = nil -- will be used as socket to email server
|
||||
|
||||
-- The display() function will be used to print the SMTP server's response
|
||||
function display(sck,response)
|
||||
print(response)
|
||||
end
|
||||
|
||||
-- The do_next() function is used to send the SMTP commands to the SMTP server in the required sequence.
|
||||
-- I was going to use socket callbacks but the code would not run callbacks after the first 3.
|
||||
function do_next()
|
||||
if(count == 0)then
|
||||
count = count+1
|
||||
local IP_ADDRESS = wifi.sta.getip()
|
||||
smtp_socket:send("HELO "..IP_ADDRESS.."\r\n")
|
||||
elseif(count==1) then
|
||||
count = count+1
|
||||
smtp_socket:send("AUTH LOGIN\r\n")
|
||||
elseif(count == 2) then
|
||||
count = count + 1
|
||||
smtp_socket:send(base64.enc(MY_EMAIL).."\r\n")
|
||||
elseif(count == 3) then
|
||||
count = count + 1
|
||||
smtp_socket:send(base64.enc(EMAIL_PASSWORD).."\r\n")
|
||||
elseif(count==4) then
|
||||
count = count+1
|
||||
smtp_socket:send("MAIL FROM:<" .. MY_EMAIL .. ">\r\n")
|
||||
elseif(count==5) then
|
||||
count = count+1
|
||||
smtp_socket:send("RCPT TO:<" .. mail_to ..">\r\n")
|
||||
elseif(count==6) then
|
||||
count = count+1
|
||||
smtp_socket:send("DATA\r\n")
|
||||
elseif(count==7) then
|
||||
count = count+1
|
||||
local message = string.gsub(
|
||||
"From: \"".. MY_EMAIL .."\"<"..MY_EMAIL..">\r\n" ..
|
||||
"To: \"".. mail_to .. "\"<".. mail_to..">\r\n"..
|
||||
"Subject: ".. email_subject .. "\r\n\r\n" ..
|
||||
email_body,"\r\n.\r\n","")
|
||||
|
||||
smtp_socket:send(message.."\r\n.\r\n")
|
||||
elseif(count==8) then
|
||||
count = count+1
|
||||
tmr.stop(0)
|
||||
smtp_socket:send("QUIT\r\n")
|
||||
else
|
||||
smtp_socket:close()
|
||||
end
|
||||
end
|
||||
|
||||
-- The connectted() function is executed when the SMTP socket is connected to the SMTP server.
|
||||
-- This function will create a timer to call the do_next function which will send the SMTP commands
|
||||
-- in sequence, one by one, every 5000 seconds.
|
||||
-- You can change the time to be smaller if that works for you, I used 5000ms just because.
|
||||
function connected(sck)
|
||||
tmr.alarm(0,5000,1,do_next)
|
||||
end
|
||||
|
||||
-- @name send_email
|
||||
-- @description Will initiated a socket connection to the SMTP server and trigger the connected() function
|
||||
-- @param subject The email's subject
|
||||
-- @param body The email's body
|
||||
function send_email(subject,body)
|
||||
count = 0
|
||||
email_subject = subject
|
||||
email_body = body
|
||||
smtp_socket = net.createConnection(net.TCP,0)
|
||||
smtp_socket:on("connection",connected)
|
||||
smtp_socket:on("receive",display)
|
||||
smtp_socket:connect(SMTP_PORT,SMTP_SERVER)
|
||||
end
|
||||
|
||||
-- Send an email
|
||||
send_email(
|
||||
"ESP8266",
|
||||
[[Hi,
|
||||
How are your IoT projects coming along?
|
||||
Best Wishes,
|
||||
ESP8266]])
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
84
lua_examples/u8glib/u8g_bitmaps.lua
Normal file
84
lua_examples/u8glib/u8g_bitmaps.lua
Normal file
@ -0,0 +1,84 @@
|
||||
|
||||
-- setup I2c and connect display
|
||||
function init_i2c_display()
|
||||
-- SDA and SCL can be assigned freely to available GPIOs
|
||||
sda = 5 -- GPIO14
|
||||
scl = 6 -- GPIO12
|
||||
sla = 0x3c
|
||||
i2c.setup(0, sda, scl, i2c.SLOW)
|
||||
disp = u8g.ssd1306_128x64_i2c(sla)
|
||||
end
|
||||
|
||||
-- setup SPI and connect display
|
||||
function init_spi_display()
|
||||
-- Hardware SPI CLK = GPIO14
|
||||
-- Hardware SPI MOSI = GPIO13
|
||||
-- Hardware SPI MISO = GPIO12 (not used)
|
||||
-- CS, D/C, and RES can be assigned freely to available GPIOs
|
||||
cs = 8 -- GPIO15, pull-down 10k to GND
|
||||
dc = 4 -- GPIO2
|
||||
res = 0 -- GPIO16
|
||||
|
||||
spi.setup(1, spi.MASTER, spi.CPOL_LOW, spi.CPHA_LOW, spi.DATABITS_8, 0)
|
||||
disp = u8g.ssd1306_128x64_spi(cs, dc, res)
|
||||
end
|
||||
|
||||
|
||||
function xbm_picture()
|
||||
disp:setFont(u8g.font_6x10)
|
||||
disp:drawStr( 0, 10, "XBM picture")
|
||||
|
||||
disp:drawXBM( 0, 20, 38, 24, xbm_data )
|
||||
end
|
||||
|
||||
function bitmap_picture(state)
|
||||
disp:setFont(u8g.font_6x10)
|
||||
disp:drawStr( 0, 10, "Bitmap picture")
|
||||
|
||||
disp:drawBitmap( 0 + (state * 10), 20 + (state * 4), 1, 8, bm_data )
|
||||
end
|
||||
|
||||
-- the draw() routine
|
||||
function draw(draw_state)
|
||||
local component = bit.rshift(draw_state, 3)
|
||||
|
||||
if (component == 0) then
|
||||
xbm_picture(bit.band(draw_state, 7))
|
||||
elseif (component == 1) then
|
||||
bitmap_picture(bit.band(draw_state, 7))
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
function bitmap_test(delay)
|
||||
-- read XBM picture
|
||||
file.open("u8glib_logo.xbm", "r")
|
||||
xbm_data = file.read()
|
||||
file.close()
|
||||
|
||||
-- read Bitmap picture
|
||||
file.open("u8g_rook.bm", "r")
|
||||
bm_data = file.read()
|
||||
file.close()
|
||||
|
||||
print("--- Starting Bitmap Test ---")
|
||||
dir = 0
|
||||
next_rotation = 0
|
||||
|
||||
local draw_state
|
||||
for draw_state = 1, 7 + 1*8, 1 do
|
||||
disp:firstPage()
|
||||
repeat
|
||||
draw(draw_state)
|
||||
until disp:nextPage() == false
|
||||
|
||||
tmr.delay(delay)
|
||||
tmr.wdclr()
|
||||
end
|
||||
|
||||
print("--- Bitmap Test done ---")
|
||||
end
|
||||
|
||||
--init_i2c_display()
|
||||
init_spi_display()
|
||||
bitmap_test(50000)
|
@ -1,13 +1,28 @@
|
||||
|
||||
-- setup I2c and connect display
|
||||
function init_i2c_display()
|
||||
sda = 5
|
||||
scl = 6
|
||||
-- SDA and SCL can be assigned freely to available GPIOs
|
||||
sda = 5 -- GPIO14
|
||||
scl = 6 -- GPIO12
|
||||
sla = 0x3c
|
||||
i2c.setup(0, sda, scl, i2c.SLOW)
|
||||
disp = u8g.ssd1306_128x64_i2c(sla)
|
||||
end
|
||||
|
||||
-- setup SPI and connect display
|
||||
function init_spi_display()
|
||||
-- Hardware SPI CLK = GPIO14
|
||||
-- Hardware SPI MOSI = GPIO13
|
||||
-- Hardware SPI MISO = GPIO12 (not used)
|
||||
-- CS, D/C, and RES can be assigned freely to available GPIOs
|
||||
cs = 8 -- GPIO15, pull-down 10k to GND
|
||||
dc = 4 -- GPIO2
|
||||
res = 0 -- GPIO16
|
||||
|
||||
spi.setup(1, spi.MASTER, spi.CPOL_LOW, spi.CPHA_LOW, spi.DATABITS_8, 0)
|
||||
disp = u8g.ssd1306_128x64_spi(cs, dc, res)
|
||||
end
|
||||
|
||||
|
||||
-- graphic test components
|
||||
function prepare()
|
||||
@ -122,9 +137,7 @@ function draw(draw_state)
|
||||
end
|
||||
end
|
||||
|
||||
function graphics_test()
|
||||
init_i2c_display()
|
||||
|
||||
function graphics_test(delay)
|
||||
print("--- Starting Graphics Test ---")
|
||||
|
||||
-- cycle through all components
|
||||
@ -135,6 +148,7 @@ function graphics_test()
|
||||
draw(draw_state)
|
||||
until disp:nextPage() == false
|
||||
--print(node.heap())
|
||||
tmr.delay(delay)
|
||||
-- re-trigger Watchdog!
|
||||
tmr.wdclr()
|
||||
end
|
||||
@ -142,4 +156,6 @@ function graphics_test()
|
||||
print("--- Graphics Test done ---")
|
||||
end
|
||||
|
||||
graphics_test()
|
||||
--init_i2c_display()
|
||||
init_spi_display()
|
||||
graphics_test(50000)
|
BIN
lua_examples/u8glib/u8g_rook.bm
Normal file
BIN
lua_examples/u8glib/u8g_rook.bm
Normal file
Binary file not shown.
@ -1,13 +1,29 @@
|
||||
|
||||
-- setup I2c and connect display
|
||||
function init_i2c_display()
|
||||
sda = 5
|
||||
scl = 6
|
||||
-- SDA and SCL can be assigned freely to available GPIOs
|
||||
sda = 5 -- GPIO14
|
||||
scl = 6 -- GPIO12
|
||||
sla = 0x3c
|
||||
i2c.setup(0, sda, scl, i2c.SLOW)
|
||||
disp = u8g.ssd1306_128x64_i2c(sla)
|
||||
end
|
||||
|
||||
-- setup SPI and connect display
|
||||
function init_spi_display()
|
||||
-- Hardware SPI CLK = GPIO14
|
||||
-- Hardware SPI MOSI = GPIO13
|
||||
-- Hardware SPI MISO = GPIO12 (not used)
|
||||
-- CS, D/C, and RES can be assigned freely to available GPIOs
|
||||
cs = 8 -- GPIO15, pull-down 10k to GND
|
||||
dc = 4 -- GPIO2
|
||||
res = 0 -- GPIO16
|
||||
|
||||
spi.setup(1, spi.MASTER, spi.CPOL_LOW, spi.CPHA_LOW, spi.DATABITS_8, 0)
|
||||
disp = u8g.ssd1306_128x64_spi(cs, dc, res)
|
||||
end
|
||||
|
||||
|
||||
-- the draw() routine
|
||||
function draw()
|
||||
disp:setFont(u8g.font_6x10)
|
||||
@ -35,13 +51,12 @@ function rotate()
|
||||
|
||||
dir = dir + 1
|
||||
dir = bit.band(dir, 3)
|
||||
-- schedule next rotation step in 1000ms
|
||||
next_rotation = tmr.now() / 1000 + 1000
|
||||
end
|
||||
end
|
||||
|
||||
function rotation_test()
|
||||
init_i2c_display()
|
||||
|
||||
print("--- Starting Rotation Test ---")
|
||||
dir = 0
|
||||
next_rotation = 0
|
||||
@ -55,10 +70,13 @@ function rotation_test()
|
||||
draw(draw_state)
|
||||
until disp:nextPage() == false
|
||||
|
||||
tmr.delay(100000)
|
||||
tmr.wdclr()
|
||||
end
|
||||
|
||||
print("--- Rotation Test done ---")
|
||||
end
|
||||
|
||||
--init_i2c_display()
|
||||
init_spi_display()
|
||||
rotation_test()
|
BIN
lua_examples/u8glib/u8glib_logo.xbm
Normal file
BIN
lua_examples/u8glib/u8glib_logo.xbm
Normal file
Binary file not shown.
41
lua_modules/base64/base64.lua
Normal file
41
lua_modules/base64/base64.lua
Normal file
@ -0,0 +1,41 @@
|
||||
-- Lua 5.1+ base64 v3.0 (c) 2009 by Alex Kloss <alexthkloss@web.de>
|
||||
-- licensed under the terms of the LGPL2
|
||||
|
||||
local moduleName = ...
|
||||
local M = {}
|
||||
_G[moduleName] = M
|
||||
|
||||
-- character table string
|
||||
local b='ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'
|
||||
|
||||
-- encoding
|
||||
function M.enc(data)
|
||||
return ((data:gsub('.', function(x)
|
||||
local r,b='',x:byte()
|
||||
for i=8,1,-1 do r=r..(b%2^i-b%2^(i-1)>0 and '1' or '0') end
|
||||
return r;
|
||||
end)..'0000'):gsub('%d%d%d?%d?%d?%d?', function(x)
|
||||
if (#x < 6) then return '' end
|
||||
local c=0
|
||||
for i=1,6 do c=c+(x:sub(i,i)=='1' and 2^(6-i) or 0) end
|
||||
return b:sub(c+1,c+1)
|
||||
end)..({ '', '==', '=' })[#data%3+1])
|
||||
end
|
||||
|
||||
-- decoding
|
||||
function M.dec(data)
|
||||
data = string.gsub(data, '[^'..b..'=]', '')
|
||||
return (data:gsub('.', function(x)
|
||||
if (x == '=') then return '' end
|
||||
local r,f='',(b:find(x)-1)
|
||||
for i=6,1,-1 do r=r..(f%2^i-f%2^(i-1)>0 and '1' or '0') end
|
||||
return r;
|
||||
end):gsub('%d%d%d?%d?%d?%d?%d?%d?', function(x)
|
||||
if (#x ~= 8) then return '' end
|
||||
local c=0
|
||||
for i=1,8 do c=c+(x:sub(i,i)=='1' and 2^(7-i) or 0) end
|
||||
return string.char(c)
|
||||
end))
|
||||
end
|
||||
|
||||
return M
|
205
lua_modules/email/imap.lua
Normal file
205
lua_modules/email/imap.lua
Normal file
@ -0,0 +1,205 @@
|
||||
---
|
||||
-- Working Example: https://www.youtube.com/watch?v=PDxTR_KJLhc
|
||||
-- IMPORTANT: run node.compile("imap.lua") after uploading this script
|
||||
-- to create a compiled module. Then run file.remove("imap.lua")
|
||||
-- @name imap
|
||||
-- @description An IMAP 4rev1 module that can be used to read email.
|
||||
-- Tested on NodeMCU 0.9.5 build 20150213.
|
||||
-- @date March 12, 2015
|
||||
-- @author Miguel
|
||||
-- GitHub: https://github.com/AllAboutEE
|
||||
-- YouTube: https://www.youtube.com/user/AllAboutEE
|
||||
-- Website: http://AllAboutEE.com
|
||||
--
|
||||
-- Visit the following URLs to learn more about IMAP:
|
||||
-- "How to test an IMAP server by using telnet" http://www.anta.net/misc/telnet-troubleshooting/imap.shtml
|
||||
-- "RFC 2060 - Internet Message Access Protocol - Version 4rev1" http://www.faqs.org/rfcs/rfc2060.html
|
||||
-------------------------------------------------------------------------------------------------------------
|
||||
local moduleName = ...
|
||||
local M = {}
|
||||
_G[moduleName] = M
|
||||
|
||||
local USERNAME = ""
|
||||
local PASSWORD = ""
|
||||
|
||||
local SERVER = ""
|
||||
local PORT = ""
|
||||
local TAG = ""
|
||||
|
||||
local DEBUG = false
|
||||
|
||||
local body = "" -- used to store an email's body / main text
|
||||
local header = "" -- used to store an email's last requested header field e.g. SUBJECT, FROM, DATA etc.
|
||||
local most_recent_num = 1 -- used to store the latest/newest email number/id
|
||||
|
||||
|
||||
local response_processed = false -- used to know if the last IMAP response has been processed
|
||||
|
||||
---
|
||||
-- @name response_processed
|
||||
-- @returns The response process status of the last IMAP command sent
|
||||
function M.response_processed()
|
||||
return response_processed
|
||||
end
|
||||
|
||||
---
|
||||
-- @name display
|
||||
-- @description A generic IMAP response processing function.
|
||||
-- Can disply the IMAP response if DEBUG is set to true.
|
||||
-- Sets the reponse processed variable to true when the string "complete"
|
||||
-- is found in the IMAP reply/response
|
||||
local function display(socket, response)
|
||||
|
||||
-- If debuggins is enabled print the IMAP response
|
||||
if(DEBUG) then
|
||||
print(response)
|
||||
end
|
||||
|
||||
-- Some IMAP responses are long enough that they will cause the display
|
||||
-- function to be called several times. One thing is certain, IMAP will replay with
|
||||
-- "<tag> OK <command> complete" when it's done sending data back.
|
||||
if(string.match(response,'complete') ~= nil) then
|
||||
response_processed = true
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
---
|
||||
-- @name config
|
||||
-- @description Initiates the IMAP settings
|
||||
function M.config(username,password,tag,debug)
|
||||
USERNAME = username
|
||||
PASSWORD = password
|
||||
TAG = tag
|
||||
DEBUG = debug
|
||||
end
|
||||
|
||||
---
|
||||
-- @name login
|
||||
-- @descrpiton Logs into a new email session
|
||||
function M.login(socket)
|
||||
response_processed = false -- we are sending a new command
|
||||
-- which means that the response for it has not been processed
|
||||
socket:send(TAG .. " LOGIN " .. USERNAME .. " " .. PASSWORD .. "\r\n")
|
||||
socket:on("receive",display)
|
||||
end
|
||||
|
||||
---
|
||||
-- @name get_most_recent_num
|
||||
-- @returns The most recent email number. Should only be called after examine()
|
||||
function M.get_most_recent_num()
|
||||
return most_recent_num
|
||||
end
|
||||
|
||||
---
|
||||
-- @name set_most_recent_num
|
||||
-- @description Gets the most recent email number from the EXAMINE command.
|
||||
-- i.e. if EXAMINE returns "* 4 EXISTS" this means that there are 4 emails,
|
||||
-- so the latest/newest will be identified by the number 4
|
||||
local function set_most_recent_num(socket,response)
|
||||
|
||||
if(DEBUG) then
|
||||
print(response)
|
||||
end
|
||||
|
||||
local _, _, num = string.find(response,"([0-9]+) EXISTS(\.)") -- the _ and _ keep the index of the string found
|
||||
-- but we don't care about that.
|
||||
|
||||
if(num~=nil) then
|
||||
most_recent_num = num
|
||||
end
|
||||
|
||||
if(string.match(response,'complete') ~= nil) then
|
||||
response_processed = true
|
||||
end
|
||||
end
|
||||
|
||||
---
|
||||
-- @name examine
|
||||
-- @description IMAP examines the given mailbox/folder. Sends the IMAP EXAMINE command
|
||||
function M.examine(socket,mailbox)
|
||||
|
||||
response_processed = false
|
||||
socket:send(TAG .. " EXAMINE " .. mailbox .. "\r\n")
|
||||
socket:on("receive",set_most_recent_num)
|
||||
end
|
||||
|
||||
---
|
||||
-- @name get_header
|
||||
-- @returns The last fetched header field
|
||||
function M.get_header()
|
||||
return header
|
||||
end
|
||||
|
||||
---
|
||||
-- @name set_header
|
||||
-- @description Records the IMAP header field response in a variable
|
||||
-- so that it may be read later
|
||||
local function set_header(socket,response)
|
||||
if(DEBUG) then
|
||||
print(response)
|
||||
end
|
||||
|
||||
header = header .. response
|
||||
if(string.match(response,'complete') ~= nil) then
|
||||
response_processed = true
|
||||
end
|
||||
end
|
||||
|
||||
---
|
||||
-- @name fetch_header
|
||||
-- @description Fetches an emails header field e.g. SUBJECT, FROM, DATE
|
||||
-- @param socket The IMAP socket to use
|
||||
-- @param msg_number The email number to read e.g. 1 will read fetch the latest/newest email
|
||||
-- @param field A header field such as SUBJECT, FROM, or DATE
|
||||
function M.fetch_header(socket,msg_number,field)
|
||||
header = "" -- we are getting a new header so clear this variable
|
||||
response_processed = false
|
||||
socket:send(TAG .. " FETCH " .. msg_number .. " BODY[HEADER.FIELDS (" .. field .. ")]\r\n")
|
||||
socket:on("receive",set_header)
|
||||
end
|
||||
|
||||
|
||||
---
|
||||
-- @name get_body
|
||||
-- @return The last email read's body
|
||||
function M.get_body()
|
||||
return body
|
||||
end
|
||||
|
||||
---
|
||||
-- @name set_body
|
||||
-- @description Records the IMAP body response in a variable
|
||||
-- so that it may be read later
|
||||
local function set_body(socket,response)
|
||||
|
||||
if(DEBUG) then
|
||||
print(response)
|
||||
end
|
||||
|
||||
body = body .. response
|
||||
if(string.match(response,'complete') ~= nil) then
|
||||
response_processed = true
|
||||
end
|
||||
end
|
||||
|
||||
---
|
||||
-- @name fetch_body_plain_text
|
||||
-- @description Sends the IMAP command to fetch a plain text version of the email's body
|
||||
-- @param socket The IMAP socket to use
|
||||
-- @param msg_number The email number to obtain e.g. 1 will obtain the latest email
|
||||
function M.fetch_body_plain_text(socket,msg_number)
|
||||
response_processed = false
|
||||
body = "" -- clear the body variable since we'll be fetching a new email
|
||||
socket:send(TAG .. " FETCH " .. msg_number .. " BODY[1]\r\n")
|
||||
socket:on("receive",set_body)
|
||||
end
|
||||
|
||||
---
|
||||
-- @name logout
|
||||
-- @description Sends the IMAP command to logout of the email session
|
||||
function M.logout(socket)
|
||||
response_processed = false
|
||||
socket:send(TAG .. " LOGOUT\r\n")
|
||||
socket:on("receive",display)
|
||||
end
|
Loading…
x
Reference in New Issue
Block a user