libdash 0.3__tar.gz → 0.4.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (99) hide show
  1. libdash-0.4.0/PKG-INFO +145 -0
  2. {libdash-0.3 → libdash-0.4.0}/README.md +12 -0
  3. {libdash-0.3 → libdash-0.4.0}/configure.ac +50 -7
  4. {libdash-0.3 → libdash-0.4.0}/libdash/parser.py +5 -4
  5. {libdash-0.3 → libdash-0.4.0}/libdash/printer.py +27 -20
  6. libdash-0.4.0/libdash.egg-info/PKG-INFO +145 -0
  7. {libdash-0.3 → libdash-0.4.0}/libdash.egg-info/SOURCES.txt +1 -0
  8. {libdash-0.3 → libdash-0.4.0}/pyproject.toml +6 -5
  9. {libdash-0.3 → libdash-0.4.0}/setup.py +26 -5
  10. {libdash-0.3 → libdash-0.4.0}/src/alias.c +22 -27
  11. {libdash-0.3 → libdash-0.4.0}/src/arith_yacc.c +2 -2
  12. {libdash-0.3 → libdash-0.4.0}/src/bltin/echo.1 +4 -2
  13. {libdash-0.3 → libdash-0.4.0}/src/bltin/printf.1 +7 -6
  14. {libdash-0.3 → libdash-0.4.0}/src/bltin/printf.c +141 -38
  15. {libdash-0.3 → libdash-0.4.0}/src/bltin/test.1 +1 -1
  16. {libdash-0.3 → libdash-0.4.0}/src/bltin/test.c +38 -36
  17. {libdash-0.3 → libdash-0.4.0}/src/bltin/times.c +1 -1
  18. {libdash-0.3 → libdash-0.4.0}/src/cd.c +1 -1
  19. {libdash-0.3 → libdash-0.4.0}/src/dash.1 +166 -73
  20. {libdash-0.3 → libdash-0.4.0}/src/error.h +0 -4
  21. {libdash-0.3 → libdash-0.4.0}/src/eval.c +52 -22
  22. {libdash-0.3 → libdash-0.4.0}/src/exec.c +34 -31
  23. {libdash-0.3 → libdash-0.4.0}/src/exec.h +5 -0
  24. {libdash-0.3 → libdash-0.4.0}/src/expand.c +927 -457
  25. {libdash-0.3 → libdash-0.4.0}/src/expand.h +5 -0
  26. {libdash-0.3 → libdash-0.4.0}/src/histedit.c +17 -15
  27. {libdash-0.3 → libdash-0.4.0}/src/init.h +4 -1
  28. {libdash-0.3 → libdash-0.4.0}/src/input.c +341 -151
  29. {libdash-0.3 → libdash-0.4.0}/src/input.h +44 -7
  30. {libdash-0.3 → libdash-0.4.0}/src/jobs.c +100 -49
  31. {libdash-0.3 → libdash-0.4.0}/src/jobs.h +2 -1
  32. {libdash-0.3 → libdash-0.4.0}/src/mail.c +1 -1
  33. {libdash-0.3 → libdash-0.4.0}/src/main.c +11 -5
  34. {libdash-0.3 → libdash-0.4.0}/src/main.h +2 -0
  35. {libdash-0.3 → libdash-0.4.0}/src/memalloc.c +37 -34
  36. {libdash-0.3 → libdash-0.4.0}/src/memalloc.h +10 -10
  37. {libdash-0.3 → libdash-0.4.0}/src/miscbltin.c +41 -28
  38. {libdash-0.3 → libdash-0.4.0}/src/mkinit.c +9 -2
  39. {libdash-0.3 → libdash-0.4.0}/src/mksignames.c +1 -3
  40. {libdash-0.3 → libdash-0.4.0}/src/mksyntax.c +8 -12
  41. {libdash-0.3 → libdash-0.4.0}/src/mktokens +1 -1
  42. {libdash-0.3 → libdash-0.4.0}/src/myhistedit.h +18 -0
  43. {libdash-0.3 → libdash-0.4.0}/src/mystring.c +6 -5
  44. {libdash-0.3 → libdash-0.4.0}/src/mystring.h +15 -1
  45. {libdash-0.3 → libdash-0.4.0}/src/nodes.c.pat +5 -15
  46. {libdash-0.3 → libdash-0.4.0}/src/options.c +18 -16
  47. {libdash-0.3 → libdash-0.4.0}/src/options.h +4 -3
  48. {libdash-0.3 → libdash-0.4.0}/src/parser.c +312 -141
  49. {libdash-0.3 → libdash-0.4.0}/src/parser.h +6 -0
  50. {libdash-0.3 → libdash-0.4.0}/src/redir.c +229 -180
  51. {libdash-0.3 → libdash-0.4.0}/src/redir.h +2 -1
  52. {libdash-0.3 → libdash-0.4.0}/src/system.h +75 -0
  53. {libdash-0.3 → libdash-0.4.0}/src/trap.c +50 -19
  54. libdash-0.4.0/src/type_description.ml +184 -0
  55. {libdash-0.3 → libdash-0.4.0}/src/var.c +40 -42
  56. {libdash-0.3 → libdash-0.4.0}/src/var.h +16 -1
  57. libdash-0.3/PKG-INFO +0 -70
  58. libdash-0.3/libdash.egg-info/PKG-INFO +0 -70
  59. {libdash-0.3 → libdash-0.4.0}/COPYING +0 -0
  60. {libdash-0.3 → libdash-0.4.0}/MANIFEST.in +0 -0
  61. {libdash-0.3 → libdash-0.4.0}/Makefile.am +0 -0
  62. {libdash-0.3 → libdash-0.4.0}/autogen.sh +0 -0
  63. {libdash-0.3 → libdash-0.4.0}/libdash/__init__.py +0 -0
  64. {libdash-0.3 → libdash-0.4.0}/libdash/_dash.py +0 -0
  65. {libdash-0.3 → libdash-0.4.0}/libdash/ast.py +0 -0
  66. {libdash-0.3 → libdash-0.4.0}/libdash.egg-info/dependency_links.txt +0 -0
  67. {libdash-0.3 → libdash-0.4.0}/libdash.egg-info/top_level.txt +0 -0
  68. {libdash-0.3 → libdash-0.4.0}/setup.cfg +0 -0
  69. {libdash-0.3 → libdash-0.4.0}/src/Makefile.am +0 -0
  70. {libdash-0.3 → libdash-0.4.0}/src/TOUR +0 -0
  71. {libdash-0.3 → libdash-0.4.0}/src/alias.h +0 -0
  72. {libdash-0.3 → libdash-0.4.0}/src/arith_yacc.h +0 -0
  73. {libdash-0.3 → libdash-0.4.0}/src/arith_yylex.c +0 -0
  74. {libdash-0.3 → libdash-0.4.0}/src/bltin/bltin.h +0 -0
  75. {libdash-0.3 → libdash-0.4.0}/src/builtins.def.in +0 -0
  76. {libdash-0.3 → libdash-0.4.0}/src/cd.h +0 -0
  77. {libdash-0.3 → libdash-0.4.0}/src/error.c +0 -0
  78. {libdash-0.3 → libdash-0.4.0}/src/eval.h +0 -0
  79. {libdash-0.3 → libdash-0.4.0}/src/funcs/cmv +0 -0
  80. {libdash-0.3 → libdash-0.4.0}/src/funcs/dirs +0 -0
  81. {libdash-0.3 → libdash-0.4.0}/src/funcs/kill +0 -0
  82. {libdash-0.3 → libdash-0.4.0}/src/funcs/login +0 -0
  83. {libdash-0.3 → libdash-0.4.0}/src/funcs/newgrp +0 -0
  84. {libdash-0.3 → libdash-0.4.0}/src/funcs/popd +0 -0
  85. {libdash-0.3 → libdash-0.4.0}/src/funcs/pushd +0 -0
  86. {libdash-0.3 → libdash-0.4.0}/src/funcs/suspend +0 -0
  87. {libdash-0.3 → libdash-0.4.0}/src/machdep.h +0 -0
  88. {libdash-0.3 → libdash-0.4.0}/src/mail.h +0 -0
  89. {libdash-0.3 → libdash-0.4.0}/src/miscbltin.h +0 -0
  90. {libdash-0.3 → libdash-0.4.0}/src/mkbuiltins +0 -0
  91. {libdash-0.3 → libdash-0.4.0}/src/mknodes.c +0 -0
  92. {libdash-0.3 → libdash-0.4.0}/src/nodetypes +0 -0
  93. {libdash-0.3 → libdash-0.4.0}/src/output.c +0 -0
  94. {libdash-0.3 → libdash-0.4.0}/src/output.h +0 -0
  95. {libdash-0.3 → libdash-0.4.0}/src/shell.h +0 -0
  96. {libdash-0.3 → libdash-0.4.0}/src/show.c +0 -0
  97. {libdash-0.3 → libdash-0.4.0}/src/show.h +0 -0
  98. {libdash-0.3 → libdash-0.4.0}/src/system.c +0 -0
  99. {libdash-0.3 → libdash-0.4.0}/src/trap.h +0 -0
