├── LICENSE ├── Makefile ├── README ├── abnf.lua ├── ascii.lua ├── ascii ├── char.lua ├── control.lua └── ctrl.lua ├── asv.lua ├── email.lua ├── gopher-index.lua ├── http-client.lua ├── http-server.lua ├── ih.lua ├── ini.lua ├── ip-text.lua ├── ip.lua ├── iri.lua ├── iso.lua ├── iso ├── char.lua ├── control.lua └── ctrl.lua ├── json.lua ├── jsons.lua ├── mimetype.lua ├── rockspecs ├── org.conman.parsers.abnf-1.0.0-4.rockspec ├── org.conman.parsers.ascii-1.0.0-2.rockspec ├── org.conman.parsers.ascii.char-1.0.0-2.rockspec ├── org.conman.parsers.ascii.control-1.0.0-2.rockspec ├── org.conman.parsers.ascii.ctrl-1.0.0-2.rockspec ├── org.conman.parsers.email-1.2.1-1.rockspec ├── org.conman.parsers.ini-1.0.1-3.rockspec ├── org.conman.parsers.ip-1.0.2-3.rockspec ├── org.conman.parsers.ip-text-1.0.0-3.rockspec ├── org.conman.parsers.iso-1.0.0-2.rockspec ├── org.conman.parsers.iso.char-1.0.0-2.rockspec ├── org.conman.parsers.iso.control-1.0.0-2.rockspec ├── org.conman.parsers.iso.ctrl-1.0.0-2.rockspec ├── org.conman.parsers.json-1.1.1-3.rockspec ├── org.conman.parsers.jsons-1.0.7-3.rockspec ├── org.conman.parsers.mimetype-1.0.0-1.rockspec ├── org.conman.parsers.soundex-1.0.1-1.rockspec ├── org.conman.parsers.strftime-1.0.1-1.rockspec ├── org.conman.parsers.url-2.0.3-3.rockspec ├── org.conman.parsers.url.gopher-2.0.0-3.rockspec ├── org.conman.parsers.url.siptel-1.0.0-3.rockspec ├── org.conman.parsers.utf8-1.0.0-2.rockspec ├── org.conman.parsers.utf8.char-1.0.0-2.rockspec ├── org.conman.parsers.utf8.control-1.0.0-2.rockspec └── org.conman.parsers.utf8.ctrl-1.0.0-2.rockspec ├── soundex.lua ├── strftime.lua ├── url.lua ├── url ├── data.lua ├── gopher.lua ├── siptel.lua └── tag.lua ├── utf8.lua └── utf8 ├── char.lua ├── control.lua └── ctrl.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 2016 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 | INSTALL = /usr/bin/install 23 | INSTALL_DATA = $(INSTALL) -m 644 24 | LUA ?= lua 25 | LUACHECK = luacheck 26 | 27 | prefix = /usr/local 28 | datarootdir = $(prefix)/share 29 | dataroot = $(datarootdir) 30 | 31 | LUADIR := $(dataroot)/lua/$(shell $(LUA) -e "print(_VERSION:match '^Lua (.*)')") 32 | 33 | .PHONY: install uninstall clean luacheck 34 | 35 | install : 36 | $(INSTALL) -d $(DESTDIR)$(LUADIR)/org/conman/parsers 37 | $(INSTALL) -d $(DESTDIR)$(LUADIR)/org/conman/parsers/url 38 | $(INSTALL) -d $(DESTDIR)$(LUADIR)/org/conman/parsers/ascii 39 | $(INSTALL) -d $(DESTDIR)$(LUADIR)/org/conman/parsers/iso 40 | $(INSTALL) -d $(DESTDIR)$(LUADIR)/org/conman/parsers/utf8 41 | $(INSTALL_DATA) *.lua $(DESTDIR)$(LUADIR)/org/conman/parsers/ 42 | $(INSTALL_DATA) url/*.lua $(DESTDIR)$(LUADIR)/org/conman/parsers/url 43 | $(INSTALL_DATA) ascii/*.lua $(DESTDIR)$(LUADIR)/org/conman/parsers/ascii 44 | $(INSTALL_DATA) iso/*.lua $(DESTDIR)$(LUADIR)/org/conman/parsers/iso 45 | $(INSTALL_DATA) utf8/*.lua $(DESTDIR)$(LUADIR)/org/conman/parsers/utf8 46 | 47 | uninstall : 48 | $(RM) -r $(DESTDIR)$(LUADIR)/org/conman/parsers 49 | 50 | clean: 51 | $(RM) $(shell find . -name '*~') 52 | 53 | luacheck: 54 | $(LUACHECK) *.lua ascii/*.lua iso/*.lua utf8/*.lua url/*.lua 55 | -------------------------------------------------------------------------------- /README: -------------------------------------------------------------------------------- 1 | 2 | The code herein contains LPeg [1] routines for parsing some common data 3 | formats. The current formats are: 4 | 5 | abnf 6 | 7 | The core ruleset from RFC-5234. These rules are used often in RFCs. 8 | 9 | ascii 10 | ascii.char 11 | ascii.control 12 | ascii.ctrl 13 | 14 | Match a single ASCII character. The top level module will match 15 | both graphical charaters and control characters. The "ascii.char" 16 | module only matches the graphical characters; the "ascii.control" 17 | module only matches the control codes. The "ascii.ctrl" will return 18 | the name of a control character, or nil if not a control character. 19 | 20 | iso 21 | iso.char 22 | iso.control 23 | iso.ctrl 24 | 25 | Match a single ISO character. The top level module will match both 26 | graphical, control characters and control sequences. The "iso.char" 27 | only matches the ISO graphical characters; the iso.control" module 28 | mathces only control characters (for example, E or \133). The 29 | "iso.ctrl" will return the name of the control character, plus any 30 | associated data as appropriate. For example: 31 | 32 | [32;40m 33 | 34 | will return a name of "SGR" and a two element array containing 32 35 | and 40. 36 | 37 | NOTE: These modules only deal with the ISO defined characters, and 38 | will NOT match those defined by ASCII. To match a graphical character 39 | that matches both ASCII and ISO: 40 | 41 | char = require "org.conman.parsers.ascii.char 42 | + require "org.conman.parsers.iso.char 43 | 44 | 45 | email 46 | 47 | Parses email headers as defined in: 48 | 49 | RFC-0822 Internet Message Format 50 | RFC-1036 Standard for Interchange of USENET Messages 51 | RFC-2045 Multipurpose Internet Mail Extensions I 52 | RFC-2046 Multipurpose Internet Mail Extensions II 53 | RFC-2047 Multipurpose Internet Mail Extensions III 54 | RFC-2048 Multipurpose Internet Mail Extensions IV 55 | RFC-2369 The Use of URLs as Meta-Syntax for Core Mail 56 | List Commands and their Transport through 57 | Message Header Fields 58 | RFC-2822 Internet Message Format 59 | RFC-2919 A Structured Field and Namespace for the Identification of Mailing Lists 60 | RFC-5064 The Archived-At Message Header Field 61 | RFC-5322 Internet Message Format 62 | 63 | Headers are returned in a Lua table. For example, the following 64 | headers: 65 | 66 | Return-Path: 67 | Received: from brevard.conman.org (brevard.conman.org 68 | [66.252.224.242]) 69 | by mail.example.com (Postfix) 70 | with ESMTP id 538562EA5D07 71 | for ; 72 | Fri, 28 Dec 2012 21:40:11 -0500 73 | From: Sean Conner 74 | To: Sherlock Holmes , 75 | the-scooby-gang: Fred , 76 | Daphne , 77 | Velma , 78 | Shaggy , 79 | Scobby-Doo ;, 80 | The Batman 81 | Subject: I know who did it! 82 | Date: Fri, 28 Dec 2012 21:40:11 -0500 83 | Message-ID: <1234.5678.90abcd@conman.org> 84 | 85 | Will return the following Lua table: 86 | 87 | { 88 | received = 89 | { 90 | [1] = 91 | { 92 | with = "ESMTP", 93 | from = "brevard.conman.org", 94 | id = "538562EA5D07", 95 | when = 96 | { 97 | min = 0.000000, 98 | zone = -18000.000000, 99 | day = 28.000000, 100 | month = 12.000000, 101 | year = 2012.000000, 102 | sec = 1.000000, 103 | hour = 1.000000, 104 | weekday = "Fri", 105 | }, 106 | for = 107 | { 108 | address = "sherlock@example.com", 109 | }, 110 | by = "mail.example.com", 111 | }, 112 | }, 113 | to = 114 | { 115 | [1] = 116 | { 117 | name = "Sherlock Holmes", 118 | address = "sherlock@example.com", 119 | }, 120 | [2] = 121 | { 122 | ['the-scooby-gang'] = 123 | { 124 | [1] = 125 | { 126 | name = "Fred", 127 | address = "fred@example.net", 128 | }, 129 | [2] = 130 | { 131 | name = "Daphne", 132 | address = "daphne@example.net", 133 | }, 134 | [3] = 135 | { 136 | name = "Velma", 137 | address = "velma@example.net", 138 | }, 139 | [4] = 140 | { 141 | name = "Shaggy", 142 | address = "shaggy@example.net", 143 | }, 144 | [5] = 145 | { 146 | name = "Scobby-Doo", 147 | address = "scooby@example.net", 148 | }, 149 | }, 150 | }, 151 | [3] = 152 | { 153 | name = "The Batman", 154 | address = "batman@example.org", 155 | }, 156 | }, 157 | from = 158 | { 159 | [1] = 160 | { 161 | name = "Sean Conner", 162 | address = "sean@conman.org", 163 | }, 164 | }, 165 | date = 166 | { 167 | min = 0.000000, 168 | zone = -18000.000000, 169 | day = 28.000000, 170 | month = 12.000000, 171 | year = 2012.000000, 172 | sec = 1.000000, 173 | hour = 1.000000, 174 | weekday = "Fri", 175 | }, 176 | return_path = 177 | { 178 | [1] = 179 | { 180 | address = "sean@conman.org", 181 | }, 182 | }, 183 | message_id = "1234.5678.90abcd@conman.org", 184 | subject = "I know who did it!", 185 | } 186 | 187 | The only fields not supported are the Resent-* fields; they are 188 | rarely used and the semantics are particularly hard to support via 189 | parsing only. These fields, as well as any other fields not 190 | otherwise understood or parsable will end up on a field called 191 | 'generic' with the key being the raw header name. 192 | 193 | json 194 | 195 | Implements a JSON parser. It requires some additional modules [2] 196 | to run. This will parse a JSON file into a Lua table. The full 197 | grammar is supported, but it expects the input to be valid UTF-8. 198 | 199 | A JSON null value will be converted to nil. If you won't want this 200 | behavior, define a global variable called "null" to be the value 201 | you want for a JSON null. 202 | 203 | jsons 204 | 205 | Another implementation of a JSON parser. This one "streams" the 206 | input, meaning it will handle large JSON files the other one won't, 207 | and is a drop in replacement. You can also pass in a function that 208 | will return more data so you can actually "stream" data into the 209 | parser. 210 | 211 | ip 212 | 213 | Provides two LPeg patterns, IPv4 and IPv6 which parse and convert 214 | said addresses directly into their network-order binary formats. 215 | 216 | ip-text 217 | 218 | Provides two LPeg patterns, IPv4 and IPv6 which parse and return said 219 | addresses as text, unlike the ip module above. 220 | 221 | ini 222 | 223 | Provides a INI file parser that returns a Lua table from a INI 224 | file. A sample INI file such as: 225 | 226 | ; we allow "default" values 227 | 228 | default = ok 229 | 230 | [section1] 231 | 232 | var1 = foo 233 | var2 = 12,23,34,54,44 234 | VAR3 = "var3=foo",33,44,55 235 | var2 = apple 236 | Var4 = 55 237 | 238 | [section2] 239 | # another comment 240 | ; and so is this one 241 | 242 | var1 = foo bar baz ; this is a comment 243 | var2 = "foo bar baz ; this is not a comment" 244 | 245 | [section1] 246 | 247 | var4=this is a test 248 | var5= this is also a test 249 | var2 = pear 250 | var3 = 88,99 251 | 252 | 253 | will result in a Lua table of: 254 | 255 | { 256 | section1 = 257 | { 258 | var1 = "foo", 259 | var5 = "this is also a test", 260 | var4 = 261 | { 262 | [1] = "55", 263 | [2] = "this is a test", 264 | }, 265 | var3 = 266 | { 267 | [1] = "var3=foo", 268 | [2] = "33", 269 | [3] = "44", 270 | [4] = "55", 271 | [5] = "88", 272 | [6] = "99", 273 | }, 274 | var2 = 275 | { 276 | [1] = "12", 277 | [2] = "23", 278 | [3] = "34", 279 | [4] = "54", 280 | [5] = "44", 281 | [6] = "apple", 282 | [7] = "pear", 283 | }, 284 | }, 285 | default = "ok", 286 | section2 = 287 | { 288 | var1 = "foo bar baz ", 289 | var2 = "foo bar baz ; this is not a comment", 290 | }, 291 | } 292 | 293 | strftime 294 | Parses the format string for strftime() (or os.date() for Lua) and 295 | returns an LPeg expression that can parse that format, with the 296 | exceptions of "%c", "%x" and "%X" (all system specific formats). 297 | For example, the format, "%A, %d %B %Y @ %H:%M:%S" will return the 298 | LPeg expression to parse this: 299 | 300 | Monday, 02 July 2018 @ 16:02:48 301 | 302 | into 303 | 304 | { 305 | min = 2.000000, 306 | wday = 2.000000, 307 | day = 2.000000, 308 | month = 7.000000, 309 | sec = 48.000000, 310 | hour = 16.000000, 311 | year = 2018.000000, 312 | } 313 | 314 | This will even work with other locales, such as "se_NO.UTF-8", 315 | which will allow LPeg to parse: 316 | 317 | vuossárga, 02 suoidnemánu 2018 @ 16:02:48 318 | 319 | into 320 | 321 | { 322 | min = 2,000000, 323 | wday = 2,000000, 324 | day = 2,000000, 325 | month = 7,000000, 326 | sec = 48,000000, 327 | hour = 16,000000, 328 | year = 2018,000000, 329 | } 330 | 331 | url 332 | 333 | Parses URLs per RFC-3986. By default, it will handle the following 334 | URL types: 335 | 336 | http: 337 | https: 338 | file: 339 | ftp: 340 | 341 | Given the following URL: 342 | 343 | http://www.conman.org/people/spc/index.cgi?one=1%3F&two=2&three=3#target1 344 | 345 | It will be broken down into a Lua table as follows: 346 | 347 | { 348 | scheme = "http", 349 | host = "www.conman.org", 350 | port = 80, 351 | path = "/people/spc/index.cgi", 352 | query = "one=1%3F&two=2&three=3", 353 | fragment = "target1", 354 | } 355 | 356 | Other URLs can be parsed, but a URL like: 357 | 358 | mailto:sean@conman.org?cc=fred@example.com,velma@example.net&subject=Current%20Mystery 359 | 360 | will be broken down as: 361 | 362 | { 363 | scheme = "mailto", 364 | path = "sean@conman.org", 365 | query = "cc=fred@example.com,velma@example.net&subject=Current%20Mystery", 366 | } 367 | 368 | which may require more parsing than provided here. 369 | 370 | url.gopher 371 | 372 | Parses "gopher:" URLs per RFC-4266. Given this URL: 373 | 374 | gopher://gopher.conman.org/0foobar%09search%20String%09plus 375 | 376 | it will be broken down as: 377 | 378 | { 379 | scheme = "gopher", 380 | host = "gopher.conman.org", 381 | port = 70.000000, 382 | type = "file", 383 | selector = "foobar", 384 | search = "search String", 385 | plus = "plus", 386 | } 387 | 388 | If you need to parse other URLs in addition to "gopher:" types, 389 | you can do: 390 | 391 | gopher = require "org.conman.parsers.url.gopher" 392 | url = require "org.conman.parsers.url" 393 | 394 | url = gopher + url 395 | info = url:match(my_url) 396 | 397 | url.siptel 398 | 399 | Parses "sip:" and "sips:" URIs per RFC-3261. 400 | Parses "tel:" URIs per RFC-3966. 401 | 402 | Examples: 403 | 404 | sip = require "org.conman.parsers.url.sip" 405 | u = sip:match [[sip:annc@example.com;play=file://fs.example.net//clips/my-intro.dvi;content-type=video/mpeg%3bencode%d3314M-25/625-50]] 406 | 407 | results in: 408 | 409 | { 410 | host = "example.com", 411 | port = 5060.000000, 412 | user = "annc", 413 | scheme = "sip", 414 | parameters = 415 | { 416 | play = "file://fs.example.net//clips/my-intro.dvi", 417 | ["content-type"] = "video/mpeg%3bencode%d3314M-25/625-50", 418 | }, 419 | } 420 | 421 | and 422 | 423 | u = sip:match [[sip:+1-(555)-555-1212;ext=1234@example.net;user=phone]] 424 | 425 | results in: 426 | 427 | { 428 | host = "example.net", 429 | port = 5060.000000, 430 | user = 431 | { 432 | number = "15555551212", 433 | global = true, 434 | parameters = 435 | { 436 | ext = "1234", 437 | }, 438 | }, 439 | scheme = "sip", 440 | parameters = 441 | { 442 | user = "phone", 443 | }, 444 | } 445 | 446 | and 447 | 448 | tel = require "org.conman.parsers.url.tel" 449 | u = tel:match "tel:+1-(555)-555-1212;ext=1234" 450 | 451 | results in: 452 | 453 | { 454 | scheme = "tel", 455 | number = "15555551212", 456 | global = true, 457 | parameters = 458 | { 459 | ext = "1234", 460 | }, 461 | } 462 | 463 | If you need to parse other URLs in addition to these types, 464 | you can do: 465 | 466 | siptel = require "org.conman.parsers.url.sip" 467 | url = require "org.conman.parsers.url" 468 | 469 | url = siptel + url 470 | info = url:match(my_url) 471 | 472 | soundex.lua 473 | 474 | Implements the Soundex algorithm. 475 | 476 | [1] http://www.inf.puc-rio.br/~roberto/lpeg/ 477 | 478 | [2] https://github.com/spc476/lua-conmanorg 479 | -------------------------------------------------------------------------------- /abnf.lua: -------------------------------------------------------------------------------- 1 | -- *************************************************************** 2 | -- 3 | -- Copyright 2016 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 | -- BNF rules per RFC-5234. These are common among a lot of RFCs, so it 23 | -- makes sense to define them in one place to be used elsewhere. 24 | -- 25 | -- ******************************************************************** 26 | -- luacheck: ignore 611 27 | 28 | local lpeg = require "lpeg" 29 | local abnf = 30 | { 31 | ALPHA = lpeg.R("AZ","az"), 32 | BIT = lpeg.P"0" + lpeg.P"1", 33 | CHAR = lpeg.R"\1\127", 34 | CR = lpeg.P"\r", 35 | CRLF = lpeg.P"\r"^-1 * lpeg.P"\n", -- [1] 36 | CTL = lpeg.R("\0\31","\127\127"), 37 | DIGIT = lpeg.R"09", 38 | DQUOTE = lpeg.P'"', 39 | HEXDIG = lpeg.R("09","AF","af"), -- [2] 40 | HTAB = lpeg.P"\t", 41 | LF = lpeg.P"\n", 42 | OCTET = lpeg.P(1), 43 | SP = lpeg.P" ", 44 | VCHAR = lpeg.R"!~", 45 | } 46 | 47 | abnf.WSP = abnf.SP + abnf.HTAB 48 | abnf.LWSP = (abnf.WSP + abnf.CRLF * abnf.WSP)^0 -- [3] 49 | 50 | return abnf 51 | 52 | -- ******************************************************************** 53 | -- 54 | -- [1] I made the CR optional, as it makes it easier to test on the command 55 | -- line under Unix, which only uses LF to mark end of lines. This 56 | -- should not effect the resulting parsers in any way. 57 | -- 58 | -- Famous last words. 59 | -- 60 | -- [2] The definition in RFC-5234 only allows upper case. I'm being 61 | -- lenient here. 62 | -- 63 | -- [3] As noted in RFC-5234, this rule should NOT be used for email 64 | -- headers. 65 | -- 66 | -- ******************************************************************** 67 | -------------------------------------------------------------------------------- /ascii.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 | -- 22 | -- Parse a valid ASCII character. 23 | -- 24 | -- ******************************************************************** 25 | -- luacheck: ignore 611 26 | 27 | return require "org.conman.parsers.ascii.char" 28 | + require "org.conman.parsers.ascii.control" -------------------------------------------------------------------------------- /ascii/char.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 | -- 22 | -- Parse a valid ASCII non-control character. 23 | -- 24 | -- ******************************************************************** 25 | -- luacheck: ignore 611 26 | 27 | local lpeg = require "lpeg" 28 | return lpeg.R" ~" 29 | -------------------------------------------------------------------------------- /ascii/control.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 | -- 22 | -- Parse a valid ASCII control character. 23 | -- 24 | -- ******************************************************************** 25 | -- luacheck: ignore 611 26 | 27 | local lpeg = require "lpeg" 28 | return lpeg.R("\0\31","\127\127") 29 | -------------------------------------------------------------------------------- /ascii/ctrl.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 | -- 22 | -- Return name of ASCII control character. For DLE, return following 23 | -- literal character (if exists). 24 | -- 25 | -- ******************************************************************** 26 | -- luacheck: ignore 611 27 | 28 | local lpeg = require "lpeg" 29 | 30 | local convert = 31 | { 32 | ['\000'] = 'NUL' , -- NULL 33 | ['\001'] = 'SOH' , -- START OF HEADING 34 | ['\002'] = 'STX' , -- START OF TEXT 35 | ['\003'] = 'ETX' , -- END OF TEXT 36 | ['\004'] = 'EOT' , -- END OF TRANSMISSION 37 | ['\005'] = 'ENQ' , -- ENQUIRY 38 | ['\006'] = 'ACK' , -- ACKNOWLEDGE 39 | ['\007'] = 'BEL' , -- BELL 40 | ['\008'] = 'BS' , -- BACKSPACE 41 | ['\009'] = 'HT' , -- CHARACTER TABULATION 42 | ['\010'] = 'LF' , -- LINE FEED 43 | ['\011'] = 'VT' , -- LINE TABULATION 44 | ['\012'] = 'FF' , -- FORM FEED 45 | ['\013'] = 'CR' , -- CARRIAGE RETURN 46 | ['\014'] = 'SI' , -- SHIFT-OUT 47 | ['\015'] = 'SO' , -- SHIFT-IN 48 | ['\016'] = 'DLE' , -- DATA LINK ESCAPE 49 | ['\017'] = 'DC1' , -- DEVICE CONTROL ONE (XON) 50 | ['\018'] = 'DC2' , -- DEVICE CONTROL TWO 51 | ['\019'] = 'DC3' , -- DEVICE CONTROL THREE (XOFF) 52 | ['\020'] = 'DC4' , -- DEVICE CONTROL FOUR 53 | ['\021'] = 'NAK' , -- NEGATIVE ACKNOWLEDGE 54 | ['\022'] = 'SYN' , -- SYNCHRONOUS IDLE 55 | ['\023'] = 'ETB' , -- END OF TRANSMISSION BLOCK 56 | ['\024'] = 'CAN' , -- CANCEL 57 | ['\025'] = 'EM' , -- END OF MEDIUM 58 | ['\026'] = 'SUB' , -- SUBSTITUTE 59 | ['\027'] = 'ESC' , -- ESCAPE 60 | ['\028'] = 'FS' , -- FILE SEPARATOR 61 | ['\029'] = 'GS' , -- GROUP SEPATATOR 62 | ['\030'] = 'RS' , -- RECORD SEPARATOR 63 | ['\031'] = 'US' , -- UNIT SEPARATOR 64 | ['\127'] = 'DEL' , -- DELETE 65 | } 66 | 67 | return lpeg.R("\0\31","\127\127") / convert 68 | -------------------------------------------------------------------------------- /asv.lua: -------------------------------------------------------------------------------- 1 | -- *************************************************************** 2 | -- 3 | -- Parse an ASV (Ascii Separated Value) file 4 | -- Copyright 2020 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 | -- 23 | -- The BNF is define in RFC-5234. 24 | -- The US-ASCII encoding is defined in RFC-20. 25 | -- The UTF-8 encoding is defined in RFC-3629. 26 | -- The keywords SHOULD and MAY are defined in RFC-2119. 27 | -- HTAB CR LF SP VCHAR are defined in RFC-5234. 28 | -- 29 | -- The SP rule MAY be extended to support Unicode whitespace. 30 | -- 31 | -- The VCHAR rule MAY be extended to support Uhicode graphic and combining 32 | -- characters. 33 | -- 34 | -- The number of units per record per grouping SHOULD be the same. 35 | -- 36 | -- The character encoding MAY be US-ASCII or UTF-8. 37 | -- 38 | -- file = group *(FS group) 39 | -- group = record *(GS record) 40 | -- record = [hunit RS] unit *(RS unit) ; *** see notes 41 | -- unit = data *(US data) 42 | -- hunit = FF hdata *(US hdata) 43 | -- 44 | -- data = *(VCHAR / SP / HTAB / CR / LF) 45 | -- hdata = *(VCHAR / SP) 46 | -- 47 | -- FF = %x0C ; Form Feed 48 | -- FS = %x1C ; File Separator 49 | -- GS = %x1D ; Group Separator 50 | -- RS = %x1E ; Record Separator 51 | -- US = %x1F ; Unit Separator 52 | -- 53 | -- ******************************************************************** 54 | -- luacheck: ignore 611 55 | 56 | local abnf = require "org.conman.parsers.abnf" 57 | local lpeg = require "lpeg" 58 | 59 | local FF = lpeg.P"\f" 60 | local FS = lpeg.P"\28" 61 | local GS = lpeg.P"\29" 62 | local RS = lpeg.P"\30" 63 | local US = lpeg.P"\31" 64 | 65 | local hdata = (abnf.VCHAR + abnf.SP)^0 66 | local data = (abnf.VCHAR + abnf.SP + abnf.HTAB + abnf.CR + abnf.LF)^0 67 | 68 | local hunit = FF * lpeg.Ct(lpeg.C(hdata) * (US * lpeg.C(hdata))^0) 69 | local unit = lpeg.Ct(lpeg.C(data) * (US * lpeg.C( data))^0) 70 | local record = lpeg.Ct(lpeg.Cg((hunit * RS),'headers')^-1 * unit * (RS * unit)^0) 71 | local group = lpeg.Ct(record * (GS * record)^0) 72 | local file = lpeg.Ct(group * (FS * group)^0) 73 | 74 | return { 75 | record = record, 76 | group = group, 77 | file = file 78 | } 79 | -------------------------------------------------------------------------------- /email.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: ignore 611 22 | 23 | local lpeg = require "lpeg" 24 | local re = require "re" 25 | 26 | local P = lpeg.P 27 | local S = lpeg.S 28 | local R = lpeg.R 29 | local V = lpeg.V 30 | local C = lpeg.C 31 | local Cc = lpeg.Cc 32 | local Cf = lpeg.Cf 33 | local Ct = lpeg.Ct 34 | local Cp = lpeg.Cp 35 | 36 | -- *********************************************************************** 37 | -- create a parsing expression that will match text case-insensitively 38 | -- *********************************************************************** 39 | 40 | local function H(text) 41 | local pattern = P(true) 42 | for c in text:gmatch(".") do 43 | pattern = pattern * (P(c:lower()) + P(c:upper())) 44 | end 45 | 46 | return pattern 47 | end 48 | 49 | -- *********************************************************************** 50 | -- function to acculate values into a table. Values with the same key 51 | -- will end up together under a single key, in the order they appear. The 52 | -- keys themselves are in no particular order. 53 | -- *********************************************************************** 54 | 55 | local function doset(tab,idx) 56 | 57 | local function append(t,l) 58 | if type(l) == 'table' and #l > 0 then 59 | for i = 1 , #l do 60 | t[#t + 1] = l[i] 61 | end 62 | else 63 | t[#t + 1] = l 64 | end 65 | end 66 | 67 | local function addto(t,l) 68 | for name,value in pairs(l) do 69 | if t[name] == nil then 70 | t[name] = value 71 | elseif type(t[name]) == 'table' then 72 | append(t[name],value) 73 | else 74 | local r = { t[name] } 75 | append(r,value) 76 | t[name] = r 77 | end 78 | end 79 | end 80 | 81 | if idx._GENERIC then 82 | tab.generic = tab.generic or {} 83 | idx._GENERIC = nil 84 | addto(tab.generic,idx) 85 | else 86 | addto(tab,idx) 87 | end 88 | 89 | return tab 90 | end 91 | 92 | -- ******************************************************************* 93 | 94 | local FROM = H "From" 95 | local VCHAR = R"!~" 96 | local WSP = S" \t" 97 | local SP = P" " 98 | local CRLF = P"\r"^-1 * P"\n" 99 | local ctext = R("!'" , "*[" , "]~") 100 | local qtext = R("!!" , "#[" , "]~") 101 | local dtext = R("!Z" , "^~") 102 | local theheaders = Cf(Ct"" * V"headers"^1,doset) * CRLF 103 | 104 | local eoh = (CRLF * #CRLF) + (CRLF - (CRLF^-1 * WSP)) 105 | local name = C((P(1) - (P":" + CRLF + WSP))^1) 106 | local value = C((P(1) - eoh)^0) / function(v) 107 | return v:gsub("[%s%c]+"," ") 108 | end 109 | 110 | local unixfrom = FROM * WSP * (P(1) - eoh)^0 * CRLF 111 | 112 | local generic_header = name * ":" * WSP^0 * value * eoh 113 | / function(a,b) 114 | b = b or "" 115 | return { [a] = b , _GENERIC = true } 116 | end 117 | 118 | local group = 119 | V"CFWS"^-1 120 | * Cf( 121 | C(V"display_name") 122 | * Cf( 123 | Ct"" * P":" * V"group_list"^-1 + Cc(), 124 | function(a,b) 125 | a[#a + 1] = b 126 | return a 127 | end 128 | ), 129 | function(a,b) 130 | return { [a] = b } 131 | end 132 | ) 133 | * P";" 134 | * V"CFWS"^-1 135 | 136 | local mimetype = 137 | Cf( 138 | Ct(C(V"type" * P"/" * V"subtype")) 139 | * ( P";" * V"FWS" 140 | * C(V"attribute") * P"=" * C(V"value") 141 | / function(a,b) 142 | return { a , b:gsub([["]],"") } 143 | end 144 | )^0 + Cc(), 145 | function(a,b) 146 | a[b[1]] = b[2] 147 | return a 148 | end 149 | ) 150 | * V"CFWS"^-1 151 | 152 | -- ******************************************************************** 153 | 154 | local G = --[[ lpeg/re ]] [[ 155 | 156 | email <- %theheaders 157 | headers <- 158 | 159 | %unixfrom -- burn a Unix style From line 160 | 161 | -- ------------------------------------------------------- 162 | -- Fields defined in RFC-822, RFC-2822 and RFC-5322 163 | -- see RFC-5321 for further information about 164 | -- Return-Path: and Received: 165 | -- ------------------------------------------------------- 166 | 167 | / {:from: fromhdr :} -> {} 168 | / {:to: tohdr :} -> {} 169 | / {:subject: subjecthdr :} -> {} 170 | / {:date: datehdr :} -> {} 171 | / {:cc: cchdr :} -> {} 172 | / {:bcc: bcchdr :} -> {} 173 | / {:comment: commenthdr :} -> {} 174 | / {:keywords: keywordshdr :} -> {} 175 | / {:message_id: message_idhdr :} -> {} 176 | / {:in_reply_to: in_reply_tohdr :} -> {} 177 | / {:references: referenceshdr :} -> {} 178 | / {:reply_to: reply_tohdr :} -> {} 179 | / {:sender: senderhdr :} -> {} 180 | / {:received: receivedhdr :} -> {} 181 | / {:return_path: return_pathhdr :} -> {} 182 | / {:encrypted: encryptedhdr :} -> {} 183 | 184 | -- -------------------------------------------------------- 185 | -- fields defined in RFC-2045, RFC-2046, RFC-2047, RFC-2048 186 | -- and RFC-2049 (MIME related headers). 187 | -- Content-Length: isn't defined, but is in common 188 | -- enough use to include it here 189 | -- -------------------------------------------------------- 190 | 191 | / {:mime: mimehdr :} -> {} 192 | / {:content_type: content_typehdr :} -> {} 193 | / {:content_transfer_encoding: ctehdr :} -> {} 194 | / {:content_id: content_idhdr :} -> {} 195 | / {:content_description: content_deschdr :} -> {} 196 | / {:content_length: content_lenhdr :} -> {} 197 | 198 | -- -------------------------------------------------------- 199 | -- fields defined in RFC-2919 (List-ID:), RFC-2369 and 200 | -- RFC-8058 (List-Unsubscribe-Post) these fields relate to 201 | -- mailing lists 202 | -- -------------------------------------------------------- 203 | 204 | / {:list_id: list_idhdr :} -> {} -- RFC-2919 205 | / {:list_help: list_helphdr :} -> {} 206 | / {:list_unsubscribe: list_unsubhdr :} -> {} 207 | / {:list_subscribe: list_subhdr :} -> {} 208 | / {:list_post: list_posthdr :} -> {} 209 | / {:list_owner: list_ownerhdr :} -> {} 210 | / {:list_archive: list_archivehdr :} -> {} 211 | / {:list_unsubscribe_post: list_unsubpost :} -> {} -- RFC-8058 212 | 213 | -- -------------------------------------------------------- 214 | -- fields defined in RFC-1036 (Usenet). There is some 215 | -- overlap with RFC-822, so those fields not defined there 216 | -- are defined here 217 | -- -------------------------------------------------------- 218 | 219 | / {:newsgroups: newsgrouphdr :} -> {} 220 | / {:path: pathhdr :} -> {} 221 | / {:followup_to: followup_tohdr :} -> {} 222 | / {:expires: expireshdr :} -> {} 223 | / {:control: controlhdr :} -> {} 224 | / {:distribution: distributionhdr :} -> {} 225 | / {:organization: organizationhdr :} -> {} 226 | / {:summary: summaryhdr :} -> {} 227 | / {:approved: approvedhdr :} -> {} 228 | / {:lines: lineshdr :} -> {} 229 | / {:xref: xrefhdr :} -> {} 230 | 231 | -- -------------------------------------------------------- 232 | -- field defined in RFC-3834 233 | -- -------------------------------------------------------- 234 | 235 | / {:auto_submitted: autosubmithdr :} -> {} 236 | 237 | -- -------------------------------------------------------- 238 | -- field defined in RFC-5064 239 | -- -------------------------------------------------------- 240 | 241 | / {:archived_at: archived_athdr :} -> {} 242 | 243 | -- -------------------------------------------------------- 244 | -- fields that are otherwise undefined accumulate here 245 | -- (also, malformed defined headers will end up here) 246 | -- -------------------------------------------------------- 247 | 248 | / %generic_header 249 | 250 | -- ------------------------------------------------------------------------ 251 | 252 | fromhdr <- %FROM ':' mailbox_list -> {} %CRLF 253 | subjecthdr <- %SUBJECT ':' unstructured => cleanup %CRLF 254 | datehdr <- %DATE ':' date_time -> {} %CRLF 255 | tohdr <- %TO ':' address_list -> {} %CRLF 256 | cchdr <- %CC ':' address_list -> {} %CRLF 257 | bcchdr <- %BCC ':' address_list -> {} %CRLF 258 | commenthdr <- %COMMENT ':' unstructured => cleanup %CRLF 259 | keywordshdr <- %KEYWORDS ':' (phrase (',' phrase)* ) -> {} %CRLF 260 | message_idhdr <- %MESSAGE_ID ':' msg_id %CRLF 261 | in_reply_tohdr <- %IN_REPLY_TO ':' msg_id+ -> {} %CRLF 262 | referenceshdr <- %REFERENCES ':' msg_id+ -> {} %CRLF 263 | reply_tohdr <- %REPLY_TO ':' address_list -> {} %CRLF 264 | senderhdr <- %SENDER ':' mailbox -> {} %CRLF 265 | receivedhdr <- %RECEIVED ':' FWS stamp -> {} %CRLF 266 | return_pathhdr <- %RETURN_PATH ':' FWS reverse_path -> {} %CRLF 267 | encryptedhdr <- %ENCRYPTED ':' unstructured => cleanup %CRLF 268 | 269 | mimehdr <- %MIME_VERSION ':' mimeversion %CRLF 270 | content_typehdr <- %CONTENT_TYPE ':' FWS %mimetype %CRLF 271 | ctehdr <- %CONTENT_TRANSFER_ENCODING ':' FWS mechanism %CRLF 272 | content_idhdr <- %CONTENT_ID ':' msg_id %CRLF 273 | content_deschdr <- %CONTENT_DESCRIPTION ':' unstructured => cleanup %CRLF 274 | content_lenhdr <- %CONTENT_LENGTH ':' FWS length %CRLF 275 | 276 | list_idhdr <- %LIST_ID ':' FWS list_id -> {} %CRLF 277 | list_helphdr <- %LIST_HELP ':' FWS list_locs -> {} %CRLF 278 | list_unsubhdr <- %LIST_UNSUBSCRIBE ':' FWS list_locs -> {} %CRLF 279 | list_subhdr <- %LIST_SUBSCRIBE ':' FWS list_locs -> {} %CRLF 280 | list_posthdr <- %LIST_POST ':' FWS (list_no? list_locs) -> {} %CRLF 281 | list_ownerhdr <- %LIST_OWNER ':' FWS list_locs -> {} %CRLF 282 | list_archivehdr <- %LIST_ARCHIVE ':' FWS list_locs -> {} %CRLF 283 | list_unsubpost <- %LIST_UNSUB_POST ':' FWS { "List-Unsubscribe=One-Click" } %CRLF 284 | 285 | newsgrouphdr <- %NEWSGROUPS ':' FWS newsgroups -> {} %CRLF 286 | pathhdr <- %PATH ':' FWS newspath? -> {} %CRLF 287 | followup_tohdr <- %FOLLOWUP_TO ':' FWS newsgroups -> {} %CRLF 288 | expireshdr <- %EXPIRES ':' date_time -> {} %CRLF 289 | controlhdr <- %CONTROL ':' FWS control_list -> {} %CRLF 290 | distributionhdr <- %DISTRIBUTION ':' FWS dist_list -> {} %CRLF 291 | organizationhdr <- %ORGANIZATION ':' unstructured => cleanup %CRLF 292 | summaryhdr <- %SUMMARY ':' unstructured => cleanup %CRLF 293 | approvedhdr <- %APPROVED ':' unstructured => cleanup %CRLF 294 | lineshdr <- %LINES ':' FWS length %CRLF 295 | xrefhdr <- %XREF ':' FWS xref -> {} %CRLF 296 | 297 | autosubmithdr <- %AUTO_SUBMITTED ':' FWS auto_submit -> {} %CRLF 298 | 299 | archived_athdr <- %ARCHIVED_AT ':' FWS archive_url %CRLF 300 | 301 | -- ------------------------------------------------------------------------ 302 | 303 | auto_submit <- {:type: ('no' / 'auto-generated' / 'auto-replied' / token) :} 304 | ( CFWS? ";" CFWS? parameter )* 305 | 306 | archive_url <- "<" { [^>]+ } ">" 307 | 308 | -- ------------------------------------------- 309 | -- Usenet (newsgroups) specific headers 310 | -- ------------------------------------------- 311 | 312 | xref <- {:host: xrefhost :} FWS xreflist 313 | xreflist <- groupmsg -> {} (FWS groupmsg)* -> {} 314 | xrefhost <- [A-Za-z0-9]+ 315 | groupmsg <- {:newsgroup: dot_atom_text :} ":" {:id: %d+ :} 316 | dist_list <- distribution (FWS? "," FWS? distribution)* 317 | distribution <- { [A-Za-z]+ } 318 | newsgroups <- { dot_atom_text } ( FWS? "," FWS? { dot_atom_text } )* 319 | newspath <- newshost (punct+ newshost)* 320 | newshost <- { [A-Za-z0-9.]+ } 321 | punct <- [][~`!@#$%^&*()-_=+{}|\;':"<>,/?] / FWS 322 | control_list <- ( 323 | ctrl_cancel 324 | / ctrl_ihave 325 | / ctrl_sendme 326 | / ctrl_newgroup 327 | / ctrl_rmgroup 328 | / ctrl_sendsys 329 | / ctrl_version 330 | ) -> {} 331 | ctrl_cancel <- {:cmd: CANCEL -> "cancel" :} FWS msg_id 332 | ctrl_ihave <- {:cmd: IHAVE -> "ihave" :} FWS msg_id+ 333 | ctrl_sendme <- {:cmd: SENDME -> "sendme" :} FWS msg_id+ 334 | ctrl_newgroup <- {:cmd: NEWGROUP -> "newgroup" :} FWS { dot_atom_text } (FWS moderated)? 335 | ctrl_rmgroup <- {:cmd: RMGROUP -> "rmgroup" :} FWS { dot_atom_text } 336 | ctrl_sendsys <- {:cmd: SENDSYS -> "sendsys" :} 337 | ctrl_version <- {:cmd: VERSION -> "version" :} 338 | moderated <- {:moderated: MODERATED :} 339 | 340 | CANCEL <- [Cc][Aa][Nn][Cc][Ee][Ll] 341 | IHAVE <- [Ii][Hh][Aa][Vv][Ee] 342 | SENDME <- [Ss][Ee][Nn][Dd][Mm][Ee] 343 | NEWGROUP <- [Nn][Ee][Ww][Gg][Rr][Oo][Uu][Pp] 344 | RMGROUP <- [Rr][Mm][Gg][Rr][Oo][Uu][Pp] 345 | SENDSYS <- [Ss][Ee][Nn][Dd][Ss][Yy][Ss] 346 | VERSION <- [Vv][Ee][Rr][Ss][Ii][Oo][Nn] 347 | MODERATED <- [Mm][Oo][Dd][Ee][Rr][Aa][Tt][Ee][Dd] 348 | 349 | -- ---------------------------------------------- 350 | -- Mailing list specific headers 351 | -- ---------------------------------------------- 352 | 353 | list_id <- {:name: { phrase? } :} "<" {:id: list_label :} ">" 354 | list_label <- dot_atom_text 355 | list_locs <- list_loc ("," list_loc)* 356 | list_loc <- CFWS? "<" { [^>]+ } ">" CFWS? 357 | list_no <- CFWS? {:list_no: [Nn][Oo] :} 358 | 359 | -- ----------------------------------------------- 360 | -- MIME specific headers 361 | -- ----------------------------------------------- 362 | 363 | length <- %d+ -> tonumber 364 | mechanism <- BIT7 -> "7bit" 365 | / BIT8 -> "8bit" 366 | / BINARY -> "binary" 367 | / QUOTED_PRINTABLE -> "quoted_printable" 368 | / BASE64 -> "base64" 369 | / x_token 370 | BIT7 <- "7" BIT 371 | BIT8 <- "8" BIT 372 | BINARY <- [Bb][Ii][Nn][Aa][Rr][Yy] 373 | QUOTED_PRINTABLE<- [Qq][Uu][Oo][Tt][Ee][Dd] 374 | "-" [Pp][Rr][Ii][Nn][Tt][Aa][Bb][Ll][Ee] 375 | BASE64 <- [Bb][Aa][Ss][Ee] "64" 376 | BIT <- [Bb][Ii][Tt] 377 | 378 | type <- discrete_type / composite_type 379 | discrete_type <- "text" 380 | / "image" 381 | / "audio" 382 | / "video" 383 | / "application" 384 | / extension_token 385 | composite_type <- "message" 386 | / "multipart" 387 | / extension_token 388 | extension_token <- x_token 389 | x_token <- [Xx] "-" ([A-Za-z0-9] / '-')+ 390 | subtype <- extension_token / iana_token 391 | iana_token <- ([A-Za-z0-9] / '-')+ 392 | parameter <- (attribute '=' value) -> {} 393 | attribute <- token 394 | value <- (token / quoted_string) 395 | token <- [^][()<>@,;:\"/?=%s%c]+ 396 | 397 | mimeversion <- (CFWS? {%d+} CFWS? '.' CFWS? {%d+} CFWS?) -> {} -> vmerge 398 | 399 | -- ---------------------------------------------------- 400 | -- tracing (Return-Path and Received) specific headers 401 | -- ---------------------------------------------------- 402 | 403 | reverse_path <- path / "<>" 404 | 405 | stamp <- ( 406 | from_domain? by_domain? opt_info? CFWS? 407 | ";" {:when: date_time -> {} :} 408 | ) -> {} 409 | from_domain <- %FROM FWS {:from: extended_domain :} 410 | by_domain <- CFWS BY FWS {:by: extended_domain :} 411 | extended_domain <- domain 412 | / domain FWS "(" tcp_info ")" 413 | / address_literal FWS "(" tcp_info ")" 414 | tcp_info <- address_literal 415 | / domain FWS address_literal 416 | opt_info <- via? with? id? for? arc? 417 | via <- CFWS VIA FWS {:link: link :} 418 | with <- CFWS WITH FWS {:with: protocol :} 419 | id <- CFWS ID FWS {:id: (atom !'.' / msg_id / dot_atom_text) :} 420 | for <- CFWS FOR FWS {:for: (path / mailbox / user) :} 421 | arc <- CFWS atom FWS word 422 | link <- TCP / addtl_link 423 | addtl_link <- atom 424 | protocol <- ESMTP !atext 425 | / SMTP !atext 426 | / attdl_protocol 427 | attdl_protocol <- atom 428 | path <- "<" (adl ":")? mailbox ">" 429 | adl <- at_domain ("," at_domain)* 430 | at_domain <- "@" domain 431 | user <- [A-Za-z0-9]+ 432 | BY <- [Bb][Yy] 433 | VIA <- [Vv][Ii][Aa] 434 | WITH <- [Ww][Ii][Tt][Hh] 435 | FOR <- [Ff][Oo][Rr] 436 | TCP <- [Tt][Cc][Pp] 437 | ESMTP <- [Ee] SMTP 438 | SMTP <- [Ss][Mm][Tt][Pp] 439 | ID <- [Ii][Dd] 440 | 441 | -- ----------------------------- 442 | -- message IDs 443 | -- ----------------------------- 444 | 445 | msg_id <- CFWS? "<" { id_left "@" id_right } ">" CFWS? 446 | id_left <- dot_atom_text 447 | id_right <- dot_atom_text / no_fold_literal 448 | no_fold_literal <- "[" %dtext* "]" 449 | 450 | -- ------------------------------------------ 451 | -- time keeps on slipping, into the future 452 | -- ------------------------------------------ 453 | 454 | date_time <- ( {:weekday: day_of_week :} "," )? thedate time CFWS? 455 | day_of_week <- FWS { day_name } 456 | day_name <- 'Mon' / 'Tue' / 'Wed' / 'Thu' / 'Fri' / 'Sat' / 'Sun' 457 | thedate <- day month year 458 | day <- FWS {:day: %d^+1 -> tonumber :} FWS 459 | month <- {:month: 460 | ( 461 | 'Jan' / 'Feb' / 'Mar' / 'Apr' 462 | / 'May' / 'Jun' / 'Jul' / 'Aug' 463 | / 'Sep' / 'Oct' / 'Nov' / 'Dec' 464 | ) -> monthtrans :} 465 | year <- FWS {:year: %d^4 -> tonumber :} FWS 466 | time <- time_of_day zone 467 | time_of_day <- hour ":" min (":" second)? 468 | hour <- {:hour: %d^2 -> tonumber :} 469 | min <- {:min: %d^2 -> tonumber :} 470 | second <- {:sec: %d^2 -> tonumber :} 471 | zone <- FWS {:zone: ((("+" / "-") %d^4) / "GMT") -> tozone:} 472 | 473 | -- ---------------------------------------------------- 474 | -- various tokens and pieces used to build up a larger 475 | -- parsing expression 476 | -- ---------------------------------------------------- 477 | 478 | unstructured <- FWS? { (FWS? %VCHAR)* } %WSP* 479 | phrase <- word+ 480 | word <- atom / quoted_string 481 | 482 | quoted_string <- CFWS? '"' ((FWS? qcontent)* => cleanup) FWS? '"' CFWS? 483 | qcontent <- %qtext / quoted_pair 484 | quoted_pair <- "\" (%VCHAR / %WSP) 485 | 486 | atom <- CFWS? {atext+} CFWS? 487 | 488 | atext <- [A-Za-z] 489 | / [0-9] 490 | / "!" 491 | / "#" 492 | / "$" 493 | / "%" 494 | / "&" 495 | / "'" 496 | / "*" 497 | / "+" 498 | / "-" 499 | / "/" 500 | / "=" 501 | / "?" 502 | / "^" 503 | / "_" 504 | / "`" 505 | / "{" 506 | / "|" 507 | / "}" 508 | / "~" 509 | 510 | dot_atom_text <- atext+ ('.' atext+)* 511 | dot_atom <- CFWS? { dot_atom_text } CFWS? 512 | FWS <- (%WSP* %CRLF)? %WSP+ 513 | CFWS <- (FWS? comment)? FWS? 514 | / FWS 515 | comment <- "(" (FWS? ccontent)* FWS? ")" 516 | ccontent <- %ctext / quoted_pair / comment 517 | 518 | -- -------------------------------------------------- 519 | -- Email addresses---for those of you who don't want 520 | -- a 4,000+ line regular expression 521 | -- -------------------------------------------------- 522 | 523 | address_list <- address ("," address)* 524 | address <- mailbox / %group 525 | group_list <- mailbox_list / CFWS 526 | mailbox_list <- mailbox ("," mailbox)* 527 | mailbox <- (name_addr / addr_spec) -> {} 528 | name_addr <- {:name: display_name? :} angle_addr 529 | display_name <- phrase+ -> {} -> merge 530 | angle_addr <- CFWS? "<" addr_spec ">" CFWS? 531 | addr_spec <- {:address: (local_part "@" domain) -> merge_addr :} 532 | local_part <- dot_atom / quoted_string 533 | domain <- dot_atom / domain_literal 534 | domain_literal <- CFWS? { "[" (FWS? %dtext)* FWS? "]" } CFWS? 535 | address_literal <- "[" %dtext* "]" 536 | 537 | ]] 538 | 539 | -- *********************************************************************** 540 | 541 | local Rules = 542 | { 543 | -- ----------------------------------------------------------------------- 544 | -- These are being defined here instead of in the re portion because of a 545 | -- rule limitiation in LPeg 0.12 (default of 200, requires a recompile to 546 | -- extend). Moving the header names out to here will let this work under 547 | -- LPeg 0.12, while still working back to LPeg 0.10.2. 548 | -- ----------------------------------------------------------------------- 549 | 550 | RETURN_PATH = H "Return-Path", 551 | RECEIVED = H "Received", 552 | -- Resent headers still need to be done 553 | DATE = H "Date", 554 | FROM = FROM, 555 | SENDER = H "Sender", 556 | REPLY_TO = H "Reply-To", 557 | TO = H "To", 558 | CC = H "Cc", 559 | BCC = H "Bcc", 560 | MESSAGE_ID = H "Message-ID", 561 | IN_REPLY_TO = H "In-Reply-To", 562 | REFERENCES = H "References", 563 | SUBJECT = H "Subject", 564 | COMMENT = H "Comment", 565 | KEYWORDS = H "Keywords", 566 | ENCRYPTED = H "Encrypted", 567 | 568 | MIME_VERSION = H "MIME-Version", 569 | CONTENT_TYPE = H "Content-Type", 570 | CONTENT_TRANSFER_ENCODING = H "Content-Transfer-Encoding", 571 | CONTENT_ID = H "Contend-ID", 572 | CONTENT_DESCRIPTION = H "Content-Description", 573 | CONTENT_LENGTH = H "Content-Length", 574 | 575 | LIST_ID = H "List-ID", 576 | LIST_HELP = H "List-Help", 577 | LIST_UNSUBSCRIBE = H "List-Unsubscribe", 578 | LIST_SUBSCRIBE = H "List-Subscribe", 579 | LIST_POST = H "List-Post", 580 | LIST_OWNER = H "List-Owner", 581 | LIST_ARCHIVE = H "List-Archive", 582 | LIST_UNSUB_POST = H "List-Unsubscribe-Post", 583 | 584 | NEWSGROUPS = H "Newsgroups", 585 | PATH = H "Path", 586 | FOLLOWUP_TO = H "Followup-To", 587 | EXPIRES = H "Expires", 588 | CONTROL = H "Control", 589 | DISTRIBUTION = H "Distribution", 590 | ORGANIZATION = H "Organization", 591 | SUMMARY = H "Summary", 592 | APPROVED = H "Approved", 593 | LINES = H "Lines", 594 | XREF = H "XRef", 595 | 596 | AUTO_SUBMITTED = H"Auto-Submitted", 597 | 598 | ARCHIVED_AT = H "Archived-At", 599 | 600 | -- -------[ end of header names ]--------------- 601 | 602 | VCHAR = VCHAR, 603 | WSP = WSP, 604 | SP = SP, 605 | CRLF = CRLF, 606 | ctext = ctext, 607 | qtext = qtext, 608 | dtext = dtext, 609 | theheaders = theheaders, 610 | group = group, 611 | mimetype = mimetype, 612 | generic_header = generic_header, 613 | unixfrom = unixfrom, 614 | 615 | tonumber = tonumber, 616 | 617 | merge_addr = function(l,d) 618 | return l .. "@" .. d 619 | end, 620 | 621 | monthtrans = function(cap) 622 | local trans = 623 | { 624 | Jan = 1 , Feb = 2 , Mar = 3 , Apr = 4 , 625 | May = 5 , Jun = 6 , Jul = 7 , Aug = 8 , 626 | Sep = 9 , Oct = 10 , Nov = 11 , Dec = 12 627 | } 628 | 629 | return trans[cap] 630 | end, 631 | 632 | merge = function(cap) 633 | return table.concat(cap," ") 634 | end, 635 | 636 | vmerge = function(cap) 637 | return table.concat(cap,".") 638 | end, 639 | 640 | last = function(list) 641 | return list[#list] 642 | end, 643 | 644 | tozone = function(cap) 645 | if cap == 'GMT' then 646 | return 0 647 | end 648 | local hour = tonumber(cap:sub(2,3)) * 3600 649 | local min = tonumber(cap:sub(4,5)) * 60 650 | local sec = hour + min 651 | 652 | if cap:sub(1,1) == '-' then 653 | return -sec 654 | else 655 | return sec 656 | end 657 | end, 658 | 659 | cleanup = function(_,position,capture) 660 | local new = capture:gsub("\n","") 661 | new = new:gsub([[\.]],function(x) return x:sub(2,2) end) 662 | new = new:gsub("\t"," ") 663 | return position,new 664 | end, 665 | 666 | ddt = function(_,p,c) 667 | local dump = require "org.conman.table".dump 668 | print(">>>",p,c) 669 | if type(c) == 'table' then 670 | dump("c",c) 671 | end 672 | return p 673 | end, 674 | }; 675 | 676 | -- ********************************************************************** 677 | 678 | return re.compile(G,Rules) * Cp() 679 | -------------------------------------------------------------------------------- /gopher-index.lua: -------------------------------------------------------------------------------- 1 | -- ************************************************************************ 2 | -- 3 | -- Parse a gopher index file. 4 | -- Copyright 2018 by Sean Conner. All Rights Reserved. 5 | -- 6 | -- This program is free software: you can redistribute it and/or modify 7 | -- it under the terms of the GNU General Public License as published by 8 | -- the Free Software Foundation, either version 3 of the License, or 9 | -- (at your option) any later version. 10 | -- 11 | -- This program is distributed in the hope that it will be useful, 12 | -- but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | -- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | -- GNU General Public License for more details. 15 | -- 16 | -- You should have received a copy of the GNU General Public License 17 | -- along with this program. If not, see . 18 | -- 19 | -- Comments, questions and criticisms can be sent to: sean@conman.org 20 | -- 21 | -- ************************************************************************ 22 | -- luacheck: ignore 611 23 | 24 | 25 | local abnf = require "org.conman.parsers.abnf" 26 | local types = require "org.conman.const.gopher-types" 27 | local control = require "org.conman.parsers.utf8.control" 28 | + require "org.conman.parsers.iso.control" 29 | + require "org.conman.parsers.ascii.control" 30 | local lpeg = require "lpeg" 31 | 32 | local Cc = lpeg.Cc 33 | local Cg = lpeg.Cg 34 | local Cs = lpeg.Cs 35 | local Ct = lpeg.Ct 36 | local P = lpeg.P 37 | local R = lpeg.R 38 | 39 | local text = Cs((#-(abnf.CRLF + abnf.HTAB) * control / "" + R" \255")^0) 40 | local type = Cg(R" ~" / types,'type') 41 | local display = Cg(text,'display') + Cg(Cc"",'display') 42 | local selector = abnf.HTAB * Cg(R" \255"^0,'selector') + Cg(Cc"",'selector') 43 | local host = abnf.HTAB * Cg(R" \255"^0,'host') + Cg(Cc"example.com",'host') 44 | local port = abnf.HTAB * Cg(R"09"^1 / tonumber + Cc(0),'port') + Cg(Cc(0),'port') 45 | local gplus = abnf.HTAB * Cg(R" \255"^0,'gplus') 46 | local line = (P"." * abnf.CRLF) * Cc(nil) 47 | + abnf.CRLF * Cc(nil) 48 | + Ct(type * display * selector * host * port * gplus^-1) * (abnf.CRLF + P(-1)) 49 | return Ct(line^1) 50 | -------------------------------------------------------------------------------- /http-client.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 | local abnf = require "org.conman.parsers.abnf" 24 | local strftime = require "org.conman.parsers.strftime" 25 | local url = require "org.conman.parsers.url" 26 | local ih = require "org.conman.parsers.ih" 27 | local lpeg = require "lpeg" 28 | 29 | local Cc = lpeg.Cc 30 | local Cf = lpeg.Cf 31 | local Cg = lpeg.Cg 32 | local Ct = lpeg.Ct 33 | local C = lpeg.C 34 | local P = lpeg.P 35 | local R = lpeg.R 36 | local S = lpeg.S 37 | local V = lpeg.V 38 | 39 | local TEXT = R("\1\8","\10\31"," \255") 40 | local separators = S[[()<>@,;:\<>/[]?={}]] 41 | local token = (R"!~" - separators)^1 42 | local quoted_pair = P"\\" * abnf.CHAR 43 | local qdtext = TEXT - P'"' 44 | local quoted_string = P'"' * (qdtext + quoted_pair)^0 * P'"' 45 | local ctext = TEXT - S"()" 46 | local comment = 47 | { 48 | "comment", 49 | comment = P"(" * (ctext + quoted_pair + V"comment")^0 * P")" 50 | } 51 | 52 | local attribute = token 53 | local value = token + quoted_string 54 | local parameter = attribute * P"=" * value 55 | local type = token 56 | local subtype = token 57 | local media_type = Ct( 58 | Cg(type * P"/" * subtype,"media") 59 | * Cg( 60 | Cf( 61 | Ct"" * (P";" * abnf.LWSP^-1 * Cg(parameter))^1, 62 | function(t,k,v) 63 | t[k] = v 64 | return t 65 | end 66 | ), 67 | 'params' 68 | )^-1 69 | ) 70 | local HTTP_date = strftime:match "%a, %d %b %Y %H:%M:%S %Z" 71 | 72 | local cache_response_directive = Cf(Ct"" * ( 73 | Cg(C'public' * Cc(true)) 74 | + Cg(C'private' * C(quoted_string)) 75 | + Cg(C'no-cache' * C(quoted_string)) 76 | + Cg(C'no-store' * Cc(true)) 77 | + Cg(C'must-revalidate' * Cc(true)) 78 | + Cg(C'proxy-revalidate' * Cc(true)) 79 | + Cg(C'max-age' * P"=" * (R"09"^1 / tonumber)) 80 | + Cg(C's-maxage' * P"=" * (R"09"^1 / tonumber)) 81 | + Cg(C(token) * P"=" * C(token + quoted_string)) 82 | ), 83 | function(t,k,v) 84 | t[k] = v 85 | return t 86 | end 87 | ) 88 | 89 | local version = P"HTTP/1.1" * Cc "1.1" 90 | + P"HTTP/1.0" * Cc "1.0" 91 | + Cc "0.9" 92 | local indication = #P"1" * Cc'info' 93 | + #P"2" * Cc'success' 94 | + #P"3" * Cc'redirect' 95 | + #P"4" * Cc'clienterr' 96 | + #P"5" * Cc'servererr' 97 | local status = (R"15" * R"09" * R"09") / tonumber 98 | local msg = R(" ~")^0 99 | local response = Ct( 100 | Cg(version, 'version') * abnf.WSP 101 | * Cg(indication,'indication') 102 | * Cg(status, 'status') * abnf.WSP 103 | * Cg(msg, 'msg') 104 | ) 105 | 106 | local header = ih.Hc"Date" * ih.COLON * HTTP_date * abnf.CRLF 107 | + ih.Hc"Content-Length" * ih.COLON * (R"09"^1 / tonumber) * abnf.CRLF 108 | + ih.Hc"Content-Location" * ih.COLON * url * abnf.CRLF 109 | + ih.Hc"Content-Type" * ih.COLON * media_type * abnf.CRLF 110 | + ih.Hc"Location" * ih.COLON * url * abnf.CRLF 111 | + ih.Hc"ETag" * ih.COLON * P"W/"^-1 * quoted_string * abnf.CRLF 112 | + ih.Hc"Connection" * ih.COLON * token * abnf.CRLF 113 | + ih.Hc"Expires" * ih.COLON * HTTP_date * abnf.CRLF 114 | + ih.Hc"Last-Modified" * ih.COLON * HTTP_date * abnf.CRLF 115 | + ih.Hc"Cache-Control" * ih.COLON * cache_response_directive * abnf.CRLF 116 | + ih.generic 117 | 118 | return { 119 | response = response, 120 | headers = ih.headers(header), 121 | } 122 | 123 | --[[ 124 | Access-Control-Allow-Origin 125 | Access-Control-Allow-Credentials 126 | Access-Control-Expose-Headers 127 | Access-Control-Max-Age 128 | Access-Control-Allow-Methods 129 | Access-Control-Allow-Headers 130 | Accept-Patch 131 | Accept-Ranges 132 | Age 133 | Allow 134 | Alt-Svc 135 | Content-Disposition 136 | Content-Encoding 137 | Content-Language 138 | Content-Range 139 | Delta-Base 140 | IM 141 | Last-Modified 142 | Link 143 | P3P 144 | Pragma 145 | Proxy-Authenticate 146 | Public-Key-Pins 147 | Retry-After 148 | Server 149 | Set-Cookie 150 | Strict-Transport-Security 151 | Trailer 152 | Transfer-Encoding 153 | Tk 154 | Upgrade 155 | Vary 156 | Via 157 | Warning 158 | WWW-Authenticate 159 | --]] 160 | -------------------------------------------------------------------------------- /http-server.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 | local abnf = require "org.conman.parsers.abnf" 24 | local strftime = require "org.conman.parsers.strftime" 25 | local url = require "org.conman.parsers.url" 26 | local ih = require "org.conman.parsers.ih" 27 | local lpeg = require "lpeg" 28 | 29 | local Cb = lpeg.Cb 30 | local Cc = lpeg.Cc 31 | local Cf = lpeg.Cf 32 | local Cg = lpeg.Cg 33 | local Ct = lpeg.Ct 34 | local C = lpeg.C 35 | local P = lpeg.P 36 | local R = lpeg.R 37 | local S = lpeg.S 38 | local V = lpeg.V 39 | 40 | local TEXT = R("\1\8","\10\31"," \255") 41 | local separators = S[[()<>@,;:\<>/[]?={}]] 42 | local token = (R"!~" - separators)^1 43 | local quoted_pair = P"\\" * abnf.CHAR 44 | local qdtext = TEXT - P'"' 45 | local quoted_string = P'"' * (qdtext + quoted_pair)^0 * P'"' 46 | local ctext = TEXT - S"()" 47 | local comment = 48 | { 49 | "comment", 50 | comment = P"(" * (ctext + quoted_pair + V"comment")^0 * P")" 51 | } 52 | 53 | local attribute = token 54 | local value = token + quoted_string 55 | local parameter = C(attribute) * P"=" * C(value) 56 | local type = token 57 | local subtype = token 58 | local media_type = Ct( 59 | Cg(type * P"/" * subtype,"media") 60 | * Cg(Ct"" / function(t) t.q = "1.0" return t end,"params") 61 | * Cg( 62 | Cf( 63 | 64 | Cb'params' 65 | * (P";" * abnf.LWSP^-1 * Cg(parameter))^1, 66 | function(t,k,v) 67 | t[k] = v 68 | return t 69 | end 70 | ) 71 | + Cb'params', 72 | 'params' 73 | ) 74 | ) 75 | local media_type_list = Ct(media_type * (abnf.LWSP^-1 * P"," * abnf.LWSP^-1 * media_type)^0) 76 | local HTTP_date = strftime:match "%a, %d %b %Y %H:%M:%S" 77 | local cache_directive = Cf(Ct"" * ( 78 | Cg(C'public' * Cc(true)) 79 | + Cg(C'private' * C(quoted_string)) 80 | + Cg(C'no-cache' * C(quoted_string)) 81 | + Cg(C'no-store' * Cc(true)) 82 | + Cg(C'must-revalidate' * Cc(true)) 83 | + Cg(C'proxy-revalidate' * Cc(true)) 84 | + Cg(C'max-age' * P"=" * (R"09"^1 / tonumber)) 85 | + Cg(C's-maxage' * P"=" * (R"09"^1 / tonumber)) 86 | + Cg(C(token) * P"=" * C(token + quoted_string)) 87 | ), 88 | function(t,k,v) 89 | t[k] = v 90 | return t 91 | end 92 | ) 93 | 94 | local Method = P"OPTIONS" 95 | + P"GET" 96 | + P"HEAD" 97 | + P"POST" 98 | + P"PUT" 99 | + P"DELETE" 100 | + P"TRACE" 101 | + P"CONNECT" 102 | + token 103 | local version = P"HTTP/1.1" * Cc"1.1" 104 | + P"HTTP/1.0" * Cc"1.0" 105 | + Cc"0.9" 106 | local request = Ct( 107 | Cg(Method, 'method') * abnf.WSP 108 | * Cg(url, 'location') * abnf.WSP 109 | * Cg(version,'version') 110 | ) 111 | local header = ih.Hc"Date" * ih.COLON * HTTP_date * abnf.CRLF 112 | + ih.Hc"Content-Length" * ih.COLON * (R"09"^1 / tonumber) * abnf.CRLF 113 | + ih.Hc"Content-Type" * ih.COLON * media_type * abnf.CRLF 114 | + ih.Hc"Connection" * ih.COLON * C(token) * abnf.CRLF 115 | + ih.Hc"Cache-Control" * ih.COLON * cache_directive * abnf.CRLF 116 | + ih.Hc"User-Agent" * ih.COLON * C(R" ~"^0) * abnf.CRLF 117 | + ih.Hc"Accept" * ih.COLON * media_type_list * abnf.CRLF 118 | + ih.generic 119 | 120 | return { 121 | request = request, 122 | headers = ih.headers(header) 123 | } 124 | 125 | --[[ 126 | A-IM 127 | Accept-Charset 128 | Accept-Encoding 129 | Accept-Language 130 | Accept-Datetime 131 | Access-Control-Request-Method 132 | Access-Control-Request-Headers 133 | Authorization 134 | Cookie 135 | Expect 136 | Forwarded 137 | From 138 | Host 139 | If-Match 140 | If-Modified-Since 141 | If-None-Match 142 | If-Range 143 | If-Unmodified-Since 144 | Max-Forwards 145 | Origin 146 | Pragma 147 | Proxy-Authorization 148 | Range 149 | Referer 150 | TE 151 | User-Agent 152 | Upgrade 153 | Via 154 | Warning 155 | --]] 156 | -------------------------------------------------------------------------------- /ih.lua: -------------------------------------------------------------------------------- 1 | -- *************************************************************** 2 | -- 3 | -- Copyright 2020 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 useful LPEG expressions to help the parsing of Internet headers. 23 | -- 24 | -- ******************************************************************** 25 | -- luacheck: ignore 611 26 | 27 | local abnf = require "org.conman.parsers.abnf" 28 | local lpeg = require "lpeg" 29 | 30 | local char = lpeg.R("AZ","az") 31 | / function(c) 32 | return lpeg.P(c:lower()) + lpeg.P(c:upper()) 33 | end 34 | + lpeg.P(1) 35 | / function(c) 36 | return lpeg.P(c) 37 | end 38 | local H = lpeg.Cf(char^1,function(a,b) return a * b end) 39 | local COLON = lpeg.P":" * abnf.LWSP 40 | local generic = lpeg.C(lpeg.R("AZ","az","09","--","__")^1) 41 | * COLON 42 | * lpeg.C((lpeg.R"!\255" + (abnf.WSP + abnf.CRLF * abnf.WSP)^1 / " ")^0) 43 | * abnf.CRLF 44 | 45 | local function headers(patt) 46 | return lpeg.Cf( 47 | lpeg.Ct"" * lpeg.Cg(patt)^1 * abnf.CRLF, 48 | function(t,k,v) t[k] = v return t end 49 | ) 50 | end 51 | 52 | return { 53 | Hc = function(s) return H:match(s) / s end, 54 | H = function(s) return H:match(s) end, 55 | COLON = COLON, 56 | generic = generic, 57 | headers = headers, 58 | } 59 | -------------------------------------------------------------------------------- /ini.lua: -------------------------------------------------------------------------------- 1 | -- *************************************************************** 2 | -- 3 | -- Copyright 2013 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 | local lpeg = require "lpeg" 24 | local Cf = lpeg.Cf 25 | local Cg = lpeg.Cg 26 | local Ct = lpeg.Ct 27 | local C = lpeg.C 28 | local P = lpeg.P 29 | local S = lpeg.S 30 | 31 | -- ********************************************************************** 32 | 33 | local merge = function() end -- forward declaration 34 | 35 | local function doset(dest,name,value) 36 | if dest[name] == nil then 37 | dest[name] = value 38 | elseif type(dest[name]) ~= 'table' then 39 | dest[name] = { dest[name] , value } 40 | else 41 | if type(value) == 'table' then 42 | for i = 1 , #value do 43 | table.insert(dest[name],value[i]) 44 | value[i] = nil 45 | end 46 | merge(dest[name],value) 47 | else 48 | table.insert(dest[name],value) 49 | end 50 | end 51 | return dest 52 | end 53 | 54 | -- ********************************************************************** 55 | 56 | merge = function(dest,src) 57 | for name,value in pairs(src) do 58 | doset(dest,name,value) 59 | end 60 | end 61 | 62 | -- ********************************************************************** 63 | 64 | local CRLF = P"\r"^-1 * P"\n" 65 | local SP = P" " + P"\t" 66 | local EQ = SP^0 * P"=" * SP^0 67 | local COMMA = SP^0 * P"," * SP^0 68 | 69 | local comment = SP^0 * (P";" + P"#") * (P(1) - CRLF)^0 70 | local blank = SP^0 * comment^-1 * CRLF 71 | 72 | local name = C((P(1) - S" \t=[]" )^1) 73 | / function(c) return c:lower() end 74 | 75 | local item = C((P(1) - S",;#\r\n")^1) 76 | local char = P(1) - P'"' 77 | local quoted = P'"' * C(char^0) * P'"' 78 | local value = quoted + item 79 | local values = Ct(value * (COMMA * value)^1) * comment^-1 80 | + value * comment^-1 81 | 82 | local pair = SP^0 * Cg(name * EQ * values) * CRLF 83 | local nvpairs = Cf(Ct"" * (blank + pair)^0,doset) 84 | 85 | local sname = SP^0 * P"[" * SP^0 * name * SP^0 * P"]" * comment^-1 * CRLF 86 | local section = Cg(sname * nvpairs) 87 | 88 | local ini = Cf(Ct"" * (blank + section + pair)^1,doset) 89 | 90 | -- ********************************************************************** 91 | 92 | return ini 93 | -------------------------------------------------------------------------------- /ip-text.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 | local lpeg = require "lpeg" 24 | local tonumber = tonumber 25 | 26 | local Cmt = lpeg.Cmt 27 | local P = lpeg.P 28 | 29 | -- ********************************************************************* 30 | 31 | local DIGIT = lpeg.locale().digit 32 | local HEXDIG = lpeg.locale().xdigit 33 | 34 | local dec_octet = Cmt(DIGIT^1,function(_,position,capture) 35 | local n = tonumber(capture) 36 | if n < 256 then 37 | return position 38 | end 39 | end) 40 | 41 | local IPv4 = dec_octet * "." * dec_octet * "." * dec_octet * "." * dec_octet 42 | local h16 = HEXDIG^-4 43 | local h16c = h16 * P":" * #HEXDIG 44 | local ls32 = IPv4 + h16c * h16 45 | 46 | local function mh16(n) 47 | local accum = h16 48 | for _ = 1 , n do 49 | accum = h16c * accum 50 | end 51 | return accum 52 | end 53 | 54 | local function mh16c(n) 55 | local accum = h16c 56 | for _ = 2 , n do 57 | accum = accum * h16c 58 | end 59 | return accum 60 | end 61 | 62 | local IPv6 = mh16c(6) * ls32 -- a 63 | + P'::' * mh16c(5) * ls32 -- b 64 | + P'::' * mh16c(4) * ls32 -- c 65 | + h16 * P'::' * mh16c(4) * ls32 66 | + P'::' * mh16c(3) * ls32 -- d 67 | + h16 * P'::' * mh16c(3) * ls32 68 | + mh16(1) * P'::' * mh16c(3) * ls32 69 | + P'::' * mh16c(2) * ls32 -- e 70 | + h16 * P'::' * mh16c(2) * ls32 71 | + mh16(1) * P'::' * mh16c(2) * ls32 72 | + mh16(2) * P'::' * mh16c(2) * ls32 73 | + P'::' * h16c * ls32 -- f 74 | + h16 * P'::' * h16c * ls32 75 | + mh16(1) * P'::' * h16c * ls32 76 | + mh16(2) * P'::' * h16c * ls32 77 | + mh16(3) * P'::' * h16c * ls32 78 | + P'::' * ls32 -- g 79 | + h16 * P'::' * ls32 80 | + mh16(1) * P'::' * ls32 81 | + mh16(2) * P'::' * ls32 82 | + mh16(3) * P'::' * ls32 83 | + mh16(4) * P'::' * ls32 84 | + P'::' * h16 -- h 85 | + h16 * P'::' * h16 86 | + mh16(1) * P'::' * h16 87 | + mh16(2) * P'::' * h16 88 | + mh16(3) * P'::' * h16 89 | + mh16(4) * P'::' * h16 90 | + mh16(5) * P'::' * h16 91 | + P'::' -- i 92 | + h16 * P'::' 93 | + mh16(1) * P'::' 94 | + mh16(2) * P'::' 95 | + mh16(3) * P'::' 96 | + mh16(4) * P'::' 97 | + mh16(5) * P'::' 98 | + mh16(6) * P'::' 99 | 100 | return { IPv4 = lpeg.C(IPv4) , IPv6 = lpeg.C(IPv6) } 101 | -------------------------------------------------------------------------------- /ip.lua: -------------------------------------------------------------------------------- 1 | -- *************************************************************** 2 | -- 3 | -- Copyright 2013 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 | local floor = math.floor 24 | local string = string 25 | local tonumber = tonumber 26 | local lpeg = require "lpeg" 27 | 28 | local Cmt = lpeg.Cmt 29 | local Cf = lpeg.Cf 30 | local P = lpeg.P 31 | 32 | -- ********************************************************************* 33 | 34 | local function acc(a,v) return a .. v end 35 | 36 | local DIGIT = lpeg.locale().digit 37 | local HEXDIG = lpeg.locale().xdigit 38 | 39 | local dec_octet = Cmt(DIGIT^1,function(_,position,capture) 40 | local n = tonumber(capture) 41 | if n < 256 then 42 | return position,string.char(n) 43 | end 44 | end) 45 | 46 | local IPv4 = Cf( 47 | dec_octet * "." * dec_octet * "." * dec_octet * "." * dec_octet, 48 | acc 49 | ) 50 | 51 | local h16 = Cmt(HEXDIG^1,function(_,position,capture) 52 | local n = tonumber(capture,16) 53 | if n < 65536 then 54 | local q = floor(n/256) 55 | local r = n % 256 56 | return position,string.char(q) .. string.char(r) 57 | end 58 | end) 59 | 60 | local h16c = h16 * P":" * #HEXDIG 61 | local ls32 = IPv4 + h16c * h16 62 | 63 | local function mcc(n) 64 | return P"::" / string.rep("\0",n * 2) 65 | end 66 | 67 | local function mh16(n) 68 | local accum = P(true) 69 | for _ = 1 , n-1 do 70 | accum = accum * h16c 71 | end 72 | accum = accum * h16 73 | return accum 74 | end 75 | 76 | local function mh16c(n) 77 | local accum = P(true) 78 | for _ = 1 , n do 79 | accum = accum * h16c 80 | end 81 | return accum 82 | end 83 | 84 | local IPv6 = Cf( mh16c(6) * ls32,acc) -- a 85 | + Cf( mcc(1) * mh16c(5) * ls32,acc) -- b 86 | + Cf( mcc(2) * mh16c(4) * ls32,acc) -- c 87 | + Cf(h16 * mcc(1) * mh16c(4) * ls32,acc) 88 | + Cf( mcc(3) * mh16c(3) * ls32,acc) -- d 89 | + Cf(h16 * mcc(2) * mh16c(3) * ls32,acc) 90 | + Cf(mh16(2) * mcc(1) * mh16c(3) * ls32,acc) 91 | + Cf( mcc(4) * mh16c(2) * ls32,acc) -- e 92 | + Cf(h16 * mcc(3) * mh16c(2) * ls32,acc) 93 | + Cf(mh16(2) * mcc(2) * mh16c(2) * ls32,acc) 94 | + Cf(mh16(3) * mcc(1) * mh16c(2) * ls32,acc) 95 | + Cf( mcc(5) * h16c * ls32,acc) -- f 96 | + Cf(h16 * mcc(4) * h16c * ls32,acc) 97 | + Cf(mh16(2) * mcc(3) * h16c * ls32,acc) 98 | + Cf(mh16(3) * mcc(2) * h16c * ls32,acc) 99 | + Cf(mh16(4) * mcc(1) * h16c * ls32,acc) 100 | + Cf( mcc(6) * ls32,acc) -- g 101 | + Cf(h16 * mcc(5) * ls32,acc) 102 | + Cf(mh16(2) * mcc(4) * ls32,acc) 103 | + Cf(mh16(3) * mcc(3) * ls32,acc) 104 | + Cf(mh16(4) * mcc(2) * ls32,acc) 105 | + Cf(mh16(5) * mcc(1) * ls32,acc) 106 | + Cf( mcc(7) * h16 ,acc) -- h 107 | + Cf(h16 * mcc(6) * h16 ,acc) 108 | + Cf(mh16(2) * mcc(5) * h16 ,acc) 109 | + Cf(mh16(3) * mcc(4) * h16 ,acc) 110 | + Cf(mh16(4) * mcc(3) * h16 ,acc) 111 | + Cf(mh16(5) * mcc(2) * h16 ,acc) 112 | + Cf(mh16(6) * mcc(1) * h16 ,acc) 113 | + Cf( mcc(8) ,acc) -- i 114 | + Cf(h16 * mcc(7) ,acc) 115 | + Cf(mh16(2) * mcc(6) ,acc) 116 | + Cf(mh16(3) * mcc(5) ,acc) 117 | + Cf(mh16(4) * mcc(4) ,acc) 118 | + Cf(mh16(5) * mcc(3) ,acc) 119 | + Cf(mh16(6) * mcc(2) ,acc) 120 | + Cf(mh16(7) * mcc(1) ,acc) 121 | 122 | return { IPv4 = IPv4 , IPv6 = IPv6 } 123 | -------------------------------------------------------------------------------- /iri.lua: -------------------------------------------------------------------------------- 1 | -- *************************************************************** 2 | -- 3 | -- Copyright 2020 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 | local ip = require "org.conman.parsers.ip-text" 24 | local abnf = require "org.conman.parsers.abnf" 25 | local lpeg = require "lpeg" 26 | local re = require "re" 27 | 28 | -- ************************************************************************ 29 | -- RFC-3987 30 | -- ************************************************************************ 31 | 32 | local G = --[[ lpeg/re ]] [[ 33 | 34 | IRI_reference <- {| IRI / irelative_ref |} 35 | IRI <- scheme ':' ihier_part ('?' iquery)? ('#' ifragment)? 36 | 37 | scheme <- {:scheme: 'https' & ':' :} {:port: %p443 :} 38 | / {:scheme: 'http' & ':' :} {:port: %p80 :} 39 | / {:scheme: 'ftp' & ':' :} {:port: %p21 :} 40 | / {:scheme: 'gemini' & ':' :} {:port: %p1965 :} 41 | / {:scheme: 'file' & ':' :} 42 | / {:scheme: %ALPHA (%ALPHA / %DIGIT / '+' / '-' / '.')* :} 43 | 44 | ihier_part <- '//' iauthority {:path: ipath_abempty :} 45 | / {:path: ipath_absolute :} 46 | / {:path: ipath_rootless :} 47 | / {:path: ipath_empty :} 48 | 49 | irelative_ref <- irelative_part ('?' iquery)? ('#' ifragment)? 50 | 51 | irelative_part <- '//' iauthority {:path: ipath_abempty :} 52 | / {:path: ipath_absolute :} 53 | / {:path: ipath_noscheme :} 54 | / {:path: ipath_empty :} 55 | 56 | iauthority <- (iuserinfo '@')? ihost (':' port)? 57 | iuserinfo <- {:user: {~ (iunreserved / %pct_encoded / sub_delims / ':')* ~} :} 58 | ihost <- {:host: IP_literal / %IPv4address / ireg_name :} 59 | port <- {:port: %DIGIT+ -> tonumber :} 60 | 61 | IP_literal <- '[' ( IPv6addrz / %IPv6address / IPvFuture) ']' -- RFC-6874 62 | IPvFuture <- { 'v' %HEXDIG+ '.' (iunreserved / sub_delims / ':')+ } 63 | ZoneID <- {~ (iunreserved / %pct_encoded)+ ~} -- RFC-6874 64 | IPv6addrz <- {~ %IPv6address '%25' -> '%%' ZoneID ~} -- RFC-6874 65 | ireg_name <- {~ (iunreserved / %pct_encoded / sub_delims)* ~} 66 | ipath <- ipath_abempty -- begins with '/' or is empty 67 | / ipath_absolute -- begins with '/' but not '//' 68 | / ipath_noscheme -- begins with a non-colon segment 69 | / ipath_rootless -- begins with a segment 70 | / ipath_empty 71 | ipath_abempty <- {~ ( '/' isegment)+ ~} / '' -> '/' 72 | ipath_absolute <- {~ '/' (isegment_nz ('/' isegment)* )? ~} 73 | ipath_noscheme <- {~ isegment_nz_nc ('/' isegment)* ~} 74 | ipath_rootless <- {~ isegment_nz ('/' isegment)* ~} 75 | ipath_empty <- '' -> '/' 76 | isegment <- ipchar* 77 | isegment_nz <- ipchar+ 78 | isegment_nz_nc <- (iunreserved / %pct_encoded / sub_delims / '@')+ 79 | ipchar <- iunreserved / %pct_encoded / sub_delims / '@' / ':' 80 | iquery <- {:query: { (ipchar / '/' / '?')* } :} 81 | ifragment <- {:fragment: {~ (ipchar / '/' / '?')* ~} :} 82 | reserved <- gen_delims / sub_delims 83 | gen_delims <- ':' / '/' / '?' / '#' / '[' / ']' / '@' 84 | sub_delims <- '!' / '$' / '&' / "'" / '(' / ')' 85 | / '*' / '+' / ',' / ';' / '=' 86 | iunreserved <- %ALPHA / %DIGIT / '-' / '.' / '_' / '~' / %utf8c 87 | ]] 88 | 89 | -- ********************************************************************* 90 | 91 | local pct_encoded = (lpeg.P"%" * abnf.HEXDIG * abnf.HEXDIG) 92 | / function(capture) 93 | local n = tonumber(capture:sub(2,-1),16) 94 | return string.char(n) 95 | end 96 | local R = 97 | { 98 | HEXDIG = abnf.HEXDIG, 99 | ALPHA = abnf.ALPHA, 100 | DIGIT = abnf.DIGIT, 101 | 102 | p443 = lpeg.Cc( 443), 103 | p80 = lpeg.Cc( 80), 104 | p21 = lpeg.Cc( 21), 105 | p1965 = lpeg.Cc(1965), 106 | tonumber = tonumber, 107 | IPv4address = ip.IPv4, 108 | IPv6address = ip.IPv6, 109 | pct_encoded = pct_encoded, 110 | utf8c = require "org.conman.parsers.utf8.char" 111 | } 112 | 113 | return re.compile(G,R) 114 | -------------------------------------------------------------------------------- /iso.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 | -- 22 | -- Parse a valid ISO character. 23 | -- 24 | -- ******************************************************************** 25 | -- luacheck: ignore 611 26 | 27 | return require "org.conman.parsers.iso.char" 28 | + require "org.conman.parsers.ascii.char" 29 | + require "org.conman.parsers.iso.control" 30 | + require "org.conman.parsers.ascii.control" 31 | -------------------------------------------------------------------------------- /iso/char.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 | -- 22 | -- Parse a valid ISO non-control character. 23 | -- 24 | -- ******************************************************************** 25 | -- luacheck: ignore 611 26 | 27 | local lpeg = require "lpeg" 28 | return lpeg.R"\160\255" 29 | -------------------------------------------------------------------------------- /iso/control.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 | -- 22 | -- Parse a valid ISO control character. 23 | -- 24 | -- ******************************************************************** 25 | -- luacheck: ignore 611 26 | 27 | local lpeg = require "lpeg" 28 | local iso = require "org.conman.parsers.iso.char" 29 | local ascii = require "org.conman.parsers.ascii.char" 30 | 31 | local CSI = lpeg.P"\155" + lpeg.P"\27[" 32 | local OSC = lpeg.P"\157" + lpeg.P"\27]" 33 | local ST = lpeg.P"\156" + lpeg.P"\27\\" 34 | local str = lpeg.S"\144\152\158\159" 35 | + lpeg.P"\27" * lpeg.S"PX^_" 36 | 37 | return CSI * lpeg.R"0?"^0 * lpeg.R" /"^0 * lpeg.R"@~" 38 | + OSC * (lpeg.R"\8\13" + ascii + iso)^0 * (ST + lpeg.P"\7") -- xterm uses BEL 39 | + str * (lpeg.R"\8\13" + ascii + iso)^0 * ST 40 | + lpeg.P"\27" * lpeg.R"`~" -- 7-bit of C1 41 | + lpeg.R"\128\159" -- rest of C1 42 | + lpeg.P"\27" * lpeg.R"@_" -- rest of C1 (7-bits) 43 | 44 | -------------------------------------------------------------------------------- /iso/ctrl.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 | -- 22 | -- Return name of ISO control character and associated data. 23 | -- 24 | -- ******************************************************************** 25 | -- luacheck: ignore 611 26 | 27 | local lpeg = require "lpeg" 28 | local iso = require "org.conman.parsers.iso.char" 29 | local ascii = require "org.conman.parsers.ascii.char" 30 | 31 | local Cb = lpeg.Cb 32 | local Cc = lpeg.Cc 33 | local Cf = lpeg.Cf 34 | local Cg = lpeg.Cg 35 | local Cs = lpeg.Cs 36 | local Ct = lpeg.Ct 37 | local C = lpeg.C 38 | local P = lpeg.P 39 | local R = lpeg.R 40 | 41 | local codes = 42 | { 43 | -- --------------------------------- 44 | -- C1 set 45 | -- --------------------------------- 46 | 47 | ['\27@'] = '\128' , ['\128'] = '\128' , 48 | ['\27A'] = '\129' , ['\129'] = '\129' , 49 | ['\27B'] = 'BPH' , ['\130'] = 'BPH' , -- BREAK PERMITTED HERE 50 | ['\27C'] = 'NBH' , ['\131'] = 'NBH' , -- NO BREAK HERE 51 | ['\27D'] = '\132' , ['\132'] = '\132' , 52 | ['\27E'] = 'NEL' , ['\133'] = 'NEL' , -- NEXT LINE 53 | ['\27F'] = 'SSA' , ['\134'] = 'SSA' , -- START OF SELECTED AREA 54 | ['\27G'] = 'ESA' , ['\135'] = 'ESA' , -- END OF SELECTED AREA 55 | ['\27H'] = 'HTS' , ['\136'] = 'HTS' , -- CHARACTER TABULATION SET 56 | ['\27I'] = 'HTJ' , ['\137'] = 'HTJ' , -- CHARACTER TABULATION WITH JUSTIFICATION 57 | ['\27J'] = 'VTS' , ['\138'] = 'VTS' , -- LINE TABULATION SET 58 | ['\27K'] = 'PLD' , ['\139'] = 'PLD' , -- PARTIAL LINE FORWARD 59 | ['\27L'] = 'PLU' , ['\140'] = 'PLU' , -- PARTIAL LINE BACKWARD 60 | ['\27M'] = 'RI' , ['\141'] = 'RI' , -- REVERSE LINE FEED 61 | ['\27N'] = 'SS2' , ['\142'] = 'SS2' , -- SINGLE-SHIFT TWO 62 | ['\27O'] = 'SS3' , ['\143'] = 'SS3' , -- SINGLE-SHIFT THREE 63 | -- DCS - handled below DEVICE CONTROL STRING 64 | ['\27Q'] = 'PU1' , ['\145'] = 'PU1' , -- PRIVATE USE ONE 65 | ['\27R'] = 'PU2' , ['\146'] = 'PU2' , -- PRIVATE USE TWO 66 | ['\27S'] = 'STS' , ['\147'] = 'STS' , -- SET TRANSMIT STATE 67 | ['\27T'] = 'CCH' , ['\148'] = 'CCH' , -- CANCEL CHARACTER 68 | ['\27U'] = 'MW' , ['\149'] = 'MW' , -- MESSAGE WAITING 69 | ['\27V'] = 'SPA' , ['\150'] = 'SPA' , -- START OF GUARDED AREA 70 | ['\27W'] = 'EPA' , ['\151'] = 'EPA' , -- END OF GUARDED AREA 71 | -- SOS - handled below START OF STRING 72 | ['\27Y'] = '\153' , ['\153'] = '\153' , 73 | ['\27Z'] = 'SCI' , ['\154'] = 'SCI' , -- SINGLE CHARACTER INTRODUCER 74 | -- CSI - handled below CONTROL SEQUENCE INTRODUCER 75 | -- ST - handled below STRING TERMINATOR 76 | -- OSC - handled below OPERATING SYSTEM COMMAND 77 | -- PM - handled below PRIVACY MESSAGE 78 | -- APC - handled below APPLICATION PROGRAM COMMAND 79 | 80 | -- --------------------------------- 81 | -- Independent control functions 82 | -- --------------------------------- 83 | 84 | ['\27`'] = 'DMI' , -- DISABLE MANUAL INPUT 85 | ['\27a'] = 'INT' , -- INTERRUPT 86 | ['\27b'] = 'EMI' , -- ENABLE MANUAL INPUT 87 | ['\27c'] = 'RTS' , -- RESET TO INITIAL STATE 88 | ['\27d'] = 'CMD' , -- CODING METHOD DELIMITER 89 | ['\27e'] = '\27e' , 90 | ['\27f'] = '\27f' , 91 | ['\27g'] = '\27g' , 92 | ['\27h'] = '\27h' , 93 | ['\27i'] = '\27i' , 94 | ['\27j'] = '\27j' , 95 | ['\27k'] = '\27k' , 96 | ['\27l'] = '\27l' , 97 | ['\27m'] = '\27m' , 98 | ['\27n'] = 'LS2' , -- LOCKING-SHIFT 2 99 | ['\27o'] = 'LS3' , -- LOCKING-SHIFT 3 100 | ['\27p'] = '\27p' , 101 | ['\27q'] = '\27q' , 102 | ['\27r'] = '\27r' , 103 | ['\27s'] = '\27s' , 104 | ['\27t'] = '\27t' , 105 | ['\27u'] = '\27u' , 106 | ['\27v'] = '\27v' , 107 | ['\27w'] = '\27w' , 108 | ['\27x'] = '\27x' , 109 | ['\27y'] = '\27y' , 110 | ['\27z'] = '\27z' , 111 | ['\27{'] = '\27{' , 112 | ['\27|'] = 'LS3R' , -- LOCKING-SHIFT THREE RIGHT 113 | ['\27}'] = 'LS2R' , -- LOCKING-SHIFT TWO RIGHT 114 | ['\27~'] = 'LSR1' , -- LOCKING-SHIFT ONE RIGHT 115 | } 116 | 117 | local cstr = R"\8\13" + ascii + iso 118 | 119 | local ST = P"\27\\" + P"\156" 120 | local DCS = (P'\27P' + P'\144') * Cc'DCS' * C(cstr^0) * ST 121 | local SOS = (P'\27X' + P'\152') * Cc'SOS' * C(cstr^0) * ST 122 | local OSC = (P'\27]' + P'\157') * Cc'OSC' * C(cstr^0) * (ST + P"\7") -- xterm 123 | local PM = (P'\27^' + P'\158') * Cc'PM' * C(cstr^0) * ST 124 | local APC = (P'\27_' + P'\159') * Cc'APC' * C(cstr^0) * ST 125 | 126 | local CSI_codes = [[ 127 | @ ICH INSERT CHARACTER 128 | A CCU CURSOR UP 129 | B CUD CURSOR DOWN 130 | C CUF CURSOR RIGHT 131 | D CUB CURSOR LEFT 132 | E CNL CURSOR NEXT LINE 133 | F CPL CURSOR PRECEDING LINE 134 | G CHA CURSOR CHARACTER ABSOLUTE 135 | H CUP CURSOR POSITION 136 | I CHT CURSOR FORWARD TABULATION 137 | J ED ERASE IN PAGE 138 | K EL ERASE IN LINE 139 | L IL INSERT LINE 140 | M DL DELETE LINE 141 | N EF ERASE IN FIELD 142 | O EA ERASE IN AREA 143 | P DCH DELETE CHARACTER 144 | Q SEE SELECT EDITING EXTENT 145 | R CPR ACTIVE POSITION REPORT 146 | S SU SCROLL UP 147 | T SD SCROLL DOWN 148 | U NP NEXT PAGE 149 | V PP PRECEDING PAGE 150 | W CTC CURSOR TABULATION CONTROL 151 | X ECH ERASE CHARACTER 152 | Y CVT CURSOR LINE TABULATION 153 | Z CBT CURSOR BACKWARD TABULATION 154 | [ SRS START REVERSED STRING 155 | \ PTX PARALLEL TEXTS 156 | ] SOS START DIRECTED STRING 157 | ^ SIMD SELECT IMPLICIT MOVEMENT DIRECTION 158 | _ _ 159 | ` HPA CHARACTER POSITION ABSOLUTE 160 | a HPR CHARACTER POSITION FORWARD 161 | b REP REPEAT 162 | c DA DEVICE ATTRIBUTES 163 | d VPA LINE POSITION ABOLUTE 164 | e VPR LINE POSITION FORWARD 165 | f HVP CHARACTER AND LINE POSITION 166 | g TBC TABULATION CLEAR 167 | h SM SET MODE 168 | i MC MEDIA COPY 169 | j HPB CHARACTER POSITION BACKWARD 170 | k VPB LINE POSITION BACKWARD 171 | l RM RESET MODE 172 | m SGR SELECT GRAPHIC RENDITION 173 | n DSR DEVICE STATUS REPORT 174 | o DAQ DEFINE AREA QUALIFICATION 175 | p p private use 176 | q q | 177 | r r V 178 | s s 179 | t t 180 | u u 181 | v v 182 | w w 183 | x x 184 | y y 185 | z z 186 | { { 187 | | | ^ 188 | } } | 189 | ~ ~ private use 190 | ]] 191 | 192 | local CSI_space_codes = [[ 193 | @ SL SCROLL LEFT 194 | A SR SCROLL RIGHT 195 | B GSM GRAPHIC SIZE MODIFICATION 196 | C GSS GRAPHIC SIZE SELECTION 197 | D FNT FONT SELECTION 198 | E TSS THIN SPACE SPECIFICATION 199 | F JFY JUSTIFY 200 | G SPI SPACING INCREMENT 201 | H QUAD QUAD 202 | I SSU SELECT SIZE UNIT 203 | J PFS PAGE FORMAT SELECTION 204 | K SHS SELECT CHARACTER SPACING 205 | L SVS SELECT LINE SPACING 206 | M IGS IDENTIFY GRAPHIC SUBREPERTOIRE 207 | N N 208 | O IDCS IDENTIFY DEVICE CONTROL STRING 209 | P PPA PAGE POSITION ABSOLUTE 210 | Q PPR PAGE POSITION FORWARD 211 | R PPB PAGE POSITION BACKWARD 212 | S SPD SELECT PRESENTATION DIRECTIONS 213 | T DTA DIMENSION TEXT AREA 214 | U SLH SET LINE HOME 215 | V SLL SET LINE LIMIT 216 | W FNK FUNCTION KEY 217 | X SPQR SET PRINT QUALITY AND RAPIDITY 218 | Y SEF SHEET EJECT AND FEED 219 | Z PEC PRESENTATION EXPAND OR CONTRACT 220 | [ SSW SET SPACE WIDTH 221 | \ SACS SET ADDITIONAL CHARACTER SEPARATION 222 | ] SAPV SELECT ALTERNATIVE PRESENTATION VARIANTS 223 | ^ STAB SELECTIVE TABULATION 224 | _ GCC GRAPHIC CHARACTER COMBINATION 225 | ` TATE TABULATION ALIGNED LEADING SPACE 226 | a TALE TABULATION ALIGNED LEADING EDGE 227 | b TAC TABULATION ALIGNED CENTERED 228 | c TCC TABULATION CENTERED ON CHARACTER 229 | d TSR TABULATION STOP REMOVE 230 | e SCO SELECT CHARACTER ORIENTATION 231 | f SCRS SET REDUCED CHARACTER SEPARATION 232 | g SCS SET CHARACTER SPACING 233 | h SLS SET LINE SPACING 234 | i i 235 | j j 236 | k SCP SELECT CHARACTER PATH 237 | l l 238 | m m 239 | n n 240 | o o 241 | p p private use 242 | q q | 243 | r r V 244 | s s 245 | t t 246 | u u 247 | v v 248 | w w 249 | x x 250 | y y 251 | z z 252 | { { 253 | | } ^ 254 | } } | 255 | ~ ~ private use 256 | ]] 257 | 258 | 259 | local CSI do 260 | 261 | local csi = P"\27[" + P"\155" 262 | local param = Cs((R"09" + P":" / ".")^1) / tonumber 263 | local params = Ct(param * (P';' * param)^0) 264 | + C(R". 17 | -- 18 | -- Comments, questions and criticisms can be sent to: sean@conman.org 19 | -- 20 | -- ******************************************************************** 21 | -- luacheck: globals null 22 | -- luacheck: ignore 611 23 | 24 | local lpeg = require "lpeg" 25 | local re = require "re" 26 | local up 27 | local utf8 28 | 29 | if _VERSION < "Lua 5.3" then 30 | local char = require "string".char 31 | local floor = require "math".floor 32 | local select = select 33 | 34 | utf8 = 35 | { 36 | char = function(...) 37 | local function onechar(n) 38 | if n < 0x80 then 39 | return char(n) 40 | elseif n < 0x800 then 41 | return char( 42 | floor(n / 2^6) + 0xC0, 43 | (n % 0x40) + 0x80 44 | ) 45 | else 46 | return char( 47 | (floor(n / 2^12) + 0xE0), 48 | (floor(n / 2^ 6) % 0x40) + 0x80, 49 | (n % 0x40) + 0x80 50 | ) 51 | end 52 | end 53 | 54 | local res = "" 55 | for i = 1 , select('#',...) do 56 | local c = select(i,...) 57 | res = res .. onechar(c) 58 | end 59 | return res 60 | end 61 | } 62 | 63 | if _VERSION == "Lua 5.1" then 64 | up = unpack -- luacheck: ignore 65 | else 66 | up = table.unpack -- luacheck: ignore 67 | end 68 | 69 | else 70 | utf8 = require "utf8" 71 | up = table.unpack -- luacheck: ignore 72 | end 73 | 74 | -- ********************************************************************** 75 | 76 | local G = --[[ lpeg/re ]] [[ 77 | json <- (object / array) !. 78 | 79 | object <- begin_object 80 | %member_list 81 | end_object 82 | member <- {: string name_separator value :} 83 | 84 | array <- begin_array 85 | {| (value (value_separator value)* )? |} 86 | end_array 87 | 88 | number <- { "-" ? int frac ? exp ? } => tonumber 89 | exp <- [Ee] [+-] ? [0-9]+ 90 | frac <- "." [0-9]+ 91 | int <- "0" / ( [1-9] [0-9]* ) 92 | 93 | string <- '"' char* -> {} => final_string '"' 94 | char <- unescaped => normal 95 | / '\"' => escape 96 | / "\\" => escape 97 | / "\b" => escape 98 | / "\f" => escape 99 | / "\n" => escape 100 | / "\r" => escape 101 | / "\t" => escape 102 | / "\/" => escape 103 | / ( 104 | "\u" 105 | { [0-9A-Fa-f]^4 } => tou16 106 | )+ -> {} => unicode 107 | 108 | unescaped <- [^\"%c] 109 | 110 | value <- "false" => retfalse 111 | / "null" => retnil 112 | / "true" => rettrue 113 | / object 114 | / array 115 | / number 116 | / string 117 | 118 | begin_array <- ws "[" ws 119 | end_array <- ws "]" ws 120 | begin_object <- ws "{" ws 121 | end_object <- ws "}" ws 122 | name_separator <- ws ":" ws 123 | value_separator <- ws "," ws 124 | ws <- %WS* 125 | ]] 126 | 127 | local member = lpeg.V"member" 128 | local value_separator = lpeg.V"value_separator" 129 | local member_list = lpeg.Cf( 130 | lpeg.Ct("") * (member * (value_separator * member)^0)^0, 131 | rawset 132 | ) 133 | 134 | -- ********************************************************************** 135 | 136 | local R = 137 | { 138 | WS = lpeg.S"\t\r\n ", 139 | 140 | member_list = member_list, 141 | 142 | retnil = function(_,position) 143 | return position,null 144 | end, 145 | 146 | retfalse = function(_,position) 147 | return position,false 148 | end, 149 | 150 | rettrue = function(_,position) 151 | return position,true 152 | end, 153 | 154 | tonumber = function(_,position,capture) 155 | return position,tonumber(capture) 156 | end, 157 | 158 | tou16 = function(_,position,capture) 159 | return position,tonumber(capture,16) 160 | end, 161 | 162 | unicode = function(_,position,capture) 163 | return position,utf8.char(up(capture)) 164 | end, 165 | 166 | normal = function(_,position,capture) 167 | return position,capture 168 | end, 169 | 170 | escape = function(_,position,capture) 171 | local trans = 172 | { 173 | [ [[\]] ] = 92, 174 | [ [[/]] ] = 47, 175 | [ [["]] ] = 34, 176 | b = 8 , 177 | f = 12 , 178 | n = 10, 179 | r = 13, 180 | t = 9 181 | } 182 | 183 | return position,string.char(trans[capture:sub(2,2)]) 184 | end, 185 | 186 | final_string = function(_,position,capture) 187 | return position,table.concat(capture,"") 188 | end, 189 | 190 | } 191 | 192 | -- ********************************************************************* 193 | 194 | lpeg.setmaxstack(1000) 195 | return re.compile(G,R) 196 | -------------------------------------------------------------------------------- /jsons.lua: -------------------------------------------------------------------------------- 1 | -- *************************************************************** 2 | -- 3 | -- Copyright 2017 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 null 22 | -- luacheck: ignore 611 23 | 24 | local lpeg = require "lpeg" 25 | local utf8 26 | 27 | if _VERSION < "Lua 5.3" then 28 | local char = require "string".char 29 | local floor = require "math".floor 30 | local select = select 31 | 32 | utf8 = 33 | { 34 | char = function(...) 35 | local function onechar(n) 36 | if n < 0x80 then 37 | return char(n) 38 | elseif n < 0x800 then 39 | return char( 40 | floor(n / 2^6) + 0xC0, 41 | (n % 0x40) + 0x80 42 | ) 43 | else 44 | return char( 45 | (floor(n / 2^12) + 0xE0), 46 | (floor(n / 2^ 6) % 0x40) + 0x80, 47 | (n % 0x40) + 0x80 48 | ) 49 | end 50 | end 51 | 52 | local res = "" 53 | for i = 1 , select('#',...) do 54 | local c = select(i,...) 55 | res = res .. onechar(c,16) 56 | end 57 | return res 58 | end 59 | } 60 | else 61 | utf8 = require "utf8" 62 | end 63 | 64 | -- ******************************************************************** 65 | 66 | local jsonS do 67 | local Cc = lpeg.Cc 68 | local Cp = lpeg.Cp 69 | local Cs = lpeg.Cs 70 | local Ct = lpeg.Ct 71 | local P = lpeg.P 72 | local R = lpeg.R 73 | local S = lpeg.S 74 | 75 | local int = P"0" 76 | + R"19" * R"09"^0 77 | local frac = P"." * R"09"^1 78 | local exp = S"Ee" * S"+-"^-1 * R"09"^1 79 | local number = (P"-"^-1 * int * frac^-1 * exp^-1) 80 | / tonumber 81 | 82 | local unescaped = R(" !","#[","]~","\128\255") 83 | local char = unescaped 84 | + P[[\"]] / [["]] 85 | + P[[\\]] / [[\]] 86 | + P[[\b]] / "\b" 87 | + P[[\f]] / "\f" 88 | + P[[\n]] / "\n" 89 | + P[[\r]] / "\r" 90 | + P[[\t]] / "\t" 91 | + P[[\/]] / "/" 92 | + P[[\u]] 93 | * ( 94 | R("09","AF","af") 95 | * R("09","AF","af") 96 | * R("09","AF","af") 97 | * R("09","AF","af") 98 | ) 99 | / function(c) 100 | return utf8.char(tonumber(c:sub(3,-1),16)) 101 | end 102 | local string = P'"' * Cs(char^0) * P'"' 103 | 104 | local ws = S"\t\r\n "^0 105 | local array = ws * P"[" * ws * #P(1) 106 | local object = ws * P"{" * ws * #P(1) 107 | local NAME = ws * P":" * ws * #P(1) 108 | local VALUE = ws * P"," * ws * #P(1) 109 | local ARRAY = ws * P"]" * ws 110 | local OBJECT = ws * P"}" * ws 111 | 112 | jsonS = Cc('string') * string * Cp() 113 | + Cc('number') * number * Cp() * #(VALUE + ARRAY + OBJECT) 114 | + P'false' * Cc('boolean') * Cc(false) * Cp() 115 | + P'true' * Cc('boolean') * Cc(true) * Cp() 116 | + P'null' * Cc('null') * Cc(null) * Cp() 117 | + array * Cc('array') * Ct("") * Cp() 118 | + object * Cc('object') * Ct("") * Cp() 119 | + ARRAY * Cc('ARRAY') * Cc(nil) * Cp() 120 | + OBJECT * Cc('OBJECT') * Cc(nil) * Cp() 121 | + NAME * Cc('NAME') * Cc(nil) * Cp() 122 | + VALUE * Cc('VALUE') * Cc(nil) * Cp() 123 | end 124 | 125 | -- ********************************************************************** 126 | -- Usage: json = jsonS:match(fundat) 127 | -- Desc: Return a Lua table populated from JSON data. This uses 128 | -- a streaming method that is more resource lean than my 129 | -- other JSON decoder. 130 | -- Input: fundat(string function) if a string, JSON encoded data. 131 | -- | if a function, it should return the next chunk 132 | -- | to parse; otherwise it should return nil or an 133 | -- | empty string to indicate no more data. 134 | -- Return: json (table) JSON data parsed as Lua data. 135 | -- 136 | -- Note: The JSON "null" value will be returned as a Lua nil. If 137 | -- you want a custom null value, define a global variable 138 | -- named "null" with the sentinel value you want. 139 | -- 140 | -- Always returning a single character from fundat() will 141 | -- cause issues with parsing. 142 | -- ********************************************************************** 143 | 144 | local function match(_,fundat) 145 | -- ----------------------------------------------------------------------- 146 | -- To be a drop-in replacement for my original JSON decoder, the fundat 147 | -- parameter can be a string. If it is, then replace it with a function 148 | -- that just returns said string. Otherwise, we have a function that will 149 | -- return the next chunk of data to read. 150 | -- ----------------------------------------------------------------------- 151 | 152 | if type(fundat) == 'string' then 153 | local data = fundat 154 | fundat = function() 155 | local d = data 156 | data = nil 157 | return d 158 | end 159 | end 160 | 161 | local data 162 | local pos 163 | local result 164 | local okay 165 | local array -- forward function reference 166 | local object -- forward function reference 167 | 168 | -- ----------------------------------------------------------------------- 169 | 170 | local function next_token(list) 171 | local token,val,newpos = jsonS:match(data,pos) 172 | if not token then 173 | local new = fundat() 174 | if new == nil or new == "" then error "parse" end 175 | data = data:sub(pos,-1) .. new 176 | pos = 1 177 | return next_token(list) 178 | else 179 | for _,isthis in ipairs(list) do 180 | if isthis == token then 181 | return token,val,newpos 182 | end 183 | end 184 | error "parse" 185 | end 186 | end 187 | 188 | -- ----------------------------------------------------------------------- 189 | -- JSON arrays and objects are mapped to Lua tables. During processing, 190 | -- the current array/object is stored in result. To help keep track of 191 | -- things, the following are temporarily stored during processing: 192 | -- 193 | -- result[false] -> parent node 194 | -- result[true] -> function to call for processing next token 195 | -- 196 | -- They are removed once an array/object is finished processing. 197 | -- ----------------------------------------------------------------------- 198 | 199 | local function insert_list(token,key,value,resume) 200 | result[key] = value 201 | result[true] = resume 202 | 203 | if token == 'array' then 204 | value[false] = result 205 | value[true] = array 206 | result = value 207 | elseif token == 'object' then 208 | value[false] = result 209 | value[true] = object 210 | result = value 211 | end 212 | 213 | return result[true]() 214 | end 215 | 216 | -- ----------------------------------------------------------------------- 217 | 218 | local end_list do 219 | -- --------------------------------------------------------- 220 | -- Sigh---the things I do to follow the letter of the spec. 221 | -- --------------------------------------------------------- 222 | 223 | local SPACE = lpeg.S"\t\r\n "^0 * lpeg.P(-1) 224 | 225 | local function drain(d) 226 | local extra = fundat() 227 | if not extra or extra == "" then 228 | return d 229 | else 230 | return drain(d .. extra) 231 | end 232 | end 233 | 234 | end_list = function() 235 | local parent = result[false] 236 | result[true] = nil 237 | result[false] = nil 238 | result = parent or result 239 | 240 | if not parent then 241 | if pos > #data then 242 | local extra = drain("") 243 | if SPACE:match(extra) then 244 | return result 245 | end 246 | end 247 | return nil 248 | else 249 | return result[true]() 250 | end 251 | end 252 | end 253 | 254 | -- ----------------------------------------------------------------------- 255 | 256 | local token 257 | local value 258 | 259 | local function array_value() 260 | token,value,pos = next_token { 'ARRAY' , 'VALUE' } 261 | if token == 'ARRAY' then 262 | return end_list() 263 | else 264 | assert(token == 'VALUE') 265 | token,value,pos = next_token { 'string' , 'number' , 'boolean' , 'null' , 'array' , 'object' } 266 | return insert_list(token,#result + 1,value,array_value) 267 | end 268 | end 269 | 270 | array = function() 271 | token,value,pos = next_token { 'string' , 'number' , 'boolean' , 'null' , 'array' , 'object' , 'ARRAY' } 272 | if token == 'ARRAY' then return end_list() end 273 | return insert_list(token,#result + 1,value,array_value) 274 | end 275 | 276 | -- ----------------------------------------------------------------------- 277 | 278 | local function object_value() 279 | token,value,pos = next_token { 'VALUE','OBJECT'} 280 | if token == 'OBJECT' then 281 | return end_list() 282 | else 283 | assert(token == 'VALUE') 284 | token,value,pos = next_token { 'string' } 285 | local name = value 286 | token,value,pos = next_token { 'NAME' } 287 | token,value,pos = next_token { 'string' , 'number' , 'boolean' , 'null' , 'array' , 'object' } 288 | return insert_list(token,name,value,object_value) 289 | end 290 | end 291 | 292 | object = function() 293 | token,value,pos = next_token { 'string' , 'OBJECT' } 294 | 295 | if token == 'OBJECT' then return end_list() end 296 | 297 | local name = value 298 | 299 | token,value,pos = next_token { 'NAME' } 300 | token,value,pos = next_token { 'string' , 'number' , 'boolean' , 'null' , 'array' , 'object' } 301 | return insert_list(token,name,value,object_value) 302 | end 303 | 304 | -- ------------------------------------------------------------------ 305 | 306 | okay,result = pcall(function() 307 | data = fundat() 308 | pos = 1 309 | 310 | if data == nil or data == "" then return nil end 311 | 312 | token,result,pos = next_token { 'array' , 'object' } 313 | 314 | if token == 'array' then 315 | return array() 316 | elseif token == 'object' then 317 | return object() 318 | end 319 | end) 320 | 321 | return okay and result or nil 322 | end 323 | 324 | -- ********************************************************************** 325 | 326 | return { match = match } 327 | -------------------------------------------------------------------------------- /mimetype.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 | -- 22 | -- Parse the MIME type from RFC-2045 23 | -- 24 | -- ******************************************************************** 25 | -- luacheck: ignore 611 26 | 27 | local lpeg = require "lpeg" 28 | local string = require "string" 29 | 30 | local Cf = lpeg.Cf 31 | local Cg = lpeg.Cg 32 | local Cs = lpeg.Cs 33 | local Ct = lpeg.Ct 34 | local C = lpeg.C 35 | local P = lpeg.P 36 | local R = lpeg.R 37 | local S = lpeg.S 38 | 39 | -- ******************************************************************** 40 | -- The rules here follow from RFC-2045, but don't follow the BNF exactly, 41 | -- but are instead, somewhat expanded out and transformed a bit such that 42 | -- the MIME type (such as "text/plain") will be folded to lowercase, and the 43 | -- paramter names will also be folded to lowercase, while the value will NOT 44 | -- be folded. 45 | -- 46 | -- NOTE: depending upon the RFC, the parameter value may indeed be defined 47 | -- as "case insensitive". 48 | -- ******************************************************************** 49 | 50 | local tspecials = S[=["(),/:;<=>?@[\]]=] 51 | local ichar = R"AZ" / string.lower + (R"!~" - tspecials) 52 | local itoken = Cs(ichar^1) 53 | local token = C((R" ~" - tspecials)^1) 54 | local quoted_string = P'"' * C(R(" !","#~")^0) * P'"' 55 | local value = quoted_string + token 56 | local parameters = Cf( 57 | Ct"" * (P";" * P" "^0 * Cg(itoken * P"=" * value))^0, 58 | function(acc,name,val) 59 | acc[name] = val 60 | return acc 61 | end 62 | ) 63 | local mimetype = Cs(ichar^1 * P"/" * ichar^1) 64 | 65 | return Ct(Cg(mimetype,'type') * Cg(parameters,'parameters')) 66 | -------------------------------------------------------------------------------- /rockspecs/org.conman.parsers.abnf-1.0.0-4.rockspec: -------------------------------------------------------------------------------- 1 | package = "org.conman.parsers.abnf" 2 | version = "1.0.0-4" 3 | rockspec_format = "3.0" 4 | 5 | source = 6 | { 7 | url = "https://raw.github.com/spc476/LPeg-Parsers/abnf-1.0.0/abnf.lua", 8 | md5 = "ea644703ca9b2b5b2ac87d71e4d552b0" 9 | } 10 | 11 | description = 12 | { 13 | homepage = "https://github.com/spc476/LPeg-Parsers", 14 | issues_url = "https://github.com/spc476/LPeg-Parsers/issues", 15 | maintainer = "Sean Conner ", 16 | license = "LGPL3+", 17 | summary = "The core BNF ruleset from RFC-5234", 18 | labels = { 'lpeg' }, 19 | detailed = [[ 20 | The core BNF ruleset from RFC-5234. This is used in a lot of 21 | modern RFCs, so it makes sense to break these out. 22 | ]], 23 | } 24 | 25 | dependencies = 26 | { 27 | "lua >= 5.1, <= 5.4", 28 | "lpeg >= 1.0.0", 29 | } 30 | 31 | build = 32 | { 33 | type = "none", 34 | copy_directories = {}, 35 | install = 36 | { 37 | lua = 38 | { 39 | ['org.conman.parsers.abnf'] = "abnf.lua" 40 | } 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /rockspecs/org.conman.parsers.ascii-1.0.0-2.rockspec: -------------------------------------------------------------------------------- 1 | package = "org.conman.parsers.ascii" 2 | version = "1.0.0-2" 3 | 4 | source = 5 | { 6 | url = "https://raw.github.com/spc476/LPeg-Parsers/ascii-1.0.0/ascii.lua", 7 | md5 = "52f581d91466223b4940f4d1b8360318", 8 | } 9 | 10 | description = 11 | { 12 | homepage = "https://github.com/spc476/LPeg-Parsers", 13 | maintainer = "Sean Conner ", 14 | license = "LGPL3+", 15 | summary = "LPEG expression to match valid ASCII characters", 16 | detailed = [[ 17 | LPEG expression to match valid ASCII characters, both graphic and 18 | control sets. 19 | ]] 20 | } 21 | 22 | dependencies = 23 | { 24 | "lua >= 5.1, <= 5.4", 25 | "lpeg >= 1.0.0", 26 | "org.conman.parsers.ascii.char >= 1.0.0", 27 | "org.conman.parsers.ascii.control >= 1.0.0", 28 | } 29 | 30 | build = 31 | { 32 | type = "none", 33 | copy_directories = {}, 34 | install = 35 | { 36 | lua = 37 | { 38 | ['org.conman.parsers.ascii'] = "ascii.lua" 39 | } 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /rockspecs/org.conman.parsers.ascii.char-1.0.0-2.rockspec: -------------------------------------------------------------------------------- 1 | package = "org.conman.parsers.ascii.char" 2 | version = "1.0.0-2" 3 | 4 | source = 5 | { 6 | url = "https://raw.github.com/spc476/LPeg-Parsers/asciig-1.0.0/ascii/char.lua", 7 | md5 = "c483ba9c0da62184f9f29e56fbae7dd4", 8 | } 9 | 10 | description = 11 | { 12 | homepage = "https://github.com/spc476/LPeg-Parsers", 13 | maintainer = "Sean Conner ", 14 | license = "LGPL3+", 15 | summary = "LPEG expression to match valid ASCII graphic characters", 16 | detailed = [[ 17 | LPEG expression to match valid ASCII graphic characters. Yes, this is 18 | a two line module, what of it? 19 | ]] 20 | } 21 | 22 | dependencies = 23 | { 24 | "lua >= 5.1, <= 5.4", 25 | "lpeg >= 1.0.0", 26 | } 27 | 28 | build = 29 | { 30 | type = "none", 31 | copy_directories = {}, 32 | install = 33 | { 34 | lua = 35 | { 36 | ['org.conman.parsers.ascii.char'] = "char.lua" 37 | } 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /rockspecs/org.conman.parsers.ascii.control-1.0.0-2.rockspec: -------------------------------------------------------------------------------- 1 | package = "org.conman.parsers.ascii.control" 2 | version = "1.0.0-2" 3 | 4 | source = 5 | { 6 | url = "https://raw.github.com/spc476/LPeg-Parsers/asciic-1.0.0/ascii/control.lua", 7 | md5 = "42e13275aefe9fb19bcba95a295c3207", 8 | } 9 | 10 | description = 11 | { 12 | homepage = "https://github.com/spc476/LPeg-Parsers", 13 | maintainer = "Sean Conner ", 14 | license = "LGPL3+", 15 | summary = "LPEG expression to match valid ASCII control characters", 16 | detailed = [[ 17 | LPEG expression to match valid ASCII control characters. Yes, this is 18 | a two line module, what of it? 19 | ]] 20 | } 21 | 22 | dependencies = 23 | { 24 | "lua >= 5.1, <= 5.4", 25 | "lpeg >= 1.0.0", 26 | } 27 | 28 | build = 29 | { 30 | type = "none", 31 | copy_directories = {}, 32 | install = 33 | { 34 | lua = 35 | { 36 | ['org.conman.parsers.ascii.control'] = "control.lua" 37 | } 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /rockspecs/org.conman.parsers.ascii.ctrl-1.0.0-2.rockspec: -------------------------------------------------------------------------------- 1 | package = "org.conman.parsers.ascii.ctrl" 2 | version = "1.0.0-2" 3 | 4 | source = 5 | { 6 | url = "https://raw.github.com/spc476/LPeg-Parsers/asciiC0-1.0.0/ascii/ctrl.lua", 7 | md5 = "7ee603a8d96973119c3176f1689a1b1d", 8 | } 9 | 10 | description = 11 | { 12 | homepage = "https://github.com/spc476/LPeg-Parsers", 13 | maintainer = "Sean Conner ", 14 | license = "LGPL3+", 15 | summary = "LPEG expression to return ASCII control character names", 16 | detailed = [[ 17 | LPEG expression to convert an ASCII control character to its name. 18 | ]] 19 | } 20 | 21 | dependencies = 22 | { 23 | "lua >= 5.1, <= 5.4", 24 | "lpeg >= 1.0.0", 25 | } 26 | 27 | build = 28 | { 29 | type = "none", 30 | copy_directories = {}, 31 | install = 32 | { 33 | lua = 34 | { 35 | ['org.conman.parsers.ascii.ctrl'] = "ctrl.lua" 36 | } 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /rockspecs/org.conman.parsers.email-1.2.1-1.rockspec: -------------------------------------------------------------------------------- 1 | package = "org.conman.parsers.email" 2 | version = "1.2.1-1" 3 | source = { 4 | url = "https://raw.github.com/spc476/LPeg-Parsers/email-1.2.1/email.lua", 5 | md5 = "2d0fb801171f57e7ce2443b0cfcf0964" 6 | } 7 | description = { 8 | summary = "Parse RFC-5322 based email messages", 9 | detailed = [[ 10 | Return a Lua table with the email headers parsed into individual 11 | fields. Any fields not defined are returned in a field called 12 | 'generic'; the name is the raw header name, with the value the 13 | raw value found. 14 | 15 | This will also return the character position past the email headers 16 | to facility reading in the body, if one exists. 17 | ]], 18 | homepage = "https://github.com/spc476/LPeg-Parsers", 19 | license = "LGPL3+", 20 | maintainer = "Sean Conner " 21 | } 22 | dependencies = { 23 | "lua >= 5.1, < 5.5", 24 | "lpeg >= 1.0.0, < 2.0.0" 25 | } 26 | build = { 27 | type = "none", 28 | copy_directories = {}, 29 | install = { 30 | lua = { 31 | ["org.conman.parsers.email"] = "email.lua" 32 | } 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /rockspecs/org.conman.parsers.ini-1.0.1-3.rockspec: -------------------------------------------------------------------------------- 1 | package = "org.conman.parsers.ini" 2 | version = "1.0.1-3" 3 | 4 | source = 5 | { 6 | url = "https://raw.github.com/spc476/LPeg-Parsers/ini-1.0.1/ini.lua", 7 | md5 = "73b83b44c6a64d932f344d0a6670229a", 8 | } 9 | 10 | description = 11 | { 12 | homepage = "https://github.com/spc476/LPeg-Parsers", 13 | maintainer = "Sean Conner ", 14 | license = "LGPL3+", 15 | summary = "Parse INI files into a Lua table", 16 | detailed = [[ 17 | Provides a INI file parser that returns a Lua table from a INI 18 | file. See the homepage for more details. 19 | ]] 20 | } 21 | 22 | dependencies = 23 | { 24 | "lua >= 5.1, <= 5.4", 25 | "lpeg >= 1.0.0" 26 | } 27 | 28 | build = 29 | { 30 | type = "none", 31 | copy_directories = {}, 32 | install = 33 | { 34 | lua = 35 | { 36 | ['org.conman.parsers.ini'] = "ini.lua" 37 | } 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /rockspecs/org.conman.parsers.ip-1.0.2-3.rockspec: -------------------------------------------------------------------------------- 1 | package = "org.conman.parsers.ip" 2 | version = "1.0.2-3" 3 | 4 | source = 5 | { 6 | url = "https://raw.github.com/spc476/LPeg-Parsers/ip-1.0.2/ip.lua", 7 | md5 = "3fabd84057dc0fb4bab8ceab5f85deea", 8 | } 9 | 10 | description = 11 | { 12 | homepage = "https://github.com/spc476/LPeg-Parsers", 13 | maintainer = "Sean Conner ", 14 | license = "LGPL3+", 15 | summary = "Parse IPv4/IPv6 addresses", 16 | detailed = [[ 17 | Parse an IPv4 or IPv6 address. The address is returned as binary in 18 | network byte order. 19 | ]] 20 | } 21 | 22 | dependencies = 23 | { 24 | "lua >= 5.1, <= 5.4", 25 | "lpeg >= 1.0.0", 26 | } 27 | 28 | build = 29 | { 30 | type = "none", 31 | copy_directories = {}, 32 | install = 33 | { 34 | lua = 35 | { 36 | ['org.conman.parsers.ip'] = "ip.lua" 37 | } 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /rockspecs/org.conman.parsers.ip-text-1.0.0-3.rockspec: -------------------------------------------------------------------------------- 1 | package = "org.conman.parsers.ip-text" 2 | version = "1.0.0-3" 3 | 4 | source = 5 | { 6 | url = "https://raw.github.com/spc476/LPeg-Parsers/ip-text-1.0.0/ip-text.lua", 7 | } 8 | 9 | description = 10 | { 11 | homepage = "https://github.com/spc476/LPeg-Parsers", 12 | maintainer = "Sean Conner ", 13 | license = "LGPL3+", 14 | summary = "Parse IPv4/IPv6 addresses", 15 | detailed = [[ 16 | Parse an IPv4 or IPv6 address. The address is returned as text, 17 | unlike the org.conman.parsers.ip module. 18 | ]] 19 | } 20 | 21 | dependencies = 22 | { 23 | "lua >= 5.1, <= 5.4", 24 | "lpeg >= 1.0.0", 25 | } 26 | 27 | build = 28 | { 29 | type = "none", 30 | copy_directories = {}, 31 | install = 32 | { 33 | lua = 34 | { 35 | ['org.conman.parsers.ip-text'] = "ip-text.lua" 36 | } 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /rockspecs/org.conman.parsers.iso-1.0.0-2.rockspec: -------------------------------------------------------------------------------- 1 | package = "org.conman.parsers.iso" 2 | version = "1.0.0-2" 3 | 4 | source = 5 | { 6 | url = "https://raw.github.com/spc476/LPeg-Parsers/iso-1.0.0/iso.lua", 7 | md5 = "6806dbbc83dee708c42720081785bacd", 8 | } 9 | 10 | description = 11 | { 12 | homepage = "https://github.com/spc476/LPeg-Parsers", 13 | maintainer = "Sean Conner ", 14 | license = "LGPL3+", 15 | summary = "LPEG expression to match valid ISO characters", 16 | detailed = [[ 17 | LPEG expression to match valid ISO characters, both graphic and 18 | control sets, for example, ISO-8859-1. This module handles *only* 19 | the characters not defined by ASCII. If you need to parse both 20 | ASCII and ISO: 21 | 22 | char = require "org.conman.parsers.iso" 23 | + require "org.conman.parsers.ascii" 24 | 25 | NOTE: The ISO control characters may match more than a single 26 | character. For example, the commonly called ANSI codes (which are 27 | not ANSI but ISO) like "[32;40m" will be matched as one unit. 28 | ]] 29 | } 30 | 31 | dependencies = 32 | { 33 | "lua >= 5,1, <= 5.4", 34 | "lpeg >= 1.0.0", 35 | "org.conman.parsers.iso.char >= 1.0.0", 36 | "org.conman.parsers.iso.control >= 1.0.0", 37 | "org.conman.parsers.ascii.char >= 1.0.0", 38 | "org.conman.parsers.ascii.control >= 1.0.0", 39 | } 40 | 41 | build = 42 | { 43 | type = "none", 44 | copy_directories = {}, 45 | install = 46 | { 47 | lua = 48 | { 49 | ['org.conman.parsers.iso'] = "iso.lua" 50 | } 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /rockspecs/org.conman.parsers.iso.char-1.0.0-2.rockspec: -------------------------------------------------------------------------------- 1 | package = "org.conman.parsers.iso.char" 2 | version = "1.0.0-2" 3 | 4 | source = 5 | { 6 | url = "https://raw.github.com/spc476/LPeg-Parsers/isog-1.0.0/iso/char.lua", 7 | md5 = "0ea3af4124f7c7c92d57ede90a2bbc86", 8 | } 9 | 10 | description = 11 | { 12 | homepage = "https://github.com/spc476/LPeg-Parsers", 13 | maintainer = "Sean Conner ", 14 | license = "LGPL3+", 15 | summary = "LPEG expression to match valid ISO graphic characters", 16 | detailed = [[ 17 | LPEG expression to match valid ISO graphic characters, for example. 18 | those of ISO-8850-1. This *does not* include matching those 19 | characters defined by ASCII. To parse both ASCII and ISO 20 | extensions: 21 | 22 | char = require "org.conman.parsers.iso.char" 23 | + require "org.conman.parsers.ascii.char" 24 | ]] 25 | } 26 | 27 | dependencies = 28 | { 29 | "lua >= 5.1, <= 5.4", 30 | "lpeg >= 1.0.0", 31 | } 32 | 33 | build = 34 | { 35 | type = "none", 36 | copy_directories = {}, 37 | install = 38 | { 39 | lua = 40 | { 41 | ['org.conman.parsers.iso.char'] = "char.lua" 42 | } 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /rockspecs/org.conman.parsers.iso.control-1.0.0-2.rockspec: -------------------------------------------------------------------------------- 1 | package = "org.conman.parsers.iso.control" 2 | version = "1.0.0-2" 3 | 4 | source = 5 | { 6 | url = "https://raw.github.com/spc476/LPeg-Parsers/isoc-1.0.0/iso/control.lua", 7 | md5 = "c8efe7bbbfc92dd05b9ad71bede5771a", 8 | } 9 | 10 | description = 11 | { 12 | homepage = "https://github.com/spc476/LPeg-Parsers", 13 | maintainer = "Sean Conner ", 14 | license = "LGPL3+", 15 | summary = "LPEG expression to match valid ISO control characters", 16 | detailed = [[ 17 | This is an LPEG expression that matches a valid ISO control 18 | character or control character sequence. For example, this will 19 | match the following ISO control sequence: 20 | 21 | [32;40m 22 | 23 | To match the ISO *and* the ASCII control sets: 24 | 25 | control = require "org.conman.parsers.ascii.control" 26 | + require "org.conman.parsers.iso.control" 27 | ]] 28 | } 29 | 30 | dependencies = 31 | { 32 | "lua >= 5.1, <= 5.4", 33 | "lpeg >= 1.0.0", 34 | "org.conman.parsers.iso.char >= 1.0.0", 35 | "org.conman.parsers.ascii.char >= 1.0.0", 36 | } 37 | 38 | build = 39 | { 40 | type = "none", 41 | copy_directories = {}, 42 | install = 43 | { 44 | lua = 45 | { 46 | ['org.conman.parsers.iso.control'] = "control.lua" 47 | } 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /rockspecs/org.conman.parsers.iso.ctrl-1.0.0-2.rockspec: -------------------------------------------------------------------------------- 1 | package = "org.conman.parsers.iso.ctrl" 2 | version = "1.0.0-2" 3 | 4 | source = 5 | { 6 | url = "https://raw.github.com/spc476/LPeg-Parsers/isoC1-1.0.0/iso/ctrl.lua", 7 | md5 = "c3a02b260477491a8004821697956aa3", 8 | } 9 | 10 | description = 11 | { 12 | homepage = "https://github.com/spc476/LPeg-Parsers", 13 | maintainer = "Sean Conner ", 14 | license = "LGPL3+", 15 | summary = "LPEG expression to return ISO control character names and associated data", 16 | detailed = [[ 17 | This returns an LPEG expression to convert an ISO control character to its name and 18 | any associated data. For example, the following sequence: 19 | 20 | [32;40m 21 | 22 | will return "SGR" and a table with two elements, 32 and 40. See the 23 | ECMA-48 standard for more information about ISO control codes. 24 | ]] 25 | } 26 | 27 | dependencies = 28 | { 29 | "lua >= 5.1, <= 5.4", 30 | "lpeg >= 1.0.0", 31 | "org.conman.parsers.iso.char >= 1.0.0", 32 | "org.conman.parsers.ascii.char >= 1.0.0", 33 | } 34 | 35 | build = 36 | { 37 | type = "none", 38 | copy_directories = {}, 39 | install = 40 | { 41 | lua = 42 | { 43 | ['org.conman.parsers.iso.ctrl'] = "ctrl.lua" 44 | } 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /rockspecs/org.conman.parsers.json-1.1.1-3.rockspec: -------------------------------------------------------------------------------- 1 | package = "org.conman.parsers.json" 2 | version = "1.1.1-3" 3 | 4 | source = 5 | { 6 | url = "https://raw.github.com/spc476/LPeg-Parsers/json-1.1.1/json.lua", 7 | } 8 | 9 | description = 10 | { 11 | homepage = "https://github.com/spc476/LPeg-Parsers", 12 | maintainer = "Sean Conner ", 13 | license = "LGPL3+", 14 | summary = "Parse JSON files", 15 | detailed = [[ 16 | Parse a JSON file into a Lua table. This supports UTF-8 encoded 17 | JSON files. 18 | ]] 19 | } 20 | 21 | dependencies = 22 | { 23 | "lua >= 5.1, <= 5.4", 24 | "lpeg >= 1.0.0", 25 | } 26 | 27 | build = 28 | { 29 | type = "none", 30 | copy_directories = {}, 31 | install = 32 | { 33 | lua = 34 | { 35 | ['org.conman.parsers.json'] = "json.lua" 36 | } 37 | } 38 | } 39 | 40 | -------------------------------------------------------------------------------- /rockspecs/org.conman.parsers.jsons-1.0.7-3.rockspec: -------------------------------------------------------------------------------- 1 | package = "org.conman.parsers.jsons" 2 | version = "1.0.7-3" 3 | 4 | source = 5 | { 6 | url = "https://raw.github.com/spc476/LPeg-Parsers/jsons-1.0.7/jsons.lua", 7 | md5 = "9917bb2705100bcfc772a0555de9aa17", 8 | } 9 | 10 | description = 11 | { 12 | homepage = "https://github.com/spc476/LPeg-Parsers", 13 | maintainer = "Sean Conner ", 14 | license = "LGPL3+", 15 | summary = "Parse JSON files", 16 | detailed = [[ 17 | Parse a JSON file into a Lua table. This supports UTF-8 encoded 18 | JSON files, and can handle much larger files than 19 | org.conman.parsers.json. You can also stream data into the parser 20 | via a function instead of passing in the entire JSON dataset as a 21 | string. 22 | ]] 23 | } 24 | 25 | dependencies = 26 | { 27 | "lua >= 5.1, <= 5.4", 28 | "lpeg >= 1.0.0", 29 | } 30 | 31 | build = 32 | { 33 | type = "none", 34 | copy_directories = {}, 35 | install = 36 | { 37 | lua = 38 | { 39 | ['org.conman.parsers.jsons'] = "jsons.lua" 40 | } 41 | } 42 | } 43 | 44 | -------------------------------------------------------------------------------- /rockspecs/org.conman.parsers.mimetype-1.0.0-1.rockspec: -------------------------------------------------------------------------------- 1 | package = "org.conman.parsers.mimetype" 2 | version = "1.0.0-1" 3 | rockspec_format = "3.0" 4 | 5 | source = 6 | { 7 | url = "https://raw.github.com/spc476/LPeg-Parsers/mimetype-1.0.0/mimetype.lua", 8 | md5 = "8f00bb5a3c4993dba3e1cdfc5be12631", 9 | } 10 | 11 | description = 12 | { 13 | homepage = "https://github.com/spc476/LPeg-Parsers", 14 | issues_url = "https://github.com/spc476/LPeg-Parsers/issues", 15 | maintainer = "Sean Conner ", 16 | license = "LGPL3+", 17 | summary = "Parse a MIME type, which can include parameters.", 18 | labels = { 'lpeg' }, 19 | detailed = [[ 20 | Parse the MIME type from RFC-2045. This is the MIME type itself, 21 | not a complete header. 22 | ]], 23 | } 24 | 25 | dependencies = 26 | { 27 | "lua >= 5.1, <= 5.4", 28 | "lpeg >= 1.0.0", 29 | } 30 | 31 | build = 32 | { 33 | type = "none", 34 | copy_directories = {}, 35 | install = 36 | { 37 | lua = 38 | { 39 | ['org.conman.parsers.mimetype'] = "mimetype.lua" 40 | } 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /rockspecs/org.conman.parsers.soundex-1.0.1-1.rockspec: -------------------------------------------------------------------------------- 1 | package = "org.conman.parsers.soundex" 2 | version = "1.0.1-1" 3 | source = { 4 | url = "https://raw.github.com/spc476/LPeg-Parsers/soundex-1.0.1/soundex.lua", 5 | md5 = "1109978152b93c3d267fd7c1f1fef803" 6 | } 7 | description = { 8 | summary = "Generate the Soundex value for a given word", 9 | detailed = [[ 10 | This is an LPEG expression that will return the Soundex value for a given word or name. 11 | ]], 12 | homepage = "https://github.com/spc476/LPeg-Parsers", 13 | license = "LGPL3+", 14 | maintainer = "Sean Conner " 15 | } 16 | dependencies = { 17 | "lua >= 5.1, <= 5.4", 18 | "lpeg >= 1.0.0" 19 | } 20 | build = { 21 | type = "none", 22 | copy_directory = {}, 23 | install = { 24 | lua = { 25 | ["org.conman.parsers.soundex"] = "soundex.lua" 26 | } 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /rockspecs/org.conman.parsers.strftime-1.0.1-1.rockspec: -------------------------------------------------------------------------------- 1 | package = "org.conman.parsers.strftime" 2 | version = "1.0.1-1" 3 | 4 | source = 5 | { 6 | url = "https://raw.github.com/spc476/LPeg-Parsers/strf-1.0.1/strftime.lua", 7 | } 8 | 9 | description = 10 | { 11 | homepage = "https://github.com/spc476/LPeg-Parsers", 12 | maintainer = "Sean Conner ", 13 | license = "LGPL3+", 14 | summary = "Generate LPeg to parse strftime() format strings", 15 | detailed = [[ 16 | Given a format string for strftime() (or os.date() in Lua), generate 17 | LPeg code to parse a string of said format. 18 | ]] 19 | } 20 | 21 | dependencies = 22 | { 23 | "lua >= 5.1, <= 5.4", 24 | "lpeg >= 1.0.0", 25 | } 26 | 27 | build = 28 | { 29 | type = "none", 30 | copy_directories = {}, 31 | install = 32 | { 33 | lua = 34 | { 35 | ['org.conman.parsers.strftime'] = "strftime.lua" 36 | } 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /rockspecs/org.conman.parsers.url-2.0.3-3.rockspec: -------------------------------------------------------------------------------- 1 | package = "org.conman.parsers.url" 2 | version = "2.0.3-3" 3 | 4 | source = 5 | { 6 | url = "https://raw.github.com/spc476/LPeg-Parsers/url-2.0.3/url.lua", 7 | md5 = "e34da71c02b01331854804c7f5558e91", 8 | } 9 | 10 | description = 11 | { 12 | homepage = "https://github.com/spc476/LPeg-Parsers", 13 | maintainer = "Sean Conner ", 14 | license = "LGPL3+", 15 | summary = [[Parse "http:", "https:", "file:" and "ftp:" URLs]], 16 | detailed = [[ 17 | Parse "http:", "https:", "file:" and "ftp:" URLs into a Lua table. 18 | It can handle other URLs but further processing may be required if 19 | so. 20 | ]], 21 | } 22 | 23 | dependencies = 24 | { 25 | "lua >= 5.1, <= 5.4", 26 | "lpeg >= 1.0.0", 27 | "org.conman.parsers.abnf >= 1.0.0", 28 | "org.conman.parsers.ip-text >= 1.0.0", 29 | } 30 | 31 | build = 32 | { 33 | type = "none", 34 | copy_directories = {}, 35 | install = 36 | { 37 | lua = 38 | { 39 | ['org.conman.parsers.url'] = "url.lua" 40 | } 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /rockspecs/org.conman.parsers.url.gopher-2.0.0-3.rockspec: -------------------------------------------------------------------------------- 1 | package = "org.conman.parsers.url.gopher" 2 | version = "2.0.0-3" 3 | 4 | source = 5 | { 6 | url = "https://raw.github.com/spc476/LPeg-Parsers/urlgopher-2.0.0/url/gopher.lua", 7 | md5 = "072ac6a2f1b8370128a1c0bdfd80ec66", 8 | } 9 | 10 | description = 11 | { 12 | homepage = "https://github.com/spc476/LPeg-Parsers", 13 | maintainer = "Sean Conner ", 14 | license = "LGPL3+", 15 | summary = [[Parse "gopher:" URLs]], 16 | detailed = [[ 17 | Parse "gopher:" URLs into a Lua table. This can only handle 18 | "gopher:" URLs. If you need to parse more than just "gopher:" URLs, 19 | then you can include, for example, "org.conman.parsers.url.url" and 20 | merge the two: 21 | 22 | gopher = require "org.conman.parsers.url.gopher" 23 | 24 | url = require "org.conman.parsers.url.url" 25 | 26 | url = gopher + url 27 | 28 | It really is that simple. 29 | ]], 30 | } 31 | 32 | dependencies = 33 | { 34 | "lua >= 5,1, <= 5.4", 35 | "lpeg >= 1.0.0", 36 | "org.conman.parsers.abnf >= 1.0.0", 37 | "org.conman.parsers.ip-text >= 1.0.0", 38 | "org.conman.const.gopher-types >= 1.0.0", 39 | } 40 | 41 | build = 42 | { 43 | type = "none", 44 | copy_directories = {}, 45 | install = 46 | { 47 | lua = 48 | { 49 | ['org.conman.parsers.url.gopher'] = "gopher.lua" 50 | } 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /rockspecs/org.conman.parsers.url.siptel-1.0.0-3.rockspec: -------------------------------------------------------------------------------- 1 | package = "org.conman.parsers.url.siptel" 2 | version = "1.0.0-3" 3 | 4 | source = 5 | { 6 | url = "https://raw.github.com/spc476/LPeg-Parsers/urlsiptel-1.0.0/url/siptel.lua", 7 | md5 = "4ef7aa192765be6d33b8af08bbfc3205", 8 | } 9 | 10 | description = 11 | { 12 | homepage = "https://github.com/spc476/LPeg-Parsers", 13 | maintainer = "Sean Conner ", 14 | license = "LGPL3+", 15 | summary = [[Parse sip:, sips: and tel: URIs]], 16 | detailed = [[ 17 | Parse sip:, sips: and tel: URIs into a Lua table. Given that the 18 | two are intertwined semantically, both are included in this module. 19 | ]], 20 | } 21 | 22 | dependencies = 23 | { 24 | "lua >= 5,1, <= 5.4", 25 | "lpeg >= 1.0.0", 26 | "org.conman.parsers.abnf >= 1.0.0", 27 | "org.conman.parsers.ip-text >= 1.0.0", 28 | } 29 | 30 | build = 31 | { 32 | type = "none", 33 | copy_directories = {}, 34 | install = 35 | { 36 | lua = 37 | { 38 | ['org.conman.parsers.url.siptel'] = "siptel.lua" 39 | } 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /rockspecs/org.conman.parsers.utf8-1.0.0-2.rockspec: -------------------------------------------------------------------------------- 1 | package = "org.conman.parsers.utf8" 2 | version = "1.0.0-2" 3 | 4 | source = 5 | { 6 | url = "https://raw.github.com/spc476/LPeg-Parsers/utf8-1.0.0/utf8.lua", 7 | md5 = "2fcf92d0bf98b2d3c2337fafdc191126", 8 | } 9 | 10 | description = 11 | { 12 | homepage = "https://github.com/spc476/LPeg-Parsers", 13 | maintainer = "Sean Conner ", 14 | license = "LGPL3+", 15 | summary = "LPEG expression to match valid ISO characters", 16 | detailed = [[ 17 | LPEG expression to match valid UTF-8 characters, both graphic and 18 | control sets. This module handles *only* the characters not defined 19 | by ASCII. If you need to parse both ASCII and UTF-8: 20 | 21 | char = require "org.conman.parsers.utf8" 22 | + require "org.conman.parsers.ascii" 23 | 24 | NOTE: The UTF-8 control characters may match more than a single 25 | character. For example, the commonly called ANSI codes (which are 26 | not ANSI but ISO) like "[32;40m" will be matched as one unit. 27 | ]] 28 | } 29 | 30 | dependencies = 31 | { 32 | "lua >= 5.1, <= 5.4", 33 | "lpeg >= 1.0.0", 34 | "org.conman.parsers.utf8.char >= 1.0.0", 35 | "org.conman.parsers.utf8.control >= 1.0.0", 36 | "org.conman.parsers.ascii.char >= 1.0.0", 37 | "org.conman.parsers.ascii.control >= 1.0.0", 38 | } 39 | 40 | build = 41 | { 42 | type = "none", 43 | copy_directories = {}, 44 | install = 45 | { 46 | lua = 47 | { 48 | ['org.conman.parsers.utf8'] = "utf8.lua" 49 | } 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /rockspecs/org.conman.parsers.utf8.char-1.0.0-2.rockspec: -------------------------------------------------------------------------------- 1 | package = "org.conman.parsers.utf8.char" 2 | version = "1.0.0-2" 3 | 4 | source = 5 | { 6 | url = "https://raw.github.com/spc476/LPeg-Parsers/utf8g-1.0.0/utf8/char.lua", 7 | md5 = "b10ba6dd8ec9f711958960c102050743", 8 | } 9 | 10 | description = 11 | { 12 | homepage = "https://github.com/spc476/LPeg-Parsers", 13 | maintainer = "Sean Conner ", 14 | license = "LGPL3+", 15 | summary = "LPEG expression to match valid ISO graphic characters", 16 | detailed = [[ 17 | LPEG expression to match valid UTF-8 graphic characters. This *does 18 | not* include matching those characters defined by ASCII. To parse 19 | both ASCII and UTF-8 extensions: 20 | 21 | char = require "org.conman.parsers.utf8.char" 22 | + require "org.conman.parsers.ascii.char" 23 | ]] 24 | } 25 | 26 | dependencies = 27 | { 28 | "lua >= 5.1, <= 5.4", 29 | "lpeg >= 1.0.0", 30 | } 31 | 32 | build = 33 | { 34 | type = "none", 35 | copy_directories = {}, 36 | install = 37 | { 38 | lua = 39 | { 40 | ['org.conman.parsers.utf8.char'] = "char.lua" 41 | } 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /rockspecs/org.conman.parsers.utf8.control-1.0.0-2.rockspec: -------------------------------------------------------------------------------- 1 | package = "org.conman.parsers.utf8.control" 2 | version = "1.0.0-2" 3 | 4 | source = 5 | { 6 | url = "https://raw.github.com/spc476/LPeg-Parsers/utf8c-1.0.0/utf8/control.lua", 7 | md5 = "46b93c198cbc0471a94a94e298f7d910", 8 | } 9 | 10 | description = 11 | { 12 | homepage = "https://github.com/spc476/LPeg-Parsers", 13 | maintainer = "Sean Conner ", 14 | license = "LGPL3+", 15 | summary = "LPEG expression to match valid ISO control characters", 16 | detailed = [[ 17 | This is an LPEG expression that matches a valid UTF-8 control 18 | character or control character sequence. For example, this will 19 | match the following ISO control sequence: 20 | 21 | [32;40m 22 | 23 | To match the UTF-8 *and* the ASCII control sets: 24 | 25 | control = require "org.conman.parsers.ascii.control" 26 | + require "org.conman.parsers.utf8.control" 27 | ]] 28 | } 29 | 30 | dependencies = 31 | { 32 | "lua >= 5.1, <= 5.4", 33 | "lpeg >= 1.0.0", 34 | "org.conman.parsers.utf8.char >= 1.0.0", 35 | "org.conman.parsers.ascii.char >= 1.0.0", 36 | } 37 | 38 | build = 39 | { 40 | type = "none", 41 | copy_directories = {}, 42 | install = 43 | { 44 | lua = 45 | { 46 | ['org.conman.parsers.utf8.control'] = "control.lua" 47 | } 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /rockspecs/org.conman.parsers.utf8.ctrl-1.0.0-2.rockspec: -------------------------------------------------------------------------------- 1 | package = "org.conman.parsers.utf8.ctrl" 2 | version = "1.0.0-2" 3 | 4 | source = 5 | { 6 | url = "https://raw.github.com/spc476/LPeg-Parsers/utf8C1-1.0.0/utf8/ctrl.lua", 7 | md5 = "bf977b1fafd0fe7a48defd3f08f7dbcc", 8 | } 9 | 10 | description = 11 | { 12 | homepage = "https://github.com/spc476/LPeg-Parsers", 13 | maintainer = "Sean Conner ", 14 | license = "LGPL3+", 15 | summary = "LPEG expression to return UTF-8 control character names and associated data", 16 | detailed = [[ 17 | This returns an LPEG expression to convert a UTF-8 control character to its name and 18 | any associated data. For example, the following sequence: 19 | 20 | [32;40m 21 | 22 | will return "SGR" and a table with two elements, 32 and 40. See the 23 | ECMA-48 standard for more information about these control codes. 24 | ]] 25 | } 26 | 27 | dependencies = 28 | { 29 | "lua >= 5.1, <= 5.4", 30 | "lpeg >= 1.0.0", 31 | "org.conman.parsers.utf8.char >= 1.0.0", 32 | "org.conman.parsers.ascii.char >= 1.0.0", 33 | } 34 | 35 | build = 36 | { 37 | type = "none", 38 | copy_directories = {}, 39 | install = 40 | { 41 | lua = 42 | { 43 | ['org.conman.parsers.utf8.ctrl'] = "ctrl.lua" 44 | } 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /soundex.lua: -------------------------------------------------------------------------------- 1 | -- *************************************************************** 2 | -- 3 | -- Copyright 2016 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 | -- https://www.archives.gov/research/census/soundex.html 22 | -- 23 | -- luacheck: ignore 611 24 | 25 | local lpeg = require "lpeg" 26 | 27 | return lpeg.P { 28 | 'soundex', 29 | ignore = lpeg.S"AEIOUWYHaeiouwyh'"^0, 30 | skip = lpeg.S"HWhw"^1, 31 | cs1 = lpeg.S"BFPVbfpv"^1, 32 | cs2 = lpeg.S"CGJKQSXZcgjkqsxz"^1, 33 | cs3 = lpeg.S"DTdt"^1, 34 | cs4 = lpeg.S"Ll"^1, 35 | cs5 = lpeg.S"MNmn"^1, 36 | cs6 = lpeg.S"Rr"^1, 37 | initial = (lpeg.V"cs1" + lpeg.V"cs2" + lpeg.V"cs3" + lpeg.V"cs4" + lpeg.V"cs5" + lpeg.V"cs6" + lpeg.P(1)) 38 | / function(c) return c:sub(1,1):upper() end, 39 | keep = lpeg.V"cs1" * (lpeg.V"skip" * lpeg.V"cs1")^-1 * lpeg.Cc "1" 40 | + lpeg.V"cs2" * (lpeg.V"skip" * lpeg.V"cs2")^-1 * lpeg.Cc "2" 41 | + lpeg.V"cs3" * (lpeg.V"skip" * lpeg.V"cs3")^-1 * lpeg.Cc "3" 42 | + lpeg.V"cs4" * (lpeg.V"skip" * lpeg.V"cs4")^-1 * lpeg.Cc "4" 43 | + lpeg.V"cs5" * (lpeg.V"skip" * lpeg.V"cs5")^-1 * lpeg.Cc "5" 44 | + lpeg.V"cs6" * (lpeg.V"skip" * lpeg.V"cs6")^-1 * lpeg.Cc "6" 45 | + lpeg.Cc "0", 46 | use = lpeg.V"ignore" * lpeg.V"keep", 47 | soundex = lpeg.Cf(lpeg.V"initial" * lpeg.V"use" * lpeg.V"use" * lpeg.V"use",function(a,c) return a..c end), 48 | } 49 | -------------------------------------------------------------------------------- /strftime.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 | local os = require "os" 24 | local lpeg = require "lpeg" 25 | 26 | local tonumber = tonumber 27 | local error = error 28 | local string = string 29 | 30 | local Cmt = lpeg.Cmt 31 | local Cg = lpeg.Cg 32 | local Ct = lpeg.Ct 33 | local Cf = lpeg.Cf 34 | local Cs = lpeg.Cs 35 | local C = lpeg.C 36 | local P = lpeg.P 37 | local S = lpeg.S 38 | local R = lpeg.R 39 | 40 | -- *********************************************************************** 41 | -- The following could be done easier and simpler with nl_langinfo(), 42 | -- but that isn't portable (being a GNU extension). This *is* portable, 43 | -- although we cannot get the formats used for "%c", "%x" or "%X". 44 | -- *********************************************************************** 45 | 46 | local short_months = {} 47 | local long_months = {} 48 | local short_days = {} 49 | local long_days = {} 50 | local am_pm = {} 51 | 52 | do 53 | local key 54 | local now = { year = 2013 , month = 1 , day = 1 , hour = 0 } 55 | 56 | for m = 1 , 12 do 57 | now.month = m 58 | key = os.date("%b", os.time(now)) 59 | short_months[key] = m 60 | key = os.date("%B", os.time(now)) 61 | long_months[key] = m 62 | end 63 | 64 | for d = 1 , 7 do 65 | now.day = d 66 | key = os.date("%a", os.time(now)) 67 | short_days[key] = d 68 | key = os.date("%A", os.time(now)) 69 | long_days[key] = d 70 | end 71 | 72 | now.hour = 0 73 | key = os.date("%p", os.time(now)) 74 | am_pm[key] = 0 75 | 76 | am_pm[key:lower()] = 0 -- GNU extension 77 | 78 | now.hour = 12 79 | key = os.date("%p", os.time(now)) 80 | am_pm[key] = 12 81 | 82 | am_pm[key:lower()] = 12 -- GNU extension 83 | 84 | end 85 | 86 | -- ******************************************************************** 87 | 88 | local function chkrange(min,max) 89 | return function(_,position,capture) 90 | local val = tonumber(capture) 91 | if val < min or val > max then 92 | return false 93 | else 94 | return position,val 95 | end 96 | end 97 | end 98 | 99 | local utf8c = R"\128\191" 100 | local utf8 = R"\192\207" * utf8c 101 | + R"\208\223" * utf8c * utf8c 102 | + R"\224\247" * utf8c * utf8c * utf8c 103 | + R"\248\251" * utf8c * utf8c * utf8c * utf8c 104 | + R"\252\253" * utf8c * utf8c * utf8c * utf8c * utf8c 105 | local char = R("AZ","az") + utf8 106 | local digit = R"09" 107 | 108 | local dday = Cmt(digit * digit, chkrange(1, 31)) 109 | local d24hour = Cmt(digit * digit, chkrange(0, 23)) 110 | local d12hour = Cmt(digit * digit, chkrange(1, 12)) 111 | local ddyear = Cmt(digit * digit * digit,chkrange(1,366)) 112 | local dmonth = Cmt(digit * digit, chkrange(1, 12)) 113 | local dminute = Cmt(digit * digit, chkrange(0, 59)) 114 | local dsecond = Cmt(digit * digit, chkrange(0, 61)) 115 | local dweeknum = Cmt(digit * digit, chkrange(0, 53)) 116 | local dweek = Cmt(digit, chkrange(0, 6)) 117 | local d2year = (digit * digit) / function(c) return c + 1900 end 118 | local d4year = (digit * digit * digit * digit) / tonumber 119 | local number = (S"-+" * digit * digit * digit * digit) 120 | local dweek1 = Cmt(digit, function(_,position,capture) 121 | local v = tonumber(capture) 122 | if v < 1 or v > 7 then 123 | return false 124 | else 125 | if v == 7 then 126 | v = 0 127 | end 128 | return position,v 129 | end 130 | end) 131 | 132 | -- ******************************************************************** 133 | 134 | local oct = R"07" 135 | local hex = R("09","AF","af") 136 | local normal = C(P(1) - (P[[\]] + P"%")) 137 | local escaped = P[[\n]] / "\n" 138 | + P[[\t]] / "\t" 139 | + P[[\v]] / "\v" 140 | + P[[\b]] / "\b" 141 | + P[[\r]] / "\r" 142 | + P[[\f]] / "\f" 143 | + P[[\a]] / "\a" 144 | + P[[\\]] / "\\" 145 | + P[[\?]] / "?" 146 | + P[[\']] / "'" 147 | + P[[\"]] / '"' 148 | + P[[\]] * C(oct * oct * oct) / function(c) return tonumber(c,8) end 149 | + P[[\x]] * C(hex * hex) / function(c) return tonumber(c,16) end 150 | local text = Cs((escaped + normal)^1) 151 | / function(c) return P(c) end 152 | 153 | -- ------------------------------------------------------------------- 154 | 155 | local directives = P"a" / function() 156 | return Cg(char^1 / short_days,"wday") 157 | end 158 | 159 | + P"A" / function() 160 | return Cg(char^1 / long_days,"wday") 161 | end 162 | 163 | + P"b" / function() 164 | return Cg(char^1 / short_months,"month") 165 | end 166 | 167 | + P"B" / function() 168 | return Cg(char^1 / long_months,"month") 169 | end 170 | 171 | + P"c" / function() 172 | error("%c format specifier not supported") 173 | end 174 | 175 | + P"d" / function() 176 | return Cg(dday,"day") 177 | end 178 | 179 | + P"H" / function() 180 | return Cg(d24hour,"hour") 181 | end 182 | 183 | + P"I" / function() 184 | return Cg(d12hour,"hour") 185 | end 186 | 187 | + P"j" / function() 188 | return Cg(ddyear,"yday") 189 | end 190 | 191 | + P"m" / function() 192 | return Cg(dmonth,"month") 193 | end 194 | 195 | + P"M" / function() 196 | return Cg(dminute,"min") 197 | end 198 | 199 | + P"p" / function() 200 | return Cg(char^1 / am_pm,"pm") 201 | end 202 | 203 | + P"S" / function() 204 | return Cg(dsecond,"sec") 205 | end 206 | 207 | + P"U" / function() 208 | return Cg(dweeknum,"weeknums") 209 | end 210 | 211 | + P"w" / function() 212 | return Cg(dweek,"wday") 213 | end 214 | 215 | + P"W" / function() 216 | return Cg(dweeknum,"weeknumm") 217 | end 218 | 219 | + P"x" / function() 220 | error("%x format specifier not supported") 221 | end 222 | 223 | + P"X" / function() 224 | error("%X format specifier not supported") 225 | end 226 | 227 | + P"y" / function() 228 | return Cg(d2year,"year") 229 | end 230 | 231 | + P"Y" / function() 232 | return Cg(d4year,"year") 233 | end 234 | 235 | + P"Z" / function() 236 | return Cg(char^1,"zone") 237 | end 238 | 239 | + P"%" / function() 240 | return P"%" 241 | end 242 | 243 | -- ------------------------------------------------------------------- 244 | -- C99 extensions 245 | -- ------------------------------------------------------------------- 246 | 247 | + P"C" / function() 248 | return Cg(d2year,"year") 249 | end 250 | 251 | 252 | + P"D" / function() 253 | return Cg(dmonth,"month") * P"/" 254 | * Cg(dday,"day") * P"/" 255 | * Cg(d2year,"year") 256 | end 257 | 258 | + P"e" / function() 259 | return P" "^-1 260 | * Cg(Cmt(digit^1,chkrange(1,31)),"day") 261 | end 262 | 263 | + P"F" / function() 264 | return Cg(d4year,"year") * P"-" 265 | * Cg(dmonth,"month") * P"-" 266 | * Cg(dday,"day") 267 | end 268 | 269 | + P"g" / function() 270 | return Cg(d2year,"year") 271 | end 272 | 273 | + P"G" / function() 274 | return Cg(d4year,"year") 275 | end 276 | 277 | + P"h" / function() 278 | return Cg(char^1 / short_months,"month") 279 | end 280 | 281 | + P"n" / function() 282 | return P"\n" 283 | end 284 | 285 | + P"r" / function() 286 | return Cg(d12hour,"hour") * P":" 287 | * Cg(dminute,"min") * P":" 288 | * Cg(dsecond,"sec") * P" " 289 | * Cg(char^1 / am_pm,"pm") 290 | end 291 | 292 | + P"R" / function() 293 | return Cg(d24hour,"hour") * P":" 294 | * Cg(dminute,"min") 295 | end 296 | 297 | + P"t" / function() 298 | return P"\t" 299 | end 300 | 301 | + P"T" / function() 302 | return Cg(d24hour,"hour") * P":" 303 | * Cg(dminute,"min") * P":" 304 | * Cg(dsecond,"sec") 305 | end 306 | 307 | + P"u" / function() 308 | return Cg(dweek1,"wday") 309 | end 310 | 311 | + P"V" / function() 312 | return Cg(dweeknum,"weeknumm4") 313 | end 314 | 315 | + P"z" / function() 316 | return Cg(number,"zone") 317 | end 318 | 319 | + P"E" / function() 320 | error("%E format modifier not supported") 321 | end 322 | 323 | + P"O" / function() 324 | error("%O format modifier not supported") 325 | end 326 | 327 | -- ------------------------------------------------------------------- 328 | -- others 329 | -- ------------------------------------------------------------------- 330 | 331 | + P"k" / function() 332 | return P" "^-1 333 | * Cg(Cmt(digit^1,chkrange(1,23)),"hour") 334 | end 335 | 336 | + P"l" / function() 337 | return P" "^-1 338 | * Cg(Cmt(digit^1,chkrange(1,12)),"hour") 339 | end 340 | 341 | + P"P" / function() 342 | return Cg(char^1 / am_pm,"pm") 343 | end 344 | 345 | + P"s" / function() 346 | return Cg(digit^1 / tonumber,"epoch") 347 | end 348 | 349 | + P"+" / function() 350 | error("%+ format specifier not supported") 351 | end 352 | 353 | -- ------------------------------------------------------------------- 354 | -- Catch all 355 | -- ------------------------------------------------------------------- 356 | 357 | + P(1) / function(c) 358 | error(string.format("%%%s format specifier not supported",c)) 359 | end 360 | 361 | local directive = P"%" * directives 362 | 363 | return Cf((text + directive)^0,function(a,b) return a * b end) 364 | / function(c) 365 | return Ct(c) 366 | end 367 | -------------------------------------------------------------------------------- /url.lua: -------------------------------------------------------------------------------- 1 | -- *************************************************************** 2 | -- 3 | -- Copyright 2016 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 | local ip = require "org.conman.parsers.ip-text" 24 | local abnf = require "org.conman.parsers.abnf" 25 | local lpeg = require "lpeg" 26 | local re = require "re" 27 | 28 | -- ************************************************************************ 29 | -- RFC-3986 RFC-6874 RFC-7320 30 | -- ************************************************************************ 31 | 32 | local G = --[[ lpeg/re ]] [[ 33 | 34 | URI_reference <- {| URI / relative_ref |} 35 | URI <- scheme ':' hier_part ('?' query)? ('#' fragment)? 36 | 37 | 38 | scheme <- {:scheme: 'https' & ':' :} {:port: %p443 :} 39 | / {:scheme: 'http' & ':' :} {:port: %p80 :} 40 | / {:scheme: 'ftp' & ':' :} {:port: %p21 :} 41 | / {:scheme: 'gemini' & ':' :} {:port: %p1965 :} 42 | / {:scheme: 'file' & ':' :} 43 | / {:scheme: %ALPHA (%ALPHA / %DIGIT / '+' / '-' / '.')* :} 44 | 45 | hier_part <- '//' authority {:path: path_abempty :} 46 | / {:path: path_absolute :} 47 | / {:path: path_rootless :} 48 | / {:path: path_empty :} 49 | 50 | relative_ref <- relative_part ('?' query)? ('#' fragment)? 51 | 52 | relative_part <- '//' authority {:path: path_abempty :} 53 | / {:path: path_absolute :} 54 | / {:path: path_noscheme :} 55 | / {:path: path_empty :} 56 | 57 | authority <- (userinfo '@')? host (':' port)? 58 | userinfo <- {:user: {~ (unreserved / %pct_encoded / sub_delims / ':')* ~} :} 59 | host <- {:host: IP_literal / %IPv4address / reg_name :} 60 | port <- {:port: %DIGIT+ -> tonumber :} 61 | 62 | IP_literal <- '[' ( IPv6addrz / %IPv6address / IPvFuture) ']' -- RFC-6874 63 | IPvFuture <- { 'v' %HEXDIG+ '.' (unreserved / sub_delims / ':')+ } 64 | ZoneID <- {~ (unreserved / %pct_encoded)+ ~} -- RFC-6874 65 | IPv6addrz <- {~ %IPv6address '%25' -> '%%' ZoneID ~} -- RFC-6874 66 | reg_name <- {~ (unreserved / %pct_encoded / sub_delims)* ~} 67 | path <- path_abempty -- begins with '/' or is empty 68 | / path_absolute -- begins with '/' but not '//' 69 | / path_noscheme -- begins with a non-colon segment 70 | / path_rootless -- begins with a segment 71 | / path_empty 72 | path_abempty <- {~ ( '/' segment)+ ~} / '' -> '/' 73 | path_absolute <- {~ '/' (segment_nz ('/' segment)* )? ~} 74 | path_noscheme <- {~ segment_nz_nc ('/' segment)* ~} 75 | path_rootless <- {~ segment_nz ('/' segment)* ~} 76 | path_empty <- '' -> '/' 77 | segment <- pchar* 78 | segment_nz <- pchar+ 79 | segment_nz_nc <- (unreserved / %pct_encoded / sub_delims / '@')+ 80 | pchar <- unreserved / %pct_encoded / sub_delims / '@' / ':' 81 | query <- {:query: { (pchar / '/' / '?')* } :} 82 | fragment <- {:fragment: {~ (pchar / '/' / '?')* ~} :} 83 | reserved <- gen_delims / sub_delims 84 | gen_delims <- ':' / '/' / '?' / '#' / '[' / ']' / '@' 85 | sub_delims <- '!' / '$' / '&' / "'" / '(' / ')' 86 | / '*' / '+' / ',' / ';' / '=' 87 | unreserved <- %ALPHA / %DIGIT / '-' / '.' / '_' / '~' 88 | ]] 89 | 90 | -- ********************************************************************* 91 | 92 | local pct_encoded = (lpeg.P"%" * abnf.HEXDIG * abnf.HEXDIG) 93 | / function(capture) 94 | local n = tonumber(capture:sub(2,-1),16) 95 | return string.char(n) 96 | end 97 | local R = 98 | { 99 | HEXDIG = abnf.HEXDIG, 100 | ALPHA = abnf.ALPHA, 101 | DIGIT = abnf.DIGIT, 102 | 103 | p443 = lpeg.Cc( 443), 104 | p80 = lpeg.Cc( 80), 105 | p21 = lpeg.Cc( 21), 106 | p1965 = lpeg.Cc(1965), 107 | tonumber = tonumber, 108 | IPv4address = ip.IPv4, 109 | IPv6address = ip.IPv6, 110 | pct_encoded = pct_encoded, 111 | } 112 | 113 | return re.compile(G,R) 114 | -------------------------------------------------------------------------------- /url/data.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: ignore 611 22 | -- RFC-2397 23 | 24 | local abnf = require "org.conman.parsers.abnf" 25 | local lpeg = require "lpeg" 26 | 27 | local Cc = lpeg.Cc 28 | local Cf = lpeg.Cf 29 | local Cg = lpeg.Cg 30 | local Cs = lpeg.Cs 31 | local Ct = lpeg.Ct 32 | local C = lpeg.C 33 | local P = lpeg.P 34 | local R = lpeg.R 35 | local S = lpeg.S 36 | 37 | -- ******************************************************************** 38 | 39 | local escaped = P"%" * C(abnf.HEXDIG * abnf.HEXDIG) 40 | / function(c) return string.char(tonumber(c,16)) end 41 | local mark = S"-_.!~*'()" 42 | local unreserved = abnf.ALPHA + abnf.DIGIT + mark 43 | local uric = escaped + unreserved 44 | 45 | local base64 = abnf.ALPHA + abnf.DIGIT + S"+/" 46 | 47 | -- ------------------------------------------------------------------------ 48 | -- RFC-2045 lists [=["(),/:;<=>?@[\]]=] as tspecials, which cannot be in 49 | -- a parameter name, and *must* be quoted to appear in a value. 50 | -- 51 | -- RFC-3986 lists [=[ "#%<>[\]^{|}]=] as unsafe and these MUST always be 52 | -- escaped in a URL. 53 | -- 54 | -- If you match up the two lists, then the following list [=[#%^{|}]=] are 55 | -- the characters that can appear in a parameter name that MUST be escaped. 56 | -- ------------------------------------------------------------------------ 57 | 58 | local mcharsafe = R"AZ" / string.lower 59 | + S[[!$&`+-.0123456789_`abcdefghijklmnopqrstuvwxyz~]] 60 | local ichar = mcharsafe 61 | + (P"%%23") / "#" 62 | + (P"%%25") / "%%" 63 | + (P"%%5E" + P"%%5e") / "^" 64 | + (P"%%7B" + P"%%7b") / "{" 65 | + (P"%%7C" + P"%%7c") / "|" 66 | + (P"%%7D" + P"%%7d") / "}" 67 | local char = escaped + (R"!~" - S";,") 68 | local itoken = Cs(ichar^1) 69 | local token = Cs(char^1) 70 | local parameters = Cf( 71 | Ct"" * (P";" * Cg(itoken * P"=" * token))^0, 72 | function(acc,name,val) 73 | acc[name] = val 74 | return acc 75 | end 76 | ) 77 | local mimetype = Cs(ichar^1 * P"/" * ichar^1) 78 | local mediatype = Cg(mimetype,'type') 79 | * Cg(#P";" * parameters,'parameters')^-1 80 | local charset = Cg(Ct(P"charset=" * Cg(token,'charset')),'parameters') 81 | local data = Cg(P"data:" / "data",'scheme') 82 | * Cg(Cc('text/plain'),'type') 83 | * Cg(Ct(Cg(Cc'US-ASCII','charset')),'parameters') 84 | * (mediatype + charset)^-1 85 | * ( 86 | ( 87 | Cg(P";base64" * Cc(true),'base64') 88 | * P"," * Cg(C(base64^1),'data') 89 | ) 90 | + 91 | ( 92 | Cg(Cc(false),'base64') 93 | * P"," * Cg(C(uric^1),'data') 94 | ) 95 | ) 96 | return Ct(data) 97 | -------------------------------------------------------------------------------- /url/gopher.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 | 22 | local abnf = require "org.conman.parsers.abnf" 23 | local ip = require "org.conman.parsers.ip-text" 24 | local lpeg = require "lpeg" 25 | local re = require "re" 26 | 27 | local tonumber = tonumber 28 | 29 | -- ************************************************************************ 30 | -- RFC-4266 The gopher URI Scheme 31 | -- 32 | -- Doesn't really go into that great of detail. It appears that %-encoding 33 | -- is only done for spaces, and in the plus area, for SP, CR, LF and TAB, 34 | -- from the only few examples I found at 35 | -- 36 | -- http://www.w3.org/Addressing/URL/4_1_Gopher+.html 37 | -- 38 | -- So, that's what I'm going with. 39 | -- 40 | -- gopher = 41 | -- { 42 | -- scheme = 'gopher', 43 | -- host = "conman.org", 44 | -- port = 70, 45 | -- type = 'dir', 46 | -- selector = "string", 47 | -- search = "string", -- optional 48 | -- plus = "string", -- optional 49 | -- } 50 | -- ************************************************************************ 51 | 52 | local G = --[[ lpeg/re ]] [[ 53 | 54 | gopher_url <- {:scheme: 'gopher' :} 55 | {:port: %p70 :} 56 | {:type: %type :} 57 | {:selector: :} 58 | '://' host (':' port)? gopher_path? 59 | gopher_path <- '/' 60 | {:type: gopher_type :} 61 | {:selector: {~ gopher_char* ~} :} 62 | ( 63 | '%09' {:search: {~ gopher_char* ~} :} 64 | ( '%09' {:plus: {~ gopher_char* ~} :} )? 65 | )? 66 | gopher_type <- gopher_char -> gtypes 67 | gopher_char <- ! '%09' (%pct_encoded / .) 68 | host <- {:host: IP_literal / %IPv4address / reg_name :} 69 | port <- {:port: %DIGIT* -> tonumber :} 70 | IP_literal <- '[' ( IPv6addrz / %IPv6address / IPvFuture ) ']' -- RFC-6874 71 | IPvFuture <- { 'v' %HEXDIG+ '.' (unreserved / sub_delims / ':')+ } 72 | IPv6addrz <- {~ %IPv6address '%25' -> '%%' ZoneID ~} -- RFC-6874 73 | ZoneID <- {~ (unreserved / %pct_encoded)+ ~} -- RFC-6874 74 | reg_name <- {~ (unreserved / %pct_encoded / sub_delims)* ~} 75 | sub_delims <- '!' / '$' / '&' / "'" / '(' / ')' 76 | / '*' / '+' / ',' / ';' / '=' 77 | unreserved <- %ALPHA / %DIGIT / '-' / '.' / '_' / '~' 78 | ]] 79 | 80 | local R = 81 | { 82 | DIGIT = abnf.DIGIT, 83 | HEXDIG = abnf.HEXDIG, 84 | ALPHA = abnf.ALPHA, 85 | p70 = lpeg.Cc(70), 86 | type = lpeg.Cc('dir'), 87 | tonumber = tonumber, 88 | gtypes = require "org.conman.const.gopher-types", 89 | IPv6address = ip.IPv6, 90 | IPv4address = ip.IPv4, 91 | pct_encoded = (lpeg.P"%" * abnf.HEXDIG * abnf.HEXDIG) 92 | / function(capture) 93 | local n = tonumber(capture:sub(2,-1),16) 94 | return string.char(n) 95 | end, 96 | } 97 | 98 | return lpeg.Ct(re.compile(G,R)) 99 | 100 | -- ************************************************************************ 101 | -------------------------------------------------------------------------------- /url/siptel.lua: -------------------------------------------------------------------------------- 1 | -- *************************************************************** 2 | -- 3 | -- Copyright 2016 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 | local abnf = require "org.conman.parsers.abnf" 24 | local ip = require "org.conman.parsers.ip-text" 25 | local lpeg = require "lpeg" 26 | 27 | -- ************************************************************************ 28 | -- RFC-3261 RFC-3966* 29 | -- sip = 30 | -- { 31 | -- scheme = 'sip', -- or 'sips' 32 | -- user = 'sean' or { number = '..' , global = true , parameters = { ... } } 33 | -- password = 'password', 34 | -- host = 'conman.org', 35 | -- port = 5060, 36 | -- parameters = { ... } 37 | -- } 38 | -- ************************************************************************ 39 | 40 | local Cc = lpeg.Cc 41 | local Cf = lpeg.Cf 42 | local Cg = lpeg.Cg 43 | local Cs = lpeg.Cs 44 | local Ct = lpeg.Ct 45 | local C = lpeg.C 46 | local P = lpeg.P 47 | local R = lpeg.R 48 | local S = lpeg.S 49 | 50 | -- ************************************************************************ 51 | 52 | local function I(text) 53 | local mkUl = Cf( 54 | ( 55 | R("AZ","az") 56 | / function(c) 57 | return P(c:lower()) + P(c:upper()) 58 | end 59 | + P(1) 60 | / function(c) return P(c) end 61 | )^1, 62 | function(a,b) return a * b end 63 | ) 64 | return mkUl:match(text) * Cc(text) 65 | end 66 | 67 | -- ************************************************************************ 68 | 69 | local alphanum = abnf.ALPHA + abnf.DIGIT 70 | local pct_encoded = (P"%" * abnf.HEXDIG * abnf.HEXDIG) 71 | / function(capture) 72 | local n = tonumber(capture:sub(2,-1),16) 73 | return n 74 | end 75 | 76 | local visual_separator = lpeg.S"-.()" / "" 77 | local phonedigit = abnf.DIGIT + visual_separator 78 | local phonedigit_hex = abnf.HEXDIG + visual_separator + P"*" + P"#" 79 | local local_number_digits = Cg(Cs(phonedigit_hex^1),'number') 80 | local global_number_digits = Cg(P"+" * Cc(true),'global') 81 | * Cg(Cs(phonedigit^1),'number') 82 | 83 | local domainlabel = alphanum * (alphanum + (P"-" * #alphanum))^0 84 | local domainname = (domainlabel * P"."^-1)^0 85 | local descriptor = global_number_digits 86 | + Cg(domainname,"domain") 87 | local phone_context = I"phone-context" * P"=" * Ct(descriptor) 88 | local ext = I"ext" * P"=" * Cs(phonedigit^1) 89 | 90 | local mark = S"-_.!~*'()" 91 | local unreserved = alphanum + mark 92 | local param_unreserved = S"[]/:&+$" 93 | local paramchar = param_unreserved + unreserved + pct_encoded 94 | local pvalue = Cs(paramchar^1) 95 | local pname = (alphanum + P"-")^1 96 | local parameter = phone_context 97 | + ext 98 | + (pname / function(c) return c:lower() end) 99 | * ((P"=" * C(pvalue)) + Cc(true)) 100 | local par = Cf( 101 | Ct"" * Cg(P";" * parameter)^0, 102 | function(a,i,v) a[i] = v return a end 103 | ) 104 | 105 | local local_number = local_number_digits * Cg(par,"parameters") - P";" 106 | local global_number = global_number_digits * Cg(par,"parameters") - P";" 107 | 108 | local telephone_subscriber = (global_number + local_number) 109 | - abnf.ALPHA -- XXX hack here 110 | local tel_scheme = Cg(lpeg.P"tel",'scheme') * P":" 111 | 112 | -- ************************************************************************ 113 | 114 | local uri_parameters = Cg(par,'parameters') 115 | local user = unreserved + pct_encoded + S"&=+$,;?/" 116 | local password = unreserved + pct_encoded + S"&=+$," 117 | local userinfo = Cg(Ct(telephone_subscriber),'user') * P'@' 118 | + Cg(Cs(user^1),'user') 119 | * (P':' * Cg(Cs(password^1),'password'))^-1 120 | * P'@' 121 | local host = Cg(ip.IPv4 + P"[" * ip.IPv6 * P"]" + domainname,'host') 122 | local port = Cg(abnf.DIGIT^1 / tonumber,'port') 123 | local hostport = host * (P':' * port)^-1 124 | local sip_scheme = Cg(P"sip",'scheme') * Cg(Cc(5060),'port') * P':' 125 | + Cg(P"sips",'scheme') * Cg(Cc(5061),'port') * P':' 126 | 127 | return Ct(sip_scheme * userinfo^-1 * hostport * uri_parameters) 128 | + Ct(tel_scheme * telephone_subscriber) 129 | -------------------------------------------------------------------------------- /url/tag.lua: -------------------------------------------------------------------------------- 1 | -- *************************************************************** 2 | -- 3 | -- Copyright 2020 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 | -- RFC-4151 23 | 24 | local abnf = require "org.conman.parsers.abnf" 25 | local lpeg = require "lpeg" 26 | 27 | local Cg = lpeg.Cg 28 | local Cs = lpeg.Cs 29 | local Ct = lpeg.Ct 30 | local P = lpeg.P 31 | local S = lpeg.S 32 | 33 | -- ------------------------------- 34 | -- Following defined in RFC-3986 35 | -- ------------------------------- 36 | 37 | local unreserved = abnf.ALPHA + abnf.DIGIT + S"-._~" 38 | local pct_encoded = (lpeg.P"%" * abnf.HEXDIG * abnf.HEXDIG) 39 | / function(capture) 40 | local n = tonumber(capture:sub(2,-1),16) 41 | return string.char(n) 42 | end 43 | local sub_delims = S"!$&'()*+,;=" 44 | local pchar = unreserved + sub_delims + S"@:" + pct_encoded 45 | local specific = Cs((S"/?" + pchar)^0) 46 | local fragment = Cs((S"/?" + pchar)^0) 47 | 48 | -- ------------------------------- 49 | -- We resume our regular RFC 50 | -- ------------------------------- 51 | 52 | local alphaNum = abnf.DIGIT + abnf.ALPHA 53 | local DNScomp = alphaNum * (alphaNum + P"-" * #alphaNum)^1 54 | local DNSname = DNScomp * (P"." * DNScomp)^0 55 | local emailAddress = (alphaNum + S"-._")^1 * P"@" * DNSname 56 | local authorityName = Cg(emailAddress + DNSname,'authority') 57 | 58 | local year = Cg(abnf.DIGIT * abnf.DIGIT * abnf.DIGIT * abnf.DIGIT,'year') 59 | local month = Cg(abnf.DIGIT * abnf.DIGIT,'month') 60 | local day = Cg(abnf.DIGIT * abnf.DIGIT,'day') 61 | local date = Cg(Ct(year * (P"-" * month * (P"-" * day)^-1)^-1),'date') 62 | 63 | local taggingEntity = authorityName * P"," * date 64 | 65 | local tag = Cg(P"tag:" / "tag",'scheme') 66 | * taggingEntity * P":" 67 | * Cg(specific,'specific') 68 | * (P"#" * Cg(fragment,'fragment'))^-1 69 | 70 | return Ct(tag) 71 | -------------------------------------------------------------------------------- /utf8.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 | -- 22 | -- Validate a valid UTF-8 character. 23 | -- 24 | -- ******************************************************************** 25 | -- luacheck: ignore 611 26 | -- RFC-3629 27 | -- 28 | -- Characters 192-193 and 245-255 will never appear in proper UTF-8 29 | -- encoding. 30 | 31 | return require "org.conman.parsers.utf8.char" 32 | + require "org.conman.parsers.ascii.char" 33 | + require "org.conman.parsers.utf8.control" 34 | + require "org.conman.parsers.ascii.control" 35 | -------------------------------------------------------------------------------- /utf8/char.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 | -- 22 | -- Parse a valid UTF-8 non-control character. 23 | -- 24 | -- ******************************************************************** 25 | -- luacheck: ignore 611 26 | 27 | local lpeg = require "lpeg" 28 | 29 | return lpeg.P"\194" * lpeg.R"\160\191" 30 | + lpeg.R"\195\223" * lpeg.R"\128\191" 31 | + lpeg.P"\224" * lpeg.R"\160\191" * lpeg.R"\128\191" 32 | + lpeg.R"\225\236" * lpeg.R"\128\191" * lpeg.R"\128\191" 33 | + lpeg.P"\237" * lpeg.R"\128\159" * lpeg.R"\128\191" 34 | + lpeg.R"\238\239" * lpeg.R"\128\191" * lpeg.R"\128\191" 35 | + lpeg.P"\240" * lpeg.R"\144\191" * lpeg.R"\128\191" * lpeg.R"\128\191" 36 | + lpeg.R"\241\243" * lpeg.R"\128\191" * lpeg.R"\128\191" * lpeg.R"\128\191" 37 | + lpeg.P"\244" * lpeg.R"\128\143" * lpeg.R"\128\191" * lpeg.R"\128\191" 38 | -------------------------------------------------------------------------------- /utf8/control.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 | -- 22 | -- Parse a valid UTF-8 control character. 23 | -- 24 | -- ******************************************************************** 25 | -- luacheck: ignore 611 26 | 27 | local lpeg = require "lpeg" 28 | local utf8 = require "org.conman.parsers.utf8.char" 29 | local ascii = require "org.conman.parsers.ascii.char" 30 | 31 | local CSI = lpeg.P"\194\155" + lpeg.P"\27[" 32 | local OSC = lpeg.P"\194\157" + lpeg.P"\27]" 33 | local ST = lpeg.P"\194\156" + lpeg.P"\27\\" 34 | local str = lpeg.P"\194" * lpeg.S"\144\152\158\159" 35 | + lpeg.P"\27" * lpeg.S"PX^_" 36 | 37 | return CSI * lpeg.R"0?"^0 * lpeg.R" /"^0 * lpeg.R"@~" 38 | + OSC * (lpeg.R"\8\13" + ascii + utf8)^0 * (ST + lpeg.P"\7") -- xterm uses BEL 39 | + str * (lpeg.R"\8\13" + ascii + utf8)^0 * ST 40 | + lpeg.P"\27" * lpeg.R"`~" -- 7-bit of C1 41 | + lpeg.P"\194" * lpeg.R"\128\159" -- rest of C1 42 | + lpeg.P"\27" * lpeg.R"@_" -- rest of C1 (7-bits) 43 | -------------------------------------------------------------------------------- /utf8/ctrl.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 | -- 22 | -- Return name of UTF-8 control character and associated data. 23 | -- 24 | -- ******************************************************************** 25 | -- luacheck: ignore 611 26 | 27 | local lpeg = require "lpeg" 28 | local utf8 = require "org.conman.parsers.utf8.char" 29 | local ascii = require "org.conman.parsers.ascii.char" 30 | local Cb = lpeg.Cb 31 | local Cc = lpeg.Cc 32 | local Cf = lpeg.Cf 33 | local Cg = lpeg.Cg 34 | local Cs = lpeg.Cs 35 | local Ct = lpeg.Ct 36 | local C = lpeg.C 37 | local P = lpeg.P 38 | local R = lpeg.R 39 | 40 | local codes = 41 | { 42 | -- --------------------------------- 43 | -- C1 set 44 | -- --------------------------------- 45 | 46 | ['\27@'] = '\194\128' , ['\194\128'] = '\194\128' , 47 | ['\27A'] = '\194\129' , ['\194\129'] = '\194\129' , 48 | ['\27B'] = 'BPH' , ['\194\130'] = 'BPH' , -- BREAK PERMITTED HERE 49 | ['\27C'] = 'NBH' , ['\194\131'] = 'NBH' , -- NO BREAK HERE 50 | ['\27D'] = '\192\132' , ['\194\132'] = '\194\132' , 51 | ['\27E'] = 'NEL' , ['\194\133'] = 'NEL' , -- NEXT LINE 52 | ['\27F'] = 'SSA' , ['\194\134'] = 'SSA' , -- START OF SELECTED AREA 53 | ['\27G'] = 'ESA' , ['\194\135'] = 'ESA' , -- END OF SELECTED AREA 54 | ['\27H'] = 'HTS' , ['\194\136'] = 'HTS' , -- CHARACTER TABULATION SET 55 | ['\27I'] = 'HTJ' , ['\194\137'] = 'HTJ' , -- CHARACTER TABULATION WITH JUSTIFICATION 56 | ['\27J'] = 'VTS' , ['\194\138'] = 'VTS' , -- LINE TABULATION SET 57 | ['\27K'] = 'PLD' , ['\194\139'] = 'PLD' , -- PARTIAL LINE FORWARD 58 | ['\27L'] = 'PLU' , ['\194\140'] = 'PLU' , -- PARTIAL LINE BACKWARD 59 | ['\27M'] = 'RI' , ['\194\141'] = 'RI' , -- REVERSE LINE FEED 60 | ['\27N'] = 'SS2' , ['\194\142'] = 'SS2' , -- SINGLE-SHIFT TWO 61 | ['\27O'] = 'SS3' , ['\194\143'] = 'SS3' , -- SINGLE-SHIFT THREE 62 | -- DCS - handled below DEVICE CONTROL STRING 63 | ['\27Q'] = 'PU1' , ['\194\145'] = 'PU1' , -- PRIVATE USE ONE 64 | ['\27R'] = 'PU2' , ['\194\146'] = 'PU2' , -- PRIVATE USE TWO 65 | ['\27S'] = 'STS' , ['\194\147'] = 'STS' , -- SET TRANSMIT STATE 66 | ['\27T'] = 'CCH' , ['\194\148'] = 'CCH' , -- CANCEL CHARACTER 67 | ['\27U'] = 'MW' , ['\194\149'] = 'MW' , -- MESSAGE WAITING 68 | ['\27V'] = 'SPA' , ['\194\150'] = 'SPA' , -- START OF GUARDED AREA 69 | ['\27W'] = 'EPA' , ['\194\151'] = 'EPA' , -- END OF GUARDED AREA 70 | -- SOS - handled below START OF STRING 71 | ['\27Y'] = '\194\153' , ['\194\153'] = '\194\153' , 72 | ['\27Z'] = 'SCI' , ['\194\154'] = 'SCI' , -- SINGLE CHARACTER INTRODUCER 73 | -- CSI - handled below CONTROL SEQUENCE INTRODUCER 74 | -- ST - handled below STRING TERMINATOR 75 | -- OSC - handled below OPERATING SYSTEM COMMAND 76 | -- PM - handled below PRIVACY MESSAGE 77 | -- APC - handled below APPLICATION PROGRAM COMMAND 78 | 79 | -- --------------------------------- 80 | -- Independent control functions 81 | -- --------------------------------- 82 | 83 | ['\27`'] = 'DMI' , -- DISABLE MANUAL INPUT 84 | ['\27a'] = 'INT' , -- INTERRUPT 85 | ['\27b'] = 'EMI' , -- ENABLE MANUAL INPUT 86 | ['\27c'] = 'RTS' , -- RESET TO INITIAL STATE 87 | ['\27d'] = 'CMD' , -- CODING METHOD DELIMITER 88 | ['\27e'] = '\27e' , 89 | ['\27f'] = '\27f' , 90 | ['\27g'] = '\27g' , 91 | ['\27h'] = '\27h' , 92 | ['\27i'] = '\27i' , 93 | ['\27j'] = '\27j' , 94 | ['\27k'] = '\27k' , 95 | ['\27l'] = '\27l' , 96 | ['\27m'] = '\27m' , 97 | ['\27n'] = 'LS2' , -- LOCKING-SHIFT 2 98 | ['\27o'] = 'LS3' , -- LOCKING-SHIFT 3 99 | ['\27p'] = '\27p' , 100 | ['\27q'] = '\27q' , 101 | ['\27r'] = '\27r' , 102 | ['\27s'] = '\27s' , 103 | ['\27t'] = '\27t' , 104 | ['\27u'] = '\27u' , 105 | ['\27v'] = '\27v' , 106 | ['\27w'] = '\27w' , 107 | ['\27x'] = '\27x' , 108 | ['\27y'] = '\27y' , 109 | ['\27z'] = '\27z' , 110 | ['\27{'] = '\27{' , 111 | ['\27|'] = 'LS3R' , -- LOCKING-SHIFT THREE RIGHT 112 | ['\27}'] = 'LS2R' , -- LOCKING-SHIFT TWO RIGHT 113 | ['\27~'] = 'LSR1' , -- LOCKING-SHIFT ONE RIGHT 114 | } 115 | 116 | local cstr = R"\8\13" + ascii + utf8 117 | 118 | local ST = P"\27\\" + P"\194\156" 119 | local DCS = (P'\27P' + P'\194\144') * Cc'DCS' * C(cstr^0) * ST 120 | local SOS = (P'\27X' + P'\194\152') * Cc'SOS' * C(cstr^0) * ST 121 | local OSC = (P'\27]' + P'\194\157') * Cc'OSC' * C(cstr^0) * (ST + P"\7") -- xterm 122 | local PM = (P'\27^' + P'\194\158') * Cc'PM' * C(cstr^0) * ST 123 | local APC = (P'\27_' + P'\194\159') * Cc'APC' * C(cstr^0) * ST 124 | 125 | local CSI_codes = [[ 126 | @ ICH INSERT CHARACTER 127 | A CCU CURSOR UP 128 | B CUD CURSOR DOWN 129 | C CUF CURSOR RIGHT 130 | D CUB CURSOR LEFT 131 | E CNL CURSOR NEXT LINE 132 | F CPL CURSOR PRECEDING LINE 133 | G CHA CURSOR CHARACTER ABSOLUTE 134 | H CUP CURSOR POSITION 135 | I CHT CURSOR FORWARD TABULATION 136 | J ED ERASE IN PAGE 137 | K EL ERASE IN LINE 138 | L IL INSERT LINE 139 | M DL DELETE LINE 140 | N EF ERASE IN FIELD 141 | O EA ERASE IN AREA 142 | P DCH DELETE CHARACTER 143 | Q SEE SELECT EDITING EXTENT 144 | R CPR ACTIVE POSITION REPORT 145 | S SU SCROLL UP 146 | T SD SCROLL DOWN 147 | U NP NEXT PAGE 148 | V PP PRECEDING PAGE 149 | W CTC CURSOR TABULATION CONTROL 150 | X ECH ERASE CHARACTER 151 | Y CVT CURSOR LINE TABULATION 152 | Z CBT CURSOR BACKWARD TABULATION 153 | [ SRS START REVERSED STRING 154 | \ PTX PARALLEL TEXTS 155 | ] SOS START DIRECTED STRING 156 | ^ SIMD SELECT IMPLICIT MOVEMENT DIRECTION 157 | _ _ 158 | ` HPA CHARACTER POSITION ABSOLUTE 159 | a HPR CHARACTER POSITION FORWARD 160 | b REP REPEAT 161 | c DA DEVICE ATTRIBUTES 162 | d VPA LINE POSITION ABOLUTE 163 | e VPR LINE POSITION FORWARD 164 | f HVP CHARACTER AND LINE POSITION 165 | g TBC TABULATION CLEAR 166 | h SM SET MODE 167 | i MC MEDIA COPY 168 | j HPB CHARACTER POSITION BACKWARD 169 | k VPB LINE POSITION BACKWARD 170 | l RM RESET MODE 171 | m SGR SELECT GRAPHIC RENDITION 172 | n DSR DEVICE STATUS REPORT 173 | o DAQ DEFINE AREA QUALIFICATION 174 | p p private use 175 | q q | 176 | r r V 177 | s s 178 | t t 179 | u u 180 | v v 181 | w w 182 | x x 183 | y y 184 | z z 185 | { { 186 | | | ^ 187 | } } | 188 | ~ ~ private use 189 | ]] 190 | 191 | local CSI_space_codes = [[ 192 | @ SL SCROLL LEFT 193 | A SR SCROLL RIGHT 194 | B GSM GRAPHIC SIZE MODIFICATION 195 | C GSS GRAPHIC SIZE SELECTION 196 | D FNT FONT SELECTION 197 | E TSS THIN SPACE SPECIFICATION 198 | F JFY JUSTIFY 199 | G SPI SPACING INCREMENT 200 | H QUAD QUAD 201 | I SSU SELECT SIZE UNIT 202 | J PFS PAGE FORMAT SELECTION 203 | K SHS SELECT CHARACTER SPACING 204 | L SVS SELECT LINE SPACING 205 | M IGS IDENTIFY GRAPHIC SUBREPERTOIRE 206 | N N 207 | O IDCS IDENTIFY DEVICE CONTROL STRING 208 | P PPA PAGE POSITION ABSOLUTE 209 | Q PPR PAGE POSITION FORWARD 210 | R PPB PAGE POSITION BACKWARD 211 | S SPD SELECT PRESENTATION DIRECTIONS 212 | T DTA DIMENSION TEXT AREA 213 | U SLH SET LINE HOME 214 | V SLL SET LINE LIMIT 215 | W FNK FUNCTION KEY 216 | X SPQR SET PRINT QUALITY AND RAPIDITY 217 | Y SEF SHEET EJECT AND FEED 218 | Z PEC PRESENTATION EXPAND OR CONTRACT 219 | [ SSW SET SPACE WIDTH 220 | \ SACS SET ADDITIONAL CHARACTER SEPARATION 221 | ] SAPV SELECT ALTERNATIVE PRESENTATION VARIANTS 222 | ^ STAB SELECTIVE TABULATION 223 | _ GCC GRAPHIC CHARACTER COMBINATION 224 | ` TATE TABULATION ALIGNED LEADING SPACE 225 | a TALE TABULATION ALIGNED LEADING EDGE 226 | b TAC TABULATION ALIGNED CENTERED 227 | c TCC TABULATION CENTERED ON CHARACTER 228 | d TSR TABULATION STOP REMOVE 229 | e SCO SELECT CHARACTER ORIENTATION 230 | f SCRS SET REDUCED CHARACTER SEPARATION 231 | g SCS SET CHARACTER SPACING 232 | h SLS SET LINE SPACING 233 | i i 234 | j j 235 | k SCP SELECT CHARACTER PATH 236 | l l 237 | m m 238 | n n 239 | o o 240 | p p private use 241 | q q | 242 | r r V 243 | s s 244 | t t 245 | u u 246 | v v 247 | w w 248 | x x 249 | y y 250 | z z 251 | { { 252 | | } ^ 253 | } } | 254 | ~ ~ private use 255 | ]] 256 | 257 | 258 | local CSI do 259 | 260 | local csi = P"\27[" + P"\194\155" 261 | local param = Cs((R"09" + P":" / ".")^1) / tonumber 262 | local params = Ct(param * (P';' * param)^0) 263 | + C(R"