Compare commits

...
605 Commits
Author SHA1 Message Date
Sergey Lyubka 30a7965135 added lsp link 2014-03-10 11:21:52 +00:00
Sergey Lyubka a8a017a048 docs updated 2014-03-10 09:23:06 +00:00
Sergey Lyubka eac8ffabc4 docs updated 2014-03-10 09:19:01 +00:00
Sergey Lyubka a7a17711ec Resetting endpoint_type in open_local_endpoint() 2014-03-10 08:35:41 +00:00
Sergey Lyubka 18e28ef879 Added lua includes 2014-03-09 20:22:51 +00:00
Sergey Lyubka ce7515fca9 Merge pull request #349 from jhorneman/master
Exposing Lua support functions
2014-03-09 20:18:49 +00:00
Jurie Horneman d5a78fb664 Fixed bug. 2014-03-09 21:12:34 +01:00
Jurie Horneman 1b3a1b74ac Exposed Lua support functions. 2014-03-09 21:11:06 +01:00
Sergey Lyubka 8dd76e6ef4 Using ns_start_thread() 2014-03-09 19:50:34 +00:00
Sergey Lyubka 976b5f37c1 Added Lua callback 2014-03-09 19:30:41 +00:00
Sergey Lyubka 31489ab7b1 Lua fixes 2014-03-09 19:26:58 +00:00
Sergey Lyubka 1eb59940a4 Re-init rewrites var in convert_uri_to_file_name() 2014-03-09 13:27:39 +00:00
Sergey Lyubka 576d769b56 Corrected links in tutorials 2014-03-09 13:13:25 +00:00
Sergey Lyubka afaba7ee17 Lua calls, birth_time fixed 2014-03-09 13:13:13 +00:00
Sergey Lyubka 40f257ef2b lua build instructions fixed 2014-03-09 13:12:49 +00:00
Sergey Lyubka 5840dc8153 Links updated 2014-03-07 17:08:23 +00:00
Sergey Lyubka 5ed3dafb56 Added warning about PHP 5.5 2014-03-07 14:46:24 +00:00
Sergey Lyubka b99bf306ec fixed image links 2014-03-07 14:40:34 +00:00
Sergey Lyubka 89fae72aa7 added 2014-03-07 14:24:37 +00:00
Sergey Lyubka ab147e8f19 Added MONGOOSE_NO_SSI to MONGOOSE_NO_FILESYSTEM 2014-03-06 13:37:23 +00:00
Sergey Lyubka 81a78f9c8b Added query string to access log 2014-03-05 11:22:23 +00:00
Sergey Lyubka 370aeefdde Added error pages and vhosts to readme 2014-03-05 11:19:18 +00:00
Sergey Lyubka c5407a75f4 #define EV_HANDLER NULL in server.c 2014-03-05 10:12:43 +00:00
Sergey Lyubka 7217aa22f1 Embedded guide 2014-03-05 02:53:19 +00:00
Sergey Lyubka 69bd5f7aa2 SSL_accept logic fix 2014-03-05 02:19:05 +00:00
Sergey Lyubka 41b3c1b23e warning squashed in convert_uri_to_file_name() 2014-03-05 01:59:58 +00:00
Sergey Lyubka f639409533 warning squashed in convert_uri_to_file_name() 2014-03-05 01:59:32 +00:00
Sergey Lyubka 67c44799c8 SSL_accept() error handling fix 2014-03-05 01:57:09 +00:00
Sergey Lyubka 4646e2ad55 Added mjpg example 2014-03-04 20:23:37 +00:00
Sergey Lyubka b77532ea3f Added mjpg example 2014-03-04 20:22:46 +00:00
Sergey Lyubka ed8168e8a1 Added virtual hosts support via url_rewrites 2014-03-04 16:15:02 +00:00
Sergey Lyubka 39e2d2ad55 Appending query_string to the URI when redirecting on HTTP error 2014-03-04 15:01:05 +00:00
Sergey Lyubka 27c6656398 SSL_accept fixes 2014-03-04 13:23:40 +00:00
Sergey Lyubka ffe83051fe build fixed 2014-03-04 13:15:56 +00:00
Sergey Lyubka 93cd77ffad Changed links 2014-03-03 21:18:57 +00:00
Sergey Lyubka 279c06c64c Cleaned up cruft from mongoose.h 2014-03-03 10:56:17 +00:00
Sergey Lyubka 570c8213b6 Cleaned unit test 2014-03-03 10:54:35 +00:00
Sergey Lyubka f521999ea6 Calling EP_CLIENT on close 2014-03-03 10:27:56 +00:00
Sergey Lyubka e41df3cf9c MG_REQ_BEGIN -> MG_REQUEST, killed MG_REQ_END, add MG_REPLY. Restored server test 2014-03-03 10:26:27 +00:00
Sergey Lyubka 65f484291f got rid of multiline comment 2014-03-03 09:45:00 +00:00
Sergey Lyubka 77db89961b mg_stat() fix for paths like X:\ 2014-03-03 01:00:38 +00:00
Sergey Lyubka ad50310bb6 Added index.shtml to index files 2014-03-02 19:49:15 +00:00
Sergey Lyubka 66ec3d1f1e Added defines for popen and pclose, for SSI under Win32 2014-03-02 18:50:02 +00:00
Sergey Lyubka a9da86d05c Mentioned SSI 2014-03-02 18:28:40 +00:00
Sergey Lyubka 5f25a88821 Restored SSI functionality 2014-03-02 18:27:51 +00:00
Sergey Lyubka fd7dc33645 unbroke unit test 2014-03-02 17:20:24 +00:00
Sergey Lyubka 9c22771a43 Merge pull request #345 from nielsegberts/master
Also clean up multi_threaded and websocket_html.c on make clean
2014-03-02 15:48:25 +00:00
Niels Egberts 11640cc3c6 Also clean up multi_threaded and websocket_html.c on make clean 2014-03-02 14:55:34 +00:00
Sergey Lyubka 2264520a2f Example changed to evented API 2014-03-02 13:05:00 +00:00
Sergey Lyubka 2f0b411ddd Added -pthread flag to unix compilation example 2014-03-02 13:00:44 +00:00
Sergey Lyubka e0aceb4f3a Fixed windows build for examples 2014-03-02 12:23:53 +00:00
Sergey Lyubka ea9a60a59a Updated examples to conform to the evented API 2014-03-02 12:16:09 +00:00
Sergey Lyubka 458320cffb Fixed #343 in conn2() for Lua 2014-03-02 10:12:12 +00:00
Sergey Lyubka e0214af422 Using private ns_avprintf() in mg_printf_data() 2014-03-02 10:07:30 +00:00
Sergey Lyubka df5e997ea7 ns_server_poll() waking up by ns_server_wakeup() 2014-03-01 01:55:40 +00:00
Sergey Lyubka 0a3cb63c73 Added mg_wakeup_server() 2014-03-01 01:47:01 +00:00
Sergey Lyubka 37f7f3fb12 Merge pull request #339 from nenioscio/master
Fix issue #338
2014-03-01 01:19:31 +00:00
Sergey Lyubka 2ac970fa16 Moving to event-based API, temporary breaking tests 2014-03-01 01:17:39 +00:00
Sergey Lyubka de35a353d4 pphp -> php 2014-02-27 22:02:18 +00:00
Klaus Wagner dbbda02f70 Fix issue #338 2014-02-27 22:12:46 +01:00
Sergey Lyubka 725c30446c more docs 2014-02-25 20:39:34 +00:00
Sergey Lyubka 60473ae41a more docs 2014-02-25 20:39:00 +00:00
Sergey Lyubka 951d20f904 Added coniditional to use net_skeleton separately 2014-02-25 18:52:23 +00:00
Sergey Lyubka 85a6abd58b Clearing flags in close_local_endpoint() 2014-02-25 12:02:45 +00:00
Sergey Lyubka 2fbe09ad7c Restored jni build dir for Android 2014-02-25 08:12:42 +00:00
Sergey Lyubka 23325efab2 Added time.h 2014-02-25 08:10:19 +00:00
Sergey Lyubka 107902bae4 add_to_set(): fix around non-negative SOCKET on Windows 2014-02-24 08:22:40 +00:00
Sergey Lyubka 9bbf4c8384 Fixed problem with mg_printf_data() 2014-02-22 16:11:47 +00:00
Sergey Lyubka c39a712540 Win32 build fix 2014-02-21 14:13:06 +00:00
Sergey Lyubka e9f6111ba1 re-added signal.h 2014-02-20 17:47:07 +00:00
Sergey Lyubka ba267a32fd squashed warning in read_from_socket 2014-02-20 17:44:47 +00:00
Sergey Lyubka f64ebbe0b1 Guarded on_cgi_data() call by ifdef, thanks to Pavel Pimenov 2014-02-20 12:33:46 +00:00
Sergey Lyubka 8865dd5e84 Moved unit_test.c to examples 2014-02-20 12:13:59 +00:00
Sergey Lyubka ce57f47de0 Added missing signal.h 2014-02-20 09:49:42 +00:00
Sergey Lyubka 48be2dbc2a Added conditional for handling idle websocket conns 2014-02-20 07:32:33 +00:00
Sergey Lyubka 8905522a94 Setting last_io_time in ns_add_sock() 2014-02-20 06:26:44 +00:00
Sergey Lyubka eea1680cf9 open_cgi_endpoint() strrchr fix 2014-02-19 16:44:01 +00:00
Sergey Lyubka d5004cb7eb PF_INET -> AF_INET, unbreaks FreeBSD 2014-02-19 16:39:30 +00:00
Sergey Lyubka 1d1a05bf39 Embedded net_skeleton 2014-02-19 16:38:53 +00:00
Sergey Lyubka 2009069037 merge 2014-02-19 16:36:27 +00:00
Sergey Lyubka 8f7703c2a9 moved to net_skeleton 2014-02-19 16:34:51 +00:00
Sergey Lyubka 8e87c4f013 Merge pull request #329 from abimaelmartell/fix/freebsd-compilation
fix compilation under FreeBSD
2014-02-14 23:46:07 +00:00
Abimael Martell 639a6dc2a8 fix compilation under FreeBSD 2014-02-14 13:21:14 -08:00
Sergey Lyubka cead9a04ca Typo fixed 2014-02-11 15:21:54 +00:00
Sergey Lyubka e528093027 Formatted example 2014-02-11 15:20:19 +00:00
Sergey Lyubka c432b783fb Formatted example 2014-02-11 15:19:18 +00:00
Sergey Lyubka e06976836f Typo fixed 2014-02-11 15:18:20 +00:00
Sergey Lyubka c9f7407573 More comments in example 2014-02-11 15:16:55 +00:00
Sergey Lyubka a40e59dbe6 URL corrected 2014-02-11 09:56:10 +00:00
Sergey Lyubka 61ee3d36d0 Merge pull request #324 from eichin/patch-1
doc typos
2014-02-11 09:55:47 +00:00
Mark Eichin 94dbf21ffb doc typos
just saw them while reading...
2014-02-11 03:41:09 -05:00
Sergey Lyubka 998425b14b Styling changes for hexdump 2014-02-10 10:21:57 +00:00
Sergey Lyubka 6900dd733a Merge pull request #322 from pavel-pimenov/master
Fix copy-paste for MONGOOSE_HEXDUMP feature
2014-02-10 09:48:26 +00:00
Pavel Pimenov 9e4cd054c8 Fix copy-paste for MONGOOSE_HEXDUMP feature 2014-02-10 12:00:51 +04:00
Sergey Lyubka 5dc317fcb0 Added -DMONGOOSE_HEXDUMP feature 2014-02-09 20:57:11 +00:00
Sergey Lyubka fbd5d77ce8 Added note about CGI env vars 2014-02-07 20:23:37 +00:00
Sergey Lyubka 6f8751b479 chat server is going to be in its own dir 2014-02-07 13:04:02 +00:00
Sergey Lyubka 877c4dc698 websocket example responses: 15 times -> 3 times 2014-02-07 13:03:28 +00:00
Sergey Lyubka 2dfc79129a better lua build 2014-02-07 13:03:11 +00:00
Sergey Lyubka 416f4bf10f Merge pull request #321 from pavel-pimenov/master
Add #ifndef MONGOOSE_NO_FILESYSTEM
2014-02-07 07:45:20 +00:00
Pavel Pimenov f9a99530ff Add #ifndef MONGOOSE_NO_FILESYSTEM 2014-02-07 11:02:12 +04:00
Sergey Lyubka 940b65e4db Merge pull request #320 from xant/upstream
added a new handler callback to be used when the http connection is being closed
2014-02-06 21:00:17 +00:00
Andrea Guzzo b22f7d3a49 added a new handler callback to be used when the http connection is being closed
so that in case of connections closed prematurely, the user can clear resources
eventually bound to the connection using the 'connection_param' member of the
mg_connection structure
2014-02-06 11:22:13 +01:00
Sergey Lyubka eaa0e26a85 Starting to rebuild chat example on Lua 2014-02-06 10:18:30 +00:00
Sergey Lyubka a3a63f7e56 Using mg_connection::callback_param for mg_iterate_over_connection() 2014-02-06 10:00:20 +00:00
Sergey Lyubka c9036f3ac0 Added workaround for non-compliant runtimes in alloc_vprintf() 2014-02-05 12:33:36 +00:00
Sergey Lyubka 60858d7fe5 NO_WEBSOCKET -> MONGOOSE_NO_WEBSOCKET 2014-02-04 19:57:00 +00:00
Sergey Lyubka 1c914bde1d Merge pull request #316 from To1ne/master
use `mg_set_request_handler`
2014-02-04 11:55:52 -08:00
Toon Claes a487332aa0 use mg_set_request_handler 2014-02-04 20:48:38 +01:00
Sergey Lyubka 3987d4d560 Merge branch 'master' of ssh://github.com/valenok/mongoose 2014-02-04 18:13:10 +00:00
Sergey Lyubka 8d3181e0bf examples/html -> examples/chat_html_root 2014-02-04 18:13:02 +00:00
Sergey Lyubka 0f1a59aeb4 Increased env buf size 4096 -> 8192. Passing TMPDIR to CGI. 2014-02-04 18:11:56 +00:00
Sergey Lyubka 2cdf259940 Merge pull request #315 from To1ne/patch-1
Correct return values: PROCESSED or CALL_AGAIN
2014-02-04 06:51:41 -08:00
Toon Claes 0187fe943a Correct return values: PROCESSED or CALL_AGAIN 2014-02-04 15:24:32 +01:00
Sergey Lyubka a34d1ec00a Better handling of MONGOOSE_NO_SOCKETPAIR 2014-02-04 14:04:54 +00:00
Sergey Lyubka e70d98b7b0 Added fixes for eCos 2014-02-04 09:59:53 +00:00
Sergey Lyubka bea012a3c1 Removed redundant addenv call 2014-02-04 08:06:49 +00:00
Sergey Lyubka eb2d470f65 Merge branch 'master' of ssh://github.com/valenok/mongoose 2014-02-03 17:54:46 +00:00
Sergey Lyubka 652c352394 Passing SERVER_NAME, TMP and TEMP env vars to CGI. 2014-02-03 17:54:31 +00:00
Sergey Lyubka f1b37b3101 Merge pull request #313 from xant/upstream
bugfix: set the correct status if we still have pending data
2014-02-03 04:52:10 -08:00
Sergey Lyubka 81b9876af8 5.2 -> 5.3 2014-02-01 16:53:09 +00:00
Sergey Lyubka 7010addadb NO_AUTH -> MONGOOSE_NO_AUTH 2014-02-01 15:17:13 +00:00
xant 9e118c8a31 bugfix: set the correct status if we still have pending data 2014-01-31 19:09:12 +01:00
Sergey Lyubka 2fc654ac35 page.lp -> dirscan.lp 2014-01-30 17:49:37 +00:00
Sergey Lyubka 45861c7890 Disabling options if functionality is not enabled 2014-01-30 14:54:02 +00:00
Sergey Lyubka 1957879e10 Casting to int in mg_sprintf() call in handle_cgi 2014-01-29 12:34:51 +00:00
Sergey Lyubka ddbe690698 CGI directory logic fixed 2014-01-29 11:42:14 +00:00
Sergey Lyubka 9ba1596c46 Closing connection after mg_send_digest_auth() 2014-01-29 01:24:21 +00:00
Sergey Lyubka de509ae952 Fix around pid_t for mingw, thanks to Jay 2014-01-28 20:09:12 +00:00
Sergey Lyubka 77817cd019 Squashed the warnings 2014-01-28 13:42:26 +00:00
Sergey Lyubka 7083bea56b mg_parse_header(): allowing no spaces for comma-separated list 2014-01-28 13:01:28 +00:00
Sergey Lyubka 3dffd7604a Removed warnings 2014-01-28 12:55:20 +00:00
Sergey Lyubka 5a67af0c73 Using 1 ms in mg_poll_server 2014-01-28 12:51:27 +00:00
Sergey Lyubka 14526a2109 mg_add_uri_handler -> mg_set_request_handler() 2014-01-28 12:42:13 +00:00
Sergey Lyubka a6cfbd2536 docs URL changed 2014-01-28 10:48:27 +00:00
Sergey Lyubka 0d28f99275 wrapped pid_t and S_ISDIR definitions into ifndef for mingw build 2014-01-27 11:12:43 +00:00
Sergey Lyubka a281e99661 calling auth handler wrapped in MONGOOSE_NO_AUTH 2014-01-27 11:10:46 +00:00
Sergey Lyubka 170df7b676 local and remote port made unsigned short 2014-01-27 11:08:32 +00:00
Sergey Lyubka 3fa5c69f98 Fixed handle_delete() stat call 2014-01-27 11:06:05 +00:00
Sergey Lyubka e31f3058fa Added test for rewrites 2014-01-27 11:03:44 +00:00
Sergey Lyubka 83a9a726d3 Checking path existence 2014-01-26 11:24:24 +00:00
Sergey Lyubka 8ae0400b0d Added ability to set "0" as listening port. Exported local_ip and local_port to the client. 2014-01-25 13:50:57 +00:00
Sergey Lyubka 037fdbcccb Ignoring chdir() return value. Resetting mg_conn in close_local_endpoint() 2014-01-25 09:45:47 +00:00
Sergey Lyubka 5d2ac4e0a6 Merge branch 'master' of ssh://github.com/valenok/mongoose 2014-01-24 20:50:21 +00:00
Sergey Lyubka f977757a9d Added mg_set_auth_handler() 2014-01-24 20:49:57 +00:00
Sergey Lyubka 1db13aeed5 Merge pull request #304 from xant/master
allow to define a default mime-type
2014-01-24 09:51:51 -08:00
Andrea Guzzo 956788d7de changed mg_get_mime_type to expect the default type as argument
instead of using a configuration option
2014-01-24 15:56:21 +01:00
Andrea Guzzo 45f6612096 allow to define a default mime-type to use when lookup in the internal table fails
instead of always returning 'text/plain'

To allow setting a different default mime-type the mg_get_mime_type() api has been
extended to require an mg_server parameter.

Note that using a static global as default mime type wouldn't have allowed us to
control it via a configuration option because there is not global initialization phase
and configuration options are provided (and specific) to each server instance.
This means that different servers can be configured to use a different default mime-type
(which is also a desired behaviour in many scenarios) when lookup fails.
2014-01-24 14:45:19 +01:00
Sergey Lyubka 2392156fd4 Not exiting on a wrong option, best effort to recover 2014-01-23 20:57:27 +00:00
Sergey Lyubka cf1811f8c3 Added build instruction for windows 2014-01-23 12:00:40 +00:00
Sergey Lyubka 93c5335d80 USE_POST_SIZE_LIMIT -> MONGOOSE_USE_POST_SIZE_LIMIT, and unit test added 2014-01-23 11:24:00 +00:00
Sergey Lyubka 192205b10b Added 2014-01-23 10:36:08 +00:00
Sergey Lyubka 0377eea9c5 Added enum for callback return codes 2014-01-22 18:25:05 +00:00
Sergey Lyubka ad89868564 Moved must_hide_file to under #ifndef MONGOOSE_NO_FILESYSTEM 2014-01-22 18:24:28 +00:00
Sergey Lyubka 976f286134 Made mg_connection::content_len int -> size_t, which is 64-bit on 64-bit systems 2014-01-20 20:57:21 +00:00
Sergey Lyubka 503a1a749d Added unit test for MONGOOSE_USE_SSL 2014-01-20 20:50:30 +00:00
Sergey Lyubka 45a4266172 more examples added 2014-01-20 11:21:35 +00:00
Sergey Lyubka 2ea17e8c6d Adjusted docs and makefile to use correct preproc flags 2014-01-20 11:17:09 +00:00
Sergey Lyubka 67b7d79710 Removed comment about MONGOOSE_USE_STACK_SIZE 2014-01-20 11:10:30 +00:00
Sergey Lyubka 2e35e25935 ENABLE_DBG -> MONGOOSE_ENABLE_DEBUG, USE_STACK_SIZE -> MONGOOSE_USE_STACK_SIZE 2014-01-20 11:04:12 +00:00
Sergey Lyubka d86d409d3c Preprocessor definitions prefixed by MONGOOSE_ 2014-01-20 10:54:15 +00:00
Sergey Lyubka 1109d3aa3c Guarded #define EINPROGRESS 2014-01-20 09:02:57 +00:00
Sergey Lyubka 8208d9e250 Fixed -DUSE_SSL build 2014-01-20 09:01:16 +00:00
Sergey Lyubka fdd086b11c moved discard_leading_iobuf_bytes() out from conditional 2014-01-20 08:55:34 +00:00
Sergey Lyubka 5825e3ea74 Adding use_ssl to mg_connect() 2014-01-20 08:55:03 +00:00
Sergey Lyubka 061ba99124 Using vnotify() for die() 2014-01-20 08:54:06 +00:00
Sergey Lyubka ead098f726 Setting server_name 2014-01-19 17:01:43 +00:00
Sergey Lyubka 7a129c17ba Added http client with unit tests 2014-01-19 16:32:43 +00:00
Sergey Lyubka 400084ea8a read_from_client -> read_from_socket 2014-01-17 16:58:19 +00:00
Sergey Lyubka 82ad9a073a Calling long running connections regardless of select() status 2014-01-17 16:37:35 +00:00
Sergey Lyubka 22aea8acac Better comment for websocket example 2014-01-17 16:37:05 +00:00
Sergey Lyubka 40e5c744da Calling long-running URI handlers on each poll iteration 2014-01-17 15:49:16 +00:00
Sergey Lyubka e648681f1d Moved mg_connect() 2014-01-17 15:42:35 +00:00
Sergey Lyubka 02f19fc05a Using mg_handler_t for iterate_over_connections() 2014-01-17 11:45:57 +00:00
Sergey Lyubka 7690f9e34b Fixed websocket example, and websocket callback calling logic. 2014-01-17 10:17:15 +00:00
Sergey Lyubka 65c1278975 win32 build of server.c fixed 2014-01-16 14:40:26 +00:00
Sergey Lyubka 05e1135940 Added stand-alone console executable 2014-01-16 13:53:18 +00:00
Sergey Lyubka 7b6e8fb93c Moved idle_timeout_ms into compile-time option 2014-01-16 13:23:23 +00:00
Sergey Lyubka 9f1679e900 Merge branch 'master' of ssh://github.com/valenok/mongoose 2014-01-15 18:05:43 +00:00
Sergey Lyubka c0af018e20 removed build dir 2014-01-15 18:02:55 +00:00
Sergey Lyubka d553ae992a Unit test moved to top 2014-01-15 17:55:39 +00:00
Sergey Lyubka 89ef8f2f30 Removed method checks for CGI 2014-01-15 11:46:05 +00:00
Sergey Lyubka 9115a99f47 Fixed scanf format in parse_port_string() 2014-01-15 11:06:37 +00:00
Sergey Lyubka bbc65c7987 put_deleve_auth_file -> dav_auth_file. added placeholders for user 2014-01-15 07:57:59 +00:00
Sergey Lyubka bac0f75dd6 int sock -> sock_t sock 2014-01-15 07:10:09 +00:00
Sergey Lyubka 6440c358c1 C++ friendliness fix 2014-01-14 23:20:23 +00:00
Sergey Lyubka 6f84c8bbfb Using unicode API for service creation 2014-01-14 21:05:35 +00:00
Sergey Lyubka 0adbfcba96 Moved send_options out of NO_DAV conditional 2014-01-14 19:28:29 +00:00
Sergey Lyubka 136c3e8200 Eat prior POST data in close_local_endpoint() 2014-01-14 13:57:55 +00:00
Sergey Lyubka 7d699ea73c Added URI handler return value 2014-01-14 13:27:00 +00:00
Sergey Lyubka fc37b08139 URI handler status code drives streaming behavior 2014-01-14 13:16:58 +00:00
Sergey Lyubka 3aaf47d4e4 Return 1 from the URI handler 2014-01-14 12:50:13 +00:00
Sergey Lyubka 346179d1f1 keep-alive for all EP_USER requests 2014-01-14 00:44:27 +00:00
Sergey Lyubka 0148bc804a Added NO_THREADS wrapper 2014-01-13 21:35:45 +00:00
Sergey Lyubka 472e198d4a Fixed mg_parse_header to allow NULL strings 2014-01-13 21:31:18 +00:00
Sergey Lyubka bf6fc3262f Added test for static config opts 2014-01-13 21:08:03 +00:00
Sergey Lyubka 53311e8d6b removed ssi tests 2014-01-13 20:39:22 +00:00
Sergey Lyubka cc636197bc Added auth example 2014-01-13 17:58:14 +00:00
Sergey Lyubka 6b4f7e785d Added upload example 2014-01-13 17:01:11 +00:00
Sergey Lyubka 73ed83c5e3 Added mg_parse_multipart 2014-01-13 16:29:12 +00:00
Sergey Lyubka 56f128514e Implemented mg_set_http_error_handler() 2014-01-13 12:17:47 +00:00
Sergey Lyubka f0571f9fd6 Using mg.request_info.content 2014-01-13 10:58:14 +00:00
Sergey Lyubka a3663da90e Exposed mg_send_digest_auth_request(). Exported conn->content to Lua 2014-01-13 10:50:26 +00:00
Sergey Lyubka f74a1e1dc2 Fixed start_process on windows to use correct interpreter 2014-01-12 07:20:53 +00:00
Sergey Lyubka 74511b42f5 Using unicode winapi to load config file 2014-01-12 07:20:12 +00:00
Sergey Lyubka 04862eec85 Added wp target 2014-01-12 07:18:29 +00:00
Sergey Lyubka 4d105386ca Better handling of non-ascii chars for windows CGIs 2014-01-11 23:17:17 +00:00
Sergey Lyubka 44a35bb5bf Removed debug statement 2014-01-11 23:15:02 +00:00
Sergey Lyubka 022c9f0d47 Handling non-ascii chars in the binary 2014-01-11 21:32:05 +00:00
Sergey Lyubka e38061970e Exposed mg_authorize_digest() 2014-01-11 16:44:37 +00:00
Sergey Lyubka a4e8dc3069 Sending status 200 to CGI by default 2014-01-11 16:18:59 +00:00
Sergey Lyubka fa4179ee53 Made clean silent 2014-01-11 16:18:29 +00:00
Sergey Lyubka a8c8cfb665 fix non-initialized comparison 2014-01-11 10:09:26 +00:00
Sergey Lyubka e0b6109214 Added -DNO_FILESYSTEM 2014-01-11 09:48:27 +00:00
Sergey Lyubka d29f849602 Fixed optional build test 2014-01-11 09:48:13 +00:00
Sergey Lyubka 848c5d753e Fixed logic for get_url_to_me 2014-01-11 03:19:46 +00:00
Sergey Lyubka 4eef5b14fb Added comment to https://github.com/cesanta/mongoose/pull/287 2014-01-10 22:48:47 +00:00
Sergey Lyubka 283af71bbf Merge pull request #287 from oli-obk/fix/last_send_data_before_shutdown
mg_printf_data was ignored if mg_destroy_server was called directly afte...
2014-01-10 14:47:00 -08:00
Sergey Lyubka ff85b802c3 Using case-insensitive string comparison for connection: keep-alive 2014-01-10 22:46:03 +00:00
Sergey Lyubka e2b42e4117 Using case-insensitive string comparison for connection: keep-alive 2014-01-10 22:43:52 +00:00
Sergey Lyubka 63909b59c5 Added __cdecl to SSL decls to make sure correct linkage with OpenSSL which is cdecl 2014-01-10 22:41:36 +00:00
Sergey Lyubka 7380c65265 5.1 -> 5.2 2014-01-10 22:37:26 +00:00
Sergey Lyubka e9316a4feb CGI fixes 2014-01-10 21:59:37 +00:00
Oliver Schneider 2ac231cb7e mg_printf_data was ignored if mg_destroy_server was called directly after 2014-01-10 18:38:18 +01:00
Sergey Lyubka a741d53028 Fixed leak for server creation/destroy 2014-01-10 11:23:29 +00:00
Sergey Lyubka 9ea7b6f8ae Removed unnecessary buffer initializer 2014-01-10 11:11:26 +00:00
Sergey Lyubka 580d3da3c7 Using unicode winapi for stat(), fopen(), open() 2014-01-10 11:03:38 +00:00
Sergey Lyubka aa59dda966 wrapped read_from_cgi() into NO_CGI 2014-01-09 17:50:57 +00:00
Sergey Lyubka 47b92e4145 Added string defs for 301 and 302 codes in status_code_to_str() 2014-01-09 17:24:20 +00:00
Sergey Lyubka fa351959a0 5.0 -> 5.1 2014-01-09 14:08:50 +00:00
Sergey Lyubka 1414e2a236 Documented rewrites for HTTP errors 2014-01-09 12:47:29 +00:00
Sergey Lyubka 5fb275e146 Added URL rewrites for HTTP errors, to allow for error pages. 2014-01-09 12:36:25 +00:00
Sergey Lyubka 9390c66b48 Moved next_option() to the rest of string functions 2014-01-09 12:34:50 +00:00
Sergey Lyubka 2f69ca37d3 Better CGI error diagnostic for UNIX 2014-01-09 10:53:25 +00:00
Sergey Lyubka 4cd11de400 Ping only websocket connections 2014-01-09 10:37:17 +00:00
Sergey Lyubka 15a2639355 Added better diagnostic to send_http_error() 2014-01-09 10:35:43 +00:00
Sergey Lyubka c20f26dbb9 removed mg_fmt() 2014-01-09 09:58:19 +00:00
Sergey Lyubka cae797cf04 Merge branch 'master' of https://github.com/cesanta/mongoose 2014-01-09 09:37:35 +00:00
Sergey Lyubka 0d885add0e Fixed put_dir() 2014-01-09 09:36:58 +00:00
Sergey Lyubka 842231cc5c GetFullPathNameA -> GetFullPathName 2014-01-08 18:20:13 +00:00
Sergey Lyubka dc55a3ae40 Added #undef UNICODE in mongoose.c to force ANSI Win32 functions 2014-01-08 18:10:15 +00:00
Sergey Lyubka 4d85cc6c76 Removed -Wno-empty-translation-unit from unix CFLAGS :-) 2014-01-08 09:27:16 +00:00
Sergey Lyubka 8ac1b40c11 Added -Wno-empty-translation-unit to the unix CFLAGS 2014-01-08 09:19:56 +00:00
Sergey Lyubka 238b43af84 Squashed warnings for gcc 4.6.3 2014-01-08 09:16:36 +00:00
Sergey Lyubka 12c8e99bd5 Removed error_log_file from tests config 2014-01-07 14:57:08 +00:00
EC2 Default User 5f2f359bd6 Squashed warning under gcc 4.6.3 2014-01-07 14:53:48 +00:00
Sergey Lyubka ccf0ce4a1f Using chunked API in post.c example 2014-01-07 09:28:20 +00:00
Sergey Lyubka 134a5b7b9e Using chunked API in multi-threaded example 2014-01-07 09:24:48 +00:00
Sergey Lyubka d39daab29e Updated docs 2014-01-07 09:12:17 +00:00
Sergey Lyubka a798b1a937 Updated docs 2014-01-07 09:10:58 +00:00
Sergey Lyubka 04de3bb2f9 Updated docs 2014-01-07 09:05:34 +00:00
Sergey Lyubka 86da250e2c Using fat mongoose for php bundle 2014-01-06 14:58:21 +00:00
Sergey Lyubka 347a8c2f70 Fix source IP in logging 2014-01-06 14:53:41 +00:00
Sergey Lyubka 9624200663 SSL build 2014-01-06 13:31:46 +00:00
Sergey Lyubka 18b1e95350 LSP functionality 2014-01-06 13:08:39 +00:00
Sergey Lyubka 407877a4d5 added mongoose-lua.exe target 2014-01-06 12:40:41 +00:00
Sergey Lyubka 7541c6339a Removed error_log_file 2014-01-06 11:52:09 +00:00
Sergey Lyubka 31f1efd4f5 Removed index.shtml from the index files 2014-01-06 11:34:32 +00:00
Sergey Lyubka 2477f80a43 Wrapped run_as_user into conditional 2014-01-06 11:32:15 +00:00
Sergey Lyubka cf94fb3642 Added BIG_SOURCES 2014-01-06 11:29:36 +00:00
Sergey Lyubka 2210043b87 removed mutex calls. wrapped ssl_certificate option in a conditional 2014-01-06 11:22:11 +00:00
Sergey Lyubka 10872b3227 Inlined openssl definitions instead of including a header - preparing for ssl amalgamation 2014-01-05 23:52:43 +00:00
Sergey Lyubka cb324cfb9a test/page.mg.lua -> test/page.lp 2014-01-05 01:50:47 +00:00
Sergey Lyubka 4ee5849a04 Fixed spelling in readme 2014-01-05 00:01:31 +00:00
Sergey Lyubka fa216849e5 Resetting connection flags in close_local_endpoint() 2014-01-04 22:17:16 +00:00
Sergey Lyubka df6e35e330 dav_auth_file moved 2014-01-04 20:49:54 +00:00
Sergey Lyubka 96bb9aac36 Docs updated 2014-01-04 20:12:07 +00:00
Sergey Lyubka 7cec2fe280 Sorted options list 2014-01-04 20:11:55 +00:00
Sergey Lyubka 02937f8852 API doc synced 2014-01-04 14:28:20 +00:00
Sergey Lyubka 51f0cc2b67 Embed doc synced 2014-01-04 14:25:37 +00:00
Sergey Lyubka 253927008c Options doc synced 2014-01-04 14:20:47 +00:00
Sergey Lyubka 9778a4ccfc Options doc synced 2014-01-04 14:18:14 +00:00
Sergey Lyubka d0e2741832 Added new response creation interface 2014-01-04 11:31:55 +00:00
Sergey Lyubka 3a5e2fba88 5.0 lua example 2014-01-04 02:16:52 +00:00
Sergey Lyubka 85940c8045 Moved <netdb.h> to under unix includes 2014-01-04 02:05:18 +00:00
Sergey Lyubka a0b599b308 Removed protection from mg_write(). Refactored mg_iterate_over_connections() 2014-01-04 00:51:07 +00:00
Sergey Lyubka d43ccda9a7 Unbroke link to page.lp 2014-01-03 22:18:38 +00:00
Sergey Lyubka 675b83a3ef Let mongoose binary change CWD to document_root 2014-01-03 21:45:13 +00:00
Sergey Lyubka dfdfcc060d Merge branch 'master' of ssh://github.com/valenok/mongoose 2014-01-03 20:26:52 +00:00
Sergey Lyubka 143fb4f423 Fixed macos build 2014-01-03 20:26:41 +00:00
Sergey Lyubka b7eb12017c Update README.md 2014-01-03 03:29:42 +00:00
Sergey Lyubka bd1c6c1506 Update README.md 2014-01-03 03:29:09 +00:00
Sergey Lyubka efb7f4f05d Added frozen 2014-01-03 03:06:50 +00:00
Sergey Lyubka 5475fe661d Implemented USE_POST_SIZE_LIMIT 2013-12-31 13:57:51 +00:00
Sergey Lyubka 8f62822a33 Using mg_printf() 2013-12-31 13:57:19 +00:00
Sergey Lyubka 0aa1a9e324 Documented USE_POST_SIZE_LIMIT, USE_EXTRA_HTTP_HEADERS 2013-12-31 13:56:59 +00:00
Sergey Lyubka 7a77bb1c4a More descriptive comment in multithreaded example 2013-12-31 09:06:21 +00:00
Sergey Lyubka 4576b69e30 Initializing remote_ip and remote_port properly 2013-12-31 09:02:24 +00:00
Sergey Lyubka 4fd6eb597d Squashed C++ warning 2013-12-30 12:10:35 +00:00
Sergey Lyubka 257dacd7bb Squashed warning about dangerous optimization 2013-12-30 11:43:07 +00:00
Sergey Lyubka c88b7b19b3 Squashed warning on Windows, using INVALID_SOCKET 2013-12-30 11:35:33 +00:00
Sergey Lyubka 4fbfb5d0d0 Expanded hello example a little 2013-12-27 19:50:14 +00:00
Sergey Lyubka 67c678270e Minor wording changes for feeatures 2013-12-27 18:32:24 +00:00
Sergey Lyubka 049db9015b Mentioned async core 2013-12-26 12:55:50 +00:00
Sergey Lyubka 9dde225b5e Squashed C++ warning in read_from_cgi() 2013-12-26 11:45:44 +00:00
Sergey Lyubka 3a0a22f4cc Add an ability to pass listening socket to mongoose binary 2013-12-26 11:37:52 +00:00
Sergey Lyubka b4a4b15835 Removed old cruft 2013-12-26 11:33:19 +00:00
Sergey Lyubka dca2eab152 removed stdio.h 2013-12-26 10:21:09 +00:00
Sergey Lyubka f9f212442c Added comment 2013-12-26 10:20:02 +00:00
Sergey Lyubka 83793aadde Removed num_threads 2013-12-26 10:14:13 +00:00
Sergey Lyubka f7a705c40a Added multi-threaded example 2013-12-26 10:13:04 +00:00
Sergey Lyubka f5f6edcf5a Added mg_printf() back 2013-12-26 10:12:18 +00:00
Sergey Lyubka 9cb1048c66 Added lightweight feature 2013-12-26 09:33:26 +00:00
Sergey Lyubka 522a7eb554 Added socket functionality 2013-12-24 11:33:56 +00:00
Sergey Lyubka 072833acd5 Squashed win32 warnings 2013-12-23 10:01:11 +00:00
Sergey Lyubka a5aa08e408 Restored post.c in windows example build 2013-12-23 08:09:59 +00:00
Sergey Lyubka 12d98a1732 Restores post.c example 2013-12-23 08:06:35 +00:00
Sergey Lyubka a6c2c2a10b Comparing URI prefix when looking for URI handler 2013-12-23 08:06:10 +00:00
Sergey Lyubka fbe1914226 Copy -> Download and copy 2013-12-23 07:22:05 +00:00
Sergey Lyubka 64a744055f Added notes on buffering POST data and websocket data 2013-12-22 08:27:23 +00:00
Sergey Lyubka 0007e47c07 Build command re-worded 2013-12-22 08:27:02 +00:00
Sergey Lyubka 4708cce8bd mg_poll_server() returns currect time. add mg_set_listening_socket() and mg_get_listening_socket() 2013-12-21 20:52:54 +00:00
Sergey Lyubka 3eb9156e60 calling iterate_over_connections() from the IO thread 2013-12-21 20:26:55 +00:00
Sergey Lyubka 2990f9328a struct linked_list_link -> struct ll 2013-12-21 20:10:08 +00:00
Sergey Lyubka a0befd65a0 Nitpick wording 2013-12-21 16:06:00 +00:00
Sergey Lyubka 872ad8badf Added NO_* and USE_* flag descriptions 2013-12-21 16:04:22 +00:00
Sergey Lyubka 0970e080d9 Added OpenSSL support 2013-12-21 15:50:11 +00:00
Sergey Lyubka 52fe1461d5 Removed SSI 2013-12-21 14:44:29 +00:00
Sergey Lyubka d5b33adb88 Properly crafting HTTP reply line by parsing CGI reply headers 2013-12-21 10:53:20 +00:00
Sergey Lyubka ec84a148f0 Creating server ctl socket in a loop to protect from interrupt 2013-12-21 10:19:12 +00:00
Sergey Lyubka 77d5d4c921 Added sldr reference 2013-12-21 08:34:02 +00:00
Sergey Lyubka 58dab48156 Using unsigned char in deliver_websocket_frame() arithmetic 2013-12-20 17:59:07 +00:00
Sergey Lyubka 7abb406d0f put_delete_auth_file -> dav_auth_file 2013-12-20 17:57:13 +00:00
Sergey Lyubka b941dcd5c5 Removed throttle option 2013-12-20 13:34:09 +00:00
Sergey Lyubka b7adf9b52a Passing server_param to the URI callback 2013-12-20 09:44:51 +00:00
Sergey Lyubka 28f7d83a74 Commented out chat example, as it is broken atm 2013-12-19 10:46:12 +00:00
Sergey Lyubka 34ee1ef3d6 Commented out chat example, as it is broken atm 2013-12-19 10:45:41 +00:00
Sergey Lyubka e518517456 Commented out chat example, as it is broken atm 2013-12-19 10:42:39 +00:00
Sergey Lyubka 7d0662f1bc Make WEBSOCKET_PING_INTERVAL_SECONDS overridable from the command line 2013-12-18 10:13:31 +00:00
Sergey Lyubka e3751d29d5 Made mongoose send websocket PINGs automatically 2013-12-18 09:35:36 +00:00
Sergey Lyubka 04b9ccca22 Testing server PINGs 2013-12-18 09:35:19 +00:00
Sergey Lyubka 1a17165227 Sending messages every 10 seconds, to allow mongoose send PINGs 2013-12-18 09:34:36 +00:00
Sergey Lyubka b6d968f00c Added qcomm example to the build 2013-12-18 09:33:59 +00:00
Sergey Lyubka a69987a711 Updated internals manual 2013-12-16 13:45:13 +00:00
Sergey Lyubka 492328474d Only hello example left, adopted to the new API 2013-12-16 13:33:50 +00:00
Sergey Lyubka 673a2c581f Removed http client, and examples references 2013-12-16 13:32:54 +00:00
Sergey Lyubka 9ef42621e0 Fixed wrong memset() in scan_directory() 2013-12-15 10:12:19 +00:00
Sergey Lyubka f5865886b2 Respecting -run_as_user 2013-12-12 20:31:43 +00:00
Sergey Lyubka 473e2a1cb2 Added <signal.h> for linux, and squashed warning in transfer_file_data() 2013-12-12 13:51:14 +00:00
Sergey Lyubka 146cf1d1c0 Calling mg_socketpair() in a loop until success. Ignoring SIGPIPE. Squashed waring in mg_start_thread() 2013-12-12 13:43:59 +00:00
Sergey Lyubka ab73055ef3 Added side-effect note for mg_create_server() 2013-12-12 13:41:33 +00:00
Sergey Lyubka 3b83543592 Commented out irrelevant design description 2013-12-10 23:49:37 +00:00
Sergey Lyubka d4ac96c24d Some wording/spelling changes 2013-12-10 23:42:44 +00:00
Sergey Lyubka 0612129a88 Async API 2013-12-10 23:34:08 +00:00
Sergey Lyubka 9bd5903f1d API.md is split to API.md and Embed.md 2013-12-10 11:16:25 +00:00
Sergey Lyubka d4eae0e251 Added minimalistic example 2013-12-10 00:40:32 +00:00
Sergey Lyubka 4d7ea04dd8 Added cast for c++ friendliness 2013-12-10 00:19:33 +00:00
Sergey Lyubka 653fab6b41 Added skeleton lua support 2013-12-09 15:53:35 +00:00
Sergey Lyubka f4c30b746e Switched to async, non-blocking core 2013-12-09 14:18:49 +00:00
Sergey Lyubka 923e5004e8 Added CFLAGS_EXTRA to windows compilation flags 2013-12-09 11:53:55 +00:00
Sergey Lyubka b14a1e25f0 Not generating mongoose.c 2013-12-08 18:39:03 +00:00
Sergey Lyubka 5a3b1123f6 tests moved under build 2013-12-07 17:47:14 +00:00
Sergey Lyubka 6a9494b683 Added mg_get_var() to core, with unit test 2013-12-07 17:46:56 +00:00
Sergey Lyubka 63c5658a2b Fixed lua compilation under linux 2013-12-07 17:45:59 +00:00
Sergey Lyubka fe087cdce9 Fixed lsp_sock_send(), return value 2013-12-07 17:45:34 +00:00
Sergey Lyubka af7efd980c Adjusting unit test for core 2013-12-06 22:14:55 +00:00
Sergey Lyubka 2cb325c981 Added DAV to core 2013-12-06 16:01:41 +00:00
Sergey Lyubka 66435a7158 Removed speed limit feature 2013-12-06 13:02:44 +00:00
Sergey Lyubka 48417ba911 Formatting change in overview 2013-12-06 13:00:33 +00:00
Sergey Lyubka f39c4c8909 Added directory listing support to core 2013-12-06 12:55:28 +00:00
Sergey Lyubka 2a7e720f12 app code moved to qcomm.c 2013-12-06 08:53:30 +00:00
Sergey Lyubka ec22250d9b Added mg_iterate_over_connections(), mg_websocket_write() 2013-12-06 08:52:42 +00:00
Sergey Lyubka a7889756a9 Made qcomm example compile 2013-12-06 08:23:26 +00:00
Sergey Lyubka 9ac67770eb mongoose5 example 2013-12-05 23:16:12 +00:00
Sergey Lyubka 3330bca4be Using mg_handler_t 2013-12-05 16:21:53 +00:00
Sergey Lyubka 31f0409bf9 Added CGI endpoint 2013-12-05 15:03:38 +00:00
Sergey Lyubka ebf9ee089b Do not send 500 when timing out getreq() 2013-12-05 11:12:07 +00:00
Sergey Lyubka 88cf329490 Closing connection on 5xx errors 2013-12-05 10:47:03 +00:00
Sergey Lyubka bba29d32ce Using socketpair for inter-thread communication 2013-12-05 10:01:11 +00:00
Sergey Lyubka 2f1f408882 Added qc test 2013-12-05 04:14:58 +00:00
Sergey Lyubka 46a9e42b8f Async websockets work 2013-12-05 04:14:10 +00:00
Sergey Lyubka 58d3abe165 Fixed iterate_callback() 2013-12-05 00:52:42 +00:00
Sergey Lyubka 03e737829a Made URI handler work 2013-12-05 00:22:21 +00:00
Sergey Lyubka 95d8881454 Fixed spool() to properly resize, commented out non-implemented API 2013-12-04 10:19:55 +00:00
Sergey Lyubka a50a52ca91 Fixed #259 2013-12-04 10:11:12 +00:00
Sergey Lyubka 50371ef309 Introduced file_stat_t to use 64 bit file support on Windows 2013-12-03 12:08:45 +00:00
Sergey Lyubka 6192d1b53a Added send_http_error() 2013-12-03 11:12:43 +00:00
Sergey Lyubka daa9175139 Added caching support (304 response) 2013-12-03 11:01:43 +00:00
Sergey Lyubka 8a65611a8c Using core.h and modified API 2013-12-02 22:22:22 +00:00
Sergey Lyubka 6c8a0aa768 denying directory accesses 2013-12-01 10:49:25 +00:00
Sergey Lyubka 787b15551d builtin mime types defs moved to top 2013-12-01 10:28:00 +00:00
Sergey Lyubka 2c896e7e5c Added proper static file handling, but range support is still broken 2013-12-01 10:25:31 +00:00
Sergey Lyubka 0e49214c7e Added mutex protection for write calls 2013-12-01 09:46:05 +00:00
Sergey Lyubka 914606a046 fmtspool() -> mg_write() 2013-12-01 07:44:38 +00:00
Sergey Lyubka b30417e908 Made core c++ friendly 2013-12-01 00:42:04 +00:00
Sergey Lyubka 5b8d4cdf68 main(argc,argv) -> main(void) 2013-12-01 00:35:22 +00:00
Sergey Lyubka ba06d135c3 Added call_user() 2013-12-01 00:33:26 +00:00
Sergey Lyubka f0d3d7e81d Cleaning up ctl sockets 2013-11-30 23:59:53 +00:00
Sergey Lyubka d1bd15291e request pipelining done 2013-11-30 23:23:38 +00:00
Sergey Lyubka d00b7f4300 Serving files 2013-11-28 20:44:11 +00:00
Sergey Lyubka ebc909b61b Added copyright 2013-11-27 14:10:51 +00:00
Sergey Lyubka 537fb39b21 Async, non-blocking experiment 2013-11-27 14:09:34 +00:00
Sergey Lyubka e106151072 Showing port number on mongoose icon context menu 2013-11-26 22:17:29 +00:00
Sergey Lyubka 257de0709f Better wording for put_delete_auth_file option 2013-11-25 17:06:24 +00:00
Sergey Lyubka 774a819e76 Better description for put_delete_auth_file option 2013-11-25 17:05:12 +00:00
Sergey Lyubka ff1412f29d Better description for put_delete_auth_file option 2013-11-25 17:04:41 +00:00
Sergey Lyubka c6606c714f Removed symbian-specific #defines. Nokia and Symbian got killed by Microsoft. 2013-11-25 14:32:33 +00:00
Sergey Lyubka de3d4e3019 Formatted hyperlinks 2013-11-25 13:45:48 +00:00
Sergey Lyubka 2f49e63d5b Moved docstrings to API.md 2013-11-25 13:43:12 +00:00
Sergey Lyubka 988b40f70d Moved webdav functions into webdav.c 2013-11-24 17:33:05 +00:00
Sergey Lyubka b5fdd48d76 Moved websocket functions into websocket.c 2013-11-24 17:29:21 +00:00
Sergey Lyubka f4f73a8dfa Init vars in handle_cgi_request() 2013-11-23 15:04:35 +00:00
Sergey Lyubka 74711c686f Added directory scanning example, and enabled posix routines in Lua for unix environment 2013-11-23 13:58:27 +00:00
Sergey Lyubka 78c994f7cc Added /I. for CL flags 2013-11-23 13:58:01 +00:00
Sergey Lyubka 2d5d668863 Squashed warning 2013-11-23 13:48:55 +00:00
Sergey Lyubka 87279f3518 Throttling functionality removed 2013-11-23 13:47:07 +00:00
Sergey Lyubka bd10a03da0 Throttling functionality removed 2013-11-23 13:46:45 +00:00
Sergey Lyubka d138119d24 Made separate target for mongoose-lua-sqlite 2013-11-23 13:44:33 +00:00
Sergey Lyubka 73019665fa moved mg_upload() into upload.c 2013-11-23 10:49:13 +00:00
Sergey Lyubka 66824e7757 moved CGI and IO into separate files 2013-11-23 10:47:35 +00:00
Sergey Lyubka 7fe6b29218 mg_get_cookie() moved to string.c 2013-11-23 10:32:43 +00:00
Sergey Lyubka ebdf973af9 log_access() moved to log.c 2013-11-23 10:31:24 +00:00
Sergey Lyubka 71dd7a96c7 mg_url_decode() moved to string.c 2013-11-23 10:26:28 +00:00
Sergey Lyubka 886dcb3f5d get_request_len() moved to string.c 2013-11-23 10:25:20 +00:00
Sergey Lyubka 37751a2875 directory ops moved to directory.c 2013-11-23 10:24:25 +00:00
Sergey Lyubka 45347bd44c Moved mime-type functions to mime.c 2013-11-23 07:48:46 +00:00
Sergey Lyubka 8c4521af03 moved remove_double_dots_and_double_slashes() to string.c 2013-11-23 07:46:11 +00:00
Sergey Lyubka 0d2a8db626 Added #define for WSAPoll 2013-11-22 13:39:57 +00:00
Sergey Lyubka e791a795b4 typo fixed 2013-11-22 08:45:04 +00:00
Sergey Lyubka 03d846529d Update README.md 2013-11-13 03:04:31 +00:00
Sergey Lyubka 607651a3ff Squashed warning for MG_REQUEST_END 2013-11-11 17:18:48 +00:00
Sergey Lyubka 0714e0dd8f Updated Android build 2013-11-04 21:15:01 +00:00
Sergey Lyubka 224d18589f Fixed -DNO_SSL build 2013-11-02 10:24:30 +00:00
Sergey Lyubka 2fd7191836 Squashed C++ void * casting warning 2013-10-30 23:04:35 +00:00
Sergey Lyubka 853d162b55 removed double def for ssl_sw 2013-10-30 23:02:36 +00:00
Sergey Lyubka 762a68a0cf Moved some docs to markdown 2013-10-30 23:02:15 +00:00
Sergey Lyubka 1da098671e Moved docstrings to API.md 2013-10-19 14:07:46 -07:00
Sergey Lyubka f852a4db0f Moved docstrings to API.md 2013-10-19 13:14:16 -07:00
Sergey Lyubka ddea940690 Docs added 2013-10-18 08:57:59 -07:00
Sergey Lyubka 292e43b41b Removed unit test dependency 2013-10-15 13:11:47 -07:00
Sergey Lyubka 915e923e35 Firing MG_HTTP_ERROR 2013-10-10 07:46:19 -07:00
Sergey Lyubka e6ac3af454 Removed debug message 2013-10-07 17:29:53 +01:00
Sergey Lyubka 3adaf8dba9 Reaping zombies properly 2013-10-07 17:29:07 +01:00
Sergey Lyubka 1777cc6e86 Squashed warning 2013-10-07 17:28:53 +01:00
Sergey Lyubka f9f623bd60 c# example synced to the current version, and tested 2013-10-06 12:16:46 +01:00
Sergey Lyubka fe95707b4e Rewording 2013-10-06 07:24:34 +01:00
Sergey Lyubka a631ee1e1e Service code refactored 2013-10-05 07:45:05 +01:00
Sergey Lyubka 493666dac6 Wording and links corrected 2013-10-03 19:34:27 +01:00
Sergey Lyubka 46ef4e33c8 Wording and links corrected 2013-10-03 19:34:00 +01:00
Sergey Lyubka cafaecfc56 Moved HTTP client, ssl and some util code into separate files 2013-10-03 19:09:35 +01:00
Sergey Lyubka 47606a71ee Moved unix and win32 code to different files 2013-10-02 23:21:13 +01:00
Sergey Lyubka eedfedd13b Added reference to a relevant pull request in getreq() comment 2013-10-01 19:09:29 +01:00
Sergey Lyubka 87d841d81b Set content_len to 0 for GET requests without Content-Length header. 2013-10-01 18:49:44 +01:00
Sergey Lyubka 5153eebc9b mg_read() does not block on content_len=0. mg_read() reads until socket is closed if content-length is not provided 2013-10-01 17:47:32 +01:00
Sergey Lyubka 70154f6c23 Moved mod_lua.c to src/lua.c 2013-10-01 15:16:09 +01:00
Sergey Lyubka d3577b7877 Moved auth code to separate file 2013-10-01 14:54:26 +01:00
Sergey Lyubka 199e0a330f Moved options handling to src/options.c 2013-09-30 19:57:33 +01:00
Sergey Lyubka a8da1b3334 Moved date parsing in build/src/parse_date.c 2013-09-30 19:51:16 +01:00
Sergey Lyubka 63c19b4631 Moved to unix file format 2013-09-30 13:11:24 +01:00
Sergey Lyubka 1f471e1cf3 Moved string functions to src/string.c 2013-09-30 13:09:16 +01:00
Sergey Lyubka ef28c37529 Removed mg_get_request_info() 2013-09-30 13:02:36 +01:00
Sergey Lyubka cd7e1b9eb7 Moved more ssl defs to internal.h 2013-09-30 12:59:43 +01:00
Sergey Lyubka 226d476856 Moved more defines to internal.h. Squashed some warnings in win32 2013-09-29 23:58:32 +01:00
Sergey Lyubka 21965e0e03 Splitting monolithic mongoose.c to separate files. Amalgamating into mongoose.c for release. 2013-09-29 23:56:59 +01:00
Sergey Lyubka 40ab4a8d3d Fixed websocket example logic when freeing the message, again! 2013-09-29 22:43:58 +01:00
Sergey Lyubka e84d0574fa Fixed websocket example logic when freeing the message 2013-09-29 22:01:31 +01:00
Sergey Lyubka 1a64d37fc7 Fixed mg_websocket_read() 2013-09-29 09:25:47 +01:00
Sergey Lyubka 9cca843a9b Typo fixed 2013-09-29 08:01:14 +01:00
Sergey Lyubka ecbf79135f Refactored API, returned back to event-based handlers. Upload and Websocket API simplified 2013-09-28 11:00:54 +01:00
Sergey Lyubka 96eb48902b Always invoking test 2013-09-28 00:15:24 +01:00
Sergey Lyubka 079c99c47f Started to restore single callback function 2013-09-26 13:25:51 +01:00
Sergey Lyubka 6d2a76b609 Added c# example 2013-09-26 12:50:11 +01:00
Sergey Lyubka 24e0950ca2 Using stdcall for mongoose.dll 2013-09-26 12:49:41 +01:00
Sergey Lyubka 98214ce1a4 Removed init_lua() and open_file() callbacks 2013-09-26 09:35:07 +01:00
Sergey Lyubka 7eed7eab36 Added mongoose.dll target 2013-09-26 09:34:36 +01:00
Sergey Lyubka f0fb5c01a2 Added unit_test.c dependency for unix_unit_test 2013-09-25 22:58:36 +01:00
Sergey Lyubka a92aa3bf49 Added unix_unit_test as a dependancy for mongoose 2013-09-25 18:37:17 +01:00
Sergey Lyubka b12cc9fd49 Refactored handle_options_request() to use mg_write() with less copying 2013-09-25 18:30:51 +01:00
Sergey Lyubka a61c3a2636 Added handle_delete_request(). Refactored convert_uri_to_file_name() 2013-09-25 18:24:36 +01:00
Sergey Lyubka 9fd435059f Setting user_data for fake connection 2013-09-25 14:28:09 +01:00
Sergey Lyubka 3156ac9791 read_websocket(): check for WEBSOCKET_OPCODE_CLOSE corrected 2013-09-25 14:25:14 +01:00
Sergey Lyubka b946f33189 Moved more docs to the web site 2013-09-24 11:24:10 +01:00
Sergey Lyubka 1e0b7054e6 Added mongoose.h to the mongoose.c dependancy 2013-09-24 11:23:51 +01:00
Sergey Lyubka 46e04e857c Added test for dir with non-ascii char 2013-09-24 10:08:39 +01:00
Sergey Lyubka 4abdeaddbf Docs reference moved to downloads section 2013-09-20 13:30:20 +01:00
Sergey Lyubka 029af1c376 Docs moved to Cesanta site 2013-09-20 13:27:48 +01:00
Sergey Lyubka c02f2ff4bb Update instruction to clone Git repo rather then using tarball 2013-09-18 09:52:06 +01:00
Sergey Lyubka f74fec8a7e Split docs by sections 2013-09-18 09:44:12 +01:00
Sergey Lyubka 50f8e8891b Removed references to usermanual.md 2013-09-18 09:44:00 +01:00
Sergey Lyubka d67b1dbd53 Added CommonProgramFiles(x86) to the CGI environment under Win32, to make Win32::OLE work under CGI 2013-09-18 08:11:37 +01:00
Sergey Lyubka b0eeb7d67b Renamed retina icons to @2x.png 2013-09-18 08:07:44 +01:00
Sergey Lyubka 2c6c75cbad Added icns icon file 2013-09-18 08:07:24 +01:00
Sergey Lyubka 241388b8a0 Using icns as bundle icon file 2013-09-18 08:07:06 +01:00
Sergey Lyubka 820b497f42 Installing icns file in DMG 2013-09-18 08:06:48 +01:00
Sergey Lyubka 88d8435a02 mongoose_22x22.png -> mongoose_22x22, let OS get Retina icon automatically 2013-09-18 08:06:08 +01:00
Sergey Lyubka f3f177f3ed Removed analytics tracking 2013-09-17 16:47:27 +01:00
Sergey Lyubka bfa171cd97 Squashed warning: added #include <direct.h> for windows getcwd() 2013-09-17 16:14:50 +01:00
Sergey Lyubka 19c94ce218 Fix for the issue 109 2013-09-17 16:09:00 +01:00
Sergey Lyubka 5e5033a0f3 Fix for the issue 156 2013-09-16 23:25:30 +01:00
Sergey Lyubka 411a269991 valenok -> cesanta 2013-09-16 22:45:19 +01:00
Sergey Lyubka bca6aab5a5 Moved UserManual to docs/ 2013-09-16 22:42:29 +01:00
Sergey Lyubka 330e2ff74e Fixed macos build target 2013-09-16 22:42:18 +01:00
Sergey Lyubka eb5848478c Added credits section mentioning those great who contributed 2013-09-12 17:30:03 +01:00
Sergey Lyubka 5bb361b1d2 Squashed warnings 2013-09-12 10:03:04 +01:00
Sergey Lyubka 0d40364089 Removed unused stuff, lua & ssl sources, reorganized targets. 2013-09-12 10:02:50 +01:00
Sergey Lyubka 16c4fe1f37 4.1 -> 4.2 2013-09-07 22:05:39 +01:00
Sergey Lyubka 3070e8572d removed file locking on windows, to fix the crash introduced by 52e3be5c58 2013-09-07 22:04:59 +01:00
Sergey Lyubka baf4d8af27 Mongoose_$V.dmg -> Mongoose-$V.dmg 2013-09-07 22:04:09 +01:00
Sergey Lyubka d5acf2e2a7 4.0 -> 4.1 2013-09-07 20:21:27 +01:00
Sergey Lyubka 22f8cb14d5 Updated downloads link 2013-09-07 20:20:11 +01:00
Sergey Lyubka e28b3ca91d Not ignoring SIGCHLD, cause it renders system() unusable on QNX 2013-09-07 19:50:54 +01:00
Sergey Lyubka 73d2b395d1 Moved SIGCHLD handler out of mongoose.c. Embedded user must set SIGCHLD handler if CGI is used. 2013-09-07 19:41:40 +01:00
Sergey Lyubka e556a487e0 Fix for the SCRIPT_NAME in the presence of PATH_INFO, https://code.google.com/p/mongoose/issues/detail?id=403 2013-09-07 18:49:24 +01:00
Sergey Lyubka 5728fa1cea Added windows_tiny target. Adding only mongoose.[ch] files to the source tarball. 2013-09-07 18:47:38 +01:00
Sergey Lyubka b461edabd9 Squashed warnings 2013-09-07 18:46:50 +01:00
Sergey Lyubka c9e666babc Merge branch 'master' of ssh://github.com/valenok/mongoose 2013-09-07 07:07:28 +01:00
Sergey Lyubka 18e64397fc Fixed tests 2013-09-07 07:07:18 +01:00
Sergey Lyubka 3c8418d324 Removed -I$(LUA) from LUA_FLAGS 2013-09-07 07:07:07 +01:00
Sergey Lyubka 784a1580ce Merge pull request #232 from ellusak/master
use chunked encoding for directory listing
2013-09-05 11:18:07 -07:00
Sergey Lyubka 6a0ac69761 version 3.9 -> 4.0 2013-09-05 12:35:44 +01:00
ellusak 7c06279a8c use chunked encoding for directory listing 2013-09-05 17:14:34 +08:00
Sergey Lyubka aec6f85f55 Merge branch 'master' of ssh://github.com/valenok/mongoose 2013-09-02 11:15:57 +01:00
Sergey Lyubka 52e3be5c58 Refactored f[un]lockfile for Windows using LockFileEx/UnlockFileEx 2013-09-02 11:15:48 +01:00
Sergey Lyubka 01a664ad06 Merge pull request #231 from tehnick/fix-compilation-warning
Fixed compilation warning
2013-08-31 03:08:06 -07:00
Boris Pek 94933047a7 Fixed compilation warning 2013-08-30 21:32:58 +03:00
Sergey Lyubka cd6005c86f Calling thread_stop() before free-ing conn 2013-08-28 09:54:00 +01:00
Sergey Lyubka 6d14ed3a18 thread_setup -> thread_start 2013-08-28 09:53:10 +01:00
Sergey Lyubka 0fb5db59d3 Putting CFLAGS at the end of the compilation flags for Linux 2013-08-27 00:02:40 +01:00
Sergey Lyubka 20b274bb2b Using amalgamated lua 2013-08-27 00:01:53 +01:00
Sergey Lyubka 00b289a0f4 Added thread_start() and thread_stop() 2013-08-26 12:22:38 +01:00
Sergey Lyubka 9818f9849b Added downloads section 2013-08-20 16:26:33 +01:00
Sergey Lyubka df1c23222e Corrected google group email address. Reworded paragraph about SLRE. 2013-08-20 07:54:28 +01:00
Sergey Lyubka f18ac3e094 Fixed test invokation 2013-08-19 19:10:41 +01:00
Sergey Lyubka d8596fae27 Fixed unit test 2013-08-19 19:10:17 +01:00
Sergey Lyubka 85209ac4fa Reverted contributions by jmucchiello 2013-08-19 11:54:47 +01:00
Sergey Lyubka a58e82b301 Added note about GNU make 2013-08-19 11:39:59 +01:00
Sergey Lyubka 35f485558b Amalgamated Lua 2013-08-19 07:56:13 +01:00
Sergey Lyubka 93365fcbd2 audio/ogg -> application/ogg 2013-08-19 06:46:13 +01:00
Sergey Lyubka e40a44ba70 Moved mod_lua to build/ 2013-08-18 23:04:36 +01:00
Sergey Lyubka 1eed770238 Moved Makefile and main.c to build/ 2013-08-18 23:02:43 +01:00
Sergey Lyubka 511ef4137f Better SSI mime type handling 2013-08-18 13:27:54 +01:00
Sergey Lyubka 479164129b Styling, lines > 80 chars 2013-08-18 13:16:53 +01:00
Sergey Lyubka 08746115e2 Sending EXTRA_HTTP_HEADERS in handle_file_request() 2013-08-18 13:03:39 +01:00
Sergey Lyubka 587aad75c1 License change 2013-08-16 11:28:50 +01:00
Sergey Lyubka 218428662e License change 2013-08-16 11:18:16 +01:00
Sergey Lyubka 04fc209644 removing dmg dir on clean 2013-08-16 11:18:04 +01:00
Sergey Lyubka 53bedd1eb5 made separate targets for each example 2013-08-16 11:17:15 +01:00
Sergey Lyubka a0b43ae8e0 Merge pull request #218 from MikieMorales/patch-3
Changing Embedding example to C file.
2013-08-14 09:50:07 -07:00
Miguel Morales 866a7e2823 Changing Embedding example to C file. 2013-08-14 12:38:32 -04:00
Sergey Lyubka 2055d41a9f Corrected misplaced brackets in parse_http_message() 2013-08-14 10:55:36 +01:00
Sergey Lyubka 1ef29c1b3b Using #define MGSQLEN for the socket queue length 2013-08-14 08:23:30 +01:00
Sergey Lyubka e95dbb90a7 Sending content-length from put_file() 2013-08-14 08:15:42 +01:00
Sergey Lyubka cf18c932a4 Refactored parse_http_message() 2013-08-14 07:41:47 +01:00
Sergey Lyubka a730afc44d Merge branch 'master' of ssh://github.com/valenok/mongoose 2013-08-14 07:09:28 +01:00
Sergey Lyubka 94296c9697 Corrected check for websocket connection close 2013-08-14 07:09:22 +01:00
Sergey Lyubka 667707df50 Merge pull request #214 from DanielOaks/server_software
Added SERVER_SOFTWARE CGI variable
2013-08-13 04:28:26 -07:00
Daniel Oaks 90b6fab3bb Added SERVER_SOFTWARE CGI variable 2013-08-13 21:21:05 +10:00
Sergey Lyubka e47dbcbdc5 Merge pull request #213 from MikieMorales/patch-1
Update UserManual.md
2013-08-12 08:59:39 -07:00
MikieMorales 2a15f8d567 Update UserManual.md
SheBang wikipedia link is broken due to the end parenthesis. I tried escaping it with backslash and it seems to be working now.
2013-08-12 11:23:11 -04:00
Sergey Lyubka b5d397c74f Merge pull request #212 from pas2k/master
Consume \n in mg_fgets when reading from membuf
2013-08-12 04:16:19 -07:00
Pavel Khlebovich 3d6b373c8f (mg_fgets) Accept lines at the end not terminated by \n
(mg_fgets) Don't consume more than size bytes when line cannot fit into buffer.
2013-08-12 14:27:20 +04:00
Sergey Lyubka ed236dddeb changed signature for mg_exec_lua_script(). fixed lua_error_handler() 2013-08-12 09:53:42 +01:00
Sergey Lyubka 596fb1e88a Merge branch 'master' of ssh://github.com/valenok/mongoose 2013-08-12 09:52:22 +01:00
Sergey Lyubka ca0cd5040d Updated sqlite 2013-08-12 09:52:10 +01:00
Pavel Khlebovich 5b84acbc14 Consume \n in mg_fgets when reading from membuf. 2013-08-12 00:47:12 +04:00
Sergey Lyubka c12838e2c3 Merge pull request #211 from nigels-com/msc_ver
gcc complains about _MSC_VER being an undefined macro.
2013-08-08 22:50:19 -07:00
Nigel Stewart fa3e6ce271 gcc complains about _MSC_VER being an undefined macro. 2013-08-08 22:08:00 -05:00
Sergey Lyubka 743f48b8e0 Added mg_exec_lua_script, mg_prepare_lua_environment -> prepare_lua_environment 2013-08-08 13:11:05 +01:00
Sergey Lyubka 421c16b2bb Added -DLUA_USE_DLOPEN, and added mongoose.o: mod_lua.c 2013-08-08 12:15:40 +01:00
Sergey Lyubka 3054a7f09e Make sure child closes all pipe fds when executing CGI 2013-08-03 07:18:25 +01:00
Sergey Lyubka 2de96bd54e Workaround for non-compliant vsnprintf() 2013-08-02 11:00:21 +01:00
Sergey Lyubka f815c315e7 Added git analytics link 2013-08-01 14:20:35 +01:00
Sergey Lyubka e59ee00154 Added request_timeout_ms 2013-07-30 15:21:34 +01:00
Sergey Lyubka b07745ab50 Added Lua dll example 2013-07-30 14:49:52 +01:00
Sergey Lyubka 2468a8fb38 Merge branch 'master' of ssh://github.com/valenok/mongoose 2013-07-30 11:19:42 +01:00
Sergey Lyubka ed38a4102e showing error string as well as numeric error on bind failure 2013-07-30 11:19:33 +01:00
Sergey Lyubka b1c66f6544 Merge pull request #207 from bick4ord/master
Add casts to fix strict compiler errors [-fpermissive]
2013-07-29 13:20:43 -07:00
bick 8f79a0564f Add casts to fix strict compiler errors [-fpermissive]
When using g++ and enforcing strict compiler errors, this commit fixes the following:

mongoose.c: In function ‘char* mg_fgets(char*, size_t, file*, char**)’:
mongoose.c:2405:60: error: invalid conversion from ‘void*’ to ‘char*’ [-fpermissive]

mongoose.c: In function ‘int set_ports_option(mg_context*)’:
mongoose.c:4586:64: error: invalid conversion from ‘void*’ to ‘socket*’ [-fpermissive]

mongoose.c: In function ‘void* worker_thread(void*)’:
mongoose.c:5104:28: error: invalid conversion from ‘void*’ to ‘mg_context*’ [-fpermissive]

mongoose.c: In function ‘void* master_thread(void*)’:
mongoose.c:5220:28: error: invalid conversion from ‘void*’ to ‘mg_context*’ [-fpermissive]
mongoose.c:5235:58: error: invalid conversion from ‘void*’ to ‘pollfd*’ [-fpermissive]
2013-07-29 11:46:24 -07:00
Sergey Lyubka 2e93cde929 Merge branch 'master' of ssh://github.com/valenok/mongoose 2013-07-28 12:15:30 +01:00
Sergey Lyubka e53d05637a Binding to IPv6 addresses 2013-07-28 12:15:16 +01:00
Sergey Lyubka 9d75d35365 v. x.x -> v.x.x 2013-07-28 08:20:21 +01:00
Sergey Lyubka 2ea8d85cff Merge pull request #206 from bick4ord/master
adding include of openssl/err.h to fix errors when NO_SSL_DL is defined:
2013-07-26 22:48:49 -07:00
bick ea81a22529 adding include of openssl/err.h to fix errors when NO_SSL_DL is defined:
mongoose.c:4680:23: error: ‘ERR_get_error’ was not declared in this scope
mongoose.c:4681:52: error: ‘ERR_error_string’ was not declared in this scope
2013-07-26 14:12:33 -07:00
Sergey Lyubka 526f3aa31c Added check for document_root != NULL in convert_uri_to_file_name(). Added #define rmdir _rmdir for win32 2013-07-25 07:22:02 +01:00
Sergey Lyubka 62d66201c9 make match_prefix() case-insensitive 2013-07-25 07:07:25 +01:00
Sergey Lyubka f32e14478f Merge pull request #203 from JoseGoncalves/fixes
Fix uninitialized argument in getsockname().
2013-07-24 04:58:27 -07:00
José Miguel Gonçalves ca019799b9 Fix uninitialized argument in getsockname(). 2013-07-24 12:24:13 +01:00
Sergey Lyubka c6fb9ac3d0 Fixed indenting in is_put_or_delete_request() 2013-07-23 08:24:52 +01:00
Sergey Lyubka c80a88a407 Added test for uploading 2 files 2013-07-23 08:17:00 +01:00
Sergey Lyubka f2e19ca3ff Fixed indenting 2013-07-23 08:16:38 +01:00
Sergey Lyubka 16c463d2e9 Added compile-time option to set stack size 2013-07-22 10:10:19 +01:00
Sergey Lyubka 6a99518048 updated readme 2013-07-22 09:54:02 +01:00
Sergey Lyubka 3b242ec68b Added Android makefile 2013-07-22 09:45:23 +01:00
Sergey Lyubka 7409166409 Updated readme 2013-07-22 09:30:01 +01:00
Sergey Lyubka ca66b84f7d Updated readme 2013-07-22 09:27:47 +01:00
Sergey Lyubka dc1c732f11 Updated readme 2013-07-22 09:24:17 +01:00
Sergey Lyubka 61148f1323 Using absolute paths for all file/directory options 2013-07-22 08:23:15 +01:00
Sergey Lyubka 136e3e353d updated readme 2013-07-21 10:09:47 +01:00
Sergey Lyubka c70b80e4e1 marketing for LSP added 2013-07-20 15:30:00 +01:00
Sergey Lyubka cba4c9d85d removed travis icon 2013-07-20 15:26:05 +01:00
Sergey Lyubka 3e588065dc removed 2013-07-20 15:25:39 +01:00
Sergey Lyubka 35cb27dbe6 Always use absolute path for document_root. If relative path is used, it is relative to mongoose.exe directory. See https://github.com/valenok/mongoose/issues/181 2013-07-20 14:11:05 +01:00
Sergey Lyubka d6b9f76e9c Added COPT to CFLAGS 2013-07-20 14:08:06 +01:00
Sergey Lyubka a9d51c0e87 squashed warning 2013-07-20 11:33:34 +01:00
Sergey Lyubka 4b163232e3 fixed docstring for mg_get_valid_option_names 2013-07-20 07:12:49 +01:00
Sergey Lyubka e003236a03 Made SSI #include file= relative to the current doc, as per spec 2013-07-19 07:57:47 +01:00
Sergey Lyubka de7745370c Merge pull request #200 from ejohnstown/master
Allow no SSL_CERTIFICATE when using init_ssl callback.
2013-07-18 23:35:16 -07:00
Sergey Lyubka 21786eec8e Changed int -> SOCKET where appropriate, per Ben Currie 2013-07-18 18:17:48 +01:00
Sergey Lyubka 036b213b2b Added connection-specific conn_data pointer to struct mg_request_info 2013-07-18 17:31:16 +01:00
John Safranek 61f5f0b725 Allow no SSL_CERTIFICATE when using init_ssl callback. 2013-07-17 16:37:28 -07:00
Sergey Lyubka d864d72470 On windows, enclosing path to CGI script in quotes to allow paths with spaces 2013-07-17 08:24:52 +01:00
Sergey Lyubka 7ca5962d2d in pull_all() and read_request(), respect ctx->stop_flag() 2013-07-16 17:17:36 +01:00
Sergey Lyubka 8ce1562f0d Using SetHandleInformation() to make socket handles on Windows non-inheritable 2013-07-16 15:52:40 +01:00
Sergey Lyubka 49d9016275 For lua, let mg.read() read only if the data is there. 2013-07-16 13:56:00 +01:00
Sergey Lyubka cdc7380d00 3.8 -> 3.9 2013-07-16 08:13:00 +01:00
162 changed files with 6940 additions and 188558 deletions

No files matched your search

-6
View File
@@ -1,6 +0,0 @@
language: c
compiler:
- gcc
- clang
# Change this to your needs
script: make linux
+13 -16
View File
@@ -1,19 +1,16 @@
Copyright (c) 2004-2013 Sergey Lyubka Copyright (c) 2004-2013 Sergey Lyubka <valenok@gmail.com>
Copyright (c) 2013 Cesanta Software Limited
All rights reserved
Permission is hereby granted, free of charge, to any person obtaining a copy This code is dual-licensed: you can redistribute it and/or modify
of this software and associated documentation files (the "Software"), to deal it under the terms of the GNU General Public License version 2 as
in the Software without restriction, including without limitation the rights published by the Free Software Foundation. For the terms of this
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell license, see <http://www.gnu.org/licenses>.
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in You are free to use this code under the terms of the GNU General
all copies or substantial portions of the Software. Public License, but WITHOUT ANY WARRANTY; without even the implied
warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the GNU General Public License for more details.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR Alternatively, you can license this code under a commercial
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, license, as set out in <http://cesanta.com/>.
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
-187
View File
@@ -1,187 +0,0 @@
# This Makefile is part of Mongoose web server project,
# https://github.com/valenok/mongoose
#
# Example custom build:
# COPT="-g -O0 -DNO_SSL_DL -DUSE_LUA -llua -lcrypto -lssl" make linux
#
# Flags are:
# -DHAVE_MD5 - use system md5 library (-2kb)
# -DNDEBUG - strip off all debug code (-5kb)
# -DDEBUG - build debug version (very noisy) (+7kb)
# -DNO_CGI - disable CGI support (-5kb)
# -DNO_SSL - disable SSL functionality (-2kb)
# -DNO_SSL_DL - link against system libssl library (-1kb)
# -DCONFIG_FILE=\"file\" - use `file' as the default config file
# -DSSL_LIB=\"libssl.so.<version>\" - use system versioned SSL shared object
# -DCRYPTO_LIB=\"libcrypto.so.<version>\" - use system versioned CRYPTO so
# -DUSE_LUA - embed Lua in Mongoose (+100kb)
PROG = mongoose
CFLAGS = -std=c99 -O2 -W -Wall -pedantic -pthread
# To build with Lua, download and unzip Lua 5.2.1 source code into the
# mongoose directory, and then add $(LUA_SOURCES) to CFLAGS
LUA = lua-5.2.1/src
LUA_FLAGS = -I$(LUA) -DLUA_COMPAT_ALL
LUA_SOURCES = $(LUA)/lapi.c $(LUA)/lcode.c $(LUA)/lctype.c \
$(LUA)/ldebug.c $(LUA)/ldo.c $(LUA)/ldump.c \
$(LUA)/lfunc.c $(LUA)/lgc.c $(LUA)/llex.c \
$(LUA)/lmem.c $(LUA)/lobject.c $(LUA)/lopcodes.c \
$(LUA)/lparser.c $(LUA)/lstate.c $(LUA)/lstring.c \
$(LUA)/ltable.c $(LUA)/ltm.c $(LUA)/lundump.c \
$(LUA)/lvm.c $(LUA)/lzio.c $(LUA)/lauxlib.c \
$(LUA)/lbaselib.c $(LUA)/lbitlib.c $(LUA)/lcorolib.c \
$(LUA)/ldblib.c $(LUA)/liolib.c $(LUA)/lmathlib.c \
$(LUA)/loslib.c $(LUA)/lstrlib.c $(LUA)/ltablib.c \
$(LUA)/loadlib.c $(LUA)/linit.c
LUA_WINOBJS = $(LUA_SOURCES:%.c=%.obj)
# Stock windows binary builds with Lua and YASSL library.
YASSL = ../cyassl-2.4.6
YASSL_FLAGS = -I $(YASSL) -I $(YASSL)/cyassl \
-D _LIB -D OPENSSL_EXTRA -D HAVE_ERRNO_H \
-D HAVE_GETHOSTBYNAME -D HAVE_INET_NTOA -D HAVE_LIMITS_H \
-D HAVE_MEMSET -D HAVE_SOCKET -D HAVE_STDDEF_H -D HAVE_STDLIB_H \
-D HAVE_STRING_H -D HAVE_SYS_STAT_H -D HAVE_SYS_TYPES_H
YASSL_SOURCES = \
$(YASSL)/src/internal.c $(YASSL)/src/io.c $(YASSL)/src/keys.c \
$(YASSL)/src/ssl.c $(YASSL)/src/tls.c $(YASSL)/ctaocrypt/src/hmac.c \
$(YASSL)/ctaocrypt/src/random.c $(YASSL)/ctaocrypt/src/sha.c \
$(YASSL)/ctaocrypt/src/sha256.c $(YASSL)/ctaocrypt/src/logging.c \
$(YASSL)/ctaocrypt/src/error.c $(YASSL)/ctaocrypt/src/rsa.c \
$(YASSL)/ctaocrypt/src/des3.c $(YASSL)/ctaocrypt/src/asn.c \
$(YASSL)/ctaocrypt/src/coding.c $(YASSL)/ctaocrypt/src/arc4.c \
$(YASSL)/ctaocrypt/src/md4.c $(YASSL)/ctaocrypt/src/md5.c \
$(YASSL)/ctaocrypt/src/dh.c $(YASSL)/ctaocrypt/src/dsa.c \
$(YASSL)/ctaocrypt/src/pwdbased.c $(YASSL)/ctaocrypt/src/aes.c \
$(YASSL)/ctaocrypt/src/md2.c $(YASSL)/ctaocrypt/src/ripemd.c \
$(YASSL)/ctaocrypt/src/sha512.c $(YASSL)/src/sniffer.c \
$(YASSL)/ctaocrypt/src/rabbit.c $(YASSL)/ctaocrypt/src/misc.c \
$(YASSL)/ctaocrypt/src/tfm.c $(YASSL)/ctaocrypt/src/integer.c \
$(YASSL)/ctaocrypt/src/ecc.c $(YASSL)/src/ocsp.c $(YASSL)/src/crl.c \
$(YASSL)/ctaocrypt/src/hc128.c $(YASSL)/ctaocrypt/src/memory.c
ALL_SOURCES = main.c mongoose.c build/sqlite3.c build/lsqlite3.c \
$(LUA_SOURCES) $(YASSL_SOURCES)
ALL_OBJECTS = $(ALL_SOURCES:%.c=%.o)
ALL_WINOBJS = $(ALL_SOURCES:%.c=%.obj)
SQLITE_FLAGS = -DTHREADSAFE=1 -DSQLITE_ENABLE_FTS3 -DSQLITE_ENABLE_FTS3_PARENTHESIS
MONGOOSE_FLAGS = -DNO_SSL_DL -DUSE_LUA -DUSE_LUA_SQLITE3 $(COPT)
FLAGS = $(MONGOOSE_FLAGS) $(SQLITE_FLAGS) $(YASSL_FLAGS) $(LUA_FLAGS)
# Using Visual Studio 6.0. To build Mongoose:
# Set MSVC variable below to where VS 6.0 is installed on your system
# Run "PATH_TO_VC6\bin\nmake windows"
MSVC = ../vc6
#DBG = /Zi /Od
DBG = /DNDEBUG /O1
CL = $(MSVC)/bin/cl /MD /TC /nologo $(DBG) /W3 /GA /I$(MSVC)/include
LINK = $(MSVC)/bin/link /incremental:no /libpath:$(MSVC)/lib /machine:IX86 \
user32.lib shell32.lib comdlg32.lib ws2_32.lib advapi32.lib
all:
@echo "make (linux|bsd|solaris|mac|windows|mingw|cygwin)"
%.obj: %.c
$(CL) /c $(FLAGS) /Fo$@ $<
%.o: %.c
$(CC) -o $@ $< -c $(FLAGS) $(CFLAGS)
# Lua library for Windows
lua.lib: $(LUA_WINOBJS)
$(MSVC)/bin/lib /out:$@ $(LUA_WINOBJS)
# To build with lua, make sure you have Lua unpacked into lua-5.2.1 directory
linux_lua: $(ALL_OBJECTS)
$(CC) $(ALL_OBJECTS) -o $(PROG) -ldl
# Make sure that the compiler flags come last in the compilation string.
# If not so, this can break some on some Linux distros which use
# "-Wl,--as-needed" turned on by default in cc command.
# Also, this is turned in many other distros in static linkage builds.
linux:
$(CC) mongoose.c main.c -o $(PROG) -ldl $(CFLAGS)
mac: bsd
bsd:
$(CC) mongoose.c main.c -o $(PROG) $(CFLAGS)
bsd_lua: $(ALL_OBJECTS)
$(CC) $(ALL_OBJECTS) -o $@
solaris:
$(CC) mongoose.c main.c -lnsl -lsocket -o $(PROG) $(CFLAGS)
lib$(PROG).a: $(ALL_OBJECTS)
ar cr $@ $(ALL_OBJECTS)
$(PROG).lib: $(ALL_WINOBJS)
$(MSVC)/bin/lib /out:$@ $(ALL_WINOBJS)
# For codesign to work in non-interactive mode, unlock login keychain:
# security unlock ~/Library/Keychains/login.keychain
# See e.g. http://lists.apple.com/archives/apple-cdsa/2008/Jan/msg00027.html
Mongoose: mongoose.c main.c
$(CC) mongoose.c main.c build/lsqlite3.c build/sqlite3.c \
-DUSE_COCOA $(CFLAGS) $(FLAGS) -mmacosx-version-min=10.4 \
$(YASSL_SOURCES) $(LUA_SOURCES) \
-framework Cocoa -ObjC -arch i386 -arch x86_64 -o Mongoose
cocoa: Mongoose
V=`perl -lne '/define\s+MONGOOSE_VERSION\s+"(\S+)"/ and print $$1' mongoose.c`; DIR=dmg/Mongoose.app && rm -rf $$DIR && mkdir -p $$DIR/Contents/{MacOS,Resources} && install -m 644 build/mongoose_*.png $$DIR/Contents/Resources/ && install -m 644 build/Info.plist $$DIR/Contents/ && install -m 755 Mongoose $$DIR/Contents/MacOS/ && ln -fs /Applications dmg/ ; hdiutil create Mongoose_$$V.dmg -volname "Mongoose $$V" -srcfolder dmg -ov #; rm -rf dmg
un:
$(CC) test/unit_test.c -o unit_test -I. -I$(LUA) $(LUA_SOURCES) \
$(CFLAGS) -g -O0
./unit_test
wi:
$(CL) test/unit_test.c $(LUA_SOURCES) $(LUA_FLAGS) \
$(YASSL_SOURCES) $(YASSL_FLAGS) /I. /DNO_SSL_DL \
/link /libpath:$(MSVC)/lib advapi32.lib /out:unit_test.exe
./unit_test.exe
windows: $(ALL_WINOBJS)
$(MSVC)/bin/rc build/res.rc
$(LINK) /nologo $(ALL_WINOBJS) build/res.res /out:$(PROG).exe
# Build for Windows under MinGW
#MINGWDBG= -DDEBUG -O0 -ggdb
MINGWDBG= -DNDEBUG -Os
MINGWOPT= -W -Wall -mthreads -Wl,--subsystem,console $(MINGWDBG) -DHAVE_STDINT $(GCC_WARNINGS) $(COPT)
mingw:
windres build\res.rc build\res.o
$(CC) $(MINGWOPT) mongoose.c -lws2_32 \
-shared -Wl,--out-implib=$(PROG).lib -o $(PROG).dll
$(CC) $(MINGWOPT) mongoose.c main.c build\res.o \
-lws2_32 -ladvapi32 -lcomdlg32 -o $(PROG).exe
# Build for Windows under Cygwin
#CYGWINDBG= -DDEBUG -O0 -ggdb
CYGWINDBG= -DNDEBUG -Os
CYGWINOPT= -W -Wall -mthreads -Wl,--subsystem,console $(CYGWINDBG) -DHAVE_STDINT $(GCC_WARNINGS) $(COPT)
cygwin:
windres ./build/res.rc ./build/res.o
$(CC) $(CYGWINOPT) mongoose.c -lws2_32 \
-shared -Wl,--out-implib=$(PROG).lib -o $(PROG).dll
$(CC) $(CYGWINOPT) -Ibuild mongoose.c main.c ./build/res.o \
-lws2_32 -ladvapi32 -o $(PROG).exe
tests:
perl test/test.pl $(TEST)
tarball: clean
F=mongoose-`perl -lne '/define\s+MONGOOSE_VERSION\s+"(\S+)"/ and print $$1' mongoose.c`.tgz ; cd .. && tar -czf x mongoose/{LICENSE,Makefile,examples,test,build,*.[ch],*.md} && mv x mongoose/$$F
release: tarball cocoa
wine make windows
V=`perl -lne '/define\s+MONGOOSE_VERSION\s+"(\S+)"/ and print $$1' mongoose.c`; upx mongoose.exe; cp mongoose.exe mongoose-$$V.exe; cp mongoose.exe mongoose_php_bundle/; zip -r mongoose_php_bundle_$$V.zip mongoose_php_bundle/
clean:
cd examples && $(MAKE) clean
rm -rf *.o *.core $(PROG) *.obj *.so $(PROG).txt *.dSYM *.tgz \
$(PROG).exe *.dll *.lib build/res.o build/res.RES *.dSYM *.zip *.pdb \
*.exe *.dmg $(ALL_OBJECTS) $(ALL_WINOBJS)
+51 -56
View File
@@ -1,68 +1,63 @@
# Project Mission # Mongoose Web Server
Project mission is to provide simple, functional, embeddable web server to Mongoose is easy to use, powerful, embeddable web server.
make it easy for application and device developers to implement web interface * [Mailing list](http://groups.google.com/group/mongoose-users)
for their application and devices, and to offer a simple web development * [Downloads & Documentation](http://cesanta.com/mongoose.shtml)
environment. * [How to use Lua Server Pages](http://cesanta.com/docs/Lua.shtml)
* [How to create basic website with Mongoose](http://cesanta.com/docs/BasicWebsite.shtml)
* [How to create PHP website with Mongoose](http://cesanta.com/docs/PhpWebsite.shtml)
* [Embedding Guide](http://cesanta.com/docs/Embed.shtml)
# Overview # Features
To accomplish it's mission, Mongoose keeps balance on functionality and - Works on Windows, Mac, UNIX/Linux, iPhone, Android, and many other platforms
simplicity by carefully selected list of features: - CGI, SSI, SSL, Digest auth, Websocket, WEbDAV, Resumed download, URL rewrite, file blacklist, Custom error pages, Virtual hosts, IP-based ACL, Windows service
- Scripting and database support ([Lua](http://lua.org) +
- Liberal, commercial-friendly [Sqlite](http://sqlite.org), see
[MIT license](http://en.wikipedia.org/wiki/MIT_License) [dirscan.lp](https://github.com/cesanta/mongoose/blob/master/examples/lua/dirscan.lp) ),
- Works on Windows, Mac, UNIX, iPhone, Android, and many other platforms which provides ready to go, powerful web development platform in
- Support for CGI, SSL, SSI, Digest (MD5) authorization, Websocket, WEbDAV one single-click executable with no dependencies
- Lua server pages with Sqlite, see - Simple and clean
[page.lp](https://github.com/valenok/mongoose/blob/master/test/page.lp) [embedding API](https://github.com/cesanta/mongoose/blob/master/mongoose.h).
- Resumed download, URL rewrite, IP-based ACL, Windows service
- Excluding files from serving by URI pattern (file blacklist)
- Download speed limit based on client subnet or URI pattern
- Small footprint: executable size is 50 kB on Linux 2.6 i386 system
- 130 kilobytes Windows executable with all of the above and no dependencies
- Simple and clean embedding API,
[mongoose.h](https://github.com/valenok/mongoose/blob/master/mongoose.h).
The source is in single The source is in single
[mongoose.c](https://github.com/valenok/mongoose/blob/master/mongoose.c) file [mongoose.c](https://github.com/cesanta/mongoose/blob/master/mongoose.c) file
to make things easy to make embedding easy
- Embedding examples: - Extremely lightweight, has a core of under 40kB and tiny runtime footprint
[hello.c](https://github.com/valenok/mongoose/blob/master/examples/hello.c), - Asyncronouns, non-blocking core supporting single- or multi-threaded usage
[post.c](https://github.com/valenok/mongoose/blob/master/examples/post.c), - On the market since 2004, stable, mature and tested,
[upload.c](https://github.com/valenok/mongoose/blob/master/examples/upload.c), has several man-years invested in continuous improvement and refinement
[websocket.c](https://github.com/valenok/mongoose/blob/master/examples/websocket.c) - Professional support and consultancy available from
- HTTP client functionality for embedded usage, capable of [Cesanta Software](http://cesanta.com), developer of Mongoose
sending arbitrary HTTP/HTTPS requests
- [User Manual](https://github.com/valenok/mongoose/blob/master/UserManual.md)
Continuous build status: ![build status](https://api.travis-ci.org/valenok/mongoose.png) # Acknowledgements
Questions can be asked at Mongoose made better thanks to the contribution of following people:
[mongoose-users@google.com](http://groups.google.com/group/mongoose-users)
mailing list.
Arnout Vandecappelle, Benoît Amiaux, Boris Pek, Cody Hanson, Colin Leitner,
# Keep Sergey happy Daniel Oaks, Eric Bakan, Erik Oomen, Filipp Kovalev, Ger Hobbelt,
Hendrik Polczynski, Igor Okulist, Jay, Joe Mucchiello, John Safranek,
I am Sergey Lyubka, a software engineer from Galway, Ireland. I started José Miguel Gonçalves, Shueng Chuan, Katerina Blinova, Konstantin Sorokin,
working on Mongoose in 2004, and since then continuously improve it, Marin Atanasov, Matt Healy, Mitch Hendrickson, Nigel Stewart, Pavel Khlebovich,
investing thousands of hours of work. My other project I'm contributing to the Sebastian Reinhard, Stefan Doehla, abadc0de, nullable.type,
community for free is T.Barmann, D.Hughes, J.C.Sloan, R.Romeo, L.E.Spencer, S.Kotay, R.M.Shorter,
[Super Light Regular Expression library](http://code.google.com/p/slre). W.Mar, J.Wilander, Santa from Memphis, S.Davies, C.Beck,
O.M.Vilhunen, C.Radik, G.Woodcock, M.Szczepkowski,
If you feel grateful for the stuff I've done, you can buy me a book from my
[Amazon wishlist](http://amzn.com/w/1OC2ZCPTQYIEP?sort=priority). Many thanks
to all who already did so: T.Barmann, D.Hughes, J.C.Sloan, R.Romeo,
L.E.Spencer, S.Kotay, R.M.Shorter, W.Mar, J.Wilander, Santa from Memphis,
S.Davies and 8 others.
Appreciated guys, you keep my brains going! Cash is also welcome indeed.
Press [<img src="http://www.paypalobjects.com/en_US/i/btn/btn_donate_SM.gif">](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=DGZ2FMP95TAL6)
button to donate. Donation progress: 710/1000 &euro;
(thanks to O.M.Vilhunen, C.Radik, G.Woodcock, M.Szczepkowski,
Eternal Lands Dev Team, T.Tollet, C.Tangerino, G.Karsai, A.Bourgett, Eternal Lands Dev Team, T.Tollet, C.Tangerino, G.Karsai, A.Bourgett,
C.Blakemore, D.Fonaryov, T.Andrle, O.IJsselmuiden, R.Womack, M.Tomlinson, C.Blakemore, D.Fonaryov, T.Andrle, O.IJsselmuiden, R.Womack, M.Tomlinson,
A.Slåttå, L.Farrell, J.D.P.Ballestero, V.Albaev, B.Harker, T.Scheffel, H.Klein, A.Slåttå, L.Farrell, J.D.P.Ballestero, V.Albaev, B.Harker, T.Scheffel, H.Klein,
R.Merit, T.Bennett, H.Solis, A.Zincenko, M.S., S.Krul, K.Cooke, S.McCallum, R.Merit, T.Bennett, H.Solis, A.Zincenko, M.S., S.Krul, K.Cooke, S.McCallum,
F.Morenius) F.Morenius, and 10 others.
![Progress](http://chart.googleapis.com/chart?chxr=0,0,1000&chxt=x&chbh=30,0,0&chs=300x35&cht=bhs&chco=90c0f0&chd=t:71.0) # Licensing
Mongoose is released under
[GNU GPL v.2](http://www.gnu.org/licenses/old-licenses/gpl-2.0.html).
Businesses have an option to get non-restrictive, royalty-free commercial
license and professional support from
[Cesanta Software](http://cesanta.com).
[Frozen JSON parser](https://github.com/cesanta/frozen),
[Super Light Regular Expression library](https://github.com/cesanta/slre),
[Super Light DNS Resolver](https://github.com/cesanta/sldr)
are other projects by Cesanta Software, developed with the same philosophy
of functionality and simplicity.
-553
View File
@@ -1,553 +0,0 @@
# Overview
Mongoose is small and easy to use web server. It is self-contained, and does
not require any external software to run.
On Windows, mongoose iconifies itself to the system tray icon when started.
Right-click on the icon pops up a menu, where it is possible to stop
mongoose, or configure it, or install it as Windows service. The easiest way
to share a folder on Windows is to copy `mongoose.exe` to a folder,
double-click the exe, and launch a browser at
[http://localhost:8080](http://localhost:8080). Note that 'localhost' should
be changed to a machine's name if a folder is accessed from other computer.
On UNIX and Mac, mongoose is a command line utility. Running `mongoose` in
terminal, optionally followed by configuration parameters
(`mongoose [OPTIONS]`) or configuration file name
(`mongoose [config_file_name]`) starts the
web server. Mongoose does not detach from terminal. Pressing `Ctrl-C` keys
would stop the server.
When started, mongoose first searches for the configuration file.
If configuration file is specified explicitly in the command line, i.e.
`mongoose path_to_config_file`, then specified configuration file is used.
Otherwise, mongoose would search for file `mongoose.conf` in the same directory
where binary is located, and use it. Configuration file can be absent.
Configuration file is a sequence of lines, each line containing
command line argument name and it's value. Empty lines, and lines beginning
with `#`, are ignored. Here is the example of `mongoose.conf` file:
document_root c:\www
listening_ports 8080,8043s
ssl_certificate c:\mongoose\ssl_cert.pem
When configuration file is processed, mongoose process command line arguments,
if they are specified. Command line arguments therefore can override
configuration file settings. Command line arguments must start with `-`.
For example, if `mongoose.conf` has line
`document_root /var/www`, and mongoose has been started as
`mongoose -document_root /etc`, then `/etc` directory will be served as
document root, because command line options take priority over
configuration file. Configuration options section below provide a good
overview of Mongoose features.
Note that configuration options on the command line must start with `-`,
but their names are the same as in the config file. All option names are
listed in the next section. Thus, the following two setups are equivalent:
# Using command line arguments
$ mongoose -listening_ports 1234 -document_root /var/www
# Using config file
$ cat mongoose.conf
listening_ports 1234
document_root /var/www
$ mongoose
Mongoose can also be used to modify `.htpasswd` passwords file:
mongoose -A <htpasswd_file> <realm> <user> <passwd>
Unlike other web servers, mongoose does not require CGI scripts be located in
a special directory. CGI scripts can be anywhere. CGI (and SSI) files are
recognized by the file name pattern. Mongoose uses shell-like glob
patterns. Pattern match starts at the beginning of the string, so essentially
patterns are prefix patterns. Syntax is as follows:
** Matches everything
* Matches everything but slash character, '/'
? Matches any character
$ Matches the end of the string
| Matches if pattern on the left side or the right side matches.
All other characters in the pattern match themselves. Examples:
**.cgi$ Any string that ends with .cgi
/foo Any string that begins with /foo
**a$|**b$ Any string that ends with a or b
# Configuration Options
Below is a list of configuration options Mongoose understands. Every option
is followed by it's default value. If default value is not present, then
it is empty.
### cgi_pattern `**.cgi$|**.pl$|**.php$`
All files that match `cgi_pattern` are treated as CGI files. Default pattern
allows CGI files be anywhere. To restrict CGIs to a certain directory,
use `/path/to/cgi-bin/**.cgi` as pattern. Note that full file path is
matched against the pattern, not the URI.
### cgi_environment
Extra environment variables to be passed to the CGI script in
addition to standard ones. The list must be comma-separated list
of name=value pairs, like this: `VARIABLE1=VALUE1,VARIABLE2=VALUE2`.
### put\_delete\_auth\_file
Passwords file for PUT and DELETE requests. Without it, PUT and DELETE requests
will fail.
### cgi_interpreter
Path to an executable to use as CGI interpreter for __all__ CGI scripts
regardless script extension. If this option is not set (which is a default),
Mongoose looks at first line of a CGI script,
[shebang line](http://en.wikipedia.org/wiki/Shebang_(Unix)), for an interpreter.
For example, if both PHP and perl CGIs are used, then
`#!/path/to/php-cgi.exe` and `#!/path/to/perl.exe` must be first lines of the
respective CGI scripts. Note that paths should be either full file paths,
or file paths relative to the current working directory of mongoose server.
If mongoose is started by mouse double-click on Windows, current working
directory is a directory where mongoose executable is located.
If all CGIs use the same interpreter, for example they are all PHP, then
`cgi_interpreter` can be set to the path to `php-cgi.exe` executable and
shebang line in the CGI scripts can be omitted.
Note that PHP scripts must use `php-cgi.exe` executable, not `php.exe`.
### protect_uri
Comma separated list of URI=PATH pairs, specifying that given
URIs must be protected with respected password files. Paths must be full
file paths.
### authentication_domain `mydomain.com`
Authorization realm used in `.htpasswd` authorization.
### ssi_pattern `**.shtml$|**.shtm$`
All files that match `ssi_pattern` are treated as SSI.
Server Side Includes (SSI) is a simple interpreted server-side scripting
language which is most commonly used to include the contents of a file into
a web page. It can be useful when it is desirable to include a common piece
of code throughout a website, for example, headers and footers.
In order for a webpage to recognize an SSI-enabled HTML file, the filename
should end with a special extension, by default the extension should be
either `.shtml` or `.shtm`.
Unknown SSI directives are silently ignored by mongoose. Currently, two SSI
directives are supported, `<!--#include ...>` and
`<!--#exec "command">`. Note that `<!--#include ...>` directive supports
three path specifications:
<!--#include virtual="path"> Path is relative to web server root
<!--#include file="path"> Path is relative to web server working dir
<!--#include "path"> Path is relative to current document
The `include` directive may be used to include the contents of a file or the
result of running a CGI script. The `exec` directive is used to execute a
command on a server, and show command's output. Example:
<!--#exec "ls -l" -->
For more information on Server Side Includes, take a look at the Wikipedia:
[Server Side Includes](http://en.wikipedia.org/wiki/Server_Side_Includes)
### throttle
Limit download speed for clients. `throttle` is a comma-separated
list of key=value pairs, where key could be:
* limit speed for all connections
x.x.x.x/mask limit speed for specified subnet
uri_prefix_pattern limit speed for given URIs
The value is a floating-point number of bytes per second, optionally
followed by a `k` or `m` character, meaning kilobytes and
megabytes respectively. A limit of 0 means unlimited rate. The
last matching rule wins. Examples:
*=1k,10.0.0.0/8=0 limit all accesses to 1 kilobyte per second,
but give connections from 10.0.0.0/8 subnet
unlimited speed
/downloads/=5k limit accesses to all URIs in `/downloads/` to
5 kilobytes per secods. All other accesses are unlimited
### access\_log\_file
Path to a file for access logs. Either full path, or relative to current
working directory. If absent (default), then accesses are not logged.
### error\_log\_file
Path to a file for error logs. Either full path, or relative to current
working directory. If absent (default), then errors are not logged.
### enable\_directory\_listing `yes`
Enable directory listing, either `yes` or `no`.
### enable\_keep\_alive `no`
Enable connection keep alive, either `yes` or `no`.
Experimental feature. Allows clients to reuse TCP connection for
subsequent HTTP requests, which improves performance.
For this to work when using request handlers it's important to add the correct
Content-Length HTTP header for each request. If this is forgotten the client
will time out.
### global\_auth\_file
Path to a global passwords file, either full path or relative to the current
working directory. If set, per-directory `.htpasswd` files are ignored,
and all requests are authorised against that file.
The file has to include the realm set through `authentication_domain` and the password in digest format:
user:realm:digest
test:test.com:ce0220efc2dd2fad6185e1f1af5a4327
(e.g. use [this generator](http://www.askapache.com/online-tools/htpasswd-generator))
### index_files `index.html,index.htm,index.cgi,index.shtml,index.php`
Comma-separated list of files to be treated as directory index
files.
### access\_control\_list
An Access Control List (ACL) allows restrictions to be put on the list of IP
addresses which have access to the web server. In the case of the Mongoose
web server, the ACL is a comma separated list of IP subnets, where each
subnet is prepended by either a `-` or a `+` sign. A plus sign means allow,
where a minus sign means deny. If a subnet mask is omitted, such as `-1.2.3.4`,
this means to deny only that single IP address.
Subnet masks may vary from 0 to 32, inclusive. The default setting is to allow
all accesses. On each request the full list is traversed, and
the last match wins. Examples:
-0.0.0.0/0,+192.168/16 deny all acccesses, only allow 192.168/16 subnet
To learn more about subnet masks, see the
[Wikipedia page on Subnetwork](http://en.wikipedia.org/wiki/Subnetwork)
### extra\_mime\_types
Extra mime types to recognize, in form `extension1=type1,exten-
sion2=type2,...`. Extension must include dot. Example:
`.cpp=plain/text,.java=plain/text`
### listening_ports `8080`
Comma-separated list of ports to listen on. If the port is SSL, a
letter `s` must be appeneded, for example, `80,443s` will open
port 80 and port 443, and connections on port 443 will be SSL-ed.
For non-SSL ports, it is allowed to append letter `r`, meaning 'redirect'.
Redirect ports will redirect all their traffic to the first configured
SSL port. For example, if `listening_ports` is `80r,443s`, then all
HTTP traffic coming at port 80 will be redirected to HTTPS port 443.
It is possible to specify an IP address to bind to. In this case,
an IP address and a colon must be prepended to the port number.
For example, to bind to a loopback interface on port 80 and to
all interfaces on HTTPS port 443, use `127.0.0.1:80,443s`.
### document_root `.`
A directory to serve. By default, currect directory is served. Current
directory is commonly referenced as dot (`.`).
### ssl_certificate
Path to SSL certificate file. This option is only required when at least one
of the `listening_ports` is SSL. The file must be in PEM format,
and it must have both private key and certificate, see for example
[ssl_cert.pem](https://github.com/valenok/mongoose/blob/master/build/ssl_cert.pem)
### num_threads `50`
Number of worker threads. Mongoose handles each incoming connection in a
separate thread. Therefore, the value of this option is effectively a number
of concurrent HTTP connections Mongoose can handle.
### run\_as\_user
Switch to given user credentials after startup. Usually, this option is
required when mongoose needs to bind on privileged port on UNIX. To do
that, mongoose needs to be started as root. But running as root is a bad idea,
therefore this option can be used to drop privileges. Example:
mongoose -listening_ports 80 -run_as_user nobody
### url\_rewrite\_patterns
Comma-separated list of URL rewrites in the form of
`uri_pattern=file_or_directory_path`. When Mongoose receives the request,
it constructs the file name to show by combining `document_root` and the URI.
However, if the rewrite option is used and `uri_pattern` matches the
requested URI, then `document_root` is ignored. Insted,
`file_or_directory_path` is used, which should be a full path name or
a path relative to the web server's current working directory. Note that
`uri_pattern`, as all mongoose patterns, is a prefix pattern.
This makes it possible to serve many directories outside from `document_root`,
redirect all requests to scripts, and do other tricky things. For example,
to redirect all accesses to `.doc` files to a special script, do:
mongoose -url_rewrite_patterns **.doc$=/path/to/cgi-bin/handle_doc.cgi
Or, to imitate user home directories support, do:
mongoose -url_rewrite_patterns /~joe/=/home/joe/,/~bill=/home/bill/
### hide\_files\_patterns
A pattern for the files to hide. Files that match the pattern will not
show up in directory listing and return `404 Not Found` if requested. Pattern
must be for a file name only, not including directory name. Example:
mongoose -hide_files_patterns secret.txt|even_more_secret.txt
# Lua Server Pages
Pre-built Windows and Mac mongoose binaries have built-in Lua Server Pages
support. That means it is possible to write PHP-like scripts with mongoose,
using Lua programming language instead of PHP. Lua is known
for it's speed and small size. Mongoose uses Lua version 5.2.1, the
documentation for it can be found at
[Lua 5.2 reference manual](http://www.lua.org/manual/5.2/).
To create a Lua Page, make sure a file has `.lp` extension. For example,
let's say it is going to be `my_page.lp`. The contents of the file, just like
with PHP, is HTML with embedded Lua code. Lua code must be enclosed in
`<? ?>` blocks, and can appear anywhere on the page. For example, to
print current weekday name, one can write:
<p>
<span>Today is:</span>
<? mg.write(os.date("%A")) ?>
</p>
Note that this example uses function `mg.write()`, which prints data to the
web page. Using function `mg.write()` is the way to generate web content from
inside Lua code. In addition to `mg.write()`, all standard library functions
are accessible from the Lua code (please check reference manual for details),
and also information about the request is available in `mg.request_info` object,
like request method, all headers, etcetera. Please refer to
`struct mg_request_info` definition in
[mongoose.h](https://github.com/valenok/mongoose/blob/master/mongoose.h)
to see what kind of information is present in `mg.request_info` object. Also,
[page.lp](https://github.com/valenok/mongoose/blob/master/test/page.lp) and
[prime_numbers.lp](https://github.com/valenok/mongoose/blob/master/examples/lua/prime_numbers.lp)
contains some example code that uses `request_info` and other functions(form submitting for example).
Mongoose exports the following to the Lua server page:
mg.read() -- reads a chunk from POST data, returns it as a string
mg.write(str) -- writes string to the client
mg.include(path) -- sources another Lua file
mg.redirect(uri) -- internal redirect to a given URI
mg.onerror(msg) -- error handler, can be overridden
mg.version -- a string that holds Mongoose version
mg.request_info -- a table with request information
-- Connect to the remote TCP server. This function is an implementation
-- of simple socket interface. It returns a socket object with three
-- methods: send, recv, close, which are synchronous (blocking).
-- connect() throws an exception on connection error.
connect(host, port, use_ssl)
-- Example of using connect() interface:
local host = 'code.google.com' -- IP address or domain name
local ok, sock = pcall(connect, host, 80, 1)
if ok then
sock:send('GET /p/mongoose/ HTTP/1.0\r\n' ..
'Host: ' .. host .. '\r\n\r\n')
local reply = sock:recv()
sock:close()
-- reply now contains the web page https://code.google.com/p/mongoose
end
**IMPORTANT: Mongoose does not send HTTP headers for Lua pages. Therefore,
every Lua Page must begin with HTTP reply line and headers**, like this:
<? print('HTTP/1.0 200 OK\r\nContent-Type: text/html\r\n\r\n') ?>
<html><body>
... the rest of the web page ...
To serve Lua Page, mongoose creates Lua context. That context is used for
all Lua blocks within the page. That means, all Lua blocks on the same page
share the same context. If one block defines a variable, for example, that
variable is visible in the block that follows.
# Common Problems
- PHP doesn't work - getting empty page, or 'File not found' error. The
reason for that is wrong paths to the interpreter. Remember that with PHP,
correct interpreter is `php-cgi.exe` (`php-cgi` on UNIX). Solution: specify
full path to the PHP interpreter, e.g.:
`mongoose -cgi_interpreter /full/path/to/php-cgi`
- Mongoose fails to start. If Mongoose exits immediately when run, this
usually indicates a syntax error in the configuration file
(named `mongoose.conf` by default) or the command-line arguments.
Syntax checking is omitted from Mongoose to keep its size low. However,
the Manual should be of help. Note: the syntax changes from time to time,
so updating the config file might be necessary after executable update.
- Embedding with OpenSSL on Windows might fail because of calling convention.
To force Mongoose to use `__stdcall` convention, add `/Gz` compilation
flag in Visual Studio compiler.
# Embedding
Embedding Mongoose is easy. Copy
[mongoose.c](https://github.com/valenok/mongoose/blob/master/mongoose.c) and
[mongoose.h](https://github.com/valenok/mongoose/blob/master/mongoose.h)
to your application's source tree and include them in the build. For
example, your application's code lives in C++ file `my_app.cpp`, then on UNIX
this command embeds Mongoose:
$ ls
my_app.cpp mongoose.c mongoose.h
$ g++ my_app.cc mongoose.c -o my_app
Somewhere in the application code, call `mg_start()` to start the server.
Pass configuration options and event handlers to `mg_start()`.
Mongoose then calls handlers when certain events happen.
For example, when new request arrives, Mongoose calls `begin_request`
handler function to let user handle the request. In the handler, user code
can get all information about the request -- parsed headers, etcetera.
Mongoose API is logically divided in three categories: server setup/shutdown
functions, functions to be used by user-written event handlers, and
convenience utility functions.
### Starting and stopping embedded web server
To start the embedded web server, call `mg_start()`. To stop it, call
`mg_stop()`.
// This structure needs to be passed to mg_start(), to let mongoose know
// which callbacks to invoke. For detailed description, see
// https://github.com/valenok/mongoose/blob/master/UserManual.md
struct mg_callbacks {
int (*begin_request)(struct mg_connection *);
void (*end_request)(const struct mg_connection *, int reply_status_code);
int (*log_message)(const struct mg_connection *, const char *message);
int (*init_ssl)(void *ssl_context);
int (*websocket_connect)(const struct mg_connection *);
void (*websocket_ready)(struct mg_connection *);
int (*websocket_data)(struct mg_connection *);
const char * (*open_file)(const struct mg_connection *,
const char *path, size_t *data_len);
void (*init_lua)(struct mg_connection *, void *lua_context);
void (*upload)(struct mg_connection *, const char *file_name);
int (*http_error)(struct mg_connection *, int status);
};
[hello.c](https://github.com/valenok/mongoose/blob/master/examples/hello.c)
provides a minimalistic example.
Common pattern is to implement `begin_request` callback, and serve static files
from memory, and/or construct dynamic replies on the fly. Here is
my [embed.c](https://gist.github.com/valenok/4714740) gist
that shows how to easily any data can be embedded
directly into the executable. If such data needs to be encrypted, then
encrypted database or encryption dongles would be a better choice.
# Build on Android
This is a small guide to help you run mongoose on Android. Currently it is
tested on the HTC Wildfire. If you have managed to run it on other devices
as well, please comment or drop an email in the mailing list.
Note : You dont need root access to run mongoose on Android.
- Download the source from the Downloads page.
- Download the Android NDK from
[here](http://developer.android.com/tools/sdk/ndk/index.html)
- Make a folder (e.g. mongoose) and inside that make a folder named "jni".
- Add `mongoose.h`, `mongoose.c` and `main.c` from the source to the jni folder.
- Make a new file in the jni folder named "Android.mk".
This is the make file for ndk-build.
Android.mk:
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := mongoose
LOCAL_SRC_FILES := main.c mongoose.c
include $(BUILD_EXECUTABLE)
- Run `./ndk-build -C /path/to/mongoose/`.
This should generate mongoose/lib/armeabi/mongoose
- Using the adb tool, push the generated mongoose binary to `/data/local`
folder on device.
- From adb shell, navigate to `/data/local` and execute `./mongoose`.
- To test if the server is running fine, visit your web-browser and
navigate to `http://127.0.0.1:8080` You should see the `Index of /` page.
![screenshot](https://a248.e.akamai.net/camo.github.com/b88428bf009a2b6141000937ab684e04cc8586af/687474703a2f2f692e696d6775722e636f6d2f62676f6b702e706e67)
Notes:
- jni stands for Java Native Interface. Read up on Android NDK if you want
to know how to interact with the native C functions of mongoose in Android
Java applications.
- Download android-sdk for the adb tool.
- TODO: A Java application that interacts with the native binary or a
shared library.
# Mongoose internals
Mongoose is multithreaded web server. `mg_start()` function allocates
web server context (`struct mg_context`), which holds all information
about web server instance:
- configuration options. Note that mongoose makes internal copies of
passed options.
- SSL context, if any
- user-defined callbacks
- opened listening sockets
- a queue for accepted sockets
- mutexes and condition variables for inter-thread synchronization
When `mg_start()` returns, all initialization is quaranteed to be complete
(e.g. listening ports are opened, SSL is initialized, etc). `mg_start()` starts
two threads: a master thread, that accepts new connections, and several
worker threads, that process accepted connections. The number of worker threads
is configurable via `num_threads` configuration option. That number puts a
limit on number of simultaneous requests that can be handled by mongoose.
When master thread accepts new connection, a new accepted socket (described by
`struct socket`) it placed into the accepted sockets queue,
which has size of 20 (see [code](https://github.com/valenok/mongoose/blob/3892e0199e6ca9613b160535d9d107ede09daa43/mongoose.c#L486)). Any idle worker thread
can grab accepted sockets from that queue. If all worker threads are busy,
master thread can accept and queue up to 20 more TCP connections,
filling up the queue.
In the attempt to queue next accepted connection, master thread blocks
until there is space in a queue. When master thread is blocked on a
full queue, TCP layer in OS can also queue incoming connection.
The number is limited by the `listen()` call parameter on listening socket,
which is `SOMAXCONN` in case of Mongoose, and depends on a platform.
Worker threads are running in an infinite loop, which in simplified form
looks something like this:
static void *worker_thread() {
while (consume_socket()) {
process_new_connection();
}
}
Function `consume_socket()` gets new accepted socket from the mongoose socket
queue, atomically removing it from the queue. If the queue is empty,
`consume_socket()` blocks and waits until new sockets are placed in a queue
by the master thread. `process_new_connection()` actually processes the
connection, i.e. reads the request, parses it, and performs appropriate action
depending on a parsed request.
Master thread uses `poll()` and `accept()` to accept new connections on
listening sockets. `poll()` is used to avoid `FD_SETSIZE` limitation of
`select()`. Since there are only a few listening sockets, there is no reason
to use hi-performance alternatives like `epoll()` or `kqueue()`. Worker
threads use blocking IO on accepted sockets for reading and writing data.
All accepted sockets have `SO_RCVTIMEO` and `SO_SNDTIMEO` socket options set
(controlled by `request_timeout_ms` mongoose option, 30 seconds default) which
specify read/write timeout on client connection.
# Other Resources
- Presentation made by Arnout Vandecappelle at FOSDEM 2011 on 2011-02-06
in Brussels, Belgium, called
"Creating secure web based user interfaces for Embedded Devices"
([pdf](http://mind.be/content/110206_Web-ui.pdf) |
[odp](http://mind.be/content/110206_Web-ui.odp))
- Linux Journal article by Michel J.Hammel, 2010-04-01, called
[Mongoose: an Embeddable Web Server in C](http://www.linuxjournal.com/article/10680)
-20
View File
@@ -1,20 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleExecutable</key> <string>Mongoose</string>
<key>CFBundlePackageType</key> <string>APPL</string>
<key>CFBundleTypeRole</key> <string>None</string>
<key>CFBundleIconFiles</key> <array>
<string>mongoose_16x16.png</string>
<string>mongoose_22x22.png</string>
<string>mongoose_32x32.png</string>
<string>mongoose_64x64.png</string>
</array>
<key>LSUIElement</key> <true/>
<key>RunAtLoad</key> <true/>
<key>Label</key> <string>com.kolkin.mongoose</string>
<key>ProgramArguments</key> <array> </array>
<key>KeepAlive</key> <true/>
</dict>
</plist>
-15
View File
@@ -1,15 +0,0 @@
LIBRARY
EXPORTS
mg_start
mg_stop
mg_read
mg_write
mg_printf
mg_get_header
mg_get_var
mg_get_cookie
mg_get_option
mg_get_valid_option_names
mg_version
mg_modify_passwords_file
mg_md5
-1885
View File
File diff suppressed because it is too large. Load diff
-589
View File
@@ -1,589 +0,0 @@
%PDF-1.5␍%âãÏÓ
1 0 obj␍<</Metadata 2 0 R/OCProperties<</D<</ON[5 0 R]/Order 6 0 R/RBGroups[]>>/OCGs[5 0 R]>>/Pages 3 0 R/Type/Catalog>>␍endobj␍2 0 obj␍<</Length 16195/Subtype/XML/Type/Metadata>>stream
<?xpacket begin="" id="W5M0MpCehiHzreSzNTczkc9d"?>
<x:xmpmeta xmlns:x="adobe:ns:meta/" x:xmptk="Adobe XMP Core 5.3-c011 66.145661, 2012/02/06-14:56:27 ">
<rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#">
<rdf:Description rdf:about=""
xmlns:xmp="http://ns.adobe.com/xap/1.0/"
xmlns:xmpGImg="http://ns.adobe.com/xap/1.0/g/img/">
<xmp:CreatorTool>Adobe Illustrator CS6 (Windows)</xmp:CreatorTool>
<xmp:CreateDate>2013-01-02T17:27:47+01:00</xmp:CreateDate>
<xmp:ModifyDate>2013-01-02T17:27:47Z</xmp:ModifyDate>
<xmp:MetadataDate>2013-01-02T17:27:47Z</xmp:MetadataDate>
<xmp:Thumbnails>
<rdf:Alt>
<rdf:li rdf:parseType="Resource">
<xmpGImg:width>256</xmpGImg:width>
<xmpGImg:height>228</xmpGImg:height>
<xmpGImg:format>JPEG</xmpGImg:format>
<xmpGImg:image>/9j/4AAQSkZJRgABAgEASABIAAD/7QAsUGhvdG9zaG9wIDMuMAA4QklNA+0AAAAAABAASAAAAAEA&#xA;AQBIAAAAAQAB/+4ADkFkb2JlAGTAAAAAAf/bAIQABgQEBAUEBgUFBgkGBQYJCwgGBggLDAoKCwoK&#xA;DBAMDAwMDAwQDA4PEA8ODBMTFBQTExwbGxscHx8fHx8fHx8fHwEHBwcNDA0YEBAYGhURFRofHx8f&#xA;Hx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8f/8AAEQgA5AEAAwER&#xA;AAIRAQMRAf/EAaIAAAAHAQEBAQEAAAAAAAAAAAQFAwIGAQAHCAkKCwEAAgIDAQEBAQEAAAAAAAAA&#xA;AQACAwQFBgcICQoLEAACAQMDAgQCBgcDBAIGAnMBAgMRBAAFIRIxQVEGE2EicYEUMpGhBxWxQiPB&#xA;UtHhMxZi8CRygvElQzRTkqKyY3PCNUQnk6OzNhdUZHTD0uIIJoMJChgZhJRFRqS0VtNVKBry4/PE&#xA;1OT0ZXWFlaW1xdXl9WZ2hpamtsbW5vY3R1dnd4eXp7fH1+f3OEhYaHiImKi4yNjo+Ck5SVlpeYmZ&#xA;qbnJ2en5KjpKWmp6ipqqusra6voRAAICAQIDBQUEBQYECAMDbQEAAhEDBCESMUEFURNhIgZxgZEy&#xA;obHwFMHR4SNCFVJicvEzJDRDghaSUyWiY7LCB3PSNeJEgxdUkwgJChgZJjZFGidkdFU38qOzwygp&#xA;0+PzhJSktMTU5PRldYWVpbXF1eX1RlZmdoaWprbG1ub2R1dnd4eXp7fH1+f3OEhYaHiImKi4yNjo&#xA;+DlJWWl5iZmpucnZ6fkqOkpaanqKmqq6ytrq+v/aAAwDAQACEQMRAD8A9U4q7FXYq7FXYq7FXYq7&#xA;FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FVsssUUbSyuscSAs7sQqqo3JJPQDFWOL+ZXk&#xA;Rrj6uNat/UrTkSQn/Iwjh+OR4wx4wyG3ube4iEtvKk0TfZkjYMp+RFRkmSpirsVYj+ZvnFfLPl2R&#xA;4XA1O8rDYr3BI+KT5IPxpkJyoMJyoI38vbs3fknRZmbkwtY4yx3NYh6f/GuGPJMeTIckydirsVdi&#xA;rsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVeG/nX55mutQby3YSlbO1I+v&#xA;lD/eTdfTNP2Y+4/m+WUZJdGnJLoiX/Lfybo/5fxavr31prq4SCWS4t6c4WnA4osbHgVUt8Vdz2pj&#xA;wgCyvAAN3nd9aW1gzXGiayLmDvx9S1uFB2AaNqBuv7DNkGs+SyHzf5sh/utavkFa0W5mA29uWPEV&#xA;4ijI/wAxfPMYIXW7o1/mfl/xKuHjKeMpbrfmLW9cnjn1a7e7liT042eg4rWuwUAfTgJJQSS9/wDy&#xA;ZufW/L+xStTBJPEf+RrOPwfL8fJvx8mb5Nm7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7&#xA;FXYq7FXYq7FXYq7FUr8063Hofl6/1V6H6rEWjU9GkPwxqf8AWdgMEjQRI0Hy9pdhqHmHX4LRGMt7&#xA;qM/xyHclnPJ5G+QqxzF5uMBZer/n3fww6bpek290EKsXmsFO5jVQsbt7KQQK9foy3IejblLxbKml&#xA;2KuxV2KvWvyR8721lI3lq9pGl1KZbGc7fvWAUxN/rcRx99u4y3HLo245dHtuXNzsVdirsVdirsVd&#xA;irsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVeffnjfRQeSGt2I53lxFGi9/gJkJ/4TK8&#xA;h2a8h2Yl+TWn6RpNrdebNauYrSM8rawaZgtQN5XUHdidlFPfIY6G5Y4xW5YP5+vtM1DzZf32m3cl&#xA;7aXL+ok0oYEEihQc6HitKL7ZCXNhI7sewMUw0bQNZ1q5a30u0e6lQcnCUAVfFmYhVHzOICQCUZfe&#xA;SPNVlA9xNp0j28ZIkngKXEakdeTwmRRT3ONJMCEjxYqlupaZaMU4/EXHUBRyJHuAMVfR35U+cbjz&#xA;L5ff63ve2DiCaQmpkUrVHbp8RGx9xmRCVhyISsM1ybN2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2Ku&#xA;xV2KuxV2KuxV2KuxV2KuxV87/nF5wi13zAtlZvz0/S+USOD8LzMf3jj2FAo+Ve+Y+SVlx8krLAmd&#xA;2ChmJCiigmtBWtBkGC3FXYqyifzCLv8AK++8qaYq2GryTJK8wf0xexcqvG0jEBWApsTxYCnU0MMt&#xA;mFDm5OCYB3Tb/nHLyP590bzNdahqNpPpujPbFJYriqCeRipj4xk78dzzp7d8r0eKYlZ2DlZZAhEf&#xA;nXp3ly18wRzaXNEL2YN+kbOL9hxTi54/CrPXcde/fMrIBezgZALedxuyOrrsykEfRkGt67+QV2qa&#xA;nq1on93cwxzotfsmFirD/ksPwy3EW3E9oy5udirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsV&#xA;dirsVdirsVdiryD80PzahWGbQ/LsweVwY7zUIzVVU7FIWHUnuw6dt9xVOfQNU59A8XylpdirsVdi&#xA;rsVTy287+bbXTf0Zb6rcRWQHFYlehVT+yrfaUewOHiLLiKSMxYlmJLE1JPUnAxZ9+UXkjSvM2o3s&#xA;mqgyWlgkZ+rKxTm8palWUhuICHofDJwjZbMcbet6f+XuheX9QXVtAhktpkHCe2EjyRywtTmtJC7c&#xA;h9pd+op0y3grcNoiByZbk2TsVdirsVdirsVdirsVdirsVdirsVdirsVdirH9Z8/eT9HLJfapCsq7&#xA;NDGTNID4FIw5H05EyAYmQDDtR/P7y9CzLYafc3ZHRpCkKk+3941PmMgcoYHKEof/AJyFuix4aGgX&#xA;sDcEn7/TGDxUeK0v/OQt3yHLRIytdwLgg0+fpnHxV8VHW3/OQmntT6zo00Xj6Uyyf8SWPD4qfFTQ&#xA;fnx5ONs0noXgmUfDA0aVY+HIOVw+KE+IHm3nL82PMXmNHtYyNO0xtjawsSzjwlk2LfIAD2yuUyWu&#xA;UyWEZBg7FXYq7FXYq7FV8cMktfTXkR+yOv0DqfoxV0kMsRAkRkJFQGBFR9OKsl/LzzbeeWdeF3FC&#xA;9zayr6d7boKkx1ryX/KU7j7u+GMqLKEqL3fR/P2m69epZaNDcSOV9S5nliaKOGMdal/tOTsoAP3D&#xA;LxO+TeJWyjJsnYq7FXYq7FXYq7FXYq7FXYq7FXYqoXt9ZWNs91ezx21vGKvLKwRR9JxtbeZeZvz3&#xA;0q1LwaBbG/lG31qascHzVdnf/hcqOXuajk7nl2v/AJgebddLLfajJ6Df8esJ9KKngVSnL/ZVysyJ&#xA;azIljuRYuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxVWt3uSwhh5OZCAIQOYZjsPg3BP0Yq9G8r/k1&#xA;5l1f059bkOl2H2hAQPXI/wAmIfDH/st/bLI4yebYMZPN7H5Z8paH5as2tdKg9ISEGaViWkkZdgXY&#xA;/PoNsuEQG4RATjCl2KuxV2KuxV2KuxV2KuxV2KuxVgvnv819I8t87K0Av9YGxgU/u4j/AMWsO/8A&#xA;kjfxpkJTphKdPCfMXmrXfMN39Z1W6aYgn0oR8MUYPZEGw+fU98oMiWgyJSjAh2KuxV2KuxV2KuxV&#xA;2KuxV2KuxV2KuxV2KuxV2KvS/wAh9LW581XN861WxtjwPhJKwUH/AIDllmIbtmMbvfMvb3Yq7FXY&#xA;q7FXYq7FXYq7FXYq7FXYq8p/Nb803055NB0KUfXaFb68U1MNdjGh/wB+eJ/Z+fSqc+gapz6B4ezM&#xA;zFmJZmNSTuSTlLS1irsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdir3D/nH2y4aPq17T+/uI&#xA;4a/8YU5f8zsuxN2J6vlra7FXYq7FXYq7FXYq7FXYq7FXYqwX81fPv+GtJFpZOP0zfKRB3MUfRpSP&#xA;Hsvv8shOVMJyp85szOxdyWZjVmO5JPUk5juO1irsVdirsVdirsVdirsVdirsVdirsVdirsVdirsV&#xA;dirsVfTH5TaQ+meRdPWReMt2Gu3H/GY1T/knxzIgKDkQFBl+TZuxV2KuxV2KuxV2KuxV2KuxVC6p&#xA;qVppenXOoXb8La1jaSVvZR0HuegwE0gmnyt5m8wXnmDW7rVbs/HO3wR9QkY2RB/qrmMTZcYmyleB&#xA;DsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVT7yR5Zm8x+Y7TTUB9At6l24/ZgQ1c/T9k&#xA;e5wxFllEWX1PHGkcaxxqFjQBUUbAACgAzKcldirsVdirsVdirsVdirsVdirsVeO/nz5pIFt5bt32&#xA;YC5vqHtX91Gfu5Ef6uU5ZdGnLLo8aypqdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirs&#xA;VfR35T+Sf8OaF9Zu4+OragFkuARvHH1SL2IrVvf5ZkQjQciEaDOcmzdirsVdirsVdirsVdirsVdi&#xA;qld3UFpazXVwwSC3RpZXPRUQFmP0AYq+TvMOsz61rd7qs/8AeXcrSBf5V6Iv+xUAZik2XFJspdgQ&#xA;7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXqH5M+Qjqd6PMOoR/7j7N/9DjYbSzr+1v1&#xA;WP8A4l8jlmON7tmON7vd8vb3YLine truncated
</rdf:li>
</rdf:Alt>
</xmp:Thumbnails>
</rdf:Description>
<rdf:Description rdf:about=""
xmlns:xmpTPg="http://ns.adobe.com/xap/1.0/t/pg/"
xmlns:stDim="http://ns.adobe.com/xap/1.0/sType/Dimensions#"
xmlns:xmpG="http://ns.adobe.com/xap/1.0/g/">
<xmpTPg:NPages>1</xmpTPg:NPages>
<xmpTPg:HasVisibleTransparency>False</xmpTPg:HasVisibleTransparency>
<xmpTPg:HasVisibleOverprint>False</xmpTPg:HasVisibleOverprint>
<xmpTPg:MaxPageSize rdf:parseType="Resource">
<stDim:w>64.000000</stDim:w>
<stDim:h>64.000000</stDim:h>
<stDim:unit>Points</stDim:unit>
</xmpTPg:MaxPageSize>
<xmpTPg:PlateNames>
<rdf:Seq>
<rdf:li>Cyan</rdf:li>
<rdf:li>Magenta</rdf:li>
<rdf:li>Yellow</rdf:li>
<rdf:li>Black</rdf:li>
</rdf:Seq>
</xmpTPg:PlateNames>
<xmpTPg:SwatchGroups>
<rdf:Seq>
<rdf:li rdf:parseType="Resource">
<xmpG:groupName>Default Swatch Group</xmpG:groupName>
<xmpG:groupType>0</xmpG:groupType>
</rdf:li>
</rdf:Seq>
</xmpTPg:SwatchGroups>
</rdf:Description>
<rdf:Description rdf:about=""
xmlns:illustrator="http://ns.adobe.com/illustrator/1.0/">
<illustrator:Type>Document</illustrator:Type>
</rdf:Description>
<rdf:Description rdf:about=""
xmlns:dc="http://purl.org/dc/elements/1.1/">
<dc:format>application/pdf</dc:format>
<dc:title>
<rdf:Alt>
<rdf:li xml:lang="x-default">Mongoo 3 smooth green</rdf:li>
</rdf:Alt>
</dc:title>
</rdf:Description>
<rdf:Description rdf:about=""
xmlns:xmpMM="http://ns.adobe.com/xap/1.0/mm/">
<xmpMM:RenditionClass>proof:pdf</xmpMM:RenditionClass>
<xmpMM:DocumentID>uuid:a2f6b830-2598-49b9-8770-4f9fa14f1be3</xmpMM:DocumentID>
<xmpMM:InstanceID>uuid:42245d04-b042-4038-b450-94c7cfb8ee6f</xmpMM:InstanceID>
</rdf:Description>
<rdf:Description rdf:about=""
xmlns:pdf="http://ns.adobe.com/pdf/1.3/">
<pdf:Producer>Adobe PDF library 10.01</pdf:Producer>
</rdf:Description>
</rdf:RDF>
</x:xmpmeta>
<?xpacket end="w"?>
endstream␍endobj␍3 0 obj␍<</Count 1/Kids[7 0 R]/Type/Pages>>␍endobj␍7 0 obj␍<</ArtBox[0.643066 4.46875 63.2324 59.6494]/BleedBox[0.0 0.0 64.0 64.0]/Contents 8 0 R/LastModified(D:20130102172747+01'00')/MediaBox[0.0 0.0 64.0 64.0]/Parent 3 0 R/PieceInfo<</Illustrator 9 0 R>>/Resources<</ExtGState<</GS0 10 0 R>>/Properties<</MC0 5 0 R>>>>/Thumb 11 0 R/TrimBox[0.0 0.0 64.0 64.0]/Type/Page>>␍endobj␍8 0 obj␍<</Filter/FlateDecode/Length 1251>>stream
H‰t–KŽ•7…çÿ*¼�kì²]¶§!#Y@+�A "±û|§Ü}i"E4}»ü¨Ç©SÇ÷Õ¯¯Ó«·¯Kúéç×éú|•ä]?7þùãú=ýu•Ül¤’»u~7éˇëÕ›÷%}øûúœj*ü«©ö<gÉfÞ­{zøtiãÓu«yøL–K[øÍ¥®ÄRK_Ù­oÌb5ÝêÊ}Xº�\pp«5ouµ§‡ëÖòžø°�}�ÔKøºÕ�7Oß.㪱P
Õ¼†‡Ûʹ¯—åÞ,üY›ªhN,Ï«,,ëºjyt#V˶å»äéÆîZ-vw_©åÚ”é¬ÅÙ™{ìŽ<¨¥äíÖÄ/‡ÌG˜»ê°NùЏըÙ#�Îåª"
Þw\¨»§ÇËH;ʹ�•¬e¯Ç¡¨qùýþC€Pq¸ù°D ,OrµžW·€Ö÷ÔiúÑçk¢EÓmåmç|9Φ%eÒ´Õ,"�CºÍ<F�¬¦ºÛÆÒ�ä¶:Y)žÍ¥;Í6•¨¤h#‘¢À8âɆæŽ>Ò»\µ¢(JØ\›^v@_ÈŸ= ,ñ<• Ûf€³pÒÈÐOǽˆ!,L÷XèKå²ÐK‹nP.6mj~X±ì,¬ÚO»è. 6oDh:�œw:ĉ G‡a÷Ȃh ½žŠ`ÖhJ˃,¿ÊÁò㱪€1³G›j '­ž6ì„55WÌ `mu��¢¼E*âdžpƒyé\„—¤×-C*�ß›s�ÐД'ÜÁ"=E‚N’ÕÓS¹¥B€à¤êÇ«“ÇàôŽšî64nSxq~Žž åÄŸî×%›D£†³SMSqXcXÕöV¹␍Ö[¶&Žê–è)øܼ˜ì…~¨␍H–8Â]@ôVí">vñ° „Ikw»,ãP0QºIl†§k[jHž ñªaµc¸èg-¢2*u]Ù 8®!ɰý<“:HWÈ­®U+±)·_/±E¸#^]¢R¥“”ZÒ¯èÏŒR:à„Ú‰ë–␍8}å=AOá@AXé!Øß®?¯wW•pKÏ¿ë8 ôÚIû»„Çà€"%Ãuè-£³o� “¤2æ[LZ}Ÿý…ÜJ¼M=ÄYLÔ5ö£-9°}ö›î3ñþt~Ä�ÑŽyÖÀ¯^ïæyG¯�QÖËjè�Bçå«T JãÍ”©'©¸†¯Âך™„ª"þHhßãs1Pi Ê[#!_R7i޲Ÿ|Qbgñ•xd ¢º3Bøñ±¸VC*U%irGÉÓõp•?Ì�À|ïžÔ/’˜TòŸ.z¤KÙ¥ù˲åEZ©�¦ßkÄÇûÙzГݥÈO»5ž®ç‹Ç*çXüù¼®;?8¼û‹`Ç*OçK¸ø:=ÀÒ·žnûáËDÕs/$Ò«ç»!Õ¬"²1~RÐ"Uǰ“ÿ4‰¢l�û5ð�?—Y4FßC¸ÜìÔ×$̰¿?‰jXC§7·ÓáS¢
ÇV~…a‹8´êC$èâïÝ,1_`ðÛv¥ãÿ¤žÞ¦û‰{4 qÒ¾ê;²
¼¥g¶N ôÜÃ uåm;4
ëýƒâÔ>hÒ�ê·€—ü d{ö«îŠ–2wðç:¯ù|Rƒoáþ—·|©|wý+ÀWûµ
endstream␍endobj␍11 0 obj␍<</BitsPerComponent 8/ColorSpace 12 0 R/Filter[/ASCII85Decode/FlateDecode]/Height 8/Length 60/Width 8>>stream
8;Xp,*=RnBA=+-oL^=GFM?1!l_%=Zlo8S9:+GRslKjBJT)I<XS0E>k]*Q8~>
endstream␍endobj␍12 0 obj␍[/Indexed/DeviceRGB 255 13 0 R]␍endobj␍13 0 obj␍<</Filter[/ASCII85Decode/FlateDecode]/Length 428>>stream
8;X]O>EqN@%''O_@%e@?J;%+8(9e>X=MR6S?i^YgA3=].HDXF.R$lIL@"pJ+EP(%0
b]6ajmNZn*!='OQZeQ^Y*,=]?C.B+\Ulg9dhD*"iC[;*=3`oP1[!S^)?1)IZ4dup`
E1r!/,*0[*9.aFIR2&b-C#s<Xl5FH@[<=!#6V)uDBXnIr.F>oRZ7Dl%MLY\.?d>Mn
6%Q2oYfNRF$$+ON<+]RUJmC0I<jlL.oXisZ;SYU[/7#<&37rclQKqeJe#,UF7Rgb1
VNWFKf>nDZ4OTs0S!saG>GGKUlQ*Q?45:CI&4J'_2j<etJICj7e7nPMb=O6S7UOH<
PO7r\I.Hu&e0d&E<.')fERr/l+*W,)q^D*ai5<uuLX.7g/>$XKrcYp0n+Xl_nU*O(
l[$6Nn+Z_Nq0]s7hs]`XX1nZ8&94a\~>
endstream␍endobj␍5 0 obj␍<</Intent 14 0 R/Name(svg2)/Type/OCG/Usage 15 0 R>>␍endobj␍14 0 obj␍[/View/Design]␍endobj␍15 0 obj␍<</CreatorInfo<</Creator(Adobe Illustrator 16.0)/Subtype/Artwork>>>>␍endobj␍10 0 obj␍<</AIS false/BM/Normal/CA 1.0/OP false/OPM 1/SA true/SMask/None/Type/ExtGState/ca 1.0/op false>>␍endobj␍9 0 obj␍<</LastModified(D:20130102172747+01'00')/Private 16 0 R>>␍endobj␍16 0 obj␍<</AIMetaData 17 0 R/AIPrivateData1 18 0 R/AIPrivateData2 19 0 R/ContainerVersion 11/CreatorVersion 16/NumBlock 2/RoundtripStreamType 1/RoundtripVersion 16>>␍endobj␍17 0 obj␍<</Length 1003>>stream
%!PS-Adobe-3.0
%%Creator: Adobe Illustrator(R) 16.0
%%AI8_CreatorVersion: 16.0.3
%%For: (Calum) ()
%%Title: (Mongoo 3 smooth green.svg)
%%CreationDate: 1/2/2013 5:27 PM
%%Canvassize: 16383
%%BoundingBox: 274 368 337 425
%%HiResBoundingBox: 274.1431 368.9688 336.7324 424.1494
%%DocumentProcessColors: Cyan Magenta Yellow Black
%AI5_FileFormat 12.0
%AI12_BuildNumber: 691
%AI3_ColorUsage: Color
%AI7_ImageSettings: 0
%%RGBProcessColor: 0 0 0 ([Registration])
%AI3_Cropmarks: 273.5 364.5 337.5 428.5
%AI3_TemplateBox: 305.5 396.5 305.5 396.5
%AI3_TileBox: 16.2998 -16 594.7002 809
%AI3_DocumentPreview: None
%AI5_ArtSize: 14400 14400
%AI5_RulerUnits: 2
%AI9_ColorModel: 1
%AI5_ArtFlags: 0 0 0 1 0 0 1 0 0
%AI5_TargetResolution: 800
%AI5_NumLayers: 1
%AI9_OpenToView: -285 842 1 1189 873 26 0 0 46 116 0 0 0 1 1 0 1 1 0 1
%AI5_OpenViewLayers: 7
%%PageOrigin:0 0
%AI7_GridSettings: 72 8 72 8 1 0 0.8 0.8 0.8 0.9 0.9 0.9
%AI9_Flatten: 1
%AI12_CMSettings: 00.MS
%%EndComments
endstream␍endobj␍18 0 obj␍<</Length 19265>>stream
%%BoundingBox: 274 368 337 425
%%HiResBoundingBox: 274.1431 368.9688 336.7324 424.1494
%AI7_Thumbnail: 128 116 8
%%BeginData: 19108 Hex Bytes
%0000330000660000990000CC0033000033330033660033990033CC0033FF
%0066000066330066660066990066CC0066FF009900009933009966009999
%0099CC0099FF00CC0000CC3300CC6600CC9900CCCC00CCFF00FF3300FF66
%00FF9900FFCC3300003300333300663300993300CC3300FF333300333333
%3333663333993333CC3333FF3366003366333366663366993366CC3366FF
%3399003399333399663399993399CC3399FF33CC0033CC3333CC6633CC99
%33CCCC33CCFF33FF0033FF3333FF6633FF9933FFCC33FFFF660000660033
%6600666600996600CC6600FF6633006633336633666633996633CC6633FF
%6666006666336666666666996666CC6666FF669900669933669966669999
%6699CC6699FF66CC0066CC3366CC6666CC9966CCCC66CCFF66FF0066FF33
%66FF6666FF9966FFCC66FFFF9900009900339900669900999900CC9900FF
%9933009933339933669933999933CC9933FF996600996633996666996699
%9966CC9966FF9999009999339999669999999999CC9999FF99CC0099CC33
%99CC6699CC9999CCCC99CCFF99FF0099FF3399FF6699FF9999FFCC99FFFF
%CC0000CC0033CC0066CC0099CC00CCCC00FFCC3300CC3333CC3366CC3399
%CC33CCCC33FFCC6600CC6633CC6666CC6699CC66CCCC66FFCC9900CC9933
%CC9966CC9999CC99CCCC99FFCCCC00CCCC33CCCC66CCCC99CCCCCCCCCCFF
%CCFF00CCFF33CCFF66CCFF99CCFFCCCCFFFFFF0033FF0066FF0099FF00CC
%FF3300FF3333FF3366FF3399FF33CCFF33FFFF6600FF6633FF6666FF6699
%FF66CCFF66FFFF9900FF9933FF9966FF9999FF99CCFF99FFFFCC00FFCC33
%FFCC66FFCC99FFCCCCFFCCFFFFFF33FFFF66FFFF99FFFFCC110000001100
%000011111111220000002200000022222222440000004400000044444444
%550000005500000055555555770000007700000077777777880000008800
%000088888888AA000000AA000000AAAAAAAABB000000BB000000BBBBBBBB
%DD000000DD000000DDDDDDDDEE000000EE000000EEEEEEEE0000000000FF
%00FF0000FFFFFF0000FF00FFFFFF00FFFFFF
%524C45FD77FFA8A8FD7EFF7D58FD7EFF2D7DFD6BFF7C585283A8FD0DFF52
%5152FD6AFF52522D582D52527D7D837DFD04A8FFA8FF83585258FD69FF52
%522DA8A883522D2D522D512D522D522D5852522D5252FD68FF7D522DA7FF
%FFA8AE7D5851585258515852522D5852582D58A8FD66FFA8522D5283FFA8
%52517D58522D522D522D522D522D522D522DA8FD66FF832D5852FFFFA82D
%5852585258525852585258525852585258A8FD66FF2D522D52A8FF52522D
%5851522D5851522D5851522D5851522D83FD65FF835251527CFFFF7D2D58
%515852585158525851585258515852582DA8FD64FF582D522DA8FFA85152
%2D522D522D522D522D522D522D522D522D522DFD64FF52582D7DFFFF5258
%525852585258525852585258525852585258525858FD62FFA8582D52A8FF
%83522D5851522D5851522D5851522D5851522D5851522D527DFD61FFA82D
%5258FFFFFF585251585258515852522D5851522D585258515852585258A8
%FD60FF7D512DA8FFA852582D522D522D522D5258A8A7A87D522D522D522D
%5251582D7DFD60FF7D2D587D582D5852585258525852587DFF7C5151FFFF
%A7515852585258525858FD5FFFAE2D522D522D522D5851522D58515251FF
%A726202651FFFF832D522D582D585258A8FD5EFF58525258515852585158
%5258515852527DA82626207CFFFFFF5852585158525852FD5EFF7D512D52
%2D522D522D522D522D522D522D52527C517CA8FFFFA82D522D522D522D52
%7DFD5CFFAE5851585258525852585258525852585258525852A8FFFFA87D
%2D58525852582D522DA8FD5BFFA8582D522D5851522D5851522D5851522D
%5851522D522D5858582D522D58515252A8A8837CFD5BFF7D2D5852585158
%5258515852585158525851585258515851522D585258515852A8FD04FFA8
%FD58FFA8582D522D522D522D522D522D522D522D522D522D522D522D522D
%522D522D522D58FD05FFCFFD57FF83585158525852585258525852585258
%52585258525852585258525852585258525852FD5CFF58522D5851522D58
%51522D5851522D5851522D5851522D5851522D5851522D5851522D527DFD
%46FFA8A883837D837D7D7D837DA783A8A8FFFFFFAE835152525851585258
%515852585158525851585258515852585158525851585258515852585158
%A7FFFFFFA8FD3EFF838352522D522D512D522D512D522D522D5251585258
%2D522D522D522D522D522D522D522D522D522D522D522D522D522D522D52
%525851522D522D522D587C7D58FD3CFFA87D52582D525158525852585258
%525852585258525851585258525852585258525852585258525852585258
%525852585258525852585258587C527D5258527D525252FD3AFFA87D5152
%2D522D5851522D5851522D5851522D5851522D5851522D5851522D585152
%2D5851522D5851522D5851522D5851522D5851522D5851522D522D525158
%52522D5258A8FD38FFA858582D5251585258515852585158525851585258
%515852585158525851585258515852585158525851585258515852585158
%52585158525851585258515852582D522D7DA8FD38FF7D582D522D522D52
%2D522D522D522D522D522D522D522D522D522D522D522D522D522D522D52
%2D522D522D522D522D522D522D522D522D522D522D522D522D522D522D51
%52A8FD38FFA8525252585258525852585258525852585258525852585258
%525852585258525852585258525852585258525852585258525852585258
%525852585258525852585258525883FD38FFA87C2D522D5851522D585152
%2D5851522D5851522D5851522D5851522D5851522D5851522D5851522D58
%51522D5851522D5851522D5851522D5851522D5851522D5851522D5258FD
%38FF7D522D58525851585258515852585158525851585258515852585158
%525851585258515852585158525851585258515852585158525851585258
%5158525851585258515852582DA8FD36FFA852522D522D522D522D522D52
%2D522D522D522D522D522D522D522D522D522D522D522D522D522D522D52
%2D522D522D522D522D522D522D522D522D522D522D522D522D522D522D52
%A8FD35FFA82D585258525852585258525852585258525852585258525852
%585258525852585258525852585258525852585258525852585258525852
%585258525852585258525852585258525852FD35FF832D522D5851522D58
%51522D5851522D5851522D5851522D5851522D5851522D5851522D585152
%2D5851522D5851522D5851522D5851522D5851522D5851522D5851522D58
%51522D582D58FD34FF832D58525851585258515852585158525851585258
%515852585158525851585258515852585158525851585258515852585158
%5258515852585158525851585258515852585158525851587CFD33FF832D
%522D522D522D522D522D522D522D522D522D522D522D522D522D522D522D
%522D522D522D522D522D522D522D522D522D522D522D522D522D522D522D
%522D522D522D522D522D522D522D7DFD32FFA82D58525852585258525852
%585258525852585258525852585258525852585258525852585258525852
%585258525852585258525852585258525852585258525852585258525852
%585258525283FD31FFA82D5251522D5851522D5851522D5851522D585152
%2D5851522D5851522D5851522D5851522D5851522D5851522D5851522D58
%51522D5851522D5851522D5851522D5851522D5851522D5851522DA8FD31
%FF5252515852585158525851585258515852585158525851585258515852
%585158525851585258515852585158525851585258515852585158525851
%58525851585258515852585158525851585258A8FD30FF58522D522D522D
%522D522D522D522D522D522D522D522D522D522D522D522D522D522D522D
%522D522D522D522D522D522D522D522D522D522D522D522D522D522D522D
%522D522D522D522D522D5258FD30FFA75852585258525852585258525852
%585258525852585258525852585258525852585258525852585258525852
%585258525852585258525852585258525852585258525852585258525852
%5852582DA8FD2FFFA8522D5851522D5851522D5851522D5851522D585152
%2D5851522D5851522D5851522D5851522D5851522D5851522D5851522D58
%51522D5851522D5851522D5851522D5851522D5851522D5851522D58A8FD
%2FFF832D5851585258515852585158525851585258515852585158525851
%585258515852585158525851585258515852585158525851585258515852
%5851585258515852585158525851585258515852527DFD2FFFA82D522D52
%2D522D522D522D522D522D522D522D522D522D522D522D522D522D522D52
%2D522D522D522D522D522D522D522D522D522D522D522D522D522D522D52
%2D522D522D522D522D522D522D522DAEFD2FFF5858525852585258525852
%585258525852585258525852585258525852585258525852585258525852
%585258525852585258525852585258525852585258525852585258525852
%585258525852582DA7FD2FFFA8522D5851522D5851522D5851522D585152
%2D5851522D5851522D5851522D5851522D5851522D5851522D5851522D58
%51522D5851522D5851522D5851522D5851522D5851522D5851522D585152
%2D58AEFD2FFF7D5158515852585158525851585258515852585158525851
%585258515852585158525851585258515852585158525851585258515852
%58515852585158525851585258515852585158525851585252A7FD2FFFA8
%2D522D522D522D522D522D522D522D522D522D522D522D522D522D522D52
%2D522D522D522D522D522D522D522D522D522D522D522D522D522D522D52
%2D522D522D522D522D522D522D522D522D5258FD30FF5858525852585258
%525852585258525852585258525852585258525852585258525852585258
%525852585258525852585258525852585258525852585258525852585258
%5258525852585258525852FD30FFA8522D5851522D5851522D5851522D58
%51522D5851522D5851522D5851522D5851522D5851522D5851522D585152
%2D5851522D5851522D5851522D5851522D5851522D5851522D5851522D58
%51522DA8FD30FF832D585158525851585258515852585158525851585258
%515852585158525851585258515852585158525851585258515852585158
%5258515852585158525851585258515852585158525851582D7DFD31FF51
%522D522D522D522D522D522D522D522D522D522D522D522D522D522D522D
%522D522D522D522D522D522D522D522D522D522D522D522D522D522D522D
%522D522D522D522D522D522D522D522D58A8FD30FFA85852585258525852
%585258525852585258525852585258525852585258525852585258525852
%585258525852585258525852585258525852585258525852585258525852
%585258525852585158A8FD31FF7D2D5851522D5851522D5851522D585152
%2D5851522D5851522D5851522D5851522D5851522D5851522D5851522D58
%51522D5851522D5851522D5851522D5851522D5851522D5851522D585151
%7DFD32FF5252515852585158525851585258515852585158525851585258
%515852585158525851585258515852585158525851585258515852585158
%525851585258515852585158525851585258515258FD32FF7D522D522D52
%2D522D522D522D522D522D522D522D522D522D522D522D522D522D522D52
%2D522D522D522D522D522D522D522D522D522D522D522D522D522D522D52
%2D522D522D522D522D522DFD33FF83515852585258525852585258525852
%585258525852585258525852585258525852585258525852585258525852
%58525852585258525852585258525852585258525852585258525852582D
%AEFD33FF515251522D5851522D5851522D5851522D5851522D5851522D58
%51522D5851522D5851522D5851522D5851522D5851522D5851522D585152
%2D5851522D5851522D5851522D5851522D582D83FD25FFA8AEA8A883A8A8
%AEFD06FFA852515852585158525851585258515852585158525851585258
%515852585158525851585258515852585158525851585258515852585158
%5258515852585158525851585258515852582D7DFD23FFA88352522D522D
%2D2D522D5858A8FFFFFF832D522D522D522D522D522D522D522D522D522D
%522D522D522D522D522D522D522D522D522D522D522D522D522D522D522D
%522D522D522D522D522D522D522D522D522D522D522D522D52A8FD22FF7C
%582D52515852585258525851582D7CA8FF58585258525852585258525852
%585258525852585258525852585258525852585258525852585258525852
%585258525852585258525852585258525852585258525852585258525852
%52A8FD20FFA8832D522D5851522D5851522D5851522D522D527D582D522D
%5851522D5851522D5851522D5851522D5851522D5851522D5851522D5851
%522D5851522D5851522D5851522D5851522D5851522D5851522D5851522D
%5851522D5851522D527DFD20FFA8582D5852585158525851585258515852
%585158525251585258515852585158525851585258515852585158525851
%585258515852585158525851585258515852585158525851585258515852
%585158525851585258515852585158525258FD20FF7D522D522D522D522D
%522D522D522D522D522D522D522D522D522D522D522D522D522D522D522D
%522D522D522D522D522D522D522D522D522D522D522D522D522D522D522D
%522D522D522D522D522D522D522D522D522D522D522D522D5252FD20FF83
%585258525852585258525852585258525852585258525852585258525852
%585258525852585258525852585258525852585258525852585258525852
%585258525852585258525852585258525852585258525852585258525852
%5852582DA8FD1FFFA8522D5851522D5851522D5851522D5851522D585152
%2D5851522D5851522D5851522D5851522D5851522D5851522D5851522D58
%51522D5851522D5851522D5851522D5851522D5851522D5851522D585152
%2D5851522D5851522D5851522D5283FD1EFFA85851585158525851585258
%515852585158525851585258515852585158525851585258515852585158
%525851585258515852585158525851585258515852585158525851585258
%51585258515852582D5852585158525851585258515852582DA8FD1EFF7D
%2D522D522D522D522D522D522D522D522D522D522D522D522D522D522D52
%2D522D522D522D522D522D522D522D522D522D522D522D522D522D522D52
%2D522D522D522D522D522D522D522D522D522D522D522D522D522D522D52
%2D522D522D5283FD1DFFA82D585258525852585258525852585258525852
%585258525852585258525852585258525852585258525852585258525852
%585258525852585258525852585258525852585258525852585258525852
%A8A858525852585258525852585258525851FD1EFF52522D5851522D5851
%522D5851522D5851522D5851522D5851522D5851522D5851522D5851522D
%5851522D5851522D5851522D5851522D5851522D5851522D5851522D5851
%522D5851522D582D527DFFFFFF525251522D5851522D5851522D582D52A8
%FD1CFFA85252585158525851585258515852585158525851585258515852
%585158525851585258515852585158525851585258515852585158525851
%585258515852585158525851585258515852582D7DA8FD04FFA82D585258
%5158525851585258515852AEFD1CFF7D2D522D522D522D522D522D522D52
%2D522D522D522D522D522D522D522D522D522D522D522D522D522D522D52
%2D522D522D522D522D522D522D522D522D522D522D522D522D522D522D52
%2D58A8FD05FFA8582D522D522D522D522D522D522D52A8FD1CFF52585258
%525852585258525852585258525852585258525852585258525852585258
%525852585258525852585258525852585258525852585258525852585258
%52585258525852585258525852FD07FF7D52525852585258525852585258
%52AEFD1BFF83522D5851522D5851522D5851522D5851522D5851522D5851
%522D5851522D5851522D5851522D5851522D5851522D5851522D5851522D
%5851522D5851522D5851522D5851522D5851522D582D58AEFD07FF2D5251
%522D5851522D5851522D52A8FD1BFF832D58515852585158525851585258
%515852585158525851585258515852585158525851585258515852585158
%525851585258515852585158525851585258515852585158525851585258
%51527DFD08FF7D2D58525851585258515852582DAEFD1BFF52522D522D52
%2D522D522D522D522D522D522D522D522D522D522D522D522D522D522D52
%2D522D522D522D522D522D522D522D522D522D522D522D522D522D522D52
%2D522D522D522D522D522DA8FD08FFA8522D522D522D522D522D522D527D
%FD1BFF585258525852585258525852585258525852585258525852585258
%525852585258525852585258525852585258525852585258525852585258
%5258525852585258525852585258525852582D7DFD0AFF58585258525852
%58525852582DA8FD1BFF2D5851522D5851522D5851522D5851522D585152
%2D5851522D5851522D5851522D5851522D5851522D5851522D5851522D58
%51522D5851522D5851522D5851522D5851522D5851522D582D52A8FD0AFF
%A82D5851522D5851522D582D527DFD1BFF58515852585158525851585258
%515852585158525851585258515852585158525851585258515852585158
%525851585258515852585158525851585258515852585158525851585258
%5158A8FD0CFF582D5852585158525851582DA8FD1BFF2D522D522D522D52
%2D522D522D522D522D522D522D522D522D522D522D522D522D522D522D52
%2D522D522D522D522D522D522D522D522D522D522D522D522D522D522D52
%2D522D522D522DA7A8FD0BFF7D512D522D522D522D522D527DFD1BFF5852
%585258525852585258525852585258525852585258525852585258525852
%585258525852585258525852585258525852585258525852585258525852
%5852585258525852585258525851587DAEFD09FFAE2D5852585258525852
%585183FD1BFF52522D5851522D5851522D5851522D5851522D5851522D58
%51522D5851522D5851522D5851522D5851522D5851522D5851522D585152
%2D5851522D5851522D5851522D5851522D5851522D582D522D7DFD09FF58
%2D5851522D5851522D5258FD1BFF7D525851585258515852585158525851
%585258515852585158525851585258515852585158525851585258515852
%585158525851585258515852585158525851585258515852585158525851
%5852582DA7FD08FF7D5251585258515852582D7CFD1BFF58522D522D522D
%522D522D522D522D522D522D522D522D522D522D522D522D522D522D522D
%522D522D522D522D522D522D522D522D522D522D522D522D522D522D522D
%522D522D522D522D522D522D522DA8FD07FFA82D522D522D522D522D522D
%FD1BFFA82D58525852585258525852585258525852585258525852585258
%525852585258525852585258525852585258525852585258525852585258
%52585258525852585258525852585258525852585258525258FD07FFA858
%52585258525852585258A8FD1AFFA7522D522D5851522D5851522D585152
%2D5851522D5851522D5851522D5851522D5851522D5851522D5851522D58
%51522D5851522D5851522D5851522D5851522D5851522D5851522D585152
%2D522D522D7DAEFD07FF2D522D5851522D5851522DA8FD1BFF5258525851
%58525851585258515852585158525851585258515852582D52527D515852
%585158525851585258515852585158525851585258515852585158525851
%58525851585258515858837DA8A8FD09FFA858525851585258515852527D
%FD1BFF7D2D522D522D522D522D522D522D522D522D522D522D522D522D52
%2D527DFFA8522D522D522D522D522D522D522D522D522D522D522D522D52
%2D522D522D522D522D522D522D522D522D7DA8FD0CFFCF2D522D522D522D
%522D522D58A8FD1AFF7D5252585258525852585258525852585258525852
%585258525852527DFFFFFF52585258525852585258525852585258525852
%585258525852585258525852585258525852585258525851587DFD0CFF58
%525852585258525852582D7CA8FD19FFAE2D5251522D5851522D5851522D
%5851522D5851522D5851522D582D83FFFFFF7D2D5251522D5851522D5851
%522D5851522D5851522D5851522D5851522D5851522D5851522D5851522D
%582D5158FD0BFF525251522D5851522D5851522D527DFD19FF7D2D585258
%515852585158525851585258515852585158525851527DFD04FF7D2D5251
%585158525851585258515852585158525851585258515852585158525851
%585258515852585158525258FD0AFF7D2D585258515852582D5852582D58
%AEFD18FF83512D522D522D522D522D522D522D522D522D522D522D522D52
%2D58FD05FFA87D582D512D522D522D522D522D522D522D522D522D522D52
%2D522D522D522D522D522D522D522D522D522D2D52FD09FF7D512D522D52
%2D522D7C52522D522DA8FD19FF5258525852585258525852585258525852
%58525852585258525851AEFD07FFAE7D7D52522D58525852585258525852
%585258525851588383587D52582D5851522D5851522D585158527DA8FD09
%FF525852585258525852FFA87D2D58A8FD19FF832D5851522D5851522D58
%51522D5851522D5851522D5851522D5258FD0BFFA87D585851522D522D52
%2D522D522D582D2D7DFFFFFFCFFFA8A87D837D7D587D587D7DA8A8FD0CFF
%A82D5251522D58515252FFFFCFA8FD1BFF582D5852585158525851585258
%51585258515852585158525851527DFD0FFFA8A87D837C7D525852522D58
%7DFD20FF7D2D5852585158525252FD1EFF7D512D522D522D522D522D522D
%522D522D522D522D522D522D522D527DFD15FFA8FFA8AEA8FD22FF7D2D52
%2D522D522D2D7DFD1EFF5258525852585258525852585258525852585258
%525852585258525252A8FD3BFF7D2D527DFF837D52A8FD1EFF832D585152
%2D5851522D5851522D5851522D5851522D5851522D5851522D5858A8A8FD
%38FF7D277DFD04FFA8FD1FFF582D58525851585258515852585158525851
%58525851585258515852582D522D52527D7D8383AEA8FD32FFA87DFD24FF
%A8522D522D522D522D522D522D522D522D522D522D522D522D522D522D52
%2D522D522D522D522D525258527D7D837DA8A8AEA8FFCFFD4CFF83585258
%525852585258525852585258525852585258525852585258525852585258
%5258525852582D5851522D5851525158527D587D7D837DA883A8A8FFA8FF
%A8FD40FF7D522D522D5851522D5851522D5851522D5851522D5851522D58
%51522D5851522D5851522D5851522D5851522D5851522D522D522D522D52
%2D522D522D5251525258527C527D7C7D7D837DA87DFD04A8FFA8CFA8FFA8
%FFA8FD28FF83582D58515852585158525851585258515852585158525851
%585258515852585158525851585258515852585158525851585258515852
%5851585258515852522D5851522D522D522D5251522D5851522D58525852
%58587C527D587D58FD047D837D7D7DA8A8FD1AFFA8582D522D522D522D52
%2D522D522D522D522D522D522D522D522D522D522D522D522D522D522D52
%2D522D522D522D522D522D522D522D522D522D522D522D522D522D522D52
%2D522D522D522D522D522D522D522D522D522D522D2D272D2D52527D7DA8
%A8FD1DFFA752525258525852585258525852585258525852585258525852
%585258525852585258525852585258525852585258525852585258525852
%58525852585258525852585258525852585258525852585258525852522D
%5252585883A8CFCFFD24FF7D582D522D5851522D5851522D5851522D5851
%522D5851522D5851522D5851522D5851522D5851522D5851522D5851522D
%5851522D5851522D5851522D5851522D5851522D5851522D522D522D522D
%522D58587D7DAEA8FD2AFFA8A858522D5852585158525851585258515852
%585158525851585258515852585158525851585258515852585158525851
%585258515852585158525851585258515852522D522D522D58587D7DA8A8
%FD34FFA87D52522D522D522D522D522D522D522D522D522D522D522D522D
%522D522D522D522D522D522D522D522D522D522D522D522D522D522D522D
%522D522D512D525258588383A8A8FD3CFFA8A87D7C52522D585158515852
%585258525852585258525852585258525852585258525852585258525851
%5852582D582D522D585258527D7DA883AEA8FD46FFAEFFA8837C7D52522D
%522D512D522D522D522D522D522D522D522D522D522D522D522D512D522D
%525158527D58837DA8A8FFA8FD54FFAEAEA8A88383FD047D587D587D587D
%587D587D58FD047D837DA883A8A8FFA8FDBFFFFF
%%EndData
endstream␍endobj␍19 0 obj␍<</Length 22912>>stream
%AI12_CompressedDataxœí½g›êº0z?ïçá?ÀT ¤�é´é½W&@f`␍&À*çÃýíW¶ÓIÖûÎ9w¯µ7 Û²eI–dÉ^Ž�_¥w[rCJs�ü³¼\V$q$+Å(~=èvÇÑ‚Å/Q&GѨÔî�PWKÞJʰ#÷‹øÅ¡·5T?^»ã^"O G×�QW‚‡'rÿC–£\tØ“åQ;ú¡HRŸþüHèÀ¡±Š8‚ÂL†Í°4ÃE³E6=?Á%ÄþOq8ìü½Ïq†W’ÇýV§ÿQ’£lž�r9!Êqù(ÏfÑûýÎ¥4´¢žcPIª�Pñ•çXê WU¬ÈÍqOê�ι)␍‡e¹++Ãb´üGìGOÄx#F¤nWþ-uÅæ'ÔÙ=ÈÖk�®8艣(Ãb„í0l½4ît[§ã^Côä
~ÎÕq«7ChZFßñó|ý �®¤Ñ:␍@1Þ/÷Jæ¾ÀSü7þt)}tð<ö^ZËŠ<è‰Êç␍˜£²0Z}ryøäY�ʪ¯¥Þ  8Ǹáè,*TÈ¡Oã»VƆ‹Át³…‚M3¹h¶ÀSyšf£]P˨“~v¤_Åè©Ü—Tüì*£+2ƒ<OÓäS}u9îJÊM¿3B}ÆÏ
A'rKêB␍£‰ZWÄxÁãS-q-*Ò&^îŽG˜@
L±øGBsɨ@ÎRÿZ¾Å]M³B6*ð,´Ç0B!*ä¹(›Ãø<Êé@ãSmµƒZÑÚÏ£i;‡™<S:�~Që`¾¾§tZÆôæyä‚Lÿ´ÿÕ¾ÂÈG#©¯uH«|b"š:¹BP«ýVYî¡Ib.éõtåõ­ñ¿ƒ&ÆuøAæì\éôQÑNÉ;¡~ÞÃË=EúïräŸ8‘Ð-EŠ’·À÷ø'üûŽþ¥ÄÎ áS¿"½Ó␍�§ÕþO©+L␍ëOÄ~+z'*ƒ �Ÿwž¨Dñ ½íãÎOx#Â�Ö�g�š…IHÍ®„ËØ@x0½
êŠÊ
ðM+zÖø?  ,#¢×ŠØ„)B¿␍qMI¿%ßÞ‹ ‚K]©ßê&?mø ƒôòêO¯!w;Þޠù‰þ=n•+ý³>é¦2¶£×²Ü5pK
¨¯ ºQF¤Î·¢v/¿oã°ˆw;Š8hwšNí;¼×¹Ô␍DEMŒu'ˆÖW:°Éß ŽFDÕVXÓERx–¹ú%Žšm�X␍ET:’/¢é}ïô[ÐÑ«qg$ó%÷HŠ^µÅzŒJÖL%�v³uX"ÌK@:í»8È;´À�þt%Xw2G}ùWÿŠ¡gO åÅqwô’ˆfNÅžMA™«è’^ˆŽž¡c‘e¢÷"zr T>K³°FR¹<(nþB³,‹ÖGšÉñjµû]T�Ñ~ýA¿áÛxö+ÊÐÑ“èÓ mEà%4‹a´ +d5X�üÍ@OÑ<,@…iPþØ9»° Kdç�àý¶«r÷ÿA˜³ëxçMø¿dôF‡n’Ž¡QËÄL™™’&š¼$²5õÿhÏ¡1ûS7j§5µ, ˆåzF{€èýì4zDå�úàþäøTG—×ëÑøï^·ÒÀ}J§1I°¦pá]Eƒ53'(¦rÍ6Ø
ŠÔWK±ÑÌŒQ�>Fã×ñž4[€¸
´ç&¼¾@ýk•Ÿ`’éu:-ïÂ}àNµ,t •NÍeÿ+˜�p¥õ^òxï¦Jßý³ã—óÁoi¸™áÏ�$”�ìÅ‘ô!ÚÃv¬ÚúÇx÷Ï€¥'­fñ;BL{ê¿�ôۣѠ˜É ÆJ—’•�L« ÿõ:¨`¥Óíbë$$ƒ(`°�•¦OµI1ê…b“¿<ñ¤Â\§ý»Œ 9ôÂíoö©Ù,ÞÉÊçwê¢ËËJí�ïWúÃúOQ®»ˆW Ћa9¬•œç*÷U}¹/ÁRWn~J­@hÒŠþŸ‘~lt°S� 2H ™+itŠG` æâÿ7TŸ¿)`l±Ñ•qÆÿ¨P(þ .PÙïAðhœÍñp$÷¾�øû«$ZŠÈ+ƒ,màÃà”ú‚o Cß­?ÿ[¬<|ÿõ␍èû¿@’»�æÿŽ×÷Å3—’Øõš÷`sþM¤¶ºËŸ÷ÖŸ@ÃúóM†•ÍRŒ@û�ª-u>Ú�¦^ô[Œ/ÇRY¡ÀùŽïW§5jžZò[Œ˜¬$Ë^ãjÈ#Ð3Ž¥÷ 4ÄÉJßF¥À²ò
»ip4Î÷Ð)`©ûýÐ|øóó`fîÓbKÝ^ Dz¦Ò¤úÓ‰ÔêŒ{Q#
çert» Õ·qpJT�p‘”è¹"␍¥QÔdNp*—Ó$Ä@li–1­qWO~Ú9n8�Görb·£ñC^ãÜÖ C©ÏxõQSî*ƈw¢»ã‘½‡# ÅfØ[Ý=(Dâ2ìôÆ]¼wg£TDTF␍YTZÑ&ŠuÒ
 ø6½�†!weÀŠ“À;Ó }îÔÆÝ®VC�Ѓ·Z␍␍F£?$ 55pu»‡ƒÇJòïû­MѤŠöÅVE=™+Ðj×QC»Š$îâH'-Ï>¡(D� ƒ™$%èjÊùî¥}ІZ#꾦©žÀd T6ªþƒÛ8—;ýfŠ8A³ÈNm$•ÎpÐÿœˆŠFQ$”Ž„Õí\JÝkù’4AÚ<—‡4DüšÕ•-N‹Ã ^™™`~mœ£ÚÊ™ÍrYWúŠ2QEw!eYè�{Q6Ú0ä�oYδa6úkb-�šÄ‰v@ˆ# •°GJ£‡,­ j÷D¶ufÅÌh’MÞ>ûróS�`Œ8"ƒÌ?miþl<@ ¾ˆ1c‘5)b8AÀ7ÿ@¡N+:4Äcé6›ÊO)z-ýá�±ÑévFl$í$|�ÅþÇÅ•�Ëc¤l>—W+™×PcýéŒ{¦NÓ^KÆ´›1áXöÒ SÑŽÏbÓ�& bpŽÉ90¸c(>P*KÝnõ÷ÈXÁø¬'Ԛؔvû]É·8ÒÇ&J ®cB²ˆÎHì7␍¹UÀÃây&À°®F¢.5¬␍ä �0ðr-𠨣™VM--åò¸%Ò` –nÅ~gØä˜Ûɲ!&M†ó|»®±&ô[Òï+©)÷[!+Õ:Êpº™Ð;<ÓDè­LÎC>Ï„˜Ô�ã4dÝ)Ï�×…
yÞ͵®,+féã%ªpa“ò-Dá‚V ÄæXÆ­Ãhtæþ‚�+0eMÝuï6ø,]ðéîûûPÒÐ˸Ê-Ä!e°Õ´’œk«¨¤I+eÝ»º�¢˜åþ¾ÙÕ`^½èè»®þ´uLþ))¦)é mZÃÌU¼ú¦âpéhCìš$¨˜f·3€åù»ƒ®ñrsh Ñ±
¨ÝN_ŠGŠü)-M¢R&ŠæLEÅþ¨kDÔGeü…}SìJ>ò¥U˜^Š3ˆžu)umòƒöëh¨„ežý
ß™4t4�Õô+¯UABfÕO “µ£XòTG°D¼í ;D?B«¦"1¤)êéعš&À|;0W€Œ‡wíN³}®Èï�®t$ý1?á.Ké«q¸º&›\¢ÕߨA;5^í5¤ÖdãaZÊ¢Èa`ơŀu(w^©¡¢Ý¢p®£þ6e¥%µÌøhæTYßkâ¨\Wì<OïÅ�ÃÓó�wGþB–:b¬]ÄX&ûÀTˆE…ÎTF½rekK±kƒŸ␍{^-b—XÖUϯ{d5?P)oXj;° èÍÞÀ̹A�␍Ò�$I{) Jìv}Š␍?;ƒ¼f.,?Ñ Ø`Ý|ØYÈ^N‘` C ␍D ØGͼÒ0ã²i¯ªU1÷h]·¬P€ø¡Ü@¡öQ„e›¨"¬ö¡u‡)…WhIú…¶¢ÕÀhkvL fnq*±+ü�øÝ$�yã␍ŽÞ¾vð9Ã;ä¸:’»;JmïXnŠNF1É´U<†Þi¾ˆƒÊ$¢}ÙXÆ£�>^p‘oC_Iœý…&G!f,/çà?—ÑÊ^VWöKËÊžÏÚ8–à7C­¢%«æ`v$�â{ŠØê ³å¡Ï‚ÝÔ·øH­cÄÊ(-ÕÂÖùD-ÆUX¥’?¾Hm/„™‘@J{ba¢gøµ¢Œ�3R-Ò¦xƒ�B‘`Y‚
µˆQÓ YŠÕúh/jÞbÀ.Ü
Z¶Úâ鯨Š6þD+
( Š·”B␍˜œï´�¦½;î¥,}qÂ.…ýOÁ¥¨µ“MvªÕ=;§´Ph1å=µ�#dRŽìņHMÖ[ó-øÓ«û¸Ô ÛüãA;¤P³?ôÄ-�®d^/&©ð£÷I␍‘8÷+ÔèJ’Ý51Q¨ ê¶G¿ßû#ªÕµÎŽc¡!(œºmèlHuaÉöR H£ƒØÖ«ÏCª/}ˆ¦␍—RMXºpÌ¥W¡.ÓÄê¤À±¶EÐ3$Ãs.†l·>¨Æv‘j.ö{@M˜¢N…�%êÑ{(!š²_‰¡p‰ÖØ{ñàm¨ïÃÚ 9VÆýf0a�‹‹ý¾¾)ç¬'âb¾âºÙ3K•ø␍uEE郎Q ²´¢Ïñ«»³óçDô'ëÝ)hg@,#›6f+ºŒ4ijÚÐ%ÈôÚxúÕU¤:RB£)ÖMrÈ
ZOmºšcÉw ­¶¬üG[Å\Š␍Ôí&_‘ ý슃²Y-è%M±P’ú(–®ŒhˆÃÔ`𤠕`mR³Hw(6ëÈØ¨,,üHñ²­¢ÎÝG6LŒ¿rŠ)�ÓWN£-¡†¨ ½�lˆ}ùýäíû(xé‘<^X±j ~ÅI(Šærr-��(±õ<@i£ç
›{ ¸¥çŽ‹–e ã¡T‘›%ôÓ‹»Éª:PÞå¾§Àë˜ÝÛâRÔyÛòÃÑ.B_Q& �¬KÑ�‰¢.U¹6štM8$ÞRï6‘TœpŠ8/2V‘á¸@“ÅH5�†C�nb‘OüÍÍÞŸO/qj””GmÝ&·d·{­-r·+akÅjºNÀŽºší�—’7TO­`ZªƒT´ÐêÙíï×  ÀFuˆ¼6ªïfáÄO³Hð-k„¬�s·»Ha³@8ίm‹@ð°¶d󶊇½e/çèÁjIÃÎGß¼N8é º¯«¡ÆÔy¶‰KšÕÏ‚â°ÑõD/�•%…&d†Õe¶«Õ1;ÍÌÞάˆpÞù-uÏ%å]š,9±õÑ–íwÌ–ŠÖâ•øS:í ºÒ®Í È¸6×wô+ãã3·â„¯ú̈÷}dˆ-?ŸDüÉt`OtÙá(ÈòÏ+5r€VEþÕ'®–uÒ]jã¤Þ݆¬[b9¿º¦�ƒ£N¿å!Vܪ]ŒEÓV‚÷`÷ñÏÔcµVžªWŸQU÷.{T<‘ûr³­È=É€l“órîUyb̼'ÂPcæAwžcGMK«Lv kPxó—¬|û¨®K¾z¦kÕK?½Ðµæµ¾Ú„· µFUÇ,ڮĎYG»8%‚G™™¼¯ö‚DÁ9:1Âí´ûU÷ØtPÛyÿ݋Ѵ˜¸Ý¦"7Ä9¡Ï»Kêáõò ßY�#ªºO¯ŸVQcHñ␍U�L0¼&GO"àˆ2,õ}”-Ÿ¦¦iÒÂŽ�ƒ4ÖyïxîÀÙ‘nZèP4"À*‹“ØÑgÏɃh¬ “›Ê.b␍wúf(a½ãÚìYõàˆ¬Ä‘tÝ÷}±ÓõR¥t¸“(^/èºæ(åÙ¬ï2ŠNÞ¼²Ä{\Ƭ9è¸s¨^ˆ¾i @ŒÀïµÒé¡xë sq)}-ŠZ²¸UÜ)Äo·ŽAìØäB½0mºº9˜ìc¼“üÜ+Z␍ìi8öñóX
_†júÚÛ)d)[òs•X;Ýéz—åQYÍ›¢õÔ�Œ ó +z´D'+ε)öÚ»–g,—KŸP1¯Åâj$ö[`Ø(Z‘† xÕ¨àðk‰©úÌkH¸ÊêÉwN½·´â0Wƒ�áG¾nÃEgÓŽÚRTu[DUKmýÕ–úÑ¡øAû毣h¹ŒŠCôX=£±RÓ3¨(,1¨Iø´6öGG  EA±’Èb‡A“æ>ÄNE?˜¥¢L¯ÚÂ�ŽdÔDSŠvp¨„íŠPöŒ fŽ(mÃq³�ºwЯ`O�Ñ �ÖÆCïäw|g÷?Ñ™ŒTàYo*��Õ¬‡Dc-ëÖ¨þrÒÌ5¢h;¿19Ømêk/#ÿ`î3?BæóîUùà@ÈV$ÔeÜrr+û–Onß62t&y’Nn·GúÆòENq¡Ã/Ö¹íëQ©ò^ØûÜ_¼Ü+ïôÖþ–Mn^æÚ±·¿KgV/L,¹õ¹Kœ>b©vÞ½½S±ä¸xK�ÜWbiú„¥3›q ?+'.ø!;<�ÞU>ùí³·-®$pBî1×{ÜH¿ÕäüG·Œ·ô~]*EÙÚl즧‡;G…á–°¿qGÕäGþ¶ª<?Ò•ÇÚÃumsw³É¬íæû*n)ÜàÒÈø…�¥n_bi!-Ä’Mê
�K@Ϫ±T½•�%:ŸÝXbTê Á%̃ãS—è[ zò¼‹²UØ_úa ÀàQ␍c/«vuk¡b+Ee†Â»½¸ÿ
?÷ºtkå¡¢␍äx¨(ëÃ[å¹+ÑþŠàÕ@Ô\¾çv.âq¦µÂ`dœ“§¼”×v(îX'·öb+Æd`¨¼|yÕwƒúª¼ÔÛW6¨úh„½Í·ì×Ú€v„úš{<wƒº¿Ømd�¡nÄž†‹·çŒãp/6W·Šå§C'¨Éõ&¿á5·¸xûxšµAÅ`0`þá‘®•rgŽPj?„¥>·~î•®½7÷]¡®°üC•°§Ãpù‡½·§<8�µöuÖ¯h^yyb^W{Eêùê*†JÀ¨SË)·™6†
”Ù¨Z§öIy©Üž#¨‰I‚â_øu“v†:Ø?06ÀÔÜ)½¾èµ©¼
̽3ÔÓêÚâWn|b@0àáâ Tsƒº¿Íö™Gg¨|â!¹Þ½9u„ºPÑYþ6Àæ©=º(¹@Í-.g…ì¶ Ô‡:]“¯¯␍¨h4&À{K›+ÇRûÆêÞ…pë:Ö•tŒRçµúüY³0Ï:¯v¸º“"ÀkÃݯ÷4–ÍìP�N_T¨é¸m¬ù,E=P¥™‡ûX¢�{yg¨ cáø¡)8B=ëJû®PÌõ5H9—JÒWÇ_cg¨GÜëq­¶s„z}Ð90 ¢¹±¾:É]¿¹A­Ð·ôkÁêqzñºU_[w‚Š„ÍíëæÐu¸·q©>pƒzBߥ·K.P«É»A)c¨Æ>ÜÇÔõ«+Ô ×Ç%¨Ï9úE|K:AE”¶pzÓù,.Ÿ¦‘üúz_w…*KÛñ7¨'ô[õ¸‚¡bJ³sí␍³p?º8p‚ª(§éEjƒKؘ'YX«rª¸0Ú3 b•c#VTÆ\™F€SPÏ6ã_¯Õû€º©ØWž¢ü�R¡~ÖlP—ߟÞ1TÖ˜«¬¸¤«§O{jzR.ž¦µ•§<²c¸ZýA¨ÛñjÊ€Š$tf˜m¯¶’ª„â–Šå#«\”’›Â邚™„š[^Ø|Øß¨‡1Ô[:kc¨xnŠ”m¸?äÍê'�º}s|l]ÞÍ?Ú2^ïèý·ó²ù-;êÅØb¿a{k,Òìx%Ƶzçê|˜g++¹½U€"N:.o‰ÊQÝ8«’+õã&}¼Ã±øí¤¼ܦ�/·y··»ôqë(‡ß‡eú$v'¸U¯Òg̓K··uúªü9²½5i6O)úêv1æRý‰¢¯wNâno³ôMì‹r~»C÷·(ãX^-0)µöéÛ›Ø&ykå8ôö�¾ýHo»½=¦ï–
»:Ò& œÒw¹jÙ­ú9ý¸˜q{ûƒ~¹\³½5!í9O¿üxO¹T.Я7ëœÛÛºž«\ÞÖÑ¥F µv”u) Æ™Â{âò¶±È”V^kno¯˜£‹…Cw¤5eæô“í¸To%˜‡G+Îo³¯ýëõ�Ñ£+ÒØáyl5qˆu­8X:ñ} wwcÔþÎyk—‚ì¨Ûà8¿åÏHØl°n^’ë½KÓÛrzíR5
Aºm␍â­ëdIžI¶µ9X6oÕg©¤‰N›ý†E¢¢l3Ë;™Ñj¹v½�Àh屺AÁ3ºV.QÍr¹”9JBµ«�Zím¹‹ºÃ€&ЋÜ*QÕ{ĺtŸ !š9ú«`gÞ�±=¢ö}C7l3�ÍFXq¡
ÆPñÜ"º•vuó<­Cg'V]Ö fÛkË1Ù*ÿpïu¡ÖÊØ ¢eML×®K.PAi>뜈nPß< î¥ V] µ²²h@U†ÅäP‡ÊY 
ûü}ûx]ƒº×µ`x!n†Ê_-°2~c(W¨˜æ\ ‚Å vų3TþቘQfÀ$÷XW¨Ø´p…ŠìŠ–�ÆXr‡*œ^Ü»CEJŠ+† ÒSêný˜˜ÚÅbJ…�¿©ä^ô.‡…�Zt=P“üóq°r‰sRÉ␍bç¬þ$ ׯ`ί>•U./KX1$rFC®Áû;Lê†IéOÚ܍ІêO˜ë-ÙGm\š|w[ç+2ê Òô¯vÌ2
Á?Ì./ã4¥w6kM…p¦÷¨‚¬Ë.¥<ÜV]S{7çðseYýï+† `sêAá§
S}î©>u̦NoU—Õ�Ô‰LD,M8c:,[phF})Ó–*ˈ á_ ÌmúÀ»[z—>¥ª)ò¡¢”1¹M&.Aü8âñ‡:Blº;Žð<fŒ�¬žƒÔ?.Í6’Âþ}â7‡õ16£Ôî“Éæ/%¤¥Ïô´sˆ½ƒd�ëÉ�ør§ˆõ”­)ÙâEöÎ4¿÷0ð¦/ƒ¸T‚v§/ú�Yx€}oÔc]°ïG­�9h�vB½67þø²J!Jž�B©�‚>~h� 1#U4�=Sz§-R(±‚iÓ•=R#ש=Q�?TôaW­úªÏ·vö4Ëqgö$–‘Ãà¶™£ãƒ#scŸepéEïÁ‘éœZÙ$6ÎhÞ;ï!åÖe}2ƵBÆåLó¯UZ~Þy �frÊl„× ½œ3¹ï­Øy ¥ÁlU2óÀMÝ}áF£‘F7•‚t‚&�ck�¡kk®M™i+2ƒ l°_FíÄ}V‹zTC«� ­�WA <IéâÉqo
‹5öe\ÂÛTœê¼w™Uô¡vŸx¿' Fh•‡–¦R¥8î1<L}Kºö�~/SO.Ã<»pÒÎŒV‘f�þkbZ>Å{Ñó–B–e␍Æu?t[©µI«*iÌðžMÄö´®T�'¹µÇˆK«û”*“ÊÁ8mÑ"|b~øÚlĽû„␍vè[z,:wKWóÜt=kŸ½VOc,&€ÒÏ%OmcÑÏ"0O£�®b±Lë7ói�–~H·NM‘¹ Ýšu�ñï˜YtN´ö¾úu??¤ù(|a†ù^Œ?Îi6éiª'LóÙŒ¶¾lÖ-[ºu•GvÍÙP›UÑiíïǾuñ÷Òu�×ì}´»³ï-ÓÌÚ·£Cú\˜{î£=˜£0ætÂe6?�3…[Z?:ž Aþ–!‰åðFP�
ìoð�«„1UuG«Æè‰fxxwÆOøöoáÝ×Ù™Ñâ*pOAÛìÇâ—óš5Úz,NÆ#ÞÕÌ(ìÇd¤G�¡n~pèÑ��b58‹ûêټ û±0’Ä�Q~Øt›QèÛ-KŸF‹AE�-œg‚÷æ#
ÈBðã ¸(ðá(¹ê4B4šÐˆ÷Óì”ËËÆB`%ÞíxeĬ•~Ôæ0Âa›5i�Á¤.¦;XD{Ï_®¡:!ƒãË“Ù�ð…[Á~èI|…dv ¾¬œNiËš…Ù{‡Vfw1ã|}QÜRqa!�3ÅÓéÐ;ô0'¹æHÈIrcˆGÁÏaàïÈÅ‹t‘Y�Ñ£Ò;ä¶o¯O\‡…�¯/„[*|ѳ8BT)p`n噇d_eÍž[o¿žeªÇVØIdYon²áÜ%.¾�C›oǃ �]V5{»x>²©ÙÜöÍr̆=ÒSÓžœ‡ÁQ(›!l¬¤µ}Ãx»␍íZ²Ûºx„×EmõôòˆÐ’GÖuqJ¾Ù¾ÙLÌBî„ Gö1 ÛLîÅ‹˜u!4␍ÉM�!-óSŠ3¥M¬€Sˆ@ŒmåC}Ò•]?5!Ⱥòù¬KŒ¦é:,~«zqÕ´© ßÊð,Þóµ‰ûÜÝ÷WSîn˜ÇµwÞ3ïFY=Ü[¨5ÝKëÍ7¼´Ðš7“Јy˜YÝøhæq[+.;…þ␍­…êŽó;n(9—q™5›™JèŽã½âÖ¨–UišFœHLš�÷×3oO˜„␍´f³Ì¦^~PÇ,»Fw
]±ÙZaƒìdi^›ï$ÝÀ´É&lÒ␍ž¨w‹xcÅG½¸¿™Yºá¹…3”~ï%Ý )é¦Y„݃‚ÖBI7
9´¹™¥Ú×_›‡˜ ¨p§4߆‚ˆïVH<ôzIâß�Œ«í�␍v9¹©ÑÒ„'ÌaÒ’^{Jê$úÈŠ‹ÕËA–<�e�Q´f�ƒgA&#PDWÞ¸ndÔØîo␍‰«¯žSï Ckþ×ðuú ÝÛ NÇ�{o£;€š�gÎ0å.l|rUü][±­žzC³FU�Vt³Û{#ß·¡ 1MzdŠ+?âÖ¦sr‹£ÙA¼
kñ^Ò¾>Š ÇlÛ›…÷wóÐþŸÝã U=ðú­yjÿN‹£›çµ6¥öožWf!;—eM\8™Ï²␍;‘ä‹“™ƒ“pwÜ={–h;ÿ†×õÑ{qt6ÌB:üúè±8ã8ºÛ¾>ã!� —@Ã2ôäi¤û|B³ŒÐWyTŒ»›¬›˜=íœé¶…¶Ä”J°Ãn-4Ÿ»v 3¹·ûÁKòZ‘–óžMë.®§ÉzDÿtÚ†5…÷ž>o÷ˆ=·>™ÈÂêëôç3'3Ž-Ý?¤mË”-#�ÚÕŒ{ðZ¦Ì¡qH¦9DÇÙQPºoÛ=Ø¡˜Ìê³y/S>ÆSÐh,ÔTÖknBmÿ Ö|h9„3…-=,¬„Ñ;ì�Žf‚~À޹ ­¹°}cèékc¦ ßøKÜ'wo²�É´¹±yŒÌìÑFÇÛÔêŽT­ÎÎÛÛ:kïuoÅze±5®Ö
K;¯µë­ó*Îå0óIçKzæòELIK3¥ó™#´&sù"æc fIçóÎå‹©‹³¥ó™ :äò™•gJçóÎ勘SgIçóÎå³*P3¤óyçòEÌ©‹³¤óyçòE¬©‹Ó§óyçò©ËÚìé|Þ¹|˜ ç‘Îç�˧Ž&\:Ÿ5Ú#O÷è[x~
Ÿ{ØW€>qC·übÅOdoÍ]␍K¨Øw¦¼}ªXcvñùj¨øu��§ŠÕ!5ª´ü¶‰4ŸÉP6‹Qæ•èòç¸SèÑš_”—Ë'2V$ñá„£kÄ×½WIŸLñiÝòstyôi`Ó¡Ãæï…;¯è`³™ŽÐý³‘w|‰jx1©Î²ÁgQ ðøfvoÁàžmƒsçñM» _âä@iw¡=Í“CªPÍ(¿´»àñ%î¢pãb2••‚ :h¢X�¯­+ÛÔ
ìaŽø$b“_␍vìëL œ÷*.Ôü'Ã1éuBB×¼3*C9Ú�Û’õr[<*.Ž6«¯)Á)«Ge!¦j ™!GÎ}©3§ÇÊGF~:F˜œÂ×q¨„�œB‹B攃"ºL>.÷9É5 Ç®fûEÞïyEÞŸ]êiŸ9Œ¨9…~‘÷Ás
ƒÒ#æŒü9…6¯§E� ÷Ö|2|‚vŒXÒ·î[ð¡‡éŒA˜ÖÜ÷>¦AšOþOH¤q³´fõ“Ã2-AT$Ë'}'�š»ow;$-l,uÏCn¸4€çÆÏÄ|ÎøÊê�}'{Ð)æ6€=8ÚöI>1ôj£óž4nc%|–¶†´Ã9.6WŸn7´ø¥ì¹Ì’Y¹ÝŸØXñ0Ô\ÓþùÖ&|1ØáêU÷KØ›Xï\ô4$Þ6¤É(U«æ•B¯(öLÝ—áÇÈ ëS¦—UÃt!hXLC98fuÐ'WÏG¹§eM'M­§ý8på}ƒçu)à‹ªÀ|ëâd¢´á|AlÖ]  ƒ Û3 øçèYúÑ9uìV(ï�GŸp�Å|¨ÊË{ÑO Ö­pÞ»eõoŽìÞ”5‹÷ÆDi½Ã™½7ÜR1¾ädéY„M@«â0¼÷ÆÝ/Ð;œÙ{ƒãã!#Áóázo"^ç@á|¸Y½7(Ž39!§�K: à½QùÆ7WÐÝ{(;H×l‚B%y^dlŠtDËôòI�␍¤H¹Æ\DÂdH/|&ÒÕr˜Œèâ¶oò’Y{vdDéºF\"(•bš3¡ †ðKcCÁV_ç”)~þ—Øž>)~A2Z=9˜$bzøé‚„�˜äæ6µ´'ÛÂA`®Ú7dá™;E˜Çü·.¦Î̳YkZrÞ¼3ó¼Ã®ç–™çKióÉÌ#ÞÁ‰ä¼ð␍ygæ…†�%3ϬC›’óæ�™7i␍Œ •™çj¥)¡sÈÌ‹˜/tràÇ9eæ©‘÷öä¼ygæ¹Ìͼ3ó|¬5·}¡½[y‰ÿhÉó‰_z M1µÎ¡—Ð;)8¿
°é娘.oæ¡càV&â�§Ø,Æ␍YMlßî8úlpC3€[Q™Ñ¼zšvyB…X»pìy(Ä´ô­5;?VŸËÞ8TcðãÃL‡Ýê¾Î÷U¿3^‚‡B¯~Ù9(€Ls␍…^ý
œàꡪ—�¢%B“Û휎:Æ␍ù�…ÄÄÅ␍…äGçeív.üxëº8š}6ÜZ#ÔÁ�I›ÏÆ2#œXBÏB›Ýf0Ö<¨K×ó™ƒâðn®I²wsM’½›S’ìó×’d™…ô|’d¡¡ù$É¢†fO’E­Ì%I¥Ñùtm�tM#Fñ8
6Pü’5œÉŠI~¬+3»ÁTacÊË›9VÈ))ϲ¬‰²3¨uošWIy&öTóòþJRÞô¶g¨¤<wçý\“òÔ ŸtÍ™“ò"ødØWïµ% ×ºÊ(¢ÜšäB°ì+kÌ…ÿé÷ýö8‡I¶œ<õ‘p*Ò¾·�B;žQÇFŽzß4šÍƒýeÿ�‰ˆkª<J§ °äuò0ì¼FÜrqý³®m}²�gn% sصw¸«¡Í—ð$ÍÊÇ/—ò±TûǺMe£‹×ë±µ£u&–ª\Þ¡‹×¯ÐÅë×±µëÝúvŽŠ–cé£z–ÎÜæÕÅiSþ4wZóOY¯Ð#afÛÓ’vwž¡Í˜¶$À␍W—dó³Ö´»xcéòÓ5Ù�O<{¥Ý½¦]¡â›È] æqnVÄ=ÙïÕ+í.–u‡Šn"סr÷º'ÀmÄ^<®•»Ø¹4Aµ]¡‡n玸&ûeÛk;wk·T´¯´»Ú5b½§ðeß=Ùoù3sÛpƒ*z@Ý£‹V­ÓžÛøq¸è
5ö¼˜»qÃpÊ3Ùo¡v°b›ZÄ·i Ó’Ç­@åÎ%[±[Ñ…³ÍX€&•qýÓ|Ú8µ¡¢þ4�‰¡z*n[c½|Îþñ½“ÊíùJÏŸo÷ÃN•\!wz␍\ýTÎ÷;½vÏ¢v�èrO.ò½¢frÿÌÑ;8ÛõzÖ>�íþóº^Ïiú‚ºíÎWfIÎ49ˆŸ*þ·­Xb=îv³_«Àmâf=×FüïÂó»h%È#N§ÁM�莕 ˆ÷¹~"ßÐïÇüs T™ý¤î·òFáÜûœ¬�°>›‰}NV‚³Ûn¦Ä>§¬>WzúÄ>'/¢ê žgbŸSVæ›ù&ö9‘�¾·6¿Ä>ww÷\ûœÂSLz^‰}¾‘�óIìsÚçqÙÅ�%±Ï:¯$«ÏcceÚÄ>—]Üy'öyd¬Ì3±/è]3&ö™âýõ¬>çíÕ™ûœ'â�škbŸSŸÌ[ßsJìsÊê³EtÍ#±Ïiu¾™_bŸSSÚfñûœ²úœ2VfLì›iáûü�6§Ä>§¬¾°H �Øç”ÕqÉôš!±ÏI'�س¾gOìs’=¦Ez^‰}N›-ÄöœkbŸµ�_wÊÄ>§¹vßX™:±Ï<KÚÎŒ×z3ebŸ‹í銑)ûLèÐü{BÙ´‰}NCŠ˜NNrÓWQ·f´I¼@q8‘>¯øê^‰jZ'~`ÑlFMŸ}å+7l*Ç<nñóS9æt‹ß–Ã~Ž*G0TùÞl"Uâ„t¿,Ï7U? �üîì] 6}m÷å×9ÀßëÊ=¿»zû42‚º„±õI³Bƒ
TåBW“‰[*|f¬&Ó¡Ýdš l²ûÌ\lOÛýS&Ïnf×8›€úzÀËÿ4Jóž‚™/ÿ#^¿ûÿæôÍãˆð™.ÿ3éi÷ÿO•r¹ü/¬rÊËÿœ��öûÿBæKM^þ™8ðÜéþ¿)"H`™0]c¯åx¸åz$ÏÍ/Çcp4Ÿ3ÉñÜ/fÎ&:òŽï0.}súœ"ÃFw£‰Ÿù– #×Hã‰ßkûÜ#C§Çáû|è‚©!ì䃴ë}c–ý“D|ÒœFI�–•Ïb­…Ú0B^ýÀùe^!ñÐUÞÛ—&Ô
[ó µÂgÌNi€ó QVA1ç°“‚[±¨²N$°¡0k {àjh*Vœhì\+߄δ7·æ~Hb�ËëíÙ¾?¤øD¶ïÉ7*xÚ)ÐýÈzŸC9´¶H°™3Wl^õ16Ì�ÙØôÚœ-n2dû–çë½ïÈYXžˆG™21æf®—;ÞÌïrÇ[
Å´RàV¥Ü»˜Qø.ºYt £ïðÑ0␍ÍáÒÐt7|[íÔ�G4R¸°X`‡ŠY6‹A'›äGxæ�B1�ó~Š{ÿ#SÌWÿMÉ�¦¦æx×·ß½UõYïýÓTu׫ÿB¦þ¸ÜûÖÄ�òÞ?‡eÍzõß,ãšðÙ„»¬ÏÞšÿ½6±g¶ïT÷þ>¾}ïùkæü2D õùœ¼<Û—Yp4-u‚—íË,„»_ÞÙ™‚p.ÈûðMÄÔRï␍‹`Ú†9¿|"ºpC³eûâVÈê9{¶ï�çÙv;xõ “}?µèA‹fcÏ¥šŒÚAid7Þ+š£Ì)ÎFïÁ�!©îñ^•û²æœKå•-×p÷ö©”ØÀ‡ÖÚbíÖ½ {BkŸØ3@"Õ=6ñçd{Öo;ÂötY¤ŠqÊ#bÒWc´» [ž¹Ta5ÆÙ¸µƒ�Çó8~%ʵL'Á[wq§È»-Sî¡|†PˆØÎ¼÷ÈL›åT­I¤Íí2ÌÆÐØÊuÝ�
ªÙ”©|€u4ðÁûzð‹R]w£ð=}s» úäyÊHà¼[ƒ�·²'}G€ê$…¡Ü(5að°ð€R␍¯ÑÇN,Ù¤QŠaçRÜqaIŸ¾ÒÔo–9eÈ,+TLÐÖ«éØbÁ93ocaÅ53O¿Qîù€Ìûa¿‰/i\Mçpë ž­öè•…øƒ±Ù7¶DÄ÷Ó+W¨+Ìa½éµåš#`†ÂiéÊ4\kŽÜp±-¹eæ û[_K=}¬¶Ì¼„)0¢ßgBò&ë
•®èS¨¹Å¥ËûêÀ áz¤?.Ô†¼;Ô½ÔÛ­+ÔU)žo›]ö”@Ê êñª+Tex³s‚
`H"âÎKúÚ2µRAƒ�¿©“‘(?¶zAʽŽ{}‹°q)š[üz­ÞŸù6™m«Ô§.œ(Eçy×¦Žš‚,â½ Lm¬¸¯YúÊ :S5Øv”ž*s¹v¡‚Œ±šmÓË/ÉãV>‹:ìx­[Ðn␍øœÜ+³,0y5ï3„‚*Á›8âp1M`¿ÓSÅ÷SÀ¥7ªÂnù¥Ç­¹`áÒãÜ"A#¶3ˆQUÈ0÷¨!4Bß@ø  € “{óMð@Ÿp9UO Ö-÷#zÂòͺ{­Ú�É8\«îp¸'¹m–FÕûœÝ žÛ‡Ôh_˜iÕç[ï› ›àÕùl=¤çàO«ÎãJ”�¨±qÄí`³`)‰A� ªKÕ5%ÑçÒ`ùˆÁóÖü¬šªg X0š5…™Üj°_Þ£,lÄÚ-é·d2dé‹ '&¹5Îò .À—ÇÁÿš3'Bÿƒy`>…�ý^»OÒEI‰�cs|óì@¥sY%´™6$[{Þ*]ˆ„6al[N"³dz5|Žb0ÜkDtºçÙ¹Å@U·(P^Ò°y‰¦9´íJ:ž/8·Ô÷ÖŸ‰9t�úßT¡À¡Lè3µæšBÑï[ ÓZhÂ÷Bšo6Q(¤Íë|hÍut*¤ydÆMd1[7‹§LI ª6šóo¦HI´²§{>bÄáø�)‰ÖN¸ç#Fl÷I‡LI š�¨-®6’[á.tÚ[ ‘’è"ö&ò� ö)‰þK�[ôC¨”D”Nä#Ú¨°)‰�ÌCûöªuH¡2—|òÝ-é³çqMuY¡Y
üÅË
ÍfÔDnãü.+ôs?Ìé²Bc!ð—3\Vh—ié²BÕ¥:íÅ€A/+ÔÝv÷²BLi¨[÷²Bsäý_¼¬ÐÙý€º%9^;ŠõjÒ¿S­Ì·êap³^x¨‘ªóm‡a£í\/<œæT«).<tÜ<Nµ2.<œ)*ø…‡Þ €‘9œj…/<œÃ©VA.< –ï9󅇂œœN=Õ…‡[ž·š �Ù.< ™P6í…‡v²°Þv83í…‡Þƒ‹xÞïâÂCïÛ=|�á.<ôQÕçpá¡o0ì|.<ô¾L•i³_xèÍÆºªnO�
{á¡÷Êg×Ó¦¾ðÐþ4qÛ¡£}3Í…‡ÞqY¦°ëÙ.< �J2� ½o;Ô×›Y/< yOá´Z[±ßv8é žòÂC÷p5Ì|.<ôÞ�QeÚìzfÇ�Xõye«¹ßvh¶fºðÐ{Ÿëó¸ðÐ;ÄÛÕsöÂC·d4óVÄŒ)К�±HŸ” ÉëÂÃR`– urs¼ípÂg3í…‡Þ­D\ï)œ=åÂtÛál©$7®ºm·9Xho€ ½ch#úù:?Nwá¡÷É#†á1ã…‡zâ—cÆvÄœ´<jòÂÃ2mzßv8»ª®^x8‡tì 1qçpá¡ÖгÅ=±¬…½ðÐ÷ŠBa3Å…‡^‰Ï_ªí9û…‡ŽD¦ßv8›L» ªü˜÷=gºðÐ[ù1E?Ìvá¡�p§Ôà°ÞA× ÃçâNuá¡c+º(öÎX qááô]N›ªQ3$g¾ðÐÂ�·0s¸ðP˪s¾íP•i³_xèDE”Û9\xèmÝkH›[â•óm‡!|�V¤Ù/<œÞö uá¡›<$·Î+D±ì}ÛaÄv´þÔzßv¨ª³_xè�¤ë¼HOqá¡÷m‡~zZð$]ÏÛÍNÈ™.<œF³™âÂC×ÙÄ@Ö­o¯Ö|.< ×9û…‡Þkv©Ú— i4©»Á3÷µB]&&ÂHtw°¦ÙÐï7ÅŒÝ# Ï<ä½w¼¿5‰’¤’˜¨j`syÁ�—␍`Ù§MöÍHÀù z–¸Ð/«(…¦lÁIu©¬([—��Ìhãp—î®ØÕ­…
.‚²ºö“×ç¢[~N®Ä�×(¶úºßŽQ›?v“ë[_…äÆúåCòºó)ÓÕê� ]ý‘.Òµ£‹]´ÔäÎ1½wQHÓǧuú¸÷þAŸu¥6}uÂèëƒÎ-}3l¿Ó·ô¨Kß¾nŽé»ômœ~LÝ$è—ÆÂýúzÿN×/¹ýÆÝ¯Òo'ñ EQªeø,¯+c¦ `”q]ˆWó+HO¸¡lÓÕt§µZxß¹}yüˆ­­,ߟ/ ëÝÒòùÕÞáJûsya¡�9�/v›Ë|aå¬ñã¾²±¦%%ÆÆ©ú†§§À˜Øníúz™^’Zðø\v'êÜà”×á%¸ÇÒ¥ÞtA¦zÃb±dÃFBÚÞE‘ŒŒ¿è·�ׄ¢œ¦“Æp'ÆÊ'î“Üê]+•èÚ{ó�Þ;;í␍_s␍”LSn}U“›Âé�©Õc’!yAWoóu|ÿ!�9“R6%ÌÊF–« ßâ=ÃKkœ±ºÉÿ]‰%6NùX:³z‹Ò€+±¥Š�‰¥;;èÙa,y±pŠr�OÑ‹íXz—kÅR'÷û±µ¯E«ø%¨¤Mîe“Hˆ.1kefÀ”;b†AC«ï¬Ç<Aµ*{"À·«“úøØ‚o·_Øü§3Ÿ ®Î-z#šŽSüIȸú퇴5öàûêW’ðÍ~R}RŒ§ÑÏ´úó˜WÛy0ª6?¿
t&{@ïöäãáîÑÝÝ ÈƒQAíçV>a¼ÀcÐ^l"0¦wâRyS{WN/ØÒãͶöâ c¼�ìcW{qÆè/^aÒ–»tfos␍?C`Ðc3ô½rÊ(o½w@ÎSk°¶='¡¡Åû2ü1†— þÉmßÄàçùΚÞ@뎘Îk)Tj␍Tp©„ ’‹ÈÖc„ÓÌïùYy¤Sx-†Ÿ7¸Ý52A™ó'.srõÉAÝkÀÿâÆ"z›T�Î<§ÍH{ÓÀ¼ÁìçÓ•Œ¸±Rüè¯ÞÔ6ªü“ü$ÒuïþÂlÝj&®¶4ùù&`˜G“šˆÅ]L
a¯¶³*]WZ›1Íö„¡Ý3_³ÉJjy\‹ï°‰n}Q%²‘ׇ.š‰¬q–FXJ^ó}øy“Q©¿qO3�マ›ÆC4âLã•Ý*°2|9í[‹Çm¨óûy‰›Lã~ÞgÔºŸO´öíÕ ¹¬¨Ç[{~¶8Ó»×W¯ÕOGìÛÉײ:šÏ^‹®$pºôšx/·sµ³RWXLn�­Ú¸‹b2$õÈVòƒø 5�ÝS:Ô¦J2£WšÙcvâðMd´o-Ö(kö%Œpôƒ·u�¦�ÝÖÖ[ëùÛôÂIííd¹€Zn¥>ÌÓ‡{É,Ì×K.Y½½ßß=º§}VtUÑ8.ÚâÓ¬®,|OóÚKmŒ–•{t!s$äÝ},qúW…踈oeÞÁº}Ktº[±tÿâ Ö‚ÓÑ
úŽGfó�H>`žÝ8æ=Õxù©¿�Ä{PÍ<ÂWœ‚Ÿõ‘F û«(Üö ‰Î¤*:Ñ]®VÑù S¨ñUvu'ö‚g©”)|àX¦™Îýˆ"ίNª˜ÄŠ4È´ê¡“G˜Û¾==š$ôîÀä• Q‹Y¤¬Ö飖ßHÃD£9Ê$·ò·ûå·ÏÝ–EÄÓt¶q„œG �ΊÌ^é+ôqïN×ô&Hö;!A¬äºù�ˆS,DÁ‚ûQê.ôkÌ~ºÆ £e¤îo_"¡w±fs|ûÂXm·6†&Œ"ijû†Â7¡ímä‹/ç'…Ýý\Ūÿ¥ÒÛéâ)~R\‘+ÅÊ¢”:¨Þ•¤Ë�÷kfÞ²WµÂbv«VXºl•_÷×Ç ðS¼r |¾¶§©h•á¯âÚÁ™%4¹qÞ¯ô,’oii§Xýz.råJ}÷ºüú\Ý?ï0;_»™ÝÊA¯3¬UºLIU!øJGSê! &…D…1n`VOB]V“�Çöîõí�².”ÏÝ«q¬�ÿÚ¿<®Šâ*U}l-´1»aLoY~)##c9ŒÞ{Ì“ ïØ
EmÜÕê£fgýðóÒ{ÀÄmŒ¹°�ܯÄl†"f(äæClwØSÏ£¨Õ“˜y␍ù•[,_Â¥Né3¿0@_tèíõ­•)A¯-UP¬zeooós÷ºÂ}…F<Ë–˜ƒXŸ'¥�V)~¿´jµ[␍Ñ)�o&‘èTi®ú\ûÒ•áunûz´SîÔV”�ÛÕû¯y_y¨ÕSû‹»gÇ€~©ò~1¼ÄL9Œ½¬VèÖr¿ìY¼0æzÒ/
çA`L8_û.cÛ‡­4϶�F?åБ° :úÈ␍À„½Óй]%VÑij6¹·æ*Vm2uc#=Ú¨ŒÅ½c�©WÇ`loíîgc
HÒÊU©ÊîïªB3UU^‹¯ë�Çý­½îíý3y¢ÌNf8hãAZt‡ÙØÞFøÄ(œdû™$Π\.}®öŸ+T~uˆ'‘@@¶ŸEÎ!¤ù�yf9G4¿1»Èm°„
»Z¶nêkU'ÐÄy?¯™&’~ZèÚx/k3Jù<‡ÀÌ*å,ë!(ÍXÙÃ&FáüU™ ËÚLªŒ#®Õ­ot‡ð$¹‘õ&ÐÀg5rÛ9°ØŒ”6¡Å˜©E v´‰_”—+q”CF^�,9|f^)–bk§ägb­ÄÆÒÏÕ+d#ð^¤ä@»">6(’Š¥…ô«Õ(¤QámbêÖ¦4ÕͶJN(SO#;é#'Mšô�N, 4=¬ôKgç;/µJ6û¶{½þ#^9xÊÂŒÄv6¶k”îHþ2&!Ó^î£tloS°<8è[içöhóæá:V}Ë�µ�Ô+œdÓ16§…Ê6ëk;ëÏíz…º|SÊï›ýFPÍAµi¡•*ìL™A¥ (ݱ¶žVªN¶¾§ÆyÐQϸ¬…R \VÖÙà[°Ž”Û¹(Þ QŽGh3"¼°�¯Á[{ítã-n ~z3*ÍãõÆÞ…)W9_�“ÁÎŽV̇wM,ˆG>£óÑeîÅTå’E‹,,�ñ¼ÞtùZ,Uo¢'t,õ5¸#Û4É‹…u´¢œÅoï‚ꎬ·8r¾ëßZo¦ {‰ª>›6àz3+èªøVýÜéeÞþ%:B/Äj+§þÏ®7a—:¢ ø�ÙsÀ ln—*ÞŽ-úaŽŽ$âÏmK�Fi3,ô•÷•Á"R®€„fÝièÚF¾“r5“fee2DaølJJW#!§w›�5›|6%“©apó,^2m•2À€Í”„Ϧ5€ ÅgSÝLiAø, “¡½½Û/É`xµèW\³\¢h¶zWz8ÝM␍è�ÝæÅi­²�Ìî¦äâjå±6zÙÝϽ�î¼_Ö«ÊKãl}›¹*‹­qµ²½Våj×ÛùÃYˆÔA«¿pg¡«¶`æí¨wRô�%=g�F`gJÈÍ ìöœ$îß·¤±†­Zkóôh8␍ÝÎóŒÍÈ0Sº/gôÜN½e0©kOáO›Ê•§ƒF—wöÍ&®�¥ñW=·®&žÕŸÆÌàO‹/=QÈwv†~ž‡²eœØ][¤íϬJ£r;ÿ"dö¯¤Ž˜m'Güݘ„Œ�Às”jPŽÛ¾\{Þ½¾ùñHÎáozì`±J [¼ä‘ Õ�‹ÿn­þÙ]«ívÅÁÌ(ü␍JÖ†±méV␍­Ð<§ain5^îÄž¾ÎƒÒ ¥¡o鵕ƒuiÁ–îÅQ␍›„öþÍÙ×6$ÿòìã©×�÷möñÔ˜¿<û!¶‰f™}<õzD×_›ý0;…3Ì>žz"lþæìã Çâ¿:ûÁ”[ÏÙ'Š¿ÕÑ6œe–Ð$t\EZÜ2J6ÎÿÑæÆß·ä Lä×™̰]¯BBÒwL ÷JV®™`ág åÝ}¯êÖrKi a4€VÏ•T§jk#Y^Ú®
*/<pÆð³……­í=͈•×ÌãG¿P«-␍à8›…lÆÖÆýýù®ÞF'nJªÀ$¬'‘}Õçõ4·²þÄ€eVI1{¯ÉdÄÏ`o)ü )P/Ã:ж{jÑ�õ‘Ý‚Â#D?é÷½´‘\ož� HúÛÅGFlpßæ“m¯íÜ­‰¦+�tîNÄ·Ÿ^ «ü¼`¬ô�ìks3ޱý1~ø´¢±gâ½XÔvØ“ëÝ›S3A=¤ú*ÒJ‰£¤vsÏþ µðãó¹ö
ÅÏëÝé¨'µ$T†WÄ™BððlÆÃøéLÇýI}jÛkO
×Ð�PdLH(?¶^5$Pi{´]^ñÅÃÚÆéÎvùËÌUäÌS„ªz}€!Óâ�n©ð™!P¹üÙ§ŠvÌ Õ5”1Hü>&gªJéáÉÀC¼±tùìB ‰¸ ‘˱75i”æÙF»␍ÿÖ4—ê m˜)Â�-Œg$R³v"meϩڠ �"‚³WÛÈÌ:Ú":§#-&m"‹`¢�T"<Ÿ[X³5@tèpmÌAؤR.m�‘TÚ©‚4 e˜ûaoƒ
0#ÜÎE<®6 nŸÙ��©YI+E»6 ™¸þm0°éÊéD³I±Z¹EƒÏ† {Ge ¬ÌšQn©Ï­Ÿk×ðõXk9;•¸Pš×¸2S ;¥e %¹g©ì�y?3-•˜(-CÏ:w˜Ò2ì,� ”–áüÙnŸß<)'IÊV–³t‚õ@Úzã… 65k'ÒÖEzša©d`¼f„␍¢ò8 1½zúEe`xí éLv3eK~®]o«Ê+õ¸»Ÿ;Ý/‹‡(OYÙY#ˆdSë·Zj®–»817Œœ êkqCÍ:“újjÛýgš­ï·R8‘
çZ�ÁÑN«>
[+ÜöÍI�ÒRá:Ñ:Í'ðOÐNwdøYLª‰T8Q-»“&?_†Î5Zå–66ÞÔ «×�­¦Æ™»š¢ûoú‹5ó‹òrC‘2¿¸aZú ÊüâcóÝ †6½K/´µ§$©–Ù;^õgIsJÕ+ÕÔ_¤Í/ED§™ˆ~Ôqö”Æ>³Ÿ;F$pJÜ0LãuYoü"IŠ4 ±iÝY"65<#n¦™+£V.hl% … ¹†Ÿ¨í6Ÿ5�ò¡–Ô³RI›ÈuÜ\Sæ-õîÕr5UH¼î¬Ó·K†­nÞ#¸$þØNý�†2Aòl…¶y 2‹Ã�äͺ’ÛºáOwó/­8qk$¯bZné“‘ùf›·>µaÞ™hƒ­ìoª›Åw„ ÙÊãCˆ½Ò<˪ߺ7¬úmüôJÒ+ª ±®~c?Pþä]–4PÜA²ç‘BwŠÉl½{LãºÈ`¯�/ÕÆß÷:}=š3eßÖ[?ô¼š’yw×0�æí.VÖ]S—¥.õ±¶{Þ|?®Ä®"æËOPtŸò¡ϵb:DÛq(qËãIƒú’!¬½ÂÞð$ë|eý)«~«ˆ\Ž í…S‹Þöví=:+_¿Ô*Ý…æîåõójµ‘Þ¹Câi -␍w4È×ñ�ÕêY‹c2³¢
›¸Æ<'}µæ™´F¹ºyµ†S~qŽ-–PÈ}I«âé®*™"‰u4-ûq’å)␍?Ñ2µ¿¦Çu¾3 ¶’~Jby«'‰¦ñyð¬L¡>îujM¨§ÍdkçDz´–Y�Î␍3�ÝMg¶ø8J¦¤èV<^Ôr6‹x q�Æ­'Üi&uœDà(­&}~lf*‡2␍…k”9‡¾ðÙ%y™Hn™dˆ.ÄAd!ùE©#ÜÛI".<A3’W%ô^-␍èkЪ„Þ;Îh)¤§›HdBQß,F¢+­ÒÒîÿ šH^rQ!+ÑÌå¸+)gJç£Ó�¦"ÿ¬GþÉì0ÌM¿%×Iº–~�*rsÜ“ú£h1šÙ½*ÙŠÔ”[ª€æü-¯‹¿´J(j ùTKt ¦ÃRå½°÷¹¿x¹)VÞé‡-{ì`‚ÛßD±ƒ—rÓûÞc‹¥Ú�6
¤PvòÚV«ÄÒô ‹SŽ�N_2y©s½Ç�ô[MÎßqtË,ìÈö¬Ý›�ÝÔàôpç¨0Üö7üÈßV•çGºòX{¸®mîn6qÞïäÉ.Ç·›²­Ñhl ×ñ´¸€Fxˆ>ÖÑYç0ð•W‡„ëå ßøhGÀ.'ã¤,­Pì ^ãÄ¥Þ3‘K«›ªÀ,Ý×ñ¢žV¹%û<D?3£Ôkõ[œäÆ?®üˆ˜³gJ�Hx/S˜)½fFŽÏÜöí ¤±7baå/SfµIåÙÚA`LgU S´wf>c_Ư;F†µ‰Mð÷ŠXïI˜A»Y±0A¶3P‹/ˆ$¼GäÜÞ�ÄYR=Xbï†Å¹îæsÎA‘FGQ¨ÉâçiôAg#–9?¦È�«›÷ Rž_ÒˆÙøh¡Ÿ÷¤]à›>9j„M,Q Mq8À³™4Ÿ½ñpFi`Â�}`O‹7>x¸Ì8µ‡â+¦nò†6±çÍf±¼{³²þVnç�»×»ý;rºEéiísae¡yßÑu"N'²7ó$7ŽS¦C,È␍�KŠœ_Q}®$È7qá–œia,S8ðá‘ÛÇÑÍøüM�߯G–XA´£Ï
y°˜9a¿Ð�;H›Ï;ùYÓAHÿ�‡X|ðÚbö˜5éjÎ}¨CGÔuÌXåLaêÇf¢=e°•=ß]#ߪχIòÍÔóчŸ±¥‡dÕÖ�Üco¿[y_¢ƒGw6¶ïyr8è kí]ÄU�¤³¼‚õ?«À,›¾lšÏÿÑOç wþφ.D·Éù©¯Á™óù?ú Cº*cè1šK௨2†ƒGó·TC�Áý·TC�ÑŒ�¿¢ÊzŒæãò>UÊ,b&Ž µË(³é¾™ùav ì;í.ó§• m§PIÚvecûÊðKÐÏ)ÊÚ@[Íbá/G$üixã°1ºhÞY}dm»¢tu㬪ï¬^L60^´í¬î¯ì›YŒ¿ZÅj^ �ðNYtb8"Áý$úFéÏ2ú3˜›Ô:Å&®ƒŽŽS�“ÑðÓ{„ñ39…ìÅtØØÆzïRß�| Ñ"Ú^œ}CqÜ,’øØt␍i¡÷âìû Þ®1â··yÇø/¯f<à}b�f$@wÌH@ÇæX‘ ´âÆ©�î©Ë¦Ø`O*üî´î<Ùbð"†�±ë®¬ jÚ v&†½sƒ žÝʽûrÕŸ¥␍|ì«w$λ�‡AÎðj@;„|–�Ô•␍x³': s¶�àã8UÑ9í@Úî¤4ða¯ Ú†‹ º5èêUEZX>?�C
4š‰6ž³ ›óº]ZéH <#ç␍Źæm␍¨Ê­Þ†4œ)Œcë¼=r¢o4šàùOÉdíz•­s9æ� /9W´ +þ¡g4@ïŸ<4mH{xÖ)èÁÔ_ºö²o9÷¡€Jîm”f�j|Í&€$;•””ZÚþT2Ñ ;Ò> %Ä@úc'lbJ <eZdPÚÃxa6Þ\\ °H³Ãg£�ØêmûÊ“ؘIáEº!}ù!çm¤uB]o¼�ÑøÎF�þÈX¤§b�¯ Èy‘¨V+Rß‹ñ‚ÉsZãQ:ö=²©�q2ƒ²½oì¨Ý##/ç”ë⥜�‹ƒñòRÎÇE‰çÆËK9%ã奜�‹’lvxx)ç㢌hǨºy)çã¢Ôü®^Êù¸(Œ·—r>.ÊN_÷ðRÎÇE‰Ã½¼”óqQjRÀÕK9%vtyy)º(KƱÒjD‘‡=ýR?�£ rº­¸pˆg)©•ºýB›º’Zq“ÔÒåŒnœeâøÆDøØ„å/›_#Áâ¯mG#ü¥ý½“Æiè`ðÇäVêVÑŽ©ÍooêûMñÉñÊ•÷×�gÓ¾¶‘_fR«mø�=J˜Ã.
#et”Ô;�bçøÄpì6DlÿIœ€©×¼d
Ðлµí¸¨[Ä È6;³wôÃnÕ£s÷>x´_J©žÀ¥Í ’ Eó™äÆŽË[²¯»»e´Ï‰rG»™õj¿eÞÉ„ÇËðèJ�¸H¶^’>:ýcñ�¤Dþa¢ä/␍Ñg¾eX!Êf³ð#‹ž7"ÿć??ØDôÁ¬gv•Q¥Óu侨ü‰ñ³û“ãS´MJ~…|½�ÿîuûP -ŽFJ§1IÃÞrEÐq²\³Ýé¶©¯–b£™ƒþÈx�>F’ú:Þ�ÅLf0Vº”¬|dZ͌ԕ~††b2‰hæ
÷?¬Mü»c½␍ôbXl5]ÊöÅžVTí')œúNh*’8êü”šr¯'÷‡ýábðá7à ¿ù݆ÿë×/ê‡GÍ
… ÍfX6­´ÞÓÃ?ý‘ø;
P/2péïŠ␍–‰L|ðî…��K«ÁåVgÿSCy¬4¥wÀ‚Dõ¥Q¦r]Ñ_¦iª5j…@ŠZ/ fô*ß
=ˆ6:ýÏaSHDJ@߇±)␍3Úóàxñ©á„£Ê÷ÀK¹øü¬­©Ã¨ØoEaIÁP†ÏÏeqïùùäOT/��w¸ns4V$x„¢Œºb¿)Á[¹ÿ!ËCý[”‹{²<jG? P?šãIÕß9žôñ¥†±¢ô{ +£ô{§«b6ÒÝ+ôèiPð§5Æ‹Îÿ›‡þ{Ú¡ÿþFC·ñp…Òdj±%7sÀd¥ï�šâŠ�*�)„"„Ÿ’2„®†#½Rj>£c¼G`<W·{õëvgX%úz áLÔѧòæ -FU{J‚ÉD×Á �çZuôù‡Žî¢�û_‘Æ‘n¦4|‚"ð»ÛO½­Ÿéø¿éwPH¬?%¶¼ ÛH°õm8.Äß;£tOTÀ Nw¥÷Q˜OTý¯ýHL9x\ó{Œ�c©\–fi. •k¢³ù'¹›«}�Ñó Eç Y¾0ÕèO7úßßeôLÂÿw ¶Ü•¤Î‡¹½æãà•Nkº±[+~“¡3# /LCõÿ‘åÞTtO*~ „™|¹ñCjަšþ‰ªßdø!Fß�•–¤È±Ù…÷¶Šßcäïbwè3ƒV»ª-ÿB<fàF�ï1æÅþzΛrWVÂϸZ훌ýÿ 1ö�ø!…¹©Ò÷w×%ô¯N¿%ÿ%õw§×ù�Ζqoä{`dJ%¿!ƒøµà9Tþ¯Æ€ÒùhOkå©u¿Çø‰d
=¬�Qº‹ö�§Sù­-|t¤C96lì=�ágTþ@ÁtÖŸQù{  �›Ê
P‡Ñ–Â
·¾6V#%íƒùÆ^{l¨␍|dL%,‘&4l‹0˜©ð`®þ=°0= aLa29×OÍg ³ïKèûEºo<Äàì£øïØ5©ÿæÊuc+~Vë.»(0‚’,wI£eu$µJzh‹Q_õÕ­–B4žˆÞßá�&ZAÛ.gðAåò‡FñŒ�ËçáKŽå…< _XF(Ð9øÂ±Y¾€Š°\–E_¸Ÿ‡7÷"jE´Añèýôë¾ý€g¿¢ =‰>½ÐÑV^^Fþa�bóL6ÊXŠçø\´‡æ¨<␍ß¹Oñy6e–b³O8ª�ã…èO(–ÏSͲø!ŸÍ1Q6W ¦ D9!Oq‚¡ �ÍASù,Eçi.ZFíó[à
Q.ÇRy€Í
T^(0Pˆ¥„‚ÀG"ÿpt�Êf6—‡Ö9š iŠaóЉ<OqLŽ�ÞB[úÊ1SÈsQ4¤<ô=Èá¾ T–Á␍Aï
lw¡ÀPÙ\�ƒž2€oÀ +(&‹ë(^ÈACP†§s¨¢@ñ|Žô½�….ó¨9Jàyh¿P XŽ#Oò,+␍�s9?É29 ‘£9J„â‡�‹.yð‡És6Àbhò�åáË1<d€„B?¤ó9xË0” à¾åaØÐ7Ž�Ö²y£±2Á!/h”Ų4OØ<‹G™ãsY\�a8T0 ÈÆ„a˜„ÐJzÁQ4OËÒ9W¥óƒŸ09¾0h6h¦·Šc(.Ï0ø!ôFÀ½/ð j>-ä4“òè<& $Ô5–bxÜ‹<U@tø@ºV€.ÁCANCTÉbÂã©|!žˆF8 ݼ �´žÐ@º‚ZL  |DQ™,‡‰€æ€Jñ€8
xª`FˆeTªbX@êËR4À |�ô�E† +‡(Œ#�ÐX�H1•«Ïh![ÀY 2í!‡šÇdS€ ;&p8Ä':eª%aHÇùÌ~ís!'^`xíaN@s�ª³h&á Ï`.»À¸·¤¨'Áp,Ð0�ˆ ðÇp<¡Xx›%sNg³¸M«b8ˆÃOX‹
 ¾@8Úç€W°˜aÙlŽÑQA‚**8qÀ½QžVñ�*r@ü9˜"¨™É":‚'<"
žÎŽƒ1S,šv1¢\ÞƒAó€*„ .‡Å�8Š/Øž�<Rq�`�<<ƒY"«·LÉñd9Ä@4<PLŽæ³ÚCŒ¦ˆá jƒHÚ ß„ïðÌ „Ñ<~X`°l¢á€ÑyD[èßO2ÕÔ@Ï@WEóÇSYÄýèIŽCüÍ"A�𓬾L¦
z] YDjhb�Ì"# W°î�.ä…l´IhX€¹Å¡Kˆ€ƒrY”åÆá f␍XµˆäÂiµc ¢N4£˜UŒ[ v˜;x“Í¡¶a`ìMråó�èˆL `µ$ˆÊy<¡Ù<Ï‚0F Að´cA€6–V@ˆP–QÅ? 2Ï¢‡0_…ª„V@B§ ;Zø<š‚ð<šß2Y/ù,"UXórˆ9&WPà‰wU!››È«
Ò®Ú ä]ÿ ê÷-tàþ¹ß—š#YI7ÇÊOE†‹Èqlà{XÍÿü§ùŸ&úýAßÔ¯Mý¡úã?ÿ!¡¢·4pÃpñ[¦j߯Xø+êø@µaáÌú2Ñjvú‹ôb$K‘Y*6Òtñ’‹´R,„A]3AJòX˜2 p²Œö�Ö;“M[]Ú³YÉŸRÍmqÎå8?Ì©+ÔÎ Ù,Y+X“çüÔ¢‚¶Š3Ù,‡¥h�æõ’°ÜódUa ºf€5E4 ,íA˜rÚC˸�ÿ•OW>ý¯3^Þ�ñ*D“á
˜âAÙÌÃ=,`␍!G–k¤ðå €íÄÁêŽõNPÅA‰Ã‰‘Ã!ÒÍñ¤"ÒAyb�v…€™!`%æ@�Å aí'Å
Ï`íÔwbX¢Æ²X%ÁöÒe
ЭCž€ºBt,Xþ¹\–<ÌaíW Vj␍t–h¿‚¦½ðH‚p¸[ 0¨ö“µ– ƒØoèùWkøÿ‡Öð¯.ð7DRÁG$�IS`±Ã,—í¹Ò
`˜‚}O@·/ /,
�@î6&O¼kDkyÁ"‹‚A¦tŽ2Ó3:‡í(d¯8bç rÐ6kün1�GV¿©�&+ôvŒ˜Z�<”Î QS;9
ôÖ¦þnù¥öH+¤wZkÇ>²æ¿2è_Í`6Ì1Þl¨:¹'ôrä[ÉÒ^jsŒÀƒ%›S™…¦ÑÂ
O²L6‡‹ C–ixHÃâMêbÿ-Ç/#zªOžpqç8ÂTð,/°,~Èc/,‡4oš¸òÄŒð»Ðìn€yÌ4 ‚äó¤^!'ÄÁaßS–bŽ%O˜|N÷=òÄW�” 4jìCC¥¸¬êõæ�Ä’NyZwG©YäMau‡”iÿêõÿ?Ð ˆ§á_bþ²‹÷³j.'dÊ”Bæ<ÇpÑ_Q>zÁ¦Dÿ4Ø Lžˆ2|–ø�ADW/ÇB�|?¤ób©ƒ,á�ŃKNó3 y¡àÿðê_öÿwñžšrÞ €(ŽÑö;²@Äê"ÍÇس4MižÉ9*‡¶…nÕb9UÓÄN-¼z�­îB/~ÿ’ïÿøêõïºõØVðf[÷ ^ßñž½üýç)–A¹B)þê?Ò,²Y9à^ø
|�Â’Óž¦!ޱ?|—•žul»úd ¸Öw¦'¦°…‚›¡¯÷Ìwÿ1¾è¯´¢¨Ã¤«¸ÛŒ©»»-¹!�á”�<~»À¨J
®Ñ‚j"øA+òON‹é9.EÈ©SÕ~ Ÿ9•F'±-Ÿ‹Òµ"vºèª�¡øSŠŠý¾<G
÷B§` �{¥(ÊAOP%½Âòrõ¬ùçÿÚ¶xÐ
endstream␍endobj␍6 0 obj␍[5 0 R]␍endobj␍20 0 obj␍<</CreationDate(D:20130102172747+01'00')/Creator(Adobe Illustrator CS6 \(Windows\))/ModDate(D:20130102172747Z)/Producer(Adobe PDF library 10.01)/Title(Mongoo 3 smooth green)>>␍endobj␍xref
0 21
0000000000 65535 f
0000000016 00000 n
0000000144 00000 n
0000016417 00000 n
0000000000 00000 f
0000018879 00000 n
0000062760 00000 n
0000016468 00000 n
0000016797 00000 n
0000019175 00000 n
0000019062 00000 n
0000018118 00000 n
0000018317 00000 n
0000018365 00000 n
0000018946 00000 n
0000018977 00000 n
0000019248 00000 n
0000019422 00000 n
0000020477 00000 n
0000039795 00000 n
0000062783 00000 n
trailer
<</Size 21/Root 1 0 R/Info 20 0 R/ID[<DAA7E1F6DAFF2748BD66B503D3959824><B0ED829296E5A049A6E2795E820EF1BF>]>>
startxref
62975
%%EOF
Binary file not shown.

Before

Width:  |  Height:  |  Size: 560 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 669 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 743 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 872 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.5 KiB

-1
View File
@@ -1 +0,0 @@
100 ICON DISCARDABLE "systray.ico"
-137414
View File
File diff suppressed because it is too large. Load diff
-7160
View File
File diff suppressed because it is too large. Load diff
-50
View File
@@ -1,50 +0,0 @@
-----BEGIN RSA PRIVATE KEY-----
MIIEogIBAAKCAQEAwONaLOP7EdegqjRuQKSDXzvHmFMZfBufjhELhNjo5KsL4ieH
hMSGCcSV6y32hzhqR5lvTViaQez+xhc58NZRu+OUgEhodRBW/vAOjpz/xdMz5HaC
EhP3E9W1pkitVseS8B5rrgJo1BfCGai1fPav1nutPq2Kj7vMy24+g460Lonf6ln1
di4aTIRtAqXtUU6RFpPJP35PkCXbTK65O8HJSxxt/XtfoezHCU5+UIwmZGYx46UB
Wzg3IfK6bGPSiHU3pdiTol0uMPt/GUK+x4NyZJ4/ImsNAicRwMBdja4ywHKXJehH
gXBthsVIHbL21x+4ibsg9eVM/XioTV6tW3IrdwIDAQABAoIBACFfdLutmkQFBcRN
HAJNNHmmsyr0vcUOVnXTFyYeDXV67qxrYHQlOHe6LqIpKq1Mon7O2kYMnWvooFAP
trOnsS6L+qaTYJdYg2TKjgo4ubw1hZXytyB/mdExuaMSkgMgtpia+tB5lD+V+LxN
x1DesZ+veFMO3Zluyckswt4qM5yVa04YFrt31H0E1rJfIen61lidXIKYmHHWuRxK
SadjFfbcqJ6P9ZF22BOkleg5Fm5NaxJmyQynOWaAkSZa5w1XySFfRjRfsbDr64G6
+LSG8YtRuvfxnvUNhynVPHcpE40eiPo6v8Ho6yZKXpV5klCKciodXAORsswSoGJa
N3nnu/ECgYEA6Yb2rM3QUEPIALdL8f/OzZ1GBSdiQB2WSAxzl9pR/dLF2H+0pitS
to0830mk92ppVmRVD3JGxYDRZQ56tlFXyGaCzJBMRIcsotAhBoNbjV0i9n5bLJYf
BmjU9yvWcgsTt0tr3B0FrtYyp2tCvwHqlxvFpFdUCj2oRw2uGpkhmNkCgYEA03M6
WxFhsix3y6eVCVvShfbLBSOqp8l0qiTEty+dgVQcWN4CO/5eyaZXKxlCG9KMmKxy
Yx+YgxZrDhfaZ0cxhHGPRKEAxM3IKwT2C8/wCaSiLWXZZpTifnSD99vtOt4wEfrG
+AghNd5kamFiM9tU0AyvhJc2vdJFuXrfeC7ntM8CgYBGDA+t4cZcbRhu7ow/OKYF
kulP3nJgHP/Y+LMrl3cEldZ2jEfZmCElVNQvfd2XwTl7injhOzvzPiKRF3jDez7D
g8w0JAxceddvttJRK9GoY4l7OoeKpjUELSnEQkf+yUfOsTbXPXVY7jMfeNL6jE6b
qN7t3qv8rmXtejMBE3G6cQKBgGR5W2BMiRSlxqKx1cKlrApV87BUe1HRCyuR3xuA
d6Item7Lx1oEi7vb242yKdSYnpApWQ06xTh83Y/Ly87JaIEbiM0+h+P8OEIg0F1a
iB+86AcUX1I8KseVy+Np0HbpfwP8GrFfA5DaRPK7pXMopEtby8cAJ1XZZaI1/ZvZ
BebHAoGAcQU9WvCkT+nIp9FpXfBybYUsvgkaizMIqp66/l3GYgYAq8p1VLGvN4v5
ec0dW58SJrCpqsM3NP78DtEzQf9OOsk+FsjBFzDU2RkeUreyt2/nQBj/2mN/+hEy
hYN0Zii2yTb63jGxKY6gH1R/r9dL8kXaJmcZrfSa3AgywnteJWg=
-----END RSA PRIVATE KEY-----
-----BEGIN CERTIFICATE-----
MIIDBjCCAe4CCQCX05m0b053QzANBgkqhkiG9w0BAQQFADBFMQswCQYDVQQGEwJB
VTETMBEGA1UECBMKU29tZS1TdGF0ZTEhMB8GA1UEChMYSW50ZXJuZXQgV2lkZ2l0
cyBQdHkgTHRkMB4XDTA4MTIwNzEwMjUyMloXDTE4MTIwNTEwMjUyMlowRTELMAkG
A1UEBhMCQVUxEzARBgNVBAgTClNvbWUtU3RhdGUxITAfBgNVBAoTGEludGVybmV0
IFdpZGdpdHMgUHR5IEx0ZDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEB
AMDjWizj+xHXoKo0bkCkg187x5hTGXwbn44RC4TY6OSrC+Inh4TEhgnElest9oc4
akeZb01YmkHs/sYXOfDWUbvjlIBIaHUQVv7wDo6c/8XTM+R2ghIT9xPVtaZIrVbH
kvAea64CaNQXwhmotXz2r9Z7rT6tio+7zMtuPoOOtC6J3+pZ9XYuGkyEbQKl7VFO
kRaTyT9+T5Al20yuuTvByUscbf17X6HsxwlOflCMJmRmMeOlAVs4NyHyumxj0oh1
N6XYk6JdLjD7fxlCvseDcmSePyJrDQInEcDAXY2uMsBylyXoR4FwbYbFSB2y9tcf
uIm7IPXlTP14qE1erVtyK3cCAwEAATANBgkqhkiG9w0BAQQFAAOCAQEAW4yZdqpB
oIdiuXRosr86Sg9FiMg/cn+2OwQ0QIaA8ZBwKsc+wIIHEgXCS8J6316BGQeUvMD+
plNe0r4GWzzmlDMdobeQ5arPRB89qd9skE6pAMdLg3FyyfEjz3A0VpskolW5VBMr
P5R7uJ1FLgH12RyAjZCWYcCRqEMOffqvyMCH6oAjyDmQOA5IssRKX/HsHntSH/HW
W7slTcP45ty1b44Nq22/ubYk0CJRQgqKOIQ3cLgPomN1jNFQbAbfVTaK1DpEysrQ
5V8a8gNW+3sVZmV6d1Mj3pN2Le62wUKuV2g6BNU7iiwcoY8HI68aRxz2hVMS+t5f
SEGI4JSxV56lYg==
-----END CERTIFICATE-----
-----BEGIN DH PARAMETERS-----
MEYCQQD+ef8hZ4XbdoyIpJyCTF2UrUEfX6mYDvxuS5O1UNYcslUqlj6JkA11e/yS
6DK8Z86W6mSj5CEk4IjbyEOECXH7AgEC
-----END DH PARAMETERS-----
BIN
View File
Binary file not shown.

Before

Width:  |  Height:  |  Size: 17 KiB

+241
View File
@@ -0,0 +1,241 @@
# Mongoose API Reference
struct mg_server *mg_create_server(void *server_param);
Creates web server instance. Returns opaque instance pointer, or NULL if
there is not enough memory. `server_param`: Could be any pointer, or NULL.
This pointer will be passed
to the callback functions as `struct mg_connection::server_param` field.
A common use case is to pass `this` pointer of the C++ wrapper class
as `user_param`, to let the callback get the pointer to the C++ object.
Note that this function doesn't make the
server instance to serve. Serving is done by `mg_poll_server()` function.
Mongoose has single-threaded, event-driven, asynchronous, non-blocking core.
When server instance is created, it contains an information about
the configuration and the state of each connection.
Server instance is capable on listening on only one port. After creation,
`struct mg_server` has a list
of active connections and configuration parameters.
Side-effect: on UNIX, `mg_create_server()` ignores SIGPIPE signals. If custom
processing is required SIGPIPE, signal handler must be set up after
calling `mg_create_server()`.
Important: Mongoose does not install `SIGCHLD` handler. If CGI is used,
`SIGCHLD` handler must be set up to reap CGI zombie processes.
void mg_destroy_server(struct mg_server **server);
Deallocates web server instance, closes all pending connections, and makes
server pointer a NULL pointer.
const char mg_set_option(struct mg_server *server, const char *name,
const char *value);
Sets a particular server option. Note that at least one option,
`listening_port`, must be specified. To serve static files, `document_root`
must be specified too. If `document_root` option is left unset, Mongoose
will not access filesystem at all. `mg_set_option()` returns NULL if option was
set successfully, otherwise it returns human-readable error string. It is
allowed to call `mg_set_option()` by the same thread that does
`mg_poll_server()` (Mongoose thread) and change server configuration while it
is serving, in between `mg_poll_server()` calls.
void mg_poll_server(struct mg_server *server, int milliseconds);
Performs one iteration of IO loop by iterating over all
active connections, performing `select()` syscall on all sockets with a timeout
of `milliseconds`. When `select()` returns, Mongoose
does an IO for each socket that has data to be sent or received. Application
code must call `mg_poll_server()` in a loop. It is an error to have more then
one thread calling `mg_poll_server()`, `mg_set_option()` or any other function
that take `struct mg_server *` parameter. Mongoose does not
mutex-protect `struct mg_server *`, therefore only single thread
(Mongoose thread) should make Mongoose calls.
`mg_poll_server()` calls user-specified event handler when certain events
occur. Sequence of events for the accepted connection is this:
* `MG_AUTH` - Mongoose asks whether this connection is authorized. If event
handler returns `MG_FALSE`, then Mongoose does not serve the request but
sends authorization request to the client. If `MG_TRUE` is returned,
then Mongoose continues on with the request.
* `MG_REQUEST` - Mongoose asks event handler to serve the request. If
event handler serves the request by sending a reply,
it should return `MG_TRUE`. Otherwise,
it should return `MG_FALSE` which tells Mongoose that request is not
served and Mongoose should serve it. For example, event handler might
choose to serve only RESTful API requests with URIs that start with
certain prefix, and let Mongoose serve all static files.
If event handler decides to serve the request, but doesn't have
all the data at the moment, it should return `MG_MORE`. That tells
Mongoose to send `MG_POLL` events on each iteration of `mg_poll_server()`
`mg_connection::connection_param` pointer is a placeholder to keep
user-specific data. For example, handler could decide to open a DB
connection and store DB connection handle in `connection_param`.
* `MG_POLL` is sent only to those connections which returned `MG_MORE`.
Event handler should try to complete the reply. If reply is completed,
then event handler should return `MG_TRUE`. Otherwise, it should
return `MG_FALSE`, and polling will continue until
handler returns `MG_TRUE`.
* `MG_HTTP_ERROR` sent when Mongoose is about to send HTTP error back
to the client. Event handler can choose to send a reply itself, in which
case event handler must return `MG_TRUE`. Otherwise, event handler must
return `MG_FALSE`
* `MG_CLOSE` is sent when the connection is closed. This event is used
to cleanup per-connection state stored in `connection_param`
if it was allocated.
Sequence of events for the client connection is this:
* `MG_CONNECT` sent when Mongoose has connected to the remote host.
This event is sent to the connection initiated by `mg_connect()` call.
Connection status is held in `mg_connection::status_code`: if zero,
then connection was successful, otherwise connection was not established.
User should send a request upon successful connection.
* `MG_REPLY` is sent when response has been received from the remote host.
* `MG_CLOSE` same as for the accepted connection.
When mongoose buffers in HTTP request and successfully parses it, it sends
`MG_REQUEST` event for GET requests immediately. For POST requests,
Mongoose delays the call until the whole POST request is buffered in memory.
POST data is available to the callback as `struct mg_connection::content`,
and POST data length is in `struct mg_connection::content_len`.
Note that websocket connections are treated the same way. Mongoose buffers
websocket frame in memory, and calls event handler when frame is fully
buffered. Frame data is available `struct mg_connection::content`, and
data length is in `struct mg_connection::content_len`, i.e. very similar to
the POST request. `struct mg_connection::is_websocket` flag indicates
whether the request is websocket or not. Also, for websocket requests,
there is `struct mg_connection::wsbits` field which contains first byte
of the websocket frame which URI handler can examine. Note that to
reply to the websocket client, `mg_websocket_write()` should be used.
To reply to the plain HTTP client, `mg_write_data()` should be used.
const char **mg_get_valid_option_names(void);
Returns a NULL-terminated array of option names and their default values.
There are two entries per option in an array: an option name followed by a
default value. A default value could be NULL. A NULL name indicates an end
of the array.
const char *mg_get_option(const struct mg_server *server, const char *name);
Returns the value of particular configuration parameter. If
given parameter name is not valid, NULL is returned. For valid names, return
value is guaranteed to be non-NULL. If parameter is not set, zero-length string
is returned.
void mg_iterate_over_connections(struct mg_server *, mg_handler_t func);
This is an interface primarily designed to push arbitrary data to websocket
connections at any time. This function could be called from the Mongoose thread
only. When it returns, Mongoose thread calls `func()` for each active
connection.
It is allowed to call `mg_send_data()` or `mg_websocket_write()` within a
callback, cause `func` is executed in the context of the Mongoose thread.
void mg_wakeup_server(struct mg_server *);
Makes `mg_poll_server()` that could be sleeping in the `select()` syscall
to break the call and return. This function can be called from any thread.
It is designed to let other threads wake up Mongoose thread from the sleep
and let it do a fresh new IO iteration over all connection. Usually it is done
when other threads decides there is new data ready to be sent by Mongoose.
void mg_send_status(struct mg_connection *, int status_code);
void mg_send_header(struct mg_connection *, const char *name,
const char *value);
void mg_send_data(struct mg_connection *, const void *data, int data_len);
void mg_printf_data(struct mg_connection *, const char *format, ...);
These functions are used to construct a response to the client. HTTP response
consists of three parts: a status line, zero or more HTTP headers,
a response body. Mongoose provides functions for all three parts:
* `mg_send_status()` is used to create status line. This function can be
called zero or once. If `mg_send_status()` is not called, then Mongoose
will send status 200 (success) implicitly.
* `mg_send_header()` adds HTTP header to the response. This function could
be called zero or more times.
* `mg_send_data()` and `mg_printf_data()` are used to send data to the
client. Note that Mongoose adds `Transfer-Encoding: chunked` header
implicitly, and sends data in chunks. Therefore, it is not necessary to
set `Content-Length` header. Note that `mg_send_data()` and
`mg_printf_data()` do not send data immediately. Instead, they spool
data in memory, and Mongoose sends that data later after URI handler
returns. If data to be sent is huge, an URI handler might
send data in pieces by saving state in
`struct mg_connection::connection_param` variable and returning `0`. Then
Mongoose will call a handler repeatedly after each socket write.
<!-- -->
int mg_websocket_write(struct mg_connection* conn, int opcode,
const char *data, size_t data_len);
Similar to `mg_write()`, but wraps the data into a websocket frame with a
given websocket `opcode`.
const char *mg_get_header(const struct mg_connection *, const char *name);
Get the value of particular HTTP header. This is a helper function.
It traverses http_headers array, and if the header is present in the array,
returns its value. If it is not present, NULL is returned.
int mg_get_var(const struct mg_connection *conn, const char *var_name,
char *buf, size_t buf_len);
Gets HTTP form variable. Both POST buffer and query string are inspected.
Form variable is url-decoded and written to the buffer. On success, this
function returns the length of decoded variable. On error, -1 is returned if
variable not found, and -2 is returned if destination buffer is too small
to hold the variable. Destination buffer is guaranteed to be
'\0' - terminated if it is not NULL or zero length.
int mg_parse_header(const char *hdr, const char *var_name, char *buf,
size_t buf_size);
This function parses HTTP header and fetches given variable's value in a buffer.
A header should be like `x=123, y=345, z="other value"`. This function is
designed to parse Cookie headers, Authorization headers, and similar. Returns
the length of the fetched value, or 0 if variable not found.
int mg_modify_passwords_file(const char *passwords_file_name,
const char *domain,
const char *user,
const char *password);
Add, edit or delete the entry in the passwords file.
This function allows an application to manipulate .htpasswd files on the
fly by adding, deleting and changing user records. This is one of the
several ways of implementing authentication on the server side. For another,
cookie-based way please refer to the examples/chat.c in the source tree.
If password is not NULL, entry is added (or modified if already exists).
If password is NULL, entry is deleted.
Return: 1 on success, 0 on error.
int mg_parse_multipart(const char *buf, int buf_len,
char *var_name, int var_name_len,
char *file_name, int file_name_len,
const char **data, int *data_len);
Parses a buffer that contains multipart form data. Stores chunk name
in a `var_name` buffer. If chunk is an uploaded file, then `file_name`
will have a file name. `data` and `data_len` will point to the chunk data.
Returns number of bytes to skip to the next chunk.
struct mg_connection *mg_connect(struct mg_server *server,
const char *host, int port, int use_ssl);
Create connection to the remote host. Returns `NULL` on error, non-null
if the connection has been scheduled for connection. Upon a connection,
Mongoose will send `MG_CONNECT` event to the event handler.
+27
View File
@@ -0,0 +1,27 @@
# Mongoose Build on Android
This is a small guide to help you run mongoose on Android. Currently it is
tested on the HTC Wildfire. If you have managed to run it on other devices
as well, please comment or drop an email in the mailing list.
Note : You dont need root access to run mongoose on Android.
- Clone Mongoose Git repo
- Download the Android NDK from [http://developer.android.com/tools/sdk/ndk/index.html](http://developer.android.com/tools/sdk/ndk/index.html)
- Run `/path-to-ndk/ndk-build -C /path-to-mongoose/examples`
That should generate mongoose/lib/armeabi/mongoose
- Using the adb tool (you need to have Android SDK installed for that),
push the generated mongoose binary to `/data/local` folder on device.
- From adb shell, navigate to `/data/local` and execute `./mongoose`.
- To test if the server is running fine, visit your web-browser and
navigate to `http://127.0.0.1:8080` You should see the `Index of /` page.
![screenshot](http://cesanta.com/images/android_build.png)
Notes:
- `jni` stands for Java Native Interface. Read up on Android NDK if you want
to know how to interact with the native C functions of mongoose in Android
Java applications.
- TODO: A Java application that interacts with the native binary or a
shared library.
+34
View File
@@ -0,0 +1,34 @@
How To Create A PHP Website With Mongoose
===========================================
## 1. Create a directory which will contain your website files. For example, on drive `C:\`, create a directory called `my_website`:
![screenshot](http://cesanta.com/images/tut_basic/tut1.png)
## 2. Inside `my_website` directory, create a new file called "index". This will be the default web page shown when the website is visited.
![screenshot](http://cesanta.com/images/tut_basic/tut2.png)
## 3. Open index file with your favorite editor (for example, Notepad) and enter some HTML code:
![screenshot](http://cesanta.com/images/tut_basic/tut3.png)
## 4. Save this file as `index.html`:
![screenshot](http://cesanta.com/images/tut_basic/tut4.png)
## 5. Download Mongoose executable from http://cesanta.com/mongoose.shtml and copy the executable inside `my_website` directory:
![screenshot](http://cesanta.com/images/tut_basic/tut5.png)
## 6. Double-click mongoose executable. An icon will appear on a system tray in the bottom right corner of the desktop:
![screenshot](http://cesanta.com/images/tut_basic/tut6.png)
## 7. Click on the mongoose icon and choose "Start browser" menu:
![screenshot](http://cesanta.com/images/tut_basic/tut7.png)
## 8. A browser will popup displaying `index.html` file. Now, you can expand your website by adding more content.
![screenshot](http://cesanta.com/images/tut_basic/tut8.png)
+173
View File
@@ -0,0 +1,173 @@
# Mongoose Embedding Guide
Embedding Mongoose is done in two steps:
1. Copy
[mongoose.c](https://raw.github.com/cesanta/mongoose/master/mongoose.c) and
[mongoose.h](https://raw.github.com/cesanta/mongoose/master/mongoose.h)
to your application's source tree and include them in the build.
2. Somewhere in the application code, call `mg_create_server()` to create
a server, configure it with `mg_set_option()` and loop with
`mg_poll_server()` until done. Call `mg_destroy_server()` to cleanup.
Here's a minimal application `app.c` that embeds mongoose:
#include "mongoose.h"
int main(void) {
struct mg_server *server = mg_create_server(NULL, NULL);
mg_set_option(server, "document_root", "."); // Serve current directory
mg_set_option(server, "listening_port", "8080"); // Open port 8080
for (;;) {
mg_poll_server(server, 1000); // Infinite loop, Ctrl-C to stop
}
mg_destroy_server(&server);
return 0;
}
To compile it, put `mongoose.c`, `mongoose.h` and `app.c` into one
folder, start terminal on UNIX or Visual Studio command line prompt on Windows,
and run the following command:
cc app.c mongoose.c -pthread -o app # on Unix
cl.exe app.c mongoose.c /TC /MD # on Windows
When run, this simple application opens port 8080 and serves static files,
CGI files and lists directory content in the current working directory.
It is possible to generate HTML page content. Mongoose can call user-defined
function when certain events occur.
That function is called _an event handler_, and it is the second parameter
to `mg_create_server()` function. Here is the example event handler function:
int event_handler(struct mg_connection *conn, enum mg_event ev) {
switch (ev) {
case MG_AUTH: return MG_TRUE;
default: return MG_FALSE;
}
}
Event handler is called by Mongoose with `struct mg_connection *`
pointer and an event number. `struct mg_connection *conn`
has all information about the request: HTTP headers, POST or websocket
data buffer, etcetera. `enum mg_event ev` tells which exactly event is sent.
For each event, an event handler returns a value which tells Mongoose how
to behave.
The sequence of events for every connection is this:
* `MG_AUTH` - Mongoose asks whether this connection is authorized. If event
handler returns `MG_FALSE`, then Mongoose does not serve the request but
sends authorization request to the client. If `MG_TRUE` is returned,
then Mongoose continues on with the request.
* `MG_REQUEST` - Mongoose asks event handler to serve the request. If
event handler serves the request by sending a reply,
it should return `MG_TRUE`. Otherwise,
it should return `MG_FALSE` which tells Mongoose that request is not
served and Mongoose should serve it. For example, event handler might
choose to serve only RESTful API requests with URIs that start with
certain prefix, and let Mongoose serve all static files.
If event handler decides to serve the request, but doesn't have
all the data at the moment, it should return `MG_MORE`. That tells
Mongoose to send `MG_POLL` events on each iteration of `mg_poll_server()`
`mg_connection::connection_param` pointer is a placeholder to keep
user-specific data. For example, handler could decide to open a DB
connection and store DB connection handle in `connection_param`.
* `MG_POLL` is sent only to those connections which returned `MG_MORE`.
Event handler should try to complete the reply. If reply is completed,
then event handler should return `MG_TRUE`. Otherwise, it should
return `MG_FALSE`, and polling will continue until
handler returns `MG_TRUE`.
* `MG_CLOSE` is sent when the connection is closed. This event is used
to cleanup per-connection state stored in `connection_param`
if it was allocated.
Let's extend our minimal application example and
create an URI that will be served by user's C code. The app will handle
`/hello` URI by showing a hello message. So, when app is run,
http://127.0.0.1:8080/hello will say hello, and here's the code:
#include <string.h>
#include "mongoose.h"
static int event_handler(struct mg_connection *conn, enum mg_event ev) {
if (ev == MG_AUTH) {
return MG_TRUE; // Authorize all requests
} else if (ev == MG_REQUEST && !strcmp(conn->uri, "/hello")) {
mg_printf_data(conn, "%s", "Hello world");
return MG_TRUE; // Mark as processed
} else {
return MG_FALSE; // Rest of the events are not processed
}
}
int main(void) {
struct mg_server *server = mg_create_server(NULL, event_handler);
mg_set_option(server, "document_root", ".");
mg_set_option(server, "listening_port", "8080");
for (;;) {
mg_poll_server(server, 1000); // Infinite loop, Ctrl-C to stop
}
mg_destroy_server(&server);
return 0;
}
## Example code
Mongoose source code contains a well-commented example code, listed below:
* [hello.c](https://github.com/cesanta/mongoose/blob/master/examples/hello.c)
a minimalistic hello world example
* [post.c](https://github.com/cesanta/mongoose/blob/master/examples/post.c)
shows how to handle form input
* [upload.c](https://github.com/cesanta/mongoose/blob/master/examples/post.c)
shows how to upload files
* [websocket.c](https://github.com/cesanta/mongoose/blob/master/examples/websocket.c) demonstrates websocket usage
* [auth.c](https://github.com/cesanta/mongoose/blob/master/examples/websocket.c) demonstrates API-controlled Digest authorization
* [mjpg.c](https://github.com/cesanta/mongoose/blob/master/examples/mjpg.c) demonstrates MJPEG streaming implementation
## Compilation flags
Below is the list of compilation flags that enable or disable certain
features. By default, some features are enabled, and could be disabled
by setting appropriate `NO_*` flag. Features that are disabled by default
could be enabled by setting appropriate `USE_*` flag. Bare bones Mongoose
is quite small, about 30 kilobytes of compiled x86 code. Each feature adds
a couple of kilobytes to the executable size, and also has some runtime penalty.
Note that some flags start with `NS_` prefix. This is because Mongoose uses
[Net Skeleton](http://github.com/cesanta/net_skeleton) as a low-level
networking engine. If user code has `#include <net_skeleton.h>`, then
all Net Skeleton functions will be available too.
-DMONGOOSE_NO_AUTH Disable MD5 authorization support
-DMONGOOSE_NO_CGI Disable CGI support
-DMONGOOSE_NO_DAV Disable WebDAV support
(PUT, DELETE, MKCOL, PROPFIND methods)
-DMONGOOSE_NO_DIRECTORY_LISTING Disable directory listing
-DMONGOOSE_NO_FILESYSTEM Disables all file IO, serving from memory only
-DMONGOOSE_NO_LOGGING Disable access/error logging
-DMONGOOSE_NO_THREADS
-DMONGOOSE_NO_WEBSOCKET Disable WebSocket support
-DMONGOOSE_USE_IDLE_TIMEOUT_SECONDS=X Idle connection timeout, default is 30
-DMONGOOSE_USE_LUA Enable Lua scripting
-DMONGOOSE_USE_LUA_SQLITE3 Enable sqlite3 binding for Lua
-DMONGOOSE_USE_POST_SIZE_LIMIT=X POST requests larger than X will be
rejected, not set by default
-DMONGOOSE_USE_EXTRA_HTTP_HEADERS=X Append X to the HTTP headers
for static files, empty by default
-DNS_ENABLE_DEBUG Enables debug messages on stdout, very noisy
-DNS_ENABLE_SSL Enable SSL
-DNS_ENABLE_IPV6 Enable IPv6 support
-DNS_ENABLE_HEXDUMP Enables hexdump of sent and received traffic
-DNS_STACK_SIZE=X Sets stack size to X for ns_start_thread()
-DNS_DISABLE_THREADS Disable threads support
-DNS_DISABLE_SOCKETPAIR For systems without loopback interface
+23
View File
@@ -0,0 +1,23 @@
# Mongoose FAQ
### PHP doesn't work: getting empty page, or 'File not found' error
The reason for that is wrong paths to the interpreter. Remember that with PHP,
correct interpreter is `php-cgi.exe` (`php-cgi` on UNIX). Solution: specify
full path to the PHP interpreter, e.g.:
mongoose -cgi_interpreter /full/path/to/php-cgi
### Mongoose fails to start
If Mongoose exits immediately when run, this
usually indicates a syntax error in the configuration file
(named `mongoose.conf` by default) or the command-line arguments.
Syntax checking is omitted from Mongoose to keep its size low. However,
the Manual should be of help. Note: the syntax changes from time to time,
so updating the config file might be necessary after executable update.
### Embedding with OpenSSL on Windows might fail because of calling convention
To force Mongoose to use `__stdcall` convention, add `/Gz` compilation
flag to the Visual Studio project settings.
+19
View File
@@ -0,0 +1,19 @@
How To Share Files With Mongoose
===========================================
## 1. Download Mongoose executable from http://cesanta.com/mongoose.shtml and copy the executable inside the directory you want to share:
![screenshot](http://cesanta.com/images/tut_sharing/tut1.png)
## 2. Double-click mongoose executable. An icon will appear on a system tray in the bottom right corner of the desktop:
![screenshot](http://cesanta.com/images/tut_sharing/tut2.png)
## 3. Click on the mongoose icon and choose "Start browser" menu:
![screenshot](http://cesanta.com/images/tut_sharing/tut3.png)
## 4. A browser will popup displaying files. That's all! To access those files from another computer, start a browser and type `http://<your_machine_ip_address>:8080/` in the address bar.
![screenshot](http://cesanta.com/images/tut_sharing/tut4.png)
## Tip: to find out what is your machine IP address, take a look at http://windows.microsoft.com/en-us/windows/find-computers-ip-address
+44
View File
@@ -0,0 +1,44 @@
# Mongoose Internals
Mongoose has single-threaded, event-driven, asynchronous, non-blocking core.
`mg_create_server()` creates a web server instance. An instance is a container
for the config options and list of active connections. To do the actual
serving, user must call `mg_poll_server()`, which iterates over all
active connections, performing `select()` syscall on all sockets with a
timeout of specified number of milliseconds. When `select()` returns, Mongoose
does an IO for each socket that has data to be sent or received. Application
code must call `mg_poll_server()` in a loop.
Mongoose server instance is designed to be used by a single thread.
It is an error to have more then
one thread calling `mg_poll_server()`, `mg_set_option()` or any other function
that take `struct mg_server *` parameter. Mongoose does not
mutex-protect `struct mg_server *`, therefore the best practice is
to call server management functions from the same thread (an IO thread).
On a multi-core systems, many server instances can be created, sharing the
same listening socket and managed by separate threads (see [multi_threaded.c](https://github.com/cesanta/mongoose/blob/master/examples/multi_threaded.c))
example.
It is an error to pass and store `struct mg_connection *` pointers for
later use to send data. The reason is that they can be invalidated by the
next `mg_poll_server()` call. For such a task,
there is `mg_iterate_over_connections()` API
exists, which sends a callback function to the IO thread, then IO thread
calls specified function for all active connection.
When mongoose buffers in HTTP request and successfully parses it, it calls
appropriate URI handler immediately for GET requests. For POST requests,
Mongoose delays the call until the whole POST request is buffered in memory.
POST data is available to the callback as `struct mg_connection::content`,
and POST data length is in `struct mg_connection::content_len`.
Note that websocket connections are treated the same way. Mongoose buffers
websocket frame in memory, and calls URI handler when frame is fully
buffered. Frame data is available `struct mg_connection::content`, and
data length is in `struct mg_connection::content_len`, i.e. very similar to
the POST request. `struct mg_connection::is_websocket` flag indicates
whether the request is websocket or not. Also, for websocket requests,
there is `struct mg_connection::wsbits` field which contains first byte
of the websocket frame which URI handler can examine. Note that to
reply to the websocket client, `mg_websocket_write()` should be used.
To reply to the plain HTTP client, `mg_write()` should be used.
+51
View File
@@ -0,0 +1,51 @@
# Mongoose Lua Server Pages
Pre-built Windows and Mac mongoose binaries support Lua Server Pages
functionality.
That means it is possible to write PHP-like scripts with mongoose
using Lua programming language instead of PHP. Lua is known
for it's speed and small size. Mongoose uses Lua version 5.2.3, the
documentation for it can be found at
[Lua 5.2 reference manual](http://www.lua.org/manual/5.2/).
To create a Lua Page, make a file that is called `ANY_NAME.lp`. For example,
`my_page.lp`. It is important to have a file
name that ends up with `.lp`, cause this is the way mongoose recognises
Lua Page file. The contents of the file, just like
with PHP, is HTML with embedded Lua code. Lua code must be enclosed within
`&lt;? ?&gt;` blocks, and can appear anywhere on the page.
Mongoose does not send HTTP headers for Lua pages. Therefore,
every Lua Page must begin with HTTP status line and headers, like this:
<? mg.write('HTTP/1.0 200 OK\r\nContent-Type: text/html\r\n\r\n') ?>
<html><body>
<span>Today is:</span> <? mg.write(os.date("%A")) ?>
</body></html>
Note that this example uses function `mg.write()`, which prints data to the
web page. Using function `mg.write()` is the way to generate web content from
inside Lua code. In addition to `mg.write()`, all standard library functions
are accessible from the Lua code (please check reference manual for details).
Information about the request is available via the `mg.request_info` object.
I contains request method, all headers, etcetera. Please refer to
`struct mg_request_info` definition in
[mongoose.h](https://github.com/cesanta/mongoose/blob/master/mongoose.h)
to see what is available via the `mg.request_info` object.
Check out [prime_numbers.lp](https://github.com/cesanta/mongoose/blob/master/examples/lua/prime_numbers.lp) for some example.
Mongoose exports the following to the Lua Server Page:
mg.write(str) -- writes string to the client
mg.onerror(msg) -- error handler, can be overridden
mg.request_info -- a table with request information
Using Lua scripting it is easy to emulate SSI functionality. For example,
to include the content of another file, one can write:
<? mg.write(io.open('MY_FILE.TXT'):read('*all')) ?>
To serve a Lua Page, mongoose creates Lua context. That context is used for
all Lua blocks within the page. That means, all Lua blocks on the same page
share the same context. If one block defines a variable, for example, that
variable is visible in all following blocks.
+147
View File
@@ -0,0 +1,147 @@
# Mongoose Configuration Options
### access\_control\_list
An Access Control List (ACL) allows restrictions to be put on the list of IP
addresses which have access to the web server. In the case of the Mongoose
web server, the ACL is a comma separated list of IP subnets, where each
subnet is prepended by either a `-` or a `+` sign. A plus sign means allow,
where a minus sign means deny. If a subnet mask is omitted, such as `-1.2.3.4`,
this means to deny only that single IP address.
Subnet masks may vary from 0 to 32, inclusive. The default setting is to allow
all accesses. On each request the full list is traversed, and
the last match wins. Example: `$ mongoose -access_control_list -0.0.0.0/0,+192.168/16` to deny all acccesses except those from `192.168/16` subnet. To learn
more about subnet masks, see the
[Wikipedia page on Subnetwork](http://en.wikipedia.org/wiki/Subnetwork)
Default: not set, all accesses are allowed.
### access\_log\_file
Path to a file for access logs. Either full path, or relative to the
mongoose executable. Default: not set, no query logging is done.
### auth_domain
Authorization realm used in `.htpasswd` authorization. Default: `mydomain.com`
### cgi_interpreter
Path to an executable to be used use as an interpreter for __all__ CGI scripts
regardless script extension. Default: not set, Mongoose looks at
[shebang line](http://en.wikipedia.org/wiki/Shebang_(Unix\).
For example, if both PHP and perl CGIs are used, then
`#!/path/to/php-cgi.exe` and `#!/path/to/perl.exe` must be first lines of the
respective CGI scripts. Note that paths should be either full file paths,
or file paths relative to the directory where mongoose executable is located.
If all CGIs use the same interpreter, for example they are all PHP, then
`cgi_interpreter` option can be set to the path to `php-cgi.exe` executable and
shebang line in the CGI scripts can be omitted.
**Note**: PHP scripts must use `php-cgi.exe`, not `php.exe`.
### cgi_pattern
All files that match `cgi_pattern` are treated as CGI files. Default pattern
allows CGI files be anywhere. To restrict CGIs to a certain directory,
use `/path/to/cgi-bin/**.cgi` as a pattern. Note that **full file path** is
matched against the pattern, not the URI.
When Mongoose starts CGI program, it creates new environment for it (in
contrast, usually child program inherits the environment from parent). Several
environment variables however are inherited from Mongoose's environment,
they are: `PATH`, `TMP`, `TEMP`, `TMPDIR`, `PERLLIB`, `MONGOOSE_CGI`. On UNIX
it is also `LD_LIBRARY_PATH`. On Windows it is also `COMSPEC`, `SYSTEMROOT`,
`SystemDrive`, `ProgramFiles`, `ProgramFiles(x86)`, `CommonProgramFiles(x86)`.
Default: `**.cgi$|**.pl$|**.php$`
### dav\_auth\_file
Authentication file for WebDAV mutation requests: `PUT`, `DELETE`, `MKCOL`.
The format of that file is the same as for the `.htpasswd` file
used for digest authentication. It can be created and managed by
`mongoose -A` command. Default: not set, WebDAV mutations are disallowed.
### document_root
A directory to serve. Default: current working directory.
### enable\_directory\_listing
Enable directory listing, either `yes` or `no`. Default: `yes`.
### extra\_mime\_types
Extra mime types to recognize, in form `extension1=type1,extension2=type2,...`.
Extension must include dot. Example:
`mongoose -extra_mime_types .cpp=plain/text,.java=plain/text`. Default: not set.
### global\_auth\_file
Path to a global passwords file, either full path or relative to the mongoose
executable. If set, per-directory `.htpasswd` files are ignored,
and all requests are authorised against that file. Use `mongoose -A` to
manage passwords, or third party utilities like
[htpasswd-generator](http://www.askapache.com/online-tools/htpasswd-generator).
Default: not set, per-directory `.htpasswd` files are respected.
### hide\_files\_patterns
A pattern for the files to hide. Files that match the pattern will not
show up in directory listing and return `404 Not Found` if requested. Pattern
must be for a file name only, not including directory name, e.g.
`mongoose -hide_files_patterns secret.txt|even_more_secret.txt`. Default:
not set.
### idle\_timeout\_ms
Timeout for idle connections in milliseconds. Default: `30000` (30 seconds)
### index_files
Comma-separated list of files to be treated as directory index
files. Default: `index.html,index.htm,index.cgi,index.shtml,index.php`
### ssl_certificate
Path to SSL certificate file. The file must be in PEM format,
and it must have both private key and certificate, see for example
[ssl_cert.pem](https://github.com/cesanta/mongoose/blob/master/build/ssl_cert.pem). If this option is set, then Mongoose serves SSL connections on
`listening_port`. Default: not set.
### listening_port
Port to listen on. Port could be prepended by the specific IP address to bind
to, e.g. `mongoose -listening_port 127.0.0.1:8080`. Otherwise Mongoose
will bind to all addresses. Default: 8080.
### run\_as\_user
Switch to given user credentials after startup. UNIX-only. This option is
required when mongoose needs to bind on privileged port on UNIX, e.g.
$ sudo mongoose -listening_port 80 -run_as_user nobody
Default: not set.
### url\_rewrites
Comma-separated list of URL rewrites in the form of
`uri_pattern=file_or_directory_path`. When Mongoose receives the request,
it constructs the file name to show by combining `document_root` and the URI.
However, if the rewrite option is used and `uri_pattern` matches the
requested URI, then `document_root` is ignored. Instead,
`file_or_directory_path` is used, which should be a full path name or
a path relative to the web server's current working directory. Note that
`uri_pattern`, as all mongoose patterns, is a prefix pattern. If `uri_pattern`
is a number, then it is treated as HTTP error code, and `file_or_directory_path`
should be an URI to redirect to. Mongoose will issue `302` temporary redirect
to the specified URI with following parameters:
`?code=HTTP_ERROR_CODE&orig_uri=ORIGINAL_URI&query_string=QUERY_STRING`.
If `uri_pattern` starts with `@` symbol, then Mongoose compares
it with the `HOST` header of the request. If they are equal, Mongoose sets
document root to `file_or_directory_path`, implementing virtual hosts support.
Examples:
# Redirect all accesses to `.doc` files to a special script
mongoose -url_rewrites **.doc$=/path/to/cgi-bin/handle_doc.cgi
# Implement user home directories support
mongoose -url_rewrites /~joe/=/home/joe/,/~bill=/home/bill/
# Redirect 404 errors to a specific error page
mongoose -url_rewrites 404=/cgi-bin/error.cgi
# Virtual hosts example: serve foo.com domain from different directory
mongoose -url_rewrites @foo.com=/var/www/foo.com
Default: not set.
+49
View File
@@ -0,0 +1,49 @@
How To Create A PHP Website With Mongoose
===========================================
## 1. Create a directory which will contain your website files. For example, on drive `C:\`, create a directory called `my_website`:
![screenshot](http://cesanta.com/images/tut_php/tut1.png)
## 2. Inside `my_website` directory, create a new file called "index". This will be the default web page shown when the website is visited.
![screenshot](http://cesanta.com/images/tut_php/tut2.png)
## 3. Open index file with your favorite editor (for example, Notepad) and enter some HTML / PHP code:
![screenshot](http://cesanta.com/images/tut_php/tut3.png)
## 4. Save this file as `index.php`:
![screenshot](http://cesanta.com/images/tut_php/tut4.png)
## 5. Download Mongoose executable from http://cesanta.com/mongoose.shtml and copy the executable inside `my_website` directory:
![screenshot](http://cesanta.com/images/tut_php/tut5.png)
## 6. Double-click mongoose executable. An icon will appear on a system tray in the bottom right corner of the desktop:
![screenshot](http://cesanta.com/images/tut_php/tut6.png)
## 7. Download PHP 5.3 zip (do NOT download PHP 5.5 cause you might have missing DLLs problem) from http://windows.php.net/download and extract it to `C:\php5` directory:
![screenshot](http://cesanta.com/images/tut_php/tut7.png)
## 8. Click on the mongoose icon and choose "Edit Settings" menu.:
![screenshot](http://cesanta.com/images/tut_php/tut8.png)
## 9. A settings dialog will appear. Click on `cgi_interpreter` button:
![screenshot](http://cesanta.com/images/tut_php/tut9.png)
## 10. Choose `C:\php5\php-cgi.exe` and click "Save Settings":
![screenshot](http://cesanta.com/images/tut_php/tut10.png)
## 11. Click on the mongoose icon and choose "Start browser" menu:
![screenshot](http://cesanta.com/images/tut_php/tut11.png)
## 12. A browser will popup displaying `index.php`.
![screenshot](http://cesanta.com/images/tut_php/tut12.png)
+75
View File
@@ -0,0 +1,75 @@
# Mongoose SSL guide
SSL is a protocol that makes web communication secure. To enable SSL
in mongoose, 3 steps are required:
1. Valid certificate file must be created
2. `ssl_certificate` options must be set to contain path to the
certificate file.
3. `listening_ports` option must contain a port number with letter `s`
appended to it, which instructs Mongoose to use SSL for all connections
made to that port.
Below is the `mongoose.conf` file snippet for typical SSL setup:
document_root www_root # Serve files in www_root directory
listening_ports 80r,443s # Redirect all HTTP requests to HTTPS
ssl_certificate ssl_cert.pem # Location of certificate file
## How to create SSL certificate file
SSL certificate file is a text file that must contain at least two
sections:
1. A private key
2. A certificate
Both sections should be chunks of text in PEM format. When PEM file is
opened in a text editor, it looks like this:
-----BEGIN RSA PRIVATE KEY-----
MIIEogIBAAKCAQEAwONaLOP7EdegqjRuQKSDXzvHmFMZfBufjhELhNjo5KsL4ieH
hYN0Zii2yTb63jGxKY6gH1R/r9dL8kXaJmcZrfSa3AgywnteJWg=
-----END RSA PRIVATE KEY-----
-----BEGIN CERTIFICATE-----
MIIDBjCCAe4CCQCX05m0b053QzANBgkqhkiG9w0BAQQFADBFMQswCQYDVQQGEwJB
SEGI4JSxV56lYg==
-----END CERTIFICATE-----
Two aforementioned sections are clearly seen. Typically, those section
are bigger then in the example shown. The text between the `BEGIN` and
`END` is the text representation of binary data, a private key and a
certificate. Therefore, in order to create a certificate file,
* private key must be converted to PEM format
* certificate must be converted to PEM format
* those two should be concatenated into a single file
If the certificate chain in used, a chain file also needs to be
converted into PEM format and appended to the certificate file.
## How SSL works
SSL is a protocol that can encrypt communication between two parties. If third
party observes all messages passed by, it would be very
hard for the third party (though not impossible) to decrypt the communication.
The idea is based on so-called public key encryption. Communicating parties
have two keys: a public key and a private key. A public key is advertised
to everybody, and it is contained in a certificate. A private key is kept
secret. Security algorithm works in a way that anybody can encrypt
a message using public key, and only private key can decrypt it.
This is why web server needs both private key and certificate: private key
is used to decrypt incoming messages, and certificate is used to tell the
public key to the other party. When communication starts, parties exchange
their public keys, and keep private keys to themselves. Man-in-the-middle
who observes the communication is unable to decrypt the messages cause
private keys are required for decryption.
Encryption algorithms are built on top of hard mathematical problem, which
makes it very expensive for man-in-the-middle to compute private keys.
For example, RSA algorithm is based on a mathematical problem of factorization.
It is easy to generate two very large prime numbers `P` and `Q` and make
a product `P * Q`. But given a product, it is very hard to recover these
two prime numbers - this is called factorization.
+86
View File
@@ -0,0 +1,86 @@
# Mongoose User Guide
Mongoose is small and easy to use web server built on top of
mongoose library. It is designed with maximum simplicity in mind. For example,
to share any directory, just drop mongoose executable in that directory,
double-click it (on UNIX, run it from shell) and launch a browser at
[http://localhost:8080](http://localhost:8080) Note that 'localhost' should
be changed to a machine's name if a folder is accessed from other computer.
On Windows and Mac, Mongoose iconifies itself to the system tray when started.
Right-click on the icon to pop up a menu, where it is possible to stop
mongoose, or configure it.
On UNIX, `mongoose` is a command line utility. Running `mongoose` in
terminal, optionally followed by configuration parameters
(`mongoose [OPTIONS]`) or configuration file name
(`mongoose [config_file_name]`) starts the
web server:
$ mongoose -document_root /var/www # Running mongoose with cmdline options
$ mongoose /etc/my_config.txt # Running mongoose with config file
$ mongoose # Running with no parameters. This will
# serve current directory on port 8080
Mongoose does not detach from terminal. Pressing `Ctrl-C` keys
stops the server.
When started, mongoose first searches for the configuration file.
If configuration file is specified explicitly in the command line, then
specified configuration file is used.
Otherwise, mongoose would search for file `mongoose.conf` in the same directory
where binary is located, and use it. Configuration file can be absent.
Configuration file is a sequence of lines, each line containing
command line argument name and it's value. Empty lines and lines beginning
with `#` are ignored. Here is the example of `mongoose.conf` file:
# This is a comment
document_root C:\www
listening_port 80
ssl_certificate C:\mongoose\ssl_cert.pem
Command line arguments are highest priority and can override
configuration file settings. For example, if `mongoose.conf` has line
`document_root /var/www`, and mongoose has been started as
`mongoose -document_root /etc`, then `/etc` directory will be used as
document root.
Note that configuration options on the command line must start with `-`,
and their names are the same as in the config file. Exampli gratia,
the following two setups are equivalent:
$ mongoose -listening_port 1234 -document_root /var/www
$ cat > mongoose.conf
listening_ports 1234
document_root /var/www
^D
$ mongoose
Mongoose can also be used to modify `.htpasswd` passwords file:
$ mongoose -A .htpasswd mydomain.com user_name user_password
Unlike other web servers, mongoose does not require CGI scripts be located in
a special directory. CGI scripts can be anywhere. CGI (and SSI) files are
recognized by the file name pattern. Mongoose uses shell-like glob
patterns. Pattern match starts at the beginning of the string, so essentially
patterns are prefix patterns. Syntax is as follows:
** Matches everything
* Matches everything but slash character, '/'
? Matches any character
$ Matches the end of the string
| Matches if pattern on the left side or the right side matches.
All other characters in the pattern match themselves. Examples:
# Pattern Meaning
**.cgi$ Any string that ends with .cgi
/foo Any string that begins with /foo
**a$|**b$ Any string that ends with a or b
To restrict CGI files only to `/cgi-bin/` directory, use this setting:
$ mongoose -cgi_pattern /cgi-bin/*.cgi # Emulate /cgi-bin/ restriction
+56 -22
View File
@@ -1,28 +1,62 @@
CFLAGS= -W -Wall -I.. -pthread -g CFLAGS = -W -Wall -I.. -pthread -g -pipe $(CFLAGS_EXTRA)
RM = rm -rf
OUT = -o $@
all: ifeq ($(OS),Windows_NT)
OS=`uname`; \ MSVC = ../../vc6
test "$$OS" = Linux && LIBS="-ldl" ; \ RM = del /q /f
$(CC) $(CFLAGS) hello.c ../mongoose.c $$LIBS $(ADD) -o hello; OUT =
$(CC) $(CFLAGS) upload.c ../mongoose.c $$LIBS $(ADD) -o upload; CC = $(MSVC)/bin/cl
$(CC) $(CFLAGS) post.c ../mongoose.c $$LIBS $(ADD) -o post; CFLAGS = /MD /TC /nologo /W3 /I$(MSVC)/include /I..
$(CC) $(CFLAGS) -DUSE_WEBSOCKET websocket.c ../mongoose.c $$LIBS $(ADD) -o websocket; CFLAGS += /link /incremental:no /libpath:$(MSVC)/lib /machine:IX86
$(CC) $(CFLAGS) chat.c ../mongoose.c $$LIBS $(ADD) -o chat CFLAGS += $(CFLAGS_EXTRA)
else
UNAME_S := $(shell uname -s)
ifeq ($(UNAME_S),Linux)
CFLAGS += -ldl
endif
ifeq ($(UNAME_S),Darwin)
endif
endif
all: hello websocket server post multi_threaded upload auth
# To enable Lua in a server, uncomment following lines
LUA = ../lua-5.2.3/src
#CFLAGS += -I$(LUA) -L$(LUA) -llua -DMONGOOSE_USE_LUA
server: server.c ../mongoose.c
$(CC) server.c ../mongoose.c $(OUT) $(CFLAGS)
hello: hello.c ../mongoose.c
$(CC) hello.c ../mongoose.c $(OUT) $(CFLAGS)
websocket: websocket_html.c websocket.c ../mongoose.c
$(CC) websocket.c websocket_html.c ../mongoose.c $(OUT) $(CFLAGS)
post: post.c ../mongoose.c
$(CC) post.c ../mongoose.c $(OUT) $(CFLAGS)
multi_threaded: multi_threaded.c ../mongoose.c
$(CC) multi_threaded.c ../mongoose.c $(OUT) $(CFLAGS)
upload: upload.c ../mongoose.c
$(CC) upload.c ../mongoose.c $(OUT) $(CFLAGS)
auth: auth.c ../mongoose.c
$(CC) auth.c ../mongoose.c $(OUT) $(CFLAGS)
mjpg: mjpg.c ../mongoose.c
$(CC) mjpg.c ../mongoose.c $(OUT) $(CFLAGS)
MSVC = e:/vc6 websocket_html.c: websocket.html
CL = $(MSVC)/bin/cl perl mkdata.pl $< > $@
CLFLAGS = /MD /TC /nologo $(DBG) /W3 /DNO_SSL \
/I$(MSVC)/include /I.. /Dsnprintf=_snprintf \
/link /incremental:no /libpath:$(MSVC)/lib /machine:IX86
windows: u:
$(CL) upload.c ../mongoose.c $(CLFLAGS) g++ unit_test.c -Wall -W -pedantic -lssl -g -O0 $(CFLAGS_EXTRA) && ./a.out
$(CL) hello.c ../mongoose.c $(CLFLAGS)
$(CL) upload.c ../mongoose.c $(CLFLAGS)
$(CL) post.c ../mongoose.c $(CLFLAGS)
$(CL) post.c ../mongoose.c $(CLFLAGS)
$(CL) /DUSE_WEBSOCKET websocket.c ../mongoose.c $(CLFLAGS)
clean: clean:
rm -rf hello upload post websocket chat *.exe *.dSYM *.obj -@$(RM) hello mjpg upload post websocket auth server multi_threaded websocket_html.c *.exe *.dSYM *.obj .*o
+36
View File
@@ -0,0 +1,36 @@
#include <stdio.h>
#include <string.h>
#include "mongoose.h"
static int ev_handler(struct mg_connection *conn, enum mg_event ev) {
if (ev == MG_AUTH) {
int result = MG_FALSE; // Not authorized
FILE *fp;
// To populate passwords file, do
// mongoose -A my_passwords.txt mydomain.com admin admin
if ((fp = fopen("my_passwords.txt", "r")) != NULL) {
result = mg_authorize_digest(conn, fp);
fclose(fp);
}
return result;
}
return MG_FALSE;
}
int main(void) {
struct mg_server *server = mg_create_server(NULL, ev_handler);
mg_set_option(server, "listening_port", "8080");
mg_set_option(server, "document_root", ".");
printf("Starting on port %s\n", mg_get_option(server, "listening_port"));
for (;;) {
mg_poll_server(server, 1000);
}
mg_destroy_server(&server);
return 0;
}
+37
View File
@@ -0,0 +1,37 @@
// This file is part of mongoose web server project,
// https://github.com/cesanta/mongoose
using System;
using System.Runtime.InteropServices;
public class Program {
static private int EventHandler(MongooseEvent ev) {
if (ev.type != 1) {
return 0; // Mark as unhandled
}
MongooseRequestInfo request_info = (MongooseRequestInfo)
Marshal.PtrToStructure(ev.request_info, typeof(MongooseRequestInfo));
if (request_info.uri != "/test") {
return 0; // Mark as unhandled
}
Mongoose.write(ev.conn, "HTTP/1.1 200 OK\r\n\r\n");
Mongoose.write(ev.conn, "Hello from C#!\n");
return 1; // Mark as handled
}
static void Main() {
Mongoose web_server = new Mongoose(".", "9000",
new MongooseEventHandler(EventHandler));
Console.WriteLine("Mongoose v." + web_server.version_ + " started.");
Console.WriteLine("Press enter to exit program.");
// Serve requests until user presses "enter" on a keyboard
Console.ReadLine();
web_server.stop();
}
}
+93
View File
@@ -0,0 +1,93 @@
// This file is part of mongoose web server project,
// https://github.com/cesanta/mongoose
using System;
using System.Runtime.InteropServices;
[StructLayout(LayoutKind.Sequential)] public struct MongooseHeader {
[MarshalAs(UnmanagedType.LPTStr)] public IntPtr name;
[MarshalAs(UnmanagedType.LPTStr)] public IntPtr value;
};
// mongoose.h :: struct mg_request_info
[StructLayout(LayoutKind.Sequential)] public struct MongooseRequestInfo {
[MarshalAs(UnmanagedType.LPTStr)] public string request_method;
[MarshalAs(UnmanagedType.LPTStr)] public string uri;
[MarshalAs(UnmanagedType.LPTStr)] public string http_version;
[MarshalAs(UnmanagedType.LPTStr)] public string query_string;
[MarshalAs(UnmanagedType.LPTStr)] public string remote_user;
public int remote_ip;
public int remote_port;
public int is_ssl;
[MarshalAs(UnmanagedType.ByValArray,SizeConst=64)]
public MongooseHeader[] http_headers;
};
[StructLayout(LayoutKind.Sequential)] public struct MongooseEvent {
public int type;
public IntPtr user_data;
public IntPtr conn_data;
public IntPtr event_param;
public IntPtr conn;
public IntPtr request_info;
};
public delegate int MongooseEventHandlerN(ref MongooseEvent ev);
public delegate int MongooseEventHandler(MongooseEvent ev);
public class Mongoose {
public const string dll_name_ = "mongoose";
public string version_ = "??";
// These are here to store a ref to the callbacks
// while they are over in unmanaged code, to prevent garbage collection.
private event MongooseEventHandlerN delegates;
private IntPtr ctx_;
[DllImport(dll_name_)] private static extern
IntPtr mg_start([MarshalAs(UnmanagedType.LPArray,
ArraySubType=UnmanagedType.LPTStr)] string[] options,
MongooseEventHandlerN callback,
IntPtr user_data);
[DllImport(dll_name_)] private static extern void mg_stop(IntPtr ctx);
[DllImport(dll_name_)] private static extern IntPtr mg_version();
[DllImport(dll_name_)] public static extern int mg_write(IntPtr conn,
string data, int length);
public Mongoose(string document_root,
string listening_ports,
MongooseEventHandler event_handler) {
version_ = Marshal.PtrToStringAnsi(mg_version());
string[] options = {
"document_root", document_root,
"listening_ports", listening_ports,
null
};
MongooseEventHandlerN cb = delegate(ref MongooseEvent ev) {
return event_handler(ev);
};
// Prevent garbage collection
delegates += cb;
ctx_ = mg_start(options, cb, IntPtr.Zero);
}
public static int write(IntPtr conn, string data) {
return mg_write(conn, data, data.Length);
}
public void stop() {
if (this.ctx_ != IntPtr.Zero) {
mg_stop(this.ctx_);
}
this.ctx_ = IntPtr.Zero;
}
~Mongoose() {
stop();
}
}
+8 -378
View File
@@ -1,385 +1,15 @@
// This file is part of the Mongoose project, http://code.google.com/p/mongoose
// It implements an online chat server. For more details,
// see the documentation on the project web site.
// To test the application,
// 1. type "make" in the directory where this file lives
// 2. point your browser to http://127.0.0.1:8081
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <string.h>
#include <time.h>
#include <stdarg.h>
#include <pthread.h>
#include "mongoose.h" #include "mongoose.h"
#define MAX_USER_LEN 20
#define MAX_MESSAGE_LEN 100
#define MAX_MESSAGES 5
#define MAX_SESSIONS 2
#define SESSION_TTL 120
static const char *authorize_url = "/authorize";
static const char *login_url = "/login.html";
static const char *ajax_reply_start =
"HTTP/1.1 200 OK\r\n"
"Cache: no-cache\r\n"
"Content-Type: application/x-javascript\r\n"
"\r\n";
// Describes single message sent to a chat. If user is empty (0 length),
// the message is then originated from the server itself.
struct message {
long id; // Message ID
char user[MAX_USER_LEN]; // User that have sent the message
char text[MAX_MESSAGE_LEN]; // Message text
time_t timestamp; // Message timestamp, UTC
};
// Describes web session.
struct session {
char session_id[33]; // Session ID, must be unique
char random[20]; // Random data used for extra user validation
char user[MAX_USER_LEN]; // Authenticated user
time_t expire; // Expiration timestamp, UTC
};
static struct message messages[MAX_MESSAGES]; // Ringbuffer for messages
static struct session sessions[MAX_SESSIONS]; // Current sessions
static long last_message_id;
// Protects messages, sessions, last_message_id
static pthread_rwlock_t rwlock = PTHREAD_RWLOCK_INITIALIZER;
// Get session object for the connection. Caller must hold the lock.
static struct session *get_session(const struct mg_connection *conn) {
int i;
const char *cookie = mg_get_header(conn, "Cookie");
char session_id[33];
time_t now = time(NULL);
mg_get_cookie(cookie, "session", session_id, sizeof(session_id));
for (i = 0; i < MAX_SESSIONS; i++) {
if (sessions[i].expire != 0 &&
sessions[i].expire > now &&
strcmp(sessions[i].session_id, session_id) == 0) {
break;
}
}
return i == MAX_SESSIONS ? NULL : &sessions[i];
}
static void get_qsvar(const struct mg_request_info *request_info,
const char *name, char *dst, size_t dst_len) {
const char *qs = request_info->query_string;
mg_get_var(qs, strlen(qs == NULL ? "" : qs), name, dst, dst_len);
}
// Get a get of messages with IDs greater than last_id and transform them
// into a JSON string. Return that string to the caller. The string is
// dynamically allocated, caller must free it. If there are no messages,
// NULL is returned.
static char *messages_to_json(long last_id) {
const struct message *message;
int max_msgs, len;
char buf[sizeof(messages)]; // Large enough to hold all messages
// Read-lock the ringbuffer. Loop over all messages, making a JSON string.
pthread_rwlock_rdlock(&rwlock);
len = 0;
max_msgs = sizeof(messages) / sizeof(messages[0]);
// If client is too far behind, return all messages.
if (last_message_id - last_id > max_msgs) {
last_id = last_message_id - max_msgs;
}
for (; last_id < last_message_id; last_id++) {
message = &messages[last_id % max_msgs];
if (message->timestamp == 0) {
break;
}
// buf is allocated on stack and hopefully is large enough to hold all
// messages (it may be too small if the ringbuffer is full and all
// messages are large. in this case asserts will trigger).
len += snprintf(buf + len, sizeof(buf) - len,
"{user: '%s', text: '%s', timestamp: %lu, id: %lu},",
message->user, message->text, message->timestamp, message->id);
assert(len > 0);
assert((size_t) len < sizeof(buf));
}
pthread_rwlock_unlock(&rwlock);
return len == 0 ? NULL : strdup(buf);
}
// If "callback" param is present in query string, this is JSONP call.
// Return 1 in this case, or 0 if "callback" is not specified.
// Wrap an output in Javascript function call.
static int handle_jsonp(struct mg_connection *conn,
const struct mg_request_info *request_info) {
char cb[64];
get_qsvar(request_info, "callback", cb, sizeof(cb));
if (cb[0] != '\0') {
mg_printf(conn, "%s(", cb);
}
return cb[0] == '\0' ? 0 : 1;
}
// A handler for the /ajax/get_messages endpoint.
// Return a list of messages with ID greater than requested.
static void ajax_get_messages(struct mg_connection *conn,
const struct mg_request_info *request_info) {
char last_id[32], *json;
int is_jsonp;
mg_printf(conn, "%s", ajax_reply_start);
is_jsonp = handle_jsonp(conn, request_info);
get_qsvar(request_info, "last_id", last_id, sizeof(last_id));
if ((json = messages_to_json(strtoul(last_id, NULL, 10))) != NULL) {
mg_printf(conn, "[%s]", json);
free(json);
}
if (is_jsonp) {
mg_printf(conn, "%s", ")");
}
}
// Allocate new message. Caller must hold the lock.
static struct message *new_message(void) {
static int size = sizeof(messages) / sizeof(messages[0]);
struct message *message = &messages[last_message_id % size];
message->id = last_message_id++;
message->timestamp = time(0);
return message;
}
static void my_strlcpy(char *dst, const char *src, size_t len) {
strncpy(dst, src, len);
dst[len - 1] = '\0';
}
// A handler for the /ajax/send_message endpoint.
static void ajax_send_message(struct mg_connection *conn,
const struct mg_request_info *request_info) {
struct message *message;
struct session *session;
char text[sizeof(message->text) - 1];
int is_jsonp;
mg_printf(conn, "%s", ajax_reply_start);
is_jsonp = handle_jsonp(conn, request_info);
get_qsvar(request_info, "text", text, sizeof(text));
if (text[0] != '\0') {
// We have a message to store. Write-lock the ringbuffer,
// grab the next message and copy data into it.
pthread_rwlock_wrlock(&rwlock);
message = new_message();
// TODO(lsm): JSON-encode all text strings
session = get_session(conn);
assert(session != NULL);
my_strlcpy(message->text, text, sizeof(text));
my_strlcpy(message->user, session->user, sizeof(message->user));
pthread_rwlock_unlock(&rwlock);
}
mg_printf(conn, "%s", text[0] == '\0' ? "false" : "true");
if (is_jsonp) {
mg_printf(conn, "%s", ")");
}
}
// Redirect user to the login form. In the cookie, store the original URL
// we came from, so that after the authorization we could redirect back.
static void redirect_to_login(struct mg_connection *conn,
const struct mg_request_info *request_info) {
mg_printf(conn, "HTTP/1.1 302 Found\r\n"
"Set-Cookie: original_url=%s\r\n"
"Location: %s\r\n\r\n",
request_info->uri, login_url);
}
// Return 1 if username/password is allowed, 0 otherwise.
static int check_password(const char *user, const char *password) {
// In production environment we should ask an authentication system
// to authenticate the user.
// Here however we do trivial check that user and password are not empty
return (user[0] && password[0]);
}
// Allocate new session object
static struct session *new_session(void) {
int i;
time_t now = time(NULL);
pthread_rwlock_wrlock(&rwlock);
for (i = 0; i < MAX_SESSIONS; i++) {
if (sessions[i].expire == 0 || sessions[i].expire < now) {
sessions[i].expire = time(0) + SESSION_TTL;
break;
}
}
pthread_rwlock_unlock(&rwlock);
return i == MAX_SESSIONS ? NULL : &sessions[i];
}
// Generate session ID. buf must be 33 bytes in size.
// Note that it is easy to steal session cookies by sniffing traffic.
// This is why all communication must be SSL-ed.
static void generate_session_id(char *buf, const char *random,
const char *user) {
mg_md5(buf, random, user, NULL);
}
static void send_server_message(const char *fmt, ...) {
va_list ap;
struct message *message;
pthread_rwlock_wrlock(&rwlock);
message = new_message();
message->user[0] = '\0'; // Empty user indicates server message
va_start(ap, fmt);
vsnprintf(message->text, sizeof(message->text), fmt, ap);
va_end(ap);
pthread_rwlock_unlock(&rwlock);
}
// A handler for the /authorize endpoint.
// Login page form sends user name and password to this endpoint.
static void authorize(struct mg_connection *conn,
const struct mg_request_info *request_info) {
char user[MAX_USER_LEN], password[MAX_USER_LEN];
struct session *session;
// Fetch user name and password.
get_qsvar(request_info, "user", user, sizeof(user));
get_qsvar(request_info, "password", password, sizeof(password));
if (check_password(user, password) && (session = new_session()) != NULL) {
// Authentication success:
// 1. create new session
// 2. set session ID token in the cookie
// 3. remove original_url from the cookie - not needed anymore
// 4. redirect client back to the original URL
//
// The most secure way is to stay HTTPS all the time. However, just to
// show the technique, we redirect to HTTP after the successful
// authentication. The danger of doing this is that session cookie can
// be stolen and an attacker may impersonate the user.
// Secure application must use HTTPS all the time.
my_strlcpy(session->user, user, sizeof(session->user));
snprintf(session->random, sizeof(session->random), "%d", rand());
generate_session_id(session->session_id, session->random, session->user);
send_server_message("<%s> joined", session->user);
mg_printf(conn, "HTTP/1.1 302 Found\r\n"
"Set-Cookie: session=%s; max-age=3600; http-only\r\n" // Session ID
"Set-Cookie: user=%s\r\n" // Set user, needed by Javascript code
"Set-Cookie: original_url=/; max-age=0\r\n" // Delete original_url
"Location: /\r\n\r\n",
session->session_id, session->user);
} else {
// Authentication failure, redirect to login.
redirect_to_login(conn, request_info);
}
}
// Return 1 if request is authorized, 0 otherwise.
static int is_authorized(const struct mg_connection *conn,
const struct mg_request_info *request_info) {
struct session *session;
char valid_id[33];
int authorized = 0;
// Always authorize accesses to login page and to authorize URI
if (!strcmp(request_info->uri, login_url) ||
!strcmp(request_info->uri, authorize_url)) {
return 1;
}
pthread_rwlock_rdlock(&rwlock);
if ((session = get_session(conn)) != NULL) {
generate_session_id(valid_id, session->random, session->user);
if (strcmp(valid_id, session->session_id) == 0) {
session->expire = time(0) + SESSION_TTL;
authorized = 1;
}
}
pthread_rwlock_unlock(&rwlock);
return authorized;
}
static void redirect_to_ssl(struct mg_connection *conn,
const struct mg_request_info *request_info) {
const char *p, *host = mg_get_header(conn, "Host");
if (host != NULL && (p = strchr(host, ':')) != NULL) {
mg_printf(conn, "HTTP/1.1 302 Found\r\n"
"Location: https://%.*s:8082/%s:8082\r\n\r\n",
(int) (p - host), host, request_info->uri);
} else {
mg_printf(conn, "%s", "HTTP/1.1 500 Error\r\n\r\nHost: header is not set");
}
}
static int begin_request_handler(struct mg_connection *conn) {
const struct mg_request_info *request_info = mg_get_request_info(conn);
int processed = 1;
if (!request_info->is_ssl) {
redirect_to_ssl(conn, request_info);
} else if (!is_authorized(conn, request_info)) {
redirect_to_login(conn, request_info);
} else if (strcmp(request_info->uri, authorize_url) == 0) {
authorize(conn, request_info);
} else if (strcmp(request_info->uri, "/ajax/get_messages") == 0) {
ajax_get_messages(conn, request_info);
} else if (strcmp(request_info->uri, "/ajax/send_message") == 0) {
ajax_send_message(conn, request_info);
} else {
// No suitable handler found, mark as not processed. Mongoose will
// try to serve the request.
processed = 0;
}
return processed;
}
static const char *options[] = {
"document_root", "html",
"listening_ports", "8081,8082s",
"ssl_certificate", "ssl_cert.pem",
"num_threads", "5",
NULL
};
int main(void) { int main(void) {
struct mg_callbacks callbacks; struct mg_server *server = mg_create_server(NULL);
struct mg_context *ctx; mg_set_option(server, "listening_port", "8080");
mg_set_option(server, "document_root", "chat_html_root");
// Initialize random number generator. It will be used later on for printf("Starting on port %s\n", mg_get_option(server, "listening_port"));
// the session identifier creation. for (;;) {
srand((unsigned) time(0)); mg_poll_server(server, 1000);
// Setup and start Mongoose
memset(&callbacks, 0, sizeof(callbacks));
callbacks.begin_request = begin_request_handler;
if ((ctx = mg_start(&callbacks, NULL, options)) == NULL) {
printf("%s\n", "Cannot start chat server, fatal exit");
exit(EXIT_FAILURE);
} }
mg_destroy_server(&server);
// Wait until enter is pressed, then exit return 0;
printf("Chat server started on ports %s, press enter to quit.\n",
mg_get_option(ctx, "listening_ports"));
getchar();
mg_stop(ctx);
printf("%s\n", "Chat server stopped.");
return EXIT_SUCCESS;
} }
// vim:ts=2:sw=2:et
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
@@ -3,7 +3,7 @@
var chat = { var chat = {
// Backend URL, string. // Backend URL, string.
// 'http://backend.address.com' or '' if backend is the same as frontend // 'http://backend.address.com' or '' if backend is the same as frontend
backendUrl: '', backendUrl: 'api.lp',
maxVisibleMessages: 10, maxVisibleMessages: 10,
errorMessageFadeOutTimeoutMs: 2000, errorMessageFadeOutTimeoutMs: 2000,
errorMessageFadeOutTimer: null, errorMessageFadeOutTimer: null,
@@ -49,9 +49,7 @@ chat.refresh = function(data) {
chat.getMessages = function(enter_loop) { chat.getMessages = function(enter_loop) {
$.ajax({ $.ajax({
dataType: 'jsonp', data: {last_id: chat.lastMessageId, cmd: 'get_messages'},
url: chat.backendUrl + '/ajax/get_messages',
data: {last_id: chat.lastMessageId},
success: chat.refresh, success: chat.refresh,
error: function() { error: function() {
}, },
@@ -82,9 +80,7 @@ chat.handleMessageInput = function(ev) {
return; return;
//input.disabled = true; //input.disabled = true;
$.ajax({ $.ajax({
dataType: 'jsonp', data: { text: input.value, cmd: 'send_message' },
url: chat.backendUrl + '/ajax/send_message',
data: {text: input.value},
success: function(ev) { success: function(ev) {
input.value = ''; input.value = '';
input.disabled = false; input.disabled = false;
@@ -98,6 +94,10 @@ chat.handleMessageInput = function(ev) {
}; };
$(document).ready(function() { $(document).ready(function() {
$.ajaxSetup({
dataType: 'json',
url: chat.backendUrl
});
$('.menu-item').click(chat.handleMenuItemClick); $('.menu-item').click(chat.handleMenuItemClick);
$('.message-input').keypress(chat.handleMessageInput); $('.message-input').keypress(chat.handleMessageInput);
chat.getMessages(true); chat.getMessages(true);
File renamed without changes.
+47
View File
@@ -0,0 +1,47 @@
#include <stdio.h>
#include <string.h>
#include "mongoose.h"
static int index_html(struct mg_connection *conn) {
FILE *fp = (FILE *) conn->connection_param;
char buf[200];
size_t n = 0;
if (fp == NULL) {
fp = fopen("../mongoose.c", "r");
conn->connection_param = (void *) fp;
}
if (fp != NULL) {
n = fread(buf, 1, sizeof(buf), fp);
mg_send_data(conn, buf, n);
if (n < sizeof(buf) || conn->wsbits != 0) {
fclose(fp);
conn->connection_param = NULL;
}
}
return n < sizeof(buf) ? MG_REQUEST_PROCESSED : MG_REQUEST_CALL_AGAIN;
}
int main(void) {
struct mg_server *server;
// Create and configure the server
server = mg_create_server(NULL);
mg_set_option(server, "listening_port", "8080");
mg_set_request_handler(server, index_html);
// Serve request. Hit Ctrl-C to terminate the program
printf("Starting on port %s\n", mg_get_option(server, "listening_port"));
for (;;) {
mg_poll_server(server, 1000);
}
// Cleanup, and free server instance
mg_destroy_server(&server);
return 0;
}
+20 -36
View File
@@ -2,50 +2,34 @@
#include <string.h> #include <string.h>
#include "mongoose.h" #include "mongoose.h"
// This function will be called by mongoose on every new request. static int ev_handler(struct mg_connection *conn, enum mg_event ev) {
static int begin_request_handler(struct mg_connection *conn) { int result = MG_FALSE;
const struct mg_request_info *request_info = mg_get_request_info(conn);
char content[100];
// Prepare the message we're going to send if (ev == MG_REQUEST) {
int content_length = snprintf(content, sizeof(content), mg_printf_data(conn, "Hello! Requested URI is [%s]", conn->uri);
"Hello from mongoose! Remote port: %d", result = MG_TRUE;
request_info->remote_port); } else if (ev == MG_AUTH) {
result = MG_TRUE;
}
// Send HTTP reply to the client return result;
mg_printf(conn,
"HTTP/1.1 200 OK\r\n"
"Content-Type: text/plain\r\n"
"Content-Length: %d\r\n" // Always set Content-Length
"\r\n"
"%s",
content_length, content);
// Returning non-zero tells mongoose that our function has replied to
// the client, and mongoose should not send client any more data.
return 1;
} }
int main(void) { int main(void) {
struct mg_context *ctx; struct mg_server *server;
struct mg_callbacks callbacks;
// List of options. Last element must be NULL. // Create and configure the server
const char *options[] = {"listening_ports", "8080", NULL}; server = mg_create_server(NULL, ev_handler);
mg_set_option(server, "listening_port", "8080");
// Prepare callbacks structure. We have only one callback, the rest are NULL. // Serve request. Hit Ctrl-C to terminate the program
memset(&callbacks, 0, sizeof(callbacks)); printf("Starting on port %s\n", mg_get_option(server, "listening_port"));
callbacks.begin_request = begin_request_handler; for (;;) {
mg_poll_server(server, 1000);
}
// Start the web server. // Cleanup, and free server instance
ctx = mg_start(&callbacks, NULL, options); mg_destroy_server(&server);
// Wait until user hits "enter". Server is running in separate thread.
// Navigating to http://localhost:8080 will invoke begin_request_handler().
getchar();
// Stop the server.
mg_stop(ctx);
return 0; return 0;
} }
+12
View File
@@ -0,0 +1,12 @@
LOCAL_PATH := $(call my-dir)/../..
include $(CLEAR_VARS)
# To build with lua support, uncomment two lines below:
#LUA_SOURCES := build/lua_5.2.1.c build/sqlite3.c build/lsqlite3.c
#LUA_FLAGS := -I$(LOCAL_PATH)/build -DTHREADSAFE=1 -DSQLITE_ENABLE_FTS3 -DSQLITE_ENABLE_FTS3_PARENTHESIS -DUSE_LUA -DUSE_LUA_SQLITE3 -DLUA_COMPAT_ALL -D"getlocaledecpoint() ='.'"
LOCAL_CFLAGS := -std=c99 -O2 -W -Wall -pthread -pipe $(LUA_FLAGS) $(COPT)
LOCAL_MODULE := mongoose
LOCAL_SRC_FILES := examples/server.c mongoose.c $(LUA_SOURCES)
include $(BUILD_EXECUTABLE)
+15
View File
@@ -0,0 +1,15 @@
HTTP/1.0 200 OK
Content-Type: text/plain
<?
-- Directory scanning example
function scandir(dir)
local t = {}
for f in io.popen('dir ' .. dir):lines() do table.insert(t, f) end
return t
end
local tab = scandir('C:\\')
for k,v in pairs(tab) do mg.write(v, '\n') end
?>
+15 -19
View File
@@ -23,24 +23,20 @@ Content-Type: text/html
<p>Reading POST data from Lua (click submit):</p> <p>Reading POST data from Lua (click submit):</p>
<form method="POST" ><input type="text" name="t1"/><input type="submit"></form> <form method="POST" ><input type="text" name="t1"/><input type="submit"></form>
<pre> <pre>
POST data: [<? POST data: [<? mg.write(mg.request_info.content) ?>]
local post_data = '' request method: [<? mg.write(mg.request_info.request_method) ?>]
if mg.request_info.request_method == 'POST' then IP/port: [<?mg.write(mg.request_info.remote_ip, ':',
post_data = mg.read() mg.request_info.remote_port) ?>]
end URI: [<? mg.write(mg.request_info.uri) ?>]
mg.write(post_data) HTTP version [<? mg.write(mg.request_info.http_version) ?>]
?>] Content Len: [<? mg.write(mg.request_info.content_len) ?>]
request method: [<? mg.write(mg.request_info.request_method) ?>] HEADERS:
IP/port: [<? mg.write(mg.request_info.remote_ip, ':', <?
mg.request_info.remote_port) ?>] for name, value in pairs(mg.request_info.http_headers) do
URI: [<? mg.write(mg.request_info.uri) ?>] mg.write(name, ':', value, '\n')
HTTP version [<? mg.write(mg.request_info.http_version) ?>] end
HEADERS: ?>
<?
for name, value in pairs(mg.request_info.http_headers) do
mg.write(name, ':', value, '\n')
end
?>
</pre> </pre>
</html> </html>
+17
View File
@@ -0,0 +1,17 @@
#include <stdio.h>
#include "lua_5.2.1.h"
static int smile(lua_State *L) {
(void) L; // Unused
printf("%s\n", ":-)");
return 0;
}
int LUA_API luaopen_lua_dll(lua_State *L) {
static const struct luaL_Reg api[] = {
{"smile", smile},
{NULL, NULL},
};
luaL_openlib(L, "lua_dll", api, 0);
return 1;
}
+94
View File
@@ -0,0 +1,94 @@
#include <sys/stat.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <time.h>
#include "mongoose.h"
static void send_file(struct mg_connection *conn, const char *path) {
char buf[1024];
struct stat st;
int n;
FILE *fp;
if (stat(path, &st) == 0 && (fp = fopen(path, "rb")) != NULL) {
mg_printf(conn, "--myboundary\r\nContent-Type: image/jpeg\r\n"
"Content-Length: %zu\r\n\r\n", st.st_size);
while ((n = fread(buf, 1, sizeof(buf), fp)) > 0) {
mg_write(conn, buf, n);
}
fclose(fp);
mg_write(conn, "\r\n", 2);
}
}
struct conn_state {
int file_index;
time_t last_poll;
};
static int ev_handler(struct mg_connection *conn, enum mg_event ev) {
const char **file_names = (const char **) conn->server_param;
struct conn_state *state;
int result = MG_FALSE;
if (ev == MG_REQUEST) {
mg_printf(conn, "%s",
"HTTP/1.0 200 OK\r\n" "Cache-Control: no-cache\r\n"
"Pragma: no-cache\r\nExpires: Thu, 01 Dec 1994 16:00:00 GMT\r\n"
"Connection: close\r\nContent-Type: multipart/x-mixed-replace; "
"boundary=--myboundary\r\n\r\n");
send_file(conn, file_names[0]);
state = (struct conn_state *) malloc(sizeof(*state));
conn->connection_param = state;
state->file_index = 1; // First file is already sent
state->last_poll = time(NULL);
result = MG_MORE;
} else if (ev == MG_POLL) {
time_t now = time(NULL);
state = (struct conn_state *) conn->connection_param;
if (state != NULL && now > state->last_poll) {
if (file_names[state->file_index] != NULL) {
send_file(conn, file_names[state->file_index]);
state->file_index++;
if (file_names[state->file_index] == NULL) {
result = MG_TRUE; // No more images, close connection
}
}
state->last_poll = now;
}
} else if (ev == MG_CLOSE) {
free(conn->connection_param);
conn->connection_param = NULL;
} else if (ev == MG_AUTH) {
result = MG_TRUE;
}
return result;
}
int main(int argc, char *argv[]) {
struct mg_server *server;
if (argc < 3) {
printf("Usage: %s image1.jpg image2.jpg ...\n", argv[0]);
return 1;
}
server = mg_create_server(&argv[1], ev_handler);
mg_set_option(server, "listening_port", "8080");
printf("Starting on port %s\n", mg_get_option(server, "listening_port"));
for (;;) {
mg_poll_server(server, 1000);
}
mg_destroy_server(&server);
return 0;
}
+53
View File
@@ -0,0 +1,53 @@
# This program is used to embed arbitrary data into a C binary. It takes
# a list of files as an input, and produces a .c data file that contains
# contents of all these files as collection of char arrays.
#
# Usage: perl <this_file> <file1> [file2, ...] > embedded_data.c
foreach my $i (0 .. $#ARGV) {
open FD, '<:raw', $ARGV[$i] or die "Cannot open $ARGV[$i]: $!\n";
printf("static const unsigned char v%d[] = {", $i);
my $byte;
my $j = 0;
while (read(FD, $byte, 1)) {
if (($j % 12) == 0) {
print "\n";
}
printf ' %#04x,', ord($byte);
$j++;
}
print " 0x00\n};\n";
close FD;
}
print <<EOS;
#include <stddef.h>
#include <string.h>
static const struct embedded_file {
const char *name;
const unsigned char *data;
size_t size;
} embedded_files[] = {
EOS
foreach my $i (0 .. $#ARGV) {
print " {\"$ARGV[$i]\", v$i, sizeof(v$i) - 1},\n";
}
print <<EOS;
{NULL, NULL, 0}
};
const char *find_embedded_file(const char *name, size_t *size) {
const struct embedded_file *p;
for (p = embedded_files; p->name != NULL; p++) {
if (!strcmp(p->name, name)) {
if (size != NULL) { *size = p->size; }
return (const char *) p->data;
}
}
return NULL;
}
EOS
+40
View File
@@ -0,0 +1,40 @@
#include "mongoose.h"
// Start a browser and hit refresh couple of times. The replies will
// come from both server instances.
static int ev_handler(struct mg_connection *conn, enum mg_event ev) {
if (ev == MG_REQUEST) {
mg_send_header(conn, "Content-Type", "text/plain");
mg_printf_data(conn, "This is a reply from server instance # %s",
(char *) conn->server_param);
return MG_TRUE;
} else if (ev == MG_AUTH) {
return MG_TRUE;
} else {
return MG_FALSE;
}
}
static void *serve(void *server) {
for (;;) mg_poll_server((struct mg_server *) server, 1000);
return NULL;
}
int main(void) {
struct mg_server *server1, *server2;
server1 = mg_create_server((void *) "1", ev_handler);
server2 = mg_create_server((void *) "2", ev_handler);
// Make both server1 and server2 listen on the same socket
mg_set_option(server1, "listening_port", "8080");
mg_set_listening_socket(server2, mg_get_listening_socket(server1));
// server1 goes to separate thread, server 2 runs in main thread.
// IMPORTANT: NEVER LET DIFFERENT THREADS HANDLE THE SAME SERVER.
mg_start_thread(serve, server1);
mg_start_thread(serve, server2);
getchar();
return 0;
}
+36 -30
View File
@@ -10,47 +10,53 @@ static const char *html_form =
"<input type=\"submit\" />" "<input type=\"submit\" />"
"</form></body></html>"; "</form></body></html>";
static int begin_request_handler(struct mg_connection *conn) { static void send_reply(struct mg_connection *conn) {
const struct mg_request_info *ri = mg_get_request_info(conn); char var1[500], var2[500];
char post_data[1024], input1[sizeof(post_data)], input2[sizeof(post_data)];
int post_data_len;
if (!strcmp(ri->uri, "/handle_post_request")) { if (strcmp(conn->uri, "/handle_post_request") == 0) {
// User has submitted a form, show submitted data and a variable value // User has submitted a form, show submitted data and a variable value
post_data_len = mg_read(conn, post_data, sizeof(post_data)); // Parse form data. var1 and var2 are guaranteed to be NUL-terminated
mg_get_var(conn, "input_1", var1, sizeof(var1));
// Parse form data. input1 and input2 are guaranteed to be NUL-terminated mg_get_var(conn, "input_2", var2, sizeof(var2));
mg_get_var(post_data, post_data_len, "input_1", input1, sizeof(input1));
mg_get_var(post_data, post_data_len, "input_2", input2, sizeof(input2));
// Send reply to the client, showing submitted form values. // Send reply to the client, showing submitted form values.
mg_printf(conn, "HTTP/1.0 200 OK\r\n" // POST data is in conn->content, data length is in conn->content_len
"Content-Type: text/plain\r\n\r\n" mg_send_header(conn, "Content-Type", "text/plain");
"Submitted data: [%.*s]\n" mg_printf_data(conn,
"Submitted data length: %d bytes\n" "Submitted data: [%.*s]\n"
"input_1: [%s]\n" "Submitted data length: %d bytes\n"
"input_2: [%s]\n", "input_1: [%s]\n"
post_data_len, post_data, post_data_len, input1, input2); "input_2: [%s]\n",
conn->content_len, conn->content,
conn->content_len, var1, var2);
} else { } else {
// Show HTML form. // Show HTML form.
mg_printf(conn, "HTTP/1.0 200 OK\r\n" mg_send_data(conn, html_form, strlen(html_form));
"Content-Length: %d\r\n" }
"Content-Type: text/html\r\n\r\n%s", }
(int) strlen(html_form), html_form);
static int ev_handler(struct mg_connection *conn, enum mg_event ev) {
if (ev == MG_REQUEST) {
send_reply(conn);
return MG_TRUE;
} else if (ev == MG_AUTH) {
return MG_TRUE;
} else {
return MG_FALSE;
} }
return 1; // Mark request as processed
} }
int main(void) { int main(void) {
struct mg_context *ctx; struct mg_server *server = mg_create_server(NULL, ev_handler);
const char *options[] = {"listening_ports", "8080", NULL};
struct mg_callbacks callbacks;
memset(&callbacks, 0, sizeof(callbacks)); mg_set_option(server, "listening_port", "8080");
callbacks.begin_request = begin_request_handler;
ctx = mg_start(&callbacks, NULL, options); printf("Starting on port %s\n", mg_get_option(server, "listening_port"));
getchar(); // Wait until user hits "enter" for (;;) {
mg_stop(ctx); mg_poll_server(server, 1000);
}
mg_destroy_server(&server);
return 0; return 0;
} }
+484
View File
@@ -0,0 +1,484 @@
// Copyright (c) 2004-2013 Sergey Lyubka
// Copyright (c) 2013-2014 Cesanta Software Limited
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
#undef UNICODE // Use ANSI WinAPI functions
#undef _UNICODE // Use multibyte encoding on Windows
#define _MBCS // Use multibyte encoding on Windows
#define _WIN32_WINNT 0x500 // Enable MIIM_BITMAP
#define _CRT_SECURE_NO_WARNINGS // Disable deprecation warning in VS2005
#define _XOPEN_SOURCE 600 // For PATH_MAX on linux
#undef WIN32_LEAN_AND_MEAN // Let windows.h always include winsock2.h
#include <sys/stat.h>
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <string.h>
#include <errno.h>
#include <limits.h>
#include <stddef.h>
#include <stdarg.h>
#include <ctype.h>
#include <time.h>
#include "mongoose.h"
#ifdef _WIN32
#include <windows.h>
#include <direct.h> // For chdir()
#include <winsvc.h>
#include <shlobj.h>
#ifndef PATH_MAX
#define PATH_MAX MAX_PATH
#endif
#ifndef S_ISDIR
#define S_ISDIR(x) ((x) & _S_IFDIR)
#endif
#define DIRSEP '\\'
#define snprintf _snprintf
#define vsnprintf _vsnprintf
#define sleep(x) Sleep((x) * 1000)
#define abs_path(rel, abs, abs_size) _fullpath((abs), (rel), (abs_size))
#define SIGCHLD 0
typedef struct _stat file_stat_t;
#define stat(x, y) _stat((x), (y))
#else
typedef struct stat file_stat_t;
#include <sys/wait.h>
#include <unistd.h>
#define DIRSEP '/'
#define __cdecl
#define abs_path(rel, abs, abs_size) realpath((rel), (abs))
#endif // _WIN32
#define MAX_OPTIONS 100
#define MAX_CONF_FILE_LINE_SIZE (8 * 1024)
static int exit_flag;
static char server_name[50]; // Set by init_server_name()
static char config_file[PATH_MAX]; // Set by process_command_line_arguments()
static struct mg_server *server; // Set by start_mongoose()
static const char *s_default_document_root = ".";
static const char *s_default_listening_port = "8080";
#if !defined(CONFIG_FILE)
#define CONFIG_FILE "mongoose.conf"
#endif /* !CONFIG_FILE */
static void __cdecl signal_handler(int sig_num) {
// Reinstantiate signal handler
signal(sig_num, signal_handler);
#ifndef _WIN32
// Do not do the trick with ignoring SIGCHLD, cause not all OSes (e.g. QNX)
// reap zombies if SIGCHLD is ignored. On QNX, for example, waitpid()
// fails if SIGCHLD is ignored, making system() non-functional.
if (sig_num == SIGCHLD) {
do {} while (waitpid(-1, &sig_num, WNOHANG) > 0);
} else
#endif
{ exit_flag = sig_num; }
}
static void vnotify(const char *fmt, va_list ap, int must_exit) {
char msg[200];
vsnprintf(msg, sizeof(msg), fmt, ap);
fprintf(stderr, "%s\n", msg);
if (must_exit) {
exit(EXIT_FAILURE);
}
}
static void notify(const char *fmt, ...) {
va_list ap;
va_start(ap, fmt);
vnotify(fmt, ap, 0);
va_end(ap);
}
static void die(const char *fmt, ...) {
va_list ap;
va_start(ap, fmt);
vnotify(fmt, ap, 1);
va_end(ap);
}
static void show_usage_and_exit(void) {
const char **names;
int i;
fprintf(stderr, "Mongoose version %s (c) Sergey Lyubka, built on %s\n",
MONGOOSE_VERSION, __DATE__);
fprintf(stderr, "Usage:\n");
#ifndef MONGOOSE_NO_AUTH
fprintf(stderr, " mongoose -A <htpasswd_file> <realm> <user> <passwd>\n");
#endif
fprintf(stderr, " mongoose [config_file]\n");
fprintf(stderr, " mongoose [-option value ...]\n");
fprintf(stderr, "\nOPTIONS:\n");
names = mg_get_valid_option_names();
for (i = 0; names[i] != NULL; i += 2) {
fprintf(stderr, " -%s %s\n",
names[i], names[i + 1] == NULL ? "<empty>" : names[i + 1]);
}
exit(EXIT_FAILURE);
}
#define EV_HANDLER NULL
static char *sdup(const char *str) {
char *p;
if ((p = (char *) malloc(strlen(str) + 1)) != NULL) {
strcpy(p, str);
}
return p;
}
static void set_option(char **options, const char *name, const char *value) {
int i;
for (i = 0; i < MAX_OPTIONS - 3; i++) {
if (options[i] == NULL) {
options[i] = sdup(name);
options[i + 1] = sdup(value);
options[i + 2] = NULL;
break;
} else if (!strcmp(options[i], name)) {
free(options[i + 1]);
options[i + 1] = sdup(value);
break;
}
}
if (i == MAX_OPTIONS - 3) {
die("%s", "Too many options specified");
}
}
static void process_command_line_arguments(char *argv[], char **options) {
char line[MAX_CONF_FILE_LINE_SIZE], opt[sizeof(line)], val[sizeof(line)], *p;
FILE *fp = NULL;
size_t i, cmd_line_opts_start = 1, line_no = 0;
// Should we use a config file ?
if (argv[1] != NULL && argv[1][0] != '-') {
snprintf(config_file, sizeof(config_file), "%s", argv[1]);
cmd_line_opts_start = 2;
} else if ((p = strrchr(argv[0], DIRSEP)) == NULL) {
// No command line flags specified. Look where binary lives
snprintf(config_file, sizeof(config_file), "%s", CONFIG_FILE);
} else {
snprintf(config_file, sizeof(config_file), "%.*s%c%s",
(int) (p - argv[0]), argv[0], DIRSEP, CONFIG_FILE);
}
fp = fopen(config_file, "r");
// If config file was set in command line and open failed, die
if (cmd_line_opts_start == 2 && fp == NULL) {
die("Cannot open config file %s: %s", config_file, strerror(errno));
}
// Load config file settings first
if (fp != NULL) {
fprintf(stderr, "Loading config file %s\n", config_file);
// Loop over the lines in config file
while (fgets(line, sizeof(line), fp) != NULL) {
line_no++;
// Ignore empty lines and comments
for (i = 0; isspace(* (unsigned char *) &line[i]); ) i++;
if (line[i] == '#' || line[i] == '\0') {
continue;
}
if (sscanf(line, "%s %[^\r\n#]", opt, val) != 2) {
printf("%s: line %d is invalid, ignoring it:\n %s",
config_file, (int) line_no, line);
} else {
set_option(options, opt, val);
}
}
fclose(fp);
}
// If we're under MacOS and started by launchd, then the second
// argument is process serial number, -psn_.....
// In this case, don't process arguments at all.
if (argv[1] == NULL || memcmp(argv[1], "-psn_", 5) != 0) {
// Handle command line flags.
// They override config file and default settings.
for (i = cmd_line_opts_start; argv[i] != NULL; i += 2) {
if (argv[i][0] != '-' || argv[i + 1] == NULL) {
show_usage_and_exit();
}
set_option(options, &argv[i][1], argv[i + 1]);
}
}
}
static void init_server_name(void) {
const char *descr = "";
snprintf(server_name, sizeof(server_name), "Mongoose web server v.%s%s",
MONGOOSE_VERSION, descr);
}
static int is_path_absolute(const char *path) {
#ifdef _WIN32
return path != NULL &&
((path[0] == '\\' && path[1] == '\\') || // UNC path, e.g. \\server\dir
(isalpha(path[0]) && path[1] == ':' && path[2] == '\\')); // E.g. X:\dir
#else
return path != NULL && path[0] == '/';
#endif
}
static char *get_option(char **options, const char *option_name) {
int i;
for (i = 0; options[i] != NULL; i++)
if (!strcmp(options[i], option_name))
return options[i + 1];
return NULL;
}
static int path_exists(const char *path, int is_dir) {
file_stat_t st;
return path == NULL || (stat(path, &st) == 0 &&
((S_ISDIR(st.st_mode) ? 1 : 0) == is_dir));
}
static void verify_existence(char **options, const char *name, int is_dir) {
const char *path = get_option(options, name);
if (!path_exists(path, is_dir)) {
notify("Invalid path for %s: [%s]: (%s). Make sure that path is either "
"absolute, or it is relative to mongoose executable.",
name, path, strerror(errno));
}
}
static void set_absolute_path(char *options[], const char *option_name,
const char *path_to_mongoose_exe) {
char path[PATH_MAX], abs[PATH_MAX], *option_value;
const char *p;
// Check whether option is already set
option_value = get_option(options, option_name);
// If option is already set and it is an absolute path,
// leave it as it is -- it's already absolute.
if (option_value != NULL && !is_path_absolute(option_value)) {
// Not absolute. Use the directory where mongoose executable lives
// be the relative directory for everything.
// Extract mongoose executable directory into path.
if ((p = strrchr(path_to_mongoose_exe, DIRSEP)) == NULL) {
getcwd(path, sizeof(path));
} else {
snprintf(path, sizeof(path), "%.*s", (int) (p - path_to_mongoose_exe),
path_to_mongoose_exe);
}
strncat(path, "/", sizeof(path) - 1);
strncat(path, option_value, sizeof(path) - 1);
// Absolutize the path, and set the option
abs_path(path, abs, sizeof(abs));
set_option(options, option_name, abs);
}
}
#ifndef MONGOOSE_NO_AUTH
int modify_passwords_file(const char *fname, const char *domain,
const char *user, const char *pass) {
int found;
char line[512], u[512], d[512], ha1[33], tmp[PATH_MAX];
FILE *fp, *fp2;
found = 0;
fp = fp2 = NULL;
// Regard empty password as no password - remove user record.
if (pass != NULL && pass[0] == '\0') {
pass = NULL;
}
(void) snprintf(tmp, sizeof(tmp), "%s.tmp", fname);
// Create the file if does not exist
if ((fp = fopen(fname, "a+")) != NULL) {
fclose(fp);
}
// Open the given file and temporary file
if ((fp = fopen(fname, "r")) == NULL) {
return 0;
} else if ((fp2 = fopen(tmp, "w+")) == NULL) {
fclose(fp);
return 0;
}
// Copy the stuff to temporary file
while (fgets(line, sizeof(line), fp) != NULL) {
if (sscanf(line, "%[^:]:%[^:]:%*s", u, d) != 2) {
continue;
}
if (!strcmp(u, user) && !strcmp(d, domain)) {
found++;
if (pass != NULL) {
mg_md5(ha1, user, ":", domain, ":", pass, NULL);
fprintf(fp2, "%s:%s:%s\n", user, domain, ha1);
}
} else {
fprintf(fp2, "%s", line);
}
}
// If new user, just add it
if (!found && pass != NULL) {
mg_md5(ha1, user, ":", domain, ":", pass, NULL);
fprintf(fp2, "%s:%s:%s\n", user, domain, ha1);
}
// Close files
fclose(fp);
fclose(fp2);
// Put the temp file in place of real file
remove(fname);
rename(tmp, fname);
return 1;
}
#endif
static void start_mongoose(int argc, char *argv[]) {
char *options[MAX_OPTIONS];
int i;
if ((server = mg_create_server(NULL, EV_HANDLER)) == NULL) {
die("%s", "Failed to start Mongoose.");
}
#ifndef MONGOOSE_NO_AUTH
// Edit passwords file if -A option is specified
if (argc > 1 && !strcmp(argv[1], "-A")) {
if (argc != 6) {
show_usage_and_exit();
}
exit(modify_passwords_file(argv[2], argv[3], argv[4], argv[5]) ?
EXIT_SUCCESS : EXIT_FAILURE);
}
#endif
// Show usage if -h or --help options are specified
if (argc == 2 && (!strcmp(argv[1], "-h") || !strcmp(argv[1], "--help"))) {
show_usage_and_exit();
}
options[0] = NULL;
set_option(options, "document_root", s_default_document_root);
set_option(options, "listening_port", s_default_listening_port);
// Update config based on command line arguments
process_command_line_arguments(argv, options);
// Make sure we have absolute paths for files and directories
// https://github.com/valenok/mongoose/issues/181
set_absolute_path(options, "document_root", argv[0]);
set_absolute_path(options, "dav_auth_file", argv[0]);
set_absolute_path(options, "cgi_interpreter", argv[0]);
set_absolute_path(options, "access_log_file", argv[0]);
set_absolute_path(options, "global_auth_file", argv[0]);
set_absolute_path(options, "ssl_certificate", argv[0]);
if (!path_exists(get_option(options, "document_root"), 1)) {
set_option(options, "document_root", s_default_document_root);
set_absolute_path(options, "document_root", argv[0]);
notify("Setting document_root to [%s]",
mg_get_option(server, "document_root"));
}
// Make extra verification for certain options
verify_existence(options, "document_root", 1);
verify_existence(options, "cgi_interpreter", 0);
verify_existence(options, "ssl_certificate", 0);
for (i = 0; options[i] != NULL; i += 2) {
const char *msg = mg_set_option(server, options[i], options[i + 1]);
if (msg != NULL) {
notify("Failed to set option [%s] to [%s]: %s",
options[i], options[i + 1], msg);
if (!strcmp(options[i], "listening_port")) {
mg_set_option(server, "listening_port", s_default_listening_port);
notify("Setting %s to [%s]", options[i], s_default_listening_port);
}
}
free(options[i]);
free(options[i + 1]);
}
// Change current working directory to document root. This way,
// scripts can use relative paths.
chdir(mg_get_option(server, "document_root"));
// Add an ability to pass listening socket to mongoose
{
const char *env = getenv("MONGOOSE_LISTENING_SOCKET");
if (env != NULL && atoi(env) > 0 ) {
mg_set_listening_socket(server, atoi(env));
}
}
// Setup signal handler: quit on Ctrl-C
signal(SIGTERM, signal_handler);
signal(SIGINT, signal_handler);
#ifndef _WIN32
signal(SIGCHLD, signal_handler);
#endif
}
int main(int argc, char *argv[]) {
init_server_name();
start_mongoose(argc, argv);
printf("%s serving [%s] on port %s\n",
server_name, mg_get_option(server, "document_root"),
mg_get_option(server, "listening_port"));
fflush(stdout); // Needed, Windows terminals might not be line-buffered
while (exit_flag == 0) {
mg_poll_server(server, 1000);
}
printf("Exiting on signal %d ...", exit_flag);
fflush(stdout);
mg_destroy_server(&server);
printf("%s\n", " done.");
return EXIT_SUCCESS;
}
+516
View File
@@ -0,0 +1,516 @@
// Unit test for the mongoose web server.
// g++ -W -Wall -pedantic -g unit_test.c -lssl && ./a.out
// cl unit_test.c /MD
#ifndef _WIN32
#define NS_ENABLE_IPV6
#define NS_ENABLE_SSL
#endif
#define MONGOOSE_POST_SIZE_LIMIT 999
// USE_* definitions must be made before #include "mongoose.c" !
#include "../mongoose.c"
#define FAIL(str, line) do { \
printf("Fail on line %d: [%s]\n", line, str); \
return str; \
} while (0)
#define ASSERT(expr) do { \
static_num_tests++; \
if (!(expr)) FAIL(#expr, __LINE__); \
} while (0)
#define RUN_TEST(test) do { const char *msg = test(); \
if (msg) return msg; } while (0)
#define HTTP_PORT "45772"
#define LISTENING_ADDR "127.0.0.1:" HTTP_PORT
static int static_num_tests = 0;
#if 0
// Connects to host:port, and sends formatted request to it. Returns
// malloc-ed reply and reply length, or NULL on error. Reply contains
// everything including headers, not just the message body.
static char *wget(const char *host, int port, int *len, const char *fmt, ...) {
char buf[2000], *reply = NULL;
int request_len, reply_size = 0, n, sock = -1;
struct sockaddr_in sin;
struct hostent *he = NULL;
va_list ap;
if (host != NULL &&
(he = gethostbyname(host)) != NULL &&
(sock = socket(PF_INET, SOCK_STREAM, 0)) != -1) {
sin.sin_family = AF_INET;
sin.sin_port = htons((uint16_t) port);
sin.sin_addr = * (struct in_addr *) he->h_addr_list[0];
if (connect(sock, (struct sockaddr *) &sin, sizeof(sin)) == 0) {
// Format and send the request.
va_start(ap, fmt);
request_len = vsnprintf(buf, sizeof(buf), fmt, ap);
va_end(ap);
while (request_len > 0 && (n = send(sock, buf, request_len, 0)) > 0) {
request_len -= n;
}
if (request_len == 0) {
*len = 0;
while ((n = recv(sock, buf, sizeof(buf), 0)) > 0) {
if (*len + n > reply_size) {
// Leak possible
reply = (char *) realloc(reply, reply_size + sizeof(buf));
reply_size += sizeof(buf);
}
if (reply != NULL) {
memcpy(reply + *len, buf, n);
*len += n;
}
}
}
closesocket(sock);
}
}
return reply;
}
#endif
static char *read_file(const char *path, int *size) {
FILE *fp;
struct stat st;
char *data = NULL;
if ((fp = fopen(path, "rb")) != NULL && !fstat(fileno(fp), &st)) {
*size = (int) st.st_size;
data = (char *) malloc(*size);
fread(data, 1, *size, fp);
fclose(fp);
}
return data;
}
static const char *test_parse_http_message() {
struct mg_connection ri;
char req1[] = "GET / HTTP/1.1\r\n\r\n";
char req2[] = "BLAH / HTTP/1.1\r\n\r\n";
char req3[] = "GET / HTTP/1.1\r\nBah\r\n";
char req4[] = "GET / HTTP/1.1\r\nA: foo bar\r\nB: bar\r\nbaz\r\n\r\n";
char req5[] = "GET / HTTP/1.1\r\n\r\n";
char req6[] = "G";
char req7[] = " blah ";
char req8[] = " HTTP/1.1 200 OK \n\n";
char req9[] = "HTTP/1.1 200 OK\r\nConnection: close\r\n\r\n";
ASSERT(get_request_len("\r\n", 3) == -1);
ASSERT(get_request_len("\r\n", 2) == 0);
ASSERT(get_request_len("GET", 3) == 0);
ASSERT(get_request_len("\n\n", 2) == 2);
ASSERT(get_request_len("\n\r\n", 3) == 3);
ASSERT(get_request_len("\xdd\xdd", 2) == 0);
ASSERT(get_request_len("\xdd\x03", 2) == -1);
ASSERT(get_request_len(req3, sizeof(req3) - 1) == 0);
ASSERT(get_request_len(req6, sizeof(req6) - 1) == 0);
ASSERT(get_request_len(req7, sizeof(req7) - 1) == 0);
ASSERT(parse_http_message(req9, sizeof(req9) - 1, &ri) == sizeof(req9) - 1);
ASSERT(ri.num_headers == 1);
ASSERT(parse_http_message(req1, sizeof(req1) - 1, &ri) == sizeof(req1) - 1);
ASSERT(strcmp(ri.http_version, "1.1") == 0);
ASSERT(ri.num_headers == 0);
ASSERT(parse_http_message(req2, sizeof(req2) - 1, &ri) == -1);
ASSERT(parse_http_message(req6, 0, &ri) == -1);
ASSERT(parse_http_message(req8, sizeof(req8) - 1, &ri) == sizeof(req8) - 1);
// TODO(lsm): Fix this. Header value may span multiple lines.
ASSERT(parse_http_message(req4, sizeof(req4) - 1, &ri) == sizeof(req4) - 1);
ASSERT(strcmp(ri.http_version, "1.1") == 0);
ASSERT(ri.num_headers == 3);
ASSERT(strcmp(ri.http_headers[0].name, "A") == 0);
ASSERT(strcmp(ri.http_headers[0].value, "foo bar") == 0);
ASSERT(strcmp(ri.http_headers[1].name, "B") == 0);
ASSERT(strcmp(ri.http_headers[1].value, "bar") == 0);
ASSERT(strcmp(ri.http_headers[2].name, "baz\r\n\r") == 0);
ASSERT(strcmp(ri.http_headers[2].value, "") == 0);
ASSERT(parse_http_message(req5, sizeof(req5) - 1, &ri) == sizeof(req5) - 1);
ASSERT(strcmp(ri.request_method, "GET") == 0);
ASSERT(strcmp(ri.http_version, "1.1") == 0);
return NULL;
}
static const char *test_should_keep_alive(void) {
struct mg_connection conn;
char req1[] = "GET / HTTP/1.1\r\n\r\n";
char req2[] = "GET / HTTP/1.0\r\n\r\n";
char req3[] = "GET / HTTP/1.1\r\nConnection: close\r\n\r\n";
char req4[] = "GET / HTTP/1.1\r\nConnection: keep-alive\r\n\r\n";
memset(&conn, 0, sizeof(conn));
ASSERT(parse_http_message(req1, sizeof(req1) - 1, &conn) == sizeof(req1) - 1);
ASSERT(should_keep_alive(&conn) != 0);
parse_http_message(req2, sizeof(req2) - 1, &conn);
ASSERT(should_keep_alive(&conn) == 0);
parse_http_message(req3, sizeof(req3) - 1, &conn);
ASSERT(should_keep_alive(&conn) == 0);
parse_http_message(req4, sizeof(req4) - 1, &conn);
ASSERT(should_keep_alive(&conn) != 0);
return NULL;
}
static const char *test_match_prefix(void) {
ASSERT(match_prefix("/api", 4, "/api") == 4);
ASSERT(match_prefix("/a/", 3, "/a/b/c") == 3);
ASSERT(match_prefix("/a/", 3, "/ab/c") == -1);
ASSERT(match_prefix("/*/", 3, "/ab/c") == 4);
ASSERT(match_prefix("**", 2, "/a/b/c") == 6);
ASSERT(match_prefix("/*", 2, "/a/b/c") == 2);
ASSERT(match_prefix("*/*", 3, "/a/b/c") == 2);
ASSERT(match_prefix("**/", 3, "/a/b/c") == 5);
ASSERT(match_prefix("**.foo|**.bar", 13, "a.bar") == 5);
ASSERT(match_prefix("a|b|cd", 6, "cdef") == 2);
ASSERT(match_prefix("a|b|c?", 6, "cdef") == 2);
ASSERT(match_prefix("a|?|cd", 6, "cdef") == 1);
ASSERT(match_prefix("/a/**.cgi", 9, "/foo/bar/x.cgi") == -1);
ASSERT(match_prefix("/a/**.cgi", 9, "/a/bar/x.cgi") == 12);
ASSERT(match_prefix("**/", 3, "/a/b/c") == 5);
ASSERT(match_prefix("**/$", 4, "/a/b/c") == -1);
ASSERT(match_prefix("**/$", 4, "/a/b/") == 5);
ASSERT(match_prefix("$", 1, "") == 0);
ASSERT(match_prefix("$", 1, "x") == -1);
ASSERT(match_prefix("*$", 2, "x") == 1);
ASSERT(match_prefix("/$", 2, "/") == 1);
ASSERT(match_prefix("**/$", 4, "/a/b/c") == -1);
ASSERT(match_prefix("**/$", 4, "/a/b/") == 5);
ASSERT(match_prefix("*", 1, "/hello/") == 0);
ASSERT(match_prefix("**.a$|**.b$", 11, "/a/b.b/") == -1);
ASSERT(match_prefix("**.a$|**.b$", 11, "/a/b.b") == 6);
ASSERT(match_prefix("**.a$|**.b$", 11, "/a/B.A") == 6);
ASSERT(match_prefix("**o$", 4, "HELLO") == 5);
return NULL;
}
static const char *test_remove_double_dots() {
struct { char before[20], after[20]; } data[] = {
{"////a", "/a"},
{"/.....", "/."},
{"/......", "/"},
{"...", "..."},
{"/...///", "/./"},
{"/a...///", "/a.../"},
{"/.x", "/.x"},
{"/\\", "/"},
{"/a\\", "/a\\"},
{"/a\\\\...", "/a\\."},
};
size_t i;
for (i = 0; i < ARRAY_SIZE(data); i++) {
remove_double_dots_and_double_slashes(data[i].before);
ASSERT(strcmp(data[i].before, data[i].after) == 0);
}
return NULL;
}
static const char *test_get_var(void) {
static const char *post[] = {
"a=1&&b=2&d&=&c=3%20&e=",
"q=&st=2012%2F11%2F13+17%3A05&et=&team_id=",
NULL
};
char buf[20];
ASSERT(get_var(post[0], strlen(post[0]), "a", buf, sizeof(buf)) == 1);
ASSERT(buf[0] == '1' && buf[1] == '\0');
ASSERT(get_var(post[0], strlen(post[0]), "b", buf, sizeof(buf)) == 1);
ASSERT(buf[0] == '2' && buf[1] == '\0');
ASSERT(get_var(post[0], strlen(post[0]), "c", buf, sizeof(buf)) == 2);
ASSERT(buf[0] == '3' && buf[1] == ' ' && buf[2] == '\0');
ASSERT(get_var(post[0], strlen(post[0]), "e", buf, sizeof(buf)) == 0);
ASSERT(buf[0] == '\0');
ASSERT(get_var(post[0], strlen(post[0]), "d", buf, sizeof(buf)) == -1);
ASSERT(get_var(post[0], strlen(post[0]), "c", buf, 2) == -2);
ASSERT(get_var(post[0], strlen(post[0]), "x", NULL, 10) == -2);
ASSERT(get_var(post[0], strlen(post[0]), "x", buf, 0) == -2);
ASSERT(get_var(post[1], strlen(post[1]), "st", buf, 16) == -2);
ASSERT(get_var(post[1], strlen(post[1]), "st", buf, 17) == 16);
return NULL;
}
static const char *test_url_decode(void) {
char buf[100];
ASSERT(mg_url_decode("foo", 3, buf, 3, 0) == -1); // No space for \0
ASSERT(mg_url_decode("foo", 3, buf, 4, 0) == 3);
ASSERT(strcmp(buf, "foo") == 0);
ASSERT(mg_url_decode("a+", 2, buf, sizeof(buf), 0) == 2);
ASSERT(strcmp(buf, "a+") == 0);
ASSERT(mg_url_decode("a+", 2, buf, sizeof(buf), 1) == 2);
ASSERT(strcmp(buf, "a ") == 0);
ASSERT(mg_url_decode("%61", 1, buf, sizeof(buf), 1) == 1);
ASSERT(strcmp(buf, "%") == 0);
ASSERT(mg_url_decode("%61", 2, buf, sizeof(buf), 1) == 2);
ASSERT(strcmp(buf, "%6") == 0);
ASSERT(mg_url_decode("%61", 3, buf, sizeof(buf), 1) == 1);
ASSERT(strcmp(buf, "a") == 0);
return NULL;
}
static const char *test_to64(void) {
ASSERT(to64("0") == 0);
ASSERT(to64("") == 0);
ASSERT(to64("123") == 123);
ASSERT(to64("-34") == -34);
ASSERT(to64("3566626116") == 3566626116);
return NULL;
}
static const char *test_base64_encode(void) {
const char *in[] = {"a", "ab", "abc", "abcd", NULL};
const char *out[] = {"YQ==", "YWI=", "YWJj", "YWJjZA=="};
char buf[100];
int i;
for (i = 0; in[i] != NULL; i++) {
base64_encode((unsigned char *) in[i], strlen(in[i]), buf);
ASSERT(!strcmp(buf, out[i]));
}
return NULL;
}
static const char *test_mg_parse_header(void) {
const char *str = "xx=1 kl yy, ert=234 kl=123, "
"ii=\"12\\\"34\" zz='aa bb',tt=2,gf=\"xx d=1234";
char buf[10];
ASSERT(mg_parse_header(str, "yy", buf, sizeof(buf)) == 0);
ASSERT(mg_parse_header(str, "ert", buf, sizeof(buf)) == 3);
ASSERT(strcmp(buf, "234") == 0);
ASSERT(mg_parse_header(str, "ert", buf, 2) == 0);
ASSERT(mg_parse_header(str, "ert", buf, 3) == 0);
ASSERT(mg_parse_header(str, "ert", buf, 4) == 3);
ASSERT(mg_parse_header(str, "gf", buf, sizeof(buf)) == 0);
ASSERT(mg_parse_header(str, "zz", buf, sizeof(buf)) == 5);
ASSERT(strcmp(buf, "aa bb") == 0);
ASSERT(mg_parse_header(str, "d", buf, sizeof(buf)) == 4);
ASSERT(strcmp(buf, "1234") == 0);
buf[0] = 'x';
ASSERT(mg_parse_header(str, "MMM", buf, sizeof(buf)) == 0);
ASSERT(buf[0] == '\0');
ASSERT(mg_parse_header(str, "kl", buf, sizeof(buf)) == 3);
ASSERT(strcmp(buf, "123") == 0);
ASSERT(mg_parse_header(str, "xx", buf, sizeof(buf)) == 1);
ASSERT(strcmp(buf, "1") == 0);
ASSERT(mg_parse_header(str, "ii", buf, sizeof(buf)) == 5);
ASSERT(strcmp(buf, "12\"34") == 0);
ASSERT(mg_parse_header(str, "tt", buf, sizeof(buf)) == 1);
ASSERT(strcmp(buf, "2") == 0);
return NULL;
}
static const char *test_next_option(void) {
const char *p, *list = "x/8,/y**=1;2k,z";
struct vec a, b;
int i;
ASSERT(next_option(NULL, &a, &b) == NULL);
for (i = 0, p = list; (p = next_option(p, &a, &b)) != NULL; i++) {
ASSERT(i != 0 || (a.ptr == list && a.len == 3 && b.len == 0));
ASSERT(i != 1 || (a.ptr == list + 4 && a.len == 4 && b.ptr == list + 9 &&
b.len == 4));
ASSERT(i != 2 || (a.ptr == list + 14 && a.len == 1 && b.len == 0));
}
return NULL;
}
static int evh1(struct mg_connection *conn, enum mg_event ev) {
char *buf = (char *) conn->connection_param;
int result = MG_FALSE;
switch (ev) {
case MG_CONNECT:
mg_printf(conn, "GET %s HTTP/1.0\r\n\r\n",
buf[0] == '1' ? "/cb1" : "/non_exist");
result = MG_TRUE;
break;
case MG_HTTP_ERROR:
mg_printf(conn, "HTTP/1.0 404 NF\r\n\r\nERR: %d", conn->status_code);
result = MG_TRUE;
break;
case MG_REQUEST:
if (!strcmp(conn->uri, "/cb1")) {
mg_printf(conn, "HTTP/1.0 200 OK\r\n\r\n%s %s %s",
(char *) conn->server_param,
buf == NULL ? "?" : "!", conn->remote_ip);
result = MG_TRUE;
}
break;
case MG_REPLY:
if (buf != NULL) {
sprintf(buf + 1, "%.*s", (int) conn->content_len, conn->content);
}
break;
case MG_AUTH:
result = MG_TRUE;
break;
default:
break;
}
return result;
}
static const char *test_server(void) {
char buf1[100] = "1", buf2[100] = "2";
struct mg_server *server = mg_create_server((void *) "foo", evh1);
struct mg_connection *conn;
ASSERT(server != NULL);
ASSERT(mg_set_option(server, "listening_port", LISTENING_ADDR) == NULL);
ASSERT(mg_set_option(server, "document_root", ".") == NULL);
ASSERT((conn = mg_connect(server, "127.0.0.1", atoi(HTTP_PORT), 0)) != NULL);
conn->connection_param = buf1;
ASSERT((conn = mg_connect(server, "127.0.0.1", atoi(HTTP_PORT), 0)) != NULL);
conn->connection_param = buf2;
{ int i; for (i = 0; i < 50; i++) mg_poll_server(server, 1); }
ASSERT(strcmp(buf1, "1foo ? 127.0.0.1") == 0);
ASSERT(strcmp(buf2, "2ERR: 404") == 0);
ASSERT(strcmp(static_config_options[URL_REWRITES * 2], "url_rewrites") == 0);
mg_destroy_server(&server);
ASSERT(server == NULL);
return NULL;
}
#define DISP "Content-Disposition: form/data; "
#define CRLF "\r\n"
#define BOUNDARY "--xyz"
static const char *test_parse_multipart(void) {
char a[100], b[100];
const char *p;
static const char f1[] = BOUNDARY CRLF DISP "name=f1" CRLF CRLF
"some_content" CRLF BOUNDARY CRLF
BOUNDARY CRLF DISP "name=f2; filename=\"foo bar.txt\"" CRLF CRLF
"another_content" CRLF BOUNDARY CRLF
"--" CRLF;
int n, n2, len, f1_len = sizeof(f1) - 1;
ASSERT(mg_parse_multipart("", 0, a, sizeof(a), b, sizeof(b), &p, &len) == 0);
ASSERT(mg_parse_multipart("a", 1, a, sizeof(a), b, sizeof(b), &p, &len) == 0);
ASSERT((n = mg_parse_multipart(f1, f1_len, a, sizeof(a),
b, sizeof(b), &p, &len)) > 0);
ASSERT(len == 12);
ASSERT(memcmp(p, "some_content", len) == 0);
ASSERT(strcmp(a, "f1") == 0);
ASSERT(b[0] == '\0');
ASSERT((n2 = mg_parse_multipart(f1 + n, f1_len - n, a, sizeof(a),
b, sizeof(b), &p, &len)) > 0);
ASSERT(len == 15);
ASSERT(memcmp(p, "another_content", len) == 0);
ASSERT(strcmp(a, "f2") == 0);
ASSERT(strcmp(b, "foo bar.txt") == 0);
ASSERT((n2 = mg_parse_multipart(f1 + n + n2, f1_len - (n + n2), a, sizeof(a),
b, sizeof(b), &p, &len)) == 0);
return NULL;
}
static int evh2(struct mg_connection *conn, enum mg_event ev) {
char *file_data, *cp = (char *) conn->connection_param;
int file_size, result = MG_FALSE;
switch (ev) {
case MG_AUTH:
result = MG_TRUE;
break;
case MG_CONNECT:
mg_printf(conn, "GET /%s HTTP/1.0\r\n\r\n", cp);
result = MG_TRUE;
break;
case MG_REQUEST:
break;
case MG_REPLY:
file_data = read_file("unit_test.c", &file_size);
sprintf(cp, "%d %s", (size_t) file_size == conn->content_len &&
memcmp(file_data, conn->content, file_size) == 0 ? 1 : 0,
conn->query_string == NULL ? "?" : conn->query_string);
free(file_data);
break;
default:
break;
}
return result;
}
static const char *test_mg_set_option(void) {
struct mg_server *server = mg_create_server(NULL, NULL);
ASSERT(mg_set_option(server, "listening_port", "0") == NULL);
ASSERT(mg_get_option(server, "listening_port")[0] != '\0');
mg_destroy_server(&server);
return NULL;
}
static const char *test_rewrites(void) {
char buf1[100] = "xx";
struct mg_server *server = mg_create_server(NULL, evh2);
struct mg_connection *conn;
const char *port;
ASSERT(mg_set_option(server, "listening_port", "0") == NULL);
ASSERT(mg_set_option(server, "document_root", ".") == NULL);
ASSERT(mg_set_option(server, "url_rewrites", "/xx=unit_test.c") == NULL);
ASSERT((port = mg_get_option(server, "listening_port")) != NULL);
ASSERT((conn = mg_connect(server, "127.0.0.1", atoi(port), 0)) != NULL);
conn->connection_param = buf1;
{ int i; for (i = 0; i < 50; i++) mg_poll_server(server, 1); }
ASSERT(strcmp(buf1, "1 ?") == 0);
mg_destroy_server(&server);
return NULL;
}
static const char *run_all_tests(void) {
RUN_TEST(test_should_keep_alive);
RUN_TEST(test_match_prefix);
RUN_TEST(test_remove_double_dots);
RUN_TEST(test_parse_http_message);
RUN_TEST(test_to64);
RUN_TEST(test_url_decode);
RUN_TEST(test_base64_encode);
RUN_TEST(test_mg_parse_header);
RUN_TEST(test_get_var);
RUN_TEST(test_next_option);
RUN_TEST(test_parse_multipart);
RUN_TEST(test_mg_set_option);
RUN_TEST(test_server);
RUN_TEST(test_rewrites);
return NULL;
}
int __cdecl main(void) {
const char *fail_msg = run_all_tests();
printf("%s, tests run: %d\n", fail_msg ? "FAIL" : "PASS", static_num_tests);
return fail_msg == NULL ? EXIT_SUCCESS : EXIT_FAILURE;
}
+43 -42
View File
@@ -3,59 +3,60 @@
#include <stdio.h> #include <stdio.h>
#include <string.h> #include <string.h>
#include <fcntl.h>
#include <stdlib.h>
#ifdef _WIN32
#include <windows.h>
#include <io.h>
#define strtoll strtol
typedef __int64 int64_t;
#else
#include <inttypes.h>
#include <unistd.h>
#endif // !_WIN32
#include "mongoose.h" #include "mongoose.h"
static int begin_request_handler(struct mg_connection *conn) { static void send_index_page(struct mg_connection *conn) {
if (!strcmp(mg_get_request_info(conn)->uri, "/handle_post_request")) { const char *data;
mg_printf(conn, "%s", "HTTP/1.0 200 OK\r\n\r\n"); int data_len;
mg_upload(conn, "/tmp"); char var_name[100], file_name[100];
} else {
// Show HTML form. Make sure it has enctype="multipart/form-data" attr.
static const char *html_form =
"<html><body>Upload example."
"<form method=\"POST\" action=\"/handle_post_request\" "
" enctype=\"multipart/form-data\">"
"<input type=\"file\" name=\"file\" /> <br/>"
"<input type=\"submit\" value=\"Upload\" />"
"</form></body></html>";
mg_printf(conn, "HTTP/1.0 200 OK\r\n" mg_printf_data(conn, "%s",
"Content-Length: %d\r\n" "<html><body>Upload example."
"Content-Type: text/html\r\n\r\n%s", "<form method=\"POST\" action=\"/handle_post_request\" "
(int) strlen(html_form), html_form); " enctype=\"multipart/form-data\">"
"<input type=\"file\" name=\"file\" /> <br/>"
"<input type=\"submit\" value=\"Upload\" />"
"</form>");
if (mg_parse_multipart(conn->content, conn->content_len,
var_name, sizeof(var_name),
file_name, sizeof(file_name),
&data, &data_len) > 0) {
mg_printf_data(conn, "%s", "Uploaded file:<pre>");
mg_send_data(conn, data, data_len);
mg_printf_data(conn, "%s", "/pre>");
} }
// Mark request as processed mg_printf_data(conn, "%s", "</body></html>");
return 1;
} }
static void upload_handler(struct mg_connection *conn, const char *path) { static int ev_handler(struct mg_connection *conn, enum mg_event ev) {
mg_printf(conn, "Saved [%s]", path); if (ev == MG_REQUEST) {
send_index_page(conn);
return MG_TRUE;
} else if (ev == MG_AUTH) {
return MG_TRUE;
} else {
return MG_FALSE;
}
} }
int main(void) { int main(void) {
struct mg_context *ctx; struct mg_server *server;
const char *options[] = {"listening_ports", "8080", NULL};
struct mg_callbacks callbacks;
memset(&callbacks, 0, sizeof(callbacks)); // Create and configure the server
callbacks.begin_request = begin_request_handler; server = mg_create_server(NULL, ev_handler);
callbacks.upload = upload_handler; mg_set_option(server, "listening_port", "8080");
ctx = mg_start(&callbacks, NULL, options);
getchar(); // Wait until user hits "enter" // Serve request. Hit Ctrl-C to terminate the program
mg_stop(ctx); printf("Starting on port %s\n", mg_get_option(server, "listening_port"));
for (;;) {
mg_poll_server(server, 1000);
}
// Cleanup, and free server instance
mg_destroy_server(&server);
return 0; return 0;
} }
+54 -31
View File
@@ -1,44 +1,67 @@
// Copyright (c) 2004-2012 Sergey Lyubka
// This file is a part of mongoose project, http://github.com/valenok/mongoose
#include <stdio.h>
#include <string.h> #include <string.h>
#include <time.h>
#include "mongoose.h" #include "mongoose.h"
static void websocket_ready_handler(struct mg_connection *conn) { #ifdef _WIN32
static const char *message = "server ready"; #define snprintf _snprintf
mg_websocket_write(conn, WEBSOCKET_OPCODE_TEXT, message, strlen(message)); #endif
extern const char *find_embedded_file(const char *, size_t *);
static int iterate_callback(struct mg_connection *c, enum mg_event ev) {
static int counter = 0;
if (ev == MG_POLL && c->is_websocket) {
char buf[20];
int len = snprintf(buf, sizeof(buf), "%d", counter++);
mg_websocket_write(c, 1, buf, len);
}
return MG_TRUE;
} }
// Arguments: static int send_reply(struct mg_connection *conn) {
// flags: first byte of websocket frame, see websocket RFC, size_t index_size;
// http://tools.ietf.org/html/rfc6455, section 5.2 const char *index_html = find_embedded_file("websocket.html", &index_size);
// data, data_len: payload data. Mask, if any, is already applied.
static int websocket_data_handler(struct mg_connection *conn, int flags,
char *data, size_t data_len) {
(void) flags; // Unused
mg_websocket_write(conn, WEBSOCKET_OPCODE_TEXT, data, data_len);
// Returning zero means stoping websocket conversation. if (conn->is_websocket) {
// Close the conversation if client has sent us "exit" string. // This handler is called for each incoming websocket frame, one or more
return memcmp(data, "exit", 4); // times for connection lifetime.
// Echo websocket data back to the client.
mg_websocket_write(conn, 1, conn->content, conn->content_len);
return conn->content_len == 4 && !memcmp(conn->content, "exit", 4) ?
MG_FALSE : MG_TRUE;
} else {
mg_send_header(conn, "Content-Type", "text/html");
mg_send_data(conn, index_html, index_size);
return MG_TRUE;
}
}
static int ev_handler(struct mg_connection *conn, enum mg_event ev) {
if (ev == MG_REQUEST) {
return send_reply(conn);
} else if (ev == MG_AUTH) {
return MG_TRUE;
} else {
return MG_FALSE;
}
} }
int main(void) { int main(void) {
struct mg_context *ctx; struct mg_server *server = mg_create_server(NULL, ev_handler);
struct mg_callbacks callbacks; time_t current_timer = 0, last_timer = time(NULL);
const char *options[] = {
"listening_ports", "8080",
"document_root", "websocket_html_root",
NULL
};
memset(&callbacks, 0, sizeof(callbacks)); mg_set_option(server, "listening_port", "8080");
callbacks.websocket_ready = websocket_ready_handler;
callbacks.websocket_data = websocket_data_handler;
ctx = mg_start(&callbacks, NULL, options);
getchar(); // Wait until user hits "enter"
mg_stop(ctx);
printf("Started on port %s\n", mg_get_option(server, "listening_port"));
for (;;) {
mg_poll_server(server, 100);
current_timer = time(NULL);
if (current_timer - last_timer > 0) {
last_timer = current_timer;
mg_iterate_over_connections(server, iterate_callback);
}
}
mg_destroy_server(&server);
return 0; return 0;
} }
+46
View File
@@ -0,0 +1,46 @@
<!DOCTYPE html>
<meta charset="utf-8" />
<title>WebSocket Test</title>
<script language="javascript" type="text/javascript">
var out = function(message) {
var div = document.createElement('div');
div.innerHTML = message;
document.getElementById('output').appendChild(div);
};
window.onload = function() {
var url = 'ws://' + location.host + '/ws';
var num_messages = 0;
websocket = new WebSocket(url);
websocket.onopen = function(ev) {
out('CONNECTED');
var msg = 'Не всё подчиняется разуму. Но всё подчиняется упорству. ';
out('SENT: ' + msg);
websocket.send(msg);
};
websocket.onclose = function(ev) {
out('DISCONNECTED');
};
websocket.onmessage = function(ev) {
if (!ev.data) {
out('<span style="color: blue;">PING... </span>');
} else {
out('<span style="color: blue;">RESPONSE: ' + ev.data + ' </span>');
num_messages++;
}
if (num_messages > 3) {
websocket.send('exit');
}
};
websocket.onerror = function(ev) {
out('<span style="color: red; ">ERROR: </span> ' + ev.data);
};
};
</script>
<style> div {font: small Verdana; } </style>
<h2>Mongoose WebSocket Test</h2>
<div id="output"></div>
</html>
-44
View File
@@ -1,44 +0,0 @@
<!DOCTYPE html>
<meta charset="utf-8" />
<title>WebSocket Test</title>
<script language="javascript" type="text/javascript">
var writeToScreen = function(message) {
var div = document.createElement('div');
div.innerHTML = message;
document.getElementById('output').appendChild(div);
};
window.onload = function() {
var url = 'ws://' + window.location.host + '/foo';
websocket = new WebSocket(url);
websocket.onopen = function(ev) {
writeToScreen('CONNECTED');
var message = 'Не всё подчиняется разуму. Но всё подчиняется упорству. ';
writeToScreen('SENT: ' + message);
websocket.send(message);
};
websocket.onclose = function(ev) {
writeToScreen('DISCONNECTED');
};
websocket.onmessage = function(ev) {
writeToScreen('<span style="color: blue;">RESPONSE: ' + ev.data +
' </span>');
websocket.send('exit');
};
websocket.onerror = function(ev) {
writeToScreen('<span style="color: red; ">ERROR: </span> ' + ev.data);
};
};
</script>
<style> div {font: small Verdana; } </style>
<h2>Mongoose WebSocket Test</h2>
<div style="width: 400px; color: #aaa; padding: 1em; ">
This page code creates websocket to the URI "/foo",
sends a message to it, waits for the reply, then sends an "exit" message.
Server must echo all messages back, and terminate the conversation after
receiving the "exit" message.
</div>
<div id="output"></div>
</html>
-114
View File
@@ -1,114 +0,0 @@
# Makefile for installing Lua
# See doc/readme.html for installation and customization instructions.
# == CHANGE THE SETTINGS BELOW TO SUIT YOUR ENVIRONMENT =======================
# Your platform. See PLATS for possible values.
PLAT= none
# Where to install. The installation starts in the src and doc directories,
# so take care if INSTALL_TOP is not an absolute path. See the local target.
# You may want to make INSTALL_LMOD and INSTALL_CMOD consistent with
# LUA_ROOT, LUA_LDIR, and LUA_CDIR in luaconf.h.
INSTALL_TOP= /usr/local
INSTALL_BIN= $(INSTALL_TOP)/bin
INSTALL_INC= $(INSTALL_TOP)/include
INSTALL_LIB= $(INSTALL_TOP)/lib
INSTALL_MAN= $(INSTALL_TOP)/man/man1
INSTALL_LMOD= $(INSTALL_TOP)/share/lua/$V
INSTALL_CMOD= $(INSTALL_TOP)/lib/lua/$V
# How to install. If your install program does not support "-p", then
# you may have to run ranlib on the installed liblua.a.
INSTALL= install -p
INSTALL_EXEC= $(INSTALL) -m 0755
INSTALL_DATA= $(INSTALL) -m 0644
#
# If you don't have "install" you can use "cp" instead.
# INSTALL= cp -p
# INSTALL_EXEC= $(INSTALL)
# INSTALL_DATA= $(INSTALL)
# Other utilities.
MKDIR= mkdir -p
RM= rm -f
# == END OF USER SETTINGS -- NO NEED TO CHANGE ANYTHING BELOW THIS LINE =======
# Convenience platforms targets.
PLATS= aix ansi bsd freebsd generic linux macosx mingw posix solaris
# What to install.
TO_BIN= lua luac
TO_INC= lua.h luaconf.h lualib.h lauxlib.h lua.hpp
TO_LIB= liblua.a
TO_MAN= lua.1 luac.1
# Lua version and release.
V= 5.2
R= $V.1
# Targets start here.
all: $(PLAT)
$(PLATS) clean:
cd src && $(MAKE) $@
test: dummy
src/lua -v
install: dummy
cd src && $(MKDIR) $(INSTALL_BIN) $(INSTALL_INC) $(INSTALL_LIB) $(INSTALL_MAN) $(INSTALL_LMOD) $(INSTALL_CMOD)
cd src && $(INSTALL_EXEC) $(TO_BIN) $(INSTALL_BIN)
cd src && $(INSTALL_DATA) $(TO_INC) $(INSTALL_INC)
cd src && $(INSTALL_DATA) $(TO_LIB) $(INSTALL_LIB)
cd doc && $(INSTALL_DATA) $(TO_MAN) $(INSTALL_MAN)
uninstall:
cd src && cd $(INSTALL_BIN) && $(RM) $(TO_BIN)
cd src && cd $(INSTALL_INC) && $(RM) $(TO_INC)
cd src && cd $(INSTALL_LIB) && $(RM) $(TO_LIB)
cd doc && cd $(INSTALL_MAN) && $(RM) $(TO_MAN)
local:
$(MAKE) install INSTALL_TOP=../install
none:
@echo "Please do 'make PLATFORM' where PLATFORM is one of these:"
@echo " $(PLATS)"
@echo "See doc/readme.html for complete instructions."
# make may get confused with test/ and install/
dummy:
# echo config parameters
echo:
@cd src && $(MAKE) -s echo
@echo "PLAT= $(PLAT)"
@echo "V= $V"
@echo "R= $R"
@echo "TO_BIN= $(TO_BIN)"
@echo "TO_INC= $(TO_INC)"
@echo "TO_LIB= $(TO_LIB)"
@echo "TO_MAN= $(TO_MAN)"
@echo "INSTALL_TOP= $(INSTALL_TOP)"
@echo "INSTALL_BIN= $(INSTALL_BIN)"
@echo "INSTALL_INC= $(INSTALL_INC)"
@echo "INSTALL_LIB= $(INSTALL_LIB)"
@echo "INSTALL_MAN= $(INSTALL_MAN)"
@echo "INSTALL_LMOD= $(INSTALL_LMOD)"
@echo "INSTALL_CMOD= $(INSTALL_CMOD)"
@echo "INSTALL_EXEC= $(INSTALL_EXEC)"
@echo "INSTALL_DATA= $(INSTALL_DATA)"
# echo pkg-config data
pc:
@echo "version=$R"
@echo "prefix=$(INSTALL_TOP)"
@echo "libdir=$(INSTALL_LIB)"
@echo "includedir=$(INSTALL_INC)"
# list targets that do not create files (but not all makes understand .PHONY)
.PHONY: all $(PLATS) clean test install local none dummy echo pecho lecho
# (end of Makefile)
-6
View File
@@ -1,6 +0,0 @@
This is Lua 5.2.1, released on 08 Jun 2012.
For installation instructions, license details, and
further information about Lua, see doc/readme.html.
-531
View File
@@ -1,531 +0,0 @@
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<HTML>
<HEAD>
<TITLE>Lua 5.2 Reference Manual - contents</TITLE>
<LINK REL="stylesheet" TYPE="text/css" HREF="lua.css">
<META HTTP-EQUIV="content-type" CONTENT="text/html; charset=iso-8859-1">
<STYLE TYPE="text/css">
ul {
list-style-type: none ;
list-style-position: outside ;
}
</STYLE>
</HEAD>
<BODY>
<HR>
<H1>
<A HREF="http://www.lua.org/"><IMG SRC="logo.gif" ALT="" BORDER=0></A>
Lua 5.2 Reference Manual
</H1>
<P>
The reference manual is the official definition of the Lua language.
For a complete introduction to Lua programming, see the book
<A HREF="http://www.lua.org/docs.html#books">Programming in Lua</A>.
<P>
<A HREF="manual.html">start</A>
&middot;
<A HREF="#contents">contents</A>
&middot;
<A HREF="#index">index</A>
<HR>
<SMALL>
Copyright &copy; 2011&ndash;2012 Lua.org, PUC-Rio.
Freely available under the terms of the
<A HREF="http://www.lua.org/license.html">Lua license</A>.
</SMALL>
<H2><A NAME="contents">Contents</A></H2>
<UL style="padding: 0">
<LI><A HREF="manual.html">1 &ndash; Introduction</A>
<P>
<LI><A HREF="manual.html#2">2 &ndash; Basic Concepts</A>
<UL>
<LI><A HREF="manual.html#2.1">2.1 &ndash; Values and Types</A>
<LI><A HREF="manual.html#2.2">2.2 &ndash; Environments and the Global Environment</A>
<LI><A HREF="manual.html#2.3">2.3 &ndash; Error Handling</A>
<LI><A HREF="manual.html#2.4">2.4 &ndash; Metatables and Metamethods</A>
<LI><A HREF="manual.html#2.5">2.5 &ndash; Garbage Collection</A>
<UL>
<LI><A HREF="manual.html#2.5.1">2.5.1 &ndash; Garbage-Collection Metamethods</A>
<LI><A HREF="manual.html#2.5.2">2.5.2 &ndash; Weak Tables</A>
</UL>
<LI><A HREF="manual.html#2.6">2.6 &ndash; Coroutines</A>
</UL>
<P>
<LI><A HREF="manual.html#3">3 &ndash; The Language</A>
<UL>
<LI><A HREF="manual.html#3.1">3.1 &ndash; Lexical Conventions</A>
<LI><A HREF="manual.html#3.2">3.2 &ndash; Variables</A>
<LI><A HREF="manual.html#3.3">3.3 &ndash; Statements</A>
<UL>
<LI><A HREF="manual.html#3.3.1">3.3.1 &ndash; Blocks</A>
<LI><A HREF="manual.html#3.3.2">3.3.2 &ndash; Chunks</A>
<LI><A HREF="manual.html#3.3.3">3.3.3 &ndash; Assignment</A>
<LI><A HREF="manual.html#3.3.4">3.3.4 &ndash; Control Structures</A>
<LI><A HREF="manual.html#3.3.5">3.3.5 &ndash; For Statement</A>
<LI><A HREF="manual.html#3.3.6">3.3.6 &ndash; Function Calls as Statements</A>
<LI><A HREF="manual.html#3.3.7">3.3.7 &ndash; Local Declarations</A>
</UL>
<LI><A HREF="manual.html#3.4">3.4 &ndash; Expressions</A>
<UL>
<LI><A HREF="manual.html#3.4.1">3.4.1 &ndash; Arithmetic Operators</A>
<LI><A HREF="manual.html#3.4.2">3.4.2 &ndash; Coercion</A>
<LI><A HREF="manual.html#3.4.3">3.4.3 &ndash; Relational Operators</A>
<LI><A HREF="manual.html#3.4.4">3.4.4 &ndash; Logical Operators</A>
<LI><A HREF="manual.html#3.4.5">3.4.5 &ndash; Concatenation</A>
<LI><A HREF="manual.html#3.4.6">3.4.6 &ndash; The Length Operator</A>
<LI><A HREF="manual.html#3.4.7">3.4.7 &ndash; Precedence</A>
<LI><A HREF="manual.html#3.4.8">3.4.8 &ndash; Table Constructors</A>
<LI><A HREF="manual.html#3.4.9">3.4.9 &ndash; Function Calls</A>
<LI><A HREF="manual.html#3.4.10">3.4.10 &ndash; Function Definitions</A>
</UL>
<LI><A HREF="manual.html#3.5">3.5 &ndash; Visibility Rules</A>
</UL>
<P>
<LI><A HREF="manual.html#4">4 &ndash; The Application Program Interface</A>
<UL>
<LI><A HREF="manual.html#4.1">4.1 &ndash; The Stack</A>
<LI><A HREF="manual.html#4.2">4.2 &ndash; Stack Size</A>
<LI><A HREF="manual.html#4.3">4.3 &ndash; Valid and Acceptable Indices</A>
<LI><A HREF="manual.html#4.4">4.4 &ndash; C Closures</A>
<LI><A HREF="manual.html#4.5">4.5 &ndash; Registry</A>
<LI><A HREF="manual.html#4.6">4.6 &ndash; Error Handling in C</A>
<LI><A HREF="manual.html#4.7">4.7 &ndash; Handling Yields in C</A>
<LI><A HREF="manual.html#4.8">4.8 &ndash; Functions and Types</A>
<LI><A HREF="manual.html#4.9">4.9 &ndash; The Debug Interface</A>
</UL>
<P>
<LI><A HREF="manual.html#5">5 &ndash; The Auxiliary Library</A>
<UL>
<LI><A HREF="manual.html#5.1">5.1 &ndash; Functions and Types</A>
</UL>
<P>
<LI><A HREF="manual.html#6">6 &ndash; Standard Libraries</A>
<UL>
<LI><A HREF="manual.html#6.1">6.1 &ndash; Basic Functions</A>
<LI><A HREF="manual.html#6.2">6.2 &ndash; Coroutine Manipulation</A>
<LI><A HREF="manual.html#6.3">6.3 &ndash; Modules</A>
<LI><A HREF="manual.html#6.4">6.4 &ndash; String Manipulation</A>
<UL>
<LI><A HREF="manual.html#6.4.1">6.4.1 &ndash; Patterns</A>
</UL>
<LI><A HREF="manual.html#6.5">6.5 &ndash; Table Manipulation</A>
<LI><A HREF="manual.html#6.6">6.6 &ndash; Mathematical Functions</A>
<LI><A HREF="manual.html#6.7">6.7 &ndash; Bitwise Operations</A>
<LI><A HREF="manual.html#6.8">6.8 &ndash; Input and Output Facilities</A>
<LI><A HREF="manual.html#6.9">6.9 &ndash; Operating System Facilities</A>
<LI><A HREF="manual.html#6.10">6.10 &ndash; The Debug Library</A>
</UL>
<P>
<LI><A HREF="manual.html#7">7 &ndash; Lua Standalone</A>
<P>
<LI><A HREF="manual.html#8">8 &ndash; Incompatibilities with the Previous Version</A>
<UL>
<LI><A HREF="manual.html#8.1">8.1 &ndash; Changes in the Language</A>
<LI><A HREF="manual.html#8.2">8.2 &ndash; Changes in the Libraries</A>
<LI><A HREF="manual.html#8.3">8.3 &ndash; Changes in the API</A>
</UL>
<P>
<LI><A HREF="manual.html#9">9 &ndash; The Complete Syntax of Lua</A>
</UL>
<H2><A NAME="index">Index</A></H2>
<TABLE WIDTH="100%">
<TR VALIGN="top">
<TD>
<H3><A NAME="functions">Lua functions</A></H3>
<P>
<A HREF="manual.html#pdf-_G">_G</A><BR>
<A HREF="manual.html#pdf-_VERSION">_VERSION</A><BR>
<P>
<A HREF="manual.html#pdf-assert">assert</A><BR>
<A HREF="manual.html#pdf-collectgarbage">collectgarbage</A><BR>
<A HREF="manual.html#pdf-dofile">dofile</A><BR>
<A HREF="manual.html#pdf-error">error</A><BR>
<A HREF="manual.html#pdf-getmetatable">getmetatable</A><BR>
<A HREF="manual.html#pdf-ipairs">ipairs</A><BR>
<A HREF="manual.html#pdf-loadfile">loadfile</A><BR>
<A HREF="manual.html#pdf-load">load</A><BR>
<A HREF="manual.html#pdf-next">next</A><BR>
<A HREF="manual.html#pdf-pairs">pairs</A><BR>
<A HREF="manual.html#pdf-pcall">pcall</A><BR>
<A HREF="manual.html#pdf-print">print</A><BR>
<A HREF="manual.html#pdf-rawequal">rawequal</A><BR>
<A HREF="manual.html#pdf-rawget">rawget</A><BR>
<A HREF="manual.html#pdf-rawlen">rawlen</A><BR>
<A HREF="manual.html#pdf-rawset">rawset</A><BR>
<A HREF="manual.html#pdf-require">require</A><BR>
<A HREF="manual.html#pdf-select">select</A><BR>
<A HREF="manual.html#pdf-setmetatable">setmetatable</A><BR>
<A HREF="manual.html#pdf-tonumber">tonumber</A><BR>
<A HREF="manual.html#pdf-tostring">tostring</A><BR>
<A HREF="manual.html#pdf-type">type</A><BR>
<A HREF="manual.html#pdf-xpcall">xpcall</A><BR>
<P>
<A HREF="manual.html#pdf-bit32.arshift">bit32.arshift</A><BR>
<A HREF="manual.html#pdf-bit32.band">bit32.band</A><BR>
<A HREF="manual.html#pdf-bit32.bnot">bit32.bnot</A><BR>
<A HREF="manual.html#pdf-bit32.bor">bit32.bor</A><BR>
<A HREF="manual.html#pdf-bit32.btest">bit32.btest</A><BR>
<A HREF="manual.html#pdf-bit32.bxor">bit32.bxor</A><BR>
<A HREF="manual.html#pdf-bit32.extract">bit32.extract</A><BR>
<A HREF="manual.html#pdf-bit32.lrotate">bit32.lrotate</A><BR>
<A HREF="manual.html#pdf-bit32.lshift">bit32.lshift</A><BR>
<A HREF="manual.html#pdf-bit32.replace">bit32.replace</A><BR>
<A HREF="manual.html#pdf-bit32.rrotate">bit32.rrotate</A><BR>
<A HREF="manual.html#pdf-bit32.rshift">bit32.rshift</A><BR>
<P>
<A HREF="manual.html#pdf-coroutine.create">coroutine.create</A><BR>
<A HREF="manual.html#pdf-coroutine.resume">coroutine.resume</A><BR>
<A HREF="manual.html#pdf-coroutine.running">coroutine.running</A><BR>
<A HREF="manual.html#pdf-coroutine.status">coroutine.status</A><BR>
<A HREF="manual.html#pdf-coroutine.wrap">coroutine.wrap</A><BR>
<A HREF="manual.html#pdf-coroutine.yield">coroutine.yield</A><BR>
<P>
<A HREF="manual.html#pdf-debug.debug">debug.debug</A><BR>
<A HREF="manual.html#pdf-debug.getuservalue">debug.getuservalue</A><BR>
<A HREF="manual.html#pdf-debug.gethook">debug.gethook</A><BR>
<A HREF="manual.html#pdf-debug.getinfo">debug.getinfo</A><BR>
<A HREF="manual.html#pdf-debug.getlocal">debug.getlocal</A><BR>
<A HREF="manual.html#pdf-debug.getmetatable">debug.getmetatable</A><BR>
<A HREF="manual.html#pdf-debug.getregistry">debug.getregistry</A><BR>
<A HREF="manual.html#pdf-debug.getupvalue">debug.getupvalue</A><BR>
<A HREF="manual.html#pdf-debug.setuservalue">debug.setuservalue</A><BR>
<A HREF="manual.html#pdf-debug.sethook">debug.sethook</A><BR>
<A HREF="manual.html#pdf-debug.setlocal">debug.setlocal</A><BR>
<A HREF="manual.html#pdf-debug.setmetatable">debug.setmetatable</A><BR>
<A HREF="manual.html#pdf-debug.setupvalue">debug.setupvalue</A><BR>
<A HREF="manual.html#pdf-debug.traceback">debug.traceback</A><BR>
<A HREF="manual.html#pdf-debug.upvalueid">debug.upvalueid</A><BR>
<A HREF="manual.html#pdf-debug.upvaluejoin">debug.upvaluejoin</A><BR>
<P>
<A HREF="manual.html#pdf-file:close">file:close</A><BR>
<A HREF="manual.html#pdf-file:flush">file:flush</A><BR>
<A HREF="manual.html#pdf-file:lines">file:lines</A><BR>
<A HREF="manual.html#pdf-file:read">file:read</A><BR>
<A HREF="manual.html#pdf-file:seek">file:seek</A><BR>
<A HREF="manual.html#pdf-file:setvbuf">file:setvbuf</A><BR>
<A HREF="manual.html#pdf-file:write">file:write</A><BR>
<P>
<A HREF="manual.html#pdf-io.close">io.close</A><BR>
<A HREF="manual.html#pdf-io.flush">io.flush</A><BR>
<A HREF="manual.html#pdf-io.input">io.input</A><BR>
<A HREF="manual.html#pdf-io.lines">io.lines</A><BR>
<A HREF="manual.html#pdf-io.open">io.open</A><BR>
<A HREF="manual.html#pdf-io.output">io.output</A><BR>
<A HREF="manual.html#pdf-io.popen">io.popen</A><BR>
<A HREF="manual.html#pdf-io.read">io.read</A><BR>
<A HREF="manual.html#pdf-io.stderr">io.stderr</A><BR>
<A HREF="manual.html#pdf-io.stdin">io.stdin</A><BR>
<A HREF="manual.html#pdf-io.stdout">io.stdout</A><BR>
<A HREF="manual.html#pdf-io.tmpfile">io.tmpfile</A><BR>
<A HREF="manual.html#pdf-io.type">io.type</A><BR>
<A HREF="manual.html#pdf-io.write">io.write</A><BR>
</TD>
<TD>
<H3>&nbsp;</H3>
<P>
<A HREF="manual.html#pdf-math.abs">math.abs</A><BR>
<A HREF="manual.html#pdf-math.acos">math.acos</A><BR>
<A HREF="manual.html#pdf-math.asin">math.asin</A><BR>
<A HREF="manual.html#pdf-math.atan">math.atan</A><BR>
<A HREF="manual.html#pdf-math.atan2">math.atan2</A><BR>
<A HREF="manual.html#pdf-math.ceil">math.ceil</A><BR>
<A HREF="manual.html#pdf-math.cos">math.cos</A><BR>
<A HREF="manual.html#pdf-math.cosh">math.cosh</A><BR>
<A HREF="manual.html#pdf-math.deg">math.deg</A><BR>
<A HREF="manual.html#pdf-math.exp">math.exp</A><BR>
<A HREF="manual.html#pdf-math.floor">math.floor</A><BR>
<A HREF="manual.html#pdf-math.fmod">math.fmod</A><BR>
<A HREF="manual.html#pdf-math.frexp">math.frexp</A><BR>
<A HREF="manual.html#pdf-math.huge">math.huge</A><BR>
<A HREF="manual.html#pdf-math.ldexp">math.ldexp</A><BR>
<A HREF="manual.html#pdf-math.log">math.log</A><BR>
<A HREF="manual.html#pdf-math.max">math.max</A><BR>
<A HREF="manual.html#pdf-math.min">math.min</A><BR>
<A HREF="manual.html#pdf-math.modf">math.modf</A><BR>
<A HREF="manual.html#pdf-math.pi">math.pi</A><BR>
<A HREF="manual.html#pdf-math.pow">math.pow</A><BR>
<A HREF="manual.html#pdf-math.rad">math.rad</A><BR>
<A HREF="manual.html#pdf-math.random">math.random</A><BR>
<A HREF="manual.html#pdf-math.randomseed">math.randomseed</A><BR>
<A HREF="manual.html#pdf-math.sin">math.sin</A><BR>
<A HREF="manual.html#pdf-math.sinh">math.sinh</A><BR>
<A HREF="manual.html#pdf-math.sqrt">math.sqrt</A><BR>
<A HREF="manual.html#pdf-math.tan">math.tan</A><BR>
<A HREF="manual.html#pdf-math.tanh">math.tanh</A><BR>
<P>
<A HREF="manual.html#pdf-os.clock">os.clock</A><BR>
<A HREF="manual.html#pdf-os.date">os.date</A><BR>
<A HREF="manual.html#pdf-os.difftime">os.difftime</A><BR>
<A HREF="manual.html#pdf-os.execute">os.execute</A><BR>
<A HREF="manual.html#pdf-os.exit">os.exit</A><BR>
<A HREF="manual.html#pdf-os.getenv">os.getenv</A><BR>
<A HREF="manual.html#pdf-os.remove">os.remove</A><BR>
<A HREF="manual.html#pdf-os.rename">os.rename</A><BR>
<A HREF="manual.html#pdf-os.setlocale">os.setlocale</A><BR>
<A HREF="manual.html#pdf-os.time">os.time</A><BR>
<A HREF="manual.html#pdf-os.tmpname">os.tmpname</A><BR>
<P>
<A HREF="manual.html#pdf-package.config">package.config</A><BR>
<A HREF="manual.html#pdf-package.cpath">package.cpath</A><BR>
<A HREF="manual.html#pdf-package.loaded">package.loaded</A><BR>
<A HREF="manual.html#pdf-package.loadlib">package.loadlib</A><BR>
<A HREF="manual.html#pdf-package.path">package.path</A><BR>
<A HREF="manual.html#pdf-package.preload">package.preload</A><BR>
<A HREF="manual.html#pdf-package.searchers">package.searchers</A><BR>
<A HREF="manual.html#pdf-package.searchpath">package.searchpath</A><BR>
<P>
<A HREF="manual.html#pdf-string.byte">string.byte</A><BR>
<A HREF="manual.html#pdf-string.char">string.char</A><BR>
<A HREF="manual.html#pdf-string.dump">string.dump</A><BR>
<A HREF="manual.html#pdf-string.find">string.find</A><BR>
<A HREF="manual.html#pdf-string.format">string.format</A><BR>
<A HREF="manual.html#pdf-string.gmatch">string.gmatch</A><BR>
<A HREF="manual.html#pdf-string.gsub">string.gsub</A><BR>
<A HREF="manual.html#pdf-string.len">string.len</A><BR>
<A HREF="manual.html#pdf-string.lower">string.lower</A><BR>
<A HREF="manual.html#pdf-string.match">string.match</A><BR>
<A HREF="manual.html#pdf-string.rep">string.rep</A><BR>
<A HREF="manual.html#pdf-string.reverse">string.reverse</A><BR>
<A HREF="manual.html#pdf-string.sub">string.sub</A><BR>
<A HREF="manual.html#pdf-string.upper">string.upper</A><BR>
<P>
<A HREF="manual.html#pdf-table.concat">table.concat</A><BR>
<A HREF="manual.html#pdf-table.insert">table.insert</A><BR>
<A HREF="manual.html#pdf-table.pack">table.pack</A><BR>
<A HREF="manual.html#pdf-table.remove">table.remove</A><BR>
<A HREF="manual.html#pdf-table.sort">table.sort</A><BR>
<A HREF="manual.html#pdf-table.unpack">table.unpack</A><BR>
</TD>
<TD>
<H3>C API</H3>
<P>
<A HREF="manual.html#lua_Alloc">lua_Alloc</A><BR>
<A HREF="manual.html#lua_CFunction">lua_CFunction</A><BR>
<A HREF="manual.html#lua_Debug">lua_Debug</A><BR>
<A HREF="manual.html#lua_Hook">lua_Hook</A><BR>
<A HREF="manual.html#lua_Integer">lua_Integer</A><BR>
<A HREF="manual.html#lua_Number">lua_Number</A><BR>
<A HREF="manual.html#lua_Reader">lua_Reader</A><BR>
<A HREF="manual.html#lua_State">lua_State</A><BR>
<A HREF="manual.html#lua_Unsigned">lua_Unsigned</A><BR>
<A HREF="manual.html#lua_Writer">lua_Writer</A><BR>
<P>
<A HREF="manual.html#lua_absindex">lua_absindex</A><BR>
<A HREF="manual.html#lua_arith">lua_arith</A><BR>
<A HREF="manual.html#lua_atpanic">lua_atpanic</A><BR>
<A HREF="manual.html#lua_call">lua_call</A><BR>
<A HREF="manual.html#lua_callk">lua_callk</A><BR>
<A HREF="manual.html#lua_checkstack">lua_checkstack</A><BR>
<A HREF="manual.html#lua_close">lua_close</A><BR>
<A HREF="manual.html#lua_compare">lua_compare</A><BR>
<A HREF="manual.html#lua_concat">lua_concat</A><BR>
<A HREF="manual.html#lua_copy">lua_copy</A><BR>
<A HREF="manual.html#lua_createtable">lua_createtable</A><BR>
<A HREF="manual.html#lua_dump">lua_dump</A><BR>
<A HREF="manual.html#lua_error">lua_error</A><BR>
<A HREF="manual.html#lua_gc">lua_gc</A><BR>
<A HREF="manual.html#lua_getallocf">lua_getallocf</A><BR>
<A HREF="manual.html#lua_getctx">lua_getctx</A><BR>
<A HREF="manual.html#lua_getfield">lua_getfield</A><BR>
<A HREF="manual.html#lua_getglobal">lua_getglobal</A><BR>
<A HREF="manual.html#lua_gethook">lua_gethook</A><BR>
<A HREF="manual.html#lua_gethookcount">lua_gethookcount</A><BR>
<A HREF="manual.html#lua_gethookmask">lua_gethookmask</A><BR>
<A HREF="manual.html#lua_getinfo">lua_getinfo</A><BR>
<A HREF="manual.html#lua_getlocal">lua_getlocal</A><BR>
<A HREF="manual.html#lua_getmetatable">lua_getmetatable</A><BR>
<A HREF="manual.html#lua_getstack">lua_getstack</A><BR>
<A HREF="manual.html#lua_gettable">lua_gettable</A><BR>
<A HREF="manual.html#lua_gettop">lua_gettop</A><BR>
<A HREF="manual.html#lua_getupvalue">lua_getupvalue</A><BR>
<A HREF="manual.html#lua_getuservalue">lua_getuservalue</A><BR>
<A HREF="manual.html#lua_insert">lua_insert</A><BR>
<A HREF="manual.html#lua_isboolean">lua_isboolean</A><BR>
<A HREF="manual.html#lua_iscfunction">lua_iscfunction</A><BR>
<A HREF="manual.html#lua_isfunction">lua_isfunction</A><BR>
<A HREF="manual.html#lua_islightuserdata">lua_islightuserdata</A><BR>
<A HREF="manual.html#lua_isnil">lua_isnil</A><BR>
<A HREF="manual.html#lua_isnone">lua_isnone</A><BR>
<A HREF="manual.html#lua_isnoneornil">lua_isnoneornil</A><BR>
<A HREF="manual.html#lua_isnumber">lua_isnumber</A><BR>
<A HREF="manual.html#lua_isstring">lua_isstring</A><BR>
<A HREF="manual.html#lua_istable">lua_istable</A><BR>
<A HREF="manual.html#lua_isthread">lua_isthread</A><BR>
<A HREF="manual.html#lua_isuserdata">lua_isuserdata</A><BR>
<A HREF="manual.html#lua_len">lua_len</A><BR>
<A HREF="manual.html#lua_load">lua_load</A><BR>
<A HREF="manual.html#lua_newstate">lua_newstate</A><BR>
<A HREF="manual.html#lua_newtable">lua_newtable</A><BR>
<A HREF="manual.html#lua_newthread">lua_newthread</A><BR>
<A HREF="manual.html#lua_newuserdata">lua_newuserdata</A><BR>
<A HREF="manual.html#lua_next">lua_next</A><BR>
<A HREF="manual.html#lua_pcall">lua_pcall</A><BR>
<A HREF="manual.html#lua_pcallk">lua_pcallk</A><BR>
<A HREF="manual.html#lua_pop">lua_pop</A><BR>
<A HREF="manual.html#lua_pushboolean">lua_pushboolean</A><BR>
<A HREF="manual.html#lua_pushcclosure">lua_pushcclosure</A><BR>
<A HREF="manual.html#lua_pushcfunction">lua_pushcfunction</A><BR>
<A HREF="manual.html#lua_pushfstring">lua_pushfstring</A><BR>
<A HREF="manual.html#lua_pushinteger">lua_pushinteger</A><BR>
<A HREF="manual.html#lua_pushlightuserdata">lua_pushlightuserdata</A><BR>
<A HREF="manual.html#lua_pushliteral">lua_pushliteral</A><BR>
<A HREF="manual.html#lua_pushlstring">lua_pushlstring</A><BR>
<A HREF="manual.html#lua_pushnil">lua_pushnil</A><BR>
<A HREF="manual.html#lua_pushnumber">lua_pushnumber</A><BR>
<A HREF="manual.html#lua_pushstring">lua_pushstring</A><BR>
<A HREF="manual.html#lua_pushthread">lua_pushthread</A><BR>
<A HREF="manual.html#lua_pushvalue">lua_pushvalue</A><BR>
<A HREF="manual.html#lua_pushvfstring">lua_pushvfstring</A><BR>
<A HREF="manual.html#lua_rawequal">lua_rawequal</A><BR>
<A HREF="manual.html#lua_rawget">lua_rawget</A><BR>
<A HREF="manual.html#lua_rawgeti">lua_rawgeti</A><BR>
<A HREF="manual.html#lua_rawlen">lua_rawlen</A><BR>
<A HREF="manual.html#lua_rawset">lua_rawset</A><BR>
<A HREF="manual.html#lua_rawseti">lua_rawseti</A><BR>
<A HREF="manual.html#lua_rawgetp">lua_rawgetp</A><BR>
<A HREF="manual.html#lua_rawsetp">lua_rawsetp</A><BR>
<A HREF="manual.html#lua_register">lua_register</A><BR>
<A HREF="manual.html#lua_remove">lua_remove</A><BR>
<A HREF="manual.html#lua_replace">lua_replace</A><BR>
<A HREF="manual.html#lua_resume">lua_resume</A><BR>
<A HREF="manual.html#lua_setallocf">lua_setallocf</A><BR>
<A HREF="manual.html#lua_setfield">lua_setfield</A><BR>
<A HREF="manual.html#lua_setglobal">lua_setglobal</A><BR>
<A HREF="manual.html#lua_sethook">lua_sethook</A><BR>
<A HREF="manual.html#lua_setlocal">lua_setlocal</A><BR>
<A HREF="manual.html#lua_setmetatable">lua_setmetatable</A><BR>
<A HREF="manual.html#lua_settable">lua_settable</A><BR>
<A HREF="manual.html#lua_settop">lua_settop</A><BR>
<A HREF="manual.html#lua_setupvalue">lua_setupvalue</A><BR>
<A HREF="manual.html#lua_setuservalue">lua_setuservalue</A><BR>
<A HREF="manual.html#lua_status">lua_status</A><BR>
<A HREF="manual.html#lua_toboolean">lua_toboolean</A><BR>
<A HREF="manual.html#lua_tocfunction">lua_tocfunction</A><BR>
<A HREF="manual.html#lua_tointeger">lua_tointeger</A><BR>
<A HREF="manual.html#lua_tointegerx">lua_tointegerx</A><BR>
<A HREF="manual.html#lua_tolstring">lua_tolstring</A><BR>
<A HREF="manual.html#lua_tonumber">lua_tonumber</A><BR>
<A HREF="manual.html#lua_tonumberx">lua_tonumberx</A><BR>
<A HREF="manual.html#lua_topointer">lua_topointer</A><BR>
<A HREF="manual.html#lua_tostring">lua_tostring</A><BR>
<A HREF="manual.html#lua_tothread">lua_tothread</A><BR>
<A HREF="manual.html#lua_tounsigned">lua_tounsigned</A><BR>
<A HREF="manual.html#lua_tounsignedx">lua_tounsignedx</A><BR>
<A HREF="manual.html#lua_touserdata">lua_touserdata</A><BR>
<A HREF="manual.html#lua_type">lua_type</A><BR>
<A HREF="manual.html#lua_typename">lua_typename</A><BR>
<A HREF="manual.html#lua_upvalueid">lua_upvalueid</A><BR>
<A HREF="manual.html#lua_upvalueindex">lua_upvalueindex</A><BR>
<A HREF="manual.html#lua_upvaluejoin">lua_upvaluejoin</A><BR>
<A HREF="manual.html#lua_version">lua_version</A><BR>
<A HREF="manual.html#lua_xmove">lua_xmove</A><BR>
<A HREF="manual.html#lua_yield">lua_yield</A><BR>
<A HREF="manual.html#lua_yieldk">lua_yieldk</A><BR>
</TD>
<TD>
<H3>auxiliary library</H3>
<P>
<A HREF="manual.html#luaL_Buffer">luaL_Buffer</A><BR>
<A HREF="manual.html#luaL_Reg">luaL_Reg</A><BR>
<P>
<A HREF="manual.html#luaL_addchar">luaL_addchar</A><BR>
<A HREF="manual.html#luaL_addlstring">luaL_addlstring</A><BR>
<A HREF="manual.html#luaL_addsize">luaL_addsize</A><BR>
<A HREF="manual.html#luaL_addstring">luaL_addstring</A><BR>
<A HREF="manual.html#luaL_addvalue">luaL_addvalue</A><BR>
<A HREF="manual.html#luaL_argcheck">luaL_argcheck</A><BR>
<A HREF="manual.html#luaL_argerror">luaL_argerror</A><BR>
<A HREF="manual.html#luaL_buffinit">luaL_buffinit</A><BR>
<A HREF="manual.html#luaL_buffinitsize">luaL_buffinitsize</A><BR>
<A HREF="manual.html#luaL_callmeta">luaL_callmeta</A><BR>
<A HREF="manual.html#luaL_checkany">luaL_checkany</A><BR>
<A HREF="manual.html#luaL_checkinteger">luaL_checkinteger</A><BR>
<A HREF="manual.html#luaL_checkint">luaL_checkint</A><BR>
<A HREF="manual.html#luaL_checklong">luaL_checklong</A><BR>
<A HREF="manual.html#luaL_checklstring">luaL_checklstring</A><BR>
<A HREF="manual.html#luaL_checknumber">luaL_checknumber</A><BR>
<A HREF="manual.html#luaL_checkoption">luaL_checkoption</A><BR>
<A HREF="manual.html#luaL_checkstack">luaL_checkstack</A><BR>
<A HREF="manual.html#luaL_checkstring">luaL_checkstring</A><BR>
<A HREF="manual.html#luaL_checktype">luaL_checktype</A><BR>
<A HREF="manual.html#luaL_checkudata">luaL_checkudata</A><BR>
<A HREF="manual.html#luaL_checkunsigned">luaL_checkunsigned</A><BR>
<A HREF="manual.html#luaL_checkversion">luaL_checkversion</A><BR>
<A HREF="manual.html#luaL_dofile">luaL_dofile</A><BR>
<A HREF="manual.html#luaL_dostring">luaL_dostring</A><BR>
<A HREF="manual.html#luaL_error">luaL_error</A><BR>
<A HREF="manual.html#luaL_execresult">luaL_execresult</A><BR>
<A HREF="manual.html#luaL_fileresult">luaL_fileresult</A><BR>
<A HREF="manual.html#luaL_getmetafield">luaL_getmetafield</A><BR>
<A HREF="manual.html#luaL_getmetatable">luaL_getmetatable</A><BR>
<A HREF="manual.html#luaL_getsubtable">luaL_getsubtable</A><BR>
<A HREF="manual.html#luaL_gsub">luaL_gsub</A><BR>
<A HREF="manual.html#luaL_len">luaL_len</A><BR>
<A HREF="manual.html#luaL_loadbuffer">luaL_loadbuffer</A><BR>
<A HREF="manual.html#luaL_loadbufferx">luaL_loadbufferx</A><BR>
<A HREF="manual.html#luaL_loadfile">luaL_loadfile</A><BR>
<A HREF="manual.html#luaL_loadfilex">luaL_loadfilex</A><BR>
<A HREF="manual.html#luaL_loadstring">luaL_loadstring</A><BR>
<A HREF="manual.html#luaL_newlib">luaL_newlib</A><BR>
<A HREF="manual.html#luaL_newlibtable">luaL_newlibtable</A><BR>
<A HREF="manual.html#luaL_newmetatable">luaL_newmetatable</A><BR>
<A HREF="manual.html#luaL_newstate">luaL_newstate</A><BR>
<A HREF="manual.html#luaL_openlibs">luaL_openlibs</A><BR>
<A HREF="manual.html#luaL_optinteger">luaL_optinteger</A><BR>
<A HREF="manual.html#luaL_optint">luaL_optint</A><BR>
<A HREF="manual.html#luaL_optlong">luaL_optlong</A><BR>
<A HREF="manual.html#luaL_optlstring">luaL_optlstring</A><BR>
<A HREF="manual.html#luaL_optnumber">luaL_optnumber</A><BR>
<A HREF="manual.html#luaL_optstring">luaL_optstring</A><BR>
<A HREF="manual.html#luaL_optunsigned">luaL_optunsigned</A><BR>
<A HREF="manual.html#luaL_prepbuffer">luaL_prepbuffer</A><BR>
<A HREF="manual.html#luaL_prepbuffsize">luaL_prepbuffsize</A><BR>
<A HREF="manual.html#luaL_pushresult">luaL_pushresult</A><BR>
<A HREF="manual.html#luaL_pushresultsize">luaL_pushresultsize</A><BR>
<A HREF="manual.html#luaL_ref">luaL_ref</A><BR>
<A HREF="manual.html#luaL_requiref">luaL_requiref</A><BR>
<A HREF="manual.html#luaL_setfuncs">luaL_setfuncs</A><BR>
<A HREF="manual.html#luaL_setmetatable">luaL_setmetatable</A><BR>
<A HREF="manual.html#luaL_testudata">luaL_testudata</A><BR>
<A HREF="manual.html#luaL_tolstring">luaL_tolstring</A><BR>
<A HREF="manual.html#luaL_traceback">luaL_traceback</A><BR>
<A HREF="manual.html#luaL_typename">luaL_typename</A><BR>
<A HREF="manual.html#luaL_unref">luaL_unref</A><BR>
<A HREF="manual.html#luaL_where">luaL_where</A><BR>
</TD>
</TR>
</TABLE>
<HR>
<SMALL CLASS="footer">
Last update:
Sat May 26 08:52:25 BRT 2012
</SMALL>
<!--
Last change: revised for Lua 5.2.1
-->
</BODY>
</HTML>
Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.1 KiB

-116
View File
@@ -1,116 +0,0 @@
.\" $Id: lua.man,v 1.13 2011/11/16 17:16:53 lhf Exp $
.TH LUA 1 "$Date: 2011/11/16 17:16:53 $"
.SH NAME
lua \- Lua interpreter
.SH SYNOPSIS
.B lua
[
.I options
]
[
.I script
[
.I args
]
]
.SH DESCRIPTION
.B lua
is the standalone Lua interpreter.
It loads and executes Lua programs,
either in textual source form or
in precompiled binary form.
(Precompiled binaries are output by
.BR luac ,
the Lua compiler.)
.B lua
can be used as a batch interpreter and also interactively.
.LP
The given
.I options
are handled in order and then
the Lua program in file
.I script
is loaded and executed.
The given
.I args
are available to
.I script
as strings in a global table named
.BR arg .
If no options or arguments are given,
then
.B "\-v \-i"
is assumed when the standard input is a terminal;
otherwise,
.B "\-"
is assumed.
.LP
In interactive mode,
.B lua
prompts the user,
reads lines from the standard input,
and executes them as they are read.
If a line does not contain a complete statement,
then a secondary prompt is displayed and
lines are read until a complete statement is formed or
a syntax error is found.
If a line starts with
.BR '=' ,
then
.B lua
evaluates and displays
the values of the expressions in the remainder of the line.
.LP
At the very start,
before even handling the command line,
.B lua
checks the contents of the environment variables
.B LUA_INIT_5_2
or
.BR LUA_INIT ,
in that order.
If the contents is of the form
.RI '@ filename ',
then
.I filename
is executed.
Otherwise, the string is assumed to be a Lua statement and is executed.
.SH OPTIONS
.TP
.BI \-e " stat"
execute statement
.IR stat .
.TP
.B \-i
enter interactive mode after executing
.IR script .
.TP
.BI \-l " name"
execute the equivalent of
.IB name =require(' name ')
before executing
.IR script .
.TP
.B \-v
show version information.
.TP
.B \-E
ignore environment variables.
.TP
.B \-\-
stop handling options.
.TP
.B \-
stop handling options and execute the standard input as a file.
.SH "SEE ALSO"
.BR luac (1)
.br
The documentation at lua.org,
especially section 7 of the reference manual.
.SH DIAGNOSTICS
Error messages should be self explanatory.
.SH AUTHORS
R. Ierusalimschy,
L. H. de Figueiredo,
W. Celes
.\" EOF
-83
View File
@@ -1,83 +0,0 @@
body {
color: #000000 ;
background-color: #FFFFFF ;
font-family: Helvetica, Arial, sans-serif ;
text-align: justify ;
margin-right: 30px ;
margin-left: 30px ;
}
h1, h2, h3, h4 {
font-family: Verdana, Geneva, sans-serif ;
font-weight: normal ;
font-style: italic ;
}
h2 {
padding-top: 0.4em ;
padding-bottom: 0.4em ;
padding-left: 30px ;
padding-right: 30px ;
margin-left: -30px ;
background-color: #E0E0FF ;
}
h3 {
padding-left: 0.5em ;
border-left: solid #E0E0FF 1em ;
}
table h3 {
padding-left: 0px ;
border-left: none ;
}
a:link {
color: #000080 ;
background-color: inherit ;
text-decoration: none ;
}
a:visited {
background-color: inherit ;
text-decoration: none ;
}
a:link:hover, a:visited:hover {
color: #000080 ;
background-color: #E0E0FF ;
}
a:link:active, a:visited:active {
color: #FF0000 ;
}
hr {
border: 0 ;
height: 1px ;
color: #a0a0a0 ;
background-color: #a0a0a0 ;
}
:target {
background-color: #F8F8F8 ;
padding: 8px ;
border: solid #a0a0a0 2px ;
}
.footer {
color: gray ;
font-size: small ;
}
input[type=text] {
border: solid #a0a0a0 2px ;
border-radius: 2em ;
-moz-border-radius: 2em ;
background-image: url('images/search.png') ;
background-repeat: no-repeat;
background-position: 4px center ;
padding-left: 20px ;
height: 2em ;
}
-118
View File
@@ -1,118 +0,0 @@
.\" $Id: luac.man,v 1.29 2011/11/16 13:53:40 lhf Exp $
.TH LUAC 1 "$Date: 2011/11/16 13:53:40 $"
.SH NAME
luac \- Lua compiler
.SH SYNOPSIS
.B luac
[
.I options
] [
.I filenames
]
.SH DESCRIPTION
.B luac
is the Lua compiler.
It translates programs written in the Lua programming language
into binary files containing precompiled chunks
that can be later loaded and executed.
.LP
The main advantages of precompiling chunks are:
faster loading,
protecting source code from accidental user changes,
and
off-line syntax checking.
Precompiling does not imply faster execution
because in Lua chunks are always compiled into bytecodes before being executed.
.B luac
simply allows those bytecodes to be saved in a file for later execution.
Precompiled chunks are not necessarily smaller than the corresponding source.
The main goal in precompiling is faster loading.
.LP
In the command line,
you can mix
text files containing Lua source and
binary files containing precompiled chunks.
.B luac
produces a single output file containing the combined bytecodes
for all files given.
Executing the combined file is equivalent to executing the given files.
By default,
the output file is named
.BR luac.out ,
but you can change this with the
.B \-o
option.
.LP
Precompiled chunks are
.I not
portable across different architectures.
Moreover,
the internal format of precompiled chunks
is likely to change when a new version of Lua is released.
Make sure you save the source files of all Lua programs that you precompile.
.LP
.SH OPTIONS
.TP
.B \-l
produce a listing of the compiled bytecode for Lua's virtual machine.
Listing bytecodes is useful to learn about Lua's virtual machine.
If no files are given, then
.B luac
loads
.B luac.out
and lists its contents.
Use
.B \-l \-l
for a full listing.
.TP
.BI \-o " file"
output to
.IR file ,
instead of the default
.BR luac.out .
(You can use
.B "'\-'"
for standard output,
but not on platforms that open standard output in text mode.)
The output file may be one of the given files because
all files are loaded before the output file is written.
Be careful not to overwrite precious files.
.TP
.B \-p
load files but do not generate any output file.
Used mainly for syntax checking and for testing precompiled chunks:
corrupted files will probably generate errors when loaded.
If no files are given, then
.B luac
loads
.B luac.out
and tests its contents.
No messages are displayed if the file loads without errors.
.TP
.B \-s
strip debug information before writing the output file.
This saves some space in very large chunks,
but if errors occur when running a stripped chunk,
then the error messages may not contain the full information they usually do.
In particular,
line numbers and names of local variables are lost.
.TP
.B \-v
show version information.
.TP
.B \-\-
stop handling options.
.TP
.B \-
stop handling options and process standard input.
.SH "SEE ALSO"
.BR lua (1)
.br
The documentation at lua.org.
.SH DIAGNOSTICS
Error messages should be self explanatory.
.SH AUTHORS
R. Ierusalimschy,
L. H. de Figueiredo,
W. Celes
.\" EOF
-24
View File
@@ -1,24 +0,0 @@
h3 code {
font-family: inherit ;
font-size: inherit ;
}
pre, code {
font-size: 12pt ;
}
span.apii {
float: right ;
font-family: inherit ;
font-style: normal ;
font-size: small ;
color: gray ;
}
p+h1, ul+h1 {
padding-top: 0.4em ;
padding-bottom: 0.4em ;
padding-left: 30px ;
margin-left: -30px ;
background-color: #E0E0FF ;
}
File diff suppressed because it is too large. Load diff
Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.7 KiB

-410
View File
@@ -1,410 +0,0 @@
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<HTML>
<HEAD>
<TITLE>Lua 5.2 readme</TITLE>
<LINK REL="stylesheet" TYPE="text/css" HREF="lua.css">
<META HTTP-EQUIV="content-type" CONTENT="text/html; charset=iso-8859-1">
<STYLE TYPE="text/css">
blockquote, .display {
border: solid #a0a0a0 2px ;
padding: 1em ;
margin: 0px ;
}
.display {
word-spacing: 0.25em ;
}
dl.display dd {
padding-bottom: 0.2em ;
}
tt, kbd, code {
font-size: 12pt ;
}
</STYLE>
</HEAD>
<BODY>
<HR>
<H1>
<A HREF="http://www.lua.org/"><IMG SRC="logo.gif" ALT="Lua" BORDER=0></A>
Welcome to Lua 5.2
</H1>
<P>
<A HREF="#about">about</A>
&middot;
<A HREF="#install">installation</A>
&middot;
<A HREF="#changes">changes</A>
&middot;
<A HREF="#license">license</A>
&middot;
<A HREF="contents.html">reference manual</A>
<H2><A NAME="about">About Lua</A></H2>
<P>
Lua is a powerful, fast, lightweight, embeddable scripting language
developed by a
<A HREF="http://www.lua.org/authors.html">team</A>
at
<A HREF="http://www.puc-rio.br/">PUC-Rio</A>,
the Pontifical Catholic University of Rio de Janeiro in Brazil.
Lua is
<A HREF="#license">free software</A>
used in many products and projects around the world.
<P>
Lua's
<A HREF="http://www.lua.org/">official web site</A>
provides complete information
about Lua,
including
an
<A HREF="http://www.lua.org/about.html">executive summary</A>
and
updated
<A HREF="http://www.lua.org/docs.html">documentation</A>,
especially the
<A HREF="http://www.lua.org/manual/5.2/">reference manual</A>,
which may differ slightly from the
<A HREF="contents.html">local copy</A>
distributed in this package.
<H2><A NAME="install">Installing Lua</A></H2>
<P>
Lua is distributed in
<A HREF="http://www.lua.org/ftp/">source</A>
form.
You need to build it before using it.
Building Lua should be straightforward
because
Lua is implemented in pure ANSI C and compiles unmodified in all known
platforms that have an ANSI C compiler.
Lua also compiles unmodified as C++.
The instructions given below for building Lua are for Unix-like platforms.
See also
<A HREF="#other">instructions for other systems</A>
and
<A HREF="#customization">customization options</A>.
<P>
If you don't have the time or the inclination to compile Lua yourself,
get a binary from
<A HREF="http://lua-users.org/wiki/LuaBinaries">LuaBinaries</A>.
Try also
<A HREF="http://luaforwindows.luaforge.net/">Lua for Windows</A>,
an easy-to-use distribution of Lua that includes many useful libraries.
<H3>Building Lua</H3>
<P>
In most Unix-like platforms, simply do "<KBD>make</KBD>" with a suitable target.
Here are the details.
<OL>
<LI>
Open a terminal window and move to
the top-level directory, which is named <TT>lua-5.2.1</TT>.
The Makefile there controls both the build process and the installation process.
<P>
<LI>
Do "<KBD>make</KBD>" and see if your platform is listed.
The platforms currently supported are:
<P>
<P CLASS="display">
aix ansi bsd freebsd generic linux macosx mingw posix solaris
</P>
<P>
If your platform is listed, just do "<KBD>make xxx</KBD>", where xxx
is your platform name.
<P>
If your platform is not listed, try the closest one or posix, generic,
ansi, in this order.
<P>
<LI>
The compilation takes only a few moments
and produces three files in the <TT>src</TT> directory:
lua (the interpreter),
luac (the compiler),
and liblua.a (the library).
<P>
<LI>
To check that Lua has been built correctly, do "<KBD>make test</KBD>"
after building Lua. This will run the interpreter and print its version string.
</OL>
<P>
If you're running Linux and get compilation errors,
make sure you have installed the <TT>readline</TT> development package.
<H3>Installing Lua</H3>
<P>
Once you have built Lua, you may want to install it in an official
place in your system. In this case, do "<KBD>make install</KBD>". The official
place and the way to install files are defined in the Makefile. You'll
probably need the right permissions to install files.
<P>
To build and install Lua in one step, do "<KBD>make xxx install</KBD>",
where xxx is your platform name.
<P>
To install Lua locally, do "<KBD>make local</KBD>".
This will create a directory <TT>install</TT> with subdirectories
<TT>bin</TT>, <TT>include</TT>, <TT>lib</TT>, <TT>man</TT>,
and install Lua as listed below.
To install Lua locally, but in some other directory, do
"<KBD>make install INSTALL_TOP=xxx</KBD>", where xxx is your chosen directory.
<DL CLASS="display">
<DT>
bin:
<DD>
lua luac
<DT>
include:
<DD>
lua.h luaconf.h lualib.h lauxlib.h lua.hpp
<DT>
lib:
<DD>
liblua.a
<DT>
man/man1:
<DD>
lua.1 luac.1
</DL>
<P>
These are the only directories you need for development.
If you only want to run Lua programs,
you only need the files in bin and man.
The files in include and lib are needed for
embedding Lua in C or C++ programs.
<H3><A NAME="customization">Customization</A></H3>
<P>
Three kinds of things can be customized by editing a file:
<UL>
<LI> Where and how to install Lua &mdash; edit <TT>Makefile</TT>.
<LI> How to build Lua &mdash; edit <TT>src/Makefile</TT>.
<LI> Lua features &mdash; edit <TT>src/luaconf.h</TT>.
</UL>
<P>
You don't actually need to edit the Makefiles because you may set the
relevant variables in the command line when invoking make.
Nevertheless, it's probably best to edit and save the Makefiles to
record the changes you need.
<P>
On the other hand, if you need to customize some Lua features, you'll need
to edit <TT>src/luaconf.h</TT> before building and installing Lua.
The edited file will be the one installed, and
it will be used by any Lua clients that you build, to ensure consistency.
Further customization is available to experts by editing the Lua sources.
<P>
We strongly recommend that you enable dynamic loading in <TT>src/luaconf.h</TT>.
This is done automatically for all platforms listed above that have
this feature and also for Windows.
<H3><A NAME="other">Building Lua on other systems</A></H3>
<P>
If you're not using the usual Unix tools, then the instructions for
building Lua depend on the compiler you use. You'll need to create
projects (or whatever your compiler uses) for building the library,
the interpreter, and the compiler, as follows:
<DL CLASS="display">
<DT>
library:
<DD>
lapi.c lcode.c lctype.c ldebug.c ldo.c ldump.c lfunc.c lgc.c llex.c
lmem.c lobject.c lopcodes.c lparser.c lstate.c lstring.c ltable.c
ltm.c lundump.c lvm.c lzio.c
lauxlib.c lbaselib.c lbitlib.c lcorolib.c ldblib.c liolib.c
lmathlib.c loslib.c lstrlib.c ltablib.c loadlib.c linit.c
<DT>
interpreter:
<DD>
library, lua.c
<DT>
compiler:
<DD>
library, luac.c
</DL>
<P>
To use Lua as a library in your own programs you'll need to know how to
create and use libraries with your compiler. Moreover, to dynamically load
C libraries for Lua you'll need to know how to create dynamic libraries
and you'll need to make sure that the Lua API functions are accessible to
those dynamic libraries &mdash; but <EM>don't</EM> link the Lua library
into each dynamic library. For Unix, we recommend that the Lua library
be linked statically into the host program and its symbols exported for
dynamic linking; <TT>src/Makefile</TT> does this for the Lua interpreter.
For Windows, we recommend that the Lua library be a DLL.
<P>
As mentioned above, you may edit <TT>src/luaconf.h</TT> to customize
some features before building Lua.
<H2><A NAME="changes">Changes since Lua 5.1</A></H2>
<P>
Here are the main changes introduced in Lua 5.2.
The
<A HREF="contents.html">reference manual</A>
lists the
<A HREF="manual.html#8">incompatibilities</A> that had to be introduced.
<H3>Main changes</H3>
<UL>
<LI> yieldable pcall and metamethods
<LI> new lexical scheme for globals
<LI> ephemeron tables
<LI> new library for bitwise operations
<LI> light C functions
<LI> emergency garbage collector
<LI> <CODE>goto</CODE> statement
<LI> finalizers for tables
</UL>
Here are the other changes introduced in Lua 5.2:
<H3>Language</H3>
<UL>
<LI> no more fenv for threads or functions
<LI> tables honor the <CODE>__len</CODE> metamethod
<LI> hex and <CODE>\z</CODE> escapes in strings
<LI> support for hexadecimal floats
<LI> order metamethods work for different types
<LI> no more verification of opcode consistency
<LI> hook event "tail return" replaced by "tail call"
<LI> empty statement
<LI> <CODE>break</CODE> statement may appear in the middle of a block
</UL>
<H3>Libraries</H3>
<UL>
<LI> arguments for function called through <CODE>xpcall</CODE>
<LI> optional 'mode' argument to load and loadfile (to control binary x text)
<LI> optional 'env' argument to load and loadfile (environment for loaded chunk)
<LI> <CODE>loadlib</CODE> may load libraries with global names (RTLD_GLOBAL)
<LI> new function <CODE>package.searchpath</CODE>
<LI> modules receive their paths when loaded
<LI> optional base in <CODE>math.log</CODE>
<LI> optional separator in <CODE>string.rep</CODE>
<LI> <CODE>file:write</CODE> returns <CODE>file</CODE>
<LI> closing a pipe returns exit status
<LI> <CODE>os.exit</CODE> may close state
<LI> new metamethods <CODE>__pairs</CODE> and <CODE>__ipairs</CODE>
<LI> new option 'isrunning' for <CODE>collectgarbage</CODE> and <CODE>lua_gc</CODE>
<LI> frontier patterns
<LI> <CODE>\0</CODE> in patterns
<LI> new option <CODE>*L</CODE> for <CODE>io.read</CODE>
<LI> options for <CODE>io.lines</CODE>
<LI> <CODE>debug.getlocal</CODE> can access function varargs
</UL>
<H3>C API</H3>
<UL>
<LI> main thread predefined in the registry
<LI> new functions
<CODE>lua_absindex</CODE>,
<CODE>lua_arith</CODE>,
<CODE>lua_compare</CODE>,
<CODE>lua_copy</CODE>,
<CODE>lua_len</CODE>,
<CODE>lua_rawgetp</CODE>,
<CODE>lua_rawsetp</CODE>,
<CODE>lua_upvalueid</CODE>,
<CODE>lua_upvaluejoin</CODE>,
<CODE>lua_version</CODE>.
<LI> new functions
<CODE>luaL_checkversion</CODE>,
<CODE>luaL_setmetatable</CODE>,
<CODE>luaL_testudata</CODE>,
<CODE>luaL_tolstring</CODE>.
<LI> <CODE>lua_pushstring</CODE> and <CODE>pushlstring</CODE> return string
<LI> <CODE>nparams</CODE> and <CODE>isvararg</CODE> available in debug API
<LI> new <CODE>lua_Unsigned</CODE>
</UL>
<H3>Implementation</H3>
<UL>
<LI> max constants per function raised to 2<SUP>26</SUP>
<LI> generational mode for garbage collection (experimental)
<LI> NaN trick (experimental)
<LI> internal (immutable) version of ctypes
<LI> simpler implementation for string buffers
<LI> parser uses much less C-stack space (no more auto arrays)
</UL>
<H3>Lua standalone interpreter</H3>
<UL>
<LI> new <CODE>-E</CODE> option to avoid environment variables
<LI> handling of non-string error messages
</UL>
<H2><A NAME="license">License</A></H2>
<A HREF="http://www.opensource.org/docs/definition.php">
<IMG SRC="osi-certified-72x60.png" ALIGN="right" BORDER="0" ALT="[osi certified]" STYLE="padding-left: 30px ;">
</A>
<P>
Lua is free software distributed under the terms of the
<A HREF="http://www.opensource.org/licenses/mit-license.html">MIT license</A>
reproduced below;
it may be used for any purpose, including commercial purposes,
at absolutely no cost without having to ask us.
The only requirement is that if you do use Lua,
then you should give us credit by including the appropriate copyright notice somewhere in your product or its documentation.
For details, see
<A HREF="http://www.lua.org/license.html">this</A>.
<BLOCKQUOTE STYLE="padding-bottom: 0em">
Copyright &copy; 1994&ndash;2012 Lua.org, PUC-Rio.
<P>
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
<P>
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
<P>
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
</BLOCKQUOTE>
<P>
<HR>
<SMALL CLASS="footer">
Last update:
Tue May 29 21:57:51 BRT 2012
</SMALL>
<!--
Last change: revised for Lua 5.2.1
-->
</BODY>
</HTML>
-187
View File
@@ -1,187 +0,0 @@
# Makefile for building Lua
# See ../doc/readme.html for installation and customization instructions.
# == CHANGE THE SETTINGS BELOW TO SUIT YOUR ENVIRONMENT =======================
# Your platform. See PLATS for possible values.
PLAT= none
CC= gcc
CFLAGS= -O2 -Wall -DLUA_COMPAT_ALL $(SYSCFLAGS) $(MYCFLAGS)
LDFLAGS= $(SYSLDFLAGS) $(MYLDFLAGS)
LIBS= -lm $(SYSLIBS) $(MYLIBS)
AR= ar rcu
RANLIB= ranlib
RM= rm -f
SYSCFLAGS=
SYSLDFLAGS=
SYSLIBS=
MYCFLAGS=
MYLDFLAGS=
MYLIBS=
MYOBJS=
# == END OF USER SETTINGS -- NO NEED TO CHANGE ANYTHING BELOW THIS LINE =======
PLATS= aix ansi bsd freebsd generic linux macosx mingw posix solaris
LUA_A= liblua.a
CORE_O= lapi.o lcode.o lctype.o ldebug.o ldo.o ldump.o lfunc.o lgc.o llex.o \
lmem.o lobject.o lopcodes.o lparser.o lstate.o lstring.o ltable.o \
ltm.o lundump.o lvm.o lzio.o
LIB_O= lauxlib.o lbaselib.o lbitlib.o lcorolib.o ldblib.o liolib.o \
lmathlib.o loslib.o lstrlib.o ltablib.o loadlib.o linit.o
BASE_O= $(CORE_O) $(LIB_O) $(MYOBJS)
LUA_T= lua
LUA_O= lua.o
LUAC_T= luac
LUAC_O= luac.o
ALL_O= $(BASE_O) $(LUA_O) $(LUAC_O)
ALL_T= $(LUA_A) $(LUA_T) $(LUAC_T)
ALL_A= $(LUA_A)
# Targets start here.
default: $(PLAT)
all: $(ALL_T)
o: $(ALL_O)
a: $(ALL_A)
$(LUA_A): $(BASE_O)
$(AR) $@ $(BASE_O)
$(RANLIB) $@
$(LUA_T): $(LUA_O) $(LUA_A)
$(CC) -o $@ $(LDFLAGS) $(LUA_O) $(LUA_A) $(LIBS)
$(LUAC_T): $(LUAC_O) $(LUA_A)
$(CC) -o $@ $(LDFLAGS) $(LUAC_O) $(LUA_A) $(LIBS)
clean:
$(RM) $(ALL_T) $(ALL_O)
depend:
@$(CC) $(CFLAGS) -MM l*.c
echo:
@echo "PLAT= $(PLAT)"
@echo "CC= $(CC)"
@echo "CFLAGS= $(CFLAGS)"
@echo "LDFLAGS= $(SYSLDFLAGS)"
@echo "LIBS= $(LIBS)"
@echo "AR= $(AR)"
@echo "RANLIB= $(RANLIB)"
@echo "RM= $(RM)"
# Convenience targets for popular platforms
ALL= all
none:
@echo "Please do 'make PLATFORM' where PLATFORM is one of these:"
@echo " $(PLATS)"
aix:
$(MAKE) $(ALL) CC="xlc" CFLAGS="-O2 -DLUA_USE_POSIX -DLUA_USE_DLOPEN" SYSLIBS="-ldl" SYSLDFLAGS="-brtl -bexpall"
ansi:
$(MAKE) $(ALL) SYSCFLAGS="-DLUA_ANSI"
bsd:
$(MAKE) $(ALL) SYSCFLAGS="-DLUA_USE_POSIX -DLUA_USE_DLOPEN" SYSLIBS="-Wl,-E"
freebsd:
$(MAKE) $(ALL) SYSCFLAGS="-DLUA_USE_LINUX" SYSLIBS="-Wl,-E -lreadline"
generic: $(ALL)
linux:
$(MAKE) $(ALL) SYSCFLAGS="-DLUA_USE_LINUX" SYSLIBS="-Wl,-E -ldl -lreadline -lncurses"
macosx:
$(MAKE) $(ALL) SYSCFLAGS="-DLUA_USE_MACOSX" SYSLIBS="-lreadline"
mingw:
$(MAKE) "LUA_A=lua52.dll" "LUA_T=lua.exe" \
"AR=$(CC) -shared -o" "RANLIB=strip --strip-unneeded" \
"SYSCFLAGS=-DLUA_BUILD_AS_DLL" "SYSLIBS=" "SYSLDFLAGS=-s" lua.exe
$(MAKE) "LUAC_T=luac.exe" luac.exe
posix:
$(MAKE) $(ALL) SYSCFLAGS="-DLUA_USE_POSIX"
solaris:
$(MAKE) $(ALL) SYSCFLAGS="-DLUA_USE_POSIX -DLUA_USE_DLOPEN" SYSLIBS="-ldl"
# list targets that do not create files (but not all makes understand .PHONY)
.PHONY: all $(PLATS) default o a clean depend echo none
# DO NOT DELETE
lapi.o: lapi.c lua.h luaconf.h lapi.h llimits.h lstate.h lobject.h ltm.h \
lzio.h lmem.h ldebug.h ldo.h lfunc.h lgc.h lstring.h ltable.h lundump.h \
lvm.h
lauxlib.o: lauxlib.c lua.h luaconf.h lauxlib.h
lbaselib.o: lbaselib.c lua.h luaconf.h lauxlib.h lualib.h
lbitlib.o: lbitlib.c lua.h luaconf.h lauxlib.h lualib.h
lcode.o: lcode.c lua.h luaconf.h lcode.h llex.h lobject.h llimits.h \
lzio.h lmem.h lopcodes.h lparser.h ldebug.h lstate.h ltm.h ldo.h lgc.h \
lstring.h ltable.h lvm.h
lcorolib.o: lcorolib.c lua.h luaconf.h lauxlib.h lualib.h
lctype.o: lctype.c lctype.h lua.h luaconf.h llimits.h
ldblib.o: ldblib.c lua.h luaconf.h lauxlib.h lualib.h
ldebug.o: ldebug.c lua.h luaconf.h lapi.h llimits.h lstate.h lobject.h \
ltm.h lzio.h lmem.h lcode.h llex.h lopcodes.h lparser.h ldebug.h ldo.h \
lfunc.h lstring.h lgc.h ltable.h lvm.h
ldo.o: ldo.c lua.h luaconf.h lapi.h llimits.h lstate.h lobject.h ltm.h \
lzio.h lmem.h ldebug.h ldo.h lfunc.h lgc.h lopcodes.h lparser.h \
lstring.h ltable.h lundump.h lvm.h
ldump.o: ldump.c lua.h luaconf.h lobject.h llimits.h lstate.h ltm.h \
lzio.h lmem.h lundump.h
lfunc.o: lfunc.c lua.h luaconf.h lfunc.h lobject.h llimits.h lgc.h \
lstate.h ltm.h lzio.h lmem.h
lgc.o: lgc.c lua.h luaconf.h ldebug.h lstate.h lobject.h llimits.h ltm.h \
lzio.h lmem.h ldo.h lfunc.h lgc.h lstring.h ltable.h
linit.o: linit.c lua.h luaconf.h lualib.h lauxlib.h
liolib.o: liolib.c lua.h luaconf.h lauxlib.h lualib.h
llex.o: llex.c lua.h luaconf.h lctype.h llimits.h ldo.h lobject.h \
lstate.h ltm.h lzio.h lmem.h llex.h lparser.h lstring.h lgc.h ltable.h
lmathlib.o: lmathlib.c lua.h luaconf.h lauxlib.h lualib.h
lmem.o: lmem.c lua.h luaconf.h ldebug.h lstate.h lobject.h llimits.h \
ltm.h lzio.h lmem.h ldo.h lgc.h
loadlib.o: loadlib.c lua.h luaconf.h lauxlib.h lualib.h
lobject.o: lobject.c lua.h luaconf.h lctype.h llimits.h ldebug.h lstate.h \
lobject.h ltm.h lzio.h lmem.h ldo.h lstring.h lgc.h lvm.h
lopcodes.o: lopcodes.c lopcodes.h llimits.h lua.h luaconf.h
loslib.o: loslib.c lua.h luaconf.h lauxlib.h lualib.h
lparser.o: lparser.c lua.h luaconf.h lcode.h llex.h lobject.h llimits.h \
lzio.h lmem.h lopcodes.h lparser.h ldebug.h lstate.h ltm.h ldo.h lfunc.h \
lstring.h lgc.h ltable.h
lstate.o: lstate.c lua.h luaconf.h lapi.h llimits.h lstate.h lobject.h \
ltm.h lzio.h lmem.h ldebug.h ldo.h lfunc.h lgc.h llex.h lstring.h \
ltable.h
lstring.o: lstring.c lua.h luaconf.h lmem.h llimits.h lobject.h lstate.h \
ltm.h lzio.h lstring.h lgc.h
lstrlib.o: lstrlib.c lua.h luaconf.h lauxlib.h lualib.h
ltable.o: ltable.c lua.h luaconf.h ldebug.h lstate.h lobject.h llimits.h \
ltm.h lzio.h lmem.h ldo.h lgc.h lstring.h ltable.h lvm.h
ltablib.o: ltablib.c lua.h luaconf.h lauxlib.h lualib.h
ltm.o: ltm.c lua.h luaconf.h lobject.h llimits.h lstate.h ltm.h lzio.h \
lmem.h lstring.h lgc.h ltable.h
lua.o: lua.c lua.h luaconf.h lauxlib.h lualib.h
luac.o: luac.c lua.h luaconf.h lauxlib.h lobject.h llimits.h lstate.h \
ltm.h lzio.h lmem.h lundump.h ldebug.h lopcodes.h
lundump.o: lundump.c lua.h luaconf.h ldebug.h lstate.h lobject.h \
llimits.h ltm.h lzio.h lmem.h ldo.h lfunc.h lstring.h lgc.h lundump.h
lvm.o: lvm.c lua.h luaconf.h ldebug.h lstate.h lobject.h llimits.h ltm.h \
lzio.h lmem.h ldo.h lfunc.h lgc.h lopcodes.h lstring.h ltable.h lvm.h
lzio.o: lzio.c lua.h luaconf.h llimits.h lmem.h lstate.h lobject.h ltm.h \
lzio.h
-1281
View File
File diff suppressed because it is too large. Load diff
-24
View File
@@ -1,24 +0,0 @@
/*
** $Id: lapi.h,v 2.7 2009/11/27 15:37:59 roberto Exp $
** Auxiliary functions from Lua API
** See Copyright Notice in lua.h
*/
#ifndef lapi_h
#define lapi_h
#include "llimits.h"
#include "lstate.h"
#define api_incr_top(L) {L->top++; api_check(L, L->top <= L->ci->top, \
"stack overflow");}
#define adjustresults(L,nres) \
{ if ((nres) == LUA_MULTRET && L->ci->top < L->top) L->ci->top = L->top; }
#define api_checknelems(L,n) api_check(L, (n) < (L->top - L->ci->func), \
"not enough elements in the stack")
#endif
-957
View File
@@ -1,957 +0,0 @@
/*
** $Id: lauxlib.c,v 1.244 2012/05/31 20:28:45 roberto Exp $
** Auxiliary functions for building Lua libraries
** See Copyright Notice in lua.h
*/
#include <errno.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
/* This file uses only the official API of Lua.
** Any function declared here could be written as an application function.
*/
#define lauxlib_c
#define LUA_LIB
#include "lua.h"
#include "lauxlib.h"
/*
** {======================================================
** Traceback
** =======================================================
*/
#define LEVELS1 12 /* size of the first part of the stack */
#define LEVELS2 10 /* size of the second part of the stack */
/*
** search for 'objidx' in table at index -1.
** return 1 + string at top if find a good name.
*/
static int findfield (lua_State *L, int objidx, int level) {
if (level == 0 || !lua_istable(L, -1))
return 0; /* not found */
lua_pushnil(L); /* start 'next' loop */
while (lua_next(L, -2)) { /* for each pair in table */
if (lua_type(L, -2) == LUA_TSTRING) { /* ignore non-string keys */
if (lua_rawequal(L, objidx, -1)) { /* found object? */
lua_pop(L, 1); /* remove value (but keep name) */
return 1;
}
else if (findfield(L, objidx, level - 1)) { /* try recursively */
lua_remove(L, -2); /* remove table (but keep name) */
lua_pushliteral(L, ".");
lua_insert(L, -2); /* place '.' between the two names */
lua_concat(L, 3);
return 1;
}
}
lua_pop(L, 1); /* remove value */
}
return 0; /* not found */
}
static int pushglobalfuncname (lua_State *L, lua_Debug *ar) {
int top = lua_gettop(L);
lua_getinfo(L, "f", ar); /* push function */
lua_pushglobaltable(L);
if (findfield(L, top + 1, 2)) {
lua_copy(L, -1, top + 1); /* move name to proper place */
lua_pop(L, 2); /* remove pushed values */
return 1;
}
else {
lua_settop(L, top); /* remove function and global table */
return 0;
}
}
static void pushfuncname (lua_State *L, lua_Debug *ar) {
if (*ar->namewhat != '\0') /* is there a name? */
lua_pushfstring(L, "function " LUA_QS, ar->name);
else if (*ar->what == 'm') /* main? */
lua_pushfstring(L, "main chunk");
else if (*ar->what == 'C') {
if (pushglobalfuncname(L, ar)) {
lua_pushfstring(L, "function " LUA_QS, lua_tostring(L, -1));
lua_remove(L, -2); /* remove name */
}
else
lua_pushliteral(L, "?");
}
else
lua_pushfstring(L, "function <%s:%d>", ar->short_src, ar->linedefined);
}
static int countlevels (lua_State *L) {
lua_Debug ar;
int li = 1, le = 1;
/* find an upper bound */
while (lua_getstack(L, le, &ar)) { li = le; le *= 2; }
/* do a binary search */
while (li < le) {
int m = (li + le)/2;
if (lua_getstack(L, m, &ar)) li = m + 1;
else le = m;
}
return le - 1;
}
LUALIB_API void luaL_traceback (lua_State *L, lua_State *L1,
const char *msg, int level) {
lua_Debug ar;
int top = lua_gettop(L);
int numlevels = countlevels(L1);
int mark = (numlevels > LEVELS1 + LEVELS2) ? LEVELS1 : 0;
if (msg) lua_pushfstring(L, "%s\n", msg);
lua_pushliteral(L, "stack traceback:");
while (lua_getstack(L1, level++, &ar)) {
if (level == mark) { /* too many levels? */
lua_pushliteral(L, "\n\t..."); /* add a '...' */
level = numlevels - LEVELS2; /* and skip to last ones */
}
else {
lua_getinfo(L1, "Slnt", &ar);
lua_pushfstring(L, "\n\t%s:", ar.short_src);
if (ar.currentline > 0)
lua_pushfstring(L, "%d:", ar.currentline);
lua_pushliteral(L, " in ");
pushfuncname(L, &ar);
if (ar.istailcall)
lua_pushliteral(L, "\n\t(...tail calls...)");
lua_concat(L, lua_gettop(L) - top);
}
}
lua_concat(L, lua_gettop(L) - top);
}
/* }====================================================== */
/*
** {======================================================
** Error-report functions
** =======================================================
*/
LUALIB_API int luaL_argerror (lua_State *L, int narg, const char *extramsg) {
lua_Debug ar;
if (!lua_getstack(L, 0, &ar)) /* no stack frame? */
return luaL_error(L, "bad argument #%d (%s)", narg, extramsg);
lua_getinfo(L, "n", &ar);
if (strcmp(ar.namewhat, "method") == 0) {
narg--; /* do not count `self' */
if (narg == 0) /* error is in the self argument itself? */
return luaL_error(L, "calling " LUA_QS " on bad self", ar.name);
}
if (ar.name == NULL)
ar.name = (pushglobalfuncname(L, &ar)) ? lua_tostring(L, -1) : "?";
return luaL_error(L, "bad argument #%d to " LUA_QS " (%s)",
narg, ar.name, extramsg);
}
static int typeerror (lua_State *L, int narg, const char *tname) {
const char *msg = lua_pushfstring(L, "%s expected, got %s",
tname, luaL_typename(L, narg));
return luaL_argerror(L, narg, msg);
}
static void tag_error (lua_State *L, int narg, int tag) {
typeerror(L, narg, lua_typename(L, tag));
}
LUALIB_API void luaL_where (lua_State *L, int level) {
lua_Debug ar;
if (lua_getstack(L, level, &ar)) { /* check function at level */
lua_getinfo(L, "Sl", &ar); /* get info about it */
if (ar.currentline > 0) { /* is there info? */
lua_pushfstring(L, "%s:%d: ", ar.short_src, ar.currentline);
return;
}
}
lua_pushliteral(L, ""); /* else, no information available... */
}
LUALIB_API int luaL_error (lua_State *L, const char *fmt, ...) {
va_list argp;
va_start(argp, fmt);
luaL_where(L, 1);
lua_pushvfstring(L, fmt, argp);
va_end(argp);
lua_concat(L, 2);
return lua_error(L);
}
LUALIB_API int luaL_fileresult (lua_State *L, int stat, const char *fname) {
int en = errno; /* calls to Lua API may change this value */
if (stat) {
lua_pushboolean(L, 1);
return 1;
}
else {
lua_pushnil(L);
if (fname)
lua_pushfstring(L, "%s: %s", fname, strerror(en));
else
lua_pushfstring(L, "%s", strerror(en));
lua_pushinteger(L, en);
return 3;
}
}
#if !defined(inspectstat) /* { */
#if defined(LUA_USE_POSIX)
#include <sys/wait.h>
/*
** use appropriate macros to interpret 'pclose' return status
*/
#define inspectstat(stat,what) \
if (WIFEXITED(stat)) { stat = WEXITSTATUS(stat); } \
else if (WIFSIGNALED(stat)) { stat = WTERMSIG(stat); what = "signal"; }
#else
#define inspectstat(stat,what) /* no op */
#endif
#endif /* } */
LUALIB_API int luaL_execresult (lua_State *L, int stat) {
const char *what = "exit"; /* type of termination */
if (stat == -1) /* error? */
return luaL_fileresult(L, 0, NULL);
else {
inspectstat(stat, what); /* interpret result */
if (*what == 'e' && stat == 0) /* successful termination? */
lua_pushboolean(L, 1);
else
lua_pushnil(L);
lua_pushstring(L, what);
lua_pushinteger(L, stat);
return 3; /* return true/nil,what,code */
}
}
/* }====================================================== */
/*
** {======================================================
** Userdata's metatable manipulation
** =======================================================
*/
LUALIB_API int luaL_newmetatable (lua_State *L, const char *tname) {
luaL_getmetatable(L, tname); /* try to get metatable */
if (!lua_isnil(L, -1)) /* name already in use? */
return 0; /* leave previous value on top, but return 0 */
lua_pop(L, 1);
lua_newtable(L); /* create metatable */
lua_pushvalue(L, -1);
lua_setfield(L, LUA_REGISTRYINDEX, tname); /* registry.name = metatable */
return 1;
}
LUALIB_API void luaL_setmetatable (lua_State *L, const char *tname) {
luaL_getmetatable(L, tname);
lua_setmetatable(L, -2);
}
LUALIB_API void *luaL_testudata (lua_State *L, int ud, const char *tname) {
void *p = lua_touserdata(L, ud);
if (p != NULL) { /* value is a userdata? */
if (lua_getmetatable(L, ud)) { /* does it have a metatable? */
luaL_getmetatable(L, tname); /* get correct metatable */
if (!lua_rawequal(L, -1, -2)) /* not the same? */
p = NULL; /* value is a userdata with wrong metatable */
lua_pop(L, 2); /* remove both metatables */
return p;
}
}
return NULL; /* value is not a userdata with a metatable */
}
LUALIB_API void *luaL_checkudata (lua_State *L, int ud, const char *tname) {
void *p = luaL_testudata(L, ud, tname);
if (p == NULL) typeerror(L, ud, tname);
return p;
}
/* }====================================================== */
/*
** {======================================================
** Argument check functions
** =======================================================
*/
LUALIB_API int luaL_checkoption (lua_State *L, int narg, const char *def,
const char *const lst[]) {
const char *name = (def) ? luaL_optstring(L, narg, def) :
luaL_checkstring(L, narg);
int i;
for (i=0; lst[i]; i++)
if (strcmp(lst[i], name) == 0)
return i;
return luaL_argerror(L, narg,
lua_pushfstring(L, "invalid option " LUA_QS, name));
}
LUALIB_API void luaL_checkstack (lua_State *L, int space, const char *msg) {
/* keep some extra space to run error routines, if needed */
const int extra = LUA_MINSTACK;
if (!lua_checkstack(L, space + extra)) {
if (msg)
luaL_error(L, "stack overflow (%s)", msg);
else
luaL_error(L, "stack overflow");
}
}
LUALIB_API void luaL_checktype (lua_State *L, int narg, int t) {
if (lua_type(L, narg) != t)
tag_error(L, narg, t);
}
LUALIB_API void luaL_checkany (lua_State *L, int narg) {
if (lua_type(L, narg) == LUA_TNONE)
luaL_argerror(L, narg, "value expected");
}
LUALIB_API const char *luaL_checklstring (lua_State *L, int narg, size_t *len) {
const char *s = lua_tolstring(L, narg, len);
if (!s) tag_error(L, narg, LUA_TSTRING);
return s;
}
LUALIB_API const char *luaL_optlstring (lua_State *L, int narg,
const char *def, size_t *len) {
if (lua_isnoneornil(L, narg)) {
if (len)
*len = (def ? strlen(def) : 0);
return def;
}
else return luaL_checklstring(L, narg, len);
}
LUALIB_API lua_Number luaL_checknumber (lua_State *L, int narg) {
int isnum;
lua_Number d = lua_tonumberx(L, narg, &isnum);
if (!isnum)
tag_error(L, narg, LUA_TNUMBER);
return d;
}
LUALIB_API lua_Number luaL_optnumber (lua_State *L, int narg, lua_Number def) {
return luaL_opt(L, luaL_checknumber, narg, def);
}
LUALIB_API lua_Integer luaL_checkinteger (lua_State *L, int narg) {
int isnum;
lua_Integer d = lua_tointegerx(L, narg, &isnum);
if (!isnum)
tag_error(L, narg, LUA_TNUMBER);
return d;
}
LUALIB_API lua_Unsigned luaL_checkunsigned (lua_State *L, int narg) {
int isnum;
lua_Unsigned d = lua_tounsignedx(L, narg, &isnum);
if (!isnum)
tag_error(L, narg, LUA_TNUMBER);
return d;
}
LUALIB_API lua_Integer luaL_optinteger (lua_State *L, int narg,
lua_Integer def) {
return luaL_opt(L, luaL_checkinteger, narg, def);
}
LUALIB_API lua_Unsigned luaL_optunsigned (lua_State *L, int narg,
lua_Unsigned def) {
return luaL_opt(L, luaL_checkunsigned, narg, def);
}
/* }====================================================== */
/*
** {======================================================
** Generic Buffer manipulation
** =======================================================
*/
/*
** check whether buffer is using a userdata on the stack as a temporary
** buffer
*/
#define buffonstack(B) ((B)->b != (B)->initb)
/*
** returns a pointer to a free area with at least 'sz' bytes
*/
LUALIB_API char *luaL_prepbuffsize (luaL_Buffer *B, size_t sz) {
lua_State *L = B->L;
if (B->size - B->n < sz) { /* not enough space? */
char *newbuff;
size_t newsize = B->size * 2; /* double buffer size */
if (newsize - B->n < sz) /* not bit enough? */
newsize = B->n + sz;
if (newsize < B->n || newsize - B->n < sz)
luaL_error(L, "buffer too large");
/* create larger buffer */
newbuff = (char *)lua_newuserdata(L, newsize * sizeof(char));
/* move content to new buffer */
memcpy(newbuff, B->b, B->n * sizeof(char));
if (buffonstack(B))
lua_remove(L, -2); /* remove old buffer */
B->b = newbuff;
B->size = newsize;
}
return &B->b[B->n];
}
LUALIB_API void luaL_addlstring (luaL_Buffer *B, const char *s, size_t l) {
char *b = luaL_prepbuffsize(B, l);
memcpy(b, s, l * sizeof(char));
luaL_addsize(B, l);
}
LUALIB_API void luaL_addstring (luaL_Buffer *B, const char *s) {
luaL_addlstring(B, s, strlen(s));
}
LUALIB_API void luaL_pushresult (luaL_Buffer *B) {
lua_State *L = B->L;
lua_pushlstring(L, B->b, B->n);
if (buffonstack(B))
lua_remove(L, -2); /* remove old buffer */
}
LUALIB_API void luaL_pushresultsize (luaL_Buffer *B, size_t sz) {
luaL_addsize(B, sz);
luaL_pushresult(B);
}
LUALIB_API void luaL_addvalue (luaL_Buffer *B) {
lua_State *L = B->L;
size_t l;
const char *s = lua_tolstring(L, -1, &l);
if (buffonstack(B))
lua_insert(L, -2); /* put value below buffer */
luaL_addlstring(B, s, l);
lua_remove(L, (buffonstack(B)) ? -2 : -1); /* remove value */
}
LUALIB_API void luaL_buffinit (lua_State *L, luaL_Buffer *B) {
B->L = L;
B->b = B->initb;
B->n = 0;
B->size = LUAL_BUFFERSIZE;
}
LUALIB_API char *luaL_buffinitsize (lua_State *L, luaL_Buffer *B, size_t sz) {
luaL_buffinit(L, B);
return luaL_prepbuffsize(B, sz);
}
/* }====================================================== */
/*
** {======================================================
** Reference system
** =======================================================
*/
/* index of free-list header */
#define freelist 0
LUALIB_API int luaL_ref (lua_State *L, int t) {
int ref;
if (lua_isnil(L, -1)) {
lua_pop(L, 1); /* remove from stack */
return LUA_REFNIL; /* `nil' has a unique fixed reference */
}
t = lua_absindex(L, t);
lua_rawgeti(L, t, freelist); /* get first free element */
ref = (int)lua_tointeger(L, -1); /* ref = t[freelist] */
lua_pop(L, 1); /* remove it from stack */
if (ref != 0) { /* any free element? */
lua_rawgeti(L, t, ref); /* remove it from list */
lua_rawseti(L, t, freelist); /* (t[freelist] = t[ref]) */
}
else /* no free elements */
ref = (int)lua_rawlen(L, t) + 1; /* get a new reference */
lua_rawseti(L, t, ref);
return ref;
}
LUALIB_API void luaL_unref (lua_State *L, int t, int ref) {
if (ref >= 0) {
t = lua_absindex(L, t);
lua_rawgeti(L, t, freelist);
lua_rawseti(L, t, ref); /* t[ref] = t[freelist] */
lua_pushinteger(L, ref);
lua_rawseti(L, t, freelist); /* t[freelist] = ref */
}
}
/* }====================================================== */
/*
** {======================================================
** Load functions
** =======================================================
*/
typedef struct LoadF {
int n; /* number of pre-read characters */
FILE *f; /* file being read */
char buff[LUAL_BUFFERSIZE]; /* area for reading file */
} LoadF;
static const char *getF (lua_State *L, void *ud, size_t *size) {
LoadF *lf = (LoadF *)ud;
(void)L; /* not used */
if (lf->n > 0) { /* are there pre-read characters to be read? */
*size = lf->n; /* return them (chars already in buffer) */
lf->n = 0; /* no more pre-read characters */
}
else { /* read a block from file */
/* 'fread' can return > 0 *and* set the EOF flag. If next call to
'getF' called 'fread', it might still wait for user input.
The next check avoids this problem. */
if (feof(lf->f)) return NULL;
*size = fread(lf->buff, 1, sizeof(lf->buff), lf->f); /* read block */
}
return lf->buff;
}
static int errfile (lua_State *L, const char *what, int fnameindex) {
const char *serr = strerror(errno);
const char *filename = lua_tostring(L, fnameindex) + 1;
lua_pushfstring(L, "cannot %s %s: %s", what, filename, serr);
lua_remove(L, fnameindex);
return LUA_ERRFILE;
}
static int skipBOM (LoadF *lf) {
const char *p = "\xEF\xBB\xBF"; /* Utf8 BOM mark */
int c;
lf->n = 0;
do {
c = getc(lf->f);
if (c == EOF || c != *(unsigned char *)p++) return c;
lf->buff[lf->n++] = c; /* to be read by the parser */
} while (*p != '\0');
lf->n = 0; /* prefix matched; discard it */
return getc(lf->f); /* return next character */
}
/*
** reads the first character of file 'f' and skips an optional BOM mark
** in its beginning plus its first line if it starts with '#'. Returns
** true if it skipped the first line. In any case, '*cp' has the
** first "valid" character of the file (after the optional BOM and
** a first-line comment).
*/
static int skipcomment (LoadF *lf, int *cp) {
int c = *cp = skipBOM(lf);
if (c == '#') { /* first line is a comment (Unix exec. file)? */
do { /* skip first line */
c = getc(lf->f);
} while (c != EOF && c != '\n') ;
*cp = getc(lf->f); /* skip end-of-line, if present */
return 1; /* there was a comment */
}
else return 0; /* no comment */
}
LUALIB_API int luaL_loadfilex (lua_State *L, const char *filename,
const char *mode) {
LoadF lf;
int status, readstatus;
int c;
int fnameindex = lua_gettop(L) + 1; /* index of filename on the stack */
if (filename == NULL) {
lua_pushliteral(L, "=stdin");
lf.f = stdin;
}
else {
lua_pushfstring(L, "@%s", filename);
lf.f = fopen(filename, "r");
if (lf.f == NULL) return errfile(L, "open", fnameindex);
}
if (skipcomment(&lf, &c)) /* read initial portion */
lf.buff[lf.n++] = '\n'; /* add line to correct line numbers */
if (c == LUA_SIGNATURE[0] && filename) { /* binary file? */
lf.f = freopen(filename, "rb", lf.f); /* reopen in binary mode */
if (lf.f == NULL) return errfile(L, "reopen", fnameindex);
skipcomment(&lf, &c); /* re-read initial portion */
}
if (c != EOF)
lf.buff[lf.n++] = c; /* 'c' is the first character of the stream */
status = lua_load(L, getF, &lf, lua_tostring(L, -1), mode);
readstatus = ferror(lf.f);
if (filename) fclose(lf.f); /* close file (even in case of errors) */
if (readstatus) {
lua_settop(L, fnameindex); /* ignore results from `lua_load' */
return errfile(L, "read", fnameindex);
}
lua_remove(L, fnameindex);
return status;
}
typedef struct LoadS {
const char *s;
size_t size;
} LoadS;
static const char *getS (lua_State *L, void *ud, size_t *size) {
LoadS *ls = (LoadS *)ud;
(void)L; /* not used */
if (ls->size == 0) return NULL;
*size = ls->size;
ls->size = 0;
return ls->s;
}
LUALIB_API int luaL_loadbufferx (lua_State *L, const char *buff, size_t size,
const char *name, const char *mode) {
LoadS ls;
ls.s = buff;
ls.size = size;
return lua_load(L, getS, &ls, name, mode);
}
LUALIB_API int luaL_loadstring (lua_State *L, const char *s) {
return luaL_loadbuffer(L, s, strlen(s), s);
}
/* }====================================================== */
LUALIB_API int luaL_getmetafield (lua_State *L, int obj, const char *event) {
if (!lua_getmetatable(L, obj)) /* no metatable? */
return 0;
lua_pushstring(L, event);
lua_rawget(L, -2);
if (lua_isnil(L, -1)) {
lua_pop(L, 2); /* remove metatable and metafield */
return 0;
}
else {
lua_remove(L, -2); /* remove only metatable */
return 1;
}
}
LUALIB_API int luaL_callmeta (lua_State *L, int obj, const char *event) {
obj = lua_absindex(L, obj);
if (!luaL_getmetafield(L, obj, event)) /* no metafield? */
return 0;
lua_pushvalue(L, obj);
lua_call(L, 1, 1);
return 1;
}
LUALIB_API int luaL_len (lua_State *L, int idx) {
int l;
int isnum;
lua_len(L, idx);
l = (int)lua_tointegerx(L, -1, &isnum);
if (!isnum)
luaL_error(L, "object length is not a number");
lua_pop(L, 1); /* remove object */
return l;
}
LUALIB_API const char *luaL_tolstring (lua_State *L, int idx, size_t *len) {
if (!luaL_callmeta(L, idx, "__tostring")) { /* no metafield? */
switch (lua_type(L, idx)) {
case LUA_TNUMBER:
case LUA_TSTRING:
lua_pushvalue(L, idx);
break;
case LUA_TBOOLEAN:
lua_pushstring(L, (lua_toboolean(L, idx) ? "true" : "false"));
break;
case LUA_TNIL:
lua_pushliteral(L, "nil");
break;
default:
lua_pushfstring(L, "%s: %p", luaL_typename(L, idx),
lua_topointer(L, idx));
break;
}
}
return lua_tolstring(L, -1, len);
}
/*
** {======================================================
** Compatibility with 5.1 module functions
** =======================================================
*/
#if defined(LUA_COMPAT_MODULE)
static const char *luaL_findtable (lua_State *L, int idx,
const char *fname, int szhint) {
const char *e;
if (idx) lua_pushvalue(L, idx);
do {
e = strchr(fname, '.');
if (e == NULL) e = fname + strlen(fname);
lua_pushlstring(L, fname, e - fname);
lua_rawget(L, -2);
if (lua_isnil(L, -1)) { /* no such field? */
lua_pop(L, 1); /* remove this nil */
lua_createtable(L, 0, (*e == '.' ? 1 : szhint)); /* new table for field */
lua_pushlstring(L, fname, e - fname);
lua_pushvalue(L, -2);
lua_settable(L, -4); /* set new table into field */
}
else if (!lua_istable(L, -1)) { /* field has a non-table value? */
lua_pop(L, 2); /* remove table and value */
return fname; /* return problematic part of the name */
}
lua_remove(L, -2); /* remove previous table */
fname = e + 1;
} while (*e == '.');
return NULL;
}
/*
** Count number of elements in a luaL_Reg list.
*/
static int libsize (const luaL_Reg *l) {
int size = 0;
for (; l && l->name; l++) size++;
return size;
}
/*
** Find or create a module table with a given name. The function
** first looks at the _LOADED table and, if that fails, try a
** global variable with that name. In any case, leaves on the stack
** the module table.
*/
LUALIB_API void luaL_pushmodule (lua_State *L, const char *modname,
int sizehint) {
luaL_findtable(L, LUA_REGISTRYINDEX, "_LOADED", 1); /* get _LOADED table */
lua_getfield(L, -1, modname); /* get _LOADED[modname] */
if (!lua_istable(L, -1)) { /* not found? */
lua_pop(L, 1); /* remove previous result */
/* try global variable (and create one if it does not exist) */
lua_pushglobaltable(L);
if (luaL_findtable(L, 0, modname, sizehint) != NULL)
luaL_error(L, "name conflict for module " LUA_QS, modname);
lua_pushvalue(L, -1);
lua_setfield(L, -3, modname); /* _LOADED[modname] = new table */
}
lua_remove(L, -2); /* remove _LOADED table */
}
LUALIB_API void luaL_openlib (lua_State *L, const char *libname,
const luaL_Reg *l, int nup) {
luaL_checkversion(L);
if (libname) {
luaL_pushmodule(L, libname, libsize(l)); /* get/create library table */
lua_insert(L, -(nup + 1)); /* move library table to below upvalues */
}
if (l)
luaL_setfuncs(L, l, nup);
else
lua_pop(L, nup); /* remove upvalues */
}
#endif
/* }====================================================== */
/*
** set functions from list 'l' into table at top - 'nup'; each
** function gets the 'nup' elements at the top as upvalues.
** Returns with only the table at the stack.
*/
LUALIB_API void luaL_setfuncs (lua_State *L, const luaL_Reg *l, int nup) {
luaL_checkversion(L);
luaL_checkstack(L, nup, "too many upvalues");
for (; l->name != NULL; l++) { /* fill the table with given functions */
int i;
for (i = 0; i < nup; i++) /* copy upvalues to the top */
lua_pushvalue(L, -nup);
lua_pushcclosure(L, l->func, nup); /* closure with those upvalues */
lua_setfield(L, -(nup + 2), l->name);
}
lua_pop(L, nup); /* remove upvalues */
}
/*
** ensure that stack[idx][fname] has a table and push that table
** into the stack
*/
LUALIB_API int luaL_getsubtable (lua_State *L, int idx, const char *fname) {
lua_getfield(L, idx, fname);
if (lua_istable(L, -1)) return 1; /* table already there */
else {
lua_pop(L, 1); /* remove previous result */
idx = lua_absindex(L, idx);
lua_newtable(L);
lua_pushvalue(L, -1); /* copy to be left at top */
lua_setfield(L, idx, fname); /* assign new table to field */
return 0; /* false, because did not find table there */
}
}
/*
** stripped-down 'require'. Calls 'openf' to open a module,
** registers the result in 'package.loaded' table and, if 'glb'
** is true, also registers the result in the global table.
** Leaves resulting module on the top.
*/
LUALIB_API void luaL_requiref (lua_State *L, const char *modname,
lua_CFunction openf, int glb) {
lua_pushcfunction(L, openf);
lua_pushstring(L, modname); /* argument to open function */
lua_call(L, 1, 1); /* open module */
luaL_getsubtable(L, LUA_REGISTRYINDEX, "_LOADED");
lua_pushvalue(L, -2); /* make copy of module (call result) */
lua_setfield(L, -2, modname); /* _LOADED[modname] = module */
lua_pop(L, 1); /* remove _LOADED table */
if (glb) {
lua_pushvalue(L, -1); /* copy of 'mod' */
lua_setglobal(L, modname); /* _G[modname] = module */
}
}
LUALIB_API const char *luaL_gsub (lua_State *L, const char *s, const char *p,
const char *r) {
const char *wild;
size_t l = strlen(p);
luaL_Buffer b;
luaL_buffinit(L, &b);
while ((wild = strstr(s, p)) != NULL) {
luaL_addlstring(&b, s, wild - s); /* push prefix */
luaL_addstring(&b, r); /* push replacement in place of pattern */
s = wild + l; /* continue after `p' */
}
luaL_addstring(&b, s); /* push last suffix */
luaL_pushresult(&b);
return lua_tostring(L, -1);
}
static void *l_alloc (void *ud, void *ptr, size_t osize, size_t nsize) {
(void)ud; (void)osize; /* not used */
if (nsize == 0) {
free(ptr);
return NULL;
}
else
return realloc(ptr, nsize);
}
static int panic (lua_State *L) {
luai_writestringerror("PANIC: unprotected error in call to Lua API (%s)\n",
lua_tostring(L, -1));
return 0; /* return to Lua to abort */
}
LUALIB_API lua_State *luaL_newstate (void) {
lua_State *L = lua_newstate(l_alloc, NULL);
if (L) lua_atpanic(L, &panic);
return L;
}
LUALIB_API void luaL_checkversion_ (lua_State *L, lua_Number ver) {
const lua_Number *v = lua_version(L);
if (v != lua_version(NULL))
luaL_error(L, "multiple Lua VMs detected");
else if (*v != ver)
luaL_error(L, "version mismatch: app. needs %f, Lua core provides %f",
ver, *v);
/* check conversions number -> integer types */
lua_pushnumber(L, -(lua_Number)0x1234);
if (lua_tointeger(L, -1) != -0x1234 ||
lua_tounsigned(L, -1) != (lua_Unsigned)-0x1234)
luaL_error(L, "bad conversion number->int;"
" must recompile Lua with proper settings");
lua_pop(L, 1);
}
-210
View File
@@ -1,210 +0,0 @@
/*
** $Id: lauxlib.h,v 1.120 2011/11/29 15:55:08 roberto Exp $
** Auxiliary functions for building Lua libraries
** See Copyright Notice in lua.h
*/
#ifndef lauxlib_h
#define lauxlib_h
#include <stddef.h>
#include <stdio.h>
#include "lua.h"
/* extra error code for `luaL_load' */
#define LUA_ERRFILE (LUA_ERRERR+1)
typedef struct luaL_Reg {
const char *name;
lua_CFunction func;
} luaL_Reg;
LUALIB_API void (luaL_checkversion_) (lua_State *L, lua_Number ver);
#define luaL_checkversion(L) luaL_checkversion_(L, LUA_VERSION_NUM)
LUALIB_API int (luaL_getmetafield) (lua_State *L, int obj, const char *e);
LUALIB_API int (luaL_callmeta) (lua_State *L, int obj, const char *e);
LUALIB_API const char *(luaL_tolstring) (lua_State *L, int idx, size_t *len);
LUALIB_API int (luaL_argerror) (lua_State *L, int numarg, const char *extramsg);
LUALIB_API const char *(luaL_checklstring) (lua_State *L, int numArg,
size_t *l);
LUALIB_API const char *(luaL_optlstring) (lua_State *L, int numArg,
const char *def, size_t *l);
LUALIB_API lua_Number (luaL_checknumber) (lua_State *L, int numArg);
LUALIB_API lua_Number (luaL_optnumber) (lua_State *L, int nArg, lua_Number def);
LUALIB_API lua_Integer (luaL_checkinteger) (lua_State *L, int numArg);
LUALIB_API lua_Integer (luaL_optinteger) (lua_State *L, int nArg,
lua_Integer def);
LUALIB_API lua_Unsigned (luaL_checkunsigned) (lua_State *L, int numArg);
LUALIB_API lua_Unsigned (luaL_optunsigned) (lua_State *L, int numArg,
lua_Unsigned def);
LUALIB_API void (luaL_checkstack) (lua_State *L, int sz, const char *msg);
LUALIB_API void (luaL_checktype) (lua_State *L, int narg, int t);
LUALIB_API void (luaL_checkany) (lua_State *L, int narg);
LUALIB_API int (luaL_newmetatable) (lua_State *L, const char *tname);
LUALIB_API void (luaL_setmetatable) (lua_State *L, const char *tname);
LUALIB_API void *(luaL_testudata) (lua_State *L, int ud, const char *tname);
LUALIB_API void *(luaL_checkudata) (lua_State *L, int ud, const char *tname);
LUALIB_API void (luaL_where) (lua_State *L, int lvl);
LUALIB_API int (luaL_error) (lua_State *L, const char *fmt, ...);
LUALIB_API int (luaL_checkoption) (lua_State *L, int narg, const char *def,
const char *const lst[]);
LUALIB_API int (luaL_fileresult) (lua_State *L, int stat, const char *fname);
LUALIB_API int (luaL_execresult) (lua_State *L, int stat);
/* pre-defined references */
#define LUA_NOREF (-2)
#define LUA_REFNIL (-1)
LUALIB_API int (luaL_ref) (lua_State *L, int t);
LUALIB_API void (luaL_unref) (lua_State *L, int t, int ref);
LUALIB_API int (luaL_loadfilex) (lua_State *L, const char *filename,
const char *mode);
#define luaL_loadfile(L,f) luaL_loadfilex(L,f,NULL)
LUALIB_API int (luaL_loadbufferx) (lua_State *L, const char *buff, size_t sz,
const char *name, const char *mode);
LUALIB_API int (luaL_loadstring) (lua_State *L, const char *s);
LUALIB_API lua_State *(luaL_newstate) (void);
LUALIB_API int (luaL_len) (lua_State *L, int idx);
LUALIB_API const char *(luaL_gsub) (lua_State *L, const char *s, const char *p,
const char *r);
LUALIB_API void (luaL_setfuncs) (lua_State *L, const luaL_Reg *l, int nup);
LUALIB_API int (luaL_getsubtable) (lua_State *L, int idx, const char *fname);
LUALIB_API void (luaL_traceback) (lua_State *L, lua_State *L1,
const char *msg, int level);
LUALIB_API void (luaL_requiref) (lua_State *L, const char *modname,
lua_CFunction openf, int glb);
/*
** ===============================================================
** some useful macros
** ===============================================================
*/
#define luaL_newlibtable(L,l) \
lua_createtable(L, 0, sizeof(l)/sizeof((l)[0]) - 1)
#define luaL_newlib(L,l) (luaL_newlibtable(L,l), luaL_setfuncs(L,l,0))
#define luaL_argcheck(L, cond,numarg,extramsg) \
((void)((cond) || luaL_argerror(L, (numarg), (extramsg))))
#define luaL_checkstring(L,n) (luaL_checklstring(L, (n), NULL))
#define luaL_optstring(L,n,d) (luaL_optlstring(L, (n), (d), NULL))
#define luaL_checkint(L,n) ((int)luaL_checkinteger(L, (n)))
#define luaL_optint(L,n,d) ((int)luaL_optinteger(L, (n), (d)))
#define luaL_checklong(L,n) ((long)luaL_checkinteger(L, (n)))
#define luaL_optlong(L,n,d) ((long)luaL_optinteger(L, (n), (d)))
#define luaL_typename(L,i) lua_typename(L, lua_type(L,(i)))
#define luaL_dofile(L, fn) \
(luaL_loadfile(L, fn) || lua_pcall(L, 0, LUA_MULTRET, 0))
#define luaL_dostring(L, s) \
(luaL_loadstring(L, s) || lua_pcall(L, 0, LUA_MULTRET, 0))
#define luaL_getmetatable(L,n) (lua_getfield(L, LUA_REGISTRYINDEX, (n)))
#define luaL_opt(L,f,n,d) (lua_isnoneornil(L,(n)) ? (d) : f(L,(n)))
#define luaL_loadbuffer(L,s,sz,n) luaL_loadbufferx(L,s,sz,n,NULL)
/*
** {======================================================
** Generic Buffer manipulation
** =======================================================
*/
typedef struct luaL_Buffer {
char *b; /* buffer address */
size_t size; /* buffer size */
size_t n; /* number of characters in buffer */
lua_State *L;
char initb[LUAL_BUFFERSIZE]; /* initial buffer */
} luaL_Buffer;
#define luaL_addchar(B,c) \
((void)((B)->n < (B)->size || luaL_prepbuffsize((B), 1)), \
((B)->b[(B)->n++] = (c)))
#define luaL_addsize(B,s) ((B)->n += (s))
LUALIB_API void (luaL_buffinit) (lua_State *L, luaL_Buffer *B);
LUALIB_API char *(luaL_prepbuffsize) (luaL_Buffer *B, size_t sz);
LUALIB_API void (luaL_addlstring) (luaL_Buffer *B, const char *s, size_t l);
LUALIB_API void (luaL_addstring) (luaL_Buffer *B, const char *s);
LUALIB_API void (luaL_addvalue) (luaL_Buffer *B);
LUALIB_API void (luaL_pushresult) (luaL_Buffer *B);
LUALIB_API void (luaL_pushresultsize) (luaL_Buffer *B, size_t sz);
LUALIB_API char *(luaL_buffinitsize) (lua_State *L, luaL_Buffer *B, size_t sz);
#define luaL_prepbuffer(B) luaL_prepbuffsize(B, LUAL_BUFFERSIZE)
/* }====================================================== */
/*
** {======================================================
** File handles for IO library
** =======================================================
*/
/*
** A file handle is a userdata with metatable 'LUA_FILEHANDLE' and
** initial structure 'luaL_Stream' (it may contain other fields
** after that initial structure).
*/
#define LUA_FILEHANDLE "FILE*"
typedef struct luaL_Stream {
FILE *f; /* stream (NULL for incompletely created streams) */
lua_CFunction closef; /* to close stream (NULL for closed streams) */
} luaL_Stream;
/* }====================================================== */
/* compatibility with old module system */
#if defined(LUA_COMPAT_MODULE)
LUALIB_API void (luaL_pushmodule) (lua_State *L, const char *modname,
int sizehint);
LUALIB_API void (luaL_openlib) (lua_State *L, const char *libname,
const luaL_Reg *l, int nup);
#define luaL_register(L,n,l) (luaL_openlib(L,(n),(l),0))
#endif
#endif
-459
View File
@@ -1,459 +0,0 @@
/*
** $Id: lbaselib.c,v 1.274 2012/04/27 14:13:19 roberto Exp $
** Basic library
** See Copyright Notice in lua.h
*/
#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define lbaselib_c
#define LUA_LIB
#include "lua.h"
#include "lauxlib.h"
#include "lualib.h"
static int luaB_print (lua_State *L) {
int n = lua_gettop(L); /* number of arguments */
int i;
lua_getglobal(L, "tostring");
for (i=1; i<=n; i++) {
const char *s;
size_t l;
lua_pushvalue(L, -1); /* function to be called */
lua_pushvalue(L, i); /* value to print */
lua_call(L, 1, 1);
s = lua_tolstring(L, -1, &l); /* get result */
if (s == NULL)
return luaL_error(L,
LUA_QL("tostring") " must return a string to " LUA_QL("print"));
if (i>1) luai_writestring("\t", 1);
luai_writestring(s, l);
lua_pop(L, 1); /* pop result */
}
luai_writeline();
return 0;
}
#define SPACECHARS " \f\n\r\t\v"
static int luaB_tonumber (lua_State *L) {
if (lua_isnoneornil(L, 2)) { /* standard conversion */
int isnum;
lua_Number n = lua_tonumberx(L, 1, &isnum);
if (isnum) {
lua_pushnumber(L, n);
return 1;
} /* else not a number; must be something */
luaL_checkany(L, 1);
}
else {
size_t l;
const char *s = luaL_checklstring(L, 1, &l);
const char *e = s + l; /* end point for 's' */
int base = luaL_checkint(L, 2);
int neg = 0;
luaL_argcheck(L, 2 <= base && base <= 36, 2, "base out of range");
s += strspn(s, SPACECHARS); /* skip initial spaces */
if (*s == '-') { s++; neg = 1; } /* handle signal */
else if (*s == '+') s++;
if (isalnum((unsigned char)*s)) {
lua_Number n = 0;
do {
int digit = (isdigit((unsigned char)*s)) ? *s - '0'
: toupper((unsigned char)*s) - 'A' + 10;
if (digit >= base) break; /* invalid numeral; force a fail */
n = n * (lua_Number)base + (lua_Number)digit;
s++;
} while (isalnum((unsigned char)*s));
s += strspn(s, SPACECHARS); /* skip trailing spaces */
if (s == e) { /* no invalid trailing characters? */
lua_pushnumber(L, (neg) ? -n : n);
return 1;
} /* else not a number */
} /* else not a number */
}
lua_pushnil(L); /* not a number */
return 1;
}
static int luaB_error (lua_State *L) {
int level = luaL_optint(L, 2, 1);
lua_settop(L, 1);
if (lua_isstring(L, 1) && level > 0) { /* add extra information? */
luaL_where(L, level);
lua_pushvalue(L, 1);
lua_concat(L, 2);
}
return lua_error(L);
}
static int luaB_getmetatable (lua_State *L) {
luaL_checkany(L, 1);
if (!lua_getmetatable(L, 1)) {
lua_pushnil(L);
return 1; /* no metatable */
}
luaL_getmetafield(L, 1, "__metatable");
return 1; /* returns either __metatable field (if present) or metatable */
}
static int luaB_setmetatable (lua_State *L) {
int t = lua_type(L, 2);
luaL_checktype(L, 1, LUA_TTABLE);
luaL_argcheck(L, t == LUA_TNIL || t == LUA_TTABLE, 2,
"nil or table expected");
if (luaL_getmetafield(L, 1, "__metatable"))
return luaL_error(L, "cannot change a protected metatable");
lua_settop(L, 2);
lua_setmetatable(L, 1);
return 1;
}
static int luaB_rawequal (lua_State *L) {
luaL_checkany(L, 1);
luaL_checkany(L, 2);
lua_pushboolean(L, lua_rawequal(L, 1, 2));
return 1;
}
static int luaB_rawlen (lua_State *L) {
int t = lua_type(L, 1);
luaL_argcheck(L, t == LUA_TTABLE || t == LUA_TSTRING, 1,
"table or string expected");
lua_pushinteger(L, lua_rawlen(L, 1));
return 1;
}
static int luaB_rawget (lua_State *L) {
luaL_checktype(L, 1, LUA_TTABLE);
luaL_checkany(L, 2);
lua_settop(L, 2);
lua_rawget(L, 1);
return 1;
}
static int luaB_rawset (lua_State *L) {
luaL_checktype(L, 1, LUA_TTABLE);
luaL_checkany(L, 2);
luaL_checkany(L, 3);
lua_settop(L, 3);
lua_rawset(L, 1);
return 1;
}
static int luaB_collectgarbage (lua_State *L) {
static const char *const opts[] = {"stop", "restart", "collect",
"count", "step", "setpause", "setstepmul",
"setmajorinc", "isrunning", "generational", "incremental", NULL};
static const int optsnum[] = {LUA_GCSTOP, LUA_GCRESTART, LUA_GCCOLLECT,
LUA_GCCOUNT, LUA_GCSTEP, LUA_GCSETPAUSE, LUA_GCSETSTEPMUL,
LUA_GCSETMAJORINC, LUA_GCISRUNNING, LUA_GCGEN, LUA_GCINC};
int o = optsnum[luaL_checkoption(L, 1, "collect", opts)];
int ex = luaL_optint(L, 2, 0);
int res = lua_gc(L, o, ex);
switch (o) {
case LUA_GCCOUNT: {
int b = lua_gc(L, LUA_GCCOUNTB, 0);
lua_pushnumber(L, res + ((lua_Number)b/1024));
lua_pushinteger(L, b);
return 2;
}
case LUA_GCSTEP: case LUA_GCISRUNNING: {
lua_pushboolean(L, res);
return 1;
}
default: {
lua_pushinteger(L, res);
return 1;
}
}
}
static int luaB_type (lua_State *L) {
luaL_checkany(L, 1);
lua_pushstring(L, luaL_typename(L, 1));
return 1;
}
static int pairsmeta (lua_State *L, const char *method, int iszero,
lua_CFunction iter) {
if (!luaL_getmetafield(L, 1, method)) { /* no metamethod? */
luaL_checktype(L, 1, LUA_TTABLE); /* argument must be a table */
lua_pushcfunction(L, iter); /* will return generator, */
lua_pushvalue(L, 1); /* state, */
if (iszero) lua_pushinteger(L, 0); /* and initial value */
else lua_pushnil(L);
}
else {
lua_pushvalue(L, 1); /* argument 'self' to metamethod */
lua_call(L, 1, 3); /* get 3 values from metamethod */
}
return 3;
}
static int luaB_next (lua_State *L) {
luaL_checktype(L, 1, LUA_TTABLE);
lua_settop(L, 2); /* create a 2nd argument if there isn't one */
if (lua_next(L, 1))
return 2;
else {
lua_pushnil(L);
return 1;
}
}
static int luaB_pairs (lua_State *L) {
return pairsmeta(L, "__pairs", 0, luaB_next);
}
static int ipairsaux (lua_State *L) {
int i = luaL_checkint(L, 2);
luaL_checktype(L, 1, LUA_TTABLE);
i++; /* next value */
lua_pushinteger(L, i);
lua_rawgeti(L, 1, i);
return (lua_isnil(L, -1)) ? 1 : 2;
}
static int luaB_ipairs (lua_State *L) {
return pairsmeta(L, "__ipairs", 1, ipairsaux);
}
static int load_aux (lua_State *L, int status) {
if (status == LUA_OK)
return 1;
else {
lua_pushnil(L);
lua_insert(L, -2); /* put before error message */
return 2; /* return nil plus error message */
}
}
static int luaB_loadfile (lua_State *L) {
const char *fname = luaL_optstring(L, 1, NULL);
const char *mode = luaL_optstring(L, 2, NULL);
int env = !lua_isnone(L, 3); /* 'env' parameter? */
int status = luaL_loadfilex(L, fname, mode);
if (status == LUA_OK && env) { /* 'env' parameter? */
lua_pushvalue(L, 3);
lua_setupvalue(L, -2, 1); /* set it as 1st upvalue of loaded chunk */
}
return load_aux(L, status);
}
/*
** {======================================================
** Generic Read function
** =======================================================
*/
/*
** reserved slot, above all arguments, to hold a copy of the returned
** string to avoid it being collected while parsed. 'load' has four
** optional arguments (chunk, source name, mode, and environment).
*/
#define RESERVEDSLOT 5
/*
** Reader for generic `load' function: `lua_load' uses the
** stack for internal stuff, so the reader cannot change the
** stack top. Instead, it keeps its resulting string in a
** reserved slot inside the stack.
*/
static const char *generic_reader (lua_State *L, void *ud, size_t *size) {
(void)(ud); /* not used */
luaL_checkstack(L, 2, "too many nested functions");
lua_pushvalue(L, 1); /* get function */
lua_call(L, 0, 1); /* call it */
if (lua_isnil(L, -1)) {
lua_pop(L, 1); /* pop result */
*size = 0;
return NULL;
}
else if (!lua_isstring(L, -1))
luaL_error(L, "reader function must return a string");
lua_replace(L, RESERVEDSLOT); /* save string in reserved slot */
return lua_tolstring(L, RESERVEDSLOT, size);
}
static int luaB_load (lua_State *L) {
int status;
size_t l;
int top = lua_gettop(L);
const char *s = lua_tolstring(L, 1, &l);
const char *mode = luaL_optstring(L, 3, "bt");
if (s != NULL) { /* loading a string? */
const char *chunkname = luaL_optstring(L, 2, s);
status = luaL_loadbufferx(L, s, l, chunkname, mode);
}
else { /* loading from a reader function */
const char *chunkname = luaL_optstring(L, 2, "=(load)");
luaL_checktype(L, 1, LUA_TFUNCTION);
lua_settop(L, RESERVEDSLOT); /* create reserved slot */
status = lua_load(L, generic_reader, NULL, chunkname, mode);
}
if (status == LUA_OK && top >= 4) { /* is there an 'env' argument */
lua_pushvalue(L, 4); /* environment for loaded function */
lua_setupvalue(L, -2, 1); /* set it as 1st upvalue */
}
return load_aux(L, status);
}
/* }====================================================== */
static int dofilecont (lua_State *L) {
return lua_gettop(L) - 1;
}
static int luaB_dofile (lua_State *L) {
const char *fname = luaL_optstring(L, 1, NULL);
lua_settop(L, 1);
if (luaL_loadfile(L, fname) != LUA_OK) lua_error(L);
lua_callk(L, 0, LUA_MULTRET, 0, dofilecont);
return dofilecont(L);
}
static int luaB_assert (lua_State *L) {
if (!lua_toboolean(L, 1))
return luaL_error(L, "%s", luaL_optstring(L, 2, "assertion failed!"));
return lua_gettop(L);
}
static int luaB_select (lua_State *L) {
int n = lua_gettop(L);
if (lua_type(L, 1) == LUA_TSTRING && *lua_tostring(L, 1) == '#') {
lua_pushinteger(L, n-1);
return 1;
}
else {
int i = luaL_checkint(L, 1);
if (i < 0) i = n + i;
else if (i > n) i = n;
luaL_argcheck(L, 1 <= i, 1, "index out of range");
return n - i;
}
}
static int finishpcall (lua_State *L, int status) {
if (!lua_checkstack(L, 1)) { /* no space for extra boolean? */
lua_settop(L, 0); /* create space for return values */
lua_pushboolean(L, 0);
lua_pushstring(L, "stack overflow");
return 2; /* return false, msg */
}
lua_pushboolean(L, status); /* first result (status) */
lua_replace(L, 1); /* put first result in first slot */
return lua_gettop(L);
}
static int pcallcont (lua_State *L) {
int status = lua_getctx(L, NULL);
return finishpcall(L, (status == LUA_YIELD));
}
static int luaB_pcall (lua_State *L) {
int status;
luaL_checkany(L, 1);
lua_pushnil(L);
lua_insert(L, 1); /* create space for status result */
status = lua_pcallk(L, lua_gettop(L) - 2, LUA_MULTRET, 0, 0, pcallcont);
return finishpcall(L, (status == LUA_OK));
}
static int luaB_xpcall (lua_State *L) {
int status;
int n = lua_gettop(L);
luaL_argcheck(L, n >= 2, 2, "value expected");
lua_pushvalue(L, 1); /* exchange function... */
lua_copy(L, 2, 1); /* ...and error handler */
lua_replace(L, 2);
status = lua_pcallk(L, n - 2, LUA_MULTRET, 1, 0, pcallcont);
return finishpcall(L, (status == LUA_OK));
}
static int luaB_tostring (lua_State *L) {
luaL_checkany(L, 1);
luaL_tolstring(L, 1, NULL);
return 1;
}
static const luaL_Reg base_funcs[] = {
{"assert", luaB_assert},
{"collectgarbage", luaB_collectgarbage},
{"dofile", luaB_dofile},
{"error", luaB_error},
{"getmetatable", luaB_getmetatable},
{"ipairs", luaB_ipairs},
{"loadfile", luaB_loadfile},
{"load", luaB_load},
#if defined(LUA_COMPAT_LOADSTRING)
{"loadstring", luaB_load},
#endif
{"next", luaB_next},
{"pairs", luaB_pairs},
{"pcall", luaB_pcall},
{"print", luaB_print},
{"rawequal", luaB_rawequal},
{"rawlen", luaB_rawlen},
{"rawget", luaB_rawget},
{"rawset", luaB_rawset},
{"select", luaB_select},
{"setmetatable", luaB_setmetatable},
{"tonumber", luaB_tonumber},
{"tostring", luaB_tostring},
{"type", luaB_type},
{"xpcall", luaB_xpcall},
{NULL, NULL}
};
LUAMOD_API int luaopen_base (lua_State *L) {
/* set global _G */
lua_pushglobaltable(L);
lua_pushglobaltable(L);
lua_setfield(L, -2, "_G");
/* open lib into global table */
luaL_setfuncs(L, base_funcs, 0);
lua_pushliteral(L, LUA_VERSION);
lua_setfield(L, -2, "_VERSION"); /* set global _VERSION */
return 1;
}
-209
View File
@@ -1,209 +0,0 @@
/*
** $Id: lbitlib.c,v 1.16 2011/06/20 16:35:23 roberto Exp $
** Standard library for bitwise operations
** See Copyright Notice in lua.h
*/
#define lbitlib_c
#define LUA_LIB
#include "lua.h"
#include "lauxlib.h"
#include "lualib.h"
/* number of bits to consider in a number */
#if !defined(LUA_NBITS)
#define LUA_NBITS 32
#endif
#define ALLONES (~(((~(lua_Unsigned)0) << (LUA_NBITS - 1)) << 1))
/* macro to trim extra bits */
#define trim(x) ((x) & ALLONES)
/* builds a number with 'n' ones (1 <= n <= LUA_NBITS) */
#define mask(n) (~((ALLONES << 1) << ((n) - 1)))
typedef lua_Unsigned b_uint;
static b_uint andaux (lua_State *L) {
int i, n = lua_gettop(L);
b_uint r = ~(b_uint)0;
for (i = 1; i <= n; i++)
r &= luaL_checkunsigned(L, i);
return trim(r);
}
static int b_and (lua_State *L) {
b_uint r = andaux(L);
lua_pushunsigned(L, r);
return 1;
}
static int b_test (lua_State *L) {
b_uint r = andaux(L);
lua_pushboolean(L, r != 0);
return 1;
}
static int b_or (lua_State *L) {
int i, n = lua_gettop(L);
b_uint r = 0;
for (i = 1; i <= n; i++)
r |= luaL_checkunsigned(L, i);
lua_pushunsigned(L, trim(r));
return 1;
}
static int b_xor (lua_State *L) {
int i, n = lua_gettop(L);
b_uint r = 0;
for (i = 1; i <= n; i++)
r ^= luaL_checkunsigned(L, i);
lua_pushunsigned(L, trim(r));
return 1;
}
static int b_not (lua_State *L) {
b_uint r = ~luaL_checkunsigned(L, 1);
lua_pushunsigned(L, trim(r));
return 1;
}
static int b_shift (lua_State *L, b_uint r, int i) {
if (i < 0) { /* shift right? */
i = -i;
r = trim(r);
if (i >= LUA_NBITS) r = 0;
else r >>= i;
}
else { /* shift left */
if (i >= LUA_NBITS) r = 0;
else r <<= i;
r = trim(r);
}
lua_pushunsigned(L, r);
return 1;
}
static int b_lshift (lua_State *L) {
return b_shift(L, luaL_checkunsigned(L, 1), luaL_checkint(L, 2));
}
static int b_rshift (lua_State *L) {
return b_shift(L, luaL_checkunsigned(L, 1), -luaL_checkint(L, 2));
}
static int b_arshift (lua_State *L) {
b_uint r = luaL_checkunsigned(L, 1);
int i = luaL_checkint(L, 2);
if (i < 0 || !(r & ((b_uint)1 << (LUA_NBITS - 1))))
return b_shift(L, r, -i);
else { /* arithmetic shift for 'negative' number */
if (i >= LUA_NBITS) r = ALLONES;
else
r = trim((r >> i) | ~(~(b_uint)0 >> i)); /* add signal bit */
lua_pushunsigned(L, r);
return 1;
}
}
static int b_rot (lua_State *L, int i) {
b_uint r = luaL_checkunsigned(L, 1);
i &= (LUA_NBITS - 1); /* i = i % NBITS */
r = trim(r);
r = (r << i) | (r >> (LUA_NBITS - i));
lua_pushunsigned(L, trim(r));
return 1;
}
static int b_lrot (lua_State *L) {
return b_rot(L, luaL_checkint(L, 2));
}
static int b_rrot (lua_State *L) {
return b_rot(L, -luaL_checkint(L, 2));
}
/*
** get field and width arguments for field-manipulation functions,
** checking whether they are valid
*/
static int fieldargs (lua_State *L, int farg, int *width) {
int f = luaL_checkint(L, farg);
int w = luaL_optint(L, farg + 1, 1);
luaL_argcheck(L, 0 <= f, farg, "field cannot be negative");
luaL_argcheck(L, 0 < w, farg + 1, "width must be positive");
if (f + w > LUA_NBITS)
luaL_error(L, "trying to access non-existent bits");
*width = w;
return f;
}
static int b_extract (lua_State *L) {
int w;
b_uint r = luaL_checkunsigned(L, 1);
int f = fieldargs(L, 2, &w);
r = (r >> f) & mask(w);
lua_pushunsigned(L, r);
return 1;
}
static int b_replace (lua_State *L) {
int w;
b_uint r = luaL_checkunsigned(L, 1);
b_uint v = luaL_checkunsigned(L, 2);
int f = fieldargs(L, 3, &w);
int m = mask(w);
v &= m; /* erase bits outside given width */
r = (r & ~(m << f)) | (v << f);
lua_pushunsigned(L, r);
return 1;
}
static const luaL_Reg bitlib[] = {
{"arshift", b_arshift},
{"band", b_and},
{"bnot", b_not},
{"bor", b_or},
{"bxor", b_xor},
{"btest", b_test},
{"extract", b_extract},
{"lrotate", b_lrot},
{"lshift", b_lshift},
{"replace", b_replace},
{"rrotate", b_rrot},
{"rshift", b_rshift},
{NULL, NULL}
};
LUAMOD_API int luaopen_bit32 (lua_State *L) {
luaL_newlib(L, bitlib);
return 1;
}
-882
View File
@@ -1,882 +0,0 @@
/*
** $Id: lcode.c,v 2.60 2011/08/30 16:26:41 roberto Exp $
** Code generator for Lua
** See Copyright Notice in lua.h
*/
#include <stdlib.h>
#define lcode_c
#define LUA_CORE
#include "lua.h"
#include "lcode.h"
#include "ldebug.h"
#include "ldo.h"
#include "lgc.h"
#include "llex.h"
#include "lmem.h"
#include "lobject.h"
#include "lopcodes.h"
#include "lparser.h"
#include "lstring.h"
#include "ltable.h"
#include "lvm.h"
#define hasjumps(e) ((e)->t != (e)->f)
static int isnumeral(expdesc *e) {
return (e->k == VKNUM && e->t == NO_JUMP && e->f == NO_JUMP);
}
void luaK_nil (FuncState *fs, int from, int n) {
Instruction *previous;
int l = from + n - 1; /* last register to set nil */
if (fs->pc > fs->lasttarget) { /* no jumps to current position? */
previous = &fs->f->code[fs->pc-1];
if (GET_OPCODE(*previous) == OP_LOADNIL) {
int pfrom = GETARG_A(*previous);
int pl = pfrom + GETARG_B(*previous);
if ((pfrom <= from && from <= pl + 1) ||
(from <= pfrom && pfrom <= l + 1)) { /* can connect both? */
if (pfrom < from) from = pfrom; /* from = min(from, pfrom) */
if (pl > l) l = pl; /* l = max(l, pl) */
SETARG_A(*previous, from);
SETARG_B(*previous, l - from);
return;
}
} /* else go through */
}
luaK_codeABC(fs, OP_LOADNIL, from, n - 1, 0); /* else no optimization */
}
int luaK_jump (FuncState *fs) {
int jpc = fs->jpc; /* save list of jumps to here */
int j;
fs->jpc = NO_JUMP;
j = luaK_codeAsBx(fs, OP_JMP, 0, NO_JUMP);
luaK_concat(fs, &j, jpc); /* keep them on hold */
return j;
}
void luaK_ret (FuncState *fs, int first, int nret) {
luaK_codeABC(fs, OP_RETURN, first, nret+1, 0);
}
static int condjump (FuncState *fs, OpCode op, int A, int B, int C) {
luaK_codeABC(fs, op, A, B, C);
return luaK_jump(fs);
}
static void fixjump (FuncState *fs, int pc, int dest) {
Instruction *jmp = &fs->f->code[pc];
int offset = dest-(pc+1);
lua_assert(dest != NO_JUMP);
if (abs(offset) > MAXARG_sBx)
luaX_syntaxerror(fs->ls, "control structure too long");
SETARG_sBx(*jmp, offset);
}
/*
** returns current `pc' and marks it as a jump target (to avoid wrong
** optimizations with consecutive instructions not in the same basic block).
*/
int luaK_getlabel (FuncState *fs) {
fs->lasttarget = fs->pc;
return fs->pc;
}
static int getjump (FuncState *fs, int pc) {
int offset = GETARG_sBx(fs->f->code[pc]);
if (offset == NO_JUMP) /* point to itself represents end of list */
return NO_JUMP; /* end of list */
else
return (pc+1)+offset; /* turn offset into absolute position */
}
static Instruction *getjumpcontrol (FuncState *fs, int pc) {
Instruction *pi = &fs->f->code[pc];
if (pc >= 1 && testTMode(GET_OPCODE(*(pi-1))))
return pi-1;
else
return pi;
}
/*
** check whether list has any jump that do not produce a value
** (or produce an inverted value)
*/
static int need_value (FuncState *fs, int list) {
for (; list != NO_JUMP; list = getjump(fs, list)) {
Instruction i = *getjumpcontrol(fs, list);
if (GET_OPCODE(i) != OP_TESTSET) return 1;
}
return 0; /* not found */
}
static int patchtestreg (FuncState *fs, int node, int reg) {
Instruction *i = getjumpcontrol(fs, node);
if (GET_OPCODE(*i) != OP_TESTSET)
return 0; /* cannot patch other instructions */
if (reg != NO_REG && reg != GETARG_B(*i))
SETARG_A(*i, reg);
else /* no register to put value or register already has the value */
*i = CREATE_ABC(OP_TEST, GETARG_B(*i), 0, GETARG_C(*i));
return 1;
}
static void removevalues (FuncState *fs, int list) {
for (; list != NO_JUMP; list = getjump(fs, list))
patchtestreg(fs, list, NO_REG);
}
static void patchlistaux (FuncState *fs, int list, int vtarget, int reg,
int dtarget) {
while (list != NO_JUMP) {
int next = getjump(fs, list);
if (patchtestreg(fs, list, reg))
fixjump(fs, list, vtarget);
else
fixjump(fs, list, dtarget); /* jump to default target */
list = next;
}
}
static void dischargejpc (FuncState *fs) {
patchlistaux(fs, fs->jpc, fs->pc, NO_REG, fs->pc);
fs->jpc = NO_JUMP;
}
void luaK_patchlist (FuncState *fs, int list, int target) {
if (target == fs->pc)
luaK_patchtohere(fs, list);
else {
lua_assert(target < fs->pc);
patchlistaux(fs, list, target, NO_REG, target);
}
}
LUAI_FUNC void luaK_patchclose (FuncState *fs, int list, int level) {
level++; /* argument is +1 to reserve 0 as non-op */
while (list != NO_JUMP) {
int next = getjump(fs, list);
lua_assert(GET_OPCODE(fs->f->code[list]) == OP_JMP &&
(GETARG_A(fs->f->code[list]) == 0 ||
GETARG_A(fs->f->code[list]) >= level));
SETARG_A(fs->f->code[list], level);
list = next;
}
}
void luaK_patchtohere (FuncState *fs, int list) {
luaK_getlabel(fs);
luaK_concat(fs, &fs->jpc, list);
}
void luaK_concat (FuncState *fs, int *l1, int l2) {
if (l2 == NO_JUMP) return;
else if (*l1 == NO_JUMP)
*l1 = l2;
else {
int list = *l1;
int next;
while ((next = getjump(fs, list)) != NO_JUMP) /* find last element */
list = next;
fixjump(fs, list, l2);
}
}
static int luaK_code (FuncState *fs, Instruction i) {
Proto *f = fs->f;
dischargejpc(fs); /* `pc' will change */
/* put new instruction in code array */
luaM_growvector(fs->ls->L, f->code, fs->pc, f->sizecode, Instruction,
MAX_INT, "opcodes");
f->code[fs->pc] = i;
/* save corresponding line information */
luaM_growvector(fs->ls->L, f->lineinfo, fs->pc, f->sizelineinfo, int,
MAX_INT, "opcodes");
f->lineinfo[fs->pc] = fs->ls->lastline;
return fs->pc++;
}
int luaK_codeABC (FuncState *fs, OpCode o, int a, int b, int c) {
lua_assert(getOpMode(o) == iABC);
lua_assert(getBMode(o) != OpArgN || b == 0);
lua_assert(getCMode(o) != OpArgN || c == 0);
lua_assert(a <= MAXARG_A && b <= MAXARG_B && c <= MAXARG_C);
return luaK_code(fs, CREATE_ABC(o, a, b, c));
}
int luaK_codeABx (FuncState *fs, OpCode o, int a, unsigned int bc) {
lua_assert(getOpMode(o) == iABx || getOpMode(o) == iAsBx);
lua_assert(getCMode(o) == OpArgN);
lua_assert(a <= MAXARG_A && bc <= MAXARG_Bx);
return luaK_code(fs, CREATE_ABx(o, a, bc));
}
static int codeextraarg (FuncState *fs, int a) {
lua_assert(a <= MAXARG_Ax);
return luaK_code(fs, CREATE_Ax(OP_EXTRAARG, a));
}
int luaK_codek (FuncState *fs, int reg, int k) {
if (k <= MAXARG_Bx)
return luaK_codeABx(fs, OP_LOADK, reg, k);
else {
int p = luaK_codeABx(fs, OP_LOADKX, reg, 0);
codeextraarg(fs, k);
return p;
}
}
void luaK_checkstack (FuncState *fs, int n) {
int newstack = fs->freereg + n;
if (newstack > fs->f->maxstacksize) {
if (newstack >= MAXSTACK)
luaX_syntaxerror(fs->ls, "function or expression too complex");
fs->f->maxstacksize = cast_byte(newstack);
}
}
void luaK_reserveregs (FuncState *fs, int n) {
luaK_checkstack(fs, n);
fs->freereg += n;
}
static void freereg (FuncState *fs, int reg) {
if (!ISK(reg) && reg >= fs->nactvar) {
fs->freereg--;
lua_assert(reg == fs->freereg);
}
}
static void freeexp (FuncState *fs, expdesc *e) {
if (e->k == VNONRELOC)
freereg(fs, e->u.info);
}
static int addk (FuncState *fs, TValue *key, TValue *v) {
lua_State *L = fs->ls->L;
TValue *idx = luaH_set(L, fs->h, key);
Proto *f = fs->f;
int k, oldsize;
if (ttisnumber(idx)) {
lua_Number n = nvalue(idx);
lua_number2int(k, n);
if (luaV_rawequalobj(&f->k[k], v))
return k;
/* else may be a collision (e.g., between 0.0 and "\0\0\0\0\0\0\0\0");
go through and create a new entry for this value */
}
/* constant not found; create a new entry */
oldsize = f->sizek;
k = fs->nk;
/* numerical value does not need GC barrier;
table has no metatable, so it does not need to invalidate cache */
setnvalue(idx, cast_num(k));
luaM_growvector(L, f->k, k, f->sizek, TValue, MAXARG_Ax, "constants");
while (oldsize < f->sizek) setnilvalue(&f->k[oldsize++]);
setobj(L, &f->k[k], v);
fs->nk++;
luaC_barrier(L, f, v);
return k;
}
int luaK_stringK (FuncState *fs, TString *s) {
TValue o;
setsvalue(fs->ls->L, &o, s);
return addk(fs, &o, &o);
}
int luaK_numberK (FuncState *fs, lua_Number r) {
int n;
lua_State *L = fs->ls->L;
TValue o;
setnvalue(&o, r);
if (r == 0 || luai_numisnan(NULL, r)) { /* handle -0 and NaN */
/* use raw representation as key to avoid numeric problems */
setsvalue(L, L->top, luaS_newlstr(L, (char *)&r, sizeof(r)));
incr_top(L);
n = addk(fs, L->top - 1, &o);
L->top--;
}
else
n = addk(fs, &o, &o); /* regular case */
return n;
}
static int boolK (FuncState *fs, int b) {
TValue o;
setbvalue(&o, b);
return addk(fs, &o, &o);
}
static int nilK (FuncState *fs) {
TValue k, v;
setnilvalue(&v);
/* cannot use nil as key; instead use table itself to represent nil */
sethvalue(fs->ls->L, &k, fs->h);
return addk(fs, &k, &v);
}
void luaK_setreturns (FuncState *fs, expdesc *e, int nresults) {
if (e->k == VCALL) { /* expression is an open function call? */
SETARG_C(getcode(fs, e), nresults+1);
}
else if (e->k == VVARARG) {
SETARG_B(getcode(fs, e), nresults+1);
SETARG_A(getcode(fs, e), fs->freereg);
luaK_reserveregs(fs, 1);
}
}
void luaK_setoneret (FuncState *fs, expdesc *e) {
if (e->k == VCALL) { /* expression is an open function call? */
e->k = VNONRELOC;
e->u.info = GETARG_A(getcode(fs, e));
}
else if (e->k == VVARARG) {
SETARG_B(getcode(fs, e), 2);
e->k = VRELOCABLE; /* can relocate its simple result */
}
}
void luaK_dischargevars (FuncState *fs, expdesc *e) {
switch (e->k) {
case VLOCAL: {
e->k = VNONRELOC;
break;
}
case VUPVAL: {
e->u.info = luaK_codeABC(fs, OP_GETUPVAL, 0, e->u.info, 0);
e->k = VRELOCABLE;
break;
}
case VINDEXED: {
OpCode op = OP_GETTABUP; /* assume 't' is in an upvalue */
freereg(fs, e->u.ind.idx);
if (e->u.ind.vt == VLOCAL) { /* 't' is in a register? */
freereg(fs, e->u.ind.t);
op = OP_GETTABLE;
}
e->u.info = luaK_codeABC(fs, op, 0, e->u.ind.t, e->u.ind.idx);
e->k = VRELOCABLE;
break;
}
case VVARARG:
case VCALL: {
luaK_setoneret(fs, e);
break;
}
default: break; /* there is one value available (somewhere) */
}
}
static int code_label (FuncState *fs, int A, int b, int jump) {
luaK_getlabel(fs); /* those instructions may be jump targets */
return luaK_codeABC(fs, OP_LOADBOOL, A, b, jump);
}
static void discharge2reg (FuncState *fs, expdesc *e, int reg) {
luaK_dischargevars(fs, e);
switch (e->k) {
case VNIL: {
luaK_nil(fs, reg, 1);
break;
}
case VFALSE: case VTRUE: {
luaK_codeABC(fs, OP_LOADBOOL, reg, e->k == VTRUE, 0);
break;
}
case VK: {
luaK_codek(fs, reg, e->u.info);
break;
}
case VKNUM: {
luaK_codek(fs, reg, luaK_numberK(fs, e->u.nval));
break;
}
case VRELOCABLE: {
Instruction *pc = &getcode(fs, e);
SETARG_A(*pc, reg);
break;
}
case VNONRELOC: {
if (reg != e->u.info)
luaK_codeABC(fs, OP_MOVE, reg, e->u.info, 0);
break;
}
default: {
lua_assert(e->k == VVOID || e->k == VJMP);
return; /* nothing to do... */
}
}
e->u.info = reg;
e->k = VNONRELOC;
}
static void discharge2anyreg (FuncState *fs, expdesc *e) {
if (e->k != VNONRELOC) {
luaK_reserveregs(fs, 1);
discharge2reg(fs, e, fs->freereg-1);
}
}
static void exp2reg (FuncState *fs, expdesc *e, int reg) {
discharge2reg(fs, e, reg);
if (e->k == VJMP)
luaK_concat(fs, &e->t, e->u.info); /* put this jump in `t' list */
if (hasjumps(e)) {
int final; /* position after whole expression */
int p_f = NO_JUMP; /* position of an eventual LOAD false */
int p_t = NO_JUMP; /* position of an eventual LOAD true */
if (need_value(fs, e->t) || need_value(fs, e->f)) {
int fj = (e->k == VJMP) ? NO_JUMP : luaK_jump(fs);
p_f = code_label(fs, reg, 0, 1);
p_t = code_label(fs, reg, 1, 0);
luaK_patchtohere(fs, fj);
}
final = luaK_getlabel(fs);
patchlistaux(fs, e->f, final, reg, p_f);
patchlistaux(fs, e->t, final, reg, p_t);
}
e->f = e->t = NO_JUMP;
e->u.info = reg;
e->k = VNONRELOC;
}
void luaK_exp2nextreg (FuncState *fs, expdesc *e) {
luaK_dischargevars(fs, e);
freeexp(fs, e);
luaK_reserveregs(fs, 1);
exp2reg(fs, e, fs->freereg - 1);
}
int luaK_exp2anyreg (FuncState *fs, expdesc *e) {
luaK_dischargevars(fs, e);
if (e->k == VNONRELOC) {
if (!hasjumps(e)) return e->u.info; /* exp is already in a register */
if (e->u.info >= fs->nactvar) { /* reg. is not a local? */
exp2reg(fs, e, e->u.info); /* put value on it */
return e->u.info;
}
}
luaK_exp2nextreg(fs, e); /* default */
return e->u.info;
}
void luaK_exp2anyregup (FuncState *fs, expdesc *e) {
if (e->k != VUPVAL || hasjumps(e))
luaK_exp2anyreg(fs, e);
}
void luaK_exp2val (FuncState *fs, expdesc *e) {
if (hasjumps(e))
luaK_exp2anyreg(fs, e);
else
luaK_dischargevars(fs, e);
}
int luaK_exp2RK (FuncState *fs, expdesc *e) {
luaK_exp2val(fs, e);
switch (e->k) {
case VTRUE:
case VFALSE:
case VNIL: {
if (fs->nk <= MAXINDEXRK) { /* constant fits in RK operand? */
e->u.info = (e->k == VNIL) ? nilK(fs) : boolK(fs, (e->k == VTRUE));
e->k = VK;
return RKASK(e->u.info);
}
else break;
}
case VKNUM: {
e->u.info = luaK_numberK(fs, e->u.nval);
e->k = VK;
/* go through */
}
case VK: {
if (e->u.info <= MAXINDEXRK) /* constant fits in argC? */
return RKASK(e->u.info);
else break;
}
default: break;
}
/* not a constant in the right range: put it in a register */
return luaK_exp2anyreg(fs, e);
}
void luaK_storevar (FuncState *fs, expdesc *var, expdesc *ex) {
switch (var->k) {
case VLOCAL: {
freeexp(fs, ex);
exp2reg(fs, ex, var->u.info);
return;
}
case VUPVAL: {
int e = luaK_exp2anyreg(fs, ex);
luaK_codeABC(fs, OP_SETUPVAL, e, var->u.info, 0);
break;
}
case VINDEXED: {
OpCode op = (var->u.ind.vt == VLOCAL) ? OP_SETTABLE : OP_SETTABUP;
int e = luaK_exp2RK(fs, ex);
luaK_codeABC(fs, op, var->u.ind.t, var->u.ind.idx, e);
break;
}
default: {
lua_assert(0); /* invalid var kind to store */
break;
}
}
freeexp(fs, ex);
}
void luaK_self (FuncState *fs, expdesc *e, expdesc *key) {
int ereg;
luaK_exp2anyreg(fs, e);
ereg = e->u.info; /* register where 'e' was placed */
freeexp(fs, e);
e->u.info = fs->freereg; /* base register for op_self */
e->k = VNONRELOC;
luaK_reserveregs(fs, 2); /* function and 'self' produced by op_self */
luaK_codeABC(fs, OP_SELF, e->u.info, ereg, luaK_exp2RK(fs, key));
freeexp(fs, key);
}
static void invertjump (FuncState *fs, expdesc *e) {
Instruction *pc = getjumpcontrol(fs, e->u.info);
lua_assert(testTMode(GET_OPCODE(*pc)) && GET_OPCODE(*pc) != OP_TESTSET &&
GET_OPCODE(*pc) != OP_TEST);
SETARG_A(*pc, !(GETARG_A(*pc)));
}
static int jumponcond (FuncState *fs, expdesc *e, int cond) {
if (e->k == VRELOCABLE) {
Instruction ie = getcode(fs, e);
if (GET_OPCODE(ie) == OP_NOT) {
fs->pc--; /* remove previous OP_NOT */
return condjump(fs, OP_TEST, GETARG_B(ie), 0, !cond);
}
/* else go through */
}
discharge2anyreg(fs, e);
freeexp(fs, e);
return condjump(fs, OP_TESTSET, NO_REG, e->u.info, cond);
}
void luaK_goiftrue (FuncState *fs, expdesc *e) {
int pc; /* pc of last jump */
luaK_dischargevars(fs, e);
switch (e->k) {
case VJMP: {
invertjump(fs, e);
pc = e->u.info;
break;
}
case VK: case VKNUM: case VTRUE: {
pc = NO_JUMP; /* always true; do nothing */
break;
}
default: {
pc = jumponcond(fs, e, 0);
break;
}
}
luaK_concat(fs, &e->f, pc); /* insert last jump in `f' list */
luaK_patchtohere(fs, e->t);
e->t = NO_JUMP;
}
void luaK_goiffalse (FuncState *fs, expdesc *e) {
int pc; /* pc of last jump */
luaK_dischargevars(fs, e);
switch (e->k) {
case VJMP: {
pc = e->u.info;
break;
}
case VNIL: case VFALSE: {
pc = NO_JUMP; /* always false; do nothing */
break;
}
default: {
pc = jumponcond(fs, e, 1);
break;
}
}
luaK_concat(fs, &e->t, pc); /* insert last jump in `t' list */
luaK_patchtohere(fs, e->f);
e->f = NO_JUMP;
}
static void codenot (FuncState *fs, expdesc *e) {
luaK_dischargevars(fs, e);
switch (e->k) {
case VNIL: case VFALSE: {
e->k = VTRUE;
break;
}
case VK: case VKNUM: case VTRUE: {
e->k = VFALSE;
break;
}
case VJMP: {
invertjump(fs, e);
break;
}
case VRELOCABLE:
case VNONRELOC: {
discharge2anyreg(fs, e);
freeexp(fs, e);
e->u.info = luaK_codeABC(fs, OP_NOT, 0, e->u.info, 0);
e->k = VRELOCABLE;
break;
}
default: {
lua_assert(0); /* cannot happen */
break;
}
}
/* interchange true and false lists */
{ int temp = e->f; e->f = e->t; e->t = temp; }
removevalues(fs, e->f);
removevalues(fs, e->t);
}
void luaK_indexed (FuncState *fs, expdesc *t, expdesc *k) {
lua_assert(!hasjumps(t));
t->u.ind.t = t->u.info;
t->u.ind.idx = luaK_exp2RK(fs, k);
t->u.ind.vt = (t->k == VUPVAL) ? VUPVAL
: check_exp(vkisinreg(t->k), VLOCAL);
t->k = VINDEXED;
}
static int constfolding (OpCode op, expdesc *e1, expdesc *e2) {
lua_Number r;
if (!isnumeral(e1) || !isnumeral(e2)) return 0;
if ((op == OP_DIV || op == OP_MOD) && e2->u.nval == 0)
return 0; /* do not attempt to divide by 0 */
r = luaO_arith(op - OP_ADD + LUA_OPADD, e1->u.nval, e2->u.nval);
e1->u.nval = r;
return 1;
}
static void codearith (FuncState *fs, OpCode op,
expdesc *e1, expdesc *e2, int line) {
if (constfolding(op, e1, e2))
return;
else {
int o2 = (op != OP_UNM && op != OP_LEN) ? luaK_exp2RK(fs, e2) : 0;
int o1 = luaK_exp2RK(fs, e1);
if (o1 > o2) {
freeexp(fs, e1);
freeexp(fs, e2);
}
else {
freeexp(fs, e2);
freeexp(fs, e1);
}
e1->u.info = luaK_codeABC(fs, op, 0, o1, o2);
e1->k = VRELOCABLE;
luaK_fixline(fs, line);
}
}
static void codecomp (FuncState *fs, OpCode op, int cond, expdesc *e1,
expdesc *e2) {
int o1 = luaK_exp2RK(fs, e1);
int o2 = luaK_exp2RK(fs, e2);
freeexp(fs, e2);
freeexp(fs, e1);
if (cond == 0 && op != OP_EQ) {
int temp; /* exchange args to replace by `<' or `<=' */
temp = o1; o1 = o2; o2 = temp; /* o1 <==> o2 */
cond = 1;
}
e1->u.info = condjump(fs, op, cond, o1, o2);
e1->k = VJMP;
}
void luaK_prefix (FuncState *fs, UnOpr op, expdesc *e, int line) {
expdesc e2;
e2.t = e2.f = NO_JUMP; e2.k = VKNUM; e2.u.nval = 0;
switch (op) {
case OPR_MINUS: {
if (isnumeral(e)) /* minus constant? */
e->u.nval = luai_numunm(NULL, e->u.nval); /* fold it */
else {
luaK_exp2anyreg(fs, e);
codearith(fs, OP_UNM, e, &e2, line);
}
break;
}
case OPR_NOT: codenot(fs, e); break;
case OPR_LEN: {
luaK_exp2anyreg(fs, e); /* cannot operate on constants */
codearith(fs, OP_LEN, e, &e2, line);
break;
}
default: lua_assert(0);
}
}
void luaK_infix (FuncState *fs, BinOpr op, expdesc *v) {
switch (op) {
case OPR_AND: {
luaK_goiftrue(fs, v);
break;
}
case OPR_OR: {
luaK_goiffalse(fs, v);
break;
}
case OPR_CONCAT: {
luaK_exp2nextreg(fs, v); /* operand must be on the `stack' */
break;
}
case OPR_ADD: case OPR_SUB: case OPR_MUL: case OPR_DIV:
case OPR_MOD: case OPR_POW: {
if (!isnumeral(v)) luaK_exp2RK(fs, v);
break;
}
default: {
luaK_exp2RK(fs, v);
break;
}
}
}
void luaK_posfix (FuncState *fs, BinOpr op,
expdesc *e1, expdesc *e2, int line) {
switch (op) {
case OPR_AND: {
lua_assert(e1->t == NO_JUMP); /* list must be closed */
luaK_dischargevars(fs, e2);
luaK_concat(fs, &e2->f, e1->f);
*e1 = *e2;
break;
}
case OPR_OR: {
lua_assert(e1->f == NO_JUMP); /* list must be closed */
luaK_dischargevars(fs, e2);
luaK_concat(fs, &e2->t, e1->t);
*e1 = *e2;
break;
}
case OPR_CONCAT: {
luaK_exp2val(fs, e2);
if (e2->k == VRELOCABLE && GET_OPCODE(getcode(fs, e2)) == OP_CONCAT) {
lua_assert(e1->u.info == GETARG_B(getcode(fs, e2))-1);
freeexp(fs, e1);
SETARG_B(getcode(fs, e2), e1->u.info);
e1->k = VRELOCABLE; e1->u.info = e2->u.info;
}
else {
luaK_exp2nextreg(fs, e2); /* operand must be on the 'stack' */
codearith(fs, OP_CONCAT, e1, e2, line);
}
break;
}
case OPR_ADD: case OPR_SUB: case OPR_MUL: case OPR_DIV:
case OPR_MOD: case OPR_POW: {
codearith(fs, cast(OpCode, op - OPR_ADD + OP_ADD), e1, e2, line);
break;
}
case OPR_EQ: case OPR_LT: case OPR_LE: {
codecomp(fs, cast(OpCode, op - OPR_EQ + OP_EQ), 1, e1, e2);
break;
}
case OPR_NE: case OPR_GT: case OPR_GE: {
codecomp(fs, cast(OpCode, op - OPR_NE + OP_EQ), 0, e1, e2);
break;
}
default: lua_assert(0);
}
}
void luaK_fixline (FuncState *fs, int line) {
fs->f->lineinfo[fs->pc - 1] = line;
}
void luaK_setlist (FuncState *fs, int base, int nelems, int tostore) {
int c = (nelems - 1)/LFIELDS_PER_FLUSH + 1;
int b = (tostore == LUA_MULTRET) ? 0 : tostore;
lua_assert(tostore != 0);
if (c <= MAXARG_C)
luaK_codeABC(fs, OP_SETLIST, base, b, c);
else if (c <= MAXARG_Ax) {
luaK_codeABC(fs, OP_SETLIST, base, b, 0);
codeextraarg(fs, c);
}
else
luaX_syntaxerror(fs->ls, "constructor too long");
fs->freereg = base + 1; /* free registers with list values */
}
-83
View File
@@ -1,83 +0,0 @@
/*
** $Id: lcode.h,v 1.58 2011/08/30 16:26:41 roberto Exp $
** Code generator for Lua
** See Copyright Notice in lua.h
*/
#ifndef lcode_h
#define lcode_h
#include "llex.h"
#include "lobject.h"
#include "lopcodes.h"
#include "lparser.h"
/*
** Marks the end of a patch list. It is an invalid value both as an absolute
** address, and as a list link (would link an element to itself).
*/
#define NO_JUMP (-1)
/*
** grep "ORDER OPR" if you change these enums (ORDER OP)
*/
typedef enum BinOpr {
OPR_ADD, OPR_SUB, OPR_MUL, OPR_DIV, OPR_MOD, OPR_POW,
OPR_CONCAT,
OPR_EQ, OPR_LT, OPR_LE,
OPR_NE, OPR_GT, OPR_GE,
OPR_AND, OPR_OR,
OPR_NOBINOPR
} BinOpr;
typedef enum UnOpr { OPR_MINUS, OPR_NOT, OPR_LEN, OPR_NOUNOPR } UnOpr;
#define getcode(fs,e) ((fs)->f->code[(e)->u.info])
#define luaK_codeAsBx(fs,o,A,sBx) luaK_codeABx(fs,o,A,(sBx)+MAXARG_sBx)
#define luaK_setmultret(fs,e) luaK_setreturns(fs, e, LUA_MULTRET)
#define luaK_jumpto(fs,t) luaK_patchlist(fs, luaK_jump(fs), t)
LUAI_FUNC int luaK_codeABx (FuncState *fs, OpCode o, int A, unsigned int Bx);
LUAI_FUNC int luaK_codeABC (FuncState *fs, OpCode o, int A, int B, int C);
LUAI_FUNC int luaK_codek (FuncState *fs, int reg, int k);
LUAI_FUNC void luaK_fixline (FuncState *fs, int line);
LUAI_FUNC void luaK_nil (FuncState *fs, int from, int n);
LUAI_FUNC void luaK_reserveregs (FuncState *fs, int n);
LUAI_FUNC void luaK_checkstack (FuncState *fs, int n);
LUAI_FUNC int luaK_stringK (FuncState *fs, TString *s);
LUAI_FUNC int luaK_numberK (FuncState *fs, lua_Number r);
LUAI_FUNC void luaK_dischargevars (FuncState *fs, expdesc *e);
LUAI_FUNC int luaK_exp2anyreg (FuncState *fs, expdesc *e);
LUAI_FUNC void luaK_exp2anyregup (FuncState *fs, expdesc *e);
LUAI_FUNC void luaK_exp2nextreg (FuncState *fs, expdesc *e);
LUAI_FUNC void luaK_exp2val (FuncState *fs, expdesc *e);
LUAI_FUNC int luaK_exp2RK (FuncState *fs, expdesc *e);
LUAI_FUNC void luaK_self (FuncState *fs, expdesc *e, expdesc *key);
LUAI_FUNC void luaK_indexed (FuncState *fs, expdesc *t, expdesc *k);
LUAI_FUNC void luaK_goiftrue (FuncState *fs, expdesc *e);
LUAI_FUNC void luaK_goiffalse (FuncState *fs, expdesc *e);
LUAI_FUNC void luaK_storevar (FuncState *fs, expdesc *var, expdesc *e);
LUAI_FUNC void luaK_setreturns (FuncState *fs, expdesc *e, int nresults);
LUAI_FUNC void luaK_setoneret (FuncState *fs, expdesc *e);
LUAI_FUNC int luaK_jump (FuncState *fs);
LUAI_FUNC void luaK_ret (FuncState *fs, int first, int nret);
LUAI_FUNC void luaK_patchlist (FuncState *fs, int list, int target);
LUAI_FUNC void luaK_patchtohere (FuncState *fs, int list);
LUAI_FUNC void luaK_patchclose (FuncState *fs, int list, int level);
LUAI_FUNC void luaK_concat (FuncState *fs, int *l1, int l2);
LUAI_FUNC int luaK_getlabel (FuncState *fs);
LUAI_FUNC void luaK_prefix (FuncState *fs, UnOpr op, expdesc *v, int line);
LUAI_FUNC void luaK_infix (FuncState *fs, BinOpr op, expdesc *v);
LUAI_FUNC void luaK_posfix (FuncState *fs, BinOpr op, expdesc *v1,
expdesc *v2, int line);
LUAI_FUNC void luaK_setlist (FuncState *fs, int base, int nelems, int tostore);
#endif
-155
View File
@@ -1,155 +0,0 @@
/*
** $Id: lcorolib.c,v 1.4 2012/04/27 18:59:04 roberto Exp $
** Coroutine Library
** See Copyright Notice in lua.h
*/
#include <stdlib.h>
#define lcorolib_c
#define LUA_LIB
#include "lua.h"
#include "lauxlib.h"
#include "lualib.h"
static int auxresume (lua_State *L, lua_State *co, int narg) {
int status;
if (!lua_checkstack(co, narg)) {
lua_pushliteral(L, "too many arguments to resume");
return -1; /* error flag */
}
if (lua_status(co) == LUA_OK && lua_gettop(co) == 0) {
lua_pushliteral(L, "cannot resume dead coroutine");
return -1; /* error flag */
}
lua_xmove(L, co, narg);
status = lua_resume(co, L, narg);
if (status == LUA_OK || status == LUA_YIELD) {
int nres = lua_gettop(co);
if (!lua_checkstack(L, nres + 1)) {
lua_pop(co, nres); /* remove results anyway */
lua_pushliteral(L, "too many results to resume");
return -1; /* error flag */
}
lua_xmove(co, L, nres); /* move yielded values */
return nres;
}
else {
lua_xmove(co, L, 1); /* move error message */
return -1; /* error flag */
}
}
static int luaB_coresume (lua_State *L) {
lua_State *co = lua_tothread(L, 1);
int r;
luaL_argcheck(L, co, 1, "coroutine expected");
r = auxresume(L, co, lua_gettop(L) - 1);
if (r < 0) {
lua_pushboolean(L, 0);
lua_insert(L, -2);
return 2; /* return false + error message */
}
else {
lua_pushboolean(L, 1);
lua_insert(L, -(r + 1));
return r + 1; /* return true + `resume' returns */
}
}
static int luaB_auxwrap (lua_State *L) {
lua_State *co = lua_tothread(L, lua_upvalueindex(1));
int r = auxresume(L, co, lua_gettop(L));
if (r < 0) {
if (lua_isstring(L, -1)) { /* error object is a string? */
luaL_where(L, 1); /* add extra info */
lua_insert(L, -2);
lua_concat(L, 2);
}
lua_error(L); /* propagate error */
}
return r;
}
static int luaB_cocreate (lua_State *L) {
lua_State *NL;
luaL_checktype(L, 1, LUA_TFUNCTION);
NL = lua_newthread(L);
lua_pushvalue(L, 1); /* move function to top */
lua_xmove(L, NL, 1); /* move function from L to NL */
return 1;
}
static int luaB_cowrap (lua_State *L) {
luaB_cocreate(L);
lua_pushcclosure(L, luaB_auxwrap, 1);
return 1;
}
static int luaB_yield (lua_State *L) {
return lua_yield(L, lua_gettop(L));
}
static int luaB_costatus (lua_State *L) {
lua_State *co = lua_tothread(L, 1);
luaL_argcheck(L, co, 1, "coroutine expected");
if (L == co) lua_pushliteral(L, "running");
else {
switch (lua_status(co)) {
case LUA_YIELD:
lua_pushliteral(L, "suspended");
break;
case LUA_OK: {
lua_Debug ar;
if (lua_getstack(co, 0, &ar) > 0) /* does it have frames? */
lua_pushliteral(L, "normal"); /* it is running */
else if (lua_gettop(co) == 0)
lua_pushliteral(L, "dead");
else
lua_pushliteral(L, "suspended"); /* initial state */
break;
}
default: /* some error occurred */
lua_pushliteral(L, "dead");
break;
}
}
return 1;
}
static int luaB_corunning (lua_State *L) {
int ismain = lua_pushthread(L);
lua_pushboolean(L, ismain);
return 2;
}
static const luaL_Reg co_funcs[] = {
{"create", luaB_cocreate},
{"resume", luaB_coresume},
{"running", luaB_corunning},
{"status", luaB_costatus},
{"wrap", luaB_cowrap},
{"yield", luaB_yield},
{NULL, NULL}
};
LUAMOD_API int luaopen_coroutine (lua_State *L) {
luaL_newlib(L, co_funcs);
return 1;
}
-52
View File
@@ -1,52 +0,0 @@
/*
** $Id: lctype.c,v 1.11 2011/10/03 16:19:23 roberto Exp $
** 'ctype' functions for Lua
** See Copyright Notice in lua.h
*/
#define lctype_c
#define LUA_CORE
#include "lctype.h"
#if !LUA_USE_CTYPE /* { */
#include <limits.h>
LUAI_DDEF const lu_byte luai_ctype_[UCHAR_MAX + 2] = {
0x00, /* EOZ */
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0. */
0x00, 0x08, 0x08, 0x08, 0x08, 0x08, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 1. */
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x0c, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, /* 2. */
0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,
0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, /* 3. */
0x16, 0x16, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,
0x04, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x05, /* 4. */
0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05,
0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, /* 5. */
0x05, 0x05, 0x05, 0x04, 0x04, 0x04, 0x04, 0x05,
0x04, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x05, /* 6. */
0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05,
0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, /* 7. */
0x05, 0x05, 0x05, 0x04, 0x04, 0x04, 0x04, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 8. */
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 9. */
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* a. */
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* b. */
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* c. */
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* d. */
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* e. */
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* f. */
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
};
#endif /* } */
-95
View File
@@ -1,95 +0,0 @@
/*
** $Id: lctype.h,v 1.12 2011/07/15 12:50:29 roberto Exp $
** 'ctype' functions for Lua
** See Copyright Notice in lua.h
*/
#ifndef lctype_h
#define lctype_h
#include "lua.h"
/*
** WARNING: the functions defined here do not necessarily correspond
** to the similar functions in the standard C ctype.h. They are
** optimized for the specific needs of Lua
*/
#if !defined(LUA_USE_CTYPE)
#if 'A' == 65 && '0' == 48
/* ASCII case: can use its own tables; faster and fixed */
#define LUA_USE_CTYPE 0
#else
/* must use standard C ctype */
#define LUA_USE_CTYPE 1
#endif
#endif
#if !LUA_USE_CTYPE /* { */
#include <limits.h>
#include "llimits.h"
#define ALPHABIT 0
#define DIGITBIT 1
#define PRINTBIT 2
#define SPACEBIT 3
#define XDIGITBIT 4
#define MASK(B) (1 << (B))
/*
** add 1 to char to allow index -1 (EOZ)
*/
#define testprop(c,p) (luai_ctype_[(c)+1] & (p))
/*
** 'lalpha' (Lua alphabetic) and 'lalnum' (Lua alphanumeric) both include '_'
*/
#define lislalpha(c) testprop(c, MASK(ALPHABIT))
#define lislalnum(c) testprop(c, (MASK(ALPHABIT) | MASK(DIGITBIT)))
#define lisdigit(c) testprop(c, MASK(DIGITBIT))
#define lisspace(c) testprop(c, MASK(SPACEBIT))
#define lisprint(c) testprop(c, MASK(PRINTBIT))
#define lisxdigit(c) testprop(c, MASK(XDIGITBIT))
/*
** this 'ltolower' only works for alphabetic characters
*/
#define ltolower(c) ((c) | ('A' ^ 'a'))
/* two more entries for 0 and -1 (EOZ) */
LUAI_DDEC const lu_byte luai_ctype_[UCHAR_MAX + 2];
#else /* }{ */
/*
** use standard C ctypes
*/
#include <ctype.h>
#define lislalpha(c) (isalpha(c) || (c) == '_')
#define lislalnum(c) (isalnum(c) || (c) == '_')
#define lisdigit(c) (isdigit(c))
#define lisspace(c) (isspace(c))
#define lisprint(c) (isprint(c))
#define lisxdigit(c) (isxdigit(c))
#define ltolower(c) (tolower(c))
#endif /* } */
#endif
-398
View File
@@ -1,398 +0,0 @@
/*
** $Id: ldblib.c,v 1.132 2012/01/19 20:14:44 roberto Exp $
** Interface from Lua to its debug API
** See Copyright Notice in lua.h
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define ldblib_c
#define LUA_LIB
#include "lua.h"
#include "lauxlib.h"
#include "lualib.h"
#define HOOKKEY "_HKEY"
static int db_getregistry (lua_State *L) {
lua_pushvalue(L, LUA_REGISTRYINDEX);
return 1;
}
static int db_getmetatable (lua_State *L) {
luaL_checkany(L, 1);
if (!lua_getmetatable(L, 1)) {
lua_pushnil(L); /* no metatable */
}
return 1;
}
static int db_setmetatable (lua_State *L) {
int t = lua_type(L, 2);
luaL_argcheck(L, t == LUA_TNIL || t == LUA_TTABLE, 2,
"nil or table expected");
lua_settop(L, 2);
lua_setmetatable(L, 1);
return 1; /* return 1st argument */
}
static int db_getuservalue (lua_State *L) {
if (lua_type(L, 1) != LUA_TUSERDATA)
lua_pushnil(L);
else
lua_getuservalue(L, 1);
return 1;
}
static int db_setuservalue (lua_State *L) {
if (lua_type(L, 1) == LUA_TLIGHTUSERDATA)
luaL_argerror(L, 1, "full userdata expected, got light userdata");
luaL_checktype(L, 1, LUA_TUSERDATA);
if (!lua_isnoneornil(L, 2))
luaL_checktype(L, 2, LUA_TTABLE);
lua_settop(L, 2);
lua_setuservalue(L, 1);
return 1;
}
static void settabss (lua_State *L, const char *i, const char *v) {
lua_pushstring(L, v);
lua_setfield(L, -2, i);
}
static void settabsi (lua_State *L, const char *i, int v) {
lua_pushinteger(L, v);
lua_setfield(L, -2, i);
}
static void settabsb (lua_State *L, const char *i, int v) {
lua_pushboolean(L, v);
lua_setfield(L, -2, i);
}
static lua_State *getthread (lua_State *L, int *arg) {
if (lua_isthread(L, 1)) {
*arg = 1;
return lua_tothread(L, 1);
}
else {
*arg = 0;
return L;
}
}
static void treatstackoption (lua_State *L, lua_State *L1, const char *fname) {
if (L == L1) {
lua_pushvalue(L, -2);
lua_remove(L, -3);
}
else
lua_xmove(L1, L, 1);
lua_setfield(L, -2, fname);
}
static int db_getinfo (lua_State *L) {
lua_Debug ar;
int arg;
lua_State *L1 = getthread(L, &arg);
const char *options = luaL_optstring(L, arg+2, "flnStu");
if (lua_isnumber(L, arg+1)) {
if (!lua_getstack(L1, (int)lua_tointeger(L, arg+1), &ar)) {
lua_pushnil(L); /* level out of range */
return 1;
}
}
else if (lua_isfunction(L, arg+1)) {
lua_pushfstring(L, ">%s", options);
options = lua_tostring(L, -1);
lua_pushvalue(L, arg+1);
lua_xmove(L, L1, 1);
}
else
return luaL_argerror(L, arg+1, "function or level expected");
if (!lua_getinfo(L1, options, &ar))
return luaL_argerror(L, arg+2, "invalid option");
lua_createtable(L, 0, 2);
if (strchr(options, 'S')) {
settabss(L, "source", ar.source);
settabss(L, "short_src", ar.short_src);
settabsi(L, "linedefined", ar.linedefined);
settabsi(L, "lastlinedefined", ar.lastlinedefined);
settabss(L, "what", ar.what);
}
if (strchr(options, 'l'))
settabsi(L, "currentline", ar.currentline);
if (strchr(options, 'u')) {
settabsi(L, "nups", ar.nups);
settabsi(L, "nparams", ar.nparams);
settabsb(L, "isvararg", ar.isvararg);
}
if (strchr(options, 'n')) {
settabss(L, "name", ar.name);
settabss(L, "namewhat", ar.namewhat);
}
if (strchr(options, 't'))
settabsb(L, "istailcall", ar.istailcall);
if (strchr(options, 'L'))
treatstackoption(L, L1, "activelines");
if (strchr(options, 'f'))
treatstackoption(L, L1, "func");
return 1; /* return table */
}
static int db_getlocal (lua_State *L) {
int arg;
lua_State *L1 = getthread(L, &arg);
lua_Debug ar;
const char *name;
int nvar = luaL_checkint(L, arg+2); /* local-variable index */
if (lua_isfunction(L, arg + 1)) { /* function argument? */
lua_pushvalue(L, arg + 1); /* push function */
lua_pushstring(L, lua_getlocal(L, NULL, nvar)); /* push local name */
return 1;
}
else { /* stack-level argument */
if (!lua_getstack(L1, luaL_checkint(L, arg+1), &ar)) /* out of range? */
return luaL_argerror(L, arg+1, "level out of range");
name = lua_getlocal(L1, &ar, nvar);
if (name) {
lua_xmove(L1, L, 1); /* push local value */
lua_pushstring(L, name); /* push name */
lua_pushvalue(L, -2); /* re-order */
return 2;
}
else {
lua_pushnil(L); /* no name (nor value) */
return 1;
}
}
}
static int db_setlocal (lua_State *L) {
int arg;
lua_State *L1 = getthread(L, &arg);
lua_Debug ar;
if (!lua_getstack(L1, luaL_checkint(L, arg+1), &ar)) /* out of range? */
return luaL_argerror(L, arg+1, "level out of range");
luaL_checkany(L, arg+3);
lua_settop(L, arg+3);
lua_xmove(L, L1, 1);
lua_pushstring(L, lua_setlocal(L1, &ar, luaL_checkint(L, arg+2)));
return 1;
}
static int auxupvalue (lua_State *L, int get) {
const char *name;
int n = luaL_checkint(L, 2);
luaL_checktype(L, 1, LUA_TFUNCTION);
name = get ? lua_getupvalue(L, 1, n) : lua_setupvalue(L, 1, n);
if (name == NULL) return 0;
lua_pushstring(L, name);
lua_insert(L, -(get+1));
return get + 1;
}
static int db_getupvalue (lua_State *L) {
return auxupvalue(L, 1);
}
static int db_setupvalue (lua_State *L) {
luaL_checkany(L, 3);
return auxupvalue(L, 0);
}
static int checkupval (lua_State *L, int argf, int argnup) {
lua_Debug ar;
int nup = luaL_checkint(L, argnup);
luaL_checktype(L, argf, LUA_TFUNCTION);
lua_pushvalue(L, argf);
lua_getinfo(L, ">u", &ar);
luaL_argcheck(L, 1 <= nup && nup <= ar.nups, argnup, "invalid upvalue index");
return nup;
}
static int db_upvalueid (lua_State *L) {
int n = checkupval(L, 1, 2);
lua_pushlightuserdata(L, lua_upvalueid(L, 1, n));
return 1;
}
static int db_upvaluejoin (lua_State *L) {
int n1 = checkupval(L, 1, 2);
int n2 = checkupval(L, 3, 4);
luaL_argcheck(L, !lua_iscfunction(L, 1), 1, "Lua function expected");
luaL_argcheck(L, !lua_iscfunction(L, 3), 3, "Lua function expected");
lua_upvaluejoin(L, 1, n1, 3, n2);
return 0;
}
#define gethooktable(L) luaL_getsubtable(L, LUA_REGISTRYINDEX, HOOKKEY)
static void hookf (lua_State *L, lua_Debug *ar) {
static const char *const hooknames[] =
{"call", "return", "line", "count", "tail call"};
gethooktable(L);
lua_pushthread(L);
lua_rawget(L, -2);
if (lua_isfunction(L, -1)) {
lua_pushstring(L, hooknames[(int)ar->event]);
if (ar->currentline >= 0)
lua_pushinteger(L, ar->currentline);
else lua_pushnil(L);
lua_assert(lua_getinfo(L, "lS", ar));
lua_call(L, 2, 0);
}
}
static int makemask (const char *smask, int count) {
int mask = 0;
if (strchr(smask, 'c')) mask |= LUA_MASKCALL;
if (strchr(smask, 'r')) mask |= LUA_MASKRET;
if (strchr(smask, 'l')) mask |= LUA_MASKLINE;
if (count > 0) mask |= LUA_MASKCOUNT;
return mask;
}
static char *unmakemask (int mask, char *smask) {
int i = 0;
if (mask & LUA_MASKCALL) smask[i++] = 'c';
if (mask & LUA_MASKRET) smask[i++] = 'r';
if (mask & LUA_MASKLINE) smask[i++] = 'l';
smask[i] = '\0';
return smask;
}
static int db_sethook (lua_State *L) {
int arg, mask, count;
lua_Hook func;
lua_State *L1 = getthread(L, &arg);
if (lua_isnoneornil(L, arg+1)) {
lua_settop(L, arg+1);
func = NULL; mask = 0; count = 0; /* turn off hooks */
}
else {
const char *smask = luaL_checkstring(L, arg+2);
luaL_checktype(L, arg+1, LUA_TFUNCTION);
count = luaL_optint(L, arg+3, 0);
func = hookf; mask = makemask(smask, count);
}
if (gethooktable(L) == 0) { /* creating hook table? */
lua_pushstring(L, "k");
lua_setfield(L, -2, "__mode"); /** hooktable.__mode = "k" */
lua_pushvalue(L, -1);
lua_setmetatable(L, -2); /* setmetatable(hooktable) = hooktable */
}
lua_pushthread(L1); lua_xmove(L1, L, 1);
lua_pushvalue(L, arg+1);
lua_rawset(L, -3); /* set new hook */
lua_sethook(L1, func, mask, count); /* set hooks */
return 0;
}
static int db_gethook (lua_State *L) {
int arg;
lua_State *L1 = getthread(L, &arg);
char buff[5];
int mask = lua_gethookmask(L1);
lua_Hook hook = lua_gethook(L1);
if (hook != NULL && hook != hookf) /* external hook? */
lua_pushliteral(L, "external hook");
else {
gethooktable(L);
lua_pushthread(L1); lua_xmove(L1, L, 1);
lua_rawget(L, -2); /* get hook */
lua_remove(L, -2); /* remove hook table */
}
lua_pushstring(L, unmakemask(mask, buff));
lua_pushinteger(L, lua_gethookcount(L1));
return 3;
}
static int db_debug (lua_State *L) {
for (;;) {
char buffer[250];
luai_writestringerror("%s", "lua_debug> ");
if (fgets(buffer, sizeof(buffer), stdin) == 0 ||
strcmp(buffer, "cont\n") == 0)
return 0;
if (luaL_loadbuffer(L, buffer, strlen(buffer), "=(debug command)") ||
lua_pcall(L, 0, 0, 0))
luai_writestringerror("%s\n", lua_tostring(L, -1));
lua_settop(L, 0); /* remove eventual returns */
}
}
static int db_traceback (lua_State *L) {
int arg;
lua_State *L1 = getthread(L, &arg);
const char *msg = lua_tostring(L, arg + 1);
if (msg == NULL && !lua_isnoneornil(L, arg + 1)) /* non-string 'msg'? */
lua_pushvalue(L, arg + 1); /* return it untouched */
else {
int level = luaL_optint(L, arg + 2, (L == L1) ? 1 : 0);
luaL_traceback(L, L1, msg, level);
}
return 1;
}
static const luaL_Reg dblib[] = {
{"debug", db_debug},
{"getuservalue", db_getuservalue},
{"gethook", db_gethook},
{"getinfo", db_getinfo},
{"getlocal", db_getlocal},
{"getregistry", db_getregistry},
{"getmetatable", db_getmetatable},
{"getupvalue", db_getupvalue},
{"upvaluejoin", db_upvaluejoin},
{"upvalueid", db_upvalueid},
{"setuservalue", db_setuservalue},
{"sethook", db_sethook},
{"setlocal", db_setlocal},
{"setmetatable", db_setmetatable},
{"setupvalue", db_setupvalue},
{"traceback", db_traceback},
{NULL, NULL}
};
LUAMOD_API int luaopen_debug (lua_State *L) {
luaL_newlib(L, dblib);
return 1;
}
-580
View File
@@ -1,580 +0,0 @@
/*
** $Id: ldebug.c,v 2.89 2012/01/20 22:05:50 roberto Exp $
** Debug Interface
** See Copyright Notice in lua.h
*/
#include <stdarg.h>
#include <stddef.h>
#include <string.h>
#define ldebug_c
#define LUA_CORE
#include "lua.h"
#include "lapi.h"
#include "lcode.h"
#include "ldebug.h"
#include "ldo.h"
#include "lfunc.h"
#include "lobject.h"
#include "lopcodes.h"
#include "lstate.h"
#include "lstring.h"
#include "ltable.h"
#include "ltm.h"
#include "lvm.h"
#define noLuaClosure(f) ((f) == NULL || (f)->c.tt == LUA_TCCL)
static const char *getfuncname (lua_State *L, CallInfo *ci, const char **name);
static int currentpc (CallInfo *ci) {
lua_assert(isLua(ci));
return pcRel(ci->u.l.savedpc, ci_func(ci)->p);
}
static int currentline (CallInfo *ci) {
return getfuncline(ci_func(ci)->p, currentpc(ci));
}
/*
** this function can be called asynchronous (e.g. during a signal)
*/
LUA_API int lua_sethook (lua_State *L, lua_Hook func, int mask, int count) {
if (func == NULL || mask == 0) { /* turn off hooks? */
mask = 0;
func = NULL;
}
if (isLua(L->ci))
L->oldpc = L->ci->u.l.savedpc;
L->hook = func;
L->basehookcount = count;
resethookcount(L);
L->hookmask = cast_byte(mask);
return 1;
}
LUA_API lua_Hook lua_gethook (lua_State *L) {
return L->hook;
}
LUA_API int lua_gethookmask (lua_State *L) {
return L->hookmask;
}
LUA_API int lua_gethookcount (lua_State *L) {
return L->basehookcount;
}
LUA_API int lua_getstack (lua_State *L, int level, lua_Debug *ar) {
int status;
CallInfo *ci;
if (level < 0) return 0; /* invalid (negative) level */
lua_lock(L);
for (ci = L->ci; level > 0 && ci != &L->base_ci; ci = ci->previous)
level--;
if (level == 0 && ci != &L->base_ci) { /* level found? */
status = 1;
ar->i_ci = ci;
}
else status = 0; /* no such level */
lua_unlock(L);
return status;
}
static const char *upvalname (Proto *p, int uv) {
TString *s = check_exp(uv < p->sizeupvalues, p->upvalues[uv].name);
if (s == NULL) return "?";
else return getstr(s);
}
static const char *findvararg (CallInfo *ci, int n, StkId *pos) {
int nparams = clLvalue(ci->func)->p->numparams;
if (n >= ci->u.l.base - ci->func - nparams)
return NULL; /* no such vararg */
else {
*pos = ci->func + nparams + n;
return "(*vararg)"; /* generic name for any vararg */
}
}
static const char *findlocal (lua_State *L, CallInfo *ci, int n,
StkId *pos) {
const char *name = NULL;
StkId base;
if (isLua(ci)) {
if (n < 0) /* access to vararg values? */
return findvararg(ci, -n, pos);
else {
base = ci->u.l.base;
name = luaF_getlocalname(ci_func(ci)->p, n, currentpc(ci));
}
}
else
base = ci->func + 1;
if (name == NULL) { /* no 'standard' name? */
StkId limit = (ci == L->ci) ? L->top : ci->next->func;
if (limit - base >= n && n > 0) /* is 'n' inside 'ci' stack? */
name = "(*temporary)"; /* generic name for any valid slot */
else
return NULL; /* no name */
}
*pos = base + (n - 1);
return name;
}
LUA_API const char *lua_getlocal (lua_State *L, const lua_Debug *ar, int n) {
const char *name;
lua_lock(L);
if (ar == NULL) { /* information about non-active function? */
if (!isLfunction(L->top - 1)) /* not a Lua function? */
name = NULL;
else /* consider live variables at function start (parameters) */
name = luaF_getlocalname(clLvalue(L->top - 1)->p, n, 0);
}
else { /* active function; get information through 'ar' */
StkId pos = 0; /* to avoid warnings */
name = findlocal(L, ar->i_ci, n, &pos);
if (name) {
setobj2s(L, L->top, pos);
api_incr_top(L);
}
}
lua_unlock(L);
return name;
}
LUA_API const char *lua_setlocal (lua_State *L, const lua_Debug *ar, int n) {
StkId pos = 0; /* to avoid warnings */
const char *name = findlocal(L, ar->i_ci, n, &pos);
lua_lock(L);
if (name)
setobjs2s(L, pos, L->top - 1);
L->top--; /* pop value */
lua_unlock(L);
return name;
}
static void funcinfo (lua_Debug *ar, Closure *cl) {
if (noLuaClosure(cl)) {
ar->source = "=[C]";
ar->linedefined = -1;
ar->lastlinedefined = -1;
ar->what = "C";
}
else {
Proto *p = cl->l.p;
ar->source = p->source ? getstr(p->source) : "=?";
ar->linedefined = p->linedefined;
ar->lastlinedefined = p->lastlinedefined;
ar->what = (ar->linedefined == 0) ? "main" : "Lua";
}
luaO_chunkid(ar->short_src, ar->source, LUA_IDSIZE);
}
static void collectvalidlines (lua_State *L, Closure *f) {
if (noLuaClosure(f)) {
setnilvalue(L->top);
incr_top(L);
}
else {
int i;
TValue v;
int *lineinfo = f->l.p->lineinfo;
Table *t = luaH_new(L); /* new table to store active lines */
sethvalue(L, L->top, t); /* push it on stack */
incr_top(L);
setbvalue(&v, 1); /* boolean 'true' to be the value of all indices */
for (i = 0; i < f->l.p->sizelineinfo; i++) /* for all lines with code */
luaH_setint(L, t, lineinfo[i], &v); /* table[line] = true */
}
}
static int auxgetinfo (lua_State *L, const char *what, lua_Debug *ar,
Closure *f, CallInfo *ci) {
int status = 1;
for (; *what; what++) {
switch (*what) {
case 'S': {
funcinfo(ar, f);
break;
}
case 'l': {
ar->currentline = (ci && isLua(ci)) ? currentline(ci) : -1;
break;
}
case 'u': {
ar->nups = (f == NULL) ? 0 : f->c.nupvalues;
if (noLuaClosure(f)) {
ar->isvararg = 1;
ar->nparams = 0;
}
else {
ar->isvararg = f->l.p->is_vararg;
ar->nparams = f->l.p->numparams;
}
break;
}
case 't': {
ar->istailcall = (ci) ? ci->callstatus & CIST_TAIL : 0;
break;
}
case 'n': {
/* calling function is a known Lua function? */
if (ci && !(ci->callstatus & CIST_TAIL) && isLua(ci->previous))
ar->namewhat = getfuncname(L, ci->previous, &ar->name);
else
ar->namewhat = NULL;
if (ar->namewhat == NULL) {
ar->namewhat = ""; /* not found */
ar->name = NULL;
}
break;
}
case 'L':
case 'f': /* handled by lua_getinfo */
break;
default: status = 0; /* invalid option */
}
}
return status;
}
LUA_API int lua_getinfo (lua_State *L, const char *what, lua_Debug *ar) {
int status;
Closure *cl;
CallInfo *ci;
StkId func;
lua_lock(L);
if (*what == '>') {
ci = NULL;
func = L->top - 1;
api_check(L, ttisfunction(func), "function expected");
what++; /* skip the '>' */
L->top--; /* pop function */
}
else {
ci = ar->i_ci;
func = ci->func;
lua_assert(ttisfunction(ci->func));
}
cl = ttisclosure(func) ? clvalue(func) : NULL;
status = auxgetinfo(L, what, ar, cl, ci);
if (strchr(what, 'f')) {
setobjs2s(L, L->top, func);
incr_top(L);
}
if (strchr(what, 'L'))
collectvalidlines(L, cl);
lua_unlock(L);
return status;
}
/*
** {======================================================
** Symbolic Execution
** =======================================================
*/
static const char *getobjname (Proto *p, int lastpc, int reg,
const char **name);
/*
** find a "name" for the RK value 'c'
*/
static void kname (Proto *p, int pc, int c, const char **name) {
if (ISK(c)) { /* is 'c' a constant? */
TValue *kvalue = &p->k[INDEXK(c)];
if (ttisstring(kvalue)) { /* literal constant? */
*name = svalue(kvalue); /* it is its own name */
return;
}
/* else no reasonable name found */
}
else { /* 'c' is a register */
const char *what = getobjname(p, pc, c, name); /* search for 'c' */
if (what && *what == 'c') { /* found a constant name? */
return; /* 'name' already filled */
}
/* else no reasonable name found */
}
*name = "?"; /* no reasonable name found */
}
/*
** try to find last instruction before 'lastpc' that modified register 'reg'
*/
static int findsetreg (Proto *p, int lastpc, int reg) {
int pc;
int setreg = -1; /* keep last instruction that changed 'reg' */
for (pc = 0; pc < lastpc; pc++) {
Instruction i = p->code[pc];
OpCode op = GET_OPCODE(i);
int a = GETARG_A(i);
switch (op) {
case OP_LOADNIL: {
int b = GETARG_B(i);
if (a <= reg && reg <= a + b) /* set registers from 'a' to 'a+b' */
setreg = pc;
break;
}
case OP_TFORCALL: {
if (reg >= a + 2) setreg = pc; /* affect all regs above its base */
break;
}
case OP_CALL:
case OP_TAILCALL: {
if (reg >= a) setreg = pc; /* affect all registers above base */
break;
}
case OP_JMP: {
int b = GETARG_sBx(i);
int dest = pc + 1 + b;
/* jump is forward and do not skip `lastpc'? */
if (pc < dest && dest <= lastpc)
pc += b; /* do the jump */
break;
}
case OP_TEST: {
if (reg == a) setreg = pc; /* jumped code can change 'a' */
break;
}
default:
if (testAMode(op) && reg == a) /* any instruction that set A */
setreg = pc;
break;
}
}
return setreg;
}
static const char *getobjname (Proto *p, int lastpc, int reg,
const char **name) {
int pc;
*name = luaF_getlocalname(p, reg + 1, lastpc);
if (*name) /* is a local? */
return "local";
/* else try symbolic execution */
pc = findsetreg(p, lastpc, reg);
if (pc != -1) { /* could find instruction? */
Instruction i = p->code[pc];
OpCode op = GET_OPCODE(i);
switch (op) {
case OP_MOVE: {
int b = GETARG_B(i); /* move from 'b' to 'a' */
if (b < GETARG_A(i))
return getobjname(p, pc, b, name); /* get name for 'b' */
break;
}
case OP_GETTABUP:
case OP_GETTABLE: {
int k = GETARG_C(i); /* key index */
int t = GETARG_B(i); /* table index */
const char *vn = (op == OP_GETTABLE) /* name of indexed variable */
? luaF_getlocalname(p, t + 1, pc)
: upvalname(p, t);
kname(p, pc, k, name);
return (vn && strcmp(vn, LUA_ENV) == 0) ? "global" : "field";
}
case OP_GETUPVAL: {
*name = upvalname(p, GETARG_B(i));
return "upvalue";
}
case OP_LOADK:
case OP_LOADKX: {
int b = (op == OP_LOADK) ? GETARG_Bx(i)
: GETARG_Ax(p->code[pc + 1]);
if (ttisstring(&p->k[b])) {
*name = svalue(&p->k[b]);
return "constant";
}
break;
}
case OP_SELF: {
int k = GETARG_C(i); /* key index */
kname(p, pc, k, name);
return "method";
}
default: break; /* go through to return NULL */
}
}
return NULL; /* could not find reasonable name */
}
static const char *getfuncname (lua_State *L, CallInfo *ci, const char **name) {
TMS tm;
Proto *p = ci_func(ci)->p; /* calling function */
int pc = currentpc(ci); /* calling instruction index */
Instruction i = p->code[pc]; /* calling instruction */
switch (GET_OPCODE(i)) {
case OP_CALL:
case OP_TAILCALL: /* get function name */
return getobjname(p, pc, GETARG_A(i), name);
case OP_TFORCALL: { /* for iterator */
*name = "for iterator";
return "for iterator";
}
/* all other instructions can call only through metamethods */
case OP_SELF:
case OP_GETTABUP:
case OP_GETTABLE: tm = TM_INDEX; break;
case OP_SETTABUP:
case OP_SETTABLE: tm = TM_NEWINDEX; break;
case OP_EQ: tm = TM_EQ; break;
case OP_ADD: tm = TM_ADD; break;
case OP_SUB: tm = TM_SUB; break;
case OP_MUL: tm = TM_MUL; break;
case OP_DIV: tm = TM_DIV; break;
case OP_MOD: tm = TM_MOD; break;
case OP_POW: tm = TM_POW; break;
case OP_UNM: tm = TM_UNM; break;
case OP_LEN: tm = TM_LEN; break;
case OP_LT: tm = TM_LT; break;
case OP_LE: tm = TM_LE; break;
case OP_CONCAT: tm = TM_CONCAT; break;
default:
return NULL; /* else no useful name can be found */
}
*name = getstr(G(L)->tmname[tm]);
return "metamethod";
}
/* }====================================================== */
/*
** only ANSI way to check whether a pointer points to an array
** (used only for error messages, so efficiency is not a big concern)
*/
static int isinstack (CallInfo *ci, const TValue *o) {
StkId p;
for (p = ci->u.l.base; p < ci->top; p++)
if (o == p) return 1;
return 0;
}
static const char *getupvalname (CallInfo *ci, const TValue *o,
const char **name) {
LClosure *c = ci_func(ci);
int i;
for (i = 0; i < c->nupvalues; i++) {
if (c->upvals[i]->v == o) {
*name = upvalname(c->p, i);
return "upvalue";
}
}
return NULL;
}
l_noret luaG_typeerror (lua_State *L, const TValue *o, const char *op) {
CallInfo *ci = L->ci;
const char *name = NULL;
const char *t = objtypename(o);
const char *kind = NULL;
if (isLua(ci)) {
kind = getupvalname(ci, o, &name); /* check whether 'o' is an upvalue */
if (!kind && isinstack(ci, o)) /* no? try a register */
kind = getobjname(ci_func(ci)->p, currentpc(ci),
cast_int(o - ci->u.l.base), &name);
}
if (kind)
luaG_runerror(L, "attempt to %s %s " LUA_QS " (a %s value)",
op, kind, name, t);
else
luaG_runerror(L, "attempt to %s a %s value", op, t);
}
l_noret luaG_concaterror (lua_State *L, StkId p1, StkId p2) {
if (ttisstring(p1) || ttisnumber(p1)) p1 = p2;
lua_assert(!ttisstring(p1) && !ttisnumber(p2));
luaG_typeerror(L, p1, "concatenate");
}
l_noret luaG_aritherror (lua_State *L, const TValue *p1, const TValue *p2) {
TValue temp;
if (luaV_tonumber(p1, &temp) == NULL)
p2 = p1; /* first operand is wrong */
luaG_typeerror(L, p2, "perform arithmetic on");
}
l_noret luaG_ordererror (lua_State *L, const TValue *p1, const TValue *p2) {
const char *t1 = objtypename(p1);
const char *t2 = objtypename(p2);
if (t1 == t2)
luaG_runerror(L, "attempt to compare two %s values", t1);
else
luaG_runerror(L, "attempt to compare %s with %s", t1, t2);
}
static void addinfo (lua_State *L, const char *msg) {
CallInfo *ci = L->ci;
if (isLua(ci)) { /* is Lua code? */
char buff[LUA_IDSIZE]; /* add file:line information */
int line = currentline(ci);
TString *src = ci_func(ci)->p->source;
if (src)
luaO_chunkid(buff, getstr(src), LUA_IDSIZE);
else { /* no source available; use "?" instead */
buff[0] = '?'; buff[1] = '\0';
}
luaO_pushfstring(L, "%s:%d: %s", buff, line, msg);
}
}
l_noret luaG_errormsg (lua_State *L) {
if (L->errfunc != 0) { /* is there an error handling function? */
StkId errfunc = restorestack(L, L->errfunc);
if (!ttisfunction(errfunc)) luaD_throw(L, LUA_ERRERR);
setobjs2s(L, L->top, L->top - 1); /* move argument */
setobjs2s(L, L->top - 1, errfunc); /* push function */
incr_top(L);
luaD_call(L, L->top - 2, 1, 0); /* call it */
}
luaD_throw(L, LUA_ERRRUN);
}
l_noret luaG_runerror (lua_State *L, const char *fmt, ...) {
va_list argp;
va_start(argp, fmt);
addinfo(L, luaO_pushvfstring(L, fmt, argp));
va_end(argp);
luaG_errormsg(L);
}
-34
View File
@@ -1,34 +0,0 @@
/*
** $Id: ldebug.h,v 2.7 2011/10/07 20:45:19 roberto Exp $
** Auxiliary functions from Debug Interface module
** See Copyright Notice in lua.h
*/
#ifndef ldebug_h
#define ldebug_h
#include "lstate.h"
#define pcRel(pc, p) (cast(int, (pc) - (p)->code) - 1)
#define getfuncline(f,pc) (((f)->lineinfo) ? (f)->lineinfo[pc] : 0)
#define resethookcount(L) (L->hookcount = L->basehookcount)
/* Active Lua function (given call info) */
#define ci_func(ci) (clLvalue((ci)->func))
LUAI_FUNC l_noret luaG_typeerror (lua_State *L, const TValue *o,
const char *opname);
LUAI_FUNC l_noret luaG_concaterror (lua_State *L, StkId p1, StkId p2);
LUAI_FUNC l_noret luaG_aritherror (lua_State *L, const TValue *p1,
const TValue *p2);
LUAI_FUNC l_noret luaG_ordererror (lua_State *L, const TValue *p1,
const TValue *p2);
LUAI_FUNC l_noret luaG_runerror (lua_State *L, const char *fmt, ...);
LUAI_FUNC l_noret luaG_errormsg (lua_State *L);
#endif
-668
View File
@@ -1,668 +0,0 @@
/*
** $Id: ldo.c,v 2.105 2012/06/08 15:14:04 roberto Exp $
** Stack and Call structure of Lua
** See Copyright Notice in lua.h
*/
#include <setjmp.h>
#include <stdlib.h>
#include <string.h>
#define ldo_c
#define LUA_CORE
#include "lua.h"
#include "lapi.h"
#include "ldebug.h"
#include "ldo.h"
#include "lfunc.h"
#include "lgc.h"
#include "lmem.h"
#include "lobject.h"
#include "lopcodes.h"
#include "lparser.h"
#include "lstate.h"
#include "lstring.h"
#include "ltable.h"
#include "ltm.h"
#include "lundump.h"
#include "lvm.h"
#include "lzio.h"
/*
** {======================================================
** Error-recovery functions
** =======================================================
*/
/*
** LUAI_THROW/LUAI_TRY define how Lua does exception handling. By
** default, Lua handles errors with exceptions when compiling as
** C++ code, with _longjmp/_setjmp when asked to use them, and with
** longjmp/setjmp otherwise.
*/
#if !defined(LUAI_THROW)
#if defined(__cplusplus) && !defined(LUA_USE_LONGJMP)
/* C++ exceptions */
#define LUAI_THROW(L,c) throw(c)
#define LUAI_TRY(L,c,a) \
try { a } catch(...) { if ((c)->status == 0) (c)->status = -1; }
#define luai_jmpbuf int /* dummy variable */
#elif defined(LUA_USE_ULONGJMP)
/* in Unix, try _longjmp/_setjmp (more efficient) */
#define LUAI_THROW(L,c) _longjmp((c)->b, 1)
#define LUAI_TRY(L,c,a) if (_setjmp((c)->b) == 0) { a }
#define luai_jmpbuf jmp_buf
#else
/* default handling with long jumps */
#define LUAI_THROW(L,c) longjmp((c)->b, 1)
#define LUAI_TRY(L,c,a) if (setjmp((c)->b) == 0) { a }
#define luai_jmpbuf jmp_buf
#endif
#endif
/* chain list of long jump buffers */
struct lua_longjmp {
struct lua_longjmp *previous;
luai_jmpbuf b;
volatile int status; /* error code */
};
static void seterrorobj (lua_State *L, int errcode, StkId oldtop) {
switch (errcode) {
case LUA_ERRMEM: { /* memory error? */
setsvalue2s(L, oldtop, G(L)->memerrmsg); /* reuse preregistered msg. */
break;
}
case LUA_ERRERR: {
setsvalue2s(L, oldtop, luaS_newliteral(L, "error in error handling"));
break;
}
default: {
setobjs2s(L, oldtop, L->top - 1); /* error message on current top */
break;
}
}
L->top = oldtop + 1;
}
l_noret luaD_throw (lua_State *L, int errcode) {
if (L->errorJmp) { /* thread has an error handler? */
L->errorJmp->status = errcode; /* set status */
LUAI_THROW(L, L->errorJmp); /* jump to it */
}
else { /* thread has no error handler */
L->status = cast_byte(errcode); /* mark it as dead */
if (G(L)->mainthread->errorJmp) { /* main thread has a handler? */
setobjs2s(L, G(L)->mainthread->top++, L->top - 1); /* copy error obj. */
luaD_throw(G(L)->mainthread, errcode); /* re-throw in main thread */
}
else { /* no handler at all; abort */
if (G(L)->panic) { /* panic function? */
lua_unlock(L);
G(L)->panic(L); /* call it (last chance to jump out) */
}
abort();
}
}
}
int luaD_rawrunprotected (lua_State *L, Pfunc f, void *ud) {
unsigned short oldnCcalls = L->nCcalls;
struct lua_longjmp lj;
lj.status = LUA_OK;
lj.previous = L->errorJmp; /* chain new error handler */
L->errorJmp = &lj;
LUAI_TRY(L, &lj,
(*f)(L, ud);
);
L->errorJmp = lj.previous; /* restore old error handler */
L->nCcalls = oldnCcalls;
return lj.status;
}
/* }====================================================== */
static void correctstack (lua_State *L, TValue *oldstack) {
CallInfo *ci;
GCObject *up;
L->top = (L->top - oldstack) + L->stack;
for (up = L->openupval; up != NULL; up = up->gch.next)
gco2uv(up)->v = (gco2uv(up)->v - oldstack) + L->stack;
for (ci = L->ci; ci != NULL; ci = ci->previous) {
ci->top = (ci->top - oldstack) + L->stack;
ci->func = (ci->func - oldstack) + L->stack;
if (isLua(ci))
ci->u.l.base = (ci->u.l.base - oldstack) + L->stack;
}
}
/* some space for error handling */
#define ERRORSTACKSIZE (LUAI_MAXSTACK + 200)
void luaD_reallocstack (lua_State *L, int newsize) {
TValue *oldstack = L->stack;
int lim = L->stacksize;
lua_assert(newsize <= LUAI_MAXSTACK || newsize == ERRORSTACKSIZE);
lua_assert(L->stack_last - L->stack == L->stacksize - EXTRA_STACK);
luaM_reallocvector(L, L->stack, L->stacksize, newsize, TValue);
for (; lim < newsize; lim++)
setnilvalue(L->stack + lim); /* erase new segment */
L->stacksize = newsize;
L->stack_last = L->stack + newsize - EXTRA_STACK;
correctstack(L, oldstack);
}
void luaD_growstack (lua_State *L, int n) {
int size = L->stacksize;
if (size > LUAI_MAXSTACK) /* error after extra size? */
luaD_throw(L, LUA_ERRERR);
else {
int needed = cast_int(L->top - L->stack) + n + EXTRA_STACK;
int newsize = 2 * size;
if (newsize > LUAI_MAXSTACK) newsize = LUAI_MAXSTACK;
if (newsize < needed) newsize = needed;
if (newsize > LUAI_MAXSTACK) { /* stack overflow? */
luaD_reallocstack(L, ERRORSTACKSIZE);
luaG_runerror(L, "stack overflow");
}
else
luaD_reallocstack(L, newsize);
}
}
static int stackinuse (lua_State *L) {
CallInfo *ci;
StkId lim = L->top;
for (ci = L->ci; ci != NULL; ci = ci->previous) {
lua_assert(ci->top <= L->stack_last);
if (lim < ci->top) lim = ci->top;
}
return cast_int(lim - L->stack) + 1; /* part of stack in use */
}
void luaD_shrinkstack (lua_State *L) {
int inuse = stackinuse(L);
int goodsize = inuse + (inuse / 8) + 2*EXTRA_STACK;
if (goodsize > LUAI_MAXSTACK) goodsize = LUAI_MAXSTACK;
if (inuse > LUAI_MAXSTACK || /* handling stack overflow? */
goodsize >= L->stacksize) /* would grow instead of shrink? */
condmovestack(L); /* don't change stack (change only for debugging) */
else
luaD_reallocstack(L, goodsize); /* shrink it */
}
void luaD_hook (lua_State *L, int event, int line) {
lua_Hook hook = L->hook;
if (hook && L->allowhook) {
CallInfo *ci = L->ci;
ptrdiff_t top = savestack(L, L->top);
ptrdiff_t ci_top = savestack(L, ci->top);
lua_Debug ar;
ar.event = event;
ar.currentline = line;
ar.i_ci = ci;
luaD_checkstack(L, LUA_MINSTACK); /* ensure minimum stack size */
ci->top = L->top + LUA_MINSTACK;
lua_assert(ci->top <= L->stack_last);
L->allowhook = 0; /* cannot call hooks inside a hook */
ci->callstatus |= CIST_HOOKED;
lua_unlock(L);
(*hook)(L, &ar);
lua_lock(L);
lua_assert(!L->allowhook);
L->allowhook = 1;
ci->top = restorestack(L, ci_top);
L->top = restorestack(L, top);
ci->callstatus &= ~CIST_HOOKED;
}
}
static void callhook (lua_State *L, CallInfo *ci) {
int hook = LUA_HOOKCALL;
ci->u.l.savedpc++; /* hooks assume 'pc' is already incremented */
if (isLua(ci->previous) &&
GET_OPCODE(*(ci->previous->u.l.savedpc - 1)) == OP_TAILCALL) {
ci->callstatus |= CIST_TAIL;
hook = LUA_HOOKTAILCALL;
}
luaD_hook(L, hook, -1);
ci->u.l.savedpc--; /* correct 'pc' */
}
static StkId adjust_varargs (lua_State *L, Proto *p, int actual) {
int i;
int nfixargs = p->numparams;
StkId base, fixed;
lua_assert(actual >= nfixargs);
/* move fixed parameters to final position */
fixed = L->top - actual; /* first fixed argument */
base = L->top; /* final position of first argument */
for (i=0; i<nfixargs; i++) {
setobjs2s(L, L->top++, fixed + i);
setnilvalue(fixed + i);
}
return base;
}
static StkId tryfuncTM (lua_State *L, StkId func) {
const TValue *tm = luaT_gettmbyobj(L, func, TM_CALL);
StkId p;
ptrdiff_t funcr = savestack(L, func);
if (!ttisfunction(tm))
luaG_typeerror(L, func, "call");
/* Open a hole inside the stack at `func' */
for (p = L->top; p > func; p--) setobjs2s(L, p, p-1);
incr_top(L);
func = restorestack(L, funcr); /* previous call may change stack */
setobj2s(L, func, tm); /* tag method is the new function to be called */
return func;
}
#define next_ci(L) (L->ci = (L->ci->next ? L->ci->next : luaE_extendCI(L)))
/*
** returns true if function has been executed (C function)
*/
int luaD_precall (lua_State *L, StkId func, int nresults) {
lua_CFunction f;
CallInfo *ci;
int n; /* number of arguments (Lua) or returns (C) */
ptrdiff_t funcr = savestack(L, func);
switch (ttype(func)) {
case LUA_TLCF: /* light C function */
f = fvalue(func);
goto Cfunc;
case LUA_TCCL: { /* C closure */
f = clCvalue(func)->f;
Cfunc:
luaD_checkstack(L, LUA_MINSTACK); /* ensure minimum stack size */
ci = next_ci(L); /* now 'enter' new function */
ci->nresults = nresults;
ci->func = restorestack(L, funcr);
ci->top = L->top + LUA_MINSTACK;
lua_assert(ci->top <= L->stack_last);
ci->callstatus = 0;
if (L->hookmask & LUA_MASKCALL)
luaD_hook(L, LUA_HOOKCALL, -1);
lua_unlock(L);
n = (*f)(L); /* do the actual call */
lua_lock(L);
api_checknelems(L, n);
luaD_poscall(L, L->top - n);
return 1;
}
case LUA_TLCL: { /* Lua function: prepare its call */
StkId base;
Proto *p = clLvalue(func)->p;
luaD_checkstack(L, p->maxstacksize);
func = restorestack(L, funcr);
n = cast_int(L->top - func) - 1; /* number of real arguments */
for (; n < p->numparams; n++)
setnilvalue(L->top++); /* complete missing arguments */
base = (!p->is_vararg) ? func + 1 : adjust_varargs(L, p, n);
ci = next_ci(L); /* now 'enter' new function */
ci->nresults = nresults;
ci->func = func;
ci->u.l.base = base;
ci->top = base + p->maxstacksize;
lua_assert(ci->top <= L->stack_last);
ci->u.l.savedpc = p->code; /* starting point */
ci->callstatus = CIST_LUA;
L->top = ci->top;
if (L->hookmask & LUA_MASKCALL)
callhook(L, ci);
return 0;
}
default: { /* not a function */
func = tryfuncTM(L, func); /* retry with 'function' tag method */
return luaD_precall(L, func, nresults); /* now it must be a function */
}
}
}
int luaD_poscall (lua_State *L, StkId firstResult) {
StkId res;
int wanted, i;
CallInfo *ci = L->ci;
if (L->hookmask & (LUA_MASKRET | LUA_MASKLINE)) {
if (L->hookmask & LUA_MASKRET) {
ptrdiff_t fr = savestack(L, firstResult); /* hook may change stack */
luaD_hook(L, LUA_HOOKRET, -1);
firstResult = restorestack(L, fr);
}
L->oldpc = ci->previous->u.l.savedpc; /* 'oldpc' for caller function */
}
res = ci->func; /* res == final position of 1st result */
wanted = ci->nresults;
L->ci = ci = ci->previous; /* back to caller */
/* move results to correct place */
for (i = wanted; i != 0 && firstResult < L->top; i--)
setobjs2s(L, res++, firstResult++);
while (i-- > 0)
setnilvalue(res++);
L->top = res;
return (wanted - LUA_MULTRET); /* 0 iff wanted == LUA_MULTRET */
}
/*
** Call a function (C or Lua). The function to be called is at *func.
** The arguments are on the stack, right after the function.
** When returns, all the results are on the stack, starting at the original
** function position.
*/
void luaD_call (lua_State *L, StkId func, int nResults, int allowyield) {
if (++L->nCcalls >= LUAI_MAXCCALLS) {
if (L->nCcalls == LUAI_MAXCCALLS)
luaG_runerror(L, "C stack overflow");
else if (L->nCcalls >= (LUAI_MAXCCALLS + (LUAI_MAXCCALLS>>3)))
luaD_throw(L, LUA_ERRERR); /* error while handing stack error */
}
if (!allowyield) L->nny++;
if (!luaD_precall(L, func, nResults)) /* is a Lua function? */
luaV_execute(L); /* call it */
if (!allowyield) L->nny--;
L->nCcalls--;
luaC_checkGC(L);
}
static void finishCcall (lua_State *L) {
CallInfo *ci = L->ci;
int n;
lua_assert(ci->u.c.k != NULL); /* must have a continuation */
lua_assert(L->nny == 0);
/* finish 'lua_callk' */
adjustresults(L, ci->nresults);
/* call continuation function */
if (!(ci->callstatus & CIST_STAT)) /* no call status? */
ci->u.c.status = LUA_YIELD; /* 'default' status */
lua_assert(ci->u.c.status != LUA_OK);
ci->callstatus = (ci->callstatus & ~(CIST_YPCALL | CIST_STAT)) | CIST_YIELDED;
lua_unlock(L);
n = (*ci->u.c.k)(L);
lua_lock(L);
api_checknelems(L, n);
/* finish 'luaD_precall' */
luaD_poscall(L, L->top - n);
}
static void unroll (lua_State *L, void *ud) {
UNUSED(ud);
for (;;) {
if (L->ci == &L->base_ci) /* stack is empty? */
return; /* coroutine finished normally */
if (!isLua(L->ci)) /* C function? */
finishCcall(L);
else { /* Lua function */
luaV_finishOp(L); /* finish interrupted instruction */
luaV_execute(L); /* execute down to higher C 'boundary' */
}
}
}
/*
** check whether thread has a suspended protected call
*/
static CallInfo *findpcall (lua_State *L) {
CallInfo *ci;
for (ci = L->ci; ci != NULL; ci = ci->previous) { /* search for a pcall */
if (ci->callstatus & CIST_YPCALL)
return ci;
}
return NULL; /* no pending pcall */
}
static int recover (lua_State *L, int status) {
StkId oldtop;
CallInfo *ci = findpcall(L);
if (ci == NULL) return 0; /* no recovery point */
/* "finish" luaD_pcall */
oldtop = restorestack(L, ci->extra);
luaF_close(L, oldtop);
seterrorobj(L, status, oldtop);
L->ci = ci;
L->allowhook = ci->u.c.old_allowhook;
L->nny = 0; /* should be zero to be yieldable */
luaD_shrinkstack(L);
L->errfunc = ci->u.c.old_errfunc;
ci->callstatus |= CIST_STAT; /* call has error status */
ci->u.c.status = status; /* (here it is) */
return 1; /* continue running the coroutine */
}
/*
** signal an error in the call to 'resume', not in the execution of the
** coroutine itself. (Such errors should not be handled by any coroutine
** error handler and should not kill the coroutine.)
*/
static l_noret resume_error (lua_State *L, const char *msg, StkId firstArg) {
L->top = firstArg; /* remove args from the stack */
setsvalue2s(L, L->top, luaS_new(L, msg)); /* push error message */
incr_top(L);
luaD_throw(L, -1); /* jump back to 'lua_resume' */
}
/*
** do the work for 'lua_resume' in protected mode
*/
static void resume (lua_State *L, void *ud) {
int nCcalls = L->nCcalls;
StkId firstArg = cast(StkId, ud);
CallInfo *ci = L->ci;
if (nCcalls >= LUAI_MAXCCALLS)
resume_error(L, "C stack overflow", firstArg);
if (L->status == LUA_OK) { /* may be starting a coroutine */
if (ci != &L->base_ci) /* not in base level? */
resume_error(L, "cannot resume non-suspended coroutine", firstArg);
/* coroutine is in base level; start running it */
if (!luaD_precall(L, firstArg - 1, LUA_MULTRET)) /* Lua function? */
luaV_execute(L); /* call it */
}
else if (L->status != LUA_YIELD)
resume_error(L, "cannot resume dead coroutine", firstArg);
else { /* resuming from previous yield */
L->status = LUA_OK;
ci->func = restorestack(L, ci->extra);
if (isLua(ci)) /* yielded inside a hook? */
luaV_execute(L); /* just continue running Lua code */
else { /* 'common' yield */
if (ci->u.c.k != NULL) { /* does it have a continuation? */
int n;
ci->u.c.status = LUA_YIELD; /* 'default' status */
ci->callstatus |= CIST_YIELDED;
lua_unlock(L);
n = (*ci->u.c.k)(L); /* call continuation */
lua_lock(L);
api_checknelems(L, n);
firstArg = L->top - n; /* yield results come from continuation */
}
luaD_poscall(L, firstArg); /* finish 'luaD_precall' */
}
unroll(L, NULL);
}
lua_assert(nCcalls == L->nCcalls);
}
LUA_API int lua_resume (lua_State *L, lua_State *from, int nargs) {
int status;
lua_lock(L);
luai_userstateresume(L, nargs);
L->nCcalls = (from) ? from->nCcalls + 1 : 1;
L->nny = 0; /* allow yields */
api_checknelems(L, (L->status == LUA_OK) ? nargs + 1 : nargs);
status = luaD_rawrunprotected(L, resume, L->top - nargs);
if (status == -1) /* error calling 'lua_resume'? */
status = LUA_ERRRUN;
else { /* yield or regular error */
while (status != LUA_OK && status != LUA_YIELD) { /* error? */
if (recover(L, status)) /* recover point? */
status = luaD_rawrunprotected(L, unroll, NULL); /* run continuation */
else { /* unrecoverable error */
L->status = cast_byte(status); /* mark thread as `dead' */
seterrorobj(L, status, L->top);
L->ci->top = L->top;
break;
}
}
lua_assert(status == L->status);
}
L->nny = 1; /* do not allow yields */
L->nCcalls--;
lua_assert(L->nCcalls == ((from) ? from->nCcalls : 0));
lua_unlock(L);
return status;
}
LUA_API int lua_yieldk (lua_State *L, int nresults, int ctx, lua_CFunction k) {
CallInfo *ci = L->ci;
luai_userstateyield(L, nresults);
lua_lock(L);
api_checknelems(L, nresults);
if (L->nny > 0) {
if (L != G(L)->mainthread)
luaG_runerror(L, "attempt to yield across metamethod/C-call boundary");
else
luaG_runerror(L, "attempt to yield from outside a coroutine");
}
L->status = LUA_YIELD;
ci->extra = savestack(L, ci->func); /* save current 'func' */
if (isLua(ci)) { /* inside a hook? */
api_check(L, k == NULL, "hooks cannot continue after yielding");
}
else {
if ((ci->u.c.k = k) != NULL) /* is there a continuation? */
ci->u.c.ctx = ctx; /* save context */
ci->func = L->top - nresults - 1; /* protect stack below results */
luaD_throw(L, LUA_YIELD);
}
lua_assert(ci->callstatus & CIST_HOOKED); /* must be inside a hook */
lua_unlock(L);
return 0; /* return to 'luaD_hook' */
}
int luaD_pcall (lua_State *L, Pfunc func, void *u,
ptrdiff_t old_top, ptrdiff_t ef) {
int status;
CallInfo *old_ci = L->ci;
lu_byte old_allowhooks = L->allowhook;
unsigned short old_nny = L->nny;
ptrdiff_t old_errfunc = L->errfunc;
L->errfunc = ef;
status = luaD_rawrunprotected(L, func, u);
if (status != LUA_OK) { /* an error occurred? */
StkId oldtop = restorestack(L, old_top);
luaF_close(L, oldtop); /* close possible pending closures */
seterrorobj(L, status, oldtop);
L->ci = old_ci;
L->allowhook = old_allowhooks;
L->nny = old_nny;
luaD_shrinkstack(L);
}
L->errfunc = old_errfunc;
return status;
}
/*
** Execute a protected parser.
*/
struct SParser { /* data to `f_parser' */
ZIO *z;
Mbuffer buff; /* dynamic structure used by the scanner */
Dyndata dyd; /* dynamic structures used by the parser */
const char *mode;
const char *name;
};
static void checkmode (lua_State *L, const char *mode, const char *x) {
if (mode && strchr(mode, x[0]) == NULL) {
luaO_pushfstring(L,
"attempt to load a %s chunk (mode is " LUA_QS ")", x, mode);
luaD_throw(L, LUA_ERRSYNTAX);
}
}
static void f_parser (lua_State *L, void *ud) {
int i;
Closure *cl;
struct SParser *p = cast(struct SParser *, ud);
int c = zgetc(p->z); /* read first character */
if (c == LUA_SIGNATURE[0]) {
checkmode(L, p->mode, "binary");
cl = luaU_undump(L, p->z, &p->buff, p->name);
}
else {
checkmode(L, p->mode, "text");
cl = luaY_parser(L, p->z, &p->buff, &p->dyd, p->name, c);
}
lua_assert(cl->l.nupvalues == cl->l.p->sizeupvalues);
for (i = 0; i < cl->l.nupvalues; i++) { /* initialize upvalues */
UpVal *up = luaF_newupval(L);
cl->l.upvals[i] = up;
luaC_objbarrier(L, cl, up);
}
}
int luaD_protectedparser (lua_State *L, ZIO *z, const char *name,
const char *mode) {
struct SParser p;
int status;
L->nny++; /* cannot yield during parsing */
p.z = z; p.name = name; p.mode = mode;
p.dyd.actvar.arr = NULL; p.dyd.actvar.size = 0;
p.dyd.gt.arr = NULL; p.dyd.gt.size = 0;
p.dyd.label.arr = NULL; p.dyd.label.size = 0;
luaZ_initbuffer(L, &p.buff);
status = luaD_pcall(L, f_parser, &p, savestack(L, L->top), L->errfunc);
luaZ_freebuffer(L, &p.buff);
luaM_freearray(L, p.dyd.actvar.arr, p.dyd.actvar.size);
luaM_freearray(L, p.dyd.gt.arr, p.dyd.gt.size);
luaM_freearray(L, p.dyd.label.arr, p.dyd.label.size);
L->nny--;
return status;
}
-46
View File
@@ -1,46 +0,0 @@
/*
** $Id: ldo.h,v 2.20 2011/11/29 15:55:08 roberto Exp $
** Stack and Call structure of Lua
** See Copyright Notice in lua.h
*/
#ifndef ldo_h
#define ldo_h
#include "lobject.h"
#include "lstate.h"
#include "lzio.h"
#define luaD_checkstack(L,n) if (L->stack_last - L->top <= (n)) \
luaD_growstack(L, n); else condmovestack(L);
#define incr_top(L) {L->top++; luaD_checkstack(L,0);}
#define savestack(L,p) ((char *)(p) - (char *)L->stack)
#define restorestack(L,n) ((TValue *)((char *)L->stack + (n)))
/* type of protected functions, to be ran by `runprotected' */
typedef void (*Pfunc) (lua_State *L, void *ud);
LUAI_FUNC int luaD_protectedparser (lua_State *L, ZIO *z, const char *name,
const char *mode);
LUAI_FUNC void luaD_hook (lua_State *L, int event, int line);
LUAI_FUNC int luaD_precall (lua_State *L, StkId func, int nresults);
LUAI_FUNC void luaD_call (lua_State *L, StkId func, int nResults,
int allowyield);
LUAI_FUNC int luaD_pcall (lua_State *L, Pfunc func, void *u,
ptrdiff_t oldtop, ptrdiff_t ef);
LUAI_FUNC int luaD_poscall (lua_State *L, StkId firstResult);
LUAI_FUNC void luaD_reallocstack (lua_State *L, int newsize);
LUAI_FUNC void luaD_growstack (lua_State *L, int n);
LUAI_FUNC void luaD_shrinkstack (lua_State *L);
LUAI_FUNC l_noret luaD_throw (lua_State *L, int errcode);
LUAI_FUNC int luaD_rawrunprotected (lua_State *L, Pfunc f, void *ud);
#endif
-173
View File
@@ -1,173 +0,0 @@
/*
** $Id: ldump.c,v 2.17 2012/01/23 23:02:10 roberto Exp $
** save precompiled Lua chunks
** See Copyright Notice in lua.h
*/
#include <stddef.h>
#define ldump_c
#define LUA_CORE
#include "lua.h"
#include "lobject.h"
#include "lstate.h"
#include "lundump.h"
typedef struct {
lua_State* L;
lua_Writer writer;
void* data;
int strip;
int status;
} DumpState;
#define DumpMem(b,n,size,D) DumpBlock(b,(n)*(size),D)
#define DumpVar(x,D) DumpMem(&x,1,sizeof(x),D)
static void DumpBlock(const void* b, size_t size, DumpState* D)
{
if (D->status==0)
{
lua_unlock(D->L);
D->status=(*D->writer)(D->L,b,size,D->data);
lua_lock(D->L);
}
}
static void DumpChar(int y, DumpState* D)
{
char x=(char)y;
DumpVar(x,D);
}
static void DumpInt(int x, DumpState* D)
{
DumpVar(x,D);
}
static void DumpNumber(lua_Number x, DumpState* D)
{
DumpVar(x,D);
}
static void DumpVector(const void* b, int n, size_t size, DumpState* D)
{
DumpInt(n,D);
DumpMem(b,n,size,D);
}
static void DumpString(const TString* s, DumpState* D)
{
if (s==NULL)
{
size_t size=0;
DumpVar(size,D);
}
else
{
size_t size=s->tsv.len+1; /* include trailing '\0' */
DumpVar(size,D);
DumpBlock(getstr(s),size*sizeof(char),D);
}
}
#define DumpCode(f,D) DumpVector(f->code,f->sizecode,sizeof(Instruction),D)
static void DumpFunction(const Proto* f, DumpState* D);
static void DumpConstants(const Proto* f, DumpState* D)
{
int i,n=f->sizek;
DumpInt(n,D);
for (i=0; i<n; i++)
{
const TValue* o=&f->k[i];
DumpChar(ttypenv(o),D);
switch (ttypenv(o))
{
case LUA_TNIL:
break;
case LUA_TBOOLEAN:
DumpChar(bvalue(o),D);
break;
case LUA_TNUMBER:
DumpNumber(nvalue(o),D);
break;
case LUA_TSTRING:
DumpString(rawtsvalue(o),D);
break;
default: lua_assert(0);
}
}
n=f->sizep;
DumpInt(n,D);
for (i=0; i<n; i++) DumpFunction(f->p[i],D);
}
static void DumpUpvalues(const Proto* f, DumpState* D)
{
int i,n=f->sizeupvalues;
DumpInt(n,D);
for (i=0; i<n; i++)
{
DumpChar(f->upvalues[i].instack,D);
DumpChar(f->upvalues[i].idx,D);
}
}
static void DumpDebug(const Proto* f, DumpState* D)
{
int i,n;
DumpString((D->strip) ? NULL : f->source,D);
n= (D->strip) ? 0 : f->sizelineinfo;
DumpVector(f->lineinfo,n,sizeof(int),D);
n= (D->strip) ? 0 : f->sizelocvars;
DumpInt(n,D);
for (i=0; i<n; i++)
{
DumpString(f->locvars[i].varname,D);
DumpInt(f->locvars[i].startpc,D);
DumpInt(f->locvars[i].endpc,D);
}
n= (D->strip) ? 0 : f->sizeupvalues;
DumpInt(n,D);
for (i=0; i<n; i++) DumpString(f->upvalues[i].name,D);
}
static void DumpFunction(const Proto* f, DumpState* D)
{
DumpInt(f->linedefined,D);
DumpInt(f->lastlinedefined,D);
DumpChar(f->numparams,D);
DumpChar(f->is_vararg,D);
DumpChar(f->maxstacksize,D);
DumpCode(f,D);
DumpConstants(f,D);
DumpUpvalues(f,D);
DumpDebug(f,D);
}
static void DumpHeader(DumpState* D)
{
lu_byte h[LUAC_HEADERSIZE];
luaU_header(h);
DumpBlock(h,LUAC_HEADERSIZE,D);
}
/*
** dump Lua function as precompiled chunk
*/
int luaU_dump (lua_State* L, const Proto* f, lua_Writer w, void* data, int strip)
{
DumpState D;
D.L=L;
D.writer=w;
D.data=data;
D.strip=strip;
D.status=0;
DumpHeader(&D);
DumpFunction(f,&D);
return D.status;
}
-161
View File
@@ -1,161 +0,0 @@
/*
** $Id: lfunc.c,v 2.29 2012/05/08 13:53:33 roberto Exp $
** Auxiliary functions to manipulate prototypes and closures
** See Copyright Notice in lua.h
*/
#include <stddef.h>
#define lfunc_c
#define LUA_CORE
#include "lua.h"
#include "lfunc.h"
#include "lgc.h"
#include "lmem.h"
#include "lobject.h"
#include "lstate.h"
Closure *luaF_newCclosure (lua_State *L, int n) {
Closure *c = &luaC_newobj(L, LUA_TCCL, sizeCclosure(n), NULL, 0)->cl;
c->c.nupvalues = cast_byte(n);
return c;
}
Closure *luaF_newLclosure (lua_State *L, int n) {
Closure *c = &luaC_newobj(L, LUA_TLCL, sizeLclosure(n), NULL, 0)->cl;
c->l.p = NULL;
c->l.nupvalues = cast_byte(n);
while (n--) c->l.upvals[n] = NULL;
return c;
}
UpVal *luaF_newupval (lua_State *L) {
UpVal *uv = &luaC_newobj(L, LUA_TUPVAL, sizeof(UpVal), NULL, 0)->uv;
uv->v = &uv->u.value;
setnilvalue(uv->v);
return uv;
}
UpVal *luaF_findupval (lua_State *L, StkId level) {
global_State *g = G(L);
GCObject **pp = &L->openupval;
UpVal *p;
UpVal *uv;
while (*pp != NULL && (p = gco2uv(*pp))->v >= level) {
GCObject *o = obj2gco(p);
lua_assert(p->v != &p->u.value);
if (p->v == level) { /* found a corresponding upvalue? */
if (isdead(g, o)) /* is it dead? */
changewhite(o); /* resurrect it */
return p;
}
resetoldbit(o); /* may create a newer upval after this one */
pp = &p->next;
}
/* not found: create a new one */
uv = &luaC_newobj(L, LUA_TUPVAL, sizeof(UpVal), pp, 0)->uv;
uv->v = level; /* current value lives in the stack */
uv->u.l.prev = &g->uvhead; /* double link it in `uvhead' list */
uv->u.l.next = g->uvhead.u.l.next;
uv->u.l.next->u.l.prev = uv;
g->uvhead.u.l.next = uv;
lua_assert(uv->u.l.next->u.l.prev == uv && uv->u.l.prev->u.l.next == uv);
return uv;
}
static void unlinkupval (UpVal *uv) {
lua_assert(uv->u.l.next->u.l.prev == uv && uv->u.l.prev->u.l.next == uv);
uv->u.l.next->u.l.prev = uv->u.l.prev; /* remove from `uvhead' list */
uv->u.l.prev->u.l.next = uv->u.l.next;
}
void luaF_freeupval (lua_State *L, UpVal *uv) {
if (uv->v != &uv->u.value) /* is it open? */
unlinkupval(uv); /* remove from open list */
luaM_free(L, uv); /* free upvalue */
}
void luaF_close (lua_State *L, StkId level) {
UpVal *uv;
global_State *g = G(L);
while (L->openupval != NULL && (uv = gco2uv(L->openupval))->v >= level) {
GCObject *o = obj2gco(uv);
lua_assert(!isblack(o) && uv->v != &uv->u.value);
L->openupval = uv->next; /* remove from `open' list */
if (isdead(g, o))
luaF_freeupval(L, uv); /* free upvalue */
else {
unlinkupval(uv); /* remove upvalue from 'uvhead' list */
setobj(L, &uv->u.value, uv->v); /* move value to upvalue slot */
uv->v = &uv->u.value; /* now current value lives here */
gch(o)->next = g->allgc; /* link upvalue into 'allgc' list */
g->allgc = o;
luaC_checkupvalcolor(g, uv);
}
}
}
Proto *luaF_newproto (lua_State *L) {
Proto *f = &luaC_newobj(L, LUA_TPROTO, sizeof(Proto), NULL, 0)->p;
f->k = NULL;
f->sizek = 0;
f->p = NULL;
f->sizep = 0;
f->code = NULL;
f->cache = NULL;
f->sizecode = 0;
f->lineinfo = NULL;
f->sizelineinfo = 0;
f->upvalues = NULL;
f->sizeupvalues = 0;
f->numparams = 0;
f->is_vararg = 0;
f->maxstacksize = 0;
f->locvars = NULL;
f->sizelocvars = 0;
f->linedefined = 0;
f->lastlinedefined = 0;
f->source = NULL;
return f;
}
void luaF_freeproto (lua_State *L, Proto *f) {
luaM_freearray(L, f->code, f->sizecode);
luaM_freearray(L, f->p, f->sizep);
luaM_freearray(L, f->k, f->sizek);
luaM_freearray(L, f->lineinfo, f->sizelineinfo);
luaM_freearray(L, f->locvars, f->sizelocvars);
luaM_freearray(L, f->upvalues, f->sizeupvalues);
luaM_free(L, f);
}
/*
** Look for n-th local variable at line `line' in function `func'.
** Returns NULL if not found.
*/
const char *luaF_getlocalname (const Proto *f, int local_number, int pc) {
int i;
for (i = 0; i<f->sizelocvars && f->locvars[i].startpc <= pc; i++) {
if (pc < f->locvars[i].endpc) { /* is variable active? */
local_number--;
if (local_number == 0)
return getstr(f->locvars[i].varname);
}
}
return NULL; /* not found */
}
-33
View File
@@ -1,33 +0,0 @@
/*
** $Id: lfunc.h,v 2.8 2012/05/08 13:53:33 roberto Exp $
** Auxiliary functions to manipulate prototypes and closures
** See Copyright Notice in lua.h
*/
#ifndef lfunc_h
#define lfunc_h
#include "lobject.h"
#define sizeCclosure(n) (cast(int, sizeof(CClosure)) + \
cast(int, sizeof(TValue)*((n)-1)))
#define sizeLclosure(n) (cast(int, sizeof(LClosure)) + \
cast(int, sizeof(TValue *)*((n)-1)))
LUAI_FUNC Proto *luaF_newproto (lua_State *L);
LUAI_FUNC Closure *luaF_newCclosure (lua_State *L, int nelems);
LUAI_FUNC Closure *luaF_newLclosure (lua_State *L, int nelems);
LUAI_FUNC UpVal *luaF_newupval (lua_State *L);
LUAI_FUNC UpVal *luaF_findupval (lua_State *L, StkId level);
LUAI_FUNC void luaF_close (lua_State *L, StkId level);
LUAI_FUNC void luaF_freeproto (lua_State *L, Proto *f);
LUAI_FUNC void luaF_freeupval (lua_State *L, UpVal *uv);
LUAI_FUNC const char *luaF_getlocalname (const Proto *func, int local_number,
int pc);
#endif
-1205
View File
File diff suppressed because it is too large. Load diff
-147
View File
@@ -1,147 +0,0 @@
/*
** $Id: lgc.h,v 2.56 2012/05/23 15:43:14 roberto Exp $
** Garbage Collector
** See Copyright Notice in lua.h
*/
#ifndef lgc_h
#define lgc_h
#include "lobject.h"
#include "lstate.h"
/*
** Collectable objects may have one of three colors: white, which
** means the object is not marked; gray, which means the
** object is marked, but its references may be not marked; and
** black, which means that the object and all its references are marked.
** The main invariant of the garbage collector, while marking objects,
** is that a black object can never point to a white one. Moreover,
** any gray object must be in a "gray list" (gray, grayagain, weak,
** allweak, ephemeron) so that it can be visited again before finishing
** the collection cycle. These lists have no meaning when the invariant
** is not being enforced (e.g., sweep phase).
*/
/* how much to allocate before next GC step */
#if !defined(GCSTEPSIZE)
/* ~100 small strings */
#define GCSTEPSIZE (cast_int(100 * sizeof(TString)))
#endif
/*
** Possible states of the Garbage Collector
*/
#define GCSpropagate 0
#define GCSatomic 1
#define GCSsweepstring 2
#define GCSsweepudata 3
#define GCSsweep 4
#define GCSpause 5
#define issweepphase(g) \
(GCSsweepstring <= (g)->gcstate && (g)->gcstate <= GCSsweep)
#define isgenerational(g) ((g)->gckind == KGC_GEN)
/*
** macro to tell when main invariant (white objects cannot point to black
** ones) must be kept. During a non-generational collection, the sweep
** phase may break the invariant, as objects turned white may point to
** still-black objects. The invariant is restored when sweep ends and
** all objects are white again. During a generational collection, the
** invariant must be kept all times.
*/
#define keepinvariant(g) (isgenerational(g) || g->gcstate <= GCSatomic)
/*
** some useful bit tricks
*/
#define resetbits(x,m) ((x) &= cast(lu_byte, ~(m)))
#define setbits(x,m) ((x) |= (m))
#define testbits(x,m) ((x) & (m))
#define bitmask(b) (1<<(b))
#define bit2mask(b1,b2) (bitmask(b1) | bitmask(b2))
#define l_setbit(x,b) setbits(x, bitmask(b))
#define resetbit(x,b) resetbits(x, bitmask(b))
#define testbit(x,b) testbits(x, bitmask(b))
/* Layout for bit use in `marked' field: */
#define WHITE0BIT 0 /* object is white (type 0) */
#define WHITE1BIT 1 /* object is white (type 1) */
#define BLACKBIT 2 /* object is black */
#define FINALIZEDBIT 3 /* object has been separated for finalization */
#define SEPARATED 4 /* object is in 'finobj' list or in 'tobefnz' */
#define FIXEDBIT 5 /* object is fixed (should not be collected) */
#define OLDBIT 6 /* object is old (only in generational mode) */
/* bit 7 is currently used by tests (luaL_checkmemory) */
#define WHITEBITS bit2mask(WHITE0BIT, WHITE1BIT)
#define iswhite(x) testbits((x)->gch.marked, WHITEBITS)
#define isblack(x) testbit((x)->gch.marked, BLACKBIT)
#define isgray(x) /* neither white nor black */ \
(!testbits((x)->gch.marked, WHITEBITS | bitmask(BLACKBIT)))
#define isold(x) testbit((x)->gch.marked, OLDBIT)
/* MOVE OLD rule: whenever an object is moved to the beginning of
a GC list, its old bit must be cleared */
#define resetoldbit(o) resetbit((o)->gch.marked, OLDBIT)
#define otherwhite(g) (g->currentwhite ^ WHITEBITS)
#define isdeadm(ow,m) (!(((m) ^ WHITEBITS) & (ow)))
#define isdead(g,v) isdeadm(otherwhite(g), (v)->gch.marked)
#define changewhite(x) ((x)->gch.marked ^= WHITEBITS)
#define gray2black(x) l_setbit((x)->gch.marked, BLACKBIT)
#define valiswhite(x) (iscollectable(x) && iswhite(gcvalue(x)))
#define luaC_white(g) cast(lu_byte, (g)->currentwhite & WHITEBITS)
#define luaC_condGC(L,c) \
{if (G(L)->GCdebt > 0) {c;}; condchangemem(L);}
#define luaC_checkGC(L) luaC_condGC(L, luaC_step(L);)
#define luaC_barrier(L,p,v) { if (valiswhite(v) && isblack(obj2gco(p))) \
luaC_barrier_(L,obj2gco(p),gcvalue(v)); }
#define luaC_barrierback(L,p,v) { if (valiswhite(v) && isblack(obj2gco(p))) \
luaC_barrierback_(L,p); }
#define luaC_objbarrier(L,p,o) \
{ if (iswhite(obj2gco(o)) && isblack(obj2gco(p))) \
luaC_barrier_(L,obj2gco(p),obj2gco(o)); }
#define luaC_objbarrierback(L,p,o) \
{ if (iswhite(obj2gco(o)) && isblack(obj2gco(p))) luaC_barrierback_(L,p); }
#define luaC_barrierproto(L,p,c) \
{ if (isblack(obj2gco(p))) luaC_barrierproto_(L,p,c); }
LUAI_FUNC void luaC_freeallobjects (lua_State *L);
LUAI_FUNC void luaC_step (lua_State *L);
LUAI_FUNC void luaC_forcestep (lua_State *L);
LUAI_FUNC void luaC_runtilstate (lua_State *L, int statesmask);
LUAI_FUNC void luaC_fullgc (lua_State *L, int isemergency);
LUAI_FUNC GCObject *luaC_newobj (lua_State *L, int tt, size_t sz,
GCObject **list, int offset);
LUAI_FUNC void luaC_barrier_ (lua_State *L, GCObject *o, GCObject *v);
LUAI_FUNC void luaC_barrierback_ (lua_State *L, GCObject *o);
LUAI_FUNC void luaC_barrierproto_ (lua_State *L, Proto *p, Closure *c);
LUAI_FUNC void luaC_checkfinalizer (lua_State *L, GCObject *o, Table *mt);
LUAI_FUNC void luaC_checkupvalcolor (global_State *g, UpVal *uv);
LUAI_FUNC void luaC_changemode (lua_State *L, int mode);
#endif
-67
View File
@@ -1,67 +0,0 @@
/*
** $Id: linit.c,v 1.32 2011/04/08 19:17:36 roberto Exp $
** Initialization of libraries for lua.c and other clients
** See Copyright Notice in lua.h
*/
/*
** If you embed Lua in your program and need to open the standard
** libraries, call luaL_openlibs in your program. If you need a
** different set of libraries, copy this file to your project and edit
** it to suit your needs.
*/
#define linit_c
#define LUA_LIB
#include "lua.h"
#include "lualib.h"
#include "lauxlib.h"
/*
** these libs are loaded by lua.c and are readily available to any Lua
** program
*/
static const luaL_Reg loadedlibs[] = {
{"_G", luaopen_base},
{LUA_LOADLIBNAME, luaopen_package},
{LUA_COLIBNAME, luaopen_coroutine},
{LUA_TABLIBNAME, luaopen_table},
{LUA_IOLIBNAME, luaopen_io},
{LUA_OSLIBNAME, luaopen_os},
{LUA_STRLIBNAME, luaopen_string},
{LUA_BITLIBNAME, luaopen_bit32},
{LUA_MATHLIBNAME, luaopen_math},
{LUA_DBLIBNAME, luaopen_debug},
{NULL, NULL}
};
/*
** these libs are preloaded and must be required before used
*/
static const luaL_Reg preloadedlibs[] = {
{NULL, NULL}
};
LUALIB_API void luaL_openlibs (lua_State *L) {
const luaL_Reg *lib;
/* call open functions from 'loadedlibs' and set results to global table */
for (lib = loadedlibs; lib->func; lib++) {
luaL_requiref(L, lib->name, lib->func, 1);
lua_pop(L, 1); /* remove lib */
}
/* add open functions from 'preloadedlibs' into 'package.preload' table */
luaL_getsubtable(L, LUA_REGISTRYINDEX, "_PRELOAD");
for (lib = preloadedlibs; lib->func; lib++) {
lua_pushcfunction(L, lib->func);
lua_setfield(L, -2, lib->name);
}
lua_pop(L, 1); /* remove _PRELOAD table */
}
-657
View File
@@ -1,657 +0,0 @@
/*
** $Id: liolib.c,v 2.108 2011/11/25 12:50:03 roberto Exp $
** Standard I/O (and system) library
** See Copyright Notice in lua.h
*/
/*
** POSIX idiosyncrasy!
** This definition must come before the inclusion of 'stdio.h'; it
** should not affect non-POSIX systems
*/
#if !defined(_FILE_OFFSET_BITS)
#define _FILE_OFFSET_BITS 64
#endif
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define liolib_c
#define LUA_LIB
#include "lua.h"
#include "lauxlib.h"
#include "lualib.h"
/*
** {======================================================
** lua_popen spawns a new process connected to the current
** one through the file streams.
** =======================================================
*/
#if !defined(lua_popen) /* { */
#if defined(LUA_USE_POPEN) /* { */
#define lua_popen(L,c,m) ((void)L, fflush(NULL), popen(c,m))
#define lua_pclose(L,file) ((void)L, pclose(file))
#elif defined(LUA_WIN) /* }{ */
#define lua_popen(L,c,m) ((void)L, _popen(c,m))
#define lua_pclose(L,file) ((void)L, _pclose(file))
#else /* }{ */
#define lua_popen(L,c,m) ((void)((void)c, m), \
luaL_error(L, LUA_QL("popen") " not supported"), (FILE*)0)
#define lua_pclose(L,file) ((void)((void)L, file), -1)
#endif /* } */
#endif /* } */
/* }====================================================== */
/*
** {======================================================
** lua_fseek/lua_ftell: configuration for longer offsets
** =======================================================
*/
#if !defined(lua_fseek) /* { */
#if defined(LUA_USE_POSIX)
#define l_fseek(f,o,w) fseeko(f,o,w)
#define l_ftell(f) ftello(f)
#define l_seeknum off_t
#elif defined(LUA_WIN) && !defined(_CRTIMP_TYPEINFO) \
&& defined(_MSC_VER) && (_MSC_VER >= 1400)
/* Windows (but not DDK) and Visual C++ 2005 or higher */
#define l_fseek(f,o,w) _fseeki64(f,o,w)
#define l_ftell(f) _ftelli64(f)
#define l_seeknum __int64
#else
#define l_fseek(f,o,w) fseek(f,o,w)
#define l_ftell(f) ftell(f)
#define l_seeknum long
#endif
#endif /* } */
/* }====================================================== */
#define IO_PREFIX "_IO_"
#define IO_INPUT (IO_PREFIX "input")
#define IO_OUTPUT (IO_PREFIX "output")
typedef luaL_Stream LStream;
#define tolstream(L) ((LStream *)luaL_checkudata(L, 1, LUA_FILEHANDLE))
#define isclosed(p) ((p)->closef == NULL)
static int io_type (lua_State *L) {
LStream *p;
luaL_checkany(L, 1);
p = (LStream *)luaL_testudata(L, 1, LUA_FILEHANDLE);
if (p == NULL)
lua_pushnil(L); /* not a file */
else if (isclosed(p))
lua_pushliteral(L, "closed file");
else
lua_pushliteral(L, "file");
return 1;
}
static int f_tostring (lua_State *L) {
LStream *p = tolstream(L);
if (isclosed(p))
lua_pushliteral(L, "file (closed)");
else
lua_pushfstring(L, "file (%p)", p->f);
return 1;
}
static FILE *tofile (lua_State *L) {
LStream *p = tolstream(L);
if (isclosed(p))
luaL_error(L, "attempt to use a closed file");
lua_assert(p->f);
return p->f;
}
/*
** When creating file handles, always creates a `closed' file handle
** before opening the actual file; so, if there is a memory error, the
** file is not left opened.
*/
static LStream *newprefile (lua_State *L) {
LStream *p = (LStream *)lua_newuserdata(L, sizeof(LStream));
p->closef = NULL; /* mark file handle as 'closed' */
luaL_setmetatable(L, LUA_FILEHANDLE);
return p;
}
static int aux_close (lua_State *L) {
LStream *p = tolstream(L);
lua_CFunction cf = p->closef;
p->closef = NULL; /* mark stream as closed */
return (*cf)(L); /* close it */
}
static int io_close (lua_State *L) {
if (lua_isnone(L, 1)) /* no argument? */
lua_getfield(L, LUA_REGISTRYINDEX, IO_OUTPUT); /* use standard output */
tofile(L); /* make sure argument is an open stream */
return aux_close(L);
}
static int f_gc (lua_State *L) {
LStream *p = tolstream(L);
if (!isclosed(p) && p->f != NULL)
aux_close(L); /* ignore closed and incompletely open files */
return 0;
}
/*
** function to close regular files
*/
static int io_fclose (lua_State *L) {
LStream *p = tolstream(L);
int res = fclose(p->f);
return luaL_fileresult(L, (res == 0), NULL);
}
static LStream *newfile (lua_State *L) {
LStream *p = newprefile(L);
p->f = NULL;
p->closef = &io_fclose;
return p;
}
static void opencheck (lua_State *L, const char *fname, const char *mode) {
LStream *p = newfile(L);
p->f = fopen(fname, mode);
if (p->f == NULL)
luaL_error(L, "cannot open file " LUA_QS " (%s)", fname, strerror(errno));
}
static int io_open (lua_State *L) {
const char *filename = luaL_checkstring(L, 1);
const char *mode = luaL_optstring(L, 2, "r");
LStream *p = newfile(L);
int i = 0;
/* check whether 'mode' matches '[rwa]%+?b?' */
if (!(mode[i] != '\0' && strchr("rwa", mode[i++]) != NULL &&
(mode[i] != '+' || ++i) && /* skip if char is '+' */
(mode[i] != 'b' || ++i) && /* skip if char is 'b' */
(mode[i] == '\0')))
return luaL_error(L, "invalid mode " LUA_QS
" (should match " LUA_QL("[rwa]%%+?b?") ")", mode);
p->f = fopen(filename, mode);
return (p->f == NULL) ? luaL_fileresult(L, 0, filename) : 1;
}
/*
** function to close 'popen' files
*/
static int io_pclose (lua_State *L) {
LStream *p = tolstream(L);
return luaL_execresult(L, lua_pclose(L, p->f));
}
static int io_popen (lua_State *L) {
const char *filename = luaL_checkstring(L, 1);
const char *mode = luaL_optstring(L, 2, "r");
LStream *p = newprefile(L);
p->f = lua_popen(L, filename, mode);
p->closef = &io_pclose;
return (p->f == NULL) ? luaL_fileresult(L, 0, filename) : 1;
}
static int io_tmpfile (lua_State *L) {
LStream *p = newfile(L);
p->f = tmpfile();
return (p->f == NULL) ? luaL_fileresult(L, 0, NULL) : 1;
}
static FILE *getiofile (lua_State *L, const char *findex) {
LStream *p;
lua_getfield(L, LUA_REGISTRYINDEX, findex);
p = (LStream *)lua_touserdata(L, -1);
if (isclosed(p))
luaL_error(L, "standard %s file is closed", findex + strlen(IO_PREFIX));
return p->f;
}
static int g_iofile (lua_State *L, const char *f, const char *mode) {
if (!lua_isnoneornil(L, 1)) {
const char *filename = lua_tostring(L, 1);
if (filename)
opencheck(L, filename, mode);
else {
tofile(L); /* check that it's a valid file handle */
lua_pushvalue(L, 1);
}
lua_setfield(L, LUA_REGISTRYINDEX, f);
}
/* return current value */
lua_getfield(L, LUA_REGISTRYINDEX, f);
return 1;
}
static int io_input (lua_State *L) {
return g_iofile(L, IO_INPUT, "r");
}
static int io_output (lua_State *L) {
return g_iofile(L, IO_OUTPUT, "w");
}
static int io_readline (lua_State *L);
static void aux_lines (lua_State *L, int toclose) {
int i;
int n = lua_gettop(L) - 1; /* number of arguments to read */
/* ensure that arguments will fit here and into 'io_readline' stack */
luaL_argcheck(L, n <= LUA_MINSTACK - 3, LUA_MINSTACK - 3, "too many options");
lua_pushvalue(L, 1); /* file handle */
lua_pushinteger(L, n); /* number of arguments to read */
lua_pushboolean(L, toclose); /* close/not close file when finished */
for (i = 1; i <= n; i++) lua_pushvalue(L, i + 1); /* copy arguments */
lua_pushcclosure(L, io_readline, 3 + n);
}
static int f_lines (lua_State *L) {
tofile(L); /* check that it's a valid file handle */
aux_lines(L, 0);
return 1;
}
static int io_lines (lua_State *L) {
int toclose;
if (lua_isnone(L, 1)) lua_pushnil(L); /* at least one argument */
if (lua_isnil(L, 1)) { /* no file name? */
lua_getfield(L, LUA_REGISTRYINDEX, IO_INPUT); /* get default input */
lua_replace(L, 1); /* put it at index 1 */
tofile(L); /* check that it's a valid file handle */
toclose = 0; /* do not close it after iteration */
}
else { /* open a new file */
const char *filename = luaL_checkstring(L, 1);
opencheck(L, filename, "r");
lua_replace(L, 1); /* put file at index 1 */
toclose = 1; /* close it after iteration */
}
aux_lines(L, toclose);
return 1;
}
/*
** {======================================================
** READ
** =======================================================
*/
static int read_number (lua_State *L, FILE *f) {
lua_Number d;
if (fscanf(f, LUA_NUMBER_SCAN, &d) == 1) {
lua_pushnumber(L, d);
return 1;
}
else {
lua_pushnil(L); /* "result" to be removed */
return 0; /* read fails */
}
}
static int test_eof (lua_State *L, FILE *f) {
int c = getc(f);
ungetc(c, f);
lua_pushlstring(L, NULL, 0);
return (c != EOF);
}
static int read_line (lua_State *L, FILE *f, int chop) {
luaL_Buffer b;
luaL_buffinit(L, &b);
for (;;) {
size_t l;
char *p = luaL_prepbuffer(&b);
if (fgets(p, LUAL_BUFFERSIZE, f) == NULL) { /* eof? */
luaL_pushresult(&b); /* close buffer */
return (lua_rawlen(L, -1) > 0); /* check whether read something */
}
l = strlen(p);
if (l == 0 || p[l-1] != '\n')
luaL_addsize(&b, l);
else {
luaL_addsize(&b, l - chop); /* chop 'eol' if needed */
luaL_pushresult(&b); /* close buffer */
return 1; /* read at least an `eol' */
}
}
}
#define MAX_SIZE_T (~(size_t)0)
static void read_all (lua_State *L, FILE *f) {
size_t rlen = LUAL_BUFFERSIZE; /* how much to read in each cycle */
luaL_Buffer b;
luaL_buffinit(L, &b);
for (;;) {
char *p = luaL_prepbuffsize(&b, rlen);
size_t nr = fread(p, sizeof(char), rlen, f);
luaL_addsize(&b, nr);
if (nr < rlen) break; /* eof? */
else if (rlen <= (MAX_SIZE_T / 4)) /* avoid buffers too large */
rlen *= 2; /* double buffer size at each iteration */
}
luaL_pushresult(&b); /* close buffer */
}
static int read_chars (lua_State *L, FILE *f, size_t n) {
size_t nr; /* number of chars actually read */
char *p;
luaL_Buffer b;
luaL_buffinit(L, &b);
p = luaL_prepbuffsize(&b, n); /* prepare buffer to read whole block */
nr = fread(p, sizeof(char), n, f); /* try to read 'n' chars */
luaL_addsize(&b, nr);
luaL_pushresult(&b); /* close buffer */
return (nr > 0); /* true iff read something */
}
static int g_read (lua_State *L, FILE *f, int first) {
int nargs = lua_gettop(L) - 1;
int success;
int n;
clearerr(f);
if (nargs == 0) { /* no arguments? */
success = read_line(L, f, 1);
n = first+1; /* to return 1 result */
}
else { /* ensure stack space for all results and for auxlib's buffer */
luaL_checkstack(L, nargs+LUA_MINSTACK, "too many arguments");
success = 1;
for (n = first; nargs-- && success; n++) {
if (lua_type(L, n) == LUA_TNUMBER) {
size_t l = (size_t)lua_tointeger(L, n);
success = (l == 0) ? test_eof(L, f) : read_chars(L, f, l);
}
else {
const char *p = lua_tostring(L, n);
luaL_argcheck(L, p && p[0] == '*', n, "invalid option");
switch (p[1]) {
case 'n': /* number */
success = read_number(L, f);
break;
case 'l': /* line */
success = read_line(L, f, 1);
break;
case 'L': /* line with end-of-line */
success = read_line(L, f, 0);
break;
case 'a': /* file */
read_all(L, f); /* read entire file */
success = 1; /* always success */
break;
default:
return luaL_argerror(L, n, "invalid format");
}
}
}
}
if (ferror(f))
return luaL_fileresult(L, 0, NULL);
if (!success) {
lua_pop(L, 1); /* remove last result */
lua_pushnil(L); /* push nil instead */
}
return n - first;
}
static int io_read (lua_State *L) {
return g_read(L, getiofile(L, IO_INPUT), 1);
}
static int f_read (lua_State *L) {
return g_read(L, tofile(L), 2);
}
static int io_readline (lua_State *L) {
LStream *p = (LStream *)lua_touserdata(L, lua_upvalueindex(1));
int i;
int n = (int)lua_tointeger(L, lua_upvalueindex(2));
if (isclosed(p)) /* file is already closed? */
return luaL_error(L, "file is already closed");
lua_settop(L , 1);
for (i = 1; i <= n; i++) /* push arguments to 'g_read' */
lua_pushvalue(L, lua_upvalueindex(3 + i));
n = g_read(L, p->f, 2); /* 'n' is number of results */
lua_assert(n > 0); /* should return at least a nil */
if (!lua_isnil(L, -n)) /* read at least one value? */
return n; /* return them */
else { /* first result is nil: EOF or error */
if (n > 1) { /* is there error information? */
/* 2nd result is error message */
return luaL_error(L, "%s", lua_tostring(L, -n + 1));
}
if (lua_toboolean(L, lua_upvalueindex(3))) { /* generator created file? */
lua_settop(L, 0);
lua_pushvalue(L, lua_upvalueindex(1));
aux_close(L); /* close it */
}
return 0;
}
}
/* }====================================================== */
static int g_write (lua_State *L, FILE *f, int arg) {
int nargs = lua_gettop(L) - arg;
int status = 1;
for (; nargs--; arg++) {
if (lua_type(L, arg) == LUA_TNUMBER) {
/* optimization: could be done exactly as for strings */
status = status &&
fprintf(f, LUA_NUMBER_FMT, lua_tonumber(L, arg)) > 0;
}
else {
size_t l;
const char *s = luaL_checklstring(L, arg, &l);
status = status && (fwrite(s, sizeof(char), l, f) == l);
}
}
if (status) return 1; /* file handle already on stack top */
else return luaL_fileresult(L, status, NULL);
}
static int io_write (lua_State *L) {
return g_write(L, getiofile(L, IO_OUTPUT), 1);
}
static int f_write (lua_State *L) {
FILE *f = tofile(L);
lua_pushvalue(L, 1); /* push file at the stack top (to be returned) */
return g_write(L, f, 2);
}
static int f_seek (lua_State *L) {
static const int mode[] = {SEEK_SET, SEEK_CUR, SEEK_END};
static const char *const modenames[] = {"set", "cur", "end", NULL};
FILE *f = tofile(L);
int op = luaL_checkoption(L, 2, "cur", modenames);
lua_Number p3 = luaL_optnumber(L, 3, 0);
l_seeknum offset = (l_seeknum)p3;
luaL_argcheck(L, (lua_Number)offset == p3, 3,
"not an integer in proper range");
op = l_fseek(f, offset, mode[op]);
if (op)
return luaL_fileresult(L, 0, NULL); /* error */
else {
lua_pushnumber(L, (lua_Number)l_ftell(f));
return 1;
}
}
static int f_setvbuf (lua_State *L) {
static const int mode[] = {_IONBF, _IOFBF, _IOLBF};
static const char *const modenames[] = {"no", "full", "line", NULL};
FILE *f = tofile(L);
int op = luaL_checkoption(L, 2, NULL, modenames);
lua_Integer sz = luaL_optinteger(L, 3, LUAL_BUFFERSIZE);
int res = setvbuf(f, NULL, mode[op], sz);
return luaL_fileresult(L, res == 0, NULL);
}
static int io_flush (lua_State *L) {
return luaL_fileresult(L, fflush(getiofile(L, IO_OUTPUT)) == 0, NULL);
}
static int f_flush (lua_State *L) {
return luaL_fileresult(L, fflush(tofile(L)) == 0, NULL);
}
/*
** functions for 'io' library
*/
static const luaL_Reg iolib[] = {
{"close", io_close},
{"flush", io_flush},
{"input", io_input},
{"lines", io_lines},
{"open", io_open},
{"output", io_output},
{"popen", io_popen},
{"read", io_read},
{"tmpfile", io_tmpfile},
{"type", io_type},
{"write", io_write},
{NULL, NULL}
};
/*
** methods for file handles
*/
static const luaL_Reg flib[] = {
{"close", io_close},
{"flush", f_flush},
{"lines", f_lines},
{"read", f_read},
{"seek", f_seek},
{"setvbuf", f_setvbuf},
{"write", f_write},
{"__gc", f_gc},
{"__tostring", f_tostring},
{NULL, NULL}
};
static void createmeta (lua_State *L) {
luaL_newmetatable(L, LUA_FILEHANDLE); /* create metatable for file handles */
lua_pushvalue(L, -1); /* push metatable */
lua_setfield(L, -2, "__index"); /* metatable.__index = metatable */
luaL_setfuncs(L, flib, 0); /* add file methods to new metatable */
lua_pop(L, 1); /* pop new metatable */
}
/*
** function to (not) close the standard files stdin, stdout, and stderr
*/
static int io_noclose (lua_State *L) {
LStream *p = tolstream(L);
p->closef = &io_noclose; /* keep file opened */
lua_pushnil(L);
lua_pushliteral(L, "cannot close standard file");
return 2;
}
static void createstdfile (lua_State *L, FILE *f, const char *k,
const char *fname) {
LStream *p = newprefile(L);
p->f = f;
p->closef = &io_noclose;
if (k != NULL) {
lua_pushvalue(L, -1);
lua_setfield(L, LUA_REGISTRYINDEX, k); /* add file to registry */
}
lua_setfield(L, -2, fname); /* add file to module */
}
LUAMOD_API int luaopen_io (lua_State *L) {
luaL_newlib(L, iolib); /* new module */
createmeta(L);
/* create (and set) default files */
createstdfile(L, stdin, IO_INPUT, "stdin");
createstdfile(L, stdout, IO_OUTPUT, "stdout");
createstdfile(L, stderr, NULL, "stderr");
return 1;
}
-527
View File
@@ -1,527 +0,0 @@
/*
** $Id: llex.c,v 2.61 2012/01/23 23:05:51 roberto Exp $
** Lexical Analyzer
** See Copyright Notice in lua.h
*/
#include <locale.h>
#include <string.h>
#define llex_c
#define LUA_CORE
#include "lua.h"
#include "lctype.h"
#include "ldo.h"
#include "llex.h"
#include "lobject.h"
#include "lparser.h"
#include "lstate.h"
#include "lstring.h"
#include "ltable.h"
#include "lzio.h"
#define next(ls) (ls->current = zgetc(ls->z))
#define currIsNewline(ls) (ls->current == '\n' || ls->current == '\r')
/* ORDER RESERVED */
static const char *const luaX_tokens [] = {
"and", "break", "do", "else", "elseif",
"end", "false", "for", "function", "goto", "if",
"in", "local", "nil", "not", "or", "repeat",
"return", "then", "true", "until", "while",
"..", "...", "==", ">=", "<=", "~=", "::", "<eof>",
"<number>", "<name>", "<string>"
};
#define save_and_next(ls) (save(ls, ls->current), next(ls))
static l_noret lexerror (LexState *ls, const char *msg, int token);
static void save (LexState *ls, int c) {
Mbuffer *b = ls->buff;
if (luaZ_bufflen(b) + 1 > luaZ_sizebuffer(b)) {
size_t newsize;
if (luaZ_sizebuffer(b) >= MAX_SIZET/2)
lexerror(ls, "lexical element too long", 0);
newsize = luaZ_sizebuffer(b) * 2;
luaZ_resizebuffer(ls->L, b, newsize);
}
b->buffer[luaZ_bufflen(b)++] = cast(char, c);
}
void luaX_init (lua_State *L) {
int i;
for (i=0; i<NUM_RESERVED; i++) {
TString *ts = luaS_new(L, luaX_tokens[i]);
luaS_fix(ts); /* reserved words are never collected */
ts->tsv.extra = cast_byte(i+1); /* reserved word */
}
}
const char *luaX_token2str (LexState *ls, int token) {
if (token < FIRST_RESERVED) {
lua_assert(token == cast(unsigned char, token));
return (lisprint(token)) ? luaO_pushfstring(ls->L, LUA_QL("%c"), token) :
luaO_pushfstring(ls->L, "char(%d)", token);
}
else {
const char *s = luaX_tokens[token - FIRST_RESERVED];
if (token < TK_EOS)
return luaO_pushfstring(ls->L, LUA_QS, s);
else
return s;
}
}
static const char *txtToken (LexState *ls, int token) {
switch (token) {
case TK_NAME:
case TK_STRING:
case TK_NUMBER:
save(ls, '\0');
return luaO_pushfstring(ls->L, LUA_QS, luaZ_buffer(ls->buff));
default:
return luaX_token2str(ls, token);
}
}
static l_noret lexerror (LexState *ls, const char *msg, int token) {
char buff[LUA_IDSIZE];
luaO_chunkid(buff, getstr(ls->source), LUA_IDSIZE);
msg = luaO_pushfstring(ls->L, "%s:%d: %s", buff, ls->linenumber, msg);
if (token)
luaO_pushfstring(ls->L, "%s near %s", msg, txtToken(ls, token));
luaD_throw(ls->L, LUA_ERRSYNTAX);
}
l_noret luaX_syntaxerror (LexState *ls, const char *msg) {
lexerror(ls, msg, ls->t.token);
}
/*
** creates a new string and anchors it in function's table so that
** it will not be collected until the end of the function's compilation
** (by that time it should be anchored in function's prototype)
*/
TString *luaX_newstring (LexState *ls, const char *str, size_t l) {
lua_State *L = ls->L;
TValue *o; /* entry for `str' */
TString *ts = luaS_newlstr(L, str, l); /* create new string */
setsvalue2s(L, L->top++, ts); /* temporarily anchor it in stack */
o = luaH_set(L, ls->fs->h, L->top - 1);
if (ttisnil(o)) { /* not in use yet? (see 'addK') */
/* boolean value does not need GC barrier;
table has no metatable, so it does not need to invalidate cache */
setbvalue(o, 1); /* t[string] = true */
luaC_checkGC(L);
}
L->top--; /* remove string from stack */
return ts;
}
/*
** increment line number and skips newline sequence (any of
** \n, \r, \n\r, or \r\n)
*/
static void inclinenumber (LexState *ls) {
int old = ls->current;
lua_assert(currIsNewline(ls));
next(ls); /* skip `\n' or `\r' */
if (currIsNewline(ls) && ls->current != old)
next(ls); /* skip `\n\r' or `\r\n' */
if (++ls->linenumber >= MAX_INT)
luaX_syntaxerror(ls, "chunk has too many lines");
}
void luaX_setinput (lua_State *L, LexState *ls, ZIO *z, TString *source,
int firstchar) {
ls->decpoint = '.';
ls->L = L;
ls->current = firstchar;
ls->lookahead.token = TK_EOS; /* no look-ahead token */
ls->z = z;
ls->fs = NULL;
ls->linenumber = 1;
ls->lastline = 1;
ls->source = source;
ls->envn = luaS_new(L, LUA_ENV); /* create env name */
luaS_fix(ls->envn); /* never collect this name */
luaZ_resizebuffer(ls->L, ls->buff, LUA_MINBUFFER); /* initialize buffer */
}
/*
** =======================================================
** LEXICAL ANALYZER
** =======================================================
*/
static int check_next (LexState *ls, const char *set) {
if (ls->current == '\0' || !strchr(set, ls->current))
return 0;
save_and_next(ls);
return 1;
}
/*
** change all characters 'from' in buffer to 'to'
*/
static void buffreplace (LexState *ls, char from, char to) {
size_t n = luaZ_bufflen(ls->buff);
char *p = luaZ_buffer(ls->buff);
while (n--)
if (p[n] == from) p[n] = to;
}
#if !defined(getlocaledecpoint)
#define getlocaledecpoint() (localeconv()->decimal_point[0])
#endif
#define buff2d(b,e) luaO_str2d(luaZ_buffer(b), luaZ_bufflen(b) - 1, e)
/*
** in case of format error, try to change decimal point separator to
** the one defined in the current locale and check again
*/
static void trydecpoint (LexState *ls, SemInfo *seminfo) {
char old = ls->decpoint;
ls->decpoint = getlocaledecpoint();
buffreplace(ls, old, ls->decpoint); /* try new decimal separator */
if (!buff2d(ls->buff, &seminfo->r)) {
/* format error with correct decimal point: no more options */
buffreplace(ls, ls->decpoint, '.'); /* undo change (for error message) */
lexerror(ls, "malformed number", TK_NUMBER);
}
}
/* LUA_NUMBER */
/*
** this function is quite liberal in what it accepts, as 'luaO_str2d'
** will reject ill-formed numerals.
*/
static void read_numeral (LexState *ls, SemInfo *seminfo) {
const char *expo = "Ee";
int first = ls->current;
lua_assert(lisdigit(ls->current));
save_and_next(ls);
if (first == '0' && check_next(ls, "Xx")) /* hexadecimal? */
expo = "Pp";
for (;;) {
if (check_next(ls, expo)) /* exponent part? */
check_next(ls, "+-"); /* optional exponent sign */
if (lisxdigit(ls->current) || ls->current == '.')
save_and_next(ls);
else break;
}
save(ls, '\0');
buffreplace(ls, '.', ls->decpoint); /* follow locale for decimal point */
if (!buff2d(ls->buff, &seminfo->r)) /* format error? */
trydecpoint(ls, seminfo); /* try to update decimal point separator */
}
/*
** skip a sequence '[=*[' or ']=*]' and return its number of '='s or
** -1 if sequence is malformed
*/
static int skip_sep (LexState *ls) {
int count = 0;
int s = ls->current;
lua_assert(s == '[' || s == ']');
save_and_next(ls);
while (ls->current == '=') {
save_and_next(ls);
count++;
}
return (ls->current == s) ? count : (-count) - 1;
}
static void read_long_string (LexState *ls, SemInfo *seminfo, int sep) {
save_and_next(ls); /* skip 2nd `[' */
if (currIsNewline(ls)) /* string starts with a newline? */
inclinenumber(ls); /* skip it */
for (;;) {
switch (ls->current) {
case EOZ:
lexerror(ls, (seminfo) ? "unfinished long string" :
"unfinished long comment", TK_EOS);
break; /* to avoid warnings */
case ']': {
if (skip_sep(ls) == sep) {
save_and_next(ls); /* skip 2nd `]' */
goto endloop;
}
break;
}
case '\n': case '\r': {
save(ls, '\n');
inclinenumber(ls);
if (!seminfo) luaZ_resetbuffer(ls->buff); /* avoid wasting space */
break;
}
default: {
if (seminfo) save_and_next(ls);
else next(ls);
}
}
} endloop:
if (seminfo)
seminfo->ts = luaX_newstring(ls, luaZ_buffer(ls->buff) + (2 + sep),
luaZ_bufflen(ls->buff) - 2*(2 + sep));
}
static void escerror (LexState *ls, int *c, int n, const char *msg) {
int i;
luaZ_resetbuffer(ls->buff); /* prepare error message */
save(ls, '\\');
for (i = 0; i < n && c[i] != EOZ; i++)
save(ls, c[i]);
lexerror(ls, msg, TK_STRING);
}
static int readhexaesc (LexState *ls) {
int c[3], i; /* keep input for error message */
int r = 0; /* result accumulator */
c[0] = 'x'; /* for error message */
for (i = 1; i < 3; i++) { /* read two hexa digits */
c[i] = next(ls);
if (!lisxdigit(c[i]))
escerror(ls, c, i + 1, "hexadecimal digit expected");
r = (r << 4) + luaO_hexavalue(c[i]);
}
return r;
}
static int readdecesc (LexState *ls) {
int c[3], i;
int r = 0; /* result accumulator */
for (i = 0; i < 3 && lisdigit(ls->current); i++) { /* read up to 3 digits */
c[i] = ls->current;
r = 10*r + c[i] - '0';
next(ls);
}
if (r > UCHAR_MAX)
escerror(ls, c, i, "decimal escape too large");
return r;
}
static void read_string (LexState *ls, int del, SemInfo *seminfo) {
save_and_next(ls); /* keep delimiter (for error messages) */
while (ls->current != del) {
switch (ls->current) {
case EOZ:
lexerror(ls, "unfinished string", TK_EOS);
break; /* to avoid warnings */
case '\n':
case '\r':
lexerror(ls, "unfinished string", TK_STRING);
break; /* to avoid warnings */
case '\\': { /* escape sequences */
int c; /* final character to be saved */
next(ls); /* do not save the `\' */
switch (ls->current) {
case 'a': c = '\a'; goto read_save;
case 'b': c = '\b'; goto read_save;
case 'f': c = '\f'; goto read_save;
case 'n': c = '\n'; goto read_save;
case 'r': c = '\r'; goto read_save;
case 't': c = '\t'; goto read_save;
case 'v': c = '\v'; goto read_save;
case 'x': c = readhexaesc(ls); goto read_save;
case '\n': case '\r':
inclinenumber(ls); c = '\n'; goto only_save;
case '\\': case '\"': case '\'':
c = ls->current; goto read_save;
case EOZ: goto no_save; /* will raise an error next loop */
case 'z': { /* zap following span of spaces */
next(ls); /* skip the 'z' */
while (lisspace(ls->current)) {
if (currIsNewline(ls)) inclinenumber(ls);
else next(ls);
}
goto no_save;
}
default: {
if (!lisdigit(ls->current))
escerror(ls, &ls->current, 1, "invalid escape sequence");
/* digital escape \ddd */
c = readdecesc(ls);
goto only_save;
}
}
read_save: next(ls); /* read next character */
only_save: save(ls, c); /* save 'c' */
no_save: break;
}
default:
save_and_next(ls);
}
}
save_and_next(ls); /* skip delimiter */
seminfo->ts = luaX_newstring(ls, luaZ_buffer(ls->buff) + 1,
luaZ_bufflen(ls->buff) - 2);
}
static int llex (LexState *ls, SemInfo *seminfo) {
luaZ_resetbuffer(ls->buff);
for (;;) {
switch (ls->current) {
case '\n': case '\r': { /* line breaks */
inclinenumber(ls);
break;
}
case ' ': case '\f': case '\t': case '\v': { /* spaces */
next(ls);
break;
}
case '-': { /* '-' or '--' (comment) */
next(ls);
if (ls->current != '-') return '-';
/* else is a comment */
next(ls);
if (ls->current == '[') { /* long comment? */
int sep = skip_sep(ls);
luaZ_resetbuffer(ls->buff); /* `skip_sep' may dirty the buffer */
if (sep >= 0) {
read_long_string(ls, NULL, sep); /* skip long comment */
luaZ_resetbuffer(ls->buff); /* previous call may dirty the buff. */
break;
}
}
/* else short comment */
while (!currIsNewline(ls) && ls->current != EOZ)
next(ls); /* skip until end of line (or end of file) */
break;
}
case '[': { /* long string or simply '[' */
int sep = skip_sep(ls);
if (sep >= 0) {
read_long_string(ls, seminfo, sep);
return TK_STRING;
}
else if (sep == -1) return '[';
else lexerror(ls, "invalid long string delimiter", TK_STRING);
}
case '=': {
next(ls);
if (ls->current != '=') return '=';
else { next(ls); return TK_EQ; }
}
case '<': {
next(ls);
if (ls->current != '=') return '<';
else { next(ls); return TK_LE; }
}
case '>': {
next(ls);
if (ls->current != '=') return '>';
else { next(ls); return TK_GE; }
}
case '~': {
next(ls);
if (ls->current != '=') return '~';
else { next(ls); return TK_NE; }
}
case ':': {
next(ls);
if (ls->current != ':') return ':';
else { next(ls); return TK_DBCOLON; }
}
case '"': case '\'': { /* short literal strings */
read_string(ls, ls->current, seminfo);
return TK_STRING;
}
case '.': { /* '.', '..', '...', or number */
save_and_next(ls);
if (check_next(ls, ".")) {
if (check_next(ls, "."))
return TK_DOTS; /* '...' */
else return TK_CONCAT; /* '..' */
}
else if (!lisdigit(ls->current)) return '.';
/* else go through */
}
case '0': case '1': case '2': case '3': case '4':
case '5': case '6': case '7': case '8': case '9': {
read_numeral(ls, seminfo);
return TK_NUMBER;
}
case EOZ: {
return TK_EOS;
}
default: {
if (lislalpha(ls->current)) { /* identifier or reserved word? */
TString *ts;
do {
save_and_next(ls);
} while (lislalnum(ls->current));
ts = luaX_newstring(ls, luaZ_buffer(ls->buff),
luaZ_bufflen(ls->buff));
seminfo->ts = ts;
if (isreserved(ts)) /* reserved word? */
return ts->tsv.extra - 1 + FIRST_RESERVED;
else {
return TK_NAME;
}
}
else { /* single-char tokens (+ - / ...) */
int c = ls->current;
next(ls);
return c;
}
}
}
}
}
void luaX_next (LexState *ls) {
ls->lastline = ls->linenumber;
if (ls->lookahead.token != TK_EOS) { /* is there a look-ahead token? */
ls->t = ls->lookahead; /* use this one */
ls->lookahead.token = TK_EOS; /* and discharge it */
}
else
ls->t.token = llex(ls, &ls->t.seminfo); /* read next token */
}
int luaX_lookahead (LexState *ls) {
lua_assert(ls->lookahead.token == TK_EOS);
ls->lookahead.token = llex(ls, &ls->lookahead.seminfo);
return ls->lookahead.token;
}
-78
View File
@@ -1,78 +0,0 @@
/*
** $Id: llex.h,v 1.72 2011/11/30 12:43:51 roberto Exp $
** Lexical Analyzer
** See Copyright Notice in lua.h
*/
#ifndef llex_h
#define llex_h
#include "lobject.h"
#include "lzio.h"
#define FIRST_RESERVED 257
/*
* WARNING: if you change the order of this enumeration,
* grep "ORDER RESERVED"
*/
enum RESERVED {
/* terminal symbols denoted by reserved words */
TK_AND = FIRST_RESERVED, TK_BREAK,
TK_DO, TK_ELSE, TK_ELSEIF, TK_END, TK_FALSE, TK_FOR, TK_FUNCTION,
TK_GOTO, TK_IF, TK_IN, TK_LOCAL, TK_NIL, TK_NOT, TK_OR, TK_REPEAT,
TK_RETURN, TK_THEN, TK_TRUE, TK_UNTIL, TK_WHILE,
/* other terminal symbols */
TK_CONCAT, TK_DOTS, TK_EQ, TK_GE, TK_LE, TK_NE, TK_DBCOLON, TK_EOS,
TK_NUMBER, TK_NAME, TK_STRING
};
/* number of reserved words */
#define NUM_RESERVED (cast(int, TK_WHILE-FIRST_RESERVED+1))
typedef union {
lua_Number r;
TString *ts;
} SemInfo; /* semantics information */
typedef struct Token {
int token;
SemInfo seminfo;
} Token;
/* state of the lexer plus state of the parser when shared by all
functions */
typedef struct LexState {
int current; /* current character (charint) */
int linenumber; /* input line counter */
int lastline; /* line of last token `consumed' */
Token t; /* current token */
Token lookahead; /* look ahead token */
struct FuncState *fs; /* current function (parser) */
struct lua_State *L;
ZIO *z; /* input stream */
Mbuffer *buff; /* buffer for tokens */
struct Dyndata *dyd; /* dynamic structures used by the parser */
TString *source; /* current source name */
TString *envn; /* environment variable name */
char decpoint; /* locale decimal point */
} LexState;
LUAI_FUNC void luaX_init (lua_State *L);
LUAI_FUNC void luaX_setinput (lua_State *L, LexState *ls, ZIO *z,
TString *source, int firstchar);
LUAI_FUNC TString *luaX_newstring (LexState *ls, const char *str, size_t l);
LUAI_FUNC void luaX_next (LexState *ls);
LUAI_FUNC int luaX_lookahead (LexState *ls);
LUAI_FUNC l_noret luaX_syntaxerror (LexState *ls, const char *s);
LUAI_FUNC const char *luaX_token2str (LexState *ls, int token);
#endif
-309
View File
@@ -1,309 +0,0 @@
/*
** $Id: llimits.h,v 1.99 2012/05/28 20:32:28 roberto Exp $
** Limits, basic types, and some other `installation-dependent' definitions
** See Copyright Notice in lua.h
*/
#ifndef llimits_h
#define llimits_h
#include <limits.h>
#include <stddef.h>
#include "lua.h"
typedef unsigned LUA_INT32 lu_int32;
typedef LUAI_UMEM lu_mem;
typedef LUAI_MEM l_mem;
/* chars used as small naturals (so that `char' is reserved for characters) */
typedef unsigned char lu_byte;
#define MAX_SIZET ((size_t)(~(size_t)0)-2)
#define MAX_LUMEM ((lu_mem)(~(lu_mem)0)-2)
#define MAX_LMEM ((l_mem) ((MAX_LUMEM >> 1) - 2))
#define MAX_INT (INT_MAX-2) /* maximum value of an int (-2 for safety) */
/*
** conversion of pointer to integer
** this is for hashing only; there is no problem if the integer
** cannot hold the whole pointer value
*/
#define IntPoint(p) ((unsigned int)(lu_mem)(p))
/* type to ensure maximum alignment */
#if !defined(LUAI_USER_ALIGNMENT_T)
#define LUAI_USER_ALIGNMENT_T union { double u; void *s; long l; }
#endif
typedef LUAI_USER_ALIGNMENT_T L_Umaxalign;
/* result of a `usual argument conversion' over lua_Number */
typedef LUAI_UACNUMBER l_uacNumber;
/* internal assertions for in-house debugging */
#if defined(lua_assert)
#define check_exp(c,e) (lua_assert(c), (e))
/* to avoid problems with conditions too long */
#define lua_longassert(c) { if (!(c)) lua_assert(0); }
#else
#define lua_assert(c) ((void)0)
#define check_exp(c,e) (e)
#define lua_longassert(c) ((void)0)
#endif
/*
** assertion for checking API calls
*/
#if !defined(luai_apicheck)
#if defined(LUA_USE_APICHECK)
#include <assert.h>
#define luai_apicheck(L,e) assert(e)
#else
#define luai_apicheck(L,e) lua_assert(e)
#endif
#endif
#define api_check(l,e,msg) luai_apicheck(l,(e) && msg)
#if !defined(UNUSED)
#define UNUSED(x) ((void)(x)) /* to avoid warnings */
#endif
#define cast(t, exp) ((t)(exp))
#define cast_byte(i) cast(lu_byte, (i))
#define cast_num(i) cast(lua_Number, (i))
#define cast_int(i) cast(int, (i))
#define cast_uchar(i) cast(unsigned char, (i))
/*
** non-return type
*/
#if defined(__GNUC__)
#define l_noret void __attribute__((noreturn))
#elif defined(_MSC_VER)
#define l_noret void __declspec(noreturn)
#else
#define l_noret void
#endif
/*
** maximum depth for nested C calls and syntactical nested non-terminals
** in a program. (Value must fit in an unsigned short int.)
*/
#if !defined(LUAI_MAXCCALLS)
#define LUAI_MAXCCALLS 200
#endif
/*
** maximum number of upvalues in a closure (both C and Lua). (Value
** must fit in an unsigned char.)
*/
#define MAXUPVAL UCHAR_MAX
/*
** type for virtual-machine instructions
** must be an unsigned with (at least) 4 bytes (see details in lopcodes.h)
*/
typedef lu_int32 Instruction;
/* maximum stack for a Lua function */
#define MAXSTACK 250
/* minimum size for the string table (must be power of 2) */
#if !defined(MINSTRTABSIZE)
#define MINSTRTABSIZE 32
#endif
/* minimum size for string buffer */
#if !defined(LUA_MINBUFFER)
#define LUA_MINBUFFER 32
#endif
#if !defined(lua_lock)
#define lua_lock(L) ((void) 0)
#define lua_unlock(L) ((void) 0)
#endif
#if !defined(luai_threadyield)
#define luai_threadyield(L) {lua_unlock(L); lua_lock(L);}
#endif
/*
** these macros allow user-specific actions on threads when you defined
** LUAI_EXTRASPACE and need to do something extra when a thread is
** created/deleted/resumed/yielded.
*/
#if !defined(luai_userstateopen)
#define luai_userstateopen(L) ((void)L)
#endif
#if !defined(luai_userstateclose)
#define luai_userstateclose(L) ((void)L)
#endif
#if !defined(luai_userstatethread)
#define luai_userstatethread(L,L1) ((void)L)
#endif
#if !defined(luai_userstatefree)
#define luai_userstatefree(L,L1) ((void)L)
#endif
#if !defined(luai_userstateresume)
#define luai_userstateresume(L,n) ((void)L)
#endif
#if !defined(luai_userstateyield)
#define luai_userstateyield(L,n) ((void)L)
#endif
/*
** lua_number2int is a macro to convert lua_Number to int.
** lua_number2integer is a macro to convert lua_Number to lua_Integer.
** lua_number2unsigned is a macro to convert a lua_Number to a lua_Unsigned.
** lua_unsigned2number is a macro to convert a lua_Unsigned to a lua_Number.
** luai_hashnum is a macro to hash a lua_Number value into an integer.
** The hash must be deterministic and give reasonable values for
** both small and large values (outside the range of integers).
*/
#if defined(MS_ASMTRICK) /* { */
/* trick with Microsoft assembler for X86 */
#define lua_number2int(i,n) __asm {__asm fld n __asm fistp i}
#define lua_number2integer(i,n) lua_number2int(i, n)
#define lua_number2unsigned(i,n) \
{__int64 l; __asm {__asm fld n __asm fistp l} i = (unsigned int)l;}
#elif defined(LUA_IEEE754TRICK) /* }{ */
/* the next trick should work on any machine using IEEE754 with
a 32-bit int type */
union luai_Cast { double l_d; LUA_INT32 l_p[2]; };
#if !defined(LUA_IEEEENDIAN) /* { */
#define LUAI_EXTRAIEEE \
static const union luai_Cast ieeeendian = {-(33.0 + 6755399441055744.0)};
#define LUA_IEEEENDIANLOC (ieeeendian.l_p[1] == 33)
#else
#define LUA_IEEEENDIANLOC LUA_IEEEENDIAN
#define LUAI_EXTRAIEEE /* empty */
#endif /* } */
#define lua_number2int32(i,n,t) \
{ LUAI_EXTRAIEEE \
volatile union luai_Cast u; u.l_d = (n) + 6755399441055744.0; \
(i) = (t)u.l_p[LUA_IEEEENDIANLOC]; }
#define luai_hashnum(i,n) \
{ volatile union luai_Cast u; u.l_d = (n) + 1.0; /* avoid -0 */ \
(i) = u.l_p[0]; (i) += u.l_p[1]; } /* add double bits for his hash */
#define lua_number2int(i,n) lua_number2int32(i, n, int)
#define lua_number2unsigned(i,n) lua_number2int32(i, n, lua_Unsigned)
/* the trick can be expanded to lua_Integer when it is a 32-bit value */
#if defined(LUA_IEEELL)
#define lua_number2integer(i,n) lua_number2int32(i, n, lua_Integer)
#endif
#endif /* } */
/* the following definitions always work, but may be slow */
#if !defined(lua_number2int)
#define lua_number2int(i,n) ((i)=(int)(n))
#endif
#if !defined(lua_number2integer)
#define lua_number2integer(i,n) ((i)=(lua_Integer)(n))
#endif
#if !defined(lua_number2unsigned) /* { */
/* the following definition assures proper modulo behavior */
#if defined(LUA_NUMBER_DOUBLE)
#include <math.h>
#define SUPUNSIGNED ((lua_Number)(~(lua_Unsigned)0) + 1)
#define lua_number2unsigned(i,n) \
((i)=(lua_Unsigned)((n) - floor((n)/SUPUNSIGNED)*SUPUNSIGNED))
#else
#define lua_number2unsigned(i,n) ((i)=(lua_Unsigned)(n))
#endif
#endif /* } */
#if !defined(lua_unsigned2number)
/* on several machines, coercion from unsigned to double is slow,
so it may be worth to avoid */
#define lua_unsigned2number(u) \
(((u) <= (lua_Unsigned)INT_MAX) ? (lua_Number)(int)(u) : (lua_Number)(u))
#endif
#if defined(ltable_c) && !defined(luai_hashnum)
#include <float.h>
#include <math.h>
#define luai_hashnum(i,n) { int e; \
n = frexp(n, &e) * (lua_Number)(INT_MAX - DBL_MAX_EXP); \
lua_number2int(i, n); i += e; }
#endif
/*
** macro to control inclusion of some hard tests on stack reallocation
*/
#if !defined(HARDSTACKTESTS)
#define condmovestack(L) ((void)0)
#else
/* realloc stack keeping its size */
#define condmovestack(L) luaD_reallocstack((L), (L)->stacksize)
#endif
#if !defined(HARDMEMTESTS)
#define condchangemem(L) condmovestack(L)
#else
#define condchangemem(L) \
((void)(!(G(L)->gcrunning) || (luaC_fullgc(L, 0), 1)))
#endif
#endif
Loaded 100 of 162 files, more files were not shown because too many files have changed in this diff. Show more