libdash-0.4.0/PKG-INFO ADDED
@@ -0,0 +1,145 @@
1
+ Metadata-Version: 2.1
2
+ Name: libdash
3
+ Version: 0.4.0
4
+ Summary: Bindings for the dash shell as a library
5
+ Author: PaSh contributors
6
+ Author-email: Michael Greenberg <michael@greenberg.science>
7
+ License: Copyright (c) 1989-1994
8
+ The Regents of the University of California. All rights reserved.
9
+ Copyright (c) 1997 Christos Zoulas. All rights reserved.
10
+ Copyright (c) 1997-2005
11
+ Herbert Xu <herbert@gondor.apana.org.au>. All rights reserved.
12
+
13
+ This code is derived from software contributed to Berkeley by Kenneth Almquist.
14
+
15
+
16
+ Redistribution and use in source and binary forms, with or without
17
+ modification, are permitted provided that the following conditions
18
+ are met:
19
+ 1. Redistributions of source code must retain the above copyright
20
+ notice, this list of conditions and the following disclaimer.
21
+ 2. Redistributions in binary form must reproduce the above copyright
22
+ notice, this list of conditions and the following disclaimer in the
23
+ documentation and/or other materials provided with the distribution.
24
+ 3. Neither the name of the University nor the names of its contributors
25
+ may be used to endorse or promote products derived from this software
26
+ without specific prior written permission.
27
+
28
+ THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
29
+ ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
30
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
31
+ ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
32
+ FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
33
+ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
34
+ OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
35
+ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
36
+ LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
37
+ OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
38
+ SUCH DAMAGE.
39
+
40
+ mksignames.c:
41
+
42
+ This file is not directly linked with dash. However, its output is.
43
+
44
+ Copyright (C) 1992 Free Software Foundation, Inc.
45
+
46
+ This file is part of GNU Bash, the Bourne Again SHell.
47
+
48
+ Bash is free software; you can redistribute it and/or modify it under
49
+ the terms of the GNU General Public License as published by the Free
50
+ Software Foundation; either version 2, or (at your option) any later
51
+ version.
52
+
53
+ Bash is distributed in the hope that it will be useful, but WITHOUT ANY
54
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or
55
+ FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
56
+ for more details.
57
+
58
+ You should have received a copy of the GNU General Public License with
59
+ your Debian GNU/Linux system, in /usr/share/common-licenses/GPL, or with the
60
+ Debian GNU/Linux hello source package as the file COPYING. If not,
61
+ write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330,
62
+ Boston, MA 02111 USA.
63
+
64
+ Project-URL: Homepage, https://github.com/binpash/libdash
65
+ Project-URL: Bug Tracker, https://github.com/binpash/libdash/issues
66
+ Classifier: Programming Language :: Python :: 3
67
+ Classifier: Topic :: System :: System Shells
68
+ Classifier: Operating System :: POSIX
69
+ Requires-Python: >=3.7
70
+ Description-Content-Type: text/markdown
71
+ License-File: COPYING
72
+
73
+ [![Main workflow](https://github.com/mgree/libdash/actions/workflows/build.yml/badge.svg)](https://github.com/mgree/libdash/actions/workflows/build.yml)
74
+
75
+ *libdash* is a fork of the Linux Kernel's `dash` shell that builds a linkable library with extra exposed interfaces. The primary use of libdash is to parse shell scripts, but it could be used for more.
76
+
77
+ The Python bindings are packaged as the [`libdash` PyPi package](https://pypi.org/project/libdash/).
78
+
79
+ The OCaml bindings---packaged as the [`libdash` OPAM package](https://opam.ocaml.org/packages/libdash/)---include two executables, `shell_to_json` and `json_to_shell`, which let you conveniently parse POSIX shell scripts into a JSON AST.
80
+
81
+ # What are the dependencies?
82
+
83
+ The C code for dash should build on a wide variety of systems; it requires `libtool` and `autotools` (`aclocal`, `autoheader`, `automake`, `autoconf`). The library may not build on platforms with esoteric linkers; it's been tested on macOS and Linux.
84
+
85
+ The Python and OCaml bindings depend on being able to build the C code. See `libdash.opam` for details on the OCaml code's dependencies, which includes the build-time external dependencies. Python wheels have no need for these build-time dependencies, but building from a Python source distribution will only succeed when `libtool` and `autotools` are present.
86
+
87
+ The CI scripts (in `.github/workflows/build.yml`) give build details.
88
+
89
+ ## How to build `libdash` from source
90
+
91
+ ### Python
92
+
93
+ Run `python3 setup.py install`. On macOS, you must first install the build dependencies via `brew install libtool autoconf automake`.
94
+
95
+ You can test the Python bindings by running:
96
+
97
+ ```
98
+ cd python; make test
99
+ ```
100
+
101
+ ### OCaml
102
+
103
+ Install the OPAM file: `opam pin add .` or `opam install .`. This will build the OCaml library and install it in your OPAM repository. There are tests in another directory; they will only build when libdash is actually installed.
104
+
105
+ You can test the OCaml bindings by running:
106
+
107
+ ```
108
+ cd ocaml; make test
109
+ ```
110
+
111
+ ### Testing
112
+
113
+ The tests use `test/round_trip.sh` to ensure that every tester file in `test/tests` round-trips correctly through parsing and pretty printing.
114
+
115
+ Additionally, you can run tests that compare the OCaml and Python implementations (after you've installed them both):
116
+
117
+ ```
118
+ cd test; make
119
+ ```
120
+
121
+ # How to use the parser
122
+
123
+ For Python, see [`python/rt.py`](https://github.com/mgree/libdash/blob/master/python/rt.py), an example tool that does a round-trip: shell syntax to AST back to shell syntax.
124
+
125
+ For OCaml, see [`ocaml/shell_to_json.ml`](https://github.com/mgree/libdash/blob/master/ocaml/shell_to_json.ml), a tool that parses shell syntax and produces JSON (using the [atdgen](https://opam.ocaml.org/packages/atdgen/) bindings).
126
+
127
+ The ideal low-level interface to use is `parsecmd_safe` in `parser.c`; you'll need to ensure that dash's initialization routines have been called and that the stack marks are managed correctly. Parsing the POSIX shell is a complicated affair: beyond the usual locale issues, aliases affect the lexer, so one must use `setalias` and `unalias` to manage any aliases that ought to exist.
128
+
129
+ # How work with the parsed nodes
130
+
131
+ The general AST is described in `nodes.h`. There are some tricky invariants around the precise formatting of control codes; the OCaml code shows some examples of working with the `args` fields in `ocaml/ast.ml`, which converts the C AST to an OCaml AST.
132
+
133
+ The OCaml tools `shell_to_json` and `json_to_shell` will produce JSON ASTs, allowing you to work with these ASTs in any language.
134
+
135
+ # Pretty printing
136
+
137
+ The pretty printer does its best to produce valid shell scripts, but it's possible to manually construct AST nodes that don't directly correspond to valid scripts.
138
+
139
+ For example, the Python AST `[[['Q', [['C', 34]]]]]` represents a quoted field containing a double quote character. Translated literally, this would yield the string `"""`, which is not a valid shell script. The pretty printer will instead automatically escape the inner quote, rendering `"\""`.
140
+
141
+ While the printer tries to get things right either way, you should use escapes to signal to the printer when to escape: you should use the Python AST `[[['Q', [['E', 34]]]]]` to mark the inner double quote as escaped.
142
+
143
+ # Known issues
144
+
145
+ We currently do not escape the character `!` (exclamation point). In an interactive shell, `!` is likely treated as a history substitution (and so should be escaped), but in a non-interactive shell, `!` is treated normally. We currently cater to non-interactive shells; eventually this behavior will be controllable.
@@ -59,3 +59,15 @@ The ideal low-level interface to use is `parsecmd_safe` in `parser.c`; you'll ne
59
59
  The general AST is described in `nodes.h`. There are some tricky invariants around the precise formatting of control codes; the OCaml code shows some examples of working with the `args` fields in `ocaml/ast.ml`, which converts the C AST to an OCaml AST.
60
60
 
61
61
  The OCaml tools `shell_to_json` and `json_to_shell` will produce JSON ASTs, allowing you to work with these ASTs in any language.
62
+
63
+ # Pretty printing
64
+
65
+ The pretty printer does its best to produce valid shell scripts, but it's possible to manually construct AST nodes that don't directly correspond to valid scripts.
66
+
67
+ For example, the Python AST `[[['Q', [['C', 34]]]]]` represents a quoted field containing a double quote character. Translated literally, this would yield the string `"""`, which is not a valid shell script. The pretty printer will instead automatically escape the inner quote, rendering `"\""`.
68
+
69
+ While the printer tries to get things right either way, you should use escapes to signal to the printer when to escape: you should use the Python AST `[[['Q', [['E', 34]]]]]` to mark the inner double quote as escaped.
70
+
71
+ # Known issues
72
+
73
+ We currently do not escape the character `!` (exclamation point). In an interactive shell, `!` is likely treated as a history substitution (and so should be escaped), but in a non-interactive shell, `!` is treated normally. We currently cater to non-interactive shells; eventually this behavior will be controllable.
@@ -1,4 +1,4 @@
1
- AC_INIT([dash],[0.5.11.5])
1
+ AC_INIT([dash],[0.5.13.3])
2
2
  AM_INIT_AUTOMAKE([foreign subdir-objects])
3
3
  AC_CONFIG_SRCDIR([src/main.c])
4
4
  AC_CONFIG_HEADERS(config.h)
@@ -10,10 +10,12 @@ dnl Checks for programs.
10
10
  AC_PROG_CC
11
11
  AC_USE_SYSTEM_EXTENSIONS
12
12
 
13
+ dnl AC_GNU_SOURCE
13
14
  AC_PROG_YACC
14
15
  dnl MMG 2018-09-26 support building the library
15
16
  AM_PROG_AR
16
17
 
18
+
17
19
  AC_MSG_CHECKING([for build system compiler])
18
20
  if test "$cross_compiling" = yes; then
19
21
  CC_FOR_BUILD=${CC_FOR_BUILD-cc}
@@ -38,17 +40,20 @@ fi
38
40
  AC_ARG_ENABLE(static, AS_HELP_STRING(--enable-static, \
39
41
  [Build statical linked program]))
40
42
  if test "$enable_static" = "yes"; then
41
- export LDFLAGS="-static -Wl,--fatal-warnings"
43
+ export LDFLAGS="-static"
42
44
  fi
43
45
 
44
46
  AC_ARG_ENABLE(fnmatch, AS_HELP_STRING(--enable-fnmatch, \
45
47
  [Use fnmatch(3) from libc]))
46
48
  AC_ARG_ENABLE(glob, AS_HELP_STRING(--enable-glob, [Use glob(3) from libc]))
49
+ AC_ARG_ENABLE(tee, AS_HELP_STRING(--disable-tee, [Do not use tee(2)]))
50
+ AC_ARG_ENABLE(memfd_create, AS_HELP_STRING(--disable-memfd-create,
51
+ [Do not use memfd_create(3)]))
47
52
 
48
53
  dnl Checks for libraries.
49
54
 
50
55
  dnl Checks for header files.
51
- AC_CHECK_HEADERS(alloca.h paths.h)
56
+ AC_CHECK_HEADERS(alloca.h paths.h sys/wait.h)
52
57
 
53
58
  dnl Check for declarations
54
59
  AC_CHECK_DECL([_PATH_BSHELL],,AC_DEFINE_UNQUOTED([_PATH_BSHELL], "/bin/sh", [Define to system shell path]),[
@@ -91,9 +96,9 @@ AC_CHECK_DECL([PRIdMAX],,
91
96
 
92
97
  dnl Checks for library functions.
93
98
  AC_CHECK_FUNCS(bsearch faccessat getpwnam getrlimit isalpha killpg \
94
- mempcpy \
99
+ memfd_create memrchr mempcpy \
95
100
  sigsetmask stpcpy strchrnul strsignal strtod strtoimax \
96
- strtoumax sysconf)
101
+ strtoumax sysconf tee wait3)
97
102
 
98
103
  dnl Check whether it's worth working around FreeBSD PR kern/125009.
99
104
  dnl The traditional behavior of access/faccessat is crazy, but
@@ -135,6 +140,24 @@ if test "$use_fnmatch" = yes && test "$enable_glob" = yes; then
135
140
  AC_CHECK_FUNCS(glob)
136
141
  fi
137
142
 
143
+ if test "$enable_tee" != no; then
144
+ AC_CHECK_FUNCS(tee, use_tee=yes)
145
+ fi
146
+
147
+ if test "$use_tee" = yes; then
148
+ AC_DEFINE([USE_TEE], [1], [Non-zero if tee(2) should be used])
149
+ else
150
+ AC_DEFINE([USE_TEE], [0], [Non-zero if tee(2) should be used])
151
+ fi
152
+
153
+ if test "$enable_memfd_create" != no; then
154
+ AC_DEFINE([USE_MEMFD_CREATE], [1],
155
+ [Non-zero if memfd_create(3) should be used])
156
+ else
157
+ AC_DEFINE([USE_MEMFD_CREATE], [0],
158
+ [Non-zero if memfd_create(3) should be used])
159
+ fi
160
+
138
161
  dnl Check for klibc signal.
139
162
  AC_CHECK_FUNC(signal)
140
163
  if test "$ac_cv_func_signal" != yes; then
@@ -144,10 +167,18 @@ if test "$ac_cv_func_signal" != yes; then
144
167
  fi
145
168
 
146
169
  dnl Check for stat64 (dietlibc/klibc).
147
- AC_CHECK_FUNC(stat64,, [
170
+ AC_CHECK_DECL(stat64, AC_CHECK_FUNC(stat64))
171
+ if test "$ac_cv_func_stat64" != yes; then
148
172
  AC_DEFINE(fstat64, fstat, [64-bit operations are the same as 32-bit])
149
173
  AC_DEFINE(lstat64, lstat, [64-bit operations are the same as 32-bit])
150
174
  AC_DEFINE(stat64, stat, [64-bit operations are the same as 32-bit])
175
+ fi
176
+
177
+ AC_CHECK_FUNC(glob64,, [
178
+ AC_DEFINE(glob64_t, glob_t, [64-bit operations are the same as 32-bit])
179
+ AC_DEFINE(glob64, glob, [64-bit operations are the same as 32-bit])
180
+ AC_DEFINE(globfree64, globfree,
181
+ [64-bit operations are the same as 32-bit])
151
182
  ])
152
183
 
153
184
  dnl OS X apparently has stat64 but not open64.
@@ -173,13 +204,25 @@ if test "$have_st_mtim" = "yes"; then
173
204
  [Define if your `struct stat' has `st_mtim'])
174
205
  fi
175
206
 
207
+ dnl F_DUPFD_CLOEXEC is a mandatory part of POSIX since Issue 7
208
+ AC_MSG_CHECKING(for F_DUPFD_CLOEXEC)
209
+ AC_COMPILE_IFELSE(
210
+ [AC_LANG_PROGRAM([#include <unistd.h>
211
+ #include <fcntl.h>],
212
+ [return fcntl(0, F_DUPFD_CLOEXEC, 0)])],
213
+ have_dupfd_cloexec=1, have_dupfd_cloexec=0)
214
+ AC_MSG_RESULT($(expr yes \& $have_dupfd_cloexec \| no))
215
+ AC_DEFINE_UNQUOTED([HAVE_F_DUPFD_CLOEXEC], [$have_dupfd_cloexec],
216
+ [Define to 1 your system supports F_DUPFD_CLOEXEC])
217
+
176
218
  AC_ARG_WITH(libedit, AS_HELP_STRING(--with-libedit, [Compile with libedit support]))
177
219
  use_libedit=
178
220
  if test "$with_libedit" = "yes"; then
179
221
  AC_CHECK_LIB(edit, history_init, [
180
222
  AC_CHECK_HEADER([histedit.h], [use_libedit="yes"],
181
223
  AC_MSG_ERROR(
182
- [Can't find required header files.]))])
224
+ [Can't find required header files.]))], [
225
+ AC_MSG_ERROR([Can't find libedit.])])
183
226
  fi
184
227
  if test "$use_libedit" != "yes"; then
185
228
  AC_DEFINE([SMALL], 1, [Define if you build with -DSMALL])
@@ -11,11 +11,11 @@ def libdash_library_path():
11
11
 
12
12
  if LIBDASH_LIBRARY_PATH is not None:
13
13
  return LIBDASH_LIBRARY_PATH
14
-
14
+
15
15
  FILE_PATH = os.path.dirname(os.path.realpath(os.path.abspath(__file__)))
16
16
  LIBDASH_LIBRARY_PATH = os.path.join(FILE_PATH, "libdash.so")
17
17
  return LIBDASH_LIBRARY_PATH
18
-
18
+
19
19
  EOF_NLEFT = -99; # libdash/src/input.c
20
20
 
21
21
  class ParsingException(Exception):
@@ -83,8 +83,9 @@ def parse(inputPath, init=True):
83
83
 
84
84
  # Last line did not have a newline
85
85
  assert (len (lines [-1]) > 0 and (lines [-1][-1] != '\n'))
86
- else:
87
- assert (nleft_after == 0); # Read whole lines
86
+ elif nleft_after != 0:
87
+ # we formerly asserted that `nleft_after != 0`, but this no longer holds
88
+ linno_after = linno_after + 1; # The last line wasn't counted
88
89
 
89
90
  n_ptr = cast (n_ptr_C, POINTER (union_node))
90
91
  new_ast = of_node (n_ptr)
@@ -15,6 +15,10 @@ STRING_OF_VAR_TYPE_DICT = {
15
15
  "Length" : "#"
16
16
  };
17
17
 
18
+ UNQUOTED = 0 # everything escaped
19
+ QUOTED = 1 # only escape special characters
20
+ HEREDOC = 2 # like QUOTED, but _don't_ escape double quotes
21
+ QUOTE_MODES = [UNQUOTED, QUOTED, HEREDOC]
18
22
 
19
23
  # dash.ml
20
24
  #
@@ -324,25 +328,27 @@ def escaped (param):
324
328
  # "${" ^ name ^ (if nul then ":" else "") ^ string_of_var_type vt ^ string_of_arg a ^ "}"
325
329
  # | Q a -> "\"" ^ string_of_arg a ^ "\""
326
330
  # | B t -> "$(" ^ to_string t ^ ")"
327
- def string_of_arg_char (c, is_quoted=False):
331
+ def string_of_arg_char (c, quote_mode=UNQUOTED):
328
332
  (type, param) = c;
329
333
 
330
334
  if (type == "E"):
331
335
  char = chr (param);
332
336
 
333
- ## MMG 2021-09-20 It might be safe to move everything except for " in the second list, but no need to do it if the tests pass
337
+ ## MMG 2021-09-20 It might be safe to move everything except for " in the second list, but no need to do it if the tests pass
338
+ ## '!' dropped for bash non-interactive bash compatibility
334
339
  ## Chars to escape unconditionally
335
- chars_to_escape = ["'", '"', '`', '(', ')', '{', '}', '$', '!', '&', '|', ';']
340
+ chars_to_escape = ["'", '"', '`', '(', ')', '{', '}', '$', '&', '|', ';']
336
341
  ## Chars to escape only when not quoted
337
342
  chars_to_escape_when_no_quotes = ['*', '?', '[', ']', '#', '<', '>', '~', ' ']
338
343
  if char in chars_to_escape:
339
344
  return '\\' + char
340
- elif char in chars_to_escape_when_no_quotes and not is_quoted:
345
+ elif char in chars_to_escape_when_no_quotes and quote_mode==UNQUOTED:
341
346
  return '\\' + char
342
347
  else:
343
348
  return escaped (param)
344
349
  elif (type == "C"):
345
- if chr(param) == '"':
350
+ # HEREDOC should never escape double quotes per POSIX 2.7.4
351
+ if quote_mode==QUOTED and chr(param) == '"':
346
352
  return '\\"'
347
353
  else:
348
354
  return chr (param);
@@ -360,7 +366,7 @@ def string_of_arg_char (c, is_quoted=False):
360
366
  print ("Unexpected param for T: %s" % param);
361
367
  abort ();
362
368
  elif (type == "A"):
363
- return "$((" + string_of_arg (param, is_quoted) + "))";
369
+ return "$((" + string_of_arg (param, quote_mode) + "))";
364
370
  elif (type == "V"):
365
371
  assert (len (param) == 4);
366
372
  if (param [0] == "Length"):
@@ -381,13 +387,20 @@ def string_of_arg_char (c, is_quoted=False):
381
387
  else:
382
388
  os.abort (); # For my own sanity
383
389
 
384
- stri += string_of_var_type (vt) + string_of_arg (a, is_quoted) + "}";
390
+ stri += string_of_var_type (vt) + string_of_arg (a, quote_mode) + "}";
385
391
 
386
392
  return stri;
387
393
  elif (type == "Q"):
388
- return "\"" + string_of_arg (param, is_quoted=True) + "\"";
394
+ return "\"" + string_of_arg (param, quote_mode=QUOTED) + "\"";
389
395
  elif (type == "B"):
390
- return "$(" + to_string (param) + ")";
396
+ body = to_string (param)
397
+ # to handle $( () )
398
+ try:
399
+ if body[0] == "(" and body[-1] == ")":
400
+ body = f" {body} "
401
+ except IndexError:
402
+ pass
403
+ return "$(" + body + ")"
391
404
  else:
392
405
  abort ();
393
406
 
@@ -395,21 +408,14 @@ def string_of_arg_char (c, is_quoted=False):
395
408
  # and string_of_arg = function
396
409
  # | [] -> ""
397
410
  # | c :: a -> string_of_arg_char c ^ string_of_arg a
398
- def string_of_arg (args, is_quoted=False):
411
+ def string_of_arg (args, quote_mode=UNQUOTED):
399
412
  # print (args);
400
413
 
401
414
  i = 0
402
415
  text = []
403
416
  while i < len(args):
404
- c = string_of_arg_char(args[i], is_quoted)
405
-
406
- # dash will parse '$?' as
407
- # [(C, '$'), (E, '?')]
408
- # but we don't normally want to escape ?
409
- #
410
- # so we check up after the fact: if the character after $ is escaped,
411
- # we'll escape the $, too
412
- if c == "$" and (i+1 < len(args)) and args[i+1][0] == "E":
417
+ c = string_of_arg_char(args[i], quote_mode=quote_mode)
418
+ if c == "$" and (i+1 < len(args)):
413
419
  c = "\\$"
414
420
  text.append(c)
415
421
 
@@ -526,7 +532,8 @@ def string_of_redir (redir):
526
532
  elif (type == "Heredoc"):
527
533
  (t, fd, a) = params;
528
534
 
529
- heredoc = string_of_arg (a, is_quoted = True);
535
+ # MMG 2022-08-23 not quite correct
536
+ heredoc = string_of_arg (a, quote_mode=HEREDOC);
530
537
  marker = fresh_marker0 (heredoc);
531
538
 
532
539
  stri = show_unless (0, fd) + "<<";
@@ -0,0 +1,145 @@
1
+ Metadata-Version: 2.1
2
+ Name: libdash
3
+ Version: 0.4.0
4
+ Summary: Bindings for the dash shell as a library
5
+ Author: PaSh contributors
6
+ Author-email: Michael Greenberg <michael@greenberg.science>
7
+ License: Copyright (c) 1989-1994
8
+ The Regents of the University of California. All rights reserved.
9
+ Copyright (c) 1997 Christos Zoulas. All rights reserved.
10
+ Copyright (c) 1997-2005
11
+ Herbert Xu <herbert@gondor.apana.org.au>. All rights reserved.
12
+
13
+ This code is derived from software contributed to Berkeley by Kenneth Almquist.
14
+
15
+
16
+ Redistribution and use in source and binary forms, with or without
17
+ modification, are permitted provided that the following conditions
18
+ are met:
19
+ 1. Redistributions of source code must retain the above copyright
20
+ notice, this list of conditions and the following disclaimer.
21
+ 2. Redistributions in binary form must reproduce the above copyright
22
+ notice, this list of conditions and the following disclaimer in the
23
+ documentation and/or other materials provided with the distribution.
24
+ 3. Neither the name of the University nor the names of its contributors
25
+ may be used to endorse or promote products derived from this software
26
+ without specific prior written permission.
27
+
28
+ THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
29
+ ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
30
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
31
+ ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
32
+ FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
33
+ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
34
+ OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
35
+ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
36
+ LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
37
+ OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
38
+ SUCH DAMAGE.
39
+
40
+ mksignames.c:
41
+
42
+ This file is not directly linked with dash. However, its output is.
43
+
44
+ Copyright (C) 1992 Free Software Foundation, Inc.
45
+
46
+ This file is part of GNU Bash, the Bourne Again SHell.
47
+
48
+ Bash is free software; you can redistribute it and/or modify it under
49
+ the terms of the GNU General Public License as published by the Free
50
+ Software Foundation; either version 2, or (at your option) any later
51
+ version.
52
+
53
+ Bash is distributed in the hope that it will be useful, but WITHOUT ANY
54
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or
55
+ FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
56
+ for more details.
57
+
58
+ You should have received a copy of the GNU General Public License with
59
+ your Debian GNU/Linux system, in /usr/share/common-licenses/GPL, or with the
60
+ Debian GNU/Linux hello source package as the file COPYING. If not,
61
+ write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330,
62
+ Boston, MA 02111 USA.
63
+
64
+ Project-URL: Homepage, https://github.com/binpash/libdash
65
+ Project-URL: Bug Tracker, https://github.com/binpash/libdash/issues
66
+ Classifier: Programming Language :: Python :: 3
67
+ Classifier: Topic :: System :: System Shells
68
+ Classifier: Operating System :: POSIX
69
+ Requires-Python: >=3.7
70
+ Description-Content-Type: text/markdown
71
+ License-File: COPYING
72
+
73
+ [![Main workflow](https://github.com/mgree/libdash/actions/workflows/build.yml/badge.svg)](https://github.com/mgree/libdash/actions/workflows/build.yml)
74
+
75
+ *libdash* is a fork of the Linux Kernel's `dash` shell that builds a linkable library with extra exposed interfaces. The primary use of libdash is to parse shell scripts, but it could be used for more.
76
+
77
+ The Python bindings are packaged as the [`libdash` PyPi package](https://pypi.org/project/libdash/).
78
+
79
+ The OCaml bindings---packaged as the [`libdash` OPAM package](https://opam.ocaml.org/packages/libdash/)---include two executables, `shell_to_json` and `json_to_shell`, which let you conveniently parse POSIX shell scripts into a JSON AST.
80
+
81
+ # What are the dependencies?
82
+
83
+ The C code for dash should build on a wide variety of systems; it requires `libtool` and `autotools` (`aclocal`, `autoheader`, `automake`, `autoconf`). The library may not build on platforms with esoteric linkers; it's been tested on macOS and Linux.
84
+
85
+ The Python and OCaml bindings depend on being able to build the C code. See `libdash.opam` for details on the OCaml code's dependencies, which includes the build-time external dependencies. Python wheels have no need for these build-time dependencies, but building from a Python source distribution will only succeed when `libtool` and `autotools` are present.
86
+
87
+ The CI scripts (in `.github/workflows/build.yml`) give build details.
88
+
89
+ ## How to build `libdash` from source
90
+
91
+ ### Python
92
+
93
+ Run `python3 setup.py install`. On macOS, you must first install the build dependencies via `brew install libtool autoconf automake`.
94
+
95
+ You can test the Python bindings by running:
96
+
97
+ ```
98
+ cd python; make test
99
+ ```
100
+
101
+ ### OCaml
102
+
103
+ Install the OPAM file: `opam pin add .` or `opam install .`. This will build the OCaml library and install it in your OPAM repository. There are tests in another directory; they will only build when libdash is actually installed.
104
+
105
+ You can test the OCaml bindings by running:
106
+
107
+ ```
108
+ cd ocaml; make test
109
+ ```
110
+
111
+ ### Testing
112
+
113
+ The tests use `test/round_trip.sh` to ensure that every tester file in `test/tests` round-trips correctly through parsing and pretty printing.
114
+
115
+ Additionally, you can run tests that compare the OCaml and Python implementations (after you've installed them both):
116
+
117
+ ```
118
+ cd test; make
119
+ ```
120
+
121
+ # How to use the parser
122
+
123
+ For Python, see [`python/rt.py`](https://github.com/mgree/libdash/blob/master/python/rt.py), an example tool that does a round-trip: shell syntax to AST back to shell syntax.
124
+
125
+ For OCaml, see [`ocaml/shell_to_json.ml`](https://github.com/mgree/libdash/blob/master/ocaml/shell_to_json.ml), a tool that parses shell syntax and produces JSON (using the [atdgen](https://opam.ocaml.org/packages/atdgen/) bindings).
126
+
127
+ The ideal low-level interface to use is `parsecmd_safe` in `parser.c`; you'll need to ensure that dash's initialization routines have been called and that the stack marks are managed correctly. Parsing the POSIX shell is a complicated affair: beyond the usual locale issues, aliases affect the lexer, so one must use `setalias` and `unalias` to manage any aliases that ought to exist.
128
+
129
+ # How work with the parsed nodes
130
+
131
+ The general AST is described in `nodes.h`. There are some tricky invariants around the precise formatting of control codes; the OCaml code shows some examples of working with the `args` fields in `ocaml/ast.ml`, which converts the C AST to an OCaml AST.
132
+
133
+ The OCaml tools `shell_to_json` and `json_to_shell` will produce JSON ASTs, allowing you to work with these ASTs in any language.
134
+
135
+ # Pretty printing
136
+
137
+ The pretty printer does its best to produce valid shell scripts, but it's possible to manually construct AST nodes that don't directly correspond to valid scripts.
138
+
139
+ For example, the Python AST `[[['Q', [['C', 34]]]]]` represents a quoted field containing a double quote character. Translated literally, this would yield the string `"""`, which is not a valid shell script. The pretty printer will instead automatically escape the inner quote, rendering `"\""`.
140
+
141
+ While the printer tries to get things right either way, you should use escapes to signal to the printer when to escape: you should use the Python AST `[[['Q', [['E', 34]]]]]` to mark the inner double quote as escaped.
142
+
143
+ # Known issues
144
+
145
+ We currently do not escape the character `!` (exclamation point). In an interactive shell, `!` is likely treated as a history substitution (and so should be escaped), but in a non-interactive shell, `!` is treated normally. We currently cater to non-interactive shells; eventually this behavior will be controllable.
@@ -75,6 +75,7 @@ src/system.c
75
75
  src/system.h
76
76
  src/trap.c
77
77
  src/trap.h
78
+ src/type_description.ml
78
79
  src/var.c
79
80
  src/var.h
80
81
  src/bltin/bltin.h
@@ -1,23 +1,24 @@
1
1
  [project]
2
2
  name = "libdash"
3
- version = "0.3"
3
+ version = "0.4.0"
4
4
  authors = [
5
5
  { name="Michael Greenberg", email="michael@greenberg.science" },
6
+ { name="PaSh contributors" },
6
7
  ]
8
+ license = { file = "COPYING" }
7
9
  description = "Bindings for the dash shell as a library"
8
10
  readme = "README.md"
9
- license = { file="COPYING" }
10
11
  requires-python = ">=3.7"
11
12
  classifiers = [
12
13
  "Programming Language :: Python :: 3",
13
14
  "Topic :: System :: System Shells",
14
- "License :: OSI Approved :: MIT License",
15
15
  "Operating System :: POSIX",
16
16
  ]
17
17
 
18
+
18
19
  [project.urls]
19
- "Homepage" = "https://github.com/mgree/libdash"
20
- "Bug Tracker" = "https://github.com/mgree/libdash/issues"
20
+ "Homepage" = "https://github.com/binpash/libdash"
21
+ "Bug Tracker" = "https://github.com/binpash/libdash/issues"
21
22
 
22
23
  [build-system]
23
24
  requires = ["setuptools>=61.0"]