summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLaurent Bercot <ska-skaware@skarnet.org>2015-03-26 12:47:19 +0000
committerLaurent Bercot <ska-skaware@skarnet.org>2015-03-26 12:47:19 +0000
commit9cf89b4437df6a7741532dd73fed770cd8eef9f2 (patch)
treeabdeb249d992b1ba90d44b838318d0d09c3369a2
parentcfe736ed5615d6e00f4ce6704591782fe790a752 (diff)
downloadexecline-9cf89b4437df6a7741532dd73fed770cd8eef9f2.tar.xz
- added el_parse() and friends
- refactored execlineb to use them - version: rc for 2.1.1.1
-rw-r--r--INSTALL2
-rw-r--r--doc/index.html4
-rw-r--r--doc/upgrade.html8
-rw-r--r--package/deps.mak7
-rw-r--r--package/info2
-rw-r--r--src/execline/execlineb.c177
-rw-r--r--src/include/execline/execline.h11
-rw-r--r--src/libexecline/deps-lib/execline3
-rw-r--r--src/libexecline/el_parse.c87
-rw-r--r--src/libexecline/el_parse_from_buffer.c18
-rw-r--r--src/libexecline/el_parse_from_string.c15
11 files changed, 170 insertions, 164 deletions
diff --git a/INSTALL b/INSTALL
index 9a8f893..c2d9b7a 100644
--- a/INSTALL
+++ b/INSTALL
@@ -6,7 +6,7 @@ Build Instructions
- A POSIX-compliant C development environment
- GNU make version 4.0 or later
- - skalibs version 2.3.1.0 or later: http://skarnet.org/software/skalibs/
+ - skalibs version 2.3.2.0 or later: http://skarnet.org/software/skalibs/
This software will run on any operating system that implements
POSIX.1-2008, available at:
diff --git a/doc/index.html b/doc/index.html
index bc2e020..ede99d1 100644
--- a/doc/index.html
+++ b/doc/index.html
@@ -51,7 +51,7 @@ shell's syntax, and has no security issues.
<li> GNU make, version 4.0 or later. Please be aware that execline will
not build with an earlier version. </li>
<li> <a href="http://skarnet.org/software/skalibs/">skalibs</a> version
-2.3.1.0 or later. It's a build-time requirement. It's also a run-time
+2.3.2.0 or later. It's a build-time requirement. It's also a run-time
requirement if you link against the shared version of the skalibs
library. </li>
</ul>
@@ -66,7 +66,7 @@ library. </li>
<h3> Download </h3>
<ul>
- <li> The current released version of execline is <a href="execline-2.1.1.0.tar.gz">2.1.1.0</a>. </li>
+ <li> The current released version of execline is <a href="execline-2.1.1.1.tar.gz">2.1.1.1</a>. </li>
<li> Alternatively, you can checkout a copy of the execline git repository:
<pre> git clone git://git.skarnet.org/execline </pre> </li>
</ul>
diff --git a/doc/upgrade.html b/doc/upgrade.html
index 1e6ab8c..32516d7 100644
--- a/doc/upgrade.html
+++ b/doc/upgrade.html
@@ -17,6 +17,14 @@
<h1> What has changed in execline </h1>
+<h2> in 2.1.1.1 </h2>
+
+<ul>
+ <li> skalibs dependency bumped to 2.3.2.0 </li>
+ <li> execlineb parser made into a library function, for easier
+inclusion in other programs </li>
+</ul>
+
<h2> in 2.1.1.0 </h2>
<ul>
diff --git a/package/deps.mak b/package/deps.mak
index 5c77ee5..6c926ae 100644
--- a/package/deps.mak
+++ b/package/deps.mak
@@ -47,6 +47,9 @@ src/execline/unexport.o src/execline/unexport.lo: src/execline/unexport.c
src/execline/wait.o src/execline/wait.lo: src/execline/wait.c src/include/execline/execline.h
src/libexecline/el_execsequence.o src/libexecline/el_execsequence.lo: src/libexecline/el_execsequence.c src/include/execline/execline.h
src/libexecline/el_getstrict.o src/libexecline/el_getstrict.lo: src/libexecline/el_getstrict.c src/include/execline/execline.h
+src/libexecline/el_parse.o src/libexecline/el_parse.lo: src/libexecline/el_parse.c src/include/execline/execline.h
+src/libexecline/el_parse_from_buffer.o src/libexecline/el_parse_from_buffer.lo: src/libexecline/el_parse_from_buffer.c src/include/execline/execline.h
+src/libexecline/el_parse_from_string.o src/libexecline/el_parse_from_string.lo: src/libexecline/el_parse_from_string.c src/include/execline/execline.h
src/libexecline/el_popenv.o src/libexecline/el_popenv.lo: src/libexecline/el_popenv.c src/include/execline/execline.h
src/libexecline/el_pushenv.o src/libexecline/el_pushenv.lo: src/libexecline/el_pushenv.c src/include/execline/execline.h
src/libexecline/el_semicolon.o src/libexecline/el_semicolon.lo: src/libexecline/el_semicolon.c src/include/execline/execline.h
@@ -152,5 +155,5 @@ unexport: private EXTRA_LIBS :=
unexport: src/execline/unexport.o -lskarnet
wait: private EXTRA_LIBS :=
wait: src/execline/wait.o ${LIBEXECLINE} -lskarnet
-libexecline.a: src/libexecline/el_execsequence.o src/libexecline/el_getstrict.o src/libexecline/el_popenv.o src/libexecline/el_pushenv.o src/libexecline/el_semicolon.o src/libexecline/el_spawn0.o src/libexecline/el_spawn1.o src/libexecline/el_substandrun.o src/libexecline/el_substandrun_str.o src/libexecline/el_substitute.o src/libexecline/el_transform.o src/libexecline/el_vardupl.o src/libexecline/exlsn_define.o src/libexecline/exlsn_elglob.o src/libexecline/exlsn_import.o src/libexecline/exlsn_multidefine.o src/libexecline/exlsn_exlp.o src/libexecline/exlsn_main.o src/libexecline/exlsn_free.o src/libexecline/exlp.o
-libexecline.so: src/libexecline/el_execsequence.lo src/libexecline/el_getstrict.lo src/libexecline/el_popenv.lo src/libexecline/el_pushenv.lo src/libexecline/el_semicolon.lo src/libexecline/el_spawn0.lo src/libexecline/el_spawn1.lo src/libexecline/el_substandrun.lo src/libexecline/el_substandrun_str.lo src/libexecline/el_substitute.lo src/libexecline/el_transform.lo src/libexecline/el_vardupl.lo src/libexecline/exlsn_define.lo src/libexecline/exlsn_elglob.lo src/libexecline/exlsn_import.lo src/libexecline/exlsn_multidefine.lo src/libexecline/exlsn_exlp.lo src/libexecline/exlsn_main.lo src/libexecline/exlsn_free.lo src/libexecline/exlp.lo
+libexecline.a: src/libexecline/el_execsequence.o src/libexecline/el_getstrict.o src/libexecline/el_parse.o src/libexecline/el_parse_from_buffer.o src/libexecline/el_parse_from_string.o src/libexecline/el_popenv.o src/libexecline/el_pushenv.o src/libexecline/el_semicolon.o src/libexecline/el_spawn0.o src/libexecline/el_spawn1.o src/libexecline/el_substandrun.o src/libexecline/el_substandrun_str.o src/libexecline/el_substitute.o src/libexecline/el_transform.o src/libexecline/el_vardupl.o src/libexecline/exlsn_define.o src/libexecline/exlsn_elglob.o src/libexecline/exlsn_import.o src/libexecline/exlsn_multidefine.o src/libexecline/exlsn_exlp.o src/libexecline/exlsn_main.o src/libexecline/exlsn_free.o src/libexecline/exlp.o
+libexecline.so: src/libexecline/el_execsequence.lo src/libexecline/el_getstrict.lo src/libexecline/el_parse.lo src/libexecline/el_parse_from_buffer.lo src/libexecline/el_parse_from_string.lo src/libexecline/el_popenv.lo src/libexecline/el_pushenv.lo src/libexecline/el_semicolon.lo src/libexecline/el_spawn0.lo src/libexecline/el_spawn1.lo src/libexecline/el_substandrun.lo src/libexecline/el_substandrun_str.lo src/libexecline/el_substitute.lo src/libexecline/el_transform.lo src/libexecline/el_vardupl.lo src/libexecline/exlsn_define.lo src/libexecline/exlsn_elglob.lo src/libexecline/exlsn_import.lo src/libexecline/exlsn_multidefine.lo src/libexecline/exlsn_exlp.lo src/libexecline/exlsn_main.lo src/libexecline/exlsn_free.lo src/libexecline/exlp.lo
diff --git a/package/info b/package/info
index f57cc18..4e34898 100644
--- a/package/info
+++ b/package/info
@@ -1,4 +1,4 @@
package=execline
-version=2.1.1.0
+version=2.1.1.1
category=admin
package_macro_name=EXECLINE
diff --git a/src/execline/execlineb.c b/src/execline/execlineb.c
index 1b9e7ad..bfe1d7e 100644
--- a/src/execline/execlineb.c
+++ b/src/execline/execlineb.c
@@ -1,6 +1,6 @@
/* ISC license. */
-#include <skalibs/uint16.h>
+#include <errno.h>
#include <skalibs/uint.h>
#include <skalibs/allreadwrite.h>
#include <skalibs/sgetopt.h>
@@ -9,6 +9,7 @@
#include <skalibs/strerr2.h>
#include <skalibs/stralloc.h>
#include <skalibs/genalloc.h>
+#include <skalibs/env.h>
#include <skalibs/djbunix.h>
#include <skalibs/skamisc.h>
#include <execline/execline.h>
@@ -16,152 +17,6 @@
#define USAGE "execlineb [ -p | -P | -S nmin ] [ -q | -w | -W ] [ -c commandline ] script args"
-typedef unsigned char chargen_t (void) ;
-
-/* Action (strongest 11 bits) */
-
-#define PUSH 0x8000
-#define PUSH0 0x4000
-#define PUSHSPECIAL 0x2000
-#define SETBASE 0x1000
-#define MARK 0x0800
-#define CALC 0x0400
-#define QUOTE 0x0200
-#define INCB 0x0100
-#define DECB 0x0080
-
-
-/* State (weakest 5 bits) */
-
-#define MAIN 0x00
-#define INWORD 0x01
-#define INWORDESC 0x02
-#define INSTR 0x03
-#define INSTRESC 0x04
-#define INREM 0x05
-#define OCT0 0x06
-#define OCT1 0x07
-#define OCT2 0x08
-#define DEC1 0x09
-#define DEC2 0x0a
-#define HEX0 0x0b
-#define HEX1 0x0c
-#define ENDCALC 0x0d
-#define OPENB 0x0e
-#define CLOSEB 0x0f
-#define ERROR 0x10
-#define ACCEPT 0x11
-
-static buffer b ;
-
-static void initbuffer (char const *s)
-{
- static char buf[BUFFER_INSIZE] ;
- int fd = open_readb(s) ;
- if (fd < 0) strerr_diefu3sys(111, "open ", s, " for reading") ;
- if (coe(fd) < 0) strerr_diefu2sys(111, "coe ", s) ;
- buffer_init(&b, &buffer_read, fd, buf, BUFFER_INSIZE) ;
-}
-
-static unsigned char nextinbuffer ()
-{
- char c ;
- switch (buffer_get(&b, &c, 1))
- {
- case -1: strerr_diefu1sys(111, "read script") ;
- case 0 : return 0 ;
- }
- return (unsigned char)c ;
-}
-
-static unsigned char const *string = 0 ;
-
-static unsigned char nextinstring ()
-{
- static unsigned int pos = 0 ;
- return string[pos++] ;
-}
-
-static int lex (stralloc *sa, chargen_t *next)
-{
- static unsigned char const class[256] = "`aaaaaaaaadaaaaaaaaaaaaaaaaaaaaaafcbffffffffffffjhhhhhhhiifffffffmmmmmmfffffffffffffffffffffeffffggmmmgfffffffkfffkfkfkflffnfoffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff" ;
- static uint16 const table[16][16] =
- {
- { 0x0011, 0x4011, 0x0010, 0x0010, 0x0010, 0x0011, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x4091 },
- { 0x0000, 0x4000, 0x8001, 0x8003, 0x8003, 0x0005, 0x0010, 0x8403, 0x8403, 0x8403, 0x8403, 0x0010, 0x8403, 0x8403, 0x0100, 0x4080 },
- { 0x0005, 0x8001, 0x8001, 0x8003, 0x8003, 0x0005, 0x0010, 0x8403, 0x8403, 0x8403, 0x8403, 0x0010, 0x8403, 0x8403, 0x8001, 0x8001 },
- { 0x0203, 0x0003, 0x8001, 0x0001, 0x8003, 0x0005, 0x0010, 0x0401, 0x0401, 0x0401, 0x0401, 0x0010, 0x0401, 0x0401, 0x0003, 0x0003 },
- { 0x0000, 0x4000, 0x8001, 0x8003, 0x0003, 0x0000, 0x0010, 0x8403, 0x8403, 0x8403, 0x8403, 0x0010, 0x8403, 0x8403, 0x0100, 0x4080 },
- { 0x0202, 0x0002, 0x8001, 0x0004, 0x8003, 0x0005, 0x0010, 0x0404, 0x0404, 0x0404, 0x0404, 0x0010, 0x0404, 0x0404, 0x0002, 0x0002 },
- { 0x8201, 0x8001, 0x8001, 0x8003, 0x8003, 0x0005, 0x0010, 0x8403, 0x8403, 0x8403, 0x8403, 0x0010, 0x8403, 0x8403, 0x8001, 0x8001 },
- { 0x8201, 0x8001, 0x8001, 0x8003, 0x2003, 0x0005, 0x0010, 0x8403, 0x8403, 0x8403, 0x8403, 0x880c, 0x800d, 0x8403, 0x8001, 0x8001 },
- { 0x8201, 0x8001, 0x8001, 0x8003, 0x9809, 0x0005, 0x8807, 0x8008, 0x800d, 0x800a, 0x800d, 0x880c, 0x800d, 0x8403, 0x8001, 0x8001 },
- { 0x8201, 0x8001, 0x8001, 0x8003, 0x9809, 0x0005, 0x0010, 0x8403, 0x8403, 0x800a, 0x800d, 0x880c, 0x800d, 0x8403, 0x8001, 0x8001 },
- { 0x8201, 0x8001, 0x8001, 0x8003, 0x1006, 0x0005, 0x8807, 0x8008, 0x800d, 0x800a, 0x800d, 0x880c, 0x800d, 0x8403, 0x8001, 0x8001 },
- { 0x8201, 0x8001, 0x8001, 0x8003, 0x2003, 0x0005, 0x0010, 0x8403, 0x8403, 0x8403, 0x8403, 0x0010, 0x8403, 0x8403, 0x8001, 0x8001 },
- { 0x8201, 0x8001, 0x8001, 0x8003, 0x8003, 0x0005, 0x100b, 0x8403, 0x8403, 0x8403, 0x8403, 0x0010, 0x8403, 0x8403, 0x8001, 0x8001 },
- { 0x8201, 0x8001, 0x8001, 0x8003, 0x8003, 0x0005, 0x0010, 0x8403, 0x8403, 0x8403, 0x8403, 0x880c, 0x800d, 0x8403, 0x8001, 0x8001 },
- { 0x820e, 0x8001, 0x8001, 0x8003, 0x8003, 0x0005, 0x0010, 0x8403, 0x8403, 0x8403, 0x8403, 0x0010, 0x8403, 0x8403, 0x8001, 0x8001 },
- { 0x820f, 0x8001, 0x8001, 0x8003, 0x8003, 0x0005, 0x0010, 0x8403, 0x8403, 0x8403, 0x8403, 0x0010, 0x8403, 0x8403, 0x8001, 0x8001 }
- } ;
-
- unsigned int mark = 0 ;
- unsigned int n = 0 ;
- unsigned char state = MAIN, base = 10 ;
- unsigned int blevel = 0 ;
-
- while (state < ERROR)
- {
- unsigned char cur = (*next)() ;
- register uint16 c = table[class[cur]-'`'][state] ;
- state = c & 0x1F ;
-
- /* Actions. The order is important ! */
-
- if (c & CALC)
- {
- unsigned int z ;
- if (!stralloc_0(sa)) return -1 ;
- sa->len = mark ;
- uint_scan_base(sa->s + sa->len, &z, base) ;
- sa->s[sa->len++] = (unsigned char)z ;
- }
- if (c & MARK) mark = sa->len ;
- if (c & QUOTE)
- {
- char tilde = EXECLINE_BLOCK_QUOTE_CHAR ;
- register unsigned int i = blevel ;
- if (!stralloc_readyplus(sa, i<<1)) return -1 ;
- while (i--) stralloc_catb(sa, &tilde, 1) ;
- }
- if (c & INCB) sa->len -= ++blevel ;
- if (c & DECB)
- {
- if (!blevel--) return -4 ;
- sa->s[--sa->len-1] = EXECLINE_BLOCK_END_CHAR ;
- if (!EXECLINE_BLOCK_END_CHAR) sa->len-- ;
- }
- if (c & PUSH) if (!stralloc_catb(sa, (char *)&cur, 1)) return -1 ;
- if (c & PUSHSPECIAL)
- {
- char x = 7 + byte_chr("abtnvfr", 7, cur) ;
- if (!stralloc_catb(sa, &x, 1)) return -1 ;
- }
- if (c & PUSH0) if (n++, !stralloc_0(sa)) return -1 ;
- if (c & SETBASE)
- switch (cur)
- {
- case 'x' : base = 16 ; break ;
- case '0' : base = 8 ; break ;
- default : base = 10 ;
- }
- }
- if (state == ERROR) return -2 ;
- if (blevel) return -3 ;
- return n ;
-}
-
-
static int myexlp (stralloc *sa, char const *const *argv, unsigned int argc, unsigned int nmin, char const *dollar0)
{
exlsn_t info = EXLSN_ZERO ;
@@ -205,16 +60,15 @@ static int myexlp (stralloc *sa, char const *const *argv, unsigned int argc, uns
return -1 ;
}
-
int main (int argc, char const *const *argv, char const *const *envp)
{
- chargen_t *next ;
stralloc sa = STRALLOC_ZERO ;
stralloc modif = STRALLOC_ZERO ;
int nc ;
int flagstrict = -1 ;
unsigned int nmin = 0 ;
- char const *dollar0 = argv[0] ;
+ char const *stringarg = 0 ;
+ char const *dollar0 = *argv ;
unsigned int flagpushenv = 2 ;
PROG = "execlineb" ;
{
@@ -230,7 +84,7 @@ int main (int argc, char const *const *argv, char const *const *envp)
case 'q' : flagstrict = 0 ; break ;
case 'w' : flagstrict = 1 ; break ;
case 'W' : flagstrict = 2 ; break ;
- case 'c' : string = (unsigned char *)l.arg ; break ;
+ case 'c' : stringarg = l.arg ; break ;
case 'S' :
{
if (!uint0_scan(l.arg, &nmin)) strerr_dieusage(100, USAGE) ;
@@ -242,17 +96,24 @@ int main (int argc, char const *const *argv, char const *const *envp)
}
argc -= l.ind ; argv += l.ind ;
}
- if (string) next = &nextinstring ;
+ if (stringarg) nc = el_parse_from_string(&sa, stringarg) ;
else
{
- if (!argv[0]) strerr_dieusage(100, USAGE) ;
- initbuffer(argv[0]) ;
- dollar0 = argv[0] ;
- argv++ ; argc-- ;
- next = &nextinbuffer ;
+ char buf[BUFFER_INSIZE] ;
+ buffer b ;
+ int fd ;
+ int e ;
+ if (!argc--) strerr_dieusage(100, USAGE) ;
+ dollar0 = *argv++ ;
+ fd = open_readb(dollar0) ;
+ if (fd < 0) strerr_diefu3sys(111, "open ", dollar0, " for reading") ;
+ buffer_init(&b, &fd_readsv, fd, buf, BUFFER_INSIZE) ;
+ nc = el_parse_from_buffer(&sa, &b) ;
+ e = errno ;
+ fd_close(fd) ;
+ errno = e ;
}
- nc = lex(&sa, next) ;
switch (nc)
{
case -4: strerr_dief2x(100, "unmatched ", "}") ;
diff --git a/src/include/execline/execline.h b/src/include/execline/execline.h
index 1f1ec68..7691cf1 100644
--- a/src/include/execline/execline.h
+++ b/src/include/execline/execline.h
@@ -5,12 +5,23 @@
#include <sys/types.h>
#include <skalibs/gccattributes.h>
+#include <skalibs/buffer.h>
#include <skalibs/stralloc.h>
#define EXECLINE_BLOCK_QUOTE_CHAR ' '
#define EXECLINE_BLOCK_END_CHAR '\0'
+/* Parsing */
+
+typedef int el_chargen_func_t (unsigned char *, void *) ;
+typedef el_chargen_func_t *el_chargen_func_t_ref ;
+
+extern int el_parse (stralloc *, el_chargen_func_t_ref, void *) ;
+extern int el_parse_from_string (stralloc *, char const *) ;
+extern int el_parse_from_buffer (stralloc *, buffer *) ;
+
+
/* Basics */
extern int el_vardupl (char const *, char const *, unsigned int) gccattr_pure ;
diff --git a/src/libexecline/deps-lib/execline b/src/libexecline/deps-lib/execline
index f3e4e49..da9d62e 100644
--- a/src/libexecline/deps-lib/execline
+++ b/src/libexecline/deps-lib/execline
@@ -1,5 +1,8 @@
el_execsequence.o
el_getstrict.o
+el_parse.o
+el_parse_from_buffer.o
+el_parse_from_string.o
el_popenv.o
el_pushenv.o
el_semicolon.o
diff --git a/src/libexecline/el_parse.c b/src/libexecline/el_parse.c
new file mode 100644
index 0000000..1544f51
--- /dev/null
+++ b/src/libexecline/el_parse.c
@@ -0,0 +1,87 @@
+/* ISC license. */
+
+#include <skalibs/uint16.h>
+#include <skalibs/uint.h>
+#include <skalibs/bytestr.h>
+#include <skalibs/stralloc.h>
+#include <skalibs/djbunix.h>
+#include <execline/execline.h>
+
+int el_parse (stralloc *sa, el_chargen_func_t_ref next, void *source)
+{
+ static unsigned char const class[256] = "`aaaaaaaaadaaaaaaaaaaaaaaaaaaaaaafcbffffffffffffjhhhhhhhiifffffffmmmmmmfffffffffffffffffffffeffffggmmmgfffffffkfffkfkfkflffnfoffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff" ;
+ static uint16 const table[16][16] =
+ {
+ { 0x0011, 0x4011, 0x0010, 0x0010, 0x0010, 0x0011, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x4091 },
+ { 0x0000, 0x4000, 0x8001, 0x8003, 0x8003, 0x0005, 0x0010, 0x8403, 0x8403, 0x8403, 0x8403, 0x0010, 0x8403, 0x8403, 0x0100, 0x4080 },
+ { 0x0005, 0x8001, 0x8001, 0x8003, 0x8003, 0x0005, 0x0010, 0x8403, 0x8403, 0x8403, 0x8403, 0x0010, 0x8403, 0x8403, 0x8001, 0x8001 },
+ { 0x0203, 0x0003, 0x8001, 0x0001, 0x8003, 0x0005, 0x0010, 0x0401, 0x0401, 0x0401, 0x0401, 0x0010, 0x0401, 0x0401, 0x0003, 0x0003 },
+ { 0x0000, 0x4000, 0x8001, 0x8003, 0x0003, 0x0000, 0x0010, 0x8403, 0x8403, 0x8403, 0x8403, 0x0010, 0x8403, 0x8403, 0x0100, 0x4080 },
+ { 0x0202, 0x0002, 0x8001, 0x0004, 0x8003, 0x0005, 0x0010, 0x0404, 0x0404, 0x0404, 0x0404, 0x0010, 0x0404, 0x0404, 0x0002, 0x0002 },
+ { 0x8201, 0x8001, 0x8001, 0x8003, 0x8003, 0x0005, 0x0010, 0x8403, 0x8403, 0x8403, 0x8403, 0x0010, 0x8403, 0x8403, 0x8001, 0x8001 },
+ { 0x8201, 0x8001, 0x8001, 0x8003, 0x2003, 0x0005, 0x0010, 0x8403, 0x8403, 0x8403, 0x8403, 0x880c, 0x800d, 0x8403, 0x8001, 0x8001 },
+ { 0x8201, 0x8001, 0x8001, 0x8003, 0x9809, 0x0005, 0x8807, 0x8008, 0x800d, 0x800a, 0x800d, 0x880c, 0x800d, 0x8403, 0x8001, 0x8001 },
+ { 0x8201, 0x8001, 0x8001, 0x8003, 0x9809, 0x0005, 0x0010, 0x8403, 0x8403, 0x800a, 0x800d, 0x880c, 0x800d, 0x8403, 0x8001, 0x8001 },
+ { 0x8201, 0x8001, 0x8001, 0x8003, 0x1006, 0x0005, 0x8807, 0x8008, 0x800d, 0x800a, 0x800d, 0x880c, 0x800d, 0x8403, 0x8001, 0x8001 },
+ { 0x8201, 0x8001, 0x8001, 0x8003, 0x2003, 0x0005, 0x0010, 0x8403, 0x8403, 0x8403, 0x8403, 0x0010, 0x8403, 0x8403, 0x8001, 0x8001 },
+ { 0x8201, 0x8001, 0x8001, 0x8003, 0x8003, 0x0005, 0x100b, 0x8403, 0x8403, 0x8403, 0x8403, 0x0010, 0x8403, 0x8403, 0x8001, 0x8001 },
+ { 0x8201, 0x8001, 0x8001, 0x8003, 0x8003, 0x0005, 0x0010, 0x8403, 0x8403, 0x8403, 0x8403, 0x880c, 0x800d, 0x8403, 0x8001, 0x8001 },
+ { 0x820e, 0x8001, 0x8001, 0x8003, 0x8003, 0x0005, 0x0010, 0x8403, 0x8403, 0x8403, 0x8403, 0x0010, 0x8403, 0x8403, 0x8001, 0x8001 },
+ { 0x820f, 0x8001, 0x8001, 0x8003, 0x8003, 0x0005, 0x0010, 0x8403, 0x8403, 0x8403, 0x8403, 0x0010, 0x8403, 0x8403, 0x8001, 0x8001 }
+ } ;
+
+ unsigned int mark = 0 ;
+ unsigned int n = 0 ;
+ unsigned int blevel = 0 ;
+ unsigned char state = 0, base = 10 ;
+
+ while (state < 0x10)
+ {
+ uint16 c ;
+ unsigned char cur ;
+ if (!(*next)(&cur, source)) return -1 ;
+ c = table[class[cur]-'`'][state] ;
+ state = c & 0x1F ;
+
+ if (c & 0x0400)
+ {
+ unsigned int z ;
+ if (!stralloc_0(sa)) return -1 ;
+ sa->len = mark ;
+ uint_scan_base(sa->s + sa->len, &z, base) ;
+ sa->s[sa->len++] = (unsigned char)z ;
+ }
+ if (c & 0x0800) mark = sa->len ;
+ if (c & 0x0200)
+ {
+ char tilde = EXECLINE_BLOCK_QUOTE_CHAR ;
+ register unsigned int i = blevel ;
+ if (!stralloc_readyplus(sa, i<<1)) return -1 ;
+ while (i--) stralloc_catb(sa, &tilde, 1) ;
+ }
+ if (c & 0x0100) sa->len -= ++blevel ;
+ if (c & 0x0080)
+ {
+ if (!blevel--) return -4 ;
+ sa->s[--sa->len-1] = EXECLINE_BLOCK_END_CHAR ;
+ if (!EXECLINE_BLOCK_END_CHAR) sa->len-- ;
+ }
+ if (c & 0x8000) if (!stralloc_catb(sa, (char *)&cur, 1)) return -1 ;
+ if (c & 0x2000)
+ {
+ char x = 7 + byte_chr("abtnvfr", 7, cur) ;
+ if (!stralloc_catb(sa, &x, 1)) return -1 ;
+ }
+ if (c & 0x4000) if (n++, !stralloc_0(sa)) return -1 ;
+ if (c & 0x1000)
+ switch (cur)
+ {
+ case 'x' : base = 16 ; break ;
+ case '0' : base = 8 ; break ;
+ default : base = 10 ;
+ }
+ }
+ if (state == 0x10) return -2 ;
+ if (blevel) return -3 ;
+ return n ;
+}
diff --git a/src/libexecline/el_parse_from_buffer.c b/src/libexecline/el_parse_from_buffer.c
new file mode 100644
index 0000000..802fe40
--- /dev/null
+++ b/src/libexecline/el_parse_from_buffer.c
@@ -0,0 +1,18 @@
+/* ISC license. */
+
+#include <skalibs/buffer.h>
+#include <skalibs/stralloc.h>
+#include <execline/execline.h>
+
+static int next (unsigned char *c, void *p)
+{
+ register int r = buffer_get((buffer *)p, (char *)c, 1) ;
+ if (r < 0) return 0 ;
+ if (!r) *c = 0 ;
+ return 1 ;
+}
+
+int el_parse_from_buffer (stralloc *sa, buffer *b)
+{
+ return el_parse(sa, &next, b) ;
+}
diff --git a/src/libexecline/el_parse_from_string.c b/src/libexecline/el_parse_from_string.c
new file mode 100644
index 0000000..04c48a3
--- /dev/null
+++ b/src/libexecline/el_parse_from_string.c
@@ -0,0 +1,15 @@
+/* ISC license. */
+
+#include <skalibs/stralloc.h>
+#include <execline/execline.h>
+
+static int next (unsigned char *c, void *p)
+{
+ *c = *(*(char const **)p)++ ;
+ return 1 ;
+}
+
+int el_parse_from_string (stralloc *sa, char const *s)
+{
+ return el_parse(sa, &next, &s) ;
+}