├── LICENSE ├── Makefile ├── README ├── build └── bin2c.c ├── lua ├── cc.lua ├── const │ ├── entity.lua │ ├── exit.lua │ ├── gopher-types.lua │ └── http-response.lua ├── date.lua ├── debug.lua ├── dns │ └── resolv.lua ├── getopt.lua ├── gzip.lua ├── mailcap.lua ├── net │ ├── ios.lua │ ├── tcp.lua │ └── tls.lua ├── nfl.lua ├── nfl │ ├── tcp.lua │ └── tls.lua ├── string.lua ├── table.lua ├── unix.lua ├── zip.lua └── zip │ ├── read.lua │ └── write.lua ├── other ├── pollset-epoll.c ├── pollset-poll.c └── pollset-select.c ├── rockspecs ├── org.conman.const.exit-1.1.1-1.rockspec ├── org.conman.const.gopher-types-2.0.1-1.rockspec ├── org.conman.env-1.0.4-1.rockspec ├── org.conman.errno-1.1.0-1.rockspec ├── org.conman.iconv-2.0.0-4.rockspec ├── org.conman.syslog-2.1.4-5.rockspec └── org.conman.tls-2.0.0-3.rockspec ├── src ├── base64.c ├── clock.c ├── crc.c ├── env.c ├── errno.c ├── fsys.c ├── hash.c ├── iconv.c ├── idn.c ├── lfsr.c ├── magic.c ├── math.c ├── net.c ├── pollset.c ├── process.c ├── signal.c ├── strcore.c ├── sys.c ├── syslog.c ├── tcc.c └── tls.c └── test ├── base64-test.lua ├── clock-test.lua ├── idn-test.lua ├── net-test.lua ├── pollset-test.lua ├── signal-test.lua └── tap14.lua /LICENSE: -------------------------------------------------------------------------------- 1 | GNU LESSER GENERAL PUBLIC LICENSE 2 | Version 3, 29 June 2007 3 | 4 | Copyright (C) 2007 Free Software Foundation, Inc. 5 | Everyone is permitted to copy and distribute verbatim copies 6 | of this license document, but changing it is not allowed. 7 | 8 | 9 | This version of the GNU Lesser General Public License incorporates 10 | the terms and conditions of version 3 of the GNU General Public 11 | License, supplemented by the additional permissions listed below. 12 | 13 | 0. Additional Definitions. 14 | 15 | As used herein, "this License" refers to version 3 of the GNU Lesser 16 | General Public License, and the "GNU GPL" refers to version 3 of the GNU 17 | General Public License. 18 | 19 | "The Library" refers to a covered work governed by this License, 20 | other than an Application or a Combined Work as defined below. 21 | 22 | An "Application" is any work that makes use of an interface provided 23 | by the Library, but which is not otherwise based on the Library. 24 | Defining a subclass of a class defined by the Library is deemed a mode 25 | of using an interface provided by the Library. 26 | 27 | A "Combined Work" is a work produced by combining or linking an 28 | Application with the Library. The particular version of the Library 29 | with which the Combined Work was made is also called the "Linked 30 | Version". 31 | 32 | The "Minimal Corresponding Source" for a Combined Work means the 33 | Corresponding Source for the Combined Work, excluding any source code 34 | for portions of the Combined Work that, considered in isolation, are 35 | based on the Application, and not on the Linked Version. 36 | 37 | The "Corresponding Application Code" for a Combined Work means the 38 | object code and/or source code for the Application, including any data 39 | and utility programs needed for reproducing the Combined Work from the 40 | Application, but excluding the System Libraries of the Combined Work. 41 | 42 | 1. Exception to Section 3 of the GNU GPL. 43 | 44 | You may convey a covered work under sections 3 and 4 of this License 45 | without being bound by section 3 of the GNU GPL. 46 | 47 | 2. Conveying Modified Versions. 48 | 49 | If you modify a copy of the Library, and, in your modifications, a 50 | facility refers to a function or data to be supplied by an Application 51 | that uses the facility (other than as an argument passed when the 52 | facility is invoked), then you may convey a copy of the modified 53 | version: 54 | 55 | a) under this License, provided that you make a good faith effort to 56 | ensure that, in the event an Application does not supply the 57 | function or data, the facility still operates, and performs 58 | whatever part of its purpose remains meaningful, or 59 | 60 | b) under the GNU GPL, with none of the additional permissions of 61 | this License applicable to that copy. 62 | 63 | 3. Object Code Incorporating Material from Library Header Files. 64 | 65 | The object code form of an Application may incorporate material from 66 | a header file that is part of the Library. You may convey such object 67 | code under terms of your choice, provided that, if the incorporated 68 | material is not limited to numerical parameters, data structure 69 | layouts and accessors, or small macros, inline functions and templates 70 | (ten or fewer lines in length), you do both of the following: 71 | 72 | a) Give prominent notice with each copy of the object code that the 73 | Library is used in it and that the Library and its use are 74 | covered by this License. 75 | 76 | b) Accompany the object code with a copy of the GNU GPL and this license 77 | document. 78 | 79 | 4. Combined Works. 80 | 81 | You may convey a Combined Work under terms of your choice that, 82 | taken together, effectively do not restrict modification of the 83 | portions of the Library contained in the Combined Work and reverse 84 | engineering for debugging such modifications, if you also do each of 85 | the following: 86 | 87 | a) Give prominent notice with each copy of the Combined Work that 88 | the Library is used in it and that the Library and its use are 89 | covered by this License. 90 | 91 | b) Accompany the Combined Work with a copy of the GNU GPL and this license 92 | document. 93 | 94 | c) For a Combined Work that displays copyright notices during 95 | execution, include the copyright notice for the Library among 96 | these notices, as well as a reference directing the user to the 97 | copies of the GNU GPL and this license document. 98 | 99 | d) Do one of the following: 100 | 101 | 0) Convey the Minimal Corresponding Source under the terms of this 102 | License, and the Corresponding Application Code in a form 103 | suitable for, and under terms that permit, the user to 104 | recombine or relink the Application with a modified version of 105 | the Linked Version to produce a modified Combined Work, in the 106 | manner specified by section 6 of the GNU GPL for conveying 107 | Corresponding Source. 108 | 109 | 1) Use a suitable shared library mechanism for linking with the 110 | Library. A suitable mechanism is one that (a) uses at run time 111 | a copy of the Library already present on the user's computer 112 | system, and (b) will operate properly with a modified version 113 | of the Library that is interface-compatible with the Linked 114 | Version. 115 | 116 | e) Provide Installation Information, but only if you would otherwise 117 | be required to provide such information under section 6 of the 118 | GNU GPL, and only to the extent that such information is 119 | necessary to install and execute a modified version of the 120 | Combined Work produced by recombining or relinking the 121 | Application with a modified version of the Linked Version. (If 122 | you use option 4d0, the Installation Information must accompany 123 | the Minimal Corresponding Source and Corresponding Application 124 | Code. If you use option 4d1, you must provide the Installation 125 | Information in the manner specified by section 6 of the GNU GPL 126 | for conveying Corresponding Source.) 127 | 128 | 5. Combined Libraries. 129 | 130 | You may place library facilities that are a work based on the 131 | Library side by side in a single library together with other library 132 | facilities that are not Applications and are not covered by this 133 | License, and convey such a combined library under terms of your 134 | choice, if you do both of the following: 135 | 136 | a) Accompany the combined library with a copy of the same work based 137 | on the Library, uncombined with any other library facilities, 138 | conveyed under the terms of this License. 139 | 140 | b) Give prominent notice with the combined library that part of it 141 | is a work based on the Library, and explaining where to find the 142 | accompanying uncombined form of the same work. 143 | 144 | 6. Revised Versions of the GNU Lesser General Public License. 145 | 146 | The Free Software Foundation may publish revised and/or new versions 147 | of the GNU Lesser General Public License from time to time. Such new 148 | versions will be similar in spirit to the present version, but may 149 | differ in detail to address new problems or concerns. 150 | 151 | Each version is given a distinguishing version number. If the 152 | Library as you received it specifies that a certain numbered version 153 | of the GNU Lesser General Public License "or any later version" 154 | applies to it, you have the option of following the terms and 155 | conditions either of that published version or of any later version 156 | published by the Free Software Foundation. If the Library as you 157 | received it does not specify a version number of the GNU Lesser 158 | General Public License, you may choose any version of the GNU Lesser 159 | General Public License ever published by the Free Software Foundation. 160 | 161 | If the Library as you received it specifies that a proxy can decide 162 | whether future versions of the GNU Lesser General Public License shall 163 | apply, that proxy's public statement of acceptance of any version is 164 | permanent authorization for you to choose that version for the 165 | Library. 166 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | ######################################################################### 2 | # 3 | # Copyright 2011 by Sean Conner. All Rights Reserved. 4 | # 5 | # This library is free software; you can redistribute it and/or modify it 6 | # under the terms of the GNU Lesser General Public License as published by 7 | # the Free Software Foundation; either version 3 of the License, or (at your 8 | # option) any later version. 9 | # 10 | # This library is distributed in the hope that it will be useful, but 11 | # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 12 | # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public 13 | # License for more details. 14 | # 15 | # You should have received a copy of the GNU Lesser General Public License 16 | # along with this library; if not, see . 17 | # 18 | # Comments, questions and criticisms can be sent to: sean@conman.org 19 | # 20 | ######################################################################## 21 | 22 | UNAME := $(shell uname) 23 | 24 | ifeq ($(UNAME),Linux) 25 | CC = gcc -std=c99 26 | CFLAGS = -g -Wall -Wextra -pedantic -Wwrite-strings 27 | SHARED = -fPIC -shared -L/usr/local/lib 28 | LDFLAGS = -g 29 | lib/clock.so : LDLIBS = -lrt 30 | endif 31 | 32 | ifeq ($(UNAME),SunOS) 33 | CC = cc -xc99 34 | CFLAGS = -g -mt -m64 -I /usr/sfw/include 35 | SHARED = -G -xcode=pic32 36 | LDFLAGS = -g 37 | lib/net.so : LDLIBS = -lsocket -lnsl 38 | lib/clock.so : LDLIBS = -lrt 39 | endif 40 | 41 | ifeq ($(UNAME),Darwin) 42 | CC = gcc -std=c99 43 | CFLAGS = -g -Wall -Wextra -pedantic 44 | SHARED = -fPIC -bundle -undefined dynamic_lookup -all_load 45 | LDFLAGS = -g 46 | lib/iconv.so : LDLIBS = -liconv 47 | endif 48 | 49 | # =================================================== 50 | 51 | INSTALL = /usr/bin/install 52 | INSTALL_PROGRAM = $(INSTALL) 53 | INSTALL_DATA = $(INSTALL) -m 644 54 | 55 | prefix = /usr/local 56 | libdir = $(prefix)/lib 57 | datarootdir = $(prefix)/share 58 | dataroot = $(datarootdir) 59 | 60 | LUA ?= lua 61 | LUA_VERSION := $(shell $(LUA) -e "print(_VERSION:match '^Lua (.*)')") 62 | LUADIR ?= $(dataroot)/lua/$(LUA_VERSION) 63 | LIBDIR ?= $(libdir)/lua/$(LUA_VERSION) 64 | 65 | ifneq ($(LUA_INCDIR),) 66 | override CFLAGS += -I$(LUA_INCDIR) 67 | endif 68 | 69 | # =================================================== 70 | 71 | .PHONY: all clean install uninstall obsolete install-obsolete 72 | 73 | lib/%.so : src/%.c 74 | $(CC) $(CFLAGS) $(SHARED) -o $@ $< $(LDLIBS) 75 | 76 | all : lib \ 77 | lib/base64.so \ 78 | lib/clock.so \ 79 | lib/crc.so \ 80 | lib/env.so \ 81 | lib/errno.so \ 82 | lib/fsys.so \ 83 | lib/hash.so \ 84 | lib/iconv.so \ 85 | lib/lfsr.so \ 86 | lib/idn.so \ 87 | lib/magic.so \ 88 | lib/math.so \ 89 | lib/net.so \ 90 | lib/pollset.so \ 91 | lib/process.so \ 92 | lib/signal.so \ 93 | lib/strcore.so \ 94 | lib/sys.so \ 95 | lib/syslog.so \ 96 | lib/tls.so \ 97 | build/bin2c 98 | 99 | obsolete: lib lib/tcc.so 100 | 101 | build/bin2c : LDLIBS = -lz 102 | build/bin2c : build/bin2c.c 103 | 104 | lib : 105 | mkdir lib 106 | 107 | lib/hash.so : LDLIBS = -lcrypto 108 | lib/magic.so : LDLIBS = -lmagic 109 | lib/tcc.so : LDLIBS = -ltcc 110 | lib/idn.so : LDLIBS = -lidn 111 | lib/tls.so : LDLIBS = -lcrypto -ltls -lssl 112 | 113 | # =================================================== 114 | 115 | install : all 116 | $(INSTALL) -d $(DESTDIR)$(LUADIR)/org/conman 117 | $(INSTALL) -d $(DESTDIR)$(LUADIR)/org/conman/dns 118 | $(INSTALL) -d $(DESTDIR)$(LUADIR)/org/conman/zip 119 | $(INSTALL) -d $(DESTDIR)$(LUADIR)/org/conman/const 120 | $(INSTALL) -d $(DESTDIR)$(LUADIR)/org/conman/net 121 | $(INSTALL) -d $(DESTDIR)$(LUADIR)/org/conman/nfl 122 | $(INSTALL) -d $(DESTDIR)$(LIBDIR)/org/conman 123 | $(INSTALL) -d $(DESTDIR)$(LIBDIR)/org/conman/fsys 124 | $(INSTALL_PROGRAM) lib/base64.so $(DESTDIR)$(LIBDIR)/org/conman 125 | $(INSTALL_PROGRAM) lib/clock.so $(DESTDIR)$(LIBDIR)/org/conman 126 | $(INSTALL_PROGRAM) lib/crc.so $(DESTDIR)$(LIBDIR)/org/conman 127 | $(INSTALL_PROGRAM) lib/env.so $(DESTDIR)$(LIBDIR)/org/conman 128 | $(INSTALL_PROGRAM) lib/errno.so $(DESTDIR)$(LIBDIR)/org/conman 129 | $(INSTALL_PROGRAM) lib/fsys.so $(DESTDIR)$(LIBDIR)/org/conman 130 | $(INSTALL_PROGRAM) lib/hash.so $(DESTDIR)$(LIBDIR)/org/conman 131 | $(INSTALL_PROGRAM) lib/iconv.so $(DESTDIR)$(LIBDIR)/org/conman 132 | $(INSTALL_PROGRAM) lib/lfsr.so $(DESTDIR)$(LIBDIR)/org/conman 133 | $(INSTALL_PROGRAM) lib/idn.so $(DESTDIR)$(LIBDIR)/org/conman 134 | $(INSTALL_PROGRAM) lib/magic.so $(DESTDIR)$(LIBDIR)/org/conman/fsys 135 | $(INSTALL_PROGRAM) lib/math.so $(DESTDIR)$(LIBDIR)/org/conman 136 | $(INSTALL_PROGRAM) lib/net.so $(DESTDIR)$(LIBDIR)/org/conman 137 | $(INSTALL_PROGRAM) lib/pollset.so $(DESTDIR)$(LIBDIR)/org/conman 138 | $(INSTALL_PROGRAM) lib/process.so $(DESTDIR)$(LIBDIR)/org/conman 139 | $(INSTALL_PROGRAM) lib/signal.so $(DESTDIR)$(LIBDIR)/org/conman 140 | $(INSTALL_PROGRAM) lib/strcore.so $(DESTDIR)$(LIBDIR)/org/conman 141 | $(INSTALL_PROGRAM) lib/sys.so $(DESTDIR)$(LIBDIR)/org/conman 142 | $(INSTALL_PROGRAM) lib/syslog.so $(DESTDIR)$(LIBDIR)/org/conman 143 | $(INSTALL_PROGRAM) lib/tls.so $(DESTDIR)$(LIBDIR)/org/conman 144 | $(INSTALL_DATA) lua/*.lua $(DESTDIR)$(LUADIR)/org/conman 145 | $(INSTALL_DATA) lua/dns/*.lua $(DESTDIR)$(LUADIR)/org/conman/dns 146 | $(INSTALL_DATA) lua/zip/*.lua $(DESTDIR)$(LUADIR)/org/conman/zip 147 | $(INSTALL_DATA) lua/const/*.lua $(DESTDIR)$(LUADIR)/org/conman/const 148 | $(INSTALL_DATA) lua/net/*.lua $(DESTDIR)$(LUADIR)/org/conman/net 149 | $(INSTALL_DATA) lua/nfl/*.lua $(DESTDIR)$(LUADIR)/org/conman/nfl 150 | 151 | install-obsolete: obsolete 152 | $(INSTALL) -d $(DESTDIR)$(LUADIR)/org/conman 153 | $(INSTALL) -d $(DESTDIR)$(LIBDIR)/org/conman 154 | $(INSTALL_PROGRAM) lib/tcc.so $(DESTDIR)$(LIBDIR)/org/conman 155 | $(INSTALL_DATA) lua/cc.lua $(DESTDIR)$(LUADIR)/org/conman 156 | 157 | uninstall: 158 | $(RM) -r $(DESTDIR)$(LIBDIR)/org/conman 159 | $(RM) -r $(DESTDIR)$(LUADIR)/org/conman 160 | 161 | clean: 162 | $(RM) $(shell find . -name '*~') 163 | $(RM) -r lib/* 164 | $(RM) build/bin2c 165 | $(RM) -r $(shell find . -name '*.dSYM') 166 | -------------------------------------------------------------------------------- /README: -------------------------------------------------------------------------------- 1 | 2 | This is a collection of Lua 5.1 .. 5.4 modules I've written. Yes, they 3 | include functionality found in other Lua modules like luasockets and 4 | luaposix. I wrote these not to reinvent the wheel (although I did) but to 5 | learn how to program in Lua. As such, I do find these modules useful and 6 | actually prefer them to such modules as luasockets and luaposix. 7 | 8 | Now, because of the functionality overlap of some of these modules with 9 | existing Lua modules, I decided to place them under a name that I know won't 10 | conflict with existing modules. I took a play out of the Java playbook and 11 | placed all these modules under the "org.conman" table. 12 | 13 | * * * * * 14 | 15 | MODULES AS LUAROCKS 16 | 17 | org.conman.const.exit (Lua) 18 | A table of standardize exit values. 19 | 20 | org.conman.const.gopher-types (Lua) 21 | A table mapping Gopher resource types (RFC-1436) to human 22 | readable types and back again. 23 | 24 | org.conman.env (C) 25 | A table containing all environtment variables. 26 | 27 | org.conman.errno (C) 28 | A table containing defined error codes from C and POSIX. 29 | 30 | org.conman.iconv (C) 31 | A wrapper for the GNU iconv library. 32 | 33 | org.conman.syslog (C) 34 | A wrapper for the syslog logging system. 35 | 36 | org.conman.tls (C) 37 | A wrapper for libtls from libressl, or libretls for OpenSSL. 38 | 39 | * * * * * 40 | 41 | MODULES IN C 42 | 43 | org.conman.base64 44 | Conversion routines to and from various formulations of Base-64 45 | 46 | org.conman.clock 47 | A POSIX timers interface. 48 | 49 | org.conman.fsys 50 | A module of POSIX functions releated to filesystems. 51 | 52 | org.conman.hash 53 | A module of standard hash functions as provided by libcrypto. 54 | 55 | org.conman.lfsr 56 | A function to generate 8, 16 or 32 bit linear feedback shift 57 | registers. 58 | 59 | org.conman.fsys.magic 60 | A wrapper around the GNU magic (file types) database. 61 | 62 | org.conman.net 63 | A module to wrap BSD/POSIX sockets programming. This supports 64 | IPv4, IPv6 and Unix sockets. 65 | 66 | org.conman.pollset 67 | A wrapper around the POSIX select() call, POSIX poll() call, the 68 | Linux epoll() call and the Mac OS-X kqueue() call, with the same 69 | API. 70 | 71 | org.conman.process 72 | A module of POSIX functions related to processes. 73 | 74 | org.conman.signal 75 | A wrapper around the ANSI signal() function, or the POSIX signal 76 | functions. 77 | 78 | org.conman.strcore 79 | Some functions working with strings written in C. 80 | 81 | org.conman.sys 82 | A table of various POSIX system dependent values. 83 | 84 | * * * * * 85 | MODULES IN LUA 86 | 87 | Modules written in Lua: 88 | 89 | org.conman.const.entity 90 | A table of HTML entities with their UTF-8 equivilents. 91 | 92 | org.conman.const.http-response 93 | A table of HTTP response codes. 94 | 95 | org.conman.date 96 | A module of some date related functions. 97 | 98 | org.conman.debug 99 | A module of some debug related functions. 100 | 101 | org.conman.getopt 102 | A module to handle parsing the command line. 103 | 104 | org.conman.mailcap 105 | A wrapper around the mailcap facility found on Unix systems. 106 | 107 | org.conman.string 108 | Some useful string functions (includes org.conman.strcore). 109 | 110 | org.conman.table 111 | Some useful table functions. 112 | 113 | org.conman.net.ios 114 | Implements an API similar to the Lua's file object API, but with 115 | callbacks to obtain the data. 116 | 117 | org.conman.net.tcp 118 | A module to turn a TCP connection into something that mimics the 119 | Lua's file:read()/file:write()/etc. API. 120 | 121 | org.conman.net.tls 122 | A module, with the API as org.conman.net.tcp, to manage TLS based 123 | connections. 124 | 125 | org.conman.nfl 126 | An event driven framework to manage network based connections via 127 | coroutines. 128 | 129 | org.conman.nfl.tcp 130 | A module, with a similar API to org.conman.net.tcp, to manage 131 | TCP connections via coroutines in an event driven environment. 132 | 133 | org.conman.nfl.tls 134 | A module, with a similar API to org.conman.net.tcp, to manage 135 | TLS-based connections via coroutines in an event driven environment. 136 | 137 | * * * * * 138 | 139 | Any modules found in this repository not listed above are either obsolete or 140 | experimental and should probably not be used. 141 | -------------------------------------------------------------------------------- /build/bin2c.c: -------------------------------------------------------------------------------- 1 | /*************************************************************************** 2 | * 3 | * Copyright 2011 by Sean Conner. 4 | * 5 | * This library is free software; you can redistribute it and/or modify it 6 | * under the terms of the GNU Lesser General Public License as published by 7 | * the Free Software Foundation; either version 3 of the License, or (at your 8 | * option) any later version. 9 | * 10 | * This library is distributed in the hope that it will be useful, but 11 | * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 12 | * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public 13 | * License for more details. 14 | * 15 | * You should have received a copy of the GNU Lesser General Public License 16 | * along with this library; if not, see . 17 | * 18 | * Comments, questions and criticisms can be sent to: sean@conman.org 19 | * 20 | *************************************************************************/ 21 | 22 | #define _GNU_SOURCE 23 | 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | 30 | #include 31 | #include 32 | 33 | extern char *optarg; 34 | extern int optind; 35 | extern int opterr; 36 | 37 | /*************************************************************************/ 38 | 39 | int load_file( 40 | const char *const fname, 41 | unsigned char **pdata, 42 | size_t *const psize 43 | ) 44 | { 45 | FILE *fp; 46 | long size; 47 | unsigned char *data; 48 | 49 | assert(fname != NULL); 50 | assert(pdata != NULL); 51 | assert(psize != NULL); 52 | 53 | *pdata = NULL; 54 | *psize = 0; 55 | 56 | fp = fopen(fname,"rb"); 57 | if (fp == NULL) 58 | return errno; 59 | 60 | if (fseek(fp,0,SEEK_END) < 0) 61 | { 62 | int err = errno; 63 | fclose(fp); 64 | return err; 65 | } 66 | 67 | size = ftell(fp); 68 | if (size == -1) 69 | { 70 | int err = errno; 71 | fclose(fp); 72 | return err; 73 | } 74 | 75 | if (fseek(fp,0,SEEK_SET) < 0) 76 | { 77 | int err = errno; 78 | fclose(fp); 79 | return err; 80 | } 81 | 82 | data = malloc(size); 83 | if (data == NULL) 84 | { 85 | int err = errno; 86 | fclose(fp); 87 | return err; 88 | } 89 | 90 | *psize = size; 91 | *pdata = data; 92 | 93 | fread(data,1,size,fp); 94 | 95 | fclose(fp); 96 | return 0; 97 | } 98 | 99 | /*************************************************************************/ 100 | 101 | int compress_data( 102 | const int level, 103 | unsigned char **pdata, 104 | const size_t size, 105 | size_t *newsize 106 | ) 107 | { 108 | z_stream sout; 109 | Bytef *buffer; 110 | int rc; 111 | 112 | if (level == 0) 113 | { 114 | *newsize = size; 115 | return 0; 116 | } 117 | 118 | buffer = malloc(size); 119 | if (buffer == NULL) 120 | return ENOMEM; 121 | 122 | sout.zalloc = Z_NULL; 123 | sout.zfree = Z_NULL; 124 | sout.opaque = NULL; 125 | rc = deflateInit(&sout,level); 126 | 127 | if (rc != Z_OK) 128 | { 129 | free(buffer); 130 | return EINVAL; 131 | } 132 | 133 | sout.next_in = (Bytef *)*pdata; 134 | sout.avail_in = size; 135 | sout.next_out = buffer; 136 | sout.avail_out = size; 137 | 138 | deflate(&sout,Z_FINISH); 139 | deflateEnd(&sout); 140 | 141 | free(*pdata); 142 | *pdata = (unsigned char *)buffer; 143 | *newsize = size - sout.avail_out; 144 | return 0; 145 | } 146 | 147 | /*************************************************************************/ 148 | 149 | void process( 150 | FILE *fpout, 151 | const unsigned char *data, 152 | const size_t size, 153 | const size_t ucsize, 154 | const char *tag 155 | ) 156 | { 157 | int cnt = 8; 158 | 159 | fprintf( 160 | fpout, 161 | "#include \n" 162 | "const unsigned char c_%s[] =\n" 163 | "{" 164 | "", 165 | tag 166 | ); 167 | 168 | for (size_t i = 0 ; i < size ; i++) 169 | { 170 | if (cnt == 8) 171 | { 172 | fputs("\n ",fpout); 173 | cnt = 0; 174 | } 175 | 176 | fprintf(fpout,"0x%02X , ",data[i]); 177 | cnt++; 178 | } 179 | 180 | fprintf( 181 | fpout, 182 | "\n};\n\nconst size_t c_%s_size = %lu;\n", 183 | tag, 184 | (unsigned long)size 185 | ); 186 | 187 | if (size != ucsize) 188 | { 189 | fprintf( 190 | fpout, 191 | "const size_t c_%s_ucsize = %lu;\n", 192 | tag, 193 | (unsigned long)ucsize 194 | ); 195 | } 196 | } 197 | 198 | /**************************************************************************/ 199 | 200 | int main(int argc,char *argv[]) 201 | { 202 | FILE *fpout; 203 | char const *tag; 204 | int c; 205 | int level; 206 | 207 | fpout = stdout; 208 | tag = "data"; 209 | level = 0; 210 | 211 | while((c = getopt(argc,argv,"o:t:hz0123456789")) != EOF) 212 | { 213 | switch(c) 214 | { 215 | default: 216 | case 'h': 217 | fprintf(stderr,"usage: %s [-o output] [-t tag] [-z] [-h] files... \n",argv[0]); 218 | return EXIT_FAILURE; 219 | case 't': 220 | tag = optarg; 221 | for ( ; *optarg ; optarg++) 222 | { 223 | if (*optarg == '-') 224 | *optarg = '_'; 225 | else if (*optarg == '.') 226 | *optarg = '_'; 227 | } 228 | break; 229 | 230 | case 'o': 231 | fpout = fopen(optarg,"wb"); 232 | if (fpout == NULL) 233 | { 234 | perror(optarg); 235 | exit(EXIT_FAILURE); 236 | } 237 | break; 238 | case 'z': 239 | level = Z_DEFAULT_COMPRESSION; 240 | break; 241 | 242 | case '0': 243 | case '1': 244 | case '2': 245 | case '3': 246 | case '4': 247 | case '5': 248 | case '6': 249 | case '7': 250 | case '8': 251 | case '9': 252 | level = c - '0'; 253 | break; 254 | } 255 | } 256 | 257 | if (optind == argc) 258 | { 259 | fprintf(stderr,"usage: %s [-o output] [-t tag] [-z] [-h] files... \n",argv[0]); 260 | return EXIT_FAILURE; 261 | } 262 | else 263 | { 264 | for (int i = optind ; i < argc ; i++) 265 | { 266 | unsigned char *data; 267 | size_t datasize; 268 | size_t realdatasize; 269 | int rc; 270 | 271 | rc = load_file(argv[i],&data,&realdatasize); 272 | if (rc != 0) 273 | { 274 | fprintf(stderr,"%s: %s\n",argv[i],strerror(rc)); 275 | free(data); 276 | return EXIT_FAILURE; 277 | } 278 | 279 | rc = compress_data(level,&data,realdatasize,&datasize); 280 | if (rc != 0) 281 | { 282 | fprintf(stderr,"%s: %s\n",argv[1],strerror(rc)); 283 | free(data); 284 | return EXIT_FAILURE; 285 | } 286 | 287 | process(fpout,data,datasize,realdatasize,tag); 288 | free(data); 289 | } 290 | } 291 | 292 | return EXIT_SUCCESS; 293 | } 294 | -------------------------------------------------------------------------------- /lua/cc.lua: -------------------------------------------------------------------------------- 1 | -- *************************************************************** 2 | -- 3 | -- Copyright 2012 by Sean Conner. All Rights Reserved. 4 | -- 5 | -- This library is free software; you can redistribute it and/or modify it 6 | -- under the terms of the GNU Lesser General Public License as published by 7 | -- the Free Software Foundation; either version 3 of the License, or (at your 8 | -- option) any later version. 9 | -- 10 | -- This library is distributed in the hope that it will be useful, but 11 | -- WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 12 | -- or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public 13 | -- License for more details. 14 | -- 15 | -- You should have received a copy of the GNU Lesser General Public License 16 | -- along with this library; if not, see . 17 | -- 18 | -- Comments, questions and criticisms can be sent to: sean@conman.org 19 | -- 20 | -- ******************************************************************** 21 | -- luacheck: globals encap CACHE compile package.ccpath 22 | -- luacheck: ignore 611 23 | 24 | local _VERSION = _VERSION 25 | local tcc = require "org.conman.tcc" 26 | local package = package 27 | local table = table 28 | local os = os 29 | local io = io 30 | local string = string 31 | local pairs = pairs 32 | local setmetatable = setmetatable 33 | 34 | if _VERSION == "Lua 5.1" then 35 | module("org.conman.cc") 36 | else 37 | _ENV = {} 38 | end 39 | 40 | package.ccpath = "/usr/loca/share/lua/5.1/?.c;/usr/local/lib/lua/5.1/?.c" 41 | 42 | local DIR = package.config:sub(1,1) 43 | local SEP = package.config:sub(3,3) 44 | local MARK = package.config:sub(5,5) 45 | local IGN = package.config:sub(9,9) 46 | 47 | do 48 | local ep = os.getenv("LUA_CCPATH") 49 | if ep ~= nil then 50 | package.ccpath = ep:gsub(";;",";" .. package.ccpath .. ";") 51 | end 52 | 53 | local function loader(name) 54 | local modulefile = name:gsub("%.",DIR) 55 | local errmsg = "" 56 | local filename 57 | local file 58 | local entry 59 | local x 60 | 61 | for path in package.ccpath:gmatch("[^%" .. SEP .. "]+") do 62 | filename = path:gsub("[%" .. MARK .. "]",modulefile) 63 | file = io.open(filename) 64 | if file then break end 65 | errmsg = errmsg .. "\n\tno file '" .. filename .. "'" 66 | end 67 | 68 | if not file then 69 | return errmsg 70 | end 71 | 72 | file:close() 73 | 74 | local _,l = name:find(IGN,1,true) 75 | if l then 76 | entry = "luaopen_" .. name:sub(l + 1,-1):gsub("%.","_") 77 | else 78 | entry = "luaopen_" .. name:gsub("%.","_") 79 | end 80 | 81 | -- --------------------------------------------------------------------- 82 | -- Why not use compile() for this? Because that caches the memory blob 83 | -- returned from relocate() via the symbol we pulled out. Lua modules 84 | -- only use this function once, then it's not used, and thus, the module 85 | -- we just loaded stands a chance of being flushed out of memory, 86 | -- causing issues. 87 | -- 88 | -- Doing it this way, we avoid that problem. We still have the problem 89 | -- if the module is removed from package.loaded{} and reloaded, which 90 | -- will cause a memory leak, but that scenario is probably very rare. 91 | -- I'm willing to live with this for now. 92 | -- --------------------------------------------------------------------- 93 | 94 | x = tcc.new() 95 | x:define("LUA_REQUIRE","1") 96 | x:output_type('memory') 97 | if x:compile(filename,true,function(msg) 98 | errmsg = errmsg .. "\n\t" .. msg 99 | end) 100 | then 101 | local blob = x:relocate() 102 | local f = x:get_symbol(entry) 103 | if f then 104 | return f 105 | end 106 | tcc.dispose(blob) 107 | errmsg = errmsg 108 | .. string.format("\n\tno entry '%s' in file '%s'",entry,filename) 109 | return errmsg 110 | end 111 | 112 | return errmsg 113 | end 114 | if _VERSION == "Lua 5.1" then 115 | table.insert(package.loaders,#package.loaders,loader) 116 | else 117 | table.insert(package.searchers,#package.searchers,loader) 118 | end 119 | end 120 | 121 | -- ******************************************************************** 122 | 123 | do 124 | local code = [[ 125 | 126 | #include 127 | 128 | #include 129 | #include 130 | #include 131 | 132 | #define CC_TYPE "CC:type" 133 | 134 | struct cclua 135 | { 136 | void *data; 137 | }; 138 | 139 | int cclua___tostring(lua_State *L) 140 | { 141 | lua_pushfstring(L,"CC:%p",luaL_checkudata(L,1,CC_TYPE)); 142 | return 1; 143 | } 144 | 145 | int cclua___gc(lua_State *L) 146 | { 147 | struct cclua *obj = luaL_checkudata(L,1,CC_TYPE); 148 | luaL_getmetafield(L,1,"dispose"); 149 | 150 | lua_pushlightuserdata(L,obj->data); 151 | lua_call(L,1,0); 152 | syslog(LOG_DEBUG,"garbage collect some C code"); 153 | 154 | return 0; 155 | } 156 | 157 | int cclua_encap(lua_State *L) 158 | { 159 | struct cclua *obj; 160 | 161 | luaL_checktype(L,1,LUA_TLIGHTUSERDATA); 162 | obj = lua_newuserdata(L,sizeof(struct cclua)); 163 | obj->data = lua_touserdata(L,1); 164 | luaL_getmetatable(L,CC_TYPE); 165 | lua_setmetatable(L,-2); 166 | return 1; 167 | } 168 | 169 | const struct luaL_Reg mcc_meta[] = 170 | { 171 | { "__tostring" , cclua___tostring } , 172 | { "__gc" , cclua___gc } , 173 | { NULL , NULL } 174 | }; 175 | 176 | int luaopen_cc(lua_State *L) 177 | { 178 | luaL_newmetatable(L,CC_TYPE); 179 | luaL_register(L,NULL,mcc_meta); 180 | lua_pushvalue(L,-1); 181 | lua_setfield(L,-2,"__index"); 182 | lua_pushvalue(L,-1); 183 | lua_setfield(L,-2,"__newindex"); 184 | 185 | if (lua_isfunction(L,1)) 186 | { 187 | lua_pushvalue(L,1); 188 | lua_setfield(L,-2,"dispose"); 189 | } 190 | 191 | lua_pushcfunction(L,cclua_encap); 192 | return 1; 193 | } 194 | ]] 195 | 196 | local x = tcc.new() 197 | x:output_type('memory') 198 | x:compile(code) 199 | x:relocate() 200 | local init = x:get_symbol('luaopen_cc') 201 | encap = init(tcc.dispose) 202 | end 203 | 204 | -- ********************************************************************** 205 | 206 | CACHE = setmetatable( {} , { __mode = "k" }) 207 | 208 | function compile(fname,code,isfile,defines) 209 | defines = defines or {} 210 | local x = tcc.new() 211 | 212 | for def,val in pairs(defines) do 213 | x:define(def,val) 214 | end 215 | x:output_type('memory') 216 | 217 | if not x:compile(code,isfile) then 218 | return nil 219 | end 220 | 221 | local blob = x:relocate() 222 | local f = x:get_symbol(fname) 223 | 224 | if f then 225 | CACHE[f] = encap(blob) 226 | return f,blob 227 | end 228 | 229 | return nil 230 | end 231 | 232 | if _VERSION >= "Lua 5.2" then 233 | return _ENV 234 | end 235 | -------------------------------------------------------------------------------- /lua/const/exit.lua: -------------------------------------------------------------------------------- 1 | -- ************************************************************************ 2 | -- 3 | -- Copyright 2018 by Sean Conner. All Rights Reserved. 4 | -- 5 | -- This library is free software; you can redistribute it and/or modify it 6 | -- under the terms of the GNU Lesser General Public License as published by 7 | -- the Free Software Foundation; either version 3 of the License, or (at your 8 | -- option) any later version. 9 | -- 10 | -- This library is distributed in the hope that it will be useful, but 11 | -- WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 12 | -- or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public 13 | -- License for more details. 14 | -- 15 | -- You should have received a copy of the GNU Lesser General Public License 16 | -- along with this library; if not, see . 17 | -- 18 | -- Comments, questions and criticisms can be sent to: sean@conman.org 19 | -- 20 | -- ************************************************************************ 21 | -- luacheck: ignore 611 22 | 23 | return { 24 | -- -------------------------------------------------------- 25 | -- The following are defined by Standard C 26 | -- -------------------------------------------------------- 27 | 28 | SUCCESS = 0, -- standard C exit code 29 | FAILURE = 1, -- standard C exit code 30 | 31 | -- ----------------------------------------------------- 32 | -- The following are defined by the LSB 33 | -- https://refspecs.linuxbase.org/LSB_5.0.0/LSB-Core-generic/LSB-Core-generic/iniscrptact.html 34 | -- ----------------------------------------------------- 35 | 36 | GENERIC_UNSPECIFIED = 1, -- same as standard C exit code 37 | INVALIDARGUMENT = 2, -- invalid or excess argumetns 38 | NOTIMPLEMENTED = 3, -- unimplemented feature 39 | NOPERMISSION = 4, -- the user has insufficient priviledges 40 | NOTINSTALLED = 5, -- the program is not installed 41 | NOTCONFIGURED = 6, -- the program is not configured 42 | NOTRUNNING = 7, -- the program is not running 43 | 44 | -- ------------------------------------------------------------------------ 45 | -- The following are defined by BSD, and usually found in C via 46 | -- ------------------------------------------------------------------------ 47 | 48 | OK = 0, -- successful termination 49 | USAGE = 64, -- command line usage error 50 | DATAERR = 65, -- data format error 51 | NOINPUT = 66, -- cannot open input 52 | NOUSER = 67, -- addressee unknown 53 | NOHOST = 68, -- host name unknown 54 | UNAVAILABLE = 69, -- service unavailable 55 | SOFTWARE = 70, -- internal software error 56 | OSERR = 71, -- system error (e.g., can't fork) 57 | OSFILE = 72, -- critical OS file missing 58 | CANTCREAT = 73, -- can't create (user) output file 59 | IOERR = 74, -- input/output error 60 | TEMPFAIL = 75, -- temp failure; user is invited to retry 61 | PROTOCOL = 76, -- remote error in protocol 62 | NOPERM = 77, -- permission denied 63 | CONFIG = 78, -- configuration error 64 | NOTFOUND = 79, -- required file not found 65 | 66 | -- ------------------------------------------------------------------- 67 | -- The following are defined by systemd 68 | -- https://www.freedesktop.org/software/systemd/man/systemd.exec.html 69 | -- ------------------------------------------------------------------- 70 | 71 | CHDIR = 200, -- Changing to the requested working directory failed. 72 | NICE = 201, -- Failed to set up process scheduling priority (nice level). 73 | FDS = 202, -- Failed to close unwanted file descriptors, or to adjust passed file descriptors. 74 | EXEC = 203, -- The actual process execution failed (specifically, the execve(2) system call). 75 | MEMORY = 204, -- Failed to perform an action due to memory shortage. 76 | LIMITS = 205, -- Failed to adjust resource limits. 77 | OOM_ADJUST = 206, -- Failed to adjust the OOM setting. 78 | SIGNAL_MASK = 207, -- Failed to set process signal mask. 79 | STDIN = 208, -- Failed to set up standard input. 80 | STDOUT = 209, -- Failed to set up standard output. 81 | CHROOT = 210, -- Failed to change root directory (chroot(2)). 82 | IOPRIO = 211, -- Failed to set up IO scheduling priority. 83 | TIMERSLACK = 212, -- Failed to set up timer slack. 84 | SECUREBITS = 213, -- Failed to set process secure bits. 85 | SETSCHEDULER = 214, -- Failed to set up CPU scheduling. 86 | CPUAFFINITY = 215, -- Failed to set up CPU affinity. 87 | GROUP = 216, -- Failed to determine or change group credentials. 88 | USER = 217, -- Failed to determine or change user credentials, or to set up user namespacing. 89 | CAPABILITIES = 218, -- Failed to drop capabilities, or apply ambient capabilities. 90 | CGROUP = 219, -- Setting up the service control group failed. 91 | SETSID = 220, -- Failed to create new process session. 92 | CONFIRM = 221, -- Execution has been cancelled by the user. 93 | STDERR = 222, -- Failed to set up standard error output. 94 | -- 223 not defined 95 | PAM = 224, -- Failed to set up PAM session. 96 | NETWORK = 225, -- Failed to set up network namespacing. 97 | NAMESPACE = 226, -- Failed to set up mount, UTS, or IPC namespacing. 98 | NO_NEW_PRIVILEDGES = 227, -- Failed to disable new privileges. 99 | SECCOMP = 228, -- Failed to apply system call filters. 100 | SELINUX_CONTEXT = 229, -- Determining or changing SELinux context failed. 101 | PERSONALITY = 230, -- Failed to set up an execution domain (personality). 102 | APPARMOR_PROFILE = 231, -- Failed to prepare changing AppArmor profile. 103 | ADDRESS_FAMILIES = 232, -- Failed to restrict address families. 104 | RUNTIME_DIRECTORY = 233, -- Setting up runtime directory failed. 105 | -- 234 not defined 106 | CHOWN = 235, -- Failed to adjust socket ownership. 107 | SMACK_PROCESS_LABEL = 236, -- Failed to set SMACK label. 108 | KEYRING = 237, -- Failed to set up kernel keyring. 109 | STATE_DIRECTORY = 238, -- Failed to set up unit's state directory. 110 | CACHE_DIRECTORY = 239, -- Failed to set up unit's cache directory. 111 | LOGS_DIRECTORY = 240, -- Failed to set up unit's logging directory. 112 | CONFIGURATION_DIRECTORY = 241, -- Failed to set up unit's configuration directory. 113 | NUMA_POLICY = 242, -- Failed to set up unit's NUMA memory policy. 114 | CREDENTIALS = 243, -- Failed to set up unit's credentials. 115 | -- 244 not defined 116 | BPF = 245, -- Failed to apply BPF restrictions. 117 | } 118 | -------------------------------------------------------------------------------- /lua/const/gopher-types.lua: -------------------------------------------------------------------------------- 1 | -- ************************************************************************ 2 | -- 3 | -- Copyright 2018 by Sean Conner. All Rights Reserved. 4 | -- 5 | -- This library is free software; you can redistribute it and/or modify it 6 | -- under the terms of the GNU Lesser General Public License as published by 7 | -- the Free Software Foundation; either version 3 of the License, or (at your 8 | -- option) any later version. 9 | -- 10 | -- This library is distributed in the hope that it will be useful, but 11 | -- WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 12 | -- or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public 13 | -- License for more details. 14 | -- 15 | -- You should have received a copy of the GNU Lesser General Public License 16 | -- along with this library; if not, see . 17 | -- 18 | -- Comments, questions and criticisms can be sent to: sean@conman.org 19 | -- 20 | -- ************************************************************************ 21 | -- luacheck: ignore 611 22 | 23 | return setmetatable( 24 | { 25 | ['0'] = 'file', -- RFC-1436 26 | ['1'] = 'dir', 27 | ['2'] = 'CSO', 28 | ['3'] = 'error', 29 | ['4'] = 'binhex', 30 | ['5'] = 'EXE', 31 | ['6'] = 'uuencode', 32 | ['7'] = 'search', 33 | ['8'] = 'telnet', 34 | ['9'] = 'binary', 35 | ['+'] = 'server', 36 | ['T'] = 'tn3270', 37 | ['g'] = 'gif', 38 | ['I'] = 'image', 39 | ['i'] = 'info', -- extensions 40 | ['c'] = 'calendar', 41 | ['d'] = 'worddoc', 42 | ['h'] = 'html', 43 | ['P'] = 'PDF', 44 | ['m'] = 'mail', 45 | ['M'] = 'MIME', 46 | ['s'] = 'sound', 47 | ['x'] = 'xml', 48 | ['p'] = 'png', 49 | [';'] = 'video', 50 | 51 | file = '0', 52 | dir = '1', 53 | CSO = '2', 54 | error = '3', 55 | binhex = '4', 56 | EXE = '5', 57 | uuencode = '6', 58 | search = '7', 59 | telnet = '8', 60 | binary = '9', 61 | server = '+', 62 | tn3270 = 'T', 63 | gif = 'g', 64 | image = 'I', 65 | info = 'i', 66 | calendar = 'c', 67 | worddoc = 'd', 68 | html = 'h', 69 | png = 'p', 70 | mail = 'm', 71 | sound = 's', 72 | xml = 'x', 73 | PDF = 'P', 74 | MIME = 'M', 75 | video = ';', 76 | }, 77 | { 78 | __index = function(_,key) return key end 79 | } 80 | ) 81 | -------------------------------------------------------------------------------- /lua/const/http-response.lua: -------------------------------------------------------------------------------- 1 | -- ************************************************************************ 2 | -- 3 | -- Copyright 2018 by Sean Conner. All Rights Reserved. 4 | -- 5 | -- This library is free software; you can redistribute it and/or modify it 6 | -- under the terms of the GNU Lesser General Public License as published by 7 | -- the Free Software Foundation; either version 3 of the License, or (at your 8 | -- option) any later version. 9 | -- 10 | -- This library is distributed in the hope that it will be useful, but 11 | -- WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 12 | -- or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public 13 | -- License for more details. 14 | -- 15 | -- You should have received a copy of the GNU Lesser General Public License 16 | -- along with this library; if not, see . 17 | -- 18 | -- Comments, questions and criticisms can be sent to: sean@conman.org 19 | -- 20 | -- ************************************************************************ 21 | -- luacheck: ignore 611 22 | -- https://www.iana.org/assignments/http-status-codes/http-status-codes.xhtml 23 | -- HTTP/1.0 RFC-1945 24 | -- HTTP/1.1 RFC-7235 RFC-7233 RFC-7232 RFC-7231 RFC-2616 RFC-2068 25 | -- HTTP/1.1-2.0 RFC-9110 26 | 27 | return { 28 | PROCESS = 29 | { 30 | CONTINUE = 100, -- RFC-9110 RFC-7231 RFC-2616 RFC-2068 31 | SWITCHPROTO = 101, -- RFC-9110 RFC-7231 RFC-2616 RFC-2068 32 | PROCESSING = 102, -- RFC-2518 33 | EARLYHINTS = 103, -- RFC-8297 34 | }, 35 | 36 | SUCCESS = 37 | { 38 | OKAY = 200, -- RFC-9110 RFC-7231 RFC-2616 RFC-2068 RFC-1945 39 | CREATED = 201, -- RFC-9110 RFC-7231 RFC-2616 RFC-2068 RFC-1945 40 | ACCEPTED = 202, -- RFC-9110 RFC-7231 RFC-2616 RFC-2068 RFC-1945 41 | NOAUTH = 203, -- RFC-9110 RFC-7231 RFC-2616 RFC-2068 42 | NOCONTENT = 204, -- RFC-9110 RFC-7231 RFC-2616 RFC-2068 RFC-1945 43 | RESETCONTENT = 205, -- RFC-9110 RFC-7231 RFC-2616 RFC-2068 44 | PARTIALCONTENT = 206, -- RFC-9110 RFC-7233 RFC-2616 RFC-2068 45 | MULTISTATUS = 207, -- RFC-4918 46 | ALREADYREPORTED = 208, -- RFC-5842 47 | IMUSED = 226, -- RFC-3229 48 | }, 49 | 50 | REDIRECT = 51 | { 52 | MULTICHOICE = 300, -- RFC-9110 RFC-7231 RFC-2616 RFC-2068 RFC-1945 53 | MOVEPERM = 301, -- RFC-9110 RFC-7231 RFC-2616 RFC-2068 RFC-1945 54 | MOVETEMP = 302, -- RFC-9110 RFC-7231 RFC-2616 RFC-2068 RFC-1945 55 | SEEOTHER = 303, -- RFC-9110 RFC-7231 RFC-2616 RFC-2068 56 | NOTMODIFIED = 304, -- RFC-9110 RFC-7232 RFC-2616 RFC-2068 RFC-1945 57 | USEPROXY = 305, -- RFC-9110 RFC-7231 RFC-2616 RFC-2068 58 | MOVETEMP_M = 307, -- RFC-9110 RFC-7231 RFC-2616 59 | MOVEPERM_M = 308, -- RFC-9110 RFC-7538 RFC-7238 60 | }, 61 | 62 | CLIENT = 63 | { 64 | BADREQ = 400, -- RFC-9110 RFC-7231 RFC-2616 RFC-2068 RFC-1945 65 | UNAUTHORIZED = 401, -- RFC-9110 RFC-7235 RFC-2616 RFC-2068 RFC-1945 66 | PAYMENTREQUIRED = 402, -- RFC-9110 RFC-7231 RFC-2616 RFC-2068 67 | FORBIDDEN = 403, -- RFC-9110 RFC-7231 RFC-2616 RFC-2068 RFC-1945 68 | NOTFOUND = 404, -- RFC-9110 RFC-7231 RFC-2616 RFC-2068 RFC-1945 69 | METHODNOTALLOWED = 405, -- RFC-9110 RFC-7231 RFC-2616 RFC-2068 70 | NOTACCEPTABLE = 406, -- RFC-9110 RFC-7231 RFC-2616 RFC-2068 71 | PROXYAUTHREQ = 407, -- RFC-9110 RFC-7235 RFC-2616 RFC-2068 72 | TIMEOUT = 408, -- RFC-9110 RFC-7231 RFC-2616 RFC-2068 73 | CONFLICT = 409, -- RFC-9110 RFC-7231 RFC-2616 RFC-2068 74 | GONE = 410, -- RFC-9110 RFC-7231 RFC-2616 RFC-2068 75 | LENGTHREQ = 411, -- RFC-9110 RFC-7231 RFC-2616 RFC-2068 76 | PRECONDITION = 412, -- RFC-9110 RFC-7232 RFC-2616 RFC-2068 77 | TOOLARGE = 413, -- RFC-9110 RFC-7231 RFC-2616 RFC-2068 78 | URITOOLONG = 414, -- RFC-9110 RFC-7231 RFC-2616 RFC-2068 79 | MEDIATYPE = 415, -- RFC-9110 RFC-7231 RFC-2616 RFC-2068 80 | RANGEERROR = 416, -- RFC-9110 RFC-7233 RFC-2616 81 | EXPECTATION = 417, -- RFC-9110 RFC-7231 RFC-2616 82 | IM_A_TEA_POT = 418, -- RFC-2324 section 2.3.2 83 | MISDIRECT = 421, -- RFC-9110 84 | UNPROCESSENTITY = 422, -- RFC-9110 85 | LOCKED = 423, -- RFC-4918 86 | FAILEDDEP = 424, -- RFC-4918 87 | TOOEARLY = 425, -- RFC-8470 88 | UPGRADE = 426, -- RFC-9110 RFC-7231 89 | PRECONDITION2 = 428, -- RFC-6585 90 | TOOMANYREQUESTS = 429, -- RFC-6585 91 | REQHDR2BIG = 431, -- RFC-6585 92 | LEGALCENSOR = 451, -- RFC-7725 93 | }, 94 | 95 | SERVER = 96 | { 97 | INTERNALERR = 500, -- RFC-9110 RFC-7231 RFC-2616 RFC-2068 RFC-1945 98 | NOTIMP = 501, -- RFC-9110 RFC-7231 RFC-2616 RFC-2068 RFC-1945 99 | BADGATEWAY = 502, -- RFC-9110 RFC-7231 RFC-2616 RFC-2068 RFC-1945 100 | NOSERVICE = 503, -- RFC-9110 RFC-7231 RFC-2616 RFC-2068 101 | GATEWAYTIMEOUT = 504, -- RFC-9110 RFC-7231 RFC-2616 RFC-2068 102 | HTTPVERSION = 505, -- RFC-9110 RFC-7231 RFC-2616 RFC-2068 103 | VARIANTALSO = 506, -- RFC-2295 104 | ENOSPC = 507, -- RFC-4918 105 | LOOP = 508, -- RFC-5842 106 | EXCEEDBW = 509, -- ? 107 | NOTEXTENDED = 510, -- RFC-2774 (obsolete) 108 | NETAUTHREQ = 511, -- RFC-6585 109 | } 110 | } 111 | -------------------------------------------------------------------------------- /lua/date.lua: -------------------------------------------------------------------------------- 1 | -- *************************************************************** 2 | -- 3 | -- Copyright 2012 by Sean Conner. All Rights Reserved. 4 | -- 5 | -- This library is free software; you can redistribute it and/or modify it 6 | -- under the terms of the GNU Lesser General Public License as published by 7 | -- the Free Software Foundation; either version 3 of the License, or (at your 8 | -- option) any later version. 9 | -- 10 | -- This library is distributed in the hope that it will be useful, but 11 | -- WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 12 | -- or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public 13 | -- License for more details. 14 | -- 15 | -- You should have received a copy of the GNU Lesser General Public License 16 | -- along with this library; if not, see . 17 | -- 18 | -- Comments, questions and criticisms can be sent to: sean@conman.org 19 | -- 20 | -- ******************************************************************** 21 | -- luacheck: globals tojulianday fromjulianday dayofweek daysinmonth 22 | -- luacheck: ignore 611 23 | 24 | local _VERSION = _VERSION 25 | local floor = math.floor 26 | local os = os 27 | 28 | if _VERSION == "Lua 5.1" then 29 | module("org.conman.date") 30 | else 31 | _ENV = {} 32 | end 33 | 34 | -- ********************************************************************* 35 | -- 36 | -- Usage: day = date.tojulianday([date]) 37 | -- 38 | -- Desc: Convert a date to a Julian day. 39 | -- 40 | -- Input: date (table/optional) given date or current date 41 | -- * year = 1999 42 | -- * month = 1..12 43 | -- * day = 1 .. 31 44 | -- 45 | -- Return: day (number) Julian day 46 | -- 47 | -- ********************************************************************* 48 | 49 | function tojulianday(date) 50 | date = date or os.date("*t") 51 | 52 | local a = floor((14 - date.month) / 12) 53 | local y = date.year + 4800 - a 54 | local m = date.month + 12 * a - 3 55 | 56 | return date.day 57 | + floor((153 * m + 2) / 5) 58 | + y * 365 59 | + floor(y / 4) 60 | - floor(y / 100) 61 | + floor(y / 400) 62 | - 32045 63 | end 64 | 65 | -- ********************************************************************** 66 | -- 67 | -- Usage: date = date.fromjulianday(day) 68 | -- 69 | -- Desc: Convert a Julian day to it's corresponding date 70 | -- 71 | -- Input: day (number) Julian day 72 | -- 73 | -- Return: date (table) 74 | -- * year = ... 75 | -- * month = 1 .. 12 76 | -- * day = 1 .. 31 77 | -- 78 | -- ********************************************************************* 79 | 80 | function fromjulianday(jd) 81 | local a = jd + 32044 82 | local b = floor((4 * a + 3) / 146097) 83 | local c = a - floor((b * 146097) / 4) 84 | local d = floor((4 * c + 3) / 1461) 85 | local e = c - floor((1461 * d) / 4) 86 | local m = floor((5 * e + 2) / 153) 87 | 88 | return { 89 | day = e - floor((153 * m + 2) / 5) + 1, 90 | month = m + 3 - 12 * floor((m / 10)), 91 | year = b * 100 + d - 4800 + floor(m / 10) 92 | } 93 | end 94 | 95 | -- ************************************************************************ 96 | -- 97 | -- Usage: day = date.dayofweek(date) 98 | -- 99 | -- Desc: Calculate the day of the week (1 .. 7, 1 = Sunday) of 100 | -- the given date. 101 | -- 102 | -- Input: date (table) 103 | -- * year = ... 104 | -- * month = 1 .. 12 105 | -- * day = 1 .. 31 106 | -- 107 | -- Return: day (number) 1..7, 1 = Sunday 108 | -- 109 | -- ********************************************************************* 110 | 111 | function dayofweek(date) 112 | local a = floor((14 - date.month) / 12) 113 | local y = date.year - a 114 | local m = date.month + 12 * a - 2 115 | local d = date.day 116 | + y 117 | + floor(y / 4) 118 | - floor(y / 100) 119 | + floor(y / 400) 120 | + floor(31 * m / 12) 121 | return (d % 7) + 1 122 | end 123 | 124 | -- ************************************************************************ 125 | -- 126 | -- Usage: max = day.daysinmonth(date) 127 | -- 128 | -- Desc: Calculate the maximum day in a month 129 | -- 130 | -- Input: date (table) 131 | -- * year = ... 132 | -- * month = 1 .. 12 133 | -- 134 | -- Return: max (number) 1 .. 28,29,30,31 (depends upon month) 135 | -- 136 | -- ********************************************************************* 137 | 138 | local maxdays = { 31 , 0 , 31 , 30 , 31 , 30 , 31 , 31 , 30 , 31 , 30 , 31 } 139 | 140 | function daysinmonth(date) 141 | if date.month == 2 then 142 | if date.year % 400 == 0 then return 29 143 | elseif date.year % 100 == 0 then return 28 144 | elseif date.year % 4 == 0 then return 29 145 | else return 28 end 146 | else 147 | return maxdays[date.month] 148 | end 149 | end 150 | 151 | -- ************************************************************************ 152 | 153 | if _VERSION >= "Lua 5.2" then 154 | return _ENV 155 | end 156 | -------------------------------------------------------------------------------- /lua/debug.lua: -------------------------------------------------------------------------------- 1 | -- *************************************************************** 2 | -- 3 | -- Copyright 2010 by Sean Conner. All Rights Reserved. 4 | -- 5 | -- This library is free software; you can redistribute it and/or modify it 6 | -- under the terms of the GNU Lesser General Public License as published by 7 | -- the Free Software Foundation; either version 3 of the License, or (at your 8 | -- option) any later version. 9 | -- 10 | -- This library is distributed in the hope that it will be useful, but 11 | -- WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 12 | -- or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public 13 | -- License for more details. 14 | -- 15 | -- You should have received a copy of the GNU Lesser General Public License 16 | -- along with this library; if not, see . 17 | -- 18 | -- Comments, questions and criticisms can be sent to: sean@conman.org 19 | -- 20 | -- ******************************************************************** 21 | -- luacheck: globals hexdump 22 | -- luacheck: ignore 611 23 | 24 | local io = require "io" 25 | local char = require "org.conman.parsers.ascii.char" 26 | local lpeg = require "lpeg" 27 | local _VERSION = _VERSION 28 | 29 | if _VERSION == "Lua 5.1" then 30 | module("org.conman.debug") 31 | else 32 | _ENV = {} 33 | end 34 | 35 | -- ********************************************************************* 36 | 37 | local toascii = lpeg.Cs((char + lpeg.P(1) / ".")^0) 38 | local tohex = lpeg.Cs((lpeg.P(1) / function(c) 39 | return ("%02X "):format(c:byte()) 40 | end)^0) 41 | 42 | function hexdump(bin,delta,bias,out) 43 | delta = delta or 16 44 | bias = bias or 0 45 | out = out or function(off,hex,ascii,d) 46 | io.stderr:write( 47 | ("%08X: "):format(off), 48 | hex, 49 | (" "):rep(3 * (d - (#hex / 3))), 50 | ascii, 51 | "\n" 52 | ) 53 | end 54 | 55 | local offset = 1 56 | 57 | while offset <= #bin do 58 | local s = bin:sub(offset,offset + (delta - 1)) 59 | local h = tohex:match(s) 60 | local a = toascii:match(s) 61 | 62 | out((offset - 1) + bias,h,a,delta) 63 | offset = offset + delta 64 | end 65 | end 66 | 67 | -- ******************************************************************** 68 | 69 | if _VERSION >= "Lua 5.2" then 70 | return _ENV 71 | end 72 | -------------------------------------------------------------------------------- /lua/dns/resolv.lua: -------------------------------------------------------------------------------- 1 | -- *************************************************************** 2 | -- 3 | -- Copyright 2010 by Sean Conner. All Rights Reserved. 4 | -- 5 | -- This library is free software; you can redistribute it and/or modify it 6 | -- under the terms of the GNU Lesser General Public License as published by 7 | -- the Free Software Foundation; either version 3 of the License, or (at your 8 | -- option) any later version. 9 | -- 10 | -- This library is distributed in the hope that it will be useful, but 11 | -- WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 12 | -- or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public 13 | -- License for more details. 14 | -- 15 | -- You should have received a copy of the GNU Lesser General Public License 16 | -- along with this library; if not, see . 17 | -- 18 | -- Comments, questions and criticisms can be sent to: sean@conman.org 19 | -- 20 | -- ******************************************************************** 21 | -- luacheck: globals address 22 | -- luacheck: ignore 611 23 | 24 | local net = require "org.conman.net" 25 | local dns = require "org.conman.dns" 26 | local math = require "math" 27 | 28 | local _VERSION = _VERSION 29 | local ipairs = ipairs 30 | 31 | if _VERSION == "Lua 5.1" then 32 | module("org.conman.dns.resolv") 33 | else 34 | _ENV = {} 35 | end 36 | 37 | -- ******************************************************************** 38 | 39 | local servers = 40 | { 41 | net.address("192.168.1.10","domain","udp"), 42 | } 43 | 44 | local searches = 45 | { 46 | ".", 47 | ".roswell.area51." 48 | } 49 | 50 | servers.current = 1 51 | servers.sock = net.socket(servers[1].family,'udp') 52 | 53 | -- ******************************************************************** 54 | 55 | local function query(host,type) 56 | local packet 57 | local result 58 | local err 59 | local id 60 | local _ 61 | local cycle 62 | 63 | id = math.random() 64 | packet,err = dns.encode { 65 | id = id, 66 | query = true, 67 | rd = true, 68 | opcode = 'query', 69 | question = 70 | { 71 | name = host, 72 | type = type, 73 | class = 'in' 74 | } 75 | } 76 | 77 | if packet == nil then 78 | return packet,err 79 | end 80 | 81 | cycle = servers.current 82 | 83 | repeat 84 | servers.sock:write(servers[servers.current],packet) 85 | 86 | _,result,err = servers.sock:read(5) 87 | if err == 0 then 88 | return dns.decode(result) 89 | end 90 | 91 | servers.sock:close() 92 | cycle = cycle + 1 93 | if cycle > #servers then 94 | cycle = 1 95 | end 96 | servers.sock = net.socket(servers[cycle].family,'udp') 97 | until cycle == servers.current 98 | 99 | return nil 100 | end 101 | 102 | -- ******************************************************************** 103 | 104 | local function query_a(host,type) 105 | type = type:upper() 106 | local a = query(host,type) 107 | 108 | if a == nil then 109 | return nil 110 | end 111 | 112 | for i = 1,#a.answers do 113 | if a.answers[i].type == type then 114 | return a.answers[i].address 115 | end 116 | end 117 | return nil 118 | end 119 | 120 | -- ******************************************************************** 121 | 122 | function address(host) 123 | for _,suffix in ipairs(searches) do 124 | local hostname = host .. suffix 125 | local a = query_a(hostname,'a') 126 | if a == nil then 127 | a = query_a(hostname,'aaaa') 128 | end 129 | if a ~= nil then 130 | return a 131 | end 132 | end 133 | return nil 134 | end 135 | 136 | -- ******************************************************************** 137 | 138 | if _VERSION >= "Lua 5.2" then 139 | return _ENV 140 | end 141 | -------------------------------------------------------------------------------- /lua/getopt.lua: -------------------------------------------------------------------------------- 1 | -- *************************************************************** 2 | -- 3 | -- Copyright 2010 by Sean Conner. All Rights Reserved. 4 | -- 5 | -- This library is free software; you can redistribute it and/or modify it 6 | -- under the terms of the GNU Lesser General Public License as published by 7 | -- the Free Software Foundation; either version 3 of the License, or (at your 8 | -- option) any later version. 9 | -- 10 | -- This library is distributed in the hope that it will be useful, but 11 | -- WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 12 | -- or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public 13 | -- License for more details. 14 | -- 15 | -- You should have received a copy of the GNU Lesser General Public License 16 | -- along with this library; if not, see . 17 | -- 18 | -- Comments, questions and criticisms can be sent to: sean@conman.org 19 | -- 20 | -- -------------------------------------------------------------------- 21 | -- 22 | -- Some standards for options. First, long options: 23 | -- http://www.gnu.org/prep/standards/standards.html#Option-Table 24 | -- 25 | -- And now for short options: 26 | -- http://www.catb.org/~esr/writings/taoup/html/ch10s05.html 27 | -- ******************************************************************** 28 | -- luacheck: globals getopt 29 | -- luacheck: ignore 611 30 | 31 | local io = require "io" 32 | local _VERSION = _VERSION 33 | local type = type 34 | 35 | if _VERSION == "Lua 5.1" then 36 | module("org.conman.getopt") 37 | else 38 | _ENV = {} 39 | end 40 | 41 | local SHORT_OPT = 1 42 | local LONG_OPT = 2 43 | local ARGUMENT = 3 44 | local CALLBACK = 4 45 | 46 | -- ************************************************************************ 47 | 48 | local function long_match(lnopt,arg,i,err) 49 | local tag 50 | local value 51 | 52 | tag,value = arg[i]:match("^%-%-([^%=]+)%=?(.*)") 53 | 54 | if lnopt == nil then 55 | err(tag) 56 | return i + 1 57 | end 58 | 59 | if lnopt[ARGUMENT] then 60 | if value == "" then 61 | i = i + 1 62 | value = arg[i] 63 | end 64 | else 65 | value = nil 66 | end 67 | 68 | lnopt[CALLBACK](value) 69 | 70 | return i + 1 71 | end 72 | 73 | -- *********************************************************************** 74 | 75 | local function short_match(shopt,arg,i,err) 76 | local value 77 | 78 | for n = 2 , #arg[i] do 79 | local opt = arg[i]:sub(n,n) 80 | 81 | if shopt[opt] == nil then 82 | err(opt) 83 | elseif not shopt[opt][ARGUMENT] then 84 | shopt[opt][CALLBACK]() 85 | else 86 | if n == #arg[i] then 87 | i = i + 1 88 | value = arg[i] 89 | else 90 | if arg[i]:sub(n+1,n+1) == '=' then 91 | value = arg[i]:sub(n+2) 92 | else 93 | value = arg[i]:sub(n+1) 94 | end 95 | end 96 | 97 | shopt[opt][CALLBACK](value) 98 | return i + 1 99 | end 100 | end 101 | return i + 1 102 | end 103 | 104 | -- *********************************************************************** 105 | 106 | function getopt(arg,options,err) 107 | local shopt = {} 108 | local lnopt = {} 109 | err = err or function(opt) 110 | io.stderr:write("unsupported option: ",opt,"\n") 111 | end 112 | 113 | for i = 1 , #options do 114 | shopt[options[i][SHORT_OPT]] = options[i] 115 | if options[i][LONG_OPT] ~= nil then 116 | if type(options[i][LONG_OPT]) == 'string' then 117 | lnopt[options[i][LONG_OPT]] = options[i] 118 | elseif type(options[i][LONG_OPT]) == 'table' then 119 | for j = 1 , #options[i][LONG_OPT] do 120 | lnopt[options[i][LONG_OPT][j]] = options[i] 121 | end 122 | end 123 | end 124 | end 125 | 126 | local i = 1 127 | 128 | while(i <= #arg) do 129 | local al 130 | local as 131 | 132 | al = arg[i]:match("^%-%-([^%=]+)") 133 | as = arg[i]:match("^%-([^%-])") 134 | 135 | if al ~= nil then 136 | i = long_match(lnopt[al],arg,i,err) 137 | elseif as ~= nil then 138 | i = short_match(shopt,arg,i,err) 139 | else 140 | return i 141 | end 142 | end 143 | 144 | return i 145 | end 146 | 147 | -- *********************************************************************** 148 | 149 | if _VERSION >= "Lua 5.2" then 150 | return _ENV 151 | end 152 | -------------------------------------------------------------------------------- /lua/gzip.lua: -------------------------------------------------------------------------------- 1 | 2 | -- RFC-1952 3 | -- luacheck: globals idiv read 4 | -- luacheck: ignore 611 5 | 6 | local _VERSION = _VERSION 7 | local pairs = pairs 8 | local setmetatable = setmetatable 9 | 10 | local math = require "math" 11 | local table = require "table" 12 | 13 | if _VERSION == "Lua 5.1" then 14 | module("org.conman.gzip") 15 | else 16 | _ENV = {} 17 | end 18 | 19 | -- ************************************************************************ 20 | 21 | local function reverse_index(tab) 22 | local keys = {} 23 | for name in pairs(tab) do 24 | table.insert(keys,name) 25 | end 26 | 27 | for i = 1 , #keys do 28 | local k = keys[i] 29 | local v = tab[k] 30 | tab[v] = k 31 | end 32 | 33 | return setmetatable(tab,{ 34 | __index = function(_,key) 35 | if type(key) == 'number' then 36 | return '-' 37 | elseif type(key) == 'string' then 38 | return 0 39 | end 40 | end 41 | }) 42 | end 43 | 44 | os = reverse_index { -- luacheck: ignore 45 | ["MS-DOS"] = 0, 46 | ["Amiga"] = 1, 47 | ["OpenVMS"] = 2, 48 | ["UNIX"] = 3, 49 | ["VM/CMS"] = 4, 50 | ["Atari ST"] = 5, 51 | ["OS/2"] = 6, 52 | ["Macintosh"] = 7, 53 | ["Z-System"] = 8, 54 | ["CP/M"] = 9, 55 | ["Windows"] = 10, 56 | ["MVS"] = 11, 57 | ["VSE"] = 12, 58 | ["Acorn Risc"] = 13, 59 | ["VFAT"] = 14, 60 | ["alternative MVS"] = 15, 61 | ["BeOS"] = 16, 62 | ["Tandem"] = 17, 63 | ["OS/400"] = 18, 64 | ["Darwin"] = 19, 65 | } 66 | 67 | -- ************************************************************************ 68 | 69 | function idiv(up,down) 70 | local q = math.floor(up/down) 71 | local r = up % down 72 | return q,r 73 | end 74 | 75 | -- ************************************************************************ 76 | 77 | local function r16(gf) 78 | return gf:read(1):byte() 79 | + gf:read(1):byte() * 2*8 80 | end 81 | 82 | -- ************************************************************************ 83 | 84 | local function r32(gf) 85 | return gf:read(1):byte() 86 | + gf:read(1):byte() * 2^8 87 | + gf:read(1):byte() * 2^16 88 | + gf:read(1):byte() * 2^24 89 | end 90 | 91 | -- ************************************************************************ 92 | 93 | local function bool(n) 94 | local q,r = idiv(n,2) 95 | return r ~= 0 , q 96 | end 97 | 98 | -- ************************************************************************ 99 | 100 | local function read_asciiz(gf,acc) 101 | acc = acc or "" 102 | local c = gf:read(1) 103 | if c == "\0" then 104 | return acc 105 | else 106 | return read_asciiz(gf,acc .. c) 107 | end 108 | end 109 | 110 | -- ************************************************************************ 111 | 112 | function read(gf) 113 | local id = gf:read(2) 114 | if id ~= "\31\139" then 115 | return nil 116 | end 117 | 118 | local comp = gf:read(1) 119 | if comp ~= "\8" then 120 | return nil 121 | end 122 | 123 | local meta = {} 124 | local f = gf:read(1):byte() 125 | meta.text,f = bool(f) 126 | local fhcrc,f = bool(f) -- luacheck: ignore 127 | local fextra,f = bool(f) -- luacheck: ignore 128 | local fname,f = bool(f) -- luacheck: ignore 129 | local fcomment,_ = bool(f) 130 | meta.mtime = r32(gf) 131 | meta.xfl = gf:read(1):byte() 132 | meta.os = os[gf:read(1):byte()] 133 | 134 | if fextra then 135 | meta.extra = {} 136 | 137 | local len = r16(gf) 138 | while len > 0 do 139 | local id2 = gf:read(2) 140 | local size = r16(gf) 141 | local data = gf:read(size) 142 | meta.extra[id2] = data 143 | len = len - 4 144 | len = len - size 145 | end 146 | end 147 | 148 | if fname then 149 | meta.name = read_asciiz(gf) 150 | end 151 | 152 | if fcomment then 153 | meta.comment = read_asciiz(gf) 154 | end 155 | 156 | if fhcrc then 157 | meta.crc16 = r16(gf) 158 | end 159 | 160 | local here = gf:seek() 161 | 162 | gf:seek('end',-8) 163 | meta.crc32 = r32(gf) 164 | meta.size = r32(gf) 165 | gf:seek('set',here) 166 | 167 | return meta 168 | end 169 | 170 | -- ************************************************************************ 171 | 172 | if _VERSION >= "Lua 5.2" then 173 | return _ENV 174 | end 175 | -------------------------------------------------------------------------------- /lua/mailcap.lua: -------------------------------------------------------------------------------- 1 | -- ************************************************************************ 2 | -- 3 | -- Handle mailcap files 4 | -- Copyright 2019 by Sean Conner. All Rights Reserved. 5 | -- 6 | -- This library is free software; you can redistribute it and/or modify it 7 | -- under the terms of the GNU Lesser General Public License as published by 8 | -- the Free Software Foundation; either version 3 of the License, or (at your 9 | -- option) any later version. 10 | -- 11 | -- This library is distributed in the hope that it will be useful, but 12 | -- WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 13 | -- or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public 14 | -- License for more details. 15 | -- 16 | -- You should have received a copy of the GNU Lesser General Public License 17 | -- along with this library; if not, see . 18 | -- 19 | -- Comments, questions and criticisms can be sent to: sean@conman.org 20 | -- 21 | -- ************************************************************************ 22 | -- luacheck: ignore 611 23 | -- 24 | -- https://www.commandlinux.com/man-page/man5/mailcap.5.html 25 | -- RFC-1524 26 | 27 | local lpeg = require "lpeg" -- semver: ~1.0.0 28 | 29 | local Carg = lpeg.Carg 30 | local Cc = lpeg.Cc 31 | local Cf = lpeg.Cf 32 | local Cg = lpeg.Cg 33 | local Cs = lpeg.Cs 34 | local Ct = lpeg.Ct 35 | local C = lpeg.C 36 | local P = lpeg.P 37 | local R = lpeg.R 38 | 39 | -- ************************************************************************ 40 | 41 | local mimetype do 42 | local iana_token = R("AZ","az","09","--","..")^1 43 | local majortype = iana_token 44 | local minortype = iana_token + P"*" 45 | 46 | mimetype = C(majortype) * P"/" * C(minortype) 47 | end 48 | 49 | -- ************************************************************************ 50 | 51 | local CAPS = {} do 52 | local EOLN = P"\n" * Carg(1) 53 | / function(c) 54 | c._line = c._line + 1 55 | end 56 | local SP = P" " 57 | + P"\\" * EOLN 58 | + P"\t" 59 | local SEMI = P";" * SP^0 60 | local char = P"\\" * EOLN / " " 61 | + P[[\]] * C(1) / "%1" 62 | + P"\t" / " " 63 | + R(" :","<\226","\192\255") 64 | local cmd = Cs(char^1) 65 | local number = R"09"^1 / tonumber 66 | local fields = P'notes=' * Cg(cmd, 'notes') 67 | + P'test=' * Cg(cmd, 'test') 68 | + P'print=' * Cg(cmd, 'print') 69 | + P'compose=' * Cg(cmd, 'compose') 70 | + P'composetyped=' * Cg(cmd, 'composedtype') 71 | + P'stream-buffer-size=' * Cg(number, 'stream_buffer_size') 72 | + P'needsterminal' * Cg(Cc(true),'needsterminal') 73 | + P'copiousoutput' * Cg(Cc(true),'copiousoutput') 74 | + P'textualnewlines=1' * Cg(Cc(true),'textualnewlines') 75 | + P'textualnewlines=0' -- false by default 76 | local program = Cg(cmd,'view') 77 | local data = program * (SEMI * fields)^0 78 | local entry = mimetype * SEMI * Ct(data) * EOLN 79 | + Cc(false) * C(R("\t\t"," \126","\192\255")^0) * EOLN 80 | 81 | local mailcapfile = Cf(Carg(1) * (Cg(entry))^0,function(caps,major,minor,node) 82 | if major then 83 | if not caps[major] then caps[major] = {} end 84 | if minor == '*' then 85 | local mt = getmetatable(caps[major]) 86 | 87 | -- ---------------------------------------------------------------- 88 | -- if mt exists, there's a duplicate entry, but since I'm not doing 89 | -- anything about, there's not much point in checking for it. 90 | -- ---------------------------------------------------------------- 91 | 92 | if not mt then 93 | mt = {} 94 | end 95 | 96 | mt.__index = function() 97 | return node 98 | end 99 | 100 | setmetatable(caps[major],mt) 101 | else 102 | caps[major][minor] = node 103 | end 104 | end 105 | 106 | return caps 107 | end) 108 | 109 | local function readmailcap(fname) 110 | local caps = { _file = fname , _line = 0 } 111 | local f = io.open(fname,"r") 112 | if f then 113 | mailcapfile:match(f:read("*a"),1,caps) 114 | f:close() 115 | end 116 | return caps 117 | end 118 | 119 | -- ********************************************************************** 120 | -- RFC-1524 states looking through $MAILCAPS and if not present, default 121 | -- to $HOME/.mailcap:/etc/mailcap:/usr/etc/mailcap:/usr/local/etc/mailcap 122 | -- I don't think that default order is great---I prefer going from local 123 | -- definitions to system definitions, so I change up the order to reflect 124 | -- that. Also, I add /usr/share/etc/mailcap, juse because. 125 | -- ********************************************************************** 126 | 127 | local mailcaps = os.getenv("MAILCAPS") 128 | 129 | if mailcaps then 130 | for path in mailcaps:gmatch "[^%:]+" do 131 | table.insert(CAPS,readmailcap(path)) 132 | end 133 | else 134 | CAPS[1] = readmailcap(os.getenv("HOME") .. "/.mailcap") 135 | CAPS[2] = readmailcap("/usr/local/etc/mailcap") 136 | CAPS[3] = readmailcap("/usr/share/etc/mailcap") 137 | CAPS[4] = readmailcap("/usr/etc/mailcap") 138 | CAPS[5] = readmailcap("/etc/mailcap") 139 | end 140 | end 141 | 142 | -- ************************************************************************ 143 | 144 | local cmd do 145 | local char = P"%s" * Carg(1) * Carg(2) 146 | / function(s,f) 147 | s.redirect = false 148 | return f 149 | end 150 | + P"%{" * Carg(4) * C(R("AZ","az","09","__","--","..")^1) * P"}" 151 | / function(tab,cap) 152 | return tab[cap] or "" 153 | end 154 | + P"%t" * Carg(3) / "%1" 155 | + R(" \126","\192\255") 156 | 157 | local redirect = Carg(1) * Carg(2) 158 | / function(s,f) 159 | if s.redirect then 160 | return string.format(" %s %s",s.dir,f) 161 | end 162 | end 163 | cmd = Carg(1) / function(s) s.redirect = true end 164 | * Cs(char^1 * redirect) 165 | end 166 | 167 | -- ************************************************************************ 168 | 169 | local function handle(what,dir,page,type,params) 170 | local function runthisp(node) 171 | if not node then return false end 172 | if node.test then 173 | local program = cmd:match(node.test,1,{ dir = "<" },page,type,params) 174 | return os.execute(program) 175 | else 176 | return true 177 | end 178 | end 179 | 180 | params = params or {} 181 | local major,minor = mimetype:match(type) 182 | 183 | for _,cap in ipairs(CAPS) do 184 | local node = cap[major] and cap[major][minor] 185 | if runthisp(node) then 186 | local program = cmd:match(node[what],1,{ dir = dir },page,type,params or {}) 187 | return os.execute(program) 188 | end 189 | end 190 | end 191 | 192 | -- ************************************************************************ 193 | 194 | return { 195 | view = function(page,type,params) 196 | return handle('view','<',page,type,params) 197 | end, 198 | 199 | print = function(page,type,params) 200 | return handle('print','<',page,type,params) 201 | end, 202 | 203 | compose = function(page,type,params) 204 | return handle('compose','>',page,type,params) 205 | end, 206 | 207 | composetyped = function(page,type,params) 208 | return handle('composetyped','>',page,type,params) 209 | end, 210 | } 211 | -------------------------------------------------------------------------------- /lua/net/tcp.lua: -------------------------------------------------------------------------------- 1 | -- ******************************************************************* 2 | -- 3 | -- Copyright 2019 by Sean Conner. All Rights Reserved. 4 | -- 5 | -- This library is free software; you can redistribute it and/or modify it 6 | -- under the terms of the GNU Lesser General Public License as published by 7 | -- the Free Software Foundation; either version 3 of the License, or (at your 8 | -- option) any later version. 9 | -- 10 | -- This library is distributed in the hope that it will be useful, but 11 | -- WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 12 | -- or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public 13 | -- License for more details. 14 | -- 15 | -- You should have received a copy of the GNU Lesser General Public License 16 | -- along with this library; if not, see . 17 | -- 18 | -- Comments, questions and criticisms can be sent to: sean@conman.org 19 | -- 20 | -- ******************************************************************* 21 | -- luacheck: globals accept listena listen connecta connect 22 | -- luacheck: ignore 611 23 | 24 | local syslog = require "org.conman.syslog" 25 | local net = require "org.conman.net" 26 | local errno = require "org.conman.errno" 27 | local ios = require "org.conman.net.ios" 28 | 29 | local _VERSION = _VERSION 30 | local setmetatable = setmetatable 31 | local ipairs = ipairs 32 | 33 | if _VERSION == "Lua 5.1" then 34 | module("org.conman.net.tcp") 35 | else 36 | _ENV = {} 37 | end 38 | 39 | -- ******************************************************************* 40 | 41 | local function make_ios(conn,remote) 42 | local state = ios() 43 | 44 | state.close = function(self) 45 | self:flush() 46 | self.__socket:close() 47 | return true 48 | end 49 | 50 | state._refill = function(self) 51 | local _,data,err = self.__socket:recv() 52 | if data then 53 | if #data > 0 then 54 | return data 55 | else 56 | return nil 57 | end 58 | else 59 | return nil,errno[err],err 60 | end 61 | end 62 | 63 | state._drain = function(self,buffer) 64 | local bytes,err = self.__socket:send(nil,buffer) 65 | if bytes >= 0 then 66 | return true 67 | else 68 | return false,errno[err],err 69 | end 70 | end 71 | 72 | state.__remote = remote 73 | state.__socket = conn 74 | 75 | if _VERSION >= "Lua 5.2" then 76 | local mt = {} 77 | mt.__gc = state.close 78 | if _VERSION >= "Lua 5.4" then 79 | mt.__close = state.close 80 | end 81 | setmetatable(state,mt) 82 | end 83 | 84 | return state 85 | end 86 | 87 | -- ******************************************************************* 88 | -- Usage: ios = tcp.accept(sock) 89 | -- Desc: Return a TCP connection 90 | -- Input: sock (userdata/socket) a listening socket 91 | -- Return: ios (table) an Input/Output object (nil on error) 92 | -- ******************************************************************* 93 | 94 | function accept(sock) 95 | local conn,remote = sock:accept() 96 | if conn then 97 | sock.nodelay = true 98 | return make_ios(conn,remote) 99 | end 100 | end 101 | 102 | -- ******************************************************************* 103 | -- Usage: sock,errmsg = tcp.listena(addr) 104 | -- Desc: Create a listening socket 105 | -- Input: addr (userdata/address) IP address and port 106 | -- Return: sock (userdata/socket) listening socket 107 | -- errmsg (string) error message 108 | -- ******************************************************************* 109 | 110 | function listena(addr) 111 | local sock,err = net.socket(addr.family,'tcp') 112 | if not sock then 113 | return false,errno[err] 114 | end 115 | 116 | sock.reuseaddr = true 117 | sock:bind() 118 | sock:listen() 119 | 120 | return sock 121 | end 122 | 123 | -- ******************************************************************* 124 | -- Usage: ios = tcp.listen(host,port) 125 | -- Desc: Create a listening socket 126 | -- Input: host (string) hostname of interface to listen on 127 | -- port (string number) port number 128 | -- Return: ios (table) Input/Output object (nil on error) 129 | -- ******************************************************************* 130 | 131 | function listen(host,port) 132 | return listena(net.address2(host,'any','tcp',port)[1]) 133 | end 134 | 135 | -- ******************************************************************* 136 | -- Usage: ios = tcp.connecta(addr) 137 | -- Desc: Connect to a remote host 138 | -- Input: addr (userdata/address) IP address and port 139 | -- Return: ios (table) Input/Output object (nil on error) 140 | -- ******************************************************************* 141 | 142 | function connecta(addr) 143 | if not addr then return end 144 | 145 | local sock,err = net.socket(addr.family,'tcp') 146 | 147 | if not sock then 148 | syslog('error',"socket(TCP) = %s",errno[err]) 149 | return 150 | end 151 | 152 | local err1 = sock:connect(addr) 153 | 154 | if err1 ~= 0 then 155 | return 156 | end 157 | 158 | return make_ios(sock,addr) 159 | end 160 | 161 | -- ******************************************************************* 162 | -- Usage: ios = tcp.connect(host,port) 163 | -- Desc: Connect to a remote host 164 | -- Input: host (string) hostname 165 | -- port (string number) port to connect to 166 | -- Return: ios (table) Input/Output object (nil on error) 167 | -- ******************************************************************* 168 | 169 | function connect(host,port) 170 | local addr = net.address2(host,'any','tcp',port) 171 | if addr then 172 | for _,a in ipairs(addr) do 173 | local conn = connecta(a) 174 | if conn then 175 | return conn 176 | end 177 | end 178 | end 179 | end 180 | 181 | -- ******************************************************************* 182 | 183 | if _VERSION >= "Lua 5.2" then 184 | return _ENV 185 | end 186 | -------------------------------------------------------------------------------- /lua/net/tls.lua: -------------------------------------------------------------------------------- 1 | -- ******************************************************************* 2 | -- 3 | -- Copyright 2019 by Sean Conner. All Rights Reserved. 4 | -- 5 | -- This library is free software; you can redistribute it and/or modify it 6 | -- under the terms of the GNU Lesser General Public License as published by 7 | -- the Free Software Foundation; either version 3 of the License, or (at your 8 | -- option) any later version. 9 | -- 10 | -- This library is distributed in the hope that it will be useful, but 11 | -- WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 12 | -- or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public 13 | -- License for more details. 14 | -- 15 | -- You should have received a copy of the GNU Lesser General Public License 16 | -- along with this library; if not, see . 17 | -- 18 | -- Comments, questions and criticisms can be sent to: sean@conman.org 19 | -- 20 | -- ******************************************************************* 21 | -- luacheck: globals accept listens listena listen connecta connect 22 | -- luacheck: ignore 611 23 | 24 | local syslog = require "org.conman.syslog" 25 | local errno = require "org.conman.errno" 26 | local net = require "org.conman.net" 27 | local tls = require "org.conman.tls" 28 | local ios = require "org.conman.net.ios" 29 | 30 | local _VERSION = _VERSION 31 | local setmetatable = setmetatable 32 | local ipairs = ipairs 33 | 34 | if _VERSION == "Lua 5.1" then 35 | module(...) 36 | else 37 | _ENV = {} -- luacheck: ignore 38 | end 39 | 40 | -- ******************************************************************* 41 | 42 | local function make_ios(ctx,conn) 43 | local state = ios() 44 | state.__ctx = ctx 45 | state.__socket = conn 46 | 47 | function state:close() -- luacheck: ignore 48 | local advice = self.__ctx:close() 49 | if advice == tls.WANT_INPUT or advice == tls.WANT_OUTPUT then 50 | return self:close() 51 | else 52 | local err = self.__socket:close() 53 | return err == 0,errno[err],err 54 | end 55 | end 56 | 57 | function state:_handshake() -- luacheck: ignore 58 | local advise = self.__ctx:handshake() 59 | if advise == tls.WANT_INPUT or advise == tls.WANT_OUTPUT then 60 | return self:_handshake() 61 | elseif advise == -1 then 62 | local msg = self.__ctx:error() or "error" 63 | syslog('error',"tls:_handshake() = %s",msg) 64 | return false,msg,-1 65 | else 66 | return true 67 | end 68 | end 69 | 70 | function state:_refill() -- luacheck: ignore 71 | local data,size = self.__ctx:read(tls.BUFFERSIZE) 72 | if size == tls.WANT_INPUT or size == tls.WANT_OUTPUT then 73 | return self:_refill() 74 | elseif size == -1 then 75 | local msg = self.__ctx:error() or "error" 76 | syslog('error',"tls:_refill() = %s",msg) 77 | return nil,msg,-1 78 | else 79 | if #data > 0 then 80 | return data 81 | else 82 | return nil 83 | end 84 | end 85 | end 86 | 87 | function state:_drain(data) -- luacheck: ignore 88 | local size = self.__ctx:write(data) 89 | if size == tls.WANT_INPUT or size == tls.WANT_OUTPUT then 90 | return self:_drain(data) 91 | elseif size == -1 then 92 | local msg = self.__ctx:error() 93 | syslog('error',"tls:_drain() = %s",msg) 94 | return false,msg,-1 95 | else 96 | return true 97 | end 98 | end 99 | 100 | if _VERSION >= "Lua 5.2" then 101 | local mt = {} 102 | mt.__gc = state.close 103 | if _VERSION >= "Lua 5.4" then 104 | mt.__close = state.close 105 | end 106 | setmetatable(state,mt) 107 | end 108 | 109 | state:setvbuf('no') 110 | return state 111 | end 112 | 113 | -- ******************************************************************* 114 | -- Usage: ios = accept(sock) 115 | -- Desc: Return a TCP connection 116 | -- Input: sock (userdata/socket) a listening socket 117 | -- Return: ios (table) an Input/Output object (nil on error) 118 | -- ******************************************************************* 119 | 120 | function accept(sock) 121 | local conn,remote = sock:accept() 122 | if conn then 123 | sock.nodelay = true 124 | return make_ios(conn,remote) 125 | end 126 | end 127 | 128 | -- ******************************************************************* 129 | -- Usage: sock,errmsg = listens(sock,conf) 130 | -- Desc: Initialize a listening TCP socket 131 | -- Input: sock (userdata/socket) bound socket 132 | -- conf (function) function for TLS configuration 133 | -- Return: sock (userdata) socket used for listening, false on error 134 | -- errmsg (string) error message 135 | -- ******************************************************************* 136 | 137 | function listens(sock,conf) 138 | local config = tls.config() 139 | local server = tls.server() 140 | 141 | if not conf(config) then return false,config:error() end 142 | if not server:configuration(config) then 143 | return false,server:error() 144 | end 145 | 146 | -- XXX finish ... 147 | 148 | return sock 149 | end 150 | 151 | -- ******************************************************************* 152 | -- Usage: sock,errmsg = listena(addr,conf) 153 | -- Desc: Initialize a listening TCP socket 154 | -- Input: addr (userdata/address) IP address 155 | -- conf (function) function for TLS configuration 156 | -- Return: sock (userdata) socket used for listening, false on error 157 | -- errmsg (string) error message 158 | -- ******************************************************************* 159 | 160 | function listena(addr,conf) 161 | local sock,err = net.socket(addr.family,'tcp') 162 | if not sock then 163 | return false,errno[err] 164 | end 165 | 166 | sock.reuseaddr = true 167 | sock:bind(addr) 168 | sock:listen() 169 | return listens(sock,conf) 170 | end 171 | 172 | -- ******************************************************************* 173 | -- Usage: sock,errmsg = listen(host,port,conf) 174 | -- Desc: Initalize a listening TCP socket 175 | -- Input: host (string) address to bind to 176 | -- port (string integer) port 177 | -- conf (function) configuration options 178 | -- Return: sock (userdata) socket used for listening, false on error 179 | -- errmsg (string) error message 180 | -- ******************************************************************* 181 | 182 | function listen(host,port,conf) 183 | return listena(net.address2(host,'ip','tcp',port)[1],conf) 184 | end 185 | 186 | -- ******************************************************************* 187 | -- Usage: ios = connecta(addr,hostname[,conf]) 188 | -- Desc: Connect to a remote address 189 | -- Input: addr (userdata/address) IP address 190 | -- hostname (string) hostname (required for TLS) 191 | -- conf (function) configuration options 192 | -- Return: ios (table) Input/Output object (nil on error) 193 | -- ******************************************************************* 194 | 195 | function connecta(addr,hostname,conf) 196 | local sock,err = net.socket(addr.family,'tcp') 197 | 198 | if not sock then 199 | return false,errno[err] 200 | end 201 | 202 | err = sock:connect(addr) 203 | 204 | if err ~= 0 then 205 | sock:close() 206 | return false,errno[err] 207 | end 208 | 209 | local config = tls.config() 210 | local ctx = tls.client() 211 | 212 | if conf then 213 | if not conf(config) then return false,config:error() end 214 | else 215 | config:protocols("all") 216 | end 217 | 218 | ctx:configure(config) 219 | 220 | if not ctx:connect_socket(sock:_tofd(),hostname) then 221 | sock:close() 222 | return false,ctx:error() or "failed to connect" 223 | end 224 | 225 | return make_ios(ctx,sock) 226 | end 227 | 228 | -- ******************************************************************* 229 | -- Usage: ios = connect(host,port[,conf]) 230 | -- Desc: Connect to a remote host 231 | -- Input: host (string) IP address 232 | -- port (string number) port to connect to 233 | -- conf (function) configuration options 234 | -- Return: ios (table) Input/Output object (nil on error) 235 | -- ******************************************************************* 236 | 237 | function connect(host,port,conf) 238 | local addr,err = net.address2(host,'any','tcp',port) 239 | if addr then 240 | for _,a in ipairs(addr) do 241 | local conn = connecta(a,host,conf) 242 | if conn then 243 | return conn 244 | end 245 | end 246 | else 247 | return nil,net.errno[err] 248 | end 249 | end 250 | 251 | -- ******************************************************************* 252 | 253 | if _VERSION >= "Lua 5.2" then 254 | return _ENV -- luacheck: ignore 255 | end 256 | -------------------------------------------------------------------------------- /lua/nfl.lua: -------------------------------------------------------------------------------- 1 | -- *************************************************************** 2 | -- 3 | -- Copyright 2018 by Sean Conner. All Rights Reserved. 4 | -- 5 | -- This library is free software; you can redistribute it and/or modify it 6 | -- under the terms of the GNU Lesser General Public License as published by 7 | -- the Free Software Foundation; either version 3 of the License, or (at your 8 | -- option) any later version. 9 | -- 10 | -- This library is distributed in the hope that it will be useful, but 11 | -- WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 12 | -- or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public 13 | -- License for more details. 14 | -- 15 | -- You should have received a copy of the GNU Lesser General Public License 16 | -- along with this library; if not, see . 17 | -- 18 | -- Comments, questions and criticisms can be sent to: sean@conman.org 19 | -- 20 | -- ******************************************************************** 21 | -- luacheck: globals SOCKETS schedule spawn timeout info dump_info 22 | -- luacheck: globals client_eventloop server_eventloop 23 | -- luacheck: ignore 611 24 | 25 | local pollset = require "org.conman.pollset" 26 | local syslog = require "org.conman.syslog" 27 | local signal = require "org.conman.signal" 28 | local clock = require "org.conman.clock" 29 | local errno = require "org.conman.errno" 30 | local coroutine = require "coroutine" 31 | local table = require "table" 32 | local debug = require "debug" 33 | local math = require "math" 34 | 35 | local _VERSION = _VERSION 36 | local print = print 37 | local assert = assert 38 | local pairs = pairs 39 | local unpack = table.unpack or unpack 40 | local tostring = tostring 41 | local setmetatable = setmetatable 42 | 43 | if _VERSION == "Lua 5.1" then 44 | module(...) 45 | else 46 | _ENV = {} -- luacheck: ignore 47 | end 48 | 49 | -- ********************************************************************** 50 | 51 | local REFQUEUE = { _n = 0 } -- list of all coroutines (for strong reference) 52 | local TOQUEUE = setmetatable({},{ __mode = "k" }) -- TimeOut queue 53 | local RUNQUEUE = {} -- run queue 54 | SOCKETS = pollset() -- event generators 55 | 56 | signal.ignore('pipe') 57 | 58 | -- ********************************************************************** 59 | -- TOQUEUE:insert() and TOQUEUE:remove() are based, more or less directly, 60 | -- up http://en.wikipedia.org/wiki/Binary_heap 61 | -- ---------------------------------------------------------------------- 62 | 63 | function TOQUEUE:insert(when,co,...) 64 | local function bubble_up(parent,child) 65 | if parent > 0 then 66 | if self[parent].awake > self[child].awake then 67 | self[parent] , self[child] = self[child] , self[parent] 68 | return bubble_up(math.floor(parent / 2),parent) 69 | end 70 | end 71 | end 72 | 73 | local idx = #self + 1 74 | local parent = math.floor(idx / 2) 75 | local info = 76 | { 77 | awake = clock.get('monotonic') + when, 78 | trigger = true, 79 | co = co, 80 | ... 81 | } 82 | 83 | self[idx] = info 84 | self[co] = info 85 | bubble_up(parent,idx) 86 | end 87 | 88 | -- ********************************************************************** 89 | 90 | function TOQUEUE:remove() 91 | local function bubble_down(parent,left,right) 92 | local smallest = parent 93 | 94 | if left <= #self and self[left].awake < self[smallest].awake then 95 | smallest = left 96 | end 97 | 98 | if right <= #self and self[right].awake < self[smallest].awake then 99 | smallest = right 100 | end 101 | 102 | if smallest ~= parent then 103 | self[parent] , self[smallest] = self[smallest] , self[parent] 104 | return bubble_down(smallest,smallest * 2,smallest * 2 + 1) 105 | end 106 | end 107 | 108 | local res = self[1] 109 | local x = table.remove(self) 110 | self[res.co] = nil 111 | 112 | if #self > 0 then 113 | self[1] = x 114 | bubble_down(1,2,3) 115 | end 116 | 117 | return res 118 | end 119 | 120 | -- ********************************************************************** 121 | 122 | function schedule(co , ... ) 123 | if not RUNQUEUE[co] then 124 | RUNQUEUE[#RUNQUEUE + 1] = { co , ... } 125 | RUNQUEUE[co] = true 126 | end 127 | end 128 | 129 | -- ********************************************************************** 130 | 131 | function spawn(f, ...) 132 | local co = coroutine.create(f) 133 | 134 | if co then 135 | REFQUEUE[co] = true 136 | REFQUEUE._n = REFQUEUE._n + 1 137 | schedule(co,...) 138 | end 139 | 140 | return co 141 | end 142 | 143 | -- ********************************************************************** 144 | 145 | function timeout(when,...) 146 | local co = coroutine.running() 147 | 148 | if when == 0 then 149 | if TOQUEUE[co] then 150 | assert(TOQUEUE[co].co == co) 151 | TOQUEUE[co].trigger = false 152 | end 153 | else 154 | TOQUEUE:insert(when,co,...) 155 | end 156 | end 157 | 158 | -- ********************************************************************** 159 | 160 | local function eventloop(done_f) 161 | if done_f() then return end 162 | 163 | local timeout = -1 164 | local now = clock.get('monotonic') 165 | 166 | while #TOQUEUE > 0 do 167 | local co = TOQUEUE[1] 168 | 169 | if co.trigger then 170 | timeout = co.awake - now 171 | if timeout > 0 then 172 | break 173 | end 174 | 175 | if coroutine.status(co.co) ~= 'dead' then 176 | schedule(co.co,unpack(co)) 177 | end 178 | end 179 | 180 | TOQUEUE:remove() 181 | end 182 | 183 | if #RUNQUEUE > 0 then 184 | timeout = 0 185 | end 186 | 187 | local okay,err = SOCKETS:wait(timeout) 188 | if not okay then 189 | syslog('error',"SOCKETS:events() = %s",errno[err]) 190 | return eventloop(done_f) 191 | end 192 | 193 | for event in SOCKETS:events() do 194 | event.obj(event) 195 | end 196 | 197 | while #RUNQUEUE > 0 do 198 | local co = table.remove(RUNQUEUE,1) 199 | RUNQUEUE[co[1]] = nil 200 | 201 | local status = coroutine.status(co[1]) 202 | 203 | if status == 'dead' then 204 | syslog('warning',"A dead coroutine was scheduled to run") 205 | 206 | elseif status == 'suspended' then 207 | local ret = { coroutine.resume(unpack(co)) } 208 | 209 | if not ret[1] then 210 | syslog('error',"CRASH: coroutine %s dead: %s",tostring(co[1]),ret[2]) 211 | local msg = debug.traceback(co[1]) 212 | for entry in msg:gmatch("[^%\n]+") do 213 | syslog('error',"CRASH: %s: %s",tostring(co[1]),entry) 214 | end 215 | end 216 | 217 | if coroutine.status(co[1]) == 'dead' then 218 | assert(REFQUEUE._n > 0) 219 | REFQUEUE[co[1]] = nil 220 | REFQUEUE._n = REFQUEUE._n - 1 221 | end 222 | 223 | else 224 | -- ===================================================================== 225 | -- There are two states not accounted for---'normal' and 'running'. 226 | -- Neither of these should happen. 227 | -- 228 | -- 'running' 229 | -- Shouldn't happen because then it means we are trying to 230 | -- resume the coroutine that is currently running (namely, this 231 | -- coroutine), which not only doesn't make sense, but I can't 232 | -- see how this could happen. 233 | -- 234 | -- 'normal' 235 | -- We're doing this check from a coroutine that isn't running 236 | -- and the coroutine we're checking is running, and I can't see 237 | -- how that can happen (and doesn't make much sense either). 238 | -- 239 | -- So this path is one of those "This should never happen" paths, 240 | -- which should never happen. And if it does, just remove the 241 | -- reference to the coroutine, and log what happened. 242 | -- ===================================================================== 243 | 244 | syslog('critical',"unexpected coroutine state %q",status) 245 | assert(REFQUEUE._n > 0) 246 | REFQUEUE[co[1]] = nil 247 | REFQUEUE._n = REFQUEUE._n - 1 248 | end 249 | end 250 | 251 | return eventloop(done_f) 252 | end 253 | 254 | -- ********************************************************************** 255 | 256 | function client_eventloop(done_f) 257 | done_f = done_f or function() return false end 258 | return eventloop(function() return REFQUEUE._n == 0 or done_f() end) 259 | end 260 | 261 | -- ********************************************************************** 262 | 263 | function server_eventloop(done_f) 264 | done_f = done_f or function() return false end 265 | return eventloop(done_f) 266 | end 267 | 268 | -- ********************************************************************** 269 | 270 | function info() 271 | return REFQUEUE._n,#RUNQUEUE,#TOQUEUE,#SOCKETS 272 | end 273 | 274 | -- ********************************************************************** 275 | 276 | function dump_info() 277 | print("SOCKETS:",#SOCKETS) 278 | for name,val in pairs(REFQUEUE) do print("REF",name,val) end 279 | for name,val in pairs(TOQUEUE) do print("TO", name,val) end 280 | for name,val in pairs(RUNQUEUE) do print("RUN",name,val) end 281 | end 282 | 283 | -- ********************************************************************** 284 | 285 | if _VERSION >= "Lua 5.2" then 286 | return _ENV -- luacheck: ignore 287 | end 288 | -------------------------------------------------------------------------------- /lua/nfl/tcp.lua: -------------------------------------------------------------------------------- 1 | -- *************************************************************** 2 | -- 3 | -- Copyright 2018 by Sean Conner. All Rights Reserved. 4 | -- 5 | -- This library is free software; you can redistribute it and/or modify it 6 | -- under the terms of the GNU Lesser General Public License as published by 7 | -- the Free Software Foundation; either version 3 of the License, or (at your 8 | -- option) any later version. 9 | -- 10 | -- This library is distributed in the hope that it will be useful, but 11 | -- WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 12 | -- or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public 13 | -- License for more details. 14 | -- 15 | -- You should have received a copy of the GNU Lesser General Public License 16 | -- along with this library; if not, see . 17 | -- 18 | -- Comments, questions and criticisms can be sent to: sean@conman.org 19 | -- 20 | -- ******************************************************************** 21 | -- luacheck: globals listens listena listen connecta connect 22 | -- luacheck: ignore 611 23 | 24 | local syslog = require "org.conman.syslog" 25 | local errno = require "org.conman.errno" 26 | local net = require "org.conman.net" 27 | local mkios = require "org.conman.net.ios" 28 | local nfl = require "org.conman.nfl" 29 | local coroutine = require "coroutine" 30 | 31 | local _VERSION = _VERSION 32 | local tostring = tostring 33 | local setmetatable = setmetatable 34 | local assert = assert 35 | local ipairs = ipairs 36 | 37 | if _VERSION == "Lua 5.1" then 38 | module(...) 39 | else 40 | _ENV = {} -- luacheck: ignore 41 | end 42 | 43 | -- ********************************************************************** 44 | -- usage: ios,handler = create_handler(conn,remote) 45 | -- desc: Create the event handler for handing network packets 46 | -- input: conn (userdata/socket) connected socket 47 | -- remote (userdata/address) remote connection 48 | -- return: ios (table) I/O object (similar to what io.open() returns) 49 | -- handler (function) event handler 50 | -- ********************************************************************** 51 | 52 | local function create_handler(conn,remote) 53 | local ios = mkios() 54 | ios.__socket = conn 55 | ios.__remote = remote 56 | ios.__output = "" 57 | ios.__rbytes = 0 58 | ios.__wbytes = 0 59 | 60 | ios._refill = function() 61 | return coroutine.yield() 62 | end 63 | 64 | ios._drain = function(self,data) 65 | local bytes,err = self.__socket:send(nil,data) 66 | if err ~= 0 then 67 | syslog('error',"socket:send() = %s",errno[err]) 68 | return false,errno[err],err 69 | end 70 | 71 | ios.__wbytes = self.__wbytes + bytes; 72 | if bytes < #data then 73 | nfl.SOCKETS:update(self.__socket,'w') 74 | coroutine.yield() 75 | data = data:sub(bytes + 1,-1) 76 | return self:_drain(data) 77 | end 78 | return true 79 | end 80 | 81 | ios.close = function(self) 82 | -- ----------------------------------------------------------------- 83 | -- XXX - this call to assert() seems to remove a bunch of calls to 84 | -- epoll_ctl() that error out under Linux. Okay. 85 | -- ----------------------------------------------------------------- 86 | assert(self.__socket:_tofd() >= 0) 87 | self:flush() 88 | nfl.SOCKETS:remove(self.__socket) 89 | local err = self.__socket:close() 90 | return err == 0,errno[err],err 91 | end 92 | 93 | if _VERSION >= "Lua 5.2" then 94 | local mt = {} 95 | mt.__gc = ios.close 96 | if _VERSION >= "Lua 5.4" then 97 | mt.__close = ios.close 98 | end 99 | setmetatable(ios,mt) 100 | end 101 | 102 | return ios,function(event) 103 | assert(not (event.read and event.write)) 104 | 105 | if event.hangup then 106 | ios._eof = true 107 | nfl.schedule(ios.__co,"") 108 | return 109 | end 110 | 111 | if event.read then 112 | local _,packet,err = ios.__socket:recv() 113 | if packet then 114 | ios._eof = #packet == 0 115 | nfl.schedule(ios.__co,packet) 116 | else 117 | if err ~= errno.EAGAIN then 118 | syslog('error',"socket:recv() = %s",errno[err]) 119 | nfl.schedule(ios.__co,false,errno[err],err) 120 | end 121 | end 122 | end 123 | 124 | if event.write then 125 | nfl.SOCKETS:update(ios.__socket,'r') 126 | nfl.schedule(ios.__co,true) 127 | end 128 | end 129 | end 130 | 131 | -- ********************************************************************** 132 | -- Usage: sock,errmsg = listens(sock,mainf) 133 | -- Desc: Initialize a listening TCP socket 134 | -- Input: sock (userdata/socket) bound socket 135 | -- mainf (function) main handler for service 136 | -- Return: sock (userdata) socket used for listening, false on error 137 | -- errmsg (string) error message 138 | -- ********************************************************************** 139 | 140 | function listens(sock,mainf) 141 | nfl.SOCKETS:insert(sock,'r',function() 142 | local conn,remote,err = sock:accept() 143 | 144 | if not conn then 145 | syslog('error',"sock:accept() = %s",errno[err]) 146 | return 147 | end 148 | 149 | conn.nonblock = true 150 | conn.nodelay = true 151 | local ios,packet_handler = create_handler(conn,remote) 152 | ios.__co = nfl.spawn(mainf,ios) 153 | nfl.SOCKETS:insert(conn,'r',packet_handler) 154 | end) 155 | 156 | return sock 157 | end 158 | 159 | -- ********************************************************************** 160 | -- Usage: sock,errmsg = listena(addr,mainf) 161 | -- Desc: Initalize a listening TCP socket 162 | -- Input: addr (userdata/address) IP address 163 | -- mainf (function) main handler for service 164 | -- Return: sock (userdata) socket used for listening, false on error 165 | -- errmsg (string) error message 166 | -- ********************************************************************** 167 | 168 | function listena(addr,mainf) 169 | local sock,err = net.socket(addr.family,'tcp') 170 | 171 | if not sock then 172 | return false,errno[err] 173 | end 174 | 175 | sock.reuseaddr = true 176 | sock.nonblock = true 177 | sock:bind(addr) 178 | sock:listen() 179 | return listens(sock,mainf) 180 | end 181 | 182 | -- ********************************************************************** 183 | -- Usage: listen(host,port,mainf) 184 | -- Desc: Initalize a listening TCP socket 185 | -- Input: host (string) address to bind to 186 | -- port (string integer) port 187 | -- mainf (function) main handler for service 188 | -- ********************************************************************** 189 | 190 | function listen(host,port,mainf) 191 | return listena(net.address2(host,'any','tcp',port)[1],mainf) 192 | end 193 | 194 | -- ********************************************************************** 195 | -- Usage: ios = tcp.connecta(addr[,to]) 196 | -- Desc: Connect to a remote address 197 | -- Input: addr (userdata/address) IP address 198 | -- to (number/optinal) timout the operation after to seconds 199 | -- Return: ios (table) Input/Output object (nil on error) 200 | -- ********************************************************************** 201 | 202 | function connecta(addr,to) 203 | if not addr then return nil end 204 | 205 | local sock,err = net.socket(addr.family,'tcp') 206 | 207 | if not sock then 208 | syslog('error',"socket(TCP) = %s",errno[err]) 209 | return 210 | end 211 | 212 | sock.nonblock = true 213 | local ios,packet_handler = create_handler(sock,addr) 214 | ios.__co = coroutine.running() 215 | 216 | -- ------------------------------------------------------------ 217 | -- In POSIXland, a non-blocking socket doing a connect become available 218 | -- when it's ready for writing. So we install a 'write' trigger, then 219 | -- call connect() and yield. When we return, it's connected (unless we're 220 | -- optionally timing out the operation). 221 | -- ------------------------------------------------------------ 222 | 223 | nfl.SOCKETS:insert(sock,'w',packet_handler) 224 | if to then nfl.timeout(to,false,errno[errno.ETIMEDOUT]) end 225 | sock:connect(addr) 226 | local okay,err1 = coroutine.yield() 227 | if to then nfl.timeout(0) end 228 | 229 | if not okay then 230 | nfl.SOCKETS:remove(sock) 231 | sock:close() 232 | syslog('error',"sock:connect(%s) = %s",tostring(addr),err1) 233 | return nil 234 | end 235 | 236 | if ios._eof then 237 | ios:close() 238 | return nil 239 | else 240 | return ios 241 | end 242 | end 243 | 244 | -- ********************************************************************** 245 | -- Usage: ios = tcp.connect(host,port[,to]) 246 | -- Desc: Connect to a remote host 247 | -- Input: host (string) IP address 248 | -- port (string number) port to connect to 249 | -- to (number/optioal) timeout the operation after to seconds 250 | -- Return: ios (table) Input/Output object (nil on error) 251 | -- ********************************************************************** 252 | 253 | function connect(host,port,to) 254 | local addr = net.address2(host,'any','tcp',port) 255 | if addr then 256 | for _,a in ipairs(addr) do 257 | local conn = connecta(a,to) 258 | if conn then 259 | return conn 260 | end 261 | end 262 | end 263 | end 264 | 265 | -- ********************************************************************** 266 | 267 | if _VERSION >= "Lua 5.2" then 268 | return _ENV -- luacheck: ignore 269 | end 270 | -------------------------------------------------------------------------------- /lua/string.lua: -------------------------------------------------------------------------------- 1 | -- *************************************************************** 2 | -- 3 | -- Copyright 2010 by Sean Conner. All Rights Reserved. 4 | -- 5 | -- This library is free software; you can redistribute it and/or modify it 6 | -- under the terms of the GNU Lesser General Public License as published by 7 | -- the Free Software Foundation; either version 3 of the License, or (at your 8 | -- option) any later version. 9 | -- 10 | -- This library is distributed in the hope that it will be useful, but 11 | -- WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 12 | -- or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public 13 | -- License for more details. 14 | -- 15 | -- You should have received a copy of the GNU Lesser General Public License 16 | -- along with this library; if not, see . 17 | -- 18 | -- Comments, questions and criticisms can be sent to: sean@conman.org 19 | -- 20 | -- ******************************************************************** 21 | -- luacheck: globals wrapt metaphone compare comparen mksplit split 22 | -- luacheck: globals template filetemplate wrap safeascii safeutf8 23 | -- luacheck: globals comparei 24 | -- luacheck: ignore 611 25 | 26 | local strcore = require "org.conman.strcore" 27 | local lpeg = require "lpeg" 28 | local string = require "string" 29 | local table = require "table" 30 | local io = require "io" 31 | 32 | local _VERSION = _VERSION 33 | local type = type 34 | local tostring = tostring 35 | 36 | if _VERSION == "Lua 5.1" then 37 | module("org.conman.string") 38 | else 39 | _ENV = {} 40 | end 41 | 42 | metaphone = strcore.metaphone 43 | compare = strcore.compare 44 | comparen = strcore.comparen 45 | comparei = strcore.comparei 46 | wrapt = strcore.wrapt 47 | safeascii = strcore.safeascii 48 | safeutf8 = strcore.safeutf8 49 | 50 | -- ******************************************************************** 51 | 52 | function mksplit(delim) 53 | delim = lpeg.P(delim or ':') 54 | local char = lpeg.C((lpeg.P(1) - delim)^0) 55 | 56 | return lpeg.Ct(char * (delim * char)^0) 57 | end 58 | 59 | -- ******************************************************************** 60 | 61 | function split(s,delim) 62 | local sp = mksplit(delim) 63 | return sp:match(s) 64 | end 65 | 66 | -- ******************************************************************** 67 | 68 | function template(temp,callbacks,data) 69 | local function cmd(tag) 70 | local word = string.sub(tag,3,-3) 71 | 72 | if type(callbacks[word]) == 'string' then 73 | return callbacks[word] 74 | elseif type(callbacks[word]) == 'function' then 75 | return callbacks[word](data) 76 | else 77 | return tostring(callbacks[word]) 78 | end 79 | end 80 | 81 | local s = string.gsub(temp,"%%{[%w%.]+}%%",cmd) 82 | return s 83 | end 84 | 85 | -- ******************************************************************** 86 | 87 | function filetemplate(temp,callbacks,data) 88 | local f = io.open(temp,"r") 89 | local d = f:read("*a") 90 | f:close() 91 | return template(d,callbacks,data) 92 | end 93 | 94 | -- ******************************************************************** 95 | 96 | function wrap(s,margin,lead) 97 | lead = lead or "" 98 | local res = wrapt(s,margin) 99 | 100 | -- ----------------------------------------------------------------------- 101 | -- insert lead into the first position. We then convert the table into a 102 | -- string, separated by a newline and the lead. This conforms to the 103 | -- behavior of the C based version of this function. 104 | -- ----------------------------------------------------------------------- 105 | 106 | table.insert(res,1,lead) 107 | return table.concat(res,"\n" .. lead) 108 | end 109 | 110 | -- ******************************************************************** 111 | 112 | if _VERSION >= "Lua 5.2" then 113 | return _ENV 114 | end 115 | -------------------------------------------------------------------------------- /lua/table.lua: -------------------------------------------------------------------------------- 1 | -- *************************************************************** 2 | -- 3 | -- Copyright 2010 by Sean Conner. All Rights Reserved. 4 | -- 5 | -- This library is free software; you can redistribute it and/or modify it 6 | -- under the terms of the GNU Lesser General Public License as published by 7 | -- the Free Software Foundation; either version 3 of the License, or (at your 8 | -- option) any later version. 9 | -- 10 | -- This library is distributed in the hope that it will be useful, but 11 | -- WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 12 | -- or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public 13 | -- License for more details. 14 | -- 15 | -- You should have received a copy of the GNU Lesser General Public License 16 | -- along with this library; if not, see . 17 | -- 18 | -- Comments, questions and criticisms can be sent to: sean@conman.org 19 | -- 20 | -- ******************************************************************** 21 | -- luacheck: globals safestring dump_value dump keepset 22 | -- luacheck: ignore 611 23 | 24 | local _VERSION = _VERSION 25 | local math = require "math" 26 | local string = require "string" 27 | local io = require "io" 28 | local ipairs = ipairs 29 | local pairs = pairs 30 | local tostring = tostring 31 | local type = type 32 | local pcall = pcall 33 | local getmetatable = getmetatable 34 | 35 | if _VERSION == "Lua 5.1" then 36 | module("org.conman.table") 37 | else 38 | _ENV = {} 39 | end 40 | 41 | -- ******************************************************************* 42 | 43 | local char_trans = 44 | { 45 | ['\a'] = '\\a', 46 | ['\b'] = '\\b', 47 | ['\t'] = '\\t', 48 | ['\n'] = '\\n', 49 | ['\v'] = '\\v', 50 | ['\f'] = '\\f', 51 | ['\r'] = '\\r', 52 | ['"'] = '\\"', 53 | ['\\'] = '\\\\', 54 | } 55 | 56 | function safestring(v) 57 | if type(v) == 'string' then 58 | return '"' .. v:gsub(".",function(c) 59 | if char_trans[c] then 60 | return char_trans[c] 61 | end 62 | 63 | local b = c:byte() 64 | 65 | if b < 32 or b > 126 then 66 | return string.format("\\%03d",b) 67 | else 68 | return c 69 | end 70 | end) .. '"' 71 | else 72 | return tostring(v) 73 | end 74 | end 75 | 76 | -- ************************************************************* 77 | 78 | function dump_value(name,value,path,level,marked) 79 | path = path or "" 80 | level = level or 0 81 | marked = marked or {} 82 | local lead = string.rep(" ",level) 83 | 84 | if type(name) == "nil" then 85 | return "" 86 | elseif type(name) == "number" then 87 | if _VERSION >= "Lua 5.3" then 88 | if math.type(name) == 'integer' then 89 | name = string.format("[%d]",name) 90 | else 91 | name = string.format("[%f]",name) 92 | end 93 | else 94 | name = string.format("[%f]",name) 95 | end 96 | elseif type(name) == 'string' then 97 | if not name:match "^[A-Za-z_][A-Za-z0-9_]*$" then 98 | name = "[" .. safestring(name) .. "]" 99 | end 100 | else 101 | name = "[" .. safestring(name) .. "]" 102 | end 103 | 104 | if type(value) == "nil" then 105 | return "" 106 | elseif type(value) == "boolean" then 107 | return string.format("%s%s = %s,\n",lead,name,tostring(value)) 108 | elseif type(value) == "number" then 109 | return string.format("%s%s = %f,\n",lead,name,value) 110 | elseif type(value) == "string" then 111 | value = safestring(value) 112 | return string.format("%s%s = %s,\n",lead,name,value) 113 | elseif type(value) == "table" then 114 | 115 | if marked[tostring(value)] ~= nil then 116 | return string.format("%s%s = %s,\n",lead,name,marked[tostring(value)]) 117 | else 118 | if path == "" then 119 | marked[tostring(value)] = name 120 | else 121 | marked[tostring(value)] = path .. "." .. name 122 | end 123 | end 124 | 125 | local s = string.format("%s%s =\n%s{\n",lead,name,lead) 126 | 127 | for k,v in pairs(value) do 128 | s = s .. dump_value(k,v,marked[tostring(value)],level + 2,marked) 129 | end 130 | 131 | s = s .. string.format("%s}",lead) 132 | if level > 0 then s = s .. string.format(",") end 133 | 134 | if getmetatable(value) ~= nil then 135 | s = s .. string.format("--METATABLE\n",lead) 136 | else 137 | s = s .. string.format("\n",lead) 138 | end 139 | return s 140 | 141 | elseif type(value) == "function" then 142 | local err,func = pcall(string.dump,value) 143 | if err == false then 144 | return string.format("%s%s = C_FUNCTION\n",lead,name) 145 | else 146 | return string.format("%s%s = loadstring(%q),\n",lead,name,func) 147 | end 148 | elseif type(value) == "thread" then 149 | return string.format("%s%s = THREAD\n",lead,name) 150 | elseif type(value) == "userdata" then 151 | local mt = getmetatable(value) 152 | 153 | if mt and (mt.__pairs or mt.__ipairs) then 154 | local s = string.format("%s%s =\n%s{\n",lead,name,lead) 155 | 156 | if mt.__ipairs then 157 | for i,v in ipairs(value) do 158 | s = s .. dump_value(i,v,marked[tostring(value)],level + 2,marked) 159 | end 160 | end 161 | 162 | if mt.__pairs then 163 | for k,v in pairs(value) do 164 | s = s .. dump_value(k,v,marked[tostring(value)],level + 2,marked) 165 | end 166 | end 167 | 168 | return s .. string.format("%s} --USERDATA\n",lead) 169 | else 170 | return string.format("%s%s = %s\n",lead,name,tostring(value)) 171 | end 172 | else 173 | error("unsupported data type!") 174 | end 175 | end 176 | 177 | -- ********************************************************** 178 | 179 | function dump(name,value) 180 | io.stdout:write(dump_value(name,value),'\n') 181 | end 182 | 183 | -- *********************************************************** 184 | 185 | function keepset(t,name,value) 186 | if t[name] == nil then 187 | t[name] = value 188 | elseif type(t[name]) == 'table' then 189 | t[name][#t[name] + 1] = value 190 | else 191 | t[name] = { t[name] , value } 192 | end 193 | 194 | return t 195 | end 196 | 197 | -- ************************************************************ 198 | 199 | if _VERSION >= "Lua 5.2" then 200 | return _ENV 201 | end 202 | 203 | -------------------------------------------------------------------------------- /lua/unix.lua: -------------------------------------------------------------------------------- 1 | -- *************************************************************** 2 | -- 3 | -- Copyright 2010 by Sean Conner. All Rights Reserved. 4 | -- 5 | -- This library is free software; you can redistribute it and/or modify it 6 | -- under the terms of the GNU Lesser General Public License as published by 7 | -- the Free Software Foundation; either version 3 of the License, or (at your 8 | -- option) any later version. 9 | -- 10 | -- This library is distributed in the hope that it will be useful, but 11 | -- WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 12 | -- or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public 13 | -- License for more details. 14 | -- 15 | -- You should have received a copy of the GNU Lesser General Public License 16 | -- along with this library; if not, see . 17 | -- 18 | -- Comments, questions and criticisms can be sent to: sean@conman.org 19 | -- 20 | -- ******************************************************************** 21 | -- luacheck: globals users groups paths 22 | -- luacheck: ignore 611 23 | 24 | local _VERSION = _VERSION 25 | local setmetatable = setmetatable 26 | local tonumber = tonumber 27 | 28 | local fsys = require "org.conman.fsys" 29 | local lpeg = require "lpeg" 30 | local io = require "io" 31 | local os = require "os" 32 | 33 | if _VERSION == "Lua 5.1" then 34 | module("org.conman.unix") 35 | else 36 | _ENV = {} 37 | end 38 | 39 | local text = lpeg.C((lpeg.R" ~" - lpeg.P":")^0) 40 | local number = lpeg.R"09"^1 / tonumber 41 | 42 | -- ************************************************************************ 43 | 44 | users = {} do 45 | local entry = lpeg.Ct( 46 | lpeg.Cg(text, "userid") * lpeg.P":" 47 | * lpeg.Cg(text, "passwd") * lpeg.P":" 48 | * lpeg.Cg(number,"uid") * lpeg.P":" 49 | * lpeg.Cg(number,"gid") * lpeg.P":" 50 | * lpeg.Cg(text, "name") * lpeg.P":" 51 | * lpeg.Cg(text, "home") * lpeg.P":" 52 | * lpeg.Cg(text, "shell") 53 | ) 54 | 55 | for line in io.lines("/etc/passwd") do 56 | local user = entry:match(line) 57 | if user then 58 | users[user.userid] = user 59 | users[user.uid] = user 60 | end 61 | end 62 | end 63 | 64 | -- ************************************************************************* 65 | 66 | groups = {} do 67 | local name = lpeg.C((lpeg.R" ~" - lpeg.S":,")^1) 68 | local users = lpeg.Ct(name * (lpeg.P"," * name)^0) 69 | + lpeg.P(true) / function() return {} end 70 | local entry = lpeg.Ct( 71 | lpeg.Cg(text, "name") * lpeg.P":" 72 | * lpeg.Cg(text, "passwd") * lpeg.P":" 73 | * lpeg.Cg(number,"gid") * lpeg.P":" 74 | * lpeg.Cg(users, "users") 75 | ) 76 | 77 | for line in io.lines("/etc/group") do 78 | local group = entry:match(line) 79 | if group then 80 | groups[group.name] = group 81 | groups[group.gid] = group 82 | end 83 | end 84 | end 85 | 86 | -- ************************************************************************ 87 | 88 | paths = setmetatable({},{ __index = function(t,k) 89 | for path in os.getenv("PATH"):gmatch "[^:]+" do 90 | if fsys.access(path .. "/" .. k,"X") then 91 | t[k] = path .. '/' .. k 92 | return t[k] 93 | end 94 | end 95 | end}) 96 | 97 | if _VERSION >= "Lua 5.2" then 98 | return _ENV 99 | end 100 | -------------------------------------------------------------------------------- /lua/zip.lua: -------------------------------------------------------------------------------- 1 | -- *************************************************************** 2 | -- 3 | -- Copyright 2014 by Sean Conner. All Rights Reserved. 4 | -- 5 | -- This library is free software; you can redistribute it and/or modify it 6 | -- under the terms of the GNU Lesser General Public License as published by 7 | -- the Free Software Foundation; either version 3 of the License, or (at your 8 | -- option) any later version. 9 | -- 10 | -- This library is distributed in the hope that it will be useful, but 11 | -- WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 12 | -- or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public 13 | -- License for more details. 14 | -- 15 | -- You should have received a copy of the GNU Lesser General Public License 16 | -- along with this library; if not, see . 17 | -- 18 | -- Comments, questions and criticisms can be sent to: sean@conman.org 19 | -- 20 | -- -------------------------------------------------------------------- 21 | -- 22 | -- To effectively use this module, you should understand the ZIP file 23 | -- format. The definitive guide to this format is at 24 | -- 25 | -- http://www.pkware.com/appnote 26 | -- 27 | -- NOTE: https://bugzilla.mozilla.org/show_bug.cgi?id=1534483 28 | -- 29 | -- ******************************************************************** 30 | -- luacheck: globals magic idiv 31 | -- luacheck: ignore 611 32 | 33 | local _VERSION = _VERSION 34 | local pairs = pairs 35 | local setmetatable = setmetatable 36 | 37 | local table = require "table" 38 | local math = require "math" 39 | 40 | if _VERSION == "Lua 5.1" then 41 | module("org.conman.zip") 42 | else 43 | _ENV = {} 44 | end 45 | 46 | -- ************************************************************************ 47 | 48 | magic = 49 | { 50 | EOCD = "PK\005\006", 51 | DIR = "PK\001\002", 52 | FILE = "PK\003\004", 53 | DATA = "PK\007\008", 54 | ARCHIVE = "PK\006\008", 55 | SIGNATURE = "PK\005\005", 56 | EOCD64 = "PK\006\006", 57 | EOCDL64 = "PK\006\007", 58 | 59 | } 60 | 61 | local function reverse_index(tab) 62 | local keys = {} 63 | for name in pairs(tab) do 64 | table.insert(keys,name) 65 | end 66 | 67 | for i = 1 , #keys do 68 | local k = keys[i] 69 | local v = tab[k] 70 | tab[v] = k 71 | end 72 | 73 | return setmetatable(tab,{ 74 | __index = function(_,key) 75 | if type(key) == 'number' then 76 | return '-' 77 | elseif type(key) == 'string' then 78 | return 0 79 | end 80 | end 81 | }) 82 | end 83 | 84 | os = reverse_index { -- luacheck: ignore 85 | ["MS-DOS"] = 0, 86 | ["Amiga"] = 1, 87 | ["OpenVMS"] = 2, 88 | ["UNIX"] = 3, 89 | ["VM/CMS"] = 4, 90 | ["Atari ST"] = 5, 91 | ["OS/2"] = 6, 92 | ["Macintosh"] = 7, 93 | ["Z-System"] = 8, 94 | ["CP/M"] = 9, 95 | ["Windows"] = 10, 96 | ["MVS"] = 11, 97 | ["VSE"] = 12, 98 | ["Acorn Risc"] = 13, 99 | ["VFAT"] = 14, 100 | ["alternative MVS"] = 15, 101 | ["BeOS"] = 16, 102 | ["Tandem"] = 17, 103 | ["OS/400"] = 18, 104 | ["Darwin"] = 19, 105 | } 106 | 107 | -- ************************************************************************ 108 | 109 | function idiv(up,down) 110 | local q = math.floor(up/down) 111 | local r = up % down 112 | return q,r 113 | end 114 | 115 | -- ************************************************************************ 116 | 117 | if _VERSION >= "Lua 5.2" then 118 | return _ENV 119 | end 120 | 121 | -------------------------------------------------------------------------------- /other/pollset-epoll.c: -------------------------------------------------------------------------------- 1 | /*************************************************************************** 2 | * 3 | * Copyright 2013 by Sean Conner. 4 | * 5 | * This library is free software; you can redistribute it and/or modify it 6 | * under the terms of the GNU Lesser General Public License as published by 7 | * the Free Software Foundation; either version 3 of the License, or (at your 8 | * option) any later version. 9 | * 10 | * This library is distributed in the hope that it will be useful, but 11 | * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 12 | * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public 13 | * License for more details. 14 | * 15 | * You should have received a copy of the GNU Lesser General Public License 16 | * along with this library; if not, see . 17 | * 18 | * Comments, questions and criticisms can be sent to: sean@conman.org 19 | * 20 | *************************************************************************/ 21 | 22 | #ifndef __GNUC__ 23 | # define __attribute__(x) 24 | #endif 25 | 26 | #include 27 | 28 | #include 29 | #include 30 | 31 | #include 32 | #include 33 | 34 | #if !defined(LUA_VERSION_NUM) || LUA_VERSION_NUM != 501 35 | # error This module is for Lua 5.1 36 | #endif 37 | 38 | #define TYPE_POLL "org.conman.pollset" 39 | 40 | /********************************************************************/ 41 | 42 | typedef struct 43 | { 44 | int efh; 45 | int ref; 46 | size_t idx; 47 | } epollset__t; 48 | 49 | /**********************************************************************/ 50 | 51 | static int epollset_toevents(lua_State *const L,int idx) 52 | { 53 | int events = 0; 54 | 55 | if (lua_istable(L,idx)) 56 | { 57 | lua_getfield(L,idx,"read"); 58 | events |= lua_isboolean(L,-1) ? EPOLLIN : 0; 59 | lua_getfield(L,idx,"write"); 60 | events |= lua_isboolean(L,-1) ? EPOLLOUT : 0; 61 | lua_getfield(L,idx,"priority"); 62 | events |= lua_isboolean(L,-1) ? EPOLLPRI : 0; 63 | lua_getfield(L,idx,"error"); 64 | events |= lua_isboolean(L,-1) ? EPOLLERR : 0; 65 | lua_getfield(L,idx,"hangup"); 66 | events |= lua_isboolean(L,-1) ? EPOLLHUP : 0; 67 | lua_getfield(L,idx,"trigger"); 68 | events |= lua_isboolean(L,-1) ? EPOLLET : 0; 69 | lua_getfield(L,idx,"oneshot"); 70 | events |= lua_isboolean(L,-1) ? EPOLLONESHOT : 0; 71 | lua_pop(L,7); 72 | } 73 | else if (lua_isstring(L,idx)) 74 | { 75 | const char *flags = lua_tostring(L,idx); 76 | for ( ; *flags ; flags++) 77 | { 78 | switch(*flags) 79 | { 80 | case 'r': events |= EPOLLIN; break; 81 | case 'w': events |= EPOLLOUT; break; 82 | case 'p': events |= EPOLLPRI; break; 83 | case 'e': events |= EPOLLERR; break; 84 | case 'h': events |= EPOLLHUP; break; 85 | case 't': events |= EPOLLET; break; 86 | case '1': events |= EPOLLONESHOT; break; 87 | default: break; 88 | } 89 | } 90 | } 91 | else if (lua_isnil(L,idx)) 92 | events |= EPOLLIN; 93 | else 94 | return luaL_error(L,"expected table or string"); 95 | 96 | return events; 97 | } 98 | 99 | /**********************************************************************/ 100 | 101 | static void epollset_pushevents(lua_State *const L,int events) 102 | { 103 | lua_createtable(L,0,8); 104 | lua_pushboolean(L,(events & EPOLLIN) != 0); 105 | lua_setfield(L,-2,"read"); 106 | lua_pushboolean(L,(events & EPOLLOUT) != 0); 107 | lua_setfield(L,-2,"write"); 108 | lua_pushboolean(L,(events & EPOLLPRI) != 0); 109 | lua_setfield(L,-2,"priority"); 110 | lua_pushboolean(L,(events & EPOLLERR) != 0); 111 | lua_setfield(L,-2,"error"); 112 | lua_pushboolean(L,(events & EPOLLHUP) != 0); 113 | lua_setfield(L,-2,"hangup"); 114 | lua_pushboolean(L,(events & EPOLLET) != 0); 115 | lua_setfield(L,-2,"trigger"); 116 | lua_pushboolean(L,(events & EPOLLONESHOT) != 0); 117 | lua_setfield(L,-2,"oneshot"); 118 | } 119 | 120 | /**********************************************************************/ 121 | 122 | static int epollset_lua(lua_State *const L) 123 | { 124 | epollset__t *set; 125 | 126 | set = lua_newuserdata(L,sizeof(epollset__t)); 127 | set->idx = 0; 128 | set->efh = epoll_create(10); 129 | 130 | if (set->efh == -1) 131 | { 132 | lua_pushnil(L); 133 | lua_pushinteger(L,errno); 134 | return 2; 135 | } 136 | 137 | lua_createtable(L,0,0); 138 | set->ref = luaL_ref(L,LUA_REGISTRYINDEX); 139 | 140 | luaL_getmetatable(L,TYPE_POLL); 141 | lua_setmetatable(L,-2); 142 | return 1; 143 | } 144 | 145 | /**********************************************************************/ 146 | 147 | static int epollmeta___tostring(lua_State *const L) 148 | { 149 | lua_pushfstring(L,"pollset (%p)",lua_touserdata(L,1)); 150 | return 1; 151 | } 152 | 153 | /**********************************************************************/ 154 | 155 | static int epollmeta___gc(lua_State *const L) 156 | { 157 | epollset__t *set = luaL_checkudata(L,1,TYPE_POLL); 158 | luaL_unref(L,LUA_REGISTRYINDEX,set->ref); 159 | close(set->efh); 160 | return 0; 161 | } 162 | 163 | /**********************************************************************/ 164 | 165 | static int epollmeta_insert(lua_State *const L) 166 | { 167 | epollset__t *set = luaL_checkudata(L,1,TYPE_POLL); 168 | int fh = luaL_checkinteger(L,2); 169 | struct epoll_event event; 170 | 171 | lua_settop(L,4); 172 | 173 | event.events = epollset_toevents(L,3); 174 | event.data.fd = fh; 175 | 176 | if (epoll_ctl(set->efh,EPOLL_CTL_ADD,fh,&event) < 0) 177 | { 178 | lua_pushinteger(L,errno); 179 | return 1; 180 | } 181 | 182 | lua_pushinteger(L,set->ref); 183 | lua_gettable(L,LUA_REGISTRYINDEX); 184 | lua_pushinteger(L,fh); 185 | 186 | if (lua_isnil(L,4)) 187 | lua_pushvalue(L,2); 188 | else 189 | lua_pushvalue(L,4); 190 | 191 | lua_settable(L,-3); 192 | 193 | set->idx++; 194 | lua_pushinteger(L,0); 195 | return 1; 196 | } 197 | 198 | /**********************************************************************/ 199 | 200 | static int epollmeta_update(lua_State *const L) 201 | { 202 | epollset__t *set = luaL_checkudata(L,1,TYPE_POLL); 203 | int fh = luaL_checkinteger(L,2); 204 | struct epoll_event event; 205 | 206 | lua_settop(L,3); 207 | 208 | event.events = epollset_toevents(L,3); 209 | event.data.fd = fh; 210 | errno = 0; 211 | 212 | epoll_ctl(set->efh,EPOLL_CTL_MOD,fh,&event); 213 | lua_pushinteger(L,errno); 214 | return 1; 215 | } 216 | 217 | /**********************************************************************/ 218 | 219 | static int epollmeta_remove(lua_State *const L) 220 | { 221 | epollset__t *set = luaL_checkudata(L,1,TYPE_POLL); 222 | int fh = luaL_checkinteger(L,2); 223 | struct epoll_event event; 224 | 225 | if (epoll_ctl(set->efh,EPOLL_CTL_DEL,fh,&event) < 0) 226 | { 227 | lua_pushinteger(L,errno); 228 | return 1; 229 | } 230 | 231 | lua_pushinteger(L,set->ref); 232 | lua_gettable(L,LUA_REGISTRYINDEX); 233 | lua_pushinteger(L,fh); 234 | lua_pushnil(L); 235 | lua_settable(L,-3); 236 | 237 | set->idx--; 238 | lua_pushinteger(L,0); 239 | return 1; 240 | } 241 | 242 | /**********************************************************************/ 243 | 244 | static int epollmeta_events(lua_State *const L) 245 | { 246 | epollset__t *set = luaL_checkudata(L,1,TYPE_POLL); 247 | lua_Number dtimeout = luaL_optnumber(L,2,-1.0); 248 | int timeout; 249 | int count; 250 | size_t idx; 251 | int i; 252 | 253 | if (dtimeout < 0) 254 | timeout = -1; 255 | else 256 | timeout = (int)(dtimeout * 1000.0); 257 | 258 | struct epoll_event events[set->idx]; 259 | 260 | count = epoll_wait(set->efh,events,set->idx,timeout); 261 | 262 | if (count < 0) 263 | { 264 | lua_pushnil(L); 265 | lua_pushinteger(L,errno); 266 | return 2; 267 | } 268 | 269 | lua_pushinteger(L,set->ref); 270 | lua_gettable(L,LUA_REGISTRYINDEX); 271 | 272 | lua_createtable(L,set->idx,0); 273 | for (idx = 1 , i = 0 ; i < count ; i++) 274 | { 275 | lua_pushnumber(L,idx++); 276 | epollset_pushevents(L,events[i].events); 277 | lua_pushinteger(L,events[i].data.fd); 278 | lua_gettable(L,-5); 279 | lua_setfield(L,-2,"obj"); 280 | lua_settable(L,-3); 281 | } 282 | 283 | lua_pushinteger(L,0); 284 | return 2; 285 | } 286 | 287 | /**********************************************************************/ 288 | 289 | static int epollmeta__POLL(lua_State *const L) 290 | { 291 | lua_pushliteral(L,"epoll"); 292 | return 1; 293 | } 294 | 295 | /**********************************************************************/ 296 | 297 | static const luaL_Reg m_epollmeta[] = 298 | { 299 | { "__tostring" , epollmeta___tostring } , 300 | { "__gc" , epollmeta___gc } , 301 | { "insert" , epollmeta_insert } , 302 | { "update" , epollmeta_update } , 303 | { "remove" , epollmeta_remove } , 304 | { "events" , epollmeta_events } , 305 | { "POLL" , epollmeta__POLL } , 306 | { NULL , NULL } 307 | }; 308 | 309 | /**********************************************************************/ 310 | 311 | int luaopen_epoll(lua_State *const L) 312 | { 313 | luaL_newmetatable(L,TYPE_POLL); 314 | luaL_register(L,NULL,m_epollmeta); 315 | lua_pushvalue(L,-1); 316 | lua_setfield(L,-1,"__index"); 317 | 318 | lua_pushcfunction(L,epollset_lua); 319 | return 1; 320 | } 321 | 322 | /**********************************************************************/ 323 | -------------------------------------------------------------------------------- /other/pollset-poll.c: -------------------------------------------------------------------------------- 1 | /*************************************************************************** 2 | * 3 | * Copyright 2013 by Sean Conner. 4 | * 5 | * This library is free software; you can redistribute it and/or modify it 6 | * under the terms of the GNU Lesser General Public License as published by 7 | * the Free Software Foundation; either version 3 of the License, or (at your 8 | * option) any later version. 9 | * 10 | * This library is distributed in the hope that it will be useful, but 11 | * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 12 | * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public 13 | * License for more details. 14 | * 15 | * You should have received a copy of the GNU Lesser General Public License 16 | * along with this library; if not, see . 17 | * 18 | * Comments, questions and criticisms can be sent to: sean@conman.org 19 | * 20 | *************************************************************************/ 21 | 22 | #ifndef __GNUC__ 23 | # define __attribute__(x) 24 | #endif 25 | 26 | #include 27 | 28 | #include 29 | #include 30 | 31 | #include 32 | #include 33 | 34 | #if !defined(LUA_VERSION_NUM) || LUA_VERSION_NUM != 501 35 | # error This module is for Lua 5.1 36 | #endif 37 | 38 | #define TYPE_POLL "org.conman.pollset" 39 | 40 | /********************************************************************/ 41 | 42 | typedef struct 43 | { 44 | struct pollfd *set; 45 | size_t idx; 46 | size_t max; 47 | int ref; 48 | } pollset__t; 49 | 50 | /**********************************************************************/ 51 | 52 | static int pollset_toevents(lua_State *const L,int idx) 53 | { 54 | int events = 0; 55 | 56 | if (lua_istable(L,idx)) 57 | { 58 | lua_getfield(L,idx,"read"); 59 | events |= lua_isboolean(L,-1) ? POLLIN : 0; 60 | lua_getfield(L,idx,"write"); 61 | events |= lua_isboolean(L,-1) ? POLLOUT : 0; 62 | lua_getfield(L,idx,"priority"); 63 | events |= lua_isboolean(L,-1) ? POLLPRI : 0; 64 | lua_getfield(L,idx,"error"); 65 | lua_pop(L,3); 66 | } 67 | else if (lua_isstring(L,idx)) 68 | { 69 | const char *flags = lua_tostring(L,idx); 70 | for ( ; *flags ; flags++) 71 | { 72 | switch(*flags) 73 | { 74 | case 'r': events |= POLLIN; break; 75 | case 'w': events |= POLLOUT; break; 76 | case 'p': events |= POLLPRI; break; 77 | default: break; 78 | } 79 | } 80 | } 81 | else if (lua_isnil(L,idx)) 82 | events |= POLLIN; 83 | else 84 | return luaL_error(L,"expected table or string"); 85 | 86 | return events; 87 | } 88 | 89 | /**********************************************************************/ 90 | 91 | static void pollset_pushevents(lua_State *const L,int events) 92 | { 93 | lua_createtable(L,0,7); 94 | lua_pushboolean(L,(events & POLLIN) != 0); 95 | lua_setfield(L,-2,"read"); 96 | lua_pushboolean(L,(events & POLLOUT) != 0); 97 | lua_setfield(L,-2,"write"); 98 | lua_pushboolean(L,(events & POLLPRI) != 0); 99 | lua_setfield(L,-2,"priority"); 100 | lua_pushboolean(L,(events & POLLERR) != 0); 101 | lua_setfield(L,-2,"error"); 102 | lua_pushboolean(L,(events & POLLHUP) != 0); 103 | lua_setfield(L,-2,"hangup"); 104 | lua_pushboolean(L,(events & POLLNVAL) != 0); 105 | lua_setfield(L,-2,"invalid"); 106 | } 107 | 108 | /**********************************************************************/ 109 | 110 | static int pollset_lua(lua_State *const L) 111 | { 112 | pollset__t *set; 113 | 114 | set = lua_newuserdata(L,sizeof(pollset__t)); 115 | set->set = NULL; 116 | set->idx = 0; 117 | set->max = 0; 118 | 119 | lua_createtable(L,0,0); 120 | set->ref = luaL_ref(L,LUA_REGISTRYINDEX); 121 | 122 | luaL_getmetatable(L,TYPE_POLL); 123 | lua_setmetatable(L,-2); 124 | return 1; 125 | } 126 | 127 | /**********************************************************************/ 128 | 129 | static int pullmeta___tostring(lua_State *const L) 130 | { 131 | lua_pushfstring(L,"pollset (%p)",lua_touserdata(L,1)); 132 | return 1; 133 | } 134 | 135 | /**********************************************************************/ 136 | 137 | static int pullmeta___gc(lua_State *const L) 138 | { 139 | lua_Alloc allocf; 140 | void *ud; 141 | 142 | pollset__t *set = luaL_checkudata(L,1,TYPE_POLL); 143 | luaL_unref(L,LUA_REGISTRYINDEX,set->ref); 144 | allocf = lua_getallocf(L,&ud); 145 | (*allocf)(ud,set->set,set->max * sizeof(struct pollfd),0); 146 | return 0; 147 | } 148 | 149 | /**********************************************************************/ 150 | 151 | static int pullmeta_insert(lua_State *const L) 152 | { 153 | pollset__t *set = luaL_checkudata(L,1,TYPE_POLL); 154 | int fh = luaL_checkinteger(L,2); 155 | 156 | lua_settop(L,4); 157 | 158 | if (set->idx == set->max) 159 | { 160 | struct pollfd *new; 161 | size_t newmax; 162 | lua_Alloc allocf; 163 | void *ud; 164 | 165 | allocf = lua_getallocf(L,&ud); 166 | newmax = set->max + 10; 167 | new = (*allocf)( 168 | ud, 169 | set->set, 170 | set->max * sizeof(struct pollfd), 171 | newmax * sizeof(struct pollfd) 172 | ); 173 | 174 | if (new == NULL) 175 | { 176 | lua_pushinteger(L,ENOMEM); 177 | return 1; 178 | } 179 | 180 | set->set = new; 181 | set->max = newmax; 182 | } 183 | 184 | set->set[set->idx].events = pollset_toevents(L,3); 185 | set->set[set->idx].fd = fh; 186 | 187 | lua_pushinteger(L,set->ref); 188 | lua_gettable(L,LUA_REGISTRYINDEX); 189 | lua_pushinteger(L,fh); 190 | 191 | if (lua_isnil(L,4)) 192 | lua_pushvalue(L,2); 193 | else 194 | lua_pushvalue(L,4); 195 | 196 | lua_settable(L,-3); 197 | 198 | set->idx++; 199 | lua_pushinteger(L,0); 200 | return 1; 201 | } 202 | 203 | /**********************************************************************/ 204 | 205 | static int pullmeta_update(lua_State *const L) 206 | { 207 | pollset__t *set = luaL_checkudata(L,1,TYPE_POLL); 208 | int fh = luaL_checkinteger(L,2); 209 | 210 | lua_settop(L,3); 211 | 212 | for (size_t i = 0 ; i < set->idx ; i++) 213 | { 214 | if (set->set[i].fd == fh) 215 | { 216 | set->set[i].events = pollset_toevents(L,3); 217 | lua_pushinteger(L,0); 218 | return 1; 219 | } 220 | } 221 | 222 | lua_pushinteger(L,EINVAL); 223 | return 1; 224 | } 225 | 226 | /**********************************************************************/ 227 | 228 | static int pullmeta_remove(lua_State *const L) 229 | { 230 | pollset__t *set = luaL_checkudata(L,1,TYPE_POLL); 231 | int fh = luaL_checkinteger(L,2); 232 | 233 | for (size_t i = 0 ; i < set->idx ; i++) 234 | { 235 | if (set->set[i].fd == fh) 236 | { 237 | lua_pushinteger(L,set->ref); 238 | lua_gettable(L,LUA_REGISTRYINDEX); 239 | lua_pushinteger(L,fh); 240 | lua_pushnil(L); 241 | lua_settable(L,-3); 242 | 243 | memmove( 244 | &set->set[i], 245 | &set->set[i+1], 246 | (set->idx - i - 1) * sizeof(struct pollfd) 247 | ); 248 | 249 | set->idx--; 250 | lua_pushinteger(L,0); 251 | return 1; 252 | } 253 | } 254 | 255 | lua_pushinteger(L,EINVAL); 256 | return 1; 257 | } 258 | 259 | /**********************************************************************/ 260 | 261 | static int pullmeta_events(lua_State *const L) 262 | { 263 | pollset__t *set = luaL_checkudata(L,1,TYPE_POLL); 264 | lua_Number dtimeout = luaL_optnumber(L,2,-1.0); 265 | int timeout; 266 | 267 | if (dtimeout < 0) 268 | timeout = -1; 269 | else 270 | timeout = (int)(dtimeout * 1000.0); 271 | 272 | if (poll(set->set,set->idx,timeout) < 0) 273 | { 274 | lua_pushnil(L); 275 | lua_pushinteger(L,errno); 276 | return 2; 277 | } 278 | 279 | lua_pushinteger(L,set->ref); 280 | lua_gettable(L,LUA_REGISTRYINDEX); 281 | 282 | lua_createtable(L,set->idx,0); 283 | for (size_t idx = 1 , i = 0 ; i < set->idx ; i++) 284 | { 285 | if (set->set[i].revents != 0) 286 | { 287 | lua_pushnumber(L,idx++); 288 | pollset_pushevents(L,set->set[i].events); 289 | lua_pushinteger(L,set->set[i].fd); 290 | lua_gettable(L,-5); 291 | lua_setfield(L,-2,"obj"); 292 | lua_settable(L,-3); 293 | } 294 | } 295 | 296 | lua_pushinteger(L,0); 297 | return 2; 298 | } 299 | 300 | /**********************************************************************/ 301 | 302 | static int pullmeta__POLL(lua_State *const L) 303 | { 304 | lua_pushliteral(L,"poll"); 305 | return 1; 306 | } 307 | 308 | /**********************************************************************/ 309 | 310 | static const luaL_Reg m_pullmeta[] = 311 | { 312 | { "__tostring" , pullmeta___tostring } , 313 | { "__gc" , pullmeta___gc } , 314 | { "insert" , pullmeta_insert } , 315 | { "update" , pullmeta_update } , 316 | { "remove" , pullmeta_remove } , 317 | { "events" , pullmeta_events } , 318 | { "POLL" , pullmeta__POLL } , 319 | { NULL , NULL } 320 | }; 321 | 322 | /**********************************************************************/ 323 | 324 | int luaopen_poll(lua_State *const L) 325 | { 326 | luaL_newmetatable(L,TYPE_POLL); 327 | luaL_register(L,NULL,m_pullmeta); 328 | lua_pushvalue(L,-1); 329 | lua_setfield(L,-1,"__index"); 330 | 331 | lua_pushcfunction(L,pollset_lua); 332 | return 1; 333 | } 334 | 335 | /**********************************************************************/ 336 | -------------------------------------------------------------------------------- /other/pollset-select.c: -------------------------------------------------------------------------------- 1 | /*************************************************************************** 2 | * 3 | * Copyright 2013 by Sean Conner. 4 | * 5 | * This library is free software; you can redistribute it and/or modify it 6 | * under the terms of the GNU Lesser General Public License as published by 7 | * the Free Software Foundation; either version 3 of the License, or (at your 8 | * option) any later version. 9 | * 10 | * This library is distributed in the hope that it will be useful, but 11 | * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 12 | * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public 13 | * License for more details. 14 | * 15 | * You should have received a copy of the GNU Lesser General Public License 16 | * along with this library; if not, see . 17 | * 18 | * Comments, questions and criticisms can be sent to: sean@conman.org 19 | * 20 | *************************************************************************/ 21 | 22 | #ifndef __GNUC__ 23 | # define __attribute__(x) 24 | #endif 25 | 26 | #include 27 | #include 28 | 29 | #include 30 | 31 | #include 32 | #include 33 | 34 | #if !defined(LUA_VERSION_NUM) || LUA_VERSION_NUM != 501 35 | # error This module is for Lua 5.1 36 | #endif 37 | 38 | #define TYPE_POLL "org.conman.pollset" 39 | 40 | /********************************************************************/ 41 | 42 | typedef struct 43 | { 44 | fd_set read; 45 | fd_set write; 46 | fd_set except; 47 | int min; 48 | int max; 49 | size_t idx; 50 | int ref; 51 | } selectset__t; 52 | 53 | /**********************************************************************/ 54 | 55 | static void selectset_toevents( 56 | lua_State *const L, 57 | int idx, 58 | selectset__t *set, 59 | int fd 60 | ) 61 | { 62 | if (lua_istable(L,idx)) 63 | { 64 | lua_getfield(L,idx,"read"); 65 | if (lua_isboolean(L,-1)) FD_SET(fd,&set->read); 66 | lua_getfield(L,idx,"write"); 67 | if (lua_isboolean(L,-1)) FD_SET(fd,&set->write); 68 | lua_getfield(L,idx,"except"); 69 | if (lua_isboolean(L,-1)) FD_SET(fd,&set->except); 70 | lua_pop(L,3); 71 | } 72 | else if (lua_isstring(L,idx)) 73 | { 74 | const char *flags = lua_tostring(L,idx); 75 | for ( ; *flags ; flags++) 76 | { 77 | switch(*flags) 78 | { 79 | case 'r': FD_SET(fd,&set->read); break; 80 | case 'w': FD_SET(fd,&set->write); break; 81 | case 'e': FD_SET(fd,&set->except); break; 82 | default: break; 83 | } 84 | } 85 | } 86 | else if (lua_isnil(L,idx)) 87 | FD_SET(fd,&set->read); 88 | else 89 | luaL_error(L,"expected table or string"); 90 | } 91 | 92 | /**********************************************************************/ 93 | 94 | static void selectset_pushevents(lua_State *const L,selectset__t *set,int fd) 95 | { 96 | lua_createtable(L,0,4); 97 | lua_pushboolean(L,FD_ISSET(fd,&set->read)); 98 | lua_setfield(L,-2,"read"); 99 | lua_pushboolean(L,FD_ISSET(fd,&set->write)); 100 | lua_setfield(L,-2,"write"); 101 | lua_pushboolean(L,FD_ISSET(fd,&set->except)); 102 | lua_setfield(L,-2,"except"); 103 | } 104 | 105 | /**********************************************************************/ 106 | 107 | static int selectset_lua(lua_State *const L) 108 | { 109 | selectset__t *set; 110 | 111 | set = lua_newuserdata(L,sizeof(selectset__t)); 112 | FD_ZERO(&set->read); 113 | FD_ZERO(&set->write); 114 | FD_ZERO(&set->except); 115 | set->idx = 0; 116 | set->min = INT_MAX; 117 | set->max = 0; 118 | 119 | lua_createtable(L,0,0); 120 | set->ref = luaL_ref(L,LUA_REGISTRYINDEX); 121 | 122 | luaL_getmetatable(L,TYPE_POLL); 123 | lua_setmetatable(L,-2); 124 | return 1; 125 | } 126 | 127 | /**********************************************************************/ 128 | 129 | static int selectmeta___tostring(lua_State *const L) 130 | { 131 | lua_pushfstring(L,"selectset (%p)",lua_touserdata(L,1)); 132 | return 1; 133 | } 134 | 135 | /**********************************************************************/ 136 | 137 | static int selectmeta___gc(lua_State *const L) 138 | { 139 | selectset__t *set = luaL_checkudata(L,1,TYPE_POLL); 140 | luaL_unref(L,LUA_REGISTRYINDEX,set->ref); 141 | return 0; 142 | } 143 | 144 | /**********************************************************************/ 145 | 146 | static int selectmeta_insert(lua_State *const L) 147 | { 148 | selectset__t *set = luaL_checkudata(L,1,TYPE_POLL); 149 | int fh = luaL_checkinteger(L,2); 150 | 151 | lua_settop(L,4); 152 | 153 | if (fh > FD_SETSIZE) 154 | { 155 | lua_pushinteger(L,EINVAL); 156 | return 1; 157 | } 158 | 159 | if (fh < set->min) set->min = fh; 160 | if (fh > set->max) set->max = fh; 161 | 162 | selectset_toevents(L,3,set,fh); 163 | 164 | lua_pushinteger(L,set->ref); 165 | lua_gettable(L,LUA_REGISTRYINDEX); 166 | lua_pushinteger(L,fh); 167 | 168 | if (lua_isnil(L,4)) 169 | lua_pushvalue(L,2); 170 | else 171 | lua_pushvalue(L,4); 172 | 173 | lua_settable(L,-3); 174 | 175 | set->idx++; 176 | lua_pushinteger(L,0); 177 | return 1; 178 | } 179 | 180 | /**********************************************************************/ 181 | 182 | static int selectmeta_update(lua_State *const L) 183 | { 184 | selectset__t *set = luaL_checkudata(L,1,TYPE_POLL); 185 | int fh = luaL_checkinteger(L,2); 186 | 187 | FD_CLR(fh,&set->read); 188 | FD_CLR(fh,&set->write); 189 | FD_CLR(fh,&set->except); 190 | 191 | selectset_toevents(L,3,set,fh); 192 | lua_pushinteger(L,0); 193 | return 1; 194 | } 195 | 196 | /**********************************************************************/ 197 | 198 | static int selectmeta_remove(lua_State *const L) 199 | { 200 | selectset__t *set = luaL_checkudata(L,1,TYPE_POLL); 201 | int fh = luaL_checkinteger(L,2); 202 | 203 | FD_CLR(fh,&set->read); 204 | FD_CLR(fh,&set->write); 205 | FD_CLR(fh,&set->except); 206 | 207 | lua_pushinteger(L,set->ref); 208 | lua_gettable(L,LUA_REGISTRYINDEX); 209 | lua_pushinteger(L,fh); 210 | lua_pushnil(L); 211 | lua_settable(L,-3); 212 | 213 | set->idx--; 214 | lua_pushinteger(L,0); 215 | return 1; 216 | } 217 | 218 | /**********************************************************************/ 219 | 220 | static int selectmeta_events(lua_State *const L) 221 | { 222 | selectset__t *set = luaL_checkudata(L,1,TYPE_POLL); 223 | double timeout = luaL_optnumber(L,2,-1.0); 224 | struct timeval tout; 225 | struct timeval *ptout; 226 | fd_set read; 227 | fd_set write; 228 | fd_set except; 229 | int rc; 230 | int i; 231 | size_t idx; 232 | 233 | if (timeout < 0) 234 | ptout = NULL; 235 | else 236 | { 237 | double seconds; 238 | double fract; 239 | 240 | fract = modf(timeout,&seconds); 241 | tout.tv_sec = (long)seconds; 242 | tout.tv_usec = (long)(fract * 1000000.0); 243 | ptout = &tout; 244 | } 245 | 246 | read = set->read; 247 | write = set->write; 248 | except = set->except; 249 | 250 | rc = select(FD_SETSIZE,&read,&write,&except,ptout); 251 | if (rc < 0) 252 | { 253 | lua_pushnil(L); 254 | lua_pushinteger(L,errno); 255 | return 2; 256 | } 257 | 258 | lua_pushinteger(L,set->ref); 259 | lua_gettable(L,LUA_REGISTRYINDEX); 260 | 261 | lua_createtable(L,set->idx,0); 262 | for (idx = 1 , i = set->min ; i <= set->max ; i++) 263 | { 264 | if (FD_ISSET(i,&read) || FD_ISSET(i,&write) || FD_ISSET(i,&except)) 265 | { 266 | lua_pushnumber(L,idx++); 267 | selectset_pushevents(L,set,i); 268 | lua_pushinteger(L,i); 269 | lua_gettable(L,-5); 270 | lua_setfield(L,-2,"obj"); 271 | lua_settable(L,-3); 272 | } 273 | } 274 | 275 | lua_pushinteger(L,0); 276 | return 2; 277 | } 278 | 279 | /**********************************************************************/ 280 | 281 | static int selectmeta__POLL(lua_State *const L) 282 | { 283 | lua_pushliteral(L,"select"); 284 | return 1; 285 | } 286 | 287 | /**********************************************************************/ 288 | 289 | static const luaL_Reg m_selectmeta[] = 290 | { 291 | { "__tostring" , selectmeta___tostring } , 292 | { "__gc" , selectmeta___gc } , 293 | { "insert" , selectmeta_insert } , 294 | { "update" , selectmeta_update } , 295 | { "remove" , selectmeta_remove } , 296 | { "events" , selectmeta_events } , 297 | { "POLL" , selectmeta__POLL } , 298 | { NULL , NULL } 299 | }; 300 | 301 | /**********************************************************************/ 302 | 303 | int luaopen_select(lua_State *const L) 304 | { 305 | luaL_newmetatable(L,TYPE_POLL); 306 | luaL_register(L,NULL,m_selectmeta); 307 | lua_pushvalue(L,-1); 308 | lua_setfield(L,-1,"__index"); 309 | 310 | lua_pushcfunction(L,selectset_lua); 311 | return 1; 312 | } 313 | 314 | /**********************************************************************/ 315 | -------------------------------------------------------------------------------- /rockspecs/org.conman.const.exit-1.1.1-1.rockspec: -------------------------------------------------------------------------------- 1 | package = "org.conman.const.exit" 2 | version = "1.1.1-1" 3 | 4 | source = 5 | { 6 | url = "https://raw.github.com/spc476/lua-conmanorg/exit-1.1.1/lua/const/exit.lua", 7 | md5 = "5887830a38db812d3b2486215b803bd5" 8 | } 9 | 10 | description = 11 | { 12 | homepage = "https://github.com/spc476/lua-conmanorg/blob/exit-1.1.1/lua/const/exit.lua", 13 | maintainer = "Sean Conner ", 14 | license = "LGPL3+", 15 | summary = "Some standard process exit return values", 16 | detailed = [[ 17 | A Lua table that defines some common exit return codes for (mostly) 18 | a POSIX system (and Linux). 19 | ]] 20 | } 21 | 22 | dependencies = 23 | { 24 | "lua", 25 | } 26 | 27 | build = 28 | { 29 | type = 'builtin', 30 | copy_directories = {}, 31 | modules = { ['org.conman.const.exit'] = "exit.lua" }, 32 | } 33 | -------------------------------------------------------------------------------- /rockspecs/org.conman.const.gopher-types-2.0.1-1.rockspec: -------------------------------------------------------------------------------- 1 | package = "org.conman.const.gopher-types" 2 | version = "2.0.1-1" 3 | 4 | source = 5 | { 6 | url = "https://raw.github.com/spc476/lua-conmanorg/gopher-types-2.0.1/lua/const/gopher-types.lua", 7 | md5 = "2602c7b56ca46f5cbbdbcbf04a3821d3", 8 | } 9 | 10 | description = 11 | { 12 | homepage = "https://github.com/spc476/lua-conmanorg/blob/gopher-types-2.0.1/lua/const/gopher-types.lua", 13 | maintainer = "Sean Conner ", 14 | license = "LGPL3+", 15 | summary = "Gopher Protocol selector types", 16 | detailed = [[ 17 | A Lua table that maps Gopher Protocol selector types to a 18 | human-readable string. It can also map the human-readable string 19 | back to a Gopher Protocol selector type. 20 | ]] 21 | } 22 | 23 | dependencies = 24 | { 25 | "lua", 26 | } 27 | 28 | build = 29 | { 30 | type = 'builtin', 31 | copy_directories = {}, 32 | modules = { ['org.conman.const.gopher-types'] = "gopher-types.lua" }, 33 | } 34 | -------------------------------------------------------------------------------- /rockspecs/org.conman.env-1.0.4-1.rockspec: -------------------------------------------------------------------------------- 1 | package = "org.conman.env" 2 | version = "1.0.4-1" 3 | 4 | source = 5 | { 6 | url = "https://raw.githubusercontent.com/spc476/lua-conmanorg/env-1.0.4/src/env.c", 7 | } 8 | 9 | description = 10 | { 11 | homepage = "https://github.com/spc476/lua-conmanorg/blob/env-1.0.4/src/env.c", 12 | maintainer = "Sean Conner ", 13 | license = "LGPL3+", 14 | summary = "Loads all environment variables into a table.", 15 | detailed = [[ 16 | A Lua module that loads all current environment variables into a 17 | single table. 18 | ]], 19 | } 20 | 21 | dependencies = 22 | { 23 | "lua >= 5.1, <= 5.4", 24 | } 25 | 26 | build = 27 | { 28 | type = "builtin", 29 | copy_directories = {}, 30 | modules = 31 | { 32 | ['org.conman.env'] = "env.c" 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /rockspecs/org.conman.errno-1.1.0-1.rockspec: -------------------------------------------------------------------------------- 1 | package = "org.conman.errno" 2 | version = "1.1.0-1" 3 | 4 | source = 5 | { 6 | url = "https://raw.githubusercontent.com/spc476/lua-conmanorg/errno-1.1.0/src/errno.c" 7 | } 8 | 9 | description = 10 | { 11 | homepage = "https://github.com/spc476/lua-conmanorg/blob/errno-1.1.0/src/errno.c", 12 | maintainer = "Sean Conner ", 13 | license = "LGPL3+", 14 | summary = "C and POSIX system error codes.", 15 | detailed = [[ 16 | A Lua module that enumerates all C and POSIX system error codes in 17 | a single table. 18 | ]], 19 | } 20 | 21 | dependencies = 22 | { 23 | "lua >= 5.1, <= 5.4", 24 | } 25 | 26 | build = 27 | { 28 | type = "builtin", 29 | copy_directories = {}, 30 | modules = 31 | { 32 | ['org.conman.errno'] = "errno.c" 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /rockspecs/org.conman.iconv-2.0.0-4.rockspec: -------------------------------------------------------------------------------- 1 | package = "org.conman.iconv" 2 | version = "2.0.0-4" 3 | 4 | source = 5 | { 6 | url = "https://raw.github.com/spc476/lua-conmanorg/iconv-2.0.0/src/iconv.c" 7 | } 8 | 9 | description = 10 | { 11 | homepage = "https://github.com/spc476/lua-conmanorg/blob/iconv-2.0.0/src/iconv.c", 12 | maintainer = "Sean Conner ", 13 | license = "LGPL3+", 14 | summary = "Lua wrapper for IConv", 15 | detailed = [[ 16 | A Lua module that wraps the iconv library call. It's simple to use: 17 | 18 | iconv = require "org.conman.iconv" 19 | 20 | trans = iconv("utf-8","iso-8859-1") -- from ISO-8869-1 to UTF-8 21 | 22 | x = This is \255 test" -- in ISO-8869-1 23 | 24 | y = trans(x) -- to UTF-8 25 | ]] 26 | } 27 | 28 | dependencies = 29 | { 30 | "lua >= 5.1, <= 5.4" 31 | } 32 | 33 | local iconv_library_dependency_override = 34 | { 35 | ICONV = 36 | { 37 | library = "iconv", 38 | }, 39 | } 40 | 41 | local iconv_library_module_override = 42 | { 43 | modules = 44 | { 45 | iconv = 46 | { 47 | libraries = {"iconv"} 48 | } 49 | } 50 | } 51 | 52 | external_dependencies = 53 | { 54 | ICONV = 55 | { 56 | header = "iconv.h" 57 | }, 58 | 59 | platforms = 60 | { 61 | cygwin = iconv_library_dependency_override, 62 | macosx = iconv_library_dependency_override, 63 | } 64 | } 65 | 66 | build = 67 | { 68 | type = "builtin", 69 | copy_directories = {}, 70 | modules = 71 | { 72 | ['org.conman.iconv'] = 73 | { 74 | sources = "iconv.c", 75 | incdirs = {"$(ICONV_INCDIR)"}, 76 | libdirs = {"$(ICONV_LIBDIR)"}, 77 | } 78 | }, 79 | 80 | platforms = 81 | { 82 | cygwin = iconv_library_module_override, 83 | macosx = iconv_library_module_override, 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /rockspecs/org.conman.syslog-2.1.4-5.rockspec: -------------------------------------------------------------------------------- 1 | package = "org.conman.syslog" 2 | version = "2.1.4-5" 3 | 4 | source = 5 | { 6 | url = "https://raw.github.com/spc476/lua-conmanorg/syslog-2.1.4/src/syslog.c" 7 | } 8 | 9 | supported_platforms = { "unix" } 10 | 11 | description = 12 | { 13 | homepage = "https://github.com/spc476/lua-conmanorg/blob/syslog-2.1.4/src/syslog.c", 14 | maintainer = "Sean Conner ", 15 | license = "LGPL3+", 16 | summary = "Lua interface to syslog()", 17 | detailed = [[ 18 | A Lua module that interfaces with syslog(). 19 | ]], 20 | } 21 | 22 | dependencies = 23 | { 24 | "lua >= 5.1, <= 5.4", 25 | } 26 | 27 | build = 28 | { 29 | type = "builtin", 30 | copy_directories = {}, 31 | modules = { ['org.conman.syslog'] = 'syslog.c' } 32 | } 33 | -------------------------------------------------------------------------------- /rockspecs/org.conman.tls-2.0.0-3.rockspec: -------------------------------------------------------------------------------- 1 | 2 | package = "org.conman.tls" 3 | version = "2.0.0-3" 4 | 5 | source = 6 | { 7 | url ="https://raw.github.com/spc476/lua-conmanorg/tls-2.0.0/src/tls.c" 8 | } 9 | 10 | description = 11 | { 12 | homepage = "https://github.com/spc476/lua-conmanorg/blob/tls-2.0.0/src/tls.c", 13 | maintainer = "Sean Conner ", 14 | license = "LGPL3+", 15 | summary = "A Lua module that implements TLS via the libtls API.", 16 | detailed = [[ 17 | 18 | This module handles TLS via the libtls API. There are several 19 | libraries now implementing this API, including LibreSSL (where it 20 | was originally developed), OpenSSL and BearSSL. 21 | 22 | You are probably better off reading the man pages for the libtls 23 | functions as this is straight port of the API. 24 | 25 | ]], 26 | } 27 | 28 | dependencies = 29 | { 30 | "lua >= 5.1, <= 5.4" 31 | } 32 | 33 | external_dependencies = 34 | { 35 | TLS = 36 | { 37 | header = "tls.h", 38 | }, 39 | } 40 | 41 | build = 42 | { 43 | type = "builtin", 44 | copy_directory = {}, 45 | modules = 46 | { 47 | ['org.conman.tls'] = 48 | { 49 | sources = "tls.c", 50 | incdirs = { "$(TLS_INCDIR)" }, 51 | libraries = { 'tls' }, 52 | } 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /src/crc.c: -------------------------------------------------------------------------------- 1 | /*************************************************************************** 2 | * 3 | * Copyright 2010 by Sean Conner. 4 | * 5 | * This library is free software; you can redistribute it and/or modify it 6 | * under the terms of the GNU Lesser General Public License as published by 7 | * the Free Software Foundation; either version 3 of the License, or (at your 8 | * option) any later version. 9 | * 10 | * This library is distributed in the hope that it will be useful, but 11 | * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 12 | * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public 13 | * License for more details. 14 | * 15 | * You should have received a copy of the GNU Lesser General Public License 16 | * along with this library; if not, see . 17 | * 18 | * Comments, questions and criticisms can be sent to: sean@conman.org 19 | * 20 | *************************************************************************/ 21 | 22 | #include 23 | #include 24 | 25 | #include 26 | #include 27 | 28 | #if !defined(LUA_VERSION_NUM) || LUA_VERSION_NUM < 501 29 | # error You need to compile against Lua 5.1 or higher 30 | #endif 31 | 32 | /******************************************************************/ 33 | 34 | static int crc32(lua_State *L) 35 | { 36 | static uint32_t const m_crc32_table[] = 37 | { 38 | 0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA, 39 | 0x076DC419, 0x706AF48F, 0xE963A535, 0x9E6495A3, 40 | 0x0EDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988, 41 | 0x09B64C2B, 0x7EB17CBD, 0xE7B82D07, 0x90BF1D91, 42 | 0x1DB71064, 0x6AB020F2, 0xF3B97148, 0x84BE41DE, 43 | 0x1ADAD47D, 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7, 44 | 0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC, 45 | 0x14015C4F, 0x63066CD9, 0xFA0F3D63, 0x8D080DF5, 46 | 0x3B6E20C8, 0x4C69105E, 0xD56041E4, 0xA2677172, 47 | 0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B, 48 | 0x35B5A8FA, 0x42B2986C, 0xDBBBC9D6, 0xACBCF940, 49 | 0x32D86CE3, 0x45DF5C75, 0xDCD60DCF, 0xABD13D59, 50 | 0x26D930AC, 0x51DE003A, 0xC8D75180, 0xBFD06116, 51 | 0x21B4F4B5, 0x56B3C423, 0xCFBA9599, 0xB8BDA50F, 52 | 0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924, 53 | 0x2F6F7C87, 0x58684C11, 0xC1611DAB, 0xB6662D3D, 54 | 0x76DC4190, 0x01DB7106, 0x98D220BC, 0xEFD5102A, 55 | 0x71B18589, 0x06B6B51F, 0x9FBFE4A5, 0xE8B8D433, 56 | 0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818, 57 | 0x7F6A0DBB, 0x086D3D2D, 0x91646C97, 0xE6635C01, 58 | 0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E, 59 | 0x6C0695ED, 0x1B01A57B, 0x8208F4C1, 0xF50FC457, 60 | 0x65B0D9C6, 0x12B7E950, 0x8BBEB8EA, 0xFCB9887C, 61 | 0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65, 62 | 0x4DB26158, 0x3AB551CE, 0xA3BC0074, 0xD4BB30E2, 63 | 0x4ADFA541, 0x3DD895D7, 0xA4D1C46D, 0xD3D6F4FB, 64 | 0x4369E96A, 0x346ED9FC, 0xAD678846, 0xDA60B8D0, 65 | 0x44042D73, 0x33031DE5, 0xAA0A4C5F, 0xDD0D7CC9, 66 | 0x5005713C, 0x270241AA, 0xBE0B1010, 0xC90C2086, 67 | 0x5768B525, 0x206F85B3, 0xB966D409, 0xCE61E49F, 68 | 0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4, 69 | 0x59B33D17, 0x2EB40D81, 0xB7BD5C3B, 0xC0BA6CAD, 70 | 0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A, 71 | 0xEAD54739, 0x9DD277AF, 0x04DB2615, 0x73DC1683, 72 | 0xE3630B12, 0x94643B84, 0x0D6D6A3E, 0x7A6A5AA8, 73 | 0xE40ECF0B, 0x9309FF9D, 0x0A00AE27, 0x7D079EB1, 74 | 0xF00F9344, 0x8708A3D2, 0x1E01F268, 0x6906C2FE, 75 | 0xF762575D, 0x806567CB, 0x196C3671, 0x6E6B06E7, 76 | 0xFED41B76, 0x89D32BE0, 0x10DA7A5A, 0x67DD4ACC, 77 | 0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5, 78 | 0xD6D6A3E8, 0xA1D1937E, 0x38D8C2C4, 0x4FDFF252, 79 | 0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, 0x48B2364B, 80 | 0xD80D2BDA, 0xAF0A1B4C, 0x36034AF6, 0x41047A60, 81 | 0xDF60EFC3, 0xA867DF55, 0x316E8EEF, 0x4669BE79, 82 | 0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236, 83 | 0xCC0C7795, 0xBB0B4703, 0x220216B9, 0x5505262F, 84 | 0xC5BA3BBE, 0xB2BD0B28, 0x2BB45A92, 0x5CB36A04, 85 | 0xC2D7FFA7, 0xB5D0CF31, 0x2CD99E8B, 0x5BDEAE1D, 86 | 0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A, 87 | 0x9C0906A9, 0xEB0E363F, 0x72076785, 0x05005713, 88 | 0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38, 89 | 0x92D28E9B, 0xE5D5BE0D, 0x7CDCEFB7, 0x0BDBDF21, 90 | 0x86D3D2D4, 0xF1D4E242, 0x68DDB3F8, 0x1FDA836E, 91 | 0x81BE16CD, 0xF6B9265B, 0x6FB077E1, 0x18B74777, 92 | 0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C, 93 | 0x8F659EFF, 0xF862AE69, 0x616BFFD3, 0x166CCF45, 94 | 0xA00AE278, 0xD70DD2EE, 0x4E048354, 0x3903B3C2, 95 | 0xA7672661, 0xD06016F7, 0x4969474D, 0x3E6E77DB, 96 | 0xAED16A4A, 0xD9D65ADC, 0x40DF0B66, 0x37D83BF0, 97 | 0xA9BCAE53, 0xDEBB9EC5, 0x47B2CF7F, 0x30B5FFE9, 98 | 0xBDBDF21C, 0xCABAC28A, 0x53B39330, 0x24B4A3A6, 99 | 0xBAD03605, 0xCDD70693, 0x54DE5729, 0x23D967BF, 100 | 0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94, 101 | 0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B, 0x2D02EF8D 102 | }; 103 | 104 | size_t size; 105 | uint8_t const *p = (uint8_t const *)luaL_checklstring(L,1,&size); 106 | uint32_t crc = ~luaL_optinteger(L,2,0); 107 | 108 | while(size--) 109 | crc = (crc >> 8) ^ m_crc32_table[ (crc ^ *p++) & 0xFF ]; 110 | 111 | lua_pushinteger(L,~crc); 112 | return 1; 113 | } 114 | 115 | /****************************************************************/ 116 | 117 | int luaopen_org_conman_crc(lua_State *L) 118 | { 119 | lua_pushcfunction(L,crc32); 120 | return 1; 121 | } 122 | 123 | /*******************************************************************/ 124 | -------------------------------------------------------------------------------- /src/env.c: -------------------------------------------------------------------------------- 1 | /******************************************** 2 | * 3 | * Copyright 2009 by Sean Conner. All Rights Reserved. 4 | * 5 | * This library is free software; you can redistribute it and/or modify it 6 | * under the terms of the GNU Lesser General Public License as published by 7 | * the Free Software Foundation; either version 3 of the License, or (at your 8 | * option) any later version. 9 | * 10 | * This library is distributed in the hope that it will be useful, but 11 | * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 12 | * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public 13 | * License for more details. 14 | * 15 | * You should have received a copy of the GNU Lesser General Public License 16 | * along with this library; if not, see . 17 | * 18 | * Comments, questions and criticisms can be sent to: sean@conman.org 19 | * 20 | * --------------------------------------------------------------------- 21 | * 22 | * This module is nothing more than an array of the environmental variables 23 | * of the current process. There's not much more to say about this than 24 | * 25 | env = require "org.conman.env" 26 | print(env.LUA_PATH) 27 | print(env['LUA_CPATH']) 28 | 29 | * 30 | *********************************************/ 31 | 32 | #include 33 | #include 34 | 35 | #include 36 | #include 37 | 38 | #if !defined(LUA_VERSION_NUM) || LUA_VERSION_NUM < 501 39 | # error You need to compile against Lua 5.1 or higher 40 | #endif 41 | 42 | int luaopen_org_conman_env(lua_State *L) 43 | { 44 | extern char const **environ; 45 | int i; 46 | 47 | #if LUA_VERSION_NUM == 501 48 | static struct luaL_Reg const env[] = 49 | { 50 | { NULL , NULL } 51 | }; 52 | 53 | luaL_register(L,"org.conman.env",env); 54 | #else 55 | lua_createtable(L,0,0); 56 | #endif 57 | 58 | for (i = 0 ; environ[i] != NULL ; i++) 59 | { 60 | char const *value = strchr(environ[i],'='); 61 | size_t len; 62 | int type; 63 | 64 | if (value != NULL) 65 | { 66 | len = (size_t)(value - environ[i]); 67 | value++; 68 | } 69 | else 70 | { 71 | len = strlen(environ[i]); 72 | value = ""; 73 | } 74 | 75 | /*--------------------------------------------------------------------- 76 | ; http://lwn.net/Articles/678148/ 77 | ; 78 | ; The gist---if two environment variables exist with the same name, 79 | ; getenv() will return the first one, while languages like Perl and Lua, 80 | ; which dump everythinig into hash, will typically return the second 81 | ; value, which could be exploited. So we duplicate the behavior of 82 | ; getenv() and only save the environment variable if it already hasn't 83 | ; been set. 84 | ;----------------------------------------------------------------------*/ 85 | 86 | lua_pushlstring(L,environ[i],len); 87 | lua_gettable(L,-2); 88 | type = lua_type(L,-1); 89 | lua_pop(L,1); 90 | 91 | if (type == LUA_TNIL) 92 | { 93 | lua_pushlstring(L,environ[i],len); 94 | lua_pushstring(L,value); 95 | lua_settable(L,-3); 96 | } 97 | } 98 | 99 | return 1; 100 | } 101 | -------------------------------------------------------------------------------- /src/hash.c: -------------------------------------------------------------------------------- 1 | /*************************************************************************** 2 | * 3 | * Copyright 2011 by Sean Conner. 4 | * 5 | * This library is free software; you can redistribute it and/or modify it 6 | * under the terms of the GNU Lesser General Public License as published by 7 | * the Free Software Foundation; either version 3 of the License, or (at your 8 | * option) any later version. 9 | * 10 | * This library is distributed in the hope that it will be useful, but 11 | * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 12 | * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public 13 | * License for more details. 14 | * 15 | * You should have received a copy of the GNU Lesser General Public License 16 | * along with this library; if not, see . 17 | * 18 | * Comments, questions and criticisms can be sent to: sean@conman.org 19 | * 20 | *************************************************************************/ 21 | 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | 28 | #include 29 | #include 30 | 31 | #include 32 | #include 33 | 34 | #ifndef OPENSSL_VERSION_NUMBER 35 | # error Could not determine OpenSSL version 36 | #endif 37 | 38 | #if !defined(LUA_VERSION_NUM) || LUA_VERSION_NUM < 501 39 | # error You need to compile against Lua 5.1 or higher 40 | #endif 41 | 42 | #define TYPE_HASH "org.conman.hash:hash" 43 | 44 | /************************************************************************/ 45 | 46 | static int hash_hexa( 47 | lua_State *L, 48 | char const *data, 49 | size_t size 50 | ) 51 | { 52 | luaL_Buffer buf; 53 | char hex[3]; 54 | 55 | luaL_buffinit(L,&buf); 56 | while(size--) 57 | { 58 | snprintf(hex,3,"%02X",(unsigned char)*data++); 59 | luaL_addlstring(&buf,hex,2); 60 | } 61 | luaL_pushresult(&buf); 62 | return 1; 63 | } 64 | 65 | /************************************************************************/ 66 | 67 | static int hashlua_new(lua_State *L) 68 | { 69 | char const *alg; 70 | EVP_MD const *m; 71 | EVP_MD_CTX **ctx; 72 | 73 | alg = luaL_optstring(L,1,"md5"); 74 | m = EVP_get_digestbyname(alg); 75 | if (m == NULL) 76 | { 77 | lua_pushnil(L); 78 | return 1; 79 | } 80 | 81 | ctx = lua_newuserdata(L,sizeof(*ctx)); 82 | #if OPENSSL_VERSION_NUMBER < 0x1010000fL 83 | *ctx = malloc(sizeof(EVP_MD_CTX)); 84 | #else 85 | *ctx = EVP_MD_CTX_new(); 86 | #endif 87 | 88 | EVP_DigestInit(*ctx,m); 89 | luaL_getmetatable(L,TYPE_HASH); 90 | lua_setmetatable(L,-2); 91 | return 1; 92 | } 93 | 94 | /************************************************************************/ 95 | 96 | static int hashlua_update(lua_State *L) 97 | { 98 | EVP_MD_CTX **ctx; 99 | char const *data; 100 | size_t size; 101 | 102 | ctx = luaL_checkudata(L,1,TYPE_HASH); 103 | data = luaL_checklstring(L,2,&size); 104 | 105 | if (size > INT_MAX) 106 | { 107 | lua_pushboolean(L,false); 108 | lua_pushinteger(L,EFBIG); 109 | return 2; 110 | } 111 | 112 | EVP_DigestUpdate(*ctx,data,size); 113 | lua_pushboolean(L,true); 114 | return 1; 115 | } 116 | 117 | /************************************************************************/ 118 | 119 | static int hashlua_final(lua_State *L) 120 | { 121 | EVP_MD_CTX **ctx; 122 | unsigned char hash[EVP_MAX_MD_SIZE]; 123 | unsigned int hashsize; 124 | 125 | ctx = luaL_checkudata(L,1,TYPE_HASH); 126 | hashsize = sizeof(hash); 127 | 128 | EVP_DigestFinal(*ctx,hash,&hashsize); 129 | lua_pushlstring(L,(char *)hash,hashsize); 130 | return 1; 131 | } 132 | 133 | /************************************************************************/ 134 | 135 | static int hashlua_finalhexa(lua_State *L) 136 | { 137 | char const *data; 138 | size_t size; 139 | 140 | hashlua_final(L); 141 | data = lua_tolstring(L,-1,&size); 142 | return hash_hexa(L,data,size); 143 | } 144 | 145 | /************************************************************************/ 146 | 147 | static int hashlua_sum(lua_State *L) 148 | { 149 | EVP_MD const *m; 150 | EVP_MD_CTX *ctx; 151 | char const *data; 152 | size_t size; 153 | char const *alg; 154 | unsigned char hash[EVP_MAX_MD_SIZE]; 155 | unsigned int hashsize; 156 | 157 | data = luaL_checklstring(L,1,&size); 158 | 159 | if (size > INT_MAX) 160 | { 161 | lua_pushnil(L); 162 | lua_pushinteger(L,EFBIG); 163 | return 2; 164 | } 165 | 166 | alg = luaL_optstring(L,2,"md5"); 167 | m = EVP_get_digestbyname(alg); 168 | if (m == NULL) 169 | { 170 | lua_pushnil(L); 171 | lua_pushinteger(L,EINVAL); 172 | return 2; 173 | } 174 | 175 | #if OPENSSL_VERSION_NUMBER < 0x1010000fL 176 | ctx = malloc(sizeof(EVP_MD_CTX)); 177 | #else 178 | ctx = EVP_MD_CTX_new(); 179 | #endif 180 | 181 | hashsize = sizeof(hash); 182 | EVP_DigestInit(ctx,m); 183 | EVP_DigestUpdate(ctx,data,size); 184 | EVP_DigestFinal(ctx,hash,&hashsize); 185 | 186 | #if OPENSSL_VERSION_NUMBER < 0x1010000fL 187 | free(ctx); 188 | #else 189 | EVP_MD_CTX_free(ctx); 190 | #endif 191 | 192 | lua_pushlstring(L,(char *)hash,hashsize); 193 | return 1; 194 | } 195 | 196 | /*****************************************************************/ 197 | 198 | static int hashlua_hexa(lua_State *L) 199 | { 200 | char const *data; 201 | size_t size; 202 | 203 | data = luaL_checklstring(L,1,&size); 204 | return hash_hexa(L,data,size); 205 | } 206 | 207 | /************************************************************************/ 208 | 209 | static int hashlua_sumhexa(lua_State *L) 210 | { 211 | char const *data; 212 | size_t size; 213 | int rc; 214 | 215 | rc = hashlua_sum(L); 216 | if (!lua_isstring(L,-1)) 217 | return rc; 218 | 219 | data = lua_tolstring(L,-1,&size); 220 | return hash_hexa(L,data,size); 221 | } 222 | 223 | /************************************************************************/ 224 | 225 | static int hashlua___tostring(lua_State *L) 226 | { 227 | lua_pushfstring(L,"hash (%p)",lua_touserdata(L,1)); 228 | return 1; 229 | } 230 | 231 | /***********************************************************************/ 232 | 233 | static int hashlua___gc(lua_State *L) 234 | { 235 | EVP_MD_CTX **ctx = luaL_checkudata(L,1,TYPE_HASH); 236 | if (*ctx != NULL) 237 | { 238 | #if OPENSSL_VERSION_NUMBER < 0x1010000fL 239 | free(*ctx); 240 | #else 241 | EVP_MD_CTX_free(*ctx); 242 | #endif 243 | *ctx = NULL; 244 | } 245 | 246 | return 0; 247 | } 248 | 249 | /***********************************************************************/ 250 | 251 | int luaopen_org_conman_hash(lua_State *L) 252 | { 253 | static struct luaL_Reg const hashlua[] = 254 | { 255 | { "new" , hashlua_new } , 256 | { "update" , hashlua_update } , 257 | { "final" , hashlua_final } , 258 | { "sum" , hashlua_sum } , 259 | { "hexa" , hashlua_hexa } , 260 | { "sumhexa" , hashlua_sumhexa } , 261 | { NULL , NULL } 262 | }; 263 | 264 | static struct luaL_Reg const hashlua_meta[] = 265 | { 266 | { "update" , hashlua_update } , 267 | { "final" , hashlua_final } , 268 | { "finalhexa" , hashlua_finalhexa } , 269 | { "__tostring" , hashlua___tostring } , 270 | { "__gc" , hashlua___gc } , 271 | #if LUA_VERSION_NUM >= 504 272 | { "__close" , hashlua___gc } , 273 | #endif 274 | { NULL , NULL } 275 | }; 276 | 277 | OpenSSL_add_all_digests(); 278 | 279 | luaL_newmetatable(L,TYPE_HASH); 280 | #if LUA_VERSION_NUM == 501 281 | luaL_register(L,NULL,hashlua_meta); 282 | #else 283 | luaL_setfuncs(L,hashlua_meta,0); 284 | #endif 285 | 286 | lua_pushvalue(L,-1); 287 | lua_setfield(L,-2,"__index"); 288 | 289 | #if LUA_VERSION_NUM == 501 290 | luaL_register(L,"org.conman.hash",hashlua); 291 | #else 292 | luaL_newlib(L,hashlua); 293 | #endif 294 | 295 | return 1; 296 | } 297 | 298 | /*************************************************************************/ 299 | -------------------------------------------------------------------------------- /src/iconv.c: -------------------------------------------------------------------------------- 1 | /********************************************************************* 2 | * 3 | * Copyright 2011 by Sean Conner. All Rights Reserved. 4 | * 5 | * This library is free software; you can redistribute it and/or modify it 6 | * under the terms of the GNU Lesser General Public License as published by 7 | * the Free Software Foundation; either version 3 of the License, or (at your 8 | * option) any later version. 9 | * 10 | * This library is distributed in the hope that it will be useful, but 11 | * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 12 | * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public 13 | * License for more details. 14 | * 15 | * You should have received a copy of the GNU Lesser General Public License 16 | * along with this library; if not, see . 17 | * 18 | * Comments, questions and criticisms can be sent to: sean@conman.org 19 | * 20 | * ------------------------------------------------------------------- 21 | * 22 | * Use of this module is straightforward. It returns a single function: 23 | * 24 | * iconv(target_charset,source_charset) 25 | * -- type(target_charset) == 'string' 26 | * -- type(source_charset) == 'string' 27 | * 28 | * This returns a userdata can can be used to transform a string from 29 | * one character set to another. 30 | * 31 | * trans = iconv(...) 32 | * newstr,err,idx = trans("this is a test") 33 | * 34 | * newstr = translated string, or nil if error 35 | * err = 0 if okay, otherwise, the error (integer) 36 | * idx = nil if okay, otherwise the index in the input where 37 | * the error happened. 38 | * 39 | * An example follows. 40 | * 41 | 42 | iconv = require "org.conman.iconv" 43 | trans = iconv("utf-8","iso-8859-1") -- convert from ISO-8859-1 44 | x = "This is \225 test" -- string in ISO-8859-1 45 | y = trans(x) -- string now in UTF-8 46 | print(y) 47 | 48 | * 49 | *********************************************************************/ 50 | 51 | #include 52 | #include 53 | #include 54 | 55 | #include 56 | 57 | #include 58 | #include 59 | 60 | #if !defined(LUA_VERSION_NUM) || LUA_VERSION_NUM < 501 61 | # error You need to compile against Lua 5.1 or higher 62 | #endif 63 | 64 | #define TYPE_ICONV "org.conman.iconv:iconv" 65 | 66 | /**************************************************************************/ 67 | 68 | static int luaiconv_open(lua_State *L) 69 | { 70 | char const *fromcode; 71 | char const *tocode; 72 | iconv_t *pic; 73 | iconv_t ic; 74 | 75 | tocode = luaL_checkstring(L,1); 76 | fromcode = luaL_checkstring(L,2); 77 | ic = iconv_open(tocode,fromcode); 78 | 79 | if (ic == (iconv_t)-1) 80 | { 81 | lua_pushnil(L); 82 | lua_pushinteger(L,errno); 83 | lua_pushfstring(L,"%s:%s",tocode,fromcode); 84 | return 3; 85 | } 86 | 87 | pic = lua_newuserdata(L,sizeof(iconv_t)); 88 | *pic = ic; 89 | 90 | luaL_getmetatable(L,TYPE_ICONV); 91 | lua_setmetatable(L,-2); 92 | lua_pushinteger(L,0); 93 | return 2; 94 | } 95 | 96 | /*************************************************************************/ 97 | 98 | static int luametaiconv___call(lua_State *L) 99 | { 100 | char const *from; 101 | char const *ofrom; 102 | size_t fsize; 103 | iconv_t *pic; 104 | char to[LUAL_BUFFERSIZE]; 105 | size_t tsize; 106 | char *pto; 107 | luaL_Buffer buf; 108 | 109 | pic = luaL_checkudata(L,1,TYPE_ICONV); 110 | from = luaL_checklstring(L,2,&fsize); 111 | tsize = sizeof(to); 112 | pto = to; 113 | ofrom = from; 114 | 115 | luaL_buffinit(L,&buf); 116 | 117 | while(fsize > 0) 118 | { 119 | if (iconv(*pic,(char **)&from,&fsize,&pto,&tsize) == (size_t)-1) 120 | { 121 | if (errno == E2BIG) 122 | { 123 | luaL_addlstring(&buf,to,sizeof(to) - tsize); 124 | pto = to; 125 | tsize = sizeof(to); 126 | } 127 | else 128 | { 129 | iconv(*pic,NULL,NULL,NULL,NULL); /* reset state */ 130 | lua_pushnil(L); 131 | lua_pushinteger(L,errno); 132 | lua_pushinteger(L,(int)(from - ofrom) + 1); 133 | return 3; 134 | } 135 | } 136 | } 137 | 138 | luaL_addlstring(&buf,to,sizeof(to) - tsize); 139 | luaL_pushresult(&buf); 140 | lua_pushinteger(L,0); 141 | return 2; 142 | } 143 | 144 | /*************************************************************************/ 145 | 146 | static int luametaiconv___tostring(lua_State *L) 147 | { 148 | lua_pushfstring(L,"iconv (%p)",lua_touserdata(L,1)); 149 | return 1; 150 | } 151 | 152 | /*************************************************************************/ 153 | 154 | static int luametaiconv___gc(lua_State *L) 155 | { 156 | iconv_t *ic = luaL_checkudata(L,1,TYPE_ICONV); 157 | if (*ic != NULL) 158 | { 159 | iconv_close(*ic); 160 | *ic = NULL; 161 | } 162 | return 0; 163 | } 164 | 165 | /*************************************************************************/ 166 | 167 | int luaopen_org_conman_iconv(lua_State *L) 168 | { 169 | static struct luaL_Reg const reg_iconv_meta[] = 170 | { 171 | { "__call" , luametaiconv___call } , 172 | { "__tostring" , luametaiconv___tostring } , 173 | { "__gc" , luametaiconv___gc } , 174 | #if LUA_VERSION_NUM >= 504 175 | { "__close" , luametaiconv___gc } , 176 | #endif 177 | { NULL , NULL } 178 | }; 179 | 180 | luaL_newmetatable(L,TYPE_ICONV); 181 | #if LUA_VERSION_NUM == 501 182 | luaL_register(L,NULL,reg_iconv_meta); 183 | #else 184 | luaL_setfuncs(L,reg_iconv_meta,0); 185 | #endif 186 | lua_pushcfunction(L,luaiconv_open); 187 | return 1; 188 | } 189 | 190 | /**************************************************************************/ 191 | -------------------------------------------------------------------------------- /src/idn.c: -------------------------------------------------------------------------------- 1 | /*************************************************************************** 2 | * 3 | * Copyright 2020 by Sean Conner. 4 | * 5 | * This library is free software; you can redistribute it and/or modify it 6 | * under the terms of the GNU Lesser General Public License as published by 7 | * the Free Software Foundation; either version 3 of the License, or (at your 8 | * option) any later version. 9 | * 10 | * This library is distributed in the hope that it will be useful, but 11 | * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 12 | * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public 13 | * License for more details. 14 | * 15 | * You should have received a copy of the GNU Lesser General Public License 16 | * along with this library; if not, see . 17 | * 18 | * Comments, questions and criticisms can be sent to: sean@conman.org 19 | * 20 | *************************************************************************/ 21 | 22 | #include 23 | #include 24 | #include 25 | #include 26 | 27 | #include 28 | #include 29 | 30 | #include 31 | #include 32 | 33 | #if !defined(LUA_VERSION_NUM) || LUA_VERSION_NUM < 501 34 | # error You need to compile against Lua 5.1 or higher 35 | #endif 36 | 37 | /************************************************************************/ 38 | 39 | union wstrp 40 | { 41 | punycode_uint *pc; 42 | uint32_t *uc; 43 | }; 44 | 45 | union wstr 46 | { 47 | punycode_uint pc[64]; 48 | uint32_t uc[64]; 49 | }; 50 | 51 | /************************************************************************/ 52 | 53 | static bool add_segment(luaL_Buffer *buf,char const *seg,size_t len) 54 | { 55 | char *normalized; 56 | union wstrp domain; 57 | char topuny[64]; 58 | size_t domainsize; 59 | size_t topunysize; 60 | bool rc; 61 | 62 | rc = false; 63 | normalized = stringprep_utf8_nfkc_normalize(seg,len); 64 | 65 | if (normalized != NULL) 66 | { 67 | domain.uc = stringprep_utf8_to_ucs4(normalized,-1,&domainsize); 68 | if (domain.uc != NULL) 69 | { 70 | topunysize = 64; 71 | 72 | if (punycode_encode(domainsize,domain.pc,NULL,&topunysize,topuny) == PUNYCODE_SUCCESS) 73 | { 74 | luaL_addlstring(buf,"xn--",4); 75 | luaL_addlstring(buf,topuny,topunysize); 76 | rc = true; 77 | } 78 | free(domain.uc); 79 | } 80 | 81 | free(normalized); 82 | } 83 | 84 | return rc; 85 | } 86 | 87 | /************************************************************************/ 88 | 89 | static int idn_encode(lua_State *L) 90 | { 91 | char const *orig = luaL_checkstring(L,1); 92 | luaL_Buffer buf; 93 | size_t si; 94 | size_t di; 95 | bool utf8; 96 | 97 | luaL_buffinit(L,&buf); 98 | 99 | for (si = di = 0 , utf8 = false ; ; di++) 100 | { 101 | if (orig[di] == '\0') 102 | { 103 | if (utf8) 104 | { 105 | if (!add_segment(&buf,&orig[si],di - si)) 106 | return 0; 107 | } 108 | else 109 | luaL_addlstring(&buf,&orig[si],di - si); 110 | 111 | luaL_pushresult(&buf); 112 | return 1; 113 | } 114 | 115 | if (orig[di] == '.') 116 | { 117 | if (utf8) 118 | { 119 | if (!add_segment(&buf,&orig[si],di - si)) 120 | return 0; 121 | } 122 | else 123 | luaL_addlstring(&buf,&orig[si],di - si); 124 | 125 | luaL_addchar(&buf,'.'); 126 | si = di + 1; 127 | utf8 = false; 128 | } 129 | else 130 | utf8 |= ((unsigned)orig[di]) > 127; 131 | } 132 | } 133 | 134 | /************************************************************************/ 135 | 136 | static int idn_decode(lua_State *L) 137 | { 138 | char const *orig = luaL_checkstring(L,1); 139 | luaL_Buffer buf; 140 | 141 | luaL_buffinit(L,&buf); 142 | 143 | while(true) 144 | { 145 | char const *p = strchr(orig,'.'); 146 | size_t len = p == NULL ? strlen(orig) : (size_t)(p - orig); 147 | 148 | if (strncmp(orig,"xn--",4) == 0) 149 | { 150 | union wstr frompuny; 151 | size_t frompunysize = 64; 152 | char *result; 153 | 154 | if (punycode_decode(len-4,&orig[4],&frompunysize,frompuny.pc,NULL) != PUNYCODE_SUCCESS) 155 | return 0; 156 | 157 | result = stringprep_ucs4_to_utf8(frompuny.uc,frompunysize,NULL,NULL); 158 | 159 | if (result != NULL) 160 | { 161 | luaL_addstring(&buf,result); 162 | free(result); 163 | } 164 | } 165 | else 166 | luaL_addlstring(&buf,orig,len); 167 | 168 | if (p != NULL) 169 | { 170 | luaL_addchar(&buf,'.'); 171 | orig = ++p; 172 | } 173 | else 174 | { 175 | luaL_pushresult(&buf); 176 | return 1; 177 | } 178 | } 179 | } 180 | 181 | /************************************************************************/ 182 | 183 | int luaopen_org_conman_idn(lua_State *L) 184 | { 185 | static luaL_Reg const m_idn_reg[] = 186 | { 187 | { "encode" , idn_encode }, 188 | { "decode" , idn_decode }, 189 | { NULL , NULL } 190 | }; 191 | 192 | #if LUA_VERSION_NUM == 501 193 | luaL_register(L,"org.conman.idn",m_idn_reg); 194 | #else 195 | luaL_newlib(L,m_idn_reg); 196 | #endif 197 | return 1; 198 | } 199 | 200 | /************************************************************************/ 201 | -------------------------------------------------------------------------------- /src/lfsr.c: -------------------------------------------------------------------------------- 1 | /********************************************************************* 2 | * 3 | * Copyright 2010 by Sean Conner. All Rights Reserved. 4 | * 5 | * This library is free software; you can redistribute it and/or modify it 6 | * under the terms of the GNU Lesser General Public License as published by 7 | * the Free Software Foundation; either version 3 of the License, or (at your 8 | * option) any later version. 9 | * 10 | * This library is distributed in the hope that it will be useful, but 11 | * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 12 | * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public 13 | * License for more details. 14 | * 15 | * You should have received a copy of the GNU Lesser General Public License 16 | * along with this library; if not, see . 17 | * 18 | * Comments, questions and criticisms can be sent to: sean@conman.org 19 | * 20 | * --------------------------------------------------------------------- 21 | * 22 | * This module implements LFSR of 8, 16 and 32 bits. These have the 23 | * following features: 24 | * 25 | * All sequence of bits between 1 and 2^bits are generated 26 | * It is very fast. 27 | * 28 | lfsr = require "org.conman.lfsr" 29 | rnd8 = lfsr( 8[,seed[,taps]]) 30 | rnd16 = lfsr(16[,seed[,taps]]) 31 | rnd32 = lfsr(32[,seed[,taps]]) 32 | rnd32 = lfsr() -- 32, 0xB4000021 33 | * 34 | * NOTE: taps for 8b, 16b and 32bs can be found here: 35 | * http://users.ece.cmu.edu/~koopman/lfsr/index.html 36 | * 37 | * ALSO SEE: 38 | * https://en.wikipedia.org/wiki/Linear-feedback_shift_register 39 | *********************************************************************/ 40 | 41 | #include 42 | #include 43 | #include 44 | 45 | /*********************************************************************/ 46 | 47 | static int lfsrnext(lua_State *L) 48 | { 49 | lua_Integer mask = lua_tointeger(L,lua_upvalueindex(1)); 50 | lua_Integer taps = lua_tointeger(L,lua_upvalueindex(2)); 51 | lua_Integer lfsr = lua_tointeger(L,lua_upvalueindex(3)); 52 | lua_Integer lsb = lfsr & 1; 53 | 54 | lfsr >>= 1; 55 | lfsr ^= (-lsb) & taps; 56 | lfsr &= mask; 57 | lua_pushinteger(L,lfsr); 58 | lua_pushinteger(L,lfsr); 59 | lua_replace(L,lua_upvalueindex(3)); 60 | return 1; 61 | } 62 | 63 | /*********************************************************************/ 64 | 65 | static int lfsr(lua_State *L) 66 | { 67 | lua_Integer bits = luaL_optinteger(L,1,32); 68 | lua_Integer seed = luaL_optinteger(L,2,0); 69 | lua_Integer taps = luaL_optinteger(L,3,0); 70 | lua_Integer mask; 71 | 72 | if (seed == 0) 73 | { 74 | FILE *fp = fopen("/dev/urandom","rb"); 75 | 76 | if (fp) 77 | { 78 | fread(&seed,sizeof(seed),1,fp); 79 | fclose(fp); 80 | } 81 | 82 | if (seed == 0) seed++; 83 | } 84 | 85 | switch(bits) 86 | { 87 | case 8: 88 | if (taps == 0) taps = 0xB4; /* Pitfall! */ 89 | mask = 0xFF; 90 | break; 91 | 92 | case 16: 93 | if (taps == 0) taps = 0xB400; /* more Pitfall! */ 94 | mask = 0xFFFF; 95 | break; 96 | 97 | case 32: 98 | if (taps == 0) taps = 0xB4000021; 99 | mask = 0xFFFFFFFF; 100 | break; 101 | 102 | default: 103 | assert(0); 104 | return luaL_error(L,"bad mask value"); 105 | } 106 | 107 | lua_pushinteger(L,mask); 108 | lua_pushinteger(L,taps); 109 | lua_pushinteger(L,seed); 110 | lua_pushcclosure(L,lfsrnext,3); 111 | return 1; 112 | } 113 | 114 | /*********************************************************************/ 115 | 116 | int luaopen_org_conman_lfsr(lua_State *L) 117 | { 118 | lua_pushcfunction(L,lfsr); 119 | return 1; 120 | } 121 | -------------------------------------------------------------------------------- /src/math.c: -------------------------------------------------------------------------------- 1 | /********************************************************************* 2 | * 3 | * Copyright 2010 by Sean Conner. All Rights Reserved. 4 | * 5 | * This library is free software; you can redistribute it and/or modify it 6 | * under the terms of the GNU Lesser General Public License as published by 7 | * the Free Software Foundation; either version 3 of the License, or (at your 8 | * option) any later version. 9 | * 10 | * This library is distributed in the hope that it will be useful, but 11 | * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 12 | * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public 13 | * License for more details. 14 | * 15 | * You should have received a copy of the GNU Lesser General Public License 16 | * along with this library; if not, see . 17 | * 18 | * Comments, questions and criticisms can be sent to: sean@conman.org 19 | * 20 | *********************************************************************/ 21 | 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | 30 | #include 31 | #include 32 | 33 | #if !defined(LUA_VERSION_NUM) || LUA_VERSION_NUM < 501 34 | # error You need to compile against Lua 5.1 or higher 35 | #endif 36 | 37 | /************************************************************************/ 38 | 39 | static int math_seed(lua_State *L) 40 | { 41 | #if LUA_VERSION_NUM >= 504 42 | lua_Integer seed[2]; 43 | #else 44 | lua_Integer seed[1]; 45 | #endif 46 | 47 | FILE *fp = fopen("/dev/urandom","rb"); 48 | if (fp == NULL) 49 | return 0; 50 | fread(seed,sizeof(seed),1,fp); 51 | fclose(fp); 52 | 53 | #if LUA_VERSION_NUM >= 504 54 | lua_pushinteger(L,seed[0]); 55 | lua_pushinteger(L,seed[1]); 56 | return 2; 57 | #else 58 | lua_pushinteger(L,seed[0]); 59 | return 1; 60 | #endif 61 | } 62 | 63 | /************************************************************************/ 64 | 65 | static int math_randomseed(lua_State *const L) 66 | { 67 | char *seedbank; 68 | char *seedbank_file; 69 | char *seedbank_log; 70 | unsigned int seed; 71 | 72 | assert(L != NULL); 73 | 74 | /*-------------------------------------------------------------------- 75 | ; The idea for this is from https://github.com/catseye/seedbank 76 | ; 77 | ; But slightly modified. If SEEDBANK_SEED is an integer, that's used 78 | ; as the seeed. If SEEDBANK_FILE is set and SEEDBANK_SEED=LAST, then 79 | ; the contents of $SEEDBANK_FILE is used. Otherwise, the older methods 80 | ; are used (so this is new functionality). 81 | ; 82 | ; In either case, if SEEDBANK_FILE is set, then the seed (however 83 | ; selected) will be saved in that file. I'm not sure of the security 84 | ; implications of this---a malicious user can set either environment 85 | ; variable to cause problems, but if a malicious user can do that, I 86 | ; suspect you have other issues. 87 | ;--------------------------------------------------------------------*/ 88 | 89 | seedbank = getenv("SEEDBANK_SEED"); 90 | 91 | if (seedbank != NULL) 92 | { 93 | char *ep; 94 | unsigned long val; 95 | char buffer[64]; 96 | 97 | if (strcmp(seedbank,"LAST") == 0) 98 | { 99 | seedbank_file = getenv("SEEDBANK_FILE"); 100 | if (seedbank_file != NULL) 101 | { 102 | FILE *fp = fopen(seedbank_file,"r"); 103 | 104 | /*------------------------------------------------------------------ 105 | ; most common error---file doesn't exist. But there's not real easy 106 | ; way to check for that condition only. So in some bizarre cases, 107 | ; not reporting an error may fail us here. Well, if we had issues 108 | ; reading, we might have issues writing, so let's hope the check 109 | ; below finds an issue. 110 | ; 111 | ; But we still need a seed. So let's skip ahead (GOTO WARNING!). 112 | ;------------------------------------------------------------------*/ 113 | 114 | if (fp != NULL) 115 | { 116 | memset(buffer,0,sizeof(buffer)); 117 | fgets(buffer,sizeof(buffer),fp); 118 | fclose(fp); 119 | seedbank = buffer; 120 | } 121 | else 122 | goto math_randomseed_normal; 123 | } 124 | } 125 | 126 | errno = 0; 127 | val = strtoul(seedbank,&ep,10); 128 | if (errno != 0) 129 | return luaL_error(L,"SEEDBANK_SEED not a valid number"); 130 | if (val > UINT_MAX) 131 | return luaL_error(L,"SEEDBANK_SEED range exceeded"); 132 | 133 | seed = val; 134 | } 135 | else 136 | { 137 | math_randomseed_normal: 138 | if (!lua_isboolean(L,1) && lua_isnumber(L,1)) 139 | seed = lua_tonumber(L,1); 140 | else 141 | { 142 | FILE *fp; 143 | 144 | if (lua_toboolean(L,1)) 145 | { 146 | fp = fopen("/dev/random","rb"); 147 | if (fp == NULL) 148 | return luaL_error(L,"The NSA is keeping you from seeding your RNG"); 149 | } 150 | else 151 | { 152 | fp = fopen("/dev/urandom","rb"); 153 | if (fp == NULL) 154 | return luaL_error(L,"cannot seed RNG"); 155 | } 156 | 157 | fread(&seed,sizeof(seed),1,fp); 158 | fclose(fp); 159 | } 160 | } 161 | 162 | seedbank_file = getenv("SEEDBANK_FILE"); 163 | if (seedbank_file) 164 | { 165 | FILE *fp = fopen(seedbank_file,"w"); 166 | if (fp != NULL) 167 | { 168 | fprintf(fp,"%u\n",seed); 169 | fclose(fp); 170 | } 171 | else 172 | return luaL_error(L,"SEEDBANK_FILE: %s",strerror(errno)); 173 | } 174 | 175 | seedbank_log = getenv("SEEDBANK_LOG"); 176 | if (seedbank_log != NULL) 177 | { 178 | FILE *fp = fopen(seedbank_log,"a"); 179 | if (fp != NULL) 180 | { 181 | time_t now = time(NULL); 182 | char buffer[20]; 183 | 184 | strftime(buffer,sizeof(buffer),"%Y-%m-%dT%H:%M:%S",localtime(&now)); 185 | fprintf(fp,"%s: %u\n",buffer,seed); 186 | fclose(fp); 187 | } 188 | } 189 | 190 | srand(seed); 191 | lua_pushnumber(L,seed); 192 | return 1; 193 | } 194 | 195 | /**************************************************************************/ 196 | 197 | static int math_idiv(lua_State *const L) 198 | { 199 | long numer = luaL_checkinteger(L,1); 200 | long denom = luaL_checkinteger(L,2); 201 | ldiv_t result; 202 | 203 | if (denom == 0) 204 | { 205 | if (numer < 0) 206 | { 207 | lua_pushnumber(L,-HUGE_VAL); 208 | lua_pushnumber(L,-HUGE_VAL); 209 | } 210 | else 211 | { 212 | lua_pushnumber(L,HUGE_VAL); 213 | lua_pushnumber(L,HUGE_VAL); 214 | } 215 | } 216 | else 217 | { 218 | result = ldiv(numer,denom); 219 | lua_pushinteger(L,result.quot); 220 | lua_pushinteger(L,result.rem); 221 | } 222 | 223 | return 2; 224 | } 225 | 226 | /**************************************************************************/ 227 | 228 | static int math_div(lua_State *const L) 229 | { 230 | double numer = luaL_checknumber(L,1); 231 | double denom = luaL_checknumber(L,2); 232 | 233 | lua_pushnumber(L,numer / denom); 234 | lua_pushnumber(L,fmod(numer,denom)); 235 | 236 | return 2; 237 | } 238 | 239 | /************************************************************************/ 240 | 241 | int luaopen_org_conman_math(lua_State *L) 242 | { 243 | static const struct luaL_Reg reg_math[] = 244 | { 245 | { "seed" , math_seed }, 246 | { "randomseed" , math_randomseed }, 247 | { "idiv" , math_idiv }, 248 | { "div" , math_div }, 249 | { NULL , NULL } 250 | }; 251 | 252 | #if LUA_VERSION_NUM == 501 253 | luaL_register(L,"org.conman.math",reg_math); 254 | #else 255 | luaL_newlib(L,reg_math); 256 | #endif 257 | return 1; 258 | } 259 | 260 | /**************************************************************************/ 261 | -------------------------------------------------------------------------------- /test/base64-test.lua: -------------------------------------------------------------------------------- 1 | -- luacheck: ignore 611 2 | 3 | local tap = require "tap14" 4 | local base64 = require "org.conman.base64" 5 | 6 | local data = "" do 7 | for i = 0 , 255 do 8 | data = data .. string.char(i) 9 | end 10 | for i = 255 , 0 , -1 do 11 | data = data .. string.char(i) 12 | end 13 | assert(#data == 512) 14 | end 15 | 16 | local tests = 17 | { 18 | { 19 | name = "RFC-1421 (deprecated)", 20 | last = "+/", 21 | pad = "=", 22 | len = 64, 23 | ignore = false, 24 | strict = false, 25 | nocrlf = false, 26 | }, 27 | 28 | { 29 | name = "RFC-2045 (default)", 30 | last = "+/", 31 | pad = "=", 32 | len = 76, 33 | ignore = true, 34 | strict = false, 35 | nocrlf = false, 36 | }, 37 | 38 | { 39 | name = "UTF-7", 40 | last = "+/", 41 | pad = "", 42 | len = -1, 43 | ignore = false, 44 | strict = false, 45 | nocrlf = true, 46 | }, 47 | 48 | { 49 | name = "IMAP", 50 | last = "+,", 51 | pad = "", 52 | len = -1, 53 | ignore = false, 54 | strict = false, 55 | nocrlf = true, 56 | }, 57 | 58 | { 59 | name = "RFC-4648 s4", 60 | last = "+/", 61 | pad = "", 62 | len = -1, 63 | ignore = false, 64 | strict = false, 65 | nocrlf = true, 66 | }, 67 | 68 | { 69 | name = "RFC-4648 s5", 70 | last = "-_", 71 | pad = "", 72 | len = -1, 73 | ignore = false, 74 | strict = false, 75 | nocrlf = true, 76 | }, 77 | } 78 | 79 | tap.plan(#tests * 5 + 4) 80 | 81 | for _,t in ipairs(tests) do 82 | local b = base64(t) 83 | local x = b:encode(data) 84 | tap.assert(x,"%s: encoding",t.name) 85 | if t.len > 0 then 86 | tap.assert(#x:match("^(.-)\n") == t.len,"%s: length check",t.name) 87 | else 88 | tap.assert(#x == 683,"%s: length check",t.name) 89 | end 90 | if t.pad == "=" then 91 | tap.assert(x:sub(-1,-1) == t.pad,"%s: pad check",t.name) 92 | else 93 | tap.assert(x:sub(-1,-1) ~= t.pad,"%s: pad check",t.name) 94 | end 95 | local y = b:decode(x) 96 | tap.assert(y,"%s: decoding",t.name) 97 | tap.assert(y == data,"%s: decoding data check",t.name) 98 | end 99 | 100 | local b = base64 { strict = true } 101 | local y = b:decode("QQ==") 102 | tap.assert(y,"strict mode: decoding good data") 103 | tap.assert(#y == 1,"strict mode: decoding length good data") 104 | tap.assert(y == 'A',"strict mode: decoding good data check") 105 | y = b:decode("QR==") 106 | tap.assert(not y,"strict mode: decoding malicious data") 107 | 108 | os.exit(tap.done()) 109 | -------------------------------------------------------------------------------- /test/clock-test.lua: -------------------------------------------------------------------------------- 1 | 2 | local tap = require "tap14" 3 | local clock = require "org.conman.clock" 4 | local process = require "org.conman.process" 5 | local signal = require "org.conman.signal" 6 | 7 | local child = process.fork() 8 | if not child then 9 | io.stderr:write("failure\n") 10 | os.exit(1) 11 | end 12 | 13 | local info 14 | 15 | if child == 0 then 16 | signal.catch('int') 17 | local left = clock.sleep(2) 18 | if left >= 0.9 and left <= 1.0 then 19 | process.exit(0) 20 | else 21 | process.exit(1) 22 | end 23 | else 24 | clock.sleep(1) 25 | signal.raise('int',child) 26 | info = process.wait(child) 27 | end 28 | 29 | tap.plan(1) 30 | tap.assert(info.rc == 0) 31 | tap.done() 32 | -------------------------------------------------------------------------------- /test/idn-test.lua: -------------------------------------------------------------------------------- 1 | 2 | -- luacheck: ignore 611 631 3 | -- Examples pulled from RFC-3492 4 | 5 | local tap = require "tap14" 6 | local idn = require "org.conman.idn" 7 | 8 | tap.plan(2) 9 | 10 | local data = 11 | { 12 | { 13 | what = "(A) Arabic (Egyptian)", 14 | orig = "\u{0644}\u{064A}\u{0647}\u{0645}\u{0627}\u{0628}\u{062A}\u{0643}\u{0644}\u{0645}\u{0648}\u{0634}\u{0639}\u{0631}\u{0628}\u{064A}\u{061F}", 15 | puny = "xn--egbpdaj6bu4bxfgehfvwxn", 16 | }, 17 | 18 | { 19 | what = "(B) Chinese (simplified)", 20 | orig = "\u{4ED6}\u{4EEC}\u{4E3A}\u{4EC0}\u{4E48}\u{4E0D}\u{8BF4}\u{4E2D}\u{6587}", 21 | puny = "xn--ihqwcrb4cv8a8dqg056pqjye", 22 | }, 23 | 24 | { 25 | what = "(C) Chinese (traditional)", 26 | orig = "\u{4ED6}\u{5011}\u{7232}\u{4EC0}\u{9EBD}\u{4E0D}\u{8AAA}\u{4E2D}\u{6587}", 27 | puny = "xn--ihqwctvzc91f659drss3x8bo0yb", 28 | }, 29 | 30 | { 31 | what = "(D) Czech: Proprostnemluvesky", 32 | orig = "\u{0050}\u{0072}\u{006F}\u{010D}\u{0070}\u{0072}\u{006F}\u{0073}\u{0074}\u{011B}\u{006E}\u{0065}\u{006D}\u{006C}\u{0075}\u{0076}\u{00ED}\u{010D}\u{0065}\u{0073}\u{006B}\u{0079}", 33 | puny = "xn--Proprostnemluvesky-uyb24dma41a", 34 | }, 35 | 36 | { 37 | what = "(E) Hebrew", 38 | orig = "\u{05DC}\u{05DE}\u{05D4}\u{05D4}\u{05DD}\u{05E4}\u{05E9}\u{05D5}\u{05D8}\u{05DC}\u{05D0}\u{05DE}\u{05D3}\u{05D1}\u{05E8}\u{05D9}\u{05DD}\u{05E2}\u{05D1}\u{05E8}\u{05D9}\u{05EA}", 39 | puny = "xn--4dbcagdahymbxekheh6e0a7fei0b", 40 | }, 41 | 42 | { 43 | what = "(F) Hindi (Devanagari)", 44 | orig = "\u{092F}\u{0939}\u{0932}\u{094B}\u{0917}\u{0939}\u{093F}\u{0928}\u{094D}\u{0926}\u{0940}\u{0915}\u{094D}\u{092F}\u{094B}\u{0902}\u{0928}\u{0939}\u{0940}\u{0902}\u{092C}\u{094B}\u{0932}\u{0938}\u{0915}\u{0924}\u{0947}\u{0939}\u{0948}\u{0902}", 45 | puny = "xn--i1baa7eci9glrd9b2ae1bj0hfcgg6iyaf8o0a1dig0cd", 46 | }, 47 | 48 | { 49 | what = "(G) Japanese (kanji and hiragana)", 50 | orig = "\u{306A}\u{305C}\u{307F}\u{3093}\u{306A}\u{65E5}\u{672C}\u{8A9E}\u{3092}\u{8A71}\u{3057}\u{3066}\u{304F}\u{308C}\u{306A}\u{3044}\u{306E}\u{304B}", 51 | puny = "xn--n8jok5ay5dzabd5bym9f0cm5685rrjetr6pdxa", 52 | }, 53 | 54 | --[[ Passed in word exceeds DNS label length 55 | { 56 | what = "(H) Korean (Hangul syllables)", 57 | orig = "\u{C138}\u{ACC4}\u{C758}\u{BAA8}\u{B4E0}\u{C0AC}\u{B78C}\u{B4E4}\u{C774}\u{D55C}\u{AD6D}\u{C5B4}\u{B97C}\u{C774}\u{D574}\u{D55C}\u{B2E4}\u{BA74}\u{C5BC}\u{B9C8}\u{B098}\u{C88B}\u{C744}\u{AE4C}", 58 | puny = "xn--989aomsvi5e83db1d2a355cv1e0vak1dwrv93d5xbh15a0dt30a5jpsd879ccm6fea98c", 59 | }, 60 | --]] 61 | 62 | { 63 | what = "(I) Russian (Cyrillic)", 64 | orig = "\u{043F}\u{043E}\u{0447}\u{0435}\u{043C}\u{0443}\u{0436}\u{0435}\u{043E}\u{043D}\u{0438}\u{043D}\u{0435}\u{0433}\u{043E}\u{0432}\u{043E}\u{0440}\u{044F}\u{0442}\u{043F}\u{043E}\u{0440}\u{0443}\u{0441}\u{0441}\u{043A}\u{0438}", 65 | puny = "xn--b1abfaaepdrnnbgefbadotcwatmq2g4l", 66 | }, 67 | 68 | { 69 | what = "(J) Spanish: PorqunopuedensimplementehablarenEspaol", 70 | orig = "\u{0050}\u{006F}\u{0072}\u{0071}\u{0075}\u{00E9}\u{006E}\u{006F}\u{0070}\u{0075}\u{0065}\u{0064}\u{0065}\u{006E}\u{0073}\u{0069}\u{006D}\u{0070}\u{006C}\u{0065}\u{006D}\u{0065}\u{006E}\u{0074}\u{0065}\u{0068}\u{0061}\u{0062}\u{006C}\u{0061}\u{0072}\u{0065}\u{006E}\u{0045}\u{0073}\u{0070}\u{0061}\u{00F1}\u{006F}\u{006C}", 71 | puny = "xn--PorqunopuedensimplementehablarenEspaol-fmd56a", 72 | }, 73 | 74 | { 75 | what = "(K) Vietnamese", 76 | orig = "\u{0054}\u{1EA1}\u{0069}\u{0073}\u{0061}\u{006F}\u{0068}\u{1ECD}\u{006B}\u{0068}\u{00F4}\u{006E}\u{0067}\u{0074}\u{0068}\u{1EC3}\u{0063}\u{0068}\u{1EC9}\u{006E}\u{00F3}\u{0069}\u{0074}\u{0069}\u{1EBF}\u{006E}\u{0067}\u{0056}\u{0069}\u{1EC7}\u{0074}", 77 | puny = "xn--TisaohkhngthchnitingVit-kjcr8268qyxafd2f1b9g", 78 | }, 79 | 80 | { 81 | what = "(L) 3B", 82 | orig = "\u{0033}\u{5E74}\u{0042}\u{7D44}\u{91D1}\u{516B}\u{5148}\u{751F}", 83 | puny = "xn--3B-ww4c5e180e575a65lsy2b", 84 | }, 85 | 86 | { 87 | what = "(M) -with-SUPER-MONKEYS", 88 | orig = "\u{5B89}\u{5BA4}\u{5948}\u{7F8E}\u{6075}\u{002D}\u{0077}\u{0069}\u{0074}\u{0068}\u{002D}\u{0053}\u{0055}\u{0050}\u{0045}\u{0052}\u{002D}\u{004D}\u{004F}\u{004E}\u{004B}\u{0045}\u{0059}\u{0053}", 89 | puny = "xn---with-SUPER-MONKEYS-pc58ag80a8qai00g7n9n", 90 | }, 91 | 92 | { 93 | what = "(N) Hello-Another-Way-", 94 | orig = "\u{0048}\u{0065}\u{006C}\u{006C}\u{006F}\u{002D}\u{0041}\u{006E}\u{006F}\u{0074}\u{0068}\u{0065}\u{0072}\u{002D}\u{0057}\u{0061}\u{0079}\u{002D}\u{305D}\u{308C}\u{305E}\u{308C}\u{306E}\u{5834}\u{6240}", 95 | puny = "xn--Hello-Another-Way--fc4qua05auwb3674vfr0b", 96 | }, 97 | 98 | { 99 | what = "(O) 2", 100 | orig = "\u{3072}\u{3068}\u{3064}\u{5C4B}\u{6839}\u{306E}\u{4E0B}\u{0032}", 101 | puny = "xn--2-u9tlzr9756bt3uc0v", 102 | }, 103 | 104 | { 105 | what = "(P) MajiKoi5", 106 | orig= "\u{004D}\u{0061}\u{006A}\u{0069}\u{3067}\u{004B}\u{006F}\u{0069}\u{3059}\u{308B}\u{0035}\u{79D2}\u{524D}", 107 | puny = "xn--MajiKoi5-783gue6qz075azm5e", 108 | }, 109 | 110 | { 111 | what = "(Q) de", 112 | orig = "\u{30D1}\u{30D5}\u{30A3}\u{30FC}\u{0064}\u{0065}\u{30EB}\u{30F3}\u{30D0}", 113 | puny = "xn--de-jg4avhby1noc0d", 114 | }, 115 | 116 | { 117 | what = "(R) ", 118 | orig = "\u{305D}\u{306E}\u{30B9}\u{30D4}\u{30FC}\u{30C9}\u{3067}", 119 | puny = "xn--d9juau41awczczp", 120 | }, 121 | 122 | --[[ Not a realistic test for this 123 | { 124 | what = "(S) -> $1.00 <-", 125 | orig = "\u{002D}\u{003E}\u{0020}\u{0024}\u{0031}\u{002E}\u{0030}\u{0030}\u{0020}\u{003C}\u{002D}", 126 | puny = "xn---> $1.00 <--", 127 | }, 128 | --]] 129 | } 130 | 131 | tap.plan(#data,"test set 1") 132 | for _,test in ipairs(data) do 133 | tap.plan(4,test.what) 134 | local e = idn.encode(test.orig) 135 | tap.assert(e,"encode()") 136 | tap.assert(e == test.puny,"encode() matches") 137 | local d = idn.decode(e) 138 | tap.assert(d,"decode()") 139 | tap.assert(d == test.orig,"decode() matches") 140 | tap.done() 141 | end 142 | tap.done() 143 | 144 | local data2 = 145 | { 146 | { 147 | what = "Normalization 1", 148 | orig = "re\u{0301}sume\u{0301}", 149 | puny = "xn--rsum-bpad", 150 | tran = "r\u{00E9}sum\u{00E9}", 151 | }, 152 | 153 | { 154 | what = "Normalization 2", 155 | orig = "fo\u{0301}\u{0321}b", 156 | puny = "xn--fb-5ja64t", 157 | tran = "f\u{00F3}\u{0321}b", 158 | }, 159 | 160 | { 161 | what = "Normalization 3", 162 | orig = "fo\u{0321}\u{0301}b", 163 | puny = "xn--fb-5ja64t", 164 | tran = "f\u{00F3}\u{0321}b", 165 | }, 166 | } 167 | 168 | tap.plan(#data2,"test set 2---normalization") 169 | for _,test in ipairs(data2) do 170 | tap.plan(4,test.what) 171 | local e = idn.encode(test.orig) 172 | tap.assert(e,"encode()") 173 | tap.assert(e == test.puny,"encode() matches") 174 | local d = idn.decode(e) 175 | tap.assert(d,"decode()") 176 | tap.assert(d == test.tran,"decode() matches") 177 | tap.done() 178 | end 179 | tap.done() 180 | os.exit(tap.done()) 181 | -------------------------------------------------------------------------------- /test/net-test.lua: -------------------------------------------------------------------------------- 1 | 2 | -- luacheck: ignore 611 3 | 4 | local tap = require "tap14" 5 | local net = require "org.conman.net" 6 | 7 | local function compare_lists(a,b) 8 | if (#a ~= #b) then return false end 9 | for i = 1 , #a do 10 | if a[i] ~= b[i] then return false end 11 | end 12 | return true 13 | end 14 | 15 | -- --------------------------------------------------------------------- 16 | -- Address tests 17 | -- --------------------------------------------------------------------- 18 | 19 | tap.plan(7) 20 | 21 | local function address_test(case) 22 | tap.plan(10,case.desc) 23 | local a1 = net.address(case.addr,case.proto,case.port) 24 | local a2 = net.address(case.addr,case.proto,case.port) 25 | 26 | tap.assert(a1 == a2,"equality works") 27 | tap.assert(#a1 == case.len,"length works") 28 | tap.assert(#a2 == case.len,"length works (again)") 29 | 30 | tap.assert(a1.family == case.family,"family") 31 | tap.assert(a1.addrbits == case.addrbits,"addrbits") 32 | tap.assert(a1.port == case.iport,"port") 33 | tap.assert(tostring(a1) == case.tostring,"tostring") 34 | tap.assert(a1:display() == case.display,"display") 35 | tap.assert(a1:display(case.iport) == case.display_port,"display port") 36 | 37 | if a1.family == 'ip6' then 38 | tap.assert(a1.daddr == '[' .. a1.addr .. ']',"daddr") 39 | else 40 | tap.assert(a1.daddr == a1.addr,"daddr") 41 | end 42 | tap.done() 43 | end 44 | 45 | address_test { 46 | desc = "UDP/IP with named port", 47 | family = 'ip', 48 | addr = "127.0.0.1", 49 | addrbits = "\127\0\0\1", 50 | proto = 'udp', 51 | port = 'domain', 52 | iport = 53, 53 | len = 4, 54 | tostring = "127.0.0.1:53", 55 | display = "127.0.0.1:53", 56 | display_port = "127.0.0.1" 57 | } 58 | 59 | address_test { 60 | desc = "TCP/IP with numeric port", 61 | family = 'ip', 62 | addr = "127.0.0.1", 63 | addrbits = "\127\0\0\1", 64 | proto = 'tcp', 65 | port = 33333, 66 | iport = 33333, 67 | len = 4, 68 | tostring = "127.0.0.1:33333", 69 | display = "127.0.0.1:33333", 70 | display_port = "127.0.0.1", 71 | } 72 | 73 | address_test { 74 | desc = "OSPF/IP, named protocol", 75 | family = 'ip', 76 | addr = "127.0.0.1", 77 | addrbits = "\127\0\0\1", 78 | proto = 'ospf', 79 | iport = 89, 80 | len = 4, 81 | tostring = "127.0.0.1:89", 82 | display = "127.0.0.1:89", 83 | display_port = "127.0.0.1", 84 | } 85 | 86 | address_test { 87 | desc = "UDP/IP6 with named port", 88 | family = 'ip6', 89 | addr = "fc00::c0ff:eeba:d015:dead:beef", 90 | addrbits = "\252\0\0\0\0\0\192\255\238\186\208\21\222\173\190\239", 91 | proto = 'udp', 92 | port = 'domain', 93 | iport = 53, 94 | len = 16, 95 | tostring = "[fc00::c0ff:eeba:d015:dead:beef]:53", 96 | display = "[fc00::c0ff:eeba:d015:dead:beef]:53", 97 | display_port = "[fc00::c0ff:eeba:d015:dead:beef]", 98 | } 99 | 100 | address_test { 101 | desc = "TCP/IP6 with numeric port", 102 | family = 'ip6', 103 | addr = "fc00::c0ff:eeba:d015:dead:beef", 104 | addrbits = "\252\0\0\0\0\0\192\255\238\186\208\21\222\173\190\239", 105 | proto = 'udp', 106 | port = 33333, 107 | iport = 33333, 108 | len = 16, 109 | tostring = "[fc00::c0ff:eeba:d015:dead:beef]:33333", 110 | display = "[fc00::c0ff:eeba:d015:dead:beef]:33333", 111 | display_port = "[fc00::c0ff:eeba:d015:dead:beef]", 112 | } 113 | 114 | address_test { 115 | desc = "OSPF/IP, named protocol", 116 | family = 'ip6', 117 | addr = "fc00::c0ff:eeba:d015:dead:beef", 118 | addrbits = "\252\0\0\0\0\0\192\255\238\186\208\21\222\173\190\239", 119 | proto = 'ospf', 120 | iport = 89, 121 | len = 16, 122 | tostring = "[fc00::c0ff:eeba:d015:dead:beef]:89", 123 | display = "[fc00::c0ff:eeba:d015:dead:beef]:89", 124 | display_port = "[fc00::c0ff:eeba:d015:dead:beef]", 125 | } 126 | 127 | local list1 = 128 | { 129 | net.address('192.168.1.10','udp',3333), 130 | net.address('192.168.1.10','udp',2222), 131 | net.address('192.168.1.10','tcp',4444), 132 | net.address('192.168.1.10','tcp',1111), 133 | net.address('127.0.0.1','udp',17), 134 | net.address('127.0.0.1','udp',3), 135 | net.address('127.0.0.1','tcp',11), 136 | net.address('127.0.0.1','tcp',7), 137 | net.address('/dev/log','udp'), 138 | net.address('/dev/log','tcp'), 139 | net.address('fc00::1','udp',33), 140 | net.address('fc00::1','udp',3), 141 | net.address('fc00::1','tcp',22), 142 | net.address('fc00::1','tcp',5), 143 | net.address('::1','udp',33), 144 | net.address('::1','udp',3), 145 | net.address('::1','tcp',22), 146 | net.address('::1','tcp',5), 147 | } 148 | 149 | local list2 = 150 | { 151 | net.address('/dev/log','tcp'), 152 | net.address('/dev/log','udp'), 153 | net.address('127.0.0.1','udp',3), 154 | net.address('127.0.0.1','tcp',7), 155 | net.address('127.0.0.1','tcp',11), 156 | net.address('127.0.0.1','udp',17), 157 | net.address('192.168.1.10','tcp',1111), 158 | net.address('192.168.1.10','udp',2222), 159 | net.address('192.168.1.10','udp',3333), 160 | net.address('192.168.1.10','tcp',4444), 161 | net.address('::1','udp',3), 162 | net.address('::1','tcp',5), 163 | net.address('::1','tcp',22), 164 | net.address('::1','udp',33), 165 | net.address('fc00::1','udp',3), 166 | net.address('fc00::1','tcp',5), 167 | net.address('fc00::1','tcp',22), 168 | net.address('fc00::1','udp',33), 169 | } 170 | 171 | table.remove(list1) -- because the last call to net.address() fills in the 172 | table.remove(list2) -- last slot with 0. So remove that 0. 173 | table.sort(list1) 174 | 175 | tap.assert(compare_lists(list1,list2),"test sortability") 176 | os.exit(tap.done(),true) 177 | -------------------------------------------------------------------------------- /test/pollset-test.lua: -------------------------------------------------------------------------------- 1 | -- luacheck: ignore 611 411 2 | 3 | local tap = require "tap14" 4 | local fsys = require "org.conman.fsys" 5 | local pollset = require "org.conman.pollset" 6 | 7 | -- ------------------------------------------------------------- 8 | -- create some data to schlep around, and a pipe to select upon 9 | -- ------------------------------------------------------------- 10 | 11 | local data = string.rep(" ",256) 12 | local pipe = fsys.pipe() 13 | pipe.read:setvbuf('no') 14 | pipe.write:setvbuf('no') 15 | 16 | -- --------------- 17 | -- Run the tests 18 | -- ---------------- 19 | 20 | tap.plan(6) 21 | local set do 22 | set = pollset() 23 | tap.assertB(set,"set creation") 24 | tap.assertB(set._implementation,"We're testing the %s implementation",set._implemenation or "-") 25 | end 26 | 27 | tap.plan(7,"timeout test (5 seconds)") do 28 | local err = set:insert(pipe.read,"r") 29 | tap.assertB(err,"inserting the read event") 30 | 31 | local zen = os.time() 32 | local okay,err = set:wait(5) 33 | local now = os.time() 34 | 35 | tap.assert(okay,"waiting") 36 | tap.assert(err,"we got an error (even if success)") 37 | tap.assert((now - zen) >= 5,"we took five seconds") 38 | 39 | local events,state,var = set:events() 40 | tap.assert(events,"events exist") 41 | tap.assert(state,"state info") 42 | tap.assert(not var,"variable info") 43 | tap.done() 44 | end 45 | 46 | tap.plan(8,"testing read readiness") do 47 | pipe.write:write(data) 48 | 49 | local zen = os.time() 50 | local okay,err = set:wait(5) 51 | local now = os.time() 52 | 53 | tap.assert(okay,"waiting for up to 5 seconds") 54 | tap.assert(not err,"no error") 55 | tap.assert((now-zen) <= 1,"we didn't actually wait") 56 | local events,state,var = set:events() 57 | tap.assert(events,"events exist") 58 | local e = events(state,var) 59 | tap.assert(e,"event item") 60 | tap.assert(e.read,"event is read event") 61 | tap.assert(events(state,var) == nil,"no further events") 62 | 63 | local blob = pipe.read:read(256) 64 | tap.assert(#blob == 256,"we have read data") 65 | tap.done() 66 | end 67 | 68 | do 69 | local err = set:remove(pipe.read) 70 | tap.assert(err == 0,"file removed from set") 71 | end 72 | 73 | tap.plan(16,"testing write readiness") do 74 | 75 | local err = set:insert(pipe.read,"r") 76 | tap.assertB(err == 0,"insert read file into set") 77 | 78 | local err = set:insert(pipe.write,"w") 79 | tap.assertB(err == 0,"insert write file into set") 80 | 81 | local zen = os.time() 82 | local okay,err = set:wait(5) 83 | local now = os.time() 84 | 85 | tap.assert(okay,"wait for events") 86 | tap.assert(not err,"no error while waiting") 87 | tap.assert((now-zen) <= 1,"no waiting for data") 88 | local events,state,var = set:events() 89 | tap.assert(events,"we have events") 90 | local e = events(state,var) 91 | tap.assert(e,"first event") 92 | tap.assert(e.write,"we can write") 93 | tap.assert(events(state,var) == nil,"no further events") 94 | 95 | pipe.write:write(data) 96 | set:remove(pipe.write) 97 | 98 | local zen = os.time() 99 | local okay,err = set:wait(5) 100 | local now = os.time() 101 | 102 | tap.assert(okay,"wait for more events") 103 | tap.assert(not err,"no error") 104 | tap.assert((now-zen) <= 1,"no waiting for data") 105 | local events,state,var = set:events() 106 | tap.assert(events,"we have events") 107 | local e = events(state,var) 108 | tap.assert(e,"first event") 109 | tap.assert(e.read,"it's a read event") 110 | 111 | local blob = pipe.read:read(256) 112 | tap.assert(#blob == 256,"we have data") 113 | tap.done() 114 | end 115 | 116 | os.exit(tap.done(),true) 117 | -------------------------------------------------------------------------------- /test/tap14.lua: -------------------------------------------------------------------------------- 1 | -- ************************************************************************* 2 | -- 3 | -- Copyright 2022 by Sean Conner. All Rights Reserved. 4 | -- 5 | -- This program is free software: you can redistribute it and/or modify it 6 | -- under the terms of the GNU General Public License as published by the 7 | -- Free Software Foundation, either version 3 of the License, or (at your 8 | -- option) any later version. 9 | -- 10 | -- This program is distributed in the hope that it will be useful, but 11 | -- WITHOUT ANY WARRANTY; without even the implied warranty of 12 | -- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General 13 | -- Public License for more details. 14 | -- 15 | -- You should have received a copy of the GNU General Public License along 16 | -- with this program. If not, see . 17 | -- 18 | -- Comments, questions and criticisms can be sent to: sean@conman.org 19 | -- 20 | -- ************************************************************************* 21 | -- luacheck: ignore 611 22 | -- luacheck: globals plan comment assert assertB done 23 | 24 | local io = require "io" 25 | local string = require "string" 26 | local os = require "os" 27 | local table = require "table" 28 | 29 | local _VERSION = _VERSION 30 | 31 | if _VERSION == "Lua 5.1" then 32 | module("tap14") 33 | else 34 | _ENV = {} 35 | end 36 | 37 | local mtaps = {} 38 | 39 | -- ************************************************************************* 40 | 41 | local function ok(msg,...) 42 | local tap = mtaps[#mtaps] 43 | io.stdout:write(tap.pad,"ok ",tap.id) 44 | if msg then 45 | io.stdout:write(" - ",string.format(msg,...)) 46 | end 47 | io.stdout:write("\n") 48 | tap.id = tap.id + 1 49 | end 50 | 51 | -- ************************************************************************* 52 | 53 | local function notok(msg,...) 54 | local tap = mtaps[#mtaps] 55 | io.stdout:write(tap.pad,"not ok ",tap.id) 56 | if msg then 57 | io.stdout:write(" - ",string.format(msg,...)) 58 | end 59 | io.stdout:write("\n") 60 | tap.pass = false 61 | tap.id = tap.id + 1 62 | end 63 | 64 | -- ************************************************************************* 65 | 66 | local function bail(msg,...) 67 | io.stdout:write("Bail out!") 68 | if msg then 69 | io.stdout:write(" ",string.format(msg,...)) 70 | end 71 | io.stdout:write("\n") 72 | os.exit(1,true) 73 | end 74 | 75 | -- ************************************************************************* 76 | 77 | function plan(plan,fmt,...) 78 | local tap = 79 | { 80 | name = (fmt and string.format(fmt,...)) or "", 81 | pad = (mtaps[#mtaps] and mtaps[#mtaps].pad .. " ") or "", 82 | plan = plan or 0, 83 | id = 1, 84 | pass = true, 85 | } 86 | 87 | if tap.name and tap.name ~= "" then 88 | io.stdout:write(mtaps[#mtaps].pad,"# Subtest: ",tap.name,"\n") 89 | end 90 | 91 | if tap.plan ~= 0 then 92 | io.stdout:write(tap.pad,"1..",tap.plan,"\n") 93 | end 94 | 95 | table.insert(mtaps,tap) 96 | end 97 | 98 | -- ************************************************************************* 99 | 100 | function comment(fmt,...) 101 | io.stdout:write(mtaps[#mtaps].pad,"# ",string.format(fmt,...),"\n") 102 | end 103 | 104 | -- ************************************************************************* 105 | 106 | function assert(cond,...) -- luacheck: ignore 107 | if cond then 108 | ok(...) 109 | else 110 | notok(...) 111 | end 112 | return cond 113 | end 114 | 115 | -- ************************************************************************* 116 | 117 | function assertB(cond,...) 118 | if cond then 119 | ok(...) 120 | else 121 | bail(...) 122 | end 123 | return cond 124 | end 125 | 126 | -- ************************************************************************* 127 | 128 | function done() 129 | local tap = table.remove(mtaps) 130 | 131 | if tap.plan == 0 then 132 | io.stdout:write(tap.pad,"1..",tap.id - 1,"\n") 133 | end 134 | 135 | if #mtaps > 0 then 136 | if tap.pass then 137 | if tap.name ~= "" then 138 | ok(tap.name) 139 | else 140 | ok() 141 | end 142 | else 143 | if tap.name ~= "" then 144 | notok(tap.name) 145 | else 146 | notok() 147 | end 148 | end 149 | end 150 | return tap.pass and 0 or 1 151 | end 152 | 153 | -- ************************************************************************* 154 | 155 | io.stdout:write("TAP version 14\n") 156 | 157 | if _VERSION >= "Lua 5.2" then 158 | return _ENV 159 | end 160 | --------------------------------------------------------------------------------