├── 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"" * R"0?"^0)
265 | + Ct""
266 |
267 | local letter = R"@~"
268 | / function(c)
269 | return P(c)
270 | end
271 |
272 | local name = R"@~"^1
273 | / function(n)
274 | return Cc(n)
275 | end
276 |
277 | local entry = P" "
278 | * Cg(letter,'letter')
279 | * P"\t"
280 | * Cg(name,'name')
281 | * P"\t"^-1 * R" ~"^0 * P"\n"
282 | * (Cb'name' * Cb'letter')
283 | / function(n,l)
284 | return n * params * l
285 | end
286 |
287 | local sletter = R"@~"
288 | / function(c)
289 | return P(" " .. c)
290 | end
291 |
292 | local sname = R"@~"^1
293 | / function(n)
294 | if #n == 1 then
295 | return Cc(" " .. n)
296 | else
297 | return Cc(n)
298 | end
299 | end
300 |
301 | local sentry = P" "
302 | * Cg(sletter,'letter')
303 | * P"\t"
304 | * Cg(sname,'name')
305 | * P"\t"^-1 * R" ~"^0 * P"\n"
306 | * (Cb'name' * Cb'letter')
307 | / function(n,l)
308 | return n * params * l
309 | end
310 |
311 | local parse_csi = Cf(entry^1, function(a,b) return a + b end)
312 | local parse_scsi = Cf(sentry^1,function(a,b) return a + b end)
313 | local other = Cg(R"0?"^0,'param')
314 | * Cg(R"!/"^0,'inter')
315 | * C(1) * Cb'param' * Cb'inter'
316 |
317 | CSI = csi
318 | * (
319 | parse_csi:match(CSI_codes)
320 | + parse_scsi:match(CSI_space_codes)
321 | + other
322 | )
323 | end
324 |
325 | return CSI + DCS + SOS + OSC+ PM + APC
326 | + R"\128\159" / codes
327 | + (P"\27" * R("@_","`~")) / codes
328 |
--------------------------------------------------------------------------------
/json.lua:
--------------------------------------------------------------------------------
1 | -- ***************************************************************
2 | --
3 | -- Copyright 2012 by Sean Conner. All Rights Reserved.
4 | --
5 | -- This library is free software; you can redistribute it and/or modify it
6 | -- under the terms of the GNU Lesser General Public License as published by
7 | -- the Free Software Foundation; either version 3 of the License, or (at your
8 | -- option) any later version.
9 | --
10 | -- This library is distributed in the hope that it will be useful, but
11 | -- WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
12 | -- or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
13 | -- License for more details.
14 | --
15 | -- You should have received a copy of the GNU Lesser General Public License
16 | -- along with this library; if not, see .
17 | --
18 | -- Comments, questions and criticisms can be sent to: sean@conman.org
19 | --
20 | -- ********************************************************************
21 | -- luacheck: globals 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"" * R"0?"^0)
264 | + Ct""
265 |
266 | local letter = R"@~"
267 | / function(c)
268 | return P(c)
269 | end
270 |
271 | local name = R"@~"^1
272 | / function(n)
273 | return Cc(n)
274 | end
275 |
276 | local entry = P" "
277 | * Cg(letter,'letter')
278 | * P"\t"
279 | * Cg(name,'name')
280 | * P"\t"^-1 * R" ~"^0 * P"\n"
281 | * (Cb'name' * Cb'letter')
282 | / function(n,l)
283 | return n * params * l
284 | end
285 |
286 | local sletter = R"@~"
287 | / function(c)
288 | return P(" " .. c)
289 | end
290 |
291 | local sname = R"@~"^1
292 | / function(n)
293 | if #n == 1 then
294 | return Cc(" " .. n)
295 | else
296 | return Cc(n)
297 | end
298 | end
299 |
300 | local sentry = P" "
301 | * Cg(sletter,'letter')
302 | * P"\t"
303 | * Cg(sname,'name')
304 | * P"\t"^-1 * R" ~"^0 * P"\n"
305 | * (Cb'name' * Cb'letter')
306 | / function(n,l)
307 | return n * params * l
308 | end
309 |
310 | local parse_csi = Cf(entry^1, function(a,b) return a + b end)
311 | local parse_scsi = Cf(sentry^1,function(a,b) return a + b end)
312 | local other = Cg(R"0?"^0,'param')
313 | * Cg(R"!/"^0,'inter')
314 | * C(1) * Cb'param' * Cb'inter'
315 |
316 | CSI = csi
317 | * (
318 | parse_csi:match(CSI_codes)
319 | + parse_scsi:match(CSI_space_codes)
320 | + other
321 | )
322 | end
323 |
324 | return CSI + DCS + SOS + OSC+ PM + APC
325 | + (P"\194" * R"\128\159") / codes
326 | + (P"\27" * R("@_","`~")) / codes
327 |
--------------------------------------------------------------------------------