Compare commits

..
3 Commits
Author SHA1 Message Date
Stephen Dolan 6ed2da6d43 Merge pull request #132 from dolmen/fix/github-urls
Fix Github URLs: stedolan.github.com -> stedolan.github.io
2013-05-23 09:16:34 -07:00
Olivier Mengué 444f0aacca Fix Github URLs: stedolan.github.com -> stedolan.github.io 2013-05-23 09:36:54 +02:00
Stephen Dolan 22006172ba fix typo and clean up docs build 2013-05-20 13:24:48 +01:00
76 changed files with 3927 additions and 7292 deletions

No files matched your search

+1 -24
View File
@@ -1,13 +1,5 @@
*.o
*.a
*.lo
*.la
*.lai
*.so
*.so.*
*~
.*.sw[a-p]
tags
jq
jq.1
@@ -22,30 +14,15 @@ parser.c
parser.h
# Autotools junk
.libs
.deps
libtool
*.log
stamp-h1
config.log
config.status
autom4te.cache
INSTALL
config.h
Makefile
jq-*.tar.gz
configure
aclocal.m4
Makefile.in
version.h
.remake-version-h
config.cache
*.rpm
m4/libtool.m4
m4/ltoptions.m4
m4/ltsugar.m4
m4/ltversion.m4
m4/lt~obsolete.m4
cscope.in.out
cscope.out
cscope.po.out
-17
View File
@@ -1,17 +0,0 @@
language: c
before_script:
- sudo apt-get install -qq valgrind
- bundle install --gemfile=docs/Gemfile
- autoreconf -i
script:
- ./setup.sh
- ./configure && make
compiler:
- gcc
- clang
notifications:
email: false
+3 -28
View File
@@ -1,31 +1,6 @@
Created By:
Stephen Dolan <mu@netsoc.tcd.ie>
Maintained by:
Nicolas Williams <nico@cryptonector.com>
Contributions by:
Anthony Shortland <anthony.shortland@me.com> - rpmbuild target
Lee Thompson <stagr.lee@gmail.com> - autoconf stuff
Santiago Lapresta <santiago.lapresta@gmail.com> - join, arrays, all, any, other filters
Nicolas Williams <nico@cryptonector.com> - library-fication, autoconf stuff, various
Jingwen Owen Ou <jingweno@gmail.com> - jqplay.org and link to it
Andrew Rodland <andrew@cleverdomain.org> - bug fixes
Ankur <ankz.kothari@gmail.com> - bug fixes
Brendan Macmillan <melbourne.research@gmail.com> - bug fixes, load library from ~/.jq
David R. MacIver <david@drmaciver.com> - bug fixes
Filippo Giunchedi <fgiunchedi@gmail.com> - bug fixes
Filippo Valsorda <filippo.valsorda@gmail.com> - recursive object merge (`*`)
Jack Pearkes <jackpearkes@gmail.com> - update tutorial
Joe Littlejohn <joe.littlejohn@nokia.com> - bug fixes
Juan Guerrero <juan.guerrero.lozano@gmail.com> - bug fixes
Kenny Shen <kenny.shen@zalora.com> - doc fixes
Markus Lanthaler <mark_lanthaler@gmx.net> - doc fixes
Michael Daines <michael@mdaines.com> - add sqrt; doc fixes
Mike McCabe <mccabe@archive.org> - math (libm) functions
Nicolas Pouillard <nicolas.pouillard@gmail.com> - add tests
Peter van Dijk <peter@7bits.nl> - doc fixes
Philipp Hagemeister <phihag@phihag.de> - doc fixes
polyester <paul@cleanclothes.org> - automake version update
Rémy Léone <remy.leone@gmail.com> - add .travis.yml
Ryoichi KATO <ryo1kato@gmail.com> - doc fixes
Contributions by
Anthony Shortland <anthony.shortland@me.com> - rpmbuild target
Lee Thompson <stagr.lee@gmail.com> - autoconf stuff
-617
View File
@@ -1,617 +0,0 @@
2014-06-09 Nicolas Williams <nico@cryptonector.com>
Add libm.h to dist file list
Add note about cmd.exe quoting
Building docs fails on powerpc (#349)
2014-06-08 Nicolas Williams <nico@cryptonector.com>
Update site news
Also fix configure.ac to use git describe --tags
Fix scripts/version: use git describe --tags ...
After tagging as 1.4 scripts/version was still producing jq-1.3-....
Add `indices(s)`, improve `index(s)`, `rindex(s)`
Now these deal with arrays as input and `s` being an array or a scalar.
Improve `index` and `rindex` examples
Remove reference to `getpath` from docs
Document `index` and `rindex` (#389)
2014-06-07 Santiago Lapresta <santiago.lapresta@gmail.com>
Added `join` function
2014-06-07 Nicolas Williams <nico@cryptonector.com>
String * number should be commutative
2014-06-04 Nicolas Williams <nico@cryptonector.com>
Add cross-compilation notes to README
A detailed set of instruction as to how to setup a cross-compilation
environment for OS X and Win32/64 would be nice.
Add -j option to scripts/crosscompile
Add flags argument to jv_parser_new()
For extensibility. We might add streaming parser options, even binary
JSON encoding options.
2014-06-02 Nicolas Williams <nico@cryptonector.com>
Fix tests failures on Windows
And Solaris 8 and 9 too, no doubt. The problem was that non-standard
vsnprintf()s that return -1 when the buffer is too small were not
properly supported.
2014-05-20 Santiago Lapresta <santiago.lapresta@gmail.com>
Documented `del` command
2014-05-11 Santiago Lapresta <santiago.lapresta@gmail.com>
Added texts/examples to unique_by function
Added unique_by function
2014-04-17 Nicolas Williams <nico@cryptonector.com>
Make pthread tls configurable for Mingw build
For the Mingw build we don't want to pull in the pthread DLL just
because we can autodetect pthread support. That would make the jq.exe
binary not self-contained.
2014-04-16 Nicolas Williams <nico@cryptonector.com>
Add autoconf checks for pthreads; fix #340
2014-03-20 Jingwen Owen Ou <jingweno@gmail.com>
Add link to jqplay
2014-03-13 Nicolas Williams <nico@cryptonector.com>
Fix for #303 in the sources
2014-03-13 Santiago Lapresta <santiago.lapresta@gmail.com>
Added `arrays` and other filters
Arrays, objects, numbers, strings, booleans, nulls, values (non-nulls)
-- these builtins filter out those inputs that don't match the name of
the builtin.
This fixes #322 and #324.
2014-03-07 Filippo Valsorda <filippo.valsorda@gmail.com>
Add a recursive object merge strategy and bind it to *
This commit adds a jv_object_merge_recursive function, that performs
recursive object merging, and binds it to multiply when applied to
two objects.
Closes #320
2014-03-06 Nicolas Williams <nico@cryptonector.com>
Make libm tests more portable
2014-02-26 Andrew Rodland <andrew@cleverdomain.org>
Repair jv_show
2014-02-26 Andrew Rodland <andrew@cleverdomain.org>
Make jq --raw-output --unbuffered work
--unbuffered was only affecting the normal output case, not the --raw-output case. Make the two of them play together.
This also makes sure that the output is flushed *after* printing the newline, so a consumer doesn't lag a line behind.
2014-02-21 Nicolas Williams <nico@cryptonector.com>
Add cbrt (cube root)
Add missing trig functions and barebones test
Remove non-standard exp10()
2014-02-21 Mike McCabe <mccabe@archive.org>
Initial add of math functions.
2014-02-20 Nicolas Williams <nico@cryptonector.com>
Add `?`, `.[]?`, and `..` operators
Make XPath-like `//a/b` recursive structure traversal easier in jq,
which then becomes:
..|.a?.b?
The `?` operator suppresses errors about . not being an array or object.
The `..` operator is equivalent to calling the new `recurse_down`
built-in, which in turn is equivalent to
recurse(.[]?)
Note that `..a` is not supported; neither is `...a`. That could be add
added, but it doesn't seem worth the trouble of saving the need to type
a '|'.
2014-02-16 Santiago Lapresta <santiago.lapresta@gmail.com>
Added `all` and `any` builtins
2014-01-25 polyester <paul@cleanclothes.org>
work with newer versions of automake
when using a newer automake, the autoreconf step fails with warnings:
"linking libtool libraries using a non-POSIX archiver requires 'AM_PROG_AR' in 'configure.ac' "
This happens for instance on ubuntu 13.10.
Doing just that, adding 'AM_PROG_AR' to configure.ac fixes the problem.
2014-01-01 Nicolas Williams <nico@cryptonector.com>
Fix #201; check that bison accepts --warnings
2013-12-27 Joe Littlejohn <joe.littlejohn@nokia.com>
Fix rpm build (`make rpm`)
* Re-add VERSION as it's required for `./setup superclean`
and `make rpm`.
* Add *.rpm to git ignore, we never want them under version control.
2013-12-27 Filippo Giunchedi <fgiunchedi@gmail.com>
include additional files in jq.spec
this will probably need changing upon SONAME bump
fix rpm Makefile target and prerequisites
depend on dist and the specfile, plus use automake's variables
2013-12-26 Nicolas Williams <nico@cryptonector.com>
Document --version
2013-12-26 Nicolas Williams <nico@cryptonector.com>
Add jv_dumpf() and jv_show()
jv_dumpf() takes a FILE *.
jv_show() is intended for use in debuggers, so it dumps the jv to stderr
and it does not jv_free() the jv, so it's safe to
"call jv_show(some_jv, -1)" in a debugger. If flags == -1 then the jv
will be shown pretty-printed and in color.
2013-12-26 Nicolas Williams <nico@cryptonector.com>
Document .foo.bar in manual
Document exit numbers
Normalize errors for -e
2013-12-25 Nicolas Williams <nico@cryptonector.com>
Fix doc typos (.[foo] wanted to be .["foo"])
Add note to jq.1 about shell quoting
2013-12-20 Philipp Hagemeister <phihag@phihag.de>
Ignore the config/test-driver file
This file is automatically generated and does not need to be committed.
Fix @uri example
Previously, the @uri example didn't match the actual behavior of the current jq, as exclamation marks do not need to be encoded in URIs.
Replace the example with an input that needs encoding, and is encoded by jq.
2013-12-17 Stephen Dolan <mu@netsoc.tcd.ie>
Allow negated object values without parens. Fixes #247
2013-12-17 Nicolas Williams <nico@cryptonector.com>
Fix memmem() error
2013-12-13 Rémy Léone <remy.leone@gmail.com>
Adding a .travis.yml file to use the travis-ci.org
From wikipedia:
Travis CI is a hosted, distributed continuous integration service used
to build and test projects hosted at GitHub.
Travis CI is configured by adding a file named .travis.yml, which is a
YAML format text file, to the root directory of the GitHub repository.
Travis CI automatically detects when a commit has been made and pushed
to a GitHub repository that is using Travis CI, and each time this
happens, it will try to build the project and run tests. This includes
commits to all branches, not just to the master branch. When that
process has completed, it will notify a developer in the way it has been
configured to do so — for example, by sending an email containing the
test results (showing success or failure), or by posting a message on an
IRC channel. It can be configured to run the tests on a range of
different machines, with different software installed (such as older
versions of a programming language, to test for compatibility).
2013-12-13 Stephen Dolan <mu@netsoc.tcd.ie>
Make the testsuite run on machines without valgrind
Format more integers as integers, not scientific notation.
jq is now willing to put up to 15 zeros after an integer before
moving to scientific notation.
2013-12-11 Nicolas Williams <nico@cryptonector.com>
Complete more-arity feature not complete
And test
2013-12-10 David R. MacIver <david@drmaciver.com>
convert range bounds to integers in a way that avoids undefined behaviour
add checking of numeric indices to an array to see if they can reasonably be considered integers. Avoid undefined behaviour if out of bounds
2013-12-09 David R. MacIver <david@drmaciver.com>
some functions were missing prototypes. Add them
2013-12-08 David R. MacIver <david@drmaciver.com>
These vfprintfs are being used as if they were printfs. Fix that
consistent use of goto out in main
2013-12-08 Stephen Dolan <mu@netsoc.tcd.ie>
Refactor jv structure.
New structure layout is simpler and also faster. In particular, it's
now small enough to be passed in registers on amd64.
Make testsuite not leak when compiled with -DNDEBUG.
2013-12-08 David R. MacIver <david@drmaciver.com>
test for losing memory on compile errors
args to jq_compile_args were not getting freed when there were errors in the compile
2013-12-06 Nicolas Williams <nico@cryptonector.com>
Fix double-free typo in print_error()
Fix manual.yml
2013-12-04 Nicolas Williams <nico@cryptonector.com>
Conditionally #define _GNU_SOURCE in compile.c
Add tests for string index by string and builtins
Add index and rindex builtins
Add index strings by string; return string indexes
% jq '.[","]'
"a,bc,def,ghij,klmno"
[1,4,8,13]
%
Make length return abs value of numeric inputs
Add callback interface for errors
Printing to stderr is not the right answer for a library.
Add jv_string_vfmt()
Document ltrimstr and rtrimstr
Test ltrimstr and rtrimstr functions
Add ltrimstr and rtrimstr functions
Document -e / --exit-status argument
Add -e | --exit-status CLI option
Document tojson and fromjson builtins
Test tojson and fromjson
Add tojson and fromjson builtins
Document split function
Document string multiplication and division
Document string functions and slicing
Test string slicing
Add string slicing
Add tests for string division/splitting
Add string division by string (split on separator)
Test starts/endswith and string multiplication
Add string multiplication by number
Add startswith/endswith
Add explode/implode jq functions to match jv API
Use uint32_t for codepoint in jv_string_append_codepoint()
Add jv string utility functions
jv_string_empty()
-> return an empty string with given allocated length (for fast
appends)
jv_string_append_codepoint
-> append a single codepoint (int) to the given string
jv_string_explode
-> return an array of codepoints making up a string
jv_string_implode
-> return the UTF-8 encoding of an array of codepoint numbers
Support more arguments for defs
2013-12-04 Stephen Dolan <mu@netsoc.tcd.ie>
Preserve insertion order in objects. Closes #169.
2013-11-30 Nicolas Pouillard <nicolas.pouillard@gmail.com>
Add a few more test cases (from the man page)
2013-11-08 Stephen Dolan <mu@netsoc.tcd.ie>
Add a --unbuffered option. Closes #206
2013-11-07 Peter van Dijk <peter@7bits.nl>
count should be length
Example refers to a count function, which does not exist. Replacing it with length works.
2013-11-07 Stephen Dolan <mu@netsoc.tcd.ie>
Fix a crash on group_by of empty list. Fixes #208.
2013-10-16 Ryoichi KATO <ryo1kato@gmail.com>
Docs: add description of --from-file option
2013-10-06 Juan Guerrero <juan.guerrero.lozano@gmail.com>
Fix typo on error message
2013-09-19 Kenny Shen <kenny.shen@zalora.com>
Add missing -i flag in build instructions
2013-09-14 Michael Daines <michael@mdaines.com>
Add test showing calculation of standard deviation
2013-09-13 Mike Daines <michael@mdaines.com>
Fix typo
2013-09-11 Michael Daines <michael@mdaines.com>
Add sqrt operator
2013-09-04 Jack Pearkes <jackpearkes@gmail.com>
docs: update the tutorial to use GitHub's API
2013-09-01 Ankur <ankz.kothari@gmail.com>
Call AM_INIT_AUTOMAKE once only
Fixes build with automake-1.14
2013-08-19 Joe Littlejohn <joe.littlejohn@nokia.com>
Fix Makefile after refactoring of stacks in 05d90517b02
2013-06-23 Stephen Dolan <mu@netsoc.tcd.ie>
Remove #includes from jv.h
Fix the jv_parser interface.
Use libtool's built-in symbol exporting rather than a mapfile.
Move gen_utf8_tables to scripts
Move libtool m4 junk to config/ and delete some autogenerated files.
Remove Autoconf-generated config.h.
2013-06-22 Stephen Dolan <mu@netsoc.tcd.ie>
Build libjq only once, and link it statically to ./jq
This means ./jq is a real binary rather than a libtool turd.
Fix distcheck.
Update list of files to be distributed.
Utf8 fixes. Closes #161
Reject all overlong UTF8 sequences.
Fix various UTF8 parsing bugs.
In particular, parse bad UTF8 by replacing the broken bits with U+FFFD
and resychronise correctly after broken sequences.
Fix example in manual for `floor`. See #155.
2013-06-21 Nicolas Williams <nico@cryptonector.com>
Document floor
Add floor operator
Document mod
Add mod (and setmod) operators
Update .gitignore
Add libjq autoconf goo
Quiet setup.sh re: tmp dir
2013-06-21 Stephen Dolan <mu@netsoc.tcd.ie>
Move cfunction invocation code to the interpreter loop.
2013-06-18 Nicolas Williams <nico@cryptonector.com>
Fix serious bug in handling of --argfile
Fix leaks in jv_load_file()
2013-06-17 Stephen Dolan <mu@netsoc.tcd.ie>
Fold opcode.{c,h} into bytecode.{c,h}
Simplify block functions for variables
Saner build instructions in README.md
Closes #144
Remove some initialise-to-zero code.
This lets valgrind find more bugs - if a field isn't given a
well-defined value valgrind will now find it instead of seeing it
set to zero with memset.
2013-06-17 Nicolas Williams <nico@cryptonector.com>
Remove accidentally introduced use of fopen "e"
2013-06-16 Stephen Dolan <mu@netsoc.tcd.ie>
Merge pull request #114 from nicowilliams/nomem_handler
Add jv_nomem_handler()
2013-06-16 Nicolas Williams <nico@cryptonector.com>
Remove last remnant of main.h
2013-06-15 Nicolas Williams <nico@cryptonector.com>
Allow --run-tests to take a file argument
Fixup API to get closer to a libjq
2013-06-15 Nicolas Williams <nico@cryptonector.com>
Move slurp_file() into library as jv_load_file()
Needed as part of creating a libjq.
2013-06-14 Stephen Dolan <mu@netsoc.tcd.ie>
Clean up lots of stack and frame logic.
Move frame defs to execute.c
2013-06-13 Stephen Dolan <mu@netsoc.tcd.ie>
Simplify frame logic.
Unify all stacks. Passes tests, but needs cleanup.
2013-06-11 Stephen Dolan <mu@netsoc.tcd.ie>
Support ."foo" syntax for accessing fields. See #141.
2013-06-09 Stephen Dolan <mu@netsoc.tcd.ie>
Unify frame and data stacks
2013-06-05 Stephen Dolan <mu@netsoc.tcd.ie>
Speed up cached configure (./configure -C)
Clean up flex lines in build
Lex and parse .foo better.
'.as' is now valid, '. foo' is now invalid. See #141.
2013-06-04 Markus Lanthaler <mark_lanthaler@gmx.net>
Update README.md
Update the link to the documentation. All GitHub pages are now using the github.io domain.
2013-06-03 Stephen Dolan <mu@netsoc.tcd.ie>
Make jq --version print to stdout, not stderr
Better error handling for .foo case in parser. See #141.
Let the parser rather than the lexer handle invalid characters.
Add command-line option to sort object keys.
Closes #79.
Clean up Makefile.am (distcheck, rebuild version.h less often)
2013-05-31 Brendan Macmillan <melbourne.research@gmail.com>
Stop warning on fgets, simple version
Stop warning on fgets, complex version
2013-05-31 Stephen Dolan <mu@netsoc.tcd.ie>
Squash a warning on some GCC versions
2013-05-29 Stephen Dolan <mu@netsoc.tcd.ie>
Support for printing object keys in sorted order.
No command-line option to enable this yet. See #79.
2013-05-29 Brendan Macmillan <melbourne.research@gmail.com>
Bugfix multiline off-by-one (locfile.c)
locfile.h -> locfile.h + locfile.c
clean up includes of a few files
Hack bugfix for multiline off-by-one (locfile.c)
Load library from ~/.jq
2013-05-24 Stephen Dolan <mu@netsoc.tcd.ie>
Make jq --version report an actual git revision.
Closes #129.
2013-05-23 Nicolas Williams <nico@cryptonector.com>
Add --argfile variant of --arg (issue #117)
This is useful when one has a database (in JSON form) to query using jq
input data.
% echo '{"a":1, "c":5}' > db.json
% echo '"c"'|./jq --argfile f /tmp/a '$f[.]'
5
% echo '"a"'|./jq --argfile f /tmp/a '$f[.]'
1
% echo '"b"'|./jq --argfile f /tmp/a '$f[.]'
null
%
2013-05-23 Stephen Dolan <mu@netsoc.tcd.ie>
'make clean' won't delete jq.1 if it can't be rebuilt.
See #131
+28 -52
View File
@@ -1,12 +1,13 @@
### C source files to be built and distributed.
LIBJQ_INCS = jq_parser.h builtin.h bytecode.h compile.h exec_stack.h \
libm.h jv_alloc.h jv_dtoa.h jv_unicode.h locfile.h \
opcode_list.h parser.y jv_utf8_tables.h lexer.l
JQ_INCS = jq_parser.h builtin.h bytecode.h compile.h execute.h \
forkable_stack.h frame_layout.h jv.h jv_alloc.h jv_aux.h jv_dtoa.h \
jv_parse.h jv_unicode.h locfile.h opcode.h opcode_list.h parser.y \
jv_utf8_tables.h lexer.l
LIBJQ_SRC = locfile.c bytecode.c compile.c execute.c builtin.c jv.c \
jv_parse.c jv_print.c jv_dtoa.c jv_unicode.c jv_aux.c jv_file.c \
jv_alloc.c jq_test.c ${LIBJQ_INCS}
JQ_SRC = opcode.c bytecode.c compile.c execute.c builtin.c jv.c \
jv_parse.c jv_print.c jv_dtoa.c jv_unicode.c jv_aux.c jv_alloc.c \
jq_test.c ${JQ_INCS}
### C build options
@@ -14,15 +15,14 @@ LIBJQ_SRC = locfile.c bytecode.c compile.c execute.c builtin.c jv.c \
AM_CFLAGS = -Wextra -Wall -Wno-missing-field-initializers \
-Wno-unused-parameter -Wno-unused-function
ACLOCAL_AMFLAGS = -I config/m4
### Generating the lexer and parser
# While there is some autoconf macro support for lex/flex, it doesn't support
# header file creation so we'll use good old make
BUILT_SOURCES = lexer.h lexer.c parser.h parser.c version.h
BUILT_SOURCES = lexer.h lexer.c parser.h parser.c
lexer.c: lexer.l
$(AM_V_LEX) flex -o lexer.c --header-file=lexer.h $<
flex -o lexer.c --header-file=lexer.h $<
lexer.h: lexer.c
# Tell YACC (bison) autoconf macros that you want a header file created.
@@ -30,31 +30,14 @@ lexer.h: lexer.c
# OSX ships an old bison, so update with homebrew or macports
AM_YFLAGS = --warnings=all -d
### libjq
lib_LTLIBRARIES = libjq.la
libjq_la_SOURCES = ${LIBJQ_SRC}
libjq_la_LIBADD = -lm
libjq_la_LDFLAGS = -export-symbols-regex '^j[qv]_' -version-info 1:4:0
include_HEADERS = jv.h jq.h
### Building the jq binary
# Remake the version.h header file if, and only if, the git ID has changed
.PHONY: .FORCE
.FORCE:
generate_ver = ver="`{ $(srcdir)/scripts/version || echo '$(VERSION)' ; } | sed 's/.*/\#define JQ_VERSION \"&\"/'`"
.remake-version-h: .FORCE
@ $(generate_ver); test "x`cat version.h 2>/dev/null`" = "x$$ver" || touch .remake-version-h
version.h: .remake-version-h
$(AM_V_GEN) $(generate_ver); echo "$$ver" > $@
main.c: config.h
bin_PROGRAMS = jq
jq_SOURCES = main.c
jq_LDFLAGS = -static-libtool-libs
jq_LDADD = libjq.la -lm
jq_SOURCES = ${JQ_SRC} main.c
### Tests (make check)
@@ -73,23 +56,20 @@ man_MANS = jq.1
.PHONY: real_docs
if ENABLE_DOCS
jq.1: $(srcdir)/docs/content/3.manual/manual.yml
$(AM_V_GEN) ( cd ${abs_srcdir}/docs; '$(BUNDLER)' exec rake manpage ) > $@ || { rm -f $@; false; }
jq.1.prebuilt: jq.1
$(AM_V_GEN) cp $^ $@ || { rm -f $@; false; }
( cd ${abs_srcdir}/docs; '$(BUNDLER)' exec rake manpage ) > $@ || { rm -f $@; false; }
jq.1.default: $(srcdir)/docs/default_manpage.md
$(AM_V_GEN) ( cd ${abs_srcdir}/docs; '$(BUNDLER)' exec rake manpage_default ) > $@ || { rm -f $@; false; }
real_docs: jq.1 jq.1.prebuilt
@if cmp jq.1 $(srcdir)/jq.1.default > /dev/null; then\
( cd ${abs_srcdir}/docs; '$(BUNDLER)' exec rake manpage_default ) > $@ || { rm -f $@; false; }
real_docs: jq.1
if cmp jq.1 $(srcdir)/jq.1.default > /dev/null; then\
rm -f jq.1; $(MAKE) $(AM_MAKEFLAGS) jq.1;\
fi
else
jq.1: $(srcdir)/jq.1.prebuilt
$(AM_V_GEN) cp $^ $@
jq.1: $(srcdir)/jq.1.default
cp $^ $@
real_docs:
@echo "Ruby dependencies not found, cannot build manpage." > /dev/stderr
@echo "Follow the instructions in docs/README.md to install them" > /dev/stderr
@echo "and then rerun ./configure" > /dev/stderr
@echo "A pre-built, possibly out-of-date manpage used." > /dev/stderr
false
endif
@@ -113,21 +93,24 @@ DOC_FILES = docs/content docs/public docs/templates docs/site.yml \
# setup is only used by distribution developers, not package developers.
# Still, as a matter of allowing patching, its not a bad idea to distribute
# the developer setup script in the tarball.
EXTRA_DIST = $(man_MANS) $(TESTS) $(TEST_LOG_COMPILER) jq.spec \
$(DOC_FILES) scripts/version parser.h parser.c lexer.h \
lexer.c
EXTRA_DIST = config.h.in $(BUILT_SOURCES) $(man_MANS) $(TESTS) \
$(TEST_LOG_COMPILER) gen_utf8_tables.py jq.spec \
$(DOC_FILES)
# README.md is expected in Github projects, good stuff in it, so we'll
# distribute it and install it with the package in the doc directory.
docdir = ${datadir}/doc/${PACKAGE}
dist_doc_DATA = README.md COPYING AUTHORS README
releasetag:
git tag -s "jq-$$(cat VERSION)" -m "jq release $$(cat VERSION)"
RELEASE ?= 1
rpm: dist jq.spec
rpm: jq
@echo "Packaging jq as an RPM ..."
mkdir -p rpm/SOURCES rpm/BUILD rpm/BUILDROOT rpm/RPMS rpm/SPECS
cp jq-$(VERSION).tar.gz rpm/SOURCES/
rpmbuild -tb --define "_topdir ${PWD}/rpm" --define "_prefix /usr" --define "myver $(VERSION)" --define "myrel ${RELEASE}" rpm/SOURCES/jq-$(VERSION).tar.gz
cp jq-$$(cat VERSION).tar.gz rpm/SOURCES/
rpmbuild -tb --define "_topdir ${PWD}/rpm" --define "_prefix /usr" --define "myver $$(cat VERSION)" --define "myrel ${RELEASE}" rpm/SOURCES/jq-$$(cat VERSION).tar.gz
find rpm/RPMS/ -name "*.rpm" -exec mv {} ./ \;
rm -rf rpm
@@ -136,12 +119,5 @@ dist-clean-local:
# Not sure why this doesn't get cleaned up automatically, guess
# automake used to man pages which are hand coded?
# 'make clean' doesn't delete the manpage if it can't be rebuilt
.PHONY: clean-local-docs
clean-local-docs:
if ENABLE_DOCS
clean-local:
rm -f jq.1
endif
clean-local: clean-local-docs
rm -f version.h .remake-version-h
-64
View File
@@ -1,64 +0,0 @@
Release history
* jq version 1.0 was released on Sun Oct 21 2012
* jq version 1.1 was released on Sun Oct 21 2012
* jq version 1.2 was released on Thu Dec 20 2012
* jq version 1.3 was released on Sun May 19 2013
* jq version 1.4 was released on Mon Jun 9 2014
As yet unreleased features in master branch, since 1.4:
- semantics
- multiple function argument numbers for any one function name,
dispatching on number of arguments in function calls
- misc
- env builting (to access the environment)
- prebuilt jq.1 man page
New features in 1.4 since 1.3:
- command-line arguments
- jq --arg-file variable file
- jq --unbuffered
- jq -e / --exit-status (set exit status based on outputs)
- jq -S / --sort-keys (now jq no longer sorts object keys by
default
- syntax
- .. -> like // in XPath (recursive traversal)
- question mark (e.g., .a?) to suppress errors
- ."foo" syntax (equivalent to .["foo"])
- better error handling for .foo
- added % operator (modulo)
- allow negation without requiring extra parenthesis
- more function arguments (up to six)
- filters:
- any, all
- iterables, arrays, objects, scalars, nulls, booleans, numbers,
strings, values
- string built-ins:
- split
- join (join an array of strings with a given separator string)
- ltrimstr, rtrimstr
- startswith, endswith
- explode, implode
- fromjson, tojson
- index, rindex, indices
- math functions
- floor, sqrt, cbrt, etetera (depends on what's available from libm)
- libjq -- a C API interface to jq's JSON representation and for
running jq programs from C applications
+7 -19
View File
@@ -6,30 +6,18 @@ jq is a command-line JSON processor.
If you want to learn to use jq, read the documentation at
[http://stedolan.github.io/jq](http://stedolan.github.io/jq). This
documentation is generated from the docs/ folder of this repository.
You can also try it online at [jqplay.org](http://jqplay.org).
If you want to hack on jq, feel free, but be warned that its internals
are not well-documented at the moment. Bring a hard hat and a
shovel. Also, read the wiki: http://github.com/stedolan/jq/wiki
shovel. Also, read the wiki: https://github.com/stedolan/jq/wiki
If you're building directly from the latest git, you'll need flex and
bison installed. To build, run:
To build jq, run
autoreconf -i
./configure
make -j8
make check
make
sudo make install (optionally)
After make finishes, you'll be able to use `./jq`. You can also
install it using:
sudo make install
If you're not using the latest git version but instead building a
released tarball (available on the website), then you won't need to
run `autoreconf` (and shouldn't), and you won't need flex or bison.
To cross-compile for OS X and Windows, see docs/Rakefile's build task
and scripts/crosscompile. You'll need a cross-compilation environment,
such as Mingw for cross-compiling for Windows.
If you've just checked out the latest version from git (rather than
using a released source tarball) then you'll need to run this first:
autoreconf
+42 -461
View File
@@ -1,17 +1,29 @@
#include <assert.h>
#include <limits.h>
#include <math.h>
#include <oniguruma.h>
#include <stdlib.h>
#include <string.h>
#include "builtin.h"
#include "compile.h"
#include "jq_parser.h"
#include "bytecode.h"
#include "locfile.h"
#include "jv_aux.h"
#include "jv_unicode.h"
typedef jv (*func_1)(jv);
typedef jv (*func_2)(jv,jv);
typedef jv (*func_3)(jv,jv,jv);
typedef jv (*func_4)(jv,jv,jv,jv);
typedef jv (*func_5)(jv,jv,jv,jv,jv);
jv cfunction_invoke(struct cfunction* function, jv input[]) {
switch (function->nargs) {
case 1: return ((func_1)function->fptr)(input[0]);
case 2: return ((func_2)function->fptr)(input[0], input[1]);
case 3: return ((func_3)function->fptr)(input[0], input[1], input[2]);
case 4: return ((func_4)function->fptr)(input[0], input[1], input[2], input[3]);
case 5: return ((func_5)function->fptr)(input[0], input[1], input[2], input[3], input[4]);
default: return jv_invalid_with_msg(jv_string("Function takes too many arguments"));
}
}
static jv type_error(jv bad, const char* msg) {
jv err = jv_invalid_with_msg(jv_string_fmt("%s %s",
jv_kind_name(jv_get_kind(bad)),
@@ -52,18 +64,6 @@ static jv f_plus(jv input, jv a, jv b) {
}
}
#define LIBM_DD(name) \
static jv f_ ## name(jv input) { \
if (jv_get_kind(input) != JV_KIND_NUMBER) { \
return type_error(input, "number required"); \
} \
jv ret = jv_number(name(jv_number_value(input))); \
jv_free(input); \
return ret; \
}
#include "libm.h"
#undef LIBM_DD
static jv f_negate(jv input) {
if (jv_get_kind(input) != JV_KIND_NUMBER) {
return type_error(input, "cannot be negated");
@@ -73,64 +73,6 @@ static jv f_negate(jv input) {
return ret;
}
static jv f_startswith(jv a, jv b) {
int alen = jv_string_length_bytes(jv_copy(a));
int blen = jv_string_length_bytes(jv_copy(b));
jv ret;
if (blen <= alen && memcmp(jv_string_value(a), jv_string_value(b), blen) == 0)
ret = jv_true();
else
ret = jv_false();
jv_free(a);
jv_free(b);
return ret;
}
static jv f_endswith(jv a, jv b) {
const char *astr = jv_string_value(a);
const char *bstr = jv_string_value(b);
size_t alen = jv_string_length_bytes(jv_copy(a));
size_t blen = jv_string_length_bytes(jv_copy(b));
jv ret;;
if (alen < blen ||
memcmp(astr + (alen - blen), bstr, blen) != 0)
ret = jv_false();
else
ret = jv_true();
jv_free(a);
jv_free(b);
return ret;
}
static jv f_ltrimstr(jv input, jv left) {
if (jv_get_kind(f_startswith(jv_copy(input), jv_copy(left))) != JV_KIND_TRUE) {
jv_free(left);
return input;
}
/*
* FIXME It'd be better to share the suffix with the original input --
* that we could do, we just can't share prefixes.
*/
int prefixlen = jv_string_length_bytes(left);
jv res = jv_string_sized(jv_string_value(input) + prefixlen,
jv_string_length_bytes(jv_copy(input)) - prefixlen);
jv_free(input);
return res;
}
static jv f_rtrimstr(jv input, jv right) {
if (jv_get_kind(f_endswith(jv_copy(input), jv_copy(right))) == JV_KIND_TRUE) {
jv res = jv_string_sized(jv_string_value(input),
jv_string_length_bytes(jv_copy(input)) - jv_string_length_bytes(right));
jv_free(input);
return res;
}
jv_free(right);
return input;
}
static jv f_minus(jv input, jv a, jv b) {
jv_free(input);
if (jv_get_kind(a) == JV_KIND_NUMBER && jv_get_kind(b) == JV_KIND_NUMBER) {
@@ -158,34 +100,9 @@ static jv f_minus(jv input, jv a, jv b) {
}
static jv f_multiply(jv input, jv a, jv b) {
jv_kind ak = jv_get_kind(a);
jv_kind bk = jv_get_kind(b);
jv_free(input);
if (ak == JV_KIND_NUMBER && bk == JV_KIND_NUMBER) {
if (jv_get_kind(a) == JV_KIND_NUMBER && jv_get_kind(b) == JV_KIND_NUMBER) {
return jv_number(jv_number_value(a) * jv_number_value(b));
} else if ((ak == JV_KIND_STRING && bk == JV_KIND_NUMBER) ||
(ak == JV_KIND_NUMBER && bk == JV_KIND_STRING)) {
jv str = a;
jv num = b;
if (ak == JV_KIND_NUMBER) {
str = b;
num = a;
}
int n;
size_t alen = jv_string_length_bytes(jv_copy(str));
jv res = str;
for (n = jv_number_value(num) - 1; n > 0; n--)
res = jv_string_append_buf(res, jv_string_value(str), alen);
jv_free(num);
if (n < 0) {
jv_free(str);
return jv_null();
}
return res;
} else if (ak == JV_KIND_OBJECT && bk == JV_KIND_OBJECT) {
return jv_object_merge_recursive(a, b);
} else {
return type_error2(a, b, "cannot be multiplied");
}
@@ -195,17 +112,6 @@ static jv f_divide(jv input, jv a, jv b) {
jv_free(input);
if (jv_get_kind(a) == JV_KIND_NUMBER && jv_get_kind(b) == JV_KIND_NUMBER) {
return jv_number(jv_number_value(a) / jv_number_value(b));
} else if (jv_get_kind(a) == JV_KIND_STRING && jv_get_kind(b) == JV_KIND_STRING) {
return jv_string_split(a, b);
} else {
return type_error2(a, b, "cannot be divided");
}
}
static jv f_mod(jv input, jv a, jv b) {
jv_free(input);
if (jv_get_kind(a) == JV_KIND_NUMBER && jv_get_kind(b) == JV_KIND_NUMBER) {
return jv_number((intmax_t)jv_number_value(a) % (intmax_t)jv_number_value(b));
} else {
return type_error2(a, b, "cannot be divided");
}
@@ -261,19 +167,6 @@ static jv f_contains(jv a, jv b) {
}
}
static jv f_dump(jv input) {
return jv_dump_string(input, 0);
}
static jv f_json_parse(jv input) {
if (jv_get_kind(input) != JV_KIND_STRING)
return type_error(input, "only strings can be parsed");
jv res = jv_parse_sized(jv_string_value(input),
jv_string_length_bytes(jv_copy(input)));
jv_free(input);
return res;
}
static jv f_tonumber(jv input) {
if (jv_get_kind(input) == JV_KIND_NUMBER) {
return input;
@@ -295,8 +188,6 @@ static jv f_length(jv input) {
return jv_number(jv_object_length(input));
} else if (jv_get_kind(input) == JV_KIND_STRING) {
return jv_number(jv_string_length_codepoints(input));
} else if (jv_get_kind(input) == JV_KIND_NUMBER) {
return jv_number(fabs(jv_number_value(input)));
} else if (jv_get_kind(input) == JV_KIND_NULL) {
jv_free(input);
return jv_number(0);
@@ -413,7 +304,7 @@ static jv f_format(jv input, jv fmt) {
if (ch < 128 && unreserved[ch]) {
line = jv_string_append_buf(line, s, 1);
} else {
line = jv_string_concat(line, jv_string_fmt("%%%02X", ch));
line = jv_string_concat(line, jv_string_fmt("%%%02x", ch));
}
s++;
}
@@ -454,7 +345,7 @@ static jv f_format(jv input, jv fmt) {
input = f_tostring(input);
jv line = jv_string("");
const char b64[64 + 1] = CHARS_ALPHANUM "+/";
const unsigned char* data = (const unsigned char*)jv_string_value(input);
const char* data = jv_string_value(input);
int len = jv_string_length_bytes(jv_copy(input));
for (int i=0; i<len; i+=3) {
uint32_t code = 0;
@@ -515,214 +406,6 @@ static jv f_group_by_impl(jv input, jv keys) {
}
}
static int f_match_name_iter(const UChar* name, const UChar *name_end, int ngroups,
int *groups, regex_t *reg, void *arg) {
jv captures = *(jv*)arg;
for (int i = 0; i < ngroups; ++i) {
jv cap = jv_array_get(jv_copy(captures),groups[i]-1);
if (jv_get_kind(cap) == JV_KIND_OBJECT) {
cap = jv_object_set(cap, jv_string("name"), jv_string_sized((const char*)name, name_end-name));
captures = jv_array_set(captures,groups[i]-1,cap);
} else {
jv_free(cap);
}
}
*(jv *)arg = captures;
return 0;
}
static jv f_match(jv input, jv regex, jv modifiers, jv testmode) {
int test = jv_equal(testmode, jv_true());
jv result;
int onigret;
int global = 0;
regex_t *reg;
OnigErrorInfo einfo;
OnigRegion* region;
if (jv_get_kind(input) != JV_KIND_STRING) {
jv_free(regex);
jv_free(modifiers);
return type_error(input, "cannot be matched, as it is not a string");
}
if (jv_get_kind(regex) != JV_KIND_STRING) {
jv_free(input);
jv_free(modifiers);
return type_error(regex, "is not a string");
}
OnigOptionType options = ONIG_OPTION_CAPTURE_GROUP;
if (jv_get_kind(modifiers) == JV_KIND_STRING) {
jv modarray = jv_string_explode(jv_copy(modifiers));
jv_array_foreach(modarray, i, mod) {
switch ((int)jv_number_value(mod)) {
case 'g':
global = 1;
break;
case 'i':
options |= ONIG_OPTION_IGNORECASE;
break;
case 'x':
options |= ONIG_OPTION_EXTEND;
break;
case 'm':
options |= ONIG_OPTION_MULTILINE;
break;
case 's':
options |= ONIG_OPTION_SINGLELINE;
break;
case 'p':
options |= ONIG_OPTION_MULTILINE | ONIG_OPTION_SINGLELINE;
break;
case 'l':
options |= ONIG_OPTION_FIND_LONGEST;
break;
case 'n':
options |= ONIG_OPTION_FIND_NOT_EMPTY;
break;
default:
jv_free(input);
jv_free(regex);
jv_free(modarray);
return jv_invalid_with_msg(jv_string_concat(modifiers,
jv_string(" is not a valid modifier string")));
}
}
jv_free(modarray);
} else if (jv_get_kind(modifiers) != JV_KIND_NULL) {
// If it isn't a string or null, then it is the wrong type...
jv_free(input);
jv_free(regex);
return type_error(modifiers, "is not a string");
}
jv_free(modifiers);
onigret = onig_new(&reg, (const UChar*)jv_string_value(regex),
(const UChar*)(jv_string_value(regex) + jv_string_length_bytes(jv_copy(regex))),
options, ONIG_ENCODING_UTF8, ONIG_SYNTAX_PERL_NG, &einfo);
if (onigret != ONIG_NORMAL) {
UChar ebuf[ONIG_MAX_ERROR_MESSAGE_LEN];
onig_error_code_to_str(ebuf, onigret, einfo);
jv_free(input);
jv_free(regex);
return jv_invalid_with_msg(jv_string_concat(jv_string("Regex failure: "),
jv_string((char*)ebuf)));
}
if (!test)
result = jv_array();
const char *input_string = jv_string_value(input);
const UChar* start = (const UChar*)jv_string_value(input);
const unsigned long length = jv_string_length_bytes(jv_copy(input));
const UChar* end = start + length;
region = onig_region_new();
do {
onigret = onig_search(reg,
(const UChar*)jv_string_value(input), end, /* string boundaries */
start, end, /* search boundaries */
region, ONIG_OPTION_NONE);
if (onigret >= 0) {
if (test) {
result = jv_true();
break;
}
// Zero-width match
if (region->end[0] == region->beg[0]) {
unsigned long idx;
const char *fr = (const char*)input_string;
for (idx = 0; fr != input_string+region->beg[0]; idx++) {
fr += jvp_utf8_decode_length(*fr);
}
jv match = jv_object_set(jv_object(), jv_string("offset"), jv_number(idx));
match = jv_object_set(match, jv_string("length"), jv_number(0));
match = jv_object_set(match, jv_string("string"), jv_string(""));
match = jv_object_set(match, jv_string("captures"), jv_array());
result = jv_array_append(result, match);
start += 1;
continue;
}
unsigned long idx;
unsigned long len;
const char *fr = (const char*)input_string;
for (idx = len = 0; fr != input_string+region->end[0]; len++) {
if (fr == input_string+region->beg[0]) idx = len, len=0;
fr += jvp_utf8_decode_length(*fr);
}
jv match = jv_object_set(jv_object(), jv_string("offset"), jv_number(idx));
unsigned long blen = region->end[0]-region->beg[0];
match = jv_object_set(match, jv_string("length"), jv_number(len));
match = jv_object_set(match, jv_string("string"), jv_string_sized(input_string+region->beg[0],blen));
jv captures = jv_array();
for (int i = 1; i < region->num_regs; ++i) {
// Empty capture.
if (region->beg[i] == region->end[i]) {
// Didn't match.
jv cap;
if (region->beg[i] == -1) {
cap = jv_object_set(jv_object(), jv_string("offset"), jv_number(-1));
cap = jv_object_set(cap, jv_string("string"), jv_null());
} else {
fr = input_string;
for (idx = 0; fr != input_string+region->beg[i]; idx++) {
fr += jvp_utf8_decode_length(*fr);
}
cap = jv_object_set(jv_object(), jv_string("offset"), jv_number(idx));
cap = jv_object_set(cap, jv_string("string"), jv_string(""));
}
cap = jv_object_set(cap, jv_string("length"), jv_number(0));
cap = jv_object_set(cap, jv_string("name"), jv_null());
captures = jv_array_append(captures, cap);
continue;
}
fr = input_string;
for (idx = len = 0; fr != input_string+region->end[i]; len++) {
if (fr == input_string+region->beg[i]) idx = len, len=0;
fr += jvp_utf8_decode_length(*fr);
}
blen = region->end[i]-region->beg[i];
jv cap = jv_object_set(jv_object(), jv_string("offset"), jv_number(idx));
cap = jv_object_set(cap, jv_string("length"), jv_number(len));
cap = jv_object_set(cap, jv_string("string"), jv_string_sized(input_string+region->beg[i],blen));
cap = jv_object_set(cap, jv_string("name"), jv_null());
captures = jv_array_append(captures,cap);
}
onig_foreach_name(reg,f_match_name_iter,&captures);
match = jv_object_set(match, jv_string("captures"), captures);
result = jv_array_append(result, match);
start = (const UChar*)(input_string+region->end[0]);
onig_region_free(region,0);
} else if (onigret == ONIG_MISMATCH) {
if (test)
result = jv_false();
break;
} else { /* Error */
UChar ebuf[ONIG_MAX_ERROR_MESSAGE_LEN];
onig_error_code_to_str(ebuf, onigret, einfo);
jv_free(result);
result = jv_invalid_with_msg(jv_string_concat(jv_string("Regex failure: "),
jv_string((char*)ebuf)));
break;
}
} while (global && start != end);
onig_region_free(region,1);
region = NULL;
if (region)
onig_region_free(region,1);
onig_free(reg);
jv_free(input);
jv_free(regex);
return result;
}
static jv minmax_by(jv values, jv keys, int is_min) {
if (jv_get_kind(values) != JV_KIND_ARRAY)
return type_error2(values, keys, "cannot be iterated over");
@@ -785,49 +468,15 @@ static jv f_error(jv input, jv msg) {
return jv_invalid_with_msg(msg);
}
// FIXME Should autoconf check for this!
#ifndef WIN32
extern const char **environ;
#endif
static jv f_env(jv input) {
jv_free(input);
jv env = jv_object();
const char *var, *val;
for (const char **e = environ; *e != NULL; e++) {
var = e[0];
val = strchr(e[0], '=');
if (val == NULL)
env = jv_object_set(env, jv_string(var), jv_null());
else if (var - val < INT_MAX)
env = jv_object_set(env, jv_string_sized(var, val - var), jv_string(val + 1));
}
return env;
}
#define LIBM_DD(name) \
{(cfunction_ptr)f_ ## name, "_" #name, 1},
static const struct cfunction function_list[] = {
#include "libm.h"
{(cfunction_ptr)f_plus, "_plus", 3},
{(cfunction_ptr)f_negate, "_negate", 1},
{(cfunction_ptr)f_minus, "_minus", 3},
{(cfunction_ptr)f_multiply, "_multiply", 3},
{(cfunction_ptr)f_divide, "_divide", 3},
{(cfunction_ptr)f_mod, "_mod", 3},
{(cfunction_ptr)f_dump, "tojson", 1},
{(cfunction_ptr)f_json_parse, "fromjson", 1},
{(cfunction_ptr)f_tonumber, "tonumber", 1},
{(cfunction_ptr)f_tostring, "tostring", 1},
{(cfunction_ptr)f_keys, "keys", 1},
{(cfunction_ptr)f_startswith, "startswith", 2},
{(cfunction_ptr)f_endswith, "endswith", 2},
{(cfunction_ptr)f_ltrimstr, "ltrimstr", 2},
{(cfunction_ptr)f_rtrimstr, "rtrimstr", 2},
{(cfunction_ptr)jv_string_split, "split", 2},
{(cfunction_ptr)jv_string_explode, "explode", 1},
{(cfunction_ptr)jv_string_implode, "implode", 1},
{(cfunction_ptr)jv_setpath, "setpath", 3}, // FIXME typechecking
{(cfunction_ptr)jv_getpath, "getpath", 2},
{(cfunction_ptr)jv_delpaths, "delpaths", 2},
@@ -850,10 +499,7 @@ static const struct cfunction function_list[] = {
{(cfunction_ptr)f_max_by_impl, "_max_by_impl", 2},
{(cfunction_ptr)f_error, "error", 2},
{(cfunction_ptr)f_format, "format", 2},
{(cfunction_ptr)f_env, "env", 1},
{(cfunction_ptr)f_match, "_match_impl", 4},
};
#undef LIBM_DD
struct bytecoded_builtin { const char* name; block code; };
static block bind_bytecoded_builtins(block b) {
@@ -880,121 +526,56 @@ static block bind_bytecoded_builtins(block b) {
};
for (unsigned i=0; i<sizeof(builtin_def_1arg)/sizeof(builtin_def_1arg[0]); i++) {
builtins = BLOCK(builtins, gen_function(builtin_def_1arg[i].name,
gen_param("arg"),
gen_op_block_unbound(CLOSURE_PARAM, "arg"),
builtin_def_1arg[i].code));
}
}
{
block rangevar = gen_op_var_fresh(STOREV, "rangevar");
block rangevar = block_bind(gen_op_var_unbound(STOREV, "rangevar"),
gen_noop(), OP_HAS_VARIABLE);
block init = BLOCK(gen_op_simple(DUP), gen_call("start", gen_noop()), rangevar);
block range = BLOCK(init,
gen_call("end", gen_noop()),
gen_op_bound(RANGE, rangevar));
gen_op_var_bound(RANGE, rangevar));
builtins = BLOCK(builtins, gen_function("range",
BLOCK(gen_param("start"), gen_param("end")),
BLOCK(gen_op_block_unbound(CLOSURE_PARAM, "start"),
gen_op_block_unbound(CLOSURE_PARAM, "end")),
range));
}
return block_bind_referenced(builtins, b, OP_IS_CALL_PSEUDO);
}
#define LIBM_DD(name) "def " #name ": _" #name ";",
static const char* const jq_builtins[] = {
"def map(f): [.[] | f];",
"def select(f): if f then . else empty end;",
"def sort(f): _sort_by_impl(map([f]));",
"def sort_by(f): sort(f);",
"def group(f): _group_by_impl(map([f]));",
"def group_by(f): group(f);",
"def unique: group(.) | map(.[0]);",
"def unique(f): group(f) | map(.[0]);",
"def unique_by(f): unique(f);",
"def max(f): _max_by_impl(map([f]));",
"def min(f): _min_by_impl(map([f]));",
"def max_by(f): max(f);",
"def min_by(f): min(f);",
#include "libm.h"
"def sort_by(f): _sort_by_impl(map([f]));",
"def group_by(f): _group_by_impl(map([f]));",
"def unique: group_by(.) | map(.[0]);",
"def max_by(f): _max_by_impl(map([f]));",
"def min_by(f): _min_by_impl(map([f]));",
"def add: reduce .[] as $x (null; . + $x);",
"def del(f): delpaths([path(f)]);",
"def _assign(paths; value): value as $v | reduce path(paths) as $p (.; setpath($p; $v));",
"def _modify(paths; update): reduce path(paths) as $p (.; setpath($p; getpath($p) | update));",
"def recurse(f): ., (f | select(. != null) | recurse(f));",
"def recurse: recurse(.[]?);",
"def recurse_down: recurse;",
"def to_entries: [keys[] as $k | {key: $k, value: .[$k]}];",
"def from_entries: map({(.key): .value}) | add | .//={};",
"def from_entries: map({(.key): .value}) | add;",
"def with_entries(f): to_entries | map(f) | from_entries;",
"def reverse: [.[length - 1 - range(0;length)]];",
"def indices(i): if type == \"array\" and (i|type) == \"array\" then .[i] elif type == \"array\" then .[[i]] else .[i] end;",
"def index(i): if type == \"array\" and (i|type) == \"array\" then .[i] elif type == \"array\" then .[[i]] else .[i] end | .[0];",
"def rindex(i): if type == \"array\" and (i|type) == \"array\" then .[i] elif type == \"array\" then .[[i]] else .[i] end | .[-1:][0];",
"def paths: path(recurse(if (type|. == \"array\" or . == \"object\") then .[] else empty end))|select(length > 0);",
"def paths(node_filter): . as $dot|paths|select(. as $p|$dot|getpath($p)|node_filter);",
"def any: reduce .[] as $i (false; . or $i);",
"def all: reduce .[] as $i (true; . and $i);",
"def arrays: select(type == \"array\");",
"def objects: select(type == \"object\");",
"def iterables: arrays, objects;",
"def booleans: select(type == \"boolean\");",
"def numbers: select(type == \"number\");",
"def strings: select(type == \"string\");",
"def nulls: select(type == \"null\");",
"def values: arrays, objects, booleans, numbers, strings;",
"def scalars: select(. == null or . == true or . == false or type == \"number\" or type == \"string\");",
"def leaf_paths: paths(scalars);",
"def join(x): reduce .[] as $i (\"\"; . + (if . == \"\" then $i else x + $i end));",
"def flatten: reduce .[] as $i ([]; if $i | type == \"array\" then . + ($i | flatten) else . + [$i] end);",
"def flatten(x): reduce .[] as $i ([]; if $i | type == \"array\" and x > 0 then . + ($i | flatten(x-1)) else . + [$i] end);",
"def range(x): range(0;x);",
"def match(re; mode): _match_impl(re; mode; false)|.[];",
"def match(val): if val | type == \"string\" then match(val; null) elif val | type == \"array\" and (val | length) > 1 then match(val[0]; val[1]) elif val | type == \"array\" and (val | length > 0) then match(val[0]; null) else error((val | type) + \" not a string or array\") end;",
"def test(re; mode): _match_impl(re; mode; true);",
"def test(val): if val |type == \"string\" then test(val; null) elif val | type == \"array\" and (val | length) > 1 then test(val[0]; val[1]) elif val | type == \"array\" and (val | length > 0) then test(val[0]; null) else error((val | type) + \" not a string or array\") end;",
// "def test(re): _match(re; null; 1);",
};
#undef LIBM_DD
static int builtins_bind_one(jq_state *jq, block* bb, const char* code) {
struct locfile src;
locfile_init(&src, jq, code, strlen(code));
block funcs;
int nerrors = jq_parse_library(&src, &funcs);
if (nerrors == 0) {
*bb = block_bind_referenced(funcs, *bb, OP_IS_CALL_PSEUDO);
}
locfile_free(&src);
return nerrors;
}
static int slurp_lib(jq_state *jq, block* bb) {
int nerrors = 0;
char* home = getenv("HOME");
if (home) { // silently ignore no $HOME
jv filename = jv_string_append_str(jv_string(home), "/.jq");
jv data = jv_load_file(jv_string_value(filename), 1);
if (jv_is_valid(data)) {
nerrors = builtins_bind_one(jq, bb, jv_string_value(data) );
}
jv_free(filename);
jv_free(data);
}
return nerrors;
}
int builtins_bind(jq_state *jq, block* bb) {
int nerrors = slurp_lib(jq, bb);
if (nerrors) {
block_free(*bb);
return nerrors;
}
block builtins_bind(block b) {
for (int i=(int)(sizeof(jq_builtins)/sizeof(jq_builtins[0]))-1; i>=0; i--) {
nerrors = builtins_bind_one(jq, bb, jq_builtins[i]);
struct locfile src;
locfile_init(&src, jq_builtins[i], strlen(jq_builtins[i]));
block funcs;
int nerrors = jq_parse_library(&src, &funcs);
assert(!nerrors);
b = block_bind_referenced(funcs, b, OP_IS_CALL_PSEUDO);
locfile_free(&src);
}
*bb = bind_bytecoded_builtins(*bb);
*bb = gen_cbinding(function_list, sizeof(function_list)/sizeof(function_list[0]), *bb);
return nerrors;
b = bind_bytecoded_builtins(b);
return gen_cbinding(function_list, sizeof(function_list)/sizeof(function_list[0]), b);
}
+14 -3
View File
@@ -1,10 +1,21 @@
#ifndef BUILTIN_H
#define BUILTIN_H
#include "jq.h"
#include "bytecode.h"
#include "compile.h"
int builtins_bind(jq_state *, block*);
block builtins_bind(block);
typedef void (*cfunction_ptr)(void);
struct cfunction {
cfunction_ptr fptr;
const char* name;
int nargs;
};
jv cfunction_invoke(struct cfunction* function, jv input[]);
#endif
+20 -52
View File
@@ -3,63 +3,17 @@
#include <stdlib.h>
#include "bytecode.h"
#include "opcode.h"
#include "jv_alloc.h"
// flags, length
#define NONE 0, 1
#define CONSTANT OP_HAS_CONSTANT, 2
#define VARIABLE (OP_HAS_VARIABLE | OP_HAS_BINDING), 3
#define BRANCH OP_HAS_BRANCH, 2
#define CFUNC (OP_HAS_CFUNC | OP_HAS_BINDING), 3
#define UFUNC (OP_HAS_UFUNC | OP_HAS_BINDING | OP_IS_CALL_PSEUDO), 4
#define DEFINITION (OP_IS_CALL_PSEUDO | OP_HAS_BINDING), 0
#define CLOSURE_REF_IMM (OP_IS_CALL_PSEUDO | OP_HAS_BINDING), 2
#define OP(name, imm, in, out) \
{name, #name, imm, in, out},
static const struct opcode_description opcode_descriptions[] = {
#include "opcode_list.h"
};
static const struct opcode_description invalid_opcode_description = {
-1, "#INVALID", 0, 0, 0, 0
};
const struct opcode_description* opcode_describe(opcode op) {
if ((int)op >= 0 && (int)op < NUM_OPCODES) {
return &opcode_descriptions[op];
} else {
return &invalid_opcode_description;
}
}
int bytecode_operation_length(uint16_t* codeptr) {
static int bytecode_operation_length(uint16_t* codeptr) {
int length = opcode_describe(*codeptr)->length;
if (*codeptr == CALL_JQ || *codeptr == TAIL_CALL_JQ) {
if (*codeptr == CALL_JQ) {
length += codeptr[1] * 2;
}
return length;
}
static void dump_code(int indent, struct bytecode* bc) {
int pc = 0;
while (pc < bc->codelen) {
printf("%*s", indent, "");
dump_operation(bc, bc->code + pc);
printf("\n");
pc += bytecode_operation_length(bc->code + pc);
}
}
static void symbol_table_free(struct symbol_table* syms) {
jv_mem_free(syms->cfunctions);
jv_free(syms->cfunc_names);
jv_mem_free(syms);
}
void dump_disassembly(int indent, struct bytecode* bc) {
if (bc->nclosures > 0) {
printf("%*s[params: ", indent, "");
@@ -83,6 +37,16 @@ void dump_disassembly(int indent, struct bytecode* bc) {
}
}
void dump_code(int indent, struct bytecode* bc) {
int pc = 0;
while (pc < bc->codelen) {
printf("%*s", indent, "");
dump_operation(bc, bc->code + pc);
printf("\n");
pc += bytecode_operation_length(bc->code + pc);
}
}
static struct bytecode* getlevel(struct bytecode* bc, int level) {
while (level > 0) {
bc = bc->parent;
@@ -98,7 +62,7 @@ void dump_operation(struct bytecode* bc, uint16_t* codeptr) {
printf("%s", op->name);
if (op->length > 1) {
uint16_t imm = bc->code[pc++];
if (op->op == CALL_JQ || op->op == TAIL_CALL_JQ) {
if (op->op == CALL_JQ) {
for (int i=0; i<imm+1; i++) {
uint16_t level = bc->code[pc++];
uint16_t idx = bc->code[pc++];
@@ -145,9 +109,13 @@ void dump_operation(struct bytecode* bc, uint16_t* codeptr) {
}
}
void symbol_table_free(struct symbol_table* syms) {
jv_mem_free(syms->cfunctions);
jv_free(syms->cfunc_names);
jv_mem_free(syms);
}
void bytecode_free(struct bytecode* bc) {
if (!bc)
return;
jv_mem_free(bc->code);
jv_free(bc->constants);
for (int i=0; i<bc->nsubfunctions; i++)
+4 -45
View File
@@ -3,52 +3,10 @@
#include <stdint.h>
#include "jv.h"
typedef enum {
#define OP(name, imm, in, out) name,
#include "opcode_list.h"
#undef OP
} opcode;
enum {
NUM_OPCODES =
#define OP(name, imm, in, out) +1
#include "opcode_list.h"
#undef OP
};
enum {
OP_HAS_CONSTANT = 2,
OP_HAS_VARIABLE = 4,
OP_HAS_BRANCH = 8,
OP_HAS_CFUNC = 32,
OP_HAS_UFUNC = 64,
OP_IS_CALL_PSEUDO = 128,
OP_HAS_BINDING = 1024,
};
struct opcode_description {
opcode op;
const char* name;
int flags;
// length in 16-bit units
int length;
int stack_in, stack_out;
};
const struct opcode_description* opcode_describe(opcode op);
#include "opcode.h"
#include "builtin.h"
#define MAX_CFUNCTION_ARGS 10
typedef void (*cfunction_ptr)();
struct cfunction {
cfunction_ptr fptr;
const char* name;
int nargs;
};
struct symbol_table {
struct cfunction* cfunctions;
int ncfunctions;
@@ -81,9 +39,10 @@ struct bytecode {
};
void dump_disassembly(int, struct bytecode* code);
void dump_code(int, struct bytecode* code);
void dump_operation(struct bytecode* bc, uint16_t* op);
int bytecode_operation_length(uint16_t* codeptr);
void symbol_table_free(struct symbol_table* syms);
void bytecode_free(struct bytecode* bc);
#endif
-102
View File
@@ -1,102 +0,0 @@
#!/bin/bash
# old values
OLD_CFLAGS=$CFLAGS
OLD_LDFLAGS=$LDFLAGS
ORIG_PWD=`pwd`
# For parallelism in make
NJOBS="-j`sysctl -n hw.ncpu || echo 1`"
# Get oniguruma
rm -rf $PWD/build/ios onig-5.9.5
echo "Downloading oniguruma 5.9.5"
curl http://www.geocities.jp/kosako3/oniguruma/archive/onig-5.9.5.tar.gz | tar xz
cd onig-5.9.5
# So, we need to remake the configure scripts so that the arm64 architecture
# exists in config.sub. In order to keep autoreconf from failing, create
# NEWS and ChangeLog.
touch NEWS ChangeLog
autoreconf -fi >/dev/null 2>&1
CC=`xcrun -f clang`
cd $ORIG_PWD
autoreconf -fi
for arch in i386 x86_64 armv7 armv7s arm64; do
# Some of the architectures are a bit different...
if [[ "$arch" = "i386" || "$arch" = "x86_64" ]]
then
SYSROOT=`xcrun -f --sdk iphonesimulator --show-sdk-path`
else
SYSROOT=`xcrun -f --sdk iphoneos --show-sdk-path`
fi
if [[ "$arch" = "arm64" ]]
then
HOST="aarch64-apple-darwin"
else
HOST="$arch-apple-darwin"
fi
CFLAGS="-arch $arch -miphoneos-version-min=6.0 -isysroot $SYSROOT $OLD_CFLAGS"
LDFLAGS="-arch $arch -miphoneos-version-min=6.0 -isysroot $SYSROOT $OLD_LDFLAGS"
# Build oniguruma for this architecture
cd onig-5.9.5
CC=$CC CFLAGS=$CFLAGS LDFLAGS=$LDFLAGS ./configure --disable-shared --enable-static --host=$HOST --prefix=$ORIG_PWD/build/ios/$arch
STATUS=$?
if [ $STATUS -ne 0 ]
then
echo "Failed to configure oniguruma for architecture $arch. Check `pwd`/config.log for details."
cd $PWD
exit $STATUS
fi
make clean
make $NJBOS install
STATUS=$?
if [ $STATUS -ne 0 ]
then
echo "Failed to make oniguruma for architecture $arch."
cd $PWD
exit $STATUS
fi
# Build jq for this architecture
cd $ORIG_PWD
CC=$CC CFLAGS=$CFLAGS LDFLAGS=$LDFLAGS ./configure --disable-shared --enable-static -host=$HOST --prefix=$ORIG_PWD/build/ios/$arch --with-oniguruma=$ORIG_PWD/build/ios/$arch
STATUS=$?
if [ $STATUS -ne 0 ]
then
echo "Failed to configure jq for architecture $arch"
exit $STATUS
fi
make clean
make $NJOBS install
STATUS=$?
if [ $STATUS -ne 0 ]
then
echo "Failed to make jq for architecture $arch"
exit $STATUS
fi
done
# lipo together the different architectures into a universal 'fat' file
lipo -create -output $ORIG_PWD/build/ios/libonig.a $ORIG_PWD/build/ios/{i386,x86_64,armv7,armv7s,arm64}/lib/libonig.a
lipo -create -output $ORIG_PWD/build/ios/libjq.a $ORIG_PWD/build/ios/{i386,x86_64,armv7,armv7s,arm64}/lib/libjq.a
# copy the products into the destination directory and clean up the single-architecture files.
cp $ORIG_PWD/build/ios/i386/include/*.h $ORIG_PWD/build/ios/
rm -rf $ORIG_PWD/build/ios/{i386,x86_64,armv7,armv7s,arm64}
echo "Products are in $ORIG_PWD/build/ios"
+50 -91
View File
@@ -1,9 +1,8 @@
#ifndef _GNU_SOURCE
#define _GNU_SOURCE // for strdup
#endif
#include <assert.h>
#include <string.h>
#include <stdlib.h>
#include "opcode.h"
#include "compile.h"
#include "bytecode.h"
#include "locfile.h"
@@ -49,9 +48,6 @@ struct inst {
struct inst* bound_by;
char* symbol;
int nformals;
int nactuals;
block subfn; // used by CLOSURE_CREATE (body of function)
block arglist; // used by CLOSURE_CREATE (formals) and CALL_JQ (arguments)
@@ -69,12 +65,9 @@ static inst* inst_new(opcode op) {
i->bytecode_pos = -1;
i->bound_by = 0;
i->symbol = 0;
i->nformals = -1;
i->nactuals = -1;
i->subfn = gen_noop();
i->arglist = gen_noop();
i->source = UNKNOWN_LOCATION;
i->compiled = 0;
return i;
}
@@ -160,26 +153,33 @@ void inst_set_target(block b, block target) {
b.first->imm.target = target.last;
}
block gen_op_unbound(opcode op, const char* name) {
assert(opcode_describe(op)->flags & OP_HAS_BINDING);
block gen_op_var_unbound(opcode op, const char* name) {
assert(opcode_describe(op)->flags & OP_HAS_VARIABLE);
inst* i = inst_new(op);
i->symbol = strdup(name);
return inst_block(i);
}
block gen_op_var_fresh(opcode op, const char* name) {
assert(opcode_describe(op)->flags & OP_HAS_VARIABLE);
return block_bind(gen_op_unbound(op, name),
gen_noop(), OP_HAS_VARIABLE);
}
block gen_op_bound(opcode op, block binder) {
block gen_op_var_bound(opcode op, block binder) {
assert(block_is_single(binder));
block b = gen_op_unbound(op, binder.first->symbol);
block b = gen_op_var_unbound(op, binder.first->symbol);
b.first->bound_by = binder.first;
return b;
}
block gen_op_block_unbound(opcode op, const char* name) {
assert(opcode_describe(op)->flags & OP_IS_CALL_PSEUDO);
inst* i = inst_new(op);
i->symbol = strdup(name);
return inst_block(i);
}
block gen_op_block_bound(opcode op, block binder) {
assert(block_is_single(binder));
block b = gen_op_block_unbound(op, binder.first->symbol);
b.first->bound_by = binder.first;
return b;
}
static void inst_join(inst* a, inst* b) {
assert(a && b);
@@ -216,34 +216,6 @@ int block_has_only_binders(block binders, int bindflags) {
return 1;
}
// Count a binder's (function) formal params
static int block_count_formals(block b) {
int args = 0;
if (b.first->op == CLOSURE_CREATE_C)
return b.first->imm.cfunc->nargs - 1;
for (inst* i = b.first->arglist.first; i; i = i->next) {
assert(i->op == CLOSURE_PARAM);
args++;
}
return args;
}
// Count a call site's actual params
static int block_count_actuals(block b) {
int args = 0;
for (inst* i = b.first; i; i = i->next) {
switch (i->op) {
default: assert(0 && "Unknown function type"); break;
case CLOSURE_CREATE:
case CLOSURE_PARAM:
case CLOSURE_CREATE_C:
args++;
break;
}
}
return args;
}
static int block_bind_subblock(block binder, block body, int bindflags) {
assert(block_is_single(binder));
assert((opcode_describe(binder.first->op)->flags & bindflags) == bindflags);
@@ -251,8 +223,6 @@ static int block_bind_subblock(block binder, block body, int bindflags) {
assert(binder.first->bound_by == 0 || binder.first->bound_by == binder.first);
binder.first->bound_by = binder.first;
if (binder.first->nformals == -1)
binder.first->nformals = block_count_formals(binder);
int nrefs = 0;
for (inst* i = body.first; i; i = i->next) {
int flags = opcode_describe(i->op)->flags;
@@ -260,12 +230,8 @@ static int block_bind_subblock(block binder, block body, int bindflags) {
i->bound_by == 0 &&
!strcmp(i->symbol, binder.first->symbol)) {
// bind this instruction
if (i->op == CALL_JQ && i->nactuals == -1)
i->nactuals = block_count_actuals(i->arglist);
if (i->nactuals == -1 || i->nactuals == binder.first->nformals) {
i->bound_by = binder.first;
nrefs++;
}
i->bound_by = binder.first;
nrefs++;
}
// binding recurses into closures
nrefs += block_bind_subblock(binder, i->subfn, bindflags);
@@ -314,16 +280,12 @@ block gen_function(const char* name, block formals, block body) {
return b;
}
block gen_param(const char* name) {
return gen_op_unbound(CLOSURE_PARAM, name);
}
block gen_lambda(block body) {
return gen_function("@lambda", gen_noop(), body);
}
block gen_call(const char* name, block args) {
block b = gen_op_unbound(CALL_JQ, name);
block b = gen_op_block_unbound(CALL_JQ, name);
b.first->arglist = args;
return b;
}
@@ -344,27 +306,30 @@ block gen_both(block a, block b) {
block gen_collect(block expr) {
block array_var = gen_op_var_fresh(STOREV, "collect");
block array_var = block_bind(gen_op_var_unbound(STOREV, "collect"),
gen_noop(), OP_HAS_VARIABLE);
block c = BLOCK(gen_op_simple(DUP), gen_const(jv_array()), array_var);
block tail = BLOCK(gen_op_bound(APPEND, array_var),
block tail = BLOCK(gen_op_var_bound(APPEND, array_var),
gen_op_simple(BACKTRACK));
return BLOCK(c,
gen_op_target(FORK, tail),
expr,
tail,
gen_op_bound(LOADVN, array_var));
gen_op_var_bound(LOADVN, array_var));
}
block gen_reduce(const char* varname, block source, block init, block body) {
block res_var = gen_op_var_fresh(STOREV, "reduce");
block res_var = block_bind(gen_op_var_unbound(STOREV, "reduce"),
gen_noop(), OP_HAS_VARIABLE);
block loop = BLOCK(gen_op_simple(DUP),
source,
block_bind(gen_op_unbound(STOREV, varname),
BLOCK(gen_op_bound(LOADVN, res_var),
block_bind(gen_op_var_unbound(STOREV, varname),
BLOCK(gen_op_var_bound(LOADVN, res_var),
body,
gen_op_bound(STOREV, res_var)),
gen_op_var_bound(STOREV, res_var)),
OP_HAS_VARIABLE),
gen_op_simple(BACKTRACK));
return BLOCK(gen_op_simple(DUP),
@@ -372,18 +337,19 @@ block gen_reduce(const char* varname, block source, block init, block body) {
res_var,
gen_op_target(FORK, loop),
loop,
gen_op_bound(LOADVN, res_var));
gen_op_var_bound(LOADVN, res_var));
}
block gen_definedor(block a, block b) {
// var found := false
block found_var = gen_op_var_fresh(STOREV, "found");
block found_var = block_bind(gen_op_var_unbound(STOREV, "found"),
gen_noop(), OP_HAS_VARIABLE);
block init = BLOCK(gen_op_simple(DUP), gen_const(jv_false()), found_var);
// if found, backtrack. Otherwise execute b
block backtrack = gen_op_simple(BACKTRACK);
block tail = BLOCK(gen_op_simple(DUP),
gen_op_bound(LOADV, found_var),
gen_op_var_bound(LOADV, found_var),
gen_op_target(JUMP_F, backtrack),
backtrack,
gen_op_simple(POP),
@@ -395,7 +361,7 @@ block gen_definedor(block a, block b) {
// found := true, produce result
block if_found = BLOCK(gen_op_simple(DUP),
gen_const(jv_true()),
gen_op_bound(STOREV, found_var),
gen_op_var_bound(STOREV, found_var),
gen_op_target(JUMP, tail));
return BLOCK(init,
@@ -434,7 +400,7 @@ block gen_or(block a, block b) {
block gen_var_binding(block var, const char* name, block body) {
return BLOCK(gen_op_simple(DUP), var,
block_bind(gen_op_unbound(STOREV, name),
block_bind(gen_op_var_unbound(STOREV, name),
body, OP_HAS_VARIABLE));
}
@@ -475,12 +441,6 @@ static int count_cfunctions(block b) {
}
static int returns_immediately(inst* i) {
while (i->op == JUMP)
i = i->imm.target;
return i->op == RET;
}
// Expands call instructions into a calling sequence
static int expand_call_arglist(struct locfile* locations, block* b) {
int errors = 0;
@@ -488,7 +448,7 @@ static int expand_call_arglist(struct locfile* locations, block* b) {
for (inst* curr; (curr = block_take(b));) {
if (opcode_describe(curr->op)->flags & OP_HAS_BINDING) {
if (!curr->bound_by) {
locfile_locate(locations, curr->source, "error: %s/%d is not defined", curr->symbol, block_count_actuals(curr->arglist));
locfile_locate(locations, curr->source, "error: %s is not defined", curr->symbol);
errors++;
// don't process this instruction if it's not well-defined
ret = BLOCK(ret, inst_block(curr));
@@ -505,12 +465,6 @@ static int expand_call_arglist(struct locfile* locations, block* b) {
case CLOSURE_CREATE:
case CLOSURE_PARAM: {
block callargs = gen_noop();
/* A call is a tail call if:
a) the next instruction is a RET or a chain of unconditional JUMPs
that ends in a RET, and
b) none of the closures -callee included- are in the current bytecode block. */
int is_tail_call = b->first && returns_immediately(b->first);
if (!curr->bound_by->compiled) is_tail_call = 0;
for (inst* i; (i = block_take(&curr->arglist));) {
assert(opcode_describe(i->op)->flags & OP_IS_CALL_PSEUDO);
block b = inst_block(i);
@@ -521,15 +475,13 @@ static int expand_call_arglist(struct locfile* locations, block* b) {
break;
case CLOSURE_CREATE:
block_append(&prelude, b);
block_append(&callargs, gen_op_bound(CLOSURE_REF, b));
block_append(&callargs, gen_op_block_bound(CLOSURE_REF, b));
break;
}
if (!i->bound_by->compiled) is_tail_call = 0;
actual_args++;
}
curr->imm.intval = actual_args;
curr->arglist = callargs;
if (is_tail_call) curr->op = TAIL_CALL_JQ;
if (curr->bound_by->op == CLOSURE_CREATE) {
for (inst* i = curr->bound_by->arglist.first; i; i = i->next) {
@@ -561,7 +513,14 @@ static int expand_call_arglist(struct locfile* locations, block* b) {
}
}
assert(actual_args == desired_args); // because now handle this above
if (actual_args != desired_args) {
locfile_locate(locations, curr->source,
"error: %s arguments to %s (expected %d but got %d)",
actual_args > desired_args ? "too many" : "too few",
curr->symbol, desired_args, actual_args);
errors++;
}
}
ret = BLOCK(ret, prelude, inst_block(curr));
}
@@ -574,13 +533,13 @@ static int compile(struct locfile* locations, struct bytecode* bc, block b) {
int pos = 0;
int var_frame_idx = 0;
bc->nsubfunctions = 0;
b = BLOCK(b, gen_op_simple(RET));
errors += expand_call_arglist(locations, &b);
b = BLOCK(b, gen_op_simple(RET));
jv localnames = jv_array();
for (inst* curr = b.first; curr; curr = curr->next) {
if (!curr->next) assert(curr == b.last);
int length = opcode_describe(curr->op)->length;
if (curr->op == CALL_JQ || curr->op == TAIL_CALL_JQ) {
if (curr->op == CALL_JQ) {
for (inst* arg = curr->arglist.first; arg; arg = arg->next) {
length += 2;
}
@@ -654,7 +613,7 @@ static int compile(struct locfile* locations, struct bytecode* bc, block b) {
assert(!curr->arglist.first);
code[pos++] = (uint16_t)curr->imm.intval;
code[pos++] = curr->bound_by->imm.intval;
} else if (curr->op == CALL_JQ || curr->op == TAIL_CALL_JQ) {
} else if (curr->op == CALL_JQ) {
assert(curr->bound_by->op == CLOSURE_CREATE ||
curr->bound_by->op == CLOSURE_PARAM);
code[pos++] = (uint16_t)curr->imm.intval;
+8 -5
View File
@@ -2,9 +2,13 @@
#define COMPILE_H
#include <stdint.h>
#include "jv.h"
#include "bytecode.h"
#include "opcode.h"
#include "locfile.h"
struct bytecode;
struct symbol_table;
struct cfunction;
struct inst;
typedef struct inst inst;
@@ -20,12 +24,11 @@ block gen_noop();
block gen_op_simple(opcode op);
block gen_const(jv constant);
block gen_op_target(opcode op, block target);
block gen_op_unbound(opcode op, const char* name);
block gen_op_bound(opcode op, block binder);
block gen_op_var_fresh(opcode op, const char* name);
block gen_op_var_unbound(opcode op, const char* name);
block gen_op_var_bound(opcode op, block binder);
block gen_op_block_unbound(opcode op, const char* name);
block gen_function(const char* name, block formals, block body);
block gen_param(const char* name);
block gen_lambda(block body);
block gen_call(const char* name, block body);
block gen_subexp(block a);
+32
View File
@@ -0,0 +1,32 @@
/* config.h.in. Generated from configure.ac by autoheader. */
/* Define to 1 if your C compiler doesn't accept -c and -o together. */
#undef NO_MINUS_C_MINUS_O
/* Name of package */
#undef PACKAGE
/* Define to the address where bug reports for this package should be sent. */
#undef PACKAGE_BUGREPORT
/* Define to the full name of this package. */
#undef PACKAGE_NAME
/* Define to the full name and version of this package. */
#undef PACKAGE_STRING
/* Define to the one symbol short name of this package. */
#undef PACKAGE_TARNAME
/* Define to the home page for this package. */
#undef PACKAGE_URL
/* Define to the version of this package. */
#undef PACKAGE_VERSION
/* Version number of package */
#undef VERSION
/* Define to 1 if `lex' declares `yytext' as a `char *' by default, not a
`char[]'. */
#undef YYTEXT_POINTER
-10
View File
@@ -1,10 +0,0 @@
config.guess
config.sub
compile
depcomp
install-sh
ltmain.sh
missing
ylwrap
test-driver
ar-lib
Executable
+343
View File
@@ -0,0 +1,343 @@
#! /bin/sh
# Wrapper for compilers which do not understand '-c -o'.
scriptversion=2012-03-05.13; # UTC
# Copyright (C) 1999, 2000, 2003, 2004, 2005, 2009, 2010, 2012 Free
# Software Foundation, Inc.
# Written by Tom Tromey <tromey@cygnus.com>.
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2, or (at your option)
# any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
# As a special exception to the GNU General Public License, if you
# distribute this file as part of a program that contains a
# configuration script generated by Autoconf, you may include it under
# the same distribution terms that you use for the rest of that program.
# This file is maintained in Automake, please report
# bugs to <bug-automake@gnu.org> or send patches to
# <automake-patches@gnu.org>.
nl='
'
# We need space, tab and new line, in precisely that order. Quoting is
# there to prevent tools from complaining about whitespace usage.
IFS=" "" $nl"
file_conv=
# func_file_conv build_file lazy
# Convert a $build file to $host form and store it in $file
# Currently only supports Windows hosts. If the determined conversion
# type is listed in (the comma separated) LAZY, no conversion will
# take place.
func_file_conv ()
{
file=$1
case $file in
/ | /[!/]*) # absolute file, and not a UNC file
if test -z "$file_conv"; then
# lazily determine how to convert abs files
case `uname -s` in
MINGW*)
file_conv=mingw
;;
CYGWIN*)
file_conv=cygwin
;;
*)
file_conv=wine
;;
esac
fi
case $file_conv/,$2, in
*,$file_conv,*)
;;
mingw/*)
file=`cmd //C echo "$file " | sed -e 's/"\(.*\) " *$/\1/'`
;;
cygwin/*)
file=`cygpath -m "$file" || echo "$file"`
;;
wine/*)
file=`winepath -w "$file" || echo "$file"`
;;
esac
;;
esac
}
# func_cl_dashL linkdir
# Make cl look for libraries in LINKDIR
func_cl_dashL ()
{
func_file_conv "$1"
if test -z "$lib_path"; then
lib_path=$file
else
lib_path="$lib_path;$file"
fi
linker_opts="$linker_opts -LIBPATH:$file"
}
# func_cl_dashl library
# Do a library search-path lookup for cl
func_cl_dashl ()
{
lib=$1
found=no
save_IFS=$IFS
IFS=';'
for dir in $lib_path $LIB
do
IFS=$save_IFS
if $shared && test -f "$dir/$lib.dll.lib"; then
found=yes
lib=$dir/$lib.dll.lib
break
fi
if test -f "$dir/$lib.lib"; then
found=yes
lib=$dir/$lib.lib
break
fi
done
IFS=$save_IFS
if test "$found" != yes; then
lib=$lib.lib
fi
}
# func_cl_wrapper cl arg...
# Adjust compile command to suit cl
func_cl_wrapper ()
{
# Assume a capable shell
lib_path=
shared=:
linker_opts=
for arg
do
if test -n "$eat"; then
eat=
else
case $1 in
-o)
# configure might choose to run compile as 'compile cc -o foo foo.c'.
eat=1
case $2 in
*.o | *.[oO][bB][jJ])
func_file_conv "$2"
set x "$@" -Fo"$file"
shift
;;
*)
func_file_conv "$2"
set x "$@" -Fe"$file"
shift
;;
esac
;;
-I)
eat=1
func_file_conv "$2" mingw
set x "$@" -I"$file"
shift
;;
-I*)
func_file_conv "${1#-I}" mingw
set x "$@" -I"$file"
shift
;;
-l)
eat=1
func_cl_dashl "$2"
set x "$@" "$lib"
shift
;;
-l*)
func_cl_dashl "${1#-l}"
set x "$@" "$lib"
shift
;;
-L)
eat=1
func_cl_dashL "$2"
;;
-L*)
func_cl_dashL "${1#-L}"
;;
-static)
shared=false
;;
-Wl,*)
arg=${1#-Wl,}
save_ifs="$IFS"; IFS=','
for flag in $arg; do
IFS="$save_ifs"
linker_opts="$linker_opts $flag"
done
IFS="$save_ifs"
;;
-Xlinker)
eat=1
linker_opts="$linker_opts $2"
;;
-*)
set x "$@" "$1"
shift
;;
*.cc | *.CC | *.cxx | *.CXX | *.[cC]++)
func_file_conv "$1"
set x "$@" -Tp"$file"
shift
;;
*.c | *.cpp | *.CPP | *.lib | *.LIB | *.Lib | *.OBJ | *.obj | *.[oO])
func_file_conv "$1" mingw
set x "$@" "$file"
shift
;;
*)
set x "$@" "$1"
shift
;;
esac
fi
shift
done
if test -n "$linker_opts"; then
linker_opts="-link$linker_opts"
fi
exec "$@" $linker_opts
exit 1
}
eat=
case $1 in
'')
echo "$0: No command. Try '$0 --help' for more information." 1>&2
exit 1;
;;
-h | --h*)
cat <<\EOF
Usage: compile [--help] [--version] PROGRAM [ARGS]
Wrapper for compilers which do not understand '-c -o'.
Remove '-o dest.o' from ARGS, run PROGRAM with the remaining
arguments, and rename the output as expected.
If you are trying to build a whole package this is not the
right script to run: please start by reading the file 'INSTALL'.
Report bugs to <bug-automake@gnu.org>.
EOF
exit $?
;;
-v | --v*)
echo "compile $scriptversion"
exit $?
;;
cl | *[/\\]cl | cl.exe | *[/\\]cl.exe )
func_cl_wrapper "$@" # Doesn't return...
;;
esac
ofile=
cfile=
for arg
do
if test -n "$eat"; then
eat=
else
case $1 in
-o)
# configure might choose to run compile as 'compile cc -o foo foo.c'.
# So we strip '-o arg' only if arg is an object.
eat=1
case $2 in
*.o | *.obj)
ofile=$2
;;
*)
set x "$@" -o "$2"
shift
;;
esac
;;
*.c)
cfile=$1
set x "$@" "$1"
shift
;;
*)
set x "$@" "$1"
shift
;;
esac
fi
shift
done
if test -z "$ofile" || test -z "$cfile"; then
# If no '-o' option was seen then we might have been invoked from a
# pattern rule where we don't need one. That is ok -- this is a
# normal compilation that the losing compiler can handle. If no
# '.c' file was seen then we are probably linking. That is also
# ok.
exec "$@"
fi
# Name of file we expect compiler to create.
cofile=`echo "$cfile" | sed 's|^.*[\\/]||; s|^[a-zA-Z]:||; s/\.c$/.o/'`
# Create the lock directory.
# Note: use '[/\\:.-]' here to ensure that we don't use the same name
# that we are using for the .o file. Also, base the name on the expected
# object file name, since that is what matters with a parallel build.
lockdir=`echo "$cofile" | sed -e 's|[/\\:.-]|_|g'`.d
while true; do
if mkdir "$lockdir" >/dev/null 2>&1; then
break
fi
sleep 1
done
# FIXME: race condition here if user kills between mkdir and trap.
trap "rmdir '$lockdir'; exit 1" 1 2 15
# Run the compile.
"$@"
ret=$?
if test -f "$cofile"; then
test "$cofile" = "$ofile" || mv "$cofile" "$ofile"
elif test -f "${cofile}bj"; then
test "${cofile}bj" = "$ofile" || mv "${cofile}bj" "$ofile"
fi
rmdir "$lockdir"
exit $ret
# Local Variables:
# mode: shell-script
# sh-indentation: 2
# eval: (add-hook 'write-file-hooks 'time-stamp)
# time-stamp-start: "scriptversion="
# time-stamp-format: "%:y-%02m-%02d.%02H"
# time-stamp-time-zone: "UTC"
# time-stamp-end: "; # UTC"
# End:
Executable
+708
View File
@@ -0,0 +1,708 @@
#! /bin/sh
# depcomp - compile a program generating dependencies as side-effects
scriptversion=2012-03-27.16; # UTC
# Copyright (C) 1999, 2000, 2003, 2004, 2005, 2006, 2007, 2009, 2010,
# 2011, 2012 Free Software Foundation, Inc.
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2, or (at your option)
# any later version.
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
# As a special exception to the GNU General Public License, if you
# distribute this file as part of a program that contains a
# configuration script generated by Autoconf, you may include it under
# the same distribution terms that you use for the rest of that program.
# Originally written by Alexandre Oliva <oliva@dcc.unicamp.br>.
case $1 in
'')
echo "$0: No command. Try '$0 --help' for more information." 1>&2
exit 1;
;;
-h | --h*)
cat <<\EOF
Usage: depcomp [--help] [--version] PROGRAM [ARGS]
Run PROGRAMS ARGS to compile a file, generating dependencies
as side-effects.
Environment variables:
depmode Dependency tracking mode.
source Source file read by 'PROGRAMS ARGS'.
object Object file output by 'PROGRAMS ARGS'.
DEPDIR directory where to store dependencies.
depfile Dependency file to output.
tmpdepfile Temporary file to use when outputting dependencies.
libtool Whether libtool is used (yes/no).
Report bugs to <bug-automake@gnu.org>.
EOF
exit $?
;;
-v | --v*)
echo "depcomp $scriptversion"
exit $?
;;
esac
# A tabulation character.
tab=' '
# A newline character.
nl='
'
if test -z "$depmode" || test -z "$source" || test -z "$object"; then
echo "depcomp: Variables source, object and depmode must be set" 1>&2
exit 1
fi
# Dependencies for sub/bar.o or sub/bar.obj go into sub/.deps/bar.Po.
depfile=${depfile-`echo "$object" |
sed 's|[^\\/]*$|'${DEPDIR-.deps}'/&|;s|\.\([^.]*\)$|.P\1|;s|Pobj$|Po|'`}
tmpdepfile=${tmpdepfile-`echo "$depfile" | sed 's/\.\([^.]*\)$/.T\1/'`}
rm -f "$tmpdepfile"
# Some modes work just like other modes, but use different flags. We
# parameterize here, but still list the modes in the big case below,
# to make depend.m4 easier to write. Note that we *cannot* use a case
# here, because this file can only contain one case statement.
if test "$depmode" = hp; then
# HP compiler uses -M and no extra arg.
gccflag=-M
depmode=gcc
fi
if test "$depmode" = dashXmstdout; then
# This is just like dashmstdout with a different argument.
dashmflag=-xM
depmode=dashmstdout
fi
cygpath_u="cygpath -u -f -"
if test "$depmode" = msvcmsys; then
# This is just like msvisualcpp but w/o cygpath translation.
# Just convert the backslash-escaped backslashes to single forward
# slashes to satisfy depend.m4
cygpath_u='sed s,\\\\,/,g'
depmode=msvisualcpp
fi
if test "$depmode" = msvc7msys; then
# This is just like msvc7 but w/o cygpath translation.
# Just convert the backslash-escaped backslashes to single forward
# slashes to satisfy depend.m4
cygpath_u='sed s,\\\\,/,g'
depmode=msvc7
fi
if test "$depmode" = xlc; then
# IBM C/C++ Compilers xlc/xlC can output gcc-like dependency informations.
gccflag=-qmakedep=gcc,-MF
depmode=gcc
fi
case "$depmode" in
gcc3)
## gcc 3 implements dependency tracking that does exactly what
## we want. Yay! Note: for some reason libtool 1.4 doesn't like
## it if -MD -MP comes after the -MF stuff. Hmm.
## Unfortunately, FreeBSD c89 acceptance of flags depends upon
## the command line argument order; so add the flags where they
## appear in depend2.am. Note that the slowdown incurred here
## affects only configure: in makefiles, %FASTDEP% shortcuts this.
for arg
do
case $arg in
-c) set fnord "$@" -MT "$object" -MD -MP -MF "$tmpdepfile" "$arg" ;;
*) set fnord "$@" "$arg" ;;
esac
shift # fnord
shift # $arg
done
"$@"
stat=$?
if test $stat -eq 0; then :
else
rm -f "$tmpdepfile"
exit $stat
fi
mv "$tmpdepfile" "$depfile"
;;
gcc)
## There are various ways to get dependency output from gcc. Here's
## why we pick this rather obscure method:
## - Don't want to use -MD because we'd like the dependencies to end
## up in a subdir. Having to rename by hand is ugly.
## (We might end up doing this anyway to support other compilers.)
## - The DEPENDENCIES_OUTPUT environment variable makes gcc act like
## -MM, not -M (despite what the docs say).
## - Using -M directly means running the compiler twice (even worse
## than renaming).
if test -z "$gccflag"; then
gccflag=-MD,
fi
"$@" -Wp,"$gccflag$tmpdepfile"
stat=$?
if test $stat -eq 0; then :
else
rm -f "$tmpdepfile"
exit $stat
fi
rm -f "$depfile"
echo "$object : \\" > "$depfile"
alpha=ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz
## The second -e expression handles DOS-style file names with drive letters.
sed -e 's/^[^:]*: / /' \
-e 's/^['$alpha']:\/[^:]*: / /' < "$tmpdepfile" >> "$depfile"
## This next piece of magic avoids the "deleted header file" problem.
## The problem is that when a header file which appears in a .P file
## is deleted, the dependency causes make to die (because there is
## typically no way to rebuild the header). We avoid this by adding
## dummy dependencies for each header file. Too bad gcc doesn't do
## this for us directly.
tr ' ' "$nl" < "$tmpdepfile" |
## Some versions of gcc put a space before the ':'. On the theory
## that the space means something, we add a space to the output as
## well. hp depmode also adds that space, but also prefixes the VPATH
## to the object. Take care to not repeat it in the output.
## Some versions of the HPUX 10.20 sed can't process this invocation
## correctly. Breaking it into two sed invocations is a workaround.
sed -e 's/^\\$//' -e '/^$/d' -e "s|.*$object$||" -e '/:$/d' \
| sed -e 's/$/ :/' >> "$depfile"
rm -f "$tmpdepfile"
;;
hp)
# This case exists only to let depend.m4 do its work. It works by
# looking at the text of this script. This case will never be run,
# since it is checked for above.
exit 1
;;
sgi)
if test "$libtool" = yes; then
"$@" "-Wp,-MDupdate,$tmpdepfile"
else
"$@" -MDupdate "$tmpdepfile"
fi
stat=$?
if test $stat -eq 0; then :
else
rm -f "$tmpdepfile"
exit $stat
fi
rm -f "$depfile"
if test -f "$tmpdepfile"; then # yes, the sourcefile depend on other files
echo "$object : \\" > "$depfile"
# Clip off the initial element (the dependent). Don't try to be
# clever and replace this with sed code, as IRIX sed won't handle
# lines with more than a fixed number of characters (4096 in
# IRIX 6.2 sed, 8192 in IRIX 6.5). We also remove comment lines;
# the IRIX cc adds comments like '#:fec' to the end of the
# dependency line.
tr ' ' "$nl" < "$tmpdepfile" \
| sed -e 's/^.*\.o://' -e 's/#.*$//' -e '/^$/ d' | \
tr "$nl" ' ' >> "$depfile"
echo >> "$depfile"
# The second pass generates a dummy entry for each header file.
tr ' ' "$nl" < "$tmpdepfile" \
| sed -e 's/^.*\.o://' -e 's/#.*$//' -e '/^$/ d' -e 's/$/:/' \
>> "$depfile"
else
# The sourcefile does not contain any dependencies, so just
# store a dummy comment line, to avoid errors with the Makefile
# "include basename.Plo" scheme.
echo "#dummy" > "$depfile"
fi
rm -f "$tmpdepfile"
;;
xlc)
# This case exists only to let depend.m4 do its work. It works by
# looking at the text of this script. This case will never be run,
# since it is checked for above.
exit 1
;;
aix)
# The C for AIX Compiler uses -M and outputs the dependencies
# in a .u file. In older versions, this file always lives in the
# current directory. Also, the AIX compiler puts '$object:' at the
# start of each line; $object doesn't have directory information.
# Version 6 uses the directory in both cases.
dir=`echo "$object" | sed -e 's|/[^/]*$|/|'`
test "x$dir" = "x$object" && dir=
base=`echo "$object" | sed -e 's|^.*/||' -e 's/\.o$//' -e 's/\.lo$//'`
if test "$libtool" = yes; then
tmpdepfile1=$dir$base.u
tmpdepfile2=$base.u
tmpdepfile3=$dir.libs/$base.u
"$@" -Wc,-M
else
tmpdepfile1=$dir$base.u
tmpdepfile2=$dir$base.u
tmpdepfile3=$dir$base.u
"$@" -M
fi
stat=$?
if test $stat -eq 0; then :
else
rm -f "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3"
exit $stat
fi
for tmpdepfile in "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3"
do
test -f "$tmpdepfile" && break
done
if test -f "$tmpdepfile"; then
# Each line is of the form 'foo.o: dependent.h'.
# Do two passes, one to just change these to
# '$object: dependent.h' and one to simply 'dependent.h:'.
sed -e "s,^.*\.[a-z]*:,$object:," < "$tmpdepfile" > "$depfile"
sed -e 's,^.*\.[a-z]*:['"$tab"' ]*,,' -e 's,$,:,' < "$tmpdepfile" >> "$depfile"
else
# The sourcefile does not contain any dependencies, so just
# store a dummy comment line, to avoid errors with the Makefile
# "include basename.Plo" scheme.
echo "#dummy" > "$depfile"
fi
rm -f "$tmpdepfile"
;;
icc)
# Intel's C compiler anf tcc (Tiny C Compiler) understand '-MD -MF file'.
# However on
# $CC -MD -MF foo.d -c -o sub/foo.o sub/foo.c
# ICC 7.0 will fill foo.d with something like
# foo.o: sub/foo.c
# foo.o: sub/foo.h
# which is wrong. We want
# sub/foo.o: sub/foo.c
# sub/foo.o: sub/foo.h
# sub/foo.c:
# sub/foo.h:
# ICC 7.1 will output
# foo.o: sub/foo.c sub/foo.h
# and will wrap long lines using '\':
# foo.o: sub/foo.c ... \
# sub/foo.h ... \
# ...
# tcc 0.9.26 (FIXME still under development at the moment of writing)
# will emit a similar output, but also prepend the continuation lines
# with horizontal tabulation characters.
"$@" -MD -MF "$tmpdepfile"
stat=$?
if test $stat -eq 0; then :
else
rm -f "$tmpdepfile"
exit $stat
fi
rm -f "$depfile"
# Each line is of the form 'foo.o: dependent.h',
# or 'foo.o: dep1.h dep2.h \', or ' dep3.h dep4.h \'.
# Do two passes, one to just change these to
# '$object: dependent.h' and one to simply 'dependent.h:'.
sed -e "s/^[ $tab][ $tab]*/ /" -e "s,^[^:]*:,$object :," \
< "$tmpdepfile" > "$depfile"
sed '
s/[ '"$tab"'][ '"$tab"']*/ /g
s/^ *//
s/ *\\*$//
s/^[^:]*: *//
/^$/d
/:$/d
s/$/ :/
' < "$tmpdepfile" >> "$depfile"
rm -f "$tmpdepfile"
;;
hp2)
# The "hp" stanza above does not work with aCC (C++) and HP's ia64
# compilers, which have integrated preprocessors. The correct option
# to use with these is +Maked; it writes dependencies to a file named
# 'foo.d', which lands next to the object file, wherever that
# happens to be.
# Much of this is similar to the tru64 case; see comments there.
dir=`echo "$object" | sed -e 's|/[^/]*$|/|'`
test "x$dir" = "x$object" && dir=
base=`echo "$object" | sed -e 's|^.*/||' -e 's/\.o$//' -e 's/\.lo$//'`
if test "$libtool" = yes; then
tmpdepfile1=$dir$base.d
tmpdepfile2=$dir.libs/$base.d
"$@" -Wc,+Maked
else
tmpdepfile1=$dir$base.d
tmpdepfile2=$dir$base.d
"$@" +Maked
fi
stat=$?
if test $stat -eq 0; then :
else
rm -f "$tmpdepfile1" "$tmpdepfile2"
exit $stat
fi
for tmpdepfile in "$tmpdepfile1" "$tmpdepfile2"
do
test -f "$tmpdepfile" && break
done
if test -f "$tmpdepfile"; then
sed -e "s,^.*\.[a-z]*:,$object:," "$tmpdepfile" > "$depfile"
# Add 'dependent.h:' lines.
sed -ne '2,${
s/^ *//
s/ \\*$//
s/$/:/
p
}' "$tmpdepfile" >> "$depfile"
else
echo "#dummy" > "$depfile"
fi
rm -f "$tmpdepfile" "$tmpdepfile2"
;;
tru64)
# The Tru64 compiler uses -MD to generate dependencies as a side
# effect. 'cc -MD -o foo.o ...' puts the dependencies into 'foo.o.d'.
# At least on Alpha/Redhat 6.1, Compaq CCC V6.2-504 seems to put
# dependencies in 'foo.d' instead, so we check for that too.
# Subdirectories are respected.
dir=`echo "$object" | sed -e 's|/[^/]*$|/|'`
test "x$dir" = "x$object" && dir=
base=`echo "$object" | sed -e 's|^.*/||' -e 's/\.o$//' -e 's/\.lo$//'`
if test "$libtool" = yes; then
# With Tru64 cc, shared objects can also be used to make a
# static library. This mechanism is used in libtool 1.4 series to
# handle both shared and static libraries in a single compilation.
# With libtool 1.4, dependencies were output in $dir.libs/$base.lo.d.
#
# With libtool 1.5 this exception was removed, and libtool now
# generates 2 separate objects for the 2 libraries. These two
# compilations output dependencies in $dir.libs/$base.o.d and
# in $dir$base.o.d. We have to check for both files, because
# one of the two compilations can be disabled. We should prefer
# $dir$base.o.d over $dir.libs/$base.o.d because the latter is
# automatically cleaned when .libs/ is deleted, while ignoring
# the former would cause a distcleancheck panic.
tmpdepfile1=$dir.libs/$base.lo.d # libtool 1.4
tmpdepfile2=$dir$base.o.d # libtool 1.5
tmpdepfile3=$dir.libs/$base.o.d # libtool 1.5
tmpdepfile4=$dir.libs/$base.d # Compaq CCC V6.2-504
"$@" -Wc,-MD
else
tmpdepfile1=$dir$base.o.d
tmpdepfile2=$dir$base.d
tmpdepfile3=$dir$base.d
tmpdepfile4=$dir$base.d
"$@" -MD
fi
stat=$?
if test $stat -eq 0; then :
else
rm -f "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3" "$tmpdepfile4"
exit $stat
fi
for tmpdepfile in "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3" "$tmpdepfile4"
do
test -f "$tmpdepfile" && break
done
if test -f "$tmpdepfile"; then
sed -e "s,^.*\.[a-z]*:,$object:," < "$tmpdepfile" > "$depfile"
sed -e 's,^.*\.[a-z]*:['"$tab"' ]*,,' -e 's,$,:,' < "$tmpdepfile" >> "$depfile"
else
echo "#dummy" > "$depfile"
fi
rm -f "$tmpdepfile"
;;
msvc7)
if test "$libtool" = yes; then
showIncludes=-Wc,-showIncludes
else
showIncludes=-showIncludes
fi
"$@" $showIncludes > "$tmpdepfile"
stat=$?
grep -v '^Note: including file: ' "$tmpdepfile"
if test "$stat" = 0; then :
else
rm -f "$tmpdepfile"
exit $stat
fi
rm -f "$depfile"
echo "$object : \\" > "$depfile"
# The first sed program below extracts the file names and escapes
# backslashes for cygpath. The second sed program outputs the file
# name when reading, but also accumulates all include files in the
# hold buffer in order to output them again at the end. This only
# works with sed implementations that can handle large buffers.
sed < "$tmpdepfile" -n '
/^Note: including file: *\(.*\)/ {
s//\1/
s/\\/\\\\/g
p
}' | $cygpath_u | sort -u | sed -n '
s/ /\\ /g
s/\(.*\)/'"$tab"'\1 \\/p
s/.\(.*\) \\/\1:/
H
$ {
s/.*/'"$tab"'/
G
p
}' >> "$depfile"
rm -f "$tmpdepfile"
;;
msvc7msys)
# This case exists only to let depend.m4 do its work. It works by
# looking at the text of this script. This case will never be run,
# since it is checked for above.
exit 1
;;
#nosideeffect)
# This comment above is used by automake to tell side-effect
# dependency tracking mechanisms from slower ones.
dashmstdout)
# Important note: in order to support this mode, a compiler *must*
# always write the preprocessed file to stdout, regardless of -o.
"$@" || exit $?
# Remove the call to Libtool.
if test "$libtool" = yes; then
while test "X$1" != 'X--mode=compile'; do
shift
done
shift
fi
# Remove '-o $object'.
IFS=" "
for arg
do
case $arg in
-o)
shift
;;
$object)
shift
;;
*)
set fnord "$@" "$arg"
shift # fnord
shift # $arg
;;
esac
done
test -z "$dashmflag" && dashmflag=-M
# Require at least two characters before searching for ':'
# in the target name. This is to cope with DOS-style filenames:
# a dependency such as 'c:/foo/bar' could be seen as target 'c' otherwise.
"$@" $dashmflag |
sed 's:^['"$tab"' ]*[^:'"$tab"' ][^:][^:]*\:['"$tab"' ]*:'"$object"'\: :' > "$tmpdepfile"
rm -f "$depfile"
cat < "$tmpdepfile" > "$depfile"
tr ' ' "$nl" < "$tmpdepfile" | \
## Some versions of the HPUX 10.20 sed can't process this invocation
## correctly. Breaking it into two sed invocations is a workaround.
sed -e 's/^\\$//' -e '/^$/d' -e '/:$/d' | sed -e 's/$/ :/' >> "$depfile"
rm -f "$tmpdepfile"
;;
dashXmstdout)
# This case only exists to satisfy depend.m4. It is never actually
# run, as this mode is specially recognized in the preamble.
exit 1
;;
makedepend)
"$@" || exit $?
# Remove any Libtool call
if test "$libtool" = yes; then
while test "X$1" != 'X--mode=compile'; do
shift
done
shift
fi
# X makedepend
shift
cleared=no eat=no
for arg
do
case $cleared in
no)
set ""; shift
cleared=yes ;;
esac
if test $eat = yes; then
eat=no
continue
fi
case "$arg" in
-D*|-I*)
set fnord "$@" "$arg"; shift ;;
# Strip any option that makedepend may not understand. Remove
# the object too, otherwise makedepend will parse it as a source file.
-arch)
eat=yes ;;
-*|$object)
;;
*)
set fnord "$@" "$arg"; shift ;;
esac
done
obj_suffix=`echo "$object" | sed 's/^.*\././'`
touch "$tmpdepfile"
${MAKEDEPEND-makedepend} -o"$obj_suffix" -f"$tmpdepfile" "$@"
rm -f "$depfile"
# makedepend may prepend the VPATH from the source file name to the object.
# No need to regex-escape $object, excess matching of '.' is harmless.
sed "s|^.*\($object *:\)|\1|" "$tmpdepfile" > "$depfile"
sed '1,2d' "$tmpdepfile" | tr ' ' "$nl" | \
## Some versions of the HPUX 10.20 sed can't process this invocation
## correctly. Breaking it into two sed invocations is a workaround.
sed -e 's/^\\$//' -e '/^$/d' -e '/:$/d' | sed -e 's/$/ :/' >> "$depfile"
rm -f "$tmpdepfile" "$tmpdepfile".bak
;;
cpp)
# Important note: in order to support this mode, a compiler *must*
# always write the preprocessed file to stdout.
"$@" || exit $?
# Remove the call to Libtool.
if test "$libtool" = yes; then
while test "X$1" != 'X--mode=compile'; do
shift
done
shift
fi
# Remove '-o $object'.
IFS=" "
for arg
do
case $arg in
-o)
shift
;;
$object)
shift
;;
*)
set fnord "$@" "$arg"
shift # fnord
shift # $arg
;;
esac
done
"$@" -E |
sed -n -e '/^# [0-9][0-9]* "\([^"]*\)".*/ s:: \1 \\:p' \
-e '/^#line [0-9][0-9]* "\([^"]*\)".*/ s:: \1 \\:p' |
sed '$ s: \\$::' > "$tmpdepfile"
rm -f "$depfile"
echo "$object : \\" > "$depfile"
cat < "$tmpdepfile" >> "$depfile"
sed < "$tmpdepfile" '/^$/d;s/^ //;s/ \\$//;s/$/ :/' >> "$depfile"
rm -f "$tmpdepfile"
;;
msvisualcpp)
# Important note: in order to support this mode, a compiler *must*
# always write the preprocessed file to stdout.
"$@" || exit $?
# Remove the call to Libtool.
if test "$libtool" = yes; then
while test "X$1" != 'X--mode=compile'; do
shift
done
shift
fi
IFS=" "
for arg
do
case "$arg" in
-o)
shift
;;
$object)
shift
;;
"-Gm"|"/Gm"|"-Gi"|"/Gi"|"-ZI"|"/ZI")
set fnord "$@"
shift
shift
;;
*)
set fnord "$@" "$arg"
shift
shift
;;
esac
done
"$@" -E 2>/dev/null |
sed -n '/^#line [0-9][0-9]* "\([^"]*\)"/ s::\1:p' | $cygpath_u | sort -u > "$tmpdepfile"
rm -f "$depfile"
echo "$object : \\" > "$depfile"
sed < "$tmpdepfile" -n -e 's% %\\ %g' -e '/^\(.*\)$/ s::'"$tab"'\1 \\:p' >> "$depfile"
echo "$tab" >> "$depfile"
sed < "$tmpdepfile" -n -e 's% %\\ %g' -e '/^\(.*\)$/ s::\1\::p' >> "$depfile"
rm -f "$tmpdepfile"
;;
msvcmsys)
# This case exists only to let depend.m4 do its work. It works by
# looking at the text of this script. This case will never be run,
# since it is checked for above.
exit 1
;;
none)
exec "$@"
;;
*)
echo "Unknown depmode $depmode" 1>&2
exit 1
;;
esac
exit 0
# Local Variables:
# mode: shell-script
# sh-indentation: 2
# eval: (add-hook 'write-file-hooks 'time-stamp)
# time-stamp-start: "scriptversion="
# time-stamp-format: "%:y-%02m-%02d.%02H"
# time-stamp-time-zone: "UTC"
# time-stamp-end: "; # UTC"
# End:
+527
View File
@@ -0,0 +1,527 @@
#!/bin/sh
# install - install a program, script, or datafile
scriptversion=2011-01-19.21; # UTC
# This originates from X11R5 (mit/util/scripts/install.sh), which was
# later released in X11R6 (xc/config/util/install.sh) with the
# following copyright and license.
#
# Copyright (C) 1994 X Consortium
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to
# deal in the Software without restriction, including without limitation the
# rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
# sell copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
# AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNEC-
# TION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#
# Except as contained in this notice, the name of the X Consortium shall not
# be used in advertising or otherwise to promote the sale, use or other deal-
# ings in this Software without prior written authorization from the X Consor-
# tium.
#
#
# FSF changes to this file are in the public domain.
#
# Calling this script install-sh is preferred over install.sh, to prevent
# `make' implicit rules from creating a file called install from it
# when there is no Makefile.
#
# This script is compatible with the BSD install script, but was written
# from scratch.
nl='
'
IFS=" "" $nl"
# set DOITPROG to echo to test this script
# Don't use :- since 4.3BSD and earlier shells don't like it.
doit=${DOITPROG-}
if test -z "$doit"; then
doit_exec=exec
else
doit_exec=$doit
fi
# Put in absolute file names if you don't have them in your path;
# or use environment vars.
chgrpprog=${CHGRPPROG-chgrp}
chmodprog=${CHMODPROG-chmod}
chownprog=${CHOWNPROG-chown}
cmpprog=${CMPPROG-cmp}
cpprog=${CPPROG-cp}
mkdirprog=${MKDIRPROG-mkdir}
mvprog=${MVPROG-mv}
rmprog=${RMPROG-rm}
stripprog=${STRIPPROG-strip}
posix_glob='?'
initialize_posix_glob='
test "$posix_glob" != "?" || {
if (set -f) 2>/dev/null; then
posix_glob=
else
posix_glob=:
fi
}
'
posix_mkdir=
# Desired mode of installed file.
mode=0755
chgrpcmd=
chmodcmd=$chmodprog
chowncmd=
mvcmd=$mvprog
rmcmd="$rmprog -f"
stripcmd=
src=
dst=
dir_arg=
dst_arg=
copy_on_change=false
no_target_directory=
usage="\
Usage: $0 [OPTION]... [-T] SRCFILE DSTFILE
or: $0 [OPTION]... SRCFILES... DIRECTORY
or: $0 [OPTION]... -t DIRECTORY SRCFILES...
or: $0 [OPTION]... -d DIRECTORIES...
In the 1st form, copy SRCFILE to DSTFILE.
In the 2nd and 3rd, copy all SRCFILES to DIRECTORY.
In the 4th, create DIRECTORIES.
Options:
--help display this help and exit.
--version display version info and exit.
-c (ignored)
-C install only if different (preserve the last data modification time)
-d create directories instead of installing files.
-g GROUP $chgrpprog installed files to GROUP.
-m MODE $chmodprog installed files to MODE.
-o USER $chownprog installed files to USER.
-s $stripprog installed files.
-t DIRECTORY install into DIRECTORY.
-T report an error if DSTFILE is a directory.
Environment variables override the default commands:
CHGRPPROG CHMODPROG CHOWNPROG CMPPROG CPPROG MKDIRPROG MVPROG
RMPROG STRIPPROG
"
while test $# -ne 0; do
case $1 in
-c) ;;
-C) copy_on_change=true;;
-d) dir_arg=true;;
-g) chgrpcmd="$chgrpprog $2"
shift;;
--help) echo "$usage"; exit $?;;
-m) mode=$2
case $mode in
*' '* | *' '* | *'
'* | *'*'* | *'?'* | *'['*)
echo "$0: invalid mode: $mode" >&2
exit 1;;
esac
shift;;
-o) chowncmd="$chownprog $2"
shift;;
-s) stripcmd=$stripprog;;
-t) dst_arg=$2
# Protect names problematic for `test' and other utilities.
case $dst_arg in
-* | [=\(\)!]) dst_arg=./$dst_arg;;
esac
shift;;
-T) no_target_directory=true;;
--version) echo "$0 $scriptversion"; exit $?;;
--) shift
break;;
-*) echo "$0: invalid option: $1" >&2
exit 1;;
*) break;;
esac
shift
done
if test $# -ne 0 && test -z "$dir_arg$dst_arg"; then
# When -d is used, all remaining arguments are directories to create.
# When -t is used, the destination is already specified.
# Otherwise, the last argument is the destination. Remove it from $@.
for arg
do
if test -n "$dst_arg"; then
# $@ is not empty: it contains at least $arg.
set fnord "$@" "$dst_arg"
shift # fnord
fi
shift # arg
dst_arg=$arg
# Protect names problematic for `test' and other utilities.
case $dst_arg in
-* | [=\(\)!]) dst_arg=./$dst_arg;;
esac
done
fi
if test $# -eq 0; then
if test -z "$dir_arg"; then
echo "$0: no input file specified." >&2
exit 1
fi
# It's OK to call `install-sh -d' without argument.
# This can happen when creating conditional directories.
exit 0
fi
if test -z "$dir_arg"; then
do_exit='(exit $ret); exit $ret'
trap "ret=129; $do_exit" 1
trap "ret=130; $do_exit" 2
trap "ret=141; $do_exit" 13
trap "ret=143; $do_exit" 15
# Set umask so as not to create temps with too-generous modes.
# However, 'strip' requires both read and write access to temps.
case $mode in
# Optimize common cases.
*644) cp_umask=133;;
*755) cp_umask=22;;
*[0-7])
if test -z "$stripcmd"; then
u_plus_rw=
else
u_plus_rw='% 200'
fi
cp_umask=`expr '(' 777 - $mode % 1000 ')' $u_plus_rw`;;
*)
if test -z "$stripcmd"; then
u_plus_rw=
else
u_plus_rw=,u+rw
fi
cp_umask=$mode$u_plus_rw;;
esac
fi
for src
do
# Protect names problematic for `test' and other utilities.
case $src in
-* | [=\(\)!]) src=./$src;;
esac
if test -n "$dir_arg"; then
dst=$src
dstdir=$dst
test -d "$dstdir"
dstdir_status=$?
else
# Waiting for this to be detected by the "$cpprog $src $dsttmp" command
# might cause directories to be created, which would be especially bad
# if $src (and thus $dsttmp) contains '*'.
if test ! -f "$src" && test ! -d "$src"; then
echo "$0: $src does not exist." >&2
exit 1
fi
if test -z "$dst_arg"; then
echo "$0: no destination specified." >&2
exit 1
fi
dst=$dst_arg
# If destination is a directory, append the input filename; won't work
# if double slashes aren't ignored.
if test -d "$dst"; then
if test -n "$no_target_directory"; then
echo "$0: $dst_arg: Is a directory" >&2
exit 1
fi
dstdir=$dst
dst=$dstdir/`basename "$src"`
dstdir_status=0
else
# Prefer dirname, but fall back on a substitute if dirname fails.
dstdir=`
(dirname "$dst") 2>/dev/null ||
expr X"$dst" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
X"$dst" : 'X\(//\)[^/]' \| \
X"$dst" : 'X\(//\)$' \| \
X"$dst" : 'X\(/\)' \| . 2>/dev/null ||
echo X"$dst" |
sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
s//\1/
q
}
/^X\(\/\/\)[^/].*/{
s//\1/
q
}
/^X\(\/\/\)$/{
s//\1/
q
}
/^X\(\/\).*/{
s//\1/
q
}
s/.*/./; q'
`
test -d "$dstdir"
dstdir_status=$?
fi
fi
obsolete_mkdir_used=false
if test $dstdir_status != 0; then
case $posix_mkdir in
'')
# Create intermediate dirs using mode 755 as modified by the umask.
# This is like FreeBSD 'install' as of 1997-10-28.
umask=`umask`
case $stripcmd.$umask in
# Optimize common cases.
*[2367][2367]) mkdir_umask=$umask;;
.*0[02][02] | .[02][02] | .[02]) mkdir_umask=22;;
*[0-7])
mkdir_umask=`expr $umask + 22 \
- $umask % 100 % 40 + $umask % 20 \
- $umask % 10 % 4 + $umask % 2
`;;
*) mkdir_umask=$umask,go-w;;
esac
# With -d, create the new directory with the user-specified mode.
# Otherwise, rely on $mkdir_umask.
if test -n "$dir_arg"; then
mkdir_mode=-m$mode
else
mkdir_mode=
fi
posix_mkdir=false
case $umask in
*[123567][0-7][0-7])
# POSIX mkdir -p sets u+wx bits regardless of umask, which
# is incompatible with FreeBSD 'install' when (umask & 300) != 0.
;;
*)
tmpdir=${TMPDIR-/tmp}/ins$RANDOM-$$
trap 'ret=$?; rmdir "$tmpdir/d" "$tmpdir" 2>/dev/null; exit $ret' 0
if (umask $mkdir_umask &&
exec $mkdirprog $mkdir_mode -p -- "$tmpdir/d") >/dev/null 2>&1
then
if test -z "$dir_arg" || {
# Check for POSIX incompatibilities with -m.
# HP-UX 11.23 and IRIX 6.5 mkdir -m -p sets group- or
# other-writeable bit of parent directory when it shouldn't.
# FreeBSD 6.1 mkdir -m -p sets mode of existing directory.
ls_ld_tmpdir=`ls -ld "$tmpdir"`
case $ls_ld_tmpdir in
d????-?r-*) different_mode=700;;
d????-?--*) different_mode=755;;
*) false;;
esac &&
$mkdirprog -m$different_mode -p -- "$tmpdir" && {
ls_ld_tmpdir_1=`ls -ld "$tmpdir"`
test "$ls_ld_tmpdir" = "$ls_ld_tmpdir_1"
}
}
then posix_mkdir=:
fi
rmdir "$tmpdir/d" "$tmpdir"
else
# Remove any dirs left behind by ancient mkdir implementations.
rmdir ./$mkdir_mode ./-p ./-- 2>/dev/null
fi
trap '' 0;;
esac;;
esac
if
$posix_mkdir && (
umask $mkdir_umask &&
$doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir"
)
then :
else
# The umask is ridiculous, or mkdir does not conform to POSIX,
# or it failed possibly due to a race condition. Create the
# directory the slow way, step by step, checking for races as we go.
case $dstdir in
/*) prefix='/';;
[-=\(\)!]*) prefix='./';;
*) prefix='';;
esac
eval "$initialize_posix_glob"
oIFS=$IFS
IFS=/
$posix_glob set -f
set fnord $dstdir
shift
$posix_glob set +f
IFS=$oIFS
prefixes=
for d
do
test X"$d" = X && continue
prefix=$prefix$d
if test -d "$prefix"; then
prefixes=
else
if $posix_mkdir; then
(umask=$mkdir_umask &&
$doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir") && break
# Don't fail if two instances are running concurrently.
test -d "$prefix" || exit 1
else
case $prefix in
*\'*) qprefix=`echo "$prefix" | sed "s/'/'\\\\\\\\''/g"`;;
*) qprefix=$prefix;;
esac
prefixes="$prefixes '$qprefix'"
fi
fi
prefix=$prefix/
done
if test -n "$prefixes"; then
# Don't fail if two instances are running concurrently.
(umask $mkdir_umask &&
eval "\$doit_exec \$mkdirprog $prefixes") ||
test -d "$dstdir" || exit 1
obsolete_mkdir_used=true
fi
fi
fi
if test -n "$dir_arg"; then
{ test -z "$chowncmd" || $doit $chowncmd "$dst"; } &&
{ test -z "$chgrpcmd" || $doit $chgrpcmd "$dst"; } &&
{ test "$obsolete_mkdir_used$chowncmd$chgrpcmd" = false ||
test -z "$chmodcmd" || $doit $chmodcmd $mode "$dst"; } || exit 1
else
# Make a couple of temp file names in the proper directory.
dsttmp=$dstdir/_inst.$$_
rmtmp=$dstdir/_rm.$$_
# Trap to clean up those temp files at exit.
trap 'ret=$?; rm -f "$dsttmp" "$rmtmp" && exit $ret' 0
# Copy the file name to the temp name.
(umask $cp_umask && $doit_exec $cpprog "$src" "$dsttmp") &&
# and set any options; do chmod last to preserve setuid bits.
#
# If any of these fail, we abort the whole thing. If we want to
# ignore errors from any of these, just make sure not to ignore
# errors from the above "$doit $cpprog $src $dsttmp" command.
#
{ test -z "$chowncmd" || $doit $chowncmd "$dsttmp"; } &&
{ test -z "$chgrpcmd" || $doit $chgrpcmd "$dsttmp"; } &&
{ test -z "$stripcmd" || $doit $stripcmd "$dsttmp"; } &&
{ test -z "$chmodcmd" || $doit $chmodcmd $mode "$dsttmp"; } &&
# If -C, don't bother to copy if it wouldn't change the file.
if $copy_on_change &&
old=`LC_ALL=C ls -dlL "$dst" 2>/dev/null` &&
new=`LC_ALL=C ls -dlL "$dsttmp" 2>/dev/null` &&
eval "$initialize_posix_glob" &&
$posix_glob set -f &&
set X $old && old=:$2:$4:$5:$6 &&
set X $new && new=:$2:$4:$5:$6 &&
$posix_glob set +f &&
test "$old" = "$new" &&
$cmpprog "$dst" "$dsttmp" >/dev/null 2>&1
then
rm -f "$dsttmp"
else
# Rename the file to the real destination.
$doit $mvcmd -f "$dsttmp" "$dst" 2>/dev/null ||
# The rename failed, perhaps because mv can't rename something else
# to itself, or perhaps because mv is so ancient that it does not
# support -f.
{
# Now remove or move aside any old file at destination location.
# We try this two ways since rm can't unlink itself on some
# systems and the destination file might be busy for other
# reasons. In this case, the final cleanup might fail but the new
# file should still install successfully.
{
test ! -f "$dst" ||
$doit $rmcmd -f "$dst" 2>/dev/null ||
{ $doit $mvcmd -f "$dst" "$rmtmp" 2>/dev/null &&
{ $doit $rmcmd -f "$rmtmp" 2>/dev/null; :; }
} ||
{ echo "$0: cannot unlink or rename $dst" >&2
(exit 1); exit 1
}
} &&
# Now rename the file to the real destination.
$doit $mvcmd "$dsttmp" "$dst"
}
fi || exit 1
trap '' 0
fi
done
# Local variables:
# eval: (add-hook 'write-file-hooks 'time-stamp)
# time-stamp-start: "scriptversion="
# time-stamp-format: "%:y-%02m-%02d.%02H"
# time-stamp-time-zone: "UTC"
# time-stamp-end: "; # UTC"
# End:
-2
View File
@@ -1,2 +0,0 @@
libtool.m4
lt*.m4
-8
View File
@@ -1,8 +0,0 @@
dnl Shamelessly stolen from Heimdal
dnl
dnl Look for function in any of the specified libraries
dnl
dnl AC_FIND_FUNC_NO_LIBS(func, libraries, includes, arguments, extra libs, extra args)
AC_DEFUN([AC_FIND_FUNC_NO_LIBS], [
AC_FIND_FUNC_NO_LIBS2([$1], ["" $2], [$3], [$4], [$5], [$6])])
-62
View File
@@ -1,62 +0,0 @@
dnl Shamelessly stolen from Heimdal
dnl
dnl Look for function in any of the specified libraries
dnl
dnl AC_FIND_FUNC_NO_LIBS2(func, libraries, includes, arguments, extra libs, extra args)
AC_DEFUN([AC_FIND_FUNC_NO_LIBS2], [
AC_MSG_CHECKING([for $1])
AC_CACHE_VAL(ac_cv_funclib_$1,
[
if eval "test \"\$ac_cv_func_$1\" != yes" ; then
ac_save_LIBS="$LIBS"
for ac_lib in $2; do
case "$ac_lib" in
"") ;;
yes) ac_lib="" ;;
no) continue ;;
-l*) ;;
*) ac_lib="-l$ac_lib" ;;
esac
LIBS="$6 $ac_lib $5 $ac_save_LIBS"
AC_LINK_IFELSE([AC_LANG_PROGRAM([[$3]],[[$1($4)]])],[eval "if test -n \"$ac_lib\";then ac_cv_funclib_$1=$ac_lib; else ac_cv_funclib_$1=yes; fi";break])
done
eval "ac_cv_funclib_$1=\${ac_cv_funclib_$1-no}"
LIBS="$ac_save_LIBS"
fi
])
eval "ac_res=\$ac_cv_funclib_$1"
if false; then
AC_CHECK_FUNCS($1)
dnl AC_CHECK_LIBS($2, foo)
fi
# $1
eval "ac_tr_func=HAVE_[]upcase($1)"
eval "ac_tr_lib=HAVE_LIB[]upcase($ac_res | sed -e 's/-l//')"
eval "LIB_$1=$ac_res"
case "$ac_res" in
yes)
eval "ac_cv_func_$1=yes"
eval "LIB_$1="
AC_DEFINE_UNQUOTED($ac_tr_func)
AC_MSG_RESULT([yes])
;;
no)
eval "ac_cv_func_$1=no"
eval "LIB_$1="
AC_MSG_RESULT([no])
;;
*)
eval "ac_cv_func_$1=yes"
eval "ac_cv_lib_`echo "$ac_res" | sed 's/-l//'`=yes"
AC_DEFINE_UNQUOTED($ac_tr_func)
AC_DEFINE_UNQUOTED($ac_tr_lib)
AC_MSG_RESULT([yes, in $ac_res])
;;
esac
AC_SUBST(LIB_$1)
])
-9
View File
@@ -1,9 +0,0 @@
dnl Shamelessly stolen from Heimdal
dnl
dnl AC_FIND_FUNC(func, libraries, includes, arguments)
AC_DEFUN([AC_FIND_FUNC], [
AC_FIND_FUNC_NO_LIBS([$1], [$2], [$3], [$4])
if test -n "$LIB_$1"; then
LIBS="$LIB_$1 $LIBS"
fi
])
-3
View File
@@ -1,3 +0,0 @@
dnl Shamelessly stolen from Heimdal
AC_DEFUN([upcase],[`echo $1 | tr abcdefghijklmnopqrstuvwxyz ABCDEFGHIJKLMNOPQRSTUVWXYZ`])dnl
Executable
+331
View File
@@ -0,0 +1,331 @@
#! /bin/sh
# Common stub for a few missing GNU programs while installing.
scriptversion=2012-01-06.13; # UTC
# Copyright (C) 1996, 1997, 1999, 2000, 2002, 2003, 2004, 2005, 2006,
# 2008, 2009, 2010, 2011, 2012 Free Software Foundation, Inc.
# Originally by Fran,cois Pinard <pinard@iro.umontreal.ca>, 1996.
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2, or (at your option)
# any later version.
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
# As a special exception to the GNU General Public License, if you
# distribute this file as part of a program that contains a
# configuration script generated by Autoconf, you may include it under
# the same distribution terms that you use for the rest of that program.
if test $# -eq 0; then
echo 1>&2 "Try \`$0 --help' for more information"
exit 1
fi
run=:
sed_output='s/.* --output[ =]\([^ ]*\).*/\1/p'
sed_minuso='s/.* -o \([^ ]*\).*/\1/p'
# In the cases where this matters, `missing' is being run in the
# srcdir already.
if test -f configure.ac; then
configure_ac=configure.ac
else
configure_ac=configure.in
fi
msg="missing on your system"
case $1 in
--run)
# Try to run requested program, and just exit if it succeeds.
run=
shift
"$@" && exit 0
# Exit code 63 means version mismatch. This often happens
# when the user try to use an ancient version of a tool on
# a file that requires a minimum version. In this case we
# we should proceed has if the program had been absent, or
# if --run hadn't been passed.
if test $? = 63; then
run=:
msg="probably too old"
fi
;;
-h|--h|--he|--hel|--help)
echo "\
$0 [OPTION]... PROGRAM [ARGUMENT]...
Handle \`PROGRAM [ARGUMENT]...' for when PROGRAM is missing, or return an
error status if there is no known handling for PROGRAM.
Options:
-h, --help display this help and exit
-v, --version output version information and exit
--run try to run the given command, and emulate it if it fails
Supported PROGRAM values:
aclocal touch file \`aclocal.m4'
autoconf touch file \`configure'
autoheader touch file \`config.h.in'
autom4te touch the output file, or create a stub one
automake touch all \`Makefile.in' files
bison create \`y.tab.[ch]', if possible, from existing .[ch]
flex create \`lex.yy.c', if possible, from existing .c
help2man touch the output file
lex create \`lex.yy.c', if possible, from existing .c
makeinfo touch the output file
yacc create \`y.tab.[ch]', if possible, from existing .[ch]
Version suffixes to PROGRAM as well as the prefixes \`gnu-', \`gnu', and
\`g' are ignored when checking the name.
Send bug reports to <bug-automake@gnu.org>."
exit $?
;;
-v|--v|--ve|--ver|--vers|--versi|--versio|--version)
echo "missing $scriptversion (GNU Automake)"
exit $?
;;
-*)
echo 1>&2 "$0: Unknown \`$1' option"
echo 1>&2 "Try \`$0 --help' for more information"
exit 1
;;
esac
# normalize program name to check for.
program=`echo "$1" | sed '
s/^gnu-//; t
s/^gnu//; t
s/^g//; t'`
# Now exit if we have it, but it failed. Also exit now if we
# don't have it and --version was passed (most likely to detect
# the program). This is about non-GNU programs, so use $1 not
# $program.
case $1 in
lex*|yacc*)
# Not GNU programs, they don't have --version.
;;
*)
if test -z "$run" && ($1 --version) > /dev/null 2>&1; then
# We have it, but it failed.
exit 1
elif test "x$2" = "x--version" || test "x$2" = "x--help"; then
# Could not run --version or --help. This is probably someone
# running `$TOOL --version' or `$TOOL --help' to check whether
# $TOOL exists and not knowing $TOOL uses missing.
exit 1
fi
;;
esac
# If it does not exist, or fails to run (possibly an outdated version),
# try to emulate it.
case $program in
aclocal*)
echo 1>&2 "\
WARNING: \`$1' is $msg. You should only need it if
you modified \`acinclude.m4' or \`${configure_ac}'. You might want
to install the \`Automake' and \`Perl' packages. Grab them from
any GNU archive site."
touch aclocal.m4
;;
autoconf*)
echo 1>&2 "\
WARNING: \`$1' is $msg. You should only need it if
you modified \`${configure_ac}'. You might want to install the
\`Autoconf' and \`GNU m4' packages. Grab them from any GNU
archive site."
touch configure
;;
autoheader*)
echo 1>&2 "\
WARNING: \`$1' is $msg. You should only need it if
you modified \`acconfig.h' or \`${configure_ac}'. You might want
to install the \`Autoconf' and \`GNU m4' packages. Grab them
from any GNU archive site."
files=`sed -n 's/^[ ]*A[CM]_CONFIG_HEADER(\([^)]*\)).*/\1/p' ${configure_ac}`
test -z "$files" && files="config.h"
touch_files=
for f in $files; do
case $f in
*:*) touch_files="$touch_files "`echo "$f" |
sed -e 's/^[^:]*://' -e 's/:.*//'`;;
*) touch_files="$touch_files $f.in";;
esac
done
touch $touch_files
;;
automake*)
echo 1>&2 "\
WARNING: \`$1' is $msg. You should only need it if
you modified \`Makefile.am', \`acinclude.m4' or \`${configure_ac}'.
You might want to install the \`Automake' and \`Perl' packages.
Grab them from any GNU archive site."
find . -type f -name Makefile.am -print |
sed 's/\.am$/.in/' |
while read f; do touch "$f"; done
;;
autom4te*)
echo 1>&2 "\
WARNING: \`$1' is needed, but is $msg.
You might have modified some files without having the
proper tools for further handling them.
You can get \`$1' as part of \`Autoconf' from any GNU
archive site."
file=`echo "$*" | sed -n "$sed_output"`
test -z "$file" && file=`echo "$*" | sed -n "$sed_minuso"`
if test -f "$file"; then
touch $file
else
test -z "$file" || exec >$file
echo "#! /bin/sh"
echo "# Created by GNU Automake missing as a replacement of"
echo "# $ $@"
echo "exit 0"
chmod +x $file
exit 1
fi
;;
bison*|yacc*)
echo 1>&2 "\
WARNING: \`$1' $msg. You should only need it if
you modified a \`.y' file. You may need the \`Bison' package
in order for those modifications to take effect. You can get
\`Bison' from any GNU archive site."
rm -f y.tab.c y.tab.h
if test $# -ne 1; then
eval LASTARG=\${$#}
case $LASTARG in
*.y)
SRCFILE=`echo "$LASTARG" | sed 's/y$/c/'`
if test -f "$SRCFILE"; then
cp "$SRCFILE" y.tab.c
fi
SRCFILE=`echo "$LASTARG" | sed 's/y$/h/'`
if test -f "$SRCFILE"; then
cp "$SRCFILE" y.tab.h
fi
;;
esac
fi
if test ! -f y.tab.h; then
echo >y.tab.h
fi
if test ! -f y.tab.c; then
echo 'main() { return 0; }' >y.tab.c
fi
;;
lex*|flex*)
echo 1>&2 "\
WARNING: \`$1' is $msg. You should only need it if
you modified a \`.l' file. You may need the \`Flex' package
in order for those modifications to take effect. You can get
\`Flex' from any GNU archive site."
rm -f lex.yy.c
if test $# -ne 1; then
eval LASTARG=\${$#}
case $LASTARG in
*.l)
SRCFILE=`echo "$LASTARG" | sed 's/l$/c/'`
if test -f "$SRCFILE"; then
cp "$SRCFILE" lex.yy.c
fi
;;
esac
fi
if test ! -f lex.yy.c; then
echo 'main() { return 0; }' >lex.yy.c
fi
;;
help2man*)
echo 1>&2 "\
WARNING: \`$1' is $msg. You should only need it if
you modified a dependency of a manual page. You may need the
\`Help2man' package in order for those modifications to take
effect. You can get \`Help2man' from any GNU archive site."
file=`echo "$*" | sed -n "$sed_output"`
test -z "$file" && file=`echo "$*" | sed -n "$sed_minuso"`
if test -f "$file"; then
touch $file
else
test -z "$file" || exec >$file
echo ".ab help2man is required to generate this page"
exit $?
fi
;;
makeinfo*)
echo 1>&2 "\
WARNING: \`$1' is $msg. You should only need it if
you modified a \`.texi' or \`.texinfo' file, or any other file
indirectly affecting the aspect of the manual. The spurious
call might also be the consequence of using a buggy \`make' (AIX,
DU, IRIX). You might want to install the \`Texinfo' package or
the \`GNU make' package. Grab either from any GNU archive site."
# The file to touch is that specified with -o ...
file=`echo "$*" | sed -n "$sed_output"`
test -z "$file" && file=`echo "$*" | sed -n "$sed_minuso"`
if test -z "$file"; then
# ... or it is the one specified with @setfilename ...
infile=`echo "$*" | sed 's/.* \([^ ]*\) *$/\1/'`
file=`sed -n '
/^@setfilename/{
s/.* \([^ ]*\) *$/\1/
p
q
}' $infile`
# ... or it is derived from the source name (dir/f.texi becomes f.info)
test -z "$file" && file=`echo "$infile" | sed 's,.*/,,;s,.[^.]*$,,'`.info
fi
# If the file does not exist, the user really needs makeinfo;
# let's fail without touching anything.
test -f $file || exit 1
touch $file
;;
*)
echo 1>&2 "\
WARNING: \`$1' is needed, and is $msg.
You might have modified some files without having the
proper tools for further handling them. Check the \`README' file,
it often tells you about the needed prerequisites for installing
this package. You may also peek at any GNU archive site, in case
some other package would contain this missing \`$1' program."
exit 1
;;
esac
exit 0
# Local variables:
# eval: (add-hook 'write-file-hooks 'time-stamp)
# time-stamp-start: "scriptversion="
# time-stamp-format: "%:y-%02m-%02d.%02H"
# time-stamp-time-zone: "UTC"
# time-stamp-end: "; # UTC"
# End:
Executable
+226
View File
@@ -0,0 +1,226 @@
#! /bin/sh
# ylwrap - wrapper for lex/yacc invocations.
scriptversion=2011-08-25.18; # UTC
# Copyright (C) 1996, 1997, 1998, 1999, 2001, 2002, 2003, 2004, 2005,
# 2007, 2009, 2010, 2011 Free Software Foundation, Inc.
#
# Written by Tom Tromey <tromey@cygnus.com>.
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2, or (at your option)
# any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
# As a special exception to the GNU General Public License, if you
# distribute this file as part of a program that contains a
# configuration script generated by Autoconf, you may include it under
# the same distribution terms that you use for the rest of that program.
# This file is maintained in Automake, please report
# bugs to <bug-automake@gnu.org> or send patches to
# <automake-patches@gnu.org>.
case "$1" in
'')
echo "$0: No files given. Try \`$0 --help' for more information." 1>&2
exit 1
;;
--basedir)
basedir=$2
shift 2
;;
-h|--h*)
cat <<\EOF
Usage: ylwrap [--help|--version] INPUT [OUTPUT DESIRED]... -- PROGRAM [ARGS]...
Wrapper for lex/yacc invocations, renaming files as desired.
INPUT is the input file
OUTPUT is one file PROG generates
DESIRED is the file we actually want instead of OUTPUT
PROGRAM is program to run
ARGS are passed to PROG
Any number of OUTPUT,DESIRED pairs may be used.
Report bugs to <bug-automake@gnu.org>.
EOF
exit $?
;;
-v|--v*)
echo "ylwrap $scriptversion"
exit $?
;;
esac
# The input.
input="$1"
shift
case "$input" in
[\\/]* | ?:[\\/]*)
# Absolute path; do nothing.
;;
*)
# Relative path. Make it absolute.
input="`pwd`/$input"
;;
esac
pairlist=
while test "$#" -ne 0; do
if test "$1" = "--"; then
shift
break
fi
pairlist="$pairlist $1"
shift
done
# The program to run.
prog="$1"
shift
# Make any relative path in $prog absolute.
case "$prog" in
[\\/]* | ?:[\\/]*) ;;
*[\\/]*) prog="`pwd`/$prog" ;;
esac
# FIXME: add hostname here for parallel makes that run commands on
# other machines. But that might take us over the 14-char limit.
dirname=ylwrap$$
do_exit="cd '`pwd`' && rm -rf $dirname > /dev/null 2>&1;"' (exit $ret); exit $ret'
trap "ret=129; $do_exit" 1
trap "ret=130; $do_exit" 2
trap "ret=141; $do_exit" 13
trap "ret=143; $do_exit" 15
mkdir $dirname || exit 1
cd $dirname
case $# in
0) "$prog" "$input" ;;
*) "$prog" "$@" "$input" ;;
esac
ret=$?
if test $ret -eq 0; then
set X $pairlist
shift
first=yes
# Since DOS filename conventions don't allow two dots,
# the DOS version of Bison writes out y_tab.c instead of y.tab.c
# and y_tab.h instead of y.tab.h. Test to see if this is the case.
y_tab_nodot="no"
if test -f y_tab.c || test -f y_tab.h; then
y_tab_nodot="yes"
fi
# The directory holding the input.
input_dir=`echo "$input" | sed -e 's,\([\\/]\)[^\\/]*$,\1,'`
# Quote $INPUT_DIR so we can use it in a regexp.
# FIXME: really we should care about more than `.' and `\'.
input_rx=`echo "$input_dir" | sed 's,\\\\,\\\\\\\\,g;s,\\.,\\\\.,g'`
while test "$#" -ne 0; do
from="$1"
# Handle y_tab.c and y_tab.h output by DOS
if test $y_tab_nodot = "yes"; then
if test $from = "y.tab.c"; then
from="y_tab.c"
else
if test $from = "y.tab.h"; then
from="y_tab.h"
fi
fi
fi
if test -f "$from"; then
# If $2 is an absolute path name, then just use that,
# otherwise prepend `../'.
case "$2" in
[\\/]* | ?:[\\/]*) target="$2";;
*) target="../$2";;
esac
# We do not want to overwrite a header file if it hasn't
# changed. This avoid useless recompilations. However the
# parser itself (the first file) should always be updated,
# because it is the destination of the .y.c rule in the
# Makefile. Divert the output of all other files to a temporary
# file so we can compare them to existing versions.
if test $first = no; then
realtarget="$target"
target="tmp-`echo $target | sed s/.*[\\/]//g`"
fi
# Edit out `#line' or `#' directives.
#
# We don't want the resulting debug information to point at
# an absolute srcdir; it is better for it to just mention the
# .y file with no path.
#
# We want to use the real output file name, not yy.lex.c for
# instance.
#
# We want the include guards to be adjusted too.
FROM=`echo "$from" | sed \
-e 'y/abcdefghijklmnopqrstuvwxyz/ABCDEFGHIJKLMNOPQRSTUVWXYZ/'\
-e 's/[^ABCDEFGHIJKLMNOPQRSTUVWXYZ]/_/g'`
TARGET=`echo "$2" | sed \
-e 'y/abcdefghijklmnopqrstuvwxyz/ABCDEFGHIJKLMNOPQRSTUVWXYZ/'\
-e 's/[^ABCDEFGHIJKLMNOPQRSTUVWXYZ]/_/g'`
sed -e "/^#/!b" -e "s,$input_rx,," -e "s,$from,$2," \
-e "s,$FROM,$TARGET," "$from" >"$target" || ret=$?
# Check whether header files must be updated.
if test $first = no; then
if test -f "$realtarget" && cmp -s "$realtarget" "$target"; then
echo "$2" is unchanged
rm -f "$target"
else
echo updating "$2"
mv -f "$target" "$realtarget"
fi
fi
else
# A missing file is only an error for the first file. This
# is a blatant hack to let us support using "yacc -d". If -d
# is not specified, we don't want an error when the header
# file is "missing".
if test $first = yes; then
ret=1
fi
fi
shift
shift
first=no
done
else
ret=$?
fi
# Remove the directory.
cd ..
rm -rf $dirname
exit $ret
# Local Variables:
# mode: shell-script
# sh-indentation: 2
# eval: (add-hook 'write-file-hooks 'time-stamp)
# time-stamp-start: "scriptversion="
# time-stamp-format: "%:y-%02m-%02d.%02H"
# time-stamp-time-zone: "UTC"
# time-stamp-end: "; # UTC"
# End:
+12 -125
View File
@@ -1,37 +1,21 @@
m4_define([jq_version], m4_esyscmd_s([git describe --tags --dirty --match 'jq-*'|sed 's/^jq-//']))
AC_INIT([jq], [jq_version], [mu@netsoc.tcd.ie],
AC_INIT([jq], [1.3], [mu@netsoc.tcd.ie],
[jq], [http://stedolan.github.com/jq/])
dnl Created autoconf implementation thompson@dtosolutions, 26NOV12
AC_PREREQ([2.61])
AC_CONFIG_AUX_DIR([config])
AM_INIT_AUTOMAKE([parallel-tests foreign -Wall])
AM_INIT_AUTOMAKE([parallel-tests foreign])
AM_SILENT_RULES([yes])
AM_PROG_AR
AC_PROG_CC
AC_PROG_CC_STDC
AC_PROG_CPP_WERROR
AC_PROG_YACC
AC_OBJEXT
AC_EXEEXT
LT_INIT([shared static win32-dll])
AM_PROG_CC_C_O
dnl couldn't use AM_PROG_LEX as it doesn't support header files like the
dnl AC_PROG_YACC macros...
dnl check bison version
AC_MSG_CHECKING([bison version])
if test "$YACC" != "bison -y"; then
AC_MSG_RESULT([not bison])
elif $YACC --help | grep -- --warnings >/dev/null; then
AC_MSG_RESULT([ok])
else
AC_MSG_RESULT([no])
AC_MSG_ERROR([You need bison version 2.5 or more recent.])
fi
dnl
dnl these program checks should probably be deleted
dnl
@@ -42,63 +26,6 @@ if test "x$LEX" != xflex; then
fi
##########################################################################
# check for ONIGURUMA library
##########################################################################
AC_ARG_WITH([oniguruma],
[AS_HELP_STRING([--with-oniguruma=prefix],
[try this for a non-standard install prefix of the oniguruma library])],
[ONIGURUMAPATHSET=1],
[ONIGURUMAPATHSET=0])
if test $ONIGURUMAPATHSET == 1; then
CFLAGS="$CFLAGS -I${with_oniguruma}/include"
LDFLAGS="$LDFLAGS -L${with_oniguruma}/lib"
fi
# store current *FLAGS and merge with AM_*FLAGS for compilation and linker check
OLD_CFLAGS=$CFLAGS;
OLD_LDFLAGS=$LDFLAGS;
CFLAGS="$AM_CFLAGS $CFLAGS"
LDFLAGS="$AM_LDFLAGS $LDFLAGS"
# ensure the library to check for is covered by the LIBS variable
OLD_LIBS=$LIBS
LIBS="$LIBS -lonig"
# check for ONIGURUMA library headers
AC_MSG_CHECKING([for oniguruma.h])
# try to compile a file that includes a header of the library oniguruma
AC_COMPILE_IFELSE([AC_LANG_PROGRAM([ #include <oniguruma.h> ])],
[AC_MSG_RESULT([yes])
# try to link the function 'onig_free' out of library oniguruma
AC_MSG_CHECKING([for oniguruma usability])
AC_LINK_IFELSE(
[AC_LANG_PROGRAM([[#include <oniguruma.h>]],
[[onig_free(0);]])],
[AC_MSG_RESULT([yes])
FOUND_ONIGURUMA=1;],
[AC_MSG_RESULT([no])
LIBS=$OLD_LIBS; dnl reset to old value since oniguruma was not found
FOUND_ONIGURUMA=0;])],
[AC_MSG_RESULT([not found])
FOUND_ONIGURUMA=0;])
# reset original *FLAGS
CFLAGS=$OLD_CFLAGS
LDFLAGS=$OLD_LDFLAGS
# handle check results
if test $FOUND_ONIGURUMA != 1; then
AC_MSG_NOTICE([Oniguruma was not found.])
AC_MSG_NOTICE([ Try setting the location using '--with-oniguruma=PREFIX' ])
AC_MSG_ERROR([ oniguruma is required to build jq.])
fi
dnl Check for valgrind
AC_CHECK_PROGS(valgrind_cmd, valgrind)
if test "x$valgrind_cmd" = "x" ; then
@@ -112,13 +39,10 @@ AC_ARG_ENABLE([docs],
AS_IF([test "x$enable_docs" != "xno"],[
AC_CHECK_PROGS(bundle_cmd, bundle)
AC_CACHE_CHECK([for Ruby dependencies], [jq_cv_ruby_deps],
[jq_cv_ruby_deps=yes;
AS_IF([test "x$bundle_cmd" = "x" || \
! bmsg="`cd ${srcdir}/docs; "$bundle_cmd" check 2>/dev/null`"],[
AC_MSG_WARN([$bmsg])
cat <<EOF
AS_IF([test "x$bundle_cmd" = "x" || \
! ( cd ${srcdir}/docs; "$bundle_cmd" check 2>/dev/null )],[
AC_MSG_WARN([no bundler])
cat <<EOF
*****************************************************************
* Ruby dependencies for building jq documentation not found. *
* You can still build, install and hack on jq, but the manpage *
@@ -126,53 +50,16 @@ AS_IF([test "x$enable_docs" != "xno"],[
* See docs/README.md for how to install the docs dependencies. *
*****************************************************************
EOF
jq_cv_ruby_deps=no
])])
if test "x$jq_cv_ruby_deps" != "xyes"; then
enable_docs=no
fi
enable_docs=no
])
])
AM_CONDITIONAL([ENABLE_DOCS], [test "x$enable_docs" != xno])
AC_FIND_FUNC([isatty], [c], [#include <unistd.h>], [0])
AC_FIND_FUNC([_isatty], [c], [#include <io.h>], [0])
AC_ARG_ENABLE([pthread-tls],
[AC_HELP_STRING([--enable-pthread-tls],
[Enable use of pthread thread local storage])],
[],
[enable_pthread_tls=no])
if test $enable_pthread_tls = yes; then
AC_FIND_FUNC([pthread_key_create], [pthread], [#include <pthread.h>], [NULL, NULL])
AC_FIND_FUNC([pthread_once], [pthread], [#include <pthread.h>], [NULL, NULL])
AC_FIND_FUNC([atexit], [pthread], [#include <stdlib.h>], [NULL])
fi
dnl Thread local storage
have___thread=no
AC_MSG_CHECKING(for thread-local storage)
AC_LINK_IFELSE([AC_LANG_SOURCE([
static __thread int x ;
int main () { x = 123; return x; }
])], have___thread=yes)
if test $have___thread = yes; then
AC_DEFINE([HAVE___THREAD],1,[Define to 1 if the system supports __thread])
fi
AC_MSG_RESULT($have___thread)
AC_C_BIGENDIAN(
AC_DEFINE([IEEE_MC68k], 1, [machine is bigendian]),
AC_DEFINE([IEEE_8087], 1, [machine is littleendian]),
AC_MSG_ERROR(unknown endianess),
AC_MSG_ERROR(universial endianess not supported)
)
AC_SUBST([BUNDLER], ["$bundle_cmd"])
AC_CONFIG_MACRO_DIR([config/m4])
dnl AC_CONFIG_MACRO_DIR([m4])
AC_CONFIG_HEADERS(config.h)
AM_INIT_AUTOMAKE([-Wall])
AC_CONFIG_FILES([Makefile])
AC_OUTPUT
+12 -4
View File
@@ -75,7 +75,7 @@ $BINARIES = {
$BINARIES.each do |name, args|
file "../build/#{name}" do |t|
sh "../scripts/crosscompile -j4 #{name} #{args}"
sh "MAKEFLAGS=-j4 ../scripts/crosscompile #{name} #{args}"
end
task :binaries => ["../build/#{name}"]
end
@@ -91,6 +91,10 @@ def load_manual
YAML::load(File.open("content/3.manual/manual.yml"))
end
def jq_version
YAML::load(File.open("site.yml"))["jq_version"]
end
task :manpage do
Tempfile.open "manpage" do |f|
manual = load_manual
@@ -137,10 +141,14 @@ task :mantests do
end
end
$TARBALL = "../jq-#{jq_version}.tar.gz"
file $TARBALL do
sh "cd ..; ./configure && make dist && make distclean"
end
directory "output/download/source"
task :tarball => ["output/download/source"] do
sh "cd ..; ./configure && make dist && make distclean"
sh "cp ../jq-*.tar.gz output/download/source"
task :tarball => ["output/download/source", $TARBALL] do
sh "cp #{$TARBALL} output/download/source"
end
task :dist => [:build, :binaries, :tarball]
+160 -241
View File
@@ -2,205 +2,123 @@ headline: Tutorial
body:
- text: |
GitHub has a JSON API, so let's play with that. This URL gets
us the last 5 commits from the jq repo:
- command: "curl 'https://api.github.com/repos/stedolan/jq/commits?per_page=5'"
Twitter has a JSON API, so let's play with that. This URL gets
us the last 5 tweets about JSON:
- command: "curl 'http://search.twitter.com/search.json?q=json&rpp=5&include_entities=true'"
result: |
[
{
"sha": "d25341478381063d1c76e81b3a52e0592a7c997f",
"commit": {
"author": {
"name": "Stephen Dolan",
"email": "mu@netsoc.tcd.ie",
"date": "2013-06-22T16:30:59Z"
},
"committer": {
"name": "Stephen Dolan",
"email": "mu@netsoc.tcd.ie",
"date": "2013-06-22T16:30:59Z"
},
"message": "Merge pull request #162 from stedolan/utf8-fixes\n\nUtf8 fixes. Closes #161",
"tree": {
"sha": "6ab697a8dfb5a96e124666bf6d6213822599fb40",
"url": "https://api.github.com/repos/stedolan/jq/git/trees/6ab697a8dfb5a96e124666bf6d6213822599fb40"
},
"url": "https://api.github.com/repos/stedolan/jq/git/commits/d25341478381063d1c76e81b3a52e0592a7c997f",
"comment_count": 0
},
"url": "https://api.github.com/repos/stedolan/jq/commits/d25341478381063d1c76e81b3a52e0592a7c997f",
"html_url": "https://github.com/stedolan/jq/commit/d25341478381063d1c76e81b3a52e0592a7c997f",
"comments_url": "https://api.github.com/repos/stedolan/jq/commits/d25341478381063d1c76e81b3a52e0592a7c997f/comments",
"author": {
"login": "stedolan",
...
- text: |
Github returns a ton of info here, and it's relatively hard to
read as it is. To syntax highlight it and order the attributes we pipe
it through jq, telling jq to just spit the input back at us using
the expression `.`:
- command: "curl 'https://api.github.com/repos/stedolan/jq/commits?per_page=5' | jq '.'"
result: |
[
{
"parents": [
{
"html_url": "https://github.com/stedolan/jq/commit/54b9c9bdb225af5d886466d72f47eafc51acb4f7",
"url": "https://api.github.com/repos/stedolan/jq/commits/54b9c9bdb225af5d886466d72f47eafc51acb4f7",
"sha": "54b9c9bdb225af5d886466d72f47eafc51acb4f7"
},
{
"html_url": "https://github.com/stedolan/jq/commit/8b1b503609c161fea4b003a7179b3fbb2dd4345a",
"url": "https://api.github.com/repos/stedolan/jq/commits/8b1b503609c161fea4b003a7179b3fbb2dd4345a",
"sha": "8b1b503609c161fea4b003a7179b3fbb2dd4345a"
}
],
"committer": {
"type": "User",
"received_events_url": "https://api.github.com/users/stedolan/received_events",
"events_url": "https://api.github.com/users/stedolan/events{/privacy}",
"repos_url": "https://api.github.com/users/stedolan/repos",
"organizations_url": "https://api.github.com/users/stedolan/orgs",
...
{"completed_in":0.108,"max_id":247677287108067328,"max_id_str":"247677287108067328","next_page":"?page=2&max_id=247677287108067328&q=json&rpp=5&include_entities=1","page":1,"query":"json","refresh_url":"?since_id=247677287108067328&q=json&include_entities=1","results":[{"created_at":"Mon, 17 Sep 2012 12:44:01 +0000","entities":{"hashtags":[],"urls":[{"url":"http:\/\/t.co\/XRvh1ZVw","expanded_url":"http:\/\/jase.im\/Ri7I0M","display_url":"jase.im\/Ri7I0M","indices":[112,132]}],"user_mentions":[{"screen_name":"imagemechanics","name":"Jason Cotterell","id":57271393,"id_str":"57271393","indices":[3,18]}]},"from_user":"_AaronNg","from_user_id":79771704,"from_user_id_str":"79771704","from_user_name":"NgChenChong","geo":null,"id":247677287108067328,"id_str":"247677287108067328","iso_language_code":"en","metadata":{"result_type":"recent"},"profile_image_url":"http:\/\/a0.twimg.com\/profile_images\/2523558403\/ek8mo4j4beq84iw28gjl_normal.jpeg","profile_image_url_https":"https:\/\/si0.twimg.com\/profile_images\/2523558403\/ek8mo4j4beq84iw28gjl_normal.jpeg","source":"&lt;a href=&quot;http:\/\/twitter.com\/&quot;&gt;web&lt;\/a&gt;","text":"RT @imagemechanics: iPhone 5 website teardown: How Apple compresses video using JPEG, JSON, and &lt;canvas&gt;.\nhttp:\/\/t.co\/XRvh1ZVw","to_user":null,"to_user_id":0,"to_user_id_str":"0","to_user_name":null}, ...
- text: |
There's still far too much info for our purposes, so we can try
just grab the first commit:
There's lots of info and no whitespace, so to make it a bit more
legible we pipe it through jq, telling jq to just spit the input
back at us using the expression `.`:
- command: "curl 'https://api.github.com/repos/stedolan/jq/commits?per_page=5' | jq '.[0]'"
- command: "curl 'http://search.twitter.com/search.json?q=json&rpp=5&include_entities=true' | jq '.'"
result: |
{
"parents": [
"since_id_str": "0",
"since_id": 0,
"results_per_page": 5,
"completed_in": 0.108,
"max_id": 247677287108067330,
"max_id_str": "247677287108067328",
"next_page": "?page=2&max_id=247677287108067328&q=json&rpp=5&include_entities=1",
"page": 1,
"query": "json",
"refresh_url": "?since_id=247677287108067328&q=json&include_entities=1",
"results": [
{
"html_url": "https://github.com/stedolan/jq/commit/54b9c9bdb225af5d886466d72f47eafc51acb4f7",
"url": "https://api.github.com/repos/stedolan/jq/commits/54b9c9bdb225af5d886466d72f47eafc51acb4f7",
"sha": "54b9c9bdb225af5d886466d72f47eafc51acb4f7"
"from_user_name": "NgChenChong",
"from_user_id_str": "79771704",
"from_user_id": 79771704,
"from_user": "_AaronNg",
"iso_language_code": "en",
"text": "RT @imagemechanics: iPhone 5 website teardown: How Apple compresses video using JPEG, JSON, and &lt;canvas&gt;.\nhttp://t.co/XRvh1ZVw",
"to_user": null
/* lots more fields... */
},
{
"html_url": "https://github.com/stedolan/jq/commit/8b1b503609c161fea4b003a7179b3fbb2dd4345a",
"url": "https://api.github.com/repos/stedolan/jq/commits/8b1b503609c161fea4b003a7179b3fbb2dd4345a",
"sha": "8b1b503609c161fea4b003a7179b3fbb2dd4345a"
}
],
"committer": {
"type": "User",
"received_events_url": "https://api.github.com/users/stedolan/received_events",
"events_url": "https://api.github.com/users/stedolan/events{/privacy}",
"repos_url": "https://api.github.com/users/stedolan/repos",
"organizations_url": "https://api.github.com/users/stedolan/orgs",
"subscriptions_url": "https://api.github.com/users/stedolan/subscriptions",
"starred_url": "https://api.github.com/users/stedolan/starred{/owner}{/repo}",
"gists_url": "https://api.github.com/users/stedolan/gists{/gist_id}",
"login": "stedolan",
"id": 79765,
"avatar_url": "https://1.gravatar.com/avatar/31de909d8e55dd07ed782d92ece59842?d=https%3A%2F%2Fidenticons.github.com%2Ffc5b6765b1c9cfaecea48ae71df4d279.png",
"gravatar_id": "31de909d8e55dd07ed782d92ece59842",
"url": "https://api.github.com/users/stedolan",
"html_url": "https://github.com/stedolan",
"followers_url": "https://api.github.com/users/stedolan/followers",
"following_url": "https://api.github.com/users/stedolan/following{/other_user}"
},
"author": {
"type": "User",
"received_events_url": "https://api.github.com/users/stedolan/received_events",
"events_url": "https://api.github.com/users/stedolan/events{/privacy}",
"repos_url": "https://api.github.com/users/stedolan/repos",
"organizations_url": "https://api.github.com/users/stedolan/orgs",
"subscriptions_url": "https://api.github.com/users/stedolan/subscriptions",
"starred_url": "https://api.github.com/users/stedolan/starred{/owner}{/repo}",
"gists_url": "https://api.github.com/users/stedolan/gists{/gist_id}",
"login": "stedolan",
"id": 79765,
"avatar_url": "https://1.gravatar.com/avatar/31de909d8e55dd07ed782d92ece59842?d=https%3A%2F%2Fidenticons.github.com%2Ffc5b6765b1c9cfaecea48ae71df4d279.png",
"gravatar_id": "31de909d8e55dd07ed782d92ece59842",
"url": "https://api.github.com/users/stedolan",
"html_url": "https://github.com/stedolan",
"followers_url": "https://api.github.com/users/stedolan/followers",
"following_url": "https://api.github.com/users/stedolan/following{/other_user}"
},
"comments_url": "https://api.github.com/repos/stedolan/jq/commits/d25341478381063d1c76e81b3a52e0592a7c997f/comments",
"html_url": "https://github.com/stedolan/jq/commit/d25341478381063d1c76e81b3a52e0592a7c997f",
"url": "https://api.github.com/repos/stedolan/jq/commits/d25341478381063d1c76e81b3a52e0592a7c997f",
"commit": {
"comment_count": 0,
"url": "https://api.github.com/repos/stedolan/jq/git/commits/d25341478381063d1c76e81b3a52e0592a7c997f",
"tree": {
"url": "https://api.github.com/repos/stedolan/jq/git/trees/6ab697a8dfb5a96e124666bf6d6213822599fb40",
"sha": "6ab697a8dfb5a96e124666bf6d6213822599fb40"
},
"message": "Merge pull request #162 from stedolan/utf8-fixes\n\nUtf8 fixes. Closes #161",
"committer": {
"date": "2013-06-22T16:30:59Z",
"email": "mu@netsoc.tcd.ie",
"name": "Stephen Dolan"
},
"author": {
"date": "2013-06-22T16:30:59Z",
"email": "mu@netsoc.tcd.ie",
"name": "Stephen Dolan"
}
},
"sha": "d25341478381063d1c76e81b3a52e0592a7c997f"
/* lots more results... */
]
}
- text: |
Let's pull out the first tweet:
- command: "curl 'http://search.twitter.com/search.json?q=json&rpp=5&include_entities=true' | jq '.results[0]'"
result: |
{
"from_user_name": "NgChenChong",
"from_user_id_str": "79771704",
"from_user_id": 79771704,
"from_user": "_AaronNg",
"iso_language_code": "en",
"text": "RT @imagemechanics: iPhone 5 website teardown: How Apple compresses video using JPEG, JSON, and &lt;canvas&gt;.\nhttp://t.co/XRvh1ZVw",
"to_user": null
/* lots more fields... */
},
- text: |
For the rest of the examples, I'll leave out the `curl` command - it's not going to change.
There's still a lot of info we don't care about there, so we'll
restrict it down to the most interesting fields.
- command: "jq '.[0] | {message: .commit.message, name: .commit.committer.name}'"
- command: "jq '.results[0] | {from_user, text}'"
result: |
{
"name": "Stephen Dolan",
"message": "Merge pull request #162 from stedolan/utf8-fixes\n\nUtf8 fixes. Closes #161"
"text": "RT @imagemechanics: iPhone 5 website teardown: How Apple compresses video using JPEG, JSON, and &lt;canvas&gt;.\nhttp://t.co/XRvh1ZVw",
"from_user": "_AaronNg"
}
- text: |
The `|` operator in jq feeds the output of one filter
(`.[0]` which gets the first element of the array in the response)
into the input of another (`{...}` which
builds an object out of those fields). You can access nested attributes,
such as `.commit.message`:
(`.results[0]` which gets the first element of the results
array) into the input of another (`{from_user, text}` which
builds an object of those two fields).
Now let's get the rest of the tweets:
Now let's get the rest of the commits:
- command: "jq '.[] | {message: .commit.message, name: .commit.committer.name}'"
- command: "jq '.results[] | {from_user, text}'"
result: |
{
"name": "Stephen Dolan",
"message": "Merge pull request #162 from stedolan/utf8-fixes\n\nUtf8 fixes. Closes #161"
"text": "RT @imagemechanics: iPhone 5 website teardown: How Apple compresses video using JPEG, JSON, and &lt;canvas&gt;.\nhttp://t.co/XRvh1ZVw",
"from_user": "_AaronNg"
}
{
"name": "Stephen Dolan",
"message": "Reject all overlong UTF8 sequences."
"text": "RT @_kud: iPhone 5 website teardown: How Apple compresses video using JPEG, JSON, and &lt;canvas&gt; -- http://t.co/Lhp92IqD",
"from_user": "blouerat"
}
{
"name": "Stephen Dolan",
"message": "Fix various UTF8 parsing bugs.\n\nIn particular, parse bad UTF8 by replacing the broken bits with U+FFFD\nand resychronise correctly after broken sequences."
"text": "Dynamic Forms Mobile App by pmadiset: Few Forms details are hosted on our server in the form of JSON. This JSON ... http://t.co/7KALdWaX",
"from_user": "cebu_iphone"
}
{
"name": "Stephen Dolan",
"message": "Fix example in manual for `floor`. See #155."
"text": "iPhone 5 website insanity - Video compressing using JPEG, JSON, and &lt;canvas&gt; http://t.co/28Jesbio (Oh #Apple, U So #Awesome...)",
"from_user": "dieswaytoofast"
}
{
"name": "Nicolas Williams",
"message": "Document floor"
"text": "RT @umutm: A very nice web-based JSON editor - http://t.co/M70snaIf",
"from_user": "Leolik"
}
- text: |
`.[]` returns each element of the array returned in the response,
one at a time, which are all fed into `{message: .commit.message, name: .commit.committer.name}`.
`.results[]` returns each element of the results array, one at a
time, which are all fed into `{from_user, text}`.
Data in jq is represented as streams of JSON values - every jq
@@ -210,108 +128,109 @@ body:
Streams are serialised by just separating JSON values with
whitespace. This is a `cat`-friendly format - you can just join
two JSON streams together and get a valid JSON stream.
If you want to get the output as a single array, you can tell jq to
"collect" all of the answers by wrapping the filter in square
brackets:
- command: "jq '[.[] | {message: .commit.message, name: .commit.committer.name}]'"
- command: "jq '[.results[] | {from_user, text}]'"
result: |
[
{
"name": "Stephen Dolan",
"message": "Merge pull request #162 from stedolan/utf8-fixes\n\nUtf8 fixes. Closes #161"
"text": "RT @imagemechanics: iPhone 5 website teardown: How Apple compresses video using JPEG, JSON, and &lt;canvas&gt;.\nhttp://t.co/XRvh1ZVw",
"from_user": "_AaronNg"
},
{
"name": "Stephen Dolan",
"message": "Reject all overlong UTF8 sequences."
"text": "RT @_kud: iPhone 5 website teardown: How Apple compresses video using JPEG, JSON, and &lt;canvas&gt; -- http://t.co/Lhp92IqD",
"from_user": "blouerat"
},
{
"name": "Stephen Dolan",
"message": "Fix various UTF8 parsing bugs.\n\nIn particular, parse bad UTF8 by replacing the broken bits with U+FFFD\nand resychronise correctly after broken sequences."
"text": "Dynamic Forms Mobile App by pmadiset: Few Forms details are hosted on our server in the form of JSON. This JSON ... http://t.co/7KALdWaX",
"from_user": "cebu_iphone"
},
{
"name": "Stephen Dolan",
"message": "Fix example in manual for `floor`. See #155."
"text": "iPhone 5 website insanity - Video compressing using JPEG, JSON, and &lt;canvas&gt; http://t.co/28Jesbio (Oh #Apple, U So #Awesome...)",
"from_user": "dieswaytoofast"
},
{
"name": "Nicolas Williams",
"message": "Document floor"
"text": "RT @umutm: A very nice web-based JSON editor - http://t.co/M70snaIf",
"from_user": "Leolik"
}
]
- text: |
- - -
Next, let's try getting the URLs out of those API results as
well. In each tweet, the Twitter API includes a field called
"entities" which looks like this:
Next, let's try getting the URLs of the parrent commits out of the
API results as well. In each commit, the GitHub API includes information
about "parent" commits. There can be one or many.
{
"user_mentions": [],
"urls": [{
"indices": [83, 103],
"display_url": "bit.ly/StniqT",
"expanded_url": "http://bit.ly/StniqT",
"url": "http://t.co/28Jesbio"
}],
"hashtags": [
{"indices": [108, 114], "text": "Apple" },
{"indices": [121, 129], "text": "Awesome"}
]
}
"parents": [
{
"html_url": "https://github.com/stedolan/jq/commit/54b9c9bdb225af5d886466d72f47eafc51acb4f7",
"url": "https://api.github.com/repos/stedolan/jq/commits/54b9c9bdb225af5d886466d72f47eafc51acb4f7",
"sha": "54b9c9bdb225af5d886466d72f47eafc51acb4f7"
},
{
"html_url": "https://github.com/stedolan/jq/commit/8b1b503609c161fea4b003a7179b3fbb2dd4345a",
"url": "https://api.github.com/repos/stedolan/jq/commits/8b1b503609c161fea4b003a7179b3fbb2dd4345a",
"sha": "8b1b503609c161fea4b003a7179b3fbb2dd4345a"
}
]
We want to pull out all of the "url" fields inside that array of url
objects, and make a simple list of strings to go along with the
"from_user" and "text" fields we already have.
We want to pull out all of the "html_url" fields inside that array of parent
commits and make a simple list of strings to go along with the
"message" and "author" fields we already have.
- command: "jq '[.[] | {message: .commit.message, name: .commit.committer.name, parents: [.parents[].html_url]}]'"
- command: "jq '.results[] | {from_user, text, urls: [.entities.urls[].url]}'"
result: |
[
{
"parents": [
"https://github.com/stedolan/jq/commit/54b9c9bdb225af5d886466d72f47eafc51acb4f7",
"https://github.com/stedolan/jq/commit/8b1b503609c161fea4b003a7179b3fbb2dd4345a"
],
"name": "Stephen Dolan",
"message": "Merge pull request #162 from stedolan/utf8-fixes\n\nUtf8 fixes. Closes #161"
},
{
"parents": [
"https://github.com/stedolan/jq/commit/ff48bd6ec538b01d1057be8e93b94eef6914e9ef"
],
"name": "Stephen Dolan",
"message": "Reject all overlong UTF8 sequences."
},
{
"parents": [
"https://github.com/stedolan/jq/commit/54b9c9bdb225af5d886466d72f47eafc51acb4f7"
],
"name": "Stephen Dolan",
"message": "Fix various UTF8 parsing bugs.\n\nIn particular, parse bad UTF8 by replacing the broken bits with U+FFFD\nand resychronise correctly after broken sequences."
},
{
"parents": [
"https://github.com/stedolan/jq/commit/3dcdc582ea993afea3f5503a78a77675967ecdfa"
],
"name": "Stephen Dolan",
"message": "Fix example in manual for `floor`. See #155."
},
{
"parents": [
"https://github.com/stedolan/jq/commit/7c4171d414f647ab08bcd20c76a4d8ed68d9c602"
],
"name": "Nicolas Williams",
"message": "Document floor"
}
]
{
"urls": [
"http://t.co/XRvh1ZVw"
],
"text": "RT @imagemechanics: iPhone 5 website teardown: How Apple compresses video using JPEG, JSON, and &lt;canvas&gt;.\nhttp://t.co/XRvh1ZVw",
"from_user": "_AaronNg"
}
{
"urls": [
"http://t.co/Lhp92IqD"
],
"text": "RT @_kud: iPhone 5 website teardown: How Apple compresses video using JPEG, JSON, and &lt;canvas&gt; -- http://t.co/Lhp92IqD",
"from_user": "blouerat"
}
{
"urls": [
"http://t.co/7KALdWaX"
],
"text": "Dynamic Forms Mobile App by pmadiset: Few Forms details are hosted on our server in the form of JSON. This JSON ... http://t.co/7KALdWaX",
"from_user": "cebu_iphone"
}
{
"urls": [
"http://t.co/28Jesbio"
],
"text": "iPhone 5 website insanity - Video compressing using JPEG, JSON, and &lt;canvas&gt; http://t.co/28Jesbio (Oh #Apple, U So #Awesome...)",
"from_user": "dieswaytoofast"
}
{
"urls": [
"http://t.co/M70snaIf"
],
"text": "RT @umutm: A very nice web-based JSON editor - http://t.co/M70snaIf",
"from_user": "Leolik"
}
- text: |
Here we're making an object as before, but this time the `parents`
field is being set to `[.parents[].html_url]}]`, which collects
all of the parent commit urls defined in the parents object.
Here we're making an object as before, but this time the urls
field is being set to `[.entities.urls[].url]`, which collects
all of the URLs defined in the entities object.
- text: |
@@ -319,4 +238,4 @@ body:
Here endeth the tutorial! There's lots more to play with, go
read [the manual](../manual/) if you're interested, and [download
jq](../download/) if you haven't already.
jq](../download/) if you haven't already.
+13 -27
View File
@@ -16,8 +16,7 @@ body:
### Linux
* jq 1.4 binaries for [64-bit](linux64/jq) or [32-bit](linux32/jq) systems.
* jq 1.3 binaries for [64-bit](linux64/jq-1.3/jq) or [32-bit](linux32/jq-1.3/jq) systems.
* Binaries for [64-bit](linux64/jq) or [32-bit](linux32/jq) systems.
* For Arch users, a PKGBUILD for jq-1.1 is in the
[AUR](https://aur.archlinux.org/packages.php?ID=63849), as
@@ -28,39 +27,31 @@ body:
manually by following instructions on [Arch Linux's
Wiki](https://wiki.archlinux.org/index.php/Arch_UseRepository).
* jq 1.3 is [in Debian](http://packages.debian.org/jq) (a request to update to 1.4 has been filed)
* jq 1.2 is [in Debian](http://packages.debian.org/jq)
### OS X
* `brew install jq` using [homebrew](http://mxcl.github.com/homebrew/)
* `brew install jq` using [homebrew](http://mxcl.github.io/homebrew/)
* Or, grab prebuilt jq 1.4 [64-bit binaries](osx64/jq) or [32-bit
* Or, grab prebuilt [64-bit binaries](osx64/jq) or [32-bit
binaries](osx32/jq)
* Or, grab prebuilt jq 1.3 [64-bit binaries](osx64/jq-1.3/jq) or [32-bit
binaries](osx32/jq-1.3/jq)
### Solaris 11
* jq 1.4 executables for [64-bit](solaris11-64/jq.exe) or [32-bit](solaris11-32/jq.exe)
### Windows
* jq 1.4 executables for [64-bit](win64/jq.exe) or [32-bit](win32/jq.exe)
* jq 1.3 executables for [64-bit](win64/jq-1.3/jq.exe) or [32-bit](win32/jq-1.3/jq.exe)
* Executables for [64-bit](win64/jq.exe) or [32-bit](win32/jq.exe)
### From source on Linux, OS X, Cygwin, and other POSIX-like operating systems
### From source on Linux or OS X
* [Source tarball for jq $JQ_VERSION](source/jq-$JQ_VERSION.tar.gz)
You can build it using the usual `./configure && make && sudo
make install` rigmarole.
If you're interested in using the lastest development version, try:
If you're interested in using the latest development version, try:
git clone https://github.com/stedolan/jq.git
cd jq
autoreconf -i
autoreconf
./configure
make
sudo make install
@@ -81,7 +72,7 @@ body:
On OS X, these are all included in Apple's command line tools, which
can be installed from [Xcode](http://developer.apple.com/technologies/tools/).
However, you may find that you need a newer version of Bison than the one provided
by Apple. This can be found in [Homebrew](http://mxcl.github.com/homebrew/)
by Apple. This can be found in [Homebrew](http://mxcl.github.io/homebrew/)
or [MacPorts](http://macports.org/).
`flex` and `bison` are used to generate the lexer and parser for
@@ -91,14 +82,9 @@ body:
#### Building the documentation
jq's documentation is compiled into static HTML using
[Bonsai](http://www.tinytree.info). To view the documentation
locally, run `rake serve` (or `bundle exec rake serve`) from the
docs/ subdirectory. To build the docs just `rake build` from the
docs subdirectory. You'll need a few Ruby dependencies, which can
be installed by following the instructions in `docs/README.md`.
The man page is built by `make jq.1`, or just `make`, also from
the YAML docs, and you'll still need the Ruby dependencies to
build the manpage.
[Bonsai](http://www.tinytree.info). To view the documentation
locally, run `rake serve` from the docs/ subdirectory. You'll
need a few Ruby dependencies, which can be installed by
following the instructions in `docs/README.md`.
File diff suppressed because it is too large. Load diff
+1 -6
View File
@@ -27,13 +27,8 @@ tail: |
for *way* more.
news:
- date: 2014-06-08
body: |
jq 1.4 (finally) released! Get it on the [download](download/) page.
- date: 2013-05-19
body: |
jq 1.3 released.
jq 1.3 (finally) released! Get it on the [download](download/) page.
+1 -1
View File
@@ -4,7 +4,7 @@
# This line is modified by the Makefile. To change the version number,
# edit the Autoconf version number at the top of configure.ac
jq_version: "1.4-2-g15c4a7f-dirty"
jq_version: "1.3"
root: '/jq'
footer: |
+1 -10
View File
@@ -10,7 +10,6 @@
<img src="{{root}}/jq.png" style="width: 400px; height: 220px; float: left; margin-right: 60px">
<div id="blurb">
{{blurb | markdownify}}
<div class="btn-group" style="float:right">
<a class="btn btn-primary dropdown-toggle" data-toggle="dropdown" href="#">
Download jq-{{jq_version}}
@@ -19,18 +18,10 @@
<ul class="dropdown-menu">
<li><a href="{{root}}/download/linux64/jq">Linux (64-bit)</a></li>
<li><a href="{{root}}/download/osx64/jq">OS X (64-bit)</a></li>
<li><a href="{{root}}/download/solaris11-64/jq">Solaris (64-bit)</a></li>
<li><a href="{{root}}/download/win64/jq.exe">Windows (64-bit)</a></li>
<li><a href="{{root}}/download/">Other platforms, older versions, and source</a></li>
<li><a href="{{root}}/download/">Other platforms and source</a></li>
</ul>
</div>
<div class="btn-group" style="float:right">
<a class="btn btn-primary" href="http://jqplay.org">
Try online!
</a>
</div>
</div>
<div style="clear:both;"></div>
</div>
-2
View File
@@ -17,8 +17,6 @@
{% endfor %}
<li><a href="https://github.com/stedolan/jq/issues">Issues</a></li>
<li><a href="https://github.com/stedolan/jq">Source</a></li>
<li><a href="http://jqplay.org">Try online!</a></li>
<li><a href="https://raw.githubusercontent.com/stedolan/jq/master/NEWS">NEWS</a></li>
</ul>
</div>
</div>
-82
View File
@@ -1,82 +0,0 @@
#ifndef EXEC_STACK_H
#define EXEC_STACK_H
#include <stddef.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
struct determine_alignment {
char x;
union { int i; double d; uint64_t u64; size_t sz; void* ptr; } u;
};
enum {ALIGNMENT = offsetof(struct determine_alignment, u)};
static size_t align_round_up(size_t sz) {
return ((sz + (ALIGNMENT - 1)) / ALIGNMENT) * ALIGNMENT;
}
typedef int stack_ptr;
struct stack {
char* mem_end; // one-past-the-end of allocated region
stack_ptr bound;
stack_ptr limit; // 0 - stack is empty
};
static void stack_init(struct stack* s) {
s->mem_end = 0;
s->bound = ALIGNMENT;
s->limit = 0;
}
static void stack_reset(struct stack* s) {
assert(s->limit == 0 && "stack freed while not empty");
char* mem_start = s->mem_end - ( -s->bound + ALIGNMENT);
free(mem_start);
stack_init(s);
}
static int stack_pop_will_free(struct stack* s, stack_ptr p) {
return p == s->limit;
}
static void* stack_block(struct stack* s, stack_ptr p) {
return (void*)(s->mem_end + p);
}
static stack_ptr* stack_block_next(struct stack* s, stack_ptr p) {
return &((stack_ptr*)stack_block(s, p))[-1];
}
static void stack_reallocate(struct stack* s, size_t sz) {
int old_mem_length = -(s->bound) + ALIGNMENT;
char* old_mem_start = s->mem_end - old_mem_length;
int new_mem_length = align_round_up((old_mem_length + sz + 256) * 2);
char* new_mem_start = realloc(old_mem_start, new_mem_length);
memmove(new_mem_start + (new_mem_length - old_mem_length),
new_mem_start, old_mem_length);
s->mem_end = new_mem_start + new_mem_length;
s->bound = -(new_mem_length - ALIGNMENT);
}
static stack_ptr stack_push_block(struct stack* s, stack_ptr p, size_t sz) {
int alloc_sz = align_round_up(sz) + ALIGNMENT;
stack_ptr r = s->limit - alloc_sz;
if (r < s->bound) {
stack_reallocate(s, alloc_sz);
}
s->limit = r;
*stack_block_next(s, r) = p;
return r;
}
static stack_ptr stack_pop_block(struct stack* s, stack_ptr p, size_t sz) {
stack_ptr r = *stack_block_next(s, p);
if (p == s->limit) {
int alloc_sz = align_round_up(sz) + ALIGNMENT;
s->limit += alloc_sz;
}
return r;
}
#endif
+168 -388
View File
@@ -1,195 +1,80 @@
#include <assert.h>
#include <errno.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include "exec_stack.h"
#include "execute.h"
#include "opcode.h"
#include "bytecode.h"
#include "forkable_stack.h"
#include "frame_layout.h"
#include "jv_alloc.h"
#include "jq_parser.h"
#include "locfile.h"
#include "jv.h"
#include "jq.h"
#include "jv_aux.h"
#include "parser.h"
#include "builtin.h"
struct jq_state {
void (*nomem_handler)(void *);
void *nomem_handler_data;
struct bytecode* bc;
jq_err_cb err_cb;
void *err_cb_data;
struct stack stk;
stack_ptr curr_frame;
stack_ptr stk_top;
stack_ptr fork_top;
struct forkable_stack data_stk;
struct forkable_stack frame_stk;
struct forkable_stack fork_stk;
jv path;
int subexp_nest;
int debug_trace_enabled;
int initial_execution;
};
struct closure {
struct bytecode* bc; // jq bytecode
stack_ptr env; // jq stack address of closed frame
};
// locals for any function called: either a closure or a local variable
union frame_entry {
struct closure closure;
jv localvar;
};
// jq function call frame
struct frame {
struct bytecode* bc; // jq bytecode for callee
stack_ptr env; // jq stack address of frame to return to
stack_ptr retdata; // jq stack address to unwind to on RET
uint16_t* retaddr; // jq bytecode return address
union frame_entry entries[0]; // nclosures + nlocals
};
static int frame_size(struct bytecode* bc) {
return sizeof(struct frame) + sizeof(union frame_entry) * (bc->nclosures + bc->nlocals);
}
static struct frame* frame_current(struct jq_state* jq) {
struct frame* fp = stack_block(&jq->stk, jq->curr_frame);
stack_ptr next = *stack_block_next(&jq->stk, jq->curr_frame);
if (next) {
struct frame* fpnext = stack_block(&jq->stk, next);
struct bytecode* bc = fpnext->bc;
assert(fp->retaddr >= bc->code && fp->retaddr < bc->code + bc->codelen);
} else {
assert(fp->retaddr == 0);
}
return fp;
}
static stack_ptr frame_get_level(struct jq_state* jq, int level) {
stack_ptr fr = jq->curr_frame;
for (int i=0; i<level; i++) {
struct frame* fp = stack_block(&jq->stk, fr);
fr = fp->env;
}
return fr;
}
static jv* frame_local_var(struct jq_state* jq, int var, int level) {
struct frame* fr = stack_block(&jq->stk, frame_get_level(jq, level));
assert(var >= 0);
assert(var < fr->bc->nlocals);
return &fr->entries[fr->bc->nclosures + var].localvar;
}
static struct closure make_closure(struct jq_state* jq, uint16_t* pc) {
uint16_t level = *pc++;
uint16_t idx = *pc++;
stack_ptr fridx = frame_get_level(jq, level);
struct frame* fr = stack_block(&jq->stk, fridx);
if (idx & ARG_NEWCLOSURE) {
// A new closure closing the frame identified by level, and with
// the bytecode body of the idx'th subfunction of that frame
int subfn_idx = idx & ~ARG_NEWCLOSURE;
assert(subfn_idx < fr->bc->nsubfunctions);
struct closure cl = {fr->bc->subfunctions[subfn_idx],
fridx};
return cl;
} else {
// A reference to a closure from the frame identified by level; copy
// it as-is
int closure = idx;
assert(closure >= 0);
assert(closure < fr->bc->nclosures);
return fr->entries[closure].closure;
}
}
static struct frame* frame_push(struct jq_state* jq, struct closure callee,
uint16_t* argdef, int nargs) {
stack_ptr new_frame_idx = stack_push_block(&jq->stk, jq->curr_frame, frame_size(callee.bc));
struct frame* new_frame = stack_block(&jq->stk, new_frame_idx);
new_frame->bc = callee.bc;
new_frame->env = callee.env;
assert(nargs == new_frame->bc->nclosures);
union frame_entry* entries = new_frame->entries;
for (int i=0; i<nargs; i++) {
entries->closure = make_closure(jq, argdef + i * 2);
entries++;
}
for (int i=0; i<callee.bc->nlocals; i++) {
entries->localvar = jv_invalid();
entries++;
}
jq->curr_frame = new_frame_idx;
return new_frame;
}
static void frame_pop(struct jq_state* jq) {
assert(jq->curr_frame);
struct frame* fp = frame_current(jq);
if (stack_pop_will_free(&jq->stk, jq->curr_frame)) {
int nlocals = fp->bc->nlocals;
for (int i=0; i<nlocals; i++) {
jv_free(*frame_local_var(jq, i, 0));
}
}
jq->curr_frame = stack_pop_block(&jq->stk, jq->curr_frame, frame_size(fp->bc));
}
typedef struct {
FORKABLE_STACK_HEADER;
jv val;
} data_stk_elem;
void stack_push(jq_state *jq, jv val) {
assert(jv_is_valid(val));
jq->stk_top = stack_push_block(&jq->stk, jq->stk_top, sizeof(jv));
jv* sval = stack_block(&jq->stk, jq->stk_top);
*sval = val;
data_stk_elem* s = forkable_stack_push(&jq->data_stk, sizeof(data_stk_elem));
s->val = val;
}
jv stack_pop(jq_state *jq) {
jv* sval = stack_block(&jq->stk, jq->stk_top);
jv val = *sval;
if (!stack_pop_will_free(&jq->stk, jq->stk_top)) {
data_stk_elem* s = forkable_stack_peek(&jq->data_stk);
jv val = s->val;
if (!forkable_stack_pop_will_free(&jq->data_stk)) {
val = jv_copy(val);
}
jq->stk_top = stack_pop_block(&jq->stk, jq->stk_top, sizeof(jv));
forkable_stack_pop(&jq->data_stk);
assert(jv_is_valid(val));
return val;
}
struct forkpoint {
stack_ptr saved_data_stack;
stack_ptr saved_curr_frame;
FORKABLE_STACK_HEADER;
struct forkable_stack_state saved_data_stack;
struct forkable_stack_state saved_call_stack;
int path_len, subexp_nest;
uint16_t* return_address;
};
struct stack_pos {
stack_ptr saved_data_stack, saved_curr_frame;
};
struct stack_pos stack_get_pos(jq_state* jq) {
struct stack_pos sp = {jq->stk_top, jq->curr_frame};
return sp;
}
void stack_save(jq_state *jq, uint16_t* retaddr, struct stack_pos sp){
jq->fork_top = stack_push_block(&jq->stk, jq->fork_top, sizeof(struct forkpoint));
struct forkpoint* fork = stack_block(&jq->stk, jq->fork_top);
fork->saved_data_stack = jq->stk_top;
fork->saved_curr_frame = jq->curr_frame;
void stack_save(jq_state *jq, uint16_t* retaddr){
struct forkpoint* fork = forkable_stack_push(&jq->fork_stk, sizeof(struct forkpoint));
forkable_stack_save(&jq->data_stk, &fork->saved_data_stack);
forkable_stack_save(&jq->frame_stk, &fork->saved_call_stack);
fork->path_len =
jv_get_kind(jq->path) == JV_KIND_ARRAY ? jv_array_length(jv_copy(jq->path)) : 0;
fork->subexp_nest = jq->subexp_nest;
fork->return_address = retaddr;
jq->stk_top = sp.saved_data_stack;
jq->curr_frame = sp.saved_curr_frame;
}
void stack_switch(jq_state *jq) {
struct forkpoint* fork = forkable_stack_peek(&jq->fork_stk);
forkable_stack_switch(&jq->data_stk, &fork->saved_data_stack);
forkable_stack_switch(&jq->frame_stk, &fork->saved_call_stack);
}
void path_append(jq_state* jq, jv component) {
@@ -204,24 +89,23 @@ void path_append(jq_state* jq, jv component) {
}
uint16_t* stack_restore(jq_state *jq){
while (!stack_pop_will_free(&jq->stk, jq->fork_top)) {
if (stack_pop_will_free(&jq->stk, jq->stk_top)) {
jv_free(stack_pop(jq));
} else if (stack_pop_will_free(&jq->stk, jq->curr_frame)) {
frame_pop(jq);
} else {
assert(0);
}
while (!forkable_stack_empty(&jq->data_stk) &&
forkable_stack_pop_will_free(&jq->data_stk)) {
jv_free(stack_pop(jq));
}
while (!forkable_stack_empty(&jq->frame_stk) &&
forkable_stack_pop_will_free(&jq->frame_stk)) {
frame_pop(&jq->frame_stk);
}
if (jq->fork_top == 0) {
if (forkable_stack_empty(&jq->fork_stk)) {
return 0;
}
struct forkpoint* fork = stack_block(&jq->stk, jq->fork_top);
struct forkpoint* fork = forkable_stack_peek(&jq->fork_stk);
uint16_t* retaddr = fork->return_address;
jq->stk_top = fork->saved_data_stack;
jq->curr_frame = fork->saved_curr_frame;
forkable_stack_restore(&jq->data_stk, &fork->saved_data_stack);
forkable_stack_restore(&jq->frame_stk, &fork->saved_call_stack);
int path_len = fork->path_len;
if (jv_get_kind(jq->path) == JV_KIND_ARRAY) {
assert(path_len >= 0);
@@ -230,49 +114,39 @@ uint16_t* stack_restore(jq_state *jq){
assert(path_len == 0);
}
jq->subexp_nest = fork->subexp_nest;
jq->fork_top = stack_pop_block(&jq->stk, jq->fork_top, sizeof(struct forkpoint));
forkable_stack_pop(&jq->fork_stk);
return retaddr;
}
static void jq_reset(jq_state *jq) {
while (stack_restore(jq)) {}
assert(jq->stk_top == 0);
assert(jq->fork_top == 0);
assert(jq->curr_frame == 0);
stack_reset(&jq->stk);
if (jv_get_kind(jq->path) != JV_KIND_INVALID)
jv_free(jq->path);
jq->path = jv_null();
jq->subexp_nest = 0;
static struct closure make_closure(struct forkable_stack* stk, frame_ptr fr, uint16_t* pc) {
uint16_t level = *pc++;
uint16_t idx = *pc++;
fr = frame_get_level(stk, fr, level);
if (idx & ARG_NEWCLOSURE) {
int subfn_idx = idx & ~ARG_NEWCLOSURE;
assert(subfn_idx < frame_self(fr)->bc->nsubfunctions);
struct closure cl = {frame_self(fr)->bc->subfunctions[subfn_idx],
forkable_stack_to_idx(stk, fr)};
return cl;
} else {
return *frame_closure_arg(fr, idx);
}
}
static void print_error(jq_state *jq, jv value) {
void print_error(jv value) {
assert(!jv_is_valid(value));
jv msg = jv_invalid_get_msg(value);
jv msg2;
if (jv_get_kind(msg) == JV_KIND_STRING)
msg2 = jv_string_fmt("jq: error: %s", jv_string_value(msg));
else
msg2 = jv_string_fmt("jq: error: <unknown>");
if (jv_get_kind(msg) == JV_KIND_STRING) {
fprintf(stderr, "jq: error: %s\n", jv_string_value(msg));
}
jv_free(msg);
if (jq->err_cb)
jq->err_cb(jq->err_cb_data, msg2);
else if (jv_get_kind(msg2) == JV_KIND_STRING)
fprintf(stderr, "%s\n", jv_string_value(msg2));
else
fprintf(stderr, "jq: error: %s\n", strerror(ENOMEM));
jv_free(msg2);
}
#define ON_BACKTRACK(op) ((op)+NUM_OPCODES)
jv jq_next(jq_state *jq) {
jv cfunc_input[MAX_CFUNCTION_ARGS];
jv_nomem_handler(jq->nomem_handler, jq->nomem_handler_data);
uint16_t* pc = stack_restore(jq);
assert(pc);
@@ -282,33 +156,30 @@ jv jq_next(jq_state *jq) {
uint16_t opcode = *pc;
if (jq->debug_trace_enabled) {
dump_operation(frame_current(jq)->bc, pc);
dump_operation(frame_current_bytecode(&jq->frame_stk), pc);
printf("\t");
const struct opcode_description* opdesc = opcode_describe(opcode);
stack_ptr param = 0;
if (!backtracking) {
int stack_in = opdesc->stack_in;
if (stack_in == -1) stack_in = pc[1];
for (int i=0; i<stack_in; i++) {
if (i == 0) {
param = jq->stk_top;
} else {
printf(" | ");
param = *stack_block_next(&jq->stk, param);
}
if (!param) break;
jv_dump(jv_copy(*(jv*)stack_block(&jq->stk, param)), 0);
//printf("<%d>", jv_get_refcnt(param->val));
//printf(" -- ");
//jv_dump(jv_copy(jq->path), 0);
data_stk_elem* param = 0;
int stack_in = opdesc->stack_in;
if (stack_in == -1) stack_in = pc[1];
for (int i=0; i<stack_in; i++) {
if (i == 0) {
param = forkable_stack_peek(&jq->data_stk);
} else {
printf(" | ");
param = forkable_stack_peek_next(&jq->data_stk, param);
}
} else {
printf("\t<backtracking>");
if (!param) break;
jv_dump(jv_copy(param->val), 0);
//printf("<%d>", jv_get_refcnt(param->val));
//printf(" -- ");
//jv_dump(jv_copy(jq->path), 0);
}
if (backtracking) printf("\t<backtracking>");
printf("\n");
}
if (backtracking) {
opcode = ON_BACKTRACK(opcode);
backtracking = 0;
@@ -319,7 +190,7 @@ jv jq_next(jq_state *jq) {
default: assert(0 && "invalid instruction");
case LOADK: {
jv v = jv_array_get(jv_copy(frame_current(jq)->bc->constants), *pc++);
jv v = jv_array_get(jv_copy(frame_current_bytecode(&jq->frame_stk)->constants), *pc++);
assert(jv_is_valid(v));
jv_free(stack_pop(jq));
stack_push(jq, v);
@@ -369,7 +240,8 @@ jv jq_next(jq_state *jq) {
jv v = stack_pop(jq);
uint16_t level = *pc++;
uint16_t vidx = *pc++;
jv* var = frame_local_var(jq, vidx, level);
frame_ptr fp = frame_get_level(&jq->frame_stk, frame_current(&jq->frame_stk), level);
jv* var = frame_local_var(fp, vidx);
assert(jv_get_kind(*var) == JV_KIND_ARRAY);
*var = jv_array_append(*var, v);
break;
@@ -385,8 +257,8 @@ jv jq_next(jq_state *jq) {
stack_push(jq, jv_object_set(objv, k, v));
stack_push(jq, stktop);
} else {
print_error(jq, jv_invalid_with_msg(jv_string_fmt("Cannot use %s as object key",
jv_kind_name(jv_get_kind(k)))));
print_error(jv_invalid_with_msg(jv_string_fmt("Cannot use %s as object key",
jv_kind_name(jv_get_kind(k)))));
jv_free(stktop);
jv_free(v);
jv_free(k);
@@ -400,11 +272,12 @@ jv jq_next(jq_state *jq) {
case RANGE: {
uint16_t level = *pc++;
uint16_t v = *pc++;
jv* var = frame_local_var(jq, v, level);
frame_ptr fp = frame_get_level(&jq->frame_stk, frame_current(&jq->frame_stk), level);
jv* var = frame_local_var(fp, v);
jv max = stack_pop(jq);
if (jv_get_kind(*var) != JV_KIND_NUMBER ||
jv_get_kind(max) != JV_KIND_NUMBER) {
print_error(jq, jv_invalid_with_msg(jv_string_fmt("Range bounds must be numeric")));
print_error(jv_invalid_with_msg(jv_string_fmt("Range bounds must be numeric")));
jv_free(max);
goto do_backtrack;
} else if (jv_number_value(jv_copy(*var)) >= jv_number_value(jv_copy(max))) {
@@ -414,10 +287,9 @@ jv jq_next(jq_state *jq) {
jv curr = jv_copy(*var);
*var = jv_number(jv_number_value(*var) + 1);
struct stack_pos spos = stack_get_pos(jq);
stack_save(jq, pc - 3);
stack_push(jq, jv_copy(max));
stack_save(jq, pc - 3, spos);
stack_switch(jq);
stack_push(jq, curr);
}
break;
@@ -427,7 +299,8 @@ jv jq_next(jq_state *jq) {
case LOADV: {
uint16_t level = *pc++;
uint16_t v = *pc++;
jv* var = frame_local_var(jq, v, level);
frame_ptr fp = frame_get_level(&jq->frame_stk, frame_current(&jq->frame_stk), level);
jv* var = frame_local_var(fp, v);
if (jq->debug_trace_enabled) {
printf("V%d = ", v);
jv_dump(jv_copy(*var), 0);
@@ -442,7 +315,8 @@ jv jq_next(jq_state *jq) {
case LOADVN: {
uint16_t level = *pc++;
uint16_t v = *pc++;
jv* var = frame_local_var(jq, v, level);
frame_ptr fp = frame_get_level(&jq->frame_stk, frame_current(&jq->frame_stk), level);
jv* var = frame_local_var(fp, v);
if (jq->debug_trace_enabled) {
printf("V%d = ", v);
jv_dump(jv_copy(*var), 0);
@@ -457,7 +331,8 @@ jv jq_next(jq_state *jq) {
case STOREV: {
uint16_t level = *pc++;
uint16_t v = *pc++;
jv* var = frame_local_var(jq, v, level);
frame_ptr fp = frame_get_level(&jq->frame_stk, frame_current(&jq->frame_stk), level);
jv* var = frame_local_var(fp, v);
jv val = stack_pop(jq);
if (jq->debug_trace_enabled) {
printf("V%d = ", v);
@@ -473,7 +348,8 @@ jv jq_next(jq_state *jq) {
jv v = stack_pop(jq);
stack_push(jq, jq->path);
stack_save(jq, pc - 1, stack_get_pos(jq));
stack_save(jq, pc - 1);
stack_switch(jq);
stack_push(jq, jv_number(jq->subexp_nest));
stack_push(jq, v);
@@ -492,9 +368,9 @@ jv jq_next(jq_state *jq) {
jv path = jq->path;
jq->path = stack_pop(jq);
struct stack_pos spos = stack_get_pos(jq);
stack_save(jq, pc - 1);
stack_push(jq, jv_copy(path));
stack_save(jq, pc - 1, spos);
stack_switch(jq);
stack_push(jq, path);
jq->subexp_nest = old_subexp_nest;
@@ -508,8 +384,7 @@ jv jq_next(jq_state *jq) {
goto do_backtrack;
}
case INDEX:
case INDEX_OPT: {
case INDEX: {
jv t = stack_pop(jq);
jv k = stack_pop(jq);
path_append(jq, jv_copy(k));
@@ -517,10 +392,7 @@ jv jq_next(jq_state *jq) {
if (jv_is_valid(v)) {
stack_push(jq, v);
} else {
if (opcode == INDEX)
print_error(jq, v);
else
jv_free(v);
print_error(v);
goto do_backtrack;
}
break;
@@ -545,18 +417,16 @@ jv jq_next(jq_state *jq) {
}
case EACH:
case EACH_OPT:
stack_push(jq, jv_number(-1));
// fallthrough
case ON_BACKTRACK(EACH):
case ON_BACKTRACK(EACH_OPT): {
case ON_BACKTRACK(EACH): {
int idx = jv_number_value(stack_pop(jq));
jv container = stack_pop(jq);
int keep_going, is_last = 0;
jv key, value;
if (jv_get_kind(container) == JV_KIND_ARRAY) {
if (opcode == EACH || opcode == EACH_OPT) idx = 0;
if (opcode == EACH) idx = 0;
else idx = idx + 1;
int len = jv_array_length(jv_copy(container));
keep_going = idx < len;
@@ -566,7 +436,7 @@ jv jq_next(jq_state *jq) {
value = jv_array_get(jv_copy(container), idx);
}
} else if (jv_get_kind(container) == JV_KIND_OBJECT) {
if (opcode == EACH || opcode == EACH_OPT) idx = jv_object_iter(container);
if (opcode == EACH) idx = jv_object_iter(container);
else idx = jv_object_iter_next(container, idx);
keep_going = jv_object_iter_valid(container, idx);
if (keep_going) {
@@ -574,12 +444,9 @@ jv jq_next(jq_state *jq) {
value = jv_object_iter_value(container, idx);
}
} else {
assert(opcode == EACH || opcode == EACH_OPT);
if (opcode == EACH) {
print_error(jq,
jv_invalid_with_msg(jv_string_fmt("Cannot iterate over %s",
jv_kind_name(jv_get_kind(container)))));
}
assert(opcode == EACH);
print_error(jv_invalid_with_msg(jv_string_fmt("Cannot iterate over %s",
jv_kind_name(jv_get_kind(container)))));
keep_going = 0;
}
@@ -592,10 +459,10 @@ jv jq_next(jq_state *jq) {
path_append(jq, key);
stack_push(jq, value);
} else {
struct stack_pos spos = stack_get_pos(jq);
stack_save(jq, pc - 1);
stack_push(jq, container);
stack_push(jq, jv_number(idx));
stack_save(jq, pc - 1, spos);
stack_switch(jq);
path_append(jq, key);
stack_push(jq, value);
}
@@ -613,7 +480,8 @@ jv jq_next(jq_state *jq) {
}
case FORK: {
stack_save(jq, pc - 1, stack_get_pos(jq));
stack_save(jq, pc - 1);
stack_switch(jq);
pc++; // skip offset this time
break;
}
@@ -627,96 +495,53 @@ jv jq_next(jq_state *jq) {
case CALL_BUILTIN: {
int nargs = *pc++;
jv top = stack_pop(jq);
jv* in = cfunc_input;
in[0] = top;
cfunc_input[0] = top;
for (int i = 1; i < nargs; i++) {
in[i] = stack_pop(jq);
cfunc_input[i] = stack_pop(jq);
}
struct cfunction* function = &frame_current(jq)->bc->globals->cfunctions[*pc++];
typedef jv (*func_1)(jv);
typedef jv (*func_2)(jv,jv);
typedef jv (*func_3)(jv,jv,jv);
typedef jv (*func_4)(jv,jv,jv,jv);
typedef jv (*func_5)(jv,jv,jv,jv,jv);
switch (function->nargs) {
case 1: top = ((func_1)function->fptr)(in[0]); break;
case 2: top = ((func_2)function->fptr)(in[0], in[1]); break;
case 3: top = ((func_3)function->fptr)(in[0], in[1], in[2]); break;
case 4: top = ((func_4)function->fptr)(in[0], in[1], in[2], in[3]); break;
case 5: top = ((func_5)function->fptr)(in[0], in[1], in[2], in[3], in[4]); break;
default: return jv_invalid_with_msg(jv_string("Function takes too many arguments"));
}
struct cfunction* func = &frame_current_bytecode(&jq->frame_stk)->globals->cfunctions[*pc++];
top = cfunction_invoke(func, cfunc_input);
if (jv_is_valid(top)) {
stack_push(jq, top);
} else {
print_error(jq, top);
print_error(top);
goto do_backtrack;
}
break;
}
case TAIL_CALL_JQ:
case CALL_JQ: {
/*
* Bytecode layout here:
*
* CALL_JQ
* <nclosures> (i.e., number of call arguments)
* <callee closure> (what we're calling)
* <nclosures' worth of closures> (frame reference + code pointer)
*
* <next instruction (to return to)>
*
* Each closure consists of two uint16_t values: a "level"
* identifying the frame to be closed over, and an index.
*
* The level is a relative number of call frames reachable from
* the currently one; 0 -> current frame, 1 -> previous frame, and
* so on.
*
* The index is either an index of the closed frame's subfunctions
* or of the closed frame's parameter closures. If the latter,
* that closure will be passed, else the closed frame's pointer
* and the subfunction's code will form the closure to be passed.
*
* See make_closure() for more information.
*/
jv input = stack_pop(jq);
uint16_t nclosures = *pc++;
uint16_t* retaddr = pc + 2 + nclosures*2;
stack_ptr retdata = jq->stk_top;
struct frame* new_frame;
struct closure cl = make_closure(jq, pc);
if (opcode == TAIL_CALL_JQ) {
retaddr = frame_current(jq)->retaddr;
retdata = frame_current(jq)->retdata;
frame_pop(jq);
frame_ptr new_frame = frame_push(&jq->frame_stk,
make_closure(&jq->frame_stk, frame_current(&jq->frame_stk), pc),
retaddr);
pc += 2;
frame_ptr old_frame = forkable_stack_peek_next(&jq->frame_stk, new_frame);
assert(nclosures == frame_self(new_frame)->bc->nclosures);
for (int i=0; i<nclosures; i++) {
*frame_closure_arg(new_frame, i) = make_closure(&jq->frame_stk, old_frame, pc);
pc += 2;
}
new_frame = frame_push(jq, cl, pc + 2, nclosures);
new_frame->retdata = retdata;
new_frame->retaddr = retaddr;
pc = new_frame->bc->code;
stack_push(jq, input);
pc = frame_current_bytecode(&jq->frame_stk)->code;
break;
}
case RET: {
jv value = stack_pop(jq);
assert(jq->stk_top == frame_current(jq)->retdata);
uint16_t* retaddr = frame_current(jq)->retaddr;
uint16_t* retaddr = *frame_current_retaddr(&jq->frame_stk);
if (retaddr) {
// function return
pc = retaddr;
frame_pop(jq);
frame_pop(&jq->frame_stk);
} else {
// top-level return, yielding value
struct stack_pos spos = stack_get_pos(jq);
jv value = stack_pop(jq);
stack_save(jq, pc - 1);
stack_push(jq, jv_null());
stack_save(jq, pc - 1, spos);
stack_switch(jq);
return value;
}
stack_push(jq, value);
break;
}
case ON_BACKTRACK(RET): {
@@ -727,60 +552,28 @@ jv jq_next(jq_state *jq) {
}
}
jq_state *jq_init(void) {
jq_state *jq;
jq = jv_mem_alloc_unguarded(sizeof(*jq));
if (jq == NULL)
return NULL;
jq->bc = 0;
stack_init(&jq->stk);
jq->stk_top = 0;
jq->fork_top = 0;
jq->curr_frame = 0;
jq->err_cb = NULL;
jq->err_cb_data = NULL;
jq->path = jv_null();
return jq;
}
void jq_set_error_cb(jq_state *jq, jq_err_cb cb, void *data) {
jq->err_cb = cb;
jq->err_cb_data = data;
}
void jq_get_error_cb(jq_state *jq, jq_err_cb *cb, void **data) {
*cb = jq->err_cb;
*data = jq->err_cb_data;
}
void jq_set_nomem_handler(jq_state *jq, void (*nomem_handler)(void *), void *data) {
jv_nomem_handler(nomem_handler, data);
jq->nomem_handler = nomem_handler;
jq->nomem_handler_data = data;
}
void jq_start(jq_state *jq, jv input, int flags) {
jv_nomem_handler(jq->nomem_handler, jq->nomem_handler_data);
jq_reset(jq);
void jq_init(struct bytecode* bc, jv input, jq_state **jq, int flags) {
jq_state *new_jq;
new_jq = jv_mem_alloc(sizeof(*new_jq));
memset(new_jq, 0, sizeof(*new_jq));
new_jq->path = jv_null();
forkable_stack_init(&new_jq->data_stk, sizeof(data_stk_elem) * 100);
forkable_stack_init(&new_jq->frame_stk, 1024);
forkable_stack_init(&new_jq->fork_stk, 1024);
struct closure top = {jq->bc, -1};
struct frame* top_frame = frame_push(jq, top, 0, 0);
top_frame->retdata = 0;
top_frame->retaddr = 0;
stack_push(jq, input);
stack_save(jq, jq->bc->code, stack_get_pos(jq));
stack_push(new_jq, input);
struct closure top = {bc, -1};
frame_push(&new_jq->frame_stk, top, 0);
stack_save(new_jq, bc->code);
stack_switch(new_jq);
if (flags & JQ_DEBUG_TRACE) {
jq->debug_trace_enabled = 1;
new_jq->debug_trace_enabled = 1;
} else {
jq->debug_trace_enabled = 0;
new_jq->debug_trace_enabled = 0;
}
jq->initial_execution = 1;
new_jq->initial_execution = 1;
*jq = new_jq;
}
void jq_teardown(jq_state **jq) {
@@ -789,24 +582,25 @@ void jq_teardown(jq_state **jq) {
return;
*jq = NULL;
jq_reset(old_jq);
bytecode_free(old_jq->bc);
old_jq->bc = 0;
while (stack_restore(old_jq)) {}
assert(forkable_stack_empty(&old_jq->fork_stk));
assert(forkable_stack_empty(&old_jq->data_stk));
assert(forkable_stack_empty(&old_jq->frame_stk));
forkable_stack_free(&old_jq->fork_stk);
forkable_stack_free(&old_jq->data_stk);
forkable_stack_free(&old_jq->frame_stk);
jv_free(old_jq->path);
jv_mem_free(old_jq);
}
int jq_compile_args(jq_state *jq, const char* str, jv args) {
jv_nomem_handler(jq->nomem_handler, jq->nomem_handler_data);
struct bytecode* jq_compile_args(const char* str, jv args) {
assert(jv_get_kind(args) == JV_KIND_ARRAY);
struct locfile locations;
locfile_init(&locations, jq, str, strlen(str));
locfile_init(&locations, str, strlen(str));
block program;
jq_reset(jq);
if (jq->bc) {
bytecode_free(jq->bc);
jq->bc = 0;
}
struct bytecode* bc = 0;
int nerrors = jq_parse(&locations, &program);
if (nerrors == 0) {
for (int i=0; i<jv_array_length(jv_copy(args)); i++) {
@@ -816,31 +610,17 @@ int jq_compile_args(jq_state *jq, const char* str, jv args) {
program = gen_var_binding(gen_const(value), jv_string_value(name), program);
jv_free(name);
}
nerrors = builtins_bind(jq, &program);
if (nerrors == 0) {
nerrors = block_compile(program, &locations, &jq->bc);
}
jv_free(args);
program = builtins_bind(program);
nerrors = block_compile(program, &locations, &bc);
}
jv_free(args);
if (nerrors) {
jv s = jv_string_fmt("%d compile %s", nerrors,
nerrors > 1 ? "errors" : "error");
if (jq->err_cb != NULL)
jq->err_cb(jq->err_cb_data, s);
else if (!jv_is_valid(s))
fprintf(stderr, "Error formatting jq compilation errors: %s\n", strerror(errno));
else
fprintf(stderr, "%s\n", jv_string_value(s));
jv_free(s);
fprintf(stderr, "%d compile %s\n", nerrors, nerrors > 1 ? "errors" : "error");
}
locfile_free(&locations);
return jq->bc != NULL;
return bc;
}
int jq_compile(jq_state *jq, const char* str) {
return jq_compile_args(jq, str, jv_array());
}
void jq_dump_disassembly(jq_state *jq, int indent) {
dump_disassembly(indent, jq->bc);
struct bytecode* jq_compile(const char* str) {
return jq_compile_args(str, jv_array());
}
+20
View File
@@ -0,0 +1,20 @@
#ifndef EXECUTE_H
#define EXECUTE_H
#include "bytecode.h"
struct bytecode* jq_compile(const char* str);
/* args must be an array of the form [{name:"foo", value:"thing"}, {name:"bar",value:3}] */
struct bytecode* jq_compile_args(const char* str, jv args);
typedef struct jq_state jq_state;
enum {JQ_DEBUG_TRACE = 1};
void jq_init(struct bytecode* bc, jv value, jq_state **, int flags);
jv jq_next(jq_state *);
void jq_teardown(jq_state **);
#endif
+172
View File
@@ -0,0 +1,172 @@
#ifndef FORKABLE_STACK_H
#define FORKABLE_STACK_H
#include <stddef.h>
#include <assert.h>
#include <string.h>
#include "jv_alloc.h"
struct forkable_stack_header {
/* distance in bytes between this header and the header
of the next object on the stack */
int next_delta;
};
#define FORKABLE_STACK_HEADER struct forkable_stack_header fk_header_
struct forkable_stack {
// Stack grows down from stk+length
char* stk;
// stk+length is just past end of allocated area
// stk = jv_mem_alloc(length)
int length;
// stk+pos is header of top object, or stk+length if empty
int pos;
// everything after-or-including stk+savedlimit must be preserved
int savedlimit;
};
static void forkable_stack_check(struct forkable_stack* s) {
assert(s->stk);
assert(s->length > 0);
assert(s->pos >= 0 && s->pos <= s->length);
assert(s->savedlimit >= 0 && s->savedlimit <= s->length);
}
static int forkable_stack_empty(struct forkable_stack* s) {
return s->pos == s->length;
}
static void forkable_stack_init(struct forkable_stack* s, size_t sz) {
s->stk = jv_mem_alloc(sz);
s->length = sz;
s->pos = s->length;
s->savedlimit = s->length;
forkable_stack_check(s);
}
static void forkable_stack_free(struct forkable_stack* s) {
assert(forkable_stack_empty(s));
assert(s->savedlimit == s->length);
jv_mem_free(s->stk);
s->stk = 0;
}
static void* forkable_stack_push(struct forkable_stack* s, size_t sz_size) {
assert(sz_size > 0 && sz_size % sizeof(struct forkable_stack_header) == 0);
int size = (int)sz_size;
forkable_stack_check(s);
int curr = s->pos < s->savedlimit ? s->pos : s->savedlimit;
if (curr - size < 0) {
int oldlen = s->length;
s->length = (size + oldlen + 1024) * 2;
s->stk = jv_mem_realloc(s->stk, s->length);
int shift = s->length - oldlen;
memmove(s->stk + shift, s->stk, oldlen);
s->pos += shift;
s->savedlimit += shift;
curr += shift;
}
int newpos = curr - size;
assert(newpos < s->pos);
void* ret = (void*)(s->stk + newpos);
((struct forkable_stack_header*)ret)->next_delta = s->pos - newpos;
s->pos = newpos;
forkable_stack_check(s);
return ret;
}
static void* forkable_stack_peek(struct forkable_stack* s) {
assert(!forkable_stack_empty(s));
forkable_stack_check(s);
return (void*)(s->stk + s->pos);
}
static void* forkable_stack_peek_next(struct forkable_stack* s, void* top) {
forkable_stack_check(s);
struct forkable_stack_header* elem = top;
int elempos = (char*)top - s->stk;
assert(elempos >= 0 && elempos < s->length);
assert(elempos + elem->next_delta <= s->length);
if (elempos + elem->next_delta < s->length) {
return (void*)(s->stk + elempos + elem->next_delta);
} else {
return 0;
}
}
// Returns 1 if the next forkable_stack_pop will permanently remove an
// object from the stack (i.e. the top object was not saved with a fork)
static int forkable_stack_pop_will_free(struct forkable_stack* s) {
return s->pos < s->savedlimit;
}
static void forkable_stack_pop(struct forkable_stack* s) {
forkable_stack_check(s);
struct forkable_stack_header* elem = forkable_stack_peek(s);
int reclaim_upto = s->pos + elem->next_delta < s->savedlimit ?
s->pos + elem->next_delta : s->savedlimit;
assert(reclaim_upto <= s->length);
int reclaimed = reclaim_upto > s->pos ? reclaim_upto - s->pos : 0;
assert(0 <= reclaimed && s->pos + reclaimed <= s->length);
// s->pos <= i < reclaim_upto means that position i is to be freed
assert((reclaimed > 0) == forkable_stack_pop_will_free(s));
int new_pos = s->pos + elem->next_delta;
jv_mem_invalidate(elem, reclaimed);
s->pos = new_pos;
}
struct forkable_stack_state {
// We save the previous pos, savedlimit as
// length-pos, length-savedlimit since these
// values are stable across stack reallocations.
int prev_pos_delta, prev_limit_delta;
};
static void forkable_stack_save(struct forkable_stack* s, struct forkable_stack_state* state) {
forkable_stack_check(s);
state->prev_pos_delta = s->length - s->pos;
state->prev_limit_delta = s->length - s->savedlimit;
if (s->pos < s->savedlimit) s->savedlimit = s->pos;
}
static void forkable_stack_switch(struct forkable_stack* s, struct forkable_stack_state* state) {
forkable_stack_check(s);
int curr_pos = s->pos;
s->pos = s->length - state->prev_pos_delta;
state->prev_pos_delta = s->length - curr_pos;
int curr_limit = s->savedlimit;
if (curr_pos < curr_limit) s->savedlimit = curr_pos;
//state->prevlimit = curr_limit; FIXME clean up
forkable_stack_check(s);
}
static void forkable_stack_restore(struct forkable_stack* s, struct forkable_stack_state* state) {
forkable_stack_check(s);
assert(s->savedlimit <= s->length - state->prev_pos_delta);
assert(s->savedlimit <= s->length - state->prev_limit_delta);
s->pos = s->length - state->prev_pos_delta;
s->savedlimit = s->length - state->prev_limit_delta;
forkable_stack_check(s);
}
typedef int stack_idx;
static stack_idx forkable_stack_to_idx(struct forkable_stack* s, void* ptr) {
char* item = ptr;
int pos = item - s->stk;
assert(pos >= 0 && pos < s->length);
return s->length - pos;
}
static void* forkable_stack_from_idx(struct forkable_stack* s, stack_idx idx) {
assert(idx >= 1 && idx <= s->length);
return &s->stk[s->length - idx];
}
#endif
+104
View File
@@ -0,0 +1,104 @@
#ifndef FRAME_LAYOUT_H
#include "forkable_stack.h"
#include "bytecode.h"
struct closure {
struct bytecode* bc;
stack_idx env;
};
struct continuation {
struct bytecode* bc;
stack_idx env;
uint16_t* retaddr;
};
typedef union frame_elem {
FORKABLE_STACK_HEADER;
struct continuation cont;
struct closure closure;
jv jsonval;
} *frame_ptr;
/*
* Frame layout
* fr[0] - FORKABLE_STACK_HEADER (next pointer)
* fr[1] - self (used to store return addresses, etc)
* fr[2...nclosures+2] - closure params
* fr[nclosures+2..nclosures+nlocals+2] - local variables
*/
static int frame_size(struct bytecode* bc) {
return sizeof(union frame_elem) * (bc->nclosures + bc->nlocals + 2);
}
static struct continuation* frame_self(frame_ptr fr) {
return &fr[1].cont;
}
static struct closure* frame_closure_arg(frame_ptr fr, int closure) {
assert(closure >= 0);
assert(closure < frame_self(fr)->bc->nclosures);
return &fr[2+closure].closure;
}
static jv* frame_local_var(frame_ptr fr, int var) {
assert(var >= 0);
assert(var < frame_self(fr)->bc->nlocals);
return &fr[2 + frame_self(fr)->bc->nclosures + var].jsonval;
}
static frame_ptr frame_current(struct forkable_stack* stk) {
frame_ptr fp = forkable_stack_peek(stk);
if (forkable_stack_peek_next(stk, fp)) {
struct bytecode* bc = frame_self(forkable_stack_peek_next(stk, fp))->bc;
assert(frame_self(fp)->retaddr >= bc->code && frame_self(fp)->retaddr < bc->code + bc->codelen);
} else {
assert(frame_self(fp)->retaddr == 0);
}
return fp;
}
static struct bytecode* frame_current_bytecode(struct forkable_stack* stk) {
return frame_self(frame_current(stk))->bc;
}
static uint16_t** frame_current_retaddr(struct forkable_stack* stk) {
return &frame_self(frame_current(stk))->retaddr;
}
static frame_ptr frame_get_parent(struct forkable_stack* stk, frame_ptr fr) {
return forkable_stack_from_idx(stk, frame_self(fr)->env);
}
static frame_ptr frame_get_level(struct forkable_stack* stk, frame_ptr fr, int level) {
for (int i=0; i<level; i++) {
fr = frame_get_parent(stk, fr);
}
return fr;
}
static frame_ptr frame_push(struct forkable_stack* stk, struct closure cl, uint16_t* retaddr) {
frame_ptr fp = forkable_stack_push(stk, frame_size(cl.bc));
struct continuation* cc = frame_self(fp);
cc->bc = cl.bc;
cc->env = cl.env;
cc->retaddr = retaddr;
for (int i=0; i<cl.bc->nlocals; i++) {
*frame_local_var(fp, i) = jv_invalid();
}
return fp;
}
static void frame_pop(struct forkable_stack* stk) {
frame_ptr fp = frame_current(stk);
if (forkable_stack_pop_will_free(stk)) {
int nlocals = frame_self(fp)->bc->nlocals;
for (int i=0; i<nlocals; i++) {
jv_free(*frame_local_var(fp, i));
}
}
forkable_stack_pop(stk);
}
#endif
@@ -6,12 +6,13 @@ mask = lambda n: (1 << n) - 1
def print_table(type, name, t):
assert len(t) == 256
print("static const %s %s[] =" % (type, name))
first = True
for i in range(0,len(t),16):
print ((" {" if i == 0 else " ") +
", ".join("0x%02x"%n for n in t[i:i+16]) +
("," if i + 16 < len(t) else "};"))
("," if i + 16 < 256 else "};"))
def utf8info(c):
@@ -29,4 +30,3 @@ print("#define UTF8_CONTINUATION_BYTE ((unsigned char)255)")
print_table("unsigned char", "utf8_coding_length", table(0))
print_table("unsigned char", "utf8_coding_bits", table(1))
print_table("int", "utf8_first_codepoint", [0, 0x0, 0x80, 0x800, 0x10000])
-2012
View File
File diff suppressed because it is too large. Load diff
-23
View File
@@ -1,23 +0,0 @@
#ifndef _JQ_H_
#define _JQ_H_
#include <stdio.h>
#include <jv.h>
enum {JQ_DEBUG_TRACE = 1};
typedef struct jq_state jq_state;
typedef void (*jq_err_cb)(void *, jv);
jq_state *jq_init(void);
void jq_set_error_cb(jq_state *, jq_err_cb, void *);
void jq_get_error_cb(jq_state *, jq_err_cb *, void **);
void jq_set_nomem_handler(jq_state *, void (*)(void *), void *);
int jq_compile(jq_state *, const char* str);
int jq_compile_args(jq_state *, const char* str, jv args);
void jq_dump_disassembly(jq_state *, int);
void jq_start(jq_state *, jv value, int flags);
jv jq_next(jq_state *);
void jq_teardown(jq_state **);
#endif /* !_JQ_H_ */
+2 -7
View File
@@ -52,16 +52,11 @@ rm -rf %{buildroot}
%endif
%{_datadir}/doc/%{name}/AUTHORS
%{_datadir}/doc/%{name}/COPYING
%{_datadir}/doc/%{name}/INSTALL
%{_datadir}/doc/%{name}/NEWS
%{_datadir}/doc/%{name}/README
%{_datadir}/doc/%{name}/README.md
%{_datadir}/man/man1/jq.1
%{_includedir}/jq.h
%{_includedir}/jv.h
%{_prefix}/lib/libjq.a
%{_prefix}/lib/libjq.la
%{_prefix}/lib/libjq.so
%{_prefix}/lib/libjq.so.1
%{_prefix}/lib/libjq.so.1.0.4
%changelog
-2
View File
@@ -1,7 +1,5 @@
#ifndef JQ_PARSER_H
#define JQ_PARSER_H
#include "locfile.h"
#include "compile.h"
int jq_parse(struct locfile* source, block* answer);
int jq_parse_library(struct locfile* locations, block* answer);
+17 -38
View File
@@ -3,23 +3,15 @@
#include <string.h>
#include <stdlib.h>
#include "jv.h"
#include "jq.h"
#include "execute.h"
static void jv_test();
static void run_jq_tests();
int jq_testsuite(int argc, char* argv[]) {
FILE *testdata = stdin;
jv_test();
if (argc > 2) {
testdata = fopen(argv[2], "r");
if (!testdata) {
perror("fopen");
exit(1);
}
}
run_jq_tests(testdata);
run_jq_tests(stdin);
return 0;
}
@@ -35,9 +27,6 @@ static void run_jq_tests(FILE *testdata) {
int tests = 0, passed = 0, invalid = 0;
jq_state *jq = NULL;
jq = jq_init();
assert(jq);
while (1) {
if (!fgets(buf, sizeof(buf), testdata)) break;
if (skipline(buf)) continue;
@@ -45,15 +34,15 @@ static void run_jq_tests(FILE *testdata) {
printf("Testing %s\n", buf);
int pass = 1;
tests++;
int compiled = jq_compile(jq, buf);
if (!compiled) {invalid++; continue;}
struct bytecode* bc = jq_compile(buf);
if (!bc) {invalid++; continue;}
printf("Disassembly:\n");
jq_dump_disassembly(jq, 2);
dump_disassembly(2, bc);
printf("\n");
if (!fgets(buf, sizeof(buf), testdata)) { invalid++; break; }
fgets(buf, sizeof(buf), testdata);
jv input = jv_parse(buf);
if (!jv_is_valid(input)){ invalid++; continue; }
jq_start(jq, input, JQ_DEBUG_TRACE);
jq_init(bc, input, &jq, JQ_DEBUG_TRACE);
while (fgets(buf, sizeof(buf), testdata)) {
if (skipline(buf)) break;
@@ -92,9 +81,10 @@ static void run_jq_tests(FILE *testdata) {
jv_free(extra);
}
}
jq_teardown(&jq);
bytecode_free(bc);
passed+=pass;
}
jq_teardown(&jq);
printf("%d of %d tests passed (%d malformed)\n", passed,tests,invalid);
if (passed != tests) exit(1);
}
@@ -125,9 +115,9 @@ static void jv_test() {
jv_free(a2);
assert(jv_get_refcnt(a) == 1);
assert(a.val.nontrivial.ptr->count == 1);
a = jv_array_append(a, jv_copy(a));
assert(jv_get_refcnt(a) == 1);
assert(a.val.nontrivial.ptr->count == 1);
assert(jv_array_length(jv_copy(a)) == 2);
assert(jv_number_value(jv_array_get(jv_copy(a), 0)) == 42);
@@ -160,9 +150,9 @@ static void jv_test() {
jv_free(subarray);
void* before = sub2.u.ptr;
void* before = sub2.val.nontrivial.ptr;
sub2 = jv_array_append(sub2, jv_number(200));
void* after = sub2.u.ptr;
void* after = sub2.val.nontrivial.ptr;
assert(before == after);
jv_free(sub2);
@@ -182,10 +172,8 @@ static void jv_test() {
a4 = jv_array_slice(a4, 0, 1);
assert(jv_array_length(jv_copy(a4)) == 1);
a4 = jv_array_append(a4, jv_number(4));
assert(jv_array_length(jv_copy(a4)) == 2);
assert(jv_array_length(jv_copy(a5)) == 2);
jv_free(a4);
jv_free(a5);
assert(jv_array_length(a4) == 2);
assert(jv_array_length(a5) == 2);
assert(jv_array_length(jv_copy(a)) == 2);
@@ -203,10 +191,8 @@ static void jv_test() {
assert(jv_equal(jv_string("foo"), jv_string_sized("foo", 3)));
char nasty[] = "foo\0";
jv shortstr = jv_string(nasty), longstr = jv_string_sized(nasty, sizeof(nasty));
assert(jv_string_length_bytes(jv_copy(shortstr)) == (int)strlen(nasty));
assert(jv_string_length_bytes(jv_copy(longstr)) == (int)sizeof(nasty));
jv_free(shortstr);
jv_free(longstr);
assert(jv_string_length_bytes(shortstr) == (int)strlen(nasty));
assert(jv_string_length_bytes(longstr) == (int)sizeof(nasty));
char a1s[] = "hello", a2s[] = "hello", bs[] = "goodbye";
@@ -252,11 +238,4 @@ static void jv_test() {
jv_free(o2);
}
/// Compile errors
{
jq_state *jq = jq_init();
jq_compile_args(jq, "}", jv_array());
jq_teardown(&jq);
}
}
+268 -522
View File
File diff suppressed because it is too large. Load diff
+28 -53
View File
@@ -1,9 +1,11 @@
#ifndef JV_H
#define JV_H
#include <stdarg.h>
#include <stdint.h>
#include <stdio.h>
#include <assert.h>
#include <stddef.h>
typedef enum {
JV_KIND_INVALID,
@@ -16,19 +18,21 @@ typedef enum {
JV_KIND_OBJECT
} jv_kind;
struct jv_refcnt;
/* All of the fields of this struct are private.
Really. Do not play with them. */
typedef struct {
unsigned char kind_flags;
unsigned char pad_;
unsigned short offset; /* array offsets */
int size;
size_t count;
} jv_refcnt;
typedef struct{
jv_refcnt* ptr;
int i[2];
} jv_nontrivial;
typedef struct {
jv_kind kind;
union {
struct jv_refcnt* ptr;
double number;
} u;
jv_nontrivial nontrivial;
} val;
} jv;
/*
@@ -43,27 +47,24 @@ static int jv_is_valid(jv x) { return jv_get_kind(x) != JV_KIND_INVALID; }
jv jv_copy(jv);
void jv_free(jv);
int jv_get_refcnt(jv);
int jv_equal(jv, jv);
int jv_contains(jv, jv);
jv jv_invalid(void);
jv jv_invalid();
jv jv_invalid_with_msg(jv);
jv jv_invalid_get_msg(jv);
int jv_invalid_has_msg(jv);
jv jv_null(void);
jv jv_true(void);
jv jv_false(void);
jv jv_null();
jv jv_true();
jv jv_false();
jv jv_bool(int);
jv jv_number(double);
double jv_number_value(jv);
int jv_is_integer(jv);
jv jv_array(void);
jv jv_array();
jv jv_array_sized(int);
int jv_array_length(jv);
jv jv_array_get(jv, int);
@@ -71,7 +72,6 @@ jv jv_array_set(jv, int, jv);
jv jv_array_append(jv, jv);
jv jv_array_concat(jv, jv);
jv jv_array_slice(jv, int, int);
jv jv_array_indexes(jv, jv);
#define jv_array_foreach(a, i, x) \
for (int jv_len__ = jv_array_length(jv_copy(a)), i=0, jv_j__ = 1; \
jv_j__; jv_j__ = 0) \
@@ -82,30 +82,21 @@ jv jv_array_indexes(jv, jv);
jv jv_string(const char*);
jv jv_string_sized(const char*, int);
jv jv_string_empty(int len);
int jv_string_length_bytes(jv);
int jv_string_length_codepoints(jv);
unsigned long jv_string_hash(jv);
uint32_t jv_string_hash(jv);
const char* jv_string_value(jv);
jv jv_string_indexes(jv j, jv k);
jv jv_string_slice(jv j, int start, int end);
jv jv_string_concat(jv, jv);
jv jv_string_vfmt(const char*, va_list);
jv jv_string_fmt(const char*, ...);
jv jv_string_append_codepoint(jv a, uint32_t c);
jv jv_string_append_buf(jv a, const char* buf, int len);
jv jv_string_append_str(jv a, const char* str);
jv jv_string_split(jv j, jv sep);
jv jv_string_explode(jv j);
jv jv_string_implode(jv j);
jv jv_object(void);
jv jv_object();
jv jv_object_get(jv object, jv key);
jv jv_object_set(jv object, jv key, jv value);
jv jv_object_delete(jv object, jv key);
int jv_object_length(jv object);
jv jv_object_merge(jv, jv);
jv jv_object_merge_recursive(jv, jv);
int jv_object_iter(jv);
int jv_object_iter_next(jv, int);
@@ -126,36 +117,20 @@ jv jv_object_iter_value(jv, int);
int jv_get_refcnt(jv);
enum { JV_PRINT_PRETTY = 1, JV_PRINT_ASCII = 2, JV_PRINT_COLOUR = 4, JV_PRINT_SORTED = 8 };
void jv_dumpf(jv, FILE *f, int flags);
enum { JV_PRINT_PRETTY = 1, JV_PRINT_ASCII = 2, JV_PRINT_COLOUR = 4 };
void jv_dump(jv, int flags);
void jv_show(jv, int flags);
jv jv_dump_string(jv, int flags);
jv jv_parse(const char* string);
jv jv_parse_sized(const char* string, int length);
typedef void (*jv_nomem_handler_f)(void *);
void jv_nomem_handler(jv_nomem_handler_f, void *);
jv jv_load_file(const char *, int);
struct jv_parser;
struct jv_parser* jv_parser_new(int);
void jv_parser_set_buf(struct jv_parser*, const char*, int, int);
jv jv_parser_next(struct jv_parser*);
void jv_parser_free(struct jv_parser*);
jv jv_get(jv, jv);
jv jv_set(jv, jv, jv);
jv jv_has(jv, jv);
jv jv_setpath(jv, jv, jv);
jv jv_getpath(jv, jv);
jv jv_delpaths(jv, jv);
jv jv_keys(jv /*object or array*/);
int jv_cmp(jv, jv);
jv jv_group(jv, jv);
jv jv_sort(jv, jv);
#endif
-114
View File
@@ -2,121 +2,11 @@
#include <stdio.h>
#include "jv_alloc.h"
struct nomem_handler {
jv_nomem_handler_f handler;
void *data;
};
#if !defined(HAVE_PTHREAD_KEY_CREATE) || \
!defined(HAVE_PTHREAD_ONCE) || \
!defined(HAVE_ATEXIT)
/* Try thread-local storage? */
#ifdef _MSC_VER
/* Visual C++: yes */
static __declspec(thread) struct nomem_handler nomem_handler;
#define USE_TLS
#else
#ifdef HAVE___THREAD
/* GCC and friends: yes */
static __thread struct nomem_handler nomem_handler;
#define USE_TLS
#endif /* HAVE___THREAD */
#endif /* _MSC_VER */
#endif /* !HAVE_PTHREAD_KEY_CREATE */
#ifdef USE_TLS
void jv_nomem_handler(jv_nomem_handler_f handler, void *data) {
nomem_handler.handler = handler;
}
static void memory_exhausted() {
if (nomem_handler.handler)
nomem_handler.handler(nomem_handler.data); // Maybe handler() will longjmp() to safety
// Or not
fprintf(stderr, "error: cannot allocate memory\n");
abort();
}
#else /* USE_TLS */
#ifdef HAVE_PTHREAD_KEY_CREATE
#include <pthread.h>
pthread_key_t nomem_handler_key;
pthread_once_t mem_once = PTHREAD_ONCE_INIT;
static void tsd_fini(void) {
struct nomem_handler *nomem_handler;
nomem_handler = pthread_getspecific(nomem_handler_key);
if (nomem_handler) {
(void) pthread_setspecific(nomem_handler_key, NULL);
free(nomem_handler);
}
}
static void tsd_init(void) {
if (pthread_key_create(&nomem_handler_key, NULL) != 0) {
fprintf(stderr, "error: cannot create thread specific key");
abort();
}
if (atexit(tsd_fini) != 0) {
fprintf(stderr, "error: cannot set an exit handler");
abort();
}
struct nomem_handler *nomem_handler = calloc(1, sizeof(struct nomem_handler));
if (pthread_setspecific(nomem_handler_key, nomem_handler) != 0) {
fprintf(stderr, "error: cannot set thread specific data");
abort();
}
}
void jv_nomem_handler(jv_nomem_handler_f handler, void *data) {
pthread_once(&mem_once, tsd_init); // cannot fail
struct nomem_handler *nomem_handler;
nomem_handler = pthread_getspecific(nomem_handler_key);
if (nomem_handler == NULL) {
handler(data);
fprintf(stderr, "error: cannot allocate memory\n");
abort();
}
nomem_handler->handler = handler;
nomem_handler->data = data;
}
static void memory_exhausted() {
struct nomem_handler *nomem_handler;
pthread_once(&mem_once, tsd_init);
nomem_handler = pthread_getspecific(nomem_handler_key);
if (nomem_handler)
nomem_handler->handler(nomem_handler->data); // Maybe handler() will longjmp() to safety
// Or not
fprintf(stderr, "error: cannot allocate memory\n");
abort();
}
#else
/* No thread-local storage of any kind that we know how to handle */
static struct nomem_handler nomem_handler;
void jv_nomem_handler(jv_nomem_handler_f handler, void *data) {
nomem_handler.handler = handler;
nomem_handler.data = data;
}
static void memory_exhausted() {
fprintf(stderr, "error: cannot allocate memory\n");
abort();
}
#endif /* HAVE_PTHREAD_KEY_CREATE */
#endif /* USE_TLS */
void* jv_mem_alloc(size_t sz) {
void* p = malloc(sz);
if (!p) {
@@ -125,10 +15,6 @@ void* jv_mem_alloc(size_t sz) {
return p;
}
void* jv_mem_alloc_unguarded(size_t sz) {
return malloc(sz);
}
void jv_mem_free(void* p) {
free(p);
}
-2
View File
@@ -2,7 +2,6 @@
#define JV_ALLOC_H
#include <stddef.h>
#include "jv.h"
#ifndef NDEBUG
extern volatile char jv_mem_uninitialised;
@@ -16,7 +15,6 @@ static void jv_mem_invalidate(void* mem, size_t n) {
}
void* jv_mem_alloc(size_t);
void* jv_mem_alloc_unguarded(size_t);
void jv_mem_free(void*);
__attribute__((warn_unused_result)) void* jv_mem_realloc(void*, size_t);
+29 -68
View File
@@ -1,21 +1,17 @@
#include "jv_aux.h"
#include <string.h>
#include <stdlib.h>
#include <assert.h>
#include "jv_alloc.h"
static int parse_slice(jv j, jv slice, int* pstart, int* pend) {
static int parse_slice(jv array, jv slice, int* pstart, int* pend) {
// Array slices
int len = jv_array_length(jv_copy(array));
jv start_jv = jv_object_get(jv_copy(slice), jv_string("start"));
jv end_jv = jv_object_get(slice, jv_string("end"));
if (jv_get_kind(start_jv) == JV_KIND_NULL) {
jv_free(start_jv);
start_jv = jv_number(0);
}
int len;
if (jv_get_kind(j) == JV_KIND_ARRAY)
len = jv_array_length(jv_copy(j));
else
len = jv_string_length_codepoints(jv_copy(j));
if (jv_get_kind(end_jv) == JV_KIND_NULL) {
jv_free(end_jv);
end_jv = jv_number(len);
@@ -26,18 +22,13 @@ static int parse_slice(jv j, jv slice, int* pstart, int* pend) {
jv_free(end_jv);
return 0;
} else {
double dstart = jv_number_value(start_jv);
double dend = jv_number_value(end_jv);
if (dstart < 0) dstart += len;
if (dend < 0) dend += len;
if (dstart < 0) dstart = 0;
if (dstart > len) dstart = len;
int start = (int)dstart;
int end = (dend > len) ? len : (int)dend;
// Ends are exclusive but e.g. 1 < 1.5 so :1.5 should be :2 not :1
if(end < dend) end += 1;
int start = (int)jv_number_value(start_jv);
int end = (int)jv_number_value(end_jv);
if (start < 0) start = len + start;
if (end < 0) end = len + end;
if (start < 0) start = 0;
if (start > len) start = len;
if (end > len) end = len;
if (end < start) end = start;
assert(0 <= start && start <= end && end <= len);
@@ -56,15 +47,10 @@ jv jv_get(jv t, jv k) {
v = jv_null();
}
} else if (jv_get_kind(t) == JV_KIND_ARRAY && jv_get_kind(k) == JV_KIND_NUMBER) {
if(jv_is_integer(k)){
v = jv_array_get(t, (int)jv_number_value(k));
if (!jv_is_valid(v)) {
jv_free(v);
v = jv_null();
}
} else {
jv_free(t);
jv_free(k);
// FIXME: don't do lookup for noninteger index
v = jv_array_get(t, (int)jv_number_value(k));
if (!jv_is_valid(v)) {
jv_free(v);
v = jv_null();
}
} else if (jv_get_kind(t) == JV_KIND_ARRAY && jv_get_kind(k) == JV_KIND_OBJECT) {
@@ -75,18 +61,6 @@ jv jv_get(jv t, jv k) {
v = jv_invalid_with_msg(jv_string_fmt("Start and end indices of an array slice must be numbers"));
jv_free(t);
}
} else if (jv_get_kind(t) == JV_KIND_STRING && jv_get_kind(k) == JV_KIND_OBJECT) {
int start, end;
if (parse_slice(t, k, &start, &end)) {
v = jv_string_slice(t, start, end);
} else {
v = jv_invalid_with_msg(jv_string_fmt("Start and end indices of an string slice must be numbers"));
jv_free(t);
}
} else if (jv_get_kind(t) == JV_KIND_STRING && jv_get_kind(k) == JV_KIND_STRING) {
v = jv_string_indexes(t, k);
} else if (jv_get_kind(t) == JV_KIND_ARRAY && jv_get_kind(k) == JV_KIND_ARRAY) {
v = jv_array_indexes(t, k);
} else if (jv_get_kind(t) == JV_KIND_NULL &&
(jv_get_kind(k) == JV_KIND_STRING ||
jv_get_kind(k) == JV_KIND_NUMBER ||
@@ -95,20 +69,9 @@ jv jv_get(jv t, jv k) {
jv_free(k);
v = jv_null();
} else {
/*
* If k is a short string it's probably from a jq .foo expression or
* similar, in which case putting it in the invalid msg may help the
* user. The length 30 is arbitrary.
*/
if (jv_get_kind(k) == JV_KIND_STRING && jv_string_length_bytes(jv_copy(k)) < 30) {
v = jv_invalid_with_msg(jv_string_fmt("Cannot index %s with string \"%s\"",
jv_kind_name(jv_get_kind(t)),
jv_string_value(k)));
} else {
v = jv_invalid_with_msg(jv_string_fmt("Cannot index %s with %s",
jv_kind_name(jv_get_kind(t)),
jv_kind_name(jv_get_kind(k))));
}
v = jv_invalid_with_msg(jv_string_fmt("Cannot index %s with %s",
jv_kind_name(jv_get_kind(t)),
jv_kind_name(jv_get_kind(k))));
jv_free(t);
jv_free(k);
}
@@ -582,23 +545,21 @@ jv jv_group(jv objects, jv keys) {
int n = jv_array_length(jv_copy(objects));
struct sort_entry* entries = sort_items(objects, keys);
jv ret = jv_array();
if (n > 0) {
jv curr_key = entries[0].key;
jv group = jv_array_append(jv_array(), entries[0].object);
for (int i = 1; i < n; i++) {
if (jv_equal(jv_copy(curr_key), jv_copy(entries[i].key))) {
jv_free(entries[i].key);
} else {
jv_free(curr_key);
curr_key = entries[i].key;
ret = jv_array_append(ret, group);
group = jv_array();
}
group = jv_array_append(group, entries[i].object);
jv curr_key = entries[0].key;
jv group = jv_array_append(jv_array(), entries[0].object);
for (int i = 1; i < n; i++) {
if (jv_equal(jv_copy(curr_key), jv_copy(entries[i].key))) {
jv_free(entries[i].key);
} else {
jv_free(curr_key);
curr_key = entries[i].key;
ret = jv_array_append(ret, group);
group = jv_array();
}
jv_free(curr_key);
ret = jv_array_append(ret, group);
group = jv_array_append(group, entries[i].object);
}
jv_free(curr_key);
ret = jv_array_append(ret, group);
jv_mem_free(entries);
return ret;
}
+20
View File
@@ -0,0 +1,20 @@
#ifndef JV_AUX_H
#define JV_AUX_H
#include "jv.h"
jv jv_get(jv t, jv k);
jv jv_set(jv t, jv k, jv v);
jv jv_has(jv t, jv k);
jv jv_setpath(jv root, jv path, jv value);
jv jv_getpath(jv root, jv path);
jv jv_delpaths(jv root, jv paths);
jv jv_keys(jv /*object or array*/);
int jv_cmp(jv, jv);
jv jv_group(jv objects, jv keys);
jv jv_sort(jv objects, jv keys);
#endif
+2 -1
View File
@@ -187,6 +187,7 @@
* used for input more than STRTOD_DIGLIM digits long (default 40).
*/
#define IEEE_8087
#define NO_ERRNO
#define NO_HEX_FP
#define No_Hex_NaN
@@ -4224,7 +4225,7 @@ jvp_dtoa
while((*b++ = *s++));
goto done0;
}
if (decpt <= -4 || decpt > se - s + 15) {
if (decpt <= -4 || decpt > se - s + 5) {
*b++ = *s++;
if (*s) {
*b++ = '.';
+1 -1
View File
@@ -17,6 +17,6 @@ double jvp_strtod(struct dtoa_context* C, const char* s, char** se);
char* jvp_dtoa(struct dtoa_context* C, double dd, int mode, int ndigits, int *decpt, int *sign, char **rve);
void jvp_freedtoa(struct dtoa_context* C, char *s);
#define JVP_DTOA_FMT_MAX_LEN 64
#define JVP_DTOA_FMT_MAX_LEN 32
char* jvp_dtoa_fmt(struct dtoa_context* C, register char *b, double x);
#endif
-46
View File
@@ -1,46 +0,0 @@
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "jv.h"
jv jv_load_file(const char* filename, int raw) {
FILE* file = fopen(filename, "r");
struct jv_parser* parser;
jv data;
if (!file) {
return jv_invalid_with_msg(jv_string_fmt("Could not open %s: %s",
filename,
strerror(errno)));
}
if (raw) {
data = jv_string("");
} else {
data = jv_array();
parser = jv_parser_new(0);
}
while (!feof(file) && !ferror(file)) {
char buf[4096];
size_t n = fread(buf, 1, sizeof(buf), file);
if (raw) {
data = jv_string_concat(data, jv_string_sized(buf, (int)n));
} else {
jv_parser_set_buf(parser, buf, n, !feof(file));
jv value;
while (jv_is_valid((value = jv_parser_next(parser))))
data = jv_array_append(data, value);
jv_free(value);
}
}
if (!raw)
jv_parser_free(parser);
int badread = ferror(file);
fclose(file);
if (badread) {
jv_free(data);
return jv_invalid_with_msg(jv_string_fmt("Error reading from %s",
filename));
}
return data;
}
+5 -45
View File
@@ -1,12 +1,11 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include "jv.h"
#include "jv_dtoa.h"
#include "jv_parse.h"
#include "jv_unicode.h"
#include "jv_alloc.h"
#include "jv_dtoa.h"
typedef const char* presult;
@@ -17,35 +16,7 @@ typedef const char* presult;
#define pfunc presult
#endif
struct jv_parser {
const char* curr_buf;
int curr_buf_length;
int curr_buf_pos;
int curr_buf_is_partial;
unsigned bom_strip_position;
jv* stack;
int stackpos;
int stacklen;
jv next;
char* tokenbuf;
int tokenpos;
int tokenlen;
int line, column;
struct dtoa_context dtoa;
enum {
JV_PARSER_NORMAL,
JV_PARSER_STRING,
JV_PARSER_STRING_ESCAPE
} st;
};
static void parser_init(struct jv_parser* p) {
void jv_parser_init(struct jv_parser* p) {
p->stack = 0;
p->stacklen = p->stackpos = 0;
p->next = jv_invalid();
@@ -60,7 +31,7 @@ static void parser_init(struct jv_parser* p) {
jvp_dtoa_context_init(&p->dtoa);
}
static void parser_free(struct jv_parser* p) {
void jv_parser_free(struct jv_parser* p) {
jv_free(p->next);
for (int i=0; i<p->stackpos; i++)
jv_free(p->stack[i]);
@@ -370,17 +341,6 @@ static pfunc scan(struct jv_parser* p, char ch, jv* out) {
return answer;
}
struct jv_parser* jv_parser_new(int flags) {
struct jv_parser* p = jv_mem_alloc(sizeof(struct jv_parser));
parser_init(p);
return p;
}
void jv_parser_free(struct jv_parser* p) {
parser_free(p);
jv_mem_free(p);
}
static const unsigned char UTF8_BOM[] = {0xEF,0xBB,0xBF};
void jv_parser_set_buf(struct jv_parser* p, const char* buf, int length, int is_partial) {
@@ -444,7 +404,7 @@ jv jv_parser_next(struct jv_parser* p) {
jv jv_parse_sized(const char* string, int length) {
struct jv_parser parser;
parser_init(&parser);
jv_parser_init(&parser);
jv_parser_set_buf(&parser, string, length, 0);
jv value = jv_parser_next(&parser);
if (jv_is_valid(value)) {
@@ -469,7 +429,7 @@ jv jv_parse_sized(const char* string, int length) {
jv_free(value);
value = jv_invalid_with_msg(jv_string("Expected JSON value"));
}
parser_free(&parser);
jv_parser_free(&parser);
if (!jv_is_valid(value) && jv_invalid_has_msg(jv_copy(value))) {
jv msg = jv_invalid_get_msg(value);
+37
View File
@@ -0,0 +1,37 @@
#ifndef JV_PARSE_H
#define JV_PARSE_H
#include "jv_dtoa.h"
struct jv_parser {
const char* curr_buf;
int curr_buf_length;
int curr_buf_pos;
int curr_buf_is_partial;
unsigned bom_strip_position;
jv* stack;
int stackpos;
int stacklen;
jv next;
char* tokenbuf;
int tokenpos;
int tokenlen;
int line, column;
struct dtoa_context dtoa;
enum {
JV_PARSER_NORMAL,
JV_PARSER_STRING,
JV_PARSER_STRING_ESCAPE
} st;
};
void jv_parser_init(struct jv_parser* p);
void jv_parser_free(struct jv_parser* p);
void jv_parser_set_buf(struct jv_parser* p, const char* buf, int length, int is_partial);
jv jv_parser_next(struct jv_parser* p);
#endif
+3 -42
View File
@@ -2,7 +2,6 @@
#include <stdio.h>
#include <float.h>
#include <string.h>
#include <assert.h>
#include "jv_dtoa.h"
#include "jv_unicode.h"
@@ -195,34 +194,7 @@ static void jv_dump_term(struct dtoa_context* C, jv x, int flags, int indent, FI
put_space(indent+INDENT, F, S);
}
int first = 1;
int i = 0;
jv keyset = jv_null();
while (1) {
jv key, value;
if (flags & JV_PRINT_SORTED) {
if (first) {
keyset = jv_keys(jv_copy(x));
i = 0;
} else {
i++;
}
if (i >= jv_array_length(jv_copy(keyset))) {
jv_free(keyset);
break;
}
key = jv_array_get(jv_copy(keyset), i);
value = jv_object_get(jv_copy(x), jv_copy(key));
} else {
if (first) {
i = jv_object_iter(x);
} else {
i = jv_object_iter_next(x, i);
}
if (!jv_object_iter_valid(x, i)) break;
key = jv_object_iter_key(x, i);
value = jv_object_iter_value(x, i);
}
jv_object_foreach(x, key, value) {
if (!first) {
if (flags & JV_PRINT_PRETTY){
put_str(",\n", F, S);
@@ -260,24 +232,13 @@ static void jv_dump_term(struct dtoa_context* C, jv x, int flags, int indent, FI
}
}
void jv_dumpf(jv x, FILE *f, int flags) {
void jv_dump(jv x, int flags) {
struct dtoa_context C;
jvp_dtoa_context_init(&C);
jv_dump_term(&C, x, flags, 0, f, 0);
jv_dump_term(&C, x, flags, 0, stdout, 0);
jvp_dtoa_context_free(&C);
}
void jv_dump(jv x, int flags) {
jv_dumpf(x, stdout, flags);
}
void jv_show(jv x, int flags) {
if (flags == -1)
flags = JV_PRINT_PRETTY | JV_PRINT_COLOUR;
jv_dumpf(jv_copy(x), stderr, flags);
fflush(stderr);
}
jv jv_dump_string(jv x, int flags) {
struct dtoa_context C;
jvp_dtoa_context_init(&C);
+17 -49
View File
@@ -3,67 +3,35 @@
#include "jv_unicode.h"
#include "jv_utf8_tables.h"
const char* jvp_utf8_next(const char* in, const char* end, int* codepoint_ret) {
assert(in <= end);
const char* jvp_utf8_next(const char* in, const char* end, int* codepoint) {
if (in == end) {
codepoint = 0;
return 0;
}
int codepoint = -1;
unsigned char first = (unsigned char)in[0];
int length = utf8_coding_length[first];
if ((first & 0x80) == 0) {
/* Fast-path for ASCII */
codepoint = first;
length = 1;
} else if (length == 0 || length == UTF8_CONTINUATION_BYTE) {
/* Bad single byte - either an invalid byte or an out-of-place continuation byte */
length = 1;
} else if (in + length > end) {
/* String ends before UTF8 sequence ends */
length = end - in;
} else {
codepoint = ((unsigned)in[0]) & utf8_coding_bits[first];
for (int i=1; i<length; i++) {
unsigned ch = (unsigned char)in[i];
if (utf8_coding_length[ch] != UTF8_CONTINUATION_BYTE){
/* Invalid UTF8 sequence - not followed by the right number of continuation bytes */
codepoint = -1;
length = i;
break;
}
codepoint = (codepoint << 6) | (ch & 0x3f);
}
if (codepoint < utf8_first_codepoint[length]) {
/* Overlong UTF8 sequence */
codepoint = -1;
}
if (0xD800 <= codepoint && codepoint <= 0xDFFF) {
/* Surrogate codepoints can't be encoded in UTF8 */
codepoint = -1;
}
if (codepoint > 0x10FFFF) {
/* Outside Unicode range */
codepoint = -1;
}
if (length == 0 || length == UTF8_CONTINUATION_BYTE || in + length > end) {
*codepoint = -1;
return 0;
}
*codepoint = ((unsigned)in[0]) & utf8_coding_bits[first];
for (int i=1; i<length; i++) {
int ch = (unsigned char)in[i];
if (utf8_coding_length[(unsigned char)in[i]] != UTF8_CONTINUATION_BYTE){
*codepoint = -1;
return 0;
}
*codepoint = (*codepoint << 6) | (ch & 0x3f);
}
assert(length > 0);
*codepoint_ret = codepoint;
return in + length;
}
int jvp_utf8_is_valid(const char* in, const char* end) {
int codepoint;
int jvp_utf8_verify(const char* in, const char* end) {
int codepoint = 0;
while ((in = jvp_utf8_next(in, end, &codepoint))) {
if (codepoint == -1) return 0;
}
return 1;
}
int jvp_utf8_decode_length(char startchar) {
if ((startchar & 0x80) == 0) return 1;
else if ((startchar & 0xC0) == 0xC0) return 2;
else if ((startchar & 0xE0) == 0xE0) return 3;
else return 4;
return codepoint != -1;
}
int jvp_utf8_encode_length(int codepoint) {
+1 -1
View File
@@ -2,7 +2,7 @@
#define JV_UNICODE_H
const char* jvp_utf8_next(const char* in, const char* end, int* codepoint);
int jvp_utf8_is_valid(const char* in, const char* end);
int jvp_utf8_decode_length(char startchar);
-2
View File
@@ -33,5 +33,3 @@ static const unsigned char utf8_coding_bits[] =
0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f,
0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f,
0x07, 0x07, 0x07, 0x07, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
static const int utf8_first_codepoint[] =
{0x00, 0x00, 0x80, 0x800, 0x10000};
+1 -5
View File
@@ -1,5 +1,4 @@
%{
#include <assert.h>
#include "jv_alloc.h"
#include "compile.h"
@@ -57,12 +56,10 @@ struct lexer_param;
"-=" { return SETMINUS; }
"*=" { return SETMULT; }
"/=" { return SETDIV; }
"%=" { return SETMOD; }
"//=" { return SETDEFINEDOR; }
"<=" { return LESSEQ; }
">=" { return GREATEREQ; }
".." { return REC; }
"."|"?"|"="|";"|","|":"|"|"|"+"|"-"|"*"|"/"|"%"|"\$"|"<"|">" { return yytext[0];}
"."|"="|";"|","|":"|"|"|"+"|"-"|"*"|"/"|"\$"|"<"|">" { return yytext[0];}
"["|"{"|"(" {
return enter(yytext[0], YY_START, yyscanner);
@@ -111,7 +108,6 @@ struct lexer_param;
[a-zA-Z_][a-zA-Z_0-9]* { yylval->literal = jv_string(yytext); return IDENT;}
\.[a-zA-Z_][a-zA-Z_0-9]* { yylval->literal = jv_string(yytext+1); return FIELD;}
[ \n\t]+ {}
-34
View File
@@ -1,34 +0,0 @@
LIBM_DD(acos)
LIBM_DD(acosh)
LIBM_DD(asin)
LIBM_DD(asinh)
LIBM_DD(atan)
LIBM_DD(atanh)
LIBM_DD(cbrt)
LIBM_DD(cos)
LIBM_DD(cosh)
LIBM_DD(exp2)
LIBM_DD(exp)
LIBM_DD(floor)
LIBM_DD(j0)
LIBM_DD(j1)
LIBM_DD(log10)
LIBM_DD(log2)
LIBM_DD(log)
LIBM_DD(sin)
LIBM_DD(sinh)
LIBM_DD(sqrt)
LIBM_DD(tan)
LIBM_DD(tanh)
LIBM_DD(tgamma)
LIBM_DD(y0)
LIBM_DD(y1)
/* LIBM_DID(jn) */
/* LIBM_DID(yn) */
/* LIBM_DDD(pow) */
/* LIBM_DDD(atan2) */
/* LIBM_DDD(hypot) */
/* LIBM_DDD(remainder) */
/* LIBM_DDI(scalbn) */
/* LIBM_DDIP(lgamma_r) */
-103
View File
@@ -1,103 +0,0 @@
#include <assert.h>
#include <errno.h>
#include <stdarg.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include "jq.h"
#include "jv_alloc.h"
#include "locfile.h"
void locfile_init(struct locfile* l, jq_state *jq, const char* data, int length) {
l->jq = jq;
l->data = data;
l->length = length;
l->nlines = 1;
for (int i=0; i<length; i++) {
if (data[i] == '\n') l->nlines++;
}
l->linemap = jv_mem_alloc(sizeof(int) * (l->nlines + 1));
l->linemap[0] = 0;
int line = 1;
for (int i=0; i<length; i++) {
if (data[i] == '\n') {
l->linemap[line] = i+1; // at start of line, not of \n
line++;
}
}
l->linemap[l->nlines] = length+1; // virtual last \n
}
void locfile_free(struct locfile* l) {
jv_mem_free(l->linemap);
}
static int locfile_get_line(struct locfile* l, int pos) {
assert(pos < l->length);
int line = 1;
while (l->linemap[line] <= pos) line++; // == if pos at start (before, never ==, because pos never on \n)
assert(line-1 < l->nlines);
return line-1;
}
static int locfile_line_length(struct locfile* l, int line) {
assert(line < l->nlines);
return l->linemap[line+1] - l->linemap[line] -1; // -1 to omit \n
}
void locfile_locate(struct locfile* l, location loc, const char* fmt, ...) {
jq_err_cb cb;
void *cb_data;
va_list fmtargs;
va_start(fmtargs, fmt);
int startline;
int offset;
if (loc.start != -1) {
startline = locfile_get_line(l, loc.start);
offset = l->linemap[startline];
}
jq_get_error_cb(l->jq, &cb, &cb_data);
jv m1 = jv_string_vfmt(fmt, fmtargs);
if (!jv_is_valid(m1)) {
jv_free(m1);
goto enomem;
}
jv m2;
if (loc.start == -1) {
m2 = jv_string_fmt("%s\n<unknown location>", jv_string_value(m1));
if (cb)
cb(cb_data, m2);
else
fprintf(stderr, "%s", jv_string_value(m2));
jv_free(m1);
jv_free(m2);
return;
}
m2 = jv_string_fmt("%s\n%.*s%*s", jv_string_value(m1),
locfile_line_length(l, startline), l->data + offset,
loc.start - offset, "");
jv_free(m1);
if (!jv_is_valid(m2)) {
jv_free(m2);
goto enomem;
}
if (cb)
cb(cb_data, m2);
else
fprintf(stderr, "%s", jv_string_value(m2));
jv_free(m2);
return;
enomem:
if (cb != NULL)
cb(cb_data, jv_invalid());
else if (errno == ENOMEM || errno == 0)
fprintf(stderr, "Error formatting jq compilation error: %s", strerror(errno ? errno : ENOMEM));
else
fprintf(stderr, "Error formatting jq compilation error: %s", strerror(errno));
return;
}
+60 -8
View File
@@ -1,8 +1,10 @@
#ifndef _LOCFILE_H
#define _LOCFILE_H
#include "jq.h"
#include <stdlib.h>
#include <stdio.h>
#include <assert.h>
#include <stdarg.h>
#include "jv_alloc.h"
typedef struct {
int start, end;
} location;
@@ -14,14 +16,64 @@ struct locfile {
int length;
int* linemap;
int nlines;
char *error;
jq_state *jq;
};
void locfile_init(struct locfile* l, jq_state *jq, const char* data, int length);
static void locfile_init(struct locfile* l, const char* data, int length) {
l->data = data;
l->length = length;
l->nlines = 1;
for (int i=0; i<length; i++) {
if (data[i] == '\n') l->nlines++;
}
l->linemap = jv_mem_alloc(sizeof(int) * (l->nlines + 1));
l->linemap[0] = 0;
int line = 1;
for (int i=0; i<length; i++) {
if (data[i] == '\n') {
l->linemap[line] = i;
line++;
}
}
l->linemap[l->nlines] = length;
}
void locfile_free(struct locfile* l);
static void locfile_free(struct locfile* l) {
jv_mem_free(l->linemap);
}
void locfile_locate(struct locfile* l, location loc, const char* fmt, ...);
static int locfile_get_line(struct locfile* l, int pos) {
assert(pos < l->length);
int line = 0;
while (l->linemap[line+1] < pos) line++;
assert(line < l->nlines);
return line;
}
static int locfile_line_length(struct locfile* l, int line) {
assert(line < l->nlines);
return l->linemap[line+1] - l->linemap[line];
}
static void locfile_locate(struct locfile* l, location loc, const char* fmt, ...) {
va_list fmtargs;
va_start(fmtargs, fmt);
vfprintf(stderr, fmt, fmtargs);
va_end(fmtargs);
fprintf(stderr, "\n");
if (loc.start == -1) {
fprintf(stderr, "<unknown location>\n");
return;
}
int startline = locfile_get_line(l, loc.start);
int offset = l->linemap[startline];
fprintf(stderr, "%.*s\n", locfile_line_length(l, startline), l->data + offset);
fprintf(stderr, "%*s", loc.start - offset, "");
for (int i = loc.start;
i < loc.end && i < offset + locfile_line_length(l, startline);
i++){
fprintf(stderr, "^");
}
fprintf(stderr, "\n");
}
#endif
+116 -229
View File
@@ -1,4 +1,3 @@
#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
#include <string.h>
@@ -6,44 +5,29 @@
#include <unistd.h>
#include "compile.h"
#include "jv.h"
#include "jq.h"
#include "jv_parse.h"
#include "execute.h"
#include "config.h" /* Autoconf generated header file */
#include "jv_alloc.h"
#include "version.h"
int jq_testsuite(int argc, char* argv[]);
static const char* progname;
/*
* For a longer help message we could use a better option parsing
* strategy, one that lets stack options.
*/
static void usage(int code) {
fprintf(stderr, "\njq - commandline JSON processor [version %s]\n", JQ_VERSION);
static void usage() {
fprintf(stderr, "\njq - commandline JSON processor [version %s]\n", PACKAGE_VERSION);
fprintf(stderr, "Usage: %s [options] <jq filter> [file...]\n\n", progname);
fprintf(stderr, "\tjq is a tool for processing JSON inputs, applying the\n");
fprintf(stderr, "\tgiven filter to its JSON text inputs and producing the\n");
fprintf(stderr, "\tfilter's results as JSON on standard output.\n");
fprintf(stderr, "\tThe simplest filter is ., which is the identity filter,\n");
fprintf(stderr, "\tcopying jq's input to its output.\n");
fprintf(stderr, "\tFor more advanced filters see the jq(1) manpage (\"man jq\")\n");
fprintf(stderr, "\tand/or http://stedolan.github.com/jq\n\n");
fprintf(stderr, "\tSome of the options include:\n");
fprintf(stderr, "\t -h\t\tthis message;\n");
fprintf(stderr, "\t -c\t\tcompact instead of pretty-printed output;\n");
fprintf(stderr, "\t -s\t\tread all inputs into an array; apply filter to it;\n");
fprintf(stderr, "\t -r\t\toutput raw strings, not JSON texts;\n");
fprintf(stderr, "\t -R\t\tread raw strings, not JSON texts;\n");
fprintf(stderr, "\t -arg a v\tset variable $a to value <v>;\n");
fprintf(stderr, "\t -argfile a f\tset variable $a to JSON texts read from <f>;\n");
fprintf(stderr, "\tSee the manpage for more options.\n");
exit(code);
fprintf(stderr, "For a description of the command line options and\n");
fprintf(stderr, "how to write jq filters (and why you might want to)\n");
fprintf(stderr, "see the jq manpage, or the online documentation at\n");
fprintf(stderr, "http://stedolan.github.io/jq\n\n");
exit(1);
}
static void die() {
fprintf(stderr, "Use %s --help for help with command-line options,\n", progname);
fprintf(stderr, "or see the jq manpage, or online docs at http://stedolan.github.com/jq\n");
exit(2);
fprintf(stderr, "or see the jq documentation at http://stedolan.github.io/jq\n");
exit(1);
}
@@ -53,51 +37,39 @@ static int isoptish(const char* text) {
return text[0] == '-' && (text[1] == '-' || isalpha(text[1]));
}
static int isoption(const char* text, char shortopt, const char* longopt, size_t *short_opts) {
if (text[0] != '-' || text[1] == '-')
*short_opts = 0;
static int isoption(const char* text, char shortopt, const char* longopt) {
if (text[0] != '-') return 0;
// check long option
if (strlen(text) == 2 && text[1] == shortopt) return 1;
if (text[1] == '-' && !strcmp(text+2, longopt)) return 1;
else if (text[1] == '-') return 0;
// must be short option; check it and...
if (!shortopt) return 0;
if (strchr(text, shortopt) != NULL) {
(*short_opts)++; // ...count it (for option stacking)
return 1;
}
return 0;
}
enum {
SLURP = 1,
RAW_INPUT = 2,
PROVIDE_NULL = 4,
RAW_OUTPUT = 8,
COMPACT_OUTPUT = 16,
ASCII_OUTPUT = 32,
COLOUR_OUTPUT = 64,
NO_COLOUR_OUTPUT = 128,
SORTED_OUTPUT = 256,
FROM_FILE = 512,
RAW_NO_LF = 1024,
UNBUFFERED_OUTPUT = 2048,
EXIT_STATUS = 4096,
SLURP = 1,
RAW_INPUT = 2,
PROVIDE_NULL = 4,
RAW_OUTPUT = 8,
COMPACT_OUTPUT = 16,
ASCII_OUTPUT = 32,
COLOUR_OUTPUT = 64,
NO_COLOUR_OUTPUT = 128,
FROM_FILE = 256,
/* debugging only */
DUMP_DISASM = 8192,
DUMP_DISASM = 2048,
};
static int options = 0;
static struct bytecode* bc;
static int process(jq_state *jq, jv value, int flags) {
int ret = 14; // No valid results && -e -> exit(4)
jq_start(jq, value, flags);
static void process(jv value, int flags) {
jq_state *jq = NULL;
jq_init(bc, value, &jq, flags);
jv result;
while (jv_is_valid(result = jq_next(jq))) {
if ((options & RAW_OUTPUT) && jv_get_kind(result) == JV_KIND_STRING) {
fwrite(jv_string_value(result), 1, jv_string_length_bytes(jv_copy(result)), stdout);
ret = 0;
jv_free(result);
} else {
int dumpopts;
@@ -108,28 +80,43 @@ static int process(jq_state *jq, jv value, int flags) {
#else
dumpopts = isatty(fileno(stdout)) ? JV_PRINT_COLOUR : 0;
#endif
if (options & SORTED_OUTPUT) dumpopts |= JV_PRINT_SORTED;
if (!(options & COMPACT_OUTPUT)) dumpopts |= JV_PRINT_PRETTY;
if (options & ASCII_OUTPUT) dumpopts |= JV_PRINT_ASCII;
if (options & COLOUR_OUTPUT) dumpopts |= JV_PRINT_COLOUR;
if (options & NO_COLOUR_OUTPUT) dumpopts &= ~JV_PRINT_COLOUR;
if (jv_get_kind(result) == JV_KIND_FALSE || jv_get_kind(result) == JV_KIND_NULL)
ret = 11;
else
ret = 0;
jv_dump(result, dumpopts);
}
if (!(options & RAW_NO_LF))
printf("\n");
if (options & UNBUFFERED_OUTPUT)
fflush(stdout);
printf("\n");
}
jv_free(result);
return ret;
jq_teardown(&jq);
}
static jv slurp_file(const char* filename) {
FILE* file = fopen(filename, "r");
if (!file) {
return jv_invalid_with_msg(jv_string_fmt("Could not open %s: %s",
filename,
strerror(errno)));
}
jv data = jv_string("");
while (!feof(file) && !ferror(file)) {
char buf[4096];
size_t n = fread(buf, 1, sizeof(buf), file);
data = jv_string_concat(data, jv_string_sized(buf, (int)n));
}
int badread = ferror(file);
fclose(file);
if (badread) {
jv_free(data);
return jv_invalid_with_msg(jv_string_fmt("Error reading from %s",
filename));
}
return data;
}
FILE* current_input;
const char** input_filenames = NULL;
const char** input_filenames;
int ninput_files;
int next_input_idx;
static int read_more(char* buf, size_t size) {
@@ -157,21 +144,11 @@ static int read_more(char* buf, size_t size) {
}
int main(int argc, char* argv[]) {
jq_state *jq = NULL;
int ret = 0;
int compiled = 0;
if (argc) progname = argv[0];
if (argc > 1 && !strcmp(argv[1], "--run-tests")) {
return jq_testsuite(argc, argv);
}
jq = jq_init();
if (jq == NULL) {
perror("malloc");
ret = 2;
goto out;
return jq_testsuite(argc - 1, argv + 1);
}
const char* program = 0;
@@ -179,13 +156,12 @@ int main(int argc, char* argv[]) {
ninput_files = 0;
int further_args_are_files = 0;
int jq_flags = 0;
size_t short_opts = 0;
jv program_arguments = jv_array();
for (int i=1; i<argc; i++, short_opts = 0) {
for (int i=1; i<argc; i++) {
if (further_args_are_files) {
input_filenames[ninput_files++] = argv[i];
} else if (!strcmp(argv[i], "--")) {
if (!program) usage(2);
if (!program) usage();
further_args_are_files = 1;
} else if (!isoptish(argv[i])) {
if (program) {
@@ -193,131 +169,49 @@ int main(int argc, char* argv[]) {
} else {
program = argv[i];
}
} else {
if (isoption(argv[i], 's', "slurp", &short_opts)) {
options |= SLURP;
if (!short_opts) continue;
}
if (isoption(argv[i], 'r', "raw-output", &short_opts)) {
options |= RAW_OUTPUT;
if (!short_opts) continue;
}
if (isoption(argv[i], 'c', "compact-output", &short_opts)) {
options |= COMPACT_OUTPUT;
if (!short_opts) continue;
}
if (isoption(argv[i], 'C', "color-output", &short_opts)) {
options |= COLOUR_OUTPUT;
if (!short_opts) continue;
}
if (isoption(argv[i], 'M', "monochrome-output", &short_opts)) {
options |= NO_COLOUR_OUTPUT;
if (!short_opts) continue;
}
if (isoption(argv[i], 'a', "ascii-output", &short_opts)) {
options |= ASCII_OUTPUT;
if (!short_opts) continue;
}
if (isoption(argv[i], 0, "unbuffered", &short_opts)) {
options |= UNBUFFERED_OUTPUT;
if (!short_opts) continue;
}
if (isoption(argv[i], 'S', "sort-keys", &short_opts)) {
options |= SORTED_OUTPUT;
if (!short_opts) continue;
}
if (isoption(argv[i], 'R', "raw-input", &short_opts)) {
options |= RAW_INPUT;
if (!short_opts) continue;
}
if (isoption(argv[i], 'n', "null-input", &short_opts)) {
options |= PROVIDE_NULL;
if (!short_opts) continue;
}
if (isoption(argv[i], 'f', "from-file", &short_opts)) {
options |= FROM_FILE;
if (!short_opts) continue;
}
if (isoption(argv[i], 'j', "join-output", &short_opts)) {
options |= RAW_OUTPUT | RAW_NO_LF;
if (!short_opts) continue;
}
if (isoption(argv[i], 'e', "exit-status", &short_opts)) {
options |= EXIT_STATUS;
if (!short_opts) continue;
}
if (isoption(argv[i], 0, "arg", &short_opts)) {
if (i >= argc - 2) {
fprintf(stderr, "%s: --arg takes two parameters (e.g. -a varname value)\n", progname);
die();
}
jv arg = jv_object();
arg = jv_object_set(arg, jv_string("name"), jv_string(argv[i+1]));
arg = jv_object_set(arg, jv_string("value"), jv_string(argv[i+2]));
program_arguments = jv_array_append(program_arguments, arg);
i += 2; // skip the next two arguments
if (!short_opts) continue;
}
if (isoption(argv[i], 0, "argfile", &short_opts)) {
if (i >= argc - 2) {
fprintf(stderr, "%s: --argfile takes two parameters (e.g. -a varname filename)\n", progname);
die();
}
jv arg = jv_object();
arg = jv_object_set(arg, jv_string("name"), jv_string(argv[i+1]));
jv data = jv_load_file(argv[i+2], 0);
if (!jv_is_valid(data)) {
data = jv_invalid_get_msg(data);
fprintf(stderr, "%s: Bad JSON in --argfile %s %s: %s\n", progname,
argv[i+1], argv[i+2], jv_string_value(data));
jv_free(data);
ret = 2;
goto out;
}
if (jv_get_kind(data) == JV_KIND_ARRAY && jv_array_length(jv_copy(data)) == 1)
data = jv_array_get(data, 0);
arg = jv_object_set(arg, jv_string("value"), data);
program_arguments = jv_array_append(program_arguments, arg);
i += 2; // skip the next two arguments
if (!short_opts) continue;
}
if (isoption(argv[i], 0, "debug-dump-disasm", &short_opts)) {
options |= DUMP_DISASM;
if (!short_opts) continue;
}
if (isoption(argv[i], 0, "debug-trace", &short_opts)) {
jq_flags |= JQ_DEBUG_TRACE;
if (!short_opts) continue;
}
if (isoption(argv[i], 'h', "help", &short_opts)) {
usage(0);
if (!short_opts) continue;
}
if (isoption(argv[i], 'V', "version", &short_opts)) {
printf("jq-%s\n", JQ_VERSION);
ret = 0;
goto out;
}
// check for unknown options... if this argument was a short option
if (strlen(argv[i]) != short_opts + 1) {
fprintf(stderr, "%s: Unknown option %s\n", progname, argv[i]);
} else if (isoption(argv[i], 's', "slurp")) {
options |= SLURP;
} else if (isoption(argv[i], 'r', "raw-output")) {
options |= RAW_OUTPUT;
} else if (isoption(argv[i], 'c', "compact-output")) {
options |= COMPACT_OUTPUT;
} else if (isoption(argv[i], 'C', "color-output")) {
options |= COLOUR_OUTPUT;
} else if (isoption(argv[i], 'M', "monochrome-output")) {
options |= NO_COLOUR_OUTPUT;
} else if (isoption(argv[i], 'a', "ascii-output")) {
options |= ASCII_OUTPUT;
} else if (isoption(argv[i], 'R', "raw-input")) {
options |= RAW_INPUT;
} else if (isoption(argv[i], 'n', "null-input")) {
options |= PROVIDE_NULL;
} else if (isoption(argv[i], 'f', "from-file")) {
options |= FROM_FILE;
} else if (isoption(argv[i], 0, "arg")) {
if (i >= argc - 2) {
fprintf(stderr, "%s: --arg takes two parameters (e.g. -a varname value)\n", progname);
die();
}
jv arg = jv_object();
arg = jv_object_set(arg, jv_string("name"), jv_string(argv[i+1]));
arg = jv_object_set(arg, jv_string("value"), jv_string(argv[i+2]));
program_arguments = jv_array_append(program_arguments, arg);
i += 2; // skip the next two arguments
} else if (isoption(argv[i], 0, "debug-dump-disasm")) {
options |= DUMP_DISASM;
} else if (isoption(argv[i], 0, "debug-trace")) {
jq_flags |= JQ_DEBUG_TRACE;
} else if (isoption(argv[i], 'h', "help")) {
usage();
} else if (isoption(argv[i], 'V', "version")) {
fprintf(stderr, "jq version %s\n", PACKAGE_VERSION);
return 0;
} else {
fprintf(stderr, "%s: Unknown option %s\n", progname, argv[i]);
die();
}
}
#if (!defined(WIN32) && defined(HAVE_ISATTY)) || defined(HAVE__ISATTY)
#if defined(HAVE__ISATTY) && defined(isatty)
#undef isatty
#define isatty _isatty
#endif
if (!program && isatty(STDOUT_FILENO) && !isatty(STDIN_FILENO))
program = ".";
#endif
if (!program) usage(2);
if (!program) usage();
if (ninput_files == 0) current_input = stdin;
if ((options & PROVIDE_NULL) && (options & (RAW_INPUT | SLURP))) {
@@ -326,31 +220,27 @@ int main(int argc, char* argv[]) {
}
if (options & FROM_FILE) {
jv data = jv_load_file(program, 1);
jv data = slurp_file(program);
if (!jv_is_valid(data)) {
data = jv_invalid_get_msg(data);
fprintf(stderr, "%s: %s\n", progname, jv_string_value(data));
jv_free(data);
ret = 2;
goto out;
return 1;
}
compiled = jq_compile_args(jq, jv_string_value(data), program_arguments);
bc = jq_compile_args(jv_string_value(data), program_arguments);
jv_free(data);
} else {
compiled = jq_compile_args(jq, program, program_arguments);
}
if (!compiled){
ret = 3;
goto out;
bc = jq_compile_args(program, program_arguments);
}
if (!bc) return 1;
if (options & DUMP_DISASM) {
jq_dump_disassembly(jq, 0);
dump_disassembly(0, bc);
printf("\n");
}
if (options & PROVIDE_NULL) {
ret = process(jq, jv_null(), jq_flags);
process(jv_null(), jq_flags);
} else {
jv slurped;
if (options & SLURP) {
@@ -360,7 +250,8 @@ int main(int argc, char* argv[]) {
slurped = jv_array();
}
}
struct jv_parser* parser = jv_parser_new(0);
struct jv_parser parser;
jv_parser_init(&parser);
char buf[4096];
while (read_more(buf, sizeof(buf))) {
if (options & RAW_INPUT) {
@@ -370,43 +261,39 @@ int main(int argc, char* argv[]) {
slurped = jv_string_concat(slurped, jv_string(buf));
} else {
if (buf[len-1] == '\n') buf[len-1] = 0;
ret = process(jq, jv_string(buf), jq_flags);
process(jv_string(buf), jq_flags);
}
}
} else {
jv_parser_set_buf(parser, buf, strlen(buf), !feof(stdin));
jv_parser_set_buf(&parser, buf, strlen(buf), !feof(stdin));
jv value;
while (jv_is_valid((value = jv_parser_next(parser)))) {
while (jv_is_valid((value = jv_parser_next(&parser)))) {
if (options & SLURP) {
slurped = jv_array_append(slurped, value);
} else {
ret = process(jq, value, jq_flags);
process(value, jq_flags);
}
}
if (jv_invalid_has_msg(jv_copy(value))) {
jv msg = jv_invalid_get_msg(value);
fprintf(stderr, "parse error: %s\n", jv_string_value(msg));
jv_free(msg);
ret = 4;
ret = 1;
break;
} else {
jv_free(value);
}
}
}
jv_parser_free(parser);
jv_parser_free(&parser);
if (ret != 0)
goto out;
if (options & SLURP) {
ret = process(jq, slurped, jq_flags);
process(slurped, jq_flags);
}
}
out:
jv_mem_free(input_filenames);
jq_teardown(&jq);
if (ret >= 10 && (options & EXIT_STATUS))
return ret - 10;
if (ret >= 10)
return 0;
bytecode_free(bc);
return ret;
}
+31
View File
@@ -0,0 +1,31 @@
#include "opcode.h"
// flags, length
#define NONE 0, 1
#define CONSTANT OP_HAS_CONSTANT, 2
#define VARIABLE (OP_HAS_VARIABLE | OP_HAS_BINDING), 3
#define BRANCH OP_HAS_BRANCH, 2
#define CFUNC (OP_HAS_CFUNC | OP_HAS_BINDING), 3
#define UFUNC (OP_HAS_UFUNC | OP_HAS_BINDING | OP_IS_CALL_PSEUDO), 4
#define DEFINITION (OP_IS_CALL_PSEUDO | OP_HAS_BINDING), 0
#define CLOSURE_REF_IMM (OP_IS_CALL_PSEUDO | OP_HAS_BINDING), 2
#define OP(name, imm, in, out) \
{name, #name, imm, in, out},
static const struct opcode_description opcode_descriptions[] = {
#include "opcode_list.h"
};
static const struct opcode_description invalid_opcode_description = {
-1, "#INVALID", 0, 0, 0, 0
};
const struct opcode_description* opcode_describe(opcode op) {
if ((int)op >= 0 && (int)op < NUM_OPCODES) {
return &opcode_descriptions[op];
} else {
return &invalid_opcode_description;
}
}
+41
View File
@@ -0,0 +1,41 @@
#ifndef OPCODE_H
#define OPCODE_H
#include <assert.h>
typedef enum {
#define OP(name, imm, in, out) name,
#include "opcode_list.h"
#undef OP
} opcode;
enum {
NUM_OPCODES =
#define OP(name, imm, in, out) +1
#include "opcode_list.h"
#undef OP
};
enum {
OP_HAS_CONSTANT = 2,
OP_HAS_VARIABLE = 4,
OP_HAS_BRANCH = 8,
OP_HAS_CFUNC = 32,
OP_HAS_UFUNC = 64,
OP_IS_CALL_PSEUDO = 128,
OP_HAS_BINDING = 1024,
};
struct opcode_description {
opcode op;
const char* name;
int flags;
// length in 16-bit units
int length;
int stack_in, stack_out;
};
const struct opcode_description* opcode_describe(opcode op);
#endif
-3
View File
@@ -6,9 +6,7 @@ OP(LOADV, VARIABLE, 1, 1)
OP(LOADVN, VARIABLE, 1, 1)
OP(STOREV, VARIABLE, 1, 0)
OP(INDEX, NONE, 2, 1)
OP(INDEX_OPT, NONE, 2, 1)
OP(EACH, NONE, 1, 1)
OP(EACH_OPT, NONE, 1, 1)
OP(FORK, BRANCH, 0, 0)
OP(JUMP, BRANCH, 0, 0)
OP(JUMP_F,BRANCH, 1, 0)
@@ -27,7 +25,6 @@ OP(CALL_BUILTIN, CFUNC, -1, 1)
OP(CALL_JQ, UFUNC, 1, 1)
OP(RET, NONE, 1, 1)
OP(TAIL_CALL_JQ, UFUNC, 1, 1)
OP(CLOSURE_PARAM, DEFINITION, 0, 0)
OP(CLOSURE_REF, CLOSURE_REF_IMM, 0, 0)
+44 -179
View File
@@ -1,16 +1,16 @@
%{
#include <stdio.h>
#include <string.h>
#include <assert.h>
#include "compile.h"
#include "jv_alloc.h"
#define YYMALLOC jv_mem_alloc
#define YYFREE jv_mem_free
struct lexer_param;
%}
%code requires {
#include "locfile.h"
struct lexer_param;
#define YYLTYPE location
#define YYLLOC_DEFAULT(Loc, Rhs, N) \
do { \
@@ -47,12 +47,8 @@ struct lexer_param;
%token INVALID_CHARACTER
%token <literal> IDENT
%token <literal> FIELD
%token <literal> LITERAL
%token <literal> FORMAT
%token Q "?"
%token REC ".."
%token SETMOD "%="
%token EQ "=="
%token NEQ "!="
%token DEFINEDOR "//"
@@ -86,12 +82,12 @@ struct lexer_param;
%right '|'
%left ','
%right "//"
%nonassoc '=' SETPIPE SETPLUS SETMINUS SETMULT SETDIV SETMOD SETDEFINEDOR
%nonassoc '=' SETPIPE SETPLUS SETMINUS SETMULT SETDIV SETDEFINEDOR
%left OR
%left AND
%nonassoc NEQ EQ '<' '>' LESSEQ GREATEREQ
%left '+' '-'
%left '*' '/' '%'
%left '*' '/'
%type <blk> Exp Term MkDict MkDictPair ExpD ElseBody QQString FuncDef FuncDefs String
@@ -116,19 +112,25 @@ void yyerror(YYLTYPE* loc, block* answer, int* errors,
int yylex(YYSTYPE* yylval, YYLTYPE* yylloc, block* answer, int* errors,
struct locfile* locations, struct lexer_param* lexer_param_ptr) {
yyscan_t lexer = lexer_param_ptr->lexer;
int tok = jq_yylex(yylval, yylloc, lexer);
if ((tok == LITERAL || tok == QQSTRING_TEXT) && !jv_is_valid(yylval->literal)) {
jv msg = jv_invalid_get_msg(jv_copy(yylval->literal));
if (jv_get_kind(msg) == JV_KIND_STRING) {
FAIL(*yylloc, jv_string_value(msg));
while (1) {
int tok = jq_yylex(yylval, yylloc, lexer);
if (tok == INVALID_CHARACTER) {
FAIL(*yylloc, "Invalid character");
} else {
FAIL(*yylloc, "Invalid literal");
if ((tok == LITERAL || tok == QQSTRING_TEXT) && !jv_is_valid(yylval->literal)) {
jv msg = jv_invalid_get_msg(jv_copy(yylval->literal));
if (jv_get_kind(msg) == JV_KIND_STRING) {
FAIL(*yylloc, jv_string_value(msg));
} else {
FAIL(*yylloc, "Invalid literal");
}
jv_free(msg);
jv_free(yylval->literal);
yylval->literal = jv_null();
}
return tok;
}
jv_free(msg);
jv_free(yylval->literal);
yylval->literal = jv_null();
}
return tok;
}
static block gen_dictpair(block k, block v) {
@@ -139,11 +141,7 @@ static block gen_index(block obj, block key) {
return BLOCK(gen_subexp(key), obj, gen_op_simple(INDEX));
}
static block gen_index_opt(block obj, block key) {
return BLOCK(gen_subexp(key), obj, gen_op_simple(INDEX_OPT));
}
static block gen_slice_index(block obj, block start, block end, opcode idx_op) {
static block gen_slice_index(block obj, block start, block end) {
block key = BLOCK(gen_subexp(gen_const(jv_object())),
gen_subexp(gen_const(jv_string("start"))),
gen_subexp(start),
@@ -151,7 +149,7 @@ static block gen_slice_index(block obj, block start, block end, opcode idx_op) {
gen_subexp(gen_const(jv_string("end"))),
gen_subexp(end),
gen_op_simple(INSERT));
return BLOCK(key, obj, gen_op_simple(idx_op));
return BLOCK(key, obj, gen_op_simple(INDEX));
}
static block gen_binop(block a, block b, int op) {
@@ -161,7 +159,6 @@ static block gen_binop(block a, block b, int op) {
case '-': funcname = "_minus"; break;
case '*': funcname = "_multiply"; break;
case '/': funcname = "_divide"; break;
case '%': funcname = "_mod"; break;
case EQ: funcname = "_equal"; break;
case NEQ: funcname = "_notequal"; break;
case '<': funcname = "_less"; break;
@@ -179,22 +176,24 @@ static block gen_format(block a, jv fmt) {
}
static block gen_definedor_assign(block object, block val) {
block tmp = gen_op_var_fresh(STOREV, "tmp");
block tmp = block_bind(gen_op_var_unbound(STOREV, "tmp"),
gen_noop(), OP_HAS_VARIABLE);
return BLOCK(gen_op_simple(DUP),
val, tmp,
gen_call("_modify", BLOCK(gen_lambda(object),
gen_lambda(gen_definedor(gen_noop(),
gen_op_bound(LOADV, tmp))))));
gen_op_var_bound(LOADV, tmp))))));
}
static block gen_update(block object, block val, int optype) {
block tmp = gen_op_var_fresh(STOREV, "tmp");
block tmp = block_bind(gen_op_var_unbound(STOREV, "tmp"),
gen_noop(), OP_HAS_VARIABLE);
return BLOCK(gen_op_simple(DUP),
val,
tmp,
gen_call("_modify", BLOCK(gen_lambda(object),
gen_lambda(gen_binop(gen_noop(),
gen_op_bound(LOADV, tmp),
gen_op_var_bound(LOADV, tmp),
optype)))));
}
@@ -235,8 +234,8 @@ Term "as" '$' IDENT '|' Exp {
"if" Exp "then" Exp ElseBody {
$$ = gen_cond($2, $4, $5);
} |
"if" Exp "then" error {
FAIL(@$, "Possibly unterminated 'if' statement");
"if" Exp error {
FAIL(@$, "Possibly unterminated 'if' statment");
$$ = $2;
} |
@@ -304,18 +303,10 @@ Exp '/' Exp {
$$ = gen_binop($1, $3, '/');
} |
Exp '%' Exp {
$$ = gen_binop($1, $3, '%');
} |
Exp "/=" Exp {
$$ = gen_update($1, $3, '/');
} |
Exp SETMOD Exp {
$$ = gen_update($1, $3, '%');
} |
Exp "==" Exp {
$$ = gen_binop($1, $3, EQ);
} |
@@ -352,7 +343,7 @@ FuncDef:
"def" IDENT '(' IDENT ')' ':' Exp ';' {
$$ = gen_function(jv_string_value($2),
gen_param(jv_string_value($4)),
gen_op_block_unbound(CLOSURE_PARAM, jv_string_value($4)),
$7);
jv_free($2);
jv_free($4);
@@ -360,75 +351,16 @@ FuncDef:
"def" IDENT '(' IDENT ';' IDENT ')' ':' Exp ';' {
$$ = gen_function(jv_string_value($2),
BLOCK(gen_param(jv_string_value($4)),
gen_param(jv_string_value($6))),
BLOCK(gen_op_block_unbound(CLOSURE_PARAM, jv_string_value($4)),
gen_op_block_unbound(CLOSURE_PARAM, jv_string_value($6))),
$9);
jv_free($2);
jv_free($4);
jv_free($6);
} |
"def" IDENT '(' IDENT ';' IDENT ';' IDENT ')' ':' Exp ';' {
$$ = gen_function(jv_string_value($2),
BLOCK(gen_param(jv_string_value($4)),
gen_param(jv_string_value($6)),
gen_param(jv_string_value($8))),
$11);
jv_free($2);
jv_free($4);
jv_free($6);
jv_free($8);
} |
"def" IDENT '(' IDENT ';' IDENT ';' IDENT ';' IDENT ')' ':' Exp ';' {
$$ = gen_function(jv_string_value($2),
BLOCK(gen_param(jv_string_value($4)),
gen_param(jv_string_value($6)),
gen_param(jv_string_value($8)),
gen_param(jv_string_value($10))),
$13);
jv_free($2);
jv_free($4);
jv_free($6);
jv_free($8);
jv_free($10);
} |
"def" IDENT '(' IDENT ';' IDENT ';' IDENT ';' IDENT ';' IDENT ')' ':' Exp ';' {
$$ = gen_function(jv_string_value($2),
BLOCK(gen_param(jv_string_value($4)),
gen_param(jv_string_value($6)),
gen_param(jv_string_value($8)),
gen_param(jv_string_value($10)),
gen_param(jv_string_value($12))),
$15);
jv_free($2);
jv_free($4);
jv_free($6);
jv_free($8);
jv_free($10);
jv_free($12);
} |
"def" IDENT '(' IDENT ';' IDENT ';' IDENT ';' IDENT ';' IDENT ';' IDENT ')' ':' Exp ';' {
$$ = gen_function(jv_string_value($2),
BLOCK(gen_param(jv_string_value($4)),
gen_param(jv_string_value($6)),
gen_param(jv_string_value($8)),
gen_param(jv_string_value($10)),
gen_param(jv_string_value($12)),
gen_param(jv_string_value($14))),
$17);
jv_free($2);
jv_free($4);
jv_free($6);
jv_free($8);
jv_free($10);
jv_free($12);
jv_free($14);
}
String:
QQSTRING_START { $<literal>$ = jv_string("text"); } QQString QQSTRING_END {
$$ = $3;
@@ -464,9 +396,7 @@ ExpD:
ExpD '|' ExpD {
$$ = block_join($1, $3);
} |
'-' ExpD {
$$ = BLOCK($2, gen_call("_negate", gen_noop()));
} |
Term {
$$ = $1;
}
@@ -476,72 +406,27 @@ Term:
'.' {
$$ = gen_noop();
} |
REC {
$$ = gen_call("recurse", gen_noop());
Term '.' IDENT {
$$ = gen_index($1, gen_const($3));
} |
Term FIELD '?' {
$$ = gen_index_opt($1, gen_const($2));
'.' IDENT {
$$ = gen_index(gen_noop(), gen_const($2));
} |
FIELD '?' {
$$ = gen_index_opt(gen_noop(), gen_const($1));
} |
Term '.' String '?' {
$$ = gen_index_opt($1, $3);
} |
'.' String '?' {
$$ = gen_index_opt(gen_noop(), $2);
} |
Term FIELD {
$$ = gen_index($1, gen_const($2));
} |
FIELD {
$$ = gen_index(gen_noop(), gen_const($1));
} |
Term '.' String {
$$ = gen_index($1, $3);
} |
'.' String {
$$ = gen_index(gen_noop(), $2);
} |
'.' error {
FAIL(@$, "try .[\"field\"] instead of .field for unusually named fields");
$$ = gen_noop();
} |
'.' IDENT error {
jv_free($2);
FAIL(@$, "try .[\"field\"] instead of .field for unusually named fields");
$$ = gen_noop();
} |
/* FIXME: string literals */
Term '[' Exp ']' '?' {
$$ = gen_index_opt($1, $3);
} |
Term '[' Exp ']' {
$$ = gen_index($1, $3);
} |
Term '[' ']' '?' {
$$ = block_join($1, gen_op_simple(EACH_OPT));
} |
Term '[' ']' {
$$ = block_join($1, gen_op_simple(EACH));
} |
Term '[' Exp ':' Exp ']' '?' {
$$ = gen_slice_index($1, $3, $5, INDEX_OPT);
} |
Term '[' Exp ':' ']' '?' {
$$ = gen_slice_index($1, $3, gen_const(jv_null()), INDEX_OPT);
} |
Term '[' ':' Exp ']' '?' {
$$ = gen_slice_index($1, gen_const(jv_null()), $4, INDEX_OPT);
} |
Term '[' Exp ':' Exp ']' {
$$ = gen_slice_index($1, $3, $5, INDEX);
$$ = gen_slice_index($1, $3, $5);
} |
Term '[' Exp ':' ']' {
$$ = gen_slice_index($1, $3, gen_const(jv_null()), INDEX);
$$ = gen_slice_index($1, $3, gen_const(jv_null()));
} |
Term '[' ':' Exp ']' {
$$ = gen_slice_index($1, gen_const(jv_null()), $4, INDEX);
$$ = gen_slice_index($1, gen_const(jv_null()), $4);
} |
LITERAL {
$$ = gen_const($1);
@@ -565,7 +450,7 @@ FORMAT {
$$ = BLOCK(gen_subexp(gen_const(jv_object())), $2, gen_op_simple(POP));
} |
'$' IDENT {
$$ = gen_location(@$, gen_op_unbound(LOADV, jv_string_value($2)));
$$ = gen_location(@$, gen_op_var_unbound(LOADV, jv_string_value($2)));
jv_free($2);
} |
IDENT {
@@ -582,26 +467,6 @@ IDENT '(' Exp ';' Exp ')' {
$$ = gen_location(@1, $$);
jv_free($1);
} |
IDENT '(' Exp ';' Exp ';' Exp ')' {
$$ = gen_call(jv_string_value($1), BLOCK(gen_lambda($3), gen_lambda($5), gen_lambda($7)));
$$ = gen_location(@1, $$);
jv_free($1);
} |
IDENT '(' Exp ';' Exp ';' Exp ';' Exp ')' {
$$ = gen_call(jv_string_value($1), BLOCK(gen_lambda($3), gen_lambda($5), gen_lambda($7), gen_lambda($9)));
$$ = gen_location(@1, $$);
jv_free($1);
} |
IDENT '(' Exp ';' Exp ';' Exp ';' Exp ';' Exp ')' {
$$ = gen_call(jv_string_value($1), BLOCK(gen_lambda($3), gen_lambda($5), gen_lambda($7), gen_lambda($9), gen_lambda($11)));
$$ = gen_location(@1, $$);
jv_free($1);
} |
IDENT '(' Exp ';' Exp ';' Exp ';' Exp ';' Exp ';' Exp ')' {
$$ = gen_call(jv_string_value($1), BLOCK(gen_lambda($3), gen_lambda($5), gen_lambda($7), gen_lambda($9), gen_lambda($11), gen_lambda($13)));
$$ = gen_location(@1, $$);
jv_free($1);
} |
'(' error ')' { $$ = gen_noop(); } |
'[' error ']' { $$ = gen_noop(); } |
Term '[' error ']' { $$ = $1; } |
+8 -19
View File
@@ -13,30 +13,19 @@
set -e
cd `dirname "$0"`/../build
jobs=-j4
case "X$1" in
X-j*) jobs=$1; shift;;
esac
plat="$1"
[ -z "$plat" ] && exit 1
shift
case "$plat" in
*/*) echo "platform name must not be a path"; exit 1;;
*..*) echo "platform name must not be a path"; exit 1;;
*) plat=$PWD/$plat;;
esac
[ -d "$plat" ] || mkdir "$plat"
rm -rf "$plat/tmp"
mkdir "$plat/tmp"
cd "$plat/tmp"
../../../configure "$@"
make "$jobs" DESTDIR=$plat install
set -x
for jq in `find . -type f \( -name jq -o -name jq.exe \) -print`; do
cp "$jq" ..
done
rm -rf tmp
mkdir install_other
../../../configure \
--prefix="`pwd`/install_other" \
--bindir="`pwd`/.." \
"$@"
make install-binaries
cd ..
rm -rf tmp
-5
View File
@@ -1,5 +0,0 @@
#!/bin/sh
set -e
cd `dirname "$0"`
git rev-parse --verify -q jq-1.0 > /dev/null 2>&1
git describe --tags --match 'jq-*' --dirty | sed 's/^jq-//'
+2 -5
View File
@@ -9,14 +9,12 @@
if [ "clean" == "$1" ]; then
make distclean || echo "continuing..."
find config/m4 -type f \( -name libtool\* -o -name lt\* \) | xargs rm -f
find config -name m4 -prune -o -type f -print | xargs rm -f
rm -rf tmp autom4te.cache
rm -rf tmp autom4te.cache config
rm -f INSTALL Makefile.in aclocal.m4 configure config.h.in ChangeLog
rm -f jv_utf8_tables.gen.h lexer.c lexer.h parser.c parser.h
elif [ "superclean" == "$1" ]; then
# if autoconf errors during distcheck, it leaves files that need chmod'ing
ver=$(scripts/version|tr -d '\n')
ver=$(tr -d '\n' <VERSION)
if [ "x${ver}" != "x" ]; then
if [ -d jq-${ver} ]; then
chmod -R u+w jq-${ver}
@@ -28,7 +26,6 @@ else
autoreconf --install
./configure --prefix=/opt/junk
make check
[ -d tmp ] && mv tmp tmp-
mkdir tmp
make DESTDIR=./tmp install
make distcheck
+3 -310
View File
@@ -36,10 +36,6 @@ null
null
[]
{x: -1}
null
{"x": -1}
# The input line starts with a 0xFEFF (byte order mark) codepoint
# No, there is no reason to have a byte order mark in UTF8 text.
# But apparently people do, so jq shouldn't break on it.
@@ -67,27 +63,18 @@ null
"\"<>&'\\\"\""
"1,\"<>&'\"\"\""
"&lt;&gt;&amp;&apos;&quot;"
"%3C%3E%26'%22"
"%3c%3e%26'%22"
"'<>&'\\''\"'"
"PD4mJyI="
# regression test for #436
@base64
"foóbar\n"
"Zm/Ds2Jhcgo="
@uri
"\u03bc"
"%CE%BC"
"%ce%bc"
@html "<b>\(.)</b>"
"<script>hax</script>"
"<b>&lt;script&gt;hax&lt;/script&gt;</b>"
[.[]|tojson|fromjson]
["foo", 1, ["a", 1, "b", 2, {"foo":"bar"}]]
["foo",1,["a",1,"b",2,{"foo":"bar"}]]
#
# Dictionary construction syntax
#
@@ -128,29 +115,6 @@ null
{"foo": {"bar": 42}, "bar": "badvalue"}
42
."foo"."bar"
{"foo": {"bar": 20}}
20
[.[]|.foo?]
[1,[2],{"foo":3,"bar":4},{},{"foo":5}]
[3,null,5]
[.[]|.foo?.bar?]
[1,[2],[],{"foo":3},{"foo":{"bar":4}},{}]
[4,null]
[..]
[1,[[2]],{ "a":[1]}]
[[1,[[2]],{"a":[1]}],1,[[2]],[2],2,{"a":[1]},[1],1]
[.[]|.[]?]
[1,null,[],[1,[2,[[3]]]],[{}],[{"a":[1,[2]]}]]
[1,[2,[[3]]],{},{"a":[1,[2]]}]
[.[]|.[1:3]?]
[1,null,true,false,"abcdef",{},{"a":1,"b":2},[],[1,2,3,4,5],[1,2]]
[null,"bc",[],[2,3],[2]]
#
# Multiple outputs, iteration
@@ -210,10 +174,6 @@ null
[0,1,2,3,4,5,6]
[[], [2,3], [0,1,2,3,4], [5,6], [], []]
[.[3:2], .[-5:4], .[:-2], .[-2:], .[3:3][1:], .[10:]]
"abcdefghi"
["","","abcdefg","hi","",""]
del(.[2:4],.[0],.[-2:])
[0,1,2,3,4,5,6,7]
[1,4,5]
@@ -325,14 +285,6 @@ null
null
[2, 8, 10, 14]
25 % 7
null
4
49732 % 472
null
172
1 + tonumber + ("10" | tonumber)
4
15
@@ -380,10 +332,6 @@ def f: (1000,2000); f
1000
2000
def f(a;b;c;d;e;f): [a+1,b,c,d,e,f]; f(.[0];.[1];.[0];.[0];.[0];.[0])
[1,2]
[2,2,1,1,1,1]
([1,2] + [4,5])
[1,2,3]
[1,2,4,5]
@@ -402,36 +350,6 @@ null
[5,6]
[1,2,3]
[.[]|floor]
[-1.1,1.1,1.9]
[-2, 1, 1]
[.[]|sqrt]
[4,9]
[2,3]
(add / length) as $m | map((. - $m) as $d | $d * $d) | add / length | sqrt
[2,4,4,4,5,5,7,9]
2
# Should write a test that calls the -lm function from C (or bc(1)) to
# check that they match the corresponding jq functions. However,
# there's so little template code standing between that it suffices to
# test a handful of these. The results were checked by eye against
# bc(1).
atan * 4 * 1000000|floor / 1000000
1
3.141592
[(3.141592 / 2) * (range(0;20) / 20)|cos * 1000000|floor / 1000000]
null
[1,0.996917,0.987688,0.972369,0.951056,0.923879,0.891006,0.85264,0.809017,0.760406,0.707106,0.649448,0.587785,0.522498,0.45399,0.382683,0.309017,0.233445,0.156434,0.078459]
[(3.141592 / 2) * (range(0;20) / 20)|sin * 1000000|floor / 1000000]
null
[0,0.078459,0.156434,0.233445,0.309016,0.382683,0.45399,0.522498,0.587785,0.649447,0.707106,0.760405,0.809016,0.85264,0.891006,0.923879,0.951056,0.972369,0.987688,0.996917]
def f(x): x | x; f([.], . + [42])
[1,2,3]
[[[1,2,3]]]
@@ -439,11 +357,6 @@ def f(x): x | x; f([.], . + [42])
[[1,2,3,42]]
[1,2,3,42,42]
# test multiple function arities and redefinition
def f: .+1; def g: f; def f: .+100; def f(a):a+.+11; [(g|f(20)), f]
1
[33,101]
# test closures and lexical scoping
def id(x):x; 2000 as $x | def f(x):1 as $x | id([$x, x, x]); def g(x): 100 as $x | f($x,$x+x); g($x)
"more testing"
@@ -487,14 +400,6 @@ path(.)
42
[]
[paths]
[1,[[],{"a":2}]]
[[0],[1],[1,0],[1,1],[1,1,"a"]]
[leaf_paths]
[1,[[],{"a":2}]]
[[0],[1,1,"a"]]
["foo",1] as $p | getpath($p), setpath($p; 20), delpaths([$p])
{"bar": 42, "foo": ["a", "b", "c", "d"]}
"b"
@@ -543,17 +448,12 @@ null
{"foo": 42}
{"foo": 43}
.[] += 2, .[] *= 2, .[] -= 2, .[] /= 2, .[] %=2
.[] += 2, .[] *= 2, .[] -= 2, .[] /= 2
[1,3,5]
[3,5,7]
[2,6,10]
[-1,1,3]
[0.5, 1.5, 2.5]
[1,1,1]
[.[] % 7]
[-7,-6,-5,-4,-3,-2,-1,0,1,2,3,4,5,6,7]
[0,-6,-5,-4,-3,-2,-1,0,1,2,3,4,5,6,0]
.foo += .foo
{"foo":2}
@@ -645,119 +545,6 @@ def inc(x): x |= .+1; inc(.[].a)
{}
[true, true, false]
# string operations
[.[]|startswith("foo")]
["fo", "foo", "barfoo", "foobar", "barfoob"]
[false, true, false, true, false]
[.[]|endswith("foo")]
["fo", "foo", "barfoo", "foobar", "barfoob"]
[false, true, true, false, false]
# match builtin
[match("( )*"; "g")]
"abc"
[{"offset":0, "length":0, "string":"", "captures":[]},{"offset":1, "length":0, "string":"", "captures":[]},{"offset":2, "length":0, "string":"", "captures":[]}]
[match("( )*"; "gn")]
"abc"
[]
[match("a"; "gi")]
"āáàä"
[]
[match(["(bar)"])]
"foo bar"
[{"offset": 4, "length": 3, "string": "bar", "captures":[{"offset": 4, "length": 3, "string": "bar", "name": null}]}]
# offsets account for combining codepoints and multi-byte UTF-8
[match("bar")]
"ā bar with a combining codepoint U+0304"
[{"offset": 3, "length": 3, "string": "bar", "captures":[]}]
# matches with combining codepoints still count them in their length
[match("bār")]
"a bār"
[{"offset": 2, "length": 4, "string": "bār", "captures":[]}]
[match(".+?\\b")]
"ā two-codepoint grapheme"
[{"offset": 0, "length": 2, "string": "ā", "captures":[]}]
[match(["foo (?<bar123>bar)? foo", "ig"])]
"foo bar foo foo foo"
[{"offset": 0, "length": 11, "string": "foo bar foo", "captures":[{"offset": 4, "length": 3, "string": "bar", "name": "bar123"}]},{"offset":12, "length": 8, "string": "foo foo", "captures":[{"offset": -1, "length": 0, "string": null, "name": "bar123"}]}]
#test builtin
[test("( )*"; "gn")]
"abc"
[false]
[test("ā")]
"ā"
[true]
[.[]|ltrimstr("foo")]
["fo", "foo", "barfoo", "foobar", "afoo"]
["fo","","barfoo","bar","afoo"]
[.[]|rtrimstr("foo")]
["fo", "foo", "barfoo", "foobar", "foob"]
["fo","","bar","foobar","foob"]
.[","]
"a,bc,def,ghij,klmno"
[1,4,8,13]
.[", "]
"a,bc,def,ghij,klmno"
[]
.[", "]
"a,b,, c, d,ef, , ghi, jklmn, o"
[4,7,13,15,20,27]
[(index(","), rindex(",")), indices(",")]
"a,bc,def,ghij,klmno"
[1,13,[1,4,8,13]]
indices(1)
[0,1,1,2,3,4,1,5]
[1,2,6]
indices([1,2])
[0,1,2,3,1,4,2,5,1,2,6,7]
[1,8]
indices([1,2])
[1]
[]
indices(", ")
"a,b, cd,e, fgh, ijkl"
[3,9,14]
[.[]|split(",")]
["a, bc, def, ghij, jklmn, a,b, c,d, e,f", "a,b,c,d, e,f,g,h"]
[["a"," bc"," def"," ghij"," jklmn"," a","b"," c","d"," e","f"],["a","b","c","d"," e","f","g","h"]]
[.[]|split(", ")]
["a, bc, def, ghij, jklmn, a,b, c,d, e,f", "a,b,c,d, e,f,g,h"]
[["a","bc","def","ghij","jklmn","a,b","c,d","e,f"],["a,b,c,d","e,f,g,h"]]
[.[] * 3]
["a", "ab", "abc"]
["aaa", "ababab", "abcabcabc"]
[.[] / ","]
["a, bc, def, ghij, jklmn, a,b, c,d, e,f", "a,b,c,d, e,f,g,h"]
[["a"," bc"," def"," ghij"," jklmn"," a","b"," c","d"," e","f"],["a","b","c","d"," e","f","g","h"]]
[.[] / ", "]
["a, bc, def, ghij, jklmn, a,b, c,d, e,f", "a,b,c,d, e,f,g,h"]
[["a","bc","def","ghij","jklmn","a,b","c,d","e,f"],["a,b,c,d","e,f,g,h"]]
map(.[1] as $needle | .[0] | contains($needle))
[[[],[]], [[1,2,3], [1,2]], [[1,2,3], [3,1]], [[1,2,3], [4]], [[1,2,3], [1,4]]]
[true, true, true, false, false]
@@ -794,10 +581,6 @@ unique
[1,2,5,3,5,3,1,3]
[1,2,3,5]
unique
[]
[]
[min, max, min_by(.[1]), max_by(.[1]), min_by(.[2]), max_by(.[2])]
[[4,2,"a"],[3,1,"a"],[2,4,"a"],[1,3,"a"]]
[[1,3,"a"],[4,2,"a"],[3,1,"a"],[2,4,"a"],[4,2,"a"],[1,3,"a"]]
@@ -817,93 +600,3 @@ unique
[{a:1}] | .[] | .a=999
null
{"a": 999}
to_entries
{"a": 1, "b": 2}
[{"key":"a", "value":1}, {"key":"b", "value":2}]
from_entries
[{"key":"a", "value":1}, {"key":"b", "value":2}]
{"a": 1, "b": 2}
with_entries(.key |= "KEY_" + .)
{"a": 1, "b": 2}
{"KEY_a": 1, "KEY_b": 2}
map(has("foo"))
[{"foo": 42}, {}]
[true, false]
map(has(2))
[[0,1], ["a","b","c"]]
[false, true]
keys
[42,3,35]
[0,1,2]
[][.]
1000000000000000000
null
map([1,2][0:.])
[-1, 1, 2, 3, 1000000000000000000]
[[1], [1], [1,2], [1,2], [1,2]]
# Test recursive object merge
{"k": {"a": 1, "b": 2}} * .
{"k": {"a": 0,"c": 3}}
{"k": {"a": 0, "b": 2, "c": 3}}
{"k": {"a": 1, "b": 2}, "hello": {"x": 1}} * .
{"k": {"a": 0,"c": 3}, "hello": 1}
{"k": {"a": 0, "b": 2, "c": 3}, "hello": 1}
{"k": {"a": 1, "b": 2}, "hello": 1} * .
{"k": {"a": 0,"c": 3}, "hello": {"x": 1}}
{"k": {"a": 0, "b": 2, "c": 3}, "hello": {"x": 1}}
{"a": {"b": 1}, "c": {"d": 2}, "e": 5} * .
{"a": {"b": 2}, "c": {"d": 3, "f": 9}}
{"a": {"b": 2}, "c": {"d": 3, "f": 9}, "e": 5}
[.[]|arrays]
[1,2,"foo",[],[3,[]],{},true,false,null]
[[],[3,[]]]
[.[]|objects]
[1,2,"foo",[],[3,[]],{},true,false,null]
[{}]
[.[]|iterables]
[1,2,"foo",[],[3,[]],{},true,false,null]
[[],[3,[]],{}]
[.[]|scalars]
[1,2,"foo",[],[3,[]],{},true,false,null]
[1,2,"foo",true,false,null]
[.[]|values]
[1,2,"foo",[],[3,[]],{},true,false,null]
[1,2,"foo",[],[3,[]],{},true,false]
[.[]|booleans]
[1,2,"foo",[],[3,[]],{},true,false,null]
[true,false]
[.[]|nulls]
[1,2,"foo",[],[3,[]],{},true,false,null]
[null]
flatten
[0, [1], [[2]], [[[3]]]]
[0, 1, 2, 3]
flatten(2)
[0, [1], [[2]], [[[3]]]]
[0, 1, 2, [3]]
flatten(2)
[0, [1, [2]], [1, [[3], 2]]]
[0, 1, 2, 1, [3], 2]
-21
View File
@@ -1,21 +0,0 @@
{
onig node recycling
Memcheck:Leak
...
fun:onig_parse_make_tree
...
}
{
onig unicode case insensitivity 1
Memcheck:Leak
...
fun:setup_tree
...
}
{
onig unicode case insensitivity 2
Memcheck:Leak
...
fun:onig*unicode*
...
}
+1 -7
View File
@@ -1,9 +1,3 @@
#!/bin/sh
if which valgrind > /dev/null; then
VALGRIND='valgrind --error-exitcode=1 -q --leak-check=full --suppressions=tests/onig.supp'
else
VALGRIND=
fi
cat $@ | $VALGRIND ./jq --run-tests
cat $@ | valgrind --error-exitcode=1 -q --leak-check=full ./jq --run-tests