· 6 years ago · Oct 13, 2019, 03:16 AM
1#include "v7.h"
2#ifdef V7_MODULE_LINES
3#line 1 "v7/src/license.h"
4#endif
5/*
6 * Copyright (c) 2013-2014 Cesanta Software Limited
7 * All rights reserved
8 *
9 * This software is dual-licensed: you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License version 2 as
11 * published by the Free Software Foundation. For the terms of this
12 * license, see <http://www.gnu.org/licenses/>.
13 *
14 * You are free to use this software under the terms of the GNU General
15 * Public License, but WITHOUT ANY WARRANTY; without even the implied
16 * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
17 * See the GNU General Public License for more details.
18 *
19 * Alternatively, you can license this software under a commercial
20 * license, as set out in <https://www.cesanta.com/license>.
21 */
22
23#ifdef V7_EXPOSE_PRIVATE
24#define V7_PRIVATE
25#define V7_EXTERN extern
26#else
27#define V7_PRIVATE static
28#define V7_EXTERN static
29#endif /* CS_V7_SRC_LICENSE_H_ */
30#ifdef V7_MODULE_LINES
31#line 1 "common/platform.h"
32#endif
33#ifndef CS_COMMON_PLATFORM_H_
34#define CS_COMMON_PLATFORM_H_
35
36/*
37 * For the "custom" platform, includes and dependencies can be
38 * provided through mg_locals.h.
39 */
40#define CS_P_CUSTOM 0
41#define CS_P_UNIX 1
42#define CS_P_WINDOWS 2
43#define CS_P_ESP32 15
44#define CS_P_ESP8266 3
45#define CS_P_CC3100 6
46#define CS_P_CC3200 4
47#define CS_P_CC3220 17
48#define CS_P_MSP432 5
49#define CS_P_TM4C129 14
50#define CS_P_MBED 7
51#define CS_P_WINCE 8
52#define CS_P_NXP_LPC 13
53#define CS_P_NXP_KINETIS 9
54#define CS_P_NRF51 12
55#define CS_P_NRF52 10
56#define CS_P_PIC32 11
57#define CS_P_STM32 16
58/* Next id: 18 */
59
60/* If not specified explicitly, we guess platform by defines. */
61#ifndef CS_PLATFORM
62
63#if defined(TARGET_IS_MSP432P4XX) || defined(__MSP432P401R__)
64#define CS_PLATFORM CS_P_MSP432
65#elif defined(cc3200) || defined(TARGET_IS_CC3200)
66#define CS_PLATFORM CS_P_CC3200
67#elif defined(cc3220) || defined(TARGET_IS_CC3220)
68#define CS_PLATFORM CS_P_CC3220
69#elif defined(__unix__) || defined(__APPLE__)
70#define CS_PLATFORM CS_P_UNIX
71#elif defined(WINCE)
72#define CS_PLATFORM CS_P_WINCE
73#elif defined(_WIN32)
74#define CS_PLATFORM CS_P_WINDOWS
75#elif defined(__MBED__)
76#define CS_PLATFORM CS_P_MBED
77#elif defined(__USE_LPCOPEN)
78#define CS_PLATFORM CS_P_NXP_LPC
79#elif defined(FRDM_K64F) || defined(FREEDOM)
80#define CS_PLATFORM CS_P_NXP_KINETIS
81#elif defined(PIC32)
82#define CS_PLATFORM CS_P_PIC32
83#elif defined(ESP_PLATFORM)
84#define CS_PLATFORM CS_P_ESP32
85#elif defined(ICACHE_FLASH)
86#define CS_PLATFORM CS_P_ESP8266
87#elif defined(TARGET_IS_TM4C129_RA0) || defined(TARGET_IS_TM4C129_RA1) || \
88 defined(TARGET_IS_TM4C129_RA2)
89#define CS_PLATFORM CS_P_TM4C129
90#elif defined(STM32)
91#define CS_PLATFORM CS_P_STM32
92#endif
93
94#ifndef CS_PLATFORM
95#error "CS_PLATFORM is not specified and we couldn't guess it."
96#endif
97
98#endif /* !defined(CS_PLATFORM) */
99
100#define MG_NET_IF_SOCKET 1
101#define MG_NET_IF_SIMPLELINK 2
102#define MG_NET_IF_LWIP_LOW_LEVEL 3
103#define MG_NET_IF_PIC32 4
104
105#define MG_SSL_IF_OPENSSL 1
106#define MG_SSL_IF_MBEDTLS 2
107#define MG_SSL_IF_SIMPLELINK 3
108
109/* Amalgamated: #include "common/platforms/platform_unix.h" */
110/* Amalgamated: #include "common/platforms/platform_windows.h" */
111/* Amalgamated: #include "common/platforms/platform_esp32.h" */
112/* Amalgamated: #include "common/platforms/platform_esp8266.h" */
113/* Amalgamated: #include "common/platforms/platform_cc3100.h" */
114/* Amalgamated: #include "common/platforms/platform_cc3200.h" */
115/* Amalgamated: #include "common/platforms/platform_cc3220.h" */
116/* Amalgamated: #include "common/platforms/platform_mbed.h" */
117/* Amalgamated: #include "common/platforms/platform_nrf51.h" */
118/* Amalgamated: #include "common/platforms/platform_nrf52.h" */
119/* Amalgamated: #include "common/platforms/platform_wince.h" */
120/* Amalgamated: #include "common/platforms/platform_nxp_lpc.h" */
121/* Amalgamated: #include "common/platforms/platform_nxp_kinetis.h" */
122/* Amalgamated: #include "common/platforms/platform_pic32.h" */
123/* Amalgamated: #include "common/platforms/platform_stm32.h" */
124
125/* Common stuff */
126
127#if !defined(WEAK)
128#if (defined(__GNUC__) || defined(__TI_COMPILER_VERSION__)) && !defined(_WIN32)
129#define WEAK __attribute__((weak))
130#else
131#define WEAK
132#endif
133#endif
134
135#ifdef __GNUC__
136#define NORETURN __attribute__((noreturn))
137#define NOINLINE __attribute__((noinline))
138#define WARN_UNUSED_RESULT __attribute__((warn_unused_result))
139#define NOINSTR __attribute__((no_instrument_function))
140#define DO_NOT_WARN_UNUSED __attribute__((unused))
141#else
142#define NORETURN
143#define NOINLINE
144#define WARN_UNUSED_RESULT
145#define NOINSTR
146#define DO_NOT_WARN_UNUSED
147#endif /* __GNUC__ */
148
149#ifndef ARRAY_SIZE
150#define ARRAY_SIZE(array) (sizeof(array) / sizeof(array[0]))
151#endif
152
153#endif /* CS_COMMON_PLATFORM_H_ */
154#ifdef V7_MODULE_LINES
155#line 1 "common/platforms/platform_windows.h"
156#endif
157#ifndef CS_COMMON_PLATFORMS_PLATFORM_WINDOWS_H_
158#define CS_COMMON_PLATFORMS_PLATFORM_WINDOWS_H_
159#if CS_PLATFORM == CS_P_WINDOWS
160
161/*
162 * MSVC++ 14.0 _MSC_VER == 1900 (Visual Studio 2015)
163 * MSVC++ 12.0 _MSC_VER == 1800 (Visual Studio 2013)
164 * MSVC++ 11.0 _MSC_VER == 1700 (Visual Studio 2012)
165 * MSVC++ 10.0 _MSC_VER == 1600 (Visual Studio 2010)
166 * MSVC++ 9.0 _MSC_VER == 1500 (Visual Studio 2008)
167 * MSVC++ 8.0 _MSC_VER == 1400 (Visual Studio 2005)
168 * MSVC++ 7.1 _MSC_VER == 1310 (Visual Studio 2003)
169 * MSVC++ 7.0 _MSC_VER == 1300
170 * MSVC++ 6.0 _MSC_VER == 1200
171 * MSVC++ 5.0 _MSC_VER == 1100
172 */
173#ifdef _MSC_VER
174#pragma warning(disable : 4127) /* FD_SET() emits warning, disable it */
175#pragma warning(disable : 4204) /* missing c99 support */
176#endif
177
178#ifndef _WINSOCK_DEPRECATED_NO_WARNINGS
179#define _WINSOCK_DEPRECATED_NO_WARNINGS 1
180#endif
181
182#ifndef _CRT_SECURE_NO_WARNINGS
183#define _CRT_SECURE_NO_WARNINGS
184#endif
185
186#include <assert.h>
187#include <direct.h>
188#include <errno.h>
189#include <fcntl.h>
190#include <io.h>
191#include <limits.h>
192#include <signal.h>
193#include <stddef.h>
194#include <stdio.h>
195#include <stdlib.h>
196#include <sys/stat.h>
197#include <time.h>
198#include <ctype.h>
199
200#ifdef _MSC_VER
201#pragma comment(lib, "ws2_32.lib") /* Linking with winsock library */
202#endif
203
204#include <winsock2.h>
205#include <ws2tcpip.h>
206#include <windows.h>
207#include <process.h>
208
209#if defined(_MSC_VER) && _MSC_VER >= 1800
210#define strdup _strdup
211#endif
212
213#ifndef EINPROGRESS
214#define EINPROGRESS WSAEINPROGRESS
215#endif
216#ifndef EWOULDBLOCK
217#define EWOULDBLOCK WSAEWOULDBLOCK
218#endif
219#ifndef __func__
220#define STRX(x) #x
221#define STR(x) STRX(x)
222#define __func__ __FILE__ ":" STR(__LINE__)
223#endif
224#define snprintf _snprintf
225#define vsnprintf _vsnprintf
226#define to64(x) _atoi64(x)
227#if !defined(__MINGW32__) && !defined(__MINGW64__)
228#define popen(x, y) _popen((x), (y))
229#define pclose(x) _pclose(x)
230#define fileno _fileno
231#endif
232#if defined(_MSC_VER) && _MSC_VER >= 1400
233#define fseeko(x, y, z) _fseeki64((x), (y), (z))
234#else
235#define fseeko(x, y, z) fseek((x), (y), (z))
236#endif
237#if defined(_MSC_VER) && _MSC_VER <= 1200
238typedef unsigned long uintptr_t;
239typedef long intptr_t;
240#endif
241typedef int socklen_t;
242#if _MSC_VER >= 1700
243#include <stdint.h>
244#else
245typedef signed char int8_t;
246typedef unsigned char uint8_t;
247typedef int int32_t;
248typedef unsigned int uint32_t;
249typedef short int16_t;
250typedef unsigned short uint16_t;
251typedef __int64 int64_t;
252typedef unsigned __int64 uint64_t;
253#endif
254typedef SOCKET sock_t;
255typedef uint32_t in_addr_t;
256#ifndef UINT16_MAX
257#define UINT16_MAX 65535
258#endif
259#ifndef UINT32_MAX
260#define UINT32_MAX 4294967295
261#endif
262#ifndef pid_t
263#define pid_t HANDLE
264#endif
265#define INT64_FMT "I64d"
266#define INT64_X_FMT "I64x"
267#define SIZE_T_FMT "Iu"
268typedef struct _stati64 cs_stat_t;
269#ifndef S_ISDIR
270#define S_ISDIR(x) (((x) &_S_IFMT) == _S_IFDIR)
271#endif
272#ifndef S_ISREG
273#define S_ISREG(x) (((x) &_S_IFMT) == _S_IFREG)
274#endif
275#define DIRSEP '\\'
276#define CS_DEFINE_DIRENT
277
278#ifndef va_copy
279#ifdef __va_copy
280#define va_copy __va_copy
281#else
282#define va_copy(x, y) (x) = (y)
283#endif
284#endif
285
286#ifndef MG_MAX_HTTP_REQUEST_SIZE
287#define MG_MAX_HTTP_REQUEST_SIZE 8192
288#endif
289
290#ifndef MG_MAX_HTTP_SEND_MBUF
291#define MG_MAX_HTTP_SEND_MBUF 4096
292#endif
293
294#ifndef MG_MAX_HTTP_HEADERS
295#define MG_MAX_HTTP_HEADERS 40
296#endif
297
298#ifndef CS_ENABLE_STDIO
299#define CS_ENABLE_STDIO 1
300#endif
301
302#ifndef MG_ENABLE_BROADCAST
303#define MG_ENABLE_BROADCAST 1
304#endif
305
306#ifndef MG_ENABLE_DIRECTORY_LISTING
307#define MG_ENABLE_DIRECTORY_LISTING 1
308#endif
309
310#ifndef MG_ENABLE_FILESYSTEM
311#define MG_ENABLE_FILESYSTEM 1
312#endif
313
314#ifndef MG_ENABLE_HTTP_CGI
315#define MG_ENABLE_HTTP_CGI MG_ENABLE_FILESYSTEM
316#endif
317
318#ifndef MG_NET_IF
319#define MG_NET_IF MG_NET_IF_SOCKET
320#endif
321
322int rmdir(const char *dirname);
323unsigned int sleep(unsigned int seconds);
324
325#endif /* CS_PLATFORM == CS_P_WINDOWS */
326#endif /* CS_COMMON_PLATFORMS_PLATFORM_WINDOWS_H_ */
327#ifdef V7_MODULE_LINES
328#line 1 "common/platforms/platform_unix.h"
329#endif
330#ifndef CS_COMMON_PLATFORMS_PLATFORM_UNIX_H_
331#define CS_COMMON_PLATFORMS_PLATFORM_UNIX_H_
332#if CS_PLATFORM == CS_P_UNIX
333
334#ifndef _XOPEN_SOURCE
335#define _XOPEN_SOURCE 600
336#endif
337
338/* <inttypes.h> wants this for C++ */
339#ifndef __STDC_FORMAT_MACROS
340#define __STDC_FORMAT_MACROS
341#endif
342
343/* C++ wants that for INT64_MAX */
344#ifndef __STDC_LIMIT_MACROS
345#define __STDC_LIMIT_MACROS
346#endif
347
348/* Enable fseeko() and ftello() functions */
349#ifndef _LARGEFILE_SOURCE
350#define _LARGEFILE_SOURCE
351#endif
352
353/* Enable 64-bit file offsets */
354#ifndef _FILE_OFFSET_BITS
355#define _FILE_OFFSET_BITS 64
356#endif
357
358#include <arpa/inet.h>
359#include <assert.h>
360#include <ctype.h>
361#include <dirent.h>
362#include <errno.h>
363#include <fcntl.h>
364#include <inttypes.h>
365#include <stdint.h>
366#include <limits.h>
367#include <math.h>
368#include <netdb.h>
369#include <netinet/in.h>
370#include <pthread.h>
371#include <signal.h>
372#include <stdarg.h>
373#include <stdio.h>
374#include <stdlib.h>
375#include <string.h>
376#include <sys/param.h>
377#include <sys/socket.h>
378#include <sys/select.h>
379#include <sys/stat.h>
380#include <sys/time.h>
381#include <sys/types.h>
382#include <unistd.h>
383
384#ifdef __APPLE__
385#include <machine/endian.h>
386#ifndef BYTE_ORDER
387#define LITTLE_ENDIAN __DARWIN_LITTLE_ENDIAN
388#define BIG_ENDIAN __DARWIN_BIG_ENDIAN
389#define PDP_ENDIAN __DARWIN_PDP_ENDIAN
390#define BYTE_ORDER __DARWIN_BYTE_ORDER
391#endif
392#endif
393
394/*
395 * osx correctly avoids defining strtoll when compiling in strict ansi mode.
396 * c++ 11 standard defines strtoll as well.
397 * We require strtoll, and if your embedded pre-c99 compiler lacks one, please
398 * implement a shim.
399 */
400#if !(defined(__cplusplus) && __cplusplus >= 201103L) && \
401 !(defined(__DARWIN_C_LEVEL) && __DARWIN_C_LEVEL >= 200809L)
402long long strtoll(const char *, char **, int);
403#endif
404
405typedef int sock_t;
406#define INVALID_SOCKET (-1)
407#define SIZE_T_FMT "zu"
408typedef struct stat cs_stat_t;
409#define DIRSEP '/'
410#define to64(x) strtoll(x, NULL, 10)
411#define INT64_FMT PRId64
412#define INT64_X_FMT PRIx64
413
414#ifndef __cdecl
415#define __cdecl
416#endif
417
418#ifndef va_copy
419#ifdef __va_copy
420#define va_copy __va_copy
421#else
422#define va_copy(x, y) (x) = (y)
423#endif
424#endif
425
426#define closesocket(x) close(x)
427
428#ifndef MG_MAX_HTTP_REQUEST_SIZE
429#define MG_MAX_HTTP_REQUEST_SIZE 8192
430#endif
431
432#ifndef MG_MAX_HTTP_SEND_MBUF
433#define MG_MAX_HTTP_SEND_MBUF 4096
434#endif
435
436#ifndef MG_MAX_HTTP_HEADERS
437#define MG_MAX_HTTP_HEADERS 40
438#endif
439
440#ifndef CS_ENABLE_STDIO
441#define CS_ENABLE_STDIO 1
442#endif
443
444#ifndef MG_ENABLE_BROADCAST
445#define MG_ENABLE_BROADCAST 1
446#endif
447
448#ifndef MG_ENABLE_DIRECTORY_LISTING
449#define MG_ENABLE_DIRECTORY_LISTING 1
450#endif
451
452#ifndef MG_ENABLE_FILESYSTEM
453#define MG_ENABLE_FILESYSTEM 1
454#endif
455
456#ifndef MG_ENABLE_HTTP_CGI
457#define MG_ENABLE_HTTP_CGI MG_ENABLE_FILESYSTEM
458#endif
459
460#ifndef MG_NET_IF
461#define MG_NET_IF MG_NET_IF_SOCKET
462#endif
463
464#ifndef MG_HOSTS_FILE_NAME
465#define MG_HOSTS_FILE_NAME "/etc/hosts"
466#endif
467
468#ifndef MG_RESOLV_CONF_FILE_NAME
469#define MG_RESOLV_CONF_FILE_NAME "/etc/resolv.conf"
470#endif
471
472#endif /* CS_PLATFORM == CS_P_UNIX */
473#endif /* CS_COMMON_PLATFORMS_PLATFORM_UNIX_H_ */
474#ifdef V7_MODULE_LINES
475#line 1 "common/platforms/platform_esp32.h"
476#endif
477/*
478 * Copyright (c) 2014-2016 Cesanta Software Limited
479 * All rights reserved
480 */
481
482#ifndef CS_COMMON_PLATFORMS_PLATFORM_ESP32_H_
483#define CS_COMMON_PLATFORMS_PLATFORM_ESP32_H_
484#if CS_PLATFORM == CS_P_ESP32
485
486#include <assert.h>
487#include <ctype.h>
488#include <dirent.h>
489#include <fcntl.h>
490#include <inttypes.h>
491#include <machine/endian.h>
492#include <stdint.h>
493#include <string.h>
494#include <sys/stat.h>
495#include <sys/time.h>
496
497#define SIZE_T_FMT "u"
498typedef struct stat cs_stat_t;
499#define DIRSEP '/'
500#define to64(x) strtoll(x, NULL, 10)
501#define INT64_FMT PRId64
502#define INT64_X_FMT PRIx64
503#define __cdecl
504#define _FILE_OFFSET_BITS 32
505
506#define MG_LWIP 1
507
508#ifndef MG_NET_IF
509#define MG_NET_IF MG_NET_IF_SOCKET
510#endif
511
512#ifndef CS_ENABLE_STDIO
513#define CS_ENABLE_STDIO 1
514#endif
515
516#endif /* CS_PLATFORM == CS_P_ESP32 */
517#endif /* CS_COMMON_PLATFORMS_PLATFORM_ESP32_H_ */
518#ifdef V7_MODULE_LINES
519#line 1 "common/platforms/platform_esp8266.h"
520#endif
521/*
522 * Copyright (c) 2014-2016 Cesanta Software Limited
523 * All rights reserved
524 */
525
526#ifndef CS_COMMON_PLATFORMS_PLATFORM_ESP8266_H_
527#define CS_COMMON_PLATFORMS_PLATFORM_ESP8266_H_
528#if CS_PLATFORM == CS_P_ESP8266
529
530#include <assert.h>
531#include <ctype.h>
532#include <fcntl.h>
533#include <inttypes.h>
534#include <machine/endian.h>
535#include <string.h>
536#include <sys/stat.h>
537#include <sys/time.h>
538
539#define SIZE_T_FMT "u"
540typedef struct stat cs_stat_t;
541#define DIRSEP '/'
542#if !defined(MGOS_VFS_DEFINE_DIRENT)
543#define CS_DEFINE_DIRENT
544#endif
545
546#define to64(x) strtoll(x, NULL, 10)
547#define INT64_FMT PRId64
548#define INT64_X_FMT PRIx64
549#define __cdecl
550#define _FILE_OFFSET_BITS 32
551
552#if !defined(RTOS_SDK) && !defined(__cplusplus)
553#define fileno(x) -1
554#endif
555
556#define MG_LWIP 1
557
558/* struct timeval is defined in sys/time.h. */
559#define LWIP_TIMEVAL_PRIVATE 0
560
561#ifndef MG_NET_IF
562#include <lwip/opt.h>
563#if LWIP_SOCKET /* RTOS SDK has LWIP sockets */
564#define MG_NET_IF MG_NET_IF_SOCKET
565#else
566#define MG_NET_IF MG_NET_IF_LWIP_LOW_LEVEL
567#endif
568#endif
569
570#ifndef CS_ENABLE_STDIO
571#define CS_ENABLE_STDIO 1
572#endif
573
574#endif /* CS_PLATFORM == CS_P_ESP8266 */
575#endif /* CS_COMMON_PLATFORMS_PLATFORM_ESP8266_H_ */
576#ifdef V7_MODULE_LINES
577#line 1 "common/platforms/platform_cc3100.h"
578#endif
579/*
580 * Copyright (c) 2014-2016 Cesanta Software Limited
581 * All rights reserved
582 */
583
584#ifndef CS_COMMON_PLATFORMS_PLATFORM_CC3100_H_
585#define CS_COMMON_PLATFORMS_PLATFORM_CC3100_H_
586#if CS_PLATFORM == CS_P_CC3100
587
588#include <assert.h>
589#include <ctype.h>
590#include <errno.h>
591#include <inttypes.h>
592#include <stdint.h>
593#include <string.h>
594#include <time.h>
595
596#define MG_NET_IF MG_NET_IF_SIMPLELINK
597#define MG_SSL_IF MG_SSL_IF_SIMPLELINK
598
599/*
600 * CC3100 SDK and STM32 SDK include headers w/out path, just like
601 * #include "simplelink.h". As result, we have to add all required directories
602 * into Makefile IPATH and do the same thing (include w/out path)
603 */
604
605#include <simplelink.h>
606#include <netapp.h>
607#undef timeval
608
609typedef int sock_t;
610#define INVALID_SOCKET (-1)
611
612#define to64(x) strtoll(x, NULL, 10)
613#define INT64_FMT PRId64
614#define INT64_X_FMT PRIx64
615#define SIZE_T_FMT "u"
616
617#define SOMAXCONN 8
618
619const char *inet_ntop(int af, const void *src, char *dst, socklen_t size);
620char *inet_ntoa(struct in_addr in);
621int inet_pton(int af, const char *src, void *dst);
622
623#endif /* CS_PLATFORM == CS_P_CC3100 */
624#endif /* CS_COMMON_PLATFORMS_PLATFORM_CC3100_H_ */
625#ifdef V7_MODULE_LINES
626#line 1 "common/platforms/simplelink/cs_simplelink.h"
627#endif
628/*
629 * Copyright (c) 2014-2016 Cesanta Software Limited
630 * All rights reserved
631 */
632
633#ifndef CS_COMMON_PLATFORMS_SIMPLELINK_CS_SIMPLELINK_H_
634#define CS_COMMON_PLATFORMS_SIMPLELINK_CS_SIMPLELINK_H_
635
636#if defined(MG_NET_IF) && MG_NET_IF == MG_NET_IF_SIMPLELINK
637
638/* If simplelink.h is already included, all bets are off. */
639#if !defined(__SIMPLELINK_H__)
640
641#include <stdbool.h>
642
643#ifndef __TI_COMPILER_VERSION__
644#undef __CONCAT
645#undef FD_CLR
646#undef FD_ISSET
647#undef FD_SET
648#undef FD_SETSIZE
649#undef FD_ZERO
650#undef fd_set
651#endif
652
653#if CS_PLATFORM == CS_P_CC3220
654#include <ti/drivers/net/wifi/porting/user.h>
655#include <ti/drivers/net/wifi/simplelink.h>
656#include <ti/drivers/net/wifi/sl_socket.h>
657#include <ti/drivers/net/wifi/netapp.h>
658#else
659/* We want to disable SL_INC_STD_BSD_API_NAMING, so we include user.h ourselves
660 * and undef it. */
661#define PROVISIONING_API_H_
662#include <simplelink/user.h>
663#undef PROVISIONING_API_H_
664#undef SL_INC_STD_BSD_API_NAMING
665
666#include <simplelink/include/simplelink.h>
667#include <simplelink/include/netapp.h>
668#endif /* CS_PLATFORM == CS_P_CC3220 */
669
670/* Now define only the subset of the BSD API that we use.
671 * Notably, close(), read() and write() are not defined. */
672#define AF_INET SL_AF_INET
673
674#define socklen_t SlSocklen_t
675#define sockaddr SlSockAddr_t
676#define sockaddr_in SlSockAddrIn_t
677#define in_addr SlInAddr_t
678
679#define SOCK_STREAM SL_SOCK_STREAM
680#define SOCK_DGRAM SL_SOCK_DGRAM
681
682#define htonl sl_Htonl
683#define ntohl sl_Ntohl
684#define htons sl_Htons
685#define ntohs sl_Ntohs
686
687#ifndef EACCES
688#define EACCES SL_EACCES
689#endif
690#ifndef EAFNOSUPPORT
691#define EAFNOSUPPORT SL_EAFNOSUPPORT
692#endif
693#ifndef EAGAIN
694#define EAGAIN SL_EAGAIN
695#endif
696#ifndef EBADF
697#define EBADF SL_EBADF
698#endif
699#ifndef EINVAL
700#define EINVAL SL_EINVAL
701#endif
702#ifndef ENOMEM
703#define ENOMEM SL_ENOMEM
704#endif
705#ifndef EWOULDBLOCK
706#define EWOULDBLOCK SL_EWOULDBLOCK
707#endif
708
709#define SOMAXCONN 8
710
711#ifdef __cplusplus
712extern "C" {
713#endif
714
715const char *inet_ntop(int af, const void *src, char *dst, socklen_t size);
716char *inet_ntoa(struct in_addr in);
717int inet_pton(int af, const char *src, void *dst);
718
719struct mg_mgr;
720struct mg_connection;
721
722typedef void (*mg_init_cb)(struct mg_mgr *mgr);
723bool mg_start_task(int priority, int stack_size, mg_init_cb mg_init);
724
725void mg_run_in_task(void (*cb)(struct mg_mgr *mgr, void *arg), void *cb_arg);
726
727int sl_fs_init(void);
728
729void sl_restart_cb(struct mg_mgr *mgr);
730
731int sl_set_ssl_opts(struct mg_connection *nc);
732
733#ifdef __cplusplus
734}
735#endif
736
737#endif /* !defined(__SIMPLELINK_H__) */
738
739/* Compatibility with older versions of SimpleLink */
740#if SL_MAJOR_VERSION_NUM < 2
741
742#define SL_ERROR_BSD_EAGAIN SL_EAGAIN
743#define SL_ERROR_BSD_EALREADY SL_EALREADY
744#define SL_ERROR_BSD_ENOPROTOOPT SL_ENOPROTOOPT
745#define SL_ERROR_BSD_ESECDATEERROR SL_ESECDATEERROR
746#define SL_ERROR_BSD_ESECSNOVERIFY SL_ESECSNOVERIFY
747#define SL_ERROR_FS_FAILED_TO_ALLOCATE_MEM SL_FS_ERR_FAILED_TO_ALLOCATE_MEM
748#define SL_ERROR_FS_FILE_HAS_NOT_BEEN_CLOSE_CORRECTLY \
749 SL_FS_FILE_HAS_NOT_BEEN_CLOSE_CORRECTLY
750#define SL_ERROR_FS_FILE_NAME_EXIST SL_FS_FILE_NAME_EXIST
751#define SL_ERROR_FS_FILE_NOT_EXISTS SL_FS_ERR_FILE_NOT_EXISTS
752#define SL_ERROR_FS_NO_AVAILABLE_NV_INDEX SL_FS_ERR_NO_AVAILABLE_NV_INDEX
753#define SL_ERROR_FS_NOT_ENOUGH_STORAGE_SPACE SL_FS_ERR_NO_AVAILABLE_BLOCKS
754#define SL_ERROR_FS_NOT_SUPPORTED SL_FS_ERR_NOT_SUPPORTED
755#define SL_ERROR_FS_WRONG_FILE_NAME SL_FS_WRONG_FILE_NAME
756#define SL_ERROR_FS_INVALID_HANDLE SL_FS_ERR_INVALID_HANDLE
757#define SL_NETCFG_MAC_ADDRESS_GET SL_MAC_ADDRESS_GET
758#define SL_SOCKET_FD_ZERO SL_FD_ZERO
759#define SL_SOCKET_FD_SET SL_FD_SET
760#define SL_SOCKET_FD_ISSET SL_FD_ISSET
761#define SL_SO_SECURE_DOMAIN_NAME_VERIFICATION SO_SECURE_DOMAIN_NAME_VERIFICATION
762
763#define SL_FS_READ FS_MODE_OPEN_READ
764#define SL_FS_WRITE FS_MODE_OPEN_WRITE
765
766#define SL_FI_FILE_SIZE(fi) ((fi).FileLen)
767#define SL_FI_FILE_MAX_SIZE(fi) ((fi).AllocatedLen)
768
769#define SlDeviceVersion_t SlVersionFull
770#define sl_DeviceGet sl_DevGet
771#define SL_DEVICE_GENERAL SL_DEVICE_GENERAL_CONFIGURATION
772#define SL_LEN_TYPE _u8
773#define SL_OPT_TYPE _u8
774
775#else /* SL_MAJOR_VERSION_NUM >= 2 */
776
777#define FS_MODE_OPEN_CREATE(max_size, flag) \
778 (SL_FS_CREATE | SL_FS_CREATE_MAX_SIZE(max_size))
779#define SL_FI_FILE_SIZE(fi) ((fi).Len)
780#define SL_FI_FILE_MAX_SIZE(fi) ((fi).MaxSize)
781
782#define SL_LEN_TYPE _u16
783#define SL_OPT_TYPE _u16
784
785#endif /* SL_MAJOR_VERSION_NUM < 2 */
786
787int slfs_open(const unsigned char *fname, uint32_t flags);
788
789#endif /* MG_NET_IF == MG_NET_IF_SIMPLELINK */
790
791#endif /* CS_COMMON_PLATFORMS_SIMPLELINK_CS_SIMPLELINK_H_ */
792#ifdef V7_MODULE_LINES
793#line 1 "common/platforms/platform_cc3200.h"
794#endif
795/*
796 * Copyright (c) 2014-2016 Cesanta Software Limited
797 * All rights reserved
798 */
799
800#ifndef CS_COMMON_PLATFORMS_PLATFORM_CC3200_H_
801#define CS_COMMON_PLATFORMS_PLATFORM_CC3200_H_
802#if CS_PLATFORM == CS_P_CC3200
803
804#include <assert.h>
805#include <ctype.h>
806#include <errno.h>
807#include <inttypes.h>
808#include <stdint.h>
809#include <string.h>
810#include <time.h>
811
812#ifndef __TI_COMPILER_VERSION__
813#include <fcntl.h>
814#include <sys/time.h>
815#endif
816
817#define MG_NET_IF MG_NET_IF_SIMPLELINK
818#define MG_SSL_IF MG_SSL_IF_SIMPLELINK
819
820/* Only SPIFFS supports directories, SLFS does not. */
821#if defined(CC3200_FS_SPIFFS) && !defined(MG_ENABLE_DIRECTORY_LISTING)
822#define MG_ENABLE_DIRECTORY_LISTING 1
823#endif
824
825/* Amalgamated: #include "common/platforms/simplelink/cs_simplelink.h" */
826
827typedef int sock_t;
828#define INVALID_SOCKET (-1)
829#define SIZE_T_FMT "u"
830typedef struct stat cs_stat_t;
831#define DIRSEP '/'
832#define to64(x) strtoll(x, NULL, 10)
833#define INT64_FMT PRId64
834#define INT64_X_FMT PRIx64
835#define __cdecl
836
837#define fileno(x) -1
838
839/* Some functions we implement for Mongoose. */
840
841#ifdef __cplusplus
842extern "C" {
843#endif
844
845#ifdef __TI_COMPILER_VERSION__
846struct SlTimeval_t;
847#define timeval SlTimeval_t
848int gettimeofday(struct timeval *t, void *tz);
849int settimeofday(const struct timeval *tv, const void *tz);
850
851int asprintf(char **strp, const char *fmt, ...);
852
853#endif
854
855/* TI's libc does not have stat & friends, add them. */
856#ifdef __TI_COMPILER_VERSION__
857
858#include <file.h>
859
860typedef unsigned int mode_t;
861typedef size_t _off_t;
862typedef long ssize_t;
863
864struct stat {
865 int st_ino;
866 mode_t st_mode;
867 int st_nlink;
868 time_t st_mtime;
869 off_t st_size;
870};
871
872int _stat(const char *pathname, struct stat *st);
873int stat(const char *pathname, struct stat *st);
874
875#define __S_IFMT 0170000
876
877#define __S_IFDIR 0040000
878#define __S_IFCHR 0020000
879#define __S_IFREG 0100000
880
881#define __S_ISTYPE(mode, mask) (((mode) &__S_IFMT) == (mask))
882
883#define S_IFDIR __S_IFDIR
884#define S_IFCHR __S_IFCHR
885#define S_IFREG __S_IFREG
886#define S_ISDIR(mode) __S_ISTYPE((mode), __S_IFDIR)
887#define S_ISREG(mode) __S_ISTYPE((mode), __S_IFREG)
888
889/* 5.x series compilers don't have va_copy, 16.x do. */
890#if __TI_COMPILER_VERSION__ < 16000000
891#define va_copy(apc, ap) ((apc) = (ap))
892#endif
893
894#endif /* __TI_COMPILER_VERSION__ */
895
896#ifdef CC3200_FS_SLFS
897#define MG_FS_SLFS
898#endif
899
900#if (defined(CC3200_FS_SPIFFS) || defined(CC3200_FS_SLFS)) && \
901 !defined(MG_ENABLE_FILESYSTEM)
902#define MG_ENABLE_FILESYSTEM 1
903#define CS_DEFINE_DIRENT
904#endif
905
906#ifndef CS_ENABLE_STDIO
907#define CS_ENABLE_STDIO 1
908#endif
909
910#ifdef __cplusplus
911}
912#endif
913
914#endif /* CS_PLATFORM == CS_P_CC3200 */
915#endif /* CS_COMMON_PLATFORMS_PLATFORM_CC3200_H_ */
916#ifdef V7_MODULE_LINES
917#line 1 "common/platforms/platform_cc3220.h"
918#endif
919/*
920 * Copyright (c) 2014-2016 Cesanta Software Limited
921 * All rights reserved
922 */
923
924#ifndef CS_COMMON_PLATFORMS_PLATFORM_CC3220_H_
925#define CS_COMMON_PLATFORMS_PLATFORM_CC3220_H_
926#if CS_PLATFORM == CS_P_CC3220
927
928#include <assert.h>
929#include <ctype.h>
930#include <errno.h>
931#include <inttypes.h>
932#include <stdint.h>
933#include <string.h>
934#include <time.h>
935
936#ifndef __TI_COMPILER_VERSION__
937#include <fcntl.h>
938#include <sys/time.h>
939#endif
940
941#define MG_NET_IF MG_NET_IF_SIMPLELINK
942#define MG_SSL_IF MG_SSL_IF_SIMPLELINK
943
944/* Only SPIFFS supports directories, SLFS does not. */
945#if defined(CC3220_FS_SPIFFS) && !defined(MG_ENABLE_DIRECTORY_LISTING)
946#define MG_ENABLE_DIRECTORY_LISTING 1
947#endif
948
949/* Amalgamated: #include "common/platforms/simplelink/cs_simplelink.h" */
950
951typedef int sock_t;
952#define INVALID_SOCKET (-1)
953#define SIZE_T_FMT "u"
954typedef struct stat cs_stat_t;
955#define DIRSEP '/'
956#define to64(x) strtoll(x, NULL, 10)
957#define INT64_FMT PRId64
958#define INT64_X_FMT PRIx64
959#define __cdecl
960
961#define fileno(x) -1
962
963/* Some functions we implement for Mongoose. */
964
965#ifdef __cplusplus
966extern "C" {
967#endif
968
969#ifdef __TI_COMPILER_VERSION__
970struct SlTimeval_t;
971#define timeval SlTimeval_t
972int gettimeofday(struct timeval *t, void *tz);
973int settimeofday(const struct timeval *tv, const void *tz);
974
975int asprintf(char **strp, const char *fmt, ...);
976
977#endif
978
979/* TI's libc does not have stat & friends, add them. */
980#ifdef __TI_COMPILER_VERSION__
981
982#include <file.h>
983
984typedef unsigned int mode_t;
985typedef size_t _off_t;
986typedef long ssize_t;
987
988struct stat {
989 int st_ino;
990 mode_t st_mode;
991 int st_nlink;
992 time_t st_mtime;
993 off_t st_size;
994};
995
996int _stat(const char *pathname, struct stat *st);
997int stat(const char *pathname, struct stat *st);
998
999#define __S_IFMT 0170000
1000
1001#define __S_IFDIR 0040000
1002#define __S_IFCHR 0020000
1003#define __S_IFREG 0100000
1004
1005#define __S_ISTYPE(mode, mask) (((mode) &__S_IFMT) == (mask))
1006
1007#define S_IFDIR __S_IFDIR
1008#define S_IFCHR __S_IFCHR
1009#define S_IFREG __S_IFREG
1010#define S_ISDIR(mode) __S_ISTYPE((mode), __S_IFDIR)
1011#define S_ISREG(mode) __S_ISTYPE((mode), __S_IFREG)
1012
1013#endif /* __TI_COMPILER_VERSION__ */
1014
1015#ifndef CS_ENABLE_STDIO
1016#define CS_ENABLE_STDIO 1
1017#endif
1018
1019#ifdef __cplusplus
1020}
1021#endif
1022
1023#endif /* CS_PLATFORM == CS_P_CC3220 */
1024#endif /* CS_COMMON_PLATFORMS_PLATFORM_CC3200_H_ */
1025#ifdef V7_MODULE_LINES
1026#line 1 "common/platforms/platform_mbed.h"
1027#endif
1028/*
1029 * Copyright (c) 2014-2016 Cesanta Software Limited
1030 * All rights reserved
1031 */
1032
1033#ifndef CS_COMMON_PLATFORMS_PLATFORM_MBED_H_
1034#define CS_COMMON_PLATFORMS_PLATFORM_MBED_H_
1035#if CS_PLATFORM == CS_P_MBED
1036
1037/*
1038 * mbed.h contains C++ code (e.g. templates), thus, it should be processed
1039 * only if included directly to startup file (ex: main.cpp)
1040 */
1041#ifdef __cplusplus
1042/* Amalgamated: #include "mbed.h" */
1043#endif /* __cplusplus */
1044
1045#include <assert.h>
1046#include <ctype.h>
1047#include <errno.h>
1048#include <inttypes.h>
1049#include <stdint.h>
1050#include <string.h>
1051#include <time.h>
1052#include <sys/stat.h>
1053#include <sys/types.h>
1054#include <fcntl.h>
1055#include <stdio.h>
1056
1057typedef struct stat cs_stat_t;
1058#define DIRSEP '/'
1059
1060#ifndef CS_ENABLE_STDIO
1061#define CS_ENABLE_STDIO 1
1062#endif
1063
1064/*
1065 * mbed can be compiled with the ARM compiler which
1066 * just doesn't come with a gettimeofday shim
1067 * because it's a BSD API and ARM targets embedded
1068 * non-unix platforms.
1069 */
1070#if defined(__ARMCC_VERSION) || defined(__ICCARM__)
1071#define _TIMEVAL_DEFINED
1072#define gettimeofday _gettimeofday
1073
1074/* copied from GCC on ARM; for some reason useconds are signed */
1075typedef long suseconds_t; /* microseconds (signed) */
1076struct timeval {
1077 time_t tv_sec; /* seconds */
1078 suseconds_t tv_usec; /* and microseconds */
1079};
1080
1081#endif
1082
1083#if MG_NET_IF == MG_NET_IF_SIMPLELINK
1084
1085#define MG_SIMPLELINK_NO_OSI 1
1086
1087#include <simplelink.h>
1088
1089typedef int sock_t;
1090#define INVALID_SOCKET (-1)
1091
1092#define to64(x) strtoll(x, NULL, 10)
1093#define INT64_FMT PRId64
1094#define INT64_X_FMT PRIx64
1095#define SIZE_T_FMT "u"
1096
1097#define SOMAXCONN 8
1098
1099const char *inet_ntop(int af, const void *src, char *dst, socklen_t size);
1100char *inet_ntoa(struct in_addr in);
1101int inet_pton(int af, const char *src, void *dst);
1102int inet_aton(const char *cp, struct in_addr *inp);
1103in_addr_t inet_addr(const char *cp);
1104
1105#endif /* MG_NET_IF == MG_NET_IF_SIMPLELINK */
1106
1107#endif /* CS_PLATFORM == CS_P_MBED */
1108#endif /* CS_COMMON_PLATFORMS_PLATFORM_MBED_H_ */
1109#ifdef V7_MODULE_LINES
1110#line 1 "common/platforms/platform_nrf51.h"
1111#endif
1112/*
1113 * Copyright (c) 2014-2016 Cesanta Software Limited
1114 * All rights reserved
1115 */
1116#ifndef CS_COMMON_PLATFORMS_PLATFORM_NRF51_H_
1117#define CS_COMMON_PLATFORMS_PLATFORM_NRF51_H_
1118#if CS_PLATFORM == CS_P_NRF51
1119
1120#include <assert.h>
1121#include <ctype.h>
1122#include <inttypes.h>
1123#include <stdint.h>
1124#include <string.h>
1125#include <time.h>
1126
1127#define to64(x) strtoll(x, NULL, 10)
1128
1129#define MG_NET_IF MG_NET_IF_LWIP_LOW_LEVEL
1130#define MG_LWIP 1
1131#define MG_ENABLE_IPV6 1
1132
1133/*
1134 * For ARM C Compiler, make lwip to export `struct timeval`; for other
1135 * compilers, suppress it.
1136 */
1137#if !defined(__ARMCC_VERSION)
1138#define LWIP_TIMEVAL_PRIVATE 0
1139#else
1140struct timeval;
1141int gettimeofday(struct timeval *tp, void *tzp);
1142#endif
1143
1144#define INT64_FMT PRId64
1145#define SIZE_T_FMT "u"
1146
1147/*
1148 * ARM C Compiler doesn't have strdup, so we provide it
1149 */
1150#define CS_ENABLE_STRDUP defined(__ARMCC_VERSION)
1151
1152#endif /* CS_PLATFORM == CS_P_NRF51 */
1153#endif /* CS_COMMON_PLATFORMS_PLATFORM_NRF51_H_ */
1154#ifdef V7_MODULE_LINES
1155#line 1 "common/platforms/platform_nrf52.h"
1156#endif
1157/*
1158 * Copyright (c) 2014-2016 Cesanta Software Limited
1159 * All rights reserved
1160 */
1161#ifndef CS_COMMON_PLATFORMS_PLATFORM_NRF52_H_
1162#define CS_COMMON_PLATFORMS_PLATFORM_NRF52_H_
1163#if CS_PLATFORM == CS_P_NRF52
1164
1165#include <assert.h>
1166#include <ctype.h>
1167#include <errno.h>
1168#include <inttypes.h>
1169#include <stdint.h>
1170#include <string.h>
1171#include <time.h>
1172
1173#define to64(x) strtoll(x, NULL, 10)
1174
1175#define MG_NET_IF MG_NET_IF_LWIP_LOW_LEVEL
1176#define MG_LWIP 1
1177#define MG_ENABLE_IPV6 1
1178
1179#if !defined(ENOSPC)
1180#define ENOSPC 28 /* No space left on device */
1181#endif
1182
1183/*
1184 * For ARM C Compiler, make lwip to export `struct timeval`; for other
1185 * compilers, suppress it.
1186 */
1187#if !defined(__ARMCC_VERSION)
1188#define LWIP_TIMEVAL_PRIVATE 0
1189#endif
1190
1191#define INT64_FMT PRId64
1192#define SIZE_T_FMT "u"
1193
1194/*
1195 * ARM C Compiler doesn't have strdup, so we provide it
1196 */
1197#define CS_ENABLE_STRDUP defined(__ARMCC_VERSION)
1198
1199#endif /* CS_PLATFORM == CS_P_NRF52 */
1200#endif /* CS_COMMON_PLATFORMS_PLATFORM_NRF52_H_ */
1201#ifdef V7_MODULE_LINES
1202#line 1 "common/platforms/platform_wince.h"
1203#endif
1204#ifndef CS_COMMON_PLATFORMS_PLATFORM_WINCE_H_
1205#define CS_COMMON_PLATFORMS_PLATFORM_WINCE_H_
1206
1207#if CS_PLATFORM == CS_P_WINCE
1208
1209/*
1210 * MSVC++ 14.0 _MSC_VER == 1900 (Visual Studio 2015)
1211 * MSVC++ 12.0 _MSC_VER == 1800 (Visual Studio 2013)
1212 * MSVC++ 11.0 _MSC_VER == 1700 (Visual Studio 2012)
1213 * MSVC++ 10.0 _MSC_VER == 1600 (Visual Studio 2010)
1214 * MSVC++ 9.0 _MSC_VER == 1500 (Visual Studio 2008)
1215 * MSVC++ 8.0 _MSC_VER == 1400 (Visual Studio 2005)
1216 * MSVC++ 7.1 _MSC_VER == 1310 (Visual Studio 2003)
1217 * MSVC++ 7.0 _MSC_VER == 1300
1218 * MSVC++ 6.0 _MSC_VER == 1200
1219 * MSVC++ 5.0 _MSC_VER == 1100
1220 */
1221#pragma warning(disable : 4127) /* FD_SET() emits warning, disable it */
1222#pragma warning(disable : 4204) /* missing c99 support */
1223
1224#ifndef _WINSOCK_DEPRECATED_NO_WARNINGS
1225#define _WINSOCK_DEPRECATED_NO_WARNINGS 1
1226#endif
1227
1228#ifndef _CRT_SECURE_NO_WARNINGS
1229#define _CRT_SECURE_NO_WARNINGS
1230#endif
1231
1232#include <assert.h>
1233#include <limits.h>
1234#include <stddef.h>
1235#include <stdio.h>
1236#include <stdlib.h>
1237#include <time.h>
1238
1239#pragma comment(lib, "ws2.lib") /* Linking with WinCE winsock library */
1240
1241#include <winsock2.h>
1242#include <ws2tcpip.h>
1243#include <windows.h>
1244
1245#define strdup _strdup
1246
1247#ifndef EINPROGRESS
1248#define EINPROGRESS WSAEINPROGRESS
1249#endif
1250
1251#ifndef EWOULDBLOCK
1252#define EWOULDBLOCK WSAEWOULDBLOCK
1253#endif
1254
1255#ifndef EAGAIN
1256#define EAGAIN EWOULDBLOCK
1257#endif
1258
1259#ifndef __func__
1260#define STRX(x) #x
1261#define STR(x) STRX(x)
1262#define __func__ __FILE__ ":" STR(__LINE__)
1263#endif
1264
1265#define snprintf _snprintf
1266#define fileno _fileno
1267#define vsnprintf _vsnprintf
1268#define sleep(x) Sleep((x) *1000)
1269#define to64(x) _atoi64(x)
1270#define rmdir _rmdir
1271
1272#if defined(_MSC_VER) && _MSC_VER >= 1400
1273#define fseeko(x, y, z) _fseeki64((x), (y), (z))
1274#else
1275#define fseeko(x, y, z) fseek((x), (y), (z))
1276#endif
1277
1278typedef int socklen_t;
1279
1280#if _MSC_VER >= 1700
1281#include <stdint.h>
1282#else
1283typedef signed char int8_t;
1284typedef unsigned char uint8_t;
1285typedef int int32_t;
1286typedef unsigned int uint32_t;
1287typedef short int16_t;
1288typedef unsigned short uint16_t;
1289typedef __int64 int64_t;
1290typedef unsigned __int64 uint64_t;
1291#endif
1292
1293typedef SOCKET sock_t;
1294typedef uint32_t in_addr_t;
1295
1296#ifndef UINT16_MAX
1297#define UINT16_MAX 65535
1298#endif
1299
1300#ifndef UINT32_MAX
1301#define UINT32_MAX 4294967295
1302#endif
1303
1304#ifndef pid_t
1305#define pid_t HANDLE
1306#endif
1307
1308#define INT64_FMT "I64d"
1309#define INT64_X_FMT "I64x"
1310/* TODO(alashkin): check if this is correct */
1311#define SIZE_T_FMT "u"
1312
1313#define DIRSEP '\\'
1314#define CS_DEFINE_DIRENT
1315
1316#ifndef va_copy
1317#ifdef __va_copy
1318#define va_copy __va_copy
1319#else
1320#define va_copy(x, y) (x) = (y)
1321#endif
1322#endif
1323
1324#ifndef MG_MAX_HTTP_REQUEST_SIZE
1325#define MG_MAX_HTTP_REQUEST_SIZE 8192
1326#endif
1327
1328#ifndef MG_MAX_HTTP_SEND_MBUF
1329#define MG_MAX_HTTP_SEND_MBUF 4096
1330#endif
1331
1332#ifndef MG_MAX_HTTP_HEADERS
1333#define MG_MAX_HTTP_HEADERS 40
1334#endif
1335
1336#ifndef CS_ENABLE_STDIO
1337#define CS_ENABLE_STDIO 1
1338#endif
1339
1340#define abort() DebugBreak();
1341
1342#ifndef BUFSIZ
1343#define BUFSIZ 4096
1344#endif
1345/*
1346 * Explicitly disabling MG_ENABLE_THREADS for WinCE
1347 * because they are enabled for _WIN32 by default
1348 */
1349#ifndef MG_ENABLE_THREADS
1350#define MG_ENABLE_THREADS 0
1351#endif
1352
1353#ifndef MG_ENABLE_FILESYSTEM
1354#define MG_ENABLE_FILESYSTEM 1
1355#endif
1356
1357#ifndef MG_NET_IF
1358#define MG_NET_IF MG_NET_IF_SOCKET
1359#endif
1360
1361typedef struct _stati64 {
1362 uint32_t st_mtime;
1363 uint32_t st_size;
1364 uint32_t st_mode;
1365} cs_stat_t;
1366
1367/*
1368 * WinCE 6.0 has a lot of useful definitions in ATL (not windows.h) headers
1369 * use #ifdefs to avoid conflicts
1370 */
1371
1372#ifndef ENOENT
1373#define ENOENT ERROR_PATH_NOT_FOUND
1374#endif
1375
1376#ifndef EACCES
1377#define EACCES ERROR_ACCESS_DENIED
1378#endif
1379
1380#ifndef ENOMEM
1381#define ENOMEM ERROR_NOT_ENOUGH_MEMORY
1382#endif
1383
1384#ifndef _UINTPTR_T_DEFINED
1385typedef unsigned int *uintptr_t;
1386#endif
1387
1388#define _S_IFREG 2
1389#define _S_IFDIR 4
1390
1391#ifndef S_ISDIR
1392#define S_ISDIR(x) (((x) &_S_IFDIR) != 0)
1393#endif
1394
1395#ifndef S_ISREG
1396#define S_ISREG(x) (((x) &_S_IFREG) != 0)
1397#endif
1398
1399int open(const char *filename, int oflag, int pmode);
1400int _wstati64(const wchar_t *path, cs_stat_t *st);
1401const char *strerror();
1402
1403#endif /* CS_PLATFORM == CS_P_WINCE */
1404#endif /* CS_COMMON_PLATFORMS_PLATFORM_WINCE_H_ */
1405#ifdef V7_MODULE_LINES
1406#line 1 "common/platforms/platform_nxp_lpc.h"
1407#endif
1408/*
1409 * Copyright (c) 2014-2016 Cesanta Software Limited
1410 * All rights reserved
1411 */
1412
1413#ifndef CS_COMMON_PLATFORMS_PLATFORM_NXP_LPC_H_
1414#define CS_COMMON_PLATFORMS_PLATFORM_NXP_LPC_H_
1415
1416#if CS_PLATFORM == CS_P_NXP_LPC
1417
1418#include <ctype.h>
1419#include <stdint.h>
1420#include <string.h>
1421
1422#define SIZE_T_FMT "u"
1423typedef struct stat cs_stat_t;
1424#define INT64_FMT "lld"
1425#define INT64_X_FMT "llx"
1426#define __cdecl
1427
1428#define MG_LWIP 1
1429
1430#define MG_NET_IF MG_NET_IF_LWIP_LOW_LEVEL
1431
1432/*
1433 * LPCXpress comes with 3 C library implementations: Newlib, NewlibNano and
1434 *Redlib.
1435 * See https://community.nxp.com/message/630860 for more details.
1436 *
1437 * Redlib is the default and lacks certain things, so we provide them.
1438 */
1439#ifdef __REDLIB_INTERFACE_VERSION__
1440
1441/* Let LWIP define timeval for us. */
1442#define LWIP_TIMEVAL_PRIVATE 1
1443
1444#define va_copy(d, s) __builtin_va_copy(d, s)
1445
1446#define CS_ENABLE_TO64 1
1447#define to64(x) cs_to64(x)
1448
1449#define CS_ENABLE_STRDUP 1
1450
1451#else
1452
1453#include <sys/time.h>
1454#define LWIP_TIMEVAL_PRIVATE 0
1455#define to64(x) strtoll(x, NULL, 10)
1456
1457#endif
1458
1459#endif /* CS_PLATFORM == CS_P_NXP_LPC */
1460#endif /* CS_COMMON_PLATFORMS_PLATFORM_NXP_LPC_H_ */
1461#ifdef V7_MODULE_LINES
1462#line 1 "common/platforms/platform_nxp_kinetis.h"
1463#endif
1464/*
1465 * Copyright (c) 2014-2016 Cesanta Software Limited
1466 * All rights reserved
1467 */
1468
1469#ifndef CS_COMMON_PLATFORMS_PLATFORM_NXP_KINETIS_H_
1470#define CS_COMMON_PLATFORMS_PLATFORM_NXP_KINETIS_H_
1471
1472#if CS_PLATFORM == CS_P_NXP_KINETIS
1473
1474#include <ctype.h>
1475#include <inttypes.h>
1476#include <string.h>
1477#include <sys/time.h>
1478
1479#define SIZE_T_FMT "u"
1480typedef struct stat cs_stat_t;
1481#define to64(x) strtoll(x, NULL, 10)
1482#define INT64_FMT "lld"
1483#define INT64_X_FMT "llx"
1484#define __cdecl
1485
1486#define MG_LWIP 1
1487
1488#define MG_NET_IF MG_NET_IF_LWIP_LOW_LEVEL
1489
1490/* struct timeval is defined in sys/time.h. */
1491#define LWIP_TIMEVAL_PRIVATE 0
1492
1493#endif /* CS_PLATFORM == CS_P_NXP_KINETIS */
1494#endif /* CS_COMMON_PLATFORMS_PLATFORM_NXP_KINETIS_H_ */
1495#ifdef V7_MODULE_LINES
1496#line 1 "common/platforms/platform_pic32.h"
1497#endif
1498/*
1499 * Copyright (c) 2014-2016 Cesanta Software Limited
1500 * All rights reserved
1501 */
1502
1503#ifndef CS_COMMON_PLATFORMS_PLATFORM_PIC32_H_
1504#define CS_COMMON_PLATFORMS_PLATFORM_PIC32_H_
1505
1506#if CS_PLATFORM == CS_P_PIC32
1507
1508#define MG_NET_IF MG_NET_IF_PIC32
1509
1510#include <stdint.h>
1511#include <time.h>
1512#include <ctype.h>
1513#include <stdlib.h>
1514
1515#include <system_config.h>
1516#include <system_definitions.h>
1517
1518#include <sys/types.h>
1519
1520typedef TCP_SOCKET sock_t;
1521#define to64(x) strtoll(x, NULL, 10)
1522
1523#define SIZE_T_FMT "lu"
1524#define INT64_FMT "lld"
1525
1526#ifndef CS_ENABLE_STDIO
1527#define CS_ENABLE_STDIO 1
1528#endif
1529
1530char *inet_ntoa(struct in_addr in);
1531
1532#endif /* CS_PLATFORM == CS_P_PIC32 */
1533
1534#endif /* CS_COMMON_PLATFORMS_PLATFORM_PIC32_H_ */
1535#ifdef V7_MODULE_LINES
1536#line 1 "common/platforms/platform_stm32.h"
1537#endif
1538/*
1539 * Copyright (c) 2014-2016 Cesanta Software Limited
1540 * All rights reserved
1541 */
1542
1543#ifndef CS_COMMON_PLATFORMS_PLATFORM_STM32_H_
1544#define CS_COMMON_PLATFORMS_PLATFORM_STM32_H_
1545#if CS_PLATFORM == CS_P_STM32
1546
1547#include <sys/types.h>
1548#include <sys/stat.h>
1549#include <stdint.h>
1550#include <inttypes.h>
1551#include <stdio.h>
1552#include <ctype.h>
1553#include <errno.h>
1554#include <memory.h>
1555#include <fcntl.h>
1556#include <stm32_sdk_hal.h>
1557
1558#define to64(x) strtoll(x, NULL, 10)
1559#define INT64_FMT PRId64
1560#define SIZE_T_FMT "u"
1561typedef struct stat cs_stat_t;
1562#define DIRSEP '/'
1563
1564#ifndef CS_ENABLE_STDIO
1565#define CS_ENABLE_STDIO 1
1566#endif
1567
1568#ifndef MG_ENABLE_FILESYSTEM
1569#define MG_ENABLE_FILESYSTEM 1
1570#endif
1571
1572#define CS_DEFINE_DIRENT
1573
1574#endif /* CS_PLATFORM == CS_P_STM32 */
1575#endif /* CS_COMMON_PLATFORMS_PLATFORM_STM32_H_ */
1576#ifdef V7_MODULE_LINES
1577#line 1 "common/mbuf.h"
1578#endif
1579/*
1580 * Copyright (c) 2015 Cesanta Software Limited
1581 * All rights reserved
1582 */
1583
1584/*
1585 * === Memory Buffers
1586 *
1587 * Mbufs are mutable/growing memory buffers, like C++ strings.
1588 * Mbuf can append data to the end of a buffer or insert data into arbitrary
1589 * position in the middle of a buffer. The buffer grows automatically when
1590 * needed.
1591 */
1592
1593#ifndef CS_COMMON_MBUF_H_
1594#define CS_COMMON_MBUF_H_
1595
1596#include <stdlib.h>
1597/* Amalgamated: #include "common/platform.h" */
1598
1599#if defined(__cplusplus)
1600extern "C" {
1601#endif
1602
1603#ifndef MBUF_SIZE_MULTIPLIER
1604#define MBUF_SIZE_MULTIPLIER 1.5
1605#endif
1606
1607/* Memory buffer descriptor */
1608struct mbuf {
1609 char *buf; /* Buffer pointer */
1610 size_t len; /* Data length. Data is located between offset 0 and len. */
1611 size_t size; /* Buffer size allocated by realloc(1). Must be >= len */
1612};
1613
1614/*
1615 * Initialises an Mbuf.
1616 * `initial_capacity` specifies the initial capacity of the mbuf.
1617 */
1618void mbuf_init(struct mbuf *, size_t initial_capacity);
1619
1620/* Frees the space allocated for the mbuffer and resets the mbuf structure. */
1621void mbuf_free(struct mbuf *);
1622
1623/*
1624 * Appends data to the Mbuf.
1625 *
1626 * Returns the number of bytes appended or 0 if out of memory.
1627 */
1628size_t mbuf_append(struct mbuf *, const void *data, size_t data_size);
1629
1630/*
1631 * Inserts data at a specified offset in the Mbuf.
1632 *
1633 * Existing data will be shifted forwards and the buffer will
1634 * be grown if necessary.
1635 * Returns the number of bytes inserted.
1636 */
1637size_t mbuf_insert(struct mbuf *, size_t, const void *, size_t);
1638
1639/* Removes `data_size` bytes from the beginning of the buffer. */
1640void mbuf_remove(struct mbuf *, size_t data_size);
1641
1642/*
1643 * Resizes an Mbuf.
1644 *
1645 * If `new_size` is smaller than buffer's `len`, the
1646 * resize is not performed.
1647 */
1648void mbuf_resize(struct mbuf *, size_t new_size);
1649
1650/* Shrinks an Mbuf by resizing its `size` to `len`. */
1651void mbuf_trim(struct mbuf *);
1652
1653#if defined(__cplusplus)
1654}
1655#endif /* __cplusplus */
1656
1657#endif /* CS_COMMON_MBUF_H_ */
1658#ifdef V7_MODULE_LINES
1659#line 1 "common/mg_mem.h"
1660#endif
1661/*
1662 * Copyright (c) 2014-2016 Cesanta Software Limited
1663 * All rights reserved
1664 */
1665
1666#ifndef CS_COMMON_MG_MEM_H_
1667#define CS_COMMON_MG_MEM_H_
1668
1669#ifdef __cplusplus
1670extern "C" {
1671#endif
1672
1673#ifndef MG_MALLOC
1674#define MG_MALLOC malloc
1675#endif
1676
1677#ifndef MG_CALLOC
1678#define MG_CALLOC calloc
1679#endif
1680
1681#ifndef MG_REALLOC
1682#define MG_REALLOC realloc
1683#endif
1684
1685#ifndef MG_FREE
1686#define MG_FREE free
1687#endif
1688
1689#ifdef __cplusplus
1690}
1691#endif
1692
1693#endif /* CS_COMMON_MG_MEM_H_ */
1694#ifdef V7_MODULE_LINES
1695#line 1 "common/mg_str.h"
1696#endif
1697/*
1698 * Copyright (c) 2014-2016 Cesanta Software Limited
1699 * All rights reserved
1700 */
1701
1702#ifndef CS_COMMON_MG_STR_H_
1703#define CS_COMMON_MG_STR_H_
1704
1705#include <stddef.h>
1706
1707/* Amalgamated: #include "common/platform.h" */
1708
1709#ifdef __cplusplus
1710extern "C" {
1711#endif
1712
1713/* Describes chunk of memory */
1714struct mg_str {
1715 const char *p; /* Memory chunk pointer */
1716 size_t len; /* Memory chunk length */
1717};
1718
1719/*
1720 * Helper functions for creating mg_str struct from plain C string.
1721 * `NULL` is allowed and becomes `{NULL, 0}`.
1722 */
1723struct mg_str mg_mk_str(const char *s);
1724struct mg_str mg_mk_str_n(const char *s, size_t len);
1725
1726/* Macro for initializing mg_str. */
1727#define MG_MK_STR(str_literal) \
1728 { str_literal, sizeof(str_literal) - 1 }
1729#define MG_NULL_STR \
1730 { NULL, 0 }
1731
1732/*
1733 * Cross-platform version of `strcmp()` where where first string is
1734 * specified by `struct mg_str`.
1735 */
1736int mg_vcmp(const struct mg_str *str2, const char *str1);
1737
1738/*
1739 * Cross-platform version of `strncasecmp()` where first string is
1740 * specified by `struct mg_str`.
1741 */
1742int mg_vcasecmp(const struct mg_str *str2, const char *str1);
1743
1744/* Creates a copy of s (heap-allocated). */
1745struct mg_str mg_strdup(const struct mg_str s);
1746
1747/*
1748 * Creates a copy of s (heap-allocated).
1749 * Resulting string is NUL-terminated (but NUL is not included in len).
1750 */
1751struct mg_str mg_strdup_nul(const struct mg_str s);
1752
1753/*
1754 * Locates character in a string.
1755 */
1756const char *mg_strchr(const struct mg_str s, int c);
1757
1758int mg_strcmp(const struct mg_str str1, const struct mg_str str2);
1759int mg_strncmp(const struct mg_str str1, const struct mg_str str2, size_t n);
1760
1761const char *mg_strstr(const struct mg_str haystack, const struct mg_str needle);
1762
1763#ifdef __cplusplus
1764}
1765#endif
1766
1767#endif /* CS_COMMON_MG_STR_H_ */
1768#ifdef V7_MODULE_LINES
1769#line 1 "common/str_util.h"
1770#endif
1771/*
1772 * Copyright (c) 2015 Cesanta Software Limited
1773 * All rights reserved
1774 */
1775
1776#ifndef CS_COMMON_STR_UTIL_H_
1777#define CS_COMMON_STR_UTIL_H_
1778
1779#include <stdarg.h>
1780#include <stdlib.h>
1781
1782/* Amalgamated: #include "common/platform.h" */
1783/* Amalgamated: #include "common/mg_str.h" */
1784
1785#ifndef CS_ENABLE_STRDUP
1786#define CS_ENABLE_STRDUP 0
1787#endif
1788
1789#ifndef CS_ENABLE_TO64
1790#define CS_ENABLE_TO64 0
1791#endif
1792
1793/*
1794 * Expands to a string representation of its argument: e.g.
1795 * `CS_STRINGIFY_LIT(5) expands to "5"`
1796 */
1797#define CS_STRINGIFY_LIT(x) #x
1798
1799/*
1800 * Expands to a string representation of its argument, which is allowed
1801 * to be a macro: e.g.
1802 *
1803 * #define FOO 123
1804 * CS_STRINGIFY_MACRO(FOO)
1805 *
1806 * expands to 123.
1807 */
1808#define CS_STRINGIFY_MACRO(x) CS_STRINGIFY_LIT(x)
1809
1810#ifdef __cplusplus
1811extern "C" {
1812#endif
1813
1814size_t c_strnlen(const char *s, size_t maxlen);
1815int c_snprintf(char *buf, size_t buf_size, const char *format, ...);
1816int c_vsnprintf(char *buf, size_t buf_size, const char *format, va_list ap);
1817/*
1818 * Find the first occurrence of find in s, where the search is limited to the
1819 * first slen characters of s.
1820 */
1821const char *c_strnstr(const char *s, const char *find, size_t slen);
1822
1823/*
1824 * Stringify binary data. Output buffer size must be 2 * size_of_input + 1
1825 * because each byte of input takes 2 bytes in string representation
1826 * plus 1 byte for the terminating \0 character.
1827 */
1828void cs_to_hex(char *to, const unsigned char *p, size_t len);
1829
1830/*
1831 * Convert stringified binary data back to binary.
1832 * Does the reverse of `cs_to_hex()`.
1833 */
1834void cs_from_hex(char *to, const char *p, size_t len);
1835
1836#if CS_ENABLE_STRDUP
1837char *strdup(const char *src);
1838#endif
1839
1840#if CS_ENABLE_TO64
1841#include <stdint.h>
1842/*
1843 * Simple string -> int64 conversion routine.
1844 */
1845int64_t cs_to64(const char *s);
1846#endif
1847
1848/*
1849 * Cross-platform version of `strncasecmp()`.
1850 */
1851int mg_ncasecmp(const char *s1, const char *s2, size_t len);
1852
1853/*
1854 * Cross-platform version of `strcasecmp()`.
1855 */
1856int mg_casecmp(const char *s1, const char *s2);
1857
1858/*
1859 * Prints message to the buffer. If the buffer is large enough to hold the
1860 * message, it returns buffer. If buffer is to small, it allocates a large
1861 * enough buffer on heap and returns allocated buffer.
1862 * This is a supposed use case:
1863 *
1864 * char buf[5], *p = buf;
1865 * mg_avprintf(&p, sizeof(buf), "%s", "hi there");
1866 * use_p_somehow(p);
1867 * if (p != buf) {
1868 * free(p);
1869 * }
1870 *
1871 * The purpose of this is to avoid malloc-ing if generated strings are small.
1872 */
1873int mg_asprintf(char **buf, size_t size, const char *fmt, ...);
1874
1875/* Same as mg_asprintf, but takes varargs list. */
1876int mg_avprintf(char **buf, size_t size, const char *fmt, va_list ap);
1877
1878/*
1879 * A helper function for traversing a comma separated list of values.
1880 * It returns a list pointer shifted to the next value or NULL if the end
1881 * of the list found.
1882 * The value is stored in a val vector. If the value has a form "x=y", then
1883 * eq_val vector is initialised to point to the "y" part, and val vector length
1884 * is adjusted to point only to "x".
1885 * If the list is just a comma separated list of entries, like "aa,bb,cc" then
1886 * `eq_val` will contain zero-length string.
1887 *
1888 * The purpose of this function is to parse comma separated string without
1889 * any copying/memory allocation.
1890 */
1891const char *mg_next_comma_list_entry(const char *list, struct mg_str *val,
1892 struct mg_str *eq_val);
1893struct mg_str mg_next_comma_list_entry_n(struct mg_str list, struct mg_str *val,
1894 struct mg_str *eq_val);
1895
1896/*
1897 * Matches 0-terminated string (mg_match_prefix) or string with given length
1898 * mg_match_prefix_n against a glob pattern.
1899 *
1900 * Match is case-insensitive. Returns number of bytes matched, or -1 if no
1901 * match.
1902 */
1903int mg_match_prefix(const char *pattern, int pattern_len, const char *str);
1904int mg_match_prefix_n(const struct mg_str pattern, const struct mg_str str);
1905
1906#ifdef __cplusplus
1907}
1908#endif
1909
1910#endif /* CS_COMMON_STR_UTIL_H_ */
1911#ifdef V7_MODULE_LINES
1912#line 1 "common/utf.h"
1913#endif
1914/*
1915 * Copyright (c) 2014 Cesanta Software Limited
1916 * All rights reserved
1917 */
1918
1919#ifndef CS_COMMON_UTF_H_
1920#define CS_COMMON_UTF_H_
1921
1922#if defined(__cplusplus)
1923extern "C" {
1924#endif /* __cplusplus */
1925
1926typedef unsigned char uchar;
1927
1928typedef unsigned short Rune; /* 16 bits */
1929
1930#define nelem(a) (sizeof(a) / sizeof(a)[0])
1931
1932enum {
1933 UTFmax = 3, /* maximum bytes per rune */
1934 Runesync = 0x80, /* cannot represent part of a UTF sequence (<) */
1935 Runeself = 0x80, /* rune and UTF sequences are the same (<) */
1936 Runeerror = 0xFFFD /* decoding error in UTF */
1937 /* Runemax = 0xFFFC */ /* maximum rune value */
1938};
1939
1940/* Edit .+1,/^$/ | cfn $PLAN9/src/lib9/utf/?*.c | grep -v static |grep -v __ */
1941int chartorune(Rune *rune, const char *str);
1942int fullrune(const char *str, int n);
1943int isdigitrune(Rune c);
1944int isnewline(Rune c);
1945int iswordchar(Rune c);
1946int isalpharune(Rune c);
1947int islowerrune(Rune c);
1948int isspacerune(Rune c);
1949int isupperrune(Rune c);
1950int runetochar(char *str, Rune *rune);
1951Rune tolowerrune(Rune c);
1952Rune toupperrune(Rune c);
1953int utfnlen(const char *s, long m);
1954const char *utfnshift(const char *s, long m);
1955
1956#if 0 /* Not implemented. */
1957int istitlerune(Rune c);
1958int runelen(Rune c);
1959int runenlen(Rune *r, int nrune);
1960Rune *runestrcat(Rune *s1, Rune *s2);
1961Rune *runestrchr(Rune *s, Rune c);
1962Rune *runestrcpy(Rune *s1, Rune *s2);
1963Rune *runestrdup(Rune *s);
1964Rune *runestrecpy(Rune *s1, Rune *es1, Rune *s2);
1965int runestrcmp(Rune *s1, Rune *s2);
1966long runestrlen(Rune *s);
1967Rune *runestrncat(Rune *s1, Rune *s2, long n);
1968int runestrncmp(Rune *s1, Rune *s2, long n);
1969Rune *runestrncpy(Rune *s1, Rune *s2, long n);
1970Rune *runestrrchr(Rune *s, Rune c);
1971Rune *runestrstr(Rune *s1, Rune *s2);
1972Rune totitlerune(Rune c);
1973char *utfecpy(char *to, char *e, char *from);
1974int utflen(char *s);
1975char *utfrrune(char *s, long c);
1976char *utfrune(char *s, long c);
1977char *utfutf(char *s1, char *s2);
1978#endif
1979
1980#if defined(__cplusplus)
1981}
1982#endif /* __cplusplus */
1983#endif /* CS_COMMON_UTF_H_ */
1984#ifdef V7_MODULE_LINES
1985#line 1 "common/base64.h"
1986#endif
1987/*
1988 * Copyright (c) 2014 Cesanta Software Limited
1989 * All rights reserved
1990 */
1991
1992#ifndef CS_COMMON_BASE64_H_
1993#define CS_COMMON_BASE64_H_
1994
1995#ifndef DISABLE_BASE64
1996#define DISABLE_BASE64 0
1997#endif
1998
1999#if !DISABLE_BASE64
2000
2001#include <stdio.h>
2002
2003#ifdef __cplusplus
2004extern "C" {
2005#endif
2006
2007typedef void (*cs_base64_putc_t)(char, void *);
2008
2009struct cs_base64_ctx {
2010 /* cannot call it putc because it's a macro on some environments */
2011 cs_base64_putc_t b64_putc;
2012 unsigned char chunk[3];
2013 int chunk_size;
2014 void *user_data;
2015};
2016
2017void cs_base64_init(struct cs_base64_ctx *ctx, cs_base64_putc_t putc,
2018 void *user_data);
2019void cs_base64_update(struct cs_base64_ctx *ctx, const char *str, size_t len);
2020void cs_base64_finish(struct cs_base64_ctx *ctx);
2021
2022void cs_base64_encode(const unsigned char *src, int src_len, char *dst);
2023void cs_fprint_base64(FILE *f, const unsigned char *src, int src_len);
2024int cs_base64_decode(const unsigned char *s, int len, char *dst, int *dec_len);
2025
2026#ifdef __cplusplus
2027}
2028#endif
2029
2030#endif /* DISABLE_BASE64 */
2031
2032#endif /* CS_COMMON_BASE64_H_ */
2033#ifdef V7_MODULE_LINES
2034#line 1 "common/cs_dbg.h"
2035#endif
2036/*
2037 * Copyright (c) 2014-2016 Cesanta Software Limited
2038 * All rights reserved
2039 */
2040
2041#ifndef CS_COMMON_CS_DBG_H_
2042#define CS_COMMON_CS_DBG_H_
2043
2044/* Amalgamated: #include "common/platform.h" */
2045
2046#if CS_ENABLE_STDIO
2047#include <stdio.h>
2048#endif
2049
2050#ifndef CS_ENABLE_DEBUG
2051#define CS_ENABLE_DEBUG 0
2052#endif
2053
2054#ifndef CS_LOG_ENABLE_TS_DIFF
2055#define CS_LOG_ENABLE_TS_DIFF 0
2056#endif
2057
2058#ifdef __cplusplus
2059extern "C" {
2060#endif /* __cplusplus */
2061
2062enum cs_log_level {
2063 LL_NONE = -1,
2064 LL_ERROR = 0,
2065 LL_WARN = 1,
2066 LL_INFO = 2,
2067 LL_DEBUG = 3,
2068 LL_VERBOSE_DEBUG = 4,
2069
2070 _LL_MIN = -2,
2071 _LL_MAX = 5,
2072};
2073
2074/* Set log level. */
2075void cs_log_set_level(enum cs_log_level level);
2076
2077/* Set log filter. NULL (a default) logs everything. */
2078void cs_log_set_filter(const char *source_file_name);
2079
2080int cs_log_print_prefix(enum cs_log_level level, const char *func,
2081 const char *filename);
2082
2083extern enum cs_log_level cs_log_threshold;
2084
2085#if CS_ENABLE_STDIO
2086
2087void cs_log_set_file(FILE *file);
2088void cs_log_printf(const char *fmt, ...)
2089#ifdef __GNUC__
2090 __attribute__((format(printf, 1, 2)))
2091#endif
2092 ;
2093
2094#define LOG(l, x) \
2095 do { \
2096 if (cs_log_print_prefix(l, __func__, __FILE__)) cs_log_printf x; \
2097 } while (0)
2098
2099#ifndef CS_NDEBUG
2100
2101#define DBG(x) LOG(LL_VERBOSE_DEBUG, x)
2102
2103#else /* NDEBUG */
2104
2105#define DBG(x)
2106
2107#endif
2108
2109#else /* CS_ENABLE_STDIO */
2110
2111#define LOG(l, x)
2112#define DBG(x)
2113
2114#endif
2115
2116#ifdef __cplusplus
2117}
2118#endif /* __cplusplus */
2119
2120#endif /* CS_COMMON_CS_DBG_H_ */
2121#ifdef V7_MODULE_LINES
2122#line 1 "common/cs_md5.h"
2123#endif
2124/*
2125 * Copyright (c) 2014 Cesanta Software Limited
2126 * All rights reserved
2127 */
2128
2129#ifndef CS_COMMON_MD5_H_
2130#define CS_COMMON_MD5_H_
2131
2132/* Amalgamated: #include "common/platform.h" */
2133
2134#ifndef CS_DISABLE_MD5
2135#define CS_DISABLE_MD5 0
2136#endif
2137
2138#ifdef __cplusplus
2139extern "C" {
2140#endif /* __cplusplus */
2141
2142typedef struct {
2143 uint32_t buf[4];
2144 uint32_t bits[2];
2145 unsigned char in[64];
2146} cs_md5_ctx;
2147
2148void cs_md5_init(cs_md5_ctx *c);
2149void cs_md5_update(cs_md5_ctx *c, const unsigned char *data, size_t len);
2150void cs_md5_final(unsigned char *md, cs_md5_ctx *c);
2151
2152#ifdef __cplusplus
2153}
2154#endif /* __cplusplus */
2155
2156#endif /* CS_COMMON_MD5_H_ */
2157#ifdef V7_MODULE_LINES
2158#line 1 "common/cs_endian.h"
2159#endif
2160/*
2161 * Copyright (c) 2014-2016 Cesanta Software Limited
2162 * All rights reserved
2163 */
2164
2165#ifndef CS_COMMON_CS_ENDIAN_H_
2166#define CS_COMMON_CS_ENDIAN_H_
2167
2168#ifdef __cplusplus
2169extern "C" {
2170#endif
2171
2172/*
2173 * clang with std=-c99 uses __LITTLE_ENDIAN, by default
2174 * while for ex, RTOS gcc - LITTLE_ENDIAN, by default
2175 * it depends on __USE_BSD, but let's have everything
2176 */
2177#if !defined(BYTE_ORDER) && defined(__BYTE_ORDER)
2178#define BYTE_ORDER __BYTE_ORDER
2179#ifndef LITTLE_ENDIAN
2180#define LITTLE_ENDIAN __LITTLE_ENDIAN
2181#endif /* LITTLE_ENDIAN */
2182#ifndef BIG_ENDIAN
2183#define BIG_ENDIAN __LITTLE_ENDIAN
2184#endif /* BIG_ENDIAN */
2185#endif /* BYTE_ORDER */
2186
2187#ifdef __cplusplus
2188}
2189#endif
2190
2191#endif /* CS_COMMON_CS_ENDIAN_H_ */
2192#ifdef V7_MODULE_LINES
2193#line 1 "common/cs_sha1.h"
2194#endif
2195/*
2196 * Copyright (c) 2014 Cesanta Software Limited
2197 * All rights reserved
2198 */
2199
2200#ifndef CS_COMMON_SHA1_H_
2201#define CS_COMMON_SHA1_H_
2202
2203#ifndef CS_DISABLE_SHA1
2204#define CS_DISABLE_SHA1 0
2205#endif
2206
2207#if !CS_DISABLE_SHA1
2208
2209/* Amalgamated: #include "common/platform.h" */
2210
2211#ifdef __cplusplus
2212extern "C" {
2213#endif /* __cplusplus */
2214
2215typedef struct {
2216 uint32_t state[5];
2217 uint32_t count[2];
2218 unsigned char buffer[64];
2219} cs_sha1_ctx;
2220
2221void cs_sha1_init(cs_sha1_ctx *);
2222void cs_sha1_update(cs_sha1_ctx *, const unsigned char *data, uint32_t len);
2223void cs_sha1_final(unsigned char digest[20], cs_sha1_ctx *);
2224void cs_hmac_sha1(const unsigned char *key, size_t key_len,
2225 const unsigned char *text, size_t text_len,
2226 unsigned char out[20]);
2227#ifdef __cplusplus
2228}
2229#endif /* __cplusplus */
2230
2231#endif /* CS_DISABLE_SHA1 */
2232
2233#endif /* CS_COMMON_SHA1_H_ */
2234#ifdef V7_MODULE_LINES
2235#line 1 "common/cs_dirent.h"
2236#endif
2237/*
2238 * Copyright (c) 2014-2016 Cesanta Software Limited
2239 * All rights reserved
2240 */
2241
2242#ifndef CS_COMMON_CS_DIRENT_H_
2243#define CS_COMMON_CS_DIRENT_H_
2244
2245#include <limits.h>
2246
2247/* Amalgamated: #include "common/platform.h" */
2248
2249#ifdef __cplusplus
2250extern "C" {
2251#endif /* __cplusplus */
2252
2253#ifdef CS_DEFINE_DIRENT
2254typedef struct { int dummy; } DIR;
2255
2256struct dirent {
2257 int d_ino;
2258#ifdef _WIN32
2259 char d_name[MAX_PATH];
2260#else
2261 /* TODO(rojer): Use PATH_MAX but make sure it's sane on every platform */
2262 char d_name[256];
2263#endif
2264};
2265
2266DIR *opendir(const char *dir_name);
2267int closedir(DIR *dir);
2268struct dirent *readdir(DIR *dir);
2269#endif /* CS_DEFINE_DIRENT */
2270
2271#ifdef __cplusplus
2272}
2273#endif /* __cplusplus */
2274
2275#endif /* CS_COMMON_CS_DIRENT_H_ */
2276#ifdef V7_MODULE_LINES
2277#line 1 "common/cs_file.h"
2278#endif
2279/*
2280 * Copyright (c) 2015 Cesanta Software Limited
2281 * All rights reserved
2282 */
2283
2284#ifndef CS_COMMON_CS_FILE_H_
2285#define CS_COMMON_CS_FILE_H_
2286
2287/* Amalgamated: #include "common/platform.h" */
2288
2289#ifdef __cplusplus
2290extern "C" {
2291#endif /* __cplusplus */
2292
2293/*
2294 * Read whole file `path` in memory. It is responsibility of the caller
2295 * to `free()` allocated memory. File content is guaranteed to be
2296 * '\0'-terminated. File size is returned in `size` variable, which does not
2297 * count terminating `\0`.
2298 * Return: allocated memory, or NULL on error.
2299 */
2300char *cs_read_file(const char *path, size_t *size);
2301
2302#ifdef CS_MMAP
2303char *cs_mmap_file(const char *path, size_t *size);
2304#endif
2305
2306#ifdef __cplusplus
2307}
2308#endif /* __cplusplus */
2309
2310#endif /* CS_COMMON_CS_FILE_H_ */
2311#ifdef V7_MODULE_LINES
2312#line 1 "common/coroutine.h"
2313#endif
2314/*
2315 * Copyright (c) 2015 Cesanta Software Limited
2316 * All rights reserved
2317 */
2318
2319/*
2320 * Module that provides generic macros and functions to implement "coroutines",
2321 * i.e. C code that uses `mbuf` as a stack for function calls.
2322 *
2323 * More info: see the design doc: https://goo.gl/kfcG61
2324 */
2325
2326#ifndef CS_COMMON_COROUTINE_H_
2327#define CS_COMMON_COROUTINE_H_
2328
2329/* Amalgamated: #include "common/mbuf.h" */
2330/* Amalgamated: #include "common/platform.h" */
2331
2332#ifdef __cplusplus
2333extern "C" {
2334#endif
2335
2336/* user-defined union, this module only operates on the pointer */
2337union user_arg_ret;
2338
2339/*
2340 * Type that represents size of local function variables. We assume we'll never
2341 * need more than 255 bytes of stack frame.
2342 */
2343typedef uint8_t cr_locals_size_t;
2344
2345/*
2346 * Descriptor of a single function; const array of such descriptors should
2347 * be given to `cr_context_init()`
2348 */
2349struct cr_func_desc {
2350 /*
2351 * Size of the function's data that should be stored on stack.
2352 *
2353 * NOTE: you should use `CR_LOCALS_SIZEOF(your_type)` instead of `sizeof()`,
2354 * since this value should be aligned by the word boundary, and
2355 * `CR_LOCALS_SIZEOF()` takes care of this.
2356 */
2357 cr_locals_size_t locals_size;
2358};
2359
2360enum cr_status {
2361 CR_RES__OK,
2362 CR_RES__OK_YIELDED,
2363
2364 CR_RES__ERR_STACK_OVERFLOW,
2365
2366 /* Underflow can only be caused by memory corruption or bug in CR */
2367 CR_RES__ERR_STACK_DATA_UNDERFLOW,
2368 /* Underflow can only be caused by memory corruption or bug in CR */
2369 CR_RES__ERR_STACK_CALL_UNDERFLOW,
2370
2371 CR_RES__ERR_UNCAUGHT_EXCEPTION,
2372};
2373
2374/* Context of the coroutine engine */
2375struct cr_ctx {
2376 /*
2377 * id of the next "function" to call. If no function is going to be called,
2378 * it's CR_FID__NONE.
2379 */
2380 uint8_t called_fid;
2381
2382 /*
2383 * when `called_fid` is not `CR_FID__NONE`, this field holds called
2384 * function's stack frame size
2385 */
2386 size_t call_locals_size;
2387
2388 /*
2389 * when `called_fid` is not `CR_FID__NONE`, this field holds called
2390 * function's arguments size
2391 */
2392 size_t call_arg_size;
2393
2394 /*
2395 * pointer to the current function's locals.
2396 * Needed to make `CR_CUR_LOCALS_PT()` fast.
2397 */
2398 uint8_t *p_cur_func_locals;
2399
2400 /* data stack */
2401 struct mbuf stack_data;
2402
2403 /* return stack */
2404 struct mbuf stack_ret;
2405
2406 /* index of the current fid + 1 in return stack */
2407 size_t cur_fid_idx;
2408
2409 /* pointer to the array of function descriptors */
2410 const struct cr_func_desc *p_func_descrs;
2411
2412 /* thrown exception. If nothing is currently thrown, it's `CR_EXC_ID__NONE` */
2413 uint8_t thrown_exc;
2414
2415 /* status: normally, it's `CR_RES__OK` */
2416 enum cr_status status;
2417
2418 /*
2419 * pointer to user-dependent union of arguments for all functions, as well as
2420 * return values, yielded and resumed values.
2421 */
2422 union user_arg_ret *p_arg_retval;
2423
2424 /* true if currently running function returns */
2425 unsigned need_return : 1;
2426
2427 /* true if currently running function yields */
2428 unsigned need_yield : 1;
2429
2430#if defined(CR_TRACK_MAX_STACK_LEN)
2431 size_t stack_data_max_len;
2432 size_t stack_ret_max_len;
2433#endif
2434};
2435
2436/*
2437 * User's enum with function ids should use items of this one like this:
2438 *
2439 * enum my_func_id {
2440 * my_func_none = CR_FID__NONE,
2441 *
2442 * my_foo = CR_FID__USER,
2443 * my_foo1,
2444 * my_foo2,
2445 *
2446 * my_bar,
2447 * my_bar1,
2448 * };
2449 *
2450 */
2451enum cr_fid {
2452 CR_FID__NONE,
2453 CR_FID__USER,
2454
2455 /* for internal usage only */
2456 CR_FID__TRY_MARKER = 0xff,
2457};
2458
2459/*
2460 * User's enum with exception ids should use items of this one like this:
2461 *
2462 * enum my_exc_id {
2463 * MY_EXC_ID__FIRST = CR_EXC_ID__USER,
2464 * MY_EXC_ID__SECOND,
2465 * MY_EXC_ID__THIRD,
2466 * };
2467 */
2468enum cr_exc_id {
2469 CR_EXC_ID__NONE,
2470 CR_EXC_ID__USER,
2471};
2472
2473/*
2474 * A type whose size is a special case for macros `CR_LOCALS_SIZEOF()` and
2475 * `CR_ARG_SIZEOF()` : it is assumed as zero size.
2476 *
2477 * This hackery is needed because empty structs (that would yield sizeof 0) are
2478 * illegal in plain C.
2479 */
2480typedef struct { uint8_t _dummy[((cr_locals_size_t) -1)]; } cr_zero_size_type_t;
2481
2482/*
2483 * To be used in dispatcher switch: depending on the "fid" (function id), we
2484 * jump to the appropriate label.
2485 */
2486#define CR_DEFINE_ENTRY_POINT(fid) \
2487 case fid: \
2488 goto fid
2489
2490/*
2491 * Returns lvalue: id of the currently active "function". It just takes the id
2492 * from the appropriate position of the "stack".
2493 *
2494 * Client code only needs it in dispatcher switch.
2495 */
2496#define CR_CURR_FUNC_C(p_ctx) \
2497 *(((cr_locals_size_t *) (p_ctx)->stack_ret.buf) + (p_ctx)->cur_fid_idx - 1)
2498
2499/*
2500 * Prepare context for calling first function.
2501 *
2502 * Should be used outside of the exec loop, right after initializing
2503 * context with `cr_context_init()`
2504 *
2505 * `call_fid`: id of the function to be called
2506 */
2507#define CR_FIRST_CALL_PREPARE_C(p_ctx, call_fid) \
2508 _CR_CALL_PREPARE(p_ctx, call_fid, CR_LOCALS_SIZEOF(call_fid##_locals_t), \
2509 CR_ARG_SIZEOF(call_fid##_arg_t), CR_FID__NONE)
2510
2511/*
2512 * Call "function" with id `call_fid`: uses `_CR_CALL_PREPARE()` to prepare
2513 * stuff, and then jumps to the `_cr_iter_begin`, which will perform all
2514 * necessary bookkeeping.
2515 *
2516 * Should be used from eval loop only.
2517 *
2518 * `local_ret_fid`: id of the label right after the function call (where
2519 * currently running function will be resumed later)
2520 */
2521#define CR_CALL_C(p_ctx, call_fid, local_ret_fid) \
2522 do { \
2523 _CR_CALL_PREPARE(p_ctx, call_fid, CR_LOCALS_SIZEOF(call_fid##_locals_t), \
2524 CR_ARG_SIZEOF(call_fid##_arg_t), local_ret_fid); \
2525 goto _cr_iter_begin; \
2526 local_ret_fid: \
2527 /* we'll get here when called function returns */ \
2528 ; \
2529 } while (0)
2530
2531/*
2532 * "Return" the value `retval` from the current "function" with id `cur_fid`.
2533 * You have to specify `cur_fid` since different functions may have different
2534 * return types.
2535 *
2536 * Should be used from eval loop only.
2537 */
2538#define CR_RETURN_C(p_ctx, cur_fid, retval) \
2539 do { \
2540 /* copy ret to arg_retval */ \
2541 CR_ARG_RET_PT_C(p_ctx)->ret.cur_fid = (retval); \
2542 /* set need_return flag */ \
2543 (p_ctx)->need_return = 1; \
2544 goto _cr_iter_begin; \
2545 } while (0)
2546
2547/*
2548 * Same as `CR_RETURN_C`, but without any return value
2549 */
2550#define CR_RETURN_VOID_C(p_ctx) \
2551 do { \
2552 /* set need_return flag */ \
2553 (p_ctx)->need_return = 1; \
2554 goto _cr_iter_begin; \
2555 } while (0)
2556
2557/*
2558 * Yield with the value `value`. It will be set just by the assigment operator
2559 * in the `yielded` field of the `union user_arg_ret`.
2560 *
2561 * `local_ret_fid`: id of the label right after the yielding (where currently
2562 * running function will be resumed later)
2563 *
2564 */
2565#define CR_YIELD_C(p_ctx, value, local_ret_fid) \
2566 do { \
2567 /* copy ret to arg_retval */ \
2568 CR_ARG_RET_PT_C(p_ctx)->yielded = (value); \
2569 /* set need_yield flag */ \
2570 (p_ctx)->need_yield = 1; \
2571 \
2572 /* adjust return func id */ \
2573 CR_CURR_FUNC_C(p_ctx) = (local_ret_fid); \
2574 \
2575 goto _cr_iter_begin; \
2576 local_ret_fid: \
2577 /* we'll get here when the machine will be resumed */ \
2578 ; \
2579 } while (0)
2580
2581/*
2582 * Prepare context for resuming with the given value. After using this
2583 * macro, you need to call your user-dependent exec function.
2584 */
2585#define CR_RESUME_C(p_ctx, value) \
2586 do { \
2587 if ((p_ctx)->status == CR_RES__OK_YIELDED) { \
2588 CR_ARG_RET_PT_C(p_ctx)->resumed = (value); \
2589 (p_ctx)->status = CR_RES__OK; \
2590 } \
2591 } while (0)
2592
2593/*
2594 * Evaluates to the yielded value (value given to `CR_YIELD_C()`)
2595 */
2596#define CR_YIELDED_C(p_ctx) (CR_ARG_RET_PT_C(p_ctx)->yielded)
2597
2598/*
2599 * Evaluates to the value given to `CR_RESUME_C()`
2600 */
2601#define CR_RESUMED_C(p_ctx) (CR_ARG_RET_PT_C(p_ctx)->resumed)
2602
2603/*
2604 * Beginning of the try-catch block.
2605 *
2606 * Should be used in eval loop only.
2607 *
2608 * `first_catch_fid`: function id of the first catch block.
2609 */
2610#define CR_TRY_C(p_ctx, first_catch_fid) \
2611 do { \
2612 _CR_STACK_RET_ALLOC((p_ctx), _CR_TRY_SIZE); \
2613 /* update pointer to current function's locals (may be invalidated) */ \
2614 _CR_CUR_FUNC_LOCALS_UPD(p_ctx); \
2615 /* */ \
2616 _CR_TRY_MARKER(p_ctx) = CR_FID__TRY_MARKER; \
2617 _CR_TRY_CATCH_FID(p_ctx) = (first_catch_fid); \
2618 } while (0)
2619
2620/*
2621 * Beginning of the individual catch block (and the end of the previous one, if
2622 * any)
2623 *
2624 * Should be used in eval loop only.
2625 *
2626 * `exc_id`: exception id to catch
2627 *
2628 * `catch_fid`: function id of this catch block.
2629 *
2630 * `next_catch_fid`: function id of the next catch block (or of the
2631 * `CR_ENDCATCH()`)
2632 */
2633#define CR_CATCH_C(p_ctx, exc_id, catch_fid, next_catch_fid) \
2634 catch_fid: \
2635 do { \
2636 if ((p_ctx)->thrown_exc != (exc_id)) { \
2637 goto next_catch_fid; \
2638 } \
2639 (p_ctx)->thrown_exc = CR_EXC_ID__NONE; \
2640 } while (0)
2641
2642/*
2643 * End of all catch blocks.
2644 *
2645 * Should be used in eval loop only.
2646 *
2647 * `endcatch_fid`: function id of this endcatch.
2648 */
2649#define CR_ENDCATCH_C(p_ctx, endcatch_fid) \
2650 endcatch_fid: \
2651 do { \
2652 (p_ctx)->stack_ret.len -= _CR_TRY_SIZE; \
2653 /* if we still have non-handled exception, continue unwinding "stack" */ \
2654 if ((p_ctx)->thrown_exc != CR_EXC_ID__NONE) { \
2655 goto _cr_iter_begin; \
2656 } \
2657 } while (0)
2658
2659/*
2660 * Throw exception.
2661 *
2662 * Should be used from eval loop only.
2663 *
2664 * `exc_id`: exception id to throw
2665 */
2666#define CR_THROW_C(p_ctx, exc_id) \
2667 do { \
2668 assert((enum cr_exc_id)(exc_id) != CR_EXC_ID__NONE); \
2669 /* clear need_return flag */ \
2670 (p_ctx)->thrown_exc = (exc_id); \
2671 goto _cr_iter_begin; \
2672 } while (0)
2673
2674/*
2675 * Get latest returned value from the given "function".
2676 *
2677 * `fid`: id of the function which returned value. Needed to ret value value
2678 * from the right field in the `(p_ctx)->arg_retval.ret` (different functions
2679 * may have different return types)
2680 */
2681#define CR_RETURNED_C(p_ctx, fid) (CR_ARG_RET_PT_C(p_ctx)->ret.fid)
2682
2683/*
2684 * Get currently thrown exception id. If nothing is being thrown at the moment,
2685 * `CR_EXC_ID__NONE` is returned
2686 */
2687#define CR_THROWN_C(p_ctx) ((p_ctx)->thrown_exc)
2688
2689/*
2690 * Like `sizeof()`, but it always evaluates to the multiple of `sizeof(void *)`
2691 *
2692 * It should be used for (struct cr_func_desc)::locals_size
2693 *
2694 * NOTE: instead of checking `sizeof(type) <= ((cr_locals_size_t) -1)`, I'd
2695 * better put the calculated value as it is, and if it overflows, then compiler
2696 * will generate warning, and this would help us to reveal our mistake. But
2697 * unfortunately, clang *always* generates this warning (even if the whole
2698 * expression yields 0), so we have to apply a bit more of dirty hacks here.
2699 */
2700#define CR_LOCALS_SIZEOF(type) \
2701 ((sizeof(type) == sizeof(cr_zero_size_type_t)) \
2702 ? 0 \
2703 : (sizeof(type) <= ((cr_locals_size_t) -1) \
2704 ? ((cr_locals_size_t)(((sizeof(type)) + (sizeof(void *) - 1)) & \
2705 (~(sizeof(void *) - 1)))) \
2706 : ((cr_locals_size_t) -1)))
2707
2708#define CR_ARG_SIZEOF(type) \
2709 ((sizeof(type) == sizeof(cr_zero_size_type_t)) ? 0 : sizeof(type))
2710
2711/*
2712 * Returns pointer to the current function's stack locals, and casts to given
2713 * type.
2714 *
2715 * Typical usage might look as follows:
2716 *
2717 * #undef L
2718 * #define L CR_CUR_LOCALS_PT(p_ctx, struct my_foo_locals)
2719 *
2720 * Then, assuming `struct my_foo_locals` has the field `bar`, we can access it
2721 * like this:
2722 *
2723 * L->bar
2724 */
2725#define CR_CUR_LOCALS_PT_C(p_ctx, type) ((type *) ((p_ctx)->p_cur_func_locals))
2726
2727/*
2728 * Returns pointer to the user-defined union of arguments and return values:
2729 * `union user_arg_ret`
2730 */
2731#define CR_ARG_RET_PT_C(p_ctx) ((p_ctx)->p_arg_retval)
2732
2733#define CR_ARG_RET_PT() CR_ARG_RET_PT_C(p_ctx)
2734
2735#define CR_CUR_LOCALS_PT(type) CR_CUR_LOCALS_PT_C(p_ctx, type)
2736
2737#define CR_CURR_FUNC() CR_CURR_FUNC_C(p_ctx)
2738
2739#define CR_CALL(call_fid, local_ret_fid) \
2740 CR_CALL_C(p_ctx, call_fid, local_ret_fid)
2741
2742#define CR_RETURN(cur_fid, retval) CR_RETURN_C(p_ctx, cur_fid, retval)
2743
2744#define CR_RETURN_VOID() CR_RETURN_VOID_C(p_ctx)
2745
2746#define CR_RETURNED(fid) CR_RETURNED_C(p_ctx, fid)
2747
2748#define CR_YIELD(value, local_ret_fid) CR_YIELD_C(p_ctx, value, local_ret_fid)
2749
2750#define CR_YIELDED() CR_YIELDED_C(p_ctx)
2751
2752#define CR_RESUME(value) CR_RESUME_C(p_ctx, value)
2753
2754#define CR_RESUMED() CR_RESUMED_C(p_ctx)
2755
2756#define CR_TRY(catch_name) CR_TRY_C(p_ctx, catch_name)
2757
2758#define CR_CATCH(exc_id, catch_name, next_catch_name) \
2759 CR_CATCH_C(p_ctx, exc_id, catch_name, next_catch_name)
2760
2761#define CR_ENDCATCH(endcatch_name) CR_ENDCATCH_C(p_ctx, endcatch_name)
2762
2763#define CR_THROW(exc_id) CR_THROW_C(p_ctx, exc_id)
2764
2765/* Private macros {{{ */
2766
2767#define _CR_CUR_FUNC_LOCALS_UPD(p_ctx) \
2768 do { \
2769 (p_ctx)->p_cur_func_locals = (uint8_t *) (p_ctx)->stack_data.buf + \
2770 (p_ctx)->stack_data.len - \
2771 _CR_CURR_FUNC_LOCALS_SIZE(p_ctx); \
2772 } while (0)
2773
2774/*
2775 * Size of the stack needed for each try-catch block.
2776 * Use `_CR_TRY_MARKER()` and `_CR_TRY_CATCH_FID()` to get/set parts.
2777 */
2778#define _CR_TRY_SIZE 2 /*CR_FID__TRY_MARKER, catch_fid*/
2779
2780/*
2781 * Evaluates to lvalue where `CR_FID__TRY_MARKER` should be stored
2782 */
2783#define _CR_TRY_MARKER(p_ctx) \
2784 *(((uint8_t *) (p_ctx)->stack_ret.buf) + (p_ctx)->stack_ret.len - 1)
2785
2786/*
2787 * Evaluates to lvalue where `catch_fid` should be stored
2788 */
2789#define _CR_TRY_CATCH_FID(p_ctx) \
2790 *(((uint8_t *) (p_ctx)->stack_ret.buf) + (p_ctx)->stack_ret.len - 2)
2791
2792#define _CR_CURR_FUNC_LOCALS_SIZE(p_ctx) \
2793 ((p_ctx)->p_func_descrs[CR_CURR_FUNC_C(p_ctx)].locals_size)
2794
2795/*
2796 * Prepare context for calling next function.
2797 *
2798 * See comments for `CR_CALL()` macro.
2799 */
2800#define _CR_CALL_PREPARE(p_ctx, _call_fid, _locals_size, _arg_size, \
2801 local_ret_fid) \
2802 do { \
2803 /* adjust return func id */ \
2804 CR_CURR_FUNC_C(p_ctx) = (local_ret_fid); \
2805 \
2806 /* set called_fid */ \
2807 (p_ctx)->called_fid = (_call_fid); \
2808 \
2809 /* set sizes: locals and arg */ \
2810 (p_ctx)->call_locals_size = (_locals_size); \
2811 (p_ctx)->call_arg_size = (_arg_size); \
2812 } while (0)
2813
2814#define _CR_STACK_DATA_OVF_CHECK(p_ctx, inc) (0)
2815
2816#define _CR_STACK_DATA_UND_CHECK(p_ctx, dec) ((p_ctx)->stack_data.len < (dec))
2817
2818#define _CR_STACK_RET_OVF_CHECK(p_ctx, inc) (0)
2819
2820#define _CR_STACK_RET_UND_CHECK(p_ctx, dec) ((p_ctx)->stack_ret.len < (dec))
2821
2822#define _CR_STACK_FID_OVF_CHECK(p_ctx, inc) (0)
2823
2824#define _CR_STACK_FID_UND_CHECK(p_ctx, dec) ((p_ctx)->cur_fid_idx < (dec))
2825
2826#if defined(CR_TRACK_MAX_STACK_LEN)
2827
2828#define _CR_STACK_DATA_ALLOC(p_ctx, inc) \
2829 do { \
2830 mbuf_append(&((p_ctx)->stack_data), NULL, (inc)); \
2831 if ((p_ctx)->stack_data_max_len < (p_ctx)->stack_data.len) { \
2832 (p_ctx)->stack_data_max_len = (p_ctx)->stack_data.len; \
2833 } \
2834 } while (0)
2835
2836#define _CR_STACK_RET_ALLOC(p_ctx, inc) \
2837 do { \
2838 mbuf_append(&((p_ctx)->stack_ret), NULL, (inc)); \
2839 if ((p_ctx)->stack_ret_max_len < (p_ctx)->stack_ret.len) { \
2840 (p_ctx)->stack_ret_max_len = (p_ctx)->stack_ret.len; \
2841 } \
2842 } while (0)
2843
2844#else
2845
2846#define _CR_STACK_DATA_ALLOC(p_ctx, inc) \
2847 do { \
2848 mbuf_append(&((p_ctx)->stack_data), NULL, (inc)); \
2849 } while (0)
2850
2851#define _CR_STACK_RET_ALLOC(p_ctx, inc) \
2852 do { \
2853 mbuf_append(&((p_ctx)->stack_ret), NULL, (inc)); \
2854 } while (0)
2855
2856#endif
2857
2858#define _CR_STACK_DATA_FREE(p_ctx, dec) \
2859 do { \
2860 (p_ctx)->stack_data.len -= (dec); \
2861 } while (0)
2862
2863#define _CR_STACK_RET_FREE(p_ctx, dec) \
2864 do { \
2865 (p_ctx)->stack_ret.len -= (dec); \
2866 } while (0)
2867
2868#define _CR_STACK_FID_ALLOC(p_ctx, inc) \
2869 do { \
2870 (p_ctx)->cur_fid_idx += (inc); \
2871 } while (0)
2872
2873#define _CR_STACK_FID_FREE(p_ctx, dec) \
2874 do { \
2875 (p_ctx)->cur_fid_idx -= (dec); \
2876 } while (0)
2877
2878/* }}} */
2879
2880/*
2881 * Should be used in eval loop right after `_cr_iter_begin:` label
2882 */
2883enum cr_status cr_on_iter_begin(struct cr_ctx *p_ctx);
2884
2885/*
2886 * Initialize context `p_ctx`.
2887 *
2888 * `p_arg_retval`: pointer to the user-defined `union user_arg_ret`
2889 *
2890 * `p_func_descrs`: array of all user function descriptors
2891 */
2892void cr_context_init(struct cr_ctx *p_ctx, union user_arg_ret *p_arg_retval,
2893 size_t arg_retval_size,
2894 const struct cr_func_desc *p_func_descrs);
2895
2896/*
2897 * free resources occupied by context (at least, "stack" arrays)
2898 */
2899void cr_context_free(struct cr_ctx *p_ctx);
2900
2901#ifdef __cplusplus
2902}
2903#endif
2904
2905#endif /* CS_COMMON_COROUTINE_H_ */
2906#ifdef V7_MODULE_LINES
2907#line 1 "v7/src/features_profiles.h"
2908#endif
2909/*
2910 * Copyright (c) 2014 Cesanta Software Limited
2911 * All rights reserved
2912 */
2913
2914#ifndef CS_V7_SRC_FEATURES_PROFILES_H_
2915#define CS_V7_SRC_FEATURES_PROFILES_H_
2916
2917#define V7_BUILD_PROFILE_MINIMAL 1
2918#define V7_BUILD_PROFILE_MEDIUM 2
2919#define V7_BUILD_PROFILE_FULL 3
2920
2921#ifndef V7_BUILD_PROFILE
2922#define V7_BUILD_PROFILE V7_BUILD_PROFILE_FULL
2923#endif
2924
2925#endif /* CS_V7_SRC_FEATURES_PROFILES_H_ */
2926#ifdef V7_MODULE_LINES
2927#line 1 "v7/src/features_minimal.h"
2928#endif
2929/*
2930 * Copyright (c) 2014 Cesanta Software Limited
2931 * All rights reserved
2932 */
2933
2934/* Amalgamated: #include "v7/src/features_profiles.h" */
2935
2936#if V7_BUILD_PROFILE == V7_BUILD_PROFILE_MINIMAL
2937
2938/* This space is intentionally left blank. */
2939
2940#endif /* CS_V7_SRC_FEATURES_MINIMAL_H_ */
2941#ifdef V7_MODULE_LINES
2942#line 1 "v7/src/features_medium.h"
2943#endif
2944/*
2945 * Copyright (c) 2014 Cesanta Software Limited
2946 * All rights reserved
2947 */
2948
2949/* Amalgamated: #include "v7/src/features_profiles.h" */
2950
2951#if V7_BUILD_PROFILE == V7_BUILD_PROFILE_MEDIUM
2952
2953#define V7_ENABLE__Date 1
2954#define V7_ENABLE__Date__now 1
2955#define V7_ENABLE__Date__UTC 1
2956#define V7_ENABLE__Math 1
2957#define V7_ENABLE__Math__atan2 1
2958#define V7_ENABLE__RegExp 1
2959
2960#endif /* CS_V7_SRC_FEATURES_MEDIUM_H_ */
2961#ifdef V7_MODULE_LINES
2962#line 1 "v7/src/features_full.h"
2963#endif
2964/*
2965 * Copyright (c) 2014 Cesanta Software Limited
2966 * All rights reserved
2967 */
2968
2969#ifndef CS_V7_SRC_FEATURES_FULL_H_
2970#define CS_V7_SRC_FEATURES_FULL_H_
2971
2972/* Amalgamated: #include "v7/src/features_profiles.h" */
2973
2974#if V7_BUILD_PROFILE == V7_BUILD_PROFILE_FULL
2975/*
2976 * DO NOT EDIT.
2977 * This file is generated by scripts/gen-features-full.pl.
2978 */
2979#ifndef CS_ENABLE_UTF8 /* ifdef-ok */
2980#define CS_ENABLE_UTF8 1
2981#endif
2982
2983#define V7_ENABLE__Array__reduce 1
2984#define V7_ENABLE__Blob 1
2985#define V7_ENABLE__Date 1
2986#define V7_ENABLE__Date__UTC 1
2987#define V7_ENABLE__Date__getters 1
2988#define V7_ENABLE__Date__now 1
2989#define V7_ENABLE__Date__parse 1
2990#define V7_ENABLE__Date__setters 1
2991#define V7_ENABLE__Date__toJSON 1
2992#define V7_ENABLE__Date__toLocaleString 1
2993#define V7_ENABLE__Date__toString 1
2994#define V7_ENABLE__File__list 1
2995#define V7_ENABLE__File__require 1
2996#define V7_ENABLE__Function__bind 1
2997#define V7_ENABLE__Function__call 1
2998#define V7_ENABLE__Math 1
2999#define V7_ENABLE__Math__abs 1
3000#define V7_ENABLE__Math__acos 1
3001#define V7_ENABLE__Math__asin 1
3002#define V7_ENABLE__Math__atan 1
3003#define V7_ENABLE__Math__atan2 1
3004#define V7_ENABLE__Math__ceil 1
3005#define V7_ENABLE__Math__constants 1
3006#define V7_ENABLE__Math__cos 1
3007#define V7_ENABLE__Math__exp 1
3008#define V7_ENABLE__Math__floor 1
3009#define V7_ENABLE__Math__log 1
3010#define V7_ENABLE__Math__max 1
3011#define V7_ENABLE__Math__min 1
3012#define V7_ENABLE__Math__pow 1
3013#define V7_ENABLE__Math__random 1
3014#define V7_ENABLE__Math__round 1
3015#define V7_ENABLE__Math__sin 1
3016#define V7_ENABLE__Math__sqrt 1
3017#define V7_ENABLE__Math__tan 1
3018#define V7_ENABLE__Memory__stats 1
3019#define V7_ENABLE__NUMBER__NEGATIVE_INFINITY 1
3020#define V7_ENABLE__NUMBER__POSITIVE_INFINITY 1
3021#define V7_ENABLE__Object__create 1
3022#define V7_ENABLE__Object__defineProperties 1
3023#define V7_ENABLE__Object__getOwnPropertyDescriptor 1
3024#define V7_ENABLE__Object__getOwnPropertyNames 1
3025#define V7_ENABLE__Object__getPrototypeOf 1
3026#define V7_ENABLE__Object__hasOwnProperty 1
3027#define V7_ENABLE__Object__isExtensible 1
3028#define V7_ENABLE__Object__isFrozen 1
3029#define V7_ENABLE__Object__isPrototypeOf 1
3030#define V7_ENABLE__Object__isSealed 1
3031#define V7_ENABLE__Object__keys 1
3032#define V7_ENABLE__Object__preventExtensions 1
3033#define V7_ENABLE__Object__propertyIsEnumerable 1
3034#define V7_ENABLE__Proxy 1
3035#define V7_ENABLE__RegExp 1
3036#define V7_ENABLE__StackTrace 1
3037#define V7_ENABLE__String__localeCompare 1
3038#define V7_ENABLE__String__localeLowerCase 1
3039#define V7_ENABLE__String__localeUpperCase 1
3040
3041#endif /* V7_BUILD_PROFILE == V7_BUILD_PROFILE_FULL */
3042
3043#endif /* CS_V7_SRC_FEATURES_FULL_H_ */
3044#ifdef V7_MODULE_LINES
3045#line 1 "v7/src/features_all.h"
3046#endif
3047/*
3048 * Copyright (c) 2014 Cesanta Software Limited
3049 * All rights reserved
3050 */
3051
3052#ifndef CS_V7_SRC_FEATURES_ALL_H_
3053#define CS_V7_SRC_FEATURES_ALL_H_
3054
3055/*
3056 * DO NOT EDIT.
3057 * This file is generated by scripts/gen-features-all.pl.
3058 */
3059
3060#ifndef V7_ENABLE__Array__reduce
3061#define V7_ENABLE__Array__reduce 0
3062#endif
3063
3064#ifndef V7_ENABLE__Blob
3065#define V7_ENABLE__Blob 0
3066#endif
3067
3068#ifndef V7_ENABLE__Date
3069#define V7_ENABLE__Date 0
3070#endif
3071
3072#ifndef V7_ENABLE__Date__UTC
3073#define V7_ENABLE__Date__UTC 0
3074#endif
3075
3076#ifndef V7_ENABLE__Date__getters
3077#define V7_ENABLE__Date__getters 0
3078#endif
3079
3080#ifndef V7_ENABLE__Date__now
3081#define V7_ENABLE__Date__now 0
3082#endif
3083
3084#ifndef V7_ENABLE__Date__parse
3085#define V7_ENABLE__Date__parse 0
3086#endif
3087
3088#ifndef V7_ENABLE__Date__setters
3089#define V7_ENABLE__Date__setters 0
3090#endif
3091
3092#ifndef V7_ENABLE__Date__toJSON
3093#define V7_ENABLE__Date__toJSON 0
3094#endif
3095
3096#ifndef V7_ENABLE__Date__toLocaleString
3097#define V7_ENABLE__Date__toLocaleString 0
3098#endif
3099
3100#ifndef V7_ENABLE__Date__toString
3101#define V7_ENABLE__Date__toString 0
3102#endif
3103
3104#ifndef V7_ENABLE__File__list
3105#define V7_ENABLE__File__list 0
3106#endif
3107
3108#ifndef V7_ENABLE__File__require
3109#define V7_ENABLE__File__require 0
3110#endif
3111
3112#ifndef V7_ENABLE__Function__bind
3113#define V7_ENABLE__Function__bind 0
3114#endif
3115
3116#ifndef V7_ENABLE__Function__call
3117#define V7_ENABLE__Function__call 0
3118#endif
3119
3120#ifndef V7_ENABLE__Math
3121#define V7_ENABLE__Math 0
3122#endif
3123
3124#ifndef V7_ENABLE__Math__abs
3125#define V7_ENABLE__Math__abs 0
3126#endif
3127
3128#ifndef V7_ENABLE__Math__acos
3129#define V7_ENABLE__Math__acos 0
3130#endif
3131
3132#ifndef V7_ENABLE__Math__asin
3133#define V7_ENABLE__Math__asin 0
3134#endif
3135
3136#ifndef V7_ENABLE__Math__atan
3137#define V7_ENABLE__Math__atan 0
3138#endif
3139
3140#ifndef V7_ENABLE__Math__atan2
3141#define V7_ENABLE__Math__atan2 0
3142#endif
3143
3144#ifndef V7_ENABLE__Math__ceil
3145#define V7_ENABLE__Math__ceil 0
3146#endif
3147
3148#ifndef V7_ENABLE__Math__constants
3149#define V7_ENABLE__Math__constants 0
3150#endif
3151
3152#ifndef V7_ENABLE__Math__cos
3153#define V7_ENABLE__Math__cos 0
3154#endif
3155
3156#ifndef V7_ENABLE__Math__exp
3157#define V7_ENABLE__Math__exp 0
3158#endif
3159
3160#ifndef V7_ENABLE__Math__floor
3161#define V7_ENABLE__Math__floor 0
3162#endif
3163
3164#ifndef V7_ENABLE__Math__log
3165#define V7_ENABLE__Math__log 0
3166#endif
3167
3168#ifndef V7_ENABLE__Math__max
3169#define V7_ENABLE__Math__max 0
3170#endif
3171
3172#ifndef V7_ENABLE__Math__min
3173#define V7_ENABLE__Math__min 0
3174#endif
3175
3176#ifndef V7_ENABLE__Math__pow
3177#define V7_ENABLE__Math__pow 0
3178#endif
3179
3180#ifndef V7_ENABLE__Math__random
3181#define V7_ENABLE__Math__random 0
3182#endif
3183
3184#ifndef V7_ENABLE__Math__round
3185#define V7_ENABLE__Math__round 0
3186#endif
3187
3188#ifndef V7_ENABLE__Math__sin
3189#define V7_ENABLE__Math__sin 0
3190#endif
3191
3192#ifndef V7_ENABLE__Math__sqrt
3193#define V7_ENABLE__Math__sqrt 0
3194#endif
3195
3196#ifndef V7_ENABLE__Math__tan
3197#define V7_ENABLE__Math__tan 0
3198#endif
3199
3200#ifndef V7_ENABLE__Memory__stats
3201#define V7_ENABLE__Memory__stats 0
3202#endif
3203
3204#ifndef V7_ENABLE__NUMBER__NEGATIVE_INFINITY
3205#define V7_ENABLE__NUMBER__NEGATIVE_INFINITY 0
3206#endif
3207
3208#ifndef V7_ENABLE__NUMBER__POSITIVE_INFINITY
3209#define V7_ENABLE__NUMBER__POSITIVE_INFINITY 0
3210#endif
3211
3212#ifndef V7_ENABLE__Object__create
3213#define V7_ENABLE__Object__create 0
3214#endif
3215
3216#ifndef V7_ENABLE__Object__defineProperties
3217#define V7_ENABLE__Object__defineProperties 0
3218#endif
3219
3220#ifndef V7_ENABLE__Object__getOwnPropertyDescriptor
3221#define V7_ENABLE__Object__getOwnPropertyDescriptor 0
3222#endif
3223
3224#ifndef V7_ENABLE__Object__getOwnPropertyNames
3225#define V7_ENABLE__Object__getOwnPropertyNames 0
3226#endif
3227
3228#ifndef V7_ENABLE__Object__getPrototypeOf
3229#define V7_ENABLE__Object__getPrototypeOf 0
3230#endif
3231
3232#ifndef V7_ENABLE__Object__hasOwnProperty
3233#define V7_ENABLE__Object__hasOwnProperty 0
3234#endif
3235
3236#ifndef V7_ENABLE__Object__isExtensible
3237#define V7_ENABLE__Object__isExtensible 0
3238#endif
3239
3240#ifndef V7_ENABLE__Object__isFrozen
3241#define V7_ENABLE__Object__isFrozen 0
3242#endif
3243
3244#ifndef V7_ENABLE__Object__isPrototypeOf
3245#define V7_ENABLE__Object__isPrototypeOf 0
3246#endif
3247
3248#ifndef V7_ENABLE__Object__isSealed
3249#define V7_ENABLE__Object__isSealed 0
3250#endif
3251
3252#ifndef V7_ENABLE__Object__keys
3253#define V7_ENABLE__Object__keys 0
3254#endif
3255
3256#ifndef V7_ENABLE__Object__preventExtensions
3257#define V7_ENABLE__Object__preventExtensions 0
3258#endif
3259
3260#ifndef V7_ENABLE__Object__propertyIsEnumerable
3261#define V7_ENABLE__Object__propertyIsEnumerable 0
3262#endif
3263
3264#ifndef V7_ENABLE__Proxy
3265#define V7_ENABLE__Proxy 0
3266#endif
3267
3268#ifndef V7_ENABLE__RegExp
3269#define V7_ENABLE__RegExp 0
3270#endif
3271
3272#ifndef V7_ENABLE__StackTrace
3273#define V7_ENABLE__StackTrace 0
3274#endif
3275
3276#ifndef V7_ENABLE__String__localeCompare
3277#define V7_ENABLE__String__localeCompare 0
3278#endif
3279
3280#ifndef V7_ENABLE__String__localeLowerCase
3281#define V7_ENABLE__String__localeLowerCase 0
3282#endif
3283
3284#ifndef V7_ENABLE__String__localeUpperCase
3285#define V7_ENABLE__String__localeUpperCase 0
3286#endif
3287
3288#endif /* CS_V7_SRC_FEATURES_ALL_H_ */
3289#ifdef V7_MODULE_LINES
3290#line 1 "v7/src/v7_features.h"
3291#endif
3292/*
3293 * Copyright (c) 2014 Cesanta Software Limited
3294 * All rights reserved
3295 */
3296
3297#ifndef CS_V7_SRC_V7_FEATURES_H_
3298#define CS_V7_SRC_V7_FEATURES_H_
3299
3300/* Only one will actually be used based on V7_BUILD_PROFILE. */
3301/* Amalgamated: #include "v7/src/features_minimal.h" */
3302/* Amalgamated: #include "v7/src/features_medium.h" */
3303/* Amalgamated: #include "v7/src/features_full.h" */
3304/* All the features will be default-defined to 0. */
3305/* Amalgamated: #include "v7/src/features_all.h" */
3306
3307#ifndef V7_DISABLE_AST_TAG_NAMES
3308#define V7_DISABLE_AST_TAG_NAMES 0
3309#endif
3310
3311#ifndef V7_DISABLE_GC
3312#define V7_DISABLE_GC 0
3313#endif
3314
3315#ifndef V7_DISABLE_CALL_ERROR_CONTEXT
3316#define V7_DISABLE_CALL_ERROR_CONTEXT 0
3317#endif
3318
3319#ifndef V7_DISABLE_FILENAMES
3320#define V7_DISABLE_FILENAMES 0
3321#endif
3322
3323#ifndef V7_DISABLE_LINE_NUMBERS
3324#define V7_DISABLE_LINE_NUMBERS 0
3325#endif
3326
3327#ifndef V7_DISABLE_STR_ALLOC_SEQ
3328#define V7_DISABLE_STR_ALLOC_SEQ 0
3329#endif
3330
3331#ifndef V7_ENABLE_CALL_TRACE
3332#define V7_ENABLE_CALL_TRACE 0
3333#endif
3334
3335#ifndef V7_ENABLE_CRYPTO
3336#define V7_ENABLE_CRYPTO 0
3337#endif
3338
3339#ifndef V7_ENABLE_DENSE_ARRAYS
3340#define V7_ENABLE_DENSE_ARRAYS 0
3341#endif
3342
3343#ifndef V7_ENABLE_ENTITY_IDS
3344#define V7_ENABLE_ENTITY_IDS 0
3345#endif
3346
3347#ifndef V7_ENABLE_FILE
3348#define V7_ENABLE_FILE 0
3349#endif
3350
3351#ifndef V7_ENABLE_FOOTPRINT_REPORT
3352#define V7_ENABLE_FOOTPRINT_REPORT 0
3353#endif
3354
3355#ifndef V7_ENABLE_GC_CHECK
3356#define V7_ENABLE_GC_CHECK 0
3357#endif
3358
3359#ifndef V7_ENABLE_JS_GETTERS
3360#define V7_ENABLE_JS_GETTERS 0
3361#endif
3362
3363#ifndef V7_ENABLE_JS_SETTERS
3364#define V7_ENABLE_JS_SETTERS 0
3365#endif
3366
3367#ifndef V7_ENABLE_STACK_TRACKING
3368#define V7_ENABLE_STACK_TRACKING 0
3369#endif
3370
3371#ifndef V7_ENABLE_SOCKET
3372#define V7_ENABLE_SOCKET 0
3373#endif
3374
3375#ifndef V7_AST_FORCE_LINE_NUMBERS
3376#define V7_AST_FORCE_LINE_NUMBERS 0
3377#endif
3378
3379#ifndef V7_HEAPUSAGE_ENABLE
3380#define V7_HEAPUSAGE_ENABLE 0
3381#endif
3382
3383#endif /* CS_V7_SRC_V7_FEATURES_H_ */
3384#ifdef V7_MODULE_LINES
3385#line 1 "v7/src/platform.h"
3386#endif
3387/*
3388 * Copyright (c) 2014 Cesanta Software Limited
3389 * All rights reserved
3390 */
3391
3392#ifndef CS_V7_SRC_PLATFORM_H_
3393#define CS_V7_SRC_PLATFORM_H_
3394
3395#ifdef __arm
3396#undef V7_ENABLE__Date
3397#define V7_ENABLE__Date 0
3398#endif
3399
3400#endif /* CS_V7_SRC_PLATFORM_H_ */
3401#ifdef V7_MODULE_LINES
3402#line 1 "v7/src/internal.h"
3403#endif
3404/*
3405 * Copyright (c) 2014 Cesanta Software Limited
3406 * All rights reserved
3407 */
3408
3409#ifndef CS_V7_SRC_INTERNAL_H_
3410#define CS_V7_SRC_INTERNAL_H_
3411
3412/* Amalgamated: #include "v7/src/license.h" */
3413
3414#ifndef FAST
3415#define FAST
3416#endif
3417
3418#ifndef STATIC
3419#define STATIC
3420#endif
3421
3422#ifndef ENDL
3423#define ENDL "\n"
3424#endif
3425
3426/*
3427 * In some compilers (watcom) NAN == NAN (and other comparisons) don't follow
3428 * the rules of IEEE 754. Since we don't know a priori which compilers
3429 * will generate correct code, we disable the fallback on selected platforms.
3430 * TODO(mkm): selectively disable on clang/gcc once we test this out.
3431 */
3432#define V7_BROKEN_NAN
3433
3434#undef _POSIX_C_SOURCE
3435#define _POSIX_C_SOURCE 200809L
3436
3437#include <assert.h>
3438#ifndef NO_LIBC
3439#include <ctype.h>
3440#endif
3441#include <errno.h>
3442#include <float.h>
3443#include <limits.h>
3444#include <math.h>
3445#include <stdarg.h>
3446#include <stddef.h>
3447#include <stdio.h>
3448#include <stdlib.h>
3449#include <string.h>
3450#include <setjmp.h>
3451
3452/* Public API. Implemented in api.c */
3453/* Amalgamated: #include "common/platform.h" */
3454
3455#ifdef V7_WINDOWS
3456#define vsnprintf _vsnprintf
3457#define snprintf _snprintf
3458
3459/* VS2015 Update 1 has ISO C99 `isnan` and `isinf` defined in math.h */
3460#if _MSC_FULL_VER < 190023506
3461#define isnan(x) _isnan(x)
3462#define isinf(x) (!_finite(x))
3463#endif
3464
3465#define __unused __pragma(warning(suppress : 4100))
3466typedef __int64 int64_t;
3467typedef int int32_t;
3468typedef unsigned int uint32_t;
3469typedef unsigned short uint16_t;
3470typedef unsigned char uint8_t;
3471
3472/* For 64bit VisualStudio 2010 */
3473#ifndef _UINTPTR_T_DEFINED
3474typedef unsigned long uintptr_t;
3475#endif
3476
3477#ifndef __func__
3478#define __func__ ""
3479#endif
3480
3481#else
3482#include <stdint.h>
3483#endif
3484
3485/* Amalgamated: #include "v7/src/v7_features.h" */
3486/* Amalgamated: #include "v7/src/platform.h" */
3487
3488/* MSVC6 doesn't have standard C math constants defined */
3489#ifndef M_E
3490#define M_E 2.71828182845904523536028747135266250
3491#endif
3492
3493#ifndef M_LOG2E
3494#define M_LOG2E 1.44269504088896340735992468100189214
3495#endif
3496
3497#ifndef M_LOG10E
3498#define M_LOG10E 0.434294481903251827651128918916605082
3499#endif
3500
3501#ifndef M_LN2
3502#define M_LN2 0.693147180559945309417232121458176568
3503#endif
3504
3505#ifndef M_LN10
3506#define M_LN10 2.30258509299404568401799145468436421
3507#endif
3508
3509#ifndef M_PI
3510#define M_PI 3.14159265358979323846264338327950288
3511#endif
3512
3513#ifndef M_SQRT2
3514#define M_SQRT2 1.41421356237309504880168872420969808
3515#endif
3516
3517#ifndef M_SQRT1_2
3518#define M_SQRT1_2 0.707106781186547524400844362104849039
3519#endif
3520
3521#ifndef NAN
3522extern double _v7_nan;
3523#define HAS_V7_NAN
3524#define NAN (_v7_nan)
3525#endif
3526
3527#ifndef INFINITY
3528extern double _v7_infinity;
3529#define HAS_V7_INFINITY
3530#define INFINITY (_v7_infinity)
3531#endif
3532
3533#ifndef EXIT_SUCCESS
3534#define EXIT_SUCCESS 0
3535#endif
3536
3537#ifndef EXIT_FAILURE
3538#define EXIT_FAILURE 1
3539#endif
3540
3541#if V7_ENABLE_GC_CHECK || defined(V7_STACK_GUARD_MIN_SIZE) || \
3542 V7_ENABLE_STACK_TRACKING || V7_ENABLE_CALL_TRACE
3543/* Need to enable GCC/clang instrumentation */
3544#define V7_CYG_PROFILE_ON
3545#endif
3546
3547#if defined(V7_CYG_PROFILE_ON)
3548extern struct v7 *v7_head;
3549
3550#if defined(V7_STACK_GUARD_MIN_SIZE)
3551extern void *v7_sp_limit;
3552#endif
3553#endif
3554
3555#ifndef ARRAY_SIZE
3556#define ARRAY_SIZE(array) (sizeof(array) / sizeof(array[0]))
3557#endif
3558
3559#define V7_STATIC_ASSERT(COND, MSG) \
3560 typedef char static_assertion_##MSG[2 * (!!(COND)) - 1]
3561
3562#define BUF_LEFT(size, used) (((size_t)(used) < (size)) ? ((size) - (used)) : 0)
3563
3564#endif /* CS_V7_SRC_INTERNAL_H_ */
3565#ifdef V7_MODULE_LINES
3566#line 1 "v7/src/core_public.h"
3567#endif
3568/*
3569 * Copyright (c) 2014 Cesanta Software Limited
3570 * All rights reserved
3571 */
3572
3573/*
3574 * === Core
3575 */
3576
3577#ifndef CS_V7_SRC_CORE_PUBLIC_H_
3578#define CS_V7_SRC_CORE_PUBLIC_H_
3579
3580#ifndef _POSIX_C_SOURCE
3581#define _POSIX_C_SOURCE 200809L
3582#endif
3583
3584/* Amalgamated: #include "v7/src/license.h" */
3585/* Amalgamated: #include "v7/src/v7_features.h" */
3586/* Amalgamated: #include "v7/src/platform.h" */
3587
3588#include <stddef.h> /* For size_t */
3589#include <stdio.h> /* For FILE */
3590
3591#if defined(__cplusplus)
3592extern "C" {
3593#endif /* __cplusplus */
3594
3595/*
3596 * TODO(dfrank) : improve amalgamation, so that we'll be able to include
3597 * files here, and include common/platform.h
3598 *
3599 * For now, copy-pasting `WARN_UNUSED_RESULT` here
3600 */
3601#ifdef __GNUC__
3602#define WARN_UNUSED_RESULT __attribute__((warn_unused_result))
3603#define NOINSTR __attribute__((no_instrument_function))
3604#else
3605#define WARN_UNUSED_RESULT
3606#define NOINSTR
3607#endif
3608
3609#define V7_VERSION "1.0"
3610
3611#if (defined(_WIN32) && !defined(__MINGW32__) && !defined(__MINGW64__)) || \
3612 (defined(_MSC_VER) && _MSC_VER <= 1200)
3613#define V7_WINDOWS
3614#endif
3615
3616#ifdef V7_WINDOWS
3617typedef unsigned __int64 uint64_t;
3618#else
3619#include <inttypes.h>
3620#endif
3621/* 64-bit value, used to store JS values */
3622typedef uint64_t v7_val_t;
3623
3624/* JavaScript `null` value */
3625#define V7_NULL ((uint64_t) 0xfffe << 48)
3626
3627/* JavaScript `undefined` value */
3628#define V7_UNDEFINED ((uint64_t) 0xfffd << 48)
3629
3630/* This if-0 is a dirty workaround to force etags to pick `struct v7` */
3631#if 0
3632/* Opaque structure. V7 engine context. */
3633struct v7 {
3634 /* ... */
3635};
3636#endif
3637
3638struct v7;
3639
3640/*
3641 * Code which is returned by some of the v7 functions. If something other than
3642 * `V7_OK` is returned from some function, the caller function typically should
3643 * either immediately cleanup and return the code further, or handle the error.
3644 */
3645enum v7_err {
3646 V7_OK,
3647 V7_SYNTAX_ERROR,
3648 V7_EXEC_EXCEPTION,
3649 V7_AST_TOO_LARGE,
3650 V7_INTERNAL_ERROR,
3651};
3652
3653/* JavaScript -> C call interface */
3654WARN_UNUSED_RESULT
3655typedef enum v7_err(v7_cfunction_t)(struct v7 *v7, v7_val_t *res);
3656
3657/* Create V7 instance */
3658struct v7 *v7_create(void);
3659
3660/*
3661 * Customizations of initial V7 state; used by `v7_create_opt()`.
3662 */
3663struct v7_create_opts {
3664 size_t object_arena_size;
3665 size_t function_arena_size;
3666 size_t property_arena_size;
3667#ifdef V7_STACK_SIZE
3668 void *c_stack_base;
3669#endif
3670#ifdef V7_FREEZE
3671 /* if not NULL, dump JS heap after init */
3672 char *freeze_file;
3673#endif
3674};
3675
3676/*
3677 * Like `v7_create()`, but allows to customize initial v7 state, see `struct
3678 * v7_create_opts`.
3679 */
3680struct v7 *v7_create_opt(struct v7_create_opts opts);
3681
3682/* Destroy V7 instance */
3683void v7_destroy(struct v7 *v7);
3684
3685/* Return root level (`global`) object of the given V7 instance. */
3686v7_val_t v7_get_global(struct v7 *v);
3687
3688/* Return current `this` object. */
3689v7_val_t v7_get_this(struct v7 *v);
3690
3691/* Return current `arguments` array */
3692v7_val_t v7_get_arguments(struct v7 *v);
3693
3694/* Return i-th argument */
3695v7_val_t v7_arg(struct v7 *v, unsigned long i);
3696
3697/* Return the length of `arguments` */
3698unsigned long v7_argc(struct v7 *v7);
3699
3700/*
3701 * Tells the GC about a JS value variable/field owned
3702 * by C code.
3703 *
3704 * User C code should own v7_val_t variables
3705 * if the value's lifetime crosses any invocation
3706 * to the v7 runtime that creates new objects or new
3707 * properties and thus can potentially trigger GC.
3708 *
3709 * The registration of the variable prevents the GC from mistakenly treat
3710 * the object as garbage. The GC might be triggered potentially
3711 * allows the GC to update pointers
3712 *
3713 * User code should also explicitly disown the variables with v7_disown once
3714 * it goes out of scope or the structure containing the v7_val_t field is freed.
3715 *
3716 * Example:
3717 *
3718 * ```
3719 * struct v7_val cb;
3720 * v7_own(v7, &cb);
3721 * cb = v7_array_get(v7, args, 0);
3722 * // do something with cb
3723 * v7_disown(v7, &cb);
3724 * ```
3725 */
3726void v7_own(struct v7 *v7, v7_val_t *v);
3727
3728/*
3729 * Returns 1 if value is found, 0 otherwise
3730 */
3731int v7_disown(struct v7 *v7, v7_val_t *v);
3732
3733/*
3734 * Enable or disable GC.
3735 *
3736 * Must be called before invoking v7_exec or v7_apply
3737 * from within a cfunction unless you know what you're doing.
3738 *
3739 * GC is disabled during execution of cfunctions in order to simplify
3740 * memory management of simple cfunctions.
3741 * However executing even small snippets of JS code causes a lot of memory
3742 * pressure. Enabling GC solves that but forces you to take care of the
3743 * reachability of your temporary V7 v7_val_t variables, as the GC needs
3744 * to know where they are since objects and strings can be either reclaimed
3745 * or relocated during a GC pass.
3746 */
3747void v7_set_gc_enabled(struct v7 *v7, int enabled);
3748
3749/*
3750 * Set an optional C stack limit.
3751 *
3752 * It sets a flag that will cause the interpreter
3753 * to throw an InterruptedError.
3754 * It's safe to call it from signal handlers and ISRs
3755 * on single threaded environments.
3756 */
3757void v7_interrupt(struct v7 *v7);
3758
3759/* Returns last parser error message. TODO: rename it to `v7_get_error()` */
3760const char *v7_get_parser_error(struct v7 *v7);
3761
3762#if V7_ENABLE_STACK_TRACKING
3763/*
3764 * Available if only `V7_ENABLE_STACK_TRACKING` is defined.
3765 *
3766 * Stack metric id. See `v7_stack_stat()`
3767 */
3768enum v7_stack_stat_what {
3769 /* max stack size consumed by `i_exec()` */
3770 V7_STACK_STAT_EXEC,
3771 /* max stack size consumed by `parse()` (which is called from `i_exec()`) */
3772 V7_STACK_STAT_PARSER,
3773
3774 V7_STACK_STATS_CNT
3775};
3776
3777/*
3778 * Available if only `V7_ENABLE_STACK_TRACKING` is defined.
3779 *
3780 * Returns stack metric specified by the metric id `what`. See
3781 * `v7_stack_stat_clean()`
3782 */
3783int v7_stack_stat(struct v7 *v7, enum v7_stack_stat_what what);
3784
3785/*
3786 * Available if only `V7_ENABLE_STACK_TRACKING` is defined.
3787 *
3788 * Clean all stack statistics gathered so far. See `v7_stack_stat()`
3789 */
3790void v7_stack_stat_clean(struct v7 *v7);
3791#endif
3792
3793#if defined(__cplusplus)
3794}
3795#endif /* __cplusplus */
3796
3797#endif /* CS_V7_SRC_CORE_PUBLIC_H_ */
3798#ifdef V7_MODULE_LINES
3799#line 1 "v7/src/std_error.h"
3800#endif
3801/*
3802 * Copyright (c) 2014 Cesanta Software Limited
3803 * All rights reserved
3804 */
3805
3806#ifndef CS_V7_SRC_STD_ERROR_H_
3807#define CS_V7_SRC_STD_ERROR_H_
3808
3809/* Amalgamated: #include "v7/src/license.h" */
3810
3811struct v7;
3812
3813/*
3814 * JavaScript error types
3815 */
3816#define TYPE_ERROR "TypeError"
3817#define SYNTAX_ERROR "SyntaxError"
3818#define REFERENCE_ERROR "ReferenceError"
3819#define INTERNAL_ERROR "InternalError"
3820#define RANGE_ERROR "RangeError"
3821#define EVAL_ERROR "EvalError"
3822#define ERROR_CTOR_MAX 6
3823/*
3824 * TODO(mkm): EvalError is not so important, we should guard it behind
3825 * something like `V7_ENABLE__EvalError`. However doing so makes it hard to
3826 * keep ERROR_CTOR_MAX up to date; perhaps let's find a better way of doing it.
3827 *
3828 * EvalError is useful mostly because we now have ecma tests failing:
3829 *
3830 * 8129 FAIL ch15/15.4/15.4.4/15.4.4.16/15.4.4.16-7-c-iii-24.js (tail -c
3831 * +7600043 tests/ecmac.db|head -c 496): [{"message":"[EvalError] is not
3832 * defined"}]
3833 *
3834 * Those tests are not EvalError specific, and they do test that the exception
3835 * handling machinery works as intended.
3836 */
3837
3838#if defined(__cplusplus)
3839extern "C" {
3840#endif /* __cplusplus */
3841
3842V7_PRIVATE void init_error(struct v7 *v7);
3843
3844#if defined(__cplusplus)
3845}
3846#endif /* __cplusplus */
3847
3848#endif /* CS_V7_SRC_STD_ERROR_H_ */
3849#ifdef V7_MODULE_LINES
3850#line 1 "v7/src/mm.h"
3851#endif
3852/*
3853 * Copyright (c) 2014 Cesanta Software Limited
3854 * All rights reserved
3855 */
3856
3857#ifndef CS_V7_SRC_MM_H_
3858#define CS_V7_SRC_MM_H_
3859
3860/* Amalgamated: #include "v7/src/internal.h" */
3861
3862typedef void (*gc_cell_destructor_t)(struct v7 *v7, void *);
3863
3864struct gc_block {
3865 struct gc_block *next;
3866 struct gc_cell *base;
3867 size_t size;
3868};
3869
3870struct gc_arena {
3871 struct gc_block *blocks;
3872 size_t size_increment;
3873 struct gc_cell *free; /* head of free list */
3874 size_t cell_size;
3875
3876#if V7_ENABLE__Memory__stats
3877 unsigned long allocations; /* cumulative counter of allocations */
3878 unsigned long garbage; /* cumulative counter of garbage */
3879 unsigned long alive; /* number of living cells */
3880#endif
3881
3882 gc_cell_destructor_t destructor;
3883
3884 int verbose;
3885 const char *name; /* for debugging purposes */
3886};
3887
3888#endif /* CS_V7_SRC_MM_H_ */
3889#ifdef V7_MODULE_LINES
3890#line 1 "v7/src/parser.h"
3891#endif
3892/*
3893 * Copyright (c) 2014 Cesanta Software Limited
3894 * All rights reserved
3895 */
3896
3897#ifndef CS_V7_SRC_PARSER_H_
3898#define CS_V7_SRC_PARSER_H_
3899
3900/* Amalgamated: #include "v7/src/internal.h" */
3901/* Amalgamated: #include "v7/src/core_public.h" */
3902
3903#if !defined(V7_NO_COMPILER)
3904
3905struct v7;
3906struct ast;
3907
3908#if defined(__cplusplus)
3909extern "C" {
3910#endif /* __cplusplus */
3911
3912struct v7_pstate {
3913 const char *file_name;
3914 const char *source_code;
3915 const char *pc; /* Current parsing position */
3916 const char *src_end; /* End of source code */
3917 int line_no; /* Line number */
3918 int prev_line_no; /* Line number of previous token */
3919 int inhibit_in; /* True while `in` expressions are inhibited */
3920 int in_function; /* True if in a function */
3921 int in_loop; /* True if in a loop */
3922 int in_switch; /* True if in a switch block */
3923 int in_strict; /* True if in strict mode */
3924};
3925
3926V7_PRIVATE enum v7_err parse(struct v7 *v7, struct ast *a, const char *src,
3927 size_t src_len, int is_json);
3928
3929#if defined(__cplusplus)
3930}
3931#endif /* __cplusplus */
3932
3933#endif /* V7_NO_COMPILER */
3934
3935#endif /* CS_V7_SRC_PARSER_H_ */
3936#ifdef V7_MODULE_LINES
3937#line 1 "v7/src/object_public.h"
3938#endif
3939/*
3940 * Copyright (c) 2014 Cesanta Software Limited
3941 * All rights reserved
3942 */
3943
3944/*
3945 * === Objects
3946 */
3947
3948#ifndef CS_V7_SRC_OBJECT_PUBLIC_H_
3949#define CS_V7_SRC_OBJECT_PUBLIC_H_
3950
3951/* Amalgamated: #include "v7/src/core_public.h" */
3952
3953#if defined(__cplusplus)
3954extern "C" {
3955#endif /* __cplusplus */
3956
3957/*
3958 * Property attributes bitmask
3959 */
3960typedef unsigned short v7_prop_attr_t;
3961#define V7_PROPERTY_NON_WRITABLE (1 << 0)
3962#define V7_PROPERTY_NON_ENUMERABLE (1 << 1)
3963#define V7_PROPERTY_NON_CONFIGURABLE (1 << 2)
3964#define V7_PROPERTY_GETTER (1 << 3)
3965#define V7_PROPERTY_SETTER (1 << 4)
3966#define _V7_PROPERTY_HIDDEN (1 << 5)
3967/* property not managed by V7 HEAP */
3968#define _V7_PROPERTY_OFF_HEAP (1 << 6)
3969/* special property holding user data and destructor cb */
3970#define _V7_PROPERTY_USER_DATA_AND_DESTRUCTOR (1 << 7)
3971/*
3972 * not a property attribute, but a flag for `v7_def()`. It's here in order to
3973 * keep all offsets in one place
3974 */
3975#define _V7_DESC_PRESERVE_VALUE (1 << 8)
3976
3977#define V7_PROP_ATTR_IS_WRITABLE(a) (!(a & V7_PROPERTY_NON_WRITABLE))
3978#define V7_PROP_ATTR_IS_ENUMERABLE(a) (!(a & V7_PROPERTY_NON_ENUMERABLE))
3979#define V7_PROP_ATTR_IS_CONFIGURABLE(a) (!(a & V7_PROPERTY_NON_CONFIGURABLE))
3980
3981/*
3982 * Internal helpers for `V7_DESC_...` macros
3983 */
3984#define _V7_DESC_SHIFT 16
3985#define _V7_DESC_MASK ((1 << _V7_DESC_SHIFT) - 1)
3986#define _V7_MK_DESC(v, n) \
3987 (((v7_prop_attr_desc_t)(n)) << _V7_DESC_SHIFT | ((v) ? (n) : 0))
3988#define _V7_MK_DESC_INV(v, n) _V7_MK_DESC(!(v), (n))
3989
3990/*
3991 * Property attribute descriptors that may be given to `v7_def()`: for each
3992 * attribute (`v7_prop_attr_t`), there is a corresponding macro, which takes
3993 * param: either 1 (set attribute) or 0 (clear attribute). If some particular
3994 * attribute isn't mentioned at all, it's left unchanged (or default, if the
3995 * property is being created)
3996 *
3997 * There is additional flag: `V7_DESC_PRESERVE_VALUE`. If it is set, the
3998 * property value isn't changed (or set to `undefined` if the property is being
3999 * created)
4000 */
4001typedef unsigned long v7_prop_attr_desc_t;
4002#define V7_DESC_WRITABLE(v) _V7_MK_DESC_INV(v, V7_PROPERTY_NON_WRITABLE)
4003#define V7_DESC_ENUMERABLE(v) _V7_MK_DESC_INV(v, V7_PROPERTY_NON_ENUMERABLE)
4004#define V7_DESC_CONFIGURABLE(v) _V7_MK_DESC_INV(v, V7_PROPERTY_NON_CONFIGURABLE)
4005#define V7_DESC_GETTER(v) _V7_MK_DESC(v, V7_PROPERTY_GETTER)
4006#define V7_DESC_SETTER(v) _V7_MK_DESC(v, V7_PROPERTY_SETTER)
4007#define V7_DESC_PRESERVE_VALUE _V7_DESC_PRESERVE_VALUE
4008
4009#define _V7_DESC_HIDDEN(v) _V7_MK_DESC(v, _V7_PROPERTY_HIDDEN)
4010#define _V7_DESC_OFF_HEAP(v) _V7_MK_DESC(v, _V7_PROPERTY_OFF_HEAP)
4011
4012/* See `v7_set_destructor_cb` */
4013typedef void(v7_destructor_cb_t)(struct v7 *v7, void *ud);
4014
4015/* Make an empty object */
4016v7_val_t v7_mk_object(struct v7 *v7);
4017
4018/*
4019 * Returns true if the given value is an object or function.
4020 * i.e. it returns true if the value holds properties and can be
4021 * used as argument to `v7_get`, `v7_set` and `v7_def`.
4022 */
4023int v7_is_object(v7_val_t v);
4024
4025/* Set object's prototype. Return old prototype or undefined on error. */
4026v7_val_t v7_set_proto(struct v7 *v7, v7_val_t obj, v7_val_t proto);
4027
4028/* Get object's prototype. */
4029v7_val_t v7_get_proto(struct v7 *v7, v7_val_t obj);
4030
4031/*
4032 * Lookup property `name` in object `obj`. If `obj` holds no such property,
4033 * an `undefined` value is returned.
4034 *
4035 * If `name_len` is ~0, `name` is assumed to be NUL-terminated and
4036 * `strlen(name)` is used.
4037 */
4038v7_val_t v7_get(struct v7 *v7, v7_val_t obj, const char *name, size_t name_len);
4039
4040/*
4041 * Like `v7_get()`, but "returns" value through `res` pointer argument.
4042 * `res` must not be `NULL`.
4043 *
4044 * Caller should check the error code returned, and if it's something other
4045 * than `V7_OK`, perform cleanup and return this code further.
4046 */
4047WARN_UNUSED_RESULT
4048enum v7_err v7_get_throwing(struct v7 *v7, v7_val_t obj, const char *name,
4049 size_t name_len, v7_val_t *res);
4050
4051/*
4052 * Define object property, similar to JavaScript `Object.defineProperty()`.
4053 *
4054 * `name`, `name_len` specify property name, `val` is a property value.
4055 * `attrs_desc` is a set of flags which can affect property's attributes,
4056 * see comment of `v7_prop_attr_desc_t` for details.
4057 *
4058 * If `name_len` is ~0, `name` is assumed to be NUL-terminated and
4059 * `strlen(name)` is used.
4060 *
4061 * Returns non-zero on success, 0 on error (e.g. out of memory).
4062 *
4063 * See also `v7_set()`.
4064 */
4065int v7_def(struct v7 *v7, v7_val_t obj, const char *name, size_t name_len,
4066 v7_prop_attr_desc_t attrs_desc, v7_val_t v);
4067
4068/*
4069 * Set object property. Behaves just like JavaScript assignment.
4070 *
4071 * See also `v7_def()`.
4072 */
4073int v7_set(struct v7 *v7, v7_val_t obj, const char *name, size_t len,
4074 v7_val_t val);
4075
4076/*
4077 * A helper function to define object's method backed by a C function `func`.
4078 * `name` must be NUL-terminated.
4079 *
4080 * Return value is the same as for `v7_set()`.
4081 */
4082int v7_set_method(struct v7 *, v7_val_t obj, const char *name,
4083 v7_cfunction_t *func);
4084
4085/*
4086 * Delete own property `name` of the object `obj`. Does not follow the
4087 * prototype chain.
4088 *
4089 * If `name_len` is ~0, `name` is assumed to be NUL-terminated and
4090 * `strlen(name)` is used.
4091 *
4092 * Returns 0 on success, -1 on error.
4093 */
4094int v7_del(struct v7 *v7, v7_val_t obj, const char *name, size_t name_len);
4095
4096#if V7_ENABLE__Proxy
4097struct prop_iter_proxy_ctx;
4098#endif
4099
4100/*
4101 * Context for property iteration, see `v7_next_prop()`.
4102 *
4103 * Clients should not interpret contents of this structure, it's here merely to
4104 * allow clients to allocate it not from the heap.
4105 */
4106struct prop_iter_ctx {
4107#if V7_ENABLE__Proxy
4108 struct prop_iter_proxy_ctx *proxy_ctx;
4109#endif
4110 struct v7_property *cur_prop;
4111
4112 unsigned init : 1;
4113};
4114
4115/*
4116 * Initialize the property iteration context `ctx`, see `v7_next_prop()` for
4117 * usage example.
4118 */
4119enum v7_err v7_init_prop_iter_ctx(struct v7 *v7, v7_val_t obj,
4120 struct prop_iter_ctx *ctx);
4121
4122/*
4123 * Destruct the property iteration context `ctx`, see `v7_next_prop()` for
4124 * usage example
4125 */
4126void v7_destruct_prop_iter_ctx(struct v7 *v7, struct prop_iter_ctx *ctx);
4127
4128/*
4129 * Iterate over the `obj`'s properties.
4130 *
4131 * Usage example (here we assume we have some `v7_val_t obj`):
4132 *
4133 * struct prop_iter_ctx ctx;
4134 * v7_val_t name, val;
4135 * v7_prop_attr_t attrs;
4136 *
4137 * v7_init_prop_iter_ctx(v7, obj, &ctx);
4138 * while (v7_next_prop(v7, &ctx, &name, &val, &attrs)) {
4139 * if (V7_PROP_ATTR_IS_ENUMERABLE(attrs)) continue;
4140 * ...
4141 * }
4142 * v7_destruct_prop_iter_ctx(v7, &ctx);
4143 *
4144 * As you see, v7_next_prop will iterate through all properties, including
4145 * non-enumerable ones, and it's your responsibility to test the attributes
4146 * with the provided `V7_PROP_ATTR_*` macros and proceed as you see fit.
4147 */
4148int v7_next_prop(struct v7 *v7, struct prop_iter_ctx *ctx, v7_val_t *name,
4149 v7_val_t *value, v7_prop_attr_t *attrs);
4150
4151/* Returns true if the object is an instance of a given constructor. */
4152int v7_is_instanceof(struct v7 *v7, v7_val_t o, const char *c);
4153
4154/* Returns true if the object is an instance of a given constructor. */
4155int v7_is_instanceof_v(struct v7 *v7, v7_val_t o, v7_val_t c);
4156
4157/*
4158 * Associates an opaque C value (anything that can be casted to a `void * )
4159 * with an object.
4160 *
4161 * You can achieve a similar effect by just setting a special property with
4162 * a foreign value (see `v7_mk_foreign`), except user data offers the following
4163 * advantages:
4164 *
4165 * 1. You don't have to come up with some arbitrary "special" property name.
4166 * 2. JS scripts cannot access user data by mistake via property lookup.
4167 * 3. The user data is available to the destructor. When the desctructor is
4168 * invoked you cannot access any of its properties.
4169 * 4. Allows the implementation to use a more compact encoding
4170 *
4171 * Does nothing if `obj` is not a mutable object.
4172 */
4173void v7_set_user_data(struct v7 *v7, v7_val_t obj, void *ud);
4174
4175/*
4176 * Get the opaque user data set with `v7_set_user_data`.
4177 *
4178 * Returns NULL if there is no user data set or if `obj` is not an object.
4179 */
4180void *v7_get_user_data(struct v7 *v7, v7_val_t obj);
4181
4182/*
4183 * Register a callback which will be invoked when a given object gets
4184 * reclaimed by the garbage collector.
4185 *
4186 * The callback will be invoked while garbage collection is still in progress
4187 * and hence the internal state of the JS heap is in an undefined state.
4188 *
4189 * The only v7 API which is safe to use in this callback is `v7_disown()`,
4190 * that's why `v7` pointer is given to it. *Calls to any other v7 functions are
4191 * illegal here*.
4192 *
4193 * The intended use case is to reclaim resources allocated by C code.
4194 */
4195void v7_set_destructor_cb(struct v7 *v7, v7_val_t obj, v7_destructor_cb_t *d);
4196
4197#if defined(__cplusplus)
4198}
4199#endif /* __cplusplus */
4200
4201#endif /* CS_V7_SRC_OBJECT_PUBLIC_H_ */
4202#ifdef V7_MODULE_LINES
4203#line 1 "v7/src/tokenizer.h"
4204#endif
4205/*
4206 * Copyright (c) 2014 Cesanta Software Limited
4207 * All rights reserved
4208 */
4209
4210#ifndef CS_V7_SRC_TOKENIZER_H_
4211#define CS_V7_SRC_TOKENIZER_H_
4212
4213/* Amalgamated: #include "v7/src/internal.h" */
4214
4215#if !defined(V7_NO_COMPILER)
4216
4217enum v7_tok {
4218 TOK_END_OF_INPUT,
4219 TOK_NUMBER,
4220 TOK_STRING_LITERAL,
4221 TOK_REGEX_LITERAL,
4222 TOK_IDENTIFIER,
4223
4224 /* Punctuators */
4225 TOK_OPEN_CURLY,
4226 TOK_CLOSE_CURLY,
4227 TOK_OPEN_PAREN,
4228 TOK_CLOSE_PAREN,
4229 TOK_COMMA,
4230 TOK_OPEN_BRACKET,
4231 TOK_CLOSE_BRACKET,
4232 TOK_DOT,
4233 TOK_COLON,
4234 TOK_SEMICOLON,
4235
4236 /* Equality ops, in this order */
4237 TOK_EQ,
4238 TOK_EQ_EQ,
4239 TOK_NE,
4240 TOK_NE_NE,
4241
4242 /* Assigns */
4243 TOK_ASSIGN,
4244 TOK_REM_ASSIGN,
4245 TOK_MUL_ASSIGN,
4246 TOK_DIV_ASSIGN,
4247 TOK_XOR_ASSIGN,
4248 TOK_PLUS_ASSIGN,
4249 TOK_MINUS_ASSIGN,
4250 TOK_OR_ASSIGN,
4251 TOK_AND_ASSIGN,
4252 TOK_LSHIFT_ASSIGN,
4253 TOK_RSHIFT_ASSIGN,
4254 TOK_URSHIFT_ASSIGN,
4255 TOK_AND,
4256 TOK_LOGICAL_OR,
4257 TOK_PLUS,
4258 TOK_MINUS,
4259 TOK_PLUS_PLUS,
4260 TOK_MINUS_MINUS,
4261 TOK_LOGICAL_AND,
4262 TOK_OR,
4263 TOK_QUESTION,
4264 TOK_TILDA,
4265 TOK_REM,
4266 TOK_MUL,
4267 TOK_DIV,
4268 TOK_XOR,
4269
4270 /* Relational ops, must go in this order */
4271 TOK_LE,
4272 TOK_LT,
4273 TOK_GE,
4274 TOK_GT,
4275 TOK_LSHIFT,
4276 TOK_RSHIFT,
4277 TOK_URSHIFT,
4278 TOK_NOT,
4279
4280 /* Keywords. must be in the same order as tokenizer.c::s_keywords array */
4281 TOK_BREAK,
4282 TOK_CASE,
4283 TOK_CATCH,
4284 TOK_CONTINUE,
4285 TOK_DEBUGGER,
4286 TOK_DEFAULT,
4287 TOK_DELETE,
4288 TOK_DO,
4289 TOK_ELSE,
4290 TOK_FALSE,
4291 TOK_FINALLY,
4292 TOK_FOR,
4293 TOK_FUNCTION,
4294 TOK_IF,
4295 TOK_IN,
4296 TOK_INSTANCEOF,
4297 TOK_NEW,
4298 TOK_NULL,
4299 TOK_RETURN,
4300 TOK_SWITCH,
4301 TOK_THIS,
4302 TOK_THROW,
4303 TOK_TRUE,
4304 TOK_TRY,
4305 TOK_TYPEOF,
4306 TOK_VAR,
4307 TOK_VOID,
4308 TOK_WHILE,
4309 TOK_WITH,
4310
4311 /* TODO(lsm): process these reserved words too */
4312 TOK_CLASS,
4313 TOK_ENUM,
4314 TOK_EXTENDS,
4315 TOK_SUPER,
4316 TOK_CONST,
4317 TOK_EXPORT,
4318 TOK_IMPORT,
4319 TOK_IMPLEMENTS,
4320 TOK_LET,
4321 TOK_PRIVATE,
4322 TOK_PUBLIC,
4323 TOK_INTERFACE,
4324 TOK_PACKAGE,
4325 TOK_PROTECTED,
4326 TOK_STATIC,
4327 TOK_YIELD,
4328
4329 NUM_TOKENS
4330};
4331
4332#if defined(__cplusplus)
4333extern "C" {
4334#endif /* __cplusplus */
4335
4336V7_PRIVATE int skip_to_next_tok(const char **ptr, const char *src_end);
4337V7_PRIVATE enum v7_tok get_tok(const char **s, const char *src_end, double *n,
4338 enum v7_tok prev_tok);
4339V7_PRIVATE int is_reserved_word_token(enum v7_tok tok);
4340
4341#if defined(__cplusplus)
4342}
4343#endif /* __cplusplus */
4344
4345#endif /* V7_NO_COMPILER */
4346
4347#endif /* CS_V7_SRC_TOKENIZER_H_ */
4348#ifdef V7_MODULE_LINES
4349#line 1 "v7/src/opcodes.h"
4350#endif
4351/*
4352 * Copyright (c) 2014 Cesanta Software Limited
4353 * All rights reserved
4354 */
4355
4356#ifndef CS_V7_SRC_OPCODES_H_
4357#define CS_V7_SRC_OPCODES_H_
4358
4359/*
4360 * ==== Instructions
4361 *
4362 * Bytecode instructions consist of 1-byte opcode, optionally followed by N
4363 * bytes of arguments.
4364 *
4365 * Opcodes that accept an index in the literal table (PUSH_LIT, GET_VAR,
4366 * SET_VAR, ...) also accept inline literals. In order to distinguish indices in
4367 * the literals table and the inline literals, indices 0 and 1 are reserved as
4368 * type tags for inline literals:
4369 *
4370 * if 0, the following bytes encode a string literal
4371 * if 1, they encode a number (textual, like in the AST)
4372 *
4373 * (see enum bcode_inline_lit_type_tag)
4374 *
4375 *
4376 * Stack diagrams follow the syntax and semantics of:
4377 *
4378 * http://everything2.com/title/Forth+stack+diagrams[Forth stack diagrams].
4379 *
4380 * We use the following extension in the terminology:
4381 *
4382 * `T`: "Try stack".
4383 * `A`: opcode arguments.
4384 * `S`: stash register (one element stack).
4385 *
4386 */
4387enum opcode {
4388 /*
4389 * Removes an item from the top of the stack. It is undefined what happens if
4390 * the stack is empty.
4391 *
4392 * `( a -- )`
4393 */
4394 OP_DROP,
4395 /*
4396 * Duplicates a value on top of the stack.
4397 *
4398 * `( a -- a a)`
4399 */
4400 OP_DUP,
4401 /*
4402 * Duplicates 2 values from the top of the stack in the same order.
4403 *
4404 * `( a b -- a b a b)`
4405 */
4406 OP_2DUP,
4407 /*
4408 * Swap the top two items on the stack.
4409 *
4410 * `( a b -- b a )`
4411 */
4412 OP_SWAP,
4413 /*
4414 * Copy current top of the stack to the temporary stash register.
4415 *
4416 * The content of the stash register will be cleared in the event of an
4417 * exception.
4418 *
4419 * `( a S: b -- a S: a)` saves TOS to stash reg
4420 */
4421 OP_STASH,
4422 /*
4423 * Replace the top of the stack with the content of the temporary stash
4424 * register.
4425 *
4426 * The stash register is cleared afterwards.
4427 *
4428 * `( a S: b -- b S: nil )` replaces tos with stash reg
4429 */
4430 OP_UNSTASH,
4431
4432 /*
4433 * Effectively drops the last-but-one element from stack
4434 *
4435 * `( a b -- b )`
4436 */
4437 OP_SWAP_DROP,
4438
4439 /*
4440 * Pushes `undefined` onto the stack.
4441 *
4442 * `( -- undefined )`
4443 */
4444 OP_PUSH_UNDEFINED,
4445 /*
4446 * Pushes `null` onto the stack.
4447 *
4448 * `( -- null )`
4449 */
4450 OP_PUSH_NULL,
4451 /*
4452 * Pushes current value of `this` onto the stack.
4453 *
4454 * `( -- this )`
4455 */
4456 OP_PUSH_THIS,
4457 /*
4458 * Pushes `true` onto the stack.
4459 *
4460 * `( -- true )`
4461 */
4462 OP_PUSH_TRUE,
4463 /*
4464 * Pushes `false` onto the stack.
4465 *
4466 * `( -- false )`
4467 */
4468 OP_PUSH_FALSE,
4469 /*
4470 * Pushes `0` onto the stack.
4471 *
4472 * `( -- 0 )`
4473 */
4474 OP_PUSH_ZERO,
4475 /*
4476 * Pushes `1` onto the stack.
4477 *
4478 * `( -- 1 )`
4479 */
4480 OP_PUSH_ONE,
4481
4482 /*
4483 * Pushes a value from literals table onto the stack.
4484 *
4485 * The opcode takes a varint operand interpreted as an index in the current
4486 * literal table (see lit table).
4487 *
4488 * ( -- a )
4489 */
4490 OP_PUSH_LIT,
4491
4492 OP_NOT,
4493 OP_LOGICAL_NOT,
4494
4495 /*
4496 * Takes a number from the top of the stack, inverts the sign and pushes it
4497 * back.
4498 *
4499 * `( a -- -a )`
4500 */
4501 OP_NEG,
4502 /*
4503 * Takes a number from the top of the stack pushes the evaluation of
4504 * `Number()`.
4505 *
4506 * `( a -- Number(a) )`
4507 */
4508 OP_POS,
4509
4510 /*
4511 * Takes 2 values from the top of the stack and performs addition operation:
4512 * If any of the two values is not `undefined`, number or boolean, both values
4513 * are converted into strings and concatenated.
4514 * Otherwise, both values are treated as numbers:
4515 * * `undefined` is converted into NaN
4516 * * `true` is converted into 1
4517 * * `false` is converted into 0
4518 *
4519 * Result is pushed back onto the stack.
4520 *
4521 * TODO: make it behave exactly like JavaScript's `+` operator.
4522 *
4523 * `( a b -- a+b )`
4524 */
4525 OP_ADD,
4526 OP_SUB, /* ( a b -- a-b ) */
4527 OP_REM, /* ( a b -- a%b ) */
4528 OP_MUL, /* ( a b -- a*b ) */
4529 OP_DIV, /* ( a b -- a/b ) */
4530 OP_LSHIFT, /* ( a b -- a<<b ) */
4531 OP_RSHIFT, /* ( a b -- a>>b ) */
4532 OP_URSHIFT, /* ( a b -- a>>>b ) */
4533 OP_OR, /* ( a b -- a|b ) */
4534 OP_XOR, /* ( a b -- a^b ) */
4535 OP_AND, /* ( a b -- a&b ) */
4536
4537 /*
4538 * Takes two numbers form the top of the stack and pushes `true` if they are
4539 * equal, or `false` if they are not equal.
4540 *
4541 * ( a b -- a===b )
4542 */
4543 OP_EQ_EQ,
4544 OP_EQ, /* ( a b -- a==b ) */
4545 OP_NE, /* ( a b -- a!=b ) */
4546 OP_NE_NE, /* ( a b -- a!==b ) */
4547 OP_LT, /* ( a b -- a<b ) */
4548 OP_LE, /* ( a b -- a<=b ) */
4549 OP_GT, /* ( a b -- a>b ) */
4550 OP_GE, /* ( a b -- a>=b ) */
4551 OP_INSTANCEOF,
4552
4553 OP_TYPEOF,
4554
4555 OP_IN,
4556 /*
4557 * Takes 2 values from the stack, treats the top of the stack as property name
4558 * and the next value must be an object, an array or a string.
4559 * If it's an object, pushes the value of its named property onto the stack.
4560 * If it's an array or a string, returns a value at a given position.
4561 */
4562 OP_GET,
4563 /*
4564 * Takes 3 items from the stack: value, property name, object. Sets the given
4565 * property of a given object to a given value, pushes value back onto the
4566 *stack.
4567 *
4568 * `( a b c -- a[b]=c )`
4569 */
4570 OP_SET,
4571 /*
4572 * Takes 1 value from the stack and a varint argument -- index of the var name
4573 * in the literals table. Tries to find the variable in the current scope
4574 * chain and assign the value to it. If the varialble is not found -- creates
4575 * a new one in the global scope. Pushes the value back to the stack.
4576 *
4577 * `( a -- a )`
4578 */
4579 OP_SET_VAR,
4580 /*
4581 * Takes a varint argument -- index of the var name in the literals table.
4582 * Looks up that variable in the scope chain and pushes its value onto the
4583 * stack.
4584 *
4585 * `( -- a )`
4586 */
4587 OP_GET_VAR,
4588
4589 /*
4590 * Like OP_GET_VAR but returns undefined
4591 * instead of throwing reference error.
4592 *
4593 * `( -- a )`
4594 */
4595 OP_SAFE_GET_VAR,
4596
4597 /*
4598 * ==== Jumps
4599 *
4600 * All jump instructions take one 4-byte argument: offset to jump to. Offset
4601 *is a
4602 * index of the byte in the instruction stream, starting with 0. No byte order
4603 * conversion is applied.
4604 *
4605 * TODO: specify byte order for the offset.
4606 */
4607
4608 /*
4609 * Unconditiona jump.
4610 */
4611 OP_JMP,
4612 /*
4613 * Takes one value from the stack and performs a jump if conversion of that
4614 * value to boolean results in `true`.
4615 *
4616 * `( a -- )`
4617 */
4618 OP_JMP_TRUE,
4619 /*
4620 * Takes one value from the stack and performs a jump if conversion of that
4621 * value to boolean results in `false`.
4622 *
4623 * `( a -- )`
4624 */
4625 OP_JMP_FALSE,
4626 /*
4627 * Like OP_JMP_TRUE but if the branch
4628 * is taken it also drops another stack element:
4629 *
4630 * if `b` is true: `( a b -- )`
4631 * if `b` is false: `( a b -- a )`
4632 */
4633 OP_JMP_TRUE_DROP,
4634
4635 /*
4636 * Conditional jump on the v7->is_continuing flag.
4637 * Clears the flag once executed.
4638 *
4639 * `( -- )`
4640 */
4641 OP_JMP_IF_CONTINUE,
4642
4643 /*
4644 * Constructs a new empty object and pushes it onto the stack.
4645 *
4646 * `( -- {} )`
4647 */
4648 OP_CREATE_OBJ,
4649 /*
4650 * Constructs a new empty array and pushes it onto the stack.
4651 *
4652 * `( -- [] )`
4653 */
4654 OP_CREATE_ARR,
4655
4656 /*
4657 * Allocates the iteration context (for `OP_NEXT_PROP`) from heap and pushes
4658 * a foreign pointer to it on stack. The allocated data is stored as "user
4659 * data" of the object, and it will be reclaimed automatically when the
4660 * object gets garbage-collected.
4661 *
4662 * `( -- ctx )`
4663 */
4664 OP_PUSH_PROP_ITER_CTX,
4665
4666 /*
4667 * Yields the next property name.
4668 * Used in the for..in construct.
4669 *
4670 * The first evaluation must receive `null` as handle.
4671 * Subsequent evaluations will either:
4672 *
4673 * a) produce a new handle, the key and true value:
4674 *
4675 * `( o h -- o h' key true)`
4676 *
4677 * b) produce a false value only, indicating no more properties:
4678 *
4679 * `( o h -- false)`
4680 */
4681 OP_NEXT_PROP,
4682
4683 /*
4684 * Copies the function object at TOS and assigns current scope
4685 * in func->scope.
4686 *
4687 * `( a -- a )`
4688 */
4689 OP_FUNC_LIT,
4690 /*
4691 * Takes the number of arguments as parameter.
4692 *
4693 * Pops N function arguments from stack, then pops function, then pops `this`.
4694 * Calls a function and populates TOS with the returned value.
4695 *
4696 * `( this f a0 a1 ... aN -- f(a0,a1,...) )`
4697 */
4698 OP_CALL,
4699 OP_NEW,
4700 /*
4701 * Checks that TOS is a callable and if not saves an exception
4702 * that will will be thrown by CALL after all arguments have been evaluated.
4703 */
4704 OP_CHECK_CALL,
4705 /*
4706 * Returns the current function.
4707 *
4708 * It has no stack side effects. The function upon return will leave the
4709 * return value on the stack. The return value must be pushed on the stack
4710 * prior to invoking a RET.
4711 *
4712 * `( -- )`
4713 */
4714 OP_RET,
4715
4716 /*
4717 * Deletes the property of given name `p` from the given object `o`. Returns
4718 * boolean value `a`.
4719 *
4720 * `( o p -- a )`
4721 */
4722 OP_DELETE,
4723
4724 /*
4725 * Like `OP_DELETE`, but uses the current scope as an object to delete
4726 * a property from.
4727 *
4728 * `( p -- a )`
4729 */
4730 OP_DELETE_VAR,
4731
4732 /*
4733 * Pushes a value (bcode offset of `catch` block) from opcode argument to
4734 * "try stack".
4735 *
4736 * Used in the beginning of the `try` block.
4737 *
4738 * `( A: a -- T: a )`
4739 */
4740 OP_TRY_PUSH_CATCH,
4741
4742 /*
4743 * Pushes a value (bcode offset of `finally` block) from opcode argument to
4744 * "try stack".
4745 *
4746 * Used in the beginning of the `try` block.
4747 *
4748 * `( A: a -- T: a )`
4749 *
4750 * TODO: implement me
4751 */
4752 OP_TRY_PUSH_FINALLY,
4753
4754 /*
4755 * Pushes a value (bcode offset of a label) from opcode argument to
4756 * "try stack".
4757 *
4758 * Used at the beginning of loops that contain break or continue.
4759 * Possible optimisation: don't emit if we can ensure that no break or
4760 * continue statement is used.
4761 *
4762 * `( A: a -- T: a )`
4763 */
4764 OP_TRY_PUSH_LOOP,
4765
4766 /*
4767 * Pushes a value (bcode offset of a label) from opcode argument to
4768 * "try stack".
4769 *
4770 * Used at the beginning of switch statements.
4771 *
4772 * `( A: a -- T: a )`
4773 */
4774 OP_TRY_PUSH_SWITCH,
4775
4776 /*
4777 * Pops a value (bcode offset of `finally` or `catch` block) from "try
4778 * stack", and discards it
4779 *
4780 * Used in the end of the `try` block, as well as in the beginning of the
4781 * `catch` and `finally` blocks
4782 *
4783 * `( T: a -- T: )`
4784 */
4785 OP_TRY_POP,
4786
4787 /*
4788 * Used in the end of the `finally` block:
4789 *
4790 * - if some value is currently being thrown, keep throwing it.
4791 * If eventually we encounter `catch` block, the thrown value gets
4792 * populated on TOS:
4793 *
4794 * `( -- a )`
4795 *
4796 * - if there is some pending value to return, keep returning it.
4797 * If we encounter no further `finally` blocks, then the returned value
4798 * gets populated on TOS:
4799 *
4800 * `( -- a )`
4801 *
4802 * And return is performed.
4803 *
4804 * - otherwise, do nothing
4805 */
4806 OP_AFTER_FINALLY,
4807
4808 /*
4809 * Throw value from TOS. First of all, it pops the value and saves it into
4810 * `v7->vals.thrown_error`:
4811 *
4812 * `( a -- )`
4813 *
4814 * Then unwinds stack looking for the first `catch` or `finally` blocks.
4815 *
4816 * - if `finally` is found, thrown value is kept into `v7->vals.thrown_error`.
4817 * - if `catch` is found, thrown value is pushed back to the stack:
4818 * `( -- a )`
4819 * - otherwise, thrown value is kept into `v7->vals.thrown_error`
4820 */
4821 OP_THROW,
4822
4823 /*
4824 * Unwind to next break entry in the try stack, evaluating
4825 * all finally blocks on its way up.
4826 *
4827 * `( -- )`
4828 */
4829 OP_BREAK,
4830
4831 /*
4832 * Like OP_BREAK, but sets the v7->is_continuing flag
4833 * which will cause OP_JMP_IF_CONTINUE to restart the loop.
4834 *
4835 * `( -- )`
4836 */
4837 OP_CONTINUE,
4838
4839 /*
4840 * Used when we enter the `catch` block. Takes a varint argument -- index of
4841 * the exception variable name in the literals table.
4842 *
4843 * Pops the exception value from the stack, creates a private frame,
4844 * sets exception property on it with the given name. pushes this
4845 * private frame to call stack.
4846 *
4847 * `( e -- )`
4848 */
4849 OP_ENTER_CATCH,
4850
4851 /*
4852 * Ued when we exit from the `catch` block. Merely pops the private frame
4853 * from the call stack.
4854 *
4855 * `( -- )`
4856 */
4857 OP_EXIT_CATCH,
4858
4859 OP_MAX,
4860};
4861
4862#define _OP_LINE_NO 0x80
4863
4864#endif /* CS_V7_SRC_OPCODES_H_ */
4865#ifdef V7_MODULE_LINES
4866#line 1 "v7/src/core.h"
4867#endif
4868/*
4869 * Copyright (c) 2014 Cesanta Software Limited
4870 * All rights reserved
4871 */
4872
4873#ifndef CS_V7_SRC_CORE_H_
4874#define CS_V7_SRC_CORE_H_
4875
4876/* Amalgamated: #include "v7/src/core_public.h" */
4877
4878/* Amalgamated: #include "common/mbuf.h" */
4879/* Amalgamated: #include "v7/src/std_error.h" */
4880/* Amalgamated: #include "v7/src/mm.h" */
4881/* Amalgamated: #include "v7/src/parser.h" */
4882/* Amalgamated: #include "v7/src/object_public.h" */
4883/* Amalgamated: #include "v7/src/tokenizer.h" */
4884/* Amalgamated: #include "v7/src/opcodes.h" */
4885
4886#if defined(__cplusplus)
4887extern "C" {
4888#endif /* __cplusplus */
4889
4890typedef uint64_t val_t;
4891
4892#if V7_ENABLE_ENTITY_IDS
4893
4894typedef unsigned short entity_id_t;
4895typedef unsigned char entity_id_part_t;
4896
4897/*
4898 * Magic numbers that are stored in various objects in order to identify their
4899 * type in runtime
4900 */
4901#define V7_ENTITY_ID_PROP 0xe9a1
4902#define V7_ENTITY_ID_PART_OBJ 0x57
4903#define V7_ENTITY_ID_PART_GEN_OBJ 0x31
4904#define V7_ENTITY_ID_PART_JS_FUNC 0x0d
4905
4906#define V7_ENTITY_ID_NONE 0xa5a5
4907#define V7_ENTITY_ID_PART_NONE 0xa5
4908
4909#endif
4910
4911/*
4912 * Double-precision floating-point number, IEEE 754
4913 *
4914 * 64 bit (8 bytes) in total
4915 * 1 bit sign
4916 * 11 bits exponent
4917 * 52 bits mantissa
4918 * 7 6 5 4 3 2 1 0
4919 * seeeeeee|eeeemmmm|mmmmmmmm|mmmmmmmm|mmmmmmmm|mmmmmmmm|mmmmmmmm|mmmmmmmm
4920 *
4921 * If an exponent is all-1 and mantissa is all-0, then it is an INFINITY:
4922 * 11111111|11110000|00000000|00000000|00000000|00000000|00000000|00000000
4923 *
4924 * If an exponent is all-1 and mantissa's MSB is 1, it is a quiet NaN:
4925 * 11111111|11111000|00000000|00000000|00000000|00000000|00000000|00000000
4926 *
4927 * V7 NaN-packing:
4928 * sign and exponent is 0xfff
4929 * 4 bits specify type (tag), must be non-zero
4930 * 48 bits specify value
4931 *
4932 * 11111111|1111tttt|vvvvvvvv|vvvvvvvv|vvvvvvvv|vvvvvvvv|vvvvvvvv|vvvvvvvv
4933 * NaN marker |type| 48-bit placeholder for values: pointers, strings
4934 *
4935 * On 64-bit platforms, pointers are really 48 bit only, so they can fit,
4936 * provided they are sign extended
4937 */
4938
4939/*
4940 * A tag is made of the sign bit and the 4 lower order bits of byte 6.
4941 * So in total we have 32 possible tags.
4942 *
4943 * Tag (1,0) however cannot hold a zero payload otherwise it's interpreted as an
4944 * INFINITY; for simplicity we're just not going to use that combination.
4945 */
4946#define MAKE_TAG(s, t) \
4947 ((uint64_t)(s) << 63 | (uint64_t) 0x7ff0 << 48 | (uint64_t)(t) << 48)
4948
4949#define V7_TAG_OBJECT MAKE_TAG(1, 0xF)
4950#define V7_TAG_FOREIGN MAKE_TAG(1, 0xE)
4951#define V7_TAG_UNDEFINED MAKE_TAG(1, 0xD)
4952#define V7_TAG_BOOLEAN MAKE_TAG(1, 0xC)
4953#define V7_TAG_NAN MAKE_TAG(1, 0xB)
4954#define V7_TAG_STRING_I MAKE_TAG(1, 0xA) /* Inlined string len < 5 */
4955#define V7_TAG_STRING_5 MAKE_TAG(1, 0x9) /* Inlined string len 5 */
4956#define V7_TAG_STRING_O MAKE_TAG(1, 0x8) /* Owned string */
4957#define V7_TAG_STRING_F MAKE_TAG(1, 0x7) /* Foreign string */
4958#define V7_TAG_STRING_C MAKE_TAG(1, 0x6) /* String chunk */
4959#define V7_TAG_FUNCTION MAKE_TAG(1, 0x5) /* JavaScript function */
4960#define V7_TAG_CFUNCTION MAKE_TAG(1, 0x4) /* C function */
4961#define V7_TAG_STRING_D MAKE_TAG(1, 0x3) /* Dictionary string */
4962#define V7_TAG_REGEXP MAKE_TAG(1, 0x2) /* Regex */
4963#define V7_TAG_NOVALUE MAKE_TAG(1, 0x1) /* Sentinel for no value */
4964#define V7_TAG_MASK MAKE_TAG(1, 0xF)
4965
4966#define _V7_NULL V7_TAG_FOREIGN
4967#define _V7_UNDEFINED V7_TAG_UNDEFINED
4968
4969V7_STATIC_ASSERT(_V7_NULL == V7_NULL, public_V7_NULL_is_wrong);
4970V7_STATIC_ASSERT(_V7_UNDEFINED == V7_UNDEFINED, public_V7_UNDEFINED_is_wrong);
4971
4972/*
4973 * Object attributes bitmask
4974 */
4975typedef unsigned char v7_obj_attr_t;
4976#define V7_OBJ_NOT_EXTENSIBLE (1 << 0) /* TODO(lsm): store this in LSB */
4977#define V7_OBJ_DENSE_ARRAY (1 << 1) /* TODO(mkm): store in some tag */
4978#define V7_OBJ_FUNCTION (1 << 2) /* function object */
4979#define V7_OBJ_OFF_HEAP (1 << 3) /* object not managed by V7 HEAP */
4980#define V7_OBJ_HAS_DESTRUCTOR (1 << 4) /* has user data */
4981#define V7_OBJ_PROXY (1 << 5) /* it's a Proxy object */
4982
4983/*
4984 * JavaScript value is either a primitive, or an object.
4985 * There are 5 primitive types: Undefined, Null, Boolean, Number, String.
4986 * Non-primitive type is an Object type. There are several classes of Objects,
4987 * see description of `struct v7_generic_object` below for more details.
4988 * This enumeration combines types and object classes in one enumeration.
4989 * NOTE(lsm): compile with `-fshort-enums` to reduce sizeof(enum v7_type) to 1.
4990 */
4991enum v7_type {
4992 /* Primitive types */
4993 V7_TYPE_UNDEFINED,
4994 V7_TYPE_NULL,
4995 V7_TYPE_BOOLEAN,
4996 V7_TYPE_NUMBER,
4997 V7_TYPE_STRING,
4998 V7_TYPE_FOREIGN,
4999 V7_TYPE_CFUNCTION,
5000
5001 /* Different classes of Object type */
5002 V7_TYPE_GENERIC_OBJECT,
5003 V7_TYPE_BOOLEAN_OBJECT,
5004 V7_TYPE_STRING_OBJECT,
5005 V7_TYPE_NUMBER_OBJECT,
5006 V7_TYPE_FUNCTION_OBJECT,
5007 V7_TYPE_CFUNCTION_OBJECT,
5008 V7_TYPE_REGEXP_OBJECT,
5009 V7_TYPE_ARRAY_OBJECT,
5010 V7_TYPE_DATE_OBJECT,
5011 V7_TYPE_ERROR_OBJECT,
5012 V7_TYPE_MAX_OBJECT_TYPE,
5013 V7_NUM_TYPES
5014};
5015
5016/*
5017 * Call frame type mask: we have a "class hierarchy" of the call frames, see
5018 * `struct v7_call_frame_base`, and the `type_mask` field represents the exact
5019 * frame type.
5020 *
5021 * Possible values are:
5022 *
5023 * - `V7_CALL_FRAME_MASK_PRIVATE | V7_CALL_FRAME_MASK_BCODE`: the most popular
5024 * frame type: call frame for bcode execution, either top-level code or JS
5025 * function.
5026 * - `V7_CALL_FRAME_MASK_PRIVATE`: used for `catch` clauses only: the variables
5027 * we create in `catch` clause should not be visible from the outside of the
5028 * clause, so we have to create a separate scope object for it.
5029 * - `V7_CALL_FRAME_MASK_CFUNC`: call frame for C function.
5030 */
5031typedef uint8_t v7_call_frame_mask_t;
5032#define V7_CALL_FRAME_MASK_BCODE (1 << 0)
5033#define V7_CALL_FRAME_MASK_PRIVATE (1 << 1)
5034#define V7_CALL_FRAME_MASK_CFUNC (1 << 2)
5035
5036/*
5037 * Base of the call frame; includes the pointer to the previous frame,
5038 * and the frame type.
5039 *
5040 * In order to save memory, it also contains some bitfields which actually
5041 * belong to some "sub-structures".
5042 *
5043 * The hierarchy is as follows:
5044 *
5045 * - v7_call_frame_base
5046 * - v7_call_frame_private
5047 * - v7_call_frame_bcode
5048 * - v7_call_frame_cfunc
5049 */
5050struct v7_call_frame_base {
5051 struct v7_call_frame_base *prev;
5052
5053 /* See comment for `v7_call_frame_mask_t` */
5054 v7_call_frame_mask_t type_mask : 3;
5055
5056 /* Belongs to `struct v7_call_frame_private` */
5057 unsigned int line_no : 16;
5058
5059 /* Belongs to `struct v7_call_frame_bcode` */
5060 unsigned is_constructor : 1;
5061
5062 /* Belongs to `struct v7_call_frame_bcode` */
5063 unsigned int is_thrown : 1;
5064};
5065
5066/*
5067 * "private" call frame, used in `catch` blocks, merely for using a separate
5068 * scope object there. It is also a "base class" for the bcode call frame,
5069 * see `struct v7_call_frame_bcode`.
5070 *
5071 * TODO(dfrank): probably implement it differently, so that we can get rid of
5072 * the separate "private" frames whatsoever (and just include it into struct
5073 * v7_call_frame_bcode )
5074 */
5075struct v7_call_frame_private {
5076 struct v7_call_frame_base base;
5077 size_t stack_size;
5078 struct {
5079 /*
5080 * Current execution scope. Initially, it is equal to the `global_object`;
5081 * and at each function call, it is augmented by the new scope object, which
5082 * has the previous value as a prototype.
5083 */
5084 val_t scope;
5085
5086 val_t try_stack;
5087 } vals;
5088};
5089
5090/*
5091 * "bcode" call frame, augments "private" frame with `bcode` and the position
5092 * in it, and `this` object. It is the primary frame type, used when executing
5093 * a bcode script or calling a function.
5094 */
5095struct v7_call_frame_bcode {
5096 struct v7_call_frame_private base;
5097 struct {
5098 val_t this_obj;
5099 val_t thrown_error;
5100 } vals;
5101 struct bcode *bcode;
5102 char *bcode_ops;
5103};
5104
5105/*
5106 * "cfunc" call frame, used when calling cfunctions.
5107 */
5108struct v7_call_frame_cfunc {
5109 struct v7_call_frame_base base;
5110
5111 struct {
5112 val_t this_obj;
5113 } vals;
5114
5115 v7_cfunction_t *cfunc;
5116};
5117
5118/*
5119 * This structure groups together all val_t logical members
5120 * of struct v7 so that GC and freeze logic can easily access all
5121 * of them together. This structure must contain only val_t members.
5122 */
5123struct v7_vals {
5124 val_t global_object;
5125
5126 val_t arguments; /* arguments of current call */
5127
5128 val_t object_prototype;
5129 val_t array_prototype;
5130 val_t boolean_prototype;
5131 val_t error_prototype;
5132 val_t string_prototype;
5133 val_t regexp_prototype;
5134 val_t number_prototype;
5135 val_t date_prototype;
5136 val_t function_prototype;
5137 val_t proxy_prototype;
5138
5139 /*
5140 * temporary register for `OP_STASH` and `OP_UNSTASH` instructions. Valid if
5141 * `v7->is_stashed` is non-zero
5142 */
5143 val_t stash;
5144
5145 val_t error_objects[ERROR_CTOR_MAX];
5146
5147 /*
5148 * Value that is being thrown. Valid if `is_thrown` is non-zero (see below)
5149 */
5150 val_t thrown_error;
5151
5152 /*
5153 * value that is going to be returned. Needed when some `finally` block needs
5154 * to be executed after `return my_value;` was issued. Used in bcode.
5155 * See also `is_returned` below
5156 */
5157 val_t returned_value;
5158
5159 val_t last_name[2]; /* used for error reporting */
5160 /* most recent OP_CHECK_CALL exceptions, to be thrown by OP_CALL|OP_NEW */
5161 val_t call_check_ex;
5162};
5163
5164struct v7 {
5165 struct v7_vals vals;
5166
5167 /*
5168 * Stack of call frames.
5169 *
5170 * Execution contexts are contained in two chains:
5171 * - Stack of call frames: to allow returning, throwing, and stack trace
5172 * generation;
5173 * - In the lexical scope via their prototype chain (to allow variable
5174 * lookup), see `struct v7_call_frame_private::scope`.
5175 *
5176 * Execution contexts should be allocated on heap, because they might not be
5177 * on a call stack but still referenced (closures).
5178 *
5179 * New call frame is created every time some top-level code is evaluated,
5180 * or some code is being `eval`-d, or some function is called, either JS
5181 * function or C function (although the call frame types are different for
5182 * JS functions and cfunctions, see `struct v7_call_frame_base` and its
5183 * sub-structures)
5184 *
5185 * When no code is being evaluated at the moment, `call_stack` is `NULL`.
5186 *
5187 * See comment for `struct v7_call_frame_base` for some more details.
5188 */
5189 struct v7_call_frame_base *call_stack;
5190
5191 /*
5192 * Bcode executes until it reaches `bottom_call_frame`. When some top-level
5193 * or `eval`-d code starts execution, the `bottom_call_frame` is set to the
5194 * call frame which was just created for the execution.
5195 */
5196 struct v7_call_frame_base *bottom_call_frame;
5197
5198 struct mbuf stack; /* value stack for bcode interpreter */
5199
5200 struct mbuf owned_strings; /* Sequence of (varint len, char data[]) */
5201 struct mbuf foreign_strings; /* Sequence of (varint len, char *data) */
5202
5203 struct mbuf tmp_stack; /* Stack of val_t* elements, used as root set */
5204 int need_gc; /* Set to true to trigger GC when safe */
5205
5206 struct gc_arena generic_object_arena;
5207 struct gc_arena function_arena;
5208 struct gc_arena property_arena;
5209#if V7_ENABLE__Memory__stats
5210 size_t function_arena_ast_size;
5211 size_t bcode_ops_size;
5212 size_t bcode_lit_total_size;
5213 size_t bcode_lit_deser_size;
5214#endif
5215 struct mbuf owned_values; /* buffer for GC roots owned by C code */
5216
5217 /*
5218 * Stack of the root bcodes being executed at the moment. Note that when some
5219 * regular JS function is called inside `eval_bcode()`, the function's bcode
5220 * is NOT added here. Buf if some cfunction is called, which in turn calls
5221 * `b_exec()` (or `b_apply()`) recursively, the new bcode is added to this
5222 * stack.
5223 */
5224 struct mbuf act_bcodes;
5225
5226 char error_msg[80]; /* Exception message */
5227
5228 struct mbuf json_visited_stack; /* Detecting cycle in to_json */
5229
5230/* Parser state */
5231#if !defined(V7_NO_COMPILER)
5232 struct v7_pstate pstate; /* Parsing state */
5233 enum v7_tok cur_tok; /* Current token */
5234 const char *tok; /* Parsed terminal token (ident, number, string) */
5235 unsigned long tok_len; /* Length of the parsed terminal token */
5236 size_t last_var_node; /* Offset of last var node or function/script node */
5237 int after_newline; /* True if the cur_tok starts a new line */
5238 double cur_tok_dbl; /* When tokenizing, parser stores TOK_NUMBER here */
5239
5240 /*
5241 * Current linenumber. Currently it is used by parser, compiler and bcode
5242 * evaluator.
5243 *
5244 * - Parser: it's the last line_no emitted to AST
5245 * - Compiler: it's the last line_no emitted to bcode
5246 */
5247 int line_no;
5248#endif /* V7_NO_COMPILER */
5249
5250 /* singleton, pointer because of amalgamation */
5251 struct v7_property *cur_dense_prop;
5252
5253 volatile int interrupted;
5254#ifdef V7_STACK_SIZE
5255 void *sp_limit;
5256 void *sp_lwm;
5257#endif
5258
5259#if defined(V7_CYG_PROFILE_ON)
5260 /* linked list of v7 contexts, needed by cyg_profile hooks */
5261 struct v7 *next_v7;
5262
5263#if V7_ENABLE_STACK_TRACKING
5264 /* linked list of stack tracking contexts */
5265 struct stack_track_ctx *stack_track_ctx;
5266
5267 int stack_stat[V7_STACK_STATS_CNT];
5268#endif
5269
5270#endif
5271
5272#ifdef V7_MALLOC_GC
5273 struct mbuf malloc_trace;
5274#endif
5275
5276/*
5277 * TODO(imax): remove V7_DISABLE_STR_ALLOC_SEQ knob after 2015/12/01 if there
5278 * are no issues.
5279 */
5280#if !V7_DISABLE_STR_ALLOC_SEQ
5281 uint16_t gc_next_asn; /* Next sequence number to use. */
5282 uint16_t gc_min_asn; /* Minimal sequence number currently in use. */
5283#endif
5284
5285#if defined(V7_TRACK_MAX_PARSER_STACK_SIZE)
5286 size_t parser_stack_data_max_size;
5287 size_t parser_stack_ret_max_size;
5288 size_t parser_stack_data_max_len;
5289 size_t parser_stack_ret_max_len;
5290#endif
5291
5292#ifdef V7_FREEZE
5293 FILE *freeze_file;
5294#endif
5295
5296 /*
5297 * true if exception is currently being created. Needed to avoid recursive
5298 * exception creation
5299 */
5300 unsigned int creating_exception : 1;
5301 /* while true, GC is inhibited */
5302 unsigned int inhibit_gc : 1;
5303 /* true if `thrown_error` is valid */
5304 unsigned int is_thrown : 1;
5305 /* true if `returned_value` is valid */
5306 unsigned int is_returned : 1;
5307 /* true if a finally block is executing while breaking */
5308 unsigned int is_breaking : 1;
5309 /* true when a continue OP is executed, reset by `OP_JMP_IF_CONTINUE` */
5310 unsigned int is_continuing : 1;
5311 /* true if some value is currently stashed (`v7->vals.stash`) */
5312 unsigned int is_stashed : 1;
5313 /* true if last emitted statement does not affect data stack */
5314 unsigned int is_stack_neutral : 1;
5315 /* true if precompiling; affects compiler bcode choices */
5316 unsigned int is_precompiling : 1;
5317
5318 enum opcode last_ops[2]; /* trace of last ops, used for error reporting */
5319};
5320
5321struct v7_property {
5322 struct v7_property *
5323 next; /* Linkage in struct v7_generic_object::properties */
5324 v7_prop_attr_t attributes;
5325#if V7_ENABLE_ENTITY_IDS
5326 entity_id_t entity_id;
5327#endif
5328 val_t name; /* Property name (a string) */
5329 val_t value; /* Property value */
5330};
5331
5332/*
5333 * "base object": structure which is shared between objects and functions.
5334 */
5335struct v7_object {
5336 /* First HIDDEN property in a chain is an internal object value */
5337 struct v7_property *properties;
5338 v7_obj_attr_t attributes;
5339#if V7_ENABLE_ENTITY_IDS
5340 entity_id_part_t entity_id_base;
5341 entity_id_part_t entity_id_spec;
5342#endif
5343};
5344
5345/*
5346 * An object is an unordered collection of properties.
5347 * A function stored in a property of an object is called a method.
5348 * A property has a name, a value, and set of attributes.
5349 * Attributes are: ReadOnly, DontEnum, DontDelete, Internal.
5350 *
5351 * A constructor is a function that creates and initializes objects.
5352 * Each constructor has an associated prototype object that is used for
5353 * inheritance and shared properties. When a constructor creates an object,
5354 * the new object references the constructor’s prototype.
5355 *
5356 * Objects could be a "generic objects" which is a collection of properties,
5357 * or a "typed object" which also hold an internal value like String or Number.
5358 * Those values are implicit, unnamed properties of the respective types,
5359 * and can be coerced into primitive types by calling a respective constructor
5360 * as a function:
5361 * var a = new Number(123);
5362 * typeof(a) == 'object';
5363 * typeof(Number(a)) == 'number';
5364 */
5365struct v7_generic_object {
5366 /*
5367 * This has to be the first field so that objects can be managed by the GC.
5368 */
5369 struct v7_object base;
5370 struct v7_object *prototype;
5371};
5372
5373/*
5374 * Variables are function-scoped and are hoisted.
5375 * Lexical scoping & closures: each function has a chain of scopes, defined
5376 * by the lexicographic order of function definitions.
5377 * Scope is different from the execution context.
5378 * Execution context carries "variable object" which is variable/value
5379 * mapping for all variables defined in a function, and `this` object.
5380 * If function is not called as a method, then `this` is a global object.
5381 * Otherwise, `this` is an object that contains called method.
5382 * New execution context is created each time a function call is performed.
5383 * Passing arguments through recursion is done using execution context, e.g.
5384 *
5385 * var factorial = function(num) {
5386 * return num < 2 ? 1 : num * factorial(num - 1);
5387 * };
5388 *
5389 * Here, recursion calls the same function `factorial` several times. Execution
5390 * contexts for each call form a stack. Each context has different variable
5391 * object, `vars`, with different values of `num`.
5392 */
5393
5394struct v7_js_function {
5395 /*
5396 * Functions are objects. This has to be the first field so that function
5397 * objects can be managed by the GC.
5398 */
5399 struct v7_object base;
5400 struct v7_generic_object *scope; /* lexical scope of the closure */
5401
5402 /* bytecode, might be shared between functions */
5403 struct bcode *bcode;
5404};
5405
5406struct v7_regexp {
5407 val_t regexp_string;
5408 struct slre_prog *compiled_regexp;
5409 long lastIndex;
5410};
5411
5412/* Vector, describes some memory location pointed by `p` with length `len` */
5413struct v7_vec {
5414 char *p;
5415 size_t len;
5416};
5417
5418/*
5419 * Constant vector, describes some const memory location pointed by `p` with
5420 * length `len`
5421 */
5422struct v7_vec_const {
5423 const char *p;
5424 size_t len;
5425};
5426
5427#define V7_VEC(str) \
5428 { (str), sizeof(str) - 1 }
5429
5430/*
5431 * Returns current execution scope.
5432 *
5433 * See comment for `struct v7_call_frame_private::vals::scope`
5434 */
5435V7_PRIVATE v7_val_t get_scope(struct v7 *v7);
5436
5437/*
5438 * Returns 1 if currently executing bcode in the "strict mode", 0 otherwise
5439 */
5440V7_PRIVATE uint8_t is_strict_mode(struct v7 *v7);
5441
5442#if defined(__cplusplus)
5443}
5444#endif /* __cplusplus */
5445
5446#endif /* CS_V7_SRC_CORE_H_ */
5447#ifdef V7_MODULE_LINES
5448#line 1 "v7/src/primitive_public.h"
5449#endif
5450/*
5451 * Copyright (c) 2014 Cesanta Software Limited
5452 * All rights reserved
5453 */
5454
5455/*
5456 * === Primitives
5457 *
5458 * All primitive values but strings.
5459 *
5460 * "foreign" values are also here, see `v7_mk_foreign()`.
5461 */
5462
5463#ifndef CS_V7_SRC_PRIMITIVE_PUBLIC_H_
5464#define CS_V7_SRC_PRIMITIVE_PUBLIC_H_
5465
5466/* Amalgamated: #include "v7/src/core_public.h" */
5467
5468#if defined(__cplusplus)
5469extern "C" {
5470#endif /* __cplusplus */
5471
5472/* Make numeric primitive value */
5473NOINSTR v7_val_t v7_mk_number(struct v7 *v7, double num);
5474
5475/*
5476 * Returns number value stored in `v7_val_t` as `double`.
5477 *
5478 * Returns NaN for non-numbers.
5479 */
5480NOINSTR double v7_get_double(struct v7 *v7, v7_val_t v);
5481
5482/*
5483 * Returns number value stored in `v7_val_t` as `int`. If the number value is
5484 * not an integer, the fraction part will be discarded.
5485 *
5486 * If the given value is a non-number, or NaN, the result is undefined.
5487 */
5488NOINSTR int v7_get_int(struct v7 *v7, v7_val_t v);
5489
5490/* Returns true if given value is a primitive number value */
5491int v7_is_number(v7_val_t v);
5492
5493/* Make boolean primitive value (either `true` or `false`) */
5494NOINSTR v7_val_t v7_mk_boolean(struct v7 *v7, int is_true);
5495
5496/*
5497 * Returns boolean stored in `v7_val_t`:
5498 * 0 for `false` or non-boolean, non-0 for `true`
5499 */
5500NOINSTR int v7_get_bool(struct v7 *v7, v7_val_t v);
5501
5502/* Returns true if given value is a primitive boolean value */
5503int v7_is_boolean(v7_val_t v);
5504
5505/*
5506 * Make `null` primitive value.
5507 *
5508 * NOTE: this function is deprecated and will be removed in future releases.
5509 * Use `V7_NULL` instead.
5510 */
5511NOINSTR v7_val_t v7_mk_null(void);
5512
5513/* Returns true if given value is a primitive `null` value */
5514int v7_is_null(v7_val_t v);
5515
5516/*
5517 * Make `undefined` primitive value.
5518 *
5519 * NOTE: this function is deprecated and will be removed in future releases.
5520 * Use `V7_UNDEFINED` instead.
5521 */
5522NOINSTR v7_val_t v7_mk_undefined(void);
5523
5524/* Returns true if given value is a primitive `undefined` value */
5525int v7_is_undefined(v7_val_t v);
5526
5527/*
5528 * Make JavaScript value that holds C/C++ `void *` pointer.
5529 *
5530 * A foreign value is completely opaque and JS code cannot do anything useful
5531 * with it except holding it in properties and passing it around.
5532 * It behaves like a sealed object with no properties.
5533 *
5534 * NOTE:
5535 * Only valid pointers (as defined by each supported architecture) will fully
5536 * preserved. In particular, all supported 64-bit architectures (x86_64, ARM-64)
5537 * actually define a 48-bit virtual address space.
5538 * Foreign values will be sign-extended as required, i.e creating a foreign
5539 * value of something like `(void *) -1` will work as expected. This is
5540 * important because in some 64-bit OSs (e.g. Solaris) the user stack grows
5541 * downwards from the end of the address space.
5542 *
5543 * If you need to store exactly sizeof(void*) bytes of raw data where
5544 * `sizeof(void*)` >= 8, please use byte arrays instead.
5545 */
5546NOINSTR v7_val_t v7_mk_foreign(struct v7 *v7, void *ptr);
5547
5548/*
5549 * Returns `void *` pointer stored in `v7_val_t`.
5550 *
5551 * Returns NULL if the value is not a foreign pointer.
5552 */
5553NOINSTR void *v7_get_ptr(struct v7 *v7, v7_val_t v);
5554
5555/* Returns true if given value holds `void *` pointer */
5556int v7_is_foreign(v7_val_t v);
5557
5558#if defined(__cplusplus)
5559}
5560#endif /* __cplusplus */
5561
5562#endif /* CS_V7_SRC_PRIMITIVE_PUBLIC_H_ */
5563#ifdef V7_MODULE_LINES
5564#line 1 "v7/src/primitive.h"
5565#endif
5566/*
5567 * Copyright (c) 2014 Cesanta Software Limited
5568 * All rights reserved
5569 */
5570
5571#ifndef CS_V7_SRC_PRIMITIVE_H_
5572#define CS_V7_SRC_PRIMITIVE_H_
5573
5574/* Amalgamated: #include "v7/src/primitive_public.h" */
5575
5576/* Amalgamated: #include "v7/src/core.h" */
5577
5578/* Returns true if given value is a number, not NaN and not Infinity. */
5579V7_PRIVATE int is_finite(struct v7 *v7, v7_val_t v);
5580
5581V7_PRIVATE val_t pointer_to_value(void *p);
5582V7_PRIVATE void *get_ptr(val_t v);
5583
5584#endif /* CS_V7_SRC_PRIMITIVE_H_ */
5585#ifdef V7_MODULE_LINES
5586#line 1 "v7/src/string_public.h"
5587#endif
5588/*
5589 * Copyright (c) 2014 Cesanta Software Limited
5590 * All rights reserved
5591 */
5592
5593/*
5594 * === Strings
5595 */
5596
5597#ifndef CS_V7_SRC_STRING_PUBLIC_H_
5598#define CS_V7_SRC_STRING_PUBLIC_H_
5599
5600/* Amalgamated: #include "v7/src/core_public.h" */
5601
5602#if defined(__cplusplus)
5603extern "C" {
5604#endif /* __cplusplus */
5605
5606/*
5607 * Creates a string primitive value.
5608 * `str` must point to the utf8 string of length `len`.
5609 * If `len` is ~0, `str` is assumed to be NUL-terminated and `strlen(str)` is
5610 * used.
5611 *
5612 * If `copy` is non-zero, the string data is copied and owned by the GC. The
5613 * caller can free the string data afterwards. Otherwise (`copy` is zero), the
5614 * caller owns the string data, and is responsible for not freeing it while it
5615 * is used.
5616 */
5617v7_val_t v7_mk_string(struct v7 *v7, const char *str, size_t len, int copy);
5618
5619/* Returns true if given value is a primitive string value */
5620int v7_is_string(v7_val_t v);
5621
5622/*
5623 * Returns a pointer to the string stored in `v7_val_t`.
5624 *
5625 * String length returned in `len`, which is allowed to be NULL. Returns NULL
5626 * if the value is not a string.
5627 *
5628 * JS strings can contain embedded NUL chars and may or may not be NUL
5629 * terminated.
5630 *
5631 * CAUTION: creating new JavaScript object, array, or string may kick in a
5632 * garbage collector, which in turn may relocate string data and invalidate
5633 * pointer returned by `v7_get_string()`.
5634 *
5635 * Short JS strings are embedded inside the `v7_val_t` value itself. This is why
5636 * a pointer to a `v7_val_t` is required. It also means that the string data
5637 * will become invalid once that `v7_val_t` value goes out of scope.
5638 */
5639const char *v7_get_string(struct v7 *v7, v7_val_t *v, size_t *len);
5640
5641/*
5642 * Returns a pointer to the string stored in `v7_val_t`.
5643 *
5644 * Returns NULL if the value is not a string or if the string is not compatible
5645 * with a C string.
5646 *
5647 * C compatible strings contain exactly one NUL char, in terminal position.
5648 *
5649 * All strings owned by the V7 engine (see `v7_mk_string()`) are guaranteed to
5650 * be NUL terminated. Out of these, those that don't include embedded NUL chars
5651 * are guaranteed to be C compatible.
5652 */
5653const char *v7_get_cstring(struct v7 *v7, v7_val_t *v);
5654
5655#if defined(__cplusplus)
5656}
5657#endif /* __cplusplus */
5658
5659#endif /* CS_V7_SRC_STRING_PUBLIC_H_ */
5660#ifdef V7_MODULE_LINES
5661#line 1 "v7/src/string.h"
5662#endif
5663/*
5664 * Copyright (c) 2014 Cesanta Software Limited
5665 * All rights reserved
5666 */
5667
5668#ifndef CS_V7_SRC_STRING_H_
5669#define CS_V7_SRC_STRING_H_
5670
5671/* Amalgamated: #include "v7/src/string_public.h" */
5672
5673/* Amalgamated: #include "v7/src/core.h" */
5674
5675/*
5676 * Size of the extra space for strings mbuf that is needed to avoid frequent
5677 * reallocations
5678 */
5679#define _V7_STRING_BUF_RESERVE 500
5680
5681#if defined(__cplusplus)
5682extern "C" {
5683#endif /* __cplusplus */
5684
5685WARN_UNUSED_RESULT
5686V7_PRIVATE enum v7_err v7_char_code_at(struct v7 *v7, v7_val_t s, v7_val_t at,
5687 double *res);
5688V7_PRIVATE int s_cmp(struct v7 *, val_t a, val_t b);
5689V7_PRIVATE val_t s_concat(struct v7 *, val_t, val_t);
5690
5691/*
5692 * Convert a C string to to an unsigned integer.
5693 * `ok` will be set to true if the string conforms to
5694 * an unsigned long.
5695 */
5696WARN_UNUSED_RESULT
5697V7_PRIVATE enum v7_err str_to_ulong(struct v7 *v7, val_t v, int *ok,
5698 unsigned long *res);
5699
5700/*
5701 * Convert a V7 string to to an unsigned integer.
5702 * `ok` will be set to true if the string conforms to
5703 * an unsigned long.
5704 *
5705 * Use it if only you need strong conformity of the value to an integer;
5706 * otherwise, use `to_long()` or `to_number_v()` instead.
5707 */
5708V7_PRIVATE unsigned long cstr_to_ulong(const char *s, size_t len, int *ok);
5709
5710enum embstr_flags {
5711 EMBSTR_ZERO_TERM = (1 << 0),
5712 EMBSTR_UNESCAPE = (1 << 1),
5713};
5714
5715V7_PRIVATE void embed_string(struct mbuf *m, size_t offset, const char *p,
5716 size_t len, uint8_t /*enum embstr_flags*/ flags);
5717
5718V7_PRIVATE size_t unescape(const char *s, size_t len, char *to);
5719
5720#if defined(__cplusplus)
5721}
5722#endif /* __cplusplus */
5723
5724#endif /* CS_V7_SRC_STRING_H_ */
5725#ifdef V7_MODULE_LINES
5726#line 1 "v7/src/exceptions_public.h"
5727#endif
5728/*
5729 * Copyright (c) 2014 Cesanta Software Limited
5730 * All rights reserved
5731 */
5732
5733/*
5734 * === Exceptions
5735 */
5736
5737#ifndef CS_V7_SRC_EXCEPTIONS_PUBLIC_H_
5738#define CS_V7_SRC_EXCEPTIONS_PUBLIC_H_
5739
5740/* Amalgamated: #include "v7/src/core_public.h" */
5741
5742#if defined(__cplusplus)
5743extern "C" {
5744#endif /* __cplusplus */
5745
5746/* Throw an exception with an already existing value. */
5747WARN_UNUSED_RESULT
5748enum v7_err v7_throw(struct v7 *v7, v7_val_t v);
5749
5750/*
5751 * Throw an exception with given formatted message.
5752 *
5753 * Pass "Error" as typ for a generic error.
5754 */
5755WARN_UNUSED_RESULT
5756enum v7_err v7_throwf(struct v7 *v7, const char *typ, const char *err_fmt, ...);
5757
5758/*
5759 * Rethrow the currently thrown object. In fact, it just returns
5760 * V7_EXEC_EXCEPTION.
5761 */
5762WARN_UNUSED_RESULT
5763enum v7_err v7_rethrow(struct v7 *v7);
5764
5765/*
5766 * Returns the value that is being thrown at the moment, or `undefined` if
5767 * nothing is being thrown. If `is_thrown` is not `NULL`, it will be set
5768 * to either 0 or 1, depending on whether something is thrown at the moment.
5769 */
5770v7_val_t v7_get_thrown_value(struct v7 *v7, unsigned char *is_thrown);
5771
5772/* Clears currently thrown value, if any. */
5773void v7_clear_thrown_value(struct v7 *v7);
5774
5775#if defined(__cplusplus)
5776}
5777#endif /* __cplusplus */
5778
5779#endif /* CS_V7_SRC_EXCEPTIONS_PUBLIC_H_ */
5780#ifdef V7_MODULE_LINES
5781#line 1 "v7/src/exceptions.h"
5782#endif
5783/*
5784 * Copyright (c) 2014 Cesanta Software Limited
5785 * All rights reserved
5786 */
5787
5788#ifndef CS_V7_SRC_EXCEPTIONS_H_
5789#define CS_V7_SRC_EXCEPTIONS_H_
5790
5791/* Amalgamated: #include "v7/src/exceptions_public.h" */
5792
5793/* Amalgamated: #include "v7/src/core.h" */
5794
5795/*
5796 * Try to perform some arbitrary call, and if the result is other than `V7_OK`,
5797 * "throws" an error with `V7_THROW()`
5798 */
5799#define V7_TRY2(call, clean_label) \
5800 do { \
5801 enum v7_err _e = call; \
5802 V7_CHECK2(_e == V7_OK, _e, clean_label); \
5803 } while (0)
5804
5805/*
5806 * Sets return value to the provided one, and `goto`s `clean`.
5807 *
5808 * For this to work, you should have local `enum v7_err rcode` variable,
5809 * and a `clean` label.
5810 */
5811#define V7_THROW2(err_code, clean_label) \
5812 do { \
5813 (void) v7; \
5814 rcode = (err_code); \
5815 assert(rcode != V7_OK); \
5816 assert(!v7_is_undefined(v7->vals.thrown_error) && v7->is_thrown); \
5817 goto clean_label; \
5818 } while (0)
5819
5820/*
5821 * Checks provided condition `cond`, and if it's false, then "throws"
5822 * provided `err_code` (see `V7_THROW()`)
5823 */
5824#define V7_CHECK2(cond, err_code, clean_label) \
5825 do { \
5826 if (!(cond)) { \
5827 V7_THROW2(err_code, clean_label); \
5828 } \
5829 } while (0)
5830
5831/*
5832 * Checks provided condition `cond`, and if it's false, then "throws"
5833 * internal error
5834 *
5835 * TODO(dfrank): it would be good to have formatted string: then, we can
5836 * specify file and line.
5837 */
5838#define V7_CHECK_INTERNAL2(cond, clean_label) \
5839 do { \
5840 if (!(cond)) { \
5841 enum v7_err __rcode = v7_throwf(v7, "Error", "Internal error"); \
5842 (void) __rcode; \
5843 V7_THROW2(V7_INTERNAL_ERROR, clean_label); \
5844 } \
5845 } while (0)
5846
5847/*
5848 * Shortcuts for the macros above, but they assume the clean label `clean`.
5849 */
5850
5851#define V7_TRY(call) V7_TRY2(call, clean)
5852#define V7_THROW(err_code) V7_THROW2(err_code, clean)
5853#define V7_CHECK(cond, err_code) V7_CHECK2(cond, err_code, clean)
5854#define V7_CHECK_INTERNAL(cond) V7_CHECK_INTERNAL2(cond, clean)
5855
5856#if defined(__cplusplus)
5857extern "C" {
5858#endif /* __cplusplus */
5859
5860/*
5861 * At the moment, most of the exception-related functions are public, and are
5862 * declared in `exceptions_public.h`
5863 */
5864
5865/*
5866 * Create an instance of the exception with type `typ` (see `TYPE_ERROR`,
5867 * `SYNTAX_ERROR`, etc), and message `msg`.
5868 */
5869V7_PRIVATE enum v7_err create_exception(struct v7 *v7, const char *typ,
5870 const char *msg, val_t *res);
5871
5872#if defined(__cplusplus)
5873}
5874#endif /* __cplusplus */
5875
5876#endif /* CS_V7_SRC_EXCEPTIONS_H_ */
5877#ifdef V7_MODULE_LINES
5878#line 1 "v7/src/object.h"
5879#endif
5880/*
5881 * Copyright (c) 2014 Cesanta Software Limited
5882 * All rights reserved
5883 */
5884
5885#ifndef CS_V7_SRC_OBJECT_H_
5886#define CS_V7_SRC_OBJECT_H_
5887
5888/* Amalgamated: #include "v7/src/object_public.h" */
5889
5890/* Amalgamated: #include "v7/src/internal.h" */
5891/* Amalgamated: #include "v7/src/core.h" */
5892
5893V7_PRIVATE val_t mk_object(struct v7 *v7, val_t prototype);
5894V7_PRIVATE val_t v7_object_to_value(struct v7_object *o);
5895V7_PRIVATE struct v7_generic_object *get_generic_object_struct(val_t v);
5896
5897/*
5898 * Returns pointer to the struct representing an object.
5899 * Given value must be an object (the caller can verify it
5900 * by calling `v7_is_object()`)
5901 */
5902V7_PRIVATE struct v7_object *get_object_struct(v7_val_t v);
5903
5904/*
5905 * Return true if given value is a JavaScript object (will return
5906 * false for function)
5907 */
5908V7_PRIVATE int v7_is_generic_object(v7_val_t v);
5909
5910V7_PRIVATE struct v7_property *v7_mk_property(struct v7 *v7);
5911
5912V7_PRIVATE struct v7_property *v7_get_own_property2(struct v7 *v7, val_t obj,
5913 const char *name,
5914 size_t len,
5915 v7_prop_attr_t attrs);
5916
5917V7_PRIVATE struct v7_property *v7_get_own_property(struct v7 *v7, val_t obj,
5918 const char *name,
5919 size_t len);
5920
5921/*
5922 * If `len` is -1/MAXUINT/~0, then `name` must be 0-terminated
5923 *
5924 * Returns a pointer to the property structure, given an object and a name of
5925 * the property as a pointer to string buffer and length.
5926 *
5927 * See also `v7_get_property_v`
5928 */
5929V7_PRIVATE struct v7_property *v7_get_property(struct v7 *v7, val_t obj,
5930 const char *name, size_t len);
5931
5932/*
5933 * Just like `v7_get_property`, but takes name as a `v7_val_t`
5934 */
5935V7_PRIVATE enum v7_err v7_get_property_v(struct v7 *v7, val_t obj,
5936 v7_val_t name,
5937 struct v7_property **res);
5938
5939WARN_UNUSED_RESULT
5940V7_PRIVATE enum v7_err v7_get_throwing_v(struct v7 *v7, v7_val_t obj,
5941 v7_val_t name, v7_val_t *res);
5942
5943V7_PRIVATE void v7_destroy_property(struct v7_property **p);
5944
5945WARN_UNUSED_RESULT
5946V7_PRIVATE enum v7_err v7_invoke_setter(struct v7 *v7, struct v7_property *prop,
5947 val_t obj, val_t val);
5948
5949/*
5950 * Like `set_property`, but takes property name as a `val_t`
5951 */
5952WARN_UNUSED_RESULT
5953V7_PRIVATE enum v7_err set_property_v(struct v7 *v7, val_t obj, val_t name,
5954 val_t val, struct v7_property **res);
5955
5956/*
5957 * Like JavaScript assignment: set a property with given `name` + `len` at
5958 * the object `obj` to value `val`. Returns a property through the `res`
5959 * (which may be `NULL` if return value is not required)
5960 */
5961WARN_UNUSED_RESULT
5962V7_PRIVATE enum v7_err set_property(struct v7 *v7, val_t obj, const char *name,
5963 size_t len, v7_val_t val,
5964 struct v7_property **res);
5965
5966/*
5967 * Like `def_property()`, but takes property name as a `val_t`
5968 */
5969WARN_UNUSED_RESULT
5970V7_PRIVATE enum v7_err def_property_v(struct v7 *v7, val_t obj, val_t name,
5971 v7_prop_attr_desc_t attrs_desc, val_t val,
5972 uint8_t as_assign,
5973 struct v7_property **res);
5974
5975/*
5976 * Define object property, similar to JavaScript `Object.defineProperty()`.
5977 *
5978 * Just like public `v7_def()`, but returns `enum v7_err`, and therefore can
5979 * throw.
5980 *
5981 * Additionally, takes param `as_assign`: if it is non-zero, it behaves
5982 * similarly to plain JavaScript assignment in terms of some exception-related
5983 * corner cases.
5984 *
5985 * `res` may be `NULL`.
5986 */
5987WARN_UNUSED_RESULT
5988V7_PRIVATE enum v7_err def_property(struct v7 *v7, val_t obj, const char *name,
5989 size_t len, v7_prop_attr_desc_t attrs_desc,
5990 v7_val_t val, uint8_t as_assign,
5991 struct v7_property **res);
5992
5993V7_PRIVATE int set_method(struct v7 *v7, val_t obj, const char *name,
5994 v7_cfunction_t *func, int num_args);
5995
5996V7_PRIVATE int set_cfunc_prop(struct v7 *v7, val_t o, const char *name,
5997 v7_cfunction_t *func);
5998
5999/* Return address of property value or NULL if the passed property is NULL */
6000WARN_UNUSED_RESULT
6001V7_PRIVATE enum v7_err v7_property_value(struct v7 *v7, val_t obj,
6002 struct v7_property *p, val_t *res);
6003
6004#if V7_ENABLE__Proxy
6005/*
6006 * Additional context for property iteration of a proxied object, see
6007 * `v7_next_prop()`.
6008 */
6009struct prop_iter_proxy_ctx {
6010 /* Proxy target object */
6011 v7_val_t target_obj;
6012 /* Proxy handler object */
6013 v7_val_t handler_obj;
6014
6015 /*
6016 * array returned by the `ownKeys` callback, valid if only `has_own_keys` is
6017 * set
6018 */
6019 v7_val_t own_keys;
6020 /*
6021 * callback to get property descriptor, one of these:
6022 * - a JS or cfunction `getOwnPropertyDescriptor`
6023 * (if `has_get_own_prop_desc_C` is not set);
6024 * - a C callback `v7_get_own_prop_desc_cb_t`.
6025 * (if `has_get_own_prop_desc_C` is set);
6026 */
6027 v7_val_t get_own_prop_desc;
6028
6029 /*
6030 * if `has_own_keys` is set, `own_key_idx` represents next index in the
6031 * `own_keys` array
6032 */
6033 unsigned own_key_idx : 29;
6034
6035 /* if set, `own_keys` is valid */
6036 unsigned has_own_keys : 1;
6037 /* if set, `get_own_prop_desc` is valid */
6038 unsigned has_get_own_prop_desc : 1;
6039 /*
6040 * if set, `get_own_prop_desc` is a C callback `has_get_own_prop_desc_C`, not
6041 * a JS callback
6042 */
6043 unsigned has_get_own_prop_desc_C : 1;
6044};
6045#endif
6046
6047/*
6048 * Like public function `v7_init_prop_iter_ctx()`, but it takes additional
6049 * argument `proxy_transp`; if it is zero, and the given `obj` is a Proxy, it
6050 * will iterate the properties of the proxy itself, not the Proxy's target.
6051 */
6052WARN_UNUSED_RESULT
6053V7_PRIVATE enum v7_err init_prop_iter_ctx(struct v7 *v7, v7_val_t obj,
6054 int proxy_transp,
6055 struct prop_iter_ctx *ctx);
6056
6057WARN_UNUSED_RESULT
6058V7_PRIVATE enum v7_err next_prop(struct v7 *v7, struct prop_iter_ctx *ctx,
6059 v7_val_t *name, v7_val_t *value,
6060 v7_prop_attr_t *attrs, int *ok);
6061
6062/*
6063 * Set new prototype `proto` for the given object `obj`. Returns `0` at
6064 * success, `-1` at failure (it may fail if given `obj` is a function object:
6065 * it's impossible to change function object's prototype)
6066 */
6067V7_PRIVATE int obj_prototype_set(struct v7 *v7, struct v7_object *obj,
6068 struct v7_object *proto);
6069
6070/*
6071 * Given a pointer to the object structure, returns a
6072 * pointer to the prototype object, or `NULL` if there is
6073 * no prototype.
6074 */
6075V7_PRIVATE struct v7_object *obj_prototype(struct v7 *v7,
6076 struct v7_object *obj);
6077
6078V7_PRIVATE int is_prototype_of(struct v7 *v7, val_t o, val_t p);
6079
6080/* Get the property holding user data and destructor, or NULL */
6081V7_PRIVATE struct v7_property *get_user_data_property(v7_val_t obj);
6082
6083#endif /* CS_V7_SRC_OBJECT_H_ */
6084#ifdef V7_MODULE_LINES
6085#line 1 "v7/src/exec_public.h"
6086#endif
6087/*
6088 * Copyright (c) 2014 Cesanta Software Limited
6089 * All rights reserved
6090 */
6091
6092/*
6093 * === Execution of JavaScript code
6094 */
6095
6096#ifndef CS_V7_SRC_EXEC_PUBLIC_H_
6097#define CS_V7_SRC_EXEC_PUBLIC_H_
6098
6099/* Amalgamated: #include "v7/src/core_public.h" */
6100
6101#if defined(__cplusplus)
6102extern "C" {
6103#endif /* __cplusplus */
6104
6105/*
6106 * Execute JavaScript `js_code`. The result of evaluation is stored in
6107 * the `result` variable.
6108 * The code can be either a JavaScript source or a precompiled bytecode.
6109 *
6110 * Return:
6111 *
6112 * - V7_OK on success. `result` contains the result of execution.
6113 * - V7_SYNTAX_ERROR if `js_code` in not a valid code. `result` is undefined.
6114 * - V7_EXEC_EXCEPTION if `js_code` threw an exception. `result` stores
6115 * an exception object.
6116 * - V7_AST_TOO_LARGE if `js_code` contains an AST segment longer than 16 bit.
6117 * `result` is undefined. To avoid this error, build V7 with V7_LARGE_AST.
6118 */
6119WARN_UNUSED_RESULT
6120enum v7_err v7_exec(struct v7 *v7, const char *js_code, v7_val_t *result);
6121
6122/*
6123 * Options for `v7_exec_opt()`. To get default options, like `v7_exec()` uses,
6124 * just zero out this struct.
6125 */
6126struct v7_exec_opts {
6127 /* Filename, used for stack traces only */
6128 const char *filename;
6129
6130 /*
6131 * Object to be used as `this`. Note: when it is zeroed out, i.e. it's a
6132 * number `0`, the `undefined` value is assumed. It means that it's
6133 * impossible to actually use the number `0` as `this` object, but it makes
6134 * little sense anyway.
6135 */
6136 v7_val_t this_obj;
6137
6138 /* Whether the given `js_code` should be interpreted as JSON, not JS code */
6139 unsigned is_json : 1;
6140};
6141
6142/*
6143 * Customizable version of `v7_exec()`: allows to specify various options, see
6144 * `struct v7_exec_opts`.
6145 */
6146enum v7_err v7_exec_opt(struct v7 *v7, const char *js_code,
6147 const struct v7_exec_opts *opts, v7_val_t *res);
6148
6149/*
6150 * Like v7_exec but it expects an explicit length instead of treating the code
6151 * as a null terminated string.
6152 *
6153 * The code can be either a JS source or a precompiled bytecode.
6154 */
6155WARN_UNUSED_RESULT
6156enum v7_err v7_exec_buf(struct v7 *v7, const char *js_code, size_t len,
6157 v7_val_t *result);
6158
6159/*
6160 * Same as `v7_exec()`, but loads source code from `path` file.
6161 */
6162WARN_UNUSED_RESULT
6163enum v7_err v7_exec_file(struct v7 *v7, const char *path, v7_val_t *result);
6164
6165/*
6166 * Parse `str` and store corresponding JavaScript object in `res` variable.
6167 * String `str` should be '\0'-terminated.
6168 * Return value and semantic is the same as for `v7_exec()`.
6169 */
6170WARN_UNUSED_RESULT
6171enum v7_err v7_parse_json(struct v7 *v7, const char *str, v7_val_t *res);
6172
6173/*
6174 * Same as `v7_parse_json()`, but loads JSON string from `path`.
6175 */
6176WARN_UNUSED_RESULT
6177enum v7_err v7_parse_json_file(struct v7 *v7, const char *path, v7_val_t *res);
6178
6179#if !defined(V7_NO_COMPILER)
6180
6181/*
6182 * Compile JavaScript code `js_code` into the byte code and write generated
6183 * byte code into opened file stream `fp`. If `generate_binary_output` is 0,
6184 * then generated byte code is in human-readable text format. Otherwise, it is
6185 * in the binary format, suitable for execution by V7 instance.
6186 * NOTE: `fp` must be a valid, opened, writable file stream.
6187 */
6188WARN_UNUSED_RESULT
6189enum v7_err v7_compile(const char *js_code, int generate_binary_output,
6190 int use_bcode, FILE *fp);
6191
6192#endif /* V7_NO_COMPILER */
6193
6194/*
6195 * Call function `func` with arguments `args`, using `this_obj` as `this`.
6196 * `args` should be an array containing arguments or `undefined`.
6197 *
6198 * `res` can be `NULL` if return value is not required.
6199 */
6200WARN_UNUSED_RESULT
6201enum v7_err v7_apply(struct v7 *v7, v7_val_t func, v7_val_t this_obj,
6202 v7_val_t args, v7_val_t *res);
6203
6204#if defined(__cplusplus)
6205}
6206#endif /* __cplusplus */
6207
6208#endif /* CS_V7_SRC_EXEC_PUBLIC_H_ */
6209#ifdef V7_MODULE_LINES
6210#line 1 "v7/src/exec.h"
6211#endif
6212/*
6213 * Copyright (c) 2014 Cesanta Software Limited
6214 * All rights reserved
6215 */
6216
6217#ifndef CS_V7_SRC_EXEC_H_
6218#define CS_V7_SRC_EXEC_H_
6219
6220/* Amalgamated: #include "v7/src/exec_public.h" */
6221
6222/* Amalgamated: #include "v7/src/core.h" */
6223
6224#if !defined(V7_NO_COMPILER)
6225
6226#if defined(__cplusplus)
6227extern "C" {
6228#endif /* __cplusplus */
6229
6230/*
6231 * At the moment, all exec-related functions are public, and are declared in
6232 * `exec_public.h`
6233 */
6234
6235WARN_UNUSED_RESULT
6236enum v7_err _v7_compile(const char *js_code, size_t js_code_size,
6237 int generate_binary_output, int use_bcode, FILE *fp);
6238
6239#if defined(__cplusplus)
6240}
6241#endif /* __cplusplus */
6242
6243#endif /* V7_NO_COMPILER */
6244
6245#endif /* CS_V7_SRC_EXEC_H_ */
6246#ifdef V7_MODULE_LINES
6247#line 1 "v7/src/array_public.h"
6248#endif
6249/*
6250 * Copyright (c) 2014 Cesanta Software Limited
6251 * All rights reserved
6252 */
6253
6254/*
6255 * === Arrays
6256 */
6257
6258#ifndef CS_V7_SRC_ARRAY_PUBLIC_H_
6259#define CS_V7_SRC_ARRAY_PUBLIC_H_
6260
6261/* Amalgamated: #include "v7/src/core_public.h" */
6262
6263#if defined(__cplusplus)
6264extern "C" {
6265#endif /* __cplusplus */
6266
6267/* Make an empty array object */
6268v7_val_t v7_mk_array(struct v7 *v7);
6269
6270/* Returns true if given value is an array object */
6271int v7_is_array(struct v7 *v7, v7_val_t v);
6272
6273/* Returns length on an array. If `arr` is not an array, 0 is returned. */
6274unsigned long v7_array_length(struct v7 *v7, v7_val_t arr);
6275
6276/* Insert value `v` in array `arr` at the end of the array. */
6277int v7_array_push(struct v7 *, v7_val_t arr, v7_val_t v);
6278
6279/*
6280 * Like `v7_array_push()`, but "returns" value through the `res` pointer
6281 * argument. `res` is allowed to be `NULL`.
6282 *
6283 * Caller should check the error code returned, and if it's something other
6284 * than `V7_OK`, perform cleanup and return this code further.
6285 */
6286WARN_UNUSED_RESULT
6287enum v7_err v7_array_push_throwing(struct v7 *v7, v7_val_t arr, v7_val_t v,
6288 int *res);
6289
6290/*
6291 * Return array member at index `index`. If `index` is out of bounds, undefined
6292 * is returned.
6293 */
6294v7_val_t v7_array_get(struct v7 *, v7_val_t arr, unsigned long index);
6295
6296/* Insert value `v` into `arr` at index `index`. */
6297int v7_array_set(struct v7 *v7, v7_val_t arr, unsigned long index, v7_val_t v);
6298
6299/*
6300 * Like `v7_array_set()`, but "returns" value through the `res` pointer
6301 * argument. `res` is allowed to be `NULL`.
6302 *
6303 * Caller should check the error code returned, and if it's something other
6304 * than `V7_OK`, perform cleanup and return this code further.
6305 */
6306WARN_UNUSED_RESULT
6307enum v7_err v7_array_set_throwing(struct v7 *v7, v7_val_t arr,
6308 unsigned long index, v7_val_t v, int *res);
6309
6310/* Delete value in array `arr` at index `index`, if it exists. */
6311void v7_array_del(struct v7 *v7, v7_val_t arr, unsigned long index);
6312
6313#if defined(__cplusplus)
6314}
6315#endif /* __cplusplus */
6316
6317#endif /* CS_V7_SRC_ARRAY_PUBLIC_H_ */
6318#ifdef V7_MODULE_LINES
6319#line 1 "v7/src/array.h"
6320#endif
6321/*
6322 * Copyright (c) 2014 Cesanta Software Limited
6323 * All rights reserved
6324 */
6325
6326#ifndef CS_V7_SRC_ARRAY_H_
6327#define CS_V7_SRC_ARRAY_H_
6328
6329/* Amalgamated: #include "v7/src/array_public.h" */
6330
6331/* Amalgamated: #include "v7/src/core.h" */
6332
6333#if defined(__cplusplus)
6334extern "C" {
6335#endif /* __cplusplus */
6336
6337V7_PRIVATE v7_val_t v7_mk_dense_array(struct v7 *v7);
6338V7_PRIVATE val_t
6339v7_array_get2(struct v7 *v7, v7_val_t arr, unsigned long index, int *has);
6340
6341#if defined(__cplusplus)
6342}
6343#endif /* __cplusplus */
6344
6345#endif /* CS_V7_SRC_ARRAY_H_ */
6346#ifdef V7_MODULE_LINES
6347#line 1 "v7/src/conversion_public.h"
6348#endif
6349/*
6350 * Copyright (c) 2014 Cesanta Software Limited
6351 * All rights reserved
6352 */
6353
6354/*
6355 * === Conversion
6356 */
6357
6358#ifndef CS_V7_SRC_CONVERSION_PUBLIC_H_
6359#define CS_V7_SRC_CONVERSION_PUBLIC_H_
6360
6361/* Amalgamated: #include "v7/src/core_public.h" */
6362
6363#if defined(__cplusplus)
6364extern "C" {
6365#endif /* __cplusplus */
6366
6367/* Stringify mode, see `v7_stringify()` and `v7_stringify_throwing()` */
6368enum v7_stringify_mode {
6369 V7_STRINGIFY_DEFAULT,
6370 V7_STRINGIFY_JSON,
6371 V7_STRINGIFY_DEBUG,
6372};
6373
6374/*
6375 * Generate string representation of the JavaScript value `val` into a buffer
6376 * `buf`, `len`. If `len` is too small to hold a generated string,
6377 * `v7_stringify()` allocates required memory. In that case, it is caller's
6378 * responsibility to free the allocated buffer. Generated string is guaranteed
6379 * to be 0-terminated.
6380 *
6381 * Available stringification modes are:
6382 *
6383 * - `V7_STRINGIFY_DEFAULT`:
6384 * Convert JS value to string, using common JavaScript semantics:
6385 * - If value is an object:
6386 * - call `toString()`;
6387 * - If `toString()` returned non-primitive value, call `valueOf()`;
6388 * - If `valueOf()` returned non-primitive value, throw `TypeError`.
6389 * - Now we have a primitive, and if it's not a string, then stringify it.
6390 *
6391 * - `V7_STRINGIFY_JSON`:
6392 * Generate JSON output
6393 *
6394 * - `V7_STRINGIFY_DEBUG`:
6395 * Mostly like JSON, but will not omit non-JSON objects like functions.
6396 *
6397 * Example code:
6398 *
6399 * char buf[100], *p;
6400 * p = v7_stringify(v7, obj, buf, sizeof(buf), V7_STRINGIFY_DEFAULT);
6401 * printf("JSON string: [%s]\n", p);
6402 * if (p != buf) {
6403 * free(p);
6404 * }
6405 */
6406char *v7_stringify(struct v7 *v7, v7_val_t v, char *buf, size_t len,
6407 enum v7_stringify_mode mode);
6408
6409/*
6410 * Like `v7_stringify()`, but "returns" value through the `res` pointer
6411 * argument. `res` must not be `NULL`.
6412 *
6413 * Caller should check the error code returned, and if it's something other
6414 * than `V7_OK`, perform cleanup and return this code further.
6415 */
6416WARN_UNUSED_RESULT
6417enum v7_err v7_stringify_throwing(struct v7 *v7, v7_val_t v, char *buf,
6418 size_t size, enum v7_stringify_mode mode,
6419 char **res);
6420
6421/*
6422 * A shortcut for `v7_stringify()` with `V7_STRINGIFY_JSON`
6423 */
6424#define v7_to_json(a, b, c, d) v7_stringify(a, b, c, d, V7_STRINGIFY_JSON)
6425
6426/* Returns true if given value evaluates to true, as in `if (v)` statement. */
6427int v7_is_truthy(struct v7 *v7, v7_val_t v);
6428
6429#if defined(__cplusplus)
6430}
6431#endif /* __cplusplus */
6432
6433#endif /* CS_V7_SRC_CONVERSION_PUBLIC_H_ */
6434#ifdef V7_MODULE_LINES
6435#line 1 "v7/src/conversion.h"
6436#endif
6437/*
6438 * Copyright (c) 2014 Cesanta Software Limited
6439 * All rights reserved
6440 */
6441
6442#ifndef CS_V7_SRC_CONVERSION_H_
6443#define CS_V7_SRC_CONVERSION_H_
6444
6445/* Amalgamated: #include "v7/src/conversion_public.h" */
6446
6447/* Amalgamated: #include "v7/src/core.h" */
6448
6449#if defined(__cplusplus)
6450extern "C" {
6451#endif /* __cplusplus */
6452
6453/*
6454 * Conversion API
6455 * ==============
6456 *
6457 * - If you need to convert any JS value to string using common JavaScript
6458 * semantics, use `to_string()`, which can convert to both `v7_val_t` or your
6459 * C buffer.
6460 *
6461 * - If you need to convert any JS value to number using common JavaScript
6462 * semantics, use `to_number_v()`;
6463 *
6464 * - If you need to convert any JS value to primitive, without forcing it to
6465 * string or number, use `to_primitive()` (see comments for this function for
6466 * details);
6467 *
6468 * - If you have a primitive value, and you want to convert it to either string
6469 * or number, you can still use functions above: `to_string()` and
6470 * `to_number_v()`. But if you want to save a bit of work, use:
6471 * - `primitive_to_str()`
6472 * - `primitive_to_number()`
6473 *
6474 * In fact, these are a bit lower level functions, which are used by
6475 * `to_string()` and `to_number_v()` after converting value to
6476 * primitive.
6477 *
6478 * - If you want to call `valueOf()` on the object, use `obj_value_of()`;
6479 * - If you want to call `toString()` on the object, use `obj_to_string()`;
6480 *
6481 * - If you need to convert any JS value to boolean using common JavaScript
6482 * semantics (as in the expression `if (v)` or `Boolean(v)`), use
6483 * `to_boolean_v()`.
6484 *
6485 * - If you want to get the JSON representation of a value, use
6486 * `to_json_or_debug()`, passing `0` as `is_debug` : writes data to your C
6487 * buffer;
6488 *
6489 * - There is one more kind of representation: `DEBUG`. It's very similar to
6490 * JSON, but it will not omit non-JSON values, such as functions. Again, use
6491 * `to_json_or_debug()`, but pass `1` as `is_debug` this time: writes data to
6492 * your C buffer;
6493 *
6494 * Additionally, for any kind of to-string conversion into C buffer, you can
6495 * use a convenience wrapper function (mostly for public API), which can
6496 * allocate the buffer for you:
6497 *
6498 * - `v7_stringify_throwing()`;
6499 * - `v7_stringify()` : the same as above, but doesn't throw.
6500 *
6501 * There are a couple of more specific conversions, which I'd like to probably
6502 * refactor or remove in the future:
6503 *
6504 * - `to_long()` : if given value is `undefined`, returns provided default
6505 * value; otherwise, converts value to number, and then truncates to `long`.
6506 * - `str_to_ulong()` : converts the value to string, and tries to parse it as
6507 * an integer. Use it if only you need strong conformity ov the value to an
6508 * integer (currently, it's used only when examining keys of array object)
6509 *
6510 * ----------------------------------------------------------------------------
6511 *
6512 * TODO(dfrank):
6513 * - Rename functions like `v7_get_double(v7, )`, `get_object_struct()` to
6514 *something
6515 * that will clearly identify that they convert to some C entity, not
6516 * `v7_val_t`
6517 * - Maybe make `to_string()` private? But then, there will be no way
6518 * in public API to convert value to `v7_val_t` string, so, for now
6519 * it's here.
6520 * - When we agree on what goes to public API, and what does not, write
6521 * similar conversion guide for public API (in `conversion_public.h`)
6522 */
6523
6524/*
6525 * Convert any JS value to number, using common JavaScript semantics:
6526 *
6527 * - If value is an object:
6528 * - call `valueOf()`;
6529 * - If `valueOf()` returned non-primitive value, call `toString()`;
6530 * - If `toString()` returned non-primitive value, throw `TypeError`.
6531 * - Now we have a primitive, and if it's not a number, then:
6532 * - If `undefined`, return `NaN`
6533 * - If `null`, return 0.0
6534 * - If boolean, return either 1 or 0
6535 * - If string, try to parse it.
6536 */
6537WARN_UNUSED_RESULT
6538V7_PRIVATE enum v7_err to_number_v(struct v7 *v7, v7_val_t v, v7_val_t *res);
6539
6540/*
6541 * Convert any JS value to string, using common JavaScript semantics,
6542 * see `v7_stringify()` and `V7_STRINGIFY_DEFAULT`.
6543 *
6544 * This function can return multiple things:
6545 *
6546 * - String as a `v7_val_t` (if `res` is not `NULL`)
6547 * - String copied to buffer `buf` with max size `buf_size` (if `buf` is not
6548 * `NULL`)
6549 * - Length of actual string, independently of `buf_size` (if `res_len` is not
6550 * `NULL`)
6551 *
6552 * The rationale of having multiple formats of returned value is the following:
6553 *
6554 * Initially, to-string conversion always returned `v7_val_t`. But it turned
6555 * out that there are situations where such an approach adds useless pressure
6556 * on GC: e.g. when converting `undefined` to string, and the caller actually
6557 * needs a C buffer, not a `v7_val_t`.
6558 *
6559 * Always returning string through `buf`+`buf_size` is bad as well: if we
6560 * convert from object to string, and either `toString()` or `valueOf()`
6561 * returned string, then we'd have to get string data from it, write to buffer,
6562 * and if caller actually need `v7_val_t`, then it will have to create new
6563 * instance of the same string: again, useless GC pressure.
6564 *
6565 * So, we have to use the combined approach. This function will make minimal
6566 * work depending on give `res` and `buf`.
6567 */
6568WARN_UNUSED_RESULT
6569V7_PRIVATE enum v7_err to_string(struct v7 *v7, v7_val_t v, v7_val_t *res,
6570 char *buf, size_t buf_size, size_t *res_len);
6571
6572/*
6573 * Convert value to primitive, if it's not already.
6574 *
6575 * For object-to-primitive conversion, each object in JavaScript has two
6576 * methods: `toString()` and `valueOf()`.
6577 *
6578 * When converting object to string, JavaScript does the following:
6579 * - call `toString()`;
6580 * - If `toString()` returned non-primitive value, call `valueOf()`;
6581 * - If `valueOf()` returned non-primitive value, throw `TypeError`.
6582 *
6583 * When converting object to number, JavaScript calls the same functions,
6584 * but in reverse:
6585 * - call `valueOf()`;
6586 * - If `valueOf()` returned non-primitive value, call `toString()`;
6587 * - If `toString()` returned non-primitive value, throw `TypeError`.
6588 *
6589 * This function `to_primitive()` performs either type of conversion,
6590 * depending on the `hint` argument (see `enum to_primitive_hint`).
6591 */
6592enum to_primitive_hint {
6593 /* Call `valueOf()` first, then `toString()` if needed */
6594 V7_TO_PRIMITIVE_HINT_NUMBER,
6595
6596 /* Call `toString()` first, then `valueOf()` if needed */
6597 V7_TO_PRIMITIVE_HINT_STRING,
6598
6599 /* STRING for Date, NUMBER for everything else */
6600 V7_TO_PRIMITIVE_HINT_AUTO,
6601};
6602WARN_UNUSED_RESULT
6603enum v7_err to_primitive(struct v7 *v7, v7_val_t v, enum to_primitive_hint hint,
6604 v7_val_t *res);
6605
6606/*
6607 * Convert primitive value to string, using common JavaScript semantics. If
6608 * you need to convert any value to string (either object or primitive),
6609 * see `to_string()` or `v7_stringify_throwing()`.
6610 *
6611 * This function can return multiple things:
6612 *
6613 * - String as a `v7_val_t` (if `res` is not `NULL`)
6614 * - String copied to buffer `buf` with max size `buf_size` (if `buf` is not
6615 * `NULL`)
6616 * - Length of actual string, independently of `buf_size` (if `res_len` is not
6617 * `NULL`)
6618 */
6619WARN_UNUSED_RESULT
6620V7_PRIVATE enum v7_err primitive_to_str(struct v7 *v7, val_t v, val_t *res,
6621 char *buf, size_t buf_size,
6622 size_t *res_len);
6623
6624/*
6625 * Convert primitive value to number, using common JavaScript semantics. If you
6626 * need to convert any value to number (either object or primitive), see
6627 * `to_number_v()`
6628 */
6629WARN_UNUSED_RESULT
6630V7_PRIVATE enum v7_err primitive_to_number(struct v7 *v7, val_t v, val_t *res);
6631
6632/*
6633 * Convert value to JSON or "debug" representation, depending on whether
6634 * `is_debug` is non-zero. The "debug" is the same as JSON, but non-JSON values
6635 * (functions, `undefined`, etc) will not be omitted.
6636 *
6637 * See also `v7_stringify()`, `v7_stringify_throwing()`.
6638 */
6639WARN_UNUSED_RESULT
6640V7_PRIVATE enum v7_err to_json_or_debug(struct v7 *v7, val_t v, char *buf,
6641 size_t size, size_t *res_len,
6642 uint8_t is_debug);
6643
6644/*
6645 * Calls `valueOf()` on given object `v`
6646 */
6647WARN_UNUSED_RESULT
6648V7_PRIVATE enum v7_err obj_value_of(struct v7 *v7, val_t v, val_t *res);
6649
6650/*
6651 * Calls `toString()` on given object `v`
6652 */
6653WARN_UNUSED_RESULT
6654V7_PRIVATE enum v7_err obj_to_string(struct v7 *v7, val_t v, val_t *res);
6655
6656/*
6657 * If given value is `undefined`, returns `default_value`; otherwise,
6658 * converts value to number, and then truncates to `long`.
6659 */
6660WARN_UNUSED_RESULT
6661V7_PRIVATE enum v7_err to_long(struct v7 *v7, val_t v, long default_value,
6662 long *res);
6663
6664/*
6665 * Converts value to boolean as in the expression `if (v)` or `Boolean(v)`.
6666 *
6667 * NOTE: it can't throw (even if the given value is an object with `valueOf()`
6668 * that throws), so it returns `val_t` directly.
6669 */
6670WARN_UNUSED_RESULT
6671V7_PRIVATE val_t to_boolean_v(struct v7 *v7, val_t v);
6672
6673#if defined(__cplusplus)
6674}
6675#endif /* __cplusplus */
6676
6677#endif /* CS_V7_SRC_CONVERSION_H_ */
6678#ifdef V7_MODULE_LINES
6679#line 1 "v7/src/varint.h"
6680#endif
6681/*
6682 * Copyright (c) 2014 Cesanta Software Limited
6683 * All rights reserved
6684 */
6685
6686#ifndef CS_V7_SRC_VARINT_H_
6687#define CS_V7_SRC_VARINT_H_
6688
6689/* Amalgamated: #include "v7/src/internal.h" */
6690
6691#if defined(__cplusplus)
6692extern "C" {
6693#endif /* __cplusplus */
6694
6695V7_PRIVATE int encode_varint(size_t len, unsigned char *p);
6696V7_PRIVATE size_t decode_varint(const unsigned char *p, int *llen);
6697V7_PRIVATE int calc_llen(size_t len);
6698
6699#if defined(__cplusplus)
6700}
6701#endif /* __cplusplus */
6702
6703#endif /* CS_V7_SRC_VARINT_H_ */
6704#ifdef V7_MODULE_LINES
6705#line 1 "common/cs_strtod.h"
6706#endif
6707/*
6708 * Copyright (c) 2014-2016 Cesanta Software Limited
6709 * All rights reserved
6710 */
6711
6712#ifndef CS_COMMON_CS_STRTOD_H_
6713#define CS_COMMON_CS_STRTOD_H_
6714
6715#ifdef __cplusplus
6716extern "C" {
6717#endif
6718
6719double cs_strtod(const char *str, char **endptr);
6720
6721#ifdef __cplusplus
6722}
6723#endif
6724
6725#endif /* CS_COMMON_CS_STRTOD_H_ */
6726#ifdef V7_MODULE_LINES
6727#line 1 "v7/src/ast.h"
6728#endif
6729/*
6730 * Copyright (c) 2014 Cesanta Software Limited
6731 * All rights reserved
6732 */
6733
6734#ifndef CS_V7_SRC_AST_H_
6735#define CS_V7_SRC_AST_H_
6736
6737#include <stdio.h>
6738/* Amalgamated: #include "common/mbuf.h" */
6739/* Amalgamated: #include "v7/src/internal.h" */
6740/* Amalgamated: #include "v7/src/core.h" */
6741
6742#if !defined(V7_NO_COMPILER)
6743
6744#if defined(__cplusplus)
6745extern "C" {
6746#endif /* __cplusplus */
6747
6748#define BIN_AST_SIGNATURE "V\007ASTV10"
6749
6750enum ast_tag {
6751 AST_NOP,
6752 AST_SCRIPT,
6753 AST_VAR,
6754 AST_VAR_DECL,
6755 AST_FUNC_DECL,
6756 AST_IF,
6757 AST_FUNC,
6758
6759 AST_ASSIGN,
6760 AST_REM_ASSIGN,
6761 AST_MUL_ASSIGN,
6762 AST_DIV_ASSIGN,
6763 AST_XOR_ASSIGN,
6764 AST_PLUS_ASSIGN,
6765 AST_MINUS_ASSIGN,
6766 AST_OR_ASSIGN,
6767 AST_AND_ASSIGN,
6768 AST_LSHIFT_ASSIGN,
6769 AST_RSHIFT_ASSIGN,
6770 AST_URSHIFT_ASSIGN,
6771
6772 AST_NUM,
6773 AST_IDENT,
6774 AST_STRING,
6775 AST_REGEX,
6776 AST_LABEL,
6777
6778 AST_SEQ,
6779 AST_WHILE,
6780 AST_DOWHILE,
6781 AST_FOR,
6782 AST_FOR_IN,
6783 AST_COND,
6784
6785 AST_DEBUGGER,
6786 AST_BREAK,
6787 AST_LABELED_BREAK,
6788 AST_CONTINUE,
6789 AST_LABELED_CONTINUE,
6790 AST_RETURN,
6791 AST_VALUE_RETURN,
6792 AST_THROW,
6793
6794 AST_TRY,
6795 AST_SWITCH,
6796 AST_CASE,
6797 AST_DEFAULT,
6798 AST_WITH,
6799
6800 AST_LOGICAL_OR,
6801 AST_LOGICAL_AND,
6802 AST_OR,
6803 AST_XOR,
6804 AST_AND,
6805
6806 AST_EQ,
6807 AST_EQ_EQ,
6808 AST_NE,
6809 AST_NE_NE,
6810
6811 AST_LE,
6812 AST_LT,
6813 AST_GE,
6814 AST_GT,
6815 AST_IN,
6816 AST_INSTANCEOF,
6817
6818 AST_LSHIFT,
6819 AST_RSHIFT,
6820 AST_URSHIFT,
6821
6822 AST_ADD,
6823 AST_SUB,
6824
6825 AST_REM,
6826 AST_MUL,
6827 AST_DIV,
6828
6829 AST_POSITIVE,
6830 AST_NEGATIVE,
6831 AST_NOT,
6832 AST_LOGICAL_NOT,
6833 AST_VOID,
6834 AST_DELETE,
6835 AST_TYPEOF,
6836 AST_PREINC,
6837 AST_PREDEC,
6838
6839 AST_POSTINC,
6840 AST_POSTDEC,
6841
6842 AST_MEMBER,
6843 AST_INDEX,
6844 AST_CALL,
6845
6846 AST_NEW,
6847
6848 AST_ARRAY,
6849 AST_OBJECT,
6850 AST_PROP,
6851 AST_GETTER,
6852 AST_SETTER,
6853
6854 AST_THIS,
6855 AST_TRUE,
6856 AST_FALSE,
6857 AST_NULL,
6858 AST_UNDEFINED,
6859
6860 AST_USE_STRICT,
6861
6862 AST_MAX_TAG
6863};
6864
6865struct ast {
6866 struct mbuf mbuf;
6867 int refcnt;
6868 int has_overflow;
6869};
6870
6871typedef unsigned long ast_off_t;
6872
6873#if __GNUC__ >= 4 && __GNUC_MINOR__ >= 8
6874#define GCC_HAS_PRAGMA_DIAGNOSTIC
6875#endif
6876
6877#ifdef GCC_HAS_PRAGMA_DIAGNOSTIC
6878/*
6879 * TODO(mkm): GCC complains that bitfields on char are not standard
6880 */
6881#pragma GCC diagnostic push
6882#pragma GCC diagnostic ignored "-Wpedantic"
6883#endif
6884struct ast_node_def {
6885#if !V7_DISABLE_AST_TAG_NAMES
6886 const char *name; /* tag name, for debugging and serialization */
6887#endif
6888 unsigned char has_varint : 1; /* has a varint body */
6889 unsigned char has_inlined : 1; /* inlined data whose size is in varint fld */
6890 unsigned char num_skips : 3; /* number of skips */
6891 unsigned char num_subtrees : 3; /* number of fixed subtrees */
6892};
6893extern const struct ast_node_def ast_node_defs[];
6894#if V7_ENABLE_FOOTPRINT_REPORT
6895extern const size_t ast_node_defs_size;
6896extern const size_t ast_node_defs_count;
6897#endif
6898#ifdef GCC_HAS_PRAGMA_DIAGNOSTIC
6899#pragma GCC diagnostic pop
6900#endif
6901
6902enum ast_which_skip {
6903 AST_END_SKIP = 0,
6904 AST_VAR_NEXT_SKIP = 1,
6905 AST_SCRIPT_FIRST_VAR_SKIP = AST_VAR_NEXT_SKIP,
6906 AST_FOR_BODY_SKIP = 1,
6907 AST_DO_WHILE_COND_SKIP = 1,
6908 AST_END_IF_TRUE_SKIP = 1,
6909 AST_TRY_CATCH_SKIP = 1,
6910 AST_TRY_FINALLY_SKIP = 2,
6911 AST_FUNC_FIRST_VAR_SKIP = AST_VAR_NEXT_SKIP,
6912 AST_FUNC_BODY_SKIP = 2,
6913 AST_SWITCH_DEFAULT_SKIP = 1
6914};
6915
6916V7_PRIVATE void ast_init(struct ast *, size_t);
6917V7_PRIVATE void ast_optimize(struct ast *);
6918V7_PRIVATE void ast_free(struct ast *);
6919
6920/*
6921 * Begins an AST node by inserting a tag to the AST at the given offset.
6922 *
6923 * It also allocates space for the fixed_size payload and the space for
6924 * the skips.
6925 *
6926 * The caller is responsible for appending children.
6927 *
6928 * Returns the offset of the node payload (one byte after the tag).
6929 * This offset can be passed to `ast_set_skip`.
6930 */
6931V7_PRIVATE ast_off_t
6932ast_insert_node(struct ast *a, ast_off_t pos, enum ast_tag tag);
6933
6934/*
6935 * Modify tag which is already added to buffer. Keeps `AST_TAG_LINENO_PRESENT`
6936 * flag.
6937 */
6938V7_PRIVATE void ast_modify_tag(struct ast *a, ast_off_t tag_off,
6939 enum ast_tag tag);
6940
6941#if !V7_DISABLE_LINE_NUMBERS
6942/*
6943 * Add line_no varint after all skips of the tag at the offset `tag_off`, and
6944 * marks the tag byte.
6945 *
6946 * Byte at the offset `tag_off` should be a valid tag.
6947 */
6948V7_PRIVATE void ast_add_line_no(struct ast *a, ast_off_t tag_off, int line_no);
6949#endif
6950
6951/*
6952 * Patches a given skip slot for an already emitted node with the
6953 * current write cursor position (e.g. AST length).
6954 *
6955 * This is intended to be invoked when a node with a variable number
6956 * of child subtrees is closed, or when the consumers need a shortcut
6957 * to the next sibling.
6958 *
6959 * Each node type has a different number and semantic for skips,
6960 * all of them defined in the `ast_which_skip` enum.
6961 * All nodes having a variable number of child subtrees must define
6962 * at least the `AST_END_SKIP` skip, which effectively skips a node
6963 * boundary.
6964 *
6965 * Every tree reader can assume this and safely skip unknown nodes.
6966 *
6967 * `pos` should be an offset of the byte right after a tag.
6968 */
6969V7_PRIVATE ast_off_t
6970ast_set_skip(struct ast *a, ast_off_t pos, enum ast_which_skip skip);
6971
6972/*
6973 * Patches a given skip slot for an already emitted node with the value
6974 * (stored as delta relative to the `pos` node) of the `where` argument.
6975 */
6976V7_PRIVATE ast_off_t ast_modify_skip(struct ast *a, ast_off_t pos,
6977 ast_off_t where, enum ast_which_skip skip);
6978
6979/*
6980 * Returns the offset in AST to which the given `skip` points.
6981 *
6982 * `pos` should be an offset of the byte right after a tag.
6983 */
6984V7_PRIVATE ast_off_t
6985ast_get_skip(struct ast *a, ast_off_t pos, enum ast_which_skip skip);
6986
6987/*
6988 * Returns the tag from the offset `ppos`, and shifts `ppos` by 1.
6989 */
6990V7_PRIVATE enum ast_tag ast_fetch_tag(struct ast *a, ast_off_t *ppos);
6991
6992/*
6993 * Moves the cursor to the tag's varint and inlined data (if there are any, see
6994 * `struct ast_node_def::has_varint` and `struct ast_node_def::has_inlined`).
6995 *
6996 * Technically, it skips node's "skips" and line number data, if either is
6997 * present.
6998 *
6999 * Assumes a cursor (`ppos`) positioned right after a tag.
7000 */
7001V7_PRIVATE void ast_move_to_inlined_data(struct ast *a, ast_off_t *ppos);
7002
7003/*
7004 * Moves the cursor to the tag's subtrees (if there are any,
7005 * see `struct ast_node_def::num_subtrees`), or to the next node in case the
7006 * current node has no subtrees.
7007 *
7008 * Technically, it skips node's "skips", line number data, and inlined data, if
7009 * either is present.
7010 *
7011 * Assumes a cursor (`ppos`) positioned right after a tag.
7012 */
7013V7_PRIVATE void ast_move_to_children(struct ast *a, ast_off_t *ppos);
7014
7015/* Helper to add a node with inlined data. */
7016V7_PRIVATE ast_off_t ast_insert_inlined_node(struct ast *a, ast_off_t pos,
7017 enum ast_tag tag, const char *name,
7018 size_t len);
7019
7020/*
7021 * Returns the line number encoded in the node, or `0` in case of none is
7022 * encoded.
7023 *
7024 * `pos` should be an offset of the byte right after a tag.
7025 */
7026V7_PRIVATE int ast_get_line_no(struct ast *a, ast_off_t pos);
7027
7028/*
7029 * `pos` should be an offset of the byte right after a tag
7030 */
7031V7_PRIVATE char *ast_get_inlined_data(struct ast *a, ast_off_t pos, size_t *n);
7032
7033/*
7034 * Returns the `double` number inlined in the node
7035 */
7036V7_PRIVATE double ast_get_num(struct ast *a, ast_off_t pos);
7037
7038/*
7039 * Skips the node and all its subnodes.
7040 *
7041 * Cursor (`ppos`) should be at the tag byte
7042 */
7043V7_PRIVATE void ast_skip_tree(struct ast *a, ast_off_t *ppos);
7044
7045V7_PRIVATE void ast_dump_tree(FILE *fp, struct ast *a, ast_off_t *ppos,
7046 int depth);
7047
7048V7_PRIVATE void release_ast(struct v7 *v7, struct ast *a);
7049
7050#if defined(__cplusplus)
7051}
7052#endif /* __cplusplus */
7053
7054#endif /* V7_NO_COMPILER */
7055
7056#endif /* CS_V7_SRC_AST_H_ */
7057#ifdef V7_MODULE_LINES
7058#line 1 "v7/src/bcode.h"
7059#endif
7060/*
7061 * Copyright (c) 2014 Cesanta Software Limited
7062 * All rights reserved
7063 */
7064
7065#ifndef CS_V7_SRC_BCODE_H_
7066#define CS_V7_SRC_BCODE_H_
7067
7068#define BIN_BCODE_SIGNATURE "V\007BCODE:"
7069
7070#if !defined(V7_NAMES_CNT_WIDTH)
7071#define V7_NAMES_CNT_WIDTH 10
7072#endif
7073
7074#if !defined(V7_ARGS_CNT_WIDTH)
7075#define V7_ARGS_CNT_WIDTH 8
7076#endif
7077
7078#define V7_NAMES_CNT_MAX ((1 << V7_NAMES_CNT_WIDTH) - 1)
7079#define V7_ARGS_CNT_MAX ((1 << V7_ARGS_CNT_WIDTH) - 1)
7080
7081/* Amalgamated: #include "v7/src/internal.h" */
7082/* Amalgamated: #include "v7/src/core.h" */
7083/* Amalgamated: #include "v7/src/opcodes.h" */
7084/* Amalgamated: #include "v7/src/string.h" */
7085/* Amalgamated: #include "v7/src/object.h" */
7086/* Amalgamated: #include "v7/src/primitive.h" */
7087/* Amalgamated: #include "common/mbuf.h" */
7088
7089enum bcode_inline_lit_type_tag {
7090 BCODE_INLINE_STRING_TYPE_TAG = 0,
7091 BCODE_INLINE_NUMBER_TYPE_TAG,
7092 BCODE_INLINE_FUNC_TYPE_TAG,
7093 BCODE_INLINE_REGEXP_TYPE_TAG,
7094
7095 BCODE_MAX_INLINE_TYPE_TAG
7096};
7097
7098#if defined(__cplusplus)
7099extern "C" {
7100#endif /* __cplusplus */
7101
7102typedef uint32_t bcode_off_t;
7103
7104/*
7105 * Each JS function will have one bcode structure
7106 * containing the instruction stream, a literal table, and function
7107 * metadata.
7108 * Instructions contain references to literals (strings, constants, etc)
7109 *
7110 * The bcode struct can be shared between function instances
7111 * and keeps a reference count used to free it in the function destructor.
7112 */
7113struct bcode {
7114 /*
7115 * Names + instruction opcode.
7116 * Names are null-terminates strings. For function's bcode, there are:
7117 * - function name (for anonymous function, the name is still present: an
7118 * empty string);
7119 * - arg names (a number of args is determined by `args_cnt`, see below);
7120 * - local names (a number or locals can be calculated:
7121 * `(names_cnt - args_cnt - 1)`).
7122 *
7123 * For script's bcode, there are just local names.
7124 */
7125 struct v7_vec ops;
7126
7127 /* Literal table */
7128 struct v7_vec lit;
7129
7130#if !V7_DISABLE_FILENAMES
7131 /* Name of the file from which this bcode was generated (used for debug) */
7132 void *filename;
7133#endif
7134
7135 /* Reference count */
7136 uint8_t refcnt;
7137
7138 /* Total number of null-terminated strings in the beginning of `ops` */
7139 unsigned int names_cnt : V7_NAMES_CNT_WIDTH;
7140
7141 /* Number of args (should be <= `(names_cnt + 1)`) */
7142 unsigned int args_cnt : V7_ARGS_CNT_WIDTH;
7143
7144 unsigned int strict_mode : 1;
7145 /*
7146 * If true this structure lives on read only memory, either
7147 * mmapped or constant data section.
7148 */
7149 unsigned int frozen : 1;
7150
7151 /* If set, `ops.buf` points to ROM, so we shouldn't free it */
7152 unsigned int ops_in_rom : 1;
7153 /* Set for deserialized bcode. Used for metrics only */
7154 unsigned int deserialized : 1;
7155
7156 /* Set when `ops` contains function name as the first `name` */
7157 unsigned int func_name_present : 1;
7158
7159#if !V7_DISABLE_FILENAMES
7160 /* If set, `filename` points to ROM, so we shouldn't free it */
7161 unsigned int filename_in_rom : 1;
7162#endif
7163};
7164
7165/*
7166 * Bcode builder context: it contains mutable mbufs for opcodes and literals,
7167 * whereas the bcode itself contains just vectors (`struct v7_vec`).
7168 */
7169struct bcode_builder {
7170 struct v7 *v7;
7171 struct bcode *bcode;
7172
7173 struct mbuf ops; /* names + instruction opcode */
7174 struct mbuf lit; /* literal table */
7175};
7176
7177V7_PRIVATE void bcode_builder_init(struct v7 *v7,
7178 struct bcode_builder *bbuilder,
7179 struct bcode *bcode);
7180V7_PRIVATE void bcode_builder_finalize(struct bcode_builder *bbuilder);
7181
7182/*
7183 * Note: `filename` must be either:
7184 *
7185 * - `NULL`. In this case, `filename_in_rom` is ignored.
7186 * - A pointer to ROM (or to any other unmanaged memory). `filename_in_rom`
7187 * must be set to 1.
7188 * - A pointer returned by `shdata_create()`, i.e. a pointer to shared data.
7189 *
7190 * If you need to copy filename from another bcode, just pass NULL initially,
7191 * and after bcode is initialized, call `bcode_copy_filename_from()`.
7192 *
7193 * To get later a proper null-terminated filename string from bcode, use
7194 * `bcode_get_filename()`.
7195 */
7196V7_PRIVATE void bcode_init(struct bcode *bcode, uint8_t strict_mode,
7197 void *filename, uint8_t filename_in_rom);
7198V7_PRIVATE void bcode_free(struct v7 *v7, struct bcode *bcode);
7199V7_PRIVATE void release_bcode(struct v7 *v7, struct bcode *bcode);
7200V7_PRIVATE void retain_bcode(struct v7 *v7, struct bcode *bcode);
7201
7202#if !V7_DISABLE_FILENAMES
7203/*
7204 * Return a pointer to null-terminated filename string
7205 */
7206V7_PRIVATE const char *bcode_get_filename(struct bcode *bcode);
7207#endif
7208
7209/*
7210 * Copy filename from `src` to `dst`. If source filename is a pointer to ROM,
7211 * then just the pointer is copied; otherwise, appropriate shdata pointer is
7212 * retained.
7213 */
7214V7_PRIVATE void bcode_copy_filename_from(struct bcode *dst, struct bcode *src);
7215
7216/*
7217 * Serialize a bcode structure.
7218 *
7219 * All literals, including functions, are inlined into `ops` data; see
7220 * the serialization logic in `bcode_op_lit()`.
7221 *
7222 * The root bcode looks just like a regular function.
7223 *
7224 * This function is used only internally, but used in a complicated mix of
7225 * configurations, hence the commented V7_PRIVATE
7226 */
7227/*V7_PRIVATE*/ void bcode_serialize(struct v7 *v7, struct bcode *bcode,
7228 FILE *f);
7229
7230V7_PRIVATE void bcode_deserialize(struct v7 *v7, struct bcode *bcode,
7231 const char *data);
7232
7233#ifdef V7_BCODE_DUMP
7234V7_PRIVATE void dump_bcode(struct v7 *v7, FILE *, struct bcode *);
7235#endif
7236
7237/* mode of literal storage: in literal table or inlined in `ops` */
7238enum lit_mode {
7239 /* literal stored in table, index is in `lit_t::lit_idx` */
7240 LIT_MODE__TABLE,
7241 /* literal should be inlined in `ops`, value is in `lit_t::inline_val` */
7242 LIT_MODE__INLINED,
7243};
7244
7245/*
7246 * Result of the addition of literal value to bcode (see `bcode_add_lit()`).
7247 * There are two possible cases:
7248 *
7249 * - Literal is added to the literal table. In this case, `mode ==
7250 * LIT_MODE__TABLE`, and the index of the literal is stored in `lit_idx`
7251 * - Literal is not added anywhere, and should be inlined into `ops`. In this
7252 * case, `mode == LIT_MODE__INLINED`, and the value to inline is stored in
7253 * `inline_val`.
7254 *
7255 * It's `bcode_op_lit()` who handles both of these cases.
7256 */
7257typedef struct {
7258 union {
7259 /*
7260 * index in literal table;
7261 * NOTE: valid if only `mode == LIT_MODE__TABLE`
7262 */
7263 size_t lit_idx;
7264
7265 /*
7266 * value to be inlined into `ops`;
7267 * NOTE: valid if only `mode == LIT_MODE__INLINED`
7268 */
7269 v7_val_t inline_val;
7270 } v; /* anonymous unions are a c11 feature */
7271
7272 /*
7273 * mode of literal storage (see `enum lit_mode`)
7274 * NOTE: we need one more bit, because enum can be signed
7275 * on some compilers (e.g. msvc) and thus will get signextended
7276 * when moved to a `enum lit_mode` variable basically corrupting
7277 * the value. See https://github.com/cesanta/v7/issues/551
7278 */
7279 enum lit_mode mode : 2;
7280} lit_t;
7281
7282V7_PRIVATE void bcode_op(struct bcode_builder *bbuilder, uint8_t op);
7283
7284#if !V7_DISABLE_LINE_NUMBERS
7285V7_PRIVATE void bcode_append_lineno(struct bcode_builder *bbuilder,
7286 int line_no);
7287#endif
7288
7289/*
7290 * Add a literal to the bcode literal table, or just decide that the literal
7291 * should be inlined into `ops`. See `lit_t` for details.
7292 */
7293V7_PRIVATE
7294lit_t bcode_add_lit(struct bcode_builder *bbuilder, v7_val_t val);
7295
7296/* disabled because of short lits */
7297#if 0
7298V7_PRIVATE v7_val_t bcode_get_lit(struct bcode *bcode, size_t idx);
7299#endif
7300
7301/*
7302 * Emit an opcode `op`, and handle the literal `lit` (see `bcode_add_lit()`,
7303 * `lit_t`). Depending on the literal storage mode (see `enum lit_mode`), this
7304 * function either emits literal table index or inlines the literal directly
7305 * into `ops.`
7306 */
7307V7_PRIVATE void bcode_op_lit(struct bcode_builder *bbuilder, enum opcode op,
7308 lit_t lit);
7309
7310/* Helper function, equivalent of `bcode_op_lit(bbuilder, OP_PUSH_LIT, lit)` */
7311V7_PRIVATE void bcode_push_lit(struct bcode_builder *bbuilder, lit_t lit);
7312
7313/*
7314 * Add name to bcode. If `idx` is null, a name is appended to the end of the
7315 * `bcode->ops.buf`. If `idx` is provided, it should point to the index at
7316 * which new name should be inserted; and it is updated by the
7317 * `bcode_add_name()` to point right after newly added name.
7318 *
7319 * This function is used only internally, but used in a complicated mix of
7320 * configurations, hence the commented V7_PRIVATE
7321 */
7322WARN_UNUSED_RESULT
7323 /*V7_PRIVATE*/ enum v7_err
7324 bcode_add_name(struct bcode_builder *bbuilder, const char *p, size_t len,
7325 size_t *idx);
7326
7327/*
7328 * Takes a pointer to the beginning of `ops` buffer and names count, returns
7329 * a pointer where actual opcodes begin (i.e. skips names).
7330 *
7331 * It takes two distinct arguments instead of just `struct bcode` pointer,
7332 * because during bcode building `ops` is stored in builder.
7333 *
7334 * This function is used only internally, but used in a complicated mix of
7335 * configurations, hence the commented V7_PRIVATE
7336 */
7337/*V7_PRIVATE*/ char *bcode_end_names(char *ops, size_t names_cnt);
7338
7339/*
7340 * Given a pointer to `ops` (which should be `bcode->ops` or a pointer returned
7341 * from previous invocation of `bcode_next_name()`), yields a name string via
7342 * arguments `pname`, `plen`.
7343 *
7344 * Returns a pointer that should be given to `bcode_next_name()` to get a next
7345 * string (Whether there is a next string should be determined via the
7346 * `names_cnt`; since if there are no more names, this function will return an
7347 * invalid non-null pointer as next name pointer)
7348 */
7349V7_PRIVATE char *bcode_next_name(char *ops, char **pname, size_t *plen);
7350
7351/*
7352 * Like `bcode_next_name()`, but instead of yielding a C string, it yields a
7353 * `val_t` value (via `res`).
7354 */
7355V7_PRIVATE char *bcode_next_name_v(struct v7 *v7, struct bcode *bcode,
7356 char *ops, val_t *res);
7357
7358V7_PRIVATE bcode_off_t bcode_pos(struct bcode_builder *bbuilder);
7359
7360V7_PRIVATE bcode_off_t bcode_add_target(struct bcode_builder *bbuilder);
7361/*
7362 * This function is used only internally, but used in a complicated mix of
7363 * configurations, hence the commented V7_PRIVATE
7364 */
7365/*V7_PRIVATE*/ bcode_off_t bcode_op_target(struct bcode_builder *bbuilder,
7366 uint8_t op);
7367/*V7_PRIVATE*/ void bcode_patch_target(struct bcode_builder *bbuilder,
7368 bcode_off_t label, bcode_off_t target);
7369
7370V7_PRIVATE void bcode_add_varint(struct bcode_builder *bbuilder, size_t value);
7371/*
7372 * Reads varint-encoded integer from the provided pointer, and adjusts
7373 * the pointer appropriately
7374 */
7375V7_PRIVATE size_t bcode_get_varint(char **ops);
7376
7377/*
7378 * Decode a literal value from a string of opcodes and update the cursor to
7379 * point past it
7380 */
7381V7_PRIVATE
7382v7_val_t bcode_decode_lit(struct v7 *v7, struct bcode *bcode, char **ops);
7383
7384#if defined(V7_BCODE_DUMP) || defined(V7_BCODE_TRACE)
7385V7_PRIVATE void dump_op(struct v7 *v7, FILE *f, struct bcode *bcode,
7386 char **ops);
7387#endif
7388
7389#if defined(__cplusplus)
7390}
7391#endif /* __cplusplus */
7392
7393#endif /* CS_V7_SRC_BCODE_H_ */
7394#ifdef V7_MODULE_LINES
7395#line 1 "v7/src/gc_public.h"
7396#endif
7397/*
7398 * Copyright (c) 2014 Cesanta Software Limited
7399 * All rights reserved
7400 */
7401
7402/*
7403 * === Garbage Collector
7404 */
7405
7406#ifndef CS_V7_SRC_GC_PUBLIC_H_
7407#define CS_V7_SRC_GC_PUBLIC_H_
7408
7409/* Amalgamated: #include "v7/src/core_public.h" */
7410
7411#if defined(__cplusplus)
7412extern "C" {
7413#endif /* __cplusplus */
7414
7415#if V7_ENABLE__Memory__stats
7416
7417/* Heap metric id, see `v7_heap_stat()` */
7418enum v7_heap_stat_what {
7419 V7_HEAP_STAT_HEAP_SIZE,
7420 V7_HEAP_STAT_HEAP_USED,
7421 V7_HEAP_STAT_STRING_HEAP_RESERVED,
7422 V7_HEAP_STAT_STRING_HEAP_USED,
7423 V7_HEAP_STAT_OBJ_HEAP_MAX,
7424 V7_HEAP_STAT_OBJ_HEAP_FREE,
7425 V7_HEAP_STAT_OBJ_HEAP_CELL_SIZE,
7426 V7_HEAP_STAT_FUNC_HEAP_MAX,
7427 V7_HEAP_STAT_FUNC_HEAP_FREE,
7428 V7_HEAP_STAT_FUNC_HEAP_CELL_SIZE,
7429 V7_HEAP_STAT_PROP_HEAP_MAX,
7430 V7_HEAP_STAT_PROP_HEAP_FREE,
7431 V7_HEAP_STAT_PROP_HEAP_CELL_SIZE,
7432 V7_HEAP_STAT_FUNC_AST_SIZE,
7433 V7_HEAP_STAT_BCODE_OPS_SIZE,
7434 V7_HEAP_STAT_BCODE_LIT_TOTAL_SIZE,
7435 V7_HEAP_STAT_BCODE_LIT_DESER_SIZE,
7436 V7_HEAP_STAT_FUNC_OWNED,
7437 V7_HEAP_STAT_FUNC_OWNED_MAX
7438};
7439
7440/* Returns a given heap statistics */
7441int v7_heap_stat(struct v7 *v7, enum v7_heap_stat_what what);
7442#endif
7443
7444/*
7445 * Perform garbage collection.
7446 * Pass true to full in order to reclaim unused heap back to the OS.
7447 */
7448void v7_gc(struct v7 *v7, int full);
7449
7450#if defined(__cplusplus)
7451}
7452#endif /* __cplusplus */
7453
7454#endif /* CS_V7_SRC_GC_PUBLIC_H_ */
7455#ifdef V7_MODULE_LINES
7456#line 1 "v7/src/gc.h"
7457#endif
7458/*
7459 * Copyright (c) 2014 Cesanta Software Limited
7460 * All rights reserved
7461 */
7462
7463#ifndef CS_V7_SRC_GC_H_
7464#define CS_V7_SRC_GC_H_
7465
7466/* Amalgamated: #include "v7/src/gc_public.h" */
7467
7468/* Amalgamated: #include "v7/src/internal.h" */
7469/* Amalgamated: #include "v7/src/core.h" */
7470
7471/*
7472 * Macros for marking reachable things: use bit 0.
7473 */
7474#define MARK(p) (((struct gc_cell *) (p))->head.word |= 1)
7475#define UNMARK(p) (((struct gc_cell *) (p))->head.word &= ~1)
7476#define MARKED(p) (((struct gc_cell *) (p))->head.word & 1)
7477
7478/*
7479 * Similar to `MARK()` / `UNMARK()` / `MARKED()`, but `.._FREE` counterparts
7480 * are intended to mark free cells (as opposed to used ones), so they use
7481 * bit 1.
7482 */
7483#define MARK_FREE(p) (((struct gc_cell *) (p))->head.word |= 2)
7484#define UNMARK_FREE(p) (((struct gc_cell *) (p))->head.word &= ~2)
7485#define MARKED_FREE(p) (((struct gc_cell *) (p))->head.word & 2)
7486
7487/*
7488 * performs arithmetics on gc_cell pointers as if they were arena->cell_size
7489 * bytes wide
7490 */
7491#define GC_CELL_OP(arena, cell, op, arg) \
7492 ((struct gc_cell *) (((char *) (cell)) op((arg) * (arena)->cell_size)))
7493
7494struct gc_tmp_frame {
7495 struct v7 *v7;
7496 size_t pos;
7497};
7498
7499struct gc_cell {
7500 union {
7501 struct gc_cell *link;
7502 uintptr_t word;
7503 } head;
7504};
7505
7506#if defined(__cplusplus)
7507extern "C" {
7508#endif /* __cplusplus */
7509
7510V7_PRIVATE struct v7_generic_object *new_generic_object(struct v7 *);
7511V7_PRIVATE struct v7_property *new_property(struct v7 *);
7512V7_PRIVATE struct v7_js_function *new_function(struct v7 *);
7513
7514V7_PRIVATE void gc_mark(struct v7 *, val_t);
7515
7516V7_PRIVATE void gc_arena_init(struct gc_arena *, size_t, size_t, size_t,
7517 const char *);
7518V7_PRIVATE void gc_arena_destroy(struct v7 *, struct gc_arena *a);
7519V7_PRIVATE void gc_sweep(struct v7 *, struct gc_arena *, size_t);
7520V7_PRIVATE void *gc_alloc_cell(struct v7 *, struct gc_arena *);
7521
7522V7_PRIVATE struct gc_tmp_frame new_tmp_frame(struct v7 *);
7523V7_PRIVATE void tmp_frame_cleanup(struct gc_tmp_frame *);
7524V7_PRIVATE void tmp_stack_push(struct gc_tmp_frame *, val_t *);
7525
7526V7_PRIVATE void compute_need_gc(struct v7 *);
7527/* perform gc if not inhibited */
7528V7_PRIVATE int maybe_gc(struct v7 *);
7529
7530#if !V7_DISABLE_STR_ALLOC_SEQ
7531V7_PRIVATE uint16_t
7532gc_next_allocation_seqn(struct v7 *v7, const char *str, size_t len);
7533V7_PRIVATE int gc_is_valid_allocation_seqn(struct v7 *v7, uint16_t n);
7534V7_PRIVATE void gc_check_valid_allocation_seqn(struct v7 *v7, uint16_t n);
7535#endif
7536
7537V7_PRIVATE uint64_t gc_string_val_to_offset(val_t v);
7538
7539/* return 0 if v is an object/function with a bad pointer */
7540V7_PRIVATE int gc_check_val(struct v7 *v7, val_t v);
7541
7542/* checks whether a pointer is within the ranges of an arena */
7543V7_PRIVATE int gc_check_ptr(const struct gc_arena *a, const void *p);
7544
7545#if V7_ENABLE__Memory__stats
7546V7_PRIVATE size_t gc_arena_size(struct gc_arena *);
7547#endif
7548
7549#if defined(__cplusplus)
7550}
7551#endif /* __cplusplus */
7552
7553#endif /* CS_V7_SRC_GC_H_ */
7554#ifdef V7_MODULE_LINES
7555#line 1 "v7/src/regexp_public.h"
7556#endif
7557/*
7558 * Copyright (c) 2014 Cesanta Software Limited
7559 * All rights reserved
7560 */
7561
7562/*
7563 * === RegExp
7564 */
7565
7566#ifndef CS_V7_SRC_REGEXP_PUBLIC_H_
7567#define CS_V7_SRC_REGEXP_PUBLIC_H_
7568
7569/* Amalgamated: #include "v7/src/core_public.h" */
7570
7571#if defined(__cplusplus)
7572extern "C" {
7573#endif /* __cplusplus */
7574
7575/*
7576 * Make RegExp object.
7577 * `regex`, `regex_len` specify a pattern, `flags` and `flags_len` specify
7578 * flags. Both utf8 encoded. For example, `regex` is `(.+)`, `flags` is `gi`.
7579 * If `regex_len` is ~0, `regex` is assumed to be NUL-terminated and
7580 * `strlen(regex)` is used.
7581 */
7582WARN_UNUSED_RESULT
7583enum v7_err v7_mk_regexp(struct v7 *v7, const char *regex, size_t regex_len,
7584 const char *flags, size_t flags_len, v7_val_t *res);
7585
7586/* Returns true if given value is a JavaScript RegExp object*/
7587int v7_is_regexp(struct v7 *v7, v7_val_t v);
7588
7589#if defined(__cplusplus)
7590}
7591#endif /* __cplusplus */
7592
7593#endif /* CS_V7_SRC_REGEXP_PUBLIC_H_ */
7594#ifdef V7_MODULE_LINES
7595#line 1 "v7/src/regexp.h"
7596#endif
7597/*
7598 * Copyright (c) 2014 Cesanta Software Limited
7599 * All rights reserved
7600 */
7601
7602#ifndef CS_V7_SRC_REGEXP_H_
7603#define CS_V7_SRC_REGEXP_H_
7604
7605/* Amalgamated: #include "v7/src/regexp_public.h" */
7606
7607/* Amalgamated: #include "v7/src/core.h" */
7608
7609#if V7_ENABLE__RegExp
7610
7611/*
7612 * Maximum number of flags returned by get_regexp_flags_str().
7613 * NOTE: does not include null-terminate byte.
7614 */
7615#define _V7_REGEXP_MAX_FLAGS_LEN 3
7616
7617struct v7_regexp;
7618
7619V7_PRIVATE struct v7_regexp *v7_get_regexp_struct(struct v7 *, v7_val_t);
7620
7621/*
7622 * Generates a string containing regexp flags, e.g. "gi".
7623 *
7624 * `buf` should point to a buffer of minimum `_V7_REGEXP_MAX_FLAGS_LEN` bytes.
7625 * Returns length of the resulted string (saved into `buf`)
7626 */
7627V7_PRIVATE size_t
7628get_regexp_flags_str(struct v7 *v7, struct v7_regexp *rp, char *buf);
7629#endif /* V7_ENABLE__RegExp */
7630
7631#endif /* CS_V7_SRC_REGEXP_H_ */
7632#ifdef V7_MODULE_LINES
7633#line 1 "v7/src/function_public.h"
7634#endif
7635/*
7636 * Copyright (c) 2014 Cesanta Software Limited
7637 * All rights reserved
7638 */
7639
7640/*
7641 * === Functions
7642 */
7643
7644#ifndef CS_V7_SRC_FUNCTION_PUBLIC_H_
7645#define CS_V7_SRC_FUNCTION_PUBLIC_H_
7646
7647/* Amalgamated: #include "v7/src/core_public.h" */
7648
7649#if defined(__cplusplus)
7650extern "C" {
7651#endif /* __cplusplus */
7652
7653/*
7654 * Make a JS function object backed by a cfunction.
7655 *
7656 * `func` is a C callback.
7657 *
7658 * A function object is JS object having the Function prototype that holds a
7659 * cfunction value in a hidden property.
7660 *
7661 * The function object will have a `prototype` property holding an object that
7662 * will be used as the prototype of objects created when calling the function
7663 * with the `new` operator.
7664 */
7665v7_val_t v7_mk_function(struct v7 *, v7_cfunction_t *func);
7666
7667/*
7668 * Make f a JS function with specified prototype `proto`, so that the resulting
7669 * function is better suited for the usage as a constructor.
7670 */
7671v7_val_t v7_mk_function_with_proto(struct v7 *v7, v7_cfunction_t *f,
7672 v7_val_t proto);
7673
7674/*
7675 * Make a JS value that holds C/C++ callback pointer.
7676 *
7677 * CAUTION: This is a low-level function value. It's not a real object and
7678 * cannot hold user defined properties. You should use `v7_mk_function` unless
7679 * you know what you're doing.
7680 */
7681v7_val_t v7_mk_cfunction(v7_cfunction_t *func);
7682
7683/*
7684 * Returns true if given value is callable (i.e. it's either a JS function or
7685 * cfunction)
7686 */
7687int v7_is_callable(struct v7 *v7, v7_val_t v);
7688
7689#if defined(__cplusplus)
7690}
7691#endif /* __cplusplus */
7692
7693#endif /* CS_V7_SRC_FUNCTION_PUBLIC_H_ */
7694#ifdef V7_MODULE_LINES
7695#line 1 "v7/src/function.h"
7696#endif
7697/*
7698 * Copyright (c) 2014 Cesanta Software Limited
7699 * All rights reserved
7700 */
7701
7702#ifndef CS_V7_SRC_FUNCTION_H_
7703#define CS_V7_SRC_FUNCTION_H_
7704
7705/* Amalgamated: #include "v7/src/function_public.h" */
7706
7707/* Amalgamated: #include "v7/src/internal.h" */
7708/* Amalgamated: #include "v7/src/core.h" */
7709
7710#if defined(__cplusplus)
7711extern "C" {
7712#endif /* __cplusplus */
7713
7714V7_PRIVATE struct v7_js_function *get_js_function_struct(val_t v);
7715V7_PRIVATE val_t
7716mk_js_function(struct v7 *v7, struct v7_generic_object *scope, val_t proto);
7717V7_PRIVATE int is_js_function(val_t v);
7718V7_PRIVATE v7_val_t mk_cfunction_lite(v7_cfunction_t *f);
7719
7720/* Returns true if given value holds a pointer to C callback */
7721V7_PRIVATE int is_cfunction_lite(v7_val_t v);
7722
7723/* Returns true if given value holds an object which represents C callback */
7724V7_PRIVATE int is_cfunction_obj(struct v7 *v7, v7_val_t v);
7725
7726/*
7727 * Returns `v7_cfunction_t *` callback pointer stored in `v7_val_t`, or NULL
7728 * if given value is neither cfunction pointer nor cfunction object.
7729 */
7730V7_PRIVATE v7_cfunction_t *get_cfunction_ptr(struct v7 *v7, v7_val_t v);
7731
7732/*
7733 * Like v7_mk_function but also sets the function's `length` property.
7734 *
7735 * The `length` property is useful for introspection and the stdlib defines it
7736 * for many core functions mostly because the ECMA test suite requires it and we
7737 * don't want to skip otherwise useful tests just because the `length` property
7738 * check fails early in the test. User defined functions don't need to specify
7739 * the length and passing -1 is a safe choice, as it will also reduce the
7740 * footprint.
7741 *
7742 * The subtle difference between set `length` explicitly to 0 rather than
7743 * just defaulting the `0` value from the prototype is that in the former case
7744 * the property cannot be change since it's read only. This again, is important
7745 * only for ecma compliance and your user code might or might not find this
7746 * relevant.
7747 *
7748 * NODO(lsm): please don't combine v7_mk_function_arg and v7_mk_function
7749 * into one function. Currently `num_args` is useful only internally. External
7750 * users can just use `v7_def` to set the length.
7751 */
7752V7_PRIVATE
7753v7_val_t mk_cfunction_obj(struct v7 *v7, v7_cfunction_t *func, int num_args);
7754
7755/*
7756 * Like v7_mk_function_with_proto but also sets the function's `length`
7757 *property.
7758 *
7759 * NODO(lsm): please don't combine mk_cfunction_obj_with_proto and
7760 * v7_mk_function_with_proto.
7761 * into one function. Currently `num_args` is useful only internally. External
7762 * users can just use `v7_def` to set the length.
7763 */
7764V7_PRIVATE
7765v7_val_t mk_cfunction_obj_with_proto(struct v7 *v7, v7_cfunction_t *f,
7766 int num_args, v7_val_t proto);
7767
7768#if defined(__cplusplus)
7769}
7770#endif /* __cplusplus */
7771
7772#endif /* CS_V7_SRC_FUNCTION_H_ */
7773#ifdef V7_MODULE_LINES
7774#line 1 "v7/src/util_public.h"
7775#endif
7776/*
7777 * Copyright (c) 2014 Cesanta Software Limited
7778 * All rights reserved
7779 */
7780
7781/*
7782 * === Utility functions
7783 */
7784
7785#ifndef CS_V7_SRC_UTIL_PUBLIC_H_
7786#define CS_V7_SRC_UTIL_PUBLIC_H_
7787
7788/* Amalgamated: #include "v7/src/core_public.h" */
7789
7790#if defined(__cplusplus)
7791extern "C" {
7792#endif /* __cplusplus */
7793
7794/* Output a string representation of the value to stdout.
7795 * V7_STRINGIFY_DEBUG mode is used. */
7796void v7_print(struct v7 *v7, v7_val_t v);
7797
7798/* Output a string representation of the value to stdout followed by a newline.
7799 * V7_STRINGIFY_DEBUG mode is used. */
7800void v7_println(struct v7 *v7, v7_val_t v);
7801
7802/* Output a string representation of the value to a file.
7803 * V7_STRINGIFY_DEBUG mode is used. */
7804void v7_fprint(FILE *f, struct v7 *v7, v7_val_t v);
7805
7806/* Output a string representation of the value to a file followed by a newline.
7807 * V7_STRINGIFY_DEBUG mode is used. */
7808void v7_fprintln(FILE *f, struct v7 *v7, v7_val_t v);
7809
7810/* Output stack trace recorded in the exception `e` to file `f` */
7811void v7_fprint_stack_trace(FILE *f, struct v7 *v7, v7_val_t e);
7812
7813/* Output error object message and possibly stack trace to f */
7814void v7_print_error(FILE *f, struct v7 *v7, const char *ctx, v7_val_t e);
7815
7816#if V7_ENABLE__Proxy
7817
7818struct v7_property;
7819
7820/*
7821 * C callback, analogue of JS callback `getOwnPropertyDescriptor()`.
7822 * Callbacks of this type are used for C API only, see `m7_mk_proxy()`.
7823 *
7824 * `name` is the name of the property, and the function should fill `attrs` and
7825 * `value` with the property data. Before this callback is called, `attrs` is
7826 * set to 0, and `value` is `V7_UNDEFINED`.
7827 *
7828 * It should return non-zero if the property should be considered existing, or
7829 * zero otherwise.
7830 *
7831 * You can inspect the property attributes with the `V7_PROP_ATTR_IS_*` macros.
7832 */
7833typedef int(v7_get_own_prop_desc_cb_t)(struct v7 *v7, v7_val_t target,
7834 v7_val_t name, v7_prop_attr_t *attrs,
7835 v7_val_t *value);
7836
7837/* Handler for `v7_mk_proxy()`; each item is a cfunction */
7838typedef struct {
7839 v7_cfunction_t *get;
7840 v7_cfunction_t *set;
7841 v7_cfunction_t *own_keys;
7842 v7_get_own_prop_desc_cb_t *get_own_prop_desc;
7843} v7_proxy_hnd_t;
7844
7845/*
7846 * Create a Proxy object, see:
7847 * https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Proxy
7848 *
7849 * Only two traps are implemented so far: `get()` and `set()`. Note that
7850 * `Object.defineProperty()` bypasses the `set()` trap.
7851 *
7852 * If `target` is not an object, the empty object will be used, so it's safe
7853 * to pass `V7_UNDEFINED` as `target`.
7854 */
7855v7_val_t v7_mk_proxy(struct v7 *v7, v7_val_t target,
7856 const v7_proxy_hnd_t *handler);
7857
7858#endif /* V7_ENABLE__Proxy */
7859
7860#if defined(__cplusplus)
7861}
7862#endif /* __cplusplus */
7863
7864#endif /* CS_V7_SRC_UTIL_PUBLIC_H_ */
7865#ifdef V7_MODULE_LINES
7866#line 1 "v7/src/util.h"
7867#endif
7868/*
7869 * Copyright (c) 2014 Cesanta Software Limited
7870 * All rights reserved
7871 */
7872
7873#ifndef CS_V7_SRC_UTIL_H_
7874#define CS_V7_SRC_UTIL_H_
7875
7876/* Amalgamated: #include "v7/src/core.h" */
7877/* Amalgamated: #include "v7/src/util_public.h" */
7878
7879struct bcode;
7880
7881V7_PRIVATE enum v7_type val_type(struct v7 *v7, val_t v);
7882
7883#if !V7_DISABLE_LINE_NUMBERS
7884V7_PRIVATE uint8_t msb_lsb_swap(uint8_t b);
7885#endif
7886
7887/*
7888 * At the moment, all other utility functions are public, and are declared in
7889 * `util_public.h`
7890 */
7891
7892#endif /* CS_V7_SRC_UTIL_H_ */
7893#ifdef V7_MODULE_LINES
7894#line 1 "v7/src/shdata.h"
7895#endif
7896/*
7897 * Copyright (c) 2014 Cesanta Software Limited
7898 * All rights reserved
7899 */
7900
7901/*
7902 * shdata (stands for "shared data") is a simple module that allows to have
7903 * reference count for an arbitrary payload data, which will be freed as
7904 * necessary. A poor man's shared_ptr.
7905 */
7906
7907#ifndef CS_V7_SRC_SHDATA_H_
7908#define CS_V7_SRC_SHDATA_H_
7909
7910/* Amalgamated: #include "v7/src/internal.h" */
7911
7912#if !V7_DISABLE_FILENAMES && !V7_DISABLE_LINE_NUMBERS
7913struct shdata {
7914 /* Reference count */
7915 uint8_t refcnt;
7916
7917 /*
7918 * Note: we'd use `unsigned char payload[];` here, but we can't, since this
7919 * feature was introduced in C99 only
7920 */
7921};
7922
7923/*
7924 * Allocate memory chunk of appropriate size, copy given `payload` data there,
7925 * retain (`shdata_retain()`), and return it.
7926 */
7927V7_PRIVATE struct shdata *shdata_create(const void *payload, size_t size);
7928
7929V7_PRIVATE struct shdata *shdata_create_from_string(const char *src);
7930
7931/*
7932 * Increment reference count for the given shared data
7933 */
7934V7_PRIVATE void shdata_retain(struct shdata *p);
7935
7936/*
7937 * Decrement reference count for the given shared data
7938 */
7939V7_PRIVATE void shdata_release(struct shdata *p);
7940
7941/*
7942 * Get payload data
7943 */
7944V7_PRIVATE void *shdata_get_payload(struct shdata *p);
7945
7946#endif
7947#endif /* CS_V7_SRC_SHDATA_H_ */
7948#ifdef V7_MODULE_LINES
7949#line 1 "v7/src/eval.h"
7950#endif
7951/*
7952 * Copyright (c) 2014 Cesanta Software Limited
7953 * All rights reserved
7954 */
7955
7956#ifndef CS_V7_SRC_EVAL_H_
7957#define CS_V7_SRC_EVAL_H_
7958
7959/* Amalgamated: #include "v7/src/internal.h" */
7960/* Amalgamated: #include "v7/src/bcode.h" */
7961
7962struct v7_call_frame_base;
7963
7964#if defined(__cplusplus)
7965extern "C" {
7966#endif /* __cplusplus */
7967
7968WARN_UNUSED_RESULT
7969V7_PRIVATE enum v7_err eval_bcode(struct v7 *v7, struct bcode *bcode,
7970 val_t this_object, uint8_t reset_line_no,
7971 val_t *_res);
7972
7973WARN_UNUSED_RESULT
7974V7_PRIVATE enum v7_err b_apply(struct v7 *v7, v7_val_t func, v7_val_t this_obj,
7975 v7_val_t args, uint8_t is_constructor,
7976 v7_val_t *res);
7977
7978WARN_UNUSED_RESULT
7979V7_PRIVATE enum v7_err b_exec(struct v7 *v7, const char *src, size_t src_len,
7980 const char *filename, val_t func, val_t args,
7981 val_t this_object, int is_json, int fr,
7982 uint8_t is_constructor, val_t *res);
7983
7984/*
7985 * Try to find the call frame whose `type_mask` intersects with the given
7986 * `type_mask`.
7987 *
7988 * Start from the top call frame, and go deeper until the matching frame is
7989 * found, or there's no more call frames. If the needed frame was not found,
7990 * returns `NULL`.
7991 */
7992V7_PRIVATE struct v7_call_frame_base *find_call_frame(struct v7 *v7,
7993 uint8_t type_mask);
7994
7995#if defined(__cplusplus)
7996}
7997#endif /* __cplusplus */
7998
7999#endif /* CS_V7_SRC_EVAL_H_ */
8000#ifdef V7_MODULE_LINES
8001#line 1 "v7/src/compiler.h"
8002#endif
8003/*
8004 * Copyright (c) 2014 Cesanta Software Limited
8005 * All rights reserved
8006 */
8007
8008#ifndef CS_V7_SRC_COMPILER_H_
8009#define CS_V7_SRC_COMPILER_H_
8010
8011/* Amalgamated: #include "v7/src/internal.h" */
8012/* Amalgamated: #include "v7/src/bcode.h" */
8013/* Amalgamated: #include "v7/src/ast.h" */
8014
8015#if !defined(V7_NO_COMPILER)
8016
8017#if defined(__cplusplus)
8018extern "C" {
8019#endif /* __cplusplus */
8020
8021V7_PRIVATE enum v7_err compile_script(struct v7 *v7, struct ast *a,
8022 struct bcode *bcode);
8023
8024V7_PRIVATE enum v7_err compile_expr(struct v7 *v7, struct ast *a,
8025 ast_off_t *ppos, struct bcode *bcode);
8026
8027#if defined(__cplusplus)
8028}
8029#endif /* __cplusplus */
8030
8031#endif /* V7_NO_COMPILER */
8032
8033#endif /* CS_V7_SRC_COMPILER_H_ */
8034#ifdef V7_MODULE_LINES
8035#line 1 "v7/src/cyg_profile.h"
8036#endif
8037/*
8038 * Copyright (c) 2014 Cesanta Software Limited
8039 * All rights reserved
8040 */
8041
8042#ifndef CS_V7_SRC_CYG_PROFILE_H_
8043#define CS_V7_SRC_CYG_PROFILE_H_
8044
8045/*
8046 * This file contains GCC/clang instrumentation callbacks, as well as
8047 * accompanying code. The actual code in these callbacks depends on enabled
8048 * features. See cyg_profile.c for some implementation details rationale.
8049 */
8050
8051struct v7;
8052
8053#if V7_ENABLE_STACK_TRACKING
8054
8055/*
8056 * Stack-tracking functionality:
8057 *
8058 * The idea is that the caller should allocate `struct stack_track_ctx`
8059 * (typically on stack) in the function to track the stack usage of, and call
8060 * `v7_stack_track_start()` in the beginning.
8061 *
8062 * Before quitting current stack frame (for example, before returning from
8063 * function), call `v7_stack_track_end()`, which returns the maximum stack
8064 * consumed size.
8065 *
8066 * These calls can be nested: for example, we may track the stack usage of the
8067 * whole application by using these functions in `main()`, as well as track
8068 * stack usage of any nested functions.
8069 *
8070 * Just to stress: both `v7_stack_track_start()` / `v7_stack_track_end()`
8071 * should be called for the same instance of `struct stack_track_ctx` in the
8072 * same stack frame.
8073 */
8074
8075/* stack tracking context */
8076struct stack_track_ctx {
8077 struct stack_track_ctx *next;
8078 void *start;
8079 void *max;
8080};
8081
8082/* see explanation above */
8083void v7_stack_track_start(struct v7 *v7, struct stack_track_ctx *ctx);
8084/* see explanation above */
8085int v7_stack_track_end(struct v7 *v7, struct stack_track_ctx *ctx);
8086
8087void v7_stack_stat_clean(struct v7 *v7);
8088
8089#endif /* V7_ENABLE_STACK_TRACKING */
8090
8091#endif /* CS_V7_SRC_CYG_PROFILE_H_ */
8092#ifdef V7_MODULE_LINES
8093#line 1 "v7/builtin/builtin.h"
8094#endif
8095/*
8096 * Copyright (c) 2015 Cesanta Software Limited
8097 * All rights reserved
8098 */
8099
8100/*
8101 * === Non-Standard API
8102 *
8103 * V7 has several non-standard extensions for `String.prototype` in
8104 * order to give a compact and fast API to access raw data obtained from
8105 * File, Socket, and hardware input/output such as I2C.
8106 * V7 IO API functions return
8107 * string data as a result of read operations, and that string data is a
8108 * raw byte array. ECMA6 provides `ArrayBuffer` and `DataView` API for dealing
8109 * with raw bytes, because strings in JavaScript are Unicode. That standard
8110 * API is too bloated for the embedded use, and does not allow to use handy
8111 * String API (e.g. `.match()`) against data.
8112 *
8113 * V7 internally stores strings as byte arrays. All strings created by the
8114 * String API are UTF8 encoded. Strings that are the result of
8115 * input/output API calls might not be a valid UTF8 strings, but nevertheless
8116 * they are represented as strings, and the following API allows to access
8117 * underlying byte sequence:
8118 *
8119 * ==== String.prototype.at(position) -> number or NaN
8120 * Return byte at index
8121 * `position`. Byte value is in 0,255 range. If `position` is out of bounds
8122 * (either negative or larger then the byte array length), NaN is returned.
8123 * Example: `"ы".at(0)` returns 0xd1.
8124 *
8125 * ==== String.prototype.blen -> number
8126 * Return string length in bytes.
8127 * Example: `"ы".blen` returns 2. Note that `"ы".length` is 1, since that
8128 * string consists of a single Unicode character (2-byte).
8129 *
8130 * === Builtin API
8131 *
8132 * Builtin API provides additional JavaScript interfaces available for V7
8133 * scripts.
8134 * File API is a wrapper around standard C calls `fopen()`, `fclose()`,
8135 * `fread()`, `fwrite()`, `rename()`, `remove()`.
8136 * Crypto API provides functions for base64, md5, and sha1 encoding/decoding.
8137 * Socket API provides low-level socket API.
8138 *
8139 * ==== File.eval(file_name)
8140 * Parse and run `file_name`.
8141 * Throws an exception if the file doesn't exist, cannot be parsed or if the
8142 * script throws any exception.
8143 *
8144 * ==== File.read(file_name) -> string or undefined
8145 * Read file `file_name` and return a string with a file content.
8146 * On any error, return `undefined` as a result.
8147 *
8148 * ==== File.write(file_name, str) -> true or false
8149 * Write string `str` to a file `file_name`. Return `true` on success,
8150 * `false` on error.
8151 *
8152 * ==== File.open(file_name [, mode]) -> file_object or null
8153 * Open a file `path`. For
8154 * list of valid `mode` values, see `fopen()` documentation. If `mode` is
8155 * not specified, mode `rb` is used, i.e. file is opened in read-only mode.
8156 * Return an opened file object, or null on error. Example:
8157 * `var f = File.open('/etc/passwd'); f.close();`
8158 *
8159 * ==== file_obj.close() -> undefined
8160 * Close opened file object.
8161 * NOTE: it is user's responsibility to close all opened file streams. V7
8162 * does not do that automatically.
8163 *
8164 * ==== file_obj.read() -> string
8165 * Read portion of data from
8166 * an opened file stream. Return string with data, or empty string on EOF
8167 * or error.
8168 *
8169 * ==== file_obj.write(str) -> num_bytes_written
8170 * Write string `str` to the opened file object. Return number of bytes written.
8171 *
8172 * ==== File.rename(old_name, new_name) -> errno
8173 * Rename file `old_name` to
8174 * `new_name`. Return 0 on success, or `errno` value on error.
8175 *
8176 * ==== File.list(dir_name) -> array_of_names
8177 * Return a list of files in a given directory, or `undefined` on error.
8178 *
8179 * ==== File.remove(file_name) -> errno
8180 * Delete file `file_name`.
8181 * Return 0 on success, or `errno` value on error.
8182 *
8183 * ==== Crypto.base64_encode(str)
8184 * Base64-encode input string `str` and return encoded string.
8185 *
8186 * ==== Crypto.base64_decode(str)
8187 * Base64-decode input string `str` and return decoded string.
8188 *
8189 * ==== Crypto.md5(str), Crypto.md5_hex(str)
8190 * Generate MD5 hash from input string `str`. Return 16-byte hash (`md5()`),
8191 * or stringified hexadecimal representation of the hash (`md5_hex`).
8192 *
8193 * ==== Crypto.sha1(str), Crypto.sha1_hex(str)
8194 * Generate SHA1 hash from input string `str`. Return 20-byte hash (`sha1()`),
8195 * or stringified hexadecimal representation of the hash (`sha1_hex`).
8196 *
8197 * ==== Socket.connect(host, port [, is_udp]) -> socket_obj
8198 * Connect to a given host. `host` can be a string IP address, or a host name.
8199 * Optional `is_udp` parameter, if true, indicates that socket should be UDP.
8200 * Return socket object on success, null on error.
8201 *
8202 * ==== Socket.listen(port [, ip_address [,is_udp]]) -> socket_obj
8203 * Create a listening socket on a given port. Optional `ip_address` argument
8204 * specifies and IP address to bind to. Optional `is_udp` parameter, if true,
8205 * indicates that socket should be UDP. Return socket object on success,
8206 * null on error.
8207 *
8208 * ==== socket_obj.accept() -> socket_obj
8209 * Sleep until new incoming connection is arrived. Return accepted socket
8210 * object on success, or `null` on error.
8211 *
8212 * ==== socket_obj.close() -> numeric_errno
8213 * Close socket object. Return 0 on success, or system errno on error.
8214 *
8215 * ==== socket_obj.recv() -> string
8216 * Read data from socket. Return data string, or empty string if peer has
8217 * disconnected, or `null` on error.
8218 *
8219 * ==== socket_obj.recvAll() -> string
8220 * Same as `recv()`, but keeps reading data until socket is closed.
8221 *
8222 * ==== sock.send(string) -> num_bytes_sent
8223 * Send string to the socket. Return number of bytes sent, or 0 on error.
8224 * Simple HTTP client example:
8225 *
8226 * var s = Socket.connect("google.com", 80);
8227 * s.send("GET / HTTP/1.0\n\n");
8228 * var reply = s.recv();
8229 */
8230
8231#ifndef CS_V7_BUILTIN_BUILTIN_H_
8232#define CS_V7_BUILTIN_BUILTIN_H_
8233
8234struct v7;
8235
8236void init_file(struct v7 *);
8237void init_socket(struct v7 *);
8238void init_crypto(struct v7 *);
8239
8240#endif /* CS_V7_BUILTIN_BUILTIN_H_ */
8241#ifdef V7_MODULE_LINES
8242#line 1 "v7/src/slre.h"
8243#endif
8244/*
8245 * Copyright (c) 2014 Cesanta Software Limited
8246 * All rights reserved
8247 *
8248 * This software is dual-licensed: you can redistribute it and/or modify
8249 * it under the terms of the GNU General Public License version 2 as
8250 * published by the Free Software Foundation. For the terms of this
8251 * license, see <http://www.gnu.org/licenses/>.
8252 *
8253 * You are free to use this software under the terms of the GNU General
8254 * Public License, but WITHOUT ANY WARRANTY; without even the implied
8255 * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
8256 * See the GNU General Public License for more details.
8257 *
8258 * Alternatively, you can license this software under a commercial
8259 * license, as set out in <https://www.cesanta.com/license>.
8260 */
8261
8262#ifndef CS_V7_SRC_SLRE_H_
8263#define CS_V7_SRC_SLRE_H_
8264
8265/* Return codes for slre_compile() */
8266enum slre_error {
8267 SLRE_OK,
8268 SLRE_INVALID_DEC_DIGIT,
8269 SLRE_INVALID_HEX_DIGIT,
8270 SLRE_INVALID_ESC_CHAR,
8271 SLRE_UNTERM_ESC_SEQ,
8272 SLRE_SYNTAX_ERROR,
8273 SLRE_UNMATCH_LBR,
8274 SLRE_UNMATCH_RBR,
8275 SLRE_NUM_OVERFLOW,
8276 SLRE_INF_LOOP_M_EMP_STR,
8277 SLRE_TOO_MANY_CHARSETS,
8278 SLRE_INV_CHARSET_RANGE,
8279 SLRE_CHARSET_TOO_LARGE,
8280 SLRE_MALFORMED_CHARSET,
8281 SLRE_INVALID_BACK_REFERENCE,
8282 SLRE_TOO_MANY_CAPTURES,
8283 SLRE_INVALID_QUANTIFIER,
8284 SLRE_BAD_CHAR_AFTER_USD
8285};
8286
8287#if V7_ENABLE__RegExp
8288
8289#ifdef __cplusplus
8290extern "C" {
8291#endif /* __cplusplus */
8292
8293/* Regex flags */
8294#define SLRE_FLAG_G 1 /* Global - match in the whole string */
8295#define SLRE_FLAG_I 2 /* Ignore case */
8296#define SLRE_FLAG_M 4 /* Multiline */
8297#define SLRE_FLAG_RE 8 /* flag RegExp/String */
8298
8299/* Describes single capture */
8300struct slre_cap {
8301 const char *start; /* points to the beginning of the capture group */
8302 const char *end; /* points to the end of the capture group */
8303};
8304
8305/* Describes all captures */
8306#define SLRE_MAX_CAPS 32
8307struct slre_loot {
8308 int num_captures;
8309 struct slre_cap caps[SLRE_MAX_CAPS];
8310};
8311
8312/* Opaque structure that holds compiled regular expression */
8313struct slre_prog;
8314
8315int slre_compile(const char *regexp, size_t regexp_len, const char *flags,
8316 size_t flags_len, struct slre_prog **, int is_regex);
8317int slre_exec(struct slre_prog *prog, int flag_g, const char *start,
8318 const char *end, struct slre_loot *loot);
8319void slre_free(struct slre_prog *prog);
8320
8321int slre_match(const char *, size_t, const char *, size_t, const char *, size_t,
8322 struct slre_loot *);
8323int slre_replace(struct slre_loot *loot, const char *src, size_t src_len,
8324 const char *replace, size_t rep_len, struct slre_loot *dst);
8325int slre_get_flags(struct slre_prog *);
8326
8327#ifdef __cplusplus
8328}
8329#endif /* __cplusplus */
8330
8331#endif /* V7_ENABLE__RegExp */
8332
8333#endif /* CS_V7_SRC_SLRE_H_ */
8334#ifdef V7_MODULE_LINES
8335#line 1 "v7/src/stdlib.h"
8336#endif
8337/*
8338 * Copyright (c) 2014 Cesanta Software Limited
8339 * All rights reserved
8340 */
8341
8342#ifndef CS_V7_SRC_STDLIB_H_
8343#define CS_V7_SRC_STDLIB_H_
8344
8345/* Amalgamated: #include "v7/src/internal.h" */
8346/* Amalgamated: #include "v7/src/core.h" */
8347
8348#if defined(__cplusplus)
8349extern "C" {
8350#endif /* __cplusplus */
8351
8352/*V7_PRIVATE*/ void init_stdlib(struct v7 *v7);
8353
8354WARN_UNUSED_RESULT
8355V7_PRIVATE enum v7_err std_eval(struct v7 *v7, v7_val_t arg, v7_val_t this_obj,
8356 int is_json, v7_val_t *res);
8357
8358#if defined(__cplusplus)
8359}
8360#endif /* __cplusplus */
8361
8362#endif /* CS_V7_SRC_STDLIB_H_ */
8363#ifdef V7_MODULE_LINES
8364#line 1 "v7/src/heapusage.h"
8365#endif
8366/*
8367 * Copyright (c) 2014-2016 Cesanta Software Limited
8368 * All rights reserved
8369 */
8370
8371#ifndef CS_V7_SRC_HEAPUSAGE_H_
8372#define CS_V7_SRC_HEAPUSAGE_H_
8373
8374#if V7_HEAPUSAGE_ENABLE
8375
8376extern volatile int heap_dont_count;
8377
8378/*
8379 * Returns total heap-allocated size in bytes (without any overhead of the
8380 * heap implementation)
8381 */
8382size_t heapusage_alloc_size(void);
8383
8384/*
8385 * Returns number of active allocations
8386 */
8387size_t heapusage_allocs_cnt(void);
8388
8389/*
8390 * Must be called before allocating some memory that should not be indicated as
8391 * memory consumed for some particular operation: for example, when we
8392 * preallocate some GC buffer.
8393 */
8394#define heapusage_dont_count(a) \
8395 do { \
8396 heap_dont_count = a; \
8397 } while (0)
8398
8399#else /* V7_HEAPUSAGE_ENABLE */
8400
8401#define heapusage_alloc_size() (0)
8402#define heapusage_allocs_cnt() (0)
8403#define heapusage_dont_count(a)
8404
8405#endif /* V7_HEAPUSAGE_ENABLE */
8406
8407#endif /* CS_V7_SRC_HEAPUSAGE_H_ */
8408#ifdef V7_MODULE_LINES
8409#line 1 "v7/src/std_proxy.h"
8410#endif
8411/*
8412 * Copyright (c) 2014 Cesanta Software Limited
8413 * All rights reserved
8414 */
8415
8416#ifndef CS_V7_SRC_STD_PROXY_H_
8417#define CS_V7_SRC_STD_PROXY_H_
8418
8419/* Amalgamated: #include "v7/src/internal.h" */
8420/* Amalgamated: #include "v7/src/core.h" */
8421
8422#if V7_ENABLE__Proxy
8423
8424#define _V7_PROXY_TARGET_NAME "__tgt"
8425#define _V7_PROXY_HANDLER_NAME "__hnd"
8426
8427#if defined(__cplusplus)
8428extern "C" {
8429#endif /* __cplusplus */
8430
8431#if V7_ENABLE__Proxy
8432
8433V7_PRIVATE enum v7_err Proxy_ctor(struct v7 *v7, v7_val_t *res);
8434
8435V7_PRIVATE void init_proxy(struct v7 *v7);
8436
8437/*
8438 * Returns whether the given name is one of the special Proxy names
8439 * (_V7_PROXY_TARGET_NAME or _V7_PROXY_HANDLER_NAME)
8440 */
8441V7_PRIVATE int is_special_proxy_name(const char *name, size_t name_len);
8442
8443#endif
8444
8445#if defined(__cplusplus)
8446}
8447#endif /* __cplusplus */
8448
8449#endif /* V7_ENABLE__Proxy */
8450
8451#endif /* CS_V7_SRC_STD_PROXY_H_ */
8452#ifdef V7_MODULE_LINES
8453#line 1 "v7/src/freeze.h"
8454#endif
8455/*
8456 * Copyright (c) 2014 Cesanta Software Limited
8457 * All rights reserved
8458 */
8459
8460#ifndef CS_V7_SRC_FREEZE_H_
8461#define CS_V7_SRC_FREEZE_H_
8462
8463#ifdef V7_FREEZE
8464
8465/* Amalgamated: #include "v7/src/internal.h" */
8466
8467struct v7_property;
8468
8469#if defined(__cplusplus)
8470extern "C" {
8471#endif /* __cplusplus */
8472
8473V7_PRIVATE void freeze(struct v7 *v7, char *filename);
8474V7_PRIVATE void freeze_obj(struct v7 *v7, FILE *f, v7_val_t v);
8475V7_PRIVATE void freeze_prop(struct v7 *v7, FILE *f, struct v7_property *prop);
8476
8477#if defined(__cplusplus)
8478}
8479#endif /* __cplusplus */
8480
8481#endif /* V7_FREEZE */
8482
8483#endif /* CS_V7_SRC_FREEZE_H_ */
8484#ifdef V7_MODULE_LINES
8485#line 1 "v7/src/std_array.h"
8486#endif
8487/*
8488 * Copyright (c) 2014 Cesanta Software Limited
8489 * All rights reserved
8490 */
8491
8492#ifndef CS_V7_SRC_STD_ARRAY_H_
8493#define CS_V7_SRC_STD_ARRAY_H_
8494
8495/* Amalgamated: #include "v7/src/internal.h" */
8496
8497#if defined(__cplusplus)
8498extern "C" {
8499#endif /* __cplusplus */
8500
8501V7_PRIVATE void init_array(struct v7 *v7);
8502
8503#if defined(__cplusplus)
8504}
8505#endif /* __cplusplus */
8506
8507#endif /* CS_V7_SRC_STD_ARRAY_H_ */
8508#ifdef V7_MODULE_LINES
8509#line 1 "v7/src/std_boolean.h"
8510#endif
8511/*
8512 * Copyright (c) 2014 Cesanta Software Limited
8513 * All rights reserved
8514 */
8515
8516#ifndef CS_V7_SRC_STD_BOOLEAN_H_
8517#define CS_V7_SRC_STD_BOOLEAN_H_
8518
8519/* Amalgamated: #include "v7/src/internal.h" */
8520
8521#if defined(__cplusplus)
8522extern "C" {
8523#endif /* __cplusplus */
8524
8525V7_PRIVATE void init_boolean(struct v7 *v7);
8526
8527#if defined(__cplusplus)
8528}
8529#endif /* __cplusplus */
8530
8531#endif /* CS_V7_SRC_STD_BOOLEAN_H_ */
8532#ifdef V7_MODULE_LINES
8533#line 1 "v7/src/std_date.h"
8534#endif
8535/*
8536 * Copyright (c) 2014 Cesanta Software Limited
8537 * All rights reserved
8538 */
8539
8540#ifndef CS_V7_SRC_STD_DATE_H_
8541#define CS_V7_SRC_STD_DATE_H_
8542
8543/* Amalgamated: #include "v7/src/internal.h" */
8544
8545#if V7_ENABLE__Date
8546
8547#if defined(__cplusplus)
8548extern "C" {
8549#endif /* __cplusplus */
8550
8551V7_PRIVATE void init_date(struct v7 *v7);
8552
8553#if defined(__cplusplus)
8554}
8555#endif /* __cplusplus */
8556
8557#endif /* V7_ENABLE__Date */
8558#endif /* CS_V7_SRC_STD_DATE_H_ */
8559#ifdef V7_MODULE_LINES
8560#line 1 "v7/src/std_function.h"
8561#endif
8562/*
8563 * Copyright (c) 2014 Cesanta Software Limited
8564 * All rights reserved
8565 */
8566
8567#ifndef CS_V7_SRC_STD_FUNCTION_H_
8568#define CS_V7_SRC_STD_FUNCTION_H_
8569
8570/* Amalgamated: #include "v7/src/internal.h" */
8571
8572#if defined(__cplusplus)
8573extern "C" {
8574#endif /* __cplusplus */
8575
8576V7_PRIVATE void init_function(struct v7 *v7);
8577
8578#if defined(__cplusplus)
8579}
8580#endif /* __cplusplus */
8581
8582#endif /* CS_V7_SRC_STD_FUNCTION_H_ */
8583#ifdef V7_MODULE_LINES
8584#line 1 "v7/src/std_json.h"
8585#endif
8586/*
8587 * Copyright (c) 2014 Cesanta Software Limited
8588 * All rights reserved
8589 */
8590
8591#ifndef CS_V7_SRC_STD_JSON_H_
8592#define CS_V7_SRC_STD_JSON_H_
8593
8594/* Amalgamated: #include "v7/src/internal.h" */
8595
8596#if defined(__cplusplus)
8597extern "C" {
8598#endif /* __cplusplus */
8599
8600V7_PRIVATE void init_json(struct v7 *v7);
8601
8602#if defined(__cplusplus)
8603}
8604#endif /* __cplusplus */
8605
8606#endif /* CS_V7_SRC_STD_JSON_H_ */
8607#ifdef V7_MODULE_LINES
8608#line 1 "v7/src/std_math.h"
8609#endif
8610/*
8611 * Copyright (c) 2014 Cesanta Software Limited
8612 * All rights reserved
8613 */
8614
8615#ifndef CS_V7_SRC_STD_MATH_H_
8616#define CS_V7_SRC_STD_MATH_H_
8617
8618/* Amalgamated: #include "v7/src/internal.h" */
8619
8620#if V7_ENABLE__Math
8621
8622#if defined(__cplusplus)
8623extern "C" {
8624#endif /* __cplusplus */
8625
8626V7_PRIVATE void init_math(struct v7 *v7);
8627
8628#if defined(__cplusplus)
8629}
8630#endif /* __cplusplus */
8631
8632#endif /* V7_ENABLE__Math */
8633#endif /* CS_V7_SRC_STD_MATH_H_ */
8634#ifdef V7_MODULE_LINES
8635#line 1 "v7/src/std_number.h"
8636#endif
8637/*
8638 * Copyright (c) 2014 Cesanta Software Limited
8639 * All rights reserved
8640 */
8641
8642#ifndef CS_V7_SRC_STD_NUMBER_H_
8643#define CS_V7_SRC_STD_NUMBER_H_
8644
8645/* Amalgamated: #include "v7/src/internal.h" */
8646
8647#if defined(__cplusplus)
8648extern "C" {
8649#endif /* __cplusplus */
8650
8651V7_PRIVATE void init_number(struct v7 *v7);
8652
8653#if defined(__cplusplus)
8654}
8655#endif /* __cplusplus */
8656
8657#endif /* CS_V7_SRC_STD_NUMBER_H_ */
8658#ifdef V7_MODULE_LINES
8659#line 1 "v7/src/std_object.h"
8660#endif
8661/*
8662 * Copyright (c) 2014 Cesanta Software Limited
8663 * All rights reserved
8664 */
8665
8666#ifndef CS_V7_SRC_STD_OBJECT_H_
8667#define CS_V7_SRC_STD_OBJECT_H_
8668
8669/* Amalgamated: #include "v7/src/internal.h" */
8670/* Amalgamated: #include "v7/src/core.h" */
8671
8672struct v7;
8673
8674#if defined(__cplusplus)
8675extern "C" {
8676#endif /* __cplusplus */
8677
8678V7_PRIVATE void init_object(struct v7 *v7);
8679
8680WARN_UNUSED_RESULT
8681V7_PRIVATE enum v7_err Obj_valueOf(struct v7 *v7, v7_val_t *res);
8682
8683#if defined(__cplusplus)
8684}
8685#endif /* __cplusplus */
8686
8687#endif /* CS_V7_SRC_STD_OBJECT_H_ */
8688#ifdef V7_MODULE_LINES
8689#line 1 "v7/src/std_regex.h"
8690#endif
8691/*
8692 * Copyright (c) 2014 Cesanta Software Limited
8693 * All rights reserved
8694 */
8695
8696#ifndef CS_V7_SRC_STD_REGEX_H_
8697#define CS_V7_SRC_STD_REGEX_H_
8698
8699/* Amalgamated: #include "v7/src/internal.h" */
8700/* Amalgamated: #include "v7/src/core.h" */
8701
8702#if V7_ENABLE__RegExp
8703
8704#if defined(__cplusplus)
8705extern "C" {
8706#endif /* __cplusplus */
8707
8708V7_PRIVATE enum v7_err Regex_ctor(struct v7 *v7, v7_val_t *res);
8709V7_PRIVATE enum v7_err rx_exec(struct v7 *v7, v7_val_t rx, v7_val_t vstr,
8710 int lind, v7_val_t *res);
8711
8712V7_PRIVATE void init_regex(struct v7 *v7);
8713
8714#if defined(__cplusplus)
8715}
8716#endif /* __cplusplus */
8717
8718#endif /* V7_ENABLE__RegExp */
8719
8720#endif /* CS_V7_SRC_STD_REGEX_H_ */
8721#ifdef V7_MODULE_LINES
8722#line 1 "v7/src/std_string.h"
8723#endif
8724/*
8725 * Copyright (c) 2014 Cesanta Software Limited
8726 * All rights reserved
8727 */
8728
8729#ifndef CS_V7_SRC_STD_STRING_H_
8730#define CS_V7_SRC_STD_STRING_H_
8731
8732/* Amalgamated: #include "v7/src/internal.h" */
8733/* Amalgamated: #include "v7/src/core.h" */
8734
8735/* Max captures for String.replace() */
8736#define V7_RE_MAX_REPL_SUB 20
8737
8738#if defined(__cplusplus)
8739extern "C" {
8740#endif /* __cplusplus */
8741
8742V7_PRIVATE void init_string(struct v7 *v7);
8743
8744#if defined(__cplusplus)
8745}
8746#endif /* __cplusplus */
8747
8748#endif /* CS_V7_SRC_STD_STRING_H_ */
8749#ifdef V7_MODULE_LINES
8750#line 1 "v7/src/js_stdlib.h"
8751#endif
8752/*
8753 * Copyright (c) 2014 Cesanta Software Limited
8754 * All rights reserved
8755 */
8756
8757#ifndef CS_V7_SRC_JS_STDLIB_H_
8758#define CS_V7_SRC_JS_STDLIB_H_
8759
8760/* Amalgamated: #include "v7/src/internal.h" */
8761
8762#if defined(__cplusplus)
8763extern "C" {
8764#endif /* __cplusplus */
8765
8766V7_PRIVATE void init_js_stdlib(struct v7 *);
8767
8768#if defined(__cplusplus)
8769}
8770#endif /* __cplusplus */
8771
8772#endif /* CS_V7_SRC_JS_STDLIB_H_ */
8773#ifdef V7_MODULE_LINES
8774#line 1 "v7/src/main_public.h"
8775#endif
8776/*
8777 * Copyright (c) 2014 Cesanta Software Limited
8778 * All rights reserved
8779 */
8780
8781/*
8782 * === v7 main()
8783 */
8784
8785#ifndef CS_V7_SRC_MAIN_PUBLIC_H_
8786#define CS_V7_SRC_MAIN_PUBLIC_H_
8787
8788/* Amalgamated: #include "v7/src/core_public.h" */
8789
8790#if defined(__cplusplus)
8791extern "C" {
8792#endif /* __cplusplus */
8793
8794/*
8795 * V7 executable main function.
8796 *
8797 * There are various callbacks available:
8798 *
8799 * `pre_freeze_init()` and `pre_init()` are optional intialization functions,
8800 * aimed to export any extra functionality into vanilla v7 engine. They are
8801 * called after v7 initialization, before executing given files or inline
8802 * expressions. `pre_freeze_init()` is called before "freezing" v7 state;
8803 * whereas `pre_init` called afterwards.
8804 *
8805 * `post_init()`, if provided, is called after executing files and expressions,
8806 * before destroying v7 instance and exiting.
8807 */
8808int v7_main(int argc, char *argv[], void (*pre_freeze_init)(struct v7 *),
8809 void (*pre_init)(struct v7 *), void (*post_init)(struct v7 *));
8810
8811#if defined(__cplusplus)
8812}
8813#endif /* __cplusplus */
8814
8815#endif /* CS_V7_SRC_MAIN_PUBLIC_H_ */
8816#ifdef V7_MODULE_LINES
8817#line 1 "v7/src/main.h"
8818#endif
8819/*
8820 * Copyright (c) 2014 Cesanta Software Limited
8821 * All rights reserved
8822 */
8823
8824#ifndef CS_V7_SRC_MAIN_H_
8825#define CS_V7_SRC_MAIN_H_
8826
8827/* Amalgamated: #include "v7/src/main_public.h" */
8828
8829#endif /* CS_V7_SRC_MAIN_H_ */
8830#ifndef V7_EXPORT_INTERNAL_HEADERS
8831#ifdef V7_MODULE_LINES
8832#line 1 "common/mbuf.c"
8833#endif
8834/*
8835 * Copyright (c) 2014 Cesanta Software Limited
8836 * All rights reserved
8837 */
8838
8839#ifndef EXCLUDE_COMMON
8840
8841#include <assert.h>
8842#include <string.h>
8843/* Amalgamated: #include "common/mbuf.h" */
8844
8845#ifndef MBUF_REALLOC
8846#define MBUF_REALLOC realloc
8847#endif
8848
8849#ifndef MBUF_FREE
8850#define MBUF_FREE free
8851#endif
8852
8853void mbuf_init(struct mbuf *mbuf, size_t initial_size) WEAK;
8854void mbuf_init(struct mbuf *mbuf, size_t initial_size) {
8855 mbuf->len = mbuf->size = 0;
8856 mbuf->buf = NULL;
8857 mbuf_resize(mbuf, initial_size);
8858}
8859
8860void mbuf_free(struct mbuf *mbuf) WEAK;
8861void mbuf_free(struct mbuf *mbuf) {
8862 if (mbuf->buf != NULL) {
8863 MBUF_FREE(mbuf->buf);
8864 mbuf_init(mbuf, 0);
8865 }
8866}
8867
8868void mbuf_resize(struct mbuf *a, size_t new_size) WEAK;
8869void mbuf_resize(struct mbuf *a, size_t new_size) {
8870 if (new_size > a->size || (new_size < a->size && new_size >= a->len)) {
8871 char *buf = (char *) MBUF_REALLOC(a->buf, new_size);
8872 /*
8873 * In case realloc fails, there's not much we can do, except keep things as
8874 * they are. Note that NULL is a valid return value from realloc when
8875 * size == 0, but that is covered too.
8876 */
8877 if (buf == NULL && new_size != 0) return;
8878 a->buf = buf;
8879 a->size = new_size;
8880 }
8881}
8882
8883void mbuf_trim(struct mbuf *mbuf) WEAK;
8884void mbuf_trim(struct mbuf *mbuf) {
8885 mbuf_resize(mbuf, mbuf->len);
8886}
8887
8888size_t mbuf_insert(struct mbuf *a, size_t off, const void *buf, size_t) WEAK;
8889size_t mbuf_insert(struct mbuf *a, size_t off, const void *buf, size_t len) {
8890 char *p = NULL;
8891
8892 assert(a != NULL);
8893 assert(a->len <= a->size);
8894 assert(off <= a->len);
8895
8896 /* check overflow */
8897 if (~(size_t) 0 - (size_t) a->buf < len) return 0;
8898
8899 if (a->len + len <= a->size) {
8900 memmove(a->buf + off + len, a->buf + off, a->len - off);
8901 if (buf != NULL) {
8902 memcpy(a->buf + off, buf, len);
8903 }
8904 a->len += len;
8905 } else {
8906 size_t new_size = (size_t)((a->len + len) * MBUF_SIZE_MULTIPLIER);
8907 if ((p = (char *) MBUF_REALLOC(a->buf, new_size)) != NULL) {
8908 a->buf = p;
8909 memmove(a->buf + off + len, a->buf + off, a->len - off);
8910 if (buf != NULL) memcpy(a->buf + off, buf, len);
8911 a->len += len;
8912 a->size = new_size;
8913 } else {
8914 len = 0;
8915 }
8916 }
8917
8918 return len;
8919}
8920
8921size_t mbuf_append(struct mbuf *a, const void *buf, size_t len) WEAK;
8922size_t mbuf_append(struct mbuf *a, const void *buf, size_t len) {
8923 return mbuf_insert(a, a->len, buf, len);
8924}
8925
8926void mbuf_remove(struct mbuf *mb, size_t n) WEAK;
8927void mbuf_remove(struct mbuf *mb, size_t n) {
8928 if (n > 0 && n <= mb->len) {
8929 memmove(mb->buf, mb->buf + n, mb->len - n);
8930 mb->len -= n;
8931 }
8932}
8933
8934#endif /* EXCLUDE_COMMON */
8935#ifdef V7_MODULE_LINES
8936#line 1 "common/str_util.c"
8937#endif
8938/*
8939 * Copyright (c) 2015 Cesanta Software Limited
8940 * All rights reserved
8941 */
8942
8943#ifndef EXCLUDE_COMMON
8944
8945/* Amalgamated: #include "common/mg_mem.h" */
8946/* Amalgamated: #include "common/platform.h" */
8947/* Amalgamated: #include "common/str_util.h" */
8948
8949#ifndef C_DISABLE_BUILTIN_SNPRINTF
8950#define C_DISABLE_BUILTIN_SNPRINTF 0
8951#endif
8952
8953/* Amalgamated: #include "common/mg_mem.h" */
8954
8955size_t c_strnlen(const char *s, size_t maxlen) WEAK;
8956size_t c_strnlen(const char *s, size_t maxlen) {
8957 size_t l = 0;
8958 for (; l < maxlen && s[l] != '\0'; l++) {
8959 }
8960 return l;
8961}
8962
8963#define C_SNPRINTF_APPEND_CHAR(ch) \
8964 do { \
8965 if (i < (int) buf_size) buf[i] = ch; \
8966 i++; \
8967 } while (0)
8968
8969#define C_SNPRINTF_FLAG_ZERO 1
8970
8971#if C_DISABLE_BUILTIN_SNPRINTF
8972int c_vsnprintf(char *buf, size_t buf_size, const char *fmt, va_list ap) WEAK;
8973int c_vsnprintf(char *buf, size_t buf_size, const char *fmt, va_list ap) {
8974 return vsnprintf(buf, buf_size, fmt, ap);
8975}
8976#else
8977static int c_itoa(char *buf, size_t buf_size, int64_t num, int base, int flags,
8978 int field_width) {
8979 char tmp[40];
8980 int i = 0, k = 0, neg = 0;
8981
8982 if (num < 0) {
8983 neg++;
8984 num = -num;
8985 }
8986
8987 /* Print into temporary buffer - in reverse order */
8988 do {
8989 int rem = num % base;
8990 if (rem < 10) {
8991 tmp[k++] = '0' + rem;
8992 } else {
8993 tmp[k++] = 'a' + (rem - 10);
8994 }
8995 num /= base;
8996 } while (num > 0);
8997
8998 /* Zero padding */
8999 if (flags && C_SNPRINTF_FLAG_ZERO) {
9000 while (k < field_width && k < (int) sizeof(tmp) - 1) {
9001 tmp[k++] = '0';
9002 }
9003 }
9004
9005 /* And sign */
9006 if (neg) {
9007 tmp[k++] = '-';
9008 }
9009
9010 /* Now output */
9011 while (--k >= 0) {
9012 C_SNPRINTF_APPEND_CHAR(tmp[k]);
9013 }
9014
9015 return i;
9016}
9017
9018int c_vsnprintf(char *buf, size_t buf_size, const char *fmt, va_list ap) WEAK;
9019int c_vsnprintf(char *buf, size_t buf_size, const char *fmt, va_list ap) {
9020 int ch, i = 0, len_mod, flags, precision, field_width;
9021
9022 while ((ch = *fmt++) != '\0') {
9023 if (ch != '%') {
9024 C_SNPRINTF_APPEND_CHAR(ch);
9025 } else {
9026 /*
9027 * Conversion specification:
9028 * zero or more flags (one of: # 0 - <space> + ')
9029 * an optional minimum field width (digits)
9030 * an optional precision (. followed by digits, or *)
9031 * an optional length modifier (one of: hh h l ll L q j z t)
9032 * conversion specifier (one of: d i o u x X e E f F g G a A c s p n)
9033 */
9034 flags = field_width = precision = len_mod = 0;
9035
9036 /* Flags. only zero-pad flag is supported. */
9037 if (*fmt == '0') {
9038 flags |= C_SNPRINTF_FLAG_ZERO;
9039 }
9040
9041 /* Field width */
9042 while (*fmt >= '0' && *fmt <= '9') {
9043 field_width *= 10;
9044 field_width += *fmt++ - '0';
9045 }
9046 /* Dynamic field width */
9047 if (*fmt == '*') {
9048 field_width = va_arg(ap, int);
9049 fmt++;
9050 }
9051
9052 /* Precision */
9053 if (*fmt == '.') {
9054 fmt++;
9055 if (*fmt == '*') {
9056 precision = va_arg(ap, int);
9057 fmt++;
9058 } else {
9059 while (*fmt >= '0' && *fmt <= '9') {
9060 precision *= 10;
9061 precision += *fmt++ - '0';
9062 }
9063 }
9064 }
9065
9066 /* Length modifier */
9067 switch (*fmt) {
9068 case 'h':
9069 case 'l':
9070 case 'L':
9071 case 'I':
9072 case 'q':
9073 case 'j':
9074 case 'z':
9075 case 't':
9076 len_mod = *fmt++;
9077 if (*fmt == 'h') {
9078 len_mod = 'H';
9079 fmt++;
9080 }
9081 if (*fmt == 'l') {
9082 len_mod = 'q';
9083 fmt++;
9084 }
9085 break;
9086 }
9087
9088 ch = *fmt++;
9089 if (ch == 's') {
9090 const char *s = va_arg(ap, const char *); /* Always fetch parameter */
9091 int j;
9092 int pad = field_width - (precision >= 0 ? c_strnlen(s, precision) : 0);
9093 for (j = 0; j < pad; j++) {
9094 C_SNPRINTF_APPEND_CHAR(' ');
9095 }
9096
9097 /* `s` may be NULL in case of %.*s */
9098 if (s != NULL) {
9099 /* Ignore negative and 0 precisions */
9100 for (j = 0; (precision <= 0 || j < precision) && s[j] != '\0'; j++) {
9101 C_SNPRINTF_APPEND_CHAR(s[j]);
9102 }
9103 }
9104 } else if (ch == 'c') {
9105 ch = va_arg(ap, int); /* Always fetch parameter */
9106 C_SNPRINTF_APPEND_CHAR(ch);
9107 } else if (ch == 'd' && len_mod == 0) {
9108 i += c_itoa(buf + i, buf_size - i, va_arg(ap, int), 10, flags,
9109 field_width);
9110 } else if (ch == 'd' && len_mod == 'l') {
9111 i += c_itoa(buf + i, buf_size - i, va_arg(ap, long), 10, flags,
9112 field_width);
9113#ifdef SSIZE_MAX
9114 } else if (ch == 'd' && len_mod == 'z') {
9115 i += c_itoa(buf + i, buf_size - i, va_arg(ap, ssize_t), 10, flags,
9116 field_width);
9117#endif
9118 } else if (ch == 'd' && len_mod == 'q') {
9119 i += c_itoa(buf + i, buf_size - i, va_arg(ap, int64_t), 10, flags,
9120 field_width);
9121 } else if ((ch == 'x' || ch == 'u') && len_mod == 0) {
9122 i += c_itoa(buf + i, buf_size - i, va_arg(ap, unsigned),
9123 ch == 'x' ? 16 : 10, flags, field_width);
9124 } else if ((ch == 'x' || ch == 'u') && len_mod == 'l') {
9125 i += c_itoa(buf + i, buf_size - i, va_arg(ap, unsigned long),
9126 ch == 'x' ? 16 : 10, flags, field_width);
9127 } else if ((ch == 'x' || ch == 'u') && len_mod == 'z') {
9128 i += c_itoa(buf + i, buf_size - i, va_arg(ap, size_t),
9129 ch == 'x' ? 16 : 10, flags, field_width);
9130 } else if (ch == 'p') {
9131 unsigned long num = (unsigned long) (uintptr_t) va_arg(ap, void *);
9132 C_SNPRINTF_APPEND_CHAR('0');
9133 C_SNPRINTF_APPEND_CHAR('x');
9134 i += c_itoa(buf + i, buf_size - i, num, 16, flags, 0);
9135 } else {
9136#ifndef NO_LIBC
9137 /*
9138 * TODO(lsm): abort is not nice in a library, remove it
9139 * Also, ESP8266 SDK doesn't have it
9140 */
9141 abort();
9142#endif
9143 }
9144 }
9145 }
9146
9147 /* Zero-terminate the result */
9148 if (buf_size > 0) {
9149 buf[i < (int) buf_size ? i : (int) buf_size - 1] = '\0';
9150 }
9151
9152 return i;
9153}
9154#endif
9155
9156int c_snprintf(char *buf, size_t buf_size, const char *fmt, ...) WEAK;
9157int c_snprintf(char *buf, size_t buf_size, const char *fmt, ...) {
9158 int result;
9159 va_list ap;
9160 va_start(ap, fmt);
9161 result = c_vsnprintf(buf, buf_size, fmt, ap);
9162 va_end(ap);
9163 return result;
9164}
9165
9166#ifdef _WIN32
9167int to_wchar(const char *path, wchar_t *wbuf, size_t wbuf_len) {
9168 int ret;
9169 char buf[MAX_PATH * 2], buf2[MAX_PATH * 2], *p;
9170
9171 strncpy(buf, path, sizeof(buf));
9172 buf[sizeof(buf) - 1] = '\0';
9173
9174 /* Trim trailing slashes. Leave backslash for paths like "X:\" */
9175 p = buf + strlen(buf) - 1;
9176 while (p > buf && p[-1] != ':' && (p[0] == '\\' || p[0] == '/')) *p-- = '\0';
9177
9178 memset(wbuf, 0, wbuf_len * sizeof(wchar_t));
9179 ret = MultiByteToWideChar(CP_UTF8, 0, buf, -1, wbuf, (int) wbuf_len);
9180
9181 /*
9182 * Convert back to Unicode. If doubly-converted string does not match the
9183 * original, something is fishy, reject.
9184 */
9185 WideCharToMultiByte(CP_UTF8, 0, wbuf, (int) wbuf_len, buf2, sizeof(buf2),
9186 NULL, NULL);
9187 if (strcmp(buf, buf2) != 0) {
9188 wbuf[0] = L'\0';
9189 ret = 0;
9190 }
9191
9192 return ret;
9193}
9194#endif /* _WIN32 */
9195
9196/* The simplest O(mn) algorithm. Better implementation are GPLed */
9197const char *c_strnstr(const char *s, const char *find, size_t slen) WEAK;
9198const char *c_strnstr(const char *s, const char *find, size_t slen) {
9199 size_t find_length = strlen(find);
9200 size_t i;
9201
9202 for (i = 0; i < slen; i++) {
9203 if (i + find_length > slen) {
9204 return NULL;
9205 }
9206
9207 if (strncmp(&s[i], find, find_length) == 0) {
9208 return &s[i];
9209 }
9210 }
9211
9212 return NULL;
9213}
9214
9215#if CS_ENABLE_STRDUP
9216char *strdup(const char *src) WEAK;
9217char *strdup(const char *src) {
9218 size_t len = strlen(src) + 1;
9219 char *ret = MG_MALLOC(len);
9220 if (ret != NULL) {
9221 strcpy(ret, src);
9222 }
9223 return ret;
9224}
9225#endif
9226
9227void cs_to_hex(char *to, const unsigned char *p, size_t len) WEAK;
9228void cs_to_hex(char *to, const unsigned char *p, size_t len) {
9229 static const char *hex = "0123456789abcdef";
9230
9231 for (; len--; p++) {
9232 *to++ = hex[p[0] >> 4];
9233 *to++ = hex[p[0] & 0x0f];
9234 }
9235 *to = '\0';
9236}
9237
9238static int fourbit(int ch) {
9239 if (ch >= '0' && ch <= '9') {
9240 return ch - '0';
9241 } else if (ch >= 'a' && ch <= 'f') {
9242 return ch - 'a' + 10;
9243 } else if (ch >= 'A' && ch <= 'F') {
9244 return ch - 'A' + 10;
9245 }
9246 return 0;
9247}
9248
9249void cs_from_hex(char *to, const char *p, size_t len) WEAK;
9250void cs_from_hex(char *to, const char *p, size_t len) {
9251 size_t i;
9252
9253 for (i = 0; i < len; i += 2) {
9254 *to++ = (fourbit(p[i]) << 4) + fourbit(p[i + 1]);
9255 }
9256 *to = '\0';
9257}
9258
9259#if CS_ENABLE_TO64
9260int64_t cs_to64(const char *s) WEAK;
9261int64_t cs_to64(const char *s) {
9262 int64_t result = 0;
9263 int64_t neg = 1;
9264 while (*s && isspace((unsigned char) *s)) s++;
9265 if (*s == '-') {
9266 neg = -1;
9267 s++;
9268 }
9269 while (isdigit((unsigned char) *s)) {
9270 result *= 10;
9271 result += (*s - '0');
9272 s++;
9273 }
9274 return result * neg;
9275}
9276#endif
9277
9278static int str_util_lowercase(const char *s) {
9279 return tolower(*(const unsigned char *) s);
9280}
9281
9282int mg_ncasecmp(const char *s1, const char *s2, size_t len) WEAK;
9283int mg_ncasecmp(const char *s1, const char *s2, size_t len) {
9284 int diff = 0;
9285
9286 if (len > 0) do {
9287 diff = str_util_lowercase(s1++) - str_util_lowercase(s2++);
9288 } while (diff == 0 && s1[-1] != '\0' && --len > 0);
9289
9290 return diff;
9291}
9292
9293int mg_casecmp(const char *s1, const char *s2) WEAK;
9294int mg_casecmp(const char *s1, const char *s2) {
9295 return mg_ncasecmp(s1, s2, (size_t) ~0);
9296}
9297
9298int mg_asprintf(char **buf, size_t size, const char *fmt, ...) WEAK;
9299int mg_asprintf(char **buf, size_t size, const char *fmt, ...) {
9300 int ret;
9301 va_list ap;
9302 va_start(ap, fmt);
9303 ret = mg_avprintf(buf, size, fmt, ap);
9304 va_end(ap);
9305 return ret;
9306}
9307
9308int mg_avprintf(char **buf, size_t size, const char *fmt, va_list ap) WEAK;
9309int mg_avprintf(char **buf, size_t size, const char *fmt, va_list ap) {
9310 va_list ap_copy;
9311 int len;
9312
9313 va_copy(ap_copy, ap);
9314 len = vsnprintf(*buf, size, fmt, ap_copy);
9315 va_end(ap_copy);
9316
9317 if (len < 0) {
9318 /* eCos and Windows are not standard-compliant and return -1 when
9319 * the buffer is too small. Keep allocating larger buffers until we
9320 * succeed or out of memory. */
9321 *buf = NULL; /* LCOV_EXCL_START */
9322 while (len < 0) {
9323 MG_FREE(*buf);
9324 size *= 2;
9325 if ((*buf = (char *) MG_MALLOC(size)) == NULL) break;
9326 va_copy(ap_copy, ap);
9327 len = vsnprintf(*buf, size, fmt, ap_copy);
9328 va_end(ap_copy);
9329 }
9330 /* LCOV_EXCL_STOP */
9331 } else if (len >= (int) size) {
9332 /* Standard-compliant code path. Allocate a buffer that is large enough. */
9333 if ((*buf = (char *) MG_MALLOC(len + 1)) == NULL) {
9334 len = -1; /* LCOV_EXCL_LINE */
9335 } else { /* LCOV_EXCL_LINE */
9336 va_copy(ap_copy, ap);
9337 len = vsnprintf(*buf, len + 1, fmt, ap_copy);
9338 va_end(ap_copy);
9339 }
9340 }
9341
9342 return len;
9343}
9344
9345const char *mg_next_comma_list_entry(const char *, struct mg_str *,
9346 struct mg_str *) WEAK;
9347const char *mg_next_comma_list_entry(const char *list, struct mg_str *val,
9348 struct mg_str *eq_val) {
9349 struct mg_str ret = mg_next_comma_list_entry_n(mg_mk_str(list), val, eq_val);
9350 return ret.p;
9351}
9352
9353struct mg_str mg_next_comma_list_entry_n(struct mg_str list, struct mg_str *val,
9354 struct mg_str *eq_val) WEAK;
9355struct mg_str mg_next_comma_list_entry_n(struct mg_str list, struct mg_str *val,
9356 struct mg_str *eq_val) {
9357 if (list.len == 0) {
9358 /* End of the list */
9359 list = mg_mk_str(NULL);
9360 } else {
9361 const char *chr = NULL;
9362 *val = list;
9363
9364 if ((chr = mg_strchr(*val, ',')) != NULL) {
9365 /* Comma found. Store length and shift the list ptr */
9366 val->len = chr - val->p;
9367 chr++;
9368 list.len -= (chr - list.p);
9369 list.p = chr;
9370 } else {
9371 /* This value is the last one */
9372 list = mg_mk_str_n(list.p + list.len, 0);
9373 }
9374
9375 if (eq_val != NULL) {
9376 /* Value has form "x=y", adjust pointers and lengths */
9377 /* so that val points to "x", and eq_val points to "y". */
9378 eq_val->len = 0;
9379 eq_val->p = (const char *) memchr(val->p, '=', val->len);
9380 if (eq_val->p != NULL) {
9381 eq_val->p++; /* Skip over '=' character */
9382 eq_val->len = val->p + val->len - eq_val->p;
9383 val->len = (eq_val->p - val->p) - 1;
9384 }
9385 }
9386 }
9387
9388 return list;
9389}
9390
9391int mg_match_prefix_n(const struct mg_str, const struct mg_str) WEAK;
9392int mg_match_prefix_n(const struct mg_str pattern, const struct mg_str str) {
9393 const char *or_str;
9394 size_t len, i = 0, j = 0;
9395 int res;
9396
9397 if ((or_str = (const char *) memchr(pattern.p, '|', pattern.len)) != NULL ||
9398 (or_str = (const char *) memchr(pattern.p, ',', pattern.len)) != NULL) {
9399 struct mg_str pstr = {pattern.p, (size_t)(or_str - pattern.p)};
9400 res = mg_match_prefix_n(pstr, str);
9401 if (res > 0) return res;
9402 pstr.p = or_str + 1;
9403 pstr.len = (pattern.p + pattern.len) - (or_str + 1);
9404 return mg_match_prefix_n(pstr, str);
9405 }
9406
9407 for (; i < pattern.len; i++, j++) {
9408 if (pattern.p[i] == '?' && j != str.len) {
9409 continue;
9410 } else if (pattern.p[i] == '$') {
9411 return j == str.len ? (int) j : -1;
9412 } else if (pattern.p[i] == '*') {
9413 i++;
9414 if (i < pattern.len && pattern.p[i] == '*') {
9415 i++;
9416 len = str.len - j;
9417 } else {
9418 len = 0;
9419 while (j + len != str.len && str.p[j + len] != '/') {
9420 len++;
9421 }
9422 }
9423 if (i == pattern.len) {
9424 return j + len;
9425 }
9426 do {
9427 const struct mg_str pstr = {pattern.p + i, pattern.len - i};
9428 const struct mg_str sstr = {str.p + j + len, str.len - j - len};
9429 res = mg_match_prefix_n(pstr, sstr);
9430 } while (res == -1 && len-- > 0);
9431 return res == -1 ? -1 : (int) (j + res + len);
9432 } else if (str_util_lowercase(&pattern.p[i]) !=
9433 str_util_lowercase(&str.p[j])) {
9434 return -1;
9435 }
9436 }
9437 return j;
9438}
9439
9440int mg_match_prefix(const char *, int, const char *) WEAK;
9441int mg_match_prefix(const char *pattern, int pattern_len, const char *str) {
9442 const struct mg_str pstr = {pattern, (size_t) pattern_len};
9443 struct mg_str s = {str, 0};
9444 if (str != NULL) s.len = strlen(str);
9445 return mg_match_prefix_n(pstr, s);
9446}
9447
9448#endif /* EXCLUDE_COMMON */
9449#ifdef V7_MODULE_LINES
9450#line 1 "common/utf.c"
9451#endif
9452/*
9453 * The authors of this software are Rob Pike and Ken Thompson.
9454 * Copyright (c) 2002 by Lucent Technologies.
9455 * Permission to use, copy, modify, and distribute this software for any
9456 * purpose without fee is hereby granted, provided that this entire notice
9457 * is included in all copies of any software which is or includes a copy
9458 * or modification of this software and in all copies of the supporting
9459 * documentation for such software.
9460 * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
9461 * WARRANTY. IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE
9462 * ANY REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
9463 * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
9464 */
9465
9466#ifndef EXCLUDE_COMMON
9467
9468/* clang-format off */
9469
9470#include <stdarg.h>
9471#include <string.h>
9472/* Amalgamated: #include "common/platform.h" */
9473/* Amalgamated: #include "common/str_util.h" */
9474/* Amalgamated: #include "common/utf.h" */
9475
9476#ifndef CS_ENABLE_UTF8
9477#define CS_ENABLE_UTF8 0
9478#endif
9479
9480#if CS_ENABLE_UTF8
9481enum {
9482 Bit1 = 7,
9483 Bitx = 6,
9484 Bit2 = 5,
9485 Bit3 = 4,
9486 Bit4 = 3,
9487 Bit5 = 2,
9488
9489 T1 = ((1 << (Bit1 + 1)) - 1) ^ 0xFF, /* 0000 0000 */
9490 Tx = ((1 << (Bitx + 1)) - 1) ^ 0xFF, /* 1000 0000 */
9491 T2 = ((1 << (Bit2 + 1)) - 1) ^ 0xFF, /* 1100 0000 */
9492 T3 = ((1 << (Bit3 + 1)) - 1) ^ 0xFF, /* 1110 0000 */
9493 T4 = ((1 << (Bit4 + 1)) - 1) ^ 0xFF, /* 1111 0000 */
9494 T5 = ((1 << (Bit5 + 1)) - 1) ^ 0xFF, /* 1111 1000 */
9495
9496 Rune1 = (1 << (Bit1 + 0 * Bitx)) - 1, /* 0000 0000 0000 0000 0111 1111 */
9497 Rune2 = (1 << (Bit2 + 1 * Bitx)) - 1, /* 0000 0000 0000 0111 1111 1111 */
9498 Rune3 = (1 << (Bit3 + 2 * Bitx)) - 1, /* 0000 0000 1111 1111 1111 1111 */
9499 Rune4 = (1 << (Bit4 + 3 * Bitx)) - 1, /* 0011 1111 1111 1111 1111 1111 */
9500
9501 Maskx = (1 << Bitx) - 1, /* 0011 1111 */
9502 Testx = Maskx ^ 0xFF, /* 1100 0000 */
9503
9504 Bad = Runeerror
9505};
9506
9507int chartorune(Rune *rune, const char *str) {
9508 int c, c1, c2 /* , c3 */;
9509 unsigned short l;
9510
9511 /*
9512 * one character sequence
9513 * 00000-0007F => T1
9514 */
9515 c = *(uchar *) str;
9516 if (c < Tx) {
9517 *rune = c;
9518 return 1;
9519 }
9520
9521 /*
9522 * two character sequence
9523 * 0080-07FF => T2 Tx
9524 */
9525 c1 = *(uchar *) (str + 1) ^ Tx;
9526 if (c1 & Testx) goto bad;
9527 if (c < T3) {
9528 if (c < T2) goto bad;
9529 l = ((c << Bitx) | c1) & Rune2;
9530 if (l <= Rune1) goto bad;
9531 *rune = l;
9532 return 2;
9533 }
9534
9535 /*
9536 * three character sequence
9537 * 0800-FFFF => T3 Tx Tx
9538 */
9539 c2 = *(uchar *) (str + 2) ^ Tx;
9540 if (c2 & Testx) goto bad;
9541 if (c < T4) {
9542 l = ((((c << Bitx) | c1) << Bitx) | c2) & Rune3;
9543 if (l <= Rune2) goto bad;
9544 *rune = l;
9545 return 3;
9546 }
9547
9548/*
9549 * four character sequence
9550 * 10000-10FFFF => T4 Tx Tx Tx
9551 */
9552/* if(UTFmax >= 4) {
9553 c3 = *(uchar*)(str+3) ^ Tx;
9554 if(c3 & Testx)
9555 goto bad;
9556 if(c < T5) {
9557 l = ((((((c << Bitx) | c1) << Bitx) | c2) << Bitx) | c3) &
9558Rune4;
9559 if(l <= Rune3)
9560 goto bad;
9561 if(l > Runemax)
9562 goto bad;
9563 *rune = l;
9564 return 4;
9565 }
9566} */
9567
9568/*
9569 * bad decoding
9570 */
9571bad:
9572 *rune = Bad;
9573 return 1;
9574}
9575
9576int runetochar(char *str, Rune *rune) {
9577 unsigned short c;
9578
9579 /*
9580 * one character sequence
9581 * 00000-0007F => 00-7F
9582 */
9583 c = *rune;
9584 if (c <= Rune1) {
9585 str[0] = c;
9586 return 1;
9587 }
9588
9589 /*
9590 * two character sequence
9591 * 00080-007FF => T2 Tx
9592 */
9593 if (c <= Rune2) {
9594 str[0] = T2 | (c >> 1 * Bitx);
9595 str[1] = Tx | (c & Maskx);
9596 return 2;
9597 }
9598
9599 /*
9600 * three character sequence
9601 * 00800-0FFFF => T3 Tx Tx
9602 */
9603 /* if(c > Runemax)
9604 c = Runeerror; */
9605 /* if(c <= Rune3) { */
9606 str[0] = T3 | (c >> 2 * Bitx);
9607 str[1] = Tx | ((c >> 1 * Bitx) & Maskx);
9608 str[2] = Tx | (c & Maskx);
9609 return 3;
9610 /* } */
9611
9612 /*
9613 * four character sequence
9614 * 010000-1FFFFF => T4 Tx Tx Tx
9615 */
9616 /* str[0] = T4 | (c >> 3*Bitx);
9617 str[1] = Tx | ((c >> 2*Bitx) & Maskx);
9618 str[2] = Tx | ((c >> 1*Bitx) & Maskx);
9619 str[3] = Tx | (c & Maskx);
9620 return 4; */
9621}
9622
9623int fullrune(const char *str, int n) {
9624 int c;
9625
9626 if (n <= 0) return 0;
9627 c = *(uchar *) str;
9628 if (c < Tx) return 1;
9629 if (c < T3) return n >= 2;
9630 if (UTFmax == 3 || c < T4) return n >= 3;
9631 return n >= 4;
9632}
9633
9634int utfnlen(const char *s, long m) {
9635 int c;
9636 long n;
9637 Rune rune;
9638 const char *es;
9639
9640 es = s + m;
9641 for (n = 0; s < es; n++) {
9642 c = *(uchar *) s;
9643 if (c < Runeself) {
9644 s++;
9645 continue;
9646 }
9647 if (!fullrune(s, es - s)) break;
9648 s += chartorune(&rune, s);
9649 }
9650 return n;
9651}
9652
9653const char *utfnshift(const char *s, long m) {
9654 int c;
9655 long n;
9656 Rune rune;
9657
9658 for (n = 0; n < m; n++) {
9659 c = *(uchar *) s;
9660 if (c < Runeself) {
9661 s++;
9662 continue;
9663 }
9664 s += chartorune(&rune, s);
9665 }
9666 return s;
9667}
9668
9669/*
9670 * The authors of this software are Rob Pike and Ken Thompson.
9671 * Copyright (c) 2002 by Lucent Technologies.
9672 * Permission to use, copy, modify, and distribute this software for any
9673 * purpose without fee is hereby granted, provided that this entire notice
9674 * is included in all copies of any software which is or includes a copy
9675 * or modification of this software and in all copies of the supporting
9676 * documentation for such software.
9677 * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
9678 * WARRANTY. IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE
9679 * ANY REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
9680 * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
9681 */
9682#include <stdarg.h>
9683#include <string.h>
9684/* Amalgamated: #include "common/utf.h" */
9685
9686/*
9687 * alpha ranges -
9688 * only covers ranges not in lower||upper
9689 */
9690static Rune __alpha2[] = {
9691 0x00d8, 0x00f6, /* Ø - ö */
9692 0x00f8, 0x01f5, /* ø - ǵ */
9693 0x0250, 0x02a8, /* ɐ - ʨ */
9694 0x038e, 0x03a1, /* Ύ - Ρ */
9695 0x03a3, 0x03ce, /* Σ - ώ */
9696 0x03d0, 0x03d6, /* ϐ - ϖ */
9697 0x03e2, 0x03f3, /* Ϣ - ϳ */
9698 0x0490, 0x04c4, /* Ґ - ӄ */
9699 0x0561, 0x0587, /* ա - և */
9700 0x05d0, 0x05ea, /* א - ת */
9701 0x05f0, 0x05f2, /* װ - ײ */
9702 0x0621, 0x063a, /* ء - غ */
9703 0x0640, 0x064a, /* ـ - ي */
9704 0x0671, 0x06b7, /* ٱ - ڷ */
9705 0x06ba, 0x06be, /* ں - ھ */
9706 0x06c0, 0x06ce, /* ۀ - ێ */
9707 0x06d0, 0x06d3, /* ې - ۓ */
9708 0x0905, 0x0939, /* अ - ह */
9709 0x0958, 0x0961, /* क़ - ॡ */
9710 0x0985, 0x098c, /* অ - ঌ */
9711 0x098f, 0x0990, /* এ - ঐ */
9712 0x0993, 0x09a8, /* ও - ন */
9713 0x09aa, 0x09b0, /* প - র */
9714 0x09b6, 0x09b9, /* শ - হ */
9715 0x09dc, 0x09dd, /* ড় - ঢ় */
9716 0x09df, 0x09e1, /* য় - ৡ */
9717 0x09f0, 0x09f1, /* ৰ - ৱ */
9718 0x0a05, 0x0a0a, /* ਅ - ਊ */
9719 0x0a0f, 0x0a10, /* ਏ - ਐ */
9720 0x0a13, 0x0a28, /* ਓ - ਨ */
9721 0x0a2a, 0x0a30, /* ਪ - ਰ */
9722 0x0a32, 0x0a33, /* ਲ - ਲ਼ */
9723 0x0a35, 0x0a36, /* ਵ - ਸ਼ */
9724 0x0a38, 0x0a39, /* ਸ - ਹ */
9725 0x0a59, 0x0a5c, /* ਖ਼ - ੜ */
9726 0x0a85, 0x0a8b, /* અ - ઋ */
9727 0x0a8f, 0x0a91, /* એ - ઑ */
9728 0x0a93, 0x0aa8, /* ઓ - ન */
9729 0x0aaa, 0x0ab0, /* પ - ર */
9730 0x0ab2, 0x0ab3, /* લ - ળ */
9731 0x0ab5, 0x0ab9, /* વ - હ */
9732 0x0b05, 0x0b0c, /* ଅ - ଌ */
9733 0x0b0f, 0x0b10, /* ଏ - ଐ */
9734 0x0b13, 0x0b28, /* ଓ - ନ */
9735 0x0b2a, 0x0b30, /* ପ - ର */
9736 0x0b32, 0x0b33, /* ଲ - ଳ */
9737 0x0b36, 0x0b39, /* ଶ - ହ */
9738 0x0b5c, 0x0b5d, /* ଡ଼ - ଢ଼ */
9739 0x0b5f, 0x0b61, /* ୟ - ୡ */
9740 0x0b85, 0x0b8a, /* அ - ஊ */
9741 0x0b8e, 0x0b90, /* எ - ஐ */
9742 0x0b92, 0x0b95, /* ஒ - க */
9743 0x0b99, 0x0b9a, /* ங - ச */
9744 0x0b9e, 0x0b9f, /* ஞ - ட */
9745 0x0ba3, 0x0ba4, /* ண - த */
9746 0x0ba8, 0x0baa, /* ந - ப */
9747 0x0bae, 0x0bb5, /* ம - வ */
9748 0x0bb7, 0x0bb9, /* ஷ - ஹ */
9749 0x0c05, 0x0c0c, /* అ - ఌ */
9750 0x0c0e, 0x0c10, /* ఎ - ఐ */
9751 0x0c12, 0x0c28, /* ఒ - న */
9752 0x0c2a, 0x0c33, /* ప - ళ */
9753 0x0c35, 0x0c39, /* వ - హ */
9754 0x0c60, 0x0c61, /* ౠ - ౡ */
9755 0x0c85, 0x0c8c, /* ಅ - ಌ */
9756 0x0c8e, 0x0c90, /* ಎ - ಐ */
9757 0x0c92, 0x0ca8, /* ಒ - ನ */
9758 0x0caa, 0x0cb3, /* ಪ - ಳ */
9759 0x0cb5, 0x0cb9, /* ವ - ಹ */
9760 0x0ce0, 0x0ce1, /* ೠ - ೡ */
9761 0x0d05, 0x0d0c, /* അ - ഌ */
9762 0x0d0e, 0x0d10, /* എ - ഐ */
9763 0x0d12, 0x0d28, /* ഒ - ന */
9764 0x0d2a, 0x0d39, /* പ - ഹ */
9765 0x0d60, 0x0d61, /* ൠ - ൡ */
9766 0x0e01, 0x0e30, /* ก - ะ */
9767 0x0e32, 0x0e33, /* า - ำ */
9768 0x0e40, 0x0e46, /* เ - ๆ */
9769 0x0e5a, 0x0e5b, /* ๚ - ๛ */
9770 0x0e81, 0x0e82, /* ກ - ຂ */
9771 0x0e87, 0x0e88, /* ງ - ຈ */
9772 0x0e94, 0x0e97, /* ດ - ທ */
9773 0x0e99, 0x0e9f, /* ນ - ຟ */
9774 0x0ea1, 0x0ea3, /* ມ - ຣ */
9775 0x0eaa, 0x0eab, /* ສ - ຫ */
9776 0x0ead, 0x0eae, /* ອ - ຮ */
9777 0x0eb2, 0x0eb3, /* າ - ຳ */
9778 0x0ec0, 0x0ec4, /* ເ - ໄ */
9779 0x0edc, 0x0edd, /* ໜ - ໝ */
9780 0x0f18, 0x0f19, /* ༘ - ༙ */
9781 0x0f40, 0x0f47, /* ཀ - ཇ */
9782 0x0f49, 0x0f69, /* ཉ - ཀྵ */
9783 0x10d0, 0x10f6, /* ა - ჶ */
9784 0x1100, 0x1159, /* ᄀ - ᅙ */
9785 0x115f, 0x11a2, /* ᅟ - ᆢ */
9786 0x11a8, 0x11f9, /* ᆨ - ᇹ */
9787 0x1e00, 0x1e9b, /* Ḁ - ẛ */
9788 0x1f50, 0x1f57, /* ὐ - ὗ */
9789 0x1f80, 0x1fb4, /* ᾀ - ᾴ */
9790 0x1fb6, 0x1fbc, /* ᾶ - ᾼ */
9791 0x1fc2, 0x1fc4, /* ῂ - ῄ */
9792 0x1fc6, 0x1fcc, /* ῆ - ῌ */
9793 0x1fd0, 0x1fd3, /* ῐ - ΐ */
9794 0x1fd6, 0x1fdb, /* ῖ - Ί */
9795 0x1fe0, 0x1fec, /* ῠ - Ῥ */
9796 0x1ff2, 0x1ff4, /* ῲ - ῴ */
9797 0x1ff6, 0x1ffc, /* ῶ - ῼ */
9798 0x210a, 0x2113, /* ℊ - ℓ */
9799 0x2115, 0x211d, /* ℕ - ℝ */
9800 0x2120, 0x2122, /* ℠ - ™ */
9801 0x212a, 0x2131, /* K - ℱ */
9802 0x2133, 0x2138, /* ℳ - ℸ */
9803 0x3041, 0x3094, /* ぁ - ゔ */
9804 0x30a1, 0x30fa, /* ァ - ヺ */
9805 0x3105, 0x312c, /* ㄅ - ㄬ */
9806 0x3131, 0x318e, /* ㄱ - ㆎ */
9807 0x3192, 0x319f, /* ㆒ - ㆟ */
9808 0x3260, 0x327b, /* ㉠ - ㉻ */
9809 0x328a, 0x32b0, /* ㊊ - ㊰ */
9810 0x32d0, 0x32fe, /* ㋐ - ㋾ */
9811 0x3300, 0x3357, /* ㌀ - ㍗ */
9812 0x3371, 0x3376, /* ㍱ - ㍶ */
9813 0x337b, 0x3394, /* ㍻ - ㎔ */
9814 0x3399, 0x339e, /* ㎙ - ㎞ */
9815 0x33a9, 0x33ad, /* ㎩ - ㎭ */
9816 0x33b0, 0x33c1, /* ㎰ - ㏁ */
9817 0x33c3, 0x33c5, /* ㏃ - ㏅ */
9818 0x33c7, 0x33d7, /* ㏇ - ㏗ */
9819 0x33d9, 0x33dd, /* ㏙ - ㏝ */
9820 0x4e00, 0x9fff, /* 一 - 鿿 */
9821 0xac00, 0xd7a3, /* 가 - 힣 */
9822 0xf900, 0xfb06, /* 豈 - st */
9823 0xfb13, 0xfb17, /* ﬓ - ﬗ */
9824 0xfb1f, 0xfb28, /* ײַ - ﬨ */
9825 0xfb2a, 0xfb36, /* שׁ - זּ */
9826 0xfb38, 0xfb3c, /* טּ - לּ */
9827 0xfb40, 0xfb41, /* נּ - סּ */
9828 0xfb43, 0xfb44, /* ףּ - פּ */
9829 0xfb46, 0xfbb1, /* צּ - ﮱ */
9830 0xfbd3, 0xfd3d, /* ﯓ - ﴽ */
9831 0xfd50, 0xfd8f, /* ﵐ - ﶏ */
9832 0xfd92, 0xfdc7, /* ﶒ - ﷇ */
9833 0xfdf0, 0xfdf9, /* ﷰ - ﷹ */
9834 0xfe70, 0xfe72, /* ﹰ - ﹲ */
9835 0xfe76, 0xfefc, /* ﹶ - ﻼ */
9836 0xff66, 0xff6f, /* ヲ - ッ */
9837 0xff71, 0xff9d, /* ア - ン */
9838 0xffa0, 0xffbe, /* ᅠ - ᄒ */
9839 0xffc2, 0xffc7, /* ᅡ - ᅦ */
9840 0xffca, 0xffcf, /* ᅧ - ᅬ */
9841 0xffd2, 0xffd7, /* ᅭ - ᅲ */
9842 0xffda, 0xffdc, /* ᅳ - ᅵ */
9843};
9844
9845/*
9846 * alpha singlets -
9847 * only covers ranges not in lower||upper
9848 */
9849static Rune __alpha1[] = {
9850 0x00aa, /* ª */
9851 0x00b5, /* µ */
9852 0x00ba, /* º */
9853 0x03da, /* Ϛ */
9854 0x03dc, /* Ϝ */
9855 0x03de, /* Ϟ */
9856 0x03e0, /* Ϡ */
9857 0x06d5, /* ە */
9858 0x09b2, /* ল */
9859 0x0a5e, /* ਫ਼ */
9860 0x0a8d, /* ઍ */
9861 0x0ae0, /* ૠ */
9862 0x0b9c, /* ஜ */
9863 0x0cde, /* ೞ */
9864 0x0e4f, /* ๏ */
9865 0x0e84, /* ຄ */
9866 0x0e8a, /* ຊ */
9867 0x0e8d, /* ຍ */
9868 0x0ea5, /* ລ */
9869 0x0ea7, /* ວ */
9870 0x0eb0, /* ະ */
9871 0x0ebd, /* ຽ */
9872 0x1fbe, /* ι */
9873 0x207f, /* ⁿ */
9874 0x20a8, /* ₨ */
9875 0x2102, /* ℂ */
9876 0x2107, /* ℇ */
9877 0x2124, /* ℤ */
9878 0x2126, /* Ω */
9879 0x2128, /* ℨ */
9880 0xfb3e, /* מּ */
9881 0xfe74, /* ﹴ */
9882};
9883
9884/*
9885 * space ranges
9886 */
9887static Rune __space2[] = {
9888 0x0009, 0x000a, /* tab and newline */
9889 0x0020, 0x0020, /* space */
9890 0x00a0, 0x00a0, /* */
9891 0x2000, 0x200b, /* - */
9892 0x2028, 0x2029, /*
-
*/
9893 0x3000, 0x3000, /* */
9894 0xfeff, 0xfeff, /* */
9895};
9896
9897/*
9898 * lower case ranges
9899 * 3rd col is conversion excess 500
9900 */
9901static Rune __toupper2[] = {
9902 0x0061, 0x007a, 468, /* a-z A-Z */
9903 0x00e0, 0x00f6, 468, /* à-ö À-Ö */
9904 0x00f8, 0x00fe, 468, /* ø-þ Ø-Þ */
9905 0x0256, 0x0257, 295, /* ɖ-ɗ Ɖ-Ɗ */
9906 0x0258, 0x0259, 298, /* ɘ-ə Ǝ-Ə */
9907 0x028a, 0x028b, 283, /* ʊ-ʋ Ʊ-Ʋ */
9908 0x03ad, 0x03af, 463, /* έ-ί Έ-Ί */
9909 0x03b1, 0x03c1, 468, /* α-ρ Α-Ρ */
9910 0x03c3, 0x03cb, 468, /* σ-ϋ Σ-Ϋ */
9911 0x03cd, 0x03ce, 437, /* ύ-ώ Ύ-Ώ */
9912 0x0430, 0x044f, 468, /* а-я А-Я */
9913 0x0451, 0x045c, 420, /* ё-ќ Ё-Ќ */
9914 0x045e, 0x045f, 420, /* ў-џ Ў-Џ */
9915 0x0561, 0x0586, 452, /* ա-ֆ Ա-Ֆ */
9916 0x1f00, 0x1f07, 508, /* ἀ-ἇ Ἀ-Ἇ */
9917 0x1f10, 0x1f15, 508, /* ἐ-ἕ Ἐ-Ἕ */
9918 0x1f20, 0x1f27, 508, /* ἠ-ἧ Ἠ-Ἧ */
9919 0x1f30, 0x1f37, 508, /* ἰ-ἷ Ἰ-Ἷ */
9920 0x1f40, 0x1f45, 508, /* ὀ-ὅ Ὀ-Ὅ */
9921 0x1f60, 0x1f67, 508, /* ὠ-ὧ Ὠ-Ὧ */
9922 0x1f70, 0x1f71, 574, /* ὰ-ά Ὰ-Ά */
9923 0x1f72, 0x1f75, 586, /* ὲ-ή Ὲ-Ή */
9924 0x1f76, 0x1f77, 600, /* ὶ-ί Ὶ-Ί */
9925 0x1f78, 0x1f79, 628, /* ὸ-ό Ὸ-Ό */
9926 0x1f7a, 0x1f7b, 612, /* ὺ-ύ Ὺ-Ύ */
9927 0x1f7c, 0x1f7d, 626, /* ὼ-ώ Ὼ-Ώ */
9928 0x1f80, 0x1f87, 508, /* ᾀ-ᾇ ᾈ-ᾏ */
9929 0x1f90, 0x1f97, 508, /* ᾐ-ᾗ ᾘ-ᾟ */
9930 0x1fa0, 0x1fa7, 508, /* ᾠ-ᾧ ᾨ-ᾯ */
9931 0x1fb0, 0x1fb1, 508, /* ᾰ-ᾱ Ᾰ-Ᾱ */
9932 0x1fd0, 0x1fd1, 508, /* ῐ-ῑ Ῐ-Ῑ */
9933 0x1fe0, 0x1fe1, 508, /* ῠ-ῡ Ῠ-Ῡ */
9934 0x2170, 0x217f, 484, /* ⅰ-ⅿ Ⅰ-Ⅿ */
9935 0x24d0, 0x24e9, 474, /* ⓐ-ⓩ Ⓐ-Ⓩ */
9936 0xff41, 0xff5a, 468, /* a-z A-Z */
9937};
9938
9939/*
9940 * lower case singlets
9941 * 2nd col is conversion excess 500
9942 */
9943static Rune __toupper1[] = {
9944 0x00ff, 621, /* ÿ Ÿ */
9945 0x0101, 499, /* ā Ā */
9946 0x0103, 499, /* ă Ă */
9947 0x0105, 499, /* ą Ą */
9948 0x0107, 499, /* ć Ć */
9949 0x0109, 499, /* ĉ Ĉ */
9950 0x010b, 499, /* ċ Ċ */
9951 0x010d, 499, /* č Č */
9952 0x010f, 499, /* ď Ď */
9953 0x0111, 499, /* đ Đ */
9954 0x0113, 499, /* ē Ē */
9955 0x0115, 499, /* ĕ Ĕ */
9956 0x0117, 499, /* ė Ė */
9957 0x0119, 499, /* ę Ę */
9958 0x011b, 499, /* ě Ě */
9959 0x011d, 499, /* ĝ Ĝ */
9960 0x011f, 499, /* ğ Ğ */
9961 0x0121, 499, /* ġ Ġ */
9962 0x0123, 499, /* ģ Ģ */
9963 0x0125, 499, /* ĥ Ĥ */
9964 0x0127, 499, /* ħ Ħ */
9965 0x0129, 499, /* ĩ Ĩ */
9966 0x012b, 499, /* ī Ī */
9967 0x012d, 499, /* ĭ Ĭ */
9968 0x012f, 499, /* į Į */
9969 0x0131, 268, /* ı I */
9970 0x0133, 499, /* ij IJ */
9971 0x0135, 499, /* ĵ Ĵ */
9972 0x0137, 499, /* ķ Ķ */
9973 0x013a, 499, /* ĺ Ĺ */
9974 0x013c, 499, /* ļ Ļ */
9975 0x013e, 499, /* ľ Ľ */
9976 0x0140, 499, /* ŀ Ŀ */
9977 0x0142, 499, /* ł Ł */
9978 0x0144, 499, /* ń Ń */
9979 0x0146, 499, /* ņ Ņ */
9980 0x0148, 499, /* ň Ň */
9981 0x014b, 499, /* ŋ Ŋ */
9982 0x014d, 499, /* ō Ō */
9983 0x014f, 499, /* ŏ Ŏ */
9984 0x0151, 499, /* ő Ő */
9985 0x0153, 499, /* œ Œ */
9986 0x0155, 499, /* ŕ Ŕ */
9987 0x0157, 499, /* ŗ Ŗ */
9988 0x0159, 499, /* ř Ř */
9989 0x015b, 499, /* ś Ś */
9990 0x015d, 499, /* ŝ Ŝ */
9991 0x015f, 499, /* ş Ş */
9992 0x0161, 499, /* š Š */
9993 0x0163, 499, /* ţ Ţ */
9994 0x0165, 499, /* ť Ť */
9995 0x0167, 499, /* ŧ Ŧ */
9996 0x0169, 499, /* ũ Ũ */
9997 0x016b, 499, /* ū Ū */
9998 0x016d, 499, /* ŭ Ŭ */
9999 0x016f, 499, /* ů Ů */
10000 0x0171, 499, /* ű Ű */
10001 0x0173, 499, /* ų Ų */
10002 0x0175, 499, /* ŵ Ŵ */
10003 0x0177, 499, /* ŷ Ŷ */
10004 0x017a, 499, /* ź Ź */
10005 0x017c, 499, /* ż Ż */
10006 0x017e, 499, /* ž Ž */
10007 0x017f, 200, /* ſ S */
10008 0x0183, 499, /* ƃ Ƃ */
10009 0x0185, 499, /* ƅ Ƅ */
10010 0x0188, 499, /* ƈ Ƈ */
10011 0x018c, 499, /* ƌ Ƌ */
10012 0x0192, 499, /* ƒ Ƒ */
10013 0x0199, 499, /* ƙ Ƙ */
10014 0x01a1, 499, /* ơ Ơ */
10015 0x01a3, 499, /* ƣ Ƣ */
10016 0x01a5, 499, /* ƥ Ƥ */
10017 0x01a8, 499, /* ƨ Ƨ */
10018 0x01ad, 499, /* ƭ Ƭ */
10019 0x01b0, 499, /* ư Ư */
10020 0x01b4, 499, /* ƴ Ƴ */
10021 0x01b6, 499, /* ƶ Ƶ */
10022 0x01b9, 499, /* ƹ Ƹ */
10023 0x01bd, 499, /* ƽ Ƽ */
10024 0x01c5, 499, /* Dž DŽ */
10025 0x01c6, 498, /* dž DŽ */
10026 0x01c8, 499, /* Lj LJ */
10027 0x01c9, 498, /* lj LJ */
10028 0x01cb, 499, /* Nj NJ */
10029 0x01cc, 498, /* nj NJ */
10030 0x01ce, 499, /* ǎ Ǎ */
10031 0x01d0, 499, /* ǐ Ǐ */
10032 0x01d2, 499, /* ǒ Ǒ */
10033 0x01d4, 499, /* ǔ Ǔ */
10034 0x01d6, 499, /* ǖ Ǖ */
10035 0x01d8, 499, /* ǘ Ǘ */
10036 0x01da, 499, /* ǚ Ǚ */
10037 0x01dc, 499, /* ǜ Ǜ */
10038 0x01df, 499, /* ǟ Ǟ */
10039 0x01e1, 499, /* ǡ Ǡ */
10040 0x01e3, 499, /* ǣ Ǣ */
10041 0x01e5, 499, /* ǥ Ǥ */
10042 0x01e7, 499, /* ǧ Ǧ */
10043 0x01e9, 499, /* ǩ Ǩ */
10044 0x01eb, 499, /* ǫ Ǫ */
10045 0x01ed, 499, /* ǭ Ǭ */
10046 0x01ef, 499, /* ǯ Ǯ */
10047 0x01f2, 499, /* Dz DZ */
10048 0x01f3, 498, /* dz DZ */
10049 0x01f5, 499, /* ǵ Ǵ */
10050 0x01fb, 499, /* ǻ Ǻ */
10051 0x01fd, 499, /* ǽ Ǽ */
10052 0x01ff, 499, /* ǿ Ǿ */
10053 0x0201, 499, /* ȁ Ȁ */
10054 0x0203, 499, /* ȃ Ȃ */
10055 0x0205, 499, /* ȅ Ȅ */
10056 0x0207, 499, /* ȇ Ȇ */
10057 0x0209, 499, /* ȉ Ȉ */
10058 0x020b, 499, /* ȋ Ȋ */
10059 0x020d, 499, /* ȍ Ȍ */
10060 0x020f, 499, /* ȏ Ȏ */
10061 0x0211, 499, /* ȑ Ȑ */
10062 0x0213, 499, /* ȓ Ȓ */
10063 0x0215, 499, /* ȕ Ȕ */
10064 0x0217, 499, /* ȗ Ȗ */
10065 0x0253, 290, /* ɓ Ɓ */
10066 0x0254, 294, /* ɔ Ɔ */
10067 0x025b, 297, /* ɛ Ɛ */
10068 0x0260, 295, /* ɠ Ɠ */
10069 0x0263, 293, /* ɣ Ɣ */
10070 0x0268, 291, /* ɨ Ɨ */
10071 0x0269, 289, /* ɩ Ɩ */
10072 0x026f, 289, /* ɯ Ɯ */
10073 0x0272, 287, /* ɲ Ɲ */
10074 0x0283, 282, /* ʃ Ʃ */
10075 0x0288, 282, /* ʈ Ʈ */
10076 0x0292, 281, /* ʒ Ʒ */
10077 0x03ac, 462, /* ά Ά */
10078 0x03cc, 436, /* ό Ό */
10079 0x03d0, 438, /* ϐ Β */
10080 0x03d1, 443, /* ϑ Θ */
10081 0x03d5, 453, /* ϕ Φ */
10082 0x03d6, 446, /* ϖ Π */
10083 0x03e3, 499, /* ϣ Ϣ */
10084 0x03e5, 499, /* ϥ Ϥ */
10085 0x03e7, 499, /* ϧ Ϧ */
10086 0x03e9, 499, /* ϩ Ϩ */
10087 0x03eb, 499, /* ϫ Ϫ */
10088 0x03ed, 499, /* ϭ Ϭ */
10089 0x03ef, 499, /* ϯ Ϯ */
10090 0x03f0, 414, /* ϰ Κ */
10091 0x03f1, 420, /* ϱ Ρ */
10092 0x0461, 499, /* ѡ Ѡ */
10093 0x0463, 499, /* ѣ Ѣ */
10094 0x0465, 499, /* ѥ Ѥ */
10095 0x0467, 499, /* ѧ Ѧ */
10096 0x0469, 499, /* ѩ Ѩ */
10097 0x046b, 499, /* ѫ Ѫ */
10098 0x046d, 499, /* ѭ Ѭ */
10099 0x046f, 499, /* ѯ Ѯ */
10100 0x0471, 499, /* ѱ Ѱ */
10101 0x0473, 499, /* ѳ Ѳ */
10102 0x0475, 499, /* ѵ Ѵ */
10103 0x0477, 499, /* ѷ Ѷ */
10104 0x0479, 499, /* ѹ Ѹ */
10105 0x047b, 499, /* ѻ Ѻ */
10106 0x047d, 499, /* ѽ Ѽ */
10107 0x047f, 499, /* ѿ Ѿ */
10108 0x0481, 499, /* ҁ Ҁ */
10109 0x0491, 499, /* ґ Ґ */
10110 0x0493, 499, /* ғ Ғ */
10111 0x0495, 499, /* ҕ Ҕ */
10112 0x0497, 499, /* җ Җ */
10113 0x0499, 499, /* ҙ Ҙ */
10114 0x049b, 499, /* қ Қ */
10115 0x049d, 499, /* ҝ Ҝ */
10116 0x049f, 499, /* ҟ Ҟ */
10117 0x04a1, 499, /* ҡ Ҡ */
10118 0x04a3, 499, /* ң Ң */
10119 0x04a5, 499, /* ҥ Ҥ */
10120 0x04a7, 499, /* ҧ Ҧ */
10121 0x04a9, 499, /* ҩ Ҩ */
10122 0x04ab, 499, /* ҫ Ҫ */
10123 0x04ad, 499, /* ҭ Ҭ */
10124 0x04af, 499, /* ү Ү */
10125 0x04b1, 499, /* ұ Ұ */
10126 0x04b3, 499, /* ҳ Ҳ */
10127 0x04b5, 499, /* ҵ Ҵ */
10128 0x04b7, 499, /* ҷ Ҷ */
10129 0x04b9, 499, /* ҹ Ҹ */
10130 0x04bb, 499, /* һ Һ */
10131 0x04bd, 499, /* ҽ Ҽ */
10132 0x04bf, 499, /* ҿ Ҿ */
10133 0x04c2, 499, /* ӂ Ӂ */
10134 0x04c4, 499, /* ӄ Ӄ */
10135 0x04c8, 499, /* ӈ Ӈ */
10136 0x04cc, 499, /* ӌ Ӌ */
10137 0x04d1, 499, /* ӑ Ӑ */
10138 0x04d3, 499, /* ӓ Ӓ */
10139 0x04d5, 499, /* ӕ Ӕ */
10140 0x04d7, 499, /* ӗ Ӗ */
10141 0x04d9, 499, /* ә Ә */
10142 0x04db, 499, /* ӛ Ӛ */
10143 0x04dd, 499, /* ӝ Ӝ */
10144 0x04df, 499, /* ӟ Ӟ */
10145 0x04e1, 499, /* ӡ Ӡ */
10146 0x04e3, 499, /* ӣ Ӣ */
10147 0x04e5, 499, /* ӥ Ӥ */
10148 0x04e7, 499, /* ӧ Ӧ */
10149 0x04e9, 499, /* ө Ө */
10150 0x04eb, 499, /* ӫ Ӫ */
10151 0x04ef, 499, /* ӯ Ӯ */
10152 0x04f1, 499, /* ӱ Ӱ */
10153 0x04f3, 499, /* ӳ Ӳ */
10154 0x04f5, 499, /* ӵ Ӵ */
10155 0x04f9, 499, /* ӹ Ӹ */
10156 0x1e01, 499, /* ḁ Ḁ */
10157 0x1e03, 499, /* ḃ Ḃ */
10158 0x1e05, 499, /* ḅ Ḅ */
10159 0x1e07, 499, /* ḇ Ḇ */
10160 0x1e09, 499, /* ḉ Ḉ */
10161 0x1e0b, 499, /* ḋ Ḋ */
10162 0x1e0d, 499, /* ḍ Ḍ */
10163 0x1e0f, 499, /* ḏ Ḏ */
10164 0x1e11, 499, /* ḑ Ḑ */
10165 0x1e13, 499, /* ḓ Ḓ */
10166 0x1e15, 499, /* ḕ Ḕ */
10167 0x1e17, 499, /* ḗ Ḗ */
10168 0x1e19, 499, /* ḙ Ḙ */
10169 0x1e1b, 499, /* ḛ Ḛ */
10170 0x1e1d, 499, /* ḝ Ḝ */
10171 0x1e1f, 499, /* ḟ Ḟ */
10172 0x1e21, 499, /* ḡ Ḡ */
10173 0x1e23, 499, /* ḣ Ḣ */
10174 0x1e25, 499, /* ḥ Ḥ */
10175 0x1e27, 499, /* ḧ Ḧ */
10176 0x1e29, 499, /* ḩ Ḩ */
10177 0x1e2b, 499, /* ḫ Ḫ */
10178 0x1e2d, 499, /* ḭ Ḭ */
10179 0x1e2f, 499, /* ḯ Ḯ */
10180 0x1e31, 499, /* ḱ Ḱ */
10181 0x1e33, 499, /* ḳ Ḳ */
10182 0x1e35, 499, /* ḵ Ḵ */
10183 0x1e37, 499, /* ḷ Ḷ */
10184 0x1e39, 499, /* ḹ Ḹ */
10185 0x1e3b, 499, /* ḻ Ḻ */
10186 0x1e3d, 499, /* ḽ Ḽ */
10187 0x1e3f, 499, /* ḿ Ḿ */
10188 0x1e41, 499, /* ṁ Ṁ */
10189 0x1e43, 499, /* ṃ Ṃ */
10190 0x1e45, 499, /* ṅ Ṅ */
10191 0x1e47, 499, /* ṇ Ṇ */
10192 0x1e49, 499, /* ṉ Ṉ */
10193 0x1e4b, 499, /* ṋ Ṋ */
10194 0x1e4d, 499, /* ṍ Ṍ */
10195 0x1e4f, 499, /* ṏ Ṏ */
10196 0x1e51, 499, /* ṑ Ṑ */
10197 0x1e53, 499, /* ṓ Ṓ */
10198 0x1e55, 499, /* ṕ Ṕ */
10199 0x1e57, 499, /* ṗ Ṗ */
10200 0x1e59, 499, /* ṙ Ṙ */
10201 0x1e5b, 499, /* ṛ Ṛ */
10202 0x1e5d, 499, /* ṝ Ṝ */
10203 0x1e5f, 499, /* ṟ Ṟ */
10204 0x1e61, 499, /* ṡ Ṡ */
10205 0x1e63, 499, /* ṣ Ṣ */
10206 0x1e65, 499, /* ṥ Ṥ */
10207 0x1e67, 499, /* ṧ Ṧ */
10208 0x1e69, 499, /* ṩ Ṩ */
10209 0x1e6b, 499, /* ṫ Ṫ */
10210 0x1e6d, 499, /* ṭ Ṭ */
10211 0x1e6f, 499, /* ṯ Ṯ */
10212 0x1e71, 499, /* ṱ Ṱ */
10213 0x1e73, 499, /* ṳ Ṳ */
10214 0x1e75, 499, /* ṵ Ṵ */
10215 0x1e77, 499, /* ṷ Ṷ */
10216 0x1e79, 499, /* ṹ Ṹ */
10217 0x1e7b, 499, /* ṻ Ṻ */
10218 0x1e7d, 499, /* ṽ Ṽ */
10219 0x1e7f, 499, /* ṿ Ṿ */
10220 0x1e81, 499, /* ẁ Ẁ */
10221 0x1e83, 499, /* ẃ Ẃ */
10222 0x1e85, 499, /* ẅ Ẅ */
10223 0x1e87, 499, /* ẇ Ẇ */
10224 0x1e89, 499, /* ẉ Ẉ */
10225 0x1e8b, 499, /* ẋ Ẋ */
10226 0x1e8d, 499, /* ẍ Ẍ */
10227 0x1e8f, 499, /* ẏ Ẏ */
10228 0x1e91, 499, /* ẑ Ẑ */
10229 0x1e93, 499, /* ẓ Ẓ */
10230 0x1e95, 499, /* ẕ Ẕ */
10231 0x1ea1, 499, /* ạ Ạ */
10232 0x1ea3, 499, /* ả Ả */
10233 0x1ea5, 499, /* ấ Ấ */
10234 0x1ea7, 499, /* ầ Ầ */
10235 0x1ea9, 499, /* ẩ Ẩ */
10236 0x1eab, 499, /* ẫ Ẫ */
10237 0x1ead, 499, /* ậ Ậ */
10238 0x1eaf, 499, /* ắ Ắ */
10239 0x1eb1, 499, /* ằ Ằ */
10240 0x1eb3, 499, /* ẳ Ẳ */
10241 0x1eb5, 499, /* ẵ Ẵ */
10242 0x1eb7, 499, /* ặ Ặ */
10243 0x1eb9, 499, /* ẹ Ẹ */
10244 0x1ebb, 499, /* ẻ Ẻ */
10245 0x1ebd, 499, /* ẽ Ẽ */
10246 0x1ebf, 499, /* ế Ế */
10247 0x1ec1, 499, /* ề Ề */
10248 0x1ec3, 499, /* ể Ể */
10249 0x1ec5, 499, /* ễ Ễ */
10250 0x1ec7, 499, /* ệ Ệ */
10251 0x1ec9, 499, /* ỉ Ỉ */
10252 0x1ecb, 499, /* ị Ị */
10253 0x1ecd, 499, /* ọ Ọ */
10254 0x1ecf, 499, /* ỏ Ỏ */
10255 0x1ed1, 499, /* ố Ố */
10256 0x1ed3, 499, /* ồ Ồ */
10257 0x1ed5, 499, /* ổ Ổ */
10258 0x1ed7, 499, /* ỗ Ỗ */
10259 0x1ed9, 499, /* ộ Ộ */
10260 0x1edb, 499, /* ớ Ớ */
10261 0x1edd, 499, /* ờ Ờ */
10262 0x1edf, 499, /* ở Ở */
10263 0x1ee1, 499, /* ỡ Ỡ */
10264 0x1ee3, 499, /* ợ Ợ */
10265 0x1ee5, 499, /* ụ Ụ */
10266 0x1ee7, 499, /* ủ Ủ */
10267 0x1ee9, 499, /* ứ Ứ */
10268 0x1eeb, 499, /* ừ Ừ */
10269 0x1eed, 499, /* ử Ử */
10270 0x1eef, 499, /* ữ Ữ */
10271 0x1ef1, 499, /* ự Ự */
10272 0x1ef3, 499, /* ỳ Ỳ */
10273 0x1ef5, 499, /* ỵ Ỵ */
10274 0x1ef7, 499, /* ỷ Ỷ */
10275 0x1ef9, 499, /* ỹ Ỹ */
10276 0x1f51, 508, /* ὑ Ὑ */
10277 0x1f53, 508, /* ὓ Ὓ */
10278 0x1f55, 508, /* ὕ Ὕ */
10279 0x1f57, 508, /* ὗ Ὗ */
10280 0x1fb3, 509, /* ᾳ ᾼ */
10281 0x1fc3, 509, /* ῃ ῌ */
10282 0x1fe5, 507, /* ῥ Ῥ */
10283 0x1ff3, 509, /* ῳ ῼ */
10284};
10285
10286/*
10287 * upper case ranges
10288 * 3rd col is conversion excess 500
10289 */
10290static Rune __tolower2[] = {
10291 0x0041, 0x005a, 532, /* A-Z a-z */
10292 0x00c0, 0x00d6, 532, /* À-Ö à-ö */
10293 0x00d8, 0x00de, 532, /* Ø-Þ ø-þ */
10294 0x0189, 0x018a, 705, /* Ɖ-Ɗ ɖ-ɗ */
10295 0x018e, 0x018f, 702, /* Ǝ-Ə ɘ-ə */
10296 0x01b1, 0x01b2, 717, /* Ʊ-Ʋ ʊ-ʋ */
10297 0x0388, 0x038a, 537, /* Έ-Ί έ-ί */
10298 0x038e, 0x038f, 563, /* Ύ-Ώ ύ-ώ */
10299 0x0391, 0x03a1, 532, /* Α-Ρ α-ρ */
10300 0x03a3, 0x03ab, 532, /* Σ-Ϋ σ-ϋ */
10301 0x0401, 0x040c, 580, /* Ё-Ќ ё-ќ */
10302 0x040e, 0x040f, 580, /* Ў-Џ ў-џ */
10303 0x0410, 0x042f, 532, /* А-Я а-я */
10304 0x0531, 0x0556, 548, /* Ա-Ֆ ա-ֆ */
10305 0x10a0, 0x10c5, 548, /* Ⴀ-Ⴥ ა-ჵ */
10306 0x1f08, 0x1f0f, 492, /* Ἀ-Ἇ ἀ-ἇ */
10307 0x1f18, 0x1f1d, 492, /* Ἐ-Ἕ ἐ-ἕ */
10308 0x1f28, 0x1f2f, 492, /* Ἠ-Ἧ ἠ-ἧ */
10309 0x1f38, 0x1f3f, 492, /* Ἰ-Ἷ ἰ-ἷ */
10310 0x1f48, 0x1f4d, 492, /* Ὀ-Ὅ ὀ-ὅ */
10311 0x1f68, 0x1f6f, 492, /* Ὠ-Ὧ ὠ-ὧ */
10312 0x1f88, 0x1f8f, 492, /* ᾈ-ᾏ ᾀ-ᾇ */
10313 0x1f98, 0x1f9f, 492, /* ᾘ-ᾟ ᾐ-ᾗ */
10314 0x1fa8, 0x1faf, 492, /* ᾨ-ᾯ ᾠ-ᾧ */
10315 0x1fb8, 0x1fb9, 492, /* Ᾰ-Ᾱ ᾰ-ᾱ */
10316 0x1fba, 0x1fbb, 426, /* Ὰ-Ά ὰ-ά */
10317 0x1fc8, 0x1fcb, 414, /* Ὲ-Ή ὲ-ή */
10318 0x1fd8, 0x1fd9, 492, /* Ῐ-Ῑ ῐ-ῑ */
10319 0x1fda, 0x1fdb, 400, /* Ὶ-Ί ὶ-ί */
10320 0x1fe8, 0x1fe9, 492, /* Ῠ-Ῡ ῠ-ῡ */
10321 0x1fea, 0x1feb, 388, /* Ὺ-Ύ ὺ-ύ */
10322 0x1ff8, 0x1ff9, 372, /* Ὸ-Ό ὸ-ό */
10323 0x1ffa, 0x1ffb, 374, /* Ὼ-Ώ ὼ-ώ */
10324 0x2160, 0x216f, 516, /* Ⅰ-Ⅿ ⅰ-ⅿ */
10325 0x24b6, 0x24cf, 526, /* Ⓐ-Ⓩ ⓐ-ⓩ */
10326 0xff21, 0xff3a, 532, /* A-Z a-z */
10327};
10328
10329/*
10330 * upper case singlets
10331 * 2nd col is conversion excess 500
10332 */
10333static Rune __tolower1[] = {
10334 0x0100, 501, /* Ā ā */
10335 0x0102, 501, /* Ă ă */
10336 0x0104, 501, /* Ą ą */
10337 0x0106, 501, /* Ć ć */
10338 0x0108, 501, /* Ĉ ĉ */
10339 0x010a, 501, /* Ċ ċ */
10340 0x010c, 501, /* Č č */
10341 0x010e, 501, /* Ď ď */
10342 0x0110, 501, /* Đ đ */
10343 0x0112, 501, /* Ē ē */
10344 0x0114, 501, /* Ĕ ĕ */
10345 0x0116, 501, /* Ė ė */
10346 0x0118, 501, /* Ę ę */
10347 0x011a, 501, /* Ě ě */
10348 0x011c, 501, /* Ĝ ĝ */
10349 0x011e, 501, /* Ğ ğ */
10350 0x0120, 501, /* Ġ ġ */
10351 0x0122, 501, /* Ģ ģ */
10352 0x0124, 501, /* Ĥ ĥ */
10353 0x0126, 501, /* Ħ ħ */
10354 0x0128, 501, /* Ĩ ĩ */
10355 0x012a, 501, /* Ī ī */
10356 0x012c, 501, /* Ĭ ĭ */
10357 0x012e, 501, /* Į į */
10358 0x0130, 301, /* İ i */
10359 0x0132, 501, /* IJ ij */
10360 0x0134, 501, /* Ĵ ĵ */
10361 0x0136, 501, /* Ķ ķ */
10362 0x0139, 501, /* Ĺ ĺ */
10363 0x013b, 501, /* Ļ ļ */
10364 0x013d, 501, /* Ľ ľ */
10365 0x013f, 501, /* Ŀ ŀ */
10366 0x0141, 501, /* Ł ł */
10367 0x0143, 501, /* Ń ń */
10368 0x0145, 501, /* Ņ ņ */
10369 0x0147, 501, /* Ň ň */
10370 0x014a, 501, /* Ŋ ŋ */
10371 0x014c, 501, /* Ō ō */
10372 0x014e, 501, /* Ŏ ŏ */
10373 0x0150, 501, /* Ő ő */
10374 0x0152, 501, /* Œ œ */
10375 0x0154, 501, /* Ŕ ŕ */
10376 0x0156, 501, /* Ŗ ŗ */
10377 0x0158, 501, /* Ř ř */
10378 0x015a, 501, /* Ś ś */
10379 0x015c, 501, /* Ŝ ŝ */
10380 0x015e, 501, /* Ş ş */
10381 0x0160, 501, /* Š š */
10382 0x0162, 501, /* Ţ ţ */
10383 0x0164, 501, /* Ť ť */
10384 0x0166, 501, /* Ŧ ŧ */
10385 0x0168, 501, /* Ũ ũ */
10386 0x016a, 501, /* Ū ū */
10387 0x016c, 501, /* Ŭ ŭ */
10388 0x016e, 501, /* Ů ů */
10389 0x0170, 501, /* Ű ű */
10390 0x0172, 501, /* Ų ų */
10391 0x0174, 501, /* Ŵ ŵ */
10392 0x0176, 501, /* Ŷ ŷ */
10393 0x0178, 379, /* Ÿ ÿ */
10394 0x0179, 501, /* Ź ź */
10395 0x017b, 501, /* Ż ż */
10396 0x017d, 501, /* Ž ž */
10397 0x0181, 710, /* Ɓ ɓ */
10398 0x0182, 501, /* Ƃ ƃ */
10399 0x0184, 501, /* Ƅ ƅ */
10400 0x0186, 706, /* Ɔ ɔ */
10401 0x0187, 501, /* Ƈ ƈ */
10402 0x018b, 501, /* Ƌ ƌ */
10403 0x0190, 703, /* Ɛ ɛ */
10404 0x0191, 501, /* Ƒ ƒ */
10405 0x0193, 705, /* Ɠ ɠ */
10406 0x0194, 707, /* Ɣ ɣ */
10407 0x0196, 711, /* Ɩ ɩ */
10408 0x0197, 709, /* Ɨ ɨ */
10409 0x0198, 501, /* Ƙ ƙ */
10410 0x019c, 711, /* Ɯ ɯ */
10411 0x019d, 713, /* Ɲ ɲ */
10412 0x01a0, 501, /* Ơ ơ */
10413 0x01a2, 501, /* Ƣ ƣ */
10414 0x01a4, 501, /* Ƥ ƥ */
10415 0x01a7, 501, /* Ƨ ƨ */
10416 0x01a9, 718, /* Ʃ ʃ */
10417 0x01ac, 501, /* Ƭ ƭ */
10418 0x01ae, 718, /* Ʈ ʈ */
10419 0x01af, 501, /* Ư ư */
10420 0x01b3, 501, /* Ƴ ƴ */
10421 0x01b5, 501, /* Ƶ ƶ */
10422 0x01b7, 719, /* Ʒ ʒ */
10423 0x01b8, 501, /* Ƹ ƹ */
10424 0x01bc, 501, /* Ƽ ƽ */
10425 0x01c4, 502, /* DŽ dž */
10426 0x01c5, 501, /* Dž dž */
10427 0x01c7, 502, /* LJ lj */
10428 0x01c8, 501, /* Lj lj */
10429 0x01ca, 502, /* NJ nj */
10430 0x01cb, 501, /* Nj nj */
10431 0x01cd, 501, /* Ǎ ǎ */
10432 0x01cf, 501, /* Ǐ ǐ */
10433 0x01d1, 501, /* Ǒ ǒ */
10434 0x01d3, 501, /* Ǔ ǔ */
10435 0x01d5, 501, /* Ǖ ǖ */
10436 0x01d7, 501, /* Ǘ ǘ */
10437 0x01d9, 501, /* Ǚ ǚ */
10438 0x01db, 501, /* Ǜ ǜ */
10439 0x01de, 501, /* Ǟ ǟ */
10440 0x01e0, 501, /* Ǡ ǡ */
10441 0x01e2, 501, /* Ǣ ǣ */
10442 0x01e4, 501, /* Ǥ ǥ */
10443 0x01e6, 501, /* Ǧ ǧ */
10444 0x01e8, 501, /* Ǩ ǩ */
10445 0x01ea, 501, /* Ǫ ǫ */
10446 0x01ec, 501, /* Ǭ ǭ */
10447 0x01ee, 501, /* Ǯ ǯ */
10448 0x01f1, 502, /* DZ dz */
10449 0x01f2, 501, /* Dz dz */
10450 0x01f4, 501, /* Ǵ ǵ */
10451 0x01fa, 501, /* Ǻ ǻ */
10452 0x01fc, 501, /* Ǽ ǽ */
10453 0x01fe, 501, /* Ǿ ǿ */
10454 0x0200, 501, /* Ȁ ȁ */
10455 0x0202, 501, /* Ȃ ȃ */
10456 0x0204, 501, /* Ȅ ȅ */
10457 0x0206, 501, /* Ȇ ȇ */
10458 0x0208, 501, /* Ȉ ȉ */
10459 0x020a, 501, /* Ȋ ȋ */
10460 0x020c, 501, /* Ȍ ȍ */
10461 0x020e, 501, /* Ȏ ȏ */
10462 0x0210, 501, /* Ȑ ȑ */
10463 0x0212, 501, /* Ȓ ȓ */
10464 0x0214, 501, /* Ȕ ȕ */
10465 0x0216, 501, /* Ȗ ȗ */
10466 0x0386, 538, /* Ά ά */
10467 0x038c, 564, /* Ό ό */
10468 0x03e2, 501, /* Ϣ ϣ */
10469 0x03e4, 501, /* Ϥ ϥ */
10470 0x03e6, 501, /* Ϧ ϧ */
10471 0x03e8, 501, /* Ϩ ϩ */
10472 0x03ea, 501, /* Ϫ ϫ */
10473 0x03ec, 501, /* Ϭ ϭ */
10474 0x03ee, 501, /* Ϯ ϯ */
10475 0x0460, 501, /* Ѡ ѡ */
10476 0x0462, 501, /* Ѣ ѣ */
10477 0x0464, 501, /* Ѥ ѥ */
10478 0x0466, 501, /* Ѧ ѧ */
10479 0x0468, 501, /* Ѩ ѩ */
10480 0x046a, 501, /* Ѫ ѫ */
10481 0x046c, 501, /* Ѭ ѭ */
10482 0x046e, 501, /* Ѯ ѯ */
10483 0x0470, 501, /* Ѱ ѱ */
10484 0x0472, 501, /* Ѳ ѳ */
10485 0x0474, 501, /* Ѵ ѵ */
10486 0x0476, 501, /* Ѷ ѷ */
10487 0x0478, 501, /* Ѹ ѹ */
10488 0x047a, 501, /* Ѻ ѻ */
10489 0x047c, 501, /* Ѽ ѽ */
10490 0x047e, 501, /* Ѿ ѿ */
10491 0x0480, 501, /* Ҁ ҁ */
10492 0x0490, 501, /* Ґ ґ */
10493 0x0492, 501, /* Ғ ғ */
10494 0x0494, 501, /* Ҕ ҕ */
10495 0x0496, 501, /* Җ җ */
10496 0x0498, 501, /* Ҙ ҙ */
10497 0x049a, 501, /* Қ қ */
10498 0x049c, 501, /* Ҝ ҝ */
10499 0x049e, 501, /* Ҟ ҟ */
10500 0x04a0, 501, /* Ҡ ҡ */
10501 0x04a2, 501, /* Ң ң */
10502 0x04a4, 501, /* Ҥ ҥ */
10503 0x04a6, 501, /* Ҧ ҧ */
10504 0x04a8, 501, /* Ҩ ҩ */
10505 0x04aa, 501, /* Ҫ ҫ */
10506 0x04ac, 501, /* Ҭ ҭ */
10507 0x04ae, 501, /* Ү ү */
10508 0x04b0, 501, /* Ұ ұ */
10509 0x04b2, 501, /* Ҳ ҳ */
10510 0x04b4, 501, /* Ҵ ҵ */
10511 0x04b6, 501, /* Ҷ ҷ */
10512 0x04b8, 501, /* Ҹ ҹ */
10513 0x04ba, 501, /* Һ һ */
10514 0x04bc, 501, /* Ҽ ҽ */
10515 0x04be, 501, /* Ҿ ҿ */
10516 0x04c1, 501, /* Ӂ ӂ */
10517 0x04c3, 501, /* Ӄ ӄ */
10518 0x04c7, 501, /* Ӈ ӈ */
10519 0x04cb, 501, /* Ӌ ӌ */
10520 0x04d0, 501, /* Ӑ ӑ */
10521 0x04d2, 501, /* Ӓ ӓ */
10522 0x04d4, 501, /* Ӕ ӕ */
10523 0x04d6, 501, /* Ӗ ӗ */
10524 0x04d8, 501, /* Ә ә */
10525 0x04da, 501, /* Ӛ ӛ */
10526 0x04dc, 501, /* Ӝ ӝ */
10527 0x04de, 501, /* Ӟ ӟ */
10528 0x04e0, 501, /* Ӡ ӡ */
10529 0x04e2, 501, /* Ӣ ӣ */
10530 0x04e4, 501, /* Ӥ ӥ */
10531 0x04e6, 501, /* Ӧ ӧ */
10532 0x04e8, 501, /* Ө ө */
10533 0x04ea, 501, /* Ӫ ӫ */
10534 0x04ee, 501, /* Ӯ ӯ */
10535 0x04f0, 501, /* Ӱ ӱ */
10536 0x04f2, 501, /* Ӳ ӳ */
10537 0x04f4, 501, /* Ӵ ӵ */
10538 0x04f8, 501, /* Ӹ ӹ */
10539 0x1e00, 501, /* Ḁ ḁ */
10540 0x1e02, 501, /* Ḃ ḃ */
10541 0x1e04, 501, /* Ḅ ḅ */
10542 0x1e06, 501, /* Ḇ ḇ */
10543 0x1e08, 501, /* Ḉ ḉ */
10544 0x1e0a, 501, /* Ḋ ḋ */
10545 0x1e0c, 501, /* Ḍ ḍ */
10546 0x1e0e, 501, /* Ḏ ḏ */
10547 0x1e10, 501, /* Ḑ ḑ */
10548 0x1e12, 501, /* Ḓ ḓ */
10549 0x1e14, 501, /* Ḕ ḕ */
10550 0x1e16, 501, /* Ḗ ḗ */
10551 0x1e18, 501, /* Ḙ ḙ */
10552 0x1e1a, 501, /* Ḛ ḛ */
10553 0x1e1c, 501, /* Ḝ ḝ */
10554 0x1e1e, 501, /* Ḟ ḟ */
10555 0x1e20, 501, /* Ḡ ḡ */
10556 0x1e22, 501, /* Ḣ ḣ */
10557 0x1e24, 501, /* Ḥ ḥ */
10558 0x1e26, 501, /* Ḧ ḧ */
10559 0x1e28, 501, /* Ḩ ḩ */
10560 0x1e2a, 501, /* Ḫ ḫ */
10561 0x1e2c, 501, /* Ḭ ḭ */
10562 0x1e2e, 501, /* Ḯ ḯ */
10563 0x1e30, 501, /* Ḱ ḱ */
10564 0x1e32, 501, /* Ḳ ḳ */
10565 0x1e34, 501, /* Ḵ ḵ */
10566 0x1e36, 501, /* Ḷ ḷ */
10567 0x1e38, 501, /* Ḹ ḹ */
10568 0x1e3a, 501, /* Ḻ ḻ */
10569 0x1e3c, 501, /* Ḽ ḽ */
10570 0x1e3e, 501, /* Ḿ ḿ */
10571 0x1e40, 501, /* Ṁ ṁ */
10572 0x1e42, 501, /* Ṃ ṃ */
10573 0x1e44, 501, /* Ṅ ṅ */
10574 0x1e46, 501, /* Ṇ ṇ */
10575 0x1e48, 501, /* Ṉ ṉ */
10576 0x1e4a, 501, /* Ṋ ṋ */
10577 0x1e4c, 501, /* Ṍ ṍ */
10578 0x1e4e, 501, /* Ṏ ṏ */
10579 0x1e50, 501, /* Ṑ ṑ */
10580 0x1e52, 501, /* Ṓ ṓ */
10581 0x1e54, 501, /* Ṕ ṕ */
10582 0x1e56, 501, /* Ṗ ṗ */
10583 0x1e58, 501, /* Ṙ ṙ */
10584 0x1e5a, 501, /* Ṛ ṛ */
10585 0x1e5c, 501, /* Ṝ ṝ */
10586 0x1e5e, 501, /* Ṟ ṟ */
10587 0x1e60, 501, /* Ṡ ṡ */
10588 0x1e62, 501, /* Ṣ ṣ */
10589 0x1e64, 501, /* Ṥ ṥ */
10590 0x1e66, 501, /* Ṧ ṧ */
10591 0x1e68, 501, /* Ṩ ṩ */
10592 0x1e6a, 501, /* Ṫ ṫ */
10593 0x1e6c, 501, /* Ṭ ṭ */
10594 0x1e6e, 501, /* Ṯ ṯ */
10595 0x1e70, 501, /* Ṱ ṱ */
10596 0x1e72, 501, /* Ṳ ṳ */
10597 0x1e74, 501, /* Ṵ ṵ */
10598 0x1e76, 501, /* Ṷ ṷ */
10599 0x1e78, 501, /* Ṹ ṹ */
10600 0x1e7a, 501, /* Ṻ ṻ */
10601 0x1e7c, 501, /* Ṽ ṽ */
10602 0x1e7e, 501, /* Ṿ ṿ */
10603 0x1e80, 501, /* Ẁ ẁ */
10604 0x1e82, 501, /* Ẃ ẃ */
10605 0x1e84, 501, /* Ẅ ẅ */
10606 0x1e86, 501, /* Ẇ ẇ */
10607 0x1e88, 501, /* Ẉ ẉ */
10608 0x1e8a, 501, /* Ẋ ẋ */
10609 0x1e8c, 501, /* Ẍ ẍ */
10610 0x1e8e, 501, /* Ẏ ẏ */
10611 0x1e90, 501, /* Ẑ ẑ */
10612 0x1e92, 501, /* Ẓ ẓ */
10613 0x1e94, 501, /* Ẕ ẕ */
10614 0x1ea0, 501, /* Ạ ạ */
10615 0x1ea2, 501, /* Ả ả */
10616 0x1ea4, 501, /* Ấ ấ */
10617 0x1ea6, 501, /* Ầ ầ */
10618 0x1ea8, 501, /* Ẩ ẩ */
10619 0x1eaa, 501, /* Ẫ ẫ */
10620 0x1eac, 501, /* Ậ ậ */
10621 0x1eae, 501, /* Ắ ắ */
10622 0x1eb0, 501, /* Ằ ằ */
10623 0x1eb2, 501, /* Ẳ ẳ */
10624 0x1eb4, 501, /* Ẵ ẵ */
10625 0x1eb6, 501, /* Ặ ặ */
10626 0x1eb8, 501, /* Ẹ ẹ */
10627 0x1eba, 501, /* Ẻ ẻ */
10628 0x1ebc, 501, /* Ẽ ẽ */
10629 0x1ebe, 501, /* Ế ế */
10630 0x1ec0, 501, /* Ề ề */
10631 0x1ec2, 501, /* Ể ể */
10632 0x1ec4, 501, /* Ễ ễ */
10633 0x1ec6, 501, /* Ệ ệ */
10634 0x1ec8, 501, /* Ỉ ỉ */
10635 0x1eca, 501, /* Ị ị */
10636 0x1ecc, 501, /* Ọ ọ */
10637 0x1ece, 501, /* Ỏ ỏ */
10638 0x1ed0, 501, /* Ố ố */
10639 0x1ed2, 501, /* Ồ ồ */
10640 0x1ed4, 501, /* Ổ ổ */
10641 0x1ed6, 501, /* Ỗ ỗ */
10642 0x1ed8, 501, /* Ộ ộ */
10643 0x1eda, 501, /* Ớ ớ */
10644 0x1edc, 501, /* Ờ ờ */
10645 0x1ede, 501, /* Ở ở */
10646 0x1ee0, 501, /* Ỡ ỡ */
10647 0x1ee2, 501, /* Ợ ợ */
10648 0x1ee4, 501, /* Ụ ụ */
10649 0x1ee6, 501, /* Ủ ủ */
10650 0x1ee8, 501, /* Ứ ứ */
10651 0x1eea, 501, /* Ừ ừ */
10652 0x1eec, 501, /* Ử ử */
10653 0x1eee, 501, /* Ữ ữ */
10654 0x1ef0, 501, /* Ự ự */
10655 0x1ef2, 501, /* Ỳ ỳ */
10656 0x1ef4, 501, /* Ỵ ỵ */
10657 0x1ef6, 501, /* Ỷ ỷ */
10658 0x1ef8, 501, /* Ỹ ỹ */
10659 0x1f59, 492, /* Ὑ ὑ */
10660 0x1f5b, 492, /* Ὓ ὓ */
10661 0x1f5d, 492, /* Ὕ ὕ */
10662 0x1f5f, 492, /* Ὗ ὗ */
10663 0x1fbc, 491, /* ᾼ ᾳ */
10664 0x1fcc, 491, /* ῌ ῃ */
10665 0x1fec, 493, /* Ῥ ῥ */
10666 0x1ffc, 491, /* ῼ ῳ */
10667};
10668
10669static Rune *rune_bsearch(Rune c, Rune *t, int n, int ne) {
10670 Rune *p;
10671 int m;
10672
10673 while (n > 1) {
10674 m = n / 2;
10675 p = t + m * ne;
10676 if (c >= p[0]) {
10677 t = p;
10678 n = n - m;
10679 } else
10680 n = m;
10681 }
10682 if (n && c >= t[0]) return t;
10683 return 0;
10684}
10685
10686Rune tolowerrune(Rune c) {
10687 Rune *p;
10688
10689 p = rune_bsearch(c, __tolower2, nelem(__tolower2) / 3, 3);
10690 if (p && c >= p[0] && c <= p[1]) return c + p[2] - 500;
10691 p = rune_bsearch(c, __tolower1, nelem(__tolower1) / 2, 2);
10692 if (p && c == p[0]) return c + p[1] - 500;
10693 return c;
10694}
10695
10696Rune toupperrune(Rune c) {
10697 Rune *p;
10698
10699 p = rune_bsearch(c, __toupper2, nelem(__toupper2) / 3, 3);
10700 if (p && c >= p[0] && c <= p[1]) return c + p[2] - 500;
10701 p = rune_bsearch(c, __toupper1, nelem(__toupper1) / 2, 2);
10702 if (p && c == p[0]) return c + p[1] - 500;
10703 return c;
10704}
10705
10706int islowerrune(Rune c) {
10707 Rune *p;
10708
10709 p = rune_bsearch(c, __toupper2, nelem(__toupper2) / 3, 3);
10710 if (p && c >= p[0] && c <= p[1]) return 1;
10711 p = rune_bsearch(c, __toupper1, nelem(__toupper1) / 2, 2);
10712 if (p && c == p[0]) return 1;
10713 return 0;
10714}
10715
10716int isupperrune(Rune c) {
10717 Rune *p;
10718
10719 p = rune_bsearch(c, __tolower2, nelem(__tolower2) / 3, 3);
10720 if (p && c >= p[0] && c <= p[1]) return 1;
10721 p = rune_bsearch(c, __tolower1, nelem(__tolower1) / 2, 2);
10722 if (p && c == p[0]) return 1;
10723 return 0;
10724}
10725
10726int isdigitrune(Rune c) {
10727 return c >= '0' && c <= '9';
10728}
10729
10730int isnewline(Rune c) {
10731 return c == 0xA || c == 0xD || c == 0x2028 || c == 0x2029;
10732}
10733
10734int iswordchar(Rune c) {
10735 return c == '_' || isdigitrune(c) || (c >= 'a' && c <= 'z') ||
10736 (c >= 'A' && c <= 'Z');
10737}
10738
10739int isalpharune(Rune c) {
10740 Rune *p;
10741
10742 if (isupperrune(c) || islowerrune(c)) return 1;
10743 p = rune_bsearch(c, __alpha2, nelem(__alpha2) / 2, 2);
10744 if (p && c >= p[0] && c <= p[1]) return 1;
10745 p = rune_bsearch(c, __alpha1, nelem(__alpha1), 1);
10746 if (p && c == p[0]) return 1;
10747 return 0;
10748}
10749
10750int isspacerune(Rune c) {
10751 Rune *p;
10752
10753 p = rune_bsearch(c, __space2, nelem(__space2) / 2, 2);
10754 if (p && c >= p[0] && c <= p[1]) return 1;
10755 return 0;
10756}
10757
10758#else /* CS_ENABLE_UTF8 */
10759
10760int chartorune(Rune *rune, const char *str) {
10761 *rune = *(uchar *) str;
10762 return 1;
10763}
10764
10765int fullrune(const char *str, int n) {
10766 (void) str;
10767 return (n <= 0) ? 0 : 1;
10768}
10769
10770int isdigitrune(Rune c) {
10771 return isdigit(c);
10772}
10773
10774int isnewline(Rune c) {
10775 return c == 0xA || c == 0xD || c == 0x2028 || c == 0x2029;
10776}
10777
10778int iswordchar(Rune c) {
10779 return c == '_' || isdigitrune(c) || (c >= 'a' && c <= 'z') ||
10780 (c >= 'A' && c <= 'Z');
10781}
10782
10783int isalpharune(Rune c) {
10784 return isalpha(c);
10785}
10786int islowerrune(Rune c) {
10787 return islower(c);
10788}
10789int isspacerune(Rune c) {
10790 return isspace(c);
10791}
10792int isupperrune(Rune c) {
10793 return isupper(c);
10794}
10795
10796int runetochar(char *str, Rune *rune) {
10797 str[0] = (char) *rune;
10798 return 1;
10799}
10800
10801Rune tolowerrune(Rune c) {
10802 return tolower(c);
10803}
10804Rune toupperrune(Rune c) {
10805 return toupper(c);
10806}
10807int utfnlen(const char *s, long m) {
10808 (void) s;
10809 return (int) c_strnlen(s, (size_t) m);
10810}
10811
10812const char *utfnshift(const char *s, long m) {
10813 return s + m;
10814}
10815
10816#endif /* CS_ENABLE_UTF8 */
10817
10818#endif /* EXCLUDE_COMMON */
10819#ifdef V7_MODULE_LINES
10820#line 1 "common/base64.c"
10821#endif
10822/*
10823 * Copyright (c) 2014 Cesanta Software Limited
10824 * All rights reserved
10825 */
10826
10827#ifndef EXCLUDE_COMMON
10828
10829/* Amalgamated: #include "common/base64.h" */
10830
10831#include <string.h>
10832
10833/* Amalgamated: #include "common/cs_dbg.h" */
10834
10835/* ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/ */
10836
10837#define NUM_UPPERCASES ('Z' - 'A' + 1)
10838#define NUM_LETTERS (NUM_UPPERCASES * 2)
10839#define NUM_DIGITS ('9' - '0' + 1)
10840
10841/*
10842 * Emit a base64 code char.
10843 *
10844 * Doesn't use memory, thus it's safe to use to safely dump memory in crashdumps
10845 */
10846static void cs_base64_emit_code(struct cs_base64_ctx *ctx, int v) {
10847 if (v < NUM_UPPERCASES) {
10848 ctx->b64_putc(v + 'A', ctx->user_data);
10849 } else if (v < (NUM_LETTERS)) {
10850 ctx->b64_putc(v - NUM_UPPERCASES + 'a', ctx->user_data);
10851 } else if (v < (NUM_LETTERS + NUM_DIGITS)) {
10852 ctx->b64_putc(v - NUM_LETTERS + '0', ctx->user_data);
10853 } else {
10854 ctx->b64_putc(v - NUM_LETTERS - NUM_DIGITS == 0 ? '+' : '/',
10855 ctx->user_data);
10856 }
10857}
10858
10859static void cs_base64_emit_chunk(struct cs_base64_ctx *ctx) {
10860 int a, b, c;
10861
10862 a = ctx->chunk[0];
10863 b = ctx->chunk[1];
10864 c = ctx->chunk[2];
10865
10866 cs_base64_emit_code(ctx, a >> 2);
10867 cs_base64_emit_code(ctx, ((a & 3) << 4) | (b >> 4));
10868 if (ctx->chunk_size > 1) {
10869 cs_base64_emit_code(ctx, (b & 15) << 2 | (c >> 6));
10870 }
10871 if (ctx->chunk_size > 2) {
10872 cs_base64_emit_code(ctx, c & 63);
10873 }
10874}
10875
10876void cs_base64_init(struct cs_base64_ctx *ctx, cs_base64_putc_t b64_putc,
10877 void *user_data) {
10878 ctx->chunk_size = 0;
10879 ctx->b64_putc = b64_putc;
10880 ctx->user_data = user_data;
10881}
10882
10883void cs_base64_update(struct cs_base64_ctx *ctx, const char *str, size_t len) {
10884 const unsigned char *src = (const unsigned char *) str;
10885 size_t i;
10886 for (i = 0; i < len; i++) {
10887 ctx->chunk[ctx->chunk_size++] = src[i];
10888 if (ctx->chunk_size == 3) {
10889 cs_base64_emit_chunk(ctx);
10890 ctx->chunk_size = 0;
10891 }
10892 }
10893}
10894
10895void cs_base64_finish(struct cs_base64_ctx *ctx) {
10896 if (ctx->chunk_size > 0) {
10897 int i;
10898 memset(&ctx->chunk[ctx->chunk_size], 0, 3 - ctx->chunk_size);
10899 cs_base64_emit_chunk(ctx);
10900 for (i = 0; i < (3 - ctx->chunk_size); i++) {
10901 ctx->b64_putc('=', ctx->user_data);
10902 }
10903 }
10904}
10905
10906#define BASE64_ENCODE_BODY \
10907 static const char *b64 = \
10908 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; \
10909 int i, j, a, b, c; \
10910 \
10911 for (i = j = 0; i < src_len; i += 3) { \
10912 a = src[i]; \
10913 b = i + 1 >= src_len ? 0 : src[i + 1]; \
10914 c = i + 2 >= src_len ? 0 : src[i + 2]; \
10915 \
10916 BASE64_OUT(b64[a >> 2]); \
10917 BASE64_OUT(b64[((a & 3) << 4) | (b >> 4)]); \
10918 if (i + 1 < src_len) { \
10919 BASE64_OUT(b64[(b & 15) << 2 | (c >> 6)]); \
10920 } \
10921 if (i + 2 < src_len) { \
10922 BASE64_OUT(b64[c & 63]); \
10923 } \
10924 } \
10925 \
10926 while (j % 4 != 0) { \
10927 BASE64_OUT('='); \
10928 } \
10929 BASE64_FLUSH()
10930
10931#define BASE64_OUT(ch) \
10932 do { \
10933 dst[j++] = (ch); \
10934 } while (0)
10935
10936#define BASE64_FLUSH() \
10937 do { \
10938 dst[j++] = '\0'; \
10939 } while (0)
10940
10941void cs_base64_encode(const unsigned char *src, int src_len, char *dst) {
10942 BASE64_ENCODE_BODY;
10943}
10944
10945#undef BASE64_OUT
10946#undef BASE64_FLUSH
10947
10948#if CS_ENABLE_STDIO
10949#define BASE64_OUT(ch) \
10950 do { \
10951 fprintf(f, "%c", (ch)); \
10952 j++; \
10953 } while (0)
10954
10955#define BASE64_FLUSH()
10956
10957void cs_fprint_base64(FILE *f, const unsigned char *src, int src_len) {
10958 BASE64_ENCODE_BODY;
10959}
10960
10961#undef BASE64_OUT
10962#undef BASE64_FLUSH
10963#endif /* CS_ENABLE_STDIO */
10964
10965/* Convert one byte of encoded base64 input stream to 6-bit chunk */
10966static unsigned char from_b64(unsigned char ch) {
10967 /* Inverse lookup map */
10968 static const unsigned char tab[128] = {
10969 255, 255, 255, 255,
10970 255, 255, 255, 255, /* 0 */
10971 255, 255, 255, 255,
10972 255, 255, 255, 255, /* 8 */
10973 255, 255, 255, 255,
10974 255, 255, 255, 255, /* 16 */
10975 255, 255, 255, 255,
10976 255, 255, 255, 255, /* 24 */
10977 255, 255, 255, 255,
10978 255, 255, 255, 255, /* 32 */
10979 255, 255, 255, 62,
10980 255, 255, 255, 63, /* 40 */
10981 52, 53, 54, 55,
10982 56, 57, 58, 59, /* 48 */
10983 60, 61, 255, 255,
10984 255, 200, 255, 255, /* 56 '=' is 200, on index 61 */
10985 255, 0, 1, 2,
10986 3, 4, 5, 6, /* 64 */
10987 7, 8, 9, 10,
10988 11, 12, 13, 14, /* 72 */
10989 15, 16, 17, 18,
10990 19, 20, 21, 22, /* 80 */
10991 23, 24, 25, 255,
10992 255, 255, 255, 255, /* 88 */
10993 255, 26, 27, 28,
10994 29, 30, 31, 32, /* 96 */
10995 33, 34, 35, 36,
10996 37, 38, 39, 40, /* 104 */
10997 41, 42, 43, 44,
10998 45, 46, 47, 48, /* 112 */
10999 49, 50, 51, 255,
11000 255, 255, 255, 255, /* 120 */
11001 };
11002 return tab[ch & 127];
11003}
11004
11005int cs_base64_decode(const unsigned char *s, int len, char *dst, int *dec_len) {
11006 unsigned char a, b, c, d;
11007 int orig_len = len;
11008 char *orig_dst = dst;
11009 while (len >= 4 && (a = from_b64(s[0])) != 255 &&
11010 (b = from_b64(s[1])) != 255 && (c = from_b64(s[2])) != 255 &&
11011 (d = from_b64(s[3])) != 255) {
11012 s += 4;
11013 len -= 4;
11014 if (a == 200 || b == 200) break; /* '=' can't be there */
11015 *dst++ = a << 2 | b >> 4;
11016 if (c == 200) break;
11017 *dst++ = b << 4 | c >> 2;
11018 if (d == 200) break;
11019 *dst++ = c << 6 | d;
11020 }
11021 *dst = 0;
11022 if (dec_len != NULL) *dec_len = (dst - orig_dst);
11023 return orig_len - len;
11024}
11025
11026#endif /* EXCLUDE_COMMON */
11027#ifdef V7_MODULE_LINES
11028#line 1 "common/cs_md5.c"
11029#endif
11030/*
11031 * This code implements the MD5 message-digest algorithm.
11032 * The algorithm is due to Ron Rivest. This code was
11033 * written by Colin Plumb in 1993, no copyright is claimed.
11034 * This code is in the public domain; do with it what you wish.
11035 *
11036 * Equivalent code is available from RSA Data Security, Inc.
11037 * This code has been tested against that, and is equivalent,
11038 * except that you don't need to include two pages of legalese
11039 * with every copy.
11040 *
11041 * To compute the message digest of a chunk of bytes, declare an
11042 * MD5Context structure, pass it to MD5Init, call MD5Update as
11043 * needed on buffers full of bytes, and then call MD5Final, which
11044 * will fill a supplied 16-byte array with the digest.
11045 */
11046
11047/* Amalgamated: #include "common/cs_md5.h" */
11048/* Amalgamated: #include "common/str_util.h" */
11049
11050#if !defined(EXCLUDE_COMMON)
11051#if !CS_DISABLE_MD5
11052
11053/* Amalgamated: #include "common/cs_endian.h" */
11054
11055static void byteReverse(unsigned char *buf, unsigned longs) {
11056/* Forrest: MD5 expect LITTLE_ENDIAN, swap if BIG_ENDIAN */
11057#if BYTE_ORDER == BIG_ENDIAN
11058 do {
11059 uint32_t t = (uint32_t)((unsigned) buf[3] << 8 | buf[2]) << 16 |
11060 ((unsigned) buf[1] << 8 | buf[0]);
11061 *(uint32_t *) buf = t;
11062 buf += 4;
11063 } while (--longs);
11064#else
11065 (void) buf;
11066 (void) longs;
11067#endif
11068}
11069
11070#define F1(x, y, z) (z ^ (x & (y ^ z)))
11071#define F2(x, y, z) F1(z, x, y)
11072#define F3(x, y, z) (x ^ y ^ z)
11073#define F4(x, y, z) (y ^ (x | ~z))
11074
11075#define MD5STEP(f, w, x, y, z, data, s) \
11076 (w += f(x, y, z) + data, w = w << s | w >> (32 - s), w += x)
11077
11078/*
11079 * Start MD5 accumulation. Set bit count to 0 and buffer to mysterious
11080 * initialization constants.
11081 */
11082void cs_md5_init(cs_md5_ctx *ctx) {
11083 ctx->buf[0] = 0x67452301;
11084 ctx->buf[1] = 0xefcdab89;
11085 ctx->buf[2] = 0x98badcfe;
11086 ctx->buf[3] = 0x10325476;
11087
11088 ctx->bits[0] = 0;
11089 ctx->bits[1] = 0;
11090}
11091
11092static void cs_md5_transform(uint32_t buf[4], uint32_t const in[16]) {
11093 register uint32_t a, b, c, d;
11094
11095 a = buf[0];
11096 b = buf[1];
11097 c = buf[2];
11098 d = buf[3];
11099
11100 MD5STEP(F1, a, b, c, d, in[0] + 0xd76aa478, 7);
11101 MD5STEP(F1, d, a, b, c, in[1] + 0xe8c7b756, 12);
11102 MD5STEP(F1, c, d, a, b, in[2] + 0x242070db, 17);
11103 MD5STEP(F1, b, c, d, a, in[3] + 0xc1bdceee, 22);
11104 MD5STEP(F1, a, b, c, d, in[4] + 0xf57c0faf, 7);
11105 MD5STEP(F1, d, a, b, c, in[5] + 0x4787c62a, 12);
11106 MD5STEP(F1, c, d, a, b, in[6] + 0xa8304613, 17);
11107 MD5STEP(F1, b, c, d, a, in[7] + 0xfd469501, 22);
11108 MD5STEP(F1, a, b, c, d, in[8] + 0x698098d8, 7);
11109 MD5STEP(F1, d, a, b, c, in[9] + 0x8b44f7af, 12);
11110 MD5STEP(F1, c, d, a, b, in[10] + 0xffff5bb1, 17);
11111 MD5STEP(F1, b, c, d, a, in[11] + 0x895cd7be, 22);
11112 MD5STEP(F1, a, b, c, d, in[12] + 0x6b901122, 7);
11113 MD5STEP(F1, d, a, b, c, in[13] + 0xfd987193, 12);
11114 MD5STEP(F1, c, d, a, b, in[14] + 0xa679438e, 17);
11115 MD5STEP(F1, b, c, d, a, in[15] + 0x49b40821, 22);
11116
11117 MD5STEP(F2, a, b, c, d, in[1] + 0xf61e2562, 5);
11118 MD5STEP(F2, d, a, b, c, in[6] + 0xc040b340, 9);
11119 MD5STEP(F2, c, d, a, b, in[11] + 0x265e5a51, 14);
11120 MD5STEP(F2, b, c, d, a, in[0] + 0xe9b6c7aa, 20);
11121 MD5STEP(F2, a, b, c, d, in[5] + 0xd62f105d, 5);
11122 MD5STEP(F2, d, a, b, c, in[10] + 0x02441453, 9);
11123 MD5STEP(F2, c, d, a, b, in[15] + 0xd8a1e681, 14);
11124 MD5STEP(F2, b, c, d, a, in[4] + 0xe7d3fbc8, 20);
11125 MD5STEP(F2, a, b, c, d, in[9] + 0x21e1cde6, 5);
11126 MD5STEP(F2, d, a, b, c, in[14] + 0xc33707d6, 9);
11127 MD5STEP(F2, c, d, a, b, in[3] + 0xf4d50d87, 14);
11128 MD5STEP(F2, b, c, d, a, in[8] + 0x455a14ed, 20);
11129 MD5STEP(F2, a, b, c, d, in[13] + 0xa9e3e905, 5);
11130 MD5STEP(F2, d, a, b, c, in[2] + 0xfcefa3f8, 9);
11131 MD5STEP(F2, c, d, a, b, in[7] + 0x676f02d9, 14);
11132 MD5STEP(F2, b, c, d, a, in[12] + 0x8d2a4c8a, 20);
11133
11134 MD5STEP(F3, a, b, c, d, in[5] + 0xfffa3942, 4);
11135 MD5STEP(F3, d, a, b, c, in[8] + 0x8771f681, 11);
11136 MD5STEP(F3, c, d, a, b, in[11] + 0x6d9d6122, 16);
11137 MD5STEP(F3, b, c, d, a, in[14] + 0xfde5380c, 23);
11138 MD5STEP(F3, a, b, c, d, in[1] + 0xa4beea44, 4);
11139 MD5STEP(F3, d, a, b, c, in[4] + 0x4bdecfa9, 11);
11140 MD5STEP(F3, c, d, a, b, in[7] + 0xf6bb4b60, 16);
11141 MD5STEP(F3, b, c, d, a, in[10] + 0xbebfbc70, 23);
11142 MD5STEP(F3, a, b, c, d, in[13] + 0x289b7ec6, 4);
11143 MD5STEP(F3, d, a, b, c, in[0] + 0xeaa127fa, 11);
11144 MD5STEP(F3, c, d, a, b, in[3] + 0xd4ef3085, 16);
11145 MD5STEP(F3, b, c, d, a, in[6] + 0x04881d05, 23);
11146 MD5STEP(F3, a, b, c, d, in[9] + 0xd9d4d039, 4);
11147 MD5STEP(F3, d, a, b, c, in[12] + 0xe6db99e5, 11);
11148 MD5STEP(F3, c, d, a, b, in[15] + 0x1fa27cf8, 16);
11149 MD5STEP(F3, b, c, d, a, in[2] + 0xc4ac5665, 23);
11150
11151 MD5STEP(F4, a, b, c, d, in[0] + 0xf4292244, 6);
11152 MD5STEP(F4, d, a, b, c, in[7] + 0x432aff97, 10);
11153 MD5STEP(F4, c, d, a, b, in[14] + 0xab9423a7, 15);
11154 MD5STEP(F4, b, c, d, a, in[5] + 0xfc93a039, 21);
11155 MD5STEP(F4, a, b, c, d, in[12] + 0x655b59c3, 6);
11156 MD5STEP(F4, d, a, b, c, in[3] + 0x8f0ccc92, 10);
11157 MD5STEP(F4, c, d, a, b, in[10] + 0xffeff47d, 15);
11158 MD5STEP(F4, b, c, d, a, in[1] + 0x85845dd1, 21);
11159 MD5STEP(F4, a, b, c, d, in[8] + 0x6fa87e4f, 6);
11160 MD5STEP(F4, d, a, b, c, in[15] + 0xfe2ce6e0, 10);
11161 MD5STEP(F4, c, d, a, b, in[6] + 0xa3014314, 15);
11162 MD5STEP(F4, b, c, d, a, in[13] + 0x4e0811a1, 21);
11163 MD5STEP(F4, a, b, c, d, in[4] + 0xf7537e82, 6);
11164 MD5STEP(F4, d, a, b, c, in[11] + 0xbd3af235, 10);
11165 MD5STEP(F4, c, d, a, b, in[2] + 0x2ad7d2bb, 15);
11166 MD5STEP(F4, b, c, d, a, in[9] + 0xeb86d391, 21);
11167
11168 buf[0] += a;
11169 buf[1] += b;
11170 buf[2] += c;
11171 buf[3] += d;
11172}
11173
11174void cs_md5_update(cs_md5_ctx *ctx, const unsigned char *buf, size_t len) {
11175 uint32_t t;
11176
11177 t = ctx->bits[0];
11178 if ((ctx->bits[0] = t + ((uint32_t) len << 3)) < t) ctx->bits[1]++;
11179 ctx->bits[1] += (uint32_t) len >> 29;
11180
11181 t = (t >> 3) & 0x3f;
11182
11183 if (t) {
11184 unsigned char *p = (unsigned char *) ctx->in + t;
11185
11186 t = 64 - t;
11187 if (len < t) {
11188 memcpy(p, buf, len);
11189 return;
11190 }
11191 memcpy(p, buf, t);
11192 byteReverse(ctx->in, 16);
11193 cs_md5_transform(ctx->buf, (uint32_t *) ctx->in);
11194 buf += t;
11195 len -= t;
11196 }
11197
11198 while (len >= 64) {
11199 memcpy(ctx->in, buf, 64);
11200 byteReverse(ctx->in, 16);
11201 cs_md5_transform(ctx->buf, (uint32_t *) ctx->in);
11202 buf += 64;
11203 len -= 64;
11204 }
11205
11206 memcpy(ctx->in, buf, len);
11207}
11208
11209void cs_md5_final(unsigned char digest[16], cs_md5_ctx *ctx) {
11210 unsigned count;
11211 unsigned char *p;
11212 uint32_t *a;
11213
11214 count = (ctx->bits[0] >> 3) & 0x3F;
11215
11216 p = ctx->in + count;
11217 *p++ = 0x80;
11218 count = 64 - 1 - count;
11219 if (count < 8) {
11220 memset(p, 0, count);
11221 byteReverse(ctx->in, 16);
11222 cs_md5_transform(ctx->buf, (uint32_t *) ctx->in);
11223 memset(ctx->in, 0, 56);
11224 } else {
11225 memset(p, 0, count - 8);
11226 }
11227 byteReverse(ctx->in, 14);
11228
11229 a = (uint32_t *) ctx->in;
11230 a[14] = ctx->bits[0];
11231 a[15] = ctx->bits[1];
11232
11233 cs_md5_transform(ctx->buf, (uint32_t *) ctx->in);
11234 byteReverse((unsigned char *) ctx->buf, 4);
11235 memcpy(digest, ctx->buf, 16);
11236 memset((char *) ctx, 0, sizeof(*ctx));
11237}
11238
11239#endif /* CS_DISABLE_MD5 */
11240#endif /* EXCLUDE_COMMON */
11241#ifdef V7_MODULE_LINES
11242#line 1 "common/cs_sha1.c"
11243#endif
11244/* Copyright(c) By Steve Reid <steve@edmweb.com> */
11245/* 100% Public Domain */
11246
11247/* Amalgamated: #include "common/cs_sha1.h" */
11248
11249#if !CS_DISABLE_SHA1 && !defined(EXCLUDE_COMMON)
11250
11251/* Amalgamated: #include "common/cs_endian.h" */
11252
11253#define SHA1HANDSOFF
11254#if defined(__sun)
11255/* Amalgamated: #include "common/solarisfixes.h" */
11256#endif
11257
11258union char64long16 {
11259 unsigned char c[64];
11260 uint32_t l[16];
11261};
11262
11263#define rol(value, bits) (((value) << (bits)) | ((value) >> (32 - (bits))))
11264
11265static uint32_t blk0(union char64long16 *block, int i) {
11266/* Forrest: SHA expect BIG_ENDIAN, swap if LITTLE_ENDIAN */
11267#if BYTE_ORDER == LITTLE_ENDIAN
11268 block->l[i] =
11269 (rol(block->l[i], 24) & 0xFF00FF00) | (rol(block->l[i], 8) & 0x00FF00FF);
11270#endif
11271 return block->l[i];
11272}
11273
11274/* Avoid redefine warning (ARM /usr/include/sys/ucontext.h define R0~R4) */
11275#undef blk
11276#undef R0
11277#undef R1
11278#undef R2
11279#undef R3
11280#undef R4
11281
11282#define blk(i) \
11283 (block->l[i & 15] = rol(block->l[(i + 13) & 15] ^ block->l[(i + 8) & 15] ^ \
11284 block->l[(i + 2) & 15] ^ block->l[i & 15], \
11285 1))
11286#define R0(v, w, x, y, z, i) \
11287 z += ((w & (x ^ y)) ^ y) + blk0(block, i) + 0x5A827999 + rol(v, 5); \
11288 w = rol(w, 30);
11289#define R1(v, w, x, y, z, i) \
11290 z += ((w & (x ^ y)) ^ y) + blk(i) + 0x5A827999 + rol(v, 5); \
11291 w = rol(w, 30);
11292#define R2(v, w, x, y, z, i) \
11293 z += (w ^ x ^ y) + blk(i) + 0x6ED9EBA1 + rol(v, 5); \
11294 w = rol(w, 30);
11295#define R3(v, w, x, y, z, i) \
11296 z += (((w | x) & y) | (w & x)) + blk(i) + 0x8F1BBCDC + rol(v, 5); \
11297 w = rol(w, 30);
11298#define R4(v, w, x, y, z, i) \
11299 z += (w ^ x ^ y) + blk(i) + 0xCA62C1D6 + rol(v, 5); \
11300 w = rol(w, 30);
11301
11302void cs_sha1_transform(uint32_t state[5], const unsigned char buffer[64]) {
11303 uint32_t a, b, c, d, e;
11304 union char64long16 block[1];
11305
11306 memcpy(block, buffer, 64);
11307 a = state[0];
11308 b = state[1];
11309 c = state[2];
11310 d = state[3];
11311 e = state[4];
11312 R0(a, b, c, d, e, 0);
11313 R0(e, a, b, c, d, 1);
11314 R0(d, e, a, b, c, 2);
11315 R0(c, d, e, a, b, 3);
11316 R0(b, c, d, e, a, 4);
11317 R0(a, b, c, d, e, 5);
11318 R0(e, a, b, c, d, 6);
11319 R0(d, e, a, b, c, 7);
11320 R0(c, d, e, a, b, 8);
11321 R0(b, c, d, e, a, 9);
11322 R0(a, b, c, d, e, 10);
11323 R0(e, a, b, c, d, 11);
11324 R0(d, e, a, b, c, 12);
11325 R0(c, d, e, a, b, 13);
11326 R0(b, c, d, e, a, 14);
11327 R0(a, b, c, d, e, 15);
11328 R1(e, a, b, c, d, 16);
11329 R1(d, e, a, b, c, 17);
11330 R1(c, d, e, a, b, 18);
11331 R1(b, c, d, e, a, 19);
11332 R2(a, b, c, d, e, 20);
11333 R2(e, a, b, c, d, 21);
11334 R2(d, e, a, b, c, 22);
11335 R2(c, d, e, a, b, 23);
11336 R2(b, c, d, e, a, 24);
11337 R2(a, b, c, d, e, 25);
11338 R2(e, a, b, c, d, 26);
11339 R2(d, e, a, b, c, 27);
11340 R2(c, d, e, a, b, 28);
11341 R2(b, c, d, e, a, 29);
11342 R2(a, b, c, d, e, 30);
11343 R2(e, a, b, c, d, 31);
11344 R2(d, e, a, b, c, 32);
11345 R2(c, d, e, a, b, 33);
11346 R2(b, c, d, e, a, 34);
11347 R2(a, b, c, d, e, 35);
11348 R2(e, a, b, c, d, 36);
11349 R2(d, e, a, b, c, 37);
11350 R2(c, d, e, a, b, 38);
11351 R2(b, c, d, e, a, 39);
11352 R3(a, b, c, d, e, 40);
11353 R3(e, a, b, c, d, 41);
11354 R3(d, e, a, b, c, 42);
11355 R3(c, d, e, a, b, 43);
11356 R3(b, c, d, e, a, 44);
11357 R3(a, b, c, d, e, 45);
11358 R3(e, a, b, c, d, 46);
11359 R3(d, e, a, b, c, 47);
11360 R3(c, d, e, a, b, 48);
11361 R3(b, c, d, e, a, 49);
11362 R3(a, b, c, d, e, 50);
11363 R3(e, a, b, c, d, 51);
11364 R3(d, e, a, b, c, 52);
11365 R3(c, d, e, a, b, 53);
11366 R3(b, c, d, e, a, 54);
11367 R3(a, b, c, d, e, 55);
11368 R3(e, a, b, c, d, 56);
11369 R3(d, e, a, b, c, 57);
11370 R3(c, d, e, a, b, 58);
11371 R3(b, c, d, e, a, 59);
11372 R4(a, b, c, d, e, 60);
11373 R4(e, a, b, c, d, 61);
11374 R4(d, e, a, b, c, 62);
11375 R4(c, d, e, a, b, 63);
11376 R4(b, c, d, e, a, 64);
11377 R4(a, b, c, d, e, 65);
11378 R4(e, a, b, c, d, 66);
11379 R4(d, e, a, b, c, 67);
11380 R4(c, d, e, a, b, 68);
11381 R4(b, c, d, e, a, 69);
11382 R4(a, b, c, d, e, 70);
11383 R4(e, a, b, c, d, 71);
11384 R4(d, e, a, b, c, 72);
11385 R4(c, d, e, a, b, 73);
11386 R4(b, c, d, e, a, 74);
11387 R4(a, b, c, d, e, 75);
11388 R4(e, a, b, c, d, 76);
11389 R4(d, e, a, b, c, 77);
11390 R4(c, d, e, a, b, 78);
11391 R4(b, c, d, e, a, 79);
11392 state[0] += a;
11393 state[1] += b;
11394 state[2] += c;
11395 state[3] += d;
11396 state[4] += e;
11397 /* Erase working structures. The order of operations is important,
11398 * used to ensure that compiler doesn't optimize those out. */
11399 memset(block, 0, sizeof(block));
11400 a = b = c = d = e = 0;
11401 (void) a;
11402 (void) b;
11403 (void) c;
11404 (void) d;
11405 (void) e;
11406}
11407
11408void cs_sha1_init(cs_sha1_ctx *context) {
11409 context->state[0] = 0x67452301;
11410 context->state[1] = 0xEFCDAB89;
11411 context->state[2] = 0x98BADCFE;
11412 context->state[3] = 0x10325476;
11413 context->state[4] = 0xC3D2E1F0;
11414 context->count[0] = context->count[1] = 0;
11415}
11416
11417void cs_sha1_update(cs_sha1_ctx *context, const unsigned char *data,
11418 uint32_t len) {
11419 uint32_t i, j;
11420
11421 j = context->count[0];
11422 if ((context->count[0] += len << 3) < j) context->count[1]++;
11423 context->count[1] += (len >> 29);
11424 j = (j >> 3) & 63;
11425 if ((j + len) > 63) {
11426 memcpy(&context->buffer[j], data, (i = 64 - j));
11427 cs_sha1_transform(context->state, context->buffer);
11428 for (; i + 63 < len; i += 64) {
11429 cs_sha1_transform(context->state, &data[i]);
11430 }
11431 j = 0;
11432 } else
11433 i = 0;
11434 memcpy(&context->buffer[j], &data[i], len - i);
11435}
11436
11437void cs_sha1_final(unsigned char digest[20], cs_sha1_ctx *context) {
11438 unsigned i;
11439 unsigned char finalcount[8], c;
11440
11441 for (i = 0; i < 8; i++) {
11442 finalcount[i] = (unsigned char) ((context->count[(i >= 4 ? 0 : 1)] >>
11443 ((3 - (i & 3)) * 8)) &
11444 255);
11445 }
11446 c = 0200;
11447 cs_sha1_update(context, &c, 1);
11448 while ((context->count[0] & 504) != 448) {
11449 c = 0000;
11450 cs_sha1_update(context, &c, 1);
11451 }
11452 cs_sha1_update(context, finalcount, 8);
11453 for (i = 0; i < 20; i++) {
11454 digest[i] =
11455 (unsigned char) ((context->state[i >> 2] >> ((3 - (i & 3)) * 8)) & 255);
11456 }
11457 memset(context, '\0', sizeof(*context));
11458 memset(&finalcount, '\0', sizeof(finalcount));
11459}
11460
11461void cs_hmac_sha1(const unsigned char *key, size_t keylen,
11462 const unsigned char *data, size_t datalen,
11463 unsigned char out[20]) {
11464 cs_sha1_ctx ctx;
11465 unsigned char buf1[64], buf2[64], tmp_key[20], i;
11466
11467 if (keylen > sizeof(buf1)) {
11468 cs_sha1_init(&ctx);
11469 cs_sha1_update(&ctx, key, keylen);
11470 cs_sha1_final(tmp_key, &ctx);
11471 key = tmp_key;
11472 keylen = sizeof(tmp_key);
11473 }
11474
11475 memset(buf1, 0, sizeof(buf1));
11476 memset(buf2, 0, sizeof(buf2));
11477 memcpy(buf1, key, keylen);
11478 memcpy(buf2, key, keylen);
11479
11480 for (i = 0; i < sizeof(buf1); i++) {
11481 buf1[i] ^= 0x36;
11482 buf2[i] ^= 0x5c;
11483 }
11484
11485 cs_sha1_init(&ctx);
11486 cs_sha1_update(&ctx, buf1, sizeof(buf1));
11487 cs_sha1_update(&ctx, data, datalen);
11488 cs_sha1_final(out, &ctx);
11489
11490 cs_sha1_init(&ctx);
11491 cs_sha1_update(&ctx, buf2, sizeof(buf2));
11492 cs_sha1_update(&ctx, out, 20);
11493 cs_sha1_final(out, &ctx);
11494}
11495
11496#endif /* EXCLUDE_COMMON */
11497#ifdef V7_MODULE_LINES
11498#line 1 "common/cs_dirent.c"
11499#endif
11500/*
11501 * Copyright (c) 2015 Cesanta Software Limited
11502 * All rights reserved
11503 */
11504
11505#ifndef EXCLUDE_COMMON
11506
11507/* Amalgamated: #include "common/mg_mem.h" */
11508/* Amalgamated: #include "common/cs_dirent.h" */
11509
11510/*
11511 * This file contains POSIX opendir/closedir/readdir API implementation
11512 * for systems which do not natively support it (e.g. Windows).
11513 */
11514
11515#ifdef _WIN32
11516struct win32_dir {
11517 DIR d;
11518 HANDLE handle;
11519 WIN32_FIND_DATAW info;
11520 struct dirent result;
11521};
11522
11523DIR *opendir(const char *name) {
11524 struct win32_dir *dir = NULL;
11525 wchar_t wpath[MAX_PATH];
11526 DWORD attrs;
11527
11528 if (name == NULL) {
11529 SetLastError(ERROR_BAD_ARGUMENTS);
11530 } else if ((dir = (struct win32_dir *) MG_MALLOC(sizeof(*dir))) == NULL) {
11531 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
11532 } else {
11533 to_wchar(name, wpath, ARRAY_SIZE(wpath));
11534 attrs = GetFileAttributesW(wpath);
11535 if (attrs != 0xFFFFFFFF && (attrs & FILE_ATTRIBUTE_DIRECTORY)) {
11536 (void) wcscat(wpath, L"\\*");
11537 dir->handle = FindFirstFileW(wpath, &dir->info);
11538 dir->result.d_name[0] = '\0';
11539 } else {
11540 MG_FREE(dir);
11541 dir = NULL;
11542 }
11543 }
11544
11545 return (DIR *) dir;
11546}
11547
11548int closedir(DIR *d) {
11549 struct win32_dir *dir = (struct win32_dir *) d;
11550 int result = 0;
11551
11552 if (dir != NULL) {
11553 if (dir->handle != INVALID_HANDLE_VALUE)
11554 result = FindClose(dir->handle) ? 0 : -1;
11555 MG_FREE(dir);
11556 } else {
11557 result = -1;
11558 SetLastError(ERROR_BAD_ARGUMENTS);
11559 }
11560
11561 return result;
11562}
11563
11564struct dirent *readdir(DIR *d) {
11565 struct win32_dir *dir = (struct win32_dir *) d;
11566 struct dirent *result = NULL;
11567
11568 if (dir) {
11569 memset(&dir->result, 0, sizeof(dir->result));
11570 if (dir->handle != INVALID_HANDLE_VALUE) {
11571 result = &dir->result;
11572 (void) WideCharToMultiByte(CP_UTF8, 0, dir->info.cFileName, -1,
11573 result->d_name, sizeof(result->d_name), NULL,
11574 NULL);
11575
11576 if (!FindNextFileW(dir->handle, &dir->info)) {
11577 (void) FindClose(dir->handle);
11578 dir->handle = INVALID_HANDLE_VALUE;
11579 }
11580
11581 } else {
11582 SetLastError(ERROR_FILE_NOT_FOUND);
11583 }
11584 } else {
11585 SetLastError(ERROR_BAD_ARGUMENTS);
11586 }
11587
11588 return result;
11589}
11590#endif
11591
11592#endif /* EXCLUDE_COMMON */
11593
11594/* ISO C requires a translation unit to contain at least one declaration */
11595typedef int cs_dirent_dummy;
11596#ifdef V7_MODULE_LINES
11597#line 1 "common/cs_file.c"
11598#endif
11599/*
11600 * Copyright (c) 2015 Cesanta Software Limited
11601 * All rights reserved
11602 */
11603
11604/* Amalgamated: #include "common/cs_file.h" */
11605
11606#include <stdio.h>
11607#include <stdlib.h>
11608
11609#ifdef CS_MMAP
11610#include <fcntl.h>
11611#include <sys/mman.h>
11612#include <sys/stat.h>
11613#endif
11614
11615#ifndef EXCLUDE_COMMON
11616char *cs_read_file(const char *path, size_t *size) WEAK;
11617char *cs_read_file(const char *path, size_t *size) {
11618 FILE *fp;
11619 char *data = NULL;
11620 if ((fp = fopen(path, "rb")) == NULL) {
11621 } else if (fseek(fp, 0, SEEK_END) != 0) {
11622 fclose(fp);
11623 } else {
11624 *size = ftell(fp);
11625 data = (char *) malloc(*size + 1);
11626 if (data != NULL) {
11627 fseek(fp, 0, SEEK_SET); /* Some platforms might not have rewind(), Oo */
11628 if (fread(data, 1, *size, fp) != *size) {
11629 free(data);
11630 return NULL;
11631 }
11632 data[*size] = '\0';
11633 }
11634 fclose(fp);
11635 }
11636 return data;
11637}
11638#endif /* EXCLUDE_COMMON */
11639
11640#ifdef CS_MMAP
11641char *cs_mmap_file(const char *path, size_t *size) WEAK;
11642char *cs_mmap_file(const char *path, size_t *size) {
11643 char *r;
11644 int fd = open(path, O_RDONLY, 0);
11645 struct stat st;
11646 if (fd < 0) return NULL;
11647 fstat(fd, &st);
11648 *size = (size_t) st.st_size;
11649 r = (char *) mmap(NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
11650 if (r == MAP_FAILED) return NULL;
11651 return r;
11652}
11653#endif
11654#ifdef V7_MODULE_LINES
11655#line 1 "common/cs_heap_trace.c"
11656#endif
11657/*
11658 * Copyright (c) 2014-2016 Cesanta Software Limited
11659 * All rights reserved
11660 */
11661
11662#include <stdint.h>
11663#include <stdio.h>
11664
11665#ifndef MGOS_ENABLE_CALL_TRACE
11666#define MGOS_ENABLE_CALL_TRACE 0
11667#endif
11668
11669#ifndef V7_ENABLE_CALL_TRACE
11670#define V7_ENABLE_CALL_TRACE 0
11671#endif
11672
11673#if MGOS_ENABLE_CALL_TRACE || V7_ENABLE_CALL_TRACE
11674/*
11675 * If we don't have V7's profiling functions, roll our own.
11676 * This is copy-pasta from v7/src/cyg_profile.c
11677 */
11678
11679#ifndef CALL_TRACE_SIZE
11680#define CALL_TRACE_SIZE 32
11681#endif
11682
11683typedef struct {
11684 void *addresses[CALL_TRACE_SIZE];
11685 uint16_t size;
11686} call_trace_t;
11687
11688static call_trace_t call_trace;
11689
11690#if MGOS_ENABLE_CALL_TRACE
11691void esp_exc_printf(const char *fmt, ...);
11692#define call_trace_printf esp_exc_printf
11693#else
11694#define call_trace_printf printf
11695#endif
11696
11697NOINSTR void print_call_trace() {
11698 static void *prev_trace[CALL_TRACE_SIZE];
11699 unsigned int size = call_trace.size;
11700 if (size > CALL_TRACE_SIZE) size = CALL_TRACE_SIZE;
11701 unsigned int i;
11702 uintptr_t pa = 0;
11703 for (i = 0; i < size; i++) {
11704 if (call_trace.addresses[i] != prev_trace[i]) break;
11705 pa = (uintptr_t) call_trace.addresses[i];
11706 }
11707 call_trace_printf("%u %u", size, i);
11708 for (; i < size; i++) {
11709 const uintptr_t a = (uintptr_t) call_trace.addresses[i];
11710 /*
11711 * Perform a rudimentary deduplication: an address is likely to have higher
11712 * bits the same as previous, turn them off.
11713 * Do it in 4-bit nibbles so they fall nicely on hex digit boundary.
11714 */
11715 uintptr_t mask = ~((uintptr_t) 0);
11716 while (mask != 0 && (a & mask) != (pa & mask)) mask <<= 4;
11717 call_trace_printf(" %lx", (unsigned long) (a & ~mask));
11718 prev_trace[i] = (void *) a;
11719 pa = a;
11720 }
11721 call_trace_printf("\n");
11722}
11723
11724#if MGOS_ENABLE_CALL_TRACE && !V7_ENABLE_CALL_TRACE
11725IRAM NOINSTR void __cyg_profile_func_enter(void *this_fn, void *call_site) {
11726 if (call_trace.size < CALL_TRACE_SIZE) {
11727 call_trace.addresses[call_trace.size] = this_fn;
11728 }
11729 call_trace.size++;
11730 (void) this_fn;
11731 (void) call_site;
11732}
11733
11734IRAM NOINSTR void __cyg_profile_func_exit(void *this_fn, void *call_site) {
11735 if (call_trace.size > 0) call_trace.size--;
11736 (void) this_fn;
11737 (void) call_site;
11738}
11739#endif
11740
11741#endif /* MGOS_ENABLE_CALL_TRACE || V7_ENABLE_CALL_TRACE */
11742#ifdef V7_MODULE_LINES
11743#line 1 "common/cs_strtod.c"
11744#endif
11745#include <ctype.h>
11746#include <math.h>
11747
11748#include <stdlib.h>
11749
11750int cs_strncasecmp(const char *s1, const char *s2, size_t n) {
11751 if (n == 0) {
11752 return 0;
11753 }
11754
11755 while (n-- != 0 && tolower((int) *s1) == tolower((int) *s2)) {
11756 if (n == 0 || *s1 == '\0' || *s2 == '\0') {
11757 break;
11758 }
11759 s1++;
11760 s2++;
11761 }
11762
11763 return tolower(*(unsigned char *) s1) - tolower(*(unsigned char *) s2);
11764}
11765
11766/*
11767 * based on Source:
11768 * https://github.com/anakod/Sming/blob/master/Sming/system/stringconversion.cpp#L93
11769 */
11770
11771double cs_strtod(const char *str, char **endptr) {
11772 double result = 0.0;
11773 char c;
11774 const char *str_start;
11775 struct {
11776 unsigned neg : 1; /* result is negative */
11777 unsigned decimals : 1; /* parsing decimal part */
11778 unsigned is_exp : 1; /* parsing exponent like e+5 */
11779 unsigned is_exp_neg : 1; /* exponent is negative */
11780 } flags = {0, 0, 0, 0};
11781
11782 while (isspace((int) *str)) {
11783 str++;
11784 }
11785
11786 if (*str == 0) {
11787 /* only space in str? */
11788 if (endptr != 0) *endptr = (char *) str;
11789 return result;
11790 }
11791
11792 /* Handle leading plus/minus signs */
11793 while (*str == '-' || *str == '+') {
11794 if (*str == '-') {
11795 flags.neg = !flags.neg;
11796 }
11797 str++;
11798 }
11799
11800 if (cs_strncasecmp(str, "NaN", 3) == 0) {
11801 if (endptr != 0) *endptr = (char *) str + 3;
11802 return NAN;
11803 }
11804
11805 if (cs_strncasecmp(str, "INF", 3) == 0) {
11806 str += 3;
11807 if (cs_strncasecmp(str, "INITY", 5) == 0) str += 5;
11808 if (endptr != 0) *endptr = (char *) str;
11809 return flags.neg ? -INFINITY : INFINITY;
11810 }
11811
11812 str_start = str;
11813
11814 if (*str == '0' && (*(str + 1) == 'x' || *(str + 1) == 'X')) {
11815 /* base 16 */
11816 str += 2;
11817 while ((c = tolower((int) *str))) {
11818 int d;
11819 if (c >= '0' && c <= '9') {
11820 d = c - '0';
11821 } else if (c >= 'a' && c <= 'f') {
11822 d = 10 + (c - 'a');
11823 } else {
11824 break;
11825 }
11826 result = 16 * result + d;
11827 str++;
11828 }
11829 } else if (*str == '0' && (*(str + 1) == 'b' || *(str + 1) == 'B')) {
11830 /* base 2 */
11831 str += 2;
11832 while ((c = *str)) {
11833 int d = c - '0';
11834 if (c != '0' && c != '1') break;
11835 result = 2 * result + d;
11836 str++;
11837 }
11838 } else if (*str == '0' && *(str + 1) >= '0' && *(str + 1) <= '7') {
11839 /* base 8 */
11840 while ((c = *str)) {
11841 int d = c - '0';
11842 if (c < '0' || c > '7') {
11843 /* fallback to base 10 */
11844 str = str_start;
11845 break;
11846 }
11847 result = 8 * result + d;
11848 str++;
11849 }
11850 }
11851
11852 if (str == str_start) {
11853 /* base 10 */
11854
11855 /* exponent specified explicitly, like in 3e-5, exponent is -5 */
11856 int exp = 0;
11857 /* exponent calculated from dot, like in 1.23, exponent is -2 */
11858 int exp_dot = 0;
11859
11860 result = 0;
11861
11862 while ((c = *str)) {
11863 int d;
11864
11865 if (c == '.') {
11866 if (!flags.decimals) {
11867 /* going to parse decimal part */
11868 flags.decimals = 1;
11869 str++;
11870 continue;
11871 } else {
11872 /* non-expected dot: assume number data is over */
11873 break;
11874 }
11875 } else if (c == 'e' || c == 'E') {
11876 /* going to parse exponent part */
11877 flags.is_exp = 1;
11878 str++;
11879 c = *str;
11880
11881 /* check sign of the exponent */
11882 if (c == '-' || c == '+') {
11883 if (c == '-') {
11884 flags.is_exp_neg = 1;
11885 }
11886 str++;
11887 }
11888
11889 continue;
11890 }
11891
11892 d = c - '0';
11893 if (d < 0 || d > 9) {
11894 break;
11895 }
11896
11897 if (!flags.is_exp) {
11898 /* apply current digit to the result */
11899 result = 10 * result + d;
11900 if (flags.decimals) {
11901 exp_dot--;
11902 }
11903 } else {
11904 /* apply current digit to the exponent */
11905 if (flags.is_exp_neg) {
11906 if (exp > -1022) {
11907 exp = 10 * exp - d;
11908 }
11909 } else {
11910 if (exp < 1023) {
11911 exp = 10 * exp + d;
11912 }
11913 }
11914 }
11915
11916 str++;
11917 }
11918
11919 exp += exp_dot;
11920
11921 /*
11922 * TODO(dfrank): it probably makes sense not to adjust intermediate `double
11923 * result`, but build double number accordingly to IEEE 754 from taken
11924 * (integer) mantissa, exponent and sign. That would work faster, and we
11925 * can avoid any possible round errors.
11926 */
11927
11928 /* if exponent is non-zero, apply it */
11929 if (exp != 0) {
11930 if (exp < 0) {
11931 while (exp++ != 0) {
11932 result /= 10;
11933 }
11934 } else {
11935 while (exp-- != 0) {
11936 result *= 10;
11937 }
11938 }
11939 }
11940 }
11941
11942 if (flags.neg) {
11943 result = -result;
11944 }
11945
11946 if (endptr != 0) {
11947 *endptr = (char *) str;
11948 }
11949
11950 return result;
11951}
11952#ifdef V7_MODULE_LINES
11953#line 1 "common/coroutine.c"
11954#endif
11955/*
11956 * Copyright (c) 2015 Cesanta Software Limited
11957 * All rights reserved
11958 */
11959
11960/*
11961 * Module that provides generic macros and functions to implement "coroutines",
11962 * i.e. C code that uses `mbuf` as a stack for function calls.
11963 *
11964 * More info: see the design doc: https://goo.gl/kfcG61
11965 */
11966
11967#include <string.h>
11968#include <stdlib.h>
11969
11970/* Amalgamated: #include "common/coroutine.h" */
11971
11972/*
11973 * Unwinds stack by 1 function. Used when we're returning from function and
11974 * when an exception is thrown.
11975 */
11976static void _level_up(struct cr_ctx *p_ctx) {
11977 /* get size of current function's stack data */
11978 size_t locals_size = _CR_CURR_FUNC_LOCALS_SIZE(p_ctx);
11979
11980 /* check stacks underflow */
11981 if (_CR_STACK_FID_UND_CHECK(p_ctx, 1 /*fid*/)) {
11982 p_ctx->status = CR_RES__ERR_STACK_CALL_UNDERFLOW;
11983 return;
11984 } else if (_CR_STACK_DATA_UND_CHECK(p_ctx, locals_size)) {
11985 p_ctx->status = CR_RES__ERR_STACK_DATA_UNDERFLOW;
11986 return;
11987 }
11988
11989 /* decrement stacks */
11990 _CR_STACK_DATA_FREE(p_ctx, locals_size);
11991 _CR_STACK_FID_FREE(p_ctx, 1 /*fid*/);
11992 p_ctx->stack_ret.len = p_ctx->cur_fid_idx;
11993
11994 /* if we have exception marker here, adjust cur_fid_idx */
11995 while (CR_CURR_FUNC_C(p_ctx) == CR_FID__TRY_MARKER) {
11996 /* check for stack underflow */
11997 if (_CR_STACK_FID_UND_CHECK(p_ctx, _CR_TRY_SIZE)) {
11998 p_ctx->status = CR_RES__ERR_STACK_CALL_UNDERFLOW;
11999 return;
12000 }
12001 _CR_STACK_FID_FREE(p_ctx, _CR_TRY_SIZE);
12002 }
12003}
12004
12005enum cr_status cr_on_iter_begin(struct cr_ctx *p_ctx) {
12006 if (p_ctx->status != CR_RES__OK) {
12007 goto out;
12008 } else if (p_ctx->called_fid != CR_FID__NONE) {
12009 /* need to call new function */
12010
12011 size_t locals_size = p_ctx->p_func_descrs[p_ctx->called_fid].locals_size;
12012 /*
12013 * increment stack pointers
12014 */
12015 /* make sure this function has correct `struct cr_func_desc` entry */
12016 assert(locals_size == p_ctx->call_locals_size);
12017 /*
12018 * make sure we haven't mistakenly included "zero-sized" `.._arg_t`
12019 * structure in `.._locals_t` struct
12020 *
12021 * By "zero-sized" I mean `cr_zero_size_type_t`.
12022 */
12023 assert(locals_size < sizeof(cr_zero_size_type_t));
12024
12025 _CR_STACK_DATA_ALLOC(p_ctx, locals_size);
12026 _CR_STACK_RET_ALLOC(p_ctx, 1 /*fid*/);
12027 p_ctx->cur_fid_idx = p_ctx->stack_ret.len;
12028
12029 /* copy arguments to our "stack" (and advance locals stack pointer) */
12030 memcpy(p_ctx->stack_data.buf + p_ctx->stack_data.len - locals_size,
12031 p_ctx->p_arg_retval, p_ctx->call_arg_size);
12032
12033 /* set function id */
12034 CR_CURR_FUNC_C(p_ctx) = p_ctx->called_fid;
12035
12036 /* clear called_fid */
12037 p_ctx->called_fid = CR_FID__NONE;
12038
12039 } else if (p_ctx->need_return) {
12040 /* need to return from the currently running function */
12041
12042 _level_up(p_ctx);
12043 if (p_ctx->status != CR_RES__OK) {
12044 goto out;
12045 }
12046
12047 p_ctx->need_return = 0;
12048
12049 } else if (p_ctx->need_yield) {
12050 /* need to yield */
12051
12052 p_ctx->need_yield = 0;
12053 p_ctx->status = CR_RES__OK_YIELDED;
12054 goto out;
12055
12056 } else if (p_ctx->thrown_exc != CR_EXC_ID__NONE) {
12057 /* exception was thrown */
12058
12059 /* unwind stack until we reach the bottom, or find some try-catch blocks */
12060 do {
12061 _level_up(p_ctx);
12062 if (p_ctx->status != CR_RES__OK) {
12063 goto out;
12064 }
12065
12066 if (_CR_TRY_MARKER(p_ctx) == CR_FID__TRY_MARKER) {
12067 /* we have some try-catch here, go to the first catch */
12068 CR_CURR_FUNC_C(p_ctx) = _CR_TRY_CATCH_FID(p_ctx);
12069 break;
12070 } else if (CR_CURR_FUNC_C(p_ctx) == CR_FID__NONE) {
12071 /* we've reached the bottom of the stack */
12072 p_ctx->status = CR_RES__ERR_UNCAUGHT_EXCEPTION;
12073 break;
12074 }
12075
12076 } while (1);
12077 }
12078
12079 /* remember pointer to current function's locals */
12080 _CR_CUR_FUNC_LOCALS_UPD(p_ctx);
12081
12082out:
12083 return p_ctx->status;
12084}
12085
12086void cr_context_init(struct cr_ctx *p_ctx, union user_arg_ret *p_arg_retval,
12087 size_t arg_retval_size,
12088 const struct cr_func_desc *p_func_descrs) {
12089 /*
12090 * make sure we haven't mistakenly included "zero-sized" `.._arg_t`
12091 * structure in `union user_arg_ret`.
12092 *
12093 * By "zero-sized" I mean `cr_zero_size_type_t`.
12094 */
12095 assert(arg_retval_size < sizeof(cr_zero_size_type_t));
12096#ifdef NDEBUG
12097 (void) arg_retval_size;
12098#endif
12099
12100 memset(p_ctx, 0x00, sizeof(*p_ctx));
12101
12102 p_ctx->p_func_descrs = p_func_descrs;
12103 p_ctx->p_arg_retval = p_arg_retval;
12104
12105 mbuf_init(&p_ctx->stack_data, 0);
12106 mbuf_init(&p_ctx->stack_ret, 0);
12107
12108 mbuf_append(&p_ctx->stack_ret, NULL, 1 /*starting byte for CR_FID__NONE*/);
12109 p_ctx->cur_fid_idx = p_ctx->stack_ret.len;
12110
12111 _CR_CALL_PREPARE(p_ctx, CR_FID__NONE, 0, 0, CR_FID__NONE);
12112}
12113
12114void cr_context_free(struct cr_ctx *p_ctx) {
12115 mbuf_free(&p_ctx->stack_data);
12116 mbuf_free(&p_ctx->stack_ret);
12117}
12118#ifdef V7_MODULE_LINES
12119#line 1 "common/platforms/mbed/mbed_libc.c"
12120#endif
12121/*
12122 * Copyright (c) 2014-2016 Cesanta Software Limited
12123 * All rights reserved
12124 */
12125
12126/* Amalgamated: #include "common/platform.h" */
12127
12128#if CS_PLATFORM == CS_P_MBED
12129
12130long timezone;
12131
12132/*
12133 * The GCC ARM toolchain for implements a weak
12134 * gettimeofday stub that should be implemented
12135 * to hook the OS time source. But mbed OS doesn't do it;
12136 * the mbed doc only talks about C date and time functions:
12137 *
12138 * https://docs.mbed.com/docs/mbed-os-api-reference/en/5.1/APIs/tasks/Time/
12139 *
12140 * gettimeof day is a BSD API.
12141 */
12142int _gettimeofday(struct timeval *tv, void *tzvp) {
12143 tv->tv_sec = time(NULL);
12144 tv->tv_usec = 0;
12145 return 0;
12146}
12147
12148int inet_aton(const char *cp, struct in_addr *inp) {
12149 /* We don't have aton, but have pton in mbed */
12150 return inet_pton(AF_INET, cp, inp);
12151}
12152
12153in_addr_t inet_addr(const char *cp) {
12154 in_addr_t ret;
12155 if (inet_pton(AF_INET, cp, &ret) != 1) {
12156 return 0;
12157 }
12158
12159 return ret;
12160}
12161
12162#endif /* CS_PLATFORM == CS_P_MBED */
12163#ifdef V7_MODULE_LINES
12164#line 1 "v7/builtin/file.c"
12165#endif
12166/*
12167 * Copyright (c) 2014 Cesanta Software Limited
12168 * All rights reserved
12169 */
12170
12171/* Amalgamated: #include "v7/src/internal.h" */
12172/* Amalgamated: #include "v7/src/core.h" */
12173/* Amalgamated: #include "v7/src/primitive.h" */
12174/* Amalgamated: #include "v7/src/string.h" */
12175/* Amalgamated: #include "v7/src/exceptions.h" */
12176/* Amalgamated: #include "v7/src/object.h" */
12177/* Amalgamated: #include "v7/src/exec.h" */
12178/* Amalgamated: #include "v7/src/array.h" */
12179/* Amalgamated: #include "common/mbuf.h" */
12180/* Amalgamated: #include "common/cs_file.h" */
12181/* Amalgamated: #include "v7/src/v7_features.h" */
12182/* Amalgamated: #include "common/cs_dirent.h" */
12183
12184#if V7_ENABLE_FILE && !defined(V7_NO_FS)
12185
12186static const char s_fd_prop[] = "__fd";
12187
12188#ifndef NO_LIBC
12189static FILE *v7_val_to_file(struct v7 *v7, v7_val_t val) {
12190 (void) v7;
12191 return (FILE *) v7_get_ptr(v7, val);
12192}
12193
12194static v7_val_t v7_file_to_val(struct v7 *v7, FILE *file) {
12195 (void) v7;
12196 return v7_mk_foreign(v7, file);
12197}
12198
12199static int v7_is_file_type(v7_val_t val) {
12200 return v7_is_foreign(val);
12201}
12202#else
12203FILE *v7_val_to_file(struct v7 *v7, v7_val_t val);
12204v7_val_t v7_file_to_val(struct v7 *v7, FILE *file);
12205int v7_is_file_type(v7_val_t val);
12206#endif
12207
12208WARN_UNUSED_RESULT
12209V7_PRIVATE enum v7_err File_eval(struct v7 *v7, v7_val_t *res) {
12210 enum v7_err rcode = V7_OK;
12211 v7_val_t arg0 = v7_arg(v7, 0);
12212
12213 *res = V7_UNDEFINED;
12214
12215 if (v7_is_string(arg0)) {
12216 const char *s = v7_get_cstring(v7, &arg0);
12217 if (s == NULL) {
12218 rcode = v7_throwf(v7, "TypeError", "Invalid string");
12219 goto clean;
12220 }
12221
12222 v7_set_gc_enabled(v7, 1);
12223 rcode = v7_exec_file(v7, s, res);
12224 if (rcode != V7_OK) {
12225 goto clean;
12226 }
12227 }
12228
12229clean:
12230 return rcode;
12231}
12232
12233WARN_UNUSED_RESULT
12234V7_PRIVATE enum v7_err File_exists(struct v7 *v7, v7_val_t *res) {
12235 enum v7_err rcode = V7_OK;
12236 v7_val_t arg0 = v7_arg(v7, 0);
12237
12238 *res = v7_mk_boolean(v7, 0);
12239
12240 if (v7_is_string(arg0)) {
12241 const char *fname = v7_get_cstring(v7, &arg0);
12242 if (fname != NULL) {
12243 struct stat st;
12244 if (stat(fname, &st) == 0) *res = v7_mk_boolean(v7, 1);
12245 }
12246 }
12247
12248 return rcode;
12249}
12250
12251WARN_UNUSED_RESULT
12252static enum v7_err f_read(struct v7 *v7, int all, v7_val_t *res) {
12253 enum v7_err rcode = V7_OK;
12254 v7_val_t this_obj = v7_get_this(v7);
12255 v7_val_t arg0 = v7_get(v7, this_obj, s_fd_prop, sizeof(s_fd_prop) - 1);
12256
12257 if (v7_is_file_type(arg0)) {
12258 struct mbuf m;
12259 char buf[BUFSIZ];
12260 int n;
12261 FILE *fp = v7_val_to_file(v7, arg0);
12262
12263 /* Read file contents into mbuf */
12264 mbuf_init(&m, 0);
12265 while ((n = fread(buf, 1, sizeof(buf), fp)) > 0) {
12266 mbuf_append(&m, buf, n);
12267 if (!all) {
12268 break;
12269 }
12270 }
12271
12272 if (m.len > 0) {
12273 *res = v7_mk_string(v7, m.buf, m.len, 1);
12274 mbuf_free(&m);
12275 goto clean;
12276 }
12277 }
12278 *res = v7_mk_string(v7, "", 0, 1);
12279
12280clean:
12281 return rcode;
12282}
12283
12284WARN_UNUSED_RESULT
12285V7_PRIVATE enum v7_err File_obj_read(struct v7 *v7, v7_val_t *res) {
12286 return f_read(v7, 0, res);
12287}
12288
12289WARN_UNUSED_RESULT
12290V7_PRIVATE enum v7_err File_obj_write(struct v7 *v7, v7_val_t *res) {
12291 enum v7_err rcode = V7_OK;
12292 v7_val_t this_obj = v7_get_this(v7);
12293 v7_val_t arg0 = v7_get(v7, this_obj, s_fd_prop, sizeof(s_fd_prop) - 1);
12294 v7_val_t arg1 = v7_arg(v7, 0);
12295 size_t n, sent = 0, len = 0;
12296
12297 if (v7_is_file_type(arg0) && v7_is_string(arg1)) {
12298 const char *s = v7_get_string(v7, &arg1, &len);
12299 FILE *fp = v7_val_to_file(v7, arg0);
12300 while (sent < len && (n = fwrite(s + sent, 1, len - sent, fp)) > 0) {
12301 sent += n;
12302 }
12303 }
12304
12305 *res = v7_mk_number(v7, sent);
12306
12307 return rcode;
12308}
12309
12310WARN_UNUSED_RESULT
12311V7_PRIVATE enum v7_err File_obj_close(struct v7 *v7, v7_val_t *res) {
12312 enum v7_err rcode = V7_OK;
12313 v7_val_t this_obj = v7_get_this(v7);
12314 v7_val_t prop = v7_get(v7, this_obj, s_fd_prop, sizeof(s_fd_prop) - 1);
12315 int ires = -1;
12316
12317 if (v7_is_file_type(prop)) {
12318 ires = fclose(v7_val_to_file(v7, prop));
12319 }
12320
12321 *res = v7_mk_number(v7, ires);
12322
12323 return rcode;
12324}
12325
12326WARN_UNUSED_RESULT
12327V7_PRIVATE enum v7_err File_open(struct v7 *v7, v7_val_t *res) {
12328 enum v7_err rcode = V7_OK;
12329 v7_val_t arg0 = v7_arg(v7, 0);
12330 v7_val_t arg1 = v7_arg(v7, 1);
12331 FILE *fp = NULL;
12332
12333 if (v7_is_string(arg0)) {
12334 const char *s1 = v7_get_cstring(v7, &arg0);
12335 const char *s2 = "rb"; /* Open files in read mode by default */
12336
12337 if (v7_is_string(arg1)) {
12338 s2 = v7_get_cstring(v7, &arg1);
12339 }
12340
12341 if (s1 == NULL || s2 == NULL) {
12342 *res = V7_NULL;
12343 goto clean;
12344 }
12345
12346 fp = fopen(s1, s2);
12347 if (fp != NULL) {
12348 v7_val_t obj = v7_mk_object(v7);
12349 v7_val_t file_proto = v7_get(
12350 v7, v7_get(v7, v7_get_global(v7), "File", ~0), "prototype", ~0);
12351 v7_set_proto(v7, obj, file_proto);
12352 v7_def(v7, obj, s_fd_prop, sizeof(s_fd_prop) - 1, V7_DESC_ENUMERABLE(0),
12353 v7_file_to_val(v7, fp));
12354 *res = obj;
12355 goto clean;
12356 }
12357 }
12358
12359 *res = V7_NULL;
12360
12361clean:
12362 return rcode;
12363}
12364
12365WARN_UNUSED_RESULT
12366V7_PRIVATE enum v7_err File_read(struct v7 *v7, v7_val_t *res) {
12367 v7_val_t arg0 = v7_arg(v7, 0);
12368
12369 if (v7_is_string(arg0)) {
12370 const char *path = v7_get_cstring(v7, &arg0);
12371 size_t size = 0;
12372 char *data = cs_read_file(path, &size);
12373 if (data != NULL) {
12374 *res = v7_mk_string(v7, data, size, 1);
12375 free(data);
12376 }
12377 }
12378
12379 return V7_OK;
12380}
12381
12382WARN_UNUSED_RESULT
12383V7_PRIVATE enum v7_err File_write(struct v7 *v7, v7_val_t *res) {
12384 v7_val_t arg0 = v7_arg(v7, 0);
12385 v7_val_t arg1 = v7_arg(v7, 1);
12386 *res = v7_mk_boolean(v7, 0);
12387
12388 if (v7_is_string(arg0) && v7_is_string(arg1)) {
12389 const char *path = v7_get_cstring(v7, &arg0);
12390 size_t len;
12391 const char *buf = v7_get_string(v7, &arg1, &len);
12392 FILE *fp = fopen(path, "wb+");
12393 if (fp != NULL) {
12394 if (fwrite(buf, 1, len, fp) == len) {
12395 *res = v7_mk_boolean(v7, 1);
12396 }
12397 fclose(fp);
12398 }
12399 }
12400
12401 return V7_OK;
12402}
12403
12404WARN_UNUSED_RESULT
12405V7_PRIVATE enum v7_err File_rename(struct v7 *v7, v7_val_t *res) {
12406 enum v7_err rcode = V7_OK;
12407 v7_val_t arg0 = v7_arg(v7, 0);
12408 v7_val_t arg1 = v7_arg(v7, 1);
12409 int ires = -1;
12410
12411 if (v7_is_string(arg0) && v7_is_string(arg1)) {
12412 const char *from = v7_get_cstring(v7, &arg0);
12413 const char *to = v7_get_cstring(v7, &arg1);
12414 if (from == NULL || to == NULL) {
12415 *res = v7_mk_number(v7, ENOENT);
12416 goto clean;
12417 }
12418
12419 ires = rename(from, to);
12420 }
12421
12422 *res = v7_mk_number(v7, ires == 0 ? 0 : errno);
12423
12424clean:
12425 return rcode;
12426}
12427
12428WARN_UNUSED_RESULT
12429V7_PRIVATE enum v7_err File_loadJSON(struct v7 *v7, v7_val_t *res) {
12430 enum v7_err rcode = V7_OK;
12431 v7_val_t arg0 = v7_arg(v7, 0);
12432
12433 *res = V7_UNDEFINED;
12434
12435 if (v7_is_string(arg0)) {
12436 const char *file_name = v7_get_cstring(v7, &arg0);
12437 if (file_name == NULL) {
12438 goto clean;
12439 }
12440
12441 rcode = v7_parse_json_file(v7, file_name, res);
12442 if (rcode != V7_OK) {
12443 /* swallow exception and return undefined */
12444 v7_clear_thrown_value(v7);
12445 rcode = V7_OK;
12446 *res = V7_UNDEFINED;
12447 }
12448 }
12449
12450clean:
12451 return rcode;
12452}
12453
12454WARN_UNUSED_RESULT
12455V7_PRIVATE enum v7_err File_remove(struct v7 *v7, v7_val_t *res) {
12456 enum v7_err rcode = V7_OK;
12457 v7_val_t arg0 = v7_arg(v7, 0);
12458 int ires = -1;
12459
12460 if (v7_is_string(arg0)) {
12461 const char *path = v7_get_cstring(v7, &arg0);
12462 if (path == NULL) {
12463 *res = v7_mk_number(v7, ENOENT);
12464 goto clean;
12465 }
12466 ires = remove(path);
12467 }
12468 *res = v7_mk_number(v7, ires == 0 ? 0 : errno);
12469
12470clean:
12471 return rcode;
12472}
12473
12474#if V7_ENABLE__File__list
12475WARN_UNUSED_RESULT
12476V7_PRIVATE enum v7_err File_list(struct v7 *v7, v7_val_t *res) {
12477 enum v7_err rcode = V7_OK;
12478 v7_val_t arg0 = v7_arg(v7, 0);
12479
12480 *res = V7_UNDEFINED;
12481
12482 if (v7_is_string(arg0)) {
12483 const char *path = v7_get_cstring(v7, &arg0);
12484 struct dirent *dp;
12485 DIR *dirp;
12486
12487 if (path == NULL) {
12488 goto clean;
12489 }
12490
12491 if ((dirp = (opendir(path))) != NULL) {
12492 *res = v7_mk_array(v7);
12493 while ((dp = readdir(dirp)) != NULL) {
12494 /* Do not show current and parent dirs */
12495 if (strcmp((const char *) dp->d_name, ".") == 0 ||
12496 strcmp((const char *) dp->d_name, "..") == 0) {
12497 continue;
12498 }
12499 /* Add file name to the list */
12500 v7_array_push(v7, *res,
12501 v7_mk_string(v7, (const char *) dp->d_name,
12502 strlen((const char *) dp->d_name), 1));
12503 }
12504 closedir(dirp);
12505 }
12506 }
12507
12508clean:
12509 return rcode;
12510}
12511#endif /* V7_ENABLE__File__list */
12512
12513void init_file(struct v7 *v7) {
12514 v7_val_t file_obj = v7_mk_object(v7), file_proto = v7_mk_object(v7);
12515 v7_set(v7, v7_get_global(v7), "File", 4, file_obj);
12516 v7_set(v7, file_obj, "prototype", 9, file_proto);
12517
12518 v7_set_method(v7, file_obj, "eval", File_eval);
12519 v7_set_method(v7, file_obj, "exists", File_exists);
12520 v7_set_method(v7, file_obj, "remove", File_remove);
12521 v7_set_method(v7, file_obj, "rename", File_rename);
12522 v7_set_method(v7, file_obj, "open", File_open);
12523 v7_set_method(v7, file_obj, "read", File_read);
12524 v7_set_method(v7, file_obj, "write", File_write);
12525 v7_set_method(v7, file_obj, "loadJSON", File_loadJSON);
12526#if V7_ENABLE__File__list
12527 v7_set_method(v7, file_obj, "list", File_list);
12528#endif
12529
12530 v7_set_method(v7, file_proto, "close", File_obj_close);
12531 v7_set_method(v7, file_proto, "read", File_obj_read);
12532 v7_set_method(v7, file_proto, "write", File_obj_write);
12533
12534#if V7_ENABLE__File__require
12535 v7_def(v7, v7_get_global(v7), "_modcache", ~0, 0, v7_mk_object(v7));
12536 if (v7_exec(v7,
12537 "function require(m) { "
12538 " if (m in _modcache) { return _modcache[m]; }"
12539 " var module = {exports:{}};"
12540 " File.eval(m);"
12541 " return (_modcache[m] = module.exports)"
12542 " }",
12543 NULL) != V7_OK) {
12544 /* TODO(mkm): percolate failure */
12545 }
12546#endif
12547}
12548#else
12549void init_file(struct v7 *v7) {
12550 (void) v7;
12551}
12552#endif /* NO_LIBC */
12553#ifdef V7_MODULE_LINES
12554#line 1 "v7/builtin/socket.c"
12555#endif
12556/*
12557 * Copyright (c) 2015 Cesanta Software Limited
12558 * All rights reserved
12559 */
12560
12561/* Amalgamated: #include "v7/src/internal.h" */
12562/* Amalgamated: #include "v7/src/core.h" */
12563/* Amalgamated: #include "v7/src/string.h" */
12564/* Amalgamated: #include "v7/src/object.h" */
12565/* Amalgamated: #include "v7/src/primitive.h" */
12566/* Amalgamated: #include "v7/src/conversion.h" */
12567/* Amalgamated: #include "common/mbuf.h" */
12568/* Amalgamated: #include "common/platform.h" */
12569
12570#if V7_ENABLE_SOCKET
12571
12572#ifdef __WATCOM__
12573#define SOMAXCONN 128
12574#endif
12575
12576#ifndef RECV_BUF_SIZE
12577#define RECV_BUF_SIZE 1024
12578#endif
12579
12580static const char s_sock_prop[] = "__sock";
12581
12582static uint32_t s_resolve(struct v7 *v7, v7_val_t ip_address) {
12583 size_t n;
12584 const char *s = v7_get_string(v7, &ip_address, &n);
12585 struct hostent *he = gethostbyname(s);
12586 return he == NULL ? 0 : *(uint32_t *) he->h_addr_list[0];
12587}
12588
12589WARN_UNUSED_RESULT
12590static enum v7_err s_fd_to_sock_obj(struct v7 *v7, sock_t fd, v7_val_t *res) {
12591 enum v7_err rcode = V7_OK;
12592 v7_val_t sock_proto =
12593 v7_get(v7, v7_get(v7, v7_get_global(v7), "Socket", ~0), "prototype", ~0);
12594
12595 *res = v7_mk_object(v7);
12596 v7_set_proto(v7, *res, sock_proto);
12597 v7_def(v7, *res, s_sock_prop, sizeof(s_sock_prop) - 1, V7_DESC_ENUMERABLE(0),
12598 v7_mk_number(v7, fd));
12599
12600 return rcode;
12601}
12602
12603/* Socket.connect(host, port [, is_udp]) -> socket_object */
12604WARN_UNUSED_RESULT
12605V7_PRIVATE enum v7_err Socket_connect(struct v7 *v7, v7_val_t *res) {
12606 enum v7_err rcode = V7_OK;
12607 v7_val_t arg0 = v7_arg(v7, 0);
12608 v7_val_t arg1 = v7_arg(v7, 1);
12609 v7_val_t arg2 = v7_arg(v7, 2);
12610
12611 if (v7_is_number(arg1) && v7_is_string(arg0)) {
12612 struct sockaddr_in sin;
12613 sock_t sock =
12614 socket(AF_INET, v7_is_truthy(v7, arg2) ? SOCK_DGRAM : SOCK_STREAM, 0);
12615 memset(&sin, 0, sizeof(sin));
12616 sin.sin_family = AF_INET;
12617 sin.sin_addr.s_addr = s_resolve(v7, arg0);
12618 sin.sin_port = htons((uint16_t) v7_get_double(v7, arg1));
12619 if (connect(sock, (struct sockaddr *) &sin, sizeof(sin)) != 0) {
12620 closesocket(sock);
12621 } else {
12622 rcode = s_fd_to_sock_obj(v7, sock, res);
12623 goto clean;
12624 }
12625 }
12626
12627 *res = V7_NULL;
12628
12629clean:
12630 return rcode;
12631}
12632
12633/* Socket.listen(port [, ip_address [,is_udp]]) -> sock */
12634WARN_UNUSED_RESULT
12635V7_PRIVATE enum v7_err Socket_listen(struct v7 *v7, v7_val_t *res) {
12636 enum v7_err rcode = V7_OK;
12637 v7_val_t arg0 = v7_arg(v7, 0);
12638 v7_val_t arg1 = v7_arg(v7, 1);
12639 v7_val_t arg2 = v7_arg(v7, 2);
12640
12641 if (v7_is_number(arg0)) {
12642 struct sockaddr_in sin;
12643 int on = 1;
12644 sock_t sock =
12645 socket(AF_INET, v7_is_truthy(v7, arg2) ? SOCK_DGRAM : SOCK_STREAM, 0);
12646 memset(&sin, 0, sizeof(sin));
12647 sin.sin_family = AF_INET;
12648 sin.sin_port = htons((uint16_t) v7_get_double(v7, arg0));
12649 if (v7_is_string(arg1)) {
12650 sin.sin_addr.s_addr = s_resolve(v7, arg1);
12651 }
12652
12653#if defined(_WIN32) && defined(SO_EXCLUSIVEADDRUSE)
12654 /* "Using SO_REUSEADDR and SO_EXCLUSIVEADDRUSE" http://goo.gl/RmrFTm */
12655 setsockopt(sock, SOL_SOCKET, SO_EXCLUSIVEADDRUSE, (void *) &on, sizeof(on));
12656#endif
12657
12658#if !defined(_WIN32) || defined(SO_EXCLUSIVEADDRUSE)
12659 /*
12660 * SO_RESUSEADDR is not enabled on Windows because the semantics of
12661 * SO_REUSEADDR on UNIX and Windows is different. On Windows,
12662 * SO_REUSEADDR allows to bind a socket to a port without error even if
12663 * the port is already open by another program. This is not the behavior
12664 * SO_REUSEADDR was designed for, and leads to hard-to-track failure
12665 * scenarios. Therefore, SO_REUSEADDR was disabled on Windows unless
12666 * SO_EXCLUSIVEADDRUSE is supported and set on a socket.
12667 */
12668 setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (void *) &on, sizeof(on));
12669#endif
12670
12671 if (bind(sock, (struct sockaddr *) &sin, sizeof(sin)) == 0) {
12672 listen(sock, SOMAXCONN);
12673 rcode = s_fd_to_sock_obj(v7, sock, res);
12674 goto clean;
12675 } else {
12676 closesocket(sock);
12677 }
12678 }
12679
12680 *res = V7_NULL;
12681
12682clean:
12683 return rcode;
12684}
12685
12686WARN_UNUSED_RESULT
12687V7_PRIVATE enum v7_err Socket_accept(struct v7 *v7, v7_val_t *res) {
12688 enum v7_err rcode = V7_OK;
12689 v7_val_t this_obj = v7_get_this(v7);
12690 v7_val_t prop = v7_get(v7, this_obj, s_sock_prop, sizeof(s_sock_prop) - 1);
12691
12692 if (v7_is_number(prop)) {
12693 struct sockaddr_in sin;
12694 socklen_t len = sizeof(sin);
12695 sock_t sock = (sock_t) v7_get_double(v7, prop);
12696 sock_t fd = accept(sock, (struct sockaddr *) &sin, &len);
12697 if (fd != INVALID_SOCKET) {
12698 rcode = s_fd_to_sock_obj(v7, fd, res);
12699 if (rcode == V7_OK) {
12700 char *remote_host = inet_ntoa(sin.sin_addr);
12701 v7_set(v7, *res, "remoteHost", ~0,
12702 v7_mk_string(v7, remote_host, ~0, 1));
12703 }
12704 goto clean;
12705 }
12706 }
12707 *res = V7_NULL;
12708
12709clean:
12710 return rcode;
12711}
12712
12713/* sock.close() -> errno */
12714WARN_UNUSED_RESULT
12715V7_PRIVATE enum v7_err Socket_close(struct v7 *v7, v7_val_t *res) {
12716 enum v7_err rcode = V7_OK;
12717 v7_val_t this_obj = v7_get_this(v7);
12718 v7_val_t prop = v7_get(v7, this_obj, s_sock_prop, sizeof(s_sock_prop) - 1);
12719 *res = v7_mk_number(v7, closesocket((sock_t) v7_get_double(v7, prop)));
12720
12721 return rcode;
12722}
12723
12724/* sock.recv() -> string */
12725WARN_UNUSED_RESULT
12726static enum v7_err s_recv(struct v7 *v7, int all, v7_val_t *res) {
12727 enum v7_err rcode = V7_OK;
12728 v7_val_t this_obj = v7_get_this(v7);
12729 v7_val_t prop = v7_get(v7, this_obj, s_sock_prop, sizeof(s_sock_prop) - 1);
12730
12731 if (v7_is_number(prop)) {
12732 char buf[RECV_BUF_SIZE];
12733 sock_t sock = (sock_t) v7_get_double(v7, prop);
12734 struct mbuf m;
12735 int n;
12736
12737 mbuf_init(&m, 0);
12738 while ((n = recv(sock, buf, sizeof(buf), 0)) > 0) {
12739 mbuf_append(&m, buf, n);
12740 if (!all) {
12741 break;
12742 }
12743 }
12744
12745 if (n <= 0) {
12746 closesocket(sock);
12747 v7_def(v7, this_obj, s_sock_prop, sizeof(s_sock_prop) - 1,
12748 V7_DESC_ENUMERABLE(0), v7_mk_number(v7, INVALID_SOCKET));
12749 }
12750
12751 if (m.len > 0) {
12752 *res = v7_mk_string(v7, m.buf, m.len, 1);
12753 mbuf_free(&m);
12754 goto clean;
12755 }
12756 }
12757
12758 *res = V7_NULL;
12759
12760clean:
12761 return rcode;
12762}
12763
12764WARN_UNUSED_RESULT
12765V7_PRIVATE enum v7_err Socket_recvAll(struct v7 *v7, v7_val_t *res) {
12766 return s_recv(v7, 1, res);
12767}
12768
12769WARN_UNUSED_RESULT
12770V7_PRIVATE enum v7_err Socket_recv(struct v7 *v7, v7_val_t *res) {
12771 return s_recv(v7, 0, res);
12772}
12773
12774WARN_UNUSED_RESULT
12775V7_PRIVATE enum v7_err Socket_send(struct v7 *v7, v7_val_t *res) {
12776 enum v7_err rcode = V7_OK;
12777 v7_val_t this_obj = v7_get_this(v7);
12778 v7_val_t arg0 = v7_arg(v7, 0);
12779 v7_val_t prop = v7_get(v7, this_obj, s_sock_prop, sizeof(s_sock_prop) - 1);
12780 size_t len, sent = 0;
12781
12782 if (v7_is_number(prop) && v7_is_string(arg0)) {
12783 const char *s = v7_get_string(v7, &arg0, &len);
12784 sock_t sock = (sock_t) v7_get_double(v7, prop);
12785 int n;
12786
12787 while (sent < len && (n = send(sock, s + sent, len - sent, 0)) > 0) {
12788 sent += n;
12789 }
12790 }
12791
12792 *res = v7_mk_number(v7, sent);
12793
12794 return rcode;
12795}
12796
12797void init_socket(struct v7 *v7) {
12798 v7_val_t socket_obj = v7_mk_object(v7), sock_proto = v7_mk_object(v7);
12799
12800 v7_set(v7, v7_get_global(v7), "Socket", 6, socket_obj);
12801 sock_proto = v7_mk_object(v7);
12802 v7_set(v7, socket_obj, "prototype", 9, sock_proto);
12803
12804 v7_set_method(v7, socket_obj, "connect", Socket_connect);
12805 v7_set_method(v7, socket_obj, "listen", Socket_listen);
12806
12807 v7_set_method(v7, sock_proto, "accept", Socket_accept);
12808 v7_set_method(v7, sock_proto, "send", Socket_send);
12809 v7_set_method(v7, sock_proto, "recv", Socket_recv);
12810 v7_set_method(v7, sock_proto, "recvAll", Socket_recvAll);
12811 v7_set_method(v7, sock_proto, "close", Socket_close);
12812
12813#ifdef _WIN32
12814 {
12815 WSADATA data;
12816 WSAStartup(MAKEWORD(2, 2), &data);
12817 /* TODO(alashkin): add WSACleanup call */
12818 }
12819#else
12820 signal(SIGPIPE, SIG_IGN);
12821#endif
12822}
12823#else
12824void init_socket(struct v7 *v7) {
12825 (void) v7;
12826}
12827#endif
12828#ifdef V7_MODULE_LINES
12829#line 1 "v7/builtin/crypto.c"
12830#endif
12831/*
12832 * Copyright (c) 2015 Cesanta Software Limited
12833 * All rights reserved
12834 */
12835
12836#include <stdlib.h>
12837#include <string.h>
12838
12839/* Amalgamated: #include "v7/src/internal.h" */
12840/* Amalgamated: #include "v7/src/core.h" */
12841/* Amalgamated: #include "v7/src/primitive.h" */
12842/* Amalgamated: #include "v7/src/string.h" */
12843/* Amalgamated: #include "v7/src/object.h" */
12844/* Amalgamated: #include "common/md5.h" */
12845/* Amalgamated: #include "common/sha1.h" */
12846/* Amalgamated: #include "common/str_util.h" */
12847/* Amalgamated: #include "common/base64.h" */
12848
12849#if V7_ENABLE_CRYPTO
12850
12851typedef void (*b64_func_t)(const unsigned char *, int, char *);
12852
12853WARN_UNUSED_RESULT
12854static enum v7_err b64_transform(struct v7 *v7, b64_func_t func, double mult,
12855 v7_val_t *res) {
12856 enum v7_err rcode = V7_OK;
12857 v7_val_t arg0 = v7_arg(v7, 0);
12858 *res = V7_UNDEFINED;
12859
12860 if (v7_is_string(arg0)) {
12861 size_t n;
12862 const char *s = v7_get_string(v7, &arg0, &n);
12863 char *buf = (char *) malloc(n * mult + 4);
12864 if (buf != NULL) {
12865 func((const unsigned char *) s, (int) n, buf);
12866 *res = v7_mk_string(v7, buf, strlen(buf), 1);
12867 free(buf);
12868 }
12869 }
12870
12871 return rcode;
12872}
12873
12874WARN_UNUSED_RESULT
12875V7_PRIVATE enum v7_err Crypto_base64_decode(struct v7 *v7, v7_val_t *res) {
12876 return b64_transform(v7, (b64_func_t) cs_base64_decode, 0.75, res);
12877}
12878
12879WARN_UNUSED_RESULT
12880V7_PRIVATE enum v7_err Crypto_base64_encode(struct v7 *v7, v7_val_t *res) {
12881 return b64_transform(v7, cs_base64_encode, 1.5, res);
12882}
12883
12884static void v7_md5(const char *data, size_t len, char buf[16]) {
12885 cs_md5_ctx ctx;
12886 cs_md5_init(&ctx);
12887 cs_md5_update(&ctx, (unsigned char *) data, len);
12888 cs_md5_final((unsigned char *) buf, &ctx);
12889}
12890
12891static void v7_sha1(const char *data, size_t len, char buf[20]) {
12892 cs_sha1_ctx ctx;
12893 cs_sha1_init(&ctx);
12894 cs_sha1_update(&ctx, (unsigned char *) data, len);
12895 cs_sha1_final((unsigned char *) buf, &ctx);
12896}
12897
12898WARN_UNUSED_RESULT
12899V7_PRIVATE enum v7_err Crypto_md5(struct v7 *v7, v7_val_t *res) {
12900 enum v7_err rcode = V7_OK;
12901 v7_val_t arg0 = v7_arg(v7, 0);
12902
12903 if (v7_is_string(arg0)) {
12904 size_t len;
12905 const char *data = v7_get_string(v7, &arg0, &len);
12906 char buf[16];
12907 v7_md5(data, len, buf);
12908 *res = v7_mk_string(v7, buf, sizeof(buf), 1);
12909 goto clean;
12910 }
12911
12912 *res = V7_NULL;
12913
12914clean:
12915 return rcode;
12916}
12917
12918WARN_UNUSED_RESULT
12919V7_PRIVATE enum v7_err Crypto_md5_hex(struct v7 *v7, v7_val_t *res) {
12920 enum v7_err rcode = V7_OK;
12921 v7_val_t arg0 = v7_arg(v7, 0);
12922
12923 if (v7_is_string(arg0)) {
12924 size_t len;
12925 const char *data = v7_get_string(v7, &arg0, &len);
12926 char hash[16], buf[sizeof(hash) * 2 + 1];
12927 v7_md5(data, len, hash);
12928 cs_to_hex(buf, (unsigned char *) hash, sizeof(hash));
12929 *res = v7_mk_string(v7, buf, sizeof(buf) - 1, 1);
12930 goto clean;
12931 }
12932 *res = V7_NULL;
12933
12934clean:
12935 return rcode;
12936}
12937
12938WARN_UNUSED_RESULT
12939V7_PRIVATE enum v7_err Crypto_sha1(struct v7 *v7, v7_val_t *res) {
12940 enum v7_err rcode = V7_OK;
12941 v7_val_t arg0 = v7_arg(v7, 0);
12942
12943 if (v7_is_string(arg0)) {
12944 size_t len;
12945 const char *data = v7_get_string(v7, &arg0, &len);
12946 char buf[20];
12947 v7_sha1(data, len, buf);
12948 *res = v7_mk_string(v7, buf, sizeof(buf), 1);
12949 goto clean;
12950 }
12951 *res = V7_NULL;
12952
12953clean:
12954 return rcode;
12955}
12956
12957WARN_UNUSED_RESULT
12958V7_PRIVATE enum v7_err Crypto_sha1_hex(struct v7 *v7, v7_val_t *res) {
12959 enum v7_err rcode = V7_OK;
12960 v7_val_t arg0 = v7_arg(v7, 0);
12961
12962 if (v7_is_string(arg0)) {
12963 size_t len;
12964 const char *data = v7_get_string(v7, &arg0, &len);
12965 char hash[20], buf[sizeof(hash) * 2 + 1];
12966 v7_sha1(data, len, hash);
12967 cs_to_hex(buf, (unsigned char *) hash, sizeof(hash));
12968 *res = v7_mk_string(v7, buf, sizeof(buf) - 1, 1);
12969 goto clean;
12970 }
12971 *res = V7_NULL;
12972
12973clean:
12974 return rcode;
12975}
12976#endif
12977
12978void init_crypto(struct v7 *v7) {
12979#if V7_ENABLE_CRYPTO
12980 v7_val_t obj = v7_mk_object(v7);
12981 v7_set(v7, v7_get_global(v7), "Crypto", 6, obj);
12982 v7_set_method(v7, obj, "md5", Crypto_md5);
12983 v7_set_method(v7, obj, "md5_hex", Crypto_md5_hex);
12984 v7_set_method(v7, obj, "sha1", Crypto_sha1);
12985 v7_set_method(v7, obj, "sha1_hex", Crypto_sha1_hex);
12986 v7_set_method(v7, obj, "base64_encode", Crypto_base64_encode);
12987 v7_set_method(v7, obj, "base64_decode", Crypto_base64_decode);
12988#else
12989 (void) v7;
12990#endif
12991}
12992#ifdef V7_MODULE_LINES
12993#line 1 "v7/src/varint.c"
12994#endif
12995/*
12996 * Copyright (c) 2014 Cesanta Software Limited
12997 * All rights reserved
12998 */
12999
13000/* Amalgamated: #include "v7/src/internal.h" */
13001/* Amalgamated: #include "v7/src/varint.h" */
13002
13003#if defined(__cplusplus)
13004extern "C" {
13005#endif /* __cplusplus */
13006
13007/*
13008 * Strings in AST are encoded as tuples (length, string).
13009 * Length is variable-length: if high bit is set in a byte, next byte is used.
13010 * Maximum string length with such encoding is 2 ^ (7 * 4) == 256 MiB,
13011 * assuming that sizeof(size_t) == 4.
13012 * Small string length (less then 128 bytes) is encoded in 1 byte.
13013 */
13014V7_PRIVATE size_t decode_varint(const unsigned char *p, int *llen) {
13015 size_t i = 0, string_len = 0;
13016
13017 do {
13018 /*
13019 * Each byte of varint contains 7 bits, in little endian order.
13020 * MSB is a continuation bit: it tells whether next byte is used.
13021 */
13022 string_len |= (p[i] & 0x7f) << (7 * i);
13023 /*
13024 * First we increment i, then check whether it is within boundary and
13025 * whether decoded byte had continuation bit set.
13026 */
13027 } while (++i < sizeof(size_t) && (p[i - 1] & 0x80));
13028 *llen = i;
13029
13030 return string_len;
13031}
13032
13033/* Return number of bytes to store length */
13034V7_PRIVATE int calc_llen(size_t len) {
13035 int n = 0;
13036
13037 do {
13038 n++;
13039 } while (len >>= 7);
13040
13041 return n;
13042}
13043
13044V7_PRIVATE int encode_varint(size_t len, unsigned char *p) {
13045 int i, llen = calc_llen(len);
13046
13047 for (i = 0; i < llen; i++) {
13048 p[i] = (len & 0x7f) | (i < llen - 1 ? 0x80 : 0);
13049 len >>= 7;
13050 }
13051
13052 return llen;
13053}
13054
13055#if defined(__cplusplus)
13056}
13057#endif /* __cplusplus */
13058#ifdef V7_MODULE_LINES
13059#line 1 "v7/src/tokenizer.c"
13060#endif
13061/*
13062 * Copyright (c) 2014 Cesanta Software Limited
13063 * All rights reserved
13064 */
13065
13066/* Amalgamated: #include "common/cs_strtod.h" */
13067/* Amalgamated: #include "common/utf.h" */
13068
13069/* Amalgamated: #include "v7/src/internal.h" */
13070/* Amalgamated: #include "v7/src/core.h" */
13071
13072#if !defined(V7_NO_COMPILER)
13073
13074/*
13075 * NOTE(lsm): Must be in the same order as enum for keywords. See comment
13076 * for function get_tok() for rationale for that.
13077 */
13078static const struct v7_vec_const s_keywords[] = {
13079 V7_VEC("break"), V7_VEC("case"), V7_VEC("catch"),
13080 V7_VEC("continue"), V7_VEC("debugger"), V7_VEC("default"),
13081 V7_VEC("delete"), V7_VEC("do"), V7_VEC("else"),
13082 V7_VEC("false"), V7_VEC("finally"), V7_VEC("for"),
13083 V7_VEC("function"), V7_VEC("if"), V7_VEC("in"),
13084 V7_VEC("instanceof"), V7_VEC("new"), V7_VEC("null"),
13085 V7_VEC("return"), V7_VEC("switch"), V7_VEC("this"),
13086 V7_VEC("throw"), V7_VEC("true"), V7_VEC("try"),
13087 V7_VEC("typeof"), V7_VEC("var"), V7_VEC("void"),
13088 V7_VEC("while"), V7_VEC("with")};
13089
13090V7_PRIVATE int is_reserved_word_token(enum v7_tok tok) {
13091 return tok >= TOK_BREAK && tok <= TOK_WITH;
13092}
13093
13094/*
13095 * Move ptr to the next token, skipping comments and whitespaces.
13096 * Return number of new line characters detected.
13097 */
13098V7_PRIVATE int skip_to_next_tok(const char **ptr, const char *src_end) {
13099 const char *s = *ptr, *p = NULL;
13100 int num_lines = 0;
13101
13102 while (s != p && s < src_end && *s != '\0' &&
13103 (isspace((unsigned char) *s) || *s == '/')) {
13104 p = s;
13105 while (s < src_end && *s != '\0' && isspace((unsigned char) *s)) {
13106 if (*s == '\n') num_lines++;
13107 s++;
13108 }
13109 if ((s + 1) < src_end && s[0] == '/' && s[1] == '/') {
13110 s += 2;
13111 while (s < src_end && s[0] != '\0' && s[0] != '\n') s++;
13112 }
13113 if ((s + 1) < src_end && s[0] == '/' && s[1] == '*') {
13114 s += 2;
13115 while (s < src_end && s[0] != '\0' && !(s[-1] == '/' && s[-2] == '*')) {
13116 if (s[0] == '\n') num_lines++;
13117 s++;
13118 }
13119 }
13120 }
13121 *ptr = s;
13122
13123 return num_lines;
13124}
13125
13126/* Advance `s` pointer to the end of identifier */
13127static void ident(const char **s, const char *src_end) {
13128 const unsigned char *p = (unsigned char *) *s;
13129 int n;
13130 Rune r;
13131
13132 while ((const char *) p < src_end && p[0] != '\0') {
13133 if (p[0] == '$' || p[0] == '_' || isalnum(p[0])) {
13134 /* $, _, or any alphanumeric are valid identifier characters */
13135 p++;
13136 } else if ((const char *) (p + 5) < src_end && p[0] == '\\' &&
13137 p[1] == 'u' && isxdigit(p[2]) && isxdigit(p[3]) &&
13138 isxdigit(p[4]) && isxdigit(p[5])) {
13139 /* Unicode escape, \uXXXX . Could be used like "var \u0078 = 1;" */
13140 p += 6;
13141 } else if ((n = chartorune(&r, (char *) p)) > 1 && isalpharune(r)) {
13142 /*
13143 * TODO(dfrank): the chartorune() call above can read `p` past the
13144 * src_end, so it might crash on incorrect code. The solution would be
13145 * to modify `chartorune()` to accept src_end argument as well.
13146 */
13147 /* Unicode alphanumeric character */
13148 p += n;
13149 } else {
13150 break;
13151 }
13152 }
13153
13154 *s = (char *) p;
13155}
13156
13157static enum v7_tok kw(const char *s, size_t len, int ntoks, enum v7_tok tok) {
13158 int i;
13159
13160 for (i = 0; i < ntoks; i++) {
13161 if (s_keywords[(tok - TOK_BREAK) + i].len == len &&
13162 memcmp(s_keywords[(tok - TOK_BREAK) + i].p + 1, s + 1, len - 1) == 0)
13163 break;
13164 }
13165
13166 return i == ntoks ? TOK_IDENTIFIER : (enum v7_tok)(tok + i);
13167}
13168
13169static enum v7_tok punct1(const char **s, const char *src_end, int ch1,
13170 enum v7_tok tok1, enum v7_tok tok2) {
13171 (*s)++;
13172 if (*s < src_end && **s == ch1) {
13173 (*s)++;
13174 return tok1;
13175 } else {
13176 return tok2;
13177 }
13178}
13179
13180static enum v7_tok punct2(const char **s, const char *src_end, int ch1,
13181 enum v7_tok tok1, int ch2, enum v7_tok tok2,
13182 enum v7_tok tok3) {
13183 if ((*s + 2) < src_end && s[0][1] == ch1 && s[0][2] == ch2) {
13184 (*s) += 3;
13185 return tok2;
13186 }
13187
13188 return punct1(s, src_end, ch1, tok1, tok3);
13189}
13190
13191static enum v7_tok punct3(const char **s, const char *src_end, int ch1,
13192 enum v7_tok tok1, int ch2, enum v7_tok tok2,
13193 enum v7_tok tok3) {
13194 (*s)++;
13195 if (*s < src_end) {
13196 if (**s == ch1) {
13197 (*s)++;
13198 return tok1;
13199 } else if (**s == ch2) {
13200 (*s)++;
13201 return tok2;
13202 }
13203 }
13204 return tok3;
13205}
13206
13207static void parse_number(const char *s, const char **end, double *num) {
13208 *num = cs_strtod(s, (char **) end);
13209}
13210
13211static enum v7_tok parse_str_literal(const char **p, const char *src_end) {
13212 const char *s = *p;
13213 int quote = '\0';
13214
13215 if (s < src_end) {
13216 quote = *s++;
13217 }
13218
13219 /* Scan string literal, handle escape sequences */
13220 for (; s < src_end && *s != '\0' && *s != quote; s++) {
13221 if (*s == '\\') {
13222 switch (s[1]) {
13223 case 'b':
13224 case 'f':
13225 case 'n':
13226 case 'r':
13227 case 't':
13228 case 'v':
13229 case '\\':
13230 s++;
13231 break;
13232 default:
13233 if (s[1] == quote) s++;
13234 break;
13235 }
13236 }
13237 }
13238
13239 if (s < src_end && *s == quote) {
13240 s++;
13241 *p = s;
13242 return TOK_STRING_LITERAL;
13243 } else {
13244 return TOK_END_OF_INPUT;
13245 }
13246}
13247
13248/*
13249 * This function is the heart of the tokenizer.
13250 * Organized as a giant switch statement.
13251 *
13252 * Switch statement is by the first character of the input stream. If first
13253 * character begins with a letter, it could be either keyword or identifier.
13254 * get_tok() calls ident() which shifts `s` pointer to the end of the word.
13255 * Now, tokenizer knows that the word begins at `p` and ends at `s`.
13256 * It calls function kw() to scan over the keywords that start with `p[0]`
13257 * letter. Therefore, keyword tokens and keyword strings must be in the
13258 * same order, to let kw() function work properly.
13259 * If kw() finds a keyword match, it returns keyword token.
13260 * Otherwise, it returns TOK_IDENTIFIER.
13261 * NOTE(lsm): `prev_tok` is a previously parsed token. It is needed for
13262 * correctly parsing regex literals.
13263 */
13264V7_PRIVATE enum v7_tok get_tok(const char **s, const char *src_end, double *n,
13265 enum v7_tok prev_tok) {
13266 const char *p = *s;
13267
13268 if (p >= src_end) {
13269 return TOK_END_OF_INPUT;
13270 }
13271
13272 switch (*p) {
13273 /* Letters */
13274 case 'a':
13275 ident(s, src_end);
13276 return TOK_IDENTIFIER;
13277 case 'b':
13278 ident(s, src_end);
13279 return kw(p, *s - p, 1, TOK_BREAK);
13280 case 'c':
13281 ident(s, src_end);
13282 return kw(p, *s - p, 3, TOK_CASE);
13283 case 'd':
13284 ident(s, src_end);
13285 return kw(p, *s - p, 4, TOK_DEBUGGER);
13286 case 'e':
13287 ident(s, src_end);
13288 return kw(p, *s - p, 1, TOK_ELSE);
13289 case 'f':
13290 ident(s, src_end);
13291 return kw(p, *s - p, 4, TOK_FALSE);
13292 case 'g':
13293 case 'h':
13294 ident(s, src_end);
13295 return TOK_IDENTIFIER;
13296 case 'i':
13297 ident(s, src_end);
13298 return kw(p, *s - p, 3, TOK_IF);
13299 case 'j':
13300 case 'k':
13301 case 'l':
13302 case 'm':
13303 ident(s, src_end);
13304 return TOK_IDENTIFIER;
13305 case 'n':
13306 ident(s, src_end);
13307 return kw(p, *s - p, 2, TOK_NEW);
13308 case 'o':
13309 case 'p':
13310 case 'q':
13311 ident(s, src_end);
13312 return TOK_IDENTIFIER;
13313 case 'r':
13314 ident(s, src_end);
13315 return kw(p, *s - p, 1, TOK_RETURN);
13316 case 's':
13317 ident(s, src_end);
13318 return kw(p, *s - p, 1, TOK_SWITCH);
13319 case 't':
13320 ident(s, src_end);
13321 return kw(p, *s - p, 5, TOK_THIS);
13322 case 'u':
13323 ident(s, src_end);
13324 return TOK_IDENTIFIER;
13325 case 'v':
13326 ident(s, src_end);
13327 return kw(p, *s - p, 2, TOK_VAR);
13328 case 'w':
13329 ident(s, src_end);
13330 return kw(p, *s - p, 2, TOK_WHILE);
13331 case 'x':
13332 case 'y':
13333 case 'z':
13334 ident(s, src_end);
13335 return TOK_IDENTIFIER;
13336
13337 case '_':
13338 case '$':
13339 case 'A':
13340 case 'B':
13341 case 'C':
13342 case 'D':
13343 case 'E':
13344 case 'F':
13345 case 'G':
13346 case 'H':
13347 case 'I':
13348 case 'J':
13349 case 'K':
13350 case 'L':
13351 case 'M':
13352 case 'N':
13353 case 'O':
13354 case 'P':
13355 case 'Q':
13356 case 'R':
13357 case 'S':
13358 case 'T':
13359 case 'U':
13360 case 'V':
13361 case 'W':
13362 case 'X':
13363 case 'Y':
13364 case 'Z':
13365 case '\\': /* Identifier may start with unicode escape sequence */
13366 ident(s, src_end);
13367 return TOK_IDENTIFIER;
13368
13369 /* Numbers */
13370 case '0':
13371 case '1':
13372 case '2':
13373 case '3':
13374 case '4':
13375 case '5':
13376 case '6':
13377 case '7':
13378 case '8':
13379 case '9':
13380 parse_number(p, s, n);
13381 return TOK_NUMBER;
13382
13383 /* String literals */
13384 case '\'':
13385 case '"':
13386 return parse_str_literal(s, src_end);
13387
13388 /* Punctuators */
13389 case '=':
13390 return punct2(s, src_end, '=', TOK_EQ, '=', TOK_EQ_EQ, TOK_ASSIGN);
13391 case '!':
13392 return punct2(s, src_end, '=', TOK_NE, '=', TOK_NE_NE, TOK_NOT);
13393
13394 case '%':
13395 return punct1(s, src_end, '=', TOK_REM_ASSIGN, TOK_REM);
13396 case '*':
13397 return punct1(s, src_end, '=', TOK_MUL_ASSIGN, TOK_MUL);
13398 case '/':
13399 /*
13400 * TOK_DIV, TOK_DIV_ASSIGN, and TOK_REGEX_LITERAL start with `/` char.
13401 * Division can happen after an expression.
13402 * In expressions like this:
13403 * a /= b; c /= d;
13404 * things between slashes is NOT a regex literal.
13405 * The switch below catches all cases where division happens.
13406 */
13407 switch (prev_tok) {
13408 case TOK_CLOSE_CURLY:
13409 case TOK_CLOSE_PAREN:
13410 case TOK_CLOSE_BRACKET:
13411 case TOK_IDENTIFIER:
13412 case TOK_NUMBER:
13413 return punct1(s, src_end, '=', TOK_DIV_ASSIGN, TOK_DIV);
13414 default:
13415 /* Not a division - this is a regex. Scan until closing slash */
13416 for (p++; p < src_end && *p != '\0' && *p != '\n'; p++) {
13417 if (*p == '\\') {
13418 /* Skip escape sequence */
13419 p++;
13420 } else if (*p == '/') {
13421 /* This is a closing slash */
13422 p++;
13423 /* Skip regex flags */
13424 while (*p == 'g' || *p == 'i' || *p == 'm') {
13425 p++;
13426 }
13427 *s = p;
13428 return TOK_REGEX_LITERAL;
13429 }
13430 }
13431 break;
13432 }
13433 return punct1(s, src_end, '=', TOK_DIV_ASSIGN, TOK_DIV);
13434 case '^':
13435 return punct1(s, src_end, '=', TOK_XOR_ASSIGN, TOK_XOR);
13436
13437 case '+':
13438 return punct3(s, src_end, '+', TOK_PLUS_PLUS, '=', TOK_PLUS_ASSIGN,
13439 TOK_PLUS);
13440 case '-':
13441 return punct3(s, src_end, '-', TOK_MINUS_MINUS, '=', TOK_MINUS_ASSIGN,
13442 TOK_MINUS);
13443 case '&':
13444 return punct3(s, src_end, '&', TOK_LOGICAL_AND, '=', TOK_AND_ASSIGN,
13445 TOK_AND);
13446 case '|':
13447 return punct3(s, src_end, '|', TOK_LOGICAL_OR, '=', TOK_OR_ASSIGN,
13448 TOK_OR);
13449
13450 case '<':
13451 if (*s + 1 < src_end && s[0][1] == '=') {
13452 (*s) += 2;
13453 return TOK_LE;
13454 }
13455 return punct2(s, src_end, '<', TOK_LSHIFT, '=', TOK_LSHIFT_ASSIGN,
13456 TOK_LT);
13457 case '>':
13458 if (*s + 1 < src_end && s[0][1] == '=') {
13459 (*s) += 2;
13460 return TOK_GE;
13461 }
13462 if (*s + 3 < src_end && s[0][1] == '>' && s[0][2] == '>' &&
13463 s[0][3] == '=') {
13464 (*s) += 4;
13465 return TOK_URSHIFT_ASSIGN;
13466 }
13467 if (*s + 2 < src_end && s[0][1] == '>' && s[0][2] == '>') {
13468 (*s) += 3;
13469 return TOK_URSHIFT;
13470 }
13471 return punct2(s, src_end, '>', TOK_RSHIFT, '=', TOK_RSHIFT_ASSIGN,
13472 TOK_GT);
13473
13474 case '{':
13475 (*s)++;
13476 return TOK_OPEN_CURLY;
13477 case '}':
13478 (*s)++;
13479 return TOK_CLOSE_CURLY;
13480 case '(':
13481 (*s)++;
13482 return TOK_OPEN_PAREN;
13483 case ')':
13484 (*s)++;
13485 return TOK_CLOSE_PAREN;
13486 case '[':
13487 (*s)++;
13488 return TOK_OPEN_BRACKET;
13489 case ']':
13490 (*s)++;
13491 return TOK_CLOSE_BRACKET;
13492 case '.':
13493 switch (*(*s + 1)) {
13494 /* Numbers */
13495 case '0':
13496 case '1':
13497 case '2':
13498 case '3':
13499 case '4':
13500 case '5':
13501 case '6':
13502 case '7':
13503 case '8':
13504 case '9':
13505 parse_number(p, s, n);
13506 return TOK_NUMBER;
13507 }
13508 (*s)++;
13509 return TOK_DOT;
13510 case ';':
13511 (*s)++;
13512 return TOK_SEMICOLON;
13513 case ':':
13514 (*s)++;
13515 return TOK_COLON;
13516 case '?':
13517 (*s)++;
13518 return TOK_QUESTION;
13519 case '~':
13520 (*s)++;
13521 return TOK_TILDA;
13522 case ',':
13523 (*s)++;
13524 return TOK_COMMA;
13525
13526 default: {
13527 /* Handle unicode variables */
13528 Rune r;
13529 if (chartorune(&r, *s) > 1 && isalpharune(r)) {
13530 ident(s, src_end);
13531 return TOK_IDENTIFIER;
13532 }
13533 return TOK_END_OF_INPUT;
13534 }
13535 }
13536}
13537
13538#ifdef TEST_RUN
13539int main(void) {
13540 const char *src =
13541 "for (var fo++ = -1; /= <= 1.17; x<<) { == <<=, 'x')} "
13542 "Infinity %=x<<=2";
13543 const char *src_end = src + strlen(src);
13544 enum v7_tok tok;
13545 double num;
13546 const char *p = src;
13547
13548 skip_to_next_tok(&src, src_end);
13549 while ((tok = get_tok(&src, src_end, &num)) != TOK_END_OF_INPUT) {
13550 printf("%d [%.*s]\n", tok, (int) (src - p), p);
13551 skip_to_next_tok(&src, src_end);
13552 p = src;
13553 }
13554 printf("%d [%.*s]\n", tok, (int) (src - p), p);
13555
13556 return 0;
13557}
13558#endif
13559
13560#endif /* V7_NO_COMPILER */
13561#ifdef V7_MODULE_LINES
13562#line 1 "v7/src/ast.c"
13563#endif
13564/*
13565 * Copyright (c) 2014 Cesanta Software Limited
13566 * All rights reserved
13567 */
13568
13569/* Amalgamated: #include "common/cs_strtod.h" */
13570/* Amalgamated: #include "common/mbuf.h" */
13571
13572/* Amalgamated: #include "v7/src/internal.h" */
13573/* Amalgamated: #include "v7/src/varint.h" */
13574/* Amalgamated: #include "v7/src/ast.h" */
13575/* Amalgamated: #include "v7/src/core.h" */
13576/* Amalgamated: #include "v7/src/string.h" */
13577/* Amalgamated: #include "common/str_util.h" */
13578
13579#if !defined(V7_NO_COMPILER)
13580
13581#ifdef V7_LARGE_AST
13582typedef uint32_t ast_skip_t;
13583#else
13584typedef uint16_t ast_skip_t;
13585#define AST_SKIP_MAX UINT16_MAX
13586#endif
13587
13588#if !V7_DISABLE_AST_TAG_NAMES
13589#define AST_ENTRY(name, has_varint, has_inlined, num_skips, num_subtrees) \
13590 { (name), (has_varint), (has_inlined), (num_skips), (num_subtrees) }
13591#else
13592#define AST_ENTRY(name, has_varint, has_inlined, num_skips, num_subtrees) \
13593 { (has_varint), (has_inlined), (num_skips), (num_subtrees) }
13594#endif
13595
13596/*
13597 * The structure of AST nodes cannot be described in portable ANSI C,
13598 * since they are variable length and packed (unaligned).
13599 *
13600 * Here each node's body is described with a pseudo-C structure notation.
13601 * The pseudo type `child` represents a variable length byte sequence
13602 * representing a fully serialized child node.
13603 *
13604 * `child body[]` represents a sequence of such subtrees.
13605 *
13606 * Pseudo-labels, such as `end:` represent the targets of skip fields
13607 * with the same name (e.g. `ast_skip_t end`).
13608 *
13609 * Skips allow skipping a subtree or sequence of subtrees.
13610 *
13611 * Sequences of subtrees (i.e. `child []`) have to be terminated by a skip:
13612 * they don't have a termination tag; all nodes whose position is before the
13613 * skip are part of the sequence.
13614 *
13615 * Skips are encoded as network-byte-order 16-bit offsets counted from the
13616 * first byte of the node body (i.e. not counting the tag itself).
13617 * This currently limits the the maximum size of a function body to 64k.
13618 *
13619 * Notes:
13620 *
13621 * - Some nodes contain skips just for performance or because it simplifies
13622 * the implementation of the interpreter. For example, technically, the FOR
13623 * node doesn't need the `body` skip in order to be correctly traversed.
13624 * However, being able to quickly skip the `iter` expression is useful
13625 * also because it allows the interpreter to avoid traversing the expression
13626 * subtree without evaluating it, just in order to find the next subtree.
13627 *
13628 * - The name `skip` was chosen because `offset` was too overloaded in general
13629 * and label` is part of our domain model (i.e. JS has a label AST node type).
13630 *
13631 *
13632 * So, each node has a mandatory field: *tag* (see `enum ast_tag`), and a
13633 * number of optional fields. Whether the node has one or another optional
13634 * field is determined by the *node descriptor*: `struct ast_node_def`. For
13635 * each node type (i.e. for each element of `enum ast_tag`) there is a
13636 * corresponding descriptor: see `ast_node_defs`.
13637 *
13638 * Optional fields are:
13639 *
13640 * - *varint*: a varint-encoded number. At the moment, this field is only used
13641 * together with the next field: inlined data, and a varint number determines
13642 * the inlined data length.
13643 * - *inlined data*: a node-specific data. Size of it is determined by the
13644 * previous field: varint.
13645 * - *skips*: as explained above, these are integer offsets, encoded in
13646 * big-endian. The number of skips is determined by the node descriptor
13647 * (`struct ast_node_def`). The size of each skip is either 16 or 32 bits,
13648 * depending on whether the macro `V7_LARGE_AST` is set. The order of skips
13649 * is determined by the `enum ast_which_skip`. See examples below for
13650 * clarity.
13651 * - *subtrees*: child nodes. Some nodes have fixed number of child nodes; in
13652 * this case, the descriptor has non-zero field `num_subtrees`. Otherwise,
13653 * `num_subtrees` is zero, and consumer handles child nodes one by one, until
13654 * the end of the node is reached (end of the node is determined by the `end`
13655 * skip)
13656 *
13657 *
13658 * Examples:
13659 *
13660 * Let's start from the very easy example script: "300;"
13661 *
13662 * Tree looks as follows:
13663 *
13664 * $ ./v7 -e "300;" -t
13665 * SCRIPT
13666 * /- [...] -/
13667 * NUM 300
13668 *
13669 * Binary data is:
13670 *
13671 * $ ./v7 -e "300;" -b | od -A n -t x1
13672 * 56 07 41 53 54 56 31 30 00 01 00 09 00 00 13 03
13673 * 33 30 30
13674 *
13675 * Let's break it down and examine:
13676 *
13677 * - 56 07 41 53 54 56 31 30 00
13678 * Just a format prefix:
13679 * Null-terminated string: `"V\007ASTV10"` (see `BIN_AST_SIGNATURE`)
13680 * - 01
13681 * AST tag: `AST_SCRIPT`. As you see in `ast_node_defs` below, node of
13682 * this type has neither *varint* nor *inlined data* fields, but it has
13683 * 2 skips: `end` and `next`. `end` is a skip to the end of the current
13684 * node (`SCRIPT`), and `next` will be explained below.
13685 *
13686 * The size of each skip depends on whether `V7_LARGE_AST` is defined.
13687 * If it is, then size is 32 bit, otherwise it's 16 bit. In this
13688 * example, we have 16-bit skips.
13689 *
13690 * The order of skips is determined by the `enum ast_which_skip`. If you
13691 * check, you'll see that `AST_END_SKIP` is 0, and `AST_VAR_NEXT_SKIP`
13692 * is 1. So, `end` skip fill be the first, and `next` will be the second:
13693 * - 00 09
13694 * `end` skip: 9 bytes. It's the size of the whole `SCRIPT` data. So, if
13695 * we have an index of the `ASC_SCRIPT` tag, we can just add this skip
13696 * (9) to this index, and therefore skip over the whole node.
13697 * - 00 00
13698 * `next` skip. `next` actually means "next variable node": since
13699 * variables are hoisted in JavaScript, when the interpreter starts
13700 * executing a top-level code or any function, it needs to get a list of
13701 * all defined variables. The `SCRIPT` node has a "skip" to the first
13702 * `var` or `function` declaration, which, in turn, has a "skip" to the
13703 * next one, etc. If there is no next `var` declaration, then 0 is
13704 * stored.
13705 *
13706 * In our super-simple script, we have no `var` neither `function`
13707 * declarations, so, this skip is 0.
13708 *
13709 * Now, the body of our SCRIPT node goes, which contains child nodes:
13710 *
13711 * - 13
13712 * AST tag: `AST_NUM`. Look at the `ast_node_defs`, and we'll see that
13713 * nodes of this type don't have any skips, but they do have the varint
13714 * field and the inlined data. Here we go:
13715 * - 03
13716 * Varint value: 3
13717 * - 33 30 30
13718 * UTF-8 string "300"
13719 *
13720 * ---------------
13721 *
13722 * The next example is a bit more interesting:
13723 *
13724 * var foo,
13725 * bar = 1;
13726 * foo = 3;
13727 * var baz = 4;
13728 *
13729 * Tree:
13730 *
13731 * $ ./v7 -e 'var foo, bar=1; foo=3; var baz = 4;' -t
13732 * SCRIPT
13733 * /- [...] -/
13734 * VAR
13735 * /- [...] -/
13736 * VAR_DECL foo
13737 * NOP
13738 * VAR_DECL bar
13739 * NUM 1
13740 * ASSIGN
13741 * IDENT foo
13742 * NUM 3
13743 * VAR
13744 * /- [...] -/
13745 * VAR_DECL baz
13746 * NUM 4
13747 *
13748 * Binary:
13749 *
13750 * $ ./v7 -e 'var foo, bar=1; foo=3; var baz = 4;' -b | od -A n -t x1
13751 * 56 07 41 53 54 56 31 30 00 01 00 2d 00 05 02 00
13752 * 12 00 1c 03 03 66 6f 6f 00 03 03 62 61 72 13 01
13753 * 31 07 14 03 66 6f 6f 13 01 33 02 00 0c 00 00 03
13754 * 03 62 61 7a 13 01 34
13755 *
13756 * Break it down:
13757 *
13758 * - 56 07 41 53 54 56 31 30 00
13759 * `"V\007ASTV10"`
13760 * - 01: AST tag: `AST_SCRIPT`
13761 * - 00 2d: `end` skip: 0x2d = 45 bytes
13762 * - 00 05: `next` skip: an offset from `AST_SCRIPT` byte to the first
13763 * `var` declaration.
13764 *
13765 * Now, body of the SCRIPT node begins, which contains child nodes,
13766 * and the first node is the var declaration `var foo, bar=1;`:
13767 *
13768 * SCRIPT node body: {{{
13769 * - 02: AST tag: `AST_VAR`
13770 * - 00 12: `end` skip: 18 bytes from tag byte to the end of current node
13771 * - 00 1c: `next` skip: 28 bytes from tag byte to the next `var` node
13772 *
13773 * The VAR node contains arbitrary number of child nodes, so, consumer
13774 * takes advantage of the `end` skip.
13775 *
13776 * VAR node body: {{{
13777 * - 03: AST tag: `AST_VAR_DECL`
13778 * - 03: Varint value: 3 (the length of the inlined data: a variable
13779 *name)
13780 * - 66 6f 6f: UTF-8 string: "foo"
13781 * - 00: AST tag: `AST_NOP`
13782 * Since we haven't provided any value to store into `foo`, NOP
13783 * without any additional data is stored in AST.
13784 *
13785 * - 03: AST tag: `AST_VAR_DECL`
13786 * - 03: Varint value: 3 (the length of the inlined data: a variable
13787 *name)
13788 * - 62 61 72: UTF-8 string: "bar"
13789 * - 13: AST tag: `AST_NUM`
13790 * - 01: Varint value: 1
13791 * - 31: UTF-8 string "1"
13792 * VAR body end }}}
13793 *
13794 * - 07: AST tag: `AST_ASSIGN`
13795 *
13796 * The ASSIGN node has fixed number of subrees: 2 (lvalue and rvalue),
13797 * so there's no `end` skip.
13798 *
13799 * ASSIGN node body: {{{
13800 * - 14: AST tag: `AST_IDENT`
13801 * - 03: Varint value: 3
13802 * - 66 6f 6f: UTF-8 string: "foo"
13803 *
13804 * - 13: AST tag: `AST_NUM`
13805 * - 01: Varint value: 1
13806 * - 33: UTF-8 string: "3"
13807 * ASSIGN body end }}}
13808 *
13809 * - 02: AST tag: `AST_VAR`
13810 * - 00 0c: `end` skip: 12 bytes from tag byte to the end of current node
13811 * - 00 00: `next` skip: no more `var` nodes
13812 *
13813 * VAR node body: {{{
13814 * - 03: AST tag: `AST_VAR_DECL`
13815 * - 03: Varint value: 3 (the length of the inlined data: a variable
13816 *name)
13817 * - 62 61 7a: UTF-8 string: "baz"
13818 * - 13: AST tag: `AST_NUM`
13819 * - 01: Varint value: 1
13820 * - 34: UTF-8 string "4"
13821 * VAR body end }}}
13822 * SCRIPT body end }}}
13823 *
13824 * --------------------------
13825 */
13826
13827const struct ast_node_def ast_node_defs[] = {
13828 AST_ENTRY("NOP", 0, 0, 0, 0), /* struct {} */
13829
13830 /*
13831 * struct {
13832 * ast_skip_t end;
13833 * ast_skip_t first_var;
13834 * child body[];
13835 * end:
13836 * }
13837 */
13838 AST_ENTRY("SCRIPT", 0, 0, 2, 0),
13839 /*
13840 * struct {
13841 * ast_skip_t end;
13842 * ast_skip_t next;
13843 * child decls[];
13844 * end:
13845 * }
13846 */
13847 AST_ENTRY("VAR", 0, 0, 2, 0),
13848 /*
13849 * struct {
13850 * varint len;
13851 * char name[len];
13852 * child expr;
13853 * }
13854 */
13855 AST_ENTRY("VAR_DECL", 1, 1, 0, 1),
13856 /*
13857 * struct {
13858 * varint len;
13859 * char name[len];
13860 * child expr;
13861 * }
13862 */
13863 AST_ENTRY("FUNC_DECL", 1, 1, 0, 1),
13864 /*
13865 * struct {
13866 * ast_skip_t end;
13867 * ast_skip_t end_true;
13868 * child cond;
13869 * child iftrue[];
13870 * end_true:
13871 * child iffalse[];
13872 * end:
13873 * }
13874 */
13875 AST_ENTRY("IF", 0, 0, 2, 1),
13876 /*
13877 * TODO(mkm) distinguish function expressions
13878 * from function statements.
13879 * Function statements behave like vars and need a
13880 * next field for hoisting.
13881 * We can also ignore the name for function expressions
13882 * if it's only needed for debugging.
13883 *
13884 * struct {
13885 * ast_skip_t end;
13886 * ast_skip_t first_var;
13887 * ast_skip_t body;
13888 * child name;
13889 * child params[];
13890 * body:
13891 * child body[];
13892 * end:
13893 * }
13894 */
13895 AST_ENTRY("FUNC", 0, 0, 3, 1),
13896 AST_ENTRY("ASSIGN", 0, 0, 0, 2), /* struct { child left, right; } */
13897 AST_ENTRY("REM_ASSIGN", 0, 0, 0, 2), /* struct { child left, right; } */
13898 AST_ENTRY("MUL_ASSIGN", 0, 0, 0, 2), /* struct { child left, right; } */
13899 AST_ENTRY("DIV_ASSIGN", 0, 0, 0, 2), /* struct { child left, right; } */
13900 AST_ENTRY("XOR_ASSIGN", 0, 0, 0, 2), /* struct { child left, right; } */
13901 AST_ENTRY("PLUS_ASSIGN", 0, 0, 0, 2), /* struct { child left, right; } */
13902 AST_ENTRY("MINUS_ASSIGN", 0, 0, 0, 2), /* struct { child left, right; } */
13903 AST_ENTRY("OR_ASSIGN", 0, 0, 0, 2), /* struct { child left, right; } */
13904 AST_ENTRY("AND_ASSIGN", 0, 0, 0, 2), /* struct { child left, right; } */
13905 AST_ENTRY("LSHIFT_ASSIGN", 0, 0, 0, 2), /* struct { child left, right; } */
13906 AST_ENTRY("RSHIFT_ASSIGN", 0, 0, 0, 2), /* struct { child left, right; } */
13907 AST_ENTRY("URSHIFT_ASSIGN", 0, 0, 0, 2), /* struct { child left, right; } */
13908 AST_ENTRY("NUM", 1, 1, 0, 0), /* struct { varint len, char s[len]; } */
13909 AST_ENTRY("IDENT", 1, 1, 0, 0), /* struct { varint len, char s[len]; } */
13910 AST_ENTRY("STRING", 1, 1, 0, 0), /* struct { varint len, char s[len]; } */
13911 AST_ENTRY("REGEX", 1, 1, 0, 0), /* struct { varint len, char s[len]; } */
13912 AST_ENTRY("LABEL", 1, 1, 0, 0), /* struct { varint len, char s[len]; } */
13913
13914 /*
13915 * struct {
13916 * ast_skip_t end;
13917 * child body[];
13918 * end:
13919 * }
13920 */
13921 AST_ENTRY("SEQ", 0, 0, 1, 0),
13922 /*
13923 * struct {
13924 * ast_skip_t end;
13925 * child cond;
13926 * child body[];
13927 * end:
13928 * }
13929 */
13930 AST_ENTRY("WHILE", 0, 0, 1, 1),
13931 /*
13932 * struct {
13933 * ast_skip_t end;
13934 * ast_skip_t cond;
13935 * child body[];
13936 * cond:
13937 * child cond;
13938 * end:
13939 * }
13940 */
13941 AST_ENTRY("DOWHILE", 0, 0, 2, 0),
13942 /*
13943 * struct {
13944 * ast_skip_t end;
13945 * ast_skip_t body;
13946 * child init;
13947 * child cond;
13948 * child iter;
13949 * body:
13950 * child body[];
13951 * end:
13952 * }
13953 */
13954 AST_ENTRY("FOR", 0, 0, 2, 3),
13955 /*
13956 * struct {
13957 * ast_skip_t end;
13958 * ast_skip_t dummy; // allows to quickly promote a for to a for in
13959 * child var;
13960 * child expr;
13961 * child dummy;
13962 * child body[];
13963 * end:
13964 * }
13965 */
13966 AST_ENTRY("FOR_IN", 0, 0, 2, 3),
13967 AST_ENTRY("COND", 0, 0, 0, 3), /* struct { child cond, iftrue, iffalse; } */
13968 AST_ENTRY("DEBUGGER", 0, 0, 0, 0), /* struct {} */
13969 AST_ENTRY("BREAK", 0, 0, 0, 0), /* struct {} */
13970
13971 /*
13972 * struct {
13973 * child label; // TODO(mkm): inline
13974 * }
13975 */
13976 AST_ENTRY("LAB_BREAK", 0, 0, 0, 1),
13977 AST_ENTRY("CONTINUE", 0, 0, 0, 0), /* struct {} */
13978
13979 /*
13980 * struct {
13981 * child label; // TODO(mkm): inline
13982 * }
13983 */
13984 AST_ENTRY("LAB_CONTINUE", 0, 0, 0, 1),
13985 AST_ENTRY("RETURN", 0, 0, 0, 0), /* struct {} */
13986 AST_ENTRY("VAL_RETURN", 0, 0, 0, 1), /* struct { child expr; } */
13987 AST_ENTRY("THROW", 0, 0, 0, 1), /* struct { child expr; } */
13988
13989 /*
13990 * struct {
13991 * ast_skip_t end;
13992 * ast_skip_t catch;
13993 * ast_skip_t finally;
13994 * child try[];
13995 * catch:
13996 * child var; // TODO(mkm): inline
13997 * child catch[];
13998 * finally:
13999 * child finally[];
14000 * end:
14001 * }
14002 */
14003 AST_ENTRY("TRY", 0, 0, 3, 1),
14004 /*
14005 * struct {
14006 * ast_skip_t end;
14007 * ast_skip_t def;
14008 * child expr;
14009 * child cases[];
14010 * def:
14011 * child default?; // optional
14012 * end:
14013 * }
14014 */
14015 AST_ENTRY("SWITCH", 0, 0, 2, 1),
14016 /*
14017 * struct {
14018 * ast_skip_t end;
14019 * child val;
14020 * child stmts[];
14021 * end:
14022 * }
14023 */
14024 AST_ENTRY("CASE", 0, 0, 1, 1),
14025 /*
14026 * struct {
14027 * ast_skip_t end;
14028 * child stmts[];
14029 * end:
14030 * }
14031 */
14032 AST_ENTRY("DEFAULT", 0, 0, 1, 0),
14033 /*
14034 * struct {
14035 * ast_skip_t end;
14036 * child expr;
14037 * child body[];
14038 * end:
14039 * }
14040 */
14041 AST_ENTRY("WITH", 0, 0, 1, 1),
14042 AST_ENTRY("LOG_OR", 0, 0, 0, 2), /* struct { child left, right; } */
14043 AST_ENTRY("LOG_AND", 0, 0, 0, 2), /* struct { child left, right; } */
14044 AST_ENTRY("OR", 0, 0, 0, 2), /* struct { child left, right; } */
14045 AST_ENTRY("XOR", 0, 0, 0, 2), /* struct { child left, right; } */
14046 AST_ENTRY("AND", 0, 0, 0, 2), /* struct { child left, right; } */
14047 AST_ENTRY("EQ", 0, 0, 0, 2), /* struct { child left, right; } */
14048 AST_ENTRY("EQ_EQ", 0, 0, 0, 2), /* struct { child left, right; } */
14049 AST_ENTRY("NE", 0, 0, 0, 2), /* struct { child left, right; } */
14050 AST_ENTRY("NE_NE", 0, 0, 0, 2), /* struct { child left, right; } */
14051 AST_ENTRY("LE", 0, 0, 0, 2), /* struct { child left, right; } */
14052 AST_ENTRY("LT", 0, 0, 0, 2), /* struct { child left, right; } */
14053 AST_ENTRY("GE", 0, 0, 0, 2), /* struct { child left, right; } */
14054 AST_ENTRY("GT", 0, 0, 0, 2), /* struct { child left, right; } */
14055 AST_ENTRY("IN", 0, 0, 0, 2), /* struct { child left, right; } */
14056 AST_ENTRY("INSTANCEOF", 0, 0, 0, 2), /* struct { child left, right; } */
14057 AST_ENTRY("LSHIFT", 0, 0, 0, 2), /* struct { child left, right; } */
14058 AST_ENTRY("RSHIFT", 0, 0, 0, 2), /* struct { child left, right; } */
14059 AST_ENTRY("URSHIFT", 0, 0, 0, 2), /* struct { child left, right; } */
14060 AST_ENTRY("ADD", 0, 0, 0, 2), /* struct { child left, right; } */
14061 AST_ENTRY("SUB", 0, 0, 0, 2), /* struct { child left, right; } */
14062 AST_ENTRY("REM", 0, 0, 0, 2), /* struct { child left, right; } */
14063 AST_ENTRY("MUL", 0, 0, 0, 2), /* struct { child left, right; } */
14064 AST_ENTRY("DIV", 0, 0, 0, 2), /* struct { child left, right; } */
14065 AST_ENTRY("POS", 0, 0, 0, 1), /* struct { child expr; } */
14066 AST_ENTRY("NEG", 0, 0, 0, 1), /* struct { child expr; } */
14067 AST_ENTRY("NOT", 0, 0, 0, 1), /* struct { child expr; } */
14068 AST_ENTRY("LOGICAL_NOT", 0, 0, 0, 1), /* struct { child expr; } */
14069 AST_ENTRY("VOID", 0, 0, 0, 1), /* struct { child expr; } */
14070 AST_ENTRY("DELETE", 0, 0, 0, 1), /* struct { child expr; } */
14071 AST_ENTRY("TYPEOF", 0, 0, 0, 1), /* struct { child expr; } */
14072 AST_ENTRY("PREINC", 0, 0, 0, 1), /* struct { child expr; } */
14073 AST_ENTRY("PREDEC", 0, 0, 0, 1), /* struct { child expr; } */
14074 AST_ENTRY("POSTINC", 0, 0, 0, 1), /* struct { child expr; } */
14075 AST_ENTRY("POSTDEC", 0, 0, 0, 1), /* struct { child expr; } */
14076
14077 /*
14078 * struct {
14079 * varint len;
14080 * char ident[len];
14081 * child expr;
14082 * }
14083 */
14084 AST_ENTRY("MEMBER", 1, 1, 0, 1),
14085 /*
14086 * struct {
14087 * child expr;
14088 * child index;
14089 * }
14090 */
14091 AST_ENTRY("INDEX", 0, 0, 0, 2),
14092 /*
14093 * struct {
14094 * ast_skip_t end;
14095 * child expr;
14096 * child args[];
14097 * end:
14098 * }
14099 */
14100 AST_ENTRY("CALL", 0, 0, 1, 1),
14101 /*
14102 * struct {
14103 * ast_skip_t end;
14104 * child expr;
14105 * child args[];
14106 * end:
14107 * }
14108 */
14109 AST_ENTRY("NEW", 0, 0, 1, 1),
14110 /*
14111 * struct {
14112 * ast_skip_t end;
14113 * child elements[];
14114 * end:
14115 * }
14116 */
14117 AST_ENTRY("ARRAY", 0, 0, 1, 0),
14118 /*
14119 * struct {
14120 * ast_skip_t end;
14121 * child props[];
14122 * end:
14123 * }
14124 */
14125 AST_ENTRY("OBJECT", 0, 0, 1, 0),
14126 /*
14127 * struct {
14128 * varint len;
14129 * char name[len];
14130 * child expr;
14131 * }
14132 */
14133 AST_ENTRY("PROP", 1, 1, 0, 1),
14134 /*
14135 * struct {
14136 * child func;
14137 * }
14138 */
14139 AST_ENTRY("GETTER", 0, 0, 0, 1),
14140 /*
14141 * struct {
14142 * child func;
14143 * end:
14144 * }
14145 */
14146 AST_ENTRY("SETTER", 0, 0, 0, 1),
14147 AST_ENTRY("THIS", 0, 0, 0, 0), /* struct {} */
14148 AST_ENTRY("TRUE", 0, 0, 0, 0), /* struct {} */
14149 AST_ENTRY("FALSE", 0, 0, 0, 0), /* struct {} */
14150 AST_ENTRY("NULL", 0, 0, 0, 0), /* struct {} */
14151 AST_ENTRY("UNDEF", 0, 0, 0, 0), /* struct {} */
14152 AST_ENTRY("USE_STRICT", 0, 0, 0, 0), /* struct {} */
14153};
14154
14155/*
14156 * A flag which is used to mark node's tag byte if the node has line number
14157 * data encoded (varint after skips). See `ast_get_line_no()`.
14158 */
14159#define AST_TAG_LINENO_PRESENT 0x80
14160
14161V7_STATIC_ASSERT(AST_MAX_TAG < 256, ast_tag_should_fit_in_char);
14162V7_STATIC_ASSERT(AST_MAX_TAG == ARRAY_SIZE(ast_node_defs), bad_node_defs);
14163V7_STATIC_ASSERT(AST_MAX_TAG <= AST_TAG_LINENO_PRESENT, bad_AST_LINE_NO);
14164
14165#if V7_ENABLE_FOOTPRINT_REPORT
14166const size_t ast_node_defs_size = sizeof(ast_node_defs);
14167const size_t ast_node_defs_count = ARRAY_SIZE(ast_node_defs);
14168#endif
14169
14170/*
14171 * Converts a given byte `t` (which should be read from the AST data buffer)
14172 * into `enum ast_tag`. This function is needed because tag might be marked
14173 * with the `AST_TAG_LINENO_PRESENT` flag; the returned tag is always unmarked,
14174 * and if the flag was indeed set, `lineno_present` is set to 1; otherwise
14175 * it is set to 0.
14176 *
14177 * `lineno_present` is allowed to be NULL, if the caller doesn't care of the
14178 * line number presence.
14179 */
14180static enum ast_tag uint8_to_tag(uint8_t t, uint8_t *lineno_present) {
14181 if (t & AST_TAG_LINENO_PRESENT) {
14182 t &= ~AST_TAG_LINENO_PRESENT;
14183 if (lineno_present != NULL) {
14184 *lineno_present = 1;
14185 }
14186 } else if (lineno_present != NULL) {
14187 *lineno_present = 0;
14188 }
14189 return (enum ast_tag) t;
14190}
14191
14192V7_PRIVATE ast_off_t
14193ast_insert_node(struct ast *a, ast_off_t pos, enum ast_tag tag) {
14194 uint8_t t = (uint8_t) tag;
14195 const struct ast_node_def *d = &ast_node_defs[tag];
14196 ast_off_t cur = pos;
14197
14198 assert(tag < AST_MAX_TAG);
14199
14200 mbuf_insert(&a->mbuf, cur, (char *) &t, sizeof(t));
14201 cur += sizeof(t);
14202
14203 mbuf_insert(&a->mbuf, cur, NULL, sizeof(ast_skip_t) * d->num_skips);
14204 cur += sizeof(ast_skip_t) * d->num_skips;
14205
14206 if (d->num_skips) {
14207 ast_set_skip(a, pos + 1, AST_END_SKIP);
14208 }
14209
14210 return pos + 1;
14211}
14212
14213V7_PRIVATE void ast_modify_tag(struct ast *a, ast_off_t tag_off,
14214 enum ast_tag tag) {
14215 a->mbuf.buf[tag_off] = tag | (a->mbuf.buf[tag_off] & 0x80);
14216}
14217
14218#if !V7_DISABLE_LINE_NUMBERS
14219V7_PRIVATE void ast_add_line_no(struct ast *a, ast_off_t tag_off, int line_no) {
14220 ast_off_t ln_off = tag_off + 1 /* tag byte */;
14221 int llen = calc_llen(line_no);
14222
14223 ast_move_to_inlined_data(a, &ln_off);
14224 mbuf_insert(&a->mbuf, ln_off, NULL, llen);
14225 encode_varint(line_no, (unsigned char *) (a->mbuf.buf + ln_off));
14226
14227 assert(a->mbuf.buf[tag_off] < AST_MAX_TAG);
14228 a->mbuf.buf[tag_off] |= AST_TAG_LINENO_PRESENT;
14229}
14230#endif
14231
14232V7_PRIVATE ast_off_t
14233ast_set_skip(struct ast *a, ast_off_t pos, enum ast_which_skip skip) {
14234 return ast_modify_skip(a, pos, a->mbuf.len, skip);
14235}
14236
14237V7_PRIVATE ast_off_t ast_modify_skip(struct ast *a, ast_off_t pos,
14238 ast_off_t where,
14239 enum ast_which_skip skip) {
14240 uint8_t *p = (uint8_t *) a->mbuf.buf + pos + skip * sizeof(ast_skip_t);
14241 ast_skip_t delta = where - pos;
14242#ifndef NDEBUG
14243 enum ast_tag tag = uint8_to_tag(*(a->mbuf.buf + pos - 1), NULL);
14244 const struct ast_node_def *def = &ast_node_defs[tag];
14245#endif
14246 assert(pos <= where);
14247
14248#ifndef V7_LARGE_AST
14249 /* the value of delta overflowed, therefore the ast is not useable */
14250 if (where - pos > AST_SKIP_MAX) {
14251 a->has_overflow = 1;
14252 }
14253#endif
14254
14255 /* assertion, to be optimizable out */
14256 assert((int) skip < def->num_skips);
14257
14258#ifdef V7_LARGE_AST
14259 p[0] = delta >> 24;
14260 p[1] = delta >> 16 & 0xff;
14261 p[2] = delta >> 8 & 0xff;
14262 p[3] = delta & 0xff;
14263#else
14264 p[0] = delta >> 8;
14265 p[1] = delta & 0xff;
14266#endif
14267 return where;
14268}
14269
14270V7_PRIVATE ast_off_t
14271ast_get_skip(struct ast *a, ast_off_t pos, enum ast_which_skip skip) {
14272 uint8_t *p;
14273 assert(pos + skip * sizeof(ast_skip_t) < a->mbuf.len);
14274
14275 p = (uint8_t *) a->mbuf.buf + pos + skip * sizeof(ast_skip_t);
14276#ifdef V7_LARGE_AST
14277 return pos + (p[3] | p[2] << 8 | p[1] << 16 | p[0] << 24);
14278#else
14279 return pos + (p[1] | p[0] << 8);
14280#endif
14281}
14282
14283V7_PRIVATE enum ast_tag ast_fetch_tag(struct ast *a, ast_off_t *ppos) {
14284 enum ast_tag ret;
14285 assert(*ppos < a->mbuf.len);
14286
14287 ret = uint8_to_tag(*(a->mbuf.buf + (*ppos)++), NULL);
14288
14289 return ret;
14290}
14291
14292V7_PRIVATE void ast_move_to_children(struct ast *a, ast_off_t *ppos) {
14293 enum ast_tag tag = uint8_to_tag(*(a->mbuf.buf + *ppos - 1), NULL);
14294 const struct ast_node_def *def = &ast_node_defs[tag];
14295 assert(*ppos - 1 < a->mbuf.len);
14296
14297 ast_move_to_inlined_data(a, ppos);
14298
14299 /* skip varint + inline data, if present */
14300 if (def->has_varint) {
14301 int llen;
14302 size_t slen = decode_varint((unsigned char *) a->mbuf.buf + *ppos, &llen);
14303 *ppos += llen;
14304 if (def->has_inlined) {
14305 *ppos += slen;
14306 }
14307 }
14308}
14309
14310V7_PRIVATE ast_off_t ast_insert_inlined_node(struct ast *a, ast_off_t pos,
14311 enum ast_tag tag, const char *name,
14312 size_t len) {
14313 const struct ast_node_def *d = &ast_node_defs[tag];
14314
14315 ast_off_t offset = ast_insert_node(a, pos, tag);
14316
14317 assert(d->has_inlined);
14318
14319 embed_string(&a->mbuf, offset + sizeof(ast_skip_t) * d->num_skips, name, len,
14320 EMBSTR_UNESCAPE);
14321
14322 return offset;
14323}
14324
14325V7_PRIVATE int ast_get_line_no(struct ast *a, ast_off_t pos) {
14326 /*
14327 * by default we'll return 0, meaning that the AST node does not contain line
14328 * number data
14329 */
14330 int ret = 0;
14331
14332#if !V7_DISABLE_LINE_NUMBERS
14333 uint8_t lineno_present;
14334 enum ast_tag tag = uint8_to_tag(*(a->mbuf.buf + pos - 1), &lineno_present);
14335
14336 if (lineno_present) {
14337 /* line number is present, so, let's decode it */
14338 int llen;
14339
14340 /* skip skips */
14341 pos += ast_node_defs[tag].num_skips * sizeof(ast_skip_t);
14342
14343 /* get line number */
14344 ret = decode_varint((unsigned char *) a->mbuf.buf + pos, &llen);
14345 }
14346#else
14347 (void) a;
14348 (void) pos;
14349#endif
14350
14351 return ret;
14352}
14353
14354V7_PRIVATE void ast_move_to_inlined_data(struct ast *a, ast_off_t *ppos) {
14355 uint8_t lineno_present = 0;
14356 enum ast_tag tag = uint8_to_tag(*(a->mbuf.buf + *ppos - 1), &lineno_present);
14357 const struct ast_node_def *def = &ast_node_defs[tag];
14358 assert(*ppos - 1 < a->mbuf.len);
14359
14360 /* skip skips */
14361 *ppos += def->num_skips * sizeof(ast_skip_t);
14362
14363 /* skip line_no, if present */
14364 if (lineno_present) {
14365 int llen;
14366 int line_no = decode_varint((unsigned char *) a->mbuf.buf + *ppos, &llen);
14367 *ppos += llen;
14368
14369 (void) line_no;
14370 }
14371}
14372
14373V7_PRIVATE char *ast_get_inlined_data(struct ast *a, ast_off_t pos, size_t *n) {
14374 int llen;
14375 assert(pos < a->mbuf.len);
14376
14377 ast_move_to_inlined_data(a, &pos);
14378
14379 *n = decode_varint((unsigned char *) a->mbuf.buf + pos, &llen);
14380 return a->mbuf.buf + pos + llen;
14381}
14382
14383V7_PRIVATE double ast_get_num(struct ast *a, ast_off_t pos) {
14384 double ret;
14385 char *str;
14386 size_t str_len;
14387 char buf[12];
14388 char *p = buf;
14389 str = ast_get_inlined_data(a, pos, &str_len);
14390 assert(str + str_len <= a->mbuf.buf + a->mbuf.len);
14391
14392 if (str_len > sizeof(buf) - 1) {
14393 p = (char *) malloc(str_len + 1);
14394 }
14395 strncpy(p, str, str_len);
14396 p[str_len] = '\0';
14397 ret = cs_strtod(p, NULL);
14398 if (p != buf) free(p);
14399 return ret;
14400}
14401
14402#ifndef NO_LIBC
14403static void comment_at_depth(FILE *fp, const char *fmt, int depth, ...) {
14404 int i;
14405 STATIC char buf[256];
14406 va_list ap;
14407 va_start(ap, depth);
14408
14409 c_vsnprintf(buf, sizeof(buf), fmt, ap);
14410
14411 for (i = 0; i < depth; i++) {
14412 fprintf(fp, " ");
14413 }
14414 fprintf(fp, "/* [%s] */\n", buf);
14415}
14416#endif
14417
14418V7_PRIVATE void ast_skip_tree(struct ast *a, ast_off_t *ppos) {
14419 enum ast_tag tag = ast_fetch_tag(a, ppos);
14420 const struct ast_node_def *def = &ast_node_defs[tag];
14421 ast_off_t skips = *ppos;
14422 int i;
14423 ast_move_to_children(a, ppos);
14424
14425 for (i = 0; i < def->num_subtrees; i++) {
14426 ast_skip_tree(a, ppos);
14427 }
14428
14429 if (def->num_skips > AST_END_SKIP) {
14430 ast_off_t end = ast_get_skip(a, skips, AST_END_SKIP);
14431
14432 while (*ppos < end) {
14433 ast_skip_tree(a, ppos);
14434 }
14435 }
14436}
14437
14438#ifndef NO_LIBC
14439V7_PRIVATE void ast_dump_tree(FILE *fp, struct ast *a, ast_off_t *ppos,
14440 int depth) {
14441 enum ast_tag tag = ast_fetch_tag(a, ppos);
14442 const struct ast_node_def *def = &ast_node_defs[tag];
14443 ast_off_t skips = *ppos;
14444 size_t slen;
14445 int i, llen;
14446
14447 for (i = 0; i < depth; i++) {
14448 fprintf(fp, " ");
14449 }
14450
14451#if !V7_DISABLE_AST_TAG_NAMES
14452 fprintf(fp, "%s", def->name);
14453#else
14454 fprintf(fp, "TAG_%d", tag);
14455#endif
14456
14457 if (def->has_inlined) {
14458 ast_off_t pos_tmp = *ppos;
14459 ast_move_to_inlined_data(a, &pos_tmp);
14460
14461 slen = decode_varint((unsigned char *) a->mbuf.buf + pos_tmp, &llen);
14462 fprintf(fp, " %.*s\n", (int) slen, a->mbuf.buf + pos_tmp + llen);
14463 } else {
14464 fprintf(fp, "\n");
14465 }
14466
14467 ast_move_to_children(a, ppos);
14468
14469 for (i = 0; i < def->num_subtrees; i++) {
14470 ast_dump_tree(fp, a, ppos, depth + 1);
14471 }
14472
14473 if (ast_node_defs[tag].num_skips) {
14474 /*
14475 * first skip always encodes end of the last children sequence.
14476 * so unless we care how the subtree sequences are grouped together
14477 * (and we currently don't) we can just read until the end of that skip.
14478 */
14479 ast_off_t end = ast_get_skip(a, skips, AST_END_SKIP);
14480
14481 comment_at_depth(fp, "...", depth + 1);
14482 while (*ppos < end) {
14483 int s;
14484 for (s = ast_node_defs[tag].num_skips - 1; s > 0; s--) {
14485 if (*ppos == ast_get_skip(a, skips, (enum ast_which_skip) s)) {
14486 comment_at_depth(fp, "%d ->", depth + 1, s);
14487 break;
14488 }
14489 }
14490 ast_dump_tree(fp, a, ppos, depth + 1);
14491 }
14492 }
14493}
14494#endif
14495
14496V7_PRIVATE void ast_init(struct ast *ast, size_t len) {
14497 mbuf_init(&ast->mbuf, len);
14498 ast->refcnt = 0;
14499 ast->has_overflow = 0;
14500}
14501
14502V7_PRIVATE void ast_optimize(struct ast *ast) {
14503 /*
14504 * leave one trailing byte so that literals can be
14505 * null terminated on the fly.
14506 */
14507 mbuf_resize(&ast->mbuf, ast->mbuf.len + 1);
14508}
14509
14510V7_PRIVATE void ast_free(struct ast *ast) {
14511 mbuf_free(&ast->mbuf);
14512 ast->refcnt = 0;
14513 ast->has_overflow = 0;
14514}
14515
14516V7_PRIVATE void release_ast(struct v7 *v7, struct ast *a) {
14517 (void) v7;
14518
14519 if (a->refcnt != 0) a->refcnt--;
14520
14521 if (a->refcnt == 0) {
14522#if V7_ENABLE__Memory__stats
14523 v7->function_arena_ast_size -= a->mbuf.size;
14524#endif
14525 ast_free(a);
14526 free(a);
14527 }
14528}
14529
14530#endif /* V7_NO_COMPILER */
14531#ifdef V7_MODULE_LINES
14532#line 1 "v7/src/bcode.c"
14533#endif
14534/*
14535 * Copyright (c) 2014 Cesanta Software Limited
14536 * All rights reserved
14537 */
14538
14539/* Amalgamated: #include "v7/src/internal.h" */
14540/* Amalgamated: #include "v7/src/bcode.h" */
14541/* Amalgamated: #include "v7/src/varint.h" */
14542/* Amalgamated: #include "v7/src/exceptions.h" */
14543/* Amalgamated: #include "v7/src/gc.h" */
14544/* Amalgamated: #include "v7/src/core.h" */
14545/* Amalgamated: #include "v7/src/regexp.h" */
14546/* Amalgamated: #include "v7/src/function.h" */
14547/* Amalgamated: #include "v7/src/util.h" */
14548/* Amalgamated: #include "v7/src/shdata.h" */
14549
14550/*
14551 * TODO(dfrank): implement `bcode_serialize_*` more generically, so that they
14552 * can write to buffer instead of a `FILE`. Then, remove a need for mmap here.
14553 */
14554#if CS_PLATFORM == CS_P_UNIX
14555#include <sys/mman.h>
14556#endif
14557
14558#if defined(V7_BCODE_DUMP) || defined(V7_BCODE_TRACE)
14559/* clang-format off */
14560static const char *op_names[] = {
14561 "DROP",
14562 "DUP",
14563 "2DUP",
14564 "SWAP",
14565 "STASH",
14566 "UNSTASH",
14567 "SWAP_DROP",
14568 "PUSH_UNDEFINED",
14569 "PUSH_NULL",
14570 "PUSH_THIS",
14571 "PUSH_TRUE",
14572 "PUSH_FALSE",
14573 "PUSH_ZERO",
14574 "PUSH_ONE",
14575 "PUSH_LIT",
14576 "NOT",
14577 "LOGICAL_NOT",
14578 "NEG",
14579 "POS",
14580 "ADD",
14581 "SUB",
14582 "REM",
14583 "MUL",
14584 "DIV",
14585 "LSHIFT",
14586 "RSHIFT",
14587 "URSHIFT",
14588 "OR",
14589 "XOR",
14590 "AND",
14591 "EQ_EQ",
14592 "EQ",
14593 "NE",
14594 "NE_NE",
14595 "LT",
14596 "LE",
14597 "GT",
14598 "GE",
14599 "INSTANCEOF",
14600 "TYPEOF",
14601 "IN",
14602 "GET",
14603 "SET",
14604 "SET_VAR",
14605 "GET_VAR",
14606 "SAFE_GET_VAR",
14607 "JMP",
14608 "JMP_TRUE",
14609 "JMP_FALSE",
14610 "JMP_TRUE_DROP",
14611 "JMP_IF_CONTINUE",
14612 "CREATE_OBJ",
14613 "CREATE_ARR",
14614 "PUSH_PROP_ITER_CTX",
14615 "NEXT_PROP",
14616 "FUNC_LIT",
14617 "CALL",
14618 "NEW",
14619 "CHECK_CALL",
14620 "RET",
14621 "DELETE",
14622 "DELETE_VAR",
14623 "TRY_PUSH_CATCH",
14624 "TRY_PUSH_FINALLY",
14625 "TRY_PUSH_LOOP",
14626 "TRY_PUSH_SWITCH",
14627 "TRY_POP",
14628 "AFTER_FINALLY",
14629 "THROW",
14630 "BREAK",
14631 "CONTINUE",
14632 "ENTER_CATCH",
14633 "EXIT_CATCH",
14634};
14635/* clang-format on */
14636
14637V7_STATIC_ASSERT(OP_MAX == ARRAY_SIZE(op_names), bad_op_names);
14638V7_STATIC_ASSERT(OP_MAX <= _OP_LINE_NO, bad_OP_LINE_NO);
14639#endif
14640
14641static void bcode_serialize_func(struct v7 *v7, struct bcode *bcode, FILE *out);
14642
14643static size_t bcode_ops_append(struct bcode_builder *bbuilder, const void *buf,
14644 size_t len) {
14645 size_t ret;
14646#if V7_ENABLE__Memory__stats
14647 bbuilder->v7->bcode_ops_size -= bbuilder->ops.len;
14648#endif
14649 ret = mbuf_append(&bbuilder->ops, buf, len);
14650#if V7_ENABLE__Memory__stats
14651 bbuilder->v7->bcode_ops_size += bbuilder->ops.len;
14652#endif
14653 return ret;
14654}
14655
14656/*
14657 * Initialize bcode builder. The `bcode` should be already initialized by the
14658 * caller, and should be empty (i.e. should not own any ops, literals, etc)
14659 *
14660 * TODO(dfrank) : probably make `bcode_builder_init()` to initialize `bcode`
14661 * as well
14662 */
14663V7_PRIVATE void bcode_builder_init(struct v7 *v7,
14664 struct bcode_builder *bbuilder,
14665 struct bcode *bcode) {
14666 memset(bbuilder, 0x00, sizeof(*bbuilder));
14667 bbuilder->v7 = v7;
14668 bbuilder->bcode = bcode;
14669
14670 mbuf_init(&bbuilder->ops, 0);
14671 mbuf_init(&bbuilder->lit, 0);
14672}
14673
14674/*
14675 * Finalize bcode builder: propagate data to the bcode and transfer the
14676 * ownership from builder to bcode
14677 */
14678V7_PRIVATE void bcode_builder_finalize(struct bcode_builder *bbuilder) {
14679 mbuf_trim(&bbuilder->ops);
14680 bbuilder->bcode->ops.p = bbuilder->ops.buf;
14681 bbuilder->bcode->ops.len = bbuilder->ops.len;
14682 mbuf_init(&bbuilder->ops, 0);
14683
14684 mbuf_trim(&bbuilder->lit);
14685 bbuilder->bcode->lit.p = bbuilder->lit.buf;
14686 bbuilder->bcode->lit.len = bbuilder->lit.len;
14687 mbuf_init(&bbuilder->lit, 0);
14688
14689 memset(bbuilder, 0x00, sizeof(*bbuilder));
14690}
14691
14692#if defined(V7_BCODE_DUMP) || defined(V7_BCODE_TRACE)
14693V7_PRIVATE void dump_op(struct v7 *v7, FILE *f, struct bcode *bcode,
14694 char **ops) {
14695 char *p = *ops;
14696
14697 assert(*p < OP_MAX);
14698 fprintf(f, "%zu: %s", (size_t)(p - bcode->ops.p), op_names[(uint8_t) *p]);
14699 switch (*p) {
14700 case OP_PUSH_LIT:
14701 case OP_SAFE_GET_VAR:
14702 case OP_GET_VAR:
14703 case OP_SET_VAR: {
14704 size_t idx = bcode_get_varint(&p);
14705 fprintf(f, "(%lu): ", (unsigned long) idx);
14706 v7_fprint(f, v7, ((val_t *) bcode->lit.p)[idx]);
14707 break;
14708 }
14709 case OP_CALL:
14710 case OP_NEW:
14711 p++;
14712 fprintf(f, "(%d)", *p);
14713 break;
14714 case OP_JMP:
14715 case OP_JMP_FALSE:
14716 case OP_JMP_TRUE:
14717 case OP_JMP_TRUE_DROP:
14718 case OP_JMP_IF_CONTINUE:
14719 case OP_TRY_PUSH_CATCH:
14720 case OP_TRY_PUSH_FINALLY:
14721 case OP_TRY_PUSH_LOOP:
14722 case OP_TRY_PUSH_SWITCH: {
14723 bcode_off_t target;
14724 p++;
14725 memcpy(&target, p, sizeof(target));
14726 fprintf(f, "(%lu)", (unsigned long) target);
14727 p += sizeof(target) - 1;
14728 break;
14729 }
14730 default:
14731 break;
14732 }
14733 fprintf(f, "\n");
14734 *ops = p;
14735}
14736#endif
14737
14738#ifdef V7_BCODE_DUMP
14739V7_PRIVATE void dump_bcode(struct v7 *v7, FILE *f, struct bcode *bcode) {
14740 char *p = bcode_end_names(bcode->ops.p, bcode->names_cnt);
14741 char *end = bcode->ops.p + bcode->ops.len;
14742 for (; p < end; p++) {
14743 dump_op(v7, f, bcode, &p);
14744 }
14745}
14746#endif
14747
14748V7_PRIVATE void bcode_init(struct bcode *bcode, uint8_t strict_mode,
14749 void *filename, uint8_t filename_in_rom) {
14750 memset(bcode, 0x00, sizeof(*bcode));
14751 bcode->refcnt = 0;
14752 bcode->args_cnt = 0;
14753 bcode->strict_mode = strict_mode;
14754#if !V7_DISABLE_FILENAMES
14755 bcode->filename = filename;
14756 bcode->filename_in_rom = filename_in_rom;
14757#else
14758 (void) filename;
14759 (void) filename_in_rom;
14760#endif
14761}
14762
14763V7_PRIVATE void bcode_free(struct v7 *v7, struct bcode *bcode) {
14764 (void) v7;
14765#if V7_ENABLE__Memory__stats
14766 if (!bcode->ops_in_rom) {
14767 v7->bcode_ops_size -= bcode->ops.len;
14768 }
14769
14770 v7->bcode_lit_total_size -= bcode->lit.len;
14771 if (bcode->deserialized) {
14772 v7->bcode_lit_deser_size -= bcode->lit.len;
14773 }
14774#endif
14775
14776 if (!bcode->ops_in_rom) {
14777 free(bcode->ops.p);
14778 }
14779 memset(&bcode->ops, 0x00, sizeof(bcode->ops));
14780
14781 free(bcode->lit.p);
14782 memset(&bcode->lit, 0x00, sizeof(bcode->lit));
14783
14784#if !V7_DISABLE_FILENAMES
14785 if (!bcode->filename_in_rom && bcode->filename != NULL) {
14786 shdata_release((struct shdata *) bcode->filename);
14787 bcode->filename = NULL;
14788 }
14789#endif
14790
14791 bcode->refcnt = 0;
14792}
14793
14794V7_PRIVATE void retain_bcode(struct v7 *v7, struct bcode *b) {
14795 (void) v7;
14796 if (!b->frozen) {
14797 b->refcnt++;
14798 }
14799}
14800
14801V7_PRIVATE void release_bcode(struct v7 *v7, struct bcode *b) {
14802 (void) v7;
14803 if (b->frozen) return;
14804
14805 assert(b->refcnt > 0);
14806 if (b->refcnt != 0) b->refcnt--;
14807
14808 if (b->refcnt == 0) {
14809 bcode_free(v7, b);
14810 free(b);
14811 }
14812}
14813
14814#if !V7_DISABLE_FILENAMES
14815V7_PRIVATE const char *bcode_get_filename(struct bcode *bcode) {
14816 const char *ret = NULL;
14817 if (bcode->filename_in_rom) {
14818 ret = (const char *) bcode->filename;
14819 } else if (bcode->filename != NULL) {
14820 ret = (const char *) shdata_get_payload((struct shdata *) bcode->filename);
14821 }
14822 return ret;
14823}
14824#endif
14825
14826V7_PRIVATE void bcode_copy_filename_from(struct bcode *dst, struct bcode *src) {
14827#if !V7_DISABLE_FILENAMES
14828 dst->filename_in_rom = src->filename_in_rom;
14829 dst->filename = src->filename;
14830
14831 if (src->filename != NULL && !src->filename_in_rom) {
14832 shdata_retain((struct shdata *) dst->filename);
14833 }
14834#else
14835 (void) dst;
14836 (void) src;
14837#endif
14838}
14839
14840V7_PRIVATE void bcode_op(struct bcode_builder *bbuilder, uint8_t op) {
14841 bcode_ops_append(bbuilder, &op, 1);
14842}
14843
14844#if !V7_DISABLE_LINE_NUMBERS
14845V7_PRIVATE void bcode_append_lineno(struct bcode_builder *bbuilder,
14846 int line_no) {
14847 int offset = bbuilder->ops.len;
14848 bcode_add_varint(bbuilder, (line_no << 1) | 1);
14849 bbuilder->ops.buf[offset] = msb_lsb_swap(bbuilder->ops.buf[offset]);
14850 assert(bbuilder->ops.buf[offset] & _OP_LINE_NO);
14851}
14852#endif
14853
14854/*
14855 * Appends varint-encoded integer to the `ops` mbuf
14856 */
14857V7_PRIVATE void bcode_add_varint(struct bcode_builder *bbuilder, size_t value) {
14858 int k = calc_llen(value); /* Calculate how many bytes length takes */
14859 int offset = bbuilder->ops.len;
14860
14861 /* Allocate buffer */
14862 bcode_ops_append(bbuilder, NULL, k);
14863
14864 /* Write value */
14865 encode_varint(value, (unsigned char *) bbuilder->ops.buf + offset);
14866}
14867
14868V7_PRIVATE size_t bcode_get_varint(char **ops) {
14869 size_t ret = 0;
14870 int len = 0;
14871 (*ops)++;
14872 ret = decode_varint((unsigned char *) *ops, &len);
14873 *ops += len - 1;
14874 return ret;
14875}
14876
14877static int bcode_is_inline_string(struct v7 *v7, val_t val) {
14878 uint64_t tag = val & V7_TAG_MASK;
14879 if (v7->is_precompiling && v7_is_string(val)) {
14880 return 1;
14881 }
14882 return tag == V7_TAG_STRING_I || tag == V7_TAG_STRING_5;
14883}
14884
14885static int bcode_is_inline_func(struct v7 *v7, val_t val) {
14886 return (v7->is_precompiling && is_js_function(val));
14887}
14888
14889static int bcode_is_inline_regexp(struct v7 *v7, val_t val) {
14890 return (v7->is_precompiling && v7_is_regexp(v7, val));
14891}
14892
14893V7_PRIVATE lit_t bcode_add_lit(struct bcode_builder *bbuilder, val_t val) {
14894 lit_t lit;
14895 memset(&lit, 0, sizeof(lit));
14896
14897 if (bcode_is_inline_string(bbuilder->v7, val) ||
14898 bcode_is_inline_func(bbuilder->v7, val) || v7_is_number(val) ||
14899 bcode_is_inline_regexp(bbuilder->v7, val)) {
14900 /* literal should be inlined (it's `bcode_op_lit()` who does this) */
14901 lit.mode = LIT_MODE__INLINED;
14902 lit.v.inline_val = val;
14903 } else {
14904 /* literal will now be added to the literal table */
14905 lit.mode = LIT_MODE__TABLE;
14906 lit.v.lit_idx = bbuilder->lit.len / sizeof(val);
14907
14908#if V7_ENABLE__Memory__stats
14909 bbuilder->v7->bcode_lit_total_size -= bbuilder->lit.len;
14910 if (bbuilder->bcode->deserialized) {
14911 bbuilder->v7->bcode_lit_deser_size -= bbuilder->lit.len;
14912 }
14913#endif
14914
14915 mbuf_append(&bbuilder->lit, &val, sizeof(val));
14916
14917 /*
14918 * immediately propagate current lit buffer to the bcode, so that GC will
14919 * be aware of it
14920 */
14921 bbuilder->bcode->lit.p = bbuilder->lit.buf;
14922 bbuilder->bcode->lit.len = bbuilder->lit.len;
14923
14924#if V7_ENABLE__Memory__stats
14925 bbuilder->v7->bcode_lit_total_size += bbuilder->lit.len;
14926 if (bbuilder->bcode->deserialized) {
14927 bbuilder->v7->bcode_lit_deser_size += bbuilder->lit.len;
14928 }
14929#endif
14930 }
14931 return lit;
14932}
14933
14934#if 0
14935V7_PRIVATE v7_val_t bcode_get_lit(struct bcode *bcode, size_t idx) {
14936 val_t ret;
14937 memcpy(&ret, bcode->lit.p + (size_t) idx * sizeof(ret), sizeof(ret));
14938 return ret;
14939}
14940#endif
14941
14942static const char *bcode_deserialize_func(struct v7 *v7, struct bcode *bcode,
14943 const char *data);
14944
14945V7_PRIVATE v7_val_t
14946bcode_decode_lit(struct v7 *v7, struct bcode *bcode, char **ops) {
14947 struct v7_vec *vec = &bcode->lit;
14948 size_t idx = bcode_get_varint(ops);
14949 switch (idx) {
14950 case BCODE_INLINE_STRING_TYPE_TAG: {
14951 val_t res;
14952 size_t len = bcode_get_varint(ops);
14953 res = v7_mk_string(
14954 v7, (const char *) *ops + 1 /*skip BCODE_INLINE_STRING_TYPE_TAG*/,
14955 len, !bcode->ops_in_rom);
14956 *ops += len + 1;
14957 return res;
14958 }
14959 case BCODE_INLINE_NUMBER_TYPE_TAG: {
14960 val_t res;
14961 memcpy(&res, *ops + 1 /*skip BCODE_INLINE_NUMBER_TYPE_TAG*/, sizeof(res));
14962 *ops += sizeof(res);
14963 return res;
14964 }
14965 case BCODE_INLINE_FUNC_TYPE_TAG: {
14966 /*
14967 * Create half-done function: without scope but _with_ prototype. Scope
14968 * will be set by `bcode_instantiate_function()`.
14969 *
14970 * The fact that the prototype is already set will make
14971 * `bcode_instantiate_function()` just set scope on this function,
14972 * instead of creating a new one.
14973 */
14974 val_t res = mk_js_function(v7, NULL, v7_mk_object(v7));
14975
14976 /* Create bcode in this half-done function */
14977 struct v7_js_function *func = get_js_function_struct(res);
14978
14979 func->bcode = (struct bcode *) calloc(1, sizeof(*func->bcode));
14980 bcode_init(func->bcode, bcode->strict_mode, NULL /* will be set below */,
14981 0);
14982 bcode_copy_filename_from(func->bcode, bcode);
14983 retain_bcode(v7, func->bcode);
14984
14985 /* deserialize the function's bcode from `ops` */
14986 *ops = (char *) bcode_deserialize_func(
14987 v7, func->bcode, *ops + 1 /*skip BCODE_INLINE_FUNC_TYPE_TAG*/);
14988
14989 /* decrement *ops, because it will be incremented by `eval_bcode` soon */
14990 *ops -= 1;
14991
14992 return res;
14993 }
14994 case BCODE_INLINE_REGEXP_TYPE_TAG: {
14995#if V7_ENABLE__RegExp
14996 enum v7_err rcode = V7_OK;
14997 val_t res;
14998 size_t len_src, len_flags;
14999 char *buf_src, *buf_flags;
15000
15001 len_src = bcode_get_varint(ops);
15002 buf_src = *ops + 1;
15003 *ops += len_src + 1 /* nul term */;
15004
15005 len_flags = bcode_get_varint(ops);
15006 buf_flags = *ops + 1;
15007 *ops += len_flags + 1 /* nul term */;
15008
15009 rcode = v7_mk_regexp(v7, buf_src, len_src, buf_flags, len_flags, &res);
15010 assert(rcode == V7_OK);
15011 (void) rcode;
15012
15013 return res;
15014#else
15015 fprintf(stderr, "Firmware is built without -DV7_ENABLE__RegExp\n");
15016 abort();
15017#endif
15018 }
15019 default:
15020 return ((val_t *) vec->p)[idx - BCODE_MAX_INLINE_TYPE_TAG];
15021 }
15022}
15023
15024V7_PRIVATE void bcode_op_lit(struct bcode_builder *bbuilder, enum opcode op,
15025 lit_t lit) {
15026 bcode_op(bbuilder, op);
15027
15028 switch (lit.mode) {
15029 case LIT_MODE__TABLE:
15030 bcode_add_varint(bbuilder, lit.v.lit_idx + BCODE_MAX_INLINE_TYPE_TAG);
15031 break;
15032
15033 case LIT_MODE__INLINED:
15034 if (v7_is_string(lit.v.inline_val)) {
15035 size_t len;
15036 const char *s = v7_get_string(bbuilder->v7, &lit.v.inline_val, &len);
15037 bcode_add_varint(bbuilder, BCODE_INLINE_STRING_TYPE_TAG);
15038 bcode_add_varint(bbuilder, len);
15039 bcode_ops_append(bbuilder, s, len + 1 /* nul term */);
15040 } else if (v7_is_number(lit.v.inline_val)) {
15041 bcode_add_varint(bbuilder, BCODE_INLINE_NUMBER_TYPE_TAG);
15042 /*
15043 * TODO(dfrank): we can save some memory by storing string
15044 * representation of a number here, instead of wasting 8 bytes for each
15045 * number.
15046 *
15047 * Alternatively, we can add more tags for integers, like
15048 * `BCODE_INLINE_S08_TYPE_TAG`, `BCODE_INLINE_S16_TYPE_TAG`, etc, since
15049 * integers are the most common numbers for sure.
15050 */
15051 bcode_ops_append(bbuilder, &lit.v.inline_val, sizeof(lit.v.inline_val));
15052 } else if (is_js_function(lit.v.inline_val)) {
15053/*
15054 * TODO(dfrank): implement `bcode_serialize_*` more generically, so
15055 * that they can write to buffer instead of a `FILE`. Then, remove this
15056 * workaround with `CS_PLATFORM == CS_P_UNIX`, `tmpfile()`, etc.
15057 */
15058#if CS_PLATFORM == CS_P_UNIX
15059 struct v7_js_function *func;
15060 FILE *fp = tmpfile();
15061 long len = 0;
15062 char *p;
15063
15064 func = get_js_function_struct(lit.v.inline_val);
15065
15066 /* we inline functions if only we're precompiling */
15067 assert(bbuilder->v7->is_precompiling);
15068
15069 bcode_add_varint(bbuilder, BCODE_INLINE_FUNC_TYPE_TAG);
15070 bcode_serialize_func(bbuilder->v7, func->bcode, fp);
15071
15072 fflush(fp);
15073
15074 len = ftell(fp);
15075
15076 p = (char *) mmap(NULL, len, PROT_WRITE, MAP_PRIVATE, fileno(fp), 0);
15077
15078 bcode_ops_append(bbuilder, p, len);
15079
15080 fclose(fp);
15081#endif
15082 } else if (v7_is_regexp(bbuilder->v7, lit.v.inline_val)) {
15083#if V7_ENABLE__RegExp
15084 struct v7_regexp *rp =
15085 v7_get_regexp_struct(bbuilder->v7, lit.v.inline_val);
15086 bcode_add_varint(bbuilder, BCODE_INLINE_REGEXP_TYPE_TAG);
15087
15088 /* append regexp source */
15089 {
15090 size_t len;
15091 const char *buf =
15092 v7_get_string(bbuilder->v7, &rp->regexp_string, &len);
15093 bcode_add_varint(bbuilder, len);
15094 bcode_ops_append(bbuilder, buf, len + 1 /* nul term */);
15095 }
15096
15097 /* append regexp flags */
15098 {
15099 char buf[_V7_REGEXP_MAX_FLAGS_LEN + 1 /* nul term */];
15100 size_t len = get_regexp_flags_str(bbuilder->v7, rp, buf);
15101 bcode_add_varint(bbuilder, len);
15102 bcode_ops_append(bbuilder, buf, len + 1 /* nul term */);
15103 }
15104#else
15105 fprintf(stderr, "Firmware is built without -DV7_ENABLE__RegExp\n");
15106 abort();
15107#endif
15108 } else {
15109 /* invalid type of inlined value */
15110 abort();
15111 }
15112 break;
15113
15114 default:
15115 /* invalid literal mode */
15116 abort();
15117 break;
15118 }
15119}
15120
15121V7_PRIVATE void bcode_push_lit(struct bcode_builder *bbuilder, lit_t lit) {
15122 bcode_op_lit(bbuilder, OP_PUSH_LIT, lit);
15123}
15124
15125WARN_UNUSED_RESULT
15126 /*V7_PRIVATE*/ enum v7_err
15127 bcode_add_name(struct bcode_builder *bbuilder, const char *p, size_t len,
15128 size_t *idx) {
15129 enum v7_err rcode = V7_OK;
15130 int llen;
15131 size_t ops_index;
15132
15133 /*
15134 * if name length is not provided, assume it's null-terminated and calculate
15135 * it
15136 */
15137 if (len == ~((size_t) 0)) {
15138 len = strlen(p);
15139 }
15140
15141 /* index at which to put name. If not provided, we'll append at the end */
15142 if (idx != NULL) {
15143 ops_index = *idx;
15144 } else {
15145 ops_index = bbuilder->ops.len;
15146 }
15147
15148 /* calculate how much varint len will take */
15149 llen = calc_llen(len);
15150
15151 /* reserve space in `ops` buffer */
15152 mbuf_insert(&bbuilder->ops, ops_index, NULL, llen + len + 1 /*null-term*/);
15153
15154 {
15155 char *ops = bbuilder->ops.buf + ops_index;
15156
15157 /* put varint len */
15158 ops += encode_varint(len, (unsigned char *) ops);
15159
15160 /* put string */
15161 memcpy(ops, p, len);
15162 ops += len;
15163
15164 /* null-terminate */
15165 *ops++ = 0x00;
15166
15167 if (idx != NULL) {
15168 *idx = ops - bbuilder->ops.buf;
15169 }
15170 }
15171
15172 /* maintain total number of names */
15173 if (bbuilder->bcode->names_cnt < V7_NAMES_CNT_MAX) {
15174 bbuilder->bcode->names_cnt++;
15175 } else {
15176 rcode = v7_throwf(bbuilder->v7, SYNTAX_ERROR, "Too many local variables");
15177 }
15178
15179 return rcode;
15180}
15181
15182/*V7_PRIVATE*/ char *bcode_end_names(char *ops, size_t names_cnt) {
15183 while (names_cnt--) {
15184 ops = bcode_next_name(ops, NULL, NULL);
15185 }
15186 return ops;
15187}
15188
15189V7_PRIVATE char *bcode_next_name(char *ops, char **pname, size_t *plen) {
15190 size_t len;
15191 int llen;
15192
15193 len = decode_varint((unsigned char *) ops, &llen);
15194
15195 ops += llen;
15196
15197 if (pname != NULL) {
15198 *pname = ops;
15199 }
15200
15201 if (plen != NULL) {
15202 *plen = len;
15203 }
15204
15205 ops += len + 1 /*null-terminator*/;
15206 return ops;
15207}
15208
15209V7_PRIVATE char *bcode_next_name_v(struct v7 *v7, struct bcode *bcode,
15210 char *ops, val_t *res) {
15211 char *name;
15212 size_t len;
15213
15214 ops = bcode_next_name(ops, &name, &len);
15215
15216 /*
15217 * If `ops` is in RAM, we create owned string, since the string may outlive
15218 * bcode. Otherwise (`ops` is in ROM), we create foreign string.
15219 */
15220 *res = v7_mk_string(v7, name, len, !bcode->ops_in_rom);
15221
15222 return ops;
15223}
15224
15225V7_PRIVATE bcode_off_t bcode_pos(struct bcode_builder *bbuilder) {
15226 return bbuilder->ops.len;
15227}
15228
15229/*
15230 * Appends a branch target and returns its location.
15231 * This location can be updated with bcode_patch_target.
15232 * To be issued following a JMP_* bytecode
15233 */
15234V7_PRIVATE bcode_off_t bcode_add_target(struct bcode_builder *bbuilder) {
15235 bcode_off_t pos = bcode_pos(bbuilder);
15236 bcode_off_t zero = 0;
15237 bcode_ops_append(bbuilder, &zero, sizeof(bcode_off_t));
15238 return pos;
15239}
15240
15241/*
15242 * Appends an op requiring a branch target. See bcode_add_target.
15243 *
15244 * This function is used only internally, but used in a complicated mix of
15245 * configurations, hence the commented V7_PRIVATE
15246 */
15247/*V7_PRIVATE*/ bcode_off_t bcode_op_target(struct bcode_builder *bbuilder,
15248 uint8_t op) {
15249 bcode_op(bbuilder, op);
15250 return bcode_add_target(bbuilder);
15251}
15252
15253/*V7_PRIVATE*/ void bcode_patch_target(struct bcode_builder *bbuilder,
15254 bcode_off_t label, bcode_off_t target) {
15255 memcpy(bbuilder->ops.buf + label, &target, sizeof(target));
15256}
15257
15258/*V7_PRIVATE*/ void bcode_serialize(struct v7 *v7, struct bcode *bcode,
15259 FILE *out) {
15260 (void) v7;
15261 (void) bcode;
15262
15263 fwrite(BIN_BCODE_SIGNATURE, sizeof(BIN_BCODE_SIGNATURE), 1, out);
15264 bcode_serialize_func(v7, bcode, out);
15265}
15266
15267static void bcode_serialize_varint(int n, FILE *out) {
15268 unsigned char buf[8];
15269 int k = calc_llen(n);
15270 encode_varint(n, buf);
15271 fwrite(buf, k, 1, out);
15272}
15273
15274static void bcode_serialize_func(struct v7 *v7, struct bcode *bcode,
15275 FILE *out) {
15276 struct v7_vec *vec;
15277 (void) v7;
15278
15279 /*
15280 * All literals should be inlined into `ops`, so we expect literals table
15281 * to be empty here
15282 */
15283 assert(bcode->lit.len == 0);
15284
15285 /* args_cnt */
15286 bcode_serialize_varint(bcode->args_cnt, out);
15287
15288 /* names_cnt */
15289 bcode_serialize_varint(bcode->names_cnt, out);
15290
15291 /* func_name_present */
15292 bcode_serialize_varint(bcode->func_name_present, out);
15293
15294 /*
15295 * bcode:
15296 * <varint> // opcodes length
15297 * <opcode>*
15298 */
15299 vec = &bcode->ops;
15300 bcode_serialize_varint(vec->len, out);
15301 fwrite(vec->p, vec->len, 1, out);
15302}
15303
15304static size_t bcode_deserialize_varint(const char **data) {
15305 size_t ret = 0;
15306 int len = 0;
15307 ret = decode_varint((const unsigned char *) (*data), &len);
15308 *data += len;
15309 return ret;
15310}
15311
15312static const char *bcode_deserialize_func(struct v7 *v7, struct bcode *bcode,
15313 const char *data) {
15314 size_t size;
15315 struct bcode_builder bbuilder;
15316
15317 bcode_builder_init(v7, &bbuilder, bcode);
15318
15319 /*
15320 * before deserializing, set the corresponding flag, so that metrics will be
15321 * updated accordingly
15322 */
15323 bcode->deserialized = 1;
15324
15325 /*
15326 * In serialized functions, all literals are inlined into `ops`, so we don't
15327 * deserialize them here in any way
15328 */
15329
15330 /* get number of args */
15331 bcode->args_cnt = bcode_deserialize_varint(&data);
15332
15333 /* get number of names */
15334 bcode->names_cnt = bcode_deserialize_varint(&data);
15335
15336 /* get whether the function name is present in `names` */
15337 bcode->func_name_present = bcode_deserialize_varint(&data);
15338
15339 /* get opcode size */
15340 size = bcode_deserialize_varint(&data);
15341
15342 bbuilder.ops.buf = (char *) data;
15343 bbuilder.ops.size = size;
15344 bbuilder.ops.len = size;
15345
15346 bcode->ops_in_rom = 1;
15347
15348 data += size;
15349
15350 bcode_builder_finalize(&bbuilder);
15351 return data;
15352}
15353
15354V7_PRIVATE void bcode_deserialize(struct v7 *v7, struct bcode *bcode,
15355 const char *data) {
15356 data = bcode_deserialize_func(v7, bcode, data);
15357}
15358#ifdef V7_MODULE_LINES
15359#line 1 "v7/src/eval.c"
15360#endif
15361/*
15362 * Copyright (c) 2014 Cesanta Software Limited
15363 * All rights reserved
15364 */
15365
15366/* Amalgamated: #include "common/str_util.h" */
15367/* Amalgamated: #include "v7/src/internal.h" */
15368/* Amalgamated: #include "v7/src/eval.h" */
15369/* Amalgamated: #include "v7/src/string.h" */
15370/* Amalgamated: #include "v7/src/array.h" */
15371/* Amalgamated: #include "v7/src/object.h" */
15372/* Amalgamated: #include "v7/src/gc.h" */
15373/* Amalgamated: #include "v7/src/compiler.h" */
15374/* Amalgamated: #include "v7/src/cyg_profile.h" */
15375/* Amalgamated: #include "v7/src/core.h" */
15376/* Amalgamated: #include "v7/src/function.h" */
15377/* Amalgamated: #include "v7/src/util.h" */
15378/* Amalgamated: #include "v7/src/shdata.h" */
15379/* Amalgamated: #include "v7/src/exceptions.h" */
15380/* Amalgamated: #include "v7/src/conversion.h" */
15381/* Amalgamated: #include "v7/src/varint.h" */
15382
15383/*
15384 * Bcode offsets in "try stack" are stored in JS numbers, i.e. in `double`s.
15385 * Apart from the offset itself, we also need some additional data:
15386 *
15387 * - type of the block that offset represents (`catch`, `finally`, `switch`,
15388 * or some loop)
15389 * - size of the stack when the block is created (needed when throwing, since
15390 * if exception is thrown from the middle of the expression, the stack may
15391 * have any arbitrary length)
15392 *
15393 * We bake all this data into integer part of the double (53 bits) :
15394 *
15395 * - 32 bits: bcode offset
15396 * - 3 bits: "tag": the type of the block
15397 * - 16 bits: stack size
15398 */
15399
15400/*
15401 * Widths of data parts
15402 */
15403#define LBLOCK_OFFSET_WIDTH 32
15404#define LBLOCK_TAG_WIDTH 3
15405#define LBLOCK_STACK_SIZE_WIDTH 16
15406
15407/*
15408 * Shifts of data parts
15409 */
15410#define LBLOCK_OFFSET_SHIFT (0)
15411#define LBLOCK_TAG_SHIFT (LBLOCK_OFFSET_SHIFT + LBLOCK_OFFSET_WIDTH)
15412#define LBLOCK_STACK_SIZE_SHIFT (LBLOCK_TAG_SHIFT + LBLOCK_TAG_WIDTH)
15413#define LBLOCK_TOTAL_WIDTH (LBLOCK_STACK_SIZE_SHIFT + LBLOCK_STACK_SIZE_WIDTH)
15414
15415/*
15416 * Masks of data parts
15417 */
15418#define LBLOCK_OFFSET_MASK \
15419 ((int64_t)(((int64_t) 1 << LBLOCK_OFFSET_WIDTH) - 1) << LBLOCK_OFFSET_SHIFT)
15420#define LBLOCK_TAG_MASK \
15421 ((int64_t)(((int64_t) 1 << LBLOCK_TAG_WIDTH) - 1) << LBLOCK_TAG_SHIFT)
15422#define LBLOCK_STACK_SIZE_MASK \
15423 ((int64_t)(((int64_t) 1 << LBLOCK_STACK_SIZE_WIDTH) - 1) \
15424 << LBLOCK_STACK_SIZE_SHIFT)
15425
15426/*
15427 * Self-check: make sure all the data can fit into double's mantissa
15428 */
15429#if (LBLOCK_TOTAL_WIDTH > 53)
15430#error lblock width is too large, it can't fit into double's mantissa
15431#endif
15432
15433/*
15434 * Tags that are used for bcode offsets in "try stack"
15435 */
15436#define LBLOCK_TAG_CATCH ((int64_t) 0x01 << LBLOCK_TAG_SHIFT)
15437#define LBLOCK_TAG_FINALLY ((int64_t) 0x02 << LBLOCK_TAG_SHIFT)
15438#define LBLOCK_TAG_LOOP ((int64_t) 0x03 << LBLOCK_TAG_SHIFT)
15439#define LBLOCK_TAG_SWITCH ((int64_t) 0x04 << LBLOCK_TAG_SHIFT)
15440
15441/*
15442 * Yields 32-bit bcode offset value
15443 */
15444#define LBLOCK_OFFSET(v) \
15445 ((bcode_off_t)(((v) &LBLOCK_OFFSET_MASK) >> LBLOCK_OFFSET_SHIFT))
15446
15447/*
15448 * Yields tag value (unshifted, to be compared with macros like
15449 * `LBLOCK_TAG_CATCH`, etc)
15450 */
15451#define LBLOCK_TAG(v) ((v) &LBLOCK_TAG_MASK)
15452
15453/*
15454 * Yields stack size
15455 */
15456#define LBLOCK_STACK_SIZE(v) \
15457 (((v) &LBLOCK_STACK_SIZE_MASK) >> LBLOCK_STACK_SIZE_SHIFT)
15458
15459/*
15460 * Yields `int64_t` value to be stored as a JavaScript number
15461 */
15462#define LBLOCK_ITEM_CREATE(offset, tag, stack_size) \
15463 ((int64_t)(offset) | (tag) | \
15464 (((int64_t)(stack_size)) << LBLOCK_STACK_SIZE_SHIFT))
15465
15466/*
15467 * make sure `bcode_off_t` is just 32-bit, so that it can fit in double
15468 * with 3-bit tag
15469 */
15470V7_STATIC_ASSERT((sizeof(bcode_off_t) * 8) == LBLOCK_OFFSET_WIDTH,
15471 wrong_size_of_bcode_off_t);
15472
15473#define PUSH(v) stack_push(&v7->stack, v)
15474#define POP() stack_pop(&v7->stack)
15475#define TOS() stack_tos(&v7->stack)
15476#define SP() stack_sp(&v7->stack)
15477
15478/*
15479 * Local-to-function block types that we might want to consider when unwinding
15480 * stack for whatever reason. see `unwind_local_blocks_stack()`.
15481 */
15482enum local_block {
15483 LOCAL_BLOCK_NONE = (0),
15484 LOCAL_BLOCK_CATCH = (1 << 0),
15485 LOCAL_BLOCK_FINALLY = (1 << 1),
15486 LOCAL_BLOCK_LOOP = (1 << 2),
15487 LOCAL_BLOCK_SWITCH = (1 << 3),
15488};
15489
15490/*
15491 * Like `V7_TRY()`, but to be used inside `eval_bcode()` only: you should
15492 * wrap all calls to cfunctions into `BTRY()` instead of `V7_TRY()`.
15493 *
15494 * If the provided function returns something other than `V7_OK`, this macro
15495 * calls `bcode_perform_throw`, which performs bcode stack unwinding.
15496 */
15497#define BTRY(call) \
15498 do { \
15499 enum v7_err _e = call; \
15500 (void) _you_should_use_BTRY_in_eval_bcode_only; \
15501 if (_e != V7_OK) { \
15502 V7_TRY(bcode_perform_throw(v7, &r, 0 /*don't take value from stack*/)); \
15503 goto op_done; \
15504 } \
15505 } while (0)
15506
15507V7_PRIVATE void stack_push(struct mbuf *s, val_t v) {
15508 mbuf_append(s, &v, sizeof(v));
15509}
15510
15511V7_PRIVATE val_t stack_pop(struct mbuf *s) {
15512 assert(s->len >= sizeof(val_t));
15513 s->len -= sizeof(val_t);
15514 return *(val_t *) (s->buf + s->len);
15515}
15516
15517V7_PRIVATE val_t stack_tos(struct mbuf *s) {
15518 assert(s->len >= sizeof(val_t));
15519 return *(val_t *) (s->buf + s->len - sizeof(val_t));
15520}
15521
15522#ifdef V7_BCODE_TRACE_STACK
15523V7_PRIVATE val_t stack_at(struct mbuf *s, size_t idx) {
15524 assert(s->len >= sizeof(val_t) * idx);
15525 return *(val_t *) (s->buf + s->len - sizeof(val_t) - idx * sizeof(val_t));
15526}
15527#endif
15528
15529V7_PRIVATE int stack_sp(struct mbuf *s) {
15530 return s->len / sizeof(val_t);
15531}
15532
15533/*
15534 * Delete a property with name `name`, `len` from an object `obj`. If the
15535 * object does not contain own property with the given `name`, moves to `obj`'s
15536 * prototype, and so on.
15537 *
15538 * If the property is eventually found, it is deleted, and `0` is returned.
15539 * Otherwise, `-1` is returned.
15540 *
15541 * If `len` is -1/MAXUINT/~0, then `name` must be 0-terminated.
15542 *
15543 * See `v7_del()` as well.
15544 */
15545static int del_property_deep(struct v7 *v7, val_t obj, const char *name,
15546 size_t len) {
15547 if (!v7_is_object(obj)) {
15548 return -1;
15549 }
15550 for (; obj != V7_NULL; obj = v7_get_proto(v7, obj)) {
15551 int del_res;
15552 if ((del_res = v7_del(v7, obj, name, len)) != -1) {
15553 return del_res;
15554 }
15555 }
15556 return -1;
15557}
15558
15559/* Visual studio 2012+ has signbit() */
15560#if defined(_MSC_VER) && _MSC_VER < 1700
15561static int signbit(double x) {
15562 double s = _copysign(1, x);
15563 return s < 0;
15564}
15565#endif
15566
15567static double b_int_bin_op(enum opcode op, double a, double b) {
15568 int32_t ia = isnan(a) || isinf(a) ? 0 : (int32_t)(int64_t) a;
15569 int32_t ib = isnan(b) || isinf(b) ? 0 : (int32_t)(int64_t) b;
15570
15571 switch (op) {
15572 case OP_LSHIFT:
15573 return (int32_t)((uint32_t) ia << ((uint32_t) ib & 31));
15574 case OP_RSHIFT:
15575 return ia >> ((uint32_t) ib & 31);
15576 case OP_URSHIFT:
15577 return (uint32_t) ia >> ((uint32_t) ib & 31);
15578 case OP_OR:
15579 return ia | ib;
15580 case OP_XOR:
15581 return ia ^ ib;
15582 case OP_AND:
15583 return ia & ib;
15584 default:
15585 assert(0);
15586 }
15587 return 0;
15588}
15589
15590static double b_num_bin_op(enum opcode op, double a, double b) {
15591 /*
15592 * For certain operations, the result is always NaN if either of arguments
15593 * is NaN
15594 */
15595 switch (op) {
15596 case OP_ADD:
15597 case OP_SUB:
15598 case OP_MUL:
15599 case OP_DIV:
15600 case OP_REM:
15601 if (isnan(a) || isnan(b)) {
15602 return NAN;
15603 }
15604 break;
15605 default:
15606 break;
15607 }
15608
15609 switch (op) {
15610 case OP_ADD: /* simple fixed width nodes with no payload */
15611 return a + b;
15612 case OP_SUB:
15613 return a - b;
15614 case OP_REM:
15615 if (b == 0 || isnan(b) || isnan(a) || isinf(b) || isinf(a)) {
15616 return NAN;
15617 }
15618 return (int) a % (int) b;
15619 case OP_MUL:
15620 return a * b;
15621 case OP_DIV:
15622 if (b == 0) {
15623 if (a == 0) return NAN;
15624 return (!signbit(a) == !signbit(b)) ? INFINITY : -INFINITY;
15625 }
15626 return a / b;
15627 case OP_LSHIFT:
15628 case OP_RSHIFT:
15629 case OP_URSHIFT:
15630 case OP_OR:
15631 case OP_XOR:
15632 case OP_AND:
15633 return b_int_bin_op(op, a, b);
15634 default:
15635 assert(0);
15636 }
15637 return 0;
15638}
15639
15640static int b_bool_bin_op(enum opcode op, double a, double b) {
15641#ifdef V7_BROKEN_NAN
15642 if (isnan(a) || isnan(b)) return op == OP_NE || op == OP_NE_NE;
15643#endif
15644
15645 switch (op) {
15646 case OP_EQ:
15647 case OP_EQ_EQ:
15648 return a == b;
15649 case OP_NE:
15650 case OP_NE_NE:
15651 return a != b;
15652 case OP_LT:
15653 return a < b;
15654 case OP_LE:
15655 return a <= b;
15656 case OP_GT:
15657 return a > b;
15658 case OP_GE:
15659 return a >= b;
15660 default:
15661 assert(0);
15662 }
15663 return 0;
15664}
15665
15666static bcode_off_t bcode_get_target(char **ops) {
15667 bcode_off_t target;
15668 (*ops)++;
15669 memcpy(&target, *ops, sizeof(target));
15670 *ops += sizeof(target) - 1;
15671 return target;
15672}
15673
15674struct bcode_registers {
15675 /*
15676 * TODO(dfrank): make it contain `struct v7_call_frame_bcode *`
15677 * and use `bcode_ops` in-place, or probably drop the `bcode_registers`
15678 * whatsoever
15679 */
15680 struct bcode *bcode;
15681 char *ops;
15682 char *end;
15683 unsigned int need_inc_ops : 1;
15684};
15685
15686/*
15687 * If returning from function implicitly, then set return value to `undefined`.
15688 *
15689 * And if function was called as a constructor, then make sure returned
15690 * value is an object.
15691 */
15692static void bcode_adjust_retval(struct v7 *v7, uint8_t is_explicit_return) {
15693 if (!is_explicit_return) {
15694 /* returning implicitly: set return value to `undefined` */
15695 POP();
15696 PUSH(V7_UNDEFINED);
15697 }
15698
15699 if (v7->call_stack->is_constructor && !v7_is_object(TOS())) {
15700 /* constructor is going to return non-object: replace it with `this` */
15701 POP();
15702 PUSH(v7_get_this(v7));
15703 }
15704}
15705
15706static void bcode_restore_registers(struct v7 *v7, struct bcode *bcode,
15707 struct bcode_registers *r) {
15708 r->bcode = bcode;
15709 r->ops = bcode->ops.p;
15710 r->end = r->ops + bcode->ops.len;
15711
15712 (void) v7;
15713}
15714
15715V7_PRIVATE struct v7_call_frame_base *find_call_frame(struct v7 *v7,
15716 uint8_t type_mask) {
15717 struct v7_call_frame_base *ret = v7->call_stack;
15718
15719 while (ret != NULL && !(ret->type_mask & type_mask)) {
15720 ret = ret->prev;
15721 }
15722
15723 return ret;
15724}
15725
15726static struct v7_call_frame_private *find_call_frame_private(struct v7 *v7) {
15727 return (struct v7_call_frame_private *) find_call_frame(
15728 v7, V7_CALL_FRAME_MASK_PRIVATE);
15729}
15730
15731static struct v7_call_frame_bcode *find_call_frame_bcode(struct v7 *v7) {
15732 return (struct v7_call_frame_bcode *) find_call_frame(
15733 v7, V7_CALL_FRAME_MASK_BCODE);
15734}
15735
15736#if 0
15737static struct v7_call_frame_cfunc *find_call_frame_cfunc(struct v7 *v7) {
15738 return (struct v7_call_frame_cfunc *) find_call_frame(
15739 v7, V7_CALL_FRAME_MASK_CFUNC);
15740}
15741#endif
15742
15743static struct v7_call_frame_base *create_call_frame(struct v7 *v7,
15744 size_t size) {
15745 struct v7_call_frame_base *call_frame_base = NULL;
15746
15747 call_frame_base = (struct v7_call_frame_base *) calloc(1, size);
15748
15749 /* save previous call frame */
15750 call_frame_base->prev = v7->call_stack;
15751
15752 /* by default, inherit line_no from the previous frame */
15753 if (v7->call_stack != NULL) {
15754 call_frame_base->line_no = v7->call_stack->line_no;
15755 }
15756
15757 return call_frame_base;
15758}
15759
15760static void init_call_frame_private(struct v7 *v7,
15761 struct v7_call_frame_private *call_frame,
15762 val_t scope) {
15763 /* make a snapshot of the current state */
15764 {
15765 struct v7_call_frame_private *cf = find_call_frame_private(v7);
15766 if (cf != NULL) {
15767 cf->stack_size = v7->stack.len;
15768 }
15769 }
15770
15771 /* set a type flag */
15772 call_frame->base.type_mask |= V7_CALL_FRAME_MASK_PRIVATE;
15773
15774 /* fill the new frame with data */
15775 call_frame->vals.scope = scope;
15776 /* `try_stack` will be lazily created in `eval_try_push()`*/
15777 call_frame->vals.try_stack = V7_UNDEFINED;
15778}
15779
15780static void init_call_frame_bcode(struct v7 *v7,
15781 struct v7_call_frame_bcode *call_frame,
15782 char *prev_bcode_ops, struct bcode *bcode,
15783 val_t this_obj, val_t scope,
15784 uint8_t is_constructor) {
15785 init_call_frame_private(v7, &call_frame->base, scope);
15786
15787 /* make a snapshot of the current state */
15788 {
15789 struct v7_call_frame_bcode *cf = find_call_frame_bcode(v7);
15790 if (cf != NULL) {
15791 cf->bcode_ops = prev_bcode_ops;
15792
15793 /* remember thrown value */
15794 cf->vals.thrown_error = v7->vals.thrown_error;
15795 cf->base.base.is_thrown = v7->is_thrown;
15796 }
15797 }
15798
15799 /* set a type flag */
15800 call_frame->base.base.type_mask |= V7_CALL_FRAME_MASK_BCODE;
15801
15802 /* fill the new frame with data */
15803 call_frame->bcode = bcode;
15804 call_frame->vals.this_obj = this_obj;
15805 call_frame->base.base.is_constructor = is_constructor;
15806}
15807
15808/*
15809 * Create new bcode call frame object and fill it with data
15810 */
15811static void append_call_frame_bcode(struct v7 *v7, char *prev_bcode_ops,
15812 struct bcode *bcode, val_t this_obj,
15813 val_t scope, uint8_t is_constructor) {
15814 struct v7_call_frame_bcode *call_frame =
15815 (struct v7_call_frame_bcode *) create_call_frame(v7, sizeof(*call_frame));
15816
15817 init_call_frame_bcode(v7, call_frame, prev_bcode_ops, bcode, this_obj, scope,
15818 is_constructor);
15819
15820 v7->call_stack = &call_frame->base.base;
15821}
15822
15823static void append_call_frame_private(struct v7 *v7, val_t scope) {
15824 struct v7_call_frame_private *call_frame =
15825 (struct v7_call_frame_private *) create_call_frame(v7,
15826 sizeof(*call_frame));
15827 init_call_frame_private(v7, call_frame, scope);
15828
15829 v7->call_stack = &call_frame->base;
15830}
15831
15832static void append_call_frame_cfunc(struct v7 *v7, val_t this_obj,
15833 v7_cfunction_t *cfunc) {
15834 struct v7_call_frame_cfunc *call_frame =
15835 (struct v7_call_frame_cfunc *) create_call_frame(v7, sizeof(*call_frame));
15836
15837 /* set a type flag */
15838 call_frame->base.type_mask |= V7_CALL_FRAME_MASK_CFUNC;
15839
15840 /* fill the new frame with data */
15841 call_frame->cfunc = cfunc;
15842 call_frame->vals.this_obj = this_obj;
15843
15844 v7->call_stack = &call_frame->base;
15845}
15846
15847/*
15848 * The caller's bcode object is needed because we have to restore literals
15849 * and `end` registers.
15850 *
15851 * TODO(mkm): put this state on a return stack
15852 *
15853 * Caller of bcode_perform_call is responsible for owning `call_frame`
15854 */
15855static enum v7_err bcode_perform_call(struct v7 *v7, v7_val_t scope_frame,
15856 struct v7_js_function *func,
15857 struct bcode_registers *r,
15858 val_t this_object, char *ops,
15859 uint8_t is_constructor) {
15860 /* new scope_frame will inherit from the function's scope */
15861 obj_prototype_set(v7, get_object_struct(scope_frame), &func->scope->base);
15862
15863 /* create new `call_frame` which will replace `v7->call_stack` */
15864 append_call_frame_bcode(v7, r->ops + 1, func->bcode, this_object, scope_frame,
15865 is_constructor);
15866
15867 bcode_restore_registers(v7, func->bcode, r);
15868
15869 /* adjust `ops` since names were already read from it */
15870 r->ops = ops;
15871
15872 /* `ops` already points to the needed instruction, no need to increment it */
15873 r->need_inc_ops = 0;
15874
15875 return V7_OK;
15876}
15877
15878/*
15879 * Apply data from the "private" call frame, typically after some other frame
15880 * was just unwound.
15881 *
15882 * The `call_frame` may actually be `NULL`, if the top frame was unwound.
15883 */
15884static void apply_frame_private(struct v7 *v7,
15885 struct v7_call_frame_private *call_frame) {
15886 /*
15887 * Adjust data stack length (restore saved).
15888 *
15889 * If `call_frame` is NULL, it means that the last call frame was just
15890 * unwound, and hence the data stack size should be 0.
15891 */
15892 size_t stack_size = (call_frame != NULL ? call_frame->stack_size : 0);
15893 assert(stack_size <= v7->stack.len);
15894 v7->stack.len = stack_size;
15895}
15896
15897/*
15898 * Apply data from the "bcode" call frame, typically after some other frame
15899 * was just unwound.
15900 *
15901 * The `call_frame` may actually be `NULL`, if the top frame was unwound; but
15902 * in this case, `r` must be `NULL` too, by design. See inline comment below.
15903 */
15904static void apply_frame_bcode(struct v7 *v7,
15905 struct v7_call_frame_bcode *call_frame,
15906 struct bcode_registers *r) {
15907 if (r != NULL) {
15908 /*
15909 * Note: if `r` is non-NULL, then `call_frame` should be non-NULL as well,
15910 * by design. If this invariant is violated, it means that
15911 * `unwind_stack_1level()` is misused.
15912 */
15913 assert(call_frame != NULL);
15914
15915 bcode_restore_registers(v7, call_frame->bcode, r);
15916 r->ops = call_frame->bcode_ops;
15917
15918 /*
15919 * restore thrown value if only there's no new thrown value
15920 * (otherwise, the new one overrides the previous one)
15921 */
15922 if (!v7->is_thrown) {
15923 v7->vals.thrown_error = call_frame->vals.thrown_error;
15924 v7->is_thrown = call_frame->base.base.is_thrown;
15925 }
15926 }
15927}
15928
15929/*
15930 * Unwinds `call_stack` by 1 frame.
15931 *
15932 * Returns the type of the unwound frame
15933 */
15934static v7_call_frame_mask_t unwind_stack_1level(struct v7 *v7,
15935 struct bcode_registers *r) {
15936 v7_call_frame_mask_t type_mask;
15937#ifdef V7_BCODE_TRACE
15938 fprintf(stderr, "unwinding stack by 1 level\n");
15939#endif
15940
15941 type_mask = v7->call_stack->type_mask;
15942
15943 /* drop the top frame */
15944 {
15945 struct v7_call_frame_base *tmp = v7->call_stack;
15946 v7->call_stack = v7->call_stack->prev;
15947 free(tmp);
15948 }
15949
15950 /*
15951 * depending on the unwound frame type, apply data from the top call frame(s)
15952 * which are still alive (if any)
15953 */
15954
15955 if (type_mask & V7_CALL_FRAME_MASK_PRIVATE) {
15956 apply_frame_private(v7, find_call_frame_private(v7));
15957 }
15958
15959 if (type_mask & V7_CALL_FRAME_MASK_BCODE) {
15960 apply_frame_bcode(v7, find_call_frame_bcode(v7), r);
15961 }
15962
15963 if (type_mask & V7_CALL_FRAME_MASK_CFUNC) {
15964 /* Nothing to do here at the moment */
15965 }
15966
15967 return type_mask;
15968}
15969
15970/*
15971 * Unwinds local "try stack" (i.e. local-to-current-function stack of nested
15972 * `try` blocks), looking for local-to-function blocks.
15973 *
15974 * Block types of interest are specified with `wanted_blocks_mask`: it's a
15975 * bitmask of `enum local_block` values.
15976 *
15977 * Only blocks of specified types will be considered, others will be dropped.
15978 *
15979 * If `restore_stack_size` is non-zero, the `v7->stack.len` will be restored
15980 * to the value saved when the block was created. This is useful when throwing,
15981 * since if we throw from the middle of the expression, the stack could have
15982 * any size. But you probably shouldn't set this flag when breaking and
15983 * returning, since it may hide real bugs in the opcode.
15984 *
15985 * Returns id of the block type that control was transferred into, or
15986 * `LOCAL_BLOCK_NONE` if no appropriate block was found. Note: returned value
15987 * contains at most 1 block bit; it can't contain multiple bits.
15988 */
15989static enum local_block unwind_local_blocks_stack(
15990 struct v7 *v7, struct bcode_registers *r, unsigned int wanted_blocks_mask,
15991 uint8_t restore_stack_size) {
15992 val_t arr = V7_UNDEFINED;
15993 struct gc_tmp_frame tf = new_tmp_frame(v7);
15994 enum local_block found_block = LOCAL_BLOCK_NONE;
15995 unsigned long length;
15996
15997 tmp_stack_push(&tf, &arr);
15998
15999 arr = find_call_frame_private(v7)->vals.try_stack;
16000 if (v7_is_array(v7, arr)) {
16001 /*
16002 * pop latest element from "try stack", loop until we need to transfer
16003 * control there
16004 */
16005 while ((length = v7_array_length(v7, arr)) > 0) {
16006 /* get latest offset from the "try stack" */
16007 int64_t offset = v7_get_double(v7, v7_array_get(v7, arr, length - 1));
16008 enum local_block cur_block = LOCAL_BLOCK_NONE;
16009
16010 /* get id of the current block type */
16011 switch (LBLOCK_TAG(offset)) {
16012 case LBLOCK_TAG_CATCH:
16013 cur_block = LOCAL_BLOCK_CATCH;
16014 break;
16015 case LBLOCK_TAG_FINALLY:
16016 cur_block = LOCAL_BLOCK_FINALLY;
16017 break;
16018 case LBLOCK_TAG_LOOP:
16019 cur_block = LOCAL_BLOCK_LOOP;
16020 break;
16021 case LBLOCK_TAG_SWITCH:
16022 cur_block = LOCAL_BLOCK_SWITCH;
16023 break;
16024 default:
16025 assert(0);
16026 break;
16027 }
16028
16029 if (cur_block & wanted_blocks_mask) {
16030 /* need to transfer control to this offset */
16031 r->ops = r->bcode->ops.p + LBLOCK_OFFSET(offset);
16032#ifdef V7_BCODE_TRACE
16033 fprintf(stderr, "transferring to block #%d: %u\n", (int) cur_block,
16034 (unsigned int) LBLOCK_OFFSET(offset));
16035#endif
16036 found_block = cur_block;
16037 /* if needed, restore stack size to the saved value */
16038 if (restore_stack_size) {
16039 v7->stack.len = LBLOCK_STACK_SIZE(offset);
16040 }
16041 break;
16042 } else {
16043#ifdef V7_BCODE_TRACE
16044 fprintf(stderr, "skipped block #%d: %u\n", (int) cur_block,
16045 (unsigned int) LBLOCK_OFFSET(offset));
16046#endif
16047 /*
16048 * since we don't need to control transfer there, just pop
16049 * it from the "try stack"
16050 */
16051 v7_array_del(v7, arr, length - 1);
16052 }
16053 }
16054 }
16055
16056 tmp_frame_cleanup(&tf);
16057 return found_block;
16058}
16059
16060/*
16061 * Perform break, if there is a `finally` block in effect, transfer
16062 * control there.
16063 */
16064static void bcode_perform_break(struct v7 *v7, struct bcode_registers *r) {
16065 enum local_block found;
16066 unsigned int mask;
16067 v7->is_breaking = 0;
16068 if (v7->is_continuing) {
16069 mask = LOCAL_BLOCK_LOOP;
16070 } else {
16071 mask = LOCAL_BLOCK_LOOP | LOCAL_BLOCK_SWITCH;
16072 }
16073
16074 /*
16075 * Keep unwinding until we find local block of interest. We should not
16076 * encounter any "function" frames; only "private" frames are allowed.
16077 */
16078 for (;;) {
16079 /*
16080 * Try to unwind local "try stack", considering only `finally` and `break`.
16081 */
16082 found = unwind_local_blocks_stack(v7, r, mask | LOCAL_BLOCK_FINALLY, 0);
16083 if (found == LOCAL_BLOCK_NONE) {
16084 /*
16085 * no blocks found: this may happen if only the `break` or `continue` has
16086 * occurred inside "private" frame. So, unwind this frame, make sure it
16087 * is indeed a "private" frame, and keep unwinding local blocks.
16088 */
16089 v7_call_frame_mask_t frame_type_mask = unwind_stack_1level(v7, r);
16090 assert(frame_type_mask == V7_CALL_FRAME_MASK_PRIVATE);
16091 (void) frame_type_mask;
16092 } else {
16093 /* found some block to transfer control into, stop unwinding */
16094 break;
16095 }
16096 }
16097
16098 /*
16099 * upon exit of a finally block we'll reenter here if is_breaking is true.
16100 * See OP_AFTER_FINALLY.
16101 */
16102 if (found == LOCAL_BLOCK_FINALLY) {
16103 v7->is_breaking = 1;
16104 }
16105
16106 /* `ops` already points to the needed instruction, no need to increment it */
16107 r->need_inc_ops = 0;
16108}
16109
16110/*
16111 * Perform return, but if there is a `finally` block in effect, transfer
16112 * control there.
16113 *
16114 * If `take_retval` is non-zero, value to return will be popped from stack
16115 * (and saved into `v7->vals.returned_value`), otherwise, it won't ae affected.
16116 */
16117static enum v7_err bcode_perform_return(struct v7 *v7,
16118 struct bcode_registers *r,
16119 int take_retval) {
16120 /*
16121 * We should either take retval from the stack, or some value should already
16122 * de pending to return
16123 */
16124 assert(take_retval || v7->is_returned);
16125
16126 if (take_retval) {
16127 /* taking return value from stack */
16128 v7->vals.returned_value = POP();
16129 v7->is_returned = 1;
16130
16131 /*
16132 * returning (say, from `finally`) dismisses any errors that are eeing
16133 * thrown at the moment as well
16134 */
16135 v7->is_thrown = 0;
16136 v7->vals.thrown_error = V7_UNDEFINED;
16137 }
16138
16139 /*
16140 * Keep unwinding until we unwound "function" frame, or found some `finally`
16141 * block.
16142 */
16143 for (;;) {
16144 /* Try to unwind local "try stack", considering only `finally` blocks */
16145 if (unwind_local_blocks_stack(v7, r, (LOCAL_BLOCK_FINALLY), 0) ==
16146 LOCAL_BLOCK_NONE) {
16147 /*
16148 * no `finally` blocks were found, so, unwind stack by 1 level, and see
16149 * if it's a "function" frame. If not, will keep unwinding.
16150 */
16151 if (unwind_stack_1level(v7, r) & V7_CALL_FRAME_MASK_BCODE) {
16152 /*
16153 * unwound frame is a "function" frame, so, push returned value to
16154 * stack, and stop unwinding
16155 */
16156 PUSH(v7->vals.returned_value);
16157 v7->is_returned = 0;
16158 v7->vals.returned_value = V7_UNDEFINED;
16159
16160 break;
16161 }
16162 } else {
16163 /* found `finally` block, so, stop unwinding */
16164 break;
16165 }
16166 }
16167
16168 /* `ops` already points to the needed instruction, no need to increment it */
16169 r->need_inc_ops = 0;
16170
16171 return V7_OK;
16172}
16173
16174/*
16175 * Perform throw inside `eval_bcode()`.
16176 *
16177 * If `take_thrown_value` is non-zero, value to return will be popped from
16178 * stack (and saved into `v7->vals.thrown_error`), otherwise, it won't be
16179 * affected.
16180 *
16181 * Returns `V7_OK` if thrown exception was caught, `V7_EXEC_EXCEPTION`
16182 * otherwise (in this case, evaluation of current script must be stopped)
16183 *
16184 * When calling this function from `eval_rcode()`, you should wrap this call
16185 * into the `V7_TRY()` macro.
16186 */
16187static enum v7_err bcode_perform_throw(struct v7 *v7, struct bcode_registers *r,
16188 int take_thrown_value) {
16189 enum v7_err rcode = V7_OK;
16190 enum local_block found;
16191
16192 assert(take_thrown_value || v7->is_thrown);
16193
16194 if (take_thrown_value) {
16195 v7->vals.thrown_error = POP();
16196 v7->is_thrown = 1;
16197
16198 /* Throwing dismisses any pending return values */
16199 v7->is_returned = 0;
16200 v7->vals.returned_value = V7_UNDEFINED;
16201 }
16202
16203 while ((found = unwind_local_blocks_stack(
16204 v7, r, (LOCAL_BLOCK_CATCH | LOCAL_BLOCK_FINALLY), 1)) ==
16205 LOCAL_BLOCK_NONE) {
16206 if (v7->call_stack != v7->bottom_call_frame) {
16207#ifdef V7_BCODE_TRACE
16208 fprintf(stderr, "not at the bottom of the stack, going to unwind..\n");
16209#endif
16210 /* not reached bottom of the stack yet, keep unwinding */
16211 unwind_stack_1level(v7, r);
16212 } else {
16213/* reached stack bottom: uncaught exception */
16214#ifdef V7_BCODE_TRACE
16215 fprintf(stderr, "reached stack bottom: uncaught exception\n");
16216#endif
16217 rcode = V7_EXEC_EXCEPTION;
16218 break;
16219 }
16220 }
16221
16222 if (found == LOCAL_BLOCK_CATCH) {
16223 /*
16224 * we're going to enter `catch` block, so, populate TOS with the thrown
16225 * value, and clear it in v7 context.
16226 */
16227 PUSH(v7->vals.thrown_error);
16228 v7->is_thrown = 0;
16229 v7->vals.thrown_error = V7_UNDEFINED;
16230 }
16231
16232 /* `ops` already points to the needed instruction, no need to increment it */
16233 r->need_inc_ops = 0;
16234
16235 return rcode;
16236}
16237
16238/*
16239 * Throws reference error from `eval_bcode()`. Always wrap a call to this
16240 * function into `V7_TRY()`.
16241 */
16242static enum v7_err bcode_throw_reference_error(struct v7 *v7,
16243 struct bcode_registers *r,
16244 val_t var_name) {
16245 enum v7_err rcode = V7_OK;
16246 const char *s;
16247 size_t name_len;
16248
16249 assert(v7_is_string(var_name));
16250 s = v7_get_string(v7, &var_name, &name_len);
16251
16252 rcode = v7_throwf(v7, REFERENCE_ERROR, "[%.*s] is not defined",
16253 (int) name_len, s);
16254 (void) rcode;
16255 return bcode_perform_throw(v7, r, 0);
16256}
16257
16258/*
16259 * Takes a half-done function (either from literal table or deserialized from
16260 * `ops` inlined data), and returns a ready-to-use function.
16261 *
16262 * The actual behaviour depends on whether the half-done function has
16263 * `prototype` defined. If there's no prototype (i.e. it's `undefined`), then
16264 * the new function is created, with bcode from a given one. If, however,
16265 * the prototype is defined, it means that the function was just deserialized
16266 * from `ops`, so we only need to set `scope` on it.
16267 *
16268 * Assumes `func` is owned by the caller.
16269 */
16270static val_t bcode_instantiate_function(struct v7 *v7, val_t func) {
16271 val_t res;
16272 struct v7_generic_object *scope;
16273 struct v7_js_function *f;
16274 assert(is_js_function(func));
16275 f = get_js_function_struct(func);
16276
16277 scope = get_generic_object_struct(get_scope(v7));
16278
16279 if (v7_is_undefined(v7_get(v7, func, "prototype", 9))) {
16280 /*
16281 * Function's `prototype` is `undefined`: it means that the function is
16282 * created by the compiler and is stored in the literal table. We have to
16283 * create completely new function
16284 */
16285 struct v7_js_function *rf;
16286
16287 res = mk_js_function(v7, scope, v7_mk_object(v7));
16288
16289 /* Copy and retain bcode */
16290 rf = get_js_function_struct(res);
16291 rf->bcode = f->bcode;
16292 retain_bcode(v7, rf->bcode);
16293 } else {
16294 /*
16295 * Function's `prototype` is NOT `undefined`: it means that the function is
16296 * deserialized from inline `ops` data, and we just need to set scope on
16297 * it.
16298 */
16299 res = func;
16300 f->scope = scope;
16301 }
16302
16303 return res;
16304}
16305
16306/**
16307 * Call C function `func` with given `this_object` and array of arguments
16308 * `args`. `func` should be a C function pointer, not C function object.
16309 */
16310static enum v7_err call_cfunction(struct v7 *v7, val_t func, val_t this_object,
16311 val_t args, uint8_t is_constructor,
16312 val_t *res) {
16313 enum v7_err rcode = V7_OK;
16314 uint8_t saved_inhibit_gc = v7->inhibit_gc;
16315 val_t saved_arguments = v7->vals.arguments;
16316 struct gc_tmp_frame tf = new_tmp_frame(v7);
16317 v7_cfunction_t *cfunc = get_cfunction_ptr(v7, func);
16318
16319 *res = V7_UNDEFINED;
16320
16321 tmp_stack_push(&tf, &saved_arguments);
16322
16323 append_call_frame_cfunc(v7, this_object, cfunc);
16324
16325 /*
16326 * prepare cfunction environment
16327 */
16328 v7->inhibit_gc = 1;
16329 v7->vals.arguments = args;
16330
16331 /* call C function */
16332 rcode = cfunc(v7, res);
16333 if (rcode != V7_OK) {
16334 goto clean;
16335 }
16336
16337 if (is_constructor && !v7_is_object(*res)) {
16338 /* constructor returned non-object: replace it with `this` */
16339 *res = v7_get_this(v7);
16340 }
16341
16342clean:
16343 v7->vals.arguments = saved_arguments;
16344 v7->inhibit_gc = saved_inhibit_gc;
16345
16346 unwind_stack_1level(v7, NULL);
16347
16348 tmp_frame_cleanup(&tf);
16349 return rcode;
16350}
16351
16352/*
16353 * Evaluate `OP_TRY_PUSH_CATCH` or `OP_TRY_PUSH_FINALLY`: Take an offset (from
16354 * the parameter of opcode) and push it onto "try stack"
16355 */
16356static void eval_try_push(struct v7 *v7, enum opcode op,
16357 struct bcode_registers *r) {
16358 val_t arr = V7_UNDEFINED;
16359 struct gc_tmp_frame tf = new_tmp_frame(v7);
16360 bcode_off_t target;
16361 int64_t offset_tag = 0;
16362
16363 tmp_stack_push(&tf, &arr);
16364
16365 /* make sure "try stack" array exists */
16366 arr = find_call_frame_private(v7)->vals.try_stack;
16367 if (!v7_is_array(v7, arr)) {
16368 arr = v7_mk_dense_array(v7);
16369 find_call_frame_private(v7)->vals.try_stack = arr;
16370 }
16371
16372 /*
16373 * push the target address at the end of the "try stack" array
16374 */
16375 switch (op) {
16376 case OP_TRY_PUSH_CATCH:
16377 offset_tag = LBLOCK_TAG_CATCH;
16378 break;
16379 case OP_TRY_PUSH_FINALLY:
16380 offset_tag = LBLOCK_TAG_FINALLY;
16381 break;
16382 case OP_TRY_PUSH_LOOP:
16383 offset_tag = LBLOCK_TAG_LOOP;
16384 break;
16385 case OP_TRY_PUSH_SWITCH:
16386 offset_tag = LBLOCK_TAG_SWITCH;
16387 break;
16388 default:
16389 assert(0);
16390 break;
16391 }
16392 target = bcode_get_target(&r->ops);
16393 v7_array_push(v7, arr, v7_mk_number(v7, LBLOCK_ITEM_CREATE(target, offset_tag,
16394 v7->stack.len)));
16395
16396 tmp_frame_cleanup(&tf);
16397}
16398
16399/*
16400 * Evaluate `OP_TRY_POP`: just pop latest item from "try stack", ignoring it
16401 */
16402static enum v7_err eval_try_pop(struct v7 *v7) {
16403 enum v7_err rcode = V7_OK;
16404 val_t arr = V7_UNDEFINED;
16405 unsigned long length;
16406 struct gc_tmp_frame tf = new_tmp_frame(v7);
16407
16408 tmp_stack_push(&tf, &arr);
16409
16410 /* get "try stack" array, which must be defined and must not be emtpy */
16411 arr = find_call_frame_private(v7)->vals.try_stack;
16412 if (!v7_is_array(v7, arr)) {
16413 rcode = v7_throwf(v7, "Error", "TRY_POP when try_stack is not an array");
16414 V7_TRY(V7_INTERNAL_ERROR);
16415 }
16416
16417 length = v7_array_length(v7, arr);
16418 if (length == 0) {
16419 rcode = v7_throwf(v7, "Error", "TRY_POP when try_stack is empty");
16420 V7_TRY(V7_INTERNAL_ERROR);
16421 }
16422
16423 /* delete the latest element of this array */
16424 v7_array_del(v7, arr, length - 1);
16425
16426clean:
16427 tmp_frame_cleanup(&tf);
16428 return rcode;
16429}
16430
16431static void own_bcode(struct v7 *v7, struct bcode *p) {
16432 mbuf_append(&v7->act_bcodes, &p, sizeof(p));
16433}
16434
16435static void disown_bcode(struct v7 *v7, struct bcode *p) {
16436#ifndef NDEBUG
16437 struct bcode **vp =
16438 (struct bcode **) (v7->act_bcodes.buf + v7->act_bcodes.len - sizeof(p));
16439
16440 /* given `p` should be the last item */
16441 assert(*vp == p);
16442#endif
16443 v7->act_bcodes.len -= sizeof(p);
16444}
16445
16446/* Keeps track of last evaluated bcodes in order to improve error reporting */
16447static void push_bcode_history(struct v7 *v7, enum opcode op) {
16448 size_t i;
16449
16450 if (op == OP_CHECK_CALL || op == OP_CALL || op == OP_NEW) return;
16451
16452 for (i = ARRAY_SIZE(v7->last_ops) - 1; i > 0; i--) {
16453 v7->last_ops[i] = v7->last_ops[i - 1];
16454 }
16455 v7->last_ops[0] = op;
16456}
16457
16458#if !V7_DISABLE_CALL_ERROR_CONTEXT
16459static void reset_last_name(struct v7 *v7) {
16460 v7->vals.last_name[0] = V7_UNDEFINED;
16461 v7->vals.last_name[1] = V7_UNDEFINED;
16462}
16463#else
16464static void reset_last_name(struct v7 *v7) {
16465 /* should be inlined out */
16466 (void) v7;
16467}
16468#endif
16469
16470static void prop_iter_ctx_dtor(struct v7 *v7, void *ud) {
16471 struct prop_iter_ctx *ctx = (struct prop_iter_ctx *) ud;
16472 v7_destruct_prop_iter_ctx(v7, ctx);
16473 free(ctx);
16474}
16475
16476/*
16477 * Evaluates given `bcode`. If `reset_line_no` is non-zero, the line number
16478 * is initially reset to 1; otherwise, it is inherited from the previous call
16479 * frame.
16480 */
16481WARN_UNUSED_RESULT
16482V7_PRIVATE enum v7_err eval_bcode(struct v7 *v7, struct bcode *bcode,
16483 val_t this_object, uint8_t reset_line_no,
16484 val_t *_res) {
16485 struct bcode_registers r;
16486 enum v7_err rcode = V7_OK;
16487 struct v7_call_frame_base *saved_bottom_call_frame = v7->bottom_call_frame;
16488
16489 /*
16490 * Dummy variable just to enforce that `BTRY()` macro is used only inside the
16491 * `eval_bcode()` function
16492 */
16493 uint8_t _you_should_use_BTRY_in_eval_bcode_only = 0;
16494
16495 char buf[512];
16496
16497 val_t res = V7_UNDEFINED, v1 = V7_UNDEFINED, v2 = V7_UNDEFINED,
16498 v3 = V7_UNDEFINED, v4 = V7_UNDEFINED, scope_frame = V7_UNDEFINED;
16499 struct gc_tmp_frame tf = new_tmp_frame(v7);
16500
16501 append_call_frame_bcode(v7, NULL, bcode, this_object, get_scope(v7), 0);
16502
16503 if (reset_line_no) {
16504 v7->call_stack->line_no = 1;
16505 }
16506
16507 /*
16508 * Set current call stack as the "bottom" call stack, so that bcode evaluator
16509 * will exit when it reaches this "bottom"
16510 */
16511 v7->bottom_call_frame = v7->call_stack;
16512
16513 bcode_restore_registers(v7, bcode, &r);
16514
16515 tmp_stack_push(&tf, &res);
16516 tmp_stack_push(&tf, &v1);
16517 tmp_stack_push(&tf, &v2);
16518 tmp_stack_push(&tf, &v3);
16519 tmp_stack_push(&tf, &v4);
16520 tmp_stack_push(&tf, &scope_frame);
16521
16522 /*
16523 * populate local variables on current scope, making them undeletable
16524 * (since they're defined with `var`)
16525 */
16526 {
16527 size_t i;
16528 for (i = 0; i < bcode->names_cnt; ++i) {
16529 r.ops = bcode_next_name_v(v7, bcode, r.ops, &v1);
16530
16531 /* set undeletable property on current scope */
16532 V7_TRY(def_property_v(v7, get_scope(v7), v1, V7_DESC_CONFIGURABLE(0),
16533 V7_UNDEFINED, 1 /*as_assign*/, NULL));
16534 }
16535 }
16536
16537restart:
16538 while (r.ops < r.end && rcode == V7_OK) {
16539 enum opcode op = (enum opcode) * r.ops;
16540
16541#if !V7_DISABLE_LINE_NUMBERS
16542 if ((uint8_t) op >= _OP_LINE_NO) {
16543 unsigned char buf[sizeof(size_t)];
16544 int len;
16545 size_t max_llen = sizeof(buf);
16546
16547 /* ASAN doesn't like out of bound reads */
16548 if (r.ops + max_llen > r.end) {
16549 max_llen = r.end - r.ops;
16550 }
16551
16552 /*
16553 * before we decode varint, we'll have to swap MSB and LSB, but we can't
16554 * do it in place since we're decoding from constant memory, so, we also
16555 * have to copy the data to the temp buffer first. 4 bytes should be
16556 * enough for everyone's line number.
16557 */
16558 memcpy(buf, r.ops, max_llen);
16559 buf[0] = msb_lsb_swap(buf[0]);
16560
16561 v7->call_stack->line_no = decode_varint(buf, &len) >> 1;
16562 assert((size_t) len <= sizeof(buf));
16563 r.ops += len;
16564
16565 continue;
16566 }
16567#endif
16568
16569 push_bcode_history(v7, op);
16570
16571 if (v7->need_gc) {
16572 if (maybe_gc(v7)) {
16573 v7->need_gc = 0;
16574 }
16575 }
16576
16577 r.need_inc_ops = 1;
16578#ifdef V7_BCODE_TRACE
16579 {
16580 char *dops = r.ops;
16581 fprintf(stderr, "eval ");
16582 dump_op(v7, stderr, r.bcode, &dops);
16583 }
16584#endif
16585
16586 switch (op) {
16587 case OP_DROP:
16588 POP();
16589 break;
16590 case OP_DUP:
16591 v1 = POP();
16592 PUSH(v1);
16593 PUSH(v1);
16594 break;
16595 case OP_2DUP:
16596 v2 = POP();
16597 v1 = POP();
16598 PUSH(v1);
16599 PUSH(v2);
16600 PUSH(v1);
16601 PUSH(v2);
16602 break;
16603 case OP_SWAP:
16604 v1 = POP();
16605 v2 = POP();
16606 PUSH(v1);
16607 PUSH(v2);
16608 break;
16609 case OP_STASH:
16610 assert(!v7->is_stashed);
16611 v7->vals.stash = TOS();
16612 v7->is_stashed = 1;
16613 break;
16614 case OP_UNSTASH:
16615 assert(v7->is_stashed);
16616 POP();
16617 PUSH(v7->vals.stash);
16618 v7->vals.stash = V7_UNDEFINED;
16619 v7->is_stashed = 0;
16620 break;
16621
16622 case OP_SWAP_DROP:
16623 v1 = POP();
16624 POP();
16625 PUSH(v1);
16626 break;
16627
16628 case OP_PUSH_UNDEFINED:
16629 PUSH(V7_UNDEFINED);
16630 break;
16631 case OP_PUSH_NULL:
16632 PUSH(V7_NULL);
16633 break;
16634 case OP_PUSH_THIS:
16635 PUSH(v7_get_this(v7));
16636 reset_last_name(v7);
16637 break;
16638 case OP_PUSH_TRUE:
16639 PUSH(v7_mk_boolean(v7, 1));
16640 reset_last_name(v7);
16641 break;
16642 case OP_PUSH_FALSE:
16643 PUSH(v7_mk_boolean(v7, 0));
16644 reset_last_name(v7);
16645 break;
16646 case OP_PUSH_ZERO:
16647 PUSH(v7_mk_number(v7, 0));
16648 reset_last_name(v7);
16649 break;
16650 case OP_PUSH_ONE:
16651 PUSH(v7_mk_number(v7, 1));
16652 reset_last_name(v7);
16653 break;
16654 case OP_PUSH_LIT: {
16655 PUSH(bcode_decode_lit(v7, r.bcode, &r.ops));
16656#if !V7_DISABLE_CALL_ERROR_CONTEXT
16657 /* name tracking */
16658 if (!v7_is_string(TOS())) {
16659 reset_last_name(v7);
16660 }
16661#endif
16662 break;
16663 }
16664 case OP_LOGICAL_NOT:
16665 v1 = POP();
16666 PUSH(v7_mk_boolean(v7, !v7_is_truthy(v7, v1)));
16667 break;
16668 case OP_NOT: {
16669 v1 = POP();
16670 BTRY(to_number_v(v7, v1, &v1));
16671 PUSH(v7_mk_number(v7, ~(int32_t) v7_get_double(v7, v1)));
16672 break;
16673 }
16674 case OP_NEG: {
16675 v1 = POP();
16676 BTRY(to_number_v(v7, v1, &v1));
16677 PUSH(v7_mk_number(v7, -v7_get_double(v7, v1)));
16678 break;
16679 }
16680 case OP_POS: {
16681 v1 = POP();
16682 BTRY(to_number_v(v7, v1, &v1));
16683 PUSH(v1);
16684 break;
16685 }
16686 case OP_ADD: {
16687 v2 = POP();
16688 v1 = POP();
16689
16690 /*
16691 * If either operand is an object, convert both of them to primitives
16692 */
16693 if (v7_is_object(v1) || v7_is_object(v2)) {
16694 BTRY(to_primitive(v7, v1, V7_TO_PRIMITIVE_HINT_AUTO, &v1));
16695 BTRY(to_primitive(v7, v2, V7_TO_PRIMITIVE_HINT_AUTO, &v2));
16696 }
16697
16698 if (v7_is_string(v1) || v7_is_string(v2)) {
16699 /* Convert both operands to strings, and concatenate */
16700
16701 BTRY(primitive_to_str(v7, v1, &v1, NULL, 0, NULL));
16702 BTRY(primitive_to_str(v7, v2, &v2, NULL, 0, NULL));
16703
16704 PUSH(s_concat(v7, v1, v2));
16705 } else {
16706 /* Convert both operands to numbers, and sum */
16707
16708 BTRY(primitive_to_number(v7, v1, &v1));
16709 BTRY(primitive_to_number(v7, v2, &v2));
16710
16711 PUSH(v7_mk_number(v7, b_num_bin_op(op, v7_get_double(v7, v1),
16712 v7_get_double(v7, v2))));
16713 }
16714 break;
16715 }
16716 case OP_SUB:
16717 case OP_REM:
16718 case OP_MUL:
16719 case OP_DIV:
16720 case OP_LSHIFT:
16721 case OP_RSHIFT:
16722 case OP_URSHIFT:
16723 case OP_OR:
16724 case OP_XOR:
16725 case OP_AND: {
16726 v2 = POP();
16727 v1 = POP();
16728
16729 BTRY(to_number_v(v7, v1, &v1));
16730 BTRY(to_number_v(v7, v2, &v2));
16731
16732 PUSH(v7_mk_number(v7, b_num_bin_op(op, v7_get_double(v7, v1),
16733 v7_get_double(v7, v2))));
16734 break;
16735 }
16736 case OP_EQ_EQ: {
16737 v2 = POP();
16738 v1 = POP();
16739 if (v7_is_string(v1) && v7_is_string(v2)) {
16740 res = v7_mk_boolean(v7, s_cmp(v7, v1, v2) == 0);
16741 } else if (v1 == v2 && v1 == V7_TAG_NAN) {
16742 res = v7_mk_boolean(v7, 0);
16743 } else {
16744 res = v7_mk_boolean(v7, v1 == v2);
16745 }
16746 PUSH(res);
16747 break;
16748 }
16749 case OP_NE_NE: {
16750 v2 = POP();
16751 v1 = POP();
16752 if (v7_is_string(v1) && v7_is_string(v2)) {
16753 res = v7_mk_boolean(v7, s_cmp(v7, v1, v2) != 0);
16754 } else if (v1 == v2 && v1 == V7_TAG_NAN) {
16755 res = v7_mk_boolean(v7, 1);
16756 } else {
16757 res = v7_mk_boolean(v7, v1 != v2);
16758 }
16759 PUSH(res);
16760 break;
16761 }
16762 case OP_EQ:
16763 case OP_NE: {
16764 v2 = POP();
16765 v1 = POP();
16766 /*
16767 * TODO(dfrank) : it's not really correct. Fix it accordingly to
16768 * the p. 4.9 of The Definitive Guide (page 71)
16769 */
16770 if (((v7_is_object(v1) || v7_is_object(v2)) && v1 == v2)) {
16771 res = v7_mk_boolean(v7, op == OP_EQ);
16772 PUSH(res);
16773 break;
16774 } else if (v7_is_undefined(v1) || v7_is_null(v1)) {
16775 res = v7_mk_boolean(
16776 v7, (op != OP_EQ) ^ (v7_is_undefined(v2) || v7_is_null(v2)));
16777 PUSH(res);
16778 break;
16779 } else if (v7_is_undefined(v2) || v7_is_null(v2)) {
16780 res = v7_mk_boolean(
16781 v7, (op != OP_EQ) ^ (v7_is_undefined(v1) || v7_is_null(v1)));
16782 PUSH(res);
16783 break;
16784 }
16785
16786 if (v7_is_string(v1) && v7_is_string(v2)) {
16787 int cmp = s_cmp(v7, v1, v2);
16788 switch (op) {
16789 case OP_EQ:
16790 res = v7_mk_boolean(v7, cmp == 0);
16791 break;
16792 case OP_NE:
16793 res = v7_mk_boolean(v7, cmp != 0);
16794 break;
16795 default:
16796 /* should never be here */
16797 assert(0);
16798 }
16799 } else {
16800 /* Convert both operands to numbers */
16801
16802 BTRY(to_number_v(v7, v1, &v1));
16803 BTRY(to_number_v(v7, v2, &v2));
16804
16805 res = v7_mk_boolean(v7, b_bool_bin_op(op, v7_get_double(v7, v1),
16806 v7_get_double(v7, v2)));
16807 }
16808 PUSH(res);
16809 break;
16810 }
16811 case OP_LT:
16812 case OP_LE:
16813 case OP_GT:
16814 case OP_GE: {
16815 v2 = POP();
16816 v1 = POP();
16817 BTRY(to_primitive(v7, v1, V7_TO_PRIMITIVE_HINT_NUMBER, &v1));
16818 BTRY(to_primitive(v7, v2, V7_TO_PRIMITIVE_HINT_NUMBER, &v2));
16819
16820 if (v7_is_string(v1) && v7_is_string(v2)) {
16821 int cmp = s_cmp(v7, v1, v2);
16822 switch (op) {
16823 case OP_LT:
16824 res = v7_mk_boolean(v7, cmp < 0);
16825 break;
16826 case OP_LE:
16827 res = v7_mk_boolean(v7, cmp <= 0);
16828 break;
16829 case OP_GT:
16830 res = v7_mk_boolean(v7, cmp > 0);
16831 break;
16832 case OP_GE:
16833 res = v7_mk_boolean(v7, cmp >= 0);
16834 break;
16835 default:
16836 /* should never be here */
16837 assert(0);
16838 }
16839 } else {
16840 /* Convert both operands to numbers */
16841
16842 BTRY(to_number_v(v7, v1, &v1));
16843 BTRY(to_number_v(v7, v2, &v2));
16844
16845 res = v7_mk_boolean(v7, b_bool_bin_op(op, v7_get_double(v7, v1),
16846 v7_get_double(v7, v2)));
16847 }
16848 PUSH(res);
16849 break;
16850 }
16851 case OP_INSTANCEOF: {
16852 v2 = POP();
16853 v1 = POP();
16854 if (!v7_is_callable(v7, v2)) {
16855 BTRY(v7_throwf(v7, TYPE_ERROR,
16856 "Expecting a function in instanceof check"));
16857 goto op_done;
16858 } else {
16859 PUSH(v7_mk_boolean(
16860 v7, is_prototype_of(v7, v1, v7_get(v7, v2, "prototype", 9))));
16861 }
16862 break;
16863 }
16864 case OP_TYPEOF:
16865 v1 = POP();
16866 switch (val_type(v7, v1)) {
16867 case V7_TYPE_NUMBER:
16868 res = v7_mk_string(v7, "number", 6, 1);
16869 break;
16870 case V7_TYPE_STRING:
16871 res = v7_mk_string(v7, "string", 6, 1);
16872 break;
16873 case V7_TYPE_BOOLEAN:
16874 res = v7_mk_string(v7, "boolean", 7, 1);
16875 break;
16876 case V7_TYPE_FUNCTION_OBJECT:
16877 case V7_TYPE_CFUNCTION_OBJECT:
16878 case V7_TYPE_CFUNCTION:
16879 res = v7_mk_string(v7, "function", 8, 1);
16880 break;
16881 case V7_TYPE_UNDEFINED:
16882 res = v7_mk_string(v7, "undefined", 9, 1);
16883 break;
16884 default:
16885 res = v7_mk_string(v7, "object", 6, 1);
16886 break;
16887 }
16888 PUSH(res);
16889 break;
16890 case OP_IN: {
16891 struct v7_property *prop = NULL;
16892 v2 = POP();
16893 v1 = POP();
16894 BTRY(to_string(v7, v1, NULL, buf, sizeof(buf), NULL));
16895 prop = v7_get_property(v7, v2, buf, ~0);
16896 PUSH(v7_mk_boolean(v7, prop != NULL));
16897 } break;
16898 case OP_GET:
16899 v2 = POP();
16900 v1 = POP();
16901 BTRY(v7_get_throwing_v(v7, v1, v2, &v3));
16902 PUSH(v3);
16903#if !V7_DISABLE_CALL_ERROR_CONTEXT
16904 v7->vals.last_name[1] = v7->vals.last_name[0];
16905 v7->vals.last_name[0] = v2;
16906#endif
16907 break;
16908 case OP_SET: {
16909 v3 = POP();
16910 v2 = POP();
16911 v1 = POP();
16912
16913 /* convert name to string, if it's not already */
16914 BTRY(to_string(v7, v2, &v2, NULL, 0, NULL));
16915
16916 /* set value */
16917 BTRY(set_property_v(v7, v1, v2, v3, NULL));
16918
16919 PUSH(v3);
16920 break;
16921 }
16922 case OP_GET_VAR:
16923 case OP_SAFE_GET_VAR: {
16924 struct v7_property *p = NULL;
16925 assert(r.ops < r.end - 1);
16926 v1 = bcode_decode_lit(v7, r.bcode, &r.ops);
16927 BTRY(v7_get_property_v(v7, get_scope(v7), v1, &p));
16928 if (p == NULL) {
16929 if (op == OP_SAFE_GET_VAR) {
16930 PUSH(V7_UNDEFINED);
16931 } else {
16932 /* variable does not exist: Reference Error */
16933 V7_TRY(bcode_throw_reference_error(v7, &r, v1));
16934 goto op_done;
16935 }
16936 break;
16937 } else {
16938 BTRY(v7_property_value(v7, get_scope(v7), p, &v2));
16939 PUSH(v2);
16940 }
16941#if !V7_DISABLE_CALL_ERROR_CONTEXT
16942 v7->vals.last_name[0] = v1;
16943 v7->vals.last_name[1] = V7_UNDEFINED;
16944#endif
16945 break;
16946 }
16947 case OP_SET_VAR: {
16948 struct v7_property *prop;
16949 v3 = POP();
16950 v2 = bcode_decode_lit(v7, r.bcode, &r.ops);
16951 v1 = get_scope(v7);
16952
16953 BTRY(to_string(v7, v2, NULL, buf, sizeof(buf), NULL));
16954 prop = v7_get_property(v7, v1, buf, strlen(buf));
16955 if (prop != NULL) {
16956 /* Property already exists: update its value */
16957 /*
16958 * TODO(dfrank): currently we can't use `def_property_v()` here,
16959 * because if the property was already found somewhere in the
16960 * prototype chain, then it should be updated, instead of creating a
16961 * new one on the top of the scope.
16962 *
16963 * Probably we need to make `def_property_v()` more generic and
16964 * use it here; or split `def_property_v()` into smaller pieces and
16965 * use one of them here.
16966 */
16967 if (!(prop->attributes & V7_PROPERTY_NON_WRITABLE)) {
16968 prop->value = v3;
16969 }
16970 } else if (!r.bcode->strict_mode) {
16971 /*
16972 * Property does not exist: since we're not in strict mode, let's
16973 * create new property at Global Object
16974 */
16975 BTRY(set_property_v(v7, v7_get_global(v7), v2, v3, NULL));
16976 } else {
16977 /*
16978 * In strict mode, throw reference error instead of polluting Global
16979 * Object
16980 */
16981 V7_TRY(bcode_throw_reference_error(v7, &r, v2));
16982 goto op_done;
16983 }
16984 PUSH(v3);
16985 break;
16986 }
16987 case OP_JMP: {
16988 bcode_off_t target = bcode_get_target(&r.ops);
16989 r.ops = r.bcode->ops.p + target - 1;
16990 break;
16991 }
16992 case OP_JMP_FALSE: {
16993 bcode_off_t target = bcode_get_target(&r.ops);
16994 v1 = POP();
16995 if (!v7_is_truthy(v7, v1)) {
16996 r.ops = r.bcode->ops.p + target - 1;
16997 }
16998 break;
16999 }
17000 case OP_JMP_TRUE: {
17001 bcode_off_t target = bcode_get_target(&r.ops);
17002 v1 = POP();
17003 if (v7_is_truthy(v7, v1)) {
17004 r.ops = r.bcode->ops.p + target - 1;
17005 }
17006 break;
17007 }
17008 case OP_JMP_TRUE_DROP: {
17009 bcode_off_t target = bcode_get_target(&r.ops);
17010 v1 = POP();
17011 if (v7_is_truthy(v7, v1)) {
17012 r.ops = r.bcode->ops.p + target - 1;
17013 v1 = POP();
17014 POP();
17015 PUSH(v1);
17016 }
17017 break;
17018 }
17019 case OP_JMP_IF_CONTINUE: {
17020 bcode_off_t target = bcode_get_target(&r.ops);
17021 if (v7->is_continuing) {
17022 r.ops = r.bcode->ops.p + target - 1;
17023 }
17024 v7->is_continuing = 0;
17025 break;
17026 }
17027 case OP_CREATE_OBJ:
17028 PUSH(v7_mk_object(v7));
17029 break;
17030 case OP_CREATE_ARR:
17031 PUSH(v7_mk_array(v7));
17032 break;
17033 case OP_PUSH_PROP_ITER_CTX: {
17034 struct prop_iter_ctx *ctx =
17035 (struct prop_iter_ctx *) calloc(1, sizeof(*ctx));
17036 BTRY(init_prop_iter_ctx(v7, TOS(), 1, ctx));
17037 v1 = v7_mk_object(v7);
17038 v7_set_user_data(v7, v1, ctx);
17039 v7_set_destructor_cb(v7, v1, prop_iter_ctx_dtor);
17040 PUSH(v1);
17041 break;
17042 }
17043 case OP_NEXT_PROP: {
17044 struct prop_iter_ctx *ctx = NULL;
17045 int ok = 0;
17046 v1 = POP(); /* ctx */
17047 v2 = POP(); /* object */
17048
17049 ctx = (struct prop_iter_ctx *) v7_get_user_data(v7, v1);
17050
17051 if (v7_is_object(v2)) {
17052 v7_prop_attr_t attrs;
17053
17054 do {
17055 /* iterate properties until we find a non-hidden enumerable one */
17056 do {
17057 BTRY(next_prop(v7, ctx, &res, NULL, &attrs, &ok));
17058 } while (ok && (attrs & (_V7_PROPERTY_HIDDEN |
17059 V7_PROPERTY_NON_ENUMERABLE)));
17060
17061 if (!ok) {
17062 /* no more properties in this object: proceed to the prototype */
17063 v2 = v7_get_proto(v7, v2);
17064 if (get_generic_object_struct(v2) != NULL) {
17065 /*
17066 * the prototype is a generic object, so, init the context for
17067 * props iteration
17068 */
17069 v7_destruct_prop_iter_ctx(v7, ctx);
17070 BTRY(init_prop_iter_ctx(v7, v2, 1, ctx));
17071 } else {
17072 /*
17073 * we can't iterate the prototype's props, so, just stop
17074 * iteration.
17075 */
17076 ctx = NULL;
17077 }
17078 }
17079 } while (!ok && ctx != NULL);
17080 } else {
17081 /*
17082 * Not an object: reset the context.
17083 */
17084 ctx = NULL;
17085 }
17086
17087 if (ctx == NULL) {
17088 PUSH(v7_mk_boolean(v7, 0));
17089
17090 /*
17091 * We could leave the context unfreed, and let the
17092 * `prop_iter_ctx_dtor()` free it when the v1 will be GC-d, but
17093 * let's do that earlier.
17094 */
17095 ctx = (struct prop_iter_ctx *) v7_get_user_data(v7, v1);
17096 v7_destruct_prop_iter_ctx(v7, ctx);
17097 free(ctx);
17098 v7_set_user_data(v7, v1, NULL);
17099 v7_set_destructor_cb(v7, v1, NULL);
17100 } else {
17101 PUSH(v2);
17102 PUSH(v1);
17103 PUSH(res);
17104 PUSH(v7_mk_boolean(v7, 1));
17105 }
17106 break;
17107 }
17108 case OP_FUNC_LIT: {
17109 v1 = POP();
17110 v2 = bcode_instantiate_function(v7, v1);
17111 PUSH(v2);
17112 break;
17113 }
17114 case OP_CHECK_CALL:
17115 v1 = TOS();
17116 if (!v7_is_callable(v7, v1)) {
17117 int arity = 0;
17118 enum v7_err ignore;
17119/* tried to call non-function object: throw a TypeError */
17120
17121#if !V7_DISABLE_CALL_ERROR_CONTEXT
17122 /*
17123 * try to provide some useful context for the error message
17124 * using a good-enough heuristics
17125 * but defer actual throw when process the incriminated call
17126 * in order to evaluate the arguments as required by the spec.
17127 */
17128 if (v7->last_ops[0] == OP_GET_VAR) {
17129 arity = 1;
17130 } else if (v7->last_ops[0] == OP_GET &&
17131 v7->last_ops[1] == OP_PUSH_LIT) {
17132 /*
17133 * OP_PUSH_LIT is used to both push property names for OP_GET
17134 * and for pushing actual literals. During PUSH_LIT push lit
17135 * evaluation we reset the last name variable in case the literal
17136 * is not a string, such as in `[].foo()`.
17137 * Unfortunately it doesn't handle `"foo".bar()`; could be
17138 * solved by adding another bytecode for property literals but
17139 * probably it doesn't matter much.
17140 */
17141 if (v7_is_undefined(v7->vals.last_name[1])) {
17142 arity = 1;
17143 } else {
17144 arity = 2;
17145 }
17146 }
17147#endif
17148
17149 switch (arity) {
17150 case 0:
17151 ignore = v7_throwf(v7, TYPE_ERROR, "value is not a function");
17152 break;
17153#if !V7_DISABLE_CALL_ERROR_CONTEXT
17154
17155 case 1:
17156 ignore = v7_throwf(v7, TYPE_ERROR, "%s is not a function",
17157 v7_get_cstring(v7, &v7->vals.last_name[0]));
17158 break;
17159 case 2:
17160 ignore = v7_throwf(v7, TYPE_ERROR, "%s.%s is not a function",
17161 v7_get_cstring(v7, &v7->vals.last_name[1]),
17162 v7_get_cstring(v7, &v7->vals.last_name[0]));
17163 break;
17164#endif
17165 };
17166
17167 v7->vals.call_check_ex = v7->vals.thrown_error;
17168 v7_clear_thrown_value(v7);
17169 (void) ignore;
17170 }
17171 break;
17172 case OP_CALL:
17173 case OP_NEW: {
17174 /* Naive implementation pending stack frame redesign */
17175 int args = (int) *(++r.ops);
17176 uint8_t is_constructor = (op == OP_NEW);
17177
17178 if (SP() < (args + 1 /*func*/ + 1 /*this*/)) {
17179 BTRY(v7_throwf(v7, INTERNAL_ERROR, "stack underflow"));
17180 goto op_done;
17181 } else {
17182 v2 = v7_mk_dense_array(v7);
17183 while (args > 0) {
17184 BTRY(v7_array_set_throwing(v7, v2, --args, POP(), NULL));
17185 }
17186 /* pop function to call */
17187 v1 = POP();
17188
17189 /* pop `this` */
17190 v3 = POP();
17191
17192 /*
17193 * adjust `this` if the function is called with the constructor
17194 * invocation pattern
17195 */
17196 if (is_constructor) {
17197 /*
17198 * The function is invoked as a constructor: we ignore `this`
17199 * value popped from stack, create new object and set prototype.
17200 */
17201
17202 /*
17203 * get "prototype" property from the constructor function,
17204 * and make sure it's an object
17205 */
17206 v4 = v7_get(v7, v1 /*func*/, "prototype", 9);
17207 if (!v7_is_object(v4)) {
17208 /* TODO(dfrank): box primitive value */
17209 BTRY(v7_throwf(
17210 v7, TYPE_ERROR,
17211 "Cannot set a primitive value as object prototype"));
17212 goto op_done;
17213 } else if (is_cfunction_lite(v4)) {
17214 /*
17215 * TODO(dfrank): maybe add support for a cfunction pointer to be
17216 * a prototype
17217 */
17218 BTRY(v7_throwf(v7, TYPE_ERROR,
17219 "Not implemented: cfunction as a prototype"));
17220 goto op_done;
17221 }
17222
17223 /* create an object with given prototype */
17224 v3 = mk_object(v7, v4 /*prototype*/);
17225 v4 = V7_UNDEFINED;
17226 }
17227
17228 if (!v7_is_callable(v7, v1)) {
17229 /* tried to call non-function object: throw a TypeError */
17230 BTRY(v7_throw(v7, v7->vals.call_check_ex));
17231 goto op_done;
17232 } else if (is_cfunction_lite(v1) || is_cfunction_obj(v7, v1)) {
17233 /* call cfunction */
17234
17235 /*
17236 * In "function invocation pattern", the `this` value popped from
17237 * stack is an `undefined`. And in non-strict mode, we should change
17238 * it to global object.
17239 */
17240 if (!is_constructor && !r.bcode->strict_mode &&
17241 v7_is_undefined(v3)) {
17242 v3 = v7->vals.global_object;
17243 }
17244
17245 BTRY(call_cfunction(v7, v1 /*func*/, v3 /*this*/, v2 /*args*/,
17246 is_constructor, &v4));
17247
17248 /* push value returned from C function to bcode stack */
17249 PUSH(v4);
17250
17251 } else {
17252 char *ops;
17253 struct v7_js_function *func = get_js_function_struct(v1);
17254
17255 /*
17256 * In "function invocation pattern", the `this` value popped from
17257 * stack is an `undefined`. And in non-strict mode, we should change
17258 * it to global object.
17259 */
17260 if (!is_constructor && !func->bcode->strict_mode &&
17261 v7_is_undefined(v3)) {
17262 v3 = v7->vals.global_object;
17263 }
17264
17265 scope_frame = v7_mk_object(v7);
17266
17267 /*
17268 * Before actual opcodes, `ops` contains one or more
17269 * null-terminated strings: first of all, the function name (if the
17270 * function is anonymous, it's an empty string).
17271 *
17272 * Then, argument names follow. We know number of arguments, so, we
17273 * know how many names to take.
17274 *
17275 * And then, local variable names follow. We know total number of
17276 * strings (`names_cnt`), so, again, we know how many names to
17277 * take.
17278 */
17279
17280 ops = func->bcode->ops.p;
17281
17282 /* populate function itself */
17283 ops = bcode_next_name_v(v7, func->bcode, ops, &v4);
17284 BTRY(def_property_v(v7, scope_frame, v4, V7_DESC_CONFIGURABLE(0),
17285 v1, 0 /*not assign*/, NULL));
17286
17287 /* populate arguments */
17288 {
17289 int arg_num;
17290 for (arg_num = 0; arg_num < func->bcode->args_cnt; ++arg_num) {
17291 ops = bcode_next_name_v(v7, func->bcode, ops, &v4);
17292 BTRY(def_property_v(
17293 v7, scope_frame, v4, V7_DESC_CONFIGURABLE(0),
17294 v7_array_get(v7, v2, arg_num), 0 /*not assign*/, NULL));
17295 }
17296 }
17297
17298 /* populate `arguments` object */
17299
17300 /*
17301 * TODO(dfrank): it's actually much more complicated than that:
17302 * it's not an array, it's an array-like object. More, in
17303 * non-strict mode, elements of `arguments` object are just aliases
17304 * for actual arguments, so this one:
17305 *
17306 * `(function(a){arguments[0]=2; return a;})(1);`
17307 *
17308 * should yield 2. Currently, it yields 1.
17309 */
17310 v7_def(v7, scope_frame, "arguments", 9, V7_DESC_CONFIGURABLE(0),
17311 v2);
17312
17313 /* populate local variables */
17314 {
17315 uint8_t loc_num;
17316 uint8_t loc_cnt = func->bcode->names_cnt - func->bcode->args_cnt -
17317 1 /*func name*/;
17318 for (loc_num = 0; loc_num < loc_cnt; ++loc_num) {
17319 ops = bcode_next_name_v(v7, func->bcode, ops, &v4);
17320 BTRY(def_property_v(v7, scope_frame, v4,
17321 V7_DESC_CONFIGURABLE(0), V7_UNDEFINED,
17322 0 /*not assign*/, NULL));
17323 }
17324 }
17325
17326 /* transfer control to the function */
17327 V7_TRY(bcode_perform_call(v7, scope_frame, func, &r, v3 /*this*/,
17328 ops, is_constructor));
17329
17330 scope_frame = V7_UNDEFINED;
17331 }
17332 }
17333 break;
17334 }
17335 case OP_RET:
17336 bcode_adjust_retval(v7, 1 /*explicit return*/);
17337 V7_TRY(bcode_perform_return(v7, &r, 1 /*take value from stack*/));
17338 break;
17339 case OP_DELETE:
17340 case OP_DELETE_VAR: {
17341 size_t name_len;
17342 struct v7_property *prop;
17343
17344 res = v7_mk_boolean(v7, 1);
17345
17346 /* pop property name to delete */
17347 v2 = POP();
17348
17349 if (op == OP_DELETE) {
17350 /* pop object to delete the property from */
17351 v1 = POP();
17352 } else {
17353 /* use scope as an object to delete the property from */
17354 v1 = get_scope(v7);
17355 }
17356
17357 if (!v7_is_object(v1)) {
17358 /*
17359 * the "object" to delete a property from is not actually an object
17360 * (at least this can happen with cfunction pointers), will just
17361 * return `true`
17362 */
17363 goto delete_clean;
17364 }
17365
17366 BTRY(to_string(v7, v2, NULL, buf, sizeof(buf), &name_len));
17367
17368 prop = v7_get_property(v7, v1, buf, name_len);
17369 if (prop == NULL) {
17370 /* not found a property; will just return `true` */
17371 goto delete_clean;
17372 }
17373
17374 /* found needed property */
17375
17376 if (prop->attributes & V7_PROPERTY_NON_CONFIGURABLE) {
17377 /*
17378 * this property is undeletable. In non-strict mode, we just
17379 * return `false`; otherwise, we throw.
17380 */
17381 if (!r.bcode->strict_mode) {
17382 res = v7_mk_boolean(v7, 0);
17383 } else {
17384 BTRY(v7_throwf(v7, TYPE_ERROR, "Cannot delete property '%s'", buf));
17385 goto op_done;
17386 }
17387 } else {
17388 /*
17389 * delete property: when we operate on the current scope, we should
17390 * walk the prototype chain when deleting property.
17391 *
17392 * But when we operate on a "real" object, we should delete own
17393 * properties only.
17394 */
17395 if (op == OP_DELETE) {
17396 v7_del(v7, v1, buf, name_len);
17397 } else {
17398 del_property_deep(v7, v1, buf, name_len);
17399 }
17400 }
17401
17402 delete_clean:
17403 PUSH(res);
17404 break;
17405 }
17406 case OP_TRY_PUSH_CATCH:
17407 case OP_TRY_PUSH_FINALLY:
17408 case OP_TRY_PUSH_LOOP:
17409 case OP_TRY_PUSH_SWITCH:
17410 eval_try_push(v7, op, &r);
17411 break;
17412 case OP_TRY_POP:
17413 V7_TRY(eval_try_pop(v7));
17414 break;
17415 case OP_AFTER_FINALLY:
17416 /*
17417 * exited from `finally` block: if some value is currently being
17418 * returned, continue returning it.
17419 *
17420 * Likewise, if some value is currently being thrown, continue
17421 * unwinding stack.
17422 */
17423 if (v7->is_thrown) {
17424 V7_TRY(
17425 bcode_perform_throw(v7, &r, 0 /*don't take value from stack*/));
17426 goto op_done;
17427 } else if (v7->is_returned) {
17428 V7_TRY(
17429 bcode_perform_return(v7, &r, 0 /*don't take value from stack*/));
17430 break;
17431 } else if (v7->is_breaking) {
17432 bcode_perform_break(v7, &r);
17433 }
17434 break;
17435 case OP_THROW:
17436 V7_TRY(bcode_perform_throw(v7, &r, 1 /*take thrown value*/));
17437 goto op_done;
17438 case OP_BREAK:
17439 bcode_perform_break(v7, &r);
17440 break;
17441 case OP_CONTINUE:
17442 v7->is_continuing = 1;
17443 bcode_perform_break(v7, &r);
17444 break;
17445 case OP_ENTER_CATCH: {
17446 /* pop thrown value from stack */
17447 v1 = POP();
17448 /* get the name of the thrown value */
17449 v2 = bcode_decode_lit(v7, r.bcode, &r.ops);
17450
17451 /*
17452 * create a new stack frame (a "private" one), and set exception
17453 * property on it
17454 */
17455 scope_frame = v7_mk_object(v7);
17456 BTRY(set_property_v(v7, scope_frame, v2, v1, NULL));
17457
17458 /* Push this "private" frame on the call stack */
17459
17460 /* new scope_frame will inherit from the current scope */
17461
17462 obj_prototype_set(v7, get_object_struct(scope_frame),
17463 get_object_struct(get_scope(v7)));
17464
17465 /*
17466 * Create new `call_frame` which will replace `v7->call_stack`.
17467 */
17468 append_call_frame_private(v7, scope_frame);
17469
17470 break;
17471 }
17472 case OP_EXIT_CATCH: {
17473 v7_call_frame_mask_t frame_type_mask;
17474 /* unwind 1 frame */
17475 frame_type_mask = unwind_stack_1level(v7, &r);
17476 /* make sure the unwound frame is a "private" frame */
17477 assert(frame_type_mask == V7_CALL_FRAME_MASK_PRIVATE);
17478#if defined(NDEBUG)
17479 (void) frame_type_mask;
17480#endif
17481 break;
17482 }
17483 default:
17484 BTRY(v7_throwf(v7, INTERNAL_ERROR, "Unknown opcode: %d", (int) op));
17485 goto op_done;
17486 }
17487
17488 op_done:
17489#ifdef V7_BCODE_TRACE
17490 /* print current stack state */
17491 {
17492 char buf[40];
17493 char *str = v7_stringify(v7, TOS(), buf, sizeof(buf), V7_STRINGIFY_DEBUG);
17494 fprintf(stderr, " stack size: %u, TOS: '%s'\n",
17495 (unsigned int) (v7->stack.len / sizeof(val_t)), str);
17496 if (str != buf) {
17497 free(str);
17498 }
17499
17500#ifdef V7_BCODE_TRACE_STACK
17501 {
17502 size_t i;
17503 for (i = 0; i < (v7->stack.len / sizeof(val_t)); i++) {
17504 char *str = v7_stringify(v7, stack_at(&v7->stack, i), buf,
17505 sizeof(buf), V7_STRINGIFY_DEBUG);
17506
17507 fprintf(stderr, " #: '%s'\n", str);
17508
17509 if (str != buf) {
17510 free(str);
17511 }
17512 }
17513 }
17514#endif
17515 }
17516#endif
17517 if (r.need_inc_ops) {
17518 r.ops++;
17519 }
17520 }
17521
17522 /* implicit return */
17523 if (v7->call_stack != v7->bottom_call_frame) {
17524#ifdef V7_BCODE_TRACE
17525 fprintf(stderr, "return implicitly\n");
17526#endif
17527 bcode_adjust_retval(v7, 0 /*implicit return*/);
17528 V7_TRY(bcode_perform_return(v7, &r, 1));
17529 goto restart;
17530 } else {
17531#ifdef V7_BCODE_TRACE
17532 const char *s = (get_scope(v7) != v7->vals.global_object)
17533 ? "not global object"
17534 : "global object";
17535 fprintf(stderr, "reached bottom_call_frame (%s)\n", s);
17536#endif
17537 }
17538
17539clean:
17540
17541 if (rcode == V7_OK) {
17542/*
17543 * bcode evaluated successfully. Make sure try stack is empty.
17544 * (data stack will be checked below, in `clean`)
17545 */
17546#ifndef NDEBUG
17547 {
17548 unsigned long try_stack_len =
17549 v7_array_length(v7, find_call_frame_private(v7)->vals.try_stack);
17550 if (try_stack_len != 0) {
17551 fprintf(stderr, "try_stack_len=%lu, should be 0\n", try_stack_len);
17552 }
17553 assert(try_stack_len == 0);
17554 }
17555#endif
17556
17557 /* get the value returned from the evaluated script */
17558 *_res = POP();
17559 }
17560
17561 assert(v7->bottom_call_frame == v7->call_stack);
17562 unwind_stack_1level(v7, NULL);
17563
17564 v7->bottom_call_frame = saved_bottom_call_frame;
17565
17566 tmp_frame_cleanup(&tf);
17567 return rcode;
17568}
17569
17570/*
17571 * TODO(dfrank) this function is probably too overloaded: it handles both
17572 * `v7_exec` and `v7_apply`. Read below why it's written this way, but it's
17573 * probably a good idea to factor out common functionality in some other
17574 * function.
17575 *
17576 * If `src` is not `NULL`, then we behave in favour of `v7_exec`: parse,
17577 * compile, and evaluate the script. The `func` and `args` are ignored.
17578 *
17579 * If, however, `src` is `NULL`, then we behave in favour of `v7_apply`: we
17580 * call the provided `func` with `args`. But unlike interpreter, we can't just
17581 * call the provided function: we need to setup environment for this call.
17582 *
17583 * Currently, we just quickly generate the "wrapper" bcode for the function.
17584 * This wrapper bcode looks like this:
17585 *
17586 * OP_PUSH_UNDEFINED
17587 * OP_PUSH_LIT # push this
17588 * OP_PUSH_LIT # push function
17589 * OP_PUSH_LIT # push arg1
17590 * OP_PUSH_LIT # push arg2
17591 * ...
17592 * OP_PUSH_LIT # push argN
17593 * OP_CALL(N) # call function with N arguments
17594 * OP_SWAP_DROP
17595 *
17596 * and then, bcode evaluator proceeds with this code.
17597 *
17598 * In fact, both cases (eval or apply) are quite similar: we should prepare
17599 * environment for the bcode evaluation in exactly the same way, and the only
17600 * different part is where we get the bcode from. This is why that
17601 * functionality is baked in the single function, but it would be good to make
17602 * it suck less.
17603 */