Repository: jqlang/jq Branch: master Commit: cec6b0f34603 Files: 387 Total size: 3.1 MB Directory structure: gitextract_tfjw1qrz/ ├── .gitattributes ├── .github/ │ ├── ISSUE_TEMPLATE/ │ │ └── bug_report.md │ ├── dependabot.yml │ └── workflows/ │ ├── ci.yml │ ├── decnum.yml │ ├── manpage.yml │ ├── oniguruma.yml │ ├── scanbuild.yml │ ├── valgrind.yml │ └── website.yml ├── .gitignore ├── .gitmodules ├── AUTHORS ├── COPYING ├── ChangeLog ├── Dockerfile ├── KEYS ├── Makefile.am ├── NEWS.md ├── README.md ├── SECURITY.md ├── compile-ios.sh ├── config/ │ ├── .gitignore │ └── m4/ │ ├── .gitignore │ ├── check-math-func.m4 │ ├── find-func-no-libs.m4 │ ├── find-func-no-libs2.m4 │ ├── find-func.m4 │ └── misc.m4 ├── configure.ac ├── docs/ │ ├── Pipfile │ ├── README.md │ ├── build_manpage.py │ ├── build_mantests.py │ ├── build_website.py │ ├── content/ │ │ ├── download/ │ │ │ └── default.yml │ │ ├── index.yml │ │ ├── manual/ │ │ │ ├── dev/ │ │ │ │ └── manual.yml │ │ │ ├── v1.3/ │ │ │ │ └── manual.yml │ │ │ ├── v1.4/ │ │ │ │ └── manual.yml │ │ │ ├── v1.5/ │ │ │ │ └── manual.yml │ │ │ ├── v1.6/ │ │ │ │ └── manual.yml │ │ │ ├── v1.7/ │ │ │ │ └── manual.yml │ │ │ └── v1.8/ │ │ │ └── manual.yml │ │ └── tutorial/ │ │ └── default.yml │ ├── manual_schema.yml │ ├── public/ │ │ ├── .htaccess │ │ ├── CNAME │ │ ├── css/ │ │ │ └── style.css │ │ ├── js/ │ │ │ └── manual-search.js │ │ └── robots.txt │ ├── templates/ │ │ ├── default.html.j2 │ │ ├── index.html.j2 │ │ ├── manual.html.j2 │ │ └── shared/ │ │ ├── _footer.html.j2 │ │ ├── _head.html.j2 │ │ └── _navbar.html.j2 │ └── validate_manual_schema.py ├── jq.1.prebuilt ├── jq.spec ├── libjq.pc.in ├── m4/ │ ├── ax_compare_version.m4 │ ├── ax_prog_bison_version.m4 │ └── ax_pthread.m4 ├── scripts/ │ ├── crosscompile │ ├── gen_utf8_tables.py │ └── version ├── sig/ │ ├── jq-release-new.key │ ├── jq-release-old.key │ ├── v1.3/ │ │ ├── jq-linux-x86.asc │ │ ├── jq-linux-x86_64.asc │ │ ├── jq-osx-x86.asc │ │ ├── jq-osx-x86_64.asc │ │ ├── jq-win32.exe.asc │ │ ├── jq-win64.exe.asc │ │ └── sha256sum.txt │ ├── v1.4/ │ │ ├── jq-linux-x86.asc │ │ ├── jq-linux-x86_64.asc │ │ ├── jq-osx-x86.asc │ │ ├── jq-osx-x86_64.asc │ │ ├── jq-solaris11-32.asc │ │ ├── jq-solaris11-64.asc │ │ ├── jq-win32.exe.asc │ │ ├── jq-win64.exe.asc │ │ └── sha256sum.txt │ ├── v1.5/ │ │ ├── jq-linux32-no-oniguruma.asc │ │ ├── jq-linux32.asc │ │ ├── jq-linux64.asc │ │ ├── jq-osx-amd64.asc │ │ ├── jq-win32.exe.asc │ │ ├── jq-win64.exe.asc │ │ └── sha256sum.txt │ ├── v1.5rc1/ │ │ ├── jq-linux-x86_64-static.asc │ │ ├── jq-win32.exe.asc │ │ ├── jq-win64.exe.asc │ │ └── sha256sum.txt │ ├── v1.5rc2/ │ │ ├── jq-linux-x86.asc │ │ ├── jq-linux-x86_64.asc │ │ ├── jq-osx-x86_64.asc │ │ ├── jq-win32.exe.asc │ │ ├── jq-win64.exe.asc │ │ └── sha256sum.txt │ ├── v1.6/ │ │ ├── jq-linux32.asc │ │ ├── jq-linux64.asc │ │ ├── jq-osx-amd64.asc │ │ ├── jq-win32.exe.asc │ │ ├── jq-win64.exe.asc │ │ └── sha256sum.txt │ ├── v1.7/ │ │ ├── jq-1.7.tar.gz.asc │ │ ├── jq-1.7.zip.asc │ │ ├── jq-linux-amd64.asc │ │ ├── jq-linux-arm64.asc │ │ ├── jq-linux-armel.asc │ │ ├── jq-linux-armhf.asc │ │ ├── jq-linux-i386.asc │ │ ├── jq-linux-mips.asc │ │ ├── jq-linux-mips64.asc │ │ ├── jq-linux-mips64el.asc │ │ ├── jq-linux-mips64r6.asc │ │ ├── jq-linux-mips64r6el.asc │ │ ├── jq-linux-mipsel.asc │ │ ├── jq-linux-mipsr6.asc │ │ ├── jq-linux-mipsr6el.asc │ │ ├── jq-linux-powerpc.asc │ │ ├── jq-linux-ppc64el.asc │ │ ├── jq-linux-riscv64.asc │ │ ├── jq-linux-s390x.asc │ │ ├── jq-linux32.asc │ │ ├── jq-linux64.asc │ │ ├── jq-macos-amd64.asc │ │ ├── jq-macos-arm64.asc │ │ ├── jq-osx-amd64.asc │ │ ├── jq-win32.exe.asc │ │ ├── jq-win64.exe.asc │ │ ├── jq-windows-amd64.exe.asc │ │ ├── jq-windows-i386.exe.asc │ │ └── sha256sum.txt │ ├── v1.7.1/ │ │ ├── jq-1.7.1.tar.gz.asc │ │ ├── jq-1.7.1.zip.asc │ │ ├── jq-linux-amd64.asc │ │ ├── jq-linux-arm64.asc │ │ ├── jq-linux-armel.asc │ │ ├── jq-linux-armhf.asc │ │ ├── jq-linux-i386.asc │ │ ├── jq-linux-mips.asc │ │ ├── jq-linux-mips64.asc │ │ ├── jq-linux-mips64el.asc │ │ ├── jq-linux-mips64r6.asc │ │ ├── jq-linux-mips64r6el.asc │ │ ├── jq-linux-mipsel.asc │ │ ├── jq-linux-mipsr6.asc │ │ ├── jq-linux-mipsr6el.asc │ │ ├── jq-linux-powerpc.asc │ │ ├── jq-linux-ppc64el.asc │ │ ├── jq-linux-riscv64.asc │ │ ├── jq-linux-s390x.asc │ │ ├── jq-linux64.asc │ │ ├── jq-macos-amd64.asc │ │ ├── jq-macos-arm64.asc │ │ ├── jq-osx-amd64.asc │ │ ├── jq-win64.exe.asc │ │ ├── jq-windows-amd64.exe.asc │ │ ├── jq-windows-i386.exe.asc │ │ └── sha256sum.txt │ ├── v1.7rc1/ │ │ ├── jq-1.7rc1.tar.gz.asc │ │ ├── jq-1.7rc1.zip.asc │ │ ├── jq-linux-amd64.asc │ │ ├── jq-linux-arm64.asc │ │ ├── jq-linux-armel.asc │ │ ├── jq-linux-armhf.asc │ │ ├── jq-linux-i386.asc │ │ ├── jq-linux-mips.asc │ │ ├── jq-linux-mips64.asc │ │ ├── jq-linux-mips64el.asc │ │ ├── jq-linux-mips64r6.asc │ │ ├── jq-linux-mips64r6el.asc │ │ ├── jq-linux-mipsel.asc │ │ ├── jq-linux-mipsr6.asc │ │ ├── jq-linux-mipsr6el.asc │ │ ├── jq-linux-powerpc.asc │ │ ├── jq-linux-ppc64el.asc │ │ ├── jq-linux-riscv64.asc │ │ ├── jq-linux-s390x.asc │ │ ├── jq-macos-amd64.asc │ │ ├── jq-macos-arm64.asc │ │ ├── jq-windows-amd64.exe.asc │ │ ├── jq-windows-i386.exe.asc │ │ └── sha256sum.txt │ ├── v1.7rc2/ │ │ ├── jq-1.7rc2.tar.gz.asc │ │ ├── jq-1.7rc2.zip.asc │ │ ├── jq-linux-amd64.asc │ │ ├── jq-linux-arm64.asc │ │ ├── jq-linux-armel.asc │ │ ├── jq-linux-armhf.asc │ │ ├── jq-linux-i386.asc │ │ ├── jq-linux-mips.asc │ │ ├── jq-linux-mips64.asc │ │ ├── jq-linux-mips64el.asc │ │ ├── jq-linux-mips64r6.asc │ │ ├── jq-linux-mips64r6el.asc │ │ ├── jq-linux-mipsel.asc │ │ ├── jq-linux-mipsr6.asc │ │ ├── jq-linux-mipsr6el.asc │ │ ├── jq-linux-powerpc.asc │ │ ├── jq-linux-ppc64el.asc │ │ ├── jq-linux-riscv64.asc │ │ ├── jq-linux-s390x.asc │ │ ├── jq-macos-amd64.asc │ │ ├── jq-macos-arm64.asc │ │ ├── jq-windows-amd64.exe.asc │ │ ├── jq-windows-i386.exe.asc │ │ └── sha256sum.txt │ ├── v1.8.0/ │ │ ├── jq-1.8.0.tar.gz.asc │ │ ├── jq-1.8.0.zip.asc │ │ ├── jq-linux-amd64.asc │ │ ├── jq-linux-arm64.asc │ │ ├── jq-linux-armel.asc │ │ ├── jq-linux-armhf.asc │ │ ├── jq-linux-i386.asc │ │ ├── jq-linux-mips.asc │ │ ├── jq-linux-mips64.asc │ │ ├── jq-linux-mips64el.asc │ │ ├── jq-linux-mips64r6.asc │ │ ├── jq-linux-mips64r6el.asc │ │ ├── jq-linux-mipsel.asc │ │ ├── jq-linux-mipsr6.asc │ │ ├── jq-linux-mipsr6el.asc │ │ ├── jq-linux-powerpc.asc │ │ ├── jq-linux-ppc64el.asc │ │ ├── jq-linux-riscv64.asc │ │ ├── jq-linux-s390x.asc │ │ ├── jq-linux64.asc │ │ ├── jq-macos-amd64.asc │ │ ├── jq-macos-arm64.asc │ │ ├── jq-osx-amd64.asc │ │ ├── jq-win64.exe.asc │ │ ├── jq-windows-amd64.exe.asc │ │ ├── jq-windows-i386.exe.asc │ │ └── sha256sum.txt │ └── v1.8.1/ │ ├── jq-1.8.1.tar.gz.asc │ ├── jq-1.8.1.zip.asc │ ├── jq-linux-amd64.asc │ ├── jq-linux-arm64.asc │ ├── jq-linux-armel.asc │ ├── jq-linux-armhf.asc │ ├── jq-linux-i386.asc │ ├── jq-linux-mips.asc │ ├── jq-linux-mips64.asc │ ├── jq-linux-mips64el.asc │ ├── jq-linux-mips64r6.asc │ ├── jq-linux-mips64r6el.asc │ ├── jq-linux-mipsel.asc │ ├── jq-linux-mipsr6.asc │ ├── jq-linux-mipsr6el.asc │ ├── jq-linux-powerpc.asc │ ├── jq-linux-ppc64el.asc │ ├── jq-linux-riscv64.asc │ ├── jq-linux-s390x.asc │ ├── jq-linux64.asc │ ├── jq-macos-amd64.asc │ ├── jq-macos-arm64.asc │ ├── jq-osx-amd64.asc │ ├── jq-win64.exe.asc │ ├── jq-windows-amd64.exe.asc │ ├── jq-windows-i386.exe.asc │ └── sha256sum.txt ├── src/ │ ├── builtin.c │ ├── builtin.h │ ├── builtin.jq │ ├── bytecode.c │ ├── bytecode.h │ ├── compile.c │ ├── compile.h │ ├── exec_stack.h │ ├── execute.c │ ├── inject_errors.c │ ├── jq.h │ ├── jq_parser.h │ ├── jq_test.c │ ├── jv.c │ ├── jv.h │ ├── jv_alloc.c │ ├── jv_alloc.h │ ├── jv_aux.c │ ├── jv_dtoa.c │ ├── jv_dtoa.h │ ├── jv_dtoa_tsd.c │ ├── jv_dtoa_tsd.h │ ├── jv_file.c │ ├── jv_parse.c │ ├── jv_print.c │ ├── jv_private.h │ ├── jv_thread.h │ ├── jv_unicode.c │ ├── jv_unicode.h │ ├── jv_utf8_tables.h │ ├── lexer.c │ ├── lexer.h │ ├── lexer.l │ ├── libm.h │ ├── linker.c │ ├── linker.h │ ├── locfile.c │ ├── locfile.h │ ├── main.c │ ├── opcode_list.h │ ├── parser.c │ ├── parser.h │ ├── parser.y │ ├── util.c │ └── util.h ├── tests/ │ ├── base64.test │ ├── base64test │ ├── jq-f-test.sh │ ├── jq.test │ ├── jq_fuzz_compile.c │ ├── jq_fuzz_execute.cpp │ ├── jq_fuzz_fixed.cpp │ ├── jq_fuzz_load_file.c │ ├── jq_fuzz_parse.c │ ├── jq_fuzz_parse_extended.c │ ├── jq_fuzz_parse_stream.c │ ├── jqtest │ ├── local.supp │ ├── man.test │ ├── manonig.test │ ├── manonigtest │ ├── mantest │ ├── modules/ │ │ ├── a.jq │ │ ├── b/ │ │ │ └── b.jq │ │ ├── c/ │ │ │ ├── c.jq │ │ │ └── d.jq │ │ ├── data.json │ │ ├── home1/ │ │ │ └── .jq │ │ ├── home2/ │ │ │ └── .jq/ │ │ │ └── g.jq │ │ ├── shadow1.jq │ │ ├── shadow2.jq │ │ ├── syntaxerror/ │ │ │ └── syntaxerror.jq │ │ ├── test_bind_order.jq │ │ ├── test_bind_order0.jq │ │ ├── test_bind_order1.jq │ │ └── test_bind_order2.jq │ ├── no-main-program.jq │ ├── onig.supp │ ├── onig.test │ ├── onigtest │ ├── optional.test │ ├── optionaltest │ ├── setup │ ├── shtest │ ├── torture/ │ │ └── input0.json │ ├── uri.test │ ├── uritest │ ├── utf8test │ └── yes-main-program.jq └── vendor/ └── decNumber/ ├── ICU-license.html ├── decBasic.c ├── decCommon.c ├── decContext.c ├── decContext.h ├── decDPD.h ├── decDouble.c ├── decDouble.h ├── decNumber.c ├── decNumber.h ├── decNumberLocal.h ├── decPacked.c ├── decPacked.h ├── decQuad.c ├── decQuad.h ├── decSingle.c ├── decSingle.h ├── decimal128.c ├── decimal128.h ├── decimal32.c ├── decimal32.h ├── decimal64.c ├── decimal64.h ├── example1.c ├── example2.c ├── example3.c ├── example4.c ├── example5.c ├── example6.c ├── example7.c ├── example8.c └── readme.txt ================================================ FILE CONTENTS ================================================ ================================================ FILE: .gitattributes ================================================ .gitattributes export-ignore .gitignore export-ignore * text=auto eol=lf vendor/** linguist-vendored # generated files src/lexer.[ch] linguist-generated=true src/parser.[ch] linguist-generated=true tests/man.test linguist-generated=true tests/manonig.test linguist-generated=true jq.1.prebuilt linguist-generated=true docs/Pipfile.lock linguist-generated=true ================================================ FILE: .github/ISSUE_TEMPLATE/bug_report.md ================================================ --- name: Bug report about: Create a report to help us improve --- **Describe the bug** A clear and concise description of what the bug is. **To Reproduce** Provide a minimal test case to reproduce the behavior. If the input is large, either attach it as a file, or [create a gist](https://gist.github.com) and link to it here. **Expected behavior** A clear and concise description of what you expected to happen. **Environment (please complete the following information):** - OS and Version: [e.g. macOS, Windows, Linux (please specify distro)] - jq version [e.g. 1.5] **Additional context** Add any other context about the problem here. ================================================ FILE: .github/dependabot.yml ================================================ version: 2 updates: - package-ecosystem: "pip" directory: "docs/" schedule: interval: "monthly" - package-ecosystem: "github-actions" directory: "/" schedule: interval: "weekly" groups: official-actions: patterns: ["actions/*"] docker-actions: patterns: ["docker/*"] ================================================ FILE: .github/workflows/ci.yml ================================================ name: CI on: push: branches: - master tags: - "jq-*" pull_request: jobs: linux: strategy: fail-fast: false matrix: arch: - amd64 - arm64 - armel - armhf - i386 - mips - mips64 - mips64el - mips64r6 - mips64r6el - mipsel - mipsr6 - mipsr6el - powerpc - ppc64el - riscv64 - s390x include: - arch: amd64 CC: x86_64-linux-gnu - arch: arm64 CC: aarch64-linux-gnu - arch: armel CC: arm-linux-gnueabi - arch: armhf CC: arm-linux-gnueabihf - arch: i386 CC: i686-linux-gnu - arch: mips CC: mips-linux-gnu - arch: mips64 CC: mips64-linux-gnuabi64 - arch: mips64el CC: mips64el-linux-gnuabi64 - arch: mips64r6 CC: mipsisa64r6-linux-gnuabi64 - arch: mips64r6el CC: mipsisa64r6el-linux-gnuabi64 - arch: mipsel CC: mipsel-linux-gnu - arch: mipsr6 CC: mipsisa32r6-linux-gnu - arch: mipsr6el CC: mipsisa32r6el-linux-gnu - arch: powerpc CC: powerpc-linux-gnu - arch: ppc64el CC: powerpc64le-linux-gnu - arch: riscv64 CC: riscv64-linux-gnu - arch: s390x CC: s390x-linux-gnu runs-on: ${{ matrix.arch == 'i386' && 'ubuntu-22.04' || 'ubuntu-24.04' }} env: AR: ${{ matrix.CC }}-ar CHOST: ${{ matrix.CC }} CC: ${{ matrix.CC }}-gcc CPP: ${{ matrix.CC }}-cpp LDFLAGS: -s SUFFIX: linux-${{ matrix.arch }} steps: - name: Clone repository uses: actions/checkout@v6 with: submodules: true - name: Install packages run: | sudo apt-get update sudo apt-get install -y automake autoconf libtool crossbuild-essential-${{ matrix.arch }} - name: Build run: | autoreconf -i ./configure \ --host=${{ matrix.CC }} \ --disable-docs \ --with-oniguruma=builtin \ --enable-static \ --enable-all-static \ CFLAGS="-O2 -pthread -fstack-protector-all" make -j"$(nproc)" file ./jq cp ./jq jq-${{ env.SUFFIX }} - name: Test # Only run tests for amd64 matching the CI machine arch if: ${{ matrix.arch == 'amd64' }} run: | make check VERBOSE=yes git diff --exit-code - name: Upload Test Logs if: ${{ failure() }} uses: actions/upload-artifact@v7 with: name: test-logs-${{ env.SUFFIX }} retention-days: 7 path: | test-suite.log tests/*.log - name: Upload artifacts uses: actions/upload-artifact@v7 with: name: jq-${{ env.SUFFIX }} path: jq-${{ env.SUFFIX }} if-no-files-found: error retention-days: 7 macos: strategy: fail-fast: false matrix: arch: - amd64 - arm64 include: - arch: amd64 target: x86_64-apple-darwin - arch: arm64 target: arm64-apple-darwin runs-on: macos-14 env: LDFLAGS: -dead_strip SUFFIX: macos-${{ matrix.arch }} steps: - name: Clone repository uses: actions/checkout@v6 with: submodules: true - name: Install packages run: | # brew update sometimes fails with "Fetching /usr/local/Homebrew/Library/Taps/homebrew/homebrew-cask failed!" brew update || brew update-reset brew install autoconf automake libtool - name: Set CC run: | echo "CC=clang -target ${{ matrix.target }}$(uname -r)" >> "$GITHUB_ENV" - name: Build run: | autoreconf -i ./configure \ --host="${{ matrix.target }}$(uname -r)" \ --disable-docs \ --with-oniguruma=builtin \ --disable-shared \ --enable-static \ --enable-all-static \ CFLAGS="-O2 -pthread -fstack-protector-all" make -j"$(sysctl -n hw.logicalcpu)" strip ./jq file ./jq cp ./jq jq-${{ env.SUFFIX }} - name: Test run: | make check VERBOSE=yes git diff --exit-code - name: Upload Test Logs if: ${{ failure() }} uses: actions/upload-artifact@v7 with: name: test-logs-${{ env.SUFFIX }} retention-days: 7 path: | test-suite.log tests/*.log - name: Upload artifacts uses: actions/upload-artifact@v7 with: name: jq-${{ env.SUFFIX }} path: jq-${{ env.SUFFIX }} if-no-files-found: error retention-days: 7 windows: strategy: fail-fast: false matrix: arch: - amd64 - i386 - arm64 include: - arch: amd64 msystem: UCRT64 os: windows-2022 - arch: i386 msystem: MINGW32 os: windows-2022 - arch: arm64 msystem: CLANGARM64 os: windows-11-arm runs-on: ${{ matrix.os }} env: LDFLAGS: -s SUFFIX: windows-${{ matrix.arch }} defaults: run: shell: msys2 {0} steps: - name: Prepare git config run: git config --system core.autocrlf false shell: bash - name: Clone repository uses: actions/checkout@v6 with: submodules: true - uses: msys2/setup-msys2@v2 with: update: true msystem: ${{ matrix.msystem }} install: >- base-devel git autoconf automake libtool pacboy: >- toolchain:p - name: Build run: | autoreconf -i ./configure \ --disable-docs \ --with-oniguruma=builtin \ --disable-shared \ --enable-static \ --enable-all-static \ CFLAGS="-O2 -pthread -fstack-protector-all -Wl,--stack,8388608" make -j$(nproc) file ./jq.exe cp ./jq.exe jq-${{ env.SUFFIX }}.exe - name: Test run: | make check VERBOSE=yes git diff --exit-code - name: Upload Test Logs if: ${{ failure() }} uses: actions/upload-artifact@v7 with: name: test-logs-${{ env.SUFFIX }} retention-days: 7 path: | test-suite.log tests/*.log - name: Upload artifacts uses: actions/upload-artifact@v7 with: name: jq-${{ env.SUFFIX }} path: jq-${{ env.SUFFIX }}.exe if-no-files-found: error retention-days: 7 dist: runs-on: ubuntu-latest steps: - name: Clone repository uses: actions/checkout@v6 with: submodules: true - name: Install packages run: | sudo apt-get update -qq sudo apt-get install -y automake autoconf - name: Create dist run: | autoreconf -i ./configure \ --disable-docs \ --with-oniguruma=builtin make distcheck make dist dist-zip git diff --exit-code - name: Upload artifacts uses: actions/upload-artifact@v7 with: name: jq-dist if-no-files-found: error retention-days: 7 path: | jq-*.tar.gz jq-*.zip docker: runs-on: ubuntu-latest permissions: id-token: write contents: read attestations: write packages: write needs: linux steps: - name: Clone repository uses: actions/checkout@v6 - name: Download executables uses: actions/download-artifact@v8 with: pattern: jq-linux-* merge-multiple: true - name: Move executables run: | mkdir -p linux/{386,amd64,arm64,arm/v7,mips64le,ppc64le,riscv64,s390x} chmod +x jq-linux-* mv jq-linux-i386 linux/386/jq mv jq-linux-amd64 linux/amd64/jq mv jq-linux-arm64 linux/arm64/jq mv jq-linux-armhf linux/arm/v7/jq mv jq-linux-mips64el linux/mips64le/jq mv jq-linux-ppc64el linux/ppc64le/jq mv jq-linux-riscv64 linux/riscv64/jq mv jq-linux-s390x linux/s390x/jq - name: Create Dockerfile run: | cat <<'EOF' >Dockerfile FROM scratch ARG TARGETPLATFORM COPY AUTHORS COPYING $TARGETPLATFORM/jq / RUN ["/jq", "--version"] ENTRYPOINT ["/jq"] EOF - name: Docker metadata uses: docker/metadata-action@v6 id: metadata with: images: ghcr.io/${{ github.repository }} tags: > ${{ startsWith(github.ref, 'refs/tags/jq-') && format('type=match,pattern=jq-(.*),group=1,value={0}', github.ref_name) || 'type=sha,format=long' }} - name: Set up QEMU uses: docker/setup-qemu-action@v4 - name: Set up Docker Buildx uses: docker/setup-buildx-action@v4 - name: Login to GitHub Container Registry uses: docker/login-action@v4 with: registry: ghcr.io username: ${{ github.repository_owner }} password: ${{ secrets.GITHUB_TOKEN }} - name: Build and release Docker image uses: docker/build-push-action@v7 id: build-push with: context: . push: ${{ startsWith(github.ref, 'refs/tags/jq-') }} provenance: false platforms: linux/386,linux/amd64,linux/arm64,linux/arm/v7,linux/mips64le,linux/ppc64le,linux/riscv64,linux/s390x tags: ${{ steps.metadata.outputs.tags }} labels: ${{ steps.metadata.outputs.labels }} - name: Generate signed attestations if: startsWith(github.ref, 'refs/tags/jq-') uses: actions/attest@v4 with: subject-name: ghcr.io/${{ github.repository }} subject-digest: ${{ steps.build-push.outputs.digest }} push-to-registry: true release: runs-on: ubuntu-latest permissions: contents: write id-token: write attestations: write pull-requests: write environment: release needs: [linux, macos, windows, dist, docker] if: startsWith(github.ref, 'refs/tags/jq-') steps: - name: Clone repository uses: actions/checkout@v6 - name: Download artifacts uses: actions/download-artifact@v8 with: pattern: jq-* merge-multiple: true - name: Upload release env: TAG_NAME: ${{ github.ref_name }} GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} run: | cp jq-linux-amd64 jq-linux64 cp jq-macos-amd64 jq-osx-amd64 cp jq-windows-amd64.exe jq-win64.exe sha256sum jq-* > sha256sum.txt gh release create "$TAG_NAME" --draft --title "jq ${TAG_NAME#jq-}" --generate-notes gh release upload "$TAG_NAME" --clobber jq-* sha256sum.txt - name: Generate signed attestations uses: actions/attest@v4 with: subject-path: jq-* - name: Import GPG key uses: crazy-max/ghaction-import-gpg@v7 with: gpg_private_key: ${{ secrets.JQ_RELEASE_GPG_PRIVATE_KEY }} passphrase: ${{ secrets.JQ_RELEASE_GPG_PASSPHRASE }} - name: Update signatures env: TAG_NAME: ${{ github.ref_name }} GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} run: | sig_dir="sig/v${TAG_NAME#jq-}" mkdir -p "$sig_dir" mv sha256sum.txt "$sig_dir" for file in jq-*; do gpg --detach-sign --armor --batch --output "${sig_dir}/${file#*/}.asc" "$file" done git add sig git config user.name 'github-actions[bot]' git config user.email 'github-actions[bot]@users.noreply.github.com' title="Update signatures of ${TAG_NAME#jq-}" git commit -m "$title" branch="update-signatures-${TAG_NAME#jq-}" git push origin "HEAD:refs/heads/$branch" gh pr create --title "$title" --body "" --head "$branch" ================================================ FILE: .github/workflows/decnum.yml ================================================ name: decnum on: push: branches: - master pull_request: jobs: disabled: runs-on: ubuntu-24.04 steps: - name: Clone repository uses: actions/checkout@v6 with: submodules: true - name: Install packages run: | sudo apt-get update sudo apt-get install -y automake autoconf libtool - name: Build run: | autoreconf -i ./configure \ --disable-docs \ --disable-maintainer-mode \ --disable-decnum make -j"$(nproc)" file ./jq - name: Test run: | diff <(echo 100000000000000000000 | ./jq) <(echo 1e+20) make check VERBOSE=yes git diff --exit-code - name: Upload Test Logs if: ${{ failure() }} uses: actions/upload-artifact@v7 with: name: test-logs-decnum-disabled retention-days: 7 path: | test-suite.log tests/*.log ================================================ FILE: .github/workflows/manpage.yml ================================================ name: Building man page, man.test, manonig.test on: push: paths: - '.github/workflows/manpage.yml' - 'docs/**' - 'tests/man.test' - 'tests/manonig.test' - 'jq.1.prebuilt' pull_request: paths: - '.github/workflows/manpage.yml' - 'docs/**' - 'tests/man.test' - 'tests/manonig.test' - 'jq.1.prebuilt' jobs: manpages: runs-on: ubuntu-latest steps: - name: Checkout code uses: actions/checkout@v6 - name: Setup Python uses: actions/setup-python@v6 with: python-version: '3.11' cache: pipenv - name: Install pipenv run: pip install pipenv - name: Install dependencies run: pipenv sync working-directory: docs - name: Validate manual schema run: pipenv run python3 validate_manual_schema.py content/manual/**/*.yml working-directory: docs - name: Configure run: | autoreconf -i ./configure --enable-docs - name: Build man page, man.test, manonig.test run: | mv jq.1.prebuilt jq.1.old rm -f tests/man.test manonig.test make jq.1.prebuilt tests/man.test tests/manonig.test - name: Make sure that jq.1.prebuilt, man.test, manonig.test are up to date run: | git diff --exit-code tests/man.test tests/manonig.test # skip build date in jq.1.prebuilt test -s jq.1.prebuilt diff -- <(tail -n +3 jq.1.old) <(tail -n +3 jq.1.prebuilt) ================================================ FILE: .github/workflows/oniguruma.yml ================================================ name: oniguruma on: push: branches: - master pull_request: # Since builtin oniguruma is tested in the CI workflow, # we test other options for --with-oniguruma here. jobs: installed: runs-on: ubuntu-24.04 steps: - name: Clone repository uses: actions/checkout@v6 - name: Install packages run: | sudo apt-get update sudo apt-get install -y automake autoconf libtool valgrind libonig-dev - name: Build run: | autoreconf -i ./configure \ --disable-docs \ --enable-valgrind \ --with-oniguruma=yes make -j"$(nproc)" file ./jq - name: Test run: | ./jq -n '"" | test("")' make check VERBOSE=yes git diff --exit-code - name: Upload Test Logs if: ${{ failure() }} uses: actions/upload-artifact@v7 with: name: test-logs-oniguruma-installed retention-days: 7 path: | test-suite.log tests/*.log disabled: runs-on: ubuntu-24.04 steps: - name: Clone repository uses: actions/checkout@v6 - name: Install packages run: | sudo apt-get update sudo apt-get install -y automake autoconf libtool valgrind - name: Build run: | autoreconf -i ./configure \ --disable-docs \ --enable-valgrind \ --with-oniguruma=no make -j"$(nproc)" file ./jq - name: Test run: | ! ./jq -n '"" | test("")' make check VERBOSE=yes git diff --exit-code - name: Upload Test Logs if: ${{ failure() }} uses: actions/upload-artifact@v7 with: name: test-logs-oniguruma-disabled retention-days: 7 path: | test-suite.log tests/*.log ================================================ FILE: .github/workflows/scanbuild.yml ================================================ name: Clang scan-build Static Analyzer Build on: push: branches: - master jobs: scan-build: runs-on: ubuntu-latest steps: - name: Clone repository uses: actions/checkout@v6 with: submodules: true - name: Install packages run: | sudo apt-get update -qq sudo apt-get install -y automake autoconf gdb valgrind clang clang-tools echo "CC=clang" >> "$GITHUB_ENV" - name: Build run: | autoreconf -i ./configure --enable-valgrind CFLAGS="-g -O0" scan-build --keep-going --exclude vendor/ make -j"$(nproc)" - name: Test run: | ulimit -c unlimited scan-build --keep-going --exclude vendor/ make -j"$(nproc)" check - name: Core dump stacks run: | if [[ -f core ]]; then gdb -batch -ex "thread apply all bt" \ "$(file core | sed "s/^[^']*'//; s/[ '].*$//")" core exit 1 fi - name: Test logs if: ${{ failure() }} run: | cat test-suite.log tests/*.log - name: Upload Logs uses: actions/upload-artifact@v7 with: name: Scan-Build Reports path: /tmp/scan-build* if-no-files-found: ignore retention-days: 7 ================================================ FILE: .github/workflows/valgrind.yml ================================================ name: valgrind on: push: branches: - master pull_request: jobs: linux: runs-on: ubuntu-24.04 steps: - name: Clone repository uses: actions/checkout@v6 with: submodules: true - name: Install packages run: | sudo apt-get update sudo apt-get install -y automake autoconf libtool valgrind - name: Build run: | autoreconf -i ./configure \ --disable-docs \ --enable-valgrind \ --with-oniguruma=builtin make -j"$(nproc)" file ./jq - name: Test run: | make check VERBOSE=yes git diff --exit-code - name: Upload Test Logs if: ${{ failure() }} uses: actions/upload-artifact@v7 with: name: test-logs-valgrind-linux retention-days: 7 path: | test-suite.log tests/*.log ================================================ FILE: .github/workflows/website.yml ================================================ name: Update website on: push: branches: - master paths: - 'docs/**' concurrency: website jobs: build: runs-on: ubuntu-latest defaults: run: working-directory: docs steps: - name: Checkout code uses: actions/checkout@v6 - name: Setup Python uses: actions/setup-python@v6 with: python-version: '3.11' cache: pipenv - name: Install pipenv run: pip install pipenv - name: Install dependencies run: pipenv sync - name: Build website run: pipenv run python3 build_website.py - name: Upload pages artifact uses: actions/upload-pages-artifact@v4 with: path: docs/output/ deploy: needs: build permissions: pages: write id-token: write environment: name: github-pages url: ${{ steps.deployment.outputs.page_url }} runs-on: ubuntu-latest steps: - name: Deploy to GitHub Pages uses: actions/deploy-pages@v4 id: deployment ================================================ FILE: .gitignore ================================================ *.o *.a *.lo *.la *.lai *.so *.so.* *.gcda *.gcno *.gcov *~ .*.sw[a-p] tags jq !tests/modules/lib/jq/ jq.1 # Generated source src/builtin.inc src/config_opts.inc *.pc # Autotools junk .libs .deps .dirstamp libtool *.log stamp-h1 config.log config.status autom4te.cache confdefs.h conftest* INSTALL Makefile jq-*.tar.gz jq-*.zip 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 tests/*.trs # Docs output docs/output cscope.in.out cscope.out cscope.po.out jq.dSYM ================================================ FILE: .gitmodules ================================================ [submodule "vendor/oniguruma"] path = vendor/oniguruma url = https://github.com/kkos/oniguruma.git ================================================ FILE: AUTHORS ================================================ Created By: Stephen Dolan Maintained by: David Tolnay Emanuele Torre Leonid S. Usov Mattias Wadman Muh Muhten Nicolas Williams Owen Ou William Langford itchyny pkoppstein Contributions by: 13ren AJ Jordan Aaron Peschel Adam Lindberg Alanscut Aleksey Tsalolikhin Alex Chamberlain Alex Jurkiewicz Alex Ozdemir Alex Wilson Alexandre Jasmin Allan Clark Andreas Heiduk Andrew O'Brien Andrew Rodland Andrew Speed Andy Lester Ankur Anthony Shortland Anthony Sottile Assaf Gordon Attila Fülöp Benjamin Wuethrich Benoit de Chezelles Bernard Niset Bhargava Mummadireddy Binbin Qian Bradley Skaggs Brahm Lower Brendan Macmillan Cameron Sparr Chance Zibolski Charles Merriam Chris LaRose Chris Moore Christoph Anton Mitterer Christopher Degawa Ciaran McNamara <1372986+ciaranmcnamara@users.noreply.github.com> Clément MATHIEU Colin Leroy-Mira Colin von Heuring Dag-Erling Smørgrav Damian Gryski Dan Church Daniel Lange David Biesack David Fetter David Haguenauer David Korczynski David R. MacIver DavidKorczynski Dawid Ferenczy Rogožan Derrick Pallas Doug Luce Eiichi Sato Eli Schwartz Eloy Coto Eric Bréchemier Erik Brinkman Eugen Evan Zacks Fabian Dellwing Felix Wolfsteller Filippo Giunchedi Filippo Valsorda Florian Weimer Frederic Cambus Gabriel Marin Gaelan Steele George Hopkins Gert Van Gool Gijs Kunze Gustav HE, Tao Han Jiang Hanfei Shen Hanson Char Haochen Xie Helmut K. C. Tessarek Henré Botha Ian Miell Ikko Ashimine J Phani Mahesh J. B. Rainsberger Jack Pearkes Jakub Jirutka Jakub Wilk James Andariese James Pearson Hughes Jan Schulz Janne Cederberg Jason Hood Jay Satiro Jesper Rønn-Jensen Jingwen Owen Ou Joe Littlejohn Joel Nothman Joel Purra Jonathan Chan Kwan Yin Jonathan Word Josh Soref <2119212+jsoref@users.noreply.github.com> Juan Guerrero Kamontat Chantrachirathumrong <14089557+kamontat@users.noreply.github.com> Kenny Shen Kim De Mey Kim Toms Kirk McKelvey Klemens Nanni LCD 47 Larry Aasen Lee Thompson Loamhoof Lucas Trzesniewski Lukas Lansky MCApollo <34170230+MCApollo@users.noreply.github.com> Marc Abramowitz Marc Bruggmann Marcin Kłopotek Marcin Serwin Mark Feit Mark McKinstry Markus Lanthaler Matt Clegg Matt Meyers Matti Åstrand Mattias Hansson Maxime Biais Maximilian Roos <5635139+max-sixty@users.noreply.github.com> Michael Daines Michael Färber <01mf02@gmail.com> Mike Daines Mike Fletcher Mike McCabe Nathan Baulch Naïm Favier Nicolas Pouillard Nicole Wren Paul Chvostek Paul Wise Peter van Dijk Philipp Hagemeister Ricardo Constantino Richard Groves Richard H Lee Riley Avron Rob Wills Robert Aboukhalil Roland C. Dowdeswell Roman Inflianskas Romero Malaquias Ryoichi KATO Rémy Léone SArpnt Samar Sunkaria Santiago Lapresta Sean Wei Sebastian Freundt Shaun Guth Shay Elkin Simon Elsbrock Stefan Stefan Seemayer Stephen Roantree Stephen Shaw Steven Ihde Steven Maude Steven Penny Thalia Archibald TheOdd Thomas Bozeman th026106 Thomas R. Hall Thomas Sibley Tim McCormack Timothy John Perisho Eccleston Tom Wolf Tomas Halman Travis Gockel Tyler Rockwood Ulrich Eckhardt W-Mark Kubacki William Chargin Yasuhiro Matsumoto Yeikel Yoichi Nakayama Zhaohui Mei Zhiming Wang calpeconsulting <61429736+calpeconsulting@users.noreply.github.com> cdnbacon dak180 davkor dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> eitsupi <50911393+eitsupi@users.noreply.github.com> fletcher gornick github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> goodactive <167312449+goodactive@users.noreply.github.com> i jkleint lectrical <14344693+lectrical@users.noreply.github.com> liviubobocu maflcko <6399679+maflcko@users.noreply.github.com> mail6543210 mjarosie myaaaaaaaaa <103326468+myaaaaaaaaa@users.noreply.github.com> nmulcahey orbea polyester rain1 riastradh sachint <32639496+sachintu47@users.noreply.github.com> sheepster tal@whatexit.org taoky trantor wellweek <148746285+wellweek@users.noreply.github.com> wllm-rbnt zstadler наб 엄태용 ================================================ FILE: COPYING ================================================ jq is copyright (C) 2012 Stephen Dolan 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 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. jq's documentation (everything found under the docs/ subdirectory in the source tree) is licensed under the Creative Commons CC BY 3.0 license, which can be found at: https://creativecommons.org/licenses/by/3.0/ The documentation website includes a copy of Twitter's Bootstrap and relies on Bonsai, Liquid templates and various other projects, look them up for detailed licensing conditions. jq incorporates David M. Gay's dtoa.c and g_fmt.c, which bear the following notices: dtoa.c: The author of this software is David M. Gay. Copyright (c) 1991, 2000, 2001 by Lucent Technologies. Permission to use, copy, modify, and distribute this software for any purpose without fee is hereby granted, provided that this entire notice is included in all copies of any software which is or includes a copy or modification of this software and in all copies of the supporting documentation for such software. THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED WARRANTY. IN PARTICULAR, NEITHER THE AUTHOR NOR LUCENT MAKES ANY REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE. g_fmt.c: The author of this software is David M. Gay. Copyright (c) 1991, 1996 by Lucent Technologies. Permission to use, copy, modify, and distribute this software for any purpose without fee is hereby granted, provided that this entire notice is included in all copies of any software which is or includes a copy or modification of this software and in all copies of the supporting documentation for such software. THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED WARRANTY. IN PARTICULAR, NEITHER THE AUTHOR NOR LUCENT MAKES ANY REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE. jq uses parts of the open source C library "decNumber", which is distributed under the following license: ICU License - ICU 1.8.1 and later COPYRIGHT AND PERMISSION NOTICE Copyright (c) 1995-2005 International Business Machines Corporation and others All rights reserved. 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, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, provided that the above copyright notice(s) and this permission notice appear in all copies of the Software and that both the above copyright notice(s) and this permission notice appear in supporting documentation. 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 OF THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. Except as contained in this notice, the name of a copyright holder shall not be used in advertising or otherwise to promote the sale, use or other dealings in this Software without prior written authorization of the copyright holder. -------------------------------------------------------------------------------- All trademarks and registered trademarks mentioned herein are the property of their respective owners. jv_thread.h is copied from Heimdal's lib/base/heimbase.h and some code in jv.c is copied from Heimdal's lib/base/dll.c: Portions Copyright (c) 2016 Kungliga Tekniska Högskolan (Royal Institute of Technology, Stockholm, Sweden). All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. jq uses a modified version of NetBSD implementation strptime(), which is distributed under the following license: Copyright (c) 1997, 1998, 2005, 2008 The NetBSD Foundation, Inc. All rights reserved. This code was contributed to The NetBSD Foundation by Klaus Klein. Heavily optimised by David Laight Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ================================================ FILE: ChangeLog ================================================ 2015-07-10 Nicolas Williams nico@cryptonector.com Use `include` for import into namespace Simplify import docs Fix typo in docs 2015-07-06 James Andariese james.andariese@locationlabs.com Dockerfile reorganized 2015-07-04 David Tolnay dtolnay@gmail.com Make jq.h usable from C++ 2015-07-03 Nicolas Williams nico@cryptonector.com Document math support 2015-06-30 David Tolnay dtolnay@gmail.com strftime wrong day-of-week (fix #838) 2015-06-28 Nicolas Williams nico@cryptonector.com Document --run-tests Make --run-tests' jv_test() quiet 2015-06-27 Nicolas Williams nico@cryptonector.com Make --run-tests less verbose by default Add more basic number tests Add `pow`, better libm detection (fix #443) 2015-06-27 David Tolnay dtolnay@gmail.com gcov exclusions flag to enable gcov and coveralls add configure option to run tests without valgrind 2015-06-20 David Tolnay dtolnay@gmail.com get Travis CI working 2015-06-26 Nicolas Williams nico@cryptonector.com Add `{$var}` `. as {$var}` syntax (fix #831) Add streaming utilities (fix #827) 2015-06-04 Santiago Lapresta santiago@typeform.com Add combinations/0 and combinations/1 2015-06-22 Nicolas Williams nico@cryptonector.com WriteFile() on WIN32 when stdout isatty (fix #824) 2015-06-19 David Tolnay dtolnay@gmail.com fix errors flagged by clang static analyzer 2015-06-19 Nicolas Williams nico@cryptonector.com Fix #811: use CommandLineToArgvW() and _wfopen() 2015-06-18 David Tolnay dtolnay@gmail.com fix use after free in f_strptime separate jq, oniguruma, sh, and man tests 2015-06-18 Nicolas Williams nico@cryptonector.com argv[] may not be UTF-8 (fix #811) 2015-06-18 Doug Luce doug@github.con.com Add alloca() discovery to configure.ac 2015-06-18 Nicolas Williams nico@cryptonector.com Fix `finites` 2015-06-17 David Tolnay dtolnay@gmail.com fix broken tests in manual.yml 2015-06-17 Nicolas Williams nico@cryptonector.com Add isnormal and related, rename *inf 2015-06-17 Nicolas Williams nico@cryptonector.com Fix #814: raise on div-0, add inf isinf nan isnan 2015-06-17 Nicolas Williams nico@cryptonector.com Sequence parser: wait for RS on startup (fix #687) 2015-06-07 David Tolnay dtolnay@gmail.com array and object destructuring (fix #533) 2015-06-03 Nicolas Williams nico@cryptonector.com Add --tab and -indent n options 2015-05-29 Nicolas Williams nico@cryptonector.com Fixup --slurpfile/argile docs Add --slurpfile Better handling of stdout errors 2015-05-25 Nicolas Williams nico@cryptonector.com Add ./configure --enable-all-static 2015-05-25 Nicolas Williams nico@cryptonector.com Keywords should be OK as object keys (fix #794) 2015-03-04 Travis Gockel travis@gockelhut.com Add wrapping and clamping to jv_array_slice 2015-04-17 Assaf Gordon assafgordon@gmail.com Print offending object in runtime error messages Add filename/line functions to jq (fix #753) 2015-04-17 Assaf Gordon assafgordon@gmail.com Report filename:line on runtime errors (fix #752) 2015-05-19 Nicolas Williams nico@cryptonector.com Document gsub/3 2015-05-03 Nicolas Williams nico@cryptonector.com Add error injection library 2015-04-28 Nicolas Williams nico@cryptonector.com Report read errors too (and fix #772) 2015-05-02 Nicolas Williams nico@cryptonector.com README: send questions to SO and Freenode 2015-04-28 Nicolas Williams nico@cryptonector.com usage() should check fprintf() result (fix #771) 2015-04-28 Nicolas Williams nico@cryptonector.com Fix header guards (fix #770) 2015-04-24 Nicolas Williams nico@cryptonector.com --raw-input wrongly adds NULs (fix #761) 2015-04-23 Nicolas Williams nico@cryptonector.com With `inputs` builtin, -n and -R can now coexist --raw-input ought to read NULs (partial fix #760) --slurp --raw-input is broken (fix #761) from_entries is broken (fix #767) 2015-04-22 Assaf Gordon assafgordon@gmail.com regex functions: report informative error if not available. 2015-04-21 Andrew O'Brien obrien.andrew@gmail.com Fixes manual generation with psych 2015-04-20 Assaf Gordon assafgordon@gmail.com Handle NUL in escaped-string output 2015-04-03 tal@whatexit.org tal@whatexit.org manual.yml: Clarify how to specify keys with ":" and special chars. 2015-04-15 Assaf Gordon assafgordon@gmail.com docs: expand @tsv section - add escape sequences. @tsv: escape \r, \n, \\ 2015-03-30 Nicolas Williams nico@cryptonector.com Add `$__loc__` (fix #740) 2015-03-29 Nicolas Williams nico@cryptonector.com Include filename and lineno in error messages 2015-03-06 Assaf Gordon assafgordon@gmail.com detect and report output writing errors 2015-03-18 Santiago Lapresta santiago.lapresta@gmail.com Adds Dockerfile 2015-03-10 Assaf Gordon assafgordon@gmail.com partial handling of input errors 2015-03-09 Assaf Gordon assafgordon@gmail.com always propagate input errors to exit code 2015-03-23 William Langford wlangfor@gmail.com Fix #735 (SIGFPE on modulo by 0) 2015-03-08 Nicolas Williams nico@cryptonector.com Add more date builtins Automake: jq depends on version.h (fix #721) 2015-03-06 Assaf Gordon assafgordon@gmail.com exit with non-zero code on runtime exceptions 2015-03-06 Nicolas Williams nico@cryptonector.com Add date builtins (fix #364) 2015-02-18 Stefan Seemayer stefan@seemayer.de Correct automake and autoconf version requirements 2015-02-17 Nicolas Williams nico@cryptonector.com Mention --disable-maintainer-mode in bison error 2015-02-16 Sebastian Freundt freundt@ga-group.nl Fix oniguruma detection logic 2015-02-15 Nicolas Williams nico@cryptonector.com Add --disable-maintainer-mode; make bison optional 2015-02-14 Nicolas Williams nico@cryptonector.com Make Oniguruma/regexp optional 2015-02-01 Nicolas Williams nico@cryptonector.com Refactor moar: move parts of main.c into libjq 2014-12-27 Nicolas Williams nico@cryptonector.com Refactor handling of inputs in main() (fix #667) 2015-02-10 Kim Toms kim.toms@bplglobal.net Enhance from_entries to better deal with Amazon AWS Tags 2015-01-26 Nicolas Williams nico@cryptonector.com Usage message for -h should go to stdout 2015-01-27 i isomorphisms@sdf.org readability 2015-01-14 Joel Purra code+github@joelpurra.com Empty arrays join/1 to an empty string, fixes #668 bug introduced by 9760245 2014-12-27 Nicolas Williams nico@cryptonector.com Add `debug` and `stderr` builtins 2015-01-13 Nicolas Williams nico@cryptonector.com join/1: respect empty strings (fix #668) 2015-01-13 Nicolas Williams nico@cryptonector.com Split on empty sep: fix #552 moar 2015-01-12 Nicolas Williams nico@cryptonector.com Fix docs for `split/0` 2015-01-12 Nicolas Williams nico@cryptonector.com Fix #552 2015-01-02 Nicolas Williams nico@cryptonector.com Look for jq/main.jq for imports 2015-01-01 Nicolas Williams nico@cryptonector.com Add static build instructions (fix #294) 2014-12-30 Nicolas Williams nico@cryptonector.com Further module system revamp (fix #659) 2014-12-28 Nicolas Williams nico@cryptonector.com Add `label $name | EXP`; fix `break` 2014-12-30 Nicolas Williams nico@cryptonector.com Remove string indexing by string (fix #454) 2014-12-30 Nicolas Williams nico@cryptonector.com Add support for testing erroneous programs 2014-12-30 Nicolas Williams nico@cryptonector.com Make --run-tests more informative 2014-10-06 pkoppstein pkoppstein@gmail.com transpose/0 for possibly jagged matrices 2014-10-07 pkoppstein pkoppstein@gmail.com bsearch(x) (binary search): builtin.c (tested), with documentation and test case. Always yields an integer (even if input is unsorted); returns (-1 - ix) if x is not in input array. 2014-10-06 pkoppstein pkoppstein@gmail.com ascii_upcase/0 and ascii_downcase/0 2014-12-27 Nicolas Williams nico@cryptonector.com Add `debug` builtin Don't force C API users to set input cb 2014-12-26 Nicolas Williams nico@cryptonector.com Make jq --run-tests show test line numbers Streaming parser torture tests Fuzz JSON parser 2014-12-22 Nicolas Williams nico@cryptonector.com Add Streaming parser (--stream) 2014-12-26 Nicolas Williams nico@cryptonector.com Allow C-coded functions to `empty` Add BLOCK_8() macro Fix `foreach` non-propagation of errors Allow zero-length buffers in jv_parser_set_buf() 2014-12-24 Nicolas Williams nico@cryptonector.com Add @tsv; fix #645 Module search revamp for pkg managers Fix #348: reject unescaped control chars 2014-12-23 Nicolas Williams nico@cryptonector.com Use __attribute__ __printf__ with GCC Make `values` faster (fix #652) 2014-12-22 Marc Abramowitz marc@marc-abramowitz.com .travis.yml: Set sudo false; use containers 2014-12-22 Santiago Lapresta santiago.lapresta@gmail.com Define `map_values` 2014-05-21 Santiago Lapresta santiago.lapresta@gmail.com `in` is now `inside`, added `in` as inverse of `has` 2014-05-20 Santiago Lapresta santiago.lapresta@gmail.com Added `in` command 2014-12-21 Eiichi Sato sato.eiichi@gmail.com Fix examples in manual Fix indents in manual.yml HTML-escape jq programs in manual Fix examples in manual 2014-12-12 Nicolas Williams nico@cryptonector.com Add until(cond; next); fix #639 Add --argjson, fix #648 2014-11-29 Nicolas Williams nico@cryptonector.com Fix refcount leak, fix #618 2014-11-28 Nicolas Williams nico@cryptonector.com STOREV/LOADV* should also print refcnts Enable printing of stack val refcnts Print stack value refcounts when tracing (#636) 2014-11-23 Colin von Heuring colin@janrain.com Doc correction 2014-11-11 Ian Miell ian.miell@gmail.com Requirements made slightly more complete: cf https://github.com/ianmiell/shutit/blob/master/library/jq/jq.py 2014-11-05 Steven Maude StevenMaude@users.noreply.github.com Fix typos in tutorial 2014-10-21 Santiago Lapresta santiago.lapresta@gmail.com Define {any,all}/2 independently from {any,all}/0 2014-10-20 Santiago Lapresta santiago.lapresta@gmail.com Define {any,all}/{0,1} in terms of {any,all}/2 2014-10-10 Nicolas Williams nico@cryptonector.com Add support for JSON sequence MIME type 2014-10-06 William Langford wlangfor@gmail.com Properly call onig_error_code_to_str 2014-10-06 pkoppstein pkoppstein@gmail.com fix sub (#586); add gsub/3; add transpose/0. 2014-10-03 Nicolas Williams nico@cryptonector.com Update docs about sort/group/min/max/unique from-entries should work with EC2 (fix #592) Remove sort/1 and group/1 2014-09-30 Nicolas Williams nico@cryptonector.com to_entries should not sort keys (fix #561) 2014-09-22 William Langford wlangfor@gmail.com Properly handle when objects cannot be folded 2014-08-30 Nicolas Williams nico@cryptonector.com Drop the jq version directory from search path Never close stdin; allow multiple `-` arguments Handle invalid inputs in argument files (fix #562) 2014-08-28 William Langford wlangfor@gmail.com Properly handle incomplete json when input is file 2014-08-10 Nicolas Williams nico@cryptonector.com Add `module` directive, `modulemeta` builtin 2014-08-09 Nicolas Williams nico@cryptonector.com Constant fold objects Fold constant arrays More constant folding: null, true, and false `.foo[-1] = ...` trips assertion (fix #490) Allow any number of jq-coded function arguments 2014-08-08 Nicolas Williams nico@cryptonector.com Make regexp builtins and range/3 use #524 too Use `def f($a): ...;` syntax for builtins Add `def f($arg):` syntax (fix #524) 2014-07-31 pkoppstein pkoppstein@gmail.com regex filters (#432): scan, splits, split, sub, gsub 2014-08-06 Nicolas Williams nico@cryptonector.com Better error msg for bad shell quoting (fix #538) 2014-08-04 William Langford wlangfor@gmail.com Actually check version for bison. 2014-08-03 pkoppstein pkoppstein@gmail.com Apply TCO to recurse/1, add recurse/2; tweak docs 2014-08-01 Adam Lindberg hello@alind.io Add example of selecting object with keys 2014-07-19 pkoppstein pkoppstein@gmail.com Add capture; document regular expression filters 2014-07-28 Nicolas Williams nico@cryptonector.com Add `first`, `nth`, `last` (fix #510) 2014-07-27 Nicolas Williams nico@cryptonector.com Fold constants (fix #504) 2014-07-21 William Langford wlangfor@gmail.com Changing color codes to fix #495 2014-07-09 William Langford wlangfor@gmail.com Added library system with -l, -L, and JQ_LIBRARY_PATH 2014-07-14 Simon Elsbrock simon@iodev.org jq 1.4 is in Debian 2014-07-13 Marc Bruggmann marcbr@spotify.com Fix manual example for `endswith`. 2014-07-09 Hanfei Shen qqshfox@gmail.com Fix examples for `del` in manual 2014-07-08 Zhiming Wang zmwangx@gmail.com Fix invalid YAML in manual.yml Add tests/all.trs to .gitignore 2014-07-09 Nicolas Williams nico@cryptonector.com Better document `path()`'s power; also `|=` Add `foreach EXP as $var (INIT; UPDATE)` form Make `while()` handle `break` 2014-07-07 Nicolas Williams nico@cryptonector.com Make C-coded built-ins take `jq_state *` argument `error(x)` should not `tostring` its arg; fix #466 `limit` should use `break` Make `any/2` and `all/2` efficient using `foreach` 2013-12-24 Nicolas Williams nico@cryptonector.com jv_invalid() shouldn't allocate 2013-12-31 Nicolas Williams nico@cryptonector.com jv_show() should be able to display invalid values 2014-07-07 Nicolas Williams nico@cryptonector.com Add `break` builtin for `foreach` Explain `foreach`'s powers a bit more Document `path(path_expression)` builtin $var["foo"]=1 can't work as expected; doc fix #236 Better check for lib has only functions (fix #138) 2014-07-06 Nicolas Williams nico@cryptonector.com Add `any/N` and `all/N` x N in (1, 2) (fix #455) Add `foreach` and `limit` 2014-07-04 William Langford wlangfor@gmail.com Add support for negative indices for .[]; fix #462 2014-07-06 Nicolas Williams nico@cryptonector.com Add general `?` operator 2014-07-05 Nicolas Williams nico@cryptonector.com Add `try EXP catch EXP` 2014-07-06 Nicolas Williams nico@cryptonector.com Document `error/1` 2014-07-02 Nicolas Williams nico@cryptonector.com Add `while(cond; update)` (fix #314) Add `range(init;upto;by)` (fix #317) 2014-07-01 Nicolas Williams nico@cryptonector.com Describe generators, range() with by to manual 2014-07-01 William Langford wlangfor@gmail.com Fixed base64 issue with UTF-8 strings 2014-06-30 Nicolas Williams nico@cryptonector.com TCO to the max! 2014-06-25 William Langford wlangfor@gmail.com Added cross-compilation script to build libjq for iOS. 2014-06-29 Zhiming Wang zmwangx@gmail.com Let @uri produce uppercase hexadecimal digits... 2014-06-24 Nicolas Williams nico@cryptonector.com Get "Try Online" button working (fix #440) 2014-06-22 Nicolas Williams nico@cryptonector.com Tail call optimization (close #437) 2014-06-20 Nicolas Williams nico@cryptonector.com Allow stacking of short options (fix #346) 2014-06-18 William Langford wlangfor@gmail.com Added regex support as per issue #164. 2014-06-17 Nicolas Williams nico@cryptonector.com Add `-j` / `--join-output` option, similar to `-r` 2014-06-18 Santiago Lapresta santiago.lapresta@gmail.com Simplified standard library 2014-06-16 Nicolas Williams nico@cryptonector.com Fix #280: from_entries of [] is null, should be {} 2014-06-16 Nicolas Williams nico@cryptonector.com No args default w/ tty stdout, not tty stdin #220 2014-06-16 Santiago Lapresta santiago.lapresta@gmail.com Added `flatten` and `flatten(x)` functions 2014-06-16 Nicolas Williams nico@cryptonector.com Add ChangeLog and NEWS files 2014-06-14 Nicolas Williams nico@cryptonector.com Allow multiple functions with different arities 2014-06-13 Nicolas Williams nico@cryptonector.com Add `env` builtin 2014-06-13 Nicolas Williams nico@cryptonector.com Document the lambda nature of function args #391 2014-06-13 Nicolas Williams nico@cryptonector.com Add jqplay link to the site 2014-06-12 Jingwen Owen Ou jingweno@gmail.com jqplay has a domain now 2014-06-12 Nicolas Williams nico@cryptonector.com Make a better jq.1 when Ruby deps missing 2014-06-11 Kim De Mey kim.demey@gmail.com Detect endianness at configuration with Autoconf AC_C_BIGENDIAN feature 2014-06-09 Nicolas Williams Add libm.h to dist file list Add note about cmd.exe quoting Building docs fails on powerpc (#349) 2014-06-08 Nicolas Williams 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 Added `join` function 2014-06-07 Nicolas Williams String * number should be commutative 2014-06-04 Nicolas Williams 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 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 Documented `del` command 2014-05-11 Santiago Lapresta Added texts/examples to unique_by function Added unique_by function 2014-04-17 Nicolas Williams 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 Add autoconf checks for pthreads; fix #340 2014-03-20 Jingwen Owen Ou Add link to jqplay 2014-03-13 Nicolas Williams Fix for #303 in the sources 2014-03-13 Santiago Lapresta 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 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 Make libm tests more portable 2014-02-26 Andrew Rodland Repair jv_show 2014-02-26 Andrew Rodland 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 Add cbrt (cube root) Add missing trig functions and barebones test Remove non-standard exp10() 2014-02-21 Mike McCabe Initial add of math functions. 2014-02-20 Nicolas Williams 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 Added `all` and `any` builtins 2014-01-25 polyester 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 Fix #201; check that bison accepts --warnings 2013-12-27 Joe Littlejohn 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 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 Document --version 2013-12-26 Nicolas Williams 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 Document .foo.bar in manual Document exit numbers Normalize errors for -e 2013-12-25 Nicolas Williams Fix doc typos (.[foo] wanted to be .["foo"]) Add note to jq.1 about shell quoting 2013-12-20 Philipp Hagemeister 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 Allow negated object values without parens. Fixes #247 2013-12-17 Nicolas Williams Fix memmem() error 2013-12-13 Rémy Léone 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 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 Complete more-arity feature not complete And test 2013-12-10 David R. MacIver 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 some functions were missing prototypes. Add them 2013-12-08 David R. MacIver These vfprintfs are being used as if they were printfs. Fix that consistent use of goto out in main 2013-12-08 Stephen Dolan 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 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 Fix double-free typo in print_error() Fix manual.yml 2013-12-04 Nicolas Williams 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 Preserve insertion order in objects. Closes #169. 2013-11-30 Nicolas Pouillard Add a few more test cases (from the man page) 2013-11-08 Stephen Dolan Add a --unbuffered option. Closes #206 2013-11-07 Peter van Dijk count should be length Example refers to a count function, which does not exist. Replacing it with length works. 2013-11-07 Stephen Dolan Fix a crash on group_by of empty list. Fixes #208. 2013-10-16 Ryoichi KATO Docs: add description of --from-file option 2013-10-06 Juan Guerrero Fix typo on error message 2013-09-19 Kenny Shen Add missing -i flag in build instructions 2013-09-14 Michael Daines Add test showing calculation of standard deviation 2013-09-13 Mike Daines Fix typo 2013-09-11 Michael Daines Add sqrt operator 2013-09-04 Jack Pearkes docs: update the tutorial to use GitHub's API 2013-09-01 Ankur Call AM_INIT_AUTOMAKE once only Fixes build with automake-1.14 2013-08-19 Joe Littlejohn Fix Makefile after refactoring of stacks in 05d90517b02 2013-06-23 Stephen Dolan 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 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 resynchronise correctly after broken sequences. Fix example in manual for `floor`. See #155. 2013-06-21 Nicolas Williams 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 Move cfunction invocation code to the interpreter loop. 2013-06-18 Nicolas Williams Fix serious bug in handling of --argfile Fix leaks in jv_load_file() 2013-06-17 Stephen Dolan 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 Remove accidentally introduced use of fopen "e" 2013-06-16 Stephen Dolan Merge pull request #114 from nicowilliams/nomem_handler Add jv_nomem_handler() 2013-06-16 Nicolas Williams Remove last remnant of main.h 2013-06-15 Nicolas Williams Allow --run-tests to take a file argument Fixup API to get closer to a libjq 2013-06-15 Nicolas Williams Move slurp_file() into library as jv_load_file() Needed as part of creating a libjq. 2013-06-14 Stephen Dolan Clean up lots of stack and frame logic. Move frame defs to execute.c 2013-06-13 Stephen Dolan Simplify frame logic. Unify all stacks. Passes tests, but needs cleanup. 2013-06-11 Stephen Dolan Support ."foo" syntax for accessing fields. See #141. 2013-06-09 Stephen Dolan Unify frame and data stacks 2013-06-05 Stephen Dolan 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 Update README.md Update the link to the documentation. All GitHub pages are now using the github.io domain. 2013-06-03 Stephen Dolan 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 Stop warning on fgets, simple version Stop warning on fgets, complex version 2013-05-31 Stephen Dolan Squash a warning on some GCC versions 2013-05-29 Stephen Dolan Support for printing object keys in sorted order. No command-line option to enable this yet. See #79. 2013-05-29 Brendan Macmillan 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 Make jq --version report an actual git revision. Closes #129. 2013-05-23 Nicolas Williams 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 'make clean' won't delete jq.1 if it can't be rebuilt. See #131 ================================================ FILE: Dockerfile ================================================ FROM debian:12-slim AS builder ENV DEBIAN_FRONTEND=noninteractive \ DEBCONF_NONINTERACTIVE_SEEN=true \ LC_ALL=C.UTF-8 \ LANG=C.UTF-8 RUN apt-get update \ && apt-get install -y \ build-essential \ autoconf \ libtool \ git \ && apt-get clean \ && rm -rf /var/lib/apt/lists/* WORKDIR /app COPY . /app RUN autoreconf -i \ && ./configure \ --disable-docs \ --with-oniguruma=builtin \ --enable-static \ --enable-all-static \ --prefix=/usr/local \ && make -j$(nproc) \ && make check VERBOSE=yes \ && make install-strip FROM scratch COPY --from=builder /app/AUTHORS /app/COPYING /usr/local/bin/jq / RUN ["/jq", "--version"] ENTRYPOINT ["/jq"] ================================================ FILE: KEYS ================================================ pub 4096R/71523402 2015-10-11 Key fingerprint = 4FD7 01D6 FA9B 3D2D F5AC 935D AF19 040C 7152 3402 uid jq Release Signing Key pub 2048R/D15684DB 2015-10-12 [expires: 2017-10-11] Key fingerprint = 7F6C 7BD3 0412 AFD5 8C1A 5007 EB26 A4F8 D156 84DB uid Nicolas Williams sub 2048R/9C9CCD6A 2015-10-12 [expires: 2017-10-11] ================================================ FILE: Makefile.am ================================================ ### C source files to be built and distributed. LIBJQ_INCS = src/builtin.h src/bytecode.h src/compile.h \ src/exec_stack.h src/jq_parser.h src/jv_alloc.h src/jv_dtoa.h \ src/jv_unicode.h src/jv_utf8_tables.h src/lexer.l src/libm.h \ src/linker.h src/locfile.h src/opcode_list.h src/parser.y \ src/util.h src/jv_dtoa_tsd.h src/jv_thread.h src/jv_private.h \ vendor/decNumber/decContext.h vendor/decNumber/decNumber.h \ vendor/decNumber/decNumberLocal.h LIBJQ_SRC = src/builtin.c src/bytecode.c src/compile.c src/execute.c \ src/jq_test.c src/jv.c src/jv_alloc.c src/jv_aux.c \ src/jv_dtoa.c src/jv_file.c src/jv_parse.c src/jv_print.c \ src/jv_unicode.c src/linker.c src/locfile.c src/util.c \ src/jv_dtoa_tsd.c \ vendor/decNumber/decContext.c vendor/decNumber/decNumber.c \ ${LIBJQ_INCS} ### C build options AM_CFLAGS = -Wextra -Wall -Wno-unused-parameter -Wno-unused-function \ -Woverlength-strings -Wstrict-prototypes if WIN32 AM_CFLAGS += -municode endif 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 if MAINTAINER_MODE BUILT_SOURCES = src/lexer.h src/lexer.c src/parser.h src/parser.c \ src/builtin.inc src/config_opts.inc src/version.h src/lexer.c: src/lexer.l $(AM_V_LEX) flex -o src/lexer.c --header-file=src/lexer.h $< src/lexer.h: src/lexer.c else BUILT_SOURCES = src/builtin.inc src/config_opts.inc src/version.h .y.c: $(AM_V_YACC) echo "NOT building parser.c!" .l.c: $(AM_V_LEX) echo "NOT building lexer.c!" endif # Tell YACC (Bison) autoconf macros that you want a header file created. # If the --warnings=all fails, you probably have an old version of Bison # macOS ships an old Bison, so update with Homebrew or MacPorts. AM_YFLAGS = --warnings=all -Wno-yacc -d ### libjq lib_LTLIBRARIES = libjq.la libjq_la_SOURCES = ${LIBJQ_SRC} libjq_la_LIBADD = -lm libjq_la_LDFLAGS = $(onig_LDFLAGS) -export-symbols-regex '^j[qv]_' -version-info 1:4:0 if WIN32 libjq_la_LIBADD += -lshlwapi libjq_la_LDFLAGS += -no-undefined endif include_HEADERS = src/jv.h src/jq.h AM_CPPFLAGS = -I$(srcdir)/src -I$(srcdir)/vendor ### Address sanitizer (ASan) if ENABLE_ASAN AM_CFLAGS += -fsanitize=address endif ### Undefined Behavior Sanitizer if ENABLE_UBSAN AM_CFLAGS += -fsanitize=undefined endif ### Code coverage with gcov if ENABLE_GCOV AM_CFLAGS += --coverage --no-inline endif ### Error injection for testing if ENABLE_ERROR_INJECTION lib_LTLIBRARIES += libinject_errors.la libinject_errors_la_SOURCES = src/inject_errors.c libinject_errors_la_LIBADD = -ldl libinject_errors_la_LDFLAGS = -module endif ### 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)' ; } | xargs printf '\043define JQ_VERSION \"%s\"\n'`" .remake-version-h: .FORCE @ $(generate_ver); test "x`cat src/version.h 2>/dev/null`" = "x$$ver" || touch .remake-version-h src/version.h: .remake-version-h mkdir -p src $(AM_V_GEN) $(generate_ver); echo "$$ver" > $@ src/config_opts.inc: mkdir -p src $(AM_V_GEN) if test -x ./config.status; then \ ./config.status --config; \ else echo "(unknown)"; \ fi | sed -e 's/\\/\\\\/g' -e 's/"/\\"/g' -e 's/^/"/' -e 's/$$/"/' -e 's/^/#define JQ_CONFIG /' > $@ src/main.c: src/version.h src/config_opts.inc src/builtin.inc: $(srcdir)/src/builtin.jq mkdir -p src $(AM_V_GEN) od -v -A n -t o1 -- $< | \ sed -e 's/$$/ /' \ -e 's/\([0123456789]\) /\1, /g' \ -e 's/ $$//' \ -e 's/ 0/ 0/g' \ -e 's/ \([123456789]\)/ 0\1/g' > $@ src/builtin.o: src/builtin.inc CLEANFILES = src/version.h .remake-version-h src/builtin.inc src/config_opts.inc bin_PROGRAMS = jq jq_SOURCES = src/main.c jq_LDADD = libjq.la -lm if ENABLE_ALL_STATIC jq_LDFLAGS = -all-static endif ### Tests (make check) TESTS = tests/mantest tests/jqtest tests/shtest tests/utf8test tests/base64test tests/uritest if !WIN32 TESTS += tests/optionaltest endif AM_TESTS_ENVIRONMENT = JQ=$(abs_builddir)/jq if ENABLE_VALGRIND AM_TESTS_ENVIRONMENT += ENABLE_VALGRIND=1 endif # This is a magic make variable that causes it to treat tests/man.test as a # DATA-type dependency for the check target. As a result, it will attempt to # run any defined targets for tests/man.test as a dependency for check. This # allows us to ensure that the tests are up-to-date if the manual has been updated check_DATA = tests/man.test ### Building the man tests # We use the examples in the manual as additional tests, to ensure they always work. # As a result, we need to rebuild the tests if the manual has been updated. # Making changes to the manpage without having the python deps means your # tests won't run. If you aren't making changes to the examples, you probably # don't care. But if you are, then you need to run the tests anyway. tests/man.test tests/manonig.test: $(srcdir)/docs/content/manual/dev/manual.yml if ENABLE_DOCS $(AM_V_GEN) ( cd ${abs_srcdir}/docs && \ $(PIPENV) run python validate_manual_schema.py content/manual/dev/manual.yml && \ $(PIPENV) run python build_mantests.py ) else @echo Changes to the manual.yml require docs to be enabled to update the manual test. @echo As a result, the manual test is out of date. endif ### Building the manpage # We build the docs from the manpage yml. If no changes have been made to the # manpage, then we'll end up using the cached version. Otherwise, we need to # rebuild it. man_MANS = jq.1 jq.1.prebuilt: $(srcdir)/docs/content/manual/dev/manual.yml if ENABLE_DOCS $(AM_V_GEN) ( cd ${abs_srcdir}/docs && \ $(PIPENV) run python validate_manual_schema.py content/manual/dev/manual.yml && \ $(PIPENV) run python build_manpage.py ) > $@ else @echo Changes to the manual.yml require docs to be enabled to update the manpage. @echo As a result, the manpage is out of date. endif jq.1: jq.1.prebuilt $(AM_V_GEN) cp $(srcdir)/jq.1.prebuilt $@ CLEANFILES += jq.1 ### Build oniguruma if BUILD_ONIGURUMA libjq_la_LIBADD += vendor/oniguruma/src/.libs/libonig.la jq_LDADD += vendor/oniguruma/src/.libs/libonig.la SUBDIRS = vendor/oniguruma endif AM_CFLAGS += $(onig_CFLAGS) if WITH_ONIGURUMA TESTS += tests/onigtest tests/manonigtest endif ### Packaging install-binaries: $(BUILT_SOURCES) $(MAKE) $(AM_MAKEFLAGS) install-exec DOC_FILES = docs/content docs/public docs/templates \ docs/Pipfile docs/Pipfile.lock docs/build_manpage.py \ docs/build_mantests.py docs/build_website.py docs/README.md \ docs/validate_manual_schema.py docs/manual_schema.yml EXTRA_DIST = $(DOC_FILES) $(man_MANS) $(TESTS) $(TEST_LOG_COMPILER) \ jq.1.prebuilt jq.spec src/lexer.c src/lexer.h src/parser.c \ src/parser.h src/version.h src/builtin.jq scripts/version \ libjq.pc \ tests/modules/a.jq tests/modules/b/b.jq tests/modules/c/c.jq \ tests/modules/c/d.jq tests/modules/data.json \ tests/modules/home1/.jq tests/modules/home2/.jq/g.jq \ tests/modules/lib/jq/e/e.jq tests/modules/lib/jq/f.jq \ tests/modules/shadow1.jq tests/modules/shadow2.jq \ tests/modules/syntaxerror/syntaxerror.jq \ tests/modules/test_bind_order.jq \ tests/modules/test_bind_order0.jq \ tests/modules/test_bind_order1.jq \ tests/modules/test_bind_order2.jq \ tests/onig.supp tests/local.supp \ tests/setup tests/torture/input0.json \ tests/optional.test tests/man.test tests/manonig.test \ tests/jq.test tests/onig.test tests/base64.test tests/uri.test \ tests/jq-f-test.sh \ tests/no-main-program.jq tests/yes-main-program.jq AM_DISTCHECK_CONFIGURE_FLAGS=--with-oniguruma=builtin # 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. dist_doc_DATA = README.md NEWS.md COPYING AUTHORS pkgconfigdir = $(libdir)/pkgconfig pkgconfig_DATA = libjq.pc RELEASE ?= 1 rpm: dist jq.spec @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 find rpm/RPMS/ -name "*.rpm" -exec mv {} ./ \; rm -rf rpm ================================================ FILE: NEWS.md ================================================ # 1.8.1 This is a patch release to fix security, performance, and build issues found in 1.8.0. Full commit log can be found at . ## Security fixes - CVE-2025-49014: Fix heap use after free in `f_strftime`, `f_strflocaltime`. @wader 499c91bca9d4d027833bc62787d1bb075c03680e - GHSA-f946-j5j2-4w5m: Fix stack overflow in `node_min_byte_len` of oniguruma. @wader 5e159b34b179417e3e0404108190a2ac7d65611c ## CLI changes - Fix assertion failure when syntax error happens at the end of the query. @itchyny #3350 ## Changes to existing functions - Fix portability of `strptime/1` especially for Windows. @itchyny #3342 ## Language changes - Revert the change of `reduce`/`foreach` state variable in 1.8.0 (#3205). This change was reverted due to serious performance regression. @itchyny #3349 ## Documentation changes - Add LICENSE notice of NetBSD's `strptime()` to COPYING. @itchyny #3344 ## Build improvements - Fix build on old Mac with old sed. @qianbinbin #3336 # 1.8.0 We are pleased to announce the release of version 1.8.0. This release includes a number of improvements since the last version. Note that some changes may introduce breaking changes to existing scripts, so be sure to read the following information carefully. Full commit log can be found at . ## Releasing - Change the version number pattern to `1.X.Y` (`1.8.0` instead of `1.8`). @itchyny #2999 - Generate provenance attestations for release artifacts and docker image. @lectrical #3225 ```sh gh attestation verify --repo jqlang/jq jq-linux-amd64 gh attestation verify --repo jqlang/jq oci://ghcr.io/jqlang/jq:1.8.0 ``` ## Security fixes - CVE-2024-23337: Fix signed integer overflow in `jvp_array_write` and `jvp_object_rehash`. @itchyny de21386681c0df0104a99d9d09db23a9b2a78b1e - The fix for this issue now limits the maximum size of arrays and objects to 536870912 (`2^29`) elements. - CVE-2024-53427: Reject NaN with payload while parsing JSON. @itchyny a09a4dfd55e6c24d04b35062ccfe4509748b1dd3 - The fix for this issue now drops support for NaN with payload in JSON (like `NaN123`). Other JSON extensions like `NaN` and `Infinity` are still supported. - CVE-2025-48060: Fix heap buffer overflow in `jv_string_vfmt`. @itchyny c6e041699d8cd31b97375a2596217aff2cfca85b - Fix use of uninitialized value in `check_literal`. @itchyny #3324 - Fix segmentation fault on `strftime/1`, `strflocaltime/1`. @itchyny #3271 - Fix unhandled overflow in `@base64d`. @emanuele6 #3080 ## CLI changes - Fix `--indent 0` implicitly enabling `--compact-output`. @amarshall @gbrlmarn @itchyny #3232 ```sh $ jq --indent 0 . <<< '{ "foo": ["hello", "world"] }' { "foo": [ "hello", "world" ] } # Previously, this implied --compact-output, but now outputs with new lines. ``` - Improve error messages to show problematic position in the filter. @itchyny #3292 ```sh $ jq -n '1 + $foo + 2' jq: error: $foo is not defined at , line 1, column 5: 1 + $foo + 2 ^^^^ jq: 1 compile error ``` - Include column number in parser and compiler error messages. @liviubobocu #3257 - Fix error message for string literal beginning with single quote. @mattmeyers #2964 ```sh $ jq .foo <<< "{'foo':'bar'}" jq: parse error: Invalid string literal; expected ", but got ' at line 1, column 7 # Previously, the error message was Invalid numeric literal at line 1, column 7. ``` - Improve `JQ_COLORS` environment variable to support larger escapes like truecolor. @SArpnt #3282 ```sh JQ_COLORS="38;2;255;173;173:38;2;255;214;165:38;2;253;255;182:38;2;202;255;191:38;2;155;246;255:38;2;160;196;255:38;2;189;178;255:38;2;255;198;255" jq -nc '[null,false,true,42,{"a":"bc"}]' ``` - Add `--library-path` long option for `-L`. @thaliaarchi #3194 - Fix `--slurp --stream` when input has no trailing newline character. @itchyny #3279 - Fix `--indent` option to error for malformed values. @thaliaarchi #3195 - Fix option parsing of `--binary` on non-Windows platforms. @calestyo #3131 - Fix issue with `~/.jq` on Windows where `$HOME` is not set. @kirkoman #3114 - Fix broken non-Latin output in the command help on Windows. @itchyny #3299 - Increase the maximum parsing depth for JSON to 10000. @itchyny #3328 - Parse short options in order given. @thaliaarchi #3194 - Consistently reset color formatting. @thaliaarchi #3034 ## New functions - Add `trim/0`, `ltrim/0` and `rtrim/0` to trim leading and trailing white spaces. @wader #3056 ```sh $ jq -n '" hello " | trim, ltrim, rtrim' "hello" "hello " " hello" ``` - Add `trimstr/1` to trim string from both ends. @gbrlmarn #3319 ```sh $ jq -n '"foobarfoo" | trimstr("foo")' "bar" ``` - Add `add/1`. Generator variant of `add/0`. @myaaaaaaaaa #3144 ```sh $ jq -c '.sum = add(.xs[])' <<< '{"xs":[1,2,3]}' {"xs":[1,2,3],"sum":6} ``` - Add `skip/2` as the counterpart to `limit/2`. @itchyny #3181 ```sh $ jq -nc '[1,2,3,4,5] | [skip(2; .[])]' [3,4,5] ``` - Add `toboolean/0` to convert strings to booleans. @brahmlower @itchyny #2098 ```sh $ jq -n '"true", "false" | toboolean' true false ``` - Add `@urid` format. Reverse of `@uri`. @fmgornick #3161 ```sh $ jq -Rr '@urid' <<< '%6a%71' jq ``` ## Changes to existing functions - Use code point index for `indices/1`, `index/1` and `rindex/1`. @wader #3065 - This is a breaking change. Use `utf8bytelength/0` to get byte index. - Improve `tonumber/0` performance and rejects numbers with leading or trailing white spaces. @itchyny @thaliaarchi #3055 #3195 - This is a breaking change. Use `trim/0` to remove leading and trailing white spaces. - Populate timezone data when formatting time. This fixes timezone name in `strftime/1`, `strflocaltime/1` for DST. @marcin-serwin @sihde #3203 #3264 #3323 - Preserve numerical precision on unary negation, `abs/0`, `length/0`. @itchyny #3242 #3275 - Make `last(empty)` yield no output values like `first(empty)`. @itchyny #3179 - Make `ltrimstr/1` and `rtrimstr/1` error for non-string inputs. @emanuele6 #2969 - Make `limit/2` error for negative count. @itchyny #3181 - Fix `mktime/0` overflow and allow fewer elements in date-time representation array. @emanuele6 #3070 #3162 - Fix non-matched optional capture group. @wader #3238 - Provide `strptime/1` on all systems. @george-hopkins @fdellwing #3008 #3094 - Fix `_WIN32` port of `strptime`. @emanuele6 #3071 - Improve `bsearch/1` performance by implementing in C. @eloycoto #2945 - Improve `unique/0` and `unique_by/1` performance. @itchyny @emanuele6 #3254 #3304 - Fix error messages including long string literal not to break Unicode characters. @itchyny #3249 - Remove `pow10/0` as it has been deprecated in glibc 2.27. Use `exp10/0` instead. @itchyny #3059 - Remove private (and undocumented) `_nwise` filter. @itchyny #3260 ## Language changes - Fix precedence of binding syntax against unary and binary operators. Also, allow some expressions as object values. @itchyny #3053 #3326 - This is a breaking change that may change the output of filters with binding syntax as follows. ```sh $ jq -nc '[-1 as $x | 1,$x]' [1,-1] # previously, [-1,-1] $ jq -nc '1 | . + 2 as $x | -$x' -3 # previously, -1 $ jq -nc '{x: 1 + 2, y: false or true, z: null // 3}' {"x":3,"y":true,"z":3} # previously, syntax error ``` - Support Tcl-style multiline comments. @emanuele6 #2989 ```sh #!/bin/sh -- # Can be use to do shebang scripts. # Next line will be seen as a comment be of the trailing backslash. \ exec jq ... # this jq expression will result in [1] [ 1, # \ 2 ] ``` - Fix `foreach` not to break init backtracking with `DUPN`. @kanwren #3266 ```sh $ jq -n '[1, 2] | foreach .[] as $x (0, 1; . + $x)' 1 3 2 4 ``` - Fix `reduce`/`foreach` state variable should not be reset each iteration. @itchyny #3205 ```sh $ jq -n 'reduce range(5) as $x (0; .+$x | select($x!=2))' 8 $ jq -nc '[foreach range(5) as $x (0; .+$x | select($x!=2); [$x,.])]' [[0,0],[1,1],[3,4],[4,8]] ``` - Support CRLF line breaks in filters. @itchyny #3274 - Improve performance of repeating strings. @itchyny #3272 ## Documentation changes - Switch the homepage to custom domain [jqlang.org](https://jqlang.org). @itchyny @owenthereal #3243 - Make latest release instead of development version the default manual. @wader #3130 - Add opengraph meta tags. @wader #3247 - Replace jqplay.org with play.jqlang.org @owenthereal #3265 - Add missing line from decNumber's licence to `COPYING`. @emanuele6 #3106 - Various document improvements. @tsibley #3322, @itchyny #3240, @jhcarl0814 #3239, @01mf02 #3184, @thaliaarchi #3199, @NathanBaulch #3173, @cjlarose #3164, @sheepster1 #3105, #3103, @kishoreinvits #3042, @jbrains #3035, @thalman #3033, @SOF3 #3017, @wader #3015, @wllm-rbnt #3002 ## Build improvements - Fix build with GCC 15 (C23). @emanuele6 #3209 - Fix build with `-Woverlength-strings` @emanuele6 #3019 - Fix compiler warning `type-limits` in `found_string`. @itchyny #3263 - Fix compiler error in `jv_dtoa.c` and `builtin.c`. @UlrichEckhardt #3036 - Fix warning: a function definition without a prototype is deprecated. @itchyny #3259 - Define `_BSD_SOURCE` in `builtin.c` for OpenBSD support. @itchyny #3278 - Define empty `JV_{,V}PRINTF_LIKE` macros if `__GNUC__` is not defined. @emanuele6 #3160 - Avoid `ctype.h` abuse: cast `char` to `unsigned char` first. @riastradh #3152 - Remove multiple calls to free when successively calling `jq_reset`. @Sameesunkaria #3134 - Enable IBM z/OS support. @sachintu47 #3277 - Fix insecure `RUNPATH`. @orbea #3212 - Avoid zero-length `calloc`. @itchyny #3280 - Move oniguruma and decNumber to vendor directory. @itchyny #3234 ## Test improvements - Run tests in C locale. @emanuele6 #3039 - Improve reliability of `NO_COLOR` tests. @dag-erling #3188 - Improve `shtest` not to fail if `JQ_COLORS` and `NO_COLOR` are already set. @SArpnt #3283 - Refactor constant folding tests. @itchyny #3233 - Make tests pass when `--disable-decnum`. @nicowilliams 6d02d53f515bf1314d644eee93ba30b0d11c7d2b - Disable Valgrind by default during testing. @itchyny #3269 # 1.7.1 ## Security - CVE-2023-50246: Fix heap buffer overflow in jvp\_literal\_number\_literal - CVE-2023-50268: fix stack-buffer-overflow if comparing nan with payload ## CLI changes - Make the default background color more suitable for bright backgrounds. @mjarosie @taoky @nicowilliams @itchyny #2904 - Allow passing the inline jq script after `--`. @emanuele6 #2919 - Restrict systems operations on OpenBSD and remove unused `mkstemp`. @klemensn #2934 - Fix possible uninitialised value dereference if `jq_init()` fails. @emanuele6 @nicowilliams #2935 ## Language changes - Simplify `paths/0` and `paths/1`. @asheiduk @emanuele6 #2946 - Reject `U+001F` in string literals. @torsten-schenk @itchyny @wader #2911 - Remove unused nref accumulator in `block_bind_library`. @emanuele6 #2914 - Remove a bunch of unused variables, and useless assignments. @emanuele6 #2914 - main.c: Remove unused EXIT\_STATUS\_EXACT option. @emanuele6 #2915 - Actually use the number correctly casted from double to int as index. @emanuele6 #2916 - src/builtin.c: remove unnecessary jv\_copy-s in type\_error/type\_error2. @emanuele6 #2937 - Remove undefined behavior caught by LLVM 10 UBSAN. @Gaelan @emanuele6 #2926 - Convert decnum to binary64 (double) instead of decimal64. This makes jq behave like the JSON specification suggests and more similar to other languages. @wader @leonid-s-usov #2949 - Fix memory leaks on invalid input for `ltrimstr/1` and `rtrimstr/1`. @emanuele6 #2977 - Fix memory leak on failed get for `setpath/2`. @emanuele6 #2970 - Fix nan from json parsing also for nans with payload that start with 'n'. @emanuele6 #2985 - Allow carriage return characters in comments. @emanuele6 #2942 #2984 ## Documentation changes - Generate links in the man page. @emanuele6 #2931 - Standardize arch types to AMD64 & ARM64 from index page download dropdown. @owenthereal #2884 ## libjq - Add extern C for C++. @rockwotj #2953 ## Build and test changes - Fix incorrect syntax for checksum file. @kamontat @wader #2899 - Remove `-dirty` version suffix for windows release build. @itchyny #2888 - Make use of `od` in tests more compatible. @nabijaczleweli @emanuele6 @nicowilliams #2922 - Add dependabot. @yeikel #2889 - Extend fuzzing setup to fuzz parser and JSON serializer. @DavidKorczynski @emanuele6 #2952 - Keep releasing executables with legacy names. @itchyny #2951 # 1.7 After a five year hiatus we're back with a GitHub organization, with new admins and new maintainers who have brought a great deal of energy to make a long-awaited and long-needed new release. We're very grateful for all the new owners, admins, and maintainers. Special thanks go to Owen Ou (@owenthereal) for pushing to set up a new GitHub organization for jq, Stephen Dolan (@stedolan) for transferring the jq repository to the new organization, @itchyny for doing a great deal of work to get the release done, Mattias Wadman (@wader) and Emanuele Torre (@emanuele6) for many PRs and code reviews. Many others also contributed PRs, issues, and code reviews as well, and you can find their contributions in the Git log and on the [closed issues and PRs page](https://github.com/jqlang/jq/issues?q=is%3Aclosed+sort%3Aupdated-desc). Since the last stable release many things have happened: - jq now lives at - New maintainers, admins, and owners have been recruited. - A list of [current maintainers](https://github.com/jqlang/jq/blob/jq-1.7/AUTHORS#L4-L14) - NEWS file is replaced by NEWS.md with Markdown format. @wader #2599 - CI, scan builds, release, website builds etc now use GitHub actions. @owenthereal @wader @itchyny #2596 #2603 #2620 #2723 - Lots of documentation improvements and fixes. - Website updated with new section search box, better section ids for linking, dark mode, etc. @itchyny #2628 - Release builds for: - Linux `amd64`, `arm64`, `armel`, `armhf`, `i386`, `mips`, `mips64`, `mips64el`, `mips64r6`, `mips64r6el`, `mipsel`, `mipsr6`, `mipsr6el`, `powerpc`, `ppc64el`, `riscv64` and `s390x` - macOS `amd64` and `arm64` - Windows `i386` and `amd64` - Docker `linux/386`, `linux/amd64`, `linux/arm64`, `linux/mips64le`, `linux/ppc64le`, `linux/riscv64` and `linux/s390x` - More details see @owenthereal #2665 - Docker images are now available from `ghcr.io/jqlang/jq` instead of Docker Hub. @itchyny #2652 #2686 - OSS-fuzz. @DavidKorczynski #2760 #2762 Full commit log can be found at but here are some highlights: ## CLI changes - Make object key color configurable using `JQ_COLORS` environment variable. @itchyny @haguenau @ericpruitt #2703 ```sh # this would make "field" bold yellow (`1;33`, the last value) $ JQ_COLORS="0;90:0;37:0;37:0;37:0;32:1;37:1;37:1;33" ./jq -n '{field: 123}' { "field": 123 } ``` - Change the default color of null to Bright Black. @itchyny #2824 - Respect `NO_COLOR` environment variable to disable color output. See for details. @itchyny #2728 - Improved `--help` output. Now mentions all options and nicer order. @itchyny @wader #2747 #2766 #2799 - Fix multiple issues of exit code using `--exit-code`/`-e` option. @ryo1kato #1697 ```sh # true-ish last output value exits with zero $ jq -ne true ; echo $? true 0 # false-ish last output value (false and null) exits with 1 $ jq -ne false ; echo $? false 1 # no output value exists with 4 $ jq -ne empty ; echo $? 4 ``` - Add `--binary`/`-b` on Windows for binary output. To get `\n` instead of `\r\n` line endings. @nicowilliams 0dab2b1 - Add `--raw-output0` for NUL (zero byte) separated output. @asottile @pabs3 @itchyny #1990 #2235 #2684 ```sh # will output a zero byte after each output $ jq -n --raw-output0 '1,2,3' | xxd 00000000: 3100 3200 3300 1.2.3. # can be used with xargs -0 $ jq -n --raw-output0 '"a","b","c"' | xargs -0 -n1 a b c $ jq -n --raw-output0 '"a b c", "d\ne\nf"' | xargs -0 printf '[%s]\n' [a b c] [d e f] # can be used with read -d '' $ while IFS= read -r -d '' json; do > jq '.name' <<< "$json" > done < <(jq -n --raw-output0 '{name:"a b c"},{name:"d\ne\nf"}') "a b c" "d\ne\nf" # also it's an error to output a string containing a NUL when using NUL separator $ jq -n --raw-output0 '"\u0000"' jq: error (at ): Cannot dump a string containing NUL with --raw-output0 option ``` - Fix assert crash and validate JSON for `--jsonarg`. @wader #2658 - Remove deprecated `--argfile` option. @itchyny #2768 - Enable stack protection. @nicowilliams #2801 ## Language changes - Use decimal number literals to preserve precision. Comparison operations respects precision but arithmetic operations might truncate. @leonid-s-usov #1752 ```sh # precision is preserved $ echo '100000000000000000' | jq . 100000000000000000 # comparison respects precision (this is false in JavaScript) $ jq -n '100000000000000000 < 100000000000000001' true # sort/0 works $ jq -n -c '[100000000000000001, 100000000000000003, 100000000000000004, 100000000000000002] | sort' [100000000000000001,100000000000000002,100000000000000003,100000000000000004] # arithmetic operations might truncate (same as JavaScript) $ jq -n '100000000000000000 + 10' 100000000000000020 ``` - Adds new builtin `pick(stream)` to emit a projection of the input object or array. @pkoppstein #2656 #2779 ```sh $ jq -n '{"a": 1, "b": {"c": 2, "d": 3}, "e": 4} | pick(.a, .b.c, .x)' { "a": 1, "b": { "c": 2 }, "x": null } ``` - Adds new builtin `debug(msgs)` that works like `debug` but applies a filter on the input before writing to stderr. @pkoppstein #2710 ```sh $ jq -n '1 as $x | 2 | debug("Entering function foo with $x == \($x)", .) | (.+1)' ["DEBUG:","Entering function foo with $x == 1"] ["DEBUG:",2] 3 $ jq -n '{a: 1, b: 2, c: 3} | debug({a, b, sum: (.a+.b)})' ["DEBUG:",{"a":1,"b":2,"sum":3}] { "a": 1, "b": 2, "c": 3 } ``` - Adds new builtin `scan($re; $flags)`. Was documented but not implemented. @itchyny #1961 ```sh # look for pattern "ab" in "abAB" ignoring casing $ jq -n '"abAB" | scan("ab"; "i")' "ab" "AB" ``` - Adds new builtin `abs` to get absolute value. This potentially allows the literal value of numbers to be preserved as `length` and `fabs` convert to float. @pkoppstein #2767 - Allow `if` without `else`-branch. When skipped the `else`-branch will be `.` (identity). @chancez @wader #1825 #2481 ```sh # convert 1 to "one" otherwise keep as is $ jq -n '1,2 | if . == 1 then "one" end' "one" 2 # behaves the same as $ jq -n '1,2 | if . == 1 then "one" else . end' "one" 2 # also works with elif $ jq -n '1,2,3 | if . == 1 then "one" elif . == 2 then "two" end "one" "two" 3 ``` - Allow use of `$binding` as key in object literals. @nicowilliams 8ea4a55 ```sh $ jq -n '"a" as $key | {$key: 123}' { "a": 123 } # previously parentheses were needed $ jq -n '"a" as $key | {($key): 123}' { "a": 123 } ``` - Allow dot between chained indexes when using `.["index"]` @nicowilliams #1168 ```sh $ jq -n '{"a": {"b": 123}} | .a["b"]' 123 # now this also works $ jq -n '{"a": {"b": 123}} | .a.["b"]' 123 ``` - Allow dot for chained value iterator `.[]`, `.[]?` @wader #2650 ```sh $ jq -n '{"a": [123]} | .a[]' 123 # now this also works $ jq -n '{"a": [123]} | .a.[]' 123 ``` - Fix try/catch catches more than it should. @nicowilliams #2750 - Speed up and refactor some builtins, also remove `scalars_or_empty/0`. @muhmuhten #1845 - Now `halt` and `halt_error` exit immediately instead of continuing to the next input. @emanuele6 #2667 - Fix issue converting string to number after previous convert error. @thalman #2400 - Fix issue representing large numbers on some platforms causing invalid JSON output. @itchyny #2661 - Fix deletion using assigning empty against arrays. @itchyny #2133 ```sh # now this works as expected, filter out all values over 2 by assigning empty $ jq -c '(.[] | select(. >= 2)) |= empty' <<< '[1,5,3,0,7]' [1,0] ``` - Allow keywords to be used as binding name in more places. @emanuele6 #2681 - Allow using `nan` as NaN in JSON. @emanuele6 #2712 - Expose a module's function names in `modulemeta`. @mrwilson #2837 - Fix `contains/1` to handle strings with NUL. @nicowilliams 61cd6db - Fix `stderr/0` to output raw text without any decoration. @itchyny #2751 - Fix `nth/2` to emit empty on index out of range. @itchyny #2674 - Fix `implode` to not assert and instead replace invalid Unicode codepoints. @wader #2646 - Fix `indices/1` and `rindex/1` in case of overlapping matches in strings. @emanuele6 #2718 - Fix `sub/3` to resolve issues involving global search-and-replace (gsub) operations. @pkoppstein #2641 - Fix `significand/0`, `gamma/0` and `drem/2` to be available on macOS. @itchyny #2756 #2775 - Fix empty regular expression matches. @itchyny #2677 - Fix overflow exception of the modulo operator. @itchyny #2629 - Fix string multiplication by 0 (and less than 1) to emit empty string. @itchyny #2142 - Fix segfault when using libjq and threads. @thalman #2546 - Fix constant folding of division and reminder with zero divisor. @itchyny #2797 - Fix `error/0`, `error/1` to throw null error. @emanuele6 #2823 - Simpler and faster `transpose`. @pkoppstein #2758 - Simple and efficient implementation of `walk/1`. @pkoppstein #2795 - Remove deprecated filters `leaf_paths`, `recurse_down`. @itchyny #2666 # Previous releases Release history - jq version 1.6 was released on Fri Nov 2 2018 - jq version 1.5 was released on Sat Aug 15 2015 - jq version 1.4 was released on Mon Jun 9 2014 - jq version 1.3 was released on Sun May 19 2013 - jq version 1.2 was released on Thu Dec 20 2012 - jq version 1.1 was released on Sun Oct 21 2012 - jq version 1.0 was released on Sun Oct 21 2012 New features in 1.6 since 1.5: - Destructuring Alternation - New Builtins: - builtins/0 - stderr/0 - halt/0, halt_error/1 - isempty/1 - walk/1 - utf8bytelength/1 - localtime/0, strflocaltime/1 - SQL-style builtins - and more! - Add support for ASAN and UBSAN - Make it easier to use jq with shebangs (8f6f28c) - Add $ENV builtin variable to access environment - Add JQ_COLORS env var for configuring the output colors New features in 1.5 since 1.4: - regular expressions (with Oniguruma) - a library/module system - many new builtins - datetime builtins - math builtins - regexp-related builtins - stream-related builtins (e.g., all/1, any/1) - minimal I/O builtins (`inputs`, `debug`) - new syntactic features, including: - destructuring (`. as [$first, $second] | ...`) - try/catch, generalized `?` operator, and label/break - `foreach` - multiple definitions of a function with different numbers of arguments - command-line arguments - --join-lines / -j for raw output - --argjson and --slurpfile - --tab and --indent - --stream (streaming JSON parser) - --seq (RFC7464 JSON text sequence) - --run-tests improvements - optimizations: - tail-call optimization - reduce and foreach no longer leak a reference to . 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, etcetera (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 ================================================ FILE: README.md ================================================ # jq `jq` is a lightweight and flexible command-line JSON processor akin to `sed`,`awk`,`grep`, and friends for JSON data. It's written in portable C and has zero runtime dependencies, allowing you to easily slice, filter, map, and transform structured data. ## Documentation - **Official Documentation**: [jqlang.org](https://jqlang.org) - **Try jq Online**: [play.jqlang.org](https://play.jqlang.org) ## Installation ### Prebuilt Binaries Download the latest releases from the [GitHub release page](https://github.com/jqlang/jq/releases). ### Docker Image Pull the [jq image](https://github.com/jqlang/jq/pkgs/container/jq) to start quickly with Docker. #### Run with Docker ##### Example: Extracting the version from a `package.json` file ```bash docker run --rm -i ghcr.io/jqlang/jq:latest < package.json '.version' ``` ##### Example: Extracting the version from a `package.json` file with a mounted volume ```bash docker run --rm -i -v "$PWD:$PWD" -w "$PWD" ghcr.io/jqlang/jq:latest '.version' package.json ``` ### Building from source #### Dependencies - libtool - make - automake - autoconf #### Instructions ```console git submodule update --init # if building from git to get oniguruma autoreconf -i # if building from git ./configure --with-oniguruma=builtin make clean # if upgrading from a version previously built from source make -j8 make check sudo make install ``` Build a statically linked version: ```console make LDFLAGS=-all-static ``` If you're not using the latest git version but instead building a released tarball (available on the release page), skip the `autoreconf` step, and flex or bison won't be needed. ##### Cross-Compilation For details on cross-compilation, check out the [GitHub Actions file](.github/workflows/ci.yml) and the [cross-compilation wiki page](https://github.com/jqlang/jq/wiki/Cross-compilation). ## Community & Support - Questions & Help: [Stack Overflow (jq tag)](https://stackoverflow.com/questions/tagged/jq) - Chat & Community: [Join us on Discord](https://discord.gg/yg6yjNmgAC) - Wiki & Advanced Topics: [Explore the Wiki](https://github.com/jqlang/jq/wiki) ## License `jq` is released under the [MIT License](COPYING). `jq`'s documentation is licensed under the [Creative Commons CC BY 3.0](COPYING). `jq` uses parts of the open source C library "decNumber", which is distributed under [ICU License](COPYING) ================================================ FILE: SECURITY.md ================================================ # How to report security vulnerabilities in `jq` GitHub has a [mechanism for private disclosure of vulnerabilities](https://docs.github.com/en/code-security/security-advisories/guidance-on-reporting-and-writing/privately-reporting-a-security-vulnerability) to repository owners and authorized persons such as maintainers. The `jqlang/jq` repository now has this feature enabled. ## Reporting a Vulnerability See [Privately Reporting a Security Vulnerability](https://docs.github.com/en/code-security/security-advisories/guidance-on-reporting-and-writing/privately-reporting-a-security-vulnerability). Click on [`jqlang/jq`](https://github.com/jqlang/jq)'s [Security page](https://github.com/jqlang/jq/security) and click on [Report a vulnerability](https://github.com/jqlang/jq/security/advisories/new). This will notify the owners and maintainers. After submitting you'll get an option to start a private clone of `jqlang/jq` for collaboration with the maintainers. ================================================ FILE: compile-ios.sh ================================================ #!/usr/bin/env bash # Mac C. compile-ios.sh for JQ. # Defaults set -e oniguruma='6.9.10' unset CFLAGS unset CXXFLAGS unset LDFLAGS # Parse args. usage(){ cat << EOF ${0##*/}: usage Description: This simple script builds oniguruma and jq for all *-apple-darwin devices. Arguments: --extra-cflags : Pass defines or includes to clang. --extra-ldflags : Pass libs or includes to ld64. --with-oniguruma : Change default version of onigurma from ${oniguruma}. EOF exit 1 } while (( $# )); do case "$1" in --with-oniguruma) shift; oniguruma="${1}" ;; --extra-cflags) shift; export CFLAGS_="${1}" ;; --extra-ldflags) shift; export LDFLAGS_="${1}" ;; --help) usage ;; *) echo -e "Unknown option: ${1}\n"; usage ;; esac shift done # Start building. echo "Building..." MAKEJOBS="$(sysctl -n hw.ncpu || echo 1)" CC_="$(xcrun -f clang || echo clang)" onig_url="https://github.com/kkos/oniguruma/releases/download/v${oniguruma}/onig-${oniguruma}.tar.gz" builddir="${TMPDIR:-/tmp}/${RANDOM:-'xxxxx'}-compile-ios-build" cwd="$(realpath ${PWD} 2>/dev/null || echo ${PWD})" t_exit() { cat << EOF A error as occurred. oniguruma location: ${builddir}/onig/onig-${oniguruma} jq location: ${cwd} Provide config.log and console logs when posting a issue. EOF } trap t_exit ERR # Onig. mkdir -p "${builddir}/onig" cd "${builddir}/" curl -L ${onig_url} | tar xz for arch in i386 x86_64 armv7 armv7s arm64; do 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 HOST="${arch}-apple-darwin" [[ "${arch}" = "arm64" ]] && HOST="aarch64-apple-darwin" CFLAGS="-arch ${arch} -miphoneos-version-min=9.0 -isysroot ${SYSROOT} ${CFLAGS_} -D_REENTRANT" LDFLAGS="-arch ${arch} -miphoneos-version-min=9.0 -isysroot ${SYSROOT} ${LDFLAGS_}" CC="${CC_} ${CFLAGS}" # ./configure; make install cd "${builddir}/onig-${oniguruma}" CC=${CC} LDFLAGS=${LDFLAGS} \ ./configure --host=${HOST} --build=$(./config.guess) --enable-shared=no --enable-static=yes --prefix=/ make -j${MAKEJOBS} install DESTDIR="${cwd}/ios/onig/${arch}" make clean # Jump back to JQ. cd ${cwd} [[ ! -f ./configure ]] && autoreconf -ivf CC=${CC} LDFLAGS=${LDFLAGS} \ ./configure --host=${HOST} --build=$(./config/config.guess) --enable-docs=no --enable-shared=no --enable-static=yes --prefix=/ --with-oniguruma=${cwd}/ios/onig/${arch} $(test -z ${BISON+x} || echo '--enable-maintainer-mode') make -j${MAKEJOBS} install DESTDIR="${cwd}/ios/jq/${arch}" make clean done mkdir -p "${cwd}/ios/dest/lib" # lipo, make a static lib. lipo -create -output ${cwd}/ios/dest/lib/libonig.a ${cwd}/ios/onig/{i386,x86_64,armv7,armv7s,arm64}/lib/libonig.a lipo -create -output ${cwd}/ios/dest/lib/libjq.a ${cwd}/ios/jq/{i386,x86_64,armv7,armv7s,arm64}/lib/libjq.a # Take the arm64 headers- the most common target. cp -r ${cwd}/ios/jq/arm64/include ${cwd}/ios/dest/ rm -rf ${cwd}/build/ios/{i386,x86_64,armv7,armv7s,arm64} echo "Output to ${cwd}/ios/dest" ================================================ FILE: config/.gitignore ================================================ config.guess config.sub compile depcomp install-sh ltmain.sh missing ylwrap test-driver ar-lib ================================================ FILE: config/m4/.gitignore ================================================ libtool.m4 lt*.m4 ================================================ FILE: config/m4/check-math-func.m4 ================================================ dnl AC_CHECK_MATH_FUNC(func) AC_DEFUN([AC_CHECK_MATH_FUNC], [ AC_LANG(C) AC_CHECK_LIB([m],[$1],[ m4_define([ac_tr_func], [HAVE_]m4_toupper($1)) AC_DEFINE(ac_tr_func, 1, [Define if you have the $1 math function.]) ],[ ]) ]) ================================================ FILE: config/m4/find-func-no-libs.m4 ================================================ 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])]) ================================================ FILE: config/m4/find-func-no-libs2.m4 ================================================ 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, 1, [Define if the $1 function is available.]) 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, 1, [Define if you have the $1 function.]) AC_DEFINE_UNQUOTED($ac_tr_lib, 1, [Define if you have the $2 library.]) AC_MSG_RESULT([yes, in $ac_res]) ;; esac AC_SUBST(LIB_$1) ]) ================================================ FILE: config/m4/find-func.m4 ================================================ 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 ]) ================================================ FILE: config/m4/misc.m4 ================================================ dnl Shamelessly stolen from Heimdal AC_DEFUN([upcase],[`echo $1 | tr abcdefghijklmnopqrstuvwxyz ABCDEFGHIJKLMNOPQRSTUVWXYZ`])dnl ================================================ FILE: configure.ac ================================================ m4_define([jq_version], m4_esyscmd_s([scripts/version]))) AC_INIT([jq],[jq_version],[https://github.com/jqlang/jq/issues],[jq],[https://jqlang.org]) dnl Created autoconf implementation thompson@dtosolutions, 26NOV12 AC_PREREQ([2.65]) AC_CONFIG_AUX_DIR([config]) AC_USE_SYSTEM_EXTENSIONS AM_INIT_AUTOMAKE([1.11.2 subdir-objects parallel-tests foreign -Wall]) AM_SILENT_RULES([yes]) AM_PROG_AR AM_MAINTAINER_MODE([disable]) AC_PROG_CC m4_version_prereq([2.70], [], [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 AC_SYS_LARGEFILE # issue 2167 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 if test "$USE_MAINTAINER_MODE" = yes; then if test "$YACC" != "bison -y"; then AC_MSG_CHECKING([bison version]) AC_MSG_RESULT([not bison]) else AX_PROG_BISON_VERSION([3], [], [AC_MSG_ERROR([You need bison version 3.0 or greater])]) fi AC_CHECK_PROGS(LEX, flex lex) fi AC_CHECK_FUNCS(memmem) AC_CHECK_HEADER("sys/cygwin.h", [have_cygwin=1;]) AC_CHECK_HEADER("shlwapi.h",[have_shlwapi=1;]) AM_CONDITIONAL([WIN32], [test "x$have_shlwapi" = x1 && test ! "x$have_cygwin" = x1]) dnl Running tests with Valgrind is slow. It is faster to iterate on dnl code without Valgrind until tests pass, then enable Valgrind and dnl fix leaks. AC_ARG_ENABLE([valgrind], AS_HELP_STRING([--enable-valgrind],[enable Valgrind during testing])) dnl Address sanitizer (ASan) AC_ARG_ENABLE([asan], AS_HELP_STRING([--enable-asan],[enable address sanitizer])) dnl Undefined Behavior Sanitizer AC_ARG_ENABLE([ubsan], AS_HELP_STRING([--enable-ubsan],[enable undefined behavior sanitizer])) dnl Code coverage AC_ARG_ENABLE([gcov], AS_HELP_STRING([--enable-gcov],[enable gcov code coverage tool])) dnl Don't attempt to build docs if python deps aren't installed AC_ARG_ENABLE([docs], AS_HELP_STRING([--disable-docs],[do not build docs]), [], [enable_docs=yes]) dnl Don't attempt to build the error injection object (if there is no LD_PRELOAD support) AC_ARG_ENABLE([error-injection], AS_HELP_STRING([--enable-error-injection],[build and test with error injection])) dnl Enable building all static AC_ARG_ENABLE([all-static], AS_HELP_STRING([--enable-all-static],[link jq with static libraries only])) dnl find pipenv AC_ARG_VAR([PIPENV], [pipenv command]) AC_CHECK_PROGS([PIPENV], pipenv) AS_IF([test "x$enable_docs" != "xno"],[ AC_CACHE_CHECK([for Python dependencies], [jq_cv_python_deps],[ jq_cv_python_deps=yes AS_IF([test "x$PIPENV" = "x" || \ ! bmsg="`cd ${srcdir}/docs; LC_ALL=$LANG "$PIPENV" --venv`"],[ jq_cv_python_deps=no ]) ]) AS_IF([test "x$jq_cv_python_deps" != "xyes"], [ AC_MSG_WARN([Error checking python dependencies: $bmsg ***************************************************************** * Python dependencies for building jq documentation not found. * * You can still build, install and hack on jq, but the manpage * * will not be rebuilt and new manpage tests will not be run. * * See docs/README.md for how to install the docs dependencies. * *****************************************************************]) enable_docs=no ]) ]) dnl Disable decNumber support AC_ARG_ENABLE([decnum], AS_HELP_STRING([--disable-decnum],[disable decnum support])) AS_IF([test "x$enable_decnum" != "xno"],[ AC_DEFINE([USE_DECNUM], 1, [Define to enable decnum support.]) ]) AM_CONDITIONAL([ENABLE_VALGRIND], [test "x$enable_valgrind" = xyes]) AM_CONDITIONAL([ENABLE_ASAN], [test "x$enable_asan" = xyes]) AM_CONDITIONAL([ENABLE_UBSAN], [test "x$enable_ubsan" = xyes]) AM_CONDITIONAL([ENABLE_GCOV], [test "x$enable_gcov" = xyes]) AM_CONDITIONAL([ENABLE_DOCS], [test "x$enable_docs" != xno]) AM_CONDITIONAL([ENABLE_ERROR_INJECTION], [test "x$enable_error_injection" = xyes]) AM_CONDITIONAL([ENABLE_ALL_STATIC], [test "x$enable_all_static" = xyes]) dnl Find pthread, if we have it. We do this first because we may set -pthread on CFLAGS dnl which can cause various macros to be defined (__REENTRANT on Darwin, for example) AX_PTHREAD([ AC_DEFINE([HAVE_PTHREAD], [1], [Define to enable POSIX threads support.]) LIBS="$PTHREAD_LIBS $LIBS" CFLAGS="$CFLAGS $PTHREAD_CFLAGS" CC="$PTHREAD_CC" ]) AC_FUNC_ALLOCA AC_FIND_FUNC([isatty], [c], [#include ], [0]) AC_FIND_FUNC([_isatty], [c], [#include ], [0]) AC_FIND_FUNC([strptime], [c], [#include ], [0, 0, 0]) AC_FIND_FUNC([strftime], [c], [#include ], [0, 0, 0, 0]) AC_FIND_FUNC([setenv], [c], [#include ], [0, 0, 0]) AC_FIND_FUNC([timegm], [c], [#include ], [0]) AC_FIND_FUNC([gmtime_r], [c], [#include ], [0, 0]) AC_FIND_FUNC([gmtime], [c], [#include ], [0]) AC_FIND_FUNC([localtime_r], [c], [#include ], [0, 0]) AC_FIND_FUNC([localtime], [c], [#include ], [0]) AC_FIND_FUNC([gettimeofday], [c], [#include ], [0, 0]) AC_CHECK_MEMBER([struct tm.tm_gmtoff], [AC_DEFINE([HAVE_TM_TM_GMT_OFF],1,[Define to 1 if the system has the tm_gmt_off field in struct tm])], [], [[#include ]]) AC_CHECK_MEMBER([struct tm.__tm_gmtoff], [AC_DEFINE([HAVE_TM___TM_GMT_OFF],1,[Define to 1 if the system has the __tm_gmt_off field in struct tm])], [], [[#include ]]) AC_FIND_FUNC([setlocale], [c], [#include ], [0,0]) dnl Figure out if we have the pthread functions we actually need AC_FIND_FUNC_NO_LIBS([pthread_key_create], [], [#include ], [NULL, NULL]) AC_FIND_FUNC_NO_LIBS([pthread_once], [], [#include ], [NULL, NULL]) AC_FIND_FUNC_NO_LIBS([atexit], [], [#include ], [NULL]) dnl libm math.h functions AC_CHECK_MATH_FUNC(acos) AC_CHECK_MATH_FUNC(acosh) AC_CHECK_MATH_FUNC(asin) AC_CHECK_MATH_FUNC(asinh) AC_CHECK_MATH_FUNC(atan2) AC_CHECK_MATH_FUNC(atan) AC_CHECK_MATH_FUNC(atanh) AC_CHECK_MATH_FUNC(cbrt) AC_CHECK_MATH_FUNC(ceil) AC_CHECK_MATH_FUNC(copysign) AC_CHECK_MATH_FUNC(cos) AC_CHECK_MATH_FUNC(cosh) AC_CHECK_MATH_FUNC(drem) AC_CHECK_MATH_FUNC(erf) AC_CHECK_MATH_FUNC(erfc) AC_CHECK_MATH_FUNC(exp10) AC_CHECK_MATH_FUNC(__exp10) dnl macOS has an __exp10 AC_CHECK_MATH_FUNC(exp2) AC_CHECK_MATH_FUNC(exp) AC_CHECK_MATH_FUNC(expm1) AC_CHECK_MATH_FUNC(fabs) AC_CHECK_MATH_FUNC(fdim) AC_CHECK_MATH_FUNC(floor) AC_CHECK_MATH_FUNC(fma) AC_CHECK_MATH_FUNC(fmax) AC_CHECK_MATH_FUNC(fmin) AC_CHECK_MATH_FUNC(fmod) AC_CHECK_MATH_FUNC(frexp) AC_CHECK_MATH_FUNC(gamma) AC_CHECK_MATH_FUNC(hypot) AC_CHECK_MATH_FUNC(j0) AC_CHECK_MATH_FUNC(j1) AC_CHECK_MATH_FUNC(jn) AC_CHECK_MATH_FUNC(ldexp) AC_CHECK_MATH_FUNC(lgamma) AC_CHECK_MATH_FUNC(log10) AC_CHECK_MATH_FUNC(log1p) AC_CHECK_MATH_FUNC(log2) AC_CHECK_MATH_FUNC(log) AC_CHECK_MATH_FUNC(logb) AC_CHECK_MATH_FUNC(modf) AC_CHECK_MATH_FUNC(lgamma_r) AC_CHECK_MATH_FUNC(nearbyint) AC_CHECK_MATH_FUNC(nextafter) AC_CHECK_MATH_FUNC(nexttoward) AC_CHECK_MATH_FUNC(pow) AC_CHECK_MATH_FUNC(remainder) AC_CHECK_MATH_FUNC(rint) AC_CHECK_MATH_FUNC(round) AC_CHECK_MATH_FUNC(scalb) AC_CHECK_MATH_FUNC(scalbln) AC_CHECK_MATH_FUNC(significand) dnl scalbn and ilogb are used on macos to replace significand if we don't have frexp AC_CHECK_MATH_FUNC(scalbn) AC_CHECK_MATH_FUNC(ilogb) AC_CHECK_MATH_FUNC(sin) AC_CHECK_MATH_FUNC(sinh) AC_CHECK_MATH_FUNC(sqrt) AC_CHECK_MATH_FUNC(tan) AC_CHECK_MATH_FUNC(tanh) AC_CHECK_MATH_FUNC(tgamma) AC_CHECK_MATH_FUNC(trunc) AC_CHECK_MATH_FUNC(y0) AC_CHECK_MATH_FUNC(y1) AC_CHECK_MATH_FUNC(yn) 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 endianness), AC_MSG_ERROR(universal endianness not supported) ) dnl Oniguruma AC_ARG_WITH([oniguruma], [AS_HELP_STRING([--with-oniguruma=prefix], [try this for a non-standard install prefix of the oniguruma library])], , [with_oniguruma=yes]) onig_CFLAGS= onig_LDFLAGS= build_oniguruma=no AS_IF([test "x$with_oniguruma" != xno], [ save_CFLAGS="$CFLAGS" save_LDFLAGS="$LDFLAGS" AS_IF([test "x$with_oniguruma" != xyes], [ AS_IF([test "x$with_oniguruma" = xbuiltin], [ build_oniguruma=yes ], [ onig_CFLAGS="-I${with_oniguruma}/include" onig_LDFLAGS="-L${with_oniguruma}/lib" ]) ]) AS_IF([test "x$build_oniguruma" = xno], [ # check for ONIGURUMA library, either in /usr or where requested CFLAGS="$CFLAGS $onig_CFLAGS" LDFLAGS="$LDFLAGS $onig_LDFLAGS" AC_CHECK_HEADER("oniguruma.h", AC_CHECK_LIB([onig],[onig_version])) # handle check results AS_IF([test "x$ac_cv_lib_onig_onig_version" != "xyes"], [ build_oniguruma=yes AC_MSG_NOTICE([Oniguruma was not found. Will use the packaged oniguruma.]) ]) ]) AS_IF([test "x$build_oniguruma" = xyes && test -f "${srcdir}/vendor/oniguruma/configure.ac" ], [ onig_CFLAGS="-I${srcdir}/vendor/oniguruma/src" onig_LDFLAGS="-L${srcdir}/vendor/oniguruma/src -Wl,-rpath,${libdir}" AC_CONFIG_SUBDIRS([vendor/oniguruma]) AC_DEFINE([HAVE_LIBONIG],1,[Define to 1 if the system includes libonig]) ]) CFLAGS="$save_CFLAGS" LDFLAGS="$save_LDFLAGS" ]) AC_SUBST(onig_CFLAGS) AC_SUBST(onig_LDFLAGS) AM_CONDITIONAL([BUILD_ONIGURUMA], [test "x$build_oniguruma" = xyes]) AM_CONDITIONAL([WITH_ONIGURUMA], [test "x$with_oniguruma" != xno]) AC_CONFIG_MACRO_DIRS([config/m4 m4]) AC_CONFIG_FILES([Makefile libjq.pc]) AC_OUTPUT ================================================ FILE: docs/Pipfile ================================================ [[source]] name = "pypi" url = "https://pypi.org/simple" verify_ssl = true [dev-packages] [packages] jinja2 = "*" pyyaml = "*" markdown = "*" lxml = "*" jsonschema = "*" importlib_resources = "*" ================================================ FILE: docs/README.md ================================================ Documentation ============= The jq website, manpages and some of the tests are generated from this directory. The manual is a YAML file in `content/manual`. To build the documentation (including building the jq manpage), you'll need `python3` and `pipenv`. You can install `pipenv` like so: pip install pipenv Though, you may need to say `pip3` instead, depending on your system. Once you have `pipenv` installed, you can install the dependencies by running `pipenv sync` from the `docs/` directory. Also, you may need to run `virtualenv -p /usr/bin/python3 venv/` and then `source venv/bin/activate`, and only then `pipenv sync`. Once this is done, rerun `./configure --enable-docs` in the jq root directory and then the `Makefile` will be able to generate the jq manpage. You can just run `make jq.1` to build the manpage manually, and `make tests/man.test` to update the manual tests. To build the website, run `pipenv run python3 build_website.py` in the `docs/` directory. To serve them locally, you can run `python3 -m http.server -d output`. ================================================ FILE: docs/build_manpage.py ================================================ #!/usr/bin/env python3 from datetime import date from io import StringIO from lxml import etree import markdown from markdown.extensions import Extension import re import sys import yaml # Prevent our markdown parser from trying to help by interpreting things in angle brackets as HTML tags. class EscapeHtml(Extension): def extendMarkdown(self, md): md.preprocessors.deregister('html_block') md.inlinePatterns.deregister('html') class RoffWalker(object): def __init__(self, tree, output=sys.stdout): self.tree = tree self.target = output self.f = StringIO() def walk(self): self._walk(self.tree, parent_tag=None) # We don't want to start lines with \. because that can confuse man # For lines that start with \., we need to prefix them with \& so it # knows not to treat that line as a directive data = re.sub(r'^\\\.', r'\&.', self.f.getvalue(), flags=re.MULTILINE) self.target.write(data) def _ul_is_special(self, root): if len(root) != 1: return False child = root[0] if child.tag != 'li': return False msg = ''.join(child.itertext()).strip() return msg.endswith(':') def _walk_child(self, root): if len(root) > 0: self._walk(root[0], parent_tag=root.tag) def _write_element(self, root, ensure_newline=True): if root.text is not None: text = self._sanitize(root.text) self.__write_raw(text) self._walk_child(root) self._write_tail(root, ensure_newline=ensure_newline) def _write_tail(self, root, ensure_newline=False, inline=False): if root.tail is not None: if inline or root.tail != '\n': text = self._sanitize(root.tail) if text.endswith('\n'): ensure_newline = False self.__write_raw(text) if ensure_newline: self.__write_raw('\n') def _walk(self, root, parent_tag=None): last_tag = None while root is not None: if root.tag == 'h1': self.__write_cmd('.TH "JQ" "1" "{}" "" ""'.format( date.today().strftime('%B %Y'))) self.__write_cmd('.SH "NAME"') # TODO: properly parse this self.__write_raw(r'\fBjq\fR \- Command\-line JSON processor' + "\n") elif root.tag == 'h2': self.__write_cmd('.SH "{}"'.format(''.join( root.itertext()).strip())) elif root.tag == 'h3': text = ''.join(root.itertext()).strip() self.__write_cmd('.SS "{}"'.format(self._h3_sanitize(text))) elif root.tag == 'p': if last_tag not in ['h2', 'h3'] and parent_tag not in ['li']: self.__write_cmd('.P') self._write_element(root, ensure_newline=(parent_tag != 'li')) elif root.tag == 'a': self._write_element(root, ensure_newline=(parent_tag != 'li')) elif root.tag == 'ul': if self._ul_is_special(root): li = root[0] self.__write_cmd('.TP') self._write_element(li) next = root.getnext() while next is not None and next.tag == 'p': if next.getnext() is not None and next.getnext( ).tag == 'pre': # we don't want to .IP these, because it'll look funny with the code indent break self.__write_cmd('.IP') self._write_element(next) root = next next = root.getnext() else: self._walk_child(root) self._write_tail(root) # A pre tag after the end of a list doesn't want two of the indentation commands if root.getnext() is None or root.getnext().tag != 'pre': self.__write_cmd('.IP "" 0') elif root.tag == 'li': self.__write_cmd(r'.IP "\(bu" 4') if root.text is not None and root.text.strip() != '': text = self._sanitize(root.text) self.__write_raw(text) self._walk_child(root) self._write_tail(root, ensure_newline=True) elif root.tag == 'strong': if root.text is not None: text = self._sanitize(root.text) self.__write_raw('\\fB{}\\fR'.format(text)) self._write_tail(root, inline=True) elif root.tag == 'em': if root.text is not None: text = self._sanitize(root.text) self.__write_raw('\\fI{}\\fR'.format(text)) self._write_tail(root, inline=True) elif root.tag == 'code': if root.text is not None: text = self._code_sanitize(root.text) self.__write_raw('\\fB{}\\fR'.format(text)) self._write_tail(root, inline=True) elif root.tag == 'pre': self.__write_cmd('.IP "" 4') self.__write_cmd('.nf\n') # extra newline for spacing reasons next = root first = True while next is not None and next.tag == 'pre': if not first: self.__write_raw('\n') text = ''.join(next.itertext(with_tail=False)) self.__write_raw(self._pre_sanitize(text)) first = False root = next next = next.getnext() self.__write_cmd('.fi') self.__write_cmd('.IP "" 0') else: self._walk_child(root) last_tag = root.tag root = root.getnext() def _base_sanitize(self, text): text = re.sub(r'\\', r'\\e', text) text = re.sub(r'\.', r'\\.', text) text = re.sub("'", r"\'", text) text = re.sub('-', r'\-', text) return text def _pre_sanitize(self, text): return self._base_sanitize(text) def _code_sanitize(self, text): text = self._base_sanitize(text) text = re.sub(r'\s', ' ', text) return text def _h3_sanitize(self, text): text = self._base_sanitize(text) text = re.sub(' \n|\n ', ' ', text) text = re.sub('\n', ' ', text) return text def _sanitize(self, text): text = self._base_sanitize(text) text = re.sub(r'<([^>]+)>', r'\\fI\1\\fR', text) text = re.sub(r' +', ' ', text) text = re.sub('\n', ' ', text) return text def __write_cmd(self, dat): print('.', dat, sep='\n', file=self.f) pass def __write_raw(self, dat): print(dat, sep='', end='', file=self.f) pass def load_yml_file(fn): with open(fn) as f: return yaml.safe_load(f) def dedent_body(body): lines = [re.sub(r'^ (\S)', r'\1', l) for l in body.split('\n')] return '\n'.join(lines) def convert_manual_to_markdown(): f = StringIO() manual = load_yml_file("content/manual/dev/manual.yml") f.write(manual.get('manpage_intro', '\n')) f.write(dedent_body(manual.get('body', '\n'))) for section in manual.get('sections', []): f.write('## {}\n'.format(section.get('title', '').upper())) f.write(dedent_body(section.get('body', '\n'))) f.write('\n') for entry in section.get('entries', []): f.write('### {}\n'.format(entry.get('title', ''))) f.write(dedent_body(entry.get('body', '\n'))) f.write('\n') if entry.get('examples') is not None: f.write("~~~~\n") first = True for example in entry.get('examples'): if not first: f.write('\n') f.write("jq '{}'\n".format(example.get('program', ''))) f.write(" {}\n".format(example.get('input', ''))) output = [str(x) for x in example.get('output', [])] f.write("=> {}\n".format(', '.join(output))) first = False f.write("~~~~\n") f.write('\n') f.write(manual.get('manpage_epilogue', '')) return f.getvalue() # Convert manual.yml to our special markdown format markdown_data = convert_manual_to_markdown() # Convert markdown to html html_data = markdown.markdown(markdown_data, extensions=[EscapeHtml(), 'fenced_code']) # Parse the html into a tree so we can walk it tr = etree.HTML(html_data, etree.HTMLParser()) # Convert the markdown to ROFF RoffWalker(tr).walk() ================================================ FILE: docs/build_mantests.py ================================================ #!/usr/bin/env python3 import yaml import re regex_program_pattern = re.compile( r'\b(?:test|match|capture|scan|split|splits|sub|gsub)\s*\(') with open('content/manual/dev/manual.yml') as source, \ open('../tests/man.test', 'w') as man, \ open('../tests/manonig.test', 'w') as manonig: manual = yaml.safe_load(source) for section in manual.get('sections', []): for entry in section.get('entries', []): for example in entry.get('examples', []): program = example.get('program', '').replace('\n', ' ') out = manonig if regex_program_pattern.search(program) else man print(program, file=out) print(example.get('input', ''), file=out) for s in example.get('output', []): print(s, file=out) print('', file=out) ================================================ FILE: docs/build_website.py ================================================ #!/usr/bin/env python3 import glob import itertools from jinja2 import Environment, FileSystemLoader, select_autoescape, pass_context from markdown import markdown from markupsafe import Markup import os import os.path import re import shutil import yaml env = Environment( loader=FileSystemLoader('templates'), autoescape=select_autoescape(['html.j2']), ) def load_yml_file(fn): with open(fn) as f: return yaml.safe_load(f) env.globals['url'] = 'https://jqlang.org' env.filters['search_id'] = lambda input: input.replace(r'`', '') env.filters['section_id'] = lambda input: re.sub( r'[^-a-zA-Z0-9_]', '', input.replace(' ', '-')).lower() env.filters['entry_id'] = lambda input: re.sub( r'^(split|first-last-nth)$', r'\1' + ('-1' if ';' not in input else '-2'), # avoid id conflict re.sub( r'\b([^-]+)(?:-\1)+\b', r'\1', # e.g. range-range-range -> range re.sub(r' ?/ ?|,? ', '-', re.sub(r'[`;]|: .*|\(.*?\)| \[.+\]', '', input)))).lower() env.filters['markdownify'] = lambda input: Markup(markdown(input)) env.filters['no_paragraph'] = lambda input: Markup(re.sub(r'', '', input)) env.globals['unique_id'] = pass_context( lambda ctx: str(next(ctx['unique_ctr']))) def raise_handler(message): raise Exception(message) env.globals['raise'] = raise_handler def generate_file(env, fname): path, base = os.path.split(fname) path = os.path.relpath(path, 'content') if path == '.': path = '' permalink = '' else: permalink = path + '/' output_dir = os.path.join('output', path) output_path = os.path.join(output_dir, 'index.html') template_name = re.sub(r'.yml$', '.html.j2', base) ctx = load_yml_file(fname) ctx.update(unique_ctr=itertools.count(1), permalink=permalink, navitem=path) os.makedirs(output_dir, exist_ok=True) env.get_template(template_name).stream(ctx).dump(output_path, encoding='utf-8') def copy_public_files(root=''): for f in os.scandir(os.path.join('public', root)): src = os.path.join(root, f.name) dst = os.path.join('output', src) if f.is_dir(): os.makedirs(dst, exist_ok=True) copy_public_files(src) else: shutil.copyfile(f.path, dst) os.makedirs('output', exist_ok=True) copy_public_files() for fn in glob.glob('content/**/*.yml', recursive=True): generate_file(env, fn) ================================================ FILE: docs/content/download/default.yml ================================================ headline: Download jq body: - text: | jq is written in C and has no runtime dependencies, so it should be possible to build it for nearly any platform. Prebuilt binaries are available for Linux, macOS and Windows. The binaries should just run, but on macOS and Linux you may need to make them executable first using `chmod +x jq`. jq is licensed under the MIT license. For all of the gory details, read the file `COPYING` in the source distribution. jq uses a C library for decimal number support. This is an ICU 1.8.1 licensed code obtained from the ICU downloads archive. ### Linux * jq is in the official [Debian](https://packages.debian.org/jq) and [Ubuntu](https://packages.ubuntu.com/jq) repositories. Install using `sudo apt-get install jq`. * jq is in the official [Fedora](https://src.fedoraproject.org/rpms/jq) repository. Install using `sudo dnf install jq`. * jq is in the official [openSUSE](https://software.opensuse.org/package/jq) repository. Install using `sudo zypper install jq`. * jq is in the official [Arch](https://archlinux.org/packages/?q=jq) repository. Install using `sudo pacman -S jq`. * jq 1.8.1 binaries for [AMD64](https://github.com/jqlang/jq/releases/download/jq-1.8.1/jq-linux-amd64) or [ARM64](https://github.com/jqlang/jq/releases/download/jq-1.8.1/jq-linux-arm64) or [i386](https://github.com/jqlang/jq/releases/download/jq-1.8.1/jq-linux-i386). * jq 1.8.0 binaries for [AMD64](https://github.com/jqlang/jq/releases/download/jq-1.8.0/jq-linux-amd64) or [ARM64](https://github.com/jqlang/jq/releases/download/jq-1.8.0/jq-linux-arm64) or [i386](https://github.com/jqlang/jq/releases/download/jq-1.8.0/jq-linux-i386). * jq 1.7.1 binaries for [AMD64](https://github.com/jqlang/jq/releases/download/jq-1.7.1/jq-linux-amd64) or [ARM64](https://github.com/jqlang/jq/releases/download/jq-1.7.1/jq-linux-arm64) or [i386](https://github.com/jqlang/jq/releases/download/jq-1.7.1/jq-linux-i386). * jq 1.7 binaries for [AMD64](https://github.com/jqlang/jq/releases/download/jq-1.7/jq-linux-amd64) or [ARM64](https://github.com/jqlang/jq/releases/download/jq-1.7/jq-linux-arm64) or [i386](https://github.com/jqlang/jq/releases/download/jq-1.7/jq-linux-i386). * jq 1.6 binaries for [AMD64](https://github.com/jqlang/jq/releases/download/jq-1.6/jq-linux64) or [i386](https://github.com/jqlang/jq/releases/download/jq-1.6/jq-linux32). * jq 1.5 binaries for [AMD64](https://github.com/jqlang/jq/releases/download/jq-1.5/jq-linux64) or [i386](https://github.com/jqlang/jq/releases/download/jq-1.5/jq-linux32). * jq 1.4 binaries for [AMD64](https://github.com/jqlang/jq/releases/download/jq-1.4/jq-linux-x86_64) or [i386](https://github.com/jqlang/jq/releases/download/jq-1.4/jq-linux-x86). * jq 1.3 binaries for [AMD64](https://github.com/jqlang/jq/releases/download/jq-1.3/jq-linux-x86_64) or [i386](https://github.com/jqlang/jq/releases/download/jq-1.3/jq-linux-x86). ### macOS * Use [Homebrew](https://brew.sh/) to install jq with `brew install jq`. * Use [MacPorts](https://www.macports.org) to install jq with `port install jq`. * Use [Fink](https://finkproject.org) to install jq with `fink install jq`. * jq 1.8.1 binaries for [Apple Silicon](https://github.com/jqlang/jq/releases/download/jq-1.8.1/jq-macos-arm64) or [Intel Mac](https://github.com/jqlang/jq/releases/download/jq-1.8.1/jq-macos-amd64). * jq 1.8.0 binaries for [Apple Silicon](https://github.com/jqlang/jq/releases/download/jq-1.8.0/jq-macos-arm64) or [Intel Mac](https://github.com/jqlang/jq/releases/download/jq-1.8.0/jq-macos-amd64). * jq 1.7.1 binaries for [Apple Silicon](https://github.com/jqlang/jq/releases/download/jq-1.7.1/jq-macos-arm64) or [Intel Mac](https://github.com/jqlang/jq/releases/download/jq-1.7.1/jq-macos-amd64). * jq 1.7 binaries for [Apple Silicon](https://github.com/jqlang/jq/releases/download/jq-1.7/jq-macos-arm64) or [Intel Mac](https://github.com/jqlang/jq/releases/download/jq-1.7/jq-macos-amd64). * jq 1.6 binary for [AMD64](https://github.com/jqlang/jq/releases/download/jq-1.6/jq-osx-amd64). * jq 1.5 binary for [AMD64](https://github.com/jqlang/jq/releases/download/jq-1.5/jq-osx-amd64). * jq 1.4 binaries for [AMD64](https://github.com/jqlang/jq/releases/download/jq-1.4/jq-osx-x86_64) or [i386](https://github.com/jqlang/jq/releases/download/jq-1.4/jq-osx-x86). * jq 1.3 binaries for [AMD64](https://github.com/jqlang/jq/releases/download/jq-1.3/jq-osx-x86_64) or [i386](https://github.com/jqlang/jq/releases/download/jq-1.3/jq-osx-x86). ### FreeBSD * `pkg install jq` as root installs a pre-built [binary package](https://www.freebsd.org/doc/en_US.ISO8859-1/books/handbook/pkgng-intro.html). * `make -C /usr/ports/textproc/jq install clean` as root installs the [jq](https://www.freshports.org/textproc/jq/) [port](https://www.freebsd.org/doc/en_US.ISO8859-1/books/handbook/ports-using.html) from source. ### Solaris * `pkgutil -i jq` in [OpenCSW](https://www.opencsw.org/p/jq) for Solaris 10+, Sparc and x86. * jq 1.4 binaries for Solaris 11 [AMD64](https://github.com/jqlang/jq/releases/download/jq-1.4/jq-solaris11-64) or [i386](https://github.com/jqlang/jq/releases/download/jq-1.4/jq-solaris11-32). ### Windows * Use [winget](https://learn.microsoft.com/en-us/windows/package-manager/winget/) to install jq with `winget install jqlang.jq`. * Use [scoop](https://scoop.sh/) to install jq with `scoop install jq`. * Use [Chocolatey NuGet](https://chocolatey.org/) to install jq with `choco install jq`. * jq 1.8.1 executables for [AMD64](https://github.com/jqlang/jq/releases/download/jq-1.8.1/jq-windows-amd64.exe) or [i386](https://github.com/jqlang/jq/releases/download/jq-1.8.1/jq-windows-i386.exe). * jq 1.8.0 executables for [AMD64](https://github.com/jqlang/jq/releases/download/jq-1.8.0/jq-windows-amd64.exe) or [i386](https://github.com/jqlang/jq/releases/download/jq-1.8.0/jq-windows-i386.exe). * jq 1.7.1 executables for [AMD64](https://github.com/jqlang/jq/releases/download/jq-1.7.1/jq-windows-amd64.exe) or [i386](https://github.com/jqlang/jq/releases/download/jq-1.7.1/jq-windows-i386.exe). * jq 1.7 executables for [AMD64](https://github.com/jqlang/jq/releases/download/jq-1.7/jq-windows-amd64.exe) or [i386](https://github.com/jqlang/jq/releases/download/jq-1.7/jq-windows-i386.exe). * jq 1.6 executables for [AMD64](https://github.com/jqlang/jq/releases/download/jq-1.6/jq-win64.exe) or [i386](https://github.com/jqlang/jq/releases/download/jq-1.6/jq-win32.exe). * jq 1.5 executables for [AMD64](https://github.com/jqlang/jq/releases/download/jq-1.5/jq-win64.exe) or [i386](https://github.com/jqlang/jq/releases/download/jq-1.5/jq-win32.exe). * jq 1.4 executables for [AMD64](https://github.com/jqlang/jq/releases/download/jq-1.4/jq-win64.exe) or [i386](https://github.com/jqlang/jq/releases/download/jq-1.4/jq-win32.exe). * jq 1.3 executables for [AMD64](https://github.com/jqlang/jq/releases/download/jq-1.3/jq-win64.exe) or [i386](https://github.com/jqlang/jq/releases/download/jq-1.3/jq-win32.exe). ### Checksums and signatures SHA-256 checksums are provided for all release and pre-release binaries. The checksums for jq 1.8.1 are in [sig/v1.8.1/sha256sum.txt](https://raw.githubusercontent.com/jqlang/jq/master/sig/v1.8.1/sha256sum.txt). The checksums for jq 1.8.0 are in [sig/v1.8.0/sha256sum.txt](https://raw.githubusercontent.com/jqlang/jq/master/sig/v1.8.0/sha256sum.txt). The checksums for jq 1.7.1 are in [sig/v1.7.1/sha256sum.txt](https://raw.githubusercontent.com/jqlang/jq/master/sig/v1.7.1/sha256sum.txt). The checksums for jq 1.7 are in [sig/v1.7/sha256sum.txt](https://raw.githubusercontent.com/jqlang/jq/master/sig/v1.7/sha256sum.txt). The checksums for jq 1.6 are in [sig/v1.6/sha256sum.txt](https://raw.githubusercontent.com/jqlang/jq/master/sig/v1.6/sha256sum.txt). The checksums for jq 1.5 are in [sig/v1.5/sha256sum.txt](https://raw.githubusercontent.com/jqlang/jq/master/sig/v1.5/sha256sum.txt). Additionally, all release artifacts are signed by a jq release key. We have two release keys, [one for 1.6 and older releases](https://raw.githubusercontent.com/jqlang/jq/master/sig/jq-release-old.key), and [one for 1.7 and newer releases](https://raw.githubusercontent.com/jqlang/jq/master/sig/jq-release-new.key). The signatures for jq 1.8.1 are in [sig/v1.8.1/\*.asc](https://github.com/jqlang/jq/tree/master/sig/v1.8.1). The signatures for jq 1.8.0 are in [sig/v1.8.0/\*.asc](https://github.com/jqlang/jq/tree/master/sig/v1.8.0). The signatures for jq 1.7.1 are in [sig/v1.7.1/\*.asc](https://github.com/jqlang/jq/tree/master/sig/v1.7.1). The signatures for jq 1.7 are in [sig/v1.7/\*.asc](https://github.com/jqlang/jq/tree/master/sig/v1.7). The signatures for jq 1.6 are in [sig/v1.6/\*.asc](https://github.com/jqlang/jq/tree/master/sig/v1.6). The signatures for jq 1.5 are in [sig/v1.5/\*.asc](https://github.com/jqlang/jq/tree/master/sig/v1.5). You can use [GnuPG](https://gnupg.org/) to verify a signature by downloading the signature and running `gpg --verify signature.asc`. ### From source on Linux, macOS, Cygwin, and other POSIX-like operating systems * [Source tarball for jq 1.8.1](https://github.com/jqlang/jq/releases/download/jq-1.8.1/jq-1.8.1.tar.gz) * [Source tarball for jq 1.8.0](https://github.com/jqlang/jq/releases/download/jq-1.8.0/jq-1.8.0.tar.gz) * [Source tarball for jq 1.7.1](https://github.com/jqlang/jq/releases/download/jq-1.7.1/jq-1.7.1.tar.gz) * [Source tarball for jq 1.7](https://github.com/jqlang/jq/releases/download/jq-1.7/jq-1.7.tar.gz) * [Source tarball for jq 1.6](https://github.com/jqlang/jq/releases/download/jq-1.6/jq-1.6.tar.gz) * [Source tarball for jq 1.5](https://github.com/jqlang/jq/releases/download/jq-1.5/jq-1.5.tar.gz) You can build it using the usual `./configure && make && sudo make install` rigmarole. If you're interested in using the latest development version, try: git clone --recursive https://github.com/jqlang/jq.git cd jq autoreconf -i ./configure make sudo make install To build it from a git clone, you'll need to install a few packages first: * [GCC](https://gcc.gnu.org) * [Make](https://www.gnu.org/software/make/) * [Autotools](https://www.gnu.org/software/automake/) For Linux systems, these will all be in your system's package manager, and if you do development on the machine they're most likely already installed. On macOS, these are all included in Apple's command line tools, which can be installed from [Xcode](https://developer.apple.com/xcode/). However, you may find that you need a newer version of Bison than the one provided by Apple. This can be found in [Homebrew](https://brew.sh/) or [MacPorts](https://macports.org/). If you want to generate the lexer and parser from source you can use the `--enable-maintainer-mode` configure flag. This requires bison to be installed. [Flex](https://github.com/westes/flex) and [Bison](https://www.gnu.org/software/bison/). ### Docker Docker image is available from [GitHub Container Registry](https://github.com/jqlang/jq/pkgs/container/jq). docker run -i --rm ghcr.io/jqlang/jq -n 'range(3)' #### Building the documentation jq's documentation is compiled into static HTML using Python. To build the docs, run `pipenv run python3 build_website.py` in the `docs/` directory. To serve them locally, you can run `python3 -m http.server -d output`. You'll need a few Python 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 Python dependencies to build the manpage. ================================================ FILE: docs/content/index.yml ================================================ headline: jq blurb: | jq is a lightweight and flexible command-line JSON processor. body1: | jq is like `sed` for JSON data - you can use it to slice and filter and map and transform structured data with the same ease that `sed`, `awk`, `grep` and friends let you play with text. body2: | jq is written in portable C, and it has zero runtime dependencies. You can download a single binary, `scp` it to a far away machine of the same type, and expect it to work. body3: | jq can mangle the data format that you have into the one that you want with very little effort, and the program to do so is often shorter and simpler than you'd expect. tail: | Go read the [tutorial](./tutorial/) for more, or the [manual](./manual/) for *way* more. Have a question related to jq? You can seek answers on [Stack Overflow](https://stackoverflow.com/) by using the [jq tag](https://stackoverflow.com/questions/tagged/jq), or in the [#jq channel](https://web.libera.chat/#jq) on [Libera.Chat](https://libera.chat/). For more interactive discussions, feel free to join our [Discord server](https://discord.gg/yg6yjNmgAC). news: - date: 1 July 2025 body: | jq 1.8.1 released. See [release notes](https://github.com/jqlang/jq/releases/tag/jq-1.8.1) for details. - date: 1 June 2025 body: | jq 1.8.0 released. See [release notes](https://github.com/jqlang/jq/releases/tag/jq-1.8.0) for details. - date: 13 December 2023 body: | jq 1.7.1 released. Security (CVE-2023-50246, CVE-2023-50268) and bug fixes. See [release notes](https://github.com/jqlang/jq/releases/tag/jq-1.7.1) for details. - date: 7 September 2023 body: | After a five-year hiatus, we've returned with a revitalized [GitHub organization](https://github.com/jqlang) and a much-anticipated 1.7 release, thanks to our new admins and maintainers. Check out the [download](./download/) page for installation options and see the [release notes](https://github.com/jqlang/jq/releases/tag/jq-1.7) for details. - date: 1 November 2018 body: | jq 1.6 released. See installation options on the [download](./download/) page, and the [release notes](https://github.com/jqlang/jq/releases/tag/jq-1.6) for details. - date: 15 August 2015 body: | jq 1.5 released, including new datetime, math, and regexp functions, try/catch syntax, array and object destructuring, a streaming parser, and a module system. See installation options on the [download](./download/) page, and the [release notes](https://github.com/jqlang/jq/releases/tag/jq-1.5) for details. - date: 26 July 2015 body: | jq 1.5rc2 is available. Get it on the [releases](https://github.com/jqlang/jq/releases) page. - date: 01 January 2015 body: | jq 1.5rc1 is available. Get it on the [releases](https://github.com/jqlang/jq/releases) page. - date: 09 June 2014 body: | jq 1.4 (finally) released! Get it on the [download](./download/) page. - date: 19 May 2013 body: | jq 1.3 released. ================================================ FILE: docs/content/manual/dev/manual.yml ================================================ --- headline: jq Manual (development version) body: | A jq program is a "filter": it takes an input, and produces an output. There are a lot of builtin filters for extracting a particular field of an object, or converting a number to a string, or various other standard tasks. Filters can be combined in various ways - you can pipe the output of one filter into another filter, or collect the output of a filter into an array. Some filters produce multiple results, for instance there's one that produces all the elements of its input array. Piping that filter into a second runs the second filter for each element of the array. Generally, things that would be done with loops and iteration in other languages are just done by gluing filters together in jq. It's important to remember that every filter has an input and an output. Even literals like "hello" or 42 are filters - they take an input but always produce the same literal as output. Operations that combine two filters, like addition, generally feed the same input to both and combine the results. So, you can implement an averaging filter as `add / length` - feeding the input array both to the `add` filter and the `length` filter and then performing the division. But that's getting ahead of ourselves. :) Let's start with something simpler: manpage_intro: | jq(1) -- Command-line JSON processor ==================================== ## SYNOPSIS `jq` [...] [...] `jq` can transform JSON in various ways, by selecting, iterating, reducing and otherwise mangling JSON documents. For instance, running the command `jq 'map(.price) | add'` will take an array of JSON objects as input and return the sum of their "price" fields. `jq` can accept text input as well, but by default, `jq` reads a stream of JSON entities (including numbers and other literals) from `stdin`. Whitespace is only needed to separate entities such as 1 and 2, and true and false. One or more may be specified, in which case `jq` will read input from those instead. The are described in the [INVOKING JQ] section; they mostly concern input and output formatting. The is written in the jq language and specifies how to transform the input file or document. ## FILTERS manpage_epilogue: | ## BUGS Presumably. Report them or discuss them at: https://github.com/jqlang/jq/issues ## AUTHOR Stephen Dolan `` sections: - title: Invoking jq body: | jq filters run on a stream of JSON data. The input to jq is parsed as a sequence of whitespace-separated JSON values which are passed through the provided filter one at a time. The output(s) of the filter are written to standard output, as a sequence of newline-separated JSON data. The simplest and most common filter (or jq program) is `.`, which is the identity operator, copying the inputs of the jq processor to the output stream. Because the default behavior of the jq processor is to read JSON texts from the input stream, and to pretty-print outputs, the `.` program's main use is to validate and pretty-print the inputs. The jq programming language is quite rich and allows for much more than just validation and pretty-printing. Note: it is important to mind the shell's quoting rules. As a general rule it's best to always quote (with single-quote characters on Unix shells) the jq program, as too many characters with special meaning to jq are also shell meta-characters. For example, `jq "foo"` will fail on most Unix shells because that will be the same as `jq foo`, which will generally fail because `foo is not defined`. When using the Windows command shell (cmd.exe) it's best to use double quotes around your jq program when given on the command-line (instead of the `-f program-file` option), but then double-quotes in the jq program need backslash escaping. When using the Powershell (`powershell.exe`) or the Powershell Core (`pwsh`/`pwsh.exe`), use single-quote characters around the jq program and backslash-escaped double-quotes (`\"`) inside the jq program. * Unix shells: `jq '.["foo"]'` * Powershell: `jq '.[\"foo\"]'` * Windows command shell: `jq ".[\"foo\"]"` Note: jq allows user-defined functions, but every jq program must have a top-level expression. You can affect how jq reads and writes its input and output using some command-line options: * `--null-input` / `-n`: Don't read any input at all. Instead, the filter is run once using `null` as the input. This is useful when using jq as a simple calculator or to construct JSON data from scratch. * `--raw-input` / `-R`: Don't parse the input as JSON. Instead, each line of text is passed to the filter as a string. If combined with `--slurp`, then the entire input is passed to the filter as a single long string. * `--slurp` / `-s`: Instead of running the filter for each JSON object in the input, read the entire input stream into a large array and run the filter just once. * `--compact-output` / `-c`: By default, jq pretty-prints JSON output. Using this option will result in more compact output by instead putting each JSON object on a single line. * `--raw-output` / `-r`: With this option, if the filter's result is a string then it will be written directly to standard output rather than being formatted as a JSON string with quotes. This can be useful for making jq filters talk to non-JSON-based systems. * `--raw-output0`: Like `-r` but jq will print NUL instead of newline after each output. This can be useful when the values being output can contain newlines. When the output value contains NUL, jq exits with non-zero code. * `--join-output` / `-j`: Like `-r` but jq won't print a newline after each output. * `--ascii-output` / `-a`: jq usually outputs non-ASCII Unicode codepoints as UTF-8, even if the input specified them as escape sequences (like "\u03bc"). Using this option, you can force jq to produce pure ASCII output with every non-ASCII character replaced with the equivalent escape sequence. * `--sort-keys` / `-S`: Output the fields of each object with the keys in sorted order. * `--color-output` / `-C` and `--monochrome-output` / `-M`: By default, jq outputs colored JSON if writing to a terminal. You can force it to produce color even if writing to a pipe or a file using `-C`, and disable color with `-M`. When the `NO_COLOR` environment variable is not empty, jq disables colored output by default, but you can enable it by `-C`. Colors can be configured with the `JQ_COLORS` environment variable (see below). * `--tab`: Use a tab for each indentation level instead of two spaces. * `--indent n`: Use the given number of spaces (no more than 7) for indentation. * `--unbuffered`: Flush the output after each JSON object is printed (useful if you're piping a slow data source into jq and piping jq's output elsewhere). * `--stream`: Parse the input in streaming fashion, outputting arrays of path and leaf values (scalars and empty arrays or empty objects). For example, `"a"` becomes `[[],"a"]`, and `[[],"a",["b"]]` becomes `[[0],[]]`, `[[1],"a"]`, and `[[2,0],"b"]`. This is useful for processing very large inputs. Use this in conjunction with filtering and the `reduce` and `foreach` syntax to reduce large inputs incrementally. * `--stream-errors`: Like `--stream`, but invalid JSON inputs yield array values where the first element is the error and the second is a path. For example, `["a",n]` produces `["Invalid literal at line 1, column 7",[1]]`. Implies `--stream`. Invalid JSON inputs produce no error values when `--stream` without `--stream-errors`. * `--seq`: Use the `application/json-seq` MIME type scheme for separating JSON texts in jq's input and output. This means that an ASCII RS (record separator) character is printed before each value on output and an ASCII LF (line feed) is printed after every output. Input JSON texts that fail to parse are ignored (but warned about), discarding all subsequent input until the next RS. This mode also parses the output of jq without the `--seq` option. * `-f` / `--from-file`: Read the filter from a file rather than from a command line, like awk's -f option. This changes the filter argument to be interpreted as a filename, instead of the source of a program. * `-L directory` / `--library-path directory`: Prepend `directory` to the search list for modules. If this option is used then no builtin search list is used. See the section on modules below. * `--arg name value`: This option passes a value to the jq program as a predefined variable. If you run jq with `--arg foo bar`, then `$foo` is available in the program and has the value `"bar"`. Note that `value` will be treated as a string, so `--arg foo 123` will bind `$foo` to `"123"`. Named arguments are also available to the jq program as `$ARGS.named`. When the name is not a valid identifier, this is the only way to access it. * `--argjson name JSON-text`: This option passes a JSON-encoded value to the jq program as a predefined variable. If you run jq with `--argjson foo 123`, then `$foo` is available in the program and has the value `123`. * `--slurpfile variable-name filename`: This option reads all the JSON texts in the named file and binds an array of the parsed JSON values to the given global variable. If you run jq with `--slurpfile foo bar`, then `$foo` is available in the program and has an array whose elements correspond to the texts in the file named `bar`. * `--rawfile variable-name filename`: This option reads in the named file and binds its content to the given global variable. If you run jq with `--rawfile foo bar`, then `$foo` is available in the program and has a string whose content is set to the text in the file named `bar`. * `--args`: Remaining arguments are positional string arguments. These are available to the jq program as `$ARGS.positional[]`. * `--jsonargs`: Remaining arguments are positional JSON text arguments. These are available to the jq program as `$ARGS.positional[]`. * `--exit-status` / `-e`: Sets the exit status of jq to 0 if the last output value was neither `false` nor `null`, 1 if the last output value was either `false` or `null`, or 4 if no valid result was ever produced. Normally jq exits with 2 if there was any usage problem or system error, 3 if there was a jq program compile error, or 0 if the jq program ran. Another way to set the exit status is with the `halt_error` builtin function. * `--binary` / `-b`: Windows users using WSL, MSYS2, or Cygwin, should use this option when using a native jq.exe, otherwise jq will turn newlines (LFs) into carriage-return-then-newline (CRLF). * `--version` / `-V`: Output the jq version and exit with zero. * `--build-configuration`: Output the build configuration of jq and exit with zero. This output has no supported format or structure and may change without notice in future releases. * `--help` / `-h`: Output the jq help and exit with zero. * `--`: Terminates argument processing. Remaining arguments are not interpreted as options. * `--run-tests [filename]`: Runs the tests in the given file or standard input. This must be the last option given and does not honor all preceding options. The input consists of comment lines, empty lines, and program lines followed by one input line, as many lines of output as are expected (one per output), and a terminating empty line. Compilation failure tests start with a line containing only `%%FAIL`, then a line containing the program to compile, then a line containing an error message to compare to the actual. Be warned that this option can change backwards-incompatibly. - title: Basic filters entries: - title: "Identity: `.`" body: | The absolute simplest filter is `.` . This filter takes its input and produces the same value as output. That is, this is the identity operator. Since jq by default pretty-prints all output, a trivial program consisting of nothing but `.` can be used to format JSON output from, say, `curl`. Although the identity filter never modifies the value of its input, jq processing can sometimes make it appear as though it does. For example, using the current implementation of jq, we would see that the expression: 1E1234567890 | . produces `1.7976931348623157e+308` on at least one platform. This is because, in the process of parsing the number, this particular version of jq has converted it to an IEEE754 double-precision representation, losing precision. The way in which jq handles numbers has changed over time and further changes are likely within the parameters set by the relevant JSON standards. Moreover, build configuration options can alter how jq processes numbers. The following remarks are therefore offered with the understanding that they are intended to be descriptive of the current version of jq and should not be interpreted as being prescriptive: (1) Any arithmetic operation on a number that has not already been converted to an IEEE754 double precision representation will trigger a conversion to the IEEE754 representation. (2) jq will attempt to maintain the original decimal precision of number literals (if the `--disable-decnum` build configuration option was not used), but in expressions such `1E1234567890`, precision will be lost if the exponent is too large. (3) Comparisons are carried out using the untruncated big decimal representation of numbers if available, as illustrated in one of the following examples. The examples below use the builtin function `have_decnum` in order to demonstrate the expected effects of using / not using the `--disable-decnum` build configuration option, and also to allow automated tests derived from these examples to pass regardless of whether that option is used. examples: - program: '.' input: '"Hello, world!"' output: ['"Hello, world!"'] - program: '.' input: '0.12345678901234567890123456789' output: ['0.12345678901234567890123456789'] - program: '[., tojson] == if have_decnum then [12345678909876543212345,"12345678909876543212345"] else [12345678909876543000000,"12345678909876543000000"] end' input: '12345678909876543212345' output: ['true'] - program: '[1234567890987654321,-1234567890987654321 | tojson] == if have_decnum then ["1234567890987654321","-1234567890987654321"] else ["1234567890987654400","-1234567890987654400"] end' input: 'null' output: ['true'] - program: '. < 0.12345678901234567890123456788' input: '0.12345678901234567890123456789' output: ['false'] - program: 'map([., . == 1]) | tojson == if have_decnum then "[[1,true],[1.000,true],[1.0,true],[1.00,true]]" else "[[1,true],[1,true],[1,true],[1,true]]" end' input: '[1, 1.000, 1.0, 100e-2]' output: ['true'] - program: '. as $big | [$big, $big + 1] | map(. > 10000000000000000000000000000000) | . == if have_decnum then [true, false] else [false, false] end' input: '10000000000000000000000000000001' output: ['true'] - title: "Object Identifier-Index: `.foo`, `.foo.bar`" body: | The simplest *useful* filter has the form `.foo`. When given a JSON object (aka dictionary or hash) as input, `.foo` produces the value at the key "foo" if the key is present, or null otherwise. A filter of the form `.foo.bar` is equivalent to `.foo | .bar`. The `.foo` syntax only works for simple, identifier-like keys, that is, keys that are all made of alphanumeric characters and underscore, and which do not start with a digit. If the key contains special characters or starts with a digit, you need to surround it with double quotes like this: `."foo$"`, or else `.["foo$"]`. For example `.["foo::bar"]` and `.["foo.bar"]` work while `.foo::bar` does not. examples: - program: '.foo' input: '{"foo": 42, "bar": "less interesting data"}' output: ['42'] - program: '.foo' input: '{"notfoo": true, "alsonotfoo": false}' output: ['null'] - program: '.["foo"]' input: '{"foo": 42}' output: ['42'] - title: "Optional Object Identifier-Index: `.foo?`" body: | Just like `.foo`, but does not output an error when `.` is not an object. examples: - program: '.foo?' input: '{"foo": 42, "bar": "less interesting data"}' output: ['42'] - program: '.foo?' input: '{"notfoo": true, "alsonotfoo": false}' output: ['null'] - program: '.["foo"]?' input: '{"foo": 42}' output: ['42'] - program: '[.foo?]' input: '[1,2]' output: ['[]'] - title: "Object Index: `.[]`" body: | You can also look up fields of an object using syntax like `.["foo"]` (`.foo` above is a shorthand version of this, but only for identifier-like strings). - title: "Array Index: `.[]`" body: | When the index value is an integer, `.[]` can index arrays. Arrays are zero-based, so `.[2]` returns the third element. Negative indices are allowed, with -1 referring to the last element, -2 referring to the next to last element, and so on. examples: - program: '.[0]' input: '[{"name":"JSON", "good":true}, {"name":"XML", "good":false}]' output: ['{"name":"JSON", "good":true}'] - program: '.[2]' input: '[{"name":"JSON", "good":true}, {"name":"XML", "good":false}]' output: ['null'] - program: '.[-2]' input: '[1,2,3]' output: ['2'] - title: "Array/String Slice: `.[:]`" body: | The `.[:]` syntax can be used to return a subarray of an array or substring of a string. The array returned by `.[10:15]` will be of length 5, containing the elements from index 10 (inclusive) to index 15 (exclusive). Either index may be negative (in which case it counts backwards from the end of the array), or omitted (in which case it refers to the start or end of the array). Indices are zero-based. examples: - program: '.[2:4]' input: '["a","b","c","d","e"]' output: ['["c", "d"]'] - program: '.[2:4]' input: '"abcdefghi"' output: ['"cd"'] - program: '.[:3]' input: '["a","b","c","d","e"]' output: ['["a", "b", "c"]'] - program: '.[-2:]' input: '["a","b","c","d","e"]' output: ['["d", "e"]'] - title: "Array/Object Value Iterator: `.[]`" body: | If you use the `.[index]` syntax, but omit the index entirely, it will return *all* of the elements of an array. Running `.[]` with the input `[1,2,3]` will produce the numbers as three separate results, rather than as a single array. A filter of the form `.foo[]` is equivalent to `.foo | .[]`. You can also use this on an object, and it will return all the values of the object. Note that the iterator operator is a generator of values. examples: - program: '.[]' input: '[{"name":"JSON", "good":true}, {"name":"XML", "good":false}]' output: - '{"name":"JSON", "good":true}' - '{"name":"XML", "good":false}' - program: '.[]' input: '[]' output: [] - program: '.foo[]' input: '{"foo":[1,2,3]}' output: ['1','2','3'] - program: '.[]' input: '{"a": 1, "b": 1}' output: ['1', '1'] - title: "`.[]?`" body: | Like `.[]`, but no errors will be output if . is not an array or object. A filter of the form `.foo[]?` is equivalent to `.foo | .[]?`. - title: "Comma: `,`" body: | If two filters are separated by a comma, then the same input will be fed into both and the two filters' output value streams will be concatenated in order: first, all of the outputs produced by the left expression, and then all of the outputs produced by the right. For instance, filter `.foo, .bar`, produces both the "foo" fields and "bar" fields as separate outputs. The `,` operator is one way to construct generators. examples: - program: '.foo, .bar' input: '{"foo": 42, "bar": "something else", "baz": true}' output: ['42', '"something else"'] - program: ".user, .projects[]" input: '{"user":"stedolan", "projects": ["jq", "wikiflow"]}' output: ['"stedolan"', '"jq"', '"wikiflow"'] - program: '.[4,2]' input: '["a","b","c","d","e"]' output: ['"e"', '"c"'] - title: "Pipe: `|`" body: | The | operator combines two filters by feeding the output(s) of the one on the left into the input of the one on the right. It's similar to the Unix shell's pipe, if you're used to that. If the one on the left produces multiple results, the one on the right will be run for each of those results. So, the expression `.[] | .foo` retrieves the "foo" field of each element of the input array. This is a cartesian product, which can be surprising. Note that `.a.b.c` is the same as `.a | .b | .c`. Note too that `.` is the input value at the particular stage in a "pipeline", specifically: where the `.` expression appears. Thus `.a | . | .b` is the same as `.a.b`, as the `.` in the middle refers to whatever value `.a` produced. examples: - program: '.[] | .name' input: '[{"name":"JSON", "good":true}, {"name":"XML", "good":false}]' output: ['"JSON"', '"XML"'] - title: "Parenthesis" body: | Parenthesis work as a grouping operator just as in any typical programming language. examples: - program: '(. + 2) * 5' input: '1' output: ['15'] - title: Types and Values body: | jq supports the same set of datatypes as JSON - numbers, strings, booleans, arrays, objects (which in JSON-speak are hashes with only string keys), and "null". Booleans, null, strings and numbers are written the same way as in JSON. Just like everything else in jq, these simple values take an input and produce an output - `42` is a valid jq expression that takes an input, ignores it, and returns 42 instead. Numbers in jq are internally represented by their IEEE754 double precision approximation. Any arithmetic operation with numbers, whether they are literals or results of previous filters, will produce a double precision floating point result. However, when parsing a literal jq will store the original literal string. If no mutation is applied to this value then it will make to the output in its original form, even if conversion to double would result in a loss. entries: - title: "Array construction: `[]`" body: | As in JSON, `[]` is used to construct arrays, as in `[1,2,3]`. The elements of the arrays can be any jq expression, including a pipeline. All of the results produced by all of the expressions are collected into one big array. You can use it to construct an array out of a known quantity of values (as in `[.foo, .bar, .baz]`) or to "collect" all the results of a filter into an array (as in `[.items[].name]`) Once you understand the "," operator, you can look at jq's array syntax in a different light: the expression `[1,2,3]` is not using a built-in syntax for comma-separated arrays, but is instead applying the `[]` operator (collect results) to the expression 1,2,3 (which produces three different results). If you have a filter `X` that produces four results, then the expression `[X]` will produce a single result, an array of four elements. examples: - program: "[.user, .projects[]]" input: '{"user":"stedolan", "projects": ["jq", "wikiflow"]}' output: ['["stedolan", "jq", "wikiflow"]'] - program: "[ .[] | . * 2]" input: '[1, 2, 3]' output: ['[2, 4, 6]'] - title: "Object Construction: `{}`" body: | Like JSON, `{}` is for constructing objects (aka dictionaries or hashes), as in: `{"a": 42, "b": 17}`. If the keys are "identifier-like", then the quotes can be left off, as in `{a:42, b:17}`. Variable references as key expressions use the value of the variable as the key. Key expressions other than constant literals, identifiers, or variable references, need to be parenthesized, e.g., `{("a"+"b"):59}`. The value can be any expression (although you may need to wrap it in parentheses if, for example, it contains colons), which gets applied to the {} expression's input (remember, all filters have an input and an output). {foo: .bar} will produce the JSON object `{"foo": 42}` if given the JSON object `{"bar":42, "baz":43}` as its input. You can use this to select particular fields of an object: if the input is an object with "user", "title", "id", and "content" fields and you just want "user" and "title", you can write {user: .user, title: .title} Because that is so common, there's a shortcut syntax for it: `{user, title}`. If one of the expressions produces multiple results, multiple dictionaries will be produced. If the input's {"user":"stedolan","titles":["JQ Primer", "More JQ"]} then the expression {user, title: .titles[]} will produce two outputs: {"user":"stedolan", "title": "JQ Primer"} {"user":"stedolan", "title": "More JQ"} Putting parentheses around the key means it will be evaluated as an expression. With the same input as above, {(.user): .titles} produces {"stedolan": ["JQ Primer", "More JQ"]} Variable references as keys use the value of the variable as the key. Without a value then the variable's name becomes the key and its value becomes the value, "f o o" as $foo | "b a r" as $bar | {$foo, $bar:$foo} produces {"foo":"f o o","b a r":"f o o"} examples: - program: '{user, title: .titles[]}' input: '{"user":"stedolan","titles":["JQ Primer", "More JQ"]}' output: - '{"user":"stedolan", "title": "JQ Primer"}' - '{"user":"stedolan", "title": "More JQ"}' - program: '{(.user): .titles}' input: '{"user":"stedolan","titles":["JQ Primer", "More JQ"]}' output: ['{"stedolan": ["JQ Primer", "More JQ"]}'] - title: "Recursive Descent: `..`" body: | Recursively descends `.`, producing every value. This is the same as the zero-argument `recurse` builtin (see below). This is intended to resemble the XPath `//` operator. Note that `..a` does not work; use `.. | .a` instead. In the example below we use `.. | .a?` to find all the values of object keys "a" in any object found "below" `.`. This is particularly useful in conjunction with `path(EXP)` (also see below) and the `?` operator. examples: - program: '.. | .a?' input: '[[{"a":1}]]' output: ['1'] - title: Builtin operators and functions body: | Some jq operators (for instance, `+`) do different things depending on the type of their arguments (arrays, numbers, etc.). However, jq never does implicit type conversions. If you try to add a string to an object you'll get an error message and no result. Please note that all numbers are converted to IEEE754 double precision floating point representation. Arithmetic and logical operators are working with these converted doubles. Results of all such operations are also limited to the double precision. The only exception to this behaviour of number is a snapshot of original number literal. When a number which originally was provided as a literal is never mutated until the end of the program then it is printed to the output in its original literal form. This also includes cases when the original literal would be truncated when converted to the IEEE754 double precision floating point number. entries: - title: "Addition: `+`" body: | The operator `+` takes two filters, applies them both to the same input, and adds the results together. What "adding" means depends on the types involved: - **Numbers** are added by normal arithmetic. - **Arrays** are added by being concatenated into a larger array. - **Strings** are added by being joined into a larger string. - **Objects** are added by merging, that is, inserting all the key-value pairs from both objects into a single combined object. If both objects contain a value for the same key, the object on the right of the `+` wins. (For recursive merge use the `*` operator.) `null` can be added to any value, and returns the other value unchanged. examples: - program: '.a + 1' input: '{"a": 7}' output: ['8'] - program: '.a + .b' input: '{"a": [1,2], "b": [3,4]}' output: ['[1,2,3,4]'] - program: '.a + null' input: '{"a": 1}' output: ['1'] - program: '.a + 1' input: '{}' output: ['1'] - program: '{a: 1} + {b: 2} + {c: 3} + {a: 42}' input: 'null' output: ['{"a": 42, "b": 2, "c": 3}'] - title: "Subtraction: `-`" body: | As well as normal arithmetic subtraction on numbers, the `-` operator can be used on arrays to remove all occurrences of the second array's elements from the first array. examples: - program: '4 - .a' input: '{"a":3}' output: ['1'] - program: . - ["xml", "yaml"] input: '["xml", "yaml", "json"]' output: ['["json"]'] - title: "Multiplication, division, modulo: `*`, `/`, `%`" body: | These infix operators behave as expected when given two numbers. Division by zero raises an error. `x % y` computes x modulo y. Multiplying a string by a number produces the concatenation of that string that many times. `"x" * 0` produces `""`. Dividing a string by another splits the first using the second as separators. Multiplying two objects will merge them recursively: this works like addition but if both objects contain a value for the same key, and the values are objects, the two are merged with the same strategy. examples: - program: '10 / . * 3' input: '5' output: ['6'] - program: '. / ", "' input: '"a, b,c,d, e"' output: ['["a","b,c,d","e"]'] - program: '{"k": {"a": 1, "b": 2}} * {"k": {"a": 0,"c": 3}}' input: 'null' output: ['{"k": {"a": 0, "b": 2, "c": 3}}'] - program: '.[] | (1 / .)?' input: '[1,0,-1]' output: ['1', '-1'] - title: "`abs`" body: | The builtin function `abs` is defined naively as: `if . < 0 then - . else . end`. For numeric input, this is the absolute value. See the section on the identity filter for the implications of this definition for numeric input. To compute the absolute value of a number as a floating point number, you may wish use `fabs`. examples: - program: 'map(abs)' input: '[-10, -1.1, -1e-1]' output: ['[10,1.1,1e-1]'] - title: "`length`" body: | The builtin function `length` gets the length of various different types of value: - The length of a **string** is the number of Unicode codepoints it contains (which will be the same as its JSON-encoded length in bytes if it's pure ASCII). - The length of a **number** is its absolute value. - The length of an **array** is the number of elements. - The length of an **object** is the number of key-value pairs. - The length of **null** is zero. - It is an error to use `length` on a **boolean**. examples: - program: '.[] | length' input: '[[1,2], "string", {"a":2}, null, -5]' output: ['2', '6', '1', '0', '5'] - title: "`utf8bytelength`" body: | The builtin function `utf8bytelength` outputs the number of bytes used to encode a string in UTF-8. examples: - program: 'utf8bytelength' input: '"\u03bc"' output: ['2'] - title: "`keys`, `keys_unsorted`" body: | The builtin function `keys`, when given an object, returns its keys in an array. The keys are sorted "alphabetically", by unicode codepoint order. This is not an order that makes particular sense in any particular language, but you can count on it being the same for any two objects with the same set of keys, regardless of locale settings. When `keys` is given an array, it returns the valid indices for that array: the integers from 0 to length-1. The `keys_unsorted` function is just like `keys`, but if the input is an object then the keys will not be sorted, instead the keys will roughly be in insertion order. examples: - program: 'keys' input: '{"abc": 1, "abcd": 2, "Foo": 3}' output: ['["Foo", "abc", "abcd"]'] - program: 'keys' input: '[42,3,35]' output: ['[0,1,2]'] - title: "`has(key)`" body: | The builtin function `has` returns whether the input object has the given key, or the input array has an element at the given index. `has($key)` has the same effect as checking whether `$key` is a member of the array returned by `keys`, although `has` will be faster. examples: - program: 'map(has("foo"))' input: '[{"foo": 42}, {}]' output: ['[true, false]'] - program: 'map(has(2))' input: '[[0,1], ["a","b","c"]]' output: ['[false, true]'] - title: "`in`" body: | The builtin function `in` returns whether or not the input key is in the given object, or the input index corresponds to an element in the given array. It is, essentially, an inversed version of `has`. examples: - program: '.[] | in({"foo": 42})' input: '["foo", "bar"]' output: ['true', 'false'] - program: 'map(in([0,1]))' input: '[2, 0]' output: ['[false, true]'] - title: "`map(f)`, `map_values(f)`" body: | For any filter `f`, `map(f)` and `map_values(f)` apply `f` to each of the values in the input array or object, that is, to the values of `.[]`. In the absence of errors, `map(f)` always outputs an array whereas `map_values(f)` outputs an array if given an array, or an object if given an object. When the input to `map_values(f)` is an object, the output object has the same keys as the input object except for those keys whose values when piped to `f` produce no values at all. The key difference between `map(f)` and `map_values(f)` is that the former simply forms an array from all the values of `($x|f)` for each value, `$x`, in the input array or object, but `map_values(f)` only uses `first($x|f)`. Specifically, for object inputs, `map_values(f)` constructs the output object by examining in turn the value of `first(.[$k]|f)` for each key, `$k`, of the input. If this expression produces no values, then the corresponding key will be dropped; otherwise, the output object will have that value at the key, `$k`. Here are some examples to clarify the behavior of `map` and `map_values` when applied to arrays. These examples assume the input is `[1]` in all cases: map(.+1) #=> [2] map(., .) #=> [1,1] map(empty) #=> [] map_values(.+1) #=> [2] map_values(., .) #=> [1] map_values(empty) #=> [] `map(f)` is equivalent to `[.[] | f]` and `map_values(f)` is equivalent to `.[] |= f`. In fact, these are their implementations. examples: - program: 'map(.+1)' input: '[1,2,3]' output: ['[2,3,4]'] - program: 'map_values(.+1)' input: '{"a": 1, "b": 2, "c": 3}' output: ['{"a": 2, "b": 3, "c": 4}'] - program: 'map(., .)' input: '[1,2]' output: ['[1,1,2,2]'] - program: 'map_values(. // empty)' input: '{"a": null, "b": true, "c": false}' output: ['{"b":true}'] - title: "`pick(pathexps)`" body: | Emit the projection of the input object or array defined by the specified sequence of path expressions, such that if `p` is any one of these specifications, then `(. | p)` will evaluate to the same value as `(. | pick(pathexps) | p)`. For arrays, negative indices and `.[m:n]` specifications should not be used. examples: - program: 'pick(.a, .b.c, .x)' input: '{"a": 1, "b": {"c": 2, "d": 3}, "e": 4}' output: ['{"a":1,"b":{"c":2},"x":null}'] - program: 'pick(.[2], .[0], .[0])' input: '[1,2,3,4]' output: ['[1,null,3]'] - title: "`path(path_expression)`" body: | Outputs array representations of the given path expression in `.`. The outputs are arrays of strings (object keys) and/or numbers (array indices). Path expressions are jq expressions like `.a`, but also `.[]`. There are two types of path expressions: ones that can match exactly, and ones that cannot. For example, `.a.b.c` is an exact match path expression, while `.a[].b` is not. `path(exact_path_expression)` will produce the array representation of the path expression even if it does not exist in `.`, if `.` is `null` or an array or an object. `path(pattern)` will produce array representations of the paths matching `pattern` if the paths exist in `.`. Note that the path expressions are not different from normal expressions. The expression `path(..|select(type=="boolean"))` outputs all the paths to boolean values in `.`, and only those paths. examples: - program: 'path(.a[0].b)' input: 'null' output: ['["a",0,"b"]'] - program: '[path(..)]' input: '{"a":[{"b":1}]}' output: ['[[],["a"],["a",0],["a",0,"b"]]'] - title: "`del(path_expression)`" body: | The builtin function `del` removes a key and its corresponding value from an object. examples: - program: 'del(.foo)' input: '{"foo": 42, "bar": 9001, "baz": 42}' output: ['{"bar": 9001, "baz": 42}'] - program: 'del(.[1, 2])' input: '["foo", "bar", "baz"]' output: ['["foo"]'] - title: "`getpath(PATHS)`" body: | The builtin function `getpath` outputs the values in `.` found at each path in `PATHS`. examples: - program: 'getpath(["a","b"])' input: 'null' output: ['null'] - program: '[getpath(["a","b"], ["a","c"])]' input: '{"a":{"b":0, "c":1}}' output: ['[0, 1]'] - title: "`setpath(PATHS; VALUE)`" body: | The builtin function `setpath` sets the `PATHS` in `.` to `VALUE`. examples: - program: 'setpath(["a","b"]; 1)' input: 'null' output: ['{"a": {"b": 1}}'] - program: 'setpath(["a","b"]; 1)' input: '{"a":{"b":0}}' output: ['{"a": {"b": 1}}'] - program: 'setpath([0,"a"]; 1)' input: 'null' output: ['[{"a":1}]'] - title: "`delpaths(PATHS)`" body: | The builtin function `delpaths` deletes the `PATHS` in `.`. `PATHS` must be an array of paths, where each path is an array of strings and numbers. examples: - program: 'delpaths([["a","b"]])' input: '{"a":{"b":1},"x":{"y":2}}' output: ['{"a":{},"x":{"y":2}}'] - title: "`to_entries`, `from_entries`, `with_entries(f)`" body: | These functions convert between an object and an array of key-value pairs. If `to_entries` is passed an object, then for each `k: v` entry in the input, the output array includes `{"key": k, "value": v}`. `from_entries` does the opposite conversion, and `with_entries(f)` is a shorthand for `to_entries | map(f) | from_entries`, useful for doing some operation to all keys and values of an object. `from_entries` accepts `"key"`, `"Key"`, `"name"`, `"Name"`, `"value"`, and `"Value"` as keys. examples: - program: 'to_entries' input: '{"a": 1, "b": 2}' output: ['[{"key":"a", "value":1}, {"key":"b", "value":2}]'] - program: 'from_entries' input: '[{"key":"a", "value":1}, {"key":"b", "value":2}]' output: ['{"a": 1, "b": 2}'] - program: 'with_entries(.key |= "KEY_" + .)' input: '{"a": 1, "b": 2}' output: ['{"KEY_a": 1, "KEY_b": 2}'] - title: "`select(boolean_expression)`" body: | The function `select(f)` produces its input unchanged if `f` returns true for that input, and produces no output otherwise. It's useful for filtering lists: `[1,2,3] | map(select(. >= 2))` will give you `[2,3]`. examples: - program: 'map(select(. >= 2))' input: '[1,5,3,0,7]' output: ['[5,3,7]'] - program: '.[] | select(.id == "second")' input: '[{"id": "first", "val": 1}, {"id": "second", "val": 2}]' output: ['{"id": "second", "val": 2}'] - title: "`arrays`, `objects`, `iterables`, `booleans`, `numbers`, `normals`, `finites`, `strings`, `nulls`, `values`, `scalars`" body: | These built-ins select only inputs that are arrays, objects, iterables (arrays or objects), booleans, numbers, normal numbers, finite numbers, strings, null, non-null values, and non-iterables, respectively. examples: - program: '.[]|numbers' input: '[[],{},1,"foo",null,true,false]' output: ['1'] - title: "`empty`" body: | `empty` returns no results. None at all. Not even `null`. It's useful on occasion. You'll know if you need it :) examples: - program: '1, empty, 2' input: 'null' output: ['1', '2'] - program: '[1,2,empty,3]' input: 'null' output: ['[1,2,3]'] - title: "`error`, `error(message)`" body: | Produces an error with the input value, or with the message given as the argument. Errors can be caught with try/catch; see below. examples: - program: 'try error catch .' input: '"error message"' output: ['"error message"'] - program: 'try error("invalid value: \(.)") catch .' input: '42' output: ['"invalid value: 42"'] - title: "`halt`" body: | Stops the jq program with no further outputs. jq will exit with exit status `0`. - title: "`halt_error`, `halt_error(exit_code)`" body: | Stops the jq program with no further outputs. The input will be printed on `stderr` as raw output (i.e., strings will not have double quotes) with no decoration, not even a newline. The given `exit_code` (defaulting to `5`) will be jq's exit status. For example, `"Error: something went wrong\n"|halt_error(1)`. - title: "`$__loc__`" body: | Produces an object with a "file" key and a "line" key, with the filename and line number where `$__loc__` occurs, as values. examples: - program: 'try error("\($__loc__)") catch .' input: 'null' output: ['"{\"file\":\"\",\"line\":1}"'] - title: "`paths`, `paths(node_filter)`" body: | `paths` outputs the paths to all the elements in its input (except it does not output the empty list, representing . itself). `paths(f)` outputs the paths to any values for which `f` is `true`. That is, `paths(type == "number")` outputs the paths to all numeric values. examples: - program: '[paths]' input: '[1,[[],{"a":2}]]' output: ['[[0],[1],[1,0],[1,1],[1,1,"a"]]'] - program: '[paths(type == "number")]' input: '[1,[[],{"a":2}]]' output: ['[[0],[1,1,"a"]]'] - title: "`add`, `add(generator)`" body: | The filter `add` takes as input an array, and produces as output the elements of the array added together. This might mean summed, concatenated or merged depending on the types of the elements of the input array - the rules are the same as those for the `+` operator (described above). If the input is an empty array, `add` returns `null`. `add(generator)` operates on the given generator rather than the input. examples: - program: add input: '["a","b","c"]' output: ['"abc"'] - program: add input: '[1, 2, 3]' output: ['6'] - program: add input: '[]' output: ["null"] - program: add(.[].a) input: '[{"a":3}, {"a":5}, {"b":6}]' output: ['8'] - title: "`any`, `any(condition)`, `any(generator; condition)`" body: | The filter `any` takes as input an array of boolean values, and produces `true` as output if any of the elements of the array are `true`. If the input is an empty array, `any` returns `false`. The `any(condition)` form applies the given condition to the elements of the input array. The `any(generator; condition)` form applies the given condition to all the outputs of the given generator. examples: - program: any input: '[true, false]' output: ["true"] - program: any input: '[false, false]' output: ["false"] - program: any input: '[]' output: ["false"] - title: "`all`, `all(condition)`, `all(generator; condition)`" body: | The filter `all` takes as input an array of boolean values, and produces `true` as output if all of the elements of the array are `true`. The `all(condition)` form applies the given condition to the elements of the input array. The `all(generator; condition)` form applies the given condition to all the outputs of the given generator. If the input is an empty array, `all` returns `true`. examples: - program: all input: '[true, false]' output: ["false"] - program: all input: '[true, true]' output: ["true"] - program: all input: '[]' output: ["true"] - title: "`flatten`, `flatten(depth)`" body: | The filter `flatten` takes as input an array of nested arrays, and produces a flat array in which all arrays inside the original array have been recursively replaced by their values. You can pass an argument to it to specify how many levels of nesting to flatten. `flatten(2)` is like `flatten`, but going only up to two levels deep. examples: - program: flatten input: '[1, [2], [[3]]]' output: ["[1, 2, 3]"] - program: flatten(1) input: '[1, [2], [[3]]]' output: ["[1, 2, [3]]"] - program: flatten input: '[[]]' output: ["[]"] - program: flatten input: '[{"foo": "bar"}, [{"foo": "baz"}]]' output: ['[{"foo": "bar"}, {"foo": "baz"}]'] - title: "`range(upto)`, `range(from; upto)`, `range(from; upto; by)`" body: | The `range` function produces a range of numbers. `range(4; 10)` produces 6 numbers, from 4 (inclusive) to 10 (exclusive). The numbers are produced as separate outputs. Use `[range(4; 10)]` to get a range as an array. The one argument form generates numbers from 0 to the given number, with an increment of 1. The two argument form generates numbers from `from` to `upto` with an increment of 1. The three argument form generates numbers `from` to `upto` with an increment of `by`. examples: - program: 'range(2; 4)' input: 'null' output: ['2', '3'] - program: '[range(2; 4)]' input: 'null' output: ['[2,3]'] - program: '[range(4)]' input: 'null' output: ['[0,1,2,3]'] - program: '[range(0; 10; 3)]' input: 'null' output: ['[0,3,6,9]'] - program: '[range(0; 10; -1)]' input: 'null' output: ['[]'] - program: '[range(0; -5; -1)]' input: 'null' output: ['[0,-1,-2,-3,-4]'] - title: "`floor`" body: | The `floor` function returns the floor of its numeric input. examples: - program: 'floor' input: '3.14159' output: ['3'] - title: "`sqrt`" body: | The `sqrt` function returns the square root of its numeric input. examples: - program: 'sqrt' input: '9' output: ['3'] - title: "`tonumber`" body: | The `tonumber` function parses its input as a number. It will convert correctly-formatted strings to their numeric equivalent, leave numbers alone, and give an error on all other input. examples: - program: '.[] | tonumber' input: '[1, "1"]' output: ['1', '1'] - title: "`toboolean`" body: | The `toboolean` function parses its input as a boolean. It will convert correctly-formatted strings to their boolean equivalent, leave booleans alone, and give an error on all other input. examples: - program: '.[] | toboolean' input: '["true", "false", true, false]' output: ['true', 'false', 'true', 'false'] - title: "`tostring`" body: | The `tostring` function prints its input as a string. Strings are left unchanged, and all other values are JSON-encoded. examples: - program: '.[] | tostring' input: '[1, "1", [1]]' output: ['"1"', '"1"', '"[1]"'] - title: "`type`" body: | The `type` function returns the type of its argument as a string, which is one of null, boolean, number, string, array or object. examples: - program: 'map(type)' input: '[0, false, [], {}, null, "hello"]' output: ['["number", "boolean", "array", "object", "null", "string"]'] - title: "`infinite`, `nan`, `isinfinite`, `isnan`, `isfinite`, `isnormal`" body: | Some arithmetic operations can yield infinities and "not a number" (NaN) values. The `isinfinite` builtin returns `true` if its input is infinite. The `isnan` builtin returns `true` if its input is a NaN. The `infinite` builtin returns a positive infinite value. The `nan` builtin returns a NaN. The `isnormal` builtin returns true if its input is a normal number. Note that division by zero raises an error. Currently most arithmetic operations operating on infinities, NaNs, and sub-normals do not raise errors. examples: - program: '.[] | (infinite * .) < 0' input: '[-1, 1]' output: ['true', 'false'] - program: 'infinite, nan | type' input: 'null' output: ['"number"', '"number"'] - title: "`sort`, `sort_by(path_expression)`" body: | The `sort` functions sorts its input, which must be an array. Values are sorted in the following order: * `null` * `false` * `true` * numbers * strings, in alphabetical order (by unicode codepoint value) * arrays, in lexical order * objects The ordering for objects is a little complex: first they're compared by comparing their sets of keys (as arrays in sorted order), and if their keys are equal then the values are compared key by key. `sort_by` may be used to sort by a particular field of an object, or by applying any jq filter. `sort_by(f)` compares two elements by comparing the result of `f` on each element. When `f` produces multiple values, it firstly compares the first values, and the second values if the first values are equal, and so on. examples: - program: 'sort' input: '[8,3,null,6]' output: ['[null,3,6,8]'] - program: 'sort_by(.foo)' input: '[{"foo":4, "bar":10}, {"foo":3, "bar":10}, {"foo":2, "bar":1}]' output: ['[{"foo":2, "bar":1}, {"foo":3, "bar":10}, {"foo":4, "bar":10}]'] - program: 'sort_by(.foo, .bar)' input: '[{"foo":4, "bar":10}, {"foo":3, "bar":20}, {"foo":2, "bar":1}, {"foo":3, "bar":10}]' output: ['[{"foo":2, "bar":1}, {"foo":3, "bar":10}, {"foo":3, "bar":20}, {"foo":4, "bar":10}]'] - title: "`group_by(path_expression)`" body: | `group_by(.foo)` takes as input an array, groups the elements having the same `.foo` field into separate arrays, and produces all of these arrays as elements of a larger array, sorted by the value of the `.foo` field. Any jq expression, not just a field access, may be used in place of `.foo`. The sorting order is the same as described in the `sort` function above. examples: - program: 'group_by(.foo)' input: '[{"foo":1, "bar":10}, {"foo":3, "bar":100}, {"foo":1, "bar":1}]' output: ['[[{"foo":1, "bar":10}, {"foo":1, "bar":1}], [{"foo":3, "bar":100}]]'] - title: "`min`, `max`, `min_by(path_exp)`, `max_by(path_exp)`" body: | Find the minimum or maximum element of the input array. The `min_by(path_exp)` and `max_by(path_exp)` functions allow you to specify a particular field or property to examine, e.g. `min_by(.foo)` finds the object with the smallest `foo` field. examples: - program: 'min' input: '[5,4,2,7]' output: ['2'] - program: 'max_by(.foo)' input: '[{"foo":1, "bar":14}, {"foo":2, "bar":3}]' output: ['{"foo":2, "bar":3}'] - title: "`unique`, `unique_by(path_exp)`" body: | The `unique` function takes as input an array and produces an array of the same elements, in sorted order, with duplicates removed. The `unique_by(path_exp)` function will keep only one element for each value obtained by applying the argument. Think of it as making an array by taking one element out of every group produced by `group`. examples: - program: 'unique' input: '[1,2,5,3,5,3,1,3]' output: ['[1,2,3,5]'] - program: 'unique_by(.foo)' input: '[{"foo": 1, "bar": 2}, {"foo": 1, "bar": 3}, {"foo": 4, "bar": 5}]' output: ['[{"foo": 1, "bar": 2}, {"foo": 4, "bar": 5}]'] - program: 'unique_by(length)' input: '["chunky", "bacon", "kitten", "cicada", "asparagus"]' output: ['["bacon", "chunky", "asparagus"]'] - title: "`reverse`" body: | This function reverses an array. examples: - program: 'reverse' input: '[1,2,3,4]' output: ['[4,3,2,1]'] - title: "`contains(element)`" body: | The filter `contains(b)` will produce true if b is completely contained within the input. A string B is contained in a string A if B is a substring of A. An array B is contained in an array A if all elements in B are contained in any element in A. An object B is contained in object A if all of the values in B are contained in the value in A with the same key. All other types are assumed to be contained in each other if they are equal. examples: - program: 'contains("bar")' input: '"foobar"' output: ['true'] - program: 'contains(["baz", "bar"])' input: '["foobar", "foobaz", "blarp"]' output: ['true'] - program: 'contains(["bazzzzz", "bar"])' input: '["foobar", "foobaz", "blarp"]' output: ['false'] - program: 'contains({foo: 12, bar: [{barp: 12}]})' input: '{"foo": 12, "bar":[1,2,{"barp":12, "blip":13}]}' output: ['true'] - program: 'contains({foo: 12, bar: [{barp: 15}]})' input: '{"foo": 12, "bar":[1,2,{"barp":12, "blip":13}]}' output: ['false'] - title: "`indices(s)`" body: | Outputs an array containing the indices in `.` where `s` occurs. The input may be an array, in which case if `s` is an array then the indices output will be those where all elements in `.` match those of `s`. examples: - program: 'indices(", ")' input: '"a,b, cd, efg, hijk"' output: ['[3,7,12]'] - program: 'indices(1)' input: '[0,1,2,1,3,1,4]' output: ['[1,3,5]'] - program: 'indices([1,2])' input: '[0,1,2,3,1,4,2,5,1,2,6,7]' output: ['[1,8]'] - title: "`index(s)`, `rindex(s)`" body: | Outputs the index of the first (`index`) or last (`rindex`) occurrence of `s` in the input. examples: - program: 'index(", ")' input: '"a,b, cd, efg, hijk"' output: ['3'] - program: 'index(1)' input: '[0,1,2,1,3,1,4]' output: ['1'] - program: 'index([1,2])' input: '[0,1,2,3,1,4,2,5,1,2,6,7]' output: ['1'] - program: 'rindex(", ")' input: '"a,b, cd, efg, hijk"' output: ['12'] - program: 'rindex(1)' input: '[0,1,2,1,3,1,4]' output: ['5'] - program: 'rindex([1,2])' input: '[0,1,2,3,1,4,2,5,1,2,6,7]' output: ['8'] - title: "`inside`" body: | The filter `inside(b)` will produce true if the input is completely contained within b. It is, essentially, an inversed version of `contains`. examples: - program: 'inside("foobar")' input: '"bar"' output: ['true'] - program: 'inside(["foobar", "foobaz", "blarp"])' input: '["baz", "bar"]' output: ['true'] - program: 'inside(["foobar", "foobaz", "blarp"])' input: '["bazzzzz", "bar"]' output: ['false'] - program: 'inside({"foo": 12, "bar":[1,2,{"barp":12, "blip":13}]})' input: '{"foo": 12, "bar": [{"barp": 12}]}' output: ['true'] - program: 'inside({"foo": 12, "bar":[1,2,{"barp":12, "blip":13}]})' input: '{"foo": 12, "bar": [{"barp": 15}]}' output: ['false'] - title: "`startswith(str)`" body: | Outputs `true` if . starts with the given string argument. examples: - program: '[.[]|startswith("foo")]' input: '["fo", "foo", "barfoo", "foobar", "barfoob"]' output: ['[false, true, false, true, false]'] - title: "`endswith(str)`" body: | Outputs `true` if . ends with the given string argument. examples: - program: '[.[]|endswith("foo")]' input: '["foobar", "barfoo"]' output: ['[false, true]'] - title: "`combinations`, `combinations(n)`" body: | Outputs all combinations of the elements of the arrays in the input array. If given an argument `n`, it outputs all combinations of `n` repetitions of the input array. examples: - program: 'combinations' input: '[[1,2], [3, 4]]' output: ['[1, 3]', '[1, 4]', '[2, 3]', '[2, 4]'] - program: 'combinations(2)' input: '[0, 1]' output: ['[0, 0]', '[0, 1]', '[1, 0]', '[1, 1]'] - title: "`ltrimstr(str)`" body: | Outputs its input with the given prefix string removed, if it starts with it. examples: - program: '[.[]|ltrimstr("foo")]' input: '["fo", "foo", "barfoo", "foobar", "afoo"]' output: ['["fo","","barfoo","bar","afoo"]'] - title: "`rtrimstr(str)`" body: | Outputs its input with the given suffix string removed, if it ends with it. examples: - program: '[.[]|rtrimstr("foo")]' input: '["fo", "foo", "barfoo", "foobar", "foob"]' output: ['["fo","","bar","foobar","foob"]'] - title: "`trimstr(str)`" body: | Outputs its input with the given string removed at both ends, if it starts or ends with it. examples: - program: '[.[]|trimstr("foo")]' input: '["fo", "foo", "barfoo", "foobarfoo", "foob"]' output: ['["fo","","bar","bar","b"]'] - title: "`trim`, `ltrim`, `rtrim`" body: | `trim` trims both leading and trailing whitespace. `ltrim` trims only leading (left side) whitespace. `rtrim` trims only trailing (right side) whitespace. Whitespace characters are the usual `" "`, `"\n"` `"\t"`, `"\r"` and also all characters in the Unicode character database with the whitespace property. Note that what considers whitespace might change in the future. examples: - program: 'trim, ltrim, rtrim' input: '" abc "' output: ['"abc"', '"abc "', '" abc"'] - title: "`explode`" body: | Converts an input string into an array of the string's codepoint numbers. examples: - program: 'explode' input: '"foobar"' output: ['[102,111,111,98,97,114]'] - title: "`implode`" body: | The inverse of explode. examples: - program: 'implode' input: '[65, 66, 67]' output: ['"ABC"'] - title: "`split(str)`" body: | Splits an input string on the separator argument. `split` can also split on regex matches when called with two arguments (see the regular expressions section below). examples: - program: 'split(", ")' input: '"a, b,c,d, e, "' output: ['["a","b,c,d","e",""]'] - title: "`join(str)`" body: | Joins the array of elements given as input, using the argument as separator. It is the inverse of `split`: that is, running `split("foo") | join("foo")` over any input string returns said input string. Numbers and booleans in the input are converted to strings. Null values are treated as empty strings. Arrays and objects in the input are not supported. examples: - program: 'join(", ")' input: '["a","b,c,d","e"]' output: ['"a, b,c,d, e"'] - program: 'join(" ")' input: '["a",1,2.3,true,null,false]' output: ['"a 1 2.3 true false"'] - title: "`ascii_downcase`, `ascii_upcase`" body: | Emit a copy of the input string with its alphabetic characters (a-z and A-Z) converted to the specified case. examples: - program: 'ascii_upcase' input: '"useful but not for é"' output: ['"USEFUL BUT NOT FOR é"'] - title: "`while(cond; update)`" body: | The `while(cond; update)` function allows you to repeatedly apply an update to `.` until `cond` is false. Note that `while(cond; update)` is internally defined as a recursive jq function. Recursive calls within `while` will not consume additional memory if `update` produces at most one output for each input. See advanced topics below. examples: - program: '[while(.<100; .*2)]' input: '1' output: ['[1,2,4,8,16,32,64]'] - title: "`repeat(exp)`" body: | The `repeat(exp)` function allows you to repeatedly apply expression `exp` to `.` until an error is raised. Note that `repeat(exp)` is internally defined as a recursive jq function. Recursive calls within `repeat` will not consume additional memory if `exp` produces at most one output for each input. See advanced topics below. examples: - program: '[repeat(.*2, error)?]' input: '1' output: ['[2]'] - title: "`until(cond; next)`" body: | The `until(cond; next)` function allows you to repeatedly apply the expression `next`, initially to `.` then to its own output, until `cond` is true. For example, this can be used to implement a factorial function (see below). Note that `until(cond; next)` is internally defined as a recursive jq function. Recursive calls within `until()` will not consume additional memory if `next` produces at most one output for each input. See advanced topics below. examples: - program: '[.,1]|until(.[0] < 1; [.[0] - 1, .[1] * .[0]])|.[1]' input: '4' output: ['24'] - title: "`recurse(f)`, `recurse`, `recurse(f; condition)`" body: | The `recurse(f)` function allows you to search through a recursive structure, and extract interesting data from all levels. Suppose your input represents a filesystem: {"name": "/", "children": [ {"name": "/bin", "children": [ {"name": "/bin/ls", "children": []}, {"name": "/bin/sh", "children": []}]}, {"name": "/home", "children": [ {"name": "/home/stephen", "children": [ {"name": "/home/stephen/jq", "children": []}]}]}]} Now suppose you want to extract all of the filenames present. You need to retrieve `.name`, `.children[].name`, `.children[].children[].name`, and so on. You can do this with: recurse(.children[]) | .name When called without an argument, `recurse` is equivalent to `recurse(.[]?)`. `recurse(f)` is identical to `recurse(f; true)` and can be used without concerns about recursion depth. `recurse(f; condition)` is a generator which begins by emitting . and then emits in turn .|f, .|f|f, .|f|f|f, ... so long as the computed value satisfies the condition. For example, to generate all the integers, at least in principle, one could write `recurse(.+1; true)`. The recursive calls in `recurse` will not consume additional memory whenever `f` produces at most a single output for each input. examples: - program: 'recurse(.foo[])' input: '{"foo":[{"foo": []}, {"foo":[{"foo":[]}]}]}' output: - '{"foo":[{"foo":[]},{"foo":[{"foo":[]}]}]}' - '{"foo":[]}' - '{"foo":[{"foo":[]}]}' - '{"foo":[]}' - program: 'recurse' input: '{"a":0,"b":[1]}' output: - '{"a":0,"b":[1]}' - '0' - '[1]' - '1' - program: 'recurse(. * .; . < 20)' input: '2' output: ['2', '4', '16'] - title: "`walk(f)`" body: | The `walk(f)` function applies f recursively to every component of the input entity. When an array is encountered, f is first applied to its elements and then to the array itself; when an object is encountered, f is first applied to all the values and then to the object. In practice, f will usually test the type of its input, as illustrated in the following examples. The first example highlights the usefulness of processing the elements of an array of arrays before processing the array itself. The second example shows how all the keys of all the objects within the input can be considered for alteration. examples: - program: 'walk(if type == "array" then sort else . end)' input: '[[4, 1, 7], [8, 5, 2], [3, 6, 9]]' output: - '[[1,4,7],[2,5,8],[3,6,9]]' - program: 'walk( if type == "object" then with_entries( .key |= sub( "^_+"; "") ) else . end )' input: '[ { "_a": { "__b": 2 } } ]' output: - '[{"a":{"b":2}}]' - title: "`have_literal_numbers`" body: | This builtin returns true if jq's build configuration includes support for preservation of input number literals. - title: "`have_decnum`" body: | This builtin returns true if jq was built with "decnum", which is the current literal number preserving numeric backend implementation for jq. - title: "`$JQ_BUILD_CONFIGURATION`" body: | This builtin binding shows the jq executable's build configuration. Its value has no particular format, but it can be expected to be at least the `./configure` command-line arguments, and may be enriched in the future to include the version strings for the build tooling used. Note that this can be overridden in the command-line with `--arg` and related options. - title: "`$ENV`, `env`" body: | `$ENV` is an object representing the environment variables as set when the jq program started. `env` outputs an object representing jq's current environment. At the moment there is no builtin for setting environment variables. examples: - program: '$ENV.PAGER' input: 'null' output: ['"less"'] - program: 'env.PAGER' input: 'null' output: ['"less"'] - title: "`transpose`" body: | Transpose a possibly jagged matrix (an array of arrays). Rows are padded with nulls so the result is always rectangular. examples: - program: 'transpose' input: '[[1], [2,3]]' output: ['[[1,2],[null,3]]'] - title: "`bsearch(x)`" body: | `bsearch(x)` conducts a binary search for x in the input array. If the input is sorted and contains x, then `bsearch(x)` will return its index in the array; otherwise, if the array is sorted, it will return (-1 - ix) where ix is an insertion point such that the array would still be sorted after the insertion of x at ix. If the array is not sorted, `bsearch(x)` will return an integer that is probably of no interest. examples: - program: 'bsearch(0)' input: '[0,1]' output: ['0'] - program: 'bsearch(0)' input: '[1,2,3]' output: ['-1'] - program: 'bsearch(4) as $ix | if $ix < 0 then .[-(1+$ix)] = 4 else . end' input: '[1,2,3]' output: ['[1,2,3,4]'] - title: "String interpolation: `\\(exp)`" body: | Inside a string, you can put an expression inside parens after a backslash. Whatever the expression returns will be interpolated into the string. examples: - program: '"The input was \(.), which is one less than \(.+1)"' input: '42' output: ['"The input was 42, which is one less than 43"'] - title: "Convert to/from JSON" body: | The `tojson` and `fromjson` builtins dump values as JSON texts or parse JSON texts into values, respectively. The `tojson` builtin differs from `tostring` in that `tostring` returns strings unmodified, while `tojson` encodes strings as JSON strings. examples: - program: '[.[]|tostring]' input: '[1, "foo", ["foo"]]' output: ['["1","foo","[\"foo\"]"]'] - program: '[.[]|tojson]' input: '[1, "foo", ["foo"]]' output: ['["1","\"foo\"","[\"foo\"]"]'] - program: '[.[]|tojson|fromjson]' input: '[1, "foo", ["foo"]]' output: ['[1,"foo",["foo"]]'] - title: "Format strings and escaping" body: | The `@foo` syntax is used to format and escape strings, which is useful for building URLs, documents in a language like HTML or XML, and so forth. `@foo` can be used as a filter on its own, the possible escapings are: * `@text`: Calls `tostring`, see that function for details. * `@json`: Serializes the input as JSON. * `@html`: Applies HTML/XML escaping, by mapping the characters `<>&'"` to their entity equivalents `<`, `>`, `&`, `'`, `"`. * `@uri`: Applies percent-encoding, by mapping all reserved URI characters to a `%XX` sequence. * `@urid`: The inverse of `@uri`, applies percent-decoding, by mapping all `%XX` sequences to their corresponding URI characters. * `@csv`: The input must be an array, and it is rendered as CSV with double quotes for strings, and quotes escaped by repetition. * `@tsv`: The input must be an array, and it is rendered as TSV (tab-separated values). Each input array will be printed as a single line. Fields are separated by a single tab (ascii `0x09`). Input characters line-feed (ascii `0x0a`), carriage-return (ascii `0x0d`), tab (ascii `0x09`) and backslash (ascii `0x5c`) will be output as escape sequences `\n`, `\r`, `\t`, `\\` respectively. * `@sh`: The input is escaped suitable for use in a command-line for a POSIX shell. If the input is an array, the output will be a series of space-separated strings. * `@base64`: The input is converted to base64 as specified by RFC 4648. * `@base64d`: The inverse of `@base64`, input is decoded as specified by RFC 4648. Note\: If the decoded string is not UTF-8, the results are undefined. This syntax can be combined with string interpolation in a useful way. You can follow a `@foo` token with a string literal. The contents of the string literal will *not* be escaped. However, all interpolations made inside that string literal will be escaped. For instance, @uri "https://www.google.com/search?q=\(.search)" will produce the following output for the input `{"search":"what is jq?"}`: "https://www.google.com/search?q=what%20is%20jq%3F" Note that the slashes, question mark, etc. in the URL are not escaped, as they were part of the string literal. examples: - program: '@html' input: '"This works if x < y"' output: ['"This works if x < y"'] - program: '@sh "echo \(.)"' input: "\"O'Hara's Ale\"" output: ["\"echo 'O'\\\\''Hara'\\\\''s Ale'\""] - program: '@base64' input: '"This is a message"' output: ['"VGhpcyBpcyBhIG1lc3NhZ2U="'] - program: '@base64d' input: '"VGhpcyBpcyBhIG1lc3NhZ2U="' output: ['"This is a message"'] - title: "Dates" body: | jq provides some basic date handling functionality, with some high-level and low-level builtins. In all cases these builtins deal exclusively with time in UTC. The `fromdateiso8601` builtin parses datetimes in the ISO 8601 format to a number of seconds since the Unix epoch (1970-01-01T00:00:00Z). The `todateiso8601` builtin does the inverse. The `fromdate` builtin parses datetime strings. Currently `fromdate` only supports ISO 8601 datetime strings, but in the future it will attempt to parse datetime strings in more formats. The `todate` builtin is an alias for `todateiso8601`. The `now` builtin outputs the current time, in seconds since the Unix epoch. Low-level jq interfaces to the C-library time functions are also provided: `strptime`, `strftime`, `strflocaltime`, `mktime`, `gmtime`, and `localtime`. Refer to your host operating system's documentation for the format strings used by `strptime` and `strftime`. Note: these are not necessarily stable interfaces in jq, particularly as to their localization functionality. The `gmtime` builtin consumes a number of seconds since the Unix epoch and outputs a "broken down time" representation of Greenwich Mean Time as an array of numbers representing (in this order): the year, the month (zero-based), the day of the month (one-based), the hour of the day, the minute of the hour, the second of the minute, the day of the week, and the day of the year -- all one-based unless otherwise stated. The day of the week number may be wrong on some systems for dates before March 1st 1900, or after December 31 2099. The `localtime` builtin works like the `gmtime` builtin, but using the local timezone setting. The `mktime` builtin consumes "broken down time" representations of time output by `gmtime` and `strptime`. The `strptime(fmt)` builtin parses input strings matching the `fmt` argument. The output is in the "broken down time" representation consumed by `mktime` and output by `gmtime`. The `strftime(fmt)` builtin formats a time (GMT) with the given format. The `strflocaltime` does the same, but using the local timezone setting. The format strings for `strptime` and `strftime` are described in typical C library documentation. The format string for ISO 8601 datetime is `"%Y-%m-%dT%H:%M:%SZ"`. jq may not support some or all of this date functionality on some systems. In particular, the `%u` and `%j` specifiers for `strptime(fmt)` are not supported on macOS. examples: - program: 'fromdate' input: '"2015-03-05T23:51:47Z"' output: ['1425599507'] - program: 'strptime("%Y-%m-%dT%H:%M:%SZ")' input: '"2015-03-05T23:51:47Z"' output: ['[2015,2,5,23,51,47,4,63]'] - program: 'strptime("%Y-%m-%dT%H:%M:%SZ")|mktime' input: '"2015-03-05T23:51:47Z"' output: ['1425599507'] - title: "SQL-Style Operators" body: | jq provides a few SQL-style operators. * `INDEX(stream; index_expression)`: This builtin produces an object whose keys are computed by the given index expression applied to each value from the given stream. * `JOIN($idx; stream; idx_expr; join_expr)`: This builtin joins the values from the given stream to the given index. The index's keys are computed by applying the given index expression to each value from the given stream. An array of the value in the stream and the corresponding value from the index is fed to the given join expression to produce each result. * `JOIN($idx; stream; idx_expr)`: Same as `JOIN($idx; stream; idx_expr; .)`. * `JOIN($idx; idx_expr)`: This builtin joins the input `.` to the given index, applying the given index expression to `.` to compute the index key. The join operation is as described above. * `IN(s)`: This builtin outputs `true` if `.` appears in the given stream, otherwise it outputs `false`. * `IN(source; s)`: This builtin outputs `true` if any value in the source stream appears in the second stream, otherwise it outputs `false`. - title: "`builtins`" body: | Returns a list of all builtin functions in the format `name/arity`. Since functions with the same name but different arities are considered separate functions, `all/0`, `all/1`, and `all/2` would all be present in the list. - title: Conditionals and Comparisons entries: - title: "`==`, `!=`" body: | The expression 'a == b' will produce 'true' if the results of evaluating a and b are equal (that is, if they represent equivalent JSON values) and 'false' otherwise. In particular, strings are never considered equal to numbers. In checking for the equality of JSON objects, the ordering of keys is irrelevant. If you're coming from JavaScript, please note that jq's `==` is like JavaScript's `===`, the "strict equality" operator. != is "not equal", and 'a != b' returns the opposite value of 'a == b' examples: - program: '. == false' input: 'null' output: ['false'] - program: '. == {"b": {"d": (4 + 1e-20), "c": 3}, "a":1}' input: '{"a":1, "b": {"c": 3, "d": 4}}' output: ['true'] - program: '.[] == 1' input: '[1, 1.0, "1", "banana"]' output: ['true', 'true', 'false', 'false'] - title: if-then-else-end body: | `if A then B else C end` will act the same as `B` if `A` produces a value other than false or null, but act the same as `C` otherwise. `if A then B end` is the same as `if A then B else . end`. That is, the `else` branch is optional, and if absent is the same as `.`. This also applies to `elif` with absent ending `else` branch. Checking for false or null is a simpler notion of "truthiness" than is found in JavaScript or Python, but it means that you'll sometimes have to be more explicit about the condition you want. You can't test whether, e.g. a string is empty using `if .name then A else B end`; you'll need something like `if .name == "" then A else B end` instead. If the condition `A` produces multiple results, then `B` is evaluated once for each result that is not false or null, and `C` is evaluated once for each false or null. More cases can be added to an if using `elif A then B` syntax. examples: - program: |- if . == 0 then "zero" elif . == 1 then "one" else "many" end input: '2' output: ['"many"'] - title: "`>`, `>=`, `<=`, `<`" body: | The comparison operators `>`, `>=`, `<=`, `<` return whether their left argument is greater than, greater than or equal to, less than or equal to or less than their right argument (respectively). The ordering is the same as that described for `sort`, above. examples: - program: '. < 5' input: '2' output: ['true'] - title: "`and`, `or`, `not`" body: | jq supports the normal Boolean operators `and`, `or`, `not`. They have the same standard of truth as if expressions - `false` and `null` are considered "false values", and anything else is a "true value". If an operand of one of these operators produces multiple results, the operator itself will produce a result for each input. `not` is in fact a builtin function rather than an operator, so it is called as a filter to which things can be piped rather than with special syntax, as in `.foo and .bar | not`. These three only produce the values `true` and `false`, and so are only useful for genuine Boolean operations, rather than the common Perl/Python/Ruby idiom of "value_that_may_be_null or default". If you want to use this form of "or", picking between two values rather than evaluating a condition, see the `//` operator below. examples: - program: '42 and "a string"' input: 'null' output: ['true'] - program: '(true, false) or false' input: 'null' output: ['true', 'false'] - program: '(true, true) and (true, false)' input: 'null' output: ['true', 'false', 'true', 'false'] - program: '[true, false | not]' input: 'null' output: ['[false, true]'] - title: "Alternative operator: `//`" body: | The `//` operator produces all the values of its left-hand side that are neither `false` nor `null`. If the left-hand side produces no values other than `false` or `null`, then `//` produces all the values of its right-hand side. A filter of the form `a // b` produces all the results of `a` that are not `false` or `null`. If `a` produces no results, or no results other than `false` or `null`, then `a // b` produces the results of `b`. This is useful for providing defaults: `.foo // 1` will evaluate to `1` if there's no `.foo` element in the input. It's similar to how `or` is sometimes used in Python (jq's `or` operator is reserved for strictly Boolean operations). Note: `some_generator // defaults_here` is not the same as `some_generator | . // defaults_here`. The latter will produce default values for all non-`false`, non-`null` values of the left-hand side, while the former will not. Precedence rules can make this confusing. For example, in `false, 1 // 2` the left-hand side of `//` is `1`, not `false, 1` -- `false, 1 // 2` parses the same way as `false, (1 // 2)`. In `(false, null, 1) | . // 42` the left-hand side of `//` is `.`, which always produces just one value, while in `(false, null, 1) // 42` the left-hand side is a generator of three values, and since it produces a value other `false` and `null`, the default `42` is not produced. examples: - program: 'empty // 42' input: 'null' output: ['42'] - program: '.foo // 42' input: '{"foo": 19}' output: ['19'] - program: '.foo // 42' input: '{}' output: ['42'] - program: '(false, null, 1) // 42' input: 'null' output: ['1'] - program: '(false, null, 1) | . // 42' input: 'null' output: ['42', '42', '1'] - title: try-catch body: | Errors can be caught by using `try EXP catch EXP`. The first expression is executed, and if it fails then the second is executed with the error message. The output of the handler, if any, is output as if it had been the output of the expression to try. The `try EXP` form uses `empty` as the exception handler. examples: - program: 'try .a catch ". is not an object"' input: 'true' output: ['". is not an object"'] - program: '[.[]|try .a]' input: '[{}, true, {"a":1}]' output: ['[null, 1]'] - program: 'try error("some exception") catch .' input: 'true' output: ['"some exception"'] - title: Breaking out of control structures body: | A convenient use of try/catch is to break out of control structures like `reduce`, `foreach`, `while`, and so on. For example: # Repeat an expression until it raises "break" as an # error, then stop repeating without re-raising the error. # But if the error caught is not "break" then re-raise it. try repeat(exp) catch if .=="break" then empty else error jq has a syntax for named lexical labels to "break" or "go (back) to": label $out | ... break $out ... The `break $label_name` expression will cause the program to act as though the nearest (to the left) `label $label_name` produced `empty`. The relationship between the `break` and corresponding `label` is lexical: the label has to be "visible" from the break. To break out of a `reduce`, for example: label $out | reduce .[] as $item (null; if .==false then break $out else ... end) The following jq program produces a syntax error: break $out because no label `$out` is visible. - title: "Error Suppression / Optional Operator: `?`" body: | The `?` operator, used as `EXP?`, is shorthand for `try EXP`. examples: - program: '[.[] | .a?]' input: '[{}, true, {"a":1}]' output: ['[null, 1]'] - program: '[.[] | tonumber?]' input: '["1", "invalid", "3", 4]' output: ['[1, 3, 4]'] - title: Regular expressions body: | jq uses the [Oniguruma regular expression library](https://github.com/kkos/oniguruma/blob/master/doc/RE), as do PHP, TextMate, Sublime Text, etc, so the description here will focus on jq specifics. Oniguruma supports several flavors of regular expression, so it is important to know that jq uses the ["Perl NG" (Perl with named groups)](https://github.com/kkos/oniguruma/blob/master/doc/SYNTAX.md) flavor. The jq regex filters are defined so that they can be used using one of these patterns: STRING | FILTER(REGEX) STRING | FILTER(REGEX; FLAGS) STRING | FILTER([REGEX]) STRING | FILTER([REGEX, FLAGS]) where: * STRING, REGEX, and FLAGS are jq strings and subject to jq string interpolation; * REGEX, after string interpolation, should be a valid regular expression; * FILTER is one of `test`, `match`, or `capture`, as described below. Since REGEX must evaluate to a JSON string, some characters that are needed to form a regular expression must be escaped. For example, the regular expression `\s` signifying a whitespace character would be written as `"\\s"`. FLAGS is a string consisting of one of more of the supported flags: * `g` - Global search (find all matches, not just the first) * `i` - Case insensitive search * `m` - Multi line mode (`.` will match newlines) * `n` - Ignore empty matches * `p` - Both s and m modes are enabled * `s` - Single line mode (`^` -> `\A`, `$` -> `\Z`) * `l` - Find longest possible matches * `x` - Extended regex format (ignore whitespace and comments) To match a whitespace with the `x` flag, use `\s`, e.g. jq -n '"a b" | test("a\\sb"; "x")' Note that certain flags may also be specified within REGEX, e.g. jq -n '("test", "TEst", "teST", "TEST") | test("(?i)te(?-i)st")' evaluates to: `true`, `true`, `false`, `false`. entries: - title: "`test(val)`, `test(regex; flags)`" body: | Like `match`, but does not return match objects, only `true` or `false` for whether or not the regex matches the input. examples: - program: 'test("foo")' input: '"foo"' output: ['true'] - program: '.[] | test("a b c # spaces are ignored"; "ix")' input: '["xabcd", "ABC"]' output: ['true', 'true'] - title: "`match(val)`, `match(regex; flags)`" body: | **match** outputs an object for each match it finds. Matches have the following fields: * `offset` - offset in UTF-8 codepoints from the beginning of the input * `length` - length in UTF-8 codepoints of the match * `string` - the string that it matched * `captures` - an array of objects representing capturing groups. Capturing group objects have the following fields: * `offset` - offset in UTF-8 codepoints from the beginning of the input * `length` - length in UTF-8 codepoints of this capturing group * `string` - the string that was captured * `name` - the name of the capturing group (or `null` if it was unnamed) Capturing groups that did not match anything return an offset of -1 examples: - program: 'match("(abc)+"; "g")' input: '"abc abc"' output: - '{"offset": 0, "length": 3, "string": "abc", "captures": [{"offset": 0, "length": 3, "string": "abc", "name": null}]}' - '{"offset": 4, "length": 3, "string": "abc", "captures": [{"offset": 4, "length": 3, "string": "abc", "name": null}]}' - program: 'match("foo")' input: '"foo bar foo"' output: ['{"offset": 0, "length": 3, "string": "foo", "captures": []}'] - program: 'match(["foo", "ig"])' input: '"foo bar FOO"' output: - '{"offset": 0, "length": 3, "string": "foo", "captures": []}' - '{"offset": 8, "length": 3, "string": "FOO", "captures": []}' - program: 'match("foo (?bar)? foo"; "ig")' input: '"foo bar foo foo foo"' output: - '{"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"}]}' - program: '[ match("."; "g")] | length' input: '"abc"' output: ['3'] - title: "`capture(val)`, `capture(regex; flags)`" body: | Collects the named captures in a JSON object, with the name of each capture as the key, and the matched string as the corresponding value. examples: - program: 'capture("(?[a-z]+)-(?[0-9]+)")' input: '"xyzzy-14"' output: ['{ "a": "xyzzy", "n": "14" }'] - title: "`scan(regex)`, `scan(regex; flags)`" body: | Emit a stream of the non-overlapping substrings of the input that match the regex in accordance with the flags, if any have been specified. If there is no match, the stream is empty. To capture all the matches for each input string, use the idiom `[ expr ]`, e.g. `[ scan(regex) ]`. If the regex contains capturing groups, the filter emits a stream of arrays, each of which contains the captured strings. examples: - program: 'scan("c")' input: '"abcdefabc"' output: ['"c"', '"c"'] - program: 'scan("(a+)(b+)")' input: '"abaabbaaabbb"' output: ['["a","b"]', '["aa","bb"]', '["aaa","bbb"]'] - title: "`split(regex; flags)`" body: | Splits an input string on each regex match. For backwards compatibility, when called with a single argument, `split` splits on a string, not a regex. examples: - program: 'split(", *"; null)' input: '"ab,cd, ef"' output: ['["ab","cd","ef"]'] - title: "`splits(regex)`, `splits(regex; flags)`" body: | These provide the same results as their `split` counterparts, but as a stream instead of an array. examples: - program: 'splits(", *")' input: '"ab,cd, ef, gh"' output: ['"ab"','"cd"','"ef"','"gh"'] - program: 'splits(",? *"; "n")' input: '"ab,cd ef, gh"' output: ['"ab"','"cd"','"ef"','"gh"'] - title: "`sub(regex; tostring)`, `sub(regex; tostring; flags)`" body: | Emit the string obtained by replacing the first match of regex in the input string with `tostring`, after interpolation. `tostring` should be a jq string or a stream of such strings, each of which may contain references to named captures. The named captures are, in effect, presented as a JSON object (as constructed by `capture`) to `tostring`, so a reference to a captured variable named "x" would take the form: `"\(.x)"`. examples: - program: 'sub("[^a-z]*(?[a-z]+)"; "Z\(.x)"; "g")' input: '"123abc456def"' output: ['"ZabcZdef"'] - program: '[sub("(?.)"; "\(.a|ascii_upcase)", "\(.a|ascii_downcase)")]' input: '"aB"' output: ['["AB","aB"]'] - title: "`gsub(regex; tostring)`, `gsub(regex; tostring; flags)`" body: | `gsub` is like `sub` but all the non-overlapping occurrences of the regex are replaced by `tostring`, after interpolation. If the second argument is a stream of jq strings, then `gsub` will produce a corresponding stream of JSON strings. examples: - program: 'gsub("(?.)[^a]*"; "+\(.x)-")' input: '"Abcabc"' output: ['"+A-+a-"'] - program: '[gsub("p"; "a", "b")]' input: '"p"' output: ['["a","b"]'] - title: Advanced features body: | Variables are an absolute necessity in most programming languages, but they're relegated to an "advanced feature" in jq. In most languages, variables are the only means of passing around data. If you calculate a value, and you want to use it more than once, you'll need to store it in a variable. To pass a value to another part of the program, you'll need that part of the program to define a variable (as a function parameter, object member, or whatever) in which to place the data. It is also possible to define functions in jq, although this is is a feature whose biggest use is defining jq's standard library (many jq functions such as `map` and `select` are in fact written in jq). jq has reduction operators, which are very powerful but a bit tricky. Again, these are mostly used internally, to define some useful bits of jq's standard library. It may not be obvious at first, but jq is all about generators (yes, as often found in other languages). Some utilities are provided to help deal with generators. Some minimal I/O support (besides reading JSON from standard input, and writing JSON to standard output) is available. Finally, there is a module/library system. entries: - title: "Variable / Symbolic Binding Operator: `... as $identifier | ...`" body: | In jq, all filters have an input and an output, so manual plumbing is not necessary to pass a value from one part of a program to the next. Many expressions, for instance `a + b`, pass their input to two distinct subexpressions (here `a` and `b` are both passed the same input), so variables aren't usually necessary in order to use a value twice. For instance, calculating the average value of an array of numbers requires a few variables in most languages - at least one to hold the array, perhaps one for each element or for a loop counter. In jq, it's simply `add / length` - the `add` expression is given the array and produces its sum, and the `length` expression is given the array and produces its length. So, there's generally a cleaner way to solve most problems in jq than defining variables. Still, sometimes they do make things easier, so jq lets you define variables using `expression as $variable`. All variable names start with `$`. Here's a slightly uglier version of the array-averaging example: length as $array_length | add / $array_length We'll need a more complicated problem to find a situation where using variables actually makes our lives easier. Suppose we have an array of blog posts, with "author" and "title" fields, and another object which is used to map author usernames to real names. Our input looks like: {"posts": [{"title": "First post", "author": "anon"}, {"title": "A well-written article", "author": "person1"}], "realnames": {"anon": "Anonymous Coward", "person1": "Person McPherson"}} We want to produce the posts with the author field containing a real name, as in: {"title": "First post", "author": "Anonymous Coward"} {"title": "A well-written article", "author": "Person McPherson"} We use a variable, `$names`, to store the realnames object, so that we can refer to it later when looking up author usernames: .realnames as $names | .posts[] | {title, author: $names[.author]} The expression `exp as $x | ...` means: for each value of expression `exp`, run the rest of the pipeline with the entire original input, and with `$x` set to that value. Thus `as` functions as something of a foreach loop. Just as `{foo}` is a handy way of writing `{foo: .foo}`, so `{$foo}` is a handy way of writing `{foo: $foo}`. Multiple variables may be declared using a single `as` expression by providing a pattern that matches the structure of the input (this is known as "destructuring"): . as {realnames: $names, posts: [$first, $second]} | ... The variable declarations in array patterns (e.g., `. as [$first, $second]`) bind to the elements of the array in from the element at index zero on up, in order. When there is no value at the index for an array pattern element, `null` is bound to that variable. Variables are scoped over the rest of the expression that defines them, so .realnames as $names | (.posts[] | {title, author: $names[.author]}) will work, but (.realnames as $names | .posts[]) | {title, author: $names[.author]} won't. For programming language theorists, it's more accurate to say that jq variables are lexically-scoped bindings. In particular there's no way to change the value of a binding; one can only setup a new binding with the same name, but which will not be visible where the old one was. examples: - program: '.bar as $x | .foo | . + $x' input: '{"foo":10, "bar":200}' output: ['210'] - program: '. as $i|[(.*2|. as $i| $i), $i]' input: '5' output: ['[10,5]'] - program: '. as [$a, $b, {c: $c}] | $a + $b + $c' input: '[2, 3, {"c": 4, "d": 5}]' output: ['9'] - program: '.[] as [$a, $b] | {a: $a, b: $b}' input: '[[0], [0, 1], [2, 1, 0]]' output: ['{"a":0,"b":null}', '{"a":0,"b":1}', '{"a":2,"b":1}'] - title: 'Destructuring Alternative Operator: `?//`' body: | The destructuring alternative operator provides a concise mechanism for destructuring an input that can take one of several forms. Suppose we have an API that returns a list of resources and events associated with them, and we want to get the user_id and timestamp of the first event for each resource. The API (having been clumsily converted from XML) will only wrap the events in an array if the resource has multiple events: {"resources": [{"id": 1, "kind": "widget", "events": {"action": "create", "user_id": 1, "ts": 13}}, {"id": 2, "kind": "widget", "events": [{"action": "create", "user_id": 1, "ts": 14}, {"action": "destroy", "user_id": 1, "ts": 15}]}]} We can use the destructuring alternative operator to handle this structural change simply: .resources[] as {$id, $kind, events: {$user_id, $ts}} ?// {$id, $kind, events: [{$user_id, $ts}]} | {$user_id, $kind, $id, $ts} Or, if we aren't sure if the input is an array of values or an object: .[] as [$id, $kind, $user_id, $ts] ?// {$id, $kind, $user_id, $ts} | ... Each alternative need not define all of the same variables, but all named variables will be available to the subsequent expression. Variables not matched in the alternative that succeeded will be `null`: .resources[] as {$id, $kind, events: {$user_id, $ts}} ?// {$id, $kind, events: [{$first_user_id, $first_ts}]} | {$user_id, $first_user_id, $kind, $id, $ts, $first_ts} Additionally, if the subsequent expression returns an error, the alternative operator will attempt to try the next binding. Errors that occur during the final alternative are passed through. [[3]] | .[] as [$a] ?// [$b] | if $a != null then error("err: \($a)") else {$a,$b} end examples: - program: '.[] as {$a, $b, c: {$d, $e}} ?// {$a, $b, c: [{$d, $e}]} | {$a, $b, $d, $e}' input: '[{"a": 1, "b": 2, "c": {"d": 3, "e": 4}}, {"a": 1, "b": 2, "c": [{"d": 3, "e": 4}]}]' output: ['{"a":1,"b":2,"d":3,"e":4}', '{"a":1,"b":2,"d":3,"e":4}'] - program: '.[] as {$a, $b, c: {$d}} ?// {$a, $b, c: [{$e}]} | {$a, $b, $d, $e}' input: '[{"a": 1, "b": 2, "c": {"d": 3, "e": 4}}, {"a": 1, "b": 2, "c": [{"d": 3, "e": 4}]}]' output: ['{"a":1,"b":2,"d":3,"e":null}', '{"a":1,"b":2,"d":null,"e":4}'] - program: '.[] as [$a] ?// [$b] | if $a != null then error("err: \($a)") else {$a,$b} end' input: '[[3]]' output: ['{"a":null,"b":3}'] - title: 'Defining Functions' body: | You can give a filter a name using "def" syntax: def increment: . + 1; From then on, `increment` is usable as a filter just like a builtin function (in fact, this is how many of the builtins are defined). A function may take arguments: def map(f): [.[] | f]; Arguments are passed as _filters_ (functions with no arguments), _not_ as values. The same argument may be referenced multiple times with different inputs (here `f` is run for each element of the input array). Arguments to a function work more like callbacks than like value arguments. This is important to understand. Consider: def foo(f): f|f; 5|foo(.*2) The result will be 20 because `f` is `.*2`, and during the first invocation of `f` `.` will be 5, and the second time it will be 10 (5 * 2), so the result will be 20. Function arguments are filters, and filters expect an input when invoked. If you want the value-argument behaviour for defining simple functions, you can just use a variable: def addvalue(f): f as $f | map(. + $f); Or use the short-hand: def addvalue($f): ...; With either definition, `addvalue(.foo)` will add the current input's `.foo` field to each element of the array. Do note that calling `addvalue(.[])` will cause the `map(. + $f)` part to be evaluated once per value in the value of `.` at the call site. Multiple definitions using the same function name are allowed. Each re-definition replaces the previous one for the same number of function arguments, but only for references from functions (or main program) subsequent to the re-definition. See also the section below on scoping. examples: - program: 'def addvalue(f): . + [f]; map(addvalue(.[0]))' input: '[[1,2],[10,20]]' output: ['[[1,2,1], [10,20,10]]'] - program: 'def addvalue(f): f as $x | map(. + $x); addvalue(.[0])' input: '[[1,2],[10,20]]' output: ['[[1,2,1,2], [10,20,1,2]]'] - title: 'Scoping' body: | There are two types of symbols in jq: value bindings (a.k.a., "variables"), and functions. Both are scoped lexically, with expressions being able to refer only to symbols that have been defined "to the left" of them. The only exception to this rule is that functions can refer to themselves so as to be able to create recursive functions. For example, in the following expression there is a binding which is visible "to the right" of it, `... | .*3 as $times_three | [. + $times_three] | ...`, but not "to the left". Consider this expression now, `... | (.*3 as $times_three | [. + $times_three]) | ...`: here the binding `$times_three` is _not_ visible past the closing parenthesis. - title: "`isempty(exp)`" body: | Returns true if `exp` produces no outputs, false otherwise. examples: - program: 'isempty(empty)' input: 'null' output: ['true'] - program: 'isempty(.[])' input: '[]' output: ['true'] - program: 'isempty(.[])' input: '[1,2,3]' output: ['false'] - title: "`limit(n; expr)`" body: | The `limit` function extracts up to `n` outputs from `expr`. examples: - program: '[limit(3; .[])]' input: '[0,1,2,3,4,5,6,7,8,9]' output: ['[0,1,2]'] - title: "`skip(n; expr)`" body: | The `skip` function skips the first `n` outputs from `expr`. examples: - program: '[skip(3; .[])]' input: '[0,1,2,3,4,5,6,7,8,9]' output: ['[3,4,5,6,7,8,9]'] - title: "`first(expr)`, `last(expr)`, `nth(n; expr)`" body: | The `first(expr)` and `last(expr)` functions extract the first and last values from `expr`, respectively. The `nth(n; expr)` function extracts the nth value output by `expr`. Note that `nth(n; expr)` doesn't support negative values of `n`. examples: - program: '[first(range(.)), last(range(.)), nth(5; range(.))]' input: '10' output: ['[0,9,5]'] - program: '[first(empty), last(empty), nth(5; empty)]' input: 'null' output: ['[]'] - title: "`first`, `last`, `nth(n)`" body: | The `first` and `last` functions extract the first and last values from any array at `.`. The `nth(n)` function extracts the nth value of any array at `.`. examples: - program: '[range(.)]|[first, last, nth(5)]' input: '10' output: ['[0,9,5]'] - title: "`reduce`" body: | The `reduce` syntax allows you to combine all of the results of an expression by accumulating them into a single answer. The form is `reduce EXP as $var (INIT; UPDATE)`. As an example, we'll pass `[1,2,3]` to this expression: reduce .[] as $item (0; . + $item) For each result that `.[]` produces, `. + $item` is run to accumulate a running total, starting from 0 as the input value. In this example, `.[]` produces the results `1`, `2`, and `3`, so the effect is similar to running something like this: 0 | 1 as $item | . + $item | 2 as $item | . + $item | 3 as $item | . + $item examples: - program: 'reduce .[] as $item (0; . + $item)' input: '[1,2,3,4,5]' output: ['15'] - program: 'reduce .[] as [$i,$j] (0; . + $i * $j)' input: '[[1,2],[3,4],[5,6]]' output: ['44'] - program: 'reduce .[] as {$x,$y} (null; .x += $x | .y += [$y])' input: '[{"x":"a","y":1},{"x":"b","y":2},{"x":"c","y":3}]' output: ['{"x":"abc","y":[1,2,3]}'] - title: "`foreach`" body: | The `foreach` syntax is similar to `reduce`, but intended to allow the construction of `limit` and reducers that produce intermediate results. The form is `foreach EXP as $var (INIT; UPDATE; EXTRACT)`. As an example, we'll pass `[1,2,3]` to this expression: foreach .[] as $item (0; . + $item; [$item, . * 2]) Like the `reduce` syntax, `. + $item` is run for each result that `.[]` produces, but `[$item, . * 2]` is run for each intermediate values. In this example, since the intermediate values are `1`, `3`, and `6`, the `foreach` expression produces `[1,2]`, `[2,6]`, and `[3,12]`. So the effect is similar to running something like this: 0 | 1 as $item | . + $item | [$item, . * 2], 2 as $item | . + $item | [$item, . * 2], 3 as $item | . + $item | [$item, . * 2] When `EXTRACT` is omitted, the identity filter is used. That is, it outputs the intermediate values as they are. examples: - program: 'foreach .[] as $item (0; . + $item)' input: '[1,2,3,4,5]' output: ['1','3','6','10','15'] - program: 'foreach .[] as $item (0; . + $item; [$item, . * 2])' input: '[1,2,3,4,5]' output: ['[1,2]','[2,6]','[3,12]','[4,20]','[5,30]'] - program: 'foreach .[] as $item (0; . + 1; {index: ., $item})' input: '["foo", "bar", "baz"]' output: - '{"index":1,"item":"foo"}' - '{"index":2,"item":"bar"}' - '{"index":3,"item":"baz"}' - title: Recursion body: | As described above, `recurse` uses recursion, and any jq function can be recursive. The `while` builtin is also implemented in terms of recursion. Tail calls are optimized whenever the expression to the left of the recursive call outputs its last value. In practice this means that the expression to the left of the recursive call should not produce more than one output for each input. For example: def recurse(f): def r: ., (f | select(. != null) | r); r; def while(cond; update): def _while: if cond then ., (update | _while) else empty end; _while; def repeat(exp): def _repeat: exp, _repeat; _repeat; - title: Generators and iterators body: | Some jq operators and functions are actually generators in that they can produce zero, one, or more values for each input, just as one might expect in other programming languages that have generators. For example, `.[]` generates all the values in its input (which must be an array or an object), `range(0; 10)` generates the integers between 0 and 10, and so on. Even the comma operator is a generator, generating first the values generated by the expression to the left of the comma, then the values generated by the expression on the right of the comma. The `empty` builtin is the generator that produces zero outputs. The `empty` builtin backtracks to the preceding generator expression. All jq functions can be generators just by using builtin generators. It is also possible to construct new generators using only recursion and the comma operator. If recursive calls are "in tail position" then the generator will be efficient. In the example below the recursive call by `_range` to itself is in tail position. The example shows off three advanced topics: tail recursion, generator construction, and sub-functions. examples: - program: 'def range(init; upto; by): def _range: if (by > 0 and . < upto) or (by < 0 and . > upto) then ., ((.+by)|_range) else empty end; if init == upto then empty elif by == 0 then init else init|_range end; range(0; 10; 3)' input: 'null' output: ['0', '3', '6', '9'] - program: 'def while(cond; update): def _while: if cond then ., (update | _while) else empty end; _while; [while(.<100; .*2)]' input: '1' output: ['[1,2,4,8,16,32,64]'] - title: 'Math' body: | jq currently only has IEEE754 double-precision (64-bit) floating point number support. Besides simple arithmetic operators such as `+`, jq also has most standard math functions from the C math library. C math functions that take a single input argument (e.g., `sin()`) are available as zero-argument jq functions. C math functions that take two input arguments (e.g., `pow()`) are available as two-argument jq functions that ignore `.`. C math functions that take three input arguments are available as three-argument jq functions that ignore `.`. Availability of standard math functions depends on the availability of the corresponding math functions in your operating system and C math library. Unavailable math functions will be defined but will raise an error. One-input C math functions: `acos` `acosh` `asin` `asinh` `atan` `atanh` `cbrt` `ceil` `cos` `cosh` `erf` `erfc` `exp` `exp10` `exp2` `expm1` `fabs` `floor` `gamma` `j0` `j1` `lgamma` `log` `log10` `log1p` `log2` `logb` `nearbyint` `rint` `round` `significand` `sin` `sinh` `sqrt` `tan` `tanh` `tgamma` `trunc` `y0` `y1`. Two-input C math functions: `atan2` `copysign` `drem` `fdim` `fmax` `fmin` `fmod` `frexp` `hypot` `jn` `ldexp` `modf` `nextafter` `nexttoward` `pow` `remainder` `scalb` `scalbln` `yn`. Three-input C math functions: `fma`. See your system's manual for more information on each of these. - title: 'I/O' body: | At this time jq has minimal support for I/O, mostly in the form of control over when inputs are read. Two builtins functions are provided for this, `input` and `inputs`, that read from the same sources (e.g., `stdin`, files named on the command-line) as jq itself. These two builtins, and jq's own reading actions, can be interleaved with each other. They are commonly used in combination with the null input option `-n` to prevent one input from being read implicitly. Two builtins provide minimal output capabilities, `debug`, and `stderr`. (Recall that a jq program's output values are always output as JSON texts on `stdout`.) The `debug` builtin can have application-specific behavior, such as for executables that use the libjq C API but aren't the jq executable itself. The `stderr` builtin outputs its input in raw mode to stderr with no additional decoration, not even a newline. Most jq builtins are referentially transparent, and yield constant and repeatable value streams when applied to constant inputs. This is not true of I/O builtins. entries: - title: "`input`" body: | Outputs one new input. Note that when using `input` it is generally necessary to invoke jq with the `-n` command-line option, otherwise the first entity will be lost. echo 1 2 3 4 | jq '[., input]' # [1,2] [3,4] - title: "`inputs`" body: | Outputs all remaining inputs, one by one. This is primarily useful for reductions over a program's inputs. Note that when using `inputs` it is generally necessary to invoke jq with the `-n` command-line option, otherwise the first entity will be lost. echo 1 2 3 | jq -n 'reduce inputs as $i (0; . + $i)' # 6 - title: "`debug`, `debug(msgs)`" body: | These two filters are like `.` but have as a side-effect the production of one or more messages on stderr. The message produced by the `debug` filter has the form ["DEBUG:",] where `` is a compact rendition of the input value. This format may change in the future. The `debug(msgs)` filter is defined as `(msgs | debug | empty), .` thus allowing great flexibility in the content of the message, while also allowing multi-line debugging statements to be created. For example, the expression: 1 as $x | 2 | debug("Entering function foo with $x == \($x)", .) | (.+1) would produce the value 3 but with the following two lines being written to stderr: ["DEBUG:","Entering function foo with $x == 1"] ["DEBUG:",2] - title: "`stderr`" body: | Prints its input in raw and compact mode to stderr with no additional decoration, not even a newline. - title: "`input_filename`" body: | Returns the name of the file whose input is currently being filtered. Note that this will not work well unless jq is running in a UTF-8 locale. - title: "`input_line_number`" body: | Returns the line number of the input currently being filtered. - title: 'Streaming' body: | With the `--stream` option jq can parse input texts in a streaming fashion, allowing jq programs to start processing large JSON texts immediately rather than after the parse completes. If you have a single JSON text that is 1GB in size, streaming it will allow you to process it much more quickly. However, streaming isn't easy to deal with as the jq program will have `[, ]` (and a few other forms) as inputs. Several builtins are provided to make handling streams easier. The examples below use the streamed form of `["a",["b"]]`, which is `[[0],"a"],[[1,0],"b"],[[1,0]],[[1]]`. Streaming forms include `[, ]` (to indicate any scalar value, empty array, or empty object), and `[]` (to indicate the end of an array or object). Future versions of jq run with `--stream` and `--seq` may output additional forms such as `["error message"]` when an input text fails to parse. entries: - title: "`truncate_stream(stream_expression)`" body: | Consumes a number as input and truncates the corresponding number of path elements from the left of the outputs of the given streaming expression. examples: - program: 'truncate_stream([[0],"a"],[[1,0],"b"],[[1,0]],[[1]])' input: '1' output: ['[[0],"b"]', '[[0]]'] - title: "`fromstream(stream_expression)`" body: | Outputs values corresponding to the stream expression's outputs. examples: - program: 'fromstream(1|truncate_stream([[0],"a"],[[1,0],"b"],[[1,0]],[[1]]))' input: 'null' output: ['["b"]'] - title: "`tostream`" body: | The `tostream` builtin outputs the streamed form of its input. examples: - program: '. as $dot|fromstream($dot|tostream)|.==$dot' input: '[0,[1,{"a":1},{"b":2}]]' output: ['true'] - title: Assignment body: | Assignment works a little differently in jq than in most programming languages. jq doesn't distinguish between references to and copies of something - two objects or arrays are either equal or not equal, without any further notion of being "the same object" or "not the same object". If an object has two fields which are arrays, `.foo` and `.bar`, and you append something to `.foo`, then `.bar` will not get bigger, even if you've previously set `.bar = .foo`. If you're used to programming in languages like Python, Java, Ruby, JavaScript, etc. then you can think of it as though jq does a full deep copy of every object before it does the assignment (for performance it doesn't actually do that, but that's the general idea). This means that it's impossible to build circular values in jq (such as an array whose first element is itself). This is quite intentional, and ensures that anything a jq program can produce can be represented in JSON. All the assignment operators in jq have path expressions on the left-hand side (LHS). The right-hand side (RHS) provides values to set to the paths named by the LHS path expressions. Values in jq are always immutable. Internally, assignment works by using a reduction to compute new, replacement values for `.` that have had all the desired assignments applied to `.`, then outputting the modified value. This might be made clear by this example: `{a:{b:{c:1}}} | (.a.b|=3), .`. This will output `{"a":{"b":3}}` and `{"a":{"b":{"c":1}}}` because the last sub-expression, `.`, sees the original value, not the modified value. Most users will want to use modification assignment operators, such as `|=` or `+=`, rather than `=`. Note that the LHS of assignment operators refers to a value in `.`. Thus `$var.foo = 1` won't work as expected (`$var.foo` is not a valid or useful path expression in `.`); use `$var | .foo = 1` instead. Note too that `.a,.b=0` does not set `.a` and `.b`, but `(.a,.b)=0` sets both. entries: - title: "Update-assignment: `|=`" body: | This is the "update" operator `|=`. It takes a filter on the right-hand side and works out the new value for the property of `.` being assigned to by running the old value through this expression. For instance, `(.foo, .bar) |= .+1` will build an object with the `foo` field set to the input's `foo` plus 1, and the `bar` field set to the input's `bar` plus 1. The left-hand side can be any general path expression; see `path()`. Note that the left-hand side of `|=` refers to a value in `.`. Thus `$var.foo |= . + 1` won't work as expected (`$var.foo` is not a valid or useful path expression in `.`); use `$var | .foo |= . + 1` instead. If the right-hand side outputs no values (i.e., `empty`), then the left-hand side path will be deleted, as with `del(path)`. If the right-hand side outputs multiple values, only the first one will be used (COMPATIBILITY NOTE: in jq 1.5 and earlier releases, it used to be that only the last one was used). examples: - program: '(..|select(type=="boolean")) |= if . then 1 else 0 end' input: '[true,false,[5,true,[true,[false]],false]]' output: ['[1,0,[5,1,[1,[0]],0]]'] - title: "Arithmetic update-assignment: `+=`, `-=`, `*=`, `/=`, `%=`, `//=`" body: | jq has a few operators of the form `a op= b`, which are all equivalent to `a |= . op b`. So, `+= 1` can be used to increment values, being the same as `|= . + 1`. examples: - program: .foo += 1 input: '{"foo": 42}' output: ['{"foo": 43}'] - title: "Plain assignment: `=`" body: | This is the plain assignment operator. Unlike the others, the input to the right-hand side (RHS) is the same as the input to the left-hand side (LHS) rather than the value at the LHS path, and all values output by the RHS will be used (as shown below). If the RHS of `=` produces multiple values, then for each such value jq will set the paths on the left-hand side to the value and then it will output the modified `.`. For example, `(.a,.b) = range(2)` outputs `{"a":0,"b":0}`, then `{"a":1,"b":1}`. The "update" assignment forms (see above) do not do this. This example should show the difference between `=` and `|=`: Provide input `{"a": {"b": 10}, "b": 20}` to the programs .a = .b and .a |= .b The former will set the `a` field of the input to the `b` field of the input, and produce the output `{"a": 20, "b": 20}`. The latter will set the `a` field of the input to the `a` field's `b` field, producing `{"a": 10, "b": 20}`. examples: - program: .a = .b input: '{"a": {"b": 10}, "b": 20}' output: ['{"a":20,"b":20}'] - program: .a |= .b input: '{"a": {"b": 10}, "b": 20}' output: ['{"a":10,"b":20}'] - program: (.a, .b) = range(3) input: 'null' output: - '{"a":0,"b":0}' - '{"a":1,"b":1}' - '{"a":2,"b":2}' - program: (.a, .b) |= range(3) input: 'null' output: ['{"a":0,"b":0}'] - title: Complex assignments body: | Lots more things are allowed on the left-hand side of a jq assignment than in most languages. We've already seen simple field accesses on the left hand side, and it's no surprise that array accesses work just as well: .posts[0].title = "JQ Manual" What may come as a surprise is that the expression on the left may produce multiple results, referring to different points in the input document: .posts[].comments |= . + ["this is great"] That example appends the string "this is great" to the "comments" array of each post in the input (where the input is an object with a field "posts" which is an array of posts). When jq encounters an assignment like 'a = b', it records the "path" taken to select a part of the input document while executing a. This path is then used to find which part of the input to change while executing the assignment. Any filter may be used on the left-hand side of an equals - whichever paths it selects from the input will be where the assignment is performed. This is a very powerful operation. Suppose we wanted to add a comment to blog posts, using the same "blog" input above. This time, we only want to comment on the posts written by "stedolan". We can find those posts using the "select" function described earlier: .posts[] | select(.author == "stedolan") The paths provided by this operation point to each of the posts that "stedolan" wrote, and we can comment on each of them in the same way that we did before: (.posts[] | select(.author == "stedolan") | .comments) |= . + ["terrible."] - title: Comments body: | You can write comments in your jq filters using `#`. A `#` character (not part of a string) starts a comment. All characters from `#` to the end of the line are ignored. If the end of the line is preceded by an odd number of backslash characters, the following line is also considered part of the comment and is ignored. For example, the following code outputs `[1,3,4,7]` [ 1, # foo \ 2, # bar \\ 3, 4, # baz \\\ 5, \ 6, 7 # comment \ comment \ comment ] Backslash continuing the comment on the next line can be useful when writing the "shebang" for a jq script: #!/bin/sh -- # total - Output the sum of the given arguments (or stdin) # usage: total [numbers...] # \ exec jq --args -MRnf -- "$0" "$@" $ARGS.positional | reduce ( if . == [] then inputs else .[] end | . as $dot | try tonumber catch false | if not or isnan then @json "total: Invalid number \($dot).\n" | halt_error(1) end ) as $n (0; . + $n) The `exec` line is considered a comment by jq, so it is ignored. But it is not ignored by `sh`, since in `sh` a backslash at the end of the line does not continue the comment. With this trick, when the script is invoked as `total 1 2`, `/bin/sh -- /path/to/total 1 2` will be run, and `sh` will then run `exec jq --args -MRnf -- /path/to/total 1 2` replacing itself with a `jq` interpreter invoked with the specified options (`-M`, `-R`, `-n`, `--args`), that evaluates the current file (`$0`), with the arguments (`$@`) that were passed to `sh`. - title: Modules body: | jq has a library/module system. Modules are files whose names end in `.jq`. Modules imported by a program are searched for in a default search path (see below). The `import` and `include` directives allow the importer to alter this path. Paths in the search path are subject to various substitutions. For paths starting with `~/`, the user's home directory is substituted for `~`. For paths starting with `$ORIGIN/`, the directory where the jq executable is located is substituted for `$ORIGIN`. For paths starting with `./` or paths that are `.`, the path of the including file is substituted for `.`. For top-level programs given on the command-line, the current directory is used. Import directives can optionally specify a search path to which the default is appended. The default search path is the search path given to the `-L` command-line option, else `["~/.jq", "$ORIGIN/../lib/jq", "$ORIGIN/../lib"]`. Null and empty string path elements terminate search path processing. A dependency with relative path `foo/bar` would be searched for in `foo/bar.jq` and `foo/bar/bar.jq` in the given search path. This is intended to allow modules to be placed in a directory along with, for example, version control files, README files, and so on, but also to allow for single-file modules. Consecutive components with the same name are not allowed to avoid ambiguities (e.g., `foo/foo`). For example, with `-L$HOME/.jq` a module `foo` can be found in `$HOME/.jq/foo.jq` and `$HOME/.jq/foo/foo.jq`. If `.jq` exists in the user's home directory, and is a file (not a directory), it is automatically sourced into the main program. entries: - title: "`import RelativePathString as NAME [];`" body: | Imports a module found at the given path relative to a directory in a search path. A `.jq` suffix will be added to the relative path string. The module's symbols are prefixed with `NAME::`. The optional metadata must be a constant jq expression. It should be an object with keys like `homepage` and so on. At this time jq only uses the `search` key/value of the metadata. The metadata is also made available to users via the `modulemeta` builtin. The `search` key in the metadata, if present, should have a string or array value (array of strings); this is the search path to be prefixed to the top-level search path. - title: "`include RelativePathString [];`" body: | Imports a module found at the given path relative to a directory in a search path as if it were included in place. A `.jq` suffix will be added to the relative path string. The module's symbols are imported into the caller's namespace as if the module's content had been included directly. The optional metadata must be a constant jq expression. It should be an object with keys like `homepage` and so on. At this time jq only uses the `search` key/value of the metadata. The metadata is also made available to users via the `modulemeta` builtin. - title: "`import RelativePathString as $NAME [];`" body: | Imports a JSON file found at the given path relative to a directory in a search path. A `.json` suffix will be added to the relative path string. The file's data will be available as `$NAME::NAME`. The optional metadata must be a constant jq expression. It should be an object with keys like `homepage` and so on. At this time jq only uses the `search` key/value of the metadata. The metadata is also made available to users via the `modulemeta` builtin. The `search` key in the metadata, if present, should have a string or array value (array of strings); this is the search path to be prefixed to the top-level search path. - title: "`module ;`" body: | This directive is entirely optional. It's not required for proper operation. It serves only the purpose of providing metadata that can be read with the `modulemeta` builtin. The metadata must be a constant jq expression. It should be an object with keys like `homepage`. At this time jq doesn't use this metadata, but it is made available to users via the `modulemeta` builtin. - title: "`modulemeta`" body: | Takes a module name as input and outputs the module's metadata as an object, with the module's imports (including metadata) as an array value for the `deps` key and the module's defined functions as an array value for the `defs` key. Programs can use this to query a module's metadata, which they could then use to, for example, search for, download, and install missing dependencies. - title: Colors body: | To configure alternative colors just set the `JQ_COLORS` environment variable to colon-delimited list of partial terminal escape sequences like `"1;31"`, in this order: - color for `null` - color for `false` - color for `true` - color for numbers - color for strings - color for arrays - color for objects - color for object keys The default color scheme is the same as setting `JQ_COLORS="0;90:0;39:0;39:0;39:0;32:1;39:1;39:1;34"`. This is not a manual for VT100/ANSI escapes. However, each of these color specifications should consist of two numbers separated by a semi-colon, where the first number is one of these: - 1 (bright) - 2 (dim) - 4 (underscore) - 5 (blink) - 7 (reverse) - 8 (hidden) and the second is one of these: - 30 (black) - 31 (red) - 32 (green) - 33 (yellow) - 34 (blue) - 35 (magenta) - 36 (cyan) - 37 (white) ================================================ FILE: docs/content/manual/v1.3/manual.yml ================================================ --- headline: jq 1.3 Manual body: | A jq program is a "filter": it takes an input, and produces an output. There are a lot of builtin filters for extracting a particular field of an object, or converting a number to a string, or various other standard tasks. Filters can be combined in various ways - you can pipe the output of one filter into another filter, or collect the output of a filter into an array. Some filters produce multiple results, for instance there's one that produces all the elements of its input array. Piping that filter into a second runs the second filter for each element of the array. Generally, things that would be done with loops and iteration in other languages are just done by gluing filters together in jq. It's important to remember that every filter has an input and an output. Even literals like "hello" or 42 are filters - they take an input but always produce the same literal as output. Operations that combine two filters, like addition, generally feed the same input to both and combine the results. So, you can implement an averaging filter as `add / length` - feeding the input array both to the `add` filter and the `length` filter and dividing the results. But that's getting ahead of ourselves. :) Let's start with something simpler: manpage_intro: | jq(1) -- Command-line JSON processor ==================================== ## SYNOPSIS `jq` [...] [...] `jq` can transform JSON in various ways, by selecting, iterating, reducing and otherwise mangling JSON documents. For instance, running the command `jq 'map(.price) | add'` will take an array of JSON objects as input and return the sum of their "price" fields. By default, `jq` reads a stream of JSON objects (whitespace separated) from `stdin`. One or more may be specified, in which case `jq` will read input from those instead. The are described in the [INVOKING JQ] section, they mostly concern input and output formatting. The is written in the jq language and specifies how to transform the input document. ## FILTERS manpage_epilogue: | ## BUGS Presumably. Report them or discuss them at: https://github.com/jqlang/jq/issues ## AUTHOR Stephen Dolan `` sections: - title: Invoking jq body: | jq filters run on a stream of JSON data. The input to jq is parsed as a sequence of whitespace-separated JSON values which are passed through the provided filter one at a time. The output(s) of the filter are written to standard output, as a sequence of newline-separated JSON data. You can affect how jq reads and writes its input and output using some command-line options: * `--null-input` / `-n`: Don't read any input at all. Instead, the filter is run once using `null` as the input. This is useful when using jq as a simple calculator or to construct JSON data from scratch. * `--raw-input` / `-R`: Don't parse the input as JSON. Instead, each line of text is passed to the filter as a string. If combined with `--slurp`, then the entire input is passed to the filter as a single long string. * `--slurp` / `-s`: Instead of running the filter for each JSON object in the input, read the entire input stream into a large array and run the filter just once. * `--compact-output` / `-c`: By default, jq pretty-prints JSON output. Using this option will result in more compact output by instead putting each JSON object on a single line. * `--raw-output` / `-r`: With this option, if the filter's result is a string then it will be written directly to standard output rather than being formatted as a JSON string with quotes. This can be useful for making jq filters talk to non-JSON-based systems. * `--ascii-output` / `-a`: jq usually outputs non-ASCII Unicode codepoints as UTF-8, even if the input specified them as escape sequences (like "\u03bc"). Using this option, you can force jq to produce pure ASCII output with every non-ASCII character replaced with the equivalent escape sequence. * `--color-output` / `-C` and `--monochrome-output` / `-M`: By default, jq outputs colored JSON if writing to a terminal. You can force it to produce color even if writing to a pipe or a file using `-C`, and disable color with `-M`. * `--arg name value`: This option passes a value to the jq program as a predefined variable. If you run jq with `--arg foo bar`, then `$foo` is available in the program and has the value `"bar"`. - title: Basic filters entries: - title: "`.`" body: | The absolute simplest (and least interesting) filter is `.`. This is a filter that takes its input and produces it unchanged as output. Since jq by default pretty-prints all output, this trivial program can be a useful way of formatting JSON output from, say, `curl`. examples: - program: '.' input: '"Hello, world!"' output: ['"Hello, world!"'] - title: "`.foo`" body: | The simplest *useful* filter is .foo. When given a JSON object (aka dictionary or hash) as input, it produces the value at the key "foo", or null if there's none present. examples: - program: '.foo' input: '{"foo": 42, "bar": "less interesting data"}' output: ['42'] - program: '.foo' input: '{"notfoo": true, "alsonotfoo": false}' output: ['null'] - title: "`.[foo]`, `.[2]`, `.[10:15]`" body: | You can also look up fields of an object using syntax like `.["foo"]` (`.foo` above is a shorthand version of this). This one works for arrays as well, if the key is an integer. Arrays are zero-based, so `.[2]` returns the third element of the array. The `.[10:15]` syntax can be used to return a subarray of an array. The array returned by `.[10:15]` will be of length 5, containing the elements from index 10 (inclusive) to index 15 (exclusive). Either index may be negative (in which case it counts backwards from the end of the array), or omitted (in which case it refers to the start or end of the array). examples: - program: '.[0]' input: '[{"name":"JSON", "good":true}, {"name":"XML", "good":false}]' output: ['{"name":"JSON", "good":true}'] - program: '.[2]' input: '[{"name":"JSON", "good":true}, {"name":"XML", "good":false}]' output: ['null'] - program: '.[2:4]' input: '["a","b","c","d","e"]' output: ['["c", "d"]'] - program: '.[:3]' input: '["a","b","c","d","e"]' output: ['["a", "b", "c"]'] - program: '.[-2:]' input: '["a","b","c","d","e"]' output: ['["d", "e"]'] - title: "`.[]`" body: | If you use the `.[foo]` syntax, but omit the index entirely, it will return *all* of the elements of an array. Running `.[]` with the input `[1,2,3]` will produce the numbers as three separate results, rather than as a single array. You can also use this on an object, and it will return all the values of the object. examples: - program: '.[]' input: '[{"name":"JSON", "good":true}, {"name":"XML", "good":false}]' output: - '{"name":"JSON", "good":true}' - '{"name":"XML", "good":false}' - program: '.[]' input: '[]' output: [] - program: '.[]' input: '{"a": 1, "b": 1}' output: ['1', '1'] - title: "`,`" body: | If two filters are separated by a comma, then the input will be fed into both and there will be multiple outputs: first, all of the outputs produced by the left expression, and then all of the outputs produced by the right. For instance, filter `.foo, .bar`, produces both the "foo" fields and "bar" fields as separate outputs. examples: - program: '.foo, .bar' input: '{"foo": 42, "bar": "something else", "baz": true}' output: ['42', '"something else"'] - program: ".user, .projects[]" input: '{"user":"stedolan", "projects": ["jq", "wikiflow"]}' output: ['"stedolan"', '"jq"', '"wikiflow"'] - program: '.[4,2]' input: '["a","b","c","d","e"]' output: ['"e"', '"c"'] - title: "`|`" body: | The | operator combines two filters by feeding the output(s) of the one on the left into the input of the one on the right. It's pretty much the same as the Unix shell's pipe, if you're used to that. If the one on the left produces multiple results, the one on the right will be run for each of those results. So, the expression `.[] | .foo` retrieves the "foo" field of each element of the input array. examples: - program: '.[] | .name' input: '[{"name":"JSON", "good":true}, {"name":"XML", "good":false}]' output: ['"JSON"', '"XML"'] - title: Types and Values body: | jq supports the same set of datatypes as JSON - numbers, strings, booleans, arrays, objects (which in JSON-speak are hashes with only string keys), and "null". Booleans, null, strings and numbers are written the same way as in JSON. Just like everything else in jq, these simple values take an input and produce an output - `42` is a valid jq expression that takes an input, ignores it, and returns 42 instead. entries: - title: "Array construction: `[]`" body: | As in JSON, `[]` is used to construct arrays, as in `[1,2,3]`. The elements of the arrays can be any jq expression. All of the results produced by all of the expressions are collected into one big array. You can use it to construct an array out of a known quantity of values (as in `[.foo, .bar, .baz]`) or to "collect" all the results of a filter into an array (as in `[.items[].name]`) Once you understand the "," operator, you can look at jq's array syntax in a different light: the expression `[1,2,3]` is not using a built-in syntax for comma-separated arrays, but is instead applying the `[]` operator (collect results) to the expression 1,2,3 (which produces three different results). If you have a filter `X` that produces four results, then the expression `[X]` will produce a single result, an array of four elements. examples: - program: "[.user, .projects[]]" input: '{"user":"stedolan", "projects": ["jq", "wikiflow"]}' output: ['["stedolan", "jq", "wikiflow"]'] - title: "Objects: `{}`" body: | Like JSON, `{}` is for constructing objects (aka dictionaries or hashes), as in: `{"a": 42, "b": 17}`. If the keys are "sensible" (all alphabetic characters), then the quotes can be left off. The value can be any expression (although you may need to wrap it in parentheses if it's a complicated one), which gets applied to the {} expression's input (remember, all filters have an input and an output). {foo: .bar} will produce the JSON object `{"foo": 42}` if given the JSON object `{"bar":42, "baz":43}`. You can use this to select particular fields of an object: if the input is an object with "user", "title", "id", and "content" fields and you just want "user" and "title", you can write {user: .user, title: .title} Because that's so common, there's a shortcut syntax: `{user, title}`. If one of the expressions produces multiple results, multiple dictionaries will be produced. If the input's {"user":"stedolan","titles":["JQ Primer", "More JQ"]} then the expression {user, title: .titles[]} will produce two outputs: {"user":"stedolan", "title": "JQ Primer"} {"user":"stedolan", "title": "More JQ"} Putting parentheses around the key means it will be evaluated as an expression. With the same input as above, {(.user): .titles} produces {"stedolan": ["JQ Primer", "More JQ"]} examples: - program: '{user, title: .titles[]}' input: '{"user":"stedolan","titles":["JQ Primer", "More JQ"]}' output: - '{"user":"stedolan", "title": "JQ Primer"}' - '{"user":"stedolan", "title": "More JQ"}' - program: '{(.user): .titles}' input: '{"user":"stedolan","titles":["JQ Primer", "More JQ"]}' output: ['{"stedolan": ["JQ Primer", "More JQ"]}'] - title: Builtin operators and functions body: | Some jq operators (for instance, `+`) do different things depending on the type of their arguments (arrays, numbers, etc.). However, jq never does implicit type conversions. If you try to add a string to an object you'll get an error message and no result. entries: - title: "Addition: `+`" body: | The operator `+` takes two filters, applies them both to the same input, and adds the results together. What "adding" means depends on the types involved: - **Numbers** are added by normal arithmetic. - **Arrays** are added by being concatenated into a larger array. - **Strings** are added by being joined into a larger string. - **Objects** are added by merging, that is, inserting all the key-value pairs from both objects into a single combined object. If both objects contain a value for the same key, the object on the right of the `+` wins. `null` can be added to any value, and returns the other value unchanged. examples: - program: '.a + 1' input: '{"a": 7}' output: ['8'] - program: '.a + .b' input: '{"a": [1,2], "b": [3,4]}' output: ['[1,2,3,4]'] - program: '.a + null' input: '{"a": 1}' output: ['1'] - program: '.a + 1' input: '{}' output: ['1'] - program: '{a: 1} + {b: 2} + {c: 3} + {a: 42}' input: 'null' output: ['{"a": 42, "b": 2, "c": 3}'] - title: "Subtraction: `-`" body: | As well as normal arithmetic subtraction on numbers, the `-` operator can be used on arrays to remove all occurrences of the second array's elements from the first array. examples: - program: '4 - .a' input: '{"a":3}' output: ['1'] - program: . - ["xml", "yaml"] input: '["xml", "yaml", "json"]' output: ['["json"]'] - title: "Multiplication, division: `*` and `/`" body: | These operators only work on numbers, and do the expected. examples: - program: '10 / . * 3' input: '5' output: ['6'] - title: '`length`' body: | The builtin function `length` gets the length of various different types of value: - The length of a **string** is the number of Unicode codepoints it contains (which will be the same as its JSON-encoded length in bytes if it's pure ASCII). - The length of an **array** is the number of elements. - The length of an **object** is the number of key-value pairs. - The length of **null** is zero. examples: - program: '.[] | length' input: '[[1,2], "string", {"a":2}, null]' output: ['2', '6', '1', '0'] - title: '`keys`' body: | The builtin function `keys`, when given an object, returns its keys in an array. The keys are sorted "alphabetically", by unicode codepoint order. This is not an order that makes particular sense in any particular language, but you can count on it being the same for any two objects with the same set of keys, regardless of locale settings. When `keys` is given an array, it returns the valid indices for that array: the integers from 0 to length-1. examples: - program: 'keys' input: '{"abc": 1, "abcd": 2, "Foo": 3}' output: ['["Foo", "abc", "abcd"]'] - program: 'keys' input: '[42,3,35]' output: ['[0,1,2]'] - title: '`has`' body: | The builtin function `has` returns whether the input object has the given key, or the input array has an element at the given index. `has($key)` has the same effect as checking whether `$key` is a member of the array returned by `keys`, although `has` will be faster. examples: - program: 'map(has("foo"))' input: '[{"foo": 42}, {}]' output: ['[true, false]'] - program: 'map(has(2))' input: '[[0,1], ["a","b","c"]]' output: ['[false, true]'] - title: "`to_entries`, `from_entries`, `with_entries(f)`" body: | These functions convert between an object and an array of key-value pairs. If `to_entries` is passed an object, then for each `k: v` entry in the input, the output array includes `{"key": k, "value": v}`. `from_entries` does the opposite conversion, and `with_entries(f)` is a shorthand for `to_entries | map(f) | from_entries`, useful for doing some operation to all keys and values of an object. examples: - program: 'to_entries' input: '{"a": 1, "b": 2}' output: ['[{"key":"a", "value":1}, {"key":"b", "value":2}]'] - program: 'from_entries' input: '[{"key":"a", "value":1}, {"key":"b", "value":2}]' output: ['{"a": 1, "b": 2}'] - program: 'with_entries(.key |= "KEY_" + .)' input: '{"a": 1, "b": 2}' output: ['{"KEY_a": 1, "KEY_b": 2}'] - title: '`select`' body: | The function `select(foo)` produces its input unchanged if `foo` returns true for that input, and produces no output otherwise. It's useful for filtering lists: '`[1,2,3] | map(select(. >= 2))`' will give you `[3]`. examples: - program: 'map(select(. >= 2))' input: '[1,5,3,0,7]' output: ['[5,3,7]'] - title: '`empty`' body: | `empty` returns no results. None at all. Not even `null`. It's useful on occasion. You'll know if you need it :) examples: - program: '1, empty, 2' input: 'null' output: ['1', '2'] - program: '[1,2,empty,3]' input: 'null' output: ['[1,2,3]'] - title: '`map(f)`' body: | For any filter `f`, `map(f)` will run that filter for each element of the input array, and produce the outputs a new array. `map(.+1)` will increment each element of an array of numbers. `map(f)` is equivalent to `[.[] | f]`. In fact, this is how it's defined. examples: - program: 'map(.+1)' input: '[1,2,3]' output: ['[2,3,4]'] - title: '`add`' body: | The filter `add` takes as input an array, and produces as output the elements of the array added together. This might mean summed, concatenated or merged depending on the types of the elements of the input array - the rules are the same as those for the `+` operator (described above). If the input is an empty array, `add` returns `null`. examples: - program: add input: '["a","b","c"]' output: ['"abc"'] - program: add input: '[1, 2, 3]' output: ['6'] - program: add input: '[]' output: ["null"] - title: '`range`' body: | The `range` function produces a range of numbers. `range(4;10)` produces 6 numbers, from 4 (inclusive) to 10 (exclusive). The numbers are produced as separate outputs. Use `[range(4;10)]` to get a range as an array. examples: - program: 'range(2;4)' input: 'null' output: ['2', '3'] - program: '[range(2;4)]' input: 'null' output: ['[2,3]'] - title: '`tonumber`' body: | The `tonumber` function parses its input as a number. It will convert correctly-formatted strings to their numeric equivalent, leave numbers alone, and give an error on all other input. examples: - program: '.[] | tonumber' input: '[1, "1"]' output: ['1', '1'] - title: '`tostring`' body: | The `tostring` function prints its input as a string. Strings are left unchanged, and all other values are JSON-encoded. examples: - program: '.[] | tostring' input: '[1, "1", [1]]' output: ['"1"', '"1"', '"[1]"'] - title: '`type`' body: | The `type` function returns the type of its argument as a string, which is one of null, boolean, number, string, array or object. examples: - program: 'map(type)' input: '[0, false, [], {}, null, "hello"]' output: ['["number", "boolean", "array", "object", "null", "string"]'] - title: '`sort`, `sort_by`' body: | The `sort` functions sorts its input, which must be an array. Values are sorted in the following order: * `null` * `false` * `true` * numbers * strings, in alphabetical order (by unicode codepoint value) * arrays, in lexical order * objects The ordering for objects is a little complex: first they're compared by comparing their sets of keys (as arrays in sorted order), and if their keys are equal then the values are compared key by key. `sort_by` may be used to sort by a particular field of an object, or by applying any jq filter. `sort_by(foo)` compares two elements by comparing the result of `foo` on each element. examples: - program: 'sort' input: '[8,3,null,6]' output: ['[null,3,6,8]'] - program: 'sort_by(.foo)' input: '[{"foo":4, "bar":10}, {"foo":3, "bar":100}, {"foo":2, "bar":1}]' output: ['[{"foo":2, "bar":1}, {"foo":3, "bar":100}, {"foo":4, "bar":10}]'] - title: '`group_by`' body: | `group_by(.foo)` takes as input an array, groups the elements having the same `.foo` field into separate arrays, and produces all of these arrays as elements of a larger array, sorted by the value of the `.foo` field. Any jq expression, not just a field access, may be used in place of `.foo`. The sorting order is the same as described in the `sort` function above. examples: - program: 'group_by(.foo)' input: '[{"foo":1, "bar":10}, {"foo":3, "bar":100}, {"foo":1, "bar":1}]' output: ['[[{"foo":1, "bar":10}, {"foo":1, "bar":1}], [{"foo":3, "bar":100}]]'] - title: '`min`, `max`, `min_by`, `max_by`' body: | Find the minimum or maximum element of the input array. The `_by` versions allow you to specify a particular field or property to examine, e.g. `min_by(.foo)` finds the object with the smallest `foo` field. examples: - program: 'min' input: '[5,4,2,7]' output: ['2'] - program: 'max_by(.foo)' input: '[{"foo":1, "bar":14}, {"foo":2, "bar":3}]' output: ['{"foo":2, "bar":3}'] - title: '`unique`' body: | The `unique` function takes as input an array and produces an array of the same elements, in sorted order, with duplicates removed. examples: - program: 'unique' input: '[1,2,5,3,5,3,1,3]' output: ['[1,2,3,5]'] - title: '`reverse`' body: | This function reverses an array. examples: - program: 'reverse' input: '[1,2,3,4]' output: ['[4,3,2,1]'] - title: '`contains`' body: | The filter `contains(b)` will produce true if b is completely contained within the input. A string B is contained in a string A if B is a substring of A. An array B is contained in an array A is all elements in B are contained in any element in A. An object B is contained in object A if all of the values in B are contained in the value in A with the same key. All other types are assumed to be contained in each other if they are equal. examples: - program: 'contains("bar")' input: '"foobar"' output: ['true'] - program: 'contains(["baz", "bar"])' input: '["foobar", "foobaz", "blarp"]' output: ['true'] - program: 'contains(["bazzzzz", "bar"])' input: '["foobar", "foobaz", "blarp"]' output: ['false'] - program: 'contains({foo: 12, bar: [{barp: 12}]})' input: '{"foo": 12, "bar":[1,2,{"barp":12, "blip":13}]}' output: ['true'] - program: 'contains({foo: 12, bar: [{barp: 15}]})' input: '{"foo": 12, "bar":[1,2,{"barp":12, "blip":13}]}' output: ['false'] - title: '`recurse`' body: | The `recurse` function allows you to search through a recursive structure, and extract interesting data from all levels. Suppose your input represents a filesystem: {"name": "/", "children": [ {"name": "/bin", "children": [ {"name": "/bin/ls", "children": []}, {"name": "/bin/sh", "children": []}]}, {"name": "/home", "children": [ {"name": "/home/stephen", "children": [ {"name": "/home/stephen/jq", "children": []}]}]}]} Now suppose you want to extract all of the filenames present. You need to retrieve `.name`, `.children[].name`, `.children[].children[].name`, and so on. You can do this with: recurse(.children[]) | .name examples: - program: 'recurse(.foo[])' input: '{"foo":[{"foo": []}, {"foo":[{"foo":[]}]}]}' output: - '{"foo":[{"foo":[]},{"foo":[{"foo":[]}]}]}' - '{"foo":[]}' - '{"foo":[{"foo":[]}]}' - '{"foo":[]}' - title: "String interpolation: `\\(exp)`" body: | Inside a string, you can put an expression inside parens after a backslash. Whatever the expression returns will be interpolated into the string. examples: - program: '"The input was \(.), which is one less than \(.+1)"' input: '42' output: ['"The input was 42, which is one less than 43"'] - title: "Format strings and escaping" body: | The `@foo` syntax is used to format and escape strings, which is useful for building URLs, documents in a language like HTML or XML, and so forth. `@foo` can be used as a filter on its own, the possible escapings are: * `@text`: Calls `tostring`, see that function for details. * `@json`: Serialises the input as JSON. * `@html`: Applies HTML/XML escaping, by mapping the characters `<>&'"` to their entity equivalents `<`, `>`, `&`, `'`, `"`. * `@uri`: Applies percent-encoding, by mapping all reserved URI characters to a `%xx` sequence. * `@csv`: The input must be an array, and it is rendered as CSV with double quotes for strings, and quotes escaped by repetition. * `@sh`: The input is escaped suitable for use in a command-line for a POSIX shell. If the input is an array, the output will be a series of space-separated strings. * `@base64`: The input is converted to base64 as specified by RFC 4648. This syntax can be combined with string interpolation in a useful way. You can follow a `@foo` token with a string literal. The contents of the string literal will *not* be escaped. However, all interpolations made inside that string literal will be escaped. For instance, @uri "https://www.google.com/search?q=\(.search)" will produce the following output for the input `{"search":"jq!"}`: https://www.google.com/search?q=jq%21 Note that the slashes, question mark, etc. in the URL are not escaped, as they were part of the string literal. examples: - program: '@html' input: '"This works if x < y"' output: ['"This works if x < y"'] - program: '@sh "echo \(.)"' input: "\"O'Hara's Ale\"" output: ["\"echo 'O'\\\\''Hara'\\\\''s Ale'\""] - title: Conditionals and Comparisons entries: - title: '`==`, `!=`' body: | The expression 'a == b' will produce 'true' if the result of a and b are equal (that is, if they represent equivalent JSON documents) and 'false' otherwise. In particular, strings are never considered equal to numbers. If you're coming from JavaScript, jq's == is like JavaScript's === - considering values equal only when they have the same type as well as the same value. != is "not equal", and 'a != b' returns the opposite value of 'a == b' examples: - program: '.[] == 1' input: '[1, 1.0, "1", "banana"]' output: ['true', 'true', 'false', 'false'] - title: if-then-else-end body: | `if A then B else C end` will act the same as `B` if `A` produces a value other than false or null, but act the same as `C` otherwise. Checking for false or null is a simpler notion of "truthiness" than is found in JavaScript or Python, but it means that you'll sometimes have to be more explicit about the condition you want: you can't test whether, e.g. a string is empty using `if .name then A else B end`, you'll need something more like `if (.name | length) > 0 then A else B end` instead. If the condition `A` produces multiple results, then `B` is evaluated once for each result that is not false or null, and `C` is evaluated once for each false or null. More cases can be added to an if using `elif A then B` syntax. examples: - program: |- if . == 0 then "zero" elif . == 1 then "one" else "many" end input: '2' output: ['"many"'] - title: "`>`, `>=`, `<=`, `<`" body: | The comparison operators `>`, `>=`, `<=`, `<` return whether their left argument is greater than, greater than or equal to, less than or equal to or less than their right argument (respectively). The ordering is the same as that described for `sort`, above. examples: - program: '. < 5' input: '2' output: ['true'] - title: "`and`, `or`, `not`" body: | jq supports the normal Boolean operators `and`, `or`, `not`. They have the same standard of truth as if expressions - `false` and `null` are considered "false values", and anything else is a "true value". If an operand of one of these operators produces multiple results, the operator itself will produce a result for each input. `not` is in fact a builtin function rather than an operator, so it is called as a filter to which things can be piped rather than with special syntax, as in `.foo and .bar | not`. These three only produce the values `true` and `false`, and so are only useful for genuine Boolean operations, rather than the common Perl/Python/Ruby idiom of "value_that_may_be_null or default". If you want to use this form of "or", picking between two values rather than evaluating a condition, see the `//` operator below. examples: - program: '42 and "a string"' input: 'null' output: ['true'] - program: '(true, false) or false' input: 'null' output: ['true', 'false'] - program: '(true, true) and (true, false)' input: 'null' output: ['true', 'false', 'true', 'false'] - program: '[true, false | not]' input: 'null' output: ['[false, true]'] - title: "Alternative operator: `//`" body: | A filter of the form `a // b` produces the same results as `a`, if `a` produces results other than `false` and `null`. Otherwise, `a // b` produces the same results as `b`. This is useful for providing defaults: `.foo // 1` will evaluate to `1` if there's no `.foo` element in the input. It's similar to how `or` is sometimes used in Python (jq's `or` operator is reserved for strictly Boolean operations). examples: - program: '.foo // 42' input: '{"foo": 19}' output: ['19'] - program: '.foo // 42' input: '{}' output: ['42'] - title: Advanced features body: | Variables are an absolute necessity in most programming languages, but they're relegated to an "advanced feature" in jq. In most languages, variables are the only means of passing around data. If you calculate a value, and you want to use it more than once, you'll need to store it in a variable. To pass a value to another part of the program, you'll need that part of the program to define a variable (as a function parameter, object member, or whatever) in which to place the data. It is also possible to define functions in jq, although this is is a feature whose biggest use is defining jq's standard library (many jq functions such as `map` and `select` are in fact written in jq). Finally, jq has a `reduce` operation, which is very powerful but a bit tricky. Again, it's mostly used internally, to define some useful bits of jq's standard library. entries: - title: Variables body: | In jq, all filters have an input and an output, so manual plumbing is not necessary to pass a value from one part of a program to the next. Many expressions, for instance `a + b`, pass their input to two distinct subexpressions (here `a` and `b` are both passed the same input), so variables aren't usually necessary in order to use a value twice. For instance, calculating the average value of an array of numbers requires a few variables in most languages - at least one to hold the array, perhaps one for each element or for a loop counter. In jq, it's simply `add / length` - the `add` expression is given the array and produces its sum, and the `length` expression is given the array and produces its length. So, there's generally a cleaner way to solve most problems in jq than defining variables. Still, sometimes they do make things easier, so jq lets you define variables using `expression as $variable`. All variable names start with `$`. Here's a slightly uglier version of the array-averaging example: length as $array_length | add / $array_length We'll need a more complicated problem to find a situation where using variables actually makes our lives easier. Suppose we have an array of blog posts, with "author" and "title" fields, and another object which is used to map author usernames to real names. Our input looks like: {"posts": [{"title": "First post", "author": "anon"}, {"title": "A well-written article", "author": "person1"}], "realnames": {"anon": "Anonymous Coward", "person1": "Person McPherson"}} We want to produce the posts with the author field containing a real name, as in: {"title": "First post", "author": "Anonymous Coward"} {"title": "A well-written article", "author": "Person McPherson"} We use a variable, $names, to store the realnames object, so that we can refer to it later when looking up author usernames: .realnames as $names | .posts[] | {title, author: $names[.author]} The expression `exp as $x | ...` means: for each value of expression `exp`, run the rest of the pipeline with the entire original input, and with `$x` set to that value. Thus `as` functions as something of a foreach loop. Variables are scoped over the rest of the expression that defines them, so .realnames as $names | (.posts[] | {title, author: $names[.author]}) will work, but (.realnames as $names | .posts[]) | {title, author: $names[.author]} won't. examples: - program: '.bar as $x | .foo | . + $x' input: '{"foo":10, "bar":200}' output: ['210'] - title: 'Defining Functions' body: | You can give a filter a name using "def" syntax: def increment: . + 1; From then on, `increment` is usable as a filter just like a builtin function (in fact, this is how some of the builtins are defined). A function may take arguments: def map(f): [.[] | f]; Arguments are passed as filters, not as values. The same argument may be referenced multiple times with different inputs (here `f` is run for each element of the input array). Arguments to a function work more like callbacks than like value arguments. If you want the value-argument behaviour for defining simple functions, you can just use a variable: def addvalue(f): f as $value | map(. + $value); With that definition, `addvalue(.foo)` will add the current input's `.foo` field to each element of the array. examples: - program: 'def addvalue(f): . + [f]; map(addvalue(.[0]))' input: '[[1,2],[10,20]]' output: ['[[1,2,1], [10,20,10]]'] - program: 'def addvalue(f): f as $x | map(. + $x); addvalue(.[0])' input: '[[1,2],[10,20]]' output: ['[[1,2,1,2], [10,20,1,2]]'] - title: "`reduce`" body: | The `reduce` syntax allows you to combine all of the results of an expression by accumulating them into a single answer. The form is `reduce EXP as $var (INIT; UPDATE)`. As an example, we'll pass `[1,2,3]` to this expression: reduce .[] as $item (0; . + $item) For each result that `.[]` produces, `. + $item` is run to accumulate a running total, starting from 0 as the input value. In this example, `.[]` produces the results `1`, `2`, and `3`, so the effect is similar to running something like this: 0 | 1 as $item | . + $item | 2 as $item | . + $item | 3 as $item | . + $item examples: - program: 'reduce .[] as $item (0; . + $item)' input: '[1,2,3,4,5]' output: ['15'] - title: Assignment body: | Assignment works a little differently in jq than in most programming languages. jq doesn't distinguish between references to and copies of something - two objects or arrays are either equal or not equal, without any further notion of being "the same object" or "not the same object". If an object has two fields which are arrays, `.foo` and `.bar`, and you append something to `.foo`, then `.bar` will not get bigger. Even if you've just set `.bar = .foo`. If you're used to programming in languages like Python, Java, Ruby, JavaScript, etc. then you can think of it as though jq does a full deep copy of every object before it does the assignment (for performance, it doesn't actually do that, but that's the general idea). entries: - title: "`=`" body: | The filter `.foo = 1` will take as input an object and produce as output an object with the "foo" field set to 1. There is no notion of "modifying" or "changing" something in jq - all jq values are immutable. For instance, .foo = .bar | .foo.baz = 1 will not have the side-effect of setting .bar.baz to be set to 1, as the similar-looking program in JavaScript, Python, Ruby or other languages would. Unlike these languages (but like Haskell and some other functional languages), there is no notion of two arrays or objects being "the same array" or "the same object". They can be equal, or not equal, but if we change one of them in no circumstances will the other change behind our backs. This means that it's impossible to build circular values in jq (such as an array whose first element is itself). This is quite intentional, and ensures that anything a jq program can produce can be represented in JSON. - title: "`|=`" body: | As well as the assignment operator '=', jq provides the "update" operator '|=', which takes a filter on the right-hand side and works out the new value for the property being assigned to by running the old value through this expression. For instance, .foo |= .+1 will build an object with the "foo" field set to the input's "foo" plus 1. This example should show the difference between '=' and '|=': Provide input '{"a": {"b": 10}, "b": 20}' to the programs: .a = .b .a |= .b The former will set the "a" field of the input to the "b" field of the input, and produce the output {"a": 20}. The latter will set the "a" field of the input to the "a" field's "b" field, producing {"a": 10}. - title: "`+=`, `-=`, `*=`, `/=`, `//=`" body: | jq has a few operators of the form `a op= b`, which are all equivalent to `a |= . op b`. So, `+= 1` can be used to increment values. examples: - program: .foo += 1 input: '{"foo": 42}' output: ['{"foo": 43}'] - title: Complex assignments body: | Lots more things are allowed on the left-hand side of a jq assignment than in most languages. We've already seen simple field accesses on the left hand side, and it's no surprise that array accesses work just as well: .posts[0].title = "JQ Manual" What may come as a surprise is that the expression on the left may produce multiple results, referring to different points in the input document: .posts[].comments |= . + ["this is great"] That example appends the string "this is great" to the "comments" array of each post in the input (where the input is an object with a field "posts" which is an array of posts). When jq encounters an assignment like 'a = b', it records the "path" taken to select a part of the input document while executing a. This path is then used to find which part of the input to change while executing the assignment. Any filter may be used on the left-hand side of an equals - whichever paths it selects from the input will be where the assignment is performed. This is a very powerful operation. Suppose we wanted to add a comment to blog posts, using the same "blog" input above. This time, we only want to comment on the posts written by "stedolan". We can find those posts using the "select" function described earlier: .posts[] | select(.author == "stedolan") The paths provided by this operation point to each of the posts that "stedolan" wrote, and we can comment on each of them in the same way that we did before: (.posts[] | select(.author == "stedolan") | .comments) |= . + ["terrible."] ================================================ FILE: docs/content/manual/v1.4/manual.yml ================================================ --- headline: jq 1.4 Manual body: | A jq program is a "filter": it takes an input, and produces an output. There are a lot of builtin filters for extracting a particular field of an object, or converting a number to a string, or various other standard tasks. Filters can be combined in various ways - you can pipe the output of one filter into another filter, or collect the output of a filter into an array. Some filters produce multiple results, for instance there's one that produces all the elements of its input array. Piping that filter into a second runs the second filter for each element of the array. Generally, things that would be done with loops and iteration in other languages are just done by gluing filters together in jq. It's important to remember that every filter has an input and an output. Even literals like "hello" or 42 are filters - they take an input but always produce the same literal as output. Operations that combine two filters, like addition, generally feed the same input to both and combine the results. So, you can implement an averaging filter as `add / length` - feeding the input array both to the `add` filter and the `length` filter and dividing the results. But that's getting ahead of ourselves. :) Let's start with something simpler: manpage_intro: | jq(1) -- Command-line JSON processor ==================================== ## SYNOPSIS `jq` [...] [...] `jq` can transform JSON in various ways, by selecting, iterating, reducing and otherwise mangling JSON documents. For instance, running the command `jq 'map(.price) | add'` will take an array of JSON objects as input and return the sum of their "price" fields. By default, `jq` reads a stream of JSON objects (whitespace separated) from `stdin`. One or more may be specified, in which case `jq` will read input from those instead. The are described in the [INVOKING JQ] section, they mostly concern input and output formatting. The is written in the jq language and specifies how to transform the input document. ## FILTERS manpage_epilogue: | ## BUGS Presumably. Report them or discuss them at: https://github.com/jqlang/jq/issues ## AUTHOR Stephen Dolan `` sections: - title: Invoking jq body: | jq filters run on a stream of JSON data. The input to jq is parsed as a sequence of whitespace-separated JSON values which are passed through the provided filter one at a time. The output(s) of the filter are written to standard output, as a sequence of newline-separated JSON data. Note: it is important to mind the shell's quoting rules. As a general rule it's best to always quote (with single-quote characters) the jq program, as too many characters with special meaning to jq are also shell meta-characters. For example, `jq "foo"` will fail on most Unix shells because that will be the same as `jq foo`, which will generally fail because `foo is not defined`. When using the Windows command shell (cmd.exe) it's best to use double quotes around your jq program when given on the command-line (instead of the `-f program-file` option), but then double-quotes in the jq program need backslash escaping. You can affect how jq reads and writes its input and output using some command-line options: * `--null-input` / `-n`: Don't read any input at all. Instead, the filter is run once using `null` as the input. This is useful when using jq as a simple calculator or to construct JSON data from scratch. * `--raw-input` / `-R`: Don't parse the input as JSON. Instead, each line of text is passed to the filter as a string. If combined with `--slurp`, then the entire input is passed to the filter as a single long string. * `--slurp` / `-s`: Instead of running the filter for each JSON object in the input, read the entire input stream into a large array and run the filter just once. * `--online-input` / `-I`: When the top-level input value is an array produce its elements instead of the array. This allows on-line processing of potentially very large top-level arrays' elements. * `--compact-output` / `-c`: By default, jq pretty-prints JSON output. Using this option will result in more compact output by instead putting each JSON object on a single line. * `--raw-output` / `-r`: With this option, if the filter's result is a string then it will be written directly to standard output rather than being formatted as a JSON string with quotes. This can be useful for making jq filters talk to non-JSON-based systems. * `--ascii-output` / `-a`: jq usually outputs non-ASCII Unicode codepoints as UTF-8, even if the input specified them as escape sequences (like "\u03bc"). Using this option, you can force jq to produce pure ASCII output with every non-ASCII character replaced with the equivalent escape sequence. * `--sort-keys` / `-S`: Output the fields of each object with the keys in sorted order. * `--color-output` / `-C` and `--monochrome-output` / `-M`: By default, jq outputs colored JSON if writing to a terminal. You can force it to produce color even if writing to a pipe or a file using `-C`, and disable color with `-M`. * `--unbuffered`: Flush the output after each JSON object is printed (useful if you're piping a slow data source into jq and piping jq's output elsewhere). * `-f filename` / `--from-file filename`: Read filter from the file rather than from a command line, like awk's -f option. You can also use '#' to make comments. * `--arg name value`: This option passes a value to the jq program as a predefined variable. If you run jq with `--arg foo bar`, then `$foo` is available in the program and has the value `"bar"`. * `--argfile name filename`: This option passes the first value from the named file as a value to the jq program as a predefined variable. If you run jq with `--argfile foo bar`, then `$foo` is available in the program and has the value resulting from parsing the content of the file named `bar`. * `--exit-status` / `-e`: Sets the exit status of jq to 0 if the last output value was neither `false` nor `null`, 1 if the last output value was either `false` or `null`, or 4 if no valid result was ever produced. Normally jq exits with 2 if there was any usage problem or system error, 3 if there was a jq program compile error, or 0 if the jq program ran. * `--version` / `-V`: Output the jq version and exit with zero. * `--help` / `-h`: Output the jq help and exit with zero. - title: Basic filters entries: - title: "`.`" body: | The absolute simplest (and least interesting) filter is `.`. This is a filter that takes its input and produces it unchanged as output. Since jq by default pretty-prints all output, this trivial program can be a useful way of formatting JSON output from, say, `curl`. examples: - program: '.' input: '"Hello, world!"' output: ['"Hello, world!"'] - title: "`.foo`, `.foo.bar`" body: | The simplest *useful* filter is `.foo`. When given a JSON object (aka dictionary or hash) as input, it produces the value at the key "foo", or null if there's none present. If the key contains special characters or starts with a digit, you need to surround it with double quotes like this: `."foo$"`. A filter of the form `.foo.bar` is equivalent to `.foo|.bar`. examples: - program: '.foo' input: '{"foo": 42, "bar": "less interesting data"}' output: ['42'] - program: '.foo' input: '{"notfoo": true, "alsonotfoo": false}' output: ['null'] - program: '.["foo"]' input: '{"foo": 42}' output: ['42'] - title: "`.foo?`" body: | Just like `.foo`, but does not output an error when `.` is not an object. examples: - program: '.foo?' input: '{"foo": 42, "bar": "less interesting data"}' output: ['42'] - program: '.foo?' input: '{"notfoo": true, "alsonotfoo": false}' output: ['null'] - program: '.["foo"]?' input: '{"foo": 42}' output: ['42'] - program: '[.foo?]' input: '[1,2]' output: ['[]'] - title: "`.[]`, `.[]`, `.[:]`" body: | You can also look up fields of an object using syntax like `.["foo"]` (`.foo` above is a shorthand version of this). This one works for arrays as well, if the key is an integer. Arrays are zero-based, so `.[2]` returns the third element of the array. The `.[10:15]` syntax can be used to return a subarray of an array or substring of a string. The array returned by `.[10:15]` will be of length 5, containing the elements from index 10 (inclusive) to index 15 (exclusive). Either index may be negative (in which case it counts backwards from the end of the array), or omitted (in which case it refers to the start or end of the array). Indices are zero-based. The `?` "operator" can also be used with the slice operator, as in `.[10:15]?`, which outputs values where the inputs are slice-able. examples: - program: '.[0]' input: '[{"name":"JSON", "good":true}, {"name":"XML", "good":false}]' output: ['{"name":"JSON", "good":true}'] - program: '.[2]' input: '[{"name":"JSON", "good":true}, {"name":"XML", "good":false}]' output: ['null'] - program: '.[2:4]' input: '["a","b","c","d","e"]' output: ['["c", "d"]'] - program: '.[2:4]' input: '"abcdefghi"' output: ['"cd"'] - program: '.[:3]' input: '["a","b","c","d","e"]' output: ['["a", "b", "c"]'] - program: '.[-2:]' input: '["a","b","c","d","e"]' output: ['["d", "e"]'] - title: "`.[]`" body: | If you use the `.[index]` syntax, but omit the index entirely, it will return *all* of the elements of an array. Running `.[]` with the input `[1,2,3]` will produce the numbers as three separate results, rather than as a single array. You can also use this on an object, and it will return all the values of the object. examples: - program: '.[]' input: '[{"name":"JSON", "good":true}, {"name":"XML", "good":false}]' output: - '{"name":"JSON", "good":true}' - '{"name":"XML", "good":false}' - program: '.[]' input: '[]' output: [] - program: '.[]' input: '{"a": 1, "b": 1}' output: ['1', '1'] - title: "`.[]?`" body: | Like `.[]`, but no errors will be output if . is not an array or object. - title: "`,`" body: | If two filters are separated by a comma, then the input will be fed into both and there will be multiple outputs: first, all of the outputs produced by the left expression, and then all of the outputs produced by the right. For instance, filter `.foo, .bar`, produces both the "foo" fields and "bar" fields as separate outputs. examples: - program: '.foo, .bar' input: '{"foo": 42, "bar": "something else", "baz": true}' output: ['42', '"something else"'] - program: ".user, .projects[]" input: '{"user":"stedolan", "projects": ["jq", "wikiflow"]}' output: ['"stedolan"', '"jq"', '"wikiflow"'] - program: '.[4,2]' input: '["a","b","c","d","e"]' output: ['"e"', '"c"'] - title: "`|`" body: | The | operator combines two filters by feeding the output(s) of the one on the left into the input of the one on the right. It's pretty much the same as the Unix shell's pipe, if you're used to that. If the one on the left produces multiple results, the one on the right will be run for each of those results. So, the expression `.[] | .foo` retrieves the "foo" field of each element of the input array. examples: - program: '.[] | .name' input: '[{"name":"JSON", "good":true}, {"name":"XML", "good":false}]' output: ['"JSON"', '"XML"'] - title: Types and Values body: | jq supports the same set of datatypes as JSON - numbers, strings, booleans, arrays, objects (which in JSON-speak are hashes with only string keys), and "null". Booleans, null, strings and numbers are written the same way as in JSON. Just like everything else in jq, these simple values take an input and produce an output - `42` is a valid jq expression that takes an input, ignores it, and returns 42 instead. entries: - title: "Array construction: `[]`" body: | As in JSON, `[]` is used to construct arrays, as in `[1,2,3]`. The elements of the arrays can be any jq expression. All of the results produced by all of the expressions are collected into one big array. You can use it to construct an array out of a known quantity of values (as in `[.foo, .bar, .baz]`) or to "collect" all the results of a filter into an array (as in `[.items[].name]`) Once you understand the "," operator, you can look at jq's array syntax in a different light: the expression `[1,2,3]` is not using a built-in syntax for comma-separated arrays, but is instead applying the `[]` operator (collect results) to the expression 1,2,3 (which produces three different results). If you have a filter `X` that produces four results, then the expression `[X]` will produce a single result, an array of four elements. examples: - program: "[.user, .projects[]]" input: '{"user":"stedolan", "projects": ["jq", "wikiflow"]}' output: ['["stedolan", "jq", "wikiflow"]'] - title: "Objects: `{}`" body: | Like JSON, `{}` is for constructing objects (aka dictionaries or hashes), as in: `{"a": 42, "b": 17}`. If the keys are "sensible" (all alphabetic characters), then the quotes can be left off. The value can be any expression (although you may need to wrap it in parentheses if it's a complicated one), which gets applied to the {} expression's input (remember, all filters have an input and an output). {foo: .bar} will produce the JSON object `{"foo": 42}` if given the JSON object `{"bar":42, "baz":43}`. You can use this to select particular fields of an object: if the input is an object with "user", "title", "id", and "content" fields and you just want "user" and "title", you can write {user: .user, title: .title} Because that's so common, there's a shortcut syntax: `{user, title}`. If one of the expressions produces multiple results, multiple dictionaries will be produced. If the input's {"user":"stedolan","titles":["JQ Primer", "More JQ"]} then the expression {user, title: .titles[]} will produce two outputs: {"user":"stedolan", "title": "JQ Primer"} {"user":"stedolan", "title": "More JQ"} Putting parentheses around the key means it will be evaluated as an expression. With the same input as above, {(.user): .titles} produces {"stedolan": ["JQ Primer", "More JQ"]} examples: - program: '{user, title: .titles[]}' input: '{"user":"stedolan","titles":["JQ Primer", "More JQ"]}' output: - '{"user":"stedolan", "title": "JQ Primer"}' - '{"user":"stedolan", "title": "More JQ"}' - program: '{(.user): .titles}' input: '{"user":"stedolan","titles":["JQ Primer", "More JQ"]}' output: ['{"stedolan": ["JQ Primer", "More JQ"]}'] - title: Builtin operators and functions body: | Some jq operators (for instance, `+`) do different things depending on the type of their arguments (arrays, numbers, etc.). However, jq never does implicit type conversions. If you try to add a string to an object you'll get an error message and no result. entries: - title: "Addition: `+`" body: | The operator `+` takes two filters, applies them both to the same input, and adds the results together. What "adding" means depends on the types involved: - **Numbers** are added by normal arithmetic. - **Arrays** are added by being concatenated into a larger array. - **Strings** are added by being joined into a larger string. - **Objects** are added by merging, that is, inserting all the key-value pairs from both objects into a single combined object. If both objects contain a value for the same key, the object on the right of the `+` wins. (For recursive merge use the `*` operator.) `null` can be added to any value, and returns the other value unchanged. examples: - program: '.a + 1' input: '{"a": 7}' output: ['8'] - program: '.a + .b' input: '{"a": [1,2], "b": [3,4]}' output: ['[1,2,3,4]'] - program: '.a + null' input: '{"a": 1}' output: ['1'] - program: '.a + 1' input: '{}' output: ['1'] - program: '{a: 1} + {b: 2} + {c: 3} + {a: 42}' input: 'null' output: ['{"a": 42, "b": 2, "c": 3}'] - title: "Subtraction: `-`" body: | As well as normal arithmetic subtraction on numbers, the `-` operator can be used on arrays to remove all occurrences of the second array's elements from the first array. examples: - program: '4 - .a' input: '{"a":3}' output: ['1'] - program: . - ["xml", "yaml"] input: '["xml", "yaml", "json"]' output: ['["json"]'] - title: "Multiplication, division, modulo: `*`, `/`, `%`" body: | These operators only work on numbers, and do the expected. Multiplying a string by a number produces the concatenation of that string that many times. Dividing a string by another splits the first using the second as separators. Multiplying two objects will merge them recursively: this works like addition but if both objects contain a value for the same key, and the values are objects, the two are merged with the same strategy. examples: - program: '10 / . * 3' input: '5' output: ['6'] - program: '. / ", "' input: '"a, b,c,d, e"' output: ['["a","b,c,d","e"]'] - program: '{"k": {"a": 1, "b": 2}} * {"k": {"a": 0,"c": 3}}' input: 'null' output: ['{"k": {"a": 0, "b": 2, "c": 3}}'] - title: "`length`" body: | The builtin function `length` gets the length of various different types of value: - The length of a **string** is the number of Unicode codepoints it contains (which will be the same as its JSON-encoded length in bytes if it's pure ASCII). - The length of an **array** is the number of elements. - The length of an **object** is the number of key-value pairs. - The length of **null** is zero. examples: - program: '.[] | length' input: '[[1,2], "string", {"a":2}, null]' output: ['2', '6', '1', '0'] - title: "`keys`" body: | The builtin function `keys`, when given an object, returns its keys in an array. The keys are sorted "alphabetically", by unicode codepoint order. This is not an order that makes particular sense in any particular language, but you can count on it being the same for any two objects with the same set of keys, regardless of locale settings. When `keys` is given an array, it returns the valid indices for that array: the integers from 0 to length-1. examples: - program: 'keys' input: '{"abc": 1, "abcd": 2, "Foo": 3}' output: ['["Foo", "abc", "abcd"]'] - program: 'keys' input: '[42,3,35]' output: ['[0,1,2]'] - title: "`has`" body: | The builtin function `has` returns whether the input object has the given key, or the input array has an element at the given index. `has($key)` has the same effect as checking whether `$key` is a member of the array returned by `keys`, although `has` will be faster. examples: - program: 'map(has("foo"))' input: '[{"foo": 42}, {}]' output: ['[true, false]'] - program: 'map(has(2))' input: '[[0,1], ["a","b","c"]]' output: ['[false, true]'] - title: "`del`" body: | The builtin function `del` removes a key and its corresponding value from an object. examples: - program: 'del(.foo)' input: '{"foo": 42, "bar": 9001, "baz": 42}' output: ['{"bar": 9001, "baz": 42}'] - program: 'del(.[1, 2])' input: '["foo", "bar", "baz"]' output: ['["foo"]'] - title: "`to_entries`, `from_entries`, `with_entries(f)`" body: | These functions convert between an object and an array of key-value pairs. If `to_entries` is passed an object, then for each `k: v` entry in the input, the output array includes `{"key": k, "value": v}`. `from_entries` does the opposite conversion, and `with_entries(f)` is a shorthand for `to_entries | map(f) | from_entries`, useful for doing some operation to all keys and values of an object. examples: - program: 'to_entries' input: '{"a": 1, "b": 2}' output: ['[{"key":"a", "value":1}, {"key":"b", "value":2}]'] - program: 'from_entries' input: '[{"key":"a", "value":1}, {"key":"b", "value":2}]' output: ['{"a": 1, "b": 2}'] - program: 'with_entries(.key |= "KEY_" + .)' input: '{"a": 1, "b": 2}' output: ['{"KEY_a": 1, "KEY_b": 2}'] - title: "`select`" body: | The function `select(foo)` produces its input unchanged if `foo` returns true for that input, and produces no output otherwise. It's useful for filtering lists: `[1,2,3] | map(select(. >= 2))` will give you `[2,3]`. examples: - program: 'map(select(. >= 2))' input: '[1,5,3,0,7]' output: ['[5,3,7]'] - title: "`arrays`, `objects`, `iterables`, `booleans`, `numbers`, `strings`, `nulls`, `values`, `scalars`" body: | These built-ins select only inputs that are arrays, objects, iterables (arrays or objects), booleans, numbers, strings, null, non-null values, and non-iterables, respectively. examples: - program: '.[]|numbers' input: '[[],{},1,"foo",null,true,false]' output: ['1'] - title: "`empty`" body: | `empty` returns no results. None at all. Not even `null`. It's useful on occasion. You'll know if you need it :) examples: - program: '1, empty, 2' input: 'null' output: ['1', '2'] - program: '[1,2,empty,3]' input: 'null' output: ['[1,2,3]'] - title: "`map(f)`" body: | For any filter `f`, `map(f)` will run that filter for each element of the input array, and produce the outputs a new array. `map(.+1)` will increment each element of an array of numbers. `map(f)` is equivalent to `[.[] | f]`. In fact, this is how it's defined. examples: - program: 'map(.+1)' input: '[1,2,3]' output: ['[2,3,4]'] - title: "`paths`" body: | Outputs the paths to all the elements in its input (except it does not output the empty list, representing . itself). `paths` is equivalent to def paths: path(recurse(if (type|. == "array" or . == "object") then .[] else empty end))|select(length > 0); examples: - program: '[paths]' input: '[1,[[],{"a":2}]]' output: ['[[0],[1],[1,0],[1,1],[1,1,"a"]]'] - title: "`leaf_paths`" body: | Outputs the paths to all the leaves (non-array, non-object elements) in its input. examples: - program: '[leaf_paths]' input: '[1,[[],{"a":2}]]' output: ['[[0],[1,1,"a"]]'] - title: "`add`" body: | The filter `add` takes as input an array, and produces as output the elements of the array added together. This might mean summed, concatenated or merged depending on the types of the elements of the input array - the rules are the same as those for the `+` operator (described above). If the input is an empty array, `add` returns `null`. examples: - program: add input: '["a","b","c"]' output: ['"abc"'] - program: add input: '[1, 2, 3]' output: ['6'] - program: add input: '[]' output: ["null"] - title: "`any`" body: | The filter `any` takes as input an array of boolean values, and produces `true` as output if any of the elements of the array are `true`. If the input is an empty array, `any` returns `false`. examples: - program: any input: '[true, false]' output: ["true"] - program: any input: '[false, false]' output: ["false"] - program: any input: '[]' output: ["false"] - title: "`all`" body: | The filter `all` takes as input an array of boolean values, and produces `true` as output if all of the elements of the array are `true`. If the input is an empty array, `all` returns `true`. examples: - program: all input: '[true, false]' output: ["false"] - program: all input: '[true, true]' output: ["true"] - program: all input: '[]' output: ["true"] - title: "`range`" body: | The `range` function produces a range of numbers. `range(4;10)` produces 6 numbers, from 4 (inclusive) to 10 (exclusive). The numbers are produced as separate outputs. Use `[range(4;10)]` to get a range as an array. examples: - program: 'range(2;4)' input: 'null' output: ['2', '3'] - program: '[range(2;4)]' input: 'null' output: ['[2,3]'] - title: "`floor`" body: | The `floor` function returns the floor of its numeric input. examples: - program: 'floor' input: '3.14159' output: ['3'] - title: "`sqrt`" body: | The `sqrt` function returns the square root of its numeric input. examples: - program: 'sqrt' input: '9' output: ['3'] - title: "`tonumber`" body: | The `tonumber` function parses its input as a number. It will convert correctly-formatted strings to their numeric equivalent, leave numbers alone, and give an error on all other input. examples: - program: '.[] | tonumber' input: '[1, "1"]' output: ['1', '1'] - title: "`tostring`" body: | The `tostring` function prints its input as a string. Strings are left unchanged, and all other values are JSON-encoded. examples: - program: '.[] | tostring' input: '[1, "1", [1]]' output: ['"1"', '"1"', '"[1]"'] - title: "`type`" body: | The `type` function returns the type of its argument as a string, which is one of null, boolean, number, string, array or object. examples: - program: 'map(type)' input: '[0, false, [], {}, null, "hello"]' output: ['["number", "boolean", "array", "object", "null", "string"]'] - title: "`sort`, `sort_by`" body: | The `sort` functions sorts its input, which must be an array. Values are sorted in the following order: * `null` * `false` * `true` * numbers * strings, in alphabetical order (by unicode codepoint value) * arrays, in lexical order * objects The ordering for objects is a little complex: first they're compared by comparing their sets of keys (as arrays in sorted order), and if their keys are equal then the values are compared key by key. `sort_by` may be used to sort by a particular field of an object, or by applying any jq filter. `sort_by(foo)` compares two elements by comparing the result of `foo` on each element. examples: - program: 'sort' input: '[8,3,null,6]' output: ['[null,3,6,8]'] - program: 'sort_by(.foo)' input: '[{"foo":4, "bar":10}, {"foo":3, "bar":100}, {"foo":2, "bar":1}]' output: ['[{"foo":2, "bar":1}, {"foo":3, "bar":100}, {"foo":4, "bar":10}]'] - title: "`group_by`" body: | `group_by(.foo)` takes as input an array, groups the elements having the same `.foo` field into separate arrays, and produces all of these arrays as elements of a larger array, sorted by the value of the `.foo` field. Any jq expression, not just a field access, may be used in place of `.foo`. The sorting order is the same as described in the `sort` function above. examples: - program: 'group_by(.foo)' input: '[{"foo":1, "bar":10}, {"foo":3, "bar":100}, {"foo":1, "bar":1}]' output: ['[[{"foo":1, "bar":10}, {"foo":1, "bar":1}], [{"foo":3, "bar":100}]]'] - title: "`min`, `max`, `min_by`, `max_by`" body: | Find the minimum or maximum element of the input array. The `_by` versions allow you to specify a particular field or property to examine, e.g. `min_by(.foo)` finds the object with the smallest `foo` field. examples: - program: 'min' input: '[5,4,2,7]' output: ['2'] - program: 'max_by(.foo)' input: '[{"foo":1, "bar":14}, {"foo":2, "bar":3}]' output: ['{"foo":2, "bar":3}'] - title: "`unique`" body: | The `unique` function takes as input an array and produces an array of the same elements, in sorted order, with duplicates removed. examples: - program: 'unique' input: '[1,2,5,3,5,3,1,3]' output: ['[1,2,3,5]'] - title: "`unique_by`" body: | The `unique_by(.foo)` function takes as input an array and produces an array of the same elements, in sorted order, with elements with a duplicate `.foo` field removed. Think of it as making an array by taking one element out of every group produced by `group_by`. examples: - program: 'unique_by(.foo)' input: '[{"foo": 1, "bar": 2}, {"foo": 1, "bar": 3}, {"foo": 4, "bar": 5}]' output: ['[{"foo": 1, "bar": 2}, {"foo": 4, "bar": 5}]'] - program: 'unique_by(length)' input: '["chunky", "bacon", "kitten", "cicada", "asparagus"]' output: ['["bacon", "chunky", "asparagus"]'] - title: "`reverse`" body: | This function reverses an array. examples: - program: 'reverse' input: '[1,2,3,4]' output: ['[4,3,2,1]'] - title: "`contains`" body: | The filter `contains(b)` will produce true if b is completely contained within the input. A string B is contained in a string A if B is a substring of A. An array B is contained in an array A is all elements in B are contained in any element in A. An object B is contained in object A if all of the values in B are contained in the value in A with the same key. All other types are assumed to be contained in each other if they are equal. examples: - program: 'contains("bar")' input: '"foobar"' output: ['true'] - program: 'contains(["baz", "bar"])' input: '["foobar", "foobaz", "blarp"]' output: ['true'] - program: 'contains(["bazzzzz", "bar"])' input: '["foobar", "foobaz", "blarp"]' output: ['false'] - program: 'contains({foo: 12, bar: [{barp: 12}]})' input: '{"foo": 12, "bar":[1,2,{"barp":12, "blip":13}]}' output: ['true'] - program: 'contains({foo: 12, bar: [{barp: 15}]})' input: '{"foo": 12, "bar":[1,2,{"barp":12, "blip":13}]}' output: ['false'] - title: "`indices(s)`" body: | Outputs an array containing the indices in `.` where `s` occurs. The input may be an array, in which case if `s` is an array then the indices output will be those where all elements in `.` match those of `s`. examples: - program: 'indices(", ")' input: '"a,b, cd, efg, hijk"' output: ['[3,7,12]'] - program: 'indices(1)' input: '[0,1,2,1,3,1,4]' output: ['[1,3,5]'] - program: 'indices([1,2])' input: '[0,1,2,3,1,4,2,5,1,2,6,7]' output: ['[1,8]'] - title: "`index(s)`, `rindex(s)`" body: | Outputs the index of the first (`index`) or last (`rindex`) occurrence of `s` in the input. examples: - program: 'index(", ")' input: '"a,b, cd, efg, hijk"' output: ['3'] - program: 'rindex(", ")' input: '"a,b, cd, efg, hijk"' output: ['12'] - title: "`startswith`" body: | Outputs `true` if . starts with the given string argument. examples: - program: '[.[]|startswith("foo")]' input: '["fo", "foo", "barfoo", "foobar", "barfoob"]' output: ['[false, true, false, true, false]'] - title: "`endswith`" body: | Outputs `true` if . ends with the given string argument. examples: - program: '[.[]|endswith("foo")]' input: '["foobar", "barfoo"]' output: ['[false, true]'] - title: "`ltrimstr`" body: | Outputs its input with the given prefix string removed, if it starts with it. examples: - program: '[.[]|ltrimstr("foo")]' input: '["fo", "foo", "barfoo", "foobar", "afoo"]' output: ['["fo","","barfoo","bar","afoo"]'] - title: "`rtrimstr`" body: | Outputs its input with the given suffix string removed, if it starts with it. examples: - program: '[.[]|rtrimstr("foo")]' input: '["fo", "foo", "barfoo", "foobar", "foob"]' output: ['["fo","","bar","foobar","foob"]'] - title: "`explode`" body: | Converts an input string into an array of the string's codepoint numbers. examples: - program: 'explode' input: '"foobar"' output: ['[102,111,111,98,97,114]'] - title: "`implode`" body: | The inverse of explode. examples: - program: 'implode' input: '[65, 66, 67]' output: ['"ABC"'] - title: "`split`" body: | Splits an input string on the separator argument. examples: - program: 'split(", ")' input: '"a, b,c,d, e"' output: ['["a","b,c,d","e"]'] - title: "`join`" body: | Joins the array of elements given as input, using the argument as separator. It is the inverse of `split`: that is, running `split("foo") | join("foo")` over any input string returns said input string. examples: - program: 'join(", ")' input: '["a","b,c,d","e"]' output: ['"a, b,c,d, e"'] - title: "`recurse`" body: | The `recurse` function allows you to search through a recursive structure, and extract interesting data from all levels. Suppose your input represents a filesystem: {"name": "/", "children": [ {"name": "/bin", "children": [ {"name": "/bin/ls", "children": []}, {"name": "/bin/sh", "children": []}]}, {"name": "/home", "children": [ {"name": "/home/stephen", "children": [ {"name": "/home/stephen/jq", "children": []}]}]}]} Now suppose you want to extract all of the filenames present. You need to retrieve `.name`, `.children[].name`, `.children[].children[].name`, and so on. You can do this with: recurse(.children[]) | .name examples: - program: 'recurse(.foo[])' input: '{"foo":[{"foo": []}, {"foo":[{"foo":[]}]}]}' output: - '{"foo":[{"foo":[]},{"foo":[{"foo":[]}]}]}' - '{"foo":[]}' - '{"foo":[{"foo":[]}]}' - '{"foo":[]}' - title: "`recurse_down`" body: | A quieter version of `recurse(.[])`, equivalent to: def recurse_down: recurse(.[]?); - title: "`..`" body: | Short-hand for `recurse_down`. This is intended to resemble the XPath `//` operator. Note that `..a` does not work; use `..|a` instead. examples: - program: '..|.a?' input: '[[{"a":1}]]' output: ['1'] - title: "String interpolation: `\\(exp)`" body: | Inside a string, you can put an expression inside parens after a backslash. Whatever the expression returns will be interpolated into the string. examples: - program: '"The input was \(.), which is one less than \(.+1)"' input: '42' output: ['"The input was 42, which is one less than 43"'] - title: "Convert to/from JSON" body: | The `tojson` and `fromjson` builtins dump values as JSON texts or parse JSON texts into values, respectively. The tojson builtin differs from tostring in that tostring returns strings unmodified, while tojson encodes strings as JSON strings. examples: - program: '[.[]|tostring]' input: '[1, "foo", ["foo"]]' output: ['["1","foo","[\"foo\"]"]'] - program: '[.[]|tojson]' input: '[1, "foo", ["foo"]]' output: ['["1","\"foo\"","[\"foo\"]"]'] - program: '[.[]|tojson|fromjson]' input: '[1, "foo", ["foo"]]' output: ['[1,"foo",["foo"]]'] - title: "Format strings and escaping" body: | The `@foo` syntax is used to format and escape strings, which is useful for building URLs, documents in a language like HTML or XML, and so forth. `@foo` can be used as a filter on its own, the possible escapings are: * `@text`: Calls `tostring`, see that function for details. * `@json`: Serialises the input as JSON. * `@html`: Applies HTML/XML escaping, by mapping the characters `<>&'"` to their entity equivalents `<`, `>`, `&`, `'`, `"`. * `@uri`: Applies percent-encoding, by mapping all reserved URI characters to a `%xx` sequence. * `@csv`: The input must be an array, and it is rendered as CSV with double quotes for strings, and quotes escaped by repetition. * `@sh`: The input is escaped suitable for use in a command-line for a POSIX shell. If the input is an array, the output will be a series of space-separated strings. * `@base64`: The input is converted to base64 as specified by RFC 4648. This syntax can be combined with string interpolation in a useful way. You can follow a `@foo` token with a string literal. The contents of the string literal will *not* be escaped. However, all interpolations made inside that string literal will be escaped. For instance, @uri "https://www.google.com/search?q=\(.search)" will produce the following output for the input `{"search":"what is jq?"}`: "https://www.google.com/search?q=what%20is%20jq%3f" Note that the slashes, question mark, etc. in the URL are not escaped, as they were part of the string literal. examples: - program: '@html' input: '"This works if x < y"' output: ['"This works if x < y"'] - program: '@sh "echo \(.)"' input: "\"O'Hara's Ale\"" output: ["\"echo 'O'\\\\''Hara'\\\\''s Ale'\""] - title: Conditionals and Comparisons entries: - title: "`==`, `!=`" body: | The expression 'a == b' will produce 'true' if the result of a and b are equal (that is, if they represent equivalent JSON documents) and 'false' otherwise. In particular, strings are never considered equal to numbers. If you're coming from JavaScript, jq's == is like JavaScript's === - considering values equal only when they have the same type as well as the same value. != is "not equal", and 'a != b' returns the opposite value of 'a == b' examples: - program: '.[] == 1' input: '[1, 1.0, "1", "banana"]' output: ['true', 'true', 'false', 'false'] - title: if-then-else-end body: | `if A then B else C end` will act the same as `B` if `A` produces a value other than false or null, but act the same as `C` otherwise. Checking for false or null is a simpler notion of "truthiness" than is found in JavaScript or Python, but it means that you'll sometimes have to be more explicit about the condition you want: you can't test whether, e.g. a string is empty using `if .name then A else B end`, you'll need something more like `if (.name | length) > 0 then A else B end` instead. If the condition `A` produces multiple results, then `B` is evaluated once for each result that is not false or null, and `C` is evaluated once for each false or null. More cases can be added to an if using `elif A then B` syntax. examples: - program: |- if . == 0 then "zero" elif . == 1 then "one" else "many" end input: '2' output: ['"many"'] - title: "`>`, `>=`, `<=`, `<`" body: | The comparison operators `>`, `>=`, `<=`, `<` return whether their left argument is greater than, greater than or equal to, less than or equal to or less than their right argument (respectively). The ordering is the same as that described for `sort`, above. examples: - program: '. < 5' input: '2' output: ['true'] - title: "`and`, `or`, `not`" body: | jq supports the normal Boolean operators `and`, `or`, `not`. They have the same standard of truth as if expressions - `false` and `null` are considered "false values", and anything else is a "true value". If an operand of one of these operators produces multiple results, the operator itself will produce a result for each input. `not` is in fact a builtin function rather than an operator, so it is called as a filter to which things can be piped rather than with special syntax, as in `.foo and .bar | not`. These three only produce the values `true` and `false`, and so are only useful for genuine Boolean operations, rather than the common Perl/Python/Ruby idiom of "value_that_may_be_null or default". If you want to use this form of "or", picking between two values rather than evaluating a condition, see the `//` operator below. examples: - program: '42 and "a string"' input: 'null' output: ['true'] - program: '(true, false) or false' input: 'null' output: ['true', 'false'] - program: '(true, true) and (true, false)' input: 'null' output: ['true', 'false', 'true', 'false'] - program: '[true, false | not]' input: 'null' output: ['[false, true]'] - title: "Alternative operator: `//`" body: | A filter of the form `a // b` produces the same results as `a`, if `a` produces results other than `false` and `null`. Otherwise, `a // b` produces the same results as `b`. This is useful for providing defaults: `.foo // 1` will evaluate to `1` if there's no `.foo` element in the input. It's similar to how `or` is sometimes used in Python (jq's `or` operator is reserved for strictly Boolean operations). examples: - program: '.foo // 42' input: '{"foo": 19}' output: ['19'] - program: '.foo // 42' input: '{}' output: ['42'] - title: Advanced features body: | Variables are an absolute necessity in most programming languages, but they're relegated to an "advanced feature" in jq. In most languages, variables are the only means of passing around data. If you calculate a value, and you want to use it more than once, you'll need to store it in a variable. To pass a value to another part of the program, you'll need that part of the program to define a variable (as a function parameter, object member, or whatever) in which to place the data. It is also possible to define functions in jq, although this is is a feature whose biggest use is defining jq's standard library (many jq functions such as `map` and `select` are in fact written in jq). Finally, jq has a `reduce` operation, which is very powerful but a bit tricky. Again, it's mostly used internally, to define some useful bits of jq's standard library. entries: - title: Variables body: | In jq, all filters have an input and an output, so manual plumbing is not necessary to pass a value from one part of a program to the next. Many expressions, for instance `a + b`, pass their input to two distinct subexpressions (here `a` and `b` are both passed the same input), so variables aren't usually necessary in order to use a value twice. For instance, calculating the average value of an array of numbers requires a few variables in most languages - at least one to hold the array, perhaps one for each element or for a loop counter. In jq, it's simply `add / length` - the `add` expression is given the array and produces its sum, and the `length` expression is given the array and produces its length. So, there's generally a cleaner way to solve most problems in jq than defining variables. Still, sometimes they do make things easier, so jq lets you define variables using `expression as $variable`. All variable names start with `$`. Here's a slightly uglier version of the array-averaging example: length as $array_length | add / $array_length We'll need a more complicated problem to find a situation where using variables actually makes our lives easier. Suppose we have an array of blog posts, with "author" and "title" fields, and another object which is used to map author usernames to real names. Our input looks like: {"posts": [{"title": "First post", "author": "anon"}, {"title": "A well-written article", "author": "person1"}], "realnames": {"anon": "Anonymous Coward", "person1": "Person McPherson"}} We want to produce the posts with the author field containing a real name, as in: {"title": "First post", "author": "Anonymous Coward"} {"title": "A well-written article", "author": "Person McPherson"} We use a variable, $names, to store the realnames object, so that we can refer to it later when looking up author usernames: .realnames as $names | .posts[] | {title, author: $names[.author]} The expression `exp as $x | ...` means: for each value of expression `exp`, run the rest of the pipeline with the entire original input, and with `$x` set to that value. Thus `as` functions as something of a foreach loop. Variables are scoped over the rest of the expression that defines them, so .realnames as $names | (.posts[] | {title, author: $names[.author]}) will work, but (.realnames as $names | .posts[]) | {title, author: $names[.author]} won't. examples: - program: '.bar as $x | .foo | . + $x' input: '{"foo":10, "bar":200}' output: ['210'] - title: 'Defining Functions' body: | You can give a filter a name using "def" syntax: def increment: . + 1; From then on, `increment` is usable as a filter just like a builtin function (in fact, this is how some of the builtins are defined). A function may take arguments: def map(f): [.[] | f]; Arguments are passed as filters, not as values. The same argument may be referenced multiple times with different inputs (here `f` is run for each element of the input array). Arguments to a function work more like callbacks than like value arguments. If you want the value-argument behaviour for defining simple functions, you can just use a variable: def addvalue(f): f as $value | map(. + $value); With that definition, `addvalue(.foo)` will add the current input's `.foo` field to each element of the array. examples: - program: 'def addvalue(f): . + [f]; map(addvalue(.[0]))' input: '[[1,2],[10,20]]' output: ['[[1,2,1], [10,20,10]]'] - program: 'def addvalue(f): f as $x | map(. + $x); addvalue(.[0])' input: '[[1,2],[10,20]]' output: ['[[1,2,1,2], [10,20,1,2]]'] - title: "`reduce`" body: | The `reduce` syntax allows you to combine all of the results of an expression by accumulating them into a single answer. The form is `reduce EXP as $var (INIT; UPDATE)`. As an example, we'll pass `[1,2,3]` to this expression: reduce .[] as $item (0; . + $item) For each result that `.[]` produces, `. + $item` is run to accumulate a running total, starting from 0 as the input value. In this example, `.[]` produces the results `1`, `2`, and `3`, so the effect is similar to running something like this: 0 | 1 as $item | . + $item | 2 as $item | . + $item | 3 as $item | . + $item examples: - program: 'reduce .[] as $item (0; . + $item)' input: '[1,2,3,4,5]' output: ['15'] - title: Assignment body: | Assignment works a little differently in jq than in most programming languages. jq doesn't distinguish between references to and copies of something - two objects or arrays are either equal or not equal, without any further notion of being "the same object" or "not the same object". If an object has two fields which are arrays, `.foo` and `.bar`, and you append something to `.foo`, then `.bar` will not get bigger. Even if you've just set `.bar = .foo`. If you're used to programming in languages like Python, Java, Ruby, JavaScript, etc. then you can think of it as though jq does a full deep copy of every object before it does the assignment (for performance, it doesn't actually do that, but that's the general idea). entries: - title: "`=`" body: | The filter `.foo = 1` will take as input an object and produce as output an object with the "foo" field set to 1. There is no notion of "modifying" or "changing" something in jq - all jq values are immutable. For instance, .foo = .bar | .foo.baz = 1 will not have the side-effect of setting .bar.baz to be set to 1, as the similar-looking program in JavaScript, Python, Ruby or other languages would. Unlike these languages (but like Haskell and some other functional languages), there is no notion of two arrays or objects being "the same array" or "the same object". They can be equal, or not equal, but if we change one of them in no circumstances will the other change behind our backs. This means that it's impossible to build circular values in jq (such as an array whose first element is itself). This is quite intentional, and ensures that anything a jq program can produce can be represented in JSON. - title: "`|=`" body: | As well as the assignment operator '=', jq provides the "update" operator '|=', which takes a filter on the right-hand side and works out the new value for the property being assigned to by running the old value through this expression. For instance, .foo |= .+1 will build an object with the "foo" field set to the input's "foo" plus 1. This example should show the difference between '=' and '|=': Provide input '{"a": {"b": 10}, "b": 20}' to the programs: .a = .b .a |= .b The former will set the "a" field of the input to the "b" field of the input, and produce the output {"a": 20}. The latter will set the "a" field of the input to the "a" field's "b" field, producing {"a": 10}. - title: "`+=`, `-=`, `*=`, `/=`, `%=`, `//=`" body: | jq has a few operators of the form `a op= b`, which are all equivalent to `a |= . op b`. So, `+= 1` can be used to increment values. examples: - program: .foo += 1 input: '{"foo": 42}' output: ['{"foo": 43}'] - title: Complex assignments body: | Lots more things are allowed on the left-hand side of a jq assignment than in most languages. We've already seen simple field accesses on the left hand side, and it's no surprise that array accesses work just as well: .posts[0].title = "JQ Manual" What may come as a surprise is that the expression on the left may produce multiple results, referring to different points in the input document: .posts[].comments |= . + ["this is great"] That example appends the string "this is great" to the "comments" array of each post in the input (where the input is an object with a field "posts" which is an array of posts). When jq encounters an assignment like 'a = b', it records the "path" taken to select a part of the input document while executing a. This path is then used to find which part of the input to change while executing the assignment. Any filter may be used on the left-hand side of an equals - whichever paths it selects from the input will be where the assignment is performed. This is a very powerful operation. Suppose we wanted to add a comment to blog posts, using the same "blog" input above. This time, we only want to comment on the posts written by "stedolan". We can find those posts using the "select" function described earlier: .posts[] | select(.author == "stedolan") The paths provided by this operation point to each of the posts that "stedolan" wrote, and we can comment on each of them in the same way that we did before: (.posts[] | select(.author == "stedolan") | .comments) |= . + ["terrible."] ================================================ FILE: docs/content/manual/v1.5/manual.yml ================================================ --- headline: jq 1.5 Manual body: | A jq program is a "filter": it takes an input, and produces an output. There are a lot of builtin filters for extracting a particular field of an object, or converting a number to a string, or various other standard tasks. Filters can be combined in various ways - you can pipe the output of one filter into another filter, or collect the output of a filter into an array. Some filters produce multiple results, for instance there's one that produces all the elements of its input array. Piping that filter into a second runs the second filter for each element of the array. Generally, things that would be done with loops and iteration in other languages are just done by gluing filters together in jq. It's important to remember that every filter has an input and an output. Even literals like "hello" or 42 are filters - they take an input but always produce the same literal as output. Operations that combine two filters, like addition, generally feed the same input to both and combine the results. So, you can implement an averaging filter as `add / length` - feeding the input array both to the `add` filter and the `length` filter and then performing the division. But that's getting ahead of ourselves. :) Let's start with something simpler: manpage_intro: | jq(1) -- Command-line JSON processor ==================================== ## SYNOPSIS `jq` [...] [...] `jq` can transform JSON in various ways, by selecting, iterating, reducing and otherwise mangling JSON documents. For instance, running the command `jq 'map(.price) | add'` will take an array of JSON objects as input and return the sum of their "price" fields. `jq` can accept text input as well, but by default, `jq` reads a stream of JSON entities (including numbers and other literals) from `stdin`. Whitespace is only needed to separate entities such as 1 and 2, and true and false. One or more may be specified, in which case `jq` will read input from those instead. The are described in the [INVOKING JQ] section; they mostly concern input and output formatting. The is written in the jq language and specifies how to transform the input file or document. ## FILTERS manpage_epilogue: | ## BUGS Presumably. Report them or discuss them at: https://github.com/jqlang/jq/issues ## AUTHOR Stephen Dolan `` sections: - title: Invoking jq body: | jq filters run on a stream of JSON data. The input to jq is parsed as a sequence of whitespace-separated JSON values which are passed through the provided filter one at a time. The output(s) of the filter are written to standard output, as a sequence of newline-separated JSON data. Note: it is important to mind the shell's quoting rules. As a general rule it's best to always quote (with single-quote characters) the jq program, as too many characters with special meaning to jq are also shell meta-characters. For example, `jq "foo"` will fail on most Unix shells because that will be the same as `jq foo`, which will generally fail because `foo is not defined`. When using the Windows command shell (cmd.exe) it's best to use double quotes around your jq program when given on the command-line (instead of the `-f program-file` option), but then double-quotes in the jq program need backslash escaping. You can affect how jq reads and writes its input and output using some command-line options: * `--null-input` / `-n`: Don't read any input at all. Instead, the filter is run once using `null` as the input. This is useful when using jq as a simple calculator or to construct JSON data from scratch. * `--raw-input` / `-R`: Don't parse the input as JSON. Instead, each line of text is passed to the filter as a string. If combined with `--slurp`, then the entire input is passed to the filter as a single long string. * `--slurp` / `-s`: Instead of running the filter for each JSON object in the input, read the entire input stream into a large array and run the filter just once. * `--compact-output` / `-c`: By default, jq pretty-prints JSON output. Using this option will result in more compact output by instead putting each JSON object on a single line. * `--raw-output` / `-r`: With this option, if the filter's result is a string then it will be written directly to standard output rather than being formatted as a JSON string with quotes. This can be useful for making jq filters talk to non-JSON-based systems. * `--join-output` / `-j`: Like `-r` but jq won't print a newline after each output. * `--ascii-output` / `-a`: jq usually outputs non-ASCII Unicode codepoints as UTF-8, even if the input specified them as escape sequences (like "\u03bc"). Using this option, you can force jq to produce pure ASCII output with every non-ASCII character replaced with the equivalent escape sequence. * `--sort-keys` / `-S`: Output the fields of each object with the keys in sorted order. * `--color-output` / `-C` and `--monochrome-output` / `-M`: By default, jq outputs colored JSON if writing to a terminal. You can force it to produce color even if writing to a pipe or a file using `-C`, and disable color with `-M`. * `--tab`: Use a tab for each indentation level instead of two spaces. * `--indent n`: Use the given number of spaces (no more than 7) for indentation. * `--unbuffered`: Flush the output after each JSON object is printed (useful if you're piping a slow data source into jq and piping jq's output elsewhere). * `--stream`: Parse the input in streaming fashion, outputting arrays of path and leaf values (scalars and empty arrays or empty objects). For example, `"a"` becomes `[[],"a"]`, and `[[],"a",["b"]]` becomes `[[0],[]]`, `[[1],"a"]`, and `[[2,0],"b"]`. This is useful for processing very large inputs. Use this in conjunction with filtering and the `reduce` and `foreach` syntax to reduce large inputs incrementally. * `--seq`: Use the `application/json-seq` MIME type scheme for separating JSON texts in jq's input and output. This means that an ASCII RS (record separator) character is printed before each value on output and an ASCII LF (line feed) is printed after every output. Input JSON texts that fail to parse are ignored (but warned about), discarding all subsequent input until the next RS. This mode also parses the output of jq without the `--seq` option. * `-f filename` / `--from-file filename`: Read filter from the file rather than from a command line, like awk's -f option. You can also use '#' to make comments. * `-L directory`: Prepend `directory` to the search list for modules. If this option is used then no builtin search list is used. See the section on modules below. * `--arg name value`: This option passes a value to the jq program as a predefined variable. If you run jq with `--arg foo bar`, then `$foo` is available in the program and has the value `"bar"`. Note that `value` will be treated as a string, so `--arg foo 123` will bind `$foo` to `"123"`. * `--argjson name JSON-text`: This option passes a JSON-encoded value to the jq program as a predefined variable. If you run jq with `--argjson foo 123`, then `$foo` is available in the program and has the value `123`. * `--slurpfile variable-name filename`: This option reads all the JSON texts in the named file and binds an array of the parsed JSON values to the given global variable. If you run jq with `--slurpfile foo bar`, then `$foo` is available in the program and has an array whose elements correspond to the texts in the file named `bar`. * `--argfile variable-name filename`: Do not use. Use `--slurpfile` instead. (This option is like `--slurpfile`, but when the file has just one text, then that is used, else an array of texts is used as in `--slurpfile`.) * `--exit-status` / `-e`: Sets the exit status of jq to 0 if the last output value was neither `false` nor `null`, 1 if the last output value was either `false` or `null`, or 4 if no valid result was ever produced. Normally jq exits with 2 if there was any usage problem or system error, 3 if there was a jq program compile error, or 0 if the jq program ran. * `--version` / `-V`: Output the jq version and exit with zero. * `--help` / `-h`: Output the jq help and exit with zero. * `--run-tests [filename]`: Runs the tests in the given file or standard input. This must be the last option given and does not honor all preceding options. The input consists of comment lines, empty lines, and program lines followed by one input line, as many lines of output as are expected (one per output), and a terminating empty line. Compilation failure tests start with a line containing only `%%FAIL`, then a line containing the program to compile, then a line containing an error message to compare to the actual. Be warned that this option can change backwards-incompatibly. - title: Basic filters entries: - title: "`.`" body: | The absolute simplest (and least interesting) filter is `.`. This is a filter that takes its input and produces it unchanged as output. Since jq by default pretty-prints all output, this trivial program can be a useful way of formatting JSON output from, say, `curl`. examples: - program: '.' input: '"Hello, world!"' output: ['"Hello, world!"'] - title: "`.foo`, `.foo.bar`" body: | The simplest *useful* filter is `.foo`. When given a JSON object (aka dictionary or hash) as input, it produces the value at the key "foo", or null if there's none present. If the key contains special characters or starts with a digit, you need to surround it with double quotes like this: `."foo$"`. A filter of the form `.foo.bar` is equivalent to `.foo|.bar`. examples: - program: '.foo' input: '{"foo": 42, "bar": "less interesting data"}' output: ['42'] - program: '.foo' input: '{"notfoo": true, "alsonotfoo": false}' output: ['null'] - program: '.["foo"]' input: '{"foo": 42}' output: ['42'] - title: "`.foo?`" body: | Just like `.foo`, but does not output an error when `.` is not an object. examples: - program: '.foo?' input: '{"foo": 42, "bar": "less interesting data"}' output: ['42'] - program: '.foo?' input: '{"notfoo": true, "alsonotfoo": false}' output: ['null'] - program: '.["foo"]?' input: '{"foo": 42}' output: ['42'] - program: '[.foo?]' input: '[1,2]' output: ['[]'] - title: "`.[]`, `.[]`, `.[:]`" body: | You can also look up fields of an object using syntax like `.["foo"]` (`.foo` above is a shorthand version of this). This one works for arrays as well, if the key is an integer. Arrays are zero-based, so `.[2]` returns the third element of the array. The `.[10:15]` syntax can be used to return a subarray of an array or substring of a string. The array returned by `.[10:15]` will be of length 5, containing the elements from index 10 (inclusive) to index 15 (exclusive). Either index may be negative (in which case it counts backwards from the end of the array), or omitted (in which case it refers to the start or end of the array). Indices are zero-based. The `.[2]` syntax can be used to return the element at the given index. Negative indices are allowed, with -1 referring to the last element, -2 referring to the next to last element, and so on. The `.foo` syntax only works for simple keys i.e. keys that are all alphanumeric characters. `.[]` works with keys that contain special characters such as colons and dots. For example `.["foo::bar"]` and `.["foo.bar"]` work while `.foo::bar` and `.foo.bar` would not. The `?` "operator" can also be used with the slice operator, as in `.[10:15]?`, which outputs values where the inputs are slice-able. examples: - program: '.[0]' input: '[{"name":"JSON", "good":true}, {"name":"XML", "good":false}]' output: ['{"name":"JSON", "good":true}'] - program: '.[2]' input: '[{"name":"JSON", "good":true}, {"name":"XML", "good":false}]' output: ['null'] - program: '.[2:4]' input: '["a","b","c","d","e"]' output: ['["c", "d"]'] - program: '.[2:4]' input: '"abcdefghi"' output: ['"cd"'] - program: '.[:3]' input: '["a","b","c","d","e"]' output: ['["a", "b", "c"]'] - program: '.[-2:]' input: '["a","b","c","d","e"]' output: ['["d", "e"]'] - program: '.[-2]' input: '[1,2,3]' output: ['2'] - title: "`.[]`" body: | If you use the `.[index]` syntax, but omit the index entirely, it will return *all* of the elements of an array. Running `.[]` with the input `[1,2,3]` will produce the numbers as three separate results, rather than as a single array. A filter of the form `.foo[]` is equivalent to `.foo | .[]`. You can also use this on an object, and it will return all the values of the object. examples: - program: '.[]' input: '[{"name":"JSON", "good":true}, {"name":"XML", "good":false}]' output: - '{"name":"JSON", "good":true}' - '{"name":"XML", "good":false}' - program: '.[]' input: '[]' output: [] - program: '.foo[]' input: '{"foo":[1,2,3]}' output: ['1','2','3'] - program: '.[]' input: '{"a": 1, "b": 1}' output: ['1', '1'] - title: "`.[]?`" body: | Like `.[]`, but no errors will be output if . is not an array or object. A filter of the form `.foo[]?` is equivalent to `.foo | .[]?`. - title: "`,`" body: | If two filters are separated by a comma, then the input will be fed into both and there will be multiple outputs: first, all of the outputs produced by the left expression, and then all of the outputs produced by the right. For instance, filter `.foo, .bar`, produces both the "foo" fields and "bar" fields as separate outputs. examples: - program: '.foo, .bar' input: '{"foo": 42, "bar": "something else", "baz": true}' output: ['42', '"something else"'] - program: ".user, .projects[]" input: '{"user":"stedolan", "projects": ["jq", "wikiflow"]}' output: ['"stedolan"', '"jq"', '"wikiflow"'] - program: '.[4,2]' input: '["a","b","c","d","e"]' output: ['"e"', '"c"'] - title: "`|`" body: | The | operator combines two filters by feeding the output(s) of the one on the left into the input of the one on the right. It's pretty much the same as the Unix shell's pipe, if you're used to that. If the one on the left produces multiple results, the one on the right will be run for each of those results. So, the expression `.[] | .foo` retrieves the "foo" field of each element of the input array. examples: - program: '.[] | .name' input: '[{"name":"JSON", "good":true}, {"name":"XML", "good":false}]' output: ['"JSON"', '"XML"'] - title: Types and Values body: | jq supports the same set of datatypes as JSON - numbers, strings, booleans, arrays, objects (which in JSON-speak are hashes with only string keys), and "null". Booleans, null, strings and numbers are written the same way as in JSON. Just like everything else in jq, these simple values take an input and produce an output - `42` is a valid jq expression that takes an input, ignores it, and returns 42 instead. entries: - title: "Array construction: `[]`" body: | As in JSON, `[]` is used to construct arrays, as in `[1,2,3]`. The elements of the arrays can be any jq expression. All of the results produced by all of the expressions are collected into one big array. You can use it to construct an array out of a known quantity of values (as in `[.foo, .bar, .baz]`) or to "collect" all the results of a filter into an array (as in `[.items[].name]`) Once you understand the "," operator, you can look at jq's array syntax in a different light: the expression `[1,2,3]` is not using a built-in syntax for comma-separated arrays, but is instead applying the `[]` operator (collect results) to the expression 1,2,3 (which produces three different results). If you have a filter `X` that produces four results, then the expression `[X]` will produce a single result, an array of four elements. examples: - program: "[.user, .projects[]]" input: '{"user":"stedolan", "projects": ["jq", "wikiflow"]}' output: ['["stedolan", "jq", "wikiflow"]'] - title: "Objects: `{}`" body: | Like JSON, `{}` is for constructing objects (aka dictionaries or hashes), as in: `{"a": 42, "b": 17}`. If the keys are "sensible" (all alphabetic characters), then the quotes can be left off. The value can be any expression (although you may need to wrap it in parentheses if it's a complicated one), which gets applied to the {} expression's input (remember, all filters have an input and an output). {foo: .bar} will produce the JSON object `{"foo": 42}` if given the JSON object `{"bar":42, "baz":43}`. You can use this to select particular fields of an object: if the input is an object with "user", "title", "id", and "content" fields and you just want "user" and "title", you can write {user: .user, title: .title} Because that's so common, there's a shortcut syntax: `{user, title}`. If one of the expressions produces multiple results, multiple dictionaries will be produced. If the input's {"user":"stedolan","titles":["JQ Primer", "More JQ"]} then the expression {user, title: .titles[]} will produce two outputs: {"user":"stedolan", "title": "JQ Primer"} {"user":"stedolan", "title": "More JQ"} Putting parentheses around the key means it will be evaluated as an expression. With the same input as above, {(.user): .titles} produces {"stedolan": ["JQ Primer", "More JQ"]} examples: - program: '{user, title: .titles[]}' input: '{"user":"stedolan","titles":["JQ Primer", "More JQ"]}' output: - '{"user":"stedolan", "title": "JQ Primer"}' - '{"user":"stedolan", "title": "More JQ"}' - program: '{(.user): .titles}' input: '{"user":"stedolan","titles":["JQ Primer", "More JQ"]}' output: ['{"stedolan": ["JQ Primer", "More JQ"]}'] - title: Builtin operators and functions body: | Some jq operators (for instance, `+`) do different things depending on the type of their arguments (arrays, numbers, etc.). However, jq never does implicit type conversions. If you try to add a string to an object you'll get an error message and no result. entries: - title: "Addition: `+`" body: | The operator `+` takes two filters, applies them both to the same input, and adds the results together. What "adding" means depends on the types involved: - **Numbers** are added by normal arithmetic. - **Arrays** are added by being concatenated into a larger array. - **Strings** are added by being joined into a larger string. - **Objects** are added by merging, that is, inserting all the key-value pairs from both objects into a single combined object. If both objects contain a value for the same key, the object on the right of the `+` wins. (For recursive merge use the `*` operator.) `null` can be added to any value, and returns the other value unchanged. examples: - program: '.a + 1' input: '{"a": 7}' output: ['8'] - program: '.a + .b' input: '{"a": [1,2], "b": [3,4]}' output: ['[1,2,3,4]'] - program: '.a + null' input: '{"a": 1}' output: ['1'] - program: '.a + 1' input: '{}' output: ['1'] - program: '{a: 1} + {b: 2} + {c: 3} + {a: 42}' input: 'null' output: ['{"a": 42, "b": 2, "c": 3}'] - title: "Subtraction: `-`" body: | As well as normal arithmetic subtraction on numbers, the `-` operator can be used on arrays to remove all occurrences of the second array's elements from the first array. examples: - program: '4 - .a' input: '{"a":3}' output: ['1'] - program: . - ["xml", "yaml"] input: '["xml", "yaml", "json"]' output: ['["json"]'] - title: "Multiplication, division, modulo: `*`, `/`, `%`" body: | These infix operators behave as expected when given two numbers. Division by zero raises an error. `x % y` computes x modulo y. Multiplying a string by a number produces the concatenation of that string that many times. `"x" * 0` produces **null**. Dividing a string by another splits the first using the second as separators. Multiplying two objects will merge them recursively: this works like addition but if both objects contain a value for the same key, and the values are objects, the two are merged with the same strategy. examples: - program: '10 / . * 3' input: '5' output: ['6'] - program: '. / ", "' input: '"a, b,c,d, e"' output: ['["a","b,c,d","e"]'] - program: '{"k": {"a": 1, "b": 2}} * {"k": {"a": 0,"c": 3}}' input: 'null' output: ['{"k": {"a": 0, "b": 2, "c": 3}}'] - program: '.[] | (1 / .)?' input: '[1,0,-1]' output: ['1', '-1'] - title: "`length`" body: | The builtin function `length` gets the length of various different types of value: - The length of a **string** is the number of Unicode codepoints it contains (which will be the same as its JSON-encoded length in bytes if it's pure ASCII). - The length of an **array** is the number of elements. - The length of an **object** is the number of key-value pairs. - The length of **null** is zero. examples: - program: '.[] | length' input: '[[1,2], "string", {"a":2}, null]' output: ['2', '6', '1', '0'] - title: "`keys`, `keys_unsorted`" body: | The builtin function `keys`, when given an object, returns its keys in an array. The keys are sorted "alphabetically", by unicode codepoint order. This is not an order that makes particular sense in any particular language, but you can count on it being the same for any two objects with the same set of keys, regardless of locale settings. When `keys` is given an array, it returns the valid indices for that array: the integers from 0 to length-1. The `keys_unsorted` function is just like `keys`, but if the input is an object then the keys will not be sorted, instead the keys will roughly be in insertion order. examples: - program: 'keys' input: '{"abc": 1, "abcd": 2, "Foo": 3}' output: ['["Foo", "abc", "abcd"]'] - program: 'keys' input: '[42,3,35]' output: ['[0,1,2]'] - title: "`has(key)`" body: | The builtin function `has` returns whether the input object has the given key, or the input array has an element at the given index. `has($key)` has the same effect as checking whether `$key` is a member of the array returned by `keys`, although `has` will be faster. examples: - program: 'map(has("foo"))' input: '[{"foo": 42}, {}]' output: ['[true, false]'] - program: 'map(has(2))' input: '[[0,1], ["a","b","c"]]' output: ['[false, true]'] - title: "`in`" body: | The builtin function `in` returns whether or not the input key is in the given object, or the input index corresponds to an element in the given array. It is, essentially, an inversed version of `has`. examples: - program: '.[] | in({"foo": 42})' input: '["foo", "bar"]' output: ['true', 'false'] - program: 'map(in([0,1]))' input: '[2, 0]' output: ['[false, true]'] - title: "`path(path_expression)`" body: | Outputs array representations of the given path expression in `.`. The outputs are arrays of strings (object keys) and/or numbers (array indices). Path expressions are jq expressions like `.a`, but also `.[]`. There are two types of path expressions: ones that can match exactly, and ones that cannot. For example, `.a.b.c` is an exact match path expression, while `.a[].b` is not. `path(exact_path_expression)` will produce the array representation of the path expression even if it does not exist in `.`, if `.` is `null` or an array or an object. `path(pattern)` will produce array representations of the paths matching `pattern` if the paths exist in `.`. Note that the path expressions are not different from normal expressions. The expression `path(..|select(type=="boolean"))` outputs all the paths to boolean values in `.`, and only those paths. examples: - program: 'path(.a[0].b)' input: 'null' output: ['["a",0,"b"]'] - program: '[path(..)]' input: '{"a":[{"b":1}]}' output: ['[[],["a"],["a",0],["a",0,"b"]]'] - title: "`del(path_expression)`" body: | The builtin function `del` removes a key and its corresponding value from an object. examples: - program: 'del(.foo)' input: '{"foo": 42, "bar": 9001, "baz": 42}' output: ['{"bar": 9001, "baz": 42}'] - program: 'del(.[1, 2])' input: '["foo", "bar", "baz"]' output: ['["foo"]'] - title: "`to_entries`, `from_entries`, `with_entries(f)`" body: | These functions convert between an object and an array of key-value pairs. If `to_entries` is passed an object, then for each `k: v` entry in the input, the output array includes `{"key": k, "value": v}`. `from_entries` does the opposite conversion, and `with_entries(f)` is a shorthand for `to_entries | map(f) | from_entries`, useful for doing some operation to all keys and values of an object. `from_entries` accepts `"key"`, `"Key"`, `"Name"`, `"value"`, and `"Value"` as keys. examples: - program: 'to_entries' input: '{"a": 1, "b": 2}' output: ['[{"key":"a", "value":1}, {"key":"b", "value":2}]'] - program: 'from_entries' input: '[{"key":"a", "value":1}, {"key":"b", "value":2}]' output: ['{"a": 1, "b": 2}'] - program: 'with_entries(.key |= "KEY_" + .)' input: '{"a": 1, "b": 2}' output: ['{"KEY_a": 1, "KEY_b": 2}'] - title: "`select(boolean_expression)`" body: | The function `select(f)` produces its input unchanged if `f` returns true for that input, and produces no output otherwise. It's useful for filtering lists: `[1,2,3] | map(select(. >= 2))` will give you `[2,3]`. examples: - program: 'map(select(. >= 2))' input: '[1,5,3,0,7]' output: ['[5,3,7]'] - program: '.[] | select(.id == "second")' input: '[{"id": "first", "val": 1}, {"id": "second", "val": 2}]' output: ['{"id": "second", "val": 2}'] - title: "`arrays`, `objects`, `iterables`, `booleans`, `numbers`, `normals`, `finites`, `strings`, `nulls`, `values`, `scalars`" body: | These built-ins select only inputs that are arrays, objects, iterables (arrays or objects), booleans, numbers, normal numbers, finite numbers, strings, null, non-null values, and non-iterables, respectively. examples: - program: '.[]|numbers' input: '[[],{},1,"foo",null,true,false]' output: ['1'] - title: "`empty`" body: | `empty` returns no results. None at all. Not even `null`. It's useful on occasion. You'll know if you need it :) examples: - program: '1, empty, 2' input: 'null' output: ['1', '2'] - program: '[1,2,empty,3]' input: 'null' output: ['[1,2,3]'] - title: "`error`, `error(message)`" body: | Produces an error with the input value, or with the message given as the argument. Errors can be caught with try/catch; see below. When the error value is `null`, it produces nothing and works just like `empty`. So `[null | error]` and `[error(null)]` both emit `[]`. examples: - program: 'try error catch .' input: '"error message"' output: ['"error message"'] - program: 'try error("invalid value: \(.)") catch .' input: '42' output: ['"invalid value: 42"'] - title: "`$__loc__`" body: | Produces an object with a "file" key and a "line" key, with the filename and line number where `$__loc__` occurs, as values. examples: - program: 'try error("\($__loc__)") catch .' input: 'null' output: ['"{\"file\":\"\",\"line\":1}"'] - title: "`map(f)`, `map_values(f)`" body: | For any filter `f`, `map(f)` will run that filter for each element of the input array, and return the outputs in a new array. `map(.+1)` will increment each element of an array of numbers. Similarly, `map_values(f)` will run that filter for each element, but it will return an object when an object is passed. `map(f)` is equivalent to `[.[] | f]`. In fact, this is how it's defined. Similarly, `map_values(f)` is defined as `.[] |= f`. examples: - program: 'map(.+1)' input: '[1,2,3]' output: ['[2,3,4]'] - program: 'map_values(.+1)' input: '{"a": 1, "b": 2, "c": 3}' output: ['{"a": 2, "b": 3, "c": 4}'] - title: "`paths`, `paths(node_filter)`, `leaf_paths`" body: | `paths` outputs the paths to all the elements in its input (except it does not output the empty list, representing . itself). `paths(f)` outputs the paths to any values for which `f` is `true`. That is, `paths(type == "number")` outputs the paths to all numeric values. `leaf_paths` is an alias of `paths(scalars)`; `leaf_paths` is *deprecated* and will be removed in the next major release. examples: - program: '[paths]' input: '[1,[[],{"a":2}]]' output: ['[[0],[1],[1,0],[1,1],[1,1,"a"]]'] - program: '[paths(type == "number")]' input: '[1,[[],{"a":2}]]' output: ['[[0],[1,1,"a"]]'] - title: "`add`" body: | The filter `add` takes as input an array, and produces as output the elements of the array added together. This might mean summed, concatenated or merged depending on the types of the elements of the input array - the rules are the same as those for the `+` operator (described above). If the input is an empty array, `add` returns `null`. examples: - program: add input: '["a","b","c"]' output: ['"abc"'] - program: add input: '[1, 2, 3]' output: ['6'] - program: add input: '[]' output: ["null"] - title: "`any`, `any(condition)`, `any(generator; condition)`" body: | The filter `any` takes as input an array of boolean values, and produces `true` as output if any of the elements of the array are `true`. If the input is an empty array, `any` returns `false`. The `any(condition)` form applies the given condition to the elements of the input array. The `any(generator; condition)` form applies the given condition to all the outputs of the given generator. examples: - program: any input: '[true, false]' output: ["true"] - program: any input: '[false, false]' output: ["false"] - program: any input: '[]' output: ["false"] - title: "`all`, `all(condition)`, `all(generator; condition)`" body: | The filter `all` takes as input an array of boolean values, and produces `true` as output if all of the elements of the array are `true`. The `all(condition)` form applies the given condition to the elements of the input array. The `all(generator; condition)` form applies the given condition to all the outputs of the given generator. If the input is an empty array, `all` returns `true`. examples: - program: all input: '[true, false]' output: ["false"] - program: all input: '[true, true]' output: ["true"] - program: all input: '[]' output: ["true"] - title: "`flatten`, `flatten(depth)`" body: | The filter `flatten` takes as input an array of nested arrays, and produces a flat array in which all arrays inside the original array have been recursively replaced by their values. You can pass an argument to it to specify how many levels of nesting to flatten. `flatten(2)` is like `flatten`, but going only up to two levels deep. examples: - program: flatten input: '[1, [2], [[3]]]' output: ["[1, 2, 3]"] - program: flatten(1) input: '[1, [2], [[3]]]' output: ["[1, 2, [3]]"] - program: flatten input: '[[]]' output: ["[]"] - program: flatten input: '[{"foo": "bar"}, [{"foo": "baz"}]]' output: ['[{"foo": "bar"}, {"foo": "baz"}]'] - title: "`range(upto)`, `range(from; upto)`, `range(from; upto; by)`" body: | The `range` function produces a range of numbers. `range(4; 10)` produces 6 numbers, from 4 (inclusive) to 10 (exclusive). The numbers are produced as separate outputs. Use `[range(4; 10)]` to get a range as an array. The one argument form generates numbers from 0 to the given number, with an increment of 1. The two argument form generates numbers from `from` to `upto` with an increment of 1. The three argument form generates numbers `from` to `upto` with an increment of `by`. examples: - program: 'range(2; 4)' input: 'null' output: ['2', '3'] - program: '[range(2; 4)]' input: 'null' output: ['[2,3]'] - program: '[range(4)]' input: 'null' output: ['[0,1,2,3]'] - program: '[range(0; 10; 3)]' input: 'null' output: ['[0,3,6,9]'] - program: '[range(0; 10; -1)]' input: 'null' output: ['[]'] - program: '[range(0; -5; -1)]' input: 'null' output: ['[0,-1,-2,-3,-4]'] - title: "`floor`" body: | The `floor` function returns the floor of its numeric input. examples: - program: 'floor' input: '3.14159' output: ['3'] - title: "`sqrt`" body: | The `sqrt` function returns the square root of its numeric input. examples: - program: 'sqrt' input: '9' output: ['3'] - title: "`tonumber`" body: | The `tonumber` function parses its input as a number. It will convert correctly-formatted strings to their numeric equivalent, leave numbers alone, and give an error on all other input. examples: - program: '.[] | tonumber' input: '[1, "1"]' output: ['1', '1'] - title: "`tostring`" body: | The `tostring` function prints its input as a string. Strings are left unchanged, and all other values are JSON-encoded. examples: - program: '.[] | tostring' input: '[1, "1", [1]]' output: ['"1"', '"1"', '"[1]"'] - title: "`type`" body: | The `type` function returns the type of its argument as a string, which is one of null, boolean, number, string, array or object. examples: - program: 'map(type)' input: '[0, false, [], {}, null, "hello"]' output: ['["number", "boolean", "array", "object", "null", "string"]'] - title: "`infinite`, `nan`, `isinfinite`, `isnan`, `isfinite`, `isnormal`" body: | Some arithmetic operations can yield infinities and "not a number" (NaN) values. The `isinfinite` builtin returns `true` if its input is infinite. The `isnan` builtin returns `true` if its input is a NaN. The `infinite` builtin returns a positive infinite value. The `nan` builtin returns a NaN. The `isnormal` builtin returns true if its input is a normal number. Note that division by zero raises an error. Currently most arithmetic operations operating on infinities, NaNs, and sub-normals do not raise errors. examples: - program: '.[] | (infinite * .) < 0' input: '[-1, 1]' output: ['true', 'false'] - program: 'infinite, nan | type' input: 'null' output: ['"number"', '"number"'] - title: "`sort`, `sort_by(path_expression)`" body: | The `sort` functions sorts its input, which must be an array. Values are sorted in the following order: * `null` * `false` * `true` * numbers * strings, in alphabetical order (by unicode codepoint value) * arrays, in lexical order * objects The ordering for objects is a little complex: first they're compared by comparing their sets of keys (as arrays in sorted order), and if their keys are equal then the values are compared key by key. `sort_by` may be used to sort by a particular field of an object, or by applying any jq filter. `sort_by(f)` compares two elements by comparing the result of `f` on each element. When `f` produces multiple values, it firstly compares the first values, and the second values if the first values are equal, and so on. examples: - program: 'sort' input: '[8,3,null,6]' output: ['[null,3,6,8]'] - program: 'sort_by(.foo)' input: '[{"foo":4, "bar":10}, {"foo":3, "bar":10}, {"foo":2, "bar":1}]' output: ['[{"foo":2, "bar":1}, {"foo":3, "bar":10}, {"foo":4, "bar":10}]'] - program: 'sort_by(.foo, .bar)' input: '[{"foo":4, "bar":10}, {"foo":3, "bar":20}, {"foo":2, "bar":1}, {"foo":3, "bar":10}]' output: ['[{"foo":2, "bar":1}, {"foo":3, "bar":10}, {"foo":3, "bar":20}, {"foo":4, "bar":10}]'] - title: "`group_by(path_expression)`" body: | `group_by(.foo)` takes as input an array, groups the elements having the same `.foo` field into separate arrays, and produces all of these arrays as elements of a larger array, sorted by the value of the `.foo` field. Any jq expression, not just a field access, may be used in place of `.foo`. The sorting order is the same as described in the `sort` function above. examples: - program: 'group_by(.foo)' input: '[{"foo":1, "bar":10}, {"foo":3, "bar":100}, {"foo":1, "bar":1}]' output: ['[[{"foo":1, "bar":10}, {"foo":1, "bar":1}], [{"foo":3, "bar":100}]]'] - title: "`min`, `max`, `min_by(path_exp)`, `max_by(path_exp)`" body: | Find the minimum or maximum element of the input array. The `min_by(path_exp)` and `max_by(path_exp)` functions allow you to specify a particular field or property to examine, e.g. `min_by(.foo)` finds the object with the smallest `foo` field. examples: - program: 'min' input: '[5,4,2,7]' output: ['2'] - program: 'max_by(.foo)' input: '[{"foo":1, "bar":14}, {"foo":2, "bar":3}]' output: ['{"foo":2, "bar":3}'] - title: "`unique`, `unique_by(path_exp)`" body: | The `unique` function takes as input an array and produces an array of the same elements, in sorted order, with duplicates removed. The `unique_by(path_exp)` function will keep only one element for each value obtained by applying the argument. Think of it as making an array by taking one element out of every group produced by `group`. examples: - program: 'unique' input: '[1,2,5,3,5,3,1,3]' output: ['[1,2,3,5]'] - program: 'unique_by(.foo)' input: '[{"foo": 1, "bar": 2}, {"foo": 1, "bar": 3}, {"foo": 4, "bar": 5}]' output: ['[{"foo": 1, "bar": 2}, {"foo": 4, "bar": 5}]'] - program: 'unique_by(length)' input: '["chunky", "bacon", "kitten", "cicada", "asparagus"]' output: ['["bacon", "chunky", "asparagus"]'] - title: "`reverse`" body: | This function reverses an array. examples: - program: 'reverse' input: '[1,2,3,4]' output: ['[4,3,2,1]'] - title: "`contains(element)`" body: | The filter `contains(b)` will produce true if b is completely contained within the input. A string B is contained in a string A if B is a substring of A. An array B is contained in an array A if all elements in B are contained in any element in A. An object B is contained in object A if all of the values in B are contained in the value in A with the same key. All other types are assumed to be contained in each other if they are equal. examples: - program: 'contains("bar")' input: '"foobar"' output: ['true'] - program: 'contains(["baz", "bar"])' input: '["foobar", "foobaz", "blarp"]' output: ['true'] - program: 'contains(["bazzzzz", "bar"])' input: '["foobar", "foobaz", "blarp"]' output: ['false'] - program: 'contains({foo: 12, bar: [{barp: 12}]})' input: '{"foo": 12, "bar":[1,2,{"barp":12, "blip":13}]}' output: ['true'] - program: 'contains({foo: 12, bar: [{barp: 15}]})' input: '{"foo": 12, "bar":[1,2,{"barp":12, "blip":13}]}' output: ['false'] - title: "`indices(s)`" body: | Outputs an array containing the indices in `.` where `s` occurs. The input may be an array, in which case if `s` is an array then the indices output will be those where all elements in `.` match those of `s`. examples: - program: 'indices(", ")' input: '"a,b, cd, efg, hijk"' output: ['[3,7,12]'] - program: 'indices(1)' input: '[0,1,2,1,3,1,4]' output: ['[1,3,5]'] - program: 'indices([1,2])' input: '[0,1,2,3,1,4,2,5,1,2,6,7]' output: ['[1,8]'] - title: "`index(s)`, `rindex(s)`" body: | Outputs the index of the first (`index`) or last (`rindex`) occurrence of `s` in the input. examples: - program: 'index(", ")' input: '"a,b, cd, efg, hijk"' output: ['3'] - program: 'index(1)' input: '[0,1,2,1,3,1,4]' output: ['1'] - program: 'index([1,2])' input: '[0,1,2,3,1,4,2,5,1,2,6,7]' output: ['1'] - program: 'rindex(", ")' input: '"a,b, cd, efg, hijk"' output: ['12'] - program: 'rindex(1)' input: '[0,1,2,1,3,1,4]' output: ['5'] - program: 'rindex([1,2])' input: '[0,1,2,3,1,4,2,5,1,2,6,7]' output: ['8'] - title: "`inside`" body: | The filter `inside(b)` will produce true if the input is completely contained within b. It is, essentially, an inversed version of `contains`. examples: - program: 'inside("foobar")' input: '"bar"' output: ['true'] - program: 'inside(["foobar", "foobaz", "blarp"])' input: '["baz", "bar"]' output: ['true'] - program: 'inside(["foobar", "foobaz", "blarp"])' input: '["bazzzzz", "bar"]' output: ['false'] - program: 'inside({"foo": 12, "bar":[1,2,{"barp":12, "blip":13}]})' input: '{"foo": 12, "bar": [{"barp": 12}]}' output: ['true'] - program: 'inside({"foo": 12, "bar":[1,2,{"barp":12, "blip":13}]})' input: '{"foo": 12, "bar": [{"barp": 15}]}' output: ['false'] - title: "`startswith(str)`" body: | Outputs `true` if . starts with the given string argument. examples: - program: '[.[]|startswith("foo")]' input: '["fo", "foo", "barfoo", "foobar", "barfoob"]' output: ['[false, true, false, true, false]'] - title: "`endswith(str)`" body: | Outputs `true` if . ends with the given string argument. examples: - program: '[.[]|endswith("foo")]' input: '["foobar", "barfoo"]' output: ['[false, true]'] - title: "`combinations`, `combinations(n)`" body: | Outputs all combinations of the elements of the arrays in the input array. If given an argument `n`, it outputs all combinations of `n` repetitions of the input array. examples: - program: 'combinations' input: '[[1,2], [3, 4]]' output: ['[1, 3]', '[1, 4]', '[2, 3]', '[2, 4]'] - program: 'combinations(2)' input: '[0, 1]' output: ['[0, 0]', '[0, 1]', '[1, 0]', '[1, 1]'] - title: "`ltrimstr(str)`" body: | Outputs its input with the given prefix string removed, if it starts with it. examples: - program: '[.[]|ltrimstr("foo")]' input: '["fo", "foo", "barfoo", "foobar", "afoo"]' output: ['["fo","","barfoo","bar","afoo"]'] - title: "`rtrimstr(str)`" body: | Outputs its input with the given suffix string removed, if it ends with it. examples: - program: '[.[]|rtrimstr("foo")]' input: '["fo", "foo", "barfoo", "foobar", "foob"]' output: ['["fo","","bar","foobar","foob"]'] - title: "`explode`" body: | Converts an input string into an array of the string's codepoint numbers. examples: - program: 'explode' input: '"foobar"' output: ['[102,111,111,98,97,114]'] - title: "`implode`" body: | The inverse of explode. examples: - program: 'implode' input: '[65, 66, 67]' output: ['"ABC"'] - title: "`split`" body: | Splits an input string on the separator argument. examples: - program: 'split(", ")' input: '"a, b,c,d, e, "' output: ['["a","b,c,d","e",""]'] - title: "`join(str)`" body: | Joins the array of elements given as input, using the argument as separator. It is the inverse of `split`: that is, running `split("foo") | join("foo")` over any input string returns said input string. examples: - program: 'join(", ")' input: '["a","b,c,d","e"]' output: ['"a, b,c,d, e"'] - title: "`ascii_downcase`, `ascii_upcase`" body: | Emit a copy of the input string with its alphabetic characters (a-z and A-Z) converted to the specified case. examples: - program: 'ascii_upcase' input: '"useful but not for é"' output: ['"USEFUL BUT NOT FOR é"'] - title: "`while(cond; update)`" body: | The `while(cond; update)` function allows you to repeatedly apply an update to `.` until `cond` is false. Note that `while(cond; update)` is internally defined as a recursive jq function. Recursive calls within `while` will not consume additional memory if `update` produces at most one output for each input. See advanced topics below. examples: - program: '[while(.<100; .*2)]' input: '1' output: ['[1,2,4,8,16,32,64]'] - title: "`until(cond; next)`" body: | The `until(cond; next)` function allows you to repeatedly apply the expression `next`, initially to `.` then to its own output, until `cond` is true. For example, this can be used to implement a factorial function (see below). Note that `until(cond; next)` is internally defined as a recursive jq function. Recursive calls within `until()` will not consume additional memory if `next` produces at most one output for each input. See advanced topics below. examples: - program: '[.,1]|until(.[0] < 1; [.[0] - 1, .[1] * .[0]])|.[1]' input: '4' output: ['24'] - title: "`recurse(f)`, `recurse`, `recurse(f; condition)`, `recurse_down`" body: | The `recurse(f)` function allows you to search through a recursive structure, and extract interesting data from all levels. Suppose your input represents a filesystem: {"name": "/", "children": [ {"name": "/bin", "children": [ {"name": "/bin/ls", "children": []}, {"name": "/bin/sh", "children": []}]}, {"name": "/home", "children": [ {"name": "/home/stephen", "children": [ {"name": "/home/stephen/jq", "children": []}]}]}]} Now suppose you want to extract all of the filenames present. You need to retrieve `.name`, `.children[].name`, `.children[].children[].name`, and so on. You can do this with: recurse(.children[]) | .name When called without an argument, `recurse` is equivalent to `recurse(.[]?)`. `recurse(f)` is identical to `recurse(f; . != null)` and can be used without concerns about recursion depth. `recurse(f; condition)` is a generator which begins by emitting . and then emits in turn .|f, .|f|f, .|f|f|f, ... so long as the computed value satisfies the condition. For example, to generate all the integers, at least in principle, one could write `recurse(.+1; true)`. For legacy reasons, `recurse_down` exists as an alias to calling `recurse` without arguments. This alias is considered *deprecated* and will be removed in the next major release. The recursive calls in `recurse` will not consume additional memory whenever `f` produces at most a single output for each input. examples: - program: 'recurse(.foo[])' input: '{"foo":[{"foo": []}, {"foo":[{"foo":[]}]}]}' output: - '{"foo":[{"foo":[]},{"foo":[{"foo":[]}]}]}' - '{"foo":[]}' - '{"foo":[{"foo":[]}]}' - '{"foo":[]}' - program: 'recurse' input: '{"a":0,"b":[1]}' output: - '{"a":0,"b":[1]}' - '0' - '[1]' - '1' - program: 'recurse(. * .; . < 20)' input: '2' output: ['2', '4', '16'] - title: "`..`" body: | Short-hand for `recurse` without arguments. This is intended to resemble the XPath `//` operator. Note that `..a` does not work; use `..|a` instead. In the example below we use `..|.a?` to find all the values of object keys "a" in any object found "below" `.`. examples: - program: '..|.a?' input: '[[{"a":1}]]' output: ['1'] - title: "`env`" body: | Outputs an object representing jq's environment. examples: - program: 'env.PAGER' input: 'null' output: ['"less"'] - title: "`transpose`" body: | Transpose a possibly jagged matrix (an array of arrays). Rows are padded with nulls so the result is always rectangular. examples: - program: 'transpose' input: '[[1], [2,3]]' output: ['[[1,2],[null,3]]'] - title: "`bsearch(x)`" body: | `bsearch(x)` conducts a binary search for x in the input array. If the input is sorted and contains x, then `bsearch(x)` will return its index in the array; otherwise, if the array is sorted, it will return (-1 - ix) where ix is an insertion point such that the array would still be sorted after the insertion of x at ix. If the array is not sorted, `bsearch(x)` will return an integer that is probably of no interest. examples: - program: 'bsearch(0)' input: '[0,1]' output: ['0'] - program: 'bsearch(0)' input: '[1,2,3]' output: ['-1'] - program: 'bsearch(4) as $ix | if $ix < 0 then .[-(1+$ix)] = 4 else . end' input: '[1,2,3]' output: ['[1,2,3,4]'] - title: "String interpolation: `\\(exp)`" body: | Inside a string, you can put an expression inside parens after a backslash. Whatever the expression returns will be interpolated into the string. examples: - program: '"The input was \(.), which is one less than \(.+1)"' input: '42' output: ['"The input was 42, which is one less than 43"'] - title: "Convert to/from JSON" body: | The `tojson` and `fromjson` builtins dump values as JSON texts or parse JSON texts into values, respectively. The tojson builtin differs from tostring in that tostring returns strings unmodified, while tojson encodes strings as JSON strings. examples: - program: '[.[]|tostring]' input: '[1, "foo", ["foo"]]' output: ['["1","foo","[\"foo\"]"]'] - program: '[.[]|tojson]' input: '[1, "foo", ["foo"]]' output: ['["1","\"foo\"","[\"foo\"]"]'] - program: '[.[]|tojson|fromjson]' input: '[1, "foo", ["foo"]]' output: ['[1,"foo",["foo"]]'] - title: "Format strings and escaping" body: | The `@foo` syntax is used to format and escape strings, which is useful for building URLs, documents in a language like HTML or XML, and so forth. `@foo` can be used as a filter on its own, the possible escapings are: * `@text`: Calls `tostring`, see that function for details. * `@json`: Serializes the input as JSON. * `@html`: Applies HTML/XML escaping, by mapping the characters `<>&'"` to their entity equivalents `<`, `>`, `&`, `'`, `"`. * `@uri`: Applies percent-encoding, by mapping all reserved URI characters to a `%XX` sequence. * `@csv`: The input must be an array, and it is rendered as CSV with double quotes for strings, and quotes escaped by repetition. * `@tsv`: The input must be an array, and it is rendered as TSV (tab-separated values). Each input array will be printed as a single line. Fields are separated by a single tab (ascii `0x09`). Input characters line-feed (ascii `0x0a`), carriage-return (ascii `0x0d`), tab (ascii `0x09`) and backslash (ascii `0x5c`) will be output as escape sequences `\n`, `\r`, `\t`, `\\` respectively. * `@sh`: The input is escaped suitable for use in a command-line for a POSIX shell. If the input is an array, the output will be a series of space-separated strings. * `@base64`: The input is converted to base64 as specified by RFC 4648. This syntax can be combined with string interpolation in a useful way. You can follow a `@foo` token with a string literal. The contents of the string literal will *not* be escaped. However, all interpolations made inside that string literal will be escaped. For instance, @uri "https://www.google.com/search?q=\(.search)" will produce the following output for the input `{"search":"what is jq?"}`: "https://www.google.com/search?q=what%20is%20jq%3F" Note that the slashes, question mark, etc. in the URL are not escaped, as they were part of the string literal. examples: - program: '@html' input: '"This works if x < y"' output: ['"This works if x < y"'] - program: '@sh "echo \(.)"' input: "\"O'Hara's Ale\"" output: ["\"echo 'O'\\\\''Hara'\\\\''s Ale'\""] - title: "Dates" body: | jq provides some basic date handling functionality, with some high-level and low-level builtins. In all cases these builtins deal exclusively with time in UTC. The `fromdateiso8601` builtin parses datetimes in the ISO 8601 format to a number of seconds since the Unix epoch (1970-01-01T00:00:00Z). The `todateiso8601` builtin does the inverse. The `fromdate` builtin parses datetime strings. Currently `fromdate` only supports ISO 8601 datetime strings, but in the future it will attempt to parse datetime strings in more formats. The `todate` builtin is an alias for `todateiso8601`. The `now` builtin outputs the current time, in seconds since the Unix epoch. Low-level jq interfaces to the C-library time functions are also provided: `strptime`, `strftime`, `mktime`, and `gmtime`. Refer to your host operating system's documentation for the format strings used by `strptime` and `strftime`. Note: these are not necessarily stable interfaces in jq, particularly as to their localization functionality. The `gmtime` builtin consumes a number of seconds since the Unix epoch and outputs a "broken down time" representation of time as an array of numbers representing (in this order): the year, the month (zero-based), the day of the month, the hour of the day, the minute of the hour, the second of the minute, the day of the week, and the day of the year -- all one-based unless otherwise stated. The `mktime` builtin consumes "broken down time" representations of time output by `gmtime` and `strptime`. The `strptime(fmt)` builtin parses input strings matching the `fmt` argument. The output is in the "broken down time" representation consumed by `mktime` and output by `gmtime`. The `strftime(fmt)` builtin formats a time with the given format. The format strings for `strptime` and `strftime` are described in typical C library documentation. The format string for ISO 8601 datetime is `"%Y-%m-%dT%H:%M:%SZ"`. jq may not support some or all of this date functionality on some systems. examples: - program: 'fromdate' input: '"2015-03-05T23:51:47Z"' output: ['1425599507'] - program: 'strptime("%Y-%m-%dT%H:%M:%SZ")' input: '"2015-03-05T23:51:47Z"' output: ['[2015,2,5,23,51,47,4,63]'] - program: 'strptime("%Y-%m-%dT%H:%M:%SZ")|mktime' input: '"2015-03-05T23:51:47Z"' output: ['1425599507'] - title: Conditionals and Comparisons entries: - title: "`==`, `!=`" body: | The expression 'a == b' will produce 'true' if the result of a and b are equal (that is, if they represent equivalent JSON documents) and 'false' otherwise. In particular, strings are never considered equal to numbers. If you're coming from JavaScript, jq's == is like JavaScript's === - considering values equal only when they have the same type as well as the same value. != is "not equal", and 'a != b' returns the opposite value of 'a == b' examples: - program: '.[] == 1' input: '[1, 1.0, "1", "banana"]' output: ['true', 'true', 'false', 'false'] - title: if-then-else-end body: | `if A then B else C end` will act the same as `B` if `A` produces a value other than false or null, but act the same as `C` otherwise. Checking for false or null is a simpler notion of "truthiness" than is found in JavaScript or Python, but it means that you'll sometimes have to be more explicit about the condition you want: you can't test whether, e.g. a string is empty using `if .name then A else B end`, you'll need something more like `if (.name | length) > 0 then A else B end` instead. If the condition `A` produces multiple results, then `B` is evaluated once for each result that is not false or null, and `C` is evaluated once for each false or null. More cases can be added to an if using `elif A then B` syntax. examples: - program: |- if . == 0 then "zero" elif . == 1 then "one" else "many" end input: '2' output: ['"many"'] - title: "`>`, `>=`, `<=`, `<`" body: | The comparison operators `>`, `>=`, `<=`, `<` return whether their left argument is greater than, greater than or equal to, less than or equal to or less than their right argument (respectively). The ordering is the same as that described for `sort`, above. examples: - program: '. < 5' input: '2' output: ['true'] - title: "`and`, `or`, `not`" body: | jq supports the normal Boolean operators `and`, `or`, `not`. They have the same standard of truth as if expressions - `false` and `null` are considered "false values", and anything else is a "true value". If an operand of one of these operators produces multiple results, the operator itself will produce a result for each input. `not` is in fact a builtin function rather than an operator, so it is called as a filter to which things can be piped rather than with special syntax, as in `.foo and .bar | not`. These three only produce the values `true` and `false`, and so are only useful for genuine Boolean operations, rather than the common Perl/Python/Ruby idiom of "value_that_may_be_null or default". If you want to use this form of "or", picking between two values rather than evaluating a condition, see the `//` operator below. examples: - program: '42 and "a string"' input: 'null' output: ['true'] - program: '(true, false) or false' input: 'null' output: ['true', 'false'] - program: '(true, true) and (true, false)' input: 'null' output: ['true', 'false', 'true', 'false'] - program: '[true, false | not]' input: 'null' output: ['[false, true]'] - title: "Alternative operator: `//`" body: | A filter of the form `a // b` produces the same results as `a`, if `a` produces results other than `false` and `null`. Otherwise, `a // b` produces the same results as `b`. This is useful for providing defaults: `.foo // 1` will evaluate to `1` if there's no `.foo` element in the input. It's similar to how `or` is sometimes used in Python (jq's `or` operator is reserved for strictly Boolean operations). examples: - program: '.foo // 42' input: '{"foo": 19}' output: ['19'] - program: '.foo // 42' input: '{}' output: ['42'] - title: try-catch body: | Errors can be caught by using `try EXP catch EXP`. The first expression is executed, and if it fails then the second is executed with the error message. The output of the handler, if any, is output as if it had been the output of the expression to try. The `try EXP` form uses `empty` as the exception handler. examples: - program: 'try .a catch ". is not an object"' input: 'true' output: ['". is not an object"'] - program: '[.[]|try .a]' input: '[{}, true, {"a":1}]' output: ['[null, 1]'] - program: 'try error("some exception") catch .' input: 'true' output: ['"some exception"'] - title: Breaking out of control structures body: | A convenient use of try/catch is to break out of control structures like `reduce`, `foreach`, `while`, and so on. For example: # Repeat an expression until it raises "break" as an # error, then stop repeating without re-raising the error. # But if the error caught is not "break" then re-raise it. try repeat(exp) catch if .=="break" then empty else error jq has a syntax for named lexical labels to "break" or "go (back) to": label $out | ... break $out ... The `break $label_name` expression will cause the program to act as though the nearest (to the left) `label $label_name` produced `empty`. The relationship between the `break` and corresponding `label` is lexical: the label has to be "visible" from the break. To break out of a `reduce`, for example: label $out | reduce .[] as $item (null; if .==false then break $out else ... end) The following jq program produces a syntax error: break $out because no label `$out` is visible. - title: "`?` operator" body: | The `?` operator, used as `EXP?`, is shorthand for `try EXP`. examples: - program: '[.[]|(.a)?]' input: '[{}, true, {"a":1}]' output: ['[null, 1]'] - title: Regular expressions body: | jq uses the Oniguruma regular expression library, as do PHP, Ruby, TextMate, Sublime Text, etc, so the description here will focus on jq specifics. The jq regex filters are defined so that they can be used using one of these patterns: STRING | FILTER(REGEX) STRING | FILTER(REGEX; FLAGS) STRING | FILTER([REGEX]) STRING | FILTER([REGEX, FLAGS]) where: * STRING, REGEX, and FLAGS are jq strings and subject to jq string interpolation; * REGEX, after string interpolation, should be a valid regular expression; * FILTER is one of `test`, `match`, or `capture`, as described below. FLAGS is a string consisting of one of more of the supported flags: * `g` - Global search (find all matches, not just the first) * `i` - Case insensitive search * `m` - Multi line mode (`.` will match newlines) * `n` - Ignore empty matches * `p` - Both s and m modes are enabled * `s` - Single line mode (`^` -> `\A`, `$` -> `\Z`) * `l` - Find longest possible matches * `x` - Extended regex format (ignore whitespace and comments) To match a whitespace with the `x` flag, use `\s`, e.g. jq -n '"a b" | test("a\\sb"; "x")' Note that certain flags may also be specified within REGEX, e.g. jq -n '("test", "TEst", "teST", "TEST") | test("(?i)te(?-i)st")' evaluates to: `true`, `true`, `false`, `false`. entries: - title: "`test(val)`, `test(regex; flags)`" body: | Like `match`, but does not return match objects, only `true` or `false` for whether or not the regex matches the input. examples: - program: 'test("foo")' input: '"foo"' output: ['true'] - program: '.[] | test("a b c # spaces are ignored"; "ix")' input: '["xabcd", "ABC"]' output: ['true', 'true'] - title: "`match(val)`, `match(regex; flags)`" body: | **match** outputs an object for each match it finds. Matches have the following fields: * `offset` - offset in UTF-8 codepoints from the beginning of the input * `length` - length in UTF-8 codepoints of the match * `string` - the string that it matched * `captures` - an array of objects representing capturing groups. Capturing group objects have the following fields: * `offset` - offset in UTF-8 codepoints from the beginning of the input * `length` - length in UTF-8 codepoints of this capturing group * `string` - the string that was captured * `name` - the name of the capturing group (or `null` if it was unnamed) Capturing groups that did not match anything return an offset of -1 examples: - program: 'match("(abc)+"; "g")' input: '"abc abc"' output: - '{"offset": 0, "length": 3, "string": "abc", "captures": [{"offset": 0, "length": 3, "string": "abc", "name": null}]}' - '{"offset": 4, "length": 3, "string": "abc", "captures": [{"offset": 4, "length": 3, "string": "abc", "name": null}]}' - program: 'match("foo")' input: '"foo bar foo"' output: ['{"offset": 0, "length": 3, "string": "foo", "captures": []}'] - program: 'match(["foo", "ig"])' input: '"foo bar FOO"' output: - '{"offset": 0, "length": 3, "string": "foo", "captures": []}' - '{"offset": 8, "length": 3, "string": "FOO", "captures": []}' - program: 'match("foo (?bar)? foo"; "ig")' input: '"foo bar foo foo foo"' output: - '{"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"}]}' - program: '[ match("."; "g")] | length' input: '"abc"' output: ['3'] - title: "`capture(val)`, `capture(regex; flags)`" body: | Collects the named captures in a JSON object, with the name of each capture as the key, and the matched string as the corresponding value. examples: - program: 'capture("(?[a-z]+)-(?[0-9]+)")' input: '"xyzzy-14"' output: ['{ "a": "xyzzy", "n": "14" }'] - title: "`scan(regex)`, `scan(regex; flags)`" body: | Emit a stream of the non-overlapping substrings of the input that match the regex in accordance with the flags, if any have been specified. If there is no match, the stream is empty. To capture all the matches for each input string, use the idiom `[ expr ]`, e.g. `[ scan(regex) ]`. examples: - program: 'scan("c")' input: '"abcdefabc"' output: ['"c"', '"c"'] - title: "`split(regex; flags)`" body: | For backwards compatibility, `split` splits on a string, not a regex. examples: - program: 'split(", *"; null)' input: '"ab,cd, ef"' output: ['["ab","cd","ef"]'] - title: "`splits(regex)`, `splits(regex; flags)`" body: | These provide the same results as their `split` counterparts, but as a stream instead of an array. examples: - program: 'splits(", *")' input: '"ab,cd, ef, gh"' output: ['"ab"','"cd"','"ef"','"gh"'] - title: "`sub(regex; tostring)` `sub(regex; string; flags)`" body: | Emit the string obtained by replacing the first match of regex in the input string with `tostring`, after interpolation. `tostring` should be a jq string, and may contain references to named captures. The named captures are, in effect, presented as a JSON object (as constructed by `capture`) to `tostring`, so a reference to a captured variable named "x" would take the form: `"\(.x)"`. examples: - program: 'sub("[^a-z]*(?[a-z]+)"; "Z\(.x)"; "g")' input: '"123abc456def"' output: ['"ZabcZdef"'] - title: "`gsub(regex; string)`, `gsub(regex; string; flags)`" body: | `gsub` is like `sub` but all the non-overlapping occurrences of the regex are replaced by the string, after interpolation. examples: - program: 'gsub("(?.)[^a]*"; "+\(.x)-")' input: '"Abcabc"' output: ['"+A-+a-"'] - title: Advanced features body: | Variables are an absolute necessity in most programming languages, but they're relegated to an "advanced feature" in jq. In most languages, variables are the only means of passing around data. If you calculate a value, and you want to use it more than once, you'll need to store it in a variable. To pass a value to another part of the program, you'll need that part of the program to define a variable (as a function parameter, object member, or whatever) in which to place the data. It is also possible to define functions in jq, although this is is a feature whose biggest use is defining jq's standard library (many jq functions such as `map` and `select` are in fact written in jq). jq has reduction operators, which are very powerful but a bit tricky. Again, these are mostly used internally, to define some useful bits of jq's standard library. It may not be obvious at first, but jq is all about generators (yes, as often found in other languages). Some utilities are provided to help deal with generators. Some minimal I/O support (besides reading JSON from standard input, and writing JSON to standard output) is available. Finally, there is a module/library system. entries: - title: Variables body: | In jq, all filters have an input and an output, so manual plumbing is not necessary to pass a value from one part of a program to the next. Many expressions, for instance `a + b`, pass their input to two distinct subexpressions (here `a` and `b` are both passed the same input), so variables aren't usually necessary in order to use a value twice. For instance, calculating the average value of an array of numbers requires a few variables in most languages - at least one to hold the array, perhaps one for each element or for a loop counter. In jq, it's simply `add / length` - the `add` expression is given the array and produces its sum, and the `length` expression is given the array and produces its length. So, there's generally a cleaner way to solve most problems in jq than defining variables. Still, sometimes they do make things easier, so jq lets you define variables using `expression as $variable`. All variable names start with `$`. Here's a slightly uglier version of the array-averaging example: length as $array_length | add / $array_length We'll need a more complicated problem to find a situation where using variables actually makes our lives easier. Suppose we have an array of blog posts, with "author" and "title" fields, and another object which is used to map author usernames to real names. Our input looks like: {"posts": [{"title": "First post", "author": "anon"}, {"title": "A well-written article", "author": "person1"}], "realnames": {"anon": "Anonymous Coward", "person1": "Person McPherson"}} We want to produce the posts with the author field containing a real name, as in: {"title": "First post", "author": "Anonymous Coward"} {"title": "A well-written article", "author": "Person McPherson"} We use a variable, $names, to store the realnames object, so that we can refer to it later when looking up author usernames: .realnames as $names | .posts[] | {title, author: $names[.author]} The expression `exp as $x | ...` means: for each value of expression `exp`, run the rest of the pipeline with the entire original input, and with `$x` set to that value. Thus `as` functions as something of a foreach loop. Just as `{foo}` is a handy way of writing `{foo: .foo}`, so `{$foo}` is a handy way of writing `{foo: $foo}`. Multiple variables may be declared using a single `as` expression by providing a pattern that matches the structure of the input (this is known as "destructuring"): . as {realnames: $names, posts: [$first, $second]} | ... The variable declarations in array patterns (e.g., `. as [$first, $second]`) bind to the elements of the array in from the element at index zero on up, in order. When there is no value at the index for an array pattern element, `null` is bound to that variable. Variables are scoped over the rest of the expression that defines them, so .realnames as $names | (.posts[] | {title, author: $names[.author]}) will work, but (.realnames as $names | .posts[]) | {title, author: $names[.author]} won't. For programming language theorists, it's more accurate to say that jq variables are lexically-scoped bindings. In particular there's no way to change the value of a binding; one can only setup a new binding with the same name, but which will not be visible where the old one was. examples: - program: '.bar as $x | .foo | . + $x' input: '{"foo":10, "bar":200}' output: ['210'] - program: '. as $i|[(.*2|. as $i| $i), $i]' input: '5' output: ['[10,5]'] - program: '. as [$a, $b, {c: $c}] | $a + $b + $c' input: '[2, 3, {"c": 4, "d": 5}]' output: ['9'] - program: '.[] as [$a, $b] | {a: $a, b: $b}' input: '[[0], [0, 1], [2, 1, 0]]' output: ['{"a":0,"b":null}', '{"a":0,"b":1}', '{"a":2,"b":1}'] - title: 'Defining Functions' body: | You can give a filter a name using "def" syntax: def increment: . + 1; From then on, `increment` is usable as a filter just like a builtin function (in fact, this is how some of the builtins are defined). A function may take arguments: def map(f): [.[] | f]; Arguments are passed as filters, not as values. The same argument may be referenced multiple times with different inputs (here `f` is run for each element of the input array). Arguments to a function work more like callbacks than like value arguments. This is important to understand. Consider: def foo(f): f|f; 5|foo(.*2) The result will be 20 because `f` is `.*2`, and during the first invocation of `f` `.` will be 5, and the second time it will be 10 (5 * 2), so the result will be 20. Function arguments are filters, and filters expect an input when invoked. If you want the value-argument behaviour for defining simple functions, you can just use a variable: def addvalue(f): f as $f | map(. + $f); Or use the short-hand: def addvalue($f): ...; With either definition, `addvalue(.foo)` will add the current input's `.foo` field to each element of the array. Multiple definitions using the same function name are allowed. Each re-definition replaces the previous one for the same number of function arguments, but only for references from functions (or main program) subsequent to the re-definition. examples: - program: 'def addvalue(f): . + [f]; map(addvalue(.[0]))' input: '[[1,2],[10,20]]' output: ['[[1,2,1], [10,20,10]]'] - program: 'def addvalue(f): f as $x | map(. + $x); addvalue(.[0])' input: '[[1,2],[10,20]]' output: ['[[1,2,1,2], [10,20,1,2]]'] - title: "`limit(n; exp)`" body: | The `limit` function extracts up to `n` outputs from `exp`. examples: - program: '[limit(3;.[])]' input: '[0,1,2,3,4,5,6,7,8,9]' output: ['[0,1,2]'] - title: "`first(expr)`, `last(expr)`, `nth(n; expr)`" body: | The `first(expr)` and `last(expr)` functions extract the first and last values from `expr`, respectively. The `nth(n; expr)` function extracts the nth value output by `expr`. This can be defined as `def nth(n; expr): last(limit(n + 1; expr));`. Note that `nth(n; expr)` doesn't support negative values of `n`. examples: - program: '[first(range(.)), last(range(.)), nth(./2; range(.))]' input: '10' output: ['[0,9,5]'] - title: "`first`, `last`, `nth(n)`" body: | The `first` and `last` functions extract the first and last values from any array at `.`. The `nth(n)` function extracts the nth value of any array at `.`. examples: - program: '[range(.)]|[first, last, nth(5)]' input: '10' output: ['[0,9,5]'] - title: "`reduce`" body: | The `reduce` syntax allows you to combine all of the results of an expression by accumulating them into a single answer. The form is `reduce EXP as $var (INIT; UPDATE)`. As an example, we'll pass `[1,2,3]` to this expression: reduce .[] as $item (0; . + $item) For each result that `.[]` produces, `. + $item` is run to accumulate a running total, starting from 0 as the input value. In this example, `.[]` produces the results `1`, `2`, and `3`, so the effect is similar to running something like this: 0 | 1 as $item | . + $item | 2 as $item | . + $item | 3 as $item | . + $item examples: - program: 'reduce .[] as $item (0; . + $item)' input: '[1,2,3,4,5]' output: ['15'] - program: 'reduce .[] as [$i,$j] (0; . + $i * $j)' input: '[[1,2],[3,4],[5,6]]' output: ['44'] - program: 'reduce .[] as {$x,$y} (null; .x += $x | .y += [$y])' input: '[{"x":"a","y":1},{"x":"b","y":2},{"x":"c","y":3}]' output: ['{"x":"abc","y":[1,2,3]}'] - title: "`foreach`" body: | The `foreach` syntax is similar to `reduce`, but intended to allow the construction of `limit` and reducers that produce intermediate results. The form is `foreach EXP as $var (INIT; UPDATE; EXTRACT)`. As an example, we'll pass `[1,2,3]` to this expression: foreach .[] as $item (0; . + $item; [$item, . * 2]) Like the `reduce` syntax, `. + $item` is run for each result that `.[]` produces, but `[$item, . * 2]` is run for each intermediate values. In this example, since the intermediate values are `1`, `3`, and `6`, the `foreach` expression produces `[1,2]`, `[2,6]`, and `[3,12]`. So the effect is similar to running something like this: 0 | 1 as $item | . + $item | [$item, . * 2], 2 as $item | . + $item | [$item, . * 2], 3 as $item | . + $item | [$item, . * 2] When `EXTRACT` is omitted, the identity filter is used. That is, it outputs the intermediate values as they are. examples: - program: 'foreach .[] as $item (0; . + $item)' input: '[1,2,3,4,5]' output: ['1','3','6','10','15'] - program: 'foreach .[] as $item (0; . + $item; [$item, . * 2])' input: '[1,2,3,4,5]' output: ['[1,2]','[2,6]','[3,12]','[4,20]','[5,30]'] - program: 'foreach .[] as $item (0; . + 1; {index: ., $item})' input: '["foo", "bar", "baz"]' output: - '{"index":1,"item":"foo"}' - '{"index":2,"item":"bar"}' - '{"index":3,"item":"baz"}' - title: Recursion body: | As described above, `recurse` uses recursion, and any jq function can be recursive. The `while` builtin is also implemented in terms of recursion. Tail calls are optimized whenever the expression to the left of the recursive call outputs its last value. In practice this means that the expression to the left of the recursive call should not produce more than one output for each input. For example: def recurse(f): def r: ., (f | select(. != null) | r); r; def while(cond; update): def _while: if cond then ., (update | _while) else empty end; _while; def repeat(exp): def _repeat: exp, _repeat; _repeat; - title: Generators and iterators body: | Some jq operators and functions are actually generators in that they can produce zero, one, or more values for each input, just as one might expect in other programming languages that have generators. For example, `.[]` generates all the values in its input (which must be an array or an object), `range(0; 10)` generates the integers between 0 and 10, and so on. Even the comma operator is a generator, generating first the values generated by the expression to the left of the comma, then for each of those, the values generate by the expression on the right of the comma. The `empty` builtin is the generator that produces zero outputs. The `empty` builtin backtracks to the preceding generator expression. All jq functions can be generators just by using builtin generators. It is also possible to define new generators using only recursion and the comma operator. If the recursive call(s) is(are) "in tail position" then the generator will be efficient. In the example below the recursive call by `_range` to itself is in tail position. The example shows off three advanced topics: tail recursion, generator construction, and sub-functions. examples: - program: 'def range(init; upto; by): def _range: if (by > 0 and . < upto) or (by < 0 and . > upto) then ., ((.+by)|_range) else . end; if by == 0 then init else init|_range end | select((by > 0 and . < upto) or (by < 0 and . > upto)); range(0; 10; 3)' input: 'null' output: ['0', '3', '6', '9'] - program: 'def while(cond; update): def _while: if cond then ., (update | _while) else empty end; _while; [while(.<100; .*2)]' input: '1' output: ['[1,2,4,8,16,32,64]'] - title: 'Math' body: | jq currently only has IEEE754 double-precision (64-bit) floating point number support. Besides simple arithmetic operators such as `+`, jq also has most standard math functions from the C math library. C math functions that take a single input argument (e.g., `sin()`) are available as zero-argument jq functions. C math functions that take two input arguments (e.g., `pow()`) are available as two-argument jq functions that ignore `.`. Availability of standard math functions depends on the availability of the corresponding math functions in your operating system and C math library. Unavailable math functions will be defined but will raise an error. - title: 'I/O' body: | At this time jq has minimal support for I/O, mostly in the form of control over when inputs are read. Two builtins functions are provided for this, `input` and `inputs`, that read from the same sources (e.g., `stdin`, files named on the command-line) as jq itself. These two builtins, and jq's own reading actions, can be interleaved with each other. One builtin provides minimal output capabilities, `debug`. (Recall that a jq program's output values are always output as JSON texts on `stdout`.) The `debug` builtin can have application-specific behavior, such as for executables that use the libjq C API but aren't the jq executable itself. entries: - title: "`input`" body: | Outputs one new input. echo 1 2 3 4 | jq '[., input]' # [1,2] [3,4] - title: "`inputs`" body: | Outputs all remaining inputs, one by one. This is primarily useful for reductions over a program's inputs. echo 1 2 3 | jq -n 'reduce inputs as $i (0; . + $i)' # 6 - title: "`debug`" body: | Causes a debug message based on the input value to be produced. The jq executable wraps the input value with `["DEBUG:", ]` and prints that and a newline on stderr, compactly. This may change in the future. - title: "`input_filename`" body: | Returns the name of the file whose input is currently being filtered. Note that this will not work well unless jq is running in a UTF-8 locale. - title: "`input_line_number`" body: | Returns the line number of the input currently being filtered. - title: 'Streaming' body: | With the `--stream` option jq can parse input texts in a streaming fashion, allowing jq programs to start processing large JSON texts immediately rather than after the parse completes. If you have a single JSON text that is 1GB in size, streaming it will allow you to process it much more quickly. However, streaming isn't easy to deal with as the jq program will have `[, ]` (and a few other forms) as inputs. Several builtins are provided to make handling streams easier. The examples below use the streamed form of `[0,[1]]`, which is `[[0],0],[[1,0],1],[[1,0]],[[1]]`. Streaming forms include `[, ]` (to indicate any scalar value, empty array, or empty object), and `[]` (to indicate the end of an array or object). Future versions of jq run with `--stream` and `--seq` may output additional forms such as `["error message"]` when an input text fails to parse. entries: - title: "`truncate_stream(stream_expression)`" body: | Consumes a number as input and truncates the corresponding number of path elements from the left of the outputs of the given streaming expression. examples: - program: 'truncate_stream([[0],1],[[1,0],2],[[1,0]],[[1]])' input: '1' output: ['[[0],2]', '[[0]]'] - title: "`fromstream(stream_expression)`" body: | Outputs values corresponding to the stream expression's outputs. examples: - program: 'fromstream(1|truncate_stream([[0],1],[[1,0],2],[[1,0]],[[1]]))' input: 'null' output: ['[2]'] - title: "`tostream`" body: | The `tostream` builtin outputs the streamed form of its input. examples: - program: '. as $dot|fromstream($dot|tostream)|.==$dot' input: '[0,[1,{"a":1},{"b":2}]]' output: ['true'] - title: Assignment body: | Assignment works a little differently in jq than in most programming languages. jq doesn't distinguish between references to and copies of something - two objects or arrays are either equal or not equal, without any further notion of being "the same object" or "not the same object". If an object has two fields which are arrays, `.foo` and `.bar`, and you append something to `.foo`, then `.bar` will not get bigger. Even if you've just set `.bar = .foo`. If you're used to programming in languages like Python, Java, Ruby, JavaScript, etc. then you can think of it as though jq does a full deep copy of every object before it does the assignment (for performance, it doesn't actually do that, but that's the general idea). All the assignment operators in jq have path expressions on the left-hand side. entries: - title: "`=`" body: | The filter `.foo = 1` will take as input an object and produce as output an object with the "foo" field set to 1. There is no notion of "modifying" or "changing" something in jq - all jq values are immutable. For instance, .foo = .bar | .foo.baz = 1 will not have the side-effect of setting .bar.baz to be set to 1, as the similar-looking program in JavaScript, Python, Ruby or other languages would. Unlike these languages (but like Haskell and some other functional languages), there is no notion of two arrays or objects being "the same array" or "the same object". They can be equal, or not equal, but if we change one of them in no circumstances will the other change behind our backs. This means that it's impossible to build circular values in jq (such as an array whose first element is itself). This is quite intentional, and ensures that anything a jq program can produce can be represented in JSON. Note that the left-hand side of '=' refers to a value in `.`. Thus `$var.foo = 1` won't work as expected (`$var.foo` is not a valid or useful path expression in `.`); use `$var | .foo = 1` instead. If the right-hand side of '=' produces multiple values, then for each such value jq will set the paths on the left-hand side to the value and then it will output the modified `.`. For example, `(.a,.b)=range(2)` outputs `{"a":0,"b":0}`, then `{"a":1,"b":1}`. The "update" assignment forms (see below) do not do this. Note too that `.a,.b=0` does not set `.a` and `.b`, but `(.a,.b)=0` sets both. - title: "`|=`" body: | As well as the assignment operator '=', jq provides the "update" operator '|=', which takes a filter on the right-hand side and works out the new value for the property of `.` being assigned to by running the old value through this expression. For instance, .foo |= .+1 will build an object with the "foo" field set to the input's "foo" plus 1. This example should show the difference between '=' and '|=': Provide input '{"a": {"b": 10}, "b": 20}' to the programs: .a = .b .a |= .b The former will set the "a" field of the input to the "b" field of the input, and produce the output {"a": 20}. The latter will set the "a" field of the input to the "a" field's "b" field, producing {"a": 10}. The left-hand side can be any general path expression; see `path()`. Note that the left-hand side of '|=' refers to a value in `.`. Thus `$var.foo |= . + 1` won't work as expected (`$var.foo` is not a valid or useful path expression in `.`); use `$var | .foo |= . + 1` instead. If the right-hand side outputs multiple values, only the last one will be used. examples: - program: '(..|select(type=="boolean")) |= if . then 1 else 0 end' input: '[true,false,[5,true,[true,[false]],false]]' output: ['[1,0,[5,1,[1,[0]],0]]'] - title: "`+=`, `-=`, `*=`, `/=`, `%=`, `//=`" body: | jq has a few operators of the form `a op= b`, which are all equivalent to `a |= . op b`. So, `+= 1` can be used to increment values. examples: - program: .foo += 1 input: '{"foo": 42}' output: ['{"foo": 43}'] - title: Complex assignments body: | Lots more things are allowed on the left-hand side of a jq assignment than in most languages. We've already seen simple field accesses on the left hand side, and it's no surprise that array accesses work just as well: .posts[0].title = "JQ Manual" What may come as a surprise is that the expression on the left may produce multiple results, referring to different points in the input document: .posts[].comments |= . + ["this is great"] That example appends the string "this is great" to the "comments" array of each post in the input (where the input is an object with a field "posts" which is an array of posts). When jq encounters an assignment like 'a = b', it records the "path" taken to select a part of the input document while executing a. This path is then used to find which part of the input to change while executing the assignment. Any filter may be used on the left-hand side of an equals - whichever paths it selects from the input will be where the assignment is performed. This is a very powerful operation. Suppose we wanted to add a comment to blog posts, using the same "blog" input above. This time, we only want to comment on the posts written by "stedolan". We can find those posts using the "select" function described earlier: .posts[] | select(.author == "stedolan") The paths provided by this operation point to each of the posts that "stedolan" wrote, and we can comment on each of them in the same way that we did before: (.posts[] | select(.author == "stedolan") | .comments) |= . + ["terrible."] - title: Modules body: | jq has a library/module system. Modules are files whose names end in `.jq`. Modules imported by a program are searched for in a default search path (see below). The `import` and `include` directives allow the importer to alter this path. Paths in the search path are subject to various substitutions. For paths starting with "~/", the user's home directory is substituted for "~". For paths starting with "$ORIGIN/", the directory where the jq executable is located is substituted for "$ORIGIN". For paths starting with "./" or paths that are ".", the path of the including file is substituted for ".". For top-level programs given on the command-line, the current directory is used. Import directives can optionally specify a search path to which the default is appended. The default search path is the search path given to the `-L` command-line option, else `["~/.jq", "$ORIGIN/../lib/jq", "$ORIGIN/../lib"]`. Null and empty string path elements terminate search path processing. A dependency with relative path "foo/bar" would be searched for in "foo/bar.jq" and "foo/bar/bar.jq" in the given search path. This is intended to allow modules to be placed in a directory along with, for example, version control files, README files, and so on, but also to allow for single-file modules. Consecutive components with the same name are not allowed to avoid ambiguities (e.g., "foo/foo"). For example, with `-L$HOME/.jq` a module `foo` can be found in `$HOME/.jq/foo.jq` and `$HOME/.jq/foo/foo.jq`. If "$HOME/.jq" is a file, it is sourced into the main program. entries: - title: "`import RelativePathString as NAME [];`" body: | Imports a module found at the given path relative to a directory in a search path. A ".jq" suffix will be added to the relative path string. The module's symbols are prefixed with "NAME::". The optional metadata must be a constant jq expression. It should be an object with keys like "homepage" and so on. At this time jq only uses the "search" key/value of the metadata. The metadata is also made available to users via the `modulemeta` builtin. The "search" key in the metadata, if present, should have a string or array value (array of strings); this is the search path to be prefixed to the top-level search path. - title: "`include RelativePathString [];`" body: | Imports a module found at the given path relative to a directory in a search path as if it were included in place. A ".jq" suffix will be added to the relative path string. The module's symbols are imported into the caller's namespace as if the module's content had been included directly. The optional metadata must be a constant jq expression. It should be an object with keys like "homepage" and so on. At this time jq only uses the "search" key/value of the metadata. The metadata is also made available to users via the `modulemeta` builtin. - title: "`import RelativePathString as $NAME [];`" body: | Imports a JSON file found at the given path relative to a directory in a search path. A ".json" suffix will be added to the relative path string. The file's data will be available as `$NAME::NAME`. The optional metadata must be a constant jq expression. It should be an object with keys like "homepage" and so on. At this time jq only uses the "search" key/value of the metadata. The metadata is also made available to users via the `modulemeta` builtin. The "search" key in the metadata, if present, should have a string or array value (array of strings); this is the search path to be prefixed to the top-level search path. - title: "`module ;`" body: | This directive is entirely optional. It's not required for proper operation. It serves only the purpose of providing metadata that can be read with the `modulemeta` builtin. The metadata must be a constant jq expression. It should be an object with keys like "homepage". At this time jq doesn't use this metadata, but it is made available to users via the `modulemeta` builtin. - title: "`modulemeta`" body: | Takes a module name as input and outputs the module's metadata as an object, with the module's imports (including metadata) as an array value for the "deps" key. Programs can use this to query a module's metadata, which they could then use to, for example, search for, download, and install missing dependencies. ================================================ FILE: docs/content/manual/v1.6/manual.yml ================================================ --- headline: jq 1.6 Manual body: | A jq program is a "filter": it takes an input, and produces an output. There are a lot of builtin filters for extracting a particular field of an object, or converting a number to a string, or various other standard tasks. Filters can be combined in various ways - you can pipe the output of one filter into another filter, or collect the output of a filter into an array. Some filters produce multiple results, for instance there's one that produces all the elements of its input array. Piping that filter into a second runs the second filter for each element of the array. Generally, things that would be done with loops and iteration in other languages are just done by gluing filters together in jq. It's important to remember that every filter has an input and an output. Even literals like "hello" or 42 are filters - they take an input but always produce the same literal as output. Operations that combine two filters, like addition, generally feed the same input to both and combine the results. So, you can implement an averaging filter as `add / length` - feeding the input array both to the `add` filter and the `length` filter and then performing the division. But that's getting ahead of ourselves. :) Let's start with something simpler: manpage_intro: | jq(1) -- Command-line JSON processor ==================================== ## SYNOPSIS `jq` [...] [...] `jq` can transform JSON in various ways, by selecting, iterating, reducing and otherwise mangling JSON documents. For instance, running the command `jq 'map(.price) | add'` will take an array of JSON objects as input and return the sum of their "price" fields. `jq` can accept text input as well, but by default, `jq` reads a stream of JSON entities (including numbers and other literals) from `stdin`. Whitespace is only needed to separate entities such as 1 and 2, and true and false. One or more may be specified, in which case `jq` will read input from those instead. The are described in the [INVOKING JQ] section; they mostly concern input and output formatting. The is written in the jq language and specifies how to transform the input file or document. ## FILTERS manpage_epilogue: | ## BUGS Presumably. Report them or discuss them at: https://github.com/jqlang/jq/issues ## AUTHOR Stephen Dolan `` sections: - title: Invoking jq body: | jq filters run on a stream of JSON data. The input to jq is parsed as a sequence of whitespace-separated JSON values which are passed through the provided filter one at a time. The output(s) of the filter are written to standard output, as a sequence of newline-separated JSON data. Note: it is important to mind the shell's quoting rules. As a general rule it's best to always quote (with single-quote characters) the jq program, as too many characters with special meaning to jq are also shell meta-characters. For example, `jq "foo"` will fail on most Unix shells because that will be the same as `jq foo`, which will generally fail because `foo is not defined`. When using the Windows command shell (cmd.exe) it's best to use double quotes around your jq program when given on the command-line (instead of the `-f program-file` option), but then double-quotes in the jq program need backslash escaping. When using the Powershell (`powershell.exe`) or the Powershell Core (`pwsh`/`pwsh.exe`), use single-quote characters around the jq program and backslash-escaped double-quotes (`\"`) inside the jq program. * Unix shells: `jq '.["foo"]'` * Powershell: `jq '.[\"foo\"]'` * Windows command shell: `jq ".[\"foo\"]"` You can affect how jq reads and writes its input and output using some command-line options: * `--null-input` / `-n`: Don't read any input at all. Instead, the filter is run once using `null` as the input. This is useful when using jq as a simple calculator or to construct JSON data from scratch. * `--raw-input` / `-R`: Don't parse the input as JSON. Instead, each line of text is passed to the filter as a string. If combined with `--slurp`, then the entire input is passed to the filter as a single long string. * `--slurp` / `-s`: Instead of running the filter for each JSON object in the input, read the entire input stream into a large array and run the filter just once. * `--compact-output` / `-c`: By default, jq pretty-prints JSON output. Using this option will result in more compact output by instead putting each JSON object on a single line. * `--raw-output` / `-r`: With this option, if the filter's result is a string then it will be written directly to standard output rather than being formatted as a JSON string with quotes. This can be useful for making jq filters talk to non-JSON-based systems. * `--join-output` / `-j`: Like `-r` but jq won't print a newline after each output. * `--ascii-output` / `-a`: jq usually outputs non-ASCII Unicode codepoints as UTF-8, even if the input specified them as escape sequences (like "\u03bc"). Using this option, you can force jq to produce pure ASCII output with every non-ASCII character replaced with the equivalent escape sequence. * `--sort-keys` / `-S`: Output the fields of each object with the keys in sorted order. * `--color-output` / `-C` and `--monochrome-output` / `-M`: By default, jq outputs colored JSON if writing to a terminal. You can force it to produce color even if writing to a pipe or a file using `-C`, and disable color with `-M`. Colors can be configured with the `JQ_COLORS` environment variable (see below). * `--tab`: Use a tab for each indentation level instead of two spaces. * `--indent n`: Use the given number of spaces (no more than 7) for indentation. * `--unbuffered`: Flush the output after each JSON object is printed (useful if you're piping a slow data source into jq and piping jq's output elsewhere). * `--stream`: Parse the input in streaming fashion, outputting arrays of path and leaf values (scalars and empty arrays or empty objects). For example, `"a"` becomes `[[],"a"]`, and `[[],"a",["b"]]` becomes `[[0],[]]`, `[[1],"a"]`, and `[[2,0],"b"]`. This is useful for processing very large inputs. Use this in conjunction with filtering and the `reduce` and `foreach` syntax to reduce large inputs incrementally. * `--seq`: Use the `application/json-seq` MIME type scheme for separating JSON texts in jq's input and output. This means that an ASCII RS (record separator) character is printed before each value on output and an ASCII LF (line feed) is printed after every output. Input JSON texts that fail to parse are ignored (but warned about), discarding all subsequent input until the next RS. This mode also parses the output of jq without the `--seq` option. * `-f filename` / `--from-file filename`: Read filter from the file rather than from a command line, like awk's -f option. You can also use '#' to make comments. * `-L directory`: Prepend `directory` to the search list for modules. If this option is used then no builtin search list is used. See the section on modules below. * `--arg name value`: This option passes a value to the jq program as a predefined variable. If you run jq with `--arg foo bar`, then `$foo` is available in the program and has the value `"bar"`. Note that `value` will be treated as a string, so `--arg foo 123` will bind `$foo` to `"123"`. Named arguments are also available to the jq program as `$ARGS.named`. * `--argjson name JSON-text`: This option passes a JSON-encoded value to the jq program as a predefined variable. If you run jq with `--argjson foo 123`, then `$foo` is available in the program and has the value `123`. * `--slurpfile variable-name filename`: This option reads all the JSON texts in the named file and binds an array of the parsed JSON values to the given global variable. If you run jq with `--slurpfile foo bar`, then `$foo` is available in the program and has an array whose elements correspond to the texts in the file named `bar`. * `--rawfile variable-name filename`: This option reads in the named file and binds its content to the given global variable. If you run jq with `--rawfile foo bar`, then `$foo` is available in the program and has a string whose content is set to the text in the file named `bar`. * `--argfile variable-name filename`: Do not use. Use `--slurpfile` instead. (This option is like `--slurpfile`, but when the file has just one text, then that is used, else an array of texts is used as in `--slurpfile`.) * `--args`: Remaining arguments are positional string arguments. These are available to the jq program as `$ARGS.positional[]`. * `--jsonargs`: Remaining arguments are positional JSON text arguments. These are available to the jq program as `$ARGS.positional[]`. * `--exit-status` / `-e`: Sets the exit status of jq to 0 if the last output value was neither `false` nor `null`, 1 if the last output value was either `false` or `null`, or 4 if no valid result was ever produced. Normally jq exits with 2 if there was any usage problem or system error, 3 if there was a jq program compile error, or 0 if the jq program ran. Another way to set the exit status is with the `halt_error` builtin function. * `--version` / `-V`: Output the jq version and exit with zero. * `--help` / `-h`: Output the jq help and exit with zero. * `--run-tests [filename]`: Runs the tests in the given file or standard input. This must be the last option given and does not honor all preceding options. The input consists of comment lines, empty lines, and program lines followed by one input line, as many lines of output as are expected (one per output), and a terminating empty line. Compilation failure tests start with a line containing only `%%FAIL`, then a line containing the program to compile, then a line containing an error message to compare to the actual. Be warned that this option can change backwards-incompatibly. - title: Basic filters entries: - title: "Identity: `.`" body: | The absolute simplest filter is `.` . This is a filter that takes its input and produces it unchanged as output. That is, this is the identity operator. Since jq by default pretty-prints all output, this trivial program can be a useful way of formatting JSON output from, say, `curl`. examples: - program: '.' input: '"Hello, world!"' output: ['"Hello, world!"'] - title: "Object Identifier-Index: `.foo`, `.foo.bar`" body: | The simplest *useful* filter is `.foo`. When given a JSON object (aka dictionary or hash) as input, it produces the value at the key "foo", or null if there's none present. A filter of the form `.foo.bar` is equivalent to `.foo|.bar`. This syntax only works for simple, identifier-like keys, that is, keys that are all made of alphanumeric characters and underscore, and which do not start with a digit. If the key contains special characters or starts with a digit, you need to surround it with double quotes like this: `."foo$"`, or else `.["foo$"]`. For example `.["foo::bar"]` and `.["foo.bar"]` work while `.foo::bar` does not, and `.foo.bar` means `.["foo"].["bar"]`. examples: - program: '.foo' input: '{"foo": 42, "bar": "less interesting data"}' output: ['42'] - program: '.foo' input: '{"notfoo": true, "alsonotfoo": false}' output: ['null'] - program: '.["foo"]' input: '{"foo": 42}' output: ['42'] - title: "Optional Object Identifier-Index: `.foo?`" body: | Just like `.foo`, but does not output an error when `.` is not an object. examples: - program: '.foo?' input: '{"foo": 42, "bar": "less interesting data"}' output: ['42'] - program: '.foo?' input: '{"notfoo": true, "alsonotfoo": false}' output: ['null'] - program: '.["foo"]?' input: '{"foo": 42}' output: ['42'] - program: '[.foo?]' input: '[1,2]' output: ['[]'] - title: "Object Index: `.[]`" body: | You can also look up fields of an object using syntax like `.["foo"]` (`.foo` above is a shorthand version of this, but only for identifier-like strings). - title: "Array Index: `.[]`" body: | When the index value is an integer, `.[]` can index arrays. Arrays are zero-based, so `.[2]` returns the third element. Negative indices are allowed, with -1 referring to the last element, -2 referring to the next to last element, and so on. examples: - program: '.[0]' input: '[{"name":"JSON", "good":true}, {"name":"XML", "good":false}]' output: ['{"name":"JSON", "good":true}'] - program: '.[2]' input: '[{"name":"JSON", "good":true}, {"name":"XML", "good":false}]' output: ['null'] - program: '.[-2]' input: '[1,2,3]' output: ['2'] - title: "Array/String Slice: `.[:]`" body: | The `.[:]` syntax can be used to return a subarray of an array or substring of a string. The array returned by `.[10:15]` will be of length 5, containing the elements from index 10 (inclusive) to index 15 (exclusive). Either index may be negative (in which case it counts backwards from the end of the array), or omitted (in which case it refers to the start or end of the array). Indices are zero-based. examples: - program: '.[2:4]' input: '["a","b","c","d","e"]' output: ['["c", "d"]'] - program: '.[2:4]' input: '"abcdefghi"' output: ['"cd"'] - program: '.[:3]' input: '["a","b","c","d","e"]' output: ['["a", "b", "c"]'] - program: '.[-2:]' input: '["a","b","c","d","e"]' output: ['["d", "e"]'] - title: "Array/Object Value Iterator: `.[]`" body: | If you use the `.[index]` syntax, but omit the index entirely, it will return *all* of the elements of an array. Running `.[]` with the input `[1,2,3]` will produce the numbers as three separate results, rather than as a single array. A filter of the form `.foo[]` is equivalent to `.foo | .[]`. You can also use this on an object, and it will return all the values of the object. examples: - program: '.[]' input: '[{"name":"JSON", "good":true}, {"name":"XML", "good":false}]' output: - '{"name":"JSON", "good":true}' - '{"name":"XML", "good":false}' - program: '.[]' input: '[]' output: [] - program: '.foo[]' input: '{"foo":[1,2,3]}' output: ['1','2','3'] - program: '.[]' input: '{"a": 1, "b": 1}' output: ['1', '1'] - title: "`.[]?`" body: | Like `.[]`, but no errors will be output if . is not an array or object. A filter of the form `.foo[]?` is equivalent to `.foo | .[]?`. - title: "Comma: `,`" body: | If two filters are separated by a comma, then the same input will be fed into both and the two filters' output value streams will be concatenated in order: first, all of the outputs produced by the left expression, and then all of the outputs produced by the right. For instance, filter `.foo, .bar`, produces both the "foo" fields and "bar" fields as separate outputs. examples: - program: '.foo, .bar' input: '{"foo": 42, "bar": "something else", "baz": true}' output: ['42', '"something else"'] - program: ".user, .projects[]" input: '{"user":"stedolan", "projects": ["jq", "wikiflow"]}' output: ['"stedolan"', '"jq"', '"wikiflow"'] - program: '.[4,2]' input: '["a","b","c","d","e"]' output: ['"e"', '"c"'] - title: "Pipe: `|`" body: | The | operator combines two filters by feeding the output(s) of the one on the left into the input of the one on the right. It's pretty much the same as the Unix shell's pipe, if you're used to that. If the one on the left produces multiple results, the one on the right will be run for each of those results. So, the expression `.[] | .foo` retrieves the "foo" field of each element of the input array. Note that `.a.b.c` is the same as `.a | .b | .c`. Note too that `.` is the input value at the particular stage in a "pipeline", specifically: where the `.` expression appears. Thus `.a | . | .b` is the same as `.a.b`, as the `.` in the middle refers to whatever value `.a` produced. examples: - program: '.[] | .name' input: '[{"name":"JSON", "good":true}, {"name":"XML", "good":false}]' output: ['"JSON"', '"XML"'] - title: "Parenthesis" body: | Parenthesis work as a grouping operator just as in any typical programming language. examples: - program: '(. + 2) * 5' input: '1' output: ['15'] - title: Types and Values body: | jq supports the same set of datatypes as JSON - numbers, strings, booleans, arrays, objects (which in JSON-speak are hashes with only string keys), and "null". Booleans, null, strings and numbers are written the same way as in JSON. Just like everything else in jq, these simple values take an input and produce an output - `42` is a valid jq expression that takes an input, ignores it, and returns 42 instead. entries: - title: "Array construction: `[]`" body: | As in JSON, `[]` is used to construct arrays, as in `[1,2,3]`. The elements of the arrays can be any jq expression, including a pipeline. All of the results produced by all of the expressions are collected into one big array. You can use it to construct an array out of a known quantity of values (as in `[.foo, .bar, .baz]`) or to "collect" all the results of a filter into an array (as in `[.items[].name]`) Once you understand the "," operator, you can look at jq's array syntax in a different light: the expression `[1,2,3]` is not using a built-in syntax for comma-separated arrays, but is instead applying the `[]` operator (collect results) to the expression 1,2,3 (which produces three different results). If you have a filter `X` that produces four results, then the expression `[X]` will produce a single result, an array of four elements. examples: - program: "[.user, .projects[]]" input: '{"user":"stedolan", "projects": ["jq", "wikiflow"]}' output: ['["stedolan", "jq", "wikiflow"]'] - program: "[ .[] | . * 2]" input: '[1, 2, 3]' output: ['[2, 4, 6]'] - title: "Object Construction: `{}`" body: | Like JSON, `{}` is for constructing objects (aka dictionaries or hashes), as in: `{"a": 42, "b": 17}`. If the keys are "identifier-like", then the quotes can be left off, as in `{a:42, b:17}`. Keys generated by expressions need to be parenthesized, e.g., `{("a"+"b"):59}`. The value can be any expression (although you may need to wrap it in parentheses if it's a complicated one), which gets applied to the {} expression's input (remember, all filters have an input and an output). {foo: .bar} will produce the JSON object `{"foo": 42}` if given the JSON object `{"bar":42, "baz":43}` as its input. You can use this to select particular fields of an object: if the input is an object with "user", "title", "id", and "content" fields and you just want "user" and "title", you can write {user: .user, title: .title} Because that is so common, there's a shortcut syntax for it: `{user, title}`. If one of the expressions produces multiple results, multiple dictionaries will be produced. If the input's {"user":"stedolan","titles":["JQ Primer", "More JQ"]} then the expression {user, title: .titles[]} will produce two outputs: {"user":"stedolan", "title": "JQ Primer"} {"user":"stedolan", "title": "More JQ"} Putting parentheses around the key means it will be evaluated as an expression. With the same input as above, {(.user): .titles} produces {"stedolan": ["JQ Primer", "More JQ"]} examples: - program: '{user, title: .titles[]}' input: '{"user":"stedolan","titles":["JQ Primer", "More JQ"]}' output: - '{"user":"stedolan", "title": "JQ Primer"}' - '{"user":"stedolan", "title": "More JQ"}' - program: '{(.user): .titles}' input: '{"user":"stedolan","titles":["JQ Primer", "More JQ"]}' output: ['{"stedolan": ["JQ Primer", "More JQ"]}'] - title: "Recursive Descent: `..`" body: | Recursively descends `.`, producing every value. This is the same as the zero-argument `recurse` builtin (see below). This is intended to resemble the XPath `//` operator. Note that `..a` does not work; use `.. | .a` instead. In the example below we use `.. | .a?` to find all the values of object keys "a" in any object found "below" `.`. This is particularly useful in conjunction with `path(EXP)` (also see below) and the `?` operator. examples: - program: '.. | .a?' input: '[[{"a":1}]]' output: ['1'] - title: Builtin operators and functions body: | Some jq operators (for instance, `+`) do different things depending on the type of their arguments (arrays, numbers, etc.). However, jq never does implicit type conversions. If you try to add a string to an object you'll get an error message and no result. entries: - title: "Addition: `+`" body: | The operator `+` takes two filters, applies them both to the same input, and adds the results together. What "adding" means depends on the types involved: - **Numbers** are added by normal arithmetic. - **Arrays** are added by being concatenated into a larger array. - **Strings** are added by being joined into a larger string. - **Objects** are added by merging, that is, inserting all the key-value pairs from both objects into a single combined object. If both objects contain a value for the same key, the object on the right of the `+` wins. (For recursive merge use the `*` operator.) `null` can be added to any value, and returns the other value unchanged. examples: - program: '.a + 1' input: '{"a": 7}' output: ['8'] - program: '.a + .b' input: '{"a": [1,2], "b": [3,4]}' output: ['[1,2,3,4]'] - program: '.a + null' input: '{"a": 1}' output: ['1'] - program: '.a + 1' input: '{}' output: ['1'] - program: '{a: 1} + {b: 2} + {c: 3} + {a: 42}' input: 'null' output: ['{"a": 42, "b": 2, "c": 3}'] - title: "Subtraction: `-`" body: | As well as normal arithmetic subtraction on numbers, the `-` operator can be used on arrays to remove all occurrences of the second array's elements from the first array. examples: - program: '4 - .a' input: '{"a":3}' output: ['1'] - program: . - ["xml", "yaml"] input: '["xml", "yaml", "json"]' output: ['["json"]'] - title: "Multiplication, division, modulo: `*`, `/`, `%`" body: | These infix operators behave as expected when given two numbers. Division by zero raises an error. `x % y` computes x modulo y. Multiplying a string by a number produces the concatenation of that string that many times. `"x" * 0` produces **null**. Dividing a string by another splits the first using the second as separators. Multiplying two objects will merge them recursively: this works like addition but if both objects contain a value for the same key, and the values are objects, the two are merged with the same strategy. examples: - program: '10 / . * 3' input: '5' output: ['6'] - program: '. / ", "' input: '"a, b,c,d, e"' output: ['["a","b,c,d","e"]'] - program: '{"k": {"a": 1, "b": 2}} * {"k": {"a": 0,"c": 3}}' input: 'null' output: ['{"k": {"a": 0, "b": 2, "c": 3}}'] - program: '.[] | (1 / .)?' input: '[1,0,-1]' output: ['1', '-1'] - title: "`length`" body: | The builtin function `length` gets the length of various different types of value: - The length of a **string** is the number of Unicode codepoints it contains (which will be the same as its JSON-encoded length in bytes if it's pure ASCII). - The length of a **number** is its absolute value. - The length of an **array** is the number of elements. - The length of an **object** is the number of key-value pairs. - The length of **null** is zero. - It is an error to use `length` on a **boolean**. examples: - program: '.[] | length' input: '[[1,2], "string", {"a":2}, null, -5]' output: ['2', '6', '1', '0', '5'] - title: "`utf8bytelength`" body: | The builtin function `utf8bytelength` outputs the number of bytes used to encode a string in UTF-8. examples: - program: 'utf8bytelength' input: '"\u03bc"' output: ['2'] - title: "`keys`, `keys_unsorted`" body: | The builtin function `keys`, when given an object, returns its keys in an array. The keys are sorted "alphabetically", by unicode codepoint order. This is not an order that makes particular sense in any particular language, but you can count on it being the same for any two objects with the same set of keys, regardless of locale settings. When `keys` is given an array, it returns the valid indices for that array: the integers from 0 to length-1. The `keys_unsorted` function is just like `keys`, but if the input is an object then the keys will not be sorted, instead the keys will roughly be in insertion order. examples: - program: 'keys' input: '{"abc": 1, "abcd": 2, "Foo": 3}' output: ['["Foo", "abc", "abcd"]'] - program: 'keys' input: '[42,3,35]' output: ['[0,1,2]'] - title: "`has(key)`" body: | The builtin function `has` returns whether the input object has the given key, or the input array has an element at the given index. `has($key)` has the same effect as checking whether `$key` is a member of the array returned by `keys`, although `has` will be faster. examples: - program: 'map(has("foo"))' input: '[{"foo": 42}, {}]' output: ['[true, false]'] - program: 'map(has(2))' input: '[[0,1], ["a","b","c"]]' output: ['[false, true]'] - title: "`in`" body: | The builtin function `in` returns whether or not the input key is in the given object, or the input index corresponds to an element in the given array. It is, essentially, an inversed version of `has`. examples: - program: '.[] | in({"foo": 42})' input: '["foo", "bar"]' output: ['true', 'false'] - program: 'map(in([0,1]))' input: '[2, 0]' output: ['[false, true]'] - title: "`map(f)`, `map_values(f)`" body: | For any filter `f`, `map(f)` will run that filter for each element of the input array, and return the outputs in a new array. `map(.+1)` will increment each element of an array of numbers. Similarly, `map_values(f)` will run that filter for each element, but it will return an object when an object is passed. `map(f)` is equivalent to `[.[] | f]`. In fact, this is how it's defined. Similarly, `map_values(f)` is defined as `.[] |= f`. examples: - program: 'map(.+1)' input: '[1,2,3]' output: ['[2,3,4]'] - program: 'map_values(.+1)' input: '{"a": 1, "b": 2, "c": 3}' output: ['{"a": 2, "b": 3, "c": 4}'] - title: "`path(path_expression)`" body: | Outputs array representations of the given path expression in `.`. The outputs are arrays of strings (object keys) and/or numbers (array indices). Path expressions are jq expressions like `.a`, but also `.[]`. There are two types of path expressions: ones that can match exactly, and ones that cannot. For example, `.a.b.c` is an exact match path expression, while `.a[].b` is not. `path(exact_path_expression)` will produce the array representation of the path expression even if it does not exist in `.`, if `.` is `null` or an array or an object. `path(pattern)` will produce array representations of the paths matching `pattern` if the paths exist in `.`. Note that the path expressions are not different from normal expressions. The expression `path(..|select(type=="boolean"))` outputs all the paths to boolean values in `.`, and only those paths. examples: - program: 'path(.a[0].b)' input: 'null' output: ['["a",0,"b"]'] - program: '[path(..)]' input: '{"a":[{"b":1}]}' output: ['[[],["a"],["a",0],["a",0,"b"]]'] - title: "`del(path_expression)`" body: | The builtin function `del` removes a key and its corresponding value from an object. examples: - program: 'del(.foo)' input: '{"foo": 42, "bar": 9001, "baz": 42}' output: ['{"bar": 9001, "baz": 42}'] - program: 'del(.[1, 2])' input: '["foo", "bar", "baz"]' output: ['["foo"]'] - title: "`getpath(PATHS)`" body: | The builtin function `getpath` outputs the values in `.` found at each path in `PATHS`. examples: - program: 'getpath(["a","b"])' input: 'null' output: ['null'] - program: '[getpath(["a","b"], ["a","c"])]' input: '{"a":{"b":0, "c":1}}' output: ['[0, 1]'] - title: "`setpath(PATHS; VALUE)`" body: | The builtin function `setpath` sets the `PATHS` in `.` to `VALUE`. examples: - program: 'setpath(["a","b"]; 1)' input: 'null' output: ['{"a": {"b": 1}}'] - program: 'setpath(["a","b"]; 1)' input: '{"a":{"b":0}}' output: ['{"a": {"b": 1}}'] - program: 'setpath([0,"a"]; 1)' input: 'null' output: ['[{"a":1}]'] - title: "`delpaths(PATHS)`" body: | The builtin function `delpaths` sets the `PATHS` in `.`. `PATHS` must be an array of paths, where each path is an array of strings and numbers. examples: - program: 'delpaths([["a","b"]])' input: '{"a":{"b":1},"x":{"y":2}}' output: ['{"a":{},"x":{"y":2}}'] - title: "`to_entries`, `from_entries`, `with_entries(f)`" body: | These functions convert between an object and an array of key-value pairs. If `to_entries` is passed an object, then for each `k: v` entry in the input, the output array includes `{"key": k, "value": v}`. `from_entries` does the opposite conversion, and `with_entries(f)` is a shorthand for `to_entries | map(f) | from_entries`, useful for doing some operation to all keys and values of an object. `from_entries` accepts `"key"`, `"Key"`, `"name"`, `"Name"`, `"value"`, and `"Value"` as keys. examples: - program: 'to_entries' input: '{"a": 1, "b": 2}' output: ['[{"key":"a", "value":1}, {"key":"b", "value":2}]'] - program: 'from_entries' input: '[{"key":"a", "value":1}, {"key":"b", "value":2}]' output: ['{"a": 1, "b": 2}'] - program: 'with_entries(.key |= "KEY_" + .)' input: '{"a": 1, "b": 2}' output: ['{"KEY_a": 1, "KEY_b": 2}'] - title: "`select(boolean_expression)`" body: | The function `select(f)` produces its input unchanged if `f` returns true for that input, and produces no output otherwise. It's useful for filtering lists: `[1,2,3] | map(select(. >= 2))` will give you `[2,3]`. examples: - program: 'map(select(. >= 2))' input: '[1,5,3,0,7]' output: ['[5,3,7]'] - program: '.[] | select(.id == "second")' input: '[{"id": "first", "val": 1}, {"id": "second", "val": 2}]' output: ['{"id": "second", "val": 2}'] - title: "`arrays`, `objects`, `iterables`, `booleans`, `numbers`, `normals`, `finites`, `strings`, `nulls`, `values`, `scalars`" body: | These built-ins select only inputs that are arrays, objects, iterables (arrays or objects), booleans, numbers, normal numbers, finite numbers, strings, null, non-null values, and non-iterables, respectively. examples: - program: '.[]|numbers' input: '[[],{},1,"foo",null,true,false]' output: ['1'] - title: "`empty`" body: | `empty` returns no results. None at all. Not even `null`. It's useful on occasion. You'll know if you need it :) examples: - program: '1, empty, 2' input: 'null' output: ['1', '2'] - program: '[1,2,empty,3]' input: 'null' output: ['[1,2,3]'] - title: "`error`, `error(message)`" body: | Produces an error with the input value, or with the message given as the argument. Errors can be caught with try/catch; see below. When the error value is `null`, it produces nothing and works just like `empty`. So `[null | error]` and `[error(null)]` both emit `[]`. examples: - program: 'try error catch .' input: '"error message"' output: ['"error message"'] - program: 'try error("invalid value: \(.)") catch .' input: '42' output: ['"invalid value: 42"'] - title: "`halt`" body: | Stops the jq program with no further outputs. jq will exit with exit status `0`. - title: "`halt_error`, `halt_error(exit_code)`" body: | Stops the jq program with no further outputs. The input will be printed on `stderr` as raw output (i.e., strings will not have double quotes) with no decoration, not even a newline. The given `exit_code` (defaulting to `5`) will be jq's exit status. For example, `"Error: something went wrong\n"|halt_error(1)`. - title: "`$__loc__`" body: | Produces an object with a "file" key and a "line" key, with the filename and line number where `$__loc__` occurs, as values. examples: - program: 'try error("\($__loc__)") catch .' input: 'null' output: ['"{\"file\":\"\",\"line\":1}"'] - title: "`paths`, `paths(node_filter)`, `leaf_paths`" body: | `paths` outputs the paths to all the elements in its input (except it does not output the empty list, representing . itself). `paths(f)` outputs the paths to any values for which `f` is `true`. That is, `paths(type == "number")` outputs the paths to all numeric values. `leaf_paths` is an alias of `paths(scalars)`; `leaf_paths` is *deprecated* and will be removed in the next major release. examples: - program: '[paths]' input: '[1,[[],{"a":2}]]' output: ['[[0],[1],[1,0],[1,1],[1,1,"a"]]'] - program: '[paths(type == "number")]' input: '[1,[[],{"a":2}]]' output: ['[[0],[1,1,"a"]]'] - title: "`add`" body: | The filter `add` takes as input an array, and produces as output the elements of the array added together. This might mean summed, concatenated or merged depending on the types of the elements of the input array - the rules are the same as those for the `+` operator (described above). If the input is an empty array, `add` returns `null`. examples: - program: add input: '["a","b","c"]' output: ['"abc"'] - program: add input: '[1, 2, 3]' output: ['6'] - program: add input: '[]' output: ["null"] - title: "`any`, `any(condition)`, `any(generator; condition)`" body: | The filter `any` takes as input an array of boolean values, and produces `true` as output if any of the elements of the array are `true`. If the input is an empty array, `any` returns `false`. The `any(condition)` form applies the given condition to the elements of the input array. The `any(generator; condition)` form applies the given condition to all the outputs of the given generator. examples: - program: any input: '[true, false]' output: ["true"] - program: any input: '[false, false]' output: ["false"] - program: any input: '[]' output: ["false"] - title: "`all`, `all(condition)`, `all(generator; condition)`" body: | The filter `all` takes as input an array of boolean values, and produces `true` as output if all of the elements of the array are `true`. The `all(condition)` form applies the given condition to the elements of the input array. The `all(generator; condition)` form applies the given condition to all the outputs of the given generator. If the input is an empty array, `all` returns `true`. examples: - program: all input: '[true, false]' output: ["false"] - program: all input: '[true, true]' output: ["true"] - program: all input: '[]' output: ["true"] - title: "`flatten`, `flatten(depth)`" body: | The filter `flatten` takes as input an array of nested arrays, and produces a flat array in which all arrays inside the original array have been recursively replaced by their values. You can pass an argument to it to specify how many levels of nesting to flatten. `flatten(2)` is like `flatten`, but going only up to two levels deep. examples: - program: flatten input: '[1, [2], [[3]]]' output: ["[1, 2, 3]"] - program: flatten(1) input: '[1, [2], [[3]]]' output: ["[1, 2, [3]]"] - program: flatten input: '[[]]' output: ["[]"] - program: flatten input: '[{"foo": "bar"}, [{"foo": "baz"}]]' output: ['[{"foo": "bar"}, {"foo": "baz"}]'] - title: "`range(upto)`, `range(from; upto)`, `range(from; upto; by)`" body: | The `range` function produces a range of numbers. `range(4; 10)` produces 6 numbers, from 4 (inclusive) to 10 (exclusive). The numbers are produced as separate outputs. Use `[range(4; 10)]` to get a range as an array. The one argument form generates numbers from 0 to the given number, with an increment of 1. The two argument form generates numbers from `from` to `upto` with an increment of 1. The three argument form generates numbers `from` to `upto` with an increment of `by`. examples: - program: 'range(2; 4)' input: 'null' output: ['2', '3'] - program: '[range(2; 4)]' input: 'null' output: ['[2,3]'] - program: '[range(4)]' input: 'null' output: ['[0,1,2,3]'] - program: '[range(0; 10; 3)]' input: 'null' output: ['[0,3,6,9]'] - program: '[range(0; 10; -1)]' input: 'null' output: ['[]'] - program: '[range(0; -5; -1)]' input: 'null' output: ['[0,-1,-2,-3,-4]'] - title: "`floor`" body: | The `floor` function returns the floor of its numeric input. examples: - program: 'floor' input: '3.14159' output: ['3'] - title: "`sqrt`" body: | The `sqrt` function returns the square root of its numeric input. examples: - program: 'sqrt' input: '9' output: ['3'] - title: "`tonumber`" body: | The `tonumber` function parses its input as a number. It will convert correctly-formatted strings to their numeric equivalent, leave numbers alone, and give an error on all other input. examples: - program: '.[] | tonumber' input: '[1, "1"]' output: ['1', '1'] - title: "`tostring`" body: | The `tostring` function prints its input as a string. Strings are left unchanged, and all other values are JSON-encoded. examples: - program: '.[] | tostring' input: '[1, "1", [1]]' output: ['"1"', '"1"', '"[1]"'] - title: "`type`" body: | The `type` function returns the type of its argument as a string, which is one of null, boolean, number, string, array or object. examples: - program: 'map(type)' input: '[0, false, [], {}, null, "hello"]' output: ['["number", "boolean", "array", "object", "null", "string"]'] - title: "`infinite`, `nan`, `isinfinite`, `isnan`, `isfinite`, `isnormal`" body: | Some arithmetic operations can yield infinities and "not a number" (NaN) values. The `isinfinite` builtin returns `true` if its input is infinite. The `isnan` builtin returns `true` if its input is a NaN. The `infinite` builtin returns a positive infinite value. The `nan` builtin returns a NaN. The `isnormal` builtin returns true if its input is a normal number. Note that division by zero raises an error. Currently most arithmetic operations operating on infinities, NaNs, and sub-normals do not raise errors. examples: - program: '.[] | (infinite * .) < 0' input: '[-1, 1]' output: ['true', 'false'] - program: 'infinite, nan | type' input: 'null' output: ['"number"', '"number"'] - title: "`sort`, `sort_by(path_expression)`" body: | The `sort` functions sorts its input, which must be an array. Values are sorted in the following order: * `null` * `false` * `true` * numbers * strings, in alphabetical order (by unicode codepoint value) * arrays, in lexical order * objects The ordering for objects is a little complex: first they're compared by comparing their sets of keys (as arrays in sorted order), and if their keys are equal then the values are compared key by key. `sort_by` may be used to sort by a particular field of an object, or by applying any jq filter. `sort_by(f)` compares two elements by comparing the result of `f` on each element. When `f` produces multiple values, it firstly compares the first values, and the second values if the first values are equal, and so on. examples: - program: 'sort' input: '[8,3,null,6]' output: ['[null,3,6,8]'] - program: 'sort_by(.foo)' input: '[{"foo":4, "bar":10}, {"foo":3, "bar":10}, {"foo":2, "bar":1}]' output: ['[{"foo":2, "bar":1}, {"foo":3, "bar":10}, {"foo":4, "bar":10}]'] - program: 'sort_by(.foo, .bar)' input: '[{"foo":4, "bar":10}, {"foo":3, "bar":20}, {"foo":2, "bar":1}, {"foo":3, "bar":10}]' output: ['[{"foo":2, "bar":1}, {"foo":3, "bar":10}, {"foo":3, "bar":20}, {"foo":4, "bar":10}]'] - title: "`group_by(path_expression)`" body: | `group_by(.foo)` takes as input an array, groups the elements having the same `.foo` field into separate arrays, and produces all of these arrays as elements of a larger array, sorted by the value of the `.foo` field. Any jq expression, not just a field access, may be used in place of `.foo`. The sorting order is the same as described in the `sort` function above. examples: - program: 'group_by(.foo)' input: '[{"foo":1, "bar":10}, {"foo":3, "bar":100}, {"foo":1, "bar":1}]' output: ['[[{"foo":1, "bar":10}, {"foo":1, "bar":1}], [{"foo":3, "bar":100}]]'] - title: "`min`, `max`, `min_by(path_exp)`, `max_by(path_exp)`" body: | Find the minimum or maximum element of the input array. The `min_by(path_exp)` and `max_by(path_exp)` functions allow you to specify a particular field or property to examine, e.g. `min_by(.foo)` finds the object with the smallest `foo` field. examples: - program: 'min' input: '[5,4,2,7]' output: ['2'] - program: 'max_by(.foo)' input: '[{"foo":1, "bar":14}, {"foo":2, "bar":3}]' output: ['{"foo":2, "bar":3}'] - title: "`unique`, `unique_by(path_exp)`" body: | The `unique` function takes as input an array and produces an array of the same elements, in sorted order, with duplicates removed. The `unique_by(path_exp)` function will keep only one element for each value obtained by applying the argument. Think of it as making an array by taking one element out of every group produced by `group`. examples: - program: 'unique' input: '[1,2,5,3,5,3,1,3]' output: ['[1,2,3,5]'] - program: 'unique_by(.foo)' input: '[{"foo": 1, "bar": 2}, {"foo": 1, "bar": 3}, {"foo": 4, "bar": 5}]' output: ['[{"foo": 1, "bar": 2}, {"foo": 4, "bar": 5}]'] - program: 'unique_by(length)' input: '["chunky", "bacon", "kitten", "cicada", "asparagus"]' output: ['["bacon", "chunky", "asparagus"]'] - title: "`reverse`" body: | This function reverses an array. examples: - program: 'reverse' input: '[1,2,3,4]' output: ['[4,3,2,1]'] - title: "`contains(element)`" body: | The filter `contains(b)` will produce true if b is completely contained within the input. A string B is contained in a string A if B is a substring of A. An array B is contained in an array A if all elements in B are contained in any element in A. An object B is contained in object A if all of the values in B are contained in the value in A with the same key. All other types are assumed to be contained in each other if they are equal. examples: - program: 'contains("bar")' input: '"foobar"' output: ['true'] - program: 'contains(["baz", "bar"])' input: '["foobar", "foobaz", "blarp"]' output: ['true'] - program: 'contains(["bazzzzz", "bar"])' input: '["foobar", "foobaz", "blarp"]' output: ['false'] - program: 'contains({foo: 12, bar: [{barp: 12}]})' input: '{"foo": 12, "bar":[1,2,{"barp":12, "blip":13}]}' output: ['true'] - program: 'contains({foo: 12, bar: [{barp: 15}]})' input: '{"foo": 12, "bar":[1,2,{"barp":12, "blip":13}]}' output: ['false'] - title: "`indices(s)`" body: | Outputs an array containing the indices in `.` where `s` occurs. The input may be an array, in which case if `s` is an array then the indices output will be those where all elements in `.` match those of `s`. examples: - program: 'indices(", ")' input: '"a,b, cd, efg, hijk"' output: ['[3,7,12]'] - program: 'indices(1)' input: '[0,1,2,1,3,1,4]' output: ['[1,3,5]'] - program: 'indices([1,2])' input: '[0,1,2,3,1,4,2,5,1,2,6,7]' output: ['[1,8]'] - title: "`index(s)`, `rindex(s)`" body: | Outputs the index of the first (`index`) or last (`rindex`) occurrence of `s` in the input. examples: - program: 'index(", ")' input: '"a,b, cd, efg, hijk"' output: ['3'] - program: 'index(1)' input: '[0,1,2,1,3,1,4]' output: ['1'] - program: 'index([1,2])' input: '[0,1,2,3,1,4,2,5,1,2,6,7]' output: ['1'] - program: 'rindex(", ")' input: '"a,b, cd, efg, hijk"' output: ['12'] - program: 'rindex(1)' input: '[0,1,2,1,3,1,4]' output: ['5'] - program: 'rindex([1,2])' input: '[0,1,2,3,1,4,2,5,1,2,6,7]' output: ['8'] - title: "`inside`" body: | The filter `inside(b)` will produce true if the input is completely contained within b. It is, essentially, an inversed version of `contains`. examples: - program: 'inside("foobar")' input: '"bar"' output: ['true'] - program: 'inside(["foobar", "foobaz", "blarp"])' input: '["baz", "bar"]' output: ['true'] - program: 'inside(["foobar", "foobaz", "blarp"])' input: '["bazzzzz", "bar"]' output: ['false'] - program: 'inside({"foo": 12, "bar":[1,2,{"barp":12, "blip":13}]})' input: '{"foo": 12, "bar": [{"barp": 12}]}' output: ['true'] - program: 'inside({"foo": 12, "bar":[1,2,{"barp":12, "blip":13}]})' input: '{"foo": 12, "bar": [{"barp": 15}]}' output: ['false'] - title: "`startswith(str)`" body: | Outputs `true` if . starts with the given string argument. examples: - program: '[.[]|startswith("foo")]' input: '["fo", "foo", "barfoo", "foobar", "barfoob"]' output: ['[false, true, false, true, false]'] - title: "`endswith(str)`" body: | Outputs `true` if . ends with the given string argument. examples: - program: '[.[]|endswith("foo")]' input: '["foobar", "barfoo"]' output: ['[false, true]'] - title: "`combinations`, `combinations(n)`" body: | Outputs all combinations of the elements of the arrays in the input array. If given an argument `n`, it outputs all combinations of `n` repetitions of the input array. examples: - program: 'combinations' input: '[[1,2], [3, 4]]' output: ['[1, 3]', '[1, 4]', '[2, 3]', '[2, 4]'] - program: 'combinations(2)' input: '[0, 1]' output: ['[0, 0]', '[0, 1]', '[1, 0]', '[1, 1]'] - title: "`ltrimstr(str)`" body: | Outputs its input with the given prefix string removed, if it starts with it. examples: - program: '[.[]|ltrimstr("foo")]' input: '["fo", "foo", "barfoo", "foobar", "afoo"]' output: ['["fo","","barfoo","bar","afoo"]'] - title: "`rtrimstr(str)`" body: | Outputs its input with the given suffix string removed, if it ends with it. examples: - program: '[.[]|rtrimstr("foo")]' input: '["fo", "foo", "barfoo", "foobar", "foob"]' output: ['["fo","","bar","foobar","foob"]'] - title: "`explode`" body: | Converts an input string into an array of the string's codepoint numbers. examples: - program: 'explode' input: '"foobar"' output: ['[102,111,111,98,97,114]'] - title: "`implode`" body: | The inverse of explode. examples: - program: 'implode' input: '[65, 66, 67]' output: ['"ABC"'] - title: "`split(str)`" body: | Splits an input string on the separator argument. examples: - program: 'split(", ")' input: '"a, b,c,d, e, "' output: ['["a","b,c,d","e",""]'] - title: "`join(str)`" body: | Joins the array of elements given as input, using the argument as separator. It is the inverse of `split`: that is, running `split("foo") | join("foo")` over any input string returns said input string. Numbers and booleans in the input are converted to strings. Null values are treated as empty strings. Arrays and objects in the input are not supported. examples: - program: 'join(", ")' input: '["a","b,c,d","e"]' output: ['"a, b,c,d, e"'] - program: 'join(" ")' input: '["a",1,2.3,true,null,false]' output: ['"a 1 2.3 true false"'] - title: "`ascii_downcase`, `ascii_upcase`" body: | Emit a copy of the input string with its alphabetic characters (a-z and A-Z) converted to the specified case. examples: - program: 'ascii_upcase' input: '"useful but not for é"' output: ['"USEFUL BUT NOT FOR é"'] - title: "`while(cond; update)`" body: | The `while(cond; update)` function allows you to repeatedly apply an update to `.` until `cond` is false. Note that `while(cond; update)` is internally defined as a recursive jq function. Recursive calls within `while` will not consume additional memory if `update` produces at most one output for each input. See advanced topics below. examples: - program: '[while(.<100; .*2)]' input: '1' output: ['[1,2,4,8,16,32,64]'] - title: "`until(cond; next)`" body: | The `until(cond; next)` function allows you to repeatedly apply the expression `next`, initially to `.` then to its own output, until `cond` is true. For example, this can be used to implement a factorial function (see below). Note that `until(cond; next)` is internally defined as a recursive jq function. Recursive calls within `until()` will not consume additional memory if `next` produces at most one output for each input. See advanced topics below. examples: - program: '[.,1]|until(.[0] < 1; [.[0] - 1, .[1] * .[0]])|.[1]' input: '4' output: ['24'] - title: "`recurse(f)`, `recurse`, `recurse(f; condition)`, `recurse_down`" body: | The `recurse(f)` function allows you to search through a recursive structure, and extract interesting data from all levels. Suppose your input represents a filesystem: {"name": "/", "children": [ {"name": "/bin", "children": [ {"name": "/bin/ls", "children": []}, {"name": "/bin/sh", "children": []}]}, {"name": "/home", "children": [ {"name": "/home/stephen", "children": [ {"name": "/home/stephen/jq", "children": []}]}]}]} Now suppose you want to extract all of the filenames present. You need to retrieve `.name`, `.children[].name`, `.children[].children[].name`, and so on. You can do this with: recurse(.children[]) | .name When called without an argument, `recurse` is equivalent to `recurse(.[]?)`. `recurse(f)` is identical to `recurse(f; true)` and can be used without concerns about recursion depth. `recurse(f; condition)` is a generator which begins by emitting . and then emits in turn .|f, .|f|f, .|f|f|f, ... so long as the computed value satisfies the condition. For example, to generate all the integers, at least in principle, one could write `recurse(.+1; true)`. For legacy reasons, `recurse_down` exists as an alias to calling `recurse` without arguments. This alias is considered *deprecated* and will be removed in the next major release. The recursive calls in `recurse` will not consume additional memory whenever `f` produces at most a single output for each input. examples: - program: 'recurse(.foo[])' input: '{"foo":[{"foo": []}, {"foo":[{"foo":[]}]}]}' output: - '{"foo":[{"foo":[]},{"foo":[{"foo":[]}]}]}' - '{"foo":[]}' - '{"foo":[{"foo":[]}]}' - '{"foo":[]}' - program: 'recurse' input: '{"a":0,"b":[1]}' output: - '{"a":0,"b":[1]}' - '0' - '[1]' - '1' - program: 'recurse(. * .; . < 20)' input: '2' output: ['2', '4', '16'] - title: "`walk(f)`" body: | The `walk(f)` function applies f recursively to every component of the input entity. When an array is encountered, f is first applied to its elements and then to the array itself; when an object is encountered, f is first applied to all the values and then to the object. In practice, f will usually test the type of its input, as illustrated in the following examples. The first example highlights the usefulness of processing the elements of an array of arrays before processing the array itself. The second example shows how all the keys of all the objects within the input can be considered for alteration. examples: - program: 'walk(if type == "array" then sort else . end)' input: '[[4, 1, 7], [8, 5, 2], [3, 6, 9]]' output: - '[[1,4,7],[2,5,8],[3,6,9]]' - program: 'walk( if type == "object" then with_entries( .key |= sub( "^_+"; "") ) else . end )' input: '[ { "_a": { "__b": 2 } } ]' output: - '[{"a":{"b":2}}]' - title: "`$ENV`, `env`" body: | `$ENV` is an object representing the environment variables as set when the jq program started. `env` outputs an object representing jq's current environment. At the moment there is no builtin for setting environment variables. examples: - program: '$ENV.PAGER' input: 'null' output: ['"less"'] - program: 'env.PAGER' input: 'null' output: ['"less"'] - title: "`transpose`" body: | Transpose a possibly jagged matrix (an array of arrays). Rows are padded with nulls so the result is always rectangular. examples: - program: 'transpose' input: '[[1], [2,3]]' output: ['[[1,2],[null,3]]'] - title: "`bsearch(x)`" body: | `bsearch(x)` conducts a binary search for x in the input array. If the input is sorted and contains x, then `bsearch(x)` will return its index in the array; otherwise, if the array is sorted, it will return (-1 - ix) where ix is an insertion point such that the array would still be sorted after the insertion of x at ix. If the array is not sorted, `bsearch(x)` will return an integer that is probably of no interest. examples: - program: 'bsearch(0)' input: '[0,1]' output: ['0'] - program: 'bsearch(0)' input: '[1,2,3]' output: ['-1'] - program: 'bsearch(4) as $ix | if $ix < 0 then .[-(1+$ix)] = 4 else . end' input: '[1,2,3]' output: ['[1,2,3,4]'] - title: "String interpolation: `\\(exp)`" body: | Inside a string, you can put an expression inside parens after a backslash. Whatever the expression returns will be interpolated into the string. examples: - program: '"The input was \(.), which is one less than \(.+1)"' input: '42' output: ['"The input was 42, which is one less than 43"'] - title: "Convert to/from JSON" body: | The `tojson` and `fromjson` builtins dump values as JSON texts or parse JSON texts into values, respectively. The `tojson` builtin differs from `tostring` in that `tostring` returns strings unmodified, while `tojson` encodes strings as JSON strings. examples: - program: '[.[]|tostring]' input: '[1, "foo", ["foo"]]' output: ['["1","foo","[\"foo\"]"]'] - program: '[.[]|tojson]' input: '[1, "foo", ["foo"]]' output: ['["1","\"foo\"","[\"foo\"]"]'] - program: '[.[]|tojson|fromjson]' input: '[1, "foo", ["foo"]]' output: ['[1,"foo",["foo"]]'] - title: "Format strings and escaping" body: | The `@foo` syntax is used to format and escape strings, which is useful for building URLs, documents in a language like HTML or XML, and so forth. `@foo` can be used as a filter on its own, the possible escapings are: * `@text`: Calls `tostring`, see that function for details. * `@json`: Serializes the input as JSON. * `@html`: Applies HTML/XML escaping, by mapping the characters `<>&'"` to their entity equivalents `<`, `>`, `&`, `'`, `"`. * `@uri`: Applies percent-encoding, by mapping all reserved URI characters to a `%XX` sequence. * `@csv`: The input must be an array, and it is rendered as CSV with double quotes for strings, and quotes escaped by repetition. * `@tsv`: The input must be an array, and it is rendered as TSV (tab-separated values). Each input array will be printed as a single line. Fields are separated by a single tab (ascii `0x09`). Input characters line-feed (ascii `0x0a`), carriage-return (ascii `0x0d`), tab (ascii `0x09`) and backslash (ascii `0x5c`) will be output as escape sequences `\n`, `\r`, `\t`, `\\` respectively. * `@sh`: The input is escaped suitable for use in a command-line for a POSIX shell. If the input is an array, the output will be a series of space-separated strings. * `@base64`: The input is converted to base64 as specified by RFC 4648. * `@base64d`: The inverse of `@base64`, input is decoded as specified by RFC 4648. Note\: If the decoded string is not UTF-8, the results are undefined. This syntax can be combined with string interpolation in a useful way. You can follow a `@foo` token with a string literal. The contents of the string literal will *not* be escaped. However, all interpolations made inside that string literal will be escaped. For instance, @uri "https://www.google.com/search?q=\(.search)" will produce the following output for the input `{"search":"what is jq?"}`: "https://www.google.com/search?q=what%20is%20jq%3F" Note that the slashes, question mark, etc. in the URL are not escaped, as they were part of the string literal. examples: - program: '@html' input: '"This works if x < y"' output: ['"This works if x < y"'] - program: '@sh "echo \(.)"' input: "\"O'Hara's Ale\"" output: ["\"echo 'O'\\\\''Hara'\\\\''s Ale'\""] - program: '@base64' input: '"This is a message"' output: ['"VGhpcyBpcyBhIG1lc3NhZ2U="'] - program: '@base64d' input: '"VGhpcyBpcyBhIG1lc3NhZ2U="' output: ['"This is a message"'] - title: "Dates" body: | jq provides some basic date handling functionality, with some high-level and low-level builtins. In all cases these builtins deal exclusively with time in UTC. The `fromdateiso8601` builtin parses datetimes in the ISO 8601 format to a number of seconds since the Unix epoch (1970-01-01T00:00:00Z). The `todateiso8601` builtin does the inverse. The `fromdate` builtin parses datetime strings. Currently `fromdate` only supports ISO 8601 datetime strings, but in the future it will attempt to parse datetime strings in more formats. The `todate` builtin is an alias for `todateiso8601`. The `now` builtin outputs the current time, in seconds since the Unix epoch. Low-level jq interfaces to the C-library time functions are also provided: `strptime`, `strftime`, `strflocaltime`, `mktime`, `gmtime`, and `localtime`. Refer to your host operating system's documentation for the format strings used by `strptime` and `strftime`. Note: these are not necessarily stable interfaces in jq, particularly as to their localization functionality. The `gmtime` builtin consumes a number of seconds since the Unix epoch and outputs a "broken down time" representation of Greenwich Mean Time as an array of numbers representing (in this order): the year, the month (zero-based), the day of the month (one-based), the hour of the day, the minute of the hour, the second of the minute, the day of the week, and the day of the year -- all one-based unless otherwise stated. The day of the week number may be wrong on some systems for dates before March 1st 1900, or after December 31 2099. The `localtime` builtin works like the `gmtime` builtin, but using the local timezone setting. The `mktime` builtin consumes "broken down time" representations of time output by `gmtime` and `strptime`. The `strptime(fmt)` builtin parses input strings matching the `fmt` argument. The output is in the "broken down time" representation consumed by `mktime` and output by `gmtime`. The `strftime(fmt)` builtin formats a time (GMT) with the given format. The `strflocaltime` does the same, but using the local timezone setting. The format strings for `strptime` and `strftime` are described in typical C library documentation. The format string for ISO 8601 datetime is `"%Y-%m-%dT%H:%M:%SZ"`. jq may not support some or all of this date functionality on some systems. In particular, the `%u` and `%j` specifiers for `strptime(fmt)` are not supported on macOS. examples: - program: 'fromdate' input: '"2015-03-05T23:51:47Z"' output: ['1425599507'] - program: 'strptime("%Y-%m-%dT%H:%M:%SZ")' input: '"2015-03-05T23:51:47Z"' output: ['[2015,2,5,23,51,47,4,63]'] - program: 'strptime("%Y-%m-%dT%H:%M:%SZ")|mktime' input: '"2015-03-05T23:51:47Z"' output: ['1425599507'] - title: "SQL-Style Operators" body: | jq provides a few SQL-style operators. * INDEX(stream; index_expression): This builtin produces an object whose keys are computed by the given index expression applied to each value from the given stream. * JOIN($idx; stream; idx_expr; join_expr): This builtin joins the values from the given stream to the given index. The index's keys are computed by applying the given index expression to each value from the given stream. An array of the value in the stream and the corresponding value from the index is fed to the given join expression to produce each result. * JOIN($idx; stream; idx_expr): Same as `JOIN($idx; stream; idx_expr; .)`. * JOIN($idx; idx_expr): This builtin joins the input `.` to the given index, applying the given index expression to `.` to compute the index key. The join operation is as described above. * IN(s): This builtin outputs `true` if `.` appears in the given stream, otherwise it outputs `false`. * IN(source; s): This builtin outputs `true` if any value in the source stream appears in the second stream, otherwise it outputs `false`. - title: "`builtins`" body: | Returns a list of all builtin functions in the format `name/arity`. Since functions with the same name but different arities are considered separate functions, `all/0`, `all/1`, and `all/2` would all be present in the list. - title: Conditionals and Comparisons entries: - title: "`==`, `!=`" body: | The expression 'a == b' will produce 'true' if the result of a and b are equal (that is, if they represent equivalent JSON documents) and 'false' otherwise. In particular, strings are never considered equal to numbers. If you're coming from JavaScript, jq's == is like JavaScript's === - considering values equal only when they have the same type as well as the same value. != is "not equal", and 'a != b' returns the opposite value of 'a == b' examples: - program: '.[] == 1' input: '[1, 1.0, "1", "banana"]' output: ['true', 'true', 'false', 'false'] - title: if-then-else-end body: | `if A then B else C end` will act the same as `B` if `A` produces a value other than false or null, but act the same as `C` otherwise. Checking for false or null is a simpler notion of "truthiness" than is found in JavaScript or Python, but it means that you'll sometimes have to be more explicit about the condition you want. You can't test whether, e.g. a string is empty using `if .name then A else B end`, you'll need something more like `if .name == "" then A else B end` instead. If the condition `A` produces multiple results, then `B` is evaluated once for each result that is not false or null, and `C` is evaluated once for each false or null. More cases can be added to an if using `elif A then B` syntax. examples: - program: |- if . == 0 then "zero" elif . == 1 then "one" else "many" end input: '2' output: ['"many"'] - title: "`>`, `>=`, `<=`, `<`" body: | The comparison operators `>`, `>=`, `<=`, `<` return whether their left argument is greater than, greater than or equal to, less than or equal to or less than their right argument (respectively). The ordering is the same as that described for `sort`, above. examples: - program: '. < 5' input: '2' output: ['true'] - title: "`and`, `or`, `not`" body: | jq supports the normal Boolean operators `and`, `or`, `not`. They have the same standard of truth as if expressions - `false` and `null` are considered "false values", and anything else is a "true value". If an operand of one of these operators produces multiple results, the operator itself will produce a result for each input. `not` is in fact a builtin function rather than an operator, so it is called as a filter to which things can be piped rather than with special syntax, as in `.foo and .bar | not`. These three only produce the values `true` and `false`, and so are only useful for genuine Boolean operations, rather than the common Perl/Python/Ruby idiom of "value_that_may_be_null or default". If you want to use this form of "or", picking between two values rather than evaluating a condition, see the `//` operator below. examples: - program: '42 and "a string"' input: 'null' output: ['true'] - program: '(true, false) or false' input: 'null' output: ['true', 'false'] - program: '(true, true) and (true, false)' input: 'null' output: ['true', 'false', 'true', 'false'] - program: '[true, false | not]' input: 'null' output: ['[false, true]'] - title: "Alternative operator: `//`" body: | A filter of the form `a // b` produces the same results as `a`, if `a` produces results other than `false` and `null`. Otherwise, `a // b` produces the same results as `b`. This is useful for providing defaults: `.foo // 1` will evaluate to `1` if there's no `.foo` element in the input. It's similar to how `or` is sometimes used in Python (jq's `or` operator is reserved for strictly Boolean operations). examples: - program: '.foo // 42' input: '{"foo": 19}' output: ['19'] - program: '.foo // 42' input: '{}' output: ['42'] - title: try-catch body: | Errors can be caught by using `try EXP catch EXP`. The first expression is executed, and if it fails then the second is executed with the error message. The output of the handler, if any, is output as if it had been the output of the expression to try. The `try EXP` form uses `empty` as the exception handler. examples: - program: 'try .a catch ". is not an object"' input: 'true' output: ['". is not an object"'] - program: '[.[]|try .a]' input: '[{}, true, {"a":1}]' output: ['[null, 1]'] - program: 'try error("some exception") catch .' input: 'true' output: ['"some exception"'] - title: Breaking out of control structures body: | A convenient use of try/catch is to break out of control structures like `reduce`, `foreach`, `while`, and so on. For example: # Repeat an expression until it raises "break" as an # error, then stop repeating without re-raising the error. # But if the error caught is not "break" then re-raise it. try repeat(exp) catch if .=="break" then empty else error jq has a syntax for named lexical labels to "break" or "go (back) to": label $out | ... break $out ... The `break $label_name` expression will cause the program to act as though the nearest (to the left) `label $label_name` produced `empty`. The relationship between the `break` and corresponding `label` is lexical: the label has to be "visible" from the break. To break out of a `reduce`, for example: label $out | reduce .[] as $item (null; if .==false then break $out else ... end) The following jq program produces a syntax error: break $out because no label `$out` is visible. - title: "Error Suppression / Optional Operator: `?`" body: | The `?` operator, used as `EXP?`, is shorthand for `try EXP`. examples: - program: '[.[] | .a?]' input: '[{}, true, {"a":1}]' output: ['[null, 1]'] - program: '[.[] | tonumber?]' input: '["1", "invalid", "3", 4]' output: ['[1, 3, 4]'] - title: Regular expressions body: | jq uses the Oniguruma regular expression library, as do PHP, Ruby, TextMate, Sublime Text, etc, so the description here will focus on jq specifics. The jq regex filters are defined so that they can be used using one of these patterns: STRING | FILTER(REGEX) STRING | FILTER(REGEX; FLAGS) STRING | FILTER([REGEX]) STRING | FILTER([REGEX, FLAGS]) where: * STRING, REGEX, and FLAGS are jq strings and subject to jq string interpolation; * REGEX, after string interpolation, should be a valid regular expression; * FILTER is one of `test`, `match`, or `capture`, as described below. FLAGS is a string consisting of one of more of the supported flags: * `g` - Global search (find all matches, not just the first) * `i` - Case insensitive search * `m` - Multi line mode (`.` will match newlines) * `n` - Ignore empty matches * `p` - Both s and m modes are enabled * `s` - Single line mode (`^` -> `\A`, `$` -> `\Z`) * `l` - Find longest possible matches * `x` - Extended regex format (ignore whitespace and comments) To match a whitespace with the `x` flag, use `\s`, e.g. jq -n '"a b" | test("a\\sb"; "x")' Note that certain flags may also be specified within REGEX, e.g. jq -n '("test", "TEst", "teST", "TEST") | test("(?i)te(?-i)st")' evaluates to: `true`, `true`, `false`, `false`. entries: - title: "`test(val)`, `test(regex; flags)`" body: | Like `match`, but does not return match objects, only `true` or `false` for whether or not the regex matches the input. examples: - program: 'test("foo")' input: '"foo"' output: ['true'] - program: '.[] | test("a b c # spaces are ignored"; "ix")' input: '["xabcd", "ABC"]' output: ['true', 'true'] - title: "`match(val)`, `match(regex; flags)`" body: | **match** outputs an object for each match it finds. Matches have the following fields: * `offset` - offset in UTF-8 codepoints from the beginning of the input * `length` - length in UTF-8 codepoints of the match * `string` - the string that it matched * `captures` - an array of objects representing capturing groups. Capturing group objects have the following fields: * `offset` - offset in UTF-8 codepoints from the beginning of the input * `length` - length in UTF-8 codepoints of this capturing group * `string` - the string that was captured * `name` - the name of the capturing group (or `null` if it was unnamed) Capturing groups that did not match anything return an offset of -1 examples: - program: 'match("(abc)+"; "g")' input: '"abc abc"' output: - '{"offset": 0, "length": 3, "string": "abc", "captures": [{"offset": 0, "length": 3, "string": "abc", "name": null}]}' - '{"offset": 4, "length": 3, "string": "abc", "captures": [{"offset": 4, "length": 3, "string": "abc", "name": null}]}' - program: 'match("foo")' input: '"foo bar foo"' output: ['{"offset": 0, "length": 3, "string": "foo", "captures": []}'] - program: 'match(["foo", "ig"])' input: '"foo bar FOO"' output: - '{"offset": 0, "length": 3, "string": "foo", "captures": []}' - '{"offset": 8, "length": 3, "string": "FOO", "captures": []}' - program: 'match("foo (?bar)? foo"; "ig")' input: '"foo bar foo foo foo"' output: - '{"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"}]}' - program: '[ match("."; "g")] | length' input: '"abc"' output: ['3'] - title: "`capture(val)`, `capture(regex; flags)`" body: | Collects the named captures in a JSON object, with the name of each capture as the key, and the matched string as the corresponding value. examples: - program: 'capture("(?[a-z]+)-(?[0-9]+)")' input: '"xyzzy-14"' output: ['{ "a": "xyzzy", "n": "14" }'] - title: "`scan(regex)`, `scan(regex; flags)`" body: | Emit a stream of the non-overlapping substrings of the input that match the regex in accordance with the flags, if any have been specified. If there is no match, the stream is empty. To capture all the matches for each input string, use the idiom `[ expr ]`, e.g. `[ scan(regex) ]`. examples: - program: 'scan("c")' input: '"abcdefabc"' output: ['"c"', '"c"'] - title: "`split(regex; flags)`" body: | For backwards compatibility, `split` splits on a string, not a regex. examples: - program: 'split(", *"; null)' input: '"ab,cd, ef"' output: ['["ab","cd","ef"]'] - title: "`splits(regex)`, `splits(regex; flags)`" body: | These provide the same results as their `split` counterparts, but as a stream instead of an array. examples: - program: 'splits(", *")' input: '"ab,cd, ef, gh"' output: ['"ab"','"cd"','"ef"','"gh"'] - title: "`sub(regex; tostring)`, `sub(regex; string; flags)`" body: | Emit the string obtained by replacing the first match of regex in the input string with `tostring`, after interpolation. `tostring` should be a jq string, and may contain references to named captures. The named captures are, in effect, presented as a JSON object (as constructed by `capture`) to `tostring`, so a reference to a captured variable named "x" would take the form: `"\(.x)"`. examples: - program: 'sub("[^a-z]*(?[a-z]+)"; "Z\(.x)"; "g")' input: '"123abc456def"' output: ['"ZabcZdef"'] - title: "`gsub(regex; string)`, `gsub(regex; string; flags)`" body: | `gsub` is like `sub` but all the non-overlapping occurrences of the regex are replaced by the string, after interpolation. examples: - program: 'gsub("(?.)[^a]*"; "+\(.x)-")' input: '"Abcabc"' output: ['"+A-+a-"'] - title: Advanced features body: | Variables are an absolute necessity in most programming languages, but they're relegated to an "advanced feature" in jq. In most languages, variables are the only means of passing around data. If you calculate a value, and you want to use it more than once, you'll need to store it in a variable. To pass a value to another part of the program, you'll need that part of the program to define a variable (as a function parameter, object member, or whatever) in which to place the data. It is also possible to define functions in jq, although this is is a feature whose biggest use is defining jq's standard library (many jq functions such as `map` and `select` are in fact written in jq). jq has reduction operators, which are very powerful but a bit tricky. Again, these are mostly used internally, to define some useful bits of jq's standard library. It may not be obvious at first, but jq is all about generators (yes, as often found in other languages). Some utilities are provided to help deal with generators. Some minimal I/O support (besides reading JSON from standard input, and writing JSON to standard output) is available. Finally, there is a module/library system. entries: - title: "Variable / Symbolic Binding Operator: `... as $identifier | ...`" body: | In jq, all filters have an input and an output, so manual plumbing is not necessary to pass a value from one part of a program to the next. Many expressions, for instance `a + b`, pass their input to two distinct subexpressions (here `a` and `b` are both passed the same input), so variables aren't usually necessary in order to use a value twice. For instance, calculating the average value of an array of numbers requires a few variables in most languages - at least one to hold the array, perhaps one for each element or for a loop counter. In jq, it's simply `add / length` - the `add` expression is given the array and produces its sum, and the `length` expression is given the array and produces its length. So, there's generally a cleaner way to solve most problems in jq than defining variables. Still, sometimes they do make things easier, so jq lets you define variables using `expression as $variable`. All variable names start with `$`. Here's a slightly uglier version of the array-averaging example: length as $array_length | add / $array_length We'll need a more complicated problem to find a situation where using variables actually makes our lives easier. Suppose we have an array of blog posts, with "author" and "title" fields, and another object which is used to map author usernames to real names. Our input looks like: {"posts": [{"title": "First post", "author": "anon"}, {"title": "A well-written article", "author": "person1"}], "realnames": {"anon": "Anonymous Coward", "person1": "Person McPherson"}} We want to produce the posts with the author field containing a real name, as in: {"title": "First post", "author": "Anonymous Coward"} {"title": "A well-written article", "author": "Person McPherson"} We use a variable, $names, to store the realnames object, so that we can refer to it later when looking up author usernames: .realnames as $names | .posts[] | {title, author: $names[.author]} The expression `exp as $x | ...` means: for each value of expression `exp`, run the rest of the pipeline with the entire original input, and with `$x` set to that value. Thus `as` functions as something of a foreach loop. Just as `{foo}` is a handy way of writing `{foo: .foo}`, so `{$foo}` is a handy way of writing `{foo: $foo}`. Multiple variables may be declared using a single `as` expression by providing a pattern that matches the structure of the input (this is known as "destructuring"): . as {realnames: $names, posts: [$first, $second]} | ... The variable declarations in array patterns (e.g., `. as [$first, $second]`) bind to the elements of the array in from the element at index zero on up, in order. When there is no value at the index for an array pattern element, `null` is bound to that variable. Variables are scoped over the rest of the expression that defines them, so .realnames as $names | (.posts[] | {title, author: $names[.author]}) will work, but (.realnames as $names | .posts[]) | {title, author: $names[.author]} won't. For programming language theorists, it's more accurate to say that jq variables are lexically-scoped bindings. In particular there's no way to change the value of a binding; one can only setup a new binding with the same name, but which will not be visible where the old one was. examples: - program: '.bar as $x | .foo | . + $x' input: '{"foo":10, "bar":200}' output: ['210'] - program: '. as $i|[(.*2|. as $i| $i), $i]' input: '5' output: ['[10,5]'] - program: '. as [$a, $b, {c: $c}] | $a + $b + $c' input: '[2, 3, {"c": 4, "d": 5}]' output: ['9'] - program: '.[] as [$a, $b] | {a: $a, b: $b}' input: '[[0], [0, 1], [2, 1, 0]]' output: ['{"a":0,"b":null}', '{"a":0,"b":1}', '{"a":2,"b":1}'] - title: 'Destructuring Alternative Operator: `?//`' body: | The destructuring alternative operator provides a concise mechanism for destructuring an input that can take one of several forms. Suppose we have an API that returns a list of resources and events associated with them, and we want to get the user_id and timestamp of the first event for each resource. The API (having been clumsily converted from XML) will only wrap the events in an array if the resource has multiple events: {"resources": [{"id": 1, "kind": "widget", "events": {"action": "create", "user_id": 1, "ts": 13}}, {"id": 2, "kind": "widget", "events": [{"action": "create", "user_id": 1, "ts": 14}, {"action": "destroy", "user_id": 1, "ts": 15}]}]} We can use the destructuring alternative operator to handle this structural change simply: .resources[] as {$id, $kind, events: {$user_id, $ts}} ?// {$id, $kind, events: [{$user_id, $ts}]} | {$user_id, $kind, $id, $ts} Or, if we aren't sure if the input is an array of values or an object: .[] as [$id, $kind, $user_id, $ts] ?// {$id, $kind, $user_id, $ts} | ... Each alternative need not define all of the same variables, but all named variables will be available to the subsequent expression. Variables not matched in the alternative that succeeded will be `null`: .resources[] as {$id, $kind, events: {$user_id, $ts}} ?// {$id, $kind, events: [{$first_user_id, $first_ts}]} | {$user_id, $first_user_id, $kind, $id, $ts, $first_ts} Additionally, if the subsequent expression returns an error, the alternative operator will attempt to try the next binding. Errors that occur during the final alternative are passed through. [[3]] | .[] as [$a] ?// [$b] | if $a != null then error("err: \($a)") else {$a,$b} end examples: - program: '.[] as {$a, $b, c: {$d, $e}} ?// {$a, $b, c: [{$d, $e}]} | {$a, $b, $d, $e}' input: '[{"a": 1, "b": 2, "c": {"d": 3, "e": 4}}, {"a": 1, "b": 2, "c": [{"d": 3, "e": 4}]}]' output: ['{"a":1,"b":2,"d":3,"e":4}', '{"a":1,"b":2,"d":3,"e":4}'] - program: '.[] as {$a, $b, c: {$d}} ?// {$a, $b, c: [{$e}]} | {$a, $b, $d, $e}' input: '[{"a": 1, "b": 2, "c": {"d": 3, "e": 4}}, {"a": 1, "b": 2, "c": [{"d": 3, "e": 4}]}]' output: ['{"a":1,"b":2,"d":3,"e":null}', '{"a":1,"b":2,"d":null,"e":4}'] - program: '.[] as [$a] ?// [$b] | if $a != null then error("err: \($a)") else {$a,$b} end' input: '[[3]]' output: ['{"a":null,"b":3}'] - title: 'Defining Functions' body: | You can give a filter a name using "def" syntax: def increment: . + 1; From then on, `increment` is usable as a filter just like a builtin function (in fact, this is how many of the builtins are defined). A function may take arguments: def map(f): [.[] | f]; Arguments are passed as _filters_ (functions with no arguments), _not_ as values. The same argument may be referenced multiple times with different inputs (here `f` is run for each element of the input array). Arguments to a function work more like callbacks than like value arguments. This is important to understand. Consider: def foo(f): f|f; 5|foo(.*2) The result will be 20 because `f` is `.*2`, and during the first invocation of `f` `.` will be 5, and the second time it will be 10 (5 * 2), so the result will be 20. Function arguments are filters, and filters expect an input when invoked. If you want the value-argument behaviour for defining simple functions, you can just use a variable: def addvalue(f): f as $f | map(. + $f); Or use the short-hand: def addvalue($f): ...; With either definition, `addvalue(.foo)` will add the current input's `.foo` field to each element of the array. Do note that calling `addvalue(.[])` will cause the `map(. + $f)` part to be evaluated once per value in the value of `.` at the call site. Multiple definitions using the same function name are allowed. Each re-definition replaces the previous one for the same number of function arguments, but only for references from functions (or main program) subsequent to the re-definition. See also the section below on scoping. examples: - program: 'def addvalue(f): . + [f]; map(addvalue(.[0]))' input: '[[1,2],[10,20]]' output: ['[[1,2,1], [10,20,10]]'] - program: 'def addvalue(f): f as $x | map(. + $x); addvalue(.[0])' input: '[[1,2],[10,20]]' output: ['[[1,2,1,2], [10,20,1,2]]'] - title: 'Scoping' body: | There are two types of symbols in jq: value bindings (a.k.a., "variables"), and functions. Both are scoped lexically, with expressions being able to refer only to symbols that have been defined "to the left" of them. The only exception to this rule is that functions can refer to themselves so as to be able to create recursive functions. For example, in the following expression there is a binding which is visible "to the right" of it, `... | .*3 as $times_three | [. + $times_three] | ...`, but not "to the left". Consider this expression now, `... | (.*3 as $times_three | [. + $times_three]) | ...`: here the binding `$times_three` is _not_ visible past the closing parenthesis. - title: "`isempty(exp)`" body: | Returns true if `exp` produces no outputs, false otherwise. examples: - program: 'isempty(empty)' input: 'null' output: ['true'] - program: 'isempty(.[])' input: '[]' output: ['true'] - program: 'isempty(.[])' input: '[1,2,3]' output: ['false'] - title: "`limit(n; exp)`" body: | The `limit` function extracts up to `n` outputs from `exp`. examples: - program: '[limit(3;.[])]' input: '[0,1,2,3,4,5,6,7,8,9]' output: ['[0,1,2]'] - title: "`first(expr)`, `last(expr)`, `nth(n; expr)`" body: | The `first(expr)` and `last(expr)` functions extract the first and last values from `expr`, respectively. The `nth(n; expr)` function extracts the nth value output by `expr`. This can be defined as `def nth(n; expr): last(limit(n + 1; expr));`. Note that `nth(n; expr)` doesn't support negative values of `n`. examples: - program: '[first(range(.)), last(range(.)), nth(./2; range(.))]' input: '10' output: ['[0,9,5]'] - title: "`first`, `last`, `nth(n)`" body: | The `first` and `last` functions extract the first and last values from any array at `.`. The `nth(n)` function extracts the nth value of any array at `.`. examples: - program: '[range(.)]|[first, last, nth(5)]' input: '10' output: ['[0,9,5]'] - title: "`reduce`" body: | The `reduce` syntax allows you to combine all of the results of an expression by accumulating them into a single answer. The form is `reduce EXP as $var (INIT; UPDATE)`. As an example, we'll pass `[1,2,3]` to this expression: reduce .[] as $item (0; . + $item) For each result that `.[]` produces, `. + $item` is run to accumulate a running total, starting from 0 as the input value. In this example, `.[]` produces the results `1`, `2`, and `3`, so the effect is similar to running something like this: 0 | 1 as $item | . + $item | 2 as $item | . + $item | 3 as $item | . + $item examples: - program: 'reduce .[] as $item (0; . + $item)' input: '[1,2,3,4,5]' output: ['15'] - program: 'reduce .[] as [$i,$j] (0; . + $i * $j)' input: '[[1,2],[3,4],[5,6]]' output: ['44'] - program: 'reduce .[] as {$x,$y} (null; .x += $x | .y += [$y])' input: '[{"x":"a","y":1},{"x":"b","y":2},{"x":"c","y":3}]' output: ['{"x":"abc","y":[1,2,3]}'] - title: "`foreach`" body: | The `foreach` syntax is similar to `reduce`, but intended to allow the construction of `limit` and reducers that produce intermediate results. The form is `foreach EXP as $var (INIT; UPDATE; EXTRACT)`. As an example, we'll pass `[1,2,3]` to this expression: foreach .[] as $item (0; . + $item; [$item, . * 2]) Like the `reduce` syntax, `. + $item` is run for each result that `.[]` produces, but `[$item, . * 2]` is run for each intermediate values. In this example, since the intermediate values are `1`, `3`, and `6`, the `foreach` expression produces `[1,2]`, `[2,6]`, and `[3,12]`. So the effect is similar to running something like this: 0 | 1 as $item | . + $item | [$item, . * 2], 2 as $item | . + $item | [$item, . * 2], 3 as $item | . + $item | [$item, . * 2] When `EXTRACT` is omitted, the identity filter is used. That is, it outputs the intermediate values as they are. examples: - program: 'foreach .[] as $item (0; . + $item)' input: '[1,2,3,4,5]' output: ['1','3','6','10','15'] - program: 'foreach .[] as $item (0; . + $item; [$item, . * 2])' input: '[1,2,3,4,5]' output: ['[1,2]','[2,6]','[3,12]','[4,20]','[5,30]'] - program: 'foreach .[] as $item (0; . + 1; {index: ., $item})' input: '["foo", "bar", "baz"]' output: - '{"index":1,"item":"foo"}' - '{"index":2,"item":"bar"}' - '{"index":3,"item":"baz"}' - title: Recursion body: | As described above, `recurse` uses recursion, and any jq function can be recursive. The `while` builtin is also implemented in terms of recursion. Tail calls are optimized whenever the expression to the left of the recursive call outputs its last value. In practice this means that the expression to the left of the recursive call should not produce more than one output for each input. For example: def recurse(f): def r: ., (f | select(. != null) | r); r; def while(cond; update): def _while: if cond then ., (update | _while) else empty end; _while; def repeat(exp): def _repeat: exp, _repeat; _repeat; - title: Generators and iterators body: | Some jq operators and functions are actually generators in that they can produce zero, one, or more values for each input, just as one might expect in other programming languages that have generators. For example, `.[]` generates all the values in its input (which must be an array or an object), `range(0; 10)` generates the integers between 0 and 10, and so on. Even the comma operator is a generator, generating first the values generated by the expression to the left of the comma, then for each of those, the values generate by the expression on the right of the comma. The `empty` builtin is the generator that produces zero outputs. The `empty` builtin backtracks to the preceding generator expression. All jq functions can be generators just by using builtin generators. It is also possible to define new generators using only recursion and the comma operator. If the recursive call(s) is(are) "in tail position" then the generator will be efficient. In the example below the recursive call by `_range` to itself is in tail position. The example shows off three advanced topics: tail recursion, generator construction, and sub-functions. examples: - program: 'def range(init; upto; by): def _range: if (by > 0 and . < upto) or (by < 0 and . > upto) then ., ((.+by)|_range) else . end; if by == 0 then init else init|_range end | select((by > 0 and . < upto) or (by < 0 and . > upto)); range(0; 10; 3)' input: 'null' output: ['0', '3', '6', '9'] - program: 'def while(cond; update): def _while: if cond then ., (update | _while) else empty end; _while; [while(.<100; .*2)]' input: '1' output: ['[1,2,4,8,16,32,64]'] - title: 'Math' body: | jq currently only has IEEE754 double-precision (64-bit) floating point number support. Besides simple arithmetic operators such as `+`, jq also has most standard math functions from the C math library. C math functions that take a single input argument (e.g., `sin()`) are available as zero-argument jq functions. C math functions that take two input arguments (e.g., `pow()`) are available as two-argument jq functions that ignore `.`. C math functions that take three input arguments are available as three-argument jq functions that ignore `.`. Availability of standard math functions depends on the availability of the corresponding math functions in your operating system and C math library. Unavailable math functions will be defined but will raise an error. One-input C math functions: `acos` `acosh` `asin` `asinh` `atan` `atanh` `cbrt` `ceil` `cos` `cosh` `erf` `erfc` `exp` `exp10` `exp2` `expm1` `fabs` `floor` `gamma` `j0` `j1` `lgamma` `log` `log10` `log1p` `log2` `logb` `nearbyint` `pow10` `rint` `round` `significand` `sin` `sinh` `sqrt` `tan` `tanh` `tgamma` `trunc` `y0` `y1`. Two-input C math functions: `atan2` `copysign` `drem` `fdim` `fmax` `fmin` `fmod` `frexp` `hypot` `jn` `ldexp` `modf` `nextafter` `nexttoward` `pow` `remainder` `scalb` `scalbln` `yn`. Three-input C math functions: `fma`. See your system's manual for more information on each of these. - title: 'I/O' body: | At this time jq has minimal support for I/O, mostly in the form of control over when inputs are read. Two builtins functions are provided for this, `input` and `inputs`, that read from the same sources (e.g., `stdin`, files named on the command-line) as jq itself. These two builtins, and jq's own reading actions, can be interleaved with each other. Two builtins provide minimal output capabilities, `debug`, and `stderr`. (Recall that a jq program's output values are always output as JSON texts on `stdout`.) The `debug` builtin can have application-specific behavior, such as for executables that use the libjq C API but aren't the jq executable itself. The `stderr` builtin outputs its input in raw mode to stderr with no additional decoration, not even a newline. Most jq builtins are referentially transparent, and yield constant and repeatable value streams when applied to constant inputs. This is not true of I/O builtins. entries: - title: "`input`" body: | Outputs one new input. echo 1 2 3 4 | jq '[., input]' # [1,2] [3,4] - title: "`inputs`" body: | Outputs all remaining inputs, one by one. This is primarily useful for reductions over a program's inputs. echo 1 2 3 | jq -n 'reduce inputs as $i (0; . + $i)' # 6 - title: "`debug`" body: | Causes a debug message based on the input value to be produced. The jq executable wraps the input value with `["DEBUG:", ]` and prints that and a newline on stderr, compactly. This may change in the future. - title: "`stderr`" body: | Prints its input in raw and compact mode to stderr with no additional decoration, not even a newline. - title: "`input_filename`" body: | Returns the name of the file whose input is currently being filtered. Note that this will not work well unless jq is running in a UTF-8 locale. - title: "`input_line_number`" body: | Returns the line number of the input currently being filtered. - title: 'Streaming' body: | With the `--stream` option jq can parse input texts in a streaming fashion, allowing jq programs to start processing large JSON texts immediately rather than after the parse completes. If you have a single JSON text that is 1GB in size, streaming it will allow you to process it much more quickly. However, streaming isn't easy to deal with as the jq program will have `[, ]` (and a few other forms) as inputs. Several builtins are provided to make handling streams easier. The examples below use the streamed form of `[0,[1]]`, which is `[[0],0],[[1,0],1],[[1,0]],[[1]]`. Streaming forms include `[, ]` (to indicate any scalar value, empty array, or empty object), and `[]` (to indicate the end of an array or object). Future versions of jq run with `--stream` and `--seq` may output additional forms such as `["error message"]` when an input text fails to parse. entries: - title: "`truncate_stream(stream_expression)`" body: | Consumes a number as input and truncates the corresponding number of path elements from the left of the outputs of the given streaming expression. examples: - program: 'truncate_stream([[0],1],[[1,0],2],[[1,0]],[[1]])' input: '1' output: ['[[0],2]', '[[0]]'] - title: "`fromstream(stream_expression)`" body: | Outputs values corresponding to the stream expression's outputs. examples: - program: 'fromstream(1|truncate_stream([[0],1],[[1,0],2],[[1,0]],[[1]]))' input: 'null' output: ['[2]'] - title: "`tostream`" body: | The `tostream` builtin outputs the streamed form of its input. examples: - program: '. as $dot|fromstream($dot|tostream)|.==$dot' input: '[0,[1,{"a":1},{"b":2}]]' output: ['true'] - title: Assignment body: | Assignment works a little differently in jq than in most programming languages. jq doesn't distinguish between references to and copies of something - two objects or arrays are either equal or not equal, without any further notion of being "the same object" or "not the same object". If an object has two fields which are arrays, `.foo` and `.bar`, and you append something to `.foo`, then `.bar` will not get bigger, even if you've previously set `.bar = .foo`. If you're used to programming in languages like Python, Java, Ruby, JavaScript, etc. then you can think of it as though jq does a full deep copy of every object before it does the assignment (for performance it doesn't actually do that, but that's the general idea). This means that it's impossible to build circular values in jq (such as an array whose first element is itself). This is quite intentional, and ensures that anything a jq program can produce can be represented in JSON. All the assignment operators in jq have path expressions on the left-hand side (LHS). The right-hand side (RHS) provides values to set to the paths named by the LHS path expressions. Values in jq are always immutable. Internally, assignment works by using a reduction to compute new, replacement values for `.` that have had all the desired assignments applied to `.`, then outputting the modified value. This might be made clear by this example: `{a:{b:{c:1}}} | (.a.b|=3), .`. This will output `{"a":{"b":3}}` and `{"a":{"b":{"c":1}}}` because the last sub-expression, `.`, sees the original value, not the modified value. Most users will want to use modification assignment operators, such as `|=` or `+=`, rather than `=`. Note that the LHS of assignment operators refers to a value in `.`. Thus `$var.foo = 1` won't work as expected (`$var.foo` is not a valid or useful path expression in `.`); use `$var | .foo = 1` instead. Note too that `.a,.b=0` does not set `.a` and `.b`, but `(.a,.b)=0` sets both. entries: - title: "Update-assignment: `|=`" body: | This is the "update" operator `|=`. It takes a filter on the right-hand side and works out the new value for the property of `.` being assigned to by running the old value through this expression. For instance, `(.foo, .bar) |= .+1` will build an object with the "foo" field set to the input's "foo" plus 1, and the "bar" field set to the input's "bar" plus 1. The left-hand side can be any general path expression; see `path()`. Note that the left-hand side of `|=` refers to a value in `.`. Thus `$var.foo |= . + 1` won't work as expected (`$var.foo` is not a valid or useful path expression in `.`); use `$var | .foo |= . + 1` instead. If the right-hand side outputs no values (i.e., `empty`), then the left-hand side path will be deleted, as with `del(path)`. If the right-hand side outputs multiple values, only the first one will be used (COMPATIBILITY NOTE: in jq 1.5 and earlier releases, it used to be that only the last one was used). examples: - program: '(..|select(type=="boolean")) |= if . then 1 else 0 end' input: '[true,false,[5,true,[true,[false]],false]]' output: ['[1,0,[5,1,[1,[0]],0]]'] - title: "Arithmetic update-assignment: `+=`, `-=`, `*=`, `/=`, `%=`, `//=`" body: | jq has a few operators of the form `a op= b`, which are all equivalent to `a |= . op b`. So, `+= 1` can be used to increment values, being the same as `|= . + 1`. examples: - program: .foo += 1 input: '{"foo": 42}' output: ['{"foo": 43}'] - title: "Plain assignment: `=`" body: | This is the plain assignment operator. Unlike the others, the input to the right-hand-side (RHS) is the same as the input to the left-hand-side (LHS) rather than the value at the LHS path, and all values output by the RHS will be used (as shown below). If the RHS of '=' produces multiple values, then for each such value jq will set the paths on the left-hand side to the value and then it will output the modified `.`. For example, `(.a,.b)=range(2)` outputs `{"a":0,"b":0}`, then `{"a":1,"b":1}`. The "update" assignment forms (see above) do not do this. This example should show the difference between '=' and '|=': Provide input `{"a": {"b": 10}, "b": 20}` to the programs: `.a = .b` `.a |= .b` The former will set the "a" field of the input to the "b" field of the input, and produce the output `{"a": 20, "b": 20}`. The latter will set the "a" field of the input to the "a" field's "b" field, producing `{"a": 10, "b": 20}`. Another example of the difference between `=` and `|=`: `null|(.a,.b)=range(3)` outputs `{"a":0,"b":0}, {"a":1,"b":1}, {"a":2,"b":2}`, while `null|(.a,.b)|=range(3)` outputs just `{"a":0,"b":0}`. - title: Complex assignments body: | Lots more things are allowed on the left-hand side of a jq assignment than in most languages. We've already seen simple field accesses on the left hand side, and it's no surprise that array accesses work just as well: .posts[0].title = "JQ Manual" What may come as a surprise is that the expression on the left may produce multiple results, referring to different points in the input document: .posts[].comments |= . + ["this is great"] That example appends the string "this is great" to the "comments" array of each post in the input (where the input is an object with a field "posts" which is an array of posts). When jq encounters an assignment like 'a = b', it records the "path" taken to select a part of the input document while executing a. This path is then used to find which part of the input to change while executing the assignment. Any filter may be used on the left-hand side of an equals - whichever paths it selects from the input will be where the assignment is performed. This is a very powerful operation. Suppose we wanted to add a comment to blog posts, using the same "blog" input above. This time, we only want to comment on the posts written by "stedolan". We can find those posts using the "select" function described earlier: .posts[] | select(.author == "stedolan") The paths provided by this operation point to each of the posts that "stedolan" wrote, and we can comment on each of them in the same way that we did before: (.posts[] | select(.author == "stedolan") | .comments) |= . + ["terrible."] - title: Modules body: | jq has a library/module system. Modules are files whose names end in `.jq`. Modules imported by a program are searched for in a default search path (see below). The `import` and `include` directives allow the importer to alter this path. Paths in the search path are subject to various substitutions. For paths starting with "~/", the user's home directory is substituted for "~". For paths starting with "$ORIGIN/", the directory where the jq executable is located is substituted for "$ORIGIN". For paths starting with "./" or paths that are ".", the path of the including file is substituted for ".". For top-level programs given on the command-line, the current directory is used. Import directives can optionally specify a search path to which the default is appended. The default search path is the search path given to the `-L` command-line option, else `["~/.jq", "$ORIGIN/../lib/jq", "$ORIGIN/../lib"]`. Null and empty string path elements terminate search path processing. A dependency with relative path "foo/bar" would be searched for in "foo/bar.jq" and "foo/bar/bar.jq" in the given search path. This is intended to allow modules to be placed in a directory along with, for example, version control files, README files, and so on, but also to allow for single-file modules. Consecutive components with the same name are not allowed to avoid ambiguities (e.g., "foo/foo"). For example, with `-L$HOME/.jq` a module `foo` can be found in `$HOME/.jq/foo.jq` and `$HOME/.jq/foo/foo.jq`. If "$HOME/.jq" is a file, it is sourced into the main program. entries: - title: "`import RelativePathString as NAME [];`" body: | Imports a module found at the given path relative to a directory in a search path. A ".jq" suffix will be added to the relative path string. The module's symbols are prefixed with "NAME::". The optional metadata must be a constant jq expression. It should be an object with keys like "homepage" and so on. At this time jq only uses the "search" key/value of the metadata. The metadata is also made available to users via the `modulemeta` builtin. The "search" key in the metadata, if present, should have a string or array value (array of strings); this is the search path to be prefixed to the top-level search path. - title: "`include RelativePathString [];`" body: | Imports a module found at the given path relative to a directory in a search path as if it were included in place. A ".jq" suffix will be added to the relative path string. The module's symbols are imported into the caller's namespace as if the module's content had been included directly. The optional metadata must be a constant jq expression. It should be an object with keys like "homepage" and so on. At this time jq only uses the "search" key/value of the metadata. The metadata is also made available to users via the `modulemeta` builtin. - title: "`import RelativePathString as $NAME [];`" body: | Imports a JSON file found at the given path relative to a directory in a search path. A ".json" suffix will be added to the relative path string. The file's data will be available as `$NAME::NAME`. The optional metadata must be a constant jq expression. It should be an object with keys like "homepage" and so on. At this time jq only uses the "search" key/value of the metadata. The metadata is also made available to users via the `modulemeta` builtin. The "search" key in the metadata, if present, should have a string or array value (array of strings); this is the search path to be prefixed to the top-level search path. - title: "`module ;`" body: | This directive is entirely optional. It's not required for proper operation. It serves only the purpose of providing metadata that can be read with the `modulemeta` builtin. The metadata must be a constant jq expression. It should be an object with keys like "homepage". At this time jq doesn't use this metadata, but it is made available to users via the `modulemeta` builtin. - title: "`modulemeta`" body: | Takes a module name as input and outputs the module's metadata as an object, with the module's imports (including metadata) as an array value for the "deps" key. Programs can use this to query a module's metadata, which they could then use to, for example, search for, download, and install missing dependencies. - title: Colors body: | To configure alternative colors just set the `JQ_COLORS` environment variable to colon-delimited list of partial terminal escape sequences like `"1;31"`, in this order: - color for `null` - color for `false` - color for `true` - color for numbers - color for strings - color for arrays - color for objects The default color scheme is the same as setting `"JQ_COLORS=1;30:0;39:0;39:0;39:0;32:1;39:1;39"`. This is not a manual for VT100/ANSI escapes. However, each of these color specifications should consist of two numbers separated by a semi-colon, where the first number is one of these: - 1 (bright) - 2 (dim) - 4 (underscore) - 5 (blink) - 7 (reverse) - 8 (hidden) and the second is one of these: - 30 (black) - 31 (red) - 32 (green) - 33 (yellow) - 34 (blue) - 35 (magenta) - 36 (cyan) - 37 (white) ================================================ FILE: docs/content/manual/v1.7/manual.yml ================================================ --- headline: jq 1.7 Manual body: | A jq program is a "filter": it takes an input, and produces an output. There are a lot of builtin filters for extracting a particular field of an object, or converting a number to a string, or various other standard tasks. Filters can be combined in various ways - you can pipe the output of one filter into another filter, or collect the output of a filter into an array. Some filters produce multiple results, for instance there's one that produces all the elements of its input array. Piping that filter into a second runs the second filter for each element of the array. Generally, things that would be done with loops and iteration in other languages are just done by gluing filters together in jq. It's important to remember that every filter has an input and an output. Even literals like "hello" or 42 are filters - they take an input but always produce the same literal as output. Operations that combine two filters, like addition, generally feed the same input to both and combine the results. So, you can implement an averaging filter as `add / length` - feeding the input array both to the `add` filter and the `length` filter and then performing the division. But that's getting ahead of ourselves. :) Let's start with something simpler: manpage_intro: | jq(1) -- Command-line JSON processor ==================================== ## SYNOPSIS `jq` [...] [...] `jq` can transform JSON in various ways, by selecting, iterating, reducing and otherwise mangling JSON documents. For instance, running the command `jq 'map(.price) | add'` will take an array of JSON objects as input and return the sum of their "price" fields. `jq` can accept text input as well, but by default, `jq` reads a stream of JSON entities (including numbers and other literals) from `stdin`. Whitespace is only needed to separate entities such as 1 and 2, and true and false. One or more may be specified, in which case `jq` will read input from those instead. The are described in the [INVOKING JQ] section; they mostly concern input and output formatting. The is written in the jq language and specifies how to transform the input file or document. ## FILTERS manpage_epilogue: | ## BUGS Presumably. Report them or discuss them at: https://github.com/jqlang/jq/issues ## AUTHOR Stephen Dolan `` sections: - title: Invoking jq body: | jq filters run on a stream of JSON data. The input to jq is parsed as a sequence of whitespace-separated JSON values which are passed through the provided filter one at a time. The output(s) of the filter are written to standard output, as a sequence of newline-separated JSON data. The simplest and most common filter (or jq program) is `.`, which is the identity operator, copying the inputs of the jq processor to the output stream. Because the default behavior of the jq processor is to read JSON texts from the input stream, and to pretty-print outputs, the `.` program's main use is to validate and pretty-print the inputs. The jq programming language is quite rich and allows for much more than just validation and pretty-printing. Note: it is important to mind the shell's quoting rules. As a general rule it's best to always quote (with single-quote characters on Unix shells) the jq program, as too many characters with special meaning to jq are also shell meta-characters. For example, `jq "foo"` will fail on most Unix shells because that will be the same as `jq foo`, which will generally fail because `foo is not defined`. When using the Windows command shell (cmd.exe) it's best to use double quotes around your jq program when given on the command-line (instead of the `-f program-file` option), but then double-quotes in the jq program need backslash escaping. When using the Powershell (`powershell.exe`) or the Powershell Core (`pwsh`/`pwsh.exe`), use single-quote characters around the jq program and backslash-escaped double-quotes (`\"`) inside the jq program. * Unix shells: `jq '.["foo"]'` * Powershell: `jq '.[\"foo\"]'` * Windows command shell: `jq ".[\"foo\"]"` Note: jq allows user-defined functions, but every jq program must have a top-level expression. You can affect how jq reads and writes its input and output using some command-line options: * `--null-input` / `-n`: Don't read any input at all. Instead, the filter is run once using `null` as the input. This is useful when using jq as a simple calculator or to construct JSON data from scratch. * `--raw-input` / `-R`: Don't parse the input as JSON. Instead, each line of text is passed to the filter as a string. If combined with `--slurp`, then the entire input is passed to the filter as a single long string. * `--slurp` / `-s`: Instead of running the filter for each JSON object in the input, read the entire input stream into a large array and run the filter just once. * `--compact-output` / `-c`: By default, jq pretty-prints JSON output. Using this option will result in more compact output by instead putting each JSON object on a single line. * `--raw-output` / `-r`: With this option, if the filter's result is a string then it will be written directly to standard output rather than being formatted as a JSON string with quotes. This can be useful for making jq filters talk to non-JSON-based systems. * `--raw-output0`: Like `-r` but jq will print NUL instead of newline after each output. This can be useful when the values being output can contain newlines. When the output value contains NUL, jq exits with non-zero code. * `--join-output` / `-j`: Like `-r` but jq won't print a newline after each output. * `--ascii-output` / `-a`: jq usually outputs non-ASCII Unicode codepoints as UTF-8, even if the input specified them as escape sequences (like "\u03bc"). Using this option, you can force jq to produce pure ASCII output with every non-ASCII character replaced with the equivalent escape sequence. * `--sort-keys` / `-S`: Output the fields of each object with the keys in sorted order. * `--color-output` / `-C` and `--monochrome-output` / `-M`: By default, jq outputs colored JSON if writing to a terminal. You can force it to produce color even if writing to a pipe or a file using `-C`, and disable color with `-M`. When the `NO_COLOR` environment variable is not empty, jq disables colored output by default, but you can enable it by `-C`. Colors can be configured with the `JQ_COLORS` environment variable (see below). * `--tab`: Use a tab for each indentation level instead of two spaces. * `--indent n`: Use the given number of spaces (no more than 7) for indentation. * `--unbuffered`: Flush the output after each JSON object is printed (useful if you're piping a slow data source into jq and piping jq's output elsewhere). * `--stream`: Parse the input in streaming fashion, outputting arrays of path and leaf values (scalars and empty arrays or empty objects). For example, `"a"` becomes `[[],"a"]`, and `[[],"a",["b"]]` becomes `[[0],[]]`, `[[1],"a"]`, and `[[2,0],"b"]`. This is useful for processing very large inputs. Use this in conjunction with filtering and the `reduce` and `foreach` syntax to reduce large inputs incrementally. * `--stream-errors`: Like `--stream`, but invalid JSON inputs yield array values where the first element is the error and the second is a path. For example, `["a",n]` produces `["Invalid literal at line 1, column 7",[1]]`. Implies `--stream`. Invalid JSON inputs produce no error values when `--stream` without `--stream-errors`. * `--seq`: Use the `application/json-seq` MIME type scheme for separating JSON texts in jq's input and output. This means that an ASCII RS (record separator) character is printed before each value on output and an ASCII LF (line feed) is printed after every output. Input JSON texts that fail to parse are ignored (but warned about), discarding all subsequent input until the next RS. This mode also parses the output of jq without the `--seq` option. * `-f filename` / `--from-file filename`: Read filter from the file rather than from a command line, like awk's -f option. You can also use '#' to make comments. * `-L directory`: Prepend `directory` to the search list for modules. If this option is used then no builtin search list is used. See the section on modules below. * `--arg name value`: This option passes a value to the jq program as a predefined variable. If you run jq with `--arg foo bar`, then `$foo` is available in the program and has the value `"bar"`. Note that `value` will be treated as a string, so `--arg foo 123` will bind `$foo` to `"123"`. Named arguments are also available to the jq program as `$ARGS.named`. * `--argjson name JSON-text`: This option passes a JSON-encoded value to the jq program as a predefined variable. If you run jq with `--argjson foo 123`, then `$foo` is available in the program and has the value `123`. * `--slurpfile variable-name filename`: This option reads all the JSON texts in the named file and binds an array of the parsed JSON values to the given global variable. If you run jq with `--slurpfile foo bar`, then `$foo` is available in the program and has an array whose elements correspond to the texts in the file named `bar`. * `--rawfile variable-name filename`: This option reads in the named file and binds its content to the given global variable. If you run jq with `--rawfile foo bar`, then `$foo` is available in the program and has a string whose content is set to the text in the file named `bar`. * `--args`: Remaining arguments are positional string arguments. These are available to the jq program as `$ARGS.positional[]`. * `--jsonargs`: Remaining arguments are positional JSON text arguments. These are available to the jq program as `$ARGS.positional[]`. * `--exit-status` / `-e`: Sets the exit status of jq to 0 if the last output value was neither `false` nor `null`, 1 if the last output value was either `false` or `null`, or 4 if no valid result was ever produced. Normally jq exits with 2 if there was any usage problem or system error, 3 if there was a jq program compile error, or 0 if the jq program ran. Another way to set the exit status is with the `halt_error` builtin function. * `--binary` / `-b`: Windows users using WSL, MSYS2, or Cygwin, should use this option when using a native jq.exe, otherwise jq will turn newlines (LFs) into carriage-return-then-newline (CRLF). * `--version` / `-V`: Output the jq version and exit with zero. * `--build-configuration`: Output the build configuration of jq and exit with zero. This output has no supported format or structure and may change without notice in future releases. * `--help` / `-h`: Output the jq help and exit with zero. * `--`: Terminates argument processing. Remaining arguments are positional, either strings, JSON texts, or input filenames, according to whether `--args` or `--jsonargs` were given. * `--run-tests [filename]`: Runs the tests in the given file or standard input. This must be the last option given and does not honor all preceding options. The input consists of comment lines, empty lines, and program lines followed by one input line, as many lines of output as are expected (one per output), and a terminating empty line. Compilation failure tests start with a line containing only `%%FAIL`, then a line containing the program to compile, then a line containing an error message to compare to the actual. Be warned that this option can change backwards-incompatibly. - title: Basic filters entries: - title: "Identity: `.`" body: | The absolute simplest filter is `.` . This filter takes its input and produces the same value as output. That is, this is the identity operator. Since jq by default pretty-prints all output, a trivial program consisting of nothing but `.` can be used to format JSON output from, say, `curl`. Although the identity filter never modifies the value of its input, jq processing can sometimes make it appear as though it does. For example, using the current implementation of jq, we would see that the expression: 1E1234567890 | . produces `1.7976931348623157e+308` on at least one platform. This is because, in the process of parsing the number, this particular version of jq has converted it to an IEEE754 double-precision representation, losing precision. The way in which jq handles numbers has changed over time and further changes are likely within the parameters set by the relevant JSON standards. The following remarks are therefore offered with the understanding that they are intended to be descriptive of the current version of jq and should not be interpreted as being prescriptive: (1) Any arithmetic operation on a number that has not already been converted to an IEEE754 double precision representation will trigger a conversion to the IEEE754 representation. (2) jq will attempt to maintain the original decimal precision of number literals, but in expressions such `1E1234567890`, precision will be lost if the exponent is too large. (3) In jq programs, a leading minus sign will trigger the conversion of the number to an IEEE754 representation. (4) Comparisons are carried out using the untruncated big decimal representation of numbers if available, as illustrated in one of the following examples. examples: - program: '.' input: '"Hello, world!"' output: ['"Hello, world!"'] - program: '.' input: '0.12345678901234567890123456789' output: ['0.12345678901234567890123456789'] - program: '[., tojson]' input: '12345678909876543212345' output: ['[12345678909876543212345,"12345678909876543212345"]'] - program: '. < 0.12345678901234567890123456788' input: '0.12345678901234567890123456789' output: ['false'] - program: 'map([., . == 1]) | tojson' input: '[1, 1.000, 1.0, 100e-2]' output: ['"[[1,true],[1.000,true],[1.0,true],[1.00,true]]"'] - program: '. as $big | [$big, $big + 1] | map(. > 10000000000000000000000000000000)' input: '10000000000000000000000000000001' output: ['[true, false]'] - title: "Object Identifier-Index: `.foo`, `.foo.bar`" body: | The simplest *useful* filter has the form `.foo`. When given a JSON object (aka dictionary or hash) as input, `.foo` produces the value at the key "foo" if the key is present, or null otherwise. A filter of the form `.foo.bar` is equivalent to `.foo | .bar`. The `.foo` syntax only works for simple, identifier-like keys, that is, keys that are all made of alphanumeric characters and underscore, and which do not start with a digit. If the key contains special characters or starts with a digit, you need to surround it with double quotes like this: `."foo$"`, or else `.["foo$"]`. For example `.["foo::bar"]` and `.["foo.bar"]` work while `.foo::bar` does not. examples: - program: '.foo' input: '{"foo": 42, "bar": "less interesting data"}' output: ['42'] - program: '.foo' input: '{"notfoo": true, "alsonotfoo": false}' output: ['null'] - program: '.["foo"]' input: '{"foo": 42}' output: ['42'] - title: "Optional Object Identifier-Index: `.foo?`" body: | Just like `.foo`, but does not output an error when `.` is not an object. examples: - program: '.foo?' input: '{"foo": 42, "bar": "less interesting data"}' output: ['42'] - program: '.foo?' input: '{"notfoo": true, "alsonotfoo": false}' output: ['null'] - program: '.["foo"]?' input: '{"foo": 42}' output: ['42'] - program: '[.foo?]' input: '[1,2]' output: ['[]'] - title: "Object Index: `.[]`" body: | You can also look up fields of an object using syntax like `.["foo"]` (`.foo` above is a shorthand version of this, but only for identifier-like strings). - title: "Array Index: `.[]`" body: | When the index value is an integer, `.[]` can index arrays. Arrays are zero-based, so `.[2]` returns the third element. Negative indices are allowed, with -1 referring to the last element, -2 referring to the next to last element, and so on. examples: - program: '.[0]' input: '[{"name":"JSON", "good":true}, {"name":"XML", "good":false}]' output: ['{"name":"JSON", "good":true}'] - program: '.[2]' input: '[{"name":"JSON", "good":true}, {"name":"XML", "good":false}]' output: ['null'] - program: '.[-2]' input: '[1,2,3]' output: ['2'] - title: "Array/String Slice: `.[:]`" body: | The `.[:]` syntax can be used to return a subarray of an array or substring of a string. The array returned by `.[10:15]` will be of length 5, containing the elements from index 10 (inclusive) to index 15 (exclusive). Either index may be negative (in which case it counts backwards from the end of the array), or omitted (in which case it refers to the start or end of the array). Indices are zero-based. examples: - program: '.[2:4]' input: '["a","b","c","d","e"]' output: ['["c", "d"]'] - program: '.[2:4]' input: '"abcdefghi"' output: ['"cd"'] - program: '.[:3]' input: '["a","b","c","d","e"]' output: ['["a", "b", "c"]'] - program: '.[-2:]' input: '["a","b","c","d","e"]' output: ['["d", "e"]'] - title: "Array/Object Value Iterator: `.[]`" body: | If you use the `.[index]` syntax, but omit the index entirely, it will return *all* of the elements of an array. Running `.[]` with the input `[1,2,3]` will produce the numbers as three separate results, rather than as a single array. A filter of the form `.foo[]` is equivalent to `.foo | .[]`. You can also use this on an object, and it will return all the values of the object. Note that the iterator operator is a generator of values. examples: - program: '.[]' input: '[{"name":"JSON", "good":true}, {"name":"XML", "good":false}]' output: - '{"name":"JSON", "good":true}' - '{"name":"XML", "good":false}' - program: '.[]' input: '[]' output: [] - program: '.foo[]' input: '{"foo":[1,2,3]}' output: ['1','2','3'] - program: '.[]' input: '{"a": 1, "b": 1}' output: ['1', '1'] - title: "`.[]?`" body: | Like `.[]`, but no errors will be output if . is not an array or object. A filter of the form `.foo[]?` is equivalent to `.foo | .[]?`. - title: "Comma: `,`" body: | If two filters are separated by a comma, then the same input will be fed into both and the two filters' output value streams will be concatenated in order: first, all of the outputs produced by the left expression, and then all of the outputs produced by the right. For instance, filter `.foo, .bar`, produces both the "foo" fields and "bar" fields as separate outputs. The `,` operator is one way to construct generators. examples: - program: '.foo, .bar' input: '{"foo": 42, "bar": "something else", "baz": true}' output: ['42', '"something else"'] - program: ".user, .projects[]" input: '{"user":"stedolan", "projects": ["jq", "wikiflow"]}' output: ['"stedolan"', '"jq"', '"wikiflow"'] - program: '.[4,2]' input: '["a","b","c","d","e"]' output: ['"e"', '"c"'] - title: "Pipe: `|`" body: | The | operator combines two filters by feeding the output(s) of the one on the left into the input of the one on the right. It's similar to the Unix shell's pipe, if you're used to that. If the one on the left produces multiple results, the one on the right will be run for each of those results. So, the expression `.[] | .foo` retrieves the "foo" field of each element of the input array. This is a cartesian product, which can be surprising. Note that `.a.b.c` is the same as `.a | .b | .c`. Note too that `.` is the input value at the particular stage in a "pipeline", specifically: where the `.` expression appears. Thus `.a | . | .b` is the same as `.a.b`, as the `.` in the middle refers to whatever value `.a` produced. examples: - program: '.[] | .name' input: '[{"name":"JSON", "good":true}, {"name":"XML", "good":false}]' output: ['"JSON"', '"XML"'] - title: "Parenthesis" body: | Parenthesis work as a grouping operator just as in any typical programming language. examples: - program: '(. + 2) * 5' input: '1' output: ['15'] - title: Types and Values body: | jq supports the same set of datatypes as JSON - numbers, strings, booleans, arrays, objects (which in JSON-speak are hashes with only string keys), and "null". Booleans, null, strings and numbers are written the same way as in JSON. Just like everything else in jq, these simple values take an input and produce an output - `42` is a valid jq expression that takes an input, ignores it, and returns 42 instead. Numbers in jq are internally represented by their IEEE754 double precision approximation. Any arithmetic operation with numbers, whether they are literals or results of previous filters, will produce a double precision floating point result. However, when parsing a literal jq will store the original literal string. If no mutation is applied to this value then it will make to the output in its original form, even if conversion to double would result in a loss. entries: - title: "Array construction: `[]`" body: | As in JSON, `[]` is used to construct arrays, as in `[1,2,3]`. The elements of the arrays can be any jq expression, including a pipeline. All of the results produced by all of the expressions are collected into one big array. You can use it to construct an array out of a known quantity of values (as in `[.foo, .bar, .baz]`) or to "collect" all the results of a filter into an array (as in `[.items[].name]`) Once you understand the "," operator, you can look at jq's array syntax in a different light: the expression `[1,2,3]` is not using a built-in syntax for comma-separated arrays, but is instead applying the `[]` operator (collect results) to the expression 1,2,3 (which produces three different results). If you have a filter `X` that produces four results, then the expression `[X]` will produce a single result, an array of four elements. examples: - program: "[.user, .projects[]]" input: '{"user":"stedolan", "projects": ["jq", "wikiflow"]}' output: ['["stedolan", "jq", "wikiflow"]'] - program: "[ .[] | . * 2]" input: '[1, 2, 3]' output: ['[2, 4, 6]'] - title: "Object Construction: `{}`" body: | Like JSON, `{}` is for constructing objects (aka dictionaries or hashes), as in: `{"a": 42, "b": 17}`. If the keys are "identifier-like", then the quotes can be left off, as in `{a:42, b:17}`. Variable references as key expressions use the value of the variable as the key. Key expressions other than constant literals, identifiers, or variable references, need to be parenthesized, e.g., `{("a"+"b"):59}`. The value can be any expression (although you may need to wrap it in parentheses if, for example, it contains colons), which gets applied to the {} expression's input (remember, all filters have an input and an output). {foo: .bar} will produce the JSON object `{"foo": 42}` if given the JSON object `{"bar":42, "baz":43}` as its input. You can use this to select particular fields of an object: if the input is an object with "user", "title", "id", and "content" fields and you just want "user" and "title", you can write {user: .user, title: .title} Because that is so common, there's a shortcut syntax for it: `{user, title}`. If one of the expressions produces multiple results, multiple dictionaries will be produced. If the input's {"user":"stedolan","titles":["JQ Primer", "More JQ"]} then the expression {user, title: .titles[]} will produce two outputs: {"user":"stedolan", "title": "JQ Primer"} {"user":"stedolan", "title": "More JQ"} Putting parentheses around the key means it will be evaluated as an expression. With the same input as above, {(.user): .titles} produces {"stedolan": ["JQ Primer", "More JQ"]} Variable references as keys use the value of the variable as the key. Without a value then the variable's name becomes the key and its value becomes the value, "f o o" as $foo | "b a r" as $bar | {$foo, $bar:$foo} produces {"foo":"f o o","b a r":"f o o"} examples: - program: '{user, title: .titles[]}' input: '{"user":"stedolan","titles":["JQ Primer", "More JQ"]}' output: - '{"user":"stedolan", "title": "JQ Primer"}' - '{"user":"stedolan", "title": "More JQ"}' - program: '{(.user): .titles}' input: '{"user":"stedolan","titles":["JQ Primer", "More JQ"]}' output: ['{"stedolan": ["JQ Primer", "More JQ"]}'] - title: "Recursive Descent: `..`" body: | Recursively descends `.`, producing every value. This is the same as the zero-argument `recurse` builtin (see below). This is intended to resemble the XPath `//` operator. Note that `..a` does not work; use `.. | .a` instead. In the example below we use `.. | .a?` to find all the values of object keys "a" in any object found "below" `.`. This is particularly useful in conjunction with `path(EXP)` (also see below) and the `?` operator. examples: - program: '.. | .a?' input: '[[{"a":1}]]' output: ['1'] - title: Builtin operators and functions body: | Some jq operators (for instance, `+`) do different things depending on the type of their arguments (arrays, numbers, etc.). However, jq never does implicit type conversions. If you try to add a string to an object you'll get an error message and no result. Please note that all numbers are converted to IEEE754 double precision floating point representation. Arithmetic and logical operators are working with these converted doubles. Results of all such operations are also limited to the double precision. The only exception to this behaviour of number is a snapshot of original number literal. When a number which originally was provided as a literal is never mutated until the end of the program then it is printed to the output in its original literal form. This also includes cases when the original literal would be truncated when converted to the IEEE754 double precision floating point number. entries: - title: "Addition: `+`" body: | The operator `+` takes two filters, applies them both to the same input, and adds the results together. What "adding" means depends on the types involved: - **Numbers** are added by normal arithmetic. - **Arrays** are added by being concatenated into a larger array. - **Strings** are added by being joined into a larger string. - **Objects** are added by merging, that is, inserting all the key-value pairs from both objects into a single combined object. If both objects contain a value for the same key, the object on the right of the `+` wins. (For recursive merge use the `*` operator.) `null` can be added to any value, and returns the other value unchanged. examples: - program: '.a + 1' input: '{"a": 7}' output: ['8'] - program: '.a + .b' input: '{"a": [1,2], "b": [3,4]}' output: ['[1,2,3,4]'] - program: '.a + null' input: '{"a": 1}' output: ['1'] - program: '.a + 1' input: '{}' output: ['1'] - program: '{a: 1} + {b: 2} + {c: 3} + {a: 42}' input: 'null' output: ['{"a": 42, "b": 2, "c": 3}'] - title: "Subtraction: `-`" body: | As well as normal arithmetic subtraction on numbers, the `-` operator can be used on arrays to remove all occurrences of the second array's elements from the first array. examples: - program: '4 - .a' input: '{"a":3}' output: ['1'] - program: . - ["xml", "yaml"] input: '["xml", "yaml", "json"]' output: ['["json"]'] - title: "Multiplication, division, modulo: `*`, `/`, `%`" body: | These infix operators behave as expected when given two numbers. Division by zero raises an error. `x % y` computes x modulo y. Multiplying a string by a number produces the concatenation of that string that many times. `"x" * 0` produces `""`. Dividing a string by another splits the first using the second as separators. Multiplying two objects will merge them recursively: this works like addition but if both objects contain a value for the same key, and the values are objects, the two are merged with the same strategy. examples: - program: '10 / . * 3' input: '5' output: ['6'] - program: '. / ", "' input: '"a, b,c,d, e"' output: ['["a","b,c,d","e"]'] - program: '{"k": {"a": 1, "b": 2}} * {"k": {"a": 0,"c": 3}}' input: 'null' output: ['{"k": {"a": 0, "b": 2, "c": 3}}'] - program: '.[] | (1 / .)?' input: '[1,0,-1]' output: ['1', '-1'] - title: "`abs`" body: | The builtin function `abs` is defined naively as: `if . < 0 then - . else . end`. For numeric input, this is the absolute value. See the section on the identity filter for the implications of this definition for numeric input. To compute the absolute value of a number as a floating point number, you may wish use `fabs`. examples: - program: 'map(abs)' input: '[-10, -1.1, -1e-1]' output: ['[10,1.1,1e-1]'] - title: "`length`" body: | The builtin function `length` gets the length of various different types of value: - The length of a **string** is the number of Unicode codepoints it contains (which will be the same as its JSON-encoded length in bytes if it's pure ASCII). - The length of a **number** is its absolute value. - The length of an **array** is the number of elements. - The length of an **object** is the number of key-value pairs. - The length of **null** is zero. - It is an error to use `length` on a **boolean**. examples: - program: '.[] | length' input: '[[1,2], "string", {"a":2}, null, -5]' output: ['2', '6', '1', '0', '5'] - title: "`utf8bytelength`" body: | The builtin function `utf8bytelength` outputs the number of bytes used to encode a string in UTF-8. examples: - program: 'utf8bytelength' input: '"\u03bc"' output: ['2'] - title: "`keys`, `keys_unsorted`" body: | The builtin function `keys`, when given an object, returns its keys in an array. The keys are sorted "alphabetically", by unicode codepoint order. This is not an order that makes particular sense in any particular language, but you can count on it being the same for any two objects with the same set of keys, regardless of locale settings. When `keys` is given an array, it returns the valid indices for that array: the integers from 0 to length-1. The `keys_unsorted` function is just like `keys`, but if the input is an object then the keys will not be sorted, instead the keys will roughly be in insertion order. examples: - program: 'keys' input: '{"abc": 1, "abcd": 2, "Foo": 3}' output: ['["Foo", "abc", "abcd"]'] - program: 'keys' input: '[42,3,35]' output: ['[0,1,2]'] - title: "`has(key)`" body: | The builtin function `has` returns whether the input object has the given key, or the input array has an element at the given index. `has($key)` has the same effect as checking whether `$key` is a member of the array returned by `keys`, although `has` will be faster. examples: - program: 'map(has("foo"))' input: '[{"foo": 42}, {}]' output: ['[true, false]'] - program: 'map(has(2))' input: '[[0,1], ["a","b","c"]]' output: ['[false, true]'] - title: "`in`" body: | The builtin function `in` returns whether or not the input key is in the given object, or the input index corresponds to an element in the given array. It is, essentially, an inversed version of `has`. examples: - program: '.[] | in({"foo": 42})' input: '["foo", "bar"]' output: ['true', 'false'] - program: 'map(in([0,1]))' input: '[2, 0]' output: ['[false, true]'] - title: "`map(f)`, `map_values(f)`" body: | For any filter `f`, `map(f)` and `map_values(f)` apply `f` to each of the values in the input array or object, that is, to the values of `.[]`. In the absence of errors, `map(f)` always outputs an array whereas `map_values(f)` outputs an array if given an array, or an object if given an object. When the input to `map_values(f)` is an object, the output object has the same keys as the input object except for those keys whose values when piped to `f` produce no values at all. The key difference between `map(f)` and `map_values(f)` is that the former simply forms an array from all the values of `($x|f)` for each value, `$x`, in the input array or object, but `map_values(f)` only uses `first($x|f)`. Specifically, for object inputs, `map_values(f)` constructs the output object by examining in turn the value of `first(.[$k]|f)` for each key, `$k`, of the input. If this expression produces no values, then the corresponding key will be dropped; otherwise, the output object will have that value at the key, `$k`. Here are some examples to clarify the behavior of `map` and `map_values` when applied to arrays. These examples assume the input is `[1]` in all cases: map(.+1) #=> [2] map(., .) #=> [1,1] map(empty) #=> [] map_values(.+1) #=> [2] map_values(., .) #=> [1] map_values(empty) #=> [] `map(f)` is equivalent to `[.[] | f]` and `map_values(f)` is equivalent to `.[] |= f`. In fact, these are their implementations. examples: - program: 'map(.+1)' input: '[1,2,3]' output: ['[2,3,4]'] - program: 'map_values(.+1)' input: '{"a": 1, "b": 2, "c": 3}' output: ['{"a": 2, "b": 3, "c": 4}'] - program: 'map(., .)' input: '[1,2]' output: ['[1,1,2,2]'] - program: 'map_values(. // empty)' input: '{"a": null, "b": true, "c": false}' output: ['{"b":true}'] - title: "`pick(pathexps)`" body: | Emit the projection of the input object or array defined by the specified sequence of path expressions, such that if `p` is any one of these specifications, then `(. | p)` will evaluate to the same value as `(. | pick(pathexps) | p)`. For arrays, negative indices and `.[m:n]` specifications should not be used. examples: - program: 'pick(.a, .b.c, .x)' input: '{"a": 1, "b": {"c": 2, "d": 3}, "e": 4}' output: ['{"a":1,"b":{"c":2},"x":null}'] - program: 'pick(.[2], .[0], .[0])' input: '[1,2,3,4]' output: ['[1,null,3]'] - title: "`path(path_expression)`" body: | Outputs array representations of the given path expression in `.`. The outputs are arrays of strings (object keys) and/or numbers (array indices). Path expressions are jq expressions like `.a`, but also `.[]`. There are two types of path expressions: ones that can match exactly, and ones that cannot. For example, `.a.b.c` is an exact match path expression, while `.a[].b` is not. `path(exact_path_expression)` will produce the array representation of the path expression even if it does not exist in `.`, if `.` is `null` or an array or an object. `path(pattern)` will produce array representations of the paths matching `pattern` if the paths exist in `.`. Note that the path expressions are not different from normal expressions. The expression `path(..|select(type=="boolean"))` outputs all the paths to boolean values in `.`, and only those paths. examples: - program: 'path(.a[0].b)' input: 'null' output: ['["a",0,"b"]'] - program: '[path(..)]' input: '{"a":[{"b":1}]}' output: ['[[],["a"],["a",0],["a",0,"b"]]'] - title: "`del(path_expression)`" body: | The builtin function `del` removes a key and its corresponding value from an object. examples: - program: 'del(.foo)' input: '{"foo": 42, "bar": 9001, "baz": 42}' output: ['{"bar": 9001, "baz": 42}'] - program: 'del(.[1, 2])' input: '["foo", "bar", "baz"]' output: ['["foo"]'] - title: "`getpath(PATHS)`" body: | The builtin function `getpath` outputs the values in `.` found at each path in `PATHS`. examples: - program: 'getpath(["a","b"])' input: 'null' output: ['null'] - program: '[getpath(["a","b"], ["a","c"])]' input: '{"a":{"b":0, "c":1}}' output: ['[0, 1]'] - title: "`setpath(PATHS; VALUE)`" body: | The builtin function `setpath` sets the `PATHS` in `.` to `VALUE`. examples: - program: 'setpath(["a","b"]; 1)' input: 'null' output: ['{"a": {"b": 1}}'] - program: 'setpath(["a","b"]; 1)' input: '{"a":{"b":0}}' output: ['{"a": {"b": 1}}'] - program: 'setpath([0,"a"]; 1)' input: 'null' output: ['[{"a":1}]'] - title: "`delpaths(PATHS)`" body: | The builtin function `delpaths` deletes the `PATHS` in `.`. `PATHS` must be an array of paths, where each path is an array of strings and numbers. examples: - program: 'delpaths([["a","b"]])' input: '{"a":{"b":1},"x":{"y":2}}' output: ['{"a":{},"x":{"y":2}}'] - title: "`to_entries`, `from_entries`, `with_entries(f)`" body: | These functions convert between an object and an array of key-value pairs. If `to_entries` is passed an object, then for each `k: v` entry in the input, the output array includes `{"key": k, "value": v}`. `from_entries` does the opposite conversion, and `with_entries(f)` is a shorthand for `to_entries | map(f) | from_entries`, useful for doing some operation to all keys and values of an object. `from_entries` accepts `"key"`, `"Key"`, `"name"`, `"Name"`, `"value"`, and `"Value"` as keys. examples: - program: 'to_entries' input: '{"a": 1, "b": 2}' output: ['[{"key":"a", "value":1}, {"key":"b", "value":2}]'] - program: 'from_entries' input: '[{"key":"a", "value":1}, {"key":"b", "value":2}]' output: ['{"a": 1, "b": 2}'] - program: 'with_entries(.key |= "KEY_" + .)' input: '{"a": 1, "b": 2}' output: ['{"KEY_a": 1, "KEY_b": 2}'] - title: "`select(boolean_expression)`" body: | The function `select(f)` produces its input unchanged if `f` returns true for that input, and produces no output otherwise. It's useful for filtering lists: `[1,2,3] | map(select(. >= 2))` will give you `[2,3]`. examples: - program: 'map(select(. >= 2))' input: '[1,5,3,0,7]' output: ['[5,3,7]'] - program: '.[] | select(.id == "second")' input: '[{"id": "first", "val": 1}, {"id": "second", "val": 2}]' output: ['{"id": "second", "val": 2}'] - title: "`arrays`, `objects`, `iterables`, `booleans`, `numbers`, `normals`, `finites`, `strings`, `nulls`, `values`, `scalars`" body: | These built-ins select only inputs that are arrays, objects, iterables (arrays or objects), booleans, numbers, normal numbers, finite numbers, strings, null, non-null values, and non-iterables, respectively. examples: - program: '.[]|numbers' input: '[[],{},1,"foo",null,true,false]' output: ['1'] - title: "`empty`" body: | `empty` returns no results. None at all. Not even `null`. It's useful on occasion. You'll know if you need it :) examples: - program: '1, empty, 2' input: 'null' output: ['1', '2'] - program: '[1,2,empty,3]' input: 'null' output: ['[1,2,3]'] - title: "`error`, `error(message)`" body: | Produces an error with the input value, or with the message given as the argument. Errors can be caught with try/catch; see below. examples: - program: 'try error catch .' input: '"error message"' output: ['"error message"'] - program: 'try error("invalid value: \(.)") catch .' input: '42' output: ['"invalid value: 42"'] - title: "`halt`" body: | Stops the jq program with no further outputs. jq will exit with exit status `0`. - title: "`halt_error`, `halt_error(exit_code)`" body: | Stops the jq program with no further outputs. The input will be printed on `stderr` as raw output (i.e., strings will not have double quotes) with no decoration, not even a newline. The given `exit_code` (defaulting to `5`) will be jq's exit status. For example, `"Error: something went wrong\n"|halt_error(1)`. - title: "`$__loc__`" body: | Produces an object with a "file" key and a "line" key, with the filename and line number where `$__loc__` occurs, as values. examples: - program: 'try error("\($__loc__)") catch .' input: 'null' output: ['"{\"file\":\"\",\"line\":1}"'] - title: "`paths`, `paths(node_filter)`" body: | `paths` outputs the paths to all the elements in its input (except it does not output the empty list, representing . itself). `paths(f)` outputs the paths to any values for which `f` is `true`. That is, `paths(type == "number")` outputs the paths to all numeric values. examples: - program: '[paths]' input: '[1,[[],{"a":2}]]' output: ['[[0],[1],[1,0],[1,1],[1,1,"a"]]'] - program: '[paths(type == "number")]' input: '[1,[[],{"a":2}]]' output: ['[[0],[1,1,"a"]]'] - title: "`add`" body: | The filter `add` takes as input an array, and produces as output the elements of the array added together. This might mean summed, concatenated or merged depending on the types of the elements of the input array - the rules are the same as those for the `+` operator (described above). If the input is an empty array, `add` returns `null`. examples: - program: add input: '["a","b","c"]' output: ['"abc"'] - program: add input: '[1, 2, 3]' output: ['6'] - program: add input: '[]' output: ["null"] - title: "`any`, `any(condition)`, `any(generator; condition)`" body: | The filter `any` takes as input an array of boolean values, and produces `true` as output if any of the elements of the array are `true`. If the input is an empty array, `any` returns `false`. The `any(condition)` form applies the given condition to the elements of the input array. The `any(generator; condition)` form applies the given condition to all the outputs of the given generator. examples: - program: any input: '[true, false]' output: ["true"] - program: any input: '[false, false]' output: ["false"] - program: any input: '[]' output: ["false"] - title: "`all`, `all(condition)`, `all(generator; condition)`" body: | The filter `all` takes as input an array of boolean values, and produces `true` as output if all of the elements of the array are `true`. The `all(condition)` form applies the given condition to the elements of the input array. The `all(generator; condition)` form applies the given condition to all the outputs of the given generator. If the input is an empty array, `all` returns `true`. examples: - program: all input: '[true, false]' output: ["false"] - program: all input: '[true, true]' output: ["true"] - program: all input: '[]' output: ["true"] - title: "`flatten`, `flatten(depth)`" body: | The filter `flatten` takes as input an array of nested arrays, and produces a flat array in which all arrays inside the original array have been recursively replaced by their values. You can pass an argument to it to specify how many levels of nesting to flatten. `flatten(2)` is like `flatten`, but going only up to two levels deep. examples: - program: flatten input: '[1, [2], [[3]]]' output: ["[1, 2, 3]"] - program: flatten(1) input: '[1, [2], [[3]]]' output: ["[1, 2, [3]]"] - program: flatten input: '[[]]' output: ["[]"] - program: flatten input: '[{"foo": "bar"}, [{"foo": "baz"}]]' output: ['[{"foo": "bar"}, {"foo": "baz"}]'] - title: "`range(upto)`, `range(from; upto)`, `range(from; upto; by)`" body: | The `range` function produces a range of numbers. `range(4; 10)` produces 6 numbers, from 4 (inclusive) to 10 (exclusive). The numbers are produced as separate outputs. Use `[range(4; 10)]` to get a range as an array. The one argument form generates numbers from 0 to the given number, with an increment of 1. The two argument form generates numbers from `from` to `upto` with an increment of 1. The three argument form generates numbers `from` to `upto` with an increment of `by`. examples: - program: 'range(2; 4)' input: 'null' output: ['2', '3'] - program: '[range(2; 4)]' input: 'null' output: ['[2,3]'] - program: '[range(4)]' input: 'null' output: ['[0,1,2,3]'] - program: '[range(0; 10; 3)]' input: 'null' output: ['[0,3,6,9]'] - program: '[range(0; 10; -1)]' input: 'null' output: ['[]'] - program: '[range(0; -5; -1)]' input: 'null' output: ['[0,-1,-2,-3,-4]'] - title: "`floor`" body: | The `floor` function returns the floor of its numeric input. examples: - program: 'floor' input: '3.14159' output: ['3'] - title: "`sqrt`" body: | The `sqrt` function returns the square root of its numeric input. examples: - program: 'sqrt' input: '9' output: ['3'] - title: "`tonumber`" body: | The `tonumber` function parses its input as a number. It will convert correctly-formatted strings to their numeric equivalent, leave numbers alone, and give an error on all other input. examples: - program: '.[] | tonumber' input: '[1, "1"]' output: ['1', '1'] - title: "`tostring`" body: | The `tostring` function prints its input as a string. Strings are left unchanged, and all other values are JSON-encoded. examples: - program: '.[] | tostring' input: '[1, "1", [1]]' output: ['"1"', '"1"', '"[1]"'] - title: "`type`" body: | The `type` function returns the type of its argument as a string, which is one of null, boolean, number, string, array or object. examples: - program: 'map(type)' input: '[0, false, [], {}, null, "hello"]' output: ['["number", "boolean", "array", "object", "null", "string"]'] - title: "`infinite`, `nan`, `isinfinite`, `isnan`, `isfinite`, `isnormal`" body: | Some arithmetic operations can yield infinities and "not a number" (NaN) values. The `isinfinite` builtin returns `true` if its input is infinite. The `isnan` builtin returns `true` if its input is a NaN. The `infinite` builtin returns a positive infinite value. The `nan` builtin returns a NaN. The `isnormal` builtin returns true if its input is a normal number. Note that division by zero raises an error. Currently most arithmetic operations operating on infinities, NaNs, and sub-normals do not raise errors. examples: - program: '.[] | (infinite * .) < 0' input: '[-1, 1]' output: ['true', 'false'] - program: 'infinite, nan | type' input: 'null' output: ['"number"', '"number"'] - title: "`sort`, `sort_by(path_expression)`" body: | The `sort` functions sorts its input, which must be an array. Values are sorted in the following order: * `null` * `false` * `true` * numbers * strings, in alphabetical order (by unicode codepoint value) * arrays, in lexical order * objects The ordering for objects is a little complex: first they're compared by comparing their sets of keys (as arrays in sorted order), and if their keys are equal then the values are compared key by key. `sort_by` may be used to sort by a particular field of an object, or by applying any jq filter. `sort_by(f)` compares two elements by comparing the result of `f` on each element. When `f` produces multiple values, it firstly compares the first values, and the second values if the first values are equal, and so on. examples: - program: 'sort' input: '[8,3,null,6]' output: ['[null,3,6,8]'] - program: 'sort_by(.foo)' input: '[{"foo":4, "bar":10}, {"foo":3, "bar":10}, {"foo":2, "bar":1}]' output: ['[{"foo":2, "bar":1}, {"foo":3, "bar":10}, {"foo":4, "bar":10}]'] - program: 'sort_by(.foo, .bar)' input: '[{"foo":4, "bar":10}, {"foo":3, "bar":20}, {"foo":2, "bar":1}, {"foo":3, "bar":10}]' output: ['[{"foo":2, "bar":1}, {"foo":3, "bar":10}, {"foo":3, "bar":20}, {"foo":4, "bar":10}]'] - title: "`group_by(path_expression)`" body: | `group_by(.foo)` takes as input an array, groups the elements having the same `.foo` field into separate arrays, and produces all of these arrays as elements of a larger array, sorted by the value of the `.foo` field. Any jq expression, not just a field access, may be used in place of `.foo`. The sorting order is the same as described in the `sort` function above. examples: - program: 'group_by(.foo)' input: '[{"foo":1, "bar":10}, {"foo":3, "bar":100}, {"foo":1, "bar":1}]' output: ['[[{"foo":1, "bar":10}, {"foo":1, "bar":1}], [{"foo":3, "bar":100}]]'] - title: "`min`, `max`, `min_by(path_exp)`, `max_by(path_exp)`" body: | Find the minimum or maximum element of the input array. The `min_by(path_exp)` and `max_by(path_exp)` functions allow you to specify a particular field or property to examine, e.g. `min_by(.foo)` finds the object with the smallest `foo` field. examples: - program: 'min' input: '[5,4,2,7]' output: ['2'] - program: 'max_by(.foo)' input: '[{"foo":1, "bar":14}, {"foo":2, "bar":3}]' output: ['{"foo":2, "bar":3}'] - title: "`unique`, `unique_by(path_exp)`" body: | The `unique` function takes as input an array and produces an array of the same elements, in sorted order, with duplicates removed. The `unique_by(path_exp)` function will keep only one element for each value obtained by applying the argument. Think of it as making an array by taking one element out of every group produced by `group`. examples: - program: 'unique' input: '[1,2,5,3,5,3,1,3]' output: ['[1,2,3,5]'] - program: 'unique_by(.foo)' input: '[{"foo": 1, "bar": 2}, {"foo": 1, "bar": 3}, {"foo": 4, "bar": 5}]' output: ['[{"foo": 1, "bar": 2}, {"foo": 4, "bar": 5}]'] - program: 'unique_by(length)' input: '["chunky", "bacon", "kitten", "cicada", "asparagus"]' output: ['["bacon", "chunky", "asparagus"]'] - title: "`reverse`" body: | This function reverses an array. examples: - program: 'reverse' input: '[1,2,3,4]' output: ['[4,3,2,1]'] - title: "`contains(element)`" body: | The filter `contains(b)` will produce true if b is completely contained within the input. A string B is contained in a string A if B is a substring of A. An array B is contained in an array A if all elements in B are contained in any element in A. An object B is contained in object A if all of the values in B are contained in the value in A with the same key. All other types are assumed to be contained in each other if they are equal. examples: - program: 'contains("bar")' input: '"foobar"' output: ['true'] - program: 'contains(["baz", "bar"])' input: '["foobar", "foobaz", "blarp"]' output: ['true'] - program: 'contains(["bazzzzz", "bar"])' input: '["foobar", "foobaz", "blarp"]' output: ['false'] - program: 'contains({foo: 12, bar: [{barp: 12}]})' input: '{"foo": 12, "bar":[1,2,{"barp":12, "blip":13}]}' output: ['true'] - program: 'contains({foo: 12, bar: [{barp: 15}]})' input: '{"foo": 12, "bar":[1,2,{"barp":12, "blip":13}]}' output: ['false'] - title: "`indices(s)`" body: | Outputs an array containing the indices in `.` where `s` occurs. The input may be an array, in which case if `s` is an array then the indices output will be those where all elements in `.` match those of `s`. examples: - program: 'indices(", ")' input: '"a,b, cd, efg, hijk"' output: ['[3,7,12]'] - program: 'indices(1)' input: '[0,1,2,1,3,1,4]' output: ['[1,3,5]'] - program: 'indices([1,2])' input: '[0,1,2,3,1,4,2,5,1,2,6,7]' output: ['[1,8]'] - title: "`index(s)`, `rindex(s)`" body: | Outputs the index of the first (`index`) or last (`rindex`) occurrence of `s` in the input. examples: - program: 'index(", ")' input: '"a,b, cd, efg, hijk"' output: ['3'] - program: 'index(1)' input: '[0,1,2,1,3,1,4]' output: ['1'] - program: 'index([1,2])' input: '[0,1,2,3,1,4,2,5,1,2,6,7]' output: ['1'] - program: 'rindex(", ")' input: '"a,b, cd, efg, hijk"' output: ['12'] - program: 'rindex(1)' input: '[0,1,2,1,3,1,4]' output: ['5'] - program: 'rindex([1,2])' input: '[0,1,2,3,1,4,2,5,1,2,6,7]' output: ['8'] - title: "`inside`" body: | The filter `inside(b)` will produce true if the input is completely contained within b. It is, essentially, an inversed version of `contains`. examples: - program: 'inside("foobar")' input: '"bar"' output: ['true'] - program: 'inside(["foobar", "foobaz", "blarp"])' input: '["baz", "bar"]' output: ['true'] - program: 'inside(["foobar", "foobaz", "blarp"])' input: '["bazzzzz", "bar"]' output: ['false'] - program: 'inside({"foo": 12, "bar":[1,2,{"barp":12, "blip":13}]})' input: '{"foo": 12, "bar": [{"barp": 12}]}' output: ['true'] - program: 'inside({"foo": 12, "bar":[1,2,{"barp":12, "blip":13}]})' input: '{"foo": 12, "bar": [{"barp": 15}]}' output: ['false'] - title: "`startswith(str)`" body: | Outputs `true` if . starts with the given string argument. examples: - program: '[.[]|startswith("foo")]' input: '["fo", "foo", "barfoo", "foobar", "barfoob"]' output: ['[false, true, false, true, false]'] - title: "`endswith(str)`" body: | Outputs `true` if . ends with the given string argument. examples: - program: '[.[]|endswith("foo")]' input: '["foobar", "barfoo"]' output: ['[false, true]'] - title: "`combinations`, `combinations(n)`" body: | Outputs all combinations of the elements of the arrays in the input array. If given an argument `n`, it outputs all combinations of `n` repetitions of the input array. examples: - program: 'combinations' input: '[[1,2], [3, 4]]' output: ['[1, 3]', '[1, 4]', '[2, 3]', '[2, 4]'] - program: 'combinations(2)' input: '[0, 1]' output: ['[0, 0]', '[0, 1]', '[1, 0]', '[1, 1]'] - title: "`ltrimstr(str)`" body: | Outputs its input with the given prefix string removed, if it starts with it. examples: - program: '[.[]|ltrimstr("foo")]' input: '["fo", "foo", "barfoo", "foobar", "afoo"]' output: ['["fo","","barfoo","bar","afoo"]'] - title: "`rtrimstr(str)`" body: | Outputs its input with the given suffix string removed, if it ends with it. examples: - program: '[.[]|rtrimstr("foo")]' input: '["fo", "foo", "barfoo", "foobar", "foob"]' output: ['["fo","","bar","foobar","foob"]'] - title: "`explode`" body: | Converts an input string into an array of the string's codepoint numbers. examples: - program: 'explode' input: '"foobar"' output: ['[102,111,111,98,97,114]'] - title: "`implode`" body: | The inverse of explode. examples: - program: 'implode' input: '[65, 66, 67]' output: ['"ABC"'] - title: "`split(str)`" body: | Splits an input string on the separator argument. `split` can also split on regex matches when called with two arguments (see the regular expressions section below). examples: - program: 'split(", ")' input: '"a, b,c,d, e, "' output: ['["a","b,c,d","e",""]'] - title: "`join(str)`" body: | Joins the array of elements given as input, using the argument as separator. It is the inverse of `split`: that is, running `split("foo") | join("foo")` over any input string returns said input string. Numbers and booleans in the input are converted to strings. Null values are treated as empty strings. Arrays and objects in the input are not supported. examples: - program: 'join(", ")' input: '["a","b,c,d","e"]' output: ['"a, b,c,d, e"'] - program: 'join(" ")' input: '["a",1,2.3,true,null,false]' output: ['"a 1 2.3 true false"'] - title: "`ascii_downcase`, `ascii_upcase`" body: | Emit a copy of the input string with its alphabetic characters (a-z and A-Z) converted to the specified case. examples: - program: 'ascii_upcase' input: '"useful but not for é"' output: ['"USEFUL BUT NOT FOR é"'] - title: "`while(cond; update)`" body: | The `while(cond; update)` function allows you to repeatedly apply an update to `.` until `cond` is false. Note that `while(cond; update)` is internally defined as a recursive jq function. Recursive calls within `while` will not consume additional memory if `update` produces at most one output for each input. See advanced topics below. examples: - program: '[while(.<100; .*2)]' input: '1' output: ['[1,2,4,8,16,32,64]'] - title: "`repeat(exp)`" body: | The `repeat(exp)` function allows you to repeatedly apply expression `exp` to `.` until an error is raised. Note that `repeat(exp)` is internally defined as a recursive jq function. Recursive calls within `repeat` will not consume additional memory if `exp` produces at most one output for each input. See advanced topics below. examples: - program: '[repeat(.*2, error)?]' input: '1' output: ['[2]'] - title: "`until(cond; next)`" body: | The `until(cond; next)` function allows you to repeatedly apply the expression `next`, initially to `.` then to its own output, until `cond` is true. For example, this can be used to implement a factorial function (see below). Note that `until(cond; next)` is internally defined as a recursive jq function. Recursive calls within `until()` will not consume additional memory if `next` produces at most one output for each input. See advanced topics below. examples: - program: '[.,1]|until(.[0] < 1; [.[0] - 1, .[1] * .[0]])|.[1]' input: '4' output: ['24'] - title: "`recurse(f)`, `recurse`, `recurse(f; condition)`" body: | The `recurse(f)` function allows you to search through a recursive structure, and extract interesting data from all levels. Suppose your input represents a filesystem: {"name": "/", "children": [ {"name": "/bin", "children": [ {"name": "/bin/ls", "children": []}, {"name": "/bin/sh", "children": []}]}, {"name": "/home", "children": [ {"name": "/home/stephen", "children": [ {"name": "/home/stephen/jq", "children": []}]}]}]} Now suppose you want to extract all of the filenames present. You need to retrieve `.name`, `.children[].name`, `.children[].children[].name`, and so on. You can do this with: recurse(.children[]) | .name When called without an argument, `recurse` is equivalent to `recurse(.[]?)`. `recurse(f)` is identical to `recurse(f; true)` and can be used without concerns about recursion depth. `recurse(f; condition)` is a generator which begins by emitting . and then emits in turn .|f, .|f|f, .|f|f|f, ... so long as the computed value satisfies the condition. For example, to generate all the integers, at least in principle, one could write `recurse(.+1; true)`. The recursive calls in `recurse` will not consume additional memory whenever `f` produces at most a single output for each input. examples: - program: 'recurse(.foo[])' input: '{"foo":[{"foo": []}, {"foo":[{"foo":[]}]}]}' output: - '{"foo":[{"foo":[]},{"foo":[{"foo":[]}]}]}' - '{"foo":[]}' - '{"foo":[{"foo":[]}]}' - '{"foo":[]}' - program: 'recurse' input: '{"a":0,"b":[1]}' output: - '{"a":0,"b":[1]}' - '0' - '[1]' - '1' - program: 'recurse(. * .; . < 20)' input: '2' output: ['2', '4', '16'] - title: "`walk(f)`" body: | The `walk(f)` function applies f recursively to every component of the input entity. When an array is encountered, f is first applied to its elements and then to the array itself; when an object is encountered, f is first applied to all the values and then to the object. In practice, f will usually test the type of its input, as illustrated in the following examples. The first example highlights the usefulness of processing the elements of an array of arrays before processing the array itself. The second example shows how all the keys of all the objects within the input can be considered for alteration. examples: - program: 'walk(if type == "array" then sort else . end)' input: '[[4, 1, 7], [8, 5, 2], [3, 6, 9]]' output: - '[[1,4,7],[2,5,8],[3,6,9]]' - program: 'walk( if type == "object" then with_entries( .key |= sub( "^_+"; "") ) else . end )' input: '[ { "_a": { "__b": 2 } } ]' output: - '[{"a":{"b":2}}]' - title: "`$JQ_BUILD_CONFIGURATION`" body: | This builtin binding shows the jq executable's build configuration. Its value has no particular format, but it can be expected to be at least the `./configure` command-line arguments, and may be enriched in the future to include the version strings for the build tooling used. Note that this can be overridden in the command-line with `--arg` and related options. - title: "`$ENV`, `env`" body: | `$ENV` is an object representing the environment variables as set when the jq program started. `env` outputs an object representing jq's current environment. At the moment there is no builtin for setting environment variables. examples: - program: '$ENV.PAGER' input: 'null' output: ['"less"'] - program: 'env.PAGER' input: 'null' output: ['"less"'] - title: "`transpose`" body: | Transpose a possibly jagged matrix (an array of arrays). Rows are padded with nulls so the result is always rectangular. examples: - program: 'transpose' input: '[[1], [2,3]]' output: ['[[1,2],[null,3]]'] - title: "`bsearch(x)`" body: | `bsearch(x)` conducts a binary search for x in the input array. If the input is sorted and contains x, then `bsearch(x)` will return its index in the array; otherwise, if the array is sorted, it will return (-1 - ix) where ix is an insertion point such that the array would still be sorted after the insertion of x at ix. If the array is not sorted, `bsearch(x)` will return an integer that is probably of no interest. examples: - program: 'bsearch(0)' input: '[0,1]' output: ['0'] - program: 'bsearch(0)' input: '[1,2,3]' output: ['-1'] - program: 'bsearch(4) as $ix | if $ix < 0 then .[-(1+$ix)] = 4 else . end' input: '[1,2,3]' output: ['[1,2,3,4]'] - title: "String interpolation: `\\(exp)`" body: | Inside a string, you can put an expression inside parens after a backslash. Whatever the expression returns will be interpolated into the string. examples: - program: '"The input was \(.), which is one less than \(.+1)"' input: '42' output: ['"The input was 42, which is one less than 43"'] - title: "Convert to/from JSON" body: | The `tojson` and `fromjson` builtins dump values as JSON texts or parse JSON texts into values, respectively. The `tojson` builtin differs from `tostring` in that `tostring` returns strings unmodified, while `tojson` encodes strings as JSON strings. examples: - program: '[.[]|tostring]' input: '[1, "foo", ["foo"]]' output: ['["1","foo","[\"foo\"]"]'] - program: '[.[]|tojson]' input: '[1, "foo", ["foo"]]' output: ['["1","\"foo\"","[\"foo\"]"]'] - program: '[.[]|tojson|fromjson]' input: '[1, "foo", ["foo"]]' output: ['[1,"foo",["foo"]]'] - title: "Format strings and escaping" body: | The `@foo` syntax is used to format and escape strings, which is useful for building URLs, documents in a language like HTML or XML, and so forth. `@foo` can be used as a filter on its own, the possible escapings are: * `@text`: Calls `tostring`, see that function for details. * `@json`: Serializes the input as JSON. * `@html`: Applies HTML/XML escaping, by mapping the characters `<>&'"` to their entity equivalents `<`, `>`, `&`, `'`, `"`. * `@uri`: Applies percent-encoding, by mapping all reserved URI characters to a `%XX` sequence. * `@csv`: The input must be an array, and it is rendered as CSV with double quotes for strings, and quotes escaped by repetition. * `@tsv`: The input must be an array, and it is rendered as TSV (tab-separated values). Each input array will be printed as a single line. Fields are separated by a single tab (ascii `0x09`). Input characters line-feed (ascii `0x0a`), carriage-return (ascii `0x0d`), tab (ascii `0x09`) and backslash (ascii `0x5c`) will be output as escape sequences `\n`, `\r`, `\t`, `\\` respectively. * `@sh`: The input is escaped suitable for use in a command-line for a POSIX shell. If the input is an array, the output will be a series of space-separated strings. * `@base64`: The input is converted to base64 as specified by RFC 4648. * `@base64d`: The inverse of `@base64`, input is decoded as specified by RFC 4648. Note\: If the decoded string is not UTF-8, the results are undefined. This syntax can be combined with string interpolation in a useful way. You can follow a `@foo` token with a string literal. The contents of the string literal will *not* be escaped. However, all interpolations made inside that string literal will be escaped. For instance, @uri "https://www.google.com/search?q=\(.search)" will produce the following output for the input `{"search":"what is jq?"}`: "https://www.google.com/search?q=what%20is%20jq%3F" Note that the slashes, question mark, etc. in the URL are not escaped, as they were part of the string literal. examples: - program: '@html' input: '"This works if x < y"' output: ['"This works if x < y"'] - program: '@sh "echo \(.)"' input: "\"O'Hara's Ale\"" output: ["\"echo 'O'\\\\''Hara'\\\\''s Ale'\""] - program: '@base64' input: '"This is a message"' output: ['"VGhpcyBpcyBhIG1lc3NhZ2U="'] - program: '@base64d' input: '"VGhpcyBpcyBhIG1lc3NhZ2U="' output: ['"This is a message"'] - title: "Dates" body: | jq provides some basic date handling functionality, with some high-level and low-level builtins. In all cases these builtins deal exclusively with time in UTC. The `fromdateiso8601` builtin parses datetimes in the ISO 8601 format to a number of seconds since the Unix epoch (1970-01-01T00:00:00Z). The `todateiso8601` builtin does the inverse. The `fromdate` builtin parses datetime strings. Currently `fromdate` only supports ISO 8601 datetime strings, but in the future it will attempt to parse datetime strings in more formats. The `todate` builtin is an alias for `todateiso8601`. The `now` builtin outputs the current time, in seconds since the Unix epoch. Low-level jq interfaces to the C-library time functions are also provided: `strptime`, `strftime`, `strflocaltime`, `mktime`, `gmtime`, and `localtime`. Refer to your host operating system's documentation for the format strings used by `strptime` and `strftime`. Note: these are not necessarily stable interfaces in jq, particularly as to their localization functionality. The `gmtime` builtin consumes a number of seconds since the Unix epoch and outputs a "broken down time" representation of Greenwich Mean Time as an array of numbers representing (in this order): the year, the month (zero-based), the day of the month (one-based), the hour of the day, the minute of the hour, the second of the minute, the day of the week, and the day of the year -- all one-based unless otherwise stated. The day of the week number may be wrong on some systems for dates before March 1st 1900, or after December 31 2099. The `localtime` builtin works like the `gmtime` builtin, but using the local timezone setting. The `mktime` builtin consumes "broken down time" representations of time output by `gmtime` and `strptime`. The `strptime(fmt)` builtin parses input strings matching the `fmt` argument. The output is in the "broken down time" representation consumed by `mktime` and output by `gmtime`. The `strftime(fmt)` builtin formats a time (GMT) with the given format. The `strflocaltime` does the same, but using the local timezone setting. The format strings for `strptime` and `strftime` are described in typical C library documentation. The format string for ISO 8601 datetime is `"%Y-%m-%dT%H:%M:%SZ"`. jq may not support some or all of this date functionality on some systems. In particular, the `%u` and `%j` specifiers for `strptime(fmt)` are not supported on macOS. examples: - program: 'fromdate' input: '"2015-03-05T23:51:47Z"' output: ['1425599507'] - program: 'strptime("%Y-%m-%dT%H:%M:%SZ")' input: '"2015-03-05T23:51:47Z"' output: ['[2015,2,5,23,51,47,4,63]'] - program: 'strptime("%Y-%m-%dT%H:%M:%SZ")|mktime' input: '"2015-03-05T23:51:47Z"' output: ['1425599507'] - title: "SQL-Style Operators" body: | jq provides a few SQL-style operators. * `INDEX(stream; index_expression)`: This builtin produces an object whose keys are computed by the given index expression applied to each value from the given stream. * `JOIN($idx; stream; idx_expr; join_expr)`: This builtin joins the values from the given stream to the given index. The index's keys are computed by applying the given index expression to each value from the given stream. An array of the value in the stream and the corresponding value from the index is fed to the given join expression to produce each result. * `JOIN($idx; stream; idx_expr)`: Same as `JOIN($idx; stream; idx_expr; .)`. * `JOIN($idx; idx_expr)`: This builtin joins the input `.` to the given index, applying the given index expression to `.` to compute the index key. The join operation is as described above. * `IN(s)`: This builtin outputs `true` if `.` appears in the given stream, otherwise it outputs `false`. * `IN(source; s)`: This builtin outputs `true` if any value in the source stream appears in the second stream, otherwise it outputs `false`. - title: "`builtins`" body: | Returns a list of all builtin functions in the format `name/arity`. Since functions with the same name but different arities are considered separate functions, `all/0`, `all/1`, and `all/2` would all be present in the list. - title: Conditionals and Comparisons entries: - title: "`==`, `!=`" body: | The expression 'a == b' will produce 'true' if the results of evaluating a and b are equal (that is, if they represent equivalent JSON values) and 'false' otherwise. In particular, strings are never considered equal to numbers. In checking for the equality of JSON objects, the ordering of keys is irrelevant. If you're coming from JavaScript, please note that jq's `==` is like JavaScript's `===`, the "strict equality" operator. != is "not equal", and 'a != b' returns the opposite value of 'a == b' examples: - program: '. == false' input: 'null' output: ['false'] - program: '. == {"b": {"d": (4 + 1e-20), "c": 3}, "a":1}' input: '{"a":1, "b": {"c": 3, "d": 4}}' output: ['true'] - program: '.[] == 1' input: '[1, 1.0, "1", "banana"]' output: ['true', 'true', 'false', 'false'] - title: if-then-else-end body: | `if A then B else C end` will act the same as `B` if `A` produces a value other than false or null, but act the same as `C` otherwise. `if A then B end` is the same as `if A then B else . end`. That is, the `else` branch is optional, and if absent is the same as `.`. This also applies to `elif` with absent ending `else` branch. Checking for false or null is a simpler notion of "truthiness" than is found in JavaScript or Python, but it means that you'll sometimes have to be more explicit about the condition you want. You can't test whether, e.g. a string is empty using `if .name then A else B end`; you'll need something like `if .name == "" then A else B end` instead. If the condition `A` produces multiple results, then `B` is evaluated once for each result that is not false or null, and `C` is evaluated once for each false or null. More cases can be added to an if using `elif A then B` syntax. examples: - program: |- if . == 0 then "zero" elif . == 1 then "one" else "many" end input: '2' output: ['"many"'] - title: "`>`, `>=`, `<=`, `<`" body: | The comparison operators `>`, `>=`, `<=`, `<` return whether their left argument is greater than, greater than or equal to, less than or equal to or less than their right argument (respectively). The ordering is the same as that described for `sort`, above. examples: - program: '. < 5' input: '2' output: ['true'] - title: "`and`, `or`, `not`" body: | jq supports the normal Boolean operators `and`, `or`, `not`. They have the same standard of truth as if expressions - `false` and `null` are considered "false values", and anything else is a "true value". If an operand of one of these operators produces multiple results, the operator itself will produce a result for each input. `not` is in fact a builtin function rather than an operator, so it is called as a filter to which things can be piped rather than with special syntax, as in `.foo and .bar | not`. These three only produce the values `true` and `false`, and so are only useful for genuine Boolean operations, rather than the common Perl/Python/Ruby idiom of "value_that_may_be_null or default". If you want to use this form of "or", picking between two values rather than evaluating a condition, see the `//` operator below. examples: - program: '42 and "a string"' input: 'null' output: ['true'] - program: '(true, false) or false' input: 'null' output: ['true', 'false'] - program: '(true, true) and (true, false)' input: 'null' output: ['true', 'false', 'true', 'false'] - program: '[true, false | not]' input: 'null' output: ['[false, true]'] - title: "Alternative operator: `//`" body: | The `//` operator produces all the values of its left-hand side that are neither `false` nor `null`, or, if the left-hand side produces no values other than `false` or `null`, then `//` produces all the values of its right-hand side. A filter of the form `a // b` produces all the results of `a` that are not `false` or `null`. If `a` produces no results, or no results other than `false` or `null`, then `a // b` produces the results of `b`. This is useful for providing defaults: `.foo // 1` will evaluate to `1` if there's no `.foo` element in the input. It's similar to how `or` is sometimes used in Python (jq's `or` operator is reserved for strictly Boolean operations). Note: `some_generator // defaults_here` is not the same as `some_generator | . // defaults_here`. The latter will produce default values for all non-`false`, non-`null` values of the left-hand side, while the former will not. Precedence rules can make this confusing. For example, in `false, 1 // 2` the left-hand side of `//` is `1`, not `false, 1` -- `false, 1 // 2` parses the same way as `false, (1 // 2)`. In `(false, null, 1) | . // 42` the left-hand side of `//` is `.`, which always produces just one value, while in `(false, null, 1) // 42` the left-hand side is a generator of three values, and since it produces a value other `false` and `null`, the default `42` is not produced. examples: - program: 'empty // 42' input: 'null' output: ['42'] - program: '.foo // 42' input: '{"foo": 19}' output: ['19'] - program: '.foo // 42' input: '{}' output: ['42'] - program: '(false, null, 1) // 42' input: 'null' output: ['1'] - program: '(false, null, 1) | . // 42' input: 'null' output: ['42', '42', '1'] - title: try-catch body: | Errors can be caught by using `try EXP catch EXP`. The first expression is executed, and if it fails then the second is executed with the error message. The output of the handler, if any, is output as if it had been the output of the expression to try. The `try EXP` form uses `empty` as the exception handler. examples: - program: 'try .a catch ". is not an object"' input: 'true' output: ['". is not an object"'] - program: '[.[]|try .a]' input: '[{}, true, {"a":1}]' output: ['[null, 1]'] - program: 'try error("some exception") catch .' input: 'true' output: ['"some exception"'] - title: Breaking out of control structures body: | A convenient use of try/catch is to break out of control structures like `reduce`, `foreach`, `while`, and so on. For example: # Repeat an expression until it raises "break" as an # error, then stop repeating without re-raising the error. # But if the error caught is not "break" then re-raise it. try repeat(exp) catch if .=="break" then empty else error jq has a syntax for named lexical labels to "break" or "go (back) to": label $out | ... break $out ... The `break $label_name` expression will cause the program to act as though the nearest (to the left) `label $label_name` produced `empty`. The relationship between the `break` and corresponding `label` is lexical: the label has to be "visible" from the break. To break out of a `reduce`, for example: label $out | reduce .[] as $item (null; if .==false then break $out else ... end) The following jq program produces a syntax error: break $out because no label `$out` is visible. - title: "Error Suppression / Optional Operator: `?`" body: | The `?` operator, used as `EXP?`, is shorthand for `try EXP`. examples: - program: '[.[] | .a?]' input: '[{}, true, {"a":1}]' output: ['[null, 1]'] - program: '[.[] | tonumber?]' input: '["1", "invalid", "3", 4]' output: ['[1, 3, 4]'] - title: Regular expressions body: | jq uses the [Oniguruma regular expression library](https://github.com/kkos/oniguruma/blob/master/doc/RE), as do PHP, TextMate, Sublime Text, etc, so the description here will focus on jq specifics. Oniguruma supports several flavors of regular expression, so it is important to know that jq uses the ["Perl NG" (Perl with named groups)](https://github.com/kkos/oniguruma/blob/master/doc/SYNTAX.md) flavor. The jq regex filters are defined so that they can be used using one of these patterns: STRING | FILTER(REGEX) STRING | FILTER(REGEX; FLAGS) STRING | FILTER([REGEX]) STRING | FILTER([REGEX, FLAGS]) where: * STRING, REGEX, and FLAGS are jq strings and subject to jq string interpolation; * REGEX, after string interpolation, should be a valid regular expression; * FILTER is one of `test`, `match`, or `capture`, as described below. Since REGEX must evaluate to a JSON string, some characters that are needed to form a regular expression must be escaped. For example, the regular expression `\s` signifying a whitespace character would be written as `"\\s"`. FLAGS is a string consisting of one of more of the supported flags: * `g` - Global search (find all matches, not just the first) * `i` - Case insensitive search * `m` - Multi line mode (`.` will match newlines) * `n` - Ignore empty matches * `p` - Both s and m modes are enabled * `s` - Single line mode (`^` -> `\A`, `$` -> `\Z`) * `l` - Find longest possible matches * `x` - Extended regex format (ignore whitespace and comments) To match a whitespace with the `x` flag, use `\s`, e.g. jq -n '"a b" | test("a\\sb"; "x")' Note that certain flags may also be specified within REGEX, e.g. jq -n '("test", "TEst", "teST", "TEST") | test("(?i)te(?-i)st")' evaluates to: `true`, `true`, `false`, `false`. entries: - title: "`test(val)`, `test(regex; flags)`" body: | Like `match`, but does not return match objects, only `true` or `false` for whether or not the regex matches the input. examples: - program: 'test("foo")' input: '"foo"' output: ['true'] - program: '.[] | test("a b c # spaces are ignored"; "ix")' input: '["xabcd", "ABC"]' output: ['true', 'true'] - title: "`match(val)`, `match(regex; flags)`" body: | **match** outputs an object for each match it finds. Matches have the following fields: * `offset` - offset in UTF-8 codepoints from the beginning of the input * `length` - length in UTF-8 codepoints of the match * `string` - the string that it matched * `captures` - an array of objects representing capturing groups. Capturing group objects have the following fields: * `offset` - offset in UTF-8 codepoints from the beginning of the input * `length` - length in UTF-8 codepoints of this capturing group * `string` - the string that was captured * `name` - the name of the capturing group (or `null` if it was unnamed) Capturing groups that did not match anything return an offset of -1 examples: - program: 'match("(abc)+"; "g")' input: '"abc abc"' output: - '{"offset": 0, "length": 3, "string": "abc", "captures": [{"offset": 0, "length": 3, "string": "abc", "name": null}]}' - '{"offset": 4, "length": 3, "string": "abc", "captures": [{"offset": 4, "length": 3, "string": "abc", "name": null}]}' - program: 'match("foo")' input: '"foo bar foo"' output: ['{"offset": 0, "length": 3, "string": "foo", "captures": []}'] - program: 'match(["foo", "ig"])' input: '"foo bar FOO"' output: - '{"offset": 0, "length": 3, "string": "foo", "captures": []}' - '{"offset": 8, "length": 3, "string": "FOO", "captures": []}' - program: 'match("foo (?bar)? foo"; "ig")' input: '"foo bar foo foo foo"' output: - '{"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"}]}' - program: '[ match("."; "g")] | length' input: '"abc"' output: ['3'] - title: "`capture(val)`, `capture(regex; flags)`" body: | Collects the named captures in a JSON object, with the name of each capture as the key, and the matched string as the corresponding value. examples: - program: 'capture("(?[a-z]+)-(?[0-9]+)")' input: '"xyzzy-14"' output: ['{ "a": "xyzzy", "n": "14" }'] - title: "`scan(regex)`, `scan(regex; flags)`" body: | Emit a stream of the non-overlapping substrings of the input that match the regex in accordance with the flags, if any have been specified. If there is no match, the stream is empty. To capture all the matches for each input string, use the idiom `[ expr ]`, e.g. `[ scan(regex) ]`. If the regex contains capturing groups, the filter emits a stream of arrays, each of which contains the captured strings. examples: - program: 'scan("c")' input: '"abcdefabc"' output: ['"c"', '"c"'] - program: 'scan("(a+)(b+)")' input: '"abaabbaaabbb"' output: ['["a","b"]', '["aa","bb"]', '["aaa","bbb"]'] - title: "`split(regex; flags)`" body: | Splits an input string on each regex match. For backwards compatibility, when called with a single argument, `split` splits on a string, not a regex. examples: - program: 'split(", *"; null)' input: '"ab,cd, ef"' output: ['["ab","cd","ef"]'] - title: "`splits(regex)`, `splits(regex; flags)`" body: | These provide the same results as their `split` counterparts, but as a stream instead of an array. examples: - program: 'splits(", *")' input: '"ab,cd, ef, gh"' output: ['"ab"','"cd"','"ef"','"gh"'] - title: "`sub(regex; tostring)`, `sub(regex; tostring; flags)`" body: | Emit the string obtained by replacing the first match of regex in the input string with `tostring`, after interpolation. `tostring` should be a jq string or a stream of such strings, each of which may contain references to named captures. The named captures are, in effect, presented as a JSON object (as constructed by `capture`) to `tostring`, so a reference to a captured variable named "x" would take the form: `"\(.x)"`. examples: - program: 'sub("[^a-z]*(?[a-z]+)"; "Z\(.x)"; "g")' input: '"123abc456def"' output: ['"ZabcZdef"'] - program: '[sub("(?.)"; "\(.a|ascii_upcase)", "\(.a|ascii_downcase)")]' input: '"aB"' output: ['["AB","aB"]'] - title: "`gsub(regex; tostring)`, `gsub(regex; tostring; flags)`" body: | `gsub` is like `sub` but all the non-overlapping occurrences of the regex are replaced by `tostring`, after interpolation. If the second argument is a stream of jq strings, then `gsub` will produce a corresponding stream of JSON strings. examples: - program: 'gsub("(?.)[^a]*"; "+\(.x)-")' input: '"Abcabc"' output: ['"+A-+a-"'] - program: '[gsub("p"; "a", "b")]' input: '"p"' output: ['["a","b"]'] - title: Advanced features body: | Variables are an absolute necessity in most programming languages, but they're relegated to an "advanced feature" in jq. In most languages, variables are the only means of passing around data. If you calculate a value, and you want to use it more than once, you'll need to store it in a variable. To pass a value to another part of the program, you'll need that part of the program to define a variable (as a function parameter, object member, or whatever) in which to place the data. It is also possible to define functions in jq, although this is is a feature whose biggest use is defining jq's standard library (many jq functions such as `map` and `select` are in fact written in jq). jq has reduction operators, which are very powerful but a bit tricky. Again, these are mostly used internally, to define some useful bits of jq's standard library. It may not be obvious at first, but jq is all about generators (yes, as often found in other languages). Some utilities are provided to help deal with generators. Some minimal I/O support (besides reading JSON from standard input, and writing JSON to standard output) is available. Finally, there is a module/library system. entries: - title: "Variable / Symbolic Binding Operator: `... as $identifier | ...`" body: | In jq, all filters have an input and an output, so manual plumbing is not necessary to pass a value from one part of a program to the next. Many expressions, for instance `a + b`, pass their input to two distinct subexpressions (here `a` and `b` are both passed the same input), so variables aren't usually necessary in order to use a value twice. For instance, calculating the average value of an array of numbers requires a few variables in most languages - at least one to hold the array, perhaps one for each element or for a loop counter. In jq, it's simply `add / length` - the `add` expression is given the array and produces its sum, and the `length` expression is given the array and produces its length. So, there's generally a cleaner way to solve most problems in jq than defining variables. Still, sometimes they do make things easier, so jq lets you define variables using `expression as $variable`. All variable names start with `$`. Here's a slightly uglier version of the array-averaging example: length as $array_length | add / $array_length We'll need a more complicated problem to find a situation where using variables actually makes our lives easier. Suppose we have an array of blog posts, with "author" and "title" fields, and another object which is used to map author usernames to real names. Our input looks like: {"posts": [{"title": "First post", "author": "anon"}, {"title": "A well-written article", "author": "person1"}], "realnames": {"anon": "Anonymous Coward", "person1": "Person McPherson"}} We want to produce the posts with the author field containing a real name, as in: {"title": "First post", "author": "Anonymous Coward"} {"title": "A well-written article", "author": "Person McPherson"} We use a variable, `$names`, to store the realnames object, so that we can refer to it later when looking up author usernames: .realnames as $names | .posts[] | {title, author: $names[.author]} The expression `exp as $x | ...` means: for each value of expression `exp`, run the rest of the pipeline with the entire original input, and with `$x` set to that value. Thus `as` functions as something of a foreach loop. Just as `{foo}` is a handy way of writing `{foo: .foo}`, so `{$foo}` is a handy way of writing `{foo: $foo}`. Multiple variables may be declared using a single `as` expression by providing a pattern that matches the structure of the input (this is known as "destructuring"): . as {realnames: $names, posts: [$first, $second]} | ... The variable declarations in array patterns (e.g., `. as [$first, $second]`) bind to the elements of the array in from the element at index zero on up, in order. When there is no value at the index for an array pattern element, `null` is bound to that variable. Variables are scoped over the rest of the expression that defines them, so .realnames as $names | (.posts[] | {title, author: $names[.author]}) will work, but (.realnames as $names | .posts[]) | {title, author: $names[.author]} won't. For programming language theorists, it's more accurate to say that jq variables are lexically-scoped bindings. In particular there's no way to change the value of a binding; one can only setup a new binding with the same name, but which will not be visible where the old one was. examples: - program: '.bar as $x | .foo | . + $x' input: '{"foo":10, "bar":200}' output: ['210'] - program: '. as $i|[(.*2|. as $i| $i), $i]' input: '5' output: ['[10,5]'] - program: '. as [$a, $b, {c: $c}] | $a + $b + $c' input: '[2, 3, {"c": 4, "d": 5}]' output: ['9'] - program: '.[] as [$a, $b] | {a: $a, b: $b}' input: '[[0], [0, 1], [2, 1, 0]]' output: ['{"a":0,"b":null}', '{"a":0,"b":1}', '{"a":2,"b":1}'] - title: 'Destructuring Alternative Operator: `?//`' body: | The destructuring alternative operator provides a concise mechanism for destructuring an input that can take one of several forms. Suppose we have an API that returns a list of resources and events associated with them, and we want to get the user_id and timestamp of the first event for each resource. The API (having been clumsily converted from XML) will only wrap the events in an array if the resource has multiple events: {"resources": [{"id": 1, "kind": "widget", "events": {"action": "create", "user_id": 1, "ts": 13}}, {"id": 2, "kind": "widget", "events": [{"action": "create", "user_id": 1, "ts": 14}, {"action": "destroy", "user_id": 1, "ts": 15}]}]} We can use the destructuring alternative operator to handle this structural change simply: .resources[] as {$id, $kind, events: {$user_id, $ts}} ?// {$id, $kind, events: [{$user_id, $ts}]} | {$user_id, $kind, $id, $ts} Or, if we aren't sure if the input is an array of values or an object: .[] as [$id, $kind, $user_id, $ts] ?// {$id, $kind, $user_id, $ts} | ... Each alternative need not define all of the same variables, but all named variables will be available to the subsequent expression. Variables not matched in the alternative that succeeded will be `null`: .resources[] as {$id, $kind, events: {$user_id, $ts}} ?// {$id, $kind, events: [{$first_user_id, $first_ts}]} | {$user_id, $first_user_id, $kind, $id, $ts, $first_ts} Additionally, if the subsequent expression returns an error, the alternative operator will attempt to try the next binding. Errors that occur during the final alternative are passed through. [[3]] | .[] as [$a] ?// [$b] | if $a != null then error("err: \($a)") else {$a,$b} end examples: - program: '.[] as {$a, $b, c: {$d, $e}} ?// {$a, $b, c: [{$d, $e}]} | {$a, $b, $d, $e}' input: '[{"a": 1, "b": 2, "c": {"d": 3, "e": 4}}, {"a": 1, "b": 2, "c": [{"d": 3, "e": 4}]}]' output: ['{"a":1,"b":2,"d":3,"e":4}', '{"a":1,"b":2,"d":3,"e":4}'] - program: '.[] as {$a, $b, c: {$d}} ?// {$a, $b, c: [{$e}]} | {$a, $b, $d, $e}' input: '[{"a": 1, "b": 2, "c": {"d": 3, "e": 4}}, {"a": 1, "b": 2, "c": [{"d": 3, "e": 4}]}]' output: ['{"a":1,"b":2,"d":3,"e":null}', '{"a":1,"b":2,"d":null,"e":4}'] - program: '.[] as [$a] ?// [$b] | if $a != null then error("err: \($a)") else {$a,$b} end' input: '[[3]]' output: ['{"a":null,"b":3}'] - title: 'Defining Functions' body: | You can give a filter a name using "def" syntax: def increment: . + 1; From then on, `increment` is usable as a filter just like a builtin function (in fact, this is how many of the builtins are defined). A function may take arguments: def map(f): [.[] | f]; Arguments are passed as _filters_ (functions with no arguments), _not_ as values. The same argument may be referenced multiple times with different inputs (here `f` is run for each element of the input array). Arguments to a function work more like callbacks than like value arguments. This is important to understand. Consider: def foo(f): f|f; 5|foo(.*2) The result will be 20 because `f` is `.*2`, and during the first invocation of `f` `.` will be 5, and the second time it will be 10 (5 * 2), so the result will be 20. Function arguments are filters, and filters expect an input when invoked. If you want the value-argument behaviour for defining simple functions, you can just use a variable: def addvalue(f): f as $f | map(. + $f); Or use the short-hand: def addvalue($f): ...; With either definition, `addvalue(.foo)` will add the current input's `.foo` field to each element of the array. Do note that calling `addvalue(.[])` will cause the `map(. + $f)` part to be evaluated once per value in the value of `.` at the call site. Multiple definitions using the same function name are allowed. Each re-definition replaces the previous one for the same number of function arguments, but only for references from functions (or main program) subsequent to the re-definition. See also the section below on scoping. examples: - program: 'def addvalue(f): . + [f]; map(addvalue(.[0]))' input: '[[1,2],[10,20]]' output: ['[[1,2,1], [10,20,10]]'] - program: 'def addvalue(f): f as $x | map(. + $x); addvalue(.[0])' input: '[[1,2],[10,20]]' output: ['[[1,2,1,2], [10,20,1,2]]'] - title: 'Scoping' body: | There are two types of symbols in jq: value bindings (a.k.a., "variables"), and functions. Both are scoped lexically, with expressions being able to refer only to symbols that have been defined "to the left" of them. The only exception to this rule is that functions can refer to themselves so as to be able to create recursive functions. For example, in the following expression there is a binding which is visible "to the right" of it, `... | .*3 as $times_three | [. + $times_three] | ...`, but not "to the left". Consider this expression now, `... | (.*3 as $times_three | [. + $times_three]) | ...`: here the binding `$times_three` is _not_ visible past the closing parenthesis. - title: "`isempty(exp)`" body: | Returns true if `exp` produces no outputs, false otherwise. examples: - program: 'isempty(empty)' input: 'null' output: ['true'] - program: 'isempty(.[])' input: '[]' output: ['true'] - program: 'isempty(.[])' input: '[1,2,3]' output: ['false'] - title: "`limit(n; exp)`" body: | The `limit` function extracts up to `n` outputs from `exp`. examples: - program: '[limit(3;.[])]' input: '[0,1,2,3,4,5,6,7,8,9]' output: ['[0,1,2]'] - title: "`first(expr)`, `last(expr)`, `nth(n; expr)`" body: | The `first(expr)` and `last(expr)` functions extract the first and last values from `expr`, respectively. The `nth(n; expr)` function extracts the nth value output by `expr`. Note that `nth(n; expr)` doesn't support negative values of `n`. examples: - program: '[first(range(.)), last(range(.)), nth(./2; range(.))]' input: '10' output: ['[0,9,5]'] - title: "`first`, `last`, `nth(n)`" body: | The `first` and `last` functions extract the first and last values from any array at `.`. The `nth(n)` function extracts the nth value of any array at `.`. examples: - program: '[range(.)]|[first, last, nth(5)]' input: '10' output: ['[0,9,5]'] - title: "`reduce`" body: | The `reduce` syntax allows you to combine all of the results of an expression by accumulating them into a single answer. The form is `reduce EXP as $var (INIT; UPDATE)`. As an example, we'll pass `[1,2,3]` to this expression: reduce .[] as $item (0; . + $item) For each result that `.[]` produces, `. + $item` is run to accumulate a running total, starting from 0 as the input value. In this example, `.[]` produces the results `1`, `2`, and `3`, so the effect is similar to running something like this: 0 | 1 as $item | . + $item | 2 as $item | . + $item | 3 as $item | . + $item examples: - program: 'reduce .[] as $item (0; . + $item)' input: '[1,2,3,4,5]' output: ['15'] - program: 'reduce .[] as [$i,$j] (0; . + $i * $j)' input: '[[1,2],[3,4],[5,6]]' output: ['44'] - program: 'reduce .[] as {$x,$y} (null; .x += $x | .y += [$y])' input: '[{"x":"a","y":1},{"x":"b","y":2},{"x":"c","y":3}]' output: ['{"x":"abc","y":[1,2,3]}'] - title: "`foreach`" body: | The `foreach` syntax is similar to `reduce`, but intended to allow the construction of `limit` and reducers that produce intermediate results. The form is `foreach EXP as $var (INIT; UPDATE; EXTRACT)`. As an example, we'll pass `[1,2,3]` to this expression: foreach .[] as $item (0; . + $item; [$item, . * 2]) Like the `reduce` syntax, `. + $item` is run for each result that `.[]` produces, but `[$item, . * 2]` is run for each intermediate values. In this example, since the intermediate values are `1`, `3`, and `6`, the `foreach` expression produces `[1,2]`, `[2,6]`, and `[3,12]`. So the effect is similar to running something like this: 0 | 1 as $item | . + $item | [$item, . * 2], 2 as $item | . + $item | [$item, . * 2], 3 as $item | . + $item | [$item, . * 2] When `EXTRACT` is omitted, the identity filter is used. That is, it outputs the intermediate values as they are. examples: - program: 'foreach .[] as $item (0; . + $item)' input: '[1,2,3,4,5]' output: ['1','3','6','10','15'] - program: 'foreach .[] as $item (0; . + $item; [$item, . * 2])' input: '[1,2,3,4,5]' output: ['[1,2]','[2,6]','[3,12]','[4,20]','[5,30]'] - program: 'foreach .[] as $item (0; . + 1; {index: ., $item})' input: '["foo", "bar", "baz"]' output: - '{"index":1,"item":"foo"}' - '{"index":2,"item":"bar"}' - '{"index":3,"item":"baz"}' - title: Recursion body: | As described above, `recurse` uses recursion, and any jq function can be recursive. The `while` builtin is also implemented in terms of recursion. Tail calls are optimized whenever the expression to the left of the recursive call outputs its last value. In practice this means that the expression to the left of the recursive call should not produce more than one output for each input. For example: def recurse(f): def r: ., (f | select(. != null) | r); r; def while(cond; update): def _while: if cond then ., (update | _while) else empty end; _while; def repeat(exp): def _repeat: exp, _repeat; _repeat; - title: Generators and iterators body: | Some jq operators and functions are actually generators in that they can produce zero, one, or more values for each input, just as one might expect in other programming languages that have generators. For example, `.[]` generates all the values in its input (which must be an array or an object), `range(0; 10)` generates the integers between 0 and 10, and so on. Even the comma operator is a generator, generating first the values generated by the expression to the left of the comma, then the values generated by the expression on the right of the comma. The `empty` builtin is the generator that produces zero outputs. The `empty` builtin backtracks to the preceding generator expression. All jq functions can be generators just by using builtin generators. It is also possible to construct new generators using only recursion and the comma operator. If recursive calls are "in tail position" then the generator will be efficient. In the example below the recursive call by `_range` to itself is in tail position. The example shows off three advanced topics: tail recursion, generator construction, and sub-functions. examples: - program: 'def range(init; upto; by): def _range: if (by > 0 and . < upto) or (by < 0 and . > upto) then ., ((.+by)|_range) else empty end; if init == upto then empty elif by == 0 then init else init|_range end; range(0; 10; 3)' input: 'null' output: ['0', '3', '6', '9'] - program: 'def while(cond; update): def _while: if cond then ., (update | _while) else empty end; _while; [while(.<100; .*2)]' input: '1' output: ['[1,2,4,8,16,32,64]'] - title: 'Math' body: | jq currently only has IEEE754 double-precision (64-bit) floating point number support. Besides simple arithmetic operators such as `+`, jq also has most standard math functions from the C math library. C math functions that take a single input argument (e.g., `sin()`) are available as zero-argument jq functions. C math functions that take two input arguments (e.g., `pow()`) are available as two-argument jq functions that ignore `.`. C math functions that take three input arguments are available as three-argument jq functions that ignore `.`. Availability of standard math functions depends on the availability of the corresponding math functions in your operating system and C math library. Unavailable math functions will be defined but will raise an error. One-input C math functions: `acos` `acosh` `asin` `asinh` `atan` `atanh` `cbrt` `ceil` `cos` `cosh` `erf` `erfc` `exp` `exp10` `exp2` `expm1` `fabs` `floor` `gamma` `j0` `j1` `lgamma` `log` `log10` `log1p` `log2` `logb` `nearbyint` `pow10` `rint` `round` `significand` `sin` `sinh` `sqrt` `tan` `tanh` `tgamma` `trunc` `y0` `y1`. Two-input C math functions: `atan2` `copysign` `drem` `fdim` `fmax` `fmin` `fmod` `frexp` `hypot` `jn` `ldexp` `modf` `nextafter` `nexttoward` `pow` `remainder` `scalb` `scalbln` `yn`. Three-input C math functions: `fma`. See your system's manual for more information on each of these. - title: 'I/O' body: | At this time jq has minimal support for I/O, mostly in the form of control over when inputs are read. Two builtins functions are provided for this, `input` and `inputs`, that read from the same sources (e.g., `stdin`, files named on the command-line) as jq itself. These two builtins, and jq's own reading actions, can be interleaved with each other. They are commonly used in combination with the null input option `-n` to prevent one input from being read implicitly. Two builtins provide minimal output capabilities, `debug`, and `stderr`. (Recall that a jq program's output values are always output as JSON texts on `stdout`.) The `debug` builtin can have application-specific behavior, such as for executables that use the libjq C API but aren't the jq executable itself. The `stderr` builtin outputs its input in raw mode to stderr with no additional decoration, not even a newline. Most jq builtins are referentially transparent, and yield constant and repeatable value streams when applied to constant inputs. This is not true of I/O builtins. entries: - title: "`input`" body: | Outputs one new input. Note that when using `input` it is generally necessary to invoke jq with the `-n` command-line option, otherwise the first entity will be lost. echo 1 2 3 4 | jq '[., input]' # [1,2] [3,4] - title: "`inputs`" body: | Outputs all remaining inputs, one by one. This is primarily useful for reductions over a program's inputs. Note that when using `inputs` it is generally necessary to invoke jq with the `-n` command-line option, otherwise the first entity will be lost. echo 1 2 3 | jq -n 'reduce inputs as $i (0; . + $i)' # 6 - title: "`debug`, `debug(msgs)`" body: | These two filters are like `.` but have as a side-effect the production of one or more messages on stderr. The message produced by the `debug` filter has the form ["DEBUG:",] where `` is a compact rendition of the input value. This format may change in the future. The `debug(msgs)` filter is defined as `(msgs | debug | empty), .` thus allowing great flexibility in the content of the message, while also allowing multi-line debugging statements to be created. For example, the expression: 1 as $x | 2 | debug("Entering function foo with $x == \($x)", .) | (.+1) would produce the value 3 but with the following two lines being written to stderr: ["DEBUG:","Entering function foo with $x == 1"] ["DEBUG:",2] - title: "`stderr`" body: | Prints its input in raw and compact mode to stderr with no additional decoration, not even a newline. - title: "`input_filename`" body: | Returns the name of the file whose input is currently being filtered. Note that this will not work well unless jq is running in a UTF-8 locale. - title: "`input_line_number`" body: | Returns the line number of the input currently being filtered. - title: 'Streaming' body: | With the `--stream` option jq can parse input texts in a streaming fashion, allowing jq programs to start processing large JSON texts immediately rather than after the parse completes. If you have a single JSON text that is 1GB in size, streaming it will allow you to process it much more quickly. However, streaming isn't easy to deal with as the jq program will have `[, ]` (and a few other forms) as inputs. Several builtins are provided to make handling streams easier. The examples below use the streamed form of `["a",["b"]]`, which is `[[0],"a"],[[1,0],"b"],[[1,0]],[[1]]`. Streaming forms include `[, ]` (to indicate any scalar value, empty array, or empty object), and `[]` (to indicate the end of an array or object). Future versions of jq run with `--stream` and `--seq` may output additional forms such as `["error message"]` when an input text fails to parse. entries: - title: "`truncate_stream(stream_expression)`" body: | Consumes a number as input and truncates the corresponding number of path elements from the left of the outputs of the given streaming expression. examples: - program: 'truncate_stream([[0],"a"],[[1,0],"b"],[[1,0]],[[1]])' input: '1' output: ['[[0],"b"]', '[[0]]'] - title: "`fromstream(stream_expression)`" body: | Outputs values corresponding to the stream expression's outputs. examples: - program: 'fromstream(1|truncate_stream([[0],"a"],[[1,0],"b"],[[1,0]],[[1]]))' input: 'null' output: ['["b"]'] - title: "`tostream`" body: | The `tostream` builtin outputs the streamed form of its input. examples: - program: '. as $dot|fromstream($dot|tostream)|.==$dot' input: '[0,[1,{"a":1},{"b":2}]]' output: ['true'] - title: Assignment body: | Assignment works a little differently in jq than in most programming languages. jq doesn't distinguish between references to and copies of something - two objects or arrays are either equal or not equal, without any further notion of being "the same object" or "not the same object". If an object has two fields which are arrays, `.foo` and `.bar`, and you append something to `.foo`, then `.bar` will not get bigger, even if you've previously set `.bar = .foo`. If you're used to programming in languages like Python, Java, Ruby, JavaScript, etc. then you can think of it as though jq does a full deep copy of every object before it does the assignment (for performance it doesn't actually do that, but that's the general idea). This means that it's impossible to build circular values in jq (such as an array whose first element is itself). This is quite intentional, and ensures that anything a jq program can produce can be represented in JSON. All the assignment operators in jq have path expressions on the left-hand side (LHS). The right-hand side (RHS) provides values to set to the paths named by the LHS path expressions. Values in jq are always immutable. Internally, assignment works by using a reduction to compute new, replacement values for `.` that have had all the desired assignments applied to `.`, then outputting the modified value. This might be made clear by this example: `{a:{b:{c:1}}} | (.a.b|=3), .`. This will output `{"a":{"b":3}}` and `{"a":{"b":{"c":1}}}` because the last sub-expression, `.`, sees the original value, not the modified value. Most users will want to use modification assignment operators, such as `|=` or `+=`, rather than `=`. Note that the LHS of assignment operators refers to a value in `.`. Thus `$var.foo = 1` won't work as expected (`$var.foo` is not a valid or useful path expression in `.`); use `$var | .foo = 1` instead. Note too that `.a,.b=0` does not set `.a` and `.b`, but `(.a,.b)=0` sets both. entries: - title: "Update-assignment: `|=`" body: | This is the "update" operator `|=`. It takes a filter on the right-hand side and works out the new value for the property of `.` being assigned to by running the old value through this expression. For instance, `(.foo, .bar) |= .+1` will build an object with the `foo` field set to the input's `foo` plus 1, and the `bar` field set to the input's `bar` plus 1. The left-hand side can be any general path expression; see `path()`. Note that the left-hand side of `|=` refers to a value in `.`. Thus `$var.foo |= . + 1` won't work as expected (`$var.foo` is not a valid or useful path expression in `.`); use `$var | .foo |= . + 1` instead. If the right-hand side outputs no values (i.e., `empty`), then the left-hand side path will be deleted, as with `del(path)`. If the right-hand side outputs multiple values, only the first one will be used (COMPATIBILITY NOTE: in jq 1.5 and earlier releases, it used to be that only the last one was used). examples: - program: '(..|select(type=="boolean")) |= if . then 1 else 0 end' input: '[true,false,[5,true,[true,[false]],false]]' output: ['[1,0,[5,1,[1,[0]],0]]'] - title: "Arithmetic update-assignment: `+=`, `-=`, `*=`, `/=`, `%=`, `//=`" body: | jq has a few operators of the form `a op= b`, which are all equivalent to `a |= . op b`. So, `+= 1` can be used to increment values, being the same as `|= . + 1`. examples: - program: .foo += 1 input: '{"foo": 42}' output: ['{"foo": 43}'] - title: "Plain assignment: `=`" body: | This is the plain assignment operator. Unlike the others, the input to the right-hand side (RHS) is the same as the input to the left-hand side (LHS) rather than the value at the LHS path, and all values output by the RHS will be used (as shown below). If the RHS of `=` produces multiple values, then for each such value jq will set the paths on the left-hand side to the value and then it will output the modified `.`. For example, `(.a,.b) = range(2)` outputs `{"a":0,"b":0}`, then `{"a":1,"b":1}`. The "update" assignment forms (see above) do not do this. This example should show the difference between `=` and `|=`: Provide input `{"a": {"b": 10}, "b": 20}` to the programs .a = .b and .a |= .b The former will set the `a` field of the input to the `b` field of the input, and produce the output `{"a": 20, "b": 20}`. The latter will set the `a` field of the input to the `a` field's `b` field, producing `{"a": 10, "b": 20}`. examples: - program: .a = .b input: '{"a": {"b": 10}, "b": 20}' output: ['{"a":20,"b":20}'] - program: .a |= .b input: '{"a": {"b": 10}, "b": 20}' output: ['{"a":10,"b":20}'] - program: (.a, .b) = range(3) input: 'null' output: - '{"a":0,"b":0}' - '{"a":1,"b":1}' - '{"a":2,"b":2}' - program: (.a, .b) |= range(3) input: 'null' output: ['{"a":0,"b":0}'] - title: Complex assignments body: | Lots more things are allowed on the left-hand side of a jq assignment than in most languages. We've already seen simple field accesses on the left hand side, and it's no surprise that array accesses work just as well: .posts[0].title = "JQ Manual" What may come as a surprise is that the expression on the left may produce multiple results, referring to different points in the input document: .posts[].comments |= . + ["this is great"] That example appends the string "this is great" to the "comments" array of each post in the input (where the input is an object with a field "posts" which is an array of posts). When jq encounters an assignment like 'a = b', it records the "path" taken to select a part of the input document while executing a. This path is then used to find which part of the input to change while executing the assignment. Any filter may be used on the left-hand side of an equals - whichever paths it selects from the input will be where the assignment is performed. This is a very powerful operation. Suppose we wanted to add a comment to blog posts, using the same "blog" input above. This time, we only want to comment on the posts written by "stedolan". We can find those posts using the "select" function described earlier: .posts[] | select(.author == "stedolan") The paths provided by this operation point to each of the posts that "stedolan" wrote, and we can comment on each of them in the same way that we did before: (.posts[] | select(.author == "stedolan") | .comments) |= . + ["terrible."] - title: Modules body: | jq has a library/module system. Modules are files whose names end in `.jq`. Modules imported by a program are searched for in a default search path (see below). The `import` and `include` directives allow the importer to alter this path. Paths in the search path are subject to various substitutions. For paths starting with `~/`, the user's home directory is substituted for `~`. For paths starting with `$ORIGIN/`, the directory where the jq executable is located is substituted for `$ORIGIN`. For paths starting with `./` or paths that are `.`, the path of the including file is substituted for `.`. For top-level programs given on the command-line, the current directory is used. Import directives can optionally specify a search path to which the default is appended. The default search path is the search path given to the `-L` command-line option, else `["~/.jq", "$ORIGIN/../lib/jq", "$ORIGIN/../lib"]`. Null and empty string path elements terminate search path processing. A dependency with relative path `foo/bar` would be searched for in `foo/bar.jq` and `foo/bar/bar.jq` in the given search path. This is intended to allow modules to be placed in a directory along with, for example, version control files, README files, and so on, but also to allow for single-file modules. Consecutive components with the same name are not allowed to avoid ambiguities (e.g., `foo/foo`). For example, with `-L$HOME/.jq` a module `foo` can be found in `$HOME/.jq/foo.jq` and `$HOME/.jq/foo/foo.jq`. If `$HOME/.jq` is a file, it is sourced into the main program. entries: - title: "`import RelativePathString as NAME [];`" body: | Imports a module found at the given path relative to a directory in a search path. A `.jq` suffix will be added to the relative path string. The module's symbols are prefixed with `NAME::`. The optional metadata must be a constant jq expression. It should be an object with keys like `homepage` and so on. At this time jq only uses the `search` key/value of the metadata. The metadata is also made available to users via the `modulemeta` builtin. The `search` key in the metadata, if present, should have a string or array value (array of strings); this is the search path to be prefixed to the top-level search path. - title: "`include RelativePathString [];`" body: | Imports a module found at the given path relative to a directory in a search path as if it were included in place. A `.jq` suffix will be added to the relative path string. The module's symbols are imported into the caller's namespace as if the module's content had been included directly. The optional metadata must be a constant jq expression. It should be an object with keys like `homepage` and so on. At this time jq only uses the `search` key/value of the metadata. The metadata is also made available to users via the `modulemeta` builtin. - title: "`import RelativePathString as $NAME [];`" body: | Imports a JSON file found at the given path relative to a directory in a search path. A `.json` suffix will be added to the relative path string. The file's data will be available as `$NAME::NAME`. The optional metadata must be a constant jq expression. It should be an object with keys like `homepage` and so on. At this time jq only uses the `search` key/value of the metadata. The metadata is also made available to users via the `modulemeta` builtin. The `search` key in the metadata, if present, should have a string or array value (array of strings); this is the search path to be prefixed to the top-level search path. - title: "`module ;`" body: | This directive is entirely optional. It's not required for proper operation. It serves only the purpose of providing metadata that can be read with the `modulemeta` builtin. The metadata must be a constant jq expression. It should be an object with keys like `homepage`. At this time jq doesn't use this metadata, but it is made available to users via the `modulemeta` builtin. - title: "`modulemeta`" body: | Takes a module name as input and outputs the module's metadata as an object, with the module's imports (including metadata) as an array value for the `deps` key and the module's defined functions as an array value for the `defs` key. Programs can use this to query a module's metadata, which they could then use to, for example, search for, download, and install missing dependencies. - title: Colors body: | To configure alternative colors just set the `JQ_COLORS` environment variable to colon-delimited list of partial terminal escape sequences like `"1;31"`, in this order: - color for `null` - color for `false` - color for `true` - color for numbers - color for strings - color for arrays - color for objects - color for object keys The default color scheme is the same as setting `JQ_COLORS="0;90:0;37:0;37:0;37:0;32:1;37:1;37:1;34"`. This is not a manual for VT100/ANSI escapes. However, each of these color specifications should consist of two numbers separated by a semi-colon, where the first number is one of these: - 1 (bright) - 2 (dim) - 4 (underscore) - 5 (blink) - 7 (reverse) - 8 (hidden) and the second is one of these: - 30 (black) - 31 (red) - 32 (green) - 33 (yellow) - 34 (blue) - 35 (magenta) - 36 (cyan) - 37 (white) ================================================ FILE: docs/content/manual/v1.8/manual.yml ================================================ --- headline: jq 1.8 Manual body: | A jq program is a "filter": it takes an input, and produces an output. There are a lot of builtin filters for extracting a particular field of an object, or converting a number to a string, or various other standard tasks. Filters can be combined in various ways - you can pipe the output of one filter into another filter, or collect the output of a filter into an array. Some filters produce multiple results, for instance there's one that produces all the elements of its input array. Piping that filter into a second runs the second filter for each element of the array. Generally, things that would be done with loops and iteration in other languages are just done by gluing filters together in jq. It's important to remember that every filter has an input and an output. Even literals like "hello" or 42 are filters - they take an input but always produce the same literal as output. Operations that combine two filters, like addition, generally feed the same input to both and combine the results. So, you can implement an averaging filter as `add / length` - feeding the input array both to the `add` filter and the `length` filter and then performing the division. But that's getting ahead of ourselves. :) Let's start with something simpler: manpage_intro: | jq(1) -- Command-line JSON processor ==================================== ## SYNOPSIS `jq` [...] [...] `jq` can transform JSON in various ways, by selecting, iterating, reducing and otherwise mangling JSON documents. For instance, running the command `jq 'map(.price) | add'` will take an array of JSON objects as input and return the sum of their "price" fields. `jq` can accept text input as well, but by default, `jq` reads a stream of JSON entities (including numbers and other literals) from `stdin`. Whitespace is only needed to separate entities such as 1 and 2, and true and false. One or more may be specified, in which case `jq` will read input from those instead. The are described in the [INVOKING JQ] section; they mostly concern input and output formatting. The is written in the jq language and specifies how to transform the input file or document. ## FILTERS manpage_epilogue: | ## BUGS Presumably. Report them or discuss them at: https://github.com/jqlang/jq/issues ## AUTHOR Stephen Dolan `` sections: - title: Invoking jq body: | jq filters run on a stream of JSON data. The input to jq is parsed as a sequence of whitespace-separated JSON values which are passed through the provided filter one at a time. The output(s) of the filter are written to standard output, as a sequence of newline-separated JSON data. The simplest and most common filter (or jq program) is `.`, which is the identity operator, copying the inputs of the jq processor to the output stream. Because the default behavior of the jq processor is to read JSON texts from the input stream, and to pretty-print outputs, the `.` program's main use is to validate and pretty-print the inputs. The jq programming language is quite rich and allows for much more than just validation and pretty-printing. Note: it is important to mind the shell's quoting rules. As a general rule it's best to always quote (with single-quote characters on Unix shells) the jq program, as too many characters with special meaning to jq are also shell meta-characters. For example, `jq "foo"` will fail on most Unix shells because that will be the same as `jq foo`, which will generally fail because `foo is not defined`. When using the Windows command shell (cmd.exe) it's best to use double quotes around your jq program when given on the command-line (instead of the `-f program-file` option), but then double-quotes in the jq program need backslash escaping. When using the Powershell (`powershell.exe`) or the Powershell Core (`pwsh`/`pwsh.exe`), use single-quote characters around the jq program and backslash-escaped double-quotes (`\"`) inside the jq program. * Unix shells: `jq '.["foo"]'` * Powershell: `jq '.[\"foo\"]'` * Windows command shell: `jq ".[\"foo\"]"` Note: jq allows user-defined functions, but every jq program must have a top-level expression. You can affect how jq reads and writes its input and output using some command-line options: * `--null-input` / `-n`: Don't read any input at all. Instead, the filter is run once using `null` as the input. This is useful when using jq as a simple calculator or to construct JSON data from scratch. * `--raw-input` / `-R`: Don't parse the input as JSON. Instead, each line of text is passed to the filter as a string. If combined with `--slurp`, then the entire input is passed to the filter as a single long string. * `--slurp` / `-s`: Instead of running the filter for each JSON object in the input, read the entire input stream into a large array and run the filter just once. * `--compact-output` / `-c`: By default, jq pretty-prints JSON output. Using this option will result in more compact output by instead putting each JSON object on a single line. * `--raw-output` / `-r`: With this option, if the filter's result is a string then it will be written directly to standard output rather than being formatted as a JSON string with quotes. This can be useful for making jq filters talk to non-JSON-based systems. * `--raw-output0`: Like `-r` but jq will print NUL instead of newline after each output. This can be useful when the values being output can contain newlines. When the output value contains NUL, jq exits with non-zero code. * `--join-output` / `-j`: Like `-r` but jq won't print a newline after each output. * `--ascii-output` / `-a`: jq usually outputs non-ASCII Unicode codepoints as UTF-8, even if the input specified them as escape sequences (like "\u03bc"). Using this option, you can force jq to produce pure ASCII output with every non-ASCII character replaced with the equivalent escape sequence. * `--sort-keys` / `-S`: Output the fields of each object with the keys in sorted order. * `--color-output` / `-C` and `--monochrome-output` / `-M`: By default, jq outputs colored JSON if writing to a terminal. You can force it to produce color even if writing to a pipe or a file using `-C`, and disable color with `-M`. When the `NO_COLOR` environment variable is not empty, jq disables colored output by default, but you can enable it by `-C`. Colors can be configured with the `JQ_COLORS` environment variable (see below). * `--tab`: Use a tab for each indentation level instead of two spaces. * `--indent n`: Use the given number of spaces (no more than 7) for indentation. * `--unbuffered`: Flush the output after each JSON object is printed (useful if you're piping a slow data source into jq and piping jq's output elsewhere). * `--stream`: Parse the input in streaming fashion, outputting arrays of path and leaf values (scalars and empty arrays or empty objects). For example, `"a"` becomes `[[],"a"]`, and `[[],"a",["b"]]` becomes `[[0],[]]`, `[[1],"a"]`, and `[[2,0],"b"]`. This is useful for processing very large inputs. Use this in conjunction with filtering and the `reduce` and `foreach` syntax to reduce large inputs incrementally. * `--stream-errors`: Like `--stream`, but invalid JSON inputs yield array values where the first element is the error and the second is a path. For example, `["a",n]` produces `["Invalid literal at line 1, column 7",[1]]`. Implies `--stream`. Invalid JSON inputs produce no error values when `--stream` without `--stream-errors`. * `--seq`: Use the `application/json-seq` MIME type scheme for separating JSON texts in jq's input and output. This means that an ASCII RS (record separator) character is printed before each value on output and an ASCII LF (line feed) is printed after every output. Input JSON texts that fail to parse are ignored (but warned about), discarding all subsequent input until the next RS. This mode also parses the output of jq without the `--seq` option. * `-f` / `--from-file`: Read the filter from a file rather than from a command line, like awk's -f option. This changes the filter argument to be interpreted as a filename, instead of the source of a program. * `-L directory` / `--library-path directory`: Prepend `directory` to the search list for modules. If this option is used then no builtin search list is used. See the section on modules below. * `--arg name value`: This option passes a value to the jq program as a predefined variable. If you run jq with `--arg foo bar`, then `$foo` is available in the program and has the value `"bar"`. Note that `value` will be treated as a string, so `--arg foo 123` will bind `$foo` to `"123"`. Named arguments are also available to the jq program as `$ARGS.named`. When the name is not a valid identifier, this is the only way to access it. * `--argjson name JSON-text`: This option passes a JSON-encoded value to the jq program as a predefined variable. If you run jq with `--argjson foo 123`, then `$foo` is available in the program and has the value `123`. * `--slurpfile variable-name filename`: This option reads all the JSON texts in the named file and binds an array of the parsed JSON values to the given global variable. If you run jq with `--slurpfile foo bar`, then `$foo` is available in the program and has an array whose elements correspond to the texts in the file named `bar`. * `--rawfile variable-name filename`: This option reads in the named file and binds its content to the given global variable. If you run jq with `--rawfile foo bar`, then `$foo` is available in the program and has a string whose content is set to the text in the file named `bar`. * `--args`: Remaining arguments are positional string arguments. These are available to the jq program as `$ARGS.positional[]`. * `--jsonargs`: Remaining arguments are positional JSON text arguments. These are available to the jq program as `$ARGS.positional[]`. * `--exit-status` / `-e`: Sets the exit status of jq to 0 if the last output value was neither `false` nor `null`, 1 if the last output value was either `false` or `null`, or 4 if no valid result was ever produced. Normally jq exits with 2 if there was any usage problem or system error, 3 if there was a jq program compile error, or 0 if the jq program ran. Another way to set the exit status is with the `halt_error` builtin function. * `--binary` / `-b`: Windows users using WSL, MSYS2, or Cygwin, should use this option when using a native jq.exe, otherwise jq will turn newlines (LFs) into carriage-return-then-newline (CRLF). * `--version` / `-V`: Output the jq version and exit with zero. * `--build-configuration`: Output the build configuration of jq and exit with zero. This output has no supported format or structure and may change without notice in future releases. * `--help` / `-h`: Output the jq help and exit with zero. * `--`: Terminates argument processing. Remaining arguments are not interpreted as options. * `--run-tests [filename]`: Runs the tests in the given file or standard input. This must be the last option given and does not honor all preceding options. The input consists of comment lines, empty lines, and program lines followed by one input line, as many lines of output as are expected (one per output), and a terminating empty line. Compilation failure tests start with a line containing only `%%FAIL`, then a line containing the program to compile, then a line containing an error message to compare to the actual. Be warned that this option can change backwards-incompatibly. - title: Basic filters entries: - title: "Identity: `.`" body: | The absolute simplest filter is `.` . This filter takes its input and produces the same value as output. That is, this is the identity operator. Since jq by default pretty-prints all output, a trivial program consisting of nothing but `.` can be used to format JSON output from, say, `curl`. Although the identity filter never modifies the value of its input, jq processing can sometimes make it appear as though it does. For example, using the current implementation of jq, we would see that the expression: 1E1234567890 | . produces `1.7976931348623157e+308` on at least one platform. This is because, in the process of parsing the number, this particular version of jq has converted it to an IEEE754 double-precision representation, losing precision. The way in which jq handles numbers has changed over time and further changes are likely within the parameters set by the relevant JSON standards. Moreover, build configuration options can alter how jq processes numbers. The following remarks are therefore offered with the understanding that they are intended to be descriptive of the current version of jq and should not be interpreted as being prescriptive: (1) Any arithmetic operation on a number that has not already been converted to an IEEE754 double precision representation will trigger a conversion to the IEEE754 representation. (2) jq will attempt to maintain the original decimal precision of number literals (if the `--disable-decnum` build configuration option was not used), but in expressions such `1E1234567890`, precision will be lost if the exponent is too large. (3) Comparisons are carried out using the untruncated big decimal representation of numbers if available, as illustrated in one of the following examples. The examples below use the builtin function `have_decnum` in order to demonstrate the expected effects of using / not using the `--disable-decnum` build configuration option, and also to allow automated tests derived from these examples to pass regardless of whether that option is used. examples: - program: '.' input: '"Hello, world!"' output: ['"Hello, world!"'] - program: '.' input: '0.12345678901234567890123456789' output: ['0.12345678901234567890123456789'] - program: '[., tojson] == if have_decnum then [12345678909876543212345,"12345678909876543212345"] else [12345678909876543000000,"12345678909876543000000"] end' input: '12345678909876543212345' output: ['true'] - program: '[1234567890987654321,-1234567890987654321 | tojson] == if have_decnum then ["1234567890987654321","-1234567890987654321"] else ["1234567890987654400","-1234567890987654400"] end' input: 'null' output: ['true'] - program: '. < 0.12345678901234567890123456788' input: '0.12345678901234567890123456789' output: ['false'] - program: 'map([., . == 1]) | tojson == if have_decnum then "[[1,true],[1.000,true],[1.0,true],[1.00,true]]" else "[[1,true],[1,true],[1,true],[1,true]]" end' input: '[1, 1.000, 1.0, 100e-2]' output: ['true'] - program: '. as $big | [$big, $big + 1] | map(. > 10000000000000000000000000000000) | . == if have_decnum then [true, false] else [false, false] end' input: '10000000000000000000000000000001' output: ['true'] - title: "Object Identifier-Index: `.foo`, `.foo.bar`" body: | The simplest *useful* filter has the form `.foo`. When given a JSON object (aka dictionary or hash) as input, `.foo` produces the value at the key "foo" if the key is present, or null otherwise. A filter of the form `.foo.bar` is equivalent to `.foo | .bar`. The `.foo` syntax only works for simple, identifier-like keys, that is, keys that are all made of alphanumeric characters and underscore, and which do not start with a digit. If the key contains special characters or starts with a digit, you need to surround it with double quotes like this: `."foo$"`, or else `.["foo$"]`. For example `.["foo::bar"]` and `.["foo.bar"]` work while `.foo::bar` does not. examples: - program: '.foo' input: '{"foo": 42, "bar": "less interesting data"}' output: ['42'] - program: '.foo' input: '{"notfoo": true, "alsonotfoo": false}' output: ['null'] - program: '.["foo"]' input: '{"foo": 42}' output: ['42'] - title: "Optional Object Identifier-Index: `.foo?`" body: | Just like `.foo`, but does not output an error when `.` is not an object. examples: - program: '.foo?' input: '{"foo": 42, "bar": "less interesting data"}' output: ['42'] - program: '.foo?' input: '{"notfoo": true, "alsonotfoo": false}' output: ['null'] - program: '.["foo"]?' input: '{"foo": 42}' output: ['42'] - program: '[.foo?]' input: '[1,2]' output: ['[]'] - title: "Object Index: `.[]`" body: | You can also look up fields of an object using syntax like `.["foo"]` (`.foo` above is a shorthand version of this, but only for identifier-like strings). - title: "Array Index: `.[]`" body: | When the index value is an integer, `.[]` can index arrays. Arrays are zero-based, so `.[2]` returns the third element. Negative indices are allowed, with -1 referring to the last element, -2 referring to the next to last element, and so on. examples: - program: '.[0]' input: '[{"name":"JSON", "good":true}, {"name":"XML", "good":false}]' output: ['{"name":"JSON", "good":true}'] - program: '.[2]' input: '[{"name":"JSON", "good":true}, {"name":"XML", "good":false}]' output: ['null'] - program: '.[-2]' input: '[1,2,3]' output: ['2'] - title: "Array/String Slice: `.[:]`" body: | The `.[:]` syntax can be used to return a subarray of an array or substring of a string. The array returned by `.[10:15]` will be of length 5, containing the elements from index 10 (inclusive) to index 15 (exclusive). Either index may be negative (in which case it counts backwards from the end of the array), or omitted (in which case it refers to the start or end of the array). Indices are zero-based. examples: - program: '.[2:4]' input: '["a","b","c","d","e"]' output: ['["c", "d"]'] - program: '.[2:4]' input: '"abcdefghi"' output: ['"cd"'] - program: '.[:3]' input: '["a","b","c","d","e"]' output: ['["a", "b", "c"]'] - program: '.[-2:]' input: '["a","b","c","d","e"]' output: ['["d", "e"]'] - title: "Array/Object Value Iterator: `.[]`" body: | If you use the `.[index]` syntax, but omit the index entirely, it will return *all* of the elements of an array. Running `.[]` with the input `[1,2,3]` will produce the numbers as three separate results, rather than as a single array. A filter of the form `.foo[]` is equivalent to `.foo | .[]`. You can also use this on an object, and it will return all the values of the object. Note that the iterator operator is a generator of values. examples: - program: '.[]' input: '[{"name":"JSON", "good":true}, {"name":"XML", "good":false}]' output: - '{"name":"JSON", "good":true}' - '{"name":"XML", "good":false}' - program: '.[]' input: '[]' output: [] - program: '.foo[]' input: '{"foo":[1,2,3]}' output: ['1','2','3'] - program: '.[]' input: '{"a": 1, "b": 1}' output: ['1', '1'] - title: "`.[]?`" body: | Like `.[]`, but no errors will be output if . is not an array or object. A filter of the form `.foo[]?` is equivalent to `.foo | .[]?`. - title: "Comma: `,`" body: | If two filters are separated by a comma, then the same input will be fed into both and the two filters' output value streams will be concatenated in order: first, all of the outputs produced by the left expression, and then all of the outputs produced by the right. For instance, filter `.foo, .bar`, produces both the "foo" fields and "bar" fields as separate outputs. The `,` operator is one way to construct generators. examples: - program: '.foo, .bar' input: '{"foo": 42, "bar": "something else", "baz": true}' output: ['42', '"something else"'] - program: ".user, .projects[]" input: '{"user":"stedolan", "projects": ["jq", "wikiflow"]}' output: ['"stedolan"', '"jq"', '"wikiflow"'] - program: '.[4,2]' input: '["a","b","c","d","e"]' output: ['"e"', '"c"'] - title: "Pipe: `|`" body: | The | operator combines two filters by feeding the output(s) of the one on the left into the input of the one on the right. It's similar to the Unix shell's pipe, if you're used to that. If the one on the left produces multiple results, the one on the right will be run for each of those results. So, the expression `.[] | .foo` retrieves the "foo" field of each element of the input array. This is a cartesian product, which can be surprising. Note that `.a.b.c` is the same as `.a | .b | .c`. Note too that `.` is the input value at the particular stage in a "pipeline", specifically: where the `.` expression appears. Thus `.a | . | .b` is the same as `.a.b`, as the `.` in the middle refers to whatever value `.a` produced. examples: - program: '.[] | .name' input: '[{"name":"JSON", "good":true}, {"name":"XML", "good":false}]' output: ['"JSON"', '"XML"'] - title: "Parenthesis" body: | Parenthesis work as a grouping operator just as in any typical programming language. examples: - program: '(. + 2) * 5' input: '1' output: ['15'] - title: Types and Values body: | jq supports the same set of datatypes as JSON - numbers, strings, booleans, arrays, objects (which in JSON-speak are hashes with only string keys), and "null". Booleans, null, strings and numbers are written the same way as in JSON. Just like everything else in jq, these simple values take an input and produce an output - `42` is a valid jq expression that takes an input, ignores it, and returns 42 instead. Numbers in jq are internally represented by their IEEE754 double precision approximation. Any arithmetic operation with numbers, whether they are literals or results of previous filters, will produce a double precision floating point result. However, when parsing a literal jq will store the original literal string. If no mutation is applied to this value then it will make to the output in its original form, even if conversion to double would result in a loss. entries: - title: "Array construction: `[]`" body: | As in JSON, `[]` is used to construct arrays, as in `[1,2,3]`. The elements of the arrays can be any jq expression, including a pipeline. All of the results produced by all of the expressions are collected into one big array. You can use it to construct an array out of a known quantity of values (as in `[.foo, .bar, .baz]`) or to "collect" all the results of a filter into an array (as in `[.items[].name]`) Once you understand the "," operator, you can look at jq's array syntax in a different light: the expression `[1,2,3]` is not using a built-in syntax for comma-separated arrays, but is instead applying the `[]` operator (collect results) to the expression 1,2,3 (which produces three different results). If you have a filter `X` that produces four results, then the expression `[X]` will produce a single result, an array of four elements. examples: - program: "[.user, .projects[]]" input: '{"user":"stedolan", "projects": ["jq", "wikiflow"]}' output: ['["stedolan", "jq", "wikiflow"]'] - program: "[ .[] | . * 2]" input: '[1, 2, 3]' output: ['[2, 4, 6]'] - title: "Object Construction: `{}`" body: | Like JSON, `{}` is for constructing objects (aka dictionaries or hashes), as in: `{"a": 42, "b": 17}`. If the keys are "identifier-like", then the quotes can be left off, as in `{a:42, b:17}`. Variable references as key expressions use the value of the variable as the key. Key expressions other than constant literals, identifiers, or variable references, need to be parenthesized, e.g., `{("a"+"b"):59}`. The value can be any expression (although you may need to wrap it in parentheses if, for example, it contains colons), which gets applied to the {} expression's input (remember, all filters have an input and an output). {foo: .bar} will produce the JSON object `{"foo": 42}` if given the JSON object `{"bar":42, "baz":43}` as its input. You can use this to select particular fields of an object: if the input is an object with "user", "title", "id", and "content" fields and you just want "user" and "title", you can write {user: .user, title: .title} Because that is so common, there's a shortcut syntax for it: `{user, title}`. If one of the expressions produces multiple results, multiple dictionaries will be produced. If the input's {"user":"stedolan","titles":["JQ Primer", "More JQ"]} then the expression {user, title: .titles[]} will produce two outputs: {"user":"stedolan", "title": "JQ Primer"} {"user":"stedolan", "title": "More JQ"} Putting parentheses around the key means it will be evaluated as an expression. With the same input as above, {(.user): .titles} produces {"stedolan": ["JQ Primer", "More JQ"]} Variable references as keys use the value of the variable as the key. Without a value then the variable's name becomes the key and its value becomes the value, "f o o" as $foo | "b a r" as $bar | {$foo, $bar:$foo} produces {"foo":"f o o","b a r":"f o o"} examples: - program: '{user, title: .titles[]}' input: '{"user":"stedolan","titles":["JQ Primer", "More JQ"]}' output: - '{"user":"stedolan", "title": "JQ Primer"}' - '{"user":"stedolan", "title": "More JQ"}' - program: '{(.user): .titles}' input: '{"user":"stedolan","titles":["JQ Primer", "More JQ"]}' output: ['{"stedolan": ["JQ Primer", "More JQ"]}'] - title: "Recursive Descent: `..`" body: | Recursively descends `.`, producing every value. This is the same as the zero-argument `recurse` builtin (see below). This is intended to resemble the XPath `//` operator. Note that `..a` does not work; use `.. | .a` instead. In the example below we use `.. | .a?` to find all the values of object keys "a" in any object found "below" `.`. This is particularly useful in conjunction with `path(EXP)` (also see below) and the `?` operator. examples: - program: '.. | .a?' input: '[[{"a":1}]]' output: ['1'] - title: Builtin operators and functions body: | Some jq operators (for instance, `+`) do different things depending on the type of their arguments (arrays, numbers, etc.). However, jq never does implicit type conversions. If you try to add a string to an object you'll get an error message and no result. Please note that all numbers are converted to IEEE754 double precision floating point representation. Arithmetic and logical operators are working with these converted doubles. Results of all such operations are also limited to the double precision. The only exception to this behaviour of number is a snapshot of original number literal. When a number which originally was provided as a literal is never mutated until the end of the program then it is printed to the output in its original literal form. This also includes cases when the original literal would be truncated when converted to the IEEE754 double precision floating point number. entries: - title: "Addition: `+`" body: | The operator `+` takes two filters, applies them both to the same input, and adds the results together. What "adding" means depends on the types involved: - **Numbers** are added by normal arithmetic. - **Arrays** are added by being concatenated into a larger array. - **Strings** are added by being joined into a larger string. - **Objects** are added by merging, that is, inserting all the key-value pairs from both objects into a single combined object. If both objects contain a value for the same key, the object on the right of the `+` wins. (For recursive merge use the `*` operator.) `null` can be added to any value, and returns the other value unchanged. examples: - program: '.a + 1' input: '{"a": 7}' output: ['8'] - program: '.a + .b' input: '{"a": [1,2], "b": [3,4]}' output: ['[1,2,3,4]'] - program: '.a + null' input: '{"a": 1}' output: ['1'] - program: '.a + 1' input: '{}' output: ['1'] - program: '{a: 1} + {b: 2} + {c: 3} + {a: 42}' input: 'null' output: ['{"a": 42, "b": 2, "c": 3}'] - title: "Subtraction: `-`" body: | As well as normal arithmetic subtraction on numbers, the `-` operator can be used on arrays to remove all occurrences of the second array's elements from the first array. examples: - program: '4 - .a' input: '{"a":3}' output: ['1'] - program: . - ["xml", "yaml"] input: '["xml", "yaml", "json"]' output: ['["json"]'] - title: "Multiplication, division, modulo: `*`, `/`, `%`" body: | These infix operators behave as expected when given two numbers. Division by zero raises an error. `x % y` computes x modulo y. Multiplying a string by a number produces the concatenation of that string that many times. `"x" * 0` produces `""`. Dividing a string by another splits the first using the second as separators. Multiplying two objects will merge them recursively: this works like addition but if both objects contain a value for the same key, and the values are objects, the two are merged with the same strategy. examples: - program: '10 / . * 3' input: '5' output: ['6'] - program: '. / ", "' input: '"a, b,c,d, e"' output: ['["a","b,c,d","e"]'] - program: '{"k": {"a": 1, "b": 2}} * {"k": {"a": 0,"c": 3}}' input: 'null' output: ['{"k": {"a": 0, "b": 2, "c": 3}}'] - program: '.[] | (1 / .)?' input: '[1,0,-1]' output: ['1', '-1'] - title: "`abs`" body: | The builtin function `abs` is defined naively as: `if . < 0 then - . else . end`. For numeric input, this is the absolute value. See the section on the identity filter for the implications of this definition for numeric input. To compute the absolute value of a number as a floating point number, you may wish use `fabs`. examples: - program: 'map(abs)' input: '[-10, -1.1, -1e-1]' output: ['[10,1.1,1e-1]'] - title: "`length`" body: | The builtin function `length` gets the length of various different types of value: - The length of a **string** is the number of Unicode codepoints it contains (which will be the same as its JSON-encoded length in bytes if it's pure ASCII). - The length of a **number** is its absolute value. - The length of an **array** is the number of elements. - The length of an **object** is the number of key-value pairs. - The length of **null** is zero. - It is an error to use `length` on a **boolean**. examples: - program: '.[] | length' input: '[[1,2], "string", {"a":2}, null, -5]' output: ['2', '6', '1', '0', '5'] - title: "`utf8bytelength`" body: | The builtin function `utf8bytelength` outputs the number of bytes used to encode a string in UTF-8. examples: - program: 'utf8bytelength' input: '"\u03bc"' output: ['2'] - title: "`keys`, `keys_unsorted`" body: | The builtin function `keys`, when given an object, returns its keys in an array. The keys are sorted "alphabetically", by unicode codepoint order. This is not an order that makes particular sense in any particular language, but you can count on it being the same for any two objects with the same set of keys, regardless of locale settings. When `keys` is given an array, it returns the valid indices for that array: the integers from 0 to length-1. The `keys_unsorted` function is just like `keys`, but if the input is an object then the keys will not be sorted, instead the keys will roughly be in insertion order. examples: - program: 'keys' input: '{"abc": 1, "abcd": 2, "Foo": 3}' output: ['["Foo", "abc", "abcd"]'] - program: 'keys' input: '[42,3,35]' output: ['[0,1,2]'] - title: "`has(key)`" body: | The builtin function `has` returns whether the input object has the given key, or the input array has an element at the given index. `has($key)` has the same effect as checking whether `$key` is a member of the array returned by `keys`, although `has` will be faster. examples: - program: 'map(has("foo"))' input: '[{"foo": 42}, {}]' output: ['[true, false]'] - program: 'map(has(2))' input: '[[0,1], ["a","b","c"]]' output: ['[false, true]'] - title: "`in`" body: | The builtin function `in` returns whether or not the input key is in the given object, or the input index corresponds to an element in the given array. It is, essentially, an inversed version of `has`. examples: - program: '.[] | in({"foo": 42})' input: '["foo", "bar"]' output: ['true', 'false'] - program: 'map(in([0,1]))' input: '[2, 0]' output: ['[false, true]'] - title: "`map(f)`, `map_values(f)`" body: | For any filter `f`, `map(f)` and `map_values(f)` apply `f` to each of the values in the input array or object, that is, to the values of `.[]`. In the absence of errors, `map(f)` always outputs an array whereas `map_values(f)` outputs an array if given an array, or an object if given an object. When the input to `map_values(f)` is an object, the output object has the same keys as the input object except for those keys whose values when piped to `f` produce no values at all. The key difference between `map(f)` and `map_values(f)` is that the former simply forms an array from all the values of `($x|f)` for each value, `$x`, in the input array or object, but `map_values(f)` only uses `first($x|f)`. Specifically, for object inputs, `map_values(f)` constructs the output object by examining in turn the value of `first(.[$k]|f)` for each key, `$k`, of the input. If this expression produces no values, then the corresponding key will be dropped; otherwise, the output object will have that value at the key, `$k`. Here are some examples to clarify the behavior of `map` and `map_values` when applied to arrays. These examples assume the input is `[1]` in all cases: map(.+1) #=> [2] map(., .) #=> [1,1] map(empty) #=> [] map_values(.+1) #=> [2] map_values(., .) #=> [1] map_values(empty) #=> [] `map(f)` is equivalent to `[.[] | f]` and `map_values(f)` is equivalent to `.[] |= f`. In fact, these are their implementations. examples: - program: 'map(.+1)' input: '[1,2,3]' output: ['[2,3,4]'] - program: 'map_values(.+1)' input: '{"a": 1, "b": 2, "c": 3}' output: ['{"a": 2, "b": 3, "c": 4}'] - program: 'map(., .)' input: '[1,2]' output: ['[1,1,2,2]'] - program: 'map_values(. // empty)' input: '{"a": null, "b": true, "c": false}' output: ['{"b":true}'] - title: "`pick(pathexps)`" body: | Emit the projection of the input object or array defined by the specified sequence of path expressions, such that if `p` is any one of these specifications, then `(. | p)` will evaluate to the same value as `(. | pick(pathexps) | p)`. For arrays, negative indices and `.[m:n]` specifications should not be used. examples: - program: 'pick(.a, .b.c, .x)' input: '{"a": 1, "b": {"c": 2, "d": 3}, "e": 4}' output: ['{"a":1,"b":{"c":2},"x":null}'] - program: 'pick(.[2], .[0], .[0])' input: '[1,2,3,4]' output: ['[1,null,3]'] - title: "`path(path_expression)`" body: | Outputs array representations of the given path expression in `.`. The outputs are arrays of strings (object keys) and/or numbers (array indices). Path expressions are jq expressions like `.a`, but also `.[]`. There are two types of path expressions: ones that can match exactly, and ones that cannot. For example, `.a.b.c` is an exact match path expression, while `.a[].b` is not. `path(exact_path_expression)` will produce the array representation of the path expression even if it does not exist in `.`, if `.` is `null` or an array or an object. `path(pattern)` will produce array representations of the paths matching `pattern` if the paths exist in `.`. Note that the path expressions are not different from normal expressions. The expression `path(..|select(type=="boolean"))` outputs all the paths to boolean values in `.`, and only those paths. examples: - program: 'path(.a[0].b)' input: 'null' output: ['["a",0,"b"]'] - program: '[path(..)]' input: '{"a":[{"b":1}]}' output: ['[[],["a"],["a",0],["a",0,"b"]]'] - title: "`del(path_expression)`" body: | The builtin function `del` removes a key and its corresponding value from an object. examples: - program: 'del(.foo)' input: '{"foo": 42, "bar": 9001, "baz": 42}' output: ['{"bar": 9001, "baz": 42}'] - program: 'del(.[1, 2])' input: '["foo", "bar", "baz"]' output: ['["foo"]'] - title: "`getpath(PATHS)`" body: | The builtin function `getpath` outputs the values in `.` found at each path in `PATHS`. examples: - program: 'getpath(["a","b"])' input: 'null' output: ['null'] - program: '[getpath(["a","b"], ["a","c"])]' input: '{"a":{"b":0, "c":1}}' output: ['[0, 1]'] - title: "`setpath(PATHS; VALUE)`" body: | The builtin function `setpath` sets the `PATHS` in `.` to `VALUE`. examples: - program: 'setpath(["a","b"]; 1)' input: 'null' output: ['{"a": {"b": 1}}'] - program: 'setpath(["a","b"]; 1)' input: '{"a":{"b":0}}' output: ['{"a": {"b": 1}}'] - program: 'setpath([0,"a"]; 1)' input: 'null' output: ['[{"a":1}]'] - title: "`delpaths(PATHS)`" body: | The builtin function `delpaths` deletes the `PATHS` in `.`. `PATHS` must be an array of paths, where each path is an array of strings and numbers. examples: - program: 'delpaths([["a","b"]])' input: '{"a":{"b":1},"x":{"y":2}}' output: ['{"a":{},"x":{"y":2}}'] - title: "`to_entries`, `from_entries`, `with_entries(f)`" body: | These functions convert between an object and an array of key-value pairs. If `to_entries` is passed an object, then for each `k: v` entry in the input, the output array includes `{"key": k, "value": v}`. `from_entries` does the opposite conversion, and `with_entries(f)` is a shorthand for `to_entries | map(f) | from_entries`, useful for doing some operation to all keys and values of an object. `from_entries` accepts `"key"`, `"Key"`, `"name"`, `"Name"`, `"value"`, and `"Value"` as keys. examples: - program: 'to_entries' input: '{"a": 1, "b": 2}' output: ['[{"key":"a", "value":1}, {"key":"b", "value":2}]'] - program: 'from_entries' input: '[{"key":"a", "value":1}, {"key":"b", "value":2}]' output: ['{"a": 1, "b": 2}'] - program: 'with_entries(.key |= "KEY_" + .)' input: '{"a": 1, "b": 2}' output: ['{"KEY_a": 1, "KEY_b": 2}'] - title: "`select(boolean_expression)`" body: | The function `select(f)` produces its input unchanged if `f` returns true for that input, and produces no output otherwise. It's useful for filtering lists: `[1,2,3] | map(select(. >= 2))` will give you `[2,3]`. examples: - program: 'map(select(. >= 2))' input: '[1,5,3,0,7]' output: ['[5,3,7]'] - program: '.[] | select(.id == "second")' input: '[{"id": "first", "val": 1}, {"id": "second", "val": 2}]' output: ['{"id": "second", "val": 2}'] - title: "`arrays`, `objects`, `iterables`, `booleans`, `numbers`, `normals`, `finites`, `strings`, `nulls`, `values`, `scalars`" body: | These built-ins select only inputs that are arrays, objects, iterables (arrays or objects), booleans, numbers, normal numbers, finite numbers, strings, null, non-null values, and non-iterables, respectively. examples: - program: '.[]|numbers' input: '[[],{},1,"foo",null,true,false]' output: ['1'] - title: "`empty`" body: | `empty` returns no results. None at all. Not even `null`. It's useful on occasion. You'll know if you need it :) examples: - program: '1, empty, 2' input: 'null' output: ['1', '2'] - program: '[1,2,empty,3]' input: 'null' output: ['[1,2,3]'] - title: "`error`, `error(message)`" body: | Produces an error with the input value, or with the message given as the argument. Errors can be caught with try/catch; see below. examples: - program: 'try error catch .' input: '"error message"' output: ['"error message"'] - program: 'try error("invalid value: \(.)") catch .' input: '42' output: ['"invalid value: 42"'] - title: "`halt`" body: | Stops the jq program with no further outputs. jq will exit with exit status `0`. - title: "`halt_error`, `halt_error(exit_code)`" body: | Stops the jq program with no further outputs. The input will be printed on `stderr` as raw output (i.e., strings will not have double quotes) with no decoration, not even a newline. The given `exit_code` (defaulting to `5`) will be jq's exit status. For example, `"Error: something went wrong\n"|halt_error(1)`. - title: "`$__loc__`" body: | Produces an object with a "file" key and a "line" key, with the filename and line number where `$__loc__` occurs, as values. examples: - program: 'try error("\($__loc__)") catch .' input: 'null' output: ['"{\"file\":\"\",\"line\":1}"'] - title: "`paths`, `paths(node_filter)`" body: | `paths` outputs the paths to all the elements in its input (except it does not output the empty list, representing . itself). `paths(f)` outputs the paths to any values for which `f` is `true`. That is, `paths(type == "number")` outputs the paths to all numeric values. examples: - program: '[paths]' input: '[1,[[],{"a":2}]]' output: ['[[0],[1],[1,0],[1,1],[1,1,"a"]]'] - program: '[paths(type == "number")]' input: '[1,[[],{"a":2}]]' output: ['[[0],[1,1,"a"]]'] - title: "`add`, `add(generator)`" body: | The filter `add` takes as input an array, and produces as output the elements of the array added together. This might mean summed, concatenated or merged depending on the types of the elements of the input array - the rules are the same as those for the `+` operator (described above). If the input is an empty array, `add` returns `null`. `add(generator)` operates on the given generator rather than the input. examples: - program: add input: '["a","b","c"]' output: ['"abc"'] - program: add input: '[1, 2, 3]' output: ['6'] - program: add input: '[]' output: ["null"] - program: add(.[].a) input: '[{"a":3}, {"a":5}, {"b":6}]' output: ['8'] - title: "`any`, `any(condition)`, `any(generator; condition)`" body: | The filter `any` takes as input an array of boolean values, and produces `true` as output if any of the elements of the array are `true`. If the input is an empty array, `any` returns `false`. The `any(condition)` form applies the given condition to the elements of the input array. The `any(generator; condition)` form applies the given condition to all the outputs of the given generator. examples: - program: any input: '[true, false]' output: ["true"] - program: any input: '[false, false]' output: ["false"] - program: any input: '[]' output: ["false"] - title: "`all`, `all(condition)`, `all(generator; condition)`" body: | The filter `all` takes as input an array of boolean values, and produces `true` as output if all of the elements of the array are `true`. The `all(condition)` form applies the given condition to the elements of the input array. The `all(generator; condition)` form applies the given condition to all the outputs of the given generator. If the input is an empty array, `all` returns `true`. examples: - program: all input: '[true, false]' output: ["false"] - program: all input: '[true, true]' output: ["true"] - program: all input: '[]' output: ["true"] - title: "`flatten`, `flatten(depth)`" body: | The filter `flatten` takes as input an array of nested arrays, and produces a flat array in which all arrays inside the original array have been recursively replaced by their values. You can pass an argument to it to specify how many levels of nesting to flatten. `flatten(2)` is like `flatten`, but going only up to two levels deep. examples: - program: flatten input: '[1, [2], [[3]]]' output: ["[1, 2, 3]"] - program: flatten(1) input: '[1, [2], [[3]]]' output: ["[1, 2, [3]]"] - program: flatten input: '[[]]' output: ["[]"] - program: flatten input: '[{"foo": "bar"}, [{"foo": "baz"}]]' output: ['[{"foo": "bar"}, {"foo": "baz"}]'] - title: "`range(upto)`, `range(from; upto)`, `range(from; upto; by)`" body: | The `range` function produces a range of numbers. `range(4; 10)` produces 6 numbers, from 4 (inclusive) to 10 (exclusive). The numbers are produced as separate outputs. Use `[range(4; 10)]` to get a range as an array. The one argument form generates numbers from 0 to the given number, with an increment of 1. The two argument form generates numbers from `from` to `upto` with an increment of 1. The three argument form generates numbers `from` to `upto` with an increment of `by`. examples: - program: 'range(2; 4)' input: 'null' output: ['2', '3'] - program: '[range(2; 4)]' input: 'null' output: ['[2,3]'] - program: '[range(4)]' input: 'null' output: ['[0,1,2,3]'] - program: '[range(0; 10; 3)]' input: 'null' output: ['[0,3,6,9]'] - program: '[range(0; 10; -1)]' input: 'null' output: ['[]'] - program: '[range(0; -5; -1)]' input: 'null' output: ['[0,-1,-2,-3,-4]'] - title: "`floor`" body: | The `floor` function returns the floor of its numeric input. examples: - program: 'floor' input: '3.14159' output: ['3'] - title: "`sqrt`" body: | The `sqrt` function returns the square root of its numeric input. examples: - program: 'sqrt' input: '9' output: ['3'] - title: "`tonumber`" body: | The `tonumber` function parses its input as a number. It will convert correctly-formatted strings to their numeric equivalent, leave numbers alone, and give an error on all other input. examples: - program: '.[] | tonumber' input: '[1, "1"]' output: ['1', '1'] - title: "`toboolean`" body: | The `toboolean` function parses its input as a boolean. It will convert correctly-formatted strings to their boolean equivalent, leave booleans alone, and give an error on all other input. examples: - program: '.[] | toboolean' input: '["true", "false", true, false]' output: ['true', 'false', 'true', 'false'] - title: "`tostring`" body: | The `tostring` function prints its input as a string. Strings are left unchanged, and all other values are JSON-encoded. examples: - program: '.[] | tostring' input: '[1, "1", [1]]' output: ['"1"', '"1"', '"[1]"'] - title: "`type`" body: | The `type` function returns the type of its argument as a string, which is one of null, boolean, number, string, array or object. examples: - program: 'map(type)' input: '[0, false, [], {}, null, "hello"]' output: ['["number", "boolean", "array", "object", "null", "string"]'] - title: "`infinite`, `nan`, `isinfinite`, `isnan`, `isfinite`, `isnormal`" body: | Some arithmetic operations can yield infinities and "not a number" (NaN) values. The `isinfinite` builtin returns `true` if its input is infinite. The `isnan` builtin returns `true` if its input is a NaN. The `infinite` builtin returns a positive infinite value. The `nan` builtin returns a NaN. The `isnormal` builtin returns true if its input is a normal number. Note that division by zero raises an error. Currently most arithmetic operations operating on infinities, NaNs, and sub-normals do not raise errors. examples: - program: '.[] | (infinite * .) < 0' input: '[-1, 1]' output: ['true', 'false'] - program: 'infinite, nan | type' input: 'null' output: ['"number"', '"number"'] - title: "`sort`, `sort_by(path_expression)`" body: | The `sort` functions sorts its input, which must be an array. Values are sorted in the following order: * `null` * `false` * `true` * numbers * strings, in alphabetical order (by unicode codepoint value) * arrays, in lexical order * objects The ordering for objects is a little complex: first they're compared by comparing their sets of keys (as arrays in sorted order), and if their keys are equal then the values are compared key by key. `sort_by` may be used to sort by a particular field of an object, or by applying any jq filter. `sort_by(f)` compares two elements by comparing the result of `f` on each element. When `f` produces multiple values, it firstly compares the first values, and the second values if the first values are equal, and so on. examples: - program: 'sort' input: '[8,3,null,6]' output: ['[null,3,6,8]'] - program: 'sort_by(.foo)' input: '[{"foo":4, "bar":10}, {"foo":3, "bar":10}, {"foo":2, "bar":1}]' output: ['[{"foo":2, "bar":1}, {"foo":3, "bar":10}, {"foo":4, "bar":10}]'] - program: 'sort_by(.foo, .bar)' input: '[{"foo":4, "bar":10}, {"foo":3, "bar":20}, {"foo":2, "bar":1}, {"foo":3, "bar":10}]' output: ['[{"foo":2, "bar":1}, {"foo":3, "bar":10}, {"foo":3, "bar":20}, {"foo":4, "bar":10}]'] - title: "`group_by(path_expression)`" body: | `group_by(.foo)` takes as input an array, groups the elements having the same `.foo` field into separate arrays, and produces all of these arrays as elements of a larger array, sorted by the value of the `.foo` field. Any jq expression, not just a field access, may be used in place of `.foo`. The sorting order is the same as described in the `sort` function above. examples: - program: 'group_by(.foo)' input: '[{"foo":1, "bar":10}, {"foo":3, "bar":100}, {"foo":1, "bar":1}]' output: ['[[{"foo":1, "bar":10}, {"foo":1, "bar":1}], [{"foo":3, "bar":100}]]'] - title: "`min`, `max`, `min_by(path_exp)`, `max_by(path_exp)`" body: | Find the minimum or maximum element of the input array. The `min_by(path_exp)` and `max_by(path_exp)` functions allow you to specify a particular field or property to examine, e.g. `min_by(.foo)` finds the object with the smallest `foo` field. examples: - program: 'min' input: '[5,4,2,7]' output: ['2'] - program: 'max_by(.foo)' input: '[{"foo":1, "bar":14}, {"foo":2, "bar":3}]' output: ['{"foo":2, "bar":3}'] - title: "`unique`, `unique_by(path_exp)`" body: | The `unique` function takes as input an array and produces an array of the same elements, in sorted order, with duplicates removed. The `unique_by(path_exp)` function will keep only one element for each value obtained by applying the argument. Think of it as making an array by taking one element out of every group produced by `group`. examples: - program: 'unique' input: '[1,2,5,3,5,3,1,3]' output: ['[1,2,3,5]'] - program: 'unique_by(.foo)' input: '[{"foo": 1, "bar": 2}, {"foo": 1, "bar": 3}, {"foo": 4, "bar": 5}]' output: ['[{"foo": 1, "bar": 2}, {"foo": 4, "bar": 5}]'] - program: 'unique_by(length)' input: '["chunky", "bacon", "kitten", "cicada", "asparagus"]' output: ['["bacon", "chunky", "asparagus"]'] - title: "`reverse`" body: | This function reverses an array. examples: - program: 'reverse' input: '[1,2,3,4]' output: ['[4,3,2,1]'] - title: "`contains(element)`" body: | The filter `contains(b)` will produce true if b is completely contained within the input. A string B is contained in a string A if B is a substring of A. An array B is contained in an array A if all elements in B are contained in any element in A. An object B is contained in object A if all of the values in B are contained in the value in A with the same key. All other types are assumed to be contained in each other if they are equal. examples: - program: 'contains("bar")' input: '"foobar"' output: ['true'] - program: 'contains(["baz", "bar"])' input: '["foobar", "foobaz", "blarp"]' output: ['true'] - program: 'contains(["bazzzzz", "bar"])' input: '["foobar", "foobaz", "blarp"]' output: ['false'] - program: 'contains({foo: 12, bar: [{barp: 12}]})' input: '{"foo": 12, "bar":[1,2,{"barp":12, "blip":13}]}' output: ['true'] - program: 'contains({foo: 12, bar: [{barp: 15}]})' input: '{"foo": 12, "bar":[1,2,{"barp":12, "blip":13}]}' output: ['false'] - title: "`indices(s)`" body: | Outputs an array containing the indices in `.` where `s` occurs. The input may be an array, in which case if `s` is an array then the indices output will be those where all elements in `.` match those of `s`. examples: - program: 'indices(", ")' input: '"a,b, cd, efg, hijk"' output: ['[3,7,12]'] - program: 'indices(1)' input: '[0,1,2,1,3,1,4]' output: ['[1,3,5]'] - program: 'indices([1,2])' input: '[0,1,2,3,1,4,2,5,1,2,6,7]' output: ['[1,8]'] - title: "`index(s)`, `rindex(s)`" body: | Outputs the index of the first (`index`) or last (`rindex`) occurrence of `s` in the input. examples: - program: 'index(", ")' input: '"a,b, cd, efg, hijk"' output: ['3'] - program: 'index(1)' input: '[0,1,2,1,3,1,4]' output: ['1'] - program: 'index([1,2])' input: '[0,1,2,3,1,4,2,5,1,2,6,7]' output: ['1'] - program: 'rindex(", ")' input: '"a,b, cd, efg, hijk"' output: ['12'] - program: 'rindex(1)' input: '[0,1,2,1,3,1,4]' output: ['5'] - program: 'rindex([1,2])' input: '[0,1,2,3,1,4,2,5,1,2,6,7]' output: ['8'] - title: "`inside`" body: | The filter `inside(b)` will produce true if the input is completely contained within b. It is, essentially, an inversed version of `contains`. examples: - program: 'inside("foobar")' input: '"bar"' output: ['true'] - program: 'inside(["foobar", "foobaz", "blarp"])' input: '["baz", "bar"]' output: ['true'] - program: 'inside(["foobar", "foobaz", "blarp"])' input: '["bazzzzz", "bar"]' output: ['false'] - program: 'inside({"foo": 12, "bar":[1,2,{"barp":12, "blip":13}]})' input: '{"foo": 12, "bar": [{"barp": 12}]}' output: ['true'] - program: 'inside({"foo": 12, "bar":[1,2,{"barp":12, "blip":13}]})' input: '{"foo": 12, "bar": [{"barp": 15}]}' output: ['false'] - title: "`startswith(str)`" body: | Outputs `true` if . starts with the given string argument. examples: - program: '[.[]|startswith("foo")]' input: '["fo", "foo", "barfoo", "foobar", "barfoob"]' output: ['[false, true, false, true, false]'] - title: "`endswith(str)`" body: | Outputs `true` if . ends with the given string argument. examples: - program: '[.[]|endswith("foo")]' input: '["foobar", "barfoo"]' output: ['[false, true]'] - title: "`combinations`, `combinations(n)`" body: | Outputs all combinations of the elements of the arrays in the input array. If given an argument `n`, it outputs all combinations of `n` repetitions of the input array. examples: - program: 'combinations' input: '[[1,2], [3, 4]]' output: ['[1, 3]', '[1, 4]', '[2, 3]', '[2, 4]'] - program: 'combinations(2)' input: '[0, 1]' output: ['[0, 0]', '[0, 1]', '[1, 0]', '[1, 1]'] - title: "`ltrimstr(str)`" body: | Outputs its input with the given prefix string removed, if it starts with it. examples: - program: '[.[]|ltrimstr("foo")]' input: '["fo", "foo", "barfoo", "foobar", "afoo"]' output: ['["fo","","barfoo","bar","afoo"]'] - title: "`rtrimstr(str)`" body: | Outputs its input with the given suffix string removed, if it ends with it. examples: - program: '[.[]|rtrimstr("foo")]' input: '["fo", "foo", "barfoo", "foobar", "foob"]' output: ['["fo","","bar","foobar","foob"]'] - title: "`trimstr(str)`" body: | Outputs its input with the given string removed at both ends, if it starts or ends with it. examples: - program: '[.[]|trimstr("foo")]' input: '["fo", "foo", "barfoo", "foobarfoo", "foob"]' output: ['["fo","","bar","bar","b"]'] - title: "`trim`, `ltrim`, `rtrim`" body: | `trim` trims both leading and trailing whitespace. `ltrim` trims only leading (left side) whitespace. `rtrim` trims only trailing (right side) whitespace. Whitespace characters are the usual `" "`, `"\n"` `"\t"`, `"\r"` and also all characters in the Unicode character database with the whitespace property. Note that what considers whitespace might change in the future. examples: - program: 'trim, ltrim, rtrim' input: '" abc "' output: ['"abc"', '"abc "', '" abc"'] - title: "`explode`" body: | Converts an input string into an array of the string's codepoint numbers. examples: - program: 'explode' input: '"foobar"' output: ['[102,111,111,98,97,114]'] - title: "`implode`" body: | The inverse of explode. examples: - program: 'implode' input: '[65, 66, 67]' output: ['"ABC"'] - title: "`split(str)`" body: | Splits an input string on the separator argument. `split` can also split on regex matches when called with two arguments (see the regular expressions section below). examples: - program: 'split(", ")' input: '"a, b,c,d, e, "' output: ['["a","b,c,d","e",""]'] - title: "`join(str)`" body: | Joins the array of elements given as input, using the argument as separator. It is the inverse of `split`: that is, running `split("foo") | join("foo")` over any input string returns said input string. Numbers and booleans in the input are converted to strings. Null values are treated as empty strings. Arrays and objects in the input are not supported. examples: - program: 'join(", ")' input: '["a","b,c,d","e"]' output: ['"a, b,c,d, e"'] - program: 'join(" ")' input: '["a",1,2.3,true,null,false]' output: ['"a 1 2.3 true false"'] - title: "`ascii_downcase`, `ascii_upcase`" body: | Emit a copy of the input string with its alphabetic characters (a-z and A-Z) converted to the specified case. examples: - program: 'ascii_upcase' input: '"useful but not for é"' output: ['"USEFUL BUT NOT FOR é"'] - title: "`while(cond; update)`" body: | The `while(cond; update)` function allows you to repeatedly apply an update to `.` until `cond` is false. Note that `while(cond; update)` is internally defined as a recursive jq function. Recursive calls within `while` will not consume additional memory if `update` produces at most one output for each input. See advanced topics below. examples: - program: '[while(.<100; .*2)]' input: '1' output: ['[1,2,4,8,16,32,64]'] - title: "`repeat(exp)`" body: | The `repeat(exp)` function allows you to repeatedly apply expression `exp` to `.` until an error is raised. Note that `repeat(exp)` is internally defined as a recursive jq function. Recursive calls within `repeat` will not consume additional memory if `exp` produces at most one output for each input. See advanced topics below. examples: - program: '[repeat(.*2, error)?]' input: '1' output: ['[2]'] - title: "`until(cond; next)`" body: | The `until(cond; next)` function allows you to repeatedly apply the expression `next`, initially to `.` then to its own output, until `cond` is true. For example, this can be used to implement a factorial function (see below). Note that `until(cond; next)` is internally defined as a recursive jq function. Recursive calls within `until()` will not consume additional memory if `next` produces at most one output for each input. See advanced topics below. examples: - program: '[.,1]|until(.[0] < 1; [.[0] - 1, .[1] * .[0]])|.[1]' input: '4' output: ['24'] - title: "`recurse(f)`, `recurse`, `recurse(f; condition)`" body: | The `recurse(f)` function allows you to search through a recursive structure, and extract interesting data from all levels. Suppose your input represents a filesystem: {"name": "/", "children": [ {"name": "/bin", "children": [ {"name": "/bin/ls", "children": []}, {"name": "/bin/sh", "children": []}]}, {"name": "/home", "children": [ {"name": "/home/stephen", "children": [ {"name": "/home/stephen/jq", "children": []}]}]}]} Now suppose you want to extract all of the filenames present. You need to retrieve `.name`, `.children[].name`, `.children[].children[].name`, and so on. You can do this with: recurse(.children[]) | .name When called without an argument, `recurse` is equivalent to `recurse(.[]?)`. `recurse(f)` is identical to `recurse(f; true)` and can be used without concerns about recursion depth. `recurse(f; condition)` is a generator which begins by emitting . and then emits in turn .|f, .|f|f, .|f|f|f, ... so long as the computed value satisfies the condition. For example, to generate all the integers, at least in principle, one could write `recurse(.+1; true)`. The recursive calls in `recurse` will not consume additional memory whenever `f` produces at most a single output for each input. examples: - program: 'recurse(.foo[])' input: '{"foo":[{"foo": []}, {"foo":[{"foo":[]}]}]}' output: - '{"foo":[{"foo":[]},{"foo":[{"foo":[]}]}]}' - '{"foo":[]}' - '{"foo":[{"foo":[]}]}' - '{"foo":[]}' - program: 'recurse' input: '{"a":0,"b":[1]}' output: - '{"a":0,"b":[1]}' - '0' - '[1]' - '1' - program: 'recurse(. * .; . < 20)' input: '2' output: ['2', '4', '16'] - title: "`walk(f)`" body: | The `walk(f)` function applies f recursively to every component of the input entity. When an array is encountered, f is first applied to its elements and then to the array itself; when an object is encountered, f is first applied to all the values and then to the object. In practice, f will usually test the type of its input, as illustrated in the following examples. The first example highlights the usefulness of processing the elements of an array of arrays before processing the array itself. The second example shows how all the keys of all the objects within the input can be considered for alteration. examples: - program: 'walk(if type == "array" then sort else . end)' input: '[[4, 1, 7], [8, 5, 2], [3, 6, 9]]' output: - '[[1,4,7],[2,5,8],[3,6,9]]' - program: 'walk( if type == "object" then with_entries( .key |= sub( "^_+"; "") ) else . end )' input: '[ { "_a": { "__b": 2 } } ]' output: - '[{"a":{"b":2}}]' - title: "`have_literal_numbers`" body: | This builtin returns true if jq's build configuration includes support for preservation of input number literals. - title: "`have_decnum`" body: | This builtin returns true if jq was built with "decnum", which is the current literal number preserving numeric backend implementation for jq. - title: "`$JQ_BUILD_CONFIGURATION`" body: | This builtin binding shows the jq executable's build configuration. Its value has no particular format, but it can be expected to be at least the `./configure` command-line arguments, and may be enriched in the future to include the version strings for the build tooling used. Note that this can be overridden in the command-line with `--arg` and related options. - title: "`$ENV`, `env`" body: | `$ENV` is an object representing the environment variables as set when the jq program started. `env` outputs an object representing jq's current environment. At the moment there is no builtin for setting environment variables. examples: - program: '$ENV.PAGER' input: 'null' output: ['"less"'] - program: 'env.PAGER' input: 'null' output: ['"less"'] - title: "`transpose`" body: | Transpose a possibly jagged matrix (an array of arrays). Rows are padded with nulls so the result is always rectangular. examples: - program: 'transpose' input: '[[1], [2,3]]' output: ['[[1,2],[null,3]]'] - title: "`bsearch(x)`" body: | `bsearch(x)` conducts a binary search for x in the input array. If the input is sorted and contains x, then `bsearch(x)` will return its index in the array; otherwise, if the array is sorted, it will return (-1 - ix) where ix is an insertion point such that the array would still be sorted after the insertion of x at ix. If the array is not sorted, `bsearch(x)` will return an integer that is probably of no interest. examples: - program: 'bsearch(0)' input: '[0,1]' output: ['0'] - program: 'bsearch(0)' input: '[1,2,3]' output: ['-1'] - program: 'bsearch(4) as $ix | if $ix < 0 then .[-(1+$ix)] = 4 else . end' input: '[1,2,3]' output: ['[1,2,3,4]'] - title: "String interpolation: `\\(exp)`" body: | Inside a string, you can put an expression inside parens after a backslash. Whatever the expression returns will be interpolated into the string. examples: - program: '"The input was \(.), which is one less than \(.+1)"' input: '42' output: ['"The input was 42, which is one less than 43"'] - title: "Convert to/from JSON" body: | The `tojson` and `fromjson` builtins dump values as JSON texts or parse JSON texts into values, respectively. The `tojson` builtin differs from `tostring` in that `tostring` returns strings unmodified, while `tojson` encodes strings as JSON strings. examples: - program: '[.[]|tostring]' input: '[1, "foo", ["foo"]]' output: ['["1","foo","[\"foo\"]"]'] - program: '[.[]|tojson]' input: '[1, "foo", ["foo"]]' output: ['["1","\"foo\"","[\"foo\"]"]'] - program: '[.[]|tojson|fromjson]' input: '[1, "foo", ["foo"]]' output: ['[1,"foo",["foo"]]'] - title: "Format strings and escaping" body: | The `@foo` syntax is used to format and escape strings, which is useful for building URLs, documents in a language like HTML or XML, and so forth. `@foo` can be used as a filter on its own, the possible escapings are: * `@text`: Calls `tostring`, see that function for details. * `@json`: Serializes the input as JSON. * `@html`: Applies HTML/XML escaping, by mapping the characters `<>&'"` to their entity equivalents `<`, `>`, `&`, `'`, `"`. * `@uri`: Applies percent-encoding, by mapping all reserved URI characters to a `%XX` sequence. * `@urid`: The inverse of `@uri`, applies percent-decoding, by mapping all `%XX` sequences to their corresponding URI characters. * `@csv`: The input must be an array, and it is rendered as CSV with double quotes for strings, and quotes escaped by repetition. * `@tsv`: The input must be an array, and it is rendered as TSV (tab-separated values). Each input array will be printed as a single line. Fields are separated by a single tab (ascii `0x09`). Input characters line-feed (ascii `0x0a`), carriage-return (ascii `0x0d`), tab (ascii `0x09`) and backslash (ascii `0x5c`) will be output as escape sequences `\n`, `\r`, `\t`, `\\` respectively. * `@sh`: The input is escaped suitable for use in a command-line for a POSIX shell. If the input is an array, the output will be a series of space-separated strings. * `@base64`: The input is converted to base64 as specified by RFC 4648. * `@base64d`: The inverse of `@base64`, input is decoded as specified by RFC 4648. Note\: If the decoded string is not UTF-8, the results are undefined. This syntax can be combined with string interpolation in a useful way. You can follow a `@foo` token with a string literal. The contents of the string literal will *not* be escaped. However, all interpolations made inside that string literal will be escaped. For instance, @uri "https://www.google.com/search?q=\(.search)" will produce the following output for the input `{"search":"what is jq?"}`: "https://www.google.com/search?q=what%20is%20jq%3F" Note that the slashes, question mark, etc. in the URL are not escaped, as they were part of the string literal. examples: - program: '@html' input: '"This works if x < y"' output: ['"This works if x < y"'] - program: '@sh "echo \(.)"' input: "\"O'Hara's Ale\"" output: ["\"echo 'O'\\\\''Hara'\\\\''s Ale'\""] - program: '@base64' input: '"This is a message"' output: ['"VGhpcyBpcyBhIG1lc3NhZ2U="'] - program: '@base64d' input: '"VGhpcyBpcyBhIG1lc3NhZ2U="' output: ['"This is a message"'] - title: "Dates" body: | jq provides some basic date handling functionality, with some high-level and low-level builtins. In all cases these builtins deal exclusively with time in UTC. The `fromdateiso8601` builtin parses datetimes in the ISO 8601 format to a number of seconds since the Unix epoch (1970-01-01T00:00:00Z). The `todateiso8601` builtin does the inverse. The `fromdate` builtin parses datetime strings. Currently `fromdate` only supports ISO 8601 datetime strings, but in the future it will attempt to parse datetime strings in more formats. The `todate` builtin is an alias for `todateiso8601`. The `now` builtin outputs the current time, in seconds since the Unix epoch. Low-level jq interfaces to the C-library time functions are also provided: `strptime`, `strftime`, `strflocaltime`, `mktime`, `gmtime`, and `localtime`. Refer to your host operating system's documentation for the format strings used by `strptime` and `strftime`. Note: these are not necessarily stable interfaces in jq, particularly as to their localization functionality. The `gmtime` builtin consumes a number of seconds since the Unix epoch and outputs a "broken down time" representation of Greenwich Mean Time as an array of numbers representing (in this order): the year, the month (zero-based), the day of the month (one-based), the hour of the day, the minute of the hour, the second of the minute, the day of the week, and the day of the year -- all one-based unless otherwise stated. The day of the week number may be wrong on some systems for dates before March 1st 1900, or after December 31 2099. The `localtime` builtin works like the `gmtime` builtin, but using the local timezone setting. The `mktime` builtin consumes "broken down time" representations of time output by `gmtime` and `strptime`. The `strptime(fmt)` builtin parses input strings matching the `fmt` argument. The output is in the "broken down time" representation consumed by `mktime` and output by `gmtime`. The `strftime(fmt)` builtin formats a time (GMT) with the given format. The `strflocaltime` does the same, but using the local timezone setting. The format strings for `strptime` and `strftime` are described in typical C library documentation. The format string for ISO 8601 datetime is `"%Y-%m-%dT%H:%M:%SZ"`. jq may not support some or all of this date functionality on some systems. In particular, the `%u` and `%j` specifiers for `strptime(fmt)` are not supported on macOS. examples: - program: 'fromdate' input: '"2015-03-05T23:51:47Z"' output: ['1425599507'] - program: 'strptime("%Y-%m-%dT%H:%M:%SZ")' input: '"2015-03-05T23:51:47Z"' output: ['[2015,2,5,23,51,47,4,63]'] - program: 'strptime("%Y-%m-%dT%H:%M:%SZ")|mktime' input: '"2015-03-05T23:51:47Z"' output: ['1425599507'] - title: "SQL-Style Operators" body: | jq provides a few SQL-style operators. * `INDEX(stream; index_expression)`: This builtin produces an object whose keys are computed by the given index expression applied to each value from the given stream. * `JOIN($idx; stream; idx_expr; join_expr)`: This builtin joins the values from the given stream to the given index. The index's keys are computed by applying the given index expression to each value from the given stream. An array of the value in the stream and the corresponding value from the index is fed to the given join expression to produce each result. * `JOIN($idx; stream; idx_expr)`: Same as `JOIN($idx; stream; idx_expr; .)`. * `JOIN($idx; idx_expr)`: This builtin joins the input `.` to the given index, applying the given index expression to `.` to compute the index key. The join operation is as described above. * `IN(s)`: This builtin outputs `true` if `.` appears in the given stream, otherwise it outputs `false`. * `IN(source; s)`: This builtin outputs `true` if any value in the source stream appears in the second stream, otherwise it outputs `false`. - title: "`builtins`" body: | Returns a list of all builtin functions in the format `name/arity`. Since functions with the same name but different arities are considered separate functions, `all/0`, `all/1`, and `all/2` would all be present in the list. - title: Conditionals and Comparisons entries: - title: "`==`, `!=`" body: | The expression 'a == b' will produce 'true' if the results of evaluating a and b are equal (that is, if they represent equivalent JSON values) and 'false' otherwise. In particular, strings are never considered equal to numbers. In checking for the equality of JSON objects, the ordering of keys is irrelevant. If you're coming from JavaScript, please note that jq's `==` is like JavaScript's `===`, the "strict equality" operator. != is "not equal", and 'a != b' returns the opposite value of 'a == b' examples: - program: '. == false' input: 'null' output: ['false'] - program: '. == {"b": {"d": (4 + 1e-20), "c": 3}, "a":1}' input: '{"a":1, "b": {"c": 3, "d": 4}}' output: ['true'] - program: '.[] == 1' input: '[1, 1.0, "1", "banana"]' output: ['true', 'true', 'false', 'false'] - title: if-then-else-end body: | `if A then B else C end` will act the same as `B` if `A` produces a value other than false or null, but act the same as `C` otherwise. `if A then B end` is the same as `if A then B else . end`. That is, the `else` branch is optional, and if absent is the same as `.`. This also applies to `elif` with absent ending `else` branch. Checking for false or null is a simpler notion of "truthiness" than is found in JavaScript or Python, but it means that you'll sometimes have to be more explicit about the condition you want. You can't test whether, e.g. a string is empty using `if .name then A else B end`; you'll need something like `if .name == "" then A else B end` instead. If the condition `A` produces multiple results, then `B` is evaluated once for each result that is not false or null, and `C` is evaluated once for each false or null. More cases can be added to an if using `elif A then B` syntax. examples: - program: |- if . == 0 then "zero" elif . == 1 then "one" else "many" end input: '2' output: ['"many"'] - title: "`>`, `>=`, `<=`, `<`" body: | The comparison operators `>`, `>=`, `<=`, `<` return whether their left argument is greater than, greater than or equal to, less than or equal to or less than their right argument (respectively). The ordering is the same as that described for `sort`, above. examples: - program: '. < 5' input: '2' output: ['true'] - title: "`and`, `or`, `not`" body: | jq supports the normal Boolean operators `and`, `or`, `not`. They have the same standard of truth as if expressions - `false` and `null` are considered "false values", and anything else is a "true value". If an operand of one of these operators produces multiple results, the operator itself will produce a result for each input. `not` is in fact a builtin function rather than an operator, so it is called as a filter to which things can be piped rather than with special syntax, as in `.foo and .bar | not`. These three only produce the values `true` and `false`, and so are only useful for genuine Boolean operations, rather than the common Perl/Python/Ruby idiom of "value_that_may_be_null or default". If you want to use this form of "or", picking between two values rather than evaluating a condition, see the `//` operator below. examples: - program: '42 and "a string"' input: 'null' output: ['true'] - program: '(true, false) or false' input: 'null' output: ['true', 'false'] - program: '(true, true) and (true, false)' input: 'null' output: ['true', 'false', 'true', 'false'] - program: '[true, false | not]' input: 'null' output: ['[false, true]'] - title: "Alternative operator: `//`" body: | The `//` operator produces all the values of its left-hand side that are neither `false` nor `null`. If the left-hand side produces no values other than `false` or `null`, then `//` produces all the values of its right-hand side. A filter of the form `a // b` produces all the results of `a` that are not `false` or `null`. If `a` produces no results, or no results other than `false` or `null`, then `a // b` produces the results of `b`. This is useful for providing defaults: `.foo // 1` will evaluate to `1` if there's no `.foo` element in the input. It's similar to how `or` is sometimes used in Python (jq's `or` operator is reserved for strictly Boolean operations). Note: `some_generator // defaults_here` is not the same as `some_generator | . // defaults_here`. The latter will produce default values for all non-`false`, non-`null` values of the left-hand side, while the former will not. Precedence rules can make this confusing. For example, in `false, 1 // 2` the left-hand side of `//` is `1`, not `false, 1` -- `false, 1 // 2` parses the same way as `false, (1 // 2)`. In `(false, null, 1) | . // 42` the left-hand side of `//` is `.`, which always produces just one value, while in `(false, null, 1) // 42` the left-hand side is a generator of three values, and since it produces a value other `false` and `null`, the default `42` is not produced. examples: - program: 'empty // 42' input: 'null' output: ['42'] - program: '.foo // 42' input: '{"foo": 19}' output: ['19'] - program: '.foo // 42' input: '{}' output: ['42'] - program: '(false, null, 1) // 42' input: 'null' output: ['1'] - program: '(false, null, 1) | . // 42' input: 'null' output: ['42', '42', '1'] - title: try-catch body: | Errors can be caught by using `try EXP catch EXP`. The first expression is executed, and if it fails then the second is executed with the error message. The output of the handler, if any, is output as if it had been the output of the expression to try. The `try EXP` form uses `empty` as the exception handler. examples: - program: 'try .a catch ". is not an object"' input: 'true' output: ['". is not an object"'] - program: '[.[]|try .a]' input: '[{}, true, {"a":1}]' output: ['[null, 1]'] - program: 'try error("some exception") catch .' input: 'true' output: ['"some exception"'] - title: Breaking out of control structures body: | A convenient use of try/catch is to break out of control structures like `reduce`, `foreach`, `while`, and so on. For example: # Repeat an expression until it raises "break" as an # error, then stop repeating without re-raising the error. # But if the error caught is not "break" then re-raise it. try repeat(exp) catch if .=="break" then empty else error jq has a syntax for named lexical labels to "break" or "go (back) to": label $out | ... break $out ... The `break $label_name` expression will cause the program to act as though the nearest (to the left) `label $label_name` produced `empty`. The relationship between the `break` and corresponding `label` is lexical: the label has to be "visible" from the break. To break out of a `reduce`, for example: label $out | reduce .[] as $item (null; if .==false then break $out else ... end) The following jq program produces a syntax error: break $out because no label `$out` is visible. - title: "Error Suppression / Optional Operator: `?`" body: | The `?` operator, used as `EXP?`, is shorthand for `try EXP`. examples: - program: '[.[] | .a?]' input: '[{}, true, {"a":1}]' output: ['[null, 1]'] - program: '[.[] | tonumber?]' input: '["1", "invalid", "3", 4]' output: ['[1, 3, 4]'] - title: Regular expressions body: | jq uses the [Oniguruma regular expression library](https://github.com/kkos/oniguruma/blob/master/doc/RE), as do PHP, TextMate, Sublime Text, etc, so the description here will focus on jq specifics. Oniguruma supports several flavors of regular expression, so it is important to know that jq uses the ["Perl NG" (Perl with named groups)](https://github.com/kkos/oniguruma/blob/master/doc/SYNTAX.md) flavor. The jq regex filters are defined so that they can be used using one of these patterns: STRING | FILTER(REGEX) STRING | FILTER(REGEX; FLAGS) STRING | FILTER([REGEX]) STRING | FILTER([REGEX, FLAGS]) where: * STRING, REGEX, and FLAGS are jq strings and subject to jq string interpolation; * REGEX, after string interpolation, should be a valid regular expression; * FILTER is one of `test`, `match`, or `capture`, as described below. Since REGEX must evaluate to a JSON string, some characters that are needed to form a regular expression must be escaped. For example, the regular expression `\s` signifying a whitespace character would be written as `"\\s"`. FLAGS is a string consisting of one of more of the supported flags: * `g` - Global search (find all matches, not just the first) * `i` - Case insensitive search * `m` - Multi line mode (`.` will match newlines) * `n` - Ignore empty matches * `p` - Both s and m modes are enabled * `s` - Single line mode (`^` -> `\A`, `$` -> `\Z`) * `l` - Find longest possible matches * `x` - Extended regex format (ignore whitespace and comments) To match a whitespace with the `x` flag, use `\s`, e.g. jq -n '"a b" | test("a\\sb"; "x")' Note that certain flags may also be specified within REGEX, e.g. jq -n '("test", "TEst", "teST", "TEST") | test("(?i)te(?-i)st")' evaluates to: `true`, `true`, `false`, `false`. entries: - title: "`test(val)`, `test(regex; flags)`" body: | Like `match`, but does not return match objects, only `true` or `false` for whether or not the regex matches the input. examples: - program: 'test("foo")' input: '"foo"' output: ['true'] - program: '.[] | test("a b c # spaces are ignored"; "ix")' input: '["xabcd", "ABC"]' output: ['true', 'true'] - title: "`match(val)`, `match(regex; flags)`" body: | **match** outputs an object for each match it finds. Matches have the following fields: * `offset` - offset in UTF-8 codepoints from the beginning of the input * `length` - length in UTF-8 codepoints of the match * `string` - the string that it matched * `captures` - an array of objects representing capturing groups. Capturing group objects have the following fields: * `offset` - offset in UTF-8 codepoints from the beginning of the input * `length` - length in UTF-8 codepoints of this capturing group * `string` - the string that was captured * `name` - the name of the capturing group (or `null` if it was unnamed) Capturing groups that did not match anything return an offset of -1 examples: - program: 'match("(abc)+"; "g")' input: '"abc abc"' output: - '{"offset": 0, "length": 3, "string": "abc", "captures": [{"offset": 0, "length": 3, "string": "abc", "name": null}]}' - '{"offset": 4, "length": 3, "string": "abc", "captures": [{"offset": 4, "length": 3, "string": "abc", "name": null}]}' - program: 'match("foo")' input: '"foo bar foo"' output: ['{"offset": 0, "length": 3, "string": "foo", "captures": []}'] - program: 'match(["foo", "ig"])' input: '"foo bar FOO"' output: - '{"offset": 0, "length": 3, "string": "foo", "captures": []}' - '{"offset": 8, "length": 3, "string": "FOO", "captures": []}' - program: 'match("foo (?bar)? foo"; "ig")' input: '"foo bar foo foo foo"' output: - '{"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"}]}' - program: '[ match("."; "g")] | length' input: '"abc"' output: ['3'] - title: "`capture(val)`, `capture(regex; flags)`" body: | Collects the named captures in a JSON object, with the name of each capture as the key, and the matched string as the corresponding value. examples: - program: 'capture("(?[a-z]+)-(?[0-9]+)")' input: '"xyzzy-14"' output: ['{ "a": "xyzzy", "n": "14" }'] - title: "`scan(regex)`, `scan(regex; flags)`" body: | Emit a stream of the non-overlapping substrings of the input that match the regex in accordance with the flags, if any have been specified. If there is no match, the stream is empty. To capture all the matches for each input string, use the idiom `[ expr ]`, e.g. `[ scan(regex) ]`. If the regex contains capturing groups, the filter emits a stream of arrays, each of which contains the captured strings. examples: - program: 'scan("c")' input: '"abcdefabc"' output: ['"c"', '"c"'] - program: 'scan("(a+)(b+)")' input: '"abaabbaaabbb"' output: ['["a","b"]', '["aa","bb"]', '["aaa","bbb"]'] - title: "`split(regex; flags)`" body: | Splits an input string on each regex match. For backwards compatibility, when called with a single argument, `split` splits on a string, not a regex. examples: - program: 'split(", *"; null)' input: '"ab,cd, ef"' output: ['["ab","cd","ef"]'] - title: "`splits(regex)`, `splits(regex; flags)`" body: | These provide the same results as their `split` counterparts, but as a stream instead of an array. examples: - program: 'splits(", *")' input: '"ab,cd, ef, gh"' output: ['"ab"','"cd"','"ef"','"gh"'] - program: 'splits(",? *"; "n")' input: '"ab,cd ef, gh"' output: ['"ab"','"cd"','"ef"','"gh"'] - title: "`sub(regex; tostring)`, `sub(regex; tostring; flags)`" body: | Emit the string obtained by replacing the first match of regex in the input string with `tostring`, after interpolation. `tostring` should be a jq string or a stream of such strings, each of which may contain references to named captures. The named captures are, in effect, presented as a JSON object (as constructed by `capture`) to `tostring`, so a reference to a captured variable named "x" would take the form: `"\(.x)"`. examples: - program: 'sub("[^a-z]*(?[a-z]+)"; "Z\(.x)"; "g")' input: '"123abc456def"' output: ['"ZabcZdef"'] - program: '[sub("(?.)"; "\(.a|ascii_upcase)", "\(.a|ascii_downcase)")]' input: '"aB"' output: ['["AB","aB"]'] - title: "`gsub(regex; tostring)`, `gsub(regex; tostring; flags)`" body: | `gsub` is like `sub` but all the non-overlapping occurrences of the regex are replaced by `tostring`, after interpolation. If the second argument is a stream of jq strings, then `gsub` will produce a corresponding stream of JSON strings. examples: - program: 'gsub("(?.)[^a]*"; "+\(.x)-")' input: '"Abcabc"' output: ['"+A-+a-"'] - program: '[gsub("p"; "a", "b")]' input: '"p"' output: ['["a","b"]'] - title: Advanced features body: | Variables are an absolute necessity in most programming languages, but they're relegated to an "advanced feature" in jq. In most languages, variables are the only means of passing around data. If you calculate a value, and you want to use it more than once, you'll need to store it in a variable. To pass a value to another part of the program, you'll need that part of the program to define a variable (as a function parameter, object member, or whatever) in which to place the data. It is also possible to define functions in jq, although this is is a feature whose biggest use is defining jq's standard library (many jq functions such as `map` and `select` are in fact written in jq). jq has reduction operators, which are very powerful but a bit tricky. Again, these are mostly used internally, to define some useful bits of jq's standard library. It may not be obvious at first, but jq is all about generators (yes, as often found in other languages). Some utilities are provided to help deal with generators. Some minimal I/O support (besides reading JSON from standard input, and writing JSON to standard output) is available. Finally, there is a module/library system. entries: - title: "Variable / Symbolic Binding Operator: `... as $identifier | ...`" body: | In jq, all filters have an input and an output, so manual plumbing is not necessary to pass a value from one part of a program to the next. Many expressions, for instance `a + b`, pass their input to two distinct subexpressions (here `a` and `b` are both passed the same input), so variables aren't usually necessary in order to use a value twice. For instance, calculating the average value of an array of numbers requires a few variables in most languages - at least one to hold the array, perhaps one for each element or for a loop counter. In jq, it's simply `add / length` - the `add` expression is given the array and produces its sum, and the `length` expression is given the array and produces its length. So, there's generally a cleaner way to solve most problems in jq than defining variables. Still, sometimes they do make things easier, so jq lets you define variables using `expression as $variable`. All variable names start with `$`. Here's a slightly uglier version of the array-averaging example: length as $array_length | add / $array_length We'll need a more complicated problem to find a situation where using variables actually makes our lives easier. Suppose we have an array of blog posts, with "author" and "title" fields, and another object which is used to map author usernames to real names. Our input looks like: {"posts": [{"title": "First post", "author": "anon"}, {"title": "A well-written article", "author": "person1"}], "realnames": {"anon": "Anonymous Coward", "person1": "Person McPherson"}} We want to produce the posts with the author field containing a real name, as in: {"title": "First post", "author": "Anonymous Coward"} {"title": "A well-written article", "author": "Person McPherson"} We use a variable, `$names`, to store the realnames object, so that we can refer to it later when looking up author usernames: .realnames as $names | .posts[] | {title, author: $names[.author]} The expression `exp as $x | ...` means: for each value of expression `exp`, run the rest of the pipeline with the entire original input, and with `$x` set to that value. Thus `as` functions as something of a foreach loop. Just as `{foo}` is a handy way of writing `{foo: .foo}`, so `{$foo}` is a handy way of writing `{foo: $foo}`. Multiple variables may be declared using a single `as` expression by providing a pattern that matches the structure of the input (this is known as "destructuring"): . as {realnames: $names, posts: [$first, $second]} | ... The variable declarations in array patterns (e.g., `. as [$first, $second]`) bind to the elements of the array in from the element at index zero on up, in order. When there is no value at the index for an array pattern element, `null` is bound to that variable. Variables are scoped over the rest of the expression that defines them, so .realnames as $names | (.posts[] | {title, author: $names[.author]}) will work, but (.realnames as $names | .posts[]) | {title, author: $names[.author]} won't. For programming language theorists, it's more accurate to say that jq variables are lexically-scoped bindings. In particular there's no way to change the value of a binding; one can only setup a new binding with the same name, but which will not be visible where the old one was. examples: - program: '.bar as $x | .foo | . + $x' input: '{"foo":10, "bar":200}' output: ['210'] - program: '. as $i|[(.*2|. as $i| $i), $i]' input: '5' output: ['[10,5]'] - program: '. as [$a, $b, {c: $c}] | $a + $b + $c' input: '[2, 3, {"c": 4, "d": 5}]' output: ['9'] - program: '.[] as [$a, $b] | {a: $a, b: $b}' input: '[[0], [0, 1], [2, 1, 0]]' output: ['{"a":0,"b":null}', '{"a":0,"b":1}', '{"a":2,"b":1}'] - title: 'Destructuring Alternative Operator: `?//`' body: | The destructuring alternative operator provides a concise mechanism for destructuring an input that can take one of several forms. Suppose we have an API that returns a list of resources and events associated with them, and we want to get the user_id and timestamp of the first event for each resource. The API (having been clumsily converted from XML) will only wrap the events in an array if the resource has multiple events: {"resources": [{"id": 1, "kind": "widget", "events": {"action": "create", "user_id": 1, "ts": 13}}, {"id": 2, "kind": "widget", "events": [{"action": "create", "user_id": 1, "ts": 14}, {"action": "destroy", "user_id": 1, "ts": 15}]}]} We can use the destructuring alternative operator to handle this structural change simply: .resources[] as {$id, $kind, events: {$user_id, $ts}} ?// {$id, $kind, events: [{$user_id, $ts}]} | {$user_id, $kind, $id, $ts} Or, if we aren't sure if the input is an array of values or an object: .[] as [$id, $kind, $user_id, $ts] ?// {$id, $kind, $user_id, $ts} | ... Each alternative need not define all of the same variables, but all named variables will be available to the subsequent expression. Variables not matched in the alternative that succeeded will be `null`: .resources[] as {$id, $kind, events: {$user_id, $ts}} ?// {$id, $kind, events: [{$first_user_id, $first_ts}]} | {$user_id, $first_user_id, $kind, $id, $ts, $first_ts} Additionally, if the subsequent expression returns an error, the alternative operator will attempt to try the next binding. Errors that occur during the final alternative are passed through. [[3]] | .[] as [$a] ?// [$b] | if $a != null then error("err: \($a)") else {$a,$b} end examples: - program: '.[] as {$a, $b, c: {$d, $e}} ?// {$a, $b, c: [{$d, $e}]} | {$a, $b, $d, $e}' input: '[{"a": 1, "b": 2, "c": {"d": 3, "e": 4}}, {"a": 1, "b": 2, "c": [{"d": 3, "e": 4}]}]' output: ['{"a":1,"b":2,"d":3,"e":4}', '{"a":1,"b":2,"d":3,"e":4}'] - program: '.[] as {$a, $b, c: {$d}} ?// {$a, $b, c: [{$e}]} | {$a, $b, $d, $e}' input: '[{"a": 1, "b": 2, "c": {"d": 3, "e": 4}}, {"a": 1, "b": 2, "c": [{"d": 3, "e": 4}]}]' output: ['{"a":1,"b":2,"d":3,"e":null}', '{"a":1,"b":2,"d":null,"e":4}'] - program: '.[] as [$a] ?// [$b] | if $a != null then error("err: \($a)") else {$a,$b} end' input: '[[3]]' output: ['{"a":null,"b":3}'] - title: 'Defining Functions' body: | You can give a filter a name using "def" syntax: def increment: . + 1; From then on, `increment` is usable as a filter just like a builtin function (in fact, this is how many of the builtins are defined). A function may take arguments: def map(f): [.[] | f]; Arguments are passed as _filters_ (functions with no arguments), _not_ as values. The same argument may be referenced multiple times with different inputs (here `f` is run for each element of the input array). Arguments to a function work more like callbacks than like value arguments. This is important to understand. Consider: def foo(f): f|f; 5|foo(.*2) The result will be 20 because `f` is `.*2`, and during the first invocation of `f` `.` will be 5, and the second time it will be 10 (5 * 2), so the result will be 20. Function arguments are filters, and filters expect an input when invoked. If you want the value-argument behaviour for defining simple functions, you can just use a variable: def addvalue(f): f as $f | map(. + $f); Or use the short-hand: def addvalue($f): ...; With either definition, `addvalue(.foo)` will add the current input's `.foo` field to each element of the array. Do note that calling `addvalue(.[])` will cause the `map(. + $f)` part to be evaluated once per value in the value of `.` at the call site. Multiple definitions using the same function name are allowed. Each re-definition replaces the previous one for the same number of function arguments, but only for references from functions (or main program) subsequent to the re-definition. See also the section below on scoping. examples: - program: 'def addvalue(f): . + [f]; map(addvalue(.[0]))' input: '[[1,2],[10,20]]' output: ['[[1,2,1], [10,20,10]]'] - program: 'def addvalue(f): f as $x | map(. + $x); addvalue(.[0])' input: '[[1,2],[10,20]]' output: ['[[1,2,1,2], [10,20,1,2]]'] - title: 'Scoping' body: | There are two types of symbols in jq: value bindings (a.k.a., "variables"), and functions. Both are scoped lexically, with expressions being able to refer only to symbols that have been defined "to the left" of them. The only exception to this rule is that functions can refer to themselves so as to be able to create recursive functions. For example, in the following expression there is a binding which is visible "to the right" of it, `... | .*3 as $times_three | [. + $times_three] | ...`, but not "to the left". Consider this expression now, `... | (.*3 as $times_three | [. + $times_three]) | ...`: here the binding `$times_three` is _not_ visible past the closing parenthesis. - title: "`isempty(exp)`" body: | Returns true if `exp` produces no outputs, false otherwise. examples: - program: 'isempty(empty)' input: 'null' output: ['true'] - program: 'isempty(.[])' input: '[]' output: ['true'] - program: 'isempty(.[])' input: '[1,2,3]' output: ['false'] - title: "`limit(n; expr)`" body: | The `limit` function extracts up to `n` outputs from `expr`. examples: - program: '[limit(3; .[])]' input: '[0,1,2,3,4,5,6,7,8,9]' output: ['[0,1,2]'] - title: "`skip(n; expr)`" body: | The `skip` function skips the first `n` outputs from `expr`. examples: - program: '[skip(3; .[])]' input: '[0,1,2,3,4,5,6,7,8,9]' output: ['[3,4,5,6,7,8,9]'] - title: "`first(expr)`, `last(expr)`, `nth(n; expr)`" body: | The `first(expr)` and `last(expr)` functions extract the first and last values from `expr`, respectively. The `nth(n; expr)` function extracts the nth value output by `expr`. Note that `nth(n; expr)` doesn't support negative values of `n`. examples: - program: '[first(range(.)), last(range(.)), nth(5; range(.))]' input: '10' output: ['[0,9,5]'] - program: '[first(empty), last(empty), nth(5; empty)]' input: 'null' output: ['[]'] - title: "`first`, `last`, `nth(n)`" body: | The `first` and `last` functions extract the first and last values from any array at `.`. The `nth(n)` function extracts the nth value of any array at `.`. examples: - program: '[range(.)]|[first, last, nth(5)]' input: '10' output: ['[0,9,5]'] - title: "`reduce`" body: | The `reduce` syntax allows you to combine all of the results of an expression by accumulating them into a single answer. The form is `reduce EXP as $var (INIT; UPDATE)`. As an example, we'll pass `[1,2,3]` to this expression: reduce .[] as $item (0; . + $item) For each result that `.[]` produces, `. + $item` is run to accumulate a running total, starting from 0 as the input value. In this example, `.[]` produces the results `1`, `2`, and `3`, so the effect is similar to running something like this: 0 | 1 as $item | . + $item | 2 as $item | . + $item | 3 as $item | . + $item examples: - program: 'reduce .[] as $item (0; . + $item)' input: '[1,2,3,4,5]' output: ['15'] - program: 'reduce .[] as [$i,$j] (0; . + $i * $j)' input: '[[1,2],[3,4],[5,6]]' output: ['44'] - program: 'reduce .[] as {$x,$y} (null; .x += $x | .y += [$y])' input: '[{"x":"a","y":1},{"x":"b","y":2},{"x":"c","y":3}]' output: ['{"x":"abc","y":[1,2,3]}'] - title: "`foreach`" body: | The `foreach` syntax is similar to `reduce`, but intended to allow the construction of `limit` and reducers that produce intermediate results. The form is `foreach EXP as $var (INIT; UPDATE; EXTRACT)`. As an example, we'll pass `[1,2,3]` to this expression: foreach .[] as $item (0; . + $item; [$item, . * 2]) Like the `reduce` syntax, `. + $item` is run for each result that `.[]` produces, but `[$item, . * 2]` is run for each intermediate values. In this example, since the intermediate values are `1`, `3`, and `6`, the `foreach` expression produces `[1,2]`, `[2,6]`, and `[3,12]`. So the effect is similar to running something like this: 0 | 1 as $item | . + $item | [$item, . * 2], 2 as $item | . + $item | [$item, . * 2], 3 as $item | . + $item | [$item, . * 2] When `EXTRACT` is omitted, the identity filter is used. That is, it outputs the intermediate values as they are. examples: - program: 'foreach .[] as $item (0; . + $item)' input: '[1,2,3,4,5]' output: ['1','3','6','10','15'] - program: 'foreach .[] as $item (0; . + $item; [$item, . * 2])' input: '[1,2,3,4,5]' output: ['[1,2]','[2,6]','[3,12]','[4,20]','[5,30]'] - program: 'foreach .[] as $item (0; . + 1; {index: ., $item})' input: '["foo", "bar", "baz"]' output: - '{"index":1,"item":"foo"}' - '{"index":2,"item":"bar"}' - '{"index":3,"item":"baz"}' - title: Recursion body: | As described above, `recurse` uses recursion, and any jq function can be recursive. The `while` builtin is also implemented in terms of recursion. Tail calls are optimized whenever the expression to the left of the recursive call outputs its last value. In practice this means that the expression to the left of the recursive call should not produce more than one output for each input. For example: def recurse(f): def r: ., (f | select(. != null) | r); r; def while(cond; update): def _while: if cond then ., (update | _while) else empty end; _while; def repeat(exp): def _repeat: exp, _repeat; _repeat; - title: Generators and iterators body: | Some jq operators and functions are actually generators in that they can produce zero, one, or more values for each input, just as one might expect in other programming languages that have generators. For example, `.[]` generates all the values in its input (which must be an array or an object), `range(0; 10)` generates the integers between 0 and 10, and so on. Even the comma operator is a generator, generating first the values generated by the expression to the left of the comma, then the values generated by the expression on the right of the comma. The `empty` builtin is the generator that produces zero outputs. The `empty` builtin backtracks to the preceding generator expression. All jq functions can be generators just by using builtin generators. It is also possible to construct new generators using only recursion and the comma operator. If recursive calls are "in tail position" then the generator will be efficient. In the example below the recursive call by `_range` to itself is in tail position. The example shows off three advanced topics: tail recursion, generator construction, and sub-functions. examples: - program: 'def range(init; upto; by): def _range: if (by > 0 and . < upto) or (by < 0 and . > upto) then ., ((.+by)|_range) else empty end; if init == upto then empty elif by == 0 then init else init|_range end; range(0; 10; 3)' input: 'null' output: ['0', '3', '6', '9'] - program: 'def while(cond; update): def _while: if cond then ., (update | _while) else empty end; _while; [while(.<100; .*2)]' input: '1' output: ['[1,2,4,8,16,32,64]'] - title: 'Math' body: | jq currently only has IEEE754 double-precision (64-bit) floating point number support. Besides simple arithmetic operators such as `+`, jq also has most standard math functions from the C math library. C math functions that take a single input argument (e.g., `sin()`) are available as zero-argument jq functions. C math functions that take two input arguments (e.g., `pow()`) are available as two-argument jq functions that ignore `.`. C math functions that take three input arguments are available as three-argument jq functions that ignore `.`. Availability of standard math functions depends on the availability of the corresponding math functions in your operating system and C math library. Unavailable math functions will be defined but will raise an error. One-input C math functions: `acos` `acosh` `asin` `asinh` `atan` `atanh` `cbrt` `ceil` `cos` `cosh` `erf` `erfc` `exp` `exp10` `exp2` `expm1` `fabs` `floor` `gamma` `j0` `j1` `lgamma` `log` `log10` `log1p` `log2` `logb` `nearbyint` `rint` `round` `significand` `sin` `sinh` `sqrt` `tan` `tanh` `tgamma` `trunc` `y0` `y1`. Two-input C math functions: `atan2` `copysign` `drem` `fdim` `fmax` `fmin` `fmod` `frexp` `hypot` `jn` `ldexp` `modf` `nextafter` `nexttoward` `pow` `remainder` `scalb` `scalbln` `yn`. Three-input C math functions: `fma`. See your system's manual for more information on each of these. - title: 'I/O' body: | At this time jq has minimal support for I/O, mostly in the form of control over when inputs are read. Two builtins functions are provided for this, `input` and `inputs`, that read from the same sources (e.g., `stdin`, files named on the command-line) as jq itself. These two builtins, and jq's own reading actions, can be interleaved with each other. They are commonly used in combination with the null input option `-n` to prevent one input from being read implicitly. Two builtins provide minimal output capabilities, `debug`, and `stderr`. (Recall that a jq program's output values are always output as JSON texts on `stdout`.) The `debug` builtin can have application-specific behavior, such as for executables that use the libjq C API but aren't the jq executable itself. The `stderr` builtin outputs its input in raw mode to stderr with no additional decoration, not even a newline. Most jq builtins are referentially transparent, and yield constant and repeatable value streams when applied to constant inputs. This is not true of I/O builtins. entries: - title: "`input`" body: | Outputs one new input. Note that when using `input` it is generally necessary to invoke jq with the `-n` command-line option, otherwise the first entity will be lost. echo 1 2 3 4 | jq '[., input]' # [1,2] [3,4] - title: "`inputs`" body: | Outputs all remaining inputs, one by one. This is primarily useful for reductions over a program's inputs. Note that when using `inputs` it is generally necessary to invoke jq with the `-n` command-line option, otherwise the first entity will be lost. echo 1 2 3 | jq -n 'reduce inputs as $i (0; . + $i)' # 6 - title: "`debug`, `debug(msgs)`" body: | These two filters are like `.` but have as a side-effect the production of one or more messages on stderr. The message produced by the `debug` filter has the form ["DEBUG:",] where `` is a compact rendition of the input value. This format may change in the future. The `debug(msgs)` filter is defined as `(msgs | debug | empty), .` thus allowing great flexibility in the content of the message, while also allowing multi-line debugging statements to be created. For example, the expression: 1 as $x | 2 | debug("Entering function foo with $x == \($x)", .) | (.+1) would produce the value 3 but with the following two lines being written to stderr: ["DEBUG:","Entering function foo with $x == 1"] ["DEBUG:",2] - title: "`stderr`" body: | Prints its input in raw and compact mode to stderr with no additional decoration, not even a newline. - title: "`input_filename`" body: | Returns the name of the file whose input is currently being filtered. Note that this will not work well unless jq is running in a UTF-8 locale. - title: "`input_line_number`" body: | Returns the line number of the input currently being filtered. - title: 'Streaming' body: | With the `--stream` option jq can parse input texts in a streaming fashion, allowing jq programs to start processing large JSON texts immediately rather than after the parse completes. If you have a single JSON text that is 1GB in size, streaming it will allow you to process it much more quickly. However, streaming isn't easy to deal with as the jq program will have `[, ]` (and a few other forms) as inputs. Several builtins are provided to make handling streams easier. The examples below use the streamed form of `["a",["b"]]`, which is `[[0],"a"],[[1,0],"b"],[[1,0]],[[1]]`. Streaming forms include `[, ]` (to indicate any scalar value, empty array, or empty object), and `[]` (to indicate the end of an array or object). Future versions of jq run with `--stream` and `--seq` may output additional forms such as `["error message"]` when an input text fails to parse. entries: - title: "`truncate_stream(stream_expression)`" body: | Consumes a number as input and truncates the corresponding number of path elements from the left of the outputs of the given streaming expression. examples: - program: 'truncate_stream([[0],"a"],[[1,0],"b"],[[1,0]],[[1]])' input: '1' output: ['[[0],"b"]', '[[0]]'] - title: "`fromstream(stream_expression)`" body: | Outputs values corresponding to the stream expression's outputs. examples: - program: 'fromstream(1|truncate_stream([[0],"a"],[[1,0],"b"],[[1,0]],[[1]]))' input: 'null' output: ['["b"]'] - title: "`tostream`" body: | The `tostream` builtin outputs the streamed form of its input. examples: - program: '. as $dot|fromstream($dot|tostream)|.==$dot' input: '[0,[1,{"a":1},{"b":2}]]' output: ['true'] - title: Assignment body: | Assignment works a little differently in jq than in most programming languages. jq doesn't distinguish between references to and copies of something - two objects or arrays are either equal or not equal, without any further notion of being "the same object" or "not the same object". If an object has two fields which are arrays, `.foo` and `.bar`, and you append something to `.foo`, then `.bar` will not get bigger, even if you've previously set `.bar = .foo`. If you're used to programming in languages like Python, Java, Ruby, JavaScript, etc. then you can think of it as though jq does a full deep copy of every object before it does the assignment (for performance it doesn't actually do that, but that's the general idea). This means that it's impossible to build circular values in jq (such as an array whose first element is itself). This is quite intentional, and ensures that anything a jq program can produce can be represented in JSON. All the assignment operators in jq have path expressions on the left-hand side (LHS). The right-hand side (RHS) provides values to set to the paths named by the LHS path expressions. Values in jq are always immutable. Internally, assignment works by using a reduction to compute new, replacement values for `.` that have had all the desired assignments applied to `.`, then outputting the modified value. This might be made clear by this example: `{a:{b:{c:1}}} | (.a.b|=3), .`. This will output `{"a":{"b":3}}` and `{"a":{"b":{"c":1}}}` because the last sub-expression, `.`, sees the original value, not the modified value. Most users will want to use modification assignment operators, such as `|=` or `+=`, rather than `=`. Note that the LHS of assignment operators refers to a value in `.`. Thus `$var.foo = 1` won't work as expected (`$var.foo` is not a valid or useful path expression in `.`); use `$var | .foo = 1` instead. Note too that `.a,.b=0` does not set `.a` and `.b`, but `(.a,.b)=0` sets both. entries: - title: "Update-assignment: `|=`" body: | This is the "update" operator `|=`. It takes a filter on the right-hand side and works out the new value for the property of `.` being assigned to by running the old value through this expression. For instance, `(.foo, .bar) |= .+1` will build an object with the `foo` field set to the input's `foo` plus 1, and the `bar` field set to the input's `bar` plus 1. The left-hand side can be any general path expression; see `path()`. Note that the left-hand side of `|=` refers to a value in `.`. Thus `$var.foo |= . + 1` won't work as expected (`$var.foo` is not a valid or useful path expression in `.`); use `$var | .foo |= . + 1` instead. If the right-hand side outputs no values (i.e., `empty`), then the left-hand side path will be deleted, as with `del(path)`. If the right-hand side outputs multiple values, only the first one will be used (COMPATIBILITY NOTE: in jq 1.5 and earlier releases, it used to be that only the last one was used). examples: - program: '(..|select(type=="boolean")) |= if . then 1 else 0 end' input: '[true,false,[5,true,[true,[false]],false]]' output: ['[1,0,[5,1,[1,[0]],0]]'] - title: "Arithmetic update-assignment: `+=`, `-=`, `*=`, `/=`, `%=`, `//=`" body: | jq has a few operators of the form `a op= b`, which are all equivalent to `a |= . op b`. So, `+= 1` can be used to increment values, being the same as `|= . + 1`. examples: - program: .foo += 1 input: '{"foo": 42}' output: ['{"foo": 43}'] - title: "Plain assignment: `=`" body: | This is the plain assignment operator. Unlike the others, the input to the right-hand side (RHS) is the same as the input to the left-hand side (LHS) rather than the value at the LHS path, and all values output by the RHS will be used (as shown below). If the RHS of `=` produces multiple values, then for each such value jq will set the paths on the left-hand side to the value and then it will output the modified `.`. For example, `(.a,.b) = range(2)` outputs `{"a":0,"b":0}`, then `{"a":1,"b":1}`. The "update" assignment forms (see above) do not do this. This example should show the difference between `=` and `|=`: Provide input `{"a": {"b": 10}, "b": 20}` to the programs .a = .b and .a |= .b The former will set the `a` field of the input to the `b` field of the input, and produce the output `{"a": 20, "b": 20}`. The latter will set the `a` field of the input to the `a` field's `b` field, producing `{"a": 10, "b": 20}`. examples: - program: .a = .b input: '{"a": {"b": 10}, "b": 20}' output: ['{"a":20,"b":20}'] - program: .a |= .b input: '{"a": {"b": 10}, "b": 20}' output: ['{"a":10,"b":20}'] - program: (.a, .b) = range(3) input: 'null' output: - '{"a":0,"b":0}' - '{"a":1,"b":1}' - '{"a":2,"b":2}' - program: (.a, .b) |= range(3) input: 'null' output: ['{"a":0,"b":0}'] - title: Complex assignments body: | Lots more things are allowed on the left-hand side of a jq assignment than in most languages. We've already seen simple field accesses on the left hand side, and it's no surprise that array accesses work just as well: .posts[0].title = "JQ Manual" What may come as a surprise is that the expression on the left may produce multiple results, referring to different points in the input document: .posts[].comments |= . + ["this is great"] That example appends the string "this is great" to the "comments" array of each post in the input (where the input is an object with a field "posts" which is an array of posts). When jq encounters an assignment like 'a = b', it records the "path" taken to select a part of the input document while executing a. This path is then used to find which part of the input to change while executing the assignment. Any filter may be used on the left-hand side of an equals - whichever paths it selects from the input will be where the assignment is performed. This is a very powerful operation. Suppose we wanted to add a comment to blog posts, using the same "blog" input above. This time, we only want to comment on the posts written by "stedolan". We can find those posts using the "select" function described earlier: .posts[] | select(.author == "stedolan") The paths provided by this operation point to each of the posts that "stedolan" wrote, and we can comment on each of them in the same way that we did before: (.posts[] | select(.author == "stedolan") | .comments) |= . + ["terrible."] - title: Comments body: | You can write comments in your jq filters using `#`. A `#` character (not part of a string) starts a comment. All characters from `#` to the end of the line are ignored. If the end of the line is preceded by an odd number of backslash characters, the following line is also considered part of the comment and is ignored. For example, the following code outputs `[1,3,4,7]` [ 1, # foo \ 2, # bar \\ 3, 4, # baz \\\ 5, \ 6, 7 # comment \ comment \ comment ] Backslash continuing the comment on the next line can be useful when writing the "shebang" for a jq script: #!/bin/sh -- # total - Output the sum of the given arguments (or stdin) # usage: total [numbers...] # \ exec jq --args -MRnf -- "$0" "$@" $ARGS.positional | reduce ( if . == [] then inputs else .[] end | . as $dot | try tonumber catch false | if not or isnan then @json "total: Invalid number \($dot).\n" | halt_error(1) end ) as $n (0; . + $n) The `exec` line is considered a comment by jq, so it is ignored. But it is not ignored by `sh`, since in `sh` a backslash at the end of the line does not continue the comment. With this trick, when the script is invoked as `total 1 2`, `/bin/sh -- /path/to/total 1 2` will be run, and `sh` will then run `exec jq --args -MRnf -- /path/to/total 1 2` replacing itself with a `jq` interpreter invoked with the specified options (`-M`, `-R`, `-n`, `--args`), that evaluates the current file (`$0`), with the arguments (`$@`) that were passed to `sh`. - title: Modules body: | jq has a library/module system. Modules are files whose names end in `.jq`. Modules imported by a program are searched for in a default search path (see below). The `import` and `include` directives allow the importer to alter this path. Paths in the search path are subject to various substitutions. For paths starting with `~/`, the user's home directory is substituted for `~`. For paths starting with `$ORIGIN/`, the directory where the jq executable is located is substituted for `$ORIGIN`. For paths starting with `./` or paths that are `.`, the path of the including file is substituted for `.`. For top-level programs given on the command-line, the current directory is used. Import directives can optionally specify a search path to which the default is appended. The default search path is the search path given to the `-L` command-line option, else `["~/.jq", "$ORIGIN/../lib/jq", "$ORIGIN/../lib"]`. Null and empty string path elements terminate search path processing. A dependency with relative path `foo/bar` would be searched for in `foo/bar.jq` and `foo/bar/bar.jq` in the given search path. This is intended to allow modules to be placed in a directory along with, for example, version control files, README files, and so on, but also to allow for single-file modules. Consecutive components with the same name are not allowed to avoid ambiguities (e.g., `foo/foo`). For example, with `-L$HOME/.jq` a module `foo` can be found in `$HOME/.jq/foo.jq` and `$HOME/.jq/foo/foo.jq`. If `.jq` exists in the user's home directory, and is a file (not a directory), it is automatically sourced into the main program. entries: - title: "`import RelativePathString as NAME [];`" body: | Imports a module found at the given path relative to a directory in a search path. A `.jq` suffix will be added to the relative path string. The module's symbols are prefixed with `NAME::`. The optional metadata must be a constant jq expression. It should be an object with keys like `homepage` and so on. At this time jq only uses the `search` key/value of the metadata. The metadata is also made available to users via the `modulemeta` builtin. The `search` key in the metadata, if present, should have a string or array value (array of strings); this is the search path to be prefixed to the top-level search path. - title: "`include RelativePathString [];`" body: | Imports a module found at the given path relative to a directory in a search path as if it were included in place. A `.jq` suffix will be added to the relative path string. The module's symbols are imported into the caller's namespace as if the module's content had been included directly. The optional metadata must be a constant jq expression. It should be an object with keys like `homepage` and so on. At this time jq only uses the `search` key/value of the metadata. The metadata is also made available to users via the `modulemeta` builtin. - title: "`import RelativePathString as $NAME [];`" body: | Imports a JSON file found at the given path relative to a directory in a search path. A `.json` suffix will be added to the relative path string. The file's data will be available as `$NAME::NAME`. The optional metadata must be a constant jq expression. It should be an object with keys like `homepage` and so on. At this time jq only uses the `search` key/value of the metadata. The metadata is also made available to users via the `modulemeta` builtin. The `search` key in the metadata, if present, should have a string or array value (array of strings); this is the search path to be prefixed to the top-level search path. - title: "`module ;`" body: | This directive is entirely optional. It's not required for proper operation. It serves only the purpose of providing metadata that can be read with the `modulemeta` builtin. The metadata must be a constant jq expression. It should be an object with keys like `homepage`. At this time jq doesn't use this metadata, but it is made available to users via the `modulemeta` builtin. - title: "`modulemeta`" body: | Takes a module name as input and outputs the module's metadata as an object, with the module's imports (including metadata) as an array value for the `deps` key and the module's defined functions as an array value for the `defs` key. Programs can use this to query a module's metadata, which they could then use to, for example, search for, download, and install missing dependencies. - title: Colors body: | To configure alternative colors just set the `JQ_COLORS` environment variable to colon-delimited list of partial terminal escape sequences like `"1;31"`, in this order: - color for `null` - color for `false` - color for `true` - color for numbers - color for strings - color for arrays - color for objects - color for object keys The default color scheme is the same as setting `JQ_COLORS="0;90:0;39:0;39:0;39:0;32:1;39:1;39:1;34"`. This is not a manual for VT100/ANSI escapes. However, each of these color specifications should consist of two numbers separated by a semi-colon, where the first number is one of these: - 1 (bright) - 2 (dim) - 4 (underscore) - 5 (blink) - 7 (reverse) - 8 (hidden) and the second is one of these: - 30 (black) - 31 (red) - 32 (green) - 33 (yellow) - 34 (blue) - 35 (magenta) - 36 (cyan) - 37 (white) ================================================ FILE: docs/content/tutorial/default.yml ================================================ 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/jqlang/jq/commits?per_page=5'" result: | [ { "sha": "cff5336ec71b6fee396a95bb0e4bea365e0cd1e8", "node_id": "C_kwDOAE3WVdoAKGNmZjUzMzZlYzcxYjZmZWUzOTZhOTViYjBlNGJlYTM2NWUwY2QxZTg", "commit": { "author": { "name": "Mattias Wadman", "email": "mattias.wadman@gmail.com", "date": "2021-06-09T14:02:22Z" }, "committer": { "name": "Nico Williams", "email": "nico@cryptonector.com", "date": "2022-05-26T21:04:32Z" }, "message": "docs: Document repeat(exp)", "tree": { "sha": "d67d5542df1f16d1a48e1fb75749f60482cd874b", "url": "https://api.github.com/repos/jqlang/jq/git/trees/d67d5542df1f16d1a48e1fb75749f60482cd874b" }, "url": "https://api.github.com/repos/jqlang/jq/git/commits/cff5336ec71b6fee396a95bb0e4bea365e0cd1e8", "comment_count": 0, "verification": { "verified": false, "reason": "unsigned", "signature": null, "payload": null } }, "url": "https://api.github.com/repos/jqlang/jq/commits/cff5336ec71b6fee396a95bb0e4bea365e0cd1e8", "html_url": "https://github.com/jqlang/jq/commit/cff5336ec71b6fee396a95bb0e4bea365e0cd1e8", "comments_url": "https://api.github.com/repos/jqlang/jq/commits/cff5336ec71b6fee396a95bb0e4bea365e0cd1e8/comments", "author": { ... - text: | GitHub returns nicely formatted JSON. For servers that don't, it can be helpful to pipe the response through jq to pretty-print it. The simplest jq program is the expression `.`, which takes the input and produces it unchanged as output. - command: "curl 'https://api.github.com/repos/jqlang/jq/commits?per_page=5' | jq '.'" result: | [ { "sha": "cff5336ec71b6fee396a95bb0e4bea365e0cd1e8", "node_id": "C_kwDOAE3WVdoAKGNmZjUzMzZlYzcxYjZmZWUzOTZhOTViYjBlNGJlYTM2NWUwY2QxZTg", "commit": { "author": { "name": "Mattias Wadman", "email": "mattias.wadman@gmail.com", "date": "2021-06-09T14:02:22Z" }, "committer": { "name": "Nico Williams", "email": "nico@cryptonector.com", "date": "2022-05-26T21:04:32Z" }, "message": "docs: Document repeat(exp)", "tree": { "sha": "d67d5542df1f16d1a48e1fb75749f60482cd874b", "url": "https://api.github.com/repos/jqlang/jq/git/trees/d67d5542df1f16d1a48e1fb75749f60482cd874b" }, "url": "https://api.github.com/repos/jqlang/jq/git/commits/cff5336ec71b6fee396a95bb0e4bea365e0cd1e8", "comment_count": 0, "verification": { "verified": false, "reason": "unsigned", "signature": null, "payload": null } }, "url": "https://api.github.com/repos/jqlang/jq/commits/cff5336ec71b6fee396a95bb0e4bea365e0cd1e8", "html_url": "https://github.com/jqlang/jq/commit/cff5336ec71b6fee396a95bb0e4bea365e0cd1e8", "comments_url": "https://api.github.com/repos/jqlang/jq/commits/cff5336ec71b6fee396a95bb0e4bea365e0cd1e8/comments", "author": { ... - text: | We can use jq to extract just the first commit. - command: "curl 'https://api.github.com/repos/jqlang/jq/commits?per_page=5' | jq '.[0]'" result: | { "sha": "cff5336ec71b6fee396a95bb0e4bea365e0cd1e8", "node_id": "C_kwDOAE3WVdoAKGNmZjUzMzZlYzcxYjZmZWUzOTZhOTViYjBlNGJlYTM2NWUwY2QxZTg", "commit": { "author": { "name": "Mattias Wadman", "email": "mattias.wadman@gmail.com", "date": "2021-06-09T14:02:22Z" }, "committer": { "name": "Nico Williams", "email": "nico@cryptonector.com", "date": "2022-05-26T21:04:32Z" }, "message": "docs: Document repeat(exp)", "tree": { "sha": "d67d5542df1f16d1a48e1fb75749f60482cd874b", "url": "https://api.github.com/repos/jqlang/jq/git/trees/d67d5542df1f16d1a48e1fb75749f60482cd874b" }, "url": "https://api.github.com/repos/jqlang/jq/git/commits/cff5336ec71b6fee396a95bb0e4bea365e0cd1e8", "comment_count": 0, "verification": { "verified": false, "reason": "unsigned", "signature": null, "payload": null } }, "url": "https://api.github.com/repos/jqlang/jq/commits/cff5336ec71b6fee396a95bb0e4bea365e0cd1e8", "html_url": "https://github.com/jqlang/jq/commit/cff5336ec71b6fee396a95bb0e4bea365e0cd1e8", "comments_url": "https://api.github.com/repos/jqlang/jq/commits/cff5336ec71b6fee396a95bb0e4bea365e0cd1e8/comments", "author": { "login": "wader", "id": 185566, "node_id": "MDQ6VXNlcjE4NTU2Ng==", "avatar_url": "https://avatars.githubusercontent.com/u/185566?v=4", "gravatar_id": "", "url": "https://api.github.com/users/wader", "html_url": "https://github.com/wader", "followers_url": "https://api.github.com/users/wader/followers", "following_url": "https://api.github.com/users/wader/following{/other_user}", "gists_url": "https://api.github.com/users/wader/gists{/gist_id}", "starred_url": "https://api.github.com/users/wader/starred{/owner}{/repo}", "subscriptions_url": "https://api.github.com/users/wader/subscriptions", "organizations_url": "https://api.github.com/users/wader/orgs", "repos_url": "https://api.github.com/users/wader/repos", "events_url": "https://api.github.com/users/wader/events{/privacy}", "received_events_url": "https://api.github.com/users/wader/received_events", "type": "User", "site_admin": false }, "committer": { "login": "nicowilliams", "id": 604851, "node_id": "MDQ6VXNlcjYwNDg1MQ==", "avatar_url": "https://avatars.githubusercontent.com/u/604851?v=4", "gravatar_id": "", "url": "https://api.github.com/users/nicowilliams", "html_url": "https://github.com/nicowilliams", "followers_url": "https://api.github.com/users/nicowilliams/followers", "following_url": "https://api.github.com/users/nicowilliams/following{/other_user}", "gists_url": "https://api.github.com/users/nicowilliams/gists{/gist_id}", "starred_url": "https://api.github.com/users/nicowilliams/starred{/owner}{/repo}", "subscriptions_url": "https://api.github.com/users/nicowilliams/subscriptions", "organizations_url": "https://api.github.com/users/nicowilliams/orgs", "repos_url": "https://api.github.com/users/nicowilliams/repos", "events_url": "https://api.github.com/users/nicowilliams/events{/privacy}", "received_events_url": "https://api.github.com/users/nicowilliams/received_events", "type": "User", "site_admin": false }, "parents": [ { "sha": "f2ad9517c72f6267ae317639ab56bbfd4a8653d4", "url": "https://api.github.com/repos/jqlang/jq/commits/f2ad9517c72f6267ae317639ab56bbfd4a8653d4", "html_url": "https://github.com/jqlang/jq/commit/f2ad9517c72f6267ae317639ab56bbfd4a8653d4" } ] } - text: | For the rest of the examples, I'll leave out the `curl` command - it's not going to change. There's 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}'" result: | { "message": "docs: Document repeat(exp)", "name": "Nico Williams" } - 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`. Now let's get the rest of the commits. - command: "jq '.[] | {message: .commit.message, name: .commit.committer.name}'" result: | { "message": "docs: Document repeat(exp)", "name": "Nico Williams" } { "message": "Mention -n in IO-section and for input/inputs", "name": "Nico Williams" } { "message": "Fix iteration problem for non decimal string\n\nWhen the string transformation to number failed, all following\ntransformation failed too.\n\nThis happend because status in decNumberFromString function is\nupdated just in error case. Reusing the DEC_CONTEXT that failed\nbefore results into error even if the string is valid number.", "name": "Nico Williams" } { "message": "docs: point to Libera.Chat instead of Freenode", "name": "Nico Williams" } { "message": "Missing \"va_end\" call. This was found by running the cppcheck static analysis where it shows as error.", "name": "Nico Williams" } - 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}`. Data in jq is represented as streams of JSON values - every jq expression runs for each value in its input stream, and can produce any number of values to its output stream. 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}]'" result: | [ { "message": "docs: Document repeat(exp)", "name": "Nico Williams" }, { "message": "Mention -n in IO-section and for input/inputs", "name": "Nico Williams" }, { "message": "Fix iteration problem for non decimal string\n\nWhen the string transformation to number failed, all following\ntransformation failed too.\n\nThis happend because status in decNumberFromString function is\nupdated just in error case. Reusing the DEC_CONTEXT that failed\nbefore results into error even if the string is valid number.", "name": "Nico Williams" }, { "message": "docs: point to Libera.Chat instead of Freenode", "name": "Nico Williams" }, { "message": "Missing \"va_end\" call. This was found by running the cppcheck static analysis where it shows as error.", "name": "Nico Williams" } ] - text: | - - - Next, let's try getting the URLs of the parent 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. "parents": [ { "sha": "f2ad9517c72f6267ae317639ab56bbfd4a8653d4", "url": "https://api.github.com/repos/jqlang/jq/commits/f2ad9517c72f6267ae317639ab56bbfd4a8653d4", "html_url": "https://github.com/jqlang/jq/commit/f2ad9517c72f6267ae317639ab56bbfd4a8653d4" } ] 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]}]'" result: | [ { "message": "docs: Document repeat(exp)", "name": "Nico Williams", "parents": [ "https://github.com/jqlang/jq/commit/f2ad9517c72f6267ae317639ab56bbfd4a8653d4" ] }, { "message": "Mention -n in IO-section and for input/inputs", "name": "Nico Williams", "parents": [ "https://github.com/jqlang/jq/commit/c4d39c4d22f2b12225ca1b311708f7e084ad9ff8" ] }, { "message": "Fix iteration problem for non decimal string\n\nWhen the string transformation to number failed, all following\ntransformation failed too.\n\nThis happend because status in decNumberFromString function is\nupdated just in error case. Reusing the DEC_CONTEXT that failed\nbefore results into error even if the string is valid number.", "name": "Nico Williams", "parents": [ "https://github.com/jqlang/jq/commit/174db0f93552bdb551ae1f3c5c64744df0ad8e2f" ] }, { "message": "docs: point to Libera.Chat instead of Freenode", "name": "Nico Williams", "parents": [ "https://github.com/jqlang/jq/commit/29cf77977ef52eec708982b19bf9d2ec17443337" ] }, { "message": "Missing \"va_end\" call. This was found by running the cppcheck static analysis where it shows as error.", "name": "Nico Williams", "parents": [ "https://github.com/jqlang/jq/commit/55e6e2c21829bd866bd4b18ee254b05c9020320a" ] } ] - 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. - text: | - - - 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. ================================================ FILE: docs/manual_schema.yml ================================================ type: object required: - headline - body - manpage_intro - manpage_epilogue - sections additionalProperties: false properties: headline: type: string body: type: string manpage_intro: type: string manpage_epilogue: type: string sections: type: array items: type: object required: - title additionalProperties: false properties: title: type: string body: type: string entries: type: array items: type: object required: - title - body additionalProperties: false properties: title: type: string body: type: string examples: type: array items: type: object required: - program - input - output additionalProperties: false properties: program: type: string input: type: string output: type: array items: type: string ================================================ FILE: docs/public/.htaccess ================================================ DirectoryIndex index.html FileETag All # Compress all static assets # compress content with type html, text, and css AddOutputFilterByType DEFLATE text/css text/html text/javascript application/javascript application/x-javascript text/js text/plain text/xml # properly handle requests coming from behind proxies Header append Vary User-Agent # Cache, aggressively ExpiresActive On ExpiresDefault "access plus 10 days" ExpiresDefault "access plus 10 years" # Mime-types AddType application/vnd.ms-fontobject .eot AddType font/ttf .ttf AddType font/otf .otf ================================================ FILE: docs/public/CNAME ================================================ jqlang.org ================================================ FILE: docs/public/css/style.css ================================================ main { padding: 1rem; & * { scroll-margin-top: 4rem; } @media print { width: 100%!important; --bs-code-color: --bs-body-color; } } header { z-index: 1050!important; /* higher than #contents */ } section[id] { display: flow-root; > :first-child { .icon-link { opacity: 0; &:focus { opacity: .8; } } &:hover .icon-link { opacity: 1; } } } .offcanvas[aria-modal=true] .nav-link { padding: .7rem; } .offcanvas-md { --bs-offcanvas-width: auto; } ul { list-style: none; padding-left: 1rem; } pre { margin: 0 .5rem 1rem; padding: .5rem 1rem; background-color: var(--bs-secondary-bg-subtle); border: var(--bs-border-width) var(--bs-border-style) var(--bs-border-color); } button { &[aria-expanded=false] { .bi-chevron-down, .hide-result-text { display: none; } } &[aria-expanded=true] { .bi-chevron-right, .show-result-text { display: none; } } } mark { padding: 0; } .container-searchbox { position: relative; & input:focus ~ kbd { display: none; } & ul { position: absolute; width: 100%; top: 100%; padding: 0; background-color: var(--bs-body-bg); border: var(--bs-border-width) var(--bs-border-style) var(--bs-border-color); } & li { padding: .3em .6em; white-space: nowrap; overflow-x: hidden; &[aria-selected=true] { background-color: var(--bs-secondary-bg); } &:hover { cursor: pointer; background-color: var(--bs-secondary-bg-subtle); } } } ================================================ FILE: docs/public/js/manual-search.js ================================================ (() => { const searchInput = document.querySelector('input#searchbox'); const sectionIDs = JSON.parse(document.querySelector('#section-ids').innerText); const sanitize = (string) => string.replaceAll('<', '<').replaceAll('>', '>'); new autoComplete({ selector: `#${searchInput.id}`, wrapper: false, data: { src: Object.keys(sectionIDs), filter: (list) => list.sort((x, y) => x.match.indexOf('<') - y.match.indexOf('<') || x.value.length - y.value.length), }, searchEngine: (query, value) => { const index = value.toLowerCase().indexOf(query.toLowerCase()); if (index >= 0) { return sanitize(value.substring(0, index)) + `${sanitize(value.substring(index, index + query.length))}` + sanitize(value.substring(index + query.length)); } }, }); searchInput.addEventListener('selection', (event) => { event.target.value = event.detail.selection.value; location.hash = `#${sectionIDs[event.detail.selection.value]}`; }); document.addEventListener('keydown', (event) => { if (event.code === 'Slash' && !event.altKey && !event.ctrlKey && !event.metaKey && !event.shiftKey && !/^(INPUT|TEXTAREA)$/.test(event.target.nodeName)) { searchInput.focus(); searchInput.select(); event.preventDefault(); } }); })(); ================================================ FILE: docs/public/robots.txt ================================================ User-agent: * Allow: / ================================================ FILE: docs/templates/default.html.j2 ================================================ {% include "shared/_head.html.j2" %} {% include "shared/_navbar.html.j2" %}

{{ headline }}

{%- for item in body %} {%- if item.text %} {{ item.text | markdownify }} {%- endif %} {%- if item.command %} {%- set resultID = unique_id() %}
{{ item.command }}
{{ item.result }}
{%- endif %} {%- endfor %}
{% include "shared/_footer.html.j2" %} ================================================ FILE: docs/templates/index.html.j2 ================================================ {% include "shared/_head.html.j2" %} {% include "shared/_navbar.html.j2" %}
{{ body1 | markdownify }}
{{ body2 | markdownify }}
{{ body3 | markdownify }}
{{ tail | markdownify }}

News

    {%- for item in news %}
  • {{ item.date }} {{ item.body | markdownify }}
  • {%- endfor %}
{% include "shared/_footer.html.j2" %} ================================================ FILE: docs/templates/manual.html.j2 ================================================ {% include "shared/_head.html.j2" %} {% include "shared/_navbar.html.j2" %}
{%- set section_ids = {} %} {%- macro check_section_id(id) -%} {%- if section_ids.__contains__(id) %} {{- raise('Duplicate section id: ' ~ id) }} {%- endif %} {%- set _ = section_ids.__setitem__(id, true) %} {%- endmacro %}

{{ headline }}

For other versions, see 1.8, 1.7, 1.6, 1.5, 1.4, 1.3 or development version.

{{ body | markdownify }} {%- for section in sections %}
{{ check_section_id(section.title | section_id) }}

{{ section.title }}

{{ section.body | markdownify if section.body }} {%- for entry in section.entries %}
{{ check_section_id(entry.title | entry_id) }}

{{ entry.title | markdownify | no_paragraph }}

{{ entry.body | markdownify }} {%- if entry.examples %}
{%- set exampleID = unique_id() %}
{%- for example in entry.examples %} {%- if not example.output[0] %} {%- endif %} {%- for output in example.output %} {%- endfor %}
Command jq '{{ example.program }}'
Input {{ example.input }}
Output none
{% if loop.first %}Output{% endif %} {{ output }}
Run
{%- endfor %}
{%- endif %}
{%- endfor %}
{%- endfor %}
{% include "shared/_footer.html.j2" %} ================================================ FILE: docs/templates/shared/_footer.html.j2 ================================================

This website is made with Bootstrap, themed with Bootswatch.

jq is licensed under the MIT license (code) and the CC-BY-3.0 license (docs).

================================================ FILE: docs/templates/shared/_head.html.j2 ================================================ {{ headline }} ================================================ FILE: docs/templates/shared/_navbar.html.j2 ================================================
Skip to main content {%- if navitem.startswith('manual') %} Skip to table of contents {%- endif %}
================================================ FILE: docs/validate_manual_schema.py ================================================ #!/usr/bin/env python3 import jsonschema import sys import yaml if len(sys.argv) < 2: sys.exit("Usage: {} MANUAL_FILE ...".format(sys.argv[0])) with open("manual_schema.yml", "r") as schema_file: manual_schema = yaml.safe_load(schema_file) for path in sys.argv[1:]: with open(path, "r") as manual_file: manual_data = yaml.safe_load(manual_file) try: jsonschema.validate(instance=manual_data, schema=manual_schema) except jsonschema.exceptions.ValidationError as e: print("Failed to validate:", path, file=sys.stderr) sys.exit(e) ================================================ FILE: jq.1.prebuilt ================================================ . .TH "JQ" "1" "May 2025" "" "" . .SH "NAME" \fBjq\fR \- Command\-line JSON processor . .SH "SYNOPSIS" \fBjq\fR [\fIoptions\fR\.\.\.] \fIfilter\fR [\fIfiles\fR\.\.\.] . .P \fBjq\fR can transform JSON in various ways, by selecting, iterating, reducing and otherwise mangling JSON documents\. For instance, running the command \fBjq \'map(\.price) | add\'\fR will take an array of JSON objects as input and return the sum of their "price" fields\. . .P \fBjq\fR can accept text input as well, but by default, \fBjq\fR reads a stream of JSON entities (including numbers and other literals) from \fBstdin\fR\. Whitespace is only needed to separate entities such as 1 and 2, and true and false\. One or more \fIfiles\fR may be specified, in which case \fBjq\fR will read input from those instead\. . .P The \fIoptions\fR are described in the [INVOKING JQ] section; they mostly concern input and output formatting\. The \fIfilter\fR is written in the jq language and specifies how to transform the input file or document\. . .SH "FILTERS" A jq program is a "filter": it takes an input, and produces an output\. There are a lot of builtin filters for extracting a particular field of an object, or converting a number to a string, or various other standard tasks\. . .P Filters can be combined in various ways \- you can pipe the output of one filter into another filter, or collect the output of a filter into an array\. . .P Some filters produce multiple results, for instance there\'s one that produces all the elements of its input array\. Piping that filter into a second runs the second filter for each element of the array\. Generally, things that would be done with loops and iteration in other languages are just done by gluing filters together in jq\. . .P It\'s important to remember that every filter has an input and an output\. Even literals like "hello" or 42 are filters \- they take an input but always produce the same literal as output\. Operations that combine two filters, like addition, generally feed the same input to both and combine the results\. So, you can implement an averaging filter as \fBadd / length\fR \- feeding the input array both to the \fBadd\fR filter and the \fBlength\fR filter and then performing the division\. . .P But that\'s getting ahead of ourselves\. :) Let\'s start with something simpler: . .SH "INVOKING JQ" jq filters run on a stream of JSON data\. The input to jq is parsed as a sequence of whitespace\-separated JSON values which are passed through the provided filter one at a time\. The output(s) of the filter are written to standard output, as a sequence of newline\-separated JSON data\. . .P The simplest and most common filter (or jq program) is \fB\.\fR, which is the identity operator, copying the inputs of the jq processor to the output stream\. Because the default behavior of the jq processor is to read JSON texts from the input stream, and to pretty\-print outputs, the \fB\.\fR program\'s main use is to validate and pretty\-print the inputs\. The jq programming language is quite rich and allows for much more than just validation and pretty\-printing\. . .P Note: it is important to mind the shell\'s quoting rules\. As a general rule it\'s best to always quote (with single\-quote characters on Unix shells) the jq program, as too many characters with special meaning to jq are also shell meta\-characters\. For example, \fBjq "foo"\fR will fail on most Unix shells because that will be the same as \fBjq foo\fR, which will generally fail because \fBfoo is not defined\fR\. When using the Windows command shell (cmd\.exe) it\'s best to use double quotes around your jq program when given on the command\-line (instead of the \fB\-f program\-file\fR option), but then double\-quotes in the jq program need backslash escaping\. When using the Powershell (\fBpowershell\.exe\fR) or the Powershell Core (\fBpwsh\fR/\fBpwsh\.exe\fR), use single\-quote characters around the jq program and backslash\-escaped double\-quotes (\fB\e"\fR) inside the jq program\. . .IP "\(bu" 4 Unix shells: \fBjq \'\.["foo"]\'\fR . .IP "\(bu" 4 Powershell: \fBjq \'\.[\e"foo\e"]\'\fR . .IP "\(bu" 4 Windows command shell: \fBjq "\.[\e"foo\e"]"\fR . .IP "" 0 . .P Note: jq allows user\-defined functions, but every jq program must have a top\-level expression\. . .P You can affect how jq reads and writes its input and output using some command\-line options: . .TP \fB\-\-null\-input\fR / \fB\-n\fR: . .IP Don\'t read any input at all\. Instead, the filter is run once using \fBnull\fR as the input\. This is useful when using jq as a simple calculator or to construct JSON data from scratch\. . .TP \fB\-\-raw\-input\fR / \fB\-R\fR: . .IP Don\'t parse the input as JSON\. Instead, each line of text is passed to the filter as a string\. If combined with \fB\-\-slurp\fR, then the entire input is passed to the filter as a single long string\. . .TP \fB\-\-slurp\fR / \fB\-s\fR: . .IP Instead of running the filter for each JSON object in the input, read the entire input stream into a large array and run the filter just once\. . .TP \fB\-\-compact\-output\fR / \fB\-c\fR: . .IP By default, jq pretty\-prints JSON output\. Using this option will result in more compact output by instead putting each JSON object on a single line\. . .TP \fB\-\-raw\-output\fR / \fB\-r\fR: . .IP With this option, if the filter\'s result is a string then it will be written directly to standard output rather than being formatted as a JSON string with quotes\. This can be useful for making jq filters talk to non\-JSON\-based systems\. . .TP \fB\-\-raw\-output0\fR: . .IP Like \fB\-r\fR but jq will print NUL instead of newline after each output\. This can be useful when the values being output can contain newlines\. When the output value contains NUL, jq exits with non\-zero code\. . .TP \fB\-\-join\-output\fR / \fB\-j\fR: . .IP Like \fB\-r\fR but jq won\'t print a newline after each output\. . .TP \fB\-\-ascii\-output\fR / \fB\-a\fR: . .IP jq usually outputs non\-ASCII Unicode codepoints as UTF\-8, even if the input specified them as escape sequences (like "\eu03bc")\. Using this option, you can force jq to produce pure ASCII output with every non\-ASCII character replaced with the equivalent escape sequence\. . .TP \fB\-\-sort\-keys\fR / \fB\-S\fR: . .IP Output the fields of each object with the keys in sorted order\. . .TP \fB\-\-color\-output\fR / \fB\-C\fR and \fB\-\-monochrome\-output\fR / \fB\-M\fR: . .IP By default, jq outputs colored JSON if writing to a terminal\. You can force it to produce color even if writing to a pipe or a file using \fB\-C\fR, and disable color with \fB\-M\fR\. When the \fBNO_COLOR\fR environment variable is not empty, jq disables colored output by default, but you can enable it by \fB\-C\fR\. . .IP Colors can be configured with the \fBJQ_COLORS\fR environment variable (see below)\. . .TP \fB\-\-tab\fR: . .IP Use a tab for each indentation level instead of two spaces\. . .TP \fB\-\-indent n\fR: . .IP Use the given number of spaces (no more than 7) for indentation\. . .TP \fB\-\-unbuffered\fR: . .IP Flush the output after each JSON object is printed (useful if you\'re piping a slow data source into jq and piping jq\'s output elsewhere)\. . .TP \fB\-\-stream\fR: . .IP Parse the input in streaming fashion, outputting arrays of path and leaf values (scalars and empty arrays or empty objects)\. For example, \fB"a"\fR becomes \fB[[],"a"]\fR, and \fB[[],"a",["b"]]\fR becomes \fB[[0],[]]\fR, \fB[[1],"a"]\fR, and \fB[[2,0],"b"]\fR\. . .IP This is useful for processing very large inputs\. Use this in conjunction with filtering and the \fBreduce\fR and \fBforeach\fR syntax to reduce large inputs incrementally\. . .TP \fB\-\-stream\-errors\fR: . .IP Like \fB\-\-stream\fR, but invalid JSON inputs yield array values where the first element is the error and the second is a path\. For example, \fB["a",n]\fR produces \fB["Invalid literal at line 1, column 7",[1]]\fR\. . .IP Implies \fB\-\-stream\fR\. Invalid JSON inputs produce no error values when \fB\-\-stream\fR without \fB\-\-stream\-errors\fR\. . .TP \fB\-\-seq\fR: . .IP Use the \fBapplication/json\-seq\fR MIME type scheme for separating JSON texts in jq\'s input and output\. This means that an ASCII RS (record separator) character is printed before each value on output and an ASCII LF (line feed) is printed after every output\. Input JSON texts that fail to parse are ignored (but warned about), discarding all subsequent input until the next RS\. This mode also parses the output of jq without the \fB\-\-seq\fR option\. . .TP \fB\-f\fR / \fB\-\-from\-file\fR: . .IP Read the filter from a file rather than from a command line, like awk\'s \-f option\. This changes the filter argument to be interpreted as a filename, instead of the source of a program\. . .TP \fB\-L directory\fR / \fB\-\-library\-path directory\fR: . .IP Prepend \fBdirectory\fR to the search list for modules\. If this option is used then no builtin search list is used\. See the section on modules below\. . .TP \fB\-\-arg name value\fR: . .IP This option passes a value to the jq program as a predefined variable\. If you run jq with \fB\-\-arg foo bar\fR, then \fB$foo\fR is available in the program and has the value \fB"bar"\fR\. Note that \fBvalue\fR will be treated as a string, so \fB\-\-arg foo 123\fR will bind \fB$foo\fR to \fB"123"\fR\. . .IP Named arguments are also available to the jq program as \fB$ARGS\.named\fR\. When the name is not a valid identifier, this is the only way to access it\. . .TP \fB\-\-argjson name JSON\-text\fR: . .IP This option passes a JSON\-encoded value to the jq program as a predefined variable\. If you run jq with \fB\-\-argjson foo 123\fR, then \fB$foo\fR is available in the program and has the value \fB123\fR\. . .TP \fB\-\-slurpfile variable\-name filename\fR: . .IP This option reads all the JSON texts in the named file and binds an array of the parsed JSON values to the given global variable\. If you run jq with \fB\-\-slurpfile foo bar\fR, then \fB$foo\fR is available in the program and has an array whose elements correspond to the texts in the file named \fBbar\fR\. . .TP \fB\-\-rawfile variable\-name filename\fR: . .IP This option reads in the named file and binds its content to the given global variable\. If you run jq with \fB\-\-rawfile foo bar\fR, then \fB$foo\fR is available in the program and has a string whose content is set to the text in the file named \fBbar\fR\. . .TP \fB\-\-args\fR: . .IP Remaining arguments are positional string arguments\. These are available to the jq program as \fB$ARGS\.positional[]\fR\. . .TP \fB\-\-jsonargs\fR: . .IP Remaining arguments are positional JSON text arguments\. These are available to the jq program as \fB$ARGS\.positional[]\fR\. . .TP \fB\-\-exit\-status\fR / \fB\-e\fR: . .IP Sets the exit status of jq to 0 if the last output value was neither \fBfalse\fR nor \fBnull\fR, 1 if the last output value was either \fBfalse\fR or \fBnull\fR, or 4 if no valid result was ever produced\. Normally jq exits with 2 if there was any usage problem or system error, 3 if there was a jq program compile error, or 0 if the jq program ran\. . .IP Another way to set the exit status is with the \fBhalt_error\fR builtin function\. . .TP \fB\-\-binary\fR / \fB\-b\fR: . .IP Windows users using WSL, MSYS2, or Cygwin, should use this option when using a native jq\.exe, otherwise jq will turn newlines (LFs) into carriage\-return\-then\-newline (CRLF)\. . .TP \fB\-\-version\fR / \fB\-V\fR: . .IP Output the jq version and exit with zero\. . .TP \fB\-\-build\-configuration\fR: . .IP Output the build configuration of jq and exit with zero\. This output has no supported format or structure and may change without notice in future releases\. . .TP \fB\-\-help\fR / \fB\-h\fR: . .IP Output the jq help and exit with zero\. . .TP \fB\-\-\fR: . .IP Terminates argument processing\. Remaining arguments are not interpreted as options\. . .TP \fB\-\-run\-tests [filename]\fR: . .IP Runs the tests in the given file or standard input\. This must be the last option given and does not honor all preceding options\. The input consists of comment lines, empty lines, and program lines followed by one input line, as many lines of output as are expected (one per output), and a terminating empty line\. Compilation failure tests start with a line containing only \fB%%FAIL\fR, then a line containing the program to compile, then a line containing an error message to compare to the actual\. . .IP Be warned that this option can change backwards\-incompatibly\. . .SH "BASIC FILTERS" . .SS "Identity: \." The absolute simplest filter is \fB\.\fR \. This filter takes its input and produces the same value as output\. That is, this is the identity operator\. . .P Since jq by default pretty\-prints all output, a trivial program consisting of nothing but \fB\.\fR can be used to format JSON output from, say, \fBcurl\fR\. . .P Although the identity filter never modifies the value of its input, jq processing can sometimes make it appear as though it does\. For example, using the current implementation of jq, we would see that the expression: . .IP "" 4 . .nf 1E1234567890 | \. . .fi . .IP "" 0 . .P produces \fB1\.7976931348623157e+308\fR on at least one platform\. This is because, in the process of parsing the number, this particular version of jq has converted it to an IEEE754 double\-precision representation, losing precision\. . .P The way in which jq handles numbers has changed over time and further changes are likely within the parameters set by the relevant JSON standards\. Moreover, build configuration options can alter how jq processes numbers\. . .P The following remarks are therefore offered with the understanding that they are intended to be descriptive of the current version of jq and should not be interpreted as being prescriptive: . .P (1) Any arithmetic operation on a number that has not already been converted to an IEEE754 double precision representation will trigger a conversion to the IEEE754 representation\. . .P (2) jq will attempt to maintain the original decimal precision of number literals (if the \fB\-\-disable\-decnum\fR build configuration option was not used), but in expressions such \fB1E1234567890\fR, precision will be lost if the exponent is too large\. . .P (3) Comparisons are carried out using the untruncated big decimal representation of numbers if available, as illustrated in one of the following examples\. . .P The examples below use the builtin function \fBhave_decnum\fR in order to demonstrate the expected effects of using / not using the \fB\-\-disable\-decnum\fR build configuration option, and also to allow automated tests derived from these examples to pass regardless of whether that option is used\. . .IP "" 4 . .nf jq \'\.\' "Hello, world!" => "Hello, world!" jq \'\.\' 0\.12345678901234567890123456789 => 0\.12345678901234567890123456789 jq \'[\., tojson] == if have_decnum then [12345678909876543212345,"12345678909876543212345"] else [12345678909876543000000,"12345678909876543000000"] end\' 12345678909876543212345 => true jq \'[1234567890987654321,\-1234567890987654321 | tojson] == if have_decnum then ["1234567890987654321","\-1234567890987654321"] else ["1234567890987654400","\-1234567890987654400"] end\' null => true jq \'\. < 0\.12345678901234567890123456788\' 0\.12345678901234567890123456789 => false jq \'map([\., \. == 1]) | tojson == if have_decnum then "[[1,true],[1\.000,true],[1\.0,true],[1\.00,true]]" else "[[1,true],[1,true],[1,true],[1,true]]" end\' [1, 1\.000, 1\.0, 100e\-2] => true jq \'\. as $big | [$big, $big + 1] | map(\. > 10000000000000000000000000000000) | \. == if have_decnum then [true, false] else [false, false] end\' 10000000000000000000000000000001 => true . .fi . .IP "" 0 . .SS "Object Identifier\-Index: \.foo, \.foo\.bar" The simplest \fIuseful\fR filter has the form \fB\.foo\fR\. When given a JSON object (aka dictionary or hash) as input, \fB\.foo\fR produces the value at the key "foo" if the key is present, or null otherwise\. . .P A filter of the form \fB\.foo\.bar\fR is equivalent to \fB\.foo | \.bar\fR\. . .P The \fB\.foo\fR syntax only works for simple, identifier\-like keys, that is, keys that are all made of alphanumeric characters and underscore, and which do not start with a digit\. . .P If the key contains special characters or starts with a digit, you need to surround it with double quotes like this: \fB\."foo$"\fR, or else \fB\.["foo$"]\fR\. . .P For example \fB\.["foo::bar"]\fR and \fB\.["foo\.bar"]\fR work while \fB\.foo::bar\fR does not\. . .IP "" 4 . .nf jq \'\.foo\' {"foo": 42, "bar": "less interesting data"} => 42 jq \'\.foo\' {"notfoo": true, "alsonotfoo": false} => null jq \'\.["foo"]\' {"foo": 42} => 42 . .fi . .IP "" 0 . .SS "Optional Object Identifier\-Index: \.foo?" Just like \fB\.foo\fR, but does not output an error when \fB\.\fR is not an object\. . .IP "" 4 . .nf jq \'\.foo?\' {"foo": 42, "bar": "less interesting data"} => 42 jq \'\.foo?\' {"notfoo": true, "alsonotfoo": false} => null jq \'\.["foo"]?\' {"foo": 42} => 42 jq \'[\.foo?]\' [1,2] => [] . .fi . .IP "" 0 . .SS "Object Index: \.[]" You can also look up fields of an object using syntax like \fB\.["foo"]\fR (\fB\.foo\fR above is a shorthand version of this, but only for identifier\-like strings)\. . .SS "Array Index: \.[]" When the index value is an integer, \fB\.[]\fR can index arrays\. Arrays are zero\-based, so \fB\.[2]\fR returns the third element\. . .P Negative indices are allowed, with \-1 referring to the last element, \-2 referring to the next to last element, and so on\. . .IP "" 4 . .nf jq \'\.[0]\' [{"name":"JSON", "good":true}, {"name":"XML", "good":false}] => {"name":"JSON", "good":true} jq \'\.[2]\' [{"name":"JSON", "good":true}, {"name":"XML", "good":false}] => null jq \'\.[\-2]\' [1,2,3] => 2 . .fi . .IP "" 0 . .SS "Array/String Slice: \.[:]" The \fB\.[:]\fR syntax can be used to return a subarray of an array or substring of a string\. The array returned by \fB\.[10:15]\fR will be of length 5, containing the elements from index 10 (inclusive) to index 15 (exclusive)\. Either index may be negative (in which case it counts backwards from the end of the array), or omitted (in which case it refers to the start or end of the array)\. Indices are zero\-based\. . .IP "" 4 . .nf jq \'\.[2:4]\' ["a","b","c","d","e"] => ["c", "d"] jq \'\.[2:4]\' "abcdefghi" => "cd" jq \'\.[:3]\' ["a","b","c","d","e"] => ["a", "b", "c"] jq \'\.[\-2:]\' ["a","b","c","d","e"] => ["d", "e"] . .fi . .IP "" 0 . .SS "Array/Object Value Iterator: \.[]" If you use the \fB\.[index]\fR syntax, but omit the index entirely, it will return \fIall\fR of the elements of an array\. Running \fB\.[]\fR with the input \fB[1,2,3]\fR will produce the numbers as three separate results, rather than as a single array\. A filter of the form \fB\.foo[]\fR is equivalent to \fB\.foo | \.[]\fR\. . .P You can also use this on an object, and it will return all the values of the object\. . .P Note that the iterator operator is a generator of values\. . .IP "" 4 . .nf jq \'\.[]\' [{"name":"JSON", "good":true}, {"name":"XML", "good":false}] => {"name":"JSON", "good":true}, {"name":"XML", "good":false} jq \'\.[]\' [] => jq \'\.foo[]\' {"foo":[1,2,3]} => 1, 2, 3 jq \'\.[]\' {"a": 1, "b": 1} => 1, 1 . .fi . .IP "" 0 . .SS "\.[]?" Like \fB\.[]\fR, but no errors will be output if \. is not an array or object\. A filter of the form \fB\.foo[]?\fR is equivalent to \fB\.foo | \.[]?\fR\. . .SS "Comma: ," If two filters are separated by a comma, then the same input will be fed into both and the two filters\' output value streams will be concatenated in order: first, all of the outputs produced by the left expression, and then all of the outputs produced by the right\. For instance, filter \fB\.foo, \.bar\fR, produces both the "foo" fields and "bar" fields as separate outputs\. . .P The \fB,\fR operator is one way to construct generators\. . .IP "" 4 . .nf jq \'\.foo, \.bar\' {"foo": 42, "bar": "something else", "baz": true} => 42, "something else" jq \'\.user, \.projects[]\' {"user":"stedolan", "projects": ["jq", "wikiflow"]} => "stedolan", "jq", "wikiflow" jq \'\.[4,2]\' ["a","b","c","d","e"] => "e", "c" . .fi . .IP "" 0 . .SS "Pipe: |" The | operator combines two filters by feeding the output(s) of the one on the left into the input of the one on the right\. It\'s similar to the Unix shell\'s pipe, if you\'re used to that\. . .P If the one on the left produces multiple results, the one on the right will be run for each of those results\. So, the expression \fB\.[] | \.foo\fR retrieves the "foo" field of each element of the input array\. This is a cartesian product, which can be surprising\. . .P Note that \fB\.a\.b\.c\fR is the same as \fB\.a | \.b | \.c\fR\. . .P Note too that \fB\.\fR is the input value at the particular stage in a "pipeline", specifically: where the \fB\.\fR expression appears\. Thus \fB\.a | \. | \.b\fR is the same as \fB\.a\.b\fR, as the \fB\.\fR in the middle refers to whatever value \fB\.a\fR produced\. . .IP "" 4 . .nf jq \'\.[] | \.name\' [{"name":"JSON", "good":true}, {"name":"XML", "good":false}] => "JSON", "XML" . .fi . .IP "" 0 . .SS "Parenthesis" Parenthesis work as a grouping operator just as in any typical programming language\. . .IP "" 4 . .nf jq \'(\. + 2) * 5\' 1 => 15 . .fi . .IP "" 0 . .SH "TYPES AND VALUES" jq supports the same set of datatypes as JSON \- numbers, strings, booleans, arrays, objects (which in JSON\-speak are hashes with only string keys), and "null"\. . .P Booleans, null, strings and numbers are written the same way as in JSON\. Just like everything else in jq, these simple values take an input and produce an output \- \fB42\fR is a valid jq expression that takes an input, ignores it, and returns 42 instead\. . .P Numbers in jq are internally represented by their IEEE754 double precision approximation\. Any arithmetic operation with numbers, whether they are literals or results of previous filters, will produce a double precision floating point result\. . .P However, when parsing a literal jq will store the original literal string\. If no mutation is applied to this value then it will make to the output in its original form, even if conversion to double would result in a loss\. . .SS "Array construction: []" As in JSON, \fB[]\fR is used to construct arrays, as in \fB[1,2,3]\fR\. The elements of the arrays can be any jq expression, including a pipeline\. All of the results produced by all of the expressions are collected into one big array\. You can use it to construct an array out of a known quantity of values (as in \fB[\.foo, \.bar, \.baz]\fR) or to "collect" all the results of a filter into an array (as in \fB[\.items[]\.name]\fR) . .P Once you understand the "," operator, you can look at jq\'s array syntax in a different light: the expression \fB[1,2,3]\fR is not using a built\-in syntax for comma\-separated arrays, but is instead applying the \fB[]\fR operator (collect results) to the expression 1,2,3 (which produces three different results)\. . .P If you have a filter \fBX\fR that produces four results, then the expression \fB[X]\fR will produce a single result, an array of four elements\. . .IP "" 4 . .nf jq \'[\.user, \.projects[]]\' {"user":"stedolan", "projects": ["jq", "wikiflow"]} => ["stedolan", "jq", "wikiflow"] jq \'[ \.[] | \. * 2]\' [1, 2, 3] => [2, 4, 6] . .fi . .IP "" 0 . .SS "Object Construction: {}" Like JSON, \fB{}\fR is for constructing objects (aka dictionaries or hashes), as in: \fB{"a": 42, "b": 17}\fR\. . .P If the keys are "identifier\-like", then the quotes can be left off, as in \fB{a:42, b:17}\fR\. Variable references as key expressions use the value of the variable as the key\. Key expressions other than constant literals, identifiers, or variable references, need to be parenthesized, e\.g\., \fB{("a"+"b"):59}\fR\. . .P The value can be any expression (although you may need to wrap it in parentheses if, for example, it contains colons), which gets applied to the {} expression\'s input (remember, all filters have an input and an output)\. . .IP "" 4 . .nf {foo: \.bar} . .fi . .IP "" 0 . .P will produce the JSON object \fB{"foo": 42}\fR if given the JSON object \fB{"bar":42, "baz":43}\fR as its input\. You can use this to select particular fields of an object: if the input is an object with "user", "title", "id", and "content" fields and you just want "user" and "title", you can write . .IP "" 4 . .nf {user: \.user, title: \.title} . .fi . .IP "" 0 . .P Because that is so common, there\'s a shortcut syntax for it: \fB{user, title}\fR\. . .P If one of the expressions produces multiple results, multiple dictionaries will be produced\. If the input\'s . .IP "" 4 . .nf {"user":"stedolan","titles":["JQ Primer", "More JQ"]} . .fi . .IP "" 0 . .P then the expression . .IP "" 4 . .nf {user, title: \.titles[]} . .fi . .IP "" 0 . .P will produce two outputs: . .IP "" 4 . .nf {"user":"stedolan", "title": "JQ Primer"} {"user":"stedolan", "title": "More JQ"} . .fi . .IP "" 0 . .P Putting parentheses around the key means it will be evaluated as an expression\. With the same input as above, . .IP "" 4 . .nf {(\.user): \.titles} . .fi . .IP "" 0 . .P produces . .IP "" 4 . .nf {"stedolan": ["JQ Primer", "More JQ"]} . .fi . .IP "" 0 . .P Variable references as keys use the value of the variable as the key\. Without a value then the variable\'s name becomes the key and its value becomes the value, . .IP "" 4 . .nf "f o o" as $foo | "b a r" as $bar | {$foo, $bar:$foo} . .fi . .IP "" 0 . .P produces . .IP "" 4 . .nf {"foo":"f o o","b a r":"f o o"} jq \'{user, title: \.titles[]}\' {"user":"stedolan","titles":["JQ Primer", "More JQ"]} => {"user":"stedolan", "title": "JQ Primer"}, {"user":"stedolan", "title": "More JQ"} jq \'{(\.user): \.titles}\' {"user":"stedolan","titles":["JQ Primer", "More JQ"]} => {"stedolan": ["JQ Primer", "More JQ"]} . .fi . .IP "" 0 . .SS "Recursive Descent: \.\." Recursively descends \fB\.\fR, producing every value\. This is the same as the zero\-argument \fBrecurse\fR builtin (see below)\. This is intended to resemble the XPath \fB//\fR operator\. Note that \fB\.\.a\fR does not work; use \fB\.\. | \.a\fR instead\. In the example below we use \fB\.\. | \.a?\fR to find all the values of object keys "a" in any object found "below" \fB\.\fR\. . .P This is particularly useful in conjunction with \fBpath(EXP)\fR (also see below) and the \fB?\fR operator\. . .IP "" 4 . .nf jq \'\.\. | \.a?\' [[{"a":1}]] => 1 . .fi . .IP "" 0 . .SH "BUILTIN OPERATORS AND FUNCTIONS" Some jq operators (for instance, \fB+\fR) do different things depending on the type of their arguments (arrays, numbers, etc\.)\. However, jq never does implicit type conversions\. If you try to add a string to an object you\'ll get an error message and no result\. . .P Please note that all numbers are converted to IEEE754 double precision floating point representation\. Arithmetic and logical operators are working with these converted doubles\. Results of all such operations are also limited to the double precision\. . .P The only exception to this behaviour of number is a snapshot of original number literal\. When a number which originally was provided as a literal is never mutated until the end of the program then it is printed to the output in its original literal form\. This also includes cases when the original literal would be truncated when converted to the IEEE754 double precision floating point number\. . .SS "Addition: +" The operator \fB+\fR takes two filters, applies them both to the same input, and adds the results together\. What "adding" means depends on the types involved: . .IP "\(bu" 4 \fBNumbers\fR are added by normal arithmetic\. . .IP "\(bu" 4 \fBArrays\fR are added by being concatenated into a larger array\. . .IP "\(bu" 4 \fBStrings\fR are added by being joined into a larger string\. . .IP "\(bu" 4 \fBObjects\fR are added by merging, that is, inserting all the key\-value pairs from both objects into a single combined object\. If both objects contain a value for the same key, the object on the right of the \fB+\fR wins\. (For recursive merge use the \fB*\fR operator\.) . .IP "" 0 . .P \fBnull\fR can be added to any value, and returns the other value unchanged\. . .IP "" 4 . .nf jq \'\.a + 1\' {"a": 7} => 8 jq \'\.a + \.b\' {"a": [1,2], "b": [3,4]} => [1,2,3,4] jq \'\.a + null\' {"a": 1} => 1 jq \'\.a + 1\' {} => 1 jq \'{a: 1} + {b: 2} + {c: 3} + {a: 42}\' null => {"a": 42, "b": 2, "c": 3} . .fi . .IP "" 0 . .SS "Subtraction: \-" As well as normal arithmetic subtraction on numbers, the \fB\-\fR operator can be used on arrays to remove all occurrences of the second array\'s elements from the first array\. . .IP "" 4 . .nf jq \'4 \- \.a\' {"a":3} => 1 jq \'\. \- ["xml", "yaml"]\' ["xml", "yaml", "json"] => ["json"] . .fi . .IP "" 0 . .SS "Multiplication, division, modulo: *, /, %" These infix operators behave as expected when given two numbers\. Division by zero raises an error\. \fBx % y\fR computes x modulo y\. . .P Multiplying a string by a number produces the concatenation of that string that many times\. \fB"x" * 0\fR produces \fB""\fR\. . .P Dividing a string by another splits the first using the second as separators\. . .P Multiplying two objects will merge them recursively: this works like addition but if both objects contain a value for the same key, and the values are objects, the two are merged with the same strategy\. . .IP "" 4 . .nf jq \'10 / \. * 3\' 5 => 6 jq \'\. / ", "\' "a, b,c,d, e" => ["a","b,c,d","e"] jq \'{"k": {"a": 1, "b": 2}} * {"k": {"a": 0,"c": 3}}\' null => {"k": {"a": 0, "b": 2, "c": 3}} jq \'\.[] | (1 / \.)?\' [1,0,\-1] => 1, \-1 . .fi . .IP "" 0 . .SS "abs" The builtin function \fBabs\fR is defined naively as: \fBif \. < 0 then \- \. else \. end\fR\. . .P For numeric input, this is the absolute value\. See the section on the identity filter for the implications of this definition for numeric input\. . .P To compute the absolute value of a number as a floating point number, you may wish use \fBfabs\fR\. . .IP "" 4 . .nf jq \'map(abs)\' [\-10, \-1\.1, \-1e\-1] => [10,1\.1,1e\-1] . .fi . .IP "" 0 . .SS "length" The builtin function \fBlength\fR gets the length of various different types of value: . .IP "\(bu" 4 The length of a \fBstring\fR is the number of Unicode codepoints it contains (which will be the same as its JSON\-encoded length in bytes if it\'s pure ASCII)\. . .IP "\(bu" 4 The length of a \fBnumber\fR is its absolute value\. . .IP "\(bu" 4 The length of an \fBarray\fR is the number of elements\. . .IP "\(bu" 4 The length of an \fBobject\fR is the number of key\-value pairs\. . .IP "\(bu" 4 The length of \fBnull\fR is zero\. . .IP "\(bu" 4 It is an error to use \fBlength\fR on a \fBboolean\fR\. . .IP "" 4 . .nf jq \'\.[] | length\' [[1,2], "string", {"a":2}, null, \-5] => 2, 6, 1, 0, 5 . .fi . .IP "" 0 . .SS "utf8bytelength" The builtin function \fButf8bytelength\fR outputs the number of bytes used to encode a string in UTF\-8\. . .IP "" 4 . .nf jq \'utf8bytelength\' "\eu03bc" => 2 . .fi . .IP "" 0 . .SS "keys, keys_unsorted" The builtin function \fBkeys\fR, when given an object, returns its keys in an array\. . .P The keys are sorted "alphabetically", by unicode codepoint order\. This is not an order that makes particular sense in any particular language, but you can count on it being the same for any two objects with the same set of keys, regardless of locale settings\. . .P When \fBkeys\fR is given an array, it returns the valid indices for that array: the integers from 0 to length\-1\. . .P The \fBkeys_unsorted\fR function is just like \fBkeys\fR, but if the input is an object then the keys will not be sorted, instead the keys will roughly be in insertion order\. . .IP "" 4 . .nf jq \'keys\' {"abc": 1, "abcd": 2, "Foo": 3} => ["Foo", "abc", "abcd"] jq \'keys\' [42,3,35] => [0,1,2] . .fi . .IP "" 0 . .SS "has(key)" The builtin function \fBhas\fR returns whether the input object has the given key, or the input array has an element at the given index\. . .P \fBhas($key)\fR has the same effect as checking whether \fB$key\fR is a member of the array returned by \fBkeys\fR, although \fBhas\fR will be faster\. . .IP "" 4 . .nf jq \'map(has("foo"))\' [{"foo": 42}, {}] => [true, false] jq \'map(has(2))\' [[0,1], ["a","b","c"]] => [false, true] . .fi . .IP "" 0 . .SS "in" The builtin function \fBin\fR returns whether or not the input key is in the given object, or the input index corresponds to an element in the given array\. It is, essentially, an inversed version of \fBhas\fR\. . .IP "" 4 . .nf jq \'\.[] | in({"foo": 42})\' ["foo", "bar"] => true, false jq \'map(in([0,1]))\' [2, 0] => [false, true] . .fi . .IP "" 0 . .SS "map(f), map_values(f)" For any filter \fBf\fR, \fBmap(f)\fR and \fBmap_values(f)\fR apply \fBf\fR to each of the values in the input array or object, that is, to the values of \fB\.[]\fR\. . .P In the absence of errors, \fBmap(f)\fR always outputs an array whereas \fBmap_values(f)\fR outputs an array if given an array, or an object if given an object\. . .P When the input to \fBmap_values(f)\fR is an object, the output object has the same keys as the input object except for those keys whose values when piped to \fBf\fR produce no values at all\. . .P The key difference between \fBmap(f)\fR and \fBmap_values(f)\fR is that the former simply forms an array from all the values of \fB($x|f)\fR for each value, \fB$x\fR, in the input array or object, but \fBmap_values(f)\fR only uses \fBfirst($x|f)\fR\. . .P Specifically, for object inputs, \fBmap_values(f)\fR constructs the output object by examining in turn the value of \fBfirst(\.[$k]|f)\fR for each key, \fB$k\fR, of the input\. If this expression produces no values, then the corresponding key will be dropped; otherwise, the output object will have that value at the key, \fB$k\fR\. . .P Here are some examples to clarify the behavior of \fBmap\fR and \fBmap_values\fR when applied to arrays\. These examples assume the input is \fB[1]\fR in all cases: . .IP "" 4 . .nf map(\.+1) #=> [2] map(\., \.) #=> [1,1] map(empty) #=> [] map_values(\.+1) #=> [2] map_values(\., \.) #=> [1] map_values(empty) #=> [] . .fi . .IP "" 0 . .P \fBmap(f)\fR is equivalent to \fB[\.[] | f]\fR and \fBmap_values(f)\fR is equivalent to \fB\.[] |= f\fR\. . .P In fact, these are their implementations\. . .IP "" 4 . .nf jq \'map(\.+1)\' [1,2,3] => [2,3,4] jq \'map_values(\.+1)\' {"a": 1, "b": 2, "c": 3} => {"a": 2, "b": 3, "c": 4} jq \'map(\., \.)\' [1,2] => [1,1,2,2] jq \'map_values(\. // empty)\' {"a": null, "b": true, "c": false} => {"b":true} . .fi . .IP "" 0 . .SS "pick(pathexps)" Emit the projection of the input object or array defined by the specified sequence of path expressions, such that if \fBp\fR is any one of these specifications, then \fB(\. | p)\fR will evaluate to the same value as \fB(\. | pick(pathexps) | p)\fR\. For arrays, negative indices and \fB\.[m:n]\fR specifications should not be used\. . .IP "" 4 . .nf jq \'pick(\.a, \.b\.c, \.x)\' {"a": 1, "b": {"c": 2, "d": 3}, "e": 4} => {"a":1,"b":{"c":2},"x":null} jq \'pick(\.[2], \.[0], \.[0])\' [1,2,3,4] => [1,null,3] . .fi . .IP "" 0 . .SS "path(path_expression)" Outputs array representations of the given path expression in \fB\.\fR\. The outputs are arrays of strings (object keys) and/or numbers (array indices)\. . .P Path expressions are jq expressions like \fB\.a\fR, but also \fB\.[]\fR\. There are two types of path expressions: ones that can match exactly, and ones that cannot\. For example, \fB\.a\.b\.c\fR is an exact match path expression, while \fB\.a[]\.b\fR is not\. . .P \fBpath(exact_path_expression)\fR will produce the array representation of the path expression even if it does not exist in \fB\.\fR, if \fB\.\fR is \fBnull\fR or an array or an object\. . .P \fBpath(pattern)\fR will produce array representations of the paths matching \fBpattern\fR if the paths exist in \fB\.\fR\. . .P Note that the path expressions are not different from normal expressions\. The expression \fBpath(\.\.|select(type=="boolean"))\fR outputs all the paths to boolean values in \fB\.\fR, and only those paths\. . .IP "" 4 . .nf jq \'path(\.a[0]\.b)\' null => ["a",0,"b"] jq \'[path(\.\.)]\' {"a":[{"b":1}]} => [[],["a"],["a",0],["a",0,"b"]] . .fi . .IP "" 0 . .SS "del(path_expression)" The builtin function \fBdel\fR removes a key and its corresponding value from an object\. . .IP "" 4 . .nf jq \'del(\.foo)\' {"foo": 42, "bar": 9001, "baz": 42} => {"bar": 9001, "baz": 42} jq \'del(\.[1, 2])\' ["foo", "bar", "baz"] => ["foo"] . .fi . .IP "" 0 . .SS "getpath(PATHS)" The builtin function \fBgetpath\fR outputs the values in \fB\.\fR found at each path in \fBPATHS\fR\. . .IP "" 4 . .nf jq \'getpath(["a","b"])\' null => null jq \'[getpath(["a","b"], ["a","c"])]\' {"a":{"b":0, "c":1}} => [0, 1] . .fi . .IP "" 0 . .SS "setpath(PATHS; VALUE)" The builtin function \fBsetpath\fR sets the \fBPATHS\fR in \fB\.\fR to \fBVALUE\fR\. . .IP "" 4 . .nf jq \'setpath(["a","b"]; 1)\' null => {"a": {"b": 1}} jq \'setpath(["a","b"]; 1)\' {"a":{"b":0}} => {"a": {"b": 1}} jq \'setpath([0,"a"]; 1)\' null => [{"a":1}] . .fi . .IP "" 0 . .SS "delpaths(PATHS)" The builtin function \fBdelpaths\fR deletes the \fBPATHS\fR in \fB\.\fR\. \fBPATHS\fR must be an array of paths, where each path is an array of strings and numbers\. . .IP "" 4 . .nf jq \'delpaths([["a","b"]])\' {"a":{"b":1},"x":{"y":2}} => {"a":{},"x":{"y":2}} . .fi . .IP "" 0 . .SS "to_entries, from_entries, with_entries(f)" These functions convert between an object and an array of key\-value pairs\. If \fBto_entries\fR is passed an object, then for each \fBk: v\fR entry in the input, the output array includes \fB{"key": k, "value": v}\fR\. . .P \fBfrom_entries\fR does the opposite conversion, and \fBwith_entries(f)\fR is a shorthand for \fBto_entries | map(f) | from_entries\fR, useful for doing some operation to all keys and values of an object\. \fBfrom_entries\fR accepts \fB"key"\fR, \fB"Key"\fR, \fB"name"\fR, \fB"Name"\fR, \fB"value"\fR, and \fB"Value"\fR as keys\. . .IP "" 4 . .nf jq \'to_entries\' {"a": 1, "b": 2} => [{"key":"a", "value":1}, {"key":"b", "value":2}] jq \'from_entries\' [{"key":"a", "value":1}, {"key":"b", "value":2}] => {"a": 1, "b": 2} jq \'with_entries(\.key |= "KEY_" + \.)\' {"a": 1, "b": 2} => {"KEY_a": 1, "KEY_b": 2} . .fi . .IP "" 0 . .SS "select(boolean_expression)" The function \fBselect(f)\fR produces its input unchanged if \fBf\fR returns true for that input, and produces no output otherwise\. . .P It\'s useful for filtering lists: \fB[1,2,3] | map(select(\. >= 2))\fR will give you \fB[2,3]\fR\. . .IP "" 4 . .nf jq \'map(select(\. >= 2))\' [1,5,3,0,7] => [5,3,7] jq \'\.[] | select(\.id == "second")\' [{"id": "first", "val": 1}, {"id": "second", "val": 2}] => {"id": "second", "val": 2} . .fi . .IP "" 0 . .SS "arrays, objects, iterables, booleans, numbers, normals, finites, strings, nulls, values, scalars" These built\-ins select only inputs that are arrays, objects, iterables (arrays or objects), booleans, numbers, normal numbers, finite numbers, strings, null, non\-null values, and non\-iterables, respectively\. . .IP "" 4 . .nf jq \'\.[]|numbers\' [[],{},1,"foo",null,true,false] => 1 . .fi . .IP "" 0 . .SS "empty" \fBempty\fR returns no results\. None at all\. Not even \fBnull\fR\. . .P It\'s useful on occasion\. You\'ll know if you need it :) . .IP "" 4 . .nf jq \'1, empty, 2\' null => 1, 2 jq \'[1,2,empty,3]\' null => [1,2,3] . .fi . .IP "" 0 . .SS "error, error(message)" Produces an error with the input value, or with the message given as the argument\. Errors can be caught with try/catch; see below\. . .IP "" 4 . .nf jq \'try error catch \.\' "error message" => "error message" jq \'try error("invalid value: \e(\.)") catch \.\' 42 => "invalid value: 42" . .fi . .IP "" 0 . .SS "halt" Stops the jq program with no further outputs\. jq will exit with exit status \fB0\fR\. . .SS "halt_error, halt_error(exit_code)" Stops the jq program with no further outputs\. The input will be printed on \fBstderr\fR as raw output (i\.e\., strings will not have double quotes) with no decoration, not even a newline\. . .P The given \fBexit_code\fR (defaulting to \fB5\fR) will be jq\'s exit status\. . .P For example, \fB"Error: something went wrong\en"|halt_error(1)\fR\. . .SS "$__loc__" Produces an object with a "file" key and a "line" key, with the filename and line number where \fB$__loc__\fR occurs, as values\. . .IP "" 4 . .nf jq \'try error("\e($__loc__)") catch \.\' null => "{\e"file\e":\e"\e",\e"line\e":1}" . .fi . .IP "" 0 . .SS "paths, paths(node_filter)" \fBpaths\fR outputs the paths to all the elements in its input (except it does not output the empty list, representing \. itself)\. . .P \fBpaths(f)\fR outputs the paths to any values for which \fBf\fR is \fBtrue\fR\. That is, \fBpaths(type == "number")\fR outputs the paths to all numeric values\. . .IP "" 4 . .nf jq \'[paths]\' [1,[[],{"a":2}]] => [[0],[1],[1,0],[1,1],[1,1,"a"]] jq \'[paths(type == "number")]\' [1,[[],{"a":2}]] => [[0],[1,1,"a"]] . .fi . .IP "" 0 . .SS "add, add(generator)" The filter \fBadd\fR takes as input an array, and produces as output the elements of the array added together\. This might mean summed, concatenated or merged depending on the types of the elements of the input array \- the rules are the same as those for the \fB+\fR operator (described above)\. . .P If the input is an empty array, \fBadd\fR returns \fBnull\fR\. . .P \fBadd(generator)\fR operates on the given generator rather than the input\. . .IP "" 4 . .nf jq \'add\' ["a","b","c"] => "abc" jq \'add\' [1, 2, 3] => 6 jq \'add\' [] => null jq \'add(\.[]\.a)\' [{"a":3}, {"a":5}, {"b":6}] => 8 . .fi . .IP "" 0 . .SS "any, any(condition), any(generator; condition)" The filter \fBany\fR takes as input an array of boolean values, and produces \fBtrue\fR as output if any of the elements of the array are \fBtrue\fR\. . .P If the input is an empty array, \fBany\fR returns \fBfalse\fR\. . .P The \fBany(condition)\fR form applies the given condition to the elements of the input array\. . .P The \fBany(generator; condition)\fR form applies the given condition to all the outputs of the given generator\. . .IP "" 4 . .nf jq \'any\' [true, false] => true jq \'any\' [false, false] => false jq \'any\' [] => false . .fi . .IP "" 0 . .SS "all, all(condition), all(generator; condition)" The filter \fBall\fR takes as input an array of boolean values, and produces \fBtrue\fR as output if all of the elements of the array are \fBtrue\fR\. . .P The \fBall(condition)\fR form applies the given condition to the elements of the input array\. . .P The \fBall(generator; condition)\fR form applies the given condition to all the outputs of the given generator\. . .P If the input is an empty array, \fBall\fR returns \fBtrue\fR\. . .IP "" 4 . .nf jq \'all\' [true, false] => false jq \'all\' [true, true] => true jq \'all\' [] => true . .fi . .IP "" 0 . .SS "flatten, flatten(depth)" The filter \fBflatten\fR takes as input an array of nested arrays, and produces a flat array in which all arrays inside the original array have been recursively replaced by their values\. You can pass an argument to it to specify how many levels of nesting to flatten\. . .P \fBflatten(2)\fR is like \fBflatten\fR, but going only up to two levels deep\. . .IP "" 4 . .nf jq \'flatten\' [1, [2], [[3]]] => [1, 2, 3] jq \'flatten(1)\' [1, [2], [[3]]] => [1, 2, [3]] jq \'flatten\' [[]] => [] jq \'flatten\' [{"foo": "bar"}, [{"foo": "baz"}]] => [{"foo": "bar"}, {"foo": "baz"}] . .fi . .IP "" 0 . .SS "range(upto), range(from; upto), range(from; upto; by)" The \fBrange\fR function produces a range of numbers\. \fBrange(4; 10)\fR produces 6 numbers, from 4 (inclusive) to 10 (exclusive)\. The numbers are produced as separate outputs\. Use \fB[range(4; 10)]\fR to get a range as an array\. . .P The one argument form generates numbers from 0 to the given number, with an increment of 1\. . .P The two argument form generates numbers from \fBfrom\fR to \fBupto\fR with an increment of 1\. . .P The three argument form generates numbers \fBfrom\fR to \fBupto\fR with an increment of \fBby\fR\. . .IP "" 4 . .nf jq \'range(2; 4)\' null => 2, 3 jq \'[range(2; 4)]\' null => [2,3] jq \'[range(4)]\' null => [0,1,2,3] jq \'[range(0; 10; 3)]\' null => [0,3,6,9] jq \'[range(0; 10; \-1)]\' null => [] jq \'[range(0; \-5; \-1)]\' null => [0,\-1,\-2,\-3,\-4] . .fi . .IP "" 0 . .SS "floor" The \fBfloor\fR function returns the floor of its numeric input\. . .IP "" 4 . .nf jq \'floor\' 3\.14159 => 3 . .fi . .IP "" 0 . .SS "sqrt" The \fBsqrt\fR function returns the square root of its numeric input\. . .IP "" 4 . .nf jq \'sqrt\' 9 => 3 . .fi . .IP "" 0 . .SS "tonumber" The \fBtonumber\fR function parses its input as a number\. It will convert correctly\-formatted strings to their numeric equivalent, leave numbers alone, and give an error on all other input\. . .IP "" 4 . .nf jq \'\.[] | tonumber\' [1, "1"] => 1, 1 . .fi . .IP "" 0 . .SS "toboolean" The \fBtoboolean\fR function parses its input as a boolean\. It will convert correctly\-formatted strings to their boolean equivalent, leave booleans alone, and give an error on all other input\. . .IP "" 4 . .nf jq \'\.[] | toboolean\' ["true", "false", true, false] => true, false, true, false . .fi . .IP "" 0 . .SS "tostring" The \fBtostring\fR function prints its input as a string\. Strings are left unchanged, and all other values are JSON\-encoded\. . .IP "" 4 . .nf jq \'\.[] | tostring\' [1, "1", [1]] => "1", "1", "[1]" . .fi . .IP "" 0 . .SS "type" The \fBtype\fR function returns the type of its argument as a string, which is one of null, boolean, number, string, array or object\. . .IP "" 4 . .nf jq \'map(type)\' [0, false, [], {}, null, "hello"] => ["number", "boolean", "array", "object", "null", "string"] . .fi . .IP "" 0 . .SS "infinite, nan, isinfinite, isnan, isfinite, isnormal" Some arithmetic operations can yield infinities and "not a number" (NaN) values\. The \fBisinfinite\fR builtin returns \fBtrue\fR if its input is infinite\. The \fBisnan\fR builtin returns \fBtrue\fR if its input is a NaN\. The \fBinfinite\fR builtin returns a positive infinite value\. The \fBnan\fR builtin returns a NaN\. The \fBisnormal\fR builtin returns true if its input is a normal number\. . .P Note that division by zero raises an error\. . .P Currently most arithmetic operations operating on infinities, NaNs, and sub\-normals do not raise errors\. . .IP "" 4 . .nf jq \'\.[] | (infinite * \.) < 0\' [\-1, 1] => true, false jq \'infinite, nan | type\' null => "number", "number" . .fi . .IP "" 0 . .SS "sort, sort_by(path_expression)" The \fBsort\fR functions sorts its input, which must be an array\. Values are sorted in the following order: . .IP "\(bu" 4 \fBnull\fR . .IP "\(bu" 4 \fBfalse\fR . .IP "\(bu" 4 \fBtrue\fR . .IP "\(bu" 4 numbers . .IP "\(bu" 4 strings, in alphabetical order (by unicode codepoint value) . .IP "\(bu" 4 arrays, in lexical order . .IP "\(bu" 4 objects . .IP "" 0 . .P The ordering for objects is a little complex: first they\'re compared by comparing their sets of keys (as arrays in sorted order), and if their keys are equal then the values are compared key by key\. . .P \fBsort_by\fR may be used to sort by a particular field of an object, or by applying any jq filter\. \fBsort_by(f)\fR compares two elements by comparing the result of \fBf\fR on each element\. When \fBf\fR produces multiple values, it firstly compares the first values, and the second values if the first values are equal, and so on\. . .IP "" 4 . .nf jq \'sort\' [8,3,null,6] => [null,3,6,8] jq \'sort_by(\.foo)\' [{"foo":4, "bar":10}, {"foo":3, "bar":10}, {"foo":2, "bar":1}] => [{"foo":2, "bar":1}, {"foo":3, "bar":10}, {"foo":4, "bar":10}] jq \'sort_by(\.foo, \.bar)\' [{"foo":4, "bar":10}, {"foo":3, "bar":20}, {"foo":2, "bar":1}, {"foo":3, "bar":10}] => [{"foo":2, "bar":1}, {"foo":3, "bar":10}, {"foo":3, "bar":20}, {"foo":4, "bar":10}] . .fi . .IP "" 0 . .SS "group_by(path_expression)" \fBgroup_by(\.foo)\fR takes as input an array, groups the elements having the same \fB\.foo\fR field into separate arrays, and produces all of these arrays as elements of a larger array, sorted by the value of the \fB\.foo\fR field\. . .P Any jq expression, not just a field access, may be used in place of \fB\.foo\fR\. The sorting order is the same as described in the \fBsort\fR function above\. . .IP "" 4 . .nf jq \'group_by(\.foo)\' [{"foo":1, "bar":10}, {"foo":3, "bar":100}, {"foo":1, "bar":1}] => [[{"foo":1, "bar":10}, {"foo":1, "bar":1}], [{"foo":3, "bar":100}]] . .fi . .IP "" 0 . .SS "min, max, min_by(path_exp), max_by(path_exp)" Find the minimum or maximum element of the input array\. . .P The \fBmin_by(path_exp)\fR and \fBmax_by(path_exp)\fR functions allow you to specify a particular field or property to examine, e\.g\. \fBmin_by(\.foo)\fR finds the object with the smallest \fBfoo\fR field\. . .IP "" 4 . .nf jq \'min\' [5,4,2,7] => 2 jq \'max_by(\.foo)\' [{"foo":1, "bar":14}, {"foo":2, "bar":3}] => {"foo":2, "bar":3} . .fi . .IP "" 0 . .SS "unique, unique_by(path_exp)" The \fBunique\fR function takes as input an array and produces an array of the same elements, in sorted order, with duplicates removed\. . .P The \fBunique_by(path_exp)\fR function will keep only one element for each value obtained by applying the argument\. Think of it as making an array by taking one element out of every group produced by \fBgroup\fR\. . .IP "" 4 . .nf jq \'unique\' [1,2,5,3,5,3,1,3] => [1,2,3,5] jq \'unique_by(\.foo)\' [{"foo": 1, "bar": 2}, {"foo": 1, "bar": 3}, {"foo": 4, "bar": 5}] => [{"foo": 1, "bar": 2}, {"foo": 4, "bar": 5}] jq \'unique_by(length)\' ["chunky", "bacon", "kitten", "cicada", "asparagus"] => ["bacon", "chunky", "asparagus"] . .fi . .IP "" 0 . .SS "reverse" This function reverses an array\. . .IP "" 4 . .nf jq \'reverse\' [1,2,3,4] => [4,3,2,1] . .fi . .IP "" 0 . .SS "contains(element)" The filter \fBcontains(b)\fR will produce true if b is completely contained within the input\. A string B is contained in a string A if B is a substring of A\. An array B is contained in an array A if all elements in B are contained in any element in A\. An object B is contained in object A if all of the values in B are contained in the value in A with the same key\. All other types are assumed to be contained in each other if they are equal\. . .IP "" 4 . .nf jq \'contains("bar")\' "foobar" => true jq \'contains(["baz", "bar"])\' ["foobar", "foobaz", "blarp"] => true jq \'contains(["bazzzzz", "bar"])\' ["foobar", "foobaz", "blarp"] => false jq \'contains({foo: 12, bar: [{barp: 12}]})\' {"foo": 12, "bar":[1,2,{"barp":12, "blip":13}]} => true jq \'contains({foo: 12, bar: [{barp: 15}]})\' {"foo": 12, "bar":[1,2,{"barp":12, "blip":13}]} => false . .fi . .IP "" 0 . .SS "indices(s)" Outputs an array containing the indices in \fB\.\fR where \fBs\fR occurs\. The input may be an array, in which case if \fBs\fR is an array then the indices output will be those where all elements in \fB\.\fR match those of \fBs\fR\. . .IP "" 4 . .nf jq \'indices(", ")\' "a,b, cd, efg, hijk" => [3,7,12] jq \'indices(1)\' [0,1,2,1,3,1,4] => [1,3,5] jq \'indices([1,2])\' [0,1,2,3,1,4,2,5,1,2,6,7] => [1,8] . .fi . .IP "" 0 . .SS "index(s), rindex(s)" Outputs the index of the first (\fBindex\fR) or last (\fBrindex\fR) occurrence of \fBs\fR in the input\. . .IP "" 4 . .nf jq \'index(", ")\' "a,b, cd, efg, hijk" => 3 jq \'index(1)\' [0,1,2,1,3,1,4] => 1 jq \'index([1,2])\' [0,1,2,3,1,4,2,5,1,2,6,7] => 1 jq \'rindex(", ")\' "a,b, cd, efg, hijk" => 12 jq \'rindex(1)\' [0,1,2,1,3,1,4] => 5 jq \'rindex([1,2])\' [0,1,2,3,1,4,2,5,1,2,6,7] => 8 . .fi . .IP "" 0 . .SS "inside" The filter \fBinside(b)\fR will produce true if the input is completely contained within b\. It is, essentially, an inversed version of \fBcontains\fR\. . .IP "" 4 . .nf jq \'inside("foobar")\' "bar" => true jq \'inside(["foobar", "foobaz", "blarp"])\' ["baz", "bar"] => true jq \'inside(["foobar", "foobaz", "blarp"])\' ["bazzzzz", "bar"] => false jq \'inside({"foo": 12, "bar":[1,2,{"barp":12, "blip":13}]})\' {"foo": 12, "bar": [{"barp": 12}]} => true jq \'inside({"foo": 12, "bar":[1,2,{"barp":12, "blip":13}]})\' {"foo": 12, "bar": [{"barp": 15}]} => false . .fi . .IP "" 0 . .SS "startswith(str)" Outputs \fBtrue\fR if \. starts with the given string argument\. . .IP "" 4 . .nf jq \'[\.[]|startswith("foo")]\' ["fo", "foo", "barfoo", "foobar", "barfoob"] => [false, true, false, true, false] . .fi . .IP "" 0 . .SS "endswith(str)" Outputs \fBtrue\fR if \. ends with the given string argument\. . .IP "" 4 . .nf jq \'[\.[]|endswith("foo")]\' ["foobar", "barfoo"] => [false, true] . .fi . .IP "" 0 . .SS "combinations, combinations(n)" Outputs all combinations of the elements of the arrays in the input array\. If given an argument \fBn\fR, it outputs all combinations of \fBn\fR repetitions of the input array\. . .IP "" 4 . .nf jq \'combinations\' [[1,2], [3, 4]] => [1, 3], [1, 4], [2, 3], [2, 4] jq \'combinations(2)\' [0, 1] => [0, 0], [0, 1], [1, 0], [1, 1] . .fi . .IP "" 0 . .SS "ltrimstr(str)" Outputs its input with the given prefix string removed, if it starts with it\. . .IP "" 4 . .nf jq \'[\.[]|ltrimstr("foo")]\' ["fo", "foo", "barfoo", "foobar", "afoo"] => ["fo","","barfoo","bar","afoo"] . .fi . .IP "" 0 . .SS "rtrimstr(str)" Outputs its input with the given suffix string removed, if it ends with it\. . .IP "" 4 . .nf jq \'[\.[]|rtrimstr("foo")]\' ["fo", "foo", "barfoo", "foobar", "foob"] => ["fo","","bar","foobar","foob"] . .fi . .IP "" 0 . .SS "trimstr(str)" Outputs its input with the given string removed at both ends, if it starts or ends with it\. . .IP "" 4 . .nf jq \'[\.[]|trimstr("foo")]\' ["fo", "foo", "barfoo", "foobarfoo", "foob"] => ["fo","","bar","bar","b"] . .fi . .IP "" 0 . .SS "trim, ltrim, rtrim" \fBtrim\fR trims both leading and trailing whitespace\. . .P \fBltrim\fR trims only leading (left side) whitespace\. . .P \fBrtrim\fR trims only trailing (right side) whitespace\. . .P Whitespace characters are the usual \fB" "\fR, \fB"\en"\fR \fB"\et"\fR, \fB"\er"\fR and also all characters in the Unicode character database with the whitespace property\. Note that what considers whitespace might change in the future\. . .IP "" 4 . .nf jq \'trim, ltrim, rtrim\' " abc " => "abc", "abc ", " abc" . .fi . .IP "" 0 . .SS "explode" Converts an input string into an array of the string\'s codepoint numbers\. . .IP "" 4 . .nf jq \'explode\' "foobar" => [102,111,111,98,97,114] . .fi . .IP "" 0 . .SS "implode" The inverse of explode\. . .IP "" 4 . .nf jq \'implode\' [65, 66, 67] => "ABC" . .fi . .IP "" 0 . .SS "split(str)" Splits an input string on the separator argument\. . .P \fBsplit\fR can also split on regex matches when called with two arguments (see the regular expressions section below)\. . .IP "" 4 . .nf jq \'split(", ")\' "a, b,c,d, e, " => ["a","b,c,d","e",""] . .fi . .IP "" 0 . .SS "join(str)" Joins the array of elements given as input, using the argument as separator\. It is the inverse of \fBsplit\fR: that is, running \fBsplit("foo") | join("foo")\fR over any input string returns said input string\. . .P Numbers and booleans in the input are converted to strings\. Null values are treated as empty strings\. Arrays and objects in the input are not supported\. . .IP "" 4 . .nf jq \'join(", ")\' ["a","b,c,d","e"] => "a, b,c,d, e" jq \'join(" ")\' ["a",1,2\.3,true,null,false] => "a 1 2\.3 true false" . .fi . .IP "" 0 . .SS "ascii_downcase, ascii_upcase" Emit a copy of the input string with its alphabetic characters (a\-z and A\-Z) converted to the specified case\. . .IP "" 4 . .nf jq \'ascii_upcase\' "useful but not for é" => "USEFUL BUT NOT FOR é" . .fi . .IP "" 0 . .SS "while(cond; update)" The \fBwhile(cond; update)\fR function allows you to repeatedly apply an update to \fB\.\fR until \fBcond\fR is false\. . .P Note that \fBwhile(cond; update)\fR is internally defined as a recursive jq function\. Recursive calls within \fBwhile\fR will not consume additional memory if \fBupdate\fR produces at most one output for each input\. See advanced topics below\. . .IP "" 4 . .nf jq \'[while(\.<100; \.*2)]\' 1 => [1,2,4,8,16,32,64] . .fi . .IP "" 0 . .SS "repeat(exp)" The \fBrepeat(exp)\fR function allows you to repeatedly apply expression \fBexp\fR to \fB\.\fR until an error is raised\. . .P Note that \fBrepeat(exp)\fR is internally defined as a recursive jq function\. Recursive calls within \fBrepeat\fR will not consume additional memory if \fBexp\fR produces at most one output for each input\. See advanced topics below\. . .IP "" 4 . .nf jq \'[repeat(\.*2, error)?]\' 1 => [2] . .fi . .IP "" 0 . .SS "until(cond; next)" The \fBuntil(cond; next)\fR function allows you to repeatedly apply the expression \fBnext\fR, initially to \fB\.\fR then to its own output, until \fBcond\fR is true\. For example, this can be used to implement a factorial function (see below)\. . .P Note that \fBuntil(cond; next)\fR is internally defined as a recursive jq function\. Recursive calls within \fBuntil()\fR will not consume additional memory if \fBnext\fR produces at most one output for each input\. See advanced topics below\. . .IP "" 4 . .nf jq \'[\.,1]|until(\.[0] < 1; [\.[0] \- 1, \.[1] * \.[0]])|\.[1]\' 4 => 24 . .fi . .IP "" 0 . .SS "recurse(f), recurse, recurse(f; condition)" The \fBrecurse(f)\fR function allows you to search through a recursive structure, and extract interesting data from all levels\. Suppose your input represents a filesystem: . .IP "" 4 . .nf {"name": "/", "children": [ {"name": "/bin", "children": [ {"name": "/bin/ls", "children": []}, {"name": "/bin/sh", "children": []}]}, {"name": "/home", "children": [ {"name": "/home/stephen", "children": [ {"name": "/home/stephen/jq", "children": []}]}]}]} . .fi . .IP "" 0 . .P Now suppose you want to extract all of the filenames present\. You need to retrieve \fB\.name\fR, \fB\.children[]\.name\fR, \fB\.children[]\.children[]\.name\fR, and so on\. You can do this with: . .IP "" 4 . .nf recurse(\.children[]) | \.name . .fi . .IP "" 0 . .P When called without an argument, \fBrecurse\fR is equivalent to \fBrecurse(\.[]?)\fR\. . .P \fBrecurse(f)\fR is identical to \fBrecurse(f; true)\fR and can be used without concerns about recursion depth\. . .P \fBrecurse(f; condition)\fR is a generator which begins by emitting \. and then emits in turn \.|f, \.|f|f, \.|f|f|f, \.\.\. so long as the computed value satisfies the condition\. For example, to generate all the integers, at least in principle, one could write \fBrecurse(\.+1; true)\fR\. . .P The recursive calls in \fBrecurse\fR will not consume additional memory whenever \fBf\fR produces at most a single output for each input\. . .IP "" 4 . .nf jq \'recurse(\.foo[])\' {"foo":[{"foo": []}, {"foo":[{"foo":[]}]}]} => {"foo":[{"foo":[]},{"foo":[{"foo":[]}]}]}, {"foo":[]}, {"foo":[{"foo":[]}]}, {"foo":[]} jq \'recurse\' {"a":0,"b":[1]} => {"a":0,"b":[1]}, 0, [1], 1 jq \'recurse(\. * \.; \. < 20)\' 2 => 2, 4, 16 . .fi . .IP "" 0 . .SS "walk(f)" The \fBwalk(f)\fR function applies f recursively to every component of the input entity\. When an array is encountered, f is first applied to its elements and then to the array itself; when an object is encountered, f is first applied to all the values and then to the object\. In practice, f will usually test the type of its input, as illustrated in the following examples\. The first example highlights the usefulness of processing the elements of an array of arrays before processing the array itself\. The second example shows how all the keys of all the objects within the input can be considered for alteration\. . .IP "" 4 . .nf jq \'walk(if type == "array" then sort else \. end)\' [[4, 1, 7], [8, 5, 2], [3, 6, 9]] => [[1,4,7],[2,5,8],[3,6,9]] jq \'walk( if type == "object" then with_entries( \.key |= sub( "^_+"; "") ) else \. end )\' [ { "_a": { "__b": 2 } } ] => [{"a":{"b":2}}] . .fi . .IP "" 0 . .SS "have_literal_numbers" This builtin returns true if jq\'s build configuration includes support for preservation of input number literals\. . .SS "have_decnum" This builtin returns true if jq was built with "decnum", which is the current literal number preserving numeric backend implementation for jq\. . .SS "$JQ_BUILD_CONFIGURATION" This builtin binding shows the jq executable\'s build configuration\. Its value has no particular format, but it can be expected to be at least the \fB\./configure\fR command\-line arguments, and may be enriched in the future to include the version strings for the build tooling used\. . .P Note that this can be overridden in the command\-line with \fB\-\-arg\fR and related options\. . .SS "$ENV, env" \fB$ENV\fR is an object representing the environment variables as set when the jq program started\. . .P \fBenv\fR outputs an object representing jq\'s current environment\. . .P At the moment there is no builtin for setting environment variables\. . .IP "" 4 . .nf jq \'$ENV\.PAGER\' null => "less" jq \'env\.PAGER\' null => "less" . .fi . .IP "" 0 . .SS "transpose" Transpose a possibly jagged matrix (an array of arrays)\. Rows are padded with nulls so the result is always rectangular\. . .IP "" 4 . .nf jq \'transpose\' [[1], [2,3]] => [[1,2],[null,3]] . .fi . .IP "" 0 . .SS "bsearch(x)" \fBbsearch(x)\fR conducts a binary search for x in the input array\. If the input is sorted and contains x, then \fBbsearch(x)\fR will return its index in the array; otherwise, if the array is sorted, it will return (\-1 \- ix) where ix is an insertion point such that the array would still be sorted after the insertion of x at ix\. If the array is not sorted, \fBbsearch(x)\fR will return an integer that is probably of no interest\. . .IP "" 4 . .nf jq \'bsearch(0)\' [0,1] => 0 jq \'bsearch(0)\' [1,2,3] => \-1 jq \'bsearch(4) as $ix | if $ix < 0 then \.[\-(1+$ix)] = 4 else \. end\' [1,2,3] => [1,2,3,4] . .fi . .IP "" 0 . .SS "String interpolation: \e(exp)" Inside a string, you can put an expression inside parens after a backslash\. Whatever the expression returns will be interpolated into the string\. . .IP "" 4 . .nf jq \'"The input was \e(\.), which is one less than \e(\.+1)"\' 42 => "The input was 42, which is one less than 43" . .fi . .IP "" 0 . .SS "Convert to/from JSON" The \fBtojson\fR and \fBfromjson\fR builtins dump values as JSON texts or parse JSON texts into values, respectively\. The \fBtojson\fR builtin differs from \fBtostring\fR in that \fBtostring\fR returns strings unmodified, while \fBtojson\fR encodes strings as JSON strings\. . .IP "" 4 . .nf jq \'[\.[]|tostring]\' [1, "foo", ["foo"]] => ["1","foo","[\e"foo\e"]"] jq \'[\.[]|tojson]\' [1, "foo", ["foo"]] => ["1","\e"foo\e"","[\e"foo\e"]"] jq \'[\.[]|tojson|fromjson]\' [1, "foo", ["foo"]] => [1,"foo",["foo"]] . .fi . .IP "" 0 . .SS "Format strings and escaping" The \fB@foo\fR syntax is used to format and escape strings, which is useful for building URLs, documents in a language like HTML or XML, and so forth\. \fB@foo\fR can be used as a filter on its own, the possible escapings are: . .TP \fB@text\fR: . .IP Calls \fBtostring\fR, see that function for details\. . .TP \fB@json\fR: . .IP Serializes the input as JSON\. . .TP \fB@html\fR: . .IP Applies HTML/XML escaping, by mapping the characters \fB<>&\'"\fR to their entity equivalents \fB<\fR, \fB>\fR, \fB&\fR, \fB'\fR, \fB"\fR\. . .TP \fB@uri\fR: . .IP Applies percent\-encoding, by mapping all reserved URI characters to a \fB%XX\fR sequence\. . .TP \fB@urid\fR: . .IP The inverse of \fB@uri\fR, applies percent\-decoding, by mapping all \fB%XX\fR sequences to their corresponding URI characters\. . .TP \fB@csv\fR: . .IP The input must be an array, and it is rendered as CSV with double quotes for strings, and quotes escaped by repetition\. . .TP \fB@tsv\fR: . .IP The input must be an array, and it is rendered as TSV (tab\-separated values)\. Each input array will be printed as a single line\. Fields are separated by a single tab (ascii \fB0x09\fR)\. Input characters line\-feed (ascii \fB0x0a\fR), carriage\-return (ascii \fB0x0d\fR), tab (ascii \fB0x09\fR) and backslash (ascii \fB0x5c\fR) will be output as escape sequences \fB\en\fR, \fB\er\fR, \fB\et\fR, \fB\e\e\fR respectively\. . .TP \fB@sh\fR: . .IP The input is escaped suitable for use in a command\-line for a POSIX shell\. If the input is an array, the output will be a series of space\-separated strings\. . .TP \fB@base64\fR: . .IP The input is converted to base64 as specified by RFC 4648\. . .TP \fB@base64d\fR: . .IP The inverse of \fB@base64\fR, input is decoded as specified by RFC 4648\. Note\e: If the decoded string is not UTF\-8, the results are undefined\. . .P This syntax can be combined with string interpolation in a useful way\. You can follow a \fB@foo\fR token with a string literal\. The contents of the string literal will \fInot\fR be escaped\. However, all interpolations made inside that string literal will be escaped\. For instance, . .IP "" 4 . .nf @uri "https://www\.google\.com/search?q=\e(\.search)" . .fi . .IP "" 0 . .P will produce the following output for the input \fB{"search":"what is jq?"}\fR: . .IP "" 4 . .nf "https://www\.google\.com/search?q=what%20is%20jq%3F" . .fi . .IP "" 0 . .P Note that the slashes, question mark, etc\. in the URL are not escaped, as they were part of the string literal\. . .IP "" 4 . .nf jq \'@html\' "This works if x < y" => "This works if x < y" jq \'@sh "echo \e(\.)"\' "O\'Hara\'s Ale" => "echo \'O\'\e\e\'\'Hara\'\e\e\'\'s Ale\'" jq \'@base64\' "This is a message" => "VGhpcyBpcyBhIG1lc3NhZ2U=" jq \'@base64d\' "VGhpcyBpcyBhIG1lc3NhZ2U=" => "This is a message" . .fi . .IP "" 0 . .SS "Dates" jq provides some basic date handling functionality, with some high\-level and low\-level builtins\. In all cases these builtins deal exclusively with time in UTC\. . .P The \fBfromdateiso8601\fR builtin parses datetimes in the ISO 8601 format to a number of seconds since the Unix epoch (1970\-01\-01T00:00:00Z)\. The \fBtodateiso8601\fR builtin does the inverse\. . .P The \fBfromdate\fR builtin parses datetime strings\. Currently \fBfromdate\fR only supports ISO 8601 datetime strings, but in the future it will attempt to parse datetime strings in more formats\. . .P The \fBtodate\fR builtin is an alias for \fBtodateiso8601\fR\. . .P The \fBnow\fR builtin outputs the current time, in seconds since the Unix epoch\. . .P Low\-level jq interfaces to the C\-library time functions are also provided: \fBstrptime\fR, \fBstrftime\fR, \fBstrflocaltime\fR, \fBmktime\fR, \fBgmtime\fR, and \fBlocaltime\fR\. Refer to your host operating system\'s documentation for the format strings used by \fBstrptime\fR and \fBstrftime\fR\. Note: these are not necessarily stable interfaces in jq, particularly as to their localization functionality\. . .P The \fBgmtime\fR builtin consumes a number of seconds since the Unix epoch and outputs a "broken down time" representation of Greenwich Mean Time as an array of numbers representing (in this order): the year, the month (zero\-based), the day of the month (one\-based), the hour of the day, the minute of the hour, the second of the minute, the day of the week, and the day of the year \-\- all one\-based unless otherwise stated\. The day of the week number may be wrong on some systems for dates before March 1st 1900, or after December 31 2099\. . .P The \fBlocaltime\fR builtin works like the \fBgmtime\fR builtin, but using the local timezone setting\. . .P The \fBmktime\fR builtin consumes "broken down time" representations of time output by \fBgmtime\fR and \fBstrptime\fR\. . .P The \fBstrptime(fmt)\fR builtin parses input strings matching the \fBfmt\fR argument\. The output is in the "broken down time" representation consumed by \fBmktime\fR and output by \fBgmtime\fR\. . .P The \fBstrftime(fmt)\fR builtin formats a time (GMT) with the given format\. The \fBstrflocaltime\fR does the same, but using the local timezone setting\. . .P The format strings for \fBstrptime\fR and \fBstrftime\fR are described in typical C library documentation\. The format string for ISO 8601 datetime is \fB"%Y\-%m\-%dT%H:%M:%SZ"\fR\. . .P jq may not support some or all of this date functionality on some systems\. In particular, the \fB%u\fR and \fB%j\fR specifiers for \fBstrptime(fmt)\fR are not supported on macOS\. . .IP "" 4 . .nf jq \'fromdate\' "2015\-03\-05T23:51:47Z" => 1425599507 jq \'strptime("%Y\-%m\-%dT%H:%M:%SZ")\' "2015\-03\-05T23:51:47Z" => [2015,2,5,23,51,47,4,63] jq \'strptime("%Y\-%m\-%dT%H:%M:%SZ")|mktime\' "2015\-03\-05T23:51:47Z" => 1425599507 . .fi . .IP "" 0 . .SS "SQL\-Style Operators" jq provides a few SQL\-style operators\. . .TP \fBINDEX(stream; index_expression)\fR: . .IP This builtin produces an object whose keys are computed by the given index expression applied to each value from the given stream\. . .TP \fBJOIN($idx; stream; idx_expr; join_expr)\fR: . .IP This builtin joins the values from the given stream to the given index\. The index\'s keys are computed by applying the given index expression to each value from the given stream\. An array of the value in the stream and the corresponding value from the index is fed to the given join expression to produce each result\. . .TP \fBJOIN($idx; stream; idx_expr)\fR: . .IP Same as \fBJOIN($idx; stream; idx_expr; \.)\fR\. . .TP \fBJOIN($idx; idx_expr)\fR: . .IP This builtin joins the input \fB\.\fR to the given index, applying the given index expression to \fB\.\fR to compute the index key\. The join operation is as described above\. . .TP \fBIN(s)\fR: . .IP This builtin outputs \fBtrue\fR if \fB\.\fR appears in the given stream, otherwise it outputs \fBfalse\fR\. . .TP \fBIN(source; s)\fR: . .IP This builtin outputs \fBtrue\fR if any value in the source stream appears in the second stream, otherwise it outputs \fBfalse\fR\. . .SS "builtins" Returns a list of all builtin functions in the format \fBname/arity\fR\. Since functions with the same name but different arities are considered separate functions, \fBall/0\fR, \fBall/1\fR, and \fBall/2\fR would all be present in the list\. . .SH "CONDITIONALS AND COMPARISONS" . .SS "==, !=" The expression \'a == b\' will produce \'true\' if the results of evaluating a and b are equal (that is, if they represent equivalent JSON values) and \'false\' otherwise\. In particular, strings are never considered equal to numbers\. In checking for the equality of JSON objects, the ordering of keys is irrelevant\. If you\'re coming from JavaScript, please note that jq\'s \fB==\fR is like JavaScript\'s \fB===\fR, the "strict equality" operator\. . .P != is "not equal", and \'a != b\' returns the opposite value of \'a == b\' . .IP "" 4 . .nf jq \'\. == false\' null => false jq \'\. == {"b": {"d": (4 + 1e\-20), "c": 3}, "a":1}\' {"a":1, "b": {"c": 3, "d": 4}} => true jq \'\.[] == 1\' [1, 1\.0, "1", "banana"] => true, true, false, false . .fi . .IP "" 0 . .SS "if\-then\-else\-end" \fBif A then B else C end\fR will act the same as \fBB\fR if \fBA\fR produces a value other than false or null, but act the same as \fBC\fR otherwise\. . .P \fBif A then B end\fR is the same as \fBif A then B else \. end\fR\. That is, the \fBelse\fR branch is optional, and if absent is the same as \fB\.\fR\. This also applies to \fBelif\fR with absent ending \fBelse\fR branch\. . .P Checking for false or null is a simpler notion of "truthiness" than is found in JavaScript or Python, but it means that you\'ll sometimes have to be more explicit about the condition you want\. You can\'t test whether, e\.g\. a string is empty using \fBif \.name then A else B end\fR; you\'ll need something like \fBif \.name == "" then A else B end\fR instead\. . .P If the condition \fBA\fR produces multiple results, then \fBB\fR is evaluated once for each result that is not false or null, and \fBC\fR is evaluated once for each false or null\. . .P More cases can be added to an if using \fBelif A then B\fR syntax\. . .IP "" 4 . .nf jq \'if \. == 0 then "zero" elif \. == 1 then "one" else "many" end\' 2 => "many" . .fi . .IP "" 0 . .SS ">, >=, <=, <" The comparison operators \fB>\fR, \fB>=\fR, \fB<=\fR, \fB<\fR return whether their left argument is greater than, greater than or equal to, less than or equal to or less than their right argument (respectively)\. . .P The ordering is the same as that described for \fBsort\fR, above\. . .IP "" 4 . .nf jq \'\. < 5\' 2 => true . .fi . .IP "" 0 . .SS "and, or, not" jq supports the normal Boolean operators \fBand\fR, \fBor\fR, \fBnot\fR\. They have the same standard of truth as if expressions \- \fBfalse\fR and \fBnull\fR are considered "false values", and anything else is a "true value"\. . .P If an operand of one of these operators produces multiple results, the operator itself will produce a result for each input\. . .P \fBnot\fR is in fact a builtin function rather than an operator, so it is called as a filter to which things can be piped rather than with special syntax, as in \fB\.foo and \.bar | not\fR\. . .P These three only produce the values \fBtrue\fR and \fBfalse\fR, and so are only useful for genuine Boolean operations, rather than the common Perl/Python/Ruby idiom of "value_that_may_be_null or default"\. If you want to use this form of "or", picking between two values rather than evaluating a condition, see the \fB//\fR operator below\. . .IP "" 4 . .nf jq \'42 and "a string"\' null => true jq \'(true, false) or false\' null => true, false jq \'(true, true) and (true, false)\' null => true, false, true, false jq \'[true, false | not]\' null => [false, true] . .fi . .IP "" 0 . .SS "Alternative operator: //" The \fB//\fR operator produces all the values of its left\-hand side that are neither \fBfalse\fR nor \fBnull\fR\. If the left\-hand side produces no values other than \fBfalse\fR or \fBnull\fR, then \fB//\fR produces all the values of its right\-hand side\. . .P A filter of the form \fBa // b\fR produces all the results of \fBa\fR that are not \fBfalse\fR or \fBnull\fR\. If \fBa\fR produces no results, or no results other than \fBfalse\fR or \fBnull\fR, then \fBa // b\fR produces the results of \fBb\fR\. . .P This is useful for providing defaults: \fB\.foo // 1\fR will evaluate to \fB1\fR if there\'s no \fB\.foo\fR element in the input\. It\'s similar to how \fBor\fR is sometimes used in Python (jq\'s \fBor\fR operator is reserved for strictly Boolean operations)\. . .P Note: \fBsome_generator // defaults_here\fR is not the same as \fBsome_generator | \. // defaults_here\fR\. The latter will produce default values for all non\-\fBfalse\fR, non\-\fBnull\fR values of the left\-hand side, while the former will not\. Precedence rules can make this confusing\. For example, in \fBfalse, 1 // 2\fR the left\-hand side of \fB//\fR is \fB1\fR, not \fBfalse, 1\fR \-\- \fBfalse, 1 // 2\fR parses the same way as \fBfalse, (1 // 2)\fR\. In \fB(false, null, 1) | \. // 42\fR the left\-hand side of \fB//\fR is \fB\.\fR, which always produces just one value, while in \fB(false, null, 1) // 42\fR the left\-hand side is a generator of three values, and since it produces a value other \fBfalse\fR and \fBnull\fR, the default \fB42\fR is not produced\. . .IP "" 4 . .nf jq \'empty // 42\' null => 42 jq \'\.foo // 42\' {"foo": 19} => 19 jq \'\.foo // 42\' {} => 42 jq \'(false, null, 1) // 42\' null => 1 jq \'(false, null, 1) | \. // 42\' null => 42, 42, 1 . .fi . .IP "" 0 . .SS "try\-catch" Errors can be caught by using \fBtry EXP catch EXP\fR\. The first expression is executed, and if it fails then the second is executed with the error message\. The output of the handler, if any, is output as if it had been the output of the expression to try\. . .P The \fBtry EXP\fR form uses \fBempty\fR as the exception handler\. . .IP "" 4 . .nf jq \'try \.a catch "\. is not an object"\' true => "\. is not an object" jq \'[\.[]|try \.a]\' [{}, true, {"a":1}] => [null, 1] jq \'try error("some exception") catch \.\' true => "some exception" . .fi . .IP "" 0 . .SS "Breaking out of control structures" A convenient use of try/catch is to break out of control structures like \fBreduce\fR, \fBforeach\fR, \fBwhile\fR, and so on\. . .P For example: . .IP "" 4 . .nf # Repeat an expression until it raises "break" as an # error, then stop repeating without re\-raising the error\. # But if the error caught is not "break" then re\-raise it\. try repeat(exp) catch if \.=="break" then empty else error . .fi . .IP "" 0 . .P jq has a syntax for named lexical labels to "break" or "go (back) to": . .IP "" 4 . .nf label $out | \.\.\. break $out \.\.\. . .fi . .IP "" 0 . .P The \fBbreak $label_name\fR expression will cause the program to act as though the nearest (to the left) \fBlabel $label_name\fR produced \fBempty\fR\. . .P The relationship between the \fBbreak\fR and corresponding \fBlabel\fR is lexical: the label has to be "visible" from the break\. . .P To break out of a \fBreduce\fR, for example: . .IP "" 4 . .nf label $out | reduce \.[] as $item (null; if \.==false then break $out else \.\.\. end) . .fi . .IP "" 0 . .P The following jq program produces a syntax error: . .IP "" 4 . .nf break $out . .fi . .IP "" 0 . .P because no label \fB$out\fR is visible\. . .SS "Error Suppression / Optional Operator: ?" The \fB?\fR operator, used as \fBEXP?\fR, is shorthand for \fBtry EXP\fR\. . .IP "" 4 . .nf jq \'[\.[] | \.a?]\' [{}, true, {"a":1}] => [null, 1] jq \'[\.[] | tonumber?]\' ["1", "invalid", "3", 4] => [1, 3, 4] . .fi . .IP "" 0 . .SH "REGULAR EXPRESSIONS" jq uses the Oniguruma regular expression library, as do PHP, TextMate, Sublime Text, etc, so the description here will focus on jq specifics\. . .P Oniguruma supports several flavors of regular expression, so it is important to know that jq uses the "Perl NG" (Perl with named groups) flavor\. . .P The jq regex filters are defined so that they can be used using one of these patterns: . .IP "" 4 . .nf STRING | FILTER(REGEX) STRING | FILTER(REGEX; FLAGS) STRING | FILTER([REGEX]) STRING | FILTER([REGEX, FLAGS]) . .fi . .IP "" 0 . .P where: . .IP "\(bu" 4 STRING, REGEX, and FLAGS are jq strings and subject to jq string interpolation; . .IP "\(bu" 4 REGEX, after string interpolation, should be a valid regular expression; . .IP "\(bu" 4 FILTER is one of \fBtest\fR, \fBmatch\fR, or \fBcapture\fR, as described below\. . .IP "" 0 . .P Since REGEX must evaluate to a JSON string, some characters that are needed to form a regular expression must be escaped\. For example, the regular expression \fB\es\fR signifying a whitespace character would be written as \fB"\e\es"\fR\. . .P FLAGS is a string consisting of one of more of the supported flags: . .IP "\(bu" 4 \fBg\fR \- Global search (find all matches, not just the first) . .IP "\(bu" 4 \fBi\fR \- Case insensitive search . .IP "\(bu" 4 \fBm\fR \- Multi line mode (\fB\.\fR will match newlines) . .IP "\(bu" 4 \fBn\fR \- Ignore empty matches . .IP "\(bu" 4 \fBp\fR \- Both s and m modes are enabled . .IP "\(bu" 4 \fBs\fR \- Single line mode (\fB^\fR \-> \fB\eA\fR, \fB$\fR \-> \fB\eZ\fR) . .IP "\(bu" 4 \fBl\fR \- Find longest possible matches . .IP "\(bu" 4 \fBx\fR \- Extended regex format (ignore whitespace and comments) . .IP "" 0 . .P To match a whitespace with the \fBx\fR flag, use \fB\es\fR, e\.g\. . .IP "" 4 . .nf jq \-n \'"a b" | test("a\e\esb"; "x")\' . .fi . .IP "" 0 . .P Note that certain flags may also be specified within REGEX, e\.g\. . .IP "" 4 . .nf jq \-n \'("test", "TEst", "teST", "TEST") | test("(?i)te(?\-i)st")\' . .fi . .IP "" 0 . .P evaluates to: \fBtrue\fR, \fBtrue\fR, \fBfalse\fR, \fBfalse\fR\. . .SS "test(val), test(regex; flags)" Like \fBmatch\fR, but does not return match objects, only \fBtrue\fR or \fBfalse\fR for whether or not the regex matches the input\. . .IP "" 4 . .nf jq \'test("foo")\' "foo" => true jq \'\.[] | test("a b c # spaces are ignored"; "ix")\' ["xabcd", "ABC"] => true, true . .fi . .IP "" 0 . .SS "match(val), match(regex; flags)" \fBmatch\fR outputs an object for each match it finds\. Matches have the following fields: . .IP "\(bu" 4 \fBoffset\fR \- offset in UTF\-8 codepoints from the beginning of the input . .IP "\(bu" 4 \fBlength\fR \- length in UTF\-8 codepoints of the match . .IP "\(bu" 4 \fBstring\fR \- the string that it matched . .IP "\(bu" 4 \fBcaptures\fR \- an array of objects representing capturing groups\. . .IP "" 0 . .P Capturing group objects have the following fields: . .IP "\(bu" 4 \fBoffset\fR \- offset in UTF\-8 codepoints from the beginning of the input . .IP "\(bu" 4 \fBlength\fR \- length in UTF\-8 codepoints of this capturing group . .IP "\(bu" 4 \fBstring\fR \- the string that was captured . .IP "\(bu" 4 \fBname\fR \- the name of the capturing group (or \fBnull\fR if it was unnamed) . .IP "" 0 . .P Capturing groups that did not match anything return an offset of \-1 . .IP "" 4 . .nf jq \'match("(abc)+"; "g")\' "abc abc" => {"offset": 0, "length": 3, "string": "abc", "captures": [{"offset": 0, "length": 3, "string": "abc", "name": null}]}, {"offset": 4, "length": 3, "string": "abc", "captures": [{"offset": 4, "length": 3, "string": "abc", "name": null}]} jq \'match("foo")\' "foo bar foo" => {"offset": 0, "length": 3, "string": "foo", "captures": []} jq \'match(["foo", "ig"])\' "foo bar FOO" => {"offset": 0, "length": 3, "string": "foo", "captures": []}, {"offset": 8, "length": 3, "string": "FOO", "captures": []} jq \'match("foo (?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"}]} jq \'[ match("\."; "g")] | length\' "abc" => 3 . .fi . .IP "" 0 . .SS "capture(val), capture(regex; flags)" Collects the named captures in a JSON object, with the name of each capture as the key, and the matched string as the corresponding value\. . .IP "" 4 . .nf jq \'capture("(?[a\-z]+)\-(?[0\-9]+)")\' "xyzzy\-14" => { "a": "xyzzy", "n": "14" } . .fi . .IP "" 0 . .SS "scan(regex), scan(regex; flags)" Emit a stream of the non\-overlapping substrings of the input that match the regex in accordance with the flags, if any have been specified\. If there is no match, the stream is empty\. To capture all the matches for each input string, use the idiom \fB[ expr ]\fR, e\.g\. \fB[ scan(regex) ]\fR\. If the regex contains capturing groups, the filter emits a stream of arrays, each of which contains the captured strings\. . .IP "" 4 . .nf jq \'scan("c")\' "abcdefabc" => "c", "c" jq \'scan("(a+)(b+)")\' "abaabbaaabbb" => ["a","b"], ["aa","bb"], ["aaa","bbb"] . .fi . .IP "" 0 . .SS "split(regex; flags)" Splits an input string on each regex match\. . .P For backwards compatibility, when called with a single argument, \fBsplit\fR splits on a string, not a regex\. . .IP "" 4 . .nf jq \'split(", *"; null)\' "ab,cd, ef" => ["ab","cd","ef"] . .fi . .IP "" 0 . .SS "splits(regex), splits(regex; flags)" These provide the same results as their \fBsplit\fR counterparts, but as a stream instead of an array\. . .IP "" 4 . .nf jq \'splits(", *")\' "ab,cd, ef, gh" => "ab", "cd", "ef", "gh" jq \'splits(",? *"; "n")\' "ab,cd ef, gh" => "ab", "cd", "ef", "gh" . .fi . .IP "" 0 . .SS "sub(regex; tostring), sub(regex; tostring; flags)" Emit the string obtained by replacing the first match of regex in the input string with \fBtostring\fR, after interpolation\. \fBtostring\fR should be a jq string or a stream of such strings, each of which may contain references to named captures\. The named captures are, in effect, presented as a JSON object (as constructed by \fBcapture\fR) to \fBtostring\fR, so a reference to a captured variable named "x" would take the form: \fB"\e(\.x)"\fR\. . .IP "" 4 . .nf jq \'sub("[^a\-z]*(?[a\-z]+)"; "Z\e(\.x)"; "g")\' "123abc456def" => "ZabcZdef" jq \'[sub("(?\.)"; "\e(\.a|ascii_upcase)", "\e(\.a|ascii_downcase)")]\' "aB" => ["AB","aB"] . .fi . .IP "" 0 . .SS "gsub(regex; tostring), gsub(regex; tostring; flags)" \fBgsub\fR is like \fBsub\fR but all the non\-overlapping occurrences of the regex are replaced by \fBtostring\fR, after interpolation\. If the second argument is a stream of jq strings, then \fBgsub\fR will produce a corresponding stream of JSON strings\. . .IP "" 4 . .nf jq \'gsub("(?\.)[^a]*"; "+\e(\.x)\-")\' "Abcabc" => "+A\-+a\-" jq \'[gsub("p"; "a", "b")]\' "p" => ["a","b"] . .fi . .IP "" 0 . .SH "ADVANCED FEATURES" Variables are an absolute necessity in most programming languages, but they\'re relegated to an "advanced feature" in jq\. . .P In most languages, variables are the only means of passing around data\. If you calculate a value, and you want to use it more than once, you\'ll need to store it in a variable\. To pass a value to another part of the program, you\'ll need that part of the program to define a variable (as a function parameter, object member, or whatever) in which to place the data\. . .P It is also possible to define functions in jq, although this is is a feature whose biggest use is defining jq\'s standard library (many jq functions such as \fBmap\fR and \fBselect\fR are in fact written in jq)\. . .P jq has reduction operators, which are very powerful but a bit tricky\. Again, these are mostly used internally, to define some useful bits of jq\'s standard library\. . .P It may not be obvious at first, but jq is all about generators (yes, as often found in other languages)\. Some utilities are provided to help deal with generators\. . .P Some minimal I/O support (besides reading JSON from standard input, and writing JSON to standard output) is available\. . .P Finally, there is a module/library system\. . .SS "Variable / Symbolic Binding Operator: \.\.\. as $identifier | \.\.\." In jq, all filters have an input and an output, so manual plumbing is not necessary to pass a value from one part of a program to the next\. Many expressions, for instance \fBa + b\fR, pass their input to two distinct subexpressions (here \fBa\fR and \fBb\fR are both passed the same input), so variables aren\'t usually necessary in order to use a value twice\. . .P For instance, calculating the average value of an array of numbers requires a few variables in most languages \- at least one to hold the array, perhaps one for each element or for a loop counter\. In jq, it\'s simply \fBadd / length\fR \- the \fBadd\fR expression is given the array and produces its sum, and the \fBlength\fR expression is given the array and produces its length\. . .P So, there\'s generally a cleaner way to solve most problems in jq than defining variables\. Still, sometimes they do make things easier, so jq lets you define variables using \fBexpression as $variable\fR\. All variable names start with \fB$\fR\. Here\'s a slightly uglier version of the array\-averaging example: . .IP "" 4 . .nf length as $array_length | add / $array_length . .fi . .IP "" 0 . .P We\'ll need a more complicated problem to find a situation where using variables actually makes our lives easier\. . .P Suppose we have an array of blog posts, with "author" and "title" fields, and another object which is used to map author usernames to real names\. Our input looks like: . .IP "" 4 . .nf {"posts": [{"title": "First post", "author": "anon"}, {"title": "A well\-written article", "author": "person1"}], "realnames": {"anon": "Anonymous Coward", "person1": "Person McPherson"}} . .fi . .IP "" 0 . .P We want to produce the posts with the author field containing a real name, as in: . .IP "" 4 . .nf {"title": "First post", "author": "Anonymous Coward"} {"title": "A well\-written article", "author": "Person McPherson"} . .fi . .IP "" 0 . .P We use a variable, \fB$names\fR, to store the realnames object, so that we can refer to it later when looking up author usernames: . .IP "" 4 . .nf \&.realnames as $names | \.posts[] | {title, author: $names[\.author]} . .fi . .IP "" 0 . .P The expression \fBexp as $x | \.\.\.\fR means: for each value of expression \fBexp\fR, run the rest of the pipeline with the entire original input, and with \fB$x\fR set to that value\. Thus \fBas\fR functions as something of a foreach loop\. . .P Just as \fB{foo}\fR is a handy way of writing \fB{foo: \.foo}\fR, so \fB{$foo}\fR is a handy way of writing \fB{foo: $foo}\fR\. . .P Multiple variables may be declared using a single \fBas\fR expression by providing a pattern that matches the structure of the input (this is known as "destructuring"): . .IP "" 4 . .nf \&. as {realnames: $names, posts: [$first, $second]} | \.\.\. . .fi . .IP "" 0 . .P The variable declarations in array patterns (e\.g\., \fB\. as [$first, $second]\fR) bind to the elements of the array in from the element at index zero on up, in order\. When there is no value at the index for an array pattern element, \fBnull\fR is bound to that variable\. . .P Variables are scoped over the rest of the expression that defines them, so . .IP "" 4 . .nf \&.realnames as $names | (\.posts[] | {title, author: $names[\.author]}) . .fi . .IP "" 0 . .P will work, but . .IP "" 4 . .nf (\.realnames as $names | \.posts[]) | {title, author: $names[\.author]} . .fi . .IP "" 0 . .P won\'t\. . .P For programming language theorists, it\'s more accurate to say that jq variables are lexically\-scoped bindings\. In particular there\'s no way to change the value of a binding; one can only setup a new binding with the same name, but which will not be visible where the old one was\. . .IP "" 4 . .nf jq \'\.bar as $x | \.foo | \. + $x\' {"foo":10, "bar":200} => 210 jq \'\. as $i|[(\.*2|\. as $i| $i), $i]\' 5 => [10,5] jq \'\. as [$a, $b, {c: $c}] | $a + $b + $c\' [2, 3, {"c": 4, "d": 5}] => 9 jq \'\.[] as [$a, $b] | {a: $a, b: $b}\' [[0], [0, 1], [2, 1, 0]] => {"a":0,"b":null}, {"a":0,"b":1}, {"a":2,"b":1} . .fi . .IP "" 0 . .SS "Destructuring Alternative Operator: ?//" The destructuring alternative operator provides a concise mechanism for destructuring an input that can take one of several forms\. . .P Suppose we have an API that returns a list of resources and events associated with them, and we want to get the user_id and timestamp of the first event for each resource\. The API (having been clumsily converted from XML) will only wrap the events in an array if the resource has multiple events: . .IP "" 4 . .nf {"resources": [{"id": 1, "kind": "widget", "events": {"action": "create", "user_id": 1, "ts": 13}}, {"id": 2, "kind": "widget", "events": [{"action": "create", "user_id": 1, "ts": 14}, {"action": "destroy", "user_id": 1, "ts": 15}]}]} . .fi . .IP "" 0 . .P We can use the destructuring alternative operator to handle this structural change simply: . .IP "" 4 . .nf \&.resources[] as {$id, $kind, events: {$user_id, $ts}} ?// {$id, $kind, events: [{$user_id, $ts}]} | {$user_id, $kind, $id, $ts} . .fi . .IP "" 0 . .P Or, if we aren\'t sure if the input is an array of values or an object: . .IP "" 4 . .nf \&.[] as [$id, $kind, $user_id, $ts] ?// {$id, $kind, $user_id, $ts} | \.\.\. . .fi . .IP "" 0 . .P Each alternative need not define all of the same variables, but all named variables will be available to the subsequent expression\. Variables not matched in the alternative that succeeded will be \fBnull\fR: . .IP "" 4 . .nf \&.resources[] as {$id, $kind, events: {$user_id, $ts}} ?// {$id, $kind, events: [{$first_user_id, $first_ts}]} | {$user_id, $first_user_id, $kind, $id, $ts, $first_ts} . .fi . .IP "" 0 . .P Additionally, if the subsequent expression returns an error, the alternative operator will attempt to try the next binding\. Errors that occur during the final alternative are passed through\. . .IP "" 4 . .nf [[3]] | \.[] as [$a] ?// [$b] | if $a != null then error("err: \e($a)") else {$a,$b} end jq \'\.[] as {$a, $b, c: {$d, $e}} ?// {$a, $b, c: [{$d, $e}]} | {$a, $b, $d, $e}\' [{"a": 1, "b": 2, "c": {"d": 3, "e": 4}}, {"a": 1, "b": 2, "c": [{"d": 3, "e": 4}]}] => {"a":1,"b":2,"d":3,"e":4}, {"a":1,"b":2,"d":3,"e":4} jq \'\.[] as {$a, $b, c: {$d}} ?// {$a, $b, c: [{$e}]} | {$a, $b, $d, $e}\' [{"a": 1, "b": 2, "c": {"d": 3, "e": 4}}, {"a": 1, "b": 2, "c": [{"d": 3, "e": 4}]}] => {"a":1,"b":2,"d":3,"e":null}, {"a":1,"b":2,"d":null,"e":4} jq \'\.[] as [$a] ?// [$b] | if $a != null then error("err: \e($a)") else {$a,$b} end\' [[3]] => {"a":null,"b":3} . .fi . .IP "" 0 . .SS "Defining Functions" You can give a filter a name using "def" syntax: . .IP "" 4 . .nf def increment: \. + 1; . .fi . .IP "" 0 . .P From then on, \fBincrement\fR is usable as a filter just like a builtin function (in fact, this is how many of the builtins are defined)\. A function may take arguments: . .IP "" 4 . .nf def map(f): [\.[] | f]; . .fi . .IP "" 0 . .P Arguments are passed as \fIfilters\fR (functions with no arguments), \fInot\fR as values\. The same argument may be referenced multiple times with different inputs (here \fBf\fR is run for each element of the input array)\. Arguments to a function work more like callbacks than like value arguments\. This is important to understand\. Consider: . .IP "" 4 . .nf def foo(f): f|f; 5|foo(\.*2) . .fi . .IP "" 0 . .P The result will be 20 because \fBf\fR is \fB\.*2\fR, and during the first invocation of \fBf\fR \fB\.\fR will be 5, and the second time it will be 10 (5 * 2), so the result will be 20\. Function arguments are filters, and filters expect an input when invoked\. . .P If you want the value\-argument behaviour for defining simple functions, you can just use a variable: . .IP "" 4 . .nf def addvalue(f): f as $f | map(\. + $f); . .fi . .IP "" 0 . .P Or use the short\-hand: . .IP "" 4 . .nf def addvalue($f): \.\.\.; . .fi . .IP "" 0 . .P With either definition, \fBaddvalue(\.foo)\fR will add the current input\'s \fB\.foo\fR field to each element of the array\. Do note that calling \fBaddvalue(\.[])\fR will cause the \fBmap(\. + $f)\fR part to be evaluated once per value in the value of \fB\.\fR at the call site\. . .P Multiple definitions using the same function name are allowed\. Each re\-definition replaces the previous one for the same number of function arguments, but only for references from functions (or main program) subsequent to the re\-definition\. See also the section below on scoping\. . .IP "" 4 . .nf jq \'def addvalue(f): \. + [f]; map(addvalue(\.[0]))\' [[1,2],[10,20]] => [[1,2,1], [10,20,10]] jq \'def addvalue(f): f as $x | map(\. + $x); addvalue(\.[0])\' [[1,2],[10,20]] => [[1,2,1,2], [10,20,1,2]] . .fi . .IP "" 0 . .SS "Scoping" There are two types of symbols in jq: value bindings (a\.k\.a\., "variables"), and functions\. Both are scoped lexically, with expressions being able to refer only to symbols that have been defined "to the left" of them\. The only exception to this rule is that functions can refer to themselves so as to be able to create recursive functions\. . .P For example, in the following expression there is a binding which is visible "to the right" of it, \fB\.\.\. | \.*3 as $times_three | [\. + $times_three] | \.\.\.\fR, but not "to the left"\. Consider this expression now, \fB\.\.\. | (\.*3 as $times_three | [\. + $times_three]) | \.\.\.\fR: here the binding \fB$times_three\fR is \fInot\fR visible past the closing parenthesis\. . .SS "isempty(exp)" Returns true if \fBexp\fR produces no outputs, false otherwise\. . .IP "" 4 . .nf jq \'isempty(empty)\' null => true jq \'isempty(\.[])\' [] => true jq \'isempty(\.[])\' [1,2,3] => false . .fi . .IP "" 0 . .SS "limit(n; expr)" The \fBlimit\fR function extracts up to \fBn\fR outputs from \fBexpr\fR\. . .IP "" 4 . .nf jq \'[limit(3; \.[])]\' [0,1,2,3,4,5,6,7,8,9] => [0,1,2] . .fi . .IP "" 0 . .SS "skip(n; expr)" The \fBskip\fR function skips the first \fBn\fR outputs from \fBexpr\fR\. . .IP "" 4 . .nf jq \'[skip(3; \.[])]\' [0,1,2,3,4,5,6,7,8,9] => [3,4,5,6,7,8,9] . .fi . .IP "" 0 . .SS "first(expr), last(expr), nth(n; expr)" The \fBfirst(expr)\fR and \fBlast(expr)\fR functions extract the first and last values from \fBexpr\fR, respectively\. . .P The \fBnth(n; expr)\fR function extracts the nth value output by \fBexpr\fR\. Note that \fBnth(n; expr)\fR doesn\'t support negative values of \fBn\fR\. . .IP "" 4 . .nf jq \'[first(range(\.)), last(range(\.)), nth(5; range(\.))]\' 10 => [0,9,5] jq \'[first(empty), last(empty), nth(5; empty)]\' null => [] . .fi . .IP "" 0 . .SS "first, last, nth(n)" The \fBfirst\fR and \fBlast\fR functions extract the first and last values from any array at \fB\.\fR\. . .P The \fBnth(n)\fR function extracts the nth value of any array at \fB\.\fR\. . .IP "" 4 . .nf jq \'[range(\.)]|[first, last, nth(5)]\' 10 => [0,9,5] . .fi . .IP "" 0 . .SS "reduce" The \fBreduce\fR syntax allows you to combine all of the results of an expression by accumulating them into a single answer\. The form is \fBreduce EXP as $var (INIT; UPDATE)\fR\. As an example, we\'ll pass \fB[1,2,3]\fR to this expression: . .IP "" 4 . .nf reduce \.[] as $item (0; \. + $item) . .fi . .IP "" 0 . .P For each result that \fB\.[]\fR produces, \fB\. + $item\fR is run to accumulate a running total, starting from 0 as the input value\. In this example, \fB\.[]\fR produces the results \fB1\fR, \fB2\fR, and \fB3\fR, so the effect is similar to running something like this: . .IP "" 4 . .nf 0 | 1 as $item | \. + $item | 2 as $item | \. + $item | 3 as $item | \. + $item jq \'reduce \.[] as $item (0; \. + $item)\' [1,2,3,4,5] => 15 jq \'reduce \.[] as [$i,$j] (0; \. + $i * $j)\' [[1,2],[3,4],[5,6]] => 44 jq \'reduce \.[] as {$x,$y} (null; \.x += $x | \.y += [$y])\' [{"x":"a","y":1},{"x":"b","y":2},{"x":"c","y":3}] => {"x":"abc","y":[1,2,3]} . .fi . .IP "" 0 . .SS "foreach" The \fBforeach\fR syntax is similar to \fBreduce\fR, but intended to allow the construction of \fBlimit\fR and reducers that produce intermediate results\. . .P The form is \fBforeach EXP as $var (INIT; UPDATE; EXTRACT)\fR\. As an example, we\'ll pass \fB[1,2,3]\fR to this expression: . .IP "" 4 . .nf foreach \.[] as $item (0; \. + $item; [$item, \. * 2]) . .fi . .IP "" 0 . .P Like the \fBreduce\fR syntax, \fB\. + $item\fR is run for each result that \fB\.[]\fR produces, but \fB[$item, \. * 2]\fR is run for each intermediate values\. In this example, since the intermediate values are \fB1\fR, \fB3\fR, and \fB6\fR, the \fBforeach\fR expression produces \fB[1,2]\fR, \fB[2,6]\fR, and \fB[3,12]\fR\. So the effect is similar to running something like this: . .IP "" 4 . .nf 0 | 1 as $item | \. + $item | [$item, \. * 2], 2 as $item | \. + $item | [$item, \. * 2], 3 as $item | \. + $item | [$item, \. * 2] . .fi . .IP "" 0 . .P When \fBEXTRACT\fR is omitted, the identity filter is used\. That is, it outputs the intermediate values as they are\. . .IP "" 4 . .nf jq \'foreach \.[] as $item (0; \. + $item)\' [1,2,3,4,5] => 1, 3, 6, 10, 15 jq \'foreach \.[] as $item (0; \. + $item; [$item, \. * 2])\' [1,2,3,4,5] => [1,2], [2,6], [3,12], [4,20], [5,30] jq \'foreach \.[] as $item (0; \. + 1; {index: \., $item})\' ["foo", "bar", "baz"] => {"index":1,"item":"foo"}, {"index":2,"item":"bar"}, {"index":3,"item":"baz"} . .fi . .IP "" 0 . .SS "Recursion" As described above, \fBrecurse\fR uses recursion, and any jq function can be recursive\. The \fBwhile\fR builtin is also implemented in terms of recursion\. . .P Tail calls are optimized whenever the expression to the left of the recursive call outputs its last value\. In practice this means that the expression to the left of the recursive call should not produce more than one output for each input\. . .P For example: . .IP "" 4 . .nf def recurse(f): def r: \., (f | select(\. != null) | r); r; def while(cond; update): def _while: if cond then \., (update | _while) else empty end; _while; def repeat(exp): def _repeat: exp, _repeat; _repeat; . .fi . .IP "" 0 . .SS "Generators and iterators" Some jq operators and functions are actually generators in that they can produce zero, one, or more values for each input, just as one might expect in other programming languages that have generators\. For example, \fB\.[]\fR generates all the values in its input (which must be an array or an object), \fBrange(0; 10)\fR generates the integers between 0 and 10, and so on\. . .P Even the comma operator is a generator, generating first the values generated by the expression to the left of the comma, then the values generated by the expression on the right of the comma\. . .P The \fBempty\fR builtin is the generator that produces zero outputs\. The \fBempty\fR builtin backtracks to the preceding generator expression\. . .P All jq functions can be generators just by using builtin generators\. It is also possible to construct new generators using only recursion and the comma operator\. If recursive calls are "in tail position" then the generator will be efficient\. In the example below the recursive call by \fB_range\fR to itself is in tail position\. The example shows off three advanced topics: tail recursion, generator construction, and sub\-functions\. . .IP "" 4 . .nf jq \'def range(init; upto; by): def _range: if (by > 0 and \. < upto) or (by < 0 and \. > upto) then \., ((\.+by)|_range) else empty end; if init == upto then empty elif by == 0 then init else init|_range end; range(0; 10; 3)\' null => 0, 3, 6, 9 jq \'def while(cond; update): def _while: if cond then \., (update | _while) else empty end; _while; [while(\.<100; \.*2)]\' 1 => [1,2,4,8,16,32,64] . .fi . .IP "" 0 . .SH "MATH" jq currently only has IEEE754 double\-precision (64\-bit) floating point number support\. . .P Besides simple arithmetic operators such as \fB+\fR, jq also has most standard math functions from the C math library\. C math functions that take a single input argument (e\.g\., \fBsin()\fR) are available as zero\-argument jq functions\. C math functions that take two input arguments (e\.g\., \fBpow()\fR) are available as two\-argument jq functions that ignore \fB\.\fR\. C math functions that take three input arguments are available as three\-argument jq functions that ignore \fB\.\fR\. . .P Availability of standard math functions depends on the availability of the corresponding math functions in your operating system and C math library\. Unavailable math functions will be defined but will raise an error\. . .P One\-input C math functions: \fBacos\fR \fBacosh\fR \fBasin\fR \fBasinh\fR \fBatan\fR \fBatanh\fR \fBcbrt\fR \fBceil\fR \fBcos\fR \fBcosh\fR \fBerf\fR \fBerfc\fR \fBexp\fR \fBexp10\fR \fBexp2\fR \fBexpm1\fR \fBfabs\fR \fBfloor\fR \fBgamma\fR \fBj0\fR \fBj1\fR \fBlgamma\fR \fBlog\fR \fBlog10\fR \fBlog1p\fR \fBlog2\fR \fBlogb\fR \fBnearbyint\fR \fBrint\fR \fBround\fR \fBsignificand\fR \fBsin\fR \fBsinh\fR \fBsqrt\fR \fBtan\fR \fBtanh\fR \fBtgamma\fR \fBtrunc\fR \fBy0\fR \fBy1\fR\. . .P Two\-input C math functions: \fBatan2\fR \fBcopysign\fR \fBdrem\fR \fBfdim\fR \fBfmax\fR \fBfmin\fR \fBfmod\fR \fBfrexp\fR \fBhypot\fR \fBjn\fR \fBldexp\fR \fBmodf\fR \fBnextafter\fR \fBnexttoward\fR \fBpow\fR \fBremainder\fR \fBscalb\fR \fBscalbln\fR \fByn\fR\. . .P Three\-input C math functions: \fBfma\fR\. . .P See your system\'s manual for more information on each of these\. . .SH "I/O" At this time jq has minimal support for I/O, mostly in the form of control over when inputs are read\. Two builtins functions are provided for this, \fBinput\fR and \fBinputs\fR, that read from the same sources (e\.g\., \fBstdin\fR, files named on the command\-line) as jq itself\. These two builtins, and jq\'s own reading actions, can be interleaved with each other\. They are commonly used in combination with the null input option \fB\-n\fR to prevent one input from being read implicitly\. . .P Two builtins provide minimal output capabilities, \fBdebug\fR, and \fBstderr\fR\. (Recall that a jq program\'s output values are always output as JSON texts on \fBstdout\fR\.) The \fBdebug\fR builtin can have application\-specific behavior, such as for executables that use the libjq C API but aren\'t the jq executable itself\. The \fBstderr\fR builtin outputs its input in raw mode to stderr with no additional decoration, not even a newline\. . .P Most jq builtins are referentially transparent, and yield constant and repeatable value streams when applied to constant inputs\. This is not true of I/O builtins\. . .SS "input" Outputs one new input\. . .P Note that when using \fBinput\fR it is generally necessary to invoke jq with the \fB\-n\fR command\-line option, otherwise the first entity will be lost\. . .IP "" 4 . .nf echo 1 2 3 4 | jq \'[\., input]\' # [1,2] [3,4] . .fi . .IP "" 0 . .SS "inputs" Outputs all remaining inputs, one by one\. . .P This is primarily useful for reductions over a program\'s inputs\. Note that when using \fBinputs\fR it is generally necessary to invoke jq with the \fB\-n\fR command\-line option, otherwise the first entity will be lost\. . .IP "" 4 . .nf echo 1 2 3 | jq \-n \'reduce inputs as $i (0; \. + $i)\' # 6 . .fi . .IP "" 0 . .SS "debug, debug(msgs)" These two filters are like \fB\.\fR but have as a side\-effect the production of one or more messages on stderr\. . .P The message produced by the \fBdebug\fR filter has the form . .IP "" 4 . .nf ["DEBUG:",] . .fi . .IP "" 0 . .P where \fB\fR is a compact rendition of the input value\. This format may change in the future\. . .P The \fBdebug(msgs)\fR filter is defined as \fB(msgs | debug | empty), \.\fR thus allowing great flexibility in the content of the message, while also allowing multi\-line debugging statements to be created\. . .P For example, the expression: . .IP "" 4 . .nf 1 as $x | 2 | debug("Entering function foo with $x == \e($x)", \.) | (\.+1) . .fi . .IP "" 0 . .P would produce the value 3 but with the following two lines being written to stderr: . .IP "" 4 . .nf ["DEBUG:","Entering function foo with $x == 1"] ["DEBUG:",2] . .fi . .IP "" 0 . .SS "stderr" Prints its input in raw and compact mode to stderr with no additional decoration, not even a newline\. . .SS "input_filename" Returns the name of the file whose input is currently being filtered\. Note that this will not work well unless jq is running in a UTF\-8 locale\. . .SS "input_line_number" Returns the line number of the input currently being filtered\. . .SH "STREAMING" With the \fB\-\-stream\fR option jq can parse input texts in a streaming fashion, allowing jq programs to start processing large JSON texts immediately rather than after the parse completes\. If you have a single JSON text that is 1GB in size, streaming it will allow you to process it much more quickly\. . .P However, streaming isn\'t easy to deal with as the jq program will have \fB[, ]\fR (and a few other forms) as inputs\. . .P Several builtins are provided to make handling streams easier\. . .P The examples below use the streamed form of \fB["a",["b"]]\fR, which is \fB[[0],"a"],[[1,0],"b"],[[1,0]],[[1]]\fR\. . .P Streaming forms include \fB[, ]\fR (to indicate any scalar value, empty array, or empty object), and \fB[]\fR (to indicate the end of an array or object)\. Future versions of jq run with \fB\-\-stream\fR and \fB\-\-seq\fR may output additional forms such as \fB["error message"]\fR when an input text fails to parse\. . .SS "truncate_stream(stream_expression)" Consumes a number as input and truncates the corresponding number of path elements from the left of the outputs of the given streaming expression\. . .IP "" 4 . .nf jq \'truncate_stream([[0],"a"],[[1,0],"b"],[[1,0]],[[1]])\' 1 => [[0],"b"], [[0]] . .fi . .IP "" 0 . .SS "fromstream(stream_expression)" Outputs values corresponding to the stream expression\'s outputs\. . .IP "" 4 . .nf jq \'fromstream(1|truncate_stream([[0],"a"],[[1,0],"b"],[[1,0]],[[1]]))\' null => ["b"] . .fi . .IP "" 0 . .SS "tostream" The \fBtostream\fR builtin outputs the streamed form of its input\. . .IP "" 4 . .nf jq \'\. as $dot|fromstream($dot|tostream)|\.==$dot\' [0,[1,{"a":1},{"b":2}]] => true . .fi . .IP "" 0 . .SH "ASSIGNMENT" Assignment works a little differently in jq than in most programming languages\. jq doesn\'t distinguish between references to and copies of something \- two objects or arrays are either equal or not equal, without any further notion of being "the same object" or "not the same object"\. . .P If an object has two fields which are arrays, \fB\.foo\fR and \fB\.bar\fR, and you append something to \fB\.foo\fR, then \fB\.bar\fR will not get bigger, even if you\'ve previously set \fB\.bar = \.foo\fR\. If you\'re used to programming in languages like Python, Java, Ruby, JavaScript, etc\. then you can think of it as though jq does a full deep copy of every object before it does the assignment (for performance it doesn\'t actually do that, but that\'s the general idea)\. . .P This means that it\'s impossible to build circular values in jq (such as an array whose first element is itself)\. This is quite intentional, and ensures that anything a jq program can produce can be represented in JSON\. . .P All the assignment operators in jq have path expressions on the left\-hand side (LHS)\. The right\-hand side (RHS) provides values to set to the paths named by the LHS path expressions\. . .P Values in jq are always immutable\. Internally, assignment works by using a reduction to compute new, replacement values for \fB\.\fR that have had all the desired assignments applied to \fB\.\fR, then outputting the modified value\. This might be made clear by this example: \fB{a:{b:{c:1}}} | (\.a\.b|=3), \.\fR\. This will output \fB{"a":{"b":3}}\fR and \fB{"a":{"b":{"c":1}}}\fR because the last sub\-expression, \fB\.\fR, sees the original value, not the modified value\. . .P Most users will want to use modification assignment operators, such as \fB|=\fR or \fB+=\fR, rather than \fB=\fR\. . .P Note that the LHS of assignment operators refers to a value in \fB\.\fR\. Thus \fB$var\.foo = 1\fR won\'t work as expected (\fB$var\.foo\fR is not a valid or useful path expression in \fB\.\fR); use \fB$var | \.foo = 1\fR instead\. . .P Note too that \fB\.a,\.b=0\fR does not set \fB\.a\fR and \fB\.b\fR, but \fB(\.a,\.b)=0\fR sets both\. . .SS "Update\-assignment: |=" This is the "update" operator \fB|=\fR\. It takes a filter on the right\-hand side and works out the new value for the property of \fB\.\fR being assigned to by running the old value through this expression\. For instance, \fB(\.foo, \.bar) |= \.+1\fR will build an object with the \fBfoo\fR field set to the input\'s \fBfoo\fR plus 1, and the \fBbar\fR field set to the input\'s \fBbar\fR plus 1\. . .P The left\-hand side can be any general path expression; see \fBpath()\fR\. . .P Note that the left\-hand side of \fB|=\fR refers to a value in \fB\.\fR\. Thus \fB$var\.foo |= \. + 1\fR won\'t work as expected (\fB$var\.foo\fR is not a valid or useful path expression in \fB\.\fR); use \fB$var | \.foo |= \. + 1\fR instead\. . .P If the right\-hand side outputs no values (i\.e\., \fBempty\fR), then the left\-hand side path will be deleted, as with \fBdel(path)\fR\. . .P If the right\-hand side outputs multiple values, only the first one will be used (COMPATIBILITY NOTE: in jq 1\.5 and earlier releases, it used to be that only the last one was used)\. . .IP "" 4 . .nf jq \'(\.\.|select(type=="boolean")) |= if \. then 1 else 0 end\' [true,false,[5,true,[true,[false]],false]] => [1,0,[5,1,[1,[0]],0]] . .fi . .IP "" 0 . .SS "Arithmetic update\-assignment: +=, \-=, *=, /=, %=, //=" jq has a few operators of the form \fBa op= b\fR, which are all equivalent to \fBa |= \. op b\fR\. So, \fB+= 1\fR can be used to increment values, being the same as \fB|= \. + 1\fR\. . .IP "" 4 . .nf jq \'\.foo += 1\' {"foo": 42} => {"foo": 43} . .fi . .IP "" 0 . .SS "Plain assignment: =" This is the plain assignment operator\. Unlike the others, the input to the right\-hand side (RHS) is the same as the input to the left\-hand side (LHS) rather than the value at the LHS path, and all values output by the RHS will be used (as shown below)\. . .P If the RHS of \fB=\fR produces multiple values, then for each such value jq will set the paths on the left\-hand side to the value and then it will output the modified \fB\.\fR\. For example, \fB(\.a,\.b) = range(2)\fR outputs \fB{"a":0,"b":0}\fR, then \fB{"a":1,"b":1}\fR\. The "update" assignment forms (see above) do not do this\. . .P This example should show the difference between \fB=\fR and \fB|=\fR: . .P Provide input \fB{"a": {"b": 10}, "b": 20}\fR to the programs . .IP "" 4 . .nf \&.a = \.b . .fi . .IP "" 0 . .P and . .IP "" 4 . .nf \&.a |= \.b . .fi . .IP "" 0 . .P The former will set the \fBa\fR field of the input to the \fBb\fR field of the input, and produce the output \fB{"a": 20, "b": 20}\fR\. The latter will set the \fBa\fR field of the input to the \fBa\fR field\'s \fBb\fR field, producing \fB{"a": 10, "b": 20}\fR\. . .IP "" 4 . .nf jq \'\.a = \.b\' {"a": {"b": 10}, "b": 20} => {"a":20,"b":20} jq \'\.a |= \.b\' {"a": {"b": 10}, "b": 20} => {"a":10,"b":20} jq \'(\.a, \.b) = range(3)\' null => {"a":0,"b":0}, {"a":1,"b":1}, {"a":2,"b":2} jq \'(\.a, \.b) |= range(3)\' null => {"a":0,"b":0} . .fi . .IP "" 0 . .SS "Complex assignments" Lots more things are allowed on the left\-hand side of a jq assignment than in most languages\. We\'ve already seen simple field accesses on the left hand side, and it\'s no surprise that array accesses work just as well: . .IP "" 4 . .nf \&.posts[0]\.title = "JQ Manual" . .fi . .IP "" 0 . .P What may come as a surprise is that the expression on the left may produce multiple results, referring to different points in the input document: . .IP "" 4 . .nf \&.posts[]\.comments |= \. + ["this is great"] . .fi . .IP "" 0 . .P That example appends the string "this is great" to the "comments" array of each post in the input (where the input is an object with a field "posts" which is an array of posts)\. . .P When jq encounters an assignment like \'a = b\', it records the "path" taken to select a part of the input document while executing a\. This path is then used to find which part of the input to change while executing the assignment\. Any filter may be used on the left\-hand side of an equals \- whichever paths it selects from the input will be where the assignment is performed\. . .P This is a very powerful operation\. Suppose we wanted to add a comment to blog posts, using the same "blog" input above\. This time, we only want to comment on the posts written by "stedolan"\. We can find those posts using the "select" function described earlier: . .IP "" 4 . .nf \&.posts[] | select(\.author == "stedolan") . .fi . .IP "" 0 . .P The paths provided by this operation point to each of the posts that "stedolan" wrote, and we can comment on each of them in the same way that we did before: . .IP "" 4 . .nf (\.posts[] | select(\.author == "stedolan") | \.comments) |= \. + ["terrible\."] . .fi . .IP "" 0 . .SH "COMMENTS" You can write comments in your jq filters using \fB#\fR\. . .P A \fB#\fR character (not part of a string) starts a comment\. All characters from \fB#\fR to the end of the line are ignored\. . .P If the end of the line is preceded by an odd number of backslash characters, the following line is also considered part of the comment and is ignored\. . .P For example, the following code outputs \fB[1,3,4,7]\fR . .IP "" 4 . .nf [ 1, # foo \e 2, # bar \e\e 3, 4, # baz \e\e\e 5, \e 6, 7 # comment \e comment \e comment ] . .fi . .IP "" 0 . .P Backslash continuing the comment on the next line can be useful when writing the "shebang" for a jq script: . .IP "" 4 . .nf #!/bin/sh \-\- # total \- Output the sum of the given arguments (or stdin) # usage: total [numbers\.\.\.] # \e exec jq \-\-args \-MRnf \-\- "$0" "$@" $ARGS\.positional | reduce ( if \. == [] then inputs else \.[] end | \. as $dot | try tonumber catch false | if not or isnan then @json "total: Invalid number \e($dot)\.\en" | halt_error(1) end ) as $n (0; \. + $n) . .fi . .IP "" 0 . .P The \fBexec\fR line is considered a comment by jq, so it is ignored\. But it is not ignored by \fBsh\fR, since in \fBsh\fR a backslash at the end of the line does not continue the comment\. With this trick, when the script is invoked as \fBtotal 1 2\fR, \fB/bin/sh \-\- /path/to/total 1 2\fR will be run, and \fBsh\fR will then run \fBexec jq \-\-args \-MRnf \-\- /path/to/total 1 2\fR replacing itself with a \fBjq\fR interpreter invoked with the specified options (\fB\-M\fR, \fB\-R\fR, \fB\-n\fR, \fB\-\-args\fR), that evaluates the current file (\fB$0\fR), with the arguments (\fB$@\fR) that were passed to \fBsh\fR\. . .SH "MODULES" jq has a library/module system\. Modules are files whose names end in \fB\.jq\fR\. . .P Modules imported by a program are searched for in a default search path (see below)\. The \fBimport\fR and \fBinclude\fR directives allow the importer to alter this path\. . .P Paths in the search path are subject to various substitutions\. . .P For paths starting with \fB~/\fR, the user\'s home directory is substituted for \fB~\fR\. . .P For paths starting with \fB$ORIGIN/\fR, the directory where the jq executable is located is substituted for \fB$ORIGIN\fR\. . .P For paths starting with \fB\./\fR or paths that are \fB\.\fR, the path of the including file is substituted for \fB\.\fR\. For top\-level programs given on the command\-line, the current directory is used\. . .P Import directives can optionally specify a search path to which the default is appended\. . .P The default search path is the search path given to the \fB\-L\fR command\-line option, else \fB["~/\.jq", "$ORIGIN/\.\./lib/jq", "$ORIGIN/\.\./lib"]\fR\. . .P Null and empty string path elements terminate search path processing\. . .P A dependency with relative path \fBfoo/bar\fR would be searched for in \fBfoo/bar\.jq\fR and \fBfoo/bar/bar\.jq\fR in the given search path\. This is intended to allow modules to be placed in a directory along with, for example, version control files, README files, and so on, but also to allow for single\-file modules\. . .P Consecutive components with the same name are not allowed to avoid ambiguities (e\.g\., \fBfoo/foo\fR)\. . .P For example, with \fB\-L$HOME/\.jq\fR a module \fBfoo\fR can be found in \fB$HOME/\.jq/foo\.jq\fR and \fB$HOME/\.jq/foo/foo\.jq\fR\. . .P If \fB\.jq\fR exists in the user\'s home directory, and is a file (not a directory), it is automatically sourced into the main program\. . .SS "import RelativePathString as NAME [];" Imports a module found at the given path relative to a directory in a search path\. A \fB\.jq\fR suffix will be added to the relative path string\. The module\'s symbols are prefixed with \fBNAME::\fR\. . .P The optional metadata must be a constant jq expression\. It should be an object with keys like \fBhomepage\fR and so on\. At this time jq only uses the \fBsearch\fR key/value of the metadata\. The metadata is also made available to users via the \fBmodulemeta\fR builtin\. . .P The \fBsearch\fR key in the metadata, if present, should have a string or array value (array of strings); this is the search path to be prefixed to the top\-level search path\. . .SS "include RelativePathString [];" Imports a module found at the given path relative to a directory in a search path as if it were included in place\. A \fB\.jq\fR suffix will be added to the relative path string\. The module\'s symbols are imported into the caller\'s namespace as if the module\'s content had been included directly\. . .P The optional metadata must be a constant jq expression\. It should be an object with keys like \fBhomepage\fR and so on\. At this time jq only uses the \fBsearch\fR key/value of the metadata\. The metadata is also made available to users via the \fBmodulemeta\fR builtin\. . .SS "import RelativePathString as $NAME [];" Imports a JSON file found at the given path relative to a directory in a search path\. A \fB\.json\fR suffix will be added to the relative path string\. The file\'s data will be available as \fB$NAME::NAME\fR\. . .P The optional metadata must be a constant jq expression\. It should be an object with keys like \fBhomepage\fR and so on\. At this time jq only uses the \fBsearch\fR key/value of the metadata\. The metadata is also made available to users via the \fBmodulemeta\fR builtin\. . .P The \fBsearch\fR key in the metadata, if present, should have a string or array value (array of strings); this is the search path to be prefixed to the top\-level search path\. . .SS "module ;" This directive is entirely optional\. It\'s not required for proper operation\. It serves only the purpose of providing metadata that can be read with the \fBmodulemeta\fR builtin\. . .P The metadata must be a constant jq expression\. It should be an object with keys like \fBhomepage\fR\. At this time jq doesn\'t use this metadata, but it is made available to users via the \fBmodulemeta\fR builtin\. . .SS "modulemeta" Takes a module name as input and outputs the module\'s metadata as an object, with the module\'s imports (including metadata) as an array value for the \fBdeps\fR key and the module\'s defined functions as an array value for the \fBdefs\fR key\. . .P Programs can use this to query a module\'s metadata, which they could then use to, for example, search for, download, and install missing dependencies\. . .SH "COLORS" To configure alternative colors just set the \fBJQ_COLORS\fR environment variable to colon\-delimited list of partial terminal escape sequences like \fB"1;31"\fR, in this order: . .IP "\(bu" 4 color for \fBnull\fR . .IP "\(bu" 4 color for \fBfalse\fR . .IP "\(bu" 4 color for \fBtrue\fR . .IP "\(bu" 4 color for numbers . .IP "\(bu" 4 color for strings . .IP "\(bu" 4 color for arrays . .IP "\(bu" 4 color for objects . .IP "\(bu" 4 color for object keys . .IP "" 0 . .P The default color scheme is the same as setting \fBJQ_COLORS="0;90:0;39:0;39:0;39:0;32:1;39:1;39:1;34"\fR\. . .P This is not a manual for VT100/ANSI escapes\. However, each of these color specifications should consist of two numbers separated by a semi\-colon, where the first number is one of these: . .IP "\(bu" 4 1 (bright) . .IP "\(bu" 4 2 (dim) . .IP "\(bu" 4 4 (underscore) . .IP "\(bu" 4 5 (blink) . .IP "\(bu" 4 7 (reverse) . .IP "\(bu" 4 8 (hidden) . .IP "" 0 . .P and the second is one of these: . .IP "\(bu" 4 30 (black) . .IP "\(bu" 4 31 (red) . .IP "\(bu" 4 32 (green) . .IP "\(bu" 4 33 (yellow) . .IP "\(bu" 4 34 (blue) . .IP "\(bu" 4 35 (magenta) . .IP "\(bu" 4 36 (cyan) . .IP "\(bu" 4 37 (white) . .IP "" 0 . .SH "BUGS" Presumably\. Report them or discuss them at: . .IP "" 4 . .nf https://github\.com/jqlang/jq/issues . .fi . .IP "" 0 . .SH "AUTHOR" Stephen Dolan \fB\fR ================================================ FILE: jq.spec ================================================ # This is spec file maintained by developers of JQ, not by a OS distro. # Your OS of choice will likely ignore this RPM spec file. Summary: Command-line JSON processor Name: jq Version: %{myver} Release: %{myrel}%{?dist} Source0: jq-%{myver}.tar.gz URL: https://jqlang.org License: MIT AND ICU AND CC-BY-3.0 AutoReqProv: no #BuildPrereq: autoconf, libtool, automake, flex, bison, python Group: Applications/System # Requires: # Disables debug packages and stripping of binaries: %global _enable_debug_package 0 %global debug_package %{nil} %global __os_install_post %{nil} # Crank up the compression %define _binary_payload w7.lzdio %description jq is a command-line JSON processor %prep %setup %build echo "Building in: \"$(pwd)\"" %if "%{devbuild}" == "yes" ./configure --prefix=%{_prefix} --enable-devel %else ./configure --prefix=%{_prefix} %endif make %install echo "Installing to: \"%{buildroot}\"" make install DESTDIR=%{buildroot} %clean rm -rf %{buildroot} %files %defattr(-,root,root) %{_bindir}/jq %if "%{devbuild}" == "yes" %{_libexecdir}/%{name}/jq_test %{_libexecdir}/%{name}/testdata %endif %{_datadir}/doc/%{name}/AUTHORS %{_datadir}/doc/%{name}/COPYING %{_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 %pre %post ================================================ FILE: libjq.pc.in ================================================ prefix=@prefix@ exec_prefix=@exec_prefix@ libdir=@libdir@ includedir=@includedir@ Name: libjq URL: https://jqlang.org/ Description: Library to process JSON using a query language Version: @VERSION@ Libs: -L${libdir} -ljq Cflags: -I${includedir} ================================================ FILE: m4/ax_compare_version.m4 ================================================ # =========================================================================== # http://www.gnu.org/software/autoconf-archive/ax_compare_version.html # =========================================================================== # # SYNOPSIS # # AX_COMPARE_VERSION(VERSION_A, OP, VERSION_B, [ACTION-IF-TRUE], [ACTION-IF-FALSE]) # # DESCRIPTION # # This macro compares two version strings. Due to the various number of # minor-version numbers that can exist, and the fact that string # comparisons are not compatible with numeric comparisons, this is not # necessarily trivial to do in a autoconf script. This macro makes doing # these comparisons easy. # # The six basic comparisons are available, as well as checking equality # limited to a certain number of minor-version levels. # # The operator OP determines what type of comparison to do, and can be one # of: # # eq - equal (test A == B) # ne - not equal (test A != B) # le - less than or equal (test A <= B) # ge - greater than or equal (test A >= B) # lt - less than (test A < B) # gt - greater than (test A > B) # # Additionally, the eq and ne operator can have a number after it to limit # the test to that number of minor versions. # # eq0 - equal up to the length of the shorter version # ne0 - not equal up to the length of the shorter version # eqN - equal up to N sub-version levels # neN - not equal up to N sub-version levels # # When the condition is true, shell commands ACTION-IF-TRUE are run, # otherwise shell commands ACTION-IF-FALSE are run. The environment # variable 'ax_compare_version' is always set to either 'true' or 'false' # as well. # # Examples: # # AX_COMPARE_VERSION([3.15.7],[lt],[3.15.8]) # AX_COMPARE_VERSION([3.15],[lt],[3.15.8]) # # would both be true. # # AX_COMPARE_VERSION([3.15.7],[eq],[3.15.8]) # AX_COMPARE_VERSION([3.15],[gt],[3.15.8]) # # would both be false. # # AX_COMPARE_VERSION([3.15.7],[eq2],[3.15.8]) # # would be true because it is only comparing two minor versions. # # AX_COMPARE_VERSION([3.15.7],[eq0],[3.15]) # # would be true because it is only comparing the lesser number of minor # versions of the two values. # # Note: The characters that separate the version numbers do not matter. An # empty string is the same as version 0. OP is evaluated by autoconf, not # configure, so must be a string, not a variable. # # The author would like to acknowledge Guido Draheim whose advice about # the m4_case and m4_ifvaln functions make this macro only include the # portions necessary to perform the specific comparison specified by the # OP argument in the final configure script. # # LICENSE # # Copyright (c) 2008 Tim Toolan # # Copying and distribution of this file, with or without modification, are # permitted in any medium without royalty provided the copyright notice # and this notice are preserved. This file is offered as-is, without any # warranty. #serial 11 dnl ######################################################################### AC_DEFUN([AX_COMPARE_VERSION], [ AC_REQUIRE([AC_PROG_AWK]) # Used to indicate true or false condition ax_compare_version=false # Convert the two version strings to be compared into a format that # allows a simple string comparison. The end result is that a version # string of the form 1.12.5-r617 will be converted to the form # 0001001200050617. In other words, each number is zero padded to four # digits, and non digits are removed. AS_VAR_PUSHDEF([A],[ax_compare_version_A]) A=`echo "$1" | sed -e 's/\([[0-9]]*\)/Z\1Z/g' \ -e 's/Z\([[0-9]]\)Z/Z0\1Z/g' \ -e 's/Z\([[0-9]][[0-9]]\)Z/Z0\1Z/g' \ -e 's/Z\([[0-9]][[0-9]][[0-9]]\)Z/Z0\1Z/g' \ -e 's/[[^0-9]]//g'` AS_VAR_PUSHDEF([B],[ax_compare_version_B]) B=`echo "$3" | sed -e 's/\([[0-9]]*\)/Z\1Z/g' \ -e 's/Z\([[0-9]]\)Z/Z0\1Z/g' \ -e 's/Z\([[0-9]][[0-9]]\)Z/Z0\1Z/g' \ -e 's/Z\([[0-9]][[0-9]][[0-9]]\)Z/Z0\1Z/g' \ -e 's/[[^0-9]]//g'` dnl # In the case of le, ge, lt, and gt, the strings are sorted as necessary dnl # then the first line is used to determine if the condition is true. dnl # The sed right after the echo is to remove any indented white space. m4_case(m4_tolower($2), [lt],[ ax_compare_version=`echo "x$A x$B" | sed 's/^ *//' | sort -r | sed "s/x${A}/false/;s/x${B}/true/;1q"` ], [gt],[ ax_compare_version=`echo "x$A x$B" | sed 's/^ *//' | sort | sed "s/x${A}/false/;s/x${B}/true/;1q"` ], [le],[ ax_compare_version=`echo "x$A x$B" | sed 's/^ *//' | sort | sed "s/x${A}/true/;s/x${B}/false/;1q"` ], [ge],[ ax_compare_version=`echo "x$A x$B" | sed 's/^ *//' | sort -r | sed "s/x${A}/true/;s/x${B}/false/;1q"` ],[ dnl Split the operator from the subversion count if present. m4_bmatch(m4_substr($2,2), [0],[ # A count of zero means use the length of the shorter version. # Determine the number of characters in A and B. ax_compare_version_len_A=`echo "$A" | $AWK '{print(length)}'` ax_compare_version_len_B=`echo "$B" | $AWK '{print(length)}'` # Set A to no more than B's length and B to no more than A's length. A=`echo "$A" | sed "s/\(.\{$ax_compare_version_len_B\}\).*/\1/"` B=`echo "$B" | sed "s/\(.\{$ax_compare_version_len_A\}\).*/\1/"` ], [[0-9]+],[ # A count greater than zero means use only that many subversions A=`echo "$A" | sed "s/\(\([[0-9]]\{4\}\)\{m4_substr($2,2)\}\).*/\1/"` B=`echo "$B" | sed "s/\(\([[0-9]]\{4\}\)\{m4_substr($2,2)\}\).*/\1/"` ], [.+],[ AC_WARNING( [illegal OP numeric parameter: $2]) ],[]) # Pad zeros at end of numbers to make same length. ax_compare_version_tmp_A="$A`echo $B | sed 's/./0/g'`" B="$B`echo $A | sed 's/./0/g'`" A="$ax_compare_version_tmp_A" # Check for equality or inequality as necessary. m4_case(m4_tolower(m4_substr($2,0,2)), [eq],[ test "x$A" = "x$B" && ax_compare_version=true ], [ne],[ test "x$A" != "x$B" && ax_compare_version=true ],[ AC_WARNING([illegal OP parameter: $2]) ]) ]) AS_VAR_POPDEF([A])dnl AS_VAR_POPDEF([B])dnl dnl # Execute ACTION-IF-TRUE / ACTION-IF-FALSE. if test "$ax_compare_version" = "true" ; then m4_ifvaln([$4],[$4],[:])dnl m4_ifvaln([$5],[else $5])dnl fi ]) dnl AX_COMPARE_VERSION ================================================ FILE: m4/ax_prog_bison_version.m4 ================================================ # =========================================================================== # Modified from # http://www.gnu.org/software/autoconf-archive/ax_prog_perl_version.html # =========================================================================== # # SYNOPSIS # # AX_PROG_BISON_VERSION([VERSION],[ACTION-IF-TRUE],[ACTION-IF-FALSE]) # # DESCRIPTION # # Makes sure that bison supports the version indicated. If true the shell # commands in ACTION-IF-TRUE are executed. If not the shell commands in # ACTION-IF-FALSE are run. Note if $PERL is not set the macro will fail. # # Example: # # AC_PROG_YACC # AX_PROG_BISON_VERSION([3.0.0],[ ... ],[ ... ]) # # This will check to make sure that the bison you have supports at least # version 3.0.0. # # NOTE: This macro uses the $YACC variable to perform the check. # AX_WITH_YACC can be used to set that variable prior to running this # macro. The $BISON_VERSION variable will be set with the detected # version. # # LICENSE # # Copyright (c) 2009 Francesco Salvestrini # # Copying and distribution of this file, with or without modification, are # permitted in any medium without royalty provided the copyright notice # and this notice are preserved. This file is offered as-is, without any # warranty. #serial 12 AC_DEFUN([AX_PROG_BISON_VERSION],[ AC_REQUIRE([AC_PROG_SED]) AC_REQUIRE([AC_PROG_GREP]) AS_IF([test -n "$YACC"],[ ax_bison_version="$1" AC_MSG_CHECKING([for bison version]) changequote(<<,>>) bison_version=`$YACC --version 2>&1 \ | $GREP bison \ | $SED -e 's/^[^0-9]*//' -e 's/[^0-9]*$//'` changequote([,]) AC_MSG_RESULT($bison_version) AC_SUBST([BISON_VERSION],[$bison_version]) AX_COMPARE_VERSION([$ax_bison_version],[le],[$bison_version],[ : $2 ],[ : $3 ]) ],[ AC_MSG_WARN([could not find bison]) $3 ]) ]) ================================================ FILE: m4/ax_pthread.m4 ================================================ # =========================================================================== # https://www.gnu.org/software/autoconf-archive/ax_pthread.html # =========================================================================== # # SYNOPSIS # # AX_PTHREAD([ACTION-IF-FOUND[, ACTION-IF-NOT-FOUND]]) # # DESCRIPTION # # This macro figures out how to build C programs using POSIX threads. It # sets the PTHREAD_LIBS output variable to the threads library and linker # flags, and the PTHREAD_CFLAGS output variable to any special C compiler # flags that are needed. (The user can also force certain compiler # flags/libs to be tested by setting these environment variables.) # # Also sets PTHREAD_CC and PTHREAD_CXX to any special C compiler that is # needed for multi-threaded programs (defaults to the value of CC # respectively CXX otherwise). (This is necessary on e.g. AIX to use the # special cc_r/CC_r compiler alias.) # # NOTE: You are assumed to not only compile your program with these flags, # but also to link with them as well. For example, you might link with # $PTHREAD_CC $CFLAGS $PTHREAD_CFLAGS $LDFLAGS ... $PTHREAD_LIBS $LIBS # $PTHREAD_CXX $CXXFLAGS $PTHREAD_CFLAGS $LDFLAGS ... $PTHREAD_LIBS $LIBS # # If you are only building threaded programs, you may wish to use these # variables in your default LIBS, CFLAGS, and CC: # # LIBS="$PTHREAD_LIBS $LIBS" # CFLAGS="$CFLAGS $PTHREAD_CFLAGS" # CXXFLAGS="$CXXFLAGS $PTHREAD_CFLAGS" # CC="$PTHREAD_CC" # CXX="$PTHREAD_CXX" # # In addition, if the PTHREAD_CREATE_JOINABLE thread-attribute constant # has a nonstandard name, this macro defines PTHREAD_CREATE_JOINABLE to # that name (e.g. PTHREAD_CREATE_UNDETACHED on AIX). # # Also HAVE_PTHREAD_PRIO_INHERIT is defined if pthread is found and the # PTHREAD_PRIO_INHERIT symbol is defined when compiling with # PTHREAD_CFLAGS. # # ACTION-IF-FOUND is a list of shell commands to run if a threads library # is found, and ACTION-IF-NOT-FOUND is a list of commands to run it if it # is not found. If ACTION-IF-FOUND is not specified, the default action # will define HAVE_PTHREAD. # # Please let the authors know if this macro fails on any platform, or if # you have any other suggestions or comments. This macro was based on work # by SGJ on autoconf scripts for FFTW (http://www.fftw.org/) (with help # from M. Frigo), as well as ac_pthread and hb_pthread macros posted by # Alejandro Forero Cuervo to the autoconf macro repository. We are also # grateful for the helpful feedback of numerous users. # # Updated for Autoconf 2.68 by Daniel Richard G. # # LICENSE # # Copyright (c) 2008 Steven G. Johnson # Copyright (c) 2011 Daniel Richard G. # Copyright (c) 2019 Marc Stevens # # 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 3 of the License, 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 . # # As a special exception, the respective Autoconf Macro's copyright owner # gives unlimited permission to copy, distribute and modify the configure # scripts that are the output of Autoconf when processing the Macro. You # need not follow the terms of the GNU General Public License when using # or distributing such scripts, even though portions of the text of the # Macro appear in them. The GNU General Public License (GPL) does govern # all other use of the material that constitutes the Autoconf Macro. # # This special exception to the GPL applies to versions of the Autoconf # Macro released by the Autoconf Archive. When you make and distribute a # modified version of the Autoconf Macro, you may extend this special # exception to the GPL to apply to your modified version as well. #serial 31 AU_ALIAS([ACX_PTHREAD], [AX_PTHREAD]) AC_DEFUN([AX_PTHREAD], [ AC_REQUIRE([AC_CANONICAL_HOST]) AC_REQUIRE([AC_PROG_CC]) AC_REQUIRE([AC_PROG_SED]) AC_LANG_PUSH([C]) ax_pthread_ok=no # We used to check for pthread.h first, but this fails if pthread.h # requires special compiler flags (e.g. on Tru64 or Sequent). # It gets checked for in the link test anyway. # First of all, check if the user has set any of the PTHREAD_LIBS, # etcetera environment variables, and if threads linking works using # them: if test "x$PTHREAD_CFLAGS$PTHREAD_LIBS" != "x"; then ax_pthread_save_CC="$CC" ax_pthread_save_CFLAGS="$CFLAGS" ax_pthread_save_LIBS="$LIBS" AS_IF([test "x$PTHREAD_CC" != "x"], [CC="$PTHREAD_CC"]) AS_IF([test "x$PTHREAD_CXX" != "x"], [CXX="$PTHREAD_CXX"]) CFLAGS="$CFLAGS $PTHREAD_CFLAGS" LIBS="$PTHREAD_LIBS $LIBS" AC_MSG_CHECKING([for pthread_join using $CC $PTHREAD_CFLAGS $PTHREAD_LIBS]) AC_LINK_IFELSE([AC_LANG_CALL([], [pthread_join])], [ax_pthread_ok=yes]) AC_MSG_RESULT([$ax_pthread_ok]) if test "x$ax_pthread_ok" = "xno"; then PTHREAD_LIBS="" PTHREAD_CFLAGS="" fi CC="$ax_pthread_save_CC" CFLAGS="$ax_pthread_save_CFLAGS" LIBS="$ax_pthread_save_LIBS" fi # We must check for the threads library under a number of different # names; the ordering is very important because some systems # (e.g. DEC) have both -lpthread and -lpthreads, where one of the # libraries is broken (non-POSIX). # Create a list of thread flags to try. Items with a "," contain both # C compiler flags (before ",") and linker flags (after ","). Other items # starting with a "-" are C compiler flags, and remaining items are # library names, except for "none" which indicates that we try without # any flags at all, and "pthread-config" which is a program returning # the flags for the Pth emulation library. ax_pthread_flags="pthreads none -Kthread -pthread -pthreads -mthreads pthread --thread-safe -mt pthread-config" # The ordering *is* (sometimes) important. Some notes on the # individual items follow: # pthreads: AIX (must check this before -lpthread) # none: in case threads are in libc; should be tried before -Kthread and # other compiler flags to prevent continual compiler warnings # -Kthread: Sequent (threads in libc, but -Kthread needed for pthread.h) # -pthread: Linux/gcc (kernel threads), BSD/gcc (userland threads), Tru64 # (Note: HP C rejects this with "bad form for `-t' option") # -pthreads: Solaris/gcc (Note: HP C also rejects) # -mt: Sun Workshop C (may only link SunOS threads [-lthread], but it # doesn't hurt to check since this sometimes defines pthreads and # -D_REENTRANT too), HP C (must be checked before -lpthread, which # is present but should not be used directly; and before -mthreads, # because the compiler interprets this as "-mt" + "-hreads") # -mthreads: Mingw32/gcc, Lynx/gcc # pthread: Linux, etcetera # --thread-safe: KAI C++ # pthread-config: use pthread-config program (for GNU Pth library) case $host_os in freebsd*) # -kthread: FreeBSD kernel threads (preferred to -pthread since SMP-able) # lthread: LinuxThreads port on FreeBSD (also preferred to -pthread) ax_pthread_flags="-kthread lthread $ax_pthread_flags" ;; hpux*) # From the cc(1) man page: "[-mt] Sets various -D flags to enable # multi-threading and also sets -lpthread." ax_pthread_flags="-mt -pthread pthread $ax_pthread_flags" ;; openedition*) # IBM z/OS requires a feature-test macro to be defined in order to # enable POSIX threads at all, so give the user a hint if this is # not set. (We don't define these ourselves, as they can affect # other portions of the system API in unpredictable ways.) AC_EGREP_CPP([AX_PTHREAD_ZOS_MISSING], [ # if !defined(_OPEN_THREADS) && !defined(_UNIX03_THREADS) AX_PTHREAD_ZOS_MISSING # endif ], [AC_MSG_WARN([IBM z/OS requires -D_OPEN_THREADS or -D_UNIX03_THREADS to enable pthreads support.])]) ;; solaris*) # On Solaris (at least, for some versions), libc contains stubbed # (non-functional) versions of the pthreads routines, so link-based # tests will erroneously succeed. (N.B.: The stubs are missing # pthread_cleanup_push, or rather a function called by this macro, # so we could check for that, but who knows whether they'll stub # that too in a future libc.) So we'll check first for the # standard Solaris way of linking pthreads (-mt -lpthread). ax_pthread_flags="-mt,-lpthread pthread $ax_pthread_flags" ;; esac # Are we compiling with Clang? AC_CACHE_CHECK([whether $CC is Clang], [ax_cv_PTHREAD_CLANG], [ax_cv_PTHREAD_CLANG=no # Note that Autoconf sets GCC=yes for Clang as well as GCC if test "x$GCC" = "xyes"; then AC_EGREP_CPP([AX_PTHREAD_CC_IS_CLANG], [/* Note: Clang 2.7 lacks __clang_[a-z]+__ */ # if defined(__clang__) && defined(__llvm__) AX_PTHREAD_CC_IS_CLANG # endif ], [ax_cv_PTHREAD_CLANG=yes]) fi ]) ax_pthread_clang="$ax_cv_PTHREAD_CLANG" # GCC generally uses -pthread, or -pthreads on some platforms (e.g. SPARC) # Note that for GCC and Clang -pthread generally implies -lpthread, # except when -nostdlib is passed. # This is problematic using libtool to build C++ shared libraries with pthread: # [1] https://gcc.gnu.org/bugzilla/show_bug.cgi?id=25460 # [2] https://bugzilla.redhat.com/show_bug.cgi?id=661333 # [3] https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=468555 # To solve this, first try -pthread together with -lpthread for GCC AS_IF([test "x$GCC" = "xyes"], [ax_pthread_flags="-pthread,-lpthread -pthread -pthreads $ax_pthread_flags"]) # Clang takes -pthread (never supported any other flag), but we'll try with -lpthread first AS_IF([test "x$ax_pthread_clang" = "xyes"], [ax_pthread_flags="-pthread,-lpthread -pthread"]) # The presence of a feature test macro requesting re-entrant function # definitions is, on some systems, a strong hint that pthreads support is # correctly enabled case $host_os in darwin* | hpux* | linux* | osf* | solaris*) ax_pthread_check_macro="_REENTRANT" ;; aix*) ax_pthread_check_macro="_THREAD_SAFE" ;; *) ax_pthread_check_macro="--" ;; esac AS_IF([test "x$ax_pthread_check_macro" = "x--"], [ax_pthread_check_cond=0], [ax_pthread_check_cond="!defined($ax_pthread_check_macro)"]) if test "x$ax_pthread_ok" = "xno"; then for ax_pthread_try_flag in $ax_pthread_flags; do case $ax_pthread_try_flag in none) AC_MSG_CHECKING([whether pthreads work without any flags]) ;; *,*) PTHREAD_CFLAGS=`echo $ax_pthread_try_flag | sed "s/^\(.*\),\(.*\)$/\1/"` PTHREAD_LIBS=`echo $ax_pthread_try_flag | sed "s/^\(.*\),\(.*\)$/\2/"` AC_MSG_CHECKING([whether pthreads work with "$PTHREAD_CFLAGS" and "$PTHREAD_LIBS"]) ;; -*) AC_MSG_CHECKING([whether pthreads work with $ax_pthread_try_flag]) PTHREAD_CFLAGS="$ax_pthread_try_flag" ;; pthread-config) AC_CHECK_PROG([ax_pthread_config], [pthread-config], [yes], [no]) AS_IF([test "x$ax_pthread_config" = "xno"], [continue]) PTHREAD_CFLAGS="`pthread-config --cflags`" PTHREAD_LIBS="`pthread-config --ldflags` `pthread-config --libs`" ;; *) AC_MSG_CHECKING([for the pthreads library -l$ax_pthread_try_flag]) PTHREAD_LIBS="-l$ax_pthread_try_flag" ;; esac ax_pthread_save_CFLAGS="$CFLAGS" ax_pthread_save_LIBS="$LIBS" CFLAGS="$CFLAGS $PTHREAD_CFLAGS" LIBS="$PTHREAD_LIBS $LIBS" # Check for various functions. We must include pthread.h, # since some functions may be macros. (On the Sequent, we # need a special flag -Kthread to make this header compile.) # We check for pthread_join because it is in -lpthread on IRIX # while pthread_create is in libc. We check for pthread_attr_init # due to DEC craziness with -lpthreads. We check for # pthread_cleanup_push because it is one of the few pthread # functions on Solaris that doesn't have a non-functional libc stub. # We try pthread_create on general principles. AC_LINK_IFELSE([AC_LANG_PROGRAM([#include # if $ax_pthread_check_cond # error "$ax_pthread_check_macro must be defined" # endif static void *some_global = NULL; static void routine(void *a) { /* To avoid any unused-parameter or unused-but-set-parameter warning. */ some_global = a; } static void *start_routine(void *a) { return a; }], [pthread_t th; pthread_attr_t attr; pthread_create(&th, 0, start_routine, 0); pthread_join(th, 0); pthread_attr_init(&attr); pthread_cleanup_push(routine, 0); pthread_cleanup_pop(0) /* ; */])], [ax_pthread_ok=yes], []) CFLAGS="$ax_pthread_save_CFLAGS" LIBS="$ax_pthread_save_LIBS" AC_MSG_RESULT([$ax_pthread_ok]) AS_IF([test "x$ax_pthread_ok" = "xyes"], [break]) PTHREAD_LIBS="" PTHREAD_CFLAGS="" done fi # Clang needs special handling, because older versions handle the -pthread # option in a rather... idiosyncratic way if test "x$ax_pthread_clang" = "xyes"; then # Clang takes -pthread; it has never supported any other flag # (Note 1: This will need to be revisited if a system that Clang # supports has POSIX threads in a separate library. This tends not # to be the way of modern systems, but it's conceivable.) # (Note 2: On some systems, notably Darwin, -pthread is not needed # to get POSIX threads support; the API is always present and # active. We could reasonably leave PTHREAD_CFLAGS empty. But # -pthread does define _REENTRANT, and while the Darwin headers # ignore this macro, third-party headers might not.) # However, older versions of Clang make a point of warning the user # that, in an invocation where only linking and no compilation is # taking place, the -pthread option has no effect ("argument unused # during compilation"). They expect -pthread to be passed in only # when source code is being compiled. # # Problem is, this is at odds with the way Automake and most other # C build frameworks function, which is that the same flags used in # compilation (CFLAGS) are also used in linking. Many systems # supported by AX_PTHREAD require exactly this for POSIX threads # support, and in fact it is often not straightforward to specify a # flag that is used only in the compilation phase and not in # linking. Such a scenario is extremely rare in practice. # # Even though use of the -pthread flag in linking would only print # a warning, this can be a nuisance for well-run software projects # that build with -Werror. So if the active version of Clang has # this misfeature, we search for an option to squash it. AC_CACHE_CHECK([whether Clang needs flag to prevent "argument unused" warning when linking with -pthread], [ax_cv_PTHREAD_CLANG_NO_WARN_FLAG], [ax_cv_PTHREAD_CLANG_NO_WARN_FLAG=unknown # Create an alternate version of $ac_link that compiles and # links in two steps (.c -> .o, .o -> exe) instead of one # (.c -> exe), because the warning occurs only in the second # step ax_pthread_save_ac_link="$ac_link" ax_pthread_sed='s/conftest\.\$ac_ext/conftest.$ac_objext/g' ax_pthread_link_step=`AS_ECHO(["$ac_link"]) | sed "$ax_pthread_sed"` ax_pthread_2step_ac_link="($ac_compile) && (echo ==== >&5) && ($ax_pthread_link_step)" ax_pthread_save_CFLAGS="$CFLAGS" for ax_pthread_try in '' -Qunused-arguments -Wno-unused-command-line-argument unknown; do AS_IF([test "x$ax_pthread_try" = "xunknown"], [break]) CFLAGS="-Werror -Wunknown-warning-option $ax_pthread_try -pthread $ax_pthread_save_CFLAGS" ac_link="$ax_pthread_save_ac_link" AC_LINK_IFELSE([AC_LANG_SOURCE([[int main(void){return 0;}]])], [ac_link="$ax_pthread_2step_ac_link" AC_LINK_IFELSE([AC_LANG_SOURCE([[int main(void){return 0;}]])], [break]) ]) done ac_link="$ax_pthread_save_ac_link" CFLAGS="$ax_pthread_save_CFLAGS" AS_IF([test "x$ax_pthread_try" = "x"], [ax_pthread_try=no]) ax_cv_PTHREAD_CLANG_NO_WARN_FLAG="$ax_pthread_try" ]) case "$ax_cv_PTHREAD_CLANG_NO_WARN_FLAG" in no | unknown) ;; *) PTHREAD_CFLAGS="$ax_cv_PTHREAD_CLANG_NO_WARN_FLAG $PTHREAD_CFLAGS" ;; esac fi # $ax_pthread_clang = yes # Various other checks: if test "x$ax_pthread_ok" = "xyes"; then ax_pthread_save_CFLAGS="$CFLAGS" ax_pthread_save_LIBS="$LIBS" CFLAGS="$CFLAGS $PTHREAD_CFLAGS" LIBS="$PTHREAD_LIBS $LIBS" # Detect AIX lossage: JOINABLE attribute is called UNDETACHED. AC_CACHE_CHECK([for joinable pthread attribute], [ax_cv_PTHREAD_JOINABLE_ATTR], [ax_cv_PTHREAD_JOINABLE_ATTR=unknown for ax_pthread_attr in PTHREAD_CREATE_JOINABLE PTHREAD_CREATE_UNDETACHED; do AC_LINK_IFELSE([AC_LANG_PROGRAM([#include ], [int attr = $ax_pthread_attr; return attr /* ; */])], [ax_cv_PTHREAD_JOINABLE_ATTR=$ax_pthread_attr; break], []) done ]) AS_IF([test "x$ax_cv_PTHREAD_JOINABLE_ATTR" != "xunknown" && \ test "x$ax_cv_PTHREAD_JOINABLE_ATTR" != "xPTHREAD_CREATE_JOINABLE" && \ test "x$ax_pthread_joinable_attr_defined" != "xyes"], [AC_DEFINE_UNQUOTED([PTHREAD_CREATE_JOINABLE], [$ax_cv_PTHREAD_JOINABLE_ATTR], [Define to necessary symbol if this constant uses a non-standard name on your system.]) ax_pthread_joinable_attr_defined=yes ]) AC_CACHE_CHECK([whether more special flags are required for pthreads], [ax_cv_PTHREAD_SPECIAL_FLAGS], [ax_cv_PTHREAD_SPECIAL_FLAGS=no case $host_os in solaris*) ax_cv_PTHREAD_SPECIAL_FLAGS="-D_POSIX_PTHREAD_SEMANTICS" ;; esac ]) AS_IF([test "x$ax_cv_PTHREAD_SPECIAL_FLAGS" != "xno" && \ test "x$ax_pthread_special_flags_added" != "xyes"], [PTHREAD_CFLAGS="$ax_cv_PTHREAD_SPECIAL_FLAGS $PTHREAD_CFLAGS" ax_pthread_special_flags_added=yes]) AC_CACHE_CHECK([for PTHREAD_PRIO_INHERIT], [ax_cv_PTHREAD_PRIO_INHERIT], [AC_LINK_IFELSE([AC_LANG_PROGRAM([[#include ]], [[int i = PTHREAD_PRIO_INHERIT; return i;]])], [ax_cv_PTHREAD_PRIO_INHERIT=yes], [ax_cv_PTHREAD_PRIO_INHERIT=no]) ]) AS_IF([test "x$ax_cv_PTHREAD_PRIO_INHERIT" = "xyes" && \ test "x$ax_pthread_prio_inherit_defined" != "xyes"], [AC_DEFINE([HAVE_PTHREAD_PRIO_INHERIT], [1], [Have PTHREAD_PRIO_INHERIT.]) ax_pthread_prio_inherit_defined=yes ]) CFLAGS="$ax_pthread_save_CFLAGS" LIBS="$ax_pthread_save_LIBS" # More AIX lossage: compile with *_r variant if test "x$GCC" != "xyes"; then case $host_os in aix*) AS_CASE(["x/$CC"], [x*/c89|x*/c89_128|x*/c99|x*/c99_128|x*/cc|x*/cc128|x*/xlc|x*/xlc_v6|x*/xlc128|x*/xlc128_v6], [#handle absolute path differently from PATH based program lookup AS_CASE(["x$CC"], [x/*], [ AS_IF([AS_EXECUTABLE_P([${CC}_r])],[PTHREAD_CC="${CC}_r"]) AS_IF([test "x${CXX}" != "x"], [AS_IF([AS_EXECUTABLE_P([${CXX}_r])],[PTHREAD_CXX="${CXX}_r"])]) ], [ AC_CHECK_PROGS([PTHREAD_CC],[${CC}_r],[$CC]) AS_IF([test "x${CXX}" != "x"], [AC_CHECK_PROGS([PTHREAD_CXX],[${CXX}_r],[$CXX])]) ] ) ]) ;; esac fi fi test -n "$PTHREAD_CC" || PTHREAD_CC="$CC" test -n "$PTHREAD_CXX" || PTHREAD_CXX="$CXX" AC_SUBST([PTHREAD_LIBS]) AC_SUBST([PTHREAD_CFLAGS]) AC_SUBST([PTHREAD_CC]) AC_SUBST([PTHREAD_CXX]) # Finally, execute ACTION-IF-FOUND/ACTION-IF-NOT-FOUND: if test "x$ax_pthread_ok" = "xyes"; then ifelse([$1],,[AC_DEFINE([HAVE_PTHREAD],[1],[Define if you have POSIX threads libraries and header files.])],[$1]) : else ax_pthread_ok=no $2 fi AC_LANG_POP ])dnl AX_PTHREAD ================================================ FILE: scripts/crosscompile ================================================ #!/bin/sh # This script is used to cross-compile binaries for # platforms other than the current one # Usage: $0 # is arbitrary, it is the name # of the directory which will be created to contain # the output binaries. # e.g. $0 win32 --host=i686-w64-mingw32 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 cd .. rm -rf tmp ================================================ FILE: scripts/gen_utf8_tables.py ================================================ #!/usr/bin/python # This program was used to generate jv_utf8_tables.gen.h mask = lambda n: (1 << n) - 1 def print_table(type, name, t): print("static const %s %s[] =" % (type, name)) 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 "};")) def utf8info(c): if c < 0x80: return 1, mask(7) if 0x80 <= c <= 0xBF: return 255, mask(6) if 0xC0 <= c <= 0xC1: return 0, 0 if 0xC2 <= c <= 0xDF: return 2, mask(5) if 0xE0 <= c <= 0xEF: return 3, mask(4) if 0xF0 <= c <= 0xF4: return 4, mask(3) if 0xF4 <= c <= 0xFF: return 0, 0 table = lambda i: [utf8info(c)[i] for c in range(256)] 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]) ================================================ FILE: scripts/version ================================================ #!/bin/sh set -eu cd "$(dirname "$0")/../" test -e .git || exit 1 if git describe --tags --match 'jq-*' >/dev/null 2>&1; then git describe --tags --match 'jq-*' --dirty | sed 's/^jq-//' else branch=$(git rev-parse --abbrev-ref HEAD) commit=$(git describe --always --dirty) echo "${branch}-${commit}" fi ================================================ FILE: sig/jq-release-new.key ================================================ -----BEGIN PGP PUBLIC KEY BLOCK----- mQINBGiLapUBEADQOs2nBPkTE+kvvYlBwLo87W1sfMmj6Vf/HCzdCiQs3oye26d2 3rLHvgpr3Tyst3bp1VpZGATV97PxjZMOkxHfIkW+T1VubiWN6c1veBP6T0BycfLN l2PbY+7FWY6pJPcKSrxMGyHqJYLs196JrGWyVJt2xHg6V8V8bEeVTXVyJsz175+a zGPbXMeM6F6v3vwMBHD0EzgS2hE4NFbiqprgo11vOV1+/WOQ3GkyonEDyWchocNY TZ9pIxUPnuBJKvf2vmOyYh6nr6PbN2aNA4JPCWGa3CwpWcsW0tTjLW5fIfWj5idH jzDEdrG4tDUxxUVAElFun85T6p1JNzSwuMRkKbnkfvH6maNAhlp+XCXko7mo5jsh ms9eysg9jnarvwwilh84q6ZHyf3qn/U9eEstiSCGuJ4OvqlYxY81rLEmNpL+FZ9r IzwMVY1O2WOnRuqpVjZiI4dy4TUcAdaVKCsI3GrDBH/hJJUjg/JybM6nEURy4w95 O7g2LEn2DL4XjYhOXTbjaEdJaxCSYBX8CfZTlkzmPG1ea4IeXjXBmlMavMQGix5b a3XAPUYB+IQALneQ00ME1KphJn0uCkH5a2GzPyW0uyliJye4F+g2KIo1gQgIIItt nptxby/AwrAd955DkAYXYWza5WwsRZ/bmHNmAgIFJfIclo89glQ/Za/z2QARAQAB tDdqcSBSZWxlYXNlIFNpZ25pbmcgS2V5IDxuby1zZW5kLWVtYWlsQGpxbGFuZy5n aXRodWIuaW8+iQJRBBMBCAA7FiEEkwealRHvwLfWzb+1sNpg+0VLrxgFAmiLapUC GwMFCwkIBwICIgIGFQoJCAsCBBYCAwECHgcCF4AACgkQsNpg+0VLrxjPjRAAgvHv AR4FPiOOSIFOEIvrbq++5Q9IeCuS/gVBb54l28nqXYtXwYs9wZEenA2A3dg5Q7eK 2x0pD6QACNeQSIoDk3Ve0qgi1mNKJd+bzgfY4028aLF4ayG5Bsmcf0mNkBl3visU pNcc20icPdzfnSRa6Fqz4CQDs7LX1nhjtBnSa0oT4gy8l924/TsPDU7tr31+DlNx VeKS/6Guwz209bcDKhLrVv7p+XaCjHUAq0obUVPPrIr2zaI7b3M7zAypHGByLA/g VfTeZiiY5j/o7L731owfDv5lZKRpnjsd8KmMu4SNvKOxu8CU2OetFvjiP/PxT7gP SgZyEakrn9titv77xhbHumZ5xTTphLYPfPDmzS94pJxU7aXBUMUI2wgdWrA3HYNf rTq9q70Jr2UCKZeCsNiIhtL3i2jBJBDfilxk82NU+/yAUDfLf6qKsMk8eoXIlcEO BbSiyXpJSApfA4paKd3O6wSjJy+F+tChWf5hjVKu+jvUhWgQTnUGCcnx500CfE47 byaoN6287g+i4eeiSCPdpUR2H8kIT0wIOhKzylc92QfgIzGJ3lMzvkQszuSDEnt8 hp/rJnBVLR34KHki82pFcn7cpyLux5t7Bcg7oatwC1sUn4eYSRJMLdJabI7HJ0Qn g9GbGqeoBEcnT/0K+CONrveDt0JbgAeQbNZOHOa5Ag0EaItqlQEQALruvRDFVmEz jBmSOJbVqEQTeuQCB6f60zIkA8IcCt87+X45AqqWQUweHAkIxynZksp0uOySCrYb 3GxI2CpjEqMN87hCI0VhUExD6ZJrtlV0+ZdpZHZUqKxBUjRj3R92IQgcUlhrTjsd aI+loBxpWk2upUNQeVBhHvJexV/Ccvgl1e1hmzmmEBXJwXAk3Dy7YRceTk4c7dbi fIIqCvxCS/4QAyTKVJK1Ilz/DgqTFN9mSq9FT5qwtgYKz2U5/Lq8lEqNEAfvrra3 94JOvfN9b5PQiKsDQyfUNgAnrKKLnaxB5QSBMHZrTomAntsiH+3tWytYav43OEn9 Ti7jkx7cKn61DxxINSb/5a127xF8zVYy9w8Mxpp+KxiR5QfAh1DkJI89gJE8C7G4 vzIogrcksFjPRH+4Iz5FI8+CjTnqw3T+qjFGxDhSpb2RBTxZxGHRO8gW3y6s4CUb 7Ir+7s5+lyjJpcQa6x22rFuf35lBuWMvifG63TmeCw42oL5XtU3oiqHjwIZkQgxY B58iN66eYIVlAOv7AVH5a5OHEUDbMem+M5jQJOqGBl/0cXkevtFENSX72eUideHO XX7+TBmXz8eqt7NkDz50fKArRL9eQIuobBglSLiE8Edmgh4hzzagPD0rbNEQHiPS TYnmUuGVJkHQrz1JRfCyB8KtVeHAygNvABEBAAGJAjYEGAEIACAWIQSTB5qVEe/A t9bNv7Ww2mD7RUuvGAUCaItqlQIbDAAKCRCw2mD7RUuvGEI6D/9S5o3qZ+hAJUWM 8CymSYzv/ysAqnyBHZuYyDMV/xonpTdxX2NVm07dOc8dcWkF07WmML7sCUfHBNwS uXl3rBoextcX7gGRtURnsRNqaW7M0q6ZckQiyanVs4+uAAfOYSWJ7uZvRQbEY0oN JQJjrgRqcuNwQKkZGT0D7Bd5cnzCBuTYWRrO5oa4BQP5bKJO4BhFOmdVpMSQAiRx 9U/7sb/C2DKkrWapxRBSAiJ3myfDs0WIvqw8zfqUoqfLKqzpg81ix302Q2UAzFAI Nq0JrStKDxzyBKsOd0YCp1MfL3Vy9VXZc1drkr6y1Pa6ieqoxFiDlbzkjkct65fW HckG+/zms6qqIcEg1KkrYQlI20/S475iv4Q4uHCt8Jm3LkNIcSRyr2EvHBmjp39/ +L2cEa87g1GNku9ItB1AeUBmyYGYbS+Xpz9+q2Jgaw8iFudWuC57XBK1xwxO2XWa 3gDIQW+4Jwx4JwX+l0NLO9VxiNrORHWXwwF/DXjQ3mw0+rL9hxu7rozpvNZq2S+a r9t7tM3jVErxQ6jlWADj0nkn1mQnxvWyL+TId4Ivj+7ThtGpbZDznMyittx7WZlS iARYZRdTNrMaxmklbxQ1jCHyU6cds6JE2Ktsvylf6GJd9PID+ANXhVhy84yxiQmj r+DHc9qnr7PlZcfurBj94kxeWHLxiA== =22V4 -----END PGP PUBLIC KEY BLOCK----- ================================================ FILE: sig/jq-release-old.key ================================================ -----BEGIN PGP PUBLIC KEY BLOCK----- Comment: jq Release Signing Key 0xAF19040C71523402 mQINBFYayakBEADL6biudAZ3V1//e3gdWMN6lbz+m5o6avu1vnbtCul/MxOF2Ygd SeXCn5gV3+F+xdrA3/Mhv9cWXzzDTp0D2U75mHw1n4OcArFvKm/RV5yOlc/wvblp WfWd/hCIIZhdHpRWdCko2ByXx9XlBRn46nGyxCFScLcHbicPjq2kIpZ7oad29gs4 bThj65G5XS48FyqixGHy0o2S0nQXNIyB1XTPm4mwHNAeOMFaYj6nhb6b5vu+RhlK syirTGU7pZYd13FM5y9NZrbxfKnGz5bdKPgb4jRi3YmBTKRzlW4IZl3SGO3kPi9a wJR4vP+cf1eEAWulrt9i4DA3/3/lpPpFh5bSo7nKW49PdOjfLWzBLtCsVhJReF97 sSPVpNmf6RrfBXnPlEBw+aU4wGRbmpA9AGV2rKsvxZbU2AqDS93Pn6S0u4XNNnjH TGxe2P9gSEH+xNuEyFcDbt0XP6Te3vSE7oMGIPhXq1FKuXygEQGV2fXa2Dovxi+q YTvbtzG5PV5lQqeexoNMUHzgHVWib/NIt7JTkBflJt33re7oayZd5DSE5zy/4n5d LH9prYJWqVGgb92Lzlk6uYDp3ztBlFdoRR+6L25iUCPRq5yS7J4Rk3ahask2CsQc aANz5xkESnS5DcakDoVtbiC1UY8eM+vXui/UF2uYCTLrz+SIIZJHPQ0fdQARAQAB tC5qcSBSZWxlYXNlIFNpZ25pbmcgS2V5IDxqcUBzdGVkb2xhbi5naXRodWIuaW8+ iQI4BBMBAgAiBQJWGsmpAhsDBgsJCAcDAgYVCAIJCgsEFgIDAQIeAQIXgAAKCRCv GQQMcVI0AoHwD/4s1L10OiimSELwTZ3x+btmKdaFBdlUhjBZd/GDE3P1pV+63D2+ LhLpZLQ3yOrplUDHGBG02Hx7/lY2YE5rRVNMyR8FqD9aMrOwQE3uERjkwFQ7Q69r S6kFLiOxUWDXNQ0wXeZ/Na6uYi6AI/oCYWnDIO3lugDUoXtHanYqK1BvJsBEvWpe UB18VcqxBQuOMPD+xNzVDSFn1uYiKKBkv4XJNLHRqdLpwmAVcLDkKTHWEy+223CZ 4zwahQKw9wPdUlakXP7v+wIxzGXaGk0yJOsYVPykQ4AkoMgvqqxyx23d6hjncR1o 36muLAiL+qELZ/rxUytduaK1Owr8cNJgPzRAEbeSRdw2hZYyEnHgNPC3atUN0wIk khzP/GHMBYIU90CdiWjGvjJeHv047Ty4S9PEYPZLQx1s8cdIeozEFt/lTqFp+9Si f2DWUKHpzQ3wfUudTD4pzSy28XJ760Kq54f1cf2CWqp577xrxRfcKKoyufF8pwqf sAno03N6MpxiK0qVwZ/0Qb2BfAI2rpxxc98qhuErlBE8WjPj7M93eaHNMTtCqCIG Hke6kMjYuwGu8NK/O0SqGqsHoXxxIvlZNda9MCPJo9xl77dphurOq/D/d9rfy/Uk 5D8ssNUBhM3s6sQl27L1avnSS12UuRdGSQwU33XbAuNG7y0a/zRnX+GqE4kCHAQQ AQIABgUCVhrKpwAKCRD5uhQ7lf9tgo26D/0WFFkhmUjSV9K/q8zSSJhuQfzoeM+n Z2DfYBfKdawbJH9/Yfg1nIFzih2lnvzk/kx8WbLSDMb0sHn6ZUZ6cVoBvrBxSgah bwPF9M8Xf4J/oBYHq8ZYjPHOWnHbEPuoNzPreqOhtSLBtP5dfZlEI6DLR2+WKj22 EmHfmBFoKZ90N2MQWQLV98DAFfsxS7Bqc9xSCbh405qCIGr/4r4P0BaIdJ2jW/9k AHwnsmJnf5lI7dn8BEMYgM3vcG4dyaWNf+eoI3cJnq+Y782KoyFjof4t1bLF2H1C vbiJ9xWv4uCeTVlTwiVJFkSUxBgmsyVofcboHF7/06HtVXDpG/ihZEOoqNPKPD4d 56V2t0hEulUpyqfs0Ic8r+sGWgvDCSqAVrXak2n0ULJ+RkpRB6ekcgOY7HdYKX1H UifaytQSxjUBXfo9HAC0Br2fyGh9s5zBcnrIrWHxwQw/RCIIv9CkZB7s6/NFYBKw Q27xTpXjHnGoEHNAA2xSyMXw9VoH3qoze/1iraK0zSFGAXpmL57HMBnOrLj7oq+O tB/cLd9o4+XFJjXHGAsXoOD5cCADkgMSMcouvPFKySfK0Kz5ScWVSsc5FvG44j/L T1WvjBgIrNAeQJ2efPYVmg5f/ALkjgnKy+lkafBk4OwXtWZCTf+9vcOF7FQ2B6N+ 7qQPymxSJxBSEg== =AiyG -----END PGP PUBLIC KEY BLOCK----- ================================================ FILE: sig/v1.3/jq-linux-x86.asc ================================================ -----BEGIN PGP SIGNATURE----- Version: GnuPG v1 iQIcBAABAgAGBQJWGzhJAAoJEK8ZBAxxUjQC8xMQAMgSl+2aYa/c/LuYKDWtVnHO G16rAq+oruc/IrEwEKqcwqTvK8M7xlAxUt5aPtAY0kRkvxadFtX8vZy1SEqAFcC5 sw7J+Oswl+5dJF0Y3j3I0hA6JuOe/+RP4r64pGlwQ0mVIJuTWqinzO9JqTOskeXy 5vSN50A0vFXzDu661UFr1v8q5+b8WhIrJhuOZtaPap33Gu9bS6fz93VBm4LE3a04 KjDydbNUoyA5HX4QVTgFON8oeVJevtqV3krnsU/ncOeTB0ThT9yywcq8HCbh7dqo EhfyATOmk3RZf3RsSAOG5CZ9cFjof6/SqVG8Cbp14MRVMkKi37mvHkqFER/WRtsv Ul1OzFfv8Jwv+cItTSB5c80kbbRfrqwf6NgZW9oTxZP3G3I5JjCTYhCaWlzO0wZ1 QAAJDBAv5GNB4rn9LXGdj2DhcCh00lJY83Bpup4LRc2RuJuJH7IUIkfRW4CAVoRd p6w5W4jYNdrrTkhfkNxSqi7FtKN23+eD2r0knPvhsWxyUcXrGhFqaImHmzQWIsX5 AviEK+nQUcuhTKolsN/97NPkRYUT9C4IVNdI8m1+EsAuwGodSvRrUwBIOoVQlYA7 MFLZZ23Su/8T5NnruP+iXmy0Y3Nf9W+GLHNn3H+9027zAs5Esd2Hy4R6W65BwWuI yYHFx8O6bi5ke72ByCUI =ru7X -----END PGP SIGNATURE----- ================================================ FILE: sig/v1.3/jq-linux-x86_64.asc ================================================ -----BEGIN PGP SIGNATURE----- Version: GnuPG v1 iQIcBAABAgAGBQJWGzhxAAoJEK8ZBAxxUjQCb2EP/08Lgfoc0rDv5IirCjXIFWxM 8C56aVfaF/8gaG75SuN3QUVBuWx3VB60Cgh/msTFrZ/jkWr+tYArNzwNAjI8a9T8 nE40SJH3kvwVrr9ALSgk9fEvikfZVKwYTc0k4h1hBataE5Z+7Di7VYPUmdLTd/ih dcJfDe6zPcYmaW6fl0glP2GLaDuLI3vxAid0MzDS1RU52z+usc/fjXWmaJwPVp76 Sd8/Uz3X6ZiFwpkfhp6XTcqkQhMZd4GS9cjnPAdRp9HFLI7S2UJ4RNj/YQIHrhQL 5Ko3KdXEWeSvD8wcr8VcZ66NfmyCls0diEU+TUv1I7VmLzVQGx9/4/uVWpfxry9D 8MLEHEJTTDT5W3hX47g29JRFJzv8PUyugkpXjQrpSoFbe/3vRxZeQNO9rjTx9t3x hdkWIjbwTg8SGH0XK+UNfR50A3VlrlPDpW5Ju2Io7/OuKRWN4i6ktFx0akFMmHUV D5u/FhEux7kJCNHnF7a7YJ1Ys4OSPUzoH3z35zhyVcW+iiX7KIKHNamWaPBw3iYa MwYVKHT6NUQiVQbTZvWJZXGArEnwq/z6jAjRQNKoTjbcVoYJunY/DZcJjnRIux9T yYnTa7IbpWZmWZWQfnb8zuSoXnhaSHZItIeUklH4K03xjpEXW7pGPLPznyDoBQeC 1WVcwpviS/Y24eSmmxaA =MlHu -----END PGP SIGNATURE----- ================================================ FILE: sig/v1.3/jq-osx-x86.asc ================================================ -----BEGIN PGP SIGNATURE----- Version: GnuPG v1 iQIcBAABAgAGBQJWGzh+AAoJEK8ZBAxxUjQCyb4QALrsqZ/QkI2a/uVPnwAh22B4 mtbplxOS8swCB4g56tG+JMuria9l1ACmpbc9eTJ/Q9z9LLwq3vBkpy0utAQp/iAQ ijZbTG7E3S/LtOzZ5MSbkGeyuDWu4YCI7DuxTZH+R43fiA/ShHUHf7rO/vofAjTu MZr7TpBRjut5htbkNrUKoYjK97hehvY0S3h1oqMSSuHS4Em9xMvv5bAsEn37+L3g o5Y5kHQ55Lu3qH1Uk87VMz+gtO4pxN+ZrNNrY2lX/hwnV7p5YDza2H0uOopBrTi4 X99x9JzdHoSrySRwS1ZDc+XYDgXP7JO9qDmNh18nXJlyCWFzDHajQS+4Hn0O5zM0 PHWasVC8tmxT0XXZlG1kPuaCkg0BFh1NXNjCUa7Ru9XHfOkaW4TyKGQa3eboyx56 q7MDvODUd3JSW4xmLJ7NFSYRCPMRiCMorQ8u8afy2OWt2W13M8OIH378dMcFoubW GB00i127dhuI95lwNsTV1seKO59bMbAJjP7ITqqDiOafg6AmTric6BJNakSsrc66 yCzhOfxqwfeRekPSirrf8nv9D7dW45yLEiXn9Irn+KghdL4KCLCB8dyc6OalITVF c01SK5xNzPRfFVzTqMdmi/dYpDL0KSMwg3O3DhPQ0LrRZDXKXj6A4KGAthpVLmRr IHj2hlGlr4hqLXUU1wE5 =I3PU -----END PGP SIGNATURE----- ================================================ FILE: sig/v1.3/jq-osx-x86_64.asc ================================================ -----BEGIN PGP SIGNATURE----- Version: GnuPG v1 iQIcBAABAgAGBQJWGziCAAoJEK8ZBAxxUjQCkGcQAMpxoK6aHzDIeVjp5kQ4MOFu dOE0xjXlPpudUfUORKqfsnPvvxJTvqlDrUhMq6d6S1Eic9ZAbfpmHGbw02tvQ7+4 hvyy/KbfBUcLZRIwZ1eej/rFUXd2fmxPwoj07SpTOgjKF+8duUzSlxBg+Kes77pj ZuMO3KUa3isaOp+kufh0+miAqHisEWzQWCfHBrVIwW63L2bf2ZSUvp4JqwfRKfr2 3hBfoll0M+iaLHr4/wGUIxRL+23afTtvQikyOXzB3rKXf+QmDePZ29isZVg94yi4 /XiDVmDM/6GpfI7u0fIoDcEgH+LE35HL/CT4zA8IzA/QwB5bCO1bPEA7DfDQq01R oghTvH5Qu0eu8tjap7EXAmch25nPys4NzPoIRnbu4i4wQUsFqGzmSFKEuU6pwDIm lsEBPbHRcGcaui2KidUNi7iQmje819KgRDhRxX65Bye9sKsD/HvMzQRce1RFYQg3 uqISuhWu8qj67J/ii2zFF+lo5HgHLqzXKcye1kY5KYq2dTIa3khq89Xkf3trsnNL IKZ+8P2eiVDjDr3UPIvVCX1JvNTdcQDMUlmoKk8g1qwuTp2PTi+c6FKicZGUMMnv o/hThK2JwnL/Iv0bJHvBU6aCXSnKLTLIdT02UvUppiN/GTMHsagvE0DRA1B1yFim /o/n4edysfzI1Pxe0b3c =ZOqW -----END PGP SIGNATURE----- ================================================ FILE: sig/v1.3/jq-win32.exe.asc ================================================ -----BEGIN PGP SIGNATURE----- Version: GnuPG v1 iQIcBAABAgAGBQJWGziHAAoJEK8ZBAxxUjQCG6cP/RNQd9g+Te+fgpFvnFDhAVyW EKZ+2B+V64m4GzrRFnGwBMqju4kFf0dZ4craagJ2gLVQ74FhvorMtphjX0MYgxtt wXyIqImlBake3GEkjUI6XW8QmlFmPix7+2fG4oEdLHwgE2/ii1DFlhTQgYYwH+Be z6wo6Nfl9OxykEHG1hl0A4AiHT1ubWogbjD87yZRO2M1rp2nHJu1TujqkjwWLXtr 0xVBSgtutfYRBvpPGhtLb4nqzkeW+lFW99A2aUo1KroyBdcrEKTJ4XMRqjYJLkSN 68e4gZqHmR6M1nA4h81bU26lhrN3LbYiOwBu67N5PnSOQE87zFPK6Dac4QyG7vzt pR2xht0QwwraxOeIrMrKs9vhUOKm9RDpNcD3z1xa+k6Qej+nP8A2zmMvUz3+C8F9 ITESyjk/28Eku5jEUs5Niz/znGvuU3A2fk/qHs7U0I8tvNWsxj29GCTzgPDoH3Vs sJKuSozoSqecBf+2x23PnGjGttL6BK6lo762qeVw6npCi/nqGFbMWpuopgJ2PiNP t2RdNzvX7v1V7ZfBOGl5iAeG/XJ18uD+hplCiUePN7Jv/3bpaJ9jlo//kIwddUP2 p89zfLPjeptAIxvkWph4ZL59pj7zsid7rSMd0WIOOqE61PKpl5jBgrdiBgKbcmJe AIRZewlOq/0l0cVtK10b =3nBK -----END PGP SIGNATURE----- ================================================ FILE: sig/v1.3/jq-win64.exe.asc ================================================ -----BEGIN PGP SIGNATURE----- Version: GnuPG v1 iQIcBAABAgAGBQJWGziKAAoJEK8ZBAxxUjQCP14P/jkKiLUgiZkXYVQs+hBJqJD2 rOsHVGmoxpjnQ8L9gUSxfZ0E80+1iTx/9JNWHs0xEKrvWKmCovfuQd8xfxZ30g5z wMa/7QWZtLdfIGkQje79WgA/+xDWSLa0T+dbcMjCwDdYPQyQE5Vf0I7qoNOj2Dcr CmkSMO6dtoilv/o2WX1x8Z1K5sqGMl64WyM5yR8sEMRBVuVqWRvELrv9+YMW2UYU yXj7tFwulyqZEoUBLlUxZhr7gjah31gBP2qqLeZhq/phdUsi9ckPusW3Un5SMaRf xEPo+y83Qrpusm9UDGsm3t90TWva3oMiExjFatFKuKvLbFCZRK0EIqdUOUMlptV6 kS3xKsvAq+vM53FfwcWx/9gcZQv5XTw7McmWZ9vZmHH24AUjuFFFZLoWxPg73Vek HaD5xTsxfYEqGRaJbYoSkSs39fw+tH0ajRoMVcZw2O2c94qAgzR/Qne9t2nQ0ypg hOzsIIdIxj9XZShkkVmlK8naf0YH0Wc3Yo3wBxkTy7QKVWtcF+x67wth2XjKHBbh lh9Gc3R/CUvRhk9gOSqHYAsy7lEIpFGjuIqYTZcXRO3BCJgjc3hV9jBiIy1iQWGg Kuh+egThw8U9z3PueP++yVjImze9Y/+78dc/rHAwXkFIysBs6vle/9ILDl5Komvv 91rFNBLkjvmJoRw4hUpG =WNFH -----END PGP SIGNATURE----- ================================================ FILE: sig/v1.3/sha256sum.txt ================================================ cf4b0b3e505958843375ac153d84ad6ee40196aa76ee373b0409f858b3cbf925 jq-linux-x86 dbacac81ebc00a7387e4c5e539a7a475981a1ac6ada20a2f6b1d8f950027751e jq-linux-x86_64 4095a48b50b754c8b3199b9c069fa9c3da0e737d8809af3205d1bf69f87cab6e jq-osx-x86 bce52800c943ff10d1ffd9c1a7e7aeddbc7bcecd7a2b05c6afb828399dbfa39f jq-osx-x86_64 c8e2ffb5b0536a50430ef9b4708a40686e4352db5c01ae90a98ba96660e5bc36 jq-win32.exe d041fdfd8b3aa3832eedf2aafad5002f2b47fb59373b71190a01422de825911f jq-win64.exe ================================================ FILE: sig/v1.4/jq-linux-x86.asc ================================================ -----BEGIN PGP SIGNATURE----- Version: GnuPG v1 iQIcBAABAgAGBQJWGzjvAAoJEK8ZBAxxUjQC5KsQAMt1IwBrIn8dvTe44djO3QYk H/qaNSRgChJI81GA+B4suTcgh+PUJcHF1EWls7CCfjfp1haocikXpNSuY7mF+43M SMdz2ZA4+N542ratUTv7YlG/igIvz6IbDysjowU3QQsCcjthmO6OF/6fd2qRhggB 3K80AMESOBBi7TkFTLw1G4M8uU6VvN+LWrG6fOcPXoRLlqShGzskDqxpobL1+o6J Cf56Z+ZVLQ6DPjW2pxK2R88788DjoJ4j53wsBqzgnHMeGzWVzvQ836rYSD4dhpSn YopiAesAYLu0hJszHbJrigt/jUGsNekQ+/ihqGXhbtDVjpYLU7At42b2w2AgjNSK GFBJmICTQZapz4o/lCCli82PngGmIVqgf6fc7qZq+HHtrcBeNYjMHMPMJroGqanJ DhCnLmE1906RpJ3VvCM5Sd9lSQQpSVzmFAh5MMnprxvsAmDbL+Ty//a/cOU4WPAJ MgXH2REmeByg8EX6SPhtshxxdIQf0CX4uh2r1aHQFtg/sNPL/EWGcRq+DVbaz/8R TJCfu9Ov0GhJlZSMHbkN9cvrjeE5CNM+7Q66JbhOMp7uOo4I9+JyknNJP7L0Nvot IcC6qsw8jMINHexW3RSDbX6b2S+0BskojAxp6IYHv0y82aaJ5I3+4UD3A5+Q34iM g1kqYu4WnPOZ+cihvGKO =8ZEt -----END PGP SIGNATURE----- ================================================ FILE: sig/v1.4/jq-linux-x86_64.asc ================================================ -----BEGIN PGP SIGNATURE----- Version: GnuPG v1 iQIcBAABAgAGBQJWGzjzAAoJEK8ZBAxxUjQCTVwQAKoTbAddyfciZzgaxSWqc0Yz f9njjvPHRtUfa0X5lDQghlpTrDY2CxqU71KknLgxW4VpnErf13KlVoMBvGJwCmU5 JcO2aE3iQDxpf6GnYa57caSsj2pR5Fi+/5nvxr2ovoCzGea3k61j7G+GV+znccAr K3c+03aq7p1LGfsqQSGPGH/nLnrqtcFonNVPxsaBuFpGMpaP4DuI+zhd5bGGo4g4 k23mWbOee/SEdYgiMNtVnkoQMZmSdae9O8VuTMoTSv8R2aLmDTrrLa/3z8m7rQAe rGQkaHhRg/fH6gLgBGJe7enqDgbNCmKp+zxfI6p5RbFvs5oH+M/wV1edG2KFUpI+ fv79Aj5XTVinNSCewrJLVHkzd328KhAeXzm319wJ0Q2sRbvO/3rhqslkRPCW9Uan uxo5dLMYqfzksy2Cwhv+c9r7Xfi7tjKidPLbwdz620eERquXSx7+kZLQyOw/mx6O ufnZKMDfhxZXt/KkNzraqkYKvZ6eO7r270ao7tdSZLDC+zELMGzIXINkOPXQDA0x m3Zz97jmfMQ6JwWU/1jCIOs+CpMueBYw3VyyqKNAUvYIjkw9A6SZFYhwcTc9k0Xh 0XSGZNjiKxTe1UJdBXG/nwNb6p5rMWwyesbiqvWiCIQ6aBX6SluODZsd4479bcVb 1fYsg+Lu9V7FiGY7ZlCz =oGfI -----END PGP SIGNATURE----- ================================================ FILE: sig/v1.4/jq-osx-x86.asc ================================================ -----BEGIN PGP SIGNATURE----- Version: GnuPG v1 iQIcBAABAgAGBQJWGzjzAAoJEK8ZBAxxUjQCmKQQAIei/vszKSXY7gyirM1FmUEO jPEzjHPJvYOEIw06/I9Jkn8ufsTQYtP+S19C8kGLRcZIonlXZxqQmbYQUv02NqEn UDRlCxiQZiGLO6i54vBWi5VhB4VNWgEbrctQ6oR+mV6MXs7RZo+2SGEJT+r4z8om HpFGQkfdfwNRbAXkIDHCx259pzL1gy/YrWV/8F0VdAH70dmqidWCQ4Lt+oymUhno 0f9gBOwIFZJXJRhhGz8unHk9XHdDlrpdvEb5XpuU1Alvt3BKa8vJslbTY48a+nI8 3XsfQhAXItAhUIWHTq1dnqmJzDvFzkZVEQQ2Zt+e7HsA9TG4StLCaYCIorUp7fbo BbxS6I9TUCbp5YBa2EHiq65/jNBlRz8+GB1cjZ3oCTpQQUTd2pFR/fdXXKxvKerr 5Gxc2CZqaOGW30iLwvtowNt5y34nf33WCTtBAPpY44aD3TkFkHcQq0hnZQI9gpV3 eB5uUoLrr3znLVIs3IX4B2/L0cKP+Dbal7iDQ5nsmEHGBy5P3yOgLbHUg80pG+lX b2wQMTCyTrl/lahJY/0n2r31yBgmHHMBNmY0dWLsXwzemh4TlVQ6IiFl1rF1PPQC F7bhTHQh1/DrhW94C/uFU83O0LveTb/U0FobAMCMgrd9Ew3C+gwXOKP96DHx6mmY ldHhiLTbmjLbfiDMaWw4 =dzyb -----END PGP SIGNATURE----- ================================================ FILE: sig/v1.4/jq-osx-x86_64.asc ================================================ -----BEGIN PGP SIGNATURE----- Version: GnuPG v1 iQIcBAABAgAGBQJWGzj0AAoJEK8ZBAxxUjQCeTYP/jt8hRyHNKtFfahjW50EcAab nSqUr5VXz80BL6vSrvixMoffv1RDFuzEZgFlYZGXErXjK7Rpo3NAE+e7EUH5vbgk kJaZjzGfw8Kx0ZCZFlmDmI5U93xYiSeIPPP8jaUEg/Al01CH/Y584bgNjyxi3zC5 RKO+/HTYd7KR5jAWNzKqV3tGvXJdi+a7Msw65OiJLRoVFX4ps/CGaI8Dh+vbbPi4 zPjG2DChoMdaRNxjQNcj/FW7M53rXIUHbXAmR1jDOSsTk16V3kX0eX9RSBsgTkjn b6/BrXnTMmTJR1osHIznuzuQ0sB84+k5CF1ZBwqYjmIr697qEl7r+bWODCN7NcJ+ Lo8re6lTAJZBqy7IKgPb6lwFg2tqd2P7UCv0Qx6dLUQGzqeUBDv5GDR5DjTQ1LqV CpyZbOFkA4UaKbmTp+DOGE5TV2D/hzUAcX/HzEo3RVAKSJIutlcxHpMyIazZbRQr RWNU4GiNr0Sbpl00oa6GU7OO/d+j+BFcEKrJ8Ud6zv0M4OCFkP0FW5CKxbl0aql2 y8cxcrdMmUhMwn/Jv7pX/N4Hqa4Jjzyy719LKRXp9yjtXV/AnEY2aQQqR+I1Q3VN DBvw7qLJe2hzQhacwOGDNHc7L5JgOC49wDw7L7MNlBGHPdEGKDMdEc/k+Nn/VnOU l2JS9gVb1lP3p1TPKSIG =PKfI -----END PGP SIGNATURE----- ================================================ FILE: sig/v1.4/jq-solaris11-32.asc ================================================ -----BEGIN PGP SIGNATURE----- Version: GnuPG v1 iQIcBAABAgAGBQJWGzj1AAoJEK8ZBAxxUjQC7PUP/3J4uNx0zpw4SlnB+yBzrKqn Zk2JahOg8wWRFbMACjMAjTMGmi9vYlLQRjesdi9WdvvlD1iW12Pi9ogA8OzFRkH+ A6It1g74k63WVtyfNHfLTeh2euQsLUc1UJZ+36FPs7lxZPsJmAL4kB1M6aHy3w/K aZT+h4iZhFeC3/JFvLhd2j6/RDf+FkAiEbRlSXoNmeBTLnNo82liEinZFUvEsglO EIVyPBGp3mtlBE8sf6WGd57IpxV4bl1mXZAap1xPVpK8hrjwXS5t2midd11ENBmK UeKcvZpmFb6qLTiep9kaUljB6nOzTYyhg6S9gaJAUDl6Wam7gtBFTIMmndoGiwQO NV+Lsj3dVFz+7kO+sZx/acC0PXfnMO2o6zBTva1RpDoHJFLmKTnPDbUFl0rZtMB9 R+HBlqRR35PWKWC3ggYPzfU5bZOVp8G97WFJlKkf5hMWzKiNoiR4hAM6IZYn1rGB S31YKV1yvLIcI4mbhogBlfvXEcgqkQt4cZip16qqpy+X5n1zEA/w6cXcpushbhpf 8G6b27PysLT/u5wViSPklpN7x/SbS4rVGzLGPvN7hYR3FgaPqADDrkZYZEIpl6Zd +Gj1M4YjcSDwInnBeaSA+n41Cg9hbudM5R2cdyZzcViLgebnjyt80H+03TDRi/aT dGs6zbsjUQWFGqP+FpgT =bERX -----END PGP SIGNATURE----- ================================================ FILE: sig/v1.4/jq-solaris11-64.asc ================================================ -----BEGIN PGP SIGNATURE----- Version: GnuPG v1 iQIcBAABAgAGBQJWGzj1AAoJEK8ZBAxxUjQCZ9UQAIlJSA4wU8lFakjVI1QfJ8AA v0FUY8KPmk2RgSHzeCRZaWuA0FJAOVNmJtW7kKT1Zg4iJ2f8enX+6QTRbWO5pges 6Ib8CltoSa1yS/RZOecyn4LtmJEkh22mhuOJdPzf7+6UmSGaMhE8yep5wg63i+GA o9vaQvllmiReR7qOjvI9cFYTdy/4iX+Nf4TBQPSJPBcXtwtH+iq72IzizgPo7fFd YoLz3V55DlAWBJsyMhVF4rgWcBcCOcMOwaZ/AsKVcKE7+NiPfFsZw0qqtBKAkYBP mKDheZmbX43rDp9Un17w3JbZZ6Uj7nglPpE8SVk9tlJJhznCmFg1ls8vdzkwjkht Cr8IlnFT8ZS3i7w9CLO8nCLuMYY2UECre/wELY915fwRGY+fP3EinO65/xBWxUdl zsq3DchIxKDorD3OiAduZIqC1ZW3XSSsiXzs2+PJwzW5ryvLxGSptVTTr35qVDdo 0igUW41pdwV1Mnltncah1+NOAWcSQzXx2E4dtPmGjEcTXSsGvt1vqTZtfFL60GKs nwONhA+mK/eMOjZ+rtJhHecpqB2moTixToq2RkOWmIhToq9jLWpOnswrUklIj5pC yxkdCU/OZDTYYU+AMXlGSQoiXems5typ+/oJsKVGPGHt6XkC+WTIX6Si1N4q7CFN 8qiYRPH8G2A1QOv5uj6L =+6XW -----END PGP SIGNATURE----- ================================================ FILE: sig/v1.4/jq-win32.exe.asc ================================================ -----BEGIN PGP SIGNATURE----- Version: GnuPG v1 iQIcBAABAgAGBQJWGzj2AAoJEK8ZBAxxUjQCJygQAJfXI0fZjCgdicjtwN2RbKP4 nLpao2BLcEkHQFmbCZXKQzy/oAGBR5xupoDbIFShum7ZEYe88Bn5W1LrKa8ELJ1C 5EQGzEsxRe5jT6YsdAJfjjEIZiDL0U6HtSq2U08iNOIIuSC6sI0FElotMUOKYqKf oExRULIkDVfYKBQEmbbUEi/gJ0d6kD8AT0ts7VQU0Ad3jCZnDnFGLZvk4XCiL9wY OIjqmA/okDHuuD4+lgexiABxgYYtJFDIIunk02LPJ6R/S5Qn7mou+HgqBJo2g16P CFwTf+f/MxBNjQOhGJtS297tAJWjjRlkZyUOraYFa0eos8Drc9PpwjJyjgyuMiPt lvFa/Lx9kwnotP8cuzZV1GY7SV60NcItIKyeoTK1QNv/Qw6DeXJ8txSGOqo8x+bV LJxLRXNHseY6+C0/1WJCIz0PF4wt7tAXmqpA9wRBJWKRaLaLnshhDMDRR18d0Ejw /4oggqNc2S1J+lF5ziUyGYyL8HjtX4ngghMhvvWlmH+UDGQlwUA/R8G/u/ESHUXU bebc9bHbo9b5TAolkCbmb8/tT+ZFTZ7oAexYgOjsv9auB82ggMTlKnN0SJag7wUy owPgSReGONDlFJ3JKWL4HLvJT/UFvqV0dnbHMmlKlebvre9v3B1sV9hl1R5Sl5du T0dL3Ha3NTeppVXq+HRr =wUMJ -----END PGP SIGNATURE----- ================================================ FILE: sig/v1.4/jq-win64.exe.asc ================================================ -----BEGIN PGP SIGNATURE----- Version: GnuPG v1 iQIcBAABAgAGBQJWGzj2AAoJEK8ZBAxxUjQCao4QALTCDd7W7SZ8tyVNSmOsILmi 7OcRdEdw3WNEpIXhYIo/NX1Sddtq1KgzHAgRb1tR3imB4UwVQfxD2olgIgoJTaMj P5jnRBIK98ht4iPXFkFmz3zOCBHSH/pXTy0jMjG0uC9czT2OWMlazA+brqaMI6oD JtgJEPIK1HfRdv0EfYCToj5LLi6iz4PVukk7i+8dqW/xFt1Lqny2ehggBFaIpG5D FAuuDbvnmzHODy7xpzPnRgBttpo6bIsQriVHrw81IWyhQJOKefjdiETB6N84+Lox ylgvk4Y5JiIrFVSoQGxbo3FlFth0CZlLSE8GuNSekAqYd+TjPIgtBmaHPuQc00sy CSw+NuaOkhq3y+rSkJgr5b04KDfvDhce2vF9maXtVPVEQ/r62WXNuCUoBVyift1J ViA+Ko9RISDlypHQBUj9KaWAUxTe14pKkaVggkrbM5c1+fvmjxr+FAZVSrnz8EOF K0J2834mNKNZWTo36NZ033BzoWE40HtSG+iDo6vGXNbAp8pFdRrjSaBO+Lklw6o4 uMixmPDABielcUIaZiu23vW2qzOhuEIav5d7lu72XI+8ZdHrUymwra3EAs9Mmg7i 0NPAwMHOPjdliswo8rp2hY7Shd7oMyNqxWj8BaPLCsxl82ofoPAtTcI4HCW2JXt4 u2hOqXKZ5LihwcfgQHpO =By7M -----END PGP SIGNATURE----- ================================================ FILE: sig/v1.4/sha256sum.txt ================================================ 998c41babeb57b4304e65b4eb73094279b3ab1e63801b6b4bddd487ce009b39d jq-1.4.tar.gz 1dee4bd2516f699723f373b2629c9173ce123b92c3a72520d0e25fcd8e3df45c jq-linux-x86 b9b63aa4b3cc85df8bdca884effb69d66e9ebd717454a9e212d9423ffe3e955f jq-linux-x86_64 6ab184edfa04d6f662a696d8594f19532ed78bc6fd05acf4cf506e789914300f jq-osx-x86 335a99a68eb9a1ecacfc947550003f103cfed627d3116c8bcae9ac11dd26d337 jq-osx-x86_64 2c1382b65a91fa27f2b9373331684de1e4ca577abeb724c3c79f4733af89b854 jq-solaris11-32 da5e4ab2879022f365b77b9babbcfbc01f30a98b884a31120031e218d676ac71 jq-solaris11-64 e08ca23dc637e8c0fe1577f592a9367e036f5b3f4c10b189c53943b0c8868866 jq-win32.exe 1c96fd65fd60763b92a28c7ee1290eeb974bc69b71b963d0e45cbfca1625565e jq-win64.exe ================================================ FILE: sig/v1.5/jq-linux32-no-oniguruma.asc ================================================ -----BEGIN PGP SIGNATURE----- Version: GnuPG v1 iQIcBAABAgAGBQJWGzltAAoJEK8ZBAxxUjQCbHIQAMU3mjBvi24X5CfTkyOmDOb9 sxxsuTOiH8Zjiy+5NP7a1YLDD/yznLmuu4fm+XzCE8DYdzkq57jSyjr8rqN5poTM bk3+9P/Jf0Kae+tpTP8mjvtJ6bVPweV/Zg+m8YwE6/iUHQHi00AyQ6/obfXx7otn X9k2IIJATAvR7WJ+5+Uc390MkVNNvuINfuuLWdSPdIbwFf9lvZ2ZmwanrWo6Gzdr /TW3MCwZjWjENGQBYNTJwswTdWww5Mo7MrEK/eHEy4DlozJyyzwe5xsWRz+ERKSJ CXe3+DTSVoc4DVuFEhU3T+7jU+Fev0FOqLlu0jD64Ma7epk8/gP/gzzV8JmkX1tV xwqZAdlPl+wNs1ZQw+9dsTZiRIT/qQBxa4y7bunnjkxaSa2ovTz6EUaioeUk62z2 e6zXNh92ZfjNKJT8An0Diq8i1P5EDH3dBHX3+2b9Qc15SFXE8vdXLqjIvTzwZ7hw fkxF37eMPfc527YKvktVUuXKkx458ossrHaYdcFnVh+etl6T/hQASE8Kp5rgVd/g 5/P6/JrkrY3JTHM8qVC74YLqQh/w3xaiBzcz+za255EcKwU3qb8G0iPJ6i30yvCC l/Hj2IREDHyogPefgq8PYah5RvVXbiWJ/UKz+qm/vinm1DUU23F18Ezakxd0Q726 Ok76sclCtAR8SCEu/3eU =fBEA -----END PGP SIGNATURE----- ================================================ FILE: sig/v1.5/jq-linux32.asc ================================================ -----BEGIN PGP SIGNATURE----- Version: GnuPG v1 iQIcBAABAgAGBQJWKaLsAAoJEK8ZBAxxUjQCv7UQAIEPihgkz3swMhxQVsRSd/dy d8sQMup6KFP3jAOABLSYyi6MrmCZhejodNd276ydxSgB/6rPClPZC6kSQsrv8fyj 2CSaQOv1cItzPSObL39xNHAoj8LOkSbb+4jultfbntWU8iuAaBzrKc6jH9VR6zgJ YfeQun2LI8AqqBK0nClSwXLXFcjxmzR7KDwX5EPeBQdM1uG0iHO+CsZWKjC+pHPy WkNqOubVpo1zFFx6pTFmDNraPOxdLvMVMZ7fuHBbdv95NEi31CE4cmQzIhLd6BbX 0xrOfT5xsib/uqlyhtUMjcqdrVcex8hptdsxrh5w9cZyhAinmpIEt59yS7Sbcg1m Cs6EdXJjjRGk5KVlyjuZJYOZxtCmdOYrLZVp7Nv2swIrUebkqWnXUAQk7Jdu8XmV 2UzkhFvlWaTVb4dJ5s1zb6C9Yv9hqACsjXzM3vstcu2tiGmaH/TGCggqmubn72Ag Ok+YdhveZxnL8iF2odz7IdpC+kC/vVfCY9ndHv3Sf3i6uLuohuT2x45R3iz8GIMI ZuexdQGz/69blhw+ZsqVpxodgZIqnCOwIk2nTkrLOw2cJbtlDWh1s/9udW+nMmPJ Z2lzSP5A9jJzMCnkb5104LdpyqbGcUO016Tn1OKyLQNssViKlV/kcP/jZ4T0vuPI NIP2sEDPJQFBmsBmFR4B =f2Mr -----END PGP SIGNATURE----- ================================================ FILE: sig/v1.5/jq-linux64.asc ================================================ -----BEGIN PGP SIGNATURE----- Version: GnuPG v1 iQIcBAABAgAGBQJWGzlxAAoJEK8ZBAxxUjQCFqIQAL2JdiZNp9GZm+SK115N5Twz mjI66fKWg+1ckSfiCdYwSzg0u7AFSECy+S8vq9WzSKsvIptGPJokIehnIrwpuw+l s7sfDA585XkRxpVoEwAdPalTRqXvmku8Sc4P1519K2DZDvtvWPY3N+tWIRE9jfcW 04KDTuWB35N8e+Mgg8z9P0NJiDanP6SUHp4r8Pc7KFQ/gOK4HKq9dFa3nsmkAq25 XJTFYPS6VU5tj/ZyTPNtMh1Nb0vp7+qeXGV+pBMwohmNoBFUyx65olwegD+dSswb Cfh59P+aWec7V6exJq7EW7ptIaZzp1LeoPfcABDjSOTEeez6ywIcsPnmfIjAh98e WovH2iiWH9XvLT6EC7gUcdlMJtvz46OkXilQAo0rK3X3pFX0T2aSqp/afdPtIvpK bErpQKt65XNsRprBkBlM1Jo6K7Cwh/SYKlbSJuvYvieORQ9w+0oqmYRCk7MZ7OOG Nxz3yEvEnzQPaXnSnJ/cK0xb9Yjj72LRV3Ors+ni9HfLm14xN7zBx+g6rudf9hy1 UFcvrxJSRFP5bZZxorWc6busisRi5E9sRQm/kGlTUUbrJrV1iae7h7s7+OqnY3aG H2lF4Gfb1eVsltQZ3DCRNiBiTD+3cmzEayD0ktHRnubOQCc331RoEwSNBsV02rkH 2ZijCFT/AmHOl/fqmX86 =b++s -----END PGP SIGNATURE----- ================================================ FILE: sig/v1.5/jq-osx-amd64.asc ================================================ -----BEGIN PGP SIGNATURE----- Version: GnuPG v1 iQIcBAABAgAGBQJWGzlyAAoJEK8ZBAxxUjQCiLMQAKBpyaj6un1mLebzt4JDQmEf qzzYK/q5RLS0vGzcYAl/ylBPdbBv6j7oT2JfPA9YfZaUPOd5O6eqk6R8OVrEipNe kvfIMnzk5joo+LDomdZvOhv6A0f/Q6eKnlr8k36INQxtbQA/xzUAuQthoo5Xn5ze d7lEHcWCpyaRne3dC5W642qG6X1hUN27lfx4MRHfSvFsSS4YIyPQHPiKPkQ9BzyZ p2XmWLwNSQRaVQU/fG8LbcRFeu7CBIFlQ0IvRfARNvJGFO+Eu6JDNZg+w8b1GL4O Td3rEb5tiJ1LEZxe2HDUV/b7/k2BywrRGnMbLFbohtyr2BmFCAzqy6UySNA/DU3H 5owLGNw0F3tWHg9yqGkTMcMTp0nfIbNKbjQcfSWKO+9gkoNyn+o78ggerRJAAt0U 0vcoLbfTMBTRfxNHaRB0dd3YxbkHvr3tAY9A1sqkBGB0SJoZ6WkLsso2tBsivq/X K9x4pXY15LSKu8opFJ1PY82Ng2FdRlkYs1CDNB5IM52mp5IAgmxGzHCy4S/XRBCq i0RSwg5xwCRllqmfRkgHQDFT8lKOLwMnLrzqQVsBneddvT//A13pHAI+vsloHbiB PwNgEdbvFVrxMaY8ampzQZ7vw15qOGcmGTJolIEhPdxvP9J9zTcf5nzF4WSJPdMC IF2dukcTW+c/C37F5nQu =+j1U -----END PGP SIGNATURE----- ================================================ FILE: sig/v1.5/jq-win32.exe.asc ================================================ -----BEGIN PGP SIGNATURE----- Version: GnuPG v1 iQIcBAABAgAGBQJWGzlyAAoJEK8ZBAxxUjQCopgQAIII75ovkAQmCS2aU5Ph2Yfk xLj40CVL7KThOWcfqKYy2Sv4+QV2dIjx14Uni/4w/dVGG0shtw1teUlfotBczR88 iyWvSVavbJLlyHESN7z4M4uApHikncNDlFJm/CuQWSVkGhtWvZZzJdoS/prypfai 1+sjtiDidNTZEJj5nfkvZ90UKpzNPJD8RGpsN5qvGyVnIYmXWZ1xe4pwKiNaUthJ 0wUBUcisTruZWCdSkV5cQMvb23sH8Qt+OZYgxJvx0Eq3+fG7Bh1J4YJLluMB1cSQ lqpOn7yJ4VptkgYeXoPMhbvN3I1/t+w43fL2P4jo5YTYuyVjxkS+VhEIGOgl7khN P0zzc1fdUw857dTP1/gXHTgMq3mWVAoQZnqcZEl1wnM155i+PYuN2kG0N2q4nt3p oQd58tZD/KmCV+QTegtt/gpavztxqWr6aagI+UynBfVKaOxY6AB+0+1oaQTX6iYK iqCqbhDi6ak8e7sXflAKrMhlnA4X+XCINdSwnYR96t/JY9tMFDiDapvbfgzdCi/D +0v7S8G0cu4pEjQw8rcotoPU2qF9cjMpmi2RsFDHpGsLv5r7avz5jDFxu9yEVMMd sp85aDh09bZfBACY4+t9m1AHCZO5LbkLremHv+nHA8ds/wiMmcCmRIgJQKvOA5l+ C/380YfJeepNvCnoIpr1 =NVrs -----END PGP SIGNATURE----- ================================================ FILE: sig/v1.5/jq-win64.exe.asc ================================================ -----BEGIN PGP SIGNATURE----- Version: GnuPG v1 iQIbBAABAgAGBQJWGzlzAAoJEK8ZBAxxUjQCW1AP9j8jyZcTFFzBAqLbxrn5Ljbj 6VXIDrutvXqcL1/KiPt2zT0deAqh08yCZh0RIQuq/o86nOXKumcK1E1jIcZPQ0p0 g3Pik4yvnJo7HCrJzzOXatfb9PokTEmM1Vo7qrJvQ1DPC8PyCS+fd2BLV4km2Uvp IMF3Wsa1nfRlcb/6Xmq/QJDhOG8MoIJ6Ldo+nFlCDqvKzGpQmmGo1gj3x32LkTUE aA8wtZ4RsCSEY959w5NVxhcX6H0iv0yzGtpOPRwaOOmymxuA0w7035P9TDrGExhU t3tMiTBWLucJgHPYH8XunBKjVzFDj8TT7gOq18MzuCJxUhPaJZZWAndFxQ8rxgNA ZUzmOpaX95DuRF9a5SMP8OpAOCOsM0lySCyJGWLoQ0Su55uaThLOVaDqBmXF13IU lviJ0DWPzDTPZ1Tn77kwhAWXglcsE6S2pBhkLID76kW2GtXVhatBPls0mE2Oe0AS p69dW/ynDuXyf0UjpcIH9UPVwsmXPX5LXztAh/2r6raW6VdnvGCjb2dWmPgFJP38 HuIKPnx6F3MeNSwKHlky3xfe7X4GNiciwTqbd6EEeIHGHMDbKSA91tuhbiBDGulC f+lGNWXPZTN+zqbUaDAArLno3vg+vQKhvvkdwfRhFYYqeFJwdKGXo5aEH5g/t/n0 8sewgmHKqlUa73LzABM= =WcIy -----END PGP SIGNATURE----- ================================================ FILE: sig/v1.5/sha256sum.txt ================================================ c4d2bfec6436341113419debf479d833692cc5cdab7eb0326b5a4d4fbe9f493c jq-1.5.tar.gz 77c2e4dd9e92c58a662582a24109330a8a94562c50c52f837f59122a951b4ffd jq-1.5.zip 264118228c08abf4db8d9e907b9638914f3eadb5cd50dc1471a84463f7991be0 jq-linux32 c6b3a7d7d3e7b70c6f51b706a3b90bd01833846c54d32ca32f0027f00226ff6d jq-linux64 386e92c982a56fe4851468d7a931dfca29560cee306a0e66c6a1bd4065d3dac5 jq-osx-amd64 1860c77bc2816b74f91705b84c7fa0dad3a062b355f021aa8c8e427e388e23fc jq-win32.exe ebecd840ba47efbf66822868178cc721a151060937f7ac406e3d31bd015bde94 jq-win64.exe ================================================ FILE: sig/v1.5rc1/jq-linux-x86_64-static.asc ================================================ -----BEGIN PGP SIGNATURE----- Version: GnuPG v1 iQIcBAABAgAGBQJWGzk2AAoJEK8ZBAxxUjQCJ8cQAJJQoCwUiFf5MHqGHGaSC07L bKyvm2OmSzVscld2lb7MsTHRUJ3RR613CpuYsNEG/nVbtaUntzgmtyMWabuGap0I QRQb08by5wP5Mve7QCOxfO9o56k/m2MJluMFv2xdJrfbLBlJuffV8rTWCNSNFpaD MLTiMnSx0APGxEoN34wOZ7ZDL6yIb+7z3Ip9P8lni4f3B+fJGCwKr9Sr5NztZVGL fDwfTBDLHwgpPvXlddg+oEDqVoSodWW9LZYKVo3q0IrT1nI4TdCsc1Fautpz7Y31 J2rcZR5qwE9jy+fkm3+vX9Hbg/QlND07ZX21bJh1suE+1ggELrVwh1iCEfBIVEZN 3tat62QUePL5ymAaElbeX5nIxuNW8U5jP5fjtVu2uEZKRdPz0I1JcGzILi479TCK /AcBhoXvdvd6sXjqgNs8ZbNBoklNqwrbLw1ESzwzaGfKytvMIO8rN8E26CO82d0v 3gob2Bc9KE6+hdobdax/SdXzjdAsyL4fDezRQGk1LvLV3I5rLs6cdR2HRjbH2uFU auNQgDLTo1PAYgsTDvDUt61O6K1m2Fx4RZgc6pligHDxlcvPJw+DkSsU+QRD0ODk 2IYhdakVFOaG+OMcCfcLFJ/3mJnhmFl/VQVdLlrELy5r6NaQo7bkLL1asU9LJLlL N5ZHYSx7HvRCAz++hd3r =GYEt -----END PGP SIGNATURE----- ================================================ FILE: sig/v1.5rc1/jq-win32.exe.asc ================================================ -----BEGIN PGP SIGNATURE----- Version: GnuPG v1 iQIcBAABAgAGBQJWGzk5AAoJEK8ZBAxxUjQCJZ8QAIlRnnKW3A6yLpAGSNsQ/Rm1 34ElcCgwwGsQFaBz7ZjzYPwFNmbrQYi4uJA14Sh0MAWgJiIfjJs+nS2YiC/6etdh uCEg4NdYtF6kPlBMQ1MJN1+OLv7ACst3kajezpoCHraEQkcFgF4CSTq2zBVeSltp QxVJkMn6CM308cbimWI+wB8z//28Sxer7KyeIbZ9Mjt0YGHYsxIeNhPtDNgVzutd 4lYGS/YRbRKrVKje/20BCmU7QnyGnWIZDx3A8ofhGbLUnKX80eBuHLWUkruGbyL7 KMuXPbKAyqtMiGRziqiqkvKRe+aQc+kvJVNUYORnV/nSBFYqqp9WpaZGy0VrXcVS szAiIxPFULeAPBiycaLyPrs2sANnbLSaK5OYc/OQl3fQd8K4HycHn7gWzTrsSiJ0 O2u7YpIZwhnJusZQFbvicU5TEnTnUs68PkBRjI/MJYGna5CrE0dhEjxQ7xfqHds4 daBHctNOo/v/Wx6cUOklpdygZK0l0DWdNNgf4u0ID/qrI/r+F2WYTMO9FTxuquID AnOcKJAnW/uoDx3eEl/Xf92Be1pvsBSU2gwJZ97UYXT1DKPdsoO8ubUNTjDL2BCL 7mVQShAasKvCB416kg2v0NqR83v2iLzfERbmyZhhR67WwjSi23r9UXPjgBGsux6h 0uohePJ5f76elv2W/8rO =4Qhb -----END PGP SIGNATURE----- ================================================ FILE: sig/v1.5rc1/jq-win64.exe.asc ================================================ -----BEGIN PGP SIGNATURE----- Version: GnuPG v1 iQIcBAABAgAGBQJWGzk6AAoJEK8ZBAxxUjQC2tMP/jitj5yEkh4PL/apImNJBZSd PPRWhOgdBvSV5kycstS3ni/sU2ZcHtf122BLonIJHJN0cL/jVZypJNIZ2gNTA4sn pi85vNuwhEKYfgMbLnVG03KoMtdjZ/kPSJn8UK+5ShEwm9HgbLbe1Pp7XQJW1nAG hdNT6ldqbyZ0j74r0yekN516VdpPPVp1R5rDVxcZMOKNeTbNlX4juEK+BsKvp1gT /SWxC6Y048ogMT1YnVySnh6Q1/2/riIhlw2u26Is4MHP9Dc7wxNyegTU6UU4uAXd Ejg81FpkhRZzF876ZOEfjlDsKLAYIEAYd5ozq/VpCA+rB30Y20tOCPuhilnuWQ53 9Le9ybgfJOGwloh3vfU3O9fbQKrL6TjA+crK/OmZvjSsyj2ef98vjWdFG8fhUr4f HVTnmJcg6R7WIBHxVnxfT9D3hIV0+l8qCWu3TtTlfdGcXqI0NcY7Exee6WbNdmkj 0nESSddP2nEb1eCEw9IlVliZevJYqwNaSmcN92EWTzJEwj9g7+yK0XWs+ZfDNTUD +iQoFY+W/skSfNr5XCyj2wlSElIHUlQtCVZvrnbRz/QmjZfUMTBdKkkVucDGvldy YyauXVEIvhFdeY59E2FzoZpdn7LzyzGbg2dA2QwGI7WB39L1QnLMrRPOmBwMJRvc JBQycWmsgKzAre48vKpD =LnUB -----END PGP SIGNATURE----- ================================================ FILE: sig/v1.5rc1/sha256sum.txt ================================================ 5c33ac16152344893f596d2c9f256b6cee6e925e53718c94d24049b640ea955f jq-1.5rc1.tar.gz dfbb2d073d2df9ee0bec44b60bd81e213b7881b27fc38d7438daee9eded2b75e jq-linux-x86_64-static bc370e22a11c85c525ba1965760faa5273aa3cd0ae69b030de4091fc776538b2 jq-win32.exe 6fb6f39d847df57b481d36941216c770ccf5f97c36e5373a0c93e63b5506c9f8 jq-win64.exe ================================================ FILE: sig/v1.5rc2/jq-linux-x86.asc ================================================ -----BEGIN PGP SIGNATURE----- Version: GnuPG v1 iQIcBAABAgAGBQJWGzlUAAoJEK8ZBAxxUjQC6acQAIREc1GPBwDiL3STKWVEUYC5 r+Cti+tWisdNGvAapCdGcwcavZ06PM3lMejBpQ5v2WghvsXhFvxDnwyQHKhbjIdG Uw3btu3ykjabHfqi5L5neQjFJwK//zsan59VSTzRWxjPHpAEoFsEihddKdx8kWzI KfPx1sn7ftO5weFcl0MU9ks9kbADJpviAvCk1mxKeNbv5KE9EYiUMjEg0kW6JmBM rIJoWc4fUR7rHbnK8fKpEuBzPLRBppFOG+ma7dx/4tCMjZmzmGIzqrCwgRStoS6j mr1Ws1f+j4y9ZdCXqubDVpzesIQ5fWc99H3kNuzIHBku4o70OOaGKdqvi5JBSiJf E6hD6FrN0ugu92IvRHNG4Vkg1hfNiff97ZX4lEHicFy2Bbpql56yHc136wAlLkvN 8ns9xIE1APTZI6J/6lHfUDStWgKOlsgf51UuT/sJQeE0N2RscSJ7cxhR2F96RQ+Y Vb+hMg8QLA99B4OWbohkKR9eePoEjLz9u9kgG/AOJy24m76pjO3az8Xee9I4LFMp ws78NtQgGi+ZJ6JP4QsEx9ZakpdWGnpDgIskQE+LL7MH0mXR07CpXXEMTnEIBMj9 ll/pFQ7bFJiPSXZZhRQVSiNhL3a6DeLe/Ik9xY/djH4WAMuOpEQsbI3cRxOktp26 FsUWKNf6I+CrLaXbbrBB =lABc -----END PGP SIGNATURE----- ================================================ FILE: sig/v1.5rc2/jq-linux-x86_64.asc ================================================ -----BEGIN PGP SIGNATURE----- Version: GnuPG v1 iQIcBAABAgAGBQJWGzlWAAoJEK8ZBAxxUjQCmrMP/1jfOkKVG7FZgArN0ZYBgJiR jP5L6/zlMG9SDecNnEVJ+PX7YdiBlnIQ7icV6iveBsSvkVyY1Mp+0ibzIePtNV8I 0SScmo4Da1gQwxaX8lKIfCTemOSvhxl0xqdOsYHq7nRxnxSmh4MFnDqXLS8ryW02 /N4NsFaUCjEvyFVfNjRGDwxyR3RhXr643p3vp+JZvZ8wLeZhM+ZXg0VDdXAFFVHJ EjIvedxV/IU4brVkqgRDPmAKdaVbLRezGl2uj7PYg1fcNXevUSHEY6bsxp9FSanU LWkD/0rElPdsV+B5ST2f3K7vTSjDOBA+6L3AEUR2tViCe/FOJGTMvVrJTG3/r7hh STARqZHX9q/1oEFQAZY1PX3mKCUrXKTBLkTWNWg78jtYXtV8JagQQPV5CcmaqPVA u0M5lNKDhgx5Qwy/Ap3FYkKtFHFuDxK6Y+px4J7hGRuH2casB1lYX+4YS4J8h4my 9dnmly/fpOI5nuONzXweX9zizNcmolqf9RAvWE0umurBj8Qyo5vMeEfiHVU3DSxw tIDAnT1bQv6s0mEBvFX2Fx6AJHc8wY4+iyu/fOMpSdMfbJ8lXeXYFH+SzV4uwseq c4j9eQ+Ab8SoCUMsFiS7KDAhsiMYk6rKn+aJthl/72GVBbnoLbYJs0frjlAsZmz+ ReXdr1sBmm2qFoJ43w+9 =UxxZ -----END PGP SIGNATURE----- ================================================ FILE: sig/v1.5rc2/jq-osx-x86_64.asc ================================================ -----BEGIN PGP SIGNATURE----- Version: GnuPG v1 iQIcBAABAgAGBQJWGzlXAAoJEK8ZBAxxUjQC3YwP/23mNNa+XscTIWHKPihfNoNn TIgGXP5znWOUmkNarIDl2ir5qi8oq6kBLoz917uz1X/KY3yB1rDoz+apB3Co1Ayh S+oRMeHUCE2V5OIBPsJyMHM3cgfdbVx3fNwZitpv4Tw7s9ilRG7SWD/2Ev2GKx/h Qn4j9JLrxJdvoSS488oyjK7rIXLSDM5R97qFS52Cl4beO0dJTdy8D7QOCF84soHb SUgrXZkNuzjs7qQRMJb60mhQeIkuUC55VoOUufoXTwpBZJNNoyqT1eNNlZXE884Z kvKJ2q0FYD7jh1Ct9KFr6gfx0HIjxMb2YYtCEilkKSCHG8JUHgCY5cpAMDZrVa5K ss9Iu+dkor96Qv7nyJ+zhjEscl1rpfvYKJbMLhC+M/lHpZc+5rtZBPFmZv8wedzB a3/hkyPpxp2YPa32CAZ4UVFE3h+lBLvT/PV5pB8UvYPbDrWzLx/V2aNLP1joZKH0 y4DECAVMAD2a3dv+xuee7ZJcmL4gK8a6sZbYuOWgnIjjGQ4W951Dz/CoiojqofKO 9QmcDiEOQQdnjpfuObSX6wNV3583z4GEHIuKLQiM7rtmIvzA2x1RCF/txZoxg9+T vwvyz+689ju/mIdUjdCGwPW6qljoMWRPXHJ11mD0CBTQmNEJiMbhE5lt/yH3/big mVPHv/DkOEM8pLdpMHlj =+eGW -----END PGP SIGNATURE----- ================================================ FILE: sig/v1.5rc2/jq-win32.exe.asc ================================================ -----BEGIN PGP SIGNATURE----- Version: GnuPG v1 iQIcBAABAgAGBQJWGzlXAAoJEK8ZBAxxUjQCwSQP/3hRFwE5XzTNpBbMFiThq8GP xON/4/6H0ql/weVZPRyoVVuToKY+oym5j6IhwBp8eswQKMF0p5FpBjFJFFeXM9RC iSmYL7NGKSZJMLQHFLM37I/eDbaIOo4OobtzD0CAg8ZN8nlIHajxZ+vsmcuU/L6k nC5++MJEBWoUMYUdqII0F+ivlZFwngrnCgeLIVwWt55ojntbBjjs32S2gT8HugPz 11zAnx5C7KfDTnDNgMPFDPL3T/yVoyasVxidTB4sQrFeR2vns4F3uDugEBAWMb9A 3WRSzcuYdlrVOzB8WoHS3E0esEeuqtPIz7y3mvrvYsZcpIPpXaagmKALG8zZ7p87 /s9zpQdFWTe+boI6CdjG1+UKY/QhDAl3zalIQiqFSiBsbk/yhDtNug6oqGO/2fQw /xWlj3CmQsSMI9KjlrcIv2k4ugbYtIxVRvEJqqI8Qb47Lmav+F+VNhrwCcFdlMiD swD4xfT2Knfkx7OOfDv7fCRE7njBBOTumYu1o7G8HbZokSkAtS5sovrzLWEzXRPz lV4Of454G5Quif+MQIw0P55XgFCLLCEpcbt4vOtkCK/GaLuV2+JKoyJMoFEG2mAr T2ufop5Re1z0hvNe2VLsMhcUpSUKsFl4h1aM+YYhsOnlGG7uXA0bTAMmU1+n2uKE k/rOwLp4Lyh9gw78IB8T =A99j -----END PGP SIGNATURE----- ================================================ FILE: sig/v1.5rc2/jq-win64.exe.asc ================================================ -----BEGIN PGP SIGNATURE----- Version: GnuPG v1 iQIcBAABAgAGBQJWGzlYAAoJEK8ZBAxxUjQC6bQP/3WzIL/KgnUmI3ziUJcaKgLx EOkMA7Ib5o5w75gg9img3pvYCLZnlf40TiRAhc/gQ+uIw8uLs2wqZFPSNE6G1U6i L2AQbcl4e7P4glvsd+PjXKz9lzCFyPtCgEeFA/T4UP07ef3yRpreFmYcW4A/5Saf WWn8nKyVL6vLS2vG4zZi6g61Rw9mlWFC6VeVLe+/IHMH3y6WtT71SDw3h0OFH+Ui DVSFXeu5Fiu/NEiZUyb2BLK/a817zhQ5xq2/mCoYrKLgLzbKaSuqMe47Qn6Yjkbo 82F+lDakDS3bsoIcvDkR2w8ABsPwPX+xDk8Z2Usyq2wcCEvSTKoB0AiczYfe6Eod uz66AoDZY/v3XXs9F3NWJqLRfRzu+fHcw9fvfzLET6gVkmbc5+Z7fDNXOtJlS2oT KKImd1vuEoffjgblera4Dg+v2f7rY7yFCQEsYGLnhyEb1/G4nb/MvQJ49NOB9AXJ pVvslWnwWJVy0pzo0VqjpldKGg2EAFcJ19+pgUOFFCF2Ax1HsvJhuxiyOKBDbn2q N8ivnjv79B62epIdUc/zGLP1In9yoQcDfenYlBI1PJL7nw4JdxFGBS5ajE/SftAD FwsuKvIlToO2s0bn+d6famRnxigWOhjr+/Bm/8AP7HAJdD3Jes6AJLsuUANNUfW6 aOU4u35qnEb1KZIrvozH =ZZtM -----END PGP SIGNATURE----- ================================================ FILE: sig/v1.5rc2/sha256sum.txt ================================================ 2fd209ca34d0891499bd32f59ec332b0b3048c449c388d428e5c5e8132a13e81 jq-1.5rc2.tar.gz fb7c57cbce7073ec18f669a313e956864dfafc58bb0c1a158881335ad7daeb58 jq-1.5rc2.zip 7ece904edef3f951ca0c6f68cdb14e782d52aa46624fe2de9cfabfbd98fe5797 jq-linux-x86 cced974e1f2c50d6203e09c2e3ede44075c4f35601233378deaf7bfedb2b4aa9 jq-linux-x86_64 25f930463c94414fbff1ba5d76a9547259073e8acb19f709880e913ab58586e1 jq-osx-x86_64 8bf6bad065dfe5bfaa4c22a9ca80fddf8bdffc06b8fc768040e4fd88fbe5f58a jq-win32.exe f8301b1279ac95e09fa9bfb1b38d411e68590bedcbe70d27ede7a70955d855dd jq-win64.exe ================================================ FILE: sig/v1.6/jq-linux32.asc ================================================ -----BEGIN PGP SIGNATURE----- iQIzBAABCAAdFiEET9cB1vqbPS31rJNdrxkEDHFSNAIFAlvbqFAACgkQrxkEDHFS NAIQNRAArTVuw4JwSbxKzC4Y+ib1Vaz5d8ntQwmiR1FBJ5hbi5dMhqD81Kl4slU0 0IDBia7Bnvthk0/H+UZHjUdkCNW8rubg87zJOt8t5XXQmIK81cPgKhxqhPA6JPA8 RNmBGs5gAxycm8x4X0EMOVTsVqAfq8NYakO6MctRlv4ut3lXfWe+prIMBpFQZr7l CqvmBY8xhLF09LLBEB+RTjhDeW7E02cYFJIW9bbcvpECmnX/fJTjGwN6+Blaq4ln nJwODDZ61TGC2ZAYcAoqcA8bkU8ms0x7RCpZrRbYG4HJstSYM8RaxUxvtW2zn6Si 7FpMvrXnDn6MWr3wph96oRTEkKQsRhxoxo7zumaiKkaAGKjyN7fFx9z89QrKoxrO CAzGdHjt6YSmXH60ArGUWKGRilyvxieKddXD3fMJ5Sz/u+yHFRNDIuOQt+KZaOfC UlvKXQamexkXmK3PEl5ZPxcuK+G/NLFawPlLLHVvdLx6B5o4r94ycfLLYqzDCiby v0EDZrgVropUMUkJJMjSmioXoizK9KZ/fl5fj+2miHEZS+s+YwZ5aoPi5IvrFUhi sYz3wEKHp3aYzTPhPt3wBU9aaWoTradSCP4pt4eJV/VeVND+vygILdoD6xFWJoc4 BT2tBrUR6uqdQXaCn3BF0lCfI17fab1elYwBkh291wZeKF7qQ8Y= =cTl4 -----END PGP SIGNATURE----- ================================================ FILE: sig/v1.6/jq-linux64.asc ================================================ -----BEGIN PGP SIGNATURE----- iQIzBAABCAAdFiEET9cB1vqbPS31rJNdrxkEDHFSNAIFAlvbqF8ACgkQrxkEDHFS NAK+UhAAx+mFwf7XRYLznTU4HoDzW3yn/H+amvYpphvtcn/eB0GsZRpZ3+EIkMUe VF9Qxidw39tZeLROdX84iaYSu1bTpd6vAdx54rMUZyPVry6m5hqUD78LccPvIDCk EyFuRuAAqlRicyNuqtlr9BUBoI7Z2c4YOA3Y4oXlOXtleL3SXKXcGvhcWQ4owZp5 MN6tT/lNu6sj8l5v0Y4GxtfDg8YOap2s9MdaNNkAgt3O3J98gadAin+vQ34ekKWr zsB7QjZaAr8OSGyWCY7BTc7UJbsTIzFzSPvYGeIP2iCBSpR+qcM5/bgrE+Q4l2TA t+p6vF1UVo9MkhEhD/2Ru/ovjqRKIVKA0J5YvEzr2jWjSAWpc75y80rovqW/vjE4 GHBJootozgrUwe/ESTATzdyfFQG8Du8znnQp1Wv3upRPieCKiLiUkRZenOTvBIvW rHhgBR73vfhyD92exum4Z97hglwzjWJZRYohyKz+D0tYffH5lG4DV2pToREMqslq 9Yr3eGREMD/6j/zIsfzKxFeC/Ar+vmZrate9bUPwX7WYdwwbRcmx7zI6hIszFDnc RONpuJokLxcgfVC3Q8Tzo5cRsAJ0eiQwO/K3oU/ZSAjJkV17E+cy3KFm/C0BSvXx BHxK2D3vqCsbtlfkLurxzjvFKIAQtFO3yfSI5mIMnWfRCgvoHcU= =O93f -----END PGP SIGNATURE----- ================================================ FILE: sig/v1.6/jq-osx-amd64.asc ================================================ -----BEGIN PGP SIGNATURE----- iQIzBAABCAAdFiEET9cB1vqbPS31rJNdrxkEDHFSNAIFAlvbqGUACgkQrxkEDHFS NAJT0hAAvuHiFUoXoHh6fJ16dY+ZvY4lWqAUap+mAWABuMpWGT0nfjq30eqvCY0e Vjk46ENJPNjCNQnxMRq3kWMqsaniWLgU/sbXK1Ws7RldhJbxjnL8y/jHtNHQtrKV +RhcJ3FhDzLSHOnIsTYYzHFZ1D+qeU+XMafVnnZSCj4SjEMZjzo9VyHJqyu+iG0w z2spLd6zFp1+6EtZkdv10NsiB69HhNxKUn0BUE2KOfasLpFZSoMN2OXNx9qatTJ0 l/+PKzSb8DkRh3uHtowyV7VHrPUQ8/WcyRqwNKMmJaB3WDDwsPJxgQT3sJVpVQaj 4d768B23NbR3LZbqPgczu50kn/6Q/DJTm7J/TNxKIOfnCsIMsiIhQ+oLe7/8c0ph xXhNZqzi06jB0kulmGus/YQY+Nojquzc+mMOysoxYo1iWscxWoK3GrImO3YMACk5 0zH6pHgLBlWZ/5ScKmvAn8tI/EfSUnsR/QMmFEZsc/80tkZBAJd3HPeamRtLqCon T8aSP+xwwzo1BFhtdVddYXlXFWIwtn9VhEYJvXN12eyhW+S+dKyUlJCdCAozkntD QxOILIc8RF4F3KvQTo+t91hbjyPGm760/iQgHU20UpRxaIkJylQ6p6rWsV1wEMMr QEENmAs0IyawgJGJ1Jr7AKOR1fqEqW2BJxQ9zi9re+dXOvVWMI0= =J3nx -----END PGP SIGNATURE----- ================================================ FILE: sig/v1.6/jq-win32.exe.asc ================================================ -----BEGIN PGP SIGNATURE----- iQIzBAABCAAdFiEET9cB1vqbPS31rJNdrxkEDHFSNAIFAlvbqGgACgkQrxkEDHFS NAKFsQ//fWWzw7pWIt2v0vCn3VOAqWv0oB3+YEhqmYNv3UJ5cJBeOndR4C0kT2uH MnTIR5WCLw9iSiNkHUX+oiWT3Rw8i8oHkA1Ub8sIin1RksV0TosTQa++9XqdO92q HBBLUe1Y9BcIU0MgEKDtLXKwg6wqW6zAl0WI5/fIPT8Du7evhI32s9zVTMH4AahO ZUM+OXmNCRDVvVp5LS3fZR8E+R3+Mt2ZplGb+aLmoX+hvVTc15GfVtFLGMz2bF1p LVG2/qs9XQP9nCaPm/JCB1F04nHTAuUb5BzJtdJUpqBJGN8diQrxLigjyxKsPVNw 118r4Q/6FELTlMg9+6qOPal++ihjuCNWex5Mqz2+ZnANvtRYVx/5bF+DY848JmqP V2k0JF/pRnwaCd9ONzYjkWcCMeoAAvwPygl20NFBUgTHC/xdh/0j+glG0IUW7Wt8 2cJyG2OpGqR8CHTc0WDwV1SM937B9CuPjYANottrl2mDmdhhykO5gpDSjf7/is4y 9sWr4MqI62aI8xBVdLmTsF4kzoWfC5go4SAHvXlsBr7bMW90hkcuuY0giB0mWZng VQtRtpddKmhstLGoKMWf7TblX4uXA5Ym03LzvwhGl3PlwKh4HvkVYBE7EaSKuJ1g s3WxN0vP6mP1nMFF26fC9IapYWIcTXjyJ7Hmo0Okwn543E37cQk= =KfqY -----END PGP SIGNATURE----- ================================================ FILE: sig/v1.6/jq-win64.exe.asc ================================================ -----BEGIN PGP SIGNATURE----- iQIzBAABCAAdFiEET9cB1vqbPS31rJNdrxkEDHFSNAIFAlvbqGsACgkQrxkEDHFS NAK2Sg/+O0nHwVg185EwKoORwL7TQ9V8VSV04Ska0lKJ0Biu0w0U8k+bkzhY5IZ5 IdNUZb5lhnPpLosCLlzHlWD3fNkBbpYLgxDrGDS7EujXcp8lI1WrwVNuY2Gbz7c3 09YAeF2ENnutS4KP0BUfdEVMlEqQIVpGldl5jKgHxlZ8nP80z6IpNL9FnX/qwkZu /fyRthz1XAEcDHfzBtSbJCJ58QoGwl4S96TsuLZnnBuNgNk97SIeiDzg7tN1FmF2 wyg7mPZhIdRaGfgRLCqO7+qFGiYS4esJj4SbLiWDREVKhqqnT5B/vF5SmshsssUm 6MH+eK0BAGIntTs0fIGtgkiiuZI4bJpkxgfr5P6/F85U2d1YAJSyJubVMJhxx1U3 vKjUYzj4ub9GieT80FFmNAbuUTOFY3y5ZLDl3WRXD23/FpXTxWvTMNWs/Ypt67iT SLcpC1iAETTsaAzLnPxPtwjApFJv/+Wy+CXZl1xAwDHH4vnSddRaSjjl9qsi7yNh U4KUAVzpHfgmsK0DY1P4wXbBEuXCVcUBhGIQ7z5/Bw0F943C1+tFz7MckQmbsvay O3+D8NeQGNb0wCIt/Ro/xIqSb8yrI4tL3+phnUxiZGxc0z6nTw1O9BdMRX6l5/5O 84QzUal8MoDWTy0pb1eqUaXp6Cek4c9Lqvc8WPq/csAE2jb/PGM= =xykx -----END PGP SIGNATURE----- ================================================ FILE: sig/v1.6/sha256sum.txt ================================================ 5de8c8e29aaa3fb9cc6b47bb27299f271354ebb72514e3accadc7d38b5bbaa72 jq-1.6.tar.gz e33f9219cd8c3851b411215dbac51d7fcca4a2b157964bfcfa56a1d718e2de14 jq-1.6.zip 319af6123aaccb174f768a1a89fb586d471e891ba217fe518f81ef05af51edd9 jq-linux32 af986793a515d500ab2d35f8d2aecd656e764504b789b66d7e1a0b727a124c44 jq-linux64 5c0a0a3ea600f302ee458b30317425dd9632d1ad8882259fcaf4e9b868b2b1ef jq-osx-amd64 0012cb4c0eb6eaf97b842e676e423a69a8fea95055d93830551b4a5a54494bd8 jq-win32.exe a51d36968dcbdeabb3142c6f5cf9b401a65dc3a095f3144bd0c118d5bb192753 jq-win64.exe ================================================ FILE: sig/v1.7/jq-1.7.tar.gz.asc ================================================ -----BEGIN PGP SIGNATURE----- iQIzBAABCAAdFiEEkwealRHvwLfWzb+1sNpg+0VLrxgFAmiLcr0ACgkQsNpg+0VL rxi2/BAAqwq1ZsOqkHK5MtgaL+fV/KtR79fuKFo2IpTC0kd2Bif8DEZedgTg2DNL ma7UU71kwEbFwOqroKoMNmLAJGrPPteTC8LCdTDYNTcMXMSWDMXmnm+WUtQvV3Vs rK5VavN3jxMLzafErfUH8ZWnrzMjZS5ZKPSOV+vgbjCtM+LsiG5ZneZ4D5BdI0o2 eoe/FA/VRoiEXCC5HOlYenMWP/zdGYVpLUQ4Xwr6ckgDw3LWKIjfWIGt8v9uLy1N 4oPVmvW9fUBXlONV+4wJV8yoomBXzD7RwYhRkdVK4B1SZcfbeqzvfeRXOlc7+n/S yteRmxcJbxo9P1JvFuIWXZ9+/2evsAEhoha7yp08M2go9Eum5SFvhuBAEB0kxsA8 7WY/wwpZxfDwU7o2H8rjPe/ciY+FTAz/K1Th5SuUocEhYdHXqJayOixDCmRVIhHt OQq82EHj4UcU4tkHf7bc1graF5XgN75Ld6/uhZeMdFv5VsfxKmMjyaRdQrstQ0Ng /wWtLGyTSYRznbruFpvGNvy655g1CMKTGvItfQg5B8rAFFCVny/KnwjeEvSjiKgF qaPYGL/TcVPVvw34agXFAx/gNEV/QDUwroYTvxzUz4qvAQ6MnpbD/hiuo6HbRCPv oCXy5RPrr2lDFoUi6n6YdCmzfP8KJhfbXC6z4DFJlYdeuKsu6MM= =9fDS -----END PGP SIGNATURE----- ================================================ FILE: sig/v1.7/jq-1.7.zip.asc ================================================ -----BEGIN PGP SIGNATURE----- iQIzBAABCAAdFiEEkwealRHvwLfWzb+1sNpg+0VLrxgFAmiLcr0ACgkQsNpg+0VL rxhU5RAAiHPJPvbbkt4cAwDupO8ma+PTbjSiJ1/rToZAybSrLrfRVRvSy6yDmVEV zvf1ie1sutfyMP9dWM1PANeXUg5RaQmMVWUWBl8MiXBiCd3g5D6lfFgzo7+GFUU4 9Foy5kmGWhx70xypuGqUdYkxYDEdGiMvYqb5xEdibT4REbPzjiqo2cOJBhNsG7ZM ntFzgfvqS2l0jHmtBjratI7La7Du41q0RLkNA1+rWNEE4RnxOY9+be5fBks5VzLa cNeIYjzp2Rl8LkLgThrjQlqKp2w67HWUsmeaFuIl6/cJQqPgi/3MbJ3WkxKFqE43 3dilzy2mmLEoKB1jpkPpewK45pI6OKJfyhAF4L5ebgqyV5M3WQzXLPUTxNcTeFJE 7NVUtROR21lhHs2QrW6hTbu2XY+UBgxhpW4fbjLUGaTyx+Ll976vPhdOckktT1un 7atnKOxkc/CcrqXvNSDn2bEJ0GzqsJjcIXiNVr64zx4LIvRASJ8HCK4VfjpF4ijy kIxYMb6OZwf8v2L1QAbA2j3Mn8jBvW5qs6HlKcFxQD1PwZGTA37WDtsMDawTonsN PV0Na855fKin4lSjn0nStu31Sg71F4K+OnBWUcs1ldAOPFlbwtVHQ4XZeXW+fKHO mXOqEIDK3JrhdJen9IHdk8+Srb8t+JJb4aqoTqQRgnAfxmdUyZE= =WaNc -----END PGP SIGNATURE----- ================================================ FILE: sig/v1.7/jq-linux-amd64.asc ================================================ -----BEGIN PGP SIGNATURE----- iQIzBAABCAAdFiEEkwealRHvwLfWzb+1sNpg+0VLrxgFAmiLcr0ACgkQsNpg+0VL rxjhhA/+JzlKXLwKeyLTweYO3SyXSXOhyYmgUSgUfnkKHZNgZ+jqrTR+YsYMlTT6 itXheljI016OwzdI1JqFDi7Au5OD35ErQxEAWX/zXty04XkyLyuh/QGE5A+6s36p 4ufKhCQyGBfGYXgHlsxfctFug4KmoQqqV7wNTsj9rZmBlSsFgZ9u1bkhTFIN6TAp VwF1U7sgndfFTy1FD00/xnB1OCEVxVo36N5gmRl8qyIPvxN3u1Q+k2gyyvg+Yj7p 5UoaihwGM46zWriMEFsGYoDiNoSD6bcuprZtK/y2gYXLAhv3MGCJw2ONmCmpQbcW ju4W1b3clYNzMVd7D1l8CS4+PoKJTgfkWvIEjle30vdICgMQ2wIa0GfSPABXfFYG SJJTVEeD5P6AnUfx/d2zzL8POIY25jjzRCx1sTSYkpPdv2zWk/7s2ul5aX2rXALg yP7DZAirYGyaEvye+WUFPtF0rT4b4Km/cZ8bdwv4Yn7ANVyik0y6pgjPnHVatS8P ktQ4hWLlith21vTZ2qPJNiDGHq1EnCQS5XCNMgJvazkBbZVcyBvCGdMyHWJ7SBuV SE5PcP4tUIdgM6mMKToDchFFA523K6NUc5AnWhoG0PellqlqrQzw+V9Sx0UWo9BS APPy3P+yamDZjKjkrtLuh+Bkwg/BYrCFrTn7yJpjZFmCPCN2wAM= =9OTr -----END PGP SIGNATURE----- ================================================ FILE: sig/v1.7/jq-linux-arm64.asc ================================================ -----BEGIN PGP SIGNATURE----- iQIzBAABCAAdFiEEkwealRHvwLfWzb+1sNpg+0VLrxgFAmiLcr4ACgkQsNpg+0VL rxhmQg/9GD7+72ljIgOti8muVAK3Wt5ZKWV/I8fmEKQD9d92kYqMGT1e2Zni+tFz pfiWFQrmF/O88mwM9KCkQQEI9Uk5jQ57lx2gWZiiZgk844QDgKePd+lf9nU9Tikh MlY5SnwiM3h8U+4CCJMDQWXp62p98q79+8IXANDIJJdczp8m/QuUuvPL2v044nSQ EAmZlMCFW6OV02AgukspwippS1wSCUkg2zf5o4gg5gcKG/xtGIhyB27zRBEBmFFV pNSPo0W26ONKgladM7V9S1w3iMbPZ1Flng78DR0ZeQOrX4SdoNuAmytKSt+FIFm5 V7WPkDP31mUpL7v6Q9INW8KSEhhwfQeYXVPWuclsbZ1hfH3AZgk2UtY6tyOi1l9f ZswkQmILfgZa3CJPiH5ryYhQQJAd/iDY1KwFD165C8DGpLNPeWVWx/8KIvVtJ7uQ iwOva68bZIhKFjEFb6gbbV1huuY9QIyXyklrwgtkrUGBDhQWSQ+uSs0Zkhmy1+GS idk5kGFNCxyaWIOzB7vlepUd4ATXbHdalzT8c4N2yLiOhQYi79kTnzLZUaL3tEEW ynIcr1Wf3M2xUUVcd43Q1GBlVlD/uilmoRl0e17jYOdq13xX4/M8797wdoOWgxO/ tDVFjI0Noj2jI7TR2qptvT4Hcz36uKOnnF3H2s1SXdyNGSTKGYk= =kcoB -----END PGP SIGNATURE----- ================================================ FILE: sig/v1.7/jq-linux-armel.asc ================================================ -----BEGIN PGP SIGNATURE----- iQIzBAABCAAdFiEEkwealRHvwLfWzb+1sNpg+0VLrxgFAmiLcr4ACgkQsNpg+0VL rxg1jxAAjxjU8b1TImyQZOag4hX/DguRuNGpIHUUsBMDgYzQ6JecoIaomanOkKqn 1K4qbqkXT2a/QxeyMVPDuOfSqfe9em3h206G6jXIUx4FRkAyUJNGvvYrjKLet7HS hZOAyp1GzFIs7syKYcCYx+w0I1WXJTp9CJTkTHYODDCuijl7z1YY/k+YUlysd3rq XkLJq6/1miZMTBP1aw4TYO9QcThu0x7HkRb35JmxZFp2C6lTakdIRWvtBjs1ybG5 0lR3ti15K00B4Y7P6lUabuXyFIE+d5keN4oDYnDe4naLyoZMh2gBZZeU+U3iFqcP +BF0N48g9l//voWfUieLEgl5khayvTWVrqPc1Urm5cCGwRYrXMaVFfOkt+0GA4ww dwoxljrkS4efEYpgPH7GjcGWe64rhIrGnUGaoKUESjDjGFN5/NC7Srra6LOz9qaL bUInJPSTRIzxImpNKYfLRKtFHrIiIxsF29iZrAABtYw9aMdkVWrT/LIFAFm4OrfM JU3vYoYtrsufc/dgEYZK8vscZvFvMzwtL9Yikea0rI25GEtjtUvDO8doxLYwlBu9 4cWDtv2t1lLsdKk+XDaS59/rWKDm6P68c/i0UAPWEESFEBnvJskLP+Jvu52omnmN 2HOZNJBp6/4ltG8hUCYORjaYpVZfbgc9bEGnnkO0OK504h5dpE0= =39s4 -----END PGP SIGNATURE----- ================================================ FILE: sig/v1.7/jq-linux-armhf.asc ================================================ -----BEGIN PGP SIGNATURE----- iQIzBAABCAAdFiEEkwealRHvwLfWzb+1sNpg+0VLrxgFAmiLcr4ACgkQsNpg+0VL rxiIWw/9EZ5FUJTf6B50+ewtwIrrSxUK15DetFVgG7uT1XFoM8IlUJ15cY1Td0KT dG9SGW4GFK5L/8rqCHO8iLCOo7+kiVQtiNgs0cthKPn6/UA5S3ihWOZGr8AJksVR odbuG2CRcUbJUK5S21RSlNP5DS2RtOZaEeZrea7FAvbMSiPUpHmj6PShY8O2lbV7 EDkwItVdf21sNTU86NvFVwgAzoRCnMgQKveDZan4V+SiyCtGlEr7l9tJ/8FkYHgA K/SJKmIgnGtEUJHdy2Es7OCVWmenKfQ9iNFf8ixD4M3/esXfMbNZX//kLzfe5+xU VkcGQvF+L/oJyvUbw1ATovyhoijcE2+DtmRkxKdHMP/7IpxhH/+ENRC7zdIXnFd8 8OYTn2GEwwmXTLnTZ6DuGeWiB5xZMyoHC5RilPu3QPG8WoPHdNVnA0Wg+YLBuliK XgfxJVOPMSOc+9s8BVPw3oaMcsP2lEmUeIOTkdAIcBN3wX997oLvGaApfTzOvDKy xDOB/JxvCbnuqZRvsr4rBzzKTpSczKa4lE9r4la4rM483T4fLqci7r362knIdQ6s Vv4CTsQ8/YTSXW7+I7khwDKPLDwyKuvPGi1BFlOQFFsF+ZanZtQOp5HmwKCZ7REj vpJhl9XCZuMG9E9bbXnrlbAEtMurDz9yryoEoZPqGyM/iN8Bpkk= =oAR5 -----END PGP SIGNATURE----- ================================================ FILE: sig/v1.7/jq-linux-i386.asc ================================================ -----BEGIN PGP SIGNATURE----- iQIzBAABCAAdFiEEkwealRHvwLfWzb+1sNpg+0VLrxgFAmiLcr4ACgkQsNpg+0VL rxiuzhAAgpI963y51Oi4DGDHv9nu7v575CG0G/QjNowGbu/zGdB7k/ygIsbE6vtI JA4lAgXWUjBxBgU0TubXc0JVnjPjIUlIvpgR0UImq4B01WXYitfF897SJChuzPx2 egD3jybvVe9B6JnZ841QXYkqvp2hZwgXKVGedjsen+qHK2mlbAoeHRKA0L5C35eX tNlycBvWyUvSjATNsy44G1LLu+ZUMKRXff425RPI/By/8Zn9diipzXCusFl0b5I5 hOdL3BFcqp4JXtJSyR7Rv1BKnCsutZMwSXXPrTIufXUVbmBv5ziH9Qb2u+pTL1Zz 23JbG99Eyw3BRGKYbdr+t01OUVMm4IVP5wrE2gzl/elr/YqwdDBcBaA9J2p6AlB+ iWkn1hlWQzgTyJLJkD3BFDzG6EgSBbGamXPJRneZZNQ5Cogdg+wkgNdZRxcn5N05 63K9CXM6mARMWWUsff2TEfjO6xQnXltU3Py99Uc8xfPVitccL7xQPSO+L6stzi7X 3wNT6imcAnpJHMj/7GqfRFAjHTmmp21IpevZhOImu7WknZvmKtBMQq+3SlECzyTB XuzNGcHp9JHtc8L7Af9lo44v9FupWY5rC3zQnPGPnQgL44xDQjimqAm38G3awPdk YYQI9EsV7Ug8pGiPXERVmsy4o8lpdiw9VBzdd3h5YElWdnrzRjw= =uTvJ -----END PGP SIGNATURE----- ================================================ FILE: sig/v1.7/jq-linux-mips.asc ================================================ -----BEGIN PGP SIGNATURE----- iQIzBAABCAAdFiEEkwealRHvwLfWzb+1sNpg+0VLrxgFAmiLcr4ACgkQsNpg+0VL rxgmwRAAkSckwt0TU79XugwnwT6Gr1ctvLvyZGplF2p5VyqJGtvOAutuPHAbm7m/ NUyKa0G/DjrVecERDJcxMon0Y+lo3E/3Z+7eQWQjHcaxJv9dI6LRhqeIAnAzTrBs IAbDoOrIKq0O7B3B97B0WomjgQ7NhXbfru14gKZxNDcIFIsc9SGEi+fm+CI0ZZcL GTo18cVZxn12iuXBt9SlIRjoOUTiNEZFC5nbEPbitMfbcAcSOoC1wVumreMo/9IM UrEKN3lCNhe2yjDUXlVGzHxWMD0iTw6TJU0XmUYneQhbvn/qHgyqp61TivQEoeUf ylh69Vt3liZu9nh8xehGUaJRjPr949QeKa/WChE5paMjI8RsC9SpQR8Lcq8lP7H/ qseMU5rwCVNQYhINkrYmL6P2pmPY1qZOFObte0HBdmJ4YaTqgm0qvAXrw9RnPqNX QJDJroQzsoL3z4cGx5DuaL/BMn+iDWDJPjhEPWiRaZycuHkuwlz341VZkJVWxlFS CDYbX028T+4dLOKvKzcm8kVTX+IEo/DGgaalhU7ialla3/+1ITJrJqFCtExOtLEg kt+x4uARUZm7mkCLDXy5hvyGY3Ai2YcSQ2E0F5mwTVXtwj4L8x4joCcPYlrW+LGz sZh0Ohb3HGB4PczyAIyEBy7QhJcEp2+uv9cQXdbylN42zddKeTE= =eK6O -----END PGP SIGNATURE----- ================================================ FILE: sig/v1.7/jq-linux-mips64.asc ================================================ -----BEGIN PGP SIGNATURE----- iQIzBAABCAAdFiEEkwealRHvwLfWzb+1sNpg+0VLrxgFAmiLcr4ACgkQsNpg+0VL rxht/xAAjF4ylq0qxdS/A/fV2raQOpVjE5/MxlQewhgqYajLdcyZh9z+wB2yA48k NnKY/wvif56WlWITjJLQ22eIb7CyXXLRZSJWBCBywHhmOdAaQURBr5aEO22N1CcC PSy5P60bGey2yiua1id7U3k63jBee5Ai6fo57Rtlt+NgHsax1CGefRkZjxp3w26A i7AzmxAND8Rmlh36HG8J3lTleAq/XD3p8TsVnllz3+RXzDOpLO6kyuWeXpnRCWJW zIqV/xMaHPEA5VhpQs6M7uvo9MhLkBuR8oo+LKeadSzm0AEGsJha0XzD10YkoJP6 a3Z7xhMTT8YZrepiYZpSti2UnmKUJHTkSCPvMqtiRJLuYaO3hITW/hsLVpoK/p8F oJbE9ki2L+jdc773a942xT28P8lQiEGcG3kKTWsfQhY9ddSjggO2ayaCPuf3f2N5 4a+awpiaTfZrynywX61ooaWiWeCks1XExH21HvMTNB1LX1dD6L0ueayIVyokglyx 7yiUGxKau1Z9zDO6cxjifZUv83umOc7x/gikGnLKb+Vhnr5HycIyllcA+cn3g2D2 caf+UXMv1mqZf5xZHU75kPnhtiY6VnJFFe6y8VI8p/HYz26hZkLslP7rz9x0llXg VZUWB0n2ONB6zPANXO1Eoc/SkuiUB3FIOctA+N+MytV1mcrg2KE= =lsxE -----END PGP SIGNATURE----- ================================================ FILE: sig/v1.7/jq-linux-mips64el.asc ================================================ -----BEGIN PGP SIGNATURE----- iQIzBAABCAAdFiEEkwealRHvwLfWzb+1sNpg+0VLrxgFAmiLcr4ACgkQsNpg+0VL rxipcRAArhIRURauqvYE2BT0dcmpeF1up0VytyQsmsEMsnRufAtCs00G4ZrtvvbT LBhxWgGwMw0trpRwML4IN4gVKsCEINE0Z0t1m6WdywqnjpPEjZs9FfL9HpGZZbT7 WV54jE7Yd6BbyfzXLfWvRQ4veooEPjKNESq09+4lKz/l+eUU5nryRlKrMOzZneIp 4t7wYukvQPyWgJbLwvL+jgPePqZwBm/fxWDuUwVWlxSVFwfw2VdAdllRWiNNdGyK mqVGMNHBxTBmsXZHqF/JRlhlMjoabB20KDPpqECWIhrRpMlA5K8+M9vc4K7cY/Xb Cw0mPtQlDyyXk15f+xbiYpFvSotUX1tg5Od7yAozNioPxpLnPeKuJFIAzNbDwzxe XkrTd2aC4GhdHavtWZbeNW7MTJi12qbMyyVCL8sme4UvgmpC0rXVQk0y4EskPdKO gBwFmFASvSbeFlMO3FJsIQEbE3crndxTLdka8IxJo6Hb1QKUUszxjovUkpUoYT5+ 1OHoDybHD2NHzziutEfvS6mUujkRf2WVQCz1MzPDxi9A2WVvBBb8V+OWbpGYcBBQ 6l8/ZMjIdBzFDKBjKcM7AH3CO9lvH041Aaxjv/Htnih5toAV6Jc7eE+hNVT54is5 nek76gPDK/RpBnAxNL/l7Fal57bi9r/kKmgByltsZKITBSJCTLs= =NM0L -----END PGP SIGNATURE----- ================================================ FILE: sig/v1.7/jq-linux-mips64r6.asc ================================================ -----BEGIN PGP SIGNATURE----- iQIzBAABCAAdFiEEkwealRHvwLfWzb+1sNpg+0VLrxgFAmiLcr4ACgkQsNpg+0VL rxjCahAArur1py1oRs+EwF1dkfn+fTehMK1tMwun/H2l9b38FgHiR0Vh8K/GfGCZ z39WOTM1Wa+T+2UzWGGx/HJZRsKR5EtizryUNF8ZgwMjcyFspGCjNGk7+4Nw3bki HccXa73b1BbO2ttCIvvzDGSWiRfaToe6Ohs9ObgJXsHjBQ9ub+4y0UKr3leya2O1 +yJYZe7FERCCE5dcXSW1X0DXvhf40IHzi2WFKYqiA/ymWht/kyv4cEQsmpv+7ZEW WNJXvqmSHIaL4EA9/AZ/a0L/F7uHwBnY6oiJmTOzLoxxzHWC3HMoRF2IkmPek/lF 2dUiqHEloA1BOADQW9yvSeUW7jR+SrJsKspnp932rHguP59cB2SOV2j3ROeTfwhK +Hpy3edLI6He9F+6EjEvuVwYJTDpY9t14j2S4vDgcQIGr++u+dQoMasHvvfdoA0I 2I1ooVlwmkRQqO+mfHc8N3hMBwjRUpU070504eNcO1JUhlh/VNKTkcCvyXqVyQoR tJJsFbRQQCPih8dYSdDbywNqSCCbR3bSyYLmJD97GEYlq3A23NAFI0RK9VLHYIAE B5lUEtOqhKOwk635lX/0n4qUY6Jbi0Oh652hq8FXcSUa+ayUHwHslt2f3cR5Y2Bi O0QtpKhxB/Lxmnbs5XOLrMQKDdtmQRz0TzBhuu5rK6WvdeDbyNE= =MEOn -----END PGP SIGNATURE----- ================================================ FILE: sig/v1.7/jq-linux-mips64r6el.asc ================================================ -----BEGIN PGP SIGNATURE----- iQIzBAABCAAdFiEEkwealRHvwLfWzb+1sNpg+0VLrxgFAmiLcr8ACgkQsNpg+0VL rxjOOQ/+MqpkUSs5vAVOziON0kVQC1Ki056+Z/h1TwlIXqLczHSJxKg3BWDxKada g96LCGipmAA3CPiHpMGCjBNgfnazYVRYDwCOViF7TQ1/QXM8ye//DK74NYEU8nxR gt9DZ3myLWvcjMJ/xZqie6RgBXprBZW2KE5WC1lZ8sbRF7sRQfmIYoWbuNxtIkLb PFBbaHXt1uYHORXnws7Df0tO4BUnl30j+nf73ZDEiczINyA9NjwCYuw1HY1xnM8j WsmjM1JuXluMGB6fm89bqzEBkSzo+96fxxv4GE0dlu3epwLKcf56E6d5vp8Pa0Zf y73nFZX3CgjrJnatmX9cgqQo7DLvd0mxOZLdycVG+qgeHmURpqW6iHfOTw3qi1r1 kpA+w78ho4LuG470q9lhosCfuyqI/meFeWjnHBIgs4FPdvyJF8fTc/ll/cn3DZFK MLKXbiN34KusZ0Mlw8ylXRELSMuC3sBKHskEfBFYevl49AAHjF41mvuzNlDouVID HlFN0OizrhDbwfRxJgUFSig8G+5CE7shbYlMjFi5SBLNU+x10XxRA/42j0Bh13e9 au9MR2u8zXCFEAwgF/nEJBwexqSZwDHjDpTR4DORhsszrt8K7t/BYyMtKz9+HQtC rV5aoSfUkyPQE12rAZn/9adyMmDkVE7dFZJb5KY5x2LBx7wuP/Q= =A+Z4 -----END PGP SIGNATURE----- ================================================ FILE: sig/v1.7/jq-linux-mipsel.asc ================================================ -----BEGIN PGP SIGNATURE----- iQIzBAABCAAdFiEEkwealRHvwLfWzb+1sNpg+0VLrxgFAmiLcr8ACgkQsNpg+0VL rxilxw//XVx7z8DBeI31/3ygqtEpme6v6SfWKWxt65nUPxYVbYm9zLnUrZlwufMH 1cRqRGTdGQU5q4TWeDwYYIO2dX+qSowTP5PQEKy33IzY1ASB191wOdPdgVT/t4oC 31Wq54fQAnZB8yDQcPCFEr7YptZRKzBxpU08BPKrYm02sm1OvqVhknzY6fPsh6Ji lfwrdae+78b0gIGTHrtYiVo6t1xccBDOZH3FMkZsUKPJlyr4NOM/GEI+3VA54Otv giDtH0/vngNXGhR/gve4JBpY/pR+s+2DVoC9qRuGd7ncuNr9IKbtjpxFZWvAT68d KywwU7rxH/az+s/IK0E1un9e+eCREcTtsJc6tZa7usl23TC1P7a2v5t5/iT0ud5O CUrPTj1oIazZNCPORC0jVGJ+F++xhCepCYSoOuuPllpUOyd3wdmtknuGrQTvq7uJ KR93Eqk2N9G4Tnu0ylSERBDBKEJviIoZSDaXL3z2tk2tCqJbUj/g5+x3oPKN+1kI 1xSbtV/5uK6JlU8zIJpbcu7AQFIyjkz7NSCGnAa/yT9cZ+xaBx/DeANRJjbkDMC1 F8vejc4O5f6/FG52GHFohhUJ3mgG8TnJPLPdm7C+yk2nUnUoegvFyVexFPUU0HOU yIdjXm4iige048m/Et8VqnH+pbO2wdMYmpQiWMn8pliNXfWNouY= =LCnN -----END PGP SIGNATURE----- ================================================ FILE: sig/v1.7/jq-linux-mipsr6.asc ================================================ -----BEGIN PGP SIGNATURE----- iQIzBAABCAAdFiEEkwealRHvwLfWzb+1sNpg+0VLrxgFAmiLcr8ACgkQsNpg+0VL rxgTHQ/9F+fhyRkb35aIPmZcfR+9ULr2GYlOe7fEL+kgrJVJaPeBwDayCxgUiQFt WQHWRT1JaPWVzUsgmJc5TQG6X1KtcHHmk+jcrVjAFkikqub+Sl/XVHBjAfpCK9+K xuqokXeo9WQfaBUfmncPp4BZpDc8/riArHfKBbwqEK2/u/mAQiN35m6ftpjKZbuk wuUvBHScUgVivBSmgFFA081iN8S7QgtaTznkCZAmZC/BXoS+W7dY2qxeNaOGYjf+ 1oDjEld7sotWwgZUKfUMbyWYOkAehtJHGMr+lahXopvjirWiMxE/kqlESzASzUbO cxZ/LLXSuY7KoiUd2Rw+KmmvxeBz5XJmSRdHLRF8Zpq34UtFkKqv8aq8iiwHwCk9 Fi5gr9ICI8Ufc54qHh8Z/wCgwv4+51d5Mgi2P43dZ5xNGNAv3nl6iPe43irHjzIz 3oB7p+5c6CsLRQmrRLTT1J7fWV5SSuLNpm6MpwK1jVezpfmR0uL1NtZzJ5/CzdxK 4U0YXJ8ModJgQZKRgIhSAJZSeqx0qWNlFywjcSDFkgkzmf8TlWNQge1hhlY8/duB wP935QjkWAH+7plY4XpLVm7S7+yRANGK7/Yw4Mc15ZffdBPFJQU0iOkExsvUKUbT gYXmNDZ/jfUjCul8h4nx65iSX+m12uybtLTFhIQfIaTXpPctWWY= =a4tI -----END PGP SIGNATURE----- ================================================ FILE: sig/v1.7/jq-linux-mipsr6el.asc ================================================ -----BEGIN PGP SIGNATURE----- iQIzBAABCAAdFiEEkwealRHvwLfWzb+1sNpg+0VLrxgFAmiLcr8ACgkQsNpg+0VL rxiwWhAAzBVIQxjaiQwEVOZrsgM1aH/nOa76bjAg1yIlGHV/N04wDHGqil/XToct Bkk9vpO6oKphTQa0PP+5tEyZKKGr/Lac64JJ4V72emJOaYjKYjzMySx77YenkH/U 8YrqE/VAkU1TXY/2k+yexGYtp72aLKtR/Zzb6LXo2Ry+UqRCjvvJ0ybrozB7F8Ap XbyQg8DGptAiQkTi/zCMvDJIkCmEJwN9Wgv+MGkhmSRxQnVxB8Zr0/OEDG8R8HsY PssC4T2u7GNEjQz8OUyMcjsCl2VT66aMR0YHcNsLUkqMJkqGUgITLnsBaN0wzeRG WABtxBw4yUM1Eq3BIE6dlb/CHZGIu9KCh6I1J6I2GNEjImoRbD+lfwXF2YEGzj+a N80ooo84EqRsLuslMuhMb46O/bZIKGxC8CbqucTjuF4tgRUBX9SxH5HI60z+9jUi dlV5c+WkftM7/Su9mtdpT6/NHDbz+uy9Rddrlk2BbftWGey88v86+NBcxSHE+wl8 /6d1RAb6MRppogRtZiuQVceFi7O9h3sdtRkBs03dUtqBi6IAl5JrdrTIq1p1gybo 7K6g1nXDvnm3FigsX0279/Lzfgg0ZzLD9zBxBDTg+DXo9qiW7fuMiYdFfy9ITANV 7Cxjd+LPhMw64U1q9vh1MzuG9fv4UvdYWKuk2Fp+4WoHug9rXV4= =Ggdn -----END PGP SIGNATURE----- ================================================ FILE: sig/v1.7/jq-linux-powerpc.asc ================================================ -----BEGIN PGP SIGNATURE----- iQIzBAABCAAdFiEEkwealRHvwLfWzb+1sNpg+0VLrxgFAmiLcr8ACgkQsNpg+0VL rxhpiw//WVObFLj1blZODLF2aq9TF5NE6TtB3ZEQqRJm+E9dnAxM7fwmu2WPEUK9 yfTsH80bFKK8iaX0VbTbssaD6zQl21p3ZoWCDSXnMbh3LyanbCBDrrw7lCJYUTN2 ZqoRncGIIDz3LAQytgZA2sb1BHTBXD7xWo9xXXkVB3gogCAJ2rn6Ekru+88WD1Lc Mm8RY9EYjkIiE2v22NQJToTvoQM3h7qK6w9LY4Inc7jgfXEjJomhUGWllvhHdt8V FBvSC/GRbP7wWeAT999F8tbSfXfcKfRwxt/7h1pC3lOmj+tERmg3H5MlVsPiT5Bz BEbiZooBpUt0cFhKl+SknAOdUMggdktKUp5YvEOxXiNqtifTP3pY5ZpJfeKwbpNP g13nBnYXXe0B+R9cGOoA1MDESAmG51KQgxz3VqJhCtvQZZ6Up6aHBKNBciMO3udS nWae+/DPNPRWqxMo2yoeMz5b891z7tlRUtcrrkMYAGDiM26BzXtV8NcS6ZBmiOEG +PVzKoPma2SZr+yIHrRxvsNC0rTX+dOzxDx+uogT5+1ZziCimwq/2CjoV9nYl59t fARgekwf38eD2XJjXRBlpTjIBoRInEukKvgssY0KlMtE+5Eok1PvsvdWvV670t3E 5zemeLlhciRqDwb+zR/aCCx4moNmYjY4/TZC6yFPmbOPGP6uc5A= =toBj -----END PGP SIGNATURE----- ================================================ FILE: sig/v1.7/jq-linux-ppc64el.asc ================================================ -----BEGIN PGP SIGNATURE----- iQIzBAABCAAdFiEEkwealRHvwLfWzb+1sNpg+0VLrxgFAmiLcr8ACgkQsNpg+0VL rxik7RAAxSJA91SLUMARACedULw2joxfNb52hpzTVCnhvh/EZ8/kI7eoZKk7MGle xrn1usrp6SPyuKOqSFypXARLXesUEYN6S857DHsJpUZV6lvDcSuuJ2J0zXnMNCu+ cd1vs3VKQ+TaL7ygl8+P+B/5K9bvCDt2GQhwwHWz5eEk2Iqvsm8vnWrPmjc/pJJ5 ckl/ojVXppkrIhDrQ1uJ5Hyc5ZN3uxjS3y+0d9S0xILeUs5funMAUSYnBnKKEvhg eRncIuOReJnRg1lOUZ5XJw5a5iz8htOkZ33wpW8UIGD70gUqDtu+RS7Rc7mdX6J4 F1juT4OB7LRK/gjhMPzdHMJcFBp1qUekLLMk6XLEi4ty/qNXiKhSsaIk8VVFCCWx Imrzt4JtxlbJ9ETJb9M6iIUsaUEkMYFlDGZlSNyj0/2ugmvbe/CZWFyI9OQkDck3 FxYMmjnmt1HkTsIOjRqEDHf0HDIdzr7B6p+wqNQKMKt/wKjGSKN4yjpwrS5ruPlb YkK9M43pbTuTvgEcXL7D7W3rqrz0KMSDcrgh7H6YUHYSkX+juIax8WhmhR5rkUUC AS3hO5I8ZqmMdnvYagNBq3dHOxZu113THo8oQ8M34zJ5R3/RB1pVGDdWW6E4kzTQ lJLZ3B7Dp3lm/kRGVIL+7sFZ62J9qMfhN6dYUHvyLaP4BHkfPPE= =2in3 -----END PGP SIGNATURE----- ================================================ FILE: sig/v1.7/jq-linux-riscv64.asc ================================================ -----BEGIN PGP SIGNATURE----- iQIzBAABCAAdFiEEkwealRHvwLfWzb+1sNpg+0VLrxgFAmiLcr8ACgkQsNpg+0VL rxgHFBAAx63JRicBn12SzDlV8Uwx4acJMivTl/79QCfvJauZpCewOs7szIsc8rvS 9lb0AYzIGis75FdfnSkoEVn9oLrS658j/kdF51fzsIn2F2gKG6JenFBWdX8pre8O /TM98uaW0JQQ9TLAaCA/zULkz9JA8W4NnmCUYdi/ULYthXw10I0CDIXOSr3fypDg uUa2pS1puIS4m8pkWkPlqG5PFJScBd8G/WQ5BTTA5EnQLS6V2WFu2Pc9IJgbPiQt cgZAx9YtFjWngfJgXagk30xp7AKJP+BKrTk/i0RtQPIG2Z0I1wHgOuysPySYBxG8 lD/2oDDltMDq9b5O8spMa+Y/Qgjkiar4f3WSk8bW0ox1OdQefXPFCQ9LuobEyJ6s 1SIe0LUfMJ/WwT3FS72g6rfRkd03ItvIExF6I33IR7H6v4LAR3X3F/tAYEsCL/qC r6H0L/EZs6Fi1s1xXJMLDtv2PCpEti7dpprYWNZhwmtfY7xtgHnLqNl9A10io88t CTsl94WYp8YqpYGNL74XM88jblNUHPDVzVk6Bdz6RzwdYhQgNWD42PlzPUiSuq6y JtEulefe5Pxg2LSpUWY+9nG8CkctfF2x/ZKgvP6rwFyLrVNnFkHhMPXgJEOnCEXo CiRdeh5B7JfUqwCS8LTkBjgU8Apx+79N6FaN7ef0K31IstFxW2c= =XkfG -----END PGP SIGNATURE----- ================================================ FILE: sig/v1.7/jq-linux-s390x.asc ================================================ -----BEGIN PGP SIGNATURE----- iQIzBAABCAAdFiEEkwealRHvwLfWzb+1sNpg+0VLrxgFAmiLcr8ACgkQsNpg+0VL rxg2xBAAnGkQwRwRkf5c9yRtiHuhVPLePuzB3nnGWhewqPkGCAnCY/PH7oswBmvp xD29/jZZ/F0cXT5Y7gA4iG1YDIAT5IHK21rJTzt2yL/Hu3rytHmUZKRlt6JawKpG a1EoEy9bxl3/1cv6zXZpOIzRpI58wctgOIcDPe/Y2J3EkJZCBF9Pk+no0zS3MhyG pScK+NPIEzqIAGWdJ3TKFMKSxGo0A1tN5H37mFL4B3t7jixNRsI7wR65S6gKVp7v oYTrBO07RqYEbdbREb/t3sh5CK5t4F/9itY0P2WT/AEzpvJnGmCtdLgSQmntggYM /UM6KIOMWs+RpCgN605z/jm09xVITaUzKXiZ1nvOPj0rUca+i372mwrMuTonQZA/ kZCjukyk9d3B3uLgXjq6GwepBwIPdHOl6Aj8cDpD0mOauYvUIkf7fi8BeuF37+Yx B093FsjZSASwlVLESXAlLW6O71S17QQvo/WePJP/wrlKPyoAivQnYzUmzypFpny7 NYTbuG/9CBcfyExksBLqElNHHkB4JcPhxhHL8uJrESSRA9YnaaXTlnGKes66tRky yzI9ymgueFwR4LOge4YCDoxwWU+dw34R+F1lz2jmlW5Wqa+pMTgVhC0w5FL++auG syiKTsWUObZv3NjN1xz2viEh4bR1ZnqT63R2vcHLjVYdl18DRI0= =m5zz -----END PGP SIGNATURE----- ================================================ FILE: sig/v1.7/jq-linux32.asc ================================================ -----BEGIN PGP SIGNATURE----- iQIzBAABCAAdFiEEkwealRHvwLfWzb+1sNpg+0VLrxgFAmiLcr8ACgkQsNpg+0VL rxiUSw/6A5cxFQlyX0y7LjUSA8RyUuj8aGfPfLfnCvvvt19qtqHLhIouMYGggMcL 52lCwsW89pBcpF6GIdLAjb7e2VxqiIMfP1vugf85o+99iurJQla/T/RviaAgSpCB 03IHawFEAwvVXd1E0PpAv03yVenvxmp6Mj6pCaI2lxh8nguV0Zoby+QxFgc8/WY9 tT12RKEMW8Ap5x+EzQVXgX2cmsKt3g62iv+5D944f1ZlqDQNs498YIojfsAuhi3r oZd3jX9RL5XAEzNe9e+tpE9cWkRwJ4ES+l099Jvad1dOkHxIlx9P2pCDThot0ddY 35GQ6jxdrYrXWv9uLAcaw4V/tBDRWFieUnmZKMZG7IYB6aOPRlcSQCYol4Z74Euv 06W9jwK5qduIZ6qeD0WP+MHNuJ8cZb16S4jIAcuoTfuU8z9DAg7UXU7/kzGBXhlE FuDYLKaVN9BCfD77nKKJLiaSufW032Dg2H/tmVcuvHY1LwKuvppqRFnv7OInBNni GwvGe/TYRwj1M4oKzDtD9eTbChNcqcuBmnuHVWojsG2RTvQHk4v905LyF6EfYuBW Mm5BgaIqMF6ZgibCwaDTIYSkQexgmPLXM5UbddZxOO05uhFGUA8oTajAmaSCT2cP 7mRtOrXnkLWzkXPSCS+ZsoJLDrnYuqE8POTK0m3Q9HxNHexxmww= =ysfz -----END PGP SIGNATURE----- ================================================ FILE: sig/v1.7/jq-linux64.asc ================================================ -----BEGIN PGP SIGNATURE----- iQIzBAABCAAdFiEEkwealRHvwLfWzb+1sNpg+0VLrxgFAmiLcsAACgkQsNpg+0VL rxj83g/8DAa+uDh+Fkj2nTf3jet4o0VX62Z89KzUBWtHsyPKlkxmN3qqYFwBadHG NZwJxyIv6MnFX5obvLF206aAsPIDeBYNYj81iM5hJZCPkQJZ1nWM6HsjABzXnHyz Z34B7/KFJvyTpUtU4JFdZbggoaaOdmx8LULhT9YN6t3K6gnYZg0doeMnW8EJqc/8 NsiT4p+pHXRHRJHneSJJC8kZrYsyfPh3XPlDr3zvBqAXRk+wELVvkZYFHM+auP/x oPkmAN2R6jeoRS6cvkm524Gjd8/5E7+GCsiesb+VkksXBEGbt8pzZuphCQp4pJRD DBfC7g4KoO9u+lu6/nJ25ToVDmo0QbEdiWYHqyboTtNI+eMJkWYRBmWs2u1wRKQa ZDSF8zTd/7JA3mOiF+T3Lqwt7Yw5/QTm989lKftKgnDmlh9jE8nSBUIdp5ZUPKmh MAxSHS/lC7GgP/mtZHo8tK04x3jUfQVFtY1iJOVpWhCu2jVJgHPKDXCNy2um5ext DKnwsNWJGq24/CK4m3b27qqGqTomRmXZKopF0YjhdasBrTWwKA0wtakiQaiQqpvE DExLIRrCAsrCRWrzBLkmJDQ8YwlT3AMfi5JlcxP4D1mYXfscj9q2b1RRHLCl2XXx cW67TuFDS4wMTLsPaGlzXKctrzXTwPWw6ZxlGg05WGk04wtWRZo= =dwCF -----END PGP SIGNATURE----- ================================================ FILE: sig/v1.7/jq-macos-amd64.asc ================================================ -----BEGIN PGP SIGNATURE----- iQIzBAABCAAdFiEEkwealRHvwLfWzb+1sNpg+0VLrxgFAmiLcsAACgkQsNpg+0VL rxihPBAAr9jG+Whevk0q1jxTwTKAkJQjoye9C1ToAFjY/NXWSt89XD+FrT9wsMt3 3jM413naDRmyZRiyAtGYek0t4RvySLs4iMXbna1lqet9lMxDieigF7q7iqtmjjCA NFy/qK8quVjaFWQcbzsCxrArRVNYYRSpYwLxhECLwvGzdILkFt8urYXIx+gpduwe dvfR0E4yOTVxhgBsB0uA97OTuPwbZfOzXEInLknIbOW+TE6OCDG++Bn1ol2gQpoP Hnk94kXur/zLWb6q7gwWlM9mcF1VHetMcYPyHbTAProS8ZxvM9Waz34vGrfZDqpH vnee40oQ4gEdhr1VPij44EItlUJBgNxFaB0kqSIEYmX6G54fr+Yg8WTLUGbGbl9R 46voarRhDA83qPDsn0CKzvA0vkGnaanrKR514HkfWJ/S3LiQaf2ylf+JQOEiT6+k 0DdgmCVUYBC4M4oWbQDbWwi0tUfcLsggwBREZCWNkEU45Gj56KbSfIsLzzg4+X62 1liZAhwxELCrHleayNczF8ZcAwgfVShId612bRiQR26RiS1jff+9ws8UR8SUZHbL KOhqPZX+kVvgMWdt3gxapHXZjaHt2ShHQCeQ7KEXiVHV4YHeyPB52t00HTk163V+ +glb9U8y0UyAJWWxKr1fEt/VQruYh/+IA2y/UOwhAyPLGEqgqjQ= =Ai8x -----END PGP SIGNATURE----- ================================================ FILE: sig/v1.7/jq-macos-arm64.asc ================================================ -----BEGIN PGP SIGNATURE----- iQIzBAABCAAdFiEEkwealRHvwLfWzb+1sNpg+0VLrxgFAmiLcsAACgkQsNpg+0VL rxjPIxAAqOKp1eAIvkBcjHkJMHBjkstXDaFfwgYxbi0P4hrKOOz13BNUJa3PEaoJ eFCd8H+SIUIKRfi54bouIQZ9bUwHYVFsKe6gnjZXO4uCUMzCBkj6zXvvDNGZ89R+ KaEDY/HUQ9Ss15An77532gCWj1aEYskIS2/2JAEAOIzQHU5kwZkVRAbh7mkXyutI 31LwxJOiRO6V8WpfkbeJYqr95p8LbT2GcgBbYwrUUUzwGRdRjr8je3OhZbQ2uN8L mjiuEt5QMhSr6ISsLeVJPfUURiF6Dxmk/2X77W2m4RqlYGzQ9LSJAjiyG8gR5HJn yi0z81PaVq50xfd8wpk/b4f5LS2Z90e2yrhfMz9fqJZdOFLApvxziVvx8UvP7EEA LLCnhCSPfcD+dScMIbwnZnuXJ348kxjwOT/mP7Q8y7BK8ZpW7vlqyHYLnG1lP2vb AoK0Ujb+6Au1oF9R7jBTTZ10QKrzG0uwAr59LRwuU/O9Fma89GSovjwuDhh3VQtW qMhmVyH7yXvrI1rHCSDdIDMqVXlmvL/sqpZskm0GsxvEvkoRccZkoU85SsL7TXzx Fe1DuDOOxGxPcAAH3z9xW43mndOYqivr/+jfwJl80h1n9Mhy9b04WlzCPb2ZKySt IgpLOvYpcRFfuLU/P1GIW/0hu2I2nlsHvPA1Qk0khmCz/ZznSdE= =SuRL -----END PGP SIGNATURE----- ================================================ FILE: sig/v1.7/jq-osx-amd64.asc ================================================ -----BEGIN PGP SIGNATURE----- iQIzBAABCAAdFiEEkwealRHvwLfWzb+1sNpg+0VLrxgFAmiLcsAACgkQsNpg+0VL rxihPBAAr9jG+Whevk0q1jxTwTKAkJQjoye9C1ToAFjY/NXWSt89XD+FrT9wsMt3 3jM413naDRmyZRiyAtGYek0t4RvySLs4iMXbna1lqet9lMxDieigF7q7iqtmjjCA NFy/qK8quVjaFWQcbzsCxrArRVNYYRSpYwLxhECLwvGzdILkFt8urYXIx+gpduwe dvfR0E4yOTVxhgBsB0uA97OTuPwbZfOzXEInLknIbOW+TE6OCDG++Bn1ol2gQpoP Hnk94kXur/zLWb6q7gwWlM9mcF1VHetMcYPyHbTAProS8ZxvM9Waz34vGrfZDqpH vnee40oQ4gEdhr1VPij44EItlUJBgNxFaB0kqSIEYmX6G54fr+Yg8WTLUGbGbl9R 46voarRhDA83qPDsn0CKzvA0vkGnaanrKR514HkfWJ/S3LiQaf2ylf+JQOEiT6+k 0DdgmCVUYBC4M4oWbQDbWwi0tUfcLsggwBREZCWNkEU45Gj56KbSfIsLzzg4+X62 1liZAhwxELCrHleayNczF8ZcAwgfVShId612bRiQR26RiS1jff+9ws8UR8SUZHbL KOhqPZX+kVvgMWdt3gxapHXZjaHt2ShHQCeQ7KEXiVHV4YHeyPB52t00HTk163V+ +glb9U8y0UyAJWWxKr1fEt/VQruYh/+IA2y/UOwhAyPLGEqgqjQ= =Ai8x -----END PGP SIGNATURE----- ================================================ FILE: sig/v1.7/jq-win32.exe.asc ================================================ -----BEGIN PGP SIGNATURE----- iQIzBAABCAAdFiEEkwealRHvwLfWzb+1sNpg+0VLrxgFAmiLcsAACgkQsNpg+0VL rxhlExAAyCOnfSnt50GJrk8AJYBQGxtWTf+S8Kvf7JhrKLojlpt6cGnr78+633jv 0jY6+O7QK8jyHmoz3kk8eaJvqG2D9JK6zx2V1T8Z6BIFX8Hv9rQFjfukMZhSEUTc OoyP12SYqk7Eq7ZpV8mfKSWR9x2bgrsC4oQyyUZLogyryAQzPIeW6uZu4f8p4/bh rWLaNBbf5Zespsp8F863vAKwtM8YakISrJEGMlZEVvoOC8QSpThDlrDhX8rezkMc 8mxKpGaqiQHkAB1TLz5le3iwWzB7y3k6OfcHv+uE2++b6Osvv1C7hma9DXMOOSIG /3V3WFjoNp6SI3jXTbCzoFTEsdUAr7FEzm5kjAoedWjkD2jvvio97xn9DnrVmi8i zuFzx0Bhv6KODorHKKCOphcnjwaZa1uPmN9mnt4PtWnwaldYjb8yPhPiPIkI7MXi mMwOHbCkQ/uPEM9toS7dzkBG102IDYkRY0GHbTJ/hMRhbkY1pahsnkpvDaO9Gz2x LIQdaBfksw8BP7VG8GsVHiCMRhhWExxakvuYpjLldX6QcLL6PCKKQbTxZfRfAOYT E0qa6JojqkZEdDMJi/NH0O2wN8s1ldTmdoBU7gmKsktnAZZHhXE4SS3vrdISeCHW AHBJ+pzs6D2K0iJjD5omiadt5X0LrvxHSUZTMDXuzE4ZRYKupkA= =qFrc -----END PGP SIGNATURE----- ================================================ FILE: sig/v1.7/jq-win64.exe.asc ================================================ -----BEGIN PGP SIGNATURE----- iQIzBAABCAAdFiEEkwealRHvwLfWzb+1sNpg+0VLrxgFAmiLcsAACgkQsNpg+0VL rxiaEw/+PytIQU+uIi0XE3cxgdyqaMBhV1OHUlLZmrWB99Q1te4R9TokQqI3kqS+ mrchFgBOtEuhhQAdJ4sDPNiT31oBW3QA8fNDkZtSjwpwEbbllhNWTE9ULXGJjxsL zZTL4brK5gBfZ7H+uK6keLCiAYHU255aPEbbt3vAwDE0iZiHi58esvE3s/5RVobN vsda/bhQRgPGC2vIVBsjIUxRNwsXSOBK1C7SWTNea7ocQT+HuyedY5nk7JQmojvg eeFnhF7ZW3X+tkM5scBd7jTBfmhNcEo4FYp7JttMy/H7h+2XvG013p9mPDniQEuz +fpp746VpOHr6XG5QdpSM1GmnRF3ZVKTo4cbn5GfLM4i9Y35HO5GA5adpfUa6G45 c7Ep3KqANaRySCSLLNcnSUg+4p366eUhUo87KPN9L+QOcXwybVJJ9iQsqzRZZmt1 EfsONLy5kTF7GjwFHML4Pb7ZiTjxJRIL3aMsbc7m9gYY/f6CKtfb2/jI1G/SjhQx T9pTLEjzL73iMUmgxx9L5VAG2qHnjkBxqCpMf7X6HCV+jTJmy72QE191KKmkYxZB pYkoihejFU3G/gdUYrqgJG2acbL6pqPX+Qc+CUaehCi+Y7z+GNU7o15j8L1byKpp NO2CPm/otvDk27pRasChkUwy3xxnkyxxB6OxAfYn28y44IcEVJE= =ZR81 -----END PGP SIGNATURE----- ================================================ FILE: sig/v1.7/jq-windows-amd64.exe.asc ================================================ -----BEGIN PGP SIGNATURE----- iQIzBAABCAAdFiEEkwealRHvwLfWzb+1sNpg+0VLrxgFAmiLcsAACgkQsNpg+0VL rxiaEw/+PytIQU+uIi0XE3cxgdyqaMBhV1OHUlLZmrWB99Q1te4R9TokQqI3kqS+ mrchFgBOtEuhhQAdJ4sDPNiT31oBW3QA8fNDkZtSjwpwEbbllhNWTE9ULXGJjxsL zZTL4brK5gBfZ7H+uK6keLCiAYHU255aPEbbt3vAwDE0iZiHi58esvE3s/5RVobN vsda/bhQRgPGC2vIVBsjIUxRNwsXSOBK1C7SWTNea7ocQT+HuyedY5nk7JQmojvg eeFnhF7ZW3X+tkM5scBd7jTBfmhNcEo4FYp7JttMy/H7h+2XvG013p9mPDniQEuz +fpp746VpOHr6XG5QdpSM1GmnRF3ZVKTo4cbn5GfLM4i9Y35HO5GA5adpfUa6G45 c7Ep3KqANaRySCSLLNcnSUg+4p366eUhUo87KPN9L+QOcXwybVJJ9iQsqzRZZmt1 EfsONLy5kTF7GjwFHML4Pb7ZiTjxJRIL3aMsbc7m9gYY/f6CKtfb2/jI1G/SjhQx T9pTLEjzL73iMUmgxx9L5VAG2qHnjkBxqCpMf7X6HCV+jTJmy72QE191KKmkYxZB pYkoihejFU3G/gdUYrqgJG2acbL6pqPX+Qc+CUaehCi+Y7z+GNU7o15j8L1byKpp NO2CPm/otvDk27pRasChkUwy3xxnkyxxB6OxAfYn28y44IcEVJE= =ZR81 -----END PGP SIGNATURE----- ================================================ FILE: sig/v1.7/jq-windows-i386.exe.asc ================================================ -----BEGIN PGP SIGNATURE----- iQIzBAABCAAdFiEEkwealRHvwLfWzb+1sNpg+0VLrxgFAmiLcsAACgkQsNpg+0VL rxhlExAAyCOnfSnt50GJrk8AJYBQGxtWTf+S8Kvf7JhrKLojlpt6cGnr78+633jv 0jY6+O7QK8jyHmoz3kk8eaJvqG2D9JK6zx2V1T8Z6BIFX8Hv9rQFjfukMZhSEUTc OoyP12SYqk7Eq7ZpV8mfKSWR9x2bgrsC4oQyyUZLogyryAQzPIeW6uZu4f8p4/bh rWLaNBbf5Zespsp8F863vAKwtM8YakISrJEGMlZEVvoOC8QSpThDlrDhX8rezkMc 8mxKpGaqiQHkAB1TLz5le3iwWzB7y3k6OfcHv+uE2++b6Osvv1C7hma9DXMOOSIG /3V3WFjoNp6SI3jXTbCzoFTEsdUAr7FEzm5kjAoedWjkD2jvvio97xn9DnrVmi8i zuFzx0Bhv6KODorHKKCOphcnjwaZa1uPmN9mnt4PtWnwaldYjb8yPhPiPIkI7MXi mMwOHbCkQ/uPEM9toS7dzkBG102IDYkRY0GHbTJ/hMRhbkY1pahsnkpvDaO9Gz2x LIQdaBfksw8BP7VG8GsVHiCMRhhWExxakvuYpjLldX6QcLL6PCKKQbTxZfRfAOYT E0qa6JojqkZEdDMJi/NH0O2wN8s1ldTmdoBU7gmKsktnAZZHhXE4SS3vrdISeCHW AHBJ+pzs6D2K0iJjD5omiadt5X0LrvxHSUZTMDXuzE4ZRYKupkA= =qFrc -----END PGP SIGNATURE----- ================================================ FILE: sig/v1.7/sha256sum.txt ================================================ 402a0d6975d946e6f4e484d1a84320414a0ff8eb6cf49d2c11d144d4d344db62 jq-1.7.tar.gz ea21e5402983d0e351f37fee72c2d456192c734ff7835e504d3d079dbf483a4a jq-1.7.zip 2f312b9587b1c1eddf3a53f9a0b7d276b9b7b94576c85bda22808ca950569716 jq-linux-amd64 ab57ee39075db4a23f899d396ecef3c6e58f6aada35bfee472468210bd126940 jq-linux-arm64 5f9129fffb49ff28a3f66a337dcff83a846146ad16a52784c1bcc3e5f26f3173 jq-linux-armel dd9786221a3a0f250ed227706b7300a69579529ac4a059c874c35a9efead68b1 jq-linux-armhf 6e8f12833541c5cff94c556d72c12585821fb68bcf09acef56c854d107fd5a6e jq-linux-i386 1a2a5f3706bf1d192577c34e260ff1550c24d8a93d2aabb64e46c29acd6847a1 jq-linux-mips 7b344267ba082af3b585ba552c0597a15cc76eca682a0cce4324e947f1cb078c jq-linux-mips64 3fb0c8890d4c07a22e47d3c794aa019df72880a5b84dcd2c2d2cf95eb16dc837 jq-linux-mips64el f4a06ca04d946f736f3754bc9a89cbfea79fbccc82b731a7816554f242357cd4 jq-linux-mips64r6 08015dd24bf546285881a423d582accc0d653b61aa9b99a1399e1d2f25308d57 jq-linux-mips64r6el 22dfcbd361c7fb672b6cb7e6aa47fdb73ca54ae27fa9a0127e291a80ec2e64e7 jq-linux-mipsel 319253ef37d3df187057f6cc99803bd03f234dbaf575efd74d1542ce800ebd6e jq-linux-mipsr6 badb7001ba7e4b9f13a95d65f150d35489904381a3cab415459d0e7e7b788ec9 jq-linux-mipsr6el 3f7b76dc415ebae4208bca4d031cd91362c12f302c56c2de07379295502d6fe8 jq-linux-powerpc 2157b08ad830c013346ee70edabcfb0a21bbd62d2c470423d1aa636ddd51764f jq-linux-ppc64el ae5f88513882250066e5773e7dff5b54e78b28493b669e7e4d29352339a204d5 jq-linux-riscv64 60fee34cc93b29905e2f27b713bf95709b97df5845b64cd1541bee461eb0bf81 jq-linux-s390x 4b4568fb5c6cbb8f1a8f640ff601c6d2bbecf9fa8f2cf796c7482e7054a01c41 jq-macos-amd64 b8d313fd4f3bd8a0b338b9ddd1c006fccf9312dc609a20d2d6e4bad964aa99f9 jq-macos-arm64 2e9cc54d0a5d098e2007decec1dbb3c555ca2f5aabded7aec907fe0ffe401aab jq-windows-amd64.exe 9500d0300e28a930ab3430a101ca940038b8e82ca441f5c9a1fddaa9d1b770df jq-windows-i386.exe ================================================ FILE: sig/v1.7.1/jq-1.7.1.tar.gz.asc ================================================ -----BEGIN PGP SIGNATURE----- iQIzBAABCAAdFiEEkwealRHvwLfWzb+1sNpg+0VLrxgFAmiLcd4ACgkQsNpg+0VL rxhEhQ//Y2Eeo5cOdVdpd1TXFAKNuihry0Y6l9OcZy41yysHfAj6iEhzjuIMeCBO KtoZU354/5FH0Ndevk+gpPoU96T4qREsrZlDyjieXgkCucYG+oNpW4k497DPX+g+ GjEUtOVtMh7sCHx6CBDdTKKzhTZA/Bk2IexKGr66wKo+8eF+GQF2ZwZ+sgd78DYm CBqlh9FJhAQVzCCrK1CnmAFct+N5k1oasFKjUPxdzS5wj4XetWWfj1rFHaexxC+n r5TCvq9YepiK2IgTQO+zo6bzbiIliRME3Jj9+C7fLR8wqpsWsGpfx+HY8Ie6OAiQ 161FyzQIk9U2MuN7rGTgyRkNLO/Zd9mBZZkhMgVEC8sFOUQJhey/Pk7ClwsJYppU tSVKrt4oO/URozk1xhGhaZAGw0vKCLLCDqjpKXrPEUTR5zqQjVnqjT4oBESI5Lvr /zG8Mw0ontK48D3cKNxuKzzUII1SStV+vd3vBXAglvB9/JTLgJlmiLoMGrnq9L4V KOMD852i8QFabFo/CsRdA2oh3yp3q7Fac+qu7D9fJMJtsCY7ge+q49mc4Tc+BBAd 7kkZ3OBZtTaUzE8hdAzrJTiXm9DprqtSA75UJ9Yl5uDYux4V7LVkBTslo6sbrYfR yEFIv6yULElJPwkGunooAwCMhJ9tb4r1JUvfJYSYAa+jt9i20Vs= =BKS6 -----END PGP SIGNATURE----- ================================================ FILE: sig/v1.7.1/jq-1.7.1.zip.asc ================================================ -----BEGIN PGP SIGNATURE----- iQIzBAABCAAdFiEEkwealRHvwLfWzb+1sNpg+0VLrxgFAmiLcd4ACgkQsNpg+0VL rxjSxxAAxez+Ag1zwobaMD0QyplI8GgXNmX0JaSOfHJjp6zC9qxEpjNIDslrINsY JZqSyOIc9Wt/gyVGQNlSuI2Xnd859Z6PhftQ96KFKxkUbWmIUJErIomL91nq1mPV prI5yVcs18xVI1WVZSlibx5G8HUwR2ZgNb6VDLvhtqJMjD2HPjjMcKUOdUbgF4U1 v+XMKaztiBV30/nDrLjJRq6Mwq+qVIn+FAyPP8hUvTDnNwhFmRIEofgKTMSUToMN eAgmNLwlBXiVO5iVJJVmQaGG6VKA73iCk5DTxSDaFj2o4yik5jVsuMincu+eVpqw GEqR+sUkJ1iSJuGRXGzJtakp5uOS7g9bdRQa8EbXFDm1AX6bgE/kfvWs8auv3+Cy N/YIedUna8UfZdltjJDdFDOPYd89HYkAUmL1OoQguOsM5gYL5wFGnNwxnIj50guH +8mjT0gphhuBKygf8qZxOyK3NFr6y6/rhFkrtHTIvAgWzmjSqFTWcq+8m99RRDbq V5OB2MSJeT1cp0LBtVTzP1zrXY6gQ0hNOorrxirzAEERd3wXBgqlgCQZ+tH1Es8D VGsbQGjal5sIFxtA00D4l50uPbfWnXBW4lbC4/yBLvA6+A2MC9WSkb0tL2Grkvks 4nIyW40kSaV8a0WvQk07567XDnJwZLJTATcMqtYu7RWiefCq/UE= =3DP0 -----END PGP SIGNATURE----- ================================================ FILE: sig/v1.7.1/jq-linux-amd64.asc ================================================ -----BEGIN PGP SIGNATURE----- iQIzBAABCAAdFiEEkwealRHvwLfWzb+1sNpg+0VLrxgFAmiLcd4ACgkQsNpg+0VL rxiHhw//TBEUiVj7hRN2sgAoot98X+iLpFY/mbChem01klE7FE/5GQ3rCuAuIxJB MjzfTb36yrQeeqH8xrHQtsjyyMcZ0GLJjkQxusrLtQ+xzfyRESFfVCXHialsmrqI 0OtI/L3y7ERKu09Iqo3ijeCa3RNAjZx2fQh/WOKB+mboX0bG8ZG8G+rwrqGazhix cdimaTcuONJ+87jUsxRDgP68LBKZL4w1h4iHl0GhGrc7rHAvDglmKeLfO/66qnMu FkZeyTmL4pVgsgQ2t2aEgTvLFKDqJUtUiEqUUmqwE+dn02/+nLLN3aCo7sw7zLjH 2k/7P7VDV7oZsrr2JQdshWSlpMjx3mxeLKuED5WM8fXwKUvktBlGPvlP0VmcG5CB 4eeAycj/iv+eSxt5HBYU5FtzbOtNWwrtt14AbN4RqFVaVGH2y/avjlPUKbA8Toz5 bnZ0rrC5IVD19tP3m4DETepCGJKis611myN2hJ+qCgm61UsBTttjx6zafNOpo2jb xl7TPpEfmIIGA7hu8y12rdOc/30RaTtTFxwa2k8oy0ma1IrP9A9k2Hy1AuOjLRal kRHE3H6PuYU+n6TcP8XgoCJtL913/M9iH5T6EVm8gGFJxJA3E8s7Ybv+Qc6UGk8r 2fF+WoKVyc6hdsasHS+VByPiuYdNWhts6jIiGGBybfb4GFhwFbE= =r9zR -----END PGP SIGNATURE----- ================================================ FILE: sig/v1.7.1/jq-linux-arm64.asc ================================================ -----BEGIN PGP SIGNATURE----- iQIyBAABCAAdFiEEkwealRHvwLfWzb+1sNpg+0VLrxgFAmiLcd4ACgkQsNpg+0VL rxi9PQ/3UjtaLAq4pQUQt1NeripPHXHyIvmy0US03V9jh23l4zjJlnysfjm1GjmR 8HzSlpdofXdsIdomoUGx/QeheJMA/jUf4Re53qM89Uae5L0t9FoXP1XuvdFc6xKH +F06AyT5qQHrM9RFkTk/XUQquWR2ILfY0hPE6F+uYpRjoXqDLIIfTXLWGZIAxxO9 jvT0YS0z6K2pM0ourhD5K+Co+PE9eajhPa7AyZm7NAciLNA5q4OzUqOva4VK1r01 wUzy68w8s5mOTUt4iATpgfn9aMcRloG6COJZd/CVeZRGQzNTjsstbXKlFzcx2G79 IHNgDnXFF+Kh4lG645TuboPFRp1xZlG7upKU09bM2rHDRZTO0nzHsOo0sGJY98ot KW3HtrHzwTftlsg9m4F9qVVqPIdjcu/ap3okEo9ADe4QJmc1VIq8XxVlXvhw6PnZ uvbkJbTGiHAn/Mrh2+A586j4/YTZSSej0TRnx5vreMg8YswEy+rw5oUsHaYpswKG oBYm2FPRhPFE+L3OyoR19h05N2RcBkuKRU80hLi7a73e/jX9N/5NfkOOiNV0p6pz GjJi/pWV9t1Tmr4l3kcn7SkViLr+P+bNY7XAhaOQNgHlKGjPjeT4xbvOQitCheyq vqp7sIDn1XrcEG5CsliMmC2sjYIB6e03QmPYSj5dyJ1eql+lXQ== =388h -----END PGP SIGNATURE----- ================================================ FILE: sig/v1.7.1/jq-linux-armel.asc ================================================ -----BEGIN PGP SIGNATURE----- iQIzBAABCAAdFiEEkwealRHvwLfWzb+1sNpg+0VLrxgFAmiLcd4ACgkQsNpg+0VL rxh9bA//feLBpnr8Qi62Jy4q2DHyzys9x7etjLF/eMG1ZoQoWXhQxYu7eRwabWhs zdDOzLlpM7Xtv7yvYeigIP+cUlkhxeaak1D3Xwyj1/2Yf/iufhbDOnKekHglGnuo NCAuUhjGsCFcpL75Gbb+IcSUuPaB36mB/S6C/EeVbGmArvA4lpo7KCYTg+05FyQC 8/lcnmNHVu32rJ22ojk+z9nZORRUFpIHIK2Pk77Vui+JM0M3nv2EDu3oXDZLRMia L7bUyP4GgTGlXHSIws+RVRiXlk/UMAJBptBi+vxhAWTrVmfcLjzYqAjFBf5AB4uu 7IVr3VcW/07UJ1Mmn6W03MgZtnvwCqgLRrmTiZDxu++WLDyQrpL3kuffg81cvD8f sGhv+AROwOo1V5gUoYVRA/kP16ph5Zhh+6HMJt7049yKpkAkZQes4Q7fVpGVapVm +mA3FCrIIrzumJCdb6J6arYnZHib+VG/vDnjRafR6HNn9R/Xl6aWuYcSVUlPmJp1 SJbzeFJEUFbv+TsutQLmkClGR91nOnFiUsyJZtASKjdyBRzNbWZeBiwQCRv7ckPU 5OoQFtEFXuMOY5HzPI/dI5CIXCXAMKJON0aDupNmNQ4EPDtEkRjnWIdy+M5OaJoE WySfSwHalmNuABjGhgdUZVROqs0qbSGte1XzoNkVp36oLvksP/8= =7S87 -----END PGP SIGNATURE----- ================================================ FILE: sig/v1.7.1/jq-linux-armhf.asc ================================================ -----BEGIN PGP SIGNATURE----- iQIzBAABCAAdFiEEkwealRHvwLfWzb+1sNpg+0VLrxgFAmiLcd8ACgkQsNpg+0VL rxgZDBAAioN1WXgi3onDx6SdbVaUnNp6C1BifwXXI2tQFFR5fAYfsjVxcZmM/kGV U85ITOs9tduggML2ZXWeNBiJcyuXHFA+BadvjDUgQWK/ZYInpaGMzdBs/tO/nnRR uMLuXbcPMiUmUIplxFelAUsjXkZrhomyRnCrIHB1IKcE0xYY/W/bWKzbUnx92jp7 w6qq7amivKtONyvoiN17NlWXhKkRr+ylwAm88mwKK6xkPVgN2no0fXJUVrhtA4lW yrC3Ff8Xw3XeBHvKy2WFoLVsZlOg8l8dYdR+vMct43D9p9v7rKPqGmbjKvdOC4jt Jf5tQ35lX2Up+/z06anIa0yoW9ywEiUNrmxNU9c11/VdoBRVX4MYz9UygAQDozje 1exr6hUv9H16+A7gsbmptRxzrJsvAGDaJEG45is3eSFtBoX63FkuDRw87DpEZwDT /ojNrbu4KsYIHMXqZLNyfDPCSGIARSMxkyey8M28sw/AWAZnTEfusKcRpn1zYxjX TUSWwPS+NLJFGQ43Re0FmxZsX1aNXfT5gia2WUm3IyxLgyyj79O6pTa3y/GbBXN8 2C4hiVPnrByvhLEq5WcgHDIYVYdwxTNR4YG6bYwkh1oCLedtkKwniKNGH/7yASuX cJvJQnwp/2oCNqeYV8heOhZlwIRCC7rZQbUkgC5uAZ/Xx2FTYGo= =KM7S -----END PGP SIGNATURE----- ================================================ FILE: sig/v1.7.1/jq-linux-i386.asc ================================================ -----BEGIN PGP SIGNATURE----- iQIzBAABCAAdFiEEkwealRHvwLfWzb+1sNpg+0VLrxgFAmiLcd8ACgkQsNpg+0VL rxiUfg//RIvFDrv+ie8dzd3P8DEBxQA1A3Z49czZcK+LwXmy2PJUivJgvnOXv/8k LnYXnURMtu9NwtpYXf1QD4Jz4q7I6X0LInaODYvGAV47boscSO287+xXVhulm6dN u0xLsuc6Mt/TikdWx3Q9WSOkB+1ZsbHFQ289S4Xp0zSQ1F4mpfWqBfEPqVaJPL1M PGr7j8IlWJ2GvVSf01t1aeHc+ijYZHdDm2YcHJ6vxbeHrqwFGXiTpllvauRkCj2o JgNVK2ilwKg3wUUBJXeAUxhaqoMmhX/6OhnolFBxkF25ir4jI0rzLAfr65Sfciyq Yz6dI7c1po04D9HA6j3QcyLI32QRUKa+nUMuNMf+XrP/jC0rsnOM+l04YneNGnIK RaBQqQN9J1NhTFClka+o6PcSaAMxypGbWNDQ4KTyKiXId5iG4Csq2RXEn+mLMDOH u5mlZp4ERp1xzSZAL6E0QxVatNCnB7wIZWHAh7bpNnt3tgvF7KCjLKcl6E3PLY7j iRKEDdrDhiV6hiniHPQk4dqYNxN4/E60vy4zdDNG/tHyyKHIjZsBUosqIAXRALia 3WsXu6Qka0X9t1OO8kznFo2UUhFS7x0NGaNTcOBCleP81JIfdpF50UD2AEEWwhMV 89yyN51bz2v9pumebu2NrhE94jLmOgEOQaUe5BzbwYLQfzE7jJ4= =y+Wi -----END PGP SIGNATURE----- ================================================ FILE: sig/v1.7.1/jq-linux-mips.asc ================================================ -----BEGIN PGP SIGNATURE----- iQIzBAABCAAdFiEEkwealRHvwLfWzb+1sNpg+0VLrxgFAmiLcd8ACgkQsNpg+0VL rxgcGRAAwEp2asToQT7ejK/dxWJ9RnWVT6i9O4HHA+77WU/8bp4qNbXKYOkmAVKl PyiFQxkJPq/fezEmRo4nURinHJiOnWRnznFeqhk5iIT3D4lubVwpQmVmJQvgamsD hS0YmSKgfG/4Ub43qug57uqw7F89foDGq6UastyDT2/z3emZxvT6gpMz1CuZji12 uZFHnK0JJMpK9a4yrs8quJe9K+lyQg8BLT2Ee/UX9TeqhdR5arYKNEWGtzSD0pDE FCDY+QgWxSIlfyGTM5dwOL/Xo4t93z9cDADb+d2q+4bIfUK+JoUT+hACDJYm5i9w M+FP9lKk5d7w3wkOoWKMnKdRVnCm/BMpeRHUhXct9QHGtAQlM8X1S2wgMeh3RSL4 uJxhb9n/jpVrCafValXCYKHISa00GfJFf35arZ50zrfrj+NSVa92fyvC/SNR7RXQ KK/e/MAUa82nU2DVJb5VO+GUMtWXK9zQZgJ64O4p+LTcV6hm55e/h11BkLeVGI5u C7PySgMttXbUVny8zXOCVtKw/yx4Kd9PKZUNhBkTocxPe3eQklFcdQLsrEEF+IIS pEXFpXDMzG0opctSMpp03rIQDYj3INScaQ2HxsetBwDqI2CkJH87s4V8dCVcpWU8 UQzp/emVyg8b1nkPyc91vn7rAiN19BRkYX3/VihPk2StcQbUZ84= =/4sS -----END PGP SIGNATURE----- ================================================ FILE: sig/v1.7.1/jq-linux-mips64.asc ================================================ -----BEGIN PGP SIGNATURE----- iQIzBAABCAAdFiEEkwealRHvwLfWzb+1sNpg+0VLrxgFAmiLcd8ACgkQsNpg+0VL rxgCFw//Rsxw9x76y+iOqgoDYsBmDCH4v40OjljBtDyC66zOwU9vR95CWhM6iTr3 dHsIqScDeAtMrY3aN1aOoPjC7JwYc3HljFNIB6m1uBAuRtaEFXfV+/z9rYK4vTFg kw/M7m+gKJY3AF3fz/W6i8oug211e2S3eeZeOUW2ISllrCc3LHCkLuGoqIlWty2v BQvvoEtYJRZ02KKTIZwWIh5ku+IFrTkc5+hxB9PGcEHS4qUnfhW0cRMP9/RwoBa7 7HxjXVHG6LNlUXASP+d+CtOrRtxlDwaGKZzYq2pzmBzm73wP7RBUrmxuKL3U+U3l p4cnKHBIvDdE/a+1QOLhL6zHZAE4WFfpKFu8cyyDhGOI5mxXPs7xDCPnF5GATETv WJ3BCPoWrfDGZpyTzonzx2XWDnIlc9weQ4aKKJ7Gbwb8Y3hHfSNgQlcIG9txgdFt ds5X/ouwcRzzB3zrGTk6Jvwpf+rhdmHnRiuzkpp4SefIQAvigiQ5VRhjxGKjah+b 43M+2wyc6539uV1oUbKGMQo11tWhyTSMYfUoJ9F5iH1za30xGQsz+TmrPZvwJdOI eOMifiamfYAyQnB/zmSkgiK8F7uOjJt23EB/F9ydJ1zgPC+fzzgwsIWKL5Nymgsu vobkSfQNdA131IUwDyCMLBgJgLi5nZ2YwhdFoPGf7NtISzk8FRU= =qIDo -----END PGP SIGNATURE----- ================================================ FILE: sig/v1.7.1/jq-linux-mips64el.asc ================================================ -----BEGIN PGP SIGNATURE----- iQIzBAABCAAdFiEEkwealRHvwLfWzb+1sNpg+0VLrxgFAmiLcd8ACgkQsNpg+0VL rxh5cA//c4nMQ2cFJWWbiZ8EWLZAtpzoXYEfjsHwKjT58xXs5WO2n/DNgr2jCuWw fZaqv1rav/aRXX9FPLaW+uYExY98axq9XxyCAGVmqaJyorXExJKOFzxeIH5ypZkt aWFeR3SPv4wTxW99bXy5Ut537l01quKPo2xUx+agdxPYGCl02HtOdFOyshNsbjxD 4LNDusboIY48shNRjeOIoX2174M1o07Bg3Kpvp4B8a3y/I9wZfLHGYYAcbXJR0uN 0Ey9ucslel7m70ibaHaTlr8Epzn7YFl5/XI4vJF8Dl68z1M9WkHRbiO8pSor5ckv uhXPdrbs16pyn/Qo/8/PFnA/jdTadaMzI4NuvVcvOp8YLFbe3UGAqlRjTpEs0cDg F/nfKF+PFfL1sb9zYkhjgCiRerhpGzdO96IuP7nzF78zEzfFT4/c2C/SBaLpwdN8 ax8YwsU9FRmu9Dp/aMy3y9H2QWmCz/vmBfwUGqD4qzNJesmk9J7HHgZqJ5e8SjdD nA+UlL9eVbXBJU2aD3x3+fX6L06irCR6JDeP/FiL+/25FZ8X4PZnL4LBTS3Ggh0S 4CPT7IUp7dsNvdQoKH8HlpUuBskzIfnZpwP7dumz76s3hxPHZEdvAWQGcEtSe/BW QvWSEqok9wTePG4P2n0AYKOmvUDpQPzhWPigiPIU9PRXpXBng1o= =wQpv -----END PGP SIGNATURE----- ================================================ FILE: sig/v1.7.1/jq-linux-mips64r6.asc ================================================ -----BEGIN PGP SIGNATURE----- iQIzBAABCAAdFiEEkwealRHvwLfWzb+1sNpg+0VLrxgFAmiLcd8ACgkQsNpg+0VL rxhB7g//UwWwAWCzjIIHrjCCzw0odLyEFWklrXhIvfwclCw5c9MQemR/qfuwzAQE +oRMN+DEs33SFRNokkGbhJc16BMqEX6l1msHFlqHc/HBX86HLwLmeEIwzVZEhWjp Lsa4HeBaXEZmLkxnT8P9sNvPmVbFUb/kdIFd8qXPEmMYfIZ04tUjGIL2iVLBhjgU rzjaIdadmi3VRMs1HF4lbu6BqB6XNX4F8E1mA0NJ8cRo+5La5sA8hUVIxXPv30E0 ndEOnZYx1LN5bXAv6dwZrjD1LIskWzY19ep898jM/2/8KpS7oYP+w7E6QKWq6aL+ E2pgjEAXSfQ/0HFCh89+b5m6TL2H2rmKhflHbZRgVuLi1k9CP85dIV4rpgpIw52I jSPws7QkdVZhtWS/wDdknFZkyloWwLpxoCBW87EfjAfjDGJqQmNAhriDFJhsJGih TwhwASvmCpaJksizoWxJriTwcLCbofyN6qtjmU4+TD2/PJ6UeO6IsL+Z0vdcxttn QujEKBnTD1jCU+PrTOdc99knflr8Hn88O7wD9Bem8gMWGz97U8uwmb/NuOFylvp+ 4jAWrokM+s56naBkgtFyGaRlLv1Gh/s7NhmiYALnZr6SRNSieRacLyPvu6NBkx+6 mvB4261OqZal0D66dGZf6l8OFOrghr8kXu9+45BQZK7UxPfAwxA= =sQMd -----END PGP SIGNATURE----- ================================================ FILE: sig/v1.7.1/jq-linux-mips64r6el.asc ================================================ -----BEGIN PGP SIGNATURE----- iQIzBAABCAAdFiEEkwealRHvwLfWzb+1sNpg+0VLrxgFAmiLcd8ACgkQsNpg+0VL rxi3fQ/+OFDEzY2396qJS9gK7Grxs6Ul0/wM7KZIFftzcc6cVShooMJTYWwiYlEh AwZsi4pqI/47zhQZKhjRebkw4okLmKX8tOrjyBC33tKRu/MfxxHQW73I96JvOfxF knO5OMB/XBHSH0H3g0IRHqFzv/y6P2spUZhY8/VR/Bzz5SfSID20IYYDACbSAUCA onsJcq7fqNK+ygfthB50nKj99WOWFar5SED6bn/uPgvxBD0JnF9eTC9IT7EVjNZI VtivR3nFQHuSUgFDJyWhKYFlpzRRij9KcPdsRSlRxFNZpVqOopI3lNJ2y/AHAeHh FHNQ6LVKBm5uJCyXttAgXTglTm97qKZaRkuHjRyAuiCDlGaKfZJYwMff6/e/YaXO 0rMu0k1ArXUNPOGnOnGequAltDbu4vqJcKbhF/EPVA36t65B3Piyh4P8tQMWWMg/ RFD41ZSARphbRct+BAXCQijwDt2M/jFhwjCPcD+UKYR4k0RkRfkDMQ+XCqmP/+5G b14+6OKk9yULXBrWlVPbT+rRoVas/a88P/R/l96FRc9KtSq8SbVJhuiwiSf/Q8P/ Oqqu9qY5pOWPdfndpAmaqD+wR1LCVT8AZvLA/cIX2Vr8urMJIgnf+tSq25UX6wYH ZMwiUoZAFUyZVGh4AB6R9M+wiz2HByHbX87OFZxuoPRK+etpX4M= =RPjm -----END PGP SIGNATURE----- ================================================ FILE: sig/v1.7.1/jq-linux-mipsel.asc ================================================ -----BEGIN PGP SIGNATURE----- iQIzBAABCAAdFiEEkwealRHvwLfWzb+1sNpg+0VLrxgFAmiLcd8ACgkQsNpg+0VL rxjp/hAAgwlPF0DYTZPquduWvTeUDBT5lz3uQvibB7lGQ74GlHEspyC63Sd1nXi9 pfCSwIEkUgpRbdkDhNPZbDa7cInO1VFKCZnjgWdeJAIaTRYuFcPg5Uik8lhg9Uu+ AGFrR1atjX3tePhcA3NjbZUKNOneQgibBoqJX199UxF6Q0o1O1EuZG5KVZbGb1up alQ2+iB78qLKGUmqwE4q01S0XxlSTMqtTKFjvRWNKJb90ZwQ3hdwIHpduEMgQ2nU Vjz/6w0nGRXpw4+zVKQt7wJfbUKWsoKlElmrBw5otXoAmhff0ZltGR1d+50xZ7Yg NQecoVl84BhkChEIuUrYeH4XlRle01SZvtJJvroinrGEyeNuouVITq1+zftTmRbE FLAqabLWc+ChK9uQHo7DVg6GELKZbVcT+h0MrI4PBo0upjON/P1SqRxLEm44H7ME huG1a88rCLa0b6qz8U331JuJhIch3Le2KA3HYDQycYoF+J+juPfyAsRGPdi1IASh ImO0i1rotRlZP24UG8rAIKIqfBjUMKsltg8mVJ+QYikrFn9oQzGNxwMAH8M17hXY SNSev+mRr8u7zNvfHnCWRbjOiI664gMpllLhDspTM6PDzEuafKrlLpBZF4Q/ymht Ua8olKOn1/K4E8ZcRl5ZrSJIP3E5p63reyVE21WOaBMHd/cyV3w= =yLDy -----END PGP SIGNATURE----- ================================================ FILE: sig/v1.7.1/jq-linux-mipsr6.asc ================================================ -----BEGIN PGP SIGNATURE----- iQIzBAABCAAdFiEEkwealRHvwLfWzb+1sNpg+0VLrxgFAmiLceAACgkQsNpg+0VL rxiWKg//TpJChosdrGdCiEFohHTNoHMIBvF1C25ohMTLRbBsgBPYS4dP/YaDWeT3 gjc1lMn/JYFj7lqxAukS4aA8H4lSkwltXG25oE4mZxDfwCl1cYZ4A1480Ee1Ubc1 t/6ypGc7VotiAxRCywRDd2h6Cb80RUczy1IyWXhS9OMbzBACUwYJhBKXdfWtxKGU 1SwR3oxLUMrKkKSyXwy/5+bjSX+E1ZmJFcUI5VN8kwERv/3v/1go0oqxeLDagM/z vtmcyvMdMEuzdIROtfCSr+CcBSh4Vy8bNrJiPD1needlE+5pgNL238P+zPuqRl0H EsYFrUod052zoHWwaHOUN3tknaFKzTjN+1UmRRwV8go+bJd4XxIwB/g+MsB95Ewe jbVyOWuOcMm2zWYSFSMeL3m78D3uHmHsFfnaeV3y6bjUnM5dQLQbt+N0kUiW7tzJ 1tNc964lUeGJcHMBUSNbOlZDHlxPmfWsNufFxCxAr/D1Pm8zk/DPNWeC6HGGWdB0 4rFeZFmvSAPQPdN0ChXYH50vzS4mQgP6jgrXsNo3JuHOK6bl3nUO1QllwOsgiCKl ZMBB/iuZWwcMFAJSundeuEvPyE0Q78GmlxbOB6UWMAH9Q1Q5fMTGW5YAy4WvHhoa bTeZOZ9CSzb3hgxxO+mujrSe0ucaUChPeghaLUJVly43Jc1xLh8= =yC09 -----END PGP SIGNATURE----- ================================================ FILE: sig/v1.7.1/jq-linux-mipsr6el.asc ================================================ -----BEGIN PGP SIGNATURE----- iQIzBAABCAAdFiEEkwealRHvwLfWzb+1sNpg+0VLrxgFAmiLceAACgkQsNpg+0VL rxgpxQ//R+95Bn2kKcghpgJnrsT2DXFwg6pq8+fB5ikhjfRPps79QLtPdsS62I1o f8chDHA82IBPh21VDHo2l4Y5WeGmvRvidH+IQQ+SE9zoIG51quEWUX+slYWvTcV/ lhcxQz0Z9pFSGy/+FAGUJX8BGLiyB6yKyHco/44F9vBNCL3WLRqEZsXI9E1yswcV wmERlOdQA6uNhTqdOKGfYtK9BZqODYosBWgE+FDZbqyYM58aBjTWcMBvtsuXDfAm nI5bG5umdtOjSeLclhEoQInD3971XI9sbWQRTh7gMwsZ1CKpXvR5b/+p78nhPbha Yxk6x8smJ6WBSQ6X5yc/ZH4dHuYObBtbpiIHSCoVNbwzI7rQUng9fmAcrwcLDmlH +MEJzxXQ1bB2rqPSlf5TE/cwcthWNAPggwPMjdC3++OswzQ5DjtG9au+MgesX7nu rDYxnDS61ZPn34lDqgLjmYXNhZ6LNRHNu1QxBwd6e6adBfkygOB/FOnvVxcTMgTd Gg8Y27UUe3iSizpCIiKTAkquM/gbFVVTze1vDswkFii6CkTkIztm9D3v4gWR61PH IQd+4E8yeY5OL2xggME0yg/0j4lzz++wze4XaQo1E3fNQcpYE/WaQuJmykDpsCnh hfkOmEd+Q8Ver3woit7RpXQO8uGrU1OW2dRDhQpYj/XZ2wF0sgg= =NopQ -----END PGP SIGNATURE----- ================================================ FILE: sig/v1.7.1/jq-linux-powerpc.asc ================================================ -----BEGIN PGP SIGNATURE----- iQIzBAABCAAdFiEEkwealRHvwLfWzb+1sNpg+0VLrxgFAmiLceAACgkQsNpg+0VL rxiXVw/9F2CgcLQKF74V3KEOrg0cn6YjAIszrgTRGULbTye9jiKHoieS+Yo19ucB tp3iDjttP0a6jPr7jfPBc/I6ae+sjdQ6rDflJbzY+8ezFjtpCZhyeNz3cByzCsMS aqojhS2IL1BB/ux+DpjUVecr5z1XXPJV/R+VYnKyN0CTrp8mh3MR6CjEmHGwuoJV VGFJe/oMMC+C2eS+Qn9yxuPAyotnVuhmlRsvKO5+5ec5yFnIJY2rF/s9Bss5cwyK tSB6EoRMND0uJSGtDfsHbgiJQTiHXTeFluvwyJQvFUAaThE4BPdgbfwN+XAVI+nm XAPVvg1vwgmzr2GHTJu+N8liRSVdzgHTYQj5RiAJEOjZEPjNRdHSU+Dd9PNTp4T2 lcuavOOja+4bXWz9EL7vgeFcD+giUIW7QG3CYlL+TAWrxOLa5ZVwEgDc4zW6qZPR Z+O5ppOLdusDXt0U7uNiSeLrw+UiuFtMBes80uZqvmBI4AvuUjRzERISKlrT9b2n 6/bD+IcwdigdRdnLQHXXRbnjFo35TajDptgdPMnG+l3LDIP8NYYtRWgHavYoBR0X tRcTSZF3QdKPSVzYwQ7uK1P+TFdsHqXtWKaHzUyhaOlRLmSjl3yCPVbRIwnLYIgs hSTJhsFhDo35w+/zoCm7IDgCf/ZHnRp/zgc3HpSHjWgWGPKD1ps= =FQz0 -----END PGP SIGNATURE----- ================================================ FILE: sig/v1.7.1/jq-linux-ppc64el.asc ================================================ -----BEGIN PGP SIGNATURE----- iQIzBAABCAAdFiEEkwealRHvwLfWzb+1sNpg+0VLrxgFAmiLceAACgkQsNpg+0VL rxjAaw/9HtCptIOmxpfbz29e1eqt1MW5yt2kRNZ+Pl/Xw1SILvhMtwHKCwrJKSrI yqOY7wQkfptemmReTN1xV+lNwjfc5l6GHQQpX5kzHjSFk87Cqo76ji2k7riQJ1FS RTy2i0cXkOW0IgHLIV/mdm7Yc/6Cay0xOzx2zr7C/azxNpVn2/3PXxkySWhfNUAo 6T7K6tmRmUT6Gp9Q28LZIVJcsr4sw9TXlCvfe99G4jFgLPuqP4J0p6EzuZkgZOzD 8brmWEo/fszjnD6Xdagb0UCZDW4FumcRwptS2uV9fu39BOIIzTlGJj5cQ08zsQlO 2xRvwuOQzAyv1CzGBIIh1c36T0zkL+I8ATvBS6FFjMSLBBp8bDXtDKad2qrZHASi fML1pbscqenGkHEuLUer0kwcJ3ndi3WVNgErqPTmLB2g8TMCS4pbkaHy1StTnxsn NQO9fMBgF9Df6PyaPi7xfmGlBEJiW9/CYckltsoTEaWnpChkZGPiVgKcvh6W2amf Y/evImn7NRrV/NE6NXzMnxCJABs9ozmoEgQWrqKEKQJ0nXGUakeDk0FTTFiQxVa9 5NV7s4ISJOI4qDevYnS/8jDtjEe41l3yyL50BVmwnX+63rWXwU9R+VBeWgUKXMWy pRYsZ9tNneL3GXoy4ERYZ8C8XFTE25P+qH8MyT5M4yaA0AJFZjM= =H6MW -----END PGP SIGNATURE----- ================================================ FILE: sig/v1.7.1/jq-linux-riscv64.asc ================================================ -----BEGIN PGP SIGNATURE----- iQIzBAABCAAdFiEEkwealRHvwLfWzb+1sNpg+0VLrxgFAmiLceAACgkQsNpg+0VL rxhxCw//TRcytUiUuQ4yjdCPzGP8DkXR8hFpwCVaZliH4dRd5ZF0Td1QS48cSM0E 3kbzAXd8L2KmJdzNmZCY8F0p1k6q0/HYdf9bj/qaXncS/6/JhwR0MSewIUgeUG2d nT45eUkKoDXERibK/HAxG517umnzXAeoowLqMhYjc2PaZn9rqFluSDs6CuZ2Uq7m DsZF2cjYHBXLDKxkjOEqY1uo4E28VlRAkm2N/xQ8HJnvJSZ021M0tvy2PrSTF52+ H2KC5JlpCGLTce9JD5EFmQ8KYLCkJ0fBY0M0CKvBK7aKXGPc8e6iCHP7yMtYPXJZ KyzE5jThiCo87A+GiWao3VNy2HMTBxs1RMJJ+raJF5VDSycMTkg5+QG2qaf1h0ER rxN3Rh2CTCkXQ+7GTECYGjcsmbR7XIHKk8oxmh46VEfVpsXBJSQ9eUzZeoWwdTT0 2JnudjVs5EUk3tzzNGDjoo/EVESXSoJHoZFLPFsrm0BfvWkEF2933Hl/hQGTxcg1 JZPlbbk+csraGiixdZCTWvRFNHCQjixGUEODR1Fo9j2vtnpVFjqQMNXpLTCfsejb UrIOXsYqh8+RjzSuYzhGbp6NmUKZMBRyPrBr9i747O5fqrv0lunIDiP9eXh4DKI2 HV+v/hMiUv5anCMihmTTKP99VOpAfBdmG0jFjfEd8xlUcNLDzpU= =6jT7 -----END PGP SIGNATURE----- ================================================ FILE: sig/v1.7.1/jq-linux-s390x.asc ================================================ -----BEGIN PGP SIGNATURE----- iQIzBAABCAAdFiEEkwealRHvwLfWzb+1sNpg+0VLrxgFAmiLceAACgkQsNpg+0VL rxiDcA//ecc7FbMqqVhrICDLCVu1h3/sNy6hsuOFz9n1A1IWB1/vlGXkYaxsONf5 AkDcBRHkt9Gt3PXxbLyhLo0zb0NWbIkIt62IfHX/NU4bEpk+95DugWMKiZ7Jnyo/ 2bsiUz51IxGlsMubTn+VOOjfdFrob93NupQI7Uob6FMI2M7347vA3qBwFgmt3CU/ WrCRR4o8sZCmjIKWo8oIZJ/7kw9fhoi2mvN3lxs0uodd4/V/t9dQgpx6vXQ13CF+ B4UwtfYKCMURDkpxM+6OAQsQWHdFCrpv8wnxx8M5uNmqxkfKAu9S8nYP5/jM/9gF nQ4A4viwc69HGPxh0hOLWXXdP4kLGYA88zDzBrPjyQhWOaGXJwUadmojAahXLfrI Yd7mUQ4wZKZsAYK4hT0NJAsp/Da5N4bXYoyvDPT3e5grYab66WBxGpvsaCZhxy/z k9Ur58eSmD2ClHiUdmELfiwK/jehh+3uHDg4uAUhxcybz9bSgxATwGUkbYND8HCC scRRmeyY8QtlXdtQVd0zhJB4uV8RJJx1D0LzeGqOyrn8HX+iHmbnRBVRrNlWirKE Q8LeFFCD449rDn86Ss03S5uwilDmtkyZ1w2DWV960ApULsi8UMTLGLEVlBU3IbUU OOB6RlPfv8pZZG40R4xrldjiQdwUD88hg6OkvUYHcrkII5xYdU0= =v+tG -----END PGP SIGNATURE----- ================================================ FILE: sig/v1.7.1/jq-linux64.asc ================================================ -----BEGIN PGP SIGNATURE----- iQIzBAABCAAdFiEEkwealRHvwLfWzb+1sNpg+0VLrxgFAmiLceAACgkQsNpg+0VL rxhBkxAAj9b99EVI4eIbHthB5LehqOXsmRCqcxh0ygfquG7KzqApMaYuqcuVULLq cyVh0NzmMLalzf2Wb30BRshSJgUHBFIbilw8vHshQ5Wr/wLOr7ZJNP6IvS+iKsR0 lkk6qM106ZmYxN/Y0AHUBjh449gjFjIvDD8ROWlC/2BA9Hq7d6fJQj6S6SmM0P9n OKF/GxjmBuIKSPgOP++If8WfbjqBf29I/irXOVFX/8f6KsCuPRBFNUW3GwcvgEEu WCUdnAnbBDjgKFhcXZK2fL0B1PS/9JZlKX9qNfmuiR+oCDp/MJoa7D4ilyUPZdzx LqzeMC//aWbJx99GtOUJGbE2ZYRzYc1/5s7fwE/i953F+Qg7U3xIdMpabLkHFn3V W5PNZvKnzKg5LGWZbHXjnadP51Sgi2mosMfq3noSLOd3tNoYh9sCR1hFMAUY9wwz ssqDrpd9kycDasJ6Q/eVs/ZGnByG74K1J+z8ES96d9MG0oiezUx2pqBWWrjANJZw 6fKI2rYyfztknT4/2oyDmzEYkrfX0liJSYA4mVDl6UxC/qq2aexjKEepFJf7zO0J pUxRTvamjU5dNVTy4DpBgZesgVx8SiaktyH60WnphyUL9CWlttgmwDXjxwiVqVZ+ XEUprAlN9SLMVgD78Hl8RZ8xMb0ZeiL7cb66H04IkEnf5XWZZ4U= =yRmS -----END PGP SIGNATURE----- ================================================ FILE: sig/v1.7.1/jq-macos-amd64.asc ================================================ -----BEGIN PGP SIGNATURE----- iQIzBAABCAAdFiEEkwealRHvwLfWzb+1sNpg+0VLrxgFAmiLceAACgkQsNpg+0VL rxg3xQ//Z2VE6wRM6rIHWnT9OzadzGcmJjEqCzCN7krdkvUMpO7OjTfl05rARnqw in98seJez4GydIpBOTlwm0MU7zM6lQ5AFsTLcR29XqKxJZF9cYZZqe0wPbDWxZuh /4sEP9cQ+Os85q1USbxOrnO0rcGDPfuBc28IZv8NOHj76DUg867d+ApTxzqkkicy Zd3oBN9Ohrs1TFN3VlEmBOlUKWxhGJTVZOzF4YzGrxh/toEfYTTlDNppNt2EEDbN HCvn5z5pxJtzc3338a1tAEoTxhdFn9fr7uAdZyxm+SZGTB9V+wfFUcKXicx04Bf7 Hn1zmS8yGEGeXa4pA33fR1MsSnO67T4OyMx18ZmlbkknJiV4GvaCmco6wlyj+AtH C5pHm4Fhf9p9IQXO+I6xcJa/allChEjv67/bZGl1QlRWrzD/Ut6SetqMHEOFyU2T eD1oImg+zlpFNeV1pEWBALqLhDLFkd0XXjSy77RxcBsN+w2VwHEb0PHbWPZ1+Etm 8i/7NPuty5eAUG4vH+hskqEFLFi0L11j6L9eLcAutjNCbR2BAOACxHkfT15bVwj4 rUFCH0Xy/jL5qr/8ondT52MthOQjUF/bw6nB9Pd2JJWa4oDihbYKC/6fzvFhLtOC tDuM4E1YBQnfQA+vPP+qEItOa5sFO/Fx2NiNAYXp54li5BSSkkw= =jB0s -----END PGP SIGNATURE----- ================================================ FILE: sig/v1.7.1/jq-macos-arm64.asc ================================================ -----BEGIN PGP SIGNATURE----- iQIzBAABCAAdFiEEkwealRHvwLfWzb+1sNpg+0VLrxgFAmiLceAACgkQsNpg+0VL rxgxvg//X+TyO3SdT94jlBn0JHBmztCtiKur1nm1XlbvA4cibfwN0hK03SPzL4d6 f6lX49JP76CtN4sGPYhOCim1CUTYRQHsCzTM/5oA9RSC5ssgg4rcoO4GK0PmaDt+ PEgiP9Qzi1aTubjcgmfkuK1+oiERYtRTDdt4LnuBBFL/mLsU6zrR9WcDTQSDo1CQ gqyn+Pvpr00UeVGS0l2JHyE+4ZgNOODqlz9tE/7Ab4iHKYF9ahPuCUoMySRA4WOk cYphD2CWWd+mJ2Oi3ryvnRo7mlJLzxusWmrkFv4ei+skttrQXFcxCOJxvqruBN2d IrR71/Ydy+ozIGwWsLAFQ/yS4KcrPJiHcmfybwx6XgXp/qyNeel+B1Sb8aO1uSjj Q0j2MBltS4DOLvAEvhFVrHzKf5zmAJETwpK4vcYqYALnLMW9O0kfV/PDpN1r0eJP cyFtu+kjuLsg1M8Hpz5y/uVoXnNBSFtCBEkoE9Dh58r7vyVp3/2BHbXvAxWQuE17 F+TwEFHX5AbRRNQEmG0uhuAaSDU6wcInepgR1Nn4F5+wtT4s+iSMe5MKK8OEV26Q q88sbJ8AJI97C1dEzD7bPYoqBxwOklhNISBI6K5rnC1Y4YnBHVNY1M9bgT02TzHz q5wrEHlo0dAzUSoCZCJvWWKjKD30yGXqybBL8mogU/dAhcJbZPQ= =3Kro -----END PGP SIGNATURE----- ================================================ FILE: sig/v1.7.1/jq-osx-amd64.asc ================================================ -----BEGIN PGP SIGNATURE----- iQIzBAABCAAdFiEEkwealRHvwLfWzb+1sNpg+0VLrxgFAmiLceEACgkQsNpg+0VL rxjqlxAAsKcs/5wnGUfL3DBueHA7giwZXd7Od5sXGPSahQpezsYF8S46t5OEN3y4 fyj1JvXfdMFSBi8Pcw+LQ5iXv+AtmRksF0UmewibVrq4ETVVF926n/tcm9eouVOF I3VKZVKm+UULhRy8XVjkMMCbqb/AZW8HZGuOnpWg4UlQgPX3FpiAYBZJdT8TLv4O UHqp8hMCp/qwCRSshTcKBqCEbdITm5OI35hqfotpoA9F0SUVTBIbu+xgvksrW5X/ 6Yy+OVvS01RFgF1F6KeJmxrfxo4K4/eNSuCbYJTHfTNB3vK5RBwki9ufqY7GOhqe RcHC9q1PSK/FUlp52MhwIwLGp+fdKcJjOpXcgZec1kHlPGENcAi8zE5WrCGaEtQa XK9DtNedbu873UuJJKA3uoeWFQLsG0GKIK+ESgG5lZWQvP57XyG2rQx2opTLVasd EA1ctJFi5IIeP8vpyF4/WI6tgy3sgULucxFlpsdxNHEm80tpa61p0A3YVRuVxAre 4GetVrb21dkgg0kfEmhHKrntaRDMI7DYwHr9YNCfxUPapgkcaYfzLM+VouFbYUiK JDnPwRYV0ti5V30nfnbQzCcVCk2za5XFhbH4kXMwbYB9XCT21hk/xlCCPG4FxFQN Gm1iNL8USJjQXtdTDq8W1aO1kah8FJO6lfZsEcJEuUpvQbbhXe0= =rNMh -----END PGP SIGNATURE----- ================================================ FILE: sig/v1.7.1/jq-win64.exe.asc ================================================ -----BEGIN PGP SIGNATURE----- iQIzBAABCAAdFiEEkwealRHvwLfWzb+1sNpg+0VLrxgFAmiLceEACgkQsNpg+0VL rxiYtw/9FETxa8Nx91lb6WKS5GknbWaaiaCIXpN4GqZORUnrMnoPqF35PyqEYPZX XXn+jvZ5fvsvyWsyWrE7+AMLZ+bS/0WQnryVg7pxfo/4RBW4eqcagBQgaORbShKd JO3F4I9nuR17QPKk86KtjvJlntxnJK0wxJvIWiFZge8gvymaLL0ot1tyak3HhD4K BPeRRl31Jgnuw/pIjgUuNPYU6DaEzPw613e8Se1SrpgA6fA4CYzO4nRl1ah0Mxws wRSVDakGKz/yRtVj9uGFSpGWfgezkU8py+5fr8PcmcLt2tVj6rFzW7siCBCMHQDu UnSuVaXtfXxc0YZV2Ih8iMP/Ehy9RDQ8CPwvo9GHPz0FZuy8lc25DB+IeRYK+qhZ z0upYYeRJyp8d4t66ReiF3JxADF1uEfN34ZSHznS6BpVHDtaAi0kDjy3c2VEDTLV Qa3zx248cT+qHMVOa+6i7AhWAWuAsSzM5xwiuOmb2RDBzoYy3maqBME5VL3u/qWt QyPHkJKpXg6OifbsyerOTPSvWUIH08lv7UKjHQJYRrlpHjwyCq8W8VlR9ceX6ee4 4IRlbZwZpv3f8T5RzCIhx28t3K5i2rPcsblFit0t8xIa+F/ZiW/0uQXyebcyFllq Gq/KMxdGAbPh4P06Dh979MMhmgr5e+FjY2W4bkeAG6N0stZ/bdg= =/bLq -----END PGP SIGNATURE----- ================================================ FILE: sig/v1.7.1/jq-windows-amd64.exe.asc ================================================ -----BEGIN PGP SIGNATURE----- iQIzBAABCAAdFiEEkwealRHvwLfWzb+1sNpg+0VLrxgFAmiLceEACgkQsNpg+0VL rxiYtw/9FETxa8Nx91lb6WKS5GknbWaaiaCIXpN4GqZORUnrMnoPqF35PyqEYPZX XXn+jvZ5fvsvyWsyWrE7+AMLZ+bS/0WQnryVg7pxfo/4RBW4eqcagBQgaORbShKd JO3F4I9nuR17QPKk86KtjvJlntxnJK0wxJvIWiFZge8gvymaLL0ot1tyak3HhD4K BPeRRl31Jgnuw/pIjgUuNPYU6DaEzPw613e8Se1SrpgA6fA4CYzO4nRl1ah0Mxws wRSVDakGKz/yRtVj9uGFSpGWfgezkU8py+5fr8PcmcLt2tVj6rFzW7siCBCMHQDu UnSuVaXtfXxc0YZV2Ih8iMP/Ehy9RDQ8CPwvo9GHPz0FZuy8lc25DB+IeRYK+qhZ z0upYYeRJyp8d4t66ReiF3JxADF1uEfN34ZSHznS6BpVHDtaAi0kDjy3c2VEDTLV Qa3zx248cT+qHMVOa+6i7AhWAWuAsSzM5xwiuOmb2RDBzoYy3maqBME5VL3u/qWt QyPHkJKpXg6OifbsyerOTPSvWUIH08lv7UKjHQJYRrlpHjwyCq8W8VlR9ceX6ee4 4IRlbZwZpv3f8T5RzCIhx28t3K5i2rPcsblFit0t8xIa+F/ZiW/0uQXyebcyFllq Gq/KMxdGAbPh4P06Dh979MMhmgr5e+FjY2W4bkeAG6N0stZ/bdg= =/bLq -----END PGP SIGNATURE----- ================================================ FILE: sig/v1.7.1/jq-windows-i386.exe.asc ================================================ -----BEGIN PGP SIGNATURE----- iQIzBAABCAAdFiEEkwealRHvwLfWzb+1sNpg+0VLrxgFAmiLceEACgkQsNpg+0VL rxi3Aw/+KIV4xZdceYNHNsSQw0Dmca4ftP2rPy3tzxHb/RdAtcG83p2bjrj76fNp fdZdQ8LclGQYwAQ4w4ZevZaXOdlAj1a0CwuRxMDlTWJ8rsiUqa47bBeAd6R6HyHi PkSZXgcwhrsF3cUsXe/sb9Iw5/LSRYz0gcyRrWLKGZV49ip4XQaHV7zDnQ+YpgQo ppM5CJ+A9qsFhzfmEpW2R8qD372NjzCoUfExJlgWZGM0IAxNWX04sr/spnp7dLnE HBYl7rVGT1LMwIqi5YbzD/1O8DzFd61nJBMKjoJp4kRmer1gxzexXlWWM2e0AXT5 rGxjSCHU5CrHQ98RsnRvvJcwNC2bV4YyV9VJm1rVlDGzyKkbRgRn/WtN3Yd1BKKo AZ8O9jzWbb0b9NKh8SM3x/+BZwqZ5/WvokG/N+jLwYSyflHgbJkGbvwWBnq/8Fl2 oBJVEH9HznOanyc7fasJp29lGxzCrgaoNKjdCWYkmqvbXZddq0pZUk09gQu/QsHt NykYjkXII6+z1vzFUVugZH9ce5eZmVdZRm1X7VNNTlfbdAFwdV8+5m/nfB9XYdT/ LTVPk72Hfu66OHcgpht1mYBnQfOzKgEQ1ppwa0LQSDpOUF4zTXsbzm1xe+F8bkhh lMpfW/YI9Trtjumyfl23fg7Smcc2RfIZLr7yPCJAQ82X0HcT5Co= =Y/mq -----END PGP SIGNATURE----- ================================================ FILE: sig/v1.7.1/sha256sum.txt ================================================ 478c9ca129fd2e3443fe27314b455e211e0d8c60bc8ff7df703873deeee580c2 jq-1.7.1.tar.gz c9fab0ed0ce278dabc0606462ab9c4c3385bc801e958993dc0ed3ebedc15cddb jq-1.7.1.zip 5942c9b0934e510ee61eb3e30273f1b3fe2590df93933a93d7c58b81d19c8ff5 jq-linux-amd64 4dd2d8a0661df0b22f1bb9a1f9830f06b6f3b8f7d91211a1ef5d7c4f06a8b4a5 jq-linux-arm64 d6b86023e0848c93a618a74b6fd741ce62f5d557fd3c2c1d7870663713b2c174 jq-linux-armel 46d18f115cca638efed22b90342d52a84a25ab1bef570551d3a16f7eb065c298 jq-linux-armhf bc473fd4b385789e9ce3d02a4c8df74dc988a34b20fe4e1a80da997eb360b599 jq-linux-i386 5b7c362a354dda4f91bbfd26f7ed92c7cf7ceac28c022b1579c7c228149b55d2 jq-linux-mips 3d4b43d0ab571431fdfc786f951a0547a05f75aed5c076409ed2cb58b7244de1 jq-linux-mips64 604f5a87da0e17a1e8c12422eeacb47e93e3eca60c8fe17a35fbc629d425bdca jq-linux-mips64el 21de7590f4bfa078514a6d3186bd68746fe331eca4807d6ca0299fbba2d2212e jq-linux-mips64r6 30ce843d9910925f6ff3417ff13db469b5a73a2d727700cb4c3c12de8665c1be jq-linux-mips64r6el 5174f769b2a8a111743e316778aeb88ae4f8cada0caacb5c93ce6baf9287dcc5 jq-linux-mipsel f6d4a65deb9002cb59c00e80af6314846d2229ecafee53449228197f7b8d28ea jq-linux-mipsr6 e88b5bda2d0df0257033477fe53eb8544fb44c8275c814d4279ab7dab84b2e51 jq-linux-mipsr6el 761a9b3ad168e4ed0413c795f5546725be3ef1e1a11951f755524dc3f4a6442d jq-linux-powerpc 758841de8a905dd82cb036c9ff6fd6e598549c6f6106fe61795797ac87551af5 jq-linux-ppc64el 04426a00def567398f6190e830b35e026fbda2ea75157fac98e41b622832ff2b jq-linux-riscv64 868b7c3ca74224a02ddb613261ddfc2e43b12daaedd5eb58373dbdc7f2c5f924 jq-linux-s390x 5942c9b0934e510ee61eb3e30273f1b3fe2590df93933a93d7c58b81d19c8ff5 jq-linux64 4155822bbf5ea90f5c79cf254665975eb4274d426d0709770c21774de5407443 jq-macos-amd64 0bbe619e663e0de2c550be2fe0d240d076799d6f8a652b70fa04aea8a8362e8a jq-macos-arm64 4155822bbf5ea90f5c79cf254665975eb4274d426d0709770c21774de5407443 jq-osx-amd64 7451fbbf37feffb9bf262bd97c54f0da558c63f0748e64152dd87b0a07b6d6ab jq-win64.exe 7451fbbf37feffb9bf262bd97c54f0da558c63f0748e64152dd87b0a07b6d6ab jq-windows-amd64.exe e4efdd6a2c463ae714ed98fd5e874fe834a3a2380e17885bd4cda1c49e5166df jq-windows-i386.exe ================================================ FILE: sig/v1.7rc1/jq-1.7rc1.tar.gz.asc ================================================ -----BEGIN PGP SIGNATURE----- iQIzBAABCAAdFiEEkwealRHvwLfWzb+1sNpg+0VLrxgFAmiLcmYACgkQsNpg+0VL rxgqOg/+Pj4c5lo05Ei10+d/fjFevoo0VUhSK/yBqFya98nRO1JCnvNk9SktJppa 2vWUjQVTmWSJkuBhjukJgb0Uj/njzQRaQpWDa3JlRLb88FZrn75MGDt4gGD6QM6B pzm/Oq8tdWYZP4EmKAs5CGaegcYBqe3kgK6IckzVdlM6LjVdC7TLry2Qy7y7iUWb ElWI5iRinb5NOBxC3J8S0mX0joyTemCbvO3uY0VavTA4slnVia3nHeNG1II0nrjs Hfyc362PtzYz0q9uZZ7vWsGL2GbKEntGYHejJsOSQB+un9FUIuHPubradNN9eIYQ 2hOUNfdzF3yR2pAO8q29JQ9LfViajQ6ovIoYA3quEC5R1cjNJCWbMJScJiqY3+V/ lq49XNWghZ6Gxd5DzMPiQJhIpLQA/pARtW/cqyIGnXkNT3ArUYZVlqMxd0eeWPJ3 W0T0wpxUe0u07VWCnpZTcPFSdNRjVNp6un1Qj+mhWZ+BcD6+fVGCDvjaF3RbI/qT ojcv0yCsR4D/jmqeWVwV9f1WtNSI4pjDC008KNU3o3Q5Lb7908g+cDGxyP1C875m 1o3yVWJh/e6b1LZn0Jag8L5DP66cJHDA9BNACZH/hnDUkkvlBiZYRwoyN8EqZd9d fxmW9EYGpAUB5FBZEJg1fauR2sUol1OkrjFH4rwxBgKO1Yb0UC8= =lfBY -----END PGP SIGNATURE----- ================================================ FILE: sig/v1.7rc1/jq-1.7rc1.zip.asc ================================================ -----BEGIN PGP SIGNATURE----- iQIzBAABCAAdFiEEkwealRHvwLfWzb+1sNpg+0VLrxgFAmiLcmYACgkQsNpg+0VL rxjMuQ//Sn0UEuZkY1HYXZocEk3AWOAlTvtIwJYNxs4UW7HlOy4hS2pG2vi5w5om Tp29frL3twqAjdCWECGdgDDjTiFb6NInsSD61cQ6ycLD8N7HRbUm5MCKro1opZkj aByTfVFNzX357aajny2mm2QirELSGprQH8Jo5piq6FtNtBq9L/gf3uB3rlyaC+Si magcFR4efphY11mNRZ3fHda0vZp04SPk9UR5YOo6UhliLWH75k1DIeIa5ZcF9Q5C l4ELb4RYlo7QsJegPDK7ws9pXC8bEbqJYq06RVpnmxZWzjItBsKdejT5AUpz7c3+ O0ZFdadg0orsjrHlUqHMmZzncuieSfZSoNO8lebWvC9iZ2+OnpFMFlfzuhQwCJFr HIO/EIs3DosMm/R+RnxpBcb/XAhnc9J8Bn/09MMwOHvTGVLfNYDX5DHxVPRd+1HQ cejKRtZiNNG90vwLoL9q6923U52DcmN5JpPSwhv8VecRyZO8rkoxIDFv9rHrgfVv u9V7cf+KrLzjeSslrEFn0I7hOW1urqvSlUiItrJHxcUtI97hEk25Qzuaoc8EVMoK Cqoq8hRXvJCkCQ8za47a7OKZuUzGP2q6G5Ihh0ofoPyga1xCmYFnjQSVGyy16ovz RNnE+LlOSPl4m+zATDVCYh44LAriLhdjof6cMLQUoa//sD9HlLo= =hvEl -----END PGP SIGNATURE----- ================================================ FILE: sig/v1.7rc1/jq-linux-amd64.asc ================================================ -----BEGIN PGP SIGNATURE----- iQIzBAABCAAdFiEEkwealRHvwLfWzb+1sNpg+0VLrxgFAmiLcmcACgkQsNpg+0VL rxhUHxAAi49m2xrVlN//CHhhxZGFwpV7vnqBeCB25kfNVctSOUGwkx3My+hjBCME QxEaMeZCk2PB+ECKylOuv5LYCbQerBUfDoucItJ4oWrjSI3d9qT5iSpMaNvIzfsT opT4ZuV9SRqS4kf16FpdsFlhMRlahcx65TftLJei7/c49xjxA54QvCqPYreI5lVv jerdM0ChRvQxZ7G5v07CKDkUimodEGUaURxn48FQLduoypNdxvd9sRuErG3XjG93 U2k5naBKHnvmafjZPX15KzR/ZVGoP8zYbBoIpcLyWIhiH0/I9JzbhKrPvArabEZa 6TsOrAQp8B/YO/kWjGDbUnKsaBOGTJ06zbmzNilu7nU/8u7qeWOSVsPXLIHOmnKt sv6DLFtDFLe7h6H93L9uz/6MucXF4Sfb1u+lcmhYRY8hotwXShadMCFcSe0OR896 ayvXCvfgkgyQgWZLA9VvRKtUdnPnK+8ML2pNPxRGq0GyxyokBYggzeP+5CDa7dwr /4gYzvQqt3BoWbqyLiVEOKUTXW4Wq36YwV7eJKHr03n0uioklYu5kwyeBXhpI4VC DMTOFYMM9jq1B7bIDNoJFYgbhrLtZgAAW4qYO595oaG9kTmIdyto//drozLsHIHA Cbans3RmBdoTuk5qF4Zlp7eY8ogklw4gxpsiZjLq2++JUKL1ZoI= =3M3X -----END PGP SIGNATURE----- ================================================ FILE: sig/v1.7rc1/jq-linux-arm64.asc ================================================ -----BEGIN PGP SIGNATURE----- iQIzBAABCAAdFiEEkwealRHvwLfWzb+1sNpg+0VLrxgFAmiLcmcACgkQsNpg+0VL rxgLhxAAg1d0RMrOEi6rdT7Ajh4SvP4Qm0x+zvEwxsVszSPxOiKal6uKDHMcn69x 599mqYJsXK8zbiHYtxoI3AmrQY85/DKEwhm3h3N5sa1IBzGmASzd3h1ewE650M4Y 4Ha5WWJWlXzA5e3LvocSl6n3ejTCcaN4pQkCwL8cd00YArRptNr6CNr4HVU3M8z6 ZyBsVsR+WzFrY8R0h6pQ5W0Oh5LGWsVKGG5SvFqlQDEgzOfo6nDIA0ZIwg52wV2A RwF49y7Wi7X3gJ9NZ5jvpVpcBQxmorpCgLo8CLj5sCTRCiuTj3S0DS5RHfSCd/py uCFRI4ss1M7z2yjEYuB5MtUIhFAImU+SEx+SZQHoL7XGHmoF1PUvw42m8L6t48bV SzZoaOKsJy7hmTRZNd7cAlx3XITFoPw4h4qXeHDWUgGs3kefgQibBG0d6+TcfoaV yKqCy68rE/v/P1CxK9dkVjawOOwAY/rhn+DH3ayeNsMgi4QrzBNVLp1FA41ZJFcw z7l5KFv1ompqac3EnVbxaJxJ0qaqnU+cdLkwnFV18e9oLTjeRbZqVSqAB4IX4IKh WbjiVrSIpTxGKozZwDYE6+NtJ+3Z6RCtDZE6sYGGkHuFbD5ZQNhlgf1hDg6outRB B8WWGInBIctIFoU1hGy8gmkAx7u+ljdFd/Gg5MWdbhHluQTM5Ko= =LrX8 -----END PGP SIGNATURE----- ================================================ FILE: sig/v1.7rc1/jq-linux-armel.asc ================================================ -----BEGIN PGP SIGNATURE----- iQIzBAABCAAdFiEEkwealRHvwLfWzb+1sNpg+0VLrxgFAmiLcmcACgkQsNpg+0VL rxhn5BAAgwJtpctwGgMXltgMZE9vRGDGH7A0VZJJ4mkRD0U30C/DGaVM+lqhTOKo otsZocC7b9gMbVTcQku2/8N19uRxmO0N2OXusof860UzKV2cTZMOIsAM0E5Ug9HY d7MgPsh3Hni/GSomYjszTczGlkFFxLuIfFkUgt23+vgLIxont7O9xSwlR/7HYleq 2rBg25Sl6nZyXztlEal23A0q+Xue8BkMhcxxj3DPXvMCrCwuxIG/OcSO+eIu0uv6 vcW24mYf/ntRjGth1om1v+dwGKcCBAWFD8H7z4CRh8G31rUGNSgNaEp/fhWo2+wV q3vtz26W9xBXnSoAoWgNt7oiqwywW65lkcgce7cNuxS8cyvG+dwx40waDQQXj6oA YBQ/C8oBd7xiuRuybWE29khQdrc+VTTfti3x7E21fHg7XG/zNVzjoTEUCuyJ4Nju MkKajscE0u3bLdCGt9auF87hY0LHfkGv5RFGBJxDk9nGS7nNK0iOQeEz4ur7Cc0L 7xMILqmUI2dpO5SJETA0Hm941j9rzZZZxGx7frXHzbN0q01tYqGsD16EajkE1i7c B9HLz1QRw97wB8H7zlX0ve2YnDR3j5wtEJSQd7vozE9f8Qy8MNQ9ij148ricXmnU +Su1FTCpcvotcKHLOdJqULVMJIb3MPv3oCesIy8uFJb4QXYMU8o= =eRCA -----END PGP SIGNATURE----- ================================================ FILE: sig/v1.7rc1/jq-linux-armhf.asc ================================================ -----BEGIN PGP SIGNATURE----- iQIzBAABCAAdFiEEkwealRHvwLfWzb+1sNpg+0VLrxgFAmiLcmcACgkQsNpg+0VL rxgZexAAvccUklYZ9yShEkTAYdq4mLcbjQZcSM6wREPQa9hfnpkbnN1YcfvbAxM9 ag92xVsztuvX7cYm2PHX5nJ/LGC8S5jBs58bPExsd9tP9UjZwK2B022YrFGjycEa OXurdv563dwiJqaplvNUWHvMN3LuVnhGi65omQ3+ZJFmdIxp2h77L2DhEmuW7h73 xRgOVsduFJzxKJWjAE8EploMds04sL7OeMYYuYo4KDo6malieKM8myk9KPL7Msm3 /j1acYeEzpHl6Bk+yE75mk5+adFNwm39Erhkm8eZstSb99g3+3T08gQG9scuKNPX O+p6rvC+sN1AMxNTgTVPaoFIRXQ1AfP5/tlwNwvPXhSBuEKPT18XazP92+gslMDK hCVJvf9UeElZOtrZ5kefhMKJO/uQ0u4DsqHAzNectk9yRzpH5KMNUQDTYYlLtaKr ykyuqNSJ/ysXP1RAZeessD9DpFzpyt7qCwbNzdR3fQDYcylHzb0R9LYUlXy9kAKp 19MBAETrPfDDTh03QeffkFXGkPVIaJSZSfg0OVsizjQwAelxmjaEjdZZeDb1q/TO oR1dc+b7qyP2RFW9S/jrG30lHUpQifivHk3eihMUsd7lJrBC2ltD+1pj3V82B5y9 KclaYxjH5eByAEaRUOB+KhtU/hDQUnrbKNNuSrLvT6nIQ4tuaDA= =CChS -----END PGP SIGNATURE----- ================================================ FILE: sig/v1.7rc1/jq-linux-i386.asc ================================================ -----BEGIN PGP SIGNATURE----- iQIzBAABCAAdFiEEkwealRHvwLfWzb+1sNpg+0VLrxgFAmiLcmcACgkQsNpg+0VL rxhwqw/8Da2dK18NsmwECjZ5MUP4ZNhp2AJMai1OymyrWI7kKpYGVOFlMTzX8hxq m7MzFv0U3Zlr/NRZx0OZU0t5gI971E1lNOzXQQWNK22cpZQPOkbfRS8hN+bPhc1p +OiMSCugfQCy5l70mRWXIIxBomdEhH+36oQ35rC5by3TwwBfG4Cu85lXd0dzjezw vDUaQpUsx584XMERRTR/FJZVzxwfdm2/o3+upYdcxTBTdAsQPYzMQatVf6gj563B gUhG2epJKYs5lVqCvnruMZgapgiWwDpFmZcY0zDjWPx+Jpyvdx/oFA+nkR4u/s// aVSZEjtQLUOSbHTYze0ITViBiiKjt2NojYXbyg5kMd++h6elWGa6BRDryH6sNugu d78pIKi1BPKM3+eMSGLtO0dwhvevz53QXNigGi5+RuhGosPRjHHhK77XtHjJldoB 29xWnMUZBCSkeuK1GZXW+ISqzusYX3bXrHhDdjR6UKhCkAiXW8bTLzckIuERtYuZ 4J2plut/YfT2mmNrerpoXt5JLDk4uYKOuegt3Mqyke5pEjw5gZjCOzUq/4ekjWCp UX6/LL8DVU0qTttr4TkvJsC0rGwtolxv1tADZP9LLU96CNgSsmc0R4ZKS7t8Emdd 0fapXq9A0z+3TIhHr7UulzkrwQtSNtuBrPc7tlSdbv5GRST0HWk= =kyea -----END PGP SIGNATURE----- ================================================ FILE: sig/v1.7rc1/jq-linux-mips.asc ================================================ -----BEGIN PGP SIGNATURE----- iQIzBAABCAAdFiEEkwealRHvwLfWzb+1sNpg+0VLrxgFAmiLcmcACgkQsNpg+0VL rxhFqRAAzyNAw+SMQ5qOTrGkrrgAy86U4PcI43/W0cYlE+51XrZh4a6yqYWH2Mje nF9s8KwIFvwo2uj+G2OFiG9cChCsd0UBS0/Fm+u1+ZbPPQ69fCRLxqBSCStO5XZ6 c0NhR1E/5xBkQJX9VP68hMJMq3ob1cpUpNCMT4RA8ARVvPNYS34HvMCj3GtZdyb3 lrAStaaZUy7dYlFeLGKk2t4pmG7r2NZji0muGN9y/caXIoRvrxD+Lz1Slnojbfux HcSV4OT8GKmf6w6D9Y9pxQo15azjiLVdKgOT+HEojtx39YV7RAgiKW0A1gObUMPn iObuI6KlJ9z99Hx14HAfeTnpuFFpxUnq7S8Jb+0sbJxRb+Gp7MHXV+rs5wSBB/Vx Yvn9zkBkMDN87Q+l3DhpSPPL+lXgvVbB09UAahSG9QE5DDu/pHE5oQrzX4Orlh/4 ue7vNxL3SDUsUNTNPn9eS73YxNSPbZBh5yWAnoTVk9M5IlVYOuF4vwRQ0y12f3pZ 9dLz0n6kSYArf2XLH7qYe5cmCeSOGgiNlp8P9mJ0r7qO1M+pKm4qtpGwuw4EWQEd 6s5lL1Z3pLBd8BNcG7d+sgOSuNGMh0UIOzXne4yqsbtdHbafaVPJn3tsIDsPRUiz Ayvnyo6YJDlkutALYDyqdaIfO/ZkHpal8nWyCFFTgNjzVq0cnMU= =QMxG -----END PGP SIGNATURE----- ================================================ FILE: sig/v1.7rc1/jq-linux-mips64.asc ================================================ -----BEGIN PGP SIGNATURE----- iQIzBAABCAAdFiEEkwealRHvwLfWzb+1sNpg+0VLrxgFAmiLcmcACgkQsNpg+0VL rxiF0BAAgdGoAA76AdTueDltQzYy8XQhHoKnw29VLPjEkiJH+p5001ifjjuwRVR2 SQIjmkORmRUJaJurNquUcVp7teJxWp64t7m3jMKFOkQKTH2eMm6MYNRfeko99Vaq fE6TZ+Ix1NC9g22A6EarozsSPb3luhWNa4OIlEUPM2T0o7hLH145mWV17+gdI4m0 jYGE3ZbD5uL4k3SWe9GLT5PJFxMCLL2TnMmtz0zvUCP8MZm1C+RcF32MMXoxjgXD 4dWyF2b8mTraR3XbmBvOty2vKxFqlQ6W9W5RmayI+REeAzQY/711OGlYY5gav9R3 0dDV+VQcd5pq2iorXKoJwg8BQHlqjO5Qvb8ShKbF7BvsOHjCSFfTvzD1skXBphvD f64jfKT0JQVzCP7XYG1aMB+6xkDHZRUBdmR+20D91ssdd5wQbrfDggv8xO1Lk1Tb PSPDNY+V53ZLdF3fdSa6/0Srtx3yHVvEIl9amYjW0RQoihNAUz+xoUChc09a7VuQ /44yNp6TWtH9LTKw+g1vmJ8VVXFbQMLmBkYPrCxDj4YsF59RBuAUmMFD9NoED8Y3 +Nwq3IpNgvtLdymSXKtDNjpoo1O/b0/H8E8vFswpCtHHk69i2Sg6DMb/Fy5U2LTL 5Pv0cnKmFAP0RnIv6fwQuysRl5TcF2hujIQktKVkGaUGlphJx7I= =h2BF -----END PGP SIGNATURE----- ================================================ FILE: sig/v1.7rc1/jq-linux-mips64el.asc ================================================ -----BEGIN PGP SIGNATURE----- iQIzBAABCAAdFiEEkwealRHvwLfWzb+1sNpg+0VLrxgFAmiLcmcACgkQsNpg+0VL rxhhWA/5AYDVBWeLyXTLuX0ovruV+4bLFjlcoi0T92s14WyUOPm/0snpF+lvR2DX zN6FawFr2v+cqOKCStlnfLNx3/m1/tL5uGRKIY7kZR5tmvdDKSJhkaHGYGL3adU7 ihuIvN9xzhHaKh9kg8NaXyDNCD/Ir9KZb9efMGhweQJk/xV3JnYeaVRR6YNsBIzG mb2pb50NK2NQcgbFEcuEyDLhjek/wIN5gFY8+fykDJVdSPZNZZ6eg2EpKgvf4EEI DvZ36AHujEMyv4JcYsnHCCQySLi20sfn3nlcq5WcNjyPEXGmkMbj6I8AsD55cSRF 8IAiJ+9XJMa8Coh+bKIe70YxdZEkhlDeECNTW7rqtVS7mk2jv9/nzlSUHcs1RAUA 72qKohp6+MqJrI4MLHNa+HkfDIfro2Yf1MPa0xm66VKlZrXPbeexAFdHVt5gBiq2 /TZ4qOCptbm5M8xBE+pkGihoISXteMcpMoA+PXrdEl3fc4DiqrhL+1Ku6BGl0569 3UJWwqpOCO8N8IXTt3pZGETrzT4zh8L5NZdeyJp+thns3YSmG0n2FScgObVadhQJ R+wRlQZ+73qDflbx69R1j+epZttG6hXqR83+I0JIBHm8NTU7gKARcjUJbQ1+dVD8 wmF/x9RmtnpUZ5KlysgCLY8RBT0E7irFvwmLMWEmjGr8mUx1IGc= =I53H -----END PGP SIGNATURE----- ================================================ FILE: sig/v1.7rc1/jq-linux-mips64r6.asc ================================================ -----BEGIN PGP SIGNATURE----- iQIzBAABCAAdFiEEkwealRHvwLfWzb+1sNpg+0VLrxgFAmiLcmgACgkQsNpg+0VL rxg6LQ//V4+w0x9VGTJmLT0DtZfndudMXuNkjw4v1i8AqwsUYhB1GmkQsuuZYLyv hO7HH/EzX2b3CIp9kNoHnpyD2g9zMk3Nf6NiSATEPr4xUU/vdbjgtUuU8Biv357E vxI6DoQ262glxH8zA0JX8QeZB8+VFKfshoZDJPE4MW3+u2mZsOemxErA6X1LB9/T R/eOgmLXBQG3n3H/YHILbhYdNKOd8VYZkMK6TdeXrVl7KRomdp1wXcL+oyDXNSWd gPZvqudR2YnWIIjEGxq6Qa9hlzaNh+b1IYFPrSAEptQNxh7gTydMMIchNtV8wdIX xcIkoY1g6Oc1iwHQODsgp8tEn3m7rMGfCKjL+datuVwKiOoIZCQpCjfPTIK9btID ub0Fiu2bKZHXUhyG03J01rL09csEl/UySdesBkPf4N9HmmuyQPNeAZGZUW5WftM7 cQm6eFiG49wA/u51fzPYxJXlvxxPxqxIjJMbnGlUijdFKz3KZsl6zhtcPDA7VgbD A8QJFaUpcKg6oCaCv5iKof8+KPluJWi2ldwVzxva0THslXD/VTvLEQ4WBcFwE2xE ZM4Hd5P6+oELihewahRFniVYThv3RXAzM3ezxmNjc0BgyXTYUEtsXeCAFUkpgF2r /oT92jW/oBzDSPUKL/2A1Fg4VfoWhi+qdkICC0jV6b2tIQ6kT2M= =yqFT -----END PGP SIGNATURE----- ================================================ FILE: sig/v1.7rc1/jq-linux-mips64r6el.asc ================================================ -----BEGIN PGP SIGNATURE----- iQIzBAABCAAdFiEEkwealRHvwLfWzb+1sNpg+0VLrxgFAmiLcmgACgkQsNpg+0VL rxh0Tw//cYM3SASF5CQyPZSgSuIQSnc4iks4iqUa3urgB2mLcyZ2KFjSed8Kf69x jgMYR6PXTDPRhaOB+PVnN8bv1THZQ2E3gUt5b7na6DwnAnD0mD4IFbp0k2KzGqUI 9Q6fGjqjUTfFjWttfKfkdNaYtcOEXRpsf2gfdPC5jNC86pdss2E89xzuy2o5pduf vrERu4kGAGQGutME443hcl9YN/1ZhsTh/ib7wd/ib31UvSHp2j49wPgoz0JYgm7O rQCV6SVEBl45rAfMtX9h2qZJJXiIQmlZr96oeJ7S0H1wwCOLTAflMsOMWZv4eOgz iejpU5mTvvI4ZUOfMk+Wt+3zjtH0RuYtIodUnN/nLOR/uLWpD7eaVpHIfXGtCYCq J80hOofFuxN+dCQaKi6kdr3Cc7V4qyfcNk1dxcBq14H7k0FE7E68uuHCBNWg2UI7 mQlpgM2+27jscGeszdohD4o6C/VKLJZBQs6Yd8w30FYLFyqtgM4cTEoabXFQeKaP 18CjXaoO7ELXdTP3D5FTKbDSxvj0P4Zn6ZJP0cqCLhqMsiuton+XWpL3dLh+Xef3 ajzDBZ9oYI/xTSi88Z1oC8M+8XxqvkASUGI3Y5dGLVZVnBOHAWtT7gmq2Nw8Vdf9 DShVQ7bzcT1HtFkFFItSwbK52ERt/wnHs0epOgcMRSs/MDdnzZU= =+/3t -----END PGP SIGNATURE----- ================================================ FILE: sig/v1.7rc1/jq-linux-mipsel.asc ================================================ -----BEGIN PGP SIGNATURE----- iQIzBAABCAAdFiEEkwealRHvwLfWzb+1sNpg+0VLrxgFAmiLcmgACgkQsNpg+0VL rxgbUg/+Mrnx1ob+WACO9L9iDmLvzX0mhtGfnMrYou9tVrfwBwVGzNdmtcufE8F2 qthcANT9tli+xg+XFzZlfzmPC0oq7Gtf7Q3X563JE94RQF9sljy5AmoI+UKE7wD3 CP4PSqp35GB4Ev4kLmiowTIH0udcid9yutQtCMB7c+jPv1pg87KK6hjaRfXYKBF9 VRUHzRfPkkx8yXrvl+rq9TSZxqiPWYPuEcPLLQk//WinMBj50A/quTmTLvOii8mL 7Ldxzsfw4w6tKRGPq60fwkrEByJGusZhafzHM34LbjSu4gtFrELDeQ8fjyQvgIvn DHOz5pU8Wb2jcKRIRolAf3MC29+PLDWIpvyvmbitT9fOqPn7E71PFvgXpPNfLle6 NQcwHROCcZ8rOMHjm8mpwd+NRuBNa4+zRCZolzr7cdkGEsQOHMIHtrUOQuSgB2Ov 6UseGB5kE9YCxgS6lAGvrwm8m3wdjNemVUkSeh3Ghws90x+yXAReSd/Fcn+WCMgQ Mi1htrJKUXnIL7MibdoMFdWXZzq7K/3oqTFzODLoYBS6RMZRsmToD4DstKb2e60g oGCrCzoATdTOn61/su8UmPeiO9eBWMSCh17EW6/B65LnDNFdbaOhZDRjaAz28eRU vu4ZbZReUufhDLrf9iIVoaoOVSASr68ZKEGTJItHxtl8F2UPON8= =3D2n -----END PGP SIGNATURE----- ================================================ FILE: sig/v1.7rc1/jq-linux-mipsr6.asc ================================================ -----BEGIN PGP SIGNATURE----- iQIzBAABCAAdFiEEkwealRHvwLfWzb+1sNpg+0VLrxgFAmiLcmgACgkQsNpg+0VL rxhh8w/+PB4r3/JmzvOfEzyRqLG1wLC3hLdm7dXyWeX+FOIGARCZ/m6L+CxAe+sK mdIBsDiGzDYaZQqQ+ps2A7XzmIA3NMIT7hRrfe0pFH+HBYWP3B42m4Ad7qgkFC7o OfPvjwYqhNq8rMTJIRTMO0q6VQOqTs93QzqoVwvfUYEZgeP7T/MVq5Ir4lp6jK4I 7B06+zXjCdbqW0NC70ga6/kV5iSTJpCI9H6AYhaAaRCeuetKEq7Czl2NtkKJ1p0V mWSOCjcpzYFs7GvZyaPCYc/BSs+63ds8a1sHcgtnz+sCCZ2CkoE0fUf+5bkKCX+a SS00wPu8frtBU74rT8TXezBrxt3SxWIOm6eqWWWEsohF0W45FHE7rrBHa8KgsMBX 0iegdzntJWgSSrMTouHae0Yr5tHoDPGS9xThatUqEKhn1xii+E7mkq3ryPaplumy h9AahwoMrqr62w2vjfjGDjkSMxJjeldwOVuaUjM+2lidNM2dE9cfjHzvSNmtlMyD 9l1dpV+AvBe1PIZUxeUwX72nT600B3lRaBdfnk+kJOMUoMqRLgsW+2oYK6lOObiJ DW7jwgLyk+vG0IqS+344W6uj++VfdFhVAMzdWKX42rfCgSdeu/vD4sS4lmuOp1yr 9IFlQnYCsb9xnQi4U/4CpBg9jeWQ+KYJq3d9VJVfb40bh55K4Q8= =h6tI -----END PGP SIGNATURE----- ================================================ FILE: sig/v1.7rc1/jq-linux-mipsr6el.asc ================================================ -----BEGIN PGP SIGNATURE----- iQIzBAABCAAdFiEEkwealRHvwLfWzb+1sNpg+0VLrxgFAmiLcmgACgkQsNpg+0VL rxgsBA/+PewQy0cuEYaVXixNa21lWzqgSjaS7R4l1KOL47aNhmQbVITeFA9FOFro 68Au/o223tFMhBWbJafB0UXUyTOdBAF8xN2OPgXv0TM7IulFSO9DMb9frHIlrg0u WMmcNr0rzNAedLsnQ66Fg+G64Se2ER/cqyxzZ6i+TctXQnt9CjupZsykK86T8eug A1wmVyLxwZnYM0wCvR142ADhCwj6yZRBUyOPvtUGUAlVEfWBxEllEqBOZHInd2Bh QP9AYTnZh5vBm/+LixhzKTJUeN2KUZCKnWc/HJKBkRozyCzkYPx7fjA8nVE/Bw7B bOhdPptxfFgck+/sPF3jlfi+Gu9daaBBYtaJZQijbc/JXXXbB0ipRaSILbPTOskR FnQ7agSmEciRoiRUccerbQVBlrF6B8zNZ+xdE/iXVsh/Ph7dRPPcfa+DdU6ysHuA e61mrcwhcbojx2SGLC06uordoMvAUCuCbbmGsS1YNwDBBmUbPfzNySFr47A/8jNR yGHZkxu/qWIuA6HHEXndsbwOnMzCLVPhD+efbVOJ5Npj5YbzWQFsrcIwci/vnNT3 AYlPeanjCk4pWUUljFQuc8vJu+YckLqckOYS2Nk6BV2c8OMYsxuyFjQcafAOflqJ utiE7gnqRyy7ktUpUeEUMgnXYmBfphFUfqFdhMS4LINY6dGHOCw= =xT/a -----END PGP SIGNATURE----- ================================================ FILE: sig/v1.7rc1/jq-linux-powerpc.asc ================================================ -----BEGIN PGP SIGNATURE----- iQIzBAABCAAdFiEEkwealRHvwLfWzb+1sNpg+0VLrxgFAmiLcmgACgkQsNpg+0VL rxiDnhAAmNuWQ4GrXoWWIaLERJlfi/VTfxK3A1CCMPxphGEYG4D7kFURmAoElSR4 2CBIUP9slRRKZWgxyiIJso4uiuwDSkDeH4IWuHGVZG3jHcOs1XMo+wUaxQfocg/N MtaChc7DlaiqmFOZexQD5+tGdI95jSCsFN3oAh3P/pfsLfkld+c7AIRnMIco6XMf fShBpQ+Y6jZ75lbxFVvoAXHeFN7Jubg2iIehQDyXPkPNZgxuOUlBRNYz4zuzh/ki H5wJRHfvi+CrWmRGihyLHUVQQB3V3awQFVMyisePe+4jIWa3LsPos29VHYhwHGKk vec6kPp5dd8040yO0AvbQD7A3Bi9s64KDo7cPdLi2wMrCXCTrCHILuSgrdNDmb3t mzVyevU+6foTH4Gt5buED1otYLhA9JZLdoddeNJwM9a2xFYn1yHBUiqhFIWQ6G1y dhamUNuxR3MXgJZKhoJKuLTYT81JaFTf63qneBlOtf7B89CN7YVbDjEpVMAMb2l6 +0eidDvBtDFYaBVdn2fmOx/ojDQTqAI8Lq8Z2EM5AixM45vUb+vIusU/EKGq1TIH ysJJXECg9Qhr4Cf7lthcjxnq7m8+/EgG8UgJuWnuknpOjpTYXU8PYLZ8u0dWDa4N EhMxYABwPnmu6dqlCEubZ//EgApFcFKxdoShCtrByw0nUv60rXU= =DvGW -----END PGP SIGNATURE----- ================================================ FILE: sig/v1.7rc1/jq-linux-ppc64el.asc ================================================ -----BEGIN PGP SIGNATURE----- iQIzBAABCAAdFiEEkwealRHvwLfWzb+1sNpg+0VLrxgFAmiLcmgACgkQsNpg+0VL rxhWzg//Xp84TAC6nKex2ltAnpCJQzql1CPauFW5Qn0bRKsUcXB1j4iMi7/piYwY buetz+jcj7g8XpEzCvV3yrE1iRCiSqL27oN2k8JbwfHuhJWSaLaAANZ7FI7LUyMw dR/5sa9BrdTJbJYw0z5AmDYNajpOJLdYwOr6/rt3Pte4e8rv0rGkT2ZzQqOwX2tu bJyocHZMDwnk65iOPIfFjdWD32zDcbnUAxsUTWPktv672VYAJ131SaKhQOuyuxKn KdQALSS+maB92cG96IjnqagQR3S8zynvOz9uThW0yn9sA9u0oMkGcmHRdK6FdYQ5 b5gaj3TZy1Qf8dHwS2+QFuMYSACMM5gjfF5L+iEZsn4pD+bRsp7QPbZSp5ebGOBq uCRV1PRUfqHFRMF7ZL28/I/RDCHhLY26Y6iUnFVUnFvuJG8TLQbGDo1Vkvj8GVQ2 Dr7DNQuqGqtjLyfkkueE6NFRtwsaimt74ELloU+RQvrlr8IueY9uBS0Tb7/hidMN 2mWhjxiScZFG34+bjQAfr9aKlzZVTpL6gXFDNtTLsbf5WP8vDG6SOzfv0NaTGSMu YQIKNO+gKiX6Kz+rFJSzhDjMwOVCOcL6YHXKWu6aBZ92YRdWKMMbi2CvH5fblvEa KnIAValae5XkY9GXcObIoCQkWWEeG0z13vLUs3qXKc4THSeFPVQ= =AZpR -----END PGP SIGNATURE----- ================================================ FILE: sig/v1.7rc1/jq-linux-riscv64.asc ================================================ -----BEGIN PGP SIGNATURE----- iQIzBAABCAAdFiEEkwealRHvwLfWzb+1sNpg+0VLrxgFAmiLcmgACgkQsNpg+0VL rxiiEQ/8CPwASVeAhBg50Drctpf4c1MY6TqJvsGJaD4uTzjoUBr2BBmDEhAJVeB1 /LsUnreZUrEn1Q5C1GglEbuVSPzrJGsFEI7tpwUOGiLmCWLJ05tC2vuIdc3+6PTq 9esR9n8o3MrS8X0XI5uYUBdyXoEXB96CgJYwy9pD+p/arrXsxzfFh39YGphVJsGO Hl1lv0aS27jsNUb8z3wwSo99zJ8zMEgm3xJHymg9yZnlF6kEUOye8BJqJStyqfvW bqg7UbSxIJ4g5jSvaaFbMdXiIS1j28pX9bS6NP37xHr5h+oGk4o/aoylEsKJeHga I60ku6kkh7pYGIYY4g6ymXbdBn1/fmk1JCUjwE1/bq4Atz1IpzX73HshPL9p47jZ Mtc+CwcS0uLy4bXR/Uiz6SLZY+o2ivOUjAaqppIdv2UU25KZ2gMxxK6wRWhS4zD6 Eb/yO5iurIhrpU9ws/zVSSsaqPfhMNp0k/+bwRhnMyNXDP8uWiaqrKPz5tnLV13y O40Z45KaLwMTlMYCj7CmgX736dwfTQr2EZyqpiCTfcXPpQzHiiE+EXx8jtZNWLmA PJ6h9WHnTQt52Itz7tDa6SgyHi5Uu/ZgjXv59A7LTcbGM28sryr6n/VYd6cQNh0s o0Q6XFYr/9fjPnxj1seUfRavtclac4BqDfdGQ/+MJJ4Sx/sPn1w= =u4Nk -----END PGP SIGNATURE----- ================================================ FILE: sig/v1.7rc1/jq-linux-s390x.asc ================================================ -----BEGIN PGP SIGNATURE----- iQIzBAABCAAdFiEEkwealRHvwLfWzb+1sNpg+0VLrxgFAmiLcmkACgkQsNpg+0VL rxhT7hAAuOrde3Dk3GIT4LAcUBE9FvYBmJNYoibCN7jqbMjyhv4ElM3/VO7U2zAp 2mADufO9MGpqFn0H+eE2qfQJsfAfSDqIKj20LBnKFqxKQzFSrwbePlrBge4a3ODt k56ZTxM2ijHp2yPTaDYtKejlSCpxoJ9fquIzzd1H6y9MRHnOxA5+Fi7VV9XYZa5p ymft8SyXVG86324MN7U8WCTkSS1P48/5vjq7Cv2Ng6saLneeGrQg0X9Wr76PpCSo 3JYuwrPi9U/BX8sqcX5m98UYqQxdKdskeBm6FfzhG8cX9rhFTtOF3Ud/DiKVNiFI s/B9ZHSGLogNgn5seycLmPXukDPEWd7fm/XPdy2HtH82mUc8bEk+TfrrSBE/R1v1 et26SSr/XuEq6gtBOrDN8W+9XjpAeSJx9+HYc0kUM9cDo7eRKWkQ/5DqYc/t560y FDCOjDgJwezh50quBAtUBTDHjR+AkXelp8tGBgdeMTODC77wpATXcooS9NRMIpky fqC9bmGYojok9n6quYOUdmMUtIkdMtzYBNOGn3TOcAbiMeRxKolRy/JINBZ6fSUW chZHXtKGg5b0kjyAT1Ti9jl6s6ZqPpLarPNcb4XKQWtlGzn4OT3EkyCSFsD7HKoQ C9ZDd7zbRU7p3SwHh6lb5Meu/fDLWzRseJLY6n91CmSJQxEv95Y= =OjTY -----END PGP SIGNATURE----- ================================================ FILE: sig/v1.7rc1/jq-macos-amd64.asc ================================================ -----BEGIN PGP SIGNATURE----- iQIzBAABCAAdFiEEkwealRHvwLfWzb+1sNpg+0VLrxgFAmiLcmkACgkQsNpg+0VL rxin4g//RcbIWxy1MlVquBec4JJASgOISbbMGcyEXSATA8OPL8vIe8H45GR37z0d saG3bZ99ct/o9T9akgzSX0ybmPwKgbGNuUNg9eegXJz5JFvSXKTw/oOmDHfpUoQ8 +NAX/t08UPv7kVtvKFKbOqMzc5015c6fWg7AzawsNXbgzE7PxbruCKw4/duqGNJe ImBuv4Rr0vhHUMTCfU0ANSnGdVswtxjMSUjD+sJpY8eKjLglQjCvz/4d64iiVEyV Ecfz2vnkbAD5vtVkTVoL31KWntYvkwBN+O//fxGRFNfnWT8RYCY+mgEhaDGWpTex 9cEzxXciaYa7hzMZStrg4bli1vs8MN+lS9HeoO4pF5ASnStNE4T4+UaDuu/jq85W Hl5fybJ/5lqDFH0nqzjF9bsVvks7fhfMpiicuY9EyY6d7GIaktzmNHyDyMm9n2xc 4MQeof2I/o2CzFb8wJRdMljUwg19fEWPDsK4XmL/CtZ0eX5JzE+vC6J0dX1pnOZz V50Kfj5UFpzncGP6wfPb+gFa2WCVzZzIpx38IMaiG1ayu675RVZQVQySX5ZEnMPu T+8dVYG2Xb2Q9yFsSjbvU7x0TFzteKxOOHItL2D5GqH97HZagOsRS7iO7/ihBGbh aFeS5gAoDsErmDyCj8i2XsVxSpc0ISDYNiePZlX7ttywZSJ2qeA= =mfbp -----END PGP SIGNATURE----- ================================================ FILE: sig/v1.7rc1/jq-macos-arm64.asc ================================================ -----BEGIN PGP SIGNATURE----- iQIzBAABCAAdFiEEkwealRHvwLfWzb+1sNpg+0VLrxgFAmiLcmkACgkQsNpg+0VL rxjuHRAAll/Lz/hjYoVdwKRNuT00NzeazYGTtUpskIFhzmSGxJdv8YCAEKWj0C0j XAzeU34zEOXhzUCyHdsypmRu2zARDhzNr+mbJl7SGfh5cM+bmJ8Ljl6QbP69JorH IQZpMGvR1qv/fvkIBca7ZF9h69gl1MRDb1LLu4062r6Kgfq5VxeSx1gbLR5ghAbg 1smqIo7WR8mBTuHLOC56bsZIZRlon3rwuqUkyYlYtiHay5nbLuH9HwjxsblVwtxn gIm1/MgOxRlCdfuvxI39bNULK9khiieyhi76Sj3ET5zhBQszxR7KjE4wEzwbkvlb 4lmepzPJdawkTRs4BBDCKkk6Cm0dL718/CRuyxs/oVczkX76ylvHURulpmoXZSHF SXKU5D1pwREbyMFIvc7uM/d+Ww9yxxJngzE/0lawVFozd6N2KpwERmMp51QdylrU t/Dp4nTL1WwdMuStDdSFLX5F37eliKjx/ITEGzTwUBXCkKuFW98KJHEH7Doa8I30 ucHcG0EIP6ilX2+ZKQ2CIplra09k8N/65mBlHBPfjvm/QQRgUUBVkZFo25xiDNCu l6iDuo+U5qRgJfv/WhEl2fjKowhuBoQso3/r7xeF7UtxDOyYv5dGeLCm3IAYbqUz 1NfxxrMh1r2oZa/MPg+c2V4Xrttf/X+cAPSRh6cLwaCm7xpkyP8= =/hN0 -----END PGP SIGNATURE----- ================================================ FILE: sig/v1.7rc1/jq-windows-amd64.exe.asc ================================================ -----BEGIN PGP SIGNATURE----- iQIzBAABCAAdFiEEkwealRHvwLfWzb+1sNpg+0VLrxgFAmiLcmkACgkQsNpg+0VL rxjghg//a3k8YL1fMg8gJu4K7seXOOwOoP0Hf5NJolQRBC1GXh4JW53ZSx7+KhUH 1T7PQKQ00yL5oHgdYookG8uOZ4zqkl7OKqu9Rryrm/u9GOw7HWfTqs/dJL5fQ6d8 vz+bHvcMLQEiXrvlsZ6kG6ZO+1yp3gzA0MS6HZ5G3o9wFrt+CuA6CDlA9K221FBo X7t84dz69rvDdoAf6EMOieoDnI4nDxAE2nls0oWA1Py3Z0ztfH91OROPucM3uhxr RM9l7QKP29FvWzkU3c3dmaXNWKGUidVsxJtzqynqVZMiJG/d3fbiErFNgPi69ek+ f9D53DpkxVrpEw3fcUrsU9tEdOKRTujzYC7O2y8WozCalU1H8/Ue4YE7uzKkhlvp cIX+OrQQng2vDRKKoqwJC1ANTMEBES2XEreoxK7Z0xNZ87WGpYuFzjLKCIWJM4Ah 4hWZ1ymTMJQEvqgy8vhPkNHoRuSrp0ZbbkcfsY++lWSzvK6FK2VsmX4RSQmNtav5 f5qBVAhqXURsLoRarRWhJR5VroHGefevFiS8ij0V9GedMowuSGsm+7lr6gvfOsuU PH0DD7G6ybwvZTPKSeNFGe2YwGwVXG/WGI3p0wVjtRuRAftZsCzKmQ7gPK4gFb5L LyvItTaST2DA41CUJg+VXr4T5GWUJvxjmNjoGAgK2M4RCmcQ6xA= =lqH4 -----END PGP SIGNATURE----- ================================================ FILE: sig/v1.7rc1/jq-windows-i386.exe.asc ================================================ -----BEGIN PGP SIGNATURE----- iQIzBAABCAAdFiEEkwealRHvwLfWzb+1sNpg+0VLrxgFAmiLcmkACgkQsNpg+0VL rxj/ZhAAxVJ3mXqCkmk7/6CxTmXnZZreaZz+RPsFU1lc1ZZ2Lx9xJS/jzOMflWEl Lw1BtG1wWgxm3P2ph8s4bdI/vSOtmZbg2DYCwOEo/iixFbwgdMuXjEivKMtxSFKY YSoD+JHjwd9gpZQkph0mEHQ7radsFTnR9NME32BCPzoGa0403BpR3dQFsjCa26Db yjV43MY0k0SOTtimghZfyB5r/guaO+49jR1TJprNV3jSZ4eHH0F21IJ3leDVOaFC eZAkDN9GSfW2Cag0G0e/roWSprM1Ehd0eGIMZ76b6/kf1vhyaSj6EXIgxVg1cW2C ghp4Wzzc27oS0EcrWHJS8KTQRPzLXb/PuCo/VQddbi7PQ1h7zeoLpcsDPAWfrOHC bfkt0uxiXbbdDjlLK65EsdgcpzRDYPsPSk/yvh3cNR3ZWUYGImjEt/AKNNTvaAid onDIdf7tXMMbhXUzF8+m2GoxsDegQDVw3iPV6liWub13Sz8aUrTeWclWp262NASr YEV5lJj5kC/rjGJTIjPXPvOBXVXy9RuSgFnY4yMU0QY0Ih9H/orwHQW/LBbcQG7F Xm6jEKdBVxGExfMeizuaT3IlbBl3hpEGemAuzuq1pQgD1ru8fCh/GCyO5IxrYs4l cIjez5lCml+pHmQhKbz4gFmFt6ioOywTgHCSY8GAuPIBSzBxp+I= =cXGV -----END PGP SIGNATURE----- ================================================ FILE: sig/v1.7rc1/sha256sum.txt ================================================ a6a7837cb46c61a8666467fef06754fe53b95c1626b5416ada58edfe1393dac3 jq-1.7rc1.tar.gz a552843335c2939741ae4b52979d6a3ef6057de5518fd4d9547d9847a6fee897 jq-1.7rc1.zip df823ab1c7c9dbe4bca47c5ce900cb71573fd4a522411eb38dc8dbfab339ba5c jq-linux-amd64 ce66388d20c6cc69d95b24f50b03157660c60c164db23f58e403d0fdd6b2e0e1 jq-linux-arm64 46360984be3ec632d642f77a3dbd4730e77089f847db2c7b7c648f4032e7fbb1 jq-linux-armel 0ad30037a0ec8ecd15ab0323aa402d9f4d5ca93c4fa1318b9f08cc8ddd739f98 jq-linux-armhf f75abe58677fa16ce1a93215e4448ff3920faaa78da2c6238b2f9484e193f4a2 jq-linux-i386 9407f122e820e0e5a0819a322d8232bd1e9146347c658ba903eb85768fbdde8e jq-linux-mips addd2e0da5c34c975da6d5ef12629606b978ca823b99ab7e8bde7dd8440a9706 jq-linux-mips64 89c3b6daaf87ae7a70d0d8e8aab4e9026e097fc8e4dd950c33689ba6360f6a96 jq-linux-mips64el d2cf17cc238e57a9373ae69e6ed7ae3eb918e0a0a76972909ef9e2387db5a0d7 jq-linux-mips64r6 d07023b4fb28fea0240c0c37e774e854c9378bc606dffa4c183bfdbd1d08d37f jq-linux-mips64r6el 5aa162cdd5fa3568cc1550e4ca4dde7f9231460877d016717a0475a79571ea03 jq-linux-mipsel 2ce97d0afe6d6420d2f0515a10e64858e50434f38f71597b7a2f703a12cf500d jq-linux-mipsr6 3f9ea2de719988c13bb355225faeb7d05bc04c362fe96fd8333e3f7450d37514 jq-linux-mipsr6el d127e6d3c5271784ae5a5673869d55e352fee3ef6ffde66c9a08be4627b6caa6 jq-linux-powerpc 5cfcf735ee21ba01151bc9e03540bc5dc373df5a7ce2389bd9ecdef4e82301c8 jq-linux-ppc64el 7db74136fe72b143b311567c9b63a16107aef7237299fc3a5749987b778ce84f jq-linux-riscv64 b7dfc2af6d1a84957987a1051f4d20276655433b2e8a5e085db75f6683d7a52b jq-linux-s390x 299dc32bc6fdf2e085e70f7efaed72da8b66fb4287b323106c2174dcc8248357 jq-macos-amd64 e159d0a02bb5f41930f8d9775777a2dde5d9e6747666e285c00d5729305a882a jq-macos-arm64 56c0361bccbd325bd1ffe607b64f955c30fbb800fef0d58c5ef69e2a242ce577 jq-windows-amd64.exe 9357fb09f158c880e5bd67d971bb98a33a2c0a1ffc33e859533a89b28c914a76 jq-windows-i386.exe ================================================ FILE: sig/v1.7rc2/jq-1.7rc2.tar.gz.asc ================================================ -----BEGIN PGP SIGNATURE----- iQIzBAABCAAdFiEEkwealRHvwLfWzb+1sNpg+0VLrxgFAmiLcnIACgkQsNpg+0VL rxjNAw//YHABP13K1tpHrvkUkKXAu4zmXRMMdR1cdxamvG1rruA7MxsOh7FBmfFQ zZAssCk6WrrMANmDd0dEpxOCiT8qPfP7hE6fFf9xbSpzJixjIn2VNLc3KkS26aB3 wV/3QWqJzExz8Bsw/6OOLjw3fL6e/69x9sdb7CtNVsY+8CNIXR/rLzbvEn2zK4SK 0PtHWMDPfeHR6o7/TTvfKKdarroDoJjj2ACzg9IGtaVoi8wADdtF2lBzeccwbd2U p5s7GEb8HecN0nA47DkzkZjb3MGvq9KTJXrVNQ1Svn1a82jSJq6FoeY2D1ZEoyOh d6WSK1s5iFqU8v7GUeVIQcKnQMpwYGRfzeeWktAQbca8WS4m62vXVPrnfkJnGJSF SRXq920j/AhhXWv0LiDxUIlQdx+7nfdGsWLooyRoR59KN4J4IkeBYVLoVb3QHvhY N1cw/pC94UzhxGlWcDG0UttNPhIY2oiop3mQKl6cyWIpZddIwFHDvrr22cUfZcor 0yZbQvpCr09xAWE7Lefg27tR9Q6iFhktxbGuTW/9zAqjmTP1anoJ5eZpH7tViv+/ far8JQkAdcJWuFn14oTvLbfwvigmCPHInHfLwnY0QK51HOsElbllQLy7BFlk6fN9 uMlSJOUfpR0S/v8jKaq5tP0ptZP3rEKxhofMEbUCbd/FVPLyq1w= =yNWP -----END PGP SIGNATURE----- ================================================ FILE: sig/v1.7rc2/jq-1.7rc2.zip.asc ================================================ -----BEGIN PGP SIGNATURE----- iQIzBAABCAAdFiEEkwealRHvwLfWzb+1sNpg+0VLrxgFAmiLcnIACgkQsNpg+0VL rxjjAg//SjVeth+bv/MCkT5ZDiaaOQ0LRjhRLWthO4A6VPpmdtBuEfJ4sbd7IjHI +G17JJy8RwZKDSEwhEQNNdvCPaD0MFZkzuil9vM82kcw5Ao2qir7lWqNbZSYcVWC xbKZys0n8GXEcCeaYnJNmlTfHfZYZUWcta4BvaeHEp1q2YIXxkEIqoFvxX7P0SpS 7vxiffj+rSOLY/xklyrpl40A44ukxpwtd7DGbCUecjZAUTJC1rL3ZlD3jf9qRtQY 4QXJ09XnJuUSHG6FCzB/BYPDPzlPlu9amhK+tIkMkyo78FlLy0mUHIsf3g5GYhh9 0ylQUFgBpjIy6449a9P6XwmcBoLE3ir9+RDg6Xu1am5L7XipiTcE0lx8Op5ZtuzE 5iR0+EFa9ZjevFCjXhSgVE1zqoa6u1/9wA0v4jWVPKTPOKs90MSScdz3hgS2k3XR vchm84BN7VcD7ob06Vcd1G1FeWHJNKrTRufHag58dHvqQF+F1bqRGsnqPkv8avu1 A7o0HShxRBpHccxkHKDmjN1imkxv0WOKH7kC71Yr+7mZsfsrOfCTelGwwHE+CJ/5 dea8VbPNReX4M/r84fo5k6+epGmhSxvH5e8gOrj4u6uK541xNzGhJxUJg+GDYHL6 87e/UdBs9V9NDPkdLJoWJX2IYlXUectZpZMZEa+TjRgD2w5QX2Q= =Sum2 -----END PGP SIGNATURE----- ================================================ FILE: sig/v1.7rc2/jq-linux-amd64.asc ================================================ -----BEGIN PGP SIGNATURE----- iQIzBAABCAAdFiEEkwealRHvwLfWzb+1sNpg+0VLrxgFAmiLcnIACgkQsNpg+0VL rxhSnA/+KGGXVk8TgZD5dS4k/y4hfmZsYNqgOEK7tYTsJubXwLWOzqUjAJJWR7pV rzp/XyhUr74692elTMufOFQw03httc2MjNnLCetK6x4d1jAvomLJrUIU/zGqn4kr wvSe2Zp3hyNLepVm03oVP0gly1Je7YMyHXeuqDG+TBEX4RkTsTaJCnl8WN3kTtXj v1WHo/18jhJRfMoj6n+dSGXk9c2nDLX41QPSwOM6Owyh7dwjFZPzTcnNywQPChmw sgzBqP2PHsRmJmtYaBJedwvVZ27egiMV1Yy9+T2G+5RpIXmrQMCvgxgDcF7S3t2l kNVsZN+nurtbCWM1YU4m1pvDmCr4MFkruo01rlXVzOZLDrT/njF8VVgadhsXfmBU O4dU2c7XR4x/rTTEa57SHgD02h4nveM4tp7mUPuVVaPRQA4GqMKEE8MtTv4Q4KgJ xRdLnKdr0r9JhVJHsrjni3bqn1fGOY6o4/LqmDRoywHT7uTcf70IEzHxhSPZtLag R8j96b6H6LHCVjET7BIl/7WmNcvIwU/6OR/QJt+CcJn4dVfxKBMix3rkg+ZuH5lF vm0HAI/uSEwDneZFp5RomFvRH6UJlB7nrWdXn/Rh526Yj7qfPbHJWnX9/BwNnpzL 7Zpc2EMdb6FoXtWLUL/E0NNQW0tTr7B33ykXXAUG2DN3Z3ce1qY= =FtAN -----END PGP SIGNATURE----- ================================================ FILE: sig/v1.7rc2/jq-linux-arm64.asc ================================================ -----BEGIN PGP SIGNATURE----- iQIzBAABCAAdFiEEkwealRHvwLfWzb+1sNpg+0VLrxgFAmiLcnIACgkQsNpg+0VL rxjDNw//Q90Z3WIulbkc3hiFizXrN8XAxQnsuuEjUI+2pMaO4OQnoB0UFL++ch/t wfnwEAL1IIZtfZe10Mm1YExGQKTpiecqq0kHN933AMjAmTWYcfIzfOs444T5mPRn HYmx4bFEv3cZO0jUoAbimk0HQdcS/ew2txrpqlQVYvihT27CkY7L/fnDbnum8+IP AUKotFpnhfFYt42l6/+MwVBQdXnxb9bhJ59PrI19Sq4Ww30qOVB8g+Ms++LqC3V6 RpzFUUeZBJLVw2O6RFS0DsZdf2TR51hX0LFOnCLq61QskqFlaoghV006Bh6osBY1 QpMV87n2dQ62PyAtJAHkNii8cKe5na05L/05PrRc4ii6PAGpkg/hWbIBRd0Ez9eq Ps+GwArG9uVEDSYi1NQ6z3fiQaiHxnwENAmqMPxWi0ZZtv6wBsIGNWyDaLXTnFyD zBu3XzLs4Rf70sVDYlUmAgJ/lNzwHeRA6rFQm0w+TMdb3seSHd9HrFFbFEeqSwlf 23iTyyKnC/ZoVrA690/3bOtTfPJrPAMAWKfJxj8I2T87TnvWdlYomMC0mkw1/Yac VuEkaFt30MNe/E0EuiqfDgJSfnPke071zCdQAzyX7ohMaBpkBnZsLzd1FE9Vh6x9 eo2hyO4wgPzXadhIzQe7z5tmOsHJVb76nWSGhdsnb+yb4HRVCTU= =2NCH -----END PGP SIGNATURE----- ================================================ FILE: sig/v1.7rc2/jq-linux-armel.asc ================================================ -----BEGIN PGP SIGNATURE----- iQIzBAABCAAdFiEEkwealRHvwLfWzb+1sNpg+0VLrxgFAmiLcnIACgkQsNpg+0VL rxgNOA/+PCuuLzpM8J5D3lIJzHr2oNsGNRiAItZG4PRbul92VhKPDGB4NOvfHHRM kj9rbU6Vn9yFU2/L6W5CXcN+YEGobrr8NFmnxlJifAhQlr0ziHNqrew37cvy+GC7 ewJbewRckpdtYkoQ9YMFHcYGCDbcCCc3MalLso1iS1hI1OFRYH4ydXlTlknUC6Br I9kxsLjgIQC6JJOmQbAWZoCDTZ9YPKt4APqmgg8NddD3QkgJESHUWQvjC0Qvbe1b gCFyFit033xLMKnONy/AC2/SyC6HY6qkfU2dWwnDCWMs1yOxoVBzKC7Z0ryheZlB EiraPpDR7Z4WjF2eiwQiuk2rJEVH0iFPah78MhZwtPVje2zPyGDTsiGuQJ8aGYFJ 3Zl9afZQ6/ujAcxuQdFJkSWnVw7VqLl4sZDa+zKCGl2iuOSa9uuU117Ib9ZQtHXp arayRhAA6gJlcseUlkE9MLPLBISzexa4RvGsTgaX3Qhap148Ehhg5dsnesQpTT9t 1z0+9JNb7UZ49Pi1sw81JyS7LR9iFpwSIGfgMChLh0I0eRcOD2m8jD5/c9q1SmqT FpPtyxbxHfsjMKf60PyGVnkAxLpxhD5Y2ngAh2wKLUEQcwWLCfvu1mlpDFW7WXMf 0rI4N+Js8tygqBhskYC/A+Lvd/g6oWfVVh+bXeYIcLmTck5PwWE= =Vnt6 -----END PGP SIGNATURE----- ================================================ FILE: sig/v1.7rc2/jq-linux-armhf.asc ================================================ -----BEGIN PGP SIGNATURE----- iQIzBAABCAAdFiEEkwealRHvwLfWzb+1sNpg+0VLrxgFAmiLcnIACgkQsNpg+0VL rxgyAhAAqHyDyFZcoX3JD6BmxS29CDcrzmOqARjUkQqLxxQ3+O7CNIKJxKrxXmLL /aPXqA8mtr8HohQbt6n/G39/5HyrKLI2jnxU71El3EXwo/y2DzJsYylqgD4ETVzC BfV9VodC6/pdCa1xJSxLzD9kMzrEIPHivUWjoLSO1H54MComHh3uzpZV4d4J7DAo rUJeshouLxy34/NlvTr1JZg+sdjvJUutCeR8iMetVg8smNcGFOLBW9Cajkts5xwx +txZ1AsoILGzAE1+bFHYKDDo3VJGiTvJta84w2OHFaJkfWVMYB5IUtvWpxjra1hB rRoeUL1wA5vPsAsuX8Ndn8fOiWaUd7N2JGq0yZcsaf9tquhwidIGg9zloET1mJCY lT2tlsdMNhHUYisfXgZew0WArMApbavtmT8+9esWKc6iByR+AvPXA3zfqKcA1CI7 4Z0R7Q56O7/tyXiOz9gvOkbvutznhl5MW63ptieMGzqHzLsn0272Mi4iqOc1h2yU ZHcMYibPOuzUXcgEWxp5v615Wty0cPfwYRhRGXSNR+kqXWxw14bCteDg3wwLsBpi 488yhXydJ/X63YB5mPNMKsIqLuRl1/x/aRWTBGC5LLx4clg3sLtIxLtY1kh4q/xR 2xiZOC+tZLkGKLz6KrkVF2Auy2074TfC+8f8cH1lU18v/rAUuZ4= =BPoE -----END PGP SIGNATURE----- ================================================ FILE: sig/v1.7rc2/jq-linux-i386.asc ================================================ -----BEGIN PGP SIGNATURE----- iQIzBAABCAAdFiEEkwealRHvwLfWzb+1sNpg+0VLrxgFAmiLcnIACgkQsNpg+0VL rxg9HxAAipIB4LUOyRgT09imIt1IB8ocwE4YTPhhwD56axCqaslDPBNZgIyyWJ+P IMW0CTgHrMVJj9FOtWQT9I2X9d4qlueBtj9/hY5rxqt4HdyQwZVfaABjmq/Hfv2J no+I9o2n20NthtYMCfhO2pL23HhmmTow3hcovccmyXPKJb+xWpUfh/qNIDss2DRE ntHIZWEvDnTCUeSk0cFkEwfvEtptPMlCaH/2gqdqFJp3sFxRz+7/xnHniKkKmxLf Sx1ShI98/5D4CTZu1wJ/3SJnT8HGgOfo7aT19s/aFG/OVnT693XDd289S1SbnEW/ y/iObtsDLJRLby8EdGQNDEsp5MABb+e2nZmuNsFcqc/Uo7pnMLROd7aAT+dfXaK3 BGUiwfNO6w/C6sPXHmgCKiHL9l1/gtCYWcMBtNOKuVYRCBqUzL/mKlLYJE95H6i1 koBxWn2VIy3lfuLs0gCKZCuCQDXjRHvhuOhIbM0BWchwpG37MC+3jlFV63Irv/xh 1IGiCYLt5mfnLglpBAM92Irx4KKaFvX0DvF/0A5PGUdPDCWHfE15YX4CC+XfJ3rV 6KgICRJEkHa9DqbymMZ+7I3RRw/d06tarv2fPsTHFPNeMBAqoRg0lwO9WaSWQ7R+ ksu0nwRVlVY7Dljw4uGjF7qRpIvCB6/aljDklMaLrdgDjwVTSgE= =SmB5 -----END PGP SIGNATURE----- ================================================ FILE: sig/v1.7rc2/jq-linux-mips.asc ================================================ -----BEGIN PGP SIGNATURE----- iQIzBAABCAAdFiEEkwealRHvwLfWzb+1sNpg+0VLrxgFAmiLcnMACgkQsNpg+0VL rxh2OQ/+I8uvLk/WJmfGggLcW/l9nlD86lEwvsxjevZokFAG0z9PSaQuN2Z+4T1n MD9uHIqJuxvDHOp6hAI3IrCzKISV59cBRxAbTgFPU4s6DVW8Y7NNKtEfk7KUiYJK 6Zq2bxqSVrpoS/rIuoNj42BLS6cTz6v7yJ15RHHERkQ9GL2Z+nRHfcqovz7dOOGL Tb4y0IQvsPb5/L0O1M3AzEYbcHwCAtfEkiC7CmBJlB9DCC2qKq8yo9pYVZYpDdaA uwotwYFREo8NoZB44l3P8GlVRVqDsqImiVODsY1InMBIy0q+7c4UmNLkJDrLyyzn JEPg29vY0oOXN/vK0tYlRc+NnNESvVGsnGnKljHy+5FRFDH/mYJRxMzFlTEnV5+g a2+sPqksTdtKJUgHVo0UvHb27t8WRxxcnXNsDC9e/SuCdQWOJufc6siJiUEOnUWO G5jUNTFOiOewhLoA+qSN6q6nlMrXPhoiNe77lnQlDqf2B5aoErUNLRNPaZbz0K1z jSlOYkOPHfnufisa7/cHgbExLTTB5OJ5cGKkOpuyw2aNmqFiyfU3qsKX23ybBFlT RQOzmlgpaO+FhJ/tXyx4u+1kCNCOM2OYMcE+qqVaQ7nTDQ3hGdblWby7K2PJm5tT Fq1P9iYbk1kBEFnvOZEKKvMWxqjTTVWu3s97abiD9yehce92wUs= =HInu -----END PGP SIGNATURE----- ================================================ FILE: sig/v1.7rc2/jq-linux-mips64.asc ================================================ -----BEGIN PGP SIGNATURE----- iQIzBAABCAAdFiEEkwealRHvwLfWzb+1sNpg+0VLrxgFAmiLcnMACgkQsNpg+0VL rxhorhAAsTr+XX32+V9lKVdD1rNSeMZr56Adudf7qibQh3DQLHyborqd4FVIl+mz 48dhTWIEs2hhjxRIhBbRWlh+H7UKIfCYIeicPxQ3wtfFnmr41pYpVVWq1zCsA1vQ n2Wn5DtPvG9m6tzgyYqTLbwESz73xBrKV9QBT5QjWTtqACr+LRkAx0BAVlVfGHBP l3ZiZCm+T0tFJo3cxIBW+MI+hhCNSIsfWUQri+MIccJq7s/hZQKzJnLzeFfxC7SC STcbd9w6xrY/FqZMT0RBsJmo747XeYumS35gtkDz0SWgT8kcmwgTVK4cFkUX+Z+G wV+QvNilYrflrHDc+dKQ+SPywGLVXi60V+kURBKXXo/1Ub0gJYIKIcW+fgEhVPa6 4HOvljvbXFgUrXP/94q4HzoXxe8eg4TuhUUF0SgALFK9MTXxGR41s7P0gkYrC0Lp 8btaTfttSEFpDvc8DblP9X1tNEKcILThln/DSdMmchMpYy0vH1uO9V/dPBN3LqrV 9yA8RR4k0fepWDLk2Ux7KGG2KT76zzu37/803x+AB3ExCqW5uIx+dmhdftD7p0VP spTa6sh8qlj11NqvILZml3vwRpF3FhiJ5baNKYUCGgt+Jcn4MQdB/lcEE4VGU5Uv sT5GgIPuxq0Q73oVd6VdJlQdIoMJ6uZfUxYsxtlZ2Zk1V+Pzx2U= =jYTD -----END PGP SIGNATURE----- ================================================ FILE: sig/v1.7rc2/jq-linux-mips64el.asc ================================================ -----BEGIN PGP SIGNATURE----- iQIzBAABCAAdFiEEkwealRHvwLfWzb+1sNpg+0VLrxgFAmiLcnMACgkQsNpg+0VL rxh12g/8Dui2XSC8rdM9ruvp4zIqM2eL7LPbErgxcN/yzlfIPJ3GKHUJQmsTnmQ6 oQtiNbQ7qNjdm28OidzweCUh3F2Vhcf1PeGEOlw59qG73gsL3EE856VAVs+4XSgm pBpmL9qmppMpnzXX+Rr/seXZH6hNW8UPa7Y2idADnRBa15wWiwcbrqNdSaErWY6m tVObgEJOSETzgcJxz/t9v3gXVbMARQeZJ5Feom4DAA8bgNyUoFagX6TYVYWmKRZT aaIpULhK7BGg8pTbjFfvzeFzVpeEQ9OJfC00pI52TVg0rxrzKqMZeI6PGgVnoEJw E7nsqq7fhah3yvqckLm9eEbcSD9LyUM9Uqyw9Mof+Ufnb+P02DMLWBgW6BxfC5nw 18lfXUKg8TmABCMm2KrsW8OsILsmHS/W0XybFcVncUy6Frzvg9ckaHrRBokbV1Nw 7CvLLO/WhKGlW1QnNMdixEXCnKzqkN+jNYMw/DMqzB+Flmfz87g0Z8UlEtJxlz1g XZqON2mDvuTjDKIZkTYtrbE0VuVMkl3NJDibf7O1AgGud7D2+HJjmzWdWnDKQuDt L7o8ebfTIP5d8euFP+q9hKjLzb7dEJ3siOjxvd/PQPUuHJLDRYfjoLInj4mqnAH/ L7BixDKh4xJ5orfJCIAQZMXPGMCZ/iYU7Dd61clpxJqbRhgzwMk= =1brC -----END PGP SIGNATURE----- ================================================ FILE: sig/v1.7rc2/jq-linux-mips64r6.asc ================================================ -----BEGIN PGP SIGNATURE----- iQIzBAABCAAdFiEEkwealRHvwLfWzb+1sNpg+0VLrxgFAmiLcnMACgkQsNpg+0VL rxi/SQ/9FByl5/uAtnMzjWYVXVg5M9++dd2OVuV7q54YbXQNJsMB426jAn48xSDO 1O31SxuaB3RfB/jcIyxSM7LYC9GQuIHBlrnqcBiIDH5GOPdyArtRTnbquC4JuYVR jEIbbrczoJdp4k9+2+XnpcWsUoiKLu5v2m74KPErTvxUytAIlg5bP/o41qe3lzuB 2Wz6rzzRVBbqqwZtYOEe9lt4fmzSG0GmoP4c02ROAxNeiDSO9I9kZGOf+OLDxCDy uowHI9zNIgb6yEXt8hScuphcIPS5WSdn+XT1Tp4VytuF/tJ3r4etOnWUIS2Ak+YV vKUEeN/9jdtYpNTjP2nYyidNlDZgzEG3Srq3O7jY9eyH/HhVJXH1rKW44E8xbkp9 46B/mVT41njBWwQZFzDS+27Lx+Y7E1ulPzX20WU8OQmoI8UNKPSxwvwDBEGlSple OWhm6IjBEmTBPYWRqn8NmAnHYhB2ySkW5JpDekDcmnCAh3a49/uSDAm9Tk7fVYJj cA0SnGGC0/dfNaHkXi/ZDs+mjrDdPRS//FnA/KuKSD8jLDWbv5fHe8zYFRgv38Hu L5i8PI6UPXQKNjKtUAz75Sog16xa8VnCwHM2OWPUp+lLW1j6WSomLsw93YB3QFd0 EF6jAk3I6fysF+xXq9V25j7V1aNfXq0Wfx6HAqt+rfeg4kBOyIs= =TMuh -----END PGP SIGNATURE----- ================================================ FILE: sig/v1.7rc2/jq-linux-mips64r6el.asc ================================================ -----BEGIN PGP SIGNATURE----- iQIzBAABCAAdFiEEkwealRHvwLfWzb+1sNpg+0VLrxgFAmiLcnMACgkQsNpg+0VL rxjsuhAAySYBBPWV7hEQ/1qFlHCIZexBjycLIsp4tButfx6eVZGN+J2zxiP8riTY lBaVJseeJVQmnuJ0oOmMLBbQymZj6Iv0Mk32FKiuC1ncPTl8+QZsNVdtse7r2mfC jL6LvaHfU9qwfMiufA8BXrejPOxX8g4Gv1YCJWAc++H+eCxupNVyPtUYFFEb+gr0 6jPxkeTqudAKah6gAfipBHnxwutc6BG33uHVAJjcGEdf9KqSVNhLzp2S643c9iG9 wk/r0S22cRS8x/HdIXxLwXj01ocxbyw+vMTAQo35CN00YXqxQShnzM8WkNKiK1wA QIpoQO98ebV1f00BBEfHe4CpMqtVSabrTSnVVNmiee/sOIstNSuQb3+BVLT5VfXa As30sUQI6MHIkVwDw/N7LFj2sT27hJEgGR3Lcjb8WSDBFbfs9k6FOMuIc7gc5MUJ uozyLkUSi2QQcdkxWooQdMEmdLxeB5r6jv1aPSc1MJ4U6ZvunEGVEsI8/g34DiKV EqtSg11t6ye7Y6gulZNJFvNFR2jSzWmDOhpEctkzFMsRWCJaXQhrOyDOYcIfSzPr co0ACbHgX6rZc4ymtNjg6RwWkXJyGtkPdaAQqQdhC6efpvK1khcsdsGu7HohMHsM w4/u7d2M70umljsVRZf1sh7C8wUA3qO/quNC83sEs2+9+dv6R2M= =hHjg -----END PGP SIGNATURE----- ================================================ FILE: sig/v1.7rc2/jq-linux-mipsel.asc ================================================ -----BEGIN PGP SIGNATURE----- iQIzBAABCAAdFiEEkwealRHvwLfWzb+1sNpg+0VLrxgFAmiLcnMACgkQsNpg+0VL rxgmARAAr9PkAo/RydnmisdkxdMnse1yI6J/KigaQUi9t34zmAeohKkgVunmLir7 jXmJdK1GKYmkf0xYZ7Bd5M0ktffk2GLkl01J7mzh4lU4vRWpAe19Obu6rMJ/i+Xt fCdd8RBfxToeVORx6J2UUp2ux/yg1f0MfxvyY6Z6UD+EMTg4MH/L70ZqEbG60/h3 BTl2QPoqN4jvACsjI2Enhm1GuF8uCcv+QOjoLnxCl0sVWUICqqhv1qm+TVP0mRma xiP5lxEF3Y1pMoDpg8lhZz1/MNSsFucbhJjEv07Ly2r7qqeEQkqwHMKebVxMPpQr A73PpGX0Jk65fSh/KyBdT9p+QllLiJCkIbqrSwcN46Ii4Pnml3gDv4kjBxCWR2uJ Diy0TA/cIt2jyQgJO907DUTjyBto3TUMzeiznTR9LBc10hqjX+Po6WMqpplraDtI SIFVaQEdjnqiV7pNQ9v/Xmxj6/hBJ0jYtRWBAsw4n/hbBCxecThlu9X6NAXWvokY hQSycKlbRoKP0Qkv6/OPJU5/2KkccmFUSt98bKg/dCx7KqcADX+DmvGyxV0Zw8XK +LonaNTFZUNsa4rLgNUOG+9aOyCvhw3Mug3FAAW7/9o+EcRNZxGhwy1G3DMM2kPU mo8mqt3K++OKU9CTq6hlfkzdYc66gTYnEcnMuT8VmernlwQtmuw= =er+w -----END PGP SIGNATURE----- ================================================ FILE: sig/v1.7rc2/jq-linux-mipsr6.asc ================================================ -----BEGIN PGP SIGNATURE----- iQIzBAABCAAdFiEEkwealRHvwLfWzb+1sNpg+0VLrxgFAmiLcnMACgkQsNpg+0VL rxgFww//fa9pBf9kvuxMrfPrxB3xHHwLxoVsQZBtj44wbNRdRGYyu7leYt8jT0a1 FUyZYZ/yqRAxhE3NRz3qSr9Y2W9Nz5YUYZBUIzCzvTyTTMAlQJKfxW9qBUV2U+df HQUOxou79d+oGMFscHodkOy2KxztwNAKPKRgHrg+CsHnn58IThiVJy7HNVAyoJZ+ CqWo7XrINpA7vy5jrpgy5f+JBg5Lgn/5G8Y0N9G6ZNJkJdQfmNlHeMYzG2ChXSD9 Yvo5QrPE21kDOCSmHgcem5DTgvfeK8ZRfNK0dyhRmtM0Ba3xk1WxldmU+k50DX1i gVozHMnyucke3VVpQNl+e+TKndu6rKgoRGPoFFRLwsYIy73upzmGdg6BHH4NZB45 wgjngXTWMrn8OmFEqsPZVWbBb11FPeA/vxzBgEYf8dtZ22yVwHyZOAjAVIWeL10q y6+SehTQut8TDxLc6u4EOkRH1upaWowfAY1evQbr/RbW9hhfE1AhOyDYmOwNlKcw 5lFGTBZ2DmhODkhxf8uBdIPYIUAAP268v7XESwUmEAGaO3+hrAF1KMBQZcroYXBJ B3G7qeW4Z3QRzkKYXa5jRa2xpH1fT1LRaYXiNULBBbowTVWlaURD+ntyxecayEkY uXXSxQsfErc/IfXaFizpimSukbAVg6YCiCox8p+WLfN+RtwuMKE= =5Atn -----END PGP SIGNATURE----- ================================================ FILE: sig/v1.7rc2/jq-linux-mipsr6el.asc ================================================ -----BEGIN PGP SIGNATURE----- iQIzBAABCAAdFiEEkwealRHvwLfWzb+1sNpg+0VLrxgFAmiLcnMACgkQsNpg+0VL rxhTtw/9EoBVXkrh3dpJd+6g83e2iYzTqdd4nxC7ZamuF49WJAPg89yz8HTlBKSg 7Notd1RmkfHV5IDda59sFZz93YlxKiT4D3+wlCgnpwBIO6e++899yGIwTssq3xMt 5MzhBvbFv4+47yNzouKHlEDxjoJ36VHt9dRJP8xSjO6PC43yFNVnlTvYoDof+2td XwmTDw+IeRJZcw0ak4E1cxlWmlU/jwl+bvhcMY+AN0ZQsHJuHIFus/2fSq3nF6UG FpqE6Gend6665z2+fpv+i2hyQZerSO+2Coj7CVGf+cWQkt8zymEAXPkff5KpxUAt cQZgzp7CBi0DhrDB4gOCFyYkFRxq5rITeBfvUbtnf4DEu6n96nuC6apupysZeY/p EnnbV1tMUUF/9FGbd6Ar1XkF2IQ6HfV5nl81ft2Y6BSE81kl4Wd2SVnTmZrMNAWo WotGikkyysTOixG3hu9q2tnU7v/jhryiVDRqegqkcNn3oRlx31BNbfNJ+j23azUX Pw0y9irQE0fFdEu69JFkTKSQECWX5tZWDFy4m5DLc0UJKBb5Tugbtq/iY7uU5iwN UZsvneGNaNe39Hst4OfCTrSLSH7NCEpxnh88TKtqGexlV/MzpxnR1h8wuVrwH0Y5 ddtam6lKb3PzP82d2ZR4aeLOF2OUbmgN6GunC2YdDOWL6o50Nmc= =9h7C -----END PGP SIGNATURE----- ================================================ FILE: sig/v1.7rc2/jq-linux-powerpc.asc ================================================ -----BEGIN PGP SIGNATURE----- iQIzBAABCAAdFiEEkwealRHvwLfWzb+1sNpg+0VLrxgFAmiLcnQACgkQsNpg+0VL rxgvQQ/+NcKAxuyiCDLXNN2t9fv1OwzYXDU/IsDVndfL9W4LN0RZljAS/vNHov3R jfnO5vmIkpbMOMZ/qebuF2FF9VZWVeveMJoTDweWRJ2+lcc8v3OPsR6BNL9Nw00N Ty+BaJkF5dj1MbhIG6enRmkvpx5JpYxFXvk9T/AaCUhQYpwyiKBlc+LZ2WyMgZ9f bNRmrPQA8g643/C/DuAgho953SW9V81iPno0EyvAfqA1EcCDZVZ0Zyhw2Cj9Nb3t 5ahp4hQlqocBSUUE5mWegnfLDTZBn7Of729MpwFJdQg0xWKrxvurawp6vM7CtUBg Do+kAbGU2wl+b6HwlCbLua1935g7+h+VOaIMY0ppGCV6CvaJt6ZrkF4DdTOB857P O+1HJ8EawdJKY9s1Zwy1/66QtQJm6Kaexjjms029Dw7bnFwtCPtMHwjePiBVR8K2 u3384gjuOwc1PKPWF643Wk355wElgXnizo35cY6Dz2ZoNLreVPefeca26t0lznRL 2lvtlz5YzTfIkhLAKSyi0zB1LUpwWvyeamyvg1CNf+W2nrTgRAzS5J0UQ4nlYEVO cPcXSnkWkZ2vnkLGLZUGtOdMZv+2n9Ey6ss6KwbdiOAncZkX6EQJGLiGqXkxumgE fJNPf77l7K/MTVDlfQWPeOSWH5KAeZq+kpsR4wFvIFTGxC1u6aA= =EJKt -----END PGP SIGNATURE----- ================================================ FILE: sig/v1.7rc2/jq-linux-ppc64el.asc ================================================ -----BEGIN PGP SIGNATURE----- iQIzBAABCAAdFiEEkwealRHvwLfWzb+1sNpg+0VLrxgFAmiLcnQACgkQsNpg+0VL rxhA0w/+Nz6Qwj4aZndpyYaE5sRmgpwmCUjCCycbvgh4JSWm5fwoN0EdWcu9i9zl FanjXZAbheRdR7zdt34gs0bYIGXM9NLJpD382zhY+woQC3oKjE0AO/crwjSt8sGI EqdOrLb6I7lgj2zZ5kmCPOMnM5buZ12NbfjlRsGXAu8bVfHgyTM1e20rUSK0ldFV EtIlvdi6dOZdTebBa3nniNSUzyX+csXW1fidX12k7Y/VTNO7pU+veGb6EfwrFR8n XmKH/zKT249SFMDCbcZs3VvuzfDJ+fBCjqsEK9AxCLsffkbLhJJqlAOKZaSE81g7 VwnwV5XvyocG67N7bVe5fA4b4eqBPM9WHpwv6WeqP8VCHkyLm3EJdmQhQOrcVDyF cA1nHlx8fw1VKTAV075l7bscEz6QT7RD3dpWqT96j72SqDxfzuLOBUT3zolNscHc 17lgr8j8/qs85GOBMtJRb3SlJZb+aLIVvEZtKvwYVhM9bdG8+7j3N2fKn4/U3Tj/ 6avdq2JeNfVeUpPGp9AmunkNfkM8+7tSK6VOY1BZwiitdjlFEdeJp//m5ERq1ul4 olxw2LIJcvEYzLozPRQCbeA+xgoJGBkwUgeF+o4YBafhi3qc8HtU0lWXCO6pa9b2 sXko60PeBy1fBzZSaO1t6nPsWsuIPPL2blLS2Sc3ShEC3/6Avc8= =nlSk -----END PGP SIGNATURE----- ================================================ FILE: sig/v1.7rc2/jq-linux-riscv64.asc ================================================ -----BEGIN PGP SIGNATURE----- iQIzBAABCAAdFiEEkwealRHvwLfWzb+1sNpg+0VLrxgFAmiLcnQACgkQsNpg+0VL rxjquQ//cBvlwCn6IH+wr7jehS2J4chhZ/vT5hW4VkDuBXG+LnyarfGmTtGOhCRx cyEO8tqOAH0tql8SedFGJ/uBRl1M3cX4iy3AFPwHTD4Sb7Qa+/lpfSPxJjiBeVRT 6KLEnI5eU8yJmpbGLIrJGtX/kFQDNxFcsw2htpzWCzjCWsba1LodD2scHlLTw/Wv RTebIeu+cZ5PH3ty8oA1baPZWH53WpZzDyNSETOSDMmyCwf6ZCuCi5iGIKftKc1a kmmM/o/dWivU2IOUpGOzteALIgbiE+mMx+7uars6a1joz4Kwaug4lUZq2lUlzLfx C3fKfZqjN53tclfSdl8MGrcC0gbSxPAHcU4X6pvHOKxEDQgzs8Sj2wikCq5TiHKW XI6noqqu+qu51er3yJomG8s06DBl8T86zggHo+XqqgFhk7x6X+h5z9Tl+2S/OOE/ OpQIH7e3lZQ6yFSd6nnfLhC0RQrlfs9RWHRT7xFR93acFnl5+9ZbvmDS6CnlhD48 XPXvlgOe7ZwQNUK3Hzz8YjiMEtnV19XxoIu7cpC37dde2uuMZrUyE5Zl7Or9xLUY lQrsEId1oE9Pf8Y+q4X7740Eiy3eebvaH8+6zMOek0ZxJbR9OA8QTHDhS4UsOJ4Z fFq/CkiY7GPYFaz6apIXd07ZM7MOxgeSUjJeJ1vpSaqMckhdqbg= =J8Yv -----END PGP SIGNATURE----- ================================================ FILE: sig/v1.7rc2/jq-linux-s390x.asc ================================================ -----BEGIN PGP SIGNATURE----- iQIzBAABCAAdFiEEkwealRHvwLfWzb+1sNpg+0VLrxgFAmiLcnQACgkQsNpg+0VL rxgmkQ//dlCQ9YptfiuHISrZydpXnpAC7xJNY+s5YBTef9Y1ae4JlTbqVjkRn9ml Q3hGpZ5fIGmSgikRt/ubvEHOW+RwevgJ+G8lYPRSBAAy5pe9fXrT5pyCjSuUkhsw ute7vTxkU8HQ4hetlb6o/4eCx6EH9nI9KiCxoYO5AjzsRmUdFtecV4CJivh00Dv2 isKDfjI0AApBqjtolTULxJ9wZ7hufyPXYiOBpp879JD/6G/KZPV5i2dt4p+l/BIV NX/dl9B+ZCMJlWDiwvfLb9Nr9dj3szCzmJ089JquU6gsrVzn/fFhJI7wYujVF+ng 1nuootH6nwuTGI4lWpwuBLrjRONJiUH312EVkIiQQQN35iE7k8oHtDdGn+/jd8Lr 2SH+BX+W31pb0iHKgyIvGYUlFJ19pGX93hzJA4YvoFaDvRN0dZy5zgPOATXh7JZf lZ3HW8h/ye3PFgGOuzUZ2469+BVajePkBPqQlXPMMe+modsbxUBe5Sz8ZYn4oor7 Dnpc64Uhgvi1kLSmL8ugLYY+1W+tvgKLAxzXQtMbIA4Ao9GTrbwMU+1RJMNQvnU4 auVhOrpZXbn4hGe5fn6xrtT89GSV6Wm6eU3vDI8UM7lzvTMBclFiDOPzN1dvEoEn Lj/R9A9yKWYmL+iHLXkSUQaBqt3C9abkYVdtOkyzbReqZR+2xo0= =HUKC -----END PGP SIGNATURE----- ================================================ FILE: sig/v1.7rc2/jq-macos-amd64.asc ================================================ -----BEGIN PGP SIGNATURE----- iQIzBAABCAAdFiEEkwealRHvwLfWzb+1sNpg+0VLrxgFAmiLcnQACgkQsNpg+0VL rxjajBAAwwnch7qxh7qvxRE1Xeqr5slfgRHsRkwg00Be7aVBxpX2hKdeUBHEtR0s ksHYAmM0mwVFMyCCPiC2tP4H4cAzgvThABDcv+fK3snhcEEgUn3LHtJ7x95IwBcv aPLnW9I+H+4n1dEGTL8iVEGVbTKC6ewsJIs+rNnbGXlwiY5R8xGIRcmwqDpMPchQ jPE+LoQ316ehMhWESFUjI+kSzBYO+UjJZd3PSKbc60oTkLpJq+6hVszFFBYWhlC/ Hufv+MWDYR1BngdTZIlIqi/vPF1Zlm4mDllIjlb0JATLAdV0u5YbrUpTj9Hvy7rf qXBwvwk5LuYIFgwVmJeSJUEcA3p6Ivg1211Fobo+3Pc1qyRZ9P3RH7AoU8upNIS/ GmJ+ESMw++QVhFdagjbNibIIsyL6Bm11VOq5rPkuzFztG0UgeCeSACN17ypQb4t1 2GAfck5ohrnuQHAYPFJv+HaHViHV1JOksFLWvYycXbb3dmg7UoKveG0YbZCLjbIB /k4hA/fzP+Noka0RAwH4w/yu4gpr1EbESKpxBKvS7je1R4SYmNCZZtcUkols6K98 SbzZyHabSLZUR1K7uuhe2OlKIgVFtPBhq0DBNeU2Pj/iVV2nkmR8GEYeqzUfnOsi pQUlWgR2R2vn3Nf5Jlc/tLPdUjbPYSccrdIKeuTcCmD/uPcpIfE= =PzAM -----END PGP SIGNATURE----- ================================================ FILE: sig/v1.7rc2/jq-macos-arm64.asc ================================================ -----BEGIN PGP SIGNATURE----- iQIzBAABCAAdFiEEkwealRHvwLfWzb+1sNpg+0VLrxgFAmiLcnQACgkQsNpg+0VL rxiD9g/5AQLqk9JWi3FFqdoTx6LI2W8FjKJoh9zky67pv03k2MpSGG6xjJbW3DGR DBAm3fjvgnIjeVYa3xJtIOX1Fdk4Xxg2nJyvqubeg0MnMtdjO1B2RPnndeIWHBAB xGIzLptp6Ws5rgOE3jWUTacwhrgyYA7iaSSRQ3GX+TRlKnec+b3RJVxVDZAlp+lG /54qSOEapkfqPYCWK8KHIYk4BIdXvmNIqHG+WpDMkKAo+5TYT0SUBBZQbrdBeWSV EoOmX5SLelTS2VZHMZmfLmb5/WMeWgcvMqahG4+bNzIGw+InNDBdS8ywBDldjlkT DbRckAUf0DckdpxvWvHLmYlUuT4oHkAVivEnKHZSig9VQ5a+46S4PuKzPzaXzFsp wG3ikTBZAAHw6OGHUwJtdAt4IrJw5NMzhvkUrXM7I9svKXdVh/GJx/7bh3KmwAVE Pe5Qg3w886vDFwRd9uXL3JtRU58WZ0x4Jp/vvtMLOnK+xFqeRnjwDZOt3WB6UUlT JN73zzE1vZJQIpms+RaXxxVOAw7YnE/S7B299ozGj0WawN46CK6UDgtSJlqIkeD+ TJHg+w6tQJyEnvWpo+hrL9azyzXuDHc8S2zjgb46iWAuG34GBHpTYlDO21qzTXg/ mNU2Kb6RAIG44pH3M3JSPWAeyrKJ6tNqEeI+IMTD560w/+uFNmo= =cu6S -----END PGP SIGNATURE----- ================================================ FILE: sig/v1.7rc2/jq-windows-amd64.exe.asc ================================================ -----BEGIN PGP SIGNATURE----- iQIzBAABCAAdFiEEkwealRHvwLfWzb+1sNpg+0VLrxgFAmiLcnQACgkQsNpg+0VL rxgbWA//V7FmvI3ufiZDhJUFk6ljkx2+Ufpz3ciH0U4FNMCNZLnaKSP6hDZxrKie ABmHkoNpHM/IHjM/uqNfYxEYMNi+k3YBgYCoQvXaEAAk1SRqGDAAmGDA1nuY4bRJ eUMMJ35uMcN0wc8nKqkpPNBprOucR617CYQ3r35jTujhhnNi4oJlLGQ4/oNK4o7i gnztrdcHNUo93pkyxXrzHmNp23iSp2cYVV/gXCT7LszvQXhrFPQGvbPf0lr9KDcV kDfwemPQEuBoahiy4ujQ1UFVs4POMi/NiZ0tLHz/t6yF0o97R1gEi2dRNnd+AQw0 hzbstzi4VaE+fkvQ9SmF7v61he3BP1PrjITQgdK9U7Ehcqh6a1x+p6LZgYQhDiSU cU3qvLUrgQlkVcVX92qhVusIg9IPW5dAF1oVECjNDCD/l7lPgvC01a8OmZ80kx0U WRqXJG6lPgHXS6BxZR2NQV9rwc8aY0faC2k0o8xQ4Z+UaESjadEhIxKnB8r57Hdd vnTCKkN7vOtN5Ey4oy6NpPaiSo7j2R/Wgz+1keoCvfEHpqu7plbE1HbqD/IYdMGJ Ozeoai2aSMcgtMrc50sc6rHHCOjgwoGmn0GbWRJTEsP82h9AnmNuPZ+5WVE2SpZc Ct5PwyT3S6wl8kDrzsofDl//dOjvsp86f3RaJ78QuooJQtQPfss= =d7yO -----END PGP SIGNATURE----- ================================================ FILE: sig/v1.7rc2/jq-windows-i386.exe.asc ================================================ -----BEGIN PGP SIGNATURE----- iQIzBAABCAAdFiEEkwealRHvwLfWzb+1sNpg+0VLrxgFAmiLcnQACgkQsNpg+0VL rxhvqA/9Fj3mM/e5QMBmZ8BSfc4ewuSFzVHsnqr45RhzOkZukyn2QyBaqJXha+/U HXKYZ34lW1zFGMCBIC/W59d9/u0LAfAvGO8qi81FodjsSEmnzBumk2igIzQR/khS p7+5Pop1JFEnv2g9DILhQhNCnuXbkwrwOq0NvaC5WhnKqsQpq0ntKfT5CvUwoaMh amLt9ed+A1e8Z43wioJ1ybpI/PoWEcMHkisK9bIOj+BUOoiiCT5T+fYid8uxVzTX kpWvS/neJjMF7yf5HPOlI7FI836fuyIZxEypXh+k8RP337gxLzyoLcyK0Dk0jvEK MSIWZ/x/L87YzgsIjKSE63FMqZT55ZKFxRtZnq/e2aIem5I3f6K6VXfnV56c2xlC YgAyJIyOF1IlJMKGZzSuFlnsKnbkyXjyTOozQMF8W9WBNOxbrL44zeUkrcS1do69 ld0WjIO0qrcXL2ASy7S7rfCmqYJTLZwGMGIBY+JlRG87xEDV9k4W6xVyTljXi+Ws S+9RxX9bCFklDstUNfZu7WOt5PYIUezjTKa3o2iFliJhR0j6UCpgEKMAeRGIHW1/ vJIJVwSSK9XZkii1sqAPmYTArkuLp9vVbESVu0J1BsOs5ov6NH8tbIMrqhM8+/HR ExjG67JnyP2IY0P+k0PvMu4YWSd2oW0YyNqSDmca1kCS08GJnRQ= =rvxh -----END PGP SIGNATURE----- ================================================ FILE: sig/v1.7rc2/sha256sum.txt ================================================ 94e908a84fda47e548355539553f6c2f038636ef6c1558dd0cb65a4d789f33e7 jq-1.7rc2.tar.gz 80b4cf6356a8182e57ccda9f2a357b846f6ddd65093ad201a590d8c2dee5dc92 jq-1.7rc2.zip f53b2c8533928c7866a3e6ed0e16401c323bcf77a761bc578114ce253c73e865 jq-linux-amd64 7a02f9d4c6fa890dc3bc87a591d1d5e8675e95efa65d098272006f200248808d jq-linux-arm64 9730f028999299a0644c5c77ce83686f78bb512f829e91046ac564692860eaad jq-linux-armel 743abf247ac5e2c133d75fc6e402cc49a3ae00d1cbad826974553b3812122831 jq-linux-armhf cc0f1cb7f64d5987f0de7d15472ea21db6b95c5cbc9ecccfc97f52e8b3e9c3d8 jq-linux-i386 16e61275535115d81e1a82c4d20d5c38b27df8a18d6cd7abe6fd4da370d6eb8e jq-linux-mips d07eee7484b0851bccf3b4a371679d2119cfd7624f55b2d3593c9d88bcedb353 jq-linux-mips64 4c01094443b5e1c026cb21e5dc9f22b02676d14a1755d1289317c09448040c73 jq-linux-mips64el f2ff6e66401c0eac4b04aaaaa4988f793b364652cf71bf7099315b60ee62259e jq-linux-mips64r6 9f2d14031282bc6f22ad117b16e2a1071b8e81c012cfdaa2caf4680b366575c9 jq-linux-mips64r6el df17797707ddea48cbdac681de2ae092482f79ea3a1bed5d979391b82573863d jq-linux-mipsel 63f8837e53fd67bd04df19d0cf68d02d90441421fef8f60d9999d4c1039855bf jq-linux-mipsr6 d6815e4b374ed6ae3552df148df1d42019acdfc7e032d02228a3e94893a7c2ad jq-linux-mipsr6el 74004dc56d5dc0f3537726d35da0f0c67c2b282fcecfa0fa56a9455fd703eb26 jq-linux-powerpc 9cf7089f0a2864b7a0e090e6bb7e23b8ff7bd4154fc63c44a327d1380b48c416 jq-linux-ppc64el 04ec542d7f1ab2aaa5ae9c3f3d49701f64ebcf7c03bd87091d607e794cf5234f jq-linux-riscv64 94ebf5b62a3be0f2606ca2dc837f3368044b467a26e609d53362fc79ab9ac197 jq-linux-s390x badfa24d3ff1c8e5570a31380b5b6349edbecb29785aebe4b051c60c6ff2c5ba jq-macos-amd64 9df6253fc8178f6fae8d30083cb926ff67cad12bed2bdff9ea6c06304f785061 jq-macos-arm64 8f39c01f1fdb9556b13b9c6625336b0bd34f45c037546772c2d8cdee3d43f73b jq-windows-amd64.exe cc2b4b741422eb98da1101a7b55b775f57aaa5f05e56bbadd28e7c70b3484e9d jq-windows-i386.exe ================================================ FILE: sig/v1.8.0/jq-1.8.0.tar.gz.asc ================================================ -----BEGIN PGP SIGNATURE----- iQIzBAABCAAdFiEEkwealRHvwLfWzb+1sNpg+0VLrxgFAmiLce8ACgkQsNpg+0VL rxjwVRAAxCmdBiPZvaAO9n7OCaIJqGJ5aeveTU5IlnYlY1Q0YZ7DT3KzxwEivQnO wNzg9CN2Z7Lu8OWlnLo/n0bVXuhf9Rv9KcwI5ZkBRhh6AJOmd3pXNgtFBtPFrL28 d0A+9x0u3HBhMdwPU3B7PXPFb6hR8djukojtZjn+eZZUZe9XjgnkDOEEloReg3M+ LBkhOa33OHpYTGJsNyzfhBIgUMzxc3rPUlpXeeLZqJfWkTA0f3nk8uRQWZy5zV1F 6kKKDDeffRKE9QcYtvDd2Rv7gUfhIvPZdRDFmphty2n64cT6433IcDELZ27hgoNq aR0tqosodwTcA2o4rir1Vo/LOd1rpDLJEmLMZ7qcUDCT/SnewAjACsPjcXU8B3dx xj9q4wTzHWt61Fd8oa5ysIFvP0eLe3pE7kOYjPlSOj4K2ydGvTQmMcF85hfNxo1B tLw1vlql5qaH2LXolGErTcIVEI0wVIg7JctqgNSnHBUF+PMShYXuZcRFGZRNRkoG 3ECsMPGtSL/TbIZa7+4Ee82mWAw3e2OG8bs8fwRWLeA3dU3dlggPMayKJ/gCPPUa kOxpdGYxisH9WDzSCtA2RjWtz47xMfVerrEICAgMz8sYyDwa/tyfgW1N3BM17QC8 hW2xXsyQKsf8DAxMiQtvnWxZsusDeM5gHibqiIdl7gfHMIqE+1o= =WcYK -----END PGP SIGNATURE----- ================================================ FILE: sig/v1.8.0/jq-1.8.0.zip.asc ================================================ -----BEGIN PGP SIGNATURE----- iQIzBAABCAAdFiEEkwealRHvwLfWzb+1sNpg+0VLrxgFAmiLce8ACgkQsNpg+0VL rxhE5w/+PH32q5aR6kP0JJqytPnGleIB3u/q4P8wAisaVuWbZRpmpLBBfNK0vG72 IXSf9KQ0Rn095MgPjMbkAMn4Hvd+cDL3zFcJ0Q5JuDv6Y7sLmdg0on1X7D27uJSE w8nzZYkvikWH3Nj2NFpcrY1VQup/2HCRm2amx6r+HlzUjt7oIDOf9q+cOChHWJ+h lKSRTaFWJe2R1Bae4UBrlYMvXmBitl8oFYCCdmUKWv9aVo1e3ksyFGv1a5KyZiLH c48BTD9B/GVs79b6thI6kL1t4bhCmtNUFeI1rxnc/HsAoNlDMayjLGaRaoLG8RS2 is33IJndyNbKArqJPZ2u4mACe4aN6j8mRw+NnKTZ0OQIOQkXfrkD6slyS2G1tsER tkwz7/ZFqDTRy1uontBSCikEuuxBFskxXo5zOUI5zKFL0lkOYKZm5aF4kMsO65+K WIZ4N6nflgK8Zj13Pjd7z30fK7CB95x+ZtYzzttyEDDOKw+gNG7Dj/eOqtjlo3ke IK2OkQyF3aVqysv8n3iOd++9nYxW4f+xn5bIFUu1b9KOffjiLYxZgAqJ0KHIWTuD qYY8xgVESdBibe8x/U4uw0jyyIT/H/rs+ftx6fr93vzGLBeJKKgtnHOnSipk5xr4 icX4I3xaRk/YdEP1cQ+Dh1mAaIIYWf8OUWw/5RHKTiFzzedHtxw= =538Q -----END PGP SIGNATURE----- ================================================ FILE: sig/v1.8.0/jq-linux-amd64.asc ================================================ -----BEGIN PGP SIGNATURE----- iQIzBAABCAAdFiEEkwealRHvwLfWzb+1sNpg+0VLrxgFAmiLce8ACgkQsNpg+0VL rxg2yg/9HiE/2PDVKJqNP3ZO5peGd6lMBoOonnMFKzcCVqZ0HOXfIYueSU4rtw5o WsCyI/L4wXJ/LP0TVAC/Tgd5aFcc8FDdY4Fn3BKfcSg+B3j6KTDuqnXmi9WnXUwD PaW8n8GTtnogNSEAma2CGsexHtgbg+5qmRxVGHAKtd6LSHa58molR3N7yVZxdYm3 JUKt0Pe6ixFCFeih3mlPYVQxV5vl/BHXkpK8FlBeiwIII4C+STlic/gHs4HqGXU1 dpUr3+LNxqlplCqv4hAYkPl94gN+cQP4bF7N2q95vZDVCZX1rPbD4A+J0MWtd55I qB8dOjmwmuTgNUqIUjhc9Apx34PneVowOJS5BIegBNe8BkLB7I7+Q8CaI6d+mCjO TU5+3N4vhXwuOgcamJkHqMsJ5ZJT3ksCFrm8qRfaJkJkoTzTAPNoCqu+AaXwE8LQ UdBMMSM8A4KUjsKaE1FmaPH3svQfz1xnVkrBI4C0McpUQZeniGvLCvxcNLwIN+25 a/kXBKjyADDebI6TipnNN5WFiEcoLdYqDPaxjlijsh0KOEx8URI2ukum84j8SgtN zFcdiBWifaOYAEyz6Djm5N6AuqJd+fCSLi3Hl+guwhOpMgQPQ0IL8cRY28R+164/ Lu/aidTOMb616nXby0e+laOlYS/oWSlXHgvja/niDk1NHRemk7E= =het+ -----END PGP SIGNATURE----- ================================================ FILE: sig/v1.8.0/jq-linux-arm64.asc ================================================ -----BEGIN PGP SIGNATURE----- iQIzBAABCAAdFiEEkwealRHvwLfWzb+1sNpg+0VLrxgFAmiLce8ACgkQsNpg+0VL rxhfyA/+OuVTUCDLb/ZrM+I31oq+r7eOlY77wBhvSqZ1Sl9ZuuugtqOyiKHAhp13 +/8iLZ+F+LGz8gDz0UzweDgV5NCF/Fzk6XBaoKqli/ZF34Jt+21jOgC3aUKdzGXe bFii2QEIGk0fEYaebz5TdHSoWxpvDBw/8He2Tx6tevFX/bQHJ+CfQikEx9++T4+l MjTHC3Rj3b2C7cU9LDzqCZnOvwXe2Qs+QUSVNVUDtb2Xi/wfVaAjgR/w7ar1fgYc Z+wSVMsCW1QnPY3MNLEbzAzYebEmIkI4SS91JgmTcNpZr4vYntpjy+IRehMiI+Rn utZljP2i+uYLS4LvgWh+IwOVq2ZW9NzJtRUIXMR/+iaf/jRzsZ47rwUFhjmqj51V 7sOHWHxYt4JmCTgILGYGBHauIw1aeCNjiEY/W65xi/oPTXtPmmMJd+CZhuoCz7F4 9zQn3ea5yMfczaZ92ZAOSzqdT+Ir1zTGD7cWXfXEdqScyEJDKCquDmL7TzWrbetg 8JAd+Xsb9viWAJ0b0+4B89zvwpZgekmH1VD25YsWCFq90U28IDB/5zmlG0KFSKcH Ry8u+/KWobkM1zJ64fQ6vTKLU5EOEtmFLPfmTZGwnwh1p2m64+waJ5Yc/2Zcq4To fqFmQeckqbLHFaoIh/AnOn13URAZmnDAv9+UHfQ+3E2WduIztRE= =Aqcr -----END PGP SIGNATURE----- ================================================ FILE: sig/v1.8.0/jq-linux-armel.asc ================================================ -----BEGIN PGP SIGNATURE----- iQIzBAABCAAdFiEEkwealRHvwLfWzb+1sNpg+0VLrxgFAmiLce8ACgkQsNpg+0VL rxgPtBAAt7r3+L7TgZwk0/jGHvCB6yMQf0DUrk5oytmVj8mfnW8CC/ZqrEpr/aHk WJYybq/DKZyrGXdNulVvzOLzYcmfKSM1qk/6vv5HJ6xTHlh6YiKbYnki7QYKY7M4 Q33xOL4Lu+wxXMN7rQbbujZKSHpu0LqwaNv3Q6fpJpXDsuvO+0qYdLVxZHTIMCSp 9+t0F47h7cKEMpSuPFpy5dEUJ4g4+m3qUBth7xcgdnp3JUuMrfj3JzSUIL3AbAt5 yiIGliqBBDaZA4Uqgu46Tkxz7gri5TuPYJKOCH1HUFE3/irjFfRG/IAux+PoauGe D7rxa+VjqoOCp9V1uFSfBO1xaaYfBiMwKkdGayw5TnQntr/Bh8//wNPSA871P+rk 5gOBp31MT1kSTMU7k1OiX9Idp4+FVUhVc72A+oGMSTeMu2NRZ9eVq+76pmEn56bn K+oKminsw4aVC9ThkR3Y2ZtlV232eNVBRJz3fKe5GQJ5x32HcUmemDczqKNtokZ/ lu4zYQIlTOyqOuvU78aEqyKO6koe+6y/BSLMAEw1yLMy0oTRItAJYDu8TdbMDztU 1YqrRkg7diBytjhsqFRExhIwMHN4ME2MNiokUSgqrs5h1+y5O5H7faEoEDK9heew WAnKiWCCj3upHjyDZBVjwyaTY8Zc50qWpy1VbPNCeN2p0Jw6YOo= =F9I6 -----END PGP SIGNATURE----- ================================================ FILE: sig/v1.8.0/jq-linux-armhf.asc ================================================ -----BEGIN PGP SIGNATURE----- iQIzBAABCAAdFiEEkwealRHvwLfWzb+1sNpg+0VLrxgFAmiLcfAACgkQsNpg+0VL rxjpixAAsE8+WOa3VN9G40OOdu6hVlNwD2lAPOPwS7GlKdkllHoNrw6rMduASYBl wIs9zk1HG4y/BI9Cp+F1r4w+ljzkjzkriRPn3nf8rJMiya8B2/TdSlJFIJ6UAp0s 6VaEPPq7WcZwQyn9v1MxxIC/UCx7xNsGL/iWbGLsiAOoYQjiFoWsds3Cr/IX2emi CxcQMKItM0Q71HgMFTbtUU+suywwIfpUQB9Zvwtb0//c47G6UgLXWXXD3gj2A8iZ r/Oj/FJZQYWXiox5qCmvQuOXV1TjJJQ/QxBbWr0DF2IvwMsOczJjM8uSW9WmqaA9 Tsz14jjQDOlu80WqpF0Vob2FAehyEFEfKQHDgQIoPGHbeM6mSUUjcD5uL9qoV7Yh AUyYokgoZFRi4bP/rW+qZVLpyHGBPeqv4MVdYNfMiOj6qoZIZkmwDj3hThisJzFU PZ7MoSh+LnsclMWuMJgSmSNMf8avA60/aAXZHzY3o/P8oLlGwYo3RkZVCdLYyDgn FGXLyW72sGFhrvwI19A2gu1umkzmLScYSSaTOmIyboq+ZA0yUGAZcDg7Fin/KP94 WGctyjwnMp9DuxVt/dxxAiRTKnxiTYJN8fOf/UT3zouXwSmmR1ExwkOX8TnA57lW Rf7xGaB5+KqDp6HNGYRfm3kdwF9fMo11xQ3SQItzAbwaPBStbIA= =cpPi -----END PGP SIGNATURE----- ================================================ FILE: sig/v1.8.0/jq-linux-i386.asc ================================================ -----BEGIN PGP SIGNATURE----- iQIzBAABCAAdFiEEkwealRHvwLfWzb+1sNpg+0VLrxgFAmiLcfAACgkQsNpg+0VL rxiSSw/9GXh9DdbiEp8au9petkagfN2I1/dOX8qgdP3i6dZ6RSQQoHSwyTQ+IRub JgLIzxtHe1koydVFtMt58xXobPyJ7lPCaNp1N7TNwO9Qek1to68jtehLY1qa7RJA vZyFHrY5MsPJfyDxkKnUuZ10p++LMEAqr6yRT7vJHUVJCDHXXOTkZ+L11bZceXBZ XT0onrl0QGuLLv9wWDO0EYumKABLGvdbsFj4ShreRiCzqJSgIt1Bpm2FD6185Jvg +l9scTs4JBFkSk4v31eu7qIi3xhP5DbMlCVeve22VMXwo4E7wkcpvcPJhazMD2Pd vgLFE+DYISQwaL78fKmStEyz+kkqAGpZ8t/LTsDgBkYVN45tImea7+fnYl6AuYDh jr+GD2U1Nzb82Pec/BpfoRz8PKPWl9H8YT2nY+ukR2HVCqwmCCDUYhTZPmE2yDki yRTp8cIZOyYc0jqtYVUZFArSoUPNNafeZS0EVsl5JR1yaCxCcjWSHbWmfDdakTBJ twsEu65kEYbwmF22eK8I+mR5FMIAc8YC4cPprI5IxTNhwZxaNWUt/UHG7VjCpg9q POE6TQK2WEu4knDUz7QV5A9lLwNTw0B7+193R/PyNQgsVuTXnqp7Ipz6VYYF47eT gIM0pRipqKl3ALn7PQn8AntP0jwvTMhLrC6po3bGmFJGHifz3sI= =VVWl -----END PGP SIGNATURE----- ================================================ FILE: sig/v1.8.0/jq-linux-mips.asc ================================================ -----BEGIN PGP SIGNATURE----- iQIzBAABCAAdFiEEkwealRHvwLfWzb+1sNpg+0VLrxgFAmiLcfAACgkQsNpg+0VL rxg1/g/+KpKpO+an3dPSfqbwEvyKo4cPP++YTv30RqeDDJqjPpkaAu4a2QC6lEOL W0ZI6/PbnmT1sTM1LrfQB9pMk7QYX49NkKNRZibwRowpinuTfIAFI3KJo8uusigL eziVW0C4lzeFMESYO/uT34RnSF/Lmn1sVfk94sLseQOlgz6dg73/wstsQDv2Ho0r av9q24+F945rmhN+Vz2UEVuzkipmiEo2ZbSfVJuHwlrYo57+y+3aTdehJp1qYV9p A7MWoHz8+5jMDjlLTWKa6RdUJgiYhgwj9Pv4L7MW/eoPnN7cS5KDQL3kR7Et4bbq 14r0/gSBY6F4qCxFopo49fCJ2gf1AF+65YFcvIaon4QXPv6YGUkHftRPDRoTFBDh s0WcvLqnYBWDoJ/Qk3amoU/ytTX6/gXT0QS4t/HBWyI8P+eQqIleABDbzFPqwyMA dQQfvMkL45xkNEdpoJrfj55cOo+W6tUADfMwvcDjvpBik5IY2bVdjDiJhq9/nu3O gIMQBfI3OTi8xLPKf25J+Wp5mrW9UXSaQ1+XhXCV9pb719UbcwOc7qSPQY+0KuZo MPuYWWAUVEDJOoWniFVThQDlP4VK+a6wSDyomhPwey/0o0TrtOmn1YvBv9NE0C6/ CG7UPj+jhOXkPodTjLVuBw1e9fAEB/elQ4RavFX3BlwUpdLV31s= =vkxu -----END PGP SIGNATURE----- ================================================ FILE: sig/v1.8.0/jq-linux-mips64.asc ================================================ -----BEGIN PGP SIGNATURE----- iQIzBAABCAAdFiEEkwealRHvwLfWzb+1sNpg+0VLrxgFAmiLcfAACgkQsNpg+0VL rxg9Nw//RPra2Jba4xF4yxQGIB2WHC4PETWDX5UNNnUcjXtzKw8ihQ5dmmNI8z5S n9NgAFZTIzJqGIbkahnasjgwcUEKH7HSPvjGONv6utAjpK4CX16qE8GRPsCw6X6e MTaapSlQZ0atM1jPHJ1yiMiH/U3mcFCTpRGotPb5NGjSniTw5mnUrXIa5FHXtJV3 /lm9RCjUq8mEwLJzueTbHNGM7OwihuoRdYUAPvK1yWkJMESBeNHGVHBg5zHt+HHo R7UdlSY53RDJN2m3yLFufOEoez3jcKDGO41LV401VGCEVx+hgAEJSt8xSqOWItCM 5MkDobecFSSWmH3kDB7KYqXC2F7Msh1n2YVvco+EJp6MD/W8JEhtoCBVNOdijD3w ivs2YzDz2l5oojSYntqBRnUTx2f37NPqCMF+7ZNPDlRDU6+BJcNTfAvRZ+B9AXBU v8iXuMdd7RENnwq8Vc1eV2GX/g3ZCfA/2v141uQqf93N3FmwRNbw6qb4QT2msohR d082pggp7NBJSdL/w2UM1NWigGp/TFWv9aqcEjlAowIK4xQcbX0qFaturlFoIZ90 xfwp0i+KR3c4FGD80sIvWW2CC0+1xYN7XJNAN67VffyHAoYw65ZY6wvmWorjoXnT 500jPF1jEAQZE3h1wYATBo2DZYJOZiyK1R4r2sr7ZRaBdgxk1xA= =tWDC -----END PGP SIGNATURE----- ================================================ FILE: sig/v1.8.0/jq-linux-mips64el.asc ================================================ -----BEGIN PGP SIGNATURE----- iQIzBAABCAAdFiEEkwealRHvwLfWzb+1sNpg+0VLrxgFAmiLcfAACgkQsNpg+0VL rxiL0Q/7B28UdzFSsYJwe5/s3Qs8UjYjujXVlDyDmprsGxi8wFFQXxTh1QxECueW KSJE4mZNXYOFRsyf0jOgMJ4/rN8FZqe4WyLzPOp1Y0gryQ8FPf64uik3jw44Vn3P DhU5XWV9Fo1BWvdzRmdYt+RbnNM2C0dr/p9ZQPia4sAyUeRzL9QJBpAJi094PJuH AzTcY63b1woOiyo4F5h5NRtyNl0ugzwRDXmZQubBvgeGLuE14rPNiJukNrEsoXmJ wBJNzrHDb1E0gCYi2a0VkWsE0quvZ/6Q8IZBOVtNGYTYzXQNZ5UIsbk963x8HBkk 2Nmoi3G3ALIKHHbWhZJlrgXLqRaulz8Z0fW8FbJFfHBQ85UXBosICsG+grVwQQ9e pgFDLEJct+tQrM6zyg1NqnZ+/aD9x1i6gRd9WFLtuPwLDou1FC+6Txex6OGbGO61 93Io9XAjg5OF9jqYVf4iLkesJB+NlSg1HVEcXdrqJak/slI9xfYU4ROA1/wDMkoE LGqnwywWYKYTC/6a/C1EVNUOtvDfE3/eNaOFu5fdG2LS37ywhRcRIhmnojzF5eFr ctPbgp0mEtKt88jdh7mEX2TWVMm97rOM8TFEwe5Wxr7ZWkEXqqNcqTnjfZQ8WWqK Z0PtDSsM55jkL5aVUKe5f9RMFnvQ9gvU/M+TweO1rsR8XscXX6M= =L2xy -----END PGP SIGNATURE----- ================================================ FILE: sig/v1.8.0/jq-linux-mips64r6.asc ================================================ -----BEGIN PGP SIGNATURE----- iQIzBAABCAAdFiEEkwealRHvwLfWzb+1sNpg+0VLrxgFAmiLcfAACgkQsNpg+0VL rxiyoRAAzfeEQ8Y4hi5kmdUAUGdcyH4Lli03bHffZgEvYjcUiqLJObs4nzrXDlfe JRPftNUSuDRjwN6u2cJXlJ4lYd81D5SnigsUE8hs5gQam7qIy6z8k+wWbZxPF9nP eXGtIsIzwL8atS14mLNr3x6OliQga6US2Kez6Cm7Nz5h3fGMI1MFcM6DqJl6tdkR pfzjR/lXUM2yXLvHjXFRZcxTxRcagAEju4irSWVlH3VimYR+ekJqaVS+u3OJ1y1x 5U1Nfpyz84Qr2I9TBaM6wyfb7YqYImSud4kuSlsgmIlJOrdp1cBK9oEazrKvNu1M A11QYCEMJRcQ6sdiuznFXH5XuoZEog2ggwP7nST2KTS31Jc4QpldEQX+PQVXtRy0 afRAtd2I1cTXS7n12PY6eEAtKs5AdEqGp7a/SAKhbJqEmR7Qlg3hHFarmVi2NhW7 r2TDg42hq6nwGHA4/2/GdccEbFbCOur0nMkXPd1ziXs0vT4pmD4kuHE8GN2S9fbA DtdB0Sl3TG5PRNb3BVXrPFN5A4wsYiIFuhHpgY5zWKwdCOuyQKn2/56sYAYkGjV1 DGRICLhzgqt35xE9RVhShwsAuGNMAID1a2pXls0Vj1QwtN2slpk+WJe74cJsQ6UW VG5kt87gjYWsp4eXehHmTnV3ganVlwi2K6/jSoPU/tvzv0c8F1Q= =N1xr -----END PGP SIGNATURE----- ================================================ FILE: sig/v1.8.0/jq-linux-mips64r6el.asc ================================================ -----BEGIN PGP SIGNATURE----- iQIzBAABCAAdFiEEkwealRHvwLfWzb+1sNpg+0VLrxgFAmiLcfAACgkQsNpg+0VL rxhc5Q//ZsnuolGGYfGqPSqkaPRBgjXvJ7EpwCiSFiOv0xTYTtxd8mH4gCzQHEWl frml7RLj9RwR4bAfGyiSFOQZ0p4K964x/Vbkr/UMep4JycdtqUgHkhRjZPNu/0lJ CZnLCU3H8wxq2muCOwMppEMnusXvYKDqixYJkVDj9kNupWN73/vqn85nZj22Fv0V B2b+fVP290/56wVUgGCuoB3D8T+f4FRGosF4AtuhewhFQ5jb0mvouEP8tjEd6k+2 oKUjJuewU18AkNHn1oZVLgyFaZGX10zVvjARHM6Nz0fY1eIqiS4WrLH44aDPd1ca 8+B/TN9cGnUqFnPAlGCCddgPjDW1G+JWTb2yaxLE8jSQB8uutADe5RCHxsgtraIT XPbppI+UZMtucpq2elF958lcp0CLGeGkd25Go5NMzXCd1NJxoOeG5faSddrTk7Mv vKMow1s7zTqP2QfgSuPyY7DKzrD2YSnUlY1hPHR+Fg5itxeri9CNQtaXFbuYk3+5 DAuoUV9CrmZsggszCtVUQogeF6deRlBFGxnWV1LgZu8lEAMRt1ef4otIpFDWcIe1 kHrmTl65DjXK56MFrwhihqbrW9gyok2qhRHwAbpsfDIuBXj6OeOxw3CpukjXj6yc khd889+n4jy+Oo2JnHLoQUvS7AEVP1vIT5hU+D7PcXbUzSnOrmY= =wiBQ -----END PGP SIGNATURE----- ================================================ FILE: sig/v1.8.0/jq-linux-mipsel.asc ================================================ -----BEGIN PGP SIGNATURE----- iQIzBAABCAAdFiEEkwealRHvwLfWzb+1sNpg+0VLrxgFAmiLcfAACgkQsNpg+0VL rxgEDw/8CI4xLrjp+jIp0B2AX5fD/n01Py7luGw31eCB1xo5zRV7Wbzr6u7JGMYX XNmFztdMiBz7WxDARTgXn2/elxxanTl55okUJuZLC0voUzOEdrXFgBqRHRn+QXKn j2XuXKwZrmimauQYwi7PLj3hIpsZ1TyRTM9sqRCdshibmkWJsUFQzvMnMQQ/SWJa fPBczzaeowUSXYswQkehPZLwvVOGSKkAHR/6vfHSUtD64oUHa/F2zunPwXQPbQjk fqZD+oNWEG2ibcF993P1Vi3YNglzSjc+rvNBBo25e1gmurcIOYZ23ilGrpRaGpGq NrRRYY80wBDBmVTfbsdWrMuAesj65GuoTnpL4ipZkmV76I5thFDLtx3OlNzmPadE D7X2C8BIpBDlTVqz4prlHpny+BvlAyHwRUwaOWVn0YxeAYzkKmeyAQbF6pdv6G8L 8TmRbOoT3fNvDk1ZZ2LDprsw8vetHVDau+J8vae2Qbysll8ijGb8cXIkRovgecBR 80rjDPuzZGhR5LrGCAaQ8lg+2ZoEp1Z72AwQuULHOlV8AmqsQGneVz/RZxEl6HaY BGYF1iCEgWOY+ngPCB6WxceXNBREh+RS3HNdwqGG7zBfcM2wBOcMyGtaYgt70Qp6 3M6ztq7KzrGASBz18OnitXNIqyBKB4B12Df5YZHDOMZ9TpLSB+Q= =rang -----END PGP SIGNATURE----- ================================================ FILE: sig/v1.8.0/jq-linux-mipsr6.asc ================================================ -----BEGIN PGP SIGNATURE----- iQIzBAABCAAdFiEEkwealRHvwLfWzb+1sNpg+0VLrxgFAmiLcfAACgkQsNpg+0VL rxjvjBAAyVa/mL7FB23pNGYIHNYlxjznlgPOM3fNmdakMoC0GIL9cGlnw8d5nynh CXmPnozscf2SNmxuIcakkKcEJ9wR+2Rnyf3QiMPDY+qdrAsJoEqBNVfzn8xk5VAg B6qE8Jc4DxGXjdFkNrA/DP5ZhncanBhv3TloXzqURDDplzAEA7VMffevkm8YwiCo N9Ov1BAG8S50JfEaNtIeq8I7a9apvte3DIFh/UitGHM0t07i9Rp/zR3BWDC4+srX qKEUGbgP8boi302wX/qT+g6m+6mQwTCjIlGzf9Ff6XunHnSE2vTHwXNf6W0Loj50 UQyPP4wc0hHcEn1TfLEK3HPVEP30zG5PbqKR3agGxq+m9+02Yi5KDxaZUClv76Ud xIFfvCeWHm0vPWoRYrJeXB3uoiYB/6PzT3yPxmR2bObZdk5+PA0J/WKDoSig0tzv DwzSwMtTqUQiAaQNpr3LLIEljzMypT9QGif75wtYJpF2vqrBSiJBMTv5CXhwzkw5 1FM56f/FmPAxjQcNzm3UuGvL2KIY5FhMGibPPV8Elw2+OxOHTsp+fBc1VufAWWDv xqkAojOgiRqMLx405yn25g0OPYD8lORTQ50RSigvNpCstqRL0ePpmkh0692C0dxq HYTgbOFOYaWeDU9RHAhYI+JUX4pNApmZN2BVC/PG4ywEq3GJGhY= =aIez -----END PGP SIGNATURE----- ================================================ FILE: sig/v1.8.0/jq-linux-mipsr6el.asc ================================================ -----BEGIN PGP SIGNATURE----- iQIzBAABCAAdFiEEkwealRHvwLfWzb+1sNpg+0VLrxgFAmiLcfEACgkQsNpg+0VL rxj15A/8C/s+IKuPzxpIBAwJCOrItbE3nRUyBXBkudhol2o9iHu/Ww/VMB+I5pOU fRHcYTtpE9R66TtEYqh7C6XXtO/HjKpxlT7nMvzBS8FOgQ83RS4o3vq2Vbnz9jbq G06eEM8Hj90IWaujnfWvs3dXHthgCyOYQy06+/0H8Q1neJ8O+v8DebUMnsP4GTpY N89HLoCkMlllkb1dof66IRhVMdSn65a5BhObk5nI8qtncrX5rmW1Da/MRQ4epNos +VpbK1E8gT80WzIyAyFTqhZxcfy+5ObXWSRCdEZmfFeW1GP1swQmccVvQhz3RPB5 ONgTP0B1ZM1B2f06b5RlKFuNXshseJ4gjFv1WoAYrMiIumBC3225H6zSFH4076Nd oO6gkOnNqPc6Qkaxr7WgDcroZ0PuF8z6tqgWTMu1yxSpoEY6tYdzTPySExaAY/xZ w6WPCwEISHcXobkO+vP3iG6GdnojXfwhhRRo0NzWCbxd7bjvOWwt2Q2m2AAbLc2n zl6CRb5l0VM0JMKrV1PPp88+ZCBB5YA0FhyjiJ1BlyhgSAwiNZ/TSdGgiPCj71Pj NlkSNzLU/0X2QifW1r2x1kOatiLegAOkB39a/ddVfRsLugFRh/TjZF7931NNwVSR 0VZqZqR4Tidcz9uEV3ISPBpx17zjw7If8aBDvcLXuInZEg3mYtQ= =P9gB -----END PGP SIGNATURE----- ================================================ FILE: sig/v1.8.0/jq-linux-powerpc.asc ================================================ -----BEGIN PGP SIGNATURE----- iQIzBAABCAAdFiEEkwealRHvwLfWzb+1sNpg+0VLrxgFAmiLcfEACgkQsNpg+0VL rxgD5RAArDShagUVgzAo98KfFoBVn6fiESc6fjiiF5uXRd947J7apCpC/HbhxG8z o1K/rKHWY41VfGixaBRv1leAXPgYFuv0jhCuvv6kTELhD3VsG4BYBNi2lzR/OP/X V1sKYw5KioxOdHyXoCy3g0nwPvN9oUhRSirvy8XfnP5xaALYbs32WA1C85dnUfcq 9ablDsoqxUwz0tFn9qYFJ2SwLxBx8GlB2WZhj6Qw+LkL0YAjetdw+T1OgkjUTc2z CnwCuVCz1RgNuBPlx8pUlxlZBT97GQlfQNwmwtKgc3dt7O7DJ4lyYZdZFnUok3p3 Af/VsEaNsyerRaY1kUnTsKF1II6ISmjxdEcKhk52SCDpMFVm9hY+/kgfjuHJDaP8 6dFl86tuUCgK92GtJlOynG5cJfRnS1YABP07704f7wNzO7rUlW+WvnNKp1ro4qem cj3A9+JcRYxSuJ36kkMD1AJ6cQEN9G/XE1IpgrwUHmuEWwVghz81u713YLHp1hWE +o8V0OyoFlWHfwmefOJYywBtqsPhAbd6fuxujPhYlroVaEOiy23i1zjFRd/HRPpe WSDaf09NIAdkKvS+wsWNSo5SabPCrMf2InqN+PX0xAx0Q+5FEnaoZJsxmbWQtbRN XKzzJaJ7DUOSMJYTLrgAHePA5QUsJotxtuiZhfY4FwW0EsQHvhU= =OSJh -----END PGP SIGNATURE----- ================================================ FILE: sig/v1.8.0/jq-linux-ppc64el.asc ================================================ -----BEGIN PGP SIGNATURE----- iQIzBAABCAAdFiEEkwealRHvwLfWzb+1sNpg+0VLrxgFAmiLcfEACgkQsNpg+0VL rxjgag/9HTPiS62srTVR1kt0pINwNrp8yajy17xOXByj8JVI1k7GW622tsjjLGrq eZLTqcGPZAV8JCS/+yPW9dncfD/IKAs2eSr1De/n0TqKcWBZTh9S6gi+IlfhtZPB imnRsTgGzGwUvi3o8Rti5ifoyRxXFLyyTRlYXSt/N38uYmK1NeXZCEWxv1lrCnKN Zt6rJqUJdCy4zwCZsyzQFV9Jk71fXBb4Fewp4OIv6Hfawacv24GKULm+fVQmJfzA Y1Yhucgq3UuEjFwDJrIazBnHfi1Ax+pmBJXAqlhaq+ccs322ZXJfdk7VrQ9OvVmk o829J7Csauzt2dI+a1SYqT5HFk0+dioQgh2GHafFGEKj9xg14blMQzHBI+UdRVKp BANtMyd1UBabkg9rYu6B0Ez891bEw3zrxMPox/5ThVbm9v7GyPJFtW38CdUwT3Jw CcwPP4KrUqyFMleRhKt/c93zCdNgu6svTeNB8cSAs8ND9Q7WnUcn+PlrQNb0Mhmt gTjhfwd51JI6F23W+OBP/SjuBrO4m9JPR11ZIgc/QLPMLYLuiUlMwzRUh6RE+Co4 VOTZSIPBvzc7sAT7Pziq0x9gwnlOBmleksy3mw70ghDzmzadSsy0l7tFZFch/x0O AzQrNff78gny46JE8kWh+GIeYZvuGgoy9PhDdIX0dynBoH5t2gA= =9bYZ -----END PGP SIGNATURE----- ================================================ FILE: sig/v1.8.0/jq-linux-riscv64.asc ================================================ -----BEGIN PGP SIGNATURE----- iQIzBAABCAAdFiEEkwealRHvwLfWzb+1sNpg+0VLrxgFAmiLcfEACgkQsNpg+0VL rxjlFBAApB7lCspLLD3bEVs1K1LzqzTCOtZu4qu7eaRRU6p07cOw2CaJ/pGul6En kQvQFxHRpUUekDrUNE92OvmWWyj4yskD90S85xxZpwPljO9p1CzkRjQnRtOI/Vx/ NAYJg+mufxSYH7D8I3TLZkB20yd0UCTvZGa+2o06nUcyI9RhiWupuFewllrxwQAu VbEvQIoVbxnbVlAnQHdyBA/nSpvYcTEB6/eK8dFL0nxTHDwRmwyqBz8UrKSKn6ZV tXf4oLLQa0aotuvFLkuHDD9fBY0OFclWMJdRqXd/S+W5v6IiFpthy6QlG+4FGkrZ fv6yXRpeaHXEVwK7m/6HOay6bnPdMJ/zFbUHK6PausNGDv+hbR33TOXrhaEBtutZ i6TMZUIGClhTpoSdttSOavChQrpMRwxvsvIYj8gdzmBEfy7y92/eEU3w57sTMS7n RqCpCqLCOoBa8L37+wN/Pe78Bhw5gJo9XKgrmFb8juN43h6Z9KA4Frx0UUPieTkk Qp/qeMrzD5t51C+Pdym+pZvJ4dx18ebvi3ueENV85ZyJJUAUVR3E54dYZ1l04dCf jNYMzy6KhexkvcddzUp2FeSzBOd2YoqwTiz42QNg20knNYWRQd1mkZJ82LKCzQXV mhfm5Qis24zeL6e5GQOhgwekptMi528NVyZhbG1RQb4Hvk66VtI= =tVIV -----END PGP SIGNATURE----- ================================================ FILE: sig/v1.8.0/jq-linux-s390x.asc ================================================ -----BEGIN PGP SIGNATURE----- iQIzBAABCAAdFiEEkwealRHvwLfWzb+1sNpg+0VLrxgFAmiLcfEACgkQsNpg+0VL rxjhYA//YJYQhxZVtc2NryRyrxzAOVLOIiX47Z5EiGbs58D/NInO0c0yEzYcoZ5G Per8m9TDigIgk0YDx7ivAOFHCoNejoP83OsaD6YpyowjjQ64mxr/LDqe/s34xC9X E4m2706+h2YViDL2IZESsPKt9puhdwOKOYzCCg7LfvzfJjgRtBe3FP8QgK6SeG/J qtUkG+c+Oe+GOWufNuzeQO/7H7RWtWZi2jTwVbny281jVKAK4gw5hI1R9srrKwkx Q6p8swVVcP3YHnbnWY/XNkXHHElX3l/R6GE0Hm3TPRyCSqCzVReFuOXIV7OYepcB nxxDflYjlA3S5KfGO0x7/hJdIxwxwQ8dE/yQTzPZEuut5LpkW9V0jSahNamA9g7Y bx6IOh1VUXc3RYxhYJ3+ivv4IxFUpjttYkxzvkVxhJl2QFj/EvHH5jnW4IE8C/7d qE2v0/SPpw1sXAkcte9n4k7OK1spPNO0N1W9sNgLYX+iWp7PGL0vi9oMcj3pizs5 HNiuMzE74Afna7yrTlJxXT8L4PHzqCpoOmK43k+SIEgIbAwVRT66kuZMZm9YGsWA 7z5u45n3gULBGocPaYmfslNbprVclmwAHYk31I2eRKgJ1CsKG6jR4yIoZEUMCDBF EcHRhEm3qe3BJXmyRYuWFrlIvACvyUnoiYaguuo1epjZAzy6R7A= =dWjW -----END PGP SIGNATURE----- ================================================ FILE: sig/v1.8.0/jq-linux64.asc ================================================ -----BEGIN PGP SIGNATURE----- iQIzBAABCAAdFiEEkwealRHvwLfWzb+1sNpg+0VLrxgFAmiLcfEACgkQsNpg+0VL rxgcYA/+K4ad2Qp8AaMD2vvMxydSFfjEujTzMOOdnbVI9Mzmu5D03HAKZdrwaZ8d rJh91tkTHjZ/KmfTrS2Pdog8jzFYj+3L2tYm5HlFuMeYtufTl0eVP1M2Bk00d9BV jVikqq4e/qTeyTmXgfhIZeKc42dgNPRovp4AXnEJ63EnW9J8mrHdFvIb823zcjm1 PUMJ6yYWwGxaKIk81twheobCYEn19PvrpmTjejpHVQp1eHyt8FV0oVIkX/OSoD5D zlGFSicqmJB1hARd7cp/5prUEX2z9NWu2sSJudVwEX7ypQ5d2sRAspjdVEdtdtX2 QRthDyTrXBfn/pTBZnN75b9wrI1qDqkGCIIOo+ldOeqrK3pd1GuOuD5YDG9dgZNB Sozf22UPwY/4awNbfgWVJBDtJ5e3IJz0Ysu6oknUBjBcusYz/cHxgDvQmhfIS33Q 1hnhyDKbMTiru0Wc1zbDRZmX34sLnLcJe2gLh8wD6gUE869Vyjlg/QowcSQctPJB 28KMDgc5S+KJRa82RSESLG9nUMs5jUMaB9MmtnE7lCiDEoJxl14lapyvp9qPRV96 mAICpWGXgNt8VQKwFRWsEPzyWjM4r6Rtd6t+MHedBQ+an9pEWao14nSYgzI+PGDn tySSIx2UIYVSh2sdIZ1jt51vIh3VWkaWq3b/kuKAsTorGSCQFSI= =whh+ -----END PGP SIGNATURE----- ================================================ FILE: sig/v1.8.0/jq-macos-amd64.asc ================================================ -----BEGIN PGP SIGNATURE----- iQIzBAABCAAdFiEEkwealRHvwLfWzb+1sNpg+0VLrxgFAmiLcfEACgkQsNpg+0VL rxgJABAAhpNMBJBZOrmfPrl0mR2kaiWCgvmP7dSq+zeUPDpMsvyQqd7/OzPEJwTO lN1hYerRHfKY4IplhDa3qmroUftPh97LVVLvFtbEkd40v2TQGKN+8YBbF1LWV16X vpBIc19K36dy0QmeYITzHzhKoJLD/kkYo6S0hXdQE7mooHwVOSJ5xibRG5TQdcku PyJewSkmAE5Omnz8VRP+fENyDcPoif+i7lqTQm1/FqZz2We4ZtNRbzSLM88wWRQD MjqTjBO118svmEXx7XICahQP4FhJrAyq2rvylI5J+C2ZT2E9qoVVPawUSmewfxde iYHdl3WT3xIDpZxpyanKALFt4+6WW63cHsQQ8BSEAnJAfxwBLfILuU9QHchoKzTP gGU1qW4NPCuUoGYLBqAdLc6MkJ9NmQbsIpOfCLOOVo9GYuwwVHxO0Eoy3YSuCqrt iGbv6s2xmI/ISkb38LfoNezrXZYDDDR1qG/+6oBSEbra3Y0uw5+sGw2QIo+BP1KX 141ZeD8O19I1FUjimXapay3lVMoLOCsVlW6X95THabi3RWb9hEHYCBqi7BKmRk64 2hwPCTVNiiScLSoL59sKaeeI5oPO0woTP497KE4vOZwABkwTxTuR7gc5v0OGvuxj zFKjliTnugecMTXnSOeAVoxdswUrTAtKc0ZA112+3BGWp8G9Y+0= =Nx1M -----END PGP SIGNATURE----- ================================================ FILE: sig/v1.8.0/jq-macos-arm64.asc ================================================ -----BEGIN PGP SIGNATURE----- iQIzBAABCAAdFiEEkwealRHvwLfWzb+1sNpg+0VLrxgFAmiLcfEACgkQsNpg+0VL rxjlIA/9EmPrz3O/Jri3bIqV2mRHUrq49eLHh5+2n9x2nKBXOvp6xrqBkxHjPScY y8HgN1/ZD5q6nVxa0IWIRSHJGxEXerJEiglxfdhwMZkE679PCIzmp5F4LQmfdzMg WrzFdlyp6JCBB2e2ojmu2Rxf8i548Q9eEqbwHkU8VdtsWFYvY3/KfJM4ilfT5+H/ jFg3ghhKlpFpzLXuI5MmGhEuwb8Xz8QT3YdICuVHrVCCsFsC4r7xFN333uDM5vCV da3G5vQjvmhT6i7OhbMnFBOvgshj7dZU1NAFM0wJDI0WoxRhdA7yFlHSzfE6IgMS hmMojLRBXai/sqeGa1My7Os6Hul/v4H2rQfVacj23IGfWcZD+dSpCMaviXg44NWj 1VZlkVgoxjmHubLD+4GApYF+IuE9iwyby28ya0OZ8YHXKZWGeCMNJxCoWrZyduJz Vg5YKmsaOvgtFiA04HnCzcZim0n69rDlgTzg2JefkNdramPEzlM+ZCAcmdJj99ki ZU1WXnafWAvXdL0MXHctEIbLQumIYBV9ye0ysoi7tShnn1JMVz983FWMtr2K0DyA x/Gx2LreOkSXWdSntbqlYIUBKaXM4ksknFWg8ux4neMACbcCU0P8IvoeOR4f6OT7 HBe02l7Z74D4I5t6EpIm7jp6TJgO2wASj7hC7nLDnPxY+Y+C4T8= =kdP7 -----END PGP SIGNATURE----- ================================================ FILE: sig/v1.8.0/jq-osx-amd64.asc ================================================ -----BEGIN PGP SIGNATURE----- iQIzBAABCAAdFiEEkwealRHvwLfWzb+1sNpg+0VLrxgFAmiLcfIACgkQsNpg+0VL rxizug//R1i+HdDixIe+AV6TQcGAlH5FTNy9/vLo3HeE7kqdgoIJ0+jbxKEMW+92 L37HDae6C5/OAnfdQXmlXIOLkeXuDl+CfAcJf/0DWwZB66o02q3veIWF0NeS2lts L0Sm4ULfM7pYqj7hcb3nUiHI2Pgk5hAoN8FqdUn4kvz2oGh76YHJ2pjoTUlGOQdR Nh0ekvP13PFsA/UfM6szRkeD2Sr5SwtpaXGJ/CwZKKfQ+qds74n9Hm2QuxQkYktl W2GKbEDgX23Ka/peFpIQJw0OzMhnDhYcqnAB3z+680AQ5XOZ56QvtLTNrfdu5l0O TFYbkEOzfCZxSKcH2HLY7paORVtC2THkmdvT/4Zs1NGsgstTmfoYgQbz6M9MSEU8 FZzcELrRrbb8eLnKiCttgqPBuVB2sBHCZJVmlez/OkEUGPFnoNdoahjnuzwlN8Ox IQNR5tJnOSw9WdPf15/MV84JzzcZwXzeiSkeNQ/iXk5yLpr0MgKQEAgtEyzw1RGb 8SYvFRVNaMr2OTaVsj9alPLMkrXksJu72CK7IoUdzUkkxnpvkkUxjc42GXKzvuH8 v8zgeofSBKUj+8HQH1UBC1dOt+rcFNsOw+E6YGZRU9tbO8TyX0FA2UVTnkl2nzrI 4I65N8rI6dvNdp7V2CzIZ/HqnqTy5Q17YKB31BJLgMdFh/kJUt4= =FylY -----END PGP SIGNATURE----- ================================================ FILE: sig/v1.8.0/jq-win64.exe.asc ================================================ -----BEGIN PGP SIGNATURE----- iQIzBAABCAAdFiEEkwealRHvwLfWzb+1sNpg+0VLrxgFAmiLcfIACgkQsNpg+0VL rxhfRw//f6a8sHFuzIzycOAWm9bI8bRBtuIWIw/8Sivf7tabVmPiIpV7ACeAMo1R YK52y1H2sjPtiSATvltDTcq2EMoamUVh3uMrod1pjm8uBoO+JZsqwsfNEhuiLXcw f9NPI79XOhulQBA00KOq/X2QkVS/XDQtMSNVn+Y7ASbPznCpKY0TBzi51oE5/ytk l1ZauxdukMS1LHSl82dT4qtVOs7+7NPL0N/EII3JW/rQk4L8lGxB2RU7iIhWkSH5 sf8Qd7diBdad/C6EM972DdsaKwBW0XaPRgqr32CusbLwyqPYHRsT+fvXPcKt3plY A9B/RV+VfHrUVXNj2+Ka9BLmSJ12JsNdYFFA/I/F5qloR25yI4eSm4xOHLjFZ7EY BxQlHqlb5yOhNpM+w4Zatl3PkCVOF30A9ODc4NLU0BVVVKa1ojEWYadsAzioMX6X KxNCWeHkeRyZ2Tdvej1T5ZmzDVKJ8PA71EeRa/ZuZKqJOXSP5p7XxomjJQ+z16dW vd54+tFOTA25LHlIKfkXfJ+WXggOMBOhnNmR6hGwd7RWeyl806Q3jreWwVjfV6Gr tFr7JtaxrgjENcV3fQ33LLbtDiu8hrY1XJ+MoLNK+id3wmPJL8uigX3szpF1sO4x +GB3Jzgs/5kYOVQCr/CVXf8G+cueDkVGWdXTdpmv5ZNlsQdOrqo= =SEif -----END PGP SIGNATURE----- ================================================ FILE: sig/v1.8.0/jq-windows-amd64.exe.asc ================================================ -----BEGIN PGP SIGNATURE----- iQIzBAABCAAdFiEEkwealRHvwLfWzb+1sNpg+0VLrxgFAmiLcfIACgkQsNpg+0VL rxhfRw//f6a8sHFuzIzycOAWm9bI8bRBtuIWIw/8Sivf7tabVmPiIpV7ACeAMo1R YK52y1H2sjPtiSATvltDTcq2EMoamUVh3uMrod1pjm8uBoO+JZsqwsfNEhuiLXcw f9NPI79XOhulQBA00KOq/X2QkVS/XDQtMSNVn+Y7ASbPznCpKY0TBzi51oE5/ytk l1ZauxdukMS1LHSl82dT4qtVOs7+7NPL0N/EII3JW/rQk4L8lGxB2RU7iIhWkSH5 sf8Qd7diBdad/C6EM972DdsaKwBW0XaPRgqr32CusbLwyqPYHRsT+fvXPcKt3plY A9B/RV+VfHrUVXNj2+Ka9BLmSJ12JsNdYFFA/I/F5qloR25yI4eSm4xOHLjFZ7EY BxQlHqlb5yOhNpM+w4Zatl3PkCVOF30A9ODc4NLU0BVVVKa1ojEWYadsAzioMX6X KxNCWeHkeRyZ2Tdvej1T5ZmzDVKJ8PA71EeRa/ZuZKqJOXSP5p7XxomjJQ+z16dW vd54+tFOTA25LHlIKfkXfJ+WXggOMBOhnNmR6hGwd7RWeyl806Q3jreWwVjfV6Gr tFr7JtaxrgjENcV3fQ33LLbtDiu8hrY1XJ+MoLNK+id3wmPJL8uigX3szpF1sO4x +GB3Jzgs/5kYOVQCr/CVXf8G+cueDkVGWdXTdpmv5ZNlsQdOrqo= =SEif -----END PGP SIGNATURE----- ================================================ FILE: sig/v1.8.0/jq-windows-i386.exe.asc ================================================ -----BEGIN PGP SIGNATURE----- iQIzBAABCAAdFiEEkwealRHvwLfWzb+1sNpg+0VLrxgFAmiLcfIACgkQsNpg+0VL rxgyjw/5AUn0mf7/oT1XSXCRXnYSJX9wIPRptAb7uhAt5jF8CqTN1sQlG9b++EHN XahoFR/y6qw97pZK7/dM58TEfJyMi3kGjwUFKHobfvVdpnE7H1ZKnAJ9e50eSFOy OexsmJfeDgPcGEocdqA/KRpdNU0V/RtY11bpJE+O20EFwxjLGmiYcDlfOq+Tr/dv kVudU3DaedL6fg5D41rnoyTFpyStuOZb+9Alpt7sv04N5QHjcxVHOqMhiKK3L121 35Q/2VdD+G2LYOh6S3JWUtSJkzGkbQH1SCEQtTKu2LRO8Q01r4QXYTHvJsYmAqfc lwaXQ4XlI+3QHCiBx9izzYIfuZSmkzbvI6j9TQ7l7OBYs/GKEGQyLtFCUW4/SaGH g+J6f9500N7sFpyM+ErsZG0+r5vvIOG3uJGGeYCykNity9Z7gTF6xtgMXvpJDm/y qY8SPlm9DdyLTuCltYbqauS0Ji4ULKgXg6ezwom++vnkaFradV2r2KDfEI7Ou1bV BWWpq0O65hN8lg1TT25s7xMFpzi6Wu8CoR0rpfzYt+7N+SEU3GqDnkhhh0UbRrH4 Xojf0bZIIQt48k2CO5hokQuD1b2cyPfqzY2XCxvQgl2x8mAI9F5fsuq57YS46Fiv HLa0DCn9dUcN/435aR7UR82wVzmbJF+bv3NsvUhy8Ex2VcsZiTo= =kd3z -----END PGP SIGNATURE----- ================================================ FILE: sig/v1.8.0/sha256sum.txt ================================================ 91811577f91d9a6195ff50c2bffec9b72c8429dc05ec3ea022fd95c06d2b319c jq-1.8.0.tar.gz 894744a9f69f18f8552b5beaf755c77145ac2d76311400e23aee43df488e9c4a jq-1.8.0.zip 8926c33326111bcd67a47a970b5a5db933ef9194ad925994934c639c76a0605c jq-linux-amd64 1084e6bf5060a463daf77193888d326c83e56bcfbc18a52e6eaa99dbe82a8b54 jq-linux-arm64 aa52ed2f930b46c21ecd95c793d7aa75fd4ce2c63ff1423c4f19c948280ce978 jq-linux-armel 4bebc752981c879d0b4656236a122b23f45051e992d6d2bf23ad4126c71e9e55 jq-linux-armhf 5cf3ad973411275d27313a96d6f8e01acfef205515964490072f31812cbb9979 jq-linux-i386 34069dfcaee4168fdced283e5732de8c558d696cad1910e607d9b68f80211a16 jq-linux-mips 8a966bf92aca0641b500792599a715f4a126b537a3a2409c4fe2bc7c741e8b78 jq-linux-mips64 373d5c84bdb4ececde6dbb37483c323470e9baae1e329aec8470533ff93482e7 jq-linux-mips64el 118ad1e0a4a9bfc5a6677dd25822affd0ffb4990bce1ebe77b819505c4a75bea jq-linux-mips64r6 cdd99b2b76dbc025a9d475873f65e85d02d357a68be1f2935d7c9cd7e2f49ad0 jq-linux-mips64r6el 015fe63efe32802ab57823236f704b18a9d1c4ba89b3cce7bf620613b21abcb4 jq-linux-mipsel cb003f147e53c7dcb8ab81745ef6da4b60015b0dbf2122470d0f3965d5e47895 jq-linux-mipsr6 4b6dd650a13f9ad1c3f4148423fb10a6f25c2b1383854039938f21072f5d59a3 jq-linux-mipsr6el 76368bb2e54d8fe0cbf6b3dbaf1c83c30e238b2b93a5ddf5403b7333cf7bfc0f jq-linux-powerpc 55a70db3bc817a0ab03f33d6e0df2cffc32a45a22b51bbc5d46424383016719e jq-linux-ppc64el c8410cf481a2129bfcd323f6b4355583413e75a49c8a88c82bbf406d07401142 jq-linux-riscv64 1f377575f90fa323d57eaa38532bddb7d6563236c83cbb27b558b3ea09574a55 jq-linux-s390x 8926c33326111bcd67a47a970b5a5db933ef9194ad925994934c639c76a0605c jq-linux64 a594f3740bf570f0dbc43ff102a9034c17719d1bb5b40f0192751234d67f172a jq-macos-amd64 aaf1efbb376d6e3eaf61f63807c32c1df519f5857dfc4f581826fa2df4b715ae jq-macos-arm64 a594f3740bf570f0dbc43ff102a9034c17719d1bb5b40f0192751234d67f172a jq-osx-amd64 b45fcbb27dcb9e9848ac39889a8bf86457b8d9d31e7c56387c6eab80008fd1f4 jq-win64.exe b45fcbb27dcb9e9848ac39889a8bf86457b8d9d31e7c56387c6eab80008fd1f4 jq-windows-amd64.exe 47e2bcc9c3526ec72fe588136dcd592afaa139bdfb9be1d64244c9dc501b1e34 jq-windows-i386.exe ================================================ FILE: sig/v1.8.1/jq-1.8.1.tar.gz.asc ================================================ -----BEGIN PGP SIGNATURE----- iQIzBAABCAAdFiEEkwealRHvwLfWzb+1sNpg+0VLrxgFAmiLcfkACgkQsNpg+0VL rxjXmBAArxAr5IxcLlEL5V8ZoEx2CpKlSY71qYqxtSAGkJUjh+5QDtZe079nhYLr IrrAJ/DpINcy8BHEVnchDKhzeVtRbJZhZ7AyIabMePYPt737NvOHEb34xisIOEzZ UNtwqeABG99ePxtcx1TFkeaKtsxZzXX77IsOwGbp+DCy7H4SanZ6t0ohdN+nyPMO xeqVKFJRfCbio7XPgokeKNObuWusH1BDKRcvhQtuDCDGonYwHRaUjF90Z8Lj0I7f vlxJCdxYstSBzCCQlFR49wfPvHAmqCBy+mJaXJB6Mddwnv7O0+D4PfHHlT3iT1jm Fi/p/o8Qq1ldxk2JLJoF6sS2BEZzGeYkOT6yALBGHK6KQSAQ/opGaslUjrb4YrCI 2/AQOJHyFhFVbnolgkAYEk+wBT8f6jRu3VOMj8iAVrzwtzR2Ir+rrlO4fBdXMNLw Fy7ZiRWSzEAIuZ9i6lb2L07q9hrv7LX1EGCzyR4ynUfT72trBUXiEA+qUkhOGJ2V xaKq1AYVeJSvZ3pm7FCDQkhXypZ7Vj0NVbt/zxMqDmWI4sEeEMbA6zoOaLa/hMI2 91TioiMSPbcQPDiwGRHfoH/vAG/iL44J9EVTBctyOI608qVFQqI+1TjnAusxmB1p bllGj9vzSkWr3BP+Huvgygq2AOMpZEruO/BnlqtiBulRvKu8dqA= =LC7Q -----END PGP SIGNATURE----- ================================================ FILE: sig/v1.8.1/jq-1.8.1.zip.asc ================================================ -----BEGIN PGP SIGNATURE----- iQIzBAABCAAdFiEEkwealRHvwLfWzb+1sNpg+0VLrxgFAmiLcfkACgkQsNpg+0VL rxhvZA//Q1358x2VWqijFo0QKfM1ho5vCmRfd1O7iI60sT/1zXjQoIbDJhKP37f6 UWpznXSbd6Ou0IoKyskh9s2Rg0Xzpz7UT0j/c+QL+KTiepDOuoo2q6HY8Yba3Aa5 gad0M6KsUAdU9eabIrPf/DcLpRnNJPb/GIvjKoio7lKpX6e4QKmm2v8RYlH926tL OXuiF8kQHL3GlTktg3nK3X3fDmFfJupa1YBoJad3EHLk2AVQZsy8xPCWvq6F1K8V eberB6rrCiQiEup1HG7rzObIUD6UJZJyI7Ltk/7qRHn099LRHPJ+h9fGizUUWlW7 u3F/G7Jl6oazrngheUTC4c4kQGPrwpMKsWTmRRbQSYsIUUB6xCHibb339uxOgY+Z w1poLh3A0SbAk+RS3nfo/hXU088vbuXciVXIsldvOkFatI0F1OC/9z5CZgioo3DS CSAzO5f5z60B1F6Dw9IzmjOTGyzX0Cz2jP+c8kLMiW3JyycP7+m5U+ZDDVvl5Z/o ZvhiVqvw1yZxu4zpzUsrBgtb5Bn4AMKHWta7RxoujUvPOILvsiwzAOZEUI+Gyqmw xsd++FRg9zV+DZyWxtQ7wJIzmdg8NEj+fJkvJfZ42bN3xFaP1Mdqlo4EvJeaD1N4 dLR5xIZXhpttPtRueVKHjPjJTMBaxKTboecsNSe6PQQx1Twx7l8= =GiWw -----END PGP SIGNATURE----- ================================================ FILE: sig/v1.8.1/jq-linux-amd64.asc ================================================ -----BEGIN PGP SIGNATURE----- iQIzBAABCAAdFiEEkwealRHvwLfWzb+1sNpg+0VLrxgFAmiLcfkACgkQsNpg+0VL rxizCg//aopfRaQZnCeDT2yR9xPScBVcwe3tybTE2qmPETLTL0qn0QHzUPvW2CZz dIcgxsGgYAuaPB29RRwy++exdNZRVSoD6T6GIyIlmdfZzlOj1sUxtVSVogj65Szx WXo4QZ6OOAlW7gsy9bH5lrcW3f2MtPKsHKoHDal6eB00fUxuKbmlkqszn3SgaZQU X4G76zeSDscXZvqS/7svhjEBAFOdHGIXOzyb9whd1MRtw8AVxoRBbEoNG43ZYgVm Q1fPdAmuea4oXdNV4WCnmIm0Un0tNLSAOwCmQ6EQWnrbCjUupwMhpbgJYb99eEc6 s+sdMwLxWXXct8/pI/vHcsz6PkgC9k6fysLkCBFy/DuNsDJNt4EBbZXIk3WEV3Vo hVJ9db9tMP7d7hpv99sFhgHubEsVBuaWRdy1tv+IZoBRXepTR6P/bm/Tox0X0x7Q +pusYfkNHHZSc1mA6765s49F4rDzfKrc65Oj9Y10z2SHc9K73dTrSR1Sp6oIGiEl pVbP3ZJZx0qDFh33SO56CTIJrRUD51uzq2cKHHuzXLghVajU7Eq2lY5cgvJbHnLT JKWmhuUUsJwc7VfNiwgKE9gX62KurDPl26Ops86rPV2LZU7bOOq1+xQ6yDWnV2Ca eg5/gIQ8Xmy0jad+KBAaJRpzuQ/HR4y6Q+GXbASCo85QW3MLl8Y= =UtSR -----END PGP SIGNATURE----- ================================================ FILE: sig/v1.8.1/jq-linux-arm64.asc ================================================ -----BEGIN PGP SIGNATURE----- iQIzBAABCAAdFiEEkwealRHvwLfWzb+1sNpg+0VLrxgFAmiLcfkACgkQsNpg+0VL rxh4vBAApGt06jJ/AyzrKq3NYCLlsV69sHXcucYR2lqE7uzMpLGITtTNdfe1DP09 r9v/KOa50rO8v53AGQLFbK9++6IUsCGqwklhQzajtIOlkquzgoC69opECJ5tlBsN fJU6WRqXOXwxyVM29i4dlRb0qXrLkI+2j+c04Lb6RFkkCTrskVRp8neZgjc/a7gg F+44V+/RcCktndhyqTRqhlKcoHsOemQEaokgIVl8kG4cYVCXj2Ul10IKHlLvkGUE jPa9RiDgP4Y+6DxiDNx33gvCb7SWkyFlGkygHDqzRQVKh8nNIyfZRMedtJiiZOmx 6xLkpkBOCOZScHPOxTxLKPCFdoQEG/RQpMoehq2oVGBdp9BMp3x+unjBDi9TXtg6 vtkhs5+G2Vd0b2LGACvqKhlFWbpDpZpYqo8NvwjZZh1AyR6QrQxjw7mdRSzQuzT+ vyzn/ge6kFdqvWCUs9KJd86e3mzrc23i8mWOfpF7ydE/7HPKZJP+uzfJUrAwfY9k UKfRPS8MgAJ0PFUhW9kPZaPmmcUWLppn5cHqcdZ0lC0mTPidnZ4J1Fv1EyR3ipH6 i5UGQbNpQ4Xc/R8jg0TIWYWht3hN1LAub3jM+mQYHRb+p08lpVGzccQPXIf4RlRJ cNwRQWkYaRorRTK5VzVmVslq5cdP0Bmn8Moa2B1bxzRQfZr/G2k= =TT0m -----END PGP SIGNATURE----- ================================================ FILE: sig/v1.8.1/jq-linux-armel.asc ================================================ -----BEGIN PGP SIGNATURE----- iQIzBAABCAAdFiEEkwealRHvwLfWzb+1sNpg+0VLrxgFAmiLcfkACgkQsNpg+0VL rxh5Pw/7BP2io7rIy0OxmVBKSGvOR4ZZ6PIo6ws4hSiHB1wNXBUk3A9Y+5ctDFXd WrnWhxvI8oodVOmLtZ85wIIllqiB6pSaU+qKiQYvSwq4DBK0GovMxJAaq+jS9+kP v97KLeORhlP6EwOFXoE7PK4/pSktDC6XB45z2fwH4cfvfoOHNdcMMLm3Bql55ElB D+ef4lTmM2lOrz7+J+q2jtXLYEbbl0tlbbE3JEEYR/2vvO3D+jBivCt0tSZYEx1p EbvICvs2aJz6aKkLy9FsFp/lyQnDZZW8oqswbIjEKf4JEj9VztIDcfz3GkiIqDKW 4l2NuMxnSrW9Wx7vNzUHhOqk7ragp5iA/WiOyVkxX7wgoS8lvWcoQWTVPCM4Vj6p 4mc1X6ABiv1UMWYgzfGtjO7MBlm7VTmw9qVF3vMIOIW16UVdEv9o6o+uzooInX58 oUCVIFwjKtoPL1ne7vROqynqyjDUD7GsQ16ky/or/nOPKugNz4VlHriOTeXuEU5Y 7IckJ3/kGRMlZDdPhvclxtwfvjb6rSf298dG4k5LownvjWTPfkvIf2OJvkUuCyWz 4lMu/pNqDG5Zae5x+0DIzwTBo8Hn80d5WJZEuAj4yAAyXclibCvLTNw0QYQFaxfn HYy77L0XOVyzHrwIjG9lv+7R0RRz95t0xuUfF8SUY90y/RTQBPQ= =Qe0M -----END PGP SIGNATURE----- ================================================ FILE: sig/v1.8.1/jq-linux-armhf.asc ================================================ -----BEGIN PGP SIGNATURE----- iQIzBAABCAAdFiEEkwealRHvwLfWzb+1sNpg+0VLrxgFAmiLcfoACgkQsNpg+0VL rxgK3BAAhfzfKs28tG9zKbQZCuKMjnBeym3dbl8KKbyj9B8m/hMo/qJ5NaLyrwYS SKD+UtKjDkvWwXfZUCgR3z3zYcsi/LrHUi6IRsrdh42VTAufDO+gR62yaBRJg5TU QlZWDtH/24W4T9HhFmmN0UPwusDvurlLqRnghQqxY5fZaRVw39nP/voQk5MWeTQv mLVTMnb+bCBrUwyX22OAnCextl7qreCOzrP7IyjuH65cNQCHD8VB5CU4L8T/3KW6 BF3eev7QTC8LTtJH+volYXVieu7GqZjTWwIHYL4FrplI3kAjITZ6Gia34sCqbMUl 1LHyArm8MgqB18OVjWADUbXRFhf5EjUtA84i+Jn+C4FS55gb6HFP10j2Fr0xSosq L5NBUr9VnNeX/kQ9H5KWMROT5bf/QIcC/0zUBMtlTrhe0yEvMVqJM8AFYWPfGR8P 0cJZAPA2PjX8fZZR7+BBd4barcIOBFrvGcyOmDLGYR26KSxCgbsRBOd9hVBYKGTj qr+f48pGZnSOyDkgcA6+3zx5Y1ktAZNEeZUDxVni3DmqYdA6jOoNdYaUqNpF8PNC FA2xN6dIx7u9dKH2Vnk3MOpU1691NBaLXFX3oFHGi5HYKu59oNDhvl1zELUB27LC CKkOfd8nDhmmI57RIMzUsMH3UqEIbAo18KPkWOn4flPevrIgLJA= =zhxS -----END PGP SIGNATURE----- ================================================ FILE: sig/v1.8.1/jq-linux-i386.asc ================================================ -----BEGIN PGP SIGNATURE----- iQIzBAABCAAdFiEEkwealRHvwLfWzb+1sNpg+0VLrxgFAmiLcfoACgkQsNpg+0VL rxgVBBAAq4nw+mrtPZKTX6JW51/edFkKfBmn3WGC+OszvkCN3Wv/RaouCwjLcgAo UY0NB3mtYBpjLU01LgPBTwcFkjJCkY6C70XH6ImaUk5z3TRwdB1LKYFVi/bH9VTn QN4VNaYy9OiGdwu8SliC2ulVgCdfWuyvPnu4maQ6XZEdyJ2bclVQi8zmOnY5mDs8 fLOagioPNlLPZMEL8yDXR56gioxBMuOlDfVPCKl6kAPdAWp57olb29JhJ00lcW11 pdIBFwePtD1wpoxHrokSDpU+a2l2cWs9IUsWHzlwKUl+fio3rbB4nPo2ajYCFivm aFDeWPV6O4sy8MgqTZAWWj96QhrytGwt+VytdFLWl43U1ocjcBWTlv9xXOP7plgr M38kBrrox9Dea46OJAHmVdsNTYJKj9+U6yWY+NJQ2T2y5qMW8tXbeTzKsj6r2KzW nwFuCkXSeXir+Xpy1JAkUHLj46rERWhYbcH2T2rNE+iWnjd4PXNZ+H1CBhUOgM8X SGe3pn3bo/BchXPCTx/mkbvErpPL+KzEFd/kMfzZT6HvDxFUy93555hG+cCV4MMI Fa1d7PwayH0OAe6mOoRK4FG8xc9QPoF6XdOwwK0cJcw0vEYPd3x9U909ze9trRjF peSBgyzENwINL7+0smADRHT2JaTyMV5B8QRHS1+hkerJvauXCzI= =lKCG -----END PGP SIGNATURE----- ================================================ FILE: sig/v1.8.1/jq-linux-mips.asc ================================================ -----BEGIN PGP SIGNATURE----- iQIzBAABCAAdFiEEkwealRHvwLfWzb+1sNpg+0VLrxgFAmiLcfoACgkQsNpg+0VL rxhnsxAAxOChJU0wE2QSZB2VwMk887xMnlQp7/KdqqYxLGMUgYF5vrEbszefork1 M/zWCCq+fGR4pklg4qvNiwU3ipFPBtumwxKJnTvvMhQ0Xdgd5xDCtyLP/wlBVOTH iREGGzldbduM/xtWtVWE82KPE5jVrNDJJSIXch2gkoltKlFX+ry2+lATgjhgXc39 VIo4tfV1/T+ceRnvG9kEmmO6Qxev9XlKFPlz4yCVx4BV4pHhnv6vQ5qyh5rTtHPT sDePmRHc0XRoJz1bImEEmcYXz/AtUcbOW6twt50icQzUZQIV9NyVdXeul1OH66vy noNXDitRmn29w8vIAQfzvFp+/C7vyp1Y7IKHDLQPUQS95ZJQPFSO6kAjaWH5f4WR 5xo2A3HMFWzuJQa66FTIout6K0SHxHqYD9n+wdhikq6ZFAX1XuzvkncJgRpG2rLU KEfSfXoaS1CMA29ZE8ELOflydJM03sxaTNuQ4FrzDek3kbGpfsczA48oOia9GgGy pXCrmH5OP5nHfCGF0JtIZsWTu9QVjNmHlanpyUi2N3Cft+OZbjJEKWTIF+Ea6t9X 6uVGy4WeJFS8R1p58jwY9490S6mvfhPlim/tfTJoutZxMNyHza5oHFSfwOeh3p7a db9HeFAt0c4XIHXlT6q1W22Gk2XxHW8DY/o3/EyLMP+H5OxqK6k= =UCEb -----END PGP SIGNATURE----- ================================================ FILE: sig/v1.8.1/jq-linux-mips64.asc ================================================ -----BEGIN PGP SIGNATURE----- iQIzBAABCAAdFiEEkwealRHvwLfWzb+1sNpg+0VLrxgFAmiLcfoACgkQsNpg+0VL rxjjPRAAzhtjW4Qqe1ZYoNOyAs1Gik1cJjAJpTWOQh7deFhHb6GdhelOr2olRvMn lczl/iAdXtJoMxXIBNkHWD15nh10UjSBfE4D+VzNwyhvLfJ9sLHUD3s5CiUTtwdj l5clbz9PYp0pTw92hE0WuXMfB2Kg0pAmsIsyHTK9bNEMukGNe121SnX6LZIo/dOB Ap8hxMWVvarpdCAD/hsMfkP5lWtzWU2vHgaCpuLBUgyORYYIBupA4hRh6r91mEJd bTqwpRR9xt1sOHRNfBpUVStLK1ixv+0tvVnhM86Spr27Yxjf7qhUnoQxrkK9Etx2 8HqX7qttayNNeDCY1nvC0vWanGXKzERu3e4kH4DtBe6zVC27T9BUCmUbrULt9eTx F1FICi5lScZ8K4FLPDvpkdVsfOpt5bXiXo9lbSzRLzojODkN0tSCPWqDktIFiAii 9KL/b+InONjwyYQbNoRQf+AFcNttaEdMyiFbc3RuCeF5alHhezWnK2SBk2BUPGvk KhICiYRPkNuCAU1QFeTWDQbHfyRzn+sgq9rBqdh76ia5SRE21Pe1hnJGhjU3P+Mz TGems2qPYPxIhv2aXTeqONvTz6yd8QTvu/XD2DRxNHWpbcBec/mXYYQmWb2V9TeQ 4aAxBOMbcsQzsIlHcKrxSrcGJTTLE0gTewylQ97TMTiXGsZ8jsU= =rKcg -----END PGP SIGNATURE----- ================================================ FILE: sig/v1.8.1/jq-linux-mips64el.asc ================================================ -----BEGIN PGP SIGNATURE----- iQIzBAABCAAdFiEEkwealRHvwLfWzb+1sNpg+0VLrxgFAmiLcfoACgkQsNpg+0VL rxhfUA//cW18nU9/jk981v6Wk6CUp7gAdRZvu65OrlEKwpjvVf4CYJEAQsxmOgLp R0Oj2plJ94Xo4BDbCjXULghfLjOWikQuIeDNVfLMV/coe3J25LjgK7ooO9/fIeFQ dLDfrjXHVl5WOmPcwDLeXnKHc5X8vd9hanxQcJqGKy1mqgcyNqUth4tomXb5BdGe 9vBaNYiL3yKw3+OXtR7TNL6c8HgGQdXmkB2wcRCZvwCGxP8RD6avrILsyJs91YER ESh/CwOtHE84LjM7JG+MmTZbiE5XAisiEw0Af7BuNT+LpZoD0xTy8Zegg91SjD5b HzB36qfITLlLqm44KjhjGh+ya8xyfCnkh+mvHMatXDPN08TucZ0O+WLiWUQdZlXZ 0exb8Y4xc+92huSptZqwO6Ykrmqva1NGk9cKWlpeoOZ2hcR9vhaaBddgzS/1vev6 EOBN0OnCSvUqznASlCkXTkPjTpAP5reaw1uSMKygc1dag3S9T8ncrDK73MAJU0mW 4saT/fGMrDMMSGCDo5NKmm69PQvf9PT/UDI5iO7TKt4G+O2fuA01QNebZfC7nbkt ZBBiO437I4I9Ut9uTG/aPj5/SVjzVfpLUeR62ZXVlbdb2yy+37+62xlL3w0jSkT3 UGTgK4wLCf+WwKPl5mqsHU0waIKZHu/zw+SKkGzcVpr+EXTdTiI= =cTGP -----END PGP SIGNATURE----- ================================================ FILE: sig/v1.8.1/jq-linux-mips64r6.asc ================================================ -----BEGIN PGP SIGNATURE----- iQIzBAABCAAdFiEEkwealRHvwLfWzb+1sNpg+0VLrxgFAmiLcfoACgkQsNpg+0VL rxgclA/+NcP0PjvBCWAz7S++K8a40f+8gv19guXn+fD4m8+ko3XTpLN12vmeUs9r imfehNYynFymgUbheM5rwZMzVM+a3jis7CnsiVxdoeh13sk8hhj9V0Apl3R/B6n7 x50o+t7nXW2UJ5F6W64Iemekgv1lstvmPa6aFWmsqoJ/mweh538SOInLz17aVs4A 2TsDdqe5Bnf/O2MIYIzA18W0+RDW88NnyZpKzpSJndTvkvoizUWzqTmuq1t7ny39 5FGTIcfI3ertzTnqYqgSijuzD4YHAqw9QXytIqE6OC55Mqe5xX6sli38hYGMjJh5 Pip6zIJcTXOOZ3s4rGKx6b0VlhOPyUszPJ8NFklJ+t9i5mM911R36tCuyZBnKrTp cZYwGacBcGXFzHEWd/yp7bsRPQJKDHy9Y7Rq+vgGwXXihYJcFVO+D3m56saiEp5v ji6e8cwRXW2wKAwScK5YPpIUWSl4SOvc6RGD8FSvYsk4Fnm88Hj+rAw92tAzAeIc Oad4ok0jLlwBqzIlOI6m4FwxcQjV9GjqvJowPEyRhvU/3B/NM+m5ILoZYbR4DNeF Z2KVBYH/r8jnRmLCU3o3dFae1vxhw5croF1mpdfEW4NjSjU/HMmZ2aRwboLsF6+A mP2NjvkthsYSGPogo5MdkwtNqnvZ3eiQMwvT1hZ61POnZSc70wA= =Bd21 -----END PGP SIGNATURE----- ================================================ FILE: sig/v1.8.1/jq-linux-mips64r6el.asc ================================================ -----BEGIN PGP SIGNATURE----- iQIzBAABCAAdFiEEkwealRHvwLfWzb+1sNpg+0VLrxgFAmiLcfoACgkQsNpg+0VL rxikKA/6Ay8GgKRAVJjy+om+268kM8bA7ai0S8XmHvaCrcV+UwvS/XPUeV8HQseS Obl9Lu9MBJFdL1SCeDSGXSMJ556t+ZLc5Y31YHiaVVHI+4DGsItXYb9lVS/FzZ8w OQkNKPAT4BRgluManUGraBM8m3QPdVW/UcguLs/btotwAaTDYBUsCXY8TnT5wbUI nSyOnVHChhwa+eexNUPahn2wlbVmxapxxta2AQC9EADLdfHQs7yBpkbsUT1OJcFR J0fvelkxwjWF9YkU3ICTz+ZGLH8k1Cido047Sx4kX9IcWufm55piH/KlTIPhZyrm FWUUus5+pdPyyZWI8m2Y4m1ctyAGuGcZTOcN1RhRFhvcOlrMh/4fs20O0Tq2Zvqo 0sSVE3GBB4gBc2UEaqI3GQa7QjnTqbbQyJm3Th+BN3WKXGENB96Q8QH7oY3iIklT kov0sTvx4XskyeiHPR2gyvl3QkpOE1aazaYXYyesUWcNal8P9aW/7QUPz+eYviNJ FTfHkdJoBf9bLX0RNNhTek8FsQYLGdTuA9qjbbg5z6QZ1AzmsUkwlEEFhBW7YWQe sX5FQo1VWx4UUY0crdilt1PfTshOGPiXL9XLU82tLhy9baVJPs6LfsrXo2lz73b/ XO3upRrKrpduykvxserln5aQBv/zjR81vIJjYOYG1vRjey3TkEM= =UeIm -----END PGP SIGNATURE----- ================================================ FILE: sig/v1.8.1/jq-linux-mipsel.asc ================================================ -----BEGIN PGP SIGNATURE----- iQIzBAABCAAdFiEEkwealRHvwLfWzb+1sNpg+0VLrxgFAmiLcfoACgkQsNpg+0VL rxgZ/BAAlltGoXK0MpmzkSElskkZeTb1rtyIITmpl6w7dNkZCBpx0oIuGMIPwOud Cy4s8PTZFU23k3geDBqksEo54RBxUPJi6HS8JfypbOICuAKk1yg0vaVsqA2t3+o3 S18ihUvkcULgLCbzWxs1kdWvc+Ay8LDRUh9fgNOmeRt0wBl5UGQihN8lsF444Oif B4BvB7Z2rGuMt6mZAnpc25QApkjg8iDaE3SpJLIiX6hxUypZ2B/qBprelsi1Gy8+ uMad4U7+qBR9yKI5MoW5ySKGY/Es/DtAXHK9BWC/QBN182Mp5tjIt5ssENfKUoum uKAcQd3y9yidbYLJSyHd+Si1jtBflHgsVL+L7dFpjsYnmaUY5s55LiNIh0bunivl 2omI8aplHUznIz8Cvsm8EGyYFdFzBbIgkYD3MIiqINroWAMXapMYqrC7zivBw+xp h9Uua6q7ZWaf6jgCecotplv5JNh5XhjzH7HZhz5pWbx+B+kqLx+c+R7JqtBFuP1C O7b8A4yaCLjwmS0OZjsgeN52jnjV5BUK7bKH4MB5lJ44T1S22JJ9qYDVb/3KlwSA fhIZFD72rkT1WN2F0VbqCvMdYdjE2+3CpTZ2JBuTPw6Bw2v6W1Gx2VCAaxPPF5F2 J1vlcFQJs29wg6Oj6vMB+KA/dbhiuoau/3yI2kwTIvKs4FuzapA= =Rw8v -----END PGP SIGNATURE----- ================================================ FILE: sig/v1.8.1/jq-linux-mipsr6.asc ================================================ -----BEGIN PGP SIGNATURE----- iQIzBAABCAAdFiEEkwealRHvwLfWzb+1sNpg+0VLrxgFAmiLcfsACgkQsNpg+0VL rxim5A/+J4NVXvavvOcEYclpqyNbr7ihVXFESF7RzPUTNeISsc1wd8GpMUTdfUDK VK2nc2o2XMxnwDlNzitGk8i3eudqmQxShjLStE2YkhsU6bsLuPUaUeeksQmebKWi AcgZlk80xQYbnAJut942jrOpDNspqdlPB3WrY0VvPlrxL31bBc3SnmIbEx5JNJom AM846DVxZUoHDAdv3PtEPLDVVvShdzpXwg4X+CLpjfixIB4GRFZWG1kYHIHF5dQV A2ZvTChX+Mng79IM+5Y+/WQTYY1A2iRNoMVAqII2Km53/m/ikQoNeRL8pCrfQWIB 12A6hHQ9yhBUaF/irRcyod42eqEvyV2UlqFQ5XbW1SMEw49hfL52Xscga74EXisc 3+m9sBR2g7GmHj3VVQlqCJVh24BXar/JyVlVtvGMpyXXM5lM7PoxtZeT30onpLGe GBxbd2Dlzza4eFol9aWZDOjybxmsXLdJ13JL4aMy6H/hSyZTQJ8vte6AnHLDsE+1 jr1U2hXsEMfZRAFoSYVdj7GW4jOjUzr5F+3flRyYKOfch1GoQNt6gCCNyNifqvZO cWWWuI5pHT70fz3JDbWPxklPkJt9qF+fiz6yeIJ/XpOcDfGrLxxaWbkcZkJqXhVB mKD7HmGVoy8cj38WMmmK1pyEk5Ct3H+BzkzdeSOvokQVJkJc+Vk= =l6+/ -----END PGP SIGNATURE----- ================================================ FILE: sig/v1.8.1/jq-linux-mipsr6el.asc ================================================ -----BEGIN PGP SIGNATURE----- iQIzBAABCAAdFiEEkwealRHvwLfWzb+1sNpg+0VLrxgFAmiLcfsACgkQsNpg+0VL rxi0dxAAhfMe4ciVKuin3ctslLmGJM67fHTvmOWOZIfjfBDzvezsM8LDfxqRHyUo pB7MF+Utq+Mqt8leaqIMswFxXbrCa2VT3FjF2/VUuq/FNtSlLOwYGPUg0HOGjZpY riFL9Pr85o+3Op+HvVa63l01dqI+eiPKRKo/gaI+ay1rQ81q3wiJx07lFFdKa/Oz qSaznsn42AWD8yHYTETAIisZKTQUzA6blJ47DvECqed60ka8ws25buB5OXvXYzTa 79ThTjB7W7+7mHUN3dJXyZ1rso79/LMy0Zoc7IuHJyYBNtdVpzQ4iwKoL56bsy26 gRU4zEkTOIBw4l58VSyGBvAZOgjQFn71iIiz5wn6jQpezCkA/vi84TiwP4472wQP 9Q/Bj32oHP+mdQwg6cCiRmitvN6uJhg1WNdYgNiB7MVM1GeRRHndI2Y9OPxCARDO GCmZ2lha4bKgP308n3rGtf8zHtFf95pYRfGsMq1b9o5hV8kMALW0kwFljvaXEieO qvSBoapUs5hQ5UIqLQ9m644ctbJRagfXqnnslKp4+coxDyoUfbENc1zQNiIFHai9 ffcZhkPgKRgKiNaZwj81fGjlwM4vQ9MsiMQrAZcoucEXtJSIzom8pbiyAwfNaPO+ XCaxBRTGMEzZ0h7+6ZQEv3HTFV0vK55qPaTlx7zHkgQDJ6ARxbk= =lzcq -----END PGP SIGNATURE----- ================================================ FILE: sig/v1.8.1/jq-linux-powerpc.asc ================================================ -----BEGIN PGP SIGNATURE----- iQIzBAABCAAdFiEEkwealRHvwLfWzb+1sNpg+0VLrxgFAmiLcfsACgkQsNpg+0VL rxhrdQ/9FxbTPxmMQuNCM6iNL8UcvItJHGHDeLZaL1YdsS3h1a2gGjmukH3TM3Cb aIsPVl6mhyo4DRH560eawrtmYP5Y0TcdcSzL7ufKpIAUVDQmYo5PsiCpq/X8rS8C cWrTez4cElUl60IUzFqt7/B7xTSNQF3qw7tr1fD0VESxDSo8SnLRGpcRhgp63Ihv FM0MP4zaTTWgQCoqr2OZ2vmEyHOx4XDyz1THDg6lA8YBqvJ0E0n8YluCVCSNvCre ncuk4WX0FOuLSGA4neYQKHxChG4kr9PmuEp8+O50EdxUtG31jsDARspaFilBumzh 2eJ2Y35TVsnRJiu59Yo4KP/PaaGMmL8CnlYAcY+qxA0hb3f/zj1e8TbpDr9SV3r8 3Pd2Psg5TQmtZYPtTYvzKaapzPwtIomSQDFOv7dxUU8ZuEbGKLfAECyAa5t6lejg 6AaRb1UIz22rszUPNyimz3r0kadguIde2Pr2FsJV2yVLRkK4+yJCZtQ18vAmfeqP /qXW9PLxfTCsqxkixAwyDlwm2QpTBg/xnMWOHF2m3TxvHoJfny9hF9rIY8Ocg4NJ 62zFHBwnSUYl8ibcR6bGE2dED9E282scPphS4cxifR0jqKHm5b6uQbK3R0brSDDd AMiwRgMKIvJBaNAda3+XD4NXQ1iFtwHthPvI3fWlZQIf7j0N7OE= =6erF -----END PGP SIGNATURE----- ================================================ FILE: sig/v1.8.1/jq-linux-ppc64el.asc ================================================ -----BEGIN PGP SIGNATURE----- iQIzBAABCAAdFiEEkwealRHvwLfWzb+1sNpg+0VLrxgFAmiLcfsACgkQsNpg+0VL rxikjxAApfPUif6FPbDNTMY1QE1IaKqXbN7kd0YYplC/mTAIcctA0yh0KQWH8Z86 0SG+HrYK+JUM34pps1FF+NYnKzV6lBwrcHM1jX0WgtiTw8OEH5OlFyiAzkixAiFi Fh/sWhaIw05Q81KwrparlXzVJlpYGJ7lrr2qF4EMN+KTOOKs8oujS2XRa7DSqE5v Xfc9Ixk2FFxNygI1I+nsV5NPvPb7a5/Ld9gALpl6XXKMbDsHLVIM6GSQSfSwnEqm rXgF3mhuX6iTVwDsOFlYhA2yHXXxDYiFi5IyxFmaTXv4/892pkICx1XRoN/D5rkB 94aG2/qmAs/qPnO7XTSkyFB/eLp0lgEBFmuTtNRP5l5SgN026LBLeiNFvoViN9kC pUUVliAGth2MGlVigYlpWtZq0nNWgslLI4XXBfBcKssKoalmU0jMIMrI0fAMZZn2 uvn/Ev0ZXvedlwMSUmDxO+5i+izyTBsdLurYYMpoc4GldDTYCNo7NXgFNJ88Jymn MKfPeBHrtT0Hn6AfeyR5xy2dMp8Cm5utfAEirjRB863RPxfGUcxs1kTIscwhnXAh /om4/FLnZB3sYh8iFv93/rrlj2I2tEZK+btYeRjE8HM2snizm+VAviBT9k8C/T94 Bb2gcMReFqVEssh1eChEhcNJuHdzjs/QpcbbQM+8WhSTHFbo9x8= =WNcQ -----END PGP SIGNATURE----- ================================================ FILE: sig/v1.8.1/jq-linux-riscv64.asc ================================================ -----BEGIN PGP SIGNATURE----- iQIzBAABCAAdFiEEkwealRHvwLfWzb+1sNpg+0VLrxgFAmiLcfsACgkQsNpg+0VL rxiTRw/+IGBpjEdSptrrFrnfXfKYss036g+ej6AK5b5VWNpjNTN2LUvJXj3A+WnK PE6trAbcIvF3mW/G8TCKEe+ZFp/2vwoNVoRCLluK6wDwRYPVCAGtro+9+JZUM2HL YAKkXavkIC2QKSA+6i7IBAXshRiuC7t7Qrxr1FRnjYWP7Mp/62Olo37H2XSqYgv0 zjr1jfs3dB/DlPzY0fCnTHDkxgFI5Rrw0AdIwMsKAoPHgnDUlneSZqKYvYnKh92d ljNJK9RkbuHLqJE7A6nzWX8FXu8v4S26kzVX2j+arw5KQe4GgUn1ll9wNN8VtCFE w/HxJdZfy5RCVOOgfVr5HyLmskEdxnNLRKYWvkHK/UQaFFlPRKKROKlEGS2PLJ+a kD6MixVyJNdKnwikBZk4QSsGvybX3kuoDmCU3fzwrKSPW3oEkRrd2sy3i3Rh4TH0 6zBk36LaU7piJsHsi9a16mNNos9DiQtXdivgZDZHTIQCO8K3M0Uqgbgax0FQfTsE MTlYAgEX1No6jcl/0koZnqCwQlRl5PZWKT41Ul1ntqKEGPIaZP4eME35bFUcgqeD A0UdFOsAm/1+af3PD4rR4s+9JEoUbdBBIhweajVz++/kS0DMEEW75W//gMDzhCLc p3okQYSdTtta0y2xjNFaSis+aUehDrnDGee7/aQA19S47iUpZAs= =1f7S -----END PGP SIGNATURE----- ================================================ FILE: sig/v1.8.1/jq-linux-s390x.asc ================================================ -----BEGIN PGP SIGNATURE----- iQIzBAABCAAdFiEEkwealRHvwLfWzb+1sNpg+0VLrxgFAmiLcfsACgkQsNpg+0VL rxhC9A//aqqfv+VEdVTlHohl47DPuxZQoj5180pC1iXNRMN9gR5LmGXbHyrgQWW7 8mAVuFi9KC1SnmDeqSelp4Nb/RrlZtBSGP4Jc8gyvzRdewm2ozP7H26AtBu1/0fn Ca/TRxz+nMAQh1rlp7K7PFXYcWaPwuRIz18yJIU8UQ3EIXgtLCp77eKNEYqLWZvl mZzInSwlxA2r4w+Ptoaozq8GahH65rTvqTBDpRXizktHA0IrSkEKl1Z9f2yJcPo4 kiBFdLz9kfnQLVdS+XiLN+CFb3qf6lLYdOMwW+1JOQyv2oH6dPtFReCEmOrnYpwl /pifCL2yH6RkKQnLQTLsyKWHMjRhMzn6uQz1Jxv2ioiqnUYXKk7aBvs7gDrnHwlM eWWnq2i5BA7Nk/DvovSHEg7NZaa3+bCBojqUaTx+DD/2L5j9V73CuteBxv9TFQfJ G3wwS6tL3PmErbrEFYwv0eqk5qfA1m7u90M+lpEQJg37qXNU+Hw+ethpuEsVYPkf 9t/NSTXs/rMIX0X2hVSC6C6/klzgJ75EHaRUFafJ/ZouMXJrlpK846eHf7vT8WVi X9oDPprPT+YvVW5F0EJygq9Wnttj+7/JHYGBU6DxXIOebXWXo2cxK8Tp9X/x4rzb PDEPy9zqB44fpkYtIW8YWIKopRiaaI5ag0OVHpzq4KxbyfCzgvY= =JnMG -----END PGP SIGNATURE----- ================================================ FILE: sig/v1.8.1/jq-linux64.asc ================================================ -----BEGIN PGP SIGNATURE----- iQIzBAABCAAdFiEEkwealRHvwLfWzb+1sNpg+0VLrxgFAmiLcfsACgkQsNpg+0VL rxiAlhAAwRvgfO4ty3SLc3Qz9j9T4N2k0MrQC6aBqG60yn46PonWcINinz2QpKhE aCTBav5DOxcAoNtXH3f95+ALyWQtVVQ8kPxbR1HF2rnYePjYC64Y2uAFOt+ugQKh qlefeIJ7KT4QrvMqQ2Pdp3AOg1jJoX1Gv7c8AMmdB2KK9s+o0nOZ5/u/K/T1WcKL TZOZPafqdggfMKR/eczMMXsk4rK3E1hE7jxM/vhq5FOOlupo0E6lr5gCtOQbCupH 2XsbawZdEohp4MvrryfKg365QfRWoOEMz0nlH5hAq2X3jEQgzZZFL1kVMzANF+9K X4HKF0Bjs/D3po1cBSQG3fi2Pyysm7Ams9ubiX2fiB8UfCuI1+oPlZ6F3zg9JDST Xf8MbIxPlZuP3T7f7PLox2wm5SyDE64fXi/yRAih0QL9I1pSw6Y8aBAfdrcRdafk uzGA0UL7rpNhBrtRC7t4PgRJrKlN1l26XrqsxMBw3XrAjR2hm43H+686uAmjqDGL P5jZmfZXS+dc6zP5oSBm1monrvG1KnxLD57ilqfULbE2NXP1fhjaJYjrdClY/5Rx QOzxvOPtMHBVRvHsq2Ar5yPjMN0dW5wc47Um2j4w2JxSfT98YRP8TNoztmrkHcJ0 LpyKh5T+WSlq7Dsu2OY3KgXkOwF3o5BGuZaIIr0G4adW3rXwtOA= =KebY -----END PGP SIGNATURE----- ================================================ FILE: sig/v1.8.1/jq-macos-amd64.asc ================================================ -----BEGIN PGP SIGNATURE----- iQIzBAABCAAdFiEEkwealRHvwLfWzb+1sNpg+0VLrxgFAmiLcfsACgkQsNpg+0VL rxiBEQ/+PCUBjQy0wrxgOpFnXRlp0VswmJiBIBWDo6cwg7Ohb4lz0lZsaq71KoOL pt3OdrkoKchPSMCDxiPU3GIDkacdOvXcFEodB336+RGO0ki4nZRokq/M8eo0wZMu WuSunHp1cLgQMcuG6Wm05IF6B5h/Ll9UWyEmOPiKnL59okVWM276N8svICldJEB9 PDngtFy6mXRV3Xc+LVqSpmkKGXUWjUSPasNz6CLu/zK/9hQtXEWLK7D4na653Xnd 3a2XZmZnXOH3c2vGTA05eK2WDOtaU4p4aS4G1qKZPT6ixpw9crg1D+Puqid6tDkI qQFgN6MjPh6T+N9chg7Dc59IOBLBvuaYSOm+zUPrb7/PxXqdAqh3OVlvddndT9j/ Hggc0yMp7UzJg6IYUMoUQekCIUqxLTDkQutoYDep/jqzqkOvvxQmP6wXslk+GNAk KM/gIlW6klmdSa869bQS1StyUKqv8EQGpZy2mv+Y81G0RkU8Px/qj/Kq+CS/e/5s BnMvP1UnDqr2pwe2/KWmeQxbMJLuJ5sVB0ZtFMbHHta5rnLYXk5vQFDVF+AqigHw OS9UPakiua916fPHhlWxAeq5l/GsQPlCE/l+cSXIjjsrcaQj8pVV+sc7PcznBiH1 jszIXhxwCJ7gKYKnGbLJ5dLxS2sra9ujxktouHCBEtispR/9QpI= =Qp9I -----END PGP SIGNATURE----- ================================================ FILE: sig/v1.8.1/jq-macos-arm64.asc ================================================ -----BEGIN PGP SIGNATURE----- iQIzBAABCAAdFiEEkwealRHvwLfWzb+1sNpg+0VLrxgFAmiLcfsACgkQsNpg+0VL rxjLkA//WPyTXeDRiIei5i23ScntpilJcP/GeEHNzNl7ucml4DMzQpel7bnpcBHy ciTJ2JLA73NHJIeEiMFavq9gQRCaEG/1gn4Mv67WQcVitQcpmPsrYfTKcjrzHsc6 gNOc9QVONJeFqQlgFEv1GbAyC0uZjwecq4zBTpefZvXm7bZQaWCLpNphL4DStSbU AGnHhpuBriVvLg9C1l1nS14GoLLf/rH+0p5tboYbyd84OPWC+gmAAq+fuW5NlV8r CFs1r0ZyiXSAuKtDmL/axyOgLj6hds0IeXuGYi/AcmhaaHlrtxZF1atZZ8GBdHC5 1Hjwgpn/+Qjh3muM6/mulsS4HFKdmrVj10rpNspMU5HLjGafSQEyiylXz7F9EM0M bexMaJ/dMMZrnGTMl6wt2SudiHNO+e2XAhvMqoeEraHekC2joZZPKAHpYrxjUdMc 1eOpUVMmRCtR46SXWbzO3BNJg2W8K3gKPr5nm4/MMVcisxbQy9tC9U21EW2IONB9 NNgQNc7Dl72bcLZPKfXRBt/1Vp5rCAjsiRSxMsYB5UgIHRYKkVFX6zMHApWSkBt2 AXjfw0ghJ7LWSFh0CwhN1hUjMYxafLZ27WvO1wTErxnoAhlwlC1zigm66R5o12Co 4CzivuE2nM8yGIcacem+P0j0aSVhvRAzKzBul0tE3yxldG1DfZM= =XwMi -----END PGP SIGNATURE----- ================================================ FILE: sig/v1.8.1/jq-osx-amd64.asc ================================================ -----BEGIN PGP SIGNATURE----- iQIzBAABCAAdFiEEkwealRHvwLfWzb+1sNpg+0VLrxgFAmiLcfwACgkQsNpg+0VL rxhXKg/+JtQ6RPBYpeCEP7DQOBW7iMrCbhmqwnBpyF2mvDwtEzICdm8YHbfJXxcR fCsMbafYDtL0XdKjPC/Y08hvoj2c3tB4bUI/CTWv16XQRRvrb9JKsrtyQ8NybOkC wkaQ495/8vAHi3FMsUuCCe1PxwPZ10tl0K+s2ERwKjjPkmf2JejdYxXVrrpfClJW GlcXItQsTNDTaT82Jj+pAmND0ReSBcgRQi4sFDnfmRKhaqKPF2MApWuCKTF4mtZe ibgsYVohQ7M5yD9G5fitnN7nHAIhv+LeL4USJis5U7HAQVDvGNqJ9YkoIh2dutBj V370l1RSY6/EzvhN4pN9E5xBF4go2T83SV6pbLc8PPx09Er2r3TyhKroOaY3DLJD UjwUkQK5wirNnEa4o2LNookE4jLOxcg6L/teKPSJNjoB41sQCcY1oUsSbI2M2xQL 9WOxyYUbjzKdeXxQLExTFcT9uNJ8WC3H5LO+5Pbl8xV+Z+ZBf1m7q6JtPRGmm3X2 WiPrm3zieoQEqu4j3cVF/+6oUwG6dWgTUOaogQp+Oc5CC3SuWJ00KFly9mZVG1Un SfRvOxBWanNqiFFmjj+LdCXQx4kOnSybtp16uogP1P8462wu3cdJjwL0qTbcQU/H mxNtXaEkaKxDim8SWs+M9Vkr2X0NizRiH1P0hHBWef3MNEKhzTI= =KFTr -----END PGP SIGNATURE----- ================================================ FILE: sig/v1.8.1/jq-win64.exe.asc ================================================ -----BEGIN PGP SIGNATURE----- iQIzBAABCAAdFiEEkwealRHvwLfWzb+1sNpg+0VLrxgFAmiLcfwACgkQsNpg+0VL rxiSMxAAnpXJxH+3/6kN6lD4bjNUYiFPo6R3BI7t05jm6UGVcYwcB4YC1CAFz/6F Lt85WVrsmnnvec/eb3/4yhnQL4OsbQrSX/YHLjmVuc4od3JMiXK2S8cH4RZunUnj WLEXfzBYGeb9jAM9NW15jEojbO3hboWgqlkGq1VCO8kFzqByGji1EvbayGF71ZSV 2tNEofxom+L7fC7HKH1dYZN9lzYr7LJZM2R2xGAGo90uxIz6PINr8wZ4X58crLFA +pjppPBD76xBqE+o7/Ey2xxxLq+E5MkdNLgurcFBPO1xhBPTFOeNcDZDyyUE8u0V Nx7bjlOUinQznZAmE+1KDmhfksp7x0fiaofpzS0g5RFH+u0Ygrc7FBFOQdnzOE2Y H5i8lvA5/ovad5TA3IaUracPKfH+oA781iubH0DRnu0czRSsciKhJrY7diCNFwAm MXFZljuqrZVZGSDLyltwvyCaVeyqzTYqWsaXsz5joWWwQ73KqxB74fDn4KGiHI9t Kul493ZO5JUykv/Mtyi8M+eHjrBIQeDKVWt0XZiMXthi2Ip+orW5qw9hfbZS1seA ru9jg/m3XNikapGugMSN9yxGNT/hj9Czthwm1sNWbxNs2IBKKLwGDTgRVc1uZ+qb 2HmccMngPUIdWSe04068ZjDbMtt2CIiLDkd+xSQXpifOzP+uTck= =EoqF -----END PGP SIGNATURE----- ================================================ FILE: sig/v1.8.1/jq-windows-amd64.exe.asc ================================================ -----BEGIN PGP SIGNATURE----- iQIzBAABCAAdFiEEkwealRHvwLfWzb+1sNpg+0VLrxgFAmiLcfwACgkQsNpg+0VL rxiSMxAAnpXJxH+3/6kN6lD4bjNUYiFPo6R3BI7t05jm6UGVcYwcB4YC1CAFz/6F Lt85WVrsmnnvec/eb3/4yhnQL4OsbQrSX/YHLjmVuc4od3JMiXK2S8cH4RZunUnj WLEXfzBYGeb9jAM9NW15jEojbO3hboWgqlkGq1VCO8kFzqByGji1EvbayGF71ZSV 2tNEofxom+L7fC7HKH1dYZN9lzYr7LJZM2R2xGAGo90uxIz6PINr8wZ4X58crLFA +pjppPBD76xBqE+o7/Ey2xxxLq+E5MkdNLgurcFBPO1xhBPTFOeNcDZDyyUE8u0V Nx7bjlOUinQznZAmE+1KDmhfksp7x0fiaofpzS0g5RFH+u0Ygrc7FBFOQdnzOE2Y H5i8lvA5/ovad5TA3IaUracPKfH+oA781iubH0DRnu0czRSsciKhJrY7diCNFwAm MXFZljuqrZVZGSDLyltwvyCaVeyqzTYqWsaXsz5joWWwQ73KqxB74fDn4KGiHI9t Kul493ZO5JUykv/Mtyi8M+eHjrBIQeDKVWt0XZiMXthi2Ip+orW5qw9hfbZS1seA ru9jg/m3XNikapGugMSN9yxGNT/hj9Czthwm1sNWbxNs2IBKKLwGDTgRVc1uZ+qb 2HmccMngPUIdWSe04068ZjDbMtt2CIiLDkd+xSQXpifOzP+uTck= =EoqF -----END PGP SIGNATURE----- ================================================ FILE: sig/v1.8.1/jq-windows-i386.exe.asc ================================================ -----BEGIN PGP SIGNATURE----- iQIzBAABCAAdFiEEkwealRHvwLfWzb+1sNpg+0VLrxgFAmiLcfwACgkQsNpg+0VL rxiN8RAAuOpoknd+8RgjTvhJSkG0It4HwoHU/fqzVbWI2LwC0hRVrpZo0YZaLeIk wOpea2J0IoYo9y16ERdy3kpD0Ckyf8TTpGhMLeOwP0VyRd+6nT3dFTGG9StvzonB F/WI9b0DnykPbDdw2FgJrFXM2JfXD55RZKfu0nXlFui+tUrZ0xx8TNVnYSk/RKyM IwzEH8JsgWbhWCN83foUv61VpWtB64YmR+PtpK5UxHDTH6yClMX4/9jQUVdz+mxO grvlgD8me1wkeco6OMBGgj/Vl0aEBHLs8jPYVRSQ63+y+lEJJf5Ec7XraSypac4t T1xaOwu9ujnkUfLVwVRCRO6QBVMpFmirKbo2K6A6XtjaGWKupqW6nsNXAZx4ox8V uuzi+yCXD069vnk3tgjJJwto7UorWfI+fc2JcSYUoZ6fkpWdknyqXUkif/BDSDmS 1FC/FHHwDo9mdhwWEN+IoqHO4pVUJvl6muu9fnOxMhLDGH9t2AmfyIzIWCcBiNCq Sa1qGHLogfbYPeFB2lqULTP1lY9FEvkFYDqgZRRZ+KSv6s8ktD/JRZm+AmLBQI+Y MdYHiessm0UwtHwQWVrEpYRQ6gZKq9T2sk1llEfMm05TPUkKSD4/zHwfPTEY+CVt xQCvJRe1xktg9c4GH6o1Lse+AsHD1yjO5cW7H2VRKLp3Qn3GtN8= =5Ar7 -----END PGP SIGNATURE----- ================================================ FILE: sig/v1.8.1/sha256sum.txt ================================================ 2be64e7129cecb11d5906290eba10af694fb9e3e7f9fc208a311dc33ca837eb0 jq-1.8.1.tar.gz ebf8ef4817fdc05bbf22f54115958707396c3e62842fbbb617b766cd40b51f59 jq-1.8.1.zip 020468de7539ce70ef1bceaf7cde2e8c4f2ca6c3afb84642aabc5c97d9fc2a0d jq-linux-amd64 6bc62f25981328edd3cfcfe6fe51b073f2d7e7710d7ef7fcdac28d4e384fc3d4 jq-linux-arm64 b98e283ff26cd7478f6fb18cc081ca0e0cb2e9980300f0bfc8bb26854d347eb2 jq-linux-armel ac304e50cf7cd24933d83dc7d0e4f79892a71a92fb02336d4ecaffa8933760bd jq-linux-armhf ee8489cb8acfddf2e6d2ab4308877b5cbb6ec6b55beedb7c6d5a4fafb2879c86 jq-linux-i386 6ee8cc51b6abbcedcd60de1eca61ec74b02cbe222d02ae4622801bd0c19895d3 jq-linux-mips 91815e1000be7765e568f56b2a1f14cad58820ee772d952b514fa02085c252e3 jq-linux-mips64 abd7cda5556a4b8dd1f0bffeefae7142edd8b371f0ad232f4b786071eccbfaa4 jq-linux-mips64el 99d16b9c05c7ff8345be7b45b2eb99eec4f185c931d03c8bd7ae86ed8d56442a jq-linux-mips64r6 a1aa419dc2b99b354d7e3d1cb9b7359042f3da4e3d3afc4e4b94d1561f5e401e jq-linux-mips64r6el e4c10ea6b02e07d0099b624134f06849675b59e353386b0059ae15c0631c9ad6 jq-linux-mipsel 1171742caf57106569857a9bb3d0b39243d3bd03504d22622150736b2844c4f0 jq-linux-mipsr6 6bd590582a88ccb86df4725e071fd43becdc90e764dac7edcd7cb1b6e7fec848 jq-linux-mipsr6el ed48a57845d0771e2a35c2e8a0b88e26ec884c0b7186c6e390fc4fab965ed835 jq-linux-powerpc cb10b38f4e5ebb3904f383f24944a6c03a373b4b125d2928ccf52f8ea78f6f73 jq-linux-ppc64el 3d7274ea14254f0220b6a6d1b8756a957f739b6a20e3886358377e8ea6687cf6 jq-linux-riscv64 b792df2f5cced0404a5fd3796d7d47625dc087b3e3dcaa81017088590bb2f3a1 jq-linux-s390x 020468de7539ce70ef1bceaf7cde2e8c4f2ca6c3afb84642aabc5c97d9fc2a0d jq-linux64 e80dbe0d2a2597e3c11c404f03337b981d74b4a8504b70586c354b7697a7c27f jq-macos-amd64 a9fe3ea2f86dfc72f6728417521ec9067b343277152b114f4e98d8cb0e263603 jq-macos-arm64 e80dbe0d2a2597e3c11c404f03337b981d74b4a8504b70586c354b7697a7c27f jq-osx-amd64 23cb60a1354eed6bcc8d9b9735e8c7b388cd1fdcb75726b93bc299ef22dd9334 jq-win64.exe 23cb60a1354eed6bcc8d9b9735e8c7b388cd1fdcb75726b93bc299ef22dd9334 jq-windows-amd64.exe 414ec99417830178bd2f6e77fc78b34de3b12fc6b6c3229f07038c5811307124 jq-windows-i386.exe ================================================ FILE: src/builtin.c ================================================ #if __SIZEOF_POINTER__==4 # define _TIME_BITS 64 #endif #ifndef __sun__ # define _XOPEN_SOURCE # define _XOPEN_SOURCE_EXTENDED 1 #else # define _XPG6 # define __EXTENSIONS__ #endif #ifdef __OpenBSD__ # define _BSD_SOURCE #endif #include #include #include #include #include #include #include #ifdef HAVE_LIBONIG #include #endif #include #include #ifdef WIN32 #include #endif #include "builtin.h" #include "compile.h" #include "jq_parser.h" #include "bytecode.h" #include "linker.h" #include "locfile.h" #include "jv_unicode.h" #include "jv_alloc.h" #include "jv_dtoa.h" #include "jv_dtoa_tsd.h" #include "jv_private.h" #include "util.h" #define BINOP(name) \ static jv f_ ## name(jq_state *jq, jv input, jv a, jv b) { \ jv_free(input); \ return binop_ ## name(a, b); \ } BINOPS #undef BINOP static jv type_error(jv bad, const char* msg) { char errbuf[30]; const char *badkind = jv_kind_name(jv_get_kind(bad)); jv err = jv_invalid_with_msg(jv_string_fmt( "%s (%s) %s", badkind, jv_dump_string_trunc(bad, errbuf, sizeof(errbuf)), msg)); return err; } static jv type_error2(jv bad1, jv bad2, const char* msg) { char errbuf1[30], errbuf2[30]; const char *badkind1 = jv_kind_name(jv_get_kind(bad1)); const char *badkind2 = jv_kind_name(jv_get_kind(bad2)); jv err = jv_invalid_with_msg(jv_string_fmt( "%s (%s) and %s (%s) %s", badkind1, jv_dump_string_trunc(bad1, errbuf1, sizeof(errbuf1)), badkind2, jv_dump_string_trunc(bad2, errbuf2, sizeof(errbuf2)), msg)); return err; } static inline jv ret_error(jv bad, jv msg) { jv_free(bad); return jv_invalid_with_msg(msg); } static inline jv ret_error2(jv bad1, jv bad2, jv msg) { jv_free(bad1); jv_free(bad2); return jv_invalid_with_msg(msg); } jv binop_plus(jv a, jv b) { if (jv_get_kind(a) == JV_KIND_NULL) { jv_free(a); return b; } else if (jv_get_kind(b) == JV_KIND_NULL) { jv_free(b); return a; } else if (jv_get_kind(a) == JV_KIND_NUMBER && jv_get_kind(b) == JV_KIND_NUMBER) { jv r = jv_number(jv_number_value(a) + jv_number_value(b)); jv_free(a); jv_free(b); return r; } else if (jv_get_kind(a) == JV_KIND_STRING && jv_get_kind(b) == JV_KIND_STRING) { return jv_string_concat(a, b); } else if (jv_get_kind(a) == JV_KIND_ARRAY && jv_get_kind(b) == JV_KIND_ARRAY) { return jv_array_concat(a, b); } else if (jv_get_kind(a) == JV_KIND_OBJECT && jv_get_kind(b) == JV_KIND_OBJECT) { return jv_object_merge(a, b); } else { return type_error2(a, b, "cannot be added"); } } #ifdef __APPLE__ // macOS has a bunch of libm deprecation warnings, so let's clean those up #ifdef HAVE_TGAMMA #define HAVE_GAMMA #define gamma tgamma #endif #ifdef HAVE___EXP10 #define HAVE_EXP10 #define exp10 __exp10 #endif #ifdef HAVE_REMAINDER #define HAVE_DREM #define drem remainder #endif // We replace significand with our own, since there's not a rename-replacement #ifdef HAVE_FREXP static double __jq_significand(double x) { int z; return 2*frexp(x, &z); } #define HAVE_SIGNIFICAND #define significand __jq_significand #elif defined(HAVE_SCALBN) && defined(HAVE_ILOGB) static double __jq_significand(double x) { return scalbn(x, -ilogb(x)); } #define HAVE_SIGNIFICAND #define significand __jq_significand #endif #endif // ifdef __APPLE__ #define LIBM_DD(name) \ static jv f_ ## name(jq_state *jq, 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; \ } #define LIBM_DD_NO(name) \ static jv f_ ## name(jq_state *jq, jv input) { \ jv error = jv_string("Error: " #name "/0 not found at build time"); \ return ret_error(input, error); \ } #define LIBM_DDD(name) \ static jv f_ ## name(jq_state *jq, jv input, jv a, jv b) { \ jv_free(input); \ if (jv_get_kind(a) != JV_KIND_NUMBER) { \ jv_free(b); \ return type_error(a, "number required"); \ } \ if (jv_get_kind(b) != JV_KIND_NUMBER) { \ jv_free(a); \ return type_error(b, "number required"); \ } \ jv ret = jv_number(name(jv_number_value(a), jv_number_value(b))); \ jv_free(a); \ jv_free(b); \ return ret; \ } #define LIBM_DDD_NO(name) \ static jv f_ ## name(jq_state *jq, jv input, jv a, jv b) { \ jv_free(b); \ jv error = jv_string("Error: " #name "/2 not found at build time"); \ return ret_error2(input, a, error); \ } #define LIBM_DDDD(name) \ static jv f_ ## name(jq_state *jq, jv input, jv a, jv b, jv c) { \ jv_free(input); \ if (jv_get_kind(a) != JV_KIND_NUMBER) { \ jv_free(b); \ jv_free(c); \ return type_error(a, "number required"); \ } \ if (jv_get_kind(b) != JV_KIND_NUMBER) { \ jv_free(a); \ jv_free(c); \ return type_error(b, "number required"); \ } \ if (jv_get_kind(c) != JV_KIND_NUMBER) { \ jv_free(a); \ jv_free(b); \ return type_error(c, "number required"); \ } \ jv ret = jv_number(name(jv_number_value(a), jv_number_value(b), jv_number_value(c))); \ jv_free(a); \ jv_free(b); \ jv_free(c); \ return ret; \ } #define LIBM_DDDD_NO(name) \ static jv f_ ## name(jq_state *jq, jv input, jv a, jv b, jv c) { \ jv_free(c); \ jv_free(b); \ jv error = jv_string("Error: " #name "/3 not found at build time"); \ return ret_error2(input, a, error); \ } #define LIBM_DA(name, type) \ static jv f_ ## name(jq_state *jq, jv input) { \ if (jv_get_kind(input) != JV_KIND_NUMBER) { \ return type_error(input, "number required"); \ } \ type value; \ double d = name(jv_number_value(input), &value); \ jv ret = JV_ARRAY(jv_number(d), jv_number(value)); \ jv_free(input); \ return ret; \ } #define LIBM_DA_NO(name, type) \ static jv f_ ## name(jq_state *jq, jv input) { \ jv error = jv_string("Error: " #name "/0 not found at build time"); \ return ret_error(input, error); \ } #include "libm.h" #undef LIBM_DDDD_NO #undef LIBM_DDD_NO #undef LIBM_DD_NO #undef LIBM_DA_NO #undef LIBM_DDDD #undef LIBM_DDD #undef LIBM_DD #undef LIBM_DA #ifdef __APPLE__ #undef gamma #undef drem #undef significand #undef exp10 #endif static jv f_negate(jq_state *jq, jv input) { if (jv_get_kind(input) != JV_KIND_NUMBER) { return type_error(input, "cannot be negated"); } jv ret = jv_number_negate(input); jv_free(input); return ret; } static jv f_startswith(jq_state *jq, jv a, jv b) { if (jv_get_kind(a) != JV_KIND_STRING || jv_get_kind(b) != JV_KIND_STRING) return ret_error2(a, b, jv_string("startswith() requires string inputs")); 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(jq_state *jq, jv a, jv b) { if (jv_get_kind(a) != JV_KIND_STRING || jv_get_kind(b) != JV_KIND_STRING) return ret_error2(a, b, jv_string("endswith() requires string inputs")); 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; } jv binop_minus(jv a, jv b) { if (jv_get_kind(a) == JV_KIND_NUMBER && jv_get_kind(b) == JV_KIND_NUMBER) { jv r = jv_number(jv_number_value(a) - jv_number_value(b)); jv_free(a); jv_free(b); return r; } else if (jv_get_kind(a) == JV_KIND_ARRAY && jv_get_kind(b) == JV_KIND_ARRAY) { jv out = jv_array(); jv_array_foreach(a, i, x) { int include = 1; jv_array_foreach(b, j, y) { if (jv_equal(jv_copy(x), y)) { include = 0; break; } } if (include) out = jv_array_append(out, jv_copy(x)); jv_free(x); } jv_free(a); jv_free(b); return out; } else { return type_error2(a, b, "cannot be subtracted"); } } jv binop_multiply(jv a, jv b) { jv_kind ak = jv_get_kind(a); jv_kind bk = jv_get_kind(b); if (ak == JV_KIND_NUMBER && bk == JV_KIND_NUMBER) { jv r = jv_number(jv_number_value(a) * jv_number_value(b)); jv_free(a); jv_free(b); return r; } 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; } double d = jv_number_value(num); jv_free(num); return jv_string_repeat(str, d < 0 || isnan(d) ? -1 : d > INT_MAX ? INT_MAX : (int)d); } 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"); } } jv binop_divide(jv a, jv b) { if (jv_get_kind(a) == JV_KIND_NUMBER && jv_get_kind(b) == JV_KIND_NUMBER) { if (jv_number_value(b) == 0.0) return type_error2(a, b, "cannot be divided because the divisor is zero"); jv r = jv_number(jv_number_value(a) / jv_number_value(b)); jv_free(a); jv_free(b); return r; } 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"); } } #define dtoi(n) ((n) < INTMAX_MIN ? INTMAX_MIN : -(n) <= INTMAX_MIN ? INTMAX_MAX : (intmax_t)(n)) jv binop_mod(jv a, jv b) { if (jv_get_kind(a) == JV_KIND_NUMBER && jv_get_kind(b) == JV_KIND_NUMBER) { double na = jv_number_value(a); double nb = jv_number_value(b); if (isnan(na) || isnan(nb)) { jv_free(a); jv_free(b); return jv_number(NAN); } intmax_t bi = dtoi(nb); if (bi == 0) return type_error2(a, b, "cannot be divided (remainder) because the divisor is zero"); // Check if the divisor is -1 to avoid overflow when the dividend is INTMAX_MIN. jv r = jv_number(bi == -1 ? 0 : dtoi(na) % bi); jv_free(a); jv_free(b); return r; } else { return type_error2(a, b, "cannot be divided (remainder)"); } } #undef dtoi jv binop_equal(jv a, jv b) { return jv_bool(jv_equal(a, b)); } jv binop_notequal(jv a, jv b) { return jv_bool(!jv_equal(a, b)); } enum cmp_op { CMP_OP_LESS, CMP_OP_GREATER, CMP_OP_LESSEQ, CMP_OP_GREATEREQ }; static jv order_cmp(jv a, jv b, enum cmp_op op) { int r = jv_cmp(a, b); return jv_bool((op == CMP_OP_LESS && r < 0) || (op == CMP_OP_LESSEQ && r <= 0) || (op == CMP_OP_GREATEREQ && r >= 0) || (op == CMP_OP_GREATER && r > 0)); } jv binop_less(jv a, jv b) { return order_cmp(a, b, CMP_OP_LESS); } jv binop_greater(jv a, jv b) { return order_cmp(a, b, CMP_OP_GREATER); } jv binop_lesseq(jv a, jv b) { return order_cmp(a, b, CMP_OP_LESSEQ); } jv binop_greatereq(jv a, jv b) { return order_cmp(a, b, CMP_OP_GREATEREQ); } static jv f_contains(jq_state *jq, jv a, jv b) { if (jv_get_kind(a) == jv_get_kind(b)) { return jv_bool(jv_contains(a, b)); } else { return type_error2(a, b, "cannot have their containment checked"); } } static jv f_dump(jq_state *jq, jv input) { return jv_dump_string(input, 0); } static jv f_json_parse(jq_state *jq, 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(jq_state *jq, jv input) { if (jv_get_kind(input) == JV_KIND_NUMBER) { return input; } if (jv_get_kind(input) == JV_KIND_STRING) { const char* s = jv_string_value(input); int len = jv_string_length_bytes(jv_copy(input)); if ((size_t)len != strlen(s)) { return type_error(input, "cannot be parsed as a number"); } #ifdef USE_DECNUM jv number = jv_number_with_literal(s); if (jv_get_kind(number) == JV_KIND_INVALID) { return type_error(input, "cannot be parsed as a number"); } #else char *end = 0; double d = jvp_strtod(tsd_dtoa_context_get(), s, &end); if (end == 0 || *end != 0) { return type_error(input, "cannot be parsed as a number"); } jv number = jv_number(d); #endif jv_free(input); return number; } return type_error(input, "cannot be parsed as a number"); } static jv f_toboolean(jq_state *jq, jv input) { if (jv_get_kind(input) == JV_KIND_TRUE || jv_get_kind(input) == JV_KIND_FALSE) { return input; } if (jv_get_kind(input) == JV_KIND_STRING) { const char *s = jv_string_value(input); int len = jv_string_length_bytes(jv_copy(input)); if ((size_t)len != strlen(s)) { return type_error(input, "cannot be parsed as a boolean"); } if (strcmp(s, "true") == 0) { jv_free(input); return jv_true(); } else if (strcmp(s, "false") == 0) { jv_free(input); return jv_false(); } } return type_error(input, "cannot be parsed as a boolean"); } static jv f_length(jq_state *jq, jv input) { if (jv_get_kind(input) == JV_KIND_ARRAY) { return jv_number(jv_array_length(input)); } else if (jv_get_kind(input) == JV_KIND_OBJECT) { 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) { jv r = jv_number_abs(input); jv_free(input); return r; } else if (jv_get_kind(input) == JV_KIND_NULL) { jv_free(input); return jv_number(0); } else { return type_error(input, "has no length"); } } static jv f_tostring(jq_state *jq, jv input) { if (jv_get_kind(input) == JV_KIND_STRING) { return input; } else { return jv_dump_string(input, 0); } } static jv f_utf8bytelength(jq_state *jq, jv input) { if (jv_get_kind(input) != JV_KIND_STRING) return type_error(input, "only strings have UTF-8 byte length"); return jv_number(jv_string_length_bytes(input)); } static const unsigned char URI_UNRESERVED[128] = { // 1 2 3 4 5 6 7 8 9 A B C D E F 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0x00 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0x10 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, // 0x20: - . 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, // 0x30: 0-9 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0x40: A-O 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1, // 0x50: P-Z _ 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0x60: a-o 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 0, // 0x70: p-z ~ }; #define CHARS_ALPHANUM "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789" static const unsigned char BASE64_ENCODE_TABLE[64 + 1] = CHARS_ALPHANUM "+/"; static const unsigned char BASE64_INVALID_ENTRY = 0xFF; static const unsigned char BASE64_DECODE_TABLE[255] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 62, // + 0xFF, 0xFF, 0xFF, 63, // / 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, // 0-9 0xFF, 0xFF, 0xFF, 99, // = 0xFF, 0xFF, 0xFF, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, // A-Z 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, // a-z 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }; static jv escape_string(jv input, const char* escapings) { assert(jv_get_kind(input) == JV_KIND_STRING); const char* lookup[128] = {0}; const char* p = escapings; lookup[0] = "\\0"; while (*p) { lookup[(int)*p] = p+1; p++; p += strlen(p); p++; } jv ret = jv_string(""); const char* i = jv_string_value(input); const char* end = i + jv_string_length_bytes(jv_copy(input)); const char* cstart; int c = 0; while ((i = jvp_utf8_next((cstart = i), end, &c))) { if (c < 128 && lookup[c]) { ret = jv_string_append_str(ret, lookup[c]); } else { ret = jv_string_append_buf(ret, cstart, i - cstart); } } jv_free(input); return ret; } static jv f_format(jq_state *jq, jv input, jv fmt) { if (jv_get_kind(fmt) != JV_KIND_STRING) { jv_free(input); return type_error(fmt, "is not a valid format"); } const char* fmt_s = jv_string_value(fmt); if (!strcmp(fmt_s, "json")) { jv_free(fmt); return jv_dump_string(input, 0); } else if (!strcmp(fmt_s, "text")) { jv_free(fmt); return f_tostring(jq, input); } else if (!strcmp(fmt_s, "csv") || !strcmp(fmt_s, "tsv")) { const char *quotes, *sep, *escapings; const char *msg; if (!strcmp(fmt_s, "csv")) { msg = "cannot be csv-formatted, only array"; quotes = "\""; sep = ","; escapings = "\"\"\"\0"; } else { msg = "cannot be tsv-formatted, only array"; assert(!strcmp(fmt_s, "tsv")); quotes = ""; sep = "\t"; escapings = "\t\\t\0\r\\r\0\n\\n\0\\\\\\\0"; } jv_free(fmt); if (jv_get_kind(input) != JV_KIND_ARRAY) return type_error(input, msg); jv line = jv_string(""); jv_array_foreach(input, i, x) { if (i) line = jv_string_append_str(line, sep); switch (jv_get_kind(x)) { case JV_KIND_NULL: /* null rendered as empty string */ jv_free(x); break; case JV_KIND_TRUE: case JV_KIND_FALSE: line = jv_string_concat(line, jv_dump_string(x, 0)); break; case JV_KIND_NUMBER: if (jv_number_value(x) != jv_number_value(x)) { /* NaN, render as empty string */ jv_free(x); } else { line = jv_string_concat(line, jv_dump_string(x, 0)); } break; case JV_KIND_STRING: { line = jv_string_append_str(line, quotes); line = jv_string_concat(line, escape_string(x, escapings)); line = jv_string_append_str(line, quotes); break; } default: jv_free(input); jv_free(line); return type_error(x, "is not valid in a csv row"); } } jv_free(input); return line; } else if (!strcmp(fmt_s, "html")) { jv_free(fmt); return escape_string(f_tostring(jq, input), "&&\0<<\0>>\0''\0\""\0"); } else if (!strcmp(fmt_s, "uri")) { jv_free(fmt); input = f_tostring(jq, input); const char* s = jv_string_value(input); int len = jv_string_length_bytes(jv_copy(input)); char *result = jv_mem_alloc((size_t)len * 3 + 1); uint32_t ri = 0; for (int i = 0; i < len; i++) { unsigned c = (unsigned)(unsigned char)s[i]; if (c < 128 && URI_UNRESERVED[c]) { result[ri++] = (char)c; } else { result[ri++] = '%'; result[ri++] = "0123456789ABCDEF"[c >> 4]; result[ri++] = "0123456789ABCDEF"[c & 0x0F]; } } jv line = jv_string_sized(result, ri); free(result); jv_free(input); return line; } else if (!strcmp(fmt_s, "urid")) { jv_free(fmt); input = f_tostring(jq, input); const char *errmsg = "is not a valid uri encoding"; const char *s = jv_string_value(input); int len = jv_string_length_bytes(jv_copy(input)); char *result = jv_mem_alloc((size_t)len + 1); uint32_t ri = 0; for (int i = 0; i < len; i++) { char c = s[i]; if (c != '%') { result[ri++] = c; } else { int hi = 0, lo = 0; for (int j = 0; j < 2; j++) { if (++i >= len) { free(result); return type_error(input, errmsg); } int *d = j == 0 ? &hi : &lo; c = s[i]; if ('0' <= c && c <= '9') *d = c - '0'; else if ('a' <= c && c <= 'f') *d = c - 'a' + 10; else if ('A' <= c && c <= 'F') *d = c - 'A' + 10; else { free(result); return type_error(input, errmsg); } } result[ri++] = (hi << 4) | lo; } } if (!jvp_utf8_is_valid(result, result + ri)) { free(result); return type_error(input, errmsg); } jv line = jv_string_sized(result, ri); free(result); jv_free(input); return line; } else if (!strcmp(fmt_s, "sh")) { jv_free(fmt); if (jv_get_kind(input) != JV_KIND_ARRAY) input = jv_array_set(jv_array(), 0, input); jv line = jv_string(""); jv_array_foreach(input, i, x) { if (i) line = jv_string_append_str(line, " "); switch (jv_get_kind(x)) { case JV_KIND_NULL: case JV_KIND_TRUE: case JV_KIND_FALSE: case JV_KIND_NUMBER: line = jv_string_concat(line, jv_dump_string(x, 0)); break; case JV_KIND_STRING: { line = jv_string_append_str(line, "'"); line = jv_string_concat(line, escape_string(x, "''\\''\0")); line = jv_string_append_str(line, "'"); break; } default: jv_free(input); jv_free(line); return type_error(x, "can not be escaped for shell"); } } jv_free(input); return line; } else if (!strcmp(fmt_s, "base64")) { jv_free(fmt); input = f_tostring(jq, input); jv line = jv_string(""); const unsigned char* data = (const unsigned char*)jv_string_value(input); int len = jv_string_length_bytes(jv_copy(input)); for (int i=0; i= 3 ? 3 : len-i; for (int j=0; j<3; j++) { code <<= 8; code |= j < n ? (unsigned)data[i+j] : 0; } char buf[4]; for (int j=0; j<4; j++) { buf[j] = BASE64_ENCODE_TABLE[(code >> (18 - j*6)) & 0x3f]; } if (n < 3) buf[3] = '='; if (n < 2) buf[2] = '='; line = jv_string_append_buf(line, buf, sizeof(buf)); } jv_free(input); return line; } else if (!strcmp(fmt_s, "base64d")) { jv_free(fmt); input = f_tostring(jq, input); const unsigned char* data = (const unsigned char*)jv_string_value(input); int len = jv_string_length_bytes(jv_copy(input)); size_t decoded_len = MAX((3 * (size_t)len) / 4, (size_t)1); // 3 usable bytes for every 4 bytes of input char *result = jv_mem_calloc(decoded_len, sizeof(char)); uint32_t ri = 0; int input_bytes_read=0; uint32_t code = 0; for (int i=0; i> 16) & 0xFF; result[ri++] = (code >> 8) & 0xFF; result[ri++] = code & 0xFF; input_bytes_read = 0; code = 0; } } if (input_bytes_read == 3) { result[ri++] = (code >> 10) & 0xFF; result[ri++] = (code >> 2) & 0xFF; } else if (input_bytes_read == 2) { result[ri++] = (code >> 4) & 0xFF; } else if (input_bytes_read == 1) { free(result); return type_error(input, "trailing base64 byte found"); } jv line = jv_string_sized(result, ri); jv_free(input); free(result); return line; } else { jv_free(input); return jv_invalid_with_msg(jv_string_concat(fmt, jv_string(" is not a valid format"))); } } static jv f_keys(jq_state *jq, jv input) { if (jv_get_kind(input) == JV_KIND_OBJECT || jv_get_kind(input) == JV_KIND_ARRAY) { return jv_keys(input); } else { return type_error(input, "has no keys"); } } static jv f_keys_unsorted(jq_state *jq, jv input) { if (jv_get_kind(input) == JV_KIND_OBJECT || jv_get_kind(input) == JV_KIND_ARRAY) { return jv_keys_unsorted(input); } else { return type_error(input, "has no keys"); } } static jv f_sort(jq_state *jq, jv input){ if (jv_get_kind(input) == JV_KIND_ARRAY) { return jv_sort(input, jv_copy(input)); } else { return type_error(input, "cannot be sorted, as it is not an array"); } } static jv f_sort_by_impl(jq_state *jq, jv input, jv keys) { if (jv_get_kind(input) == JV_KIND_ARRAY && jv_get_kind(keys) == JV_KIND_ARRAY && jv_array_length(jv_copy(input)) == jv_array_length(jv_copy(keys))) { return jv_sort(input, keys); } else { return type_error2(input, keys, "cannot be sorted, as they are not both arrays"); } } /* * Assuming the input array is sorted, bsearch/1 returns * the index of the target if the target is in the input array; and otherwise * (-1 - ix), where ix is the insertion point that would leave the array sorted. * If the input is not sorted, bsearch will terminate but with irrelevant results. */ static jv f_bsearch(jq_state *jq, jv input, jv target) { if (jv_get_kind(input) != JV_KIND_ARRAY) { jv_free(target); return type_error(input, "cannot be searched from"); } int start = 0; int end = jv_array_length(jv_copy(input)); jv answer = jv_invalid(); while (start < end) { int mid = start + (end - start) / 2; int result = jv_cmp(jv_copy(target), jv_array_get(jv_copy(input), mid)); if (result == 0) { answer = jv_number(mid); break; } else if (result < 0) { end = mid; } else { start = mid + 1; } } if (!jv_is_valid(answer)) { answer = jv_number(-1 - start); } jv_free(input); jv_free(target); return answer; } static jv f_group_by_impl(jq_state *jq, jv input, jv keys) { if (jv_get_kind(input) == JV_KIND_ARRAY && jv_get_kind(keys) == JV_KIND_ARRAY && jv_array_length(jv_copy(input)) == jv_array_length(jv_copy(keys))) { return jv_group(input, keys); } else { return type_error2(input, keys, "cannot be sorted, as they are not both arrays"); } } static jv f_unique(jq_state *jq, jv input) { if (jv_get_kind(input) == JV_KIND_ARRAY) { return jv_unique(input, jv_copy(input)); } else { return type_error(input, "cannot be sorted, as it is not an array"); } } static jv f_unique_by_impl(jq_state *jq, jv input, jv keys) { if (jv_get_kind(input) == JV_KIND_ARRAY && jv_get_kind(keys) == JV_KIND_ARRAY && jv_array_length(jv_copy(input)) == jv_array_length(jv_copy(keys))) { return jv_unique(input, keys); } else { return type_error2(input, keys, "cannot be sorted, as they are not both arrays"); } } #ifdef HAVE_LIBONIG 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(jq_state *jq, 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(®, (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))); } result = test ? jv_false() : 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("")); jv captures = jv_array(); for (int i = 1; i < region->num_regs; ++i) { jv cap = jv_object(); if (region->beg[i] == -1) { cap = jv_object_set(cap, jv_string("offset"), jv_number(-1)); cap = jv_object_set(cap, jv_string("string"), jv_null()); } else { cap = jv_object_set(cap, 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); } onig_foreach_name(reg, f_match_name_iter, &captures); match = jv_object_set(match, jv_string("captures"), captures); result = jv_array_append(result, match); // ensure '"qux" | match("(?=u)"; "g")' matches just once start = (const UChar*)(input_string+region->end[0]+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) { 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; onig_free(reg); jv_free(input); jv_free(regex); return result; } #else /* !HAVE_LIBONIG */ static jv f_match(jq_state *jq, jv input, jv regex, jv modifiers, jv testmode) { jv_free(input); jv_free(regex); jv_free(modifiers); jv_free(testmode); return jv_invalid_with_msg(jv_string("jq was compiled without ONIGURUMA regex library. match/test/sub and related functions are not available.")); } #endif /* HAVE_LIBONIG */ 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"); if (jv_get_kind(keys) != JV_KIND_ARRAY) return type_error2(values, keys, "cannot be iterated over"); if (jv_array_length(jv_copy(values)) != jv_array_length(jv_copy(keys))) return type_error2(values, keys, "have wrong length"); if (jv_array_length(jv_copy(values)) == 0) { jv_free(values); jv_free(keys); return jv_null(); } jv ret = jv_array_get(jv_copy(values), 0); jv retkey = jv_array_get(jv_copy(keys), 0); for (int i=1; i 0x10FFFF || (nv >= 0xD800 && nv <= 0xDFFF)) nv = 0xFFFD; // U+FFFD REPLACEMENT CHARACTER s = jv_string_append_codepoint(s, nv); } jv_free(a); return s; } static jv f_setpath(jq_state *jq, jv a, jv b, jv c) { return jv_setpath(a, b, c); } extern jv _jq_path_append(jq_state *, jv, jv, jv); static jv f_getpath(jq_state *jq, jv a, jv b) { return _jq_path_append(jq, a, b, jv_getpath(jv_copy(a), jv_copy(b))); } static jv f_delpaths(jq_state *jq, jv a, jv b) { return jv_delpaths(a, b); } static jv f_has(jq_state *jq, jv a, jv b) { return jv_has(a, b); } static jv f_modulemeta(jq_state *jq, jv a) { if (jv_get_kind(a) != JV_KIND_STRING) { return ret_error(a, jv_string("modulemeta input module name must be a string")); } return load_module_meta(jq, a); } static jv f_input(jq_state *jq, jv input) { jv_free(input); jq_input_cb cb; void *data; jq_get_input_cb(jq, &cb, &data); if (cb == NULL) return jv_invalid_with_msg(jv_string("break")); jv v = cb(jq, data); if (jv_is_valid(v) || jv_invalid_has_msg(jv_copy(v))) return v; return jv_invalid_with_msg(jv_string("break")); } static jv f_debug(jq_state *jq, jv input) { jq_msg_cb cb; void *data; jq_get_debug_cb(jq, &cb, &data); if (cb != NULL) cb(data, jv_copy(input)); return input; } static jv f_stderr(jq_state *jq, jv input) { jq_msg_cb cb; void *data; jq_get_stderr_cb(jq, &cb, &data); if (cb != NULL) cb(data, jv_copy(input)); return input; } static jv tm2jv(struct tm *tm, double fsecs) { return JV_ARRAY(jv_number(tm->tm_year + 1900), jv_number(tm->tm_mon), jv_number(tm->tm_mday), jv_number(tm->tm_hour), jv_number(tm->tm_min), jv_number(tm->tm_sec + (fsecs - floor(fsecs))), jv_number(tm->tm_wday), jv_number(tm->tm_yday)); } #if defined(WIN32) && !defined(HAVE_SETENV) static int setenv(const char *var, const char *val, int ovr) { BOOL b; char c[2]; if (!ovr) { DWORD d; d = GetEnvironmentVariableA (var, c, 2); if (0 != d && GetLastError () != ERROR_ENVVAR_NOT_FOUND) { return d; } } b = SetEnvironmentVariableA (var, val); if (b) { return 0; } return 1; } #endif /* * mktime() has side-effects and anyways, returns time in the local * timezone, not UTC. We want timegm(), which isn't standard. * * To make things worse, mktime() tells you what the timezone * adjustment is, but you have to #define _BSD_SOURCE to get this * field of struct tm on some systems. * * This is all to blame on POSIX, of course. * * Our wrapper tries to use timegm() if available, or mktime() and * correct for its side-effects if possible. * * Returns (time_t)-2 if mktime()'s side-effects cannot be corrected. */ static time_t my_mktime(struct tm *tm) { #ifdef HAVE_TIMEGM return timegm(tm); #elif HAVE_TM_TM_GMT_OFF time_t t = mktime(tm); if (t == (time_t)-1) return t; return t + tm->tm_gmtoff; #elif HAVE_TM___TM_GMT_OFF time_t t = mktime(tm); if (t == (time_t)-1) return t; return t + tm->__tm_gmtoff; #elif WIN32 return _mkgmtime(tm); #else char *tz; tz = (tz = getenv("TZ")) != NULL ? strdup(tz) : NULL; if (tz != NULL) setenv("TZ", "", 1); time_t t = mktime(tm); if (tz != NULL) { setenv("TZ", tz, 1); free(tz); } return t; #endif } /* Compute and set tm_wday */ static void set_tm_wday(struct tm *tm) { /* * https://en.wikipedia.org/wiki/Determination_of_the_day_of_the_week#Gauss.27s_algorithm * https://cs.uwaterloo.ca/~alopez-o/math-faq/node73.html * * Tested with dates from 1900-01-01 through 2100-01-01. This * algorithm produces the wrong day-of-the-week number for dates in * the range 1900-01-01..1900-02-28, and for 2100-01-01..2100-02-28. * Since this is only needed on OS X and *BSD, we might just document * this. */ int century = (1900 + tm->tm_year) / 100; int year = (1900 + tm->tm_year) % 100; if (tm->tm_mon < 2) year--; /* * The month value in the wday computation below is shifted so that * March is 1, April is 2, .., January is 11, and February is 12. */ int mon = tm->tm_mon - 1; if (mon < 1) mon += 12; int wday = (tm->tm_mday + (int)floor((2.6 * mon - 0.2)) + year + (int)floor(year / 4.0) + (int)floor(century / 4.0) - 2 * century) % 7; if (wday < 0) wday += 7; #if 0 /* See commentary above */ assert(wday == tm->tm_wday || tm->tm_wday == 8); #endif tm->tm_wday = wday; } /* * Compute and set tm_yday. * */ static void set_tm_yday(struct tm *tm) { static const int d[] = {0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334}; int mon = tm->tm_mon; int year = 1900 + tm->tm_year; int leap_day = 0; if (tm->tm_mon > 1 && ((year % 4 == 0 && year % 100 != 0) || (year % 400 == 0))) leap_day = 1; /* Bound check index into d[] */ if (mon < 0) mon = -mon; if (mon > 11) mon %= 12; int yday = d[mon] + leap_day + tm->tm_mday - 1; assert(yday == tm->tm_yday || tm->tm_yday == 367); tm->tm_yday = yday; } static jv f_strptime(jq_state *jq, jv a, jv b) { if (jv_get_kind(a) != JV_KIND_STRING || jv_get_kind(b) != JV_KIND_STRING) { return ret_error2(a, b, jv_string("strptime/1 requires string inputs and arguments")); } struct tm tm; memset(&tm, 0, sizeof(tm)); tm.tm_wday = 8; // sentinel tm.tm_yday = 367; // sentinel const char *input = jv_string_value(a); const char *fmt = jv_string_value(b); const char *end = strptime(input, fmt, &tm); if (end == NULL || (*end != '\0' && !isspace((unsigned char)*end))) { return ret_error2(a, b, jv_string_fmt("date \"%s\" does not match format \"%s\"", input, fmt)); } jv_free(b); /* * This is OS X or some *BSD whose strptime() is just not that * helpful! * * We don't know that the format string did involve parsing a * year, or a month (if tm->tm_mon == 0). But with our invalid * day-of-week and day-of-year sentinel checks above, the worst * this can do is produce garbage. */ #ifdef __APPLE__ /* * Apple has made it worse, and different versions of the OS have different * behaviors. Some versions just don't touch the fields, but others do, and * sometimes provide wrong answers, at that! We can't tell at compile-time * which behavior the target system will have, so instead we always use our * functions to set these on OS X, and document that %u and %j are * unsupported on OS X. */ set_tm_wday(&tm); set_tm_yday(&tm); #elif defined(WIN32) || !defined(HAVE_STRPTIME) set_tm_wday(&tm); #else if (tm.tm_wday == 8 && tm.tm_mday != 0 && tm.tm_mon >= 0 && tm.tm_mon <= 11) set_tm_wday(&tm); if (tm.tm_yday == 367 && tm.tm_mday != 0 && tm.tm_mon >= 0 && tm.tm_mon <= 11) set_tm_yday(&tm); #endif jv r = tm2jv(&tm, 0); if (*end != '\0') r = jv_array_append(r, jv_string(end)); jv_free(a); // must come after `*end` because `end` is a pointer into `a`'s string return r; } static int jv2tm(jv a, struct tm *tm, int localtime) { memset(tm, 0, sizeof(*tm)); static const size_t offsets[] = { offsetof(struct tm, tm_year), offsetof(struct tm, tm_mon), offsetof(struct tm, tm_mday), offsetof(struct tm, tm_hour), offsetof(struct tm, tm_min), offsetof(struct tm, tm_sec), offsetof(struct tm, tm_wday), offsetof(struct tm, tm_yday), }; for (size_t i = 0; i < (sizeof offsets / sizeof *offsets); ++i) { jv n = jv_array_get(jv_copy(a), i); if (!jv_is_valid(n)) break; if (jv_get_kind(n) != JV_KIND_NUMBER || jvp_number_is_nan(n)) { jv_free(a); jv_free(n); return 0; } double d = jv_number_value(n); if (i == 0) /* year */ d -= 1900; *(int *)((void *)tm + offsets[i]) = d < INT_MIN ? INT_MIN : d > INT_MAX ? INT_MAX : (int)d; jv_free(n); } if (localtime) { tm->tm_isdst = -1; mktime(tm); } else { #ifdef HAVE_TIMEGM timegm(tm); #elif HAVE_TM_TM_GMT_OFF // tm->tm_gmtoff = 0; tm->tm_zone = "GMT"; #elif HAVE_TM___TM_GMT_OFF // tm->__tm_gmtoff = 0; tm->__tm_zone = "GMT"; #endif // tm->tm_isdst = 0; // The standard permits the tm structure to contain additional members. We // hope it is okay to initialize them to zero, because the standard does not // provide an alternative. } jv_free(a); return 1; } #undef TO_TM_FIELD static jv f_mktime(jq_state *jq, jv a) { if (jv_get_kind(a) != JV_KIND_ARRAY) return ret_error(a, jv_string("mktime requires array inputs")); struct tm tm; if (!jv2tm(a, &tm, 0)) return jv_invalid_with_msg(jv_string("mktime requires parsed datetime inputs")); time_t t = my_mktime(&tm); if (t == (time_t)-1) return jv_invalid_with_msg(jv_string("invalid gmtime representation")); if (t == (time_t)-2) return jv_invalid_with_msg(jv_string("mktime not supported on this platform")); return jv_number(t); } #ifdef HAVE_GMTIME_R static jv f_gmtime(jq_state *jq, jv a) { if (jv_get_kind(a) != JV_KIND_NUMBER) return ret_error(a, jv_string("gmtime() requires numeric inputs")); struct tm tm, *tmp; memset(&tm, 0, sizeof(tm)); double fsecs = jv_number_value(a); time_t secs = fsecs; jv_free(a); tmp = gmtime_r(&secs, &tm); if (tmp == NULL) return jv_invalid_with_msg(jv_string("error converting number of seconds since epoch to datetime")); return tm2jv(tmp, fsecs); } #elif defined HAVE_GMTIME static jv f_gmtime(jq_state *jq, jv a) { if (jv_get_kind(a) != JV_KIND_NUMBER) return ret_error(a, jv_string("gmtime requires numeric inputs")); struct tm tm, *tmp; memset(&tm, 0, sizeof(tm)); double fsecs = jv_number_value(a); time_t secs = fsecs; jv_free(a); tmp = gmtime(&secs); if (tmp == NULL) return jv_invalid_with_msg(jv_string("error converting number of seconds since epoch to datetime")); return tm2jv(tmp, fsecs); } #else static jv f_gmtime(jq_state *jq, jv a) { jv_free(a); return jv_invalid_with_msg(jv_string("gmtime not implemented on this platform")); } #endif #ifdef HAVE_LOCALTIME_R static jv f_localtime(jq_state *jq, jv a) { if (jv_get_kind(a) != JV_KIND_NUMBER) return ret_error(a, jv_string("localtime() requires numeric inputs")); struct tm tm, *tmp; memset(&tm, 0, sizeof(tm)); double fsecs = jv_number_value(a); time_t secs = fsecs; jv_free(a); tmp = localtime_r(&secs, &tm); if (tmp == NULL) return jv_invalid_with_msg(jv_string("error converting number of seconds since epoch to datetime")); return tm2jv(tmp, fsecs); } #elif defined HAVE_GMTIME static jv f_localtime(jq_state *jq, jv a) { if (jv_get_kind(a) != JV_KIND_NUMBER) return ret_error(a, jv_string("localtime requires numeric inputs")); struct tm tm, *tmp; memset(&tm, 0, sizeof(tm)); double fsecs = jv_number_value(a); time_t secs = fsecs; jv_free(a); tmp = localtime(&secs); if (tmp == NULL) return jv_invalid_with_msg(jv_string("error converting number of seconds since epoch to datetime")); return tm2jv(tmp, fsecs); } #else static jv f_localtime(jq_state *jq, jv a) { jv_free(a); return jv_invalid_with_msg(jv_string("localtime not implemented on this platform")); } #endif #ifdef HAVE_STRFTIME static jv f_strftime(jq_state *jq, jv a, jv b) { if (jv_get_kind(a) == JV_KIND_NUMBER) { a = f_gmtime(jq, a); if (!jv_is_valid(a)) { jv_free(b); return a; } } else if (jv_get_kind(a) != JV_KIND_ARRAY) { return ret_error2(a, b, jv_string("strftime/1 requires parsed datetime inputs")); } if (jv_get_kind(b) != JV_KIND_STRING) return ret_error2(a, b, jv_string("strftime/1 requires a string format")); struct tm tm; if (!jv2tm(a, &tm, 0)) return ret_error(b, jv_string("strftime/1 requires parsed datetime inputs")); const char *fmt = jv_string_value(b); int fmt_not_empty = *fmt != '\0'; size_t max_size = strlen(fmt) + 100; char *buf = jv_mem_alloc(max_size); #ifdef __APPLE__ /* Apple Libc (as of version 1669.40.2) contains a bug which causes it to * ignore the `tm.tm_gmtoff` in favor of the global timezone. To print the * proper timezone offset we temporarily switch the TZ to UTC. */ char *tz = (tz = getenv("TZ")) != NULL ? strdup(tz) : NULL; setenv("TZ", "UTC", 1); #endif size_t n = strftime(buf, max_size, fmt, &tm); #ifdef __APPLE__ if (tz) { setenv("TZ", tz, 1); free(tz); } else { unsetenv("TZ"); } #endif jv_free(b); /* POSIX doesn't provide errno values for strftime() failures; weird */ if ((n == 0 && fmt_not_empty) || n > max_size) { free(buf); return jv_invalid_with_msg(jv_string("strftime/1: unknown system failure")); } jv ret = jv_string_sized(buf, n); free(buf); return ret; } #else static jv f_strftime(jq_state *jq, jv a, jv b) { jv_free(a); jv_free(b); return jv_invalid_with_msg(jv_string("strftime/1 not implemented on this platform")); } #endif #ifdef HAVE_STRFTIME static jv f_strflocaltime(jq_state *jq, jv a, jv b) { if (jv_get_kind(a) == JV_KIND_NUMBER) { a = f_localtime(jq, a); if (!jv_is_valid(a)) { jv_free(b); return a; } } else if (jv_get_kind(a) != JV_KIND_ARRAY) { return ret_error2(a, b, jv_string("strflocaltime/1 requires parsed datetime inputs")); } if (jv_get_kind(b) != JV_KIND_STRING) return ret_error2(a, b, jv_string("strflocaltime/1 requires a string format")); struct tm tm; if (!jv2tm(a, &tm, 1)) return ret_error(b, jv_string("strflocaltime/1 requires parsed datetime inputs")); const char *fmt = jv_string_value(b); int fmt_not_empty = *fmt != '\0'; size_t max_size = strlen(fmt) + 100; char *buf = jv_mem_alloc(max_size); size_t n = strftime(buf, max_size, fmt, &tm); jv_free(b); /* POSIX doesn't provide errno values for strftime() failures; weird */ if ((n == 0 && fmt_not_empty) || n > max_size) { free(buf); return jv_invalid_with_msg(jv_string("strflocaltime/1: unknown system failure")); } jv ret = jv_string_sized(buf, n); free(buf); return ret; } #else static jv f_strflocaltime(jq_state *jq, jv a, jv b) { jv_free(a); jv_free(b); return jv_invalid_with_msg(jv_string("strflocaltime/1 not implemented on this platform")); } #endif #ifdef HAVE_GETTIMEOFDAY static jv f_now(jq_state *jq, jv a) { jv_free(a); struct timeval tv; if (gettimeofday(&tv, NULL) == -1) return jv_number(time(NULL)); return jv_number(tv.tv_sec + tv.tv_usec / 1000000.0); } #else static jv f_now(jq_state *jq, jv a) { jv_free(a); return jv_number(time(NULL)); } #endif static jv f_current_filename(jq_state *jq, jv a) { jv_free(a); jv r = jq_util_input_get_current_filename(jq); if (jv_is_valid(r)) return r; jv_free(r); return jv_null(); } static jv f_current_line(jq_state *jq, jv a) { jv_free(a); return jq_util_input_get_current_line(jq); } static jv f_have_decnum(jq_state *jq, jv a) { jv_free(a); #ifdef USE_DECNUM return jv_true(); #else return jv_false(); #endif } #define CFUNC(func, name, arity) \ {.fptr = { .a ## arity = func }, name, arity} #define LIBM_DD(name) \ CFUNC(f_ ## name, #name, 1), #define LIBM_DD_NO(name) LIBM_DD(name) #define LIBM_DA(name, type) LIBM_DD(name) #define LIBM_DA_NO(name, type) LIBM_DD(name) #define LIBM_DDD(name) \ CFUNC(f_ ## name, #name, 3), #define LIBM_DDD_NO(name) LIBM_DDD(name) #define LIBM_DDDD(name) \ CFUNC(f_ ## name, #name, 4), #define LIBM_DDDD_NO(name) LIBM_DDDD(name) static const struct cfunction function_list[] = { #include "libm.h" CFUNC(f_negate, "_negate", 1), #define BINOP(name) CFUNC(f_ ## name, "_" #name, 3), BINOPS #undef BINOP CFUNC(f_dump, "tojson", 1), CFUNC(f_json_parse, "fromjson", 1), CFUNC(f_tonumber, "tonumber", 1), CFUNC(f_toboolean, "toboolean", 1), CFUNC(f_tostring, "tostring", 1), CFUNC(f_keys, "keys", 1), CFUNC(f_keys_unsorted, "keys_unsorted", 1), CFUNC(f_startswith, "startswith", 2), CFUNC(f_endswith, "endswith", 2), CFUNC(f_string_split, "split", 2), CFUNC(f_string_explode, "explode", 1), CFUNC(f_string_implode, "implode", 1), CFUNC(f_string_indexes, "_strindices", 2), CFUNC(f_string_trim, "trim", 1), CFUNC(f_string_ltrim, "ltrim", 1), CFUNC(f_string_rtrim, "rtrim", 1), CFUNC(f_setpath, "setpath", 3), CFUNC(f_getpath, "getpath", 2), CFUNC(f_delpaths, "delpaths", 2), CFUNC(f_has, "has", 2), CFUNC(f_contains, "contains", 2), CFUNC(f_length, "length", 1), CFUNC(f_utf8bytelength, "utf8bytelength", 1), CFUNC(f_type, "type", 1), CFUNC(f_isinfinite, "isinfinite", 1), CFUNC(f_isnan, "isnan", 1), CFUNC(f_isnormal, "isnormal", 1), CFUNC(f_infinite, "infinite", 1), CFUNC(f_nan, "nan", 1), CFUNC(f_sort, "sort", 1), CFUNC(f_sort_by_impl, "_sort_by_impl", 2), CFUNC(f_group_by_impl, "_group_by_impl", 2), CFUNC(f_unique, "unique", 1), CFUNC(f_unique_by_impl, "_unique_by_impl", 2), CFUNC(f_bsearch, "bsearch", 2), CFUNC(f_min, "min", 1), CFUNC(f_max, "max", 1), CFUNC(f_min_by_impl, "_min_by_impl", 2), CFUNC(f_max_by_impl, "_max_by_impl", 2), CFUNC(f_error, "error", 1), CFUNC(f_format, "format", 2), CFUNC(f_env, "env", 1), CFUNC(f_halt, "halt", 1), CFUNC(f_halt_error, "halt_error", 2), CFUNC(f_get_search_list, "get_search_list", 1), CFUNC(f_get_prog_origin, "get_prog_origin", 1), CFUNC(f_get_jq_origin, "get_jq_origin", 1), CFUNC(f_match, "_match_impl", 4), CFUNC(f_modulemeta, "modulemeta", 1), CFUNC(f_input, "input", 1), CFUNC(f_debug, "debug", 1), CFUNC(f_stderr, "stderr", 1), CFUNC(f_strptime, "strptime", 2), CFUNC(f_strftime, "strftime", 2), CFUNC(f_strflocaltime, "strflocaltime", 2), CFUNC(f_mktime, "mktime", 1), CFUNC(f_gmtime, "gmtime", 1), CFUNC(f_localtime, "localtime", 1), CFUNC(f_now, "now", 1), CFUNC(f_current_filename, "input_filename", 1), CFUNC(f_current_line, "input_line_number", 1), CFUNC(f_have_decnum, "have_decnum", 1), CFUNC(f_have_decnum, "have_literal_numbers", 1), }; #undef LIBM_DDDD_NO #undef LIBM_DDD_NO #undef LIBM_DD_NO #undef LIBM_DA_NO #undef LIBM_DDDD #undef LIBM_DDD #undef LIBM_DD #undef LIBM_DA // This is a hack to make last(g) yield no output values, // if g yields no output values, without using boxing. static block gen_last_1(void) { block last_var = gen_op_var_fresh(STOREV, "last"); block is_empty_var = gen_op_var_fresh(STOREV, "is_empty"); block init = BLOCK(gen_op_simple(DUP), gen_const(jv_null()), last_var, gen_op_simple(DUP), gen_const(jv_true()), is_empty_var); block call_arg = BLOCK(gen_call("arg", gen_noop()), gen_op_simple(DUP), gen_op_bound(STOREV, last_var), gen_const(jv_false()), gen_op_bound(STOREV, is_empty_var), gen_op_simple(BACKTRACK)); block if_empty = gen_op_simple(BACKTRACK); return BLOCK(init, gen_op_target(FORK, call_arg), call_arg, BLOCK(gen_op_bound(LOADVN, is_empty_var), gen_op_target(JUMP_F, if_empty), if_empty, gen_op_bound(LOADVN, last_var))); } struct bytecoded_builtin { const char* name; block code; }; static block bind_bytecoded_builtins(block b) { block builtins = gen_noop(); { struct bytecoded_builtin builtin_defs[] = { {"empty", gen_op_simple(BACKTRACK)}, {"not", gen_condbranch(gen_const(jv_false()), gen_const(jv_true()))} }; for (unsigned i=0; i", jq_builtins, sizeof(jq_builtins)-1); int nerrors = jq_parse_library(src, &builtins); assert(!nerrors); locfile_free(src); builtins = bind_bytecoded_builtins(builtins); builtins = gen_cbinding(function_list, sizeof(function_list)/sizeof(function_list[0]), builtins); builtins = gen_builtin_list(builtins); *bb = block_bind_referenced(builtins, *bb, OP_IS_CALL_PSEUDO); return nerrors; } ================================================ FILE: src/builtin.h ================================================ #ifndef BUILTIN_H #define BUILTIN_H #include "jq.h" #include "bytecode.h" #include "compile.h" int builtins_bind(jq_state *, block*); #define BINOPS \ BINOP(plus) \ BINOP(minus) \ BINOP(multiply) \ BINOP(divide) \ BINOP(mod) \ BINOP(equal) \ BINOP(notequal) \ BINOP(less) \ BINOP(lesseq) \ BINOP(greater) \ BINOP(greatereq) \ #define BINOP(name) jv binop_ ## name(jv, jv); BINOPS #undef BINOP #endif ================================================ FILE: src/builtin.jq ================================================ def halt_error: halt_error(5); def error(msg): msg|error; def map(f): [.[] | f]; def select(f): if f then . else empty end; def sort_by(f): _sort_by_impl(map([f])); def group_by(f): _group_by_impl(map([f])); def unique_by(f): _unique_by_impl(map([f])); def max_by(f): _max_by_impl(map([f])); def min_by(f): _min_by_impl(map([f])); def add(f): reduce f as $x (null; . + $x); def add: add(.[]); def del(f): delpaths([path(f)]); def abs: if . < 0 then - . else . end; def _assign(paths; $value): reduce path(paths) as $p (.; setpath($p; $value)); def _modify(paths; update): reduce path(paths) as $p ([., []]; . as $dot | null | label $out | ($dot[0] | getpath($p)) as $v | ( ( $$$$v | update | (., break $out) as $v | $$$$dot | setpath([0] + $p; $v) ), ( $$$$dot | setpath([1, (.[1] | length)]; $p) ) ) ) | . as $dot | $dot[0] | delpaths($dot[1]); def map_values(f): .[] |= f; # recurse def recurse(f): def r: ., (f | r); r; def recurse(f; cond): def r: ., (f | select(cond) | r); r; def recurse: recurse(.[]?); def to_entries: [keys_unsorted[] as $k | {key: $k, value: .[$k]}]; def from_entries: map({(.key // .Key // .name // .Name): (if has("value") then .value else .Value end)}) | 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]] elif type == "string" and ($i|type) == "string" then _strindices($i) else .[$i] end; def index($i): indices($i) | .[0]; # TODO: optimize def rindex($i): indices($i) | .[-1:][0]; # TODO: optimize def paths: path(recurse)|select(length > 0); def paths(node_filter): path(recurse|select(node_filter))|select(length > 0); def isfinite: type == "number" and (isinfinite | not); def arrays: select(type == "array"); def objects: select(type == "object"); def iterables: select(type|. == "array" or . == "object"); def booleans: select(type == "boolean"); def numbers: select(type == "number"); def normals: select(isnormal); def finites: select(isfinite); def strings: select(type == "string"); def nulls: select(. == null); def values: select(. != null); def scalars: select(type|. != "array" and . != "object"); def join($x): reduce .[] as $i (null; (if .==null then "" else .+$x end) + ($i | if type=="boolean" or type=="number" then tostring else .//"" end) ) // ""; def _flatten($x): reduce .[] as $i ([]; if $i | type == "array" and $x != 0 then . + ($i | _flatten($x-1)) else . + [$i] end); def flatten($x): if $x < 0 then error("flatten depth must not be negative") else _flatten($x) end; def flatten: _flatten(-1); def range($x): range(0;$x); def fromdateiso8601: strptime("%Y-%m-%dT%H:%M:%SZ")|mktime; def todateiso8601: strftime("%Y-%m-%dT%H:%M:%SZ"); def fromdate: fromdateiso8601; def todate: todateiso8601; def ltrimstr($left): if startswith($left) then .[$left | length:] end; def rtrimstr($right): if endswith($right) then .[:length - ($right | length)] end; def trimstr($val): ltrimstr($val) | rtrimstr($val); def match(re; mode): _match_impl(re; mode; false)|.[]; def match($val): ($val|type) as $vt | if $vt == "string" then match($val; null) elif $vt == "array" and ($val | length) > 1 then match($val[0]; $val[1]) elif $vt == "array" and ($val | length) > 0 then match($val[0]; null) else error( $vt + " not a string or array") end; def test(re; mode): _match_impl(re; mode; true); def test($val): ($val|type) as $vt | if $vt == "string" then test($val; null) elif $vt == "array" and ($val | length) > 1 then test($val[0]; $val[1]) elif $vt == "array" and ($val | length) > 0 then test($val[0]; null) else error( $vt + " not a string or array") end; def capture(re; mods): match(re; mods) | reduce ( .captures | .[] | select(.name != null) | { (.name) : .string } ) as $pair ({}; . + $pair); def capture($val): ($val|type) as $vt | if $vt == "string" then capture($val; null) elif $vt == "array" and ($val | length) > 1 then capture($val[0]; $val[1]) elif $vt == "array" and ($val | length) > 0 then capture($val[0]; null) else error( $vt + " not a string or array") end; def scan($re; $flags): match($re; "g" + $flags) | if (.captures|length > 0) then [ .captures | .[] | .string ] else .string end; def scan($re): scan($re; null); # splits/1 produces a stream; split/1 is retained for backward compatibility. def splits($re; $flags): .[foreach (match($re; $flags+"g"), null) as {$offset, $length} (null; {start: .next, end: $offset, next: ($offset+$length)})]; def splits($re): splits($re; null); # split emits an array for backward compatibility def split($re; $flags): [ splits($re; $flags) ]; # If s contains capture variables, then create a capture object and pipe it to s, bearing # in mind that s could be a stream def sub($re; s; $flags): . as $in | (reduce match($re; $flags) as $edit ({result: [], previous: 0}; $in[ .previous: ($edit | .offset) ] as $gap # create the "capture" objects (one per item in s) | [reduce ( $edit | .captures | .[] | select(.name != null) | { (.name) : .string } ) as $pair ({}; . + $pair) | s ] as $inserts | reduce range(0; $inserts|length) as $ix (.; .result[$ix] += $gap + $inserts[$ix]) | .previous = ($edit | .offset + .length ) ) | .result[] + $in[.previous:] ) // $in; def sub($re; s): sub($re; s; ""); def gsub($re; s; flags): sub($re; s; flags + "g"); def gsub($re; s): sub($re; s; "g"); ######################################################################## # generic iterator/generator def while(cond; update): def _while: if cond then ., (update | _while) else empty end; _while; def until(cond; next): def _until: if cond then . else (next|_until) end; _until; def limit($n; expr): if $n > 0 then label $out | foreach expr as $item ($n; . - 1; $item, if . <= 0 then break $out else empty end) elif $n == 0 then empty else error("limit doesn't support negative count") end; def skip($n; expr): if $n > 0 then foreach expr as $item ($n; . - 1; if . < 0 then $item else empty end) elif $n == 0 then expr else error("skip doesn't support negative count") end; # range/3, with a `by` expression argument def range($init; $upto; $by): if $by > 0 then $init|while(. < $upto; . + $by) elif $by < 0 then $init|while(. > $upto; . + $by) else empty end; def first(g): label $out | g | ., break $out; def isempty(g): first((g|false), true); def all(generator; condition): isempty(generator|condition and empty); def any(generator; condition): isempty(generator|condition or empty)|not; def all(condition): all(.[]; condition); def any(condition): any(.[]; condition); def all: all(.[]; .); def any: any(.[]; .); def nth($n; g): if $n < 0 then error("nth doesn't support negative indices") else first(skip($n; g)) end; def first: .[0]; def last: .[-1]; def nth($n): .[$n]; def combinations: if length == 0 then [] else .[0][] as $x | (.[1:] | combinations) as $y | [$x] + $y end; def combinations(n): . as $dot | [range(n) | $dot] | combinations; # transpose a possibly jagged matrix, quickly; # rows are padded with nulls so the result is always rectangular. def transpose: [range(0; map(length)|max // 0) as $i | [.[][$i]]]; def in(xs): . as $x | xs | has($x); def inside(xs): . as $x | xs | contains($x); def repeat(exp): def _repeat: exp, _repeat; _repeat; def inputs: try repeat(input) catch if .=="break" then empty else error end; # like ruby's downcase - only characters A to Z are affected def ascii_downcase: explode | map( if 65 <= . and . <= 90 then . + 32 else . end) | implode; # like ruby's upcase - only characters a to z are affected def ascii_upcase: explode | map( if 97 <= . and . <= 122 then . - 32 else . end) | implode; # Streaming utilities def truncate_stream(stream): . as $n | null | stream | . as $input | if (.[0]|length) > $n then setpath([0];$input[0][$n:]) else empty end; def fromstream(i): {x: null, e: false} as $init | # .x = object being built; .e = emit and reset state foreach i as $i ($init ; if .e then $init else . end | if $i|length == 2 then setpath(["e"]; $i[0]|length==0) | setpath(["x"]+$i[0]; $i[1]) else setpath(["e"]; $i[0]|length==1) end ; if .e then .x else empty end); def tostream: path(def r: (.[]?|r), .; r) as $p | getpath($p) | reduce path(.[]?) as $q ([$p, .]; [$p+$q]); # Apply f to composite entities recursively, and to atoms def walk(f): def w: if type == "object" then map_values(w) elif type == "array" then map(w) else . end | f; w; # pathexps could be a stream of dot-paths def pick(pathexps): . as $in | reduce path(pathexps) as $a (null; setpath($a; $in|getpath($a)) ); # ensure the output of debug(m1,m2) is kept together: def debug(msgs): (msgs | debug | empty), .; # SQL-ish operators here: def INDEX(stream; idx_expr): reduce stream as $row ({}; .[$row|idx_expr|tostring] = $row); def INDEX(idx_expr): INDEX(.[]; idx_expr); def JOIN($idx; idx_expr): [.[] | [., $idx[idx_expr]]]; def JOIN($idx; stream; idx_expr): stream | [., $idx[idx_expr]]; def JOIN($idx; stream; idx_expr; join_expr): stream | [., $idx[idx_expr]] | join_expr; def IN(s): any(s == .; .); def IN(src; s): any(src == s; .); ================================================ FILE: src/bytecode.c ================================================ #include #include #include #include "bytecode.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 GLOBAL (OP_HAS_CONSTANT | OP_HAS_VARIABLE | OP_HAS_BINDING | OP_IS_CALL_PSEUDO), 4 #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) { int length = opcode_describe(*codeptr)->length; if (*codeptr == CALL_JQ || *codeptr == TAIL_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, ""); jv params = jv_object_get(jv_copy(bc->debuginfo), jv_string("params")); for (int i=0; inclosures; i++) { if (i) printf(", "); jv name = jv_array_get(jv_copy(params), i); printf("%s", jv_string_value(name)); jv_free(name); } jv_free(params); printf("]\n"); } dump_code(indent, bc); for (int i=0; insubfunctions; i++) { struct bytecode* subfn = bc->subfunctions[i]; jv name = jv_object_get(jv_copy(subfn->debuginfo), jv_string("name")); printf("%*s%s:%d:\n", indent, "", jv_string_value(name), i); jv_free(name); dump_disassembly(indent+2, subfn); } } static struct bytecode* getlevel(struct bytecode* bc, int level) { while (level > 0) { bc = bc->parent; level--; } return bc; } void dump_operation(struct bytecode* bc, uint16_t* codeptr) { int pc = codeptr - bc->code; printf("%04d ", pc); const struct opcode_description* op = opcode_describe(bc->code[pc++]); printf("%s", op->name); if (op->length > 1) { uint16_t imm = bc->code[pc++]; if (op->op == CALL_JQ || op->op == TAIL_CALL_JQ) { for (int i=0; icode[pc++]; uint16_t idx = bc->code[pc++]; jv name; if (idx & ARG_NEWCLOSURE) { idx &= ~ARG_NEWCLOSURE; name = jv_object_get(jv_copy(getlevel(bc,level)->subfunctions[idx]->debuginfo), jv_string("name")); } else { name = jv_array_get(jv_object_get(jv_copy(getlevel(bc,level)->debuginfo), jv_string("params")), idx); } printf(" %s:%d", jv_string_value(name), idx); jv_free(name); if (level) { printf("^%d", level); } } } else if (op->op == CALL_BUILTIN) { int func = bc->code[pc++]; jv name = jv_array_get(jv_copy(bc->globals->cfunc_names), func); printf(" %s", jv_string_value(name)); jv_free(name); } else if (op->flags & OP_HAS_BRANCH) { printf(" %04d", pc + imm); } else if (op->flags & OP_HAS_CONSTANT) { printf(" "); jv_dump(jv_array_get(jv_copy(bc->constants), imm), 0); } else if (op->flags & OP_HAS_VARIABLE) { uint16_t v = bc->code[pc++]; jv name = jv_array_get(jv_object_get(jv_copy(getlevel(bc,imm)->debuginfo), jv_string("locals")), v); printf(" $%s:%d", jv_string_value(name), v); jv_free(name); if (imm) { printf("^%d", imm); } } else { printf(" %d", imm); } } } void bytecode_free(struct bytecode* bc) { if (!bc) return; jv_mem_free(bc->code); jv_free(bc->constants); for (int i=0; insubfunctions; i++) bytecode_free(bc->subfunctions[i]); if (!bc->parent) symbol_table_free(bc->globals); jv_mem_free(bc->subfunctions); jv_free(bc->debuginfo); jv_mem_free(bc); } ================================================ FILE: src/bytecode.h ================================================ #ifndef BYTECODE_H #define BYTECODE_H #include #include "jq.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, // NOTE: Not actually part of any op -- a pseudo-op flag for special // handling of `break`. OP_BIND_WILDCARD = 2048, }; 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); #define MAX_CFUNCTION_ARGS 4 struct cfunction { union { jv (*a1)(jq_state *, jv); jv (*a2)(jq_state *, jv, jv); jv (*a3)(jq_state *, jv, jv, jv); jv (*a4)(jq_state *, jv, jv, jv, jv); } fptr; const char* name; int nargs; }; struct symbol_table { struct cfunction* cfunctions; int ncfunctions; jv cfunc_names; }; // The bytecode format matters in: // execute.c - interpreter // compile.c - compiler // bytecode.c - disassembler #define ARG_NEWCLOSURE 0x1000 struct bytecode { uint16_t* code; int codelen; int nlocals; int nclosures; jv constants; // JSON array of constants struct symbol_table* globals; struct bytecode** subfunctions; int nsubfunctions; struct bytecode* parent; jv debuginfo; }; void dump_disassembly(int, struct bytecode* code); void dump_operation(struct bytecode* bc, uint16_t* op); int bytecode_operation_length(uint16_t* codeptr); void bytecode_free(struct bytecode* bc); #endif ================================================ FILE: src/compile.c ================================================ #include #include #include #include #include "compile.h" #include "bytecode.h" #include "locfile.h" #include "jv_alloc.h" #include "util.h" /* The intermediate representation for jq filters is as a sequence of struct inst, which form a doubly-linked list via the next and prev pointers. A "block" represents a sequence of "struct inst", which may be empty. Blocks are generated by the parser bottom-up, so may have free variables (refer to things not defined). See inst.bound_by and inst.symbol. */ struct inst { struct inst* next; struct inst* prev; opcode op; struct { uint16_t intval; struct inst* target; jv constant; const struct cfunction* cfunc; } imm; struct locfile* locfile; location source; // Binding // An instruction requiring binding (for parameters/variables/functions) // is in one of three states: // inst->bound_by = NULL - Unbound free variable // inst->bound_by = inst - This instruction binds a variable // inst->bound_by = other - Uses variable bound by other instruction // Unbound instructions (references to other things that may or may not // exist) are created by "gen_foo_unbound", and bindings are created by // block_bind(definition, body), which binds all instructions in // body which are unbound and refer to "definition" by name. struct inst* bound_by; char* symbol; int any_unbound; int referenced; int nformals; int nactuals; block subfn; // used by CLOSURE_CREATE (body of function) block arglist; // used by CLOSURE_CREATE (formals) and CALL_JQ (arguments) // This instruction is compiled as part of which function? // (only used during block_compile) struct bytecode* compiled; int bytecode_pos; // position just after this insn }; static inst* inst_new(opcode op) { inst* i = jv_mem_alloc(sizeof(inst)); i->next = i->prev = 0; i->op = op; i->bytecode_pos = -1; i->bound_by = 0; i->symbol = 0; i->any_unbound = 0; i->referenced = 0; i->nformals = -1; i->nactuals = -1; i->subfn = gen_noop(); i->arglist = gen_noop(); i->source = UNKNOWN_LOCATION; i->locfile = 0; return i; } static void inst_free(struct inst* i) { jv_mem_free(i->symbol); block_free(i->subfn); block_free(i->arglist); if (i->locfile) locfile_free(i->locfile); if (opcode_describe(i->op)->flags & OP_HAS_CONSTANT) { jv_free(i->imm.constant); } jv_mem_free(i); } static block inst_block(inst* i) { block b = {i,i}; return b; } int block_is_single(block b) { return b.first && b.first == b.last; } static inst* block_take(block* b) { if (b->first == 0) return 0; inst* i = b->first; if (i->next) { i->next->prev = 0; b->first = i->next; i->next = 0; } else { b->first = 0; b->last = 0; } return i; } block gen_location(location loc, struct locfile* l, block b) { for (inst* i = b.first; i; i = i->next) { if (i->source.start == UNKNOWN_LOCATION.start && i->source.end == UNKNOWN_LOCATION.end) { i->source = loc; i->locfile = locfile_retain(l); } } return b; } block gen_noop(void) { block b = {0,0}; return b; } int block_is_noop(block b) { return (b.first == 0 && b.last == 0); } block gen_op_simple(opcode op) { assert(opcode_describe(op)->length == 1); return inst_block(inst_new(op)); } block gen_error(jv constant) { assert(opcode_describe(ERRORK)->flags & OP_HAS_CONSTANT); inst *i = inst_new(ERRORK); i->imm.constant = constant; return inst_block(i); } block gen_const(jv constant) { assert(opcode_describe(LOADK)->flags & OP_HAS_CONSTANT); inst* i = inst_new(LOADK); i->imm.constant = constant; return inst_block(i); } block gen_const_global(jv constant, const char *name) { assert((opcode_describe(STORE_GLOBAL)->flags & (OP_HAS_CONSTANT | OP_HAS_VARIABLE | OP_HAS_BINDING)) == (OP_HAS_CONSTANT | OP_HAS_VARIABLE | OP_HAS_BINDING)); inst* i = inst_new(STORE_GLOBAL); i->imm.constant = constant; i->symbol = strdup(name); i->any_unbound = 0; return inst_block(i); } block gen_op_pushk_under(jv constant) { assert(opcode_describe(PUSHK_UNDER)->flags & OP_HAS_CONSTANT); inst* i = inst_new(PUSHK_UNDER); i->imm.constant = constant; return inst_block(i); } int block_is_const(block b) { return (block_is_single(b) && (b.first->op == LOADK || b.first->op == PUSHK_UNDER)); } jv_kind block_const_kind(block b) { assert(block_is_const(b)); return jv_get_kind(b.first->imm.constant); } jv block_const(block b) { assert(block_is_const(b)); return jv_copy(b.first->imm.constant); } block gen_op_target(opcode op, block target) { assert(opcode_describe(op)->flags & OP_HAS_BRANCH); assert(target.last); inst* i = inst_new(op); i->imm.target = target.last; return inst_block(i); } block gen_op_targetlater(opcode op) { assert(opcode_describe(op)->flags & OP_HAS_BRANCH); inst* i = inst_new(op); i->imm.target = 0; return inst_block(i); } void inst_set_target(block b, block target) { assert(block_is_single(b)); assert(opcode_describe(b.first->op)->flags & OP_HAS_BRANCH); assert(target.last); b.first->imm.target = target.last; } block gen_op_unbound(opcode op, const char* name) { assert(opcode_describe(op)->flags & OP_HAS_BINDING); inst* i = inst_new(op); i->symbol = strdup(name); i->any_unbound = 1; return inst_block(i); } block gen_op_var_fresh(opcode op, const char* name) { assert(opcode_describe(op)->flags & OP_HAS_VARIABLE); block b = gen_op_unbound(op, name); b.first->bound_by = b.first; return b; } block gen_op_bound(opcode op, block binder) { assert(block_is_single(binder)); block b = gen_op_unbound(op, binder.first->symbol); b.first->bound_by = binder.first; b.first->any_unbound = 0; return b; } block gen_dictpair(block k, block v) { return BLOCK(gen_subexp(k), gen_subexp(v), gen_op_simple(INSERT)); } static void inst_join(inst* a, inst* b) { assert(a && b); assert(!a->next); assert(!b->prev); a->next = b; b->prev = a; } void block_append(block* b, block b2) { if (b2.first) { if (b->last) { inst_join(b->last, b2.first); } else { b->first = b2.first; } b->last = b2.last; } } block block_join(block a, block b) { block c = a; block_append(&c, b); return c; } int block_has_only_binders_and_imports(block binders, int bindflags) { bindflags |= OP_HAS_BINDING; for (inst* curr = binders.first; curr; curr = curr->next) { if ((opcode_describe(curr->op)->flags & bindflags) != bindflags && curr->op != DEPS && curr->op != MODULEMETA) { return 0; } } return 1; } static int inst_is_binder(inst *i, int bindflags) { return !((opcode_describe(i->op)->flags & bindflags) != bindflags && i->op != MODULEMETA); } int block_has_only_binders(block binders, int bindflags) { bindflags |= OP_HAS_BINDING; bindflags &= ~OP_BIND_WILDCARD; for (inst* curr = binders.first; curr; curr = curr->next) { if ((opcode_describe(curr->op)->flags & bindflags) != bindflags && curr->op != MODULEMETA) { return 0; } } return 1; } // 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_inner(int* any_unbound, block binder, block body, int bindflags, int break_distance) { assert(block_is_single(binder)); assert((opcode_describe(binder.first->op)->flags & bindflags) == (bindflags & ~OP_BIND_WILDCARD)); assert(binder.first->symbol); assert(binder.first->bound_by == 0 || binder.first->bound_by == binder.first); assert(break_distance >= 0); binder.first->bound_by = binder.first; int nrefs = 0; for (inst* i = body.first; i; i = i->next) { if (i->any_unbound == 0) continue; int flags = opcode_describe(i->op)->flags; if ((flags & bindflags) == (bindflags & ~OP_BIND_WILDCARD) && i->bound_by == 0 && (!strcmp(i->symbol, binder.first->symbol) || // Check for break/break2/break3; see parser.y ((bindflags & OP_BIND_WILDCARD) && i->symbol[0] == '*' && break_distance <= 3 && (i->symbol[1] == '1' + break_distance) && i->symbol[2] == '\0'))) { // bind this instruction if (i->nactuals == -1 || i->nactuals == binder.first->nformals) { i->bound_by = binder.first; nrefs++; } } else if ((flags & bindflags) == (bindflags & ~OP_BIND_WILDCARD) && i->bound_by != 0 && !strncmp(binder.first->symbol, "*anonlabel", sizeof("*anonlabel") - 1) && !strncmp(i->symbol, "*anonlabel", sizeof("*anonlabel") - 1)) { // Increment the break distance required for this binder to match // a break whenever we come across a STOREV of *anonlabel... break_distance++; } i->any_unbound = (i->symbol && !i->bound_by); // binding recurses into closures nrefs += block_bind_subblock_inner(&i->any_unbound, binder, i->subfn, bindflags, break_distance); // binding recurses into argument list nrefs += block_bind_subblock_inner(&i->any_unbound, binder, i->arglist, bindflags, break_distance); if (i->any_unbound) *any_unbound = 1; } return nrefs; } static int block_bind_subblock(block binder, block body, int bindflags, int break_distance) { int any_unbound; return block_bind_subblock_inner(&any_unbound, binder, body, bindflags, break_distance); } static int block_bind_each(block binder, block body, int bindflags) { assert(block_has_only_binders(binder, bindflags)); bindflags |= OP_HAS_BINDING; int nrefs = 0; for (inst* curr = binder.first; curr; curr = curr->next) { nrefs += block_bind_subblock(inst_block(curr), body, bindflags, 0); } return nrefs; } static block block_bind(block binder, block body, int bindflags) { block_bind_each(binder, body, bindflags); return block_join(binder, body); } block block_bind_library(block binder, block body, int bindflags, const char *libname) { bindflags |= OP_HAS_BINDING; int matchlen = (libname == NULL) ? 0 : strlen(libname); char *matchname = jv_mem_alloc(matchlen+2+1); matchname[0] = '\0'; if (libname != NULL && libname[0] != '\0') { strcpy(matchname,libname); strcpy(matchname+matchlen, "::"); matchlen += 2; } assert(block_has_only_binders(binder, bindflags)); for (inst *curr = binder.last; curr; curr = curr->prev) { int bindflags2 = bindflags; char* cname = curr->symbol; char* tname = jv_mem_alloc(strlen(curr->symbol)+matchlen+1); strcpy(tname, matchname); strcpy(tname+matchlen, curr->symbol); // Ew if ((opcode_describe(curr->op)->flags & (OP_HAS_VARIABLE | OP_HAS_CONSTANT))) bindflags2 = OP_HAS_VARIABLE | OP_HAS_BINDING; // This mutation is ugly, even if we undo it curr->symbol = tname; block_bind_subblock(inst_block(curr), body, bindflags2, 0); curr->symbol = cname; free(tname); } free(matchname); return body; // We don't return a join because we don't want those sticking around... } static inst* block_take_last(block* b) { inst* i = b->last; if (i == 0) return 0; if (i->prev) { i->prev->next = i->next; b->last = i->prev; i->prev = 0; } else { b->first = 0; b->last = 0; } return i; } // Binds a sequence of binders, which *must not* already be bound to each other, // to body, throwing away unreferenced defs block block_bind_referenced(block binder, block body, int bindflags) { assert(block_has_only_binders(binder, bindflags)); bindflags |= OP_HAS_BINDING; inst* curr; while ((curr = block_take_last(&binder))) { block b = inst_block(curr); if (block_bind_subblock(b, body, bindflags, 0) == 0) { block_free(b); } else { body = BLOCK(b, body); } } return body; } block block_bind_self(block binder, int bindflags) { assert(block_has_only_binders(binder, bindflags)); bindflags |= OP_HAS_BINDING; block body = gen_noop(); inst* curr; while ((curr = block_take_last(&binder))) { block b = inst_block(curr); block_bind_subblock(b, body, bindflags, 0); body = BLOCK(b, body); } return body; } static void block_mark_referenced(block body) { int saw_top = 0; for (inst* i = body.last; i; i = i->prev) { if (saw_top && i->bound_by == i && !i->referenced) continue; if (i->op == TOP) { saw_top = 1; } if (i->bound_by) { i->bound_by->referenced = 1; } block_mark_referenced(i->arglist); block_mark_referenced(i->subfn); } } block block_drop_unreferenced(block body) { block_mark_referenced(body); block refd = gen_noop(); inst* curr; while ((curr = block_take(&body))) { if (curr->bound_by == curr && !curr->referenced) { inst_free(curr); } else { refd = BLOCK(refd, inst_block(curr)); } } return refd; } jv block_take_imports(block* body) { jv imports = jv_array(); /* Parser should never generate TOP before imports */ assert(!(body->first && body->first->op == TOP && body->first->next && (body->first->next->op == MODULEMETA || body->first->next->op == DEPS))); while (body->first && (body->first->op == MODULEMETA || body->first->op == DEPS)) { inst* dep = block_take(body); if (dep->op == DEPS) { imports = jv_array_append(imports, jv_copy(dep->imm.constant)); } inst_free(dep); } return imports; } jv block_list_funcs(block body, int omit_underscores) { jv funcs = jv_object(); // Use the keys for set semantics. for (inst *pos = body.first; pos != NULL; pos = pos->next) { if (pos->op == CLOSURE_CREATE || pos->op == CLOSURE_CREATE_C) { if (pos->symbol != NULL && (!omit_underscores || pos->symbol[0] != '_')) { funcs = jv_object_set(funcs, jv_string_fmt("%s/%i", pos->symbol, pos->nformals), jv_null()); } } } return jv_keys_unsorted(funcs); } block gen_module(block metadata) { assert(block_is_const(metadata) && block_const_kind(metadata) == JV_KIND_OBJECT); inst* i = inst_new(MODULEMETA); i->imm.constant = block_const(metadata); if (jv_get_kind(i->imm.constant) != JV_KIND_OBJECT) i->imm.constant = jv_object_set(jv_object(), jv_string("metadata"), i->imm.constant); block_free(metadata); return inst_block(i); } jv block_module_meta(block b) { if (b.first != NULL && b.first->op == MODULEMETA) return jv_copy(b.first->imm.constant); return jv_null(); } block gen_import(const char* name, const char* as, int is_data) { inst* i = inst_new(DEPS); jv meta = jv_object(); if (as != NULL) meta = jv_object_set(meta, jv_string("as"), jv_string(as)); meta = jv_object_set(meta, jv_string("is_data"), is_data ? jv_true() : jv_false()); meta = jv_object_set(meta, jv_string("relpath"), jv_string(name)); i->imm.constant = meta; return inst_block(i); } block gen_import_meta(block import, block metadata) { assert(block_is_single(import) && import.first->op == DEPS); assert(block_is_const(metadata) && block_const_kind(metadata) == JV_KIND_OBJECT); inst *i = import.first; i->imm.constant = jv_object_merge(block_const(metadata), i->imm.constant); block_free(metadata); return import; } block gen_function(const char* name, block formals, block body) { inst* i = inst_new(CLOSURE_CREATE); int nformals = 0; for (inst* i = formals.last; i; i = i->prev) { nformals++; i->nformals = 0; if (i->op == CLOSURE_PARAM_REGULAR) { i->op = CLOSURE_PARAM; body = gen_var_binding(gen_call(i->symbol, gen_noop()), i->symbol, body); } block_bind_subblock(inst_block(i), body, OP_IS_CALL_PSEUDO | OP_HAS_BINDING, 0); } i->subfn = body; i->symbol = strdup(name); i->any_unbound = -1; i->nformals = nformals; i->arglist = formals; block b = inst_block(i); block_bind_subblock(b, b, OP_IS_CALL_PSEUDO | OP_HAS_BINDING, 0); return b; } block gen_param_regular(const char* name) { return gen_op_unbound(CLOSURE_PARAM_REGULAR, name); } 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); b.first->arglist = args; b.first->nactuals = block_count_actuals(b.first->arglist); return b; } block gen_subexp(block a) { if (block_is_noop(a)) { return gen_op_simple(DUP); } if (block_is_single(a) && a.first->op == LOADK) { jv c = block_const(a); block_free(a); return gen_op_pushk_under(c); } return BLOCK(gen_op_simple(SUBEXP_BEGIN), a, gen_op_simple(SUBEXP_END)); } block gen_both(block a, block b) { block jump = gen_op_targetlater(JUMP); block fork = gen_op_target(FORK, jump); block c = BLOCK(fork, a, jump, b); inst_set_target(jump, c); return c; } block gen_const_object(block expr) { int is_const = 1; jv o = jv_object(); jv k = jv_null(); jv v = jv_null(); for (inst *i = expr.first; i; i = i->next) { if (i->op == PUSHK_UNDER) { k = jv_copy(i->imm.constant); i = i->next; } else if (i->op != SUBEXP_BEGIN || i->next == NULL || i->next->op != LOADK || i->next->next == NULL || i->next->next->op != SUBEXP_END) { is_const = 0; break; } else { k = jv_copy(i->next->imm.constant); i = i->next->next->next; } if (i != NULL && i->op == PUSHK_UNDER) { v = jv_copy(i->imm.constant); i = i->next; } else if (i == NULL || i->op != SUBEXP_BEGIN || i->next == NULL || i->next->op != LOADK || i->next->next == NULL || i->next->next->op != SUBEXP_END) { is_const = 0; break; } else { v = jv_copy(i->next->imm.constant); i = i->next->next->next; } if (i == NULL || i->op != INSERT) { is_const = 0; break; } if (jv_get_kind(k) != JV_KIND_STRING) { is_const = 0; break; } o = jv_object_set(o, k, v); k = jv_null(); v = jv_null(); } if (!is_const) { jv_free(o); jv_free(k); jv_free(v); block b = {0,0}; return b; } block_free(expr); return gen_const(o); } static block gen_const_array(block expr) { /* * An expr of all constant elements looks like this: * * 0009 FORK 0027 * 0011 FORK 0023 * 0013 FORK 0019 * 0015 LOADK 1 * 0017 JUMP 0021 * 0019 LOADK 2 * 0021 JUMP 0025 * 0023 LOADK 3 * 0025 JUMP 0029 * 0027 LOADK 4 * * That's: N-1 commas for N elements, N LOADKs, and a JUMP between * every LOADK. The sequence ends in a LOADK. Any deviation and it's * not a list of constants. * * Here we check for this pattern almost exactly. We don't check that * the targets of the FORK and JUMP instructions are in the right * sequence. */ int all_const = 1; int commas = 0; int normal = 1; jv a = jv_array(); for (inst *i = expr.first; i; i = i->next) { if (i->op == FORK) { commas++; if (i->imm.target == NULL || i->imm.target->op != JUMP || jv_array_length(jv_copy(a)) > 0) { normal = 0; break; } } else if (all_const && i->op == LOADK) { if (i->next != NULL && i->next->op != JUMP) { normal = 0; break; } a = jv_array_append(a, jv_copy(i->imm.constant)); } else if (i->op != JUMP || i->imm.target == NULL || i->imm.target->op != LOADK) { all_const = 0; } } if (all_const && normal && (expr.last == NULL || expr.last->op == LOADK) && jv_array_length(jv_copy(a)) == commas + 1) { block_free(expr); return gen_const(a); } jv_free(a); block b = {0,0}; return b; } block gen_collect(block expr) { block const_array = gen_const_array(expr); if (const_array.first != NULL) return const_array; block array_var = gen_op_var_fresh(STOREV, "collect"); block c = BLOCK(gen_op_simple(DUP), gen_const(jv_array()), array_var); block tail = BLOCK(gen_op_bound(APPEND, array_var), gen_op_simple(BACKTRACK)); return BLOCK(c, gen_op_target(FORK, tail), expr, tail, gen_op_bound(LOADVN, array_var)); } static block bind_matcher(block matcher, block body) { // cannot call block_bind(matcher, body) because that requires // block_has_only_binders(matcher), which is not true here as matchers // may also contain code to extract the correct elements for (inst* i = matcher.first; i; i = i->next) { if ((i->op == STOREV || i->op == STOREVN) && !i->bound_by) block_bind_subblock(inst_block(i), body, OP_HAS_VARIABLE, 0); } return BLOCK(matcher, body); } // Extract destructuring var names from the block // *vars should be a jv_object (for set semantics) static void block_get_unbound_vars(block b, jv *vars) { assert(vars != NULL); assert(jv_get_kind(*vars) == JV_KIND_OBJECT); for (inst* i = b.first; i; i = i->next) { if (i->subfn.first) { block_get_unbound_vars(i->subfn, vars); continue; } if ((i->op == STOREV || i->op == STOREVN) && i->bound_by == NULL) { *vars = jv_object_set(*vars, jv_string(i->symbol), jv_true()); } } } /* Build wrappers around destructuring matchers so that we can chain them * when we have errors. The approach is as follows: * DESTRUCTURE_ALT NEXT_MATCHER (unless last matcher) * existing_matcher_block * JUMP BODY */ static block bind_alternation_matchers(block matchers, block body) { block preamble = {0}; block altmatchers = {0}; block mb = {0}; block final_matcher = matchers; // Pass through the matchers to find all destructured names. while (final_matcher.first && final_matcher.first->op == DESTRUCTURE_ALT) { block_append(&altmatchers, inst_block(block_take(&final_matcher))); } // We don't have any alternations here, so we can use the simplest case. if (altmatchers.first == NULL) { return bind_matcher(final_matcher, body); } // Collect var names jv all_vars = jv_object(); block_get_unbound_vars(altmatchers, &all_vars); block_get_unbound_vars(final_matcher, &all_vars); // We need a preamble of STOREVs to which to bind the matchers and the body. jv_object_keys_foreach(all_vars, key) { preamble = BLOCK(preamble, gen_op_simple(DUP), gen_const(jv_null()), gen_op_unbound(STOREV, jv_string_value(key))); jv_free(key); } jv_free(all_vars); // Now we build each matcher in turn for (inst *i = altmatchers.first; i; i = i->next) { block submatcher = i->subfn; // If we're successful, jump to the end of the matchers submatcher = BLOCK(submatcher, gen_op_target(JUMP, final_matcher)); // DESTRUCTURE_ALT to the end of this submatcher so we can skip to the next one on error mb = BLOCK(mb, gen_op_target(DESTRUCTURE_ALT, submatcher), submatcher); // We're done with this inst and we don't want it anymore // But we can't let it free the submatcher block. i->subfn.first = i->subfn.last = NULL; } // We're done with these insts now. block_free(altmatchers); return bind_matcher(preamble, BLOCK(mb, final_matcher, body)); } block gen_reduce(block source, block matcher, block init, block body) { block res_var = gen_op_var_fresh(STOREV, "reduce"); block loop = BLOCK(gen_op_simple(DUPN), source, bind_alternation_matchers(matcher, BLOCK(gen_op_bound(LOADVN, res_var), body, gen_op_bound(STOREV, res_var))), gen_op_simple(BACKTRACK)); return BLOCK(gen_op_simple(DUP), init, res_var, gen_op_target(FORK, loop), loop, gen_op_bound(LOADVN, res_var)); } block gen_foreach(block source, block matcher, block init, block update, block extract) { block state_var = gen_op_var_fresh(STOREV, "foreach"); return BLOCK(gen_op_simple(DUP), init, state_var, gen_op_simple(DUP), // get a value from the source expression: source, // destructure the value into variable(s) for all the code // in the body to see bind_alternation_matchers(matcher, // load the loop state variable BLOCK(gen_op_bound(LOADVN, state_var), // generate updated state update, // save the updated state for value extraction gen_op_simple(DUP), // save new state gen_op_bound(STOREV, state_var), // extract an output... extract))); } block gen_definedor(block a, block b) { // var found := false block found_var = gen_op_var_fresh(STOREV, "found"); 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_target(JUMP_F, backtrack), backtrack, gen_op_simple(POP), b); // try again block if_notfound = gen_op_simple(BACKTRACK); // found := true, produce result block if_found = BLOCK(gen_op_simple(DUP), gen_const(jv_true()), gen_op_bound(STOREV, found_var), gen_op_target(JUMP, tail)); return BLOCK(init, gen_op_target(FORK, if_notfound), a, gen_op_target(JUMP_F, if_found), if_found, if_notfound, tail); } int block_has_main(block top) { for (inst *c = top.first; c; c = c->next) { if (c->op == TOP) return 1; } return 0; } int block_is_funcdef(block b) { if (b.first != NULL && b.first->op == CLOSURE_CREATE) return 1; return 0; } block gen_condbranch(block iftrue, block iffalse) { iftrue = BLOCK(iftrue, gen_op_target(JUMP, iffalse)); return BLOCK(gen_op_target(JUMP_F, iftrue), iftrue, iffalse); } block gen_and(block a, block b) { // a and b = if a then (if b then true else false) else false return BLOCK(gen_op_simple(DUP), a, gen_condbranch(BLOCK(gen_op_simple(POP), b, gen_condbranch(gen_const(jv_true()), gen_const(jv_false()))), BLOCK(gen_op_simple(POP), gen_const(jv_false())))); } block gen_or(block a, block b) { // a or b = if a then true else (if b then true else false) return BLOCK(gen_op_simple(DUP), a, gen_condbranch(BLOCK(gen_op_simple(POP), gen_const(jv_true())), BLOCK(gen_op_simple(POP), b, gen_condbranch(gen_const(jv_true()), gen_const(jv_false()))))); } block gen_destructure_alt(block matcher) { for (inst *i = matcher.first; i; i = i->next) { if (i->op == STOREV) { i->op = STOREVN; } } inst* i = inst_new(DESTRUCTURE_ALT); i->subfn = matcher; return inst_block(i); } block gen_var_binding(block var, const char* name, block body) { return gen_destructure(var, gen_op_unbound(STOREV, name), body); } block gen_array_matcher(block left, block curr) { int index; if (block_is_noop(left)) index = 0; else { // `left` was returned by this function, so the third inst is the // constant containing the previously used index assert(left.first->op == DUP); assert(left.first->next != NULL); inst *i = NULL; if (left.first->next->op == PUSHK_UNDER) { i = left.first->next; } else { assert(left.first->next->op == SUBEXP_BEGIN); assert(left.first->next->next->op == LOADK); i = left.first->next->next; } index = 1 + (int) jv_number_value(i->imm.constant); } // `left` goes at the end so that the const index is in a predictable place return BLOCK(gen_op_simple(DUP), gen_subexp(gen_const(jv_number(index))), gen_op_simple(INDEX), curr, left); } block gen_object_matcher(block name, block curr) { return BLOCK(gen_op_simple(DUP), gen_subexp(name), gen_op_simple(INDEX), curr); } block gen_destructure(block var, block matchers, block body) { // var bindings can be added after coding the program; leave the TOP first. block top = gen_noop(); if (body.first && body.first->op == TOP) top = inst_block(block_take(&body)); if (matchers.first && matchers.first->op == DESTRUCTURE_ALT) { block_append(&var, gen_op_simple(DUP)); } else { top = BLOCK(top, gen_op_simple(DUP)); } return BLOCK(top, gen_subexp(var), gen_op_simple(POP), bind_alternation_matchers(matchers, body)); } // Like gen_var_binding(), but bind `break`'s wildcard unbound variable static block gen_wildvar_binding(block var, const char* name, block body) { return BLOCK(gen_op_simple(DUP), var, block_bind(gen_op_unbound(STOREV, name), body, OP_HAS_VARIABLE | OP_BIND_WILDCARD)); } block gen_cond(block cond, block iftrue, block iffalse) { return BLOCK(gen_op_simple(DUP), BLOCK(gen_subexp(cond), gen_op_simple(POP)), gen_condbranch(BLOCK(gen_op_simple(POP), iftrue), BLOCK(gen_op_simple(POP), iffalse))); } block gen_try(block exp, block handler) { /* * Produce: * * TRY_BEGIN handler * * TRY_END * JUMP past_handler * handler: * past_handler: * * If backtracks then TRY_BEGIN will backtrack. * * If produces a value then we'll execute whatever bytecode follows * this sequence. If that code raises an exception, then TRY_END will wrap * and re-raise that exception, and TRY_BEGIN will unwrap and re-raise the * exception (see jq_next()). * * If raises then the TRY_BEGIN will see a non-wrapped exception and * will jump to the handler (note the TRY_END will not execute in this case), * and if the handler produces any values, then we'll execute whatever * bytecode follows this sequence. Note that TRY_END will not execute in * this case, so if the handler raises an exception, or code past the handler * raises an exception, then that exception won't be wrapped and re-raised, * and the TRY_BEGIN will not catch it because it does not stack_save() when * it branches to the handler. */ if (block_is_noop(handler)) handler = BLOCK(gen_op_simple(DUP), gen_op_simple(POP)); block jump = gen_op_target(JUMP, handler); return BLOCK(gen_op_target(TRY_BEGIN, jump), exp, gen_op_simple(TRY_END), jump, handler); } block gen_label(const char *label, block exp) { block cond = gen_call("_equal", BLOCK(gen_lambda(gen_noop()), gen_lambda(gen_op_unbound(LOADV, label)))); return gen_wildvar_binding(gen_op_simple(GENLABEL), label, BLOCK(gen_op_simple(POP), // try exp catch if . == $label // then empty // else error end // // Can't use gen_binop(), as that's firmly // stuck in parser.y as it refers to things // like EQ. gen_try(exp, gen_cond(cond, gen_op_simple(BACKTRACK), gen_call("error", gen_noop()))))); } block gen_cbinding(const struct cfunction* cfunctions, int ncfunctions, block code) { for (int cfunc=0; cfuncimm.cfunc = &cfunctions[cfunc]; i->symbol = strdup(cfunctions[cfunc].name); i->nformals = cfunctions[cfunc].nargs - 1; i->any_unbound = 0; code = BLOCK(inst_block(i), code); } return code; } static uint16_t nesting_level(struct bytecode* bc, inst* target) { uint16_t level = 0; assert(bc && target && target->compiled); while (bc && target->compiled != bc) { level++; bc = bc->parent; } assert(bc && bc == target->compiled); return level; } static int count_cfunctions(block b) { int n = 0; for (inst* i = b.first; i; i = i->next) { if (i->op == CLOSURE_CREATE_C) n++; n += count_cfunctions(i->subfn); } return n; } #ifndef WIN32 extern char **environ; #endif static jv make_env(jv env) { if (jv_is_valid(env)) return jv_copy(env); jv r = jv_object(); if (environ == NULL) return r; for (size_t i = 0; environ[i] != NULL; i++) { const char *eq; if ((eq = strchr(environ[i], '=')) == NULL) r = jv_object_delete(r, jv_string(environ[i])); else r = jv_object_set(r, jv_string_sized(environ[i], eq - environ[i]), jv_string(eq + 1)); } return jv_copy(r); } // Expands call instructions into a calling sequence static int expand_call_arglist(block* b, jv args, jv *env) { int errors = 0; block ret = gen_noop(); for (inst* curr; (curr = block_take(b));) { if (opcode_describe(curr->op)->flags & OP_HAS_BINDING) { if (!curr->bound_by && curr->op == LOADV && strcmp(curr->symbol, "ENV") == 0) { curr->op = LOADK; *env = curr->imm.constant = make_env(*env); } else if (!curr->bound_by && curr->op == LOADV && jv_object_has(jv_copy(args), jv_string(curr->symbol))) { curr->op = LOADK; curr->imm.constant = jv_object_get(jv_copy(args), jv_string(curr->symbol)); } else if (!curr->bound_by) { if (curr->symbol[0] == '*' && curr->symbol[1] >= '1' && curr->symbol[1] <= '3' && curr->symbol[2] == '\0') locfile_locate(curr->locfile, curr->source, "jq: error: break used outside labeled control structure"); else if (curr->op == LOADV) locfile_locate(curr->locfile, curr->source, "jq: error: $%s is not defined", curr->symbol); else locfile_locate(curr->locfile, curr->source, "jq: error: %s/%d is not defined", curr->symbol, curr->nactuals); errors++; // don't process this instruction if it's not well-defined ret = BLOCK(ret, inst_block(curr)); continue; } } block prelude = gen_noop(); if (curr->op == CALL_JQ) { int actual_args = 0, desired_args = 0; // We expand the argument list as a series of instructions switch (curr->bound_by->op) { default: assert(0 && "Unknown function type"); break; case CLOSURE_CREATE: case CLOSURE_PARAM: { block callargs = gen_noop(); for (inst* i; (i = block_take(&curr->arglist));) { assert(opcode_describe(i->op)->flags & OP_IS_CALL_PSEUDO); block b = inst_block(i); switch (i->op) { default: assert(0 && "Unknown type of parameter"); break; case CLOSURE_REF: block_append(&callargs, b); break; case CLOSURE_CREATE: block_append(&prelude, b); block_append(&callargs, gen_op_bound(CLOSURE_REF, b)); break; } actual_args++; } curr->imm.intval = actual_args; curr->arglist = callargs; if (curr->bound_by->op == CLOSURE_CREATE) { for (inst* i = curr->bound_by->arglist.first; i; i = i->next) { assert(i->op == CLOSURE_PARAM); desired_args++; } } break; } case CLOSURE_CREATE_C: { for (inst* i; (i = block_take(&curr->arglist)); ) { assert(i->op == CLOSURE_CREATE); // FIXME block body = i->subfn; i->subfn = gen_noop(); inst_free(i); // arguments should be pushed in reverse order, prepend them to prelude errors += expand_call_arglist(&body, args, env); prelude = BLOCK(gen_subexp(body), prelude); actual_args++; } assert(curr->op == CALL_JQ); curr->op = CALL_BUILTIN; curr->imm.intval = actual_args + 1 /* include the implicit input in arg count */; assert(curr->bound_by->op == CLOSURE_CREATE_C); desired_args = curr->bound_by->imm.cfunc->nargs - 1; assert(!curr->arglist.first); break; } } assert(actual_args == desired_args); // because now handle this above } ret = BLOCK(ret, prelude, inst_block(curr)); } *b = ret; return errors; } static int compile(struct bytecode* bc, block b, struct locfile* lf, jv args, jv *env) { int errors = 0; int pos = 0; int var_frame_idx = 0; bc->nsubfunctions = 0; errors += expand_call_arglist(&b, args, env); 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) { for (inst* arg = curr->arglist.first; arg; arg = arg->next) { length += 2; } } pos += length; curr->bytecode_pos = pos; curr->compiled = bc; assert(curr->op != CLOSURE_REF && curr->op != CLOSURE_PARAM); if ((opcode_describe(curr->op)->flags & OP_HAS_VARIABLE) && curr->bound_by == curr) { curr->imm.intval = var_frame_idx++; localnames = jv_array_append(localnames, jv_string(curr->symbol)); } if (curr->op == CLOSURE_CREATE) { assert(curr->bound_by == curr); // Prevent subfunction index from overflowing into ARG_NEWCLOSURE flag if (bc->nsubfunctions >= ARG_NEWCLOSURE) { locfile_locate(lf, curr->source, "too many function parameters or local function definitions (max %d)", ARG_NEWCLOSURE - 1); errors++; break; } curr->imm.intval = bc->nsubfunctions++; } if (curr->op == CLOSURE_CREATE_C) { assert(curr->bound_by == curr); int idx = bc->globals->ncfunctions++; bc->globals->cfunc_names = jv_array_append(bc->globals->cfunc_names, jv_string(curr->symbol)); bc->globals->cfunctions[idx] = *curr->imm.cfunc; curr->imm.intval = idx; } } if (pos > 0xFFFF) { // too long for program counter to fit in uint16_t locfile_locate(lf, UNKNOWN_LOCATION, "function compiled to %d bytes which is too long", pos); errors++; } bc->codelen = pos; bc->debuginfo = jv_object_set(bc->debuginfo, jv_string("locals"), localnames); if (bc->nsubfunctions && !errors) { bc->subfunctions = jv_mem_calloc(bc->nsubfunctions, sizeof(struct bytecode*)); for (inst* curr = b.first; curr; curr = curr->next) { if (curr->op == CLOSURE_CREATE) { struct bytecode* subfn = jv_mem_alloc(sizeof(struct bytecode)); bc->subfunctions[curr->imm.intval] = subfn; subfn->globals = bc->globals; subfn->parent = bc; subfn->nclosures = 0; subfn->debuginfo = jv_object_set(jv_object(), jv_string("name"), jv_string(curr->symbol)); jv params = jv_array(); for (inst* param = curr->arglist.first; param; param = param->next) { assert(param->op == CLOSURE_PARAM); assert(param->bound_by == param); // Prevent closure index from overflowing into ARG_NEWCLOSURE flag if (subfn->nclosures >= ARG_NEWCLOSURE) { locfile_locate(lf, curr->source, "function has too many parameters (max %d)", ARG_NEWCLOSURE - 1); errors++; break; } param->imm.intval = subfn->nclosures++; param->compiled = subfn; params = jv_array_append(params, jv_string(param->symbol)); } subfn->debuginfo = jv_object_set(subfn->debuginfo, jv_string("params"), params); errors += compile(subfn, curr->subfn, lf, args, env); curr->subfn = gen_noop(); } } } else { bc->nsubfunctions = 0; bc->subfunctions = 0; } uint16_t* code = jv_mem_calloc(bc->codelen, sizeof(uint16_t)); bc->code = code; pos = 0; jv constant_pool = jv_array(); int maxvar = -1; if (!errors) for (inst* curr = b.first; curr; curr = curr->next) { const struct opcode_description* op = opcode_describe(curr->op); if (op->length == 0) continue; code[pos++] = curr->op; assert(curr->op != CLOSURE_REF && curr->op != CLOSURE_PARAM); if (curr->op == CALL_BUILTIN) { assert(curr->bound_by->op == CLOSURE_CREATE_C); assert(!curr->arglist.first); code[pos++] = (uint16_t)curr->imm.intval; code[pos++] = curr->bound_by->imm.intval; } 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; code[pos++] = nesting_level(bc, curr->bound_by); code[pos++] = curr->bound_by->imm.intval | (curr->bound_by->op == CLOSURE_CREATE ? ARG_NEWCLOSURE : 0); for (inst* arg = curr->arglist.first; arg; arg = arg->next) { assert(arg->op == CLOSURE_REF && arg->bound_by->op == CLOSURE_CREATE); code[pos++] = nesting_level(bc, arg->bound_by); code[pos++] = arg->bound_by->imm.intval | ARG_NEWCLOSURE; } } else if ((op->flags & OP_HAS_CONSTANT) && (op->flags & OP_HAS_VARIABLE)) { // STORE_GLOBAL: constant global, basically code[pos++] = jv_array_length(jv_copy(constant_pool)); constant_pool = jv_array_append(constant_pool, jv_copy(curr->imm.constant)); code[pos++] = nesting_level(bc, curr->bound_by); uint16_t var = (uint16_t)curr->bound_by->imm.intval; code[pos++] = var; if (var > maxvar) maxvar = var; } else if (op->flags & OP_HAS_CONSTANT) { code[pos++] = jv_array_length(jv_copy(constant_pool)); constant_pool = jv_array_append(constant_pool, jv_copy(curr->imm.constant)); } else if (op->flags & OP_HAS_VARIABLE) { code[pos++] = nesting_level(bc, curr->bound_by); uint16_t var = (uint16_t)curr->bound_by->imm.intval; code[pos++] = var; if (var > maxvar) maxvar = var; } else if (op->flags & OP_HAS_BRANCH) { assert(curr->imm.target->bytecode_pos != -1); assert(curr->imm.target->bytecode_pos > pos); // only forward branches code[pos] = curr->imm.target->bytecode_pos - (pos + 1); pos++; } else if (op->length > 1) { assert(0 && "codegen not implemented for this operation"); } } bc->constants = constant_pool; bc->nlocals = maxvar + 2; // FIXME: frames of size zero? block_free(b); return errors; } int block_compile(block b, struct bytecode** out, struct locfile* lf, jv args) { struct bytecode* bc = jv_mem_alloc(sizeof(struct bytecode)); bc->parent = 0; bc->nclosures = 0; bc->globals = jv_mem_alloc(sizeof(struct symbol_table)); int ncfunc = count_cfunctions(b); bc->globals->ncfunctions = 0; bc->globals->cfunctions = jv_mem_calloc(MAX(ncfunc, 1), sizeof(struct cfunction)); bc->globals->cfunc_names = jv_array(); bc->debuginfo = jv_object_set(jv_object(), jv_string("name"), jv_null()); jv env = jv_invalid(); int nerrors = compile(bc, b, lf, args, &env); jv_free(args); jv_free(env); assert(bc->globals->ncfunctions == ncfunc); if (nerrors > 0) { bytecode_free(bc); *out = 0; } else { *out = bc; } return nerrors; } void block_free(block b) { struct inst* next; for (struct inst* curr = b.first; curr; curr = next) { next = curr->next; inst_free(curr); } } ================================================ FILE: src/compile.h ================================================ #ifndef COMPILE_H #define COMPILE_H #include #include "jv.h" #include "bytecode.h" #include "locfile.h" struct inst; typedef struct inst inst; typedef struct block { inst* first; inst* last; } block; block gen_location(location, struct locfile*, block); block gen_noop(void); int block_is_noop(block b); block gen_op_simple(opcode op); block gen_error(jv constant); block gen_const(jv constant); block gen_const_global(jv constant, const char *name); int block_is_const(block b); jv_kind block_const_kind(block b); jv block_const(block b); 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_pushk_under(jv constant); block gen_module(block metadata); jv block_module_meta(block b); block gen_import(const char* name, const char *as, int is_data); block gen_import_meta(block import, block metadata); block gen_function(const char* name, block formals, block body); block gen_param_regular(const char* name); block gen_param(const char* name); block gen_lambda(block body); block gen_call(const char* name, block body); block gen_subexp(block a); block gen_both(block a, block b); block gen_const_object(block expr); block gen_collect(block expr); block gen_reduce(block source, block matcher, block init, block body); block gen_foreach(block source, block matcher, block init, block update, block extract); block gen_definedor(block a, block b); block gen_condbranch(block iftrue, block iffalse); block gen_and(block a, block b); block gen_or(block a, block b); block gen_dictpair(block k, block v); block gen_var_binding(block var, const char* name, block body); block gen_array_matcher(block left, block curr); block gen_object_matcher(block name, block curr); block gen_destructure(block var, block matcher, block body); block gen_destructure_alt(block matcher); block gen_cond(block cond, block iftrue, block iffalse); block gen_try(block exp, block handler); block gen_label(const char *label, block exp); block gen_cbinding(const struct cfunction* functions, int nfunctions, block b); void block_append(block* b, block b2); block block_join(block a, block b); int block_has_only_binders_and_imports(block, int bindflags); int block_has_only_binders(block, int bindflags); int block_has_main(block); int block_is_funcdef(block b); int block_is_single(block b); block block_bind_library(block binder, block body, int bindflags, const char* libname); block block_bind_referenced(block binder, block body, int bindflags); block block_bind_self(block binder, int bindflags); block block_drop_unreferenced(block body); jv block_take_imports(block* body); jv block_list_funcs(block body, int omit_underscores); int block_compile(block, struct bytecode**, struct locfile*, jv); void block_free(block); // Here's some horrible preprocessor gunk so that code // sequences can be constructed as BLOCK(block1, block2, block3) #define BLOCK_1(b1) (b1) #define BLOCK_2(b1,b2) (block_join((b1),(b2))) #define BLOCK_3(b1,b2,b3) (block_join(BLOCK_2(b1,b2),(b3))) #define BLOCK_4(b1,b2,b3,b4) (block_join(BLOCK_3(b1,b2,b3),(b4))) #define BLOCK_5(b1,b2,b3,b4,b5) (block_join(BLOCK_4(b1,b2,b3,b4),(b5))) #define BLOCK_6(b1,b2,b3,b4,b5,b6) (block_join(BLOCK_5(b1,b2,b3,b4,b5),(b6))) #define BLOCK_7(b1,b2,b3,b4,b5,b6,b7) (block_join(BLOCK_6(b1,b2,b3,b4,b5,b6),(b7))) #define BLOCK_8(b1,b2,b3,b4,b5,b6,b7,b8) (block_join(BLOCK_7(b1,b2,b3,b4,b5,b6,b7),(b8))) #define BLOCK_IDX(_1,_2,_3,_4,_5,_6,_7,_8,NAME,...) NAME #define BLOCK(...) \ BLOCK_IDX(__VA_ARGS__, BLOCK_8, BLOCK_7, BLOCK_6, BLOCK_5, BLOCK_4, BLOCK_3, BLOCK_2, BLOCK_1)(__VA_ARGS__) #endif ================================================ FILE: src/exec_stack.h ================================================ #ifndef EXEC_STACK_H #define EXEC_STACK_H #include #include #include #include #include "jv_alloc.h" /* * The stack is a directed forest of variably sized blocks. Each block has a * "next" block which is at a higher memory address, or 0 if the block has no * "next" block. More than one block may have no "next" block. A block may be * the "next" block of more than one other block. Pushed blocks are added at * the low-address end of the stack. * * Stack pointers are negative integers that are offsets relative to "mem_end", * the end of the allocated region. The stack "bound" is the stack pointer of * the last block that would be able to fit in the currently allocated region. * The stack "limit" is the stack pointer of the last block currently in the * stack. The stack pointer of the "next" block is stored directly below each * block. * * <- mem_end = 0x100 * 0xF8 +------------+ * 0xF0 | | * 0xE8 +------------+ <- stack_ptr1 = -0x18 * 0xE0 next = 0 * 0xD8 +------------+ * 0xD0 | | * 0xC8 | | * 0xC0 +------------+ <- stack_ptr2 = limit = -0x40 * 0xB8 next = -0x18 * 0xB0 * 0xA8 <- bound = -0x58 * 0xA0 */ 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"); if(s->mem_end != NULL) { 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 != NULL) ? (s->mem_end - old_mem_length) : NULL; int new_mem_length = align_round_up((old_mem_length + sz + 256) * 2); char* new_mem_start = jv_mem_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 ================================================ FILE: src/execute.c ================================================ #include #include #include #include #include #include #include #include "exec_stack.h" #include "bytecode.h" #include "jv_alloc.h" #include "locfile.h" #include "jv.h" #include "jq.h" #include "builtin.h" #include "linker.h" struct jq_state { void (*nomem_handler)(void *); void *nomem_handler_data; struct bytecode* bc; jq_msg_cb err_cb; void *err_cb_data; jv error; struct stack stk; stack_ptr curr_frame; stack_ptr stk_top; stack_ptr fork_top; jv path; jv value_at_path; int subexp_nest; int debug_trace_enabled; int initial_execution; unsigned next_label; int halted; jv exit_code; jv error_message; jv attrs; jq_input_cb input_cb; void *input_cb_data; jq_msg_cb debug_cb; void *debug_cb_data; jq_msg_cb stderr_cb; void *stderr_cb_data; }; 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[]; // 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; istk, 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; iclosure = make_closure(jq, argdef + i * 2); entries++; } for (int i=0; inlocals; 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; icurr_frame = stack_pop_block(&jq->stk, jq->curr_frame, frame_size(fp->bc)); } 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; } 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)) { val = jv_copy(val); } jq->stk_top = stack_pop_block(&jq->stk, jq->stk_top, sizeof(jv)); assert(jv_is_valid(val)); return val; } // Like stack_pop(), but assert !stack_pop_will_free() and replace with // jv_null() on the stack. jv stack_popn(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)) { *sval = jv_null(); } jq->stk_top = stack_pop_block(&jq->stk, jq->stk_top, sizeof(jv)); assert(jv_is_valid(val)); return val; } struct forkpoint { stack_ptr saved_data_stack; stack_ptr saved_curr_frame; int path_len, subexp_nest; jv value_at_path; 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; fork->path_len = jv_get_kind(jq->path) == JV_KIND_ARRAY ? jv_array_length(jv_copy(jq->path)) : 0; fork->value_at_path = jv_copy(jq->value_at_path); fork->subexp_nest = jq->subexp_nest; fork->return_address = retaddr; jq->stk_top = sp.saved_data_stack; jq->curr_frame = sp.saved_curr_frame; } static int path_intact(jq_state *jq, jv curr) { if (jq->subexp_nest == 0 && jv_get_kind(jq->path) == JV_KIND_ARRAY) { return jv_identical(curr, jv_copy(jq->value_at_path)); } else { jv_free(curr); return 1; } } static void path_append(jq_state* jq, jv component, jv value_at_path) { if (jq->subexp_nest == 0 && jv_get_kind(jq->path) == JV_KIND_ARRAY) { int n1 = jv_array_length(jv_copy(jq->path)); jq->path = jv_array_append(jq->path, component); int n2 = jv_array_length(jv_copy(jq->path)); assert(n2 == n1 + 1); jv_free(jq->value_at_path); jq->value_at_path = value_at_path; } else { jv_free(component); jv_free(value_at_path); } } /* For f_getpath() */ jv _jq_path_append(jq_state *jq, jv v, jv p, jv value_at_path) { if (jq->subexp_nest != 0 || jv_get_kind(jq->path) != JV_KIND_ARRAY || !jv_is_valid(value_at_path)) { jv_free(v); jv_free(p); return value_at_path; } if (!jv_identical(v, jv_copy(jq->value_at_path))) { jv_free(p); return value_at_path; } if (jv_get_kind(p) == JV_KIND_ARRAY) jq->path = jv_array_concat(jq->path, p); else jq->path = jv_array_append(jq->path, p); jv_free(jq->value_at_path); return jv_copy(jq->value_at_path = value_at_path); } 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); } } if (jq->fork_top == 0) { return 0; } struct forkpoint* fork = stack_block(&jq->stk, jq->fork_top); uint16_t* retaddr = fork->return_address; jq->stk_top = fork->saved_data_stack; jq->curr_frame = fork->saved_curr_frame; int path_len = fork->path_len; if (jv_get_kind(jq->path) == JV_KIND_ARRAY) { assert(path_len >= 0); jq->path = jv_array_slice(jq->path, 0, path_len); } else { fork->path_len = 0; } jv_free(jq->value_at_path); jq->value_at_path = fork->value_at_path; jq->subexp_nest = fork->subexp_nest; jq->fork_top = stack_pop_block(&jq->stk, jq->fork_top, sizeof(struct forkpoint)); 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); jv_free(jq->error); jq->error = jv_null(); jq->halted = 0; jv_free(jq->exit_code); jq->exit_code = jv_invalid(); jv_free(jq->error_message); jq->error_message = jv_invalid(); if (jv_get_kind(jq->path) != JV_KIND_INVALID) jv_free(jq->path); jq->path = jv_null(); jv_free(jq->value_at_path); jq->value_at_path = jv_null(); jq->subexp_nest = 0; } void jq_report_error(jq_state *jq, jv value) { assert(jq->err_cb); // callback must jv_free() its jv argument jq->err_cb(jq->err_cb_data, value); } static void set_error(jq_state *jq, jv value) { // Record so try/catch can find it. jv_free(jq->error); jq->error = value; } #define ON_BACKTRACK(op) ((op)+NUM_OPCODES) jv jq_next(jq_state *jq) { jv_nomem_handler(jq->nomem_handler, jq->nomem_handler_data); uint16_t* pc = stack_restore(jq); assert(pc); int raising; int backtracking = !jq->initial_execution; jq->initial_execution = 0; assert(jv_get_kind(jq->error) == JV_KIND_NULL); while (1) { if (jq->halted) { if (jq->debug_trace_enabled) printf("\t\n"); return jv_invalid(); } uint16_t opcode = *pc; raising = 0; if (jq->debug_trace_enabled) { dump_operation(frame_current(jq)->bc, 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]; param = jq->stk_top; for (int i=0; istk, param); } if (!param) break; jv_dump(jv_copy(*(jv*)stack_block(&jq->stk, param)), JV_PRINT_REFCOUNT); //printf("<%d>", jv_get_refcnt(param->val)); //printf(" -- "); //jv_dump(jv_copy(jq->path), 0); } if (jq->debug_trace_enabled & JQ_DEBUG_TRACE_DETAIL) { while ((param = *stack_block_next(&jq->stk, param))) { printf(" || "); jv_dump(jv_copy(*(jv*)stack_block(&jq->stk, param)), JV_PRINT_REFCOUNT); } } } else { printf("\t"); } printf("\n"); } if (backtracking) { opcode = ON_BACKTRACK(opcode); backtracking = 0; raising = !jv_is_valid(jq->error); } pc++; switch (opcode) { default: assert(0 && "invalid instruction"); case TOP: break; case ERRORK: { jv v = jv_array_get(jv_copy(frame_current(jq)->bc->constants), *pc++); set_error(jq, jv_invalid_with_msg(v)); goto do_backtrack; } case LOADK: { jv v = jv_array_get(jv_copy(frame_current(jq)->bc->constants), *pc++); assert(jv_is_valid(v)); jv_free(stack_pop(jq)); stack_push(jq, v); break; } case GENLABEL: { stack_push(jq, JV_OBJECT(jv_string("__jq"), jv_number(jq->next_label++))); break; } case DUP: { jv v = stack_pop(jq); stack_push(jq, jv_copy(v)); stack_push(jq, v); break; } case DUPN: { jv v = stack_popn(jq); stack_push(jq, jv_copy(v)); stack_push(jq, v); break; } case DUP2: { jv keep = stack_pop(jq); jv v = stack_pop(jq); stack_push(jq, jv_copy(v)); stack_push(jq, keep); stack_push(jq, v); break; } case SUBEXP_BEGIN: { jv v = stack_pop(jq); stack_push(jq, jv_copy(v)); stack_push(jq, v); jq->subexp_nest++; break; } case SUBEXP_END: { assert(jq->subexp_nest > 0); jq->subexp_nest--; jv a = stack_pop(jq); jv b = stack_pop(jq); stack_push(jq, a); stack_push(jq, b); break; } case PUSHK_UNDER: { jv v = jv_array_get(jv_copy(frame_current(jq)->bc->constants), *pc++); assert(jv_is_valid(v)); jv v2 = stack_pop(jq); stack_push(jq, v); stack_push(jq, v2); break; } case POP: { jv_free(stack_pop(jq)); break; } case APPEND: { jv v = stack_pop(jq); uint16_t level = *pc++; uint16_t vidx = *pc++; jv* var = frame_local_var(jq, vidx, level); assert(jv_get_kind(*var) == JV_KIND_ARRAY); *var = jv_array_append(*var, v); break; } case INSERT: { jv stktop = stack_pop(jq); jv v = stack_pop(jq); jv k = stack_pop(jq); jv objv = stack_pop(jq); assert(jv_get_kind(objv) == JV_KIND_OBJECT); if (jv_get_kind(k) == JV_KIND_STRING) { stack_push(jq, jv_object_set(objv, k, v)); stack_push(jq, stktop); } else { char errbuf[30]; set_error(jq, jv_invalid_with_msg(jv_string_fmt( "Cannot use %s (%s) as object key", jv_kind_name(jv_get_kind(k)), jv_dump_string_trunc(jv_copy(k), errbuf, sizeof(errbuf))))); jv_free(stktop); jv_free(v); jv_free(k); jv_free(objv); goto do_backtrack; } break; } case ON_BACKTRACK(RANGE): case RANGE: { uint16_t level = *pc++; uint16_t v = *pc++; jv* var = frame_local_var(jq, v, level); jv max = stack_pop(jq); if (raising) { jv_free(max); goto do_backtrack; } if (jv_get_kind(*var) != JV_KIND_NUMBER || jv_get_kind(max) != JV_KIND_NUMBER) { set_error(jq, jv_invalid_with_msg(jv_string_fmt("Range bounds must be numeric"))); jv_free(max); goto do_backtrack; } else if (jv_number_value(*var) >= jv_number_value(max)) { /* finished iterating */ jv_free(max); goto do_backtrack; } else { jv curr = *var; *var = jv_number(jv_number_value(*var) + 1); struct stack_pos spos = stack_get_pos(jq); stack_push(jq, max); stack_save(jq, pc - 3, spos); stack_push(jq, curr); } break; } // FIXME: loadv/storev may do too much copying/freeing case LOADV: { uint16_t level = *pc++; uint16_t v = *pc++; jv* var = frame_local_var(jq, v, level); if (jq->debug_trace_enabled) { printf("V%d = ", v); jv_dump(jv_copy(*var), JV_PRINT_REFCOUNT); printf("\n"); } jv_free(stack_pop(jq)); stack_push(jq, jv_copy(*var)); break; } // Does a load but replaces the variable with null case LOADVN: { uint16_t level = *pc++; uint16_t v = *pc++; jv* var = frame_local_var(jq, v, level); if (jq->debug_trace_enabled) { printf("V%d = ", v); jv_dump(jv_copy(*var), JV_PRINT_REFCOUNT); printf("\n"); } jv_free(stack_popn(jq)); // This `stack_push()` invalidates the `var` reference, so stack_push(jq, *var); // we have to re-resolve `var` before we can set it to null var = frame_local_var(jq, v, level); *var = jv_null(); break; } case STOREVN: stack_save(jq, pc - 1, stack_get_pos(jq)); JQ_FALLTHROUGH; case STOREV: { uint16_t level = *pc++; uint16_t v = *pc++; jv* var = frame_local_var(jq, v, level); jv val = stack_pop(jq); if (jq->debug_trace_enabled) { printf("V%d = ", v); jv_dump(jv_copy(val), 0); printf(" (%d)\n", jv_get_refcnt(val)); } jv_free(*var); *var = val; break; } case ON_BACKTRACK(STOREVN): { uint16_t level = *pc++; uint16_t v = *pc++; jv* var = frame_local_var(jq, v, level); jv_free(*var); *var = jv_null(); goto do_backtrack; break; } case STORE_GLOBAL: { // Get the constant jv val = jv_array_get(jv_copy(frame_current(jq)->bc->constants), *pc++); assert(jv_is_valid(val)); // Store the var uint16_t level = *pc++; uint16_t v = *pc++; jv* var = frame_local_var(jq, v, level); if (jq->debug_trace_enabled) { printf("V%d = ", v); jv_dump(jv_copy(val), 0); printf(" (%d)\n", jv_get_refcnt(val)); } jv_free(*var); *var = val; break; } case PATH_BEGIN: { jv v = stack_pop(jq); stack_push(jq, jq->path); stack_save(jq, pc - 1, stack_get_pos(jq)); stack_push(jq, jv_number(jq->subexp_nest)); stack_push(jq, jq->value_at_path); stack_push(jq, jv_copy(v)); jq->path = jv_array(); jq->value_at_path = v; // next INDEX operation must index into v jq->subexp_nest = 0; break; } case PATH_END: { jv v = stack_pop(jq); // detect invalid path expression like path(.a | reverse) if (!path_intact(jq, jv_copy(v))) { char errbuf[30]; jv msg = jv_string_fmt( "Invalid path expression with result %s", jv_dump_string_trunc(v, errbuf, sizeof(errbuf))); set_error(jq, jv_invalid_with_msg(msg)); goto do_backtrack; } jv_free(v); // discard value, only keep path jv old_value_at_path = stack_pop(jq); int old_subexp_nest = (int)jv_number_value(stack_pop(jq)); jv path = jq->path; jq->path = stack_pop(jq); struct stack_pos spos = stack_get_pos(jq); stack_push(jq, jv_copy(path)); stack_save(jq, pc - 1, spos); stack_push(jq, path); jq->subexp_nest = old_subexp_nest; jv_free(jq->value_at_path); jq->value_at_path = old_value_at_path; break; } case ON_BACKTRACK(PATH_BEGIN): case ON_BACKTRACK(PATH_END): { jv_free(jq->path); jq->path = stack_pop(jq); goto do_backtrack; } case INDEX: case INDEX_OPT: { jv t = stack_pop(jq); jv k = stack_pop(jq); // detect invalid path expression like path(reverse | .a) if (!path_intact(jq, jv_copy(t))) { char keybuf[30]; char objbuf[30]; jv msg = jv_string_fmt( "Invalid path expression near attempt to access element %s of %s", jv_dump_string_trunc(k, keybuf, sizeof(keybuf)), jv_dump_string_trunc(t, objbuf, sizeof(objbuf))); set_error(jq, jv_invalid_with_msg(msg)); goto do_backtrack; } jv v = jv_get(t, jv_copy(k)); if (jv_is_valid(v)) { path_append(jq, k, jv_copy(v)); stack_push(jq, v); } else { jv_free(k); if (opcode == INDEX) set_error(jq, v); else jv_free(v); goto do_backtrack; } break; } case JUMP: { uint16_t offset = *pc++; pc += offset; break; } case JUMP_F: { uint16_t offset = *pc++; jv t = stack_pop(jq); jv_kind kind = jv_get_kind(t); if (kind == JV_KIND_FALSE || kind == JV_KIND_NULL) { pc += offset; } stack_push(jq, t); // FIXME do this better break; } case EACH: case EACH_OPT: { jv container = stack_pop(jq); // detect invalid path expression like path(reverse | .[]) if (!path_intact(jq, jv_copy(container))) { char errbuf[30]; jv msg = jv_string_fmt( "Invalid path expression near attempt to iterate through %s", jv_dump_string_trunc(container, errbuf, sizeof(errbuf))); set_error(jq, jv_invalid_with_msg(msg)); goto do_backtrack; } stack_push(jq, container); stack_push(jq, jv_number(-1)); JQ_FALLTHROUGH; } case ON_BACKTRACK(EACH): case ON_BACKTRACK(EACH_OPT): { 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; else idx = idx + 1; int len = jv_array_length(jv_copy(container)); keep_going = idx < len; is_last = idx == len - 1; if (keep_going) { key = jv_number(idx); 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); else idx = jv_object_iter_next(container, idx); keep_going = jv_object_iter_valid(container, idx); if (keep_going) { key = jv_object_iter_key(container, idx); value = jv_object_iter_value(container, idx); } } else { assert(opcode == EACH || opcode == EACH_OPT); if (opcode == EACH) { char errbuf[30]; set_error(jq, jv_invalid_with_msg(jv_string_fmt( "Cannot iterate over %s (%s)", jv_kind_name(jv_get_kind(container)), jv_dump_string_trunc(jv_copy(container), errbuf, sizeof(errbuf))))); } keep_going = 0; } if (!keep_going || raising) { if (keep_going) { jv_free(key); jv_free(value); } jv_free(container); goto do_backtrack; } else if (is_last) { // we don't need to make a backtrack point jv_free(container); path_append(jq, key, jv_copy(value)); stack_push(jq, value); } else { struct stack_pos spos = stack_get_pos(jq); stack_push(jq, container); stack_push(jq, jv_number(idx)); stack_save(jq, pc - 1, spos); path_append(jq, key, jv_copy(value)); stack_push(jq, value); } break; } do_backtrack: case BACKTRACK: { pc = stack_restore(jq); if (!pc) { if (!jv_is_valid(jq->error)) { jv error = jq->error; jq->error = jv_null(); return error; } return jv_invalid(); } backtracking = 1; break; } case TRY_BEGIN: stack_save(jq, pc - 1, stack_get_pos(jq)); pc++; // skip handler offset this time break; case TRY_END: stack_save(jq, pc - 1, stack_get_pos(jq)); break; case ON_BACKTRACK(TRY_BEGIN): { if (!raising) { /* * `try EXP ...` -- EXP backtracked (e.g., EXP was `empty`), so we * backtrack more: */ jv_free(stack_pop(jq)); goto do_backtrack; } /* * Else `(try EXP ... ) | EXP2` raised an error. * * If the error was wrapped in another error, then that means EXP2 raised * the error. We unwrap it and re-raise it as it wasn't raised by EXP. * * See commentary in gen_try(). */ jv e = jv_invalid_get_msg(jv_copy(jq->error)); if (!jv_is_valid(e) && jv_invalid_has_msg(jv_copy(e))) { set_error(jq, e); goto do_backtrack; } jv_free(e); /* * Else we caught an error containing a non-error value, so we jump to * the handler. * * See commentary in gen_try(). */ uint16_t offset = *pc++; jv_free(stack_pop(jq)); // free the input stack_push(jq, jv_invalid_get_msg(jq->error)); // push the error's message jq->error = jv_null(); pc += offset; break; } case ON_BACKTRACK(TRY_END): // Wrap the error so the matching TRY_BEGIN doesn't catch it if (raising) set_error(jq, jv_invalid_with_msg(jv_copy(jq->error))); goto do_backtrack; case DESTRUCTURE_ALT: case FORK: { stack_save(jq, pc - 1, stack_get_pos(jq)); pc++; // skip offset this time break; } case ON_BACKTRACK(DESTRUCTURE_ALT): { if (jv_is_valid(jq->error)) { // `try EXP ...` backtracked here (no value, `empty`), so we backtrack more jv_free(stack_pop(jq)); goto do_backtrack; } // `try EXP ...` exception caught in EXP // DESTRUCTURE_ALT doesn't want the error message on the stack, // as we would just want to throw it away anyway. if (opcode != ON_BACKTRACK(DESTRUCTURE_ALT)) { jv_free(stack_pop(jq)); // free the input stack_push(jq, jv_invalid_get_msg(jq->error)); // push the error's message } else { jv_free(jq->error); } jq->error = jv_null(); uint16_t offset = *pc++; pc += offset; break; } case ON_BACKTRACK(FORK): { if (raising) goto do_backtrack; uint16_t offset = *pc++; pc += offset; break; } case CALL_BUILTIN: { int nargs = *pc++; struct cfunction* function = &frame_current(jq)->bc->globals->cfunctions[*pc++]; jv in[MAX_CFUNCTION_ARGS]; for (int i = 0; i < nargs; ++i) in[i] = stack_pop(jq); jv top; switch (function->nargs) { case 1: top = function->fptr.a1(jq, in[0]); break; case 2: top = function->fptr.a2(jq, in[0], in[1]); break; case 3: top = function->fptr.a3(jq, in[0], in[1], in[2]); break; case 4: top = function->fptr.a4(jq, in[0], in[1], in[2], in[3]); break; default: assert(0 && "Invalid number of arguments"); } if (!jv_is_valid(top)) { if (jv_invalid_has_msg(jv_copy(top))) set_error(jq, top); else jv_free(top); goto do_backtrack; } stack_push(jq, top); break; } case TAIL_CALL_JQ: case CALL_JQ: { /* * Bytecode layout here: * * CALL_JQ * (i.e., number of call arguments) * (what we're calling) * (frame reference + code pointer) * * * * 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); } 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); break; } case RET: { jv value = stack_pop(jq); assert(jq->stk_top == frame_current(jq)->retdata); uint16_t* retaddr = frame_current(jq)->retaddr; if (retaddr) { // function return pc = retaddr; frame_pop(jq); } else { // top-level return, yielding value struct stack_pos spos = stack_get_pos(jq); stack_push(jq, jv_null()); stack_save(jq, pc - 1, spos); return value; } stack_push(jq, value); break; } case ON_BACKTRACK(RET): { // resumed after top-level return goto do_backtrack; } } } } jv jq_format_error(jv msg) { if (jv_get_kind(msg) == JV_KIND_NULL || (jv_get_kind(msg) == JV_KIND_INVALID && !jv_invalid_has_msg(jv_copy(msg)))) { jv_free(msg); fprintf(stderr, "jq: error: out of memory\n"); return jv_null(); } if (jv_get_kind(msg) == JV_KIND_STRING) return msg; // expected to already be formatted if (jv_get_kind(msg) == JV_KIND_INVALID) msg = jv_invalid_get_msg(msg); if (jv_get_kind(msg) == JV_KIND_NULL) return jq_format_error(msg); // ENOMEM // Invalid with msg; prefix with "jq: error: " if (jv_get_kind(msg) != JV_KIND_INVALID) { if (jv_get_kind(msg) == JV_KIND_STRING) { jv r = jv_string_fmt("jq: error: %s", jv_string_value(msg)); jv_free(msg); return r; } msg = jv_dump_string(msg, JV_PRINT_INVALID); if (jv_get_kind(msg) == JV_KIND_STRING) { jv r = jv_string_fmt("jq: error: %s", jv_string_value(msg)); jv_free(msg); return r; } jv_free(msg); return jq_format_error(jv_null()); // ENOMEM } // An invalid inside an invalid! return jq_format_error(jv_invalid_get_msg(msg)); } // XXX Refactor into a utility function that returns a jv and one that // uses it and then prints that jv's string as the complete error // message. static void default_err_cb(void *data, jv msg) { msg = jq_format_error(msg); fprintf((FILE *)data, "%s\n", jv_string_value(msg)); jv_free(msg); } jq_state *jq_init(void) { jq_state *jq; jq = jv_mem_alloc_unguarded(sizeof(*jq)); if (jq == NULL) return NULL; jq->bc = 0; jq->next_label = 0; stack_init(&jq->stk); jq->stk_top = 0; jq->fork_top = 0; jq->curr_frame = 0; jq->error = jv_null(); jq->halted = 0; jq->exit_code = jv_invalid(); jq->error_message = jv_invalid(); jq->input_cb = NULL; jq->input_cb_data = NULL; jq->debug_cb = NULL; jq->debug_cb_data = NULL; jq->stderr_cb = NULL; jq->stderr_cb_data = NULL; jq->err_cb = default_err_cb; jq->err_cb_data = stderr; jq->attrs = jv_object(); jq->path = jv_null(); jq->value_at_path = jv_null(); jq->nomem_handler = NULL; jq->nomem_handler_data = NULL; return jq; } void jq_set_error_cb(jq_state *jq, jq_msg_cb cb, void *data) { if (cb == NULL) { jq->err_cb = default_err_cb; jq->err_cb_data = stderr; } else { jq->err_cb = cb; jq->err_cb_data = data; } } void jq_get_error_cb(jq_state *jq, jq_msg_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); 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)); jq->debug_trace_enabled = flags & JQ_DEBUG_TRACE_ALL; jq->initial_execution = 1; } void jq_teardown(jq_state **jq) { jq_state *old_jq = *jq; if (old_jq == NULL) return; *jq = NULL; jq_reset(old_jq); bytecode_free(old_jq->bc); old_jq->bc = 0; jv_free(old_jq->attrs); jv_mem_free(old_jq); } static int ret_follows(uint16_t *pc) { if (*pc == RET) return 1; if (*pc++ != JUMP) return 0; return ret_follows(pc + *pc + 1); // FIXME, might be ironic } /* * Look for tail calls that can be optimized: tail calls with no * references left to the current frame. * * We're staring at this bytecode layout: * * CALL_JQ * * (2 units) * (2 units each) * * * A closure is: * * (a relative frame count chased via the current frame's env) * (an index of a subfunction or closure in that frame) * * We're looking for: * * 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- have level == 0. */ static uint16_t tail_call_analyze(uint16_t *pc) { assert(*pc == CALL_JQ); pc++; // + 1 for the callee closure for (uint16_t nclosures = *pc++ + 1; nclosures > 0; pc++, nclosures--) { if (*pc++ == 0) return CALL_JQ; } if (ret_follows(pc)) return TAIL_CALL_JQ; return CALL_JQ; } static struct bytecode *optimize_code(struct bytecode *bc) { uint16_t *pc = bc->code; // FIXME: Don't mutate bc->code... while (pc < bc->code + bc->codelen) { switch (*pc) { case CALL_JQ: *pc = tail_call_analyze(pc); break; // Other bytecode optimizations here. A peephole optimizer would // fit right in. default: break; } pc += bytecode_operation_length(pc); } return bc; } static struct bytecode *optimize(struct bytecode *bc) { for (int i=0; insubfunctions; i++) { bc->subfunctions[i] = optimize(bc->subfunctions[i]); } return optimize_code(bc); } static jv args2obj(jv args) { if (jv_get_kind(args) == JV_KIND_OBJECT) return args; assert(jv_get_kind(args) == JV_KIND_ARRAY); jv r = jv_object(); jv kk = jv_string("name"); jv vk = jv_string("value"); jv_array_foreach(args, i, v) r = jv_object_set(r, jv_object_get(jv_copy(v), jv_copy(kk)), jv_object_get(v, jv_copy(vk))); jv_free(args); jv_free(kk); jv_free(vk); return r; } int jq_compile_args(jq_state *jq, const char* str, jv args) { jv_nomem_handler(jq->nomem_handler, jq->nomem_handler_data); assert(jv_get_kind(args) == JV_KIND_ARRAY || jv_get_kind(args) == JV_KIND_OBJECT); struct locfile* locations; locations = locfile_init(jq, "", str, strlen(str)); block program; jq_reset(jq); if (jq->bc) { bytecode_free(jq->bc); jq->bc = 0; } int nerrors = load_program(jq, locations, &program); if (nerrors == 0) { nerrors = builtins_bind(jq, &program); if (nerrors == 0) nerrors = block_compile(program, &jq->bc, locations, args2obj(args)); else jv_free(args); } else jv_free(args); if (nerrors) jq_report_error(jq, jv_string_fmt("jq: %d compile %s", nerrors, nerrors > 1 ? "errors" : "error")); if (jq->bc) jq->bc = optimize(jq->bc); locfile_free(locations); return jq->bc != NULL; } int jq_compile(jq_state *jq, const char* str) { return jq_compile_args(jq, str, jv_object()); } jv jq_get_jq_origin(jq_state *jq) { return jq_get_attr(jq, jv_string("JQ_ORIGIN")); } jv jq_get_prog_origin(jq_state *jq) { return jq_get_attr(jq, jv_string("PROGRAM_ORIGIN")); } jv jq_get_lib_dirs(jq_state *jq) { jv lib_dirs = jq_get_attr(jq, jv_string("JQ_LIBRARY_PATH")); return jv_is_valid(lib_dirs) ? lib_dirs : jv_array(); } void jq_set_attrs(jq_state *jq, jv attrs) { assert(jv_get_kind(attrs) == JV_KIND_OBJECT); jv_free(jq->attrs); jq->attrs = attrs; } void jq_set_attr(jq_state *jq, jv attr, jv val) { jq->attrs = jv_object_set(jq->attrs, attr, val); } jv jq_get_attr(jq_state *jq, jv attr) { return jv_object_get(jv_copy(jq->attrs), attr); } void jq_dump_disassembly(jq_state *jq, int indent) { dump_disassembly(indent, jq->bc); } void jq_set_input_cb(jq_state *jq, jq_input_cb cb, void *data) { jq->input_cb = cb; jq->input_cb_data = data; } void jq_get_input_cb(jq_state *jq, jq_input_cb *cb, void **data) { *cb = jq->input_cb; *data = jq->input_cb_data; } void jq_set_debug_cb(jq_state *jq, jq_msg_cb cb, void *data) { jq->debug_cb = cb; jq->debug_cb_data = data; } void jq_get_debug_cb(jq_state *jq, jq_msg_cb *cb, void **data) { *cb = jq->debug_cb; *data = jq->debug_cb_data; } void jq_set_stderr_cb(jq_state *jq, jq_msg_cb cb, void *data) { jq->stderr_cb = cb; jq->stderr_cb_data = data; } void jq_get_stderr_cb(jq_state *jq, jq_msg_cb *cb, void **data) { *cb = jq->stderr_cb; *data = jq->stderr_cb_data; } void jq_halt(jq_state *jq, jv exit_code, jv error_message) { assert(!jq->halted); jq->halted = 1; jq->exit_code = exit_code; jq->error_message = error_message; } int jq_halted(jq_state *jq) { return jq->halted; } jv jq_get_exit_code(jq_state *jq) { return jv_copy(jq->exit_code); } jv jq_get_error_message(jq_state *jq) { return jv_copy(jq->error_message); } ================================================ FILE: src/inject_errors.c ================================================ #include #include #include #include #include #include static FILE *fail; static FILE *fail_read; static FILE *fail_write; static FILE *fail_close; static int error; static FILE * (*real_fopen)(const char *, const char *); static int (*real_fclose)(FILE *); static int (*real_ferror)(FILE *); static void (*real_clearerr)(FILE *); static char * (*real_fgets)(char *, int, FILE *); static size_t (*real_fread)(void *, size_t, size_t, FILE *); static size_t (*real_fwrite)(const void *, size_t, size_t, FILE *); #define GET_REAL(sym) \ do { \ if (real_ ## sym == 0) { \ real_ ## sym = dlsym(RTLD_NEXT, #sym); \ assert(real_ ## sym != 0); \ } \ } while (0) #define dbg_write(msg) (void)write(2, msg, sizeof(msg) - 1) #define dbg() \ do { \ dbg_write("here: "); \ dbg_write(__func__); \ dbg_write("!\n"); \ } while (0) FILE *fopen(const char *path, const char *mode) { GET_REAL(fopen); fail = fail_read = fail_write = fail_close = 0; FILE *f = real_fopen(path, mode); error = EIO; if (strcmp(path, "fail_read") == 0) { fail = fail_read = f; } else if (strncmp(path, "fail_write", sizeof("fail_write") - 1) == 0) { // Not that jq opens files for write anyways... fail = fail_write = f; if (strcmp(path, "fail_write_enospc") == 0) error = ENOSPC; } else if (strncmp(path, "fail_close", sizeof("fail_close") - 1) == 0) { fail = fail_close = f; if (strcmp(path, "fail_close_enospc") == 0) error = ENOSPC; } return f; } int fclose(FILE *f) { GET_REAL(fclose); int res = real_fclose(f); if (fail_close == f) { fail = fail_read = fail_write = fail_close = 0; return EOF; } return res; } char * fgets(char *buf, int len, FILE *f) { GET_REAL(fgets); char *res = real_fgets(buf, len, f); if (fail_read == f) return 0; return res; } size_t fread(void *buf, size_t sz, size_t nemb, FILE *f) { GET_REAL(fread); size_t res = real_fread(buf, sz, nemb, f); if (fail_read == f) return 0; return res; } size_t fwrite(const void *buf, size_t sz, size_t nemb, FILE *f) { GET_REAL(fwrite); size_t res = real_fwrite(buf, sz, nemb, f); if (fail_write == f) return 0; return res; } int ferror(FILE *f) { GET_REAL(ferror); int res = real_ferror(f); if (fail == f) { errno = error; return 1; } return res; } void clearerr(FILE *f) { GET_REAL(clearerr); real_clearerr(f); if (fail == f) { fail = fail_read = fail_write = fail_close = 0; error = 0; } } ================================================ FILE: src/jq.h ================================================ #ifndef JQ_H #define JQ_H #include #include "jv.h" #ifdef __cplusplus extern "C" { #endif enum { JQ_DEBUG_TRACE = 1, JQ_DEBUG_TRACE_DETAIL = 2, JQ_DEBUG_TRACE_ALL = JQ_DEBUG_TRACE | JQ_DEBUG_TRACE_DETAIL, }; typedef struct jq_state jq_state; typedef void (*jq_msg_cb)(void *, jv); jq_state *jq_init(void); void jq_set_error_cb(jq_state *, jq_msg_cb, void *); void jq_get_error_cb(jq_state *, jq_msg_cb *, void **); void jq_set_nomem_handler(jq_state *, void (*)(void *), void *); jv jq_format_error(jv msg); void jq_report_error(jq_state *, jv); int jq_compile(jq_state *, const char*); int jq_compile_args(jq_state *, const char*, jv); void jq_dump_disassembly(jq_state *, int); void jq_start(jq_state *, jv value, int); jv jq_next(jq_state *); void jq_teardown(jq_state **); void jq_halt(jq_state *, jv, jv); int jq_halted(jq_state *); jv jq_get_exit_code(jq_state *); jv jq_get_error_message(jq_state *); typedef jv (*jq_input_cb)(jq_state *, void *); void jq_set_input_cb(jq_state *, jq_input_cb, void *); void jq_get_input_cb(jq_state *, jq_input_cb *, void **); void jq_set_debug_cb(jq_state *, jq_msg_cb, void *); void jq_get_debug_cb(jq_state *, jq_msg_cb *, void **); void jq_set_stderr_cb(jq_state *, jq_msg_cb, void *); void jq_get_stderr_cb(jq_state *, jq_msg_cb *, void **); void jq_set_attrs(jq_state *, jv); jv jq_get_attrs(jq_state *); jv jq_get_jq_origin(jq_state *); jv jq_get_prog_origin(jq_state *); jv jq_get_lib_dirs(jq_state *); void jq_set_attr(jq_state *, jv, jv); jv jq_get_attr(jq_state *, jv); /* * We use char * instead of jf for filenames here because filenames * should be in the process' locale's codeset, which may not be UTF-8, * whereas jv string values must be in UTF-8. This way the caller * doesn't have to perform any codeset conversions. */ typedef struct jq_util_input_state jq_util_input_state; typedef void (*jq_util_msg_cb)(void *, const char *); jq_util_input_state *jq_util_input_init(jq_util_msg_cb, void *); void jq_util_input_set_parser(jq_util_input_state *, jv_parser *, int); void jq_util_input_free(jq_util_input_state **); void jq_util_input_add_input(jq_util_input_state *, const char *); int jq_util_input_errors(jq_util_input_state *); jv jq_util_input_next_input(jq_util_input_state *); jv jq_util_input_next_input_cb(jq_state *, void *); jv jq_util_input_get_position(jq_state*); jv jq_util_input_get_current_filename(jq_state*); jv jq_util_input_get_current_line(jq_state*); int jq_set_colors(const char *); #ifdef __cplusplus } #endif #endif /* !JQ_H */ ================================================ FILE: src/jq_parser.h ================================================ #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); #endif ================================================ FILE: src/jq_test.c ================================================ #include #include #include #include #ifdef HAVE_PTHREAD #include #endif #include "jv.h" #include "jq.h" static void jv_test(void); static void run_jq_tests(jv, int, FILE *, int, int); static void run_jq_start_state_tests(void); static void run_jq_compile_args_tests(void); static void run_jq_recompile_tests(void); static void run_jq_exhaust_and_reuse_tests(void); #ifdef HAVE_PTHREAD static void run_jq_pthread_tests(void); #endif int jq_testsuite(jv libdirs, int verbose, int argc, char* argv[]) { int skip = -1; int take = -1; int nfiles = 0; jv_test(); for (int i = 0; i < argc; i++) { if (!strcmp(argv[i], "--skip")) { if (++i >= argc) { fprintf(stderr, "--skip requires an argument\n"); exit(1); } skip = atoi(argv[i]); } else if (!strcmp(argv[i], "--take")) { if (++i >= argc) { fprintf(stderr, "--take requires an argument\n"); exit(1); } take = atoi(argv[i]); } else { FILE *testdata = fopen(argv[i], "r"); if (!testdata) { perror("fopen"); exit(1); } run_jq_tests(jv_copy(libdirs), verbose, testdata, skip, take); fclose(testdata); nfiles++; } } if (nfiles == 0) run_jq_tests(jv_copy(libdirs), verbose, stdin, skip, take); jv_free(libdirs); run_jq_start_state_tests(); run_jq_compile_args_tests(); run_jq_recompile_tests(); run_jq_exhaust_and_reuse_tests(); #ifdef HAVE_PTHREAD run_jq_pthread_tests(); #endif return 0; } static int skipline(const char* buf) { int p = 0; while (buf[p] == ' ' || buf[p] == '\t') p++; if (buf[p] == '#' || buf[p] == '\n' || buf[p] == 0) return 1; return 0; } static int checkerrormsg(const char* buf) { return strcmp(buf, "%%FAIL\n") == 0; } static int checkfail(const char* buf) { return strcmp(buf, "%%FAIL\n") == 0 || strcmp(buf, "%%FAIL IGNORE MSG\n") == 0; } struct err_data { char buf[4096]; }; static void test_err_cb(void *data, jv e) { struct err_data *err_data = data; if (jv_get_kind(e) != JV_KIND_STRING) e = jv_dump_string(e, JV_PRINT_INVALID); if (!strncmp(jv_string_value(e), "jq: error", sizeof("jq: error") - 1)) snprintf(err_data->buf, sizeof(err_data->buf), "%s", jv_string_value(e)); jv_free(e); } static void run_jq_tests(jv lib_dirs, int verbose, FILE *testdata, int skip, int take) { char prog[4096] = {0}; char buf[4096]; struct err_data err_msg; int tests = 0, passed = 0, invalid = 0; unsigned int lineno = 0; int must_fail = 0; int check_msg = 0; jq_state *jq = NULL; int tests_to_skip = skip > 0 ? skip : 0; int tests_to_take = take; jq = jq_init(); assert(jq); if (jv_get_kind(lib_dirs) == JV_KIND_NULL) lib_dirs = jv_array(); jq_set_attr(jq, jv_string("JQ_LIBRARY_PATH"), lib_dirs); while (1) { if (!fgets(prog, sizeof(prog), testdata)) break; lineno++; if (skipline(prog)) continue; if (checkfail(prog)) { must_fail = 1; check_msg = checkerrormsg(prog); jq_set_error_cb(jq, test_err_cb, &err_msg); continue; } if (prog[strlen(prog)-1] == '\n') prog[strlen(prog)-1] = 0; if (skip > 0) { skip--; goto next; } else if (skip == 0) { printf("Skipped %d tests\n", tests_to_skip); skip = -1; } if (take > 0) { take--; } else if (take == 0) { printf("Hit the number of tests limit (%d), breaking\n", tests_to_take); break; } int pass = 1; tests++; printf("Test #%d: '%s' at line number %u\n", tests + tests_to_skip, prog, lineno); int compiled = jq_compile(jq, prog); if (must_fail) { jq_set_error_cb(jq, NULL, NULL); if (compiled) { printf("*** Test program compiled successfully, but should fail at line number %u: %s\n", lineno, prog); goto fail; } char *err_buf = err_msg.buf; while (fgets(buf, sizeof(buf), testdata)) { lineno++; if (skipline(buf)) break; if (check_msg) { if (buf[strlen(buf)-1] == '\n') buf[strlen(buf)-1] = '\0'; if (strncmp(buf, err_buf, strlen(buf)) != 0) { if (strchr(err_buf, '\n')) *strchr(err_buf, '\n') = '\0'; printf("*** Erroneous program failed with '%s', but expected '%s' at line number %u: %s\n", err_buf, buf, lineno, prog); goto fail; } err_buf += strlen(buf); if (*err_buf == '\n') err_buf++; } } if (check_msg && *err_buf != '\0') { if (strchr(err_buf, '\n')) *strchr(err_buf, '\n') = '\0'; printf("*** Erroneous program failed with extra message '%s' at line %u: %s\n", err_buf, lineno, prog); invalid++; pass = 0; } must_fail = 0; check_msg = 0; passed += pass; continue; } if (!compiled) { printf("*** Test program failed to compile at line %u: %s\n", lineno, prog); goto fail; } if (verbose) { printf("Disassembly:\n"); jq_dump_disassembly(jq, 2); printf("\n"); } if (!fgets(buf, sizeof(buf), testdata)) { invalid++; break; } lineno++; jv input = jv_parse(buf); if (!jv_is_valid(input)) { printf("*** Input is invalid on line %u: %s\n", lineno, buf); goto fail; } jq_start(jq, input, verbose ? JQ_DEBUG_TRACE : 0); while (fgets(buf, sizeof(buf), testdata)) { lineno++; if (skipline(buf)) break; jv expected = jv_parse(buf); if (!jv_is_valid(expected)) { printf("*** Expected result is invalid on line %u: %s\n", lineno, buf); goto fail; } jv actual = jq_next(jq); if (!jv_is_valid(actual)) { jv_free(expected); jv_free(actual); printf("*** Insufficient results for test at line number %u: %s\n", lineno, prog); pass = 0; break; } else if (!jv_equal(jv_copy(expected), jv_copy(actual))) { printf("*** Expected "); jv_dump(jv_copy(expected), 0); printf(", but got "); jv_dump(jv_copy(actual), 0); printf(" for test at line number %u: %s\n", lineno, prog); pass = 0; } #ifdef USE_DECNUM jv as_string = jv_dump_string(jv_copy(expected), 0); jv reparsed = jv_parse_sized(jv_string_value(as_string), jv_string_length_bytes(jv_copy(as_string))); if (!jv_equal(jv_copy(expected), jv_copy(reparsed))) { printf("*** Expected result should be equal after reparsing, but got "); jv_dump(jv_copy(reparsed), 0); printf(" for test at line %u: %s\n", lineno, buf); pass = 0; } jv_free(as_string); jv_free(reparsed); #endif jv_free(expected); jv_free(actual); } if (pass) { jv extra = jq_next(jq); if (jv_is_valid(extra)) { printf("*** Superfluous result: "); jv_dump(extra, 0); printf(" for test at line number %u, %s\n", lineno, prog); invalid++; pass = 0; } else { jv_free(extra); } } passed += pass; continue; fail: invalid++; next: while (fgets(buf, sizeof(buf), testdata)) { lineno++; if (skipline(buf)) break; } must_fail = 0; check_msg = 0; } jq_teardown(&jq); int total_skipped = tests_to_skip; if (skip > 0) { total_skipped = tests_to_skip - skip; } printf("%d of %d tests passed (%d malformed, %d skipped)\n", passed, tests, invalid, total_skipped); if (skip > 0) { printf("WARN: skipped past the end of file, exiting with status 2\n"); exit(2); } if (passed != tests) exit(1); } static int test_start_state(jq_state *jq, char *prog) { int pass = 1; jv message = jq_get_error_message(jq); if (jv_is_valid(message)) { printf("*** Expected error_message to be invalid after jq_start: %s\n", prog); pass = 0; } jv_free(message); jv exit_code = jq_get_exit_code(jq); if (jv_is_valid(exit_code)) { printf("*** Expected exit_code to be invalid after jq_start: %s\n", prog); pass = 0; } jv_free(exit_code); if (jq_halted(jq)) { printf("*** Expected jq to not be halted after jq_start: %s\n", prog); pass = 0; } return pass; } // Test jq_state is reset after subsequent calls to jq_start. static void test_jq_start_resets_state(char *prog, const char *input) { printf("Test jq_state: %s\n", prog); jq_state *jq = jq_init(); assert(jq); int compiled = jq_compile(jq, prog); assert(compiled); // First call to jq_start. Run until completion. jv parsed_input = jv_parse(input); assert(jv_is_valid(parsed_input)); jq_start(jq, parsed_input, 0); assert(test_start_state(jq, prog)); while (1) { jv result = jq_next(jq); int valid = jv_is_valid(result); jv_free(result); if (!valid) { break; } } // Second call to jq_start. jv parsed_input2 = jv_parse(input); assert(jv_is_valid(parsed_input2)); jq_start(jq, parsed_input2, 0); assert(test_start_state(jq, prog)); jq_teardown(&jq); } static void run_jq_start_state_tests(void) { test_jq_start_resets_state(".[]", "[1,2,3]"); test_jq_start_resets_state(".[] | if .%2 == 0 then halt_error else . end", "[1,2,3]"); } static void compile_args_and_check(jq_state *jq, const char *prog, jv args, jv input, jv expected) { printf(" subtest: %s\n", prog); int compiled = jq_compile_args(jq, prog, args); assert(compiled); jq_start(jq, input, 0); jv result = jq_next(jq); assert(jv_is_valid(result)); assert(jv_equal(result, expected)); jv extra = jq_next(jq); assert(!jv_is_valid(extra)); jv_free(extra); } // Test that jq_compile_args() with array arguments handles jv // refcounting correctly in args2obj(). The array path converts // [{"name":"k","value":"v"}, ...] into {"k":"v", ...}. static void run_jq_compile_args_tests(void) { printf("Test jq_compile_args with array args\n"); jq_state *jq = jq_init(); assert(jq); // Empty array: loop body never runs, kk/vk allocated and freed compile_args_and_check(jq, "42", jv_array(), jv_null(), jv_number(42)); // Single element: one iteration, no reuse of kk/vk compile_args_and_check(jq, "$val", JV_ARRAY(JV_OBJECT(jv_string("name"), jv_string("val"), jv_string("value"), jv_number(42))), jv_null(), jv_number(42)); // Two elements: minimum to trigger former UAF on iteration 2 compile_args_and_check(jq, "$x + $y", JV_ARRAY(JV_OBJECT(jv_string("name"), jv_string("x"), jv_string("value"), jv_number(1)), JV_OBJECT(jv_string("name"), jv_string("y"), jv_string("value"), jv_number(2))), jv_null(), jv_number(3)); // Three elements: exercises further loop iterations compile_args_and_check(jq, "$a + $b + $c", JV_ARRAY(JV_OBJECT(jv_string("name"), jv_string("a"), jv_string("value"), jv_string("hello")), JV_OBJECT(jv_string("name"), jv_string("b"), jv_string("value"), jv_string(" ")), JV_OBJECT(jv_string("name"), jv_string("c"), jv_string("value"), jv_string("world"))), jv_null(), jv_string("hello world")); // Object args: bypasses args2obj loop via early return compile_args_and_check(jq, "$x * $y", JV_OBJECT(jv_string("x"), jv_number(10), jv_string("y"), jv_number(20)), jv_null(), jv_number(200)); jq_teardown(&jq); } // Test that recompiling on the same jq_state doesn't leak or // double-free the previous bytecode, and that switching between // jq_compile and jq_compile_args works correctly. static void run_jq_recompile_tests(void) { printf("Test jq recompile on same state\n"); jq_state *jq = jq_init(); assert(jq); // First program via jq_compile int compiled = jq_compile(jq, ". + 1"); assert(compiled); jq_start(jq, jv_number(1), 0); jv r = jq_next(jq); assert(jv_is_valid(r)); assert(jv_number_value(r) == 2); jv_free(r); r = jq_next(jq); assert(!jv_is_valid(r)); jv_free(r); // Recompile with a different program on the same state compiled = jq_compile(jq, ". * 2"); assert(compiled); jq_start(jq, jv_number(5), 0); r = jq_next(jq); assert(jv_is_valid(r)); assert(jv_number_value(r) == 10); jv_free(r); r = jq_next(jq); assert(!jv_is_valid(r)); jv_free(r); // Recompile via jq_compile_args with array args (args2obj path) compiled = jq_compile_args(jq, "$n + $m", JV_ARRAY(JV_OBJECT(jv_string("name"), jv_string("n"), jv_string("value"), jv_number(100)), JV_OBJECT(jv_string("name"), jv_string("m"), jv_string("value"), jv_number(7)))); assert(compiled); jq_start(jq, jv_null(), 0); r = jq_next(jq); assert(jv_is_valid(r)); assert(jv_number_value(r) == 107); jv_free(r); r = jq_next(jq); assert(!jv_is_valid(r)); jv_free(r); // Back to jq_compile after jq_compile_args compiled = jq_compile(jq, ". - 1"); assert(compiled); jq_start(jq, jv_number(10), 0); r = jq_next(jq); assert(jv_is_valid(r)); assert(jv_number_value(r) == 9); jv_free(r); r = jq_next(jq); assert(!jv_is_valid(r)); jv_free(r); jq_teardown(&jq); } // Test that exhausting jq_next doesn't corrupt state, and that // the same jq_state can be reused with jq_start after exhaustion. static void run_jq_exhaust_and_reuse_tests(void) { printf("Test jq exhaust and reuse\n"); jq_state *jq = jq_init(); assert(jq); int compiled = jq_compile(jq, ".[]"); assert(compiled); // First run: drain all results jq_start(jq, jv_parse("[1,2,3]"), 0); for (int i = 1; i <= 3; i++) { jv r = jq_next(jq); assert(jv_is_valid(r)); assert(jv_number_value(r) == i); jv_free(r); } jv r = jq_next(jq); assert(!jv_is_valid(r)); jv_free(r); // Reuse with new input on the same compiled program jq_start(jq, jv_parse("[10,20]"), 0); r = jq_next(jq); assert(jv_is_valid(r)); assert(jv_number_value(r) == 10); jv_free(r); r = jq_next(jq); assert(jv_is_valid(r)); assert(jv_number_value(r) == 20); jv_free(r); r = jq_next(jq); assert(!jv_is_valid(r)); jv_free(r); // Reuse again with empty array (zero results) jq_start(jq, jv_parse("[]"), 0); r = jq_next(jq); assert(!jv_is_valid(r)); jv_free(r); // Reuse once more after zero-result run jq_start(jq, jv_parse("[99]"), 0); r = jq_next(jq); assert(jv_is_valid(r)); assert(jv_number_value(r) == 99); jv_free(r); r = jq_next(jq); assert(!jv_is_valid(r)); jv_free(r); jq_teardown(&jq); } /// pthread regression test #ifdef HAVE_PTHREAD #define NUMBER_OF_THREADS 3 struct test_pthread_data { int result; }; static int test_pthread_jq_parse(jq_state *jq, struct jv_parser *parser) { int rv = 0; jv value; value = jv_parser_next(parser); while (jv_is_valid(value)) { jq_start(jq, value, 0); jv result = jq_next(jq); while (jv_is_valid(result)) { jv_free(result); result = jq_next(jq); } jv_free(result); value = jv_parser_next(parser); } jv_free(value); return rv; } static void *test_pthread_run(void *ptr) { int rv; jq_state *jq; const char *prg = ".data"; const char *buf = "{ \"data\": 1 }"; struct test_pthread_data *data = ptr; jq = jq_init(); if (jq_compile(jq, prg) == 0) { jq_teardown(&jq); return NULL; } struct jv_parser *parser = jv_parser_new(0); jv_parser_set_buf(parser, buf, strlen(buf), 0); rv = test_pthread_jq_parse(jq, parser); data->result = rv; jv_parser_free(parser); jq_teardown(&jq); return NULL; } static void run_jq_pthread_tests(void) { pthread_t threads[NUMBER_OF_THREADS]; struct test_pthread_data data[NUMBER_OF_THREADS]; int createerror; int a; memset(&threads, 0, sizeof(threads)); memset(&data, 0, sizeof(data)); // Create all threads for (a = 0; a < NUMBER_OF_THREADS; ++a) { createerror = pthread_create(&threads[a], NULL, test_pthread_run, &data[a]); assert(createerror == 0); } // wait for all threads for(a = 0; a < NUMBER_OF_THREADS; ++a) { #ifdef __MVS__ if (threads[a].__ != 0) { #else if (threads[a] != 0) { #endif pthread_join(threads[a], NULL); } } // check results for(a = 0; a < NUMBER_OF_THREADS; ++a) { assert(data[a].result == 0); } } #endif // HAVE_PTHREAD static void jv_test(void) { /// JSON parser regression tests { jv v = jv_parse("{\"a':\"12\"}"); assert(jv_get_kind(v) == JV_KIND_INVALID); v = jv_invalid_get_msg(v); assert(strcmp(jv_string_value(v), "Expected separator between values at line 1, column 9 (while parsing '{\"a':\"12\"}')") == 0); jv_free(v); } /// Arrays and numbers { jv a = jv_array(); assert(jv_get_kind(a) == JV_KIND_ARRAY); assert(jv_array_length(jv_copy(a)) == 0); assert(jv_array_length(jv_copy(a)) == 0); a = jv_array_append(a, jv_number(42)); assert(jv_array_length(jv_copy(a)) == 1); assert(jv_number_value(jv_array_get(jv_copy(a), 0)) == 42); jv a2 = jv_array_append(jv_array(), jv_number(42)); assert(jv_equal(jv_copy(a), jv_copy(a))); assert(jv_equal(jv_copy(a2), jv_copy(a2))); assert(jv_equal(jv_copy(a), jv_copy(a2))); assert(jv_equal(jv_copy(a2), jv_copy(a))); jv_free(a2); a2 = jv_array_append(jv_array(), jv_number(19)); assert(!jv_equal(jv_copy(a), jv_copy(a2))); assert(!jv_equal(jv_copy(a2), jv_copy(a))); jv_free(a2); assert(jv_get_refcnt(a) == 1); a = jv_array_append(a, jv_copy(a)); assert(jv_get_refcnt(a) == 1); assert(jv_array_length(jv_copy(a)) == 2); assert(jv_number_value(jv_array_get(jv_copy(a), 0)) == 42); for (int i=0; i<10; i++) { jv subarray = jv_array_get(jv_copy(a), 1); assert(jv_get_kind(subarray) == JV_KIND_ARRAY); assert(jv_array_length(jv_copy(subarray)) == 1); assert(jv_number_value(jv_array_get(jv_copy(subarray), 0)) == 42); jv_free(subarray); } jv subarray = jv_array_get(jv_copy(a), 1); assert(jv_get_kind(subarray) == JV_KIND_ARRAY); assert(jv_array_length(jv_copy(subarray)) == 1); assert(jv_number_value(jv_array_get(jv_copy(subarray), 0)) == 42); jv sub2 = jv_copy(subarray); sub2 = jv_array_append(sub2, jv_number(19)); assert(jv_get_kind(sub2) == JV_KIND_ARRAY); assert(jv_array_length(jv_copy(sub2)) == 2); assert(jv_number_value(jv_array_get(jv_copy(sub2), 0)) == 42); assert(jv_number_value(jv_array_get(jv_copy(sub2), 1)) == 19); assert(jv_get_kind(subarray) == JV_KIND_ARRAY); assert(jv_array_length(jv_copy(subarray)) == 1); assert(jv_number_value(jv_array_get(jv_copy(subarray), 0)) == 42); jv_free(subarray); void* before = sub2.u.ptr; sub2 = jv_array_append(sub2, jv_number(200)); void* after = sub2.u.ptr; assert(before == after); jv_free(sub2); jv a3 = jv_array_append(jv_copy(a), jv_number(19)); assert(jv_array_length(jv_copy(a3)) == 3); assert(jv_number_value(jv_array_get(jv_copy(a3), 0)) == 42); assert(jv_array_length(jv_array_get(jv_copy(a3), 1)) == 1); assert(jv_number_value(jv_array_get(jv_copy(a3), 2)) == 19); jv_free(a3); jv a4 = jv_array(); a4 = jv_array_append(a4, jv_number(1)); a4 = jv_array_append(a4, jv_number(2)); jv a5 = jv_copy(a4); a4 = jv_array_append(a4, jv_number(3)); 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(jv_copy(a)) == 2); assert(jv_number_value(jv_array_get(jv_copy(a), 0)) == 42); assert(jv_array_length(jv_array_get(jv_copy(a), 1)) == 1); //jv_dump(jv_copy(a), 0); printf("\n"); jv_free(a); } /// Strings { 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); char a1s[] = "hello", a2s[] = "hello", bs[] = "goodbye"; jv a1 = jv_string(a1s), a2 = jv_string(a2s), b = jv_string(bs); assert(jv_equal(jv_copy(a1), jv_copy(a2))); assert(jv_equal(jv_copy(a2), jv_copy(a1))); assert(!jv_equal(jv_copy(a1), jv_copy(b))); assert(jv_string_hash(jv_copy(a1)) == jv_string_hash(jv_copy(a1))); assert(jv_string_hash(jv_copy(a1)) == jv_string_hash(jv_copy(a2))); assert(jv_string_hash(jv_copy(b)) != jv_string_hash(jv_copy(a1))); jv_free(a1); jv_free(a2); jv_free(b); assert(jv_equal(jv_string("hello42!"), jv_string_fmt("hello%d%s", 42, "!"))); char big[20000]; for (int i=0; i<(int)sizeof(big); i++) big[i] = 'a'; big[sizeof(big)-1] = 0; jv str = jv_string_fmt("%s", big); assert(jv_string_length_bytes(jv_copy(str)) == sizeof(big) - 1); assert(!strcmp(big, jv_string_value(str))); jv_free(str); } /// Objects { jv o1 = jv_object(); o1 = jv_object_set(o1, jv_string("foo"), jv_number(42)); o1 = jv_object_set(o1, jv_string("bar"), jv_number(24)); assert(jv_number_value(jv_object_get(jv_copy(o1), jv_string("foo"))) == 42); assert(jv_number_value(jv_object_get(jv_copy(o1), jv_string("bar"))) == 24); jv o2 = jv_object_set(jv_copy(o1), jv_string("foo"), jv_number(420)); o2 = jv_object_set(o2, jv_string("bar"), jv_number(240)); assert(jv_number_value(jv_object_get(jv_copy(o1), jv_string("foo"))) == 42); assert(jv_number_value(jv_object_get(jv_copy(o1), jv_string("bar"))) == 24); assert(jv_number_value(jv_object_get(jv_copy(o2), jv_string("foo"))) == 420); jv_free(o1); assert(jv_number_value(jv_object_get(jv_copy(o2), jv_string("bar"))) == 240); //jv_dump(jv_copy(o2), 0); printf("\n"); jv_free(o2); } } ================================================ FILE: src/jv.c ================================================ /* * Portions Copyright (c) 2016 Kungliga Tekniska Högskolan * (Royal Institute of Technology, Stockholm, Sweden). * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED * OF THE POSSIBILITY OF SUCH DAMAGE. * */ #include #include #include #include #include #include #include #include #include #include #include "jv_alloc.h" #include "jv.h" #include "jv_unicode.h" #include "util.h" /* * Internal refcounting helpers */ typedef struct jv_refcnt { int count; } jv_refcnt; static const jv_refcnt JV_REFCNT_INIT = {1}; static void jvp_refcnt_inc(jv_refcnt* c) { c->count++; } static int jvp_refcnt_dec(jv_refcnt* c) { c->count--; return c->count == 0; } static int jvp_refcnt_unshared(jv_refcnt* c) { assert(c->count > 0); return c->count == 1; } #define KIND_MASK 0xF #define PFLAGS_MASK 0xF0 #define PTYPE_MASK 0x70 typedef enum { JVP_PAYLOAD_NONE = 0, JVP_PAYLOAD_ALLOCATED = 0x80, } payload_flags; #define JVP_MAKE_PFLAGS(ptype, allocated) ((((ptype) << 4) & PTYPE_MASK) | ((allocated) ? JVP_PAYLOAD_ALLOCATED : 0)) #define JVP_MAKE_FLAGS(kind, pflags) ((kind & KIND_MASK) | (pflags & PFLAGS_MASK)) #define JVP_FLAGS(j) ((j).kind_flags) #define JVP_KIND(j) (JVP_FLAGS(j) & KIND_MASK) #define JVP_HAS_FLAGS(j, flags) (JVP_FLAGS(j) == flags) #define JVP_HAS_KIND(j, kind) (JVP_KIND(j) == kind) #define JVP_IS_ALLOCATED(j) (j.kind_flags & JVP_PAYLOAD_ALLOCATED) #define JVP_FLAGS_NULL JVP_MAKE_FLAGS(JV_KIND_NULL, JVP_PAYLOAD_NONE) #define JVP_FLAGS_INVALID JVP_MAKE_FLAGS(JV_KIND_INVALID, JVP_PAYLOAD_NONE) #define JVP_FLAGS_FALSE JVP_MAKE_FLAGS(JV_KIND_FALSE, JVP_PAYLOAD_NONE) #define JVP_FLAGS_TRUE JVP_MAKE_FLAGS(JV_KIND_TRUE, JVP_PAYLOAD_NONE) jv_kind jv_get_kind(jv x) { return JVP_KIND(x); } const char* jv_kind_name(jv_kind k) { switch (k) { case JV_KIND_INVALID: return ""; case JV_KIND_NULL: return "null"; case JV_KIND_FALSE: return "boolean"; case JV_KIND_TRUE: return "boolean"; case JV_KIND_NUMBER: return "number"; case JV_KIND_STRING: return "string"; case JV_KIND_ARRAY: return "array"; case JV_KIND_OBJECT: return "object"; } assert(0 && "invalid kind"); return ""; } const jv JV_NULL = {JVP_FLAGS_NULL, 0, 0, 0, {0}}; const jv JV_INVALID = {JVP_FLAGS_INVALID, 0, 0, 0, {0}}; const jv JV_FALSE = {JVP_FLAGS_FALSE, 0, 0, 0, {0}}; const jv JV_TRUE = {JVP_FLAGS_TRUE, 0, 0, 0, {0}}; jv jv_true(void) { return JV_TRUE; } jv jv_false(void) { return JV_FALSE; } jv jv_null(void) { return JV_NULL; } jv jv_bool(int x) { return x ? JV_TRUE : JV_FALSE; } /* * Invalid objects, with optional error messages */ #define JVP_FLAGS_INVALID_MSG JVP_MAKE_FLAGS(JV_KIND_INVALID, JVP_PAYLOAD_ALLOCATED) typedef struct { jv_refcnt refcnt; jv errmsg; } jvp_invalid; jv jv_invalid_with_msg(jv err) { jvp_invalid* i = jv_mem_alloc(sizeof(jvp_invalid)); i->refcnt = JV_REFCNT_INIT; i->errmsg = err; jv x = {JVP_FLAGS_INVALID_MSG, 0, 0, 0, {&i->refcnt}}; return x; } jv jv_invalid(void) { return JV_INVALID; } jv jv_invalid_get_msg(jv inv) { assert(JVP_HAS_KIND(inv, JV_KIND_INVALID)); jv x; if (JVP_HAS_FLAGS(inv, JVP_FLAGS_INVALID_MSG)) { x = jv_copy(((jvp_invalid*)inv.u.ptr)->errmsg); } else { x = jv_null(); } jv_free(inv); return x; } int jv_invalid_has_msg(jv inv) { assert(JVP_HAS_KIND(inv, JV_KIND_INVALID)); int r = JVP_HAS_FLAGS(inv, JVP_FLAGS_INVALID_MSG); jv_free(inv); return r; } static void jvp_invalid_free(jv x) { assert(JVP_HAS_KIND(x, JV_KIND_INVALID)); if (JVP_HAS_FLAGS(x, JVP_FLAGS_INVALID_MSG) && jvp_refcnt_dec(x.u.ptr)) { jv_free(((jvp_invalid*)x.u.ptr)->errmsg); jv_mem_free(x.u.ptr); } } /* * Numbers */ #ifdef USE_DECNUM #include "jv_dtoa.h" #include "jv_dtoa_tsd.h" // we will manage the space for the struct #define DECNUMDIGITS 1 #include "decNumber/decNumber.h" enum { JVP_NUMBER_NATIVE = 0, JVP_NUMBER_DECIMAL = 1 }; #define JVP_FLAGS_NUMBER_NATIVE JVP_MAKE_FLAGS(JV_KIND_NUMBER, JVP_MAKE_PFLAGS(JVP_NUMBER_NATIVE, 0)) #define JVP_FLAGS_NUMBER_LITERAL JVP_MAKE_FLAGS(JV_KIND_NUMBER, JVP_MAKE_PFLAGS(JVP_NUMBER_DECIMAL, 1)) // the decimal precision of binary double #define DEC_NUMBER_DOUBLE_PRECISION (17) #define DEC_NUMBER_STRING_GUARD (14) #define DEC_NUMBER_DOUBLE_EXTRA_UNITS ((DEC_NUMBER_DOUBLE_PRECISION - DECNUMDIGITS + DECDPUN - 1)/DECDPUN) #include "jv_thread.h" #ifdef WIN32 #ifndef __MINGW32__ /* Copied from Heimdal: thread-specific keys; see lib/base/dll.c in Heimdal */ /* * This is an implementation of thread-specific storage with * destructors. WIN32 doesn't quite have this. Instead it has * DllMain(), an entry point in every DLL that gets called to notify the * DLL of thread/process "attach"/"detach" events. * * We use __thread (or __declspec(thread)) for the thread-local itself * and DllMain() DLL_THREAD_DETACH events to drive destruction of * thread-local values. * * When building in maintainer mode on non-Windows pthread systems this * uses a single pthread key instead to implement multiple keys. This * keeps the code from rotting when modified by non-Windows developers. */ /* Logical array of keys that grows lock-lessly */ typedef struct tls_keys tls_keys; struct tls_keys { void (**keys_dtors)(void *); /* array of destructors */ size_t keys_start_idx; /* index of first destructor */ size_t keys_num; tls_keys *keys_next; }; /* * Well, not quite locklessly. We need synchronization primitives to do * this locklessly. An atomic CAS will do. */ static pthread_mutex_t tls_key_defs_lock = PTHREAD_MUTEX_INITIALIZER; static tls_keys *tls_key_defs; /* Logical array of values (per-thread; no locking needed here) */ struct tls_values { void **values; /* realloc()ed */ size_t values_num; }; #ifdef _MSC_VER static __declspec(thread) struct nomem_handler nomem_handler; #else static __thread struct tls_values values; #endif #define DEAD_KEY ((void *)8) static void w32_service_thread_detach(void *unused) { tls_keys *key_defs; void (*dtor)(void*); size_t i; pthread_mutex_lock(&tls_key_defs_lock); key_defs = tls_key_defs; pthread_mutex_unlock(&tls_key_defs_lock); if (key_defs == NULL) return; for (i = 0; i < values.values_num; i++) { assert(i >= key_defs->keys_start_idx); if (i >= key_defs->keys_start_idx + key_defs->keys_num) { pthread_mutex_lock(&tls_key_defs_lock); key_defs = key_defs->keys_next; pthread_mutex_unlock(&tls_key_defs_lock); assert(key_defs != NULL); assert(i >= key_defs->keys_start_idx); assert(i < key_defs->keys_start_idx + key_defs->keys_num); } dtor = key_defs->keys_dtors[i - key_defs->keys_start_idx]; if (values.values[i] != NULL && dtor != NULL && dtor != DEAD_KEY) dtor(values.values[i]); values.values[i] = NULL; } } extern void jv_tsd_dtoa_ctx_init(); extern void jv_tsd_dtoa_ctx_fini(); void jv_tsd_dec_ctx_fini(); void jv_tsd_dec_ctx_init(); BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved) { switch (fdwReason) { case DLL_PROCESS_ATTACH: /*create_pt_key();*/ jv_tsd_dtoa_ctx_init(); jv_tsd_dec_ctx_init(); return TRUE; case DLL_PROCESS_DETACH: jv_tsd_dtoa_ctx_fini(); jv_tsd_dec_ctx_fini(); return TRUE; case DLL_THREAD_ATTACH: return 0; case DLL_THREAD_DETACH: w32_service_thread_detach(NULL); return TRUE; default: return TRUE; } } int pthread_key_create(pthread_key_t *key, void (*dtor)(void *)) { tls_keys *key_defs, *new_key_defs; size_t i, k; int ret = ENOMEM; pthread_mutex_lock(&tls_key_defs_lock); if (tls_key_defs == NULL) { /* First key */ new_key_defs = calloc(1, sizeof(*new_key_defs)); if (new_key_defs == NULL) { pthread_mutex_unlock(&tls_key_defs_lock); return ENOMEM; } new_key_defs->keys_num = 8; new_key_defs->keys_dtors = calloc(new_key_defs->keys_num, sizeof(*new_key_defs->keys_dtors)); if (new_key_defs->keys_dtors == NULL) { pthread_mutex_unlock(&tls_key_defs_lock); free(new_key_defs); return ENOMEM; } tls_key_defs = new_key_defs; new_key_defs->keys_dtors[0] = dtor; for (i = 1; i < new_key_defs->keys_num; i++) new_key_defs->keys_dtors[i] = NULL; pthread_mutex_unlock(&tls_key_defs_lock); return 0; } for (key_defs = tls_key_defs; key_defs != NULL; key_defs = key_defs->keys_next) { k = key_defs->keys_start_idx; for (i = 0; i < key_defs->keys_num; i++, k++) { if (key_defs->keys_dtors[i] == NULL) { /* Found free slot; use it */ key_defs->keys_dtors[i] = dtor; *key = k; pthread_mutex_unlock(&tls_key_defs_lock); return 0; } } if (key_defs->keys_next != NULL) continue; /* Grow the registration array */ /* XXX DRY */ new_key_defs = calloc(1, sizeof(*new_key_defs)); if (new_key_defs == NULL) break; new_key_defs->keys_dtors = calloc(key_defs->keys_num + key_defs->keys_num / 2, sizeof(*new_key_defs->keys_dtors)); if (new_key_defs->keys_dtors == NULL) { free(new_key_defs); break; } new_key_defs->keys_start_idx = key_defs->keys_start_idx + key_defs->keys_num; new_key_defs->keys_num = key_defs->keys_num + key_defs->keys_num / 2; new_key_defs->keys_dtors[i] = dtor; for (i = 1; i < new_key_defs->keys_num; i++) new_key_defs->keys_dtors[i] = NULL; key_defs->keys_next = new_key_defs; ret = 0; break; } pthread_mutex_unlock(&tls_key_defs_lock); return ret; } static void key_lookup(pthread_key_t key, tls_keys **kd, size_t *dtor_idx, void (**dtor)(void *)) { tls_keys *key_defs; if (kd != NULL) *kd = NULL; if (dtor_idx != NULL) *dtor_idx = 0; if (dtor != NULL) *dtor = NULL; pthread_mutex_lock(&tls_key_defs_lock); key_defs = tls_key_defs; pthread_mutex_unlock(&tls_key_defs_lock); while (key_defs != NULL) { if (key >= key_defs->keys_start_idx && key < key_defs->keys_start_idx + key_defs->keys_num) { if (kd != NULL) *kd = key_defs; if (dtor_idx != NULL) *dtor_idx = key - key_defs->keys_start_idx; if (dtor != NULL) *dtor = key_defs->keys_dtors[key - key_defs->keys_start_idx]; return; } pthread_mutex_lock(&tls_key_defs_lock); key_defs = key_defs->keys_next; pthread_mutex_unlock(&tls_key_defs_lock); assert(key_defs != NULL); assert(key >= key_defs->keys_start_idx); } } int pthread_setspecific(pthread_key_t key, void *value) { void **new_values; size_t new_num; void (*dtor)(void *); size_t i; key_lookup(key, NULL, NULL, &dtor); if (dtor == NULL) return EINVAL; if (key >= values.values_num) { if (values.values_num == 0) { values.values = NULL; new_num = 8; } else { new_num = (values.values_num + values.values_num / 2); } new_values = realloc(values.values, sizeof(void *) * new_num); if (new_values == NULL) return ENOMEM; for (i = values.values_num; i < new_num; i++) new_values[i] = NULL; values.values = new_values; values.values_num = new_num; } assert(key < values.values_num); if (values.values[key] != NULL && dtor != NULL && dtor != DEAD_KEY) dtor(values.values[key]); values.values[key] = value; return 0; } void * pthread_getspecific(pthread_key_t key) { if (key >= values.values_num) return NULL; return values.values[key]; } #else #include #endif #else #include #endif static pthread_key_t dec_ctx_key; static pthread_once_t dec_ctx_once = PTHREAD_ONCE_INIT; #define DEC_CONTEXT() tsd_dec_ctx_get(&dec_ctx_key) // atexit finalizer to clean up the tsd dec contexts if main() exits // without having called pthread_exit() void jv_tsd_dec_ctx_fini(void) { jv_mem_free(pthread_getspecific(dec_ctx_key)); pthread_setspecific(dec_ctx_key, NULL); } void jv_tsd_dec_ctx_init(void) { if (pthread_key_create(&dec_ctx_key, jv_mem_free) != 0) { fprintf(stderr, "error: cannot create thread specific key"); abort(); } atexit(jv_tsd_dec_ctx_fini); } static decContext* tsd_dec_ctx_get(pthread_key_t *key) { pthread_once(&dec_ctx_once, jv_tsd_dec_ctx_init); // cannot fail decContext *ctx = (decContext*)pthread_getspecific(*key); if (ctx) { return ctx; } ctx = malloc(sizeof(decContext)); if (ctx) { if (key == &dec_ctx_key) { decContextDefault(ctx, DEC_INIT_BASE); // make sure (Int)D2U(rhs->exponent-lhs->exponent) does not overflow ctx->digits = MIN(DEC_MAX_DIGITS, INT32_MAX - (DECDPUN - 1) - (ctx->emax - ctx->emin - 1)); ctx->traps = 0; /*no errors*/ } if (pthread_setspecific(*key, ctx) != 0) { fprintf(stderr, "error: cannot store thread specific data"); abort(); } } return ctx; } typedef struct { jv_refcnt refcnt; double num_double; char * literal_data; decNumber num_decimal; // must be the last field in the structure for memory management } jvp_literal_number; typedef struct { decNumber number; decNumberUnit units[DEC_NUMBER_DOUBLE_EXTRA_UNITS]; } decNumberDoublePrecision; static inline int jvp_number_is_literal(jv n) { assert(JVP_HAS_KIND(n, JV_KIND_NUMBER)); return JVP_HAS_FLAGS(n, JVP_FLAGS_NUMBER_LITERAL); } static jvp_literal_number* jvp_literal_number_ptr(jv j) { assert(JVP_HAS_FLAGS(j, JVP_FLAGS_NUMBER_LITERAL)); return (jvp_literal_number*)j.u.ptr; } static decNumber* jvp_dec_number_ptr(jv j) { assert(JVP_HAS_FLAGS(j, JVP_FLAGS_NUMBER_LITERAL)); return &(((jvp_literal_number*)j.u.ptr)->num_decimal); } static jvp_literal_number* jvp_literal_number_alloc(unsigned literal_length) { /* The number of units needed is ceil(DECNUMDIGITS/DECDPUN) */ int units = ((literal_length+DECDPUN-1)/DECDPUN); jvp_literal_number* n = jv_mem_alloc( sizeof(jvp_literal_number) + sizeof(decNumberUnit) * units ); n->refcnt = JV_REFCNT_INIT; n->num_double = NAN; n->literal_data = NULL; return n; } static jv jvp_literal_number_new(const char * literal) { jvp_literal_number* n = jvp_literal_number_alloc(strlen(literal)); decContext *ctx = DEC_CONTEXT(); decContextClearStatus(ctx, DEC_Conversion_syntax); decNumberFromString(&n->num_decimal, literal, ctx); if (ctx->status & DEC_Conversion_syntax) { jv_mem_free(n); return JV_INVALID; } if (decNumberIsNaN(&n->num_decimal)) { // Reject NaN with payload. if (n->num_decimal.digits > 1 || *n->num_decimal.lsu != 0) { jv_mem_free(n); return JV_INVALID; } jv_mem_free(n); return jv_number(NAN); } jv r = {JVP_FLAGS_NUMBER_LITERAL, 0, 0, 0, {&n->refcnt}}; return r; } static double jvp_literal_number_to_double(jv j) { assert(JVP_HAS_FLAGS(j, JVP_FLAGS_NUMBER_LITERAL)); decContext dblCtx; // init as decimal64 but change digits to allow conversion to binary64 (double) decContextDefault(&dblCtx, DEC_INIT_DECIMAL64); dblCtx.digits = DEC_NUMBER_DOUBLE_PRECISION; decNumber *p_dec_number = jvp_dec_number_ptr(j); decNumberDoublePrecision dec_double; char literal[DEC_NUMBER_DOUBLE_PRECISION + DEC_NUMBER_STRING_GUARD + 1]; // reduce the number to the shortest possible form // that fits into the 64 bit floating point representation decNumberReduce(&dec_double.number, p_dec_number, &dblCtx); decNumberToString(&dec_double.number, literal); char *end; return jvp_strtod(tsd_dtoa_context_get(), literal, &end); } static const char* jvp_literal_number_literal(jv n) { assert(JVP_HAS_FLAGS(n, JVP_FLAGS_NUMBER_LITERAL)); decNumber *pdec = jvp_dec_number_ptr(n); jvp_literal_number* plit = jvp_literal_number_ptr(n); if (decNumberIsNaN(pdec)) { return "null"; } if (decNumberIsInfinite(pdec)) { // We cannot preserve the literal data of numbers outside the limited // range of exponent. Since `decNumberToString` returns "Infinity" // (or "-Infinity"), and to reduce stack allocations as possible, we // normalize infinities in the callers instead of printing the maximum // (or minimum) double here. return NULL; } if (plit->literal_data == NULL) { int len = jvp_dec_number_ptr(n)->digits + 15 /* 14 + NUL */; plit->literal_data = jv_mem_alloc(len); // Preserve the actual precision as we have parsed it // don't do decNumberTrim(pdec); decNumberToString(pdec, plit->literal_data); } return plit->literal_data; } int jv_number_has_literal(jv n) { assert(JVP_HAS_KIND(n, JV_KIND_NUMBER)); return JVP_HAS_FLAGS(n, JVP_FLAGS_NUMBER_LITERAL); } const char* jv_number_get_literal(jv n) { assert(JVP_HAS_KIND(n, JV_KIND_NUMBER)); if (JVP_HAS_FLAGS(n, JVP_FLAGS_NUMBER_LITERAL)) { return jvp_literal_number_literal(n); } else { return NULL; } } jv jv_number_with_literal(const char * literal) { return jvp_literal_number_new(literal); } #endif /* USE_DECNUM */ jv jv_number(double x) { jv j = { #ifdef USE_DECNUM JVP_FLAGS_NUMBER_NATIVE, #else JV_KIND_NUMBER, #endif 0, 0, 0, {.number = x} }; return j; } static void jvp_number_free(jv j) { assert(JVP_HAS_KIND(j, JV_KIND_NUMBER)); #ifdef USE_DECNUM if (JVP_HAS_FLAGS(j, JVP_FLAGS_NUMBER_LITERAL) && jvp_refcnt_dec(j.u.ptr)) { jvp_literal_number* n = jvp_literal_number_ptr(j); if (n->literal_data) { jv_mem_free(n->literal_data); } jv_mem_free(n); } #endif } double jv_number_value(jv j) { assert(JVP_HAS_KIND(j, JV_KIND_NUMBER)); #ifdef USE_DECNUM if (JVP_HAS_FLAGS(j, JVP_FLAGS_NUMBER_LITERAL)) { jvp_literal_number* n = jvp_literal_number_ptr(j); if (isnan(n->num_double)) { n->num_double = jvp_literal_number_to_double(j); } return n->num_double; } #endif return j.u.number; } int jv_is_integer(jv j){ if (!JVP_HAS_KIND(j, JV_KIND_NUMBER)){ return 0; } double x = jv_number_value(j); double ipart; double fpart = modf(x, &ipart); return fabs(fpart) < DBL_EPSILON; } int jvp_number_is_nan(jv n) { assert(JVP_HAS_KIND(n, JV_KIND_NUMBER)); #ifdef USE_DECNUM if (JVP_HAS_FLAGS(n, JVP_FLAGS_NUMBER_LITERAL)) { decNumber *pdec = jvp_dec_number_ptr(n); return decNumberIsNaN(pdec); } #endif return isnan(n.u.number); } jv jv_number_abs(jv n) { assert(JVP_HAS_KIND(n, JV_KIND_NUMBER)); #ifdef USE_DECNUM if (JVP_HAS_FLAGS(n, JVP_FLAGS_NUMBER_LITERAL)) { jvp_literal_number* m = jvp_literal_number_alloc(jvp_dec_number_ptr(n)->digits); decNumberAbs(&m->num_decimal, jvp_dec_number_ptr(n), DEC_CONTEXT()); jv r = {JVP_FLAGS_NUMBER_LITERAL, 0, 0, 0, {&m->refcnt}}; return r; } #endif return jv_number(fabs(jv_number_value(n))); } jv jv_number_negate(jv n) { assert(JVP_HAS_KIND(n, JV_KIND_NUMBER)); #ifdef USE_DECNUM if (JVP_HAS_FLAGS(n, JVP_FLAGS_NUMBER_LITERAL)) { jvp_literal_number* m = jvp_literal_number_alloc(jvp_dec_number_ptr(n)->digits); decNumberMinus(&m->num_decimal, jvp_dec_number_ptr(n), DEC_CONTEXT()); jv r = {JVP_FLAGS_NUMBER_LITERAL, 0, 0, 0, {&m->refcnt}}; return r; } #endif return jv_number(-jv_number_value(n)); } int jvp_number_cmp(jv a, jv b) { assert(JVP_HAS_KIND(a, JV_KIND_NUMBER)); assert(JVP_HAS_KIND(b, JV_KIND_NUMBER)); #ifdef USE_DECNUM if (JVP_HAS_FLAGS(a, JVP_FLAGS_NUMBER_LITERAL) && JVP_HAS_FLAGS(b, JVP_FLAGS_NUMBER_LITERAL)) { struct { decNumber number; decNumberUnit units[1]; } res; decNumberCompare(&res.number, jvp_dec_number_ptr(a), jvp_dec_number_ptr(b), DEC_CONTEXT() ); if (decNumberIsZero(&res.number)) { return 0; } else if (decNumberIsNegative(&res.number)) { return -1; } else { return 1; } } #endif double da = jv_number_value(a), db = jv_number_value(b); if (da < db) { return -1; } else if (da == db) { return 0; } else { return 1; } } static int jvp_number_equal(jv a, jv b) { return jvp_number_cmp(a, b) == 0; } /* * Arrays (internal helpers) */ #define ARRAY_SIZE_ROUND_UP(n) (((n)*3)/2) #define JVP_FLAGS_ARRAY JVP_MAKE_FLAGS(JV_KIND_ARRAY, JVP_PAYLOAD_ALLOCATED) static int imax(int a, int b) { if (a>b) return a; else return b; } //FIXME signed vs unsigned typedef struct { jv_refcnt refcnt; int length, alloc_length; jv elements[]; } jvp_array; static jvp_array* jvp_array_ptr(jv a) { assert(JVP_HAS_KIND(a, JV_KIND_ARRAY)); return (jvp_array*)a.u.ptr; } static jvp_array* jvp_array_alloc(unsigned size) { jvp_array* a = jv_mem_alloc(sizeof(jvp_array) + sizeof(jv) * size); a->refcnt.count = 1; a->length = 0; a->alloc_length = size; return a; } static jv jvp_array_new(unsigned size) { jv r = {JVP_FLAGS_ARRAY, 0, 0, 0, {&jvp_array_alloc(size)->refcnt}}; return r; } static void jvp_array_free(jv a) { assert(JVP_HAS_KIND(a, JV_KIND_ARRAY)); if (jvp_refcnt_dec(a.u.ptr)) { jvp_array* array = jvp_array_ptr(a); for (int i=0; ilength; i++) { jv_free(array->elements[i]); } jv_mem_free(array); } } static int jvp_array_length(jv a) { assert(JVP_HAS_KIND(a, JV_KIND_ARRAY)); return a.size; } static int jvp_array_offset(jv a) { assert(JVP_HAS_KIND(a, JV_KIND_ARRAY)); return a.offset; } static jv* jvp_array_read(jv a, int i) { assert(JVP_HAS_KIND(a, JV_KIND_ARRAY)); if (i >= 0 && i < jvp_array_length(a)) { jvp_array* array = jvp_array_ptr(a); assert(i + jvp_array_offset(a) < array->length); return &array->elements[i + jvp_array_offset(a)]; } else { return 0; } } static jv* jvp_array_write(jv* a, int i) { assert(i >= 0); jvp_array* array = jvp_array_ptr(*a); int pos = i + jvp_array_offset(*a); if (pos < array->alloc_length && jvp_refcnt_unshared(a->u.ptr)) { // use existing array space for (int j = array->length; j <= pos; j++) { array->elements[j] = JV_NULL; } array->length = imax(pos + 1, array->length); a->size = imax(i + 1, a->size); return &array->elements[pos]; } else { // allocate a new array int new_length = imax(i + 1, jvp_array_length(*a)); jvp_array* new_array = jvp_array_alloc(ARRAY_SIZE_ROUND_UP(new_length)); int j; for (j = 0; j < jvp_array_length(*a); j++) { new_array->elements[j] = jv_copy(array->elements[j + jvp_array_offset(*a)]); } for (; j < new_length; j++) { new_array->elements[j] = JV_NULL; } new_array->length = new_length; jvp_array_free(*a); jv new_jv = {JVP_FLAGS_ARRAY, 0, 0, new_length, {&new_array->refcnt}}; *a = new_jv; return &new_array->elements[i]; } } static int jvp_array_equal(jv a, jv b) { if (jvp_array_length(a) != jvp_array_length(b)) return 0; if (jvp_array_ptr(a) == jvp_array_ptr(b) && jvp_array_offset(a) == jvp_array_offset(b)) return 1; for (int i=0; i len) *pstart = len; if (*pend > len) *pend = len; if (*pend < *pstart) *pend = *pstart; } static int jvp_array_contains(jv a, jv b) { int r = 1; jv_array_foreach(b, bi, belem) { int ri = 0; jv_array_foreach(a, ai, aelem) { if (jv_contains(aelem, jv_copy(belem))) { ri = 1; break; } } jv_free(belem); if (!ri) { r = 0; break; } } return r; } /* * Public */ static jv jvp_array_slice(jv a, int start, int end) { assert(JVP_HAS_KIND(a, JV_KIND_ARRAY)); int len = jvp_array_length(a); jvp_clamp_slice_params(len, &start, &end); assert(0 <= start && start <= end && end <= len); // FIXME: maybe slice should reallocate if the slice is small enough if (start == end) { jv_free(a); return jv_array(); } if (a.offset + start >= 1 << (sizeof(a.offset) * CHAR_BIT)) { jv r = jv_array_sized(end - start); for (int i = start; i < end; i++) r = jv_array_append(r, jv_array_get(jv_copy(a), i)); jv_free(a); return r; } else { a.offset += start; a.size = end - start; return a; } } /* * Arrays (public interface) */ jv jv_array_sized(int n) { return jvp_array_new(n); } jv jv_array(void) { return jv_array_sized(16); } int jv_array_length(jv j) { assert(JVP_HAS_KIND(j, JV_KIND_ARRAY)); int len = jvp_array_length(j); jv_free(j); return len; } jv jv_array_get(jv j, int idx) { assert(JVP_HAS_KIND(j, JV_KIND_ARRAY)); jv* slot = jvp_array_read(j, idx); jv val; if (slot) { val = jv_copy(*slot); } else { val = jv_invalid(); } jv_free(j); return val; } jv jv_array_set(jv j, int idx, jv val) { assert(JVP_HAS_KIND(j, JV_KIND_ARRAY)); if (idx < 0) idx = jvp_array_length(j) + idx; if (idx < 0) { jv_free(j); jv_free(val); return jv_invalid_with_msg(jv_string("Out of bounds negative array index")); } if (idx > (INT_MAX >> 2) - jvp_array_offset(j)) { jv_free(j); jv_free(val); return jv_invalid_with_msg(jv_string("Array index too large")); } // copy/free of val,j coalesced jv* slot = jvp_array_write(&j, idx); jv_free(*slot); *slot = val; return j; } jv jv_array_append(jv j, jv val) { // copy/free of val,j coalesced return jv_array_set(j, jv_array_length(jv_copy(j)), val); } jv jv_array_concat(jv a, jv b) { assert(JVP_HAS_KIND(a, JV_KIND_ARRAY)); assert(JVP_HAS_KIND(b, JV_KIND_ARRAY)); // FIXME: could be faster jv_array_foreach(b, i, elem) { a = jv_array_append(a, elem); if (!jv_is_valid(a)) break; } jv_free(b); return a; } jv jv_array_slice(jv a, int start, int end) { assert(JVP_HAS_KIND(a, JV_KIND_ARRAY)); // copy/free of a coalesced return jvp_array_slice(a, start, end); } jv jv_array_indexes(jv a, jv b) { jv res = jv_array(); int idx = -1; int alen = jv_array_length(jv_copy(a)); for (int ai = 0; ai < alen; ++ai) { jv_array_foreach(b, bi, belem) { if (!jv_equal(jv_array_get(jv_copy(a), ai + bi), belem)) idx = -1; else if (bi == 0 && idx == -1) idx = ai; } if (idx > -1) res = jv_array_append(res, jv_number(idx)); idx = -1; } jv_free(a); jv_free(b); return res; } /* * Strings (internal helpers) */ #define JVP_FLAGS_STRING JVP_MAKE_FLAGS(JV_KIND_STRING, JVP_PAYLOAD_ALLOCATED) typedef struct { jv_refcnt refcnt; uint32_t hash; // high 31 bits are length, low bit is a flag // indicating whether hash has been computed. uint32_t length_hashed; uint32_t alloc_length; char data[]; } jvp_string; static jvp_string* jvp_string_ptr(jv a) { assert(JVP_HAS_KIND(a, JV_KIND_STRING)); return (jvp_string*)a.u.ptr; } static jvp_string* jvp_string_alloc(uint32_t size) { jvp_string* s = jv_mem_alloc(sizeof(jvp_string) + size + 1); s->refcnt.count = 1; s->alloc_length = size; return s; } /* Copy a UTF8 string, replacing all badly encoded points with U+FFFD */ static jv jvp_string_copy_replace_bad(const char* data, uint32_t length) { const char* end = data + length; const char* i = data; uint32_t maxlength = length * 3 + 1; // worst case: all bad bytes, each becomes a 3-byte U+FFFD jvp_string* s = jvp_string_alloc(maxlength); char* out = s->data; int c = 0; while ((i = jvp_utf8_next(i, end, &c))) { if (c == -1) { c = 0xFFFD; // U+FFFD REPLACEMENT CHARACTER } out += jvp_utf8_encode(c, out); assert(out < s->data + maxlength); } length = out - s->data; s->data[length] = 0; s->length_hashed = length << 1; jv r = {JVP_FLAGS_STRING, 0, 0, 0, {&s->refcnt}}; return r; } /* Assumes valid UTF8 */ static jv jvp_string_new(const char* data, uint32_t length) { jvp_string* s = jvp_string_alloc(length); s->length_hashed = length << 1; if (data != NULL) memcpy(s->data, data, length); s->data[length] = 0; jv r = {JVP_FLAGS_STRING, 0, 0, 0, {&s->refcnt}}; return r; } static jv jvp_string_empty_new(uint32_t length) { jvp_string* s = jvp_string_alloc(length); s->length_hashed = 0; memset(s->data, 0, length); s->data[length] = 0; jv r = {JVP_FLAGS_STRING, 0, 0, 0, {&s->refcnt}}; return r; } static void jvp_string_free(jv js) { jvp_string* s = jvp_string_ptr(js); if (jvp_refcnt_dec(&s->refcnt)) { jv_mem_free(s); } } static uint32_t jvp_string_length(jvp_string* s) { return s->length_hashed >> 1; } static uint32_t jvp_string_remaining_space(jvp_string* s) { assert(s->alloc_length >= jvp_string_length(s)); uint32_t r = s->alloc_length - jvp_string_length(s); return r; } static jv jvp_string_append(jv string, const char* data, uint32_t len) { jvp_string* s = jvp_string_ptr(string); uint32_t currlen = jvp_string_length(s); if (jvp_refcnt_unshared(string.u.ptr) && jvp_string_remaining_space(s) >= len) { // the next string fits at the end of a memcpy(s->data + currlen, data, len); s->data[currlen + len] = 0; s->length_hashed = (currlen + len) << 1; return string; } else { // allocate a bigger buffer and copy uint32_t allocsz = (currlen + len) * 2; if (allocsz < 32) allocsz = 32; jvp_string* news = jvp_string_alloc(allocsz); news->length_hashed = (currlen + len) << 1; memcpy(news->data, s->data, currlen); memcpy(news->data + currlen, data, len); news->data[currlen + len] = 0; jvp_string_free(string); jv r = {JVP_FLAGS_STRING, 0, 0, 0, {&news->refcnt}}; return r; } } static const uint32_t HASH_SEED = 0x432A9843; static uint32_t rotl32 (uint32_t x, int8_t r){ return (x << r) | (x >> (32 - r)); } static uint32_t jvp_string_hash(jv jstr) { jvp_string* str = jvp_string_ptr(jstr); if (str->length_hashed & 1) return str->hash; /* The following is based on MurmurHash3. MurmurHash3 was written by Austin Appleby, and is placed in the public domain. */ const uint8_t* data = (const uint8_t*)str->data; int len = (int)jvp_string_length(str); const int nblocks = len / 4; uint32_t h1 = HASH_SEED; const uint32_t c1 = 0xcc9e2d51; const uint32_t c2 = 0x1b873593; const uint32_t* blocks = (const uint32_t *)(data + nblocks*4); for(int i = -nblocks; i; i++) { uint32_t k1 = blocks[i]; //FIXME: endianness/alignment k1 *= c1; k1 = rotl32(k1,15); k1 *= c2; h1 ^= k1; h1 = rotl32(h1,13); h1 = h1*5+0xe6546b64; } const uint8_t* tail = (const uint8_t*)(data + nblocks*4); uint32_t k1 = 0; switch(len & 3) { case 3: k1 ^= tail[2] << 16; JQ_FALLTHROUGH; case 2: k1 ^= tail[1] << 8; JQ_FALLTHROUGH; case 1: k1 ^= tail[0]; k1 *= c1; k1 = rotl32(k1,15); k1 *= c2; h1 ^= k1; } h1 ^= len; h1 ^= h1 >> 16; h1 *= 0x85ebca6b; h1 ^= h1 >> 13; h1 *= 0xc2b2ae35; h1 ^= h1 >> 16; str->length_hashed |= 1; str->hash = h1; return h1; } static int jvp_string_equal(jv a, jv b) { assert(JVP_HAS_KIND(a, JV_KIND_STRING)); assert(JVP_HAS_KIND(b, JV_KIND_STRING)); jvp_string* stra = jvp_string_ptr(a); jvp_string* strb = jvp_string_ptr(b); if (jvp_string_length(stra) != jvp_string_length(strb)) return 0; return memcmp(stra->data, strb->data, jvp_string_length(stra)) == 0; } /* * Strings (public API) */ jv jv_string_sized(const char* str, int len) { return jvp_utf8_is_valid(str, str+len) ? jvp_string_new(str, len) : jvp_string_copy_replace_bad(str, len); } jv jv_string_empty(int len) { return jvp_string_empty_new(len); } jv jv_string(const char* str) { return jv_string_sized(str, strlen(str)); } int jv_string_length_bytes(jv j) { assert(JVP_HAS_KIND(j, JV_KIND_STRING)); int r = jvp_string_length(jvp_string_ptr(j)); jv_free(j); return r; } int jv_string_length_codepoints(jv j) { assert(JVP_HAS_KIND(j, JV_KIND_STRING)); const char* i = jv_string_value(j); const char* end = i + jv_string_length_bytes(jv_copy(j)); int c = 0, len = 0; while ((i = jvp_utf8_next(i, end, &c))) len++; jv_free(j); return len; } jv jv_string_indexes(jv j, jv k) { assert(JVP_HAS_KIND(j, JV_KIND_STRING)); assert(JVP_HAS_KIND(k, JV_KIND_STRING)); const char *jstr = jv_string_value(j); const char *idxstr = jv_string_value(k); const char *p, *lp; int jlen = jv_string_length_bytes(jv_copy(j)); int idxlen = jv_string_length_bytes(jv_copy(k)); jv a = jv_array(); if (idxlen != 0) { int n = 0; p = lp = jstr; while ((p = _jq_memmem(p, (jstr + jlen) - p, idxstr, idxlen)) != NULL) { while (lp < p) { lp += jvp_utf8_decode_length(*lp); n++; } a = jv_array_append(a, jv_number(n)); if (!jv_is_valid(a)) break; p++; } } jv_free(j); jv_free(k); return a; } jv jv_string_repeat(jv j, int n) { assert(JVP_HAS_KIND(j, JV_KIND_STRING)); if (n < 0) { jv_free(j); return jv_null(); } int len = jv_string_length_bytes(jv_copy(j)); int64_t res_len = (int64_t)len * n; if (res_len >= INT_MAX) { jv_free(j); return jv_invalid_with_msg(jv_string("Repeat string result too long")); } if (res_len == 0) { jv_free(j); return jv_string(""); } jv res = jv_string_empty(res_len); res = jvp_string_append(res, jv_string_value(j), len); for (int curr = len, grow; curr < res_len; curr += grow) { grow = MIN(res_len - curr, curr); res = jvp_string_append(res, jv_string_value(res), grow); } jv_free(j); return res; } jv jv_string_split(jv j, jv sep) { assert(JVP_HAS_KIND(j, JV_KIND_STRING)); assert(JVP_HAS_KIND(sep, JV_KIND_STRING)); const char *jstr = jv_string_value(j); const char *jend = jstr + jv_string_length_bytes(jv_copy(j)); const char *sepstr = jv_string_value(sep); const char *p, *s; int seplen = jv_string_length_bytes(jv_copy(sep)); jv a = jv_array(); assert(jv_get_refcnt(a) == 1); if (seplen == 0) { int c; while ((jstr = jvp_utf8_next(jstr, jend, &c))) { a = jv_array_append(a, jv_string_append_codepoint(jv_string(""), c)); if (!jv_is_valid(a)) break; } } else { for (p = jstr; p < jend; p = s + seplen) { s = _jq_memmem(p, jend - p, sepstr, seplen); if (s == NULL) s = jend; a = jv_array_append(a, jv_string_sized(p, s - p)); if (!jv_is_valid(a)) break; // Add an empty string to denote that j ends on a sep if (s + seplen == jend && seplen != 0) a = jv_array_append(a, jv_string("")); } } jv_free(j); jv_free(sep); return a; } jv jv_string_explode(jv j) { assert(JVP_HAS_KIND(j, JV_KIND_STRING)); const char* i = jv_string_value(j); int len = jv_string_length_bytes(jv_copy(j)); const char* end = i + len; jv a = jv_array_sized(len); int c; while ((i = jvp_utf8_next(i, end, &c))) { a = jv_array_append(a, jv_number(c)); if (!jv_is_valid(a)) break; } jv_free(j); return a; } jv jv_string_implode(jv j) { assert(JVP_HAS_KIND(j, JV_KIND_ARRAY)); int len = jv_array_length(jv_copy(j)); jv s = jv_string_empty(len); int i; assert(len >= 0); for (i = 0; i < len; i++) { jv n = jv_array_get(jv_copy(j), i); assert(JVP_HAS_KIND(n, JV_KIND_NUMBER)); int nv = jv_number_value(n); jv_free(n); // outside codepoint range or in utf16 surrogate pair range if (nv < 0 || nv > 0x10FFFF || (nv >= 0xD800 && nv <= 0xDFFF)) nv = 0xFFFD; // U+FFFD REPLACEMENT CHARACTER s = jv_string_append_codepoint(s, nv); } jv_free(j); return s; } unsigned long jv_string_hash(jv j) { assert(JVP_HAS_KIND(j, JV_KIND_STRING)); uint32_t hash = jvp_string_hash(j); jv_free(j); return hash; } const char* jv_string_value(jv j) { assert(JVP_HAS_KIND(j, JV_KIND_STRING)); return jvp_string_ptr(j)->data; } jv jv_string_slice(jv j, int start, int end) { assert(JVP_HAS_KIND(j, JV_KIND_STRING)); const char *s = jv_string_value(j); int len = jv_string_length_bytes(jv_copy(j)); int i; const char *p, *e; int c; jv res; jvp_clamp_slice_params(len, &start, &end); assert(0 <= start && start <= end && end <= len); /* Look for byte offset corresponding to start codepoints */ for (p = s, i = 0; i < start; i++) { p = jvp_utf8_next(p, s + len, &c); if (p == NULL) { jv_free(j); return jv_string_empty(16); } if (c == -1) { jv_free(j); return jv_invalid_with_msg(jv_string("Invalid UTF-8 string")); } } /* Look for byte offset corresponding to end codepoints */ for (e = p; e != NULL && i < end; i++) { e = jvp_utf8_next(e, s + len, &c); if (e == NULL) { e = s + len; break; } if (c == -1) { jv_free(j); return jv_invalid_with_msg(jv_string("Invalid UTF-8 string")); } } /* * NOTE: Ideally we should do here what jvp_array_slice() does instead * of allocating a new string as we do! However, we assume NUL- * terminated strings all over, and in the jv API, so for now we waste * memory like a drunken navy programmer. There's probably nothing we * can do about it. */ res = jv_string_sized(p, e - p); jv_free(j); return res; } jv jv_string_concat(jv a, jv b) { a = jvp_string_append(a, jv_string_value(b), jvp_string_length(jvp_string_ptr(b))); jv_free(b); return a; } jv jv_string_append_buf(jv a, const char* buf, int len) { if (jvp_utf8_is_valid(buf, buf+len)) { a = jvp_string_append(a, buf, len); } else { jv b = jvp_string_copy_replace_bad(buf, len); a = jv_string_concat(a, b); } return a; } jv jv_string_append_codepoint(jv a, uint32_t c) { char buf[5]; int len = jvp_utf8_encode(c, buf); a = jvp_string_append(a, buf, len); return a; } jv jv_string_append_str(jv a, const char* str) { return jv_string_append_buf(a, str, strlen(str)); } jv jv_string_vfmt(const char* fmt, va_list ap) { int size = 1024; while (1) { char* buf = jv_mem_alloc(size); va_list ap2; va_copy(ap2, ap); int n = vsnprintf(buf, size, fmt, ap2); va_end(ap2); /* * NOTE: here we support old vsnprintf()s that return -1 because the * buffer is too small. */ if (n >= 0 && n < size) { jv ret = jv_string_sized(buf, n); jv_mem_free(buf); return ret; } else { jv_mem_free(buf); size = (n > 0) ? /* standard */ (n * 2) : /* not standard */ (size * 2); } } } jv jv_string_fmt(const char* fmt, ...) { va_list args; va_start(args, fmt); jv res = jv_string_vfmt(fmt, args); va_end(args); return res; } /* * Objects (internal helpers) */ #define JVP_FLAGS_OBJECT JVP_MAKE_FLAGS(JV_KIND_OBJECT, JVP_PAYLOAD_ALLOCATED) struct object_slot { int next; /* next slot with same hash, for collisions */ uint32_t hash; jv string; jv value; }; typedef struct { jv_refcnt refcnt; int next_free; struct object_slot elements[]; } jvp_object; /* warning: nontrivial justification of alignment */ static jv jvp_object_new(int size) { // Allocates an object of (size) slots and (size*2) hash buckets. // size must be a power of two assert(size > 0 && (size & (size - 1)) == 0); jvp_object* obj = jv_mem_alloc(sizeof(jvp_object) + sizeof(struct object_slot) * size + sizeof(int) * (size * 2)); obj->refcnt.count = 1; for (int i=0; ielements[i].next = i - 1; obj->elements[i].string = JV_NULL; obj->elements[i].hash = 0; obj->elements[i].value = JV_NULL; } obj->next_free = 0; int* hashbuckets = (int*)(&obj->elements[size]); for (int i=0; irefcnt}}; return r; } static jvp_object* jvp_object_ptr(jv o) { assert(JVP_HAS_KIND(o, JV_KIND_OBJECT)); return (jvp_object*)o.u.ptr; } static uint32_t jvp_object_mask(jv o) { assert(JVP_HAS_KIND(o, JV_KIND_OBJECT)); return (o.size * 2) - 1; } static int jvp_object_size(jv o) { assert(JVP_HAS_KIND(o, JV_KIND_OBJECT)); return o.size; } static int* jvp_object_buckets(jv o) { return (int*)(&jvp_object_ptr(o)->elements[o.size]); } static int* jvp_object_find_bucket(jv object, jv key) { return jvp_object_buckets(object) + (jvp_object_mask(object) & jvp_string_hash(key)); } static struct object_slot* jvp_object_get_slot(jv object, int slot) { assert(slot == -1 || (slot >= 0 && slot < jvp_object_size(object))); if (slot == -1) return 0; else return &jvp_object_ptr(object)->elements[slot]; } static struct object_slot* jvp_object_next_slot(jv object, struct object_slot* slot) { return jvp_object_get_slot(object, slot->next); } static struct object_slot* jvp_object_find_slot(jv object, jv keystr, int* bucket) { uint32_t hash = jvp_string_hash(keystr); for (struct object_slot* curr = jvp_object_get_slot(object, *bucket); curr; curr = jvp_object_next_slot(object, curr)) { if (curr->hash == hash && jvp_string_equal(keystr, curr->string)) { return curr; } } return 0; } static struct object_slot* jvp_object_add_slot(jv object, jv key, int* bucket) { jvp_object* o = jvp_object_ptr(object); int newslot_idx = o->next_free; if (newslot_idx == jvp_object_size(object)) return 0; struct object_slot* newslot = jvp_object_get_slot(object, newslot_idx); o->next_free++; newslot->next = *bucket; *bucket = newslot_idx; newslot->hash = jvp_string_hash(key); newslot->string = key; return newslot; } static jv* jvp_object_read(jv object, jv key) { assert(JVP_HAS_KIND(key, JV_KIND_STRING)); int* bucket = jvp_object_find_bucket(object, key); struct object_slot* slot = jvp_object_find_slot(object, key, bucket); if (slot == 0) return 0; else return &slot->value; } static void jvp_object_free(jv o) { assert(JVP_HAS_KIND(o, JV_KIND_OBJECT)); if (jvp_refcnt_dec(o.u.ptr)) { for (int i=0; istring) != JV_KIND_NULL) { jvp_string_free(slot->string); jv_free(slot->value); } } jv_mem_free(jvp_object_ptr(o)); } } static int jvp_object_rehash(jv *objectp) { jv object = *objectp; assert(JVP_HAS_KIND(object, JV_KIND_OBJECT)); assert(jvp_refcnt_unshared(object.u.ptr)); int size = jvp_object_size(object); if (size > INT_MAX >> 2) return 0; jv new_object = jvp_object_new(size * 2); for (int i=0; istring) == JV_KIND_NULL) continue; int* new_bucket = jvp_object_find_bucket(new_object, slot->string); assert(!jvp_object_find_slot(new_object, slot->string, new_bucket)); struct object_slot* new_slot = jvp_object_add_slot(new_object, slot->string, new_bucket); assert(new_slot); new_slot->value = slot->value; } // references are transported, just drop the old table jv_mem_free(jvp_object_ptr(object)); *objectp = new_object; return 1; } static jv jvp_object_unshare(jv object) { assert(JVP_HAS_KIND(object, JV_KIND_OBJECT)); if (jvp_refcnt_unshared(object.u.ptr)) return object; jv new_object = jvp_object_new(jvp_object_size(object)); jvp_object_ptr(new_object)->next_free = jvp_object_ptr(object)->next_free; for (int i=0; istring) != JV_KIND_NULL) { new_slot->string = jv_copy(old_slot->string); new_slot->value = jv_copy(old_slot->value); } } int* old_buckets = jvp_object_buckets(object); int* new_buckets = jvp_object_buckets(new_object); memcpy(new_buckets, old_buckets, sizeof(int) * jvp_object_size(new_object)*2); jvp_object_free(object); assert(jvp_refcnt_unshared(new_object.u.ptr)); return new_object; } static int jvp_object_write(jv* object, jv key, jv **valpp) { *object = jvp_object_unshare(*object); int* bucket = jvp_object_find_bucket(*object, key); struct object_slot* slot = jvp_object_find_slot(*object, key, bucket); if (slot) { // already has the key jvp_string_free(key); *valpp = &slot->value; return 1; } slot = jvp_object_add_slot(*object, key, bucket); if (slot) { slot->value = jv_invalid(); } else { if (!jvp_object_rehash(object)) { jvp_string_free(key); *valpp = NULL; return 0; } bucket = jvp_object_find_bucket(*object, key); assert(!jvp_object_find_slot(*object, key, bucket)); slot = jvp_object_add_slot(*object, key, bucket); assert(slot); slot->value = jv_invalid(); } *valpp = &slot->value; return 1; } static int jvp_object_delete(jv* object, jv key) { assert(JVP_HAS_KIND(key, JV_KIND_STRING)); *object = jvp_object_unshare(*object); int* bucket = jvp_object_find_bucket(*object, key); int* prev_ptr = bucket; uint32_t hash = jvp_string_hash(key); for (struct object_slot* curr = jvp_object_get_slot(*object, *bucket); curr; curr = jvp_object_next_slot(*object, curr)) { if (hash == curr->hash && jvp_string_equal(key, curr->string)) { *prev_ptr = curr->next; jvp_string_free(curr->string); curr->string = JV_NULL; jv_free(curr->value); return 1; } prev_ptr = &curr->next; } return 0; } static int jvp_object_length(jv object) { int n = 0; for (int i=0; istring) != JV_KIND_NULL) n++; } return n; } static int jvp_object_equal(jv o1, jv o2) { int len2 = jvp_object_length(o2); int len1 = 0; for (int i=0; istring) == JV_KIND_NULL) continue; jv* slot2 = jvp_object_read(o2, slot->string); if (!slot2) return 0; // FIXME: do less refcounting here if (!jv_equal(jv_copy(slot->value), jv_copy(*slot2))) return 0; len1++; } return len1 == len2; } static int jvp_object_contains(jv a, jv b) { assert(JVP_HAS_KIND(a, JV_KIND_OBJECT)); assert(JVP_HAS_KIND(b, JV_KIND_OBJECT)); int r = 1; jv_object_foreach(b, key, b_val) { jv a_val = jv_object_get(jv_copy(a), key); r = jv_contains(a_val, b_val); if (!r) break; } return r; } /* * Objects (public interface) */ #define DEFAULT_OBJECT_SIZE 8 jv jv_object(void) { return jvp_object_new(8); } jv jv_object_get(jv object, jv key) { assert(JVP_HAS_KIND(object, JV_KIND_OBJECT)); assert(JVP_HAS_KIND(key, JV_KIND_STRING)); jv* slot = jvp_object_read(object, key); jv val; if (slot) { val = jv_copy(*slot); } else { val = jv_invalid(); } jv_free(object); jv_free(key); return val; } int jv_object_has(jv object, jv key) { assert(JVP_HAS_KIND(object, JV_KIND_OBJECT)); assert(JVP_HAS_KIND(key, JV_KIND_STRING)); jv* slot = jvp_object_read(object, key); int res = slot ? 1 : 0; jv_free(object); jv_free(key); return res; } jv jv_object_set(jv object, jv key, jv value) { assert(JVP_HAS_KIND(object, JV_KIND_OBJECT)); assert(JVP_HAS_KIND(key, JV_KIND_STRING)); // copy/free of object, key, value coalesced jv* slot; if (!jvp_object_write(&object, key, &slot)) { jv_free(object); jv_free(value); return jv_invalid_with_msg(jv_string("Object too big")); } jv_free(*slot); *slot = value; return object; } jv jv_object_delete(jv object, jv key) { assert(JVP_HAS_KIND(object, JV_KIND_OBJECT)); assert(JVP_HAS_KIND(key, JV_KIND_STRING)); jvp_object_delete(&object, key); jv_free(key); return object; } int jv_object_length(jv object) { assert(JVP_HAS_KIND(object, JV_KIND_OBJECT)); int n = jvp_object_length(object); jv_free(object); return n; } jv jv_object_merge(jv a, jv b) { assert(JVP_HAS_KIND(a, JV_KIND_OBJECT)); jv_object_foreach(b, k, v) { a = jv_object_set(a, k, v); if (!jv_is_valid(a)) break; } jv_free(b); return a; } jv jv_object_merge_recursive(jv a, jv b) { assert(JVP_HAS_KIND(a, JV_KIND_OBJECT)); assert(JVP_HAS_KIND(b, JV_KIND_OBJECT)); jv_object_foreach(b, k, v) { jv elem = jv_object_get(jv_copy(a), jv_copy(k)); if (jv_is_valid(elem) && JVP_HAS_KIND(elem, JV_KIND_OBJECT) && JVP_HAS_KIND(v, JV_KIND_OBJECT)) { a = jv_object_set(a, k, jv_object_merge_recursive(elem, v)); } else { jv_free(elem); a = jv_object_set(a, k, v); } if (!jv_is_valid(a)) break; } jv_free(b); return a; } /* * Object iteration (internal helpers) */ enum { ITER_FINISHED = -2 }; int jv_object_iter_valid(jv object, int i) { return i != ITER_FINISHED; } int jv_object_iter(jv object) { assert(JVP_HAS_KIND(object, JV_KIND_OBJECT)); return jv_object_iter_next(object, -1); } int jv_object_iter_next(jv object, int iter) { assert(JVP_HAS_KIND(object, JV_KIND_OBJECT)); assert(iter != ITER_FINISHED); struct object_slot* slot; do { iter++; if (iter >= jvp_object_size(object)) return ITER_FINISHED; slot = jvp_object_get_slot(object, iter); } while (jv_get_kind(slot->string) == JV_KIND_NULL); assert(jv_get_kind(jvp_object_get_slot(object,iter)->string) == JV_KIND_STRING); return iter; } jv jv_object_iter_key(jv object, int iter) { jv s = jvp_object_get_slot(object, iter)->string; assert(JVP_HAS_KIND(s, JV_KIND_STRING)); return jv_copy(s); } jv jv_object_iter_value(jv object, int iter) { return jv_copy(jvp_object_get_slot(object, iter)->value); } /* * Memory management */ jv jv_copy(jv j) { if (JVP_IS_ALLOCATED(j)) { jvp_refcnt_inc(j.u.ptr); } return j; } void jv_free(jv j) { switch(JVP_KIND(j)) { case JV_KIND_ARRAY: jvp_array_free(j); break; case JV_KIND_STRING: jvp_string_free(j); break; case JV_KIND_OBJECT: jvp_object_free(j); break; case JV_KIND_INVALID: jvp_invalid_free(j); break; case JV_KIND_NUMBER: jvp_number_free(j); break; } } int jv_get_refcnt(jv j) { if (JVP_IS_ALLOCATED(j)) { return j.u.ptr->count; } else { return 1; } } /* * Higher-level operations */ int jv_equal(jv a, jv b) { int r; if (jv_get_kind(a) != jv_get_kind(b)) { r = 0; } else if (JVP_IS_ALLOCATED(a) && JVP_IS_ALLOCATED(b) && a.kind_flags == b.kind_flags && a.size == b.size && a.u.ptr == b.u.ptr) { r = 1; } else { switch (jv_get_kind(a)) { case JV_KIND_NUMBER: r = jvp_number_equal(a, b); break; case JV_KIND_ARRAY: r = jvp_array_equal(a, b); break; case JV_KIND_STRING: r = jvp_string_equal(a, b); break; case JV_KIND_OBJECT: r = jvp_object_equal(a, b); break; default: r = 1; break; } } jv_free(a); jv_free(b); return r; } int jv_identical(jv a, jv b) { int r; if (a.kind_flags != b.kind_flags || a.offset != b.offset || a.size != b.size) { r = 0; } else { if (JVP_IS_ALLOCATED(a) /* b has the same flags */) { r = a.u.ptr == b.u.ptr; } else { r = memcmp(&a.u.ptr, &b.u.ptr, sizeof(a.u)) == 0; } } jv_free(a); jv_free(b); return r; } int jv_contains(jv a, jv b) { int r = 1; if (jv_get_kind(a) != jv_get_kind(b)) { r = 0; } else if (JVP_HAS_KIND(a, JV_KIND_OBJECT)) { r = jvp_object_contains(a, b); } else if (JVP_HAS_KIND(a, JV_KIND_ARRAY)) { r = jvp_array_contains(a, b); } else if (JVP_HAS_KIND(a, JV_KIND_STRING)) { int b_len = jv_string_length_bytes(jv_copy(b)); if (b_len != 0) { r = _jq_memmem(jv_string_value(a), jv_string_length_bytes(jv_copy(a)), jv_string_value(b), b_len) != 0; } else { r = 1; } } else { r = jv_equal(jv_copy(a), jv_copy(b)); } jv_free(a); jv_free(b); return r; } ================================================ FILE: src/jv.h ================================================ #ifndef JV_H #define JV_H #include #include #include #ifdef __cplusplus extern "C" { #endif #if (defined(__GNUC__) && __GNUC__ >= 7) || \ (defined(__clang__) && __clang_major__ >= 10) # define JQ_FALLTHROUGH __attribute__((fallthrough)) #else # define JQ_FALLTHROUGH do {} while (0) /* fallthrough */ #endif typedef enum { JV_KIND_INVALID, JV_KIND_NULL, JV_KIND_FALSE, JV_KIND_TRUE, JV_KIND_NUMBER, JV_KIND_STRING, JV_KIND_ARRAY, 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; union { struct jv_refcnt* ptr; double number; } u; } jv; /* * All jv_* functions consume (decref) input and produce (incref) output * Except jv_copy */ jv_kind jv_get_kind(jv); const char* jv_kind_name(jv_kind); 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_identical(jv, jv); int jv_contains(jv, jv); jv jv_invalid(void); 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_bool(int); jv jv_number(double); jv jv_number_with_literal(const char*); double jv_number_value(jv); int jv_is_integer(jv); jv jv_number_abs(jv); jv jv_number_negate(jv); int jv_number_has_literal(jv); const char* jv_number_get_literal(jv); jv jv_array(void); jv jv_array_sized(int); int jv_array_length(jv); jv jv_array_get(jv, int); 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) \ for (jv x; \ i < jv_len__ ? \ (x = jv_array_get(jv_copy(a), i), 1) : 0; \ i++) #define JV_ARRAY_1(e) (jv_array_append(jv_array(),e)) #define JV_ARRAY_2(e1,e2) (jv_array_append(JV_ARRAY_1(e1),e2)) #define JV_ARRAY_3(e1,e2,e3) (jv_array_append(JV_ARRAY_2(e1,e2),e3)) #define JV_ARRAY_4(e1,e2,e3,e4) (jv_array_append(JV_ARRAY_3(e1,e2,e3),e4)) #define JV_ARRAY_5(e1,e2,e3,e4,e5) (jv_array_append(JV_ARRAY_4(e1,e2,e3,e4),e5)) #define JV_ARRAY_6(e1,e2,e3,e4,e5,e6) (jv_array_append(JV_ARRAY_5(e1,e2,e3,e4,e5),e6)) #define JV_ARRAY_7(e1,e2,e3,e4,e5,e6,e7) (jv_array_append(JV_ARRAY_6(e1,e2,e3,e4,e5,e6),e7)) #define JV_ARRAY_8(e1,e2,e3,e4,e5,e6,e7,e8) (jv_array_append(JV_ARRAY_7(e1,e2,e3,e4,e5,e6,e7),e8)) #define JV_ARRAY_9(e1,e2,e3,e4,e5,e6,e7,e8,e9) (jv_array_append(JV_ARRAY_8(e1,e2,e3,e4,e5,e6,e7,e8),e9)) #define JV_ARRAY_IDX(_1,_2,_3,_4,_5,_6,_7,_8,_9,NAME,...) NAME #define JV_ARRAY(...) \ JV_ARRAY_IDX(__VA_ARGS__, JV_ARRAY_9, JV_ARRAY_8, JV_ARRAY_7, JV_ARRAY_6, JV_ARRAY_5, JV_ARRAY_4, JV_ARRAY_3, JV_ARRAY_2, JV_ARRAY_1, dummy)(__VA_ARGS__) #ifdef __GNUC__ #define JV_PRINTF_LIKE(fmt_arg_num, args_num) \ __attribute__ ((__format__( __printf__, fmt_arg_num, args_num))) #define JV_VPRINTF_LIKE(fmt_arg_num) \ __attribute__ ((__format__( __printf__, fmt_arg_num, 0))) #else #define JV_PRINTF_LIKE(fmt_arg_num, args_num) #define JV_VPRINTF_LIKE(fmt_arg_num) #endif 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); 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_VPRINTF_LIKE(1); jv jv_string_fmt(const char*, ...) JV_PRINTF_LIKE(1, 2); 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_repeat(jv j, int n); 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_get(jv object, jv key); int jv_object_has(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); int jv_object_iter_valid(jv, int); jv jv_object_iter_key(jv, int); jv jv_object_iter_value(jv, int); #define jv_object_foreach(t, k, v) \ for (int jv_i__ = jv_object_iter(t), jv_j__ = 1; jv_j__; jv_j__ = 0) \ for (jv k, v; \ jv_object_iter_valid((t), jv_i__) ? \ (k = jv_object_iter_key(t, jv_i__), \ v = jv_object_iter_value(t, jv_i__), \ 1) \ : 0; \ jv_i__ = jv_object_iter_next(t, jv_i__)) \ #define jv_object_keys_foreach(t, k) \ for (int jv_i__ = jv_object_iter(t), jv_j__ = 1; jv_j__; jv_j__ = 0) \ for (jv k; \ jv_object_iter_valid((t), jv_i__) ? \ (k = jv_object_iter_key(t, jv_i__), \ 1) \ : 0; \ jv_i__ = jv_object_iter_next(t, jv_i__)) #define JV_OBJECT_1(k1) (jv_object_set(jv_object(),(k1),jv_null())) #define JV_OBJECT_2(k1,v1) (jv_object_set(jv_object(),(k1),(v1))) #define JV_OBJECT_3(k1,v1,k2) (jv_object_set(JV_OBJECT_2((k1),(v1)),(k2),jv_null())) #define JV_OBJECT_4(k1,v1,k2,v2) (jv_object_set(JV_OBJECT_2((k1),(v1)),(k2),(v2))) #define JV_OBJECT_5(k1,v1,k2,v2,k3) (jv_object_set(JV_OBJECT_4((k1),(v1),(k2),(v2)),(k3),jv_null())) #define JV_OBJECT_6(k1,v1,k2,v2,k3,v3) (jv_object_set(JV_OBJECT_4((k1),(v1),(k2),(v2)),(k3),(v3))) #define JV_OBJECT_7(k1,v1,k2,v2,k3,v3,k4) (jv_object_set(JV_OBJECT_6((k1),(v1),(k2),(v2),(k3),(v3)),(k4),jv_null())) #define JV_OBJECT_8(k1,v1,k2,v2,k3,v3,k4,v4) (jv_object_set(JV_OBJECT_6((k1),(v1),(k2),(v2),(k3),(v3)),(k4),(v4))) #define JV_OBJECT_9(k1,v1,k2,v2,k3,v3,k4,v4,k5) \ (jv_object_set(JV_OBJECT_8((k1),(v1),(k2),(v2),(k3),(v3),(k4),(v4)),(k5),jv_null())) #define JV_OBJECT_10(k1,v1,k2,v2,k3,v3,k4,v4,k5,v5) \ (jv_object_set(JV_OBJECT_8((k1),(v1),(k2),(v2),(k3),(v3),(k4),(v4)),(k5),(v5))) #define JV_OBJECT_11(k1,v1,k2,v2,k3,v3,k4,v4,k5,v5,k6) \ (jv_object_set(JV_OBJECT_10((k1),(v1),(k2),(v2),(k3),(v3),(k4),(v4),(k5),(v5)),(k6),jv_null())) #define JV_OBJECT_12(k1,v1,k2,v2,k3,v3,k4,v4,k5,v5,k6,v6) \ (jv_object_set(JV_OBJECT_10((k1),(v1),(k2),(v2),(k3),(v3),(k4),(v4),(k5),(v5)),(k6),(v6))) #define JV_OBJECT_13(k1,v1,k2,v2,k3,v3,k4,v4,k5,v5,k6,v6,k7) \ (jv_object_set(JV_OBJECT_12((k1),(v1),(k2),(v2),(k3),(v3),(k4),(v4),(k5),(v5),(k6),(v6)),(k7),jv_null())) #define JV_OBJECT_14(k1,v1,k2,v2,k3,v3,k4,v4,k5,v5,k6,v6,k7,v7) \ (jv_object_set(JV_OBJECT_12((k1),(v1),(k2),(v2),(k3),(v3),(k4),(v4),(k5),(v5),(k6),(v6)),(k7),(v7))) #define JV_OBJECT_15(k1,v1,k2,v2,k3,v3,k4,v4,k5,v5,k6,v6,k7,v7,k8) \ (jv_object_set(JV_OBJECT_14((k1),(v1),(k2),(v2),(k3),(v3),(k4),(v4),(k5),(v5),(k6),(v6),(k7),(v7)),(k8),jv_null())) #define JV_OBJECT_16(k1,v1,k2,v2,k3,v3,k4,v4,k5,v5,k6,v6,k7,v7,k8,v8) \ (jv_object_set(JV_OBJECT_14((k1),(v1),(k2),(v2),(k3),(v3),(k4),(v4),(k5),(v5),(k6),(v6),(k7),(v7)),(k8),(v8))) #define JV_OBJECT_17(k1,v1,k2,v2,k3,v3,k4,v4,k5,v5,k6,v6,k7,v7,k8,v8,k9) \ (jv_object_set(JV_OBJECT_16((k1),(v1),(k2),(v2),(k3),(v3),(k4),(v4),(k5),(v5),(k6),(v6),(k7),(v7),(k8),(v8)),(k9),jv_null())) #define JV_OBJECT_18(k1,v1,k2,v2,k3,v3,k4,v4,k5,v5,k6,v6,k7,v7,k8,v8,k9,v9) \ (jv_object_set(JV_OBJECT_16((k1),(v1),(k2),(v2),(k3),(v3),(k4),(v4),(k5),(v5),(k6),(v6),(k7),(v7),(k8),(v8)),(k9),(v9))) #define JV_OBJECT_IDX(_1,_2,_3,_4,_5,_6,_7,_8,_9,_10,_11,_12,_13,_14,_15,_16,_17,_18,NAME,...) NAME #define JV_OBJECT(...) \ JV_OBJECT_IDX(__VA_ARGS__, \ JV_OBJECT_18, JV_OBJECT_17, JV_OBJECT_16, JV_OBJECT_15, \ JV_OBJECT_14, JV_OBJECT_13, JV_OBJECT_12, JV_OBJECT_11, \ JV_OBJECT_10, JV_OBJECT_9, JV_OBJECT_8, JV_OBJECT_7, \ JV_OBJECT_6, JV_OBJECT_5, JV_OBJECT_4, JV_OBJECT_3, \ JV_OBJECT_2, JV_OBJECT_1)(__VA_ARGS__) int jv_get_refcnt(jv); enum jv_print_flags { JV_PRINT_PRETTY = 1, JV_PRINT_ASCII = 2, JV_PRINT_COLOR = 4, JV_PRINT_COLOUR = 4, JV_PRINT_SORTED = 8, JV_PRINT_INVALID = 16, JV_PRINT_REFCOUNT = 32, JV_PRINT_TAB = 64, JV_PRINT_ISATTY = 128, JV_PRINT_SPACE0 = 256, JV_PRINT_SPACE1 = 512, JV_PRINT_SPACE2 = 1024, }; #define JV_PRINT_INDENT_FLAGS(n) \ ((n) < 0 || (n) > 7 ? JV_PRINT_TAB | JV_PRINT_PRETTY : (n) << 8 | JV_PRINT_PRETTY) void jv_dumpf(jv, FILE *f, int flags); void jv_dump(jv, int flags); void jv_show(jv, int flags); jv jv_dump_string(jv, int flags); char *jv_dump_string_trunc(jv x, char *outbuf, size_t bufsize); enum { JV_PARSE_SEQ = 1, JV_PARSE_STREAMING = 2, JV_PARSE_STREAM_ERRORS = 4, }; jv jv_parse(const char* string); jv jv_parse_sized(const char* string, int length); jv jv_parse_custom_flags(const char* string, int flags); typedef void (*jv_nomem_handler_f)(void *); void jv_nomem_handler(jv_nomem_handler_f, void *); jv jv_load_file(const char *, int); typedef struct jv_parser jv_parser; jv_parser* jv_parser_new(int); void jv_parser_set_buf(jv_parser*, const char*, int, int); int jv_parser_remaining(jv_parser*); jv jv_parser_next(jv_parser*); void jv_parser_free(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*/); jv jv_keys_unsorted(jv /*object or array*/); int jv_cmp(jv, jv); jv jv_sort(jv, jv); jv jv_group(jv, jv); jv jv_unique(jv, jv); #ifdef __cplusplus } #endif #endif /* true/false/null: check kind number: introduce/eliminate jv to integer array: copy free slice index update updateslice? */ ================================================ FILE: src/jv_alloc.c ================================================ #include #include #include #include #include "jv.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(void) { if (nomem_handler.handler) nomem_handler.handler(nomem_handler.data); // Maybe handler() will longjmp() to safety // Or not fprintf(stderr, "jq: error: cannot allocate memory\n"); abort(); } #else /* USE_TLS */ #ifdef HAVE_PTHREAD_KEY_CREATE #include static pthread_key_t nomem_handler_key; static pthread_once_t mem_once = PTHREAD_ONCE_INIT; /* tsd_fini is called on application exit */ /* it clears the nomem_handler allocated in the main thread */ 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); } } /* The tsd_fini_thread is a destructor set by calling */ /* pthread_key_create(&nomem_handler_key, tsd_fini_thread) */ /* It is called when thread ends */ static void tsd_fini_thread(void *nomem_handler) { free(nomem_handler); } static void tsd_init(void) { if (pthread_key_create(&nomem_handler_key, tsd_fini_thread) != 0) { fprintf(stderr, "jq: error: cannot create thread specific key"); abort(); } if (atexit(tsd_fini) != 0) { fprintf(stderr, "jq: error: cannot set an exit handler"); abort(); } } static void tsd_init_nomem_handler(void) { if (pthread_getspecific(nomem_handler_key) == NULL) { struct nomem_handler *nomem_handler = calloc(1, sizeof(struct nomem_handler)); if (pthread_setspecific(nomem_handler_key, nomem_handler) != 0) { fprintf(stderr, "jq: 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 tsd_init_nomem_handler(); struct nomem_handler *nomem_handler; nomem_handler = pthread_getspecific(nomem_handler_key); if (nomem_handler == NULL) { handler(data); fprintf(stderr, "jq: error: cannot allocate memory\n"); abort(); } nomem_handler->handler = handler; nomem_handler->data = data; } static void memory_exhausted(void) { struct nomem_handler *nomem_handler; pthread_once(&mem_once, tsd_init); tsd_init_nomem_handler(); nomem_handler = pthread_getspecific(nomem_handler_key); if (nomem_handler && nomem_handler->handler) nomem_handler->handler(nomem_handler->data); // Maybe handler() will longjmp() to safety // Or not fprintf(stderr, "jq: 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(void) { fprintf(stderr, "jq: 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) { memory_exhausted(); } return p; } void* jv_mem_alloc_unguarded(size_t sz) { return malloc(sz); } void* jv_mem_calloc(size_t nemb, size_t sz) { assert(nemb > 0 && sz > 0); void* p = calloc(nemb, sz); if (!p) { memory_exhausted(); } return p; } void* jv_mem_calloc_unguarded(size_t nemb, size_t sz) { assert(nemb > 0 && sz > 0); return calloc(nemb, sz); } char* jv_mem_strdup(const char *s) { char *p = strdup(s); if (!p) { memory_exhausted(); } return p; } char* jv_mem_strdup_unguarded(const char *s) { return strdup(s); } void jv_mem_free(void* p) { free(p); } void* jv_mem_realloc(void* p, size_t sz) { p = realloc(p, sz); if (!p) { memory_exhausted(); } return p; } ================================================ FILE: src/jv_alloc.h ================================================ #ifndef JV_ALLOC_H #define JV_ALLOC_H #include void* jv_mem_alloc(size_t); void* jv_mem_alloc_unguarded(size_t); void* jv_mem_calloc(size_t, size_t); void* jv_mem_calloc_unguarded(size_t, size_t); char* jv_mem_strdup(const char *); char* jv_mem_strdup_unguarded(const char *); void jv_mem_free(void*); __attribute__((warn_unused_result)) void* jv_mem_realloc(void*, size_t); #endif ================================================ FILE: src/jv_aux.c ================================================ #include #include #include #include #include #include "jv.h" #include "jv_alloc.h" #include "jv_private.h" // making this static verbose function here // until we introduce a less confusing naming scheme // of jv_* API with regards to the memory management static double jv_number_get_value_and_consume(jv number) { double value = jv_number_value(number); jv_free(number); return value; } static jv parse_slice(jv j, jv slice, int* pstart, int* pend) { // Array slices 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(j); } else if (jv_get_kind(j) == JV_KIND_STRING) { len = jv_string_length_codepoints(j); } else { /* * XXX This should be dead code because callers shouldn't call this * function if `j' is neither an array nor a string. */ jv_free(j); jv_free(start_jv); jv_free(end_jv); return jv_invalid_with_msg(jv_string("Only arrays and strings can be sliced")); } if (jv_get_kind(end_jv) == JV_KIND_NULL) { jv_free(end_jv); end_jv = jv_number(len); } if (jv_get_kind(start_jv) != JV_KIND_NUMBER || jv_get_kind(end_jv) != JV_KIND_NUMBER) { jv_free(start_jv); jv_free(end_jv); return jv_invalid_with_msg(jv_string("Array/string slice indices must be integers")); } double dstart = jv_number_value(start_jv); double dend = jv_number_value(end_jv); int start, end; jv_free(start_jv); jv_free(end_jv); if (isnan(dstart)) dstart = 0; if (dstart < 0) dstart += len; if (dstart < 0) dstart = 0; if (dstart > len) dstart = len; start = dstart > INT_MAX ? INT_MAX : (int)dstart; // Rounds down if (isnan(dend)) dend = len; if (dend < 0) dend += len; if (dend < 0) dend = start; end = dend > INT_MAX ? INT_MAX : (int)dend; if (end > len) end = len; if (end < len) end += end < dend ? 1 : 0; // We round start down // but round end up if (end < start) end = start; assert(0 <= start && start <= end && end <= len); *pstart = start; *pend = end; return jv_true(); } jv jv_get(jv t, jv k) { jv v; if (jv_get_kind(t) == JV_KIND_OBJECT && jv_get_kind(k) == JV_KIND_STRING) { v = jv_object_get(t, 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_NUMBER) { if (jvp_number_is_nan(k)) { jv_free(t); v = jv_null(); } else { double didx = jv_number_value(k); if (didx < INT_MIN) didx = INT_MIN; if (didx > INT_MAX) didx = INT_MAX; int idx = (int)didx; if (idx < 0) idx += jv_array_length(jv_copy(t)); v = jv_array_get(t, idx); if (!jv_is_valid(v)) { jv_free(v); v = jv_null(); } } jv_free(k); } else if (jv_get_kind(t) == JV_KIND_ARRAY && jv_get_kind(k) == JV_KIND_OBJECT) { int start, end; jv e = parse_slice(jv_copy(t), k, &start, &end); if (jv_get_kind(e) == JV_KIND_TRUE) { v = jv_array_slice(t, start, end); } else { jv_free(t); v = e; } } else if (jv_get_kind(t) == JV_KIND_STRING && jv_get_kind(k) == JV_KIND_OBJECT) { int start, end; jv e = parse_slice(jv_copy(t), k, &start, &end); if (jv_get_kind(e) == JV_KIND_TRUE) { v = jv_string_slice(t, start, end); } else { jv_free(t); v = e; } } 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 || jv_get_kind(k) == JV_KIND_OBJECT)) { jv_free(t); jv_free(k); v = jv_null(); } else { char errbuf[30]; v = jv_invalid_with_msg(jv_string_fmt( "Cannot index %s with %s (%s)", jv_kind_name(jv_get_kind(t)), jv_kind_name(jv_get_kind(k)), jv_dump_string_trunc(jv_copy(k), errbuf, sizeof(errbuf)))); jv_free(t); jv_free(k); } return v; } jv jv_set(jv t, jv k, jv v) { if (!jv_is_valid(v)) { jv_free(t); jv_free(k); return v; } int isnull = jv_get_kind(t) == JV_KIND_NULL; if (jv_get_kind(k) == JV_KIND_STRING && (jv_get_kind(t) == JV_KIND_OBJECT || isnull)) { if (isnull) t = jv_object(); t = jv_object_set(t, k, v); } else if (jv_get_kind(k) == JV_KIND_NUMBER && (jv_get_kind(t) == JV_KIND_ARRAY || isnull)) { if (jvp_number_is_nan(k)) { jv_free(t); jv_free(k); jv_free(v); t = jv_invalid_with_msg(jv_string("Cannot set array element at NaN index")); } else { double didx = jv_number_value(k); if (didx < INT_MIN) didx = INT_MIN; if (didx > INT_MAX) didx = INT_MAX; if (isnull) t = jv_array(); t = jv_array_set(t, (int)didx, v); jv_free(k); } } else if (jv_get_kind(k) == JV_KIND_OBJECT && (jv_get_kind(t) == JV_KIND_ARRAY || isnull)) { if (isnull) t = jv_array(); int start, end; jv e = parse_slice(jv_copy(t), k, &start, &end); if (jv_get_kind(e) == JV_KIND_TRUE) { if (jv_get_kind(v) == JV_KIND_ARRAY) { int array_len = jv_array_length(jv_copy(t)); assert(0 <= start && start <= end && end <= array_len); int slice_len = end - start; int insert_len = jv_array_length(jv_copy(v)); if (slice_len < insert_len) { // array is growing int shift = insert_len - slice_len; for (int i = array_len - 1; i >= end && jv_is_valid(t); i--) { t = jv_array_set(t, i + shift, jv_array_get(jv_copy(t), i)); } } else if (slice_len > insert_len) { // array is shrinking int shift = slice_len - insert_len; for (int i = end; i < array_len && jv_is_valid(t); i++) { t = jv_array_set(t, i - shift, jv_array_get(jv_copy(t), i)); } if (jv_is_valid(t)) t = jv_array_slice(t, 0, array_len - shift); } for (int i = 0; i < insert_len && jv_is_valid(t); i++) { t = jv_array_set(t, start + i, jv_array_get(jv_copy(v), i)); } jv_free(v); } else { jv_free(t); jv_free(v); t = jv_invalid_with_msg(jv_string_fmt("A slice of an array can only be assigned another array")); } } else { jv_free(t); jv_free(v); t = e; } } else if (jv_get_kind(k) == JV_KIND_OBJECT && jv_get_kind(t) == JV_KIND_STRING) { jv_free(t); jv_free(k); jv_free(v); /* Well, why not? We should implement this... */ t = jv_invalid_with_msg(jv_string_fmt("Cannot update string slices")); } else { jv err = jv_invalid_with_msg(jv_string_fmt("Cannot update field at %s index of %s", jv_kind_name(jv_get_kind(k)), jv_kind_name(jv_get_kind(t)))); jv_free(t); jv_free(k); jv_free(v); t = err; } return t; } jv jv_has(jv t, jv k) { assert(jv_is_valid(t)); assert(jv_is_valid(k)); jv ret; if (jv_get_kind(t) == JV_KIND_NULL) { jv_free(t); jv_free(k); ret = jv_false(); } else if (jv_get_kind(t) == JV_KIND_OBJECT && jv_get_kind(k) == JV_KIND_STRING) { jv elem = jv_object_get(t, k); ret = jv_bool(jv_is_valid(elem)); jv_free(elem); } else if (jv_get_kind(t) == JV_KIND_ARRAY && jv_get_kind(k) == JV_KIND_NUMBER) { if (jvp_number_is_nan(k)) { jv_free(t); ret = jv_false(); } else { jv elem = jv_array_get(t, (int)jv_number_value(k)); ret = jv_bool(jv_is_valid(elem)); jv_free(elem); } jv_free(k); } else { ret = jv_invalid_with_msg(jv_string_fmt("Cannot check whether %s has a %s key", jv_kind_name(jv_get_kind(t)), jv_kind_name(jv_get_kind(k)))); jv_free(t); jv_free(k); } return ret; } // assumes keys is a sorted array static jv jv_dels(jv t, jv keys) { assert(jv_get_kind(keys) == JV_KIND_ARRAY); assert(jv_is_valid(t)); if (jv_get_kind(t) == JV_KIND_NULL || jv_array_length(jv_copy(keys)) == 0) { // no change } else if (jv_get_kind(t) == JV_KIND_ARRAY) { // extract slices, they must be handled differently jv neg_keys = jv_array(); jv nonneg_keys = jv_array(); jv new_array = jv_array(); jv starts = jv_array(), ends = jv_array(); jv_array_foreach(keys, i, key) { if (jv_get_kind(key) == JV_KIND_NUMBER) { if (jvp_number_is_nan(key)) { jv_free(key); } else if (jv_number_value(key) < 0) { neg_keys = jv_array_append(neg_keys, key); } else { nonneg_keys = jv_array_append(nonneg_keys, key); } } else if (jv_get_kind(key) == JV_KIND_OBJECT) { int start, end; jv e = parse_slice(jv_copy(t), key, &start, &end); if (jv_get_kind(e) == JV_KIND_TRUE) { starts = jv_array_append(starts, jv_number(start)); ends = jv_array_append(ends, jv_number(end)); } else { jv_free(new_array); new_array = e; goto arr_out; } } else { jv_free(new_array); new_array = jv_invalid_with_msg(jv_string_fmt("Cannot delete %s element of array", jv_kind_name(jv_get_kind(key)))); jv_free(key); goto arr_out; } } int neg_idx = 0; int nonneg_idx = 0; int len = jv_array_length(jv_copy(t)); for (int i = 0; i < len; ++i) { int del = 0; while (neg_idx < jv_array_length(jv_copy(neg_keys))) { int delidx = len + (int)jv_number_get_value_and_consume(jv_array_get(jv_copy(neg_keys), neg_idx)); if (i == delidx) { del = 1; } if (i < delidx) { break; } neg_idx++; } while (nonneg_idx < jv_array_length(jv_copy(nonneg_keys))) { int delidx = (int)jv_number_get_value_and_consume(jv_array_get(jv_copy(nonneg_keys), nonneg_idx)); if (i == delidx) { del = 1; } if (i < delidx) { break; } nonneg_idx++; } for (int sidx=0; !del && sidx start); int delkey = jv_array_length(jv_array_get(jv_copy(paths), i)) == start + 1; jv key = jv_array_get(jv_array_get(jv_copy(paths), i), start); int j = i; do j++; while (j < jv_array_length(jv_copy(paths)) && jv_equal(jv_copy(key), jv_array_get(jv_array_get(jv_copy(paths), j), start))); // if i <= entry < j, then entry starts with key if (delkey) { // deleting this entire key, we don't care about any more specific deletions delkeys = jv_array_append(delkeys, key); } else { // deleting certain sub-parts of this key jv subobject = jv_get(jv_copy(object), jv_copy(key)); if (!jv_is_valid(subobject)) { jv_free(key); jv_free(object); object = subobject; break; } else if (jv_get_kind(subobject) == JV_KIND_NULL) { jv_free(key); jv_free(subobject); } else { jv newsubobject = delpaths_sorted(subobject, jv_array_slice(jv_copy(paths), i, j), start+1); if (!jv_is_valid(newsubobject)) { jv_free(key); jv_free(object); object = newsubobject; break; } object = jv_set(object, key, newsubobject); } if (!jv_is_valid(object)) break; } i = j; } jv_free(paths); if (jv_is_valid(object)) object = jv_dels(object, delkeys); else jv_free(delkeys); return object; } jv jv_delpaths(jv object, jv paths) { if (jv_get_kind(paths) != JV_KIND_ARRAY) { jv_free(object); jv_free(paths); return jv_invalid_with_msg(jv_string("Paths must be specified as an array")); } paths = jv_sort(paths, jv_copy(paths)); jv_array_foreach(paths, i, elem) { if (jv_get_kind(elem) != JV_KIND_ARRAY) { jv_free(object); jv_free(paths); jv err = jv_invalid_with_msg(jv_string_fmt("Path must be specified as array, not %s", jv_kind_name(jv_get_kind(elem)))); jv_free(elem); return err; } jv_free(elem); } if (jv_array_length(jv_copy(paths)) == 0) { // nothing is being deleted jv_free(paths); return object; } if (jv_array_length(jv_array_get(jv_copy(paths), 0)) == 0) { // everything is being deleted jv_free(paths); jv_free(object); return jv_null(); } return delpaths_sorted(object, paths, 0); } static int string_cmp(const void* pa, const void* pb){ const jv* a = pa; const jv* b = pb; int lena = jv_string_length_bytes(jv_copy(*a)); int lenb = jv_string_length_bytes(jv_copy(*b)); int minlen = lena < lenb ? lena : lenb; int r = memcmp(jv_string_value(*a), jv_string_value(*b), minlen); if (r == 0) r = lena - lenb; return r; } jv jv_keys_unsorted(jv x) { if (jv_get_kind(x) != JV_KIND_OBJECT) return jv_keys(x); jv answer = jv_array_sized(jv_object_length(jv_copy(x))); jv_object_foreach(x, key, value) { answer = jv_array_append(answer, key); jv_free(value); } jv_free(x); return answer; } jv jv_keys(jv x) { if (jv_get_kind(x) == JV_KIND_OBJECT) { int nkeys = jv_object_length(jv_copy(x)); if (nkeys == 0) { jv_free(x); return jv_array(); } jv* keys = jv_mem_calloc(nkeys, sizeof(jv)); int kidx = 0; jv_object_foreach(x, key, value) { keys[kidx++] = key; jv_free(value); } qsort(keys, nkeys, sizeof(jv), string_cmp); jv answer = jv_array_sized(nkeys); for (int i = 0; i= jv_array_length(jv_copy(a)); int b_done = i >= jv_array_length(jv_copy(b)); if (a_done || b_done) { r = b_done - a_done; //suddenly, logic break; } jv xa = jv_array_get(jv_copy(a), i); jv xb = jv_array_get(jv_copy(b), i); r = jv_cmp(xa, xb); i++; } break; } case JV_KIND_OBJECT: { jv keys_a = jv_keys(jv_copy(a)); jv keys_b = jv_keys(jv_copy(b)); r = jv_cmp(jv_copy(keys_a), keys_b); if (r == 0) { jv_array_foreach(keys_a, i, key) { jv xa = jv_object_get(jv_copy(a), jv_copy(key)); jv xb = jv_object_get(jv_copy(b), key); r = jv_cmp(xa, xb); if (r) break; } } jv_free(keys_a); break; } } jv_free(a); jv_free(b); return r; } struct sort_entry { jv object; jv key; int index; }; static int sort_cmp(const void* pa, const void* pb) { const struct sort_entry* a = pa; const struct sort_entry* b = pb; int r = jv_cmp(jv_copy(a->key), jv_copy(b->key)); // comparing by index if r == 0 makes the sort stable return r ? r : (a->index - b->index); } static struct sort_entry* sort_items(jv objects, jv keys) { assert(jv_get_kind(objects) == JV_KIND_ARRAY); assert(jv_get_kind(keys) == JV_KIND_ARRAY); assert(jv_array_length(jv_copy(objects)) == jv_array_length(jv_copy(keys))); int n = jv_array_length(jv_copy(objects)); if (n == 0) { jv_free(objects); jv_free(keys); return NULL; } struct sort_entry* entries = jv_mem_calloc(n, sizeof(struct sort_entry)); for (int i=0; i 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_free(curr_key); ret = jv_array_append(ret, group); } jv_mem_free(entries); return ret; } jv jv_unique(jv objects, jv keys) { assert(jv_get_kind(objects) == JV_KIND_ARRAY); assert(jv_get_kind(keys) == JV_KIND_ARRAY); assert(jv_array_length(jv_copy(objects)) == jv_array_length(jv_copy(keys))); int n = jv_array_length(jv_copy(objects)); struct sort_entry* entries = sort_items(objects, keys); jv ret = jv_array(); jv curr_key = jv_invalid(); for (int i = 0; i < n; i++) { if (jv_equal(jv_copy(curr_key), jv_copy(entries[i].key))) { jv_free(entries[i].key); jv_free(entries[i].object); } else { jv_free(curr_key); curr_key = entries[i].key; ret = jv_array_append(ret, entries[i].object); } } jv_free(curr_key); jv_mem_free(entries); return ret; } ================================================ FILE: src/jv_dtoa.c ================================================ /**************************************************************** * * The author of this software is David M. Gay. * * Copyright (c) 1991, 2000, 2001 by Lucent Technologies. * * Permission to use, copy, modify, and distribute this software for any * purpose without fee is hereby granted, provided that this entire notice * is included in all copies of any software which is or includes a copy * or modification of this software and in all copies of the supporting * documentation for such software. * * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED * WARRANTY. IN PARTICULAR, NEITHER THE AUTHOR NOR LUCENT MAKES ANY * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE. * ***************************************************************/ /* Please send bug reports to David M. Gay (dmg at acm dot org, * with " at " changed at "@" and " dot " changed to "."). */ /* On a machine with IEEE extended-precision registers, it is * necessary to specify double-precision (53-bit) rounding precision * before invoking strtod or dtoa. If the machine uses (the equivalent * of) Intel 80x87 arithmetic, the call * _control87(PC_53, MCW_PC); * does this with many compilers. Whether this or another call is * appropriate depends on the compiler; for this to work, it may be * necessary to #include "float.h" or another system-dependent header * file. */ /* strtod for IEEE-, VAX-, and IBM-arithmetic machines. * (Note that IEEE arithmetic is disabled by gcc's -ffast-math flag.) * * This strtod returns a nearest machine number to the input decimal * string (or sets errno to ERANGE). With IEEE arithmetic, ties are * broken by the IEEE round-even rule. Otherwise ties are broken by * biased rounding (add half and chop). * * Inspired loosely by William D. Clinger's paper "How to Read Floating * Point Numbers Accurately" [Proc. ACM SIGPLAN '90, pp. 92-101]. * * Modifications: * * 1. We only require IEEE, IBM, or VAX double-precision * arithmetic (not IEEE double-extended). * 2. We get by with floating-point arithmetic in a case that * Clinger missed -- when we're computing d * 10^n * for a small integer d and the integer n is not too * much larger than 22 (the maximum integer k for which * we can represent 10^k exactly), we may be able to * compute (d*10^k) * 10^(e-k) with just one roundoff. * 3. Rather than a bit-at-a-time adjustment of the binary * result in the hard case, we use floating-point * arithmetic to determine the adjustment to within * one bit; only in really hard cases do we need to * compute a second residual. * 4. Because of 3., we don't need a large table of powers of 10 * for ten-to-e (just some small tables, e.g. of 10^k * for 0 <= k <= 22). */ /* * #define IEEE_8087 for IEEE-arithmetic machines where the least * significant byte has the lowest address. * #define IEEE_MC68k for IEEE-arithmetic machines where the most * significant byte has the lowest address. * #define Long int on machines with 32-bit ints and 64-bit longs. * #define IBM for IBM mainframe-style floating-point arithmetic. * #define VAX for VAX-style floating-point arithmetic (D_floating). * #define No_leftright to omit left-right logic in fast floating-point * computation of dtoa. This will cause dtoa modes 4 and 5 to be * treated the same as modes 2 and 3 for some inputs. * #define Honor_FLT_ROUNDS if FLT_ROUNDS can assume the values 2 or 3 * and strtod and dtoa should round accordingly. Unless Trust_FLT_ROUNDS * is also #defined, fegetround() will be queried for the rounding mode. * Note that both FLT_ROUNDS and fegetround() are specified by the C99 * standard (and are specified to be consistent, with fesetround() * affecting the value of FLT_ROUNDS), but that some (Linux) systems * do not work correctly in this regard, so using fegetround() is more * portable than using FLT_ROUNDS directly. * #define Check_FLT_ROUNDS if FLT_ROUNDS can assume the values 2 or 3 * and Honor_FLT_ROUNDS is not #defined. * #define RND_PRODQUOT to use rnd_prod and rnd_quot (assembly routines * that use extended-precision instructions to compute rounded * products and quotients) with IBM. * #define ROUND_BIASED for IEEE-format with biased rounding and arithmetic * that rounds toward +Infinity. * #define ROUND_BIASED_without_Round_Up for IEEE-format with biased * rounding when the underlying floating-point arithmetic uses * unbiased rounding. This prevent using ordinary floating-point * arithmetic when the result could be computed with one rounding error. * #define Inaccurate_Divide for IEEE-format with correctly rounded * products but inaccurate quotients, e.g., for Intel i860. * #define NO_LONG_LONG on machines that do not have a "long long" * integer type (of >= 64 bits). On such machines, you can * #define Just_16 to store 16 bits per 32-bit Long when doing * high-precision integer arithmetic. Whether this speeds things * up or slows things down depends on the machine and the number * being converted. If long long is available and the name is * something other than "long long", #define Llong to be the name, * and if "unsigned Llong" does not work as an unsigned version of * Llong, #define #ULLong to be the corresponding unsigned type. * #define KR_headers for old-style C function headers. * #define Bad_float_h if your system lacks a float.h or if it does not * define some or all of DBL_DIG, DBL_MAX_10_EXP, DBL_MAX_EXP, * FLT_RADIX, FLT_ROUNDS, and DBL_MAX. * #define MALLOC your_malloc, where your_malloc(n) acts like malloc(n) * if memory is available and otherwise does something you deem * appropriate. If MALLOC is undefined, malloc will be invoked * directly -- and assumed always to succeed. Similarly, if you * want something other than the system's free() to be called to * recycle memory acquired from MALLOC, #define FREE to be the * name of the alternate routine. (FREE or free is only called in * pathological cases, e.g., in a dtoa call after a dtoa return in * mode 3 with thousands of digits requested.) * #define Omit_Private_Memory to omit logic (added Jan. 1998) for making * memory allocations from a private pool of memory when possible. * When used, the private pool is PRIVATE_MEM bytes long: 2304 bytes, * unless #defined to be a different length. This default length * suffices to get rid of MALLOC calls except for unusual cases, * such as decimal-to-binary conversion of a very long string of * digits. The longest string dtoa can return is about 751 bytes * long. For conversions by strtod of strings of 800 digits and * all dtoa conversions in single-threaded executions with 8-byte * pointers, PRIVATE_MEM >= 7400 appears to suffice; with 4-byte * pointers, PRIVATE_MEM >= 7112 appears adequate. * #define NO_INFNAN_CHECK if you do not wish to have INFNAN_CHECK * #defined automatically on IEEE systems. On such systems, * when INFNAN_CHECK is #defined, strtod checks * for Infinity and NaN (case insensitively). On some systems * (e.g., some HP systems), it may be necessary to #define NAN_WORD0 * appropriately -- to the most significant word of a quiet NaN. * (On HP Series 700/800 machines, -DNAN_WORD0=0x7ff40000 works.) * When INFNAN_CHECK is #defined and No_Hex_NaN is not #defined, * strtod also accepts (case insensitively) strings of the form * NaN(x), where x is a string of hexadecimal digits and spaces; * if there is only one string of hexadecimal digits, it is taken * for the 52 fraction bits of the resulting NaN; if there are two * or more strings of hex digits, the first is for the high 20 bits, * the second and subsequent for the low 32 bits, with intervening * white space ignored; but if this results in none of the 52 * fraction bits being on (an IEEE Infinity symbol), then NAN_WORD0 * and NAN_WORD1 are used instead. * #define MULTIPLE_THREADS if the system offers preemptively scheduled * multiple threads. In this case, you must provide (or suitably * #define) two locks, acquired by ACQUIRE_DTOA_LOCK(n) and freed * by FREE_DTOA_LOCK(n) for n = 0 or 1. (The second lock, accessed * in pow5mult, ensures lazy evaluation of only one copy of high * powers of 5; omitting this lock would introduce a small * probability of wasting memory, but would otherwise be harmless.) * You must also invoke freedtoa(s) to free the value s returned by * dtoa. You may do so whether or not MULTIPLE_THREADS is #defined. * #define NO_IEEE_Scale to disable new (Feb. 1997) logic in strtod that * avoids underflows on inputs whose result does not underflow. * If you #define NO_IEEE_Scale on a machine that uses IEEE-format * floating-point numbers and flushes underflows to zero rather * than implementing gradual underflow, then you must also #define * Sudden_Underflow. * #define USE_LOCALE to use the current locale's decimal_point value. * #define SET_INEXACT if IEEE arithmetic is being used and extra * computation should be done to set the inexact flag when the * result is inexact and avoid setting inexact when the result * is exact. In this case, dtoa.c must be compiled in * an environment, perhaps provided by #include "dtoa.c" in a * suitable wrapper, that defines two functions, * int get_inexact(void); * void clear_inexact(void); * such that get_inexact() returns a nonzero value if the * inexact bit is already set, and clear_inexact() sets the * inexact bit to 0. When SET_INEXACT is #defined, strtod * also does extra computations to set the underflow and overflow * flags when appropriate (i.e., when the result is tiny and * inexact or when it is a numeric value rounded to +-infinity). * #define NO_ERRNO if strtod should not assign errno = ERANGE when * the result overflows to +-Infinity or underflows to 0. * #define NO_HEX_FP to omit recognition of hexadecimal floating-point * values by strtod. * #define NO_STRTOD_BIGCOMP (on IEEE-arithmetic systems only for now) * to disable logic for "fast" testing of very long input strings * to strtod. This testing proceeds by initially truncating the * input string, then if necessary comparing the whole string with * a decimal expansion to decide close cases. This logic is only * used for input more than STRTOD_DIGLIM digits long (default 40). */ #define NO_ERRNO #define NO_HEX_FP #define No_Hex_NaN #define Long int #include "jv_dtoa.h" #include "jv_alloc.h" #include "jv.h" #define MALLOC jv_mem_alloc #define FREE jv_mem_free #ifndef Long #define Long long #endif #ifndef ULong typedef unsigned Long ULong; #endif #ifdef DEBUG #include "stdio.h" #define Bug(x) {fprintf(stderr, "%s\n", x); exit(1);} #endif #include "stdlib.h" #include "string.h" #ifdef USE_LOCALE #include "locale.h" #endif #ifdef Honor_FLT_ROUNDS #ifndef Trust_FLT_ROUNDS #include #endif #endif #ifdef MALLOC extern void *MALLOC(size_t); #else #define MALLOC malloc #endif #undef IEEE_Arith #undef Avoid_Underflow #ifdef IEEE_MC68k #define IEEE_Arith #endif #ifdef IEEE_8087 #define IEEE_Arith #endif #ifdef IEEE_Arith #ifndef NO_INFNAN_CHECK #undef INFNAN_CHECK #define INFNAN_CHECK #endif #else #undef INFNAN_CHECK #define NO_STRTOD_BIGCOMP #endif #include "errno.h" #ifdef Bad_float_h #ifdef IEEE_Arith #define DBL_DIG 15 #define DBL_MAX_10_EXP 308 #define DBL_MAX_EXP 1024 #define FLT_RADIX 2 #endif /*IEEE_Arith*/ #ifdef IBM #define DBL_DIG 16 #define DBL_MAX_10_EXP 75 #define DBL_MAX_EXP 63 #define FLT_RADIX 16 #define DBL_MAX 7.2370055773322621e+75 #endif #ifdef VAX #define DBL_DIG 16 #define DBL_MAX_10_EXP 38 #define DBL_MAX_EXP 127 #define FLT_RADIX 2 #define DBL_MAX 1.7014118346046923e+38 #endif #ifndef LONG_MAX #define LONG_MAX 2147483647 #endif #else /* ifndef Bad_float_h */ #include "float.h" #endif /* Bad_float_h */ #ifndef __MATH_H__ #include "math.h" #endif #ifdef __cplusplus extern "C" { #endif #ifndef CONST #define CONST const #endif #if defined(IEEE_8087) + defined(IEEE_MC68k) + defined(VAX) + defined(IBM) != 1 # error Exactly one of IEEE_8087, IEEE_MC68k, VAX, or IBM should be defined. #endif typedef union { double d; ULong L[2]; } U; #ifdef IEEE_8087 #define word0(x) (x)->L[1] #define word1(x) (x)->L[0] #else #define word0(x) (x)->L[0] #define word1(x) (x)->L[1] #endif #define dval(x) (x)->d #ifndef STRTOD_DIGLIM #define STRTOD_DIGLIM 40 #endif #ifdef DIGLIM_DEBUG extern int strtod_diglim; #else #define strtod_diglim STRTOD_DIGLIM #endif /* The following definition of Storeinc is appropriate for MIPS processors. * An alternative that might be better on some machines is * #define Storeinc(a,b,c) (*a++ = b << 16 | c & 0xffff) */ #if defined(IEEE_8087) + defined(VAX) #define Storeinc(a,b,c) (((unsigned short *)a)[1] = (unsigned short)b, \ ((unsigned short *)a)[0] = (unsigned short)c, a++) #else #define Storeinc(a,b,c) (((unsigned short *)a)[0] = (unsigned short)b, \ ((unsigned short *)a)[1] = (unsigned short)c, a++) #endif /* #define P DBL_MANT_DIG */ /* Ten_pmax = floor(P*log(2)/log(5)) */ /* Bletch = (highest power of 2 < DBL_MAX_10_EXP) / 16 */ /* Quick_max = floor((P-1)*log(FLT_RADIX)/log(10) - 1) */ /* Int_max = floor(P*log(FLT_RADIX)/log(10) - 1) */ #ifdef IEEE_Arith #define Exp_shift 20 #define Exp_shift1 20 #define Exp_msk1 0x100000 #define Exp_msk11 0x100000 #define Exp_mask 0x7ff00000 #define P 53 #define Nbits 53 #define Bias 1023 #define Emax 1023 #define Emin (-1022) #define Exp_1 0x3ff00000 #define Exp_11 0x3ff00000 #define Ebits 11 #define Frac_mask 0xfffff #define Frac_mask1 0xfffff #define Ten_pmax 22 #define Bletch 0x10 #define Bndry_mask 0xfffff #define Bndry_mask1 0xfffff #define LSB 1 #define Sign_bit 0x80000000 #define Log2P 1 #define Tiny0 0 #define Tiny1 1 #define Quick_max 14 #define Int_max 14 #ifndef NO_IEEE_Scale #define Avoid_Underflow #ifdef Flush_Denorm /* debugging option */ #undef Sudden_Underflow #endif #endif #ifndef Flt_Rounds #ifdef FLT_ROUNDS #define Flt_Rounds FLT_ROUNDS #else #define Flt_Rounds 1 #endif #endif /*Flt_Rounds*/ #ifdef Honor_FLT_ROUNDS #undef Check_FLT_ROUNDS #define Check_FLT_ROUNDS #else #define Rounding Flt_Rounds #endif #else /* ifndef IEEE_Arith */ #undef Check_FLT_ROUNDS #undef Honor_FLT_ROUNDS #undef SET_INEXACT #undef Sudden_Underflow #define Sudden_Underflow #ifdef IBM #undef Flt_Rounds #define Flt_Rounds 0 #define Exp_shift 24 #define Exp_shift1 24 #define Exp_msk1 0x1000000 #define Exp_msk11 0x1000000 #define Exp_mask 0x7f000000 #define P 14 #define Nbits 56 #define Bias 65 #define Emax 248 #define Emin (-260) #define Exp_1 0x41000000 #define Exp_11 0x41000000 #define Ebits 8 /* exponent has 7 bits, but 8 is the right value in b2d */ #define Frac_mask 0xffffff #define Frac_mask1 0xffffff #define Bletch 4 #define Ten_pmax 22 #define Bndry_mask 0xefffff #define Bndry_mask1 0xffffff #define LSB 1 #define Sign_bit 0x80000000 #define Log2P 4 #define Tiny0 0x100000 #define Tiny1 0 #define Quick_max 14 #define Int_max 15 #else /* VAX */ #undef Flt_Rounds #define Flt_Rounds 1 #define Exp_shift 23 #define Exp_shift1 7 #define Exp_msk1 0x80 #define Exp_msk11 0x800000 #define Exp_mask 0x7f80 #define P 56 #define Nbits 56 #define Bias 129 #define Emax 126 #define Emin (-129) #define Exp_1 0x40800000 #define Exp_11 0x4080 #define Ebits 8 #define Frac_mask 0x7fffff #define Frac_mask1 0xffff007f #define Ten_pmax 24 #define Bletch 2 #define Bndry_mask 0xffff007f #define Bndry_mask1 0xffff007f #define LSB 0x10000 #define Sign_bit 0x8000 #define Log2P 1 #define Tiny0 0x80 #define Tiny1 0 #define Quick_max 15 #define Int_max 15 #endif /* IBM, VAX */ #endif /* IEEE_Arith */ #ifndef IEEE_Arith #define ROUND_BIASED #else #ifdef ROUND_BIASED_without_Round_Up #undef ROUND_BIASED #define ROUND_BIASED #endif #endif #ifdef RND_PRODQUOT #define rounded_product(a,b) a = rnd_prod(a, b) #define rounded_quotient(a,b) a = rnd_quot(a, b) extern double rnd_prod(double, double), rnd_quot(double, double); #else #define rounded_product(a,b) a *= b #define rounded_quotient(a,b) a /= b #endif #define Big0 (Frac_mask1 | Exp_msk1*(DBL_MAX_EXP+Bias-1)) #define Big1 0xffffffff #ifndef Pack_32 #define Pack_32 #endif typedef struct BCinfo BCinfo; struct BCinfo { int dp0, dp1, dplen, dsign, e0, inexact, nd, nd0, rounding, scale, uflchk; }; #define FFFFFFFF 0xffffffffUL #ifdef NO_LONG_LONG #undef ULLong #ifdef Just_16 #undef Pack_32 /* When Pack_32 is not defined, we store 16 bits per 32-bit Long. * This makes some inner loops simpler and sometimes saves work * during multiplications, but it often seems to make things slightly * slower. Hence the default is now to store 32 bits per Long. */ #endif #else /* long long available */ #ifndef Llong #define Llong long long #endif #ifndef ULLong #define ULLong unsigned Llong #endif #endif /* NO_LONG_LONG */ struct Bigint { struct Bigint *next; int k, maxwds, sign, wds; ULong x[1]; }; typedef struct Bigint Bigint; void jvp_dtoa_context_init(struct dtoa_context* C) { int i; for (i=0; i<(int)(sizeof(C->freelist)/sizeof(C->freelist[0])); i++) { C->freelist[i] = 0; } C->p5s = 0; } static Bigint * Balloc(struct dtoa_context* C, int k) { int x; Bigint *rv; /* The k > Kmax case does not need ACQUIRE_DTOA_LOCK(0), */ /* but this case seems very unlikely. */ if (k <= Kmax && (rv = C->freelist[k])) C->freelist[k] = rv->next; else { x = 1 << k; rv = (Bigint *)MALLOC(sizeof(Bigint) + (x-1)*sizeof(ULong)); rv->k = k; rv->maxwds = x; } rv->sign = rv->wds = 0; return rv; } static void Bfree (struct dtoa_context* C, Bigint *v) { if (v) { if (v->k > Kmax) #ifdef FREE FREE((void*)v); #else free((void*)v); #endif else { v->next = C->freelist[v->k]; C->freelist[v->k] = v; } } } void jvp_dtoa_context_free(struct dtoa_context* C) { int k; while (C->p5s) { Bigint* p5 = C->p5s; C->p5s = p5->next; Bfree(C, p5); } for (k=0; k<(int)(sizeof(C->freelist)/sizeof(C->freelist[0])); k++) { while (C->freelist[k]) { Bigint* v = C->freelist[k]; C->freelist[k] = v->next; FREE(v); } } } #define Bcopy(x,y) memcpy((char *)&x->sign, (char *)&y->sign, \ y->wds*sizeof(Long) + 2*sizeof(int)) static Bigint * multadd (struct dtoa_context* C, Bigint *b, int m, int a) /* multiply by m and add a */ { int i, wds; #ifdef ULLong ULong *x; ULLong carry, y; #else ULong carry, *x, y; #ifdef Pack_32 ULong xi, z; #endif #endif Bigint *b1; wds = b->wds; x = b->x; i = 0; carry = a; do { #ifdef ULLong y = *x * (ULLong)m + carry; carry = y >> 32; *x++ = y & FFFFFFFF; #else #ifdef Pack_32 xi = *x; y = (xi & 0xffff) * m + carry; z = (xi >> 16) * m + (y >> 16); carry = z >> 16; *x++ = (z << 16) + (y & 0xffff); #else y = *x * m + carry; carry = y >> 16; *x++ = y & 0xffff; #endif #endif } while(++i < wds); if (carry) { if (wds >= b->maxwds) { b1 = Balloc(C, b->k+1); Bcopy(b1, b); Bfree(C, b); b = b1; } b->x[wds++] = carry; b->wds = wds; } return b; } static Bigint * s2b (struct dtoa_context* C, const char *s, int nd0, int nd, ULong y9, int dplen) { Bigint *b; int i, k; Long x, y; x = (nd + 8) / 9; for(k = 0, y = 1; x > y; y <<= 1, k++) ; #ifdef Pack_32 b = Balloc(C, k); b->x[0] = y9; b->wds = 1; #else b = Balloc(C, k+1); b->x[0] = y9 & 0xffff; b->wds = (b->x[1] = y9 >> 16) ? 2 : 1; #endif i = 9; if (9 < nd0) { s += 9; do b = multadd(C, b, 10, *s++ - '0'); while(++i < nd0); s += dplen; } else s += dplen + 9; for(; i < nd; i++) b = multadd(C, b, 10, *s++ - '0'); return b; } static int hi0bits (struct dtoa_context* C, ULong x) { int k = 0; if (!(x & 0xffff0000)) { k = 16; x <<= 16; } if (!(x & 0xff000000)) { k += 8; x <<= 8; } if (!(x & 0xf0000000)) { k += 4; x <<= 4; } if (!(x & 0xc0000000)) { k += 2; x <<= 2; } if (!(x & 0x80000000)) { k++; if (!(x & 0x40000000)) return 32; } return k; } static int lo0bits (struct dtoa_context* C, ULong *y) { int k; ULong x = *y; if (x & 7) { if (x & 1) return 0; if (x & 2) { *y = x >> 1; return 1; } *y = x >> 2; return 2; } k = 0; if (!(x & 0xffff)) { k = 16; x >>= 16; } if (!(x & 0xff)) { k += 8; x >>= 8; } if (!(x & 0xf)) { k += 4; x >>= 4; } if (!(x & 0x3)) { k += 2; x >>= 2; } if (!(x & 1)) { k++; x >>= 1; if (!x) return 32; } *y = x; return k; } static Bigint * i2b (struct dtoa_context* C, int i) { Bigint *b; b = Balloc(C, 1); b->x[0] = i; b->wds = 1; return b; } static Bigint * mult (struct dtoa_context* C, Bigint *a, Bigint *b) { Bigint *c; int k, wa, wb, wc; ULong *x, *xa, *xae, *xb, *xbe, *xc, *xc0; ULong y; #ifdef ULLong ULLong carry, z; #else ULong carry, z; #ifdef Pack_32 ULong z2; #endif #endif if (a->wds < b->wds) { c = a; a = b; b = c; } k = a->k; wa = a->wds; wb = b->wds; wc = wa + wb; if (wc > a->maxwds) k++; c = Balloc(C, k); for(x = c->x, xa = x + wc; x < xa; x++) *x = 0; xa = a->x; xae = xa + wa; xb = b->x; xbe = xb + wb; xc0 = c->x; #ifdef ULLong for(; xb < xbe; xc0++) { if ((y = *xb++)) { x = xa; xc = xc0; carry = 0; do { z = *x++ * (ULLong)y + *xc + carry; carry = z >> 32; *xc++ = z & FFFFFFFF; } while(x < xae); *xc = carry; } } #else #ifdef Pack_32 for(; xb < xbe; xb++, xc0++) { if (y = *xb & 0xffff) { x = xa; xc = xc0; carry = 0; do { z = (*x & 0xffff) * y + (*xc & 0xffff) + carry; carry = z >> 16; z2 = (*x++ >> 16) * y + (*xc >> 16) + carry; carry = z2 >> 16; Storeinc(xc, z2, z); } while(x < xae); *xc = carry; } if (y = *xb >> 16) { x = xa; xc = xc0; carry = 0; z2 = *xc; do { z = (*x & 0xffff) * y + (*xc >> 16) + carry; carry = z >> 16; Storeinc(xc, z, z2); z2 = (*x++ >> 16) * y + (*xc & 0xffff) + carry; carry = z2 >> 16; } while(x < xae); *xc = z2; } } #else for(; xb < xbe; xc0++) { if (y = *xb++) { x = xa; xc = xc0; carry = 0; do { z = *x++ * y + *xc + carry; carry = z >> 16; *xc++ = z & 0xffff; } while(x < xae); *xc = carry; } } #endif #endif for(xc0 = c->x, xc = xc0 + wc; wc > 0 && !*--xc; --wc) ; c->wds = wc; return c; } static Bigint * pow5mult (struct dtoa_context* C, Bigint *b, int k) { Bigint *b1, *p5, *p51; int i; static const int p05[3] = { 5, 25, 125 }; if ((i = k & 3)) b = multadd(C, b, p05[i-1], 0); if (!(k >>= 2)) return b; if (!(p5 = C->p5s)) { /* first time */ p5 = C->p5s = i2b(C, 625); p5->next = 0; } for(;;) { if (k & 1) { b1 = mult(C, b, p5); Bfree(C, b); b = b1; } if (!(k >>= 1)) break; if (!(p51 = p5->next)) { p51 = p5->next = mult(C, p5,p5); p51->next = 0; } p5 = p51; } return b; } static Bigint * lshift (struct dtoa_context* C, Bigint *b, int k) { int i, k1, n, n1; Bigint *b1; ULong *x, *x1, *xe, z; #ifdef Pack_32 n = k >> 5; #else n = k >> 4; #endif k1 = b->k; n1 = n + b->wds + 1; for(i = b->maxwds; n1 > i; i <<= 1) k1++; b1 = Balloc(C, k1); x1 = b1->x; for(i = 0; i < n; i++) *x1++ = 0; x = b->x; xe = x + b->wds; #ifdef Pack_32 if (k &= 0x1f) { k1 = 32 - k; z = 0; do { *x1++ = *x << k | z; z = *x++ >> k1; } while(x < xe); if ((*x1 = z)) ++n1; } #else if (k &= 0xf) { k1 = 16 - k; z = 0; do { *x1++ = *x << k & 0xffff | z; z = *x++ >> k1; } while(x < xe); if (*x1 = z) ++n1; } #endif else do *x1++ = *x++; while(x < xe); b1->wds = n1 - 1; Bfree(C, b); return b1; } static int cmp (struct dtoa_context* C, Bigint *a, Bigint *b) { ULong *xa, *xa0, *xb, *xb0; int i, j; i = a->wds; j = b->wds; #ifdef DEBUG if (i > 1 && !a->x[i-1]) Bug("cmp called with a->x[a->wds-1] == 0"); if (j > 1 && !b->x[j-1]) Bug("cmp called with b->x[b->wds-1] == 0"); #endif if (i -= j) return i; xa0 = a->x; xa = xa0 + j; xb0 = b->x; xb = xb0 + j; for(;;) { if (*--xa != *--xb) return *xa < *xb ? -1 : 1; if (xa <= xa0) break; } return 0; } static Bigint * diff (struct dtoa_context* C, Bigint *a, Bigint *b) { Bigint *c; int i, wa, wb; ULong *xa, *xae, *xb, *xbe, *xc; #ifdef ULLong ULLong borrow, y; #else ULong borrow, y; #ifdef Pack_32 ULong z; #endif #endif i = cmp(C, a,b); if (!i) { c = Balloc(C, 0); c->wds = 1; c->x[0] = 0; return c; } if (i < 0) { c = a; a = b; b = c; i = 1; } else i = 0; c = Balloc(C, a->k); c->sign = i; wa = a->wds; xa = a->x; xae = xa + wa; wb = b->wds; xb = b->x; xbe = xb + wb; xc = c->x; borrow = 0; #ifdef ULLong do { y = (ULLong)*xa++ - *xb++ - borrow; borrow = y >> 32 & (ULong)1; *xc++ = y & FFFFFFFF; } while(xb < xbe); while(xa < xae) { y = *xa++ - borrow; borrow = y >> 32 & (ULong)1; *xc++ = y & FFFFFFFF; } #else #ifdef Pack_32 do { y = (*xa & 0xffff) - (*xb & 0xffff) - borrow; borrow = (y & 0x10000) >> 16; z = (*xa++ >> 16) - (*xb++ >> 16) - borrow; borrow = (z & 0x10000) >> 16; Storeinc(xc, z, y); } while(xb < xbe); while(xa < xae) { y = (*xa & 0xffff) - borrow; borrow = (y & 0x10000) >> 16; z = (*xa++ >> 16) - borrow; borrow = (z & 0x10000) >> 16; Storeinc(xc, z, y); } #else do { y = *xa++ - *xb++ - borrow; borrow = (y & 0x10000) >> 16; *xc++ = y & 0xffff; } while(xb < xbe); while(xa < xae) { y = *xa++ - borrow; borrow = (y & 0x10000) >> 16; *xc++ = y & 0xffff; } #endif #endif while(!*--xc) wa--; c->wds = wa; return c; } static double ulp (struct dtoa_context* C, U *x) { Long L; U u; L = (word0(x) & Exp_mask) - (P-1)*Exp_msk1; #ifndef Avoid_Underflow #ifndef Sudden_Underflow if (L > 0) { #endif #endif #ifdef IBM L |= Exp_msk1 >> 4; #endif word0(&u) = L; word1(&u) = 0; #ifndef Avoid_Underflow #ifndef Sudden_Underflow } else { L = -L >> Exp_shift; if (L < Exp_shift) { word0(&u) = 0x80000 >> L; word1(&u) = 0; } else { word0(&u) = 0; L -= Exp_shift; word1(&u) = L >= 31 ? 1 : 1 << 31 - L; } } #endif #endif return dval(&u); } static double b2d (struct dtoa_context* C, Bigint *a, int *e) { ULong *xa, *xa0, w, y, z; int k; U d; #ifdef VAX ULong d0, d1; #else #define d0 word0(&d) #define d1 word1(&d) #endif xa0 = a->x; xa = xa0 + a->wds; y = *--xa; #ifdef DEBUG if (!y) Bug("zero y in b2d"); #endif k = hi0bits(C, y); *e = 32 - k; #ifdef Pack_32 if (k < Ebits) { d0 = Exp_1 | y >> (Ebits - k); w = xa > xa0 ? *--xa : 0; d1 = y << ((32-Ebits) + k) | w >> (Ebits - k); goto ret_d; } z = xa > xa0 ? *--xa : 0; if (k -= Ebits) { d0 = Exp_1 | y << k | z >> (32 - k); y = xa > xa0 ? *--xa : 0; d1 = z << k | y >> (32 - k); } else { d0 = Exp_1 | y; d1 = z; } #else if (k < Ebits + 16) { z = xa > xa0 ? *--xa : 0; d0 = Exp_1 | y << k - Ebits | z >> Ebits + 16 - k; w = xa > xa0 ? *--xa : 0; y = xa > xa0 ? *--xa : 0; d1 = z << k + 16 - Ebits | w << k - Ebits | y >> 16 + Ebits - k; goto ret_d; } z = xa > xa0 ? *--xa : 0; w = xa > xa0 ? *--xa : 0; k -= Ebits + 16; d0 = Exp_1 | y << k + 16 | z << k | w >> 16 - k; y = xa > xa0 ? *--xa : 0; d1 = w << k + 16 | y << k; #endif ret_d: #ifdef VAX word0(&d) = d0 >> 16 | d0 << 16; word1(&d) = d1 >> 16 | d1 << 16; #else #undef d0 #undef d1 #endif return dval(&d); } static Bigint * d2b (struct dtoa_context* C, U *d, int *e, int *bits) { Bigint *b; int de, k; ULong *x, y, z; #ifndef Sudden_Underflow int i; #endif #ifdef VAX ULong d0, d1; d0 = word0(d) >> 16 | word0(d) << 16; d1 = word1(d) >> 16 | word1(d) << 16; #else #define d0 word0(d) #define d1 word1(d) #endif #ifdef Pack_32 b = Balloc(C, 1); #else b = Balloc(C, 2); #endif x = b->x; z = d0 & Frac_mask; d0 &= 0x7fffffff; /* clear sign bit, which we ignore */ #ifdef Sudden_Underflow de = (int)(d0 >> Exp_shift); #ifndef IBM z |= Exp_msk11; #endif #else if ((de = (int)(d0 >> Exp_shift))) z |= Exp_msk1; #endif #ifdef Pack_32 if ((y = d1)) { if ((k = lo0bits(C, &y))) { x[0] = y | z << (32 - k); z >>= k; } else x[0] = y; #ifndef Sudden_Underflow i = #endif b->wds = (x[1] = z) ? 2 : 1; } else { k = lo0bits(C, &z); x[0] = z; #ifndef Sudden_Underflow i = #endif b->wds = 1; k += 32; } #else if (y = d1) { if (k = lo0bits(C, &y)) if (k >= 16) { x[0] = y | z << 32 - k & 0xffff; x[1] = z >> k - 16 & 0xffff; x[2] = z >> k; i = 2; } else { x[0] = y & 0xffff; x[1] = y >> 16 | z << 16 - k & 0xffff; x[2] = z >> k & 0xffff; x[3] = z >> k+16; i = 3; } else { x[0] = y & 0xffff; x[1] = y >> 16; x[2] = z & 0xffff; x[3] = z >> 16; i = 3; } } else { #ifdef DEBUG if (!z) Bug("Zero passed to d2b"); #endif k = lo0bits(C, &z); if (k >= 16) { x[0] = z; i = 0; } else { x[0] = z & 0xffff; x[1] = z >> 16; i = 1; } k += 32; } while(!x[i]) --i; b->wds = i + 1; #endif #ifndef Sudden_Underflow if (de) { #endif #ifdef IBM *e = (de - Bias - (P-1) << 2) + k; *bits = 4*P + 8 - k - hi0bits(C, word0(d) & Frac_mask); #else *e = de - Bias - (P-1) + k; *bits = P - k; #endif #ifndef Sudden_Underflow } else { *e = de - Bias - (P-1) + 1 + k; #ifdef Pack_32 *bits = 32*i - hi0bits(C, x[i-1]); #else *bits = (i+2)*16 - hi0bits(C, x[i]); #endif } #endif return b; } #undef d0 #undef d1 static double ratio (struct dtoa_context* C, Bigint *a, Bigint *b) { U da, db; int k, ka, kb; dval(&da) = b2d(C, a, &ka); dval(&db) = b2d(C, b, &kb); #ifdef Pack_32 k = ka - kb + 32*(a->wds - b->wds); #else k = ka - kb + 16*(a->wds - b->wds); #endif #ifdef IBM if (k > 0) { word0(&da) += (k >> 2)*Exp_msk1; if (k &= 3) dval(&da) *= 1 << k; } else { k = -k; word0(&db) += (k >> 2)*Exp_msk1; if (k &= 3) dval(&db) *= 1 << k; } #else if (k > 0) word0(&da) += k*Exp_msk1; else { k = -k; word0(&db) += k*Exp_msk1; } #endif return dval(&da) / dval(&db); } static CONST double tens[] = { 1e0, 1e1, 1e2, 1e3, 1e4, 1e5, 1e6, 1e7, 1e8, 1e9, 1e10, 1e11, 1e12, 1e13, 1e14, 1e15, 1e16, 1e17, 1e18, 1e19, 1e20, 1e21, 1e22 #ifdef VAX , 1e23, 1e24 #endif }; static CONST double #ifdef IEEE_Arith bigtens[] = { 1e16, 1e32, 1e64, 1e128, 1e256 }; static CONST double tinytens[] = { 1e-16, 1e-32, 1e-64, 1e-128, #ifdef Avoid_Underflow 9007199254740992.*9007199254740992.e-256 /* = 2^106 * 1e-256 */ #else 1e-256 #endif }; /* The factor of 2^53 in tinytens[4] helps us avoid setting the underflow */ /* flag unnecessarily. It leads to a song and dance at the end of strtod. */ #define Scale_Bit 0x10 #define n_bigtens 5 #else #ifdef IBM bigtens[] = { 1e16, 1e32, 1e64 }; static CONST double tinytens[] = { 1e-16, 1e-32, 1e-64 }; #define n_bigtens 3 #else bigtens[] = { 1e16, 1e32 }; static CONST double tinytens[] = { 1e-16, 1e-32 }; #define n_bigtens 2 #endif #endif #undef Need_Hexdig #ifdef INFNAN_CHECK #ifndef No_Hex_NaN #define Need_Hexdig #endif #endif #ifndef Need_Hexdig #ifndef NO_HEX_FP #define Need_Hexdig #endif #endif #ifdef Need_Hexdig /*{*/ static unsigned char hexdig[256]; static void htinit(unsigned char *h, unsigned char *s, int inc) { int i, j; for(i = 0; (j = s[i]) !=0; i++) h[j] = i + inc; } static void hexdig_init(void) { #define USC (unsigned char *) htinit(hexdig, USC "0123456789", 0x10); htinit(hexdig, USC "abcdef", 0x10 + 10); htinit(hexdig, USC "ABCDEF", 0x10 + 10); } #endif /* } Need_Hexdig */ #ifdef INFNAN_CHECK #ifndef NAN_WORD0 #define NAN_WORD0 0x7ff80000 #endif #ifndef NAN_WORD1 #define NAN_WORD1 0 #endif static int match (struct dtoa_context* C, const char **sp, const char *t) { int c, d; CONST char *s = *sp; while((d = *t++)) { if ((c = *++s) >= 'A' && c <= 'Z') c += 'a' - 'A'; if (c != d) return 0; } *sp = s + 1; return 1; } #ifndef No_Hex_NaN static void hexnan (struct dtoa_context* C, U *rvp, const char **sp) { ULong c, x[2]; CONST char *s; int c1, havedig, udx0, xshift; if (!hexdig['0']) hexdig_init(); x[0] = x[1] = 0; havedig = xshift = 0; udx0 = 1; s = *sp; /* allow optional initial 0x or 0X */ while((c = *(CONST unsigned char*)(s+1)) && c <= ' ') ++s; if (s[1] == '0' && (s[2] == 'x' || s[2] == 'X')) s += 2; while((c = *(CONST unsigned char*)++s)) { if ((c1 = hexdig[c])) c = c1 & 0xf; else if (c <= ' ') { if (udx0 && havedig) { udx0 = 0; xshift = 1; } continue; } #ifdef GDTOA_NON_PEDANTIC_NANCHECK else if (/*(*/ c == ')' && havedig) { *sp = s + 1; break; } else return; /* invalid form: don't change *sp */ #else else { do { if (/*(*/ c == ')') { *sp = s + 1; break; } } while((c = *++s)); break; } #endif havedig = 1; if (xshift) { xshift = 0; x[0] = x[1]; x[1] = 0; } if (udx0) x[0] = (x[0] << 4) | (x[1] >> 28); x[1] = (x[1] << 4) | c; } if ((x[0] &= 0xfffff) || x[1]) { word0(rvp) = Exp_mask | x[0]; word1(rvp) = x[1]; } } #endif /*No_Hex_NaN*/ #endif /* INFNAN_CHECK */ #ifdef Pack_32 #define ULbits 32 #define kshift 5 #define kmask 31 #else #define ULbits 16 #define kshift 4 #define kmask 15 #endif #if !defined(NO_HEX_FP) || defined(Honor_FLT_ROUNDS) /*{*/ static Bigint * increment(struct dtoa_context* C, Bigint *b) { ULong *x, *xe; Bigint *b1; x = b->x; xe = x + b->wds; do { if (*x < (ULong)0xffffffffL) { ++*x; return b; } *x++ = 0; } while(x < xe); { if (b->wds >= b->maxwds) { b1 = Balloc(C, b->k+1); Bcopy(b1,b); Bfree(C, b); b = b1; } b->x[b->wds++] = 1; } return b; } #endif /*}*/ #ifndef NO_HEX_FP /*{*/ static void rshift(struct dtoa_context* C, Bigint *b, int k) { ULong *x, *x1, *xe, y; int n; x = x1 = b->x; n = k >> kshift; if (n < b->wds) { xe = x + b->wds; x += n; if (k &= kmask) { n = 32 - k; y = *x++ >> k; while(x < xe) { *x1++ = (y | (*x << n)) & 0xffffffff; y = *x++ >> k; } if ((*x1 = y) !=0) x1++; } else while(x < xe) *x1++ = *x++; } if ((b->wds = x1 - b->x) == 0) b->x[0] = 0; } static ULong any_on(Bigint *b, int k) { int n, nwds; ULong *x, *x0, x1, x2; x = b->x; nwds = b->wds; n = k >> kshift; if (n > nwds) n = nwds; else if (n < nwds && (k &= kmask)) { x1 = x2 = x[n]; x1 >>= k; x1 <<= k; if (x1 != x2) return 1; } x0 = x; x += n; while(x > x0) if (*--x) return 1; return 0; } enum { /* rounding values: same as FLT_ROUNDS */ Round_zero = 0, Round_near = 1, Round_up = 2, Round_down = 3 }; static void gethex(struct dtoa_context* C, CONST char **sp, U *rvp, int rounding, int sign) { Bigint *b; CONST unsigned char *decpt, *s0, *s, *s1; Long e, e1; ULong L, lostbits, *x; int big, denorm, esign, havedig, k, n, nbits, up, zret; #ifdef IBM int j; #endif enum { #ifdef IEEE_Arith /*{{*/ emax = 0x7fe - Bias - P + 1, emin = Emin - P + 1 #else /*}{*/ emin = Emin - P, #ifdef VAX emax = 0x7ff - Bias - P + 1 #endif #ifdef IBM emax = 0x7f - Bias - P #endif #endif /*}}*/ }; #ifdef USE_LOCALE int i; #ifdef NO_LOCALE_CACHE const unsigned char *decimalpoint = (unsigned char*) localeconv()->decimal_point; #else const unsigned char *decimalpoint; static unsigned char *decimalpoint_cache; if (!(s0 = decimalpoint_cache)) { s0 = (unsigned char*)localeconv()->decimal_point; if ((decimalpoint_cache = (unsigned char*) MALLOC(strlen((CONST char*)s0) + 1))) { strcpy((char*)decimalpoint_cache, (CONST char*)s0); s0 = decimalpoint_cache; } } decimalpoint = s0; #endif #endif if (!hexdig['0']) hexdig_init(); havedig = 0; s0 = *(CONST unsigned char **)sp + 2; while(s0[havedig] == '0') havedig++; s0 += havedig; s = s0; decpt = 0; zret = 0; e = 0; if (hexdig[*s]) havedig++; else { zret = 1; #ifdef USE_LOCALE for(i = 0; decimalpoint[i]; ++i) { if (s[i] != decimalpoint[i]) goto pcheck; } decpt = s += i; #else if (*s != '.') goto pcheck; decpt = ++s; #endif if (!hexdig[*s]) goto pcheck; while(*s == '0') s++; if (hexdig[*s]) zret = 0; havedig = 1; s0 = s; } while(hexdig[*s]) s++; #ifdef USE_LOCALE if (*s == *decimalpoint && !decpt) { for(i = 1; decimalpoint[i]; ++i) { if (s[i] != decimalpoint[i]) goto pcheck; } decpt = s += i; #else if (*s == '.' && !decpt) { decpt = ++s; #endif while(hexdig[*s]) s++; }/*}*/ if (decpt) e = -(((Long)(s-decpt)) << 2); pcheck: s1 = s; big = esign = 0; switch(*s) { case 'p': case 'P': switch(*++s) { case '-': esign = 1; /* no break */ JQ_FALLTHROUGH; case '+': s++; } if ((n = hexdig[*s]) == 0 || n > 0x19) { s = s1; break; } e1 = n - 0x10; while((n = hexdig[*++s]) !=0 && n <= 0x19) { if (e1 & 0xf8000000) big = 1; e1 = 10*e1 + n - 0x10; } if (esign) e1 = -e1; e += e1; } *sp = (char*)s; if (!havedig) *sp = (char*)s0 - 1; if (zret) goto retz1; if (big) { if (esign) { #ifdef IEEE_Arith switch(rounding) { case Round_up: if (sign) break; goto ret_tiny; case Round_down: if (!sign) break; goto ret_tiny; } #endif goto retz; #ifdef IEEE_Arith ret_tiny: #ifndef NO_ERRNO errno = ERANGE; #endif word0(rvp) = 0; word1(rvp) = 1; return; #endif /* IEEE_Arith */ } switch(rounding) { case Round_near: goto ovfl1; case Round_up: if (!sign) goto ovfl1; goto ret_big; case Round_down: if (sign) goto ovfl1; goto ret_big; } ret_big: word0(rvp) = Big0; word1(rvp) = Big1; return; } n = s1 - s0 - 1; for(k = 0; n > (1 << (kshift-2)) - 1; n >>= 1) k++; b = Balloc(C, k); x = b->x; n = 0; L = 0; #ifdef USE_LOCALE for(i = 0; decimalpoint[i+1]; ++i); #endif while(s1 > s0) { #ifdef USE_LOCALE if (*--s1 == decimalpoint[i]) { s1 -= i; continue; } #else if (*--s1 == '.') continue; #endif if (n == ULbits) { *x++ = L; L = 0; n = 0; } L |= (hexdig[*s1] & 0x0f) << n; n += 4; } *x++ = L; b->wds = n = x - b->x; n = ULbits*n - hi0bits(C, L); nbits = Nbits; lostbits = 0; x = b->x; if (n > nbits) { n -= nbits; if (any_on(b,n)) { lostbits = 1; k = n - 1; if (x[k>>kshift] & 1 << (k & kmask)) { lostbits = 2; if (k > 0 && any_on(b,k)) lostbits = 3; } } rshift(C, b, n); e += n; } else if (n < nbits) { n = nbits - n; b = lshift(C, b, n); e -= n; x = b->x; } if (e > Emax) { ovfl: Bfree(C, b); ovfl1: #ifndef NO_ERRNO errno = ERANGE; #endif word0(rvp) = Exp_mask; word1(rvp) = 0; return; } denorm = 0; if (e < emin) { denorm = 1; n = emin - e; if (n >= nbits) { #ifdef IEEE_Arith /*{*/ switch (rounding) { case Round_near: if (n == nbits && (n < 2 || any_on(b,n-1))) goto ret_tiny; break; case Round_up: if (!sign) goto ret_tiny; break; case Round_down: if (sign) goto ret_tiny; } #endif /* } IEEE_Arith */ Bfree(C, b); retz: #ifndef NO_ERRNO errno = ERANGE; #endif retz1: rvp->d = 0.; return; } k = n - 1; if (lostbits) lostbits = 1; else if (k > 0) lostbits = any_on(b,k); if (x[k>>kshift] & 1 << (k & kmask)) lostbits |= 2; nbits -= n; rshift(C, b,n); e = emin; } if (lostbits) { up = 0; switch(rounding) { case Round_zero: break; case Round_near: if (lostbits & 2 && (lostbits & 1) | (x[0] & 1)) up = 1; break; case Round_up: up = 1 - sign; break; case Round_down: up = sign; } if (up) { k = b->wds; b = increment(C, b); x = b->x; if (denorm) { #if 0 if (nbits == Nbits - 1 && x[nbits >> kshift] & 1 << (nbits & kmask)) denorm = 0; /* not currently used */ #endif } else if (b->wds > k || ((n = nbits & kmask) !=0 && hi0bits(C, x[k-1]) < 32-n)) { rshift(C, b,1); if (++e > Emax) goto ovfl; } } } #ifdef IEEE_Arith if (denorm) word0(rvp) = b->wds > 1 ? b->x[1] & ~0x100000 : 0; else word0(rvp) = (b->x[1] & ~0x100000) | ((e + 0x3ff + 52) << 20); word1(rvp) = b->x[0]; #endif #ifdef IBM if ((j = e & 3)) { k = b->x[0] & ((1 << j) - 1); rshift(C, b,j); if (k) { switch(rounding) { case Round_up: if (!sign) increment(b); break; case Round_down: if (sign) increment(b); break; case Round_near: j = 1 << (j-1); if (k & j && ((k & (j-1)) | lostbits)) increment(b); } } } e >>= 2; word0(rvp) = b->x[1] | ((e + 65 + 13) << 24); word1(rvp) = b->x[0]; #endif #ifdef VAX /* The next two lines ignore swap of low- and high-order 2 bytes. */ /* word0(rvp) = (b->x[1] & ~0x800000) | ((e + 129 + 55) << 23); */ /* word1(rvp) = b->x[0]; */ word0(rvp) = ((b->x[1] & ~0x800000) >> 16) | ((e + 129 + 55) << 7) | (b->x[1] << 16); word1(rvp) = (b->x[0] >> 16) | (b->x[0] << 16); #endif Bfree(C, b); } #endif /*!NO_HEX_FP}*/ static int dshift(struct dtoa_context* C, Bigint *b, int p2) { int rv = hi0bits(C, b->x[b->wds-1]) - 4; if (p2 > 0) rv -= p2; return rv & kmask; } static int quorem (struct dtoa_context* C, Bigint *b, Bigint *S) { int n; ULong *bx, *bxe, q, *sx, *sxe; #ifdef ULLong ULLong borrow, carry, y, ys; #else ULong borrow, carry, y, ys; #ifdef Pack_32 ULong si, z, zs; #endif #endif n = S->wds; #ifdef DEBUG /*debug*/ if (b->wds > n) /*debug*/ Bug("oversize b in quorem"); #endif if (b->wds < n) return 0; sx = S->x; sxe = sx + --n; bx = b->x; bxe = bx + n; q = *bxe / (*sxe + 1); /* ensure q <= true quotient */ #ifdef DEBUG #ifdef NO_STRTOD_BIGCOMP /*debug*/ if (q > 9) #else /* An oversized q is possible when quorem is called from bigcomp and */ /* the input is near, e.g., twice the smallest denormalized number. */ /*debug*/ if (q > 15) #endif /*debug*/ Bug("oversized quotient in quorem"); #endif if (q) { borrow = 0; carry = 0; do { #ifdef ULLong ys = *sx++ * (ULLong)q + carry; carry = ys >> 32; y = *bx - (ys & FFFFFFFF) - borrow; borrow = y >> 32 & (ULong)1; *bx++ = y & FFFFFFFF; #else #ifdef Pack_32 si = *sx++; ys = (si & 0xffff) * q + carry; zs = (si >> 16) * q + (ys >> 16); carry = zs >> 16; y = (*bx & 0xffff) - (ys & 0xffff) - borrow; borrow = (y & 0x10000) >> 16; z = (*bx >> 16) - (zs & 0xffff) - borrow; borrow = (z & 0x10000) >> 16; Storeinc(bx, z, y); #else ys = *sx++ * q + carry; carry = ys >> 16; y = *bx - (ys & 0xffff) - borrow; borrow = (y & 0x10000) >> 16; *bx++ = y & 0xffff; #endif #endif } while(sx <= sxe); if (!*bxe) { bx = b->x; while(--bxe > bx && !*bxe) --n; b->wds = n; } } if (cmp(C, b, S) >= 0) { q++; borrow = 0; carry = 0; bx = b->x; sx = S->x; do { #ifdef ULLong ys = *sx++ + carry; carry = ys >> 32; y = *bx - (ys & FFFFFFFF) - borrow; borrow = y >> 32 & (ULong)1; *bx++ = y & FFFFFFFF; #else #ifdef Pack_32 si = *sx++; ys = (si & 0xffff) + carry; zs = (si >> 16) + (ys >> 16); carry = zs >> 16; y = (*bx & 0xffff) - (ys & 0xffff) - borrow; borrow = (y & 0x10000) >> 16; z = (*bx >> 16) - (zs & 0xffff) - borrow; borrow = (z & 0x10000) >> 16; Storeinc(bx, z, y); #else ys = *sx++ + carry; carry = ys >> 16; y = *bx - (ys & 0xffff) - borrow; borrow = (y & 0x10000) >> 16; *bx++ = y & 0xffff; #endif #endif } while(sx <= sxe); bx = b->x; bxe = bx + n; if (!*bxe) { while(--bxe > bx && !*bxe) --n; b->wds = n; } } return q; } #if defined(Avoid_Underflow) || !defined(NO_STRTOD_BIGCOMP) /*{*/ static double sulp (struct dtoa_context* C, U *x, BCinfo *bc) { U u; double rv; int i; rv = ulp(C, x); if (!bc->scale || (i = 2*P + 1 - ((word0(x) & Exp_mask) >> Exp_shift)) <= 0) return rv; /* Is there an example where i <= 0 ? */ word0(&u) = Exp_1 + (i << Exp_shift); word1(&u) = 0; return rv * u.d; } #endif /*}*/ #ifndef NO_STRTOD_BIGCOMP static void bigcomp (struct dtoa_context* C, U *rv, const char *s0, BCinfo *bc) { Bigint *b, *d; int b2, bbits, d2, dd=0, dig, dsign, i, j, nd, nd0, p2, p5, speccase; dsign = bc->dsign; nd = bc->nd; nd0 = bc->nd0; p5 = nd + bc->e0 - 1; speccase = 0; #ifndef Sudden_Underflow if (rv->d == 0.) { /* special case: value near underflow-to-zero */ /* threshold was rounded to zero */ b = i2b(C, 1); p2 = Emin - P + 1; bbits = 1; #ifdef Avoid_Underflow word0(rv) = (P+2) << Exp_shift; #else word1(rv) = 1; #endif i = 0; #ifdef Honor_FLT_ROUNDS if (bc->rounding == 1) #endif { speccase = 1; --p2; dsign = 0; goto have_i; } } else #endif b = d2b(C, rv, &p2, &bbits); #ifdef Avoid_Underflow p2 -= bc->scale; #endif /* floor(log2(rv)) == bbits - 1 + p2 */ /* Check for denormal case. */ i = P - bbits; if (i > (j = P - Emin - 1 + p2)) { #ifdef Sudden_Underflow Bfree(C, b); b = i2b(C, 1); p2 = Emin; i = P - 1; #ifdef Avoid_Underflow word0(rv) = (1 + bc->scale) << Exp_shift; #else word0(rv) = Exp_msk1; #endif word1(rv) = 0; #else i = j; #endif } #ifdef Honor_FLT_ROUNDS if (bc->rounding != 1) { if (i > 0) b = lshift(C, b, i); if (dsign) b = increment(b); } else #endif { b = lshift(C, b, ++i); b->x[0] |= 1; } #ifndef Sudden_Underflow have_i: #endif p2 -= p5 + i; d = i2b(C, 1); /* Arrange for convenient computation of quotients: * shift left if necessary so divisor has 4 leading 0 bits. */ if (p5 > 0) d = pow5mult(C, d, p5); else if (p5 < 0) b = pow5mult(C, b, -p5); if (p2 > 0) { b2 = p2; d2 = 0; } else { b2 = 0; d2 = -p2; } i = dshift(C, d, d2); if ((b2 += i) > 0) b = lshift(C, b, b2); if ((d2 += i) > 0) d = lshift(C, d, d2); /* Now b/d = exactly half-way between the two floating-point values */ /* on either side of the input string. Compute first digit of b/d. */ if (!(dig = quorem(C, b,d))) { b = multadd(C, b, 10, 0); /* very unlikely */ dig = quorem(C, b,d); } /* Compare b/d with s0 */ for(i = 0; i < nd0; ) { if ((dd = s0[i++] - '0' - dig)) goto ret; if (!b->x[0] && b->wds == 1) { if (i < nd) dd = 1; goto ret; } b = multadd(C, b, 10, 0); dig = quorem(C, b,d); } for(j = bc->dp1; i++ < nd;) { if ((dd = s0[j++] - '0' - dig)) goto ret; if (!b->x[0] && b->wds == 1) { if (i < nd) dd = 1; goto ret; } b = multadd(C, b, 10, 0); dig = quorem(C, b,d); } if (dig > 0 || b->x[0] || b->wds > 1) dd = -1; ret: Bfree(C, b); Bfree(C, d); #ifdef Honor_FLT_ROUNDS if (bc->rounding != 1) { if (dd < 0) { if (bc->rounding == 0) { if (!dsign) goto retlow1; } else if (dsign) goto rethi1; } else if (dd > 0) { if (bc->rounding == 0) { if (dsign) goto rethi1; goto ret1; } if (!dsign) goto rethi1; dval(rv) += 2.*sulp(C, rv,bc); } else { bc->inexact = 0; if (dsign) goto rethi1; } } else #endif if (speccase) { if (dd <= 0) rv->d = 0.; } else if (dd < 0) { if (!dsign) /* does not happen for round-near */ retlow1: dval(rv) -= sulp(C, rv,bc); } else if (dd > 0) { if (dsign) { rethi1: dval(rv) += sulp(C, rv,bc); } } else { /* Exact half-way case: apply round-even rule. */ if ((j = ((word0(rv) & Exp_mask) >> Exp_shift) - bc->scale) <= 0) { i = 1 - j; if (i <= 31) { if (word1(rv) & (0x1 << i)) goto odd; } else if (word0(rv) & (0x1 << (i-32))) goto odd; } else if (word1(rv) & 1) { odd: if (dsign) goto rethi1; goto retlow1; } } #ifdef Honor_FLT_ROUNDS ret1: #endif return; } #endif /* NO_STRTOD_BIGCOMP */ double jvp_strtod (struct dtoa_context* C, const char *s00, char **se) { int bb2, bb5, bbe, bd2, bd5, bbbits, bs2, c, e, e1; #ifdef Honor_FLT_ROUNDS int test_scale; #endif int esign, i, j, k, nd, nd0, nf, nz, nz0, nz1, sign; CONST char *s, *s0, *s1; double aadj, aadj1; Long L; U aadj2, adj, rv, rv0; ULong y, z; BCinfo bc; Bigint *bb=0, *bb1, *bd=0, *bd0, *bs=0, *delta=0; #ifdef Avoid_Underflow ULong Lsb, Lsb1; #endif #ifdef SET_INEXACT int oldinexact; #endif #ifndef NO_STRTOD_BIGCOMP int req_bigcomp = 0; #endif #ifdef Honor_FLT_ROUNDS /*{*/ #ifdef Trust_FLT_ROUNDS /*{{ only define this if FLT_ROUNDS really works! */ bc.rounding = Flt_Rounds; #else /*}{*/ bc.rounding = 1; switch(fegetround()) { case FE_TOWARDZERO: bc.rounding = 0; break; case FE_UPWARD: bc.rounding = 2; break; case FE_DOWNWARD: bc.rounding = 3; } #endif /*}}*/ #endif /*}*/ #ifdef USE_LOCALE CONST char *s2; #endif sign = nz0 = nz1 = nz = bc.dplen = bc.uflchk = 0; dval(&rv) = 0.; switch(*(s = s00)) { case '-': sign = 1; /* no break */ JQ_FALLTHROUGH; case '+': if (*++s) break; /* no break */ JQ_FALLTHROUGH; case 0: goto ret0; default: break; } if (*s == '0') { #ifndef NO_HEX_FP /*{*/ switch(s[1]) { case 'x': case 'X': #ifdef Honor_FLT_ROUNDS gethex(C, &s, &rv, bc.rounding, sign); #else gethex(C, &s, &rv, 1, sign); #endif goto ret; } #endif /*}*/ nz0 = 1; while(*++s == '0') ; if (!*s) goto ret; } s0 = s; y = z = 0; for(nd = nf = 0; (c = *s) >= '0' && c <= '9'; nd++, s++) if (nd < 9) y = 10*y + c - '0'; else if (nd < 16) z = 10*z + c - '0'; nd0 = nd; bc.dp0 = bc.dp1 = s - s0; for(s1 = s; s1 > s0 && *--s1 == '0'; ) ++nz1; #ifdef USE_LOCALE s1 = localeconv()->decimal_point; if (c == *s1) { c = '.'; if (*++s1) { s2 = s; for(;;) { if (*++s2 != *s1) { c = 0; break; } if (!*++s1) { s = s2; break; } } } } #endif if (c == '.') { c = *++s; bc.dp1 = s - s0; bc.dplen = bc.dp1 - bc.dp0; if (!nd) { for(; c == '0'; c = *++s) nz++; if (c > '0' && c <= '9') { bc.dp0 = s0 - s; bc.dp1 = bc.dp0 + bc.dplen; s0 = s; nf += nz; nz = 0; goto have_dig; } goto dig_done; } for(; c >= '0' && c <= '9'; c = *++s) { have_dig: nz++; if (c -= '0') { nf += nz; for(i = 1; i < nz; i++) if (nd++ < 9) y *= 10; else if (nd <= DBL_DIG + 1) z *= 10; if (nd++ < 9) y = 10*y + c; else if (nd <= DBL_DIG + 1) z = 10*z + c; nz = nz1 = 0; } } } dig_done: e = 0; if (c == 'e' || c == 'E') { if (!nd && !nz && !nz0) { goto ret0; } s00 = s; esign = 0; switch(c = *++s) { case '-': esign = 1; JQ_FALLTHROUGH; case '+': c = *++s; } if (c >= '0' && c <= '9') { while(c == '0') c = *++s; if (c > '0' && c <= '9') { L = c - '0'; s1 = s; while((c = *++s) >= '0' && c <= '9') L = 10*L + c - '0'; if (s - s1 > 8 || L > 19999) /* Avoid confusion from exponents * so large that e might overflow. */ e = 19999; /* safe for 16 bit ints */ else e = (int)L; if (esign) e = -e; } else e = 0; } else s = s00; } if (!nd) { if (!nz && !nz0) { #ifdef INFNAN_CHECK /* Check for Nan and Infinity */ if (!bc.dplen) switch(c) { case 'i': case 'I': if (match(C, &s,"nf")) { --s; if (!match(C, &s,"inity")) ++s; word0(&rv) = 0x7ff00000; word1(&rv) = 0; goto ret; } break; case 'n': case 'N': if (match(C, &s, "an")) { word0(&rv) = NAN_WORD0; word1(&rv) = NAN_WORD1; #ifndef No_Hex_NaN if (*s == '(') /*)*/ hexnan(C, &rv, &s); #endif goto ret; } } #endif /* INFNAN_CHECK */ ret0: s = s00; sign = 0; } goto ret; } bc.e0 = e1 = e -= nf; /* Now we have nd0 digits, starting at s0, followed by a * decimal point, followed by nd-nd0 digits. The number we're * after is the integer represented by those digits times * 10**e */ if (!nd0) nd0 = nd; k = nd < DBL_DIG + 1 ? nd : DBL_DIG + 1; dval(&rv) = y; if (k > 9) { #ifdef SET_INEXACT if (k > DBL_DIG) oldinexact = get_inexact(); #endif dval(&rv) = tens[k - 9] * dval(&rv) + z; } bd0 = 0; if (nd <= DBL_DIG #ifndef RND_PRODQUOT #ifndef Honor_FLT_ROUNDS && Flt_Rounds == 1 #endif #endif ) { if (!e) goto ret; #ifndef ROUND_BIASED_without_Round_Up if (e > 0) { if (e <= Ten_pmax) { #ifdef VAX goto vax_ovfl_check; #else #ifdef Honor_FLT_ROUNDS /* round correctly FLT_ROUNDS = 2 or 3 */ if (sign) { rv.d = -rv.d; sign = 0; } #endif /* rv = */ rounded_product(dval(&rv), tens[e]); goto ret; #endif } i = DBL_DIG - nd; if (e <= Ten_pmax + i) { /* A fancier test would sometimes let us do * this for larger i values. */ #ifdef Honor_FLT_ROUNDS /* round correctly FLT_ROUNDS = 2 or 3 */ if (sign) { rv.d = -rv.d; sign = 0; } #endif e -= i; dval(&rv) *= tens[i]; #ifdef VAX /* VAX exponent range is so narrow we must * worry about overflow here... */ vax_ovfl_check: word0(&rv) -= P*Exp_msk1; /* rv = */ rounded_product(dval(&rv), tens[e]); if ((word0(&rv) & Exp_mask) > Exp_msk1*(DBL_MAX_EXP+Bias-1-P)) goto ovfl; word0(&rv) += P*Exp_msk1; #else /* rv = */ rounded_product(dval(&rv), tens[e]); #endif goto ret; } } #ifndef Inaccurate_Divide else if (e >= -Ten_pmax) { #ifdef Honor_FLT_ROUNDS /* round correctly FLT_ROUNDS = 2 or 3 */ if (sign) { rv.d = -rv.d; sign = 0; } #endif /* rv = */ rounded_quotient(dval(&rv), tens[-e]); goto ret; } #endif #endif /* ROUND_BIASED_without_Round_Up */ } e1 += nd - k; #ifdef IEEE_Arith #ifdef SET_INEXACT bc.inexact = 1; if (k <= DBL_DIG) oldinexact = get_inexact(); #endif #ifdef Avoid_Underflow bc.scale = 0; #endif #ifdef Honor_FLT_ROUNDS if (bc.rounding >= 2) { if (sign) bc.rounding = bc.rounding == 2 ? 0 : 2; else if (bc.rounding != 2) bc.rounding = 0; } #endif #endif /*IEEE_Arith*/ /* Get starting approximation = rv * 10**e1 */ if (e1 > 0) { if ((i = e1 & 15)) dval(&rv) *= tens[i]; if (e1 &= ~15) { if (e1 > DBL_MAX_10_EXP) { ovfl: /* Can't trust HUGE_VAL */ #ifdef IEEE_Arith #ifdef Honor_FLT_ROUNDS switch(bc.rounding) { case 0: /* toward 0 */ case 3: /* toward -infinity */ word0(&rv) = Big0; word1(&rv) = Big1; break; default: word0(&rv) = Exp_mask; word1(&rv) = 0; } #else /*Honor_FLT_ROUNDS*/ word0(&rv) = Exp_mask; word1(&rv) = 0; #endif /*Honor_FLT_ROUNDS*/ #ifdef SET_INEXACT /* set overflow bit */ dval(&rv0) = 1e300; dval(&rv0) *= dval(&rv0); #endif #else /*IEEE_Arith*/ word0(&rv) = Big0; word1(&rv) = Big1; #endif /*IEEE_Arith*/ range_err: if (bd0) { Bfree(C, bb); Bfree(C, bd); Bfree(C, bs); Bfree(C, bd0); Bfree(C, delta); } #ifndef NO_ERRNO errno = ERANGE; #endif goto ret; } e1 >>= 4; for(j = 0; e1 > 1; j++, e1 >>= 1) if (e1 & 1) dval(&rv) *= bigtens[j]; /* The last multiplication could overflow. */ word0(&rv) -= P*Exp_msk1; dval(&rv) *= bigtens[j]; if ((z = word0(&rv) & Exp_mask) > Exp_msk1*(DBL_MAX_EXP+Bias-P)) goto ovfl; if (z > Exp_msk1*(DBL_MAX_EXP+Bias-1-P)) { /* set to largest number */ /* (Can't trust DBL_MAX) */ word0(&rv) = Big0; word1(&rv) = Big1; } else word0(&rv) += P*Exp_msk1; } } else if (e1 < 0) { e1 = -e1; if ((i = e1 & 15)) dval(&rv) /= tens[i]; if (e1 >>= 4) { if (e1 >= 1 << n_bigtens) goto undfl; #ifdef Avoid_Underflow if (e1 & Scale_Bit) bc.scale = 2*P; for(j = 0; e1 > 0; j++, e1 >>= 1) if (e1 & 1) dval(&rv) *= tinytens[j]; if (bc.scale && (j = 2*P + 1 - ((word0(&rv) & Exp_mask) >> Exp_shift)) > 0) { /* scaled rv is denormal; clear j low bits */ if (j >= 32) { if (j > 54) goto undfl; word1(&rv) = 0; if (j >= 53) word0(&rv) = (P+2)*Exp_msk1; else word0(&rv) &= 0xffffffff << (j-32); } else word1(&rv) &= 0xffffffff << j; } #else for(j = 0; e1 > 1; j++, e1 >>= 1) if (e1 & 1) dval(&rv) *= tinytens[j]; /* The last multiplication could underflow. */ dval(&rv0) = dval(&rv); dval(&rv) *= tinytens[j]; if (!dval(&rv)) { dval(&rv) = 2.*dval(&rv0); dval(&rv) *= tinytens[j]; #endif if (!dval(&rv)) { undfl: dval(&rv) = 0.; goto range_err; } #ifndef Avoid_Underflow word0(&rv) = Tiny0; word1(&rv) = Tiny1; /* The refinement below will clean * this approximation up. */ } #endif } } /* Now the hard part -- adjusting rv to the correct value.*/ /* Put digits into bd: true value = bd * 10^e */ bc.nd = nd - nz1; #ifndef NO_STRTOD_BIGCOMP bc.nd0 = nd0; /* Only needed if nd > strtod_diglim, but done here */ /* to silence an erroneous warning about bc.nd0 */ /* possibly not being initialized. */ if (nd > strtod_diglim) { /* ASSERT(strtod_diglim >= 18); 18 == one more than the */ /* minimum number of decimal digits to distinguish double values */ /* in IEEE arithmetic. */ i = j = 18; if (i > nd0) j += bc.dplen; for(;;) { if (--j < bc.dp1 && j >= bc.dp0) j = bc.dp0 - 1; if (s0[j] != '0') break; --i; } e += nd - i; nd = i; if (nd0 > nd) nd0 = nd; if (nd < 9) { /* must recompute y */ y = 0; for(i = 0; i < nd0; ++i) y = 10*y + s0[i] - '0'; for(j = bc.dp1; i < nd; ++i) y = 10*y + s0[j++] - '0'; } } #endif bd0 = s2b(C, s0, nd0, nd, y, bc.dplen); for(;;) { bd = Balloc(C, bd0->k); Bcopy(bd, bd0); bb = d2b(C, &rv, &bbe, &bbbits); /* rv = bb * 2^bbe */ bs = i2b(C, 1); if (e >= 0) { bb2 = bb5 = 0; bd2 = bd5 = e; } else { bb2 = bb5 = -e; bd2 = bd5 = 0; } if (bbe >= 0) bb2 += bbe; else bd2 -= bbe; bs2 = bb2; #ifdef Honor_FLT_ROUNDS if (bc.rounding != 1) bs2++; #endif #ifdef Avoid_Underflow Lsb = LSB; Lsb1 = 0; j = bbe - bc.scale; i = j + bbbits - 1; /* logb(rv) */ j = P + 1 - bbbits; if (i < Emin) { /* denormal */ i = Emin - i; j -= i; if (i < 32) Lsb <<= i; else if (i < 52) Lsb1 = Lsb << (i-32); else Lsb1 = Exp_mask; } #else /*Avoid_Underflow*/ #ifdef Sudden_Underflow #ifdef IBM j = 1 + 4*P - 3 - bbbits + ((bbe + bbbits - 1) & 3); #else j = P + 1 - bbbits; #endif #else /*Sudden_Underflow*/ j = bbe; i = j + bbbits - 1; /* logb(rv) */ if (i < Emin) /* denormal */ j += P - Emin; else j = P + 1 - bbbits; #endif /*Sudden_Underflow*/ #endif /*Avoid_Underflow*/ bb2 += j; bd2 += j; #ifdef Avoid_Underflow bd2 += bc.scale; #endif i = bb2 < bd2 ? bb2 : bd2; if (i > bs2) i = bs2; if (i > 0) { bb2 -= i; bd2 -= i; bs2 -= i; } if (bb5 > 0) { bs = pow5mult(C, bs, bb5); bb1 = mult(C, bs, bb); Bfree(C, bb); bb = bb1; } if (bb2 > 0) bb = lshift(C, bb, bb2); if (bd5 > 0) bd = pow5mult(C, bd, bd5); if (bd2 > 0) bd = lshift(C, bd, bd2); if (bs2 > 0) bs = lshift(C, bs, bs2); delta = diff(C, bb, bd); bc.dsign = delta->sign; delta->sign = 0; i = cmp(C, delta, bs); #ifndef NO_STRTOD_BIGCOMP /*{*/ if (bc.nd > nd && i <= 0) { if (bc.dsign) { /* Must use bigcomp(C, ). */ req_bigcomp = 1; break; } #ifdef Honor_FLT_ROUNDS if (bc.rounding != 1) { if (i < 0) { req_bigcomp = 1; break; } } else #endif i = -1; /* Discarded digits make delta smaller. */ } #endif /*}*/ #ifdef Honor_FLT_ROUNDS /*{*/ if (bc.rounding != 1) { if (i < 0) { /* Error is less than an ulp */ if (!delta->x[0] && delta->wds <= 1) { /* exact */ #ifdef SET_INEXACT bc.inexact = 0; #endif break; } if (bc.rounding) { if (bc.dsign) { adj.d = 1.; goto apply_adj; } } else if (!bc.dsign) { adj.d = -1.; if (!word1(&rv) && !(word0(&rv) & Frac_mask)) { y = word0(&rv) & Exp_mask; test_scale = y; #ifdef Avoid_Underflow test_scale = (!bc.scale || y > 2*P*Exp_msk1); #endif if (test_scale) { delta = lshift(C, delta,Log2P); if (cmp(C, delta, bs) <= 0) adj.d = -0.5; } } apply_adj: #ifdef Avoid_Underflow /*{*/ if (bc.scale && (y = word0(&rv) & Exp_mask) <= 2*P*Exp_msk1) word0(&adj) += (2*P+1)*Exp_msk1 - y; #else #ifdef Sudden_Underflow if ((word0(&rv) & Exp_mask) <= P*Exp_msk1) { word0(&rv) += P*Exp_msk1; dval(&rv) += adj.d*ulp(C, dval(&rv)); word0(&rv) -= P*Exp_msk1; } else #endif /*Sudden_Underflow*/ #endif /*Avoid_Underflow}*/ dval(&rv) += adj.d*ulp(C, &rv); } break; } adj.d = ratio(C, delta, bs); if (adj.d < 1.) adj.d = 1.; if (adj.d <= 0x7ffffffe) { /* adj = rounding ? ceil(adj) : floor(adj); */ y = adj.d; if (y != adj.d) { if (!((bc.rounding>>1) ^ bc.dsign)) y++; adj.d = y; } } #ifdef Avoid_Underflow /*{*/ if (bc.scale && (y = word0(&rv) & Exp_mask) <= 2*P*Exp_msk1) word0(&adj) += (2*P+1)*Exp_msk1 - y; #else #ifdef Sudden_Underflow if ((word0(&rv) & Exp_mask) <= P*Exp_msk1) { word0(&rv) += P*Exp_msk1; adj.d *= ulp(C, dval(&rv)); if (bc.dsign) dval(&rv) += adj.d; else dval(&rv) -= adj.d; word0(&rv) -= P*Exp_msk1; goto cont; } #endif /*Sudden_Underflow*/ #endif /*Avoid_Underflow}*/ adj.d *= ulp(C, &rv); if (bc.dsign) { if (word0(&rv) == Big0 && word1(&rv) == Big1) goto ovfl; dval(&rv) += adj.d; } else dval(&rv) -= adj.d; goto cont; } #endif /*}Honor_FLT_ROUNDS*/ if (i < 0) { /* Error is less than half an ulp -- check for * special case of mantissa a power of two. */ if (bc.dsign || word1(&rv) || word0(&rv) & Bndry_mask #ifdef IEEE_Arith /*{*/ #ifdef Avoid_Underflow || (word0(&rv) & Exp_mask) <= (2*P+1)*Exp_msk1 #else || (word0(&rv) & Exp_mask) <= Exp_msk1 #endif #endif /*}*/ ) { #ifdef SET_INEXACT if (!delta->x[0] && delta->wds <= 1) bc.inexact = 0; #endif break; } if (!delta->x[0] && delta->wds <= 1) { /* exact result */ #ifdef SET_INEXACT bc.inexact = 0; #endif break; } delta = lshift(C, delta,Log2P); if (cmp(C, delta, bs) > 0) goto drop_down; break; } if (i == 0) { /* exactly half-way between */ if (bc.dsign) { if ((word0(&rv) & Bndry_mask1) == Bndry_mask1 && word1(&rv) == ( #ifdef Avoid_Underflow (bc.scale && (y = word0(&rv) & Exp_mask) <= 2*P*Exp_msk1) ? (0xffffffff & (0xffffffff << (2*P+1-(y>>Exp_shift)))) : #endif 0xffffffff)) { /*boundary case -- increment exponent*/ if (word0(&rv) == Big0 && word1(&rv) == Big1) goto ovfl; word0(&rv) = (word0(&rv) & Exp_mask) + Exp_msk1 #ifdef IBM | Exp_msk1 >> 4 #endif ; word1(&rv) = 0; #ifdef Avoid_Underflow bc.dsign = 0; #endif break; } } else if (!(word0(&rv) & Bndry_mask) && !word1(&rv)) { drop_down: /* boundary case -- decrement exponent */ #ifdef Sudden_Underflow /*{{*/ L = word0(&rv) & Exp_mask; #ifdef IBM if (L < Exp_msk1) #else #ifdef Avoid_Underflow if (L <= (bc.scale ? (2*P+1)*Exp_msk1 : Exp_msk1)) #else if (L <= Exp_msk1) #endif /*Avoid_Underflow*/ #endif /*IBM*/ { if (bc.nd >nd) { bc.uflchk = 1; break; } goto undfl; } L -= Exp_msk1; #else /*Sudden_Underflow}{*/ #ifdef Avoid_Underflow if (bc.scale) { L = word0(&rv) & Exp_mask; if (L <= (2*P+1)*Exp_msk1) { if (L > (P+2)*Exp_msk1) /* round even ==> */ /* accept rv */ break; /* rv = smallest denormal */ if (bc.nd >nd) { bc.uflchk = 1; break; } goto undfl; } } #endif /*Avoid_Underflow*/ L = (word0(&rv) & Exp_mask) - Exp_msk1; #endif /*Sudden_Underflow}}*/ word0(&rv) = L | Bndry_mask1; word1(&rv) = 0xffffffff; #ifdef IBM goto cont; #else #ifndef NO_STRTOD_BIGCOMP if (bc.nd > nd) goto cont; #endif break; #endif } #ifndef ROUND_BIASED #ifdef Avoid_Underflow if (Lsb1) { if (!(word0(&rv) & Lsb1)) break; } else if (!(word1(&rv) & Lsb)) break; #else if (!(word1(&rv) & LSB)) break; #endif #endif if (bc.dsign) #ifdef Avoid_Underflow dval(&rv) += sulp(C, &rv, &bc); #else dval(&rv) += ulp(C, &rv); #endif #ifndef ROUND_BIASED else { #ifdef Avoid_Underflow dval(&rv) -= sulp(C, &rv, &bc); #else dval(&rv) -= ulp(C, &rv); #endif #ifndef Sudden_Underflow if (!dval(&rv)) { if (bc.nd >nd) { bc.uflchk = 1; break; } goto undfl; } #endif } #ifdef Avoid_Underflow bc.dsign = 1 - bc.dsign; #endif #endif break; } if ((aadj = ratio(C, delta, bs)) <= 2.) { if (bc.dsign) aadj = aadj1 = 1.; else if (word1(&rv) || word0(&rv) & Bndry_mask) { #ifndef Sudden_Underflow if (word1(&rv) == Tiny1 && !word0(&rv)) { if (bc.nd >nd) { bc.uflchk = 1; break; } goto undfl; } #endif aadj = 1.; aadj1 = -1.; } else { /* special case -- power of FLT_RADIX to be */ /* rounded down... */ if (aadj < 2./FLT_RADIX) aadj = 1./FLT_RADIX; else aadj *= 0.5; aadj1 = -aadj; } } else { aadj *= 0.5; aadj1 = bc.dsign ? aadj : -aadj; #ifdef Check_FLT_ROUNDS switch(bc.rounding) { case 2: /* towards +infinity */ aadj1 -= 0.5; break; case 0: /* towards 0 */ case 3: /* towards -infinity */ aadj1 += 0.5; } #else if (Flt_Rounds == 0) aadj1 += 0.5; #endif /*Check_FLT_ROUNDS*/ } y = word0(&rv) & Exp_mask; /* Check for overflow */ if (y == Exp_msk1*(DBL_MAX_EXP+Bias-1)) { dval(&rv0) = dval(&rv); word0(&rv) -= P*Exp_msk1; adj.d = aadj1 * ulp(C, &rv); dval(&rv) += adj.d; if ((word0(&rv) & Exp_mask) >= Exp_msk1*(DBL_MAX_EXP+Bias-P)) { if (word0(&rv0) == Big0 && word1(&rv0) == Big1) goto ovfl; word0(&rv) = Big0; word1(&rv) = Big1; goto cont; } else word0(&rv) += P*Exp_msk1; } else { #ifdef Avoid_Underflow if (bc.scale && y <= 2*P*Exp_msk1) { if (aadj <= 0x7fffffff) { if ((z = aadj) <= 0) z = 1; aadj = z; aadj1 = bc.dsign ? aadj : -aadj; } dval(&aadj2) = aadj1; word0(&aadj2) += (2*P+1)*Exp_msk1 - y; aadj1 = dval(&aadj2); adj.d = aadj1 * ulp(C, &rv); dval(&rv) += adj.d; if (rv.d == 0.) #ifdef NO_STRTOD_BIGCOMP goto undfl; #else { if (bc.nd > nd) bc.dsign = 1; break; } #endif } else { adj.d = aadj1 * ulp(C, &rv); dval(&rv) += adj.d; } #else #ifdef Sudden_Underflow if ((word0(&rv) & Exp_mask) <= P*Exp_msk1) { dval(&rv0) = dval(&rv); word0(&rv) += P*Exp_msk1; adj.d = aadj1 * ulp(C, &rv); dval(&rv) += adj.d; #ifdef IBM if ((word0(&rv) & Exp_mask) < P*Exp_msk1) #else if ((word0(&rv) & Exp_mask) <= P*Exp_msk1) #endif { if (word0(&rv0) == Tiny0 && word1(&rv0) == Tiny1) { if (bc.nd >nd) { bc.uflchk = 1; break; } goto undfl; } word0(&rv) = Tiny0; word1(&rv) = Tiny1; goto cont; } else word0(&rv) -= P*Exp_msk1; } else { adj.d = aadj1 * ulp(C, &rv); dval(&rv) += adj.d; } #else /*Sudden_Underflow*/ /* Compute adj so that the IEEE rounding rules will * correctly round rv + adj in some half-way cases. * If rv * ulp(C, rv) is denormalized (i.e., * y <= (P-1)*Exp_msk1), we must adjust aadj to avoid * trouble from bits lost to denormalization; * example: 1.2e-307 . */ if (y <= (P-1)*Exp_msk1 && aadj > 1.) { aadj1 = (double)(int)(aadj + 0.5); if (!bc.dsign) aadj1 = -aadj1; } adj.d = aadj1 * ulp(C, &rv); dval(&rv) += adj.d; #endif /*Sudden_Underflow*/ #endif /*Avoid_Underflow*/ } z = word0(&rv) & Exp_mask; #ifndef SET_INEXACT if (bc.nd == nd) { #ifdef Avoid_Underflow if (!bc.scale) #endif if (y == z) { /* Can we stop now? */ L = (Long)aadj; aadj -= L; /* The tolerances below are conservative. */ if (bc.dsign || word1(&rv) || word0(&rv) & Bndry_mask) { if (aadj < .4999999 || aadj > .5000001) break; } else if (aadj < .4999999/FLT_RADIX) break; } } #endif cont: Bfree(C, bb); Bfree(C, bd); Bfree(C, bs); Bfree(C, delta); } Bfree(C, bb); Bfree(C, bd); Bfree(C, bs); Bfree(C, bd0); Bfree(C, delta); #ifndef NO_STRTOD_BIGCOMP if (req_bigcomp) { bd0 = 0; bc.e0 += nz1; bigcomp(C, &rv, s0, &bc); y = word0(&rv) & Exp_mask; if (y == Exp_mask) goto ovfl; if (y == 0 && rv.d == 0.) goto undfl; } #endif #ifdef SET_INEXACT if (bc.inexact) { if (!oldinexact) { word0(&rv0) = Exp_1 + (70 << Exp_shift); word1(&rv0) = 0; dval(&rv0) += 1.; } } else if (!oldinexact) clear_inexact(); #endif #ifdef Avoid_Underflow if (bc.scale) { word0(&rv0) = Exp_1 - 2*P*Exp_msk1; word1(&rv0) = 0; dval(&rv) *= dval(&rv0); #ifndef NO_ERRNO /* try to avoid the bug of testing an 8087 register value */ #ifdef IEEE_Arith if (!(word0(&rv) & Exp_mask)) #else if (word0(&rv) == 0 && word1(&rv) == 0) #endif errno = ERANGE; #endif } #endif /* Avoid_Underflow */ #ifdef SET_INEXACT if (bc.inexact && !(word0(&rv) & Exp_mask)) { /* set underflow bit */ dval(&rv0) = 1e-300; dval(&rv0) *= dval(&rv0); } #endif ret: if (se) *se = (char *)s; return sign ? -dval(&rv) : dval(&rv); } static char * rv_alloc(struct dtoa_context* C, int i) { int j, k, *r; j = sizeof(ULong); for(k = 0; (int)(sizeof(Bigint) - sizeof(ULong) - sizeof(int)) + j <= i; j <<= 1) k++; r = (int*)Balloc(C, k); *r = k; return (char *)(r+1); } static char * nrv_alloc(struct dtoa_context* C, const char *s, char **rve, int n) { char *rv, *t; t = rv = rv_alloc(C, n); while((*t = *s++)) t++; if (rve) *rve = t; return rv; } /* freedtoa(s) must be used to free values s returned by dtoa * when MULTIPLE_THREADS is #defined. It should be used in all cases, * but for consistency with earlier versions of dtoa, it is optional * when MULTIPLE_THREADS is not defined. */ void jvp_freedtoa(struct dtoa_context* C, char *s) { Bigint *b = (Bigint *)((int *)s - 1); b->maxwds = 1 << (b->k = *(int*)b); Bfree(C, b); } /* dtoa for IEEE arithmetic (dmg): convert double to ASCII string. * * Inspired by "How to Print Floating-Point Numbers Accurately" by * Guy L. Steele, Jr. and Jon L. White [Proc. ACM SIGPLAN '90, pp. 112-126]. * * Modifications: * 1. Rather than iterating, we use a simple numeric overestimate * to determine k = floor(log10(d)). We scale relevant * quantities using O(log2(k)) rather than O(k) multiplications. * 2. For some modes > 2 (corresponding to ecvt and fcvt), we don't * try to generate digits strictly left to right. Instead, we * compute with fewer bits and propagate the carry if necessary * when rounding the final digit up. This is often faster. * 3. Under the assumption that input will be rounded nearest, * mode 0 renders 1e23 as 1e23 rather than 9.999999999999999e22. * That is, we allow equality in stopping tests when the * round-nearest rule will give the same floating-point value * as would satisfaction of the stopping test with strict * inequality. * 4. We remove common factors of powers of 2 from relevant * quantities. * 5. When converting floating-point integers less than 1e16, * we use floating-point arithmetic rather than resorting * to multiple-precision integers. * 6. When asked to produce fewer than 15 digits, we first try * to get by with floating-point arithmetic; we resort to * multiple-precision integer arithmetic only if we cannot * guarantee that the floating-point calculation has given * the correctly rounded result. For k requested digits and * "uniformly" distributed input, the probability is * something like 10^(k-15) that we must resort to the Long * calculation. */ char * jvp_dtoa (struct dtoa_context* C, double dd, int mode, int ndigits, int *decpt, int *sign, char **rve) { /* Arguments ndigits, decpt, sign are similar to those of ecvt and fcvt; trailing zeros are suppressed from the returned string. If not null, *rve is set to point to the end of the return value. If d is +-Infinity or NaN, then *decpt is set to 9999. mode: 0 ==> shortest string that yields d when read in and rounded to nearest. 1 ==> like 0, but with Steele & White stopping rule; e.g. with IEEE P754 arithmetic , mode 0 gives 1e23 whereas mode 1 gives 9.999999999999999e22. 2 ==> max(1,ndigits) significant digits. This gives a return value similar to that of ecvt, except that trailing zeros are suppressed. 3 ==> through ndigits past the decimal point. This gives a return value similar to that from fcvt, except that trailing zeros are suppressed, and ndigits can be negative. 4,5 ==> similar to 2 and 3, respectively, but (in round-nearest mode) with the tests of mode 0 to possibly return a shorter string that rounds to d. With IEEE arithmetic and compilation with -DHonor_FLT_ROUNDS, modes 4 and 5 behave the same as modes 2 and 3 when FLT_ROUNDS != 1. 6-9 ==> Debugging modes similar to mode - 4: don't try fast floating-point estimate (if applicable). Values of mode other than 0-9 are treated as mode 0. Sufficient space is allocated to the return value to hold the suppressed trailing zeros. */ int bbits, b2, b5, be, dig, i, ieps, ilim, ilim0, ilim1, j, j1=0, k, k0, k_check, leftright, m2, m5, s2, s5, spec_case, try_quick; Long L; #ifndef Sudden_Underflow int denorm; ULong x; #endif Bigint *b, *b1, *delta, *mlo, *mhi, *S; U d2, eps, u; double ds; char *s, *s0; #ifndef No_leftright #ifdef IEEE_Arith U eps1; #endif #endif #ifdef SET_INEXACT int inexact, oldinexact; #endif #ifdef Honor_FLT_ROUNDS /*{*/ int Rounding; #ifdef Trust_FLT_ROUNDS /*{{ only define this if FLT_ROUNDS really works! */ Rounding = Flt_Rounds; #else /*}{*/ Rounding = 1; switch(fegetround()) { case FE_TOWARDZERO: Rounding = 0; break; case FE_UPWARD: Rounding = 2; break; case FE_DOWNWARD: Rounding = 3; } #endif /*}}*/ #endif /*}*/ u.d = dd; if (word0(&u) & Sign_bit) { /* set sign for everything, including 0's and NaNs */ *sign = 1; word0(&u) &= ~Sign_bit; /* clear sign bit */ } else *sign = 0; #if defined(IEEE_Arith) + defined(VAX) #ifdef IEEE_Arith if ((word0(&u) & Exp_mask) == Exp_mask) #else if (word0(&u) == 0x8000) #endif { /* Infinity or NaN */ *decpt = 9999; #ifdef IEEE_Arith if (!word1(&u) && !(word0(&u) & 0xfffff)) return nrv_alloc(C, "Infinity", rve, 8); #endif return nrv_alloc(C, "NaN", rve, 3); } #endif #ifdef IBM dval(&u) += 0; /* normalize */ #endif if (!dval(&u)) { *decpt = 1; return nrv_alloc(C, "0", rve, 1); } #ifdef SET_INEXACT try_quick = oldinexact = get_inexact(); inexact = 1; #endif #ifdef Honor_FLT_ROUNDS if (Rounding >= 2) { if (*sign) Rounding = Rounding == 2 ? 0 : 2; else if (Rounding != 2) Rounding = 0; } #endif b = d2b(C, &u, &be, &bbits); #ifdef Sudden_Underflow i = (int)(word0(&u) >> Exp_shift1 & (Exp_mask>>Exp_shift1)); #else if ((i = (int)(word0(&u) >> Exp_shift1 & (Exp_mask>>Exp_shift1)))) { #endif dval(&d2) = dval(&u); word0(&d2) &= Frac_mask1; word0(&d2) |= Exp_11; #ifdef IBM if (j = 11 - hi0bits(C, word0(&d2) & Frac_mask)) dval(&d2) /= 1 << j; #endif /* log(x) ~=~ log(1.5) + (x-1.5)/1.5 * log10(x) = log(x) / log(10) * ~=~ log(1.5)/log(10) + (x-1.5)/(1.5*log(10)) * log10(d) = (i-Bias)*log(2)/log(10) + log10(d2) * * This suggests computing an approximation k to log10(d) by * * k = (i - Bias)*0.301029995663981 * + ( (d2-1.5)*0.289529654602168 + 0.176091259055681 ); * * We want k to be too large rather than too small. * The error in the first-order Taylor series approximation * is in our favor, so we just round up the constant enough * to compensate for any error in the multiplication of * (i - Bias) by 0.301029995663981; since |i - Bias| <= 1077, * and 1077 * 0.30103 * 2^-52 ~=~ 7.2e-14, * adding 1e-13 to the constant term more than suffices. * Hence we adjust the constant term to 0.1760912590558. * (We could get a more accurate k by invoking log10, * but this is probably not worthwhile.) */ i -= Bias; #ifdef IBM i <<= 2; i += j; #endif #ifndef Sudden_Underflow denorm = 0; } else { /* d is denormalized */ i = bbits + be + (Bias + (P-1) - 1); x = i > 32 ? word0(&u) << (64 - i) | word1(&u) >> (i - 32) : word1(&u) << (32 - i); dval(&d2) = x; word0(&d2) -= 31*Exp_msk1; /* adjust exponent */ i -= (Bias + (P-1) - 1) + 1; denorm = 1; } #endif ds = (dval(&d2)-1.5)*0.289529654602168 + 0.1760912590558 + i*0.301029995663981; k = (int)ds; if (ds < 0. && ds != k) k--; /* want k = floor(ds) */ k_check = 1; if (k >= 0 && k <= Ten_pmax) { if (dval(&u) < tens[k]) k--; k_check = 0; } j = bbits - i - 1; if (j >= 0) { b2 = 0; s2 = j; } else { b2 = -j; s2 = 0; } if (k >= 0) { b5 = 0; s5 = k; s2 += k; } else { b2 -= k; b5 = -k; s5 = 0; } if (mode < 0 || mode > 9) mode = 0; #ifndef SET_INEXACT #ifdef Check_FLT_ROUNDS try_quick = Rounding == 1; #else try_quick = 1; #endif #endif /*SET_INEXACT*/ if (mode > 5) { mode -= 4; try_quick = 0; } leftright = 1; ilim = ilim1 = -1; /* Values for cases 0 and 1; done here to */ /* silence erroneous "gcc -Wall" warning. */ switch(mode) { case 0: case 1: i = 18; ndigits = 0; break; case 2: leftright = 0; /* no break */ JQ_FALLTHROUGH; case 4: if (ndigits <= 0) ndigits = 1; ilim = ilim1 = i = ndigits; break; case 3: leftright = 0; /* no break */ JQ_FALLTHROUGH; case 5: i = ndigits + k + 1; ilim = i; ilim1 = i - 1; if (i <= 0) i = 1; } s = s0 = rv_alloc(C, i); #ifdef Honor_FLT_ROUNDS if (mode > 1 && Rounding != 1) leftright = 0; #endif if (ilim >= 0 && ilim <= Quick_max && try_quick) { /* Try to get by with floating-point arithmetic. */ i = 0; dval(&d2) = dval(&u); k0 = k; ilim0 = ilim; ieps = 2; /* conservative */ if (k > 0) { ds = tens[k&0xf]; j = k >> 4; if (j & Bletch) { /* prevent overflows */ j &= Bletch - 1; dval(&u) /= bigtens[n_bigtens-1]; ieps++; } for(; j; j >>= 1, i++) if (j & 1) { ieps++; ds *= bigtens[i]; } dval(&u) /= ds; } else if ((j1 = -k)) { dval(&u) *= tens[j1 & 0xf]; for(j = j1 >> 4; j; j >>= 1, i++) if (j & 1) { ieps++; dval(&u) *= bigtens[i]; } } if (k_check && dval(&u) < 1. && ilim > 0) { if (ilim1 <= 0) goto fast_failed; ilim = ilim1; k--; dval(&u) *= 10.; ieps++; } dval(&eps) = ieps*dval(&u) + 7.; word0(&eps) -= (P-1)*Exp_msk1; if (ilim == 0) { S = mhi = 0; dval(&u) -= 5.; if (dval(&u) > dval(&eps)) goto one_digit; if (dval(&u) < -dval(&eps)) goto no_digits; goto fast_failed; } #ifndef No_leftright if (leftright) { /* Use Steele & White method of only * generating digits needed. */ dval(&eps) = 0.5/tens[ilim-1] - dval(&eps); #ifdef IEEE_Arith if (k0 < 0 && j1 >= 307) { eps1.d = 1.01e256; /* 1.01 allows roundoff in the next few lines */ word0(&eps1) -= Exp_msk1 * (Bias+P-1); dval(&eps1) *= tens[j1 & 0xf]; for(i = 0, j = (j1-256) >> 4; j; j >>= 1, i++) if (j & 1) dval(&eps1) *= bigtens[i]; if (eps.d < eps1.d) eps.d = eps1.d; } #endif for(i = 0;;) { L = dval(&u); dval(&u) -= L; *s++ = '0' + (int)L; if (1. - dval(&u) < dval(&eps)) goto bump_up; if (dval(&u) < dval(&eps)) goto ret1; if (++i >= ilim) break; dval(&eps) *= 10.; dval(&u) *= 10.; } } else { #endif /* Generate ilim digits, then fix them up. */ dval(&eps) *= tens[ilim-1]; for(i = 1;; i++, dval(&u) *= 10.) { L = (Long)(dval(&u)); if (!(dval(&u) -= L)) ilim = i; *s++ = '0' + (int)L; if (i == ilim) { if (dval(&u) > 0.5 + dval(&eps)) goto bump_up; else if (dval(&u) < 0.5 - dval(&eps)) { while(*--s == '0'); s++; goto ret1; } break; } } #ifndef No_leftright } #endif fast_failed: s = s0; dval(&u) = dval(&d2); k = k0; ilim = ilim0; } /* Do we have a "small" integer? */ if (be >= 0 && k <= Int_max) { /* Yes. */ ds = tens[k]; if (ndigits < 0 && ilim <= 0) { S = mhi = 0; if (ilim < 0 || dval(&u) <= 5*ds) goto no_digits; goto one_digit; } for(i = 1;; i++, dval(&u) *= 10.) { L = (Long)(dval(&u) / ds); dval(&u) -= L*ds; #ifdef Check_FLT_ROUNDS /* If FLT_ROUNDS == 2, L will usually be high by 1 */ if (dval(&u) < 0) { L--; dval(&u) += ds; } #endif *s++ = '0' + (int)L; if (!dval(&u)) { #ifdef SET_INEXACT inexact = 0; #endif break; } if (i == ilim) { #ifdef Honor_FLT_ROUNDS if (mode > 1) switch(Rounding) { case 0: goto ret1; case 2: goto bump_up; } #endif dval(&u) += dval(&u); #ifdef ROUND_BIASED if (dval(&u) >= ds) #else if (dval(&u) > ds || (dval(&u) == ds && L & 1)) #endif { bump_up: while(*--s == '9') if (s == s0) { k++; *s = '0'; break; } ++*s++; } break; } } goto ret1; } m2 = b2; m5 = b5; mhi = mlo = 0; if (leftright) { i = #ifndef Sudden_Underflow denorm ? be + (Bias + (P-1) - 1 + 1) : #endif #ifdef IBM 1 + 4*P - 3 - bbits + ((bbits + be - 1) & 3); #else 1 + P - bbits; #endif b2 += i; s2 += i; mhi = i2b(C, 1); } if (m2 > 0 && s2 > 0) { i = m2 < s2 ? m2 : s2; b2 -= i; m2 -= i; s2 -= i; } if (b5 > 0) { if (leftright) { if (m5 > 0) { mhi = pow5mult(C, mhi, m5); b1 = mult(C, mhi, b); Bfree(C, b); b = b1; } if ((j = b5 - m5)) b = pow5mult(C, b, j); } else b = pow5mult(C, b, b5); } S = i2b(C, 1); if (s5 > 0) S = pow5mult(C, S, s5); /* Check for special case that d is a normalized power of 2. */ spec_case = 0; if ((mode < 2 || leftright) #ifdef Honor_FLT_ROUNDS && Rounding == 1 #endif ) { if (!word1(&u) && !(word0(&u) & Bndry_mask) #ifndef Sudden_Underflow && word0(&u) & (Exp_mask & ~Exp_msk1) #endif ) { /* The special case */ b2 += Log2P; s2 += Log2P; spec_case = 1; } } /* Arrange for convenient computation of quotients: * shift left if necessary so divisor has 4 leading 0 bits. * * Perhaps we should just compute leading 28 bits of S once * and for all and pass them and a shift to quorem, so it * can do shifts and ors to compute the numerator for q. */ i = dshift(C, S, s2); b2 += i; m2 += i; s2 += i; if (b2 > 0) b = lshift(C, b, b2); if (s2 > 0) S = lshift(C, S, s2); if (k_check) { if (cmp(C, b,S) < 0) { k--; b = multadd(C, b, 10, 0); /* we botched the k estimate */ if (leftright) mhi = multadd(C, mhi, 10, 0); ilim = ilim1; } } if (ilim <= 0 && (mode == 3 || mode == 5)) { if (ilim < 0 || cmp(C, b,S = multadd(C, S,5,0)) <= 0) { /* no digits, fcvt style */ no_digits: k = -1 - ndigits; goto ret; } one_digit: *s++ = '1'; k++; goto ret; } if (leftright) { if (m2 > 0) mhi = lshift(C, mhi, m2); /* Compute mlo -- check for special case * that d is a normalized power of 2. */ mlo = mhi; if (spec_case) { mhi = Balloc(C, mhi->k); Bcopy(mhi, mlo); mhi = lshift(C, mhi, Log2P); } for(i = 1;;i++) { dig = quorem(C, b,S) + '0'; /* Do we yet have the shortest decimal string * that will round to d? */ j = cmp(C, b, mlo); delta = diff(C, S, mhi); j1 = delta->sign ? 1 : cmp(C, b, delta); Bfree(C, delta); #ifndef ROUND_BIASED if (j1 == 0 && mode != 1 && !(word1(&u) & 1) #ifdef Honor_FLT_ROUNDS && Rounding >= 1 #endif ) { if (dig == '9') goto round_9_up; if (j > 0) dig++; #ifdef SET_INEXACT else if (!b->x[0] && b->wds <= 1) inexact = 0; #endif *s++ = dig; goto ret; } #endif if (j < 0 || (j == 0 && mode != 1 #ifndef ROUND_BIASED && !(word1(&u) & 1) #endif )) { if (!b->x[0] && b->wds <= 1) { #ifdef SET_INEXACT inexact = 0; #endif goto accept_dig; } #ifdef Honor_FLT_ROUNDS if (mode > 1) switch(Rounding) { case 0: goto accept_dig; case 2: goto keep_dig; } #endif /*Honor_FLT_ROUNDS*/ if (j1 > 0) { b = lshift(C, b, 1); j1 = cmp(C, b, S); #ifdef ROUND_BIASED if (j1 >= 0 /*)*/ #else if ((j1 > 0 || (j1 == 0 && dig & 1)) #endif && dig++ == '9') goto round_9_up; } accept_dig: *s++ = dig; goto ret; } if (j1 > 0) { #ifdef Honor_FLT_ROUNDS if (!Rounding) goto accept_dig; #endif if (dig == '9') { /* possible if i == 1 */ round_9_up: *s++ = '9'; goto roundoff; } *s++ = dig + 1; goto ret; } #ifdef Honor_FLT_ROUNDS keep_dig: #endif *s++ = dig; if (i == ilim) break; b = multadd(C, b, 10, 0); if (mlo == mhi) mlo = mhi = multadd(C, mhi, 10, 0); else { mlo = multadd(C, mlo, 10, 0); mhi = multadd(C, mhi, 10, 0); } } } else for(i = 1;; i++) { *s++ = dig = quorem(C, b,S) + '0'; if (!b->x[0] && b->wds <= 1) { #ifdef SET_INEXACT inexact = 0; #endif goto ret; } if (i >= ilim) break; b = multadd(C, b, 10, 0); } /* Round off last digit */ #ifdef Honor_FLT_ROUNDS switch(Rounding) { case 0: goto trimzeros; case 2: goto roundoff; } #endif b = lshift(C, b, 1); j = cmp(C, b, S); #ifdef ROUND_BIASED if (j >= 0) #else if (j > 0 || (j == 0 && dig & 1)) #endif { roundoff: while(*--s == '9') if (s == s0) { k++; *s++ = '1'; goto ret; } ++*s++; } else { #ifdef Honor_FLT_ROUNDS trimzeros: #endif while(*--s == '0'); s++; } ret: Bfree(C, S); if (mhi) { if (mlo && mlo != mhi) Bfree(C, mlo); Bfree(C, mhi); } ret1: #ifdef SET_INEXACT if (inexact) { if (!oldinexact) { word0(&u) = Exp_1 + (70 << Exp_shift); word1(&u) = 0; dval(&u) += 1.; } } else if (!oldinexact) clear_inexact(); #endif Bfree(C, b); *s = 0; *decpt = k + 1; if (rve) *rve = s; return s0; } #ifdef __cplusplus } #endif /**************************************************************** * * The author of this software is David M. Gay. * * Copyright (c) 1991, 1996 by Lucent Technologies. * * Permission to use, copy, modify, and distribute this software for any * purpose without fee is hereby granted, provided that this entire notice * is included in all copies of any software which is or includes a copy * or modification of this software and in all copies of the supporting * documentation for such software. * * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED * WARRANTY. IN PARTICULAR, NEITHER THE AUTHOR NOR LUCENT MAKES ANY * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE. * ***************************************************************/ /* g_fmt(buf,x) stores the closest decimal approximation to x in buf; * it suffices to declare buf * char buf[32]; */ char * jvp_dtoa_fmt(struct dtoa_context* C, register char *b, double x) { register int i, k; register char *s; int decpt, j, sign; char *b0, *s0, *se; b0 = b; #ifdef IGNORE_ZERO_SIGN if (!x) { *b++ = '0'; *b = 0; goto done; } #endif s = s0 = jvp_dtoa(C, x, 0, 0, &decpt, &sign, &se); if (sign) *b++ = '-'; if (decpt == 9999) /* Infinity or Nan */ { while((*b++ = *s++)); goto done0; } if (decpt <= -4 || decpt > se - s + 15) { *b++ = *s++; if (*s) { *b++ = '.'; while((*b = *s++)) b++; } *b++ = 'e'; /* sprintf(b, "%+.2d", decpt - 1); */ if (--decpt < 0) { *b++ = '-'; decpt = -decpt; } else *b++ = '+'; for(j = 2, k = 10; 10*k <= decpt; j++, k *= 10); for(;;) { i = decpt / k; *b++ = i + '0'; if (--j <= 0) break; decpt -= i*k; decpt *= 10; } *b = 0; } else if (decpt <= 0) { *b++ = '0'; *b++ = '.'; for(; decpt < 0; decpt++) *b++ = '0'; while((*b++ = *s++)); } else { while((*b = *s++)) { b++; if (--decpt == 0 && *s) *b++ = '.'; } for(; decpt > 0; decpt--) *b++ = '0'; *b = 0; } done0: jvp_freedtoa(C, s0); goto done; done: return b0; } ================================================ FILE: src/jv_dtoa.h ================================================ #ifndef JV_DTOA_H #define JV_DTOA_H #define Kmax 7 struct Bigint; struct dtoa_context { struct Bigint *freelist[Kmax+1]; struct Bigint *p5s; }; void jvp_dtoa_context_init(struct dtoa_context* ctx); void jvp_dtoa_context_free(struct dtoa_context* ctx); 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 char* jvp_dtoa_fmt(struct dtoa_context* C, register char *b, double x); #endif ================================================ FILE: src/jv_dtoa_tsd.c ================================================ #include #include #include "jv_thread.h" #include "jv_dtoa_tsd.h" #include "jv_dtoa.h" #include "jv_alloc.h" static pthread_once_t dtoa_ctx_once = PTHREAD_ONCE_INIT; static pthread_key_t dtoa_ctx_key; static void tsd_dtoa_ctx_dtor(void *ctx) { if (ctx) { jvp_dtoa_context_free((struct dtoa_context *)ctx); jv_mem_free(ctx); } } #ifndef WIN32 static #endif void jv_tsd_dtoa_ctx_fini(void) { struct dtoa_context *ctx = pthread_getspecific(dtoa_ctx_key); tsd_dtoa_ctx_dtor(ctx); pthread_setspecific(dtoa_ctx_key, NULL); } #ifndef WIN32 static #endif void jv_tsd_dtoa_ctx_init(void) { if (pthread_key_create(&dtoa_ctx_key, tsd_dtoa_ctx_dtor) != 0) { fprintf(stderr, "error: cannot create thread specific key"); abort(); } atexit(jv_tsd_dtoa_ctx_fini); } inline struct dtoa_context *tsd_dtoa_context_get(void) { pthread_once(&dtoa_ctx_once, jv_tsd_dtoa_ctx_init); // cannot fail struct dtoa_context *ctx = (struct dtoa_context*)pthread_getspecific(dtoa_ctx_key); if (!ctx) { ctx = jv_mem_alloc(sizeof(struct dtoa_context)); jvp_dtoa_context_init(ctx); if (pthread_setspecific(dtoa_ctx_key, ctx) != 0) { jv_mem_free(ctx); fprintf(stderr, "error: cannot set thread specific data"); abort(); } } return ctx; } ================================================ FILE: src/jv_dtoa_tsd.h ================================================ #ifndef JV_DTOA_TSD_H #define JV_DTOA_TSD_H struct dtoa_context *tsd_dtoa_context_get(void); #endif ================================================ FILE: src/jv_file.c ================================================ #include #include #include #include #include #include #include #include "jv.h" #include "jv_unicode.h" jv jv_load_file(const char* filename, int raw) { struct stat sb; int fd = open(filename, O_RDONLY); if (fd == -1) { return jv_invalid_with_msg(jv_string_fmt("Could not open %s: %s", filename, strerror(errno))); } if (fstat(fd, &sb) == -1 || S_ISDIR(sb.st_mode)) { close(fd); return jv_invalid_with_msg(jv_string_fmt("Could not open %s: %s", filename, "It's a directory")); } FILE* file = fdopen(fd, "r"); struct jv_parser* parser = NULL; jv data; if (!file) { close(fd); 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); } // To avoid mangling UTF-8 multi-byte sequences that cross the end of our read // buffer, we need to be able to read the remainder of a sequence and add that // before appending. char buf[4096 + 4]; while (!feof(file) && !ferror(file)) { size_t n = fread(buf, 1, sizeof(buf) - 4, file); if (n == 0) continue; char *end = buf + n; int len = 0; if (jvp_utf8_backtrack(end - 1, buf, &len) && len > 0 && !feof(file) && !ferror(file)) { n += fread(end, 1, len, file); } if (raw) { data = jv_string_append_buf(data, buf, 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); if (jv_invalid_has_msg(jv_copy(value))) { jv_free(data); data = value; break; } jv_free(value); } } if (!raw) jv_parser_free(parser); int badread = ferror(file); if (fclose(file) != 0 || badread) { jv_free(data); return jv_invalid_with_msg(jv_string_fmt("Error reading from %s", filename)); } return data; } ================================================ FILE: src/jv_parse.c ================================================ #include #include #include #include #include "jv.h" #include "jv_dtoa.h" #include "jv_unicode.h" #include "jv_alloc.h" #include "jv_dtoa.h" typedef const char* presult; #ifndef MAX_PARSING_DEPTH #define MAX_PARSING_DEPTH (10000) #endif #define TRY(x) do {presult msg__ = (x); if (msg__) return msg__; } while(0) #ifdef __GNUC__ #define pfunc __attribute__((warn_unused_result)) presult #else #define pfunc presult #endif enum last_seen { JV_LAST_NONE = 0, JV_LAST_OPEN_ARRAY = '[', JV_LAST_OPEN_OBJECT = '{', JV_LAST_COLON = ':', JV_LAST_COMMA = ',', JV_LAST_VALUE = 'V', }; struct jv_parser { const char* curr_buf; int curr_buf_length; int curr_buf_pos; int curr_buf_is_partial; int eof; unsigned bom_strip_position; int flags; jv* stack; // parser int stackpos; // parser int stacklen; // both (optimization; it's really pathlen for streaming) jv path; // streamer enum last_seen last_seen; // streamer jv output; // streamer jv next; // both char* tokenbuf; int tokenpos; int tokenlen; int line, column; struct dtoa_context dtoa; enum { JV_PARSER_NORMAL, JV_PARSER_STRING, JV_PARSER_STRING_ESCAPE, JV_PARSER_WAITING_FOR_RS // parse error, waiting for RS } st; unsigned int last_ch_was_ws:1; }; static void parser_init(struct jv_parser* p, int flags) { p->flags = flags; if ((p->flags & JV_PARSE_STREAMING)) { p->path = jv_array(); } else { p->path = jv_invalid(); p->flags &= ~(JV_PARSE_STREAM_ERRORS); } p->stack = 0; p->stacklen = p->stackpos = 0; p->last_seen = JV_LAST_NONE; p->output = jv_invalid(); p->next = jv_invalid(); p->tokenlen = 256; p->tokenbuf = jv_mem_alloc(p->tokenlen); p->tokenpos = 0; if ((p->flags & JV_PARSE_SEQ)) p->st = JV_PARSER_WAITING_FOR_RS; else p->st = JV_PARSER_NORMAL; p->eof = 0; p->curr_buf = 0; p->curr_buf_length = p->curr_buf_pos = p->curr_buf_is_partial = 0; p->bom_strip_position = 0; p->last_ch_was_ws = 0; p->line = 1; p->column = 0; jvp_dtoa_context_init(&p->dtoa); } static void parser_reset(struct jv_parser* p) { if ((p->flags & JV_PARSE_STREAMING)) { jv_free(p->path); p->path = jv_array(); p->stacklen = 0; } p->last_seen = JV_LAST_NONE; jv_free(p->output); p->output = jv_invalid(); jv_free(p->next); p->next = jv_invalid(); for (int i=0; istackpos; i++) jv_free(p->stack[i]); p->stackpos = 0; p->tokenpos = 0; p->st = JV_PARSER_NORMAL; } static void parser_free(struct jv_parser* p) { parser_reset(p); jv_free(p->path); jv_free(p->output); jv_mem_free(p->stack); jv_mem_free(p->tokenbuf); jvp_dtoa_context_free(&p->dtoa); } static pfunc value(struct jv_parser* p, jv val) { if ((p->flags & JV_PARSE_STREAMING)) { if (jv_is_valid(p->next) || p->last_seen == JV_LAST_VALUE) { jv_free(val); return "Expected separator between values"; } if (p->stacklen > 0) p->last_seen = JV_LAST_VALUE; else p->last_seen = JV_LAST_NONE; } else { if (jv_is_valid(p->next)) { jv_free(val); return "Expected separator between values"; } } jv_free(p->next); p->next = val; return 0; } static void push(struct jv_parser* p, jv v) { assert(p->stackpos <= p->stacklen); if (p->stackpos == p->stacklen) { p->stacklen = p->stacklen * 2 + 10; p->stack = jv_mem_realloc(p->stack, p->stacklen * sizeof(jv)); } assert(p->stackpos < p->stacklen); p->stack[p->stackpos++] = v; } static pfunc parse_token(struct jv_parser* p, char ch) { switch (ch) { case '[': if (p->stackpos >= MAX_PARSING_DEPTH) return "Exceeds depth limit for parsing"; if (jv_is_valid(p->next)) return "Expected separator between values"; push(p, jv_array()); break; case '{': if (p->stackpos >= MAX_PARSING_DEPTH) return "Exceeds depth limit for parsing"; if (jv_is_valid(p->next)) return "Expected separator between values"; push(p, jv_object()); break; case ':': if (!jv_is_valid(p->next)) return "Expected string key before ':'"; if (p->stackpos == 0 || jv_get_kind(p->stack[p->stackpos-1]) != JV_KIND_OBJECT) return "':' not as part of an object"; if (jv_get_kind(p->next) != JV_KIND_STRING) return "Object keys must be strings"; push(p, p->next); p->next = jv_invalid(); break; case ',': if (!jv_is_valid(p->next)) return "Expected value before ','"; if (p->stackpos == 0) return "',' not as part of an object or array"; if (jv_get_kind(p->stack[p->stackpos-1]) == JV_KIND_ARRAY) { p->stack[p->stackpos-1] = jv_array_append(p->stack[p->stackpos-1], p->next); p->next = jv_invalid(); } else if (jv_get_kind(p->stack[p->stackpos-1]) == JV_KIND_STRING) { assert(p->stackpos > 1 && jv_get_kind(p->stack[p->stackpos-2]) == JV_KIND_OBJECT); p->stack[p->stackpos-2] = jv_object_set(p->stack[p->stackpos-2], p->stack[p->stackpos-1], p->next); p->stackpos--; p->next = jv_invalid(); } else { // this case hits on input like {"a", "b"} return "Objects must consist of key:value pairs"; } break; case ']': if (p->stackpos == 0 || jv_get_kind(p->stack[p->stackpos-1]) != JV_KIND_ARRAY) return "Unmatched ']'"; if (jv_is_valid(p->next)) { p->stack[p->stackpos-1] = jv_array_append(p->stack[p->stackpos-1], p->next); p->next = jv_invalid(); } else { if (jv_array_length(jv_copy(p->stack[p->stackpos-1])) != 0) { // this case hits on input like [1,2,3,] return "Expected another array element"; } } jv_free(p->next); p->next = p->stack[--p->stackpos]; break; case '}': if (p->stackpos == 0) return "Unmatched '}'"; if (jv_is_valid(p->next)) { if (jv_get_kind(p->stack[p->stackpos-1]) != JV_KIND_STRING) return "Objects must consist of key:value pairs"; assert(p->stackpos > 1 && jv_get_kind(p->stack[p->stackpos-2]) == JV_KIND_OBJECT); p->stack[p->stackpos-2] = jv_object_set(p->stack[p->stackpos-2], p->stack[p->stackpos-1], p->next); p->stackpos--; p->next = jv_invalid(); } else { if (jv_get_kind(p->stack[p->stackpos-1]) != JV_KIND_OBJECT) return "Unmatched '}'"; if (jv_object_length(jv_copy(p->stack[p->stackpos-1])) != 0) return "Expected another key-value pair"; } jv_free(p->next); p->next = p->stack[--p->stackpos]; break; } return 0; } static pfunc stream_token(struct jv_parser* p, char ch) { jv_kind k; jv last; switch (ch) { case '[': if (jv_is_valid(p->next)) return "Expected a separator between values"; if (p->last_seen == JV_LAST_OPEN_OBJECT) // Looks like {["foo"]} return "Expected string key after '{', not '['"; if (p->last_seen == JV_LAST_COMMA) { last = jv_array_get(jv_copy(p->path), p->stacklen - 1); k = jv_get_kind(last); jv_free(last); if (k != JV_KIND_NUMBER) // Looks like {"x":"y",["foo"]} return "Expected string key after ',' in object, not '['"; } p->path = jv_array_append(p->path, jv_number(0)); // push p->last_seen = JV_LAST_OPEN_ARRAY; p->stacklen++; break; case '{': if (p->last_seen == JV_LAST_VALUE) return "Expected a separator between values"; if (p->last_seen == JV_LAST_OPEN_OBJECT) // Looks like {{"foo":"bar"}} return "Expected string key after '{', not '{'"; if (p->last_seen == JV_LAST_COMMA) { last = jv_array_get(jv_copy(p->path), p->stacklen - 1); k = jv_get_kind(last); jv_free(last); if (k != JV_KIND_NUMBER) // Looks like {"x":"y",{"foo":"bar"}} return "Expected string key after ',' in object, not '{'"; } // Push object key: null, since we don't know it yet p->path = jv_array_append(p->path, jv_null()); // push p->last_seen = JV_LAST_OPEN_OBJECT; p->stacklen++; break; case ':': last = jv_invalid(); if (p->stacklen == 0 || jv_get_kind(last = jv_array_get(jv_copy(p->path), p->stacklen - 1)) == JV_KIND_NUMBER) { jv_free(last); return "':' not as part of an object"; } jv_free(last); if (!jv_is_valid(p->next) || p->last_seen == JV_LAST_NONE) return "Expected string key before ':'"; if (jv_get_kind(p->next) != JV_KIND_STRING) return "Object keys must be strings"; if (p->last_seen != JV_LAST_VALUE) return "':' should follow a key"; p->last_seen = JV_LAST_COLON; p->path = jv_array_set(p->path, p->stacklen - 1, p->next); p->next = jv_invalid(); break; case ',': if (p->last_seen != JV_LAST_VALUE) return "Expected value before ','"; if (p->stacklen == 0) return "',' not as part of an object or array"; last = jv_array_get(jv_copy(p->path), p->stacklen - 1); k = jv_get_kind(last); if (k == JV_KIND_NUMBER) { int idx = jv_number_value(last); if (jv_is_valid(p->next)) { p->output = JV_ARRAY(jv_copy(p->path), p->next); p->next = jv_invalid(); } p->path = jv_array_set(p->path, p->stacklen - 1, jv_number(idx + 1)); p->last_seen = JV_LAST_COMMA; } else if (k == JV_KIND_STRING) { if (jv_is_valid(p->next)) { p->output = JV_ARRAY(jv_copy(p->path), p->next); p->next = jv_invalid(); } p->path = jv_array_set(p->path, p->stacklen - 1, jv_null()); // ready for another key:value pair p->last_seen = JV_LAST_COMMA; } else { assert(k == JV_KIND_NULL); // this case hits on input like {,} // make sure to handle input like {"a", "b"} and {"a":, ...} jv_free(last); return "Objects must consist of key:value pairs"; } jv_free(last); break; case ']': if (p->stacklen == 0) return "Unmatched ']' at the top-level"; if (p->last_seen == JV_LAST_COMMA) return "Expected another array element"; if (p->last_seen == JV_LAST_OPEN_ARRAY) assert(!jv_is_valid(p->next)); last = jv_array_get(jv_copy(p->path), p->stacklen - 1); k = jv_get_kind(last); jv_free(last); if (k != JV_KIND_NUMBER) return "Unmatched ']' in the middle of an object"; if (jv_is_valid(p->next)) { p->output = JV_ARRAY(jv_copy(p->path), p->next, jv_true()); p->next = jv_invalid(); } else if (p->last_seen != JV_LAST_OPEN_ARRAY) { p->output = JV_ARRAY(jv_copy(p->path)); } p->path = jv_array_slice(p->path, 0, --(p->stacklen)); // pop //assert(!jv_is_valid(p->next)); jv_free(p->next); p->next = jv_invalid(); if (p->last_seen == JV_LAST_OPEN_ARRAY) p->output = JV_ARRAY(jv_copy(p->path), jv_array()); // Empty arrays are leaves if (p->stacklen == 0) p->last_seen = JV_LAST_NONE; else p->last_seen = JV_LAST_VALUE; break; case '}': if (p->stacklen == 0) return "Unmatched '}' at the top-level"; if (p->last_seen == JV_LAST_COMMA) return "Expected another key:value pair"; if (p->last_seen == JV_LAST_OPEN_OBJECT) assert(!jv_is_valid(p->next)); last = jv_array_get(jv_copy(p->path), p->stacklen - 1); k = jv_get_kind(last); jv_free(last); if (k == JV_KIND_NUMBER) return "Unmatched '}' in the middle of an array"; if (jv_is_valid(p->next)) { if (k != JV_KIND_STRING) return "Objects must consist of key:value pairs"; p->output = JV_ARRAY(jv_copy(p->path), p->next, jv_true()); p->next = jv_invalid(); } else { // Perhaps {"a":[]} if (p->last_seen == JV_LAST_COLON) // Looks like {"a":} return "Missing value in key:value pair"; if (p->last_seen == JV_LAST_COMMA) // Looks like {"a":0,} return "Expected another key-value pair"; if (p->last_seen == JV_LAST_OPEN_ARRAY) return "Unmatched '}' in the middle of an array"; if (p->last_seen != JV_LAST_VALUE && p->last_seen != JV_LAST_OPEN_OBJECT) return "Unmatched '}'"; if (p->last_seen != JV_LAST_OPEN_OBJECT) p->output = JV_ARRAY(jv_copy(p->path)); } p->path = jv_array_slice(p->path, 0, --(p->stacklen)); // pop jv_free(p->next); p->next = jv_invalid(); if (p->last_seen == JV_LAST_OPEN_OBJECT) p->output = JV_ARRAY(jv_copy(p->path), jv_object()); // Empty arrays are leaves if (p->stacklen == 0) p->last_seen = JV_LAST_NONE; else p->last_seen = JV_LAST_VALUE; break; } return 0; } static void tokenadd(struct jv_parser* p, char c) { assert(p->tokenpos <= p->tokenlen); if (p->tokenpos >= (p->tokenlen - 1)) { p->tokenlen = p->tokenlen*2 + 256; p->tokenbuf = jv_mem_realloc(p->tokenbuf, p->tokenlen); } assert(p->tokenpos < p->tokenlen); p->tokenbuf[p->tokenpos++] = c; } static int unhex4(char* hex) { int r = 0; for (int i=0; i<4; i++) { char c = *hex++; int n; if ('0' <= c && c <= '9') n = c - '0'; else if ('a' <= c && c <= 'f') n = c - 'a' + 10; else if ('A' <= c && c <= 'F') n = c - 'A' + 10; else return -1; r <<= 4; r |= n; } return r; } static pfunc found_string(struct jv_parser* p) { char* in = p->tokenbuf; char* out = p->tokenbuf; char* end = p->tokenbuf + p->tokenpos; while (in < end) { char c = *in++; if (c == '\\') { if (in >= end) return "Expected escape character at end of string"; c = *in++; switch (c) { case '\\': case '"': case '/': *out++ = c; break; case 'b': *out++ = '\b'; break; case 'f': *out++ = '\f'; break; case 't': *out++ = '\t'; break; case 'n': *out++ = '\n'; break; case 'r': *out++ = '\r'; break; case 'u': /* ahh, the complicated case */ if (in + 4 > end) return "Invalid \\uXXXX escape"; int hexvalue = unhex4(in); if (hexvalue < 0) return "Invalid characters in \\uXXXX escape"; unsigned long codepoint = (unsigned long)hexvalue; in += 4; if (0xD800 <= codepoint && codepoint <= 0xDBFF) { /* who thought UTF-16 surrogate pairs were a good idea? */ if (in + 6 > end || in[0] != '\\' || in[1] != 'u') return "Invalid \\uXXXX\\uXXXX surrogate pair escape"; unsigned long surrogate = unhex4(in+2); if (!(0xDC00 <= surrogate && surrogate <= 0xDFFF)) return "Invalid \\uXXXX\\uXXXX surrogate pair escape"; in += 6; codepoint = 0x10000 + (((codepoint - 0xD800) << 10) |(surrogate - 0xDC00)); } if (codepoint > 0x10FFFF) codepoint = 0xFFFD; // U+FFFD REPLACEMENT CHARACTER out += jvp_utf8_encode(codepoint, out); break; default: return "Invalid escape"; } } else { if (!(c & ~0x1F)) return "Invalid string: control characters from U+0000 through U+001F must be escaped"; *out++ = c; } } TRY(value(p, jv_string_sized(p->tokenbuf, out - p->tokenbuf))); p->tokenpos = 0; return 0; } static pfunc check_literal(struct jv_parser* p) { if (p->tokenpos == 0) return 0; const char* pattern = 0; int plen; jv v; switch (p->tokenbuf[0]) { case 't': pattern = "true"; plen = 4; v = jv_true(); break; case 'f': pattern = "false"; plen = 5; v = jv_false(); break; case '\'': return "Invalid string literal; expected \", but got '"; case 'n': // if it starts with 'n', it could be a literal "nan" if (p->tokenpos > 1 && p->tokenbuf[1] == 'u') { pattern = "null"; plen = 4; v = jv_null(); } } if (pattern) { if (p->tokenpos != plen) return "Invalid literal"; for (int i=0; itokenbuf[i] != pattern[i]) return "Invalid literal"; TRY(value(p, v)); } else { // FIXME: better parser p->tokenbuf[p->tokenpos] = 0; #ifdef USE_DECNUM jv number = jv_number_with_literal(p->tokenbuf); if (jv_get_kind(number) == JV_KIND_INVALID) { return "Invalid numeric literal"; } TRY(value(p, number)); #else char *end = 0; double d = jvp_strtod(&p->dtoa, p->tokenbuf, &end); if (end == 0 || *end != 0) { return "Invalid numeric literal"; } TRY(value(p, jv_number(d))); #endif } p->tokenpos = 0; return 0; } typedef enum { LITERAL, WHITESPACE, STRUCTURE, QUOTE, INVALID } chclass; static chclass classify(char c) { switch (c) { case ' ': case '\t': case '\r': case '\n': return WHITESPACE; case '"': return QUOTE; case '[': case ',': case ']': case '{': case ':': case '}': return STRUCTURE; default: return LITERAL; } } static const presult OK = "output produced"; static int parse_check_done(struct jv_parser* p, jv* out) { if (p->stackpos == 0 && jv_is_valid(p->next)) { *out = p->next; p->next = jv_invalid(); return 1; } else { return 0; } } static int stream_check_done(struct jv_parser* p, jv* out) { if (p->stacklen == 0 && jv_is_valid(p->next)) { *out = JV_ARRAY(jv_copy(p->path),p->next); p->next = jv_invalid(); return 1; } else if (jv_is_valid(p->output)) { if (jv_array_length(jv_copy(p->output)) > 2) { // At end of an array or object, necessitating one more output by // which to indicate this *out = jv_array_slice(jv_copy(p->output), 0, 2); p->output = jv_array_slice(p->output, 0, 1); // arrange one more output } else { // No further processing needed *out = p->output; p->output = jv_invalid(); } return 1; } else { return 0; } } static int seq_check_truncation(struct jv_parser* p) { return (!p->last_ch_was_ws && (p->stackpos > 0 || p->tokenpos > 0 || jv_get_kind(p->next) == JV_KIND_NUMBER)); } static int stream_seq_check_truncation(struct jv_parser* p) { jv_kind k = jv_get_kind(p->next); return (p->stacklen > 0 || k == JV_KIND_NUMBER || k == JV_KIND_TRUE || k == JV_KIND_FALSE || k == JV_KIND_NULL); } static int parse_is_top_num(struct jv_parser* p) { return (p->stackpos == 0 && jv_get_kind(p->next) == JV_KIND_NUMBER); } static int stream_is_top_num(struct jv_parser* p) { return (p->stacklen == 0 && jv_get_kind(p->next) == JV_KIND_NUMBER); } #define check_done(p, o) \ (((p)->flags & JV_PARSE_STREAMING) ? stream_check_done((p), (o)) : parse_check_done((p), (o))) #define token(p, ch) \ (((p)->flags & JV_PARSE_STREAMING) ? stream_token((p), (ch)) : parse_token((p), (ch))) #define check_truncation(p) \ (((p)->flags & JV_PARSE_STREAMING) ? stream_seq_check_truncation((p)) : seq_check_truncation((p))) #define is_top_num(p) \ (((p)->flags & JV_PARSE_STREAMING) ? stream_is_top_num((p)) : parse_is_top_num((p))) static pfunc scan(struct jv_parser* p, char ch, jv* out) { p->column++; if (ch == '\n') { p->line++; p->column = 0; } if ((p->flags & JV_PARSE_SEQ) && ch == '\036' /* ASCII RS; see draft-ietf-json-sequence-07 */) { if (check_truncation(p)) { if (check_literal(p) == 0 && is_top_num(p)) return "Potentially truncated top-level numeric value"; return "Truncated value"; } TRY(check_literal(p)); if (p->st == JV_PARSER_NORMAL && check_done(p, out)) return OK; // shouldn't happen? assert(!jv_is_valid(*out)); parser_reset(p); jv_free(*out); *out = jv_invalid(); return OK; } presult answer = 0; p->last_ch_was_ws = 0; if (p->st == JV_PARSER_NORMAL) { chclass cls = classify(ch); if (cls == WHITESPACE) p->last_ch_was_ws = 1; if (cls != LITERAL) { TRY(check_literal(p)); if (check_done(p, out)) answer = OK; } switch (cls) { case LITERAL: tokenadd(p, ch); break; case WHITESPACE: break; case QUOTE: p->st = JV_PARSER_STRING; break; case STRUCTURE: TRY(token(p, ch)); break; case INVALID: return "Invalid character"; } if (check_done(p, out)) answer = OK; } else { if (ch == '"' && p->st == JV_PARSER_STRING) { TRY(found_string(p)); p->st = JV_PARSER_NORMAL; if (check_done(p, out)) answer = OK; } else { tokenadd(p, ch); if (ch == '\\' && p->st == JV_PARSER_STRING) { p->st = JV_PARSER_STRING_ESCAPE; } else { p->st = JV_PARSER_STRING; } } } return answer; } struct jv_parser* jv_parser_new(int flags) { struct jv_parser* p = jv_mem_alloc(sizeof(struct jv_parser)); parser_init(p, flags); p->flags = flags; 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}; int jv_parser_remaining(struct jv_parser* p) { if (p->curr_buf == 0) return 0; return (p->curr_buf_length - p->curr_buf_pos); } void jv_parser_set_buf(struct jv_parser* p, const char* buf, int length, int is_partial) { assert((p->curr_buf == 0 || p->curr_buf_pos == p->curr_buf_length) && "previous buffer not exhausted"); while (length > 0 && p->bom_strip_position < sizeof(UTF8_BOM)) { if ((unsigned char)*buf == UTF8_BOM[p->bom_strip_position]) { // matched a BOM character buf++; length--; p->bom_strip_position++; } else { if (p->bom_strip_position == 0) { // no BOM in this document p->bom_strip_position = sizeof(UTF8_BOM); } else { // malformed BOM (prefix present, rest missing) p->bom_strip_position = 0xff; } } } p->curr_buf = buf; p->curr_buf_length = length; p->curr_buf_pos = 0; p->curr_buf_is_partial = is_partial; } static jv make_error(struct jv_parser*, const char *, ...) JV_PRINTF_LIKE(2, 3); static jv make_error(struct jv_parser* p, const char *fmt, ...) { va_list ap; va_start(ap, fmt); jv e = jv_string_vfmt(fmt, ap); va_end(ap); if ((p->flags & JV_PARSE_STREAM_ERRORS)) return JV_ARRAY(e, jv_copy(p->path)); return jv_invalid_with_msg(e); } jv jv_parser_next(struct jv_parser* p) { if (p->eof) return jv_invalid(); if (!p->curr_buf) return jv_invalid(); // Need a buffer if (p->bom_strip_position == 0xff) { if (!(p->flags & JV_PARSE_SEQ)) return jv_invalid_with_msg(jv_string("Malformed BOM")); p->st =JV_PARSER_WAITING_FOR_RS; parser_reset(p); } jv value = jv_invalid(); if ((p->flags & JV_PARSE_STREAMING) && stream_check_done(p, &value)) return value; char ch; presult msg = 0; while (!msg && p->curr_buf_pos < p->curr_buf_length) { ch = p->curr_buf[p->curr_buf_pos++]; if (p->st == JV_PARSER_WAITING_FOR_RS) { if (ch == '\n') { p->line++; p->column = 0; } else { p->column++; } if (ch == '\036') p->st = JV_PARSER_NORMAL; continue; // need to resync, wait for RS } msg = scan(p, ch, &value); } if (msg == OK) { return value; } else if (msg) { jv_free(value); if (ch != '\036' && (p->flags & JV_PARSE_SEQ)) { // Skip to the next RS p->st = JV_PARSER_WAITING_FOR_RS; value = make_error(p, "%s at line %d, column %d (need RS to resync)", msg, p->line, p->column); parser_reset(p); return value; } value = make_error(p, "%s at line %d, column %d", msg, p->line, p->column); parser_reset(p); if (!(p->flags & JV_PARSE_SEQ)) { // We're not parsing a JSON text sequence; throw this buffer away. // XXX We should fail permanently here. p->curr_buf = 0; p->curr_buf_pos = 0; } // Else ch must be RS; don't clear buf so we can start parsing again after this ch return value; } else if (p->curr_buf_is_partial) { assert(p->curr_buf_pos == p->curr_buf_length); // need another buffer return jv_invalid(); } else { // at EOF p->eof = 1; assert(p->curr_buf_pos == p->curr_buf_length); jv_free(value); if (p->st == JV_PARSER_WAITING_FOR_RS) return make_error(p, "Unfinished abandoned text at EOF at line %d, column %d", p->line, p->column); if (p->st != JV_PARSER_NORMAL) { value = make_error(p, "Unfinished string at EOF at line %d, column %d", p->line, p->column); parser_reset(p); p->st = JV_PARSER_WAITING_FOR_RS; return value; } if ((msg = check_literal(p))) { value = make_error(p, "%s at EOF at line %d, column %d", msg, p->line, p->column); parser_reset(p); p->st = JV_PARSER_WAITING_FOR_RS; return value; } if (((p->flags & JV_PARSE_STREAMING) && p->stacklen != 0) || (!(p->flags & JV_PARSE_STREAMING) && p->stackpos != 0)) { value = make_error(p, "Unfinished JSON term at EOF at line %d, column %d", p->line, p->column); parser_reset(p); p->st = JV_PARSER_WAITING_FOR_RS; return value; } // p->next is either invalid (nothing here, but no syntax error) // or valid (this is the value). either way it's the thing to return if ((p->flags & JV_PARSE_STREAMING) && jv_is_valid(p->next)) { value = JV_ARRAY(jv_copy(p->path), p->next); // except in streaming mode we've got to make it [path,value] } else { value = p->next; } p->next = jv_invalid(); if ((p->flags & JV_PARSE_SEQ) && !p->last_ch_was_ws && jv_get_kind(value) == JV_KIND_NUMBER) { jv_free(value); return make_error(p, "Potentially truncated top-level numeric value at EOF at line %d, column %d", p->line, p->column); } return value; } } jv jv_parse_sized_custom_flags(const char* string, int length, int flags) { struct jv_parser parser; parser_init(&parser, flags); jv_parser_set_buf(&parser, string, length, 0); jv value = jv_parser_next(&parser); if (jv_is_valid(value)) { jv next = jv_parser_next(&parser); if (jv_is_valid(next)) { // multiple JSON values, we only wanted one jv_free(value); jv_free(next); value = jv_invalid_with_msg(jv_string("Unexpected extra JSON values")); } else if (jv_invalid_has_msg(jv_copy(next))) { // parser error after the first JSON value jv_free(value); value = next; } else { // a single valid JSON value jv_free(next); } } else if (jv_invalid_has_msg(jv_copy(value))) { // parse error, we'll return it } else { // no value at all jv_free(value); value = jv_invalid_with_msg(jv_string("Expected JSON value")); } parser_free(&parser); if (!jv_is_valid(value) && jv_invalid_has_msg(jv_copy(value))) { jv msg = jv_invalid_get_msg(value); value = jv_invalid_with_msg(jv_string_fmt("%s (while parsing '%s')", jv_string_value(msg), string)); jv_free(msg); } return value; } jv jv_parse_sized(const char* string, int length) { return jv_parse_sized_custom_flags(string, length, 0); } jv jv_parse(const char* string) { return jv_parse_sized(string, strlen(string)); } jv jv_parse_custom_flags(const char* string, int flags) { return jv_parse_sized_custom_flags(string, strlen(string), flags); } ================================================ FILE: src/jv_print.c ================================================ #include #include #include #include #ifdef WIN32 #include #include #include #endif #include "jv.h" #include "jv_dtoa.h" #include "jv_dtoa_tsd.h" #include "jv_unicode.h" #include "jv_alloc.h" #include "jv_private.h" #include "util.h" #ifndef MAX_PRINT_DEPTH #define MAX_PRINT_DEPTH (10000) #endif #define ESC "\033" #define COL(c) (ESC "[" c "m") #define COLRESET (ESC "[0m") // Color table. See https://en.wikipedia.org/wiki/ANSI_escape_code#Colors // for how to choose these. The order is same as jv_kind definition, and // the last color is used for object keys. #define DEFAULT_COLORS \ {COL("0;90"), COL("0;39"), COL("0;39"), COL("0;39"),\ COL("0;32"), COL("1;39"), COL("1;39"), COL("1;34")}; static const char *const default_colors[] = DEFAULT_COLORS; static const char *colors[] = DEFAULT_COLORS; #define COLORS_LEN (sizeof(colors) / sizeof(colors[0])) #define FIELD_COLOR (colors[7]) static char *colors_buf = NULL; int jq_set_colors(const char *code_str) { if (code_str == NULL) return 1; // the start of each color code in the env var, and the byte after the end of the last one const char *codes[COLORS_LEN + 1]; size_t num_colors; // must be initialized before `goto default_colors`, used later to loop over every color size_t ci = 0; for (num_colors = 0;; num_colors++) { codes[num_colors] = code_str; code_str += strspn(code_str, "0123456789;"); if (code_str[0] == '\0' || num_colors + 1 >= COLORS_LEN) { break; } else if (code_str[0] != ':') { return 0; // invalid character } code_str++; } if (codes[num_colors] != code_str) { // count the last color and store its end (plus one byte for consistency with starts) // an empty last color would be ignored (for cases like "" and "0:") num_colors++; codes[num_colors] = code_str + 1; } else if (num_colors == 0) { if (colors_buf != NULL) { jv_mem_free(colors_buf); colors_buf = NULL; } goto default_colors; } colors_buf = jv_mem_realloc( colors_buf, // add ESC '[' 'm' to each string // '\0' is already included in difference of codes codes[num_colors] - codes[0] + 3 * num_colors ); char *cb = colors_buf; for (; ci < num_colors; ci++) { colors[ci] = cb; size_t len = codes[ci + 1] - 1 - codes[ci]; cb[0] = ESC[0]; cb[1] = '['; memcpy(cb + 2, codes[ci], len); cb[2 + len] = 'm'; cb[3 + len] = '\0'; cb += len + 4; } default_colors: for (; ci < COLORS_LEN; ci++) colors[ci] = default_colors[ci]; return 1; } static void put_buf(const char *s, int len, FILE *fout, jv *strout, int is_tty) { if (strout) { *strout = jv_string_append_buf(*strout, s, len); } else { #ifdef WIN32 /* See util.h */ if (is_tty) { wchar_t *ws; size_t wl; if (len == -1) len = strlen(s); wl = MultiByteToWideChar(CP_UTF8, 0, s, len, NULL, 0); ws = jv_mem_calloc(wl + 1, sizeof(*ws)); if (!ws) return; wl = MultiByteToWideChar(CP_UTF8, 0, s, len, ws, wl + 1); ws[wl] = 0; WriteConsoleW((HANDLE)_get_osfhandle(fileno(fout)), ws, wl, NULL, NULL); free(ws); } else fwrite(s, 1, len, fout); #else fwrite(s, 1, len, fout); #endif } } static void put_char(char c, FILE* fout, jv* strout, int T) { put_buf(&c, 1, fout, strout, T); } static void put_str(const char* s, FILE* fout, jv* strout, int T) { put_buf(s, strlen(s), fout, strout, T); } static void put_indent(int n, int flags, FILE* fout, jv* strout, int T) { if (flags & JV_PRINT_TAB) { while (n--) put_char('\t', fout, strout, T); } else { n *= ((flags & (JV_PRINT_SPACE0 | JV_PRINT_SPACE1 | JV_PRINT_SPACE2)) >> 8); while (n--) put_char(' ', fout, strout, T); } } static void jvp_dump_string(jv str, int ascii_only, FILE* F, jv* S, int T) { assert(jv_get_kind(str) == JV_KIND_STRING); const char* i = jv_string_value(str); const char* end = i + jv_string_length_bytes(jv_copy(str)); const char* cstart; int c = 0; char buf[32]; put_char('"', F, S, T); while ((i = jvp_utf8_next((cstart = i), end, &c))) { assert(c != -1); int unicode_escape = 0; if (0x20 <= c && c <= 0x7E) { // printable ASCII if (c == '"' || c == '\\') { put_char('\\', F, S, T); } put_char(c, F, S, T); } else if (c < 0x20 || c == 0x7F) { // ASCII control character switch (c) { case '\b': put_char('\\', F, S, T); put_char('b', F, S, T); break; case '\t': put_char('\\', F, S, T); put_char('t', F, S, T); break; case '\r': put_char('\\', F, S, T); put_char('r', F, S, T); break; case '\n': put_char('\\', F, S, T); put_char('n', F, S, T); break; case '\f': put_char('\\', F, S, T); put_char('f', F, S, T); break; default: unicode_escape = 1; break; } } else { if (ascii_only) { unicode_escape = 1; } else { put_buf(cstart, i - cstart, F, S, T); } } if (unicode_escape) { if (c <= 0xffff) { snprintf(buf, sizeof(buf), "\\u%04x", c); } else { c -= 0x10000; snprintf(buf, sizeof(buf), "\\u%04x\\u%04x", 0xD800 | ((c & 0xffc00) >> 10), 0xDC00 | (c & 0x003ff)); } put_str(buf, F, S, T); } } assert(c != -1); put_char('"', F, S, T); } static void put_refcnt(struct dtoa_context* C, int refcnt, FILE *F, jv* S, int T){ char buf[JVP_DTOA_FMT_MAX_LEN]; put_char(' ', F, S, T); put_char('(', F, S, T); put_str(jvp_dtoa_fmt(C, buf, refcnt), F, S, T); put_char(')', F, S, T); } static void jv_dump_term(struct dtoa_context* C, jv x, int flags, int indent, FILE* F, jv* S) { char buf[JVP_DTOA_FMT_MAX_LEN]; const char* color = 0; double refcnt = (flags & JV_PRINT_REFCOUNT) ? jv_get_refcnt(x) - 1 : -1; if ((flags & JV_PRINT_COLOR) && jv_get_kind(x) != JV_KIND_INVALID) { color = colors[(int)jv_get_kind(x) - 1]; put_str(color, F, S, flags & JV_PRINT_ISATTY); } if (indent > MAX_PRINT_DEPTH) { put_str("", F, S, flags & JV_PRINT_ISATTY); } else switch (jv_get_kind(x)) { default: case JV_KIND_INVALID: if (flags & JV_PRINT_INVALID) { jv msg = jv_invalid_get_msg(jv_copy(x)); if (jv_get_kind(msg) == JV_KIND_STRING) { put_str("', F, S, flags & JV_PRINT_ISATTY); } else { put_str("", F, S, flags & JV_PRINT_ISATTY); } } else { assert(0 && "Invalid value"); } break; case JV_KIND_NULL: put_str("null", F, S, flags & JV_PRINT_ISATTY); break; case JV_KIND_FALSE: put_str("false", F, S, flags & JV_PRINT_ISATTY); break; case JV_KIND_TRUE: put_str("true", F, S, flags & JV_PRINT_ISATTY); break; case JV_KIND_NUMBER: { if (jvp_number_is_nan(x)) { jv_dump_term(C, jv_null(), flags, indent, F, S); } else { #ifdef USE_DECNUM const char * literal_data = jv_number_get_literal(x); if (literal_data) { put_str(literal_data, F, S, flags & JV_PRINT_ISATTY); } else { #endif double d = jv_number_value(x); if (d != d) { // JSON doesn't have NaN, so we'll render it as "null" put_str("null", F, S, flags & JV_PRINT_ISATTY); } else { // Normalise infinities to something we can print in valid JSON if (d > DBL_MAX) d = DBL_MAX; if (d < -DBL_MAX) d = -DBL_MAX; put_str(jvp_dtoa_fmt(C, buf, d), F, S, flags & JV_PRINT_ISATTY); } } #ifdef USE_DECNUM } #endif break; } case JV_KIND_STRING: jvp_dump_string(x, flags & JV_PRINT_ASCII, F, S, flags & JV_PRINT_ISATTY); if (flags & JV_PRINT_REFCOUNT) put_refcnt(C, refcnt, F, S, flags & JV_PRINT_ISATTY); break; case JV_KIND_ARRAY: { if (jv_array_length(jv_copy(x)) == 0) { put_str("[]", F, S, flags & JV_PRINT_ISATTY); break; } put_char('[', F, S, flags & JV_PRINT_ISATTY); jv_array_foreach(x, i, elem) { if (i!=0) { if (color) put_str(color, F, S, flags & JV_PRINT_ISATTY); put_char(',', F, S, flags & JV_PRINT_ISATTY); } if (color) put_str(COLRESET, F, S, flags & JV_PRINT_ISATTY); if (flags & JV_PRINT_PRETTY) { put_char('\n', F, S, flags & JV_PRINT_ISATTY); put_indent(indent + 1, flags, F, S, flags & JV_PRINT_ISATTY); } jv_dump_term(C, elem, flags, indent + 1, F, S); } if (flags & JV_PRINT_PRETTY) { put_char('\n', F, S, flags & JV_PRINT_ISATTY); put_indent(indent, flags, F, S, flags & JV_PRINT_ISATTY); } if (color) put_str(color, F, S, flags & JV_PRINT_ISATTY); put_char(']', F, S, flags & JV_PRINT_ISATTY); if (flags & JV_PRINT_REFCOUNT) put_refcnt(C, refcnt, F, S, flags & JV_PRINT_ISATTY); break; } case JV_KIND_OBJECT: { if (jv_object_length(jv_copy(x)) == 0) { put_str("{}", F, S, flags & JV_PRINT_ISATTY); break; } put_char('{', F, S, flags & JV_PRINT_ISATTY); 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); } if (!first) { if (color) put_str(color, F, S, flags & JV_PRINT_ISATTY); put_char(',', F, S, flags & JV_PRINT_ISATTY); } if (color) put_str(COLRESET, F, S, flags & JV_PRINT_ISATTY); if (flags & JV_PRINT_PRETTY) { put_char('\n', F, S, flags & JV_PRINT_ISATTY); put_indent(indent + 1, flags, F, S, flags & JV_PRINT_ISATTY); } first = 0; if (color) put_str(FIELD_COLOR, F, S, flags & JV_PRINT_ISATTY); jvp_dump_string(key, flags & JV_PRINT_ASCII, F, S, flags & JV_PRINT_ISATTY); jv_free(key); if (color) put_str(COLRESET, F, S, flags & JV_PRINT_ISATTY); if (color) put_str(color, F, S, flags & JV_PRINT_ISATTY); put_char(':', F, S, flags & JV_PRINT_ISATTY); if (color) put_str(COLRESET, F, S, flags & JV_PRINT_ISATTY); if (flags & JV_PRINT_PRETTY) { put_char(' ', F, S, flags & JV_PRINT_ISATTY); } jv_dump_term(C, value, flags, indent + 1, F, S); } if (flags & JV_PRINT_PRETTY) { put_char('\n', F, S, flags & JV_PRINT_ISATTY); put_indent(indent, flags, F, S, flags & JV_PRINT_ISATTY); } if (color) put_str(color, F, S, flags & JV_PRINT_ISATTY); put_char('}', F, S, flags & JV_PRINT_ISATTY); if (flags & JV_PRINT_REFCOUNT) put_refcnt(C, refcnt, F, S, flags & JV_PRINT_ISATTY); } } jv_free(x); if (color) { put_str(COLRESET, F, S, flags & JV_PRINT_ISATTY); } } void jv_dumpf(jv x, FILE *f, int flags) { jv_dump_term(tsd_dtoa_context_get(), x, flags, 0, f, 0); } void jv_dump(jv x, int flags) { jv_dumpf(x, stdout, flags); } /* This one is nice for use in debuggers */ void jv_show(jv x, int flags) { if (flags == -1) flags = JV_PRINT_PRETTY | JV_PRINT_COLOR | JV_PRINT_INDENT_FLAGS(2); jv_dumpf(jv_copy(x), stderr, flags | JV_PRINT_INVALID); fflush(stderr); } jv jv_dump_string(jv x, int flags) { jv s = jv_string(""); jv_dump_term(tsd_dtoa_context_get(), x, flags, 0, 0, &s); return s; } char *jv_dump_string_trunc(jv x, char *outbuf, size_t bufsize) { assert(bufsize > 0); x = jv_dump_string(x, 0); const char *str = jv_string_value(x); const size_t len = strlen(str); if (len > bufsize - 1 && bufsize >= 8) { char delim = 0; switch (str[0]) { case '"': delim = '"'; break; case '[': delim = ']'; break; case '{': delim = '}'; break; } size_t l = bufsize - (delim ? 5 : 4); // "...", delim (if any), '\0' const char *s = jvp_utf8_backtrack(str + l, str, NULL); if (s) l = s - str; memcpy(outbuf, str, l); outbuf[l++] = '.'; outbuf[l++] = '.'; outbuf[l++] = '.'; if (delim) outbuf[l++] = delim; outbuf[l] = '\0'; } else { size_t l = MIN(len, bufsize - 1); memcpy(outbuf, str, l); outbuf[l] = '\0'; } jv_free(x); return outbuf; } ================================================ FILE: src/jv_private.h ================================================ #ifndef JV_PRIVATE #define JV_PRIVATE int jvp_number_cmp(jv, jv); int jvp_number_is_nan(jv); #endif //JV_PRIVATE ================================================ FILE: src/jv_thread.h ================================================ #ifndef JV_THREAD_H #define JV_THREAD_H #ifdef WIN32 #ifndef __MINGW32__ #include #include #include /* Copied from Heimdal: pthread-like mutexes for WIN32 -- see lib/base/heimbase.h in Heimdal */ typedef struct pthread_mutex { HANDLE h; } pthread_mutex_t; #define PTHREAD_MUTEX_INITIALIZER { INVALID_HANDLE_VALUE } static inline int pthread_mutex_init(pthread_mutex_t *m) { m->h = CreateSemaphore(NULL, 1, 1, NULL); if (m->h == INVALID_HANDLE_VALUE) return EAGAIN; return 0; } static inline int pthread_mutex_lock(pthread_mutex_t *m) { HANDLE h, new_h; int created = 0; h = InterlockedCompareExchangePointer(&m->h, m->h, m->h); if (h == INVALID_HANDLE_VALUE || h == NULL) { created = 1; new_h = CreateSemaphore(NULL, 0, 1, NULL); if (new_h == INVALID_HANDLE_VALUE) return EAGAIN; if (InterlockedCompareExchangePointer(&m->h, new_h, h) != h) { created = 0; CloseHandle(new_h); } } if (!created) WaitForSingleObject(m->h, INFINITE); return 0; } static inline int pthread_mutex_unlock(pthread_mutex_t *m) { if (ReleaseSemaphore(m->h, 1, NULL) == FALSE) return EPERM; return 0; } static inline int pthread_mutex_destroy(pthread_mutex_t *m) { HANDLE h; h = InterlockedCompareExchangePointer(&m->h, INVALID_HANDLE_VALUE, m->h); if (h != INVALID_HANDLE_VALUE) CloseHandle(h); return 0; } typedef unsigned long pthread_key_t; int pthread_key_create(pthread_key_t *, void (*)(void *)); int pthread_setspecific(pthread_key_t, void *); void *pthread_getspecific(pthread_key_t); #else #include #endif #else #include #endif #endif /* JV_THREAD_H */ ================================================ FILE: src/jv_unicode.c ================================================ #include #include #include "jv_unicode.h" #include "jv_utf8_tables.h" // jvp_utf8_backtrack returns the beginning of the last codepoint in the // string, assuming that start is the last byte in the string. // If the last codepoint is incomplete, returns the number of missing bytes via // *missing_bytes. If there are no leading bytes or an invalid byte is // encountered, NULL is returned and *missing_bytes is not altered. const char* jvp_utf8_backtrack(const char* start, const char* min, int *missing_bytes) { assert(min <= start); if (min == start) { return min; } int length = 0; int seen = 1; while (start >= min && (length = utf8_coding_length[(unsigned char)*start]) == UTF8_CONTINUATION_BYTE) { start--; seen++; } if (length == 0 || length == UTF8_CONTINUATION_BYTE || length - seen < 0) { return NULL; } if (missing_bytes) *missing_bytes = length - seen; return start; } const char* jvp_utf8_next(const char* in, const char* end, int* codepoint_ret) { assert(in <= end); if (in == end) { 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 0x10FFFF) { /* Outside Unicode range */ codepoint = -1; } } assert(length > 0); *codepoint_ret = codepoint; return in + length; } int jvp_utf8_is_valid(const char* in, const char* end) { int codepoint; while ((in = jvp_utf8_next(in, end, &codepoint))) { if (codepoint == -1) return 0; } return 1; } /* Assumes startchar is the first byte of a valid character sequence */ int jvp_utf8_decode_length(char startchar) { if ((startchar & 0x80) == 0) return 1; // 0___ ____ else if ((startchar & 0xE0) == 0xC0) return 2; // 110_ ____ else if ((startchar & 0xF0) == 0xE0) return 3; // 1110 ____ else return 4; // 1111 ____ } int jvp_utf8_encode_length(int codepoint) { if (codepoint <= 0x7F) return 1; else if (codepoint <= 0x7FF) return 2; else if (codepoint <= 0xFFFF) return 3; else return 4; } int jvp_utf8_encode(int codepoint, char* out) { assert(codepoint >= 0 && codepoint <= 0x10FFFF); char* start = out; if (codepoint <= 0x7F) { *out++ = codepoint; } else if (codepoint <= 0x7FF) { *out++ = 0xC0 + ((codepoint & 0x7C0) >> 6); *out++ = 0x80 + ((codepoint & 0x03F)); } else if(codepoint <= 0xFFFF) { *out++ = 0xE0 + ((codepoint & 0xF000) >> 12); *out++ = 0x80 + ((codepoint & 0x0FC0) >> 6); *out++ = 0x80 + ((codepoint & 0x003F)); } else { *out++ = 0xF0 + ((codepoint & 0x1C0000) >> 18); *out++ = 0x80 + ((codepoint & 0x03F000) >> 12); *out++ = 0x80 + ((codepoint & 0x000FC0) >> 6); *out++ = 0x80 + ((codepoint & 0x00003F)); } assert(out - start == jvp_utf8_encode_length(codepoint)); return out - start; } // characters with White_Space property in: // https://www.unicode.org/Public/UCD/latest/ucd/PropList.txt int jvp_codepoint_is_whitespace(int c) { return (c >= 0x0009 && c <= 0x000D) || // .. c == 0x0020 || // SPACE c == 0x0085 || // c == 0x00A0 || // NO-BREAK SPACE c == 0x1680 || // OGHAM SPACE MARK (c >= 0x2000 && c <= 0x200A) || // EN QUAD..HAIR SPACE c == 0x2028 || // LINE SEPARATOR c == 0x2029 || // PARAGRAPH SEPARATOR c == 0x202F || // NARROW NO-BREAK SPACE c == 0x205F || // MEDIUM MATHEMATICAL SPACE c == 0x3000 // IDEOGRAPHIC SPACE ; } ================================================ FILE: src/jv_unicode.h ================================================ #ifndef JV_UNICODE_H #define JV_UNICODE_H const char* jvp_utf8_backtrack(const char* start, const char* min, int *missing_bytes); 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); int jvp_utf8_encode_length(int codepoint); int jvp_utf8_encode(int codepoint, char* out); int jvp_codepoint_is_whitespace(int c); #endif ================================================ FILE: src/jv_utf8_tables.h ================================================ #define UTF8_CONTINUATION_BYTE ((unsigned char)255) static const unsigned char utf8_coding_length[] = {0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x04, 0x04, 0x04, 0x04, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; static const unsigned char utf8_coding_bits[] = {0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x00, 0x00, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 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}; ================================================ FILE: src/lexer.c ================================================ #line 2 "src/lexer.c" #line 4 "src/lexer.c" #define YY_INT_ALIGNED short int /* A lexical scanner generated by flex */ #define FLEX_SCANNER #define YY_FLEX_MAJOR_VERSION 2 #define YY_FLEX_MINOR_VERSION 6 #define YY_FLEX_SUBMINOR_VERSION 4 #if YY_FLEX_SUBMINOR_VERSION > 0 #define FLEX_BETA #endif #ifdef yy_create_buffer #define jq_yy_create_buffer_ALREADY_DEFINED #else #define yy_create_buffer jq_yy_create_buffer #endif #ifdef yy_delete_buffer #define jq_yy_delete_buffer_ALREADY_DEFINED #else #define yy_delete_buffer jq_yy_delete_buffer #endif #ifdef yy_scan_buffer #define jq_yy_scan_buffer_ALREADY_DEFINED #else #define yy_scan_buffer jq_yy_scan_buffer #endif #ifdef yy_scan_string #define jq_yy_scan_string_ALREADY_DEFINED #else #define yy_scan_string jq_yy_scan_string #endif #ifdef yy_scan_bytes #define jq_yy_scan_bytes_ALREADY_DEFINED #else #define yy_scan_bytes jq_yy_scan_bytes #endif #ifdef yy_init_buffer #define jq_yy_init_buffer_ALREADY_DEFINED #else #define yy_init_buffer jq_yy_init_buffer #endif #ifdef yy_flush_buffer #define jq_yy_flush_buffer_ALREADY_DEFINED #else #define yy_flush_buffer jq_yy_flush_buffer #endif #ifdef yy_load_buffer_state #define jq_yy_load_buffer_state_ALREADY_DEFINED #else #define yy_load_buffer_state jq_yy_load_buffer_state #endif #ifdef yy_switch_to_buffer #define jq_yy_switch_to_buffer_ALREADY_DEFINED #else #define yy_switch_to_buffer jq_yy_switch_to_buffer #endif #ifdef yypush_buffer_state #define jq_yypush_buffer_state_ALREADY_DEFINED #else #define yypush_buffer_state jq_yypush_buffer_state #endif #ifdef yypop_buffer_state #define jq_yypop_buffer_state_ALREADY_DEFINED #else #define yypop_buffer_state jq_yypop_buffer_state #endif #ifdef yyensure_buffer_stack #define jq_yyensure_buffer_stack_ALREADY_DEFINED #else #define yyensure_buffer_stack jq_yyensure_buffer_stack #endif #ifdef yylex #define jq_yylex_ALREADY_DEFINED #else #define yylex jq_yylex #endif #ifdef yyrestart #define jq_yyrestart_ALREADY_DEFINED #else #define yyrestart jq_yyrestart #endif #ifdef yylex_init #define jq_yylex_init_ALREADY_DEFINED #else #define yylex_init jq_yylex_init #endif #ifdef yylex_init_extra #define jq_yylex_init_extra_ALREADY_DEFINED #else #define yylex_init_extra jq_yylex_init_extra #endif #ifdef yylex_destroy #define jq_yylex_destroy_ALREADY_DEFINED #else #define yylex_destroy jq_yylex_destroy #endif #ifdef yyget_debug #define jq_yyget_debug_ALREADY_DEFINED #else #define yyget_debug jq_yyget_debug #endif #ifdef yyset_debug #define jq_yyset_debug_ALREADY_DEFINED #else #define yyset_debug jq_yyset_debug #endif #ifdef yyget_extra #define jq_yyget_extra_ALREADY_DEFINED #else #define yyget_extra jq_yyget_extra #endif #ifdef yyset_extra #define jq_yyset_extra_ALREADY_DEFINED #else #define yyset_extra jq_yyset_extra #endif #ifdef yyget_in #define jq_yyget_in_ALREADY_DEFINED #else #define yyget_in jq_yyget_in #endif #ifdef yyset_in #define jq_yyset_in_ALREADY_DEFINED #else #define yyset_in jq_yyset_in #endif #ifdef yyget_out #define jq_yyget_out_ALREADY_DEFINED #else #define yyget_out jq_yyget_out #endif #ifdef yyset_out #define jq_yyset_out_ALREADY_DEFINED #else #define yyset_out jq_yyset_out #endif #ifdef yyget_leng #define jq_yyget_leng_ALREADY_DEFINED #else #define yyget_leng jq_yyget_leng #endif #ifdef yyget_text #define jq_yyget_text_ALREADY_DEFINED #else #define yyget_text jq_yyget_text #endif #ifdef yyget_lineno #define jq_yyget_lineno_ALREADY_DEFINED #else #define yyget_lineno jq_yyget_lineno #endif #ifdef yyset_lineno #define jq_yyset_lineno_ALREADY_DEFINED #else #define yyset_lineno jq_yyset_lineno #endif #ifdef yyget_column #define jq_yyget_column_ALREADY_DEFINED #else #define yyget_column jq_yyget_column #endif #ifdef yyset_column #define jq_yyset_column_ALREADY_DEFINED #else #define yyset_column jq_yyset_column #endif #ifdef yywrap #define jq_yywrap_ALREADY_DEFINED #else #define yywrap jq_yywrap #endif #ifdef yyget_lval #define jq_yyget_lval_ALREADY_DEFINED #else #define yyget_lval jq_yyget_lval #endif #ifdef yyset_lval #define jq_yyset_lval_ALREADY_DEFINED #else #define yyset_lval jq_yyset_lval #endif #ifdef yyget_lloc #define jq_yyget_lloc_ALREADY_DEFINED #else #define yyget_lloc jq_yyget_lloc #endif #ifdef yyset_lloc #define jq_yyset_lloc_ALREADY_DEFINED #else #define yyset_lloc jq_yyset_lloc #endif #ifdef yyalloc #define jq_yyalloc_ALREADY_DEFINED #else #define yyalloc jq_yyalloc #endif #ifdef yyrealloc #define jq_yyrealloc_ALREADY_DEFINED #else #define yyrealloc jq_yyrealloc #endif #ifdef yyfree #define jq_yyfree_ALREADY_DEFINED #else #define yyfree jq_yyfree #endif /* First, we deal with platform-specific or compiler-specific issues. */ /* begin standard C headers. */ #include #include #include #include /* end standard C headers. */ /* flex integer type definitions */ #ifndef FLEXINT_H #define FLEXINT_H /* C99 systems have . Non-C99 systems may or may not. */ #if defined (__STDC_VERSION__) && __STDC_VERSION__ >= 199901L /* C99 says to define __STDC_LIMIT_MACROS before including stdint.h, * if you want the limit (max/min) macros for int types. */ #ifndef __STDC_LIMIT_MACROS #define __STDC_LIMIT_MACROS 1 #endif #include typedef int8_t flex_int8_t; typedef uint8_t flex_uint8_t; typedef int16_t flex_int16_t; typedef uint16_t flex_uint16_t; typedef int32_t flex_int32_t; typedef uint32_t flex_uint32_t; #else typedef signed char flex_int8_t; typedef short int flex_int16_t; typedef int flex_int32_t; typedef unsigned char flex_uint8_t; typedef unsigned short int flex_uint16_t; typedef unsigned int flex_uint32_t; /* Limits of integral types. */ #ifndef INT8_MIN #define INT8_MIN (-128) #endif #ifndef INT16_MIN #define INT16_MIN (-32767-1) #endif #ifndef INT32_MIN #define INT32_MIN (-2147483647-1) #endif #ifndef INT8_MAX #define INT8_MAX (127) #endif #ifndef INT16_MAX #define INT16_MAX (32767) #endif #ifndef INT32_MAX #define INT32_MAX (2147483647) #endif #ifndef UINT8_MAX #define UINT8_MAX (255U) #endif #ifndef UINT16_MAX #define UINT16_MAX (65535U) #endif #ifndef UINT32_MAX #define UINT32_MAX (4294967295U) #endif #ifndef SIZE_MAX #define SIZE_MAX (~(size_t)0) #endif #endif /* ! C99 */ #endif /* ! FLEXINT_H */ /* begin standard C++ headers. */ /* TODO: this is always defined, so inline it */ #define yyconst const #if defined(__GNUC__) && __GNUC__ >= 3 #define yynoreturn __attribute__((__noreturn__)) #else #define yynoreturn #endif /* Returned upon end-of-file. */ #define YY_NULL 0 /* Promotes a possibly negative, possibly signed char to an * integer in range [0..255] for use as an array index. */ #define YY_SC_TO_UI(c) ((YY_CHAR) (c)) /* An opaque pointer. */ #ifndef YY_TYPEDEF_YY_SCANNER_T #define YY_TYPEDEF_YY_SCANNER_T typedef void* yyscan_t; #endif /* For convenience, these vars (plus the bison vars far below) are macros in the reentrant scanner. */ #define yyin yyg->yyin_r #define yyout yyg->yyout_r #define yyextra yyg->yyextra_r #define yyleng yyg->yyleng_r #define yytext yyg->yytext_r #define yylineno (YY_CURRENT_BUFFER_LVALUE->yy_bs_lineno) #define yycolumn (YY_CURRENT_BUFFER_LVALUE->yy_bs_column) #define yy_flex_debug yyg->yy_flex_debug_r /* Enter a start condition. This macro really ought to take a parameter, * but we do it the disgusting crufty way forced on us by the ()-less * definition of BEGIN. */ #define BEGIN yyg->yy_start = 1 + 2 * /* Translate the current start state into a value that can be later handed * to BEGIN to return to the state. The YYSTATE alias is for lex * compatibility. */ #define YY_START ((yyg->yy_start - 1) / 2) #define YYSTATE YY_START /* Action number for EOF rule of a given start state. */ #define YY_STATE_EOF(state) (YY_END_OF_BUFFER + state + 1) /* Special action meaning "start processing a new file". */ #define YY_NEW_FILE yyrestart( yyin , yyscanner ) #define YY_END_OF_BUFFER_CHAR 0 /* Size of default input buffer. */ #ifndef YY_BUF_SIZE #ifdef __ia64__ /* On IA-64, the buffer size is 16k, not 8k. * Moreover, YY_BUF_SIZE is 2*YY_READ_BUF_SIZE in the general case. * Ditto for the __ia64__ case accordingly. */ #define YY_BUF_SIZE 32768 #else #define YY_BUF_SIZE 16384 #endif /* __ia64__ */ #endif /* The state buf must be large enough to hold one state per character in the main buffer. */ #define YY_STATE_BUF_SIZE ((YY_BUF_SIZE + 2) * sizeof(yy_state_type)) #ifndef YY_TYPEDEF_YY_BUFFER_STATE #define YY_TYPEDEF_YY_BUFFER_STATE typedef struct yy_buffer_state *YY_BUFFER_STATE; #endif #ifndef YY_TYPEDEF_YY_SIZE_T #define YY_TYPEDEF_YY_SIZE_T typedef size_t yy_size_t; #endif #define EOB_ACT_CONTINUE_SCAN 0 #define EOB_ACT_END_OF_FILE 1 #define EOB_ACT_LAST_MATCH 2 #define YY_LESS_LINENO(n) #define YY_LINENO_REWIND_TO(ptr) /* Return all but the first "n" matched characters back to the input stream. */ #define yyless(n) \ do \ { \ /* Undo effects of setting up yytext. */ \ int yyless_macro_arg = (n); \ YY_LESS_LINENO(yyless_macro_arg);\ *yy_cp = yyg->yy_hold_char; \ YY_RESTORE_YY_MORE_OFFSET \ yyg->yy_c_buf_p = yy_cp = yy_bp + yyless_macro_arg - YY_MORE_ADJ; \ YY_DO_BEFORE_ACTION; /* set up yytext again */ \ } \ while ( 0 ) #define unput(c) yyunput( c, yyg->yytext_ptr , yyscanner ) #ifndef YY_STRUCT_YY_BUFFER_STATE #define YY_STRUCT_YY_BUFFER_STATE struct yy_buffer_state { FILE *yy_input_file; char *yy_ch_buf; /* input buffer */ char *yy_buf_pos; /* current position in input buffer */ /* Size of input buffer in bytes, not including room for EOB * characters. */ int yy_buf_size; /* Number of characters read into yy_ch_buf, not including EOB * characters. */ int yy_n_chars; /* Whether we "own" the buffer - i.e., we know we created it, * and can realloc() it to grow it, and should free() it to * delete it. */ int yy_is_our_buffer; /* Whether this is an "interactive" input source; if so, and * if we're using stdio for input, then we want to use getc() * instead of fread(), to make sure we stop fetching input after * each newline. */ int yy_is_interactive; /* Whether we're considered to be at the beginning of a line. * If so, '^' rules will be active on the next match, otherwise * not. */ int yy_at_bol; int yy_bs_lineno; /**< The line count. */ int yy_bs_column; /**< The column count. */ /* Whether to try to fill the input buffer when we reach the * end of it. */ int yy_fill_buffer; int yy_buffer_status; #define YY_BUFFER_NEW 0 #define YY_BUFFER_NORMAL 1 /* When an EOF's been seen but there's still some text to process * then we mark the buffer as YY_EOF_PENDING, to indicate that we * shouldn't try reading from the input source any more. We might * still have a bunch of tokens to match, though, because of * possible backing-up. * * When we actually see the EOF, we change the status to "new" * (via yyrestart()), so that the user can continue scanning by * just pointing yyin at a new input file. */ #define YY_BUFFER_EOF_PENDING 2 }; #endif /* !YY_STRUCT_YY_BUFFER_STATE */ /* We provide macros for accessing buffer states in case in the * future we want to put the buffer states in a more general * "scanner state". * * Returns the top of the stack, or NULL. */ #define YY_CURRENT_BUFFER ( yyg->yy_buffer_stack \ ? yyg->yy_buffer_stack[yyg->yy_buffer_stack_top] \ : NULL) /* Same as previous macro, but useful when we know that the buffer stack is not * NULL or when we need an lvalue. For internal use only. */ #define YY_CURRENT_BUFFER_LVALUE yyg->yy_buffer_stack[yyg->yy_buffer_stack_top] void yyrestart ( FILE *input_file , yyscan_t yyscanner ); void yy_switch_to_buffer ( YY_BUFFER_STATE new_buffer , yyscan_t yyscanner ); YY_BUFFER_STATE yy_create_buffer ( FILE *file, int size , yyscan_t yyscanner ); void yy_delete_buffer ( YY_BUFFER_STATE b , yyscan_t yyscanner ); void yy_flush_buffer ( YY_BUFFER_STATE b , yyscan_t yyscanner ); void yypush_buffer_state ( YY_BUFFER_STATE new_buffer , yyscan_t yyscanner ); void yypop_buffer_state ( yyscan_t yyscanner ); static void yyensure_buffer_stack ( yyscan_t yyscanner ); static void yy_load_buffer_state ( yyscan_t yyscanner ); static void yy_init_buffer ( YY_BUFFER_STATE b, FILE *file , yyscan_t yyscanner ); #define YY_FLUSH_BUFFER yy_flush_buffer( YY_CURRENT_BUFFER , yyscanner) YY_BUFFER_STATE yy_scan_buffer ( char *base, yy_size_t size , yyscan_t yyscanner ); YY_BUFFER_STATE yy_scan_string ( const char *yy_str , yyscan_t yyscanner ); YY_BUFFER_STATE yy_scan_bytes ( const char *bytes, int len , yyscan_t yyscanner ); void *yyalloc ( yy_size_t , yyscan_t yyscanner ); void *yyrealloc ( void *, yy_size_t , yyscan_t yyscanner ); void yyfree ( void * , yyscan_t yyscanner ); #define yy_new_buffer yy_create_buffer #define yy_set_interactive(is_interactive) \ { \ if ( ! YY_CURRENT_BUFFER ){ \ yyensure_buffer_stack (yyscanner); \ YY_CURRENT_BUFFER_LVALUE = \ yy_create_buffer( yyin, YY_BUF_SIZE , yyscanner); \ } \ YY_CURRENT_BUFFER_LVALUE->yy_is_interactive = is_interactive; \ } #define yy_set_bol(at_bol) \ { \ if ( ! YY_CURRENT_BUFFER ){\ yyensure_buffer_stack (yyscanner); \ YY_CURRENT_BUFFER_LVALUE = \ yy_create_buffer( yyin, YY_BUF_SIZE , yyscanner); \ } \ YY_CURRENT_BUFFER_LVALUE->yy_at_bol = at_bol; \ } #define YY_AT_BOL() (YY_CURRENT_BUFFER_LVALUE->yy_at_bol) /* Begin user sect3 */ #define jq_yywrap(yyscanner) (/*CONSTCOND*/1) #define YY_SKIP_YYWRAP typedef flex_uint8_t YY_CHAR; typedef int yy_state_type; #define yytext_ptr yytext_r static yy_state_type yy_get_previous_state ( yyscan_t yyscanner ); static yy_state_type yy_try_NUL_trans ( yy_state_type current_state , yyscan_t yyscanner); static int yy_get_next_buffer ( yyscan_t yyscanner ); static void yynoreturn yy_fatal_error ( const char* msg , yyscan_t yyscanner ); /* Done after the current pattern has been matched and before the * corresponding action - sets up yytext. */ #define YY_DO_BEFORE_ACTION \ yyg->yytext_ptr = yy_bp; \ yyleng = (int) (yy_cp - yy_bp); \ yyg->yy_hold_char = *yy_cp; \ *yy_cp = '\0'; \ yyg->yy_c_buf_p = yy_cp; #define YY_NUM_RULES 53 #define YY_END_OF_BUFFER 54 /* This struct is not used in this scanner, but its presence is necessary. */ struct yy_trans_info { flex_int32_t yy_verify; flex_int32_t yy_nxt; }; static const flex_int16_t yy_accept[171] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 54, 52, 51, 51, 52, 42, 1, 37, 37, 38, 39, 37, 37, 37, 37, 37, 37, 41, 37, 37, 37, 37, 52, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 37, 46, 46, 44, 47, 2, 3, 2, 2, 51, 4, 50, 50, 31, 29, 27, 28, 35, 41, 49, 20, 30, 41, 41, 0, 33, 5, 34, 0, 40, 48, 0, 48, 6, 48, 48, 48, 48, 48, 48, 11, 48, 48, 48, 48, 16, 48, 48, 48, 26, 46, 45, 43, 45, 3, 2, 0, 50, 0, 50, 49, 32, 41, 0, 41, 36, 0, 15, 48, 48, 10, 48, 48, 17, 48, 48, 48, 48, 48, 48, 48, 21, 0, 45, 0, 50, 48, 48, 48, 14, 13, 48, 48, 48, 48, 48, 48, 12, 45, 50, 24, 22, 48, 48, 48, 23, 48, 48, 45, 50, 48, 7, 48, 9, 18, 50, 19, 8, 25, 0 } ; static const YY_CHAR yy_ec[256] = { 0, 1, 1, 1, 1, 1, 1, 1, 1, 2, 3, 1, 1, 4, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 5, 6, 7, 8, 9, 1, 1, 10, 11, 12, 13, 14, 15, 16, 17, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 19, 20, 21, 22, 23, 24, 25, 26, 26, 26, 26, 27, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 28, 29, 30, 1, 31, 1, 32, 33, 34, 35, 36, 37, 26, 38, 39, 26, 40, 41, 42, 43, 44, 45, 26, 46, 47, 48, 49, 26, 26, 26, 50, 26, 51, 52, 53, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 } ; static const YY_CHAR yy_meta[54] = { 0, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 3, 1, 4, 5, 1, 1, 1, 1, 1, 1, 6, 6, 1, 7, 1, 8, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 1, 1, 1 } ; static const flex_int16_t yy_base[186] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 51, 52, 56, 58, 340, 341, 61, 64, 317, 341, 341, 307, 315, 341, 341, 314, 313, 341, 312, 53, 53, 56, 311, 310, 309, 313, 0, 310, 54, 57, 58, 59, 63, 65, 70, 67, 72, 69, 60, 79, 306, 0, 0, 341, 83, 341, 341, 324, 107, 116, 341, 307, 83, 341, 341, 341, 341, 341, 103, 0, 303, 341, 104, 108, 128, 341, 341, 341, 307, 0, 304, 301, 110, 297, 114, 75, 115, 108, 118, 119, 293, 109, 123, 129, 132, 290, 137, 130, 139, 341, 0, 276, 341, 273, 341, 341, 297, 278, 265, 140, 0, 341, 142, 261, 258, 341, 0, 252, 142, 145, 250, 149, 144, 247, 151, 152, 154, 156, 157, 158, 165, 245, 172, 231, 0, 166, 222, 164, 171, 221, 220, 169, 172, 174, 175, 178, 179, 218, 206, 180, 215, 214, 181, 183, 192, 213, 184, 186, 201, 193, 198, 210, 206, 209, 89, 207, 86, 81, 37, 341, 242, 250, 253, 259, 264, 269, 277, 285, 290, 295, 300, 302, 307, 311, 315 } ; static const flex_int16_t yy_def[186] = { 0, 170, 1, 1, 1, 1, 1, 1, 1, 1, 1, 171, 171, 172, 172, 170, 170, 170, 170, 170, 170, 170, 173, 170, 170, 170, 170, 170, 170, 170, 174, 170, 170, 170, 170, 170, 170, 175, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 170, 177, 177, 170, 178, 170, 170, 170, 170, 170, 170, 179, 179, 170, 170, 170, 170, 170, 170, 180, 170, 170, 170, 170, 170, 170, 170, 170, 170, 175, 176, 170, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 170, 177, 170, 170, 181, 170, 170, 170, 179, 170, 179, 180, 170, 170, 170, 170, 170, 182, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 178, 183, 173, 179, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 184, 179, 176, 176, 176, 176, 176, 176, 176, 176, 185, 179, 176, 176, 176, 176, 176, 179, 176, 176, 179, 0, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170 } ; static const flex_int16_t yy_nxt[395] = { 0, 16, 17, 18, 17, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 28, 28, 33, 34, 35, 36, 37, 38, 38, 24, 16, 25, 38, 39, 40, 41, 42, 43, 44, 38, 45, 38, 46, 47, 38, 48, 38, 49, 38, 50, 38, 38, 24, 51, 25, 53, 53, 109, 54, 54, 57, 58, 57, 58, 60, 60, 60, 60, 60, 60, 68, 71, 69, 73, 82, 74, 72, 82, 82, 82, 82, 55, 55, 82, 75, 82, 59, 82, 59, 82, 82, 86, 82, 75, 103, 82, 87, 97, 83, 82, 94, 82, 84, 109, 85, 88, 82, 89, 91, 82, 90, 106, 107, 92, 93, 110, 96, 95, 98, 60, 60, 60, 69, 113, 120, 73, 99, 74, 82, 82, 82, 75, 75, 104, 82, 82, 75, 106, 82, 82, 75, 75, 114, 82, 114, 75, 118, 115, 122, 82, 82, 119, 82, 121, 124, 126, 123, 82, 127, 82, 109, 113, 82, 128, 82, 82, 125, 131, 129, 82, 75, 82, 82, 130, 82, 138, 82, 82, 82, 75, 139, 141, 136, 170, 82, 82, 109, 140, 142, 82, 132, 82, 82, 145, 82, 82, 144, 143, 82, 82, 109, 82, 153, 82, 82, 151, 82, 146, 147, 148, 152, 150, 82, 109, 158, 160, 161, 156, 82, 154, 157, 164, 104, 165, 155, 166, 82, 109, 163, 82, 82, 133, 162, 82, 82, 82, 133, 167, 82, 169, 82, 82, 82, 168, 52, 52, 52, 52, 52, 52, 52, 52, 56, 56, 56, 56, 56, 56, 56, 56, 62, 133, 62, 70, 70, 82, 70, 82, 70, 80, 82, 80, 82, 80, 81, 81, 81, 115, 81, 101, 115, 101, 101, 101, 101, 135, 101, 102, 102, 102, 102, 102, 102, 102, 102, 108, 108, 108, 109, 108, 111, 106, 111, 133, 111, 134, 133, 134, 134, 137, 82, 137, 149, 82, 149, 149, 159, 82, 159, 159, 102, 117, 102, 102, 82, 116, 112, 109, 105, 100, 82, 79, 78, 77, 76, 67, 66, 65, 64, 63, 61, 170, 15, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170 } ; static const flex_int16_t yy_chk[395] = { 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 11, 12, 169, 11, 12, 13, 13, 14, 14, 17, 17, 17, 18, 18, 18, 30, 31, 30, 32, 39, 32, 31, 40, 41, 42, 49, 11, 12, 43, 32, 44, 13, 46, 14, 48, 45, 41, 47, 32, 55, 86, 42, 49, 39, 50, 46, 168, 39, 63, 40, 43, 167, 43, 45, 165, 44, 59, 59, 45, 45, 63, 48, 47, 50, 60, 60, 60, 69, 73, 86, 74, 50, 74, 88, 92, 83, 69, 73, 55, 85, 87, 74, 59, 89, 90, 69, 73, 75, 93, 75, 74, 83, 75, 88, 94, 98, 85, 95, 87, 89, 92, 88, 97, 93, 99, 110, 113, 119, 94, 123, 120, 90, 98, 95, 122, 113, 125, 126, 97, 127, 119, 128, 129, 130, 113, 120, 123, 110, 133, 138, 131, 136, 122, 125, 142, 99, 139, 143, 128, 144, 145, 127, 126, 146, 147, 150, 153, 142, 154, 157, 138, 158, 129, 130, 131, 139, 136, 155, 160, 147, 150, 153, 145, 161, 143, 146, 157, 133, 158, 144, 160, 163, 166, 155, 164, 162, 159, 154, 156, 152, 151, 149, 161, 148, 166, 141, 140, 137, 163, 171, 171, 171, 171, 171, 171, 171, 171, 172, 172, 172, 172, 172, 172, 172, 172, 173, 134, 173, 174, 174, 132, 174, 124, 174, 175, 121, 175, 118, 175, 176, 176, 176, 115, 176, 177, 114, 177, 177, 177, 177, 109, 177, 178, 178, 178, 178, 178, 178, 178, 178, 179, 179, 179, 108, 179, 180, 107, 180, 104, 180, 181, 102, 181, 181, 182, 96, 182, 183, 91, 183, 183, 184, 84, 184, 184, 185, 82, 185, 185, 81, 79, 71, 62, 58, 51, 38, 36, 35, 34, 33, 29, 27, 26, 23, 22, 19, 15, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170 } ; /* The intent behind this definition is that it'll catch * any uses of REJECT which flex missed. */ #define REJECT reject_used_but_not_detected #define yymore() yymore_used_but_not_detected #define YY_MORE_ADJ 0 #define YY_RESTORE_YY_MORE_OFFSET #line 1 "src/lexer.l" #line 2 "src/lexer.l" #include #include "jv_alloc.h" #include "compile.h" struct lexer_param; #include "parser.h" /* Generated by bison. */ #define YY_USER_ACTION \ do { \ yylloc->start = yyget_extra(yyscanner); \ yylloc->end = yylloc->start + yyleng; \ yyset_extra(yylloc->end, yyscanner); \ } while (0); #line 818 "src/lexer.c" #line 26 "src/lexer.l" static int enter(int opening, int state, yyscan_t yyscanner); static int try_exit(int closing, int state, yyscan_t yyscanner); #line 823 "src/lexer.c" #define YY_NO_INPUT 1 #line 825 "src/lexer.c" #define INITIAL 0 #define IN_PAREN 1 #define IN_BRACKET 2 #define IN_BRACE 3 #define IN_QQINTERP 4 #define IN_QQSTRING 5 #define IN_COMMENT 6 #ifndef YY_NO_UNISTD_H /* Special case for "unistd.h", since it is non-ANSI. We include it way * down here because we want the user's section 1 to have been scanned first. * The user has a chance to override it with an option. */ #include #endif #define YY_EXTRA_TYPE int /* Holds the entire state of the reentrant scanner. */ struct yyguts_t { /* User-defined. Not touched by flex. */ YY_EXTRA_TYPE yyextra_r; /* The rest are the same as the globals declared in the non-reentrant scanner. */ FILE *yyin_r, *yyout_r; size_t yy_buffer_stack_top; /**< index of top of stack. */ size_t yy_buffer_stack_max; /**< capacity of stack. */ YY_BUFFER_STATE * yy_buffer_stack; /**< Stack as an array. */ char yy_hold_char; int yy_n_chars; int yyleng_r; char *yy_c_buf_p; int yy_init; int yy_start; int yy_did_buffer_switch_on_eof; int yy_start_stack_ptr; int yy_start_stack_depth; int *yy_start_stack; yy_state_type yy_last_accepting_state; char* yy_last_accepting_cpos; int yylineno_r; int yy_flex_debug_r; char *yytext_r; int yy_more_flag; int yy_more_len; YYSTYPE * yylval_r; YYLTYPE * yylloc_r; }; /* end struct yyguts_t */ static int yy_init_globals ( yyscan_t yyscanner ); /* This must go here because YYSTYPE and YYLTYPE are included * from bison output in section 1.*/ # define yylval yyg->yylval_r # define yylloc yyg->yylloc_r int yylex_init (yyscan_t* scanner); int yylex_init_extra ( YY_EXTRA_TYPE user_defined, yyscan_t* scanner); /* Accessor methods to globals. These are made visible to non-reentrant scanners for convenience. */ int yylex_destroy ( yyscan_t yyscanner ); int yyget_debug ( yyscan_t yyscanner ); void yyset_debug ( int debug_flag , yyscan_t yyscanner ); YY_EXTRA_TYPE yyget_extra ( yyscan_t yyscanner ); void yyset_extra ( YY_EXTRA_TYPE user_defined , yyscan_t yyscanner ); FILE *yyget_in ( yyscan_t yyscanner ); void yyset_in ( FILE * _in_str , yyscan_t yyscanner ); FILE *yyget_out ( yyscan_t yyscanner ); void yyset_out ( FILE * _out_str , yyscan_t yyscanner ); int yyget_leng ( yyscan_t yyscanner ); char *yyget_text ( yyscan_t yyscanner ); int yyget_lineno ( yyscan_t yyscanner ); void yyset_lineno ( int _line_number , yyscan_t yyscanner ); int yyget_column ( yyscan_t yyscanner ); void yyset_column ( int _column_no , yyscan_t yyscanner ); YYSTYPE * yyget_lval ( yyscan_t yyscanner ); void yyset_lval ( YYSTYPE * yylval_param , yyscan_t yyscanner ); YYLTYPE *yyget_lloc ( yyscan_t yyscanner ); void yyset_lloc ( YYLTYPE * yylloc_param , yyscan_t yyscanner ); /* Macros after this point can all be overridden by user definitions in * section 1. */ #ifndef YY_SKIP_YYWRAP #ifdef __cplusplus extern "C" int yywrap ( yyscan_t yyscanner ); #else extern int yywrap ( yyscan_t yyscanner ); #endif #endif #ifndef YY_NO_UNPUT #endif #ifndef yytext_ptr static void yy_flex_strncpy ( char *, const char *, int , yyscan_t yyscanner); #endif #ifdef YY_NEED_STRLEN static int yy_flex_strlen ( const char * , yyscan_t yyscanner); #endif #ifndef YY_NO_INPUT #ifdef __cplusplus static int yyinput ( yyscan_t yyscanner ); #else static int input ( yyscan_t yyscanner ); #endif #endif static void yy_push_state ( int _new_state , yyscan_t yyscanner); static void yy_pop_state ( yyscan_t yyscanner ); static int yy_top_state ( yyscan_t yyscanner ); /* Amount of stuff to slurp up with each read. */ #ifndef YY_READ_BUF_SIZE #ifdef __ia64__ /* On IA-64, the buffer size is 16k, not 8k */ #define YY_READ_BUF_SIZE 16384 #else #define YY_READ_BUF_SIZE 8192 #endif /* __ia64__ */ #endif /* Copy whatever the last rule matched to the standard output. */ #ifndef ECHO /* This used to be an fputs(), but since the string might contain NUL's, * we now use fwrite(). */ #define ECHO do { if (fwrite( yytext, (size_t) yyleng, 1, yyout )) {} } while (0) #endif /* Gets input and stuffs it into "buf". number of characters read, or YY_NULL, * is returned in "result". */ #ifndef YY_INPUT #define YY_INPUT(buf,result,max_size) \ if ( YY_CURRENT_BUFFER_LVALUE->yy_is_interactive ) \ { \ int c = '*'; \ int n; \ for ( n = 0; n < max_size && \ (c = getc( yyin )) != EOF && c != '\n'; ++n ) \ buf[n] = (char) c; \ if ( c == '\n' ) \ buf[n++] = (char) c; \ if ( c == EOF && ferror( yyin ) ) \ YY_FATAL_ERROR( "input in flex scanner failed" ); \ result = n; \ } \ else \ { \ errno=0; \ while ( (result = (int) fread(buf, 1, (yy_size_t) max_size, yyin)) == 0 && ferror(yyin)) \ { \ if( errno != EINTR) \ { \ YY_FATAL_ERROR( "input in flex scanner failed" ); \ break; \ } \ errno=0; \ clearerr(yyin); \ } \ }\ \ #endif /* No semi-colon after return; correct usage is to write "yyterminate();" - * we don't want an extra ';' after the "return" because that will cause * some compilers to complain about unreachable statements. */ #ifndef yyterminate #define yyterminate() return YY_NULL #endif /* Number of entries by which start-condition stack grows. */ #ifndef YY_START_STACK_INCR #define YY_START_STACK_INCR 25 #endif /* Report a fatal error. */ #ifndef YY_FATAL_ERROR #define YY_FATAL_ERROR(msg) yy_fatal_error( msg , yyscanner) #endif /* end tables serialization structures and prototypes */ /* Default declaration of generated scanner - a define so the user can * easily add parameters. */ #ifndef YY_DECL #define YY_DECL_IS_OURS 1 extern int yylex \ (YYSTYPE * yylval_param, YYLTYPE * yylloc_param , yyscan_t yyscanner); #define YY_DECL int yylex \ (YYSTYPE * yylval_param, YYLTYPE * yylloc_param , yyscan_t yyscanner) #endif /* !YY_DECL */ /* Code executed at the beginning of each rule, after yytext and yyleng * have been set up. */ #ifndef YY_USER_ACTION #define YY_USER_ACTION #endif /* Code executed at the end of each rule. */ #ifndef YY_BREAK #define YY_BREAK /*LINTED*/break; #endif #define YY_RULE_SETUP \ YY_USER_ACTION /** The main scanner function which does all the work. */ YY_DECL { yy_state_type yy_current_state; char *yy_cp, *yy_bp; int yy_act; struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; yylval = yylval_param; yylloc = yylloc_param; if ( !yyg->yy_init ) { yyg->yy_init = 1; #ifdef YY_USER_INIT YY_USER_INIT; #endif if ( ! yyg->yy_start ) yyg->yy_start = 1; /* first start state */ if ( ! yyin ) yyin = stdin; if ( ! yyout ) yyout = stdout; if ( ! YY_CURRENT_BUFFER ) { yyensure_buffer_stack (yyscanner); YY_CURRENT_BUFFER_LVALUE = yy_create_buffer( yyin, YY_BUF_SIZE , yyscanner); } yy_load_buffer_state( yyscanner ); } { #line 39 "src/lexer.l" #line 1120 "src/lexer.c" while ( /*CONSTCOND*/1 ) /* loops until end-of-file is reached */ { yy_cp = yyg->yy_c_buf_p; /* Support of yytext. */ *yy_cp = yyg->yy_hold_char; /* yy_bp points to the position in yy_ch_buf of the start of * the current run. */ yy_bp = yy_cp; yy_current_state = yyg->yy_start; yy_match: do { YY_CHAR yy_c = yy_ec[YY_SC_TO_UI(*yy_cp)] ; if ( yy_accept[yy_current_state] ) { yyg->yy_last_accepting_state = yy_current_state; yyg->yy_last_accepting_cpos = yy_cp; } while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state ) { yy_current_state = (int) yy_def[yy_current_state]; if ( yy_current_state >= 171 ) yy_c = yy_meta[yy_c]; } yy_current_state = yy_nxt[yy_base[yy_current_state] + yy_c]; ++yy_cp; } while ( yy_base[yy_current_state] != 341 ); yy_find_action: yy_act = yy_accept[yy_current_state]; if ( yy_act == 0 ) { /* have to back up */ yy_cp = yyg->yy_last_accepting_cpos; yy_current_state = yyg->yy_last_accepting_state; yy_act = yy_accept[yy_current_state]; } YY_DO_BEFORE_ACTION; do_action: /* This label is used only to access EOF actions. */ switch ( yy_act ) { /* beginning of action switch */ case 0: /* must back up */ /* undo the effects of YY_DO_BEFORE_ACTION */ *yy_cp = yyg->yy_hold_char; yy_cp = yyg->yy_last_accepting_cpos; yy_current_state = yyg->yy_last_accepting_state; goto yy_find_action; case 1: YY_RULE_SETUP #line 41 "src/lexer.l" { yy_push_state(IN_COMMENT, yyscanner); } YY_BREAK case 2: /* rule 2 can match eol */ YY_RULE_SETUP #line 43 "src/lexer.l" { } YY_BREAK case 3: /* rule 3 can match eol */ YY_RULE_SETUP #line 44 "src/lexer.l" { yy_pop_state(yyscanner); } YY_BREAK case YY_STATE_EOF(IN_COMMENT): #line 46 "src/lexer.l" { yy_pop_state(yyscanner); } YY_BREAK case 4: YY_RULE_SETUP #line 48 "src/lexer.l" { return NEQ; } YY_BREAK case 5: YY_RULE_SETUP #line 49 "src/lexer.l" { return EQ; } YY_BREAK case 6: YY_RULE_SETUP #line 50 "src/lexer.l" { return AS; } YY_BREAK case 7: YY_RULE_SETUP #line 51 "src/lexer.l" { return IMPORT; } YY_BREAK case 8: YY_RULE_SETUP #line 52 "src/lexer.l" { return INCLUDE; } YY_BREAK case 9: YY_RULE_SETUP #line 53 "src/lexer.l" { return MODULE; } YY_BREAK case 10: YY_RULE_SETUP #line 54 "src/lexer.l" { return DEF; } YY_BREAK case 11: YY_RULE_SETUP #line 55 "src/lexer.l" { return IF; } YY_BREAK case 12: YY_RULE_SETUP #line 56 "src/lexer.l" { return THEN; } YY_BREAK case 13: YY_RULE_SETUP #line 57 "src/lexer.l" { return ELSE; } YY_BREAK case 14: YY_RULE_SETUP #line 58 "src/lexer.l" { return ELSE_IF; } YY_BREAK case 15: YY_RULE_SETUP #line 59 "src/lexer.l" { return AND; } YY_BREAK case 16: YY_RULE_SETUP #line 60 "src/lexer.l" { return OR; } YY_BREAK case 17: YY_RULE_SETUP #line 61 "src/lexer.l" { return END; } YY_BREAK case 18: YY_RULE_SETUP #line 62 "src/lexer.l" { return REDUCE; } YY_BREAK case 19: YY_RULE_SETUP #line 63 "src/lexer.l" { return FOREACH; } YY_BREAK case 20: YY_RULE_SETUP #line 64 "src/lexer.l" { return DEFINEDOR; } YY_BREAK case 21: YY_RULE_SETUP #line 65 "src/lexer.l" { return TRY; } YY_BREAK case 22: YY_RULE_SETUP #line 66 "src/lexer.l" { return CATCH; } YY_BREAK case 23: YY_RULE_SETUP #line 67 "src/lexer.l" { return LABEL; } YY_BREAK case 24: YY_RULE_SETUP #line 68 "src/lexer.l" { return BREAK; } YY_BREAK case 25: YY_RULE_SETUP #line 69 "src/lexer.l" { return LOC; } YY_BREAK case 26: YY_RULE_SETUP #line 70 "src/lexer.l" { return SETPIPE; } YY_BREAK case 27: YY_RULE_SETUP #line 71 "src/lexer.l" { return SETPLUS; } YY_BREAK case 28: YY_RULE_SETUP #line 72 "src/lexer.l" { return SETMINUS; } YY_BREAK case 29: YY_RULE_SETUP #line 73 "src/lexer.l" { return SETMULT; } YY_BREAK case 30: YY_RULE_SETUP #line 74 "src/lexer.l" { return SETDIV; } YY_BREAK case 31: YY_RULE_SETUP #line 75 "src/lexer.l" { return SETMOD; } YY_BREAK case 32: YY_RULE_SETUP #line 76 "src/lexer.l" { return SETDEFINEDOR; } YY_BREAK case 33: YY_RULE_SETUP #line 77 "src/lexer.l" { return LESSEQ; } YY_BREAK case 34: YY_RULE_SETUP #line 78 "src/lexer.l" { return GREATEREQ; } YY_BREAK case 35: YY_RULE_SETUP #line 79 "src/lexer.l" { return REC; } YY_BREAK case 36: YY_RULE_SETUP #line 80 "src/lexer.l" { return ALTERNATION; } YY_BREAK case 37: YY_RULE_SETUP #line 81 "src/lexer.l" { return yytext[0];} YY_BREAK case 38: YY_RULE_SETUP #line 83 "src/lexer.l" { return enter(yytext[0], YY_START, yyscanner); } YY_BREAK case 39: YY_RULE_SETUP #line 87 "src/lexer.l" { return try_exit(yytext[0], YY_START, yyscanner); } YY_BREAK case 40: YY_RULE_SETUP #line 91 "src/lexer.l" { yylval->literal = jv_string_sized(yytext + 1, yyleng - 1); return FORMAT; } YY_BREAK case 41: YY_RULE_SETUP #line 95 "src/lexer.l" { yylval->literal = jv_parse_sized(yytext, yyleng); return LITERAL; } YY_BREAK case 42: YY_RULE_SETUP #line 99 "src/lexer.l" { yy_push_state(IN_QQSTRING, yyscanner); return QQSTRING_START; } YY_BREAK case 43: YY_RULE_SETUP #line 105 "src/lexer.l" { return enter(QQSTRING_INTERP_START, YY_START, yyscanner); } YY_BREAK case 44: YY_RULE_SETUP #line 108 "src/lexer.l" { yy_pop_state(yyscanner); return QQSTRING_END; } YY_BREAK case 45: /* rule 45 can match eol */ YY_RULE_SETUP #line 112 "src/lexer.l" { /* pass escapes to the json parser */ jv escapes = jv_string_fmt("\"%.*s\"", (int)yyleng, yytext); yylval->literal = jv_parse_sized(jv_string_value(escapes), jv_string_length_bytes(jv_copy(escapes))); jv_free(escapes); return QQSTRING_TEXT; } YY_BREAK case 46: /* rule 46 can match eol */ YY_RULE_SETUP #line 119 "src/lexer.l" { yylval->literal = jv_string_sized(yytext, yyleng); return QQSTRING_TEXT; } YY_BREAK case 47: YY_RULE_SETUP #line 123 "src/lexer.l" { return INVALID_CHARACTER; } YY_BREAK case 48: YY_RULE_SETUP #line 129 "src/lexer.l" { yylval->literal = jv_string(yytext); return IDENT;} YY_BREAK case 49: YY_RULE_SETUP #line 130 "src/lexer.l" { yylval->literal = jv_string(yytext+1); return FIELD;} YY_BREAK case 50: YY_RULE_SETUP #line 131 "src/lexer.l" { yylval->literal = jv_string(yytext+1); return BINDING;} YY_BREAK case 51: /* rule 51 can match eol */ YY_RULE_SETUP #line 133 "src/lexer.l" {} YY_BREAK case 52: YY_RULE_SETUP #line 135 "src/lexer.l" { return INVALID_CHARACTER; } YY_BREAK case 53: YY_RULE_SETUP #line 137 "src/lexer.l" YY_FATAL_ERROR( "flex scanner jammed" ); YY_BREAK #line 1482 "src/lexer.c" case YY_STATE_EOF(INITIAL): case YY_STATE_EOF(IN_PAREN): case YY_STATE_EOF(IN_BRACKET): case YY_STATE_EOF(IN_BRACE): case YY_STATE_EOF(IN_QQINTERP): case YY_STATE_EOF(IN_QQSTRING): yyterminate(); case YY_END_OF_BUFFER: { /* Amount of text matched not including the EOB char. */ int yy_amount_of_matched_text = (int) (yy_cp - yyg->yytext_ptr) - 1; /* Undo the effects of YY_DO_BEFORE_ACTION. */ *yy_cp = yyg->yy_hold_char; YY_RESTORE_YY_MORE_OFFSET if ( YY_CURRENT_BUFFER_LVALUE->yy_buffer_status == YY_BUFFER_NEW ) { /* We're scanning a new file or input source. It's * possible that this happened because the user * just pointed yyin at a new source and called * yylex(). If so, then we have to assure * consistency between YY_CURRENT_BUFFER and our * globals. Here is the right place to do so, because * this is the first action (other than possibly a * back-up) that will match for the new input source. */ yyg->yy_n_chars = YY_CURRENT_BUFFER_LVALUE->yy_n_chars; YY_CURRENT_BUFFER_LVALUE->yy_input_file = yyin; YY_CURRENT_BUFFER_LVALUE->yy_buffer_status = YY_BUFFER_NORMAL; } /* Note that here we test for yy_c_buf_p "<=" to the position * of the first EOB in the buffer, since yy_c_buf_p will * already have been incremented past the NUL character * (since all states make transitions on EOB to the * end-of-buffer state). Contrast this with the test * in input(). */ if ( yyg->yy_c_buf_p <= &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[yyg->yy_n_chars] ) { /* This was really a NUL. */ yy_state_type yy_next_state; yyg->yy_c_buf_p = yyg->yytext_ptr + yy_amount_of_matched_text; yy_current_state = yy_get_previous_state( yyscanner ); /* Okay, we're now positioned to make the NUL * transition. We couldn't have * yy_get_previous_state() go ahead and do it * for us because it doesn't know how to deal * with the possibility of jamming (and we don't * want to build jamming into it because then it * will run more slowly). */ yy_next_state = yy_try_NUL_trans( yy_current_state , yyscanner); yy_bp = yyg->yytext_ptr + YY_MORE_ADJ; if ( yy_next_state ) { /* Consume the NUL. */ yy_cp = ++yyg->yy_c_buf_p; yy_current_state = yy_next_state; goto yy_match; } else { yy_cp = yyg->yy_c_buf_p; goto yy_find_action; } } else switch ( yy_get_next_buffer( yyscanner ) ) { case EOB_ACT_END_OF_FILE: { yyg->yy_did_buffer_switch_on_eof = 0; if ( yywrap( yyscanner ) ) { /* Note: because we've taken care in * yy_get_next_buffer() to have set up * yytext, we can now set up * yy_c_buf_p so that if some total * hoser (like flex itself) wants to * call the scanner after we return the * YY_NULL, it'll still work - another * YY_NULL will get returned. */ yyg->yy_c_buf_p = yyg->yytext_ptr + YY_MORE_ADJ; yy_act = YY_STATE_EOF(YY_START); goto do_action; } else { if ( ! yyg->yy_did_buffer_switch_on_eof ) YY_NEW_FILE; } break; } case EOB_ACT_CONTINUE_SCAN: yyg->yy_c_buf_p = yyg->yytext_ptr + yy_amount_of_matched_text; yy_current_state = yy_get_previous_state( yyscanner ); yy_cp = yyg->yy_c_buf_p; yy_bp = yyg->yytext_ptr + YY_MORE_ADJ; goto yy_match; case EOB_ACT_LAST_MATCH: yyg->yy_c_buf_p = &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[yyg->yy_n_chars]; yy_current_state = yy_get_previous_state( yyscanner ); yy_cp = yyg->yy_c_buf_p; yy_bp = yyg->yytext_ptr + YY_MORE_ADJ; goto yy_find_action; } break; } default: YY_FATAL_ERROR( "fatal flex scanner internal error--no action found" ); } /* end of action switch */ } /* end of scanning one token */ } /* end of user's declarations */ } /* end of yylex */ /* yy_get_next_buffer - try to read in a new buffer * * Returns a code representing an action: * EOB_ACT_LAST_MATCH - * EOB_ACT_CONTINUE_SCAN - continue scanning from current position * EOB_ACT_END_OF_FILE - end of file */ static int yy_get_next_buffer (yyscan_t yyscanner) { struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; char *dest = YY_CURRENT_BUFFER_LVALUE->yy_ch_buf; char *source = yyg->yytext_ptr; int number_to_move, i; int ret_val; if ( yyg->yy_c_buf_p > &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[yyg->yy_n_chars + 1] ) YY_FATAL_ERROR( "fatal flex scanner internal error--end of buffer missed" ); if ( YY_CURRENT_BUFFER_LVALUE->yy_fill_buffer == 0 ) { /* Don't try to fill the buffer, so this is an EOF. */ if ( yyg->yy_c_buf_p - yyg->yytext_ptr - YY_MORE_ADJ == 1 ) { /* We matched a single character, the EOB, so * treat this as a final EOF. */ return EOB_ACT_END_OF_FILE; } else { /* We matched some text prior to the EOB, first * process it. */ return EOB_ACT_LAST_MATCH; } } /* Try to read more data. */ /* First move last chars to start of buffer. */ number_to_move = (int) (yyg->yy_c_buf_p - yyg->yytext_ptr - 1); for ( i = 0; i < number_to_move; ++i ) *(dest++) = *(source++); if ( YY_CURRENT_BUFFER_LVALUE->yy_buffer_status == YY_BUFFER_EOF_PENDING ) /* don't do the read, it's not guaranteed to return an EOF, * just force an EOF */ YY_CURRENT_BUFFER_LVALUE->yy_n_chars = yyg->yy_n_chars = 0; else { int num_to_read = YY_CURRENT_BUFFER_LVALUE->yy_buf_size - number_to_move - 1; while ( num_to_read <= 0 ) { /* Not enough room in the buffer - grow it. */ /* just a shorter name for the current buffer */ YY_BUFFER_STATE b = YY_CURRENT_BUFFER_LVALUE; int yy_c_buf_p_offset = (int) (yyg->yy_c_buf_p - b->yy_ch_buf); if ( b->yy_is_our_buffer ) { int new_size = b->yy_buf_size * 2; if ( new_size <= 0 ) b->yy_buf_size += b->yy_buf_size / 8; else b->yy_buf_size *= 2; b->yy_ch_buf = (char *) /* Include room in for 2 EOB chars. */ yyrealloc( (void *) b->yy_ch_buf, (yy_size_t) (b->yy_buf_size + 2) , yyscanner ); } else /* Can't grow it, we don't own it. */ b->yy_ch_buf = NULL; if ( ! b->yy_ch_buf ) YY_FATAL_ERROR( "fatal error - scanner input buffer overflow" ); yyg->yy_c_buf_p = &b->yy_ch_buf[yy_c_buf_p_offset]; num_to_read = YY_CURRENT_BUFFER_LVALUE->yy_buf_size - number_to_move - 1; } if ( num_to_read > YY_READ_BUF_SIZE ) num_to_read = YY_READ_BUF_SIZE; /* Read in more data. */ YY_INPUT( (&YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[number_to_move]), yyg->yy_n_chars, num_to_read ); YY_CURRENT_BUFFER_LVALUE->yy_n_chars = yyg->yy_n_chars; } if ( yyg->yy_n_chars == 0 ) { if ( number_to_move == YY_MORE_ADJ ) { ret_val = EOB_ACT_END_OF_FILE; yyrestart( yyin , yyscanner); } else { ret_val = EOB_ACT_LAST_MATCH; YY_CURRENT_BUFFER_LVALUE->yy_buffer_status = YY_BUFFER_EOF_PENDING; } } else ret_val = EOB_ACT_CONTINUE_SCAN; if ((yyg->yy_n_chars + number_to_move) > YY_CURRENT_BUFFER_LVALUE->yy_buf_size) { /* Extend the array by 50%, plus the number we really need. */ int new_size = yyg->yy_n_chars + number_to_move + (yyg->yy_n_chars >> 1); YY_CURRENT_BUFFER_LVALUE->yy_ch_buf = (char *) yyrealloc( (void *) YY_CURRENT_BUFFER_LVALUE->yy_ch_buf, (yy_size_t) new_size , yyscanner ); if ( ! YY_CURRENT_BUFFER_LVALUE->yy_ch_buf ) YY_FATAL_ERROR( "out of dynamic memory in yy_get_next_buffer()" ); /* "- 2" to take care of EOB's */ YY_CURRENT_BUFFER_LVALUE->yy_buf_size = (int) (new_size - 2); } yyg->yy_n_chars += number_to_move; YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[yyg->yy_n_chars] = YY_END_OF_BUFFER_CHAR; YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[yyg->yy_n_chars + 1] = YY_END_OF_BUFFER_CHAR; yyg->yytext_ptr = &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[0]; return ret_val; } /* yy_get_previous_state - get the state just before the EOB char was reached */ static yy_state_type yy_get_previous_state (yyscan_t yyscanner) { yy_state_type yy_current_state; char *yy_cp; struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; yy_current_state = yyg->yy_start; for ( yy_cp = yyg->yytext_ptr + YY_MORE_ADJ; yy_cp < yyg->yy_c_buf_p; ++yy_cp ) { YY_CHAR yy_c = (*yy_cp ? yy_ec[YY_SC_TO_UI(*yy_cp)] : 1); if ( yy_accept[yy_current_state] ) { yyg->yy_last_accepting_state = yy_current_state; yyg->yy_last_accepting_cpos = yy_cp; } while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state ) { yy_current_state = (int) yy_def[yy_current_state]; if ( yy_current_state >= 171 ) yy_c = yy_meta[yy_c]; } yy_current_state = yy_nxt[yy_base[yy_current_state] + yy_c]; } return yy_current_state; } /* yy_try_NUL_trans - try to make a transition on the NUL character * * synopsis * next_state = yy_try_NUL_trans( current_state ); */ static yy_state_type yy_try_NUL_trans (yy_state_type yy_current_state , yyscan_t yyscanner) { int yy_is_jam; struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; /* This var may be unused depending upon options. */ char *yy_cp = yyg->yy_c_buf_p; YY_CHAR yy_c = 1; if ( yy_accept[yy_current_state] ) { yyg->yy_last_accepting_state = yy_current_state; yyg->yy_last_accepting_cpos = yy_cp; } while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state ) { yy_current_state = (int) yy_def[yy_current_state]; if ( yy_current_state >= 171 ) yy_c = yy_meta[yy_c]; } yy_current_state = yy_nxt[yy_base[yy_current_state] + yy_c]; yy_is_jam = (yy_current_state == 170); (void)yyg; return yy_is_jam ? 0 : yy_current_state; } #ifndef YY_NO_UNPUT #endif #ifndef YY_NO_INPUT #ifdef __cplusplus static int yyinput (yyscan_t yyscanner) #else static int input (yyscan_t yyscanner) #endif { int c; struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; *yyg->yy_c_buf_p = yyg->yy_hold_char; if ( *yyg->yy_c_buf_p == YY_END_OF_BUFFER_CHAR ) { /* yy_c_buf_p now points to the character we want to return. * If this occurs *before* the EOB characters, then it's a * valid NUL; if not, then we've hit the end of the buffer. */ if ( yyg->yy_c_buf_p < &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[yyg->yy_n_chars] ) /* This was really a NUL. */ *yyg->yy_c_buf_p = '\0'; else { /* need more input */ int offset = (int) (yyg->yy_c_buf_p - yyg->yytext_ptr); ++yyg->yy_c_buf_p; switch ( yy_get_next_buffer( yyscanner ) ) { case EOB_ACT_LAST_MATCH: /* This happens because yy_g_n_b() * sees that we've accumulated a * token and flags that we need to * try matching the token before * proceeding. But for input(), * there's no matching to consider. * So convert the EOB_ACT_LAST_MATCH * to EOB_ACT_END_OF_FILE. */ /* Reset buffer status. */ yyrestart( yyin , yyscanner); /*FALLTHROUGH*/ case EOB_ACT_END_OF_FILE: { if ( yywrap( yyscanner ) ) return 0; if ( ! yyg->yy_did_buffer_switch_on_eof ) YY_NEW_FILE; #ifdef __cplusplus return yyinput(yyscanner); #else return input(yyscanner); #endif } case EOB_ACT_CONTINUE_SCAN: yyg->yy_c_buf_p = yyg->yytext_ptr + offset; break; } } } c = *(unsigned char *) yyg->yy_c_buf_p; /* cast for 8-bit char's */ *yyg->yy_c_buf_p = '\0'; /* preserve yytext */ yyg->yy_hold_char = *++yyg->yy_c_buf_p; return c; } #endif /* ifndef YY_NO_INPUT */ /** Immediately switch to a different input stream. * @param input_file A readable stream. * @param yyscanner The scanner object. * @note This function does not reset the start condition to @c INITIAL . */ void yyrestart (FILE * input_file , yyscan_t yyscanner) { struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; if ( ! YY_CURRENT_BUFFER ){ yyensure_buffer_stack (yyscanner); YY_CURRENT_BUFFER_LVALUE = yy_create_buffer( yyin, YY_BUF_SIZE , yyscanner); } yy_init_buffer( YY_CURRENT_BUFFER, input_file , yyscanner); yy_load_buffer_state( yyscanner ); } /** Switch to a different input buffer. * @param new_buffer The new input buffer. * @param yyscanner The scanner object. */ void yy_switch_to_buffer (YY_BUFFER_STATE new_buffer , yyscan_t yyscanner) { struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; /* TODO. We should be able to replace this entire function body * with * yypop_buffer_state(); * yypush_buffer_state(new_buffer); */ yyensure_buffer_stack (yyscanner); if ( YY_CURRENT_BUFFER == new_buffer ) return; if ( YY_CURRENT_BUFFER ) { /* Flush out information for old buffer. */ *yyg->yy_c_buf_p = yyg->yy_hold_char; YY_CURRENT_BUFFER_LVALUE->yy_buf_pos = yyg->yy_c_buf_p; YY_CURRENT_BUFFER_LVALUE->yy_n_chars = yyg->yy_n_chars; } YY_CURRENT_BUFFER_LVALUE = new_buffer; yy_load_buffer_state( yyscanner ); /* We don't actually know whether we did this switch during * EOF (yywrap()) processing, but the only time this flag * is looked at is after yywrap() is called, so it's safe * to go ahead and always set it. */ yyg->yy_did_buffer_switch_on_eof = 1; } static void yy_load_buffer_state (yyscan_t yyscanner) { struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; yyg->yy_n_chars = YY_CURRENT_BUFFER_LVALUE->yy_n_chars; yyg->yytext_ptr = yyg->yy_c_buf_p = YY_CURRENT_BUFFER_LVALUE->yy_buf_pos; yyin = YY_CURRENT_BUFFER_LVALUE->yy_input_file; yyg->yy_hold_char = *yyg->yy_c_buf_p; } /** Allocate and initialize an input buffer state. * @param file A readable stream. * @param size The character buffer size in bytes. When in doubt, use @c YY_BUF_SIZE. * @param yyscanner The scanner object. * @return the allocated buffer state. */ YY_BUFFER_STATE yy_create_buffer (FILE * file, int size , yyscan_t yyscanner) { YY_BUFFER_STATE b; b = (YY_BUFFER_STATE) yyalloc( sizeof( struct yy_buffer_state ) , yyscanner ); if ( ! b ) YY_FATAL_ERROR( "out of dynamic memory in yy_create_buffer()" ); b->yy_buf_size = size; /* yy_ch_buf has to be 2 characters longer than the size given because * we need to put in 2 end-of-buffer characters. */ b->yy_ch_buf = (char *) yyalloc( (yy_size_t) (b->yy_buf_size + 2) , yyscanner ); if ( ! b->yy_ch_buf ) YY_FATAL_ERROR( "out of dynamic memory in yy_create_buffer()" ); b->yy_is_our_buffer = 1; yy_init_buffer( b, file , yyscanner); return b; } /** Destroy the buffer. * @param b a buffer created with yy_create_buffer() * @param yyscanner The scanner object. */ void yy_delete_buffer (YY_BUFFER_STATE b , yyscan_t yyscanner) { struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; if ( ! b ) return; if ( b == YY_CURRENT_BUFFER ) /* Not sure if we should pop here. */ YY_CURRENT_BUFFER_LVALUE = (YY_BUFFER_STATE) 0; if ( b->yy_is_our_buffer ) yyfree( (void *) b->yy_ch_buf , yyscanner ); yyfree( (void *) b , yyscanner ); } /* Initializes or reinitializes a buffer. * This function is sometimes called more than once on the same buffer, * such as during a yyrestart() or at EOF. */ static void yy_init_buffer (YY_BUFFER_STATE b, FILE * file , yyscan_t yyscanner) { int oerrno = errno; struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; yy_flush_buffer( b , yyscanner); b->yy_input_file = file; b->yy_fill_buffer = 1; /* If b is the current buffer, then yy_init_buffer was _probably_ * called from yyrestart() or through yy_get_next_buffer. * In that case, we don't want to reset the lineno or column. */ if (b != YY_CURRENT_BUFFER){ b->yy_bs_lineno = 1; b->yy_bs_column = 0; } b->yy_is_interactive = file ? (isatty( fileno(file) ) > 0) : 0; errno = oerrno; } /** Discard all buffered characters. On the next scan, YY_INPUT will be called. * @param b the buffer state to be flushed, usually @c YY_CURRENT_BUFFER. * @param yyscanner The scanner object. */ void yy_flush_buffer (YY_BUFFER_STATE b , yyscan_t yyscanner) { struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; if ( ! b ) return; b->yy_n_chars = 0; /* We always need two end-of-buffer characters. The first causes * a transition to the end-of-buffer state. The second causes * a jam in that state. */ b->yy_ch_buf[0] = YY_END_OF_BUFFER_CHAR; b->yy_ch_buf[1] = YY_END_OF_BUFFER_CHAR; b->yy_buf_pos = &b->yy_ch_buf[0]; b->yy_at_bol = 1; b->yy_buffer_status = YY_BUFFER_NEW; if ( b == YY_CURRENT_BUFFER ) yy_load_buffer_state( yyscanner ); } /** Pushes the new state onto the stack. The new state becomes * the current state. This function will allocate the stack * if necessary. * @param new_buffer The new state. * @param yyscanner The scanner object. */ void yypush_buffer_state (YY_BUFFER_STATE new_buffer , yyscan_t yyscanner) { struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; if (new_buffer == NULL) return; yyensure_buffer_stack(yyscanner); /* This block is copied from yy_switch_to_buffer. */ if ( YY_CURRENT_BUFFER ) { /* Flush out information for old buffer. */ *yyg->yy_c_buf_p = yyg->yy_hold_char; YY_CURRENT_BUFFER_LVALUE->yy_buf_pos = yyg->yy_c_buf_p; YY_CURRENT_BUFFER_LVALUE->yy_n_chars = yyg->yy_n_chars; } /* Only push if top exists. Otherwise, replace top. */ if (YY_CURRENT_BUFFER) yyg->yy_buffer_stack_top++; YY_CURRENT_BUFFER_LVALUE = new_buffer; /* copied from yy_switch_to_buffer. */ yy_load_buffer_state( yyscanner ); yyg->yy_did_buffer_switch_on_eof = 1; } /** Removes and deletes the top of the stack, if present. * The next element becomes the new top. * @param yyscanner The scanner object. */ void yypop_buffer_state (yyscan_t yyscanner) { struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; if (!YY_CURRENT_BUFFER) return; yy_delete_buffer(YY_CURRENT_BUFFER , yyscanner); YY_CURRENT_BUFFER_LVALUE = NULL; if (yyg->yy_buffer_stack_top > 0) --yyg->yy_buffer_stack_top; if (YY_CURRENT_BUFFER) { yy_load_buffer_state( yyscanner ); yyg->yy_did_buffer_switch_on_eof = 1; } } /* Allocates the stack if it does not exist. * Guarantees space for at least one push. */ static void yyensure_buffer_stack (yyscan_t yyscanner) { yy_size_t num_to_alloc; struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; if (!yyg->yy_buffer_stack) { /* First allocation is just for 2 elements, since we don't know if this * scanner will even need a stack. We use 2 instead of 1 to avoid an * immediate realloc on the next call. */ num_to_alloc = 1; /* After all that talk, this was set to 1 anyways... */ yyg->yy_buffer_stack = (struct yy_buffer_state**)yyalloc (num_to_alloc * sizeof(struct yy_buffer_state*) , yyscanner); if ( ! yyg->yy_buffer_stack ) YY_FATAL_ERROR( "out of dynamic memory in yyensure_buffer_stack()" ); memset(yyg->yy_buffer_stack, 0, num_to_alloc * sizeof(struct yy_buffer_state*)); yyg->yy_buffer_stack_max = num_to_alloc; yyg->yy_buffer_stack_top = 0; return; } if (yyg->yy_buffer_stack_top >= (yyg->yy_buffer_stack_max) - 1){ /* Increase the buffer to prepare for a possible push. */ yy_size_t grow_size = 8 /* arbitrary grow size */; num_to_alloc = yyg->yy_buffer_stack_max + grow_size; yyg->yy_buffer_stack = (struct yy_buffer_state**)yyrealloc (yyg->yy_buffer_stack, num_to_alloc * sizeof(struct yy_buffer_state*) , yyscanner); if ( ! yyg->yy_buffer_stack ) YY_FATAL_ERROR( "out of dynamic memory in yyensure_buffer_stack()" ); /* zero only the new slots.*/ memset(yyg->yy_buffer_stack + yyg->yy_buffer_stack_max, 0, grow_size * sizeof(struct yy_buffer_state*)); yyg->yy_buffer_stack_max = num_to_alloc; } } /** Setup the input buffer state to scan directly from a user-specified character buffer. * @param base the character buffer * @param size the size in bytes of the character buffer * @param yyscanner The scanner object. * @return the newly allocated buffer state object. */ YY_BUFFER_STATE yy_scan_buffer (char * base, yy_size_t size , yyscan_t yyscanner) { YY_BUFFER_STATE b; if ( size < 2 || base[size-2] != YY_END_OF_BUFFER_CHAR || base[size-1] != YY_END_OF_BUFFER_CHAR ) /* They forgot to leave room for the EOB's. */ return NULL; b = (YY_BUFFER_STATE) yyalloc( sizeof( struct yy_buffer_state ) , yyscanner ); if ( ! b ) YY_FATAL_ERROR( "out of dynamic memory in yy_scan_buffer()" ); b->yy_buf_size = (int) (size - 2); /* "- 2" to take care of EOB's */ b->yy_buf_pos = b->yy_ch_buf = base; b->yy_is_our_buffer = 0; b->yy_input_file = NULL; b->yy_n_chars = b->yy_buf_size; b->yy_is_interactive = 0; b->yy_at_bol = 1; b->yy_fill_buffer = 0; b->yy_buffer_status = YY_BUFFER_NEW; yy_switch_to_buffer( b , yyscanner ); return b; } /** Setup the input buffer state to scan a string. The next call to yylex() will * scan from a @e copy of @a str. * @param yystr a NUL-terminated string to scan * @param yyscanner The scanner object. * @return the newly allocated buffer state object. * @note If you want to scan bytes that may contain NUL values, then use * yy_scan_bytes() instead. */ YY_BUFFER_STATE yy_scan_string (const char * yystr , yyscan_t yyscanner) { return yy_scan_bytes( yystr, (int) strlen(yystr) , yyscanner); } /** Setup the input buffer state to scan the given bytes. The next call to yylex() will * scan from a @e copy of @a bytes. * @param yybytes the byte buffer to scan * @param _yybytes_len the number of bytes in the buffer pointed to by @a bytes. * @param yyscanner The scanner object. * @return the newly allocated buffer state object. */ YY_BUFFER_STATE yy_scan_bytes (const char * yybytes, int _yybytes_len , yyscan_t yyscanner) { YY_BUFFER_STATE b; char *buf; yy_size_t n; int i; /* Get memory for full buffer, including space for trailing EOB's. */ n = (yy_size_t) (_yybytes_len + 2); buf = (char *) yyalloc( n , yyscanner ); if ( ! buf ) YY_FATAL_ERROR( "out of dynamic memory in yy_scan_bytes()" ); for ( i = 0; i < _yybytes_len; ++i ) buf[i] = yybytes[i]; buf[_yybytes_len] = buf[_yybytes_len+1] = YY_END_OF_BUFFER_CHAR; b = yy_scan_buffer( buf, n , yyscanner); if ( ! b ) YY_FATAL_ERROR( "bad buffer in yy_scan_bytes()" ); /* It's okay to grow etc. this buffer, and we should throw it * away when we're done. */ b->yy_is_our_buffer = 1; return b; } static void yy_push_state (int _new_state , yyscan_t yyscanner) { struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; if ( yyg->yy_start_stack_ptr >= yyg->yy_start_stack_depth ) { yy_size_t new_size; yyg->yy_start_stack_depth += YY_START_STACK_INCR; new_size = (yy_size_t) yyg->yy_start_stack_depth * sizeof( int ); if ( ! yyg->yy_start_stack ) yyg->yy_start_stack = (int *) yyalloc( new_size , yyscanner ); else yyg->yy_start_stack = (int *) yyrealloc( (void *) yyg->yy_start_stack, new_size , yyscanner ); if ( ! yyg->yy_start_stack ) YY_FATAL_ERROR( "out of memory expanding start-condition stack" ); } yyg->yy_start_stack[yyg->yy_start_stack_ptr++] = YY_START; BEGIN(_new_state); } static void yy_pop_state (yyscan_t yyscanner) { struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; if ( --yyg->yy_start_stack_ptr < 0 ) YY_FATAL_ERROR( "start-condition stack underflow" ); BEGIN(yyg->yy_start_stack[yyg->yy_start_stack_ptr]); } static int yy_top_state (yyscan_t yyscanner) { struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; return yyg->yy_start_stack[yyg->yy_start_stack_ptr - 1]; } #ifndef YY_EXIT_FAILURE #define YY_EXIT_FAILURE 2 #endif static void yynoreturn yy_fatal_error (const char* msg , yyscan_t yyscanner) { struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; (void)yyg; fprintf( stderr, "%s\n", msg ); exit( YY_EXIT_FAILURE ); } /* Redefine yyless() so it works in section 3 code. */ #undef yyless #define yyless(n) \ do \ { \ /* Undo effects of setting up yytext. */ \ int yyless_macro_arg = (n); \ YY_LESS_LINENO(yyless_macro_arg);\ yytext[yyleng] = yyg->yy_hold_char; \ yyg->yy_c_buf_p = yytext + yyless_macro_arg; \ yyg->yy_hold_char = *yyg->yy_c_buf_p; \ *yyg->yy_c_buf_p = '\0'; \ yyleng = yyless_macro_arg; \ } \ while ( 0 ) /* Accessor methods (get/set functions) to struct members. */ /** Get the user-defined data for this scanner. * @param yyscanner The scanner object. */ YY_EXTRA_TYPE yyget_extra (yyscan_t yyscanner) { struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; return yyextra; } /** Get the current line number. * @param yyscanner The scanner object. */ int yyget_lineno (yyscan_t yyscanner) { struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; if (! YY_CURRENT_BUFFER) return 0; return yylineno; } /** Get the current column number. * @param yyscanner The scanner object. */ int yyget_column (yyscan_t yyscanner) { struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; if (! YY_CURRENT_BUFFER) return 0; return yycolumn; } /** Get the input stream. * @param yyscanner The scanner object. */ FILE *yyget_in (yyscan_t yyscanner) { struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; return yyin; } /** Get the output stream. * @param yyscanner The scanner object. */ FILE *yyget_out (yyscan_t yyscanner) { struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; return yyout; } /** Get the length of the current token. * @param yyscanner The scanner object. */ int yyget_leng (yyscan_t yyscanner) { struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; return yyleng; } /** Get the current token. * @param yyscanner The scanner object. */ char *yyget_text (yyscan_t yyscanner) { struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; return yytext; } /** Set the user-defined data. This data is never touched by the scanner. * @param user_defined The data to be associated with this scanner. * @param yyscanner The scanner object. */ void yyset_extra (YY_EXTRA_TYPE user_defined , yyscan_t yyscanner) { struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; yyextra = user_defined ; } /** Set the current line number. * @param _line_number line number * @param yyscanner The scanner object. */ void yyset_lineno (int _line_number , yyscan_t yyscanner) { struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; /* lineno is only valid if an input buffer exists. */ if (! YY_CURRENT_BUFFER ) YY_FATAL_ERROR( "yyset_lineno called with no buffer" ); yylineno = _line_number; } /** Set the current column. * @param _column_no column number * @param yyscanner The scanner object. */ void yyset_column (int _column_no , yyscan_t yyscanner) { struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; /* column is only valid if an input buffer exists. */ if (! YY_CURRENT_BUFFER ) YY_FATAL_ERROR( "yyset_column called with no buffer" ); yycolumn = _column_no; } /** Set the input stream. This does not discard the current * input buffer. * @param _in_str A readable stream. * @param yyscanner The scanner object. * @see yy_switch_to_buffer */ void yyset_in (FILE * _in_str , yyscan_t yyscanner) { struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; yyin = _in_str ; } void yyset_out (FILE * _out_str , yyscan_t yyscanner) { struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; yyout = _out_str ; } int yyget_debug (yyscan_t yyscanner) { struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; return yy_flex_debug; } void yyset_debug (int _bdebug , yyscan_t yyscanner) { struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; yy_flex_debug = _bdebug ; } /* Accessor methods for yylval and yylloc */ YYSTYPE * yyget_lval (yyscan_t yyscanner) { struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; return yylval; } void yyset_lval (YYSTYPE * yylval_param , yyscan_t yyscanner) { struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; yylval = yylval_param; } YYLTYPE *yyget_lloc (yyscan_t yyscanner) { struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; return yylloc; } void yyset_lloc (YYLTYPE * yylloc_param , yyscan_t yyscanner) { struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; yylloc = yylloc_param; } /* User-visible API */ /* yylex_init is special because it creates the scanner itself, so it is * the ONLY reentrant function that doesn't take the scanner as the last argument. * That's why we explicitly handle the declaration, instead of using our macros. */ int yylex_init(yyscan_t* ptr_yy_globals) { if (ptr_yy_globals == NULL){ errno = EINVAL; return 1; } *ptr_yy_globals = (yyscan_t) yyalloc ( sizeof( struct yyguts_t ), NULL ); if (*ptr_yy_globals == NULL){ errno = ENOMEM; return 1; } /* By setting to 0xAA, we expose bugs in yy_init_globals. Leave at 0x00 for releases. */ memset(*ptr_yy_globals,0x00,sizeof(struct yyguts_t)); return yy_init_globals ( *ptr_yy_globals ); } /* yylex_init_extra has the same functionality as yylex_init, but follows the * convention of taking the scanner as the last argument. Note however, that * this is a *pointer* to a scanner, as it will be allocated by this call (and * is the reason, too, why this function also must handle its own declaration). * The user defined value in the first argument will be available to yyalloc in * the yyextra field. */ int yylex_init_extra( YY_EXTRA_TYPE yy_user_defined, yyscan_t* ptr_yy_globals ) { struct yyguts_t dummy_yyguts; yyset_extra (yy_user_defined, &dummy_yyguts); if (ptr_yy_globals == NULL){ errno = EINVAL; return 1; } *ptr_yy_globals = (yyscan_t) yyalloc ( sizeof( struct yyguts_t ), &dummy_yyguts ); if (*ptr_yy_globals == NULL){ errno = ENOMEM; return 1; } /* By setting to 0xAA, we expose bugs in yy_init_globals. Leave at 0x00 for releases. */ memset(*ptr_yy_globals,0x00,sizeof(struct yyguts_t)); yyset_extra (yy_user_defined, *ptr_yy_globals); return yy_init_globals ( *ptr_yy_globals ); } static int yy_init_globals (yyscan_t yyscanner) { struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; /* Initialization is the same as for the non-reentrant scanner. * This function is called from yylex_destroy(), so don't allocate here. */ yyg->yy_buffer_stack = NULL; yyg->yy_buffer_stack_top = 0; yyg->yy_buffer_stack_max = 0; yyg->yy_c_buf_p = NULL; yyg->yy_init = 0; yyg->yy_start = 0; yyg->yy_start_stack_ptr = 0; yyg->yy_start_stack_depth = 0; yyg->yy_start_stack = NULL; /* Defined in main.c */ #ifdef YY_STDINIT yyin = stdin; yyout = stdout; #else yyin = NULL; yyout = NULL; #endif /* For future reference: Set errno on error, since we are called by * yylex_init() */ return 0; } /* yylex_destroy is for both reentrant and non-reentrant scanners. */ int yylex_destroy (yyscan_t yyscanner) { struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; /* Pop the buffer stack, destroying each element. */ while(YY_CURRENT_BUFFER){ yy_delete_buffer( YY_CURRENT_BUFFER , yyscanner ); YY_CURRENT_BUFFER_LVALUE = NULL; yypop_buffer_state(yyscanner); } /* Destroy the stack itself. */ yyfree(yyg->yy_buffer_stack , yyscanner); yyg->yy_buffer_stack = NULL; /* Destroy the start condition stack. */ yyfree( yyg->yy_start_stack , yyscanner ); yyg->yy_start_stack = NULL; /* Reset the globals. This is important in a non-reentrant scanner so the next time * yylex() is called, initialization will occur. */ yy_init_globals( yyscanner); /* Destroy the main struct (reentrant only). */ yyfree ( yyscanner , yyscanner ); yyscanner = NULL; return 0; } /* * Internal utility routines. */ #ifndef yytext_ptr static void yy_flex_strncpy (char* s1, const char * s2, int n , yyscan_t yyscanner) { struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; (void)yyg; int i; for ( i = 0; i < n; ++i ) s1[i] = s2[i]; } #endif #ifdef YY_NEED_STRLEN static int yy_flex_strlen (const char * s , yyscan_t yyscanner) { int n; for ( n = 0; s[n]; ++n ) ; return n; } #endif #define YYTABLES_NAME "yytables" #line 137 "src/lexer.l" /* perhaps these should be calls... */ /* "true" { return TRUE; } "false" { return FALSE; } "null" { return NULL; } */ static int try_exit(int c, int state, yyscan_t yyscanner) { char match = 0; int ret; switch (state) { case IN_PAREN: match = ret = ')'; break; case IN_BRACKET: match = ret = ']'; break; case IN_BRACE: match = ret = '}'; break; case IN_QQINTERP: match = ')'; ret = QQSTRING_INTERP_END; break; default: // may not be the best error to give return INVALID_CHARACTER; } assert(match); if (match == c) { yy_pop_state(yyscanner); return ret; } else { // FIXME: should we pop? Give a better error at least return INVALID_CHARACTER; } } static int enter(int c, int currstate, yyscan_t yyscanner) { int state = 0; switch (c) { case '(': state = IN_PAREN; break; case '[': state = IN_BRACKET; break; case '{': state = IN_BRACE; break; case QQSTRING_INTERP_START: state = IN_QQINTERP; break; } assert(state); yy_push_state(state, yyscanner); return c; } void* yyalloc(size_t sz, void* extra) { return jv_mem_alloc(sz); } void* yyrealloc(void* p, size_t sz, void* extra) { return jv_mem_realloc(p, sz); } void yyfree(void* p, void* extra) { jv_mem_free(p); } ================================================ FILE: src/lexer.h ================================================ #ifndef jq_yyHEADER_H #define jq_yyHEADER_H 1 #define jq_yyIN_HEADER 1 #line 6 "src/lexer.h" #line 8 "src/lexer.h" #define YY_INT_ALIGNED short int /* A lexical scanner generated by flex */ #define FLEX_SCANNER #define YY_FLEX_MAJOR_VERSION 2 #define YY_FLEX_MINOR_VERSION 6 #define YY_FLEX_SUBMINOR_VERSION 4 #if YY_FLEX_SUBMINOR_VERSION > 0 #define FLEX_BETA #endif #ifdef yy_create_buffer #define jq_yy_create_buffer_ALREADY_DEFINED #else #define yy_create_buffer jq_yy_create_buffer #endif #ifdef yy_delete_buffer #define jq_yy_delete_buffer_ALREADY_DEFINED #else #define yy_delete_buffer jq_yy_delete_buffer #endif #ifdef yy_scan_buffer #define jq_yy_scan_buffer_ALREADY_DEFINED #else #define yy_scan_buffer jq_yy_scan_buffer #endif #ifdef yy_scan_string #define jq_yy_scan_string_ALREADY_DEFINED #else #define yy_scan_string jq_yy_scan_string #endif #ifdef yy_scan_bytes #define jq_yy_scan_bytes_ALREADY_DEFINED #else #define yy_scan_bytes jq_yy_scan_bytes #endif #ifdef yy_init_buffer #define jq_yy_init_buffer_ALREADY_DEFINED #else #define yy_init_buffer jq_yy_init_buffer #endif #ifdef yy_flush_buffer #define jq_yy_flush_buffer_ALREADY_DEFINED #else #define yy_flush_buffer jq_yy_flush_buffer #endif #ifdef yy_load_buffer_state #define jq_yy_load_buffer_state_ALREADY_DEFINED #else #define yy_load_buffer_state jq_yy_load_buffer_state #endif #ifdef yy_switch_to_buffer #define jq_yy_switch_to_buffer_ALREADY_DEFINED #else #define yy_switch_to_buffer jq_yy_switch_to_buffer #endif #ifdef yypush_buffer_state #define jq_yypush_buffer_state_ALREADY_DEFINED #else #define yypush_buffer_state jq_yypush_buffer_state #endif #ifdef yypop_buffer_state #define jq_yypop_buffer_state_ALREADY_DEFINED #else #define yypop_buffer_state jq_yypop_buffer_state #endif #ifdef yyensure_buffer_stack #define jq_yyensure_buffer_stack_ALREADY_DEFINED #else #define yyensure_buffer_stack jq_yyensure_buffer_stack #endif #ifdef yylex #define jq_yylex_ALREADY_DEFINED #else #define yylex jq_yylex #endif #ifdef yyrestart #define jq_yyrestart_ALREADY_DEFINED #else #define yyrestart jq_yyrestart #endif #ifdef yylex_init #define jq_yylex_init_ALREADY_DEFINED #else #define yylex_init jq_yylex_init #endif #ifdef yylex_init_extra #define jq_yylex_init_extra_ALREADY_DEFINED #else #define yylex_init_extra jq_yylex_init_extra #endif #ifdef yylex_destroy #define jq_yylex_destroy_ALREADY_DEFINED #else #define yylex_destroy jq_yylex_destroy #endif #ifdef yyget_debug #define jq_yyget_debug_ALREADY_DEFINED #else #define yyget_debug jq_yyget_debug #endif #ifdef yyset_debug #define jq_yyset_debug_ALREADY_DEFINED #else #define yyset_debug jq_yyset_debug #endif #ifdef yyget_extra #define jq_yyget_extra_ALREADY_DEFINED #else #define yyget_extra jq_yyget_extra #endif #ifdef yyset_extra #define jq_yyset_extra_ALREADY_DEFINED #else #define yyset_extra jq_yyset_extra #endif #ifdef yyget_in #define jq_yyget_in_ALREADY_DEFINED #else #define yyget_in jq_yyget_in #endif #ifdef yyset_in #define jq_yyset_in_ALREADY_DEFINED #else #define yyset_in jq_yyset_in #endif #ifdef yyget_out #define jq_yyget_out_ALREADY_DEFINED #else #define yyget_out jq_yyget_out #endif #ifdef yyset_out #define jq_yyset_out_ALREADY_DEFINED #else #define yyset_out jq_yyset_out #endif #ifdef yyget_leng #define jq_yyget_leng_ALREADY_DEFINED #else #define yyget_leng jq_yyget_leng #endif #ifdef yyget_text #define jq_yyget_text_ALREADY_DEFINED #else #define yyget_text jq_yyget_text #endif #ifdef yyget_lineno #define jq_yyget_lineno_ALREADY_DEFINED #else #define yyget_lineno jq_yyget_lineno #endif #ifdef yyset_lineno #define jq_yyset_lineno_ALREADY_DEFINED #else #define yyset_lineno jq_yyset_lineno #endif #ifdef yyget_column #define jq_yyget_column_ALREADY_DEFINED #else #define yyget_column jq_yyget_column #endif #ifdef yyset_column #define jq_yyset_column_ALREADY_DEFINED #else #define yyset_column jq_yyset_column #endif #ifdef yywrap #define jq_yywrap_ALREADY_DEFINED #else #define yywrap jq_yywrap #endif #ifdef yyget_lval #define jq_yyget_lval_ALREADY_DEFINED #else #define yyget_lval jq_yyget_lval #endif #ifdef yyset_lval #define jq_yyset_lval_ALREADY_DEFINED #else #define yyset_lval jq_yyset_lval #endif #ifdef yyget_lloc #define jq_yyget_lloc_ALREADY_DEFINED #else #define yyget_lloc jq_yyget_lloc #endif #ifdef yyset_lloc #define jq_yyset_lloc_ALREADY_DEFINED #else #define yyset_lloc jq_yyset_lloc #endif #ifdef yyalloc #define jq_yyalloc_ALREADY_DEFINED #else #define yyalloc jq_yyalloc #endif #ifdef yyrealloc #define jq_yyrealloc_ALREADY_DEFINED #else #define yyrealloc jq_yyrealloc #endif #ifdef yyfree #define jq_yyfree_ALREADY_DEFINED #else #define yyfree jq_yyfree #endif /* First, we deal with platform-specific or compiler-specific issues. */ /* begin standard C headers. */ #include #include #include #include /* end standard C headers. */ /* flex integer type definitions */ #ifndef FLEXINT_H #define FLEXINT_H /* C99 systems have . Non-C99 systems may or may not. */ #if defined (__STDC_VERSION__) && __STDC_VERSION__ >= 199901L /* C99 says to define __STDC_LIMIT_MACROS before including stdint.h, * if you want the limit (max/min) macros for int types. */ #ifndef __STDC_LIMIT_MACROS #define __STDC_LIMIT_MACROS 1 #endif #include typedef int8_t flex_int8_t; typedef uint8_t flex_uint8_t; typedef int16_t flex_int16_t; typedef uint16_t flex_uint16_t; typedef int32_t flex_int32_t; typedef uint32_t flex_uint32_t; #else typedef signed char flex_int8_t; typedef short int flex_int16_t; typedef int flex_int32_t; typedef unsigned char flex_uint8_t; typedef unsigned short int flex_uint16_t; typedef unsigned int flex_uint32_t; /* Limits of integral types. */ #ifndef INT8_MIN #define INT8_MIN (-128) #endif #ifndef INT16_MIN #define INT16_MIN (-32767-1) #endif #ifndef INT32_MIN #define INT32_MIN (-2147483647-1) #endif #ifndef INT8_MAX #define INT8_MAX (127) #endif #ifndef INT16_MAX #define INT16_MAX (32767) #endif #ifndef INT32_MAX #define INT32_MAX (2147483647) #endif #ifndef UINT8_MAX #define UINT8_MAX (255U) #endif #ifndef UINT16_MAX #define UINT16_MAX (65535U) #endif #ifndef UINT32_MAX #define UINT32_MAX (4294967295U) #endif #ifndef SIZE_MAX #define SIZE_MAX (~(size_t)0) #endif #endif /* ! C99 */ #endif /* ! FLEXINT_H */ /* begin standard C++ headers. */ /* TODO: this is always defined, so inline it */ #define yyconst const #if defined(__GNUC__) && __GNUC__ >= 3 #define yynoreturn __attribute__((__noreturn__)) #else #define yynoreturn #endif /* An opaque pointer. */ #ifndef YY_TYPEDEF_YY_SCANNER_T #define YY_TYPEDEF_YY_SCANNER_T typedef void* yyscan_t; #endif /* For convenience, these vars (plus the bison vars far below) are macros in the reentrant scanner. */ #define yyin yyg->yyin_r #define yyout yyg->yyout_r #define yyextra yyg->yyextra_r #define yyleng yyg->yyleng_r #define yytext yyg->yytext_r #define yylineno (YY_CURRENT_BUFFER_LVALUE->yy_bs_lineno) #define yycolumn (YY_CURRENT_BUFFER_LVALUE->yy_bs_column) #define yy_flex_debug yyg->yy_flex_debug_r /* Size of default input buffer. */ #ifndef YY_BUF_SIZE #ifdef __ia64__ /* On IA-64, the buffer size is 16k, not 8k. * Moreover, YY_BUF_SIZE is 2*YY_READ_BUF_SIZE in the general case. * Ditto for the __ia64__ case accordingly. */ #define YY_BUF_SIZE 32768 #else #define YY_BUF_SIZE 16384 #endif /* __ia64__ */ #endif #ifndef YY_TYPEDEF_YY_BUFFER_STATE #define YY_TYPEDEF_YY_BUFFER_STATE typedef struct yy_buffer_state *YY_BUFFER_STATE; #endif #ifndef YY_TYPEDEF_YY_SIZE_T #define YY_TYPEDEF_YY_SIZE_T typedef size_t yy_size_t; #endif #ifndef YY_STRUCT_YY_BUFFER_STATE #define YY_STRUCT_YY_BUFFER_STATE struct yy_buffer_state { FILE *yy_input_file; char *yy_ch_buf; /* input buffer */ char *yy_buf_pos; /* current position in input buffer */ /* Size of input buffer in bytes, not including room for EOB * characters. */ int yy_buf_size; /* Number of characters read into yy_ch_buf, not including EOB * characters. */ int yy_n_chars; /* Whether we "own" the buffer - i.e., we know we created it, * and can realloc() it to grow it, and should free() it to * delete it. */ int yy_is_our_buffer; /* Whether this is an "interactive" input source; if so, and * if we're using stdio for input, then we want to use getc() * instead of fread(), to make sure we stop fetching input after * each newline. */ int yy_is_interactive; /* Whether we're considered to be at the beginning of a line. * If so, '^' rules will be active on the next match, otherwise * not. */ int yy_at_bol; int yy_bs_lineno; /**< The line count. */ int yy_bs_column; /**< The column count. */ /* Whether to try to fill the input buffer when we reach the * end of it. */ int yy_fill_buffer; int yy_buffer_status; }; #endif /* !YY_STRUCT_YY_BUFFER_STATE */ void yyrestart ( FILE *input_file , yyscan_t yyscanner ); void yy_switch_to_buffer ( YY_BUFFER_STATE new_buffer , yyscan_t yyscanner ); YY_BUFFER_STATE yy_create_buffer ( FILE *file, int size , yyscan_t yyscanner ); void yy_delete_buffer ( YY_BUFFER_STATE b , yyscan_t yyscanner ); void yy_flush_buffer ( YY_BUFFER_STATE b , yyscan_t yyscanner ); void yypush_buffer_state ( YY_BUFFER_STATE new_buffer , yyscan_t yyscanner ); void yypop_buffer_state ( yyscan_t yyscanner ); YY_BUFFER_STATE yy_scan_buffer ( char *base, yy_size_t size , yyscan_t yyscanner ); YY_BUFFER_STATE yy_scan_string ( const char *yy_str , yyscan_t yyscanner ); YY_BUFFER_STATE yy_scan_bytes ( const char *bytes, int len , yyscan_t yyscanner ); void *yyalloc ( yy_size_t , yyscan_t yyscanner ); void *yyrealloc ( void *, yy_size_t , yyscan_t yyscanner ); void yyfree ( void * , yyscan_t yyscanner ); /* Begin user sect3 */ #define jq_yywrap(yyscanner) (/*CONSTCOND*/1) #define YY_SKIP_YYWRAP #define yytext_ptr yytext_r #ifdef YY_HEADER_EXPORT_START_CONDITIONS #define INITIAL 0 #define IN_PAREN 1 #define IN_BRACKET 2 #define IN_BRACE 3 #define IN_QQINTERP 4 #define IN_QQSTRING 5 #define IN_COMMENT 6 #endif #ifndef YY_NO_UNISTD_H /* Special case for "unistd.h", since it is non-ANSI. We include it way * down here because we want the user's section 1 to have been scanned first. * The user has a chance to override it with an option. */ #include #endif #define YY_EXTRA_TYPE int int yylex_init (yyscan_t* scanner); int yylex_init_extra ( YY_EXTRA_TYPE user_defined, yyscan_t* scanner); /* Accessor methods to globals. These are made visible to non-reentrant scanners for convenience. */ int yylex_destroy ( yyscan_t yyscanner ); int yyget_debug ( yyscan_t yyscanner ); void yyset_debug ( int debug_flag , yyscan_t yyscanner ); YY_EXTRA_TYPE yyget_extra ( yyscan_t yyscanner ); void yyset_extra ( YY_EXTRA_TYPE user_defined , yyscan_t yyscanner ); FILE *yyget_in ( yyscan_t yyscanner ); void yyset_in ( FILE * _in_str , yyscan_t yyscanner ); FILE *yyget_out ( yyscan_t yyscanner ); void yyset_out ( FILE * _out_str , yyscan_t yyscanner ); int yyget_leng ( yyscan_t yyscanner ); char *yyget_text ( yyscan_t yyscanner ); int yyget_lineno ( yyscan_t yyscanner ); void yyset_lineno ( int _line_number , yyscan_t yyscanner ); int yyget_column ( yyscan_t yyscanner ); void yyset_column ( int _column_no , yyscan_t yyscanner ); YYSTYPE * yyget_lval ( yyscan_t yyscanner ); void yyset_lval ( YYSTYPE * yylval_param , yyscan_t yyscanner ); YYLTYPE *yyget_lloc ( yyscan_t yyscanner ); void yyset_lloc ( YYLTYPE * yylloc_param , yyscan_t yyscanner ); /* Macros after this point can all be overridden by user definitions in * section 1. */ #ifndef YY_SKIP_YYWRAP #ifdef __cplusplus extern "C" int yywrap ( yyscan_t yyscanner ); #else extern int yywrap ( yyscan_t yyscanner ); #endif #endif #ifndef yytext_ptr static void yy_flex_strncpy ( char *, const char *, int , yyscan_t yyscanner); #endif #ifdef YY_NEED_STRLEN static int yy_flex_strlen ( const char * , yyscan_t yyscanner); #endif #ifndef YY_NO_INPUT #endif /* Amount of stuff to slurp up with each read. */ #ifndef YY_READ_BUF_SIZE #ifdef __ia64__ /* On IA-64, the buffer size is 16k, not 8k */ #define YY_READ_BUF_SIZE 16384 #else #define YY_READ_BUF_SIZE 8192 #endif /* __ia64__ */ #endif /* Number of entries by which start-condition stack grows. */ #ifndef YY_START_STACK_INCR #define YY_START_STACK_INCR 25 #endif /* Default declaration of generated scanner - a define so the user can * easily add parameters. */ #ifndef YY_DECL #define YY_DECL_IS_OURS 1 extern int yylex \ (YYSTYPE * yylval_param, YYLTYPE * yylloc_param , yyscan_t yyscanner); #define YY_DECL int yylex \ (YYSTYPE * yylval_param, YYLTYPE * yylloc_param , yyscan_t yyscanner) #endif /* !YY_DECL */ /* yy_get_previous_state - get the state just before the EOB char was reached */ #undef YY_NEW_FILE #undef YY_FLUSH_BUFFER #undef yy_set_bol #undef yy_new_buffer #undef yy_set_interactive #undef YY_DO_BEFORE_ACTION #ifdef YY_DECL_IS_OURS #undef YY_DECL_IS_OURS #undef YY_DECL #endif #ifndef jq_yy_create_buffer_ALREADY_DEFINED #undef yy_create_buffer #endif #ifndef jq_yy_delete_buffer_ALREADY_DEFINED #undef yy_delete_buffer #endif #ifndef jq_yy_scan_buffer_ALREADY_DEFINED #undef yy_scan_buffer #endif #ifndef jq_yy_scan_string_ALREADY_DEFINED #undef yy_scan_string #endif #ifndef jq_yy_scan_bytes_ALREADY_DEFINED #undef yy_scan_bytes #endif #ifndef jq_yy_init_buffer_ALREADY_DEFINED #undef yy_init_buffer #endif #ifndef jq_yy_flush_buffer_ALREADY_DEFINED #undef yy_flush_buffer #endif #ifndef jq_yy_load_buffer_state_ALREADY_DEFINED #undef yy_load_buffer_state #endif #ifndef jq_yy_switch_to_buffer_ALREADY_DEFINED #undef yy_switch_to_buffer #endif #ifndef jq_yypush_buffer_state_ALREADY_DEFINED #undef yypush_buffer_state #endif #ifndef jq_yypop_buffer_state_ALREADY_DEFINED #undef yypop_buffer_state #endif #ifndef jq_yyensure_buffer_stack_ALREADY_DEFINED #undef yyensure_buffer_stack #endif #ifndef jq_yylex_ALREADY_DEFINED #undef yylex #endif #ifndef jq_yyrestart_ALREADY_DEFINED #undef yyrestart #endif #ifndef jq_yylex_init_ALREADY_DEFINED #undef yylex_init #endif #ifndef jq_yylex_init_extra_ALREADY_DEFINED #undef yylex_init_extra #endif #ifndef jq_yylex_destroy_ALREADY_DEFINED #undef yylex_destroy #endif #ifndef jq_yyget_debug_ALREADY_DEFINED #undef yyget_debug #endif #ifndef jq_yyset_debug_ALREADY_DEFINED #undef yyset_debug #endif #ifndef jq_yyget_extra_ALREADY_DEFINED #undef yyget_extra #endif #ifndef jq_yyset_extra_ALREADY_DEFINED #undef yyset_extra #endif #ifndef jq_yyget_in_ALREADY_DEFINED #undef yyget_in #endif #ifndef jq_yyset_in_ALREADY_DEFINED #undef yyset_in #endif #ifndef jq_yyget_out_ALREADY_DEFINED #undef yyget_out #endif #ifndef jq_yyset_out_ALREADY_DEFINED #undef yyset_out #endif #ifndef jq_yyget_leng_ALREADY_DEFINED #undef yyget_leng #endif #ifndef jq_yyget_text_ALREADY_DEFINED #undef yyget_text #endif #ifndef jq_yyget_lineno_ALREADY_DEFINED #undef yyget_lineno #endif #ifndef jq_yyset_lineno_ALREADY_DEFINED #undef yyset_lineno #endif #ifndef jq_yyget_column_ALREADY_DEFINED #undef yyget_column #endif #ifndef jq_yyset_column_ALREADY_DEFINED #undef yyset_column #endif #ifndef jq_yywrap_ALREADY_DEFINED #undef yywrap #endif #ifndef jq_yyget_lval_ALREADY_DEFINED #undef yyget_lval #endif #ifndef jq_yyset_lval_ALREADY_DEFINED #undef yyset_lval #endif #ifndef jq_yyget_lloc_ALREADY_DEFINED #undef yyget_lloc #endif #ifndef jq_yyset_lloc_ALREADY_DEFINED #undef yyset_lloc #endif #ifndef jq_yyalloc_ALREADY_DEFINED #undef yyalloc #endif #ifndef jq_yyrealloc_ALREADY_DEFINED #undef yyrealloc #endif #ifndef jq_yyfree_ALREADY_DEFINED #undef yyfree #endif #ifndef jq_yytext_ALREADY_DEFINED #undef yytext #endif #ifndef jq_yyleng_ALREADY_DEFINED #undef yyleng #endif #ifndef jq_yyin_ALREADY_DEFINED #undef yyin #endif #ifndef jq_yyout_ALREADY_DEFINED #undef yyout #endif #ifndef jq_yy_flex_debug_ALREADY_DEFINED #undef yy_flex_debug #endif #ifndef jq_yylineno_ALREADY_DEFINED #undef yylineno #endif #ifndef jq_yytables_fload_ALREADY_DEFINED #undef yytables_fload #endif #ifndef jq_yytables_destroy_ALREADY_DEFINED #undef yytables_destroy #endif #ifndef jq_yyTABLES_NAME_ALREADY_DEFINED #undef yyTABLES_NAME #endif #line 137 "src/lexer.l" #line 739 "src/lexer.h" #undef jq_yyIN_HEADER #endif /* jq_yyHEADER_H */ ================================================ FILE: src/lexer.l ================================================ %{ #include #include "jv_alloc.h" #include "compile.h" struct lexer_param; #include "parser.h" /* Generated by bison. */ #define YY_USER_ACTION \ do { \ yylloc->start = yyget_extra(yyscanner); \ yylloc->end = yylloc->start + yyleng; \ yyset_extra(yylloc->end, yyscanner); \ } while (0); %} %s IN_PAREN %s IN_BRACKET %s IN_BRACE %s IN_QQINTERP %x IN_QQSTRING %x IN_COMMENT %{ static int enter(int opening, int state, yyscan_t yyscanner); static int try_exit(int closing, int state, yyscan_t yyscanner); %} %option noyywrap nounput noinput nodefault %option noyyalloc noyyrealloc noyyfree %option reentrant %option extra-type="int" %option bison-bridge bison-locations %option prefix="jq_yy" %option stack %% "#" { yy_push_state(IN_COMMENT, yyscanner); } { \\(\\|\r?\n)|. { } \r?\n { yy_pop_state(yyscanner); } } <> { yy_pop_state(yyscanner); } "!=" { return NEQ; } "==" { return EQ; } "as" { return AS; } "import" { return IMPORT; } "include" { return INCLUDE; } "module" { return MODULE; } "def" { return DEF; } "if" { return IF; } "then" { return THEN; } "else" { return ELSE; } "elif" { return ELSE_IF; } "and" { return AND; } "or" { return OR; } "end" { return END; } "reduce" { return REDUCE; } "foreach" { return FOREACH; } "//" { return DEFINEDOR; } "try" { return TRY; } "catch" { return CATCH; } "label" { return LABEL; } "break" { return BREAK; } "$__loc__" { return LOC; } "|=" { return SETPIPE; } "+=" { return SETPLUS; } "-=" { return SETMINUS; } "*=" { return SETMULT; } "/=" { return SETDIV; } "%=" { return SETMOD; } "//=" { return SETDEFINEDOR; } "<=" { return LESSEQ; } ">=" { return GREATEREQ; } ".." { return REC; } "?//" { return ALTERNATION; } "."|"?"|"="|";"|","|":"|"|"|"+"|"-"|"*"|"/"|"%"|"\$"|"<"|">" { return yytext[0];} "["|"{"|"(" { return enter(yytext[0], YY_START, yyscanner); } "]"|"}"|")" { return try_exit(yytext[0], YY_START, yyscanner); } "@"[a-zA-Z0-9_]+ { yylval->literal = jv_string_sized(yytext + 1, yyleng - 1); return FORMAT; } ([0-9]+(\.[0-9]*)?|\.[0-9]+)([eE][+-]?[0-9]+)? { yylval->literal = jv_parse_sized(yytext, yyleng); return LITERAL; } "\"" { yy_push_state(IN_QQSTRING, yyscanner); return QQSTRING_START; } { "\\(" { return enter(QQSTRING_INTERP_START, YY_START, yyscanner); } "\"" { yy_pop_state(yyscanner); return QQSTRING_END; } (\\[^u(]|\\u[a-zA-Z0-9]{0,4})+ { /* pass escapes to the json parser */ jv escapes = jv_string_fmt("\"%.*s\"", (int)yyleng, yytext); yylval->literal = jv_parse_sized(jv_string_value(escapes), jv_string_length_bytes(jv_copy(escapes))); jv_free(escapes); return QQSTRING_TEXT; } [^\\\"]+ { yylval->literal = jv_string_sized(yytext, yyleng); return QQSTRING_TEXT; } . { return INVALID_CHARACTER; } } ([a-zA-Z_][a-zA-Z_0-9]*::)*[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;} \$([a-zA-Z_][a-zA-Z_0-9]*::)*[a-zA-Z_][a-zA-Z_0-9]* { yylval->literal = jv_string(yytext+1); return BINDING;} [ \r\n\t]+ {} . { return INVALID_CHARACTER; } %% /* perhaps these should be calls... */ /* "true" { return TRUE; } "false" { return FALSE; } "null" { return NULL; } */ static int try_exit(int c, int state, yyscan_t yyscanner) { char match = 0; int ret; switch (state) { case IN_PAREN: match = ret = ')'; break; case IN_BRACKET: match = ret = ']'; break; case IN_BRACE: match = ret = '}'; break; case IN_QQINTERP: match = ')'; ret = QQSTRING_INTERP_END; break; default: // may not be the best error to give return INVALID_CHARACTER; } assert(match); if (match == c) { yy_pop_state(yyscanner); return ret; } else { // FIXME: should we pop? Give a better error at least return INVALID_CHARACTER; } } static int enter(int c, int currstate, yyscan_t yyscanner) { int state = 0; switch (c) { case '(': state = IN_PAREN; break; case '[': state = IN_BRACKET; break; case '{': state = IN_BRACE; break; case QQSTRING_INTERP_START: state = IN_QQINTERP; break; } assert(state); yy_push_state(state, yyscanner); return c; } void* yyalloc(size_t sz, void* extra) { return jv_mem_alloc(sz); } void* yyrealloc(void* p, size_t sz, void* extra) { return jv_mem_realloc(p, sz); } void yyfree(void* p, void* extra) { jv_mem_free(p); } ================================================ FILE: src/libm.h ================================================ #ifdef HAVE_ACOS LIBM_DD(acos) #else LIBM_DD_NO(acos) #endif #ifdef HAVE_ACOSH LIBM_DD(acosh) #else LIBM_DD_NO(acosh) #endif #ifdef HAVE_ASIN LIBM_DD(asin) #else LIBM_DD_NO(asin) #endif #ifdef HAVE_ASINH LIBM_DD(asinh) #else LIBM_DD_NO(asinh) #endif #ifdef HAVE_ATAN LIBM_DD(atan) #else LIBM_DD_NO(atan) #endif #ifdef HAVE_ATAN2 LIBM_DDD(atan2) #else LIBM_DDD_NO(atan2) #endif #ifdef HAVE_ATANH LIBM_DD(atanh) #else LIBM_DD_NO(atanh) #endif #ifdef HAVE_CBRT LIBM_DD(cbrt) #else LIBM_DD_NO(cbrt) #endif #ifdef HAVE_COS LIBM_DD(cos) #else LIBM_DD_NO(cos) #endif #ifdef HAVE_COSH LIBM_DD(cosh) #else LIBM_DD_NO(cosh) #endif #ifdef HAVE_EXP LIBM_DD(exp) #else LIBM_DD_NO(exp) #endif #ifdef HAVE_EXP2 LIBM_DD(exp2) #else LIBM_DD_NO(exp2) #endif #ifdef HAVE_FLOOR LIBM_DD(floor) #else LIBM_DD_NO(floor) #endif #ifdef HAVE_HYPOT LIBM_DDD(hypot) #else LIBM_DDD_NO(hypot) #endif #ifdef HAVE_J0 LIBM_DD(j0) #else LIBM_DD_NO(j0) #endif #ifdef HAVE_J1 LIBM_DD(j1) #else LIBM_DD_NO(j1) #endif #ifdef HAVE_LOG LIBM_DD(log) #else LIBM_DD_NO(log) #endif #ifdef HAVE_LOG10 LIBM_DD(log10) #else LIBM_DD_NO(log10) #endif #ifdef HAVE_LOG2 LIBM_DD(log2) #else LIBM_DD_NO(log2) #endif #ifdef HAVE_POW LIBM_DDD(pow) #else LIBM_DDD_NO(pow) #endif #ifdef HAVE_REMAINDER LIBM_DDD(remainder) #else LIBM_DDD_NO(remainder) #endif #ifdef HAVE_SIN LIBM_DD(sin) #else LIBM_DD_NO(sin) #endif #ifdef HAVE_SINH LIBM_DD(sinh) #else LIBM_DD_NO(sinh) #endif #ifdef HAVE_SQRT LIBM_DD(sqrt) #else LIBM_DD_NO(sqrt) #endif #ifdef HAVE_TAN LIBM_DD(tan) #else LIBM_DD_NO(tan) #endif #ifdef HAVE_TANH LIBM_DD(tanh) #else LIBM_DD_NO(tanh) #endif #ifdef HAVE_TGAMMA LIBM_DD(tgamma) #else LIBM_DD_NO(tgamma) #endif #ifdef HAVE_Y0 LIBM_DD(y0) #else LIBM_DD_NO(y0) #endif #ifdef HAVE_Y1 LIBM_DD(y1) #else LIBM_DD_NO(y1) #endif #ifdef HAVE_JN LIBM_DDD(jn) #endif #ifdef HAVE_YN LIBM_DDD(yn) #endif #ifdef HAVE_CEIL LIBM_DD(ceil) #else LIBM_DD_NO(ceil) #endif #ifdef HAVE_COPYSIGN LIBM_DDD(copysign) #else LIBM_DDD_NO(copysign) #endif #if defined(HAVE_DREM) && !defined(WIN32) LIBM_DDD(drem) #else LIBM_DDD_NO(drem) #endif #ifdef HAVE_ERF LIBM_DD(erf) #else LIBM_DD_NO(erf) #endif #ifdef HAVE_ERFC LIBM_DD(erfc) #else LIBM_DD_NO(erfc) #endif #if defined(HAVE_EXP10) && !defined(WIN32) LIBM_DD(exp10) #else LIBM_DD_NO(exp10) #endif #ifdef HAVE_EXPM1 LIBM_DD(expm1) #else LIBM_DD_NO(expm1) #endif #ifdef HAVE_FABS LIBM_DD(fabs) #else LIBM_DD_NO(fabs) #endif #ifdef HAVE_FDIM LIBM_DDD(fdim) #else LIBM_DDD_NO(fdim) #endif #ifdef HAVE_FMA LIBM_DDDD(fma) #else LIBM_DDDD_NO(fma) #endif #ifdef HAVE_FMAX LIBM_DDD(fmax) #else LIBM_DDD_NO(fmax) #endif #ifdef HAVE_FMIN LIBM_DDD(fmin) #else LIBM_DDD_NO(fmin) #endif #ifdef HAVE_FMOD LIBM_DDD(fmod) #else LIBM_DDD_NO(fmod) #endif #if defined(HAVE_GAMMA) LIBM_DD(gamma) #else LIBM_DD_NO(gamma) #endif #ifdef HAVE_LGAMMA LIBM_DD(lgamma) #else LIBM_DD_NO(lgamma) #endif #ifdef HAVE_LOG1P LIBM_DD(log1p) #else LIBM_DD_NO(log1p) #endif #ifdef HAVE_LOGB LIBM_DD(logb) #else LIBM_DD_NO(logb) #endif #ifdef HAVE_NEARBYINT LIBM_DD(nearbyint) #else LIBM_DD_NO(nearbyint) #endif #ifdef HAVE_NEXTAFTER LIBM_DDD(nextafter) #else LIBM_DDD_NO(nextafter) #endif #ifdef HAVE_NEXTTOWARD LIBM_DDD(nexttoward) #else LIBM_DDD_NO(nexttoward) #endif #ifdef HAVE_RINT LIBM_DD(rint) #else LIBM_DD_NO(rint) #endif #ifdef HAVE_ROUND LIBM_DD(round) #else LIBM_DD_NO(round) #endif #ifdef HAVE_SCALB LIBM_DDD(scalb) #else LIBM_DDD_NO(scalb) #endif #ifdef HAVE_SCALBLN LIBM_DDD(scalbln) #else LIBM_DDD_NO(scalbln) #endif #if defined(HAVE_SIGNIFICAND) && !defined(WIN32) LIBM_DD(significand) #else LIBM_DD_NO(significand) #endif #ifdef HAVE_TRUNC LIBM_DD(trunc) #else LIBM_DD_NO(trunc) #endif #ifdef HAVE_LDEXP LIBM_DDD(ldexp) #else LIBM_DDD_NO(ldexp) #endif #ifdef HAVE_MODF LIBM_DA(modf, double) #else LIBM_DA_NO(modf, double) #endif #ifdef HAVE_FREXP LIBM_DA(frexp, int) #else LIBM_DA_NO(frexp, int) #endif #ifdef HAVE_LGAMMA_R LIBM_DA(lgamma_r, int) #else LIBM_DA_NO(lgamma_r, int) #endif ================================================ FILE: src/linker.c ================================================ #include #include #include #include #include #include #include #include #include #ifdef WIN32 #include #endif #include "jq_parser.h" #include "locfile.h" #include "jv.h" #include "jq.h" #include "util.h" #include "compile.h" #include "jv_alloc.h" struct lib_loading_state { char **names; block *defs; uint64_t ct; }; static int load_library(jq_state *jq, jv lib_path, int is_data, int raw, int optional, const char *as, block *out_block, struct lib_loading_state *lib_state); static int path_is_relative(jv p) { const char *s = jv_string_value(p); #ifdef WIN32 int res = PathIsRelativeA(s); #else int res = *s != '/'; #endif jv_free(p); return res; } // Given a lib_path to search first, creates a chain of search paths // in the following order: // 1. lib_path // 2. -L paths passed in on the command line (from jq_state*) or builtin list static jv build_lib_search_chain(jq_state *jq, jv search_path, jv jq_origin, jv lib_origin) { assert(jv_get_kind(search_path) == JV_KIND_ARRAY); jv expanded = jv_array(); jv expanded_elt; jv err = jv_null(); jv_array_foreach(search_path, i, path) { if (jv_get_kind(path) != JV_KIND_STRING) { jv_free(path); continue; } path = expand_path(path); if (!jv_is_valid(path)) { jv_free(err); err = path; path = jv_null(); continue; } if (strcmp(".",jv_string_value(path)) == 0) { expanded_elt = jv_copy(path); } else if (strncmp("$ORIGIN/",jv_string_value(path),sizeof("$ORIGIN/") - 1) == 0) { expanded_elt = jv_string_fmt("%s/%s", jv_string_value(jq_origin), jv_string_value(path) + sizeof ("$ORIGIN/") - 1); } else if (jv_get_kind(lib_origin) == JV_KIND_STRING && path_is_relative(jv_copy(path))) { expanded_elt = jv_string_fmt("%s/%s", jv_string_value(lib_origin), jv_string_value(path)); } else { expanded_elt = path; path = jv_invalid(); } expanded = jv_array_append(expanded, expanded_elt); jv_free(path); } jv_free(jq_origin); jv_free(lib_origin); jv_free(search_path); return JV_ARRAY(expanded, err); } // Doesn't actually check that name not be an absolute path, and we // don't have to: we always append relative paths to others (with a '/' // in between). static jv validate_relpath(jv name) { const char *s = jv_string_value(name); if (strchr(s, '\\')) { jv res = jv_invalid_with_msg(jv_string_fmt("Modules must be named by relative paths using '/', not '\\' (%s)", s)); jv_free(name); return res; } jv components = jv_string_split(jv_copy(name), jv_string("/")); jv_array_foreach(components, i, x) { if (!strcmp(jv_string_value(x), "..")) { jv_free(x); jv_free(components); jv res = jv_invalid_with_msg(jv_string_fmt("Relative paths to modules may not traverse to parent directories (%s)", s)); jv_free(name); return res; } if (i > 0 && jv_equal(jv_copy(x), jv_array_get(jv_copy(components), i - 1))) { jv_free(x); jv_free(components); jv res = jv_invalid_with_msg(jv_string_fmt("module names must not have equal consecutive components: %s", jv_string_value(name))); jv_free(name); return res; } jv_free(x); } jv_free(components); return name; } // Assumes name has been validated static jv jv_basename(jv name) { const char *s = jv_string_value(name); const char *p = strrchr(s, '/'); if (!p) return name; jv res = jv_string_fmt("%s", p); jv_free(name); return res; } // Asummes validated relative path to module static jv find_lib(jq_state *jq, jv rel_path, jv search, const char *suffix, jv jq_origin, jv lib_origin) { if (!jv_is_valid(rel_path)) { jv_free(search); jv_free(jq_origin); jv_free(lib_origin); return rel_path; } if (jv_get_kind(rel_path) != JV_KIND_STRING) { jv_free(rel_path); jv_free(search); jv_free(jq_origin); jv_free(lib_origin); return jv_invalid_with_msg(jv_string_fmt("Module path must be a string")); } if (jv_get_kind(search) != JV_KIND_ARRAY) { jv_free(rel_path); jv_free(search); jv_free(jq_origin); jv_free(lib_origin); return jv_invalid_with_msg(jv_string_fmt("Module search path must be an array")); } struct stat st; int ret; // Ideally we should cache this somewhere search = build_lib_search_chain(jq, search, jq_origin, lib_origin); jv err = jv_array_get(jv_copy(search), 1); search = jv_array_get(search, 0); jv bname = jv_basename(jv_copy(rel_path)); jv_array_foreach(search, i, spath) { if (jv_get_kind(spath) == JV_KIND_NULL) { jv_free(spath); break; } if (jv_get_kind(spath) != JV_KIND_STRING || strcmp(jv_string_value(spath), "") == 0) { jv_free(spath); continue; /* XXX report non-strings in search path?? */ } // Try ${search_dir}/${rel_path}.jq jv testpath = jq_realpath(jv_string_fmt("%s/%s%s", jv_string_value(spath), jv_string_value(rel_path), suffix)); ret = stat(jv_string_value(testpath),&st); if (ret == -1 && errno == ENOENT) { jv_free(testpath); // Try ${search_dir}/$(dirname ${rel_path})/jq/main.jq testpath = jq_realpath(jv_string_fmt("%s/%s/%s%s", jv_string_value(spath), jv_string_value(rel_path), "jq/main", suffix)); ret = stat(jv_string_value(testpath),&st); } if (ret == -1 && errno == ENOENT) { jv_free(testpath); // Try ${search_dir}/${rel_path}/$(basename ${rel_path}).jq testpath = jq_realpath(jv_string_fmt("%s/%s/%s%s", jv_string_value(spath), jv_string_value(rel_path), jv_string_value(bname), suffix)); ret = stat(jv_string_value(testpath),&st); } if (ret == 0) { jv_free(err); jv_free(rel_path); jv_free(search); jv_free(bname); jv_free(spath); return testpath; } jv_free(testpath); jv_free(spath); } jv output; if (!jv_is_valid(err)) { err = jv_invalid_get_msg(err); output = jv_invalid_with_msg(jv_string_fmt("module not found: %s (%s)", jv_string_value(rel_path), jv_string_value(err))); } else { output = jv_invalid_with_msg(jv_string_fmt("module not found: %s", jv_string_value(rel_path))); } jv_free(err); jv_free(rel_path); jv_free(search); jv_free(bname); return output; } static jv default_search(jq_state *jq, jv value) { if (!jv_is_valid(value)) { // dependent didn't say; prepend . to system search path listj jv_free(value); return jv_array_concat(JV_ARRAY(jv_string(".")), jq_get_lib_dirs(jq)); } if (jv_get_kind(value) != JV_KIND_ARRAY) return JV_ARRAY(value); return value; } // XXX Split this into a util that takes a callback, and then... static int process_dependencies(jq_state *jq, jv jq_origin, jv lib_origin, block *src_block, struct lib_loading_state *lib_state) { jv deps = block_take_imports(src_block); block bk = *src_block; int nerrors = 0; // XXX This is a backward jv_array_foreach because bindings go in reverse for (int i = jv_array_length(jv_copy(deps)); i > 0; ) { i--; jv dep = jv_array_get(jv_copy(deps), i); const char *as_str = NULL; int is_data = jv_get_kind(jv_object_get(jv_copy(dep), jv_string("is_data"))) == JV_KIND_TRUE; int raw = 0; jv v = jv_object_get(jv_copy(dep), jv_string("raw")); if (jv_get_kind(v) == JV_KIND_TRUE) raw = 1; int optional = 0; if (jv_get_kind(jv_object_get(jv_copy(dep), jv_string("optional"))) == JV_KIND_TRUE) optional = 1; jv_free(v); jv relpath = validate_relpath(jv_object_get(jv_copy(dep), jv_string("relpath"))); jv as = jv_object_get(jv_copy(dep), jv_string("as")); assert(!jv_is_valid(as) || jv_get_kind(as) == JV_KIND_STRING); if (jv_get_kind(as) == JV_KIND_STRING) as_str = jv_string_value(as); jv search = default_search(jq, jv_object_get(dep, jv_string("search"))); // dep is now freed; do not reuse // find_lib does a lot of work that could be cached... jv resolved = find_lib(jq, relpath, search, is_data ? ".json" : ".jq", jv_copy(jq_origin), jv_copy(lib_origin)); // XXX ...move the rest of this into a callback. if (!jv_is_valid(resolved)) { jv_free(as); if (optional) { jv_free(resolved); continue; } jv emsg = jv_invalid_get_msg(resolved); jq_report_error(jq, jv_string_fmt("jq: error: %s\n",jv_string_value(emsg))); jv_free(emsg); jv_free(deps); jv_free(jq_origin); jv_free(lib_origin); return 1; } if (is_data) { // Can't reuse data libs because the wrong name is bound block dep_def_block; nerrors += load_library(jq, resolved, is_data, raw, optional, as_str, &dep_def_block, lib_state); if (nerrors == 0) { // Bind as both $data::data and $data for backward compatibility vs common sense bk = block_bind_library(dep_def_block, bk, OP_IS_CALL_PSEUDO, as_str); bk = block_bind_library(dep_def_block, bk, OP_IS_CALL_PSEUDO, NULL); } } else { uint64_t state_idx = 0; for (; state_idx < lib_state->ct; ++state_idx) { if (strcmp(lib_state->names[state_idx],jv_string_value(resolved)) == 0) break; } if (state_idx < lib_state->ct) { // Found jv_free(resolved); // Bind the library to the program bk = block_bind_library(lib_state->defs[state_idx], bk, OP_IS_CALL_PSEUDO, as_str); } else { // Not found. Add it to the table before binding. block dep_def_block = gen_noop(); nerrors += load_library(jq, resolved, is_data, raw, optional, as_str, &dep_def_block, lib_state); // resolved has been freed if (nerrors == 0) { // Bind the library to the program bk = block_bind_library(dep_def_block, bk, OP_IS_CALL_PSEUDO, as_str); } } } jv_free(as); } jv_free(lib_origin); jv_free(jq_origin); jv_free(deps); return nerrors; } // Loads the library at lib_path into lib_state, putting the library's defs // into *out_block static int load_library(jq_state *jq, jv lib_path, int is_data, int raw, int optional, const char *as, block *out_block, struct lib_loading_state *lib_state) { int nerrors = 0; struct locfile* src = NULL; block program; jv data; if (is_data && !raw) data = jv_load_file(jv_string_value(lib_path), 0); else data = jv_load_file(jv_string_value(lib_path), 1); int state_idx; if (!jv_is_valid(data)) { program = gen_noop(); if (!optional) { if (jv_invalid_has_msg(jv_copy(data))) data = jv_invalid_get_msg(data); else data = jv_string("unknown error"); jq_report_error(jq, jv_string_fmt("jq: error loading data file %s: %s\n", jv_string_value(lib_path), jv_string_value(data))); nerrors++; } goto out; } else if (is_data) { // import "foo" as $bar; program = gen_const_global(jv_copy(data), as); } else { // import "foo" as bar; src = locfile_init(jq, jv_string_value(lib_path), jv_string_value(data), jv_string_length_bytes(jv_copy(data))); nerrors += jq_parse_library(src, &program); locfile_free(src); if (nerrors == 0) { char *lib_origin = strdup(jv_string_value(lib_path)); nerrors += process_dependencies(jq, jq_get_jq_origin(jq), jv_string(dirname(lib_origin)), &program, lib_state); free(lib_origin); program = block_bind_self(program, OP_IS_CALL_PSEUDO); } } if (nerrors == 0) { state_idx = lib_state->ct++; lib_state->names = jv_mem_realloc(lib_state->names, lib_state->ct * sizeof(const char *)); lib_state->defs = jv_mem_realloc(lib_state->defs, lib_state->ct * sizeof(block)); lib_state->names[state_idx] = strdup(jv_string_value(lib_path)); lib_state->defs[state_idx] = program; } out: *out_block = program; jv_free(lib_path); jv_free(data); return nerrors; } // FIXME It'd be nice to have an option to search the same search path // as we do in process_dependencies. jv load_module_meta(jq_state *jq, jv mod_relpath) { // We can't know the caller's origin; we could though, if it was passed in jv lib_path = find_lib(jq, validate_relpath(mod_relpath), jq_get_lib_dirs(jq), ".jq", jq_get_jq_origin(jq), jv_null()); if (!jv_is_valid(lib_path)) return lib_path; jv meta = jv_null(); jv data = jv_load_file(jv_string_value(lib_path), 1); if (jv_is_valid(data)) { block program; struct locfile* src = locfile_init(jq, jv_string_value(lib_path), jv_string_value(data), jv_string_length_bytes(jv_copy(data))); int nerrors = jq_parse_library(src, &program); if (nerrors == 0) { meta = block_module_meta(program); if (jv_get_kind(meta) == JV_KIND_NULL) meta = jv_object(); meta = jv_object_set(meta, jv_string("deps"), block_take_imports(&program)); meta = jv_object_set(meta, jv_string("defs"), block_list_funcs(program, 0)); } locfile_free(src); block_free(program); } jv_free(lib_path); jv_free(data); return meta; } int load_program(jq_state *jq, struct locfile* src, block *out_block) { int nerrors = 0; block program; struct lib_loading_state lib_state = {0,0,0}; nerrors = jq_parse(src, &program); if (nerrors) return nerrors; if (!block_has_main(program)) { jq_report_error(jq, jv_string("jq: error: Top-level program not given (try \".\")")); block_free(program); return 1; } jv home = get_home(); if (jv_is_valid(home)) { /* Import ~/.jq as a library named "" found in $HOME or %USERPROFILE% */ block import = gen_import_meta(gen_import("", NULL, 0), gen_const(JV_OBJECT( jv_string("optional"), jv_true(), jv_string("search"), home))); program = BLOCK(import, program); } else { // silently ignore if home dir not determined jv_free(home); } nerrors = process_dependencies(jq, jq_get_jq_origin(jq), jq_get_prog_origin(jq), &program, &lib_state); block libs = gen_noop(); for (uint64_t i = 0; i < lib_state.ct; ++i) { free(lib_state.names[i]); if (nerrors == 0 && !block_is_const(lib_state.defs[i])) libs = block_join(libs, lib_state.defs[i]); else block_free(lib_state.defs[i]); } free(lib_state.names); free(lib_state.defs); if (nerrors) block_free(program); else *out_block = block_drop_unreferenced(block_join(libs, program)); return nerrors; } ================================================ FILE: src/linker.h ================================================ #ifndef LINKER_H #define LINKER_H int load_program(jq_state *jq, struct locfile* src, block *out_block); jv load_module_meta(jq_state *jq, jv modname); #endif ================================================ FILE: src/locfile.c ================================================ #include #include #include #include #include #include #include "jq.h" #include "jv_alloc.h" #include "locfile.h" #include "util.h" struct locfile* locfile_init(jq_state *jq, const char *fname, const char* data, int length) { struct locfile* l = jv_mem_alloc(sizeof(struct locfile)); l->jq = jq; l->fname = jv_string(fname); l->data = jv_mem_alloc(length); memcpy((char*)l->data,data,length); l->length = length; l->nlines = 1; l->refct = 1; for (int i=0; inlines++; } l->linemap = jv_mem_calloc(l->nlines + 1, sizeof(int)); l->linemap[0] = 0; int line = 1; for (int i=0; ilinemap[line] = i+1; // at start of line, not of \n line++; } } l->linemap[l->nlines] = length+1; // virtual last \n return l; } struct locfile* locfile_retain(struct locfile* l) { l->refct++; return l; } void locfile_free(struct locfile* l) { if (--(l->refct) == 0) { jv_free(l->fname); jv_mem_free(l->linemap); jv_mem_free((char*)l->data); jv_mem_free(l); } } 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, ...) { va_list fmtargs; va_start(fmtargs, fmt); jv m1 = jv_string_vfmt(fmt, fmtargs); va_end(fmtargs); if (!jv_is_valid(m1)) { jq_report_error(l->jq, m1); return; } if (loc.start == -1) { jq_report_error(l->jq, jv_string_fmt("jq: error: %s", jv_string_value(m1))); jv_free(m1); return; } int startline = locfile_get_line(l, loc.start); int offset = l->linemap[startline]; int end = MIN(loc.end, MAX(l->linemap[startline+1] - 1, loc.start + 1)); jv underline = jv_string_repeat(jv_string("^"), end - loc.start); jv m2 = jv_string_fmt("%s at %s, line %d, column %d:\n %.*s\n %*s", jv_string_value(m1), jv_string_value(l->fname), startline + 1, loc.start - offset + 1, locfile_line_length(l, startline), l->data + offset, end - offset, jv_string_value(underline)); jv_free(m1); jv_free(underline); jq_report_error(l->jq, m2); return; } ================================================ FILE: src/locfile.h ================================================ #ifndef LOCFILE_H #define LOCFILE_H #include "jq.h" typedef struct { int start, end; } location; static const location UNKNOWN_LOCATION = {-1, -1}; struct locfile { jv fname; const char* data; int length; int* linemap; int nlines; char *error; jq_state *jq; int refct; }; struct locfile* locfile_init(jq_state *, const char *, const char *, int); struct locfile* locfile_retain(struct locfile *); int locfile_get_line(struct locfile *, int); void locfile_free(struct locfile *); void locfile_locate(struct locfile *, location, const char *, ...); #endif ================================================ FILE: src/main.c ================================================ #include #include #include #include #ifdef HAVE_SETLOCALE #include #endif #include #include #include #include #ifdef WIN32 #include #include #include #include #include #include #include extern void jv_tsd_dtoa_ctx_init(); #endif #ifdef HAVE_LIBONIG #include #endif #if !defined(HAVE_ISATTY) && defined(HAVE__ISATTY) #undef isatty #define isatty _isatty #endif #if defined(HAVE_ISATTY) || defined(HAVE__ISATTY) #define USE_ISATTY #endif #include "jv.h" #include "jq.h" #include "util.h" #include "src/version.h" #include "src/config_opts.inc" int jq_testsuite(jv lib_dirs, int verbose, int argc, char* argv[]); /* * For a longer help message we could use a better option parsing * strategy, one that lets stack options. */ static void usage(int code, int keep_it_short) { FILE *f = stderr; if (code == 0) f = stdout; int ret = fprintf(f, "jq - commandline JSON processor [version %s]\n" "\nUsage:\tjq [options] [file...]\n" "\tjq [options] --args [strings...]\n" "\tjq [options] --jsonargs [JSON_TEXTS...]\n\n" "jq is a tool for processing JSON inputs, applying the given filter to\n" "its JSON text inputs and producing the filter's results as JSON on\n" "standard output.\n\n" "The simplest filter is ., which copies jq's input to its output\n" "unmodified except for formatting. For more advanced filters see\n" "the jq(1) manpage (\"man jq\") and/or https://jqlang.org/.\n\n" "Example:\n\n\t$ echo '{\"foo\": 0}' | jq .\n" "\t{\n\t \"foo\": 0\n\t}\n\n", JQ_VERSION); if (keep_it_short) { fprintf(f, "For listing the command options, use jq --help.\n"); } else { (void) fprintf(f, "Command options:\n" " -n, --null-input use `null` as the single input value;\n" " -R, --raw-input read each line as string instead of JSON;\n" " -s, --slurp read all inputs into an array and use it as\n" " the single input value;\n" " -c, --compact-output compact instead of pretty-printed output;\n" " -r, --raw-output output strings without escapes and quotes;\n" " --raw-output0 implies -r and output NUL after each output;\n" " -j, --join-output implies -r and output without newline after\n" " each output;\n" " -a, --ascii-output output strings by only ASCII characters\n" " using escape sequences;\n" " -S, --sort-keys sort keys of each object on output;\n" " -C, --color-output colorize JSON output;\n" " -M, --monochrome-output disable colored output;\n" " --tab use tabs for indentation;\n" " --indent n use n spaces for indentation (max 7 spaces);\n" " --unbuffered flush output stream after each output;\n" " --stream parse the input value in streaming fashion;\n" " --stream-errors implies --stream and report parse error as\n" " an array;\n" " --seq parse input/output as application/json-seq;\n" " -f, --from-file load the filter from a file;\n" " -L, --library-path dir search modules from the directory;\n" " --arg name value set $name to the string value;\n" " --argjson name value set $name to the JSON value;\n" " --slurpfile name file set $name to an array of JSON values read\n" " from the file;\n" " --rawfile name file set $name to string contents of file;\n" " --args consume remaining arguments as positional\n" " string values;\n" " --jsonargs consume remaining arguments as positional\n" " JSON values;\n" " -e, --exit-status set exit status code based on the output;\n" #ifdef WIN32 " -b, --binary open input/output streams in binary mode;\n" #endif " -V, --version show the version;\n" " --build-configuration show jq's build configuration;\n" " -h, --help show the help;\n" " -- terminates argument processing;\n\n" "Named arguments are also available as $ARGS.named[], while\n" "positional arguments are available as $ARGS.positional[].\n"); } exit((ret < 0 && code == 0) ? 2 : code); } static void die(void) { fprintf(stderr, "Use jq --help for help with command-line options,\n"); fprintf(stderr, "or see the jq manpage, or online docs at https://jqlang.org\n"); exit(2); } static int isoptish(const char* text) { return text[0] == '-' && (text[1] == '-' || isalpha((unsigned char)text[1])); } static int isoption(const char** text, char shortopt, const char* longopt, int is_short) { if (is_short) { if (shortopt && **text == shortopt) { (*text)++; if (!**text) *text = NULL; return 1; } } else { if (!strcmp(*text, longopt)) { *text = NULL; return 1; } } return 0; } enum { SLURP = 1, RAW_INPUT = 2, PROVIDE_NULL = 4, RAW_OUTPUT = 8, RAW_OUTPUT0 = 16, ASCII_OUTPUT = 32, COLOR_OUTPUT = 64, NO_COLOR_OUTPUT = 128, SORTED_OUTPUT = 256, FROM_FILE = 512, RAW_NO_LF = 1024, UNBUFFERED_OUTPUT = 2048, EXIT_STATUS = 4096, SEQ = 16384, /* debugging only */ DUMP_DISASM = 32768, }; enum { JQ_OK = 0, JQ_OK_NULL_KIND = -1, /* exit 0 if --exit-status is not set*/ JQ_ERROR_SYSTEM = 2, JQ_ERROR_COMPILE = 3, JQ_OK_NO_OUTPUT = -4, /* exit 0 if --exit-status is not set*/ JQ_ERROR_UNKNOWN = 5, }; #define jq_exit_with_status(r) exit(abs(r)) #define jq_exit(r) exit( r > 0 ? r : 0 ) static int process(jq_state *jq, jv value, int flags, int dumpopts, int options) { int ret = JQ_OK_NO_OUTPUT; // No valid results && -e -> exit(4) jq_start(jq, value, flags); jv result; while (jv_is_valid(result = jq_next(jq))) { if ((options & RAW_OUTPUT) && jv_get_kind(result) == JV_KIND_STRING) { if (options & ASCII_OUTPUT) { jv_dumpf(jv_copy(result), stdout, JV_PRINT_ASCII); } else if ((options & RAW_OUTPUT0) && strlen(jv_string_value(result)) != (unsigned long)jv_string_length_bytes(jv_copy(result))) { jv_free(result); result = jv_invalid_with_msg(jv_string( "Cannot dump a string containing NUL with --raw-output0 option")); break; } else { priv_fwrite(jv_string_value(result), jv_string_length_bytes(jv_copy(result)), stdout, dumpopts & JV_PRINT_ISATTY); } ret = JQ_OK; jv_free(result); } else { if (jv_get_kind(result) == JV_KIND_FALSE || jv_get_kind(result) == JV_KIND_NULL) ret = JQ_OK_NULL_KIND; else ret = JQ_OK; if (options & SEQ) priv_fwrite("\036", 1, stdout, dumpopts & JV_PRINT_ISATTY); jv_dump(result, dumpopts); } if (!(options & RAW_NO_LF)) priv_fwrite("\n", 1, stdout, dumpopts & JV_PRINT_ISATTY); if (options & RAW_OUTPUT0) priv_fwrite("\0", 1, stdout, dumpopts & JV_PRINT_ISATTY); if (options & UNBUFFERED_OUTPUT) fflush(stdout); } if (jq_halted(jq)) { // jq program invoked `halt` or `halt_error` jv exit_code = jq_get_exit_code(jq); if (!jv_is_valid(exit_code)) ret = JQ_OK; else if (jv_get_kind(exit_code) == JV_KIND_NUMBER) ret = jv_number_value(exit_code); else ret = JQ_ERROR_UNKNOWN; jv_free(exit_code); jv error_message = jq_get_error_message(jq); if (jv_get_kind(error_message) == JV_KIND_STRING) { // No prefix should be added to the output of `halt_error`. priv_fwrite(jv_string_value(error_message), jv_string_length_bytes(jv_copy(error_message)), stderr, dumpopts & JV_PRINT_ISATTY); } else if (jv_get_kind(error_message) == JV_KIND_NULL) { // Halt with no output } else if (jv_is_valid(error_message)) { error_message = jv_dump_string(error_message, 0); fprintf(stderr, "%s\n", jv_string_value(error_message)); } // else no message on stderr; use --debug-trace to see a message fflush(stderr); jv_free(error_message); } else if (jv_invalid_has_msg(jv_copy(result))) { // Uncaught jq exception jv msg = jv_invalid_get_msg(jv_copy(result)); jv input_pos = jq_util_input_get_position(jq); if (jv_get_kind(msg) == JV_KIND_STRING) { fprintf(stderr, "jq: error (at %s): %s\n", jv_string_value(input_pos), jv_string_value(msg)); } else { msg = jv_dump_string(msg, 0); fprintf(stderr, "jq: error (at %s) (not a string): %s\n", jv_string_value(input_pos), jv_string_value(msg)); } ret = JQ_ERROR_UNKNOWN; jv_free(input_pos); jv_free(msg); } jv_free(result); return ret; } static void debug_cb(void *data, jv input) { int dumpopts = *(int *)data; jv_dumpf(JV_ARRAY(jv_string("DEBUG:"), input), stderr, dumpopts & ~(JV_PRINT_PRETTY)); fprintf(stderr, "\n"); } static void stderr_cb(void *data, jv input) { if (jv_get_kind(input) == JV_KIND_STRING) { int dumpopts = *(int *)data; priv_fwrite(jv_string_value(input), jv_string_length_bytes(jv_copy(input)), stderr, dumpopts & JV_PRINT_ISATTY); } else { input = jv_dump_string(input, 0); fprintf(stderr, "%s", jv_string_value(input)); } jv_free(input); } #ifdef WIN32 int umain(int argc, char* argv[]); int wmain(int argc, wchar_t* wargv[]) { size_t arg_sz; char **argv = alloca(argc * sizeof(wchar_t*)); for (int i = 0; i < argc; i++) { argv[i] = alloca((arg_sz = WideCharToMultiByte(CP_UTF8, 0, wargv[i], -1, 0, 0, 0, 0))); WideCharToMultiByte(CP_UTF8, 0, wargv[i], -1, argv[i], arg_sz, 0, 0); } return umain(argc, argv); } int umain(int argc, char* argv[]) { #else /*}*/ int main(int argc, char* argv[]) { #endif jq_state *jq = NULL; jq_util_input_state *input_state = NULL; int ret = JQ_OK_NO_OUTPUT; int compiled = 0; int parser_flags = 0; int nfiles = 0; int last_result = -1; /* -1 = no result, 0=null or false, 1=true */ int badwrite; int options = 0; #ifdef HAVE_SETLOCALE (void) setlocale(LC_ALL, ""); #endif #ifdef HAVE_LIBONIG // use a lower regex parse depth limit than the default (4096) to protect // from stack-overflows // https://github.com/jqlang/jq/security/advisories/GHSA-f946-j5j2-4w5m onig_set_parse_depth_limit(1024); #endif #ifdef __OpenBSD__ if (pledge("stdio rpath", NULL) == -1) { perror("pledge"); exit(JQ_ERROR_SYSTEM); } #endif #ifdef WIN32 jv_tsd_dtoa_ctx_init(); fflush(stdout); fflush(stderr); _setmode(fileno(stdout), _O_TEXT | _O_U8TEXT); _setmode(fileno(stderr), _O_TEXT | _O_U8TEXT); #endif jv ARGS = jv_array(); /* positional arguments */ jv program_arguments = jv_object(); /* named arguments */ jq = jq_init(); if (jq == NULL) { perror("jq_init"); ret = JQ_ERROR_SYSTEM; goto out; } int dumpopts = JV_PRINT_INDENT_FLAGS(2); const char* program = 0; input_state = jq_util_input_init(NULL, NULL); // XXX add err_cb int further_args_are_strings = 0; int further_args_are_json = 0; int args_done = 0; int jq_flags = 0; jv lib_search_paths = jv_null(); for (int i=1; i= argc - 1) { fprintf(stderr, "-L takes a parameter: (e.g. -L /search/path or -L/search/path)\n"); die(); } else { lib_search_paths = jv_array_append(lib_search_paths, jq_realpath(jv_string(argv[i+1]))); i++; } } else if (isoption(&text, 'b', "binary", is_short)) { #ifdef WIN32 fflush(stdout); fflush(stderr); _setmode(fileno(stdin), _O_BINARY); _setmode(fileno(stdout), _O_BINARY); _setmode(fileno(stderr), _O_BINARY); #endif } else if (isoption(&text, 0, "tab", is_short)) { dumpopts &= ~JV_PRINT_INDENT_FLAGS(7); dumpopts |= JV_PRINT_TAB | JV_PRINT_PRETTY; } else if (isoption(&text, 0, "indent", is_short)) { if (i >= argc - 1) { fprintf(stderr, "jq: --indent takes one parameter\n"); die(); } char* end = NULL; errno = 0; long indent = strtol(argv[i+1], &end, 10); if (errno || indent < -1 || indent > 7 || isspace(*argv[i+1]) || end == argv[i+1] || *end) { fprintf(stderr, "jq: --indent takes a number between -1 and 7\n"); die(); } dumpopts &= ~(JV_PRINT_TAB | JV_PRINT_INDENT_FLAGS(7)); dumpopts |= JV_PRINT_INDENT_FLAGS(indent); i++; } else if (isoption(&text, 0, "seq", is_short)) { options |= SEQ; } else if (isoption(&text, 0, "stream", is_short)) { parser_flags |= JV_PARSE_STREAMING; } else if (isoption(&text, 0, "stream-errors", is_short)) { parser_flags |= JV_PARSE_STREAMING | JV_PARSE_STREAM_ERRORS; } else if (isoption(&text, 'e', "exit-status", is_short)) { options |= EXIT_STATUS; } else if (isoption(&text, 0, "args", is_short)) { further_args_are_strings = 1; further_args_are_json = 0; } else if (isoption(&text, 0, "jsonargs", is_short)) { further_args_are_strings = 0; further_args_are_json = 1; } else if (isoption(&text, 0, "arg", is_short)) { if (i >= argc - 2) { fprintf(stderr, "jq: --arg takes two parameters (e.g. --arg varname value)\n"); die(); } if (!jv_object_has(jv_copy(program_arguments), jv_string(argv[i+1]))) program_arguments = jv_object_set(program_arguments, jv_string(argv[i+1]), jv_string(argv[i+2])); i += 2; // skip the next two arguments } else if (isoption(&text, 0, "argjson", is_short)) { if (i >= argc - 2) { fprintf(stderr, "jq: --argjson takes two parameters (e.g. --argjson varname text)\n"); die(); } if (!jv_object_has(jv_copy(program_arguments), jv_string(argv[i+1]))) { jv v = jv_parse(argv[i+2]); if (!jv_is_valid(v)) { fprintf(stderr, "jq: invalid JSON text passed to --argjson\n"); die(); } program_arguments = jv_object_set(program_arguments, jv_string(argv[i+1]), v); } i += 2; // skip the next two arguments } else if ((raw = isoption(&text, 0, "rawfile", is_short)) || isoption(&text, 0, "slurpfile", is_short)) { const char *which = raw ? "rawfile" : "slurpfile"; if (i >= argc - 2) { fprintf(stderr, "jq: --%s takes two parameters (e.g. --%s varname filename)\n", which, which); die(); } if (!jv_object_has(jv_copy(program_arguments), jv_string(argv[i+1]))) { jv data = jv_load_file(argv[i+2], raw); if (!jv_is_valid(data)) { data = jv_invalid_get_msg(data); fprintf(stderr, "jq: Bad JSON in --%s %s %s: %s\n", which, argv[i+1], argv[i+2], jv_string_value(data)); jv_free(data); ret = JQ_ERROR_SYSTEM; goto out; } program_arguments = jv_object_set(program_arguments, jv_string(argv[i+1]), data); } i += 2; // skip the next two arguments } else if (isoption(&text, 0, "debug-dump-disasm", is_short)) { options |= DUMP_DISASM; } else if (isoption(&text, 0, "debug-trace=all", is_short)) { jq_flags |= JQ_DEBUG_TRACE_ALL; } else if (isoption(&text, 0, "debug-trace", is_short)) { jq_flags |= JQ_DEBUG_TRACE; } else if (isoption(&text, 'h', "help", is_short)) { usage(0, 0); } else if (isoption(&text, 'V', "version", is_short)) { printf("jq-%s\n", JQ_VERSION); ret = JQ_OK; goto out; } else if (isoption(&text, 0, "build-configuration", is_short)) { printf("%s\n", JQ_CONFIG); ret = JQ_OK; goto out; } else if (isoption(&text, 0, "run-tests", is_short)) { i++; // XXX Pass program_arguments, even a whole jq_state *, through; // could be useful for testing ret = jq_testsuite(lib_search_paths, (options & DUMP_DISASM) || (jq_flags & JQ_DEBUG_TRACE), argc - i, argv + i); goto out; } else { if (is_short) { fprintf(stderr, "jq: Unknown option -%c\n", text[0]); } else { fprintf(stderr, "jq: Unknown option --%s\n", text); } die(); } } } } #ifdef USE_ISATTY if (isatty(STDOUT_FILENO)) { #ifndef WIN32 dumpopts |= JV_PRINT_ISATTY | JV_PRINT_COLOR; #else /* Verify we actually have the console, as the NUL device is also regarded as tty. Windows can handle color if ANSICON (or ConEmu) is installed, or Windows 10 supports the virtual terminal */ DWORD mode; HANDLE con = GetStdHandle(STD_OUTPUT_HANDLE); if (GetConsoleMode(con, &mode)) { dumpopts |= JV_PRINT_ISATTY; if (getenv("ANSICON") != NULL || SetConsoleMode(con, mode | 4/*ENABLE_VIRTUAL_TERMINAL_PROCESSING*/)) dumpopts |= JV_PRINT_COLOR; } #endif if (dumpopts & JV_PRINT_COLOR) { char *no_color = getenv("NO_COLOR"); if (no_color != NULL && no_color[0] != '\0') dumpopts &= ~JV_PRINT_COLOR; } } #endif if (options & SORTED_OUTPUT) dumpopts |= JV_PRINT_SORTED; if (options & ASCII_OUTPUT) dumpopts |= JV_PRINT_ASCII; if (options & COLOR_OUTPUT) dumpopts |= JV_PRINT_COLOR; if (options & NO_COLOR_OUTPUT) dumpopts &= ~JV_PRINT_COLOR; if (!jq_set_colors(getenv("JQ_COLORS"))) fprintf(stderr, "Failed to set $JQ_COLORS\n"); if (jv_get_kind(lib_search_paths) == JV_KIND_NULL) { // Default search path list lib_search_paths = JV_ARRAY(jv_string("~/.jq"), jv_string("$ORIGIN/../lib/jq"), jv_string("$ORIGIN/../lib")); } jq_set_attr(jq, jv_string("JQ_LIBRARY_PATH"), lib_search_paths); char *origin = strdup(argv[0]); if (origin == NULL) { fprintf(stderr, "jq: error: out of memory\n"); exit(1); } jq_set_attr(jq, jv_string("JQ_ORIGIN"), jv_string(dirname(origin))); free(origin); if (strchr(JQ_VERSION, '-') == NULL) jq_set_attr(jq, jv_string("VERSION_DIR"), jv_string(JQ_VERSION)); else jq_set_attr(jq, jv_string("VERSION_DIR"), jv_string_fmt("%.*s-master", (int)(strchr(JQ_VERSION, '-') - JQ_VERSION), JQ_VERSION)); #ifdef USE_ISATTY if (!program && !(options & FROM_FILE) && (!isatty(STDOUT_FILENO) || !isatty(STDIN_FILENO))) program = "."; #endif if (!program) usage(2, 1); if (options & FROM_FILE) { char *program_origin = strdup(program); if (program_origin == NULL) { perror("malloc"); exit(2); } jv data = jv_load_file(program, 1); if (!jv_is_valid(data)) { data = jv_invalid_get_msg(data); fprintf(stderr, "jq: %s\n", jv_string_value(data)); free(program_origin); jv_free(data); ret = JQ_ERROR_SYSTEM; goto out; } jq_set_attr(jq, jv_string("PROGRAM_ORIGIN"), jq_realpath(jv_string(dirname(program_origin)))); ARGS = JV_OBJECT(jv_string("positional"), ARGS, jv_string("named"), jv_copy(program_arguments)); program_arguments = jv_object_set(program_arguments, jv_string("ARGS"), jv_copy(ARGS)); if (!jv_object_has(jv_copy(program_arguments), jv_string("JQ_BUILD_CONFIGURATION"))) program_arguments = jv_object_set(program_arguments, jv_string("JQ_BUILD_CONFIGURATION"), jv_string(JQ_CONFIG)); /* named arguments */ compiled = jq_compile_args(jq, jv_string_value(data), jv_copy(program_arguments)); free(program_origin); jv_free(data); } else { jq_set_attr(jq, jv_string("PROGRAM_ORIGIN"), jq_realpath(jv_string("."))); // XXX is this good? ARGS = JV_OBJECT(jv_string("positional"), ARGS, jv_string("named"), jv_copy(program_arguments)); program_arguments = jv_object_set(program_arguments, jv_string("ARGS"), jv_copy(ARGS)); if (!jv_object_has(jv_copy(program_arguments), jv_string("JQ_BUILD_CONFIGURATION"))) program_arguments = jv_object_set(program_arguments, jv_string("JQ_BUILD_CONFIGURATION"), jv_string(JQ_CONFIG)); /* named arguments */ compiled = jq_compile_args(jq, program, jv_copy(program_arguments)); } if (!compiled){ ret = JQ_ERROR_COMPILE; goto out; } if (options & DUMP_DISASM) { jq_dump_disassembly(jq, 0); printf("\n"); } if ((options & SEQ)) parser_flags |= JV_PARSE_SEQ; if ((options & RAW_INPUT)) jq_util_input_set_parser(input_state, NULL, (options & SLURP) ? 1 : 0); else jq_util_input_set_parser(input_state, jv_parser_new(parser_flags), (options & SLURP) ? 1 : 0); // Let jq program read from inputs jq_set_input_cb(jq, jq_util_input_next_input_cb, input_state); // Let jq program call `debug` builtin and have that go somewhere jq_set_debug_cb(jq, debug_cb, &dumpopts); // Let jq program call `stderr` builtin and have that go somewhere jq_set_stderr_cb(jq, stderr_cb, &dumpopts); if (nfiles == 0) jq_util_input_add_input(input_state, "-"); if (options & PROVIDE_NULL) { ret = process(jq, jv_null(), jq_flags, dumpopts, options); } else { jv value; while (jq_util_input_errors(input_state) == 0 && (jv_is_valid((value = jq_util_input_next_input(input_state))) || jv_invalid_has_msg(jv_copy(value)))) { if (jv_is_valid(value)) { ret = process(jq, value, jq_flags, dumpopts, options); if (ret <= 0 && ret != JQ_OK_NO_OUTPUT) last_result = (ret != JQ_OK_NULL_KIND); if (jq_halted(jq)) break; continue; } // Parse error jv msg = jv_invalid_get_msg(value); if (!(options & SEQ)) { ret = JQ_ERROR_UNKNOWN; fprintf(stderr, "jq: parse error: %s\n", jv_string_value(msg)); jv_free(msg); break; } // --seq -> errors are not fatal fprintf(stderr, "jq: ignoring parse error: %s\n", jv_string_value(msg)); jv_free(msg); } } if (jq_util_input_errors(input_state) != 0) ret = JQ_ERROR_SYSTEM; out: badwrite = ferror(stdout); if (fclose(stdout)!=0 || badwrite) { fprintf(stderr,"jq: error: writing output failed: %s\n", strerror(errno)); ret = JQ_ERROR_SYSTEM; } jv_free(ARGS); jv_free(program_arguments); jq_util_input_free(&input_state); jq_teardown(&jq); if (options & EXIT_STATUS) { if (ret != JQ_OK_NO_OUTPUT) jq_exit_with_status(ret); else switch (last_result) { case -1: jq_exit_with_status(JQ_OK_NO_OUTPUT); case 0: jq_exit_with_status(JQ_OK_NULL_KIND); default: jq_exit_with_status(JQ_OK); } } else jq_exit(ret); } ================================================ FILE: src/opcode_list.h ================================================ OP(LOADK, CONSTANT, 1, 1) OP(DUP, NONE, 1, 2) OP(DUPN, NONE, 1, 2) OP(DUP2, NONE, 2, 3) OP(PUSHK_UNDER, CONSTANT, 1, 2) OP(POP, NONE, 1, 0) OP(LOADV, VARIABLE, 1, 1) OP(LOADVN, VARIABLE, 1, 1) OP(STOREV, VARIABLE, 1, 0) OP(STORE_GLOBAL, GLOBAL, 0, 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(TRY_BEGIN, BRANCH, 0, 0) OP(TRY_END, NONE, 0, 0) OP(JUMP, BRANCH, 0, 0) OP(JUMP_F,BRANCH, 1, 0) OP(BACKTRACK, NONE, 0, 0) OP(APPEND, VARIABLE,1, 0) OP(INSERT, NONE, 4, 2) OP(RANGE, VARIABLE, 1, 1) OP(SUBEXP_BEGIN, NONE, 1, 2) OP(SUBEXP_END, NONE, 2, 2) OP(PATH_BEGIN, NONE, 1, 2) OP(PATH_END, NONE, 2, 1) 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) OP(CLOSURE_CREATE, DEFINITION, 0, 0) OP(CLOSURE_CREATE_C, DEFINITION, 0, 0) OP(TOP, NONE, 0, 0) OP(CLOSURE_PARAM_REGULAR, DEFINITION, 0, 0) OP(DEPS, CONSTANT, 0, 0) OP(MODULEMETA, CONSTANT, 0, 0) OP(GENLABEL, NONE, 0, 1) OP(DESTRUCTURE_ALT, BRANCH, 0, 0) OP(STOREVN, VARIABLE, 1, 0) OP(ERRORK, CONSTANT, 1, 0) ================================================ FILE: src/parser.c ================================================ /* A Bison parser, made by GNU Bison 3.8.2. */ /* Bison implementation for Yacc-like parsers in C Copyright (C) 1984, 1989-1990, 2000-2015, 2018-2021 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 3 of the License, 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 . */ /* As a special exception, you may create a larger work that contains part or all of the Bison parser skeleton and distribute that work under terms of your choice, so long as that work isn't itself a parser generator using the skeleton or a modified version thereof as a parser skeleton. Alternatively, if you modify or redistribute the parser skeleton itself, you may (at your option) remove this special exception, which will cause the skeleton and the resulting Bison output files to be licensed under the GNU General Public License without this special exception. This special exception was added by the Free Software Foundation in version 2.2 of Bison. */ /* C LALR(1) parser skeleton written by Richard Stallman, by simplifying the original so-called "semantic" parser. */ /* DO NOT RELY ON FEATURES THAT ARE NOT DOCUMENTED in the manual, especially those whose name start with YY_ or yy_. They are private implementation details that can be changed or removed. */ /* All symbols defined below should begin with yy or YY, to avoid infringing on user name space. This should be done even for local variables, as they might otherwise be expanded by user macros. There are some unavoidable exceptions within include files to define necessary library symbols; they are noted "INFRINGES ON USER NAME SPACE" below. */ /* Identify Bison output, and Bison version. */ #define YYBISON 30802 /* Bison version string. */ #define YYBISON_VERSION "3.8.2" /* Skeleton name. */ #define YYSKELETON_NAME "yacc.c" /* Pure parsers. */ #define YYPURE 1 /* Push parsers. */ #define YYPUSH 0 /* Pull parsers. */ #define YYPULL 1 /* First part of user prologue. */ #line 1 "src/parser.y" #include #include #include #include #include "compile.h" #include "jv_alloc.h" #include "builtin.h" #define YYMALLOC jv_mem_alloc #define YYFREE jv_mem_free #line 83 "src/parser.c" # ifndef YY_CAST # ifdef __cplusplus # define YY_CAST(Type, Val) static_cast (Val) # define YY_REINTERPRET_CAST(Type, Val) reinterpret_cast (Val) # else # define YY_CAST(Type, Val) ((Type) (Val)) # define YY_REINTERPRET_CAST(Type, Val) ((Type) (Val)) # endif # endif # ifndef YY_NULLPTR # if defined __cplusplus # if 201103L <= __cplusplus # define YY_NULLPTR nullptr # else # define YY_NULLPTR 0 # endif # else # define YY_NULLPTR ((void*)0) # endif # endif /* Use api.header.include to #include this header instead of duplicating it here. */ #ifndef YY_YY_SRC_PARSER_H_INCLUDED # define YY_YY_SRC_PARSER_H_INCLUDED /* Debug traces. */ #ifndef YYDEBUG # define YYDEBUG 0 #endif #if YYDEBUG extern int yydebug; #endif /* "%code requires" blocks. */ #line 12 "src/parser.y" #include "locfile.h" struct lexer_param; #define YYLTYPE location #define YYLLOC_DEFAULT(Loc, Rhs, N) \ do { \ if (N) { \ (Loc).start = YYRHSLOC(Rhs, 1).start; \ (Loc).end = YYRHSLOC(Rhs, N).end; \ } else { \ (Loc).start = YYRHSLOC(Rhs, 0).end; \ (Loc).end = YYRHSLOC(Rhs, 0).end; \ } \ } while (0) #line 135 "src/parser.c" /* Token kinds. */ #ifndef YYTOKENTYPE # define YYTOKENTYPE enum yytokentype { YYEMPTY = -2, YYEOF = 0, /* "end of file" */ YYerror = 256, /* error */ YYUNDEF = 257, /* "invalid token" */ INVALID_CHARACTER = 258, /* INVALID_CHARACTER */ IDENT = 259, /* IDENT */ FIELD = 260, /* FIELD */ BINDING = 261, /* BINDING */ LITERAL = 262, /* LITERAL */ FORMAT = 263, /* FORMAT */ REC = 264, /* ".." */ SETMOD = 265, /* "%=" */ EQ = 266, /* "==" */ NEQ = 267, /* "!=" */ DEFINEDOR = 268, /* "//" */ AS = 269, /* "as" */ DEF = 270, /* "def" */ MODULE = 271, /* "module" */ IMPORT = 272, /* "import" */ INCLUDE = 273, /* "include" */ IF = 274, /* "if" */ THEN = 275, /* "then" */ ELSE = 276, /* "else" */ ELSE_IF = 277, /* "elif" */ REDUCE = 278, /* "reduce" */ FOREACH = 279, /* "foreach" */ END = 280, /* "end" */ AND = 281, /* "and" */ OR = 282, /* "or" */ TRY = 283, /* "try" */ CATCH = 284, /* "catch" */ LABEL = 285, /* "label" */ BREAK = 286, /* "break" */ LOC = 287, /* "$__loc__" */ SETPIPE = 288, /* "|=" */ SETPLUS = 289, /* "+=" */ SETMINUS = 290, /* "-=" */ SETMULT = 291, /* "*=" */ SETDIV = 292, /* "/=" */ SETDEFINEDOR = 293, /* "//=" */ LESSEQ = 294, /* "<=" */ GREATEREQ = 295, /* ">=" */ ALTERNATION = 296, /* "?//" */ QQSTRING_START = 297, /* QQSTRING_START */ QQSTRING_TEXT = 298, /* QQSTRING_TEXT */ QQSTRING_INTERP_START = 299, /* QQSTRING_INTERP_START */ QQSTRING_INTERP_END = 300, /* QQSTRING_INTERP_END */ QQSTRING_END = 301, /* QQSTRING_END */ FUNCDEF = 302, /* FUNCDEF */ NONOPT = 303 /* NONOPT */ }; typedef enum yytokentype yytoken_kind_t; #endif /* Token kinds. */ #define YYEMPTY -2 #define YYEOF 0 #define YYerror 256 #define YYUNDEF 257 #define INVALID_CHARACTER 258 #define IDENT 259 #define FIELD 260 #define BINDING 261 #define LITERAL 262 #define FORMAT 263 #define REC 264 #define SETMOD 265 #define EQ 266 #define NEQ 267 #define DEFINEDOR 268 #define AS 269 #define DEF 270 #define MODULE 271 #define IMPORT 272 #define INCLUDE 273 #define IF 274 #define THEN 275 #define ELSE 276 #define ELSE_IF 277 #define REDUCE 278 #define FOREACH 279 #define END 280 #define AND 281 #define OR 282 #define TRY 283 #define CATCH 284 #define LABEL 285 #define BREAK 286 #define LOC 287 #define SETPIPE 288 #define SETPLUS 289 #define SETMINUS 290 #define SETMULT 291 #define SETDIV 292 #define SETDEFINEDOR 293 #define LESSEQ 294 #define GREATEREQ 295 #define ALTERNATION 296 #define QQSTRING_START 297 #define QQSTRING_TEXT 298 #define QQSTRING_INTERP_START 299 #define QQSTRING_INTERP_END 300 #define QQSTRING_END 301 #define FUNCDEF 302 #define NONOPT 303 /* Value type. */ #if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED union YYSTYPE { #line 32 "src/parser.y" jv literal; block blk; #line 256 "src/parser.c" }; typedef union YYSTYPE YYSTYPE; # define YYSTYPE_IS_TRIVIAL 1 # define YYSTYPE_IS_DECLARED 1 #endif /* Location type. */ #if ! defined YYLTYPE && ! defined YYLTYPE_IS_DECLARED typedef struct YYLTYPE YYLTYPE; struct YYLTYPE { int first_line; int first_column; int last_line; int last_column; }; # define YYLTYPE_IS_DECLARED 1 # define YYLTYPE_IS_TRIVIAL 1 #endif int yyparse (block* answer, int* errors, struct locfile* locations, struct lexer_param* lexer_param_ptr); #endif /* !YY_YY_SRC_PARSER_H_INCLUDED */ /* Symbol kind. */ enum yysymbol_kind_t { YYSYMBOL_YYEMPTY = -2, YYSYMBOL_YYEOF = 0, /* "end of file" */ YYSYMBOL_YYerror = 1, /* error */ YYSYMBOL_YYUNDEF = 2, /* "invalid token" */ YYSYMBOL_INVALID_CHARACTER = 3, /* INVALID_CHARACTER */ YYSYMBOL_IDENT = 4, /* IDENT */ YYSYMBOL_FIELD = 5, /* FIELD */ YYSYMBOL_BINDING = 6, /* BINDING */ YYSYMBOL_LITERAL = 7, /* LITERAL */ YYSYMBOL_FORMAT = 8, /* FORMAT */ YYSYMBOL_REC = 9, /* ".." */ YYSYMBOL_SETMOD = 10, /* "%=" */ YYSYMBOL_EQ = 11, /* "==" */ YYSYMBOL_NEQ = 12, /* "!=" */ YYSYMBOL_DEFINEDOR = 13, /* "//" */ YYSYMBOL_AS = 14, /* "as" */ YYSYMBOL_DEF = 15, /* "def" */ YYSYMBOL_MODULE = 16, /* "module" */ YYSYMBOL_IMPORT = 17, /* "import" */ YYSYMBOL_INCLUDE = 18, /* "include" */ YYSYMBOL_IF = 19, /* "if" */ YYSYMBOL_THEN = 20, /* "then" */ YYSYMBOL_ELSE = 21, /* "else" */ YYSYMBOL_ELSE_IF = 22, /* "elif" */ YYSYMBOL_REDUCE = 23, /* "reduce" */ YYSYMBOL_FOREACH = 24, /* "foreach" */ YYSYMBOL_END = 25, /* "end" */ YYSYMBOL_AND = 26, /* "and" */ YYSYMBOL_OR = 27, /* "or" */ YYSYMBOL_TRY = 28, /* "try" */ YYSYMBOL_CATCH = 29, /* "catch" */ YYSYMBOL_LABEL = 30, /* "label" */ YYSYMBOL_BREAK = 31, /* "break" */ YYSYMBOL_LOC = 32, /* "$__loc__" */ YYSYMBOL_SETPIPE = 33, /* "|=" */ YYSYMBOL_SETPLUS = 34, /* "+=" */ YYSYMBOL_SETMINUS = 35, /* "-=" */ YYSYMBOL_SETMULT = 36, /* "*=" */ YYSYMBOL_SETDIV = 37, /* "/=" */ YYSYMBOL_SETDEFINEDOR = 38, /* "//=" */ YYSYMBOL_LESSEQ = 39, /* "<=" */ YYSYMBOL_GREATEREQ = 40, /* ">=" */ YYSYMBOL_ALTERNATION = 41, /* "?//" */ YYSYMBOL_QQSTRING_START = 42, /* QQSTRING_START */ YYSYMBOL_QQSTRING_TEXT = 43, /* QQSTRING_TEXT */ YYSYMBOL_QQSTRING_INTERP_START = 44, /* QQSTRING_INTERP_START */ YYSYMBOL_QQSTRING_INTERP_END = 45, /* QQSTRING_INTERP_END */ YYSYMBOL_QQSTRING_END = 46, /* QQSTRING_END */ YYSYMBOL_FUNCDEF = 47, /* FUNCDEF */ YYSYMBOL_48_ = 48, /* '|' */ YYSYMBOL_49_ = 49, /* ',' */ YYSYMBOL_50_ = 50, /* '=' */ YYSYMBOL_51_ = 51, /* '<' */ YYSYMBOL_52_ = 52, /* '>' */ YYSYMBOL_53_ = 53, /* '+' */ YYSYMBOL_54_ = 54, /* '-' */ YYSYMBOL_55_ = 55, /* '*' */ YYSYMBOL_56_ = 56, /* '/' */ YYSYMBOL_57_ = 57, /* '%' */ YYSYMBOL_NONOPT = 58, /* NONOPT */ YYSYMBOL_59_ = 59, /* '?' */ YYSYMBOL_60_ = 60, /* '.' */ YYSYMBOL_61_ = 61, /* '[' */ YYSYMBOL_62_ = 62, /* ';' */ YYSYMBOL_63_ = 63, /* ':' */ YYSYMBOL_64_ = 64, /* '(' */ YYSYMBOL_65_ = 65, /* ')' */ YYSYMBOL_66_ = 66, /* ']' */ YYSYMBOL_67_ = 67, /* '{' */ YYSYMBOL_68_ = 68, /* '}' */ YYSYMBOL_69_ = 69, /* '$' */ YYSYMBOL_YYACCEPT = 70, /* $accept */ YYSYMBOL_TopLevel = 71, /* TopLevel */ YYSYMBOL_Module = 72, /* Module */ YYSYMBOL_Imports = 73, /* Imports */ YYSYMBOL_FuncDefs = 74, /* FuncDefs */ YYSYMBOL_Query = 75, /* Query */ YYSYMBOL_Expr = 76, /* Expr */ YYSYMBOL_Import = 77, /* Import */ YYSYMBOL_ImportWhat = 78, /* ImportWhat */ YYSYMBOL_ImportFrom = 79, /* ImportFrom */ YYSYMBOL_FuncDef = 80, /* FuncDef */ YYSYMBOL_Params = 81, /* Params */ YYSYMBOL_Param = 82, /* Param */ YYSYMBOL_StringStart = 83, /* StringStart */ YYSYMBOL_String = 84, /* String */ YYSYMBOL_QQString = 85, /* QQString */ YYSYMBOL_ElseBody = 86, /* ElseBody */ YYSYMBOL_Term = 87, /* Term */ YYSYMBOL_Args = 88, /* Args */ YYSYMBOL_Arg = 89, /* Arg */ YYSYMBOL_RepPatterns = 90, /* RepPatterns */ YYSYMBOL_Patterns = 91, /* Patterns */ YYSYMBOL_Pattern = 92, /* Pattern */ YYSYMBOL_ArrayPats = 93, /* ArrayPats */ YYSYMBOL_ObjPats = 94, /* ObjPats */ YYSYMBOL_ObjPat = 95, /* ObjPat */ YYSYMBOL_Keyword = 96, /* Keyword */ YYSYMBOL_DictPairs = 97, /* DictPairs */ YYSYMBOL_DictPair = 98, /* DictPair */ YYSYMBOL_DictExpr = 99 /* DictExpr */ }; typedef enum yysymbol_kind_t yysymbol_kind_t; /* Second part of user prologue. */ #line 127 "src/parser.y" #include "lexer.h" struct lexer_param { yyscan_t lexer; }; #define FAIL(loc, msg) \ do { \ location l = loc; \ yyerror(&l, answer, errors, locations, lexer_param_ptr, msg); \ /*YYERROR*/; \ } while (0) void yyerror(YYLTYPE* loc, block* answer, int* errors, struct locfile* locations, struct lexer_param* lexer_param_ptr, const char *s){ (*errors)++; locfile_locate(locations, *loc, "jq: error: %s", s); } 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)); } else { FAIL(*yylloc, "Invalid literal"); } jv_free(msg); jv_free(yylval->literal); yylval->literal = jv_null(); } return tok; } /* Returns string message if the block is a constant that is not valid as an * object key. */ static jv check_object_key(block k) { if (block_is_const(k) && block_const_kind(k) != JV_KIND_STRING) { char errbuf[30]; return jv_string_fmt("Cannot use %s (%s) as object key", jv_kind_name(block_const_kind(k)), jv_dump_string_trunc(block_const(k), errbuf, sizeof(errbuf))); } return jv_invalid(); } 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) { block key = BLOCK(gen_subexp(gen_const(jv_object())), gen_subexp(gen_const(jv_string("start"))), gen_subexp(start), gen_op_simple(INSERT), gen_subexp(gen_const(jv_string("end"))), gen_subexp(end), gen_op_simple(INSERT)); return BLOCK(key, obj, gen_op_simple(idx_op)); } static block constant_fold(block a, block b, int op) { if (!block_is_single(a) || !block_is_const(a) || !block_is_single(b) || !block_is_const(b)) return gen_noop(); jv jv_a = block_const(a); block_free(a); jv jv_b = block_const(b); block_free(b); jv res = jv_invalid(); switch (op) { case '+': res = binop_plus(jv_a, jv_b); break; case '-': res = binop_minus(jv_a, jv_b); break; case '*': res = binop_multiply(jv_a, jv_b); break; case '/': res = binop_divide(jv_a, jv_b); break; case '%': res = binop_mod(jv_a, jv_b); break; case EQ: res = binop_equal(jv_a, jv_b); break; case NEQ: res = binop_notequal(jv_a, jv_b); break; case '<': res = binop_less(jv_a, jv_b); break; case '>': res = binop_greater(jv_a, jv_b); break; case LESSEQ: res = binop_lesseq(jv_a, jv_b); break; case GREATEREQ: res = binop_greatereq(jv_a, jv_b); break; } if (jv_is_valid(res)) return gen_const(res); return gen_error(jv_invalid_get_msg(res)); } static block gen_binop(block a, block b, int op) { block folded = constant_fold(a, b, op); if (!block_is_noop(folded)) return folded; const char* funcname = 0; switch (op) { case '+': funcname = "_plus"; break; 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; case '>': funcname = "_greater"; break; case LESSEQ: funcname = "_lesseq"; break; case GREATEREQ: funcname = "_greatereq"; break; } assert(funcname); return gen_call(funcname, BLOCK(gen_lambda(a), gen_lambda(b))); } static block gen_format(block a, jv fmt) { return BLOCK(a, gen_call("format", gen_lambda(gen_const(fmt)))); } static block gen_definedor_assign(block object, block val) { block tmp = gen_op_var_fresh(STOREV, "tmp"); 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)))))); } static block gen_update(block object, block val, int optype) { block tmp = gen_op_var_fresh(STOREV, "tmp"); 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), optype))))); } static block gen_loc_object(location *loc, struct locfile *locations) { return gen_const(JV_OBJECT(jv_string("file"), jv_copy(locations->fname), jv_string("line"), jv_number(locfile_get_line(locations, loc->start) + 1))); } #line 547 "src/parser.c" #ifdef short # undef short #endif /* On compilers that do not define __PTRDIFF_MAX__ etc., make sure and (if available) are included so that the code can choose integer types of a good width. */ #ifndef __PTRDIFF_MAX__ # include /* INFRINGES ON USER NAME SPACE */ # if defined __STDC_VERSION__ && 199901 <= __STDC_VERSION__ # include /* INFRINGES ON USER NAME SPACE */ # define YY_STDINT_H # endif #endif /* Narrow types that promote to a signed type and that can represent a signed or unsigned integer of at least N bits. In tables they can save space and decrease cache pressure. Promoting to a signed type helps avoid bugs in integer arithmetic. */ #ifdef __INT_LEAST8_MAX__ typedef __INT_LEAST8_TYPE__ yytype_int8; #elif defined YY_STDINT_H typedef int_least8_t yytype_int8; #else typedef signed char yytype_int8; #endif #ifdef __INT_LEAST16_MAX__ typedef __INT_LEAST16_TYPE__ yytype_int16; #elif defined YY_STDINT_H typedef int_least16_t yytype_int16; #else typedef short yytype_int16; #endif /* Work around bug in HP-UX 11.23, which defines these macros incorrectly for preprocessor constants. This workaround can likely be removed in 2023, as HPE has promised support for HP-UX 11.23 (aka HP-UX 11i v2) only through the end of 2022; see Table 2 of . */ #ifdef __hpux # undef UINT_LEAST8_MAX # undef UINT_LEAST16_MAX # define UINT_LEAST8_MAX 255 # define UINT_LEAST16_MAX 65535 #endif #if defined __UINT_LEAST8_MAX__ && __UINT_LEAST8_MAX__ <= __INT_MAX__ typedef __UINT_LEAST8_TYPE__ yytype_uint8; #elif (!defined __UINT_LEAST8_MAX__ && defined YY_STDINT_H \ && UINT_LEAST8_MAX <= INT_MAX) typedef uint_least8_t yytype_uint8; #elif !defined __UINT_LEAST8_MAX__ && UCHAR_MAX <= INT_MAX typedef unsigned char yytype_uint8; #else typedef short yytype_uint8; #endif #if defined __UINT_LEAST16_MAX__ && __UINT_LEAST16_MAX__ <= __INT_MAX__ typedef __UINT_LEAST16_TYPE__ yytype_uint16; #elif (!defined __UINT_LEAST16_MAX__ && defined YY_STDINT_H \ && UINT_LEAST16_MAX <= INT_MAX) typedef uint_least16_t yytype_uint16; #elif !defined __UINT_LEAST16_MAX__ && USHRT_MAX <= INT_MAX typedef unsigned short yytype_uint16; #else typedef int yytype_uint16; #endif #ifndef YYPTRDIFF_T # if defined __PTRDIFF_TYPE__ && defined __PTRDIFF_MAX__ # define YYPTRDIFF_T __PTRDIFF_TYPE__ # define YYPTRDIFF_MAXIMUM __PTRDIFF_MAX__ # elif defined PTRDIFF_MAX # ifndef ptrdiff_t # include /* INFRINGES ON USER NAME SPACE */ # endif # define YYPTRDIFF_T ptrdiff_t # define YYPTRDIFF_MAXIMUM PTRDIFF_MAX # else # define YYPTRDIFF_T long # define YYPTRDIFF_MAXIMUM LONG_MAX # endif #endif #ifndef YYSIZE_T # ifdef __SIZE_TYPE__ # define YYSIZE_T __SIZE_TYPE__ # elif defined size_t # define YYSIZE_T size_t # elif defined __STDC_VERSION__ && 199901 <= __STDC_VERSION__ # include /* INFRINGES ON USER NAME SPACE */ # define YYSIZE_T size_t # else # define YYSIZE_T unsigned # endif #endif #define YYSIZE_MAXIMUM \ YY_CAST (YYPTRDIFF_T, \ (YYPTRDIFF_MAXIMUM < YY_CAST (YYSIZE_T, -1) \ ? YYPTRDIFF_MAXIMUM \ : YY_CAST (YYSIZE_T, -1))) #define YYSIZEOF(X) YY_CAST (YYPTRDIFF_T, sizeof (X)) /* Stored state numbers (used for stacks). */ typedef yytype_int16 yy_state_t; /* State numbers in computations. */ typedef int yy_state_fast_t; #ifndef YY_ # if defined YYENABLE_NLS && YYENABLE_NLS # if ENABLE_NLS # include /* INFRINGES ON USER NAME SPACE */ # define YY_(Msgid) dgettext ("bison-runtime", Msgid) # endif # endif # ifndef YY_ # define YY_(Msgid) Msgid # endif #endif #ifndef YY_ATTRIBUTE_PURE # if defined __GNUC__ && 2 < __GNUC__ + (96 <= __GNUC_MINOR__) # define YY_ATTRIBUTE_PURE __attribute__ ((__pure__)) # else # define YY_ATTRIBUTE_PURE # endif #endif #ifndef YY_ATTRIBUTE_UNUSED # if defined __GNUC__ && 2 < __GNUC__ + (7 <= __GNUC_MINOR__) # define YY_ATTRIBUTE_UNUSED __attribute__ ((__unused__)) # else # define YY_ATTRIBUTE_UNUSED # endif #endif /* Suppress unused-variable warnings by "using" E. */ #if ! defined lint || defined __GNUC__ # define YY_USE(E) ((void) (E)) #else # define YY_USE(E) /* empty */ #endif /* Suppress an incorrect diagnostic about yylval being uninitialized. */ #if defined __GNUC__ && ! defined __ICC && 406 <= __GNUC__ * 100 + __GNUC_MINOR__ # if __GNUC__ * 100 + __GNUC_MINOR__ < 407 # define YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN \ _Pragma ("GCC diagnostic push") \ _Pragma ("GCC diagnostic ignored \"-Wuninitialized\"") # else # define YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN \ _Pragma ("GCC diagnostic push") \ _Pragma ("GCC diagnostic ignored \"-Wuninitialized\"") \ _Pragma ("GCC diagnostic ignored \"-Wmaybe-uninitialized\"") # endif # define YY_IGNORE_MAYBE_UNINITIALIZED_END \ _Pragma ("GCC diagnostic pop") #else # define YY_INITIAL_VALUE(Value) Value #endif #ifndef YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN # define YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN # define YY_IGNORE_MAYBE_UNINITIALIZED_END #endif #ifndef YY_INITIAL_VALUE # define YY_INITIAL_VALUE(Value) /* Nothing. */ #endif #if defined __cplusplus && defined __GNUC__ && ! defined __ICC && 6 <= __GNUC__ # define YY_IGNORE_USELESS_CAST_BEGIN \ _Pragma ("GCC diagnostic push") \ _Pragma ("GCC diagnostic ignored \"-Wuseless-cast\"") # define YY_IGNORE_USELESS_CAST_END \ _Pragma ("GCC diagnostic pop") #endif #ifndef YY_IGNORE_USELESS_CAST_BEGIN # define YY_IGNORE_USELESS_CAST_BEGIN # define YY_IGNORE_USELESS_CAST_END #endif #define YY_ASSERT(E) ((void) (0 && (E))) #if 1 /* The parser invokes alloca or malloc; define the necessary symbols. */ # ifdef YYSTACK_USE_ALLOCA # if YYSTACK_USE_ALLOCA # ifdef __GNUC__ # define YYSTACK_ALLOC __builtin_alloca # elif defined __BUILTIN_VA_ARG_INCR # include /* INFRINGES ON USER NAME SPACE */ # elif defined _AIX # define YYSTACK_ALLOC __alloca # elif defined _MSC_VER # include /* INFRINGES ON USER NAME SPACE */ # define alloca _alloca # else # define YYSTACK_ALLOC alloca # if ! defined _ALLOCA_H && ! defined EXIT_SUCCESS # include /* INFRINGES ON USER NAME SPACE */ /* Use EXIT_SUCCESS as a witness for stdlib.h. */ # ifndef EXIT_SUCCESS # define EXIT_SUCCESS 0 # endif # endif # endif # endif # endif # ifdef YYSTACK_ALLOC /* Pacify GCC's 'empty if-body' warning. */ # define YYSTACK_FREE(Ptr) do { /* empty */; } while (0) # ifndef YYSTACK_ALLOC_MAXIMUM /* The OS might guarantee only one guard page at the bottom of the stack, and a page size can be as small as 4096 bytes. So we cannot safely invoke alloca (N) if N exceeds 4096. Use a slightly smaller number to allow for a few compiler-allocated temporary stack slots. */ # define YYSTACK_ALLOC_MAXIMUM 4032 /* reasonable circa 2006 */ # endif # else # define YYSTACK_ALLOC YYMALLOC # define YYSTACK_FREE YYFREE # ifndef YYSTACK_ALLOC_MAXIMUM # define YYSTACK_ALLOC_MAXIMUM YYSIZE_MAXIMUM # endif # if (defined __cplusplus && ! defined EXIT_SUCCESS \ && ! ((defined YYMALLOC || defined malloc) \ && (defined YYFREE || defined free))) # include /* INFRINGES ON USER NAME SPACE */ # ifndef EXIT_SUCCESS # define EXIT_SUCCESS 0 # endif # endif # ifndef YYMALLOC # define YYMALLOC malloc # if ! defined malloc && ! defined EXIT_SUCCESS void *malloc (YYSIZE_T); /* INFRINGES ON USER NAME SPACE */ # endif # endif # ifndef YYFREE # define YYFREE free # if ! defined free && ! defined EXIT_SUCCESS void free (void *); /* INFRINGES ON USER NAME SPACE */ # endif # endif # endif #endif /* 1 */ #if (! defined yyoverflow \ && (! defined __cplusplus \ || (defined YYLTYPE_IS_TRIVIAL && YYLTYPE_IS_TRIVIAL \ && defined YYSTYPE_IS_TRIVIAL && YYSTYPE_IS_TRIVIAL))) /* A type that is properly aligned for any stack member. */ union yyalloc { yy_state_t yyss_alloc; YYSTYPE yyvs_alloc; YYLTYPE yyls_alloc; }; /* The size of the maximum gap between one aligned stack and the next. */ # define YYSTACK_GAP_MAXIMUM (YYSIZEOF (union yyalloc) - 1) /* The size of an array large to enough to hold all stacks, each with N elements. */ # define YYSTACK_BYTES(N) \ ((N) * (YYSIZEOF (yy_state_t) + YYSIZEOF (YYSTYPE) \ + YYSIZEOF (YYLTYPE)) \ + 2 * YYSTACK_GAP_MAXIMUM) # define YYCOPY_NEEDED 1 /* Relocate STACK from its old location to the new one. The local variables YYSIZE and YYSTACKSIZE give the old and new number of elements in the stack, and YYPTR gives the new location of the stack. Advance YYPTR to a properly aligned location for the next stack. */ # define YYSTACK_RELOCATE(Stack_alloc, Stack) \ do \ { \ YYPTRDIFF_T yynewbytes; \ YYCOPY (&yyptr->Stack_alloc, Stack, yysize); \ Stack = &yyptr->Stack_alloc; \ yynewbytes = yystacksize * YYSIZEOF (*Stack) + YYSTACK_GAP_MAXIMUM; \ yyptr += yynewbytes / YYSIZEOF (*yyptr); \ } \ while (0) #endif #if defined YYCOPY_NEEDED && YYCOPY_NEEDED /* Copy COUNT objects from SRC to DST. The source and destination do not overlap. */ # ifndef YYCOPY # if defined __GNUC__ && 1 < __GNUC__ # define YYCOPY(Dst, Src, Count) \ __builtin_memcpy (Dst, Src, YY_CAST (YYSIZE_T, (Count)) * sizeof (*(Src))) # else # define YYCOPY(Dst, Src, Count) \ do \ { \ YYPTRDIFF_T yyi; \ for (yyi = 0; yyi < (Count); yyi++) \ (Dst)[yyi] = (Src)[yyi]; \ } \ while (0) # endif # endif #endif /* !YYCOPY_NEEDED */ /* YYFINAL -- State number of the termination state. */ #define YYFINAL 31 /* YYLAST -- Last index in YYTABLE. */ #define YYLAST 1226 /* YYNTOKENS -- Number of terminals. */ #define YYNTOKENS 70 /* YYNNTS -- Number of nonterminals. */ #define YYNNTS 30 /* YYNRULES -- Number of rules. */ #define YYNRULES 168 /* YYNSTATES -- Number of states. */ #define YYNSTATES 312 /* YYMAXUTOK -- Last valid token kind. */ #define YYMAXUTOK 303 /* YYTRANSLATE(TOKEN-NUM) -- Symbol number corresponding to TOKEN-NUM as returned by yylex, with out-of-bounds checking. */ #define YYTRANSLATE(YYX) \ (0 <= (YYX) && (YYX) <= YYMAXUTOK \ ? YY_CAST (yysymbol_kind_t, yytranslate[YYX]) \ : YYSYMBOL_YYUNDEF) /* YYTRANSLATE[TOKEN-NUM] -- Symbol number corresponding to TOKEN-NUM as returned by yylex. */ static const yytype_int8 yytranslate[] = { 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 69, 57, 2, 2, 64, 65, 55, 53, 49, 54, 60, 56, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 63, 62, 51, 50, 52, 59, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 61, 2, 66, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 67, 48, 68, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 58 }; #if YYDEBUG /* YYRLINE[YYN] -- Source line where rule number YYN was defined. */ static const yytype_int16 yyrline[] = { 0, 282, 282, 285, 290, 293, 308, 311, 316, 319, 325, 328, 331, 337, 340, 343, 349, 352, 355, 358, 361, 364, 367, 370, 373, 376, 379, 382, 385, 388, 391, 394, 397, 400, 403, 406, 409, 412, 415, 421, 424, 441, 450, 457, 465, 476, 481, 487, 490, 495, 499, 506, 509, 515, 522, 525, 528, 534, 537, 540, 546, 549, 552, 560, 564, 567, 570, 573, 576, 579, 582, 585, 588, 592, 598, 601, 604, 607, 610, 613, 616, 619, 622, 625, 628, 631, 634, 637, 640, 643, 646, 649, 652, 655, 658, 661, 664, 671, 674, 677, 680, 683, 687, 690, 694, 712, 716, 720, 723, 735, 740, 741, 742, 743, 746, 749, 754, 759, 762, 767, 770, 775, 779, 782, 787, 790, 795, 798, 803, 806, 809, 812, 815, 818, 826, 832, 835, 838, 841, 844, 847, 850, 853, 856, 859, 862, 865, 868, 871, 874, 877, 880, 883, 889, 892, 895, 900, 903, 906, 909, 913, 918, 922, 926, 930, 934, 942, 948, 951 }; #endif /** Accessing symbol of state STATE. */ #define YY_ACCESSING_SYMBOL(State) YY_CAST (yysymbol_kind_t, yystos[State]) #if 1 /* The user-facing name of the symbol whose (internal) number is YYSYMBOL. No bounds checking. */ static const char *yysymbol_name (yysymbol_kind_t yysymbol) YY_ATTRIBUTE_UNUSED; /* YYTNAME[SYMBOL-NUM] -- String name of the symbol SYMBOL-NUM. First, the terminals, then, starting at YYNTOKENS, nonterminals. */ static const char *const yytname[] = { "\"end of file\"", "error", "\"invalid token\"", "INVALID_CHARACTER", "IDENT", "FIELD", "BINDING", "LITERAL", "FORMAT", "\"..\"", "\"%=\"", "\"==\"", "\"!=\"", "\"//\"", "\"as\"", "\"def\"", "\"module\"", "\"import\"", "\"include\"", "\"if\"", "\"then\"", "\"else\"", "\"elif\"", "\"reduce\"", "\"foreach\"", "\"end\"", "\"and\"", "\"or\"", "\"try\"", "\"catch\"", "\"label\"", "\"break\"", "\"$__loc__\"", "\"|=\"", "\"+=\"", "\"-=\"", "\"*=\"", "\"/=\"", "\"//=\"", "\"<=\"", "\">=\"", "\"?//\"", "QQSTRING_START", "QQSTRING_TEXT", "QQSTRING_INTERP_START", "QQSTRING_INTERP_END", "QQSTRING_END", "FUNCDEF", "'|'", "','", "'='", "'<'", "'>'", "'+'", "'-'", "'*'", "'/'", "'%'", "NONOPT", "'?'", "'.'", "'['", "';'", "':'", "'('", "')'", "']'", "'{'", "'}'", "'$'", "$accept", "TopLevel", "Module", "Imports", "FuncDefs", "Query", "Expr", "Import", "ImportWhat", "ImportFrom", "FuncDef", "Params", "Param", "StringStart", "String", "QQString", "ElseBody", "Term", "Args", "Arg", "RepPatterns", "Patterns", "Pattern", "ArrayPats", "ObjPats", "ObjPat", "Keyword", "DictPairs", "DictPair", "DictExpr", YY_NULLPTR }; static const char * yysymbol_name (yysymbol_kind_t yysymbol) { return yytname[yysymbol]; } #endif #define YYPACT_NINF (-146) #define yypact_value_is_default(Yyn) \ ((Yyn) == YYPACT_NINF) #define YYTABLE_NINF (-154) #define yytable_value_is_error(Yyn) \ ((Yyn) == YYTABLE_NINF) /* YYPACT[STATE-NUM] -- Index in YYTABLE of the portion describing STATE-NUM. */ static const yytype_int16 yypact[] = { 31, 890, 44, 35, 11, 9, -146, -146, 38, -146, 85, 890, 956, 956, 956, 112, 26, -146, -146, 956, 279, 345, 412, 608, 59, 25, 1040, 890, -146, -146, -2, -146, 4, 4, 890, 35, 692, 890, -146, -146, 20, -18, 1073, 1105, 131, 86, -146, -146, -2, -146, 164, 38, 108, 107, -146, 22, 104, 0, -34, 121, 124, -146, -146, -146, -146, -146, -146, -146, -146, -146, -146, -146, -146, -146, -146, -146, -146, -146, -146, -146, 890, 135, 137, 134, 126, 141, 890, 890, -146, 956, 956, 956, 956, -5, 956, 956, 956, 956, 956, 956, 956, 956, 956, 956, 956, 956, 956, 956, 956, 956, 956, 956, 84, 177, 147, -146, 3, 173, 199, -146, -146, -146, 84, 890, -146, -146, 114, 84, 77, -146, 890, 13, 479, -5, -5, 546, 890, -146, -146, -146, -146, -146, -146, 956, -146, 956, 956, 78, 956, 956, -146, 663, 220, 84, -146, 1169, 505, 505, 1137, -146, -5, 1018, 187, 166, 188, 606, 205, 1169, 1169, 1169, 1169, 1169, 1169, 505, 505, 1169, 505, 505, 208, 208, -146, -146, -146, -146, 890, -146, -146, 758, 176, 175, 890, 184, 6, 57, -146, -146, 890, -146, 123, -146, -146, 83, -146, -146, 18, 185, 189, -146, -146, 84, 1137, 200, 200, 200, 203, 200, 200, 206, -146, -146, -146, -42, 207, 209, 210, 890, 212, -45, -146, 213, -5, 890, 33, 193, 28, -146, -146, 71, -146, 824, 218, -146, -146, -146, -146, 13, 215, 890, 890, -146, -146, 890, 890, 956, 956, -5, -146, -5, -5, -5, 103, -5, 1018, -146, -5, 227, 84, -146, -146, 222, 223, 226, 74, -146, -146, 890, -7, 2, 160, 163, 200, 200, -146, -146, -146, -146, 225, -146, -146, -146, -146, -146, -146, 235, 170, -146, 890, 890, 890, -5, -146, -146, 18, 105, 76, -146, -146, -146, 890, -146, 142, -146 }; /* YYDEFACT[STATE-NUM] -- Default reduction number in state STATE-NUM. Performed when YYTABLE does not specify something else to do. Zero means the default is an error. */ static const yytype_uint8 yydefact[] = { 4, 0, 0, 6, 108, 69, 106, 89, 91, 61, 0, 0, 0, 0, 0, 0, 0, 107, 52, 0, 0, 0, 0, 0, 0, 0, 15, 0, 54, 90, 38, 1, 0, 0, 8, 6, 0, 0, 65, 51, 0, 0, 0, 0, 104, 0, 63, 62, 92, 72, 0, 0, 71, 0, 95, 0, 0, 0, 0, 162, 161, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 163, 0, 159, 164, 0, 154, 0, 0, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10, 0, 68, 88, 0, 0, 0, 44, 43, 3, 2, 8, 7, 39, 0, 116, 0, 114, 0, 0, 0, 0, 0, 0, 0, 73, 67, 111, 94, 110, 93, 0, 113, 0, 0, 0, 0, 0, 96, 0, 0, 13, 14, 31, 32, 33, 16, 121, 0, 0, 0, 0, 120, 19, 18, 21, 23, 25, 27, 30, 20, 36, 37, 17, 34, 35, 22, 24, 26, 28, 29, 55, 0, 53, 64, 0, 70, 0, 0, 79, 0, 0, 9, 40, 0, 109, 0, 50, 49, 0, 47, 101, 0, 0, 0, 103, 102, 12, 168, 166, 156, 160, 0, 158, 157, 0, 155, 105, 124, 0, 0, 0, 128, 0, 0, 0, 126, 0, 0, 0, 0, 81, 0, 66, 112, 0, 78, 0, 75, 42, 41, 115, 45, 0, 0, 0, 0, 59, 100, 0, 0, 0, 0, 0, 122, 0, 0, 0, 0, 0, 0, 123, 0, 119, 11, 56, 80, 77, 87, 86, 0, 74, 48, 0, 0, 0, 0, 0, 167, 165, 125, 134, 130, 129, 0, 132, 127, 131, 76, 84, 83, 85, 0, 58, 0, 0, 0, 0, 82, 46, 0, 0, 0, 133, 57, 97, 0, 99, 0, 98 }; /* YYPGOTO[NTERM-NUM]. */ static const yytype_int16 yypgoto[] = { -146, -146, -146, 236, 179, -1, 1, -146, -146, 253, -8, -146, 53, -146, 5, -146, 7, 284, -146, 115, -146, 60, -100, -146, -146, 48, -145, 169, -146, -140 }; /* YYDEFGOTO[NTERM-NUM]. */ static const yytype_uint8 yydefgoto[] = { 0, 2, 3, 34, 121, 112, 26, 35, 36, 118, 27, 201, 202, 28, 29, 113, 250, 30, 128, 129, 162, 163, 164, 221, 227, 228, 82, 83, 84, 211 }; /* YYTABLE[YYPACT[STATE-NUM]] -- What to do in state STATE-NUM. If positive, shift that token. If negative, reduce the rule whose number is the opposite. If YYTABLE_NINF, syntax error. */ static const yytype_int16 yytable[] = { 25, 159, 132, 114, 262, 212, 213, 255, 215, 216, 41, 51, 51, 42, 43, 44, 229, 199, 295, 200, 55, 57, 296, 263, 256, 52, 123, 46, 81, 143, 86, 87, 47, 122, 144, 126, 127, 119, 119, 247, 248, 86, 87, 249, 31, 18, 18, 1, 86, 87, 86, 87, 32, 33, 86, 87, 160, 115, 116, 117, 220, 241, 161, 242, 187, 142, 86, 87, 38, 239, 86, 87, 240, 86, 87, 37, 86, 87, 267, 147, 39, 86, 87, 130, 131, 153, 154, 88, 140, 40, 155, 156, 157, 158, 269, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 280, 281, 123, 192, 229, 45, 86, 87, 188, 86, 87, 86, 87, 86, 87, 85, 198, 265, 204, 86, 87, 136, 209, 208, 270, 308, 196, 293, 309, 197, 214, 210, 245, 210, 210, 246, 210, 210, 86, 87, 86, 87, 282, 81, 283, 284, 285, 135, 287, 86, 87, 289, 137, 226, 138, 286, 141, 307, 86, 87, 139, 189, 151, 195, 4, 5, 6, 7, 8, 9, 232, 145, 244, 234, 146, 10, 237, 86, 87, 11, 205, 206, 127, 12, 13, 148, 305, 149, 14, 150, 15, 16, 17, 186, 311, 86, 87, 152, 86, 87, 193, 231, 18, 90, 91, 86, 87, 183, 184, 297, 185, 260, 298, 219, 19, 230, -118, 266, 94, 301, 20, 21, 235, 190, 22, 272, 191, 23, 236, 24, 238, 102, 103, 276, 277, 253, 251, 278, 279, 268, 252, 210, 210, 105, 106, 107, 108, 109, 110, 111, 109, 110, 111, 254, 226, -117, 143, 257, 124, 258, 259, 294, 261, 264, 273, 275, -60, 49, 290, 291, 50, -60, 292, 120, 51, 299, -60, -60, -60, -60, -60, 300, 302, 303, 304, 274, -60, -60, -60, 194, 48, -60, -60, -60, 310, -60, 306, 288, 243, -60, -60, -60, -60, -60, -60, -60, -60, 218, 18, 0, 0, -60, 0, 0, -60, -60, -60, -60, -60, -60, -60, -60, -60, -60, 0, -60, -60, -60, -60, -60, 0, -60, -60, 53, -60, 0, 4, 5, 6, 7, 8, 9, 0, 0, 0, 0, 0, 10, 0, 0, 0, 11, 0, 0, 0, 12, 13, 0, 0, 0, 14, 0, 15, 16, 17, 0, 0, 0, 0, 0, 0, 0, 0, 0, 18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 19, 0, 0, 0, 0, 0, 20, 21, 0, 0, 22, 0, 54, 23, 56, 24, 0, 4, 5, 6, 7, 8, 9, 0, 0, 0, 0, 0, 10, 0, 0, 0, 11, 0, 0, 0, 12, 13, 0, 0, 0, 14, 0, 15, 16, 17, 0, 0, 0, 0, 0, 0, 0, 0, 0, 18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 19, 0, 0, 0, 0, 0, 20, 21, 0, 0, 22, 0, 0, 23, 203, 24, 0, 4, 5, 6, 7, 8, 9, 0, 0, 0, 0, 0, 10, 0, 0, 0, 11, 0, 0, 0, 12, 13, 0, 0, 0, 14, 0, 15, 16, 17, 0, 0, 0, 0, -154, -154, 0, 0, 0, 18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 19, 0, 0, 0, 0, 0, 20, 21, 0, 0, 22, -154, -154, 23, 207, 24, 0, 4, 5, 6, 7, 8, 9, -154, -154, 107, 108, 109, 110, 111, 0, 0, 11, 0, 0, 0, 12, 13, 0, 0, 0, 14, 0, 0, 16, 17, 0, 0, 0, 0, 0, 0, 0, 0, 0, 18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 19, 0, 0, 0, 0, 0, 20, 21, 0, 58, 22, 0, 59, 23, 60, 24, 51, 90, 91, 0, 0, 0, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 0, 0, 0, 0, 102, 103, 0, 0, 0, 18, 0, 0, 0, 0, 0, 0, 105, 106, 107, 108, 109, 110, 111, 217, 0, 0, 59, 0, 60, 0, 51, 80, 0, 0, 0, -153, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 4, 5, 6, 7, 8, 9, 0, 0, 0, 18, 0, 10, 0, 0, 0, 11, 0, 0, 0, 12, 13, 0, 0, 0, 14, 0, 15, 16, 17, 0, 0, 80, 0, 0, 0, -153, 0, 0, 18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 19, 0, 0, 0, 0, 0, 20, 21, 125, 0, 22, 0, 0, 23, 0, 24, 4, 5, 6, 7, 8, 9, 0, 0, 0, 0, 0, 10, 0, 0, 0, 11, 0, 0, 0, 12, 13, 0, 0, 0, 14, 0, 15, 16, 17, 0, 0, 0, 0, 0, 0, 0, 0, 0, 18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 19, 0, 0, 0, 0, 0, 20, 21, 0, 0, 22, 0, 233, 23, 0, 24, 4, 5, 6, 7, 8, 9, 0, 0, 0, 0, 0, 10, 0, 0, 0, 11, 0, 0, 0, 12, 13, 0, 0, 0, 14, 0, 15, 16, 17, 0, 0, 0, 0, 0, 0, 0, 0, 0, 18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 19, 0, 0, 0, 0, 0, 20, 21, 0, 0, 22, 0, 271, 23, 0, 24, 4, 5, 6, 7, 8, 9, 0, 0, 0, 0, 0, 10, 0, 0, 0, 11, 0, 0, 0, 12, 13, 0, 0, 0, 14, 0, 15, 16, 17, 0, 0, 0, 0, 0, 0, 0, 0, 0, 18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 19, 0, 0, 0, 0, 0, 20, 21, 0, 0, 22, 0, 0, 23, 0, 24, 4, 5, 6, 7, 8, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 11, 0, 0, 0, 12, 13, 0, 0, 0, 14, 0, 0, 16, 17, 0, 0, 0, 0, 0, 0, 0, 0, 0, 18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 19, 0, 0, 0, 0, 0, 20, 21, 0, 222, 22, 0, 223, 23, 224, 24, 51, 0, 0, 0, 0, 0, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 89, 90, 91, 92, 93, 0, 0, 0, 0, 0, 18, 0, 0, 0, 0, 0, 94, 95, 0, 0, 0, 0, 0, 96, 97, 98, 99, 100, 101, 102, 103, 0, 225, 89, 90, 91, 92, 133, 0, 0, 104, 105, 106, 107, 108, 109, 110, 111, 0, 94, 95, 0, 0, 0, 0, 0, 96, 97, 98, 99, 100, 101, 102, 103, 0, 89, 90, 91, 92, 134, 0, 0, 0, 104, 105, 106, 107, 108, 109, 110, 111, 94, 95, 0, 0, 0, 0, 0, 96, 97, 98, 99, 100, 101, 102, 103, 0, 89, 90, 91, 92, 0, 0, 0, 0, 104, 105, 106, 107, 108, 109, 110, 111, 94, 95, 0, 0, 0, 0, 0, 96, 97, 98, 99, 100, 101, 102, 103, 0, -154, 90, 91, 0, 0, 0, 0, 0, 104, 105, 106, 107, 108, 109, 110, 111, 94, 95, 0, 0, 0, 0, 0, -154, -154, -154, -154, -154, -154, 102, 103, 0, 0, 0, 0, 0, 0, 0, 0, 0, -154, 105, 106, 107, 108, 109, 110, 111 }; static const yytype_int16 yycheck[] = { 1, 6, 20, 5, 49, 145, 146, 49, 148, 149, 11, 8, 8, 12, 13, 14, 161, 4, 25, 6, 21, 22, 20, 68, 66, 20, 34, 1, 23, 63, 48, 49, 6, 34, 68, 36, 37, 32, 33, 21, 22, 48, 49, 25, 0, 42, 42, 16, 48, 49, 48, 49, 17, 18, 48, 49, 61, 59, 60, 61, 160, 4, 67, 6, 61, 65, 48, 49, 59, 63, 48, 49, 66, 48, 49, 64, 48, 49, 45, 80, 42, 48, 49, 63, 64, 86, 87, 62, 66, 4, 89, 90, 91, 92, 66, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 253, 254, 123, 117, 262, 6, 48, 49, 116, 48, 49, 48, 49, 48, 49, 69, 130, 230, 132, 48, 49, 48, 136, 135, 66, 62, 62, 66, 65, 65, 65, 143, 62, 145, 146, 65, 148, 149, 48, 49, 48, 49, 255, 151, 257, 258, 259, 29, 261, 48, 49, 264, 1, 161, 59, 65, 65, 65, 48, 49, 66, 1, 49, 62, 4, 5, 6, 7, 8, 9, 184, 63, 62, 187, 63, 15, 190, 48, 49, 19, 133, 134, 196, 23, 24, 63, 299, 63, 28, 68, 30, 31, 32, 59, 65, 48, 49, 69, 48, 49, 14, 48, 42, 11, 12, 48, 49, 43, 44, 62, 46, 225, 62, 6, 54, 41, 41, 231, 26, 62, 60, 61, 59, 63, 64, 239, 66, 67, 66, 69, 59, 39, 40, 247, 248, 48, 64, 251, 252, 59, 64, 253, 254, 51, 52, 53, 54, 55, 56, 57, 55, 56, 57, 63, 262, 41, 63, 63, 35, 63, 63, 275, 63, 63, 59, 63, 0, 1, 59, 59, 4, 5, 59, 33, 8, 63, 10, 11, 12, 13, 14, 59, 296, 297, 298, 245, 20, 21, 22, 123, 19, 25, 26, 27, 308, 29, 302, 262, 196, 33, 34, 35, 36, 37, 38, 39, 40, 151, 42, -1, -1, 45, -1, -1, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, -1, 59, 60, 61, 62, 63, -1, 65, 66, 1, 68, -1, 4, 5, 6, 7, 8, 9, -1, -1, -1, -1, -1, 15, -1, -1, -1, 19, -1, -1, -1, 23, 24, -1, -1, -1, 28, -1, 30, 31, 32, -1, -1, -1, -1, -1, -1, -1, -1, -1, 42, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 54, -1, -1, -1, -1, -1, 60, 61, -1, -1, 64, -1, 66, 67, 1, 69, -1, 4, 5, 6, 7, 8, 9, -1, -1, -1, -1, -1, 15, -1, -1, -1, 19, -1, -1, -1, 23, 24, -1, -1, -1, 28, -1, 30, 31, 32, -1, -1, -1, -1, -1, -1, -1, -1, -1, 42, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 54, -1, -1, -1, -1, -1, 60, 61, -1, -1, 64, -1, -1, 67, 1, 69, -1, 4, 5, 6, 7, 8, 9, -1, -1, -1, -1, -1, 15, -1, -1, -1, 19, -1, -1, -1, 23, 24, -1, -1, -1, 28, -1, 30, 31, 32, -1, -1, -1, -1, 11, 12, -1, -1, -1, 42, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 54, -1, -1, -1, -1, -1, 60, 61, -1, -1, 64, 39, 40, 67, 1, 69, -1, 4, 5, 6, 7, 8, 9, 51, 52, 53, 54, 55, 56, 57, -1, -1, 19, -1, -1, -1, 23, 24, -1, -1, -1, 28, -1, -1, 31, 32, -1, -1, -1, -1, -1, -1, -1, -1, -1, 42, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 54, -1, -1, -1, -1, -1, 60, 61, -1, 1, 64, -1, 4, 67, 6, 69, 8, 11, 12, -1, -1, -1, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, -1, -1, -1, -1, 39, 40, -1, -1, -1, 42, -1, -1, -1, -1, -1, -1, 51, 52, 53, 54, 55, 56, 57, 1, -1, -1, 4, -1, 6, -1, 8, 64, -1, -1, -1, 68, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 4, 5, 6, 7, 8, 9, -1, -1, -1, 42, -1, 15, -1, -1, -1, 19, -1, -1, -1, 23, 24, -1, -1, -1, 28, -1, 30, 31, 32, -1, -1, 64, -1, -1, -1, 68, -1, -1, 42, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 54, -1, -1, -1, -1, -1, 60, 61, 62, -1, 64, -1, -1, 67, -1, 69, 4, 5, 6, 7, 8, 9, -1, -1, -1, -1, -1, 15, -1, -1, -1, 19, -1, -1, -1, 23, 24, -1, -1, -1, 28, -1, 30, 31, 32, -1, -1, -1, -1, -1, -1, -1, -1, -1, 42, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 54, -1, -1, -1, -1, -1, 60, 61, -1, -1, 64, -1, 66, 67, -1, 69, 4, 5, 6, 7, 8, 9, -1, -1, -1, -1, -1, 15, -1, -1, -1, 19, -1, -1, -1, 23, 24, -1, -1, -1, 28, -1, 30, 31, 32, -1, -1, -1, -1, -1, -1, -1, -1, -1, 42, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 54, -1, -1, -1, -1, -1, 60, 61, -1, -1, 64, -1, 66, 67, -1, 69, 4, 5, 6, 7, 8, 9, -1, -1, -1, -1, -1, 15, -1, -1, -1, 19, -1, -1, -1, 23, 24, -1, -1, -1, 28, -1, 30, 31, 32, -1, -1, -1, -1, -1, -1, -1, -1, -1, 42, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 54, -1, -1, -1, -1, -1, 60, 61, -1, -1, 64, -1, -1, 67, -1, 69, 4, 5, 6, 7, 8, 9, -1, -1, -1, -1, -1, -1, -1, -1, -1, 19, -1, -1, -1, 23, 24, -1, -1, -1, 28, -1, -1, 31, 32, -1, -1, -1, -1, -1, -1, -1, -1, -1, 42, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 54, -1, -1, -1, -1, -1, 60, 61, -1, 1, 64, -1, 4, 67, 6, 69, 8, -1, -1, -1, -1, -1, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 10, 11, 12, 13, 14, -1, -1, -1, -1, -1, 42, -1, -1, -1, -1, -1, 26, 27, -1, -1, -1, -1, -1, 33, 34, 35, 36, 37, 38, 39, 40, -1, 64, 10, 11, 12, 13, 14, -1, -1, 50, 51, 52, 53, 54, 55, 56, 57, -1, 26, 27, -1, -1, -1, -1, -1, 33, 34, 35, 36, 37, 38, 39, 40, -1, 10, 11, 12, 13, 14, -1, -1, -1, 50, 51, 52, 53, 54, 55, 56, 57, 26, 27, -1, -1, -1, -1, -1, 33, 34, 35, 36, 37, 38, 39, 40, -1, 10, 11, 12, 13, -1, -1, -1, -1, 50, 51, 52, 53, 54, 55, 56, 57, 26, 27, -1, -1, -1, -1, -1, 33, 34, 35, 36, 37, 38, 39, 40, -1, 10, 11, 12, -1, -1, -1, -1, -1, 50, 51, 52, 53, 54, 55, 56, 57, 26, 27, -1, -1, -1, -1, -1, 33, 34, 35, 36, 37, 38, 39, 40, -1, -1, -1, -1, -1, -1, -1, -1, -1, 50, 51, 52, 53, 54, 55, 56, 57 }; /* YYSTOS[STATE-NUM] -- The symbol kind of the accessing symbol of state STATE-NUM. */ static const yytype_int8 yystos[] = { 0, 16, 71, 72, 4, 5, 6, 7, 8, 9, 15, 19, 23, 24, 28, 30, 31, 32, 42, 54, 60, 61, 64, 67, 69, 75, 76, 80, 83, 84, 87, 0, 17, 18, 73, 77, 78, 64, 59, 42, 4, 75, 76, 76, 76, 6, 1, 6, 87, 1, 4, 8, 84, 1, 66, 75, 1, 75, 1, 4, 6, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 64, 84, 96, 97, 98, 69, 48, 49, 62, 10, 11, 12, 13, 14, 26, 27, 33, 34, 35, 36, 37, 38, 39, 40, 50, 51, 52, 53, 54, 55, 56, 57, 75, 85, 5, 59, 60, 61, 79, 84, 79, 74, 75, 80, 73, 62, 75, 75, 88, 89, 63, 64, 20, 14, 14, 29, 48, 1, 59, 66, 66, 65, 65, 63, 68, 63, 63, 75, 63, 63, 68, 49, 69, 75, 75, 76, 76, 76, 76, 6, 61, 67, 90, 91, 92, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 43, 44, 46, 59, 61, 84, 1, 63, 66, 75, 14, 74, 62, 62, 65, 75, 4, 6, 81, 82, 1, 75, 91, 91, 1, 76, 75, 76, 99, 99, 99, 65, 99, 99, 1, 97, 6, 92, 93, 1, 4, 6, 64, 84, 94, 95, 96, 41, 48, 75, 66, 75, 59, 66, 75, 59, 63, 66, 4, 6, 89, 62, 62, 65, 21, 22, 25, 86, 64, 64, 48, 63, 49, 66, 63, 63, 63, 75, 63, 49, 68, 63, 92, 75, 45, 59, 66, 66, 66, 75, 59, 82, 63, 75, 75, 75, 75, 99, 99, 92, 92, 92, 92, 65, 92, 95, 92, 59, 59, 59, 66, 75, 25, 20, 62, 62, 63, 59, 62, 75, 75, 75, 92, 86, 65, 62, 65, 75, 65 }; /* YYR1[RULE-NUM] -- Symbol kind of the left-hand side of rule RULE-NUM. */ static const yytype_int8 yyr1[] = { 0, 70, 71, 71, 72, 72, 73, 73, 74, 74, 75, 75, 75, 75, 75, 75, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 77, 77, 78, 78, 78, 79, 80, 80, 81, 81, 82, 82, 83, 83, 84, 85, 85, 85, 86, 86, 86, 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, 88, 88, 89, 90, 90, 91, 91, 92, 92, 92, 93, 93, 94, 94, 95, 95, 95, 95, 95, 95, 95, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 97, 97, 97, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 99, 99 }; /* YYR2[RULE-NUM] -- Number of symbols on the right-hand side of rule RULE-NUM. */ static const yytype_int8 yyr2[] = { 0, 2, 3, 3, 0, 3, 0, 2, 0, 2, 2, 5, 4, 3, 3, 1, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 1, 2, 3, 4, 4, 2, 1, 5, 8, 1, 3, 1, 1, 2, 1, 3, 0, 2, 4, 5, 3, 1, 1, 1, 2, 2, 3, 2, 4, 3, 2, 1, 3, 2, 2, 3, 5, 4, 6, 5, 4, 3, 5, 4, 7, 6, 6, 6, 5, 5, 2, 1, 1, 1, 2, 3, 3, 2, 3, 9, 11, 9, 5, 4, 4, 4, 2, 4, 1, 1, 1, 4, 3, 3, 4, 3, 1, 3, 1, 3, 1, 3, 1, 1, 3, 3, 1, 3, 1, 3, 1, 3, 3, 3, 3, 5, 3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 3, 3, 3, 3, 1, 3, 1, 1, 1, 1, 5, 3, 3, 1 }; enum { YYENOMEM = -2 }; #define yyerrok (yyerrstatus = 0) #define yyclearin (yychar = YYEMPTY) #define YYACCEPT goto yyacceptlab #define YYABORT goto yyabortlab #define YYERROR goto yyerrorlab #define YYNOMEM goto yyexhaustedlab #define YYRECOVERING() (!!yyerrstatus) #define YYBACKUP(Token, Value) \ do \ if (yychar == YYEMPTY) \ { \ yychar = (Token); \ yylval = (Value); \ YYPOPSTACK (yylen); \ yystate = *yyssp; \ goto yybackup; \ } \ else \ { \ yyerror (&yylloc, answer, errors, locations, lexer_param_ptr, YY_("syntax error: cannot back up")); \ YYERROR; \ } \ while (0) /* Backward compatibility with an undocumented macro. Use YYerror or YYUNDEF. */ #define YYERRCODE YYUNDEF /* YYLLOC_DEFAULT -- Set CURRENT to span from RHS[1] to RHS[N]. If N is 0, then set CURRENT to the empty location which ends the previous symbol: RHS[0] (always defined). */ #ifndef YYLLOC_DEFAULT # define YYLLOC_DEFAULT(Current, Rhs, N) \ do \ if (N) \ { \ (Current).first_line = YYRHSLOC (Rhs, 1).first_line; \ (Current).first_column = YYRHSLOC (Rhs, 1).first_column; \ (Current).last_line = YYRHSLOC (Rhs, N).last_line; \ (Current).last_column = YYRHSLOC (Rhs, N).last_column; \ } \ else \ { \ (Current).first_line = (Current).last_line = \ YYRHSLOC (Rhs, 0).last_line; \ (Current).first_column = (Current).last_column = \ YYRHSLOC (Rhs, 0).last_column; \ } \ while (0) #endif #define YYRHSLOC(Rhs, K) ((Rhs)[K]) /* Enable debugging if requested. */ #if YYDEBUG # ifndef YYFPRINTF # include /* INFRINGES ON USER NAME SPACE */ # define YYFPRINTF fprintf # endif # define YYDPRINTF(Args) \ do { \ if (yydebug) \ YYFPRINTF Args; \ } while (0) /* YYLOCATION_PRINT -- Print the location on the stream. This macro was not mandated originally: define only if we know we won't break user code: when these are the locations we know. */ # ifndef YYLOCATION_PRINT # if defined YY_LOCATION_PRINT /* Temporary convenience wrapper in case some people defined the undocumented and private YY_LOCATION_PRINT macros. */ # define YYLOCATION_PRINT(File, Loc) YY_LOCATION_PRINT(File, *(Loc)) # elif defined YYLTYPE_IS_TRIVIAL && YYLTYPE_IS_TRIVIAL /* Print *YYLOCP on YYO. Private, do not rely on its existence. */ YY_ATTRIBUTE_UNUSED static int yy_location_print_ (FILE *yyo, YYLTYPE const * const yylocp) { int res = 0; int end_col = 0 != yylocp->last_column ? yylocp->last_column - 1 : 0; if (0 <= yylocp->first_line) { res += YYFPRINTF (yyo, "%d", yylocp->first_line); if (0 <= yylocp->first_column) res += YYFPRINTF (yyo, ".%d", yylocp->first_column); } if (0 <= yylocp->last_line) { if (yylocp->first_line < yylocp->last_line) { res += YYFPRINTF (yyo, "-%d", yylocp->last_line); if (0 <= end_col) res += YYFPRINTF (yyo, ".%d", end_col); } else if (0 <= end_col && yylocp->first_column < end_col) res += YYFPRINTF (yyo, "-%d", end_col); } return res; } # define YYLOCATION_PRINT yy_location_print_ /* Temporary convenience wrapper in case some people defined the undocumented and private YY_LOCATION_PRINT macros. */ # define YY_LOCATION_PRINT(File, Loc) YYLOCATION_PRINT(File, &(Loc)) # else # define YYLOCATION_PRINT(File, Loc) ((void) 0) /* Temporary convenience wrapper in case some people defined the undocumented and private YY_LOCATION_PRINT macros. */ # define YY_LOCATION_PRINT YYLOCATION_PRINT # endif # endif /* !defined YYLOCATION_PRINT */ # define YY_SYMBOL_PRINT(Title, Kind, Value, Location) \ do { \ if (yydebug) \ { \ YYFPRINTF (stderr, "%s ", Title); \ yy_symbol_print (stderr, \ Kind, Value, Location, answer, errors, locations, lexer_param_ptr); \ YYFPRINTF (stderr, "\n"); \ } \ } while (0) /*-----------------------------------. | Print this symbol's value on YYO. | `-----------------------------------*/ static void yy_symbol_value_print (FILE *yyo, yysymbol_kind_t yykind, YYSTYPE const * const yyvaluep, YYLTYPE const * const yylocationp, block* answer, int* errors, struct locfile* locations, struct lexer_param* lexer_param_ptr) { FILE *yyoutput = yyo; YY_USE (yyoutput); YY_USE (yylocationp); YY_USE (answer); YY_USE (errors); YY_USE (locations); YY_USE (lexer_param_ptr); if (!yyvaluep) return; YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN YY_USE (yykind); YY_IGNORE_MAYBE_UNINITIALIZED_END } /*---------------------------. | Print this symbol on YYO. | `---------------------------*/ static void yy_symbol_print (FILE *yyo, yysymbol_kind_t yykind, YYSTYPE const * const yyvaluep, YYLTYPE const * const yylocationp, block* answer, int* errors, struct locfile* locations, struct lexer_param* lexer_param_ptr) { YYFPRINTF (yyo, "%s %s (", yykind < YYNTOKENS ? "token" : "nterm", yysymbol_name (yykind)); YYLOCATION_PRINT (yyo, yylocationp); YYFPRINTF (yyo, ": "); yy_symbol_value_print (yyo, yykind, yyvaluep, yylocationp, answer, errors, locations, lexer_param_ptr); YYFPRINTF (yyo, ")"); } /*------------------------------------------------------------------. | yy_stack_print -- Print the state stack from its BOTTOM up to its | | TOP (included). | `------------------------------------------------------------------*/ static void yy_stack_print (yy_state_t *yybottom, yy_state_t *yytop) { YYFPRINTF (stderr, "Stack now"); for (; yybottom <= yytop; yybottom++) { int yybot = *yybottom; YYFPRINTF (stderr, " %d", yybot); } YYFPRINTF (stderr, "\n"); } # define YY_STACK_PRINT(Bottom, Top) \ do { \ if (yydebug) \ yy_stack_print ((Bottom), (Top)); \ } while (0) /*------------------------------------------------. | Report that the YYRULE is going to be reduced. | `------------------------------------------------*/ static void yy_reduce_print (yy_state_t *yyssp, YYSTYPE *yyvsp, YYLTYPE *yylsp, int yyrule, block* answer, int* errors, struct locfile* locations, struct lexer_param* lexer_param_ptr) { int yylno = yyrline[yyrule]; int yynrhs = yyr2[yyrule]; int yyi; YYFPRINTF (stderr, "Reducing stack by rule %d (line %d):\n", yyrule - 1, yylno); /* The symbols being reduced. */ for (yyi = 0; yyi < yynrhs; yyi++) { YYFPRINTF (stderr, " $%d = ", yyi + 1); yy_symbol_print (stderr, YY_ACCESSING_SYMBOL (+yyssp[yyi + 1 - yynrhs]), &yyvsp[(yyi + 1) - (yynrhs)], &(yylsp[(yyi + 1) - (yynrhs)]), answer, errors, locations, lexer_param_ptr); YYFPRINTF (stderr, "\n"); } } # define YY_REDUCE_PRINT(Rule) \ do { \ if (yydebug) \ yy_reduce_print (yyssp, yyvsp, yylsp, Rule, answer, errors, locations, lexer_param_ptr); \ } while (0) /* Nonzero means print parse trace. It is left uninitialized so that multiple parsers can coexist. */ int yydebug; #else /* !YYDEBUG */ # define YYDPRINTF(Args) ((void) 0) # define YY_SYMBOL_PRINT(Title, Kind, Value, Location) # define YY_STACK_PRINT(Bottom, Top) # define YY_REDUCE_PRINT(Rule) #endif /* !YYDEBUG */ /* YYINITDEPTH -- initial size of the parser's stacks. */ #ifndef YYINITDEPTH # define YYINITDEPTH 200 #endif /* YYMAXDEPTH -- maximum size the stacks can grow to (effective only if the built-in stack extension method is used). Do not make this value too large; the results are undefined if YYSTACK_ALLOC_MAXIMUM < YYSTACK_BYTES (YYMAXDEPTH) evaluated with infinite-precision integer arithmetic. */ #ifndef YYMAXDEPTH # define YYMAXDEPTH 10000 #endif /* Context of a parse error. */ typedef struct { yy_state_t *yyssp; yysymbol_kind_t yytoken; YYLTYPE *yylloc; } yypcontext_t; /* Put in YYARG at most YYARGN of the expected tokens given the current YYCTX, and return the number of tokens stored in YYARG. If YYARG is null, return the number of expected tokens (guaranteed to be less than YYNTOKENS). Return YYENOMEM on memory exhaustion. Return 0 if there are more than YYARGN expected tokens, yet fill YYARG up to YYARGN. */ static int yypcontext_expected_tokens (const yypcontext_t *yyctx, yysymbol_kind_t yyarg[], int yyargn) { /* Actual size of YYARG. */ int yycount = 0; int yyn = yypact[+*yyctx->yyssp]; if (!yypact_value_is_default (yyn)) { /* Start YYX at -YYN if negative to avoid negative indexes in YYCHECK. In other words, skip the first -YYN actions for this state because they are default actions. */ int yyxbegin = yyn < 0 ? -yyn : 0; /* Stay within bounds of both yycheck and yytname. */ int yychecklim = YYLAST - yyn + 1; int yyxend = yychecklim < YYNTOKENS ? yychecklim : YYNTOKENS; int yyx; for (yyx = yyxbegin; yyx < yyxend; ++yyx) if (yycheck[yyx + yyn] == yyx && yyx != YYSYMBOL_YYerror && !yytable_value_is_error (yytable[yyx + yyn])) { if (!yyarg) ++yycount; else if (yycount == yyargn) return 0; else yyarg[yycount++] = YY_CAST (yysymbol_kind_t, yyx); } } if (yyarg && yycount == 0 && 0 < yyargn) yyarg[0] = YYSYMBOL_YYEMPTY; return yycount; } #ifndef yystrlen # if defined __GLIBC__ && defined _STRING_H # define yystrlen(S) (YY_CAST (YYPTRDIFF_T, strlen (S))) # else /* Return the length of YYSTR. */ static YYPTRDIFF_T yystrlen (const char *yystr) { YYPTRDIFF_T yylen; for (yylen = 0; yystr[yylen]; yylen++) continue; return yylen; } # endif #endif #ifndef yystpcpy # if defined __GLIBC__ && defined _STRING_H && defined _GNU_SOURCE # define yystpcpy stpcpy # else /* Copy YYSRC to YYDEST, returning the address of the terminating '\0' in YYDEST. */ static char * yystpcpy (char *yydest, const char *yysrc) { char *yyd = yydest; const char *yys = yysrc; while ((*yyd++ = *yys++) != '\0') continue; return yyd - 1; } # endif #endif #ifndef yytnamerr /* Copy to YYRES the contents of YYSTR after stripping away unnecessary quotes and backslashes, so that it's suitable for yyerror. The heuristic is that double-quoting is unnecessary unless the string contains an apostrophe, a comma, or backslash (other than backslash-backslash). YYSTR is taken from yytname. If YYRES is null, do not copy; instead, return the length of what the result would have been. */ static YYPTRDIFF_T yytnamerr (char *yyres, const char *yystr) { if (*yystr == '"') { YYPTRDIFF_T yyn = 0; char const *yyp = yystr; for (;;) switch (*++yyp) { case '\'': case ',': goto do_not_strip_quotes; case '\\': if (*++yyp != '\\') goto do_not_strip_quotes; else goto append; append: default: if (yyres) yyres[yyn] = *yyp; yyn++; break; case '"': if (yyres) yyres[yyn] = '\0'; return yyn; } do_not_strip_quotes: ; } if (yyres) return yystpcpy (yyres, yystr) - yyres; else return yystrlen (yystr); } #endif static int yy_syntax_error_arguments (const yypcontext_t *yyctx, yysymbol_kind_t yyarg[], int yyargn) { /* Actual size of YYARG. */ int yycount = 0; /* There are many possibilities here to consider: - If this state is a consistent state with a default action, then the only way this function was invoked is if the default action is an error action. In that case, don't check for expected tokens because there are none. - The only way there can be no lookahead present (in yychar) is if this state is a consistent state with a default action. Thus, detecting the absence of a lookahead is sufficient to determine that there is no unexpected or expected token to report. In that case, just report a simple "syntax error". - Don't assume there isn't a lookahead just because this state is a consistent state with a default action. There might have been a previous inconsistent state, consistent state with a non-default action, or user semantic action that manipulated yychar. - Of course, the expected token list depends on states to have correct lookahead information, and it depends on the parser not to perform extra reductions after fetching a lookahead from the scanner and before detecting a syntax error. Thus, state merging (from LALR or IELR) and default reductions corrupt the expected token list. However, the list is correct for canonical LR with one exception: it will still contain any token that will not be accepted due to an error action in a later state. */ if (yyctx->yytoken != YYSYMBOL_YYEMPTY) { int yyn; if (yyarg) yyarg[yycount] = yyctx->yytoken; ++yycount; yyn = yypcontext_expected_tokens (yyctx, yyarg ? yyarg + 1 : yyarg, yyargn - 1); if (yyn == YYENOMEM) return YYENOMEM; else yycount += yyn; } return yycount; } /* Copy into *YYMSG, which is of size *YYMSG_ALLOC, an error message about the unexpected token YYTOKEN for the state stack whose top is YYSSP. Return 0 if *YYMSG was successfully written. Return -1 if *YYMSG is not large enough to hold the message. In that case, also set *YYMSG_ALLOC to the required number of bytes. Return YYENOMEM if the required number of bytes is too large to store. */ static int yysyntax_error (YYPTRDIFF_T *yymsg_alloc, char **yymsg, const yypcontext_t *yyctx) { enum { YYARGS_MAX = 5 }; /* Internationalized format string. */ const char *yyformat = YY_NULLPTR; /* Arguments of yyformat: reported tokens (one for the "unexpected", one per "expected"). */ yysymbol_kind_t yyarg[YYARGS_MAX]; /* Cumulated lengths of YYARG. */ YYPTRDIFF_T yysize = 0; /* Actual size of YYARG. */ int yycount = yy_syntax_error_arguments (yyctx, yyarg, YYARGS_MAX); if (yycount == YYENOMEM) return YYENOMEM; switch (yycount) { #define YYCASE_(N, S) \ case N: \ yyformat = S; \ break default: /* Avoid compiler warnings. */ YYCASE_(0, YY_("syntax error")); YYCASE_(1, YY_("syntax error, unexpected %s")); YYCASE_(2, YY_("syntax error, unexpected %s, expecting %s")); YYCASE_(3, YY_("syntax error, unexpected %s, expecting %s or %s")); YYCASE_(4, YY_("syntax error, unexpected %s, expecting %s or %s or %s")); YYCASE_(5, YY_("syntax error, unexpected %s, expecting %s or %s or %s or %s")); #undef YYCASE_ } /* Compute error message size. Don't count the "%s"s, but reserve room for the terminator. */ yysize = yystrlen (yyformat) - 2 * yycount + 1; { int yyi; for (yyi = 0; yyi < yycount; ++yyi) { YYPTRDIFF_T yysize1 = yysize + yytnamerr (YY_NULLPTR, yytname[yyarg[yyi]]); if (yysize <= yysize1 && yysize1 <= YYSTACK_ALLOC_MAXIMUM) yysize = yysize1; else return YYENOMEM; } } if (*yymsg_alloc < yysize) { *yymsg_alloc = 2 * yysize; if (! (yysize <= *yymsg_alloc && *yymsg_alloc <= YYSTACK_ALLOC_MAXIMUM)) *yymsg_alloc = YYSTACK_ALLOC_MAXIMUM; return -1; } /* Avoid sprintf, as that infringes on the user's name space. Don't have undefined behavior even if the translation produced a string with the wrong number of "%s"s. */ { char *yyp = *yymsg; int yyi = 0; while ((*yyp = *yyformat) != '\0') if (*yyp == '%' && yyformat[1] == 's' && yyi < yycount) { yyp += yytnamerr (yyp, yytname[yyarg[yyi++]]); yyformat += 2; } else { ++yyp; ++yyformat; } } return 0; } /*-----------------------------------------------. | Release the memory associated to this symbol. | `-----------------------------------------------*/ static void yydestruct (const char *yymsg, yysymbol_kind_t yykind, YYSTYPE *yyvaluep, YYLTYPE *yylocationp, block* answer, int* errors, struct locfile* locations, struct lexer_param* lexer_param_ptr) { YY_USE (yyvaluep); YY_USE (yylocationp); YY_USE (answer); YY_USE (errors); YY_USE (locations); YY_USE (lexer_param_ptr); if (!yymsg) yymsg = "Deleting"; YY_SYMBOL_PRINT (yymsg, yykind, yyvaluep, yylocationp); YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN switch (yykind) { case YYSYMBOL_IDENT: /* IDENT */ #line 37 "src/parser.y" { jv_free(((*yyvaluep).literal)); } #line 2004 "src/parser.c" break; case YYSYMBOL_FIELD: /* FIELD */ #line 37 "src/parser.y" { jv_free(((*yyvaluep).literal)); } #line 2010 "src/parser.c" break; case YYSYMBOL_BINDING: /* BINDING */ #line 37 "src/parser.y" { jv_free(((*yyvaluep).literal)); } #line 2016 "src/parser.c" break; case YYSYMBOL_LITERAL: /* LITERAL */ #line 37 "src/parser.y" { jv_free(((*yyvaluep).literal)); } #line 2022 "src/parser.c" break; case YYSYMBOL_FORMAT: /* FORMAT */ #line 37 "src/parser.y" { jv_free(((*yyvaluep).literal)); } #line 2028 "src/parser.c" break; case YYSYMBOL_QQSTRING_TEXT: /* QQSTRING_TEXT */ #line 37 "src/parser.y" { jv_free(((*yyvaluep).literal)); } #line 2034 "src/parser.c" break; case YYSYMBOL_Module: /* Module */ #line 38 "src/parser.y" { block_free(((*yyvaluep).blk)); } #line 2040 "src/parser.c" break; case YYSYMBOL_Imports: /* Imports */ #line 38 "src/parser.y" { block_free(((*yyvaluep).blk)); } #line 2046 "src/parser.c" break; case YYSYMBOL_FuncDefs: /* FuncDefs */ #line 38 "src/parser.y" { block_free(((*yyvaluep).blk)); } #line 2052 "src/parser.c" break; case YYSYMBOL_Query: /* Query */ #line 38 "src/parser.y" { block_free(((*yyvaluep).blk)); } #line 2058 "src/parser.c" break; case YYSYMBOL_Expr: /* Expr */ #line 38 "src/parser.y" { block_free(((*yyvaluep).blk)); } #line 2064 "src/parser.c" break; case YYSYMBOL_Import: /* Import */ #line 38 "src/parser.y" { block_free(((*yyvaluep).blk)); } #line 2070 "src/parser.c" break; case YYSYMBOL_ImportWhat: /* ImportWhat */ #line 38 "src/parser.y" { block_free(((*yyvaluep).blk)); } #line 2076 "src/parser.c" break; case YYSYMBOL_ImportFrom: /* ImportFrom */ #line 38 "src/parser.y" { block_free(((*yyvaluep).blk)); } #line 2082 "src/parser.c" break; case YYSYMBOL_FuncDef: /* FuncDef */ #line 38 "src/parser.y" { block_free(((*yyvaluep).blk)); } #line 2088 "src/parser.c" break; case YYSYMBOL_Params: /* Params */ #line 38 "src/parser.y" { block_free(((*yyvaluep).blk)); } #line 2094 "src/parser.c" break; case YYSYMBOL_Param: /* Param */ #line 38 "src/parser.y" { block_free(((*yyvaluep).blk)); } #line 2100 "src/parser.c" break; case YYSYMBOL_StringStart: /* StringStart */ #line 37 "src/parser.y" { jv_free(((*yyvaluep).literal)); } #line 2106 "src/parser.c" break; case YYSYMBOL_String: /* String */ #line 38 "src/parser.y" { block_free(((*yyvaluep).blk)); } #line 2112 "src/parser.c" break; case YYSYMBOL_QQString: /* QQString */ #line 38 "src/parser.y" { block_free(((*yyvaluep).blk)); } #line 2118 "src/parser.c" break; case YYSYMBOL_ElseBody: /* ElseBody */ #line 38 "src/parser.y" { block_free(((*yyvaluep).blk)); } #line 2124 "src/parser.c" break; case YYSYMBOL_Term: /* Term */ #line 38 "src/parser.y" { block_free(((*yyvaluep).blk)); } #line 2130 "src/parser.c" break; case YYSYMBOL_Args: /* Args */ #line 38 "src/parser.y" { block_free(((*yyvaluep).blk)); } #line 2136 "src/parser.c" break; case YYSYMBOL_Arg: /* Arg */ #line 38 "src/parser.y" { block_free(((*yyvaluep).blk)); } #line 2142 "src/parser.c" break; case YYSYMBOL_RepPatterns: /* RepPatterns */ #line 38 "src/parser.y" { block_free(((*yyvaluep).blk)); } #line 2148 "src/parser.c" break; case YYSYMBOL_Patterns: /* Patterns */ #line 38 "src/parser.y" { block_free(((*yyvaluep).blk)); } #line 2154 "src/parser.c" break; case YYSYMBOL_Pattern: /* Pattern */ #line 38 "src/parser.y" { block_free(((*yyvaluep).blk)); } #line 2160 "src/parser.c" break; case YYSYMBOL_ArrayPats: /* ArrayPats */ #line 38 "src/parser.y" { block_free(((*yyvaluep).blk)); } #line 2166 "src/parser.c" break; case YYSYMBOL_ObjPats: /* ObjPats */ #line 38 "src/parser.y" { block_free(((*yyvaluep).blk)); } #line 2172 "src/parser.c" break; case YYSYMBOL_ObjPat: /* ObjPat */ #line 38 "src/parser.y" { block_free(((*yyvaluep).blk)); } #line 2178 "src/parser.c" break; case YYSYMBOL_Keyword: /* Keyword */ #line 37 "src/parser.y" { jv_free(((*yyvaluep).literal)); } #line 2184 "src/parser.c" break; case YYSYMBOL_DictPairs: /* DictPairs */ #line 38 "src/parser.y" { block_free(((*yyvaluep).blk)); } #line 2190 "src/parser.c" break; case YYSYMBOL_DictPair: /* DictPair */ #line 38 "src/parser.y" { block_free(((*yyvaluep).blk)); } #line 2196 "src/parser.c" break; case YYSYMBOL_DictExpr: /* DictExpr */ #line 38 "src/parser.y" { block_free(((*yyvaluep).blk)); } #line 2202 "src/parser.c" break; default: break; } YY_IGNORE_MAYBE_UNINITIALIZED_END } /*----------. | yyparse. | `----------*/ int yyparse (block* answer, int* errors, struct locfile* locations, struct lexer_param* lexer_param_ptr) { /* Lookahead token kind. */ int yychar; /* The semantic value of the lookahead symbol. */ /* Default value used for initialization, for pacifying older GCCs or non-GCC compilers. */ YY_INITIAL_VALUE (static YYSTYPE yyval_default;) YYSTYPE yylval YY_INITIAL_VALUE (= yyval_default); /* Location data for the lookahead symbol. */ static YYLTYPE yyloc_default # if defined YYLTYPE_IS_TRIVIAL && YYLTYPE_IS_TRIVIAL = { 1, 1, 1, 1 } # endif ; YYLTYPE yylloc = yyloc_default; /* Number of syntax errors so far. */ int yynerrs = 0; yy_state_fast_t yystate = 0; /* Number of tokens to shift before error messages enabled. */ int yyerrstatus = 0; /* Refer to the stacks through separate pointers, to allow yyoverflow to reallocate them elsewhere. */ /* Their size. */ YYPTRDIFF_T yystacksize = YYINITDEPTH; /* The state stack: array, bottom, top. */ yy_state_t yyssa[YYINITDEPTH]; yy_state_t *yyss = yyssa; yy_state_t *yyssp = yyss; /* The semantic value stack: array, bottom, top. */ YYSTYPE yyvsa[YYINITDEPTH]; YYSTYPE *yyvs = yyvsa; YYSTYPE *yyvsp = yyvs; /* The location stack: array, bottom, top. */ YYLTYPE yylsa[YYINITDEPTH]; YYLTYPE *yyls = yylsa; YYLTYPE *yylsp = yyls; int yyn; /* The return value of yyparse. */ int yyresult; /* Lookahead symbol kind. */ yysymbol_kind_t yytoken = YYSYMBOL_YYEMPTY; /* The variables used to return semantic value and location from the action routines. */ YYSTYPE yyval; YYLTYPE yyloc; /* The locations where the error started and ended. */ YYLTYPE yyerror_range[3]; /* Buffer for error messages, and its allocated size. */ char yymsgbuf[128]; char *yymsg = yymsgbuf; YYPTRDIFF_T yymsg_alloc = sizeof yymsgbuf; #define YYPOPSTACK(N) (yyvsp -= (N), yyssp -= (N), yylsp -= (N)) /* The number of symbols on the RHS of the reduced rule. Keep to zero when no symbol should be popped. */ int yylen = 0; YYDPRINTF ((stderr, "Starting parse\n")); yychar = YYEMPTY; /* Cause a token to be read. */ yylsp[0] = yylloc; goto yysetstate; /*------------------------------------------------------------. | yynewstate -- push a new state, which is found in yystate. | `------------------------------------------------------------*/ yynewstate: /* In all cases, when you get here, the value and location stacks have just been pushed. So pushing a state here evens the stacks. */ yyssp++; /*--------------------------------------------------------------------. | yysetstate -- set current state (the top of the stack) to yystate. | `--------------------------------------------------------------------*/ yysetstate: YYDPRINTF ((stderr, "Entering state %d\n", yystate)); YY_ASSERT (0 <= yystate && yystate < YYNSTATES); YY_IGNORE_USELESS_CAST_BEGIN *yyssp = YY_CAST (yy_state_t, yystate); YY_IGNORE_USELESS_CAST_END YY_STACK_PRINT (yyss, yyssp); if (yyss + yystacksize - 1 <= yyssp) #if !defined yyoverflow && !defined YYSTACK_RELOCATE YYNOMEM; #else { /* Get the current used size of the three stacks, in elements. */ YYPTRDIFF_T yysize = yyssp - yyss + 1; # if defined yyoverflow { /* Give user a chance to reallocate the stack. Use copies of these so that the &'s don't force the real ones into memory. */ yy_state_t *yyss1 = yyss; YYSTYPE *yyvs1 = yyvs; YYLTYPE *yyls1 = yyls; /* Each stack pointer address is followed by the size of the data in use in that stack, in bytes. This used to be a conditional around just the two extra args, but that might be undefined if yyoverflow is a macro. */ yyoverflow (YY_("memory exhausted"), &yyss1, yysize * YYSIZEOF (*yyssp), &yyvs1, yysize * YYSIZEOF (*yyvsp), &yyls1, yysize * YYSIZEOF (*yylsp), &yystacksize); yyss = yyss1; yyvs = yyvs1; yyls = yyls1; } # else /* defined YYSTACK_RELOCATE */ /* Extend the stack our own way. */ if (YYMAXDEPTH <= yystacksize) YYNOMEM; yystacksize *= 2; if (YYMAXDEPTH < yystacksize) yystacksize = YYMAXDEPTH; { yy_state_t *yyss1 = yyss; union yyalloc *yyptr = YY_CAST (union yyalloc *, YYSTACK_ALLOC (YY_CAST (YYSIZE_T, YYSTACK_BYTES (yystacksize)))); if (! yyptr) YYNOMEM; YYSTACK_RELOCATE (yyss_alloc, yyss); YYSTACK_RELOCATE (yyvs_alloc, yyvs); YYSTACK_RELOCATE (yyls_alloc, yyls); # undef YYSTACK_RELOCATE if (yyss1 != yyssa) YYSTACK_FREE (yyss1); } # endif yyssp = yyss + yysize - 1; yyvsp = yyvs + yysize - 1; yylsp = yyls + yysize - 1; YY_IGNORE_USELESS_CAST_BEGIN YYDPRINTF ((stderr, "Stack size increased to %ld\n", YY_CAST (long, yystacksize))); YY_IGNORE_USELESS_CAST_END if (yyss + yystacksize - 1 <= yyssp) YYABORT; } #endif /* !defined yyoverflow && !defined YYSTACK_RELOCATE */ if (yystate == YYFINAL) YYACCEPT; goto yybackup; /*-----------. | yybackup. | `-----------*/ yybackup: /* Do appropriate processing given the current state. Read a lookahead token if we need one and don't already have one. */ /* First try to decide what to do without reference to lookahead token. */ yyn = yypact[yystate]; if (yypact_value_is_default (yyn)) goto yydefault; /* Not known => get a lookahead token if don't already have one. */ /* YYCHAR is either empty, or end-of-input, or a valid lookahead. */ if (yychar == YYEMPTY) { YYDPRINTF ((stderr, "Reading a token\n")); yychar = yylex (&yylval, &yylloc, answer, errors, locations, lexer_param_ptr); } if (yychar <= YYEOF) { yychar = YYEOF; yytoken = YYSYMBOL_YYEOF; YYDPRINTF ((stderr, "Now at end of input.\n")); } else if (yychar == YYerror) { /* The scanner already issued an error message, process directly to error recovery. But do not keep the error token as lookahead, it is too special and may lead us to an endless loop in error recovery. */ yychar = YYUNDEF; yytoken = YYSYMBOL_YYerror; yyerror_range[1] = yylloc; goto yyerrlab1; } else { yytoken = YYTRANSLATE (yychar); YY_SYMBOL_PRINT ("Next token is", yytoken, &yylval, &yylloc); } /* If the proper action on seeing token YYTOKEN is to reduce or to detect an error, take that action. */ yyn += yytoken; if (yyn < 0 || YYLAST < yyn || yycheck[yyn] != yytoken) goto yydefault; yyn = yytable[yyn]; if (yyn <= 0) { if (yytable_value_is_error (yyn)) goto yyerrlab; yyn = -yyn; goto yyreduce; } /* Count tokens shifted since error; after three, turn off error status. */ if (yyerrstatus) yyerrstatus--; /* Shift the lookahead token. */ YY_SYMBOL_PRINT ("Shifting", yytoken, &yylval, &yylloc); yystate = yyn; YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN *++yyvsp = yylval; YY_IGNORE_MAYBE_UNINITIALIZED_END *++yylsp = yylloc; /* Discard the shifted token. */ yychar = YYEMPTY; goto yynewstate; /*-----------------------------------------------------------. | yydefault -- do the default action for the current state. | `-----------------------------------------------------------*/ yydefault: yyn = yydefact[yystate]; if (yyn == 0) goto yyerrlab; goto yyreduce; /*-----------------------------. | yyreduce -- do a reduction. | `-----------------------------*/ yyreduce: /* yyn is the number of a rule to reduce with. */ yylen = yyr2[yyn]; /* If YYLEN is nonzero, implement the default value of the action: '$$ = $1'. Otherwise, the following line sets YYVAL to garbage. This behavior is undocumented and Bison users should not rely upon it. Assigning to YYVAL unconditionally makes the parser a bit smaller, and it avoids a GCC warning that YYVAL may be used uninitialized. */ yyval = yyvsp[1-yylen]; /* Default location. */ YYLLOC_DEFAULT (yyloc, (yylsp - yylen), yylen); yyerror_range[1] = yyloc; YY_REDUCE_PRINT (yyn); switch (yyn) { case 2: /* TopLevel: Module Imports Query */ #line 282 "src/parser.y" { *answer = BLOCK((yyvsp[-2].blk), (yyvsp[-1].blk), gen_op_simple(TOP), (yyvsp[0].blk)); } #line 2510 "src/parser.c" break; case 3: /* TopLevel: Module Imports FuncDefs */ #line 285 "src/parser.y" { *answer = BLOCK((yyvsp[-2].blk), (yyvsp[-1].blk), (yyvsp[0].blk)); } #line 2518 "src/parser.c" break; case 4: /* Module: %empty */ #line 290 "src/parser.y" { (yyval.blk) = gen_noop(); } #line 2526 "src/parser.c" break; case 5: /* Module: "module" Query ';' */ #line 293 "src/parser.y" { if (!block_is_const((yyvsp[-1].blk))) { FAIL((yylsp[-1]), "Module metadata must be constant"); (yyval.blk) = gen_noop(); block_free((yyvsp[-1].blk)); } else if (block_const_kind((yyvsp[-1].blk)) != JV_KIND_OBJECT) { FAIL((yylsp[-1]), "Module metadata must be an object"); (yyval.blk) = gen_noop(); block_free((yyvsp[-1].blk)); } else { (yyval.blk) = gen_module((yyvsp[-1].blk)); } } #line 2544 "src/parser.c" break; case 6: /* Imports: %empty */ #line 308 "src/parser.y" { (yyval.blk) = gen_noop(); } #line 2552 "src/parser.c" break; case 7: /* Imports: Import Imports */ #line 311 "src/parser.y" { (yyval.blk) = BLOCK((yyvsp[-1].blk), (yyvsp[0].blk)); } #line 2560 "src/parser.c" break; case 8: /* FuncDefs: %empty */ #line 316 "src/parser.y" { (yyval.blk) = gen_noop(); } #line 2568 "src/parser.c" break; case 9: /* FuncDefs: FuncDef FuncDefs */ #line 319 "src/parser.y" { (yyval.blk) = block_join((yyvsp[-1].blk), (yyvsp[0].blk)); } #line 2576 "src/parser.c" break; case 10: /* Query: FuncDef Query */ #line 325 "src/parser.y" { (yyval.blk) = block_bind_referenced((yyvsp[-1].blk), (yyvsp[0].blk), OP_IS_CALL_PSEUDO); } #line 2584 "src/parser.c" break; case 11: /* Query: Expr "as" Patterns '|' Query */ #line 328 "src/parser.y" { (yyval.blk) = gen_destructure((yyvsp[-4].blk), (yyvsp[-2].blk), (yyvsp[0].blk)); } #line 2592 "src/parser.c" break; case 12: /* Query: "label" BINDING '|' Query */ #line 331 "src/parser.y" { jv v = jv_string_fmt("*label-%s", jv_string_value((yyvsp[-2].literal))); (yyval.blk) = gen_location((yyloc), locations, gen_label(jv_string_value(v), (yyvsp[0].blk))); jv_free((yyvsp[-2].literal)); jv_free(v); } #line 2603 "src/parser.c" break; case 13: /* Query: Query '|' Query */ #line 337 "src/parser.y" { (yyval.blk) = block_join((yyvsp[-2].blk), (yyvsp[0].blk)); } #line 2611 "src/parser.c" break; case 14: /* Query: Query ',' Query */ #line 340 "src/parser.y" { (yyval.blk) = gen_both((yyvsp[-2].blk), (yyvsp[0].blk)); } #line 2619 "src/parser.c" break; case 15: /* Query: Expr */ #line 343 "src/parser.y" { (yyval.blk) = (yyvsp[0].blk); } #line 2627 "src/parser.c" break; case 16: /* Expr: Expr "//" Expr */ #line 349 "src/parser.y" { (yyval.blk) = gen_definedor((yyvsp[-2].blk), (yyvsp[0].blk)); } #line 2635 "src/parser.c" break; case 17: /* Expr: Expr '=' Expr */ #line 352 "src/parser.y" { (yyval.blk) = gen_call("_assign", BLOCK(gen_lambda((yyvsp[-2].blk)), gen_lambda((yyvsp[0].blk)))); } #line 2643 "src/parser.c" break; case 18: /* Expr: Expr "or" Expr */ #line 355 "src/parser.y" { (yyval.blk) = gen_or((yyvsp[-2].blk), (yyvsp[0].blk)); } #line 2651 "src/parser.c" break; case 19: /* Expr: Expr "and" Expr */ #line 358 "src/parser.y" { (yyval.blk) = gen_and((yyvsp[-2].blk), (yyvsp[0].blk)); } #line 2659 "src/parser.c" break; case 20: /* Expr: Expr "//=" Expr */ #line 361 "src/parser.y" { (yyval.blk) = gen_definedor_assign((yyvsp[-2].blk), (yyvsp[0].blk)); } #line 2667 "src/parser.c" break; case 21: /* Expr: Expr "|=" Expr */ #line 364 "src/parser.y" { (yyval.blk) = gen_call("_modify", BLOCK(gen_lambda((yyvsp[-2].blk)), gen_lambda((yyvsp[0].blk)))); } #line 2675 "src/parser.c" break; case 22: /* Expr: Expr '+' Expr */ #line 367 "src/parser.y" { (yyval.blk) = gen_binop((yyvsp[-2].blk), (yyvsp[0].blk), '+'); } #line 2683 "src/parser.c" break; case 23: /* Expr: Expr "+=" Expr */ #line 370 "src/parser.y" { (yyval.blk) = gen_update((yyvsp[-2].blk), (yyvsp[0].blk), '+'); } #line 2691 "src/parser.c" break; case 24: /* Expr: Expr '-' Expr */ #line 373 "src/parser.y" { (yyval.blk) = gen_binop((yyvsp[-2].blk), (yyvsp[0].blk), '-'); } #line 2699 "src/parser.c" break; case 25: /* Expr: Expr "-=" Expr */ #line 376 "src/parser.y" { (yyval.blk) = gen_update((yyvsp[-2].blk), (yyvsp[0].blk), '-'); } #line 2707 "src/parser.c" break; case 26: /* Expr: Expr '*' Expr */ #line 379 "src/parser.y" { (yyval.blk) = gen_binop((yyvsp[-2].blk), (yyvsp[0].blk), '*'); } #line 2715 "src/parser.c" break; case 27: /* Expr: Expr "*=" Expr */ #line 382 "src/parser.y" { (yyval.blk) = gen_update((yyvsp[-2].blk), (yyvsp[0].blk), '*'); } #line 2723 "src/parser.c" break; case 28: /* Expr: Expr '/' Expr */ #line 385 "src/parser.y" { (yyval.blk) = gen_binop((yyvsp[-2].blk), (yyvsp[0].blk), '/'); } #line 2731 "src/parser.c" break; case 29: /* Expr: Expr '%' Expr */ #line 388 "src/parser.y" { (yyval.blk) = gen_binop((yyvsp[-2].blk), (yyvsp[0].blk), '%'); } #line 2739 "src/parser.c" break; case 30: /* Expr: Expr "/=" Expr */ #line 391 "src/parser.y" { (yyval.blk) = gen_update((yyvsp[-2].blk), (yyvsp[0].blk), '/'); } #line 2747 "src/parser.c" break; case 31: /* Expr: Expr "%=" Expr */ #line 394 "src/parser.y" { (yyval.blk) = gen_update((yyvsp[-2].blk), (yyvsp[0].blk), '%'); } #line 2755 "src/parser.c" break; case 32: /* Expr: Expr "==" Expr */ #line 397 "src/parser.y" { (yyval.blk) = gen_binop((yyvsp[-2].blk), (yyvsp[0].blk), EQ); } #line 2763 "src/parser.c" break; case 33: /* Expr: Expr "!=" Expr */ #line 400 "src/parser.y" { (yyval.blk) = gen_binop((yyvsp[-2].blk), (yyvsp[0].blk), NEQ); } #line 2771 "src/parser.c" break; case 34: /* Expr: Expr '<' Expr */ #line 403 "src/parser.y" { (yyval.blk) = gen_binop((yyvsp[-2].blk), (yyvsp[0].blk), '<'); } #line 2779 "src/parser.c" break; case 35: /* Expr: Expr '>' Expr */ #line 406 "src/parser.y" { (yyval.blk) = gen_binop((yyvsp[-2].blk), (yyvsp[0].blk), '>'); } #line 2787 "src/parser.c" break; case 36: /* Expr: Expr "<=" Expr */ #line 409 "src/parser.y" { (yyval.blk) = gen_binop((yyvsp[-2].blk), (yyvsp[0].blk), LESSEQ); } #line 2795 "src/parser.c" break; case 37: /* Expr: Expr ">=" Expr */ #line 412 "src/parser.y" { (yyval.blk) = gen_binop((yyvsp[-2].blk), (yyvsp[0].blk), GREATEREQ); } #line 2803 "src/parser.c" break; case 38: /* Expr: Term */ #line 415 "src/parser.y" { (yyval.blk) = (yyvsp[0].blk); } #line 2811 "src/parser.c" break; case 39: /* Import: ImportWhat ';' */ #line 421 "src/parser.y" { (yyval.blk) = (yyvsp[-1].blk); } #line 2819 "src/parser.c" break; case 40: /* Import: ImportWhat Query ';' */ #line 424 "src/parser.y" { if (!block_is_const((yyvsp[-1].blk))) { FAIL((yylsp[-1]), "Module metadata must be constant"); (yyval.blk) = gen_noop(); block_free((yyvsp[-2].blk)); block_free((yyvsp[-1].blk)); } else if (block_const_kind((yyvsp[-1].blk)) != JV_KIND_OBJECT) { FAIL((yylsp[-1]), "Module metadata must be an object"); (yyval.blk) = gen_noop(); block_free((yyvsp[-2].blk)); block_free((yyvsp[-1].blk)); } else { (yyval.blk) = gen_import_meta((yyvsp[-2].blk), (yyvsp[-1].blk)); } } #line 2839 "src/parser.c" break; case 41: /* ImportWhat: "import" ImportFrom "as" BINDING */ #line 441 "src/parser.y" { jv v = block_const((yyvsp[-2].blk)); // XXX Make gen_import take only blocks and the int is_data so we // don't have to free so much stuff here (yyval.blk) = gen_import(jv_string_value(v), jv_string_value((yyvsp[0].literal)), 1); block_free((yyvsp[-2].blk)); jv_free((yyvsp[0].literal)); jv_free(v); } #line 2853 "src/parser.c" break; case 42: /* ImportWhat: "import" ImportFrom "as" IDENT */ #line 450 "src/parser.y" { jv v = block_const((yyvsp[-2].blk)); (yyval.blk) = gen_import(jv_string_value(v), jv_string_value((yyvsp[0].literal)), 0); block_free((yyvsp[-2].blk)); jv_free((yyvsp[0].literal)); jv_free(v); } #line 2865 "src/parser.c" break; case 43: /* ImportWhat: "include" ImportFrom */ #line 457 "src/parser.y" { jv v = block_const((yyvsp[0].blk)); (yyval.blk) = gen_import(jv_string_value(v), NULL, 0); block_free((yyvsp[0].blk)); jv_free(v); } #line 2876 "src/parser.c" break; case 44: /* ImportFrom: String */ #line 465 "src/parser.y" { if (!block_is_const((yyvsp[0].blk))) { FAIL((yylsp[0]), "Import path must be constant"); (yyval.blk) = gen_const(jv_string("")); block_free((yyvsp[0].blk)); } else { (yyval.blk) = (yyvsp[0].blk); } } #line 2890 "src/parser.c" break; case 45: /* FuncDef: "def" IDENT ':' Query ';' */ #line 476 "src/parser.y" { (yyval.blk) = gen_function(jv_string_value((yyvsp[-3].literal)), gen_noop(), (yyvsp[-1].blk)); jv_free((yyvsp[-3].literal)); } #line 2899 "src/parser.c" break; case 46: /* FuncDef: "def" IDENT '(' Params ')' ':' Query ';' */ #line 481 "src/parser.y" { (yyval.blk) = gen_function(jv_string_value((yyvsp[-6].literal)), (yyvsp[-4].blk), (yyvsp[-1].blk)); jv_free((yyvsp[-6].literal)); } #line 2908 "src/parser.c" break; case 47: /* Params: Param */ #line 487 "src/parser.y" { (yyval.blk) = (yyvsp[0].blk); } #line 2916 "src/parser.c" break; case 48: /* Params: Params ';' Param */ #line 490 "src/parser.y" { (yyval.blk) = BLOCK((yyvsp[-2].blk), (yyvsp[0].blk)); } #line 2924 "src/parser.c" break; case 49: /* Param: BINDING */ #line 495 "src/parser.y" { (yyval.blk) = gen_param_regular(jv_string_value((yyvsp[0].literal))); jv_free((yyvsp[0].literal)); } #line 2933 "src/parser.c" break; case 50: /* Param: IDENT */ #line 499 "src/parser.y" { (yyval.blk) = gen_param(jv_string_value((yyvsp[0].literal))); jv_free((yyvsp[0].literal)); } #line 2942 "src/parser.c" break; case 51: /* StringStart: FORMAT QQSTRING_START */ #line 506 "src/parser.y" { (yyval.literal) = (yyvsp[-1].literal); } #line 2950 "src/parser.c" break; case 52: /* StringStart: QQSTRING_START */ #line 509 "src/parser.y" { (yyval.literal) = jv_string("text"); } #line 2958 "src/parser.c" break; case 53: /* String: StringStart QQString QQSTRING_END */ #line 515 "src/parser.y" { (yyval.blk) = (yyvsp[-1].blk); jv_free((yyvsp[-2].literal)); } #line 2967 "src/parser.c" break; case 54: /* QQString: %empty */ #line 522 "src/parser.y" { (yyval.blk) = gen_const(jv_string("")); } #line 2975 "src/parser.c" break; case 55: /* QQString: QQString QQSTRING_TEXT */ #line 525 "src/parser.y" { (yyval.blk) = gen_binop((yyvsp[-1].blk), gen_const((yyvsp[0].literal)), '+'); } #line 2983 "src/parser.c" break; case 56: /* QQString: QQString QQSTRING_INTERP_START Query QQSTRING_INTERP_END */ #line 528 "src/parser.y" { (yyval.blk) = gen_binop((yyvsp[-3].blk), gen_format((yyvsp[-1].blk), jv_copy((yyvsp[-4].literal))), '+'); } #line 2991 "src/parser.c" break; case 57: /* ElseBody: "elif" Query "then" Query ElseBody */ #line 534 "src/parser.y" { (yyval.blk) = gen_cond((yyvsp[-3].blk), (yyvsp[-1].blk), (yyvsp[0].blk)); } #line 2999 "src/parser.c" break; case 58: /* ElseBody: "else" Query "end" */ #line 537 "src/parser.y" { (yyval.blk) = (yyvsp[-1].blk); } #line 3007 "src/parser.c" break; case 59: /* ElseBody: "end" */ #line 540 "src/parser.y" { (yyval.blk) = gen_noop(); } #line 3015 "src/parser.c" break; case 60: /* Term: '.' */ #line 546 "src/parser.y" { (yyval.blk) = gen_noop(); } #line 3023 "src/parser.c" break; case 61: /* Term: ".." */ #line 549 "src/parser.y" { (yyval.blk) = gen_call("recurse", gen_noop()); } #line 3031 "src/parser.c" break; case 62: /* Term: "break" BINDING */ #line 552 "src/parser.y" { jv v = jv_string_fmt("*label-%s", jv_string_value((yyvsp[0].literal))); // impossible symbol (yyval.blk) = gen_location((yyloc), locations, BLOCK(gen_op_unbound(LOADV, jv_string_value(v)), gen_call("error", gen_noop()))); jv_free(v); jv_free((yyvsp[0].literal)); } #line 3044 "src/parser.c" break; case 63: /* Term: "break" error */ #line 560 "src/parser.y" { FAIL((yyloc), "break requires a label to break to"); (yyval.blk) = gen_noop(); } #line 3053 "src/parser.c" break; case 64: /* Term: Term FIELD '?' */ #line 564 "src/parser.y" { (yyval.blk) = gen_index_opt((yyvsp[-2].blk), gen_const((yyvsp[-1].literal))); } #line 3061 "src/parser.c" break; case 65: /* Term: FIELD '?' */ #line 567 "src/parser.y" { (yyval.blk) = gen_index_opt(gen_noop(), gen_const((yyvsp[-1].literal))); } #line 3069 "src/parser.c" break; case 66: /* Term: Term '.' String '?' */ #line 570 "src/parser.y" { (yyval.blk) = gen_index_opt((yyvsp[-3].blk), (yyvsp[-1].blk)); } #line 3077 "src/parser.c" break; case 67: /* Term: '.' String '?' */ #line 573 "src/parser.y" { (yyval.blk) = gen_index_opt(gen_noop(), (yyvsp[-1].blk)); } #line 3085 "src/parser.c" break; case 68: /* Term: Term FIELD */ #line 576 "src/parser.y" { (yyval.blk) = gen_index((yyvsp[-1].blk), gen_const((yyvsp[0].literal))); } #line 3093 "src/parser.c" break; case 69: /* Term: FIELD */ #line 579 "src/parser.y" { (yyval.blk) = gen_index(gen_noop(), gen_const((yyvsp[0].literal))); } #line 3101 "src/parser.c" break; case 70: /* Term: Term '.' String */ #line 582 "src/parser.y" { (yyval.blk) = gen_index((yyvsp[-2].blk), (yyvsp[0].blk)); } #line 3109 "src/parser.c" break; case 71: /* Term: '.' String */ #line 585 "src/parser.y" { (yyval.blk) = gen_index(gen_noop(), (yyvsp[0].blk)); } #line 3117 "src/parser.c" break; case 72: /* Term: '.' error */ #line 588 "src/parser.y" { FAIL((yyloc), "try .[\"field\"] instead of .field for unusually named fields"); (yyval.blk) = gen_noop(); } #line 3126 "src/parser.c" break; case 73: /* Term: '.' IDENT error */ #line 592 "src/parser.y" { jv_free((yyvsp[-1].literal)); FAIL((yyloc), "try .[\"field\"] instead of .field for unusually named fields"); (yyval.blk) = gen_noop(); } #line 3136 "src/parser.c" break; case 74: /* Term: Term '[' Query ']' '?' */ #line 598 "src/parser.y" { (yyval.blk) = gen_index_opt((yyvsp[-4].blk), (yyvsp[-2].blk)); } #line 3144 "src/parser.c" break; case 75: /* Term: Term '[' Query ']' */ #line 601 "src/parser.y" { (yyval.blk) = gen_index((yyvsp[-3].blk), (yyvsp[-1].blk)); } #line 3152 "src/parser.c" break; case 76: /* Term: Term '.' '[' Query ']' '?' */ #line 604 "src/parser.y" { (yyval.blk) = gen_index_opt((yyvsp[-5].blk), (yyvsp[-2].blk)); } #line 3160 "src/parser.c" break; case 77: /* Term: Term '.' '[' Query ']' */ #line 607 "src/parser.y" { (yyval.blk) = gen_index((yyvsp[-4].blk), (yyvsp[-1].blk)); } #line 3168 "src/parser.c" break; case 78: /* Term: Term '[' ']' '?' */ #line 610 "src/parser.y" { (yyval.blk) = block_join((yyvsp[-3].blk), gen_op_simple(EACH_OPT)); } #line 3176 "src/parser.c" break; case 79: /* Term: Term '[' ']' */ #line 613 "src/parser.y" { (yyval.blk) = block_join((yyvsp[-2].blk), gen_op_simple(EACH)); } #line 3184 "src/parser.c" break; case 80: /* Term: Term '.' '[' ']' '?' */ #line 616 "src/parser.y" { (yyval.blk) = block_join((yyvsp[-4].blk), gen_op_simple(EACH_OPT)); } #line 3192 "src/parser.c" break; case 81: /* Term: Term '.' '[' ']' */ #line 619 "src/parser.y" { (yyval.blk) = block_join((yyvsp[-3].blk), gen_op_simple(EACH)); } #line 3200 "src/parser.c" break; case 82: /* Term: Term '[' Query ':' Query ']' '?' */ #line 622 "src/parser.y" { (yyval.blk) = gen_slice_index((yyvsp[-6].blk), (yyvsp[-4].blk), (yyvsp[-2].blk), INDEX_OPT); } #line 3208 "src/parser.c" break; case 83: /* Term: Term '[' Query ':' ']' '?' */ #line 625 "src/parser.y" { (yyval.blk) = gen_slice_index((yyvsp[-5].blk), (yyvsp[-3].blk), gen_const(jv_null()), INDEX_OPT); } #line 3216 "src/parser.c" break; case 84: /* Term: Term '[' ':' Query ']' '?' */ #line 628 "src/parser.y" { (yyval.blk) = gen_slice_index((yyvsp[-5].blk), gen_const(jv_null()), (yyvsp[-2].blk), INDEX_OPT); } #line 3224 "src/parser.c" break; case 85: /* Term: Term '[' Query ':' Query ']' */ #line 631 "src/parser.y" { (yyval.blk) = gen_slice_index((yyvsp[-5].blk), (yyvsp[-3].blk), (yyvsp[-1].blk), INDEX); } #line 3232 "src/parser.c" break; case 86: /* Term: Term '[' Query ':' ']' */ #line 634 "src/parser.y" { (yyval.blk) = gen_slice_index((yyvsp[-4].blk), (yyvsp[-2].blk), gen_const(jv_null()), INDEX); } #line 3240 "src/parser.c" break; case 87: /* Term: Term '[' ':' Query ']' */ #line 637 "src/parser.y" { (yyval.blk) = gen_slice_index((yyvsp[-4].blk), gen_const(jv_null()), (yyvsp[-1].blk), INDEX); } #line 3248 "src/parser.c" break; case 88: /* Term: Term '?' */ #line 640 "src/parser.y" { (yyval.blk) = gen_try((yyvsp[-1].blk), gen_op_simple(BACKTRACK)); } #line 3256 "src/parser.c" break; case 89: /* Term: LITERAL */ #line 643 "src/parser.y" { (yyval.blk) = gen_const((yyvsp[0].literal)); } #line 3264 "src/parser.c" break; case 90: /* Term: String */ #line 646 "src/parser.y" { (yyval.blk) = (yyvsp[0].blk); } #line 3272 "src/parser.c" break; case 91: /* Term: FORMAT */ #line 649 "src/parser.y" { (yyval.blk) = gen_format(gen_noop(), (yyvsp[0].literal)); } #line 3280 "src/parser.c" break; case 92: /* Term: '-' Term */ #line 652 "src/parser.y" { (yyval.blk) = BLOCK((yyvsp[0].blk), gen_call("_negate", gen_noop())); } #line 3288 "src/parser.c" break; case 93: /* Term: '(' Query ')' */ #line 655 "src/parser.y" { (yyval.blk) = (yyvsp[-1].blk); } #line 3296 "src/parser.c" break; case 94: /* Term: '[' Query ']' */ #line 658 "src/parser.y" { (yyval.blk) = gen_collect((yyvsp[-1].blk)); } #line 3304 "src/parser.c" break; case 95: /* Term: '[' ']' */ #line 661 "src/parser.y" { (yyval.blk) = gen_const(jv_array()); } #line 3312 "src/parser.c" break; case 96: /* Term: '{' DictPairs '}' */ #line 664 "src/parser.y" { block o = gen_const_object((yyvsp[-1].blk)); if (o.first != NULL) (yyval.blk) = o; else (yyval.blk) = BLOCK(gen_subexp(gen_const(jv_object())), (yyvsp[-1].blk), gen_op_simple(POP)); } #line 3324 "src/parser.c" break; case 97: /* Term: "reduce" Expr "as" Patterns '(' Query ';' Query ')' */ #line 671 "src/parser.y" { (yyval.blk) = gen_reduce((yyvsp[-7].blk), (yyvsp[-5].blk), (yyvsp[-3].blk), (yyvsp[-1].blk)); } #line 3332 "src/parser.c" break; case 98: /* Term: "foreach" Expr "as" Patterns '(' Query ';' Query ';' Query ')' */ #line 674 "src/parser.y" { (yyval.blk) = gen_foreach((yyvsp[-9].blk), (yyvsp[-7].blk), (yyvsp[-5].blk), (yyvsp[-3].blk), (yyvsp[-1].blk)); } #line 3340 "src/parser.c" break; case 99: /* Term: "foreach" Expr "as" Patterns '(' Query ';' Query ')' */ #line 677 "src/parser.y" { (yyval.blk) = gen_foreach((yyvsp[-7].blk), (yyvsp[-5].blk), (yyvsp[-3].blk), (yyvsp[-1].blk), gen_noop()); } #line 3348 "src/parser.c" break; case 100: /* Term: "if" Query "then" Query ElseBody */ #line 680 "src/parser.y" { (yyval.blk) = gen_cond((yyvsp[-3].blk), (yyvsp[-1].blk), (yyvsp[0].blk)); } #line 3356 "src/parser.c" break; case 101: /* Term: "if" Query "then" error */ #line 683 "src/parser.y" { FAIL((yyloc), "Possibly unterminated 'if' statement"); (yyval.blk) = (yyvsp[-2].blk); } #line 3365 "src/parser.c" break; case 102: /* Term: "try" Expr "catch" Expr */ #line 687 "src/parser.y" { (yyval.blk) = gen_try((yyvsp[-2].blk), (yyvsp[0].blk)); } #line 3373 "src/parser.c" break; case 103: /* Term: "try" Expr "catch" error */ #line 690 "src/parser.y" { FAIL((yyloc), "Possibly unterminated 'try' statement"); (yyval.blk) = (yyvsp[-2].blk); } #line 3382 "src/parser.c" break; case 104: /* Term: "try" Expr */ #line 694 "src/parser.y" { (yyval.blk) = gen_try((yyvsp[0].blk), gen_op_simple(BACKTRACK)); } #line 3390 "src/parser.c" break; case 105: /* Term: '$' '$' '$' BINDING */ #line 712 "src/parser.y" { (yyval.blk) = gen_location((yyloc), locations, gen_op_unbound(LOADVN, jv_string_value((yyvsp[0].literal)))); jv_free((yyvsp[0].literal)); } #line 3399 "src/parser.c" break; case 106: /* Term: BINDING */ #line 716 "src/parser.y" { (yyval.blk) = gen_location((yyloc), locations, gen_op_unbound(LOADV, jv_string_value((yyvsp[0].literal)))); jv_free((yyvsp[0].literal)); } #line 3408 "src/parser.c" break; case 107: /* Term: "$__loc__" */ #line 720 "src/parser.y" { (yyval.blk) = gen_loc_object(&(yyloc), locations); } #line 3416 "src/parser.c" break; case 108: /* Term: IDENT */ #line 723 "src/parser.y" { const char *s = jv_string_value((yyvsp[0].literal)); if (strcmp(s, "false") == 0) (yyval.blk) = gen_const(jv_false()); else if (strcmp(s, "true") == 0) (yyval.blk) = gen_const(jv_true()); else if (strcmp(s, "null") == 0) (yyval.blk) = gen_const(jv_null()); else (yyval.blk) = gen_location((yyloc), locations, gen_call(s, gen_noop())); jv_free((yyvsp[0].literal)); } #line 3433 "src/parser.c" break; case 109: /* Term: IDENT '(' Args ')' */ #line 735 "src/parser.y" { (yyval.blk) = gen_call(jv_string_value((yyvsp[-3].literal)), (yyvsp[-1].blk)); (yyval.blk) = gen_location((yylsp[-3]), locations, (yyval.blk)); jv_free((yyvsp[-3].literal)); } #line 3443 "src/parser.c" break; case 110: /* Term: '(' error ')' */ #line 740 "src/parser.y" { (yyval.blk) = gen_noop(); } #line 3449 "src/parser.c" break; case 111: /* Term: '[' error ']' */ #line 741 "src/parser.y" { (yyval.blk) = gen_noop(); } #line 3455 "src/parser.c" break; case 112: /* Term: Term '[' error ']' */ #line 742 "src/parser.y" { (yyval.blk) = (yyvsp[-3].blk); } #line 3461 "src/parser.c" break; case 113: /* Term: '{' error '}' */ #line 743 "src/parser.y" { (yyval.blk) = gen_noop(); } #line 3467 "src/parser.c" break; case 114: /* Args: Arg */ #line 746 "src/parser.y" { (yyval.blk) = (yyvsp[0].blk); } #line 3475 "src/parser.c" break; case 115: /* Args: Args ';' Arg */ #line 749 "src/parser.y" { (yyval.blk) = BLOCK((yyvsp[-2].blk), (yyvsp[0].blk)); } #line 3483 "src/parser.c" break; case 116: /* Arg: Query */ #line 754 "src/parser.y" { (yyval.blk) = gen_lambda((yyvsp[0].blk)); } #line 3491 "src/parser.c" break; case 117: /* RepPatterns: RepPatterns "?//" Pattern */ #line 759 "src/parser.y" { (yyval.blk) = BLOCK((yyvsp[-2].blk), gen_destructure_alt((yyvsp[0].blk))); } #line 3499 "src/parser.c" break; case 118: /* RepPatterns: Pattern */ #line 762 "src/parser.y" { (yyval.blk) = gen_destructure_alt((yyvsp[0].blk)); } #line 3507 "src/parser.c" break; case 119: /* Patterns: RepPatterns "?//" Pattern */ #line 767 "src/parser.y" { (yyval.blk) = BLOCK((yyvsp[-2].blk), (yyvsp[0].blk)); } #line 3515 "src/parser.c" break; case 120: /* Patterns: Pattern */ #line 770 "src/parser.y" { (yyval.blk) = (yyvsp[0].blk); } #line 3523 "src/parser.c" break; case 121: /* Pattern: BINDING */ #line 775 "src/parser.y" { (yyval.blk) = gen_op_unbound(STOREV, jv_string_value((yyvsp[0].literal))); jv_free((yyvsp[0].literal)); } #line 3532 "src/parser.c" break; case 122: /* Pattern: '[' ArrayPats ']' */ #line 779 "src/parser.y" { (yyval.blk) = BLOCK((yyvsp[-1].blk), gen_op_simple(POP)); } #line 3540 "src/parser.c" break; case 123: /* Pattern: '{' ObjPats '}' */ #line 782 "src/parser.y" { (yyval.blk) = BLOCK((yyvsp[-1].blk), gen_op_simple(POP)); } #line 3548 "src/parser.c" break; case 124: /* ArrayPats: Pattern */ #line 787 "src/parser.y" { (yyval.blk) = gen_array_matcher(gen_noop(), (yyvsp[0].blk)); } #line 3556 "src/parser.c" break; case 125: /* ArrayPats: ArrayPats ',' Pattern */ #line 790 "src/parser.y" { (yyval.blk) = gen_array_matcher((yyvsp[-2].blk), (yyvsp[0].blk)); } #line 3564 "src/parser.c" break; case 126: /* ObjPats: ObjPat */ #line 795 "src/parser.y" { (yyval.blk) = (yyvsp[0].blk); } #line 3572 "src/parser.c" break; case 127: /* ObjPats: ObjPats ',' ObjPat */ #line 798 "src/parser.y" { (yyval.blk) = BLOCK((yyvsp[-2].blk), (yyvsp[0].blk)); } #line 3580 "src/parser.c" break; case 128: /* ObjPat: BINDING */ #line 803 "src/parser.y" { (yyval.blk) = gen_object_matcher(gen_const((yyvsp[0].literal)), gen_op_unbound(STOREV, jv_string_value((yyvsp[0].literal)))); } #line 3588 "src/parser.c" break; case 129: /* ObjPat: BINDING ':' Pattern */ #line 806 "src/parser.y" { (yyval.blk) = gen_object_matcher(gen_const((yyvsp[-2].literal)), BLOCK(gen_op_simple(DUP), gen_op_unbound(STOREV, jv_string_value((yyvsp[-2].literal))), (yyvsp[0].blk))); } #line 3596 "src/parser.c" break; case 130: /* ObjPat: IDENT ':' Pattern */ #line 809 "src/parser.y" { (yyval.blk) = gen_object_matcher(gen_const((yyvsp[-2].literal)), (yyvsp[0].blk)); } #line 3604 "src/parser.c" break; case 131: /* ObjPat: Keyword ':' Pattern */ #line 812 "src/parser.y" { (yyval.blk) = gen_object_matcher(gen_const((yyvsp[-2].literal)), (yyvsp[0].blk)); } #line 3612 "src/parser.c" break; case 132: /* ObjPat: String ':' Pattern */ #line 815 "src/parser.y" { (yyval.blk) = gen_object_matcher((yyvsp[-2].blk), (yyvsp[0].blk)); } #line 3620 "src/parser.c" break; case 133: /* ObjPat: '(' Query ')' ':' Pattern */ #line 818 "src/parser.y" { jv msg = check_object_key((yyvsp[-3].blk)); if (jv_is_valid(msg)) { FAIL((yylsp[-3]), jv_string_value(msg)); } jv_free(msg); (yyval.blk) = gen_object_matcher((yyvsp[-3].blk), (yyvsp[0].blk)); } #line 3633 "src/parser.c" break; case 134: /* ObjPat: error ':' Pattern */ #line 826 "src/parser.y" { FAIL((yyloc), "May need parentheses around object key expression"); (yyval.blk) = (yyvsp[0].blk); } #line 3642 "src/parser.c" break; case 135: /* Keyword: "as" */ #line 832 "src/parser.y" { (yyval.literal) = jv_string("as"); } #line 3650 "src/parser.c" break; case 136: /* Keyword: "def" */ #line 835 "src/parser.y" { (yyval.literal) = jv_string("def"); } #line 3658 "src/parser.c" break; case 137: /* Keyword: "module" */ #line 838 "src/parser.y" { (yyval.literal) = jv_string("module"); } #line 3666 "src/parser.c" break; case 138: /* Keyword: "import" */ #line 841 "src/parser.y" { (yyval.literal) = jv_string("import"); } #line 3674 "src/parser.c" break; case 139: /* Keyword: "include" */ #line 844 "src/parser.y" { (yyval.literal) = jv_string("include"); } #line 3682 "src/parser.c" break; case 140: /* Keyword: "if" */ #line 847 "src/parser.y" { (yyval.literal) = jv_string("if"); } #line 3690 "src/parser.c" break; case 141: /* Keyword: "then" */ #line 850 "src/parser.y" { (yyval.literal) = jv_string("then"); } #line 3698 "src/parser.c" break; case 142: /* Keyword: "else" */ #line 853 "src/parser.y" { (yyval.literal) = jv_string("else"); } #line 3706 "src/parser.c" break; case 143: /* Keyword: "elif" */ #line 856 "src/parser.y" { (yyval.literal) = jv_string("elif"); } #line 3714 "src/parser.c" break; case 144: /* Keyword: "reduce" */ #line 859 "src/parser.y" { (yyval.literal) = jv_string("reduce"); } #line 3722 "src/parser.c" break; case 145: /* Keyword: "foreach" */ #line 862 "src/parser.y" { (yyval.literal) = jv_string("foreach"); } #line 3730 "src/parser.c" break; case 146: /* Keyword: "end" */ #line 865 "src/parser.y" { (yyval.literal) = jv_string("end"); } #line 3738 "src/parser.c" break; case 147: /* Keyword: "and" */ #line 868 "src/parser.y" { (yyval.literal) = jv_string("and"); } #line 3746 "src/parser.c" break; case 148: /* Keyword: "or" */ #line 871 "src/parser.y" { (yyval.literal) = jv_string("or"); } #line 3754 "src/parser.c" break; case 149: /* Keyword: "try" */ #line 874 "src/parser.y" { (yyval.literal) = jv_string("try"); } #line 3762 "src/parser.c" break; case 150: /* Keyword: "catch" */ #line 877 "src/parser.y" { (yyval.literal) = jv_string("catch"); } #line 3770 "src/parser.c" break; case 151: /* Keyword: "label" */ #line 880 "src/parser.y" { (yyval.literal) = jv_string("label"); } #line 3778 "src/parser.c" break; case 152: /* Keyword: "break" */ #line 883 "src/parser.y" { (yyval.literal) = jv_string("break"); } #line 3786 "src/parser.c" break; case 153: /* DictPairs: %empty */ #line 889 "src/parser.y" { (yyval.blk) = gen_noop(); } #line 3794 "src/parser.c" break; case 154: /* DictPairs: DictPair */ #line 892 "src/parser.y" { (yyval.blk) = (yyvsp[0].blk); } #line 3802 "src/parser.c" break; case 155: /* DictPairs: DictPair ',' DictPairs */ #line 895 "src/parser.y" { (yyval.blk) = block_join((yyvsp[-2].blk), (yyvsp[0].blk)); } #line 3810 "src/parser.c" break; case 156: /* DictPair: IDENT ':' DictExpr */ #line 900 "src/parser.y" { (yyval.blk) = gen_dictpair(gen_const((yyvsp[-2].literal)), (yyvsp[0].blk)); } #line 3818 "src/parser.c" break; case 157: /* DictPair: Keyword ':' DictExpr */ #line 903 "src/parser.y" { (yyval.blk) = gen_dictpair(gen_const((yyvsp[-2].literal)), (yyvsp[0].blk)); } #line 3826 "src/parser.c" break; case 158: /* DictPair: String ':' DictExpr */ #line 906 "src/parser.y" { (yyval.blk) = gen_dictpair((yyvsp[-2].blk), (yyvsp[0].blk)); } #line 3834 "src/parser.c" break; case 159: /* DictPair: String */ #line 909 "src/parser.y" { (yyval.blk) = gen_dictpair((yyvsp[0].blk), BLOCK(gen_op_simple(POP), gen_op_simple(DUP2), gen_op_simple(DUP2), gen_op_simple(INDEX))); } #line 3843 "src/parser.c" break; case 160: /* DictPair: BINDING ':' DictExpr */ #line 913 "src/parser.y" { (yyval.blk) = gen_dictpair(gen_location((yyloc), locations, gen_op_unbound(LOADV, jv_string_value((yyvsp[-2].literal)))), (yyvsp[0].blk)); jv_free((yyvsp[-2].literal)); } #line 3853 "src/parser.c" break; case 161: /* DictPair: BINDING */ #line 918 "src/parser.y" { (yyval.blk) = gen_dictpair(gen_const((yyvsp[0].literal)), gen_location((yyloc), locations, gen_op_unbound(LOADV, jv_string_value((yyvsp[0].literal))))); } #line 3862 "src/parser.c" break; case 162: /* DictPair: IDENT */ #line 922 "src/parser.y" { (yyval.blk) = gen_dictpair(gen_const(jv_copy((yyvsp[0].literal))), gen_index(gen_noop(), gen_const((yyvsp[0].literal)))); } #line 3871 "src/parser.c" break; case 163: /* DictPair: "$__loc__" */ #line 926 "src/parser.y" { (yyval.blk) = gen_dictpair(gen_const(jv_string("__loc__")), gen_loc_object(&(yyloc), locations)); } #line 3880 "src/parser.c" break; case 164: /* DictPair: Keyword */ #line 930 "src/parser.y" { (yyval.blk) = gen_dictpair(gen_const(jv_copy((yyvsp[0].literal))), gen_index(gen_noop(), gen_const((yyvsp[0].literal)))); } #line 3889 "src/parser.c" break; case 165: /* DictPair: '(' Query ')' ':' DictExpr */ #line 934 "src/parser.y" { jv msg = check_object_key((yyvsp[-3].blk)); if (jv_is_valid(msg)) { FAIL((yylsp[-3]), jv_string_value(msg)); } jv_free(msg); (yyval.blk) = gen_dictpair((yyvsp[-3].blk), (yyvsp[0].blk)); } #line 3902 "src/parser.c" break; case 166: /* DictPair: error ':' DictExpr */ #line 942 "src/parser.y" { FAIL((yylsp[-2]), "May need parentheses around object key expression"); (yyval.blk) = (yyvsp[0].blk); } #line 3911 "src/parser.c" break; case 167: /* DictExpr: DictExpr '|' DictExpr */ #line 948 "src/parser.y" { (yyval.blk) = block_join((yyvsp[-2].blk), (yyvsp[0].blk)); } #line 3919 "src/parser.c" break; case 168: /* DictExpr: Expr */ #line 951 "src/parser.y" { (yyval.blk) = (yyvsp[0].blk); } #line 3927 "src/parser.c" break; #line 3931 "src/parser.c" default: break; } /* User semantic actions sometimes alter yychar, and that requires that yytoken be updated with the new translation. We take the approach of translating immediately before every use of yytoken. One alternative is translating here after every semantic action, but that translation would be missed if the semantic action invokes YYABORT, YYACCEPT, or YYERROR immediately after altering yychar or if it invokes YYBACKUP. In the case of YYABORT or YYACCEPT, an incorrect destructor might then be invoked immediately. In the case of YYERROR or YYBACKUP, subsequent parser actions might lead to an incorrect destructor call or verbose syntax error message before the lookahead is translated. */ YY_SYMBOL_PRINT ("-> $$ =", YY_CAST (yysymbol_kind_t, yyr1[yyn]), &yyval, &yyloc); YYPOPSTACK (yylen); yylen = 0; *++yyvsp = yyval; *++yylsp = yyloc; /* Now 'shift' the result of the reduction. Determine what state that goes to, based on the state we popped back to and the rule number reduced by. */ { const int yylhs = yyr1[yyn] - YYNTOKENS; const int yyi = yypgoto[yylhs] + *yyssp; yystate = (0 <= yyi && yyi <= YYLAST && yycheck[yyi] == *yyssp ? yytable[yyi] : yydefgoto[yylhs]); } goto yynewstate; /*--------------------------------------. | yyerrlab -- here on detecting error. | `--------------------------------------*/ yyerrlab: /* Make sure we have latest lookahead translation. See comments at user semantic actions for why this is necessary. */ yytoken = yychar == YYEMPTY ? YYSYMBOL_YYEMPTY : YYTRANSLATE (yychar); /* If not already recovering from an error, report this error. */ if (!yyerrstatus) { ++yynerrs; { yypcontext_t yyctx = {yyssp, yytoken, &yylloc}; char const *yymsgp = YY_("syntax error"); int yysyntax_error_status; yysyntax_error_status = yysyntax_error (&yymsg_alloc, &yymsg, &yyctx); if (yysyntax_error_status == 0) yymsgp = yymsg; else if (yysyntax_error_status == -1) { if (yymsg != yymsgbuf) YYSTACK_FREE (yymsg); yymsg = YY_CAST (char *, YYSTACK_ALLOC (YY_CAST (YYSIZE_T, yymsg_alloc))); if (yymsg) { yysyntax_error_status = yysyntax_error (&yymsg_alloc, &yymsg, &yyctx); yymsgp = yymsg; } else { yymsg = yymsgbuf; yymsg_alloc = sizeof yymsgbuf; yysyntax_error_status = YYENOMEM; } } yyerror (&yylloc, answer, errors, locations, lexer_param_ptr, yymsgp); if (yysyntax_error_status == YYENOMEM) YYNOMEM; } } yyerror_range[1] = yylloc; if (yyerrstatus == 3) { /* If just tried and failed to reuse lookahead token after an error, discard it. */ if (yychar <= YYEOF) { /* Return failure if at end of input. */ if (yychar == YYEOF) YYABORT; } else { yydestruct ("Error: discarding", yytoken, &yylval, &yylloc, answer, errors, locations, lexer_param_ptr); yychar = YYEMPTY; } } /* Else will try to reuse lookahead token after shifting the error token. */ goto yyerrlab1; /*---------------------------------------------------. | yyerrorlab -- error raised explicitly by YYERROR. | `---------------------------------------------------*/ yyerrorlab: /* Pacify compilers when the user code never invokes YYERROR and the label yyerrorlab therefore never appears in user code. */ if (0) YYERROR; ++yynerrs; /* Do not reclaim the symbols of the rule whose action triggered this YYERROR. */ YYPOPSTACK (yylen); yylen = 0; YY_STACK_PRINT (yyss, yyssp); yystate = *yyssp; goto yyerrlab1; /*-------------------------------------------------------------. | yyerrlab1 -- common code for both syntax error and YYERROR. | `-------------------------------------------------------------*/ yyerrlab1: yyerrstatus = 3; /* Each real token shifted decrements this. */ /* Pop stack until we find a state that shifts the error token. */ for (;;) { yyn = yypact[yystate]; if (!yypact_value_is_default (yyn)) { yyn += YYSYMBOL_YYerror; if (0 <= yyn && yyn <= YYLAST && yycheck[yyn] == YYSYMBOL_YYerror) { yyn = yytable[yyn]; if (0 < yyn) break; } } /* Pop the current state because it cannot handle the error token. */ if (yyssp == yyss) YYABORT; yyerror_range[1] = *yylsp; yydestruct ("Error: popping", YY_ACCESSING_SYMBOL (yystate), yyvsp, yylsp, answer, errors, locations, lexer_param_ptr); YYPOPSTACK (1); yystate = *yyssp; YY_STACK_PRINT (yyss, yyssp); } YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN *++yyvsp = yylval; YY_IGNORE_MAYBE_UNINITIALIZED_END yyerror_range[2] = yylloc; ++yylsp; YYLLOC_DEFAULT (*yylsp, yyerror_range, 2); /* Shift the error token. */ YY_SYMBOL_PRINT ("Shifting", YY_ACCESSING_SYMBOL (yyn), yyvsp, yylsp); yystate = yyn; goto yynewstate; /*-------------------------------------. | yyacceptlab -- YYACCEPT comes here. | `-------------------------------------*/ yyacceptlab: yyresult = 0; goto yyreturnlab; /*-----------------------------------. | yyabortlab -- YYABORT comes here. | `-----------------------------------*/ yyabortlab: yyresult = 1; goto yyreturnlab; /*-----------------------------------------------------------. | yyexhaustedlab -- YYNOMEM (memory exhaustion) comes here. | `-----------------------------------------------------------*/ yyexhaustedlab: yyerror (&yylloc, answer, errors, locations, lexer_param_ptr, YY_("memory exhausted")); yyresult = 2; goto yyreturnlab; /*----------------------------------------------------------. | yyreturnlab -- parsing is finished, clean up and return. | `----------------------------------------------------------*/ yyreturnlab: if (yychar != YYEMPTY) { /* Make sure we have latest lookahead translation. See comments at user semantic actions for why this is necessary. */ yytoken = YYTRANSLATE (yychar); yydestruct ("Cleanup: discarding lookahead", yytoken, &yylval, &yylloc, answer, errors, locations, lexer_param_ptr); } /* Do not reclaim the symbols of the rule whose action triggered this YYABORT or YYACCEPT. */ YYPOPSTACK (yylen); YY_STACK_PRINT (yyss, yyssp); while (yyssp != yyss) { yydestruct ("Cleanup: popping", YY_ACCESSING_SYMBOL (+*yyssp), yyvsp, yylsp, answer, errors, locations, lexer_param_ptr); YYPOPSTACK (1); } #ifndef yyoverflow if (yyss != yyssa) YYSTACK_FREE (yyss); #endif if (yymsg != yymsgbuf) YYSTACK_FREE (yymsg); return yyresult; } #line 954 "src/parser.y" int jq_parse(struct locfile* locations, block* answer) { struct lexer_param scanner; YY_BUFFER_STATE buf; jq_yylex_init_extra(0, &scanner.lexer); buf = jq_yy_scan_bytes(locations->data, locations->length, scanner.lexer); int errors = 0; *answer = gen_noop(); yyparse(answer, &errors, locations, &scanner); jq_yy_delete_buffer(buf, scanner.lexer); jq_yylex_destroy(scanner.lexer); if (errors > 0) { block_free(*answer); *answer = gen_noop(); } return errors; } int jq_parse_library(struct locfile* locations, block* answer) { int errs = jq_parse(locations, answer); if (errs) return errs; if (block_has_main(*answer)) { locfile_locate(locations, UNKNOWN_LOCATION, "jq: error: library should only have function definitions, not a main expression"); return 1; } assert(block_has_only_binders_and_imports(*answer, OP_IS_CALL_PSEUDO)); return 0; } ================================================ FILE: src/parser.h ================================================ /* A Bison parser, made by GNU Bison 3.8.2. */ /* Bison interface for Yacc-like parsers in C Copyright (C) 1984, 1989-1990, 2000-2015, 2018-2021 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 3 of the License, 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 . */ /* As a special exception, you may create a larger work that contains part or all of the Bison parser skeleton and distribute that work under terms of your choice, so long as that work isn't itself a parser generator using the skeleton or a modified version thereof as a parser skeleton. Alternatively, if you modify or redistribute the parser skeleton itself, you may (at your option) remove this special exception, which will cause the skeleton and the resulting Bison output files to be licensed under the GNU General Public License without this special exception. This special exception was added by the Free Software Foundation in version 2.2 of Bison. */ /* DO NOT RELY ON FEATURES THAT ARE NOT DOCUMENTED in the manual, especially those whose name start with YY_ or yy_. They are private implementation details that can be changed or removed. */ #ifndef YY_YY_SRC_PARSER_H_INCLUDED # define YY_YY_SRC_PARSER_H_INCLUDED /* Debug traces. */ #ifndef YYDEBUG # define YYDEBUG 0 #endif #if YYDEBUG extern int yydebug; #endif /* "%code requires" blocks. */ #line 12 "src/parser.y" #include "locfile.h" struct lexer_param; #define YYLTYPE location #define YYLLOC_DEFAULT(Loc, Rhs, N) \ do { \ if (N) { \ (Loc).start = YYRHSLOC(Rhs, 1).start; \ (Loc).end = YYRHSLOC(Rhs, N).end; \ } else { \ (Loc).start = YYRHSLOC(Rhs, 0).end; \ (Loc).end = YYRHSLOC(Rhs, 0).end; \ } \ } while (0) #line 66 "src/parser.h" /* Token kinds. */ #ifndef YYTOKENTYPE # define YYTOKENTYPE enum yytokentype { YYEMPTY = -2, YYEOF = 0, /* "end of file" */ YYerror = 256, /* error */ YYUNDEF = 257, /* "invalid token" */ INVALID_CHARACTER = 258, /* INVALID_CHARACTER */ IDENT = 259, /* IDENT */ FIELD = 260, /* FIELD */ BINDING = 261, /* BINDING */ LITERAL = 262, /* LITERAL */ FORMAT = 263, /* FORMAT */ REC = 264, /* ".." */ SETMOD = 265, /* "%=" */ EQ = 266, /* "==" */ NEQ = 267, /* "!=" */ DEFINEDOR = 268, /* "//" */ AS = 269, /* "as" */ DEF = 270, /* "def" */ MODULE = 271, /* "module" */ IMPORT = 272, /* "import" */ INCLUDE = 273, /* "include" */ IF = 274, /* "if" */ THEN = 275, /* "then" */ ELSE = 276, /* "else" */ ELSE_IF = 277, /* "elif" */ REDUCE = 278, /* "reduce" */ FOREACH = 279, /* "foreach" */ END = 280, /* "end" */ AND = 281, /* "and" */ OR = 282, /* "or" */ TRY = 283, /* "try" */ CATCH = 284, /* "catch" */ LABEL = 285, /* "label" */ BREAK = 286, /* "break" */ LOC = 287, /* "$__loc__" */ SETPIPE = 288, /* "|=" */ SETPLUS = 289, /* "+=" */ SETMINUS = 290, /* "-=" */ SETMULT = 291, /* "*=" */ SETDIV = 292, /* "/=" */ SETDEFINEDOR = 293, /* "//=" */ LESSEQ = 294, /* "<=" */ GREATEREQ = 295, /* ">=" */ ALTERNATION = 296, /* "?//" */ QQSTRING_START = 297, /* QQSTRING_START */ QQSTRING_TEXT = 298, /* QQSTRING_TEXT */ QQSTRING_INTERP_START = 299, /* QQSTRING_INTERP_START */ QQSTRING_INTERP_END = 300, /* QQSTRING_INTERP_END */ QQSTRING_END = 301, /* QQSTRING_END */ FUNCDEF = 302, /* FUNCDEF */ NONOPT = 303 /* NONOPT */ }; typedef enum yytokentype yytoken_kind_t; #endif /* Token kinds. */ #define YYEMPTY -2 #define YYEOF 0 #define YYerror 256 #define YYUNDEF 257 #define INVALID_CHARACTER 258 #define IDENT 259 #define FIELD 260 #define BINDING 261 #define LITERAL 262 #define FORMAT 263 #define REC 264 #define SETMOD 265 #define EQ 266 #define NEQ 267 #define DEFINEDOR 268 #define AS 269 #define DEF 270 #define MODULE 271 #define IMPORT 272 #define INCLUDE 273 #define IF 274 #define THEN 275 #define ELSE 276 #define ELSE_IF 277 #define REDUCE 278 #define FOREACH 279 #define END 280 #define AND 281 #define OR 282 #define TRY 283 #define CATCH 284 #define LABEL 285 #define BREAK 286 #define LOC 287 #define SETPIPE 288 #define SETPLUS 289 #define SETMINUS 290 #define SETMULT 291 #define SETDIV 292 #define SETDEFINEDOR 293 #define LESSEQ 294 #define GREATEREQ 295 #define ALTERNATION 296 #define QQSTRING_START 297 #define QQSTRING_TEXT 298 #define QQSTRING_INTERP_START 299 #define QQSTRING_INTERP_END 300 #define QQSTRING_END 301 #define FUNCDEF 302 #define NONOPT 303 /* Value type. */ #if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED union YYSTYPE { #line 32 "src/parser.y" jv literal; block blk; #line 187 "src/parser.h" }; typedef union YYSTYPE YYSTYPE; # define YYSTYPE_IS_TRIVIAL 1 # define YYSTYPE_IS_DECLARED 1 #endif /* Location type. */ #if ! defined YYLTYPE && ! defined YYLTYPE_IS_DECLARED typedef struct YYLTYPE YYLTYPE; struct YYLTYPE { int first_line; int first_column; int last_line; int last_column; }; # define YYLTYPE_IS_DECLARED 1 # define YYLTYPE_IS_TRIVIAL 1 #endif int yyparse (block* answer, int* errors, struct locfile* locations, struct lexer_param* lexer_param_ptr); #endif /* !YY_YY_SRC_PARSER_H_INCLUDED */ ================================================ FILE: src/parser.y ================================================ %{ #include #include #include #include #include "compile.h" #include "jv_alloc.h" #include "builtin.h" #define YYMALLOC jv_mem_alloc #define YYFREE jv_mem_free %} %code requires { #include "locfile.h" struct lexer_param; #define YYLTYPE location #define YYLLOC_DEFAULT(Loc, Rhs, N) \ do { \ if (N) { \ (Loc).start = YYRHSLOC(Rhs, 1).start; \ (Loc).end = YYRHSLOC(Rhs, N).end; \ } else { \ (Loc).start = YYRHSLOC(Rhs, 0).end; \ (Loc).end = YYRHSLOC(Rhs, 0).end; \ } \ } while (0) } %locations %define parse.error verbose %define api.pure %union { jv literal; block blk; } %destructor { jv_free($$); } %destructor { block_free($$); } %parse-param {block* answer} %parse-param {int* errors} %parse-param {struct locfile* locations} %parse-param {struct lexer_param* lexer_param_ptr} %lex-param {block* answer} %lex-param {int* errors} %lex-param {struct locfile* locations} %lex-param {struct lexer_param* lexer_param_ptr} %token INVALID_CHARACTER %token IDENT %token FIELD %token BINDING %token LITERAL %token FORMAT %token REC ".." %token SETMOD "%=" %token EQ "==" %token NEQ "!=" %token DEFINEDOR "//" %token AS "as" %token DEF "def" %token MODULE "module" %token IMPORT "import" %token INCLUDE "include" %token IF "if" %token THEN "then" %token ELSE "else" %token ELSE_IF "elif" %token REDUCE "reduce" %token FOREACH "foreach" %token END "end" %token AND "and" %token OR "or" %token TRY "try" %token CATCH "catch" %token LABEL "label" %token BREAK "break" %token LOC "$__loc__" %token SETPIPE "|=" %token SETPLUS "+=" %token SETMINUS "-=" %token SETMULT "*=" %token SETDIV "/=" %token SETDEFINEDOR "//=" %token LESSEQ "<=" %token GREATEREQ ">=" %token ALTERNATION "?//" %token QQSTRING_START %token QQSTRING_TEXT %token QQSTRING_INTERP_START %token QQSTRING_INTERP_END %token QQSTRING_END /* Instead of raising this, find a way to use precedence to resolve * shift-reduce conflicts. */ %expect 0 %precedence FUNCDEF %right '|' %left ',' %right "//" %nonassoc '=' SETPIPE SETPLUS SETMINUS SETMULT SETDIV SETMOD SETDEFINEDOR %left OR %left AND %nonassoc NEQ EQ '<' '>' LESSEQ GREATEREQ %left '+' '-' %left '*' '/' '%' %precedence NONOPT /* non-optional; rules for which a specialized '?' rule should be preferred over Expr '?' */ %precedence '?' '.' '[' FIELD %precedence "try" %precedence "catch" %type Query Expr Term %type DictPairs DictPair DictExpr %type ElseBody %type String QQString %type FuncDef FuncDefs %type Module Import Imports ImportWhat ImportFrom %type Param Params Arg Args %type Patterns RepPatterns Pattern ArrayPats ObjPats ObjPat %type Keyword %type StringStart %{ #include "lexer.h" struct lexer_param { yyscan_t lexer; }; #define FAIL(loc, msg) \ do { \ location l = loc; \ yyerror(&l, answer, errors, locations, lexer_param_ptr, msg); \ /*YYERROR*/; \ } while (0) void yyerror(YYLTYPE* loc, block* answer, int* errors, struct locfile* locations, struct lexer_param* lexer_param_ptr, const char *s){ (*errors)++; locfile_locate(locations, *loc, "jq: error: %s", s); } 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)); } else { FAIL(*yylloc, "Invalid literal"); } jv_free(msg); jv_free(yylval->literal); yylval->literal = jv_null(); } return tok; } /* Returns string message if the block is a constant that is not valid as an * object key. */ static jv check_object_key(block k) { if (block_is_const(k) && block_const_kind(k) != JV_KIND_STRING) { char errbuf[30]; return jv_string_fmt("Cannot use %s (%s) as object key", jv_kind_name(block_const_kind(k)), jv_dump_string_trunc(block_const(k), errbuf, sizeof(errbuf))); } return jv_invalid(); } 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) { block key = BLOCK(gen_subexp(gen_const(jv_object())), gen_subexp(gen_const(jv_string("start"))), gen_subexp(start), gen_op_simple(INSERT), gen_subexp(gen_const(jv_string("end"))), gen_subexp(end), gen_op_simple(INSERT)); return BLOCK(key, obj, gen_op_simple(idx_op)); } static block constant_fold(block a, block b, int op) { if (!block_is_single(a) || !block_is_const(a) || !block_is_single(b) || !block_is_const(b)) return gen_noop(); jv jv_a = block_const(a); block_free(a); jv jv_b = block_const(b); block_free(b); jv res = jv_invalid(); switch (op) { case '+': res = binop_plus(jv_a, jv_b); break; case '-': res = binop_minus(jv_a, jv_b); break; case '*': res = binop_multiply(jv_a, jv_b); break; case '/': res = binop_divide(jv_a, jv_b); break; case '%': res = binop_mod(jv_a, jv_b); break; case EQ: res = binop_equal(jv_a, jv_b); break; case NEQ: res = binop_notequal(jv_a, jv_b); break; case '<': res = binop_less(jv_a, jv_b); break; case '>': res = binop_greater(jv_a, jv_b); break; case LESSEQ: res = binop_lesseq(jv_a, jv_b); break; case GREATEREQ: res = binop_greatereq(jv_a, jv_b); break; } if (jv_is_valid(res)) return gen_const(res); return gen_error(jv_invalid_get_msg(res)); } static block gen_binop(block a, block b, int op) { block folded = constant_fold(a, b, op); if (!block_is_noop(folded)) return folded; const char* funcname = 0; switch (op) { case '+': funcname = "_plus"; break; 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; case '>': funcname = "_greater"; break; case LESSEQ: funcname = "_lesseq"; break; case GREATEREQ: funcname = "_greatereq"; break; } assert(funcname); return gen_call(funcname, BLOCK(gen_lambda(a), gen_lambda(b))); } static block gen_format(block a, jv fmt) { return BLOCK(a, gen_call("format", gen_lambda(gen_const(fmt)))); } static block gen_definedor_assign(block object, block val) { block tmp = gen_op_var_fresh(STOREV, "tmp"); 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)))))); } static block gen_update(block object, block val, int optype) { block tmp = gen_op_var_fresh(STOREV, "tmp"); 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), optype))))); } static block gen_loc_object(location *loc, struct locfile *locations) { return gen_const(JV_OBJECT(jv_string("file"), jv_copy(locations->fname), jv_string("line"), jv_number(locfile_get_line(locations, loc->start) + 1))); } %} %% TopLevel: Module Imports Query { *answer = BLOCK($1, $2, gen_op_simple(TOP), $3); } | Module Imports FuncDefs { *answer = BLOCK($1, $2, $3); } Module: %empty { $$ = gen_noop(); } | "module" Query ';' { if (!block_is_const($2)) { FAIL(@2, "Module metadata must be constant"); $$ = gen_noop(); block_free($2); } else if (block_const_kind($2) != JV_KIND_OBJECT) { FAIL(@2, "Module metadata must be an object"); $$ = gen_noop(); block_free($2); } else { $$ = gen_module($2); } } Imports: %empty { $$ = gen_noop(); } | Import Imports { $$ = BLOCK($1, $2); } FuncDefs: %empty { $$ = gen_noop(); } | FuncDef FuncDefs { $$ = block_join($1, $2); } Query: FuncDef Query %prec FUNCDEF { $$ = block_bind_referenced($1, $2, OP_IS_CALL_PSEUDO); } | Expr "as" Patterns '|' Query { $$ = gen_destructure($1, $3, $5); } | "label" BINDING '|' Query { jv v = jv_string_fmt("*label-%s", jv_string_value($2)); $$ = gen_location(@$, locations, gen_label(jv_string_value(v), $4)); jv_free($2); jv_free(v); } | Query '|' Query { $$ = block_join($1, $3); } | Query ',' Query { $$ = gen_both($1, $3); } | Expr { $$ = $1; } Expr: Expr "//" Expr { $$ = gen_definedor($1, $3); } | Expr '=' Expr { $$ = gen_call("_assign", BLOCK(gen_lambda($1), gen_lambda($3))); } | Expr "or" Expr { $$ = gen_or($1, $3); } | Expr "and" Expr { $$ = gen_and($1, $3); } | Expr "//=" Expr { $$ = gen_definedor_assign($1, $3); } | Expr "|=" Expr { $$ = gen_call("_modify", BLOCK(gen_lambda($1), gen_lambda($3))); } | Expr '+' Expr { $$ = gen_binop($1, $3, '+'); } | Expr "+=" Expr { $$ = gen_update($1, $3, '+'); } | Expr '-' Expr { $$ = gen_binop($1, $3, '-'); } | Expr "-=" Expr { $$ = gen_update($1, $3, '-'); } | Expr '*' Expr { $$ = gen_binop($1, $3, '*'); } | Expr "*=" Expr { $$ = gen_update($1, $3, '*'); } | Expr '/' Expr { $$ = gen_binop($1, $3, '/'); } | Expr '%' Expr { $$ = gen_binop($1, $3, '%'); } | Expr "/=" Expr { $$ = gen_update($1, $3, '/'); } | Expr SETMOD Expr { $$ = gen_update($1, $3, '%'); } | Expr "==" Expr { $$ = gen_binop($1, $3, EQ); } | Expr "!=" Expr { $$ = gen_binop($1, $3, NEQ); } | Expr '<' Expr { $$ = gen_binop($1, $3, '<'); } | Expr '>' Expr { $$ = gen_binop($1, $3, '>'); } | Expr "<=" Expr { $$ = gen_binop($1, $3, LESSEQ); } | Expr ">=" Expr { $$ = gen_binop($1, $3, GREATEREQ); } | Term %prec NONOPT { $$ = $1; } Import: ImportWhat ';' { $$ = $1; } | ImportWhat Query ';' { if (!block_is_const($2)) { FAIL(@2, "Module metadata must be constant"); $$ = gen_noop(); block_free($1); block_free($2); } else if (block_const_kind($2) != JV_KIND_OBJECT) { FAIL(@2, "Module metadata must be an object"); $$ = gen_noop(); block_free($1); block_free($2); } else { $$ = gen_import_meta($1, $2); } } ImportWhat: "import" ImportFrom "as" BINDING { jv v = block_const($2); // XXX Make gen_import take only blocks and the int is_data so we // don't have to free so much stuff here $$ = gen_import(jv_string_value(v), jv_string_value($4), 1); block_free($2); jv_free($4); jv_free(v); } | "import" ImportFrom "as" IDENT { jv v = block_const($2); $$ = gen_import(jv_string_value(v), jv_string_value($4), 0); block_free($2); jv_free($4); jv_free(v); } | "include" ImportFrom { jv v = block_const($2); $$ = gen_import(jv_string_value(v), NULL, 0); block_free($2); jv_free(v); } ImportFrom: String { if (!block_is_const($1)) { FAIL(@1, "Import path must be constant"); $$ = gen_const(jv_string("")); block_free($1); } else { $$ = $1; } } FuncDef: "def" IDENT ':' Query ';' { $$ = gen_function(jv_string_value($2), gen_noop(), $4); jv_free($2); } | "def" IDENT '(' Params ')' ':' Query ';' { $$ = gen_function(jv_string_value($2), $4, $7); jv_free($2); } Params: Param { $$ = $1; } | Params ';' Param { $$ = BLOCK($1, $3); } Param: BINDING { $$ = gen_param_regular(jv_string_value($1)); jv_free($1); } | IDENT { $$ = gen_param(jv_string_value($1)); jv_free($1); } StringStart: FORMAT QQSTRING_START { $$ = $1; } | QQSTRING_START { $$ = jv_string("text"); } String: StringStart QQString QQSTRING_END { $$ = $2; jv_free($1); }; QQString: %empty { $$ = gen_const(jv_string("")); } | QQString QQSTRING_TEXT { $$ = gen_binop($1, gen_const($2), '+'); } | QQString QQSTRING_INTERP_START Query QQSTRING_INTERP_END { $$ = gen_binop($1, gen_format($3, jv_copy($0)), '+'); } ElseBody: "elif" Query "then" Query ElseBody { $$ = gen_cond($2, $4, $5); } | "else" Query "end" { $$ = $2; } | "end" { $$ = gen_noop(); } Term: '.' { $$ = gen_noop(); } | REC { $$ = gen_call("recurse", gen_noop()); } | BREAK BINDING { jv v = jv_string_fmt("*label-%s", jv_string_value($2)); // impossible symbol $$ = gen_location(@$, locations, BLOCK(gen_op_unbound(LOADV, jv_string_value(v)), gen_call("error", gen_noop()))); jv_free(v); jv_free($2); } | BREAK error { FAIL(@$, "break requires a label to break to"); $$ = gen_noop(); } | Term FIELD '?' { $$ = gen_index_opt($1, 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 %prec NONOPT { $$ = gen_index($1, gen_const($2)); } | FIELD %prec NONOPT { $$ = gen_index(gen_noop(), gen_const($1)); } | Term '.' String %prec NONOPT { $$ = gen_index($1, $3); } | '.' String %prec NONOPT { $$ = 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 '[' Query ']' '?' { $$ = gen_index_opt($1, $3); } | Term '[' Query ']' %prec NONOPT { $$ = gen_index($1, $3); } | Term '.' '[' Query ']' '?' { $$ = gen_index_opt($1, $4); } | Term '.' '[' Query ']' %prec NONOPT { $$ = gen_index($1, $4); } | Term '[' ']' '?' { $$ = block_join($1, gen_op_simple(EACH_OPT)); } | Term '[' ']' %prec NONOPT { $$ = block_join($1, gen_op_simple(EACH)); } | Term '.' '[' ']' '?' { $$ = block_join($1, gen_op_simple(EACH_OPT)); } | Term '.' '[' ']' %prec NONOPT { $$ = block_join($1, gen_op_simple(EACH)); } | Term '[' Query ':' Query ']' '?' { $$ = gen_slice_index($1, $3, $5, INDEX_OPT); } | Term '[' Query ':' ']' '?' { $$ = gen_slice_index($1, $3, gen_const(jv_null()), INDEX_OPT); } | Term '[' ':' Query ']' '?' { $$ = gen_slice_index($1, gen_const(jv_null()), $4, INDEX_OPT); } | Term '[' Query ':' Query ']' %prec NONOPT { $$ = gen_slice_index($1, $3, $5, INDEX); } | Term '[' Query ':' ']' %prec NONOPT { $$ = gen_slice_index($1, $3, gen_const(jv_null()), INDEX); } | Term '[' ':' Query ']' %prec NONOPT { $$ = gen_slice_index($1, gen_const(jv_null()), $4, INDEX); } | Term '?' { $$ = gen_try($1, gen_op_simple(BACKTRACK)); } | LITERAL { $$ = gen_const($1); } | String { $$ = $1; } | FORMAT { $$ = gen_format(gen_noop(), $1); } | '-' Term { $$ = BLOCK($2, gen_call("_negate", gen_noop())); } | '(' Query ')' { $$ = $2; } | '[' Query ']' { $$ = gen_collect($2); } | '[' ']' { $$ = gen_const(jv_array()); } | '{' DictPairs '}' { block o = gen_const_object($2); if (o.first != NULL) $$ = o; else $$ = BLOCK(gen_subexp(gen_const(jv_object())), $2, gen_op_simple(POP)); } | "reduce" Expr "as" Patterns '(' Query ';' Query ')' { $$ = gen_reduce($2, $4, $6, $8); } | "foreach" Expr "as" Patterns '(' Query ';' Query ';' Query ')' { $$ = gen_foreach($2, $4, $6, $8, $10); } | "foreach" Expr "as" Patterns '(' Query ';' Query ')' { $$ = gen_foreach($2, $4, $6, $8, gen_noop()); } | "if" Query "then" Query ElseBody { $$ = gen_cond($2, $4, $5); } | "if" Query "then" error { FAIL(@$, "Possibly unterminated 'if' statement"); $$ = $2; } | "try" Expr "catch" Expr { $$ = gen_try($2, $4); } | "try" Expr "catch" error { FAIL(@$, "Possibly unterminated 'try' statement"); $$ = $2; } | "try" Expr { $$ = gen_try($2, gen_op_simple(BACKTRACK)); } | /* * This `$$$$varname` hack is strictly private to jq builtins. DO NOT USE!! * * This is used in `_modify`, in src/builtin.jq, to avoid holding on to a * reference to `.`. * * We could just have the compiler emit bytecode for `_modify` so it can use * LOADVN w/o needing jq syntax for LOADVN. * * This syntax, `$$$$varname`, violates referential transparency: it has * side-effects that are surprising. * * DO NOT USE!! I will break your jq code if you do use this outside * src/builtin.jq. */ '$' '$' '$' BINDING { $$ = gen_location(@$, locations, gen_op_unbound(LOADVN, jv_string_value($4))); jv_free($4); } | BINDING { $$ = gen_location(@$, locations, gen_op_unbound(LOADV, jv_string_value($1))); jv_free($1); } | "$__loc__" { $$ = gen_loc_object(&@$, locations); } | IDENT { const char *s = jv_string_value($1); if (strcmp(s, "false") == 0) $$ = gen_const(jv_false()); else if (strcmp(s, "true") == 0) $$ = gen_const(jv_true()); else if (strcmp(s, "null") == 0) $$ = gen_const(jv_null()); else $$ = gen_location(@$, locations, gen_call(s, gen_noop())); jv_free($1); } | IDENT '(' Args ')' { $$ = gen_call(jv_string_value($1), $3); $$ = gen_location(@1, locations, $$); jv_free($1); } | '(' error ')' { $$ = gen_noop(); } | '[' error ']' { $$ = gen_noop(); } | Term '[' error ']' { $$ = $1; } | '{' error '}' { $$ = gen_noop(); } Args: Arg { $$ = $1; } | Args ';' Arg { $$ = BLOCK($1, $3); } Arg: Query { $$ = gen_lambda($1); } RepPatterns: RepPatterns "?//" Pattern { $$ = BLOCK($1, gen_destructure_alt($3)); } | Pattern { $$ = gen_destructure_alt($1); } Patterns: RepPatterns "?//" Pattern { $$ = BLOCK($1, $3); } | Pattern { $$ = $1; } Pattern: BINDING { $$ = gen_op_unbound(STOREV, jv_string_value($1)); jv_free($1); } | '[' ArrayPats ']' { $$ = BLOCK($2, gen_op_simple(POP)); } | '{' ObjPats '}' { $$ = BLOCK($2, gen_op_simple(POP)); } ArrayPats: Pattern { $$ = gen_array_matcher(gen_noop(), $1); } | ArrayPats ',' Pattern { $$ = gen_array_matcher($1, $3); } ObjPats: ObjPat { $$ = $1; } | ObjPats ',' ObjPat { $$ = BLOCK($1, $3); } ObjPat: BINDING { $$ = gen_object_matcher(gen_const($1), gen_op_unbound(STOREV, jv_string_value($1))); } | BINDING ':' Pattern { $$ = gen_object_matcher(gen_const($1), BLOCK(gen_op_simple(DUP), gen_op_unbound(STOREV, jv_string_value($1)), $3)); } | IDENT ':' Pattern { $$ = gen_object_matcher(gen_const($1), $3); } | Keyword ':' Pattern { $$ = gen_object_matcher(gen_const($1), $3); } | String ':' Pattern { $$ = gen_object_matcher($1, $3); } | '(' Query ')' ':' Pattern { jv msg = check_object_key($2); if (jv_is_valid(msg)) { FAIL(@2, jv_string_value(msg)); } jv_free(msg); $$ = gen_object_matcher($2, $5); } | error ':' Pattern { FAIL(@$, "May need parentheses around object key expression"); $$ = $3; } Keyword: "as" { $$ = jv_string("as"); } | "def" { $$ = jv_string("def"); } | "module" { $$ = jv_string("module"); } | "import" { $$ = jv_string("import"); } | "include" { $$ = jv_string("include"); } | "if" { $$ = jv_string("if"); } | "then" { $$ = jv_string("then"); } | "else" { $$ = jv_string("else"); } | "elif" { $$ = jv_string("elif"); } | "reduce" { $$ = jv_string("reduce"); } | "foreach" { $$ = jv_string("foreach"); } | "end" { $$ = jv_string("end"); } | "and" { $$ = jv_string("and"); } | "or" { $$ = jv_string("or"); } | "try" { $$ = jv_string("try"); } | "catch" { $$ = jv_string("catch"); } | "label" { $$ = jv_string("label"); } | "break" { $$ = jv_string("break"); } DictPairs: %empty { $$ = gen_noop(); } | DictPair { $$ = $1; } | DictPair ',' DictPairs { $$ = block_join($1, $3); } DictPair: IDENT ':' DictExpr { $$ = gen_dictpair(gen_const($1), $3); } | Keyword ':' DictExpr { $$ = gen_dictpair(gen_const($1), $3); } | String ':' DictExpr { $$ = gen_dictpair($1, $3); } | String { $$ = gen_dictpair($1, BLOCK(gen_op_simple(POP), gen_op_simple(DUP2), gen_op_simple(DUP2), gen_op_simple(INDEX))); } | BINDING ':' DictExpr { $$ = gen_dictpair(gen_location(@$, locations, gen_op_unbound(LOADV, jv_string_value($1))), $3); jv_free($1); } | BINDING { $$ = gen_dictpair(gen_const($1), gen_location(@$, locations, gen_op_unbound(LOADV, jv_string_value($1)))); } | IDENT { $$ = gen_dictpair(gen_const(jv_copy($1)), gen_index(gen_noop(), gen_const($1))); } | "$__loc__" { $$ = gen_dictpair(gen_const(jv_string("__loc__")), gen_loc_object(&@$, locations)); } | Keyword { $$ = gen_dictpair(gen_const(jv_copy($1)), gen_index(gen_noop(), gen_const($1))); } | '(' Query ')' ':' DictExpr { jv msg = check_object_key($2); if (jv_is_valid(msg)) { FAIL(@2, jv_string_value(msg)); } jv_free(msg); $$ = gen_dictpair($2, $5); } | error ':' DictExpr { FAIL(@1, "May need parentheses around object key expression"); $$ = $3; } DictExpr: DictExpr '|' DictExpr { $$ = block_join($1, $3); } | Expr { $$ = $1; } %% int jq_parse(struct locfile* locations, block* answer) { struct lexer_param scanner; YY_BUFFER_STATE buf; jq_yylex_init_extra(0, &scanner.lexer); buf = jq_yy_scan_bytes(locations->data, locations->length, scanner.lexer); int errors = 0; *answer = gen_noop(); yyparse(answer, &errors, locations, &scanner); jq_yy_delete_buffer(buf, scanner.lexer); jq_yylex_destroy(scanner.lexer); if (errors > 0) { block_free(*answer); *answer = gen_noop(); } return errors; } int jq_parse_library(struct locfile* locations, block* answer) { int errs = jq_parse(locations, answer); if (errs) return errs; if (block_has_main(*answer)) { locfile_locate(locations, UNKNOWN_LOCATION, "jq: error: library should only have function definitions, not a main expression"); return 1; } assert(block_has_only_binders_and_imports(*answer, OP_IS_CALL_PSEUDO)); return 0; } ================================================ FILE: src/util.c ================================================ /*- * Parts (strptime()) Copyright (c) 1997, 1998, 2005, 2008 The NetBSD Foundation, Inc. * All rights reserved. * * This code was contributed to The NetBSD Foundation by Klaus Klein. * Heavily optimised by David Laight * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #include #include #include #include #include #include #include #include #include #include #ifdef HAVE_ALLOCA_H # include #elif !defined alloca # ifdef __GNUC__ # define alloca __builtin_alloca # elif defined _MSC_VER # include # define alloca _alloca # elif !defined HAVE_ALLOCA # ifdef __cplusplus extern "C" # endif void *alloca (size_t); # endif #endif #ifdef WIN32 #include #include #include #include #include #endif #include "util.h" #include "jq.h" #include "jv_alloc.h" #include "jv_unicode.h" #ifdef WIN32 FILE *fopen(const char *fname, const char *mode) { size_t sz = sizeof(wchar_t) * MultiByteToWideChar(CP_UTF8, 0, fname, -1, NULL, 0); wchar_t *wfname = alloca(sz + 2); // +2 is not needed, but just in case MultiByteToWideChar(CP_UTF8, 0, fname, -1, wfname, sz); sz = sizeof(wchar_t) * MultiByteToWideChar(CP_UTF8, 0, mode, -1, NULL, 0); wchar_t *wmode = alloca(sz + 2); // +2 is not needed, but just in case MultiByteToWideChar(CP_UTF8, 0, mode, -1, wmode, sz); return _wfopen(wfname, wmode); } #endif jv expand_path(jv path) { assert(jv_get_kind(path) == JV_KIND_STRING); const char *pstr = jv_string_value(path); jv ret = path; if (jv_string_length_bytes(jv_copy(path)) > 1 && pstr[0] == '~' && pstr[1] == '/') { jv home = get_home(); if (jv_is_valid(home)) { ret = jv_string_fmt("%s/%s",jv_string_value(home),pstr+2); jv_free(home); } else { jv emsg = jv_invalid_get_msg(home); ret = jv_invalid_with_msg(jv_string_fmt("Could not expand %s. (%s)", pstr, jv_string_value(emsg))); jv_free(emsg); } jv_free(path); } return ret; } jv get_home(void) { jv ret; char *home = getenv("HOME"); if (!home) { #ifndef WIN32 ret = jv_invalid_with_msg(jv_string("Could not find home directory.")); #else home = getenv("USERPROFILE"); if (!home) { home = getenv("HOMEPATH"); if (!home) { ret = jv_invalid_with_msg(jv_string("Could not find home directory.")); } else { const char *hd = getenv("HOMEDRIVE"); if (!hd) hd = ""; ret = jv_string_fmt("%s%s",hd,home); } } else { ret = jv_string(home); } #endif } else { ret = jv_string(home); } return ret; } jv jq_realpath(jv path) { int path_max; char *buf = NULL; #ifdef _PC_PATH_MAX path_max = pathconf(jv_string_value(path),_PC_PATH_MAX); #else path_max = PATH_MAX; #endif if (path_max > 0) { buf = jv_mem_alloc(path_max); } #ifdef WIN32 char *tmp = _fullpath(buf, jv_string_value(path), path_max); #else char *tmp = realpath(jv_string_value(path), buf); #endif if (tmp == NULL) { free(buf); return path; } jv_free(path); path = jv_string(tmp); free(tmp); return path; } const void *_jq_memmem(const void *haystack, size_t haystacklen, const void *needle, size_t needlelen) { #ifdef HAVE_MEMMEM return (const void*)memmem(haystack, haystacklen, needle, needlelen); #else const char *h = haystack; const char *n = needle; size_t hi, hi2, ni; if (haystacklen < needlelen || haystacklen == 0) return NULL; for (hi = 0; hi < (haystacklen - needlelen + 1); hi++) { for (ni = 0, hi2 = hi; ni < needlelen; ni++, hi2++) { if (h[hi2] != n[ni]) goto not_this; } return &h[hi]; not_this: continue; } return NULL; #endif /* !HAVE_MEMMEM */ } struct jq_util_input_state { jq_util_msg_cb err_cb; void *err_cb_data; jv_parser *parser; FILE* current_input; char **files; int nfiles; int curr_file; int failures; jv slurped; char buf[4096]; size_t buf_valid_len; jv current_filename; size_t current_line; }; static void fprinter(void *data, const char *fname) { fprintf((FILE *)data, "jq: error: Could not open file %s: %s\n", fname, strerror(errno)); } // If parser == NULL -> RAW jq_util_input_state *jq_util_input_init(jq_util_msg_cb err_cb, void *err_cb_data) { if (err_cb == NULL) { err_cb = fprinter; err_cb_data = stderr; } jq_util_input_state *new_state = jv_mem_calloc(1, sizeof(*new_state)); new_state->err_cb = err_cb; new_state->err_cb_data = err_cb_data; new_state->slurped = jv_invalid(); new_state->current_filename = jv_invalid(); return new_state; } void jq_util_input_set_parser(jq_util_input_state *state, jv_parser *parser, int slurp) { assert(!jv_is_valid(state->slurped)); state->parser = parser; if (parser == NULL && slurp) state->slurped = jv_string(""); else if (slurp) state->slurped = jv_array(); else state->slurped = jv_invalid(); } void jq_util_input_free(jq_util_input_state **state) { jq_util_input_state *old_state = *state; *state = NULL; if (old_state == NULL) return; if (old_state->parser != NULL) jv_parser_free(old_state->parser); for (int i = 0; i < old_state->nfiles; i++) free(old_state->files[i]); free(old_state->files); jv_free(old_state->slurped); jv_free(old_state->current_filename); jv_mem_free(old_state); } void jq_util_input_add_input(jq_util_input_state *state, const char *fname) { state->files = jv_mem_realloc(state->files, (state->nfiles + 1) * sizeof(state->files[0])); state->files[state->nfiles++] = jv_mem_strdup(fname); } int jq_util_input_errors(jq_util_input_state *state) { return state->failures; } static const char *next_file(jq_util_input_state *state) { if (state->curr_file < state->nfiles) return state->files[state->curr_file++]; return NULL; } static int jq_util_input_read_more(jq_util_input_state *state) { if (!state->current_input || feof(state->current_input) || ferror(state->current_input)) { if (state->current_input && ferror(state->current_input)) { // System-level input error on the stream. It will be closed (below). // TODO: report it. Can't use 'state->err_cb()' as it is hard-coded for // 'open' related problems. fprintf(stderr,"jq: error: %s\n", strerror(errno)); } if (state->current_input) { if (state->current_input == stdin) { clearerr(stdin); // perhaps we can read again; anyways, we don't fclose(stdin) } else { fclose(state->current_input); } state->current_input = NULL; } const char *f = next_file(state); if (f != NULL) { jv_free(state->current_filename); state->current_line = 0; if (!strcmp(f, "-")) { state->current_input = stdin; state->current_filename = jv_string(""); } else { state->current_input = fopen(f, "r"); state->current_filename = jv_string(f); if (!state->current_input) { state->err_cb(state->err_cb_data, f); state->failures++; } } } } state->buf[0] = 0; state->buf_valid_len = 0; if (state->current_input) { char *res; memset(state->buf, 0xff, sizeof(state->buf)); const int max_utf8_len = 4; const int max_gets_len = sizeof(state->buf) - max_utf8_len; while (!(res = fgets(state->buf, max_gets_len, state->current_input)) && ferror(state->current_input) && errno == EINTR) clearerr(state->current_input); if (res == NULL) { state->buf[0] = 0; if (ferror(state->current_input)) state->failures++; } else { const char *p = memchr(state->buf, '\n', max_gets_len); if (p != NULL) state->current_line++; if (p == NULL && state->parser != NULL) { /* * There should be no NULs in JSON texts (but JSON text * sequences are another story). */ state->buf_valid_len = strlen(state->buf); } else if (p == NULL && feof(state->current_input)) { size_t i; /* * XXX We don't know how many bytes we've read! * * We can't use getline() because there need not be any newlines * in the input. The only entirely correct choices are: use * fgetc() or fread(). Using fread() will complicate buffer * management here. * * For now we check how much fgets() read by scanning backwards for the * terminating '\0'. This only works because we previously memset our * buffer with something nonzero. */ for (i = max_gets_len - 1; i > 0; i--) { if (state->buf[i] == '\0') break; } state->buf_valid_len = i; } else if (p == NULL) { state->buf_valid_len = max_gets_len - 1; char *end = state->buf + state->buf_valid_len; int len = 0; if (jvp_utf8_backtrack(end - 1, state->buf, &len) && len > 0) { state->buf_valid_len += fread(end, 1, len, state->current_input); } } else { state->buf_valid_len = (p - state->buf) + 1; } } } return state->curr_file == state->nfiles && !state->current_input; } jv jq_util_input_next_input_cb(jq_state *jq, void *data) { return jq_util_input_next_input((jq_util_input_state *)data); } // Return the current_filename:current_line jv jq_util_input_get_position(jq_state *jq) { jq_input_cb cb = NULL; void *cb_data = NULL; jq_get_input_cb(jq, &cb, &cb_data); assert(cb == jq_util_input_next_input_cb); if (cb != jq_util_input_next_input_cb) return jv_invalid_with_msg(jv_string("Invalid jq_util_input API usage")); jq_util_input_state *s = (jq_util_input_state *)cb_data; // We can't assert that current_filename is a string because if // the error was a JSON parser error then we may not have set // current_filename yet. if (jv_get_kind(s->current_filename) != JV_KIND_STRING) return jv_string(""); jv v = jv_string_fmt("%s:%lu", jv_string_value(s->current_filename), (unsigned long)s->current_line); return v; } jv jq_util_input_get_current_filename(jq_state* jq) { jq_input_cb cb=NULL; void *cb_data=NULL; jq_get_input_cb(jq, &cb, &cb_data); if (cb != jq_util_input_next_input_cb) return jv_invalid_with_msg(jv_string("Unknown input filename")); jq_util_input_state *s = (jq_util_input_state *)cb_data; jv v = jv_copy(s->current_filename); return v; } jv jq_util_input_get_current_line(jq_state* jq) { jq_input_cb cb=NULL; void *cb_data=NULL; jq_get_input_cb(jq, &cb, &cb_data); if (cb != jq_util_input_next_input_cb) return jv_invalid_with_msg(jv_string("Unknown input line number")); jq_util_input_state *s = (jq_util_input_state *)cb_data; jv v = jv_number(s->current_line); return v; } // Blocks to read one more input from stdin and/or given files // When slurping, it returns just one value jv jq_util_input_next_input(jq_util_input_state *state) { int is_last = 0; jv value = jv_invalid(); // need more input do { if (state->parser == NULL) { // Raw input is_last = jq_util_input_read_more(state); if (state->buf_valid_len == 0) continue; if (jv_is_valid(state->slurped)) { // Slurped raw input state->slurped = jv_string_concat(state->slurped, jv_string_sized(state->buf, state->buf_valid_len)); } else { if (!jv_is_valid(value)) value = jv_string(""); if (state->buf[state->buf_valid_len-1] == '\n') { // whole line state->buf[state->buf_valid_len-1] = 0; return jv_string_concat(value, jv_string_sized(state->buf, state->buf_valid_len-1)); } value = jv_string_concat(value, jv_string_sized(state->buf, state->buf_valid_len)); state->buf[0] = '\0'; state->buf_valid_len = 0; } } else { if (jv_parser_remaining(state->parser) == 0) { is_last = jq_util_input_read_more(state); jv_parser_set_buf(state->parser, state->buf, state->buf_valid_len, !is_last); } value = jv_parser_next(state->parser); if (jv_is_valid(state->slurped)) { if (jv_is_valid(value)) { state->slurped = jv_array_append(state->slurped, value); value = jv_invalid(); } else if (jv_invalid_has_msg(jv_copy(value))) return value; // Not slurped parsed input } else if (jv_is_valid(value) || jv_invalid_has_msg(jv_copy(value))) { return value; } } } while (!is_last); if (jv_is_valid(state->slurped)) { value = state->slurped; state->slurped = jv_invalid(); } return value; } #ifndef HAVE_STRPTIME /* http://cvsweb.netbsd.org/bsdweb.cgi/~checkout~/src/lib/libc/time/strptime.c?only_with_tag=HEAD * NetBSD implementation strptime(). * Format description: https://netbsd.gw.com/cgi-bin/man-cgi?strptime+3+NetBSD-current * Adapted by https://github.com/res2001 (https://github.com/res2001/strptime). */ #include #include #include #include static const unsigned char *conv_num(const unsigned char *, int *, unsigned int, unsigned int); static const unsigned char *find_string(const unsigned char *, int *, const char * const *, const char * const *, int); /* * We do not implement alternate representations. However, we always * check whether a given modifier is allowed for a certain conversion. */ #define ALT_E 0x01 #define ALT_O 0x02 #define LEGAL_ALT(x) { if (alt_format & ~(x)) return NULL; } #define TM_YEAR_BASE 1900 #define TM_SUNDAY 0 #define TM_MONDAY 1 #define TM_TUESDAY 2 #define TM_WEDNESDAY 3 #define TM_THURSDAY 4 #define TM_FRIDAY 5 #define TM_SATURDAY 6 #define S_YEAR (1 << 0) #define S_MON (1 << 1) #define S_YDAY (1 << 2) #define S_MDAY (1 << 3) #define S_WDAY (1 << 4) #define S_HOUR (1 << 5) #define HAVE_MDAY(s) (s & S_MDAY) #define HAVE_MON(s) (s & S_MON) #define HAVE_WDAY(s) (s & S_WDAY) #define HAVE_YDAY(s) (s & S_YDAY) #define HAVE_YEAR(s) (s & S_YEAR) #define HAVE_HOUR(s) (s & S_HOUR) #define SECSPERMIN 60 #define MINSPERHOUR 60 #define SECSPERHOUR (SECSPERMIN * MINSPERHOUR) #define HOURSPERDAY 24 #define HERE_D_T_FMT "%a %b %e %H:%M:%S %Y" #define HERE_D_FMT "%y/%m/%d" #define HERE_T_FMT_AMPM "%I:%M:%S %p" #define HERE_T_FMT "%H:%M:%S" #define isleap(y) (((y) % 4) == 0 && (((y) % 100) != 0 || ((y) % 400) == 0)) /* ** Since everything in isleap is modulo 400 (or a factor of 400), we know that ** isleap(y) == isleap(y % 400) ** and so ** isleap(a + b) == isleap((a + b) % 400) ** or ** isleap(a + b) == isleap(a % 400 + b % 400) ** This is true even if % means modulo rather than Fortran remainder ** (which is allowed by C89 but not by C99 or later). ** We use this to avoid addition overflow problems. */ #define isleap_sum(a, b) isleap((a) % 400 + (b) % 400) #ifdef _MSC_VER #define tzname _tzname #define strncasecmp _strnicmp #endif #ifdef TM_ZONE static char* utc = "UTC"; #endif /* RFC-822/RFC-2822 */ static const char *const nast[] = { "EST", "CST", "MST", "PST", "\0\0\0" }; static const char *const nadt[] = { "EDT", "CDT", "MDT", "PDT", "\0\0\0" }; static const char *const weekday_name[] = { "Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday" }; static const char *const ab_weekday_name[] = { "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" }; static const char *const month_name[] = { "January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December" }; static const char *const ab_month_name[] = { "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" }; static const char *const am_pm[] = {"AM", "PM"}; /* * Table to determine the ordinal date for the start of a month. * Ref: http://en.wikipedia.org/wiki/ISO_week_date */ static const int start_of_month[2][13] = { /* non-leap year */ { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365 }, /* leap year */ { 0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335, 366 } }; /* * Calculate the week day of the first day of a year. Valid for * the Gregorian calendar, which began Sept 14, 1752 in the UK * and its colonies. Ref: * http://en.wikipedia.org/wiki/Determination_of_the_day_of_the_week */ static int first_wday_of(int yr) { return ((2 * (3 - (yr / 100) % 4)) + (yr % 100) + ((yr % 100) / 4) + (isleap(yr) ? 6 : 0) + 1) % 7; } #define delim(p) ((p) == '\0' || isspace((unsigned char)(p))) static int fromzone(const unsigned char **bp, struct tm *tm, int mandatory) { // timezone_t tz; char buf[512], *p; const unsigned char *rp; for (p = buf, rp = *bp; !delim(*rp) && p < &buf[sizeof(buf) - 1]; rp++) *p++ = *rp; *p = '\0'; if (mandatory) *bp = rp; if (!isalnum((unsigned char)*buf)) return 0; // tz = tzalloc(buf); // if (tz == NULL) // return 0; *bp = rp; tm->tm_isdst = 0; /* XXX */ #ifdef TM_GMTOFF tm->TM_GMTOFF = tzgetgmtoff(tz, tm->tm_isdst); #endif #ifdef TM_ZONE // Can't use tzgetname() here because we are going to free() tm->TM_ZONE = NULL; /* XXX */ #endif // tzfree(tz); return 1; } char* strptime(const char *buf, const char *fmt, struct tm *tm) { unsigned char c; const unsigned char *bp, *ep, *zname; int alt_format, i, split_year = 0, neg = 0, state = 0, day_offset = -1, week_offset = 0, offs, mandatory; const char *new_fmt; bp = (const unsigned char *)buf; while (bp != NULL && (c = *fmt++) != '\0') { /* Clear `alternate' modifier prior to new conversion. */ alt_format = 0; i = 0; /* Eat up white-space. */ if (isspace(c)) { while (isspace(*bp)) bp++; continue; } if (c != '%') goto literal; again: switch (c = *fmt++) { case '%': /* "%%" is converted to "%". */ literal: if (c != *bp++) return NULL; LEGAL_ALT(0); continue; /* * "Alternative" modifiers. Just set the appropriate flag * and start over again. */ case 'E': /* "%E?" alternative conversion modifier. */ LEGAL_ALT(0); alt_format |= ALT_E; goto again; case 'O': /* "%O?" alternative conversion modifier. */ LEGAL_ALT(0); alt_format |= ALT_O; goto again; /* * "Complex" conversion rules, implemented through recursion. */ case 'c': /* Date and time, using the locale's format. */ // new_fmt = _TIME_LOCALE(loc)->d_t_fmt; new_fmt = HERE_D_T_FMT; state |= S_WDAY | S_MON | S_MDAY | S_YEAR; goto recurse; case 'F': /* The date as "%Y-%m-%d". */ new_fmt = "%Y-%m-%d"; LEGAL_ALT(0); state |= S_MON | S_MDAY | S_YEAR; goto recurse; case 'R': /* The time as "%H:%M". */ new_fmt = "%H:%M"; LEGAL_ALT(0); goto recurse; case 'r': /* The time in 12-hour clock representation. */ // new_fmt = _TIME_LOCALE(loc)->t_fmt_ampm; new_fmt = HERE_T_FMT_AMPM; LEGAL_ALT(0); goto recurse; case 'X': /* The time, using the locale's format. */ /* fall through */ case 'T': /* The time as "%H:%M:%S". */ new_fmt = HERE_T_FMT; LEGAL_ALT(0); recurse: bp = (const unsigned char *)strptime((const char *)bp, new_fmt, tm); LEGAL_ALT(ALT_E); continue; case 'x': /* The date, using the locale's format. */ /* fall through */ case 'D': /* The date as "%y/%m/%d". */ { new_fmt = HERE_D_FMT; LEGAL_ALT(0); state |= S_MON | S_MDAY | S_YEAR; const int year = split_year ? tm->tm_year : 0; bp = (const unsigned char *)strptime((const char *)bp, new_fmt, tm); LEGAL_ALT(ALT_E); tm->tm_year += year; if (split_year && tm->tm_year % (2000 - TM_YEAR_BASE) <= 68) tm->tm_year -= 2000 - TM_YEAR_BASE; split_year = 1; continue; } /* * "Elementary" conversion rules. */ case 'A': /* The day of week, using the locale's form. */ case 'a': bp = find_string(bp, &tm->tm_wday, weekday_name, ab_weekday_name, 7); LEGAL_ALT(0); state |= S_WDAY; continue; case 'B': /* The month, using the locale's form. */ case 'b': case 'h': bp = find_string(bp, &tm->tm_mon, month_name, ab_month_name, 12); LEGAL_ALT(0); state |= S_MON; continue; case 'C': /* The century number. */ i = 20; bp = conv_num(bp, &i, 0, 99); i = i * 100 - TM_YEAR_BASE; if (split_year) i += tm->tm_year % 100; split_year = 1; tm->tm_year = i; LEGAL_ALT(ALT_E); state |= S_YEAR; continue; case 'd': /* The day of month. */ case 'e': bp = conv_num(bp, &tm->tm_mday, 1, 31); LEGAL_ALT(ALT_O); state |= S_MDAY; continue; case 'k': /* The hour (24-hour clock representation). */ LEGAL_ALT(0); /* FALLTHROUGH */ case 'H': bp = conv_num(bp, &tm->tm_hour, 0, 23); LEGAL_ALT(ALT_O); state |= S_HOUR; continue; case 'l': /* The hour (12-hour clock representation). */ LEGAL_ALT(0); /* FALLTHROUGH */ case 'I': bp = conv_num(bp, &tm->tm_hour, 1, 12); if (tm->tm_hour == 12) tm->tm_hour = 0; LEGAL_ALT(ALT_O); state |= S_HOUR; continue; case 'j': /* The day of year. */ i = 1; bp = conv_num(bp, &i, 1, 366); tm->tm_yday = i - 1; LEGAL_ALT(0); state |= S_YDAY; continue; case 'M': /* The minute. */ bp = conv_num(bp, &tm->tm_min, 0, 59); LEGAL_ALT(ALT_O); continue; case 'm': /* The month. */ i = 1; bp = conv_num(bp, &i, 1, 12); tm->tm_mon = i - 1; LEGAL_ALT(ALT_O); state |= S_MON; continue; case 'p': /* The locale's equivalent of AM/PM. */ bp = find_string(bp, &i, am_pm, NULL, 2); if (HAVE_HOUR(state) && tm->tm_hour > 11) return NULL; tm->tm_hour += i * 12; LEGAL_ALT(0); continue; case 'S': /* The seconds. */ bp = conv_num(bp, &tm->tm_sec, 0, 61); LEGAL_ALT(ALT_O); continue; case 's': { /* seconds since the epoch */ #ifdef _WIN32 const time_t TIME_MAX = INT32_MAX; #else const time_t TIME_MAX = INT64_MAX; #endif time_t sse, d; if (*bp < '0' || *bp > '9') { bp = NULL; continue; } sse = *bp++ - '0'; while (*bp >= '0' && *bp <= '9') { d = *bp++ - '0'; if (sse > TIME_MAX/10) { bp = NULL; break; } sse *= 10; if (sse > TIME_MAX - d) { bp = NULL; break; } sse += d; } if (bp == NULL) continue; #ifdef _WIN32 if (localtime_s(tm, &sse)) #else if (localtime_r(&sse, tm) == NULL) #endif bp = NULL; else state |= S_YDAY | S_WDAY | S_MON | S_MDAY | S_YEAR; continue; } case 'U': /* The week of year, beginning on sunday. */ case 'W': /* The week of year, beginning on monday. */ /* * This is bogus, as we can not assume any valid * information present in the tm structure at this * point to calculate a real value, so save the * week for now in case it can be used later. */ bp = conv_num(bp, &i, 0, 53); LEGAL_ALT(ALT_O); if (c == 'U') day_offset = TM_SUNDAY; else day_offset = TM_MONDAY; week_offset = i; continue; case 'w': /* The day of week, beginning on sunday. */ bp = conv_num(bp, &tm->tm_wday, 0, 6); LEGAL_ALT(ALT_O); state |= S_WDAY; continue; case 'u': /* The day of week, monday = 1. */ bp = conv_num(bp, &i, 1, 7); tm->tm_wday = i % 7; LEGAL_ALT(ALT_O); state |= S_WDAY; continue; case 'g': /* The year corresponding to the ISO week * number but without the century. */ bp = conv_num(bp, &i, 0, 99); continue; case 'G': /* The year corresponding to the ISO week * number with century. */ do bp++; while (isdigit(*bp)); continue; case 'V': /* The ISO 8601:1988 week number as decimal */ bp = conv_num(bp, &i, 0, 53); continue; case 'Y': /* The year. */ i = TM_YEAR_BASE; /* just for data sanity... */ bp = conv_num(bp, &i, 0, 9999); tm->tm_year = i - TM_YEAR_BASE; LEGAL_ALT(ALT_E); state |= S_YEAR; continue; case 'y': /* The year within 100 years of the epoch. */ /* LEGAL_ALT(ALT_E | ALT_O); */ bp = conv_num(bp, &i, 0, 99); if (split_year) /* preserve century */ i += (tm->tm_year / 100) * 100; else { split_year = 1; if (i <= 68) i = i + 2000 - TM_YEAR_BASE; } tm->tm_year = i; state |= S_YEAR; continue; case 'Z': // time zone name case 'z': // #ifdef _WIN32 _tzset(); #else tzset(); #endif mandatory = c == 'z'; /* * We recognize all ISO 8601 formats: * Z = Zulu time/UTC * [+-]hhmm * [+-]hh:mm * [+-]hh * We recognize all RFC-822/RFC-2822 formats: * UT|GMT * North American : UTC offsets * E[DS]T = Eastern : -4 | -5 * C[DS]T = Central : -5 | -6 * M[DS]T = Mountain: -6 | -7 * P[DS]T = Pacific : -7 | -8 * Nautical/Military * [A-IL-M] = -1 ... -9 (J not used) * [N-Y] = +1 ... +12 * Note: J maybe used to denote non-nautical * local time */ if (mandatory) while (isspace(*bp)) bp++; zname = bp; switch (*bp++) { case 'G': if (*bp++ != 'M') goto namedzone; /*FALLTHROUGH*/ case 'U': if (*bp++ != 'T') goto namedzone; else if (!delim(*bp) && *bp++ != 'C') goto namedzone; /*FALLTHROUGH*/ case 'Z': if (!delim(*bp)) goto namedzone; tm->tm_isdst = 0; #ifdef TM_GMTOFF tm->TM_GMTOFF = 0; #endif #ifdef TM_ZONE tm->TM_ZONE = utc; #endif continue; case '+': neg = 0; break; case '-': neg = 1; break; default: namedzone: bp = zname; /* Nautical / Military style */ if (delim(bp[1]) && ((*bp >= 'A' && *bp <= 'I') || (*bp >= 'L' && *bp <= 'Y'))) { #ifdef TM_GMTOFF /* Argh! No 'J'! */ if (*bp >= 'A' && *bp <= 'I') tm->TM_GMTOFF = (int)*bp - ('A' - 1); else if (*bp >= 'L' && *bp <= 'M') tm->TM_GMTOFF = (int)*bp - 'A'; else if (*bp >= 'N' && *bp <= 'Y') tm->TM_GMTOFF = 'M' - (int)*bp; tm->TM_GMTOFF *= SECSPERHOUR; #endif #ifdef TM_ZONE tm->TM_ZONE = NULL; /* XXX */ #endif bp++; continue; } /* 'J' is local time */ if (delim(bp[1]) && *bp == 'J') { #ifdef TM_GMTOFF tm->TM_GMTOFF = -timezone; #endif #ifdef TM_ZONE tm->TM_ZONE = NULL; /* XXX */ #endif bp++; continue; } /* * From our 3 letter hard-coded table * XXX: Can be removed, handled by tzload() */ if (delim(bp[0]) || delim(bp[1]) || delim(bp[2]) || !delim(bp[3])) goto loadzone; ep = find_string(bp, &i, nast, NULL, 4); if (ep != NULL) { #ifdef TM_GMTOFF tm->TM_GMTOFF = (-5 - i) * SECSPERHOUR; #endif #ifdef TM_ZONE tm->TM_ZONE = __UNCONST(nast[i]); #endif bp = ep; continue; } ep = find_string(bp, &i, nadt, NULL, 4); if (ep != NULL) { tm->tm_isdst = 1; #ifdef TM_GMTOFF tm->TM_GMTOFF = (-4 - i) * SECSPERHOUR; #endif #ifdef TM_ZONE tm->TM_ZONE = __UNCONST(nadt[i]); #endif bp = ep; continue; } /* * Our current timezone */ ep = find_string(bp, &i, (const char * const *)tzname, NULL, 2); if (ep != NULL) { tm->tm_isdst = i; #ifdef TM_GMTOFF tm->TM_GMTOFF = -timezone; #endif #ifdef TM_ZONE tm->TM_ZONE = tzname[i]; #endif bp = ep; continue; } loadzone: /* * The hard way, load the zone! */ if (fromzone(&bp, tm, mandatory)) continue; goto out; } offs = 0; for (i = 0; i < 4; ) { if (isdigit(*bp)) { offs = offs * 10 + (*bp++ - '0'); i++; continue; } if (i == 2 && *bp == ':') { bp++; continue; } break; } if (isdigit(*bp)) goto out; switch (i) { case 2: offs *= SECSPERHOUR; break; case 4: i = offs % 100; offs /= 100; if (i >= SECSPERMIN) goto out; /* Convert minutes into decimal */ offs = offs * SECSPERHOUR + i * SECSPERMIN; break; default: out: if (mandatory) return NULL; bp = zname; continue; } /* ISO 8601 & RFC 3339 limit to 23:59 max */ if (offs >= (HOURSPERDAY * SECSPERHOUR)) goto out; if (neg) offs = -offs; tm->tm_isdst = 0; /* XXX */ #ifdef TM_GMTOFF tm->TM_GMTOFF = offs; #endif #ifdef TM_ZONE tm->TM_ZONE = NULL; /* XXX */ #endif continue; /* * Miscellaneous conversions. */ case 'n': /* Any kind of white-space. */ case 't': while (isspace(*bp)) bp++; LEGAL_ALT(0); continue; default: /* Unknown/unsupported conversion. */ return NULL; } } if (!HAVE_YDAY(state) && HAVE_YEAR(state)) { if (HAVE_MON(state) && HAVE_MDAY(state)) { /* calculate day of year (ordinal date) */ tm->tm_yday = start_of_month[isleap_sum(tm->tm_year, TM_YEAR_BASE)][tm->tm_mon] + (tm->tm_mday - 1); state |= S_YDAY; } else if (day_offset != -1) { /* * Set the date to the first Sunday (or Monday) * of the specified week of the year. */ if (!HAVE_WDAY(state)) { tm->tm_wday = day_offset; state |= S_WDAY; } tm->tm_yday = (7 - first_wday_of(tm->tm_year + TM_YEAR_BASE) + day_offset) % 7 + (week_offset - 1) * 7 + tm->tm_wday - day_offset; state |= S_YDAY; } } if (HAVE_YDAY(state) && HAVE_YEAR(state)) { int isleap; if (!HAVE_MON(state)) { /* calculate month of day of year */ i = 0; isleap = isleap_sum(tm->tm_year, TM_YEAR_BASE); while (tm->tm_yday >= start_of_month[isleap][i]) i++; if (i > 12) { i = 1; tm->tm_yday -= start_of_month[isleap][12]; tm->tm_year++; } tm->tm_mon = i - 1; state |= S_MON; } if (!HAVE_MDAY(state)) { /* calculate day of month */ isleap = isleap_sum(tm->tm_year, TM_YEAR_BASE); tm->tm_mday = tm->tm_yday - start_of_month[isleap][tm->tm_mon] + 1; state |= S_MDAY; } if (!HAVE_WDAY(state)) { /* calculate day of week */ i = 0; week_offset = first_wday_of(tm->tm_year); while (i++ <= tm->tm_yday) { if (week_offset++ >= 6) week_offset = 0; } tm->tm_wday = week_offset; state |= S_WDAY; } } return (char*)bp; } static const unsigned char * conv_num(const unsigned char *buf, int *dest, unsigned int llim, unsigned int ulim) { unsigned int result = 0; unsigned char ch; /* The limit also determines the number of valid digits. */ unsigned int rulim = ulim; ch = *buf; if (ch < '0' || ch > '9') return NULL; do { result *= 10; result += ch - '0'; rulim /= 10; ch = *++buf; } while ((result <= ulim) && rulim && ch >= '0' && ch <= '9'); if (result < llim || result > ulim) return NULL; *dest = result; return buf; } static const unsigned char * find_string(const unsigned char *bp, int *tgt, const char * const *n1, const char * const *n2, int c) { int i; size_t len; /* check full name - then abbreviated ones */ for (; n1 != NULL; n1 = n2, n2 = NULL) { for (i = 0; i < c; i++, n1++) { len = strlen(*n1); if (strncasecmp(*n1, (const char *)bp, len) == 0) { *tgt = i; return bp + len; } } } /* Nothing matched */ return NULL; } #endif ================================================ FILE: src/util.h ================================================ #ifndef UTIL_H #define UTIL_H #ifdef WIN32 /* For WriteFile() below */ #include #include #include #include #include #include #endif #include "jv.h" jv expand_path(jv); jv get_home(void); jv jq_realpath(jv); /* * The Windows CRT and console are something else. In order for the * console to get UTF-8 written to it correctly we have to bypass stdio * completely. No amount of fflush()ing helps. If the first byte of a * buffer being written with fwrite() is non-ASCII UTF-8 then the * console misinterprets the byte sequence. But one must not * WriteFile() if stdout is a file!1!! * * We carry knowledge of whether the FILE * is a tty everywhere we * output to it just so we can write with WriteFile() if stdout is a * console on WIN32. */ static void priv_fwrite(const char *s, size_t len, FILE *fout, int is_tty) { #ifdef WIN32 if (is_tty) WriteFile((HANDLE)_get_osfhandle(fileno(fout)), s, len, NULL, NULL); else fwrite(s, 1, len, fout); #else fwrite(s, 1, len, fout); #endif } const void *_jq_memmem(const void *haystack, size_t haystacklen, const void *needle, size_t needlelen); #ifndef MIN #define MIN(a,b) \ ({ __typeof__ (a) _a = (a); \ __typeof__ (b) _b = (b); \ _a < _b ? _a : _b; }) #endif #ifndef MAX #define MAX(a,b) \ ({ __typeof__ (a) _a = (a); \ __typeof__ (b) _b = (b); \ _a > _b ? _a : _b; }) #endif #include #ifndef HAVE_STRPTIME char* strptime(const char *buf, const char *fmt, struct tm *tm); #endif #endif /* UTIL_H */ ================================================ FILE: tests/base64.test ================================================ # Tests are groups of three lines: program, input, expected output # Blank lines and lines starting with # are ignored @base64 "" "" @base64 "<>&'\"\t" "PD4mJyIJ" # decoding encoded output results in same text (@base64|@base64d) "<>&'\"\t" "<>&'\"\t" # regression test for #436 @base64 "foóbar\n" "Zm/Ds2Jhcgo=" @base64d "" "" @base64d "=" "" @base64d "Zm/Ds2Jhcgo=" "foóbar\n" # optional trailing equals padding (With padding, this is cWl4YmF6Cg==) @base64d "cWl4YmF6Cg" "qixbaz\n" # invalid base64 characters (whitespace) . | try @base64d catch . "Not base64 data" "string (\"Not base64 data\") is not valid base64 data" # invalid base64 (too many bytes, QUJD = "ABCD" . | try @base64d catch . "QUJDa" "string (\"QUJDa\") trailing base64 byte found" ================================================ FILE: tests/base64test ================================================ #!/bin/sh . "${0%/*}/setup" "$@" $VALGRIND $Q $JQ -L "$mods" --run-tests $JQTESTDIR/base64.test ================================================ FILE: tests/jq-f-test.sh ================================================ #!/bin/sh # this next line is ignored by jq, which otherwise does not continue comments \ exec jq -nef "$0" "$@" true ================================================ FILE: tests/jq.test ================================================ # Tests are groups of three lines: program, input, expected output # Blank lines and lines starting with # are ignored # # Simple value tests to check parser. Input is irrelevant # true null true false null false null 42 null 1 null 1 -1 null -1 # FIXME: much more number testing needed {} null {} [] null [] {x:-1},{x:-.},{x:-.|abs} 1 {"x":-1} {"x":-1} {"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. . "byte order mark" "byte order mark" # We test escapes by matching them against Unicode codepoints # FIXME: more tests needed for weird unicode stuff (e.g. utf16 pairs) "Aa\r\n\t\b\f\u03bc" null "Aa\u000d\u000a\u0009\u0008\u000c\u03bc" . "Aa\r\n\t\b\f\u03bc" "Aa\u000d\u000a\u0009\u0008\u000c\u03bc" %%FAIL "u\vw" jq: error: Invalid escape at line 1, column 4 (while parsing '"\v"') at , line 1, column 3: "u\vw" ^^ "inter\("pol" + "ation")" null "interpolation" @text,@json,([1,.]|@csv,@tsv),@html,(@uri|.,@urid),@sh,(@base64|.,@base64d) "!()<>&'\"\t" "!()<>&'\"\t" "\"!()<>&'\\\"\\t\"" "1,\"!()<>&'\"\"\t\"" "1\t!()<>&'\"\\t" "!()<>&'"\t" "%21%28%29%3C%3E%26%27%22%09" "!()<>&'\"\t" "'!()<>&'\\''\"\t'" "ISgpPD4mJyIJ" "!()<>&'\"\t" # regression test for #436 @base64 "foóbar\n" "Zm/Ds2Jhcgo=" @base64d "Zm/Ds2Jhcgo=" "foóbar\n" @uri "\u03bc" "%CE%BC" @urid "%CE%BC" "\u03bc" @html "\(.)" "" "<script>hax</script>" [.[]|tojson|fromjson] ["foo", 1, ["a", 1, "b", 2, {"foo":"bar"}]] ["foo",1,["a",1,"b",2,{"foo":"bar"}]] # # Dictionary construction syntax # {a: 1} null {"a":1} {a,b,(.d):.a,e:.b} {"a":1, "b":2, "c":3, "d":"c"} {"a":1, "b":2, "c":1, "e":2} {"a",b,"a$\(1+1)"} {"a":1, "b":2, "c":3, "a$2":4} {"a":1, "b":2, "a$2":4} %%FAIL {(0):1} jq: error: Cannot use number (0) as object key at , line 1, column 3: {(0):1} ^ %%FAIL {1+2:3} jq: error: May need parentheses around object key expression at , line 1, column 2: {1+2:3} ^^^ %%FAIL {non_const:., (0):1} jq: error: Cannot use number (0) as object key at , line 1, column 16: {non_const:., (0):1} ^ # # Field access, piping # .foo {"foo": 42, "bar": 43} 42 .foo | .bar {"foo": {"bar": 42}, "bar": "badvalue"} 42 .foo.bar {"foo": {"bar": 42}, "bar": "badvalue"} 42 .foo_bar {"foo_bar": 2} 2 .["foo"].bar {"foo": {"bar": 42}, "bar": "badvalue"} 42 ."foo"."bar" {"foo": {"bar": 20}} 20 .e0, .E1, .E-1, .E+1 {"e0": 1, "E1": 2, "E": 3} 1 2 2 4 [.[]|.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]] # chaining/suffix-list, with and without dot map(try .a[] catch ., try .a.[] catch ., .a[]?, .a.[]?) [{"a": [1,2]}, {"a": 123}] [1,2,1,2,1,2,1,2,"Cannot iterate over number (123)","Cannot iterate over number (123)"] # oss-fuzz #66070: objects[] leaks if a non-last element throws an error try ["OK", (.[] | error)] catch ["KO", .] {"a":["b"],"c":["d"]} ["KO",["b"]] # # Negative array indices # try (.foo[-1] = 0) catch . null "Out of bounds negative array index" try (.foo[-2] = 0) catch . null "Out of bounds negative array index" .[-1] = 5 [0,1,2] [0,1,5] .[-2] = 5 [0,1,2] [0,5,2] try (.[999999999] = 0) catch . null "Array index too large" # # Multiple outputs, iteration # .[] [1,2,3] 1 2 3 1,1 [] 1 1 1,. [] 1 [] [.] [2] [[2]] [[2]] [3] [[2]] [{}] [2] [{}] [.[]] ["a"] ["a"] [(.,1),((.,.[]),(2,3))] ["a","b"] [["a","b"],1,["a","b"],"a","b",2,3] [([5,5][]),.,.[]] [1,2,3] [5,5,[1,2,3],1,2,3] {x: (1,2)},{x:3} | .x null 1 2 3 [.[-4,-3,-2,-1,0,1,2,3]] [1,2,3] [null,1,2,3,1,2,3,null] [range(0;10)] null [0,1,2,3,4,5,6,7,8,9] [range(0,1;3,4)] null [0,1,2, 0,1,2,3, 1,2, 1,2,3] [range(0;10;3)] null [0,3,6,9] [range(0;10;-1)] null [] [range(0;-5;-1)] null [0,-1,-2,-3,-4] [range(0,1;4,5;1,2)] null [0,1,2,3,0,2, 0,1,2,3,4,0,2,4, 1,2,3,1,3, 1,2,3,4,1,3] [while(.<100; .*2)] 1 [1,2,4,8,16,32,64] [(label $here | .[] | if .>1 then break $here else . end), "hi!"] [0,1,2] [0,1,"hi!"] [(label $here | .[] | if .>1 then break $here else . end), "hi!"] [0,2,1] [0,"hi!"] %%FAIL . as $foo | break $foo jq: error: $*label-foo is not defined at , line 1, column 13: . as $foo | break $foo ^^^^^^^^^^ [.[]|[.,1]|until(.[0] < 1; [.[0] - 1, .[1] * .[0]])|.[1]] [1,2,3,4,5] [1,2,6,24,120] [label $out | foreach .[] as $item ([3, null]; if .[0] < 1 then break $out else [.[0] -1, $item] end; .[1])] [11,22,33,44,55,66,77,88,99] [11,22,33] [foreach range(5) as $item (0; $item)] null [0,1,2,3,4] [foreach .[] as [$i, $j] (0; . + $i - $j)] [[2,1], [5,3], [6,4]] [1,3,5] [foreach .[] as {a:$a} (0; . + $a; -.)] [{"a":1}, {"b":2}, {"a":3, "b":4}] [-1, -1, -4] [-foreach -.[] as $x (0; . + $x)] [1,2,3] [1,3,6] [foreach .[] / .[] as $i (0; . + $i)] [1,2] [1,3,3.5,4.5] [foreach .[] as $x (0; . + $x) as $x | $x] [1,2,3] [1,3,6] [limit(3; .[])] [11,22,33,44,55,66,77,88,99] [11,22,33] [limit(0; error)] "badness" [] [limit(1; 1, error)] "badness" [1] try limit(-1; error) catch . null "limit doesn't support negative count" [skip(3; .[])] [1,2,3,4,5,6,7,8,9] [4,5,6,7,8,9] [skip(0,2,3,4; .[])] [1,2,3] [1,2,3,3] [skip(3; .[])] [] [] try skip(-1; error) catch . null "skip doesn't support negative count" nth(1; 0,1,error("foo")) null 1 [first(range(.)), last(range(.))] 10 [0,9] [first(range(.)), last(range(.))] 0 [] [nth(0,5,9,10,15; range(.)), try nth(-1; range(.)) catch .] 10 [0,5,9,"nth doesn't support negative indices"] # Check that first(g) does not extract more than one value from g first(1,error("foo")) null 1 # # Check that various builtins evaluate all arguments where appropriate, # doing cartesian products where appropriate. # # Check that limit does work for each value produced by n! [limit(5,7; range(9))] null [0,1,2,3,4,0,1,2,3,4,5,6] # Same check for nth [nth(5,7; range(9;0;-1))] null [4,2] # Same check for range/3 [range(0,1,2;4,3,2;2,3)] null [0,2,0,3,0,2,0,0,0,1,3,1,1,1,1,1,2,2,2,2] # Same check for range/1 [range(3,5)] null [0,1,2,0,1,2,3,4] # Same check for index/1, rindex/1, indices/1 [(index(",","|"), rindex(",","|")), indices(",","|")] "a,b|c,d,e||f,g,h,|,|,i,j" [1,3,22,19,[1,5,7,12,14,16,18,20,22],[3,9,10,17,19]] # Same check for join/1 join(",","/") ["a","b","c","d"] "a,b,c,d" "a/b/c/d" [.[]|join("a")] [[],[""],["",""],["","",""]] ["","","a","aa"] # Same check for flatten/1 flatten(3,2,1) [0, [1], [[2]], [[[3]]]] [0,1,2,3] [0,1,2,[3]] [0,1,[2],[[3]]] # # Slices # [.[3:2], .[-5:4], .[:-2], .[-2:], .[3:3][1:], .[10:]] [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] .[2:4] = ([], ["a","b"], ["a","b","c"]) [0,1,2,3,4,5,6,7] [0,1,4,5,6,7] [0,1,"a","b",4,5,6,7] [0,1,"a","b","c",4,5,6,7] # Slices at large offsets (issue #1108) # # This is written this way because [range()] is # significantly slower under valgrind than .[] = value. # # We range down rather than up so that we have just one realloc. reduce range(65540;65536;-1) as $i ([]; .[$i] = $i)|.[65536:] null [null,65537,65538,65539,65540] # # Variables # 1 as $x | 2 as $y | [$x,$y,$x] null [1,2,1] [1,2,3][] as $x | [[4,5,6,7][$x]] null [5] [6] [7] 42 as $x | . | . | . + 432 | $x + 1 34324 43 1 + 2 as $x | -$x null -3 "x" as $x | "a"+"y" as $y | $x+","+$y null "x,ay" 1 as $x | [$x,$x,$x as $x | $x] null [1,1,1] [1, {c:3, d:4}] as [$a, {c:$b, b:$c}] | $a, $b, $c null 1 3 null . as {as: $kw, "str": $str, ("e"+"x"+"p"): $exp} | [$kw, $str, $exp] {"as": 1, "str": 2, "exp": 3} [1, 2, 3] .[] as [$a, $b] | [$b, $a] [[1], [1, 2, 3]] [null, 1] [2, 1] . as $i | . as [$i] | $i [0] 0 . as [$i] | . as $i | $i [0] [0] %%FAIL . as [] | null jq: error: syntax error, unexpected ']', expecting BINDING or '[' or '{' at , line 1, column 7: . as [] | null ^ %%FAIL . as {} | null jq: error: syntax error, unexpected '}' at , line 1, column 7: . as {} | null ^ %%FAIL . as $foo | [$foo, $bar] jq: error: $bar is not defined at , line 1, column 20: . as $foo | [$foo, $bar] ^^^^ %%FAIL . as {(true):$foo} | $foo jq: error: Cannot use boolean (true) as object key at , line 1, column 8: . as {(true):$foo} | $foo ^^^^ # [.,(.[] | {x:.},.),.,.[]] # # Builtin functions # 1+1 null 2 1+1 "wtasdf" 2.0 2-1 null 1 2-(-1) null 3 1e+0+0.001e3 "I wonder what this will be?" 20e-1 .+4 15 19.0 .+null {"a":42} {"a":42} null+. null null .a+.b {"a":42} 42 [1,2,3] + [.] null [1,2,3,null] {"a":1} + {"b":2} + {"c":3} "asdfasdf" {"a":1, "b":2, "c":3} "asdf" + "jkl;" + . + . + . "some string" "asdfjkl;some stringsome stringsome string" "\u0000\u0020\u0000" + . "\u0000\u0020\u0000" "\u0000 \u0000\u0000 \u0000" 42 - . 11 31 [1,2,3,4,1] - [.,3] 1 [2,4] [-1 as $x | 1,$x] null [1,-1] [10 * 20, 20 / .] 4 [200, 5] 1 + 2 * 2 + 10 / 2 null 10 [16 / 4 / 2, 16 / 4 * 2, 16 - 4 - 2, 16 - 4 + 2] null [2, 8, 10, 14] 1e-19 + 1e-20 - 5e-21 null 1.05e-19 1 / 1e-17 null 1e+17 9E999999999, 9999999999E999999990, 1E-999999999, 0.000000001E-999999990 null 9E+999999999 9.999999999E+999999999 1E-999999999 1E-999999999 5E500000000 > 5E-5000000000, 10000E500000000 > 10000E-5000000000 null true true # #2825 (1e999999999, 10e999999999) > (1e-1147483646, 0.1e-1147483646) null true true true true 25 % 7 null 4 49732 % 472 null 172 [(infinite, -infinite) % (1, -1, infinite)] null [0,0,0,0,0,-1] [nan % 1, 1 % nan | isnan] null [true,true] 1 + tonumber + ("10" | tonumber) 4 15 "123\u0000456" | try tonumber catch . null "string (\"123\\u0000456\") cannot be parsed as a number" map(toboolean) ["false","true",false,true] [false,true,false,true] .[] | try toboolean catch . [null,0,"tru","truee","fals","falsee",[],{}] "null (null) cannot be parsed as a boolean" "number (0) cannot be parsed as a boolean" "string (\"tru\") cannot be parsed as a boolean" "string (\"truee\") cannot be parsed as a boolean" "string (\"fals\") cannot be parsed as a boolean" "string (\"falsee\") cannot be parsed as a boolean" "array ([]) cannot be parsed as a boolean" "object ({}) cannot be parsed as a boolean" "true\u0000x", "false\u0000" | try toboolean catch . null "string (\"true\\u0000x\") cannot be parsed as a boolean" "string (\"false\\u0000\") cannot be parsed as a boolean" [{"a":42},.object,10,.num,false,true,null,"b",[1,4]] | .[] as $x | [$x == .[]] {"object": {"a":42}, "num":10.0} [true, true, false, false, false, false, false, false, false] [true, true, false, false, false, false, false, false, false] [false, false, true, true, false, false, false, false, false] [false, false, true, true, false, false, false, false, false] [false, false, false, false, true, false, false, false, false] [false, false, false, false, false, true, false, false, false] [false, false, false, false, false, false, true, false, false] [false, false, false, false, false, false, false, true, false] [false, false, false, false, false, false, false, false, true ] [.[] | length] [[], {}, [1,2], {"a":42}, "asdf", "\u03bc"] [0, 0, 2, 1, 4, 1] utf8bytelength "asdf\u03bc" 6 [.[] | try utf8bytelength catch .] [[], {}, [1,2], 55, true, false] ["array ([]) only strings have UTF-8 byte length","object ({}) only strings have UTF-8 byte length","array ([1,2]) only strings have UTF-8 byte length","number (55) only strings have UTF-8 byte length","boolean (true) only strings have UTF-8 byte length","boolean (false) only strings have UTF-8 byte length"] map(keys) [{}, {"abcd":1,"abc":2,"abcde":3}, {"x":1, "z": 3, "y":2}] [[], ["abc","abcd","abcde"], ["x","y","z"]] [1,2,empty,3,empty,4] null [1,2,3,4] map(add) [[], [1,2,3], ["a","b","c"], [[3],[4,5],[6]], [{"a":1}, {"b":2}, {"a":3}]] [null, 6, "abc", [3,4,5,6], {"a":3, "b": 2}] map_values(.+1) [0,1,2] [1,2,3] [add(null), add(range(range(10))), add(empty), add(10,range(10))] null [null,120,null,55] # Real-world use case for add(empty) .sum = add(.arr[]) {"arr":[]} {"arr":[],"sum":null} add({(.[]):1}) | keys ["a","a","b","a","d","b","d","a","d"] ["a","b","d"] # # User-defined functions # Oh god. # def f: . + 1; def g: def g: . + 100; f | g | f; (f | g), g 3.0 106.0 105.0 def f: (1000,2000); f 123412345 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] def f: 1; def g: f, def f: 2; def g: 3; f, def f: g; f, g; def f: 4; [f, def f: g; def g: 5; f, g]+[f,g] null [4,1,2,3,3,5,4,1,2,3,3] # Test precedence of 'def' vs '|' def a: 0; . | a null 0 # Many arguments def f(a;b;c;d;e;f;g;h;i;j): [j,i,h,g,f,e,d,c,b,a]; f(.[0];.[1];.[2];.[3];.[4];.[5];.[6];.[7];.[8];.[9]) [0,1,2,3,4,5,6,7,8,9] [9,8,7,6,5,4,3,2,1,0] ([1,2] + [4,5]) [1,2,3] [1,2,4,5] true [1] true null,1,null "hello" null 1 null [1,2,3] [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]]] [[1,2,3],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" [1,100,2100.0,100,2100.0] # test def f($a) syntax def x(a;b): a as $a | b as $b | $a + $b; def y($a;$b): $a + $b; def check(a;b): [x(a;b)] == [y(a;b)]; check(.[];.[]*2) [1,2,3] true # test backtracking through function calls and returns # this test is *evil* [[20,10][1,0] as $x | def f: (100,200) as $y | def g: [$x + $y, .]; . + $x | g; f[0] | [f][0][1] | f] 999999999 [[110.0, 130.0], [210.0, 130.0], [110.0, 230.0], [210.0, 230.0], [120.0, 160.0], [220.0, 160.0], [120.0, 260.0], [220.0, 260.0]] # test recursion def fac: if . == 1 then 1 else . * (. - 1 | fac) end; [.[] | fac] [1,2,3,4] [1,2,6,24] # test stack overflow and reallocation # this test is disabled for now, it takes a realllllly long time. # def f: if length > 1000 then . else .+[1]|f end; f | length # [] # 1001 reduce .[] as $x (0; . + $x) [1,2,4] 7 reduce .[] as [$i, {j:$j}] (0; . + $i - $j) [[2,{"j":1}], [5,{"j":3}], [6,{"j":4}]] 5 reduce [[1,2,10], [3,4,10]][] as [$i,$j] (0; . + $i * $j) null 14 [-reduce -.[] as $x (0; . + $x)] [1,2,3] [6] [reduce .[] / .[] as $i (0; . + $i)] [1,2] [4.5] reduce .[] as $x (0; . + $x) as $x | $x [1,2,3] 6 # This, while useless, should still compile. reduce . as $n (.; .) null null # Destructuring . as {$a, b: [$c, {$d}]} | [$a, $c, $d] {"a":1, "b":[2,{"d":3}]} [1,2,3] . as {$a, $b:[$c, $d]}| [$a, $b, $c, $d] {"a":1, "b":[2,{"d":3}]} [1,[2,{"d":3}],2,{"d":3}] # Destructuring with alternation .[] | . as {$a, b: [$c, {$d}]} ?// [$a, {$b}, $e] ?// $f | [$a, $b, $c, $d, $e, $f] [{"a":1, "b":[2,{"d":3}]}, [4, {"b":5, "c":6}, 7, 8, 9], "foo"] [1, null, 2, 3, null, null] [4, 5, null, null, 7, null] [null, null, null, null, null, "foo"] # Destructuring DUP/POP issues .[] | . as {a:$a} ?// {a:$a} ?// {a:$a} | $a [[3],[4],[5],6] # Runtime error: "jq: Cannot index array with string (\"c\")" .[] as {a:$a} ?// {a:$a} ?// {a:$a} | $a [[3],[4],[5],6] # Runtime error: "jq: Cannot index array with string (\"c\")" [[3],[4],[5],6][] | . as {a:$a} ?// {a:$a} ?// {a:$a} | $a null # Runtime error: "jq: Cannot index array with string (\"c\")" [[3],[4],[5],6] | .[] as {a:$a} ?// {a:$a} ?// {a:$a} | $a null # Runtime error: "jq: Cannot index array with string (\"c\")" .[] | . as {a:$a} ?// {a:$a} ?// $a | $a [[3],[4],[5],6] [3] [4] [5] 6 .[] as {a:$a} ?// {a:$a} ?// $a | $a [[3],[4],[5],6] [3] [4] [5] 6 [[3],[4],[5],6][] | . as {a:$a} ?// {a:$a} ?// $a | $a null [3] [4] [5] 6 [[3],[4],[5],6] | .[] as {a:$a} ?// {a:$a} ?// $a | $a null [3] [4] [5] 6 .[] | . as {a:$a} ?// $a ?// {a:$a} | $a [[3],[4],[5],6] [3] [4] [5] 6 .[] as {a:$a} ?// $a ?// {a:$a} | $a [[3],[4],[5],6] [3] [4] [5] 6 [[3],[4],[5],6][] | . as {a:$a} ?// $a ?// {a:$a} | $a null [3] [4] [5] 6 [[3],[4],[5],6] | .[] as {a:$a} ?// $a ?// {a:$a} | $a null [3] [4] [5] 6 .[] | . as $a ?// {a:$a} ?// {a:$a} | $a [[3],[4],[5],6] [3] [4] [5] 6 .[] as $a ?// {a:$a} ?// {a:$a} | $a [[3],[4],[5],6] [3] [4] [5] 6 [[3],[4],[5],6][] | . as $a ?// {a:$a} ?// {a:$a} | $a null [3] [4] [5] 6 [[3],[4],[5],6] | .[] as $a ?// {a:$a} ?// {a:$a} | $a null [3] [4] [5] 6 . as $dot|any($dot[];not) [1,2,3,4,true,false,1,2,3,4,5] true . as $dot|any($dot[];not) [1,2,3,4,true] false . as $dot|all($dot[];.) [1,2,3,4,true,false,1,2,3,4,5] false . as $dot|all($dot[];.) [1,2,3,4,true] true # Check short-circuiting any(true, error; .) "badness" true all(false, error; .) "badness" false any(not) [] false all(not) [] true any(not) [false] true all(not) [false] true [any,all] [] [false,true] [any,all] [true] [true,true] [any,all] [false] [false,false] [any,all] [true,false] [true,false] [any,all] [null,null,true] [true,false] # # Paths # path(.foo[0,1]) null ["foo", 0] ["foo", 1] path(.[] | select(.>3)) [1,5,3] [1] path(.) 42 [] try path(.a | map(select(.b == 0))) catch . {"a":[{"b":0}]} "Invalid path expression with result [{\"b\":0}]" try path(.a | map(select(.b == 0)) | .[0]) catch . {"a":[{"b":0}]} "Invalid path expression near attempt to access element 0 of [{\"b\":0}]" try path(.a | map(select(.b == 0)) | .c) catch . {"a":[{"b":0}]} "Invalid path expression near attempt to access element \"c\" of [{\"b\":0}]" try path(.a | map(select(.b == 0)) | .[]) catch . {"a":[{"b":0}]} "Invalid path expression near attempt to iterate through [{\"b\":0}]" path(.a[path(.b)[0]]) {"a":{"b":0}} ["a","b"] [paths] [1,[[],{"a":2}]] [[0],[1],[1,0],[1,1],[1,1,"a"]] ["foo",1] as $p | getpath($p), setpath($p; 20), delpaths([$p]) {"bar": 42, "foo": ["a", "b", "c", "d"]} "b" {"bar": 42, "foo": ["a", 20, "c", "d"]} {"bar": 42, "foo": ["a", "c", "d"]} map(getpath([2])), map(setpath([2]; 42)), map(delpaths([[2]])) [[0], [0,1], [0,1,2]] [null, null, 2] [[0,null,42], [0,1,42], [0,1,42]] [[0], [0,1], [0,1]] map(delpaths([[0,"foo"]])) [[{"foo":2, "x":1}], [{"bar":2}]] [[{"x":1}], [{"bar":2}]] ["foo",1] as $p | getpath($p), setpath($p; 20), delpaths([$p]) {"bar":false} null {"bar":false, "foo": [null, 20]} {"bar":false} delpaths([[-200]]) [1,2,3] [1,2,3] try delpaths(0) catch . {} "Paths must be specified as an array" del(.), del(empty), del((.foo,.bar,.baz) | .[2,3,0]), del(.foo[0], .bar[0], .foo, .baz.bar[0].x) {"foo": [0,1,2,3,4], "bar": [0,1]} null {"foo": [0,1,2,3,4], "bar": [0,1]} {"foo": [1,4], "bar": [1]} {"bar": [1]} del(.[1], .[-6], .[2], .[-3:9]) [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] [0, 3, 5, 6, 9] del(.[nan]) [1,2,3] [1,2,3] del(.[nan,nan]) [1,2,3] [1,2,3] # negative index setpath([-1]; 1) [0] [1] pick(.a.b.c) null {"a":{"b":{"c":null}}} pick(first) [1,2] [1] pick(first|first) [[10,20],30] [[10]] # negative indices in path expressions (since last/1 is .[-1]) try pick(last) catch . [1,2] "Out of bounds negative array index" # # Assignment # .message = "goodbye" {"message": "hello"} {"message": "goodbye"} .foo = .bar {"bar":42} {"foo":42, "bar":42} .foo |= .+1 {"foo": 42} {"foo": 43} .[] += 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} {"foo":4} .[0].a |= {"old":., "new":(.+1)} [{"a":1,"b":2}] [{"a":{"old":1, "new":2},"b":2}] def inc(x): x |= .+1; inc(.[].a) [{"a":1,"b":2},{"a":2,"b":4},{"a":7,"b":8}] [{"a":2,"b":2},{"a":3,"b":4},{"a":8,"b":8}] # #1358, getpath/1 should work in path expressions .[] | try (getpath(["a",0,"b"]) |= 5) catch . [null,{"b":0},{"a":0},{"a":null},{"a":[0,1]},{"a":{"b":1}},{"a":[{}]},{"a":[{"c":3}]}] {"a":[{"b":5}]} {"b":0,"a":[{"b":5}]} "Cannot index number with number (0)" {"a":[{"b":5}]} "Cannot index number with string (\"b\")" "Cannot index object with number (0)" {"a":[{"b":5}]} {"a":[{"c":3,"b":5}]} # #2051, deletion using assigning empty against arrays (.[] | select(. >= 2)) |= empty [1,5,3,0,7] [1,0] .[] |= select(. % 2 == 0) [0,1,2,3,4,5] [0,2,4] .foo[1,4,2,3] |= empty {"foo":[0,1,2,3,4,5]} {"foo":[0,5]} .[2][3] = 1 [4] [4, null, [null, null, null, 1]] .foo[2].bar = 1 {"foo":[11], "bar":42} {"foo":[11,null,{"bar":1}], "bar":42} try ((map(select(.a == 1))[].b) = 10) catch . [{"a":0},{"a":1}] "Invalid path expression near attempt to iterate through [{\"a\":1}]" try ((map(select(.a == 1))[].a) |= .+1) catch . [{"a":0},{"a":1}] "Invalid path expression near attempt to iterate through [{\"a\":1}]" def x: .[1,2]; x=10 [0,1,2] [0,10,10] try (def x: reverse; x=10) catch . [0,1,2] "Invalid path expression with result [2,1,0]" .[] = 1 [1,null,Infinity,-Infinity,NaN,-NaN] [1,1,1,1,1,1] # # Conditionals # [.[] | if .foo then "yep" else "nope" end] [{"foo":0},{"foo":1},{"foo":[]},{"foo":true},{"foo":false},{"foo":null},{"foo":"foo"},{}] ["yep","yep","yep","yep","nope","nope","yep","nope"] [.[] | if .baz then "strange" elif .foo then "yep" else "nope" end] [{"foo":0},{"foo":1},{"foo":[]},{"foo":true},{"foo":false},{"foo":null},{"foo":"foo"},{}] ["yep","yep","yep","yep","nope","nope","yep","nope"] [if 1,null,2 then 3 else 4 end] null [3,4,3] [if empty then 3 else 4 end] null [] [if 1 then 3,4 else 5 end] null [3,4] [if null then 3 else 5,6 end] null [5,6] [if true then 3 end] 7 [3] [if false then 3 end] 7 [7] [if false then 3 else . end] 7 [7] [if false then 3 elif false then 4 end] 7 [7] [if false then 3 elif false then 4 else . end] 7 [7] [-if true then 1 else 2 end] null [-1] {x: if true then 1 else 2 end} null {"x":1} if true then [.] else . end [] null null [.[] | [.foo[] // .bar]] [{"foo":[1,2], "bar": 42}, {"foo":[1], "bar": null}, {"foo":[null,false,3], "bar": 18}, {"foo":[], "bar":42}, {"foo": [null,false,null], "bar": 41}] [[1,2], [1], [3], [42], [41]] .[] //= .[0] ["hello",true,false,[false],null] ["hello",true,"hello",[false],"hello"] .[] | [.[0] and .[1], .[0] or .[1]] [[true,[]], [false,1], [42,null], [null,false]] [true,true] [false,true] [false,true] [false,false] [.[] | not] [1,0,false,null,true,"hello"] [false,false,true,true,false,false] # Check numeric comparison binops [10 > 0, 10 > 10, 10 > 20, 10 < 0, 10 < 10, 10 < 20] {} [true,false,false,false,false,true] [10 >= 0, 10 >= 10, 10 >= 20, 10 <= 0, 10 <= 10, 10 <= 20] {} [true,true,false,false,true,true] # And some in/equality tests [ 10 == 10, 10 != 10, 10 != 11, 10 == 11] {} [true,false,true,false] ["hello" == "hello", "hello" != "hello", "hello" == "world", "hello" != "world" ] {} [true,false,false,true] [[1,2,3] == [1,2,3], [1,2,3] != [1,2,3], [1,2,3] == [4,5,6], [1,2,3] != [4,5,6]] {} [true,false,false,true] [{"foo":42} == {"foo":42},{"foo":42} != {"foo":42}, {"foo":42} != {"bar":42}, {"foo":42} == {"bar":42}] {} [true,false,true,false] # ugly complicated thing [{"foo":[1,2,{"bar":18},"world"]} == {"foo":[1,2,{"bar":18},"world"]},{"foo":[1,2,{"bar":18},"world"]} == {"foo":[1,2,{"bar":19},"world"]}] {} [true,false] # containment operator [("foo" | contains("foo")), ("foobar" | contains("foo")), ("foo" | contains("foobar"))] {} [true, true, false] # containment operator (embedded NULs!) [contains(""), contains("\u0000")] "\u0000" [true, true] [contains(""), contains("a"), contains("ab"), contains("c"), contains("d")] "ab\u0000cd" [true, true, true, true, true] [contains("cd"), contains("b\u0000"), contains("ab\u0000")] "ab\u0000cd" [true, true, true] [contains("b\u0000c"), contains("b\u0000cd"), contains("b\u0000cd")] "ab\u0000cd" [true, true, true] [contains("@"), contains("\u0000@"), contains("\u0000what")] "ab\u0000cd" [false, false, false] # Try/catch and general `?` operator [.[]|try if . == 0 then error("foo") elif . == 1 then .a elif . == 2 then empty else . end catch .] [0,1,2,3] ["foo","Cannot index number with string (\"a\")",3] [.[]|(.a, .a)?] [null,true,{"a":1}] [null,null,1,1] [[.[]|[.a,.a]]?] [null,true,{"a":1}] [] [if error then 1 else 2 end?] "foo" [] try error(0) // 1 null 1 1, try error(2), 3 null 1 3 1 + try 2 catch 3 + 4 null 7 [-try .] 1 [-1] try -.? catch . "foo" "string (\"foo\") cannot be negated" {x: try 1, y: try error catch 2, z: if true then 3 end} null {"x":1,"y":2,"z":3} {x: 1 + 2, y: false or true, z: null // 3} null {"x":3,"y":true,"z":3} .[] | try error catch . [1,null,2] 1 null 2 try error("\($__loc__)") catch . null "{\"file\":\"\",\"line\":1}" # 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] [.[] | split(", ")] ["a,b, c, d, e,f",", a,b, c, d, e,f, "] [["a,b","c","d","e,f"],["","a,b","c","d","e,f",""]] split("") "abc" ["a","b","c"] [.[]|ltrimstr("foo")] ["fo", "foo", "barfoo", "foobar", "afoo"] ["fo","","barfoo","bar","afoo"] [.[]|rtrimstr("foo")] ["fo", "foo", "barfoo", "foobar", "foob"] ["fo","","bar","foobar","foob"] [.[]|trimstr("foo")] ["fo", "foo", "barfoo", "foobarfoo", "foob"] ["fo","","bar","bar","b"] [.[]|ltrimstr("")] ["a", "xx", ""] ["a", "xx", ""] [.[]|rtrimstr("")] ["a", "xx", ""] ["a", "xx", ""] [.[]|trimstr("")] ["a", "xx", ""] ["a", "xx", ""] [(index(","), rindex(",")), indices(",")] "a,bc,def,ghij,klmno" [1,13,[1,4,8,13]] [ index("aba"), rindex("aba"), indices("aba") ] "xababababax" [1,7,[1,3,5,7]] # trim # \u000b is vertical tab (\v not supported by json) map(trim), map(ltrim), map(rtrim) [" \n\t\r\f\u000b", ""," ", "a", " a ", "abc", " abc ", " abc", "abc "] ["", "", "", "a", "a", "abc", "abc", "abc", "abc"] ["", "", "", "a", "a ", "abc", "abc ", "abc", "abc "] ["", "", "", "a", " a", "abc", " abc", " abc", "abc"] trim, ltrim, rtrim "\u0009\u000A\u000B\u000C\u000D\u0020\u0085\u00A0\u1680\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200A\u2028\u2029\u202F\u205F\u3000abc\u0009\u000A\u000B\u000C\u000D\u0020\u0085\u00A0\u1680\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200A\u2028\u2029\u202F\u205F\u3000" "abc" "abc\u0009\u000A\u000B\u000C\u000D\u0020\u0085\u00A0\u1680\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200A\u2028\u2029\u202F\u205F\u3000" "\u0009\u000A\u000B\u000C\u000D\u0020\u0085\u00A0\u1680\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200A\u2028\u2029\u202F\u205F\u3000abc" try trim catch ., try ltrim catch ., try rtrim catch . 123 "trim input must be a string" "trim input must be a string" "trim input must be a string" 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] index("!") "здравствуй мир!" 14 .[:rindex("x")] "正xyz" "正" indices("o") "🇬🇧oo" [2,3] indices("o") "ƒoo" [1,2] [.[]|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"] [.[] * "abc"] [-1.0, -0.5, 0.0, 0.5, 1.0, 1.5, 3.7, 10.0] [null,null,"","","abc","abc","abcabcabc","abcabcabcabcabcabcabcabcabcabc"] [. * (nan,-nan)] "abc" [null,null] . * 100000 | [.[:10],.[-10:]] "abc" ["abcabcabca","cabcabcabc"] . * 1000000000 "" "" try (. * 1000000000) catch . "abc" "Repeat string result too long" [.[] / ","] ["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] map(.[1] as $needle | .[0] | contains($needle)) [[["foobar", "foobaz"], ["baz", "bar"]], [["foobar", "foobaz"], ["foo"]], [["foobar", "foobaz"], ["blap"]]] [true, true, false] [({foo: 12, bar:13} | contains({foo: 12})), ({foo: 12} | contains({})), ({foo: 12, bar:13} | contains({baz:14}))] {} [true, true, false] {foo: {baz: 12, blap: {bar: 13}}, bar: 14} | contains({bar: 14, foo: {blap: {}}}) {} true {foo: {baz: 12, blap: {bar: 13}}, bar: 14} | contains({bar: 14, foo: {blap: {bar: 14}}}) {} false sort [42,[2,5,3,11],10,{"a":42,"b":2},{"a":42},true,2,[2,6],"hello",null,[2,5,6],{"a":[],"b":1},"abc","ab",[3,10],{},false,"abcd",null] [null,null,false,true,2,10,42,"ab","abc","abcd","hello",[2,5,3,11],[2,5,6],[2,6],[3,10],{},{"a":42},{"a":42,"b":2},{"a":[],"b":1}] (sort_by(.b) | sort_by(.a)), sort_by(.a, .b), sort_by(.b, .c), group_by(.b), group_by(.a + .b - .c == 2) [{"a": 1, "b": 4, "c": 14}, {"a": 4, "b": 1, "c": 3}, {"a": 1, "b": 4, "c": 3}, {"a": 0, "b": 2, "c": 43}] [{"a": 0, "b": 2, "c": 43}, {"a": 1, "b": 4, "c": 14}, {"a": 1, "b": 4, "c": 3}, {"a": 4, "b": 1, "c": 3}] [{"a": 0, "b": 2, "c": 43}, {"a": 1, "b": 4, "c": 14}, {"a": 1, "b": 4, "c": 3}, {"a": 4, "b": 1, "c": 3}] [{"a": 4, "b": 1, "c": 3}, {"a": 0, "b": 2, "c": 43}, {"a": 1, "b": 4, "c": 3}, {"a": 1, "b": 4, "c": 14}] [[{"a": 4, "b": 1, "c": 3}], [{"a": 0, "b": 2, "c": 43}], [{"a": 1, "b": 4, "c": 14}, {"a": 1, "b": 4, "c": 3}]] [[{"a": 1, "b": 4, "c": 14}, {"a": 0, "b": 2, "c": 43}], [{"a": 4, "b": 1, "c": 3}, {"a": 1, "b": 4, "c": 3}]] 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"]] [min,max,min_by(.),max_by(.)] [] [null,null,null,null] .foo[.baz] {"foo":{"bar":4},"baz":"bar"} 4 .[] | .error = "no, it's OK" [{"error":true}] {"error": "no, it's OK"} [{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}, {"name":"c", "value":3}, {"Name":"d", "Value":4}] {"a": 1, "b": 2, "c": 3, "d": 4} 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] has(nan) [0,1,2] false 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(0) [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] try flatten(-1) catch . [0, [1], [[2]], [[[3]]]] "flatten depth must not be negative" transpose [[1], [2,3]] [[1,2],[null,3]] transpose [] [] ascii_upcase "useful but not for é" "USEFUL BUT NOT FOR é" bsearch(0,1,2,3,4) [1,2,3] -1 0 1 2 -4 bsearch({x:1}) [{ "x": 0 },{ "x": 1 },{ "x": 2 }] 1 try ["OK", bsearch(0)] catch ["KO",.] "aa" ["KO","string (\"aa\") cannot be searched from"] strftime("%Y-%m-%dT%H:%M:%SZ") [2015,2,5,23,51,47,4,63] "2015-03-05T23:51:47Z" strftime("%A, %B %d, %Y") 1435677542.822351 "Tuesday, June 30, 2015" strftime("%Y-%m-%dT%H:%M:%SZ") [2024,2,15] "2024-03-15T00:00:00Z" mktime [2024,8,21] 1726876800 gmtime 1425599507 [2015,2,5,23,51,47,4,63] gmtime[5] 1425599507.25 47.25 # test invalid tm input try strftime("%Y-%m-%dT%H:%M:%SZ") catch . ["a",1,2,3,4,5,6,7] "strftime/1 requires parsed datetime inputs" try strflocaltime("%Y-%m-%dT%H:%M:%SZ") catch . ["a",1,2,3,4,5,6,7] "strflocaltime/1 requires parsed datetime inputs" try mktime catch . ["a",1,2,3,4,5,6,7] "mktime requires parsed datetime inputs" # oss-fuzz #67403: non-string argument with number input fails assert try ["OK", strftime([])] catch ["KO", .] 0 ["KO","strftime/1 requires a string format"] try ["OK", strflocaltime({})] catch ["KO", .] 0 ["KO","strflocaltime/1 requires a string format"] [strptime("%Y-%m-%dT%H:%M:%SZ")|(.,mktime)] "2015-03-05T23:51:47Z" [[2015,2,5,23,51,47,4,63],1425599507] # Check day-of-week and day of year computations # (should trip an assert if this fails) last(range(365 * 67)|("1970-03-01T01:02:03Z"|strptime("%Y-%m-%dT%H:%M:%SZ")|mktime) + (86400 * .)|strftime("%Y-%m-%dT%H:%M:%SZ")|strptime("%Y-%m-%dT%H:%M:%SZ")) null [2037,1,11,1,2,3,3,41] # module system import "a" as foo; import "b" as bar; def fooa: foo::a; [fooa, bar::a, bar::b, foo::a] null ["a","b","c","a"] import "c" as foo; [foo::a, foo::c] null [0,"acmehbah"] include "c"; [a, c] null [0,"acmehbah"] import "data" as $e; import "data" as $d; [$d[].this,$e[].that,$d::d[].this,$e::e[].that]|join(";") null "is a test;is too;is a test;is too" # Regression test for #2000 import "data" as $a; import "data" as $b; def f: {$a, $b}; f null {"a":[{"this":"is a test","that":"is too"}],"b":[{"this":"is a test","that":"is too"}]} include "shadow1"; e null 2 include "shadow1"; include "shadow2"; e null 3 import "shadow1" as f; import "shadow2" as f; import "shadow1" as e; [e::e, f::e] null [2,3] %%FAIL module (.+1); 0 jq: error: Module metadata must be constant at , line 1, column 8: module (.+1); 0 ^^^^^ %%FAIL module []; 0 jq: error: Module metadata must be an object at , line 1, column 8: module []; 0 ^^ %%FAIL include "a" (.+1); 0 jq: error: Module metadata must be constant at , line 1, column 13: include "a" (.+1); 0 ^^^^^ %%FAIL include "a" []; 0 jq: error: Module metadata must be an object at , line 1, column 13: include "a" []; 0 ^^ %%FAIL include "\ "; 0 jq: error: Invalid escape at line 1, column 4 (while parsing '"\ "') at , line 1, column 10: include "\ "; 0 ^^ %%FAIL include "\(a)"; 0 jq: error: Import path must be constant at , line 1, column 9: include "\(a)"; 0 ^^^^^^ modulemeta "c" {"whatever":null,"deps":[{"as":"foo","is_data":false,"relpath":"a"},{"search":"./","as":"d","is_data":false,"relpath":"d"},{"search":"./","as":"d2","is_data":false,"relpath":"d"},{"search":"./../lib/jq","as":"e","is_data":false,"relpath":"e"},{"search":"./../lib/jq","as":"f","is_data":false,"relpath":"f"},{"as":"d","is_data":true,"relpath":"data"}],"defs":["a/0","c/0"]} modulemeta | .deps | length "c" 6 modulemeta | .defs | length "c" 2 %%FAIL IGNORE MSG import "syntaxerror" as e; . jq: error: syntax error, unexpected ';', expecting end of file at tests/modules/syntaxerror/syntaxerror.jq, line 1, column 4: wat; ^ %%FAIL %::wat jq: error: syntax error, unexpected '%', expecting end of file at , line 1, column 1: %::wat ^ import "test_bind_order" as check; check::check null true try -. catch . "very-long-long-long-long-string" "string (\"very-long-long-long-long...\") cannot be negated" try (.-.) catch . "very-long-long-long-long-string" "string (\"very-long-long-long-long...\") and string (\"very-long-long-long-long...\") cannot be subtracted" "x" * range(0; 12; 2) + "☆" * 8 | try -. catch . null "string (\"☆☆☆☆☆☆☆☆\") cannot be negated" "string (\"xx☆☆☆☆☆☆☆☆\") cannot be negated" "string (\"xxxx☆☆☆☆☆☆...\") cannot be negated" "string (\"xxxxxx☆☆☆☆☆☆...\") cannot be negated" "string (\"xxxxxxxx☆☆☆☆☆...\") cannot be negated" "string (\"xxxxxxxxxx☆☆☆☆...\") cannot be negated" try (. + "x") catch . == if have_decnum then "number (12345678901234567890123456...) and string (\"x\") cannot be added" else "number (12345678901234568000000000...) and string (\"x\") cannot be added" end 123456789012345678901234567890 true join(",") ["1",2,true,false,3.4] "1,2,true,false,3.4" .[] | join(",") [[], [null], [null,null], [null,null,null]] "" "" "," ",," .[] | join(",") [["a",null], [null,"a"]] "a," ",a" try join(",") catch . ["1","2",{"a":{"b":{"c":33}}}] "string (\"1,2,\") and object ({\"a\":{\"b\":{\"c\":33}}}) cannot be added" try join(",") catch . ["1","2",[3,4,5]] "string (\"1,2,\") and array ([3,4,5]) cannot be added" {if:0,and:1,or:2,then:3,else:4,elif:5,end:6,as:7,def:8,reduce:9,foreach:10,try:11,catch:12,label:13,import:14,include:15,module:16} null {"if":0,"and":1,"or":2,"then":3,"else":4,"elif":5,"end":6,"as":7,"def":8,"reduce":9,"foreach":10,"try":11,"catch":12,"label":13,"import":14,"include":15,"module":16} try (1/.) catch . 0 "number (1) and number (0) cannot be divided because the divisor is zero" try (1/0) catch . 0 "number (1) and number (0) cannot be divided because the divisor is zero" try (0/0) catch . 0 "number (0) and number (0) cannot be divided because the divisor is zero" try (1%.) catch . 0 "number (1) and number (0) cannot be divided (remainder) because the divisor is zero" try (1%0) catch . 0 "number (1) and number (0) cannot be divided (remainder) because the divisor is zero" # Basic numbers tests: integers, powers of two [range(-52;52;1)] as $powers | [$powers[]|pow(2;.)|log2|round] == $powers null true [range(-99/2;99/2;1)] as $orig | [$orig[]|pow(2;.)|log2] as $back | ($orig|keys)[]|. as $k | (($orig|.[$k])-($back|.[$k]))|if . < 0 then . * -1 else . end|select(.>.00005) null %%FAIL { jq: error: syntax error, unexpected end of file at , line 1, column 1: { ^ %%FAIL } jq: error: syntax error, unexpected INVALID_CHARACTER, expecting end of file at , line 1, column 1: } ^ (.[{}] = 0)? null INDEX(range(5)|[., "foo\(.)"]; .[0]) null {"0":[0,"foo0"],"1":[1,"foo1"],"2":[2,"foo2"],"3":[3,"foo3"],"4":[4,"foo4"]} JOIN({"0":[0,"abc"],"1":[1,"bcd"],"2":[2,"def"],"3":[3,"efg"],"4":[4,"fgh"]}; .[0]|tostring) [[5,"foo"],[3,"bar"],[1,"foobar"]] [[[5,"foo"],null],[[3,"bar"],[3,"efg"]],[[1,"foobar"],[1,"bcd"]]] range(5;10)|IN(range(10)) null true true true true true range(5;13)|IN(range(0;10;3)) null false true false false true false false false range(10;12)|IN(range(10)) null false false IN(range(10;20); range(10)) null false IN(range(5;20); range(10)) null true # Regression test for #1347 (.a as $x | .b) = "b" {"a":null,"b":null} {"a":null,"b":"b"} # Regression test for #1368 (.. | select(type == "object" and has("b") and (.b | type) == "array")|.b) |= .[0] {"a": {"b": [1, {"b": 3}]}} {"a": {"b": 1}} isempty(empty) null true isempty(range(3)) null false isempty(1,error("foo")) null false # Regression test for #1815 index("") "" null # check that dead code removal occurs after builtin it generation builtins|length > 10 null true "-1"|IN(builtins[] / "/"|.[1]) null false all(builtins[] / "/"; .[1]|tonumber >= 0) null true builtins|any(.[:1] == "_") null false ## Test ability to use keywords (uncomment after eval is pushed) #(.[] as $kw | "\"{\($kw)} as $\($kw) | $\($kw) | {$\($kw)} | {\($kw):.\($kw)}\""|eval|empty),null #["as","def","module","import","include","if","then","else","elif","end","reduce","foreach","and","or","try","catch","label","break","__loc__"] #null # #(.[] as $kw | "\"def f($\($kw)): $\($kw); f(.)\""|eval|empty),null #["as","def","module","import","include","if","then","else","elif","end","reduce","foreach","and","or","try","catch","label","break","__loc__"] #null # # Tests to cover the new toliteral number functionality # For an example see #1652 and other linked issues # # We are backward and sanity compatible map(. == 1) [1, 1.0, 1.000, 100e-2, 1e+0, 0.0001e4] [true, true, true, true, true, true] # When no arithmetic is involved jq should preserve the literal value .[0] | tostring | . == if have_decnum then "13911860366432393" else "13911860366432392" end [13911860366432393] true .x | tojson | . == if have_decnum then "13911860366432393" else "13911860366432392" end {"x":13911860366432393} true (13911860366432393 == 13911860366432392) | . == if have_decnum then false else true end null true # Applying arithmetic to the value will truncate the result to double . - 10 13911860366432393 13911860366432382 .[0] - 10 [13911860366432393] 13911860366432382 .x - 10 {"x":13911860366432393} 13911860366432382 # Unary negation preserves numerical precision -. | tojson == if have_decnum then "-13911860366432393" else "-13911860366432392" end 13911860366432393 true -. | tojson == if have_decnum then "0.12345678901234567890123456789" else "0.12345678901234568" end -0.12345678901234567890123456789 true [1E+1000,-1E+1000 | tojson] == if have_decnum then ["1E+1000","-1E+1000"] else ["1.7976931348623157e+308","-1.7976931348623157e+308"] end null true . |= try . catch . 1 1 # decnum to double conversion .[] as $n | $n+0 | [., tostring, . == $n] [-9007199254740993, -9007199254740992, 9007199254740992, 9007199254740993, 13911860366432393] [-9007199254740992,"-9007199254740992",true] [-9007199254740992,"-9007199254740992",true] [9007199254740992,"9007199254740992",true] [9007199254740992,"9007199254740992",true] [13911860366432392,"13911860366432392",true] # abs, fabs, length abs "abc" "abc" map(abs) [-0, 0, -10, -1.1] [0,0,10,1.1] map(fabs) [-0, 0, -10, -1.1] [0,0,10,1.1] map(abs == length) | unique [-10, -1.1, -1e-1, 1000000000000000002] [true] # The following is NOT prescriptive: map(abs) [0.1,1000000000000000002] [1e-1, 1000000000000000002] [1E+1000,-1E+1000 | abs | tojson] | unique == if have_decnum then ["1E+1000"] else ["1.7976931348623157e+308"] end null true [1E+1000,-1E+1000 | length | tojson] | unique == if have_decnum then ["1E+1000"] else ["1.7976931348623157e+308"] end null true # Using a keyword as variable/label name 123 as $label | $label null 123 [ label $if | range(10) | ., (select(. == 5) | break $if) ] null [0,1,2,3,4,5] reduce .[] as $then (4 as $else | $else; . as $elif | . + $then * $elif) [1,2,3] 96 1 as $foreach | 2 as $and | 3 as $or | { $foreach, $and, $or, a } {"a":4,"b":5} {"foreach":1,"and":2,"or":3,"a":4} [ foreach .[] as $try (1 as $catch | $catch - 1; . + $try; .) ] [10,9,8,7] [10,19,27,34] # Object construction { a, $__loc__, c } {"a":[1,2,3],"b":"foo","c":{"hi":"hey"}} {"a":[1,2,3],"__loc__":{"file":"","line":1},"c":{"hi":"hey"}} 1 as $x | "2" as $y | "3" as $z | { $x, as, $y: 4, ($z): 5, if: 6, foo: 7 } {"as":8} {"x":1,"as":8,"2":4,"3":5,"if":6,"foo":7} # nan is parsed as a valid NaN value from JSON fromjson | isnan "nan" true tojson | fromjson {"a":nan} {"a":null} # NaN with payload is not parsed .[] | try (fromjson | isnan) catch . ["NaN","-NaN","NaN1","NaN10","NaN100","NaN1000","NaN10000","NaN100000"] true true "Invalid numeric literal at EOF at line 1, column 4 (while parsing 'NaN1')" "Invalid numeric literal at EOF at line 1, column 5 (while parsing 'NaN10')" "Invalid numeric literal at EOF at line 1, column 6 (while parsing 'NaN100')" "Invalid numeric literal at EOF at line 1, column 7 (while parsing 'NaN1000')" "Invalid numeric literal at EOF at line 1, column 8 (while parsing 'NaN10000')" "Invalid numeric literal at EOF at line 1, column 9 (while parsing 'NaN100000')" # calling input/0, or debug/0 in a test doesn't crash jq try input catch . null "break" debug 1 1 # try/catch catches more than it should #1859 "foo" | try ((try . catch "caught too much") | error) catch "caught just right" null "caught just right" .[]|(try (if .=="hi" then . else error end) catch empty) | "\(.) there!" ["hi","ho"] "hi there!" try (["hi","ho"]|.[]|(try . catch (if .=="ho" then "BROKEN"|error else empty end)) | if .=="ho" then error else "\(.) there!" end) catch "caught outside \(.)" null "hi there!" "caught outside ho" .[]|(try . catch (if .=="ho" then "BROKEN"|error else empty end)) | if .=="ho" then error else "\(.) there!" end ["hi","ho"] "hi there!" try (try error catch "inner catch \(.)") catch "outer catch \(.)" "foo" "inner catch foo" try ((try error catch "inner catch \(.)")|error) catch "outer catch \(.)" "foo" "outer catch inner catch foo" # Also #1859, but from #1885 first(.?,.?) null null # Also #1859, but from #2140 {foo: "bar"} | .foo |= .? null {"foo": "bar"} # Also #1859, but from #2220 . |= try 2 1 2 . |= try 2 catch 3 1 2 .[] |= try tonumber ["1", "2a", "3", " 4", "5 ", "6.7", ".89", "-876", "+5.43", 21] [1, 3, 6.7, 0.89, -876, 5.43, 21] # Also 1859, but from 2073 any(keys[]|tostring?;true) {"a":"1","b":"2","c":"3"} true # explode/implode # test replacement character (65533) for outside codepoint range and 0xd800 (55296) - 0xdfff (57343) utf16 surrogate pair range # 1.1 and 1.9 to test round down of non-ints implode|explode [-1,0,1,2,3,1114111,1114112,55295,55296,57343,57344,1.1,1.9] [65533,0,1,2,3,1114111,65533,55295,65533,65533,57344,1,1] map(try implode catch .) [123,["a"],[nan]] ["implode input must be an array","string (\"a\") can't be imploded, unicode codepoint needs to be numeric","number (null) can't be imploded, unicode codepoint needs to be numeric"] try 0[implode] catch . [] "Cannot index number with string (\"\")" # walk walk(.) {"x":0} {"x":0} walk(1) {"x":0} 1 # The following is a regression test, not a requirement: [walk(.,1)] {"x":0} [{"x":0},1] # Issue #2584 walk(select(IN({}, []) | not)) {"a":1,"b":[]} {"a":1} # #2815 [range(10)] | .[1.2:3.5] null [1,2,3] [range(10)] | .[1.5:3.5] null [1,2,3] [range(10)] | .[1.7:3.5] null [1,2,3] [range(10)] | .[1.7:4294967295] null [1,2,3,4,5,6,7,8,9] [range(10)] | .[1.7:-4294967296] null [] [[range(10)] | .[1.1,1.5,1.7]] null [1,1,1] [range(5)] | .[1.1] = 5 null [0,5,2,3,4] [range(3)] | .[nan:1] null [0] [range(3)] | .[1:nan] null [1,2] [range(3)] | .[nan] null null try ([range(3)] | .[nan] = 9) catch . null "Cannot set array element at NaN index" try ("foobar" | .[1.5:3.5] = "xyz") catch . null "Cannot update string slices" try ([range(10)] | .[1.5:3.5] = ["xyz"]) catch . null [0,"xyz",4,5,6,7,8,9] try ("foobar" | .[1.5]) catch . null "Cannot index string with number (1.5)" # setpath/2 does not leak the input after an invalid get #2970 try ["ok", setpath([1]; 1)] catch ["ko", .] {"hi":"hello"} ["ko","Cannot index object with number (1)"] try fromjson catch . "{'a': 123}" "Invalid string literal; expected \", but got ' at line 1, column 5 (while parsing '{'a': 123}')" # ltrimstr/1 rtrimstr/1 don't leak on invalid input #2977 try ltrimstr(1) catch "x", try rtrimstr(1) catch "x" | "ok" "hi" "ok" "ok" try ltrimstr("x") catch "x", try rtrimstr("x") catch "x" | "ok" {"hey":[]} "ok" "ok" # ltrimstr/1 and rtrimstr/1 return an error for non-strings. #2969 .[] as [$x, $y] | try ["ok", ($x | ltrimstr($y))] catch ["ko", .] [["hi",1],[1,"hi"],["hi","hi"],[1,1]] ["ko","startswith() requires string inputs"] ["ko","startswith() requires string inputs"] ["ok",""] ["ko","startswith() requires string inputs"] .[] as [$x, $y] | try ["ok", ($x | rtrimstr($y))] catch ["ko", .] [["hi",1],[1,"hi"],["hi","hi"],[1,1]] ["ko","endswith() requires string inputs"] ["ko","endswith() requires string inputs"] ["ok",""] ["ko","endswith() requires string inputs"] # oss-fuzz #66061: setpath/2 leaks when indexing array with array try ["OK", setpath([[1]]; 1)] catch ["KO", .] [] ["KO","Cannot update field at array index of array"] # regression test for #3227 foreach .[] as $x (0, 1; . + $x) [1, 2] 1 3 2 4 # regression test for CVE-2025-49014 (use of fmt after free) # tests with both empty string literal and empty string created by function # as they seems to behave reference wise differently. strflocaltime("" | ., @uri) 0 "" "" # regression tests for #3413 # upper range bounds should be in sync with the constants defined at # src/jv_parse.c:#define MAX_PARSING_DEPTH (N) # src/jv_print.c:#define MAX_PRINT_DEPTH (N) # (N-1) reduce range(9999) as $_ ([];[.]) | tojson | fromjson | flatten null [] # (N) reduce range(10000) as $_ ([];[.]) | tojson | try (fromjson) catch . | (contains("") | not) and contains("Exceeds depth limit for parsing") null true # (N+1) reduce range(10001) as $_ ([];[.]) | tojson | contains("") null true ================================================ FILE: tests/jq_fuzz_compile.c ================================================ #include #include #include #include "jq.h" int LLVMFuzzerTestOneInput(uint8_t *data, size_t size) { // Creat null-terminated string char *null_terminated = (char *)malloc(size + 1); memcpy(null_terminated, (char *)data, size); null_terminated[size] = '\0'; // Fuzzer entrypoint jq_state *jq = NULL; jq = jq_init(); if (jq != NULL) { if (jq_compile(jq, null_terminated)) { jq_dump_disassembly(jq, 2); } } jq_teardown(&jq); // Free the null-terminated string free(null_terminated); return 0; } ================================================ FILE: tests/jq_fuzz_execute.cpp ================================================ #include #include #include "jq.h" #include "jv.h" #include "oniguruma.h" extern "C" int LLVMFuzzerInitialize(int *argc, char ***argv) { onig_set_parse_depth_limit(1024); return 0; } // Fuzzer inspired by /src/jq_test.c // The goal is to have the fuzzer execute the functions: // jq_compile -> jv_parse -> jq_next. extern "C" int LLVMFuzzerTestOneInput(uint8_t *data, size_t size) { FuzzedDataProvider fdp(data, size); std::string prog_payload = fdp.ConsumeRandomLengthString(); std::string parse_payload1 = fdp.ConsumeRandomLengthString(); std::string parse_payload2 = fdp.ConsumeRandomLengthString(); jq_state *jq = NULL; jq = jq_init(); if (jq != NULL) { jq_set_attr(jq, jv_string("JQ_ORIGIN"), jv_string("/tmp/")); if (jq_compile(jq, prog_payload.c_str())) { // Process to jv_parse and then jv_next jv input = jv_parse(parse_payload1.c_str()); if (jv_is_valid(input)) { jq_start(jq, input, 0); jv next = jv_parse(parse_payload2.c_str()); if (jv_is_valid(next)) { jv actual = jq_next(jq); jv_free(actual); } jv_free(next); } else { // Only free if input is invalid as otherwise jq_teardown // frees it. jv_free(input); } } } jq_teardown(&jq); return 0; } ================================================ FILE: tests/jq_fuzz_fixed.cpp ================================================ #include #include #include "jq.h" #include "jv.h" const char *jq_progs[] = { ". / \", \"", ".[]", "$ENV.PAGER", ".[0]", ". < 0.12345678901234567890123456788", ".[] == 1", ".[] | (1 / .)?", "10 / . * 3", "[1,2,empty,3]", "1, empty, 2", "[.,1]|until(.[0] < 1; [.[0] - 1, .[1] * .[0]])|.[1]", ".[-2:]", ".[-2]", ".[2]", "[ .[] | . * 2]", ".[2:4]", "(. + 2) * 5", ".[:3]", ".[4,2]", "42 and \"a string\"", "4 - .a", ". < 5", ".. | .a?", "[.[] | .a?]", ".a + 1", "{a: 1} + {b: 2} + {c: 3} + {a: 42}", ".a + .b", ".a = .b", ".a |= .b", "add", "all", ".a + null", "any", ".[] as [$a, $b] | {a: $a, b: $b}", ". as [$a, $b, {c: $c}] | $a + $b + $c", ".[] as {$a, $b, c: {$d}} ?// {$a, $b, c: [{$e}]} | {$a, $b, $d, $e}", ".[] as {$a, $b, c: {$d, $e}} ?// {$a, $b, c: [{$d, $e}]} | {$a, $b, " "$d, $e}", ".[] as [$a] ?// [$b] | if $a != null then error(\"err: \\($a)\") else " "{$a,$b} end", ". as $big | [$big, $big + 1] | map(. > " "10000000000000000000000000000000)", ". as $dot|fromstream($dot|tostream)|.==$dot", ". as $i|[(.*2|. as $i| $i), $i]", "ascii_upcase", ".bar as $x | .foo | . + $x", "@base64", "@base64d", ". == {\"b\": {\"d\": (4 + 1e-20), \"c\": 3}, \"a\":1}", "bsearch(0)", "bsearch(4) as $ix | if $ix < 0 then .[-(1+$ix)] = 4 else . end", "capture(\"(?[a-z]+)-(?[0-9]+)\")", "capture(\"(?[a-z]+)-(?[0-9]+)\")", "combinations", "combinations(2)", "contains(\"bar\")", "contains([\"baz\", \"bar\"])", "contains([\"bazzzzz\", \"bar\"])", "contains({foo: 12, bar: [{barp: 15}]})", "def addvalue(f): f as $x | map(. + $x); addvalue(.[0])", "def addvalue(f): . + [f]; map(addvalue(.[0]))", "def while(cond; update): def _while: if cond then ., (update | " "_while) else empty end; _while; [while(.<100; .*2)]", "del(.[1, 2])", "del(.foo)", "delpaths([[\"a\",\"b\"]])", "empty // 42", "[.[]|endswith(\"foo\")]", "env.PAGER", "explode", ". == false", "(false, null, 1) // 42", "(false, null, 1) | . // 42", "flatten", "flatten(1)", "floor", ".[\"foo\"]", ".[\"foo\"]?", ".foo", ".foo?", ".foo[]", "[.foo?]", ".foo += 1", ".foo // 42", ".foo, .bar", "foreach .[] as $item (0; . + $item)", "foreach .[] as $item (0; . + $item; [$item, . * 2])", "foreach .[] as $item (0; . + 1; {index: ., $item})", "fromdate", "from_entries", "fromstream(1|truncate_stream([[0],1],[[1,0],2],[[1,0]],[[1]]))", "getpath([\"a\",\"b\"])", "[getpath([\"a\",\"b\"], [\"a\",\"c\"])]", "group_by(.foo)", "[.[] | gsub(\", \"; \":\")]", "gsub(\"$\"; \"a\"; \"g\")", "gsub(\"^\"; \"a\")", "[gsub(\"(?.)\"; \"\\(.a|ascii_upcase)\", \"\\(.a|ascii_downcase)\", " "\"c\")]", "gsub(\"^.*?a\"; \"b\")", "gsub(\"^.*a\"; \"b\")", "gsub(\"a\";\"b\")", "gsub(\"\"; \"a\"; \"g\")", "gsub(\"\"; \"a\"; \"g\")", "gsub(\"[^a-z]*(?[a-z]*)\"; \"Z\\(.x)\")", "gsub(\"\\b(?.)\"; \"\\(.x|ascii_downcase)\")", "gsub(\"(?\\d)\"; \":\\(.d);\")", "gsub(\"^\"; \"\"; \"g\")", "[gsub(\"p\"; \"a\", \"b\")]", "gsub(\"(?=u)\"; \"u\")", "gsub(\"(.*)\"; \"\"; \"x\")", "gsub(\"(?.)[^a]*\"; \"+\\(.x)-\")", "gsub(\"(?.)(?[0-9])\"; \"\\(.x|ascii_downcase)\\(.y)\")", "@html", "if . == 0 then \"zero\" elif . == 1 then \"one\" else \"many\" " "end", "implode", "index(\", \")", "index(1)", "index([1,2])", "indices(\", \")", "indices(1)", "indices([1,2])", ".[] | (infinite * .) < 0", "infinite, nan | type", ".[] | in({\"foo\": 42})", "inside({\"foo\": 12, \"bar\":[1,2,{\"barp\":12, \"blip\":13}]})", "inside({\"foo\": 12, \"bar\":[1,2,{\"barp\":12, \"blip\":13}]})", "inside(\"foobar\")", "inside([\"foobar\", \"foobaz\", \"blarp\"])", "inside([\"foobar\", \"foobaz\", \"blarp\"])", "isempty(.[])", "isempty(.[])", "isempty(empty)", "join(\" \")", "join(\", \")", "keys", "keys", ".[] | length", "[limit(3;.[])]", "[.[]|ltrimstr(\"foo\")]", "map(., .)", "map(.+1)", "map([., . == 1]) | tojson", "map(abs)", "map(has(2))", "map(has(\"foo\"))", "map(in([0,1]))", "map(select(. >= 2))", "map(type)", "map_values(.+1)", "map_values(. // empty)", "match(\"(abc)+\"; \"g\")", "[match(\"a\"; \"gi\")]", "[match(\".+?\\b\")]", "[match([\"(bar)\"])]", "match(\"foo\")", "[match([\"foo (?bar)? foo\", \"ig\"])]", "match(\"foo (?bar)? foo\"; \"ig\")", "match([\"foo\", \"ig\"])", "[match(\"\"; \"g\")]", "[ match(\".\"; \"g\")] | length", "[match(\"( )*\"; \"gn\")]", "max_by(.foo)", "min", ".[] | .name", ".[]|numbers", "[path(..)]", "path(.a[0].b)", "[paths]", "[paths(type == \"number\")]", "pick(.[2], .[0], .[0])", "pick(.a, .b.c, .x)", "[range(0; 10; -1)]", "[range(0; 10; 3)]", "[range(0; -5; -1)]", "[range(2; 4)]", "range(2; 4)", "[range(4)]", "[range(.)]|[first, last, nth(5)]", "recurse", "recurse(. * .; . < 20)", "recurse(.foo[])", "reduce .[] as [$i,$j] (0; . + $i * $j)", "reduce .[] as $item (0; . + $item)", "reduce .[] as {$x,$y} (null; .x += $x | .y += [$y])", "[repeat(.*2, error)?]", "reverse", "rindex(\", \")", "rindex(1)", "rindex([1,2])", "[.[]|rtrimstr(\"foo\")]", "[.[] | scan(\", \")]", "[.[] | scan(\"b+\"; \"i\")]", "scan(\"c\")", ".[] | select(.id == \"second\")", "(..|select(type==\"boolean\")) |= if . then 1 else 0 end", "setpath([0,\"a\"]; 1)", "setpath([\"a\",\"b\"]; 1)", "setpath([\"a\",\"b\"]; 1)", "@sh \"echo \\(.)\"", "sort", "sort_by(.foo)", "sort_by(.foo, .bar)", "split(\", *\"; null)", "splits(\", *\")", "sqrt", "[.[]|startswith(\"foo\")]", "strptime(\"%Y-%m-%dT%H:%M:%SZ\")", "strptime(\"%Y-%m-%dT%H:%M:%SZ\")|mktime", "[sub(\"(?.)\"; \"\\(.a|ascii_upcase)\", \"\\(.a|ascii_downcase)\")]", "[sub(\"(?.)\"; \"\\(.a|ascii_upcase)\", \"\\(.a|ascii_downcase)\", " "\"c\")]", "[sub(\"a\"; \"b\", \"c\")]", "sub(\"[^a-z]*(?[a-z]+)\"; \"Z\\(.x)\"; \"g\")", "[.[]|[[sub(\", *\";\":\")], [gsub(\", *\";\":\")], [scan(\", *\")]]]", "[.[]|[[sub(\", +\";\":\")], [gsub(\", +\";\":\")], [scan(\", +\")]]]", "sub(\"^(?.)\"; \"Head=\\(.head) Tail=\")", "[test(\"ā\")]", ".[] | test(\"a b c # spaces are ignored\"; \"ix\")", "test(\"foo\")", "to_entries", "[., tojson]", "[.[]|tojson]", "[.[]|tojson|fromjson]", ".[] | tonumber", "[.[] | tonumber?]", ".[] | tostring", "[.[]|tostring]", "transpose", "[true, false | not]", "(true, false) or false", "(true, true) and (true, false)", "truncate_stream([[0],1],[[1,0],2],[[1,0]],[[1]])", "[.[]|try .a]", "unique", "unique_by(.foo)", "unique_by(length)", ".user, .projects[]", "[.user, .projects[]]", "{(.user): .titles}", "{user, title: .titles[]}", "utf8bytelength", "walk(if type == \"array\" then sort else . end)", "walk( if type == \"object\" then with_entries( .key |= sub( \"^_+\"; " "\"\") ) else . end )", "[while(.<100; .*2)]", "with_entries(.key |= \"KEY_\" + .)", ". - [\"xml\", \"yaml\"]", }; // Fuzzer inspired by /src/jq_test.c // The goal is to have the fuzzer execute the functions: // jq_compile -> jv_parse -> jq_next. extern "C" int LLVMFuzzerTestOneInput(uint8_t *data, size_t size) { FuzzedDataProvider fdp(data, size); std::string parse_payload1 = fdp.ConsumeRandomLengthString(); std::string parse_payload2 = fdp.ConsumeRandomLengthString(); int idx = fdp.ConsumeIntegralInRange( 0, (sizeof(jq_progs) / sizeof(char *)) - 1); jq_state *jq = NULL; jq = jq_init(); if (jq != NULL) { jq_set_attr(jq, jv_string("JQ_ORIGIN"), jv_string("/tmp/")); if (jq_compile(jq, jq_progs[idx])) { // Process to jv_parse and then jv_next jv input = jv_parse(parse_payload1.c_str()); if (jv_is_valid(input)) { jq_start(jq, input, 0); jv next = jv_parse(parse_payload2.c_str()); if (jv_is_valid(next)) { jv actual = jq_next(jq); jv_free(actual); } jv_free(next); } else { // Only free if input is invalid as otherwise jq_teardown // frees it. jv_free(input); } } } jq_teardown(&jq); return 0; } ================================================ FILE: tests/jq_fuzz_load_file.c ================================================ #include #include #include #include "jv.h" int LLVMFuzzerTestOneInput(uint8_t *data, size_t size) { // Create file with fuzzer data char filename[256]; sprintf(filename, "/tmp/libfuzzer.%d", getpid()); FILE *fp = fopen(filename, "wb"); if (!fp) { return 0; } fwrite(data, size, 1, fp); fclose(fp); // Fuzz the two version of jv_load_file jv data1 = jv_load_file(filename, 1); jv_free(data1); jv data2 = jv_load_file(filename, 0); jv_free(data2); // Clean up fuzz file unlink(filename); return 0; } ================================================ FILE: tests/jq_fuzz_parse.c ================================================ #include #include #include #include "jv.h" int LLVMFuzzerTestOneInput(uint8_t *data, size_t size) { // Creat null-terminated string char *null_terminated = (char *)malloc(size + 1); memcpy(null_terminated, (char *)data, size); null_terminated[size] = '\0'; // Fuzzer entrypoint jv res = jv_parse(null_terminated); jv_free(res); // Free the null-terminated string free(null_terminated); return 0; } ================================================ FILE: tests/jq_fuzz_parse_extended.c ================================================ #include #include #include #include "jv.h" int LLVMFuzzerTestOneInput(uint8_t *data, size_t size) { if (size < 8) { return 0; } int fuzz_flags = *(int*)data; data += 4; size -= 4; int dump_flags = *(int*)data; data += 4; size -= 4; // Creat null-terminated string char *null_terminated = (char *)malloc(size + 1); memcpy(null_terminated, (char *)data, size); null_terminated[size] = '\0'; // Fuzzer entrypoint jv res = jv_parse_custom_flags(null_terminated, fuzz_flags); if (jv_is_valid(res)) { jv_dump(res, dump_flags); } else { jv_free(res); } // Free the null-terminated string free(null_terminated); return 0; } ================================================ FILE: tests/jq_fuzz_parse_stream.c ================================================ #include #include #include #include "jv.h" int LLVMFuzzerTestOneInput(uint8_t *data, size_t size) { // Create null-terminated string char *null_terminated = (char *)malloc(size + 1); memcpy(null_terminated, (char *)data, size); null_terminated[size] = '\0'; // Use the iterative jv_parser API for streaming mode. // The single-shot jv_parse_custom_flags() returns "Unexpected extra JSON // values" for any compound JSON in streaming mode, because the streaming // parser produces multiple tokens but the single-shot API expects exactly // one value. jv_parser *parser = jv_parser_new(JV_PARSE_STREAMING); jv_parser_set_buf(parser, null_terminated, (int)size, 0); jv value; while (jv_is_valid(value = jv_parser_next(parser))) { jv_free(value); } jv_free(value); jv_parser_free(parser); // Free the null-terminated string free(null_terminated); return 0; } ================================================ FILE: tests/jqtest ================================================ #!/bin/sh . "${0%/*}/setup" "$@" $VALGRIND $Q $JQ -L "$mods" --run-tests $JQTESTDIR/jq.test ================================================ FILE: tests/local.supp ================================================ { macos valgrind 1 Memcheck:Leak match-leak-kinds: possible fun:calloc fun:map_images_nolock ... fun:_dyld_objc_notify_register fun:_objc_init fun:_os_object_init fun:libdispatch_init fun:libSystem_initializer ... } ================================================ FILE: tests/man.test ================================================ . "Hello, world!" "Hello, world!" . 0.12345678901234567890123456789 0.12345678901234567890123456789 [., tojson] == if have_decnum then [12345678909876543212345,"12345678909876543212345"] else [12345678909876543000000,"12345678909876543000000"] end 12345678909876543212345 true [1234567890987654321,-1234567890987654321 | tojson] == if have_decnum then ["1234567890987654321","-1234567890987654321"] else ["1234567890987654400","-1234567890987654400"] end null true . < 0.12345678901234567890123456788 0.12345678901234567890123456789 false map([., . == 1]) | tojson == if have_decnum then "[[1,true],[1.000,true],[1.0,true],[1.00,true]]" else "[[1,true],[1,true],[1,true],[1,true]]" end [1, 1.000, 1.0, 100e-2] true . as $big | [$big, $big + 1] | map(. > 10000000000000000000000000000000) | . == if have_decnum then [true, false] else [false, false] end 10000000000000000000000000000001 true .foo {"foo": 42, "bar": "less interesting data"} 42 .foo {"notfoo": true, "alsonotfoo": false} null .["foo"] {"foo": 42} 42 .foo? {"foo": 42, "bar": "less interesting data"} 42 .foo? {"notfoo": true, "alsonotfoo": false} null .["foo"]? {"foo": 42} 42 [.foo?] [1,2] [] .[0] [{"name":"JSON", "good":true}, {"name":"XML", "good":false}] {"name":"JSON", "good":true} .[2] [{"name":"JSON", "good":true}, {"name":"XML", "good":false}] null .[-2] [1,2,3] 2 .[2:4] ["a","b","c","d","e"] ["c", "d"] .[2:4] "abcdefghi" "cd" .[:3] ["a","b","c","d","e"] ["a", "b", "c"] .[-2:] ["a","b","c","d","e"] ["d", "e"] .[] [{"name":"JSON", "good":true}, {"name":"XML", "good":false}] {"name":"JSON", "good":true} {"name":"XML", "good":false} .[] [] .foo[] {"foo":[1,2,3]} 1 2 3 .[] {"a": 1, "b": 1} 1 1 .foo, .bar {"foo": 42, "bar": "something else", "baz": true} 42 "something else" .user, .projects[] {"user":"stedolan", "projects": ["jq", "wikiflow"]} "stedolan" "jq" "wikiflow" .[4,2] ["a","b","c","d","e"] "e" "c" .[] | .name [{"name":"JSON", "good":true}, {"name":"XML", "good":false}] "JSON" "XML" (. + 2) * 5 1 15 [.user, .projects[]] {"user":"stedolan", "projects": ["jq", "wikiflow"]} ["stedolan", "jq", "wikiflow"] [ .[] | . * 2] [1, 2, 3] [2, 4, 6] {user, title: .titles[]} {"user":"stedolan","titles":["JQ Primer", "More JQ"]} {"user":"stedolan", "title": "JQ Primer"} {"user":"stedolan", "title": "More JQ"} {(.user): .titles} {"user":"stedolan","titles":["JQ Primer", "More JQ"]} {"stedolan": ["JQ Primer", "More JQ"]} .. | .a? [[{"a":1}]] 1 .a + 1 {"a": 7} 8 .a + .b {"a": [1,2], "b": [3,4]} [1,2,3,4] .a + null {"a": 1} 1 .a + 1 {} 1 {a: 1} + {b: 2} + {c: 3} + {a: 42} null {"a": 42, "b": 2, "c": 3} 4 - .a {"a":3} 1 . - ["xml", "yaml"] ["xml", "yaml", "json"] ["json"] 10 / . * 3 5 6 . / ", " "a, b,c,d, e" ["a","b,c,d","e"] {"k": {"a": 1, "b": 2}} * {"k": {"a": 0,"c": 3}} null {"k": {"a": 0, "b": 2, "c": 3}} .[] | (1 / .)? [1,0,-1] 1 -1 map(abs) [-10, -1.1, -1e-1] [10,1.1,1e-1] .[] | length [[1,2], "string", {"a":2}, null, -5] 2 6 1 0 5 utf8bytelength "\u03bc" 2 keys {"abc": 1, "abcd": 2, "Foo": 3} ["Foo", "abc", "abcd"] keys [42,3,35] [0,1,2] map(has("foo")) [{"foo": 42}, {}] [true, false] map(has(2)) [[0,1], ["a","b","c"]] [false, true] .[] | in({"foo": 42}) ["foo", "bar"] true false map(in([0,1])) [2, 0] [false, true] map(.+1) [1,2,3] [2,3,4] map_values(.+1) {"a": 1, "b": 2, "c": 3} {"a": 2, "b": 3, "c": 4} map(., .) [1,2] [1,1,2,2] map_values(. // empty) {"a": null, "b": true, "c": false} {"b":true} pick(.a, .b.c, .x) {"a": 1, "b": {"c": 2, "d": 3}, "e": 4} {"a":1,"b":{"c":2},"x":null} pick(.[2], .[0], .[0]) [1,2,3,4] [1,null,3] path(.a[0].b) null ["a",0,"b"] [path(..)] {"a":[{"b":1}]} [[],["a"],["a",0],["a",0,"b"]] del(.foo) {"foo": 42, "bar": 9001, "baz": 42} {"bar": 9001, "baz": 42} del(.[1, 2]) ["foo", "bar", "baz"] ["foo"] getpath(["a","b"]) null null [getpath(["a","b"], ["a","c"])] {"a":{"b":0, "c":1}} [0, 1] setpath(["a","b"]; 1) null {"a": {"b": 1}} setpath(["a","b"]; 1) {"a":{"b":0}} {"a": {"b": 1}} setpath([0,"a"]; 1) null [{"a":1}] delpaths([["a","b"]]) {"a":{"b":1},"x":{"y":2}} {"a":{},"x":{"y":2}} 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(select(. >= 2)) [1,5,3,0,7] [5,3,7] .[] | select(.id == "second") [{"id": "first", "val": 1}, {"id": "second", "val": 2}] {"id": "second", "val": 2} .[]|numbers [[],{},1,"foo",null,true,false] 1 1, empty, 2 null 1 2 [1,2,empty,3] null [1,2,3] try error catch . "error message" "error message" try error("invalid value: \(.)") catch . 42 "invalid value: 42" try error("\($__loc__)") catch . null "{\"file\":\"\",\"line\":1}" [paths] [1,[[],{"a":2}]] [[0],[1],[1,0],[1,1],[1,1,"a"]] [paths(type == "number")] [1,[[],{"a":2}]] [[0],[1,1,"a"]] add ["a","b","c"] "abc" add [1, 2, 3] 6 add [] null add(.[].a) [{"a":3}, {"a":5}, {"b":6}] 8 any [true, false] true any [false, false] false any [] false all [true, false] false all [true, true] true all [] true flatten [1, [2], [[3]]] [1, 2, 3] flatten(1) [1, [2], [[3]]] [1, 2, [3]] flatten [[]] [] flatten [{"foo": "bar"}, [{"foo": "baz"}]] [{"foo": "bar"}, {"foo": "baz"}] range(2; 4) null 2 3 [range(2; 4)] null [2,3] [range(4)] null [0,1,2,3] [range(0; 10; 3)] null [0,3,6,9] [range(0; 10; -1)] null [] [range(0; -5; -1)] null [0,-1,-2,-3,-4] floor 3.14159 3 sqrt 9 3 .[] | tonumber [1, "1"] 1 1 .[] | toboolean ["true", "false", true, false] true false true false .[] | tostring [1, "1", [1]] "1" "1" "[1]" map(type) [0, false, [], {}, null, "hello"] ["number", "boolean", "array", "object", "null", "string"] .[] | (infinite * .) < 0 [-1, 1] true false infinite, nan | type null "number" "number" sort [8,3,null,6] [null,3,6,8] sort_by(.foo) [{"foo":4, "bar":10}, {"foo":3, "bar":10}, {"foo":2, "bar":1}] [{"foo":2, "bar":1}, {"foo":3, "bar":10}, {"foo":4, "bar":10}] sort_by(.foo, .bar) [{"foo":4, "bar":10}, {"foo":3, "bar":20}, {"foo":2, "bar":1}, {"foo":3, "bar":10}] [{"foo":2, "bar":1}, {"foo":3, "bar":10}, {"foo":3, "bar":20}, {"foo":4, "bar":10}] group_by(.foo) [{"foo":1, "bar":10}, {"foo":3, "bar":100}, {"foo":1, "bar":1}] [[{"foo":1, "bar":10}, {"foo":1, "bar":1}], [{"foo":3, "bar":100}]] min [5,4,2,7] 2 max_by(.foo) [{"foo":1, "bar":14}, {"foo":2, "bar":3}] {"foo":2, "bar":3} unique [1,2,5,3,5,3,1,3] [1,2,3,5] unique_by(.foo) [{"foo": 1, "bar": 2}, {"foo": 1, "bar": 3}, {"foo": 4, "bar": 5}] [{"foo": 1, "bar": 2}, {"foo": 4, "bar": 5}] unique_by(length) ["chunky", "bacon", "kitten", "cicada", "asparagus"] ["bacon", "chunky", "asparagus"] reverse [1,2,3,4] [4,3,2,1] contains("bar") "foobar" true contains(["baz", "bar"]) ["foobar", "foobaz", "blarp"] true contains(["bazzzzz", "bar"]) ["foobar", "foobaz", "blarp"] false contains({foo: 12, bar: [{barp: 12}]}) {"foo": 12, "bar":[1,2,{"barp":12, "blip":13}]} true contains({foo: 12, bar: [{barp: 15}]}) {"foo": 12, "bar":[1,2,{"barp":12, "blip":13}]} false indices(", ") "a,b, cd, efg, hijk" [3,7,12] indices(1) [0,1,2,1,3,1,4] [1,3,5] indices([1,2]) [0,1,2,3,1,4,2,5,1,2,6,7] [1,8] index(", ") "a,b, cd, efg, hijk" 3 index(1) [0,1,2,1,3,1,4] 1 index([1,2]) [0,1,2,3,1,4,2,5,1,2,6,7] 1 rindex(", ") "a,b, cd, efg, hijk" 12 rindex(1) [0,1,2,1,3,1,4] 5 rindex([1,2]) [0,1,2,3,1,4,2,5,1,2,6,7] 8 inside("foobar") "bar" true inside(["foobar", "foobaz", "blarp"]) ["baz", "bar"] true inside(["foobar", "foobaz", "blarp"]) ["bazzzzz", "bar"] false inside({"foo": 12, "bar":[1,2,{"barp":12, "blip":13}]}) {"foo": 12, "bar": [{"barp": 12}]} true inside({"foo": 12, "bar":[1,2,{"barp":12, "blip":13}]}) {"foo": 12, "bar": [{"barp": 15}]} false [.[]|startswith("foo")] ["fo", "foo", "barfoo", "foobar", "barfoob"] [false, true, false, true, false] [.[]|endswith("foo")] ["foobar", "barfoo"] [false, true] combinations [[1,2], [3, 4]] [1, 3] [1, 4] [2, 3] [2, 4] combinations(2) [0, 1] [0, 0] [0, 1] [1, 0] [1, 1] [.[]|ltrimstr("foo")] ["fo", "foo", "barfoo", "foobar", "afoo"] ["fo","","barfoo","bar","afoo"] [.[]|rtrimstr("foo")] ["fo", "foo", "barfoo", "foobar", "foob"] ["fo","","bar","foobar","foob"] [.[]|trimstr("foo")] ["fo", "foo", "barfoo", "foobarfoo", "foob"] ["fo","","bar","bar","b"] trim, ltrim, rtrim " abc " "abc" "abc " " abc" explode "foobar" [102,111,111,98,97,114] implode [65, 66, 67] "ABC" join(", ") ["a","b,c,d","e"] "a, b,c,d, e" join(" ") ["a",1,2.3,true,null,false] "a 1 2.3 true false" ascii_upcase "useful but not for é" "USEFUL BUT NOT FOR é" [while(.<100; .*2)] 1 [1,2,4,8,16,32,64] [repeat(.*2, error)?] 1 [2] [.,1]|until(.[0] < 1; [.[0] - 1, .[1] * .[0]])|.[1] 4 24 recurse(.foo[]) {"foo":[{"foo": []}, {"foo":[{"foo":[]}]}]} {"foo":[{"foo":[]},{"foo":[{"foo":[]}]}]} {"foo":[]} {"foo":[{"foo":[]}]} {"foo":[]} recurse {"a":0,"b":[1]} {"a":0,"b":[1]} 0 [1] 1 recurse(. * .; . < 20) 2 2 4 16 walk(if type == "array" then sort else . end) [[4, 1, 7], [8, 5, 2], [3, 6, 9]] [[1,4,7],[2,5,8],[3,6,9]] $ENV.PAGER null "less" env.PAGER null "less" transpose [[1], [2,3]] [[1,2],[null,3]] bsearch(0) [0,1] 0 bsearch(0) [1,2,3] -1 bsearch(4) as $ix | if $ix < 0 then .[-(1+$ix)] = 4 else . end [1,2,3] [1,2,3,4] "The input was \(.), which is one less than \(.+1)" 42 "The input was 42, which is one less than 43" [.[]|tostring] [1, "foo", ["foo"]] ["1","foo","[\"foo\"]"] [.[]|tojson] [1, "foo", ["foo"]] ["1","\"foo\"","[\"foo\"]"] [.[]|tojson|fromjson] [1, "foo", ["foo"]] [1,"foo",["foo"]] @html "This works if x < y" "This works if x < y" @sh "echo \(.)" "O'Hara's Ale" "echo 'O'\\''Hara'\\''s Ale'" @base64 "This is a message" "VGhpcyBpcyBhIG1lc3NhZ2U=" @base64d "VGhpcyBpcyBhIG1lc3NhZ2U=" "This is a message" fromdate "2015-03-05T23:51:47Z" 1425599507 strptime("%Y-%m-%dT%H:%M:%SZ") "2015-03-05T23:51:47Z" [2015,2,5,23,51,47,4,63] strptime("%Y-%m-%dT%H:%M:%SZ")|mktime "2015-03-05T23:51:47Z" 1425599507 . == false null false . == {"b": {"d": (4 + 1e-20), "c": 3}, "a":1} {"a":1, "b": {"c": 3, "d": 4}} true .[] == 1 [1, 1.0, "1", "banana"] true true false false if . == 0 then "zero" elif . == 1 then "one" else "many" end 2 "many" . < 5 2 true 42 and "a string" null true (true, false) or false null true false (true, true) and (true, false) null true false true false [true, false | not] null [false, true] empty // 42 null 42 .foo // 42 {"foo": 19} 19 .foo // 42 {} 42 (false, null, 1) // 42 null 1 (false, null, 1) | . // 42 null 42 42 1 try .a catch ". is not an object" true ". is not an object" [.[]|try .a] [{}, true, {"a":1}] [null, 1] try error("some exception") catch . true "some exception" [.[] | .a?] [{}, true, {"a":1}] [null, 1] [.[] | tonumber?] ["1", "invalid", "3", 4] [1, 3, 4] .bar as $x | .foo | . + $x {"foo":10, "bar":200} 210 . as $i|[(.*2|. as $i| $i), $i] 5 [10,5] . as [$a, $b, {c: $c}] | $a + $b + $c [2, 3, {"c": 4, "d": 5}] 9 .[] as [$a, $b] | {a: $a, b: $b} [[0], [0, 1], [2, 1, 0]] {"a":0,"b":null} {"a":0,"b":1} {"a":2,"b":1} .[] as {$a, $b, c: {$d, $e}} ?// {$a, $b, c: [{$d, $e}]} | {$a, $b, $d, $e} [{"a": 1, "b": 2, "c": {"d": 3, "e": 4}}, {"a": 1, "b": 2, "c": [{"d": 3, "e": 4}]}] {"a":1,"b":2,"d":3,"e":4} {"a":1,"b":2,"d":3,"e":4} .[] as {$a, $b, c: {$d}} ?// {$a, $b, c: [{$e}]} | {$a, $b, $d, $e} [{"a": 1, "b": 2, "c": {"d": 3, "e": 4}}, {"a": 1, "b": 2, "c": [{"d": 3, "e": 4}]}] {"a":1,"b":2,"d":3,"e":null} {"a":1,"b":2,"d":null,"e":4} .[] as [$a] ?// [$b] | if $a != null then error("err: \($a)") else {$a,$b} end [[3]] {"a":null,"b":3} def addvalue(f): . + [f]; map(addvalue(.[0])) [[1,2],[10,20]] [[1,2,1], [10,20,10]] def addvalue(f): f as $x | map(. + $x); addvalue(.[0]) [[1,2],[10,20]] [[1,2,1,2], [10,20,1,2]] isempty(empty) null true isempty(.[]) [] true isempty(.[]) [1,2,3] false [limit(3; .[])] [0,1,2,3,4,5,6,7,8,9] [0,1,2] [skip(3; .[])] [0,1,2,3,4,5,6,7,8,9] [3,4,5,6,7,8,9] [first(range(.)), last(range(.)), nth(5; range(.))] 10 [0,9,5] [first(empty), last(empty), nth(5; empty)] null [] [range(.)]|[first, last, nth(5)] 10 [0,9,5] reduce .[] as $item (0; . + $item) [1,2,3,4,5] 15 reduce .[] as [$i,$j] (0; . + $i * $j) [[1,2],[3,4],[5,6]] 44 reduce .[] as {$x,$y} (null; .x += $x | .y += [$y]) [{"x":"a","y":1},{"x":"b","y":2},{"x":"c","y":3}] {"x":"abc","y":[1,2,3]} foreach .[] as $item (0; . + $item) [1,2,3,4,5] 1 3 6 10 15 foreach .[] as $item (0; . + $item; [$item, . * 2]) [1,2,3,4,5] [1,2] [2,6] [3,12] [4,20] [5,30] foreach .[] as $item (0; . + 1; {index: ., $item}) ["foo", "bar", "baz"] {"index":1,"item":"foo"} {"index":2,"item":"bar"} {"index":3,"item":"baz"} def range(init; upto; by): def _range: if (by > 0 and . < upto) or (by < 0 and . > upto) then ., ((.+by)|_range) else empty end; if init == upto then empty elif by == 0 then init else init|_range end; range(0; 10; 3) null 0 3 6 9 def while(cond; update): def _while: if cond then ., (update | _while) else empty end; _while; [while(.<100; .*2)] 1 [1,2,4,8,16,32,64] truncate_stream([[0],"a"],[[1,0],"b"],[[1,0]],[[1]]) 1 [[0],"b"] [[0]] fromstream(1|truncate_stream([[0],"a"],[[1,0],"b"],[[1,0]],[[1]])) null ["b"] . as $dot|fromstream($dot|tostream)|.==$dot [0,[1,{"a":1},{"b":2}]] true (..|select(type=="boolean")) |= if . then 1 else 0 end [true,false,[5,true,[true,[false]],false]] [1,0,[5,1,[1,[0]],0]] .foo += 1 {"foo": 42} {"foo": 43} .a = .b {"a": {"b": 10}, "b": 20} {"a":20,"b":20} .a |= .b {"a": {"b": 10}, "b": 20} {"a":10,"b":20} (.a, .b) = range(3) null {"a":0,"b":0} {"a":1,"b":1} {"a":2,"b":2} (.a, .b) |= range(3) null {"a":0,"b":0} ================================================ FILE: tests/manonig.test ================================================ split(", ") "a, b,c,d, e, " ["a","b,c,d","e",""] walk( if type == "object" then with_entries( .key |= sub( "^_+"; "") ) else . end ) [ { "_a": { "__b": 2 } } ] [{"a":{"b":2}}] test("foo") "foo" true .[] | test("a b c # spaces are ignored"; "ix") ["xabcd", "ABC"] true true match("(abc)+"; "g") "abc abc" {"offset": 0, "length": 3, "string": "abc", "captures": [{"offset": 0, "length": 3, "string": "abc", "name": null}]} {"offset": 4, "length": 3, "string": "abc", "captures": [{"offset": 4, "length": 3, "string": "abc", "name": null}]} match("foo") "foo bar foo" {"offset": 0, "length": 3, "string": "foo", "captures": []} match(["foo", "ig"]) "foo bar FOO" {"offset": 0, "length": 3, "string": "foo", "captures": []} {"offset": 8, "length": 3, "string": "FOO", "captures": []} match("foo (?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"}]} [ match("."; "g")] | length "abc" 3 capture("(?[a-z]+)-(?[0-9]+)") "xyzzy-14" { "a": "xyzzy", "n": "14" } scan("c") "abcdefabc" "c" "c" scan("(a+)(b+)") "abaabbaaabbb" ["a","b"] ["aa","bb"] ["aaa","bbb"] split(", *"; null) "ab,cd, ef" ["ab","cd","ef"] splits(", *") "ab,cd, ef, gh" "ab" "cd" "ef" "gh" splits(",? *"; "n") "ab,cd ef, gh" "ab" "cd" "ef" "gh" sub("[^a-z]*(?[a-z]+)"; "Z\(.x)"; "g") "123abc456def" "ZabcZdef" [sub("(?.)"; "\(.a|ascii_upcase)", "\(.a|ascii_downcase)")] "aB" ["AB","aB"] gsub("(?.)[^a]*"; "+\(.x)-") "Abcabc" "+A-+a-" [gsub("p"; "a", "b")] "p" ["a","b"] ================================================ FILE: tests/manonigtest ================================================ #!/bin/sh . "${0%/*}/setup" "$@" $VALGRIND $Q $JQ -L "$mods" --run-tests $JQBASEDIR/tests/manonig.test ================================================ FILE: tests/mantest ================================================ #!/bin/sh . "${0%/*}/setup" "$@" # We set PAGER because there's a mantest for `env` that uses it. env PAGER=less $VALGRIND $Q $JQ -L "$mods" --run-tests $JQBASEDIR/tests/man.test ================================================ FILE: tests/modules/a.jq ================================================ module {version:1.7}; def a: "a"; ================================================ FILE: tests/modules/b/b.jq ================================================ def a: "b"; def b: "c"; ================================================ FILE: tests/modules/c/c.jq ================================================ module {whatever:null}; import "a" as foo; import "d" as d {search:"./"}; import "d" as d2{search:"./"}; import "e" as e {search:"./../lib/jq"}; import "f" as f {search:"./../lib/jq"}; import "data" as $d; def a: 0; def c: if $d::d[0] != {this:"is a test",that:"is too"} then error("data import is busted") elif d2::meh != d::meh then error("import twice doesn't work") elif foo::a != "a" then error("foo::a didn't work as expected") elif d::meh != "meh" then error("d::meh didn't work as expected") elif e::bah != "bah" then error("e::bah didn't work as expected") elif f::f != "f is here" then error("f::f didn't work as expected") else foo::a + "c" + d::meh + e::bah end; ================================================ FILE: tests/modules/c/d.jq ================================================ def meh: "meh"; ================================================ FILE: tests/modules/data.json ================================================ { "this": "is a test", "that": "is too" } ================================================ FILE: tests/modules/home1/.jq ================================================ def foo: "baz"; def f: "wat"; def f: "foo"; def g: "bar"; def fg: f+g; ================================================ FILE: tests/modules/home2/.jq/g.jq ================================================ def g: 1; ================================================ FILE: tests/modules/shadow1.jq ================================================ def e: 1; def e: 2; ================================================ FILE: tests/modules/shadow2.jq ================================================ def e: 3; ================================================ FILE: tests/modules/syntaxerror/syntaxerror.jq ================================================ wat; ================================================ FILE: tests/modules/test_bind_order.jq ================================================ import "test_bind_order0" as t; import "test_bind_order1" as t; import "test_bind_order2" as t; def check: if [t::sym0,t::sym1,t::sym2] == [0,1,2] then true else false end; ================================================ FILE: tests/modules/test_bind_order0.jq ================================================ def sym0: 0; def sym1: 0; ================================================ FILE: tests/modules/test_bind_order1.jq ================================================ def sym1: 1; def sym2: 1; ================================================ FILE: tests/modules/test_bind_order2.jq ================================================ def sym2: 2; ================================================ FILE: tests/no-main-program.jq ================================================ def a: .; ================================================ FILE: tests/onig.supp ================================================ { 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* ... } ================================================ FILE: tests/onig.test ================================================ # match builtin [match("( )*"; "g")] "abc" [{"offset":0,"length":0,"string":"","captures":[{"offset":-1,"string":null,"length":0,"name":null}]},{"offset":1,"length":0,"string":"","captures":[{"offset":-1,"string":null,"length":0,"name":null}]},{"offset":2,"length":0,"string":"","captures":[{"offset":-1,"string":null,"length":0,"name":null}]},{"offset":3,"length":0,"string":"","captures":[{"offset":-1,"string":null,"length":0,"name":null}]}] [match("( )*"; "gn")] "abc" [] [match(""; "g")] "ab" [{"offset":0,"length":0,"string":"","captures":[]},{"offset":1,"length":0,"string":"","captures":[]},{"offset":2,"length":0,"string":"","captures":[]}] [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 (?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"}]}] # non-matched optional group "a","b","c" | capture("(?a)?b?") null {"x":"a"} {"x":null} {"x":null} "a","b","c" | match("(?a)?b?") null {"offset":0,"length":1,"string":"a","captures":[{"offset":0,"length":1,"string":"a","name":"x"}]} {"offset":0,"length":1,"string":"b","captures":[{"offset":-1,"string":null,"length":0,"name":"x"}]} {"offset":0,"length":0,"string":"","captures":[{"offset":-1,"string":null,"length":0,"name":"x"}]} # same as above but allow empty match for group "a","b","c" | capture("(?a?)?b?") null {"x":"a"} {"x":""} {"x":""} "a","b","c" | match("(?a?)?b?") null {"offset":0,"length":1,"string":"a","captures":[{"offset":0,"length":1,"string":"a","name":"x"}]} {"offset":0,"length":1,"string":"b","captures":[{"offset":0,"string":"","length":0,"name":"x"}]} {"offset":0,"length":0,"string":"","captures":[{"offset":0,"string":"","length":0,"name":"x"}]} #test builtin [test("( )*"; "gn")] "abc" [false] [test("ā")] "ā" [true] capture("(?[a-z]+)-(?[0-9]+)") "xyzzy-14" {"a":"xyzzy","n":"14"} # jq-coded utilities built on match: # # The second element in these tests' inputs tests the case where the # fromstring matches both the head and tail of the string [.[] | sub(", "; ":")] ["a,b, c, d, e,f", ", a,b, c, d, e,f, "] ["a,b:c, d, e,f",":a,b, c, d, e,f, "] sub("^(?.)"; "Head=\(.head) Tail=") "abcdef" "Head=a Tail=bcdef" [.[] | gsub(", "; ":")] ["a,b, c, d, e,f",", a,b, c, d, e,f, "] ["a,b:c:d:e,f",":a,b:c:d:e,f:"] gsub("(?\\d)"; ":\(.d);") "a1b2" "a:1;b:2;" gsub("a";"b") "aaaaa" "bbbbb" gsub("(.*)"; ""; "x") "" "" gsub(""; "a"; "g") "" "a" gsub("^"; ""; "g") "a" "a" gsub(""; "a"; "g") "a" "aaa" gsub("$"; "a"; "g") "a" "aa" gsub("^"; "a") "" "a" gsub("(?=u)"; "u") "qux" "quux" gsub("^.*a"; "b") "aaa" "b" gsub("^.*?a"; "b") "aaa" "baa" # The following is for regression testing and should not be construed as a requirement: [gsub("a"; "b", "c")] "a" ["b","c"] [.[] | scan(", ")] ["a,b, c, d, e,f",", a,b, c, d, e,f, "] [", ",", ",", ",", ",", ",", ",", ",", "] [.[]|[[sub(", *";":")], [gsub(", *";":")], [scan(", *")]]] ["a,b, c, d, e,f",", a,b, c, d, e,f, "] [[["a:b, c, d, e,f"],["a:b:c:d:e:f"],[",",", ",", ",", ",","]],[[":a,b, c, d, e,f, "],[":a:b:c:d:e:f:"],[", ",",",", ",", ",", ",",",", "]]] [.[]|[[sub(", +";":")], [gsub(", +";":")], [scan(", +")]]] ["a,b, c, d, e,f",", a,b, c, d, e,f, "] [[["a,b:c, d, e,f"],["a,b:c:d:e,f"],[", ",", ",", "]],[[":a,b, c, d, e,f, "],[":a,b:c:d:e,f:"],[", ",", ",", ",", ",", "]]] [.[] | scan("b+"; "i")] ["","bBb","abcABBBCabbbc"] ["bBb","b","BBB","bbb"] # reference to named captures gsub("(?.)[^a]*"; "+\(.x)-") "Abcabc" "+A-+a-" gsub("(?.)(?[0-9])"; "\(.x|ascii_downcase)\(.y)") "A1 B2 CD" "a1 b2 CD" gsub("\\b(?.)"; "\(.x|ascii_downcase)") "ABC DEF" "aBC dEF" gsub("[^a-z]*(?[a-z]*)"; "Z\(.x)") "123foo456bar" "ZfooZbarZ" # utf-8 sub("(?.)"; "\(.x)!") "’" "’!" [sub("a"; "b", "c")] "a" ["b","c"] [sub("(?.)"; "\(.a|ascii_upcase)", "\(.a|ascii_downcase)", "c")] "aB" ["AB","aB","cB"] [gsub("(?.)"; "\(.a|ascii_upcase)", "\(.a|ascii_downcase)", "c")] "aB" ["AB","ab","cc"] # splits [splits("")] "ab" ["","a","b",""] [splits("c")] "ab" ["ab"] [splits("a+"; "i")] "abAABBabA" ["","b","BB","b",""] [splits("b+"; "i")] "abAABBabA" ["a","AA","a","A"] ================================================ FILE: tests/onigtest ================================================ #!/bin/sh . "${0%/*}/setup" "$@" $VALGRIND $Q $JQ -L "$mods" --run-tests $JQTESTDIR/onig.test ================================================ FILE: tests/optional.test ================================================ # See tests/jq.test and the jq manual for more information. # Regression test for #3276 (fails on mingw/WIN32) fromdate "2038-01-19T03:14:08Z" 2147483648 # %e is not available on mingw/WIN32 strftime("%A, %B %e, %Y") 1435677542.822351 "Tuesday, June 30, 2015" ================================================ FILE: tests/optionaltest ================================================ #!/bin/sh . "${0%/*}/setup" "$@" $VALGRIND $Q $JQ -L "$mods" --run-tests $JQTESTDIR/optional.test ================================================ FILE: tests/setup ================================================ #!/bin/sh # This is meant to be included by each test's shell script driver. if [ -n "$TRACE_TESTS" ]; then set -x fi set -eu JQTESTDIR=$(cd "$(dirname "$0")" && pwd) JQBASEDIR=$JQTESTDIR/.. JQ=${JQ:-$JQBASEDIR/jq} # Some tests have locale-dependent output; use C locale. Fixes #3038 LC_ALL=C export LC_ALL if [ -n "${ENABLE_VALGRIND-}" ] && which valgrind > /dev/null; then VALGRIND="valgrind --error-exitcode=1 --leak-check=full \ --suppressions=$JQTESTDIR/onig.supp \ --suppressions=$JQTESTDIR/local.supp" VG_EXIT0=--error-exitcode=0 Q=-q else VALGRIND= VG_EXIT0= Q= fi mods=$JQTESTDIR/modules clean=true d= clean () { if ! $clean; then echo "See temp files in $d!" elif [ -n "$d" ]; then rm -rf "$d" fi } trap clean EXIT d=$(mktemp -d -t jqXXXXXX || true) if [ -z "$d" ]; then echo "Your OS does not support mktemp(1) -d" 1>&2 exit 1 fi ================================================ FILE: tests/shtest ================================================ #!/bin/sh -x . "${0%/*}/setup" "$@" msys=false mingw=false case "$(uname -s)" in MSYS*) msys=true;; MINGW*) mingw=true;; esac JQ_NO_B=$JQ JQ="$JQ -b" PATH=$JQBASEDIR:$PATH $JQBASEDIR/tests/jq-f-test.sh > /dev/null SHELL=/bin/sh export SHELL unset JQ_COLORS unset NO_COLOR if [ -f "$JQBASEDIR/.libs/libinject_errors.so" ]; then # Do some simple error injection tests to check that we're handling # I/O errors correctly. ( libinject=$JQBASEDIR/.libs/libinject_errors.so cd $d LD_PRELOAD=$libinject $JQ . /dev/null touch fail_read LD_PRELOAD=$libinject $JQ . fail_read && exit 2 touch fail_close LD_PRELOAD=$libinject $JQ . fail_close && exit 2 true ) fi printf 'a\0b\nc\0d\ne' > $d/input $VALGRIND $Q $JQ -Rse '. == "a\u0000b\nc\u0000d\ne"' $d/input $VALGRIND $Q $JQ -Rne '[inputs] == ["a\u0000b", "c\u0000d", "e"]' $d/input ## Test constant folding nref=$($VALGRIND $Q $JQ -n --debug-dump-disasm '"foo"' | wc -l) for exp in '1+1' '1-1' '2*3' '9/3' '9%3' '9==3' '9!=3' \ '9<3' '9>3' '9<=3' '9>=3' '1+2*3-4/5%6' '"foo" + "bar"'; do n=$($VALGRIND $Q $JQ -n --debug-dump-disasm "$exp" | wc -l) if [ $n -ne $nref ]; then echo "Constant expression folding didn't work: $exp" exit 1 fi done ## Test JSON sequence support cat > $d/expected < /dev/null 2> $d/out cmp $d/out $d/expected cat > $d/expected < /dev/null 2> $d/out cmp $d/out $d/expected # Note that here jq sees no inputs at all but it still succeeds because # --seq ignores parse errors cat > $d/expected < $d/out 2>&1 cmp $d/out $d/expected # with -e option should give 4 here as there's no valid output after # ignoring parse errors with --seq. printf '"foo' | $JQ -ce --seq . > $d/out 2>&1 || ret=$? [ $ret -eq 4 ] cmp $d/out $d/expected # Numeric values truncated by EOF are ignored cat > $d/expected < $d/out 2>&1 cmp $d/out $d/expected cat > $d/expected <:1): Unfinished abandoned text at EOF at line 2, column 0 EOF if printf '1\n' | $JQ -cen --seq '[inputs] == []' >/dev/null 2> $d/out; then printf 'Error expected but jq exited successfully\n' 1>&2 exit 2 fi cmp $d/out $d/expected # Test control characters for #2909 cat > $d/expected < $d/out 2>&1; then printf 'Error expected but jq exited successfully\n' 1>&2 exit 2 fi cmp $d/out $d/expected done printf '" ~\\u007f"\n' > $d/expected printf "\"$(printf '\\%03o' 32 126 127)\"" | $JQ '.' > $d/out 2>&1 cmp $d/out $d/expected ## Test --exit-status data='{"i": 1}\n{"i": 2}\n{"i": 3}\n' printf "$data" | $JQ --exit-status 'select(.i==1)' > /dev/null 2>&1 printf "$data" | $JQ --exit-status 'select(.i==2)' > /dev/null 2>&1 printf "$data" | $JQ --exit-status 'select(.i==3)' > /dev/null 2>&1 ret=0 printf "$data" | $JQ --exit-status 'select(.i==4)' > /dev/null 2>&1 || ret=$? [ $ret -eq 4 ] ret=0 printf "$data" | $JQ --exit-status 'select(.i==2) | false' > /dev/null 2>&1 || ret=$? [ $ret -eq 1 ] printf "$data" | $JQ --exit-status 'select(.i==2) | true' > /dev/null 2>&1 # Regression test for #951 printf '"a\n' > $d/input if $VALGRIND $Q $JQ -e . $d/input; then printf 'Issue #951 is back?\n' 1>&2 exit 2 fi # Regression test for #2146 if echo "foobar" | $JQ .; then printf 'Issue #2146 is back?\n' 1>&2 exit 1 elif [ $? -ne 5 ]; then echo "Invalid input had wrong error code" 1>&2 exit 1 fi # Regression test for #2367; make sure to call jq twice if ! echo '{"a": 1E9999999999}' | $JQ . | $JQ -e .a; then printf 'Issue #2367 is back?\n' 1>&2 exit 1 fi # Regression test for #1534 echo "[1,2,3,4]" > $d/expected printf "[1,2][3,4]" | $JQ -cs add > $d/out 2>&1 cmp $d/out $d/expected printf "[1,2][3,4]\n" | $JQ -cs add > $d/out 2>&1 cmp $d/out $d/expected # Regression test for #3273 echo "[[[0],1],[[0]],[[0],2],[[0]]]" > $d/expected printf "[1][2]" | $JQ -c -s --stream . > $d/out 2>&1 cmp $d/out $d/expected printf "[1][2]\n" | $JQ -c -s --stream . > $d/out 2>&1 cmp $d/out $d/expected # Regression test for --raw-output0 printf "a\0b\0" > $d/expected printf '["a", "b"]' | $VALGRIND $Q $JQ --raw-output0 '.[]' > $d/out cmp $d/out $d/expected printf "a\0" > $d/expected if printf '["a", "c\\u0000d", "b"]' | $VALGRIND $Q $JQ --raw-output0 '.[]' > $d/out; then echo "Should exit error on string containing NUL with --raw-output0" 1>&2 exit 1 elif [ $? -ne 5 ]; then echo "Invalid error code" 1>&2 exit 1 else cmp $d/out $d/expected fi # Regression tests for #3194 echo 42 > $d/expected $JQ -nn 42 > $d/out 2>&1 cmp $d/out $d/expected $JQ -nL. 42 > $d/out 2>&1 cmp $d/out $d/expected $JQ -nL . 42 > $d/out 2>&1 cmp $d/out $d/expected $JQ -h > $d/expected 2>&1 $JQ -hV > $d/out 2>&1 cmp $d/out $d/expected $JQ -h -V > $d/out 2>&1 cmp $d/out $d/expected $JQ -V > $d/expected 2>&1 $JQ -Vh > $d/out 2>&1 cmp $d/out $d/expected $JQ -V -h > $d/out 2>&1 cmp $d/out $d/expected # CRLF line break support #1219 if ! x=$($JQ -n "$(printf '1\r\n+\r\n2')") || [ "$x" != '3' ]; then echo 'CRLF line break support failed?' 1>&2 exit 1 fi ## Test streaming parser ## If we add an option to stream to the `import ... as $symbol;` directive ## then we can move these tests into tests/all.test. $VALGRIND $Q $JQ -c '. as $d|path(..) as $p|$d|getpath($p)|select((type|. != "array" and . != "object") or length==0)|[$p,.]' < "$JQTESTDIR/torture/input0.json" > $d/out0 $VALGRIND $Q $JQ --stream -c '.|select(length==2)' < "$JQTESTDIR/torture/input0.json" > $d/out1 diff $d/out0 $d/out1 printf '["Unfinished JSON term at EOF at line 1, column 1",[0]]\n' > $d/expected printf '[' | $VALGRIND $Q $JQ --stream-errors -c . > $d/out 2>&1 diff $d/out $d/expected ## XXX This test can be moved to tests/all.test _now_ clean=false if which seq > /dev/null 2>&1; then # XXX We should try every prefix of input0.json, but that makes this # test very, very slow when run with valgrind, and the whole point # is to run it with valgrind. # #len=$(wc -c < "$JQTESTDIR/torture/input0.json") if [ -z "$VALGRIND" ]; then start=1 end=$(wc -c < "$JQTESTDIR/torture/input0.json") else start=120 end=151 fi for i in $(seq $start $end); do dd "if=tests/torture/input0.json" bs=$i count=1 2>/dev/null | $VALGRIND $JQ -c . > $d/out0 2>$d/err || true if [ -n "$VALGRIND" ]; then grep '^==[0-9][0-9]*== ERROR SUMMARY: 0 errors' $d/err > /dev/null else tail -n1 -- "$d/err" | grep -Ei 'assert|abort|core' && false fi dd "if=tests/torture/input0.json" bs=$i count=1 2>/dev/null | $VALGRIND $JQ -cn --stream 'fromstream(inputs)' > $d/out1 2>$d/err || true if [ -n "$VALGRIND" ]; then grep '^==[0-9][0-9]*== ERROR SUMMARY: 0 errors' $d/err > /dev/null else tail -n1 -- "$d/err" | grep -Ei 'assert|abort|core' && false fi diff $d/out0 $d/out1 done else echo "Not doing torture tests" fi ## Regression test for issue #2378 assert when stream parse broken object pair echo '{"a":1,"b",' | $JQ --stream > /dev/null 2> $d/err || true grep 'Objects must consist of key:value pairs' $d/err > /dev/null ## Regression tests for issue #2463 assert when stream parse non-scalar object key echo '{{"a":"b"}}' | $JQ --stream > /dev/null 2> $d/err || true grep "Expected string key after '{', not '{'" $d/err > /dev/null echo '{"x":"y",{"a":"b"}}' | $JQ --stream > /dev/null 2> $d/err || true grep "Expected string key after ',' in object, not '{'" $d/err > /dev/null echo '{["a","b"]}' | $JQ --stream > /dev/null 2> $d/err || true grep "Expected string key after '{', not '\\['" $d/err > /dev/null echo '{"x":"y",["a","b"]}' | $JQ --stream > /dev/null 2> $d/err || true grep "Expected string key after ',' in object, not '\\['" $d/err > /dev/null # debug, stderr $VALGRIND $Q $JQ -n '"test", {} | debug, stderr' >/dev/null $JQ -n -c -j '"hello\nworld", null, [false, 0], {"foo":["bar"]}, "\n" | stderr' >$d/out 2>$d/err cat > $d/expected <<'EOF' hello worldnull[false,0]{"foo":["bar"]} EOF cmp $d/out $d/expected cmp $d/err $d/expected # --arg, --argjson, $ARGS.named $VALGRIND $JQ -n -c --arg foo 1 --argjson bar 2 '{$foo, $bar} | ., . == $ARGS.named' > $d/out printf '{"foo":"1","bar":2}\ntrue\n' > $d/expected cmp $d/out $d/expected # --slurpfile, --rawfile $VALGRIND $JQ -n --slurpfile foo $JQBASEDIR/tests/modules/data.json \ --rawfile bar $JQBASEDIR/tests/modules/data.json '{$foo, $bar}' > $d/out cat > $d/expected <<'EOF' { "foo": [ { "this": "is a test", "that": "is too" } ], "bar": "{\n \"this\": \"is a test\",\n \"that\": \"is too\"\n}\n" } EOF cmp $d/out $d/expected # --args, --jsonargs, $ARGS.positional $VALGRIND $JQ -n -c --args '$ARGS.positional' foo bar baz > $d/out printf '["foo","bar","baz"]\n' > $d/expected cmp $d/out $d/expected $VALGRIND $JQ -n -c --jsonargs '$ARGS.positional' null true '[]' '{}' > $d/out printf '[null,true,[],{}]\n' > $d/expected cmp $d/out $d/expected $VALGRIND $JQ -n -c '$ARGS.positional' --args foo 1 --jsonargs 2 '{}' --args 3 4 > $d/out printf '["foo","1",2,{},"3","4"]\n' > $d/expected cmp $d/out $d/expected $VALGRIND $JQ -n -c '$ARGS.positional' --args --jsonargs > $d/out printf '[]\n' > $d/expected cmp $d/out $d/expected ## Regression test for issue #2572 assert when using --jsonargs and invalid JSON $VALGRIND $JQ -n --jsonargs null invalid && EC=$? || EC=$? if [ "$EC" -ne 2 ]; then echo "--jsonargs exited with wrong exit code, expected 2 got $EC" 1>&2 exit 1 fi # this tests the args_done code path "--" $VALGRIND $JQ -n --jsonargs null -- invalid && EC=$? || EC=$? if [ "$EC" -ne 2 ]; then echo "--jsonargs exited with wrong exit code, expected 2 got $EC" 1>&2 exit 1 fi ## Fuzz parser ## XXX With a $(urandom) builtin we could move this test into tests/all.test clean=false if dd if=/dev/urandom bs=16 count=1024 > $d/rand 2>/dev/null; then # Have a /dev/urandom, good $VALGRIND $Q $JQ --seq . $d/rand >/dev/null 2>&1 $VALGRIND $Q $JQ --seq --stream . $d/rand >/dev/null 2>&1 dd if=/dev/urandom bs=16 count=1024 > $d/rand 2>/dev/null $VALGRIND $Q $JQ --seq . $d/rand >/dev/null 2>&1 $VALGRIND $Q $JQ --seq --stream . $d/rand >/dev/null 2>&1 dd if=/dev/urandom bs=16 count=1024 > $d/rand 2>/dev/null $VALGRIND $Q $JQ --seq . $d/rand >/dev/null 2>&1 $VALGRIND $Q $JQ --seq --stream . $d/rand >/dev/null 2>&1 fi clean=true ## Test library/module system # Check handling of ~/.jq; these can't move into jq_test.c yet because # they depend on $HOME if [ "$(HOME="$mods/home1" $VALGRIND $Q $JQ -nr fg)" != foobar ]; then echo "Bug #479 appears to be back" 1>&2 exit 1 fi if $msys || $mingw; then HOME_BAK=$HOME unset HOME if [ "$(USERPROFILE="$mods/home1" $VALGRIND $Q $JQ -nr foo)" != baz ]; then echo "Bug #3104 regressed (sourcing %USERPROFILE%/.jq on Windows)" 1>&2 exit 1 fi export HOME=$HOME_BAK unset HOME_BAK fi if [ $(HOME="$mods/home1" $VALGRIND $Q $JQ --debug-dump-disasm -n fg | grep '^[a-z]' | wc -l) -ne 3 ]; then echo "Binding too many defs into program" 1>&2 exit 1 fi if ! HOME="$mods/home2" $VALGRIND $Q $JQ -n 'include "g"; empty'; then echo "Mishandling directory ~/.jq" 1>&2 exit 1 fi cd "$JQBASEDIR" # so that relative library paths are guaranteed correct if ! $VALGRIND $Q $JQ -L ./tests/modules -ne 'import "test_bind_order" as check; check::check==true'; then echo "Issue #817 regression?" 1>&2 exit 1 fi cd "$JQBASEDIR" if ! $VALGRIND $Q $JQ -L tests/modules -ne 'import "test_bind_order" as check; check::check==true'; then echo "Issue #817 regression?" 1>&2 exit 1 fi ## Halt if ! $VALGRIND $Q $JQ -n halt; then echo "jq halt didn't work as expected" 1>&2 exit 1 fi if $VALGRIND $Q $VG_EXIT0 $JQ -n 'halt_error(1)'; then echo "jq halt_error(1) didn't work as expected" 1>&2 exit 1 elif [ $? -ne 1 ]; then echo "jq halt_error(1) had wrong error code" 1>&2 exit 1 fi if $VALGRIND $Q $VG_EXIT0 $JQ -n 'halt_error(11)'; then echo "jq halt_error(11) didn't work as expected" 1>&2 exit 1 elif [ $? -ne 11 ]; then echo "jq halt_error(11) had wrong error code" 1>&2 exit 1 fi if [ -n "$($VALGRIND $Q $JQ -n 'halt_error(1)' 2>&1)" ]; then echo "jq halt_error(1) had unexpected output" 1>&2 exit 1 fi if [ -n "$($VALGRIND $Q $JQ -n '"xyz\n" | halt_error(1)' 2>/dev/null)" ]; then echo "jq halt_error(1) had unexpected output on stdout" 1>&2 exit 1 fi if [ "$($VALGRIND $Q $JQ -n '"xy" | halt_error(1)' 2>&1 || echo "z")" != "xyz" ]; then echo "jq halt_error(1) had unexpected output" 1>&2 exit 1 fi if [ "$($VALGRIND $Q $JQ -n '"x\u0000y\u0000z" | halt_error(1)' 2>&1 | tr '\0' '.')" != "x.y.z" ]; then echo "jq halt_error(1) had unexpected output" 1>&2 exit 1 fi if [ "$($VALGRIND $Q $JQ -n '{"a":"xyz"} | halt_error(1)' 2>&1)" != '{"a":"xyz"}' ]; then echo "jq halt_error(1) had unexpected output" 1>&2 exit 1 fi # Check $JQ_COLORS ## Default colors, null input $JQ -Ccn . > $d/color printf '\033[0;90mnull\033[0m\n' > $d/expect cmp $d/color $d/expect ## Set non-default color, null input JQ_COLORS='4;31' $JQ -Ccn . > $d/color printf '\033[4;31mnull\033[0m\n' > $d/expect cmp $d/color $d/expect ## Set implicit empty color, null input $JQ -Ccn . > $d/color printf '\033[0;90mnull\033[0m\n' > $d/expect cmp $d/color $d/expect ## Set explicit empty color, null input JQ_COLORS=':' $JQ -Ccn . > $d/color printf '\033[mnull\033[0m\n' > $d/expect cmp $d/color $d/expect ## Extra colors, null input JQ_COLORS='::::::::' $JQ -Ccn . > $d/color printf '\033[mnull\033[0m\n' > $d/expect cmp $d/color $d/expect ## Default colors, complex input $JQ -Ccn '[{"a":true,"b":false},"abc",123,null]' > $d/color { printf '\033[1;39m[\033[0m' printf '\033[1;39m{\033[0m' printf '\033[1;34m"a"\033[0m' printf '\033[1;39m:\033[0m' printf '\033[0;39mtrue\033[0m' printf '\033[1;39m,\033[0m' printf '\033[1;34m"b"\033[0m' printf '\033[1;39m:\033[0m' printf '\033[0;39mfalse\033[0m' printf '\033[1;39m}\033[0m' printf '\033[1;39m,\033[0m' printf '\033[0;32m"abc"\033[0m' printf '\033[1;39m,\033[0m' printf '\033[0;39m123\033[0m' printf '\033[1;39m,\033[0m' printf '\033[0;90mnull\033[0m' printf '\033[1;39m]\033[0m\n' } > $d/expect cmp $d/color $d/expect ## Set non-default colors, complex input JQ_COLORS='0;30:0;31:0;32:0;33:0;34:1;35:1;36:1;37' \ $JQ -Ccn '[{"a":true,"b":false},"abc",123,null]' > $d/color { printf '\033[1;35m[\033[0m' printf '\033[1;36m{\033[0m' printf '\033[1;37m"a"\033[0m' printf '\033[1;36m:\033[0m' printf '\033[0;32mtrue\033[0m' printf '\033[1;36m,\033[0m' printf '\033[1;37m"b"\033[0m' printf '\033[1;36m:\033[0m' printf '\033[0;31mfalse\033[0m' printf '\033[1;36m}\033[0m' printf '\033[1;35m,\033[0m' printf '\033[0;34m"abc"\033[0m' printf '\033[1;35m,\033[0m' printf '\033[0;33m123\033[0m' printf '\033[1;35m,\033[0m' printf '\033[0;30mnull\033[0m' printf '\033[1;35m]\033[0m\n' } > $d/expect cmp $d/color $d/expect ## Set non-default colors only for literals, complex input JQ_COLORS='0;37:0;31:0;35:0;34:0;36' \ $JQ -Ccn '[{"a":true,"b":false},"abc",123,null]' > $d/color { printf '\033[1;39m[\033[0m' printf '\033[1;39m{\033[0m' printf '\033[1;34m"a"\033[0m' printf '\033[1;39m:\033[0m' printf '\033[0;35mtrue\033[0m' printf '\033[1;39m,\033[0m' printf '\033[1;34m"b"\033[0m' printf '\033[1;39m:\033[0m' printf '\033[0;31mfalse\033[0m' printf '\033[1;39m}\033[0m' printf '\033[1;39m,\033[0m' printf '\033[0;36m"abc"\033[0m' printf '\033[1;39m,\033[0m' printf '\033[0;34m123\033[0m' printf '\033[1;39m,\033[0m' printf '\033[0;37mnull\033[0m' printf '\033[1;39m]\033[0m\n' } > $d/expect cmp $d/color $d/expect ## Default colors, complex input, indented $JQ -Cn '[{"a":true,"b":false},"abc",123,null]' > $d/color { printf '\033[1;39m[\033[0m\n' printf ' \033[1;39m{\033[0m\n' printf ' \033[1;34m"a"\033[0m' printf '\033[1;39m:\033[0m ' printf '\033[0;39mtrue\033[0m' printf '\033[1;39m,\033[0m\n' printf ' \033[1;34m"b"\033[0m' printf '\033[1;39m:\033[0m ' printf '\033[0;39mfalse\033[0m\n' printf ' \033[1;39m}\033[0m' printf '\033[1;39m,\033[0m\n' printf ' \033[0;32m"abc"\033[0m' printf '\033[1;39m,\033[0m\n' printf ' \033[0;39m123\033[0m' printf '\033[1;39m,\033[0m\n' printf ' \033[0;90mnull\033[0m\n' printf '\033[1;39m]\033[0m\n' } > $d/expect cmp $d/color $d/expect ## Set non-default colors, complex input, indented JQ_COLORS='0;30:0;31:0;32:0;33:0;34:1;35:1;36:1;37' \ $JQ -Cn '[{"a":true,"b":false},"abc",123,null]' > $d/color { printf '\033[1;35m[\033[0m\n' printf ' \033[1;36m{\033[0m\n' printf ' \033[1;37m"a"\033[0m' printf '\033[1;36m:\033[0m ' printf '\033[0;32mtrue\033[0m' printf '\033[1;36m,\033[0m\n' printf ' \033[1;37m"b"\033[0m' printf '\033[1;36m:\033[0m ' printf '\033[0;31mfalse\033[0m\n' printf ' \033[1;36m}\033[0m' printf '\033[1;35m,\033[0m\n' printf ' \033[0;34m"abc"\033[0m' printf '\033[1;35m,\033[0m\n' printf ' \033[0;33m123\033[0m' printf '\033[1;35m,\033[0m\n' printf ' \033[0;30mnull\033[0m\n' printf '\033[1;35m]\033[0m\n' } > $d/expect cmp $d/color $d/expect ## Set truecolor, complex input, indented JQ_COLORS=$(printf '38;2;%s:' \ '255;173;173' '255;214;165' '253;255;182' '202;255;191' \ '155;246;255' '160;196;255' '189;178;255' '255;198;255') \ $JQ -Cn '[{"a":true,"b":false},"abc",123,null]' > $d/color { printf '\033[38;2;160;196;255m[\033[0m\n' printf ' \033[38;2;189;178;255m{\033[0m\n' printf ' \033[38;2;255;198;255m"a"\033[0m' printf '\033[38;2;189;178;255m:\033[0m ' printf '\033[38;2;253;255;182mtrue\033[0m' printf '\033[38;2;189;178;255m,\033[0m\n' printf ' \033[38;2;255;198;255m"b"\033[0m' printf '\033[38;2;189;178;255m:\033[0m ' printf '\033[38;2;255;214;165mfalse\033[0m\n' printf ' \033[38;2;189;178;255m}\033[0m' printf '\033[38;2;160;196;255m,\033[0m\n' printf ' \033[38;2;155;246;255m"abc"\033[0m' printf '\033[38;2;160;196;255m,\033[0m\n' printf ' \033[38;2;202;255;191m123\033[0m' printf '\033[38;2;160;196;255m,\033[0m\n' printf ' \033[38;2;255;173;173mnull\033[0m\n' printf '\033[38;2;160;196;255m]\033[0m\n' } > $d/expect cmp $d/color $d/expect # Check invalid JQ_COLORS echo 'Failed to set $JQ_COLORS' > $d/expect_warning $JQ -Ccn '[{"a":true,"b":false},"abc",123,null]' > $d/expect for colors in '/' '[30' '30m' '30:31m:32' '30:*:31' 'invalid'; do JQ_COLORS=$colors \ $JQ -Ccn '[{"a":true,"b":false},"abc",123,null]' > $d/color 2>$d/warning cmp $d/color $d/expect cmp $d/warning $d/expect_warning done # Check $NO_COLOR test_no_color=true $msys && test_no_color=false $mingw && test_no_color=false if $test_no_color && command -v script >/dev/null 2>&1; then if script -qc echo /dev/null >/dev/null 2>&1; then faketty() { script -qec "$*" /dev/null; } else # macOS faketty() { script -q /dev/null "$@" /dev/null | sed 's/^\x5E\x44\x08\x08//'; } fi faketty $JQ_NO_B -n . > $d/color printf '\033[0;90mnull\033[0m\r\n' > $d/expect od -tc $d/expect od -tc $d/color cmp $d/color $d/expect faketty env NO_COLOR= $JQ_NO_B -n . > $d/color printf '\033[0;90mnull\033[0m\r\n' > $d/expect od -tc $d/expect od -tc $d/color cmp $d/color $d/expect faketty env NO_COLOR=1 $JQ_NO_B -n . > $d/color printf 'null\r\n' > $d/expect od -tc $d/expect od -tc $d/color cmp $d/color $d/expect faketty env NO_COLOR=1 $JQ_NO_B -Cn . > $d/color printf '\033[0;90mnull\033[0m\r\n' > $d/expect od -tc $d/expect od -tc $d/color cmp $d/color $d/expect fi # #2785 if $VALGRIND $Q $JQ -n -f "$JQTESTDIR/no-main-program.jq" > $d/out 2>&1; then echo "jq -f $JQTESTDIR/no-main-program.jq succeeded" exit 1 else EC=$? if [ $EC -eq 1 ]; then echo "jq -f $JQTESTDIR/no-main-program.jq failed with memory errors" exit 1 fi if [ $EC -ne 3 ]; then echo "jq -f $JQTESTDIR/no-main-program.jq failed with wrong exit code ($EC)" exit 1 fi fi cat > $d/expected < $d/out 2>&1; then echo "jq -f $JQTESTDIR/yes-main-program.jq failed" exit 1 fi if ! $msys && ! $mingw && locales=$(locale -a); then { l=$(grep -Ev '^(C|LANG|POSIX|en)' | grep -Ei '\.utf-?8$' | head -n1) ;} \ < $d/out 2>&1; then echo 'syntax error not detected' exit 1 fi cat > $d/expected <, line 5, column 3: catch ] ^^^^^ jq: error: Possibly unterminated 'if' statement at , line 2, column 7: try if . ^^^^ jq: error: Possibly unterminated 'try' statement at , line 2, column 3: try if . ^^^^^^^^ jq: 3 compile errors EOF diff $d/out $d/expected # Test syntax error messages when error happens at the end. if $VALGRIND $Q $JQ -n 'if ' > $d/out 2>&1; then echo 'syntax error not detected' exit 1 fi cat > $d/expected <, line 1, column 3: if ^ jq: 1 compile error EOF diff $d/out $d/expected # Comments! if ! x=$($JQ -n '123 # comment') || [ "$x" != 123 ]; then echo 'comment did not work' exit 1 fi cr=$(printf \\r) if ! x=$($JQ -n "1 # foo$cr + 2") || [ "$x" != 1 ]; then echo 'regression: carriage return terminates comment' exit 1 fi if ! x=$($JQ -cn '[ 1, # foo \ 2, # bar \\ 3, 4, # baz \\\ 5, \ 6, 7 # comment \ comment \ comment ]') || [ "$x" != '[1,3,4,7]' ]; then echo 'multiline comment was not handled correctly' exit 1 fi if ! x=$($JQ -cn "$(printf '[\r\n1,# comment\r\n2,# comment\\\r\ncomment\r\n3\r\n]')") \ || [ "$x" != '[1,2,3]' ]; then echo 'multiline comment with CRLF line breaks was not handled correctly' exit 1 fi # Allow passing the inline jq script before -- #2919 if ! r=$($JQ --args -rn -- '$ARGS.positional[0]' bar) || [ "$r" != bar ]; then echo "passing the inline script after -- didn't work" exit 1 fi if ! r=$($JQ --args -rn 1 -- '$ARGS.positional[0]' bar) || [ "$r" != 1 ]; then echo "passing the inline script before -- didn't work" exit 1 fi # CVE-2023-50246: No heap overflow for '-10E-1000000001' $VALGRIND $Q $JQ . <<\NUM -10E-1000000001 NUM # test for --indent and --compact-output -- #1465 printf '[1,2]\n' > $d/expected $JQ --compact-output -n "[1,2]" > $d/out cmp $d/out $d/expected printf '[\n1,\n2\n]\n' > $d/expected $JQ --indent 0 -n "[1,2]" > $d/out cmp $d/out $d/expected printf '[\n 1,\n 2\n]\n' > $d/expected $JQ --indent 1 -n "[1,2]" > $d/out cmp $d/out $d/expected printf '[\n 1,\n 2\n]\n' > $d/expected $JQ --indent 5 -n "[1,2]" > $d/out cmp $d/out $d/expected printf '[\n{\n"a": 1\n}\n]\n' > $d/expected $JQ --indent 0 -n "[{a:1}]" > $d/out cmp $d/out $d/expected printf '[\n {\n "a": 1\n }\n]\n' > $d/expected $JQ --indent 1 -n "[{a:1}]" > $d/out cmp $d/out $d/expected printf '[\n {\n "a": 1\n }\n]\n' > $d/expected $JQ --indent 6 -n "[{a:1}]" > $d/out cmp $d/out $d/expected if ! $msys && ! $mingw; then # Test handling of timezones -- #2429, #2475 if ! r=$(TZ=Asia/Tokyo $JQ -rn '1731627341 | strflocaltime("%F %T %z %Z")') \ || [ "$r" != "2024-11-15 08:35:41 +0900 JST" ]; then echo "Incorrectly formatted local time" exit 1 fi if ! r=$(TZ=Europe/Paris $JQ -rn '1731627341 | strflocaltime("%F %T %z %Z")') \ || [ "$r" != "2024-11-15 00:35:41 +0100 CET" ]; then echo "Incorrectly formatted local time" exit 1 fi # Test when DST is in effect: #1912 if ! r=$(TZ=Europe/Paris $JQ -rn '1750500000 | strflocaltime("%F %T %z %Z")') \ || [ "$r" != "2025-06-21 12:00:00 +0200 CEST" ]; then echo "Incorrectly formatted local time" exit 1 fi if ! r=$(TZ=Europe/Paris $JQ -rn '1731627341 | strftime("%F %T %z %Z")') \ || ( [ "$r" != "2024-11-14 23:35:41 +0000 UTC" ] \ && [ "$r" != "2024-11-14 23:35:41 +0000 GMT" ] ); then echo "Incorrectly formatted universal time" exit 1 fi if ! r=$(TZ=Etc/GMT+7 $JQ -nc '1731627341 | .,. | [strftime("%FT%T"),strflocaltime("%FT%T%z")]' ) \ || [ "$r" != '["2024-11-14T23:35:41","2024-11-14T16:35:41-0700"] ["2024-11-14T23:35:41","2024-11-14T16:35:41-0700"]' ]; then echo "strftime or strftimelocal are not pure functions" exit 1 fi fi # Test ARG_NEWCLOSURE overflow protection (issue #3458) # Test 1: Too many function parameters (4097 params triggers the limit) echo "Testing function parameter limit..." cat > $d/expected < $d/prog.jq $JQ -nf $d/prog.jq 2> $d/out && { echo "Expected compile error for too many parameters" exit 1 } diff $d/out $d/expected # Test 2: Too many local functions (4097 functions triggers the limit) echo "Testing local function limit..." cat > $d/expected < $d/prog.jq $JQ -nf $d/prog.jq 2> $d/out && { echo "Expected compile error for too many local functions" exit 1 } diff $d/out $d/expected exit 0 ================================================ FILE: tests/torture/input0.json ================================================ 0 12 true false null [] {} [{}] [[]] [0,01,[12,22,[34,[45,56],7]],[]] {"a":[1]} {"a":[{}]} {"a":[{},[],[[]]]} {"a":[{"b":[]}]} {"a":[{"b":[]},{},[2]]} ================================================ FILE: tests/uri.test ================================================ # Tests are groups of three lines: program, input, expected output # Blank lines and lines starting with # are ignored # @uri @uri "" "" @uri "\b\t\n\f\r\"\\" "%08%09%0A%0C%0D%22%5C" @uri ",-./09:;<=>?@AZ[\\]^_`az{|}~\u007f" "%2C-.%2F09%3A%3B%3C%3D%3E%3F%40AZ%5B%5C%5D%5E_%60az%7B%7C%7D~%7F" @uri "a \u03bc \u2230 \ud83d\ude0e" "a%20%CE%BC%20%E2%88%B0%20%F0%9F%98%8E" @uri "a\u0000b\u0000c" "a%00b%00c" # @urid @urid "" "" @urid "%08%09%0A%0C%0D%22%5C" "\b\t\n\f\r\"\\" @urid "%2C-.%2F09%3A%3B%3C%3D%3E%3F%40AZ%5B%5C%5D%5E_%60az%7B%7C%7D~%7F" ",-./09:;<=>?@AZ[\\]^_`az{|}~\u007f" @urid "a%20%CE%BC%20%E2%88%B0%20%F0%9F%98%8E" "a \u03bc \u2230 \ud83d\ude0e" @urid "a%00b%00c" "a\u0000b\u0000c" @urid "hello world" "hello world" @urid "Knäckebröd" "Knäckebröd" @urid "%c3%a4b%c3%a7d%c3%ab" "äbçdë" @urid "a\u0000b\u0000c" "a\u0000b\u0000c" # '%' at end of string . | try @urid catch . "abc%" "string (\"abc%\") is not a valid uri encoding" # '%' followed by only one hex digit . | try @urid catch . "abc%f" "string (\"abc%f\") is not a valid uri encoding" # '%' followed by non-hex character . | try @urid catch . "abc%g" "string (\"abc%g\") is not a valid uri encoding" # invalid hex value ('FX') . | try @urid catch . "%FX%9F%98%8E" "string (\"%FX%9F%98%8E\") is not a valid uri encoding" # incomplete 4-byte UTF-8 sequence (only 3 bytes) . | try @urid catch . "%F0%93%81" "string (\"%F0%93%81\") is not a valid uri encoding" # invalid continuation byte (0xC0 is not 10xxxxxx) . | try @urid catch . "%F0%C0%81%8E" "string (\"%F0%C0%81%8E\") is not a valid uri encoding" ================================================ FILE: tests/uritest ================================================ #!/bin/sh . "${0%/*}/setup" "$@" $VALGRIND $Q $JQ -L "$mods" --run-tests $JQTESTDIR/uri.test ================================================ FILE: tests/utf8test ================================================ #!/bin/sh -x . "${0%/*}/setup" "$@" # Reading jq file does not corrupt multi-byte characters -- #1311 for l in 1 2 3 4; do $VALGRIND $Q $JQ -rn "[(range($l) | 48), (range(3000) | 128515)] | implode | \"\\(tojson) | explode | unique == [48, 128515]\"" > $d/input if ! $VALGRIND $Q $JQ -nef $d/input > /dev/null; then echo "Reading jq file corrupted multi-byte characters" exit 1 fi done # Slurping raw input does not corrupt multi-byte characters -- #3389 for l in 1 2 3 4; do $VALGRIND $Q $JQ -jn "[(range($l) | 48), (range(3000) | 128515)] | implode" > $d/input if ! $VALGRIND $Q $JQ -Rse 'explode | unique == [48, 128515]' $d/input > /dev/null; then echo "Slurping raw input corrupted multi-byte characters" exit 1 fi done exit 0 ================================================ FILE: tests/yes-main-program.jq ================================================ def a: .; 0 ================================================ FILE: vendor/decNumber/ICU-license.html ================================================ ICU License - ICU 1.8.1 and later

ICU License - ICU 1.8.1 and later

COPYRIGHT AND PERMISSION NOTICE

Copyright (c) 1995-2005 International Business Machines Corporation and others
All rights reserved.

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, and/or sell copies of the Software, and to permit persons
to whom the Software is furnished to do so, provided that the above
copyright notice(s) and this permission notice appear in all copies of
the Software and that both the above copyright notice(s) and this
permission notice appear in supporting documentation.

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
OF THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
HOLDERS INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL
INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING
FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.

Except as contained in this notice, the name of a copyright holder
shall not be used in advertising or otherwise to promote the sale, use
or other dealings in this Software without prior written authorization
of the copyright holder.

--------------------------------------------------------------------------------
All trademarks and registered trademarks mentioned herein are the property of their respective owners.
================================================ FILE: vendor/decNumber/decBasic.c ================================================ /* ------------------------------------------------------------------ */ /* decBasic.c -- common base code for Basic decimal types */ /* ------------------------------------------------------------------ */ /* Copyright (c) IBM Corporation, 2000, 2010. All rights reserved. */ /* */ /* This software is made available under the terms of the */ /* ICU License -- ICU 1.8.1 and later. */ /* */ /* The description and User's Guide ("The decNumber C Library") for */ /* this software is included in the package as decNumber.pdf. This */ /* document is also available in HTML, together with specifications, */ /* testcases, and Web links, on the General Decimal Arithmetic page. */ /* */ /* Please send comments, suggestions, and corrections to the author: */ /* mfc@uk.ibm.com */ /* Mike Cowlishaw, IBM Fellow */ /* IBM UK, PO Box 31, Birmingham Road, Warwick CV34 5JL, UK */ /* ------------------------------------------------------------------ */ /* This module comprises code that is shared between decDouble and */ /* decQuad (but not decSingle). The main arithmetic operations are */ /* here (Add, Subtract, Multiply, FMA, and Division operators). */ /* */ /* Unlike decNumber, parameterization takes place at compile time */ /* rather than at runtime. The parameters are set in the decDouble.c */ /* (etc.) files, which then include this one to produce the compiled */ /* code. The functions here, therefore, are code shared between */ /* multiple formats. */ /* */ /* This must be included after decCommon.c. */ /* ------------------------------------------------------------------ */ // Names here refer to decFloat rather than to decDouble, etc., and // the functions are in strict alphabetical order. // The compile-time flags SINGLE, DOUBLE, and QUAD are set up in // decCommon.c #if !defined(QUAD) #error decBasic.c must be included after decCommon.c #endif #if SINGLE #error Routines in decBasic.c are for decDouble and decQuad only #endif /* Private constants */ #define DIVIDE 0x80000000 // Divide operations [as flags] #define REMAINDER 0x40000000 // .. #define DIVIDEINT 0x20000000 // .. #define REMNEAR 0x10000000 // .. /* Private functions (local, used only by routines in this module) */ static decFloat *decDivide(decFloat *, const decFloat *, const decFloat *, decContext *, uInt); static decFloat *decCanonical(decFloat *, const decFloat *); static void decFiniteMultiply(bcdnum *, uByte *, const decFloat *, const decFloat *); static decFloat *decInfinity(decFloat *, const decFloat *); static decFloat *decInvalid(decFloat *, decContext *); static decFloat *decNaNs(decFloat *, const decFloat *, const decFloat *, decContext *); static Int decNumCompare(const decFloat *, const decFloat *, Flag); static decFloat *decToIntegral(decFloat *, const decFloat *, decContext *, enum rounding, Flag); static uInt decToInt32(const decFloat *, decContext *, enum rounding, Flag, Flag); /* ------------------------------------------------------------------ */ /* decCanonical -- copy a decFloat, making canonical */ /* */ /* result gets the canonicalized df */ /* df is the decFloat to copy and make canonical */ /* returns result */ /* */ /* This is exposed via decFloatCanonical for Double and Quad only. */ /* This works on specials, too; no error or exception is possible. */ /* ------------------------------------------------------------------ */ static decFloat * decCanonical(decFloat *result, const decFloat *df) { uInt encode, precode, dpd; // work uInt inword, uoff, canon; // .. Int n; // counter (down) if (df!=result) *result=*df; // effect copy if needed if (DFISSPECIAL(result)) { if (DFISINF(result)) return decInfinity(result, df); // clean Infinity // is a NaN DFWORD(result, 0)&=~ECONNANMASK; // clear ECON except selector if (DFISCCZERO(df)) return result; // coefficient continuation is 0 // drop through to check payload } // return quickly if the coefficient continuation is canonical { // declare block #if DOUBLE uInt sourhi=DFWORD(df, 0); uInt sourlo=DFWORD(df, 1); if (CANONDPDOFF(sourhi, 8) && CANONDPDTWO(sourhi, sourlo, 30) && CANONDPDOFF(sourlo, 20) && CANONDPDOFF(sourlo, 10) && CANONDPDOFF(sourlo, 0)) return result; #elif QUAD uInt sourhi=DFWORD(df, 0); uInt sourmh=DFWORD(df, 1); uInt sourml=DFWORD(df, 2); uInt sourlo=DFWORD(df, 3); if (CANONDPDOFF(sourhi, 4) && CANONDPDTWO(sourhi, sourmh, 26) && CANONDPDOFF(sourmh, 16) && CANONDPDOFF(sourmh, 6) && CANONDPDTWO(sourmh, sourml, 28) && CANONDPDOFF(sourml, 18) && CANONDPDOFF(sourml, 8) && CANONDPDTWO(sourml, sourlo, 30) && CANONDPDOFF(sourlo, 20) && CANONDPDOFF(sourlo, 10) && CANONDPDOFF(sourlo, 0)) return result; #endif } // block // Loop to repair a non-canonical coefficent, as needed inword=DECWORDS-1; // current input word uoff=0; // bit offset of declet encode=DFWORD(result, inword); for (n=DECLETS-1; n>=0; n--) { // count down declets of 10 bits dpd=encode>>uoff; uoff+=10; if (uoff>32) { // crossed uInt boundary inword--; encode=DFWORD(result, inword); uoff-=32; dpd|=encode<<(10-uoff); // get pending bits } dpd&=0x3ff; // clear uninteresting bits if (dpd<0x16e) continue; // must be canonical canon=BIN2DPD[DPD2BIN[dpd]]; // determine canonical declet if (canon==dpd) continue; // have canonical declet // need to replace declet if (uoff>=10) { // all within current word encode&=~(0x3ff<<(uoff-10)); // clear the 10 bits ready for replace encode|=canon<<(uoff-10); // insert the canonical form DFWORD(result, inword)=encode; // .. and save continue; } // straddled words precode=DFWORD(result, inword+1); // get previous precode&=0xffffffff>>(10-uoff); // clear top bits DFWORD(result, inword+1)=precode|(canon<<(32-(10-uoff))); encode&=0xffffffff<>(10-uoff); // insert canonical DFWORD(result, inword)=encode; // .. and save } // n return result; } // decCanonical /* ------------------------------------------------------------------ */ /* decDivide -- divide operations */ /* */ /* result gets the result of dividing dfl by dfr: */ /* dfl is the first decFloat (lhs) */ /* dfr is the second decFloat (rhs) */ /* set is the context */ /* op is the operation selector */ /* returns result */ /* */ /* op is one of DIVIDE, REMAINDER, DIVIDEINT, or REMNEAR. */ /* ------------------------------------------------------------------ */ #define DIVCOUNT 0 // 1 to instrument subtractions counter #define DIVBASE ((uInt)BILLION) // the base used for divide #define DIVOPLEN DECPMAX9 // operand length ('digits' base 10**9) #define DIVACCLEN (DIVOPLEN*3) // accumulator length (ditto) static decFloat * decDivide(decFloat *result, const decFloat *dfl, const decFloat *dfr, decContext *set, uInt op) { decFloat quotient; // for remainders bcdnum num; // for final conversion uInt acc[DIVACCLEN]; // coefficent in base-billion .. uInt div[DIVOPLEN]; // divisor in base-billion .. uInt quo[DIVOPLEN+1]; // quotient in base-billion .. uByte bcdacc[(DIVOPLEN+1)*9+2]; // for quotient in BCD, +1, +1 uInt *msua, *msud, *msuq; // -> msu of acc, div, and quo Int divunits, accunits; // lengths Int quodigits; // digits in quotient uInt *lsua, *lsuq; // -> current acc and quo lsus Int length, multiplier; // work uInt carry, sign; // .. uInt *ua, *ud, *uq; // .. uByte *ub; // .. uInt uiwork; // for macros uInt divtop; // top unit of div adjusted for estimating #if DIVCOUNT static uInt maxcount=0; // worst-seen subtractions count uInt divcount=0; // subtractions count [this divide] #endif // calculate sign num.sign=(DFWORD(dfl, 0)^DFWORD(dfr, 0)) & DECFLOAT_Sign; if (DFISSPECIAL(dfl) || DFISSPECIAL(dfr)) { // either is special? // NaNs are handled as usual if (DFISNAN(dfl) || DFISNAN(dfr)) return decNaNs(result, dfl, dfr, set); // one or two infinities if (DFISINF(dfl)) { if (DFISINF(dfr)) return decInvalid(result, set); // Two infinities bad if (op&(REMAINDER|REMNEAR)) return decInvalid(result, set); // as is rem // Infinity/x is infinite and quiet, even if x=0 DFWORD(result, 0)=num.sign; return decInfinity(result, result); } // must be x/Infinity -- remainders are lhs if (op&(REMAINDER|REMNEAR)) return decCanonical(result, dfl); // divides: return zero with correct sign and exponent depending // on op (Etiny for divide, 0 for divideInt) decFloatZero(result); if (op==DIVIDEINT) DFWORD(result, 0)|=num.sign; // add sign else DFWORD(result, 0)=num.sign; // zeros the exponent, too return result; } // next, handle zero operands (x/0 and 0/x) if (DFISZERO(dfr)) { // x/0 if (DFISZERO(dfl)) { // 0/0 is undefined decFloatZero(result); DFWORD(result, 0)=DECFLOAT_qNaN; set->status|=DEC_Division_undefined; return result; } if (op&(REMAINDER|REMNEAR)) return decInvalid(result, set); // bad rem set->status|=DEC_Division_by_zero; DFWORD(result, 0)=num.sign; return decInfinity(result, result); // x/0 -> signed Infinity } num.exponent=GETEXPUN(dfl)-GETEXPUN(dfr); // ideal exponent if (DFISZERO(dfl)) { // 0/x (x!=0) // if divide, result is 0 with ideal exponent; divideInt has // exponent=0, remainders give zero with lower exponent if (op&DIVIDEINT) { decFloatZero(result); DFWORD(result, 0)|=num.sign; // add sign return result; } if (!(op&DIVIDE)) { // a remainder // exponent is the minimum of the operands num.exponent=MINI(GETEXPUN(dfl), GETEXPUN(dfr)); // if the result is zero the sign shall be sign of dfl num.sign=DFWORD(dfl, 0)&DECFLOAT_Sign; } bcdacc[0]=0; num.msd=bcdacc; // -> 0 num.lsd=bcdacc; // .. return decFinalize(result, &num, set); // [divide may clamp exponent] } // 0/x // [here, both operands are known to be finite and non-zero] // extract the operand coefficents into 'units' which are // base-billion; the lhs is high-aligned in acc and the msu of both // acc and div is at the right-hand end of array (offset length-1); // the quotient can need one more unit than the operands as digits // in it are not necessarily aligned neatly; further, the quotient // may not start accumulating until after the end of the initial // operand in acc if that is small (e.g., 1) so the accumulator // must have at least that number of units extra (at the ls end) GETCOEFFBILL(dfl, acc+DIVACCLEN-DIVOPLEN); GETCOEFFBILL(dfr, div); // zero the low uInts of acc acc[0]=0; acc[1]=0; acc[2]=0; acc[3]=0; #if DOUBLE #if DIVOPLEN!=2 #error Unexpected Double DIVOPLEN #endif #elif QUAD acc[4]=0; acc[5]=0; acc[6]=0; acc[7]=0; #if DIVOPLEN!=4 #error Unexpected Quad DIVOPLEN #endif #endif // set msu and lsu pointers msua=acc+DIVACCLEN-1; // [leading zeros removed below] msuq=quo+DIVOPLEN; //[loop for div will terminate because operands are non-zero] for (msud=div+DIVOPLEN-1; *msud==0;) msud--; // the initial least-significant unit of acc is set so acc appears // to have the same length as div. // This moves one position towards the least possible for each // iteration divunits=(Int)(msud-div+1); // precalculate lsua=msua-divunits+1; // initial working lsu of acc lsuq=msuq; // and of quo // set up the estimator for the multiplier; this is the msu of div, // plus two bits from the unit below (if any) rounded up by one if // there are any non-zero bits or units below that [the extra two // bits makes for a much better estimate when the top unit is small] divtop=*msud<<2; if (divunits>1) { uInt *um=msud-1; uInt d=*um; if (d>=750000000) {divtop+=3; d-=750000000;} else if (d>=500000000) {divtop+=2; d-=500000000;} else if (d>=250000000) {divtop++; d-=250000000;} if (d) divtop++; else for (um--; um>=div; um--) if (*um) { divtop++; break; } } // >1 unit #if DECTRACE {Int i; printf("----- div="); for (i=divunits-1; i>=0; i--) printf("%09ld ", (LI)div[i]); printf("\n");} #endif // now collect up to DECPMAX+1 digits in the quotient (this may // need OPLEN+1 uInts if unaligned) quodigits=0; // no digits yet for (;; lsua--) { // outer loop -- each input position #if DECCHECK if (lsua=lsua;) msua--; accunits=(Int)(msua-lsua+1); // [maybe 0] // subtraction is only necessary and possible if there are as // least as many units remaining in acc for this iteration as // there are in div if (accunitsdiv: subtraction necessary at this position for (ud=msud, ua=msua; ud>div; ud--, ua--) if (*ud!=*ua) break; // [now at first mismatch or lsu] if (*ud>*ua) break; // next time... if (*ud==*ua) { // all compared equal *lsuq+=1; // increment result msua=lsua; // collapse acc units *msua=0; // .. to a zero break; } // subtraction necessary; estimate multiplier [see above] // if both *msud and *msua are small it is cost-effective to // bring in part of the following units (if any) to get a // better estimate (assume some other non-zero in div) #define DIVLO 1000000U #define DIVHI (DIVBASE/DIVLO) #if DECUSE64 if (divunits>1) { // there cannot be a *(msud-2) for DECDOUBLE so next is // an exact calculation unless DECQUAD (which needs to // assume bits out there if divunits>2) uLong mul=(uLong)*msua * DIVBASE + *(msua-1); uLong div=(uLong)*msud * DIVBASE + *(msud-1); #if QUAD if (divunits>2) div++; #endif mul/=div; multiplier=(Int)mul; } else multiplier=*msua/(*msud); #else if (divunits>1 && *msuadivunits // msud is one unit 'lower' than msua, so estimate differently #if DECUSE64 uLong mul; // as before, bring in extra digits if possible if (divunits>1 && *msua>DIVSHIFTA); carry=(uInt)(((uLong)hop*DIVMAGIC)>>DIVSHIFTB); // the estimate is now in hi; now calculate sub-hi*10**9 // to get the remainder (which will be =DIVBASE) { lo-=DIVBASE; // correct by +1 carry++; } } #else // 32-bit uInt hi; // calculate multiplier*(*ud) into hi and lo LONGMUL32HI(hi, *ud, multiplier); // get the high word lo=multiplier*(*ud); // .. and the low lo+=carry; // add the old hi carry=hi+(lo=DIVBASE) { // split is needed hop=(carry<<3)+(lo>>DIVSHIFTA); // hi:lo/2**29 LONGMUL32HI(carry, hop, DIVMAGIC); // only need the high word // [DIVSHIFTB is 32, so carry can be used directly] // the estimate is now in carry; now calculate hi:lo-est*10**9; // happily the top word of the result is irrelevant because it // will always be zero so this needs only one multiplication lo-=(carry*DIVBASE); // the correction here will be at most +1; do it if (lo>=DIVBASE) { lo-=DIVBASE; carry++; } } #endif if (lo>*ua) { // borrow needed *ua+=DIVBASE; carry++; } *ua-=lo; } // ud loop if (carry) *ua-=carry; // accdigits>divdigits [cannot borrow] } // inner loop // the outer loop terminates when there is either an exact result // or enough digits; first update the quotient digit count and // pointer (if any significant digits) #if DECTRACE if (*lsuq || quodigits) printf("*lsuq=%09ld\n", (LI)*lsuq); #endif if (quodigits) { quodigits+=9; // had leading unit earlier lsuq--; if (quodigits>DECPMAX+1) break; // have enough } else if (*lsuq) { // first quotient digits const uInt *pow; for (pow=DECPOWERS; *lsuq>=*pow; pow++) quodigits++; lsuq--; // [cannot have >DECPMAX+1 on first unit] } if (*msua!=0) continue; // not an exact result // acc is zero iff used all of original units and zero down to lsua // (must also continue to original lsu for correct quotient length) if (lsua>acc+DIVACCLEN-DIVOPLEN) continue; for (; msua>lsua && *msua==0;) msua--; if (*msua==0 && msua==lsua) break; } // outer loop // all of the original operand in acc has been covered at this point // quotient now has at least DECPMAX+2 digits // *msua is now non-0 if inexact and sticky bits // lsuq is one below the last uint of the quotient lsuq++; // set -> true lsu of quo if (*msua) *lsuq|=1; // apply sticky bit // quo now holds the (unrounded) quotient in base-billion; one // base-billion 'digit' per uInt. #if DECTRACE printf("DivQuo:"); for (uq=msuq; uq>=lsuq; uq--) printf(" %09ld", (LI)*uq); printf("\n"); #endif // Now convert to BCD for rounding and cleanup, starting from the // most significant end [offset by one into bcdacc to leave room // for a possible carry digit if rounding for REMNEAR is needed] for (uq=msuq, ub=bcdacc+1; uq>=lsuq; uq--, ub+=9) { uInt top, mid, rem; // work if (*uq==0) { // no split needed UBFROMUI(ub, 0); // clear 9 BCD8s UBFROMUI(ub+4, 0); // .. *(ub+8)=0; // .. continue; } // *uq is non-zero -- split the base-billion digit into // hi, mid, and low three-digits #define divsplit9 1000000 // divisor #define divsplit6 1000 // divisor // The splitting is done by simple divides and remainders, // assuming the compiler will optimize these [GCC does] top=*uq/divsplit9; rem=*uq%divsplit9; mid=rem/divsplit6; rem=rem%divsplit6; // lay out the nine BCD digits (plus one unwanted byte) UBFROMUI(ub, UBTOUI(&BIN2BCD8[top*4])); UBFROMUI(ub+3, UBTOUI(&BIN2BCD8[mid*4])); UBFROMUI(ub+6, UBTOUI(&BIN2BCD8[rem*4])); } // BCD conversion loop ub--; // -> lsu // complete the bcdnum; quodigits is correct, so the position of // the first non-zero is known num.msd=bcdacc+1+(msuq-lsuq+1)*9-quodigits; num.lsd=ub; // make exponent adjustments, etc if (lsuamaxcount) { // new high-water nark maxcount=divcount; printf("DivNewMaxCount: %ld\n", (LI)maxcount); } #endif if (op&DIVIDE) return decFinalize(result, &num, set); // all done // Is DIVIDEINT or a remainder; there is more to do -- first form // the integer (this is done 'after the fact', unlike as in // decNumber, so as not to tax DIVIDE) // The first non-zero digit will be in the first 9 digits, known // from quodigits and num.msd, so there is always space for DECPMAX // digits length=(Int)(num.lsd-num.msd+1); //printf("Length exp: %ld %ld\n", (LI)length, (LI)num.exponent); if (length+num.exponent>DECPMAX) { // cannot fit decFloatZero(result); DFWORD(result, 0)=DECFLOAT_qNaN; set->status|=DEC_Division_impossible; return result; } if (num.exponent>=0) { // already an int, or need pad zeros for (ub=num.lsd+1; ub<=num.lsd+num.exponent; ub++) *ub=0; num.lsd+=num.exponent; } else { // too long: round or truncate needed Int drop=-num.exponent; if (!(op&REMNEAR)) { // simple truncate num.lsd-=drop; if (num.lsd re-round digit uByte reround; // reround value *(num.msd-1)=0; // in case of left carry, or make 0 if (drop 0] reround=*roundat; for (ub=roundat+1; ub<=num.lsd; ub++) { if (*ub!=0) { reround=DECSTICKYTAB[reround]; break; } } // check stickies if (roundat>num.msd) num.lsd=roundat-1; else { num.msd--; // use the 0 .. num.lsd=num.msd; // .. at the new MSD place } if (reround!=0) { // discarding non-zero uInt bump=0; // rounding is DEC_ROUND_HALF_EVEN always if (reround>5) bump=1; // >0.5 goes up else if (reround==5) // exactly 0.5000 .. bump=*(num.lsd) & 0x01; // .. up iff [new] lsd is odd if (bump!=0) { // need increment // increment the coefficient; this might end up with 1000... ub=num.lsd; for (; UBTOUI(ub-3)==0x09090909; ub-=4) UBFROMUI(ub-3, 0); for (; *ub==9; ub--) *ub=0; // at most 3 more *ub+=1; if (ub9 #error Exponent may overflow when doubled for Multiply #endif #if MULACCLEN!=(MULACCLEN/4)*4 // This assumption is used below only for initialization #error MULACCLEN is not a multiple of 4 #endif static void decFiniteMultiply(bcdnum *num, uByte *bcdacc, const decFloat *dfl, const decFloat *dfr) { uInt bufl[MULOPLEN]; // left coefficient (base-billion) uInt bufr[MULOPLEN]; // right coefficient (base-billion) uInt *ui, *uj; // work uByte *ub; // .. uInt uiwork; // for macros #if DECUSE64 uLong accl[MULACCLEN]; // lazy accumulator (base-billion+) uLong *pl; // work -> lazy accumulator uInt acc[MULACCLEN]; // coefficent in base-billion .. #else uInt acc[MULACCLEN*2]; // accumulator in base-billion .. #endif uInt *pa; // work -> accumulator //printf("Base10**9: OpLen=%d MulAcclen=%d\n", OPLEN, MULACCLEN); /* Calculate sign and exponent */ num->sign=(DFWORD(dfl, 0)^DFWORD(dfr, 0)) & DECFLOAT_Sign; num->exponent=GETEXPUN(dfl)+GETEXPUN(dfr); // [see assertion above] /* Extract the coefficients and prepare the accumulator */ // the coefficients of the operands are decoded into base-billion // numbers in uInt arrays (bufl and bufr, LSD at offset 0) of the // appropriate size. GETCOEFFBILL(dfl, bufl); GETCOEFFBILL(dfr, bufr); #if DECTRACE && 0 printf("CoeffbL:"); for (ui=bufl+MULOPLEN-1; ui>=bufl; ui--) printf(" %08lx", (LI)*ui); printf("\n"); printf("CoeffbR:"); for (uj=bufr+MULOPLEN-1; uj>=bufr; uj--) printf(" %08lx", (LI)*uj); printf("\n"); #endif // start the 64-bit/32-bit differing paths... #if DECUSE64 // zero the accumulator #if MULACCLEN==4 accl[0]=0; accl[1]=0; accl[2]=0; accl[3]=0; #else // use a loop // MULACCLEN is a multiple of four, asserted above for (pl=accl; pl1 may be // needed. Values of A and B are chosen to satisfy the constraints // just mentioned while minimizing the maximum error (and hence the // maximum correction), as shown in the following table: // // Type OPLEN A B maxX maxError maxCorrection // --------------------------------------------------------- // DOUBLE 2 29 32 <2*10**18 0.63 1 // QUAD 4 30 31 <4*10**18 1.17 2 // // In the OPLEN==2 case there is most choice, but the value for B // of 32 has a big advantage as then the calculation of the // estimate requires no shifting; the compiler can extract the high // word directly after multiplying magic*hop. #define MULMAGIC 2305843009U // 2**61/10**9 [both cases] #if DOUBLE #define MULSHIFTA 29 #define MULSHIFTB 32 #elif QUAD #define MULSHIFTA 30 #define MULSHIFTB 31 #else #error Unexpected type #endif #if DECTRACE printf("MulAccl:"); for (pl=accl+MULACCLEN-1; pl>=accl; pl--) printf(" %08lx:%08lx", (LI)(*pl>>32), (LI)(*pl&0xffffffff)); printf("\n"); #endif for (pl=accl, pa=acc; pl=MULTBASE) { // *pl holds a binary number which needs to be split hop=(uInt)(*pl>>MULSHIFTA); est=(uInt)(((uLong)hop*MULMAGIC)>>MULSHIFTB); // the estimate is now in est; now calculate hi:lo-est*10**9; // happily the top word of the result is irrelevant because it // will always be zero so this needs only one multiplication lo=(uInt)(*pl-((uLong)est*MULTBASE)); // low word of result // If QUAD, the correction here could be +2 if (lo>=MULTBASE) { lo-=MULTBASE; // correct by +1 est++; #if QUAD // may need to correct by +2 if (lo>=MULTBASE) { lo-=MULTBASE; est++; } #endif } // finally place lo as the new coefficient 'digit' and add est to // the next place up [this is safe because this path is never // taken on the final iteration as *pl will fit] *pa=lo; *(pl+1)+=est; } // *pl needed split else { // *pl1 may be // needed. Values of A and B are chosen to satisfy the constraints // just mentioned while minimizing the maximum error (and hence the // maximum correction), as shown in the following table: // // Type OPLEN A B maxX maxError maxCorrection // --------------------------------------------------------- // DOUBLE 2 29 32 <2*10**18 0.63 1 // QUAD 4 30 31 <4*10**18 1.17 2 // // In the OPLEN==2 case there is most choice, but the value for B // of 32 has a big advantage as then the calculation of the // estimate requires no shifting; the high word is simply // calculated from multiplying magic*hop. #define MULMAGIC 2305843009U // 2**61/10**9 [both cases] #if DOUBLE #define MULSHIFTA 29 #define MULSHIFTB 32 #elif QUAD #define MULSHIFTA 30 #define MULSHIFTB 31 #else #error Unexpected type #endif #if DECTRACE printf("MulHiLo:"); for (pa=acc+MULACCLEN-1; pa>=acc; pa--) printf(" %08lx:%08lx", (LI)*(pa+MULACCLEN), (LI)*pa); printf("\n"); #endif for (pa=acc;; pa++) { // each low uInt uInt hi, lo; // words of exact multiply result uInt hop, estlo; // work #if QUAD uInt esthi; // .. #endif lo=*pa; hi=*(pa+MULACCLEN); // top 32 bits // hi and lo now hold a binary number which needs to be split #if DOUBLE hop=(hi<<3)+(lo>>MULSHIFTA); // hi:lo/2**29 LONGMUL32HI(estlo, hop, MULMAGIC);// only need the high word // [MULSHIFTB is 32, so estlo can be used directly] // the estimate is now in estlo; now calculate hi:lo-est*10**9; // happily the top word of the result is irrelevant because it // will always be zero so this needs only one multiplication lo-=(estlo*MULTBASE); // esthi=0; // high word is ignored below // the correction here will be at most +1; do it if (lo>=MULTBASE) { lo-=MULTBASE; estlo++; } #elif QUAD hop=(hi<<2)+(lo>>MULSHIFTA); // hi:lo/2**30 LONGMUL32HI(esthi, hop, MULMAGIC);// shift will be 31 .. estlo=hop*MULMAGIC; // .. so low word needed estlo=(esthi<<1)+(estlo>>MULSHIFTB); // [just the top bit] // esthi=0; // high word is ignored below lo-=(estlo*MULTBASE); // as above // the correction here could be +1 or +2 if (lo>=MULTBASE) { lo-=MULTBASE; estlo++; } if (lo>=MULTBASE) { lo-=MULTBASE; estlo++; } #else #error Unexpected type #endif // finally place lo as the new accumulator digit and add est to // the next place up; this latter add could cause a carry of 1 // to the high word of the next place *pa=lo; *(pa+1)+=estlo; // esthi is always 0 for DOUBLE and QUAD so this is skipped // *(pa+1+MULACCLEN)+=esthi; if (*(pa+1)=acc; pa--) printf(" %09ld", (LI)*pa); printf("\n"); #endif // Now convert to BCD for rounding and cleanup, starting from the // most significant end pa=acc+MULACCLEN-1; if (*pa!=0) num->msd=bcdacc+LEADZEROS;// drop known lead zeros else { // >=1 word of leading zeros num->msd=bcdacc; // known leading zeros are gone pa--; // skip first word .. for (; *pa==0; pa--) if (pa==acc) break; // .. and any more leading 0s } for (ub=bcdacc;; pa--, ub+=9) { if (*pa!=0) { // split(s) needed uInt top, mid, rem; // work // *pa is non-zero -- split the base-billion acc digit into // hi, mid, and low three-digits #define mulsplit9 1000000 // divisor #define mulsplit6 1000 // divisor // The splitting is done by simple divides and remainders, // assuming the compiler will optimize these where useful // [GCC does] top=*pa/mulsplit9; rem=*pa%mulsplit9; mid=rem/mulsplit6; rem=rem%mulsplit6; // lay out the nine BCD digits (plus one unwanted byte) UBFROMUI(ub, UBTOUI(&BIN2BCD8[top*4])); UBFROMUI(ub+3, UBTOUI(&BIN2BCD8[mid*4])); UBFROMUI(ub+6, UBTOUI(&BIN2BCD8[rem*4])); } else { // *pa==0 UBFROMUI(ub, 0); // clear 9 BCD8s UBFROMUI(ub+4, 0); // .. *(ub+8)=0; // .. } if (pa==acc) break; } // BCD conversion loop num->lsd=ub+8; // complete the bcdnum .. #if DECTRACE decShowNum(num, "postmult"); decFloatShow(dfl, "dfl"); decFloatShow(dfr, "dfr"); #endif return; } // decFiniteMultiply /* ------------------------------------------------------------------ */ /* decFloatAbs -- absolute value, heeding NaNs, etc. */ /* */ /* result gets the canonicalized df with sign 0 */ /* df is the decFloat to abs */ /* set is the context */ /* returns result */ /* */ /* This has the same effect as decFloatPlus unless df is negative, */ /* in which case it has the same effect as decFloatMinus. The */ /* effect is also the same as decFloatCopyAbs except that NaNs are */ /* handled normally (the sign of a NaN is not affected, and an sNaN */ /* will signal) and the result will be canonical. */ /* ------------------------------------------------------------------ */ decFloat * decFloatAbs(decFloat *result, const decFloat *df, decContext *set) { if (DFISNAN(df)) return decNaNs(result, df, NULL, set); decCanonical(result, df); // copy and check DFBYTE(result, 0)&=~0x80; // zero sign bit return result; } // decFloatAbs /* ------------------------------------------------------------------ */ /* decFloatAdd -- add two decFloats */ /* */ /* result gets the result of adding dfl and dfr: */ /* dfl is the first decFloat (lhs) */ /* dfr is the second decFloat (rhs) */ /* set is the context */ /* returns result */ /* */ /* ------------------------------------------------------------------ */ #if QUAD // Table for testing MSDs for fastpath elimination; returns the MSD of // a decDouble or decQuad (top 6 bits tested) ignoring the sign. // Infinities return -32 and NaNs return -128 so that summing the two // MSDs also allows rapid tests for the Specials (see code below). const Int DECTESTMSD[64]={ 0, 1, 2, 3, 4, 5, 6, 7, 0, 1, 2, 3, 4, 5, 6, 7, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 8, 9, 8, 9, -32, -128, 0, 1, 2, 3, 4, 5, 6, 7, 0, 1, 2, 3, 4, 5, 6, 7, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 8, 9, 8, 9, -32, -128}; #else // The table for testing MSDs is shared between the modules extern const Int DECTESTMSD[64]; #endif decFloat * decFloatAdd(decFloat *result, const decFloat *dfl, const decFloat *dfr, decContext *set) { bcdnum num; // for final conversion Int bexpl, bexpr; // left and right biased exponents uByte *ub, *us, *ut; // work uInt uiwork; // for macros #if QUAD uShort uswork; // .. #endif uInt sourhil, sourhir; // top words from source decFloats // [valid only through end of // fastpath code -- before swap] uInt diffsign; // non-zero if signs differ uInt carry; // carry: 0 or 1 before add loop Int overlap; // coefficient overlap (if full) Int summ; // sum of the MSDs // the following buffers hold coefficients with various alignments // (see commentary and diagrams below) uByte acc[4+2+DECPMAX*3+8]; uByte buf[4+2+DECPMAX*2]; uByte *umsd, *ulsd; // local MSD and LSD pointers #if DECLITEND #define CARRYPAT 0x01000000 // carry=1 pattern #else #define CARRYPAT 0x00000001 // carry=1 pattern #endif /* Start decoding the arguments */ // The initial exponents are placed into the opposite Ints to // that which might be expected; there are two sets of data to // keep track of (each decFloat and the corresponding exponent), // and this scheme means that at the swap point (after comparing // exponents) only one pair of words needs to be swapped // whichever path is taken (thereby minimising worst-case path). // The calculated exponents will be nonsense when the arguments are // Special, but are not used in that path sourhil=DFWORD(dfl, 0); // LHS top word summ=DECTESTMSD[sourhil>>26]; // get first MSD for testing bexpr=DECCOMBEXP[sourhil>>26]; // get exponent high bits (in place) bexpr+=GETECON(dfl); // .. + continuation sourhir=DFWORD(dfr, 0); // RHS top word summ+=DECTESTMSD[sourhir>>26]; // sum MSDs for testing bexpl=DECCOMBEXP[sourhir>>26]; bexpl+=GETECON(dfr); // here bexpr has biased exponent from lhs, and vice versa diffsign=(sourhil^sourhir)&DECFLOAT_Sign; // now determine whether to take a fast path or the full-function // slow path. The slow path must be taken when: // -- both numbers are finite, and: // the exponents are different, or // the signs are different, or // the sum of the MSDs is >8 (hence might overflow) // specialness and the sum of the MSDs can be tested at once using // the summ value just calculated, so the test for specials is no // longer on the worst-case path (as of 3.60) if (summ<=8) { // MSD+MSD is good, or there is a special if (summ<0) { // there is a special // Inf+Inf would give -64; Inf+finite is -32 or higher if (summ<-64) return decNaNs(result, dfl, dfr, set); // one or two NaNs // two infinities with different signs is invalid if (summ==-64 && diffsign) return decInvalid(result, set); if (DFISINF(dfl)) return decInfinity(result, dfl); // LHS is infinite return decInfinity(result, dfr); // RHS must be Inf } // Here when both arguments are finite; fast path is possible // (currently only for aligned and same-sign) if (bexpr==bexpl && !diffsign) { uInt tac[DECLETS+1]; // base-1000 coefficient uInt encode; // work // Get one coefficient as base-1000 and add the other GETCOEFFTHOU(dfl, tac); // least-significant goes to [0] ADDCOEFFTHOU(dfr, tac); // here the sum of the MSDs (plus any carry) will be <10 due to // the fastpath test earlier // construct the result; low word is the same for both formats encode =BIN2DPD[tac[0]]; encode|=BIN2DPD[tac[1]]<<10; encode|=BIN2DPD[tac[2]]<<20; encode|=BIN2DPD[tac[3]]<<30; DFWORD(result, (DECBYTES/4)-1)=encode; // collect next two declets (all that remains, for Double) encode =BIN2DPD[tac[3]]>>2; encode|=BIN2DPD[tac[4]]<<8; #if QUAD // complete and lay out middling words encode|=BIN2DPD[tac[5]]<<18; encode|=BIN2DPD[tac[6]]<<28; DFWORD(result, 2)=encode; encode =BIN2DPD[tac[6]]>>4; encode|=BIN2DPD[tac[7]]<<6; encode|=BIN2DPD[tac[8]]<<16; encode|=BIN2DPD[tac[9]]<<26; DFWORD(result, 1)=encode; // and final two declets encode =BIN2DPD[tac[9]]>>6; encode|=BIN2DPD[tac[10]]<<4; #endif // add exponent continuation and sign (from either argument) encode|=sourhil & (ECONMASK | DECFLOAT_Sign); // create lookup index = MSD + top two bits of biased exponent <<4 tac[DECLETS]|=(bexpl>>DECECONL)<<4; encode|=DECCOMBFROM[tac[DECLETS]]; // add constructed combination field DFWORD(result, 0)=encode; // complete // decFloatShow(result, ">"); return result; } // fast path OK // drop through to slow path } // low sum or Special(s) /* Slow path required -- arguments are finite and might overflow, */ /* or require alignment, or might have different signs */ // now swap either exponents or argument pointers if (bexpl<=bexpr) { // original left is bigger Int bexpswap=bexpl; bexpl=bexpr; bexpr=bexpswap; // printf("left bigger\n"); } else { const decFloat *dfswap=dfl; dfl=dfr; dfr=dfswap; // printf("right bigger\n"); } // [here dfl and bexpl refer to the datum with the larger exponent, // of if the exponents are equal then the original LHS argument] // if lhs is zero then result will be the rhs (now known to have // the smaller exponent), which also may need to be tested for zero // for the weird IEEE 754 sign rules if (DFISZERO(dfl)) { decCanonical(result, dfr); // clean copy // "When the sum of two operands with opposite signs is // exactly zero, the sign of that sum shall be '+' in all // rounding modes except round toward -Infinity, in which // mode that sign shall be '-'." if (diffsign && DFISZERO(result)) { DFWORD(result, 0)&=~DECFLOAT_Sign; // assume sign 0 if (set->round==DEC_ROUND_FLOOR) DFWORD(result, 0)|=DECFLOAT_Sign; } return result; } // numfl is zero // [here, LHS is non-zero; code below assumes that] // Coefficients layout during the calculations to follow: // // Overlap case: // +------------------------------------------------+ // acc: |0000| coeffa | tail B | | // +------------------------------------------------+ // buf: |0000| pad0s | coeffb | | // +------------------------------------------------+ // // Touching coefficients or gap: // +------------------------------------------------+ // acc: |0000| coeffa | gap | coeffb | // +------------------------------------------------+ // [buf not used or needed; gap clamped to Pmax] // lay out lhs coefficient into accumulator; this starts at acc+4 // for decDouble or acc+6 for decQuad so the LSD is word- // aligned; the top word gap is there only in case a carry digit // is prefixed after the add -- it does not need to be zeroed #if DOUBLE #define COFF 4 // offset into acc #elif QUAD UBFROMUS(acc+4, 0); // prefix 00 #define COFF 6 // offset into acc #endif GETCOEFF(dfl, acc+COFF); // decode from decFloat ulsd=acc+COFF+DECPMAX-1; umsd=acc+4; // [having this here avoids #if DECTRACE {bcdnum tum; tum.msd=umsd; tum.lsd=ulsd; tum.exponent=bexpl-DECBIAS; tum.sign=DFWORD(dfl, 0) & DECFLOAT_Sign; decShowNum(&tum, "dflx");} #endif // if signs differ, take ten's complement of lhs (here the // coefficient is subtracted from all-nines; the 1 is added during // the later add cycle -- zeros to the right do not matter because // the complement of zero is zero); these are fixed-length inverts // where the lsd is known to be at a 4-byte boundary (so no borrow // possible) carry=0; // assume no carry if (diffsign) { carry=CARRYPAT; // for +1 during add UBFROMUI(acc+ 4, 0x09090909-UBTOUI(acc+ 4)); UBFROMUI(acc+ 8, 0x09090909-UBTOUI(acc+ 8)); UBFROMUI(acc+12, 0x09090909-UBTOUI(acc+12)); UBFROMUI(acc+16, 0x09090909-UBTOUI(acc+16)); #if QUAD UBFROMUI(acc+20, 0x09090909-UBTOUI(acc+20)); UBFROMUI(acc+24, 0x09090909-UBTOUI(acc+24)); UBFROMUI(acc+28, 0x09090909-UBTOUI(acc+28)); UBFROMUI(acc+32, 0x09090909-UBTOUI(acc+32)); UBFROMUI(acc+36, 0x09090909-UBTOUI(acc+36)); #endif } // diffsign // now process the rhs coefficient; if it cannot overlap lhs then // it can be put straight into acc (with an appropriate gap, if // needed) because no actual addition will be needed (except // possibly to complete ten's complement) overlap=DECPMAX-(bexpl-bexpr); #if DECTRACE printf("exps: %ld %ld\n", (LI)(bexpl-DECBIAS), (LI)(bexpr-DECBIAS)); printf("Overlap=%ld carry=%08lx\n", (LI)overlap, (LI)carry); #endif if (overlap<=0) { // no overlap possible uInt gap; // local work // since a full addition is not needed, a ten's complement // calculation started above may need to be completed if (carry) { for (ub=ulsd; *ub==9; ub--) *ub=0; *ub+=1; carry=0; // taken care of } // up to DECPMAX-1 digits of the final result can extend down // below the LSD of the lhs, so if the gap is >DECPMAX then the // rhs will be simply sticky bits. In this case the gap is // clamped to DECPMAX and the exponent adjusted to suit [this is // safe because the lhs is non-zero]. gap=-overlap; if (gap>DECPMAX) { bexpr+=gap-1; gap=DECPMAX; } ub=ulsd+gap+1; // where MSD will go // Fill the gap with 0s; note that there is no addition to do ut=acc+COFF+DECPMAX; // start of gap for (; ut DECPMAX *ub=(uByte)(!DFISZERO(dfr)); // make sticky digit } else { // need full coefficient GETCOEFF(dfr, ub); // decode from decFloat ub+=DECPMAX-1; // new LSD... } ulsd=ub; // save new LSD } // no overlap possible else { // overlap>0 // coefficients overlap (perhaps completely, although also // perhaps only where zeros) if (overlap==DECPMAX) { // aligned ub=buf+COFF; // where msd will go #if QUAD UBFROMUS(buf+4, 0); // clear quad's 00 #endif GETCOEFF(dfr, ub); // decode from decFloat } else { // unaligned ub=buf+COFF+DECPMAX-overlap; // where MSD will go // Fill the prefix gap with 0s; 8 will cover most common // unalignments, so start with direct assignments (a loop is // then used for any remaining -- the loop (and the one in a // moment) is not then on the critical path because the number // of additions is reduced by (at least) two in this case) UBFROMUI(buf+4, 0); // [clears decQuad 00 too] UBFROMUI(buf+8, 0); if (ub>buf+12) { ut=buf+12; // start any remaining for (; ut=acc+4; ut-=4, us-=4) { // big-endian add loop // bcd8 add carry+=UBTOUI(us); // rhs + carry if (carry==0) continue; // no-op carry+=UBTOUI(ut); // lhs // Big-endian BCD adjust (uses internal carry) carry+=0x76f6f6f6; // note top nibble not all bits // apply BCD adjust and save UBFROMUI(ut, (carry & 0x0f0f0f0f) - ((carry & 0x60606060)>>4)); carry>>=31; // true carry was at far left } // add loop #else for (; ut>=acc+4; ut-=4, us-=4) { // little-endian add loop // bcd8 add carry+=UBTOUI(us); // rhs + carry if (carry==0) continue; // no-op [common if unaligned] carry+=UBTOUI(ut); // lhs // Little-endian BCD adjust; inter-digit carry must be manual // because the lsb from the array will be in the most-significant // byte of carry carry+=0x76767676; // note no inter-byte carries carry+=(carry & 0x80000000)>>15; carry+=(carry & 0x00800000)>>15; carry+=(carry & 0x00008000)>>15; carry-=(carry & 0x60606060)>>4; // BCD adjust back UBFROMUI(ut, carry & 0x0f0f0f0f); // clear debris and save // here, final carry-out bit is at 0x00000080; move it ready // for next word-add (i.e., to 0x01000000) carry=(carry & 0x00000080)<<17; } // add loop #endif #if DECTRACE {bcdnum tum; printf("Add done, carry=%08lx, diffsign=%ld\n", (LI)carry, (LI)diffsign); tum.msd=umsd; // acc+4; tum.lsd=ulsd; tum.exponent=0; tum.sign=0; decShowNum(&tum, "dfadd");} #endif } // overlap possible // ordering here is a little strange in order to have slowest path // first in GCC asm listing if (diffsign) { // subtraction if (!carry) { // no carry out means RHS=umsd+BNEXT) { // unaligned // eight will handle most unaligments for Double; 16 for Quad UBFROMUI(umsd+BNEXT, 0x09090909-UBTOUI(umsd+BNEXT)); UBFROMUI(umsd+BNEXT+4, 0x09090909-UBTOUI(umsd+BNEXT+4)); #if DOUBLE #define BNEXTY (BNEXT+8) #elif QUAD UBFROMUI(umsd+BNEXT+8, 0x09090909-UBTOUI(umsd+BNEXT+8)); UBFROMUI(umsd+BNEXT+12, 0x09090909-UBTOUI(umsd+BNEXT+12)); #define BNEXTY (BNEXT+16) #endif if (ulsd>=umsd+BNEXTY) { // very unaligned ut=umsd+BNEXTY; // -> continue for (;;ut+=4) { UBFROMUI(ut, 0x09090909-UBTOUI(ut)); // invert four digits if (ut>=ulsd-3) break; // all done } } } // complete the ten's complement by adding 1 for (ub=ulsd; *ub==9; ub--) *ub=0; *ub+=1; } // borrowed else { // carry out means RHS>=LHS num.sign=DFWORD(dfr, 0) & DECFLOAT_Sign; // all done except for the special IEEE 754 exact-zero-result // rule (see above); while testing for zero, strip leading // zeros (which will save decFinalize doing it) (this is in // diffsign path, so carry impossible and true umsd is // acc+COFF) // Check the initial coefficient area using the fast macro; // this will often be all that needs to be done (as on the // worst-case path when the subtraction was aligned and // full-length) if (ISCOEFFZERO(acc+COFF)) { umsd=acc+COFF+DECPMAX-1; // so far, so zero if (ulsd>umsd) { // more to check umsd++; // to align after checked area for (; UBTOUI(umsd)==0 && umsd+3round==DEC_ROUND_FLOOR) num.sign=DECFLOAT_Sign; } } // [else was not zero, might still have leading zeros] } // subtraction gave positive result } // diffsign else { // same-sign addition num.sign=DFWORD(dfl, 0)&DECFLOAT_Sign; #if DOUBLE if (carry) { // only possible with decDouble *(acc+3)=1; // [Quad has leading 00] umsd=acc+3; } #endif } // same sign num.msd=umsd; // set MSD .. num.lsd=ulsd; // .. and LSD num.exponent=bexpr-DECBIAS; // set exponent to smaller, unbiassed #if DECTRACE decFloatShow(dfl, "dfl"); decFloatShow(dfr, "dfr"); decShowNum(&num, "postadd"); #endif return decFinalize(result, &num, set); // round, check, and lay out } // decFloatAdd /* ------------------------------------------------------------------ */ /* decFloatAnd -- logical digitwise AND of two decFloats */ /* */ /* result gets the result of ANDing dfl and dfr */ /* dfl is the first decFloat (lhs) */ /* dfr is the second decFloat (rhs) */ /* set is the context */ /* returns result, which will be canonical with sign=0 */ /* */ /* The operands must be positive, finite with exponent q=0, and */ /* comprise just zeros and ones; if not, Invalid operation results. */ /* ------------------------------------------------------------------ */ decFloat * decFloatAnd(decFloat *result, const decFloat *dfl, const decFloat *dfr, decContext *set) { if (!DFISUINT01(dfl) || !DFISUINT01(dfr) || !DFISCC01(dfl) || !DFISCC01(dfr)) return decInvalid(result, set); // the operands are positive finite integers (q=0) with just 0s and 1s #if DOUBLE DFWORD(result, 0)=ZEROWORD |((DFWORD(dfl, 0) & DFWORD(dfr, 0))&0x04009124); DFWORD(result, 1)=(DFWORD(dfl, 1) & DFWORD(dfr, 1))&0x49124491; #elif QUAD DFWORD(result, 0)=ZEROWORD |((DFWORD(dfl, 0) & DFWORD(dfr, 0))&0x04000912); DFWORD(result, 1)=(DFWORD(dfl, 1) & DFWORD(dfr, 1))&0x44912449; DFWORD(result, 2)=(DFWORD(dfl, 2) & DFWORD(dfr, 2))&0x12449124; DFWORD(result, 3)=(DFWORD(dfl, 3) & DFWORD(dfr, 3))&0x49124491; #endif return result; } // decFloatAnd /* ------------------------------------------------------------------ */ /* decFloatCanonical -- copy a decFloat, making canonical */ /* */ /* result gets the canonicalized df */ /* df is the decFloat to copy and make canonical */ /* returns result */ /* */ /* This works on specials, too; no error or exception is possible. */ /* ------------------------------------------------------------------ */ decFloat * decFloatCanonical(decFloat *result, const decFloat *df) { return decCanonical(result, df); } // decFloatCanonical /* ------------------------------------------------------------------ */ /* decFloatClass -- return the class of a decFloat */ /* */ /* df is the decFloat to test */ /* returns the decClass that df falls into */ /* ------------------------------------------------------------------ */ enum decClass decFloatClass(const decFloat *df) { Int exp; // exponent if (DFISSPECIAL(df)) { if (DFISQNAN(df)) return DEC_CLASS_QNAN; if (DFISSNAN(df)) return DEC_CLASS_SNAN; // must be an infinity if (DFISSIGNED(df)) return DEC_CLASS_NEG_INF; return DEC_CLASS_POS_INF; } if (DFISZERO(df)) { // quite common if (DFISSIGNED(df)) return DEC_CLASS_NEG_ZERO; return DEC_CLASS_POS_ZERO; } // is finite and non-zero; similar code to decFloatIsNormal, here // [this could be speeded up slightly by in-lining decFloatDigits] exp=GETEXPUN(df) // get unbiased exponent .. +decFloatDigits(df)-1; // .. and make adjusted exponent if (exp>=DECEMIN) { // is normal if (DFISSIGNED(df)) return DEC_CLASS_NEG_NORMAL; return DEC_CLASS_POS_NORMAL; } // is subnormal if (DFISSIGNED(df)) return DEC_CLASS_NEG_SUBNORMAL; return DEC_CLASS_POS_SUBNORMAL; } // decFloatClass /* ------------------------------------------------------------------ */ /* decFloatClassString -- return the class of a decFloat as a string */ /* */ /* df is the decFloat to test */ /* returns a constant string describing the class df falls into */ /* ------------------------------------------------------------------ */ const char *decFloatClassString(const decFloat *df) { enum decClass eclass=decFloatClass(df); if (eclass==DEC_CLASS_POS_NORMAL) return DEC_ClassString_PN; if (eclass==DEC_CLASS_NEG_NORMAL) return DEC_ClassString_NN; if (eclass==DEC_CLASS_POS_ZERO) return DEC_ClassString_PZ; if (eclass==DEC_CLASS_NEG_ZERO) return DEC_ClassString_NZ; if (eclass==DEC_CLASS_POS_SUBNORMAL) return DEC_ClassString_PS; if (eclass==DEC_CLASS_NEG_SUBNORMAL) return DEC_ClassString_NS; if (eclass==DEC_CLASS_POS_INF) return DEC_ClassString_PI; if (eclass==DEC_CLASS_NEG_INF) return DEC_ClassString_NI; if (eclass==DEC_CLASS_QNAN) return DEC_ClassString_QN; if (eclass==DEC_CLASS_SNAN) return DEC_ClassString_SN; return DEC_ClassString_UN; // Unknown } // decFloatClassString /* ------------------------------------------------------------------ */ /* decFloatCompare -- compare two decFloats; quiet NaNs allowed */ /* */ /* result gets the result of comparing dfl and dfr */ /* dfl is the first decFloat (lhs) */ /* dfr is the second decFloat (rhs) */ /* set is the context */ /* returns result, which may be -1, 0, 1, or NaN (Unordered) */ /* ------------------------------------------------------------------ */ decFloat * decFloatCompare(decFloat *result, const decFloat *dfl, const decFloat *dfr, decContext *set) { Int comp; // work // NaNs are handled as usual if (DFISNAN(dfl) || DFISNAN(dfr)) return decNaNs(result, dfl, dfr, set); // numeric comparison needed comp=decNumCompare(dfl, dfr, 0); decFloatZero(result); if (comp==0) return result; DFBYTE(result, DECBYTES-1)=0x01; // LSD=1 if (comp<0) DFBYTE(result, 0)|=0x80; // set sign bit return result; } // decFloatCompare /* ------------------------------------------------------------------ */ /* decFloatCompareSignal -- compare two decFloats; all NaNs signal */ /* */ /* result gets the result of comparing dfl and dfr */ /* dfl is the first decFloat (lhs) */ /* dfr is the second decFloat (rhs) */ /* set is the context */ /* returns result, which may be -1, 0, 1, or NaN (Unordered) */ /* ------------------------------------------------------------------ */ decFloat * decFloatCompareSignal(decFloat *result, const decFloat *dfl, const decFloat *dfr, decContext *set) { Int comp; // work // NaNs are handled as usual, except that all NaNs signal if (DFISNAN(dfl) || DFISNAN(dfr)) { set->status|=DEC_Invalid_operation; return decNaNs(result, dfl, dfr, set); } // numeric comparison needed comp=decNumCompare(dfl, dfr, 0); decFloatZero(result); if (comp==0) return result; DFBYTE(result, DECBYTES-1)=0x01; // LSD=1 if (comp<0) DFBYTE(result, 0)|=0x80; // set sign bit return result; } // decFloatCompareSignal /* ------------------------------------------------------------------ */ /* decFloatCompareTotal -- compare two decFloats with total ordering */ /* */ /* result gets the result of comparing dfl and dfr */ /* dfl is the first decFloat (lhs) */ /* dfr is the second decFloat (rhs) */ /* returns result, which may be -1, 0, or 1 */ /* ------------------------------------------------------------------ */ decFloat * decFloatCompareTotal(decFloat *result, const decFloat *dfl, const decFloat *dfr) { Int comp; // work uInt uiwork; // for macros #if QUAD uShort uswork; // .. #endif if (DFISNAN(dfl) || DFISNAN(dfr)) { Int nanl, nanr; // work // morph NaNs to +/- 1 or 2, leave numbers as 0 nanl=DFISSNAN(dfl)+DFISQNAN(dfl)*2; // quiet > signalling if (DFISSIGNED(dfl)) nanl=-nanl; nanr=DFISSNAN(dfr)+DFISQNAN(dfr)*2; if (DFISSIGNED(dfr)) nanr=-nanr; if (nanl>nanr) comp=+1; else if (nanl*uc) comp=sigl; // difference found else comp=-sigl; // .. break; } } } // same NaN type and sign } else { // numeric comparison needed comp=decNumCompare(dfl, dfr, 1); // total ordering } decFloatZero(result); if (comp==0) return result; DFBYTE(result, DECBYTES-1)=0x01; // LSD=1 if (comp<0) DFBYTE(result, 0)|=0x80; // set sign bit return result; } // decFloatCompareTotal /* ------------------------------------------------------------------ */ /* decFloatCompareTotalMag -- compare magnitudes with total ordering */ /* */ /* result gets the result of comparing abs(dfl) and abs(dfr) */ /* dfl is the first decFloat (lhs) */ /* dfr is the second decFloat (rhs) */ /* returns result, which may be -1, 0, or 1 */ /* ------------------------------------------------------------------ */ decFloat * decFloatCompareTotalMag(decFloat *result, const decFloat *dfl, const decFloat *dfr) { decFloat a, b; // for copy if needed // copy and redirect signed operand(s) if (DFISSIGNED(dfl)) { decFloatCopyAbs(&a, dfl); dfl=&a; } if (DFISSIGNED(dfr)) { decFloatCopyAbs(&b, dfr); dfr=&b; } return decFloatCompareTotal(result, dfl, dfr); } // decFloatCompareTotalMag /* ------------------------------------------------------------------ */ /* decFloatCopy -- copy a decFloat as-is */ /* */ /* result gets the copy of dfl */ /* dfl is the decFloat to copy */ /* returns result */ /* */ /* This is a bitwise operation; no errors or exceptions are possible. */ /* ------------------------------------------------------------------ */ decFloat * decFloatCopy(decFloat *result, const decFloat *dfl) { if (dfl!=result) *result=*dfl; // copy needed return result; } // decFloatCopy /* ------------------------------------------------------------------ */ /* decFloatCopyAbs -- copy a decFloat as-is and set sign bit to 0 */ /* */ /* result gets the copy of dfl with sign bit 0 */ /* dfl is the decFloat to copy */ /* returns result */ /* */ /* This is a bitwise operation; no errors or exceptions are possible. */ /* ------------------------------------------------------------------ */ decFloat * decFloatCopyAbs(decFloat *result, const decFloat *dfl) { if (dfl!=result) *result=*dfl; // copy needed DFBYTE(result, 0)&=~0x80; // zero sign bit return result; } // decFloatCopyAbs /* ------------------------------------------------------------------ */ /* decFloatCopyNegate -- copy a decFloat as-is with inverted sign bit */ /* */ /* result gets the copy of dfl with sign bit inverted */ /* dfl is the decFloat to copy */ /* returns result */ /* */ /* This is a bitwise operation; no errors or exceptions are possible. */ /* ------------------------------------------------------------------ */ decFloat * decFloatCopyNegate(decFloat *result, const decFloat *dfl) { if (dfl!=result) *result=*dfl; // copy needed DFBYTE(result, 0)^=0x80; // invert sign bit return result; } // decFloatCopyNegate /* ------------------------------------------------------------------ */ /* decFloatCopySign -- copy a decFloat with the sign of another */ /* */ /* result gets the result of copying dfl with the sign of dfr */ /* dfl is the first decFloat (lhs) */ /* dfr is the second decFloat (rhs) */ /* returns result */ /* */ /* This is a bitwise operation; no errors or exceptions are possible. */ /* ------------------------------------------------------------------ */ decFloat * decFloatCopySign(decFloat *result, const decFloat *dfl, const decFloat *dfr) { uByte sign=(uByte)(DFBYTE(dfr, 0)&0x80); // save sign bit if (dfl!=result) *result=*dfl; // copy needed DFBYTE(result, 0)&=~0x80; // clear sign .. DFBYTE(result, 0)=(uByte)(DFBYTE(result, 0)|sign); // .. and set saved return result; } // decFloatCopySign /* ------------------------------------------------------------------ */ /* decFloatDigits -- return the number of digits in a decFloat */ /* */ /* df is the decFloat to investigate */ /* returns the number of significant digits in the decFloat; a */ /* zero coefficient returns 1 as does an infinity (a NaN returns */ /* the number of digits in the payload) */ /* ------------------------------------------------------------------ */ // private macro to extract a declet according to provided formula // (form), and if it is non-zero then return the calculated digits // depending on the declet number (n), where n=0 for the most // significant declet; uses uInt dpd for work #define dpdlenchk(n, form) dpd=(form)&0x3ff; \ if (dpd) return (DECPMAX-1-3*(n))-(3-DPD2BCD8[dpd*4+3]) // next one is used when it is known that the declet must be // non-zero, or is the final zero declet #define dpdlendun(n, form) dpd=(form)&0x3ff; \ if (dpd==0) return 1; \ return (DECPMAX-1-3*(n))-(3-DPD2BCD8[dpd*4+3]) uInt decFloatDigits(const decFloat *df) { uInt dpd; // work uInt sourhi=DFWORD(df, 0); // top word from source decFloat #if QUAD uInt sourmh, sourml; #endif uInt sourlo; if (DFISINF(df)) return 1; // A NaN effectively has an MSD of 0; otherwise if non-zero MSD // then the coefficient is full-length if (!DFISNAN(df) && DECCOMBMSD[sourhi>>26]) return DECPMAX; #if DOUBLE if (sourhi&0x0003ffff) { // ends in first dpdlenchk(0, sourhi>>8); sourlo=DFWORD(df, 1); dpdlendun(1, (sourhi<<2) | (sourlo>>30)); } // [cannot drop through] sourlo=DFWORD(df, 1); // sourhi not involved now if (sourlo&0xfff00000) { // in one of first two dpdlenchk(1, sourlo>>30); // very rare dpdlendun(2, sourlo>>20); } // [cannot drop through] dpdlenchk(3, sourlo>>10); dpdlendun(4, sourlo); // [cannot drop through] #elif QUAD if (sourhi&0x00003fff) { // ends in first dpdlenchk(0, sourhi>>4); sourmh=DFWORD(df, 1); dpdlendun(1, ((sourhi)<<6) | (sourmh>>26)); } // [cannot drop through] sourmh=DFWORD(df, 1); if (sourmh) { dpdlenchk(1, sourmh>>26); dpdlenchk(2, sourmh>>16); dpdlenchk(3, sourmh>>6); sourml=DFWORD(df, 2); dpdlendun(4, ((sourmh)<<4) | (sourml>>28)); } // [cannot drop through] sourml=DFWORD(df, 2); if (sourml) { dpdlenchk(4, sourml>>28); dpdlenchk(5, sourml>>18); dpdlenchk(6, sourml>>8); sourlo=DFWORD(df, 3); dpdlendun(7, ((sourml)<<2) | (sourlo>>30)); } // [cannot drop through] sourlo=DFWORD(df, 3); if (sourlo&0xfff00000) { // in one of first two dpdlenchk(7, sourlo>>30); // very rare dpdlendun(8, sourlo>>20); } // [cannot drop through] dpdlenchk(9, sourlo>>10); dpdlendun(10, sourlo); // [cannot drop through] #endif } // decFloatDigits /* ------------------------------------------------------------------ */ /* decFloatDivide -- divide a decFloat by another */ /* */ /* result gets the result of dividing dfl by dfr: */ /* dfl is the first decFloat (lhs) */ /* dfr is the second decFloat (rhs) */ /* set is the context */ /* returns result */ /* */ /* ------------------------------------------------------------------ */ // This is just a wrapper. decFloat * decFloatDivide(decFloat *result, const decFloat *dfl, const decFloat *dfr, decContext *set) { return decDivide(result, dfl, dfr, set, DIVIDE); } // decFloatDivide /* ------------------------------------------------------------------ */ /* decFloatDivideInteger -- integer divide a decFloat by another */ /* */ /* result gets the result of dividing dfl by dfr: */ /* dfl is the first decFloat (lhs) */ /* dfr is the second decFloat (rhs) */ /* set is the context */ /* returns result */ /* */ /* ------------------------------------------------------------------ */ decFloat * decFloatDivideInteger(decFloat *result, const decFloat *dfl, const decFloat *dfr, decContext *set) { return decDivide(result, dfl, dfr, set, DIVIDEINT); } // decFloatDivideInteger /* ------------------------------------------------------------------ */ /* decFloatFMA -- multiply and add three decFloats, fused */ /* */ /* result gets the result of (dfl*dfr)+dff with a single rounding */ /* dfl is the first decFloat (lhs) */ /* dfr is the second decFloat (rhs) */ /* dff is the final decFloat (fhs) */ /* set is the context */ /* returns result */ /* */ /* ------------------------------------------------------------------ */ decFloat * decFloatFMA(decFloat *result, const decFloat *dfl, const decFloat *dfr, const decFloat *dff, decContext *set) { // The accumulator has the bytes needed for FiniteMultiply, plus // one byte to the left in case of carry, plus DECPMAX+2 to the // right for the final addition (up to full fhs + round & sticky) #define FMALEN (ROUNDUP4(1+ (DECPMAX9*18+1) +DECPMAX+2)) uByte acc[FMALEN]; // for multiplied coefficient in BCD // .. and for final result bcdnum mul; // for multiplication result bcdnum fin; // for final operand, expanded uByte coe[ROUNDUP4(DECPMAX)]; // dff coefficient in BCD bcdnum *hi, *lo; // bcdnum with higher/lower exponent uInt diffsign; // non-zero if signs differ uInt hipad; // pad digit for hi if needed Int padding; // excess exponent uInt carry; // +1 for ten's complement and during add uByte *ub, *uh, *ul; // work uInt uiwork; // for macros // handle all the special values [any special operand leads to a // special result] if (DFISSPECIAL(dfl) || DFISSPECIAL(dfr) || DFISSPECIAL(dff)) { decFloat proxy; // multiplication result proxy // NaNs are handled as usual, giving priority to sNaNs if (DFISSNAN(dfl) || DFISSNAN(dfr)) return decNaNs(result, dfl, dfr, set); if (DFISSNAN(dff)) return decNaNs(result, dff, NULL, set); if (DFISNAN(dfl) || DFISNAN(dfr)) return decNaNs(result, dfl, dfr, set); if (DFISNAN(dff)) return decNaNs(result, dff, NULL, set); // One or more of the three is infinite // infinity times zero is bad decFloatZero(&proxy); if (DFISINF(dfl)) { if (DFISZERO(dfr)) return decInvalid(result, set); decInfinity(&proxy, &proxy); } else if (DFISINF(dfr)) { if (DFISZERO(dfl)) return decInvalid(result, set); decInfinity(&proxy, &proxy); } // compute sign of multiplication and place in proxy DFWORD(&proxy, 0)|=(DFWORD(dfl, 0)^DFWORD(dfr, 0))&DECFLOAT_Sign; if (!DFISINF(dff)) return decFloatCopy(result, &proxy); // dff is Infinite if (!DFISINF(&proxy)) return decInfinity(result, dff); // both sides of addition are infinite; different sign is bad if ((DFWORD(dff, 0)&DECFLOAT_Sign)!=(DFWORD(&proxy, 0)&DECFLOAT_Sign)) return decInvalid(result, set); return decFloatCopy(result, &proxy); } /* Here when all operands are finite */ // First multiply dfl*dfr decFiniteMultiply(&mul, acc+1, dfl, dfr); // The multiply is complete, exact and unbounded, and described in // mul with the coefficient held in acc[1...] // now add in dff; the algorithm is essentially the same as // decFloatAdd, but the code is different because the code there // is highly optimized for adding two numbers of the same size fin.exponent=GETEXPUN(dff); // get dff exponent and sign fin.sign=DFWORD(dff, 0)&DECFLOAT_Sign; diffsign=mul.sign^fin.sign; // note if signs differ fin.msd=coe; fin.lsd=coe+DECPMAX-1; GETCOEFF(dff, coe); // extract the coefficient // now set hi and lo so that hi points to whichever of mul and fin // has the higher exponent and lo points to the other [don't care, // if the same]. One coefficient will be in acc, the other in coe. if (mul.exponent>=fin.exponent) { hi=&mul; lo=&fin; } else { hi=&fin; lo=&mul; } // remove leading zeros on both operands; this will save time later // and make testing for zero trivial (tests are safe because acc // and coe are rounded up to uInts) for (; UBTOUI(hi->msd)==0 && hi->msd+3lsd;) hi->msd+=4; for (; *hi->msd==0 && hi->msdlsd;) hi->msd++; for (; UBTOUI(lo->msd)==0 && lo->msd+3lsd;) lo->msd+=4; for (; *lo->msd==0 && lo->msdlsd;) lo->msd++; // if hi is zero then result will be lo (which has the smaller // exponent), which also may need to be tested for zero for the // weird IEEE 754 sign rules if (*hi->msd==0) { // hi is zero // "When the sum of two operands with opposite signs is // exactly zero, the sign of that sum shall be '+' in all // rounding modes except round toward -Infinity, in which // mode that sign shall be '-'." if (diffsign) { if (*lo->msd==0) { // lo is zero lo->sign=0; if (set->round==DEC_ROUND_FLOOR) lo->sign=DECFLOAT_Sign; } // diffsign && lo=0 } // diffsign return decFinalize(result, lo, set); // may need clamping } // numfl is zero // [here, both are minimal length and hi is non-zero] // (if lo is zero then padding with zeros may be needed, below) // if signs differ, take the ten's complement of hi (zeros to the // right do not matter because the complement of zero is zero); the // +1 is done later, as part of the addition, inserted at the // correct digit hipad=0; carry=0; if (diffsign) { hipad=9; carry=1; // exactly the correct number of digits must be inverted for (uh=hi->msd; uhlsd-3; uh+=4) UBFROMUI(uh, 0x09090909-UBTOUI(uh)); for (; uh<=hi->lsd; uh++) *uh=(uByte)(0x09-*uh); } // ready to add; note that hi has no leading zeros so gap // calculation does not have to be as pessimistic as in decFloatAdd // (this is much more like the arbitrary-precision algorithm in // Rexx and decNumber) // padding is the number of zeros that would need to be added to hi // for its lsd to be aligned with the lsd of lo padding=hi->exponent-lo->exponent; // printf("FMA pad %ld\n", (LI)padding); // the result of the addition will be built into the accumulator, // starting from the far right; this could be either hi or lo, and // will be aligned ub=acc+FMALEN-1; // where lsd of result will go ul=lo->lsd; // lsd of rhs if (padding!=0) { // unaligned // if the msd of lo is more than DECPMAX+2 digits to the right of // the original msd of hi then it can be reduced to a single // digit at the right place, as it stays clear of hi digits // [it must be DECPMAX+2 because during a subtraction the msd // could become 0 after a borrow from 1.000 to 0.9999...] Int hilen=(Int)(hi->lsd-hi->msd+1); // length of hi Int lolen=(Int)(lo->lsd-lo->msd+1); // and of lo if (hilen+padding-lolen > DECPMAX+2) { // can reduce lo to single // make sure it is virtually at least DECPMAX from hi->msd, at // least to right of hi->lsd (in case of destructive subtract), // and separated by at least two digits from either of those // (the tricky DOUBLE case is when hi is a 1 that will become a // 0.9999... by subtraction: // hi: 1 E+16 // lo: .................1000000000000000 E-16 // which for the addition pads to: // hi: 1000000000000000000 E-16 // lo: .................1000000000000000 E-16 Int newexp=MINI(hi->exponent, hi->exponent+hilen-DECPMAX)-3; // printf("FMA reduce: %ld\n", (LI)reduce); lo->lsd=lo->msd; // to single digit [maybe 0] lo->exponent=newexp; // new lowest exponent padding=hi->exponent-lo->exponent; // recalculate ul=lo->lsd; // .. and repoint } // padding is still > 0, but will fit in acc (less leading carry slot) #if DECCHECK if (padding<=0) printf("FMA low padding: %ld\n", (LI)padding); if (hilen+padding+1>FMALEN) printf("FMA excess hilen+padding: %ld+%ld \n", (LI)hilen, (LI)padding); // printf("FMA padding: %ld\n", (LI)padding); #endif // padding digits can now be set in the result; one or more of // these will come from lo; others will be zeros in the gap for (; ul-3>=lo->msd && padding>3; padding-=4, ul-=4, ub-=4) { UBFROMUI(ub-3, UBTOUI(ul-3)); // [cannot overlap] } for (; ul>=lo->msd && padding>0; padding--, ul--, ub--) *ub=*ul; for (;padding>0; padding--, ub--) *ub=0; // mind the gap } // addition now complete to the right of the rightmost digit of hi uh=hi->lsd; // dow do the add from hi->lsd to the left // [bytewise, because either operand can run out at any time] // carry was set up depending on ten's complement above // first assume both operands have some digits for (;; ub--) { if (uhmsd || ulmsd) break; *ub=(uByte)(carry+(*uh--)+(*ul--)); carry=0; if (*ub<10) continue; *ub-=10; carry=1; } // both loop if (ulmsd) { // to left of lo for (;; ub--) { if (uhmsd) break; *ub=(uByte)(carry+(*uh--)); // [+0] carry=0; if (*ub<10) continue; *ub-=10; carry=1; } // hi loop } else { // to left of hi for (;; ub--) { if (ulmsd) break; *ub=(uByte)(carry+hipad+(*ul--)); carry=0; if (*ub<10) continue; *ub-=10; carry=1; } // lo loop } // addition complete -- now handle carry, borrow, etc. // use lo to set up the num (its exponent is already correct, and // sign usually is) lo->msd=ub+1; lo->lsd=acc+FMALEN-1; // decShowNum(lo, "lo"); if (!diffsign) { // same-sign addition if (carry) { // carry out *ub=1; // place the 1 .. lo->msd--; // .. and update } } // same sign else { // signs differed (subtraction) if (!carry) { // no carry out means hisign=hi->sign; // sign is lhs sign for (ul=lo->msd; ullsd-3; ul+=4) UBFROMUI(ul, 0x09090909-UBTOUI(ul)); for (; ul<=lo->lsd; ul++) *ul=(uByte)(0x09-*ul); // [leaves ul at lsd+1] // complete the ten's complement by adding 1 [cannot overrun] for (ul--; *ul==9; ul--) *ul=0; *ul+=1; } // borrowed else { // carry out means hi>=lo // sign to use is lo->sign // all done except for the special IEEE 754 exact-zero-result // rule (see above); while testing for zero, strip leading // zeros (which will save decFinalize doing it) for (; UBTOUI(lo->msd)==0 && lo->msd+3lsd;) lo->msd+=4; for (; *lo->msd==0 && lo->msdlsd;) lo->msd++; if (*lo->msd==0) { // must be true zero (and diffsign) lo->sign=0; // assume + if (set->round==DEC_ROUND_FLOOR) lo->sign=DECFLOAT_Sign; } // [else was not zero, might still have leading zeros] } // subtraction gave positive result } // diffsign #if DECCHECK // assert no left underrun if (lo->msdmsd)); } #endif return decFinalize(result, lo, set); // round, check, and lay out } // decFloatFMA /* ------------------------------------------------------------------ */ /* decFloatFromInt -- initialise a decFloat from an Int */ /* */ /* result gets the converted Int */ /* n is the Int to convert */ /* returns result */ /* */ /* The result is Exact; no errors or exceptions are possible. */ /* ------------------------------------------------------------------ */ decFloat * decFloatFromInt32(decFloat *result, Int n) { uInt u=(uInt)n; // copy as bits uInt encode; // work DFWORD(result, 0)=ZEROWORD; // always #if QUAD DFWORD(result, 1)=0; DFWORD(result, 2)=0; #endif if (n<0) { // handle -n with care // [This can be done without the test, but is then slightly slower] u=(~u)+1; DFWORD(result, 0)|=DECFLOAT_Sign; } // Since the maximum value of u now is 2**31, only the low word of // result is affected encode=BIN2DPD[u%1000]; u/=1000; encode|=BIN2DPD[u%1000]<<10; u/=1000; encode|=BIN2DPD[u%1000]<<20; u/=1000; // now 0, 1, or 2 encode|=u<<30; DFWORD(result, DECWORDS-1)=encode; return result; } // decFloatFromInt32 /* ------------------------------------------------------------------ */ /* decFloatFromUInt -- initialise a decFloat from a uInt */ /* */ /* result gets the converted uInt */ /* n is the uInt to convert */ /* returns result */ /* */ /* The result is Exact; no errors or exceptions are possible. */ /* ------------------------------------------------------------------ */ decFloat * decFloatFromUInt32(decFloat *result, uInt u) { uInt encode; // work DFWORD(result, 0)=ZEROWORD; // always #if QUAD DFWORD(result, 1)=0; DFWORD(result, 2)=0; #endif encode=BIN2DPD[u%1000]; u/=1000; encode|=BIN2DPD[u%1000]<<10; u/=1000; encode|=BIN2DPD[u%1000]<<20; u/=1000; // now 0 -> 4 encode|=u<<30; DFWORD(result, DECWORDS-1)=encode; DFWORD(result, DECWORDS-2)|=u>>2; // rarely non-zero return result; } // decFloatFromUInt32 /* ------------------------------------------------------------------ */ /* decFloatInvert -- logical digitwise INVERT of a decFloat */ /* */ /* result gets the result of INVERTing df */ /* df is the decFloat to invert */ /* set is the context */ /* returns result, which will be canonical with sign=0 */ /* */ /* The operand must be positive, finite with exponent q=0, and */ /* comprise just zeros and ones; if not, Invalid operation results. */ /* ------------------------------------------------------------------ */ decFloat * decFloatInvert(decFloat *result, const decFloat *df, decContext *set) { uInt sourhi=DFWORD(df, 0); // top word of dfs if (!DFISUINT01(df) || !DFISCC01(df)) return decInvalid(result, set); // the operand is a finite integer (q=0) #if DOUBLE DFWORD(result, 0)=ZEROWORD|((~sourhi)&0x04009124); DFWORD(result, 1)=(~DFWORD(df, 1)) &0x49124491; #elif QUAD DFWORD(result, 0)=ZEROWORD|((~sourhi)&0x04000912); DFWORD(result, 1)=(~DFWORD(df, 1)) &0x44912449; DFWORD(result, 2)=(~DFWORD(df, 2)) &0x12449124; DFWORD(result, 3)=(~DFWORD(df, 3)) &0x49124491; #endif return result; } // decFloatInvert /* ------------------------------------------------------------------ */ /* decFloatIs -- decFloat tests (IsSigned, etc.) */ /* */ /* df is the decFloat to test */ /* returns 0 or 1 in a uInt */ /* */ /* Many of these could be macros, but having them as real functions */ /* is a little cleaner (and they can be referred to here by the */ /* generic names) */ /* ------------------------------------------------------------------ */ uInt decFloatIsCanonical(const decFloat *df) { if (DFISSPECIAL(df)) { if (DFISINF(df)) { if (DFWORD(df, 0)&ECONMASK) return 0; // exponent continuation if (!DFISCCZERO(df)) return 0; // coefficient continuation return 1; } // is a NaN if (DFWORD(df, 0)&ECONNANMASK) return 0; // exponent continuation if (DFISCCZERO(df)) return 1; // coefficient continuation // drop through to check payload } { // declare block #if DOUBLE uInt sourhi=DFWORD(df, 0); uInt sourlo=DFWORD(df, 1); if (CANONDPDOFF(sourhi, 8) && CANONDPDTWO(sourhi, sourlo, 30) && CANONDPDOFF(sourlo, 20) && CANONDPDOFF(sourlo, 10) && CANONDPDOFF(sourlo, 0)) return 1; #elif QUAD uInt sourhi=DFWORD(df, 0); uInt sourmh=DFWORD(df, 1); uInt sourml=DFWORD(df, 2); uInt sourlo=DFWORD(df, 3); if (CANONDPDOFF(sourhi, 4) && CANONDPDTWO(sourhi, sourmh, 26) && CANONDPDOFF(sourmh, 16) && CANONDPDOFF(sourmh, 6) && CANONDPDTWO(sourmh, sourml, 28) && CANONDPDOFF(sourml, 18) && CANONDPDOFF(sourml, 8) && CANONDPDTWO(sourml, sourlo, 30) && CANONDPDOFF(sourlo, 20) && CANONDPDOFF(sourlo, 10) && CANONDPDOFF(sourlo, 0)) return 1; #endif } // block return 0; // a declet is non-canonical } uInt decFloatIsFinite(const decFloat *df) { return !DFISSPECIAL(df); } uInt decFloatIsInfinite(const decFloat *df) { return DFISINF(df); } uInt decFloatIsInteger(const decFloat *df) { return DFISINT(df); } uInt decFloatIsLogical(const decFloat *df) { return DFISUINT01(df) & DFISCC01(df); } uInt decFloatIsNaN(const decFloat *df) { return DFISNAN(df); } uInt decFloatIsNegative(const decFloat *df) { return DFISSIGNED(df) && !DFISZERO(df) && !DFISNAN(df); } uInt decFloatIsNormal(const decFloat *df) { Int exp; // exponent if (DFISSPECIAL(df)) return 0; if (DFISZERO(df)) return 0; // is finite and non-zero exp=GETEXPUN(df) // get unbiased exponent .. +decFloatDigits(df)-1; // .. and make adjusted exponent return (exp>=DECEMIN); // < DECEMIN is subnormal } uInt decFloatIsPositive(const decFloat *df) { return !DFISSIGNED(df) && !DFISZERO(df) && !DFISNAN(df); } uInt decFloatIsSignaling(const decFloat *df) { return DFISSNAN(df); } uInt decFloatIsSignalling(const decFloat *df) { return DFISSNAN(df); } uInt decFloatIsSigned(const decFloat *df) { return DFISSIGNED(df); } uInt decFloatIsSubnormal(const decFloat *df) { if (DFISSPECIAL(df)) return 0; // is finite if (decFloatIsNormal(df)) return 0; // it is Use |A| */ /* A=0 -> -Infinity (Division by zero) */ /* A=Infinite -> +Infinity (Exact) */ /* A=1 exactly -> 0 (Exact) */ /* NaNs are propagated as usual */ /* ------------------------------------------------------------------ */ decFloat * decFloatLogB(decFloat *result, const decFloat *df, decContext *set) { Int ae; // adjusted exponent if (DFISNAN(df)) return decNaNs(result, df, NULL, set); if (DFISINF(df)) { DFWORD(result, 0)=0; // need +ve return decInfinity(result, result); // canonical +Infinity } if (DFISZERO(df)) { set->status|=DEC_Division_by_zero; // as per 754 DFWORD(result, 0)=DECFLOAT_Sign; // make negative return decInfinity(result, result); // canonical -Infinity } ae=GETEXPUN(df) // get unbiased exponent .. +decFloatDigits(df)-1; // .. and make adjusted exponent // ae has limited range (3 digits for DOUBLE and 4 for QUAD), so // it is worth using a special case of decFloatFromInt32 DFWORD(result, 0)=ZEROWORD; // always if (ae<0) { DFWORD(result, 0)|=DECFLOAT_Sign; // -0 so far ae=-ae; } #if DOUBLE DFWORD(result, 1)=BIN2DPD[ae]; // a single declet #elif QUAD DFWORD(result, 1)=0; DFWORD(result, 2)=0; DFWORD(result, 3)=(ae/1000)<<10; // is <10, so need no DPD encode DFWORD(result, 3)|=BIN2DPD[ae%1000]; #endif return result; } // decFloatLogB /* ------------------------------------------------------------------ */ /* decFloatMax -- return maxnum of two operands */ /* */ /* result gets the chosen decFloat */ /* dfl is the first decFloat (lhs) */ /* dfr is the second decFloat (rhs) */ /* set is the context */ /* returns result */ /* */ /* If just one operand is a quiet NaN it is ignored. */ /* ------------------------------------------------------------------ */ decFloat * decFloatMax(decFloat *result, const decFloat *dfl, const decFloat *dfr, decContext *set) { Int comp; if (DFISNAN(dfl)) { // sNaN or both NaNs leads to normal NaN processing if (DFISNAN(dfr) || DFISSNAN(dfl)) return decNaNs(result, dfl, dfr, set); return decCanonical(result, dfr); // RHS is numeric } if (DFISNAN(dfr)) { // sNaN leads to normal NaN processing (both NaN handled above) if (DFISSNAN(dfr)) return decNaNs(result, dfl, dfr, set); return decCanonical(result, dfl); // LHS is numeric } // Both operands are numeric; numeric comparison needed -- use // total order for a well-defined choice (and +0 > -0) comp=decNumCompare(dfl, dfr, 1); if (comp>=0) return decCanonical(result, dfl); return decCanonical(result, dfr); } // decFloatMax /* ------------------------------------------------------------------ */ /* decFloatMaxMag -- return maxnummag of two operands */ /* */ /* result gets the chosen decFloat */ /* dfl is the first decFloat (lhs) */ /* dfr is the second decFloat (rhs) */ /* set is the context */ /* returns result */ /* */ /* Returns according to the magnitude comparisons if both numeric and */ /* unequal, otherwise returns maxnum */ /* ------------------------------------------------------------------ */ decFloat * decFloatMaxMag(decFloat *result, const decFloat *dfl, const decFloat *dfr, decContext *set) { Int comp; decFloat absl, absr; if (DFISNAN(dfl) || DFISNAN(dfr)) return decFloatMax(result, dfl, dfr, set); decFloatCopyAbs(&absl, dfl); decFloatCopyAbs(&absr, dfr); comp=decNumCompare(&absl, &absr, 0); if (comp>0) return decCanonical(result, dfl); if (comp<0) return decCanonical(result, dfr); return decFloatMax(result, dfl, dfr, set); } // decFloatMaxMag /* ------------------------------------------------------------------ */ /* decFloatMin -- return minnum of two operands */ /* */ /* result gets the chosen decFloat */ /* dfl is the first decFloat (lhs) */ /* dfr is the second decFloat (rhs) */ /* set is the context */ /* returns result */ /* */ /* If just one operand is a quiet NaN it is ignored. */ /* ------------------------------------------------------------------ */ decFloat * decFloatMin(decFloat *result, const decFloat *dfl, const decFloat *dfr, decContext *set) { Int comp; if (DFISNAN(dfl)) { // sNaN or both NaNs leads to normal NaN processing if (DFISNAN(dfr) || DFISSNAN(dfl)) return decNaNs(result, dfl, dfr, set); return decCanonical(result, dfr); // RHS is numeric } if (DFISNAN(dfr)) { // sNaN leads to normal NaN processing (both NaN handled above) if (DFISSNAN(dfr)) return decNaNs(result, dfl, dfr, set); return decCanonical(result, dfl); // LHS is numeric } // Both operands are numeric; numeric comparison needed -- use // total order for a well-defined choice (and +0 > -0) comp=decNumCompare(dfl, dfr, 1); if (comp<=0) return decCanonical(result, dfl); return decCanonical(result, dfr); } // decFloatMin /* ------------------------------------------------------------------ */ /* decFloatMinMag -- return minnummag of two operands */ /* */ /* result gets the chosen decFloat */ /* dfl is the first decFloat (lhs) */ /* dfr is the second decFloat (rhs) */ /* set is the context */ /* returns result */ /* */ /* Returns according to the magnitude comparisons if both numeric and */ /* unequal, otherwise returns minnum */ /* ------------------------------------------------------------------ */ decFloat * decFloatMinMag(decFloat *result, const decFloat *dfl, const decFloat *dfr, decContext *set) { Int comp; decFloat absl, absr; if (DFISNAN(dfl) || DFISNAN(dfr)) return decFloatMin(result, dfl, dfr, set); decFloatCopyAbs(&absl, dfl); decFloatCopyAbs(&absr, dfr); comp=decNumCompare(&absl, &absr, 0); if (comp<0) return decCanonical(result, dfl); if (comp>0) return decCanonical(result, dfr); return decFloatMin(result, dfl, dfr, set); } // decFloatMinMag /* ------------------------------------------------------------------ */ /* decFloatMinus -- negate value, heeding NaNs, etc. */ /* */ /* result gets the canonicalized 0-df */ /* df is the decFloat to minus */ /* set is the context */ /* returns result */ /* */ /* This has the same effect as 0-df where the exponent of the zero is */ /* the same as that of df (if df is finite). */ /* The effect is also the same as decFloatCopyNegate except that NaNs */ /* are handled normally (the sign of a NaN is not affected, and an */ /* sNaN will signal), the result is canonical, and zero gets sign 0. */ /* ------------------------------------------------------------------ */ decFloat * decFloatMinus(decFloat *result, const decFloat *df, decContext *set) { if (DFISNAN(df)) return decNaNs(result, df, NULL, set); decCanonical(result, df); // copy and check if (DFISZERO(df)) DFBYTE(result, 0)&=~0x80; // turn off sign bit else DFBYTE(result, 0)^=0x80; // flip sign bit return result; } // decFloatMinus /* ------------------------------------------------------------------ */ /* decFloatMultiply -- multiply two decFloats */ /* */ /* result gets the result of multiplying dfl and dfr: */ /* dfl is the first decFloat (lhs) */ /* dfr is the second decFloat (rhs) */ /* set is the context */ /* returns result */ /* */ /* ------------------------------------------------------------------ */ decFloat * decFloatMultiply(decFloat *result, const decFloat *dfl, const decFloat *dfr, decContext *set) { bcdnum num; // for final conversion uByte bcdacc[DECPMAX9*18+1]; // for coefficent in BCD if (DFISSPECIAL(dfl) || DFISSPECIAL(dfr)) { // either is special? // NaNs are handled as usual if (DFISNAN(dfl) || DFISNAN(dfr)) return decNaNs(result, dfl, dfr, set); // infinity times zero is bad if (DFISINF(dfl) && DFISZERO(dfr)) return decInvalid(result, set); if (DFISINF(dfr) && DFISZERO(dfl)) return decInvalid(result, set); // both infinite; return canonical infinity with computed sign DFWORD(result, 0)=DFWORD(dfl, 0)^DFWORD(dfr, 0); // compute sign return decInfinity(result, result); } /* Here when both operands are finite */ decFiniteMultiply(&num, bcdacc, dfl, dfr); return decFinalize(result, &num, set); // round, check, and lay out } // decFloatMultiply /* ------------------------------------------------------------------ */ /* decFloatNextMinus -- next towards -Infinity */ /* */ /* result gets the next lesser decFloat */ /* dfl is the decFloat to start with */ /* set is the context */ /* returns result */ /* */ /* This is 754 nextdown; Invalid is the only status possible (from */ /* an sNaN). */ /* ------------------------------------------------------------------ */ decFloat * decFloatNextMinus(decFloat *result, const decFloat *dfl, decContext *set) { decFloat delta; // tiny increment uInt savestat; // saves status enum rounding saveround; // .. and mode // +Infinity is the special case if (DFISINF(dfl) && !DFISSIGNED(dfl)) { DFSETNMAX(result); return result; // [no status to set] } // other cases are effected by sutracting a tiny delta -- this // should be done in a wider format as the delta is unrepresentable // here (but can be done with normal add if the sign of zero is // treated carefully, because no Inexactitude is interesting); // rounding to -Infinity then pushes the result to next below decFloatZero(&delta); // set up tiny delta DFWORD(&delta, DECWORDS-1)=1; // coefficient=1 DFWORD(&delta, 0)=DECFLOAT_Sign; // Sign=1 + biased exponent=0 // set up for the directional round saveround=set->round; // save mode set->round=DEC_ROUND_FLOOR; // .. round towards -Infinity savestat=set->status; // save status decFloatAdd(result, dfl, &delta, set); // Add rules mess up the sign when going from +Ntiny to 0 if (DFISZERO(result)) DFWORD(result, 0)^=DECFLOAT_Sign; // correct set->status&=DEC_Invalid_operation; // preserve only sNaN status set->status|=savestat; // restore pending flags set->round=saveround; // .. and mode return result; } // decFloatNextMinus /* ------------------------------------------------------------------ */ /* decFloatNextPlus -- next towards +Infinity */ /* */ /* result gets the next larger decFloat */ /* dfl is the decFloat to start with */ /* set is the context */ /* returns result */ /* */ /* This is 754 nextup; Invalid is the only status possible (from */ /* an sNaN). */ /* ------------------------------------------------------------------ */ decFloat * decFloatNextPlus(decFloat *result, const decFloat *dfl, decContext *set) { uInt savestat; // saves status enum rounding saveround; // .. and mode decFloat delta; // tiny increment // -Infinity is the special case if (DFISINF(dfl) && DFISSIGNED(dfl)) { DFSETNMAX(result); DFWORD(result, 0)|=DECFLOAT_Sign; // make negative return result; // [no status to set] } // other cases are effected by sutracting a tiny delta -- this // should be done in a wider format as the delta is unrepresentable // here (but can be done with normal add if the sign of zero is // treated carefully, because no Inexactitude is interesting); // rounding to +Infinity then pushes the result to next above decFloatZero(&delta); // set up tiny delta DFWORD(&delta, DECWORDS-1)=1; // coefficient=1 DFWORD(&delta, 0)=0; // Sign=0 + biased exponent=0 // set up for the directional round saveround=set->round; // save mode set->round=DEC_ROUND_CEILING; // .. round towards +Infinity savestat=set->status; // save status decFloatAdd(result, dfl, &delta, set); // Add rules mess up the sign when going from -Ntiny to -0 if (DFISZERO(result)) DFWORD(result, 0)^=DECFLOAT_Sign; // correct set->status&=DEC_Invalid_operation; // preserve only sNaN status set->status|=savestat; // restore pending flags set->round=saveround; // .. and mode return result; } // decFloatNextPlus /* ------------------------------------------------------------------ */ /* decFloatNextToward -- next towards a decFloat */ /* */ /* result gets the next decFloat */ /* dfl is the decFloat to start with */ /* dfr is the decFloat to move toward */ /* set is the context */ /* returns result */ /* */ /* This is 754-1985 nextafter, as modified during revision (dropped */ /* from 754-2008); status may be set unless the result is a normal */ /* number. */ /* ------------------------------------------------------------------ */ decFloat * decFloatNextToward(decFloat *result, const decFloat *dfl, const decFloat *dfr, decContext *set) { decFloat delta; // tiny increment or decrement decFloat pointone; // 1e-1 uInt savestat; // saves status enum rounding saveround; // .. and mode uInt deltatop; // top word for delta Int comp; // work if (DFISNAN(dfl) || DFISNAN(dfr)) return decNaNs(result, dfl, dfr, set); // Both are numeric, so Invalid no longer a possibility comp=decNumCompare(dfl, dfr, 0); if (comp==0) return decFloatCopySign(result, dfl, dfr); // equal // unequal; do NextPlus or NextMinus but with different status rules if (comp<0) { // lhsround; // save mode set->round=DEC_ROUND_CEILING; // .. round towards +Infinity deltatop=0; // positive delta } else { // lhs>rhs, do NextMinus, see above for commentary if (DFISINF(dfl) && !DFISSIGNED(dfl)) { // +Infinity special case DFSETNMAX(result); return result; } saveround=set->round; // save mode set->round=DEC_ROUND_FLOOR; // .. round towards -Infinity deltatop=DECFLOAT_Sign; // negative delta } savestat=set->status; // save status // Here, Inexact is needed where appropriate (and hence Underflow, // etc.). Therefore the tiny delta which is otherwise // unrepresentable (see NextPlus and NextMinus) is constructed // using the multiplication of FMA. decFloatZero(&delta); // set up tiny delta DFWORD(&delta, DECWORDS-1)=1; // coefficient=1 DFWORD(&delta, 0)=deltatop; // Sign + biased exponent=0 decFloatFromString(&pointone, "1E-1", set); // set up multiplier decFloatFMA(result, &delta, &pointone, dfl, set); // [Delta is truly tiny, so no need to correct sign of zero] // use new status unless the result is normal if (decFloatIsNormal(result)) set->status=savestat; // else goes forward set->round=saveround; // restore mode return result; } // decFloatNextToward /* ------------------------------------------------------------------ */ /* decFloatOr -- logical digitwise OR of two decFloats */ /* */ /* result gets the result of ORing dfl and dfr */ /* dfl is the first decFloat (lhs) */ /* dfr is the second decFloat (rhs) */ /* set is the context */ /* returns result, which will be canonical with sign=0 */ /* */ /* The operands must be positive, finite with exponent q=0, and */ /* comprise just zeros and ones; if not, Invalid operation results. */ /* ------------------------------------------------------------------ */ decFloat * decFloatOr(decFloat *result, const decFloat *dfl, const decFloat *dfr, decContext *set) { if (!DFISUINT01(dfl) || !DFISUINT01(dfr) || !DFISCC01(dfl) || !DFISCC01(dfr)) return decInvalid(result, set); // the operands are positive finite integers (q=0) with just 0s and 1s #if DOUBLE DFWORD(result, 0)=ZEROWORD |((DFWORD(dfl, 0) | DFWORD(dfr, 0))&0x04009124); DFWORD(result, 1)=(DFWORD(dfl, 1) | DFWORD(dfr, 1))&0x49124491; #elif QUAD DFWORD(result, 0)=ZEROWORD |((DFWORD(dfl, 0) | DFWORD(dfr, 0))&0x04000912); DFWORD(result, 1)=(DFWORD(dfl, 1) | DFWORD(dfr, 1))&0x44912449; DFWORD(result, 2)=(DFWORD(dfl, 2) | DFWORD(dfr, 2))&0x12449124; DFWORD(result, 3)=(DFWORD(dfl, 3) | DFWORD(dfr, 3))&0x49124491; #endif return result; } // decFloatOr /* ------------------------------------------------------------------ */ /* decFloatPlus -- add value to 0, heeding NaNs, etc. */ /* */ /* result gets the canonicalized 0+df */ /* df is the decFloat to plus */ /* set is the context */ /* returns result */ /* */ /* This has the same effect as 0+df where the exponent of the zero is */ /* the same as that of df (if df is finite). */ /* The effect is also the same as decFloatCopy except that NaNs */ /* are handled normally (the sign of a NaN is not affected, and an */ /* sNaN will signal), the result is canonical, and zero gets sign 0. */ /* ------------------------------------------------------------------ */ decFloat * decFloatPlus(decFloat *result, const decFloat *df, decContext *set) { if (DFISNAN(df)) return decNaNs(result, df, NULL, set); decCanonical(result, df); // copy and check if (DFISZERO(df)) DFBYTE(result, 0)&=~0x80; // turn off sign bit return result; } // decFloatPlus /* ------------------------------------------------------------------ */ /* decFloatQuantize -- quantize a decFloat */ /* */ /* result gets the result of quantizing dfl to match dfr */ /* dfl is the first decFloat (lhs) */ /* dfr is the second decFloat (rhs), which sets the exponent */ /* set is the context */ /* returns result */ /* */ /* Unless there is an error or the result is infinite, the exponent */ /* of result is guaranteed to be the same as that of dfr. */ /* ------------------------------------------------------------------ */ decFloat * decFloatQuantize(decFloat *result, const decFloat *dfl, const decFloat *dfr, decContext *set) { Int explb, exprb; // left and right biased exponents uByte *ulsd; // local LSD pointer uByte *ub, *uc; // work Int drop; // .. uInt dpd; // .. uInt encode; // encoding accumulator uInt sourhil, sourhir; // top words from source decFloats uInt uiwork; // for macros #if QUAD uShort uswork; // .. #endif // the following buffer holds the coefficient for manipulation uByte buf[4+DECPMAX*3+2*QUAD]; // + space for zeros to left or right #if DECTRACE bcdnum num; // for trace displays #endif /* Start decoding the arguments */ sourhil=DFWORD(dfl, 0); // LHS top word explb=DECCOMBEXP[sourhil>>26]; // get exponent high bits (in place) sourhir=DFWORD(dfr, 0); // RHS top word exprb=DECCOMBEXP[sourhir>>26]; if (EXPISSPECIAL(explb | exprb)) { // either is special? // NaNs are handled as usual if (DFISNAN(dfl) || DFISNAN(dfr)) return decNaNs(result, dfl, dfr, set); // one infinity but not both is bad if (DFISINF(dfl)!=DFISINF(dfr)) return decInvalid(result, set); // both infinite; return canonical infinity with sign of LHS return decInfinity(result, dfl); } /* Here when both arguments are finite */ // complete extraction of the exponents [no need to unbias] explb+=GETECON(dfl); // + continuation exprb+=GETECON(dfr); // .. // calculate the number of digits to drop from the coefficient drop=exprb-explb; // 0 if nothing to do if (drop==0) return decCanonical(result, dfl); // return canonical // the coefficient is needed; lay it out into buf, offset so zeros // can be added before or after as needed -- an extra heading is // added so can safely pad Quad DECPMAX-1 zeros to the left by // fours #define BUFOFF (buf+4+DECPMAX) GETCOEFF(dfl, BUFOFF); // decode from decFloat // [now the msd is at BUFOFF and the lsd is at BUFOFF+DECPMAX-1] #if DECTRACE num.msd=BUFOFF; num.lsd=BUFOFF+DECPMAX-1; num.exponent=explb-DECBIAS; num.sign=sourhil & DECFLOAT_Sign; decShowNum(&num, "dfl"); #endif if (drop>0) { // [most common case] // (this code is very similar to that in decFloatFinalize, but // has many differences so is duplicated here -- so any changes // may need to be made there, too) uByte *roundat; // -> re-round digit uByte reround; // reround value // printf("Rounding; drop=%ld\n", (LI)drop); // there is at least one zero needed to the left, in all but one // exceptional (all-nines) case, so place four zeros now; this is // needed almost always and makes rounding all-nines by fours safe UBFROMUI(BUFOFF-4, 0); // Three cases here: // 1. new LSD is in coefficient (almost always) // 2. new LSD is digit to left of coefficient (so MSD is // round-for-reround digit) // 3. new LSD is to left of case 2 (whole coefficient is sticky) // Note that leading zeros can safely be treated as useful digits // [duplicate check-stickies code to save a test] // [by-digit check for stickies as runs of zeros are rare] if (dropstatus|=DEC_Inexact; // next decide whether to increment the coefficient if (set->round==DEC_ROUND_HALF_EVEN) { // fastpath slowest case if (reround>5) bump=1; // >0.5 goes up else if (reround==5) // exactly 0.5000 .. bump=*ulsd & 0x01; // .. up iff [new] lsd is odd } // r-h-e else switch (set->round) { case DEC_ROUND_DOWN: { // no change break;} // r-d case DEC_ROUND_HALF_DOWN: { if (reround>5) bump=1; break;} // r-h-d case DEC_ROUND_HALF_UP: { if (reround>=5) bump=1; break;} // r-h-u case DEC_ROUND_UP: { if (reround>0) bump=1; break;} // r-u case DEC_ROUND_CEILING: { // same as _UP for positive numbers, and as _DOWN for negatives if (!(sourhil&DECFLOAT_Sign) && reround>0) bump=1; break;} // r-c case DEC_ROUND_FLOOR: { // same as _UP for negative numbers, and as _DOWN for positive // [negative reround cannot occur on 0] if (sourhil&DECFLOAT_Sign && reround>0) bump=1; break;} // r-f case DEC_ROUND_05UP: { if (reround>0) { // anything out there is 'sticky' // bump iff lsd=0 or 5; this cannot carry so it could be // effected immediately with no bump -- but the code // is clearer if this is done the same way as the others if (*ulsd==0 || *ulsd==5) bump=1; } break;} // r-r default: { // e.g., DEC_ROUND_MAX set->status|=DEC_Invalid_context; #if DECCHECK printf("Unknown rounding mode: %ld\n", (LI)set->round); #endif break;} } // switch (not r-h-e) // printf("ReRound: %ld bump: %ld\n", (LI)reround, (LI)bump); if (bump!=0) { // need increment // increment the coefficient; this could give 1000... (after // the all nines case) ub=ulsd; for (; UBTOUI(ub-3)==0x09090909; ub-=4) UBFROMUI(ub-3, 0); // now at most 3 digits left to non-9 (usually just the one) for (; *ub==9; ub--) *ub=0; *ub+=1; // [the all-nines case will have carried one digit to the // left of the original MSD -- just where it is needed] } // bump needed } // inexact rounding // now clear zeros to the left so exactly DECPMAX digits will be // available in the coefficent -- the first word to the left was // cleared earlier for safe carry; now add any more needed if (drop>4) { UBFROMUI(BUFOFF-8, 0); // must be at least 5 for (uc=BUFOFF-12; uc>ulsd-DECPMAX-3; uc-=4) UBFROMUI(uc, 0); } } // need round (drop>0) else { // drop<0; padding with -drop digits is needed // This is the case where an error can occur if the padded // coefficient will not fit; checking for this can be done in the // same loop as padding for zeros if the no-hope and zero cases // are checked first if (-drop>DECPMAX-1) { // cannot fit unless 0 if (!ISCOEFFZERO(BUFOFF)) return decInvalid(result, set); // a zero can have any exponent; just drop through and use it ulsd=BUFOFF+DECPMAX-1; } else { // padding will fit (but may still be too long) // final-word mask depends on endianess #if DECLITEND static const uInt dmask[]={0, 0x000000ff, 0x0000ffff, 0x00ffffff}; #else static const uInt dmask[]={0, 0xff000000, 0xffff0000, 0xffffff00}; #endif // note that here zeros to the right are added by fours, so in // the Quad case this could write 36 zeros if the coefficient has // fewer than three significant digits (hence the +2*QUAD for buf) for (uc=BUFOFF+DECPMAX;; uc+=4) { UBFROMUI(uc, 0); if (UBTOUI(uc-DECPMAX)!=0) { // could be bad // if all four digits should be zero, definitely bad if (uc<=BUFOFF+DECPMAX+(-drop)-4) return decInvalid(result, set); // must be a 1- to 3-digit sequence; check more carefully if ((UBTOUI(uc-DECPMAX)&dmask[(-drop)%4])!=0) return decInvalid(result, set); break; // no need for loop end test } if (uc>=BUFOFF+DECPMAX+(-drop)-4) break; // done } ulsd=BUFOFF+DECPMAX+(-drop)-1; } // pad and check leading zeros } // drop<0 #if DECTRACE num.msd=ulsd-DECPMAX+1; num.lsd=ulsd; num.exponent=explb-DECBIAS; num.sign=sourhil & DECFLOAT_Sign; decShowNum(&num, "res"); #endif /*------------------------------------------------------------------*/ /* At this point the result is DECPMAX digits, ending at ulsd, so */ /* fits the encoding exactly; there is no possibility of error */ /*------------------------------------------------------------------*/ encode=((exprb>>DECECONL)<<4) + *(ulsd-DECPMAX+1); // make index encode=DECCOMBFROM[encode]; // indexed by (0-2)*16+msd // the exponent continuation can be extracted from the original RHS encode|=sourhir & ECONMASK; encode|=sourhil&DECFLOAT_Sign; // add the sign from LHS // finally encode the coefficient // private macro to encode a declet; this version can be used // because all coefficient digits exist #define getDPD3q(dpd, n) ub=ulsd-(3*(n))-2; \ dpd=BCD2DPD[(*ub*256)+(*(ub+1)*16)+*(ub+2)]; #if DOUBLE getDPD3q(dpd, 4); encode|=dpd<<8; getDPD3q(dpd, 3); encode|=dpd>>2; DFWORD(result, 0)=encode; encode=dpd<<30; getDPD3q(dpd, 2); encode|=dpd<<20; getDPD3q(dpd, 1); encode|=dpd<<10; getDPD3q(dpd, 0); encode|=dpd; DFWORD(result, 1)=encode; #elif QUAD getDPD3q(dpd,10); encode|=dpd<<4; getDPD3q(dpd, 9); encode|=dpd>>6; DFWORD(result, 0)=encode; encode=dpd<<26; getDPD3q(dpd, 8); encode|=dpd<<16; getDPD3q(dpd, 7); encode|=dpd<<6; getDPD3q(dpd, 6); encode|=dpd>>4; DFWORD(result, 1)=encode; encode=dpd<<28; getDPD3q(dpd, 5); encode|=dpd<<18; getDPD3q(dpd, 4); encode|=dpd<<8; getDPD3q(dpd, 3); encode|=dpd>>2; DFWORD(result, 2)=encode; encode=dpd<<30; getDPD3q(dpd, 2); encode|=dpd<<20; getDPD3q(dpd, 1); encode|=dpd<<10; getDPD3q(dpd, 0); encode|=dpd; DFWORD(result, 3)=encode; #endif return result; } // decFloatQuantize /* ------------------------------------------------------------------ */ /* decFloatReduce -- reduce finite coefficient to minimum length */ /* */ /* result gets the reduced decFloat */ /* df is the source decFloat */ /* set is the context */ /* returns result, which will be canonical */ /* */ /* This removes all possible trailing zeros from the coefficient; */ /* some may remain when the number is very close to Nmax. */ /* Special values are unchanged and no status is set unless df=sNaN. */ /* Reduced zero has an exponent q=0. */ /* ------------------------------------------------------------------ */ decFloat * decFloatReduce(decFloat *result, const decFloat *df, decContext *set) { bcdnum num; // work uByte buf[DECPMAX], *ub; // coefficient and pointer if (df!=result) *result=*df; // copy, if needed if (DFISNAN(df)) return decNaNs(result, df, NULL, set); // sNaN // zeros and infinites propagate too if (DFISINF(df)) return decInfinity(result, df); // canonical if (DFISZERO(df)) { uInt sign=DFWORD(df, 0)&DECFLOAT_Sign; decFloatZero(result); DFWORD(result, 0)|=sign; return result; // exponent dropped, sign OK } // non-zero finite GETCOEFF(df, buf); ub=buf+DECPMAX-1; // -> lsd if (*ub) return result; // no trailing zeros for (ub--; *ub==0;) ub--; // terminates because non-zero // *ub is the first non-zero from the right num.sign=DFWORD(df, 0)&DECFLOAT_Sign; // set up number... num.exponent=GETEXPUN(df)+(Int)(buf+DECPMAX-1-ub); // adjusted exponent num.msd=buf; num.lsd=ub; return decFinalize(result, &num, set); } // decFloatReduce /* ------------------------------------------------------------------ */ /* decFloatRemainder -- integer divide and return remainder */ /* */ /* result gets the remainder of dividing dfl by dfr: */ /* dfl is the first decFloat (lhs) */ /* dfr is the second decFloat (rhs) */ /* set is the context */ /* returns result */ /* */ /* ------------------------------------------------------------------ */ decFloat * decFloatRemainder(decFloat *result, const decFloat *dfl, const decFloat *dfr, decContext *set) { return decDivide(result, dfl, dfr, set, REMAINDER); } // decFloatRemainder /* ------------------------------------------------------------------ */ /* decFloatRemainderNear -- integer divide to nearest and remainder */ /* */ /* result gets the remainder of dividing dfl by dfr: */ /* dfl is the first decFloat (lhs) */ /* dfr is the second decFloat (rhs) */ /* set is the context */ /* returns result */ /* */ /* This is the IEEE remainder, where the nearest integer is used. */ /* ------------------------------------------------------------------ */ decFloat * decFloatRemainderNear(decFloat *result, const decFloat *dfl, const decFloat *dfr, decContext *set) { return decDivide(result, dfl, dfr, set, REMNEAR); } // decFloatRemainderNear /* ------------------------------------------------------------------ */ /* decFloatRotate -- rotate the coefficient of a decFloat left/right */ /* */ /* result gets the result of rotating dfl */ /* dfl is the source decFloat to rotate */ /* dfr is the count of digits to rotate, an integer (with q=0) */ /* set is the context */ /* returns result */ /* */ /* The digits of the coefficient of dfl are rotated to the left (if */ /* dfr is positive) or to the right (if dfr is negative) without */ /* adjusting the exponent or the sign of dfl. */ /* */ /* dfr must be in the range -DECPMAX through +DECPMAX. */ /* NaNs are propagated as usual. An infinite dfl is unaffected (but */ /* dfr must be valid). No status is set unless dfr is invalid or an */ /* operand is an sNaN. The result is canonical. */ /* ------------------------------------------------------------------ */ #define PHALF (ROUNDUP(DECPMAX/2, 4)) // half length, rounded up decFloat * decFloatRotate(decFloat *result, const decFloat *dfl, const decFloat *dfr, decContext *set) { Int rotate; // dfr as an Int uByte buf[DECPMAX+PHALF]; // coefficient + half uInt digits, savestat; // work bcdnum num; // .. uByte *ub; // .. if (DFISNAN(dfl)||DFISNAN(dfr)) return decNaNs(result, dfl, dfr, set); if (!DFISINT(dfr)) return decInvalid(result, set); digits=decFloatDigits(dfr); // calculate digits if (digits>2) return decInvalid(result, set); // definitely out of range rotate=DPD2BIN[DFWORD(dfr, DECWORDS-1)&0x3ff]; // is in bottom declet if (rotate>DECPMAX) return decInvalid(result, set); // too big // [from here on no error or status change is possible] if (DFISINF(dfl)) return decInfinity(result, dfl); // canonical // handle no-rotate cases if (rotate==0 || rotate==DECPMAX) return decCanonical(result, dfl); // a real rotate is needed: 0 < rotate < DECPMAX // reduce the rotation to no more than half to reduce copying later // (for QUAD in fact half + 2 digits) if (DFISSIGNED(dfr)) rotate=-rotate; if (abs(rotate)>PHALF) { if (rotate<0) rotate=DECPMAX+rotate; else rotate=rotate-DECPMAX; } // now lay out the coefficient, leaving room to the right or the // left depending on the direction of rotation ub=buf; if (rotate<0) ub+=PHALF; // rotate right, so space to left GETCOEFF(dfl, ub); // copy half the digits to left or right, and set num.msd if (rotate<0) { memcpy(buf, buf+DECPMAX, PHALF); num.msd=buf+PHALF+rotate; } else { memcpy(buf+DECPMAX, buf, PHALF); num.msd=buf+rotate; } // fill in rest of num num.lsd=num.msd+DECPMAX-1; num.sign=DFWORD(dfl, 0)&DECFLOAT_Sign; num.exponent=GETEXPUN(dfl); savestat=set->status; // record decFinalize(result, &num, set); set->status=savestat; // restore return result; } // decFloatRotate /* ------------------------------------------------------------------ */ /* decFloatSameQuantum -- test decFloats for same quantum */ /* */ /* dfl is the first decFloat (lhs) */ /* dfr is the second decFloat (rhs) */ /* returns 1 if the operands have the same quantum, 0 otherwise */ /* */ /* No error is possible and no status results. */ /* ------------------------------------------------------------------ */ uInt decFloatSameQuantum(const decFloat *dfl, const decFloat *dfr) { if (DFISSPECIAL(dfl) || DFISSPECIAL(dfr)) { if (DFISNAN(dfl) && DFISNAN(dfr)) return 1; if (DFISINF(dfl) && DFISINF(dfr)) return 1; return 0; // any other special mixture gives false } if (GETEXP(dfl)==GETEXP(dfr)) return 1; // biased exponents match return 0; } // decFloatSameQuantum /* ------------------------------------------------------------------ */ /* decFloatScaleB -- multiply by a power of 10, as per 754 */ /* */ /* result gets the result of the operation */ /* dfl is the first decFloat (lhs) */ /* dfr is the second decFloat (rhs), am integer (with q=0) */ /* set is the context */ /* returns result */ /* */ /* This computes result=dfl x 10**dfr where dfr is an integer in the */ /* range +/-2*(emax+pmax), typically resulting from LogB. */ /* Underflow and Overflow (with Inexact) may occur. NaNs propagate */ /* as usual. */ /* ------------------------------------------------------------------ */ #define SCALEBMAX 2*(DECEMAX+DECPMAX) // D=800, Q=12356 decFloat * decFloatScaleB(decFloat *result, const decFloat *dfl, const decFloat *dfr, decContext *set) { uInt digits; // work Int expr; // dfr as an Int if (DFISNAN(dfl)||DFISNAN(dfr)) return decNaNs(result, dfl, dfr, set); if (!DFISINT(dfr)) return decInvalid(result, set); digits=decFloatDigits(dfr); // calculate digits #if DOUBLE if (digits>3) return decInvalid(result, set); // definitely out of range expr=DPD2BIN[DFWORD(dfr, 1)&0x3ff]; // must be in bottom declet #elif QUAD if (digits>5) return decInvalid(result, set); // definitely out of range expr=DPD2BIN[DFWORD(dfr, 3)&0x3ff] // in bottom 2 declets .. +DPD2BIN[(DFWORD(dfr, 3)>>10)&0x3ff]*1000; // .. #endif if (expr>SCALEBMAX) return decInvalid(result, set); // oops // [from now on no error possible] if (DFISINF(dfl)) return decInfinity(result, dfl); // canonical if (DFISSIGNED(dfr)) expr=-expr; // dfl is finite and expr is valid *result=*dfl; // copy to target return decFloatSetExponent(result, set, GETEXPUN(result)+expr); } // decFloatScaleB /* ------------------------------------------------------------------ */ /* decFloatShift -- shift the coefficient of a decFloat left or right */ /* */ /* result gets the result of shifting dfl */ /* dfl is the source decFloat to shift */ /* dfr is the count of digits to shift, an integer (with q=0) */ /* set is the context */ /* returns result */ /* */ /* The digits of the coefficient of dfl are shifted to the left (if */ /* dfr is positive) or to the right (if dfr is negative) without */ /* adjusting the exponent or the sign of dfl. */ /* */ /* dfr must be in the range -DECPMAX through +DECPMAX. */ /* NaNs are propagated as usual. An infinite dfl is unaffected (but */ /* dfr must be valid). No status is set unless dfr is invalid or an */ /* operand is an sNaN. The result is canonical. */ /* ------------------------------------------------------------------ */ decFloat * decFloatShift(decFloat *result, const decFloat *dfl, const decFloat *dfr, decContext *set) { Int shift; // dfr as an Int uByte buf[DECPMAX*2]; // coefficient + padding uInt digits, savestat; // work bcdnum num; // .. uInt uiwork; // for macros if (DFISNAN(dfl)||DFISNAN(dfr)) return decNaNs(result, dfl, dfr, set); if (!DFISINT(dfr)) return decInvalid(result, set); digits=decFloatDigits(dfr); // calculate digits if (digits>2) return decInvalid(result, set); // definitely out of range shift=DPD2BIN[DFWORD(dfr, DECWORDS-1)&0x3ff]; // is in bottom declet if (shift>DECPMAX) return decInvalid(result, set); // too big // [from here on no error or status change is possible] if (DFISINF(dfl)) return decInfinity(result, dfl); // canonical // handle no-shift and all-shift (clear to zero) cases if (shift==0) return decCanonical(result, dfl); if (shift==DECPMAX) { // zero with sign uByte sign=(uByte)(DFBYTE(dfl, 0)&0x80); // save sign bit decFloatZero(result); // make +0 DFBYTE(result, 0)=(uByte)(DFBYTE(result, 0)|sign); // and set sign // [cannot safely use CopySign] return result; } // a real shift is needed: 0 < shift < DECPMAX num.sign=DFWORD(dfl, 0)&DECFLOAT_Sign; num.exponent=GETEXPUN(dfl); num.msd=buf; GETCOEFF(dfl, buf); if (DFISSIGNED(dfr)) { // shift right // edge cases are taken care of, so this is easy num.lsd=buf+DECPMAX-shift-1; } else { // shift left -- zero padding needed to right UBFROMUI(buf+DECPMAX, 0); // 8 will handle most cases UBFROMUI(buf+DECPMAX+4, 0); // .. if (shift>8) memset(buf+DECPMAX+8, 0, 8+QUAD*18); // all other cases num.msd+=shift; num.lsd=num.msd+DECPMAX-1; } savestat=set->status; // record decFinalize(result, &num, set); set->status=savestat; // restore return result; } // decFloatShift /* ------------------------------------------------------------------ */ /* decFloatSubtract -- subtract a decFloat from another */ /* */ /* result gets the result of subtracting dfr from dfl: */ /* dfl is the first decFloat (lhs) */ /* dfr is the second decFloat (rhs) */ /* set is the context */ /* returns result */ /* */ /* ------------------------------------------------------------------ */ decFloat * decFloatSubtract(decFloat *result, const decFloat *dfl, const decFloat *dfr, decContext *set) { decFloat temp; // NaNs must propagate without sign change if (DFISNAN(dfr)) return decFloatAdd(result, dfl, dfr, set); temp=*dfr; // make a copy DFBYTE(&temp, 0)^=0x80; // flip sign return decFloatAdd(result, dfl, &temp, set); // and add to the lhs } // decFloatSubtract /* ------------------------------------------------------------------ */ /* decFloatToInt -- round to 32-bit binary integer (4 flavours) */ /* */ /* df is the decFloat to round */ /* set is the context */ /* round is the rounding mode to use */ /* returns a uInt or an Int, rounded according to the name */ /* */ /* Invalid will always be signaled if df is a NaN, is Infinite, or is */ /* outside the range of the target; Inexact will not be signaled for */ /* simple rounding unless 'Exact' appears in the name. */ /* ------------------------------------------------------------------ */ uInt decFloatToUInt32(const decFloat *df, decContext *set, enum rounding round) { return decToInt32(df, set, round, 0, 1);} uInt decFloatToUInt32Exact(const decFloat *df, decContext *set, enum rounding round) { return decToInt32(df, set, round, 1, 1);} Int decFloatToInt32(const decFloat *df, decContext *set, enum rounding round) { return (Int)decToInt32(df, set, round, 0, 0);} Int decFloatToInt32Exact(const decFloat *df, decContext *set, enum rounding round) { return (Int)decToInt32(df, set, round, 1, 0);} /* ------------------------------------------------------------------ */ /* decFloatToIntegral -- round to integral value (two flavours) */ /* */ /* result gets the result */ /* df is the decFloat to round */ /* set is the context */ /* round is the rounding mode to use */ /* returns result */ /* */ /* No exceptions, even Inexact, are raised except for sNaN input, or */ /* if 'Exact' appears in the name. */ /* ------------------------------------------------------------------ */ decFloat * decFloatToIntegralValue(decFloat *result, const decFloat *df, decContext *set, enum rounding round) { return decToIntegral(result, df, set, round, 0);} decFloat * decFloatToIntegralExact(decFloat *result, const decFloat *df, decContext *set) { return decToIntegral(result, df, set, set->round, 1);} /* ------------------------------------------------------------------ */ /* decFloatXor -- logical digitwise XOR of two decFloats */ /* */ /* result gets the result of XORing dfl and dfr */ /* dfl is the first decFloat (lhs) */ /* dfr is the second decFloat (rhs) */ /* set is the context */ /* returns result, which will be canonical with sign=0 */ /* */ /* The operands must be positive, finite with exponent q=0, and */ /* comprise just zeros and ones; if not, Invalid operation results. */ /* ------------------------------------------------------------------ */ decFloat * decFloatXor(decFloat *result, const decFloat *dfl, const decFloat *dfr, decContext *set) { if (!DFISUINT01(dfl) || !DFISUINT01(dfr) || !DFISCC01(dfl) || !DFISCC01(dfr)) return decInvalid(result, set); // the operands are positive finite integers (q=0) with just 0s and 1s #if DOUBLE DFWORD(result, 0)=ZEROWORD |((DFWORD(dfl, 0) ^ DFWORD(dfr, 0))&0x04009124); DFWORD(result, 1)=(DFWORD(dfl, 1) ^ DFWORD(dfr, 1))&0x49124491; #elif QUAD DFWORD(result, 0)=ZEROWORD |((DFWORD(dfl, 0) ^ DFWORD(dfr, 0))&0x04000912); DFWORD(result, 1)=(DFWORD(dfl, 1) ^ DFWORD(dfr, 1))&0x44912449; DFWORD(result, 2)=(DFWORD(dfl, 2) ^ DFWORD(dfr, 2))&0x12449124; DFWORD(result, 3)=(DFWORD(dfl, 3) ^ DFWORD(dfr, 3))&0x49124491; #endif return result; } // decFloatXor /* ------------------------------------------------------------------ */ /* decInvalid -- set Invalid_operation result */ /* */ /* result gets a canonical NaN */ /* set is the context */ /* returns result */ /* */ /* status has Invalid_operation added */ /* ------------------------------------------------------------------ */ static decFloat *decInvalid(decFloat *result, decContext *set) { decFloatZero(result); DFWORD(result, 0)=DECFLOAT_qNaN; set->status|=DEC_Invalid_operation; return result; } // decInvalid /* ------------------------------------------------------------------ */ /* decInfinity -- set canonical Infinity with sign from a decFloat */ /* */ /* result gets a canonical Infinity */ /* df is source decFloat (only the sign is used) */ /* returns result */ /* */ /* df may be the same as result */ /* ------------------------------------------------------------------ */ static decFloat *decInfinity(decFloat *result, const decFloat *df) { uInt sign=DFWORD(df, 0); // save source signword decFloatZero(result); // clear everything DFWORD(result, 0)=DECFLOAT_Inf | (sign & DECFLOAT_Sign); return result; } // decInfinity /* ------------------------------------------------------------------ */ /* decNaNs -- handle NaN argument(s) */ /* */ /* result gets the result of handling dfl and dfr, one or both of */ /* which is a NaN */ /* dfl is the first decFloat (lhs) */ /* dfr is the second decFloat (rhs) -- may be NULL for a single- */ /* operand operation */ /* set is the context */ /* returns result */ /* */ /* Called when one or both operands is a NaN, and propagates the */ /* appropriate result to res. When an sNaN is found, it is changed */ /* to a qNaN and Invalid operation is set. */ /* ------------------------------------------------------------------ */ static decFloat *decNaNs(decFloat *result, const decFloat *dfl, const decFloat *dfr, decContext *set) { // handle sNaNs first if (dfr!=NULL && DFISSNAN(dfr) && !DFISSNAN(dfl)) dfl=dfr; // use RHS if (DFISSNAN(dfl)) { decCanonical(result, dfl); // propagate canonical sNaN DFWORD(result, 0)&=~(DECFLOAT_qNaN ^ DECFLOAT_sNaN); // quiet set->status|=DEC_Invalid_operation; return result; } // one or both is a quiet NaN if (!DFISNAN(dfl)) dfl=dfr; // RHS must be NaN, use it return decCanonical(result, dfl); // propagate canonical qNaN } // decNaNs /* ------------------------------------------------------------------ */ /* decNumCompare -- numeric comparison of two decFloats */ /* */ /* dfl is the left-hand decFloat, which is not a NaN */ /* dfr is the right-hand decFloat, which is not a NaN */ /* tot is 1 for total order compare, 0 for simple numeric */ /* returns -1, 0, or +1 for dfldfr */ /* */ /* No error is possible; status and mode are unchanged. */ /* ------------------------------------------------------------------ */ static Int decNumCompare(const decFloat *dfl, const decFloat *dfr, Flag tot) { Int sigl, sigr; // LHS and RHS non-0 signums Int shift; // shift needed to align operands uByte *ub, *uc; // work uInt uiwork; // for macros // buffers +2 if Quad (36 digits), need double plus 4 for safe padding uByte bufl[DECPMAX*2+QUAD*2+4]; // for LHS coefficient + padding uByte bufr[DECPMAX*2+QUAD*2+4]; // for RHS coefficient + padding sigl=1; if (DFISSIGNED(dfl)) { if (!DFISSIGNED(dfr)) { // -LHS +RHS if (DFISZERO(dfl) && DFISZERO(dfr) && !tot) return 0; return -1; // RHS wins } sigl=-1; } if (DFISSIGNED(dfr)) { if (!DFISSIGNED(dfl)) { // +LHS -RHS if (DFISZERO(dfl) && DFISZERO(dfr) && !tot) return 0; return +1; // LHS wins } } // signs are the same; operand(s) could be zero sigr=-sigl; // sign to return if abs(RHS) wins if (DFISINF(dfl)) { if (DFISINF(dfr)) return 0; // both infinite & same sign return sigl; // inf > n } if (DFISINF(dfr)) return sigr; // n < inf [dfl is finite] // here, both are same sign and finite; calculate their offset shift=GETEXP(dfl)-GETEXP(dfr); // [0 means aligned] // [bias can be ignored -- the absolute exponent is not relevant] if (DFISZERO(dfl)) { if (!DFISZERO(dfr)) return sigr; // LHS=0, RHS!=0 // both are zero, return 0 if both same exponent or numeric compare if (shift==0 || !tot) return 0; if (shift>0) return sigl; return sigr; // [shift<0] } else { // LHS!=0 if (DFISZERO(dfr)) return sigl; // LHS!=0, RHS=0 } // both are known to be non-zero at this point // if the exponents are so different that the coefficients do not // overlap (by even one digit) then a full comparison is not needed if (abs(shift)>=DECPMAX) { // no overlap // coefficients are known to be non-zero if (shift>0) return sigl; return sigr; // [shift<0] } // decode the coefficients // (shift both right two if Quad to make a multiple of four) #if QUAD UBFROMUI(bufl, 0); UBFROMUI(bufr, 0); #endif GETCOEFF(dfl, bufl+QUAD*2); // decode from decFloat GETCOEFF(dfr, bufr+QUAD*2); // .. if (shift==0) { // aligned; common and easy // all multiples of four, here for (ub=bufl, uc=bufr; ub*uc) return sigl; // difference found if (*ub<*uc) return sigr; // .. } } } // aligned else if (shift>0) { // lhs to left ub=bufl; // RHS pointer // pad bufl so right-aligned; most shifts will fit in 8 UBFROMUI(bufl+DECPMAX+QUAD*2, 0); // add eight zeros UBFROMUI(bufl+DECPMAX+QUAD*2+4, 0); // .. if (shift>8) { // more than eight; fill the rest, and also worth doing the // lead-in by fours uByte *up; // work uByte *upend=bufl+DECPMAX+QUAD*2+shift; for (up=bufl+DECPMAX+QUAD*2+8; upbufl+shift-4) break; } } // check remaining leading digits for (; ub*uc) return sigl; // difference found if (*ub<*uc) return sigr; // .. } } // mismatch if (uc==bufr+QUAD*2+DECPMAX-4) break; // all checked } } // shift>0 else { // shift<0) .. RHS is to left of LHS; mirror shift>0 uc=bufr; // RHS pointer // pad bufr so right-aligned; most shifts will fit in 8 UBFROMUI(bufr+DECPMAX+QUAD*2, 0); // add eight zeros UBFROMUI(bufr+DECPMAX+QUAD*2+4, 0); // .. if (shift<-8) { // more than eight; fill the rest, and also worth doing the // lead-in by fours uByte *up; // work uByte *upend=bufr+DECPMAX+QUAD*2-shift; for (up=bufr+DECPMAX+QUAD*2+8; upbufr-shift-4) break; } } // check remaining leading digits for (; uc*uc) return sigl; // difference found if (*ub<*uc) return sigr; // .. } } // mismatch if (ub==bufl+QUAD*2+DECPMAX-4) break; // all checked } } // shift<0 // Here when compare equal if (!tot) return 0; // numerically equal // total ordering .. exponent matters if (shift>0) return sigl; // total order by exponent if (shift<0) return sigr; // .. return 0; } // decNumCompare /* ------------------------------------------------------------------ */ /* decToInt32 -- local routine to effect ToInteger conversions */ /* */ /* df is the decFloat to convert */ /* set is the context */ /* rmode is the rounding mode to use */ /* exact is 1 if Inexact should be signalled */ /* unsign is 1 if the result a uInt, 0 if an Int (cast to uInt) */ /* returns 32-bit result as a uInt */ /* */ /* Invalid is set is df is a NaN, is infinite, or is out-of-range; in */ /* these cases 0 is returned. */ /* ------------------------------------------------------------------ */ static uInt decToInt32(const decFloat *df, decContext *set, enum rounding rmode, Flag exact, Flag unsign) { Int exp; // exponent uInt sourhi, sourpen, sourlo; // top word from source decFloat .. uInt hi, lo; // .. penultimate, least, etc. decFloat zero, result; // work Int i; // .. /* Start decoding the argument */ sourhi=DFWORD(df, 0); // top word exp=DECCOMBEXP[sourhi>>26]; // get exponent high bits (in place) if (EXPISSPECIAL(exp)) { // is special? set->status|=DEC_Invalid_operation; // signal return 0; } /* Here when the argument is finite */ if (GETEXPUN(df)==0) result=*df; // already a true integer else { // need to round to integer enum rounding saveround; // saver uInt savestatus; // .. saveround=set->round; // save rounding mode .. savestatus=set->status; // .. and status set->round=rmode; // set mode decFloatZero(&zero); // make 0E+0 set->status=0; // clear decFloatQuantize(&result, df, &zero, set); // [this may fail] set->round=saveround; // restore rounding mode .. if (exact) set->status|=savestatus; // include Inexact else set->status=savestatus; // .. or just original status } // only the last four declets of the coefficient can contain // non-zero; check for others (and also NaN or Infinity from the // Quantize) first (see DFISZERO for explanation): // decFloatShow(&result, "sofar"); #if DOUBLE if ((DFWORD(&result, 0)&0x1c03ff00)!=0 || (DFWORD(&result, 0)&0x60000000)==0x60000000) { #elif QUAD if ((DFWORD(&result, 2)&0xffffff00)!=0 || DFWORD(&result, 1)!=0 || (DFWORD(&result, 0)&0x1c003fff)!=0 || (DFWORD(&result, 0)&0x60000000)==0x60000000) { #endif set->status|=DEC_Invalid_operation; // Invalid or out of range return 0; } // get last twelve digits of the coefficent into hi & ho, base // 10**9 (see GETCOEFFBILL): sourlo=DFWORD(&result, DECWORDS-1); lo=DPD2BIN0[sourlo&0x3ff] +DPD2BINK[(sourlo>>10)&0x3ff] +DPD2BINM[(sourlo>>20)&0x3ff]; sourpen=DFWORD(&result, DECWORDS-2); hi=DPD2BIN0[((sourpen<<2) | (sourlo>>30))&0x3ff]; // according to request, check range carefully if (unsign) { if (hi>4 || (hi==4 && lo>294967295) || (hi+lo!=0 && DFISSIGNED(&result))) { set->status|=DEC_Invalid_operation; // out of range return 0; } return hi*BILLION+lo; } // signed if (hi>2 || (hi==2 && lo>147483647)) { // handle the usual edge case if (lo==147483648 && hi==2 && DFISSIGNED(&result)) return 0x80000000; set->status|=DEC_Invalid_operation; // truly out of range return 0; } i=hi*BILLION+lo; if (DFISSIGNED(&result)) i=-i; return (uInt)i; } // decToInt32 /* ------------------------------------------------------------------ */ /* decToIntegral -- local routine to effect ToIntegral value */ /* */ /* result gets the result */ /* df is the decFloat to round */ /* set is the context */ /* rmode is the rounding mode to use */ /* exact is 1 if Inexact should be signalled */ /* returns result */ /* ------------------------------------------------------------------ */ static decFloat * decToIntegral(decFloat *result, const decFloat *df, decContext *set, enum rounding rmode, Flag exact) { Int exp; // exponent uInt sourhi; // top word from source decFloat enum rounding saveround; // saver uInt savestatus; // .. decFloat zero; // work /* Start decoding the argument */ sourhi=DFWORD(df, 0); // top word exp=DECCOMBEXP[sourhi>>26]; // get exponent high bits (in place) if (EXPISSPECIAL(exp)) { // is special? // NaNs are handled as usual if (DFISNAN(df)) return decNaNs(result, df, NULL, set); // must be infinite; return canonical infinity with sign of df return decInfinity(result, df); } /* Here when the argument is finite */ // complete extraction of the exponent exp+=GETECON(df)-DECBIAS; // .. + continuation and unbias if (exp>=0) return decCanonical(result, df); // already integral saveround=set->round; // save rounding mode .. savestatus=set->status; // .. and status set->round=rmode; // set mode decFloatZero(&zero); // make 0E+0 decFloatQuantize(result, df, &zero, set); // 'integrate'; cannot fail set->round=saveround; // restore rounding mode .. if (!exact) set->status=savestatus; // .. and status, unless exact return result; } // decToIntegral ================================================ FILE: vendor/decNumber/decCommon.c ================================================ /* ------------------------------------------------------------------ */ /* decCommon.c -- common code for all three fixed-size types */ /* ------------------------------------------------------------------ */ /* Copyright (c) IBM Corporation, 2000, 2010. All rights reserved. */ /* */ /* This software is made available under the terms of the */ /* ICU License -- ICU 1.8.1 and later. */ /* */ /* The description and User's Guide ("The decNumber C Library") for */ /* this software is included in the package as decNumber.pdf. This */ /* document is also available in HTML, together with specifications, */ /* testcases, and Web links, on the General Decimal Arithmetic page. */ /* */ /* Please send comments, suggestions, and corrections to the author: */ /* mfc@uk.ibm.com */ /* Mike Cowlishaw, IBM Fellow */ /* IBM UK, PO Box 31, Birmingham Road, Warwick CV34 5JL, UK */ /* ------------------------------------------------------------------ */ /* This module comprises code that is shared between all the formats */ /* (decSingle, decDouble, and decQuad); it includes set and extract */ /* of format components, widening, narrowing, and string conversions. */ /* */ /* Unlike decNumber, parameterization takes place at compile time */ /* rather than at runtime. The parameters are set in the decDouble.c */ /* (etc.) files, which then include this one to produce the compiled */ /* code. The functions here, therefore, are code shared between */ /* multiple formats. */ /* ------------------------------------------------------------------ */ // Names here refer to decFloat rather than to decDouble, etc., and // the functions are in strict alphabetical order. // Constants, tables, and debug function(s) are included only for QUAD // (which will always be compiled if DOUBLE or SINGLE are used). // // Whenever a decContext is used, only the status may be set (using // OR) or the rounding mode read; all other fields are ignored and // untouched. // names for simpler testing and default context #if DECPMAX==7 #define SINGLE 1 #define DOUBLE 0 #define QUAD 0 #define DEFCONTEXT DEC_INIT_DECIMAL32 #elif DECPMAX==16 #define SINGLE 0 #define DOUBLE 1 #define QUAD 0 #define DEFCONTEXT DEC_INIT_DECIMAL64 #elif DECPMAX==34 #define SINGLE 0 #define DOUBLE 0 #define QUAD 1 #define DEFCONTEXT DEC_INIT_DECIMAL128 #else #error Unexpected DECPMAX value #endif /* Assertions */ #if DECPMAX!=7 && DECPMAX!=16 && DECPMAX!=34 #error Unexpected Pmax (DECPMAX) value for this module #endif // Assert facts about digit characters, etc. #if ('9'&0x0f)!=9 #error This module assumes characters are of the form 0b....nnnn // where .... are don't care 4 bits and nnnn is 0000 through 1001 #endif #if ('9'&0xf0)==('.'&0xf0) #error This module assumes '.' has a different mask than a digit #endif // Assert ToString lay-out conditions #if DECSTRING DECSTRING #error Exponent form can be too long for ToString to lay out safely #endif #if DECEMAXD > 4 #error Exponent form is too long for ToString to lay out // Note: code for up to 9 digits exists in archives [decOct] #endif /* Private functions used here and possibly in decBasic.c, etc. */ static decFloat * decFinalize(decFloat *, bcdnum *, decContext *); static Flag decBiStr(const char *, const char *, const char *); /* Macros and private tables; those which are not format-dependent */ /* are only included if decQuad is being built. */ /* ------------------------------------------------------------------ */ /* Combination field lookup tables (uInts to save measurable work) */ /* */ /* DECCOMBEXP - 2 most-significant-bits of exponent (00, 01, or */ /* 10), shifted left for format, or DECFLOAT_Inf/NaN */ /* DECCOMBWEXP - The same, for the next-wider format (unless QUAD) */ /* DECCOMBMSD - 4-bit most-significant-digit */ /* [0 if the index is a special (Infinity or NaN)] */ /* DECCOMBFROM - 5-bit combination field from EXP top bits and MSD */ /* (placed in uInt so no shift is needed) */ /* */ /* DECCOMBEXP, DECCOMBWEXP, and DECCOMBMSD are indexed by the sign */ /* and 5-bit combination field (0-63, the second half of the table */ /* identical to the first half) */ /* DECCOMBFROM is indexed by expTopTwoBits*16 + msd */ /* */ /* DECCOMBMSD and DECCOMBFROM are not format-dependent and so are */ /* only included once, when QUAD is being built */ /* ------------------------------------------------------------------ */ static const uInt DECCOMBEXP[64]={ 0, 0, 0, 0, 0, 0, 0, 0, 1< DPD #define DEC_BIN2DPD 1 // 0-999 -> DPD #define DEC_BIN2BCD8 1 // 0-999 -> ddd, len #define DEC_DPD2BCD8 1 // DPD -> ddd, len #define DEC_DPD2BIN 1 // DPD -> 0-999 #define DEC_DPD2BINK 1 // DPD -> 0-999000 #define DEC_DPD2BINM 1 // DPD -> 0-999000000 #include "decDPD.h" // source of the lookup tables #endif /* ----------------------------------------------------------------- */ /* decBiStr -- compare string with pairwise options */ /* */ /* targ is the string to compare */ /* str1 is one of the strings to compare against (length may be 0) */ /* str2 is the other; it must be the same length as str1 */ /* */ /* returns 1 if strings compare equal, (that is, targ is the same */ /* length as str1 and str2, and each character of targ is in one */ /* of str1 or str2 in the corresponding position), or 0 otherwise */ /* */ /* This is used for generic caseless compare, including the awkward */ /* case of the Turkish dotted and dotless Is. Use as (for example): */ /* if (decBiStr(test, "mike", "MIKE")) ... */ /* ----------------------------------------------------------------- */ static Flag decBiStr(const char *targ, const char *str1, const char *str2) { for (;;targ++, str1++, str2++) { if (*targ!=*str1 && *targ!=*str2) return 0; // *targ has a match in one (or both, if terminator) if (*targ=='\0') break; } // forever return 1; } // decBiStr /* ------------------------------------------------------------------ */ /* decFinalize -- adjust and store a final result */ /* */ /* df is the decFloat format number which gets the final result */ /* num is the descriptor of the number to be checked and encoded */ /* [its values, including the coefficient, may be modified] */ /* set is the context to use */ /* returns df */ /* */ /* The num descriptor may point to a bcd8 string of any length; this */ /* string may have leading insignificant zeros. If it has more than */ /* DECPMAX digits then the final digit can be a round-for-reround */ /* digit (i.e., it may include a sticky bit residue). */ /* */ /* The exponent (q) may be one of the codes for a special value and */ /* can be up to 999999999 for conversion from string. */ /* */ /* No error is possible, but Inexact, Underflow, and/or Overflow may */ /* be set. */ /* ------------------------------------------------------------------ */ // Constant whose size varies with format; also the check for surprises static uByte allnines[DECPMAX]= #if SINGLE {9, 9, 9, 9, 9, 9, 9}; #elif DOUBLE {9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9}; #elif QUAD {9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9}; #endif static decFloat * decFinalize(decFloat *df, bcdnum *num, decContext *set) { uByte *ub; // work uInt dpd; // .. uInt uiwork; // for macros uByte *umsd=num->msd; // local copy uByte *ulsd=num->lsd; // .. uInt encode; // encoding accumulator Int length; // coefficient length #if DECCHECK Int clen=ulsd-umsd+1; #if QUAD #define COEXTRA 2 // extra-long coefficent #else #define COEXTRA 0 #endif if (clen<1 || clen>DECPMAX*3+2+COEXTRA) printf("decFinalize: suspect coefficient [length=%ld]\n", (LI)clen); if (num->sign!=0 && num->sign!=DECFLOAT_Sign) printf("decFinalize: bad sign [%08lx]\n", (LI)num->sign); if (!EXPISSPECIAL(num->exponent) && (num->exponent>1999999999 || num->exponent<-1999999999)) printf("decFinalize: improbable exponent [%ld]\n", (LI)num->exponent); // decShowNum(num, "final"); #endif // A special will have an 'exponent' which is very positive and a // coefficient < DECPMAX length=(uInt)(ulsd-umsd+1); // coefficient length if (!NUMISSPECIAL(num)) { Int drop; // digits to be dropped // skip leading insignificant zeros to calculate an exact length // [this is quite expensive] if (*umsd==0) { for (; umsd+3exponent); // drop can now be > digits for bottom-clamp (subnormal) cases if (drop>0) { // rounding needed // (decFloatQuantize has very similar code to this, so any // changes may need to be made there, too) uByte *roundat; // -> re-round digit uByte reround; // reround value // printf("Rounding; drop=%ld\n", (LI)drop); num->exponent+=drop; // always update exponent // Three cases here: // 1. new LSD is in coefficient (almost always) // 2. new LSD is digit to left of coefficient (so MSD is // round-for-reround digit) // 3. new LSD is to left of case 2 (whole coefficient is sticky) // [duplicate check-stickies code to save a test] // [by-digit check for stickies as runs of zeros are rare] if (dropstatus|=DEC_Inexact; // if adjusted exponent [exp+digits-1] is < EMIN then num is // subnormal -- so raise Underflow if (num->exponentexponent+(ulsd-umsd+1)-1)status|=DEC_Underflow; // next decide whether increment of the coefficient is needed if (set->round==DEC_ROUND_HALF_EVEN) { // fastpath slowest case if (reround>5) bump=1; // >0.5 goes up else if (reround==5) // exactly 0.5000 .. bump=*ulsd & 0x01; // .. up iff [new] lsd is odd } // r-h-e else switch (set->round) { case DEC_ROUND_DOWN: { // no change break;} // r-d case DEC_ROUND_HALF_DOWN: { if (reround>5) bump=1; break;} // r-h-d case DEC_ROUND_HALF_UP: { if (reround>=5) bump=1; break;} // r-h-u case DEC_ROUND_UP: { if (reround>0) bump=1; break;} // r-u case DEC_ROUND_CEILING: { // same as _UP for positive numbers, and as _DOWN for negatives if (!num->sign && reround>0) bump=1; break;} // r-c case DEC_ROUND_FLOOR: { // same as _UP for negative numbers, and as _DOWN for positive // [negative reround cannot occur on 0] if (num->sign && reround>0) bump=1; break;} // r-f case DEC_ROUND_05UP: { if (reround>0) { // anything out there is 'sticky' // bump iff lsd=0 or 5; this cannot carry so it could be // effected immediately with no bump -- but the code // is clearer if this is done the same way as the others if (*ulsd==0 || *ulsd==5) bump=1; } break;} // r-r default: { // e.g., DEC_ROUND_MAX set->status|=DEC_Invalid_context; #if DECCHECK printf("Unknown rounding mode: %ld\n", (LI)set->round); #endif break;} } // switch (not r-h-e) // printf("ReRound: %ld bump: %ld\n", (LI)reround, (LI)bump); if (bump!=0) { // need increment // increment the coefficient; this might end up with 1000... // (after the all nines case) ub=ulsd; for(; ub-3>=umsd && UBTOUI(ub-3)==0x09090909; ub-=4) { UBFROMUI(ub-3, 0); // to 00000000 } // [note ub could now be to left of msd, and it is not safe // to write to the left of the msd] // now at most 3 digits left to non-9 (usually just the one) for (; ub>=umsd; *ub=0, ub--) { if (*ub==9) continue; // carry *ub+=1; break; } if (ubexponent++; } else { // if coefficient is shorter than Pmax then num is // subnormal, so extend it; this is safe as drop>0 // (or, if the coefficient was supplied above, it could // not be 9); this may make the result normal. ulsd++; *ulsd=0; // [exponent unchanged] #if DECCHECK if (num->exponent!=DECQTINY) // sanity check printf("decFinalize: bad all-nines extend [^%ld, %ld]\n", (LI)num->exponent, (LI)(ulsd-umsd+1)); #endif } // subnormal extend } // had all-nines } // bump needed } // inexact rounding length=ulsd-umsd+1; // recalculate (may be 0) // The coefficient will now fit and has final length unless overflow // decShowNum(num, "rounded"); // if exponent is >=emax may have to clamp, overflow, or fold-down if (num->exponent>DECEMAX-(DECPMAX-1)) { // is edge case // printf("overflow checks...\n"); if (*ulsd==0 && ulsd==umsd) { // have zero num->exponent=DECEMAX-(DECPMAX-1); // clamp to max } else if ((num->exponent+length-1)>DECEMAX) { // > Nmax // Overflow -- these could go straight to encoding, here, but // instead num is adjusted to keep the code cleaner Flag needmax=0; // 1 for finite result set->status|=(DEC_Overflow | DEC_Inexact); switch (set->round) { case DEC_ROUND_DOWN: { needmax=1; // never Infinity break;} // r-d case DEC_ROUND_05UP: { needmax=1; // never Infinity break;} // r-05 case DEC_ROUND_CEILING: { if (num->sign) needmax=1; // Infinity iff non-negative break;} // r-c case DEC_ROUND_FLOOR: { if (!num->sign) needmax=1; // Infinity iff negative break;} // r-f default: break; // Infinity in all other cases } if (!needmax) { // easy .. set Infinity num->exponent=DECFLOAT_Inf; *umsd=0; // be clean: coefficient to 0 ulsd=umsd; // .. } else { // return Nmax umsd=allnines; // use constant array ulsd=allnines+DECPMAX-1; num->exponent=DECEMAX-(DECPMAX-1); } } else { // no overflow but non-zero and may have to fold-down Int shift=num->exponent-(DECEMAX-(DECPMAX-1)); if (shift>0) { // fold-down needed // fold down needed; must copy to buffer in order to pad // with zeros safely; fortunately this is not the worst case // path because cannot have had a round uByte buffer[ROUNDUP(DECPMAX+3, 4)]; // [+3 allows uInt padding] uByte *s=umsd; // source uByte *t=buffer; // safe target uByte *tlsd=buffer+(ulsd-umsd)+shift; // target LSD // printf("folddown shift=%ld\n", (LI)shift); for (; s<=ulsd; s+=4, t+=4) UBFROMUI(t, UBTOUI(s)); for (t=tlsd-shift+1; t<=tlsd; t+=4) UBFROMUI(t, 0); // pad 0s num->exponent-=shift; umsd=buffer; ulsd=tlsd; } } // fold-down? length=ulsd-umsd+1; // recalculate length } // high-end edge case } // finite number /*------------------------------------------------------------------*/ /* At this point the result will properly fit the decFloat */ /* encoding, and it can be encoded with no possibility of error */ /*------------------------------------------------------------------*/ // Following code does not alter coefficient (could be allnines array) // fast path possible when DECPMAX digits if (length==DECPMAX) { return decFloatFromBCD(df, num->exponent, umsd, num->sign); } // full-length // slower path when not a full-length number; must care about length // [coefficient length here will be < DECPMAX] if (!NUMISSPECIAL(num)) { // is still finite // encode the combination field and exponent continuation uInt uexp=(uInt)(num->exponent+DECBIAS); // biased exponent uInt code=(uexp>>DECECONL)<<4; // top two bits of exp // [msd==0] // look up the combination field and make high word encode=DECCOMBFROM[code]; // indexed by (0-2)*16+msd encode|=(uexp<<(32-6-DECECONL)) & 0x03ffffff; // exponent continuation } else encode=num->exponent; // special [already in word] encode|=num->sign; // add sign // private macro to extract a declet, n (where 0<=n=umsd) dpd=BCD2DPD[(*ub*256)+(*(ub+1)*16)+*(ub+2)]; \ else {dpd=*(ub+2); if (ub+1==umsd) dpd+=*(ub+1)*16; dpd=BCD2DPD[dpd];} // place the declets in the encoding words and copy to result (df), // according to endianness; in all cases complete the sign word // first #if DECPMAX==7 getDPDt(dpd, 1); encode|=dpd<<10; getDPDt(dpd, 0); encode|=dpd; DFWORD(df, 0)=encode; // just the one word #elif DECPMAX==16 getDPDt(dpd, 4); encode|=dpd<<8; getDPDt(dpd, 3); encode|=dpd>>2; DFWORD(df, 0)=encode; encode=dpd<<30; getDPDt(dpd, 2); encode|=dpd<<20; getDPDt(dpd, 1); encode|=dpd<<10; getDPDt(dpd, 0); encode|=dpd; DFWORD(df, 1)=encode; #elif DECPMAX==34 getDPDt(dpd,10); encode|=dpd<<4; getDPDt(dpd, 9); encode|=dpd>>6; DFWORD(df, 0)=encode; encode=dpd<<26; getDPDt(dpd, 8); encode|=dpd<<16; getDPDt(dpd, 7); encode|=dpd<<6; getDPDt(dpd, 6); encode|=dpd>>4; DFWORD(df, 1)=encode; encode=dpd<<28; getDPDt(dpd, 5); encode|=dpd<<18; getDPDt(dpd, 4); encode|=dpd<<8; getDPDt(dpd, 3); encode|=dpd>>2; DFWORD(df, 2)=encode; encode=dpd<<30; getDPDt(dpd, 2); encode|=dpd<<20; getDPDt(dpd, 1); encode|=dpd<<10; getDPDt(dpd, 0); encode|=dpd; DFWORD(df, 3)=encode; #endif // printf("Status: %08lx\n", (LI)set->status); // decFloatShow(df, "final2"); return df; } // decFinalize /* ------------------------------------------------------------------ */ /* decFloatFromBCD -- set decFloat from exponent, BCD8, and sign */ /* */ /* df is the target decFloat */ /* exp is the in-range unbiased exponent, q, or a special value in */ /* the form returned by decFloatGetExponent */ /* bcdar holds DECPMAX digits to set the coefficient from, one */ /* digit in each byte (BCD8 encoding); the first (MSD) is ignored */ /* if df is a NaN; all are ignored if df is infinite. */ /* All bytes must be in 0-9; results are undefined otherwise. */ /* sig is DECFLOAT_Sign to set the sign bit, 0 otherwise */ /* returns df, which will be canonical */ /* */ /* No error is possible, and no status will be set. */ /* ------------------------------------------------------------------ */ decFloat * decFloatFromBCD(decFloat *df, Int exp, const uByte *bcdar, Int sig) { uInt encode, dpd; // work const uByte *ub; // .. if (EXPISSPECIAL(exp)) encode=exp|sig;// specials already encoded else { // is finite // encode the combination field and exponent continuation uInt uexp=(uInt)(exp+DECBIAS); // biased exponent uInt code=(uexp>>DECECONL)<<4; // top two bits of exp code+=bcdar[0]; // add msd // look up the combination field and make high word encode=DECCOMBFROM[code]|sig; // indexed by (0-2)*16+msd encode|=(uexp<<(32-6-DECECONL)) & 0x03ffffff; // exponent continuation } // private macro to extract a declet, n (where 0<=n>2; DFWORD(df, 0)=encode; encode=dpd<<30; getDPDb(dpd, 2); encode|=dpd<<20; getDPDb(dpd, 1); encode|=dpd<<10; getDPDb(dpd, 0); encode|=dpd; DFWORD(df, 1)=encode; #elif DECPMAX==34 getDPDb(dpd,10); encode|=dpd<<4; getDPDb(dpd, 9); encode|=dpd>>6; DFWORD(df, 0)=encode; encode=dpd<<26; getDPDb(dpd, 8); encode|=dpd<<16; getDPDb(dpd, 7); encode|=dpd<<6; getDPDb(dpd, 6); encode|=dpd>>4; DFWORD(df, 1)=encode; encode=dpd<<28; getDPDb(dpd, 5); encode|=dpd<<18; getDPDb(dpd, 4); encode|=dpd<<8; getDPDb(dpd, 3); encode|=dpd>>2; DFWORD(df, 2)=encode; encode=dpd<<30; getDPDb(dpd, 2); encode|=dpd<<20; getDPDb(dpd, 1); encode|=dpd<<10; getDPDb(dpd, 0); encode|=dpd; DFWORD(df, 3)=encode; #endif // decFloatShow(df, "fromB"); return df; } // decFloatFromBCD /* ------------------------------------------------------------------ */ /* decFloatFromPacked -- set decFloat from exponent and packed BCD */ /* */ /* df is the target decFloat */ /* exp is the in-range unbiased exponent, q, or a special value in */ /* the form returned by decFloatGetExponent */ /* packed holds DECPMAX packed decimal digits plus a sign nibble */ /* (all 6 codes are OK); the first (MSD) is ignored if df is a NaN */ /* and all except sign are ignored if df is infinite. For DOUBLE */ /* and QUAD the first (pad) nibble is also ignored in all cases. */ /* All coefficient nibbles must be in 0-9 and sign in A-F; results */ /* are undefined otherwise. */ /* returns df, which will be canonical */ /* */ /* No error is possible, and no status will be set. */ /* ------------------------------------------------------------------ */ decFloat * decFloatFromPacked(decFloat *df, Int exp, const uByte *packed) { uByte bcdar[DECPMAX+2]; // work [+1 for pad, +1 for sign] const uByte *ip; // .. uByte *op; // .. Int sig=0; // sign // expand coefficient and sign to BCDAR #if SINGLE op=bcdar+1; // no pad digit #else op=bcdar; // first (pad) digit ignored #endif for (ip=packed; ip>4; *op++=(uByte)(*ip&0x0f); // [final nibble is sign] } op--; // -> sign byte if (*op==DECPMINUS || *op==DECPMINUSALT) sig=DECFLOAT_Sign; if (EXPISSPECIAL(exp)) { // Infinity or NaN if (!EXPISINF(exp)) bcdar[1]=0; // a NaN: ignore MSD else memset(bcdar+1, 0, DECPMAX); // Infinite: coefficient to 0 } return decFloatFromBCD(df, exp, bcdar+1, sig); } // decFloatFromPacked /* ------------------------------------------------------------------ */ /* decFloatFromPackedChecked -- set from exponent and packed; checked */ /* */ /* df is the target decFloat */ /* exp is the in-range unbiased exponent, q, or a special value in */ /* the form returned by decFloatGetExponent */ /* packed holds DECPMAX packed decimal digits plus a sign nibble */ /* (all 6 codes are OK); the first (MSD) must be 0 if df is a NaN */ /* and all digits must be 0 if df is infinite. For DOUBLE and */ /* QUAD the first (pad) nibble must be 0. */ /* All coefficient nibbles must be in 0-9 and sign in A-F. */ /* returns df, which will be canonical or NULL if any of the */ /* requirements are not met (if this case df is unchanged); that */ /* is, the input data must be as returned by decFloatToPacked, */ /* except that all six sign codes are acccepted. */ /* */ /* No status will be set. */ /* ------------------------------------------------------------------ */ decFloat * decFloatFromPackedChecked(decFloat *df, Int exp, const uByte *packed) { uByte bcdar[DECPMAX+2]; // work [+1 for pad, +1 for sign] const uByte *ip; // .. uByte *op; // .. Int sig=0; // sign // expand coefficient and sign to BCDAR #if SINGLE op=bcdar+1; // no pad digit #else op=bcdar; // first (pad) digit here #endif for (ip=packed; ip>4; if (*op>9) return NULL; op++; *op=(uByte)(*ip&0x0f); // [final nibble is sign] if (*op>9 && ip sign byte if (*op<=9) return NULL; // bad sign if (*op==DECPMINUS || *op==DECPMINUSALT) sig=DECFLOAT_Sign; #if !SINGLE if (bcdar[0]!=0) return NULL; // bad pad nibble #endif if (EXPISNAN(exp)) { // a NaN if (bcdar[1]!=0) return NULL; // bad msd } // NaN else if (EXPISINF(exp)) { // is infinite Int i; for (i=0; iDECEMAX-DECPMAX+1) return NULL; if (exp first character of decimal part const char *c; // work uByte *ub; // .. uInt uiwork; // for macros bcdnum num; // collects data for finishing uInt error=DEC_Conversion_syntax; // assume the worst uByte buffer[ROUNDUP(DECSTRING+11, 8)]; // room for most coefficents, // some common rounding, +3, & pad #if DECTRACE // printf("FromString %s ...\n", string); #endif for(;;) { // once-only 'loop' num.sign=0; // assume non-negative num.msd=buffer; // MSD is here always // detect and validate the coefficient, including any leading, // trailing, or embedded '.' // [could test four-at-a-time here (saving 10% for decQuads), // but that risks storage violation because the position of the // terminator is unknown] for (c=string;; c++) { // -> input character if (((unsigned)(*c-'0'))<=9) continue; // '0' through '9' is good if (*c=='\0') break; // most common non-digit if (*c=='.') { if (dotchar!=NULL) break; // not first '.' dotchar=c; // record offset into decimal part continue;} if (c==string) { // first in string... if (*c=='-') { // valid - sign cfirst++; num.sign=DECFLOAT_Sign; continue;} if (*c=='+') { // valid + sign cfirst++; continue;} } // *c is not a digit, terminator, or a valid +, -, or '.' break; } // c loop digits=(uInt)(c-cfirst); // digits (+1 if a dot) if (digits>0) { // had digits and/or dot const char *clast=c-1; // note last coefficient char position Int exp=0; // exponent accumulator if (*c!='\0') { // something follows the coefficient uInt edig; // unsigned work // had some digits and more to come; expect E[+|-]nnn now const char *firstexp; // exponent first non-zero if (*c!='E' && *c!='e') break; c++; // to (optional) sign if (*c=='-' || *c=='+') c++; // step over sign (c=clast+2) if (*c=='\0') break; // no digits! (e.g., '1.2E') for (; *c=='0';) c++; // skip leading zeros [even last] firstexp=c; // remember start [maybe '\0'] // gather exponent digits edig=(uInt)*c-(uInt)'0'; if (edig<=9) { // [check not bad or terminator] exp+=edig; // avoid initial X10 c++; for (;; c++) { edig=(uInt)*c-(uInt)'0'; if (edig>9) break; exp=exp*10+edig; } } // if not now on the '\0', *c must not be a digit if (*c!='\0') break; // (this next test must be after the syntax checks) // if definitely more than the possible digits for format then // the exponent may have wrapped, so simply set it to a certain // over/underflow value if (c>firstexp+DECEMAXD) exp=DECEMAX*2; if (*(clast+2)=='-') exp=-exp; // was negative } // exponent part if (dotchar!=NULL) { // had a '.' digits--; // remove from digits count if (digits==0) break; // was dot alone: bad syntax exp-=(Int)(clast-dotchar); // adjust exponent // [the '.' can now be ignored] } num.exponent=exp; // exponent is good; store it // Here when whole string has been inspected and syntax is good // cfirst->first digit or dot, clast->last digit or dot error=0; // no error possible now // if the number of digits in the coefficient will fit in buffer // then it can simply be converted to bcd8 and copied -- decFinalize // will take care of leading zeros and rounding; the buffer is big // enough for all canonical coefficients, including 0.00000nn... ub=buffer; if (digits<=(Int)(sizeof(buffer)-3)) { // [-3 allows by-4s copy] c=cfirst; if (dotchar!=NULL) { // a dot to worry about if (*(c+1)=='.') { // common canonical case *ub++=(uByte)(*c-'0'); // copy leading digit c+=2; // prepare to handle rest } else for (; c<=clast;) { // '.' could be anywhere // as usual, go by fours when safe; NB it has been asserted // that a '.' does not have the same mask as a digit if (c<=clast-3 // safe for four && (UBTOUI(c)&0xf0f0f0f0)==CHARMASK) { // test four UBFROMUI(ub, UBTOUI(c)&0x0f0f0f0f); // to BCD8 ub+=4; c+=4; continue; } if (*c=='.') { // found the dot c++; // step over it .. break; // .. and handle the rest } *ub++=(uByte)(*c++-'0'); } } // had dot // Now no dot; do this by fours (where safe) for (; c<=clast-3; c+=4, ub+=4) UBFROMUI(ub, UBTOUI(c)&0x0f0f0f0f); for (; c<=clast; c++, ub++) *ub=(uByte)(*c-'0'); num.lsd=buffer+digits-1; // record new LSD } // fits else { // too long for buffer // [This is a rare and unusual case; arbitrary-length input] // strip leading zeros [but leave final 0 if all 0's] if (*cfirst=='.') cfirst++; // step past dot at start if (*cfirst=='0') { // [cfirst always -> digit] for (; cfirst LSD for (; c<=clast; c++) { // inspect remaining chars if (*c!='0') { // sticky bit needed if (*c=='.') continue; // [ignore] *ub=DECSTICKYTAB[*ub]; // update round-for-reround break; // no need to look at more } } num.lsd=ub; // record LSD // adjust exponent for dropped digits num.exponent+=digits-(Int)(ub-buffer+1); } // too long for buffer } // digits and/or dot else { // no digits or dot were found // only Infinities and NaNs are allowed, here if (*c=='\0') break; // nothing there is bad buffer[0]=0; // default a coefficient of 0 num.lsd=buffer; // .. if (decBiStr(c, "infinity", "INFINITY") || decBiStr(c, "inf", "INF")) num.exponent=DECFLOAT_Inf; else { // should be a NaN num.exponent=DECFLOAT_qNaN; // assume quiet NaN if (*c=='s' || *c=='S') { // probably an sNaN num.exponent=DECFLOAT_sNaN; // effect the 's' c++; // and step over it } if (*c!='N' && *c!='n') break; // check caseless "NaN" c++; if (*c!='a' && *c!='A') break; // .. c++; if (*c!='N' && *c!='n') break; // .. c++; // now either nothing, or nnnn payload (no dots), expected // -> start of integer, and skip leading 0s [including plain 0] for (cfirst=c; *cfirst=='0';) cfirst++; if (*cfirst!='\0') { // not empty or all-0, payload // payload found; check all valid digits and copy to buffer as bcd8 ub=buffer; for (c=cfirst;; c++, ub++) { if ((unsigned)(*c-'0')>9) break; // quit if not 0-9 if (c-cfirst==DECPMAX-1) break; // too many digits *ub=(uByte)(*c-'0'); // good bcd8 } if (*c!='\0') break; // not all digits, or too many num.lsd=ub-1; // record new LSD } } // NaN or sNaN error=0; // syntax is OK } // digits=0 (special expected) break; // drop out } // [for(;;) once-loop] // decShowNum(&num, "fromStr"); if (error!=0) { set->status|=error; num.exponent=DECFLOAT_qNaN; // set up quiet NaN num.sign=0; // .. with 0 sign buffer[0]=0; // .. and coefficient num.lsd=buffer; // .. // decShowNum(&num, "oops"); } // decShowNum(&num, "dffs"); decFinalize(result, &num, set); // round, check, and lay out // decFloatShow(result, "fromString"); return result; } // decFloatFromString /* ------------------------------------------------------------------ */ /* decFloatFromWider -- conversion from next-wider format */ /* */ /* result is the decFloat format number which gets the result of */ /* the conversion */ /* wider is the decFloatWider format number which will be narrowed */ /* set is the context */ /* returns result */ /* */ /* Narrowing can cause rounding, overflow, etc., but not Invalid */ /* operation (sNaNs are copied and do not signal). */ /* ------------------------------------------------------------------ */ // narrow-to is not possible for decQuad format numbers; simply omit #if !QUAD decFloat * decFloatFromWider(decFloat *result, const decFloatWider *wider, decContext *set) { bcdnum num; // collects data for finishing uByte bcdar[DECWPMAX]; // room for wider coefficient uInt widerhi=DFWWORD(wider, 0); // top word Int exp; GETWCOEFF(wider, bcdar); num.msd=bcdar; // MSD is here always num.lsd=bcdar+DECWPMAX-1; // LSD is here always num.sign=widerhi&0x80000000; // extract sign [DECFLOAT_Sign=Neg] // decode the wider combination field to exponent exp=DECCOMBWEXP[widerhi>>26]; // decode from wider combination field // if it is a special there's nothing to do unless sNaN; if it's // finite then add the (wider) exponent continuation and unbias if (EXPISSPECIAL(exp)) exp=widerhi&0x7e000000; // include sNaN selector else exp+=GETWECON(wider)-DECWBIAS; num.exponent=exp; // decShowNum(&num, "dffw"); return decFinalize(result, &num, set);// round, check, and lay out } // decFloatFromWider #endif /* ------------------------------------------------------------------ */ /* decFloatGetCoefficient -- get coefficient as BCD8 */ /* */ /* df is the decFloat from which to extract the coefficient */ /* bcdar is where DECPMAX bytes will be written, one BCD digit in */ /* each byte (BCD8 encoding); if df is a NaN the first byte will */ /* be zero, and if it is infinite they will all be zero */ /* returns the sign of the coefficient (DECFLOAT_Sign if negative, */ /* 0 otherwise) */ /* */ /* No error is possible, and no status will be set. If df is a */ /* special value the array is set to zeros (for Infinity) or to the */ /* payload of a qNaN or sNaN. */ /* ------------------------------------------------------------------ */ Int decFloatGetCoefficient(const decFloat *df, uByte *bcdar) { if (DFISINF(df)) memset(bcdar, 0, DECPMAX); else { GETCOEFF(df, bcdar); // use macro if (DFISNAN(df)) bcdar[0]=0; // MSD needs correcting } return GETSIGN(df); } // decFloatGetCoefficient /* ------------------------------------------------------------------ */ /* decFloatGetExponent -- get unbiased exponent */ /* */ /* df is the decFloat from which to extract the exponent */ /* returns the exponent, q. */ /* */ /* No error is possible, and no status will be set. If df is a */ /* special value the first seven bits of the decFloat are returned, */ /* left adjusted and with the first (sign) bit set to 0 (followed by */ /* 25 0 bits). e.g., -sNaN would return 0x7e000000 (DECFLOAT_sNaN). */ /* ------------------------------------------------------------------ */ Int decFloatGetExponent(const decFloat *df) { if (DFISSPECIAL(df)) return DFWORD(df, 0)&0x7e000000; return GETEXPUN(df); } // decFloatGetExponent /* ------------------------------------------------------------------ */ /* decFloatSetCoefficient -- set coefficient from BCD8 */ /* */ /* df is the target decFloat (and source of exponent/special value) */ /* bcdar holds DECPMAX digits to set the coefficient from, one */ /* digit in each byte (BCD8 encoding); the first (MSD) is ignored */ /* if df is a NaN; all are ignored if df is infinite. */ /* sig is DECFLOAT_Sign to set the sign bit, 0 otherwise */ /* returns df, which will be canonical */ /* */ /* No error is possible, and no status will be set. */ /* ------------------------------------------------------------------ */ decFloat * decFloatSetCoefficient(decFloat *df, const uByte *bcdar, Int sig) { uInt exp; // for exponent uByte bcdzero[DECPMAX]; // for infinities // Exponent/special code is extracted from df if (DFISSPECIAL(df)) { exp=DFWORD(df, 0)&0x7e000000; if (DFISINF(df)) { memset(bcdzero, 0, DECPMAX); return decFloatFromBCD(df, exp, bcdzero, sig); } } else exp=GETEXPUN(df); return decFloatFromBCD(df, exp, bcdar, sig); } // decFloatSetCoefficient /* ------------------------------------------------------------------ */ /* decFloatSetExponent -- set exponent or special value */ /* */ /* df is the target decFloat (and source of coefficient/payload) */ /* set is the context for reporting status */ /* exp is the unbiased exponent, q, or a special value in the form */ /* returned by decFloatGetExponent */ /* returns df, which will be canonical */ /* */ /* No error is possible, but Overflow or Underflow might occur. */ /* ------------------------------------------------------------------ */ decFloat * decFloatSetExponent(decFloat *df, decContext *set, Int exp) { uByte bcdcopy[DECPMAX]; // for coefficient bcdnum num; // work num.exponent=exp; num.sign=decFloatGetCoefficient(df, bcdcopy); // extract coefficient if (DFISSPECIAL(df)) { // MSD or more needs correcting if (DFISINF(df)) memset(bcdcopy, 0, DECPMAX); bcdcopy[0]=0; } num.msd=bcdcopy; num.lsd=bcdcopy+DECPMAX-1; return decFinalize(df, &num, set); } // decFloatSetExponent /* ------------------------------------------------------------------ */ /* decFloatRadix -- returns the base (10) */ /* */ /* df is any decFloat of this format */ /* ------------------------------------------------------------------ */ uInt decFloatRadix(const decFloat *df) { if (df) return 10; // to placate compiler return 10; } // decFloatRadix /* The following function is not available if DECPRINT=0 */ #if DECPRINT /* ------------------------------------------------------------------ */ /* decFloatShow -- printf a decFloat in hexadecimal and decimal */ /* df is the decFloat to show */ /* tag is a tag string displayed with the number */ /* */ /* This is a debug aid; the precise format of the string may change. */ /* ------------------------------------------------------------------ */ void decFloatShow(const decFloat *df, const char *tag) { char hexbuf[DECBYTES*2+DECBYTES/4+1]; // NB blank after every fourth char buff[DECSTRING]; // for value in decimal Int i, j=0; for (i=0; ibytes[DECBYTES-1-i]); #else sprintf(&hexbuf[j], "%02x", df->bytes[i]); #endif j+=2; // the next line adds blank (and terminator) after final pair, too if ((i+1)%4==0) {strcpy(&hexbuf[j], " "); j++;} } decFloatToString(df, buff); printf(">%s> %s [big-endian] %s\n", tag, hexbuf, buff); return; } // decFloatShow #endif /* ------------------------------------------------------------------ */ /* decFloatToBCD -- get sign, exponent, and BCD8 from a decFloat */ /* */ /* df is the source decFloat */ /* exp will be set to the unbiased exponent, q, or to a special */ /* value in the form returned by decFloatGetExponent */ /* bcdar is where DECPMAX bytes will be written, one BCD digit in */ /* each byte (BCD8 encoding); if df is a NaN the first byte will */ /* be zero, and if it is infinite they will all be zero */ /* returns the sign of the coefficient (DECFLOAT_Sign if negative, */ /* 0 otherwise) */ /* */ /* No error is possible, and no status will be set. */ /* ------------------------------------------------------------------ */ Int decFloatToBCD(const decFloat *df, Int *exp, uByte *bcdar) { if (DFISINF(df)) { memset(bcdar, 0, DECPMAX); *exp=DFWORD(df, 0)&0x7e000000; } else { GETCOEFF(df, bcdar); // use macro if (DFISNAN(df)) { bcdar[0]=0; // MSD needs correcting *exp=DFWORD(df, 0)&0x7e000000; } else { // finite *exp=GETEXPUN(df); } } return GETSIGN(df); } // decFloatToBCD /* ------------------------------------------------------------------ */ /* decFloatToEngString -- conversion to numeric string, engineering */ /* */ /* df is the decFloat format number to convert */ /* string is the string where the result will be laid out */ /* */ /* string must be at least DECPMAX+9 characters (the worst case is */ /* "-0.00000nnn...nnn\0", which is as long as the exponent form when */ /* DECEMAXD<=4); this condition is asserted above */ /* */ /* No error is possible, and no status will be set */ /* ------------------------------------------------------------------ */ char * decFloatToEngString(const decFloat *df, char *string){ uInt msd; // coefficient MSD Int exp; // exponent top two bits or full uInt comb; // combination field char *cstart; // coefficient start char *c; // output pointer in string char *s, *t; // .. (source, target) Int pre, e; // work const uByte *u; // .. uInt uiwork; // for macros [one compiler needs // volatile here to avoid bug, but // that doubles execution time] // Source words; macro handles endianness uInt sourhi=DFWORD(df, 0); // word with sign #if DECPMAX==16 uInt sourlo=DFWORD(df, 1); #elif DECPMAX==34 uInt sourmh=DFWORD(df, 1); uInt sourml=DFWORD(df, 2); uInt sourlo=DFWORD(df, 3); #endif c=string; // where result will go if (((Int)sourhi)<0) *c++='-'; // handle sign comb=sourhi>>26; // sign+combination field msd=DECCOMBMSD[comb]; // decode the combination field exp=DECCOMBEXP[comb]; // .. if (EXPISSPECIAL(exp)) { // special if (exp==DECFLOAT_Inf) { // infinity strcpy(c, "Inf"); strcpy(c+3, "inity"); return string; // easy } if (sourhi&0x02000000) *c++='s'; // sNaN strcpy(c, "NaN"); // complete word c+=3; // step past // quick exit if the payload is zero #if DECPMAX==7 if ((sourhi&0x000fffff)==0) return string; #elif DECPMAX==16 if (sourlo==0 && (sourhi&0x0003ffff)==0) return string; #elif DECPMAX==34 if (sourlo==0 && sourml==0 && sourmh==0 && (sourhi&0x00003fff)==0) return string; #endif // otherwise drop through to add integer; set correct exp etc. exp=0; msd=0; // setup for following code } else { // complete exponent; top two bits are in place exp+=GETECON(df)-DECBIAS; // .. + continuation and unbias } /* convert the digits of the significand to characters */ cstart=c; // save start of coefficient if (msd) *c++=(char)('0'+(char)msd); // non-zero most significant digit // Decode the declets. After extracting each declet, it is // decoded to a 4-uByte sequence by table lookup; the four uBytes // are the three encoded BCD8 digits followed by a 1-byte length // (significant digits, except that 000 has length 0). This allows // us to left-align the first declet with non-zero content, then // the remaining ones are full 3-char length. Fixed-length copies // are used because variable-length memcpy causes a subroutine call // in at least two compilers. (The copies are length 4 for speed // and are safe because the last item in the array is of length // three and has the length byte following.) #define dpd2char(dpdin) u=&DPD2BCD8[((dpdin)&0x3ff)*4]; \ if (c!=cstart) {UBFROMUI(c, UBTOUI(u)|CHARMASK); c+=3;} \ else if (*(u+3)) { \ UBFROMUI(c, UBTOUI(u+3-*(u+3))|CHARMASK); c+=*(u+3);} #if DECPMAX==7 dpd2char(sourhi>>10); // declet 1 dpd2char(sourhi); // declet 2 #elif DECPMAX==16 dpd2char(sourhi>>8); // declet 1 dpd2char((sourhi<<2) | (sourlo>>30)); // declet 2 dpd2char(sourlo>>20); // declet 3 dpd2char(sourlo>>10); // declet 4 dpd2char(sourlo); // declet 5 #elif DECPMAX==34 dpd2char(sourhi>>4); // declet 1 dpd2char((sourhi<<6) | (sourmh>>26)); // declet 2 dpd2char(sourmh>>16); // declet 3 dpd2char(sourmh>>6); // declet 4 dpd2char((sourmh<<4) | (sourml>>28)); // declet 5 dpd2char(sourml>>18); // declet 6 dpd2char(sourml>>8); // declet 7 dpd2char((sourml<<2) | (sourlo>>30)); // declet 8 dpd2char(sourlo>>20); // declet 9 dpd2char(sourlo>>10); // declet 10 dpd2char(sourlo); // declet 11 #endif if (c==cstart) *c++='0'; // all zeros, empty -- make "0" if (exp==0) { // integer or NaN case -- easy *c='\0'; // terminate return string; } /* non-0 exponent */ e=0; // assume no E pre=(Int)(c-cstart)+exp; // length+exp [c->LSD+1] // [here, pre-exp is the digits count (==1 for zero)] if (exp>0 || pre<-5) { // need exponential form e=pre-1; // calculate E value pre=1; // assume one digit before '.' if (e!=0) { // engineering: may need to adjust Int adj; // adjustment // The C remainder operator is undefined for negative numbers, so // a positive remainder calculation must be used here if (e<0) { adj=(-e)%3; if (adj!=0) adj=3-adj; } else { // e>0 adj=e%3; } e=e-adj; // if dealing with zero still produce an exponent which is a // multiple of three, as expected, but there will only be the // one zero before the E, still. Otherwise note the padding. if (!DFISZERO(df)) pre+=adj; else { // is zero if (adj!=0) { // 0.00Esnn needed e=e+3; pre=-(2-adj); } } // zero } // engineering adjustment } // exponential form // printf("e=%ld pre=%ld exp=%ld\n", (LI)e, (LI)pre, (LI)exp); /* modify the coefficient, adding 0s, '.', and E+nn as needed */ if (pre>0) { // ddd.ddd (plain), perhaps with E // or dd00 padding for engineering char *dotat=cstart+pre; if (dotat=dotat; s-=4, t-=4) UBFROMUI(t, UBTOUI(s)); *dotat='.'; c++; // length increased by one } // need dot? else for (; c0 else { /* -5<=pre<=0: here for plain 0.ddd or 0.000ddd forms (may have E, but only for 0.00E+3 kind of case -- with plenty of spare space in this case */ pre=-pre+2; // gap width, including "0." t=cstart+ROUNDDOWN4(c-cstart)+pre; // preferred first target point // backoff if too far to the right if (t>string+DECSTRING-5) t=string+DECSTRING-5; // adjust to fit // now shift the entire coefficient to the right, being careful not // to access to the left of string [cannot use memcpy] for (s=t-pre; s>=string; s-=4, t-=4) UBFROMUI(t, UBTOUI(s)); // for Quads and Singles there may be a character or two left... s+=3; // where next would come from for(; s>=cstart; s--, t--) *(t+3)=*(s); // now have fill 0. through 0.00000; use overlaps to avoid tests if (pre>=4) { memcpy(cstart+pre-4, "0000", 4); memcpy(cstart, "0.00", 4); } else { // 2 or 3 *(cstart+pre-1)='0'; memcpy(cstart, "0.", 2); } c+=pre; // to end } // finally add the E-part, if needed; it will never be 0, and has // a maximum length of 3 or 4 digits (asserted above) if (e!=0) { memcpy(c, "E+", 2); // starts with E, assume + c++; if (e<0) { *c='-'; // oops, need '-' e=-e; // uInt, please } c++; // Three-character exponents are easy; 4-character a little trickier #if DECEMAXD<=3 u=&BIN2BCD8[e*4]; // -> 3 digits + length byte // copy fixed 4 characters [is safe], starting at non-zero // and with character mask to convert BCD to char UBFROMUI(c, UBTOUI(u+3-*(u+3))|CHARMASK); c+=*(u+3); // bump pointer appropriately #elif DECEMAXD==4 if (e<1000) { // 3 (or fewer) digits case u=&BIN2BCD8[e*4]; // -> 3 digits + length byte UBFROMUI(c, UBTOUI(u+3-*(u+3))|CHARMASK); // [as above] c+=*(u+3); // bump pointer appropriately } else { // 4-digits Int thou=((e>>3)*1049)>>17; // e/1000 Int rem=e-(1000*thou); // e%1000 *c++=(char)('0'+(char)thou); // the thousands digit u=&BIN2BCD8[rem*4]; // -> 3 digits + length byte UBFROMUI(c, UBTOUI(u)|CHARMASK);// copy fixed 3+1 characters [is safe] c+=3; // bump pointer, always 3 digits } #endif } *c='\0'; // terminate //printf("res %s\n", string); return string; } // decFloatToEngString /* ------------------------------------------------------------------ */ /* decFloatToPacked -- convert decFloat to Packed decimal + exponent */ /* */ /* df is the source decFloat */ /* exp will be set to the unbiased exponent, q, or to a special */ /* value in the form returned by decFloatGetExponent */ /* packed is where DECPMAX nibbles will be written with the sign as */ /* final nibble (0x0c for +, 0x0d for -); a NaN has a first nibble */ /* of zero, and an infinity is all zeros. decDouble and decQuad */ /* have a additional leading zero nibble, leading to result */ /* lengths of 4, 9, and 18 bytes. */ /* returns the sign of the coefficient (DECFLOAT_Sign if negative, */ /* 0 otherwise) */ /* */ /* No error is possible, and no status will be set. */ /* ------------------------------------------------------------------ */ Int decFloatToPacked(const decFloat *df, Int *exp, uByte *packed) { uByte bcdar[DECPMAX+2]; // work buffer uByte *ip=bcdar, *op=packed; // work pointers if (DFISINF(df)) { memset(bcdar, 0, DECPMAX+2); *exp=DECFLOAT_Inf; } else { GETCOEFF(df, bcdar+1); // use macro if (DFISNAN(df)) { bcdar[1]=0; // MSD needs clearing *exp=DFWORD(df, 0)&0x7e000000; } else { // finite *exp=GETEXPUN(df); } } // now pack; coefficient currently at bcdar+1 #if SINGLE ip++; // ignore first byte #else *ip=0; // need leading zero #endif // set final byte to Packed BCD sign value bcdar[DECPMAX+1]=(DFISSIGNED(df) ? DECPMINUS : DECPPLUS); // pack an even number of bytes... for (; op>26; // sign+combination field msd=DECCOMBMSD[comb]; // decode the combination field exp=DECCOMBEXP[comb]; // .. if (!EXPISSPECIAL(exp)) { // finite // complete exponent; top two bits are in place exp+=GETECON(df)-DECBIAS; // .. + continuation and unbias } else { // IS special if (exp==DECFLOAT_Inf) { // infinity strcpy(c, "Infinity"); return string; // easy } if (sourhi&0x02000000) *c++='s'; // sNaN strcpy(c, "NaN"); // complete word c+=3; // step past // quick exit if the payload is zero #if DECPMAX==7 if ((sourhi&0x000fffff)==0) return string; #elif DECPMAX==16 if (sourlo==0 && (sourhi&0x0003ffff)==0) return string; #elif DECPMAX==34 if (sourlo==0 && sourml==0 && sourmh==0 && (sourhi&0x00003fff)==0) return string; #endif // otherwise drop through to add integer; set correct exp etc. exp=0; msd=0; // setup for following code } /* convert the digits of the significand to characters */ cstart=c; // save start of coefficient if (msd) *c++=(char)('0'+(char)msd); // non-zero most significant digit // Decode the declets. After extracting each declet, it is // decoded to a 4-uByte sequence by table lookup; the four uBytes // are the three encoded BCD8 digits followed by a 1-byte length // (significant digits, except that 000 has length 0). This allows // us to left-align the first declet with non-zero content, then // the remaining ones are full 3-char length. Fixed-length copies // are used because variable-length memcpy causes a subroutine call // in at least two compilers. (The copies are length 4 for speed // and are safe because the last item in the array is of length // three and has the length byte following.) #define dpd2char(dpdin) u=&DPD2BCD8[((dpdin)&0x3ff)*4]; \ if (c!=cstart) {UBFROMUI(c, UBTOUI(u)|CHARMASK); c+=3;} \ else if (*(u+3)) { \ UBFROMUI(c, UBTOUI(u+3-*(u+3))|CHARMASK); c+=*(u+3);} #if DECPMAX==7 dpd2char(sourhi>>10); // declet 1 dpd2char(sourhi); // declet 2 #elif DECPMAX==16 dpd2char(sourhi>>8); // declet 1 dpd2char((sourhi<<2) | (sourlo>>30)); // declet 2 dpd2char(sourlo>>20); // declet 3 dpd2char(sourlo>>10); // declet 4 dpd2char(sourlo); // declet 5 #elif DECPMAX==34 dpd2char(sourhi>>4); // declet 1 dpd2char((sourhi<<6) | (sourmh>>26)); // declet 2 dpd2char(sourmh>>16); // declet 3 dpd2char(sourmh>>6); // declet 4 dpd2char((sourmh<<4) | (sourml>>28)); // declet 5 dpd2char(sourml>>18); // declet 6 dpd2char(sourml>>8); // declet 7 dpd2char((sourml<<2) | (sourlo>>30)); // declet 8 dpd2char(sourlo>>20); // declet 9 dpd2char(sourlo>>10); // declet 10 dpd2char(sourlo); // declet 11 #endif if (c==cstart) *c++='0'; // all zeros, empty -- make "0" //[This fast path is valid but adds 3-5 cycles to worst case length] //if (exp==0) { // integer or NaN case -- easy // *c='\0'; // terminate // return string; // } e=0; // assume no E pre=(Int)(c-cstart)+exp; // length+exp [c->LSD+1] // [here, pre-exp is the digits count (==1 for zero)] if (exp>0 || pre<-5) { // need exponential form e=pre-1; // calculate E value pre=1; // assume one digit before '.' } // exponential form /* modify the coefficient, adding 0s, '.', and E+nn as needed */ if (pre>0) { // ddd.ddd (plain), perhaps with E char *dotat=cstart+pre; if (dotat=dotat; s-=4, t-=4) UBFROMUI(t, UBTOUI(s)); *dotat='.'; c++; // length increased by one } // need dot? // finally add the E-part, if needed; it will never be 0, and has // a maximum length of 3 or 4 digits (asserted above) if (e!=0) { memcpy(c, "E+", 2); // starts with E, assume + c++; if (e<0) { *c='-'; // oops, need '-' e=-e; // uInt, please } c++; // Three-character exponents are easy; 4-character a little trickier #if DECEMAXD<=3 u=&BIN2BCD8[e*4]; // -> 3 digits + length byte // copy fixed 4 characters [is safe], starting at non-zero // and with character mask to convert BCD to char UBFROMUI(c, UBTOUI(u+3-*(u+3))|CHARMASK); c+=*(u+3); // bump pointer appropriately #elif DECEMAXD==4 if (e<1000) { // 3 (or fewer) digits case u=&BIN2BCD8[e*4]; // -> 3 digits + length byte UBFROMUI(c, UBTOUI(u+3-*(u+3))|CHARMASK); // [as above] c+=*(u+3); // bump pointer appropriately } else { // 4-digits Int thou=((e>>3)*1049)>>17; // e/1000 Int rem=e-(1000*thou); // e%1000 *c++=(char)('0'+(char)thou); // the thousands digit u=&BIN2BCD8[rem*4]; // -> 3 digits + length byte UBFROMUI(c, UBTOUI(u)|CHARMASK); // copy fixed 3+1 characters [is safe] c+=3; // bump pointer, always 3 digits } #endif } *c='\0'; // add terminator //printf("res %s\n", string); return string; } // pre>0 /* -5<=pre<=0: here for plain 0.ddd or 0.000ddd forms (can never have E) */ // Surprisingly, this is close to being the worst-case path, so the // shift is done by fours; this is a little tricky because the // rightmost character to be written must not be beyond where the // rightmost terminator could be -- so backoff to not touch // terminator position if need be (this can make exact alignments // for full Doubles, but in some cases needs care not to access too // far to the left) pre=-pre+2; // gap width, including "0." t=cstart+ROUNDDOWN4(c-cstart)+pre; // preferred first target point // backoff if too far to the right if (t>string+DECSTRING-5) t=string+DECSTRING-5; // adjust to fit // now shift the entire coefficient to the right, being careful not // to access to the left of string [cannot use memcpy] for (s=t-pre; s>=string; s-=4, t-=4) UBFROMUI(t, UBTOUI(s)); // for Quads and Singles there may be a character or two left... s+=3; // where next would come from for(; s>=cstart; s--, t--) *(t+3)=*(s); // now have fill 0. through 0.00000; use overlaps to avoid tests if (pre>=4) { memcpy(cstart+pre-4, "0000", 4); memcpy(cstart, "0.00", 4); } else { // 2 or 3 *(cstart+pre-1)='0'; memcpy(cstart, "0.", 2); } *(c+pre)='\0'; // terminate return string; } // decFloatToString /* ------------------------------------------------------------------ */ /* decFloatToWider -- conversion to next-wider format */ /* */ /* source is the decFloat format number which gets the result of */ /* the conversion */ /* wider is the decFloatWider format number which will be narrowed */ /* returns wider */ /* */ /* Widening is always exact; no status is set (sNaNs are copied and */ /* do not signal). The result will be canonical if the source is, */ /* and may or may not be if the source is not. */ /* ------------------------------------------------------------------ */ // widening is not possible for decQuad format numbers; simply omit #if !QUAD decFloatWider * decFloatToWider(const decFloat *source, decFloatWider *wider) { uInt msd; /* Construct and copy the sign word */ if (DFISSPECIAL(source)) { // copy sign, combination, and first bit of exponent (sNaN selector) DFWWORD(wider, 0)=DFWORD(source, 0)&0xfe000000; msd=0; } else { // is finite number uInt exp=GETEXPUN(source)+DECWBIAS; // get unbiased exponent and rebias uInt code=(exp>>DECWECONL)<<29; // set two bits of exp [msd=0] code|=(exp<<(32-6-DECWECONL)) & 0x03ffffff; // add exponent continuation code|=DFWORD(source, 0)&0x80000000; // add sign DFWWORD(wider, 0)=code; // .. and place top word in wider msd=GETMSD(source); // get source coefficient MSD [0-9] } /* Copy the coefficient and clear any 'unused' words to left */ #if SINGLE DFWWORD(wider, 1)=(DFWORD(source, 0)&0x000fffff)|(msd<<20); #elif DOUBLE DFWWORD(wider, 2)=(DFWORD(source, 0)&0x0003ffff)|(msd<<18); DFWWORD(wider, 3)=DFWORD(source, 1); DFWWORD(wider, 1)=0; #endif return wider; } // decFloatToWider #endif /* ------------------------------------------------------------------ */ /* decFloatVersion -- return package version string */ /* */ /* returns a constant string describing this package */ /* ------------------------------------------------------------------ */ const char *decFloatVersion(void) { return DECVERSION; } // decFloatVersion /* ------------------------------------------------------------------ */ /* decFloatZero -- set to canonical (integer) zero */ /* */ /* df is the decFloat format number to integer +0 (q=0, c=+0) */ /* returns df */ /* */ /* No error is possible, and no status can be set. */ /* ------------------------------------------------------------------ */ decFloat * decFloatZero(decFloat *df){ DFWORD(df, 0)=ZEROWORD; // set appropriate top word #if DOUBLE || QUAD DFWORD(df, 1)=0; #if QUAD DFWORD(df, 2)=0; DFWORD(df, 3)=0; #endif #endif // decFloatShow(df, "zero"); return df; } // decFloatZero /* ------------------------------------------------------------------ */ /* Private generic function (not format-specific) for development use */ /* ------------------------------------------------------------------ */ // This is included once only, for all to use #if QUAD && (DECCHECK || DECTRACE) /* ---------------------------------------------------------------- */ /* decShowNum -- display bcd8 number in debug form */ /* */ /* num is the bcdnum to display */ /* tag is a string to label the display */ /* ---------------------------------------------------------------- */ void decShowNum(const bcdnum *num, const char *tag) { const char *csign="+"; // sign character uByte *ub; // work uInt uiwork; // for macros if (num->sign==DECFLOAT_Sign) csign="-"; printf(">%s> ", tag); if (num->exponent==DECFLOAT_Inf) printf("%sInfinity", csign); else if (num->exponent==DECFLOAT_qNaN) printf("%sqNaN", csign); else if (num->exponent==DECFLOAT_sNaN) printf("%ssNaN", csign); else { // finite char qbuf[10]; // for right-aligned q char *c; // work const uByte *u; // .. Int e=num->exponent; // .. exponent strcpy(qbuf, "q="); c=&qbuf[2]; // where exponent will go // lay out the exponent if (e<0) { *c++='-'; // add '-' e=-e; // uInt, please } #if DECEMAXD>4 #error Exponent form is too long for ShowNum to lay out #endif if (e==0) *c++='0'; // 0-length case else if (e<1000) { // 3 (or fewer) digits case u=&BIN2BCD8[e*4]; // -> 3 digits + length byte UBFROMUI(c, UBTOUI(u+3-*(u+3))|CHARMASK); // [as above] c+=*(u+3); // bump pointer appropriately } else { // 4-digits Int thou=((e>>3)*1049)>>17; // e/1000 Int rem=e-(1000*thou); // e%1000 *c++=(char)('0'+(char)thou); // the thousands digit u=&BIN2BCD8[rem*4]; // -> 3 digits + length byte UBFROMUI(c, UBTOUI(u)|CHARMASK); // copy fixed 3+1 characters [is safe] c+=3; // bump pointer, always 3 digits } *c='\0'; // add terminator printf("%7s c=%s", qbuf, csign); } if (!EXPISSPECIAL(num->exponent) || num->msd!=num->lsd || *num->lsd!=0) { for (ub=num->msd; ub<=num->lsd; ub++) { // coefficient... printf("%1x", *ub); if ((num->lsd-ub)%3==0 && ub!=num->lsd) printf(" "); // 4-space } } printf("\n"); } // decShowNum #endif ================================================ FILE: vendor/decNumber/decContext.c ================================================ /* ------------------------------------------------------------------ */ /* Decimal Context module */ /* ------------------------------------------------------------------ */ /* Copyright (c) IBM Corporation, 2000, 2009. All rights reserved. */ /* */ /* This software is made available under the terms of the */ /* ICU License -- ICU 1.8.1 and later. */ /* */ /* The description and User's Guide ("The decNumber C Library") for */ /* this software is called decNumber.pdf. This document is */ /* available, together with arithmetic and format specifications, */ /* testcases, and Web links, on the General Decimal Arithmetic page. */ /* */ /* Please send comments, suggestions, and corrections to the author: */ /* mfc@uk.ibm.com */ /* Mike Cowlishaw, IBM Fellow */ /* IBM UK, PO Box 31, Birmingham Road, Warwick CV34 5JL, UK */ /* ------------------------------------------------------------------ */ /* This module comprises the routines for handling arithmetic */ /* context structures. */ /* ------------------------------------------------------------------ */ #include // for strcmp #include // for printf if DECCHECK #include "decContext.h" // context and base types #include "decNumberLocal.h" // decNumber local types, etc. /* compile-time endian tester [assumes sizeof(Int)>1] */ static const Int mfcone=1; // constant 1 static const Flag *mfctop=(const Flag *)&mfcone; // -> top byte #define LITEND *mfctop // named flag; 1=little-endian /* ------------------------------------------------------------------ */ /* round-for-reround digits */ /* ------------------------------------------------------------------ */ const uByte DECSTICKYTAB[10]={1,1,2,3,4,6,6,7,8,9}; /* used if sticky */ /* ------------------------------------------------------------------ */ /* Powers of ten (powers[n]==10**n, 0<=n<=9) */ /* ------------------------------------------------------------------ */ const uInt DECPOWERS[10]={1, 10, 100, 1000, 10000, 100000, 1000000, 10000000, 100000000, 1000000000}; /* ------------------------------------------------------------------ */ /* decContextClearStatus -- clear bits in current status */ /* */ /* context is the context structure to be queried */ /* mask indicates the bits to be cleared (the status bit that */ /* corresponds to each 1 bit in the mask is cleared) */ /* returns context */ /* */ /* No error is possible. */ /* ------------------------------------------------------------------ */ decContext *decContextClearStatus(decContext *context, uInt mask) { context->status&=~mask; return context; } // decContextClearStatus /* ------------------------------------------------------------------ */ /* decContextDefault -- initialize a context structure */ /* */ /* context is the structure to be initialized */ /* kind selects the required set of default values, one of: */ /* DEC_INIT_BASE -- select ANSI X3-274 defaults */ /* DEC_INIT_DECIMAL32 -- select IEEE 754 defaults, 32-bit */ /* DEC_INIT_DECIMAL64 -- select IEEE 754 defaults, 64-bit */ /* DEC_INIT_DECIMAL128 -- select IEEE 754 defaults, 128-bit */ /* For any other value a valid context is returned, but with */ /* Invalid_operation set in the status field. */ /* returns a context structure with the appropriate initial values. */ /* ------------------------------------------------------------------ */ decContext * decContextDefault(decContext *context, Int kind) { // set defaults... context->digits=9; // 9 digits context->emax=DEC_MAX_EMAX; // 9-digit exponents context->emin=DEC_MIN_EMIN; // .. balanced context->round=DEC_ROUND_HALF_UP; // 0.5 rises context->traps=DEC_Errors; // all but informational context->status=0; // cleared context->clamp=0; // no clamping #if DECSUBSET context->extended=0; // cleared #endif switch (kind) { case DEC_INIT_BASE: // [use defaults] break; case DEC_INIT_DECIMAL32: context->digits=7; // digits context->emax=96; // Emax context->emin=-95; // Emin context->round=DEC_ROUND_HALF_EVEN; // 0.5 to nearest even context->traps=0; // no traps set context->clamp=1; // clamp exponents #if DECSUBSET context->extended=1; // set #endif break; case DEC_INIT_DECIMAL64: context->digits=16; // digits context->emax=384; // Emax context->emin=-383; // Emin context->round=DEC_ROUND_HALF_EVEN; // 0.5 to nearest even context->traps=0; // no traps set context->clamp=1; // clamp exponents #if DECSUBSET context->extended=1; // set #endif break; case DEC_INIT_DECIMAL128: context->digits=34; // digits context->emax=6144; // Emax context->emin=-6143; // Emin context->round=DEC_ROUND_HALF_EVEN; // 0.5 to nearest even context->traps=0; // no traps set context->clamp=1; // clamp exponents #if DECSUBSET context->extended=1; // set #endif break; default: // invalid Kind // use defaults, and .. decContextSetStatus(context, DEC_Invalid_operation); // trap } return context;} // decContextDefault /* ------------------------------------------------------------------ */ /* decContextGetRounding -- return current rounding mode */ /* */ /* context is the context structure to be queried */ /* returns the rounding mode */ /* */ /* No error is possible. */ /* ------------------------------------------------------------------ */ enum rounding decContextGetRounding(decContext *context) { return context->round; } // decContextGetRounding /* ------------------------------------------------------------------ */ /* decContextGetStatus -- return current status */ /* */ /* context is the context structure to be queried */ /* returns status */ /* */ /* No error is possible. */ /* ------------------------------------------------------------------ */ uInt decContextGetStatus(decContext *context) { return context->status; } // decContextGetStatus /* ------------------------------------------------------------------ */ /* decContextRestoreStatus -- restore bits in current status */ /* */ /* context is the context structure to be updated */ /* newstatus is the source for the bits to be restored */ /* mask indicates the bits to be restored (the status bit that */ /* corresponds to each 1 bit in the mask is set to the value of */ /* the correspnding bit in newstatus) */ /* returns context */ /* */ /* No error is possible. */ /* ------------------------------------------------------------------ */ decContext *decContextRestoreStatus(decContext *context, uInt newstatus, uInt mask) { context->status&=~mask; // clear the selected bits context->status|=(mask&newstatus); // or in the new bits return context; } // decContextRestoreStatus /* ------------------------------------------------------------------ */ /* decContextSaveStatus -- save bits in current status */ /* */ /* context is the context structure to be queried */ /* mask indicates the bits to be saved (the status bits that */ /* correspond to each 1 bit in the mask are saved) */ /* returns the AND of the mask and the current status */ /* */ /* No error is possible. */ /* ------------------------------------------------------------------ */ uInt decContextSaveStatus(decContext *context, uInt mask) { return context->status&mask; } // decContextSaveStatus /* ------------------------------------------------------------------ */ /* decContextSetRounding -- set current rounding mode */ /* */ /* context is the context structure to be updated */ /* newround is the value which will replace the current mode */ /* returns context */ /* */ /* No error is possible. */ /* ------------------------------------------------------------------ */ decContext *decContextSetRounding(decContext *context, enum rounding newround) { context->round=newround; return context; } // decContextSetRounding /* ------------------------------------------------------------------ */ /* decContextSetStatus -- set status and raise trap if appropriate */ /* */ /* context is the context structure to be updated */ /* status is the DEC_ exception code */ /* returns the context structure */ /* */ /* Control may never return from this routine, if there is a signal */ /* handler and it takes a long jump. */ /* ------------------------------------------------------------------ */ decContext * decContextSetStatus(decContext *context, uInt status) { context->status|=status; if (status & context->traps) raise(SIGFPE); return context;} // decContextSetStatus /* ------------------------------------------------------------------ */ /* decContextSetStatusFromString -- set status from a string + trap */ /* */ /* context is the context structure to be updated */ /* string is a string exactly equal to one that might be returned */ /* by decContextStatusToString */ /* */ /* The status bit corresponding to the string is set, and a trap */ /* is raised if appropriate. */ /* */ /* returns the context structure, unless the string is equal to */ /* DEC_Condition_MU or is not recognized. In these cases NULL is */ /* returned. */ /* ------------------------------------------------------------------ */ decContext * decContextSetStatusFromString(decContext *context, const char *string) { if (strcmp(string, DEC_Condition_CS)==0) return decContextSetStatus(context, DEC_Conversion_syntax); if (strcmp(string, DEC_Condition_DZ)==0) return decContextSetStatus(context, DEC_Division_by_zero); if (strcmp(string, DEC_Condition_DI)==0) return decContextSetStatus(context, DEC_Division_impossible); if (strcmp(string, DEC_Condition_DU)==0) return decContextSetStatus(context, DEC_Division_undefined); if (strcmp(string, DEC_Condition_IE)==0) return decContextSetStatus(context, DEC_Inexact); if (strcmp(string, DEC_Condition_IS)==0) return decContextSetStatus(context, DEC_Insufficient_storage); if (strcmp(string, DEC_Condition_IC)==0) return decContextSetStatus(context, DEC_Invalid_context); if (strcmp(string, DEC_Condition_IO)==0) return decContextSetStatus(context, DEC_Invalid_operation); #if DECSUBSET if (strcmp(string, DEC_Condition_LD)==0) return decContextSetStatus(context, DEC_Lost_digits); #endif if (strcmp(string, DEC_Condition_OV)==0) return decContextSetStatus(context, DEC_Overflow); if (strcmp(string, DEC_Condition_PA)==0) return decContextSetStatus(context, DEC_Clamped); if (strcmp(string, DEC_Condition_RO)==0) return decContextSetStatus(context, DEC_Rounded); if (strcmp(string, DEC_Condition_SU)==0) return decContextSetStatus(context, DEC_Subnormal); if (strcmp(string, DEC_Condition_UN)==0) return decContextSetStatus(context, DEC_Underflow); if (strcmp(string, DEC_Condition_ZE)==0) return context; return NULL; // Multiple status, or unknown } // decContextSetStatusFromString /* ------------------------------------------------------------------ */ /* decContextSetStatusFromStringQuiet -- set status from a string */ /* */ /* context is the context structure to be updated */ /* string is a string exactly equal to one that might be returned */ /* by decContextStatusToString */ /* */ /* The status bit corresponding to the string is set; no trap is */ /* raised. */ /* */ /* returns the context structure, unless the string is equal to */ /* DEC_Condition_MU or is not recognized. In these cases NULL is */ /* returned. */ /* ------------------------------------------------------------------ */ decContext * decContextSetStatusFromStringQuiet(decContext *context, const char *string) { if (strcmp(string, DEC_Condition_CS)==0) return decContextSetStatusQuiet(context, DEC_Conversion_syntax); if (strcmp(string, DEC_Condition_DZ)==0) return decContextSetStatusQuiet(context, DEC_Division_by_zero); if (strcmp(string, DEC_Condition_DI)==0) return decContextSetStatusQuiet(context, DEC_Division_impossible); if (strcmp(string, DEC_Condition_DU)==0) return decContextSetStatusQuiet(context, DEC_Division_undefined); if (strcmp(string, DEC_Condition_IE)==0) return decContextSetStatusQuiet(context, DEC_Inexact); if (strcmp(string, DEC_Condition_IS)==0) return decContextSetStatusQuiet(context, DEC_Insufficient_storage); if (strcmp(string, DEC_Condition_IC)==0) return decContextSetStatusQuiet(context, DEC_Invalid_context); if (strcmp(string, DEC_Condition_IO)==0) return decContextSetStatusQuiet(context, DEC_Invalid_operation); #if DECSUBSET if (strcmp(string, DEC_Condition_LD)==0) return decContextSetStatusQuiet(context, DEC_Lost_digits); #endif if (strcmp(string, DEC_Condition_OV)==0) return decContextSetStatusQuiet(context, DEC_Overflow); if (strcmp(string, DEC_Condition_PA)==0) return decContextSetStatusQuiet(context, DEC_Clamped); if (strcmp(string, DEC_Condition_RO)==0) return decContextSetStatusQuiet(context, DEC_Rounded); if (strcmp(string, DEC_Condition_SU)==0) return decContextSetStatusQuiet(context, DEC_Subnormal); if (strcmp(string, DEC_Condition_UN)==0) return decContextSetStatusQuiet(context, DEC_Underflow); if (strcmp(string, DEC_Condition_ZE)==0) return context; return NULL; // Multiple status, or unknown } // decContextSetStatusFromStringQuiet /* ------------------------------------------------------------------ */ /* decContextSetStatusQuiet -- set status without trap */ /* */ /* context is the context structure to be updated */ /* status is the DEC_ exception code */ /* returns the context structure */ /* */ /* No error is possible. */ /* ------------------------------------------------------------------ */ decContext * decContextSetStatusQuiet(decContext *context, uInt status) { context->status|=status; return context;} // decContextSetStatusQuiet /* ------------------------------------------------------------------ */ /* decContextStatusToString -- convert status flags to a string */ /* */ /* context is a context with valid status field */ /* */ /* returns a constant string describing the condition. If multiple */ /* (or no) flags are set, a generic constant message is returned. */ /* ------------------------------------------------------------------ */ const char *decContextStatusToString(const decContext *context) { Int status=context->status; // test the five IEEE first, as some of the others are ambiguous when // DECEXTFLAG=0 if (status==DEC_Invalid_operation ) return DEC_Condition_IO; if (status==DEC_Division_by_zero ) return DEC_Condition_DZ; if (status==DEC_Overflow ) return DEC_Condition_OV; if (status==DEC_Underflow ) return DEC_Condition_UN; if (status==DEC_Inexact ) return DEC_Condition_IE; if (status==DEC_Division_impossible ) return DEC_Condition_DI; if (status==DEC_Division_undefined ) return DEC_Condition_DU; if (status==DEC_Rounded ) return DEC_Condition_RO; if (status==DEC_Clamped ) return DEC_Condition_PA; if (status==DEC_Subnormal ) return DEC_Condition_SU; if (status==DEC_Conversion_syntax ) return DEC_Condition_CS; if (status==DEC_Insufficient_storage ) return DEC_Condition_IS; if (status==DEC_Invalid_context ) return DEC_Condition_IC; #if DECSUBSET if (status==DEC_Lost_digits ) return DEC_Condition_LD; #endif if (status==0 ) return DEC_Condition_ZE; return DEC_Condition_MU; // Multiple errors } // decContextStatusToString /* ------------------------------------------------------------------ */ /* decContextTestEndian -- test whether DECLITEND is set correctly */ /* */ /* quiet is 1 to suppress message; 0 otherwise */ /* returns 0 if DECLITEND is correct */ /* 1 if DECLITEND is incorrect and should be 1 */ /* -1 if DECLITEND is incorrect and should be 0 */ /* */ /* A message is displayed if the return value is not 0 and quiet==0. */ /* */ /* No error is possible. */ /* ------------------------------------------------------------------ */ Int decContextTestEndian(Flag quiet) { Int res=0; // optimist uInt dle=(uInt)DECLITEND; // unsign if (dle>1) dle=1; // ensure 0 or 1 if (LITEND!=DECLITEND) { if (!quiet) { // always refer to this #if DECPRINT const char *adj; if (LITEND) adj="little"; else adj="big"; printf("Warning: DECLITEND is set to %d, but this computer appears to be %s-endian\n", DECLITEND, adj); #endif } res=(Int)LITEND-dle; } return res; } // decContextTestEndian /* ------------------------------------------------------------------ */ /* decContextTestSavedStatus -- test bits in saved status */ /* */ /* oldstatus is the status word to be tested */ /* mask indicates the bits to be tested (the oldstatus bits that */ /* correspond to each 1 bit in the mask are tested) */ /* returns 1 if any of the tested bits are 1, or 0 otherwise */ /* */ /* No error is possible. */ /* ------------------------------------------------------------------ */ uInt decContextTestSavedStatus(uInt oldstatus, uInt mask) { return (oldstatus&mask)!=0; } // decContextTestSavedStatus /* ------------------------------------------------------------------ */ /* decContextTestStatus -- test bits in current status */ /* */ /* context is the context structure to be updated */ /* mask indicates the bits to be tested (the status bits that */ /* correspond to each 1 bit in the mask are tested) */ /* returns 1 if any of the tested bits are 1, or 0 otherwise */ /* */ /* No error is possible. */ /* ------------------------------------------------------------------ */ uInt decContextTestStatus(decContext *context, uInt mask) { return (context->status&mask)!=0; } // decContextTestStatus /* ------------------------------------------------------------------ */ /* decContextZeroStatus -- clear all status bits */ /* */ /* context is the context structure to be updated */ /* returns context */ /* */ /* No error is possible. */ /* ------------------------------------------------------------------ */ decContext *decContextZeroStatus(decContext *context) { context->status=0; return context; } // decContextZeroStatus ================================================ FILE: vendor/decNumber/decContext.h ================================================ /* ------------------------------------------------------------------ */ /* Decimal Context module header */ /* ------------------------------------------------------------------ */ /* Copyright (c) IBM Corporation, 2000, 2010. All rights reserved. */ /* */ /* This software is made available under the terms of the */ /* ICU License -- ICU 1.8.1 and later. */ /* */ /* The description and User's Guide ("The decNumber C Library") for */ /* this software is called decNumber.pdf. This document is */ /* available, together with arithmetic and format specifications, */ /* testcases, and Web links, on the General Decimal Arithmetic page. */ /* */ /* Please send comments, suggestions, and corrections to the author: */ /* mfc@uk.ibm.com */ /* Mike Cowlishaw, IBM Fellow */ /* IBM UK, PO Box 31, Birmingham Road, Warwick CV34 5JL, UK */ /* ------------------------------------------------------------------ */ /* */ /* Context variables must always have valid values: */ /* */ /* status -- [any bits may be cleared, but not set, by user] */ /* round -- must be one of the enumerated rounding modes */ /* */ /* The following variables are implied for fixed size formats (i.e., */ /* they are ignored) but should still be set correctly in case used */ /* with decNumber functions: */ /* */ /* clamp -- must be either 0 or 1 */ /* digits -- must be in the range 1 through 999999999 */ /* emax -- must be in the range 0 through 999999999 */ /* emin -- must be in the range 0 through -999999999 */ /* extended -- must be either 0 or 1 [present only if DECSUBSET] */ /* traps -- only defined bits may be set */ /* */ /* ------------------------------------------------------------------ */ #if !defined(DECCONTEXT) #define DECCONTEXT #define DECCNAME "decContext" /* Short name */ #define DECCFULLNAME "Decimal Context Descriptor" /* Verbose name */ #define DECCAUTHOR "Mike Cowlishaw" /* Who to blame */ #if !defined(int32_t) #include /* C99 standard integers */ #endif #include /* for printf, etc. */ #include /* for traps */ /* Extended flags setting -- set this to 0 to use only IEEE flags */ #if !defined(DECEXTFLAG) #define DECEXTFLAG 1 /* 1=enable extended flags */ #endif /* Conditional code flag -- set this to 0 for best performance */ #if !defined(DECSUBSET) #define DECSUBSET 0 /* 1=enable subset arithmetic */ #endif /* Context for operations, with associated constants */ enum rounding { DEC_ROUND_CEILING, /* round towards +infinity */ DEC_ROUND_UP, /* round away from 0 */ DEC_ROUND_HALF_UP, /* 0.5 rounds up */ DEC_ROUND_HALF_EVEN, /* 0.5 rounds to nearest even */ DEC_ROUND_HALF_DOWN, /* 0.5 rounds down */ DEC_ROUND_DOWN, /* round towards 0 (truncate) */ DEC_ROUND_FLOOR, /* round towards -infinity */ DEC_ROUND_05UP, /* round for reround */ DEC_ROUND_MAX /* enum must be less than this */ }; #define DEC_ROUND_DEFAULT DEC_ROUND_HALF_EVEN; typedef struct { int32_t digits; /* working precision */ int32_t emax; /* maximum positive exponent */ int32_t emin; /* minimum negative exponent */ enum rounding round; /* rounding mode */ uint32_t traps; /* trap-enabler flags */ uint32_t status; /* status flags */ uint8_t clamp; /* flag: apply IEEE exponent clamp */ #if DECSUBSET uint8_t extended; /* flag: special-values allowed */ #endif } decContext; /* Maxima and Minima for context settings */ #define DEC_MAX_DIGITS 999999999 #define DEC_MIN_DIGITS 1 #define DEC_MAX_EMAX 999999999 #define DEC_MIN_EMAX 0 #define DEC_MAX_EMIN 0 #define DEC_MIN_EMIN -999999999 #define DEC_MAX_MATH 999999 /* max emax, etc., for math funcs. */ /* Classifications for decimal numbers, aligned with 754 (note that */ /* 'normal' and 'subnormal' are meaningful only with a decContext */ /* or a fixed size format). */ enum decClass { DEC_CLASS_SNAN, DEC_CLASS_QNAN, DEC_CLASS_NEG_INF, DEC_CLASS_NEG_NORMAL, DEC_CLASS_NEG_SUBNORMAL, DEC_CLASS_NEG_ZERO, DEC_CLASS_POS_ZERO, DEC_CLASS_POS_SUBNORMAL, DEC_CLASS_POS_NORMAL, DEC_CLASS_POS_INF }; /* Strings for the decClasses */ #define DEC_ClassString_SN "sNaN" #define DEC_ClassString_QN "NaN" #define DEC_ClassString_NI "-Infinity" #define DEC_ClassString_NN "-Normal" #define DEC_ClassString_NS "-Subnormal" #define DEC_ClassString_NZ "-Zero" #define DEC_ClassString_PZ "+Zero" #define DEC_ClassString_PS "+Subnormal" #define DEC_ClassString_PN "+Normal" #define DEC_ClassString_PI "+Infinity" #define DEC_ClassString_UN "Invalid" /* Trap-enabler and Status flags (exceptional conditions), and */ /* their names. The top byte is reserved for internal use */ #if DECEXTFLAG /* Extended flags */ #define DEC_Conversion_syntax 0x00000001 #define DEC_Division_by_zero 0x00000002 #define DEC_Division_impossible 0x00000004 #define DEC_Division_undefined 0x00000008 #define DEC_Insufficient_storage 0x00000010 /* [when malloc fails] */ #define DEC_Inexact 0x00000020 #define DEC_Invalid_context 0x00000040 #define DEC_Invalid_operation 0x00000080 #if DECSUBSET #define DEC_Lost_digits 0x00000100 #endif #define DEC_Overflow 0x00000200 #define DEC_Clamped 0x00000400 #define DEC_Rounded 0x00000800 #define DEC_Subnormal 0x00001000 #define DEC_Underflow 0x00002000 #else /* IEEE flags only */ #define DEC_Conversion_syntax 0x00000010 #define DEC_Division_by_zero 0x00000002 #define DEC_Division_impossible 0x00000010 #define DEC_Division_undefined 0x00000010 #define DEC_Insufficient_storage 0x00000010 /* [when malloc fails] */ #define DEC_Inexact 0x00000001 #define DEC_Invalid_context 0x00000010 #define DEC_Invalid_operation 0x00000010 #if DECSUBSET #define DEC_Lost_digits 0x00000000 #endif #define DEC_Overflow 0x00000008 #define DEC_Clamped 0x00000000 #define DEC_Rounded 0x00000000 #define DEC_Subnormal 0x00000000 #define DEC_Underflow 0x00000004 #endif /* IEEE 754 groupings for the flags */ /* [DEC_Clamped, DEC_Lost_digits, DEC_Rounded, and DEC_Subnormal */ /* are not in IEEE 754] */ #define DEC_IEEE_754_Division_by_zero (DEC_Division_by_zero) #if DECSUBSET #define DEC_IEEE_754_Inexact (DEC_Inexact | DEC_Lost_digits) #else #define DEC_IEEE_754_Inexact (DEC_Inexact) #endif #define DEC_IEEE_754_Invalid_operation (DEC_Conversion_syntax | \ DEC_Division_impossible | \ DEC_Division_undefined | \ DEC_Insufficient_storage | \ DEC_Invalid_context | \ DEC_Invalid_operation) #define DEC_IEEE_754_Overflow (DEC_Overflow) #define DEC_IEEE_754_Underflow (DEC_Underflow) /* flags which are normally errors (result is qNaN, infinite, or 0) */ #define DEC_Errors (DEC_IEEE_754_Division_by_zero | \ DEC_IEEE_754_Invalid_operation | \ DEC_IEEE_754_Overflow | DEC_IEEE_754_Underflow) /* flags which cause a result to become qNaN */ #define DEC_NaNs DEC_IEEE_754_Invalid_operation /* flags which are normally for information only (finite results) */ #if DECSUBSET #define DEC_Information (DEC_Clamped | DEC_Rounded | DEC_Inexact \ | DEC_Lost_digits) #else #define DEC_Information (DEC_Clamped | DEC_Rounded | DEC_Inexact) #endif /* IEEE 854 names (for compatibility with older decNumber versions) */ #define DEC_IEEE_854_Division_by_zero DEC_IEEE_754_Division_by_zero #define DEC_IEEE_854_Inexact DEC_IEEE_754_Inexact #define DEC_IEEE_854_Invalid_operation DEC_IEEE_754_Invalid_operation #define DEC_IEEE_854_Overflow DEC_IEEE_754_Overflow #define DEC_IEEE_854_Underflow DEC_IEEE_754_Underflow /* Name strings for the exceptional conditions */ #define DEC_Condition_CS "Conversion syntax" #define DEC_Condition_DZ "Division by zero" #define DEC_Condition_DI "Division impossible" #define DEC_Condition_DU "Division undefined" #define DEC_Condition_IE "Inexact" #define DEC_Condition_IS "Insufficient storage" #define DEC_Condition_IC "Invalid context" #define DEC_Condition_IO "Invalid operation" #if DECSUBSET #define DEC_Condition_LD "Lost digits" #endif #define DEC_Condition_OV "Overflow" #define DEC_Condition_PA "Clamped" #define DEC_Condition_RO "Rounded" #define DEC_Condition_SU "Subnormal" #define DEC_Condition_UN "Underflow" #define DEC_Condition_ZE "No status" #define DEC_Condition_MU "Multiple status" #define DEC_Condition_Length 21 /* length of the longest string, */ /* including terminator */ /* Initialization descriptors, used by decContextDefault */ #define DEC_INIT_BASE 0 #define DEC_INIT_DECIMAL32 32 #define DEC_INIT_DECIMAL64 64 #define DEC_INIT_DECIMAL128 128 /* Synonyms */ #define DEC_INIT_DECSINGLE DEC_INIT_DECIMAL32 #define DEC_INIT_DECDOUBLE DEC_INIT_DECIMAL64 #define DEC_INIT_DECQUAD DEC_INIT_DECIMAL128 /* decContext routines */ extern decContext * decContextClearStatus(decContext *, uint32_t); extern decContext * decContextDefault(decContext *, int32_t); extern enum rounding decContextGetRounding(decContext *); extern uint32_t decContextGetStatus(decContext *); extern decContext * decContextRestoreStatus(decContext *, uint32_t, uint32_t); extern uint32_t decContextSaveStatus(decContext *, uint32_t); extern decContext * decContextSetRounding(decContext *, enum rounding); extern decContext * decContextSetStatus(decContext *, uint32_t); extern decContext * decContextSetStatusFromString(decContext *, const char *); extern decContext * decContextSetStatusFromStringQuiet(decContext *, const char *); extern decContext * decContextSetStatusQuiet(decContext *, uint32_t); extern const char * decContextStatusToString(const decContext *); extern int32_t decContextTestEndian(uint8_t); extern uint32_t decContextTestSavedStatus(uint32_t, uint32_t); extern uint32_t decContextTestStatus(decContext *, uint32_t); extern decContext * decContextZeroStatus(decContext *); #endif ================================================ FILE: vendor/decNumber/decDPD.h ================================================ /* ------------------------------------------------------------------------ */ /* Binary Coded Decimal and Densely Packed Decimal conversion lookup tables */ /* [Automatically generated -- do not edit. 2008.06.21] */ /* ------------------------------------------------------------------------ */ /* Copyright (c) IBM Corporation, 2000, 2008. All rights reserved. */ /* ------------------------------------------------------------------------ */ /* For details, see DPDecimal.html on the General Decimal Arithmetic page. */ /* */ /* This include file defines several DPD and BCD conversion tables: */ /* */ /* uint16_t BCD2DPD[2458]; -- BCD -> DPD (0x999 => 2457) */ /* uint16_t BIN2DPD[1000]; -- Bin -> DPD (999 => 2457) */ /* uint8_t BIN2CHAR[4001]; -- Bin -> CHAR (999 => '\3' '9' '9' '9') */ /* uint8_t BIN2BCD8[4000]; -- Bin -> bytes (999 => 9 9 9 3) */ /* uint16_t DPD2BCD[1024]; -- DPD -> BCD (0x3FF => 0x999) */ /* uint16_t DPD2BIN[1024]; -- DPD -> BIN (0x3FF => 999) */ /* uint32_t DPD2BINK[1024]; -- DPD -> BIN * 1000 (0x3FF => 999000) */ /* uint32_t DPD2BINM[1024]; -- DPD -> BIN * 1E+6 (0x3FF => 999000000) */ /* uint8_t DPD2BCD8[4096]; -- DPD -> bytes (x3FF => 9 9 9 3) */ /* */ /* In all cases the result (10 bits or 12 bits, or binary) is right-aligned */ /* in the table entry. BIN2CHAR entries are a single byte length (0 for */ /* value 0) followed by three digit characters; a trailing terminator is */ /* included to allow 4-char moves always. BIN2BCD8 and DPD2BCD8 entries */ /* are similar with the three BCD8 digits followed by a one-byte length */ /* (again, length=0 for value 0). */ /* */ /* To use a table, its name, prefixed with DEC_, must be defined with a */ /* value of 1 before this header file is included. For example: */ /* #define DEC_BCD2DPD 1 */ /* This mechanism allows software to only include tables that are needed. */ /* ------------------------------------------------------------------------ */ #if defined(DEC_BCD2DPD) && DEC_BCD2DPD==1 && !defined(DECBCD2DPD) #define DECBCD2DPD const uint16_t BCD2DPD[2458]={ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 0, 0, 0, 0, 0, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 0, 0, 0, 0, 0, 0, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 0, 0, 0, 0, 0, 0, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 0, 0, 0, 0, 0, 0, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 0, 0, 0, 0, 0, 0, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 0, 0, 0, 0, 0, 0, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 0, 0, 0, 0, 0, 0, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 0, 0, 0, 0, 0, 0, 10, 11, 42, 43, 74, 75, 106, 107, 78, 79, 0, 0, 0, 0, 0, 0, 26, 27, 58, 59, 90, 91, 122, 123, 94, 95, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 0, 0, 0, 0, 0, 0, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 0, 0, 0, 0, 0, 0, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 0, 0, 0, 0, 0, 0, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 0, 0, 0, 0, 0, 0, 192, 193, 194, 195, 196, 197, 198, 199, 200, 201, 0, 0, 0, 0, 0, 0, 208, 209, 210, 211, 212, 213, 214, 215, 216, 217, 0, 0, 0, 0, 0, 0, 224, 225, 226, 227, 228, 229, 230, 231, 232, 233, 0, 0, 0, 0, 0, 0, 240, 241, 242, 243, 244, 245, 246, 247, 248, 249, 0, 0, 0, 0, 0, 0, 138, 139, 170, 171, 202, 203, 234, 235, 206, 207, 0, 0, 0, 0, 0, 0, 154, 155, 186, 187, 218, 219, 250, 251, 222, 223, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 256, 257, 258, 259, 260, 261, 262, 263, 264, 265, 0, 0, 0, 0, 0, 0, 272, 273, 274, 275, 276, 277, 278, 279, 280, 281, 0, 0, 0, 0, 0, 0, 288, 289, 290, 291, 292, 293, 294, 295, 296, 297, 0, 0, 0, 0, 0, 0, 304, 305, 306, 307, 308, 309, 310, 311, 312, 313, 0, 0, 0, 0, 0, 0, 320, 321, 322, 323, 324, 325, 326, 327, 328, 329, 0, 0, 0, 0, 0, 0, 336, 337, 338, 339, 340, 341, 342, 343, 344, 345, 0, 0, 0, 0, 0, 0, 352, 353, 354, 355, 356, 357, 358, 359, 360, 361, 0, 0, 0, 0, 0, 0, 368, 369, 370, 371, 372, 373, 374, 375, 376, 377, 0, 0, 0, 0, 0, 0, 266, 267, 298, 299, 330, 331, 362, 363, 334, 335, 0, 0, 0, 0, 0, 0, 282, 283, 314, 315, 346, 347, 378, 379, 350, 351, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 384, 385, 386, 387, 388, 389, 390, 391, 392, 393, 0, 0, 0, 0, 0, 0, 400, 401, 402, 403, 404, 405, 406, 407, 408, 409, 0, 0, 0, 0, 0, 0, 416, 417, 418, 419, 420, 421, 422, 423, 424, 425, 0, 0, 0, 0, 0, 0, 432, 433, 434, 435, 436, 437, 438, 439, 440, 441, 0, 0, 0, 0, 0, 0, 448, 449, 450, 451, 452, 453, 454, 455, 456, 457, 0, 0, 0, 0, 0, 0, 464, 465, 466, 467, 468, 469, 470, 471, 472, 473, 0, 0, 0, 0, 0, 0, 480, 481, 482, 483, 484, 485, 486, 487, 488, 489, 0, 0, 0, 0, 0, 0, 496, 497, 498, 499, 500, 501, 502, 503, 504, 505, 0, 0, 0, 0, 0, 0, 394, 395, 426, 427, 458, 459, 490, 491, 462, 463, 0, 0, 0, 0, 0, 0, 410, 411, 442, 443, 474, 475, 506, 507, 478, 479, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 512, 513, 514, 515, 516, 517, 518, 519, 520, 521, 0, 0, 0, 0, 0, 0, 528, 529, 530, 531, 532, 533, 534, 535, 536, 537, 0, 0, 0, 0, 0, 0, 544, 545, 546, 547, 548, 549, 550, 551, 552, 553, 0, 0, 0, 0, 0, 0, 560, 561, 562, 563, 564, 565, 566, 567, 568, 569, 0, 0, 0, 0, 0, 0, 576, 577, 578, 579, 580, 581, 582, 583, 584, 585, 0, 0, 0, 0, 0, 0, 592, 593, 594, 595, 596, 597, 598, 599, 600, 601, 0, 0, 0, 0, 0, 0, 608, 609, 610, 611, 612, 613, 614, 615, 616, 617, 0, 0, 0, 0, 0, 0, 624, 625, 626, 627, 628, 629, 630, 631, 632, 633, 0, 0, 0, 0, 0, 0, 522, 523, 554, 555, 586, 587, 618, 619, 590, 591, 0, 0, 0, 0, 0, 0, 538, 539, 570, 571, 602, 603, 634, 635, 606, 607, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 640, 641, 642, 643, 644, 645, 646, 647, 648, 649, 0, 0, 0, 0, 0, 0, 656, 657, 658, 659, 660, 661, 662, 663, 664, 665, 0, 0, 0, 0, 0, 0, 672, 673, 674, 675, 676, 677, 678, 679, 680, 681, 0, 0, 0, 0, 0, 0, 688, 689, 690, 691, 692, 693, 694, 695, 696, 697, 0, 0, 0, 0, 0, 0, 704, 705, 706, 707, 708, 709, 710, 711, 712, 713, 0, 0, 0, 0, 0, 0, 720, 721, 722, 723, 724, 725, 726, 727, 728, 729, 0, 0, 0, 0, 0, 0, 736, 737, 738, 739, 740, 741, 742, 743, 744, 745, 0, 0, 0, 0, 0, 0, 752, 753, 754, 755, 756, 757, 758, 759, 760, 761, 0, 0, 0, 0, 0, 0, 650, 651, 682, 683, 714, 715, 746, 747, 718, 719, 0, 0, 0, 0, 0, 0, 666, 667, 698, 699, 730, 731, 762, 763, 734, 735, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 768, 769, 770, 771, 772, 773, 774, 775, 776, 777, 0, 0, 0, 0, 0, 0, 784, 785, 786, 787, 788, 789, 790, 791, 792, 793, 0, 0, 0, 0, 0, 0, 800, 801, 802, 803, 804, 805, 806, 807, 808, 809, 0, 0, 0, 0, 0, 0, 816, 817, 818, 819, 820, 821, 822, 823, 824, 825, 0, 0, 0, 0, 0, 0, 832, 833, 834, 835, 836, 837, 838, 839, 840, 841, 0, 0, 0, 0, 0, 0, 848, 849, 850, 851, 852, 853, 854, 855, 856, 857, 0, 0, 0, 0, 0, 0, 864, 865, 866, 867, 868, 869, 870, 871, 872, 873, 0, 0, 0, 0, 0, 0, 880, 881, 882, 883, 884, 885, 886, 887, 888, 889, 0, 0, 0, 0, 0, 0, 778, 779, 810, 811, 842, 843, 874, 875, 846, 847, 0, 0, 0, 0, 0, 0, 794, 795, 826, 827, 858, 859, 890, 891, 862, 863, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 896, 897, 898, 899, 900, 901, 902, 903, 904, 905, 0, 0, 0, 0, 0, 0, 912, 913, 914, 915, 916, 917, 918, 919, 920, 921, 0, 0, 0, 0, 0, 0, 928, 929, 930, 931, 932, 933, 934, 935, 936, 937, 0, 0, 0, 0, 0, 0, 944, 945, 946, 947, 948, 949, 950, 951, 952, 953, 0, 0, 0, 0, 0, 0, 960, 961, 962, 963, 964, 965, 966, 967, 968, 969, 0, 0, 0, 0, 0, 0, 976, 977, 978, 979, 980, 981, 982, 983, 984, 985, 0, 0, 0, 0, 0, 0, 992, 993, 994, 995, 996, 997, 998, 999, 1000, 1001, 0, 0, 0, 0, 0, 0, 1008, 1009, 1010, 1011, 1012, 1013, 1014, 1015, 1016, 1017, 0, 0, 0, 0, 0, 0, 906, 907, 938, 939, 970, 971, 1002, 1003, 974, 975, 0, 0, 0, 0, 0, 0, 922, 923, 954, 955, 986, 987, 1018, 1019, 990, 991, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 12, 13, 268, 269, 524, 525, 780, 781, 46, 47, 0, 0, 0, 0, 0, 0, 28, 29, 284, 285, 540, 541, 796, 797, 62, 63, 0, 0, 0, 0, 0, 0, 44, 45, 300, 301, 556, 557, 812, 813, 302, 303, 0, 0, 0, 0, 0, 0, 60, 61, 316, 317, 572, 573, 828, 829, 318, 319, 0, 0, 0, 0, 0, 0, 76, 77, 332, 333, 588, 589, 844, 845, 558, 559, 0, 0, 0, 0, 0, 0, 92, 93, 348, 349, 604, 605, 860, 861, 574, 575, 0, 0, 0, 0, 0, 0, 108, 109, 364, 365, 620, 621, 876, 877, 814, 815, 0, 0, 0, 0, 0, 0, 124, 125, 380, 381, 636, 637, 892, 893, 830, 831, 0, 0, 0, 0, 0, 0, 14, 15, 270, 271, 526, 527, 782, 783, 110, 111, 0, 0, 0, 0, 0, 0, 30, 31, 286, 287, 542, 543, 798, 799, 126, 127, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 140, 141, 396, 397, 652, 653, 908, 909, 174, 175, 0, 0, 0, 0, 0, 0, 156, 157, 412, 413, 668, 669, 924, 925, 190, 191, 0, 0, 0, 0, 0, 0, 172, 173, 428, 429, 684, 685, 940, 941, 430, 431, 0, 0, 0, 0, 0, 0, 188, 189, 444, 445, 700, 701, 956, 957, 446, 447, 0, 0, 0, 0, 0, 0, 204, 205, 460, 461, 716, 717, 972, 973, 686, 687, 0, 0, 0, 0, 0, 0, 220, 221, 476, 477, 732, 733, 988, 989, 702, 703, 0, 0, 0, 0, 0, 0, 236, 237, 492, 493, 748, 749, 1004, 1005, 942, 943, 0, 0, 0, 0, 0, 0, 252, 253, 508, 509, 764, 765, 1020, 1021, 958, 959, 0, 0, 0, 0, 0, 0, 142, 143, 398, 399, 654, 655, 910, 911, 238, 239, 0, 0, 0, 0, 0, 0, 158, 159, 414, 415, 670, 671, 926, 927, 254, 255}; #endif #if defined(DEC_DPD2BCD) && DEC_DPD2BCD==1 && !defined(DECDPD2BCD) #define DECDPD2BCD const uint16_t DPD2BCD[1024]={ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 128, 129, 2048, 2049, 2176, 2177, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 144, 145, 2064, 2065, 2192, 2193, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 130, 131, 2080, 2081, 2056, 2057, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 146, 147, 2096, 2097, 2072, 2073, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 132, 133, 2112, 2113, 136, 137, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 148, 149, 2128, 2129, 152, 153, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 134, 135, 2144, 2145, 2184, 2185, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 150, 151, 2160, 2161, 2200, 2201, 256, 257, 258, 259, 260, 261, 262, 263, 264, 265, 384, 385, 2304, 2305, 2432, 2433, 272, 273, 274, 275, 276, 277, 278, 279, 280, 281, 400, 401, 2320, 2321, 2448, 2449, 288, 289, 290, 291, 292, 293, 294, 295, 296, 297, 386, 387, 2336, 2337, 2312, 2313, 304, 305, 306, 307, 308, 309, 310, 311, 312, 313, 402, 403, 2352, 2353, 2328, 2329, 320, 321, 322, 323, 324, 325, 326, 327, 328, 329, 388, 389, 2368, 2369, 392, 393, 336, 337, 338, 339, 340, 341, 342, 343, 344, 345, 404, 405, 2384, 2385, 408, 409, 352, 353, 354, 355, 356, 357, 358, 359, 360, 361, 390, 391, 2400, 2401, 2440, 2441, 368, 369, 370, 371, 372, 373, 374, 375, 376, 377, 406, 407, 2416, 2417, 2456, 2457, 512, 513, 514, 515, 516, 517, 518, 519, 520, 521, 640, 641, 2050, 2051, 2178, 2179, 528, 529, 530, 531, 532, 533, 534, 535, 536, 537, 656, 657, 2066, 2067, 2194, 2195, 544, 545, 546, 547, 548, 549, 550, 551, 552, 553, 642, 643, 2082, 2083, 2088, 2089, 560, 561, 562, 563, 564, 565, 566, 567, 568, 569, 658, 659, 2098, 2099, 2104, 2105, 576, 577, 578, 579, 580, 581, 582, 583, 584, 585, 644, 645, 2114, 2115, 648, 649, 592, 593, 594, 595, 596, 597, 598, 599, 600, 601, 660, 661, 2130, 2131, 664, 665, 608, 609, 610, 611, 612, 613, 614, 615, 616, 617, 646, 647, 2146, 2147, 2184, 2185, 624, 625, 626, 627, 628, 629, 630, 631, 632, 633, 662, 663, 2162, 2163, 2200, 2201, 768, 769, 770, 771, 772, 773, 774, 775, 776, 777, 896, 897, 2306, 2307, 2434, 2435, 784, 785, 786, 787, 788, 789, 790, 791, 792, 793, 912, 913, 2322, 2323, 2450, 2451, 800, 801, 802, 803, 804, 805, 806, 807, 808, 809, 898, 899, 2338, 2339, 2344, 2345, 816, 817, 818, 819, 820, 821, 822, 823, 824, 825, 914, 915, 2354, 2355, 2360, 2361, 832, 833, 834, 835, 836, 837, 838, 839, 840, 841, 900, 901, 2370, 2371, 904, 905, 848, 849, 850, 851, 852, 853, 854, 855, 856, 857, 916, 917, 2386, 2387, 920, 921, 864, 865, 866, 867, 868, 869, 870, 871, 872, 873, 902, 903, 2402, 2403, 2440, 2441, 880, 881, 882, 883, 884, 885, 886, 887, 888, 889, 918, 919, 2418, 2419, 2456, 2457, 1024, 1025, 1026, 1027, 1028, 1029, 1030, 1031, 1032, 1033, 1152, 1153, 2052, 2053, 2180, 2181, 1040, 1041, 1042, 1043, 1044, 1045, 1046, 1047, 1048, 1049, 1168, 1169, 2068, 2069, 2196, 2197, 1056, 1057, 1058, 1059, 1060, 1061, 1062, 1063, 1064, 1065, 1154, 1155, 2084, 2085, 2120, 2121, 1072, 1073, 1074, 1075, 1076, 1077, 1078, 1079, 1080, 1081, 1170, 1171, 2100, 2101, 2136, 2137, 1088, 1089, 1090, 1091, 1092, 1093, 1094, 1095, 1096, 1097, 1156, 1157, 2116, 2117, 1160, 1161, 1104, 1105, 1106, 1107, 1108, 1109, 1110, 1111, 1112, 1113, 1172, 1173, 2132, 2133, 1176, 1177, 1120, 1121, 1122, 1123, 1124, 1125, 1126, 1127, 1128, 1129, 1158, 1159, 2148, 2149, 2184, 2185, 1136, 1137, 1138, 1139, 1140, 1141, 1142, 1143, 1144, 1145, 1174, 1175, 2164, 2165, 2200, 2201, 1280, 1281, 1282, 1283, 1284, 1285, 1286, 1287, 1288, 1289, 1408, 1409, 2308, 2309, 2436, 2437, 1296, 1297, 1298, 1299, 1300, 1301, 1302, 1303, 1304, 1305, 1424, 1425, 2324, 2325, 2452, 2453, 1312, 1313, 1314, 1315, 1316, 1317, 1318, 1319, 1320, 1321, 1410, 1411, 2340, 2341, 2376, 2377, 1328, 1329, 1330, 1331, 1332, 1333, 1334, 1335, 1336, 1337, 1426, 1427, 2356, 2357, 2392, 2393, 1344, 1345, 1346, 1347, 1348, 1349, 1350, 1351, 1352, 1353, 1412, 1413, 2372, 2373, 1416, 1417, 1360, 1361, 1362, 1363, 1364, 1365, 1366, 1367, 1368, 1369, 1428, 1429, 2388, 2389, 1432, 1433, 1376, 1377, 1378, 1379, 1380, 1381, 1382, 1383, 1384, 1385, 1414, 1415, 2404, 2405, 2440, 2441, 1392, 1393, 1394, 1395, 1396, 1397, 1398, 1399, 1400, 1401, 1430, 1431, 2420, 2421, 2456, 2457, 1536, 1537, 1538, 1539, 1540, 1541, 1542, 1543, 1544, 1545, 1664, 1665, 2054, 2055, 2182, 2183, 1552, 1553, 1554, 1555, 1556, 1557, 1558, 1559, 1560, 1561, 1680, 1681, 2070, 2071, 2198, 2199, 1568, 1569, 1570, 1571, 1572, 1573, 1574, 1575, 1576, 1577, 1666, 1667, 2086, 2087, 2152, 2153, 1584, 1585, 1586, 1587, 1588, 1589, 1590, 1591, 1592, 1593, 1682, 1683, 2102, 2103, 2168, 2169, 1600, 1601, 1602, 1603, 1604, 1605, 1606, 1607, 1608, 1609, 1668, 1669, 2118, 2119, 1672, 1673, 1616, 1617, 1618, 1619, 1620, 1621, 1622, 1623, 1624, 1625, 1684, 1685, 2134, 2135, 1688, 1689, 1632, 1633, 1634, 1635, 1636, 1637, 1638, 1639, 1640, 1641, 1670, 1671, 2150, 2151, 2184, 2185, 1648, 1649, 1650, 1651, 1652, 1653, 1654, 1655, 1656, 1657, 1686, 1687, 2166, 2167, 2200, 2201, 1792, 1793, 1794, 1795, 1796, 1797, 1798, 1799, 1800, 1801, 1920, 1921, 2310, 2311, 2438, 2439, 1808, 1809, 1810, 1811, 1812, 1813, 1814, 1815, 1816, 1817, 1936, 1937, 2326, 2327, 2454, 2455, 1824, 1825, 1826, 1827, 1828, 1829, 1830, 1831, 1832, 1833, 1922, 1923, 2342, 2343, 2408, 2409, 1840, 1841, 1842, 1843, 1844, 1845, 1846, 1847, 1848, 1849, 1938, 1939, 2358, 2359, 2424, 2425, 1856, 1857, 1858, 1859, 1860, 1861, 1862, 1863, 1864, 1865, 1924, 1925, 2374, 2375, 1928, 1929, 1872, 1873, 1874, 1875, 1876, 1877, 1878, 1879, 1880, 1881, 1940, 1941, 2390, 2391, 1944, 1945, 1888, 1889, 1890, 1891, 1892, 1893, 1894, 1895, 1896, 1897, 1926, 1927, 2406, 2407, 2440, 2441, 1904, 1905, 1906, 1907, 1908, 1909, 1910, 1911, 1912, 1913, 1942, 1943, 2422, 2423, 2456, 2457}; #endif #if defined(DEC_BIN2DPD) && DEC_BIN2DPD==1 && !defined(DECBIN2DPD) #define DECBIN2DPD const uint16_t BIN2DPD[1000]={ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 10, 11, 42, 43, 74, 75, 106, 107, 78, 79, 26, 27, 58, 59, 90, 91, 122, 123, 94, 95, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 192, 193, 194, 195, 196, 197, 198, 199, 200, 201, 208, 209, 210, 211, 212, 213, 214, 215, 216, 217, 224, 225, 226, 227, 228, 229, 230, 231, 232, 233, 240, 241, 242, 243, 244, 245, 246, 247, 248, 249, 138, 139, 170, 171, 202, 203, 234, 235, 206, 207, 154, 155, 186, 187, 218, 219, 250, 251, 222, 223, 256, 257, 258, 259, 260, 261, 262, 263, 264, 265, 272, 273, 274, 275, 276, 277, 278, 279, 280, 281, 288, 289, 290, 291, 292, 293, 294, 295, 296, 297, 304, 305, 306, 307, 308, 309, 310, 311, 312, 313, 320, 321, 322, 323, 324, 325, 326, 327, 328, 329, 336, 337, 338, 339, 340, 341, 342, 343, 344, 345, 352, 353, 354, 355, 356, 357, 358, 359, 360, 361, 368, 369, 370, 371, 372, 373, 374, 375, 376, 377, 266, 267, 298, 299, 330, 331, 362, 363, 334, 335, 282, 283, 314, 315, 346, 347, 378, 379, 350, 351, 384, 385, 386, 387, 388, 389, 390, 391, 392, 393, 400, 401, 402, 403, 404, 405, 406, 407, 408, 409, 416, 417, 418, 419, 420, 421, 422, 423, 424, 425, 432, 433, 434, 435, 436, 437, 438, 439, 440, 441, 448, 449, 450, 451, 452, 453, 454, 455, 456, 457, 464, 465, 466, 467, 468, 469, 470, 471, 472, 473, 480, 481, 482, 483, 484, 485, 486, 487, 488, 489, 496, 497, 498, 499, 500, 501, 502, 503, 504, 505, 394, 395, 426, 427, 458, 459, 490, 491, 462, 463, 410, 411, 442, 443, 474, 475, 506, 507, 478, 479, 512, 513, 514, 515, 516, 517, 518, 519, 520, 521, 528, 529, 530, 531, 532, 533, 534, 535, 536, 537, 544, 545, 546, 547, 548, 549, 550, 551, 552, 553, 560, 561, 562, 563, 564, 565, 566, 567, 568, 569, 576, 577, 578, 579, 580, 581, 582, 583, 584, 585, 592, 593, 594, 595, 596, 597, 598, 599, 600, 601, 608, 609, 610, 611, 612, 613, 614, 615, 616, 617, 624, 625, 626, 627, 628, 629, 630, 631, 632, 633, 522, 523, 554, 555, 586, 587, 618, 619, 590, 591, 538, 539, 570, 571, 602, 603, 634, 635, 606, 607, 640, 641, 642, 643, 644, 645, 646, 647, 648, 649, 656, 657, 658, 659, 660, 661, 662, 663, 664, 665, 672, 673, 674, 675, 676, 677, 678, 679, 680, 681, 688, 689, 690, 691, 692, 693, 694, 695, 696, 697, 704, 705, 706, 707, 708, 709, 710, 711, 712, 713, 720, 721, 722, 723, 724, 725, 726, 727, 728, 729, 736, 737, 738, 739, 740, 741, 742, 743, 744, 745, 752, 753, 754, 755, 756, 757, 758, 759, 760, 761, 650, 651, 682, 683, 714, 715, 746, 747, 718, 719, 666, 667, 698, 699, 730, 731, 762, 763, 734, 735, 768, 769, 770, 771, 772, 773, 774, 775, 776, 777, 784, 785, 786, 787, 788, 789, 790, 791, 792, 793, 800, 801, 802, 803, 804, 805, 806, 807, 808, 809, 816, 817, 818, 819, 820, 821, 822, 823, 824, 825, 832, 833, 834, 835, 836, 837, 838, 839, 840, 841, 848, 849, 850, 851, 852, 853, 854, 855, 856, 857, 864, 865, 866, 867, 868, 869, 870, 871, 872, 873, 880, 881, 882, 883, 884, 885, 886, 887, 888, 889, 778, 779, 810, 811, 842, 843, 874, 875, 846, 847, 794, 795, 826, 827, 858, 859, 890, 891, 862, 863, 896, 897, 898, 899, 900, 901, 902, 903, 904, 905, 912, 913, 914, 915, 916, 917, 918, 919, 920, 921, 928, 929, 930, 931, 932, 933, 934, 935, 936, 937, 944, 945, 946, 947, 948, 949, 950, 951, 952, 953, 960, 961, 962, 963, 964, 965, 966, 967, 968, 969, 976, 977, 978, 979, 980, 981, 982, 983, 984, 985, 992, 993, 994, 995, 996, 997, 998, 999, 1000, 1001, 1008, 1009, 1010, 1011, 1012, 1013, 1014, 1015, 1016, 1017, 906, 907, 938, 939, 970, 971, 1002, 1003, 974, 975, 922, 923, 954, 955, 986, 987, 1018, 1019, 990, 991, 12, 13, 268, 269, 524, 525, 780, 781, 46, 47, 28, 29, 284, 285, 540, 541, 796, 797, 62, 63, 44, 45, 300, 301, 556, 557, 812, 813, 302, 303, 60, 61, 316, 317, 572, 573, 828, 829, 318, 319, 76, 77, 332, 333, 588, 589, 844, 845, 558, 559, 92, 93, 348, 349, 604, 605, 860, 861, 574, 575, 108, 109, 364, 365, 620, 621, 876, 877, 814, 815, 124, 125, 380, 381, 636, 637, 892, 893, 830, 831, 14, 15, 270, 271, 526, 527, 782, 783, 110, 111, 30, 31, 286, 287, 542, 543, 798, 799, 126, 127, 140, 141, 396, 397, 652, 653, 908, 909, 174, 175, 156, 157, 412, 413, 668, 669, 924, 925, 190, 191, 172, 173, 428, 429, 684, 685, 940, 941, 430, 431, 188, 189, 444, 445, 700, 701, 956, 957, 446, 447, 204, 205, 460, 461, 716, 717, 972, 973, 686, 687, 220, 221, 476, 477, 732, 733, 988, 989, 702, 703, 236, 237, 492, 493, 748, 749, 1004, 1005, 942, 943, 252, 253, 508, 509, 764, 765, 1020, 1021, 958, 959, 142, 143, 398, 399, 654, 655, 910, 911, 238, 239, 158, 159, 414, 415, 670, 671, 926, 927, 254, 255}; #endif #if defined(DEC_DPD2BIN) && DEC_DPD2BIN==1 && !defined(DECDPD2BIN) #define DECDPD2BIN const uint16_t DPD2BIN[1024]={ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 80, 81, 800, 801, 880, 881, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 90, 91, 810, 811, 890, 891, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 82, 83, 820, 821, 808, 809, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 92, 93, 830, 831, 818, 819, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 84, 85, 840, 841, 88, 89, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 94, 95, 850, 851, 98, 99, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 86, 87, 860, 861, 888, 889, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 96, 97, 870, 871, 898, 899, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 180, 181, 900, 901, 980, 981, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 190, 191, 910, 911, 990, 991, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 182, 183, 920, 921, 908, 909, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 192, 193, 930, 931, 918, 919, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 184, 185, 940, 941, 188, 189, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 194, 195, 950, 951, 198, 199, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 186, 187, 960, 961, 988, 989, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 196, 197, 970, 971, 998, 999, 200, 201, 202, 203, 204, 205, 206, 207, 208, 209, 280, 281, 802, 803, 882, 883, 210, 211, 212, 213, 214, 215, 216, 217, 218, 219, 290, 291, 812, 813, 892, 893, 220, 221, 222, 223, 224, 225, 226, 227, 228, 229, 282, 283, 822, 823, 828, 829, 230, 231, 232, 233, 234, 235, 236, 237, 238, 239, 292, 293, 832, 833, 838, 839, 240, 241, 242, 243, 244, 245, 246, 247, 248, 249, 284, 285, 842, 843, 288, 289, 250, 251, 252, 253, 254, 255, 256, 257, 258, 259, 294, 295, 852, 853, 298, 299, 260, 261, 262, 263, 264, 265, 266, 267, 268, 269, 286, 287, 862, 863, 888, 889, 270, 271, 272, 273, 274, 275, 276, 277, 278, 279, 296, 297, 872, 873, 898, 899, 300, 301, 302, 303, 304, 305, 306, 307, 308, 309, 380, 381, 902, 903, 982, 983, 310, 311, 312, 313, 314, 315, 316, 317, 318, 319, 390, 391, 912, 913, 992, 993, 320, 321, 322, 323, 324, 325, 326, 327, 328, 329, 382, 383, 922, 923, 928, 929, 330, 331, 332, 333, 334, 335, 336, 337, 338, 339, 392, 393, 932, 933, 938, 939, 340, 341, 342, 343, 344, 345, 346, 347, 348, 349, 384, 385, 942, 943, 388, 389, 350, 351, 352, 353, 354, 355, 356, 357, 358, 359, 394, 395, 952, 953, 398, 399, 360, 361, 362, 363, 364, 365, 366, 367, 368, 369, 386, 387, 962, 963, 988, 989, 370, 371, 372, 373, 374, 375, 376, 377, 378, 379, 396, 397, 972, 973, 998, 999, 400, 401, 402, 403, 404, 405, 406, 407, 408, 409, 480, 481, 804, 805, 884, 885, 410, 411, 412, 413, 414, 415, 416, 417, 418, 419, 490, 491, 814, 815, 894, 895, 420, 421, 422, 423, 424, 425, 426, 427, 428, 429, 482, 483, 824, 825, 848, 849, 430, 431, 432, 433, 434, 435, 436, 437, 438, 439, 492, 493, 834, 835, 858, 859, 440, 441, 442, 443, 444, 445, 446, 447, 448, 449, 484, 485, 844, 845, 488, 489, 450, 451, 452, 453, 454, 455, 456, 457, 458, 459, 494, 495, 854, 855, 498, 499, 460, 461, 462, 463, 464, 465, 466, 467, 468, 469, 486, 487, 864, 865, 888, 889, 470, 471, 472, 473, 474, 475, 476, 477, 478, 479, 496, 497, 874, 875, 898, 899, 500, 501, 502, 503, 504, 505, 506, 507, 508, 509, 580, 581, 904, 905, 984, 985, 510, 511, 512, 513, 514, 515, 516, 517, 518, 519, 590, 591, 914, 915, 994, 995, 520, 521, 522, 523, 524, 525, 526, 527, 528, 529, 582, 583, 924, 925, 948, 949, 530, 531, 532, 533, 534, 535, 536, 537, 538, 539, 592, 593, 934, 935, 958, 959, 540, 541, 542, 543, 544, 545, 546, 547, 548, 549, 584, 585, 944, 945, 588, 589, 550, 551, 552, 553, 554, 555, 556, 557, 558, 559, 594, 595, 954, 955, 598, 599, 560, 561, 562, 563, 564, 565, 566, 567, 568, 569, 586, 587, 964, 965, 988, 989, 570, 571, 572, 573, 574, 575, 576, 577, 578, 579, 596, 597, 974, 975, 998, 999, 600, 601, 602, 603, 604, 605, 606, 607, 608, 609, 680, 681, 806, 807, 886, 887, 610, 611, 612, 613, 614, 615, 616, 617, 618, 619, 690, 691, 816, 817, 896, 897, 620, 621, 622, 623, 624, 625, 626, 627, 628, 629, 682, 683, 826, 827, 868, 869, 630, 631, 632, 633, 634, 635, 636, 637, 638, 639, 692, 693, 836, 837, 878, 879, 640, 641, 642, 643, 644, 645, 646, 647, 648, 649, 684, 685, 846, 847, 688, 689, 650, 651, 652, 653, 654, 655, 656, 657, 658, 659, 694, 695, 856, 857, 698, 699, 660, 661, 662, 663, 664, 665, 666, 667, 668, 669, 686, 687, 866, 867, 888, 889, 670, 671, 672, 673, 674, 675, 676, 677, 678, 679, 696, 697, 876, 877, 898, 899, 700, 701, 702, 703, 704, 705, 706, 707, 708, 709, 780, 781, 906, 907, 986, 987, 710, 711, 712, 713, 714, 715, 716, 717, 718, 719, 790, 791, 916, 917, 996, 997, 720, 721, 722, 723, 724, 725, 726, 727, 728, 729, 782, 783, 926, 927, 968, 969, 730, 731, 732, 733, 734, 735, 736, 737, 738, 739, 792, 793, 936, 937, 978, 979, 740, 741, 742, 743, 744, 745, 746, 747, 748, 749, 784, 785, 946, 947, 788, 789, 750, 751, 752, 753, 754, 755, 756, 757, 758, 759, 794, 795, 956, 957, 798, 799, 760, 761, 762, 763, 764, 765, 766, 767, 768, 769, 786, 787, 966, 967, 988, 989, 770, 771, 772, 773, 774, 775, 776, 777, 778, 779, 796, 797, 976, 977, 998, 999}; #endif #if defined(DEC_DPD2BINK) && DEC_DPD2BINK==1 && !defined(DECDPD2BINK) #define DECDPD2BINK const uint32_t DPD2BINK[1024]={ 0, 1000, 2000, 3000, 4000, 5000, 6000, 7000, 8000, 9000, 80000, 81000, 800000, 801000, 880000, 881000, 10000, 11000, 12000, 13000, 14000, 15000, 16000, 17000, 18000, 19000, 90000, 91000, 810000, 811000, 890000, 891000, 20000, 21000, 22000, 23000, 24000, 25000, 26000, 27000, 28000, 29000, 82000, 83000, 820000, 821000, 808000, 809000, 30000, 31000, 32000, 33000, 34000, 35000, 36000, 37000, 38000, 39000, 92000, 93000, 830000, 831000, 818000, 819000, 40000, 41000, 42000, 43000, 44000, 45000, 46000, 47000, 48000, 49000, 84000, 85000, 840000, 841000, 88000, 89000, 50000, 51000, 52000, 53000, 54000, 55000, 56000, 57000, 58000, 59000, 94000, 95000, 850000, 851000, 98000, 99000, 60000, 61000, 62000, 63000, 64000, 65000, 66000, 67000, 68000, 69000, 86000, 87000, 860000, 861000, 888000, 889000, 70000, 71000, 72000, 73000, 74000, 75000, 76000, 77000, 78000, 79000, 96000, 97000, 870000, 871000, 898000, 899000, 100000, 101000, 102000, 103000, 104000, 105000, 106000, 107000, 108000, 109000, 180000, 181000, 900000, 901000, 980000, 981000, 110000, 111000, 112000, 113000, 114000, 115000, 116000, 117000, 118000, 119000, 190000, 191000, 910000, 911000, 990000, 991000, 120000, 121000, 122000, 123000, 124000, 125000, 126000, 127000, 128000, 129000, 182000, 183000, 920000, 921000, 908000, 909000, 130000, 131000, 132000, 133000, 134000, 135000, 136000, 137000, 138000, 139000, 192000, 193000, 930000, 931000, 918000, 919000, 140000, 141000, 142000, 143000, 144000, 145000, 146000, 147000, 148000, 149000, 184000, 185000, 940000, 941000, 188000, 189000, 150000, 151000, 152000, 153000, 154000, 155000, 156000, 157000, 158000, 159000, 194000, 195000, 950000, 951000, 198000, 199000, 160000, 161000, 162000, 163000, 164000, 165000, 166000, 167000, 168000, 169000, 186000, 187000, 960000, 961000, 988000, 989000, 170000, 171000, 172000, 173000, 174000, 175000, 176000, 177000, 178000, 179000, 196000, 197000, 970000, 971000, 998000, 999000, 200000, 201000, 202000, 203000, 204000, 205000, 206000, 207000, 208000, 209000, 280000, 281000, 802000, 803000, 882000, 883000, 210000, 211000, 212000, 213000, 214000, 215000, 216000, 217000, 218000, 219000, 290000, 291000, 812000, 813000, 892000, 893000, 220000, 221000, 222000, 223000, 224000, 225000, 226000, 227000, 228000, 229000, 282000, 283000, 822000, 823000, 828000, 829000, 230000, 231000, 232000, 233000, 234000, 235000, 236000, 237000, 238000, 239000, 292000, 293000, 832000, 833000, 838000, 839000, 240000, 241000, 242000, 243000, 244000, 245000, 246000, 247000, 248000, 249000, 284000, 285000, 842000, 843000, 288000, 289000, 250000, 251000, 252000, 253000, 254000, 255000, 256000, 257000, 258000, 259000, 294000, 295000, 852000, 853000, 298000, 299000, 260000, 261000, 262000, 263000, 264000, 265000, 266000, 267000, 268000, 269000, 286000, 287000, 862000, 863000, 888000, 889000, 270000, 271000, 272000, 273000, 274000, 275000, 276000, 277000, 278000, 279000, 296000, 297000, 872000, 873000, 898000, 899000, 300000, 301000, 302000, 303000, 304000, 305000, 306000, 307000, 308000, 309000, 380000, 381000, 902000, 903000, 982000, 983000, 310000, 311000, 312000, 313000, 314000, 315000, 316000, 317000, 318000, 319000, 390000, 391000, 912000, 913000, 992000, 993000, 320000, 321000, 322000, 323000, 324000, 325000, 326000, 327000, 328000, 329000, 382000, 383000, 922000, 923000, 928000, 929000, 330000, 331000, 332000, 333000, 334000, 335000, 336000, 337000, 338000, 339000, 392000, 393000, 932000, 933000, 938000, 939000, 340000, 341000, 342000, 343000, 344000, 345000, 346000, 347000, 348000, 349000, 384000, 385000, 942000, 943000, 388000, 389000, 350000, 351000, 352000, 353000, 354000, 355000, 356000, 357000, 358000, 359000, 394000, 395000, 952000, 953000, 398000, 399000, 360000, 361000, 362000, 363000, 364000, 365000, 366000, 367000, 368000, 369000, 386000, 387000, 962000, 963000, 988000, 989000, 370000, 371000, 372000, 373000, 374000, 375000, 376000, 377000, 378000, 379000, 396000, 397000, 972000, 973000, 998000, 999000, 400000, 401000, 402000, 403000, 404000, 405000, 406000, 407000, 408000, 409000, 480000, 481000, 804000, 805000, 884000, 885000, 410000, 411000, 412000, 413000, 414000, 415000, 416000, 417000, 418000, 419000, 490000, 491000, 814000, 815000, 894000, 895000, 420000, 421000, 422000, 423000, 424000, 425000, 426000, 427000, 428000, 429000, 482000, 483000, 824000, 825000, 848000, 849000, 430000, 431000, 432000, 433000, 434000, 435000, 436000, 437000, 438000, 439000, 492000, 493000, 834000, 835000, 858000, 859000, 440000, 441000, 442000, 443000, 444000, 445000, 446000, 447000, 448000, 449000, 484000, 485000, 844000, 845000, 488000, 489000, 450000, 451000, 452000, 453000, 454000, 455000, 456000, 457000, 458000, 459000, 494000, 495000, 854000, 855000, 498000, 499000, 460000, 461000, 462000, 463000, 464000, 465000, 466000, 467000, 468000, 469000, 486000, 487000, 864000, 865000, 888000, 889000, 470000, 471000, 472000, 473000, 474000, 475000, 476000, 477000, 478000, 479000, 496000, 497000, 874000, 875000, 898000, 899000, 500000, 501000, 502000, 503000, 504000, 505000, 506000, 507000, 508000, 509000, 580000, 581000, 904000, 905000, 984000, 985000, 510000, 511000, 512000, 513000, 514000, 515000, 516000, 517000, 518000, 519000, 590000, 591000, 914000, 915000, 994000, 995000, 520000, 521000, 522000, 523000, 524000, 525000, 526000, 527000, 528000, 529000, 582000, 583000, 924000, 925000, 948000, 949000, 530000, 531000, 532000, 533000, 534000, 535000, 536000, 537000, 538000, 539000, 592000, 593000, 934000, 935000, 958000, 959000, 540000, 541000, 542000, 543000, 544000, 545000, 546000, 547000, 548000, 549000, 584000, 585000, 944000, 945000, 588000, 589000, 550000, 551000, 552000, 553000, 554000, 555000, 556000, 557000, 558000, 559000, 594000, 595000, 954000, 955000, 598000, 599000, 560000, 561000, 562000, 563000, 564000, 565000, 566000, 567000, 568000, 569000, 586000, 587000, 964000, 965000, 988000, 989000, 570000, 571000, 572000, 573000, 574000, 575000, 576000, 577000, 578000, 579000, 596000, 597000, 974000, 975000, 998000, 999000, 600000, 601000, 602000, 603000, 604000, 605000, 606000, 607000, 608000, 609000, 680000, 681000, 806000, 807000, 886000, 887000, 610000, 611000, 612000, 613000, 614000, 615000, 616000, 617000, 618000, 619000, 690000, 691000, 816000, 817000, 896000, 897000, 620000, 621000, 622000, 623000, 624000, 625000, 626000, 627000, 628000, 629000, 682000, 683000, 826000, 827000, 868000, 869000, 630000, 631000, 632000, 633000, 634000, 635000, 636000, 637000, 638000, 639000, 692000, 693000, 836000, 837000, 878000, 879000, 640000, 641000, 642000, 643000, 644000, 645000, 646000, 647000, 648000, 649000, 684000, 685000, 846000, 847000, 688000, 689000, 650000, 651000, 652000, 653000, 654000, 655000, 656000, 657000, 658000, 659000, 694000, 695000, 856000, 857000, 698000, 699000, 660000, 661000, 662000, 663000, 664000, 665000, 666000, 667000, 668000, 669000, 686000, 687000, 866000, 867000, 888000, 889000, 670000, 671000, 672000, 673000, 674000, 675000, 676000, 677000, 678000, 679000, 696000, 697000, 876000, 877000, 898000, 899000, 700000, 701000, 702000, 703000, 704000, 705000, 706000, 707000, 708000, 709000, 780000, 781000, 906000, 907000, 986000, 987000, 710000, 711000, 712000, 713000, 714000, 715000, 716000, 717000, 718000, 719000, 790000, 791000, 916000, 917000, 996000, 997000, 720000, 721000, 722000, 723000, 724000, 725000, 726000, 727000, 728000, 729000, 782000, 783000, 926000, 927000, 968000, 969000, 730000, 731000, 732000, 733000, 734000, 735000, 736000, 737000, 738000, 739000, 792000, 793000, 936000, 937000, 978000, 979000, 740000, 741000, 742000, 743000, 744000, 745000, 746000, 747000, 748000, 749000, 784000, 785000, 946000, 947000, 788000, 789000, 750000, 751000, 752000, 753000, 754000, 755000, 756000, 757000, 758000, 759000, 794000, 795000, 956000, 957000, 798000, 799000, 760000, 761000, 762000, 763000, 764000, 765000, 766000, 767000, 768000, 769000, 786000, 787000, 966000, 967000, 988000, 989000, 770000, 771000, 772000, 773000, 774000, 775000, 776000, 777000, 778000, 779000, 796000, 797000, 976000, 977000, 998000, 999000}; #endif #if defined(DEC_DPD2BINM) && DEC_DPD2BINM==1 && !defined(DECDPD2BINM) #define DECDPD2BINM const uint32_t DPD2BINM[1024]={0, 1000000, 2000000, 3000000, 4000000, 5000000, 6000000, 7000000, 8000000, 9000000, 80000000, 81000000, 800000000, 801000000, 880000000, 881000000, 10000000, 11000000, 12000000, 13000000, 14000000, 15000000, 16000000, 17000000, 18000000, 19000000, 90000000, 91000000, 810000000, 811000000, 890000000, 891000000, 20000000, 21000000, 22000000, 23000000, 24000000, 25000000, 26000000, 27000000, 28000000, 29000000, 82000000, 83000000, 820000000, 821000000, 808000000, 809000000, 30000000, 31000000, 32000000, 33000000, 34000000, 35000000, 36000000, 37000000, 38000000, 39000000, 92000000, 93000000, 830000000, 831000000, 818000000, 819000000, 40000000, 41000000, 42000000, 43000000, 44000000, 45000000, 46000000, 47000000, 48000000, 49000000, 84000000, 85000000, 840000000, 841000000, 88000000, 89000000, 50000000, 51000000, 52000000, 53000000, 54000000, 55000000, 56000000, 57000000, 58000000, 59000000, 94000000, 95000000, 850000000, 851000000, 98000000, 99000000, 60000000, 61000000, 62000000, 63000000, 64000000, 65000000, 66000000, 67000000, 68000000, 69000000, 86000000, 87000000, 860000000, 861000000, 888000000, 889000000, 70000000, 71000000, 72000000, 73000000, 74000000, 75000000, 76000000, 77000000, 78000000, 79000000, 96000000, 97000000, 870000000, 871000000, 898000000, 899000000, 100000000, 101000000, 102000000, 103000000, 104000000, 105000000, 106000000, 107000000, 108000000, 109000000, 180000000, 181000000, 900000000, 901000000, 980000000, 981000000, 110000000, 111000000, 112000000, 113000000, 114000000, 115000000, 116000000, 117000000, 118000000, 119000000, 190000000, 191000000, 910000000, 911000000, 990000000, 991000000, 120000000, 121000000, 122000000, 123000000, 124000000, 125000000, 126000000, 127000000, 128000000, 129000000, 182000000, 183000000, 920000000, 921000000, 908000000, 909000000, 130000000, 131000000, 132000000, 133000000, 134000000, 135000000, 136000000, 137000000, 138000000, 139000000, 192000000, 193000000, 930000000, 931000000, 918000000, 919000000, 140000000, 141000000, 142000000, 143000000, 144000000, 145000000, 146000000, 147000000, 148000000, 149000000, 184000000, 185000000, 940000000, 941000000, 188000000, 189000000, 150000000, 151000000, 152000000, 153000000, 154000000, 155000000, 156000000, 157000000, 158000000, 159000000, 194000000, 195000000, 950000000, 951000000, 198000000, 199000000, 160000000, 161000000, 162000000, 163000000, 164000000, 165000000, 166000000, 167000000, 168000000, 169000000, 186000000, 187000000, 960000000, 961000000, 988000000, 989000000, 170000000, 171000000, 172000000, 173000000, 174000000, 175000000, 176000000, 177000000, 178000000, 179000000, 196000000, 197000000, 970000000, 971000000, 998000000, 999000000, 200000000, 201000000, 202000000, 203000000, 204000000, 205000000, 206000000, 207000000, 208000000, 209000000, 280000000, 281000000, 802000000, 803000000, 882000000, 883000000, 210000000, 211000000, 212000000, 213000000, 214000000, 215000000, 216000000, 217000000, 218000000, 219000000, 290000000, 291000000, 812000000, 813000000, 892000000, 893000000, 220000000, 221000000, 222000000, 223000000, 224000000, 225000000, 226000000, 227000000, 228000000, 229000000, 282000000, 283000000, 822000000, 823000000, 828000000, 829000000, 230000000, 231000000, 232000000, 233000000, 234000000, 235000000, 236000000, 237000000, 238000000, 239000000, 292000000, 293000000, 832000000, 833000000, 838000000, 839000000, 240000000, 241000000, 242000000, 243000000, 244000000, 245000000, 246000000, 247000000, 248000000, 249000000, 284000000, 285000000, 842000000, 843000000, 288000000, 289000000, 250000000, 251000000, 252000000, 253000000, 254000000, 255000000, 256000000, 257000000, 258000000, 259000000, 294000000, 295000000, 852000000, 853000000, 298000000, 299000000, 260000000, 261000000, 262000000, 263000000, 264000000, 265000000, 266000000, 267000000, 268000000, 269000000, 286000000, 287000000, 862000000, 863000000, 888000000, 889000000, 270000000, 271000000, 272000000, 273000000, 274000000, 275000000, 276000000, 277000000, 278000000, 279000000, 296000000, 297000000, 872000000, 873000000, 898000000, 899000000, 300000000, 301000000, 302000000, 303000000, 304000000, 305000000, 306000000, 307000000, 308000000, 309000000, 380000000, 381000000, 902000000, 903000000, 982000000, 983000000, 310000000, 311000000, 312000000, 313000000, 314000000, 315000000, 316000000, 317000000, 318000000, 319000000, 390000000, 391000000, 912000000, 913000000, 992000000, 993000000, 320000000, 321000000, 322000000, 323000000, 324000000, 325000000, 326000000, 327000000, 328000000, 329000000, 382000000, 383000000, 922000000, 923000000, 928000000, 929000000, 330000000, 331000000, 332000000, 333000000, 334000000, 335000000, 336000000, 337000000, 338000000, 339000000, 392000000, 393000000, 932000000, 933000000, 938000000, 939000000, 340000000, 341000000, 342000000, 343000000, 344000000, 345000000, 346000000, 347000000, 348000000, 349000000, 384000000, 385000000, 942000000, 943000000, 388000000, 389000000, 350000000, 351000000, 352000000, 353000000, 354000000, 355000000, 356000000, 357000000, 358000000, 359000000, 394000000, 395000000, 952000000, 953000000, 398000000, 399000000, 360000000, 361000000, 362000000, 363000000, 364000000, 365000000, 366000000, 367000000, 368000000, 369000000, 386000000, 387000000, 962000000, 963000000, 988000000, 989000000, 370000000, 371000000, 372000000, 373000000, 374000000, 375000000, 376000000, 377000000, 378000000, 379000000, 396000000, 397000000, 972000000, 973000000, 998000000, 999000000, 400000000, 401000000, 402000000, 403000000, 404000000, 405000000, 406000000, 407000000, 408000000, 409000000, 480000000, 481000000, 804000000, 805000000, 884000000, 885000000, 410000000, 411000000, 412000000, 413000000, 414000000, 415000000, 416000000, 417000000, 418000000, 419000000, 490000000, 491000000, 814000000, 815000000, 894000000, 895000000, 420000000, 421000000, 422000000, 423000000, 424000000, 425000000, 426000000, 427000000, 428000000, 429000000, 482000000, 483000000, 824000000, 825000000, 848000000, 849000000, 430000000, 431000000, 432000000, 433000000, 434000000, 435000000, 436000000, 437000000, 438000000, 439000000, 492000000, 493000000, 834000000, 835000000, 858000000, 859000000, 440000000, 441000000, 442000000, 443000000, 444000000, 445000000, 446000000, 447000000, 448000000, 449000000, 484000000, 485000000, 844000000, 845000000, 488000000, 489000000, 450000000, 451000000, 452000000, 453000000, 454000000, 455000000, 456000000, 457000000, 458000000, 459000000, 494000000, 495000000, 854000000, 855000000, 498000000, 499000000, 460000000, 461000000, 462000000, 463000000, 464000000, 465000000, 466000000, 467000000, 468000000, 469000000, 486000000, 487000000, 864000000, 865000000, 888000000, 889000000, 470000000, 471000000, 472000000, 473000000, 474000000, 475000000, 476000000, 477000000, 478000000, 479000000, 496000000, 497000000, 874000000, 875000000, 898000000, 899000000, 500000000, 501000000, 502000000, 503000000, 504000000, 505000000, 506000000, 507000000, 508000000, 509000000, 580000000, 581000000, 904000000, 905000000, 984000000, 985000000, 510000000, 511000000, 512000000, 513000000, 514000000, 515000000, 516000000, 517000000, 518000000, 519000000, 590000000, 591000000, 914000000, 915000000, 994000000, 995000000, 520000000, 521000000, 522000000, 523000000, 524000000, 525000000, 526000000, 527000000, 528000000, 529000000, 582000000, 583000000, 924000000, 925000000, 948000000, 949000000, 530000000, 531000000, 532000000, 533000000, 534000000, 535000000, 536000000, 537000000, 538000000, 539000000, 592000000, 593000000, 934000000, 935000000, 958000000, 959000000, 540000000, 541000000, 542000000, 543000000, 544000000, 545000000, 546000000, 547000000, 548000000, 549000000, 584000000, 585000000, 944000000, 945000000, 588000000, 589000000, 550000000, 551000000, 552000000, 553000000, 554000000, 555000000, 556000000, 557000000, 558000000, 559000000, 594000000, 595000000, 954000000, 955000000, 598000000, 599000000, 560000000, 561000000, 562000000, 563000000, 564000000, 565000000, 566000000, 567000000, 568000000, 569000000, 586000000, 587000000, 964000000, 965000000, 988000000, 989000000, 570000000, 571000000, 572000000, 573000000, 574000000, 575000000, 576000000, 577000000, 578000000, 579000000, 596000000, 597000000, 974000000, 975000000, 998000000, 999000000, 600000000, 601000000, 602000000, 603000000, 604000000, 605000000, 606000000, 607000000, 608000000, 609000000, 680000000, 681000000, 806000000, 807000000, 886000000, 887000000, 610000000, 611000000, 612000000, 613000000, 614000000, 615000000, 616000000, 617000000, 618000000, 619000000, 690000000, 691000000, 816000000, 817000000, 896000000, 897000000, 620000000, 621000000, 622000000, 623000000, 624000000, 625000000, 626000000, 627000000, 628000000, 629000000, 682000000, 683000000, 826000000, 827000000, 868000000, 869000000, 630000000, 631000000, 632000000, 633000000, 634000000, 635000000, 636000000, 637000000, 638000000, 639000000, 692000000, 693000000, 836000000, 837000000, 878000000, 879000000, 640000000, 641000000, 642000000, 643000000, 644000000, 645000000, 646000000, 647000000, 648000000, 649000000, 684000000, 685000000, 846000000, 847000000, 688000000, 689000000, 650000000, 651000000, 652000000, 653000000, 654000000, 655000000, 656000000, 657000000, 658000000, 659000000, 694000000, 695000000, 856000000, 857000000, 698000000, 699000000, 660000000, 661000000, 662000000, 663000000, 664000000, 665000000, 666000000, 667000000, 668000000, 669000000, 686000000, 687000000, 866000000, 867000000, 888000000, 889000000, 670000000, 671000000, 672000000, 673000000, 674000000, 675000000, 676000000, 677000000, 678000000, 679000000, 696000000, 697000000, 876000000, 877000000, 898000000, 899000000, 700000000, 701000000, 702000000, 703000000, 704000000, 705000000, 706000000, 707000000, 708000000, 709000000, 780000000, 781000000, 906000000, 907000000, 986000000, 987000000, 710000000, 711000000, 712000000, 713000000, 714000000, 715000000, 716000000, 717000000, 718000000, 719000000, 790000000, 791000000, 916000000, 917000000, 996000000, 997000000, 720000000, 721000000, 722000000, 723000000, 724000000, 725000000, 726000000, 727000000, 728000000, 729000000, 782000000, 783000000, 926000000, 927000000, 968000000, 969000000, 730000000, 731000000, 732000000, 733000000, 734000000, 735000000, 736000000, 737000000, 738000000, 739000000, 792000000, 793000000, 936000000, 937000000, 978000000, 979000000, 740000000, 741000000, 742000000, 743000000, 744000000, 745000000, 746000000, 747000000, 748000000, 749000000, 784000000, 785000000, 946000000, 947000000, 788000000, 789000000, 750000000, 751000000, 752000000, 753000000, 754000000, 755000000, 756000000, 757000000, 758000000, 759000000, 794000000, 795000000, 956000000, 957000000, 798000000, 799000000, 760000000, 761000000, 762000000, 763000000, 764000000, 765000000, 766000000, 767000000, 768000000, 769000000, 786000000, 787000000, 966000000, 967000000, 988000000, 989000000, 770000000, 771000000, 772000000, 773000000, 774000000, 775000000, 776000000, 777000000, 778000000, 779000000, 796000000, 797000000, 976000000, 977000000, 998000000, 999000000}; #endif #if defined(DEC_BIN2CHAR) && DEC_BIN2CHAR==1 && !defined(DECBIN2CHAR) #define DECBIN2CHAR const uint8_t BIN2CHAR[4001]={ '\0','0','0','0', '\1','0','0','1', '\1','0','0','2', '\1','0','0','3', '\1','0','0','4', '\1','0','0','5', '\1','0','0','6', '\1','0','0','7', '\1','0','0','8', '\1','0','0','9', '\2','0','1','0', '\2','0','1','1', '\2','0','1','2', '\2','0','1','3', '\2','0','1','4', '\2','0','1','5', '\2','0','1','6', '\2','0','1','7', '\2','0','1','8', '\2','0','1','9', '\2','0','2','0', '\2','0','2','1', '\2','0','2','2', '\2','0','2','3', '\2','0','2','4', '\2','0','2','5', '\2','0','2','6', '\2','0','2','7', '\2','0','2','8', '\2','0','2','9', '\2','0','3','0', '\2','0','3','1', '\2','0','3','2', '\2','0','3','3', '\2','0','3','4', '\2','0','3','5', '\2','0','3','6', '\2','0','3','7', '\2','0','3','8', '\2','0','3','9', '\2','0','4','0', '\2','0','4','1', '\2','0','4','2', '\2','0','4','3', '\2','0','4','4', '\2','0','4','5', '\2','0','4','6', '\2','0','4','7', '\2','0','4','8', '\2','0','4','9', '\2','0','5','0', '\2','0','5','1', '\2','0','5','2', '\2','0','5','3', '\2','0','5','4', '\2','0','5','5', '\2','0','5','6', '\2','0','5','7', '\2','0','5','8', '\2','0','5','9', '\2','0','6','0', '\2','0','6','1', '\2','0','6','2', '\2','0','6','3', '\2','0','6','4', '\2','0','6','5', '\2','0','6','6', '\2','0','6','7', '\2','0','6','8', '\2','0','6','9', '\2','0','7','0', '\2','0','7','1', '\2','0','7','2', '\2','0','7','3', '\2','0','7','4', '\2','0','7','5', '\2','0','7','6', '\2','0','7','7', '\2','0','7','8', '\2','0','7','9', '\2','0','8','0', '\2','0','8','1', '\2','0','8','2', '\2','0','8','3', '\2','0','8','4', '\2','0','8','5', '\2','0','8','6', '\2','0','8','7', '\2','0','8','8', '\2','0','8','9', '\2','0','9','0', '\2','0','9','1', '\2','0','9','2', '\2','0','9','3', '\2','0','9','4', '\2','0','9','5', '\2','0','9','6', '\2','0','9','7', '\2','0','9','8', '\2','0','9','9', '\3','1','0','0', '\3','1','0','1', '\3','1','0','2', '\3','1','0','3', '\3','1','0','4', '\3','1','0','5', '\3','1','0','6', '\3','1','0','7', '\3','1','0','8', '\3','1','0','9', '\3','1','1','0', '\3','1','1','1', '\3','1','1','2', '\3','1','1','3', '\3','1','1','4', '\3','1','1','5', '\3','1','1','6', '\3','1','1','7', '\3','1','1','8', '\3','1','1','9', '\3','1','2','0', '\3','1','2','1', '\3','1','2','2', '\3','1','2','3', '\3','1','2','4', '\3','1','2','5', '\3','1','2','6', '\3','1','2','7', '\3','1','2','8', '\3','1','2','9', '\3','1','3','0', '\3','1','3','1', '\3','1','3','2', '\3','1','3','3', '\3','1','3','4', '\3','1','3','5', '\3','1','3','6', '\3','1','3','7', '\3','1','3','8', '\3','1','3','9', '\3','1','4','0', '\3','1','4','1', '\3','1','4','2', '\3','1','4','3', '\3','1','4','4', '\3','1','4','5', '\3','1','4','6', '\3','1','4','7', '\3','1','4','8', '\3','1','4','9', '\3','1','5','0', '\3','1','5','1', '\3','1','5','2', '\3','1','5','3', '\3','1','5','4', '\3','1','5','5', '\3','1','5','6', '\3','1','5','7', '\3','1','5','8', '\3','1','5','9', '\3','1','6','0', '\3','1','6','1', '\3','1','6','2', '\3','1','6','3', '\3','1','6','4', '\3','1','6','5', '\3','1','6','6', '\3','1','6','7', '\3','1','6','8', '\3','1','6','9', '\3','1','7','0', '\3','1','7','1', '\3','1','7','2', '\3','1','7','3', '\3','1','7','4', '\3','1','7','5', '\3','1','7','6', '\3','1','7','7', '\3','1','7','8', '\3','1','7','9', '\3','1','8','0', '\3','1','8','1', '\3','1','8','2', '\3','1','8','3', '\3','1','8','4', '\3','1','8','5', '\3','1','8','6', '\3','1','8','7', '\3','1','8','8', '\3','1','8','9', '\3','1','9','0', '\3','1','9','1', '\3','1','9','2', '\3','1','9','3', '\3','1','9','4', '\3','1','9','5', '\3','1','9','6', '\3','1','9','7', '\3','1','9','8', '\3','1','9','9', '\3','2','0','0', '\3','2','0','1', '\3','2','0','2', '\3','2','0','3', '\3','2','0','4', '\3','2','0','5', '\3','2','0','6', '\3','2','0','7', '\3','2','0','8', '\3','2','0','9', '\3','2','1','0', '\3','2','1','1', '\3','2','1','2', '\3','2','1','3', '\3','2','1','4', '\3','2','1','5', '\3','2','1','6', '\3','2','1','7', '\3','2','1','8', '\3','2','1','9', '\3','2','2','0', '\3','2','2','1', '\3','2','2','2', '\3','2','2','3', '\3','2','2','4', '\3','2','2','5', '\3','2','2','6', '\3','2','2','7', '\3','2','2','8', '\3','2','2','9', '\3','2','3','0', '\3','2','3','1', '\3','2','3','2', '\3','2','3','3', '\3','2','3','4', '\3','2','3','5', '\3','2','3','6', '\3','2','3','7', '\3','2','3','8', '\3','2','3','9', '\3','2','4','0', '\3','2','4','1', '\3','2','4','2', '\3','2','4','3', '\3','2','4','4', '\3','2','4','5', '\3','2','4','6', '\3','2','4','7', '\3','2','4','8', '\3','2','4','9', '\3','2','5','0', '\3','2','5','1', '\3','2','5','2', '\3','2','5','3', '\3','2','5','4', '\3','2','5','5', '\3','2','5','6', '\3','2','5','7', '\3','2','5','8', '\3','2','5','9', '\3','2','6','0', '\3','2','6','1', '\3','2','6','2', '\3','2','6','3', '\3','2','6','4', '\3','2','6','5', '\3','2','6','6', '\3','2','6','7', '\3','2','6','8', '\3','2','6','9', '\3','2','7','0', '\3','2','7','1', '\3','2','7','2', '\3','2','7','3', '\3','2','7','4', '\3','2','7','5', '\3','2','7','6', '\3','2','7','7', '\3','2','7','8', '\3','2','7','9', '\3','2','8','0', '\3','2','8','1', '\3','2','8','2', '\3','2','8','3', '\3','2','8','4', '\3','2','8','5', '\3','2','8','6', '\3','2','8','7', '\3','2','8','8', '\3','2','8','9', '\3','2','9','0', '\3','2','9','1', '\3','2','9','2', '\3','2','9','3', '\3','2','9','4', '\3','2','9','5', '\3','2','9','6', '\3','2','9','7', '\3','2','9','8', '\3','2','9','9', '\3','3','0','0', '\3','3','0','1', '\3','3','0','2', '\3','3','0','3', '\3','3','0','4', '\3','3','0','5', '\3','3','0','6', '\3','3','0','7', '\3','3','0','8', '\3','3','0','9', '\3','3','1','0', '\3','3','1','1', '\3','3','1','2', '\3','3','1','3', '\3','3','1','4', '\3','3','1','5', '\3','3','1','6', '\3','3','1','7', '\3','3','1','8', '\3','3','1','9', '\3','3','2','0', '\3','3','2','1', '\3','3','2','2', '\3','3','2','3', '\3','3','2','4', '\3','3','2','5', '\3','3','2','6', '\3','3','2','7', '\3','3','2','8', '\3','3','2','9', '\3','3','3','0', '\3','3','3','1', '\3','3','3','2', '\3','3','3','3', '\3','3','3','4', '\3','3','3','5', '\3','3','3','6', '\3','3','3','7', '\3','3','3','8', '\3','3','3','9', '\3','3','4','0', '\3','3','4','1', '\3','3','4','2', '\3','3','4','3', '\3','3','4','4', '\3','3','4','5', '\3','3','4','6', '\3','3','4','7', '\3','3','4','8', '\3','3','4','9', '\3','3','5','0', '\3','3','5','1', '\3','3','5','2', '\3','3','5','3', '\3','3','5','4', '\3','3','5','5', '\3','3','5','6', '\3','3','5','7', '\3','3','5','8', '\3','3','5','9', '\3','3','6','0', '\3','3','6','1', '\3','3','6','2', '\3','3','6','3', '\3','3','6','4', '\3','3','6','5', '\3','3','6','6', '\3','3','6','7', '\3','3','6','8', '\3','3','6','9', '\3','3','7','0', '\3','3','7','1', '\3','3','7','2', '\3','3','7','3', '\3','3','7','4', '\3','3','7','5', '\3','3','7','6', '\3','3','7','7', '\3','3','7','8', '\3','3','7','9', '\3','3','8','0', '\3','3','8','1', '\3','3','8','2', '\3','3','8','3', '\3','3','8','4', '\3','3','8','5', '\3','3','8','6', '\3','3','8','7', '\3','3','8','8', '\3','3','8','9', '\3','3','9','0', '\3','3','9','1', '\3','3','9','2', '\3','3','9','3', '\3','3','9','4', '\3','3','9','5', '\3','3','9','6', '\3','3','9','7', '\3','3','9','8', '\3','3','9','9', '\3','4','0','0', '\3','4','0','1', '\3','4','0','2', '\3','4','0','3', '\3','4','0','4', '\3','4','0','5', '\3','4','0','6', '\3','4','0','7', '\3','4','0','8', '\3','4','0','9', '\3','4','1','0', '\3','4','1','1', '\3','4','1','2', '\3','4','1','3', '\3','4','1','4', '\3','4','1','5', '\3','4','1','6', '\3','4','1','7', '\3','4','1','8', '\3','4','1','9', '\3','4','2','0', '\3','4','2','1', '\3','4','2','2', '\3','4','2','3', '\3','4','2','4', '\3','4','2','5', '\3','4','2','6', '\3','4','2','7', '\3','4','2','8', '\3','4','2','9', '\3','4','3','0', '\3','4','3','1', '\3','4','3','2', '\3','4','3','3', '\3','4','3','4', '\3','4','3','5', '\3','4','3','6', '\3','4','3','7', '\3','4','3','8', '\3','4','3','9', '\3','4','4','0', '\3','4','4','1', '\3','4','4','2', '\3','4','4','3', '\3','4','4','4', '\3','4','4','5', '\3','4','4','6', '\3','4','4','7', '\3','4','4','8', '\3','4','4','9', '\3','4','5','0', '\3','4','5','1', '\3','4','5','2', '\3','4','5','3', '\3','4','5','4', '\3','4','5','5', '\3','4','5','6', '\3','4','5','7', '\3','4','5','8', '\3','4','5','9', '\3','4','6','0', '\3','4','6','1', '\3','4','6','2', '\3','4','6','3', '\3','4','6','4', '\3','4','6','5', '\3','4','6','6', '\3','4','6','7', '\3','4','6','8', '\3','4','6','9', '\3','4','7','0', '\3','4','7','1', '\3','4','7','2', '\3','4','7','3', '\3','4','7','4', '\3','4','7','5', '\3','4','7','6', '\3','4','7','7', '\3','4','7','8', '\3','4','7','9', '\3','4','8','0', '\3','4','8','1', '\3','4','8','2', '\3','4','8','3', '\3','4','8','4', '\3','4','8','5', '\3','4','8','6', '\3','4','8','7', '\3','4','8','8', '\3','4','8','9', '\3','4','9','0', '\3','4','9','1', '\3','4','9','2', '\3','4','9','3', '\3','4','9','4', '\3','4','9','5', '\3','4','9','6', '\3','4','9','7', '\3','4','9','8', '\3','4','9','9', '\3','5','0','0', '\3','5','0','1', '\3','5','0','2', '\3','5','0','3', '\3','5','0','4', '\3','5','0','5', '\3','5','0','6', '\3','5','0','7', '\3','5','0','8', '\3','5','0','9', '\3','5','1','0', '\3','5','1','1', '\3','5','1','2', '\3','5','1','3', '\3','5','1','4', '\3','5','1','5', '\3','5','1','6', '\3','5','1','7', '\3','5','1','8', '\3','5','1','9', '\3','5','2','0', '\3','5','2','1', '\3','5','2','2', '\3','5','2','3', '\3','5','2','4', '\3','5','2','5', '\3','5','2','6', '\3','5','2','7', '\3','5','2','8', '\3','5','2','9', '\3','5','3','0', '\3','5','3','1', '\3','5','3','2', '\3','5','3','3', '\3','5','3','4', '\3','5','3','5', '\3','5','3','6', '\3','5','3','7', '\3','5','3','8', '\3','5','3','9', '\3','5','4','0', '\3','5','4','1', '\3','5','4','2', '\3','5','4','3', '\3','5','4','4', '\3','5','4','5', '\3','5','4','6', '\3','5','4','7', '\3','5','4','8', '\3','5','4','9', '\3','5','5','0', '\3','5','5','1', '\3','5','5','2', '\3','5','5','3', '\3','5','5','4', '\3','5','5','5', '\3','5','5','6', '\3','5','5','7', '\3','5','5','8', '\3','5','5','9', '\3','5','6','0', '\3','5','6','1', '\3','5','6','2', '\3','5','6','3', '\3','5','6','4', '\3','5','6','5', '\3','5','6','6', '\3','5','6','7', '\3','5','6','8', '\3','5','6','9', '\3','5','7','0', '\3','5','7','1', '\3','5','7','2', '\3','5','7','3', '\3','5','7','4', '\3','5','7','5', '\3','5','7','6', '\3','5','7','7', '\3','5','7','8', '\3','5','7','9', '\3','5','8','0', '\3','5','8','1', '\3','5','8','2', '\3','5','8','3', '\3','5','8','4', '\3','5','8','5', '\3','5','8','6', '\3','5','8','7', '\3','5','8','8', '\3','5','8','9', '\3','5','9','0', '\3','5','9','1', '\3','5','9','2', '\3','5','9','3', '\3','5','9','4', '\3','5','9','5', '\3','5','9','6', '\3','5','9','7', '\3','5','9','8', '\3','5','9','9', '\3','6','0','0', '\3','6','0','1', '\3','6','0','2', '\3','6','0','3', '\3','6','0','4', '\3','6','0','5', '\3','6','0','6', '\3','6','0','7', '\3','6','0','8', '\3','6','0','9', '\3','6','1','0', '\3','6','1','1', '\3','6','1','2', '\3','6','1','3', '\3','6','1','4', '\3','6','1','5', '\3','6','1','6', '\3','6','1','7', '\3','6','1','8', '\3','6','1','9', '\3','6','2','0', '\3','6','2','1', '\3','6','2','2', '\3','6','2','3', '\3','6','2','4', '\3','6','2','5', '\3','6','2','6', '\3','6','2','7', '\3','6','2','8', '\3','6','2','9', '\3','6','3','0', '\3','6','3','1', '\3','6','3','2', '\3','6','3','3', '\3','6','3','4', '\3','6','3','5', '\3','6','3','6', '\3','6','3','7', '\3','6','3','8', '\3','6','3','9', '\3','6','4','0', '\3','6','4','1', '\3','6','4','2', '\3','6','4','3', '\3','6','4','4', '\3','6','4','5', '\3','6','4','6', '\3','6','4','7', '\3','6','4','8', '\3','6','4','9', '\3','6','5','0', '\3','6','5','1', '\3','6','5','2', '\3','6','5','3', '\3','6','5','4', '\3','6','5','5', '\3','6','5','6', '\3','6','5','7', '\3','6','5','8', '\3','6','5','9', '\3','6','6','0', '\3','6','6','1', '\3','6','6','2', '\3','6','6','3', '\3','6','6','4', '\3','6','6','5', '\3','6','6','6', '\3','6','6','7', '\3','6','6','8', '\3','6','6','9', '\3','6','7','0', '\3','6','7','1', '\3','6','7','2', '\3','6','7','3', '\3','6','7','4', '\3','6','7','5', '\3','6','7','6', '\3','6','7','7', '\3','6','7','8', '\3','6','7','9', '\3','6','8','0', '\3','6','8','1', '\3','6','8','2', '\3','6','8','3', '\3','6','8','4', '\3','6','8','5', '\3','6','8','6', '\3','6','8','7', '\3','6','8','8', '\3','6','8','9', '\3','6','9','0', '\3','6','9','1', '\3','6','9','2', '\3','6','9','3', '\3','6','9','4', '\3','6','9','5', '\3','6','9','6', '\3','6','9','7', '\3','6','9','8', '\3','6','9','9', '\3','7','0','0', '\3','7','0','1', '\3','7','0','2', '\3','7','0','3', '\3','7','0','4', '\3','7','0','5', '\3','7','0','6', '\3','7','0','7', '\3','7','0','8', '\3','7','0','9', '\3','7','1','0', '\3','7','1','1', '\3','7','1','2', '\3','7','1','3', '\3','7','1','4', '\3','7','1','5', '\3','7','1','6', '\3','7','1','7', '\3','7','1','8', '\3','7','1','9', '\3','7','2','0', '\3','7','2','1', '\3','7','2','2', '\3','7','2','3', '\3','7','2','4', '\3','7','2','5', '\3','7','2','6', '\3','7','2','7', '\3','7','2','8', '\3','7','2','9', '\3','7','3','0', '\3','7','3','1', '\3','7','3','2', '\3','7','3','3', '\3','7','3','4', '\3','7','3','5', '\3','7','3','6', '\3','7','3','7', '\3','7','3','8', '\3','7','3','9', '\3','7','4','0', '\3','7','4','1', '\3','7','4','2', '\3','7','4','3', '\3','7','4','4', '\3','7','4','5', '\3','7','4','6', '\3','7','4','7', '\3','7','4','8', '\3','7','4','9', '\3','7','5','0', '\3','7','5','1', '\3','7','5','2', '\3','7','5','3', '\3','7','5','4', '\3','7','5','5', '\3','7','5','6', '\3','7','5','7', '\3','7','5','8', '\3','7','5','9', '\3','7','6','0', '\3','7','6','1', '\3','7','6','2', '\3','7','6','3', '\3','7','6','4', '\3','7','6','5', '\3','7','6','6', '\3','7','6','7', '\3','7','6','8', '\3','7','6','9', '\3','7','7','0', '\3','7','7','1', '\3','7','7','2', '\3','7','7','3', '\3','7','7','4', '\3','7','7','5', '\3','7','7','6', '\3','7','7','7', '\3','7','7','8', '\3','7','7','9', '\3','7','8','0', '\3','7','8','1', '\3','7','8','2', '\3','7','8','3', '\3','7','8','4', '\3','7','8','5', '\3','7','8','6', '\3','7','8','7', '\3','7','8','8', '\3','7','8','9', '\3','7','9','0', '\3','7','9','1', '\3','7','9','2', '\3','7','9','3', '\3','7','9','4', '\3','7','9','5', '\3','7','9','6', '\3','7','9','7', '\3','7','9','8', '\3','7','9','9', '\3','8','0','0', '\3','8','0','1', '\3','8','0','2', '\3','8','0','3', '\3','8','0','4', '\3','8','0','5', '\3','8','0','6', '\3','8','0','7', '\3','8','0','8', '\3','8','0','9', '\3','8','1','0', '\3','8','1','1', '\3','8','1','2', '\3','8','1','3', '\3','8','1','4', '\3','8','1','5', '\3','8','1','6', '\3','8','1','7', '\3','8','1','8', '\3','8','1','9', '\3','8','2','0', '\3','8','2','1', '\3','8','2','2', '\3','8','2','3', '\3','8','2','4', '\3','8','2','5', '\3','8','2','6', '\3','8','2','7', '\3','8','2','8', '\3','8','2','9', '\3','8','3','0', '\3','8','3','1', '\3','8','3','2', '\3','8','3','3', '\3','8','3','4', '\3','8','3','5', '\3','8','3','6', '\3','8','3','7', '\3','8','3','8', '\3','8','3','9', '\3','8','4','0', '\3','8','4','1', '\3','8','4','2', '\3','8','4','3', '\3','8','4','4', '\3','8','4','5', '\3','8','4','6', '\3','8','4','7', '\3','8','4','8', '\3','8','4','9', '\3','8','5','0', '\3','8','5','1', '\3','8','5','2', '\3','8','5','3', '\3','8','5','4', '\3','8','5','5', '\3','8','5','6', '\3','8','5','7', '\3','8','5','8', '\3','8','5','9', '\3','8','6','0', '\3','8','6','1', '\3','8','6','2', '\3','8','6','3', '\3','8','6','4', '\3','8','6','5', '\3','8','6','6', '\3','8','6','7', '\3','8','6','8', '\3','8','6','9', '\3','8','7','0', '\3','8','7','1', '\3','8','7','2', '\3','8','7','3', '\3','8','7','4', '\3','8','7','5', '\3','8','7','6', '\3','8','7','7', '\3','8','7','8', '\3','8','7','9', '\3','8','8','0', '\3','8','8','1', '\3','8','8','2', '\3','8','8','3', '\3','8','8','4', '\3','8','8','5', '\3','8','8','6', '\3','8','8','7', '\3','8','8','8', '\3','8','8','9', '\3','8','9','0', '\3','8','9','1', '\3','8','9','2', '\3','8','9','3', '\3','8','9','4', '\3','8','9','5', '\3','8','9','6', '\3','8','9','7', '\3','8','9','8', '\3','8','9','9', '\3','9','0','0', '\3','9','0','1', '\3','9','0','2', '\3','9','0','3', '\3','9','0','4', '\3','9','0','5', '\3','9','0','6', '\3','9','0','7', '\3','9','0','8', '\3','9','0','9', '\3','9','1','0', '\3','9','1','1', '\3','9','1','2', '\3','9','1','3', '\3','9','1','4', '\3','9','1','5', '\3','9','1','6', '\3','9','1','7', '\3','9','1','8', '\3','9','1','9', '\3','9','2','0', '\3','9','2','1', '\3','9','2','2', '\3','9','2','3', '\3','9','2','4', '\3','9','2','5', '\3','9','2','6', '\3','9','2','7', '\3','9','2','8', '\3','9','2','9', '\3','9','3','0', '\3','9','3','1', '\3','9','3','2', '\3','9','3','3', '\3','9','3','4', '\3','9','3','5', '\3','9','3','6', '\3','9','3','7', '\3','9','3','8', '\3','9','3','9', '\3','9','4','0', '\3','9','4','1', '\3','9','4','2', '\3','9','4','3', '\3','9','4','4', '\3','9','4','5', '\3','9','4','6', '\3','9','4','7', '\3','9','4','8', '\3','9','4','9', '\3','9','5','0', '\3','9','5','1', '\3','9','5','2', '\3','9','5','3', '\3','9','5','4', '\3','9','5','5', '\3','9','5','6', '\3','9','5','7', '\3','9','5','8', '\3','9','5','9', '\3','9','6','0', '\3','9','6','1', '\3','9','6','2', '\3','9','6','3', '\3','9','6','4', '\3','9','6','5', '\3','9','6','6', '\3','9','6','7', '\3','9','6','8', '\3','9','6','9', '\3','9','7','0', '\3','9','7','1', '\3','9','7','2', '\3','9','7','3', '\3','9','7','4', '\3','9','7','5', '\3','9','7','6', '\3','9','7','7', '\3','9','7','8', '\3','9','7','9', '\3','9','8','0', '\3','9','8','1', '\3','9','8','2', '\3','9','8','3', '\3','9','8','4', '\3','9','8','5', '\3','9','8','6', '\3','9','8','7', '\3','9','8','8', '\3','9','8','9', '\3','9','9','0', '\3','9','9','1', '\3','9','9','2', '\3','9','9','3', '\3','9','9','4', '\3','9','9','5', '\3','9','9','6', '\3','9','9','7', '\3','9','9','8', '\3','9','9','9', '\0'}; #endif #if defined(DEC_DPD2BCD8) && DEC_DPD2BCD8==1 && !defined(DECDPD2BCD8) #define DECDPD2BCD8 const uint8_t DPD2BCD8[4096]={ 0,0,0,0, 0,0,1,1, 0,0,2,1, 0,0,3,1, 0,0,4,1, 0,0,5,1, 0,0,6,1, 0,0,7,1, 0,0,8,1, 0,0,9,1, 0,8,0,2, 0,8,1,2, 8,0,0,3, 8,0,1,3, 8,8,0,3, 8,8,1,3, 0,1,0,2, 0,1,1,2, 0,1,2,2, 0,1,3,2, 0,1,4,2, 0,1,5,2, 0,1,6,2, 0,1,7,2, 0,1,8,2, 0,1,9,2, 0,9,0,2, 0,9,1,2, 8,1,0,3, 8,1,1,3, 8,9,0,3, 8,9,1,3, 0,2,0,2, 0,2,1,2, 0,2,2,2, 0,2,3,2, 0,2,4,2, 0,2,5,2, 0,2,6,2, 0,2,7,2, 0,2,8,2, 0,2,9,2, 0,8,2,2, 0,8,3,2, 8,2,0,3, 8,2,1,3, 8,0,8,3, 8,0,9,3, 0,3,0,2, 0,3,1,2, 0,3,2,2, 0,3,3,2, 0,3,4,2, 0,3,5,2, 0,3,6,2, 0,3,7,2, 0,3,8,2, 0,3,9,2, 0,9,2,2, 0,9,3,2, 8,3,0,3, 8,3,1,3, 8,1,8,3, 8,1,9,3, 0,4,0,2, 0,4,1,2, 0,4,2,2, 0,4,3,2, 0,4,4,2, 0,4,5,2, 0,4,6,2, 0,4,7,2, 0,4,8,2, 0,4,9,2, 0,8,4,2, 0,8,5,2, 8,4,0,3, 8,4,1,3, 0,8,8,2, 0,8,9,2, 0,5,0,2, 0,5,1,2, 0,5,2,2, 0,5,3,2, 0,5,4,2, 0,5,5,2, 0,5,6,2, 0,5,7,2, 0,5,8,2, 0,5,9,2, 0,9,4,2, 0,9,5,2, 8,5,0,3, 8,5,1,3, 0,9,8,2, 0,9,9,2, 0,6,0,2, 0,6,1,2, 0,6,2,2, 0,6,3,2, 0,6,4,2, 0,6,5,2, 0,6,6,2, 0,6,7,2, 0,6,8,2, 0,6,9,2, 0,8,6,2, 0,8,7,2, 8,6,0,3, 8,6,1,3, 8,8,8,3, 8,8,9,3, 0,7,0,2, 0,7,1,2, 0,7,2,2, 0,7,3,2, 0,7,4,2, 0,7,5,2, 0,7,6,2, 0,7,7,2, 0,7,8,2, 0,7,9,2, 0,9,6,2, 0,9,7,2, 8,7,0,3, 8,7,1,3, 8,9,8,3, 8,9,9,3, 1,0,0,3, 1,0,1,3, 1,0,2,3, 1,0,3,3, 1,0,4,3, 1,0,5,3, 1,0,6,3, 1,0,7,3, 1,0,8,3, 1,0,9,3, 1,8,0,3, 1,8,1,3, 9,0,0,3, 9,0,1,3, 9,8,0,3, 9,8,1,3, 1,1,0,3, 1,1,1,3, 1,1,2,3, 1,1,3,3, 1,1,4,3, 1,1,5,3, 1,1,6,3, 1,1,7,3, 1,1,8,3, 1,1,9,3, 1,9,0,3, 1,9,1,3, 9,1,0,3, 9,1,1,3, 9,9,0,3, 9,9,1,3, 1,2,0,3, 1,2,1,3, 1,2,2,3, 1,2,3,3, 1,2,4,3, 1,2,5,3, 1,2,6,3, 1,2,7,3, 1,2,8,3, 1,2,9,3, 1,8,2,3, 1,8,3,3, 9,2,0,3, 9,2,1,3, 9,0,8,3, 9,0,9,3, 1,3,0,3, 1,3,1,3, 1,3,2,3, 1,3,3,3, 1,3,4,3, 1,3,5,3, 1,3,6,3, 1,3,7,3, 1,3,8,3, 1,3,9,3, 1,9,2,3, 1,9,3,3, 9,3,0,3, 9,3,1,3, 9,1,8,3, 9,1,9,3, 1,4,0,3, 1,4,1,3, 1,4,2,3, 1,4,3,3, 1,4,4,3, 1,4,5,3, 1,4,6,3, 1,4,7,3, 1,4,8,3, 1,4,9,3, 1,8,4,3, 1,8,5,3, 9,4,0,3, 9,4,1,3, 1,8,8,3, 1,8,9,3, 1,5,0,3, 1,5,1,3, 1,5,2,3, 1,5,3,3, 1,5,4,3, 1,5,5,3, 1,5,6,3, 1,5,7,3, 1,5,8,3, 1,5,9,3, 1,9,4,3, 1,9,5,3, 9,5,0,3, 9,5,1,3, 1,9,8,3, 1,9,9,3, 1,6,0,3, 1,6,1,3, 1,6,2,3, 1,6,3,3, 1,6,4,3, 1,6,5,3, 1,6,6,3, 1,6,7,3, 1,6,8,3, 1,6,9,3, 1,8,6,3, 1,8,7,3, 9,6,0,3, 9,6,1,3, 9,8,8,3, 9,8,9,3, 1,7,0,3, 1,7,1,3, 1,7,2,3, 1,7,3,3, 1,7,4,3, 1,7,5,3, 1,7,6,3, 1,7,7,3, 1,7,8,3, 1,7,9,3, 1,9,6,3, 1,9,7,3, 9,7,0,3, 9,7,1,3, 9,9,8,3, 9,9,9,3, 2,0,0,3, 2,0,1,3, 2,0,2,3, 2,0,3,3, 2,0,4,3, 2,0,5,3, 2,0,6,3, 2,0,7,3, 2,0,8,3, 2,0,9,3, 2,8,0,3, 2,8,1,3, 8,0,2,3, 8,0,3,3, 8,8,2,3, 8,8,3,3, 2,1,0,3, 2,1,1,3, 2,1,2,3, 2,1,3,3, 2,1,4,3, 2,1,5,3, 2,1,6,3, 2,1,7,3, 2,1,8,3, 2,1,9,3, 2,9,0,3, 2,9,1,3, 8,1,2,3, 8,1,3,3, 8,9,2,3, 8,9,3,3, 2,2,0,3, 2,2,1,3, 2,2,2,3, 2,2,3,3, 2,2,4,3, 2,2,5,3, 2,2,6,3, 2,2,7,3, 2,2,8,3, 2,2,9,3, 2,8,2,3, 2,8,3,3, 8,2,2,3, 8,2,3,3, 8,2,8,3, 8,2,9,3, 2,3,0,3, 2,3,1,3, 2,3,2,3, 2,3,3,3, 2,3,4,3, 2,3,5,3, 2,3,6,3, 2,3,7,3, 2,3,8,3, 2,3,9,3, 2,9,2,3, 2,9,3,3, 8,3,2,3, 8,3,3,3, 8,3,8,3, 8,3,9,3, 2,4,0,3, 2,4,1,3, 2,4,2,3, 2,4,3,3, 2,4,4,3, 2,4,5,3, 2,4,6,3, 2,4,7,3, 2,4,8,3, 2,4,9,3, 2,8,4,3, 2,8,5,3, 8,4,2,3, 8,4,3,3, 2,8,8,3, 2,8,9,3, 2,5,0,3, 2,5,1,3, 2,5,2,3, 2,5,3,3, 2,5,4,3, 2,5,5,3, 2,5,6,3, 2,5,7,3, 2,5,8,3, 2,5,9,3, 2,9,4,3, 2,9,5,3, 8,5,2,3, 8,5,3,3, 2,9,8,3, 2,9,9,3, 2,6,0,3, 2,6,1,3, 2,6,2,3, 2,6,3,3, 2,6,4,3, 2,6,5,3, 2,6,6,3, 2,6,7,3, 2,6,8,3, 2,6,9,3, 2,8,6,3, 2,8,7,3, 8,6,2,3, 8,6,3,3, 8,8,8,3, 8,8,9,3, 2,7,0,3, 2,7,1,3, 2,7,2,3, 2,7,3,3, 2,7,4,3, 2,7,5,3, 2,7,6,3, 2,7,7,3, 2,7,8,3, 2,7,9,3, 2,9,6,3, 2,9,7,3, 8,7,2,3, 8,7,3,3, 8,9,8,3, 8,9,9,3, 3,0,0,3, 3,0,1,3, 3,0,2,3, 3,0,3,3, 3,0,4,3, 3,0,5,3, 3,0,6,3, 3,0,7,3, 3,0,8,3, 3,0,9,3, 3,8,0,3, 3,8,1,3, 9,0,2,3, 9,0,3,3, 9,8,2,3, 9,8,3,3, 3,1,0,3, 3,1,1,3, 3,1,2,3, 3,1,3,3, 3,1,4,3, 3,1,5,3, 3,1,6,3, 3,1,7,3, 3,1,8,3, 3,1,9,3, 3,9,0,3, 3,9,1,3, 9,1,2,3, 9,1,3,3, 9,9,2,3, 9,9,3,3, 3,2,0,3, 3,2,1,3, 3,2,2,3, 3,2,3,3, 3,2,4,3, 3,2,5,3, 3,2,6,3, 3,2,7,3, 3,2,8,3, 3,2,9,3, 3,8,2,3, 3,8,3,3, 9,2,2,3, 9,2,3,3, 9,2,8,3, 9,2,9,3, 3,3,0,3, 3,3,1,3, 3,3,2,3, 3,3,3,3, 3,3,4,3, 3,3,5,3, 3,3,6,3, 3,3,7,3, 3,3,8,3, 3,3,9,3, 3,9,2,3, 3,9,3,3, 9,3,2,3, 9,3,3,3, 9,3,8,3, 9,3,9,3, 3,4,0,3, 3,4,1,3, 3,4,2,3, 3,4,3,3, 3,4,4,3, 3,4,5,3, 3,4,6,3, 3,4,7,3, 3,4,8,3, 3,4,9,3, 3,8,4,3, 3,8,5,3, 9,4,2,3, 9,4,3,3, 3,8,8,3, 3,8,9,3, 3,5,0,3, 3,5,1,3, 3,5,2,3, 3,5,3,3, 3,5,4,3, 3,5,5,3, 3,5,6,3, 3,5,7,3, 3,5,8,3, 3,5,9,3, 3,9,4,3, 3,9,5,3, 9,5,2,3, 9,5,3,3, 3,9,8,3, 3,9,9,3, 3,6,0,3, 3,6,1,3, 3,6,2,3, 3,6,3,3, 3,6,4,3, 3,6,5,3, 3,6,6,3, 3,6,7,3, 3,6,8,3, 3,6,9,3, 3,8,6,3, 3,8,7,3, 9,6,2,3, 9,6,3,3, 9,8,8,3, 9,8,9,3, 3,7,0,3, 3,7,1,3, 3,7,2,3, 3,7,3,3, 3,7,4,3, 3,7,5,3, 3,7,6,3, 3,7,7,3, 3,7,8,3, 3,7,9,3, 3,9,6,3, 3,9,7,3, 9,7,2,3, 9,7,3,3, 9,9,8,3, 9,9,9,3, 4,0,0,3, 4,0,1,3, 4,0,2,3, 4,0,3,3, 4,0,4,3, 4,0,5,3, 4,0,6,3, 4,0,7,3, 4,0,8,3, 4,0,9,3, 4,8,0,3, 4,8,1,3, 8,0,4,3, 8,0,5,3, 8,8,4,3, 8,8,5,3, 4,1,0,3, 4,1,1,3, 4,1,2,3, 4,1,3,3, 4,1,4,3, 4,1,5,3, 4,1,6,3, 4,1,7,3, 4,1,8,3, 4,1,9,3, 4,9,0,3, 4,9,1,3, 8,1,4,3, 8,1,5,3, 8,9,4,3, 8,9,5,3, 4,2,0,3, 4,2,1,3, 4,2,2,3, 4,2,3,3, 4,2,4,3, 4,2,5,3, 4,2,6,3, 4,2,7,3, 4,2,8,3, 4,2,9,3, 4,8,2,3, 4,8,3,3, 8,2,4,3, 8,2,5,3, 8,4,8,3, 8,4,9,3, 4,3,0,3, 4,3,1,3, 4,3,2,3, 4,3,3,3, 4,3,4,3, 4,3,5,3, 4,3,6,3, 4,3,7,3, 4,3,8,3, 4,3,9,3, 4,9,2,3, 4,9,3,3, 8,3,4,3, 8,3,5,3, 8,5,8,3, 8,5,9,3, 4,4,0,3, 4,4,1,3, 4,4,2,3, 4,4,3,3, 4,4,4,3, 4,4,5,3, 4,4,6,3, 4,4,7,3, 4,4,8,3, 4,4,9,3, 4,8,4,3, 4,8,5,3, 8,4,4,3, 8,4,5,3, 4,8,8,3, 4,8,9,3, 4,5,0,3, 4,5,1,3, 4,5,2,3, 4,5,3,3, 4,5,4,3, 4,5,5,3, 4,5,6,3, 4,5,7,3, 4,5,8,3, 4,5,9,3, 4,9,4,3, 4,9,5,3, 8,5,4,3, 8,5,5,3, 4,9,8,3, 4,9,9,3, 4,6,0,3, 4,6,1,3, 4,6,2,3, 4,6,3,3, 4,6,4,3, 4,6,5,3, 4,6,6,3, 4,6,7,3, 4,6,8,3, 4,6,9,3, 4,8,6,3, 4,8,7,3, 8,6,4,3, 8,6,5,3, 8,8,8,3, 8,8,9,3, 4,7,0,3, 4,7,1,3, 4,7,2,3, 4,7,3,3, 4,7,4,3, 4,7,5,3, 4,7,6,3, 4,7,7,3, 4,7,8,3, 4,7,9,3, 4,9,6,3, 4,9,7,3, 8,7,4,3, 8,7,5,3, 8,9,8,3, 8,9,9,3, 5,0,0,3, 5,0,1,3, 5,0,2,3, 5,0,3,3, 5,0,4,3, 5,0,5,3, 5,0,6,3, 5,0,7,3, 5,0,8,3, 5,0,9,3, 5,8,0,3, 5,8,1,3, 9,0,4,3, 9,0,5,3, 9,8,4,3, 9,8,5,3, 5,1,0,3, 5,1,1,3, 5,1,2,3, 5,1,3,3, 5,1,4,3, 5,1,5,3, 5,1,6,3, 5,1,7,3, 5,1,8,3, 5,1,9,3, 5,9,0,3, 5,9,1,3, 9,1,4,3, 9,1,5,3, 9,9,4,3, 9,9,5,3, 5,2,0,3, 5,2,1,3, 5,2,2,3, 5,2,3,3, 5,2,4,3, 5,2,5,3, 5,2,6,3, 5,2,7,3, 5,2,8,3, 5,2,9,3, 5,8,2,3, 5,8,3,3, 9,2,4,3, 9,2,5,3, 9,4,8,3, 9,4,9,3, 5,3,0,3, 5,3,1,3, 5,3,2,3, 5,3,3,3, 5,3,4,3, 5,3,5,3, 5,3,6,3, 5,3,7,3, 5,3,8,3, 5,3,9,3, 5,9,2,3, 5,9,3,3, 9,3,4,3, 9,3,5,3, 9,5,8,3, 9,5,9,3, 5,4,0,3, 5,4,1,3, 5,4,2,3, 5,4,3,3, 5,4,4,3, 5,4,5,3, 5,4,6,3, 5,4,7,3, 5,4,8,3, 5,4,9,3, 5,8,4,3, 5,8,5,3, 9,4,4,3, 9,4,5,3, 5,8,8,3, 5,8,9,3, 5,5,0,3, 5,5,1,3, 5,5,2,3, 5,5,3,3, 5,5,4,3, 5,5,5,3, 5,5,6,3, 5,5,7,3, 5,5,8,3, 5,5,9,3, 5,9,4,3, 5,9,5,3, 9,5,4,3, 9,5,5,3, 5,9,8,3, 5,9,9,3, 5,6,0,3, 5,6,1,3, 5,6,2,3, 5,6,3,3, 5,6,4,3, 5,6,5,3, 5,6,6,3, 5,6,7,3, 5,6,8,3, 5,6,9,3, 5,8,6,3, 5,8,7,3, 9,6,4,3, 9,6,5,3, 9,8,8,3, 9,8,9,3, 5,7,0,3, 5,7,1,3, 5,7,2,3, 5,7,3,3, 5,7,4,3, 5,7,5,3, 5,7,6,3, 5,7,7,3, 5,7,8,3, 5,7,9,3, 5,9,6,3, 5,9,7,3, 9,7,4,3, 9,7,5,3, 9,9,8,3, 9,9,9,3, 6,0,0,3, 6,0,1,3, 6,0,2,3, 6,0,3,3, 6,0,4,3, 6,0,5,3, 6,0,6,3, 6,0,7,3, 6,0,8,3, 6,0,9,3, 6,8,0,3, 6,8,1,3, 8,0,6,3, 8,0,7,3, 8,8,6,3, 8,8,7,3, 6,1,0,3, 6,1,1,3, 6,1,2,3, 6,1,3,3, 6,1,4,3, 6,1,5,3, 6,1,6,3, 6,1,7,3, 6,1,8,3, 6,1,9,3, 6,9,0,3, 6,9,1,3, 8,1,6,3, 8,1,7,3, 8,9,6,3, 8,9,7,3, 6,2,0,3, 6,2,1,3, 6,2,2,3, 6,2,3,3, 6,2,4,3, 6,2,5,3, 6,2,6,3, 6,2,7,3, 6,2,8,3, 6,2,9,3, 6,8,2,3, 6,8,3,3, 8,2,6,3, 8,2,7,3, 8,6,8,3, 8,6,9,3, 6,3,0,3, 6,3,1,3, 6,3,2,3, 6,3,3,3, 6,3,4,3, 6,3,5,3, 6,3,6,3, 6,3,7,3, 6,3,8,3, 6,3,9,3, 6,9,2,3, 6,9,3,3, 8,3,6,3, 8,3,7,3, 8,7,8,3, 8,7,9,3, 6,4,0,3, 6,4,1,3, 6,4,2,3, 6,4,3,3, 6,4,4,3, 6,4,5,3, 6,4,6,3, 6,4,7,3, 6,4,8,3, 6,4,9,3, 6,8,4,3, 6,8,5,3, 8,4,6,3, 8,4,7,3, 6,8,8,3, 6,8,9,3, 6,5,0,3, 6,5,1,3, 6,5,2,3, 6,5,3,3, 6,5,4,3, 6,5,5,3, 6,5,6,3, 6,5,7,3, 6,5,8,3, 6,5,9,3, 6,9,4,3, 6,9,5,3, 8,5,6,3, 8,5,7,3, 6,9,8,3, 6,9,9,3, 6,6,0,3, 6,6,1,3, 6,6,2,3, 6,6,3,3, 6,6,4,3, 6,6,5,3, 6,6,6,3, 6,6,7,3, 6,6,8,3, 6,6,9,3, 6,8,6,3, 6,8,7,3, 8,6,6,3, 8,6,7,3, 8,8,8,3, 8,8,9,3, 6,7,0,3, 6,7,1,3, 6,7,2,3, 6,7,3,3, 6,7,4,3, 6,7,5,3, 6,7,6,3, 6,7,7,3, 6,7,8,3, 6,7,9,3, 6,9,6,3, 6,9,7,3, 8,7,6,3, 8,7,7,3, 8,9,8,3, 8,9,9,3, 7,0,0,3, 7,0,1,3, 7,0,2,3, 7,0,3,3, 7,0,4,3, 7,0,5,3, 7,0,6,3, 7,0,7,3, 7,0,8,3, 7,0,9,3, 7,8,0,3, 7,8,1,3, 9,0,6,3, 9,0,7,3, 9,8,6,3, 9,8,7,3, 7,1,0,3, 7,1,1,3, 7,1,2,3, 7,1,3,3, 7,1,4,3, 7,1,5,3, 7,1,6,3, 7,1,7,3, 7,1,8,3, 7,1,9,3, 7,9,0,3, 7,9,1,3, 9,1,6,3, 9,1,7,3, 9,9,6,3, 9,9,7,3, 7,2,0,3, 7,2,1,3, 7,2,2,3, 7,2,3,3, 7,2,4,3, 7,2,5,3, 7,2,6,3, 7,2,7,3, 7,2,8,3, 7,2,9,3, 7,8,2,3, 7,8,3,3, 9,2,6,3, 9,2,7,3, 9,6,8,3, 9,6,9,3, 7,3,0,3, 7,3,1,3, 7,3,2,3, 7,3,3,3, 7,3,4,3, 7,3,5,3, 7,3,6,3, 7,3,7,3, 7,3,8,3, 7,3,9,3, 7,9,2,3, 7,9,3,3, 9,3,6,3, 9,3,7,3, 9,7,8,3, 9,7,9,3, 7,4,0,3, 7,4,1,3, 7,4,2,3, 7,4,3,3, 7,4,4,3, 7,4,5,3, 7,4,6,3, 7,4,7,3, 7,4,8,3, 7,4,9,3, 7,8,4,3, 7,8,5,3, 9,4,6,3, 9,4,7,3, 7,8,8,3, 7,8,9,3, 7,5,0,3, 7,5,1,3, 7,5,2,3, 7,5,3,3, 7,5,4,3, 7,5,5,3, 7,5,6,3, 7,5,7,3, 7,5,8,3, 7,5,9,3, 7,9,4,3, 7,9,5,3, 9,5,6,3, 9,5,7,3, 7,9,8,3, 7,9,9,3, 7,6,0,3, 7,6,1,3, 7,6,2,3, 7,6,3,3, 7,6,4,3, 7,6,5,3, 7,6,6,3, 7,6,7,3, 7,6,8,3, 7,6,9,3, 7,8,6,3, 7,8,7,3, 9,6,6,3, 9,6,7,3, 9,8,8,3, 9,8,9,3, 7,7,0,3, 7,7,1,3, 7,7,2,3, 7,7,3,3, 7,7,4,3, 7,7,5,3, 7,7,6,3, 7,7,7,3, 7,7,8,3, 7,7,9,3, 7,9,6,3, 7,9,7,3, 9,7,6,3, 9,7,7,3, 9,9,8,3, 9,9,9,3}; #endif #if defined(DEC_BIN2BCD8) && DEC_BIN2BCD8==1 && !defined(DECBIN2BCD8) #define DECBIN2BCD8 const uint8_t BIN2BCD8[4000]={ 0,0,0,0, 0,0,1,1, 0,0,2,1, 0,0,3,1, 0,0,4,1, 0,0,5,1, 0,0,6,1, 0,0,7,1, 0,0,8,1, 0,0,9,1, 0,1,0,2, 0,1,1,2, 0,1,2,2, 0,1,3,2, 0,1,4,2, 0,1,5,2, 0,1,6,2, 0,1,7,2, 0,1,8,2, 0,1,9,2, 0,2,0,2, 0,2,1,2, 0,2,2,2, 0,2,3,2, 0,2,4,2, 0,2,5,2, 0,2,6,2, 0,2,7,2, 0,2,8,2, 0,2,9,2, 0,3,0,2, 0,3,1,2, 0,3,2,2, 0,3,3,2, 0,3,4,2, 0,3,5,2, 0,3,6,2, 0,3,7,2, 0,3,8,2, 0,3,9,2, 0,4,0,2, 0,4,1,2, 0,4,2,2, 0,4,3,2, 0,4,4,2, 0,4,5,2, 0,4,6,2, 0,4,7,2, 0,4,8,2, 0,4,9,2, 0,5,0,2, 0,5,1,2, 0,5,2,2, 0,5,3,2, 0,5,4,2, 0,5,5,2, 0,5,6,2, 0,5,7,2, 0,5,8,2, 0,5,9,2, 0,6,0,2, 0,6,1,2, 0,6,2,2, 0,6,3,2, 0,6,4,2, 0,6,5,2, 0,6,6,2, 0,6,7,2, 0,6,8,2, 0,6,9,2, 0,7,0,2, 0,7,1,2, 0,7,2,2, 0,7,3,2, 0,7,4,2, 0,7,5,2, 0,7,6,2, 0,7,7,2, 0,7,8,2, 0,7,9,2, 0,8,0,2, 0,8,1,2, 0,8,2,2, 0,8,3,2, 0,8,4,2, 0,8,5,2, 0,8,6,2, 0,8,7,2, 0,8,8,2, 0,8,9,2, 0,9,0,2, 0,9,1,2, 0,9,2,2, 0,9,3,2, 0,9,4,2, 0,9,5,2, 0,9,6,2, 0,9,7,2, 0,9,8,2, 0,9,9,2, 1,0,0,3, 1,0,1,3, 1,0,2,3, 1,0,3,3, 1,0,4,3, 1,0,5,3, 1,0,6,3, 1,0,7,3, 1,0,8,3, 1,0,9,3, 1,1,0,3, 1,1,1,3, 1,1,2,3, 1,1,3,3, 1,1,4,3, 1,1,5,3, 1,1,6,3, 1,1,7,3, 1,1,8,3, 1,1,9,3, 1,2,0,3, 1,2,1,3, 1,2,2,3, 1,2,3,3, 1,2,4,3, 1,2,5,3, 1,2,6,3, 1,2,7,3, 1,2,8,3, 1,2,9,3, 1,3,0,3, 1,3,1,3, 1,3,2,3, 1,3,3,3, 1,3,4,3, 1,3,5,3, 1,3,6,3, 1,3,7,3, 1,3,8,3, 1,3,9,3, 1,4,0,3, 1,4,1,3, 1,4,2,3, 1,4,3,3, 1,4,4,3, 1,4,5,3, 1,4,6,3, 1,4,7,3, 1,4,8,3, 1,4,9,3, 1,5,0,3, 1,5,1,3, 1,5,2,3, 1,5,3,3, 1,5,4,3, 1,5,5,3, 1,5,6,3, 1,5,7,3, 1,5,8,3, 1,5,9,3, 1,6,0,3, 1,6,1,3, 1,6,2,3, 1,6,3,3, 1,6,4,3, 1,6,5,3, 1,6,6,3, 1,6,7,3, 1,6,8,3, 1,6,9,3, 1,7,0,3, 1,7,1,3, 1,7,2,3, 1,7,3,3, 1,7,4,3, 1,7,5,3, 1,7,6,3, 1,7,7,3, 1,7,8,3, 1,7,9,3, 1,8,0,3, 1,8,1,3, 1,8,2,3, 1,8,3,3, 1,8,4,3, 1,8,5,3, 1,8,6,3, 1,8,7,3, 1,8,8,3, 1,8,9,3, 1,9,0,3, 1,9,1,3, 1,9,2,3, 1,9,3,3, 1,9,4,3, 1,9,5,3, 1,9,6,3, 1,9,7,3, 1,9,8,3, 1,9,9,3, 2,0,0,3, 2,0,1,3, 2,0,2,3, 2,0,3,3, 2,0,4,3, 2,0,5,3, 2,0,6,3, 2,0,7,3, 2,0,8,3, 2,0,9,3, 2,1,0,3, 2,1,1,3, 2,1,2,3, 2,1,3,3, 2,1,4,3, 2,1,5,3, 2,1,6,3, 2,1,7,3, 2,1,8,3, 2,1,9,3, 2,2,0,3, 2,2,1,3, 2,2,2,3, 2,2,3,3, 2,2,4,3, 2,2,5,3, 2,2,6,3, 2,2,7,3, 2,2,8,3, 2,2,9,3, 2,3,0,3, 2,3,1,3, 2,3,2,3, 2,3,3,3, 2,3,4,3, 2,3,5,3, 2,3,6,3, 2,3,7,3, 2,3,8,3, 2,3,9,3, 2,4,0,3, 2,4,1,3, 2,4,2,3, 2,4,3,3, 2,4,4,3, 2,4,5,3, 2,4,6,3, 2,4,7,3, 2,4,8,3, 2,4,9,3, 2,5,0,3, 2,5,1,3, 2,5,2,3, 2,5,3,3, 2,5,4,3, 2,5,5,3, 2,5,6,3, 2,5,7,3, 2,5,8,3, 2,5,9,3, 2,6,0,3, 2,6,1,3, 2,6,2,3, 2,6,3,3, 2,6,4,3, 2,6,5,3, 2,6,6,3, 2,6,7,3, 2,6,8,3, 2,6,9,3, 2,7,0,3, 2,7,1,3, 2,7,2,3, 2,7,3,3, 2,7,4,3, 2,7,5,3, 2,7,6,3, 2,7,7,3, 2,7,8,3, 2,7,9,3, 2,8,0,3, 2,8,1,3, 2,8,2,3, 2,8,3,3, 2,8,4,3, 2,8,5,3, 2,8,6,3, 2,8,7,3, 2,8,8,3, 2,8,9,3, 2,9,0,3, 2,9,1,3, 2,9,2,3, 2,9,3,3, 2,9,4,3, 2,9,5,3, 2,9,6,3, 2,9,7,3, 2,9,8,3, 2,9,9,3, 3,0,0,3, 3,0,1,3, 3,0,2,3, 3,0,3,3, 3,0,4,3, 3,0,5,3, 3,0,6,3, 3,0,7,3, 3,0,8,3, 3,0,9,3, 3,1,0,3, 3,1,1,3, 3,1,2,3, 3,1,3,3, 3,1,4,3, 3,1,5,3, 3,1,6,3, 3,1,7,3, 3,1,8,3, 3,1,9,3, 3,2,0,3, 3,2,1,3, 3,2,2,3, 3,2,3,3, 3,2,4,3, 3,2,5,3, 3,2,6,3, 3,2,7,3, 3,2,8,3, 3,2,9,3, 3,3,0,3, 3,3,1,3, 3,3,2,3, 3,3,3,3, 3,3,4,3, 3,3,5,3, 3,3,6,3, 3,3,7,3, 3,3,8,3, 3,3,9,3, 3,4,0,3, 3,4,1,3, 3,4,2,3, 3,4,3,3, 3,4,4,3, 3,4,5,3, 3,4,6,3, 3,4,7,3, 3,4,8,3, 3,4,9,3, 3,5,0,3, 3,5,1,3, 3,5,2,3, 3,5,3,3, 3,5,4,3, 3,5,5,3, 3,5,6,3, 3,5,7,3, 3,5,8,3, 3,5,9,3, 3,6,0,3, 3,6,1,3, 3,6,2,3, 3,6,3,3, 3,6,4,3, 3,6,5,3, 3,6,6,3, 3,6,7,3, 3,6,8,3, 3,6,9,3, 3,7,0,3, 3,7,1,3, 3,7,2,3, 3,7,3,3, 3,7,4,3, 3,7,5,3, 3,7,6,3, 3,7,7,3, 3,7,8,3, 3,7,9,3, 3,8,0,3, 3,8,1,3, 3,8,2,3, 3,8,3,3, 3,8,4,3, 3,8,5,3, 3,8,6,3, 3,8,7,3, 3,8,8,3, 3,8,9,3, 3,9,0,3, 3,9,1,3, 3,9,2,3, 3,9,3,3, 3,9,4,3, 3,9,5,3, 3,9,6,3, 3,9,7,3, 3,9,8,3, 3,9,9,3, 4,0,0,3, 4,0,1,3, 4,0,2,3, 4,0,3,3, 4,0,4,3, 4,0,5,3, 4,0,6,3, 4,0,7,3, 4,0,8,3, 4,0,9,3, 4,1,0,3, 4,1,1,3, 4,1,2,3, 4,1,3,3, 4,1,4,3, 4,1,5,3, 4,1,6,3, 4,1,7,3, 4,1,8,3, 4,1,9,3, 4,2,0,3, 4,2,1,3, 4,2,2,3, 4,2,3,3, 4,2,4,3, 4,2,5,3, 4,2,6,3, 4,2,7,3, 4,2,8,3, 4,2,9,3, 4,3,0,3, 4,3,1,3, 4,3,2,3, 4,3,3,3, 4,3,4,3, 4,3,5,3, 4,3,6,3, 4,3,7,3, 4,3,8,3, 4,3,9,3, 4,4,0,3, 4,4,1,3, 4,4,2,3, 4,4,3,3, 4,4,4,3, 4,4,5,3, 4,4,6,3, 4,4,7,3, 4,4,8,3, 4,4,9,3, 4,5,0,3, 4,5,1,3, 4,5,2,3, 4,5,3,3, 4,5,4,3, 4,5,5,3, 4,5,6,3, 4,5,7,3, 4,5,8,3, 4,5,9,3, 4,6,0,3, 4,6,1,3, 4,6,2,3, 4,6,3,3, 4,6,4,3, 4,6,5,3, 4,6,6,3, 4,6,7,3, 4,6,8,3, 4,6,9,3, 4,7,0,3, 4,7,1,3, 4,7,2,3, 4,7,3,3, 4,7,4,3, 4,7,5,3, 4,7,6,3, 4,7,7,3, 4,7,8,3, 4,7,9,3, 4,8,0,3, 4,8,1,3, 4,8,2,3, 4,8,3,3, 4,8,4,3, 4,8,5,3, 4,8,6,3, 4,8,7,3, 4,8,8,3, 4,8,9,3, 4,9,0,3, 4,9,1,3, 4,9,2,3, 4,9,3,3, 4,9,4,3, 4,9,5,3, 4,9,6,3, 4,9,7,3, 4,9,8,3, 4,9,9,3, 5,0,0,3, 5,0,1,3, 5,0,2,3, 5,0,3,3, 5,0,4,3, 5,0,5,3, 5,0,6,3, 5,0,7,3, 5,0,8,3, 5,0,9,3, 5,1,0,3, 5,1,1,3, 5,1,2,3, 5,1,3,3, 5,1,4,3, 5,1,5,3, 5,1,6,3, 5,1,7,3, 5,1,8,3, 5,1,9,3, 5,2,0,3, 5,2,1,3, 5,2,2,3, 5,2,3,3, 5,2,4,3, 5,2,5,3, 5,2,6,3, 5,2,7,3, 5,2,8,3, 5,2,9,3, 5,3,0,3, 5,3,1,3, 5,3,2,3, 5,3,3,3, 5,3,4,3, 5,3,5,3, 5,3,6,3, 5,3,7,3, 5,3,8,3, 5,3,9,3, 5,4,0,3, 5,4,1,3, 5,4,2,3, 5,4,3,3, 5,4,4,3, 5,4,5,3, 5,4,6,3, 5,4,7,3, 5,4,8,3, 5,4,9,3, 5,5,0,3, 5,5,1,3, 5,5,2,3, 5,5,3,3, 5,5,4,3, 5,5,5,3, 5,5,6,3, 5,5,7,3, 5,5,8,3, 5,5,9,3, 5,6,0,3, 5,6,1,3, 5,6,2,3, 5,6,3,3, 5,6,4,3, 5,6,5,3, 5,6,6,3, 5,6,7,3, 5,6,8,3, 5,6,9,3, 5,7,0,3, 5,7,1,3, 5,7,2,3, 5,7,3,3, 5,7,4,3, 5,7,5,3, 5,7,6,3, 5,7,7,3, 5,7,8,3, 5,7,9,3, 5,8,0,3, 5,8,1,3, 5,8,2,3, 5,8,3,3, 5,8,4,3, 5,8,5,3, 5,8,6,3, 5,8,7,3, 5,8,8,3, 5,8,9,3, 5,9,0,3, 5,9,1,3, 5,9,2,3, 5,9,3,3, 5,9,4,3, 5,9,5,3, 5,9,6,3, 5,9,7,3, 5,9,8,3, 5,9,9,3, 6,0,0,3, 6,0,1,3, 6,0,2,3, 6,0,3,3, 6,0,4,3, 6,0,5,3, 6,0,6,3, 6,0,7,3, 6,0,8,3, 6,0,9,3, 6,1,0,3, 6,1,1,3, 6,1,2,3, 6,1,3,3, 6,1,4,3, 6,1,5,3, 6,1,6,3, 6,1,7,3, 6,1,8,3, 6,1,9,3, 6,2,0,3, 6,2,1,3, 6,2,2,3, 6,2,3,3, 6,2,4,3, 6,2,5,3, 6,2,6,3, 6,2,7,3, 6,2,8,3, 6,2,9,3, 6,3,0,3, 6,3,1,3, 6,3,2,3, 6,3,3,3, 6,3,4,3, 6,3,5,3, 6,3,6,3, 6,3,7,3, 6,3,8,3, 6,3,9,3, 6,4,0,3, 6,4,1,3, 6,4,2,3, 6,4,3,3, 6,4,4,3, 6,4,5,3, 6,4,6,3, 6,4,7,3, 6,4,8,3, 6,4,9,3, 6,5,0,3, 6,5,1,3, 6,5,2,3, 6,5,3,3, 6,5,4,3, 6,5,5,3, 6,5,6,3, 6,5,7,3, 6,5,8,3, 6,5,9,3, 6,6,0,3, 6,6,1,3, 6,6,2,3, 6,6,3,3, 6,6,4,3, 6,6,5,3, 6,6,6,3, 6,6,7,3, 6,6,8,3, 6,6,9,3, 6,7,0,3, 6,7,1,3, 6,7,2,3, 6,7,3,3, 6,7,4,3, 6,7,5,3, 6,7,6,3, 6,7,7,3, 6,7,8,3, 6,7,9,3, 6,8,0,3, 6,8,1,3, 6,8,2,3, 6,8,3,3, 6,8,4,3, 6,8,5,3, 6,8,6,3, 6,8,7,3, 6,8,8,3, 6,8,9,3, 6,9,0,3, 6,9,1,3, 6,9,2,3, 6,9,3,3, 6,9,4,3, 6,9,5,3, 6,9,6,3, 6,9,7,3, 6,9,8,3, 6,9,9,3, 7,0,0,3, 7,0,1,3, 7,0,2,3, 7,0,3,3, 7,0,4,3, 7,0,5,3, 7,0,6,3, 7,0,7,3, 7,0,8,3, 7,0,9,3, 7,1,0,3, 7,1,1,3, 7,1,2,3, 7,1,3,3, 7,1,4,3, 7,1,5,3, 7,1,6,3, 7,1,7,3, 7,1,8,3, 7,1,9,3, 7,2,0,3, 7,2,1,3, 7,2,2,3, 7,2,3,3, 7,2,4,3, 7,2,5,3, 7,2,6,3, 7,2,7,3, 7,2,8,3, 7,2,9,3, 7,3,0,3, 7,3,1,3, 7,3,2,3, 7,3,3,3, 7,3,4,3, 7,3,5,3, 7,3,6,3, 7,3,7,3, 7,3,8,3, 7,3,9,3, 7,4,0,3, 7,4,1,3, 7,4,2,3, 7,4,3,3, 7,4,4,3, 7,4,5,3, 7,4,6,3, 7,4,7,3, 7,4,8,3, 7,4,9,3, 7,5,0,3, 7,5,1,3, 7,5,2,3, 7,5,3,3, 7,5,4,3, 7,5,5,3, 7,5,6,3, 7,5,7,3, 7,5,8,3, 7,5,9,3, 7,6,0,3, 7,6,1,3, 7,6,2,3, 7,6,3,3, 7,6,4,3, 7,6,5,3, 7,6,6,3, 7,6,7,3, 7,6,8,3, 7,6,9,3, 7,7,0,3, 7,7,1,3, 7,7,2,3, 7,7,3,3, 7,7,4,3, 7,7,5,3, 7,7,6,3, 7,7,7,3, 7,7,8,3, 7,7,9,3, 7,8,0,3, 7,8,1,3, 7,8,2,3, 7,8,3,3, 7,8,4,3, 7,8,5,3, 7,8,6,3, 7,8,7,3, 7,8,8,3, 7,8,9,3, 7,9,0,3, 7,9,1,3, 7,9,2,3, 7,9,3,3, 7,9,4,3, 7,9,5,3, 7,9,6,3, 7,9,7,3, 7,9,8,3, 7,9,9,3, 8,0,0,3, 8,0,1,3, 8,0,2,3, 8,0,3,3, 8,0,4,3, 8,0,5,3, 8,0,6,3, 8,0,7,3, 8,0,8,3, 8,0,9,3, 8,1,0,3, 8,1,1,3, 8,1,2,3, 8,1,3,3, 8,1,4,3, 8,1,5,3, 8,1,6,3, 8,1,7,3, 8,1,8,3, 8,1,9,3, 8,2,0,3, 8,2,1,3, 8,2,2,3, 8,2,3,3, 8,2,4,3, 8,2,5,3, 8,2,6,3, 8,2,7,3, 8,2,8,3, 8,2,9,3, 8,3,0,3, 8,3,1,3, 8,3,2,3, 8,3,3,3, 8,3,4,3, 8,3,5,3, 8,3,6,3, 8,3,7,3, 8,3,8,3, 8,3,9,3, 8,4,0,3, 8,4,1,3, 8,4,2,3, 8,4,3,3, 8,4,4,3, 8,4,5,3, 8,4,6,3, 8,4,7,3, 8,4,8,3, 8,4,9,3, 8,5,0,3, 8,5,1,3, 8,5,2,3, 8,5,3,3, 8,5,4,3, 8,5,5,3, 8,5,6,3, 8,5,7,3, 8,5,8,3, 8,5,9,3, 8,6,0,3, 8,6,1,3, 8,6,2,3, 8,6,3,3, 8,6,4,3, 8,6,5,3, 8,6,6,3, 8,6,7,3, 8,6,8,3, 8,6,9,3, 8,7,0,3, 8,7,1,3, 8,7,2,3, 8,7,3,3, 8,7,4,3, 8,7,5,3, 8,7,6,3, 8,7,7,3, 8,7,8,3, 8,7,9,3, 8,8,0,3, 8,8,1,3, 8,8,2,3, 8,8,3,3, 8,8,4,3, 8,8,5,3, 8,8,6,3, 8,8,7,3, 8,8,8,3, 8,8,9,3, 8,9,0,3, 8,9,1,3, 8,9,2,3, 8,9,3,3, 8,9,4,3, 8,9,5,3, 8,9,6,3, 8,9,7,3, 8,9,8,3, 8,9,9,3, 9,0,0,3, 9,0,1,3, 9,0,2,3, 9,0,3,3, 9,0,4,3, 9,0,5,3, 9,0,6,3, 9,0,7,3, 9,0,8,3, 9,0,9,3, 9,1,0,3, 9,1,1,3, 9,1,2,3, 9,1,3,3, 9,1,4,3, 9,1,5,3, 9,1,6,3, 9,1,7,3, 9,1,8,3, 9,1,9,3, 9,2,0,3, 9,2,1,3, 9,2,2,3, 9,2,3,3, 9,2,4,3, 9,2,5,3, 9,2,6,3, 9,2,7,3, 9,2,8,3, 9,2,9,3, 9,3,0,3, 9,3,1,3, 9,3,2,3, 9,3,3,3, 9,3,4,3, 9,3,5,3, 9,3,6,3, 9,3,7,3, 9,3,8,3, 9,3,9,3, 9,4,0,3, 9,4,1,3, 9,4,2,3, 9,4,3,3, 9,4,4,3, 9,4,5,3, 9,4,6,3, 9,4,7,3, 9,4,8,3, 9,4,9,3, 9,5,0,3, 9,5,1,3, 9,5,2,3, 9,5,3,3, 9,5,4,3, 9,5,5,3, 9,5,6,3, 9,5,7,3, 9,5,8,3, 9,5,9,3, 9,6,0,3, 9,6,1,3, 9,6,2,3, 9,6,3,3, 9,6,4,3, 9,6,5,3, 9,6,6,3, 9,6,7,3, 9,6,8,3, 9,6,9,3, 9,7,0,3, 9,7,1,3, 9,7,2,3, 9,7,3,3, 9,7,4,3, 9,7,5,3, 9,7,6,3, 9,7,7,3, 9,7,8,3, 9,7,9,3, 9,8,0,3, 9,8,1,3, 9,8,2,3, 9,8,3,3, 9,8,4,3, 9,8,5,3, 9,8,6,3, 9,8,7,3, 9,8,8,3, 9,8,9,3, 9,9,0,3, 9,9,1,3, 9,9,2,3, 9,9,3,3, 9,9,4,3, 9,9,5,3, 9,9,6,3, 9,9,7,3, 9,9,8,3, 9,9,9,3}; #endif ================================================ FILE: vendor/decNumber/decDouble.c ================================================ /* ------------------------------------------------------------------ */ /* decDouble.c -- decDouble operations module */ /* ------------------------------------------------------------------ */ /* Copyright (c) IBM Corporation, 2000, 2010. All rights reserved. */ /* */ /* This software is made available under the terms of the */ /* ICU License -- ICU 1.8.1 and later. */ /* */ /* The description and User's Guide ("The decNumber C Library") for */ /* this software is included in the package as decNumber.pdf. This */ /* document is also available in HTML, together with specifications, */ /* testcases, and Web links, on the General Decimal Arithmetic page. */ /* */ /* Please send comments, suggestions, and corrections to the author: */ /* mfc@uk.ibm.com */ /* Mike Cowlishaw, IBM Fellow */ /* IBM UK, PO Box 31, Birmingham Road, Warwick CV34 5JL, UK */ /* ------------------------------------------------------------------ */ /* This module comprises decDouble operations (including conversions) */ /* ------------------------------------------------------------------ */ #include "decContext.h" // public includes #include "decDouble.h" // .. /* Constant mappings for shared code */ #define DECPMAX DECDOUBLE_Pmax #define DECEMIN DECDOUBLE_Emin #define DECEMAX DECDOUBLE_Emax #define DECEMAXD DECDOUBLE_EmaxD #define DECBYTES DECDOUBLE_Bytes #define DECSTRING DECDOUBLE_String #define DECECONL DECDOUBLE_EconL #define DECBIAS DECDOUBLE_Bias #define DECLETS DECDOUBLE_Declets #define DECQTINY (-DECDOUBLE_Bias) // parameters of next-wider format #define DECWBYTES DECQUAD_Bytes #define DECWPMAX DECQUAD_Pmax #define DECWECONL DECQUAD_EconL #define DECWBIAS DECQUAD_Bias /* Type and function mappings for shared code */ #define decFloat decDouble // Type name #define decFloatWider decQuad // Type name // Utilities and conversions (binary results, extractors, etc.) #define decFloatFromBCD decDoubleFromBCD #define decFloatFromInt32 decDoubleFromInt32 #define decFloatFromPacked decDoubleFromPacked #define decFloatFromPackedChecked decDoubleFromPackedChecked #define decFloatFromString decDoubleFromString #define decFloatFromUInt32 decDoubleFromUInt32 #define decFloatFromWider decDoubleFromWider #define decFloatGetCoefficient decDoubleGetCoefficient #define decFloatGetExponent decDoubleGetExponent #define decFloatSetCoefficient decDoubleSetCoefficient #define decFloatSetExponent decDoubleSetExponent #define decFloatShow decDoubleShow #define decFloatToBCD decDoubleToBCD #define decFloatToEngString decDoubleToEngString #define decFloatToInt32 decDoubleToInt32 #define decFloatToInt32Exact decDoubleToInt32Exact #define decFloatToPacked decDoubleToPacked #define decFloatToString decDoubleToString #define decFloatToUInt32 decDoubleToUInt32 #define decFloatToUInt32Exact decDoubleToUInt32Exact #define decFloatToWider decDoubleToWider #define decFloatZero decDoubleZero // Computational (result is a decFloat) #define decFloatAbs decDoubleAbs #define decFloatAdd decDoubleAdd #define decFloatAnd decDoubleAnd #define decFloatDivide decDoubleDivide #define decFloatDivideInteger decDoubleDivideInteger #define decFloatFMA decDoubleFMA #define decFloatInvert decDoubleInvert #define decFloatLogB decDoubleLogB #define decFloatMax decDoubleMax #define decFloatMaxMag decDoubleMaxMag #define decFloatMin decDoubleMin #define decFloatMinMag decDoubleMinMag #define decFloatMinus decDoubleMinus #define decFloatMultiply decDoubleMultiply #define decFloatNextMinus decDoubleNextMinus #define decFloatNextPlus decDoubleNextPlus #define decFloatNextToward decDoubleNextToward #define decFloatOr decDoubleOr #define decFloatPlus decDoublePlus #define decFloatQuantize decDoubleQuantize #define decFloatReduce decDoubleReduce #define decFloatRemainder decDoubleRemainder #define decFloatRemainderNear decDoubleRemainderNear #define decFloatRotate decDoubleRotate #define decFloatScaleB decDoubleScaleB #define decFloatShift decDoubleShift #define decFloatSubtract decDoubleSubtract #define decFloatToIntegralValue decDoubleToIntegralValue #define decFloatToIntegralExact decDoubleToIntegralExact #define decFloatXor decDoubleXor // Comparisons #define decFloatCompare decDoubleCompare #define decFloatCompareSignal decDoubleCompareSignal #define decFloatCompareTotal decDoubleCompareTotal #define decFloatCompareTotalMag decDoubleCompareTotalMag // Copies #define decFloatCanonical decDoubleCanonical #define decFloatCopy decDoubleCopy #define decFloatCopyAbs decDoubleCopyAbs #define decFloatCopyNegate decDoubleCopyNegate #define decFloatCopySign decDoubleCopySign // Non-computational #define decFloatClass decDoubleClass #define decFloatClassString decDoubleClassString #define decFloatDigits decDoubleDigits #define decFloatIsCanonical decDoubleIsCanonical #define decFloatIsFinite decDoubleIsFinite #define decFloatIsInfinite decDoubleIsInfinite #define decFloatIsInteger decDoubleIsInteger #define decFloatIsLogical decDoubleIsLogical #define decFloatIsNaN decDoubleIsNaN #define decFloatIsNegative decDoubleIsNegative #define decFloatIsNormal decDoubleIsNormal #define decFloatIsPositive decDoubleIsPositive #define decFloatIsSignaling decDoubleIsSignaling #define decFloatIsSignalling decDoubleIsSignalling #define decFloatIsSigned decDoubleIsSigned #define decFloatIsSubnormal decDoubleIsSubnormal #define decFloatIsZero decDoubleIsZero #define decFloatRadix decDoubleRadix #define decFloatSameQuantum decDoubleSameQuantum #define decFloatVersion decDoubleVersion #include "decNumberLocal.h" // local includes (need DECPMAX) #include "decCommon.c" // non-arithmetic decFloat routines #include "decBasic.c" // basic formats routines ================================================ FILE: vendor/decNumber/decDouble.h ================================================ /* ------------------------------------------------------------------ */ /* decDouble.h -- Decimal 64-bit format module header */ /* ------------------------------------------------------------------ */ /* Copyright (c) IBM Corporation, 2000, 2010. All rights reserved. */ /* */ /* This software is made available under the terms of the */ /* ICU License -- ICU 1.8.1 and later. */ /* */ /* The description and User's Guide ("The decNumber C Library") for */ /* this software is included in the package as decNumber.pdf. This */ /* document is also available in HTML, together with specifications, */ /* testcases, and Web links, on the General Decimal Arithmetic page. */ /* */ /* Please send comments, suggestions, and corrections to the author: */ /* mfc@uk.ibm.com */ /* Mike Cowlishaw, IBM Fellow */ /* IBM UK, PO Box 31, Birmingham Road, Warwick CV34 5JL, UK */ /* ------------------------------------------------------------------ */ #if !defined(DECDOUBLE) #define DECDOUBLE #define DECDOUBLENAME "decimalDouble" /* Short name */ #define DECDOUBLETITLE "Decimal 64-bit datum" /* Verbose name */ #define DECDOUBLEAUTHOR "Mike Cowlishaw" /* Who to blame */ /* parameters for decDoubles */ #define DECDOUBLE_Bytes 8 /* length */ #define DECDOUBLE_Pmax 16 /* maximum precision (digits) */ #define DECDOUBLE_Emin -383 /* minimum adjusted exponent */ #define DECDOUBLE_Emax 384 /* maximum adjusted exponent */ #define DECDOUBLE_EmaxD 3 /* maximum exponent digits */ #define DECDOUBLE_Bias 398 /* bias for the exponent */ #define DECDOUBLE_String 25 /* maximum string length, +1 */ #define DECDOUBLE_EconL 8 /* exponent continuation length */ #define DECDOUBLE_Declets 5 /* count of declets */ /* highest biased exponent (Elimit-1) */ #define DECDOUBLE_Ehigh (DECDOUBLE_Emax + DECDOUBLE_Bias - (DECDOUBLE_Pmax-1)) /* Required includes */ #include "decContext.h" #include "decQuad.h" /* The decDouble decimal 64-bit type, accessible by all sizes */ typedef union { uint8_t bytes[DECDOUBLE_Bytes]; /* fields: 1, 5, 8, 50 bits */ uint16_t shorts[DECDOUBLE_Bytes/2]; uint32_t words[DECDOUBLE_Bytes/4]; #if DECUSE64 uint64_t longs[DECDOUBLE_Bytes/8]; #endif } decDouble; /* ---------------------------------------------------------------- */ /* Routines -- implemented as decFloat routines in common files */ /* ---------------------------------------------------------------- */ /* Utilities and conversions, extractors, etc.) */ extern decDouble * decDoubleFromBCD(decDouble *, int32_t, const uint8_t *, int32_t); extern decDouble * decDoubleFromInt32(decDouble *, int32_t); extern decDouble * decDoubleFromPacked(decDouble *, int32_t, const uint8_t *); extern decDouble * decDoubleFromPackedChecked(decDouble *, int32_t, const uint8_t *); extern decDouble * decDoubleFromString(decDouble *, const char *, decContext *); extern decDouble * decDoubleFromUInt32(decDouble *, uint32_t); extern decDouble * decDoubleFromWider(decDouble *, const decQuad *, decContext *); extern int32_t decDoubleGetCoefficient(const decDouble *, uint8_t *); extern int32_t decDoubleGetExponent(const decDouble *); extern decDouble * decDoubleSetCoefficient(decDouble *, const uint8_t *, int32_t); extern decDouble * decDoubleSetExponent(decDouble *, decContext *, int32_t); extern void decDoubleShow(const decDouble *, const char *); extern int32_t decDoubleToBCD(const decDouble *, int32_t *, uint8_t *); extern char * decDoubleToEngString(const decDouble *, char *); extern int32_t decDoubleToInt32(const decDouble *, decContext *, enum rounding); extern int32_t decDoubleToInt32Exact(const decDouble *, decContext *, enum rounding); extern int32_t decDoubleToPacked(const decDouble *, int32_t *, uint8_t *); extern char * decDoubleToString(const decDouble *, char *); extern uint32_t decDoubleToUInt32(const decDouble *, decContext *, enum rounding); extern uint32_t decDoubleToUInt32Exact(const decDouble *, decContext *, enum rounding); extern decQuad * decDoubleToWider(const decDouble *, decQuad *); extern decDouble * decDoubleZero(decDouble *); /* Computational (result is a decDouble) */ extern decDouble * decDoubleAbs(decDouble *, const decDouble *, decContext *); extern decDouble * decDoubleAdd(decDouble *, const decDouble *, const decDouble *, decContext *); extern decDouble * decDoubleAnd(decDouble *, const decDouble *, const decDouble *, decContext *); extern decDouble * decDoubleDivide(decDouble *, const decDouble *, const decDouble *, decContext *); extern decDouble * decDoubleDivideInteger(decDouble *, const decDouble *, const decDouble *, decContext *); extern decDouble * decDoubleFMA(decDouble *, const decDouble *, const decDouble *, const decDouble *, decContext *); extern decDouble * decDoubleInvert(decDouble *, const decDouble *, decContext *); extern decDouble * decDoubleLogB(decDouble *, const decDouble *, decContext *); extern decDouble * decDoubleMax(decDouble *, const decDouble *, const decDouble *, decContext *); extern decDouble * decDoubleMaxMag(decDouble *, const decDouble *, const decDouble *, decContext *); extern decDouble * decDoubleMin(decDouble *, const decDouble *, const decDouble *, decContext *); extern decDouble * decDoubleMinMag(decDouble *, const decDouble *, const decDouble *, decContext *); extern decDouble * decDoubleMinus(decDouble *, const decDouble *, decContext *); extern decDouble * decDoubleMultiply(decDouble *, const decDouble *, const decDouble *, decContext *); extern decDouble * decDoubleNextMinus(decDouble *, const decDouble *, decContext *); extern decDouble * decDoubleNextPlus(decDouble *, const decDouble *, decContext *); extern decDouble * decDoubleNextToward(decDouble *, const decDouble *, const decDouble *, decContext *); extern decDouble * decDoubleOr(decDouble *, const decDouble *, const decDouble *, decContext *); extern decDouble * decDoublePlus(decDouble *, const decDouble *, decContext *); extern decDouble * decDoubleQuantize(decDouble *, const decDouble *, const decDouble *, decContext *); extern decDouble * decDoubleReduce(decDouble *, const decDouble *, decContext *); extern decDouble * decDoubleRemainder(decDouble *, const decDouble *, const decDouble *, decContext *); extern decDouble * decDoubleRemainderNear(decDouble *, const decDouble *, const decDouble *, decContext *); extern decDouble * decDoubleRotate(decDouble *, const decDouble *, const decDouble *, decContext *); extern decDouble * decDoubleScaleB(decDouble *, const decDouble *, const decDouble *, decContext *); extern decDouble * decDoubleShift(decDouble *, const decDouble *, const decDouble *, decContext *); extern decDouble * decDoubleSubtract(decDouble *, const decDouble *, const decDouble *, decContext *); extern decDouble * decDoubleToIntegralValue(decDouble *, const decDouble *, decContext *, enum rounding); extern decDouble * decDoubleToIntegralExact(decDouble *, const decDouble *, decContext *); extern decDouble * decDoubleXor(decDouble *, const decDouble *, const decDouble *, decContext *); /* Comparisons */ extern decDouble * decDoubleCompare(decDouble *, const decDouble *, const decDouble *, decContext *); extern decDouble * decDoubleCompareSignal(decDouble *, const decDouble *, const decDouble *, decContext *); extern decDouble * decDoubleCompareTotal(decDouble *, const decDouble *, const decDouble *); extern decDouble * decDoubleCompareTotalMag(decDouble *, const decDouble *, const decDouble *); /* Copies */ extern decDouble * decDoubleCanonical(decDouble *, const decDouble *); extern decDouble * decDoubleCopy(decDouble *, const decDouble *); extern decDouble * decDoubleCopyAbs(decDouble *, const decDouble *); extern decDouble * decDoubleCopyNegate(decDouble *, const decDouble *); extern decDouble * decDoubleCopySign(decDouble *, const decDouble *, const decDouble *); /* Non-computational */ extern enum decClass decDoubleClass(const decDouble *); extern const char * decDoubleClassString(const decDouble *); extern uint32_t decDoubleDigits(const decDouble *); extern uint32_t decDoubleIsCanonical(const decDouble *); extern uint32_t decDoubleIsFinite(const decDouble *); extern uint32_t decDoubleIsInfinite(const decDouble *); extern uint32_t decDoubleIsInteger(const decDouble *); extern uint32_t decDoubleIsLogical(const decDouble *); extern uint32_t decDoubleIsNaN(const decDouble *); extern uint32_t decDoubleIsNegative(const decDouble *); extern uint32_t decDoubleIsNormal(const decDouble *); extern uint32_t decDoubleIsPositive(const decDouble *); extern uint32_t decDoubleIsSignaling(const decDouble *); extern uint32_t decDoubleIsSignalling(const decDouble *); extern uint32_t decDoubleIsSigned(const decDouble *); extern uint32_t decDoubleIsSubnormal(const decDouble *); extern uint32_t decDoubleIsZero(const decDouble *); extern uint32_t decDoubleRadix(const decDouble *); extern uint32_t decDoubleSameQuantum(const decDouble *, const decDouble *); extern const char * decDoubleVersion(void); /* decNumber conversions; these are implemented as macros so as not */ /* to force a dependency on decimal64 and decNumber in decDouble. */ /* decDoubleFromNumber returns a decimal64 * to avoid warnings. */ #define decDoubleToNumber(dq, dn) decimal64ToNumber((decimal64 *)(dq), dn) #define decDoubleFromNumber(dq, dn, set) decimal64FromNumber((decimal64 *)(dq), dn, set) #endif ================================================ FILE: vendor/decNumber/decNumber.c ================================================ /* ------------------------------------------------------------------ */ /* Decimal Number arithmetic module */ /* ------------------------------------------------------------------ */ /* Copyright (c) IBM Corporation, 2000, 2009. All rights reserved. */ /* */ /* This software is made available under the terms of the */ /* ICU License -- ICU 1.8.1 and later. */ /* */ /* The description and User's Guide ("The decNumber C Library") for */ /* this software is called decNumber.pdf. This document is */ /* available, together with arithmetic and format specifications, */ /* testcases, and Web links, on the General Decimal Arithmetic page. */ /* */ /* Please send comments, suggestions, and corrections to the author: */ /* mfc@uk.ibm.com */ /* Mike Cowlishaw, IBM Fellow */ /* IBM UK, PO Box 31, Birmingham Road, Warwick CV34 5JL, UK */ /* ------------------------------------------------------------------ */ /* This module comprises the routines for arbitrary-precision General */ /* Decimal Arithmetic as defined in the specification which may be */ /* found on the General Decimal Arithmetic pages. It implements both */ /* the full ('extended') arithmetic and the simpler ('subset') */ /* arithmetic. */ /* */ /* Usage notes: */ /* */ /* 1. This code is ANSI C89 except: */ /* */ /* a) C99 line comments (double forward slash) are used. (Most C */ /* compilers accept these. If yours does not, a simple script */ /* can be used to convert them to ANSI C comments.) */ /* */ /* b) Types from C99 stdint.h are used. If you do not have this */ /* header file, see the User's Guide section of the decNumber */ /* documentation; this lists the necessary definitions. */ /* */ /* c) If DECDPUN>4 or DECUSE64=1, the C99 64-bit int64_t and */ /* uint64_t types may be used. To avoid these, set DECUSE64=0 */ /* and DECDPUN<=4 (see documentation). */ /* */ /* The code also conforms to C99 restrictions; in particular, */ /* strict aliasing rules are observed. */ /* */ /* 2. The decNumber format which this library uses is optimized for */ /* efficient processing of relatively short numbers; in particular */ /* it allows the use of fixed sized structures and minimizes copy */ /* and move operations. It does, however, support arbitrary */ /* precision (up to 999,999,999 digits) and arbitrary exponent */ /* range (Emax in the range 0 through 999,999,999 and Emin in the */ /* range -999,999,999 through 0). Mathematical functions (for */ /* example decNumberExp) as identified below are restricted more */ /* tightly: digits, emax, and -emin in the context must be <= */ /* DEC_MAX_MATH (999999), and their operand(s) must be within */ /* these bounds. */ /* */ /* 3. Logical functions are further restricted; their operands must */ /* be finite, positive, have an exponent of zero, and all digits */ /* must be either 0 or 1. The result will only contain digits */ /* which are 0 or 1 (and will have exponent=0 and a sign of 0). */ /* */ /* 4. Operands to operator functions are never modified unless they */ /* are also specified to be the result number (which is always */ /* permitted). Other than that case, operands must not overlap. */ /* */ /* 5. Error handling: the type of the error is ORed into the status */ /* flags in the current context (decContext structure). The */ /* SIGFPE signal is then raised if the corresponding trap-enabler */ /* flag in the decContext is set (is 1). */ /* */ /* It is the responsibility of the caller to clear the status */ /* flags as required. */ /* */ /* The result of any routine which returns a number will always */ /* be a valid number (which may be a special value, such as an */ /* Infinity or NaN). */ /* */ /* 6. The decNumber format is not an exchangeable concrete */ /* representation as it comprises fields which may be machine- */ /* dependent (packed or unpacked, or special length, for example). */ /* Canonical conversions to and from strings are provided; other */ /* conversions are available in separate modules. */ /* */ /* 7. Normally, input operands are assumed to be valid. Set DECCHECK */ /* to 1 for extended operand checking (including NULL operands). */ /* Results are undefined if a badly-formed structure (or a NULL */ /* pointer to a structure) is provided, though with DECCHECK */ /* enabled the operator routines are protected against exceptions. */ /* (Except if the result pointer is NULL, which is unrecoverable.) */ /* */ /* However, the routines will never cause exceptions if they are */ /* given well-formed operands, even if the value of the operands */ /* is inappropriate for the operation and DECCHECK is not set. */ /* (Except for SIGFPE, as and where documented.) */ /* */ /* 8. Subset arithmetic is available only if DECSUBSET is set to 1. */ /* ------------------------------------------------------------------ */ /* Implementation notes for maintenance of this module: */ /* */ /* 1. Storage leak protection: Routines which use malloc are not */ /* permitted to use return for fastpath or error exits (i.e., */ /* they follow strict structured programming conventions). */ /* Instead they have a do{}while(0); construct surrounding the */ /* code which is protected -- break may be used to exit this. */ /* Other routines can safely use the return statement inline. */ /* */ /* Storage leak accounting can be enabled using DECALLOC. */ /* */ /* 2. All loops use the for(;;) construct. Any do construct does */ /* not loop; it is for allocation protection as just described. */ /* */ /* 3. Setting status in the context must always be the very last */ /* action in a routine, as non-0 status may raise a trap and hence */ /* the call to set status may not return (if the handler uses long */ /* jump). Therefore all cleanup must be done first. In general, */ /* to achieve this status is accumulated and is only applied just */ /* before return by calling decContextSetStatus (via decStatus). */ /* */ /* Routines which allocate storage cannot, in general, use the */ /* 'top level' routines which could cause a non-returning */ /* transfer of control. The decXxxxOp routines are safe (do not */ /* call decStatus even if traps are set in the context) and should */ /* be used instead (they are also a little faster). */ /* */ /* 4. Exponent checking is minimized by allowing the exponent to */ /* grow outside its limits during calculations, provided that */ /* the decFinalize function is called later. Multiplication and */ /* division, and intermediate calculations in exponentiation, */ /* require more careful checks because of the risk of 31-bit */ /* overflow (the most negative valid exponent is -1999999997, for */ /* a 999999999-digit number with adjusted exponent of -999999999). */ /* */ /* 5. Rounding is deferred until finalization of results, with any */ /* 'off to the right' data being represented as a single digit */ /* residue (in the range -1 through 9). This avoids any double- */ /* rounding when more than one shortening takes place (for */ /* example, when a result is subnormal). */ /* */ /* 6. The digits count is allowed to rise to a multiple of DECDPUN */ /* during many operations, so whole Units are handled and exact */ /* accounting of digits is not needed. The correct digits value */ /* is found by decGetDigits, which accounts for leading zeros. */ /* This must be called before any rounding if the number of digits */ /* is not known exactly. */ /* */ /* 7. The multiply-by-reciprocal 'trick' is used for partitioning */ /* numbers up to four digits, using appropriate constants. This */ /* is not useful for longer numbers because overflow of 32 bits */ /* would lead to 4 multiplies, which is almost as expensive as */ /* a divide (unless a floating-point or 64-bit multiply is */ /* assumed to be available). */ /* */ /* 8. Unusual abbreviations that may be used in the commentary: */ /* lhs -- left hand side (operand, of an operation) */ /* lsd -- least significant digit (of coefficient) */ /* lsu -- least significant Unit (of coefficient) */ /* msd -- most significant digit (of coefficient) */ /* msi -- most significant item (in an array) */ /* msu -- most significant Unit (of coefficient) */ /* rhs -- right hand side (operand, of an operation) */ /* +ve -- positive */ /* -ve -- negative */ /* ** -- raise to the power */ /* ------------------------------------------------------------------ */ #include // for malloc, free, etc. #include // for printf [if needed] #include // for strcpy #include // for lower #include "decNumber.h" // base number library #include "decNumberLocal.h" // decNumber local types, etc. /* Constants */ // Public lookup table used by the D2U macro const uByte d2utable[DECMAXD2U+1]=D2UTABLE; #define DECVERB 1 // set to 1 for verbose DECCHECK #define powers DECPOWERS // old internal name // Local constants #define DIVIDE 0x80 // Divide operators #define REMAINDER 0x40 // .. #define DIVIDEINT 0x20 // .. #define REMNEAR 0x10 // .. #define COMPARE 0x01 // Compare operators #define COMPMAX 0x02 // .. #define COMPMIN 0x03 // .. #define COMPTOTAL 0x04 // .. #define COMPNAN 0x05 // .. [NaN processing] #define COMPSIG 0x06 // .. [signaling COMPARE] #define COMPMAXMAG 0x07 // .. #define COMPMINMAG 0x08 // .. #define DEC_sNaN 0x40000000 // local status: sNaN signal #define BADINT (Int)0x80000000 // most-negative Int; error indicator // Next two indicate an integer >= 10**6, and its parity (bottom bit) #define BIGEVEN (Int)0x80000002 #define BIGODD (Int)0x80000003 static Unit uarrone[1]={1}; // Unit array of 1, used for incrementing /* Granularity-dependent code */ #if DECDPUN<=4 #define eInt Int // extended integer #define ueInt uInt // unsigned extended integer // Constant multipliers for divide-by-power-of five using reciprocal // multiply, after removing powers of 2 by shifting, and final shift // of 17 [we only need up to **4] static const uInt multies[]={131073, 26215, 5243, 1049, 210}; // QUOT10 -- macro to return the quotient of unit u divided by 10**n #define QUOT10(u, n) ((((uInt)(u)>>(n))*multies[n])>>17) #else // For DECDPUN>4 non-ANSI-89 64-bit types are needed. #if !DECUSE64 #error decNumber.c: DECUSE64 must be 1 when DECDPUN>4 #endif #define eInt Long // extended integer #define ueInt uLong // unsigned extended integer #endif /* Local routines */ static decNumber * decAddOp(decNumber *, const decNumber *, const decNumber *, decContext *, uByte, uInt *); static Flag decBiStr(const char *, const char *, const char *); static uInt decCheckMath(const decNumber *, decContext *, uInt *); static void decApplyRound(decNumber *, decContext *, Int, uInt *); static Int decCompare(const decNumber *lhs, const decNumber *rhs, Flag); static decNumber * decCompareOp(decNumber *, const decNumber *, const decNumber *, decContext *, Flag, uInt *); static void decCopyFit(decNumber *, const decNumber *, decContext *, Int *, uInt *); static decNumber * decDecap(decNumber *, Int); static decNumber * decDivideOp(decNumber *, const decNumber *, const decNumber *, decContext *, Flag, uInt *); static decNumber * decExpOp(decNumber *, const decNumber *, decContext *, uInt *); static void decFinalize(decNumber *, decContext *, Int *, uInt *); static Int decGetDigits(Unit *, Int); static Int decGetInt(const decNumber *); static decNumber * decLnOp(decNumber *, const decNumber *, decContext *, uInt *); static decNumber * decMultiplyOp(decNumber *, const decNumber *, const decNumber *, decContext *, uInt *); static decNumber * decNaNs(decNumber *, const decNumber *, const decNumber *, decContext *, uInt *); static decNumber * decQuantizeOp(decNumber *, const decNumber *, const decNumber *, decContext *, Flag, uInt *); static void decReverse(Unit *, Unit *); static void decSetCoeff(decNumber *, decContext *, const Unit *, Int, Int *, uInt *); static void decSetMaxValue(decNumber *, decContext *); static void decSetOverflow(decNumber *, decContext *, uInt *); static void decSetSubnormal(decNumber *, decContext *, Int *, uInt *); static Int decShiftToLeast(Unit *, Int, Int); static Int decShiftToMost(Unit *, Int, Int); static void decStatus(decNumber *, uInt, decContext *); static void decToString(const decNumber *, char[], Flag); static decNumber * decTrim(decNumber *, decContext *, Flag, Flag, Int *); static Int decUnitAddSub(const Unit *, Int, const Unit *, Int, Int, Unit *, Int); static Int decUnitCompare(const Unit *, Int, const Unit *, Int, Int); #if !DECSUBSET /* decFinish == decFinalize when no subset arithmetic needed */ #define decFinish(a,b,c,d) decFinalize(a,b,c,d) #else static void decFinish(decNumber *, decContext *, Int *, uInt *); static decNumber * decRoundOperand(const decNumber *, decContext *, uInt *); #endif /* Local macros */ // masked special-values bits #define SPECIALARG (rhs->bits & DECSPECIAL) #define SPECIALARGS ((lhs->bits | rhs->bits) & DECSPECIAL) /* Diagnostic macros, etc. */ #if DECALLOC // Handle malloc/free accounting. If enabled, our accountable routines // are used; otherwise the code just goes straight to the system malloc // and free routines. #define malloc(a) decMalloc(a) #define free(a) decFree(a) #define DECFENCE 0x5a // corruption detector // 'Our' malloc and free: static void *decMalloc(size_t); static void decFree(void *); uInt decAllocBytes=0; // count of bytes allocated // Note that DECALLOC code only checks for storage buffer overflow. // To check for memory leaks, the decAllocBytes variable must be // checked to be 0 at appropriate times (e.g., after the test // harness completes a set of tests). This checking may be unreliable // if the testing is done in a multi-thread environment. #endif #if DECCHECK // Optional checking routines. Enabling these means that decNumber // and decContext operands to operator routines are checked for // correctness. This roughly doubles the execution time of the // fastest routines (and adds 600+ bytes), so should not normally be // used in 'production'. // decCheckInexact is used to check that inexact results have a full // complement of digits (where appropriate -- this is not the case // for Quantize, for example) #define DECUNRESU ((decNumber *)(void *)0xffffffff) #define DECUNUSED ((const decNumber *)(void *)0xffffffff) #define DECUNCONT ((decContext *)(void *)(0xffffffff)) static Flag decCheckOperands(decNumber *, const decNumber *, const decNumber *, decContext *); static Flag decCheckNumber(const decNumber *); static void decCheckInexact(const decNumber *, decContext *); #endif #if DECTRACE || DECCHECK // Optional trace/debugging routines (may or may not be used) void decNumberShow(const decNumber *); // displays the components of a number static void decDumpAr(char, const Unit *, Int); #endif /* ================================================================== */ /* Conversions */ /* ================================================================== */ /* ------------------------------------------------------------------ */ /* from-int32 -- conversion from Int or uInt */ /* */ /* dn is the decNumber to receive the integer */ /* in or uin is the integer to be converted */ /* returns dn */ /* */ /* No error is possible. */ /* ------------------------------------------------------------------ */ decNumber * decNumberFromInt32(decNumber *dn, Int in) { uInt unsig; if (in>=0) unsig=in; else { // negative (possibly BADINT) if (in==BADINT) unsig=(uInt)1073741824*2; // special case else unsig=-in; // invert } // in is now positive decNumberFromUInt32(dn, unsig); if (in<0) dn->bits=DECNEG; // sign needed return dn; } // decNumberFromInt32 decNumber * decNumberFromUInt32(decNumber *dn, uInt uin) { Unit *up; // work pointer decNumberZero(dn); // clean if (uin==0) return dn; // [or decGetDigits bad call] for (up=dn->lsu; uin>0; up++) { *up=(Unit)(uin%(DECDPUNMAX+1)); uin=uin/(DECDPUNMAX+1); } dn->digits=decGetDigits(dn->lsu, up-dn->lsu); return dn; } // decNumberFromUInt32 /* ------------------------------------------------------------------ */ /* to-int32 -- conversion to Int or uInt */ /* */ /* dn is the decNumber to convert */ /* set is the context for reporting errors */ /* returns the converted decNumber, or 0 if Invalid is set */ /* */ /* Invalid is set if the decNumber does not have exponent==0 or if */ /* it is a NaN, Infinite, or out-of-range. */ /* ------------------------------------------------------------------ */ Int decNumberToInt32(const decNumber *dn, decContext *set) { #if DECCHECK if (decCheckOperands(DECUNRESU, DECUNUSED, dn, set)) return 0; #endif // special or too many digits, or bad exponent if (dn->bits&DECSPECIAL || dn->digits>10 || dn->exponent!=0) ; // bad else { // is a finite integer with 10 or fewer digits Int d; // work const Unit *up; // .. uInt hi=0, lo; // .. up=dn->lsu; // -> lsu lo=*up; // get 1 to 9 digits #if DECDPUN>1 // split to higher hi=lo/10; lo=lo%10; #endif up++; // collect remaining Units, if any, into hi for (d=DECDPUN; ddigits; up++, d+=DECDPUN) hi+=*up*powers[d-1]; // now low has the lsd, hi the remainder if (hi>214748364 || (hi==214748364 && lo>7)) { // out of range? // most-negative is a reprieve if (dn->bits&DECNEG && hi==214748364 && lo==8) return 0x80000000; // bad -- drop through } else { // in-range always Int i=X10(hi)+lo; if (dn->bits&DECNEG) return -i; return i; } } // integer decContextSetStatus(set, DEC_Invalid_operation); // [may not return] return 0; } // decNumberToInt32 uInt decNumberToUInt32(const decNumber *dn, decContext *set) { #if DECCHECK if (decCheckOperands(DECUNRESU, DECUNUSED, dn, set)) return 0; #endif // special or too many digits, or bad exponent, or negative (<0) if (dn->bits&DECSPECIAL || dn->digits>10 || dn->exponent!=0 || (dn->bits&DECNEG && !ISZERO(dn))); // bad else { // is a finite integer with 10 or fewer digits Int d; // work const Unit *up; // .. uInt hi=0, lo; // .. up=dn->lsu; // -> lsu lo=*up; // get 1 to 9 digits #if DECDPUN>1 // split to higher hi=lo/10; lo=lo%10; #endif up++; // collect remaining Units, if any, into hi for (d=DECDPUN; ddigits; up++, d+=DECDPUN) hi+=*up*powers[d-1]; // now low has the lsd, hi the remainder if (hi>429496729 || (hi==429496729 && lo>5)) ; // no reprieve possible else return X10(hi)+lo; } // integer decContextSetStatus(set, DEC_Invalid_operation); // [may not return] return 0; } // decNumberToUInt32 /* ------------------------------------------------------------------ */ /* to-scientific-string -- conversion to numeric string */ /* to-engineering-string -- conversion to numeric string */ /* */ /* decNumberToString(dn, string); */ /* decNumberToEngString(dn, string); */ /* */ /* dn is the decNumber to convert */ /* string is the string where the result will be laid out */ /* */ /* string must be at least dn->digits+14 characters long */ /* */ /* No error is possible, and no status can be set. */ /* ------------------------------------------------------------------ */ char * decNumberToString(const decNumber *dn, char *string){ decToString(dn, string, 0); return string; } // DecNumberToString char * decNumberToEngString(const decNumber *dn, char *string){ decToString(dn, string, 1); return string; } // DecNumberToEngString /* ------------------------------------------------------------------ */ /* to-number -- conversion from numeric string */ /* */ /* decNumberFromString -- convert string to decNumber */ /* dn -- the number structure to fill */ /* chars[] -- the string to convert ('\0' terminated) */ /* set -- the context used for processing any error, */ /* determining the maximum precision available */ /* (set.digits), determining the maximum and minimum */ /* exponent (set.emax and set.emin), determining if */ /* extended values are allowed, and checking the */ /* rounding mode if overflow occurs or rounding is */ /* needed. */ /* */ /* The length of the coefficient and the size of the exponent are */ /* checked by this routine, so the correct error (Underflow or */ /* Overflow) can be reported or rounding applied, as necessary. */ /* */ /* If bad syntax is detected, the result will be a quiet NaN. */ /* ------------------------------------------------------------------ */ decNumber * decNumberFromString(decNumber *dn, const char chars[], decContext *set) { Int exponent=0; // working exponent [assume 0] uByte bits=0; // working flags [assume +ve] Unit *res; // where result will be built Unit resbuff[SD2U(DECBUFFER+9)];// local buffer in case need temporary // [+9 allows for ln() constants] Unit *allocres=NULL; // -> allocated result, iff allocated Int d=0; // count of digits found in decimal part const char *dotchar=NULL; // where dot was found const char *cfirst=chars; // -> first character of decimal part const char *last=NULL; // -> last digit of decimal part const char *c; // work Unit *up; // .. #if DECDPUN>1 Int cut, out; // .. #endif Int residue; // rounding residue uInt status=0; // error code #if DECCHECK if (decCheckOperands(DECUNRESU, DECUNUSED, DECUNUSED, set)) return decNumberZero(dn); #endif do { // status & malloc protection for (c=chars;; c++) { // -> input character if (*c>='0' && *c<='9') { // test for Arabic digit last=c; d++; // count of real digits continue; // still in decimal part } if (*c=='.' && dotchar==NULL) { // first '.' dotchar=c; // record offset into decimal part if (c==cfirst) cfirst++; // first digit must follow continue;} if (c==chars) { // first in string... if (*c=='-') { // valid - sign cfirst++; bits=DECNEG; continue;} if (*c=='+') { // valid + sign cfirst++; continue;} } // *c is not a digit, or a valid +, -, or '.' break; } // c if (last==NULL) { // no digits yet status=DEC_Conversion_syntax;// assume the worst if (*c=='\0') break; // and no more to come... #if DECSUBSET // if subset then infinities and NaNs are not allowed if (!set->extended) break; // hopeless #endif // Infinities and NaNs are possible, here if (dotchar!=NULL) break; // .. unless had a dot decNumberZero(dn); // be optimistic if (decBiStr(c, "infinity", "INFINITY") || decBiStr(c, "inf", "INF")) { dn->bits=bits | DECINF; status=0; // is OK break; // all done } // a NaN expected // 2003.09.10 NaNs are now permitted to have a sign dn->bits=bits | DECNAN; // assume simple NaN if (*c=='s' || *c=='S') { // looks like an sNaN c++; dn->bits=bits | DECSNAN; } if (*c!='n' && *c!='N') break; // check caseless "NaN" c++; if (*c!='a' && *c!='A') break; // .. c++; if (*c!='n' && *c!='N') break; // .. c++; // now either nothing, or nnnn payload, expected // -> start of integer and skip leading 0s [including plain 0] for (cfirst=c; *cfirst=='0';) cfirst++; if (*cfirst=='\0') { // "NaN" or "sNaN", maybe with all 0s status=0; // it's good break; // .. } // something other than 0s; setup last and d as usual [no dots] for (c=cfirst;; c++, d++) { if (*c<'0' || *c>'9') break; // test for Arabic digit last=c; } if (*c!='\0') break; // not all digits if (d>set->digits-1) { // [NB: payload in a decNumber can be full length unless // clamped, in which case can only be digits-1] if (set->clamp) break; if (d>set->digits) break; } // too many digits? // good; drop through to convert the integer to coefficient status=0; // syntax is OK bits=dn->bits; // for copy-back } // last==NULL else if (*c!='\0') { // more to process... // had some digits; exponent is only valid sequence now Flag nege; // 1=negative exponent const char *firstexp; // -> first significant exponent digit status=DEC_Conversion_syntax;// assume the worst uInt expa=0; // accumulator for exponent if (*c!='e' && *c!='E') break; /* Found 'e' or 'E' -- now process explicit exponent */ // 1998.07.11: sign no longer required nege=0; c++; // to (possible) sign if (*c=='-') {nege=1; c++;} else if (*c=='+') c++; if (*c=='\0') break; for (; *c=='0' && *(c+1)!='\0';) c++; // strip insignificant zeros firstexp=c; // save exponent digit place for (; ;c++) { if (*c<'0' || *c>'9') break; // not a digit expa=X10(expa)+(Int)*c-(Int)'0'; } // c // if not now on a '\0', *c must not be a digit if (*c!='\0') break; // (this next test must be after the syntax checks) // if it was too long the exponent may have wrapped, so check // carefully and set it to a certain overflow if wrap possible if (c>=firstexp+9+1) { if (c>firstexp+9+1 || *firstexp>'1') expa=DECNUMMAXE*2; // [up to 1999999999 is OK, for example 1E-1000000998] } exponent=(Int)expa; // save exponent if (nege) exponent=-exponent; // was negative status=0; // is OK } // stuff after digits // Here when whole string has been inspected; syntax is good // cfirst->first digit (never dot), last->last digit (ditto) // strip leading zeros/dot [leave final 0 if all 0's] if (*cfirst=='0') { // [cfirst has stepped over .] for (c=cfirst; cextended) { decNumberZero(dn); // clean result break; // [could be return] } #endif } // at least one leading 0 // Handle decimal point... if (dotchar!=NULL && dotchardigits) res=dn->lsu; // fits into supplied decNumber else { // rounding needed Int needbytes=D2U(d)*sizeof(Unit);// bytes needed res=resbuff; // assume use local buffer if (needbytes>(Int)sizeof(resbuff)) { // too big for local allocres=(Unit *)malloc(needbytes); if (allocres==NULL) {status|=DEC_Insufficient_storage; break;} res=allocres; } } // res now -> number lsu, buffer, or allocated storage for Unit array // Place the coefficient into the selected Unit array // [this is often 70% of the cost of this function when DECDPUN>1] #if DECDPUN>1 out=0; // accumulator up=res+D2U(d)-1; // -> msu cut=d-(up-res)*DECDPUN; // digits in top unit for (c=cfirst;; c++) { // along the digits if (*c=='.') continue; // ignore '.' [don't decrement cut] out=X10(out)+(Int)*c-(Int)'0'; if (c==last) break; // done [never get to trailing '.'] cut--; if (cut>0) continue; // more for this unit *up=(Unit)out; // write unit up--; // prepare for unit below.. cut=DECDPUN; // .. out=0; // .. } // c *up=(Unit)out; // write lsu #else // DECDPUN==1 up=res; // -> lsu for (c=last; c>=cfirst; c--) { // over each character, from least if (*c=='.') continue; // ignore . [don't step up] *up=(Unit)((Int)*c-(Int)'0'); up++; } // c #endif dn->bits=bits; dn->exponent=exponent; dn->digits=d; // if not in number (too long) shorten into the number if (d>set->digits) { residue=0; decSetCoeff(dn, set, res, d, &residue, &status); // always check for overflow or subnormal and round as needed decFinalize(dn, set, &residue, &status); } else { // no rounding, but may still have overflow or subnormal // [these tests are just for performance; finalize repeats them] if ((dn->exponent-1emin-dn->digits) || (dn->exponent-1>set->emax-set->digits)) { residue=0; decFinalize(dn, set, &residue, &status); } } // decNumberShow(dn); } while(0); // [for break] if (allocres!=NULL) free(allocres); // drop any storage used if (status!=0) decStatus(dn, status, set); return dn; } /* decNumberFromString */ /* ================================================================== */ /* Operators */ /* ================================================================== */ /* ------------------------------------------------------------------ */ /* decNumberAbs -- absolute value operator */ /* */ /* This computes C = abs(A) */ /* */ /* res is C, the result. C may be A */ /* rhs is A */ /* set is the context */ /* */ /* See also decNumberCopyAbs for a quiet bitwise version of this. */ /* C must have space for set->digits digits. */ /* ------------------------------------------------------------------ */ /* This has the same effect as decNumberPlus unless A is negative, */ /* in which case it has the same effect as decNumberMinus. */ /* ------------------------------------------------------------------ */ decNumber * decNumberAbs(decNumber *res, const decNumber *rhs, decContext *set) { decNumber dzero; // for 0 uInt status=0; // accumulator #if DECCHECK if (decCheckOperands(res, DECUNUSED, rhs, set)) return res; #endif decNumberZero(&dzero); // set 0 dzero.exponent=rhs->exponent; // [no coefficient expansion] decAddOp(res, &dzero, rhs, set, (uByte)(rhs->bits & DECNEG), &status); if (status!=0) decStatus(res, status, set); #if DECCHECK decCheckInexact(res, set); #endif return res; } // decNumberAbs /* ------------------------------------------------------------------ */ /* decNumberAdd -- add two Numbers */ /* */ /* This computes C = A + B */ /* */ /* res is C, the result. C may be A and/or B (e.g., X=X+X) */ /* lhs is A */ /* rhs is B */ /* set is the context */ /* */ /* C must have space for set->digits digits. */ /* ------------------------------------------------------------------ */ /* This just calls the routine shared with Subtract */ decNumber * decNumberAdd(decNumber *res, const decNumber *lhs, const decNumber *rhs, decContext *set) { uInt status=0; // accumulator decAddOp(res, lhs, rhs, set, 0, &status); if (status!=0) decStatus(res, status, set); #if DECCHECK decCheckInexact(res, set); #endif return res; } // decNumberAdd /* ------------------------------------------------------------------ */ /* decNumberAnd -- AND two Numbers, digitwise */ /* */ /* This computes C = A & B */ /* */ /* res is C, the result. C may be A and/or B (e.g., X=X&X) */ /* lhs is A */ /* rhs is B */ /* set is the context (used for result length and error report) */ /* */ /* C must have space for set->digits digits. */ /* */ /* Logical function restrictions apply (see above); a NaN is */ /* returned with Invalid_operation if a restriction is violated. */ /* ------------------------------------------------------------------ */ decNumber * decNumberAnd(decNumber *res, const decNumber *lhs, const decNumber *rhs, decContext *set) { const Unit *ua, *ub; // -> operands const Unit *msua, *msub; // -> operand msus Unit *uc, *msuc; // -> result and its msu Int msudigs; // digits in res msu #if DECCHECK if (decCheckOperands(res, lhs, rhs, set)) return res; #endif if (lhs->exponent!=0 || decNumberIsSpecial(lhs) || decNumberIsNegative(lhs) || rhs->exponent!=0 || decNumberIsSpecial(rhs) || decNumberIsNegative(rhs)) { decStatus(res, DEC_Invalid_operation, set); return res; } // operands are valid ua=lhs->lsu; // bottom-up ub=rhs->lsu; // .. uc=res->lsu; // .. msua=ua+D2U(lhs->digits)-1; // -> msu of lhs msub=ub+D2U(rhs->digits)-1; // -> msu of rhs msuc=uc+D2U(set->digits)-1; // -> msu of result msudigs=MSUDIGITS(set->digits); // [faster than remainder] for (; uc<=msuc; ua++, ub++, uc++) { // Unit loop Unit a, b; // extract units if (ua>msua) a=0; else a=*ua; if (ub>msub) b=0; else b=*ub; *uc=0; // can now write back if (a|b) { // maybe 1 bits to examine Int i, j; *uc=0; // can now write back // This loop could be unrolled and/or use BIN2BCD tables for (i=0; i1) { decStatus(res, DEC_Invalid_operation, set); return res; } if (uc==msuc && i==msudigs-1) break; // just did final digit } // each digit } // both OK } // each unit // [here uc-1 is the msu of the result] res->digits=decGetDigits(res->lsu, uc-res->lsu); res->exponent=0; // integer res->bits=0; // sign=0 return res; // [no status to set] } // decNumberAnd /* ------------------------------------------------------------------ */ /* decNumberCompare -- compare two Numbers */ /* */ /* This computes C = A ? B */ /* */ /* res is C, the result. C may be A and/or B (e.g., X=X?X) */ /* lhs is A */ /* rhs is B */ /* set is the context */ /* */ /* C must have space for one digit (or NaN). */ /* ------------------------------------------------------------------ */ decNumber * decNumberCompare(decNumber *res, const decNumber *lhs, const decNumber *rhs, decContext *set) { uInt status=0; // accumulator decCompareOp(res, lhs, rhs, set, COMPARE, &status); if (status!=0) decStatus(res, status, set); return res; } // decNumberCompare /* ------------------------------------------------------------------ */ /* decNumberCompareSignal -- compare, signalling on all NaNs */ /* */ /* This computes C = A ? B */ /* */ /* res is C, the result. C may be A and/or B (e.g., X=X?X) */ /* lhs is A */ /* rhs is B */ /* set is the context */ /* */ /* C must have space for one digit (or NaN). */ /* ------------------------------------------------------------------ */ decNumber * decNumberCompareSignal(decNumber *res, const decNumber *lhs, const decNumber *rhs, decContext *set) { uInt status=0; // accumulator decCompareOp(res, lhs, rhs, set, COMPSIG, &status); if (status!=0) decStatus(res, status, set); return res; } // decNumberCompareSignal /* ------------------------------------------------------------------ */ /* decNumberCompareTotal -- compare two Numbers, using total ordering */ /* */ /* This computes C = A ? B, under total ordering */ /* */ /* res is C, the result. C may be A and/or B (e.g., X=X?X) */ /* lhs is A */ /* rhs is B */ /* set is the context */ /* */ /* C must have space for one digit; the result will always be one of */ /* -1, 0, or 1. */ /* ------------------------------------------------------------------ */ decNumber * decNumberCompareTotal(decNumber *res, const decNumber *lhs, const decNumber *rhs, decContext *set) { uInt status=0; // accumulator decCompareOp(res, lhs, rhs, set, COMPTOTAL, &status); if (status!=0) decStatus(res, status, set); return res; } // decNumberCompareTotal /* ------------------------------------------------------------------ */ /* decNumberCompareTotalMag -- compare, total ordering of magnitudes */ /* */ /* This computes C = |A| ? |B|, under total ordering */ /* */ /* res is C, the result. C may be A and/or B (e.g., X=X?X) */ /* lhs is A */ /* rhs is B */ /* set is the context */ /* */ /* C must have space for one digit; the result will always be one of */ /* -1, 0, or 1. */ /* ------------------------------------------------------------------ */ decNumber * decNumberCompareTotalMag(decNumber *res, const decNumber *lhs, const decNumber *rhs, decContext *set) { uInt status=0; // accumulator uInt needbytes; // for space calculations decNumber bufa[D2N(DECBUFFER+1)];// +1 in case DECBUFFER=0 decNumber *allocbufa=NULL; // -> allocated bufa, iff allocated decNumber bufb[D2N(DECBUFFER+1)]; decNumber *allocbufb=NULL; // -> allocated bufb, iff allocated decNumber *a, *b; // temporary pointers #if DECCHECK if (decCheckOperands(res, lhs, rhs, set)) return res; #endif do { // protect allocated storage // if either is negative, take a copy and absolute if (decNumberIsNegative(lhs)) { // lhs<0 a=bufa; needbytes=sizeof(decNumber)+(D2U(lhs->digits)-1)*sizeof(Unit); if (needbytes>sizeof(bufa)) { // need malloc space allocbufa=(decNumber *)malloc(needbytes); if (allocbufa==NULL) { // hopeless -- abandon status|=DEC_Insufficient_storage; break;} a=allocbufa; // use the allocated space } decNumberCopy(a, lhs); // copy content a->bits&=~DECNEG; // .. and clear the sign lhs=a; // use copy from here on } if (decNumberIsNegative(rhs)) { // rhs<0 b=bufb; needbytes=sizeof(decNumber)+(D2U(rhs->digits)-1)*sizeof(Unit); if (needbytes>sizeof(bufb)) { // need malloc space allocbufb=(decNumber *)malloc(needbytes); if (allocbufb==NULL) { // hopeless -- abandon status|=DEC_Insufficient_storage; break;} b=allocbufb; // use the allocated space } decNumberCopy(b, rhs); // copy content b->bits&=~DECNEG; // .. and clear the sign rhs=b; // use copy from here on } decCompareOp(res, lhs, rhs, set, COMPTOTAL, &status); } while(0); // end protected if (allocbufa!=NULL) free(allocbufa); // drop any storage used if (allocbufb!=NULL) free(allocbufb); // .. if (status!=0) decStatus(res, status, set); return res; } // decNumberCompareTotalMag /* ------------------------------------------------------------------ */ /* decNumberDivide -- divide one number by another */ /* */ /* This computes C = A / B */ /* */ /* res is C, the result. C may be A and/or B (e.g., X=X/X) */ /* lhs is A */ /* rhs is B */ /* set is the context */ /* */ /* C must have space for set->digits digits. */ /* ------------------------------------------------------------------ */ decNumber * decNumberDivide(decNumber *res, const decNumber *lhs, const decNumber *rhs, decContext *set) { uInt status=0; // accumulator decDivideOp(res, lhs, rhs, set, DIVIDE, &status); if (status!=0) decStatus(res, status, set); #if DECCHECK decCheckInexact(res, set); #endif return res; } // decNumberDivide /* ------------------------------------------------------------------ */ /* decNumberDivideInteger -- divide and return integer quotient */ /* */ /* This computes C = A # B, where # is the integer divide operator */ /* */ /* res is C, the result. C may be A and/or B (e.g., X=X#X) */ /* lhs is A */ /* rhs is B */ /* set is the context */ /* */ /* C must have space for set->digits digits. */ /* ------------------------------------------------------------------ */ decNumber * decNumberDivideInteger(decNumber *res, const decNumber *lhs, const decNumber *rhs, decContext *set) { uInt status=0; // accumulator decDivideOp(res, lhs, rhs, set, DIVIDEINT, &status); if (status!=0) decStatus(res, status, set); return res; } // decNumberDivideInteger /* ------------------------------------------------------------------ */ /* decNumberExp -- exponentiation */ /* */ /* This computes C = exp(A) */ /* */ /* res is C, the result. C may be A */ /* rhs is A */ /* set is the context; note that rounding mode has no effect */ /* */ /* C must have space for set->digits digits. */ /* */ /* Mathematical function restrictions apply (see above); a NaN is */ /* returned with Invalid_operation if a restriction is violated. */ /* */ /* Finite results will always be full precision and Inexact, except */ /* when A is a zero or -Infinity (giving 1 or 0 respectively). */ /* */ /* An Inexact result is rounded using DEC_ROUND_HALF_EVEN; it will */ /* almost always be correctly rounded, but may be up to 1 ulp in */ /* error in rare cases. */ /* ------------------------------------------------------------------ */ /* This is a wrapper for decExpOp which can handle the slightly wider */ /* (double) range needed by Ln (which has to be able to calculate */ /* exp(-a) where a can be the tiniest number (Ntiny). */ /* ------------------------------------------------------------------ */ decNumber * decNumberExp(decNumber *res, const decNumber *rhs, decContext *set) { uInt status=0; // accumulator #if DECSUBSET decNumber *allocrhs=NULL; // non-NULL if rounded rhs allocated #endif #if DECCHECK if (decCheckOperands(res, DECUNUSED, rhs, set)) return res; #endif // Check restrictions; these restrictions ensure that if h=8 (see // decExpOp) then the result will either overflow or underflow to 0. // Other math functions restrict the input range, too, for inverses. // If not violated then carry out the operation. if (!decCheckMath(rhs, set, &status)) do { // protect allocation #if DECSUBSET if (!set->extended) { // reduce operand and set lostDigits status, as needed if (rhs->digits>set->digits) { allocrhs=decRoundOperand(rhs, set, &status); if (allocrhs==NULL) break; rhs=allocrhs; } } #endif decExpOp(res, rhs, set, &status); } while(0); // end protected #if DECSUBSET if (allocrhs !=NULL) free(allocrhs); // drop any storage used #endif // apply significant status if (status!=0) decStatus(res, status, set); #if DECCHECK decCheckInexact(res, set); #endif return res; } // decNumberExp /* ------------------------------------------------------------------ */ /* decNumberFMA -- fused multiply add */ /* */ /* This computes D = (A * B) + C with only one rounding */ /* */ /* res is D, the result. D may be A or B or C (e.g., X=FMA(X,X,X)) */ /* lhs is A */ /* rhs is B */ /* fhs is C [far hand side] */ /* set is the context */ /* */ /* Mathematical function restrictions apply (see above); a NaN is */ /* returned with Invalid_operation if a restriction is violated. */ /* */ /* C must have space for set->digits digits. */ /* ------------------------------------------------------------------ */ decNumber * decNumberFMA(decNumber *res, const decNumber *lhs, const decNumber *rhs, const decNumber *fhs, decContext *set) { uInt status=0; // accumulator decContext dcmul; // context for the multiplication uInt needbytes; // for space calculations decNumber bufa[D2N(DECBUFFER*2+1)]; decNumber *allocbufa=NULL; // -> allocated bufa, iff allocated decNumber *acc; // accumulator pointer decNumber dzero; // work #if DECCHECK if (decCheckOperands(res, lhs, rhs, set)) return res; if (decCheckOperands(res, fhs, DECUNUSED, set)) return res; #endif do { // protect allocated storage #if DECSUBSET if (!set->extended) { // [undefined if subset] status|=DEC_Invalid_operation; break;} #endif // Check math restrictions [these ensure no overflow or underflow] if ((!decNumberIsSpecial(lhs) && decCheckMath(lhs, set, &status)) || (!decNumberIsSpecial(rhs) && decCheckMath(rhs, set, &status)) || (!decNumberIsSpecial(fhs) && decCheckMath(fhs, set, &status))) break; // set up context for multiply dcmul=*set; dcmul.digits=lhs->digits+rhs->digits; // just enough // [The above may be an over-estimate for subset arithmetic, but that's OK] dcmul.emax=DEC_MAX_EMAX; // effectively unbounded .. dcmul.emin=DEC_MIN_EMIN; // [thanks to Math restrictions] // set up decNumber space to receive the result of the multiply acc=bufa; // may fit needbytes=sizeof(decNumber)+(D2U(dcmul.digits)-1)*sizeof(Unit); if (needbytes>sizeof(bufa)) { // need malloc space allocbufa=(decNumber *)malloc(needbytes); if (allocbufa==NULL) { // hopeless -- abandon status|=DEC_Insufficient_storage; break;} acc=allocbufa; // use the allocated space } // multiply with extended range and necessary precision //printf("emin=%ld\n", dcmul.emin); decMultiplyOp(acc, lhs, rhs, &dcmul, &status); // Only Invalid operation (from sNaN or Inf * 0) is possible in // status; if either is seen than ignore fhs (in case it is // another sNaN) and set acc to NaN unless we had an sNaN // [decMultiplyOp leaves that to caller] // Note sNaN has to go through addOp to shorten payload if // necessary if ((status&DEC_Invalid_operation)!=0) { if (!(status&DEC_sNaN)) { // but be true invalid decNumberZero(res); // acc not yet set res->bits=DECNAN; break; } decNumberZero(&dzero); // make 0 (any non-NaN would do) fhs=&dzero; // use that } #if DECCHECK else { // multiply was OK if (status!=0) printf("Status=%08lx after FMA multiply\n", (LI)status); } #endif // add the third operand and result -> res, and all is done decAddOp(res, acc, fhs, set, 0, &status); } while(0); // end protected if (allocbufa!=NULL) free(allocbufa); // drop any storage used if (status!=0) decStatus(res, status, set); #if DECCHECK decCheckInexact(res, set); #endif return res; } // decNumberFMA /* ------------------------------------------------------------------ */ /* decNumberInvert -- invert a Number, digitwise */ /* */ /* This computes C = ~A */ /* */ /* res is C, the result. C may be A (e.g., X=~X) */ /* rhs is A */ /* set is the context (used for result length and error report) */ /* */ /* C must have space for set->digits digits. */ /* */ /* Logical function restrictions apply (see above); a NaN is */ /* returned with Invalid_operation if a restriction is violated. */ /* ------------------------------------------------------------------ */ decNumber * decNumberInvert(decNumber *res, const decNumber *rhs, decContext *set) { const Unit *ua, *msua; // -> operand and its msu Unit *uc, *msuc; // -> result and its msu Int msudigs; // digits in res msu #if DECCHECK if (decCheckOperands(res, DECUNUSED, rhs, set)) return res; #endif if (rhs->exponent!=0 || decNumberIsSpecial(rhs) || decNumberIsNegative(rhs)) { decStatus(res, DEC_Invalid_operation, set); return res; } // operand is valid ua=rhs->lsu; // bottom-up uc=res->lsu; // .. msua=ua+D2U(rhs->digits)-1; // -> msu of rhs msuc=uc+D2U(set->digits)-1; // -> msu of result msudigs=MSUDIGITS(set->digits); // [faster than remainder] for (; uc<=msuc; ua++, uc++) { // Unit loop Unit a; // extract unit Int i, j; // work if (ua>msua) a=0; else a=*ua; *uc=0; // can now write back // always need to examine all bits in rhs // This loop could be unrolled and/or use BIN2BCD tables for (i=0; i1) { decStatus(res, DEC_Invalid_operation, set); return res; } if (uc==msuc && i==msudigs-1) break; // just did final digit } // each digit } // each unit // [here uc-1 is the msu of the result] res->digits=decGetDigits(res->lsu, uc-res->lsu); res->exponent=0; // integer res->bits=0; // sign=0 return res; // [no status to set] } // decNumberInvert /* ------------------------------------------------------------------ */ /* decNumberLn -- natural logarithm */ /* */ /* This computes C = ln(A) */ /* */ /* res is C, the result. C may be A */ /* rhs is A */ /* set is the context; note that rounding mode has no effect */ /* */ /* C must have space for set->digits digits. */ /* */ /* Notable cases: */ /* A<0 -> Invalid */ /* A=0 -> -Infinity (Exact) */ /* A=+Infinity -> +Infinity (Exact) */ /* A=1 exactly -> 0 (Exact) */ /* */ /* Mathematical function restrictions apply (see above); a NaN is */ /* returned with Invalid_operation if a restriction is violated. */ /* */ /* An Inexact result is rounded using DEC_ROUND_HALF_EVEN; it will */ /* almost always be correctly rounded, but may be up to 1 ulp in */ /* error in rare cases. */ /* ------------------------------------------------------------------ */ /* This is a wrapper for decLnOp which can handle the slightly wider */ /* (+11) range needed by Ln, Log10, etc. (which may have to be able */ /* to calculate at p+e+2). */ /* ------------------------------------------------------------------ */ decNumber * decNumberLn(decNumber *res, const decNumber *rhs, decContext *set) { uInt status=0; // accumulator #if DECSUBSET decNumber *allocrhs=NULL; // non-NULL if rounded rhs allocated #endif #if DECCHECK if (decCheckOperands(res, DECUNUSED, rhs, set)) return res; #endif // Check restrictions; this is a math function; if not violated // then carry out the operation. if (!decCheckMath(rhs, set, &status)) do { // protect allocation #if DECSUBSET if (!set->extended) { // reduce operand and set lostDigits status, as needed if (rhs->digits>set->digits) { allocrhs=decRoundOperand(rhs, set, &status); if (allocrhs==NULL) break; rhs=allocrhs; } // special check in subset for rhs=0 if (ISZERO(rhs)) { // +/- zeros -> error status|=DEC_Invalid_operation; break;} } // extended=0 #endif decLnOp(res, rhs, set, &status); } while(0); // end protected #if DECSUBSET if (allocrhs !=NULL) free(allocrhs); // drop any storage used #endif // apply significant status if (status!=0) decStatus(res, status, set); #if DECCHECK decCheckInexact(res, set); #endif return res; } // decNumberLn /* ------------------------------------------------------------------ */ /* decNumberLogB - get adjusted exponent, by 754 rules */ /* */ /* This computes C = adjustedexponent(A) */ /* */ /* res is C, the result. C may be A */ /* rhs is A */ /* set is the context, used only for digits and status */ /* */ /* For an unrounded result, digits may need to be 10 (A might have */ /* 10**9 digits and an exponent of +999999999, or one digit and an */ /* exponent of -1999999999). */ /* */ /* This returns the adjusted exponent of A after (in theory) padding */ /* with zeros on the right to set->digits digits while keeping the */ /* same value. The exponent is not limited by emin/emax. */ /* */ /* Notable cases: */ /* A<0 -> Use |A| */ /* A=0 -> -Infinity (Division by zero) */ /* A=Infinite -> +Infinity (Exact) */ /* A=1 exactly -> 0 (Exact) */ /* NaNs are propagated as usual */ /* ------------------------------------------------------------------ */ decNumber * decNumberLogB(decNumber *res, const decNumber *rhs, decContext *set) { uInt status=0; // accumulator #if DECCHECK if (decCheckOperands(res, DECUNUSED, rhs, set)) return res; #endif // NaNs as usual; Infinities return +Infinity; 0->oops if (decNumberIsNaN(rhs)) decNaNs(res, rhs, NULL, set, &status); else if (decNumberIsInfinite(rhs)) decNumberCopyAbs(res, rhs); else if (decNumberIsZero(rhs)) { decNumberZero(res); // prepare for Infinity res->bits=DECNEG|DECINF; // -Infinity status|=DEC_Division_by_zero; // as per 754 } else { // finite non-zero Int ae=rhs->exponent+rhs->digits-1; // adjusted exponent if (set->digits>=10) decNumberFromInt32(res, ae); // lay it out else { decNumber buft[D2N(10)]; // temporary number decNumber *t=buft; // .. decNumberFromInt32(t, ae); // lay it out decNumberPlus(res, t, set); // round as necessary } } if (status!=0) decStatus(res, status, set); return res; } // decNumberLogB /* ------------------------------------------------------------------ */ /* decNumberLog10 -- logarithm in base 10 */ /* */ /* This computes C = log10(A) */ /* */ /* res is C, the result. C may be A */ /* rhs is A */ /* set is the context; note that rounding mode has no effect */ /* */ /* C must have space for set->digits digits. */ /* */ /* Notable cases: */ /* A<0 -> Invalid */ /* A=0 -> -Infinity (Exact) */ /* A=+Infinity -> +Infinity (Exact) */ /* A=10**n (if n is an integer) -> n (Exact) */ /* */ /* Mathematical function restrictions apply (see above); a NaN is */ /* returned with Invalid_operation if a restriction is violated. */ /* */ /* An Inexact result is rounded using DEC_ROUND_HALF_EVEN; it will */ /* almost always be correctly rounded, but may be up to 1 ulp in */ /* error in rare cases. */ /* ------------------------------------------------------------------ */ /* This calculates ln(A)/ln(10) using appropriate precision. For */ /* ln(A) this is the max(p, rhs->digits + t) + 3, where p is the */ /* requested digits and t is the number of digits in the exponent */ /* (maximum 6). For ln(10) it is p + 3; this is often handled by the */ /* fastpath in decLnOp. The final division is done to the requested */ /* precision. */ /* ------------------------------------------------------------------ */ decNumber * decNumberLog10(decNumber *res, const decNumber *rhs, decContext *set) { uInt status=0, ignore=0; // status accumulators uInt needbytes; // for space calculations Int p; // working precision Int t; // digits in exponent of A // buffers for a and b working decimals // (adjustment calculator, same size) decNumber bufa[D2N(DECBUFFER+2)]; decNumber *allocbufa=NULL; // -> allocated bufa, iff allocated decNumber *a=bufa; // temporary a decNumber bufb[D2N(DECBUFFER+2)]; decNumber *allocbufb=NULL; // -> allocated bufb, iff allocated decNumber *b=bufb; // temporary b decNumber bufw[D2N(10)]; // working 2-10 digit number decNumber *w=bufw; // .. #if DECSUBSET decNumber *allocrhs=NULL; // non-NULL if rounded rhs allocated #endif decContext aset; // working context #if DECCHECK if (decCheckOperands(res, DECUNUSED, rhs, set)) return res; #endif // Check restrictions; this is a math function; if not violated // then carry out the operation. if (!decCheckMath(rhs, set, &status)) do { // protect malloc #if DECSUBSET if (!set->extended) { // reduce operand and set lostDigits status, as needed if (rhs->digits>set->digits) { allocrhs=decRoundOperand(rhs, set, &status); if (allocrhs==NULL) break; rhs=allocrhs; } // special check in subset for rhs=0 if (ISZERO(rhs)) { // +/- zeros -> error status|=DEC_Invalid_operation; break;} } // extended=0 #endif decContextDefault(&aset, DEC_INIT_DECIMAL64); // clean context // handle exact powers of 10; only check if +ve finite if (!(rhs->bits&(DECNEG|DECSPECIAL)) && !ISZERO(rhs)) { Int residue=0; // (no residue) uInt copystat=0; // clean status // round to a single digit... aset.digits=1; decCopyFit(w, rhs, &aset, &residue, ©stat); // copy & shorten // if exact and the digit is 1, rhs is a power of 10 if (!(copystat&DEC_Inexact) && w->lsu[0]==1) { // the exponent, conveniently, is the power of 10; making // this the result needs a little care as it might not fit, // so first convert it into the working number, and then move // to res decNumberFromInt32(w, w->exponent); residue=0; decCopyFit(res, w, set, &residue, &status); // copy & round decFinish(res, set, &residue, &status); // cleanup/set flags break; } // not a power of 10 } // not a candidate for exact // simplify the information-content calculation to use 'total // number of digits in a, including exponent' as compared to the // requested digits, as increasing this will only rarely cost an // iteration in ln(a) anyway t=6; // it can never be >6 // allocate space when needed... p=(rhs->digits+t>set->digits?rhs->digits+t:set->digits)+3; needbytes=sizeof(decNumber)+(D2U(p)-1)*sizeof(Unit); if (needbytes>sizeof(bufa)) { // need malloc space allocbufa=(decNumber *)malloc(needbytes); if (allocbufa==NULL) { // hopeless -- abandon status|=DEC_Insufficient_storage; break;} a=allocbufa; // use the allocated space } aset.digits=p; // as calculated aset.emax=DEC_MAX_MATH; // usual bounds aset.emin=-DEC_MAX_MATH; // .. aset.clamp=0; // and no concrete format decLnOp(a, rhs, &aset, &status); // a=ln(rhs) // skip the division if the result so far is infinite, NaN, or // zero, or there was an error; note NaN from sNaN needs copy if (status&DEC_NaNs && !(status&DEC_sNaN)) break; if (a->bits&DECSPECIAL || ISZERO(a)) { decNumberCopy(res, a); // [will fit] break;} // for ln(10) an extra 3 digits of precision are needed p=set->digits+3; needbytes=sizeof(decNumber)+(D2U(p)-1)*sizeof(Unit); if (needbytes>sizeof(bufb)) { // need malloc space allocbufb=(decNumber *)malloc(needbytes); if (allocbufb==NULL) { // hopeless -- abandon status|=DEC_Insufficient_storage; break;} b=allocbufb; // use the allocated space } decNumberZero(w); // set up 10... #if DECDPUN==1 w->lsu[1]=1; w->lsu[0]=0; // .. #else w->lsu[0]=10; // .. #endif w->digits=2; // .. aset.digits=p; decLnOp(b, w, &aset, &ignore); // b=ln(10) aset.digits=set->digits; // for final divide decDivideOp(res, a, b, &aset, DIVIDE, &status); // into result } while(0); // [for break] if (allocbufa!=NULL) free(allocbufa); // drop any storage used if (allocbufb!=NULL) free(allocbufb); // .. #if DECSUBSET if (allocrhs !=NULL) free(allocrhs); // .. #endif // apply significant status if (status!=0) decStatus(res, status, set); #if DECCHECK decCheckInexact(res, set); #endif return res; } // decNumberLog10 /* ------------------------------------------------------------------ */ /* decNumberMax -- compare two Numbers and return the maximum */ /* */ /* This computes C = A ? B, returning the maximum by 754 rules */ /* */ /* res is C, the result. C may be A and/or B (e.g., X=X?X) */ /* lhs is A */ /* rhs is B */ /* set is the context */ /* */ /* C must have space for set->digits digits. */ /* ------------------------------------------------------------------ */ decNumber * decNumberMax(decNumber *res, const decNumber *lhs, const decNumber *rhs, decContext *set) { uInt status=0; // accumulator decCompareOp(res, lhs, rhs, set, COMPMAX, &status); if (status!=0) decStatus(res, status, set); #if DECCHECK decCheckInexact(res, set); #endif return res; } // decNumberMax /* ------------------------------------------------------------------ */ /* decNumberMaxMag -- compare and return the maximum by magnitude */ /* */ /* This computes C = A ? B, returning the maximum by 754 rules */ /* */ /* res is C, the result. C may be A and/or B (e.g., X=X?X) */ /* lhs is A */ /* rhs is B */ /* set is the context */ /* */ /* C must have space for set->digits digits. */ /* ------------------------------------------------------------------ */ decNumber * decNumberMaxMag(decNumber *res, const decNumber *lhs, const decNumber *rhs, decContext *set) { uInt status=0; // accumulator decCompareOp(res, lhs, rhs, set, COMPMAXMAG, &status); if (status!=0) decStatus(res, status, set); #if DECCHECK decCheckInexact(res, set); #endif return res; } // decNumberMaxMag /* ------------------------------------------------------------------ */ /* decNumberMin -- compare two Numbers and return the minimum */ /* */ /* This computes C = A ? B, returning the minimum by 754 rules */ /* */ /* res is C, the result. C may be A and/or B (e.g., X=X?X) */ /* lhs is A */ /* rhs is B */ /* set is the context */ /* */ /* C must have space for set->digits digits. */ /* ------------------------------------------------------------------ */ decNumber * decNumberMin(decNumber *res, const decNumber *lhs, const decNumber *rhs, decContext *set) { uInt status=0; // accumulator decCompareOp(res, lhs, rhs, set, COMPMIN, &status); if (status!=0) decStatus(res, status, set); #if DECCHECK decCheckInexact(res, set); #endif return res; } // decNumberMin /* ------------------------------------------------------------------ */ /* decNumberMinMag -- compare and return the minimum by magnitude */ /* */ /* This computes C = A ? B, returning the minimum by 754 rules */ /* */ /* res is C, the result. C may be A and/or B (e.g., X=X?X) */ /* lhs is A */ /* rhs is B */ /* set is the context */ /* */ /* C must have space for set->digits digits. */ /* ------------------------------------------------------------------ */ decNumber * decNumberMinMag(decNumber *res, const decNumber *lhs, const decNumber *rhs, decContext *set) { uInt status=0; // accumulator decCompareOp(res, lhs, rhs, set, COMPMINMAG, &status); if (status!=0) decStatus(res, status, set); #if DECCHECK decCheckInexact(res, set); #endif return res; } // decNumberMinMag /* ------------------------------------------------------------------ */ /* decNumberMinus -- prefix minus operator */ /* */ /* This computes C = 0 - A */ /* */ /* res is C, the result. C may be A */ /* rhs is A */ /* set is the context */ /* */ /* See also decNumberCopyNegate for a quiet bitwise version of this. */ /* C must have space for set->digits digits. */ /* ------------------------------------------------------------------ */ /* Simply use AddOp for the subtract, which will do the necessary. */ /* ------------------------------------------------------------------ */ decNumber * decNumberMinus(decNumber *res, const decNumber *rhs, decContext *set) { decNumber dzero; uInt status=0; // accumulator #if DECCHECK if (decCheckOperands(res, DECUNUSED, rhs, set)) return res; #endif decNumberZero(&dzero); // make 0 dzero.exponent=rhs->exponent; // [no coefficient expansion] decAddOp(res, &dzero, rhs, set, DECNEG, &status); if (status!=0) decStatus(res, status, set); #if DECCHECK decCheckInexact(res, set); #endif return res; } // decNumberMinus /* ------------------------------------------------------------------ */ /* decNumberNextMinus -- next towards -Infinity */ /* */ /* This computes C = A - infinitesimal, rounded towards -Infinity */ /* */ /* res is C, the result. C may be A */ /* rhs is A */ /* set is the context */ /* */ /* This is a generalization of 754 NextDown. */ /* ------------------------------------------------------------------ */ decNumber * decNumberNextMinus(decNumber *res, const decNumber *rhs, decContext *set) { decNumber dtiny; // constant decContext workset=*set; // work uInt status=0; // accumulator #if DECCHECK if (decCheckOperands(res, DECUNUSED, rhs, set)) return res; #endif // +Infinity is the special case if ((rhs->bits&(DECINF|DECNEG))==DECINF) { decSetMaxValue(res, set); // is +ve // there is no status to set return res; } decNumberZero(&dtiny); // start with 0 dtiny.lsu[0]=1; // make number that is .. dtiny.exponent=DEC_MIN_EMIN-1; // .. smaller than tiniest workset.round=DEC_ROUND_FLOOR; decAddOp(res, rhs, &dtiny, &workset, DECNEG, &status); status&=DEC_Invalid_operation|DEC_sNaN; // only sNaN Invalid please if (status!=0) decStatus(res, status, set); return res; } // decNumberNextMinus /* ------------------------------------------------------------------ */ /* decNumberNextPlus -- next towards +Infinity */ /* */ /* This computes C = A + infinitesimal, rounded towards +Infinity */ /* */ /* res is C, the result. C may be A */ /* rhs is A */ /* set is the context */ /* */ /* This is a generalization of 754 NextUp. */ /* ------------------------------------------------------------------ */ decNumber * decNumberNextPlus(decNumber *res, const decNumber *rhs, decContext *set) { decNumber dtiny; // constant decContext workset=*set; // work uInt status=0; // accumulator #if DECCHECK if (decCheckOperands(res, DECUNUSED, rhs, set)) return res; #endif // -Infinity is the special case if ((rhs->bits&(DECINF|DECNEG))==(DECINF|DECNEG)) { decSetMaxValue(res, set); res->bits=DECNEG; // negative // there is no status to set return res; } decNumberZero(&dtiny); // start with 0 dtiny.lsu[0]=1; // make number that is .. dtiny.exponent=DEC_MIN_EMIN-1; // .. smaller than tiniest workset.round=DEC_ROUND_CEILING; decAddOp(res, rhs, &dtiny, &workset, 0, &status); status&=DEC_Invalid_operation|DEC_sNaN; // only sNaN Invalid please if (status!=0) decStatus(res, status, set); return res; } // decNumberNextPlus /* ------------------------------------------------------------------ */ /* decNumberNextToward -- next towards rhs */ /* */ /* This computes C = A +/- infinitesimal, rounded towards */ /* +/-Infinity in the direction of B, as per 754-1985 nextafter */ /* modified during revision but dropped from 754-2008. */ /* */ /* res is C, the result. C may be A or B. */ /* lhs is A */ /* rhs is B */ /* set is the context */ /* */ /* This is a generalization of 754-1985 NextAfter. */ /* ------------------------------------------------------------------ */ decNumber * decNumberNextToward(decNumber *res, const decNumber *lhs, const decNumber *rhs, decContext *set) { decNumber dtiny; // constant decContext workset=*set; // work Int result; // .. uInt status=0; // accumulator #if DECCHECK if (decCheckOperands(res, lhs, rhs, set)) return res; #endif if (decNumberIsNaN(lhs) || decNumberIsNaN(rhs)) { decNaNs(res, lhs, rhs, set, &status); } else { // Is numeric, so no chance of sNaN Invalid, etc. result=decCompare(lhs, rhs, 0); // sign matters if (result==BADINT) status|=DEC_Insufficient_storage; // rare else { // valid compare if (result==0) decNumberCopySign(res, lhs, rhs); // easy else { // differ: need NextPlus or NextMinus uByte sub; // add or subtract if (result<0) { // lhsbits&(DECINF|DECNEG))==(DECINF|DECNEG)) { decSetMaxValue(res, set); res->bits=DECNEG; // negative return res; // there is no status to set } workset.round=DEC_ROUND_CEILING; sub=0; // add, please } // plus else { // lhs>rhs, do nextminus // +Infinity is the special case if ((lhs->bits&(DECINF|DECNEG))==DECINF) { decSetMaxValue(res, set); return res; // there is no status to set } workset.round=DEC_ROUND_FLOOR; sub=DECNEG; // subtract, please } // minus decNumberZero(&dtiny); // start with 0 dtiny.lsu[0]=1; // make number that is .. dtiny.exponent=DEC_MIN_EMIN-1; // .. smaller than tiniest decAddOp(res, lhs, &dtiny, &workset, sub, &status); // + or - // turn off exceptions if the result is a normal number // (including Nmin), otherwise let all status through if (decNumberIsNormal(res, set)) status=0; } // unequal } // compare OK } // numeric if (status!=0) decStatus(res, status, set); return res; } // decNumberNextToward /* ------------------------------------------------------------------ */ /* decNumberOr -- OR two Numbers, digitwise */ /* */ /* This computes C = A | B */ /* */ /* res is C, the result. C may be A and/or B (e.g., X=X|X) */ /* lhs is A */ /* rhs is B */ /* set is the context (used for result length and error report) */ /* */ /* C must have space for set->digits digits. */ /* */ /* Logical function restrictions apply (see above); a NaN is */ /* returned with Invalid_operation if a restriction is violated. */ /* ------------------------------------------------------------------ */ decNumber * decNumberOr(decNumber *res, const decNumber *lhs, const decNumber *rhs, decContext *set) { const Unit *ua, *ub; // -> operands const Unit *msua, *msub; // -> operand msus Unit *uc, *msuc; // -> result and its msu Int msudigs; // digits in res msu #if DECCHECK if (decCheckOperands(res, lhs, rhs, set)) return res; #endif if (lhs->exponent!=0 || decNumberIsSpecial(lhs) || decNumberIsNegative(lhs) || rhs->exponent!=0 || decNumberIsSpecial(rhs) || decNumberIsNegative(rhs)) { decStatus(res, DEC_Invalid_operation, set); return res; } // operands are valid ua=lhs->lsu; // bottom-up ub=rhs->lsu; // .. uc=res->lsu; // .. msua=ua+D2U(lhs->digits)-1; // -> msu of lhs msub=ub+D2U(rhs->digits)-1; // -> msu of rhs msuc=uc+D2U(set->digits)-1; // -> msu of result msudigs=MSUDIGITS(set->digits); // [faster than remainder] for (; uc<=msuc; ua++, ub++, uc++) { // Unit loop Unit a, b; // extract units if (ua>msua) a=0; else a=*ua; if (ub>msub) b=0; else b=*ub; *uc=0; // can now write back if (a|b) { // maybe 1 bits to examine Int i, j; // This loop could be unrolled and/or use BIN2BCD tables for (i=0; i1) { decStatus(res, DEC_Invalid_operation, set); return res; } if (uc==msuc && i==msudigs-1) break; // just did final digit } // each digit } // non-zero } // each unit // [here uc-1 is the msu of the result] res->digits=decGetDigits(res->lsu, uc-res->lsu); res->exponent=0; // integer res->bits=0; // sign=0 return res; // [no status to set] } // decNumberOr /* ------------------------------------------------------------------ */ /* decNumberPlus -- prefix plus operator */ /* */ /* This computes C = 0 + A */ /* */ /* res is C, the result. C may be A */ /* rhs is A */ /* set is the context */ /* */ /* See also decNumberCopy for a quiet bitwise version of this. */ /* C must have space for set->digits digits. */ /* ------------------------------------------------------------------ */ /* This simply uses AddOp; Add will take fast path after preparing A. */ /* Performance is a concern here, as this routine is often used to */ /* check operands and apply rounding and overflow/underflow testing. */ /* ------------------------------------------------------------------ */ decNumber * decNumberPlus(decNumber *res, const decNumber *rhs, decContext *set) { decNumber dzero; uInt status=0; // accumulator #if DECCHECK if (decCheckOperands(res, DECUNUSED, rhs, set)) return res; #endif decNumberZero(&dzero); // make 0 dzero.exponent=rhs->exponent; // [no coefficient expansion] decAddOp(res, &dzero, rhs, set, 0, &status); if (status!=0) decStatus(res, status, set); #if DECCHECK decCheckInexact(res, set); #endif return res; } // decNumberPlus /* ------------------------------------------------------------------ */ /* decNumberMultiply -- multiply two Numbers */ /* */ /* This computes C = A x B */ /* */ /* res is C, the result. C may be A and/or B (e.g., X=X+X) */ /* lhs is A */ /* rhs is B */ /* set is the context */ /* */ /* C must have space for set->digits digits. */ /* ------------------------------------------------------------------ */ decNumber * decNumberMultiply(decNumber *res, const decNumber *lhs, const decNumber *rhs, decContext *set) { uInt status=0; // accumulator decMultiplyOp(res, lhs, rhs, set, &status); if (status!=0) decStatus(res, status, set); #if DECCHECK decCheckInexact(res, set); #endif return res; } // decNumberMultiply /* ------------------------------------------------------------------ */ /* decNumberPower -- raise a number to a power */ /* */ /* This computes C = A ** B */ /* */ /* res is C, the result. C may be A and/or B (e.g., X=X**X) */ /* lhs is A */ /* rhs is B */ /* set is the context */ /* */ /* C must have space for set->digits digits. */ /* */ /* Mathematical function restrictions apply (see above); a NaN is */ /* returned with Invalid_operation if a restriction is violated. */ /* */ /* However, if 1999999997<=B<=999999999 and B is an integer then the */ /* restrictions on A and the context are relaxed to the usual bounds, */ /* for compatibility with the earlier (integer power only) version */ /* of this function. */ /* */ /* When B is an integer, the result may be exact, even if rounded. */ /* */ /* The final result is rounded according to the context; it will */ /* almost always be correctly rounded, but may be up to 1 ulp in */ /* error in rare cases. */ /* ------------------------------------------------------------------ */ decNumber * decNumberPower(decNumber *res, const decNumber *lhs, const decNumber *rhs, decContext *set) { #if DECSUBSET decNumber *alloclhs=NULL; // non-NULL if rounded lhs allocated decNumber *allocrhs=NULL; // .., rhs #endif decNumber *allocdac=NULL; // -> allocated acc buffer, iff used decNumber *allocinv=NULL; // -> allocated 1/x buffer, iff used Int reqdigits=set->digits; // requested DIGITS Int n; // rhs in binary Flag rhsint=0; // 1 if rhs is an integer Flag useint=0; // 1 if can use integer calculation Flag isoddint=0; // 1 if rhs is an integer and odd Int i; // work #if DECSUBSET Int dropped; // .. #endif uInt needbytes; // buffer size needed Flag seenbit; // seen a bit while powering Int residue=0; // rounding residue uInt status=0; // accumulators uByte bits=0; // result sign if errors decContext aset; // working context decNumber dnOne; // work value 1... // local accumulator buffer [a decNumber, with digits+elength+1 digits] decNumber dacbuff[D2N(DECBUFFER+9)]; decNumber *dac=dacbuff; // -> result accumulator // same again for possible 1/lhs calculation decNumber invbuff[D2N(DECBUFFER+9)]; #if DECCHECK if (decCheckOperands(res, lhs, rhs, set)) return res; #endif do { // protect allocated storage #if DECSUBSET if (!set->extended) { // reduce operands and set status, as needed if (lhs->digits>reqdigits) { alloclhs=decRoundOperand(lhs, set, &status); if (alloclhs==NULL) break; lhs=alloclhs; } if (rhs->digits>reqdigits) { allocrhs=decRoundOperand(rhs, set, &status); if (allocrhs==NULL) break; rhs=allocrhs; } } #endif // [following code does not require input rounding] // handle NaNs and rhs Infinity (lhs infinity is harder) if (SPECIALARGS) { if (decNumberIsNaN(lhs) || decNumberIsNaN(rhs)) { // NaNs decNaNs(res, lhs, rhs, set, &status); break;} if (decNumberIsInfinite(rhs)) { // rhs Infinity Flag rhsneg=rhs->bits&DECNEG; // save rhs sign if (decNumberIsNegative(lhs) // lhs<0 && !decNumberIsZero(lhs)) // .. status|=DEC_Invalid_operation; else { // lhs >=0 decNumberZero(&dnOne); // set up 1 dnOne.lsu[0]=1; decNumberCompare(dac, lhs, &dnOne, set); // lhs ? 1 decNumberZero(res); // prepare for 0/1/Infinity if (decNumberIsNegative(dac)) { // lhs<1 if (rhsneg) res->bits|=DECINF; // +Infinity [else is +0] } else if (dac->lsu[0]==0) { // lhs=1 // 1**Infinity is inexact, so return fully-padded 1.0000 Int shift=set->digits-1; *res->lsu=1; // was 0, make int 1 res->digits=decShiftToMost(res->lsu, 1, shift); res->exponent=-shift; // make 1.0000... status|=DEC_Inexact|DEC_Rounded; // deemed inexact } else { // lhs>1 if (!rhsneg) res->bits|=DECINF; // +Infinity [else is +0] } } // lhs>=0 break;} // [lhs infinity drops through] } // specials // Original rhs may be an integer that fits and is in range n=decGetInt(rhs); if (n!=BADINT) { // it is an integer rhsint=1; // record the fact for 1**n isoddint=(Flag)n&1; // [works even if big] if (n!=BIGEVEN && n!=BIGODD) // can use integer path? useint=1; // looks good } if (decNumberIsNegative(lhs) // -x .. && isoddint) bits=DECNEG; // .. to an odd power // handle LHS infinity if (decNumberIsInfinite(lhs)) { // [NaNs already handled] uByte rbits=rhs->bits; // save decNumberZero(res); // prepare if (n==0) *res->lsu=1; // [-]Inf**0 => 1 else { // -Inf**nonint -> error if (!rhsint && decNumberIsNegative(lhs)) { status|=DEC_Invalid_operation; // -Inf**nonint is error break;} if (!(rbits & DECNEG)) bits|=DECINF; // was not a **-n // [otherwise will be 0 or -0] res->bits=bits; } break;} // similarly handle LHS zero if (decNumberIsZero(lhs)) { if (n==0) { // 0**0 => Error #if DECSUBSET if (!set->extended) { // [unless subset] decNumberZero(res); *res->lsu=1; // return 1 break;} #endif status|=DEC_Invalid_operation; } else { // 0**x uByte rbits=rhs->bits; // save if (rbits & DECNEG) { // was a 0**(-n) #if DECSUBSET if (!set->extended) { // [bad if subset] status|=DEC_Invalid_operation; break;} #endif bits|=DECINF; } decNumberZero(res); // prepare // [otherwise will be 0 or -0] res->bits=bits; } break;} // here both lhs and rhs are finite; rhs==0 is handled in the // integer path. Next handle the non-integer cases if (!useint) { // non-integral rhs // any -ve lhs is bad, as is either operand or context out of // bounds if (decNumberIsNegative(lhs)) { status|=DEC_Invalid_operation; break;} if (decCheckMath(lhs, set, &status) || decCheckMath(rhs, set, &status)) break; // variable status decContextDefault(&aset, DEC_INIT_DECIMAL64); // clean context aset.emax=DEC_MAX_MATH; // usual bounds aset.emin=-DEC_MAX_MATH; // .. aset.clamp=0; // and no concrete format // calculate the result using exp(ln(lhs)*rhs), which can // all be done into the accumulator, dac. The precision needed // is enough to contain the full information in the lhs (which // is the total digits, including exponent), or the requested // precision, if larger, + 4; 6 is used for the exponent // maximum length, and this is also used when it is shorter // than the requested digits as it greatly reduces the >0.5 ulp // cases at little cost (because Ln doubles digits each // iteration so a few extra digits rarely causes an extra // iteration) aset.digits=MAXI(lhs->digits, set->digits)+6+4; } // non-integer rhs else { // rhs is in-range integer if (n==0) { // x**0 = 1 // (0**0 was handled above) decNumberZero(res); // result=1 *res->lsu=1; // .. break;} // rhs is a non-zero integer if (n<0) n=-n; // use abs(n) aset=*set; // clone the context aset.round=DEC_ROUND_HALF_EVEN; // internally use balanced // calculate the working DIGITS aset.digits=reqdigits+(rhs->digits+rhs->exponent)+2; #if DECSUBSET if (!set->extended) aset.digits--; // use classic precision #endif // it's an error if this is more than can be handled if (aset.digits>DECNUMMAXP) {status|=DEC_Invalid_operation; break;} } // integer path // aset.digits is the count of digits for the accumulator needed // if accumulator is too long for local storage, then allocate needbytes=sizeof(decNumber)+(D2U(aset.digits)-1)*sizeof(Unit); // [needbytes also used below if 1/lhs needed] if (needbytes>sizeof(dacbuff)) { allocdac=(decNumber *)malloc(needbytes); if (allocdac==NULL) { // hopeless -- abandon status|=DEC_Insufficient_storage; break;} dac=allocdac; // use the allocated space } // here, aset is set up and accumulator is ready for use if (!useint) { // non-integral rhs // x ** y; special-case x=1 here as it will otherwise always // reduce to integer 1; decLnOp has a fastpath which detects // the case of x=1 decLnOp(dac, lhs, &aset, &status); // dac=ln(lhs) // [no error possible, as lhs 0 already handled] if (ISZERO(dac)) { // x==1, 1.0, etc. // need to return fully-padded 1.0000 etc., but rhsint->1 *dac->lsu=1; // was 0, make int 1 if (!rhsint) { // add padding Int shift=set->digits-1; dac->digits=decShiftToMost(dac->lsu, 1, shift); dac->exponent=-shift; // make 1.0000... status|=DEC_Inexact|DEC_Rounded; // deemed inexact } } else { decMultiplyOp(dac, dac, rhs, &aset, &status); // dac=dac*rhs decExpOp(dac, dac, &aset, &status); // dac=exp(dac) } // and drop through for final rounding } // non-integer rhs else { // carry on with integer decNumberZero(dac); // acc=1 *dac->lsu=1; // .. // if a negative power the constant 1 is needed, and if not subset // invert the lhs now rather than inverting the result later if (decNumberIsNegative(rhs)) { // was a **-n [hence digits>0] decNumber *inv=invbuff; // assume use fixed buffer decNumberCopy(&dnOne, dac); // dnOne=1; [needed now or later] #if DECSUBSET if (set->extended) { // need to calculate 1/lhs #endif // divide lhs into 1, putting result in dac [dac=1/dac] decDivideOp(dac, &dnOne, lhs, &aset, DIVIDE, &status); // now locate or allocate space for the inverted lhs if (needbytes>sizeof(invbuff)) { allocinv=(decNumber *)malloc(needbytes); if (allocinv==NULL) { // hopeless -- abandon status|=DEC_Insufficient_storage; break;} inv=allocinv; // use the allocated space } // [inv now points to big-enough buffer or allocated storage] decNumberCopy(inv, dac); // copy the 1/lhs decNumberCopy(dac, &dnOne); // restore acc=1 lhs=inv; // .. and go forward with new lhs #if DECSUBSET } #endif } // Raise-to-the-power loop... seenbit=0; // set once a 1-bit is encountered for (i=1;;i++){ // for each bit [top bit ignored] // abandon if had overflow or terminal underflow if (status & (DEC_Overflow|DEC_Underflow)) { // interesting? if (status&DEC_Overflow || ISZERO(dac)) break; } // [the following two lines revealed an optimizer bug in a C++ // compiler, with symptom: 5**3 -> 25, when n=n+n was used] n=n<<1; // move next bit to testable position if (n<0) { // top bit is set seenbit=1; // OK, significant bit seen decMultiplyOp(dac, dac, lhs, &aset, &status); // dac=dac*x } if (i==31) break; // that was the last bit if (!seenbit) continue; // no need to square 1 decMultiplyOp(dac, dac, dac, &aset, &status); // dac=dac*dac [square] } /*i*/ // 32 bits // complete internal overflow or underflow processing if (status & (DEC_Overflow|DEC_Underflow)) { #if DECSUBSET // If subset, and power was negative, reverse the kind of -erflow // [1/x not yet done] if (!set->extended && decNumberIsNegative(rhs)) { if (status & DEC_Overflow) status^=DEC_Overflow | DEC_Underflow | DEC_Subnormal; else { // trickier -- Underflow may or may not be set status&=~(DEC_Underflow | DEC_Subnormal); // [one or both] status|=DEC_Overflow; } } #endif dac->bits=(dac->bits & ~DECNEG) | bits; // force correct sign // round subnormals [to set.digits rather than aset.digits] // or set overflow result similarly as required decFinalize(dac, set, &residue, &status); decNumberCopy(res, dac); // copy to result (is now OK length) break; } #if DECSUBSET if (!set->extended && // subset math decNumberIsNegative(rhs)) { // was a **-n [hence digits>0] // so divide result into 1 [dac=1/dac] decDivideOp(dac, &dnOne, dac, &aset, DIVIDE, &status); } #endif } // rhs integer path // reduce result to the requested length and copy to result decCopyFit(res, dac, set, &residue, &status); decFinish(res, set, &residue, &status); // final cleanup #if DECSUBSET if (!set->extended) decTrim(res, set, 0, 1, &dropped); // trailing zeros #endif } while(0); // end protected if (allocdac!=NULL) free(allocdac); // drop any storage used if (allocinv!=NULL) free(allocinv); // .. #if DECSUBSET if (alloclhs!=NULL) free(alloclhs); // .. if (allocrhs!=NULL) free(allocrhs); // .. #endif if (status!=0) decStatus(res, status, set); #if DECCHECK decCheckInexact(res, set); #endif return res; } // decNumberPower /* ------------------------------------------------------------------ */ /* decNumberQuantize -- force exponent to requested value */ /* */ /* This computes C = op(A, B), where op adjusts the coefficient */ /* of C (by rounding or shifting) such that the exponent (-scale) */ /* of C has exponent of B. The numerical value of C will equal A, */ /* except for the effects of any rounding that occurred. */ /* */ /* res is C, the result. C may be A or B */ /* lhs is A, the number to adjust */ /* rhs is B, the number with exponent to match */ /* set is the context */ /* */ /* C must have space for set->digits digits. */ /* */ /* Unless there is an error or the result is infinite, the exponent */ /* after the operation is guaranteed to be equal to that of B. */ /* ------------------------------------------------------------------ */ decNumber * decNumberQuantize(decNumber *res, const decNumber *lhs, const decNumber *rhs, decContext *set) { uInt status=0; // accumulator decQuantizeOp(res, lhs, rhs, set, 1, &status); if (status!=0) decStatus(res, status, set); return res; } // decNumberQuantize /* ------------------------------------------------------------------ */ /* decNumberReduce -- remove trailing zeros */ /* */ /* This computes C = 0 + A, and normalizes the result */ /* */ /* res is C, the result. C may be A */ /* rhs is A */ /* set is the context */ /* */ /* C must have space for set->digits digits. */ /* ------------------------------------------------------------------ */ // Previously known as Normalize decNumber * decNumberNormalize(decNumber *res, const decNumber *rhs, decContext *set) { return decNumberReduce(res, rhs, set); } // decNumberNormalize decNumber * decNumberReduce(decNumber *res, const decNumber *rhs, decContext *set) { #if DECSUBSET decNumber *allocrhs=NULL; // non-NULL if rounded rhs allocated #endif uInt status=0; // as usual Int residue=0; // as usual Int dropped; // work #if DECCHECK if (decCheckOperands(res, DECUNUSED, rhs, set)) return res; #endif do { // protect allocated storage #if DECSUBSET if (!set->extended) { // reduce operand and set lostDigits status, as needed if (rhs->digits>set->digits) { allocrhs=decRoundOperand(rhs, set, &status); if (allocrhs==NULL) break; rhs=allocrhs; } } #endif // [following code does not require input rounding] // Infinities copy through; NaNs need usual treatment if (decNumberIsNaN(rhs)) { decNaNs(res, rhs, NULL, set, &status); break; } // reduce result to the requested length and copy to result decCopyFit(res, rhs, set, &residue, &status); // copy & round decFinish(res, set, &residue, &status); // cleanup/set flags decTrim(res, set, 1, 0, &dropped); // normalize in place // [may clamp] } while(0); // end protected #if DECSUBSET if (allocrhs !=NULL) free(allocrhs); // .. #endif if (status!=0) decStatus(res, status, set);// then report status return res; } // decNumberReduce /* ------------------------------------------------------------------ */ /* decNumberRescale -- force exponent to requested value */ /* */ /* This computes C = op(A, B), where op adjusts the coefficient */ /* of C (by rounding or shifting) such that the exponent (-scale) */ /* of C has the value B. The numerical value of C will equal A, */ /* except for the effects of any rounding that occurred. */ /* */ /* res is C, the result. C may be A or B */ /* lhs is A, the number to adjust */ /* rhs is B, the requested exponent */ /* set is the context */ /* */ /* C must have space for set->digits digits. */ /* */ /* Unless there is an error or the result is infinite, the exponent */ /* after the operation is guaranteed to be equal to B. */ /* ------------------------------------------------------------------ */ decNumber * decNumberRescale(decNumber *res, const decNumber *lhs, const decNumber *rhs, decContext *set) { uInt status=0; // accumulator decQuantizeOp(res, lhs, rhs, set, 0, &status); if (status!=0) decStatus(res, status, set); return res; } // decNumberRescale /* ------------------------------------------------------------------ */ /* decNumberRemainder -- divide and return remainder */ /* */ /* This computes C = A % B */ /* */ /* res is C, the result. C may be A and/or B (e.g., X=X%X) */ /* lhs is A */ /* rhs is B */ /* set is the context */ /* */ /* C must have space for set->digits digits. */ /* ------------------------------------------------------------------ */ decNumber * decNumberRemainder(decNumber *res, const decNumber *lhs, const decNumber *rhs, decContext *set) { uInt status=0; // accumulator decDivideOp(res, lhs, rhs, set, REMAINDER, &status); if (status!=0) decStatus(res, status, set); #if DECCHECK decCheckInexact(res, set); #endif return res; } // decNumberRemainder /* ------------------------------------------------------------------ */ /* decNumberRemainderNear -- divide and return remainder from nearest */ /* */ /* This computes C = A % B, where % is the IEEE remainder operator */ /* */ /* res is C, the result. C may be A and/or B (e.g., X=X%X) */ /* lhs is A */ /* rhs is B */ /* set is the context */ /* */ /* C must have space for set->digits digits. */ /* ------------------------------------------------------------------ */ decNumber * decNumberRemainderNear(decNumber *res, const decNumber *lhs, const decNumber *rhs, decContext *set) { uInt status=0; // accumulator decDivideOp(res, lhs, rhs, set, REMNEAR, &status); if (status!=0) decStatus(res, status, set); #if DECCHECK decCheckInexact(res, set); #endif return res; } // decNumberRemainderNear /* ------------------------------------------------------------------ */ /* decNumberRotate -- rotate the coefficient of a Number left/right */ /* */ /* This computes C = A rot B (in base ten and rotating set->digits */ /* digits). */ /* */ /* res is C, the result. C may be A and/or B (e.g., X=XrotX) */ /* lhs is A */ /* rhs is B, the number of digits to rotate (-ve to right) */ /* set is the context */ /* */ /* The digits of the coefficient of A are rotated to the left (if B */ /* is positive) or to the right (if B is negative) without adjusting */ /* the exponent or the sign of A. If lhs->digits is less than */ /* set->digits the coefficient is padded with zeros on the left */ /* before the rotate. Any leading zeros in the result are removed */ /* as usual. */ /* */ /* B must be an integer (q=0) and in the range -set->digits through */ /* +set->digits. */ /* C must have space for set->digits digits. */ /* NaNs are propagated as usual. Infinities are unaffected (but */ /* B must be valid). No status is set unless B is invalid or an */ /* operand is an sNaN. */ /* ------------------------------------------------------------------ */ decNumber * decNumberRotate(decNumber *res, const decNumber *lhs, const decNumber *rhs, decContext *set) { uInt status=0; // accumulator Int rotate; // rhs as an Int #if DECCHECK if (decCheckOperands(res, lhs, rhs, set)) return res; #endif // NaNs propagate as normal if (decNumberIsNaN(lhs) || decNumberIsNaN(rhs)) decNaNs(res, lhs, rhs, set, &status); // rhs must be an integer else if (decNumberIsInfinite(rhs) || rhs->exponent!=0) status=DEC_Invalid_operation; else { // both numeric, rhs is an integer rotate=decGetInt(rhs); // [cannot fail] if (rotate==BADINT // something bad .. || rotate==BIGODD || rotate==BIGEVEN // .. very big .. || abs(rotate)>set->digits) // .. or out of range status=DEC_Invalid_operation; else { // rhs is OK decNumberCopy(res, lhs); // convert -ve rotate to equivalent positive rotation if (rotate<0) rotate=set->digits+rotate; if (rotate!=0 && rotate!=set->digits // zero or full rotation && !decNumberIsInfinite(res)) { // lhs was infinite // left-rotate to do; 0 < rotate < set->digits uInt units, shift; // work uInt msudigits; // digits in result msu Unit *msu=res->lsu+D2U(res->digits)-1; // current msu Unit *msumax=res->lsu+D2U(set->digits)-1; // rotation msu for (msu++; msu<=msumax; msu++) *msu=0; // ensure high units=0 res->digits=set->digits; // now full-length msudigits=MSUDIGITS(res->digits); // actual digits in msu // rotation here is done in-place, in three steps // 1. shift all to least up to one unit to unit-align final // lsd [any digits shifted out are rotated to the left, // abutted to the original msd (which may require split)] // // [if there are no whole units left to rotate, the // rotation is now complete] // // 2. shift to least, from below the split point only, so that // the final msd is in the right place in its Unit [any // digits shifted out will fit exactly in the current msu, // left aligned, no split required] // // 3. rotate all the units by reversing left part, right // part, and then whole // // example: rotate right 8 digits (2 units + 2), DECDPUN=3. // // start: 00a bcd efg hij klm npq // // 1a 000 0ab cde fgh|ijk lmn [pq saved] // 1b 00p qab cde fgh|ijk lmn // // 2a 00p qab cde fgh|00i jkl [mn saved] // 2b mnp qab cde fgh|00i jkl // // 3a fgh cde qab mnp|00i jkl // 3b fgh cde qab mnp|jkl 00i // 3c 00i jkl mnp qab cde fgh // Step 1: amount to shift is the partial right-rotate count rotate=set->digits-rotate; // make it right-rotate units=rotate/DECDPUN; // whole units to rotate shift=rotate%DECDPUN; // left-over digits count if (shift>0) { // not an exact number of units uInt save=res->lsu[0]%powers[shift]; // save low digit(s) decShiftToLeast(res->lsu, D2U(res->digits), shift); if (shift>msudigits) { // msumax-1 needs >0 digits uInt rem=save%powers[shift-msudigits];// split save *msumax=(Unit)(save/powers[shift-msudigits]); // and insert *(msumax-1)=*(msumax-1) +(Unit)(rem*powers[DECDPUN-(shift-msudigits)]); // .. } else { // all fits in msumax *msumax=*msumax+(Unit)(save*powers[msudigits-shift]); // [maybe *1] } } // digits shift needed // If whole units to rotate... if (units>0) { // some to do // Step 2: the units to touch are the whole ones in rotate, // if any, and the shift is DECDPUN-msudigits (which may be // 0, again) shift=DECDPUN-msudigits; if (shift>0) { // not an exact number of units uInt save=res->lsu[0]%powers[shift]; // save low digit(s) decShiftToLeast(res->lsu, units, shift); *msumax=*msumax+(Unit)(save*powers[msudigits]); } // partial shift needed // Step 3: rotate the units array using triple reverse // (reversing is easy and fast) decReverse(res->lsu+units, msumax); // left part decReverse(res->lsu, res->lsu+units-1); // right part decReverse(res->lsu, msumax); // whole } // whole units to rotate // the rotation may have left an undetermined number of zeros // on the left, so true length needs to be calculated res->digits=decGetDigits(res->lsu, msumax-res->lsu+1); } // rotate needed } // rhs OK } // numerics if (status!=0) decStatus(res, status, set); return res; } // decNumberRotate /* ------------------------------------------------------------------ */ /* decNumberSameQuantum -- test for equal exponents */ /* */ /* res is the result number, which will contain either 0 or 1 */ /* lhs is a number to test */ /* rhs is the second (usually a pattern) */ /* */ /* No errors are possible and no context is needed. */ /* ------------------------------------------------------------------ */ decNumber * decNumberSameQuantum(decNumber *res, const decNumber *lhs, const decNumber *rhs) { Unit ret=0; // return value #if DECCHECK if (decCheckOperands(res, lhs, rhs, DECUNCONT)) return res; #endif if (SPECIALARGS) { if (decNumberIsNaN(lhs) && decNumberIsNaN(rhs)) ret=1; else if (decNumberIsInfinite(lhs) && decNumberIsInfinite(rhs)) ret=1; // [anything else with a special gives 0] } else if (lhs->exponent==rhs->exponent) ret=1; decNumberZero(res); // OK to overwrite an operand now *res->lsu=ret; return res; } // decNumberSameQuantum /* ------------------------------------------------------------------ */ /* decNumberScaleB -- multiply by a power of 10 */ /* */ /* This computes C = A x 10**B where B is an integer (q=0) with */ /* maximum magnitude 2*(emax+digits) */ /* */ /* res is C, the result. C may be A or B */ /* lhs is A, the number to adjust */ /* rhs is B, the requested power of ten to use */ /* set is the context */ /* */ /* C must have space for set->digits digits. */ /* */ /* The result may underflow or overflow. */ /* ------------------------------------------------------------------ */ decNumber * decNumberScaleB(decNumber *res, const decNumber *lhs, const decNumber *rhs, decContext *set) { Int reqexp; // requested exponent change [B] uInt status=0; // accumulator Int residue; // work #if DECCHECK if (decCheckOperands(res, lhs, rhs, set)) return res; #endif // Handle special values except lhs infinite if (decNumberIsNaN(lhs) || decNumberIsNaN(rhs)) decNaNs(res, lhs, rhs, set, &status); // rhs must be an integer else if (decNumberIsInfinite(rhs) || rhs->exponent!=0) status=DEC_Invalid_operation; else { // lhs is a number; rhs is a finite with q==0 reqexp=decGetInt(rhs); // [cannot fail] // maximum range is larger than getInt can handle, so this is // more restrictive than the specification if (reqexp==BADINT // something bad .. || reqexp==BIGODD || reqexp==BIGEVEN // it was huge || (abs(reqexp)+1)/2>(set->digits+set->emax)) // .. or out of range status=DEC_Invalid_operation; else { // rhs is OK decNumberCopy(res, lhs); // all done if infinite lhs if (!decNumberIsInfinite(res)) { // prepare to scale Int exp=res->exponent; // save for overflow test res->exponent+=reqexp; // adjust the exponent if (((exp^reqexp)>=0) // same sign ... && ((exp^res->exponent)<0)) { // .. but result had different // the calculation overflowed, so force right treatment if (exp<0) res->exponent=DEC_MIN_EMIN-DEC_MAX_DIGITS; else res->exponent=DEC_MAX_EMAX+1; } residue=0; decFinalize(res, set, &residue, &status); // final check } // finite LHS } // rhs OK } // rhs finite if (status!=0) decStatus(res, status, set); return res; } // decNumberScaleB /* ------------------------------------------------------------------ */ /* decNumberShift -- shift the coefficient of a Number left or right */ /* */ /* This computes C = A << B or C = A >> -B (in base ten). */ /* */ /* res is C, the result. C may be A and/or B (e.g., X=X<digits through */ /* +set->digits. */ /* C must have space for set->digits digits. */ /* NaNs are propagated as usual. Infinities are unaffected (but */ /* B must be valid). No status is set unless B is invalid or an */ /* operand is an sNaN. */ /* ------------------------------------------------------------------ */ decNumber * decNumberShift(decNumber *res, const decNumber *lhs, const decNumber *rhs, decContext *set) { uInt status=0; // accumulator Int shift; // rhs as an Int #if DECCHECK if (decCheckOperands(res, lhs, rhs, set)) return res; #endif // NaNs propagate as normal if (decNumberIsNaN(lhs) || decNumberIsNaN(rhs)) decNaNs(res, lhs, rhs, set, &status); // rhs must be an integer else if (decNumberIsInfinite(rhs) || rhs->exponent!=0) status=DEC_Invalid_operation; else { // both numeric, rhs is an integer shift=decGetInt(rhs); // [cannot fail] if (shift==BADINT // something bad .. || shift==BIGODD || shift==BIGEVEN // .. very big .. || abs(shift)>set->digits) // .. or out of range status=DEC_Invalid_operation; else { // rhs is OK decNumberCopy(res, lhs); if (shift!=0 && !decNumberIsInfinite(res)) { // something to do if (shift>0) { // to left if (shift==set->digits) { // removing all *res->lsu=0; // so place 0 res->digits=1; // .. } else { // // first remove leading digits if necessary if (res->digits+shift>set->digits) { decDecap(res, res->digits+shift-set->digits); // that updated res->digits; may have gone to 1 (for a // single digit or for zero } if (res->digits>1 || *res->lsu) // if non-zero.. res->digits=decShiftToMost(res->lsu, res->digits, shift); } // partial left } // left else { // to right if (-shift>=res->digits) { // discarding all *res->lsu=0; // so place 0 res->digits=1; // .. } else { decShiftToLeast(res->lsu, D2U(res->digits), -shift); res->digits-=(-shift); } } // to right } // non-0 non-Inf shift } // rhs OK } // numerics if (status!=0) decStatus(res, status, set); return res; } // decNumberShift /* ------------------------------------------------------------------ */ /* decNumberSquareRoot -- square root operator */ /* */ /* This computes C = squareroot(A) */ /* */ /* res is C, the result. C may be A */ /* rhs is A */ /* set is the context; note that rounding mode has no effect */ /* */ /* C must have space for set->digits digits. */ /* ------------------------------------------------------------------ */ /* This uses the following varying-precision algorithm in: */ /* */ /* Properly Rounded Variable Precision Square Root, T. E. Hull and */ /* A. Abrham, ACM Transactions on Mathematical Software, Vol 11 #3, */ /* pp229-237, ACM, September 1985. */ /* */ /* The square-root is calculated using Newton's method, after which */ /* a check is made to ensure the result is correctly rounded. */ /* */ /* % [Reformatted original Numerical Turing source code follows.] */ /* function sqrt(x : real) : real */ /* % sqrt(x) returns the properly rounded approximation to the square */ /* % root of x, in the precision of the calling environment, or it */ /* % fails if x < 0. */ /* % t e hull and a abrham, august, 1984 */ /* if x <= 0 then */ /* if x < 0 then */ /* assert false */ /* else */ /* result 0 */ /* end if */ /* end if */ /* var f := setexp(x, 0) % fraction part of x [0.1 <= x < 1] */ /* var e := getexp(x) % exponent part of x */ /* var approx : real */ /* if e mod 2 = 0 then */ /* approx := .259 + .819 * f % approx to root of f */ /* else */ /* f := f/l0 % adjustments */ /* e := e + 1 % for odd */ /* approx := .0819 + 2.59 * f % exponent */ /* end if */ /* */ /* var p:= 3 */ /* const maxp := currentprecision + 2 */ /* loop */ /* p := min(2*p - 2, maxp) % p = 4,6,10, . . . , maxp */ /* precision p */ /* approx := .5 * (approx + f/approx) */ /* exit when p = maxp */ /* end loop */ /* */ /* % approx is now within 1 ulp of the properly rounded square root */ /* % of f; to ensure proper rounding, compare squares of (approx - */ /* % l/2 ulp) and (approx + l/2 ulp) with f. */ /* p := currentprecision */ /* begin */ /* precision p + 2 */ /* const approxsubhalf := approx - setexp(.5, -p) */ /* if mulru(approxsubhalf, approxsubhalf) > f then */ /* approx := approx - setexp(.l, -p + 1) */ /* else */ /* const approxaddhalf := approx + setexp(.5, -p) */ /* if mulrd(approxaddhalf, approxaddhalf) < f then */ /* approx := approx + setexp(.l, -p + 1) */ /* end if */ /* end if */ /* end */ /* result setexp(approx, e div 2) % fix exponent */ /* end sqrt */ /* ------------------------------------------------------------------ */ decNumber * decNumberSquareRoot(decNumber *res, const decNumber *rhs, decContext *set) { decContext workset, approxset; // work contexts decNumber dzero; // used for constant zero Int maxp; // largest working precision Int workp; // working precision Int residue=0; // rounding residue uInt status=0, ignore=0; // status accumulators uInt rstatus; // .. Int exp; // working exponent Int ideal; // ideal (preferred) exponent Int needbytes; // work Int dropped; // .. #if DECSUBSET decNumber *allocrhs=NULL; // non-NULL if rounded rhs allocated #endif // buffer for f [needs +1 in case DECBUFFER 0] decNumber buff[D2N(DECBUFFER+1)]; // buffer for a [needs +2 to match likely maxp] decNumber bufa[D2N(DECBUFFER+2)]; // buffer for temporary, b [must be same size as a] decNumber bufb[D2N(DECBUFFER+2)]; decNumber *allocbuff=NULL; // -> allocated buff, iff allocated decNumber *allocbufa=NULL; // -> allocated bufa, iff allocated decNumber *allocbufb=NULL; // -> allocated bufb, iff allocated decNumber *f=buff; // reduced fraction decNumber *a=bufa; // approximation to result decNumber *b=bufb; // intermediate result // buffer for temporary variable, up to 3 digits decNumber buft[D2N(3)]; decNumber *t=buft; // up-to-3-digit constant or work #if DECCHECK if (decCheckOperands(res, DECUNUSED, rhs, set)) return res; #endif do { // protect allocated storage #if DECSUBSET if (!set->extended) { // reduce operand and set lostDigits status, as needed if (rhs->digits>set->digits) { allocrhs=decRoundOperand(rhs, set, &status); if (allocrhs==NULL) break; // [Note: 'f' allocation below could reuse this buffer if // used, but as this is rare they are kept separate for clarity.] rhs=allocrhs; } } #endif // [following code does not require input rounding] // handle infinities and NaNs if (SPECIALARG) { if (decNumberIsInfinite(rhs)) { // an infinity if (decNumberIsNegative(rhs)) status|=DEC_Invalid_operation; else decNumberCopy(res, rhs); // +Infinity } else decNaNs(res, rhs, NULL, set, &status); // a NaN break; } // calculate the ideal (preferred) exponent [floor(exp/2)] // [It would be nicer to write: ideal=rhs->exponent>>1, but this // generates a compiler warning. Generated code is the same.] ideal=(rhs->exponent&~1)/2; // target // handle zeros if (ISZERO(rhs)) { decNumberCopy(res, rhs); // could be 0 or -0 res->exponent=ideal; // use the ideal [safe] // use decFinish to clamp any out-of-range exponent, etc. decFinish(res, set, &residue, &status); break; } // any other -x is an oops if (decNumberIsNegative(rhs)) { status|=DEC_Invalid_operation; break; } // space is needed for three working variables // f -- the same precision as the RHS, reduced to 0.01->0.99... // a -- Hull's approximation -- precision, when assigned, is // currentprecision+1 or the input argument precision, // whichever is larger (+2 for use as temporary) // b -- intermediate temporary result (same size as a) // if any is too long for local storage, then allocate workp=MAXI(set->digits+1, rhs->digits); // actual rounding precision workp=MAXI(workp, 7); // at least 7 for low cases maxp=workp+2; // largest working precision needbytes=sizeof(decNumber)+(D2U(rhs->digits)-1)*sizeof(Unit); if (needbytes>(Int)sizeof(buff)) { allocbuff=(decNumber *)malloc(needbytes); if (allocbuff==NULL) { // hopeless -- abandon status|=DEC_Insufficient_storage; break;} f=allocbuff; // use the allocated space } // a and b both need to be able to hold a maxp-length number needbytes=sizeof(decNumber)+(D2U(maxp)-1)*sizeof(Unit); if (needbytes>(Int)sizeof(bufa)) { // [same applies to b] allocbufa=(decNumber *)malloc(needbytes); allocbufb=(decNumber *)malloc(needbytes); if (allocbufa==NULL || allocbufb==NULL) { // hopeless status|=DEC_Insufficient_storage; break;} a=allocbufa; // use the allocated spaces b=allocbufb; // .. } // copy rhs -> f, save exponent, and reduce so 0.1 <= f < 1 decNumberCopy(f, rhs); exp=f->exponent+f->digits; // adjusted to Hull rules f->exponent=-(f->digits); // to range // set up working context decContextDefault(&workset, DEC_INIT_DECIMAL64); workset.emax=DEC_MAX_EMAX; workset.emin=DEC_MIN_EMIN; // [Until further notice, no error is possible and status bits // (Rounded, etc.) should be ignored, not accumulated.] // Calculate initial approximation, and allow for odd exponent workset.digits=workp; // p for initial calculation t->bits=0; t->digits=3; a->bits=0; a->digits=3; if ((exp & 1)==0) { // even exponent // Set t=0.259, a=0.819 t->exponent=-3; a->exponent=-3; #if DECDPUN>=3 t->lsu[0]=259; a->lsu[0]=819; #elif DECDPUN==2 t->lsu[0]=59; t->lsu[1]=2; a->lsu[0]=19; a->lsu[1]=8; #else t->lsu[0]=9; t->lsu[1]=5; t->lsu[2]=2; a->lsu[0]=9; a->lsu[1]=1; a->lsu[2]=8; #endif } else { // odd exponent // Set t=0.0819, a=2.59 f->exponent--; // f=f/10 exp++; // e=e+1 t->exponent=-4; a->exponent=-2; #if DECDPUN>=3 t->lsu[0]=819; a->lsu[0]=259; #elif DECDPUN==2 t->lsu[0]=19; t->lsu[1]=8; a->lsu[0]=59; a->lsu[1]=2; #else t->lsu[0]=9; t->lsu[1]=1; t->lsu[2]=8; a->lsu[0]=9; a->lsu[1]=5; a->lsu[2]=2; #endif } decMultiplyOp(a, a, f, &workset, &ignore); // a=a*f decAddOp(a, a, t, &workset, 0, &ignore); // ..+t // [a is now the initial approximation for sqrt(f), calculated with // currentprecision, which is also a's precision.] // the main calculation loop decNumberZero(&dzero); // make 0 decNumberZero(t); // set t = 0.5 t->lsu[0]=5; // .. t->exponent=-1; // .. workset.digits=3; // initial p for (; workset.digitsexponent+=exp/2; // set correct exponent rstatus=0; // clear status residue=0; // .. and accumulator decCopyFit(a, a, &approxset, &residue, &rstatus); // reduce (if needed) decFinish(a, &approxset, &residue, &rstatus); // clean and finalize // Overflow was possible if the input exponent was out-of-range, // in which case quit if (rstatus&DEC_Overflow) { status=rstatus; // use the status as-is decNumberCopy(res, a); // copy to result break; } // Preserve status except Inexact/Rounded status|=(rstatus & ~(DEC_Rounded|DEC_Inexact)); // Carry out the Hull correction a->exponent-=exp/2; // back to 0.1->1 // a is now at final precision and within 1 ulp of the properly // rounded square root of f; to ensure proper rounding, compare // squares of (a - l/2 ulp) and (a + l/2 ulp) with f. // Here workset.digits=maxp and t=0.5, and a->digits determines // the ulp workset.digits--; // maxp-1 is OK now t->exponent=-a->digits-1; // make 0.5 ulp decAddOp(b, a, t, &workset, DECNEG, &ignore); // b = a - 0.5 ulp workset.round=DEC_ROUND_UP; decMultiplyOp(b, b, b, &workset, &ignore); // b = mulru(b, b) decCompareOp(b, f, b, &workset, COMPARE, &ignore); // b ? f, reversed if (decNumberIsNegative(b)) { // f < b [i.e., b > f] // this is the more common adjustment, though both are rare t->exponent++; // make 1.0 ulp t->lsu[0]=1; // .. decAddOp(a, a, t, &workset, DECNEG, &ignore); // a = a - 1 ulp // assign to approx [round to length] approxset.emin-=exp/2; // adjust to match a approxset.emax-=exp/2; decAddOp(a, &dzero, a, &approxset, 0, &ignore); } else { decAddOp(b, a, t, &workset, 0, &ignore); // b = a + 0.5 ulp workset.round=DEC_ROUND_DOWN; decMultiplyOp(b, b, b, &workset, &ignore); // b = mulrd(b, b) decCompareOp(b, b, f, &workset, COMPARE, &ignore); // b ? f if (decNumberIsNegative(b)) { // b < f t->exponent++; // make 1.0 ulp t->lsu[0]=1; // .. decAddOp(a, a, t, &workset, 0, &ignore); // a = a + 1 ulp // assign to approx [round to length] approxset.emin-=exp/2; // adjust to match a approxset.emax-=exp/2; decAddOp(a, &dzero, a, &approxset, 0, &ignore); } } // [no errors are possible in the above, and rounding/inexact during // estimation are irrelevant, so status was not accumulated] // Here, 0.1 <= a < 1 (still), so adjust back a->exponent+=exp/2; // set correct exponent // count droppable zeros [after any subnormal rounding] by // trimming a copy decNumberCopy(b, a); decTrim(b, set, 1, 1, &dropped); // [drops trailing zeros] // Set Inexact and Rounded. The answer can only be exact if // it is short enough so that squaring it could fit in workp // digits, so this is the only (relatively rare) condition that // a careful check is needed if (b->digits*2-1 > workp) { // cannot fit status|=DEC_Inexact|DEC_Rounded; } else { // could be exact/unrounded uInt mstatus=0; // local status decMultiplyOp(b, b, b, &workset, &mstatus); // try the multiply if (mstatus&DEC_Overflow) { // result just won't fit status|=DEC_Inexact|DEC_Rounded; } else { // plausible decCompareOp(t, b, rhs, &workset, COMPARE, &mstatus); // b ? rhs if (!ISZERO(t)) status|=DEC_Inexact|DEC_Rounded; // not equal else { // is Exact // here, dropped is the count of trailing zeros in 'a' // use closest exponent to ideal... Int todrop=ideal-a->exponent; // most that can be dropped if (todrop<0) status|=DEC_Rounded; // ideally would add 0s else { // unrounded // there are some to drop, but emax may not allow all Int maxexp=set->emax-set->digits+1; Int maxdrop=maxexp-a->exponent; if (todrop>maxdrop && set->clamp) { // apply clamping todrop=maxdrop; status|=DEC_Clamped; } if (dropped0) { // have some to drop decShiftToLeast(a->lsu, D2U(a->digits), todrop); a->exponent+=todrop; // maintain numerical value a->digits-=todrop; // new length } } } } } // double-check Underflow, as perhaps the result could not have // been subnormal (initial argument too big), or it is now Exact if (status&DEC_Underflow) { Int ae=rhs->exponent+rhs->digits-1; // adjusted exponent // check if truly subnormal #if DECEXTFLAG // DEC_Subnormal too if (ae>=set->emin*2) status&=~(DEC_Subnormal|DEC_Underflow); #else if (ae>=set->emin*2) status&=~DEC_Underflow; #endif // check if truly inexact if (!(status&DEC_Inexact)) status&=~DEC_Underflow; } decNumberCopy(res, a); // a is now the result } while(0); // end protected if (allocbuff!=NULL) free(allocbuff); // drop any storage used if (allocbufa!=NULL) free(allocbufa); // .. if (allocbufb!=NULL) free(allocbufb); // .. #if DECSUBSET if (allocrhs !=NULL) free(allocrhs); // .. #endif if (status!=0) decStatus(res, status, set);// then report status #if DECCHECK decCheckInexact(res, set); #endif return res; } // decNumberSquareRoot /* ------------------------------------------------------------------ */ /* decNumberSubtract -- subtract two Numbers */ /* */ /* This computes C = A - B */ /* */ /* res is C, the result. C may be A and/or B (e.g., X=X-X) */ /* lhs is A */ /* rhs is B */ /* set is the context */ /* */ /* C must have space for set->digits digits. */ /* ------------------------------------------------------------------ */ decNumber * decNumberSubtract(decNumber *res, const decNumber *lhs, const decNumber *rhs, decContext *set) { uInt status=0; // accumulator decAddOp(res, lhs, rhs, set, DECNEG, &status); if (status!=0) decStatus(res, status, set); #if DECCHECK decCheckInexact(res, set); #endif return res; } // decNumberSubtract /* ------------------------------------------------------------------ */ /* decNumberToIntegralExact -- round-to-integral-value with InExact */ /* decNumberToIntegralValue -- round-to-integral-value */ /* */ /* res is the result */ /* rhs is input number */ /* set is the context */ /* */ /* res must have space for any value of rhs. */ /* */ /* This implements the IEEE special operators and therefore treats */ /* special values as valid. For finite numbers it returns */ /* rescale(rhs, 0) if rhs->exponent is <0. */ /* Otherwise the result is rhs (so no error is possible, except for */ /* sNaN). */ /* */ /* The context is used for rounding mode and status after sNaN, but */ /* the digits setting is ignored. The Exact version will signal */ /* Inexact if the result differs numerically from rhs; the other */ /* never signals Inexact. */ /* ------------------------------------------------------------------ */ decNumber * decNumberToIntegralExact(decNumber *res, const decNumber *rhs, decContext *set) { decNumber dn; decContext workset; // working context uInt status=0; // accumulator #if DECCHECK if (decCheckOperands(res, DECUNUSED, rhs, set)) return res; #endif // handle infinities and NaNs if (SPECIALARG) { if (decNumberIsInfinite(rhs)) decNumberCopy(res, rhs); // an Infinity else decNaNs(res, rhs, NULL, set, &status); // a NaN } else { // finite // have a finite number; no error possible (res must be big enough) if (rhs->exponent>=0) return decNumberCopy(res, rhs); // that was easy, but if negative exponent there is work to do... workset=*set; // clone rounding, etc. workset.digits=rhs->digits; // no length rounding workset.traps=0; // no traps decNumberZero(&dn); // make a number with exponent 0 decNumberQuantize(res, rhs, &dn, &workset); status|=workset.status; } if (status!=0) decStatus(res, status, set); return res; } // decNumberToIntegralExact decNumber * decNumberToIntegralValue(decNumber *res, const decNumber *rhs, decContext *set) { decContext workset=*set; // working context workset.traps=0; // no traps decNumberToIntegralExact(res, rhs, &workset); // this never affects set, except for sNaNs; NaN will have been set // or propagated already, so no need to call decStatus set->status|=workset.status&DEC_Invalid_operation; return res; } // decNumberToIntegralValue /* ------------------------------------------------------------------ */ /* decNumberXor -- XOR two Numbers, digitwise */ /* */ /* This computes C = A ^ B */ /* */ /* res is C, the result. C may be A and/or B (e.g., X=X^X) */ /* lhs is A */ /* rhs is B */ /* set is the context (used for result length and error report) */ /* */ /* C must have space for set->digits digits. */ /* */ /* Logical function restrictions apply (see above); a NaN is */ /* returned with Invalid_operation if a restriction is violated. */ /* ------------------------------------------------------------------ */ decNumber * decNumberXor(decNumber *res, const decNumber *lhs, const decNumber *rhs, decContext *set) { const Unit *ua, *ub; // -> operands const Unit *msua, *msub; // -> operand msus Unit *uc, *msuc; // -> result and its msu Int msudigs; // digits in res msu #if DECCHECK if (decCheckOperands(res, lhs, rhs, set)) return res; #endif if (lhs->exponent!=0 || decNumberIsSpecial(lhs) || decNumberIsNegative(lhs) || rhs->exponent!=0 || decNumberIsSpecial(rhs) || decNumberIsNegative(rhs)) { decStatus(res, DEC_Invalid_operation, set); return res; } // operands are valid ua=lhs->lsu; // bottom-up ub=rhs->lsu; // .. uc=res->lsu; // .. msua=ua+D2U(lhs->digits)-1; // -> msu of lhs msub=ub+D2U(rhs->digits)-1; // -> msu of rhs msuc=uc+D2U(set->digits)-1; // -> msu of result msudigs=MSUDIGITS(set->digits); // [faster than remainder] for (; uc<=msuc; ua++, ub++, uc++) { // Unit loop Unit a, b; // extract units if (ua>msua) a=0; else a=*ua; if (ub>msub) b=0; else b=*ub; *uc=0; // can now write back if (a|b) { // maybe 1 bits to examine Int i, j; // This loop could be unrolled and/or use BIN2BCD tables for (i=0; i1) { decStatus(res, DEC_Invalid_operation, set); return res; } if (uc==msuc && i==msudigs-1) break; // just did final digit } // each digit } // non-zero } // each unit // [here uc-1 is the msu of the result] res->digits=decGetDigits(res->lsu, uc-res->lsu); res->exponent=0; // integer res->bits=0; // sign=0 return res; // [no status to set] } // decNumberXor /* ================================================================== */ /* Utility routines */ /* ================================================================== */ /* ------------------------------------------------------------------ */ /* decNumberClass -- return the decClass of a decNumber */ /* dn -- the decNumber to test */ /* set -- the context to use for Emin */ /* returns the decClass enum */ /* ------------------------------------------------------------------ */ enum decClass decNumberClass(const decNumber *dn, decContext *set) { if (decNumberIsSpecial(dn)) { if (decNumberIsQNaN(dn)) return DEC_CLASS_QNAN; if (decNumberIsSNaN(dn)) return DEC_CLASS_SNAN; // must be an infinity if (decNumberIsNegative(dn)) return DEC_CLASS_NEG_INF; return DEC_CLASS_POS_INF; } // is finite if (decNumberIsNormal(dn, set)) { // most common if (decNumberIsNegative(dn)) return DEC_CLASS_NEG_NORMAL; return DEC_CLASS_POS_NORMAL; } // is subnormal or zero if (decNumberIsZero(dn)) { // most common if (decNumberIsNegative(dn)) return DEC_CLASS_NEG_ZERO; return DEC_CLASS_POS_ZERO; } if (decNumberIsNegative(dn)) return DEC_CLASS_NEG_SUBNORMAL; return DEC_CLASS_POS_SUBNORMAL; } // decNumberClass /* ------------------------------------------------------------------ */ /* decNumberClassToString -- convert decClass to a string */ /* */ /* eclass is a valid decClass */ /* returns a constant string describing the class (max 13+1 chars) */ /* ------------------------------------------------------------------ */ const char *decNumberClassToString(enum decClass eclass) { if (eclass==DEC_CLASS_POS_NORMAL) return DEC_ClassString_PN; if (eclass==DEC_CLASS_NEG_NORMAL) return DEC_ClassString_NN; if (eclass==DEC_CLASS_POS_ZERO) return DEC_ClassString_PZ; if (eclass==DEC_CLASS_NEG_ZERO) return DEC_ClassString_NZ; if (eclass==DEC_CLASS_POS_SUBNORMAL) return DEC_ClassString_PS; if (eclass==DEC_CLASS_NEG_SUBNORMAL) return DEC_ClassString_NS; if (eclass==DEC_CLASS_POS_INF) return DEC_ClassString_PI; if (eclass==DEC_CLASS_NEG_INF) return DEC_ClassString_NI; if (eclass==DEC_CLASS_QNAN) return DEC_ClassString_QN; if (eclass==DEC_CLASS_SNAN) return DEC_ClassString_SN; return DEC_ClassString_UN; // Unknown } // decNumberClassToString /* ------------------------------------------------------------------ */ /* decNumberCopy -- copy a number */ /* */ /* dest is the target decNumber */ /* src is the source decNumber */ /* returns dest */ /* */ /* (dest==src is allowed and is a no-op) */ /* All fields are updated as required. This is a utility operation, */ /* so special values are unchanged and no error is possible. */ /* ------------------------------------------------------------------ */ decNumber * decNumberCopy(decNumber *dest, const decNumber *src) { #if DECCHECK if (src==NULL) return decNumberZero(dest); #endif if (dest==src) return dest; // no copy required // Use explicit assignments here as structure assignment could copy // more than just the lsu (for small DECDPUN). This would not affect // the value of the results, but could disturb test harness spill // checking. dest->bits=src->bits; dest->exponent=src->exponent; dest->digits=src->digits; dest->lsu[0]=src->lsu[0]; if (src->digits>DECDPUN) { // more Units to come const Unit *smsup, *s; // work Unit *d; // .. // memcpy for the remaining Units would be safe as they cannot // overlap. However, this explicit loop is faster in short cases. d=dest->lsu+1; // -> first destination smsup=src->lsu+D2U(src->digits); // -> source msu+1 for (s=src->lsu+1; sdigits digits. */ /* No exception or error can occur; this is a quiet bitwise operation.*/ /* See also decNumberAbs for a checking version of this. */ /* ------------------------------------------------------------------ */ decNumber * decNumberCopyAbs(decNumber *res, const decNumber *rhs) { #if DECCHECK if (decCheckOperands(res, DECUNUSED, rhs, DECUNCONT)) return res; #endif decNumberCopy(res, rhs); res->bits&=~DECNEG; // turn off sign return res; } // decNumberCopyAbs /* ------------------------------------------------------------------ */ /* decNumberCopyNegate -- quiet negate value operator */ /* */ /* This sets C = negate(A) */ /* */ /* res is C, the result. C may be A */ /* rhs is A */ /* */ /* C must have space for set->digits digits. */ /* No exception or error can occur; this is a quiet bitwise operation.*/ /* See also decNumberMinus for a checking version of this. */ /* ------------------------------------------------------------------ */ decNumber * decNumberCopyNegate(decNumber *res, const decNumber *rhs) { #if DECCHECK if (decCheckOperands(res, DECUNUSED, rhs, DECUNCONT)) return res; #endif decNumberCopy(res, rhs); res->bits^=DECNEG; // invert the sign return res; } // decNumberCopyNegate /* ------------------------------------------------------------------ */ /* decNumberCopySign -- quiet copy and set sign operator */ /* */ /* This sets C = A with the sign of B */ /* */ /* res is C, the result. C may be A */ /* lhs is A */ /* rhs is B */ /* */ /* C must have space for set->digits digits. */ /* No exception or error can occur; this is a quiet bitwise operation.*/ /* ------------------------------------------------------------------ */ decNumber * decNumberCopySign(decNumber *res, const decNumber *lhs, const decNumber *rhs) { uByte sign; // rhs sign #if DECCHECK if (decCheckOperands(res, DECUNUSED, rhs, DECUNCONT)) return res; #endif sign=rhs->bits & DECNEG; // save sign bit decNumberCopy(res, lhs); res->bits&=~DECNEG; // clear the sign res->bits|=sign; // set from rhs return res; } // decNumberCopySign /* ------------------------------------------------------------------ */ /* decNumberGetBCD -- get the coefficient in BCD8 */ /* dn is the source decNumber */ /* bcd is the uInt array that will receive dn->digits BCD bytes, */ /* most-significant at offset 0 */ /* returns bcd */ /* */ /* bcd must have at least dn->digits bytes. No error is possible; if */ /* dn is a NaN or Infinite, digits must be 1 and the coefficient 0. */ /* ------------------------------------------------------------------ */ uByte * decNumberGetBCD(const decNumber *dn, uByte *bcd) { uByte *ub=bcd+dn->digits-1; // -> lsd const Unit *up=dn->lsu; // Unit pointer, -> lsu #if DECDPUN==1 // trivial simple copy for (; ub>=bcd; ub--, up++) *ub=*up; #else // chopping needed uInt u=*up; // work uInt cut=DECDPUN; // downcounter through unit for (; ub>=bcd; ub--) { *ub=(uByte)(u%10); // [*6554 trick inhibits, here] u=u/10; cut--; if (cut>0) continue; // more in this unit up++; u=*up; cut=DECDPUN; } #endif return bcd; } // decNumberGetBCD /* ------------------------------------------------------------------ */ /* decNumberSetBCD -- set (replace) the coefficient from BCD8 */ /* dn is the target decNumber */ /* bcd is the uInt array that will source n BCD bytes, most- */ /* significant at offset 0 */ /* n is the number of digits in the source BCD array (bcd) */ /* returns dn */ /* */ /* dn must have space for at least n digits. No error is possible; */ /* if dn is a NaN, or Infinite, or is to become a zero, n must be 1 */ /* and bcd[0] zero. */ /* ------------------------------------------------------------------ */ decNumber * decNumberSetBCD(decNumber *dn, const uByte *bcd, uInt n) { Unit *up=dn->lsu+D2U(dn->digits)-1; // -> msu [target pointer] const uByte *ub=bcd; // -> source msd #if DECDPUN==1 // trivial simple copy for (; ub=dn->lsu; up--) { // each Unit from msu *up=0; // will take <=DECDPUN digits for (; cut>0; ub++, cut--) *up=X10(*up)+*ub; cut=DECDPUN; // next Unit has all digits } #endif dn->digits=n; // set digit count return dn; } // decNumberSetBCD /* ------------------------------------------------------------------ */ /* decNumberIsNormal -- test normality of a decNumber */ /* dn is the decNumber to test */ /* set is the context to use for Emin */ /* returns 1 if |dn| is finite and >=Nmin, 0 otherwise */ /* ------------------------------------------------------------------ */ Int decNumberIsNormal(const decNumber *dn, decContext *set) { Int ae; // adjusted exponent #if DECCHECK if (decCheckOperands(DECUNRESU, DECUNUSED, dn, set)) return 0; #endif if (decNumberIsSpecial(dn)) return 0; // not finite if (decNumberIsZero(dn)) return 0; // not non-zero ae=dn->exponent+dn->digits-1; // adjusted exponent if (aeemin) return 0; // is subnormal return 1; } // decNumberIsNormal /* ------------------------------------------------------------------ */ /* decNumberIsSubnormal -- test subnormality of a decNumber */ /* dn is the decNumber to test */ /* set is the context to use for Emin */ /* returns 1 if |dn| is finite, non-zero, and exponent+dn->digits-1; // adjusted exponent if (aeemin) return 1; // is subnormal return 0; } // decNumberIsSubnormal /* ------------------------------------------------------------------ */ /* decNumberTrim -- remove insignificant zeros */ /* */ /* dn is the number to trim */ /* returns dn */ /* */ /* All fields are updated as required. This is a utility operation, */ /* so special values are unchanged and no error is possible. The */ /* zeros are removed unconditionally. */ /* ------------------------------------------------------------------ */ decNumber * decNumberTrim(decNumber *dn) { Int dropped; // work decContext set; // .. #if DECCHECK if (decCheckOperands(DECUNRESU, DECUNUSED, dn, DECUNCONT)) return dn; #endif decContextDefault(&set, DEC_INIT_BASE); // clamp=0 return decTrim(dn, &set, 0, 1, &dropped); } // decNumberTrim /* ------------------------------------------------------------------ */ /* decNumberVersion -- return the name and version of this module */ /* */ /* No error is possible. */ /* ------------------------------------------------------------------ */ const char * decNumberVersion(void) { return DECVERSION; } // decNumberVersion /* ------------------------------------------------------------------ */ /* decNumberZero -- set a number to 0 */ /* */ /* dn is the number to set, with space for one digit */ /* returns dn */ /* */ /* No error is possible. */ /* ------------------------------------------------------------------ */ // Memset is not used as it is much slower in some environments. decNumber * decNumberZero(decNumber *dn) { #if DECCHECK if (decCheckOperands(dn, DECUNUSED, DECUNUSED, DECUNCONT)) return dn; #endif dn->bits=0; dn->exponent=0; dn->digits=1; dn->lsu[0]=0; return dn; } // decNumberZero /* ================================================================== */ /* Local routines */ /* ================================================================== */ /* ------------------------------------------------------------------ */ /* decToString -- lay out a number into a string */ /* */ /* dn is the number to lay out */ /* string is where to lay out the number */ /* eng is 1 if Engineering, 0 if Scientific */ /* */ /* string must be at least dn->digits+14 characters long */ /* No error is possible. */ /* */ /* Note that this routine can generate a -0 or 0.000. These are */ /* never generated in subset to-number or arithmetic, but can occur */ /* in non-subset arithmetic (e.g., -1*0 or 1.234-1.234). */ /* ------------------------------------------------------------------ */ // If DECCHECK is enabled the string "?" is returned if a number is // invalid. static void decToString(const decNumber *dn, char *string, Flag eng) { Int exp=dn->exponent; // local copy Int e; // E-part value Int pre; // digits before the '.' Int cut; // for counting digits in a Unit char *c=string; // work [output pointer] const Unit *up=dn->lsu+D2U(dn->digits)-1; // -> msu [input pointer] uInt u, pow; // work #if DECCHECK if (decCheckOperands(DECUNRESU, dn, DECUNUSED, DECUNCONT)) { strcpy(string, "?"); return;} #endif if (decNumberIsNegative(dn)) { // Negatives get a minus *c='-'; c++; } if (dn->bits&DECSPECIAL) { // Is a special value if (decNumberIsInfinite(dn)) { strcpy(c, "Inf"); strcpy(c+3, "inity"); return;} // a NaN if (dn->bits&DECSNAN) { // signalling NaN *c='s'; c++; } strcpy(c, "NaN"); c+=3; // step past // if not a clean non-zero coefficient, that's all there is in a // NaN string if (exp!=0 || (*dn->lsu==0 && dn->digits==1)) return; // [drop through to add integer] } // calculate how many digits in msu, and hence first cut cut=MSUDIGITS(dn->digits); // [faster than remainder] cut--; // power of ten for digit if (exp==0) { // simple integer [common fastpath] for (;up>=dn->lsu; up--) { // each Unit from msu u=*up; // contains DECDPUN digits to lay out for (; cut>=0; c++, cut--) TODIGIT(u, cut, c, pow); cut=DECDPUN-1; // next Unit has all digits } *c='\0'; // terminate the string return;} /* non-0 exponent -- assume plain form */ pre=dn->digits+exp; // digits before '.' e=0; // no E if ((exp>0) || (pre<-5)) { // need exponential form e=exp+dn->digits-1; // calculate E value pre=1; // assume one digit before '.' if (eng && (e!=0)) { // engineering: may need to adjust Int adj; // adjustment // The C remainder operator is undefined for negative numbers, so // a positive remainder calculation must be used here if (e<0) { adj=(-e)%3; if (adj!=0) adj=3-adj; } else { // e>0 adj=e%3; } e=e-adj; // if dealing with zero still produce an exponent which is a // multiple of three, as expected, but there will only be the // one zero before the E, still. Otherwise note the padding. if (!ISZERO(dn)) pre+=adj; else { // is zero if (adj!=0) { // 0.00Esnn needed e=e+3; pre=-(2-adj); } } // zero } // eng } // need exponent /* lay out the digits of the coefficient, adding 0s and . as needed */ u=*up; if (pre>0) { // xxx.xxx or xx00 (engineering) form Int n=pre; for (; pre>0; pre--, c++, cut--) { if (cut<0) { // need new Unit if (up==dn->lsu) break; // out of input digits (pre>digits) up--; cut=DECDPUN-1; u=*up; } TODIGIT(u, cut, c, pow); } if (ndigits) { // more to come, after '.' *c='.'; c++; for (;; c++, cut--) { if (cut<0) { // need new Unit if (up==dn->lsu) break; // out of input digits up--; cut=DECDPUN-1; u=*up; } TODIGIT(u, cut, c, pow); } } else for (; pre>0; pre--, c++) *c='0'; // 0 padding (for engineering) needed } else { // 0.xxx or 0.000xxx form *c='0'; c++; *c='.'; c++; for (; pre<0; pre++, c++) *c='0'; // add any 0's after '.' for (; ; c++, cut--) { if (cut<0) { // need new Unit if (up==dn->lsu) break; // out of input digits up--; cut=DECDPUN-1; u=*up; } TODIGIT(u, cut, c, pow); } } /* Finally add the E-part, if needed. It will never be 0, has a base maximum and minimum of +999999999 through -999999999, but could range down to -1999999998 for anormal numbers */ if (e!=0) { Flag had=0; // 1=had non-zero *c='E'; c++; *c='+'; c++; // assume positive u=e; // .. if (e<0) { *(c-1)='-'; // oops, need - u=-e; // uInt, please } // lay out the exponent [_itoa or equivalent is not ANSI C] for (cut=9; cut>=0; cut--) { TODIGIT(u, cut, c, pow); if (*c=='0' && !had) continue; // skip leading zeros had=1; // had non-0 c++; // step for next } // cut } *c='\0'; // terminate the string (all paths) return; } // decToString /* ------------------------------------------------------------------ */ /* decAddOp -- add/subtract operation */ /* */ /* This computes C = A + B */ /* */ /* res is C, the result. C may be A and/or B (e.g., X=X+X) */ /* lhs is A */ /* rhs is B */ /* set is the context */ /* negate is DECNEG if rhs should be negated, or 0 otherwise */ /* status accumulates status for the caller */ /* */ /* C must have space for set->digits digits. */ /* Inexact in status must be 0 for correct Exact zero sign in result */ /* ------------------------------------------------------------------ */ /* If possible, the coefficient is calculated directly into C. */ /* However, if: */ /* -- a digits+1 calculation is needed because the numbers are */ /* unaligned and span more than set->digits digits */ /* -- a carry to digits+1 digits looks possible */ /* -- C is the same as A or B, and the result would destructively */ /* overlap the A or B coefficient */ /* then the result must be calculated into a temporary buffer. In */ /* this case a local (stack) buffer is used if possible, and only if */ /* too long for that does malloc become the final resort. */ /* */ /* Misalignment is handled as follows: */ /* Apad: (AExp>BExp) Swap operands and proceed as for BExp>AExp. */ /* BPad: Apply the padding by a combination of shifting (whole */ /* units) and multiplication (part units). */ /* */ /* Addition, especially x=x+1, is speed-critical. */ /* The static buffer is larger than might be expected to allow for */ /* calls from higher-level functions (notable exp). */ /* ------------------------------------------------------------------ */ static decNumber * decAddOp(decNumber *res, const decNumber *lhs, const decNumber *rhs, decContext *set, uByte negate, uInt *status) { #if DECSUBSET decNumber *alloclhs=NULL; // non-NULL if rounded lhs allocated decNumber *allocrhs=NULL; // .., rhs #endif Int rhsshift; // working shift (in Units) Int maxdigits; // longest logical length Int mult; // multiplier Int residue; // rounding accumulator uByte bits; // result bits Flag diffsign; // non-0 if arguments have different sign Unit *acc; // accumulator for result Unit accbuff[SD2U(DECBUFFER*2+20)]; // local buffer [*2+20 reduces many // allocations when called from // other operations, notable exp] Unit *allocacc=NULL; // -> allocated acc buffer, iff allocated Int reqdigits=set->digits; // local copy; requested DIGITS Int padding; // work #if DECCHECK if (decCheckOperands(res, lhs, rhs, set)) return res; #endif do { // protect allocated storage #if DECSUBSET if (!set->extended) { // reduce operands and set lostDigits status, as needed if (lhs->digits>reqdigits) { alloclhs=decRoundOperand(lhs, set, status); if (alloclhs==NULL) break; lhs=alloclhs; } if (rhs->digits>reqdigits) { allocrhs=decRoundOperand(rhs, set, status); if (allocrhs==NULL) break; rhs=allocrhs; } } #endif // [following code does not require input rounding] // note whether signs differ [used all paths] diffsign=(Flag)((lhs->bits^rhs->bits^negate)&DECNEG); // handle infinities and NaNs if (SPECIALARGS) { // a special bit set if (SPECIALARGS & (DECSNAN | DECNAN)) // a NaN decNaNs(res, lhs, rhs, set, status); else { // one or two infinities if (decNumberIsInfinite(lhs)) { // LHS is infinity // two infinities with different signs is invalid if (decNumberIsInfinite(rhs) && diffsign) { *status|=DEC_Invalid_operation; break; } bits=lhs->bits & DECNEG; // get sign from LHS } else bits=(rhs->bits^negate) & DECNEG;// RHS must be Infinity bits|=DECINF; decNumberZero(res); res->bits=bits; // set +/- infinity } // an infinity break; } // Quick exit for add 0s; return the non-0, modified as need be if (ISZERO(lhs)) { Int adjust; // work Int lexp=lhs->exponent; // save in case LHS==RES bits=lhs->bits; // .. residue=0; // clear accumulator decCopyFit(res, rhs, set, &residue, status); // copy (as needed) res->bits^=negate; // flip if rhs was negated #if DECSUBSET if (set->extended) { // exponents on zeros count #endif // exponent will be the lower of the two adjust=lexp-res->exponent; // adjustment needed [if -ve] if (ISZERO(res)) { // both 0: special IEEE 754 rules if (adjust<0) res->exponent=lexp; // set exponent // 0-0 gives +0 unless rounding to -infinity, and -0-0 gives -0 if (diffsign) { if (set->round!=DEC_ROUND_FLOOR) res->bits=0; else res->bits=DECNEG; // preserve 0 sign } } else { // non-0 res if (adjust<0) { // 0-padding needed if ((res->digits-adjust)>set->digits) { adjust=res->digits-set->digits; // to fit exactly *status|=DEC_Rounded; // [but exact] } res->digits=decShiftToMost(res->lsu, res->digits, -adjust); res->exponent+=adjust; // set the exponent. } } // non-0 res #if DECSUBSET } // extended #endif decFinish(res, set, &residue, status); // clean and finalize break;} if (ISZERO(rhs)) { // [lhs is non-zero] Int adjust; // work Int rexp=rhs->exponent; // save in case RHS==RES bits=rhs->bits; // be clean residue=0; // clear accumulator decCopyFit(res, lhs, set, &residue, status); // copy (as needed) #if DECSUBSET if (set->extended) { // exponents on zeros count #endif // exponent will be the lower of the two // [0-0 case handled above] adjust=rexp-res->exponent; // adjustment needed [if -ve] if (adjust<0) { // 0-padding needed if ((res->digits-adjust)>set->digits) { adjust=res->digits-set->digits; // to fit exactly *status|=DEC_Rounded; // [but exact] } res->digits=decShiftToMost(res->lsu, res->digits, -adjust); res->exponent+=adjust; // set the exponent. } #if DECSUBSET } // extended #endif decFinish(res, set, &residue, status); // clean and finalize break;} // [NB: both fastpath and mainpath code below assume these cases // (notably 0-0) have already been handled] // calculate the padding needed to align the operands padding=rhs->exponent-lhs->exponent; // Fastpath cases where the numbers are aligned and normal, the RHS // is all in one unit, no operand rounding is needed, and no carry, // lengthening, or borrow is needed if (padding==0 && rhs->digits<=DECDPUN && rhs->exponent>=set->emin // [some normals drop through] && rhs->exponent<=set->emax-set->digits+1 // [could clamp] && rhs->digits<=reqdigits && lhs->digits<=reqdigits) { Int partial=*lhs->lsu; if (!diffsign) { // adding partial+=*rhs->lsu; if ((partial<=DECDPUNMAX) // result fits in unit && (lhs->digits>=DECDPUN || // .. and no digits-count change partial<(Int)powers[lhs->digits])) { // .. if (res!=lhs) decNumberCopy(res, lhs); // not in place *res->lsu=(Unit)partial; // [copy could have overwritten RHS] break; } // else drop out for careful add } else { // signs differ partial-=*rhs->lsu; if (partial>0) { // no borrow needed, and non-0 result if (res!=lhs) decNumberCopy(res, lhs); // not in place *res->lsu=(Unit)partial; // this could have reduced digits [but result>0] res->digits=decGetDigits(res->lsu, D2U(res->digits)); break; } // else drop out for careful subtract } } // Now align (pad) the lhs or rhs so they can be added or // subtracted, as necessary. If one number is much larger than // the other (that is, if in plain form there is a least one // digit between the lowest digit of one and the highest of the // other) padding with up to DIGITS-1 trailing zeros may be // needed; then apply rounding (as exotic rounding modes may be // affected by the residue). rhsshift=0; // rhs shift to left (padding) in Units bits=lhs->bits; // assume sign is that of LHS mult=1; // likely multiplier // [if padding==0 the operands are aligned; no padding is needed] if (padding!=0) { // some padding needed; always pad the RHS, as any required // padding can then be effected by a simple combination of // shifts and a multiply Flag swapped=0; if (padding<0) { // LHS needs the padding const decNumber *t; padding=-padding; // will be +ve bits=(uByte)(rhs->bits^negate); // assumed sign is now that of RHS t=lhs; lhs=rhs; rhs=t; swapped=1; } // If, after pad, rhs would be longer than lhs by digits+1 or // more then lhs cannot affect the answer, except as a residue, // so only need to pad up to a length of DIGITS+1. if (rhs->digits+padding > lhs->digits+reqdigits+1) { // The RHS is sufficient // for residue use the relative sign indication... Int shift=reqdigits-rhs->digits; // left shift needed residue=1; // residue for rounding if (diffsign) residue=-residue; // signs differ // copy, shortening if necessary decCopyFit(res, rhs, set, &residue, status); // if it was already shorter, then need to pad with zeros if (shift>0) { res->digits=decShiftToMost(res->lsu, res->digits, shift); res->exponent-=shift; // adjust the exponent. } // flip the result sign if unswapped and rhs was negated if (!swapped) res->bits^=negate; decFinish(res, set, &residue, status); // done break;} // LHS digits may affect result rhsshift=D2U(padding+1)-1; // this much by Unit shift .. mult=powers[padding-(rhsshift*DECDPUN)]; // .. this by multiplication } // padding needed if (diffsign) mult=-mult; // signs differ // determine the longer operand maxdigits=rhs->digits+padding; // virtual length of RHS if (lhs->digits>maxdigits) maxdigits=lhs->digits; // Decide on the result buffer to use; if possible place directly // into result. acc=res->lsu; // assume add direct to result // If destructive overlap, or the number is too long, or a carry or // borrow to DIGITS+1 might be possible, a buffer must be used. // [Might be worth more sophisticated tests when maxdigits==reqdigits] if ((maxdigits>=reqdigits) // is, or could be, too large || (res==rhs && rhsshift>0)) { // destructive overlap // buffer needed, choose it; units for maxdigits digits will be // needed, +1 Unit for carry or borrow Int need=D2U(maxdigits)+1; acc=accbuff; // assume use local buffer if (need*sizeof(Unit)>sizeof(accbuff)) { // printf("malloc add %ld %ld\n", need, sizeof(accbuff)); allocacc=(Unit *)malloc(need*sizeof(Unit)); if (allocacc==NULL) { // hopeless -- abandon *status|=DEC_Insufficient_storage; break;} acc=allocacc; } } res->bits=(uByte)(bits&DECNEG); // it's now safe to overwrite.. res->exponent=lhs->exponent; // .. operands (even if aliased) #if DECTRACE decDumpAr('A', lhs->lsu, D2U(lhs->digits)); decDumpAr('B', rhs->lsu, D2U(rhs->digits)); printf(" :h: %ld %ld\n", rhsshift, mult); #endif // add [A+B*m] or subtract [A+B*(-m)] res->digits=decUnitAddSub(lhs->lsu, D2U(lhs->digits), rhs->lsu, D2U(rhs->digits), rhsshift, acc, mult) *DECDPUN; // [units -> digits] if (res->digits<0) { // borrowed... res->digits=-res->digits; res->bits^=DECNEG; // flip the sign } #if DECTRACE decDumpAr('+', acc, D2U(res->digits)); #endif // If a buffer was used the result must be copied back, possibly // shortening. (If no buffer was used then the result must have // fit, so can't need rounding and residue must be 0.) residue=0; // clear accumulator if (acc!=res->lsu) { #if DECSUBSET if (set->extended) { // round from first significant digit #endif // remove leading zeros that were added due to rounding up to // integral Units -- before the test for rounding. if (res->digits>reqdigits) res->digits=decGetDigits(acc, D2U(res->digits)); decSetCoeff(res, set, acc, res->digits, &residue, status); #if DECSUBSET } else { // subset arithmetic rounds from original significant digit // May have an underestimate. This only occurs when both // numbers fit in DECDPUN digits and are padding with a // negative multiple (-10, -100...) and the top digit(s) become // 0. (This only matters when using X3.274 rules where the // leading zero could be included in the rounding.) if (res->digitsdigits))=0; // ensure leading 0 is there res->digits=maxdigits; } else { // remove leading zeros that added due to rounding up to // integral Units (but only those in excess of the original // maxdigits length, unless extended) before test for rounding. if (res->digits>reqdigits) { res->digits=decGetDigits(acc, D2U(res->digits)); if (res->digitsdigits=maxdigits; } } decSetCoeff(res, set, acc, res->digits, &residue, status); // Now apply rounding if needed before removing leading zeros. // This is safe because subnormals are not a possibility if (residue!=0) { decApplyRound(res, set, residue, status); residue=0; // did what needed to be done } } // subset #endif } // used buffer // strip leading zeros [these were left on in case of subset subtract] res->digits=decGetDigits(res->lsu, D2U(res->digits)); // apply checks and rounding decFinish(res, set, &residue, status); // "When the sum of two operands with opposite signs is exactly // zero, the sign of that sum shall be '+' in all rounding modes // except round toward -Infinity, in which mode that sign shall be // '-'." [Subset zeros also never have '-', set by decFinish.] if (ISZERO(res) && diffsign #if DECSUBSET && set->extended #endif && (*status&DEC_Inexact)==0) { if (set->round==DEC_ROUND_FLOOR) res->bits|=DECNEG; // sign - else res->bits&=~DECNEG; // sign + } } while(0); // end protected if (allocacc!=NULL) free(allocacc); // drop any storage used #if DECSUBSET if (allocrhs!=NULL) free(allocrhs); // .. if (alloclhs!=NULL) free(alloclhs); // .. #endif return res; } // decAddOp /* ------------------------------------------------------------------ */ /* decDivideOp -- division operation */ /* */ /* This routine performs the calculations for all four division */ /* operators (divide, divideInteger, remainder, remainderNear). */ /* */ /* C=A op B */ /* */ /* res is C, the result. C may be A and/or B (e.g., X=X/X) */ /* lhs is A */ /* rhs is B */ /* set is the context */ /* op is DIVIDE, DIVIDEINT, REMAINDER, or REMNEAR respectively. */ /* status is the usual accumulator */ /* */ /* C must have space for set->digits digits. */ /* */ /* ------------------------------------------------------------------ */ /* The underlying algorithm of this routine is the same as in the */ /* 1981 S/370 implementation, that is, non-restoring long division */ /* with bi-unit (rather than bi-digit) estimation for each unit */ /* multiplier. In this pseudocode overview, complications for the */ /* Remainder operators and division residues for exact rounding are */ /* omitted for clarity. */ /* */ /* Prepare operands and handle special values */ /* Test for x/0 and then 0/x */ /* Exp =Exp1 - Exp2 */ /* Exp =Exp +len(var1) -len(var2) */ /* Sign=Sign1 * Sign2 */ /* Pad accumulator (Var1) to double-length with 0's (pad1) */ /* Pad Var2 to same length as Var1 */ /* msu2pair/plus=1st 2 or 1 units of var2, +1 to allow for round */ /* have=0 */ /* Do until (have=digits+1 OR residue=0) */ /* if exp<0 then if integer divide/residue then leave */ /* this_unit=0 */ /* Do forever */ /* compare numbers */ /* if <0 then leave inner_loop */ /* if =0 then (* quick exit without subtract *) do */ /* this_unit=this_unit+1; output this_unit */ /* leave outer_loop; end */ /* Compare lengths of numbers (mantissae): */ /* If same then tops2=msu2pair -- {units 1&2 of var2} */ /* else tops2=msu2plus -- {0, unit 1 of var2} */ /* tops1=first_unit_of_Var1*10**DECDPUN +second_unit_of_var1 */ /* mult=tops1/tops2 -- Good and safe guess at divisor */ /* if mult=0 then mult=1 */ /* this_unit=this_unit+mult */ /* subtract */ /* end inner_loop */ /* if have\=0 | this_unit\=0 then do */ /* output this_unit */ /* have=have+1; end */ /* var2=var2/10 */ /* exp=exp-1 */ /* end outer_loop */ /* exp=exp+1 -- set the proper exponent */ /* if have=0 then generate answer=0 */ /* Return (Result is defined by Var1) */ /* */ /* ------------------------------------------------------------------ */ /* Two working buffers are needed during the division; one (digits+ */ /* 1) to accumulate the result, and the other (up to 2*digits+1) for */ /* long subtractions. These are acc and var1 respectively. */ /* var1 is a copy of the lhs coefficient, var2 is the rhs coefficient.*/ /* The static buffers may be larger than might be expected to allow */ /* for calls from higher-level functions (notable exp). */ /* ------------------------------------------------------------------ */ static decNumber * decDivideOp(decNumber *res, const decNumber *lhs, const decNumber *rhs, decContext *set, Flag op, uInt *status) { #if DECSUBSET decNumber *alloclhs=NULL; // non-NULL if rounded lhs allocated decNumber *allocrhs=NULL; // .., rhs #endif Unit accbuff[SD2U(DECBUFFER+DECDPUN+10)]; // local buffer Unit *acc=accbuff; // -> accumulator array for result Unit *allocacc=NULL; // -> allocated buffer, iff allocated Unit *accnext; // -> where next digit will go Int acclength; // length of acc needed [Units] Int accunits; // count of units accumulated Int accdigits; // count of digits accumulated Unit varbuff[SD2U(DECBUFFER*2+DECDPUN)]; // buffer for var1 Unit *var1=varbuff; // -> var1 array for long subtraction Unit *varalloc=NULL; // -> allocated buffer, iff used Unit *msu1; // -> msu of var1 const Unit *var2; // -> var2 array const Unit *msu2; // -> msu of var2 Int msu2plus; // msu2 plus one [does not vary] eInt msu2pair; // msu2 pair plus one [does not vary] Int var1units, var2units; // actual lengths Int var2ulen; // logical length (units) Int var1initpad=0; // var1 initial padding (digits) Int maxdigits; // longest LHS or required acc length Int mult; // multiplier for subtraction Unit thisunit; // current unit being accumulated Int residue; // for rounding Int reqdigits=set->digits; // requested DIGITS Int exponent; // working exponent Int maxexponent=0; // DIVIDE maximum exponent if unrounded uByte bits; // working sign Unit *target; // work const Unit *source; // .. uInt const *pow; // .. Int shift, cut; // .. #if DECSUBSET Int dropped; // work #endif #if DECCHECK if (decCheckOperands(res, lhs, rhs, set)) return res; #endif do { // protect allocated storage #if DECSUBSET if (!set->extended) { // reduce operands and set lostDigits status, as needed if (lhs->digits>reqdigits) { alloclhs=decRoundOperand(lhs, set, status); if (alloclhs==NULL) break; lhs=alloclhs; } if (rhs->digits>reqdigits) { allocrhs=decRoundOperand(rhs, set, status); if (allocrhs==NULL) break; rhs=allocrhs; } } #endif // [following code does not require input rounding] bits=(lhs->bits^rhs->bits)&DECNEG; // assumed sign for divisions // handle infinities and NaNs if (SPECIALARGS) { // a special bit set if (SPECIALARGS & (DECSNAN | DECNAN)) { // one or two NaNs decNaNs(res, lhs, rhs, set, status); break; } // one or two infinities if (decNumberIsInfinite(lhs)) { // LHS (dividend) is infinite if (decNumberIsInfinite(rhs) || // two infinities are invalid .. op & (REMAINDER | REMNEAR)) { // as is remainder of infinity *status|=DEC_Invalid_operation; break; } // [Note that infinity/0 raises no exceptions] decNumberZero(res); res->bits=bits|DECINF; // set +/- infinity break; } else { // RHS (divisor) is infinite residue=0; if (op&(REMAINDER|REMNEAR)) { // result is [finished clone of] lhs decCopyFit(res, lhs, set, &residue, status); } else { // a division decNumberZero(res); res->bits=bits; // set +/- zero // for DIVIDEINT the exponent is always 0. For DIVIDE, result // is a 0 with infinitely negative exponent, clamped to minimum if (op&DIVIDE) { res->exponent=set->emin-set->digits+1; *status|=DEC_Clamped; } } decFinish(res, set, &residue, status); break; } } // handle 0 rhs (x/0) if (ISZERO(rhs)) { // x/0 is always exceptional if (ISZERO(lhs)) { decNumberZero(res); // [after lhs test] *status|=DEC_Division_undefined;// 0/0 will become NaN } else { decNumberZero(res); if (op&(REMAINDER|REMNEAR)) *status|=DEC_Invalid_operation; else { *status|=DEC_Division_by_zero; // x/0 res->bits=bits|DECINF; // .. is +/- Infinity } } break;} // handle 0 lhs (0/x) if (ISZERO(lhs)) { // 0/x [x!=0] #if DECSUBSET if (!set->extended) decNumberZero(res); else { #endif if (op&DIVIDE) { residue=0; exponent=lhs->exponent-rhs->exponent; // ideal exponent decNumberCopy(res, lhs); // [zeros always fit] res->bits=bits; // sign as computed res->exponent=exponent; // exponent, too decFinalize(res, set, &residue, status); // check exponent } else if (op&DIVIDEINT) { decNumberZero(res); // integer 0 res->bits=bits; // sign as computed } else { // a remainder exponent=rhs->exponent; // [save in case overwrite] decNumberCopy(res, lhs); // [zeros always fit] if (exponentexponent) res->exponent=exponent; // use lower } #if DECSUBSET } #endif break;} // Precalculate exponent. This starts off adjusted (and hence fits // in 31 bits) and becomes the usual unadjusted exponent as the // division proceeds. The order of evaluation is important, here, // to avoid wrap. exponent=(lhs->exponent+lhs->digits)-(rhs->exponent+rhs->digits); // If the working exponent is -ve, then some quick exits are // possible because the quotient is known to be <1 // [for REMNEAR, it needs to be < -1, as -0.5 could need work] if (exponent<0 && !(op==DIVIDE)) { if (op&DIVIDEINT) { decNumberZero(res); // integer part is 0 #if DECSUBSET if (set->extended) #endif res->bits=bits; // set +/- zero break;} // fastpath remainders so long as the lhs has the smaller // (or equal) exponent if (lhs->exponent<=rhs->exponent) { if (op&REMAINDER || exponent<-1) { // It is REMAINDER or safe REMNEAR; result is [finished // clone of] lhs (r = x - 0*y) residue=0; decCopyFit(res, lhs, set, &residue, status); decFinish(res, set, &residue, status); break; } // [unsafe REMNEAR drops through] } } // fastpaths /* Long (slow) division is needed; roll up the sleeves... */ // The accumulator will hold the quotient of the division. // If it needs to be too long for stack storage, then allocate. acclength=D2U(reqdigits+DECDPUN); // in Units if (acclength*sizeof(Unit)>sizeof(accbuff)) { // printf("malloc dvacc %ld units\n", acclength); allocacc=(Unit *)malloc(acclength*sizeof(Unit)); if (allocacc==NULL) { // hopeless -- abandon *status|=DEC_Insufficient_storage; break;} acc=allocacc; // use the allocated space } // var1 is the padded LHS ready for subtractions. // If it needs to be too long for stack storage, then allocate. // The maximum units needed for var1 (long subtraction) is: // Enough for // (rhs->digits+reqdigits-1) -- to allow full slide to right // or (lhs->digits) -- to allow for long lhs // whichever is larger // +1 -- for rounding of slide to right // +1 -- for leading 0s // +1 -- for pre-adjust if a remainder or DIVIDEINT // [Note: unused units do not participate in decUnitAddSub data] maxdigits=rhs->digits+reqdigits-1; if (lhs->digits>maxdigits) maxdigits=lhs->digits; var1units=D2U(maxdigits)+2; // allocate a guard unit above msu1 for REMAINDERNEAR if (!(op&DIVIDE)) var1units++; if ((var1units+1)*sizeof(Unit)>sizeof(varbuff)) { // printf("malloc dvvar %ld units\n", var1units+1); varalloc=(Unit *)malloc((var1units+1)*sizeof(Unit)); if (varalloc==NULL) { // hopeless -- abandon *status|=DEC_Insufficient_storage; break;} var1=varalloc; // use the allocated space } // Extend the lhs and rhs to full long subtraction length. The lhs // is truly extended into the var1 buffer, with 0 padding, so a // subtract in place is always possible. The rhs (var2) has // virtual padding (implemented by decUnitAddSub). // One guard unit was allocated above msu1 for rem=rem+rem in // REMAINDERNEAR. msu1=var1+var1units-1; // msu of var1 source=lhs->lsu+D2U(lhs->digits)-1; // msu of input array for (target=msu1; source>=lhs->lsu; source--, target--) *target=*source; for (; target>=var1; target--) *target=0; // rhs (var2) is left-aligned with var1 at the start var2ulen=var1units; // rhs logical length (units) var2units=D2U(rhs->digits); // rhs actual length (units) var2=rhs->lsu; // -> rhs array msu2=var2+var2units-1; // -> msu of var2 [never changes] // now set up the variables which will be used for estimating the // multiplication factor. If these variables are not exact, add // 1 to make sure that the multiplier is never overestimated. msu2plus=*msu2; // it's value .. if (var2units>1) msu2plus++; // .. +1 if any more msu2pair=(eInt)*msu2*(DECDPUNMAX+1);// top two pair .. if (var2units>1) { // .. [else treat 2nd as 0] msu2pair+=*(msu2-1); // .. if (var2units>2) msu2pair++; // .. +1 if any more } // The calculation is working in units, which may have leading zeros, // but the exponent was calculated on the assumption that they are // both left-aligned. Adjust the exponent to compensate: add the // number of leading zeros in var1 msu and subtract those in var2 msu. // [This is actually done by counting the digits and negating, as // lead1=DECDPUN-digits1, and similarly for lead2.] for (pow=&powers[1]; *msu1>=*pow; pow++) exponent--; for (pow=&powers[1]; *msu2>=*pow; pow++) exponent++; // Now, if doing an integer divide or remainder, ensure that // the result will be Unit-aligned. To do this, shift the var1 // accumulator towards least if need be. (It's much easier to // do this now than to reassemble the residue afterwards, if // doing a remainder.) Also ensure the exponent is not negative. if (!(op&DIVIDE)) { Unit *u; // work // save the initial 'false' padding of var1, in digits var1initpad=(var1units-D2U(lhs->digits))*DECDPUN; // Determine the shift to do. if (exponent<0) cut=-exponent; else cut=DECDPUN-exponent%DECDPUN; decShiftToLeast(var1, var1units, cut); exponent+=cut; // maintain numerical value var1initpad-=cut; // .. and reduce padding // clean any most-significant units which were just emptied for (u=msu1; cut>=DECDPUN; cut-=DECDPUN, u--) *u=0; } // align else { // is DIVIDE maxexponent=lhs->exponent-rhs->exponent; // save // optimization: if the first iteration will just produce 0, // preadjust to skip it [valid for DIVIDE only] if (*msu1<*msu2) { var2ulen--; // shift down exponent-=DECDPUN; // update the exponent } } // ---- start the long-division loops ------------------------------ accunits=0; // no units accumulated yet accdigits=0; // .. or digits accnext=acc+acclength-1; // -> msu of acc [NB: allows digits+1] for (;;) { // outer forever loop thisunit=0; // current unit assumed 0 // find the next unit for (;;) { // inner forever loop // strip leading zero units [from either pre-adjust or from // subtract last time around]. Leave at least one unit. for (; *msu1==0 && msu1>var1; msu1--) var1units--; if (var1units msu for (pv1=msu1; ; pv1--, pv2--) { // v1=*pv1 -- always OK v2=0; // assume in padding if (pv2>=var2) v2=*pv2; // in range if (*pv1!=v2) break; // no longer the same if (pv1==var1) break; // done; leave pv1 as is } // here when all inspected or a difference seen if (*pv1v2. Prepare for real subtraction; the lengths are equal // Estimate the multiplier (there's always a msu1-1)... // Bring in two units of var2 to provide a good estimate. mult=(Int)(((eInt)*msu1*(DECDPUNMAX+1)+*(msu1-1))/msu2pair); } // lengths the same else { // var1units > var2ulen, so subtraction is safe // The var2 msu is one unit towards the lsu of the var1 msu, // so only one unit for var2 can be used. mult=(Int)(((eInt)*msu1*(DECDPUNMAX+1)+*(msu1-1))/msu2plus); } if (mult==0) mult=1; // must always be at least 1 // subtraction needed; var1 is > var2 thisunit=(Unit)(thisunit+mult); // accumulate // subtract var1-var2, into var1; only the overlap needs // processing, as this is an in-place calculation shift=var2ulen-var2units; #if DECTRACE decDumpAr('1', &var1[shift], var1units-shift); decDumpAr('2', var2, var2units); printf("m=%ld\n", -mult); #endif decUnitAddSub(&var1[shift], var1units-shift, var2, var2units, 0, &var1[shift], -mult); #if DECTRACE decDumpAr('#', &var1[shift], var1units-shift); #endif // var1 now probably has leading zeros; these are removed at the // top of the inner loop. } // inner loop // The next unit has been calculated in full; unless it's a // leading zero, add to acc if (accunits!=0 || thisunit!=0) { // is first or non-zero *accnext=thisunit; // store in accumulator // account exactly for the new digits if (accunits==0) { accdigits++; // at least one for (pow=&powers[1]; thisunit>=*pow; pow++) accdigits++; } else accdigits+=DECDPUN; accunits++; // update count accnext--; // ready for next if (accdigits>reqdigits) break; // have enough digits } // if the residue is zero, the operation is done (unless divide // or divideInteger and still not enough digits yet) if (*var1==0 && var1units==1) { // residue is 0 if (op&(REMAINDER|REMNEAR)) break; if ((op&DIVIDE) && (exponent<=maxexponent)) break; // [drop through if divideInteger] } // also done enough if calculating remainder or integer // divide and just did the last ('units') unit if (exponent==0 && !(op&DIVIDE)) break; // to get here, var1 is less than var2, so divide var2 by the per- // Unit power of ten and go for the next digit var2ulen--; // shift down exponent-=DECDPUN; // update the exponent } // outer loop // ---- division is complete --------------------------------------- // here: acc has at least reqdigits+1 of good results (or fewer // if early stop), starting at accnext+1 (its lsu) // var1 has any residue at the stopping point // accunits is the number of digits collected in acc if (accunits==0) { // acc is 0 accunits=1; // show have a unit .. accdigits=1; // .. *accnext=0; // .. whose value is 0 } else accnext++; // back to last placed // accnext now -> lowest unit of result residue=0; // assume no residue if (op&DIVIDE) { // record the presence of any residue, for rounding if (*var1!=0 || var1units>1) residue=1; else { // no residue // Had an exact division; clean up spurious trailing 0s. // There will be at most DECDPUN-1, from the final multiply, // and then only if the result is non-0 (and even) and the // exponent is 'loose'. #if DECDPUN>1 Unit lsu=*accnext; if (!(lsu&0x01) && (lsu!=0)) { // count the trailing zeros Int drop=0; for (;; drop++) { // [will terminate because lsu!=0] if (exponent>=maxexponent) break; // don't chop real 0s #if DECDPUN<=4 if ((lsu-QUOT10(lsu, drop+1) *powers[drop+1])!=0) break; // found non-0 digit #else if (lsu%powers[drop+1]!=0) break; // found non-0 digit #endif exponent++; } if (drop>0) { accunits=decShiftToLeast(accnext, accunits, drop); accdigits=decGetDigits(accnext, accunits); accunits=D2U(accdigits); // [exponent was adjusted in the loop] } } // neither odd nor 0 #endif } // exact divide } // divide else /* op!=DIVIDE */ { // check for coefficient overflow if (accdigits+exponent>reqdigits) { *status|=DEC_Division_impossible; break; } if (op & (REMAINDER|REMNEAR)) { // [Here, the exponent will be 0, because var1 was adjusted // appropriately.] Int postshift; // work Flag wasodd=0; // integer was odd Unit *quotlsu; // for save Int quotdigits; // .. bits=lhs->bits; // remainder sign is always as lhs // Fastpath when residue is truly 0 is worthwhile [and // simplifies the code below] if (*var1==0 && var1units==1) { // residue is 0 Int exp=lhs->exponent; // save min(exponents) if (rhs->exponentexponent; decNumberZero(res); // 0 coefficient #if DECSUBSET if (set->extended) #endif res->exponent=exp; // .. with proper exponent res->bits=(uByte)(bits&DECNEG); // [cleaned] decFinish(res, set, &residue, status); // might clamp break; } // note if the quotient was odd if (*accnext & 0x01) wasodd=1; // acc is odd quotlsu=accnext; // save in case need to reinspect quotdigits=accdigits; // .. // treat the residue, in var1, as the value to return, via acc // calculate the unused zero digits. This is the smaller of: // var1 initial padding (saved above) // var2 residual padding, which happens to be given by: postshift=var1initpad+exponent-lhs->exponent+rhs->exponent; // [the 'exponent' term accounts for the shifts during divide] if (var1initpadexponent; // exponent is smaller of lhs & rhs if (rhs->exponentexponent; // Now correct the result if doing remainderNear; if it // (looking just at coefficients) is > rhs/2, or == rhs/2 and // the integer was odd then the result should be rem-rhs. if (op&REMNEAR) { Int compare, tarunits; // work Unit *up; // .. // calculate remainder*2 into the var1 buffer (which has // 'headroom' of an extra unit and hence enough space) // [a dedicated 'double' loop would be faster, here] tarunits=decUnitAddSub(accnext, accunits, accnext, accunits, 0, accnext, 1); // decDumpAr('r', accnext, tarunits); // Here, accnext (var1) holds tarunits Units with twice the // remainder's coefficient, which must now be compared to the // RHS. The remainder's exponent may be smaller than the RHS's. compare=decUnitCompare(accnext, tarunits, rhs->lsu, D2U(rhs->digits), rhs->exponent-exponent); if (compare==BADINT) { // deep trouble *status|=DEC_Insufficient_storage; break;} // now restore the remainder by dividing by two; the lsu // is known to be even. for (up=accnext; up0 || (compare==0 && wasodd)) { // adjustment needed Int exp, expunits, exprem; // work // This is effectively causing round-up of the quotient, // so if it was the rare case where it was full and all // nines, it would overflow and hence division-impossible // should be raised Flag allnines=0; // 1 if quotient all nines if (quotdigits==reqdigits) { // could be borderline for (up=quotlsu; ; up++) { if (quotdigits>DECDPUN) { if (*up!=DECDPUNMAX) break;// non-nines } else { // this is the last Unit if (*up==powers[quotdigits]-1) allnines=1; break; } quotdigits-=DECDPUN; // checked those digits } // up } // borderline check if (allnines) { *status|=DEC_Division_impossible; break;} // rem-rhs is needed; the sign will invert. Again, var1 // can safely be used for the working Units array. exp=rhs->exponent-exponent; // RHS padding needed // Calculate units and remainder from exponent. expunits=exp/DECDPUN; exprem=exp%DECDPUN; // subtract [A+B*(-m)]; the result will always be negative accunits=-decUnitAddSub(accnext, accunits, rhs->lsu, D2U(rhs->digits), expunits, accnext, -(Int)powers[exprem]); accdigits=decGetDigits(accnext, accunits); // count digits exactly accunits=D2U(accdigits); // and recalculate the units for copy // [exponent is as for original remainder] bits^=DECNEG; // flip the sign } } // REMNEAR } // REMAINDER or REMNEAR } // not DIVIDE // Set exponent and bits res->exponent=exponent; res->bits=(uByte)(bits&DECNEG); // [cleaned] // Now the coefficient. decSetCoeff(res, set, accnext, accdigits, &residue, status); decFinish(res, set, &residue, status); // final cleanup #if DECSUBSET // If a divide then strip trailing zeros if subset [after round] if (!set->extended && (op==DIVIDE)) decTrim(res, set, 0, 1, &dropped); #endif } while(0); // end protected if (varalloc!=NULL) free(varalloc); // drop any storage used if (allocacc!=NULL) free(allocacc); // .. #if DECSUBSET if (allocrhs!=NULL) free(allocrhs); // .. if (alloclhs!=NULL) free(alloclhs); // .. #endif return res; } // decDivideOp /* ------------------------------------------------------------------ */ /* decMultiplyOp -- multiplication operation */ /* */ /* This routine performs the multiplication C=A x B. */ /* */ /* res is C, the result. C may be A and/or B (e.g., X=X*X) */ /* lhs is A */ /* rhs is B */ /* set is the context */ /* status is the usual accumulator */ /* */ /* C must have space for set->digits digits. */ /* */ /* ------------------------------------------------------------------ */ /* 'Classic' multiplication is used rather than Karatsuba, as the */ /* latter would give only a minor improvement for the short numbers */ /* expected to be handled most (and uses much more memory). */ /* */ /* There are two major paths here: the general-purpose ('old code') */ /* path which handles all DECDPUN values, and a fastpath version */ /* which is used if 64-bit ints are available, DECDPUN<=4, and more */ /* than two calls to decUnitAddSub would be made. */ /* */ /* The fastpath version lumps units together into 8-digit or 9-digit */ /* chunks, and also uses a lazy carry strategy to minimise expensive */ /* 64-bit divisions. The chunks are then broken apart again into */ /* units for continuing processing. Despite this overhead, the */ /* fastpath can speed up some 16-digit operations by 10x (and much */ /* more for higher-precision calculations). */ /* */ /* A buffer always has to be used for the accumulator; in the */ /* fastpath, buffers are also always needed for the chunked copies of */ /* of the operand coefficients. */ /* Static buffers are larger than needed just for multiply, to allow */ /* for calls from other operations (notably exp). */ /* ------------------------------------------------------------------ */ #define FASTMUL (DECUSE64 && DECDPUN<5) static decNumber * decMultiplyOp(decNumber *res, const decNumber *lhs, const decNumber *rhs, decContext *set, uInt *status) { Int accunits; // Units of accumulator in use Int exponent; // work Int residue=0; // rounding residue uByte bits; // result sign Unit *acc; // -> accumulator Unit array Int needbytes; // size calculator void *allocacc=NULL; // -> allocated accumulator, iff allocated Unit accbuff[SD2U(DECBUFFER*4+1)]; // buffer (+1 for DECBUFFER==0, // *4 for calls from other operations) const Unit *mer, *mermsup; // work Int madlength; // Units in multiplicand Int shift; // Units to shift multiplicand by #if FASTMUL // if DECDPUN is 1 or 3 work in base 10**9, otherwise // (DECDPUN is 2 or 4) then work in base 10**8 #if DECDPUN & 1 // odd #define FASTBASE 1000000000 // base #define FASTDIGS 9 // digits in base #define FASTLAZY 18 // carry resolution point [1->18] #else #define FASTBASE 100000000 #define FASTDIGS 8 #define FASTLAZY 1844 // carry resolution point [1->1844] #endif // three buffers are used, two for chunked copies of the operands // (base 10**8 or base 10**9) and one base 2**64 accumulator with // lazy carry evaluation uInt zlhibuff[(DECBUFFER*2+1)/8+1]; // buffer (+1 for DECBUFFER==0) uInt *zlhi=zlhibuff; // -> lhs array uInt *alloclhi=NULL; // -> allocated buffer, iff allocated uInt zrhibuff[(DECBUFFER*2+1)/8+1]; // buffer (+1 for DECBUFFER==0) uInt *zrhi=zrhibuff; // -> rhs array uInt *allocrhi=NULL; // -> allocated buffer, iff allocated uLong zaccbuff[(DECBUFFER*2+1)/4+2]; // buffer (+1 for DECBUFFER==0) // [allocacc is shared for both paths, as only one will run] uLong *zacc=zaccbuff; // -> accumulator array for exact result #if DECDPUN==1 Int zoff; // accumulator offset #endif uInt *lip, *rip; // item pointers uInt *lmsi, *rmsi; // most significant items Int ilhs, irhs, iacc; // item counts in the arrays Int lazy; // lazy carry counter uLong lcarry; // uLong carry uInt carry; // carry (NB not uLong) Int count; // work const Unit *cup; // .. Unit *up; // .. uLong *lp; // .. Int p; // .. #endif #if DECSUBSET decNumber *alloclhs=NULL; // -> allocated buffer, iff allocated decNumber *allocrhs=NULL; // -> allocated buffer, iff allocated #endif #if DECCHECK if (decCheckOperands(res, lhs, rhs, set)) return res; #endif // precalculate result sign bits=(uByte)((lhs->bits^rhs->bits)&DECNEG); // handle infinities and NaNs if (SPECIALARGS) { // a special bit set if (SPECIALARGS & (DECSNAN | DECNAN)) { // one or two NaNs decNaNs(res, lhs, rhs, set, status); return res;} // one or two infinities; Infinity * 0 is invalid if (((lhs->bits & DECINF)==0 && ISZERO(lhs)) ||((rhs->bits & DECINF)==0 && ISZERO(rhs))) { *status|=DEC_Invalid_operation; return res;} decNumberZero(res); res->bits=bits|DECINF; // infinity return res;} // For best speed, as in DMSRCN [the original Rexx numerics // module], use the shorter number as the multiplier (rhs) and // the longer as the multiplicand (lhs) to minimise the number of // adds (partial products) if (lhs->digitsdigits) { // swap... const decNumber *hold=lhs; lhs=rhs; rhs=hold; } do { // protect allocated storage #if DECSUBSET if (!set->extended) { // reduce operands and set lostDigits status, as needed if (lhs->digits>set->digits) { alloclhs=decRoundOperand(lhs, set, status); if (alloclhs==NULL) break; lhs=alloclhs; } if (rhs->digits>set->digits) { allocrhs=decRoundOperand(rhs, set, status); if (allocrhs==NULL) break; rhs=allocrhs; } } #endif // [following code does not require input rounding] #if FASTMUL // fastpath can be used // use the fast path if there are enough digits in the shorter // operand to make the setup and takedown worthwhile #define NEEDTWO (DECDPUN*2) // within two decUnitAddSub calls if (rhs->digits>NEEDTWO) { // use fastpath... // calculate the number of elements in each array ilhs=(lhs->digits+FASTDIGS-1)/FASTDIGS; // [ceiling] irhs=(rhs->digits+FASTDIGS-1)/FASTDIGS; // .. iacc=ilhs+irhs; // allocate buffers if required, as usual needbytes=ilhs*sizeof(uInt); if (needbytes>(Int)sizeof(zlhibuff)) { alloclhi=(uInt *)malloc(needbytes); zlhi=alloclhi;} needbytes=irhs*sizeof(uInt); if (needbytes>(Int)sizeof(zrhibuff)) { allocrhi=(uInt *)malloc(needbytes); zrhi=allocrhi;} // Allocating the accumulator space needs a special case when // DECDPUN=1 because when converting the accumulator to Units // after the multiplication each 8-byte item becomes 9 1-byte // units. Therefore iacc extra bytes are needed at the front // (rounded up to a multiple of 8 bytes), and the uLong // accumulator starts offset the appropriate number of units // to the right to avoid overwrite during the unchunking. needbytes=iacc*sizeof(uLong); #if DECDPUN==1 zoff=(iacc+7)/8; // items to offset by needbytes+=zoff*8; #endif if (needbytes>(Int)sizeof(zaccbuff)) { allocacc=(uLong *)malloc(needbytes); zacc=(uLong *)allocacc;} if (zlhi==NULL||zrhi==NULL||zacc==NULL) { *status|=DEC_Insufficient_storage; break;} acc=(Unit *)zacc; // -> target Unit array #if DECDPUN==1 zacc+=zoff; // start uLong accumulator to right #endif // assemble the chunked copies of the left and right sides for (count=lhs->digits, cup=lhs->lsu, lip=zlhi; count>0; lip++) for (p=0, *lip=0; p0; p+=DECDPUN, cup++, count-=DECDPUN) *lip+=*cup*powers[p]; lmsi=lip-1; // save -> msi for (count=rhs->digits, cup=rhs->lsu, rip=zrhi; count>0; rip++) for (p=0, *rip=0; p0; p+=DECDPUN, cup++, count-=DECDPUN) *rip+=*cup*powers[p]; rmsi=rip-1; // save -> msi // zero the accumulator for (lp=zacc; lp0 && rip!=rmsi) continue; lazy=FASTLAZY; // reset delay count // spin up the accumulator resolving overflows for (lp=zacc; lp assume buffer for accumulator needbytes=(D2U(lhs->digits)+D2U(rhs->digits))*sizeof(Unit); if (needbytes>(Int)sizeof(accbuff)) { allocacc=(Unit *)malloc(needbytes); if (allocacc==NULL) {*status|=DEC_Insufficient_storage; break;} acc=(Unit *)allocacc; // use the allocated space } /* Now the main long multiplication loop */ // Unlike the equivalent in the IBM Java implementation, there // is no advantage in calculating from msu to lsu. So, do it // by the book, as it were. // Each iteration calculates ACC=ACC+MULTAND*MULT accunits=1; // accumulator starts at '0' *acc=0; // .. (lsu=0) shift=0; // no multiplicand shift at first madlength=D2U(lhs->digits); // this won't change mermsup=rhs->lsu+D2U(rhs->digits); // -> msu+1 of multiplier for (mer=rhs->lsu; merlsu, madlength, 0, &acc[shift], *mer) + shift; else { // extend acc with a 0; it will be used shortly *(acc+accunits)=0; // [this avoids length of <=0 later] accunits++; } // multiply multiplicand by 10**DECDPUN for next Unit to left shift++; // add this for 'logical length' } // n #if FASTMUL } // unchunked units #endif // common end-path #if DECTRACE decDumpAr('*', acc, accunits); // Show exact result #endif // acc now contains the exact result of the multiplication, // possibly with a leading zero unit; build the decNumber from // it, noting if any residue res->bits=bits; // set sign res->digits=decGetDigits(acc, accunits); // count digits exactly // There can be a 31-bit wrap in calculating the exponent. // This can only happen if both input exponents are negative and // both their magnitudes are large. If there was a wrap, set a // safe very negative exponent, from which decFinalize() will // raise a hard underflow shortly. exponent=lhs->exponent+rhs->exponent; // calculate exponent if (lhs->exponent<0 && rhs->exponent<0 && exponent>0) exponent=-2*DECNUMMAXE; // force underflow res->exponent=exponent; // OK to overwrite now // Set the coefficient. If any rounding, residue records decSetCoeff(res, set, acc, res->digits, &residue, status); decFinish(res, set, &residue, status); // final cleanup } while(0); // end protected if (allocacc!=NULL) free(allocacc); // drop any storage used #if DECSUBSET if (allocrhs!=NULL) free(allocrhs); // .. if (alloclhs!=NULL) free(alloclhs); // .. #endif #if FASTMUL if (allocrhi!=NULL) free(allocrhi); // .. if (alloclhi!=NULL) free(alloclhi); // .. #endif return res; } // decMultiplyOp /* ------------------------------------------------------------------ */ /* decExpOp -- effect exponentiation */ /* */ /* This computes C = exp(A) */ /* */ /* res is C, the result. C may be A */ /* rhs is A */ /* set is the context; note that rounding mode has no effect */ /* */ /* C must have space for set->digits digits. status is updated but */ /* not set. */ /* */ /* Restrictions: */ /* */ /* digits, emax, and -emin in the context must be less than */ /* 2*DEC_MAX_MATH (1999998), and the rhs must be within these */ /* bounds or a zero. This is an internal routine, so these */ /* restrictions are contractual and not enforced. */ /* */ /* A finite result is rounded using DEC_ROUND_HALF_EVEN; it will */ /* almost always be correctly rounded, but may be up to 1 ulp in */ /* error in rare cases. */ /* */ /* Finite results will always be full precision and Inexact, except */ /* when A is a zero or -Infinity (giving 1 or 0 respectively). */ /* ------------------------------------------------------------------ */ /* This approach used here is similar to the algorithm described in */ /* */ /* Variable Precision Exponential Function, T. E. Hull and */ /* A. Abrham, ACM Transactions on Mathematical Software, Vol 12 #2, */ /* pp79-91, ACM, June 1986. */ /* */ /* with the main difference being that the iterations in the series */ /* evaluation are terminated dynamically (which does not require the */ /* extra variable-precision variables which are expensive in this */ /* context). */ /* */ /* The error analysis in Hull & Abrham's paper applies except for the */ /* round-off error accumulation during the series evaluation. This */ /* code does not precalculate the number of iterations and so cannot */ /* use Horner's scheme. Instead, the accumulation is done at double- */ /* precision, which ensures that the additions of the terms are exact */ /* and do not accumulate round-off (and any round-off errors in the */ /* terms themselves move 'to the right' faster than they can */ /* accumulate). This code also extends the calculation by allowing, */ /* in the spirit of other decNumber operators, the input to be more */ /* precise than the result (the precision used is based on the more */ /* precise of the input or requested result). */ /* */ /* Implementation notes: */ /* */ /* 1. This is separated out as decExpOp so it can be called from */ /* other Mathematical functions (notably Ln) with a wider range */ /* than normal. In particular, it can handle the slightly wider */ /* (double) range needed by Ln (which has to be able to calculate */ /* exp(-x) where x can be the tiniest number (Ntiny). */ /* */ /* 2. Normalizing x to be <=0.1 (instead of <=1) reduces loop */ /* iterations by approximately a third with additional (although */ /* diminishing) returns as the range is reduced to even smaller */ /* fractions. However, h (the power of 10 used to correct the */ /* result at the end, see below) must be kept <=8 as otherwise */ /* the final result cannot be computed. Hence the leverage is a */ /* sliding value (8-h), where potentially the range is reduced */ /* more for smaller values. */ /* */ /* The leverage that can be applied in this way is severely */ /* limited by the cost of the raise-to-the power at the end, */ /* which dominates when the number of iterations is small (less */ /* than ten) or when rhs is short. As an example, the adjustment */ /* x**10,000,000 needs 31 multiplications, all but one full-width. */ /* */ /* 3. The restrictions (especially precision) could be raised with */ /* care, but the full decNumber range seems very hard within the */ /* 32-bit limits. */ /* */ /* 4. The working precisions for the static buffers are twice the */ /* obvious size to allow for calls from decNumberPower. */ /* ------------------------------------------------------------------ */ decNumber * decExpOp(decNumber *res, const decNumber *rhs, decContext *set, uInt *status) { uInt ignore=0; // working status Int h; // adjusted exponent for 0.xxxx Int p; // working precision Int residue; // rounding residue uInt needbytes; // for space calculations const decNumber *x=rhs; // (may point to safe copy later) decContext aset, tset, dset; // working contexts Int comp; // work // the argument is often copied to normalize it, so (unusually) it // is treated like other buffers, using DECBUFFER, +1 in case // DECBUFFER is 0 decNumber bufr[D2N(DECBUFFER*2+1)]; decNumber *allocrhs=NULL; // non-NULL if rhs buffer allocated // the working precision will be no more than set->digits+8+1 // so for on-stack buffers DECBUFFER+9 is used, +1 in case DECBUFFER // is 0 (and twice that for the accumulator) // buffer for t, term (working precision plus) decNumber buft[D2N(DECBUFFER*2+9+1)]; decNumber *allocbuft=NULL; // -> allocated buft, iff allocated decNumber *t=buft; // term // buffer for a, accumulator (working precision * 2), at least 9 decNumber bufa[D2N(DECBUFFER*4+18+1)]; decNumber *allocbufa=NULL; // -> allocated bufa, iff allocated decNumber *a=bufa; // accumulator // decNumber for the divisor term; this needs at most 9 digits // and so can be fixed size [16 so can use standard context] decNumber bufd[D2N(16)]; decNumber *d=bufd; // divisor decNumber numone; // constant 1 #if DECCHECK Int iterations=0; // for later sanity check if (decCheckOperands(res, DECUNUSED, rhs, set)) return res; #endif do { // protect allocated storage if (SPECIALARG) { // handle infinities and NaNs if (decNumberIsInfinite(rhs)) { // an infinity if (decNumberIsNegative(rhs)) // -Infinity -> +0 decNumberZero(res); else decNumberCopy(res, rhs); // +Infinity -> self } else decNaNs(res, rhs, NULL, set, status); // a NaN break;} if (ISZERO(rhs)) { // zeros -> exact 1 decNumberZero(res); // make clean 1 *res->lsu=1; // .. break;} // [no status to set] // e**x when 0 < x < 0.66 is < 1+3x/2, hence can fast-path // positive and negative tiny cases which will result in inexact // 1. This also allows the later add-accumulate to always be // exact (because its length will never be more than twice the // working precision). // The comparator (tiny) needs just one digit, so use the // decNumber d for it (reused as the divisor, etc., below); its // exponent is such that if x is positive it will have // set->digits-1 zeros between the decimal point and the digit, // which is 4, and if x is negative one more zero there as the // more precise result will be of the form 0.9999999 rather than // 1.0000001. Hence, tiny will be 0.0000004 if digits=7 and x>0 // or 0.00000004 if digits=7 and x<0. If RHS not larger than // this then the result will be 1.000000 decNumberZero(d); // clean *d->lsu=4; // set 4 .. d->exponent=-set->digits; // * 10**(-d) if (decNumberIsNegative(rhs)) d->exponent--; // negative case comp=decCompare(d, rhs, 1); // signless compare if (comp==BADINT) { *status|=DEC_Insufficient_storage; break;} if (comp>=0) { // rhs < d Int shift=set->digits-1; decNumberZero(res); // set 1 *res->lsu=1; // .. res->digits=decShiftToMost(res->lsu, 1, shift); res->exponent=-shift; // make 1.0000... *status|=DEC_Inexact | DEC_Rounded; // .. inexactly break;} // tiny // set up the context to be used for calculating a, as this is // used on both paths below decContextDefault(&aset, DEC_INIT_DECIMAL64); // accumulator bounds are as requested (could underflow) aset.emax=set->emax; // usual bounds aset.emin=set->emin; // .. aset.clamp=0; // and no concrete format // calculate the adjusted (Hull & Abrham) exponent (where the // decimal point is just to the left of the coefficient msd) h=rhs->exponent+rhs->digits; // if h>8 then 10**h cannot be calculated safely; however, when // h=8 then exp(|rhs|) will be at least exp(1E+7) which is at // least 6.59E+4342944, so (due to the restriction on Emax/Emin) // overflow (or underflow to 0) is guaranteed -- so this case can // be handled by simply forcing the appropriate excess if (h>8) { // overflow/underflow // set up here so Power call below will over or underflow to // zero; set accumulator to either 2 or 0.02 // [stack buffer for a is always big enough for this] decNumberZero(a); *a->lsu=2; // not 1 but < exp(1) if (decNumberIsNegative(rhs)) a->exponent=-2; // make 0.02 h=8; // clamp so 10**h computable p=9; // set a working precision } else { // h<=8 Int maxlever=(rhs->digits>8?1:0); // [could/should increase this for precisions >40 or so, too] // if h is 8, cannot normalize to a lower upper limit because // the final result will not be computable (see notes above), // but leverage can be applied whenever h is less than 8. // Apply as much as possible, up to a MAXLEVER digits, which // sets the tradeoff against the cost of the later a**(10**h). // As h is increased, the working precision below also // increases to compensate for the "constant digits at the // front" effect. Int lever=MINI(8-h, maxlever); // leverage attainable Int use=-rhs->digits-lever; // exponent to use for RHS h+=lever; // apply leverage selected if (h<0) { // clamp use+=h; // [may end up subnormal] h=0; } // Take a copy of RHS if it needs normalization (true whenever x>=1) if (rhs->exponent!=use) { decNumber *newrhs=bufr; // assume will fit on stack needbytes=sizeof(decNumber)+(D2U(rhs->digits)-1)*sizeof(Unit); if (needbytes>sizeof(bufr)) { // need malloc space allocrhs=(decNumber *)malloc(needbytes); if (allocrhs==NULL) { // hopeless -- abandon *status|=DEC_Insufficient_storage; break;} newrhs=allocrhs; // use the allocated space } decNumberCopy(newrhs, rhs); // copy to safe space newrhs->exponent=use; // normalize; now <1 x=newrhs; // ready for use // decNumberShow(x); } // Now use the usual power series to evaluate exp(x). The // series starts as 1 + x + x^2/2 ... so prime ready for the // third term by setting the term variable t=x, the accumulator // a=1, and the divisor d=2. // First determine the working precision. From Hull & Abrham // this is set->digits+h+2. However, if x is 'over-precise' we // need to allow for all its digits to potentially participate // (consider an x where all the excess digits are 9s) so in // this case use x->digits+h+2 p=MAXI(x->digits, set->digits)+h+2; // [h<=8] // a and t are variable precision, and depend on p, so space // must be allocated for them if necessary // the accumulator needs to be able to hold 2p digits so that // the additions on the second and subsequent iterations are // sufficiently exact. needbytes=sizeof(decNumber)+(D2U(p*2)-1)*sizeof(Unit); if (needbytes>sizeof(bufa)) { // need malloc space allocbufa=(decNumber *)malloc(needbytes); if (allocbufa==NULL) { // hopeless -- abandon *status|=DEC_Insufficient_storage; break;} a=allocbufa; // use the allocated space } // the term needs to be able to hold p digits (which is // guaranteed to be larger than x->digits, so the initial copy // is safe); it may also be used for the raise-to-power // calculation below, which needs an extra two digits needbytes=sizeof(decNumber)+(D2U(p+2)-1)*sizeof(Unit); if (needbytes>sizeof(buft)) { // need malloc space allocbuft=(decNumber *)malloc(needbytes); if (allocbuft==NULL) { // hopeless -- abandon *status|=DEC_Insufficient_storage; break;} t=allocbuft; // use the allocated space } decNumberCopy(t, x); // term=x decNumberZero(a); *a->lsu=1; // accumulator=1 decNumberZero(d); *d->lsu=2; // divisor=2 decNumberZero(&numone); *numone.lsu=1; // constant 1 for increment // set up the contexts for calculating a, t, and d decContextDefault(&tset, DEC_INIT_DECIMAL64); dset=tset; // accumulator bounds are set above, set precision now aset.digits=p*2; // double // term bounds avoid any underflow or overflow tset.digits=p; tset.emin=DEC_MIN_EMIN; // [emax is plenty] // [dset.digits=16, etc., are sufficient] // finally ready to roll for (;;) { #if DECCHECK iterations++; #endif // only the status from the accumulation is interesting // [but it should remain unchanged after first add] decAddOp(a, a, t, &aset, 0, status); // a=a+t decMultiplyOp(t, t, x, &tset, &ignore); // t=t*x decDivideOp(t, t, d, &tset, DIVIDE, &ignore); // t=t/d // the iteration ends when the term cannot affect the result, // if rounded to p digits, which is when its value is smaller // than the accumulator by p+1 digits. There must also be // full precision in a. if (((a->digits+a->exponent)>=(t->digits+t->exponent+p+1)) && (a->digits>=p)) break; decAddOp(d, d, &numone, &dset, 0, &ignore); // d=d+1 } // iterate #if DECCHECK // just a sanity check; comment out test to show always if (iterations>p+3) printf("Exp iterations=%ld, status=%08lx, p=%ld, d=%ld\n", (LI)iterations, (LI)*status, (LI)p, (LI)x->digits); #endif } // h<=8 // apply postconditioning: a=a**(10**h) -- this is calculated // at a slightly higher precision than Hull & Abrham suggest if (h>0) { Int seenbit=0; // set once a 1-bit is seen Int i; // counter Int n=powers[h]; // always positive aset.digits=p+2; // sufficient precision // avoid the overhead and many extra digits of decNumberPower // as all that is needed is the short 'multipliers' loop; here // accumulate the answer into t decNumberZero(t); *t->lsu=1; // acc=1 for (i=1;;i++){ // for each bit [top bit ignored] // abandon if have had overflow or terminal underflow if (*status & (DEC_Overflow|DEC_Underflow)) { // interesting? if (*status&DEC_Overflow || ISZERO(t)) break;} n=n<<1; // move next bit to testable position if (n<0) { // top bit is set seenbit=1; // OK, have a significant bit decMultiplyOp(t, t, a, &aset, status); // acc=acc*x } if (i==31) break; // that was the last bit if (!seenbit) continue; // no need to square 1 decMultiplyOp(t, t, t, &aset, status); // acc=acc*acc [square] } /*i*/ // 32 bits // decNumberShow(t); a=t; // and carry on using t instead of a } // Copy and round the result to res residue=1; // indicate dirt to right .. if (ISZERO(a)) residue=0; // .. unless underflowed to 0 aset.digits=set->digits; // [use default rounding] decCopyFit(res, a, &aset, &residue, status); // copy & shorten decFinish(res, set, &residue, status); // cleanup/set flags } while(0); // end protected if (allocrhs !=NULL) free(allocrhs); // drop any storage used if (allocbufa!=NULL) free(allocbufa); // .. if (allocbuft!=NULL) free(allocbuft); // .. // [status is handled by caller] return res; } // decExpOp /* ------------------------------------------------------------------ */ /* Initial-estimate natural logarithm table */ /* */ /* LNnn -- 90-entry 16-bit table for values from .10 through .99. */ /* The result is a 4-digit encode of the coefficient (c=the */ /* top 14 bits encoding 0-9999) and a 2-digit encode of the */ /* exponent (e=the bottom 2 bits encoding 0-3) */ /* */ /* The resulting value is given by: */ /* */ /* v = -c * 10**(-e-3) */ /* */ /* where e and c are extracted from entry k = LNnn[x-10] */ /* where x is truncated (NB) into the range 10 through 99, */ /* and then c = k>>2 and e = k&3. */ /* ------------------------------------------------------------------ */ const uShort LNnn[90]={9016, 8652, 8316, 8008, 7724, 7456, 7208, 6972, 6748, 6540, 6340, 6148, 5968, 5792, 5628, 5464, 5312, 5164, 5020, 4884, 4748, 4620, 4496, 4376, 4256, 4144, 4032, 39233, 38181, 37157, 36157, 35181, 34229, 33297, 32389, 31501, 30629, 29777, 28945, 28129, 27329, 26545, 25777, 25021, 24281, 23553, 22837, 22137, 21445, 20769, 20101, 19445, 18801, 18165, 17541, 16925, 16321, 15721, 15133, 14553, 13985, 13421, 12865, 12317, 11777, 11241, 10717, 10197, 9685, 9177, 8677, 8185, 7697, 7213, 6737, 6269, 5801, 5341, 4889, 4437, 39930, 35534, 31186, 26886, 22630, 18418, 14254, 10130, 6046, 20055}; /* ------------------------------------------------------------------ */ /* decLnOp -- effect natural logarithm */ /* */ /* This computes C = ln(A) */ /* */ /* res is C, the result. C may be A */ /* rhs is A */ /* set is the context; note that rounding mode has no effect */ /* */ /* C must have space for set->digits digits. */ /* */ /* Notable cases: */ /* A<0 -> Invalid */ /* A=0 -> -Infinity (Exact) */ /* A=+Infinity -> +Infinity (Exact) */ /* A=1 exactly -> 0 (Exact) */ /* */ /* Restrictions (as for Exp): */ /* */ /* digits, emax, and -emin in the context must be less than */ /* DEC_MAX_MATH+11 (1000010), and the rhs must be within these */ /* bounds or a zero. This is an internal routine, so these */ /* restrictions are contractual and not enforced. */ /* */ /* A finite result is rounded using DEC_ROUND_HALF_EVEN; it will */ /* almost always be correctly rounded, but may be up to 1 ulp in */ /* error in rare cases. */ /* ------------------------------------------------------------------ */ /* The result is calculated using Newton's method, with each */ /* iteration calculating a' = a + x * exp(-a) - 1. See, for example, */ /* Epperson 1989. */ /* */ /* The iteration ends when the adjustment x*exp(-a)-1 is tiny enough. */ /* This has to be calculated at the sum of the precision of x and the */ /* working precision. */ /* */ /* Implementation notes: */ /* */ /* 1. This is separated out as decLnOp so it can be called from */ /* other Mathematical functions (e.g., Log 10) with a wider range */ /* than normal. In particular, it can handle the slightly wider */ /* (+9+2) range needed by a power function. */ /* */ /* 2. The speed of this function is about 10x slower than exp, as */ /* it typically needs 4-6 iterations for short numbers, and the */ /* extra precision needed adds a squaring effect, twice. */ /* */ /* 3. Fastpaths are included for ln(10) and ln(2), up to length 40, */ /* as these are common requests. ln(10) is used by log10(x). */ /* */ /* 4. An iteration might be saved by widening the LNnn table, and */ /* would certainly save at least one if it were made ten times */ /* bigger, too (for truncated fractions 0.100 through 0.999). */ /* However, for most practical evaluations, at least four or five */ /* iterations will be neede -- so this would only speed up by */ /* 20-25% and that probably does not justify increasing the table */ /* size. */ /* */ /* 5. The static buffers are larger than might be expected to allow */ /* for calls from decNumberPower. */ /* ------------------------------------------------------------------ */ decNumber * decLnOp(decNumber *res, const decNumber *rhs, decContext *set, uInt *status) { uInt ignore=0; // working status accumulator uInt needbytes; // for space calculations Int residue; // rounding residue Int r; // rhs=f*10**r [see below] Int p; // working precision Int pp; // precision for iteration Int t; // work // buffers for a (accumulator, typically precision+2) and b // (adjustment calculator, same size) decNumber bufa[D2N(DECBUFFER+12)]; decNumber *allocbufa=NULL; // -> allocated bufa, iff allocated decNumber *a=bufa; // accumulator/work decNumber bufb[D2N(DECBUFFER*2+2)]; decNumber *allocbufb=NULL; // -> allocated bufa, iff allocated decNumber *b=bufb; // adjustment/work decNumber numone; // constant 1 decNumber cmp; // work decContext aset, bset; // working contexts #if DECCHECK Int iterations=0; // for later sanity check if (decCheckOperands(res, DECUNUSED, rhs, set)) return res; #endif do { // protect allocated storage if (SPECIALARG) { // handle infinities and NaNs if (decNumberIsInfinite(rhs)) { // an infinity if (decNumberIsNegative(rhs)) // -Infinity -> error *status|=DEC_Invalid_operation; else decNumberCopy(res, rhs); // +Infinity -> self } else decNaNs(res, rhs, NULL, set, status); // a NaN break;} if (ISZERO(rhs)) { // +/- zeros -> -Infinity decNumberZero(res); // make clean res->bits=DECINF|DECNEG; // set - infinity break;} // [no status to set] // Non-zero negatives are bad... if (decNumberIsNegative(rhs)) { // -x -> error *status|=DEC_Invalid_operation; break;} // Here, rhs is positive, finite, and in range // lookaside fastpath code for ln(2) and ln(10) at common lengths if (rhs->exponent==0 && set->digits<=40) { #if DECDPUN==1 if (rhs->lsu[0]==0 && rhs->lsu[1]==1 && rhs->digits==2) { // ln(10) #else if (rhs->lsu[0]==10 && rhs->digits==2) { // ln(10) #endif aset=*set; aset.round=DEC_ROUND_HALF_EVEN; #define LN10 "2.302585092994045684017991454684364207601" decNumberFromString(res, LN10, &aset); *status|=(DEC_Inexact | DEC_Rounded); // is inexact break;} if (rhs->lsu[0]==2 && rhs->digits==1) { // ln(2) aset=*set; aset.round=DEC_ROUND_HALF_EVEN; #define LN2 "0.6931471805599453094172321214581765680755" decNumberFromString(res, LN2, &aset); *status|=(DEC_Inexact | DEC_Rounded); break;} } // integer and short // Determine the working precision. This is normally the // requested precision + 2, with a minimum of 9. However, if // the rhs is 'over-precise' then allow for all its digits to // potentially participate (consider an rhs where all the excess // digits are 9s) so in this case use rhs->digits+2. p=MAXI(rhs->digits, MAXI(set->digits, 7))+2; // Allocate space for the accumulator and the high-precision // adjustment calculator, if necessary. The accumulator must // be able to hold p digits, and the adjustment up to // rhs->digits+p digits. They are also made big enough for 16 // digits so that they can be used for calculating the initial // estimate. needbytes=sizeof(decNumber)+(D2U(MAXI(p,16))-1)*sizeof(Unit); if (needbytes>sizeof(bufa)) { // need malloc space allocbufa=(decNumber *)malloc(needbytes); if (allocbufa==NULL) { // hopeless -- abandon *status|=DEC_Insufficient_storage; break;} a=allocbufa; // use the allocated space } pp=p+rhs->digits; needbytes=sizeof(decNumber)+(D2U(MAXI(pp,16))-1)*sizeof(Unit); if (needbytes>sizeof(bufb)) { // need malloc space allocbufb=(decNumber *)malloc(needbytes); if (allocbufb==NULL) { // hopeless -- abandon *status|=DEC_Insufficient_storage; break;} b=allocbufb; // use the allocated space } // Prepare an initial estimate in acc. Calculate this by // considering the coefficient of x to be a normalized fraction, // f, with the decimal point at far left and multiplied by // 10**r. Then, rhs=f*10**r and 0.1<=f<1, and // ln(x) = ln(f) + ln(10)*r // Get the initial estimate for ln(f) from a small lookup // table (see above) indexed by the first two digits of f, // truncated. decContextDefault(&aset, DEC_INIT_DECIMAL64); // 16-digit extended r=rhs->exponent+rhs->digits; // 'normalised' exponent decNumberFromInt32(a, r); // a=r decNumberFromInt32(b, 2302585); // b=ln(10) (2.302585) b->exponent=-6; // .. decMultiplyOp(a, a, b, &aset, &ignore); // a=a*b // now get top two digits of rhs into b by simple truncate and // force to integer residue=0; // (no residue) aset.digits=2; aset.round=DEC_ROUND_DOWN; decCopyFit(b, rhs, &aset, &residue, &ignore); // copy & shorten b->exponent=0; // make integer t=decGetInt(b); // [cannot fail] if (t<10) t=X10(t); // adjust single-digit b t=LNnn[t-10]; // look up ln(b) decNumberFromInt32(b, t>>2); // b=ln(b) coefficient b->exponent=-(t&3)-3; // set exponent b->bits=DECNEG; // ln(0.10)->ln(0.99) always -ve aset.digits=16; aset.round=DEC_ROUND_HALF_EVEN; // restore decAddOp(a, a, b, &aset, 0, &ignore); // acc=a+b // the initial estimate is now in a, with up to 4 digits correct. // When rhs is at or near Nmax the estimate will be low, so we // will approach it from below, avoiding overflow when calling exp. decNumberZero(&numone); *numone.lsu=1; // constant 1 for adjustment // accumulator bounds are as requested (could underflow, but // cannot overflow) aset.emax=set->emax; aset.emin=set->emin; aset.clamp=0; // no concrete format // set up a context to be used for the multiply and subtract bset=aset; bset.emax=DEC_MAX_MATH*2; // use double bounds for the bset.emin=-DEC_MAX_MATH*2; // adjustment calculation // [see decExpOp call below] // for each iteration double the number of digits to calculate, // up to a maximum of p pp=9; // initial precision // [initially 9 as then the sequence starts 7+2, 16+2, and // 34+2, which is ideal for standard-sized numbers] aset.digits=pp; // working context bset.digits=pp+rhs->digits; // wider context for (;;) { // iterate #if DECCHECK iterations++; if (iterations>24) break; // consider 9 * 2**24 #endif // calculate the adjustment (exp(-a)*x-1) into b. This is a // catastrophic subtraction but it really is the difference // from 1 that is of interest. // Use the internal entry point to Exp as it allows the double // range for calculating exp(-a) when a is the tiniest subnormal. a->bits^=DECNEG; // make -a decExpOp(b, a, &bset, &ignore); // b=exp(-a) a->bits^=DECNEG; // restore sign of a // now multiply by rhs and subtract 1, at the wider precision decMultiplyOp(b, b, rhs, &bset, &ignore); // b=b*rhs decAddOp(b, b, &numone, &bset, DECNEG, &ignore); // b=b-1 // the iteration ends when the adjustment cannot affect the // result by >=0.5 ulp (at the requested digits), which // is when its value is smaller than the accumulator by // set->digits+1 digits (or it is zero) -- this is a looser // requirement than for Exp because all that happens to the // accumulator after this is the final rounding (but note that // there must also be full precision in a, or a=0). if (decNumberIsZero(b) || (a->digits+a->exponent)>=(b->digits+b->exponent+set->digits+1)) { if (a->digits==p) break; if (decNumberIsZero(a)) { decCompareOp(&cmp, rhs, &numone, &aset, COMPARE, &ignore); // rhs=1 ? if (cmp.lsu[0]==0) a->exponent=0; // yes, exact 0 else *status|=(DEC_Inexact | DEC_Rounded); // no, inexact break; } // force padding if adjustment has gone to 0 before full length if (decNumberIsZero(b)) b->exponent=a->exponent-p; } // not done yet ... decAddOp(a, a, b, &aset, 0, &ignore); // a=a+b for next estimate if (pp==p) continue; // precision is at maximum // lengthen the next calculation pp=pp*2; // double precision if (pp>p) pp=p; // clamp to maximum aset.digits=pp; // working context bset.digits=pp+rhs->digits; // wider context } // Newton's iteration #if DECCHECK // just a sanity check; remove the test to show always if (iterations>24) printf("Ln iterations=%ld, status=%08lx, p=%ld, d=%ld\n", (LI)iterations, (LI)*status, (LI)p, (LI)rhs->digits); #endif // Copy and round the result to res residue=1; // indicate dirt to right if (ISZERO(a)) residue=0; // .. unless underflowed to 0 aset.digits=set->digits; // [use default rounding] decCopyFit(res, a, &aset, &residue, status); // copy & shorten decFinish(res, set, &residue, status); // cleanup/set flags } while(0); // end protected if (allocbufa!=NULL) free(allocbufa); // drop any storage used if (allocbufb!=NULL) free(allocbufb); // .. // [status is handled by caller] return res; } // decLnOp /* ------------------------------------------------------------------ */ /* decQuantizeOp -- force exponent to requested value */ /* */ /* This computes C = op(A, B), where op adjusts the coefficient */ /* of C (by rounding or shifting) such that the exponent (-scale) */ /* of C has the value B or matches the exponent of B. */ /* The numerical value of C will equal A, except for the effects of */ /* any rounding that occurred. */ /* */ /* res is C, the result. C may be A or B */ /* lhs is A, the number to adjust */ /* rhs is B, the requested exponent */ /* set is the context */ /* quant is 1 for quantize or 0 for rescale */ /* status is the status accumulator (this can be called without */ /* risk of control loss) */ /* */ /* C must have space for set->digits digits. */ /* */ /* Unless there is an error or the result is infinite, the exponent */ /* after the operation is guaranteed to be that requested. */ /* ------------------------------------------------------------------ */ static decNumber * decQuantizeOp(decNumber *res, const decNumber *lhs, const decNumber *rhs, decContext *set, Flag quant, uInt *status) { #if DECSUBSET decNumber *alloclhs=NULL; // non-NULL if rounded lhs allocated decNumber *allocrhs=NULL; // .., rhs #endif const decNumber *inrhs=rhs; // save original rhs Int reqdigits=set->digits; // requested DIGITS Int reqexp; // requested exponent [-scale] Int residue=0; // rounding residue Int etiny=set->emin-(reqdigits-1); #if DECCHECK if (decCheckOperands(res, lhs, rhs, set)) return res; #endif do { // protect allocated storage #if DECSUBSET if (!set->extended) { // reduce operands and set lostDigits status, as needed if (lhs->digits>reqdigits) { alloclhs=decRoundOperand(lhs, set, status); if (alloclhs==NULL) break; lhs=alloclhs; } if (rhs->digits>reqdigits) { // [this only checks lostDigits] allocrhs=decRoundOperand(rhs, set, status); if (allocrhs==NULL) break; rhs=allocrhs; } } #endif // [following code does not require input rounding] // Handle special values if (SPECIALARGS) { // NaNs get usual processing if (SPECIALARGS & (DECSNAN | DECNAN)) decNaNs(res, lhs, rhs, set, status); // one infinity but not both is bad else if ((lhs->bits ^ rhs->bits) & DECINF) *status|=DEC_Invalid_operation; // both infinity: return lhs else decNumberCopy(res, lhs); // [nop if in place] break; } // set requested exponent if (quant) reqexp=inrhs->exponent; // quantize -- match exponents else { // rescale -- use value of rhs // Original rhs must be an integer that fits and is in range, // which could be from -1999999997 to +999999999, thanks to // subnormals reqexp=decGetInt(inrhs); // [cannot fail] } #if DECSUBSET if (!set->extended) etiny=set->emin; // no subnormals #endif if (reqexp==BADINT // bad (rescale only) or .. || reqexp==BIGODD || reqexp==BIGEVEN // very big (ditto) or .. || (reqexpset->emax)) { // > emax *status|=DEC_Invalid_operation; break;} // the RHS has been processed, so it can be overwritten now if necessary if (ISZERO(lhs)) { // zero coefficient unchanged decNumberCopy(res, lhs); // [nop if in place] res->exponent=reqexp; // .. just set exponent #if DECSUBSET if (!set->extended) res->bits=0; // subset specification; no -0 #endif } else { // non-zero lhs Int adjust=reqexp-lhs->exponent; // digit adjustment needed // if adjusted coefficient will definitely not fit, give up now if ((lhs->digits-adjust)>reqdigits) { *status|=DEC_Invalid_operation; break; } if (adjust>0) { // increasing exponent // this will decrease the length of the coefficient by adjust // digits, and must round as it does so decContext workset; // work workset=*set; // clone rounding, etc. workset.digits=lhs->digits-adjust; // set requested length // [note that the latter can be <1, here] decCopyFit(res, lhs, &workset, &residue, status); // fit to result decApplyRound(res, &workset, residue, status); // .. and round residue=0; // [used] // If just rounded a 999s case, exponent will be off by one; // adjust back (after checking space), if so. if (res->exponent>reqexp) { // re-check needed, e.g., for quantize(0.9999, 0.001) under // set->digits==3 if (res->digits==reqdigits) { // cannot shift by 1 *status&=~(DEC_Inexact | DEC_Rounded); // [clean these] *status|=DEC_Invalid_operation; break; } res->digits=decShiftToMost(res->lsu, res->digits, 1); // shift res->exponent--; // (re)adjust the exponent. } #if DECSUBSET if (ISZERO(res) && !set->extended) res->bits=0; // subset; no -0 #endif } // increase else /* adjust<=0 */ { // decreasing or = exponent // this will increase the length of the coefficient by -adjust // digits, by adding zero or more trailing zeros; this is // already checked for fit, above decNumberCopy(res, lhs); // [it will fit] // if padding needed (adjust<0), add it now... if (adjust<0) { res->digits=decShiftToMost(res->lsu, res->digits, -adjust); res->exponent+=adjust; // adjust the exponent } } // decrease } // non-zero // Check for overflow [do not use Finalize in this case, as an // overflow here is a "don't fit" situation] if (res->exponent>set->emax-res->digits+1) { // too big *status|=DEC_Invalid_operation; break; } else { decFinalize(res, set, &residue, status); // set subnormal flags *status&=~DEC_Underflow; // suppress Underflow [as per 754] } } while(0); // end protected #if DECSUBSET if (allocrhs!=NULL) free(allocrhs); // drop any storage used if (alloclhs!=NULL) free(alloclhs); // .. #endif return res; } // decQuantizeOp /* ------------------------------------------------------------------ */ /* decCompareOp -- compare, min, or max two Numbers */ /* */ /* This computes C = A ? B and carries out one of four operations: */ /* COMPARE -- returns the signum (as a number) giving the */ /* result of a comparison unless one or both */ /* operands is a NaN (in which case a NaN results) */ /* COMPSIG -- as COMPARE except that a quiet NaN raises */ /* Invalid operation. */ /* COMPMAX -- returns the larger of the operands, using the */ /* 754 maxnum operation */ /* COMPMAXMAG -- ditto, comparing absolute values */ /* COMPMIN -- the 754 minnum operation */ /* COMPMINMAG -- ditto, comparing absolute values */ /* COMTOTAL -- returns the signum (as a number) giving the */ /* result of a comparison using 754 total ordering */ /* */ /* res is C, the result. C may be A and/or B (e.g., X=X?X) */ /* lhs is A */ /* rhs is B */ /* set is the context */ /* op is the operation flag */ /* status is the usual accumulator */ /* */ /* C must have space for one digit for COMPARE or set->digits for */ /* COMPMAX, COMPMIN, COMPMAXMAG, or COMPMINMAG. */ /* ------------------------------------------------------------------ */ /* The emphasis here is on speed for common cases, and avoiding */ /* coefficient comparison if possible. */ /* ------------------------------------------------------------------ */ decNumber * decCompareOp(decNumber *res, const decNumber *lhs, const decNumber *rhs, decContext *set, Flag op, uInt *status) { #if DECSUBSET decNumber *alloclhs=NULL; // non-NULL if rounded lhs allocated decNumber *allocrhs=NULL; // .., rhs #endif Int result=0; // default result value uByte merged; // work #if DECCHECK if (decCheckOperands(res, lhs, rhs, set)) return res; #endif do { // protect allocated storage #if DECSUBSET if (!set->extended) { // reduce operands and set lostDigits status, as needed if (lhs->digits>set->digits) { alloclhs=decRoundOperand(lhs, set, status); if (alloclhs==NULL) {result=BADINT; break;} lhs=alloclhs; } if (rhs->digits>set->digits) { allocrhs=decRoundOperand(rhs, set, status); if (allocrhs==NULL) {result=BADINT; break;} rhs=allocrhs; } } #endif // [following code does not require input rounding] // If total ordering then handle differing signs 'up front' if (op==COMPTOTAL) { // total ordering if (decNumberIsNegative(lhs) & !decNumberIsNegative(rhs)) { result=-1; break; } if (!decNumberIsNegative(lhs) & decNumberIsNegative(rhs)) { result=+1; break; } } // handle NaNs specially; let infinities drop through // This assumes sNaN (even just one) leads to NaN. merged=(lhs->bits | rhs->bits) & (DECSNAN | DECNAN); if (merged) { // a NaN bit set if (op==COMPARE); // result will be NaN else if (op==COMPSIG) // treat qNaN as sNaN *status|=DEC_Invalid_operation | DEC_sNaN; else if (op==COMPTOTAL) { // total ordering, always finite // signs are known to be the same; compute the ordering here // as if the signs are both positive, then invert for negatives if (!decNumberIsNaN(lhs)) result=-1; else if (!decNumberIsNaN(rhs)) result=+1; // here if both NaNs else if (decNumberIsSNaN(lhs) && decNumberIsQNaN(rhs)) result=-1; else if (decNumberIsQNaN(lhs) && decNumberIsSNaN(rhs)) result=+1; else { // both NaN or both sNaN // now it just depends on the payload result=decUnitCompare(lhs->lsu, D2U(lhs->digits), rhs->lsu, D2U(rhs->digits), 0); // [Error not possible, as these are 'aligned'] } // both same NaNs if (decNumberIsNegative(lhs)) result=-result; break; } // total order else if (merged & DECSNAN); // sNaN -> qNaN else { // here if MIN or MAX and one or two quiet NaNs // min or max -- 754 rules ignore single NaN if (!decNumberIsNaN(lhs) || !decNumberIsNaN(rhs)) { // just one NaN; force choice to be the non-NaN operand op=COMPMAX; if (lhs->bits & DECNAN) result=-1; // pick rhs else result=+1; // pick lhs break; } } // max or min op=COMPNAN; // use special path decNaNs(res, lhs, rhs, set, status); // propagate NaN break; } // have numbers if (op==COMPMAXMAG || op==COMPMINMAG) result=decCompare(lhs, rhs, 1); else result=decCompare(lhs, rhs, 0); // sign matters } while(0); // end protected if (result==BADINT) *status|=DEC_Insufficient_storage; // rare else { if (op==COMPARE || op==COMPSIG ||op==COMPTOTAL) { // returning signum if (op==COMPTOTAL && result==0) { // operands are numerically equal or same NaN (and same sign, // tested first); if identical, leave result 0 if (lhs->exponent!=rhs->exponent) { if (lhs->exponentexponent) result=-1; else result=+1; if (decNumberIsNegative(lhs)) result=-result; } // lexp!=rexp } // total-order by exponent decNumberZero(res); // [always a valid result] if (result!=0) { // must be -1 or +1 *res->lsu=1; if (result<0) res->bits=DECNEG; } } else if (op==COMPNAN); // special, drop through else { // MAX or MIN, non-NaN result Int residue=0; // rounding accumulator // choose the operand for the result const decNumber *choice; if (result==0) { // operands are numerically equal // choose according to sign then exponent (see 754) uByte slhs=(lhs->bits & DECNEG); uByte srhs=(rhs->bits & DECNEG); #if DECSUBSET if (!set->extended) { // subset: force left-hand op=COMPMAX; result=+1; } else #endif if (slhs!=srhs) { // signs differ if (slhs) result=-1; // rhs is max else result=+1; // lhs is max } else if (slhs && srhs) { // both negative if (lhs->exponentexponent) result=+1; else result=-1; // [if equal, use lhs, technically identical] } else { // both positive if (lhs->exponent>rhs->exponent) result=+1; else result=-1; // [ditto] } } // numerically equal // here result will be non-0; reverse if looking for MIN if (op==COMPMIN || op==COMPMINMAG) result=-result; choice=(result>0 ? lhs : rhs); // choose // copy chosen to result, rounding if need be decCopyFit(res, choice, set, &residue, status); decFinish(res, set, &residue, status); } } #if DECSUBSET if (allocrhs!=NULL) free(allocrhs); // free any storage used if (alloclhs!=NULL) free(alloclhs); // .. #endif return res; } // decCompareOp /* ------------------------------------------------------------------ */ /* decCompare -- compare two decNumbers by numerical value */ /* */ /* This routine compares A ? B without altering them. */ /* */ /* Arg1 is A, a decNumber which is not a NaN */ /* Arg2 is B, a decNumber which is not a NaN */ /* Arg3 is 1 for a sign-independent compare, 0 otherwise */ /* */ /* returns -1, 0, or 1 for AB, or BADINT if failure */ /* (the only possible failure is an allocation error) */ /* ------------------------------------------------------------------ */ static Int decCompare(const decNumber *lhs, const decNumber *rhs, Flag abs) { Int result; // result value Int sigr; // rhs signum Int compare; // work result=1; // assume signum(lhs) if (ISZERO(lhs)) result=0; if (abs) { if (ISZERO(rhs)) return result; // LHS wins or both 0 // RHS is non-zero if (result==0) return -1; // LHS is 0; RHS wins // [here, both non-zero, result=1] } else { // signs matter if (result && decNumberIsNegative(lhs)) result=-1; sigr=1; // compute signum(rhs) if (ISZERO(rhs)) sigr=0; else if (decNumberIsNegative(rhs)) sigr=-1; if (result > sigr) return +1; // L > R, return 1 if (result < sigr) return -1; // L < R, return -1 if (result==0) return 0; // both 0 } // signums are the same; both are non-zero if ((lhs->bits | rhs->bits) & DECINF) { // one or more infinities if (decNumberIsInfinite(rhs)) { if (decNumberIsInfinite(lhs)) result=0;// both infinite else result=-result; // only rhs infinite } return result; } // must compare the coefficients, allowing for exponents if (lhs->exponent>rhs->exponent) { // LHS exponent larger // swap sides, and sign const decNumber *temp=lhs; lhs=rhs; rhs=temp; result=-result; } compare=decUnitCompare(lhs->lsu, D2U(lhs->digits), rhs->lsu, D2U(rhs->digits), rhs->exponent-lhs->exponent); if (compare!=BADINT) compare*=result; // comparison succeeded return compare; } // decCompare /* ------------------------------------------------------------------ */ /* decUnitCompare -- compare two >=0 integers in Unit arrays */ /* */ /* This routine compares A ? B*10**E where A and B are unit arrays */ /* A is a plain integer */ /* B has an exponent of E (which must be non-negative) */ /* */ /* Arg1 is A first Unit (lsu) */ /* Arg2 is A length in Units */ /* Arg3 is B first Unit (lsu) */ /* Arg4 is B length in Units */ /* Arg5 is E (0 if the units are aligned) */ /* */ /* returns -1, 0, or 1 for AB, or BADINT if failure */ /* (the only possible failure is an allocation error, which can */ /* only occur if E!=0) */ /* ------------------------------------------------------------------ */ static Int decUnitCompare(const Unit *a, Int alength, const Unit *b, Int blength, Int exp) { Unit *acc; // accumulator for result Unit accbuff[SD2U(DECBUFFER*2+1)]; // local buffer Unit *allocacc=NULL; // -> allocated acc buffer, iff allocated Int accunits, need; // units in use or needed for acc const Unit *l, *r, *u; // work Int expunits, exprem, result; // .. if (exp==0) { // aligned; fastpath if (alength>blength) return 1; if (alength=a; l--, r--) { if (*l>*r) return 1; if (*l<*r) return -1; } return 0; // all units match } // aligned // Unaligned. If one is >1 unit longer than the other, padded // approximately, then can return easily if (alength>blength+(Int)D2U(exp)) return 1; if (alength+1sizeof(accbuff)) { allocacc=(Unit *)malloc(need*sizeof(Unit)); if (allocacc==NULL) return BADINT; // hopeless -- abandon acc=allocacc; } // Calculate units and remainder from exponent. expunits=exp/DECDPUN; exprem=exp%DECDPUN; // subtract [A+B*(-m)] accunits=decUnitAddSub(a, alength, b, blength, expunits, acc, -(Int)powers[exprem]); // [UnitAddSub result may have leading zeros, even on zero] if (accunits<0) result=-1; // negative result else { // non-negative result // check units of the result before freeing any storage for (u=acc; u=0 integers in Unit arrays */ /* */ /* This routine performs the calculation: */ /* */ /* C=A+(B*M) */ /* */ /* Where M is in the range -DECDPUNMAX through +DECDPUNMAX. */ /* */ /* A may be shorter or longer than B. */ /* */ /* Leading zeros are not removed after a calculation. The result is */ /* either the same length as the longer of A and B (adding any */ /* shift), or one Unit longer than that (if a Unit carry occurred). */ /* */ /* A and B content are not altered unless C is also A or B. */ /* C may be the same array as A or B, but only if no zero padding is */ /* requested (that is, C may be B only if bshift==0). */ /* C is filled from the lsu; only those units necessary to complete */ /* the calculation are referenced. */ /* */ /* Arg1 is A first Unit (lsu) */ /* Arg2 is A length in Units */ /* Arg3 is B first Unit (lsu) */ /* Arg4 is B length in Units */ /* Arg5 is B shift in Units (>=0; pads with 0 units if positive) */ /* Arg6 is C first Unit (lsu) */ /* Arg7 is M, the multiplier */ /* */ /* returns the count of Units written to C, which will be non-zero */ /* and negated if the result is negative. That is, the sign of the */ /* returned Int is the sign of the result (positive for zero) and */ /* the absolute value of the Int is the count of Units. */ /* */ /* It is the caller's responsibility to make sure that C size is */ /* safe, allowing space if necessary for a one-Unit carry. */ /* */ /* This routine is severely performance-critical; *any* change here */ /* must be measured (timed) to assure no performance degradation. */ /* In particular, trickery here tends to be counter-productive, as */ /* increased complexity of code hurts register optimizations on */ /* register-poor architectures. Avoiding divisions is nearly */ /* always a Good Idea, however. */ /* */ /* Special thanks to Rick McGuire (IBM Cambridge, MA) and Dave Clark */ /* (IBM Warwick, UK) for some of the ideas used in this routine. */ /* ------------------------------------------------------------------ */ static Int decUnitAddSub(const Unit *a, Int alength, const Unit *b, Int blength, Int bshift, Unit *c, Int m) { const Unit *alsu=a; // A lsu [need to remember it] Unit *clsu=c; // C ditto Unit *minC; // low water mark for C Unit *maxC; // high water mark for C eInt carry=0; // carry integer (could be Long) Int add; // work #if DECDPUN<=4 // myriadal, millenary, etc. Int est; // estimated quotient #endif #if DECTRACE if (alength<1 || blength<1) printf("decUnitAddSub: alen blen m %ld %ld [%ld]\n", alength, blength, m); #endif maxC=c+alength; // A is usually the longer minC=c+blength; // .. and B the shorter if (bshift!=0) { // B is shifted; low As copy across minC+=bshift; // if in place [common], skip copy unless there's a gap [rare] if (a==c && bshift<=alength) { c+=bshift; a+=bshift; } else for (; cmaxC) { // swap Unit *hold=minC; minC=maxC; maxC=hold; } // For speed, do the addition as two loops; the first where both A // and B contribute, and the second (if necessary) where only one or // other of the numbers contribute. // Carry handling is the same (i.e., duplicated) in each case. for (; c=0) { est=(((ueInt)carry>>11)*53687)>>18; *c=(Unit)(carry-est*(DECDPUNMAX+1)); // remainder carry=est; // likely quotient [89%] if (*c>11)*53687)>>18; *c=(Unit)(carry-est*(DECDPUNMAX+1)); carry=est-(DECDPUNMAX+1); // correctly negative if (*c=0) { est=(((ueInt)carry>>3)*16777)>>21; *c=(Unit)(carry-est*(DECDPUNMAX+1)); // remainder carry=est; // likely quotient [99%] if (*c>3)*16777)>>21; *c=(Unit)(carry-est*(DECDPUNMAX+1)); carry=est-(DECDPUNMAX+1); // correctly negative if (*c=0) { est=QUOT10(carry, DECDPUN); *c=(Unit)(carry-est*(DECDPUNMAX+1)); // remainder carry=est; // quotient continue; } // negative case carry=carry+(eInt)(DECDPUNMAX+1)*(DECDPUNMAX+1); // make positive est=QUOT10(carry, DECDPUN); *c=(Unit)(carry-est*(DECDPUNMAX+1)); carry=est-(DECDPUNMAX+1); // correctly negative #else // remainder operator is undefined if negative, so must test if ((ueInt)carry<(DECDPUNMAX+1)*2) { // fastpath carry +1 *c=(Unit)(carry-(DECDPUNMAX+1)); // [helps additions] carry=1; continue; } if (carry>=0) { *c=(Unit)(carry%(DECDPUNMAX+1)); carry=carry/(DECDPUNMAX+1); continue; } // negative case carry=carry+(eInt)(DECDPUNMAX+1)*(DECDPUNMAX+1); // make positive *c=(Unit)(carry%(DECDPUNMAX+1)); carry=carry/(DECDPUNMAX+1)-(DECDPUNMAX+1); #endif } // c // now may have one or other to complete // [pretest to avoid loop setup/shutdown] if (cDECDPUNMAX #if DECDPUN==4 // use divide-by-multiply if (carry>=0) { est=(((ueInt)carry>>11)*53687)>>18; *c=(Unit)(carry-est*(DECDPUNMAX+1)); // remainder carry=est; // likely quotient [79.7%] if (*c>11)*53687)>>18; *c=(Unit)(carry-est*(DECDPUNMAX+1)); carry=est-(DECDPUNMAX+1); // correctly negative if (*c=0) { est=(((ueInt)carry>>3)*16777)>>21; *c=(Unit)(carry-est*(DECDPUNMAX+1)); // remainder carry=est; // likely quotient [99%] if (*c>3)*16777)>>21; *c=(Unit)(carry-est*(DECDPUNMAX+1)); carry=est-(DECDPUNMAX+1); // correctly negative if (*c=0) { est=QUOT10(carry, DECDPUN); *c=(Unit)(carry-est*(DECDPUNMAX+1)); // remainder carry=est; // quotient continue; } // negative case carry=carry+(eInt)(DECDPUNMAX+1)*(DECDPUNMAX+1); // make positive est=QUOT10(carry, DECDPUN); *c=(Unit)(carry-est*(DECDPUNMAX+1)); carry=est-(DECDPUNMAX+1); // correctly negative #else if ((ueInt)carry<(DECDPUNMAX+1)*2){ // fastpath carry 1 *c=(Unit)(carry-(DECDPUNMAX+1)); carry=1; continue; } // remainder operator is undefined if negative, so must test if (carry>=0) { *c=(Unit)(carry%(DECDPUNMAX+1)); carry=carry/(DECDPUNMAX+1); continue; } // negative case carry=carry+(eInt)(DECDPUNMAX+1)*(DECDPUNMAX+1); // make positive *c=(Unit)(carry%(DECDPUNMAX+1)); carry=carry/(DECDPUNMAX+1)-(DECDPUNMAX+1); #endif } // c // OK, all A and B processed; might still have carry or borrow // return number of Units in the result, negated if a borrow if (carry==0) return c-clsu; // no carry, so no more to do if (carry>0) { // positive carry *c=(Unit)carry; // place as new unit c++; // .. return c-clsu; } // -ve carry: it's a borrow; complement needed add=1; // temporary carry... for (c=clsu; c current Unit #if DECCHECK if (decCheckOperands(dn, DECUNUSED, DECUNUSED, DECUNCONT)) return dn; #endif *dropped=0; // assume no zeros dropped if ((dn->bits & DECSPECIAL) // fast exit if special .. || (*dn->lsu & 0x01)) return dn; // .. or odd if (ISZERO(dn)) { // .. or 0 dn->exponent=0; // (sign is preserved) return dn; } // have a finite number which is even exp=dn->exponent; cut=1; // digit (1-DECDPUN) in Unit up=dn->lsu; // -> current Unit for (d=0; ddigits-1; d++) { // [don't strip the final digit] // slice by powers #if DECDPUN<=4 uInt quot=QUOT10(*up, cut); if ((*up-quot*powers[cut])!=0) break; // found non-0 digit #else if (*up%powers[cut]!=0) break; // found non-0 digit #endif // have a trailing 0 if (!all) { // trimming // [if exp>0 then all trailing 0s are significant for trim] if (exp<=0) { // if digit might be significant if (exp==0) break; // then quit exp++; // next digit might be significant } } cut++; // next power if (cut>DECDPUN) { // need new Unit up++; cut=1; } } // d if (d==0) return dn; // none to drop // may need to limit drop if clamping if (set->clamp && !noclamp) { Int maxd=set->emax-set->digits+1-dn->exponent; if (maxd<=0) return dn; // nothing possible if (d>maxd) d=maxd; } // effect the drop decShiftToLeast(dn->lsu, D2U(dn->digits), d); dn->exponent+=d; // maintain numerical value dn->digits-=d; // new length *dropped=d; // report the count return dn; } // decTrim /* ------------------------------------------------------------------ */ /* decReverse -- reverse a Unit array in place */ /* */ /* ulo is the start of the array */ /* uhi is the end of the array (highest Unit to include) */ /* */ /* The units ulo through uhi are reversed in place (if the number */ /* of units is odd, the middle one is untouched). Note that the */ /* digit(s) in each unit are unaffected. */ /* ------------------------------------------------------------------ */ static void decReverse(Unit *ulo, Unit *uhi) { Unit temp; for (; ulo=uar; source--, target--) *target=*source; } else { first=uar+D2U(digits+shift)-1; // where msu of source will end up for (; source>=uar; source--, target--) { // split the source Unit and accumulate remainder for next #if DECDPUN<=4 uInt quot=QUOT10(*source, cut); uInt rem=*source-quot*powers[cut]; next+=quot; #else uInt rem=*source%powers[cut]; next+=*source/powers[cut]; #endif if (target<=first) *target=(Unit)next; // write to target iff valid next=rem*powers[DECDPUN-cut]; // save remainder for next Unit } } // shift-move // propagate any partial unit to one below and clear the rest for (; target>=uar; target--) { *target=(Unit)next; next=0; } return digits+shift; } // decShiftToMost /* ------------------------------------------------------------------ */ /* decShiftToLeast -- shift digits in array towards least significant */ /* */ /* uar is the array */ /* units is length of the array, in units */ /* shift is the number of digits to remove from the lsu end; it */ /* must be zero or positive and <= than units*DECDPUN. */ /* */ /* returns the new length of the integer in the array, in units */ /* */ /* Removed digits are discarded (lost). Units not required to hold */ /* the final result are unchanged. */ /* ------------------------------------------------------------------ */ static Int decShiftToLeast(Unit *uar, Int units, Int shift) { Unit *target, *up; // work Int cut, count; // work Int quot, rem; // for division if (shift==0) return units; // [fastpath] nothing to do if (shift==units*DECDPUN) { // [fastpath] little to do *uar=0; // all digits cleared gives zero return 1; // leaves just the one } target=uar; // both paths cut=MSUDIGITS(shift); if (cut==DECDPUN) { // unit-boundary case; easy up=uar+D2U(shift); for (; updigits is > set->digits) */ /* set is the relevant context */ /* status is the status accumulator */ /* */ /* returns an allocated decNumber with the rounded result. */ /* */ /* lostDigits and other status may be set by this. */ /* */ /* Since the input is an operand, it must not be modified. */ /* Instead, return an allocated decNumber, rounded as required. */ /* It is the caller's responsibility to free the allocated storage. */ /* */ /* If no storage is available then the result cannot be used, so NULL */ /* is returned. */ /* ------------------------------------------------------------------ */ static decNumber *decRoundOperand(const decNumber *dn, decContext *set, uInt *status) { decNumber *res; // result structure uInt newstatus=0; // status from round Int residue=0; // rounding accumulator // Allocate storage for the returned decNumber, big enough for the // length specified by the context res=(decNumber *)malloc(sizeof(decNumber) +(D2U(set->digits)-1)*sizeof(Unit)); if (res==NULL) { *status|=DEC_Insufficient_storage; return NULL; } decCopyFit(res, dn, set, &residue, &newstatus); decApplyRound(res, set, residue, &newstatus); // If that set Inexact then "lost digits" is raised... if (newstatus & DEC_Inexact) newstatus|=DEC_Lost_digits; *status|=newstatus; return res; } // decRoundOperand #endif /* ------------------------------------------------------------------ */ /* decCopyFit -- copy a number, truncating the coefficient if needed */ /* */ /* dest is the target decNumber */ /* src is the source decNumber */ /* set is the context [used for length (digits) and rounding mode] */ /* residue is the residue accumulator */ /* status contains the current status to be updated */ /* */ /* (dest==src is allowed and will be a no-op if fits) */ /* All fields are updated as required. */ /* ------------------------------------------------------------------ */ static void decCopyFit(decNumber *dest, const decNumber *src, decContext *set, Int *residue, uInt *status) { dest->bits=src->bits; dest->exponent=src->exponent; decSetCoeff(dest, set, src->lsu, src->digits, residue, status); } // decCopyFit /* ------------------------------------------------------------------ */ /* decSetCoeff -- set the coefficient of a number */ /* */ /* dn is the number whose coefficient array is to be set. */ /* It must have space for set->digits digits */ /* set is the context [for size] */ /* lsu -> lsu of the source coefficient [may be dn->lsu] */ /* len is digits in the source coefficient [may be dn->digits] */ /* residue is the residue accumulator. This has values as in */ /* decApplyRound, and will be unchanged unless the */ /* target size is less than len. In this case, the */ /* coefficient is truncated and the residue is updated to */ /* reflect the previous residue and the dropped digits. */ /* status is the status accumulator, as usual */ /* */ /* The coefficient may already be in the number, or it can be an */ /* external intermediate array. If it is in the number, lsu must == */ /* dn->lsu and len must == dn->digits. */ /* */ /* Note that the coefficient length (len) may be < set->digits, and */ /* in this case this merely copies the coefficient (or is a no-op */ /* if dn->lsu==lsu). */ /* */ /* Note also that (only internally, from decQuantizeOp and */ /* decSetSubnormal) the value of set->digits may be less than one, */ /* indicating a round to left. This routine handles that case */ /* correctly; caller ensures space. */ /* */ /* dn->digits, dn->lsu (and as required), and dn->exponent are */ /* updated as necessary. dn->bits (sign) is unchanged. */ /* */ /* DEC_Rounded status is set if any digits are discarded. */ /* DEC_Inexact status is set if any non-zero digits are discarded, or */ /* incoming residue was non-0 (implies rounded) */ /* ------------------------------------------------------------------ */ // mapping array: maps 0-9 to canonical residues, so that a residue // can be adjusted in the range [-1, +1] and achieve correct rounding // 0 1 2 3 4 5 6 7 8 9 static const uByte resmap[10]={0, 3, 3, 3, 3, 5, 7, 7, 7, 7}; static void decSetCoeff(decNumber *dn, decContext *set, const Unit *lsu, Int len, Int *residue, uInt *status) { Int discard; // number of digits to discard uInt cut; // cut point in Unit const Unit *up; // work Unit *target; // .. Int count; // .. #if DECDPUN<=4 uInt temp; // .. #endif discard=len-set->digits; // digits to discard if (discard<=0) { // no digits are being discarded if (dn->lsu!=lsu) { // copy needed // copy the coefficient array to the result number; no shift needed count=len; // avoids D2U up=lsu; for (target=dn->lsu; count>0; target++, up++, count-=DECDPUN) *target=*up; dn->digits=len; // set the new length } // dn->exponent and residue are unchanged, record any inexactitude if (*residue!=0) *status|=(DEC_Inexact | DEC_Rounded); return; } // some digits must be discarded ... dn->exponent+=discard; // maintain numerical value *status|=DEC_Rounded; // accumulate Rounded status if (*residue>1) *residue=1; // previous residue now to right, so reduce if (discard>len) { // everything, +1, is being discarded // guard digit is 0 // residue is all the number [NB could be all 0s] if (*residue<=0) { // not already positive count=len; // avoids D2U for (up=lsu; count>0; up++, count-=DECDPUN) if (*up!=0) { // found non-0 *residue=1; break; // no need to check any others } } if (*residue!=0) *status|=DEC_Inexact; // record inexactitude *dn->lsu=0; // coefficient will now be 0 dn->digits=1; // .. return; } // total discard // partial discard [most common case] // here, at least the first (most significant) discarded digit exists // spin up the number, noting residue during the spin, until get to // the Unit with the first discarded digit. When reach it, extract // it and remember its position count=0; for (up=lsu;; up++) { count+=DECDPUN; if (count>=discard) break; // full ones all checked if (*up!=0) *residue=1; } // up // here up -> Unit with first discarded digit cut=discard-(count-DECDPUN)-1; if (cut==DECDPUN-1) { // unit-boundary case (fast) Unit half=(Unit)powers[DECDPUN]>>1; // set residue directly if (*up>=half) { if (*up>half) *residue=7; else *residue+=5; // add sticky bit } else { // digits<=0) { // special for Quantize/Subnormal :-( *dn->lsu=0; // .. result is 0 dn->digits=1; // .. } else { // shift to least count=set->digits; // now digits to end up with dn->digits=count; // set the new length up++; // move to next // on unit boundary, so shift-down copy loop is simple for (target=dn->lsu; count>0; target++, up++, count-=DECDPUN) *target=*up; } } // unit-boundary case else { // discard digit is in low digit(s), and not top digit uInt discard1; // first discarded digit uInt quot, rem; // for divisions if (cut==0) quot=*up; // is at bottom of unit else /* cut>0 */ { // it's not at bottom of unit #if DECDPUN<=4 quot=QUOT10(*up, cut); rem=*up-quot*powers[cut]; #else rem=*up%powers[cut]; quot=*up/powers[cut]; #endif if (rem!=0) *residue=1; } // discard digit is now at bottom of quot #if DECDPUN<=4 temp=(quot*6554)>>16; // fast /10 // Vowels algorithm here not a win (9 instructions) discard1=quot-X10(temp); quot=temp; #else discard1=quot%10; quot=quot/10; #endif // here, discard1 is the guard digit, and residue is everything // else [use mapping array to accumulate residue safely] *residue+=resmap[discard1]; cut++; // update cut // here: up -> Unit of the array with bottom digit // cut is the division point for each Unit // quot holds the uncut high-order digits for the current unit if (set->digits<=0) { // special for Quantize/Subnormal :-( *dn->lsu=0; // .. result is 0 dn->digits=1; // .. } else { // shift to least needed count=set->digits; // now digits to end up with dn->digits=count; // set the new length // shift-copy the coefficient array to the result number for (target=dn->lsu; ; target++) { *target=(Unit)quot; count-=(DECDPUN-cut); if (count<=0) break; up++; quot=*up; #if DECDPUN<=4 quot=QUOT10(quot, cut); rem=*up-quot*powers[cut]; #else rem=quot%powers[cut]; quot=quot/powers[cut]; #endif *target=(Unit)(*target+rem*powers[DECDPUN-cut]); count-=cut; if (count<=0) break; } // shift-copy loop } // shift to least } // not unit boundary if (*residue!=0) *status|=DEC_Inexact; // record inexactitude return; } // decSetCoeff /* ------------------------------------------------------------------ */ /* decApplyRound -- apply pending rounding to a number */ /* */ /* dn is the number, with space for set->digits digits */ /* set is the context [for size and rounding mode] */ /* residue indicates pending rounding, being any accumulated */ /* guard and sticky information. It may be: */ /* 6-9: rounding digit is >5 */ /* 5: rounding digit is exactly half-way */ /* 1-4: rounding digit is <5 and >0 */ /* 0: the coefficient is exact */ /* -1: as 1, but the hidden digits are subtractive, that */ /* is, of the opposite sign to dn. In this case the */ /* coefficient must be non-0. This case occurs when */ /* subtracting a small number (which can be reduced to */ /* a sticky bit); see decAddOp. */ /* status is the status accumulator, as usual */ /* */ /* This routine applies rounding while keeping the length of the */ /* coefficient constant. The exponent and status are unchanged */ /* except if: */ /* */ /* -- the coefficient was increased and is all nines (in which */ /* case Overflow could occur, and is handled directly here so */ /* the caller does not need to re-test for overflow) */ /* */ /* -- the coefficient was decreased and becomes all nines (in which */ /* case Underflow could occur, and is also handled directly). */ /* */ /* All fields in dn are updated as required. */ /* */ /* ------------------------------------------------------------------ */ static void decApplyRound(decNumber *dn, decContext *set, Int residue, uInt *status) { Int bump; // 1 if coefficient needs to be incremented // -1 if coefficient needs to be decremented if (residue==0) return; // nothing to apply bump=0; // assume a smooth ride // now decide whether, and how, to round, depending on mode switch (set->round) { case DEC_ROUND_05UP: { // round zero or five up (for reround) // This is the same as DEC_ROUND_DOWN unless there is a // positive residue and the lsd of dn is 0 or 5, in which case // it is bumped; when residue is <0, the number is therefore // bumped down unless the final digit was 1 or 6 (in which // case it is bumped down and then up -- a no-op) Int lsd5=*dn->lsu%5; // get lsd and quintate if (residue<0 && lsd5!=1) bump=-1; else if (residue>0 && lsd5==0) bump=1; // [bump==1 could be applied directly; use common path for clarity] break;} // r-05 case DEC_ROUND_DOWN: { // no change, except if negative residue if (residue<0) bump=-1; break;} // r-d case DEC_ROUND_HALF_DOWN: { if (residue>5) bump=1; break;} // r-h-d case DEC_ROUND_HALF_EVEN: { if (residue>5) bump=1; // >0.5 goes up else if (residue==5) { // exactly 0.5000... // 0.5 goes up iff [new] lsd is odd if (*dn->lsu & 0x01) bump=1; } break;} // r-h-e case DEC_ROUND_HALF_UP: { if (residue>=5) bump=1; break;} // r-h-u case DEC_ROUND_UP: { if (residue>0) bump=1; break;} // r-u case DEC_ROUND_CEILING: { // same as _UP for positive numbers, and as _DOWN for negatives // [negative residue cannot occur on 0] if (decNumberIsNegative(dn)) { if (residue<0) bump=-1; } else { if (residue>0) bump=1; } break;} // r-c case DEC_ROUND_FLOOR: { // same as _UP for negative numbers, and as _DOWN for positive // [negative residue cannot occur on 0] if (!decNumberIsNegative(dn)) { if (residue<0) bump=-1; } else { if (residue>0) bump=1; } break;} // r-f default: { // e.g., DEC_ROUND_MAX *status|=DEC_Invalid_context; #if DECTRACE || (DECCHECK && DECVERB) printf("Unknown rounding mode: %d\n", set->round); #endif break;} } // switch // now bump the number, up or down, if need be if (bump==0) return; // no action required // Simply use decUnitAddSub unless bumping up and the number is // all nines. In this special case set to 100... explicitly // and adjust the exponent by one (as otherwise could overflow // the array) // Similarly handle all-nines result if bumping down. if (bump>0) { Unit *up; // work uInt count=dn->digits; // digits to be checked for (up=dn->lsu; ; up++) { if (count<=DECDPUN) { // this is the last Unit (the msu) if (*up!=powers[count]-1) break; // not still 9s // here if it, too, is all nines *up=(Unit)powers[count-1]; // here 999 -> 100 etc. for (up=up-1; up>=dn->lsu; up--) *up=0; // others all to 0 dn->exponent++; // and bump exponent // [which, very rarely, could cause Overflow...] if ((dn->exponent+dn->digits)>set->emax+1) { decSetOverflow(dn, set, status); } return; // done } // a full unit to check, with more to come if (*up!=DECDPUNMAX) break; // not still 9s count-=DECDPUN; } // up } // bump>0 else { // -1 // here checking for a pre-bump of 1000... (leading 1, all // other digits zero) Unit *up, *sup; // work uInt count=dn->digits; // digits to be checked for (up=dn->lsu; ; up++) { if (count<=DECDPUN) { // this is the last Unit (the msu) if (*up!=powers[count-1]) break; // not 100.. // here if have the 1000... case sup=up; // save msu pointer *up=(Unit)powers[count]-1; // here 100 in msu -> 999 // others all to all-nines, too for (up=up-1; up>=dn->lsu; up--) *up=(Unit)powers[DECDPUN]-1; dn->exponent--; // and bump exponent // iff the number was at the subnormal boundary (exponent=etiny) // then the exponent is now out of range, so it will in fact get // clamped to etiny and the final 9 dropped. // printf(">> emin=%d exp=%d sdig=%d\n", set->emin, // dn->exponent, set->digits); if (dn->exponent+1==set->emin-set->digits+1) { if (count==1 && dn->digits==1) *sup=0; // here 9 -> 0[.9] else { *sup=(Unit)powers[count-1]-1; // here 999.. in msu -> 99.. dn->digits--; } dn->exponent++; *status|=DEC_Underflow | DEC_Subnormal | DEC_Inexact | DEC_Rounded; } return; // done } // a full unit to check, with more to come if (*up!=0) break; // not still 0s count-=DECDPUN; } // up } // bump<0 // Actual bump needed. Do it. decUnitAddSub(dn->lsu, D2U(dn->digits), uarrone, 1, 0, dn->lsu, bump); } // decApplyRound #if DECSUBSET /* ------------------------------------------------------------------ */ /* decFinish -- finish processing a number */ /* */ /* dn is the number */ /* set is the context */ /* residue is the rounding accumulator (as in decApplyRound) */ /* status is the accumulator */ /* */ /* This finishes off the current number by: */ /* 1. If not extended: */ /* a. Converting a zero result to clean '0' */ /* b. Reducing positive exponents to 0, if would fit in digits */ /* 2. Checking for overflow and subnormals (always) */ /* Note this is just Finalize when no subset arithmetic. */ /* All fields are updated as required. */ /* ------------------------------------------------------------------ */ static void decFinish(decNumber *dn, decContext *set, Int *residue, uInt *status) { if (!set->extended) { if ISZERO(dn) { // value is zero dn->exponent=0; // clean exponent .. dn->bits=0; // .. and sign return; // no error possible } if (dn->exponent>=0) { // non-negative exponent // >0; reduce to integer if possible if (set->digits >= (dn->exponent+dn->digits)) { dn->digits=decShiftToMost(dn->lsu, dn->digits, dn->exponent); dn->exponent=0; } } } // !extended decFinalize(dn, set, residue, status); } // decFinish #endif /* ------------------------------------------------------------------ */ /* decFinalize -- final check, clamp, and round of a number */ /* */ /* dn is the number */ /* set is the context */ /* residue is the rounding accumulator (as in decApplyRound) */ /* status is the status accumulator */ /* */ /* This finishes off the current number by checking for subnormal */ /* results, applying any pending rounding, checking for overflow, */ /* and applying any clamping. */ /* Underflow and overflow conditions are raised as appropriate. */ /* All fields are updated as required. */ /* ------------------------------------------------------------------ */ static void decFinalize(decNumber *dn, decContext *set, Int *residue, uInt *status) { Int shift; // shift needed if clamping Int tinyexp=set->emin-dn->digits+1; // precalculate subnormal boundary // Must be careful, here, when checking the exponent as the // adjusted exponent could overflow 31 bits [because it may already // be up to twice the expected]. // First test for subnormal. This must be done before any final // round as the result could be rounded to Nmin or 0. if (dn->exponent<=tinyexp) { // prefilter Int comp; decNumber nmin; // A very nasty case here is dn == Nmin and residue<0 if (dn->exponentemin; comp=decCompare(dn, &nmin, 1); // (signless compare) if (comp==BADINT) { // oops *status|=DEC_Insufficient_storage; // abandon... return; } if (*residue<0 && comp==0) { // neg residue and dn==Nmin decApplyRound(dn, set, *residue, status); // might force down decSetSubnormal(dn, set, residue, status); return; } } // now apply any pending round (this could raise overflow). if (*residue!=0) decApplyRound(dn, set, *residue, status); // Check for overflow [redundant in the 'rare' case] or clamp if (dn->exponent<=set->emax-set->digits+1) return; // neither needed // here when might have an overflow or clamp to do if (dn->exponent>set->emax-dn->digits+1) { // too big decSetOverflow(dn, set, status); return; } // here when the result is normal but in clamp range if (!set->clamp) return; // here when need to apply the IEEE exponent clamp (fold-down) shift=dn->exponent-(set->emax-set->digits+1); // shift coefficient (if non-zero) if (!ISZERO(dn)) { dn->digits=decShiftToMost(dn->lsu, dn->digits, shift); } dn->exponent-=shift; // adjust the exponent to match *status|=DEC_Clamped; // and record the dirty deed return; } // decFinalize /* ------------------------------------------------------------------ */ /* decSetOverflow -- set number to proper overflow value */ /* */ /* dn is the number (used for sign [only] and result) */ /* set is the context [used for the rounding mode, etc.] */ /* status contains the current status to be updated */ /* */ /* This sets the sign of a number and sets its value to either */ /* Infinity or the maximum finite value, depending on the sign of */ /* dn and the rounding mode, following IEEE 754 rules. */ /* ------------------------------------------------------------------ */ static void decSetOverflow(decNumber *dn, decContext *set, uInt *status) { Flag needmax=0; // result is maximum finite value uByte sign=dn->bits&DECNEG; // clean and save sign bit if (ISZERO(dn)) { // zero does not overflow magnitude Int emax=set->emax; // limit value if (set->clamp) emax-=set->digits-1; // lower if clamping if (dn->exponent>emax) { // clamp required dn->exponent=emax; *status|=DEC_Clamped; } return; } decNumberZero(dn); switch (set->round) { case DEC_ROUND_DOWN: { needmax=1; // never Infinity break;} // r-d case DEC_ROUND_05UP: { needmax=1; // never Infinity break;} // r-05 case DEC_ROUND_CEILING: { if (sign) needmax=1; // Infinity if non-negative break;} // r-c case DEC_ROUND_FLOOR: { if (!sign) needmax=1; // Infinity if negative break;} // r-f default: break; // Infinity in all other cases } if (needmax) { decSetMaxValue(dn, set); dn->bits=sign; // set sign } else dn->bits=sign|DECINF; // Value is +/-Infinity *status|=DEC_Overflow | DEC_Inexact | DEC_Rounded; } // decSetOverflow /* ------------------------------------------------------------------ */ /* decSetMaxValue -- set number to +Nmax (maximum normal value) */ /* */ /* dn is the number to set */ /* set is the context [used for digits and emax] */ /* */ /* This sets the number to the maximum positive value. */ /* ------------------------------------------------------------------ */ static void decSetMaxValue(decNumber *dn, decContext *set) { Unit *up; // work Int count=set->digits; // nines to add dn->digits=count; // fill in all nines to set maximum value for (up=dn->lsu; ; up++) { if (count>DECDPUN) *up=DECDPUNMAX; // unit full o'nines else { // this is the msu *up=(Unit)(powers[count]-1); break; } count-=DECDPUN; // filled those digits } // up dn->bits=0; // + sign dn->exponent=set->emax-set->digits+1; } // decSetMaxValue /* ------------------------------------------------------------------ */ /* decSetSubnormal -- process value whose exponent is extended) { decNumberZero(dn); // always full overflow *status|=DEC_Underflow | DEC_Subnormal | DEC_Inexact | DEC_Rounded; return; } #endif // Full arithmetic -- allow subnormals, rounded to minimum exponent // (Etiny) if needed etiny=set->emin-(set->digits-1); // smallest allowed exponent if ISZERO(dn) { // value is zero // residue can never be non-zero here #if DECCHECK if (*residue!=0) { printf("++ Subnormal 0 residue %ld\n", (LI)*residue); *status|=DEC_Invalid_operation; } #endif if (dn->exponentexponent=etiny; *status|=DEC_Clamped; } return; } *status|=DEC_Subnormal; // have a non-zero subnormal adjust=etiny-dn->exponent; // calculate digits to remove if (adjust<=0) { // not out of range; unrounded // residue can never be non-zero here, except in the Nmin-residue // case (which is a subnormal result), so can take fast-path here // it may already be inexact (from setting the coefficient) if (*status&DEC_Inexact) *status|=DEC_Underflow; return; } // adjust>0, so need to rescale the result so exponent becomes Etiny // [this code is similar to that in rescale] workset=*set; // clone rounding, etc. workset.digits=dn->digits-adjust; // set requested length workset.emin-=adjust; // and adjust emin to match // [note that the latter can be <1, here, similar to Rescale case] decSetCoeff(dn, &workset, dn->lsu, dn->digits, residue, status); decApplyRound(dn, &workset, *residue, status); // Use 754 default rule: Underflow is set iff Inexact // [independent of whether trapped] if (*status&DEC_Inexact) *status|=DEC_Underflow; // if rounded up a 999s case, exponent will be off by one; adjust // back if so [it will fit, because it was shortened earlier] if (dn->exponent>etiny) { dn->digits=decShiftToMost(dn->lsu, dn->digits, 1); dn->exponent--; // (re)adjust the exponent. } // if rounded to zero, it is by definition clamped... if (ISZERO(dn)) *status|=DEC_Clamped; } // decSetSubnormal /* ------------------------------------------------------------------ */ /* decCheckMath - check entry conditions for a math function */ /* */ /* This checks the context and the operand */ /* */ /* rhs is the operand to check */ /* set is the context to check */ /* status is unchanged if both are good */ /* */ /* returns non-zero if status is changed, 0 otherwise */ /* */ /* Restrictions enforced: */ /* */ /* digits, emax, and -emin in the context must be less than */ /* DEC_MAX_MATH (999999), and A must be within these bounds if */ /* non-zero. Invalid_operation is set in the status if a */ /* restriction is violated. */ /* ------------------------------------------------------------------ */ static uInt decCheckMath(const decNumber *rhs, decContext *set, uInt *status) { uInt save=*status; // record if (set->digits>DEC_MAX_MATH || set->emax>DEC_MAX_MATH || -set->emin>DEC_MAX_MATH) *status|=DEC_Invalid_context; else if ((rhs->digits>DEC_MAX_MATH || rhs->exponent+rhs->digits>DEC_MAX_MATH+1 || rhs->exponent+rhs->digits<2*(1-DEC_MAX_MATH)) && !ISZERO(rhs)) *status|=DEC_Invalid_operation; return (*status!=save); } // decCheckMath /* ------------------------------------------------------------------ */ /* decGetInt -- get integer from a number */ /* */ /* dn is the number [which will not be altered] */ /* */ /* returns one of: */ /* BADINT if there is a non-zero fraction */ /* the converted integer */ /* BIGEVEN if the integer is even and magnitude > 2*10**9 */ /* BIGODD if the integer is odd and magnitude > 2*10**9 */ /* */ /* This checks and gets a whole number from the input decNumber. */ /* The sign can be determined from dn by the caller when BIGEVEN or */ /* BIGODD is returned. */ /* ------------------------------------------------------------------ */ static Int decGetInt(const decNumber *dn) { Int theInt; // result accumulator const Unit *up; // work Int got; // digits (real or not) processed Int ilength=dn->digits+dn->exponent; // integral length Flag neg=decNumberIsNegative(dn); // 1 if -ve // The number must be an integer that fits in 10 digits // Assert, here, that 10 is enough for any rescale Etiny #if DEC_MAX_EMAX > 999999999 #error GetInt may need updating [for Emax] #endif #if DEC_MIN_EMIN < -999999999 #error GetInt may need updating [for Emin] #endif if (ISZERO(dn)) return 0; // zeros are OK, with any exponent up=dn->lsu; // ready for lsu theInt=0; // ready to accumulate if (dn->exponent>=0) { // relatively easy // no fractional part [usual]; allow for positive exponent got=dn->exponent; } else { // -ve exponent; some fractional part to check and discard Int count=-dn->exponent; // digits to discard // spin up whole units until reach the Unit with the unit digit for (; count>=DECDPUN; up++) { if (*up!=0) return BADINT; // non-zero Unit to discard count-=DECDPUN; } if (count==0) got=0; // [a multiple of DECDPUN] else { // [not multiple of DECDPUN] Int rem; // work // slice off fraction digits and check for non-zero #if DECDPUN<=4 theInt=QUOT10(*up, count); rem=*up-theInt*powers[count]; #else rem=*up%powers[count]; // slice off discards theInt=*up/powers[count]; #endif if (rem!=0) return BADINT; // non-zero fraction // it looks good got=DECDPUN-count; // number of digits so far up++; // ready for next } } // now it's known there's no fractional part // tricky code now, to accumulate up to 9.3 digits if (got==0) {theInt=*up; got+=DECDPUN; up++;} // ensure lsu is there if (ilength<11) { Int save=theInt; // collect any remaining unit(s) for (; got1999999997) ilength=11; else if (!neg && theInt>999999999) ilength=11; if (ilength==11) theInt=save; // restore correct low bit } } if (ilength>10) { // too big if (theInt&1) return BIGODD; // bottom bit 1 return BIGEVEN; // bottom bit 0 } if (neg) theInt=-theInt; // apply sign return theInt; } // decGetInt /* ------------------------------------------------------------------ */ /* decDecap -- decapitate the coefficient of a number */ /* */ /* dn is the number to be decapitated */ /* drop is the number of digits to be removed from the left of dn; */ /* this must be <= dn->digits (if equal, the coefficient is */ /* set to 0) */ /* */ /* Returns dn; dn->digits will be <= the initial digits less drop */ /* (after removing drop digits there may be leading zero digits */ /* which will also be removed). Only dn->lsu and dn->digits change. */ /* ------------------------------------------------------------------ */ static decNumber *decDecap(decNumber *dn, Int drop) { Unit *msu; // -> target cut point Int cut; // work if (drop>=dn->digits) { // losing the whole thing #if DECCHECK if (drop>dn->digits) printf("decDecap called with drop>digits [%ld>%ld]\n", (LI)drop, (LI)dn->digits); #endif dn->lsu[0]=0; dn->digits=1; return dn; } msu=dn->lsu+D2U(dn->digits-drop)-1; // -> likely msu cut=MSUDIGITS(dn->digits-drop); // digits to be in use in msu if (cut!=DECDPUN) *msu%=powers[cut]; // clear left digits // that may have left leading zero digits, so do a proper count... dn->digits=decGetDigits(dn->lsu, msu-dn->lsu+1); return dn; } // decDecap /* ------------------------------------------------------------------ */ /* decBiStr -- compare string with pairwise options */ /* */ /* targ is the string to compare */ /* str1 is one of the strings to compare against (length may be 0) */ /* str2 is the other; it must be the same length as str1 */ /* */ /* returns 1 if strings compare equal, (that is, it is the same */ /* length as str1 and str2, and each character of targ is in either */ /* str1 or str2 in the corresponding position), or 0 otherwise */ /* */ /* This is used for generic caseless compare, including the awkward */ /* case of the Turkish dotted and dotless Is. Use as (for example): */ /* if (decBiStr(test, "mike", "MIKE")) ... */ /* ------------------------------------------------------------------ */ static Flag decBiStr(const char *targ, const char *str1, const char *str2) { for (;;targ++, str1++, str2++) { if (*targ!=*str1 && *targ!=*str2) return 0; // *targ has a match in one (or both, if terminator) if (*targ=='\0') break; } // forever return 1; } // decBiStr /* ------------------------------------------------------------------ */ /* decNaNs -- handle NaN operand or operands */ /* */ /* res is the result number */ /* lhs is the first operand */ /* rhs is the second operand, or NULL if none */ /* context is used to limit payload length */ /* status contains the current status */ /* returns res in case convenient */ /* */ /* Called when one or both operands is a NaN, and propagates the */ /* appropriate result to res. When an sNaN is found, it is changed */ /* to a qNaN and Invalid operation is set. */ /* ------------------------------------------------------------------ */ static decNumber * decNaNs(decNumber *res, const decNumber *lhs, const decNumber *rhs, decContext *set, uInt *status) { // This decision tree ends up with LHS being the source pointer, // and status updated if need be if (lhs->bits & DECSNAN) *status|=DEC_Invalid_operation | DEC_sNaN; else if (rhs==NULL); else if (rhs->bits & DECSNAN) { lhs=rhs; *status|=DEC_Invalid_operation | DEC_sNaN; } else if (lhs->bits & DECNAN); else lhs=rhs; // propagate the payload if (lhs->digits<=set->digits) decNumberCopy(res, lhs); // easy else { // too long const Unit *ul; Unit *ur, *uresp1; // copy safe number of units, then decapitate res->bits=lhs->bits; // need sign etc. uresp1=res->lsu+D2U(set->digits); for (ur=res->lsu, ul=lhs->lsu; urdigits=D2U(set->digits)*DECDPUN; // maybe still too long if (res->digits>set->digits) decDecap(res, res->digits-set->digits); } res->bits&=~DECSNAN; // convert any sNaN to NaN, while res->bits|=DECNAN; // .. preserving sign res->exponent=0; // clean exponent // [coefficient was copied/decapitated] return res; } // decNaNs /* ------------------------------------------------------------------ */ /* decStatus -- apply non-zero status */ /* */ /* dn is the number to set if error */ /* status contains the current status (not yet in context) */ /* set is the context */ /* */ /* If the status is an error status, the number is set to a NaN, */ /* unless the error was an overflow, divide-by-zero, or underflow, */ /* in which case the number will have already been set. */ /* */ /* The context status is then updated with the new status. Note that */ /* this may raise a signal, so control may never return from this */ /* routine (hence resources must be recovered before it is called). */ /* ------------------------------------------------------------------ */ static void decStatus(decNumber *dn, uInt status, decContext *set) { if (status & DEC_NaNs) { // error status -> NaN // if cause was an sNaN, clear and propagate [NaN is already set up] if (status & DEC_sNaN) status&=~DEC_sNaN; else { decNumberZero(dn); // other error: clean throughout dn->bits=DECNAN; // and make a quiet NaN } } decContextSetStatus(set, status); // [may not return] return; } // decStatus /* ------------------------------------------------------------------ */ /* decGetDigits -- count digits in a Units array */ /* */ /* uar is the Unit array holding the number (this is often an */ /* accumulator of some sort) */ /* len is the length of the array in units [>=1] */ /* */ /* returns the number of (significant) digits in the array */ /* */ /* All leading zeros are excluded, except the last if the array has */ /* only zero Units. */ /* ------------------------------------------------------------------ */ // This may be called twice during some operations. static Int decGetDigits(Unit *uar, Int len) { Unit *up=uar+(len-1); // -> msu Int digits=(len-1)*DECDPUN+1; // possible digits excluding msu #if DECDPUN>4 uInt const *pow; // work #endif // (at least 1 in final msu) #if DECCHECK if (len<1) printf("decGetDigits called with len<1 [%ld]\n", (LI)len); #endif for (; up>=uar; up--) { if (*up==0) { // unit is all 0s if (digits==1) break; // a zero has one digit digits-=DECDPUN; // adjust for 0 unit continue;} // found the first (most significant) non-zero Unit #if DECDPUN>1 // not done yet if (*up<10) break; // is 1-9 digits++; #if DECDPUN>2 // not done yet if (*up<100) break; // is 10-99 digits++; #if DECDPUN>3 // not done yet if (*up<1000) break; // is 100-999 digits++; #if DECDPUN>4 // count the rest ... for (pow=&powers[4]; *up>=*pow; pow++) digits++; #endif #endif #endif #endif break; } // up return digits; } // decGetDigits #if DECTRACE | DECCHECK /* ------------------------------------------------------------------ */ /* decNumberShow -- display a number [debug aid] */ /* dn is the number to show */ /* */ /* Shows: sign, exponent, coefficient (msu first), digits */ /* or: sign, special-value */ /* ------------------------------------------------------------------ */ // this is public so other modules can use it void decNumberShow(const decNumber *dn) { const Unit *up; // work uInt u, d; // .. Int cut; // .. char isign='+'; // main sign if (dn==NULL) { printf("NULL\n"); return;} if (decNumberIsNegative(dn)) isign='-'; printf(" >> %c ", isign); if (dn->bits&DECSPECIAL) { // Is a special value if (decNumberIsInfinite(dn)) printf("Infinity"); else { // a NaN if (dn->bits&DECSNAN) printf("sNaN"); // signalling NaN else printf("NaN"); } // if coefficient and exponent are 0, no more to do if (dn->exponent==0 && dn->digits==1 && *dn->lsu==0) { printf("\n"); return;} // drop through to report other information printf(" "); } // now carefully display the coefficient up=dn->lsu+D2U(dn->digits)-1; // msu printf("%ld", (LI)*up); for (up=up-1; up>=dn->lsu; up--) { u=*up; printf(":"); for (cut=DECDPUN-1; cut>=0; cut--) { d=u/powers[cut]; u-=d*powers[cut]; printf("%ld", (LI)d); } // cut } // up if (dn->exponent!=0) { char esign='+'; if (dn->exponent<0) esign='-'; printf(" E%c%ld", esign, (LI)abs(dn->exponent)); } printf(" [%ld]\n", (LI)dn->digits); } // decNumberShow #endif #if DECTRACE || DECCHECK /* ------------------------------------------------------------------ */ /* decDumpAr -- display a unit array [debug/check aid] */ /* name is a single-character tag name */ /* ar is the array to display */ /* len is the length of the array in Units */ /* ------------------------------------------------------------------ */ static void decDumpAr(char name, const Unit *ar, Int len) { Int i; const char *spec; #if DECDPUN==9 spec="%09d "; #elif DECDPUN==8 spec="%08d "; #elif DECDPUN==7 spec="%07d "; #elif DECDPUN==6 spec="%06d "; #elif DECDPUN==5 spec="%05d "; #elif DECDPUN==4 spec="%04d "; #elif DECDPUN==3 spec="%03d "; #elif DECDPUN==2 spec="%02d "; #else spec="%d "; #endif printf(" :%c: ", name); for (i=len-1; i>=0; i--) { if (i==len-1) printf("%ld ", (LI)ar[i]); else printf(spec, ar[i]); } printf("\n"); return;} #endif #if DECCHECK /* ------------------------------------------------------------------ */ /* decCheckOperands -- check operand(s) to a routine */ /* res is the result structure (not checked; it will be set to */ /* quiet NaN if error found (and it is not NULL)) */ /* lhs is the first operand (may be DECUNRESU) */ /* rhs is the second (may be DECUNUSED) */ /* set is the context (may be DECUNCONT) */ /* returns 0 if both operands, and the context are clean, or 1 */ /* otherwise (in which case the context will show an error, */ /* unless NULL). Note that res is not cleaned; caller should */ /* handle this so res=NULL case is safe. */ /* The caller is expected to abandon immediately if 1 is returned. */ /* ------------------------------------------------------------------ */ static Flag decCheckOperands(decNumber *res, const decNumber *lhs, const decNumber *rhs, decContext *set) { Flag bad=0; if (set==NULL) { // oops; hopeless #if DECTRACE || DECVERB printf("Reference to context is NULL.\n"); #endif bad=1; return 1;} else if (set!=DECUNCONT && (set->digits<1 || set->round>=DEC_ROUND_MAX)) { bad=1; #if DECTRACE || DECVERB printf("Bad context [digits=%ld round=%ld].\n", (LI)set->digits, (LI)set->round); #endif } else { if (res==NULL) { bad=1; #if DECTRACE // this one not DECVERB as standard tests include NULL printf("Reference to result is NULL.\n"); #endif } if (!bad && lhs!=DECUNUSED) bad=(decCheckNumber(lhs)); if (!bad && rhs!=DECUNUSED) bad=(decCheckNumber(rhs)); } if (bad) { if (set!=DECUNCONT) decContextSetStatus(set, DEC_Invalid_operation); if (res!=DECUNRESU && res!=NULL) { decNumberZero(res); res->bits=DECNAN; // qNaN } } return bad; } // decCheckOperands /* ------------------------------------------------------------------ */ /* decCheckNumber -- check a number */ /* dn is the number to check */ /* returns 0 if the number is clean, or 1 otherwise */ /* */ /* The number is considered valid if it could be a result from some */ /* operation in some valid context. */ /* ------------------------------------------------------------------ */ static Flag decCheckNumber(const decNumber *dn) { const Unit *up; // work uInt maxuint; // .. Int ae, d, digits; // .. Int emin, emax; // .. if (dn==NULL) { // hopeless #if DECTRACE // this one not DECVERB as standard tests include NULL printf("Reference to decNumber is NULL.\n"); #endif return 1;} // check special values if (dn->bits & DECSPECIAL) { if (dn->exponent!=0) { #if DECTRACE || DECVERB printf("Exponent %ld (not 0) for a special value [%02x].\n", (LI)dn->exponent, dn->bits); #endif return 1;} // 2003.09.08: NaNs may now have coefficients, so next tests Inf only if (decNumberIsInfinite(dn)) { if (dn->digits!=1) { #if DECTRACE || DECVERB printf("Digits %ld (not 1) for an infinity.\n", (LI)dn->digits); #endif return 1;} if (*dn->lsu!=0) { #if DECTRACE || DECVERB printf("LSU %ld (not 0) for an infinity.\n", (LI)*dn->lsu); #endif decDumpAr('I', dn->lsu, D2U(dn->digits)); return 1;} } // Inf // 2002.12.26: negative NaNs can now appear through proposed IEEE // concrete formats (decimal64, etc.). return 0; } // check the coefficient if (dn->digits<1 || dn->digits>DECNUMMAXP) { #if DECTRACE || DECVERB printf("Digits %ld in number.\n", (LI)dn->digits); #endif return 1;} d=dn->digits; for (up=dn->lsu; d>0; up++) { if (d>DECDPUN) maxuint=DECDPUNMAX; else { // reached the msu maxuint=powers[d]-1; if (dn->digits>1 && *upmaxuint) { #if DECTRACE || DECVERB printf("Bad Unit [%08lx] in %ld-digit number at offset %ld [maxuint %ld].\n", (LI)*up, (LI)dn->digits, (LI)(up-dn->lsu), (LI)maxuint); #endif return 1;} d-=DECDPUN; } // check the exponent. Note that input operands can have exponents // which are out of the set->emin/set->emax and set->digits range // (just as they can have more digits than set->digits). ae=dn->exponent+dn->digits-1; // adjusted exponent emax=DECNUMMAXE; emin=DECNUMMINE; digits=DECNUMMAXP; if (ae+emax) { #if DECTRACE || DECVERB printf("Adjusted exponent overflow [%ld].\n", (LI)ae); decNumberShow(dn); #endif return 1;} return 0; // it's OK } // decCheckNumber /* ------------------------------------------------------------------ */ /* decCheckInexact -- check a normal finite inexact result has digits */ /* dn is the number to check */ /* set is the context (for status and precision) */ /* sets Invalid operation, etc., if some digits are missing */ /* [this check is not made for DECSUBSET compilation or when */ /* subnormal is not set] */ /* ------------------------------------------------------------------ */ static void decCheckInexact(const decNumber *dn, decContext *set) { #if !DECSUBSET && DECEXTFLAG if ((set->status & (DEC_Inexact|DEC_Subnormal))==DEC_Inexact && (set->digits!=dn->digits) && !(dn->bits & DECSPECIAL)) { #if DECTRACE || DECVERB printf("Insufficient digits [%ld] on normal Inexact result.\n", (LI)dn->digits); decNumberShow(dn); #endif decContextSetStatus(set, DEC_Invalid_operation); } #else // next is a noop for quiet compiler if (dn!=NULL && dn->digits==0) set->status|=DEC_Invalid_operation; #endif return; } // decCheckInexact #endif #if DECALLOC #undef malloc #undef free /* ------------------------------------------------------------------ */ /* decMalloc -- accountable allocation routine */ /* n is the number of bytes to allocate */ /* */ /* Semantics is the same as the stdlib malloc routine, but bytes */ /* allocated are accounted for globally, and corruption fences are */ /* added before and after the 'actual' storage. */ /* ------------------------------------------------------------------ */ /* This routine allocates storage with an extra twelve bytes; 8 are */ /* at the start and hold: */ /* 0-3 the original length requested */ /* 4-7 buffer corruption detection fence (DECFENCE, x4) */ /* The 4 bytes at the end also hold a corruption fence (DECFENCE, x4) */ /* ------------------------------------------------------------------ */ static void *decMalloc(size_t n) { uInt size=n+12; // true size void *alloc; // -> allocated storage uByte *b, *b0; // work uInt uiwork; // for macros alloc=malloc(size); // -> allocated storage if (alloc==NULL) return NULL; // out of strorage b0=(uByte *)alloc; // as bytes decAllocBytes+=n; // account for storage UBFROMUI(alloc, n); // save n // printf(" alloc ++ dAB: %ld (%ld)\n", (LI)decAllocBytes, (LI)n); for (b=b0+4; b play area } // decMalloc /* ------------------------------------------------------------------ */ /* decFree -- accountable free routine */ /* alloc is the storage to free */ /* */ /* Semantics is the same as the stdlib malloc routine, except that */ /* the global storage accounting is updated and the fences are */ /* checked to ensure that no routine has written 'out of bounds'. */ /* ------------------------------------------------------------------ */ /* This routine first checks that the fences have not been corrupted. */ /* It then frees the storage using the 'truw' storage address (that */ /* is, offset by 8). */ /* ------------------------------------------------------------------ */ static void decFree(void *alloc) { uInt n; // original length uByte *b, *b0; // work uInt uiwork; // for macros if (alloc==NULL) return; // allowed; it's a nop b0=(uByte *)alloc; // as bytes b0-=8; // -> true start of storage n=UBTOUI(b0); // lift length for (b=b0+4; b0 */ /* and <10; 3 or powers of 2 are best]. */ /* DECNUMDIGITS is the default number of digits that can be held in */ /* the structure. If undefined, 1 is assumed and it is assumed */ /* that the structure will be immediately followed by extra space, */ /* as required. DECNUMDIGITS is always >0. */ #if !defined(DECNUMDIGITS) #define DECNUMDIGITS 1 #endif /* The size (integer data type) of each unit is determined by the */ /* number of digits it will hold. */ #if DECDPUN<=2 #define decNumberUnit uint8_t #elif DECDPUN<=4 #define decNumberUnit uint16_t #else #define decNumberUnit uint32_t #endif /* The number of units needed is ceil(DECNUMDIGITS/DECDPUN) */ #define DECNUMUNITS ((DECNUMDIGITS+DECDPUN-1)/DECDPUN) /* The data structure... */ typedef struct { int32_t digits; /* Count of digits in the coefficient; >0 */ int32_t exponent; /* Unadjusted exponent, unbiased, in */ /* range: -1999999997 through 999999999 */ uint8_t bits; /* Indicator bits (see above) */ /* Coefficient, from least significant unit */ decNumberUnit lsu[DECNUMUNITS]; } decNumber; /* Notes: */ /* 1. If digits is > DECDPUN then there will one or more */ /* decNumberUnits immediately following the first element of lsu.*/ /* These contain the remaining (more significant) digits of the */ /* number, and may be in the lsu array, or may be guaranteed by */ /* some other mechanism (such as being contained in another */ /* structure, or being overlaid on dynamically allocated */ /* storage). */ /* */ /* Each integer of the coefficient (except potentially the last) */ /* contains DECDPUN digits (e.g., a value in the range 0 through */ /* 99999999 if DECDPUN is 8, or 0 through 999 if DECDPUN is 3). */ /* */ /* 2. A decNumber converted to a string may need up to digits+14 */ /* characters. The worst cases (non-exponential and exponential */ /* formats) are -0.00000{9...}# and -9.{9...}E+999999999# */ /* (where # is '\0') */ /* ---------------------------------------------------------------- */ /* decNumber public functions and macros */ /* ---------------------------------------------------------------- */ /* Conversions */ decNumber * decNumberFromInt32(decNumber *, int32_t); decNumber * decNumberFromUInt32(decNumber *, uint32_t); decNumber * decNumberFromString(decNumber *, const char *, decContext *); char * decNumberToString(const decNumber *, char *); char * decNumberToEngString(const decNumber *, char *); uint32_t decNumberToUInt32(const decNumber *, decContext *); int32_t decNumberToInt32(const decNumber *, decContext *); uint8_t * decNumberGetBCD(const decNumber *, uint8_t *); decNumber * decNumberSetBCD(decNumber *, const uint8_t *, uint32_t); /* Operators and elementary functions */ decNumber * decNumberAbs(decNumber *, const decNumber *, decContext *); decNumber * decNumberAdd(decNumber *, const decNumber *, const decNumber *, decContext *); decNumber * decNumberAnd(decNumber *, const decNumber *, const decNumber *, decContext *); decNumber * decNumberCompare(decNumber *, const decNumber *, const decNumber *, decContext *); decNumber * decNumberCompareSignal(decNumber *, const decNumber *, const decNumber *, decContext *); decNumber * decNumberCompareTotal(decNumber *, const decNumber *, const decNumber *, decContext *); decNumber * decNumberCompareTotalMag(decNumber *, const decNumber *, const decNumber *, decContext *); decNumber * decNumberDivide(decNumber *, const decNumber *, const decNumber *, decContext *); decNumber * decNumberDivideInteger(decNumber *, const decNumber *, const decNumber *, decContext *); decNumber * decNumberExp(decNumber *, const decNumber *, decContext *); decNumber * decNumberFMA(decNumber *, const decNumber *, const decNumber *, const decNumber *, decContext *); decNumber * decNumberInvert(decNumber *, const decNumber *, decContext *); decNumber * decNumberLn(decNumber *, const decNumber *, decContext *); decNumber * decNumberLogB(decNumber *, const decNumber *, decContext *); decNumber * decNumberLog10(decNumber *, const decNumber *, decContext *); decNumber * decNumberMax(decNumber *, const decNumber *, const decNumber *, decContext *); decNumber * decNumberMaxMag(decNumber *, const decNumber *, const decNumber *, decContext *); decNumber * decNumberMin(decNumber *, const decNumber *, const decNumber *, decContext *); decNumber * decNumberMinMag(decNumber *, const decNumber *, const decNumber *, decContext *); decNumber * decNumberMinus(decNumber *, const decNumber *, decContext *); decNumber * decNumberMultiply(decNumber *, const decNumber *, const decNumber *, decContext *); decNumber * decNumberNormalize(decNumber *, const decNumber *, decContext *); decNumber * decNumberOr(decNumber *, const decNumber *, const decNumber *, decContext *); decNumber * decNumberPlus(decNumber *, const decNumber *, decContext *); decNumber * decNumberPower(decNumber *, const decNumber *, const decNumber *, decContext *); decNumber * decNumberQuantize(decNumber *, const decNumber *, const decNumber *, decContext *); decNumber * decNumberReduce(decNumber *, const decNumber *, decContext *); decNumber * decNumberRemainder(decNumber *, const decNumber *, const decNumber *, decContext *); decNumber * decNumberRemainderNear(decNumber *, const decNumber *, const decNumber *, decContext *); decNumber * decNumberRescale(decNumber *, const decNumber *, const decNumber *, decContext *); decNumber * decNumberRotate(decNumber *, const decNumber *, const decNumber *, decContext *); decNumber * decNumberSameQuantum(decNumber *, const decNumber *, const decNumber *); decNumber * decNumberScaleB(decNumber *, const decNumber *, const decNumber *, decContext *); decNumber * decNumberShift(decNumber *, const decNumber *, const decNumber *, decContext *); decNumber * decNumberSquareRoot(decNumber *, const decNumber *, decContext *); decNumber * decNumberSubtract(decNumber *, const decNumber *, const decNumber *, decContext *); decNumber * decNumberToIntegralExact(decNumber *, const decNumber *, decContext *); decNumber * decNumberToIntegralValue(decNumber *, const decNumber *, decContext *); decNumber * decNumberXor(decNumber *, const decNumber *, const decNumber *, decContext *); /* Utilities */ enum decClass decNumberClass(const decNumber *, decContext *); const char * decNumberClassToString(enum decClass); decNumber * decNumberCopy(decNumber *, const decNumber *); decNumber * decNumberCopyAbs(decNumber *, const decNumber *); decNumber * decNumberCopyNegate(decNumber *, const decNumber *); decNumber * decNumberCopySign(decNumber *, const decNumber *, const decNumber *); decNumber * decNumberNextMinus(decNumber *, const decNumber *, decContext *); decNumber * decNumberNextPlus(decNumber *, const decNumber *, decContext *); decNumber * decNumberNextToward(decNumber *, const decNumber *, const decNumber *, decContext *); decNumber * decNumberTrim(decNumber *); const char * decNumberVersion(void); decNumber * decNumberZero(decNumber *); /* Functions for testing decNumbers (normality depends on context) */ int32_t decNumberIsNormal(const decNumber *, decContext *); int32_t decNumberIsSubnormal(const decNumber *, decContext *); /* Macros for testing decNumber *dn */ #define decNumberIsCanonical(dn) (1) /* All decNumbers are saintly */ #define decNumberIsFinite(dn) (((dn)->bits&DECSPECIAL)==0) #define decNumberIsInfinite(dn) (((dn)->bits&DECINF)!=0) #define decNumberIsNaN(dn) (((dn)->bits&(DECNAN|DECSNAN))!=0) #define decNumberIsNegative(dn) (((dn)->bits&DECNEG)!=0) #define decNumberIsQNaN(dn) (((dn)->bits&(DECNAN))!=0) #define decNumberIsSNaN(dn) (((dn)->bits&(DECSNAN))!=0) #define decNumberIsSpecial(dn) (((dn)->bits&DECSPECIAL)!=0) #define decNumberIsZero(dn) (*(dn)->lsu==0 \ && (dn)->digits==1 \ && (((dn)->bits&DECSPECIAL)==0)) #define decNumberRadix(dn) (10) #endif ================================================ FILE: vendor/decNumber/decNumberLocal.h ================================================ /* ------------------------------------------------------------------ */ /* decNumber package local type, tuning, and macro definitions */ /* ------------------------------------------------------------------ */ /* Copyright (c) IBM Corporation, 2000, 2010. All rights reserved. */ /* */ /* This software is made available under the terms of the */ /* ICU License -- ICU 1.8.1 and later. */ /* */ /* The description and User's Guide ("The decNumber C Library") for */ /* this software is called decNumber.pdf. This document is */ /* available, together with arithmetic and format specifications, */ /* testcases, and Web links, on the General Decimal Arithmetic page. */ /* */ /* Please send comments, suggestions, and corrections to the author: */ /* mfc@uk.ibm.com */ /* Mike Cowlishaw, IBM Fellow */ /* IBM UK, PO Box 31, Birmingham Road, Warwick CV34 5JL, UK */ /* ------------------------------------------------------------------ */ /* This header file is included by all modules in the decNumber */ /* library, and contains local type definitions, tuning parameters, */ /* etc. It should not need to be used by application programs. */ /* decNumber.h or one of decDouble (etc.) must be included first. */ /* ------------------------------------------------------------------ */ #if !defined(DECNUMBERLOC) #define DECNUMBERLOC #define DECVERSION "decNumber 3.68" /* Package Version [16 max.] */ #define DECNLAUTHOR "Mike Cowlishaw" /* Who to blame */ #include /* for abs */ #include /* for memset, strcpy */ /* Conditional code flag -- set this to match hardware platform */ #if !defined(DECLITEND) #define DECLITEND 1 /* 1=little-endian, 0=big-endian */ #endif /* Conditional code flag -- set this to 1 for best performance */ #if !defined(DECUSE64) #define DECUSE64 1 /* 1=use int64s, 0=int32 & smaller only */ #endif /* Conditional code flag -- set this to 0 to exclude printf calls */ #if !defined(DECPRINT) #define DECPRINT 1 /* 1=allow printf calls; 0=no printf */ #endif /* Conditional check flags -- set these to 0 for best performance */ #if !defined(DECCHECK) #define DECCHECK 0 /* 1 to enable robust checking */ #endif #if !defined(DECALLOC) #define DECALLOC 0 /* 1 to enable memory accounting */ #endif #if !defined(DECTRACE) #define DECTRACE 0 /* 1 to trace certain internals, etc. */ #endif /* Tuning parameter for decNumber (arbitrary precision) module */ #if !defined(DECBUFFER) #define DECBUFFER 36 /* Size basis for local buffers. This */ /* should be a common maximum precision */ /* rounded up to a multiple of 4; must */ /* be zero or positive. */ #endif /* ---------------------------------------------------------------- */ /* Check parameter dependencies */ /* ---------------------------------------------------------------- */ #if DECCHECK & !DECPRINT #error DECCHECK needs DECPRINT to be useful #endif #if DECALLOC & !DECPRINT #error DECALLOC needs DECPRINT to be useful #endif #if DECTRACE & !DECPRINT #error DECTRACE needs DECPRINT to be useful #endif /* ---------------------------------------------------------------- */ /* Definitions for all modules (general-purpose) */ /* ---------------------------------------------------------------- */ /* Local names for common types -- for safety, decNumber modules do */ /* not use int or long directly. */ #define Flag uint8_t #define Byte int8_t #define uByte uint8_t #define Short int16_t #define uShort uint16_t #define Int int32_t #define uInt uint32_t #define Unit decNumberUnit #if DECUSE64 #define Long int64_t #define uLong uint64_t #endif /* Development-use definitions */ typedef long int LI; /* for printf arguments only */ #define DECNOINT 0 /* 1 to check no internal use of 'int' */ /* or stdint types */ #if DECNOINT /* if these interfere with your C includes, do not set DECNOINT */ #define int ? /* enable to ensure that plain C 'int' */ #define long ?? /* .. or 'long' types are not used */ #endif /* Shared lookup tables */ extern const uByte DECSTICKYTAB[10]; /* re-round digits if sticky */ extern const uInt DECPOWERS[10]; /* powers of ten table */ /* The following are included from decDPD.h */ extern const uShort DPD2BIN[1024]; /* DPD -> 0-999 */ extern const uShort BIN2DPD[1000]; /* 0-999 -> DPD */ extern const uInt DPD2BINK[1024]; /* DPD -> 0-999000 */ extern const uInt DPD2BINM[1024]; /* DPD -> 0-999000000 */ extern const uByte DPD2BCD8[4096]; /* DPD -> ddd + len */ extern const uByte BIN2BCD8[4000]; /* 0-999 -> ddd + len */ extern const uShort BCD2DPD[2458]; /* 0-0x999 -> DPD (0x999=2457)*/ /* LONGMUL32HI -- set w=(u*v)>>32, where w, u, and v are uInts */ /* (that is, sets w to be the high-order word of the 64-bit result; */ /* the low-order word is simply u*v.) */ /* This version is derived from Knuth via Hacker's Delight; */ /* it seems to optimize better than some others tried */ #define LONGMUL32HI(w, u, v) { \ uInt u0, u1, v0, v1, w0, w1, w2, t; \ u0=u & 0xffff; u1=u>>16; \ v0=v & 0xffff; v1=v>>16; \ w0=u0*v0; \ t=u1*v0 + (w0>>16); \ w1=t & 0xffff; w2=t>>16; \ w1=u0*v1 + w1; \ (w)=u1*v1 + w2 + (w1>>16);} /* ROUNDUP -- round an integer up to a multiple of n */ #define ROUNDUP(i, n) ((((i)+(n)-1)/n)*n) #define ROUNDUP4(i) (((i)+3)&~3) /* special for n=4 */ /* ROUNDDOWN -- round an integer down to a multiple of n */ #define ROUNDDOWN(i, n) (((i)/n)*n) #define ROUNDDOWN4(i) ((i)&~3) /* special for n=4 */ /* References to multi-byte sequences under different sizes; these */ /* require locally declared variables, but do not violate strict */ /* aliasing or alignment (as did the UINTAT simple cast to uInt). */ /* Variables needed are uswork, uiwork, etc. [so do not use at same */ /* level in an expression, e.g., UBTOUI(x)==UBTOUI(y) may fail]. */ /* Return a uInt, etc., from bytes starting at a char* or uByte* */ #define UBTOUS(b) (memcpy((void *)&uswork, b, 2), uswork) #define UBTOUI(b) (memcpy((void *)&uiwork, b, 4), uiwork) /* Store a uInt, etc., into bytes starting at a char* or uByte*. */ /* Returns i, evaluated, for convenience; has to use uiwork because */ /* i may be an expression. */ #define UBFROMUS(b, i) (uswork=(i), memcpy(b, (void *)&uswork, 2), uswork) #define UBFROMUI(b, i) (uiwork=(i), memcpy(b, (void *)&uiwork, 4), uiwork) /* X10 and X100 -- multiply integer i by 10 or 100 */ /* [shifts are usually faster than multiply; could be conditional] */ #define X10(i) (((i)<<1)+((i)<<3)) #define X100(i) (((i)<<2)+((i)<<5)+((i)<<6)) /* MAXI and MINI -- general max & min (not in ANSI) for integers */ #define MAXI(x,y) ((x)<(y)?(y):(x)) #define MINI(x,y) ((x)>(y)?(y):(x)) /* Useful constants */ #define BILLION 1000000000 /* 10**9 */ /* CHARMASK: 0x30303030 for ASCII/UTF8; 0xF0F0F0F0 for EBCDIC */ #define CHARMASK ((((((((uInt)'0')<<8)+'0')<<8)+'0')<<8)+'0') /* ---------------------------------------------------------------- */ /* Definitions for arbitary-precision modules (only valid after */ /* decNumber.h has been included) */ /* ---------------------------------------------------------------- */ /* Limits and constants */ #define DECNUMMAXP 999999999 /* maximum precision code can handle */ #define DECNUMMAXE 999999999 /* maximum adjusted exponent ditto */ #define DECNUMMINE -999999999 /* minimum adjusted exponent ditto */ #if (DECNUMMAXP != DEC_MAX_DIGITS) #error Maximum digits mismatch #endif #if (DECNUMMAXE != DEC_MAX_EMAX) #error Maximum exponent mismatch #endif #if (DECNUMMINE != DEC_MIN_EMIN) #error Minimum exponent mismatch #endif /* Set DECDPUNMAX -- the maximum integer that fits in DECDPUN */ /* digits, and D2UTABLE -- the initializer for the D2U table */ #if DECDPUN==1 #define DECDPUNMAX 9 #define D2UTABLE {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17, \ 18,19,20,21,22,23,24,25,26,27,28,29,30,31,32, \ 33,34,35,36,37,38,39,40,41,42,43,44,45,46,47, \ 48,49} #elif DECDPUN==2 #define DECDPUNMAX 99 #define D2UTABLE {0,1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8,9,9,10,10, \ 11,11,12,12,13,13,14,14,15,15,16,16,17,17,18, \ 18,19,19,20,20,21,21,22,22,23,23,24,24,25} #elif DECDPUN==3 #define DECDPUNMAX 999 #define D2UTABLE {0,1,1,1,2,2,2,3,3,3,4,4,4,5,5,5,6,6,6,7,7,7, \ 8,8,8,9,9,9,10,10,10,11,11,11,12,12,12,13,13, \ 13,14,14,14,15,15,15,16,16,16,17} #elif DECDPUN==4 #define DECDPUNMAX 9999 #define D2UTABLE {0,1,1,1,1,2,2,2,2,3,3,3,3,4,4,4,4,5,5,5,5,6, \ 6,6,6,7,7,7,7,8,8,8,8,9,9,9,9,10,10,10,10,11, \ 11,11,11,12,12,12,12,13} #elif DECDPUN==5 #define DECDPUNMAX 99999 #define D2UTABLE {0,1,1,1,1,1,2,2,2,2,2,3,3,3,3,3,4,4,4,4,4,5, \ 5,5,5,5,6,6,6,6,6,7,7,7,7,7,8,8,8,8,8,9,9,9, \ 9,9,10,10,10,10} #elif DECDPUN==6 #define DECDPUNMAX 999999 #define D2UTABLE {0,1,1,1,1,1,1,2,2,2,2,2,2,3,3,3,3,3,3,4,4,4, \ 4,4,4,5,5,5,5,5,5,6,6,6,6,6,6,7,7,7,7,7,7,8, \ 8,8,8,8,8,9} #elif DECDPUN==7 #define DECDPUNMAX 9999999 #define D2UTABLE {0,1,1,1,1,1,1,1,2,2,2,2,2,2,2,3,3,3,3,3,3,3, \ 4,4,4,4,4,4,4,5,5,5,5,5,5,5,6,6,6,6,6,6,6,7, \ 7,7,7,7,7,7} #elif DECDPUN==8 #define DECDPUNMAX 99999999 #define D2UTABLE {0,1,1,1,1,1,1,1,1,2,2,2,2,2,2,2,2,3,3,3,3,3, \ 3,3,3,4,4,4,4,4,4,4,4,5,5,5,5,5,5,5,5,6,6,6, \ 6,6,6,6,6,7} #elif DECDPUN==9 #define DECDPUNMAX 999999999 #define D2UTABLE {0,1,1,1,1,1,1,1,1,1,2,2,2,2,2,2,2,2,2,3,3,3, \ 3,3,3,3,3,3,4,4,4,4,4,4,4,4,4,5,5,5,5,5,5,5, \ 5,5,6,6,6,6} #elif defined(DECDPUN) #error DECDPUN must be in the range 1-9 #endif /* ----- Shared data (in decNumber.c) ----- */ /* Public lookup table used by the D2U macro (see below) */ #define DECMAXD2U 49 extern const uByte d2utable[DECMAXD2U+1]; /* ----- Macros ----- */ /* ISZERO -- return true if decNumber dn is a zero */ /* [performance-critical in some situations] */ #define ISZERO(dn) decNumberIsZero(dn) /* now just a local name */ /* D2U -- return the number of Units needed to hold d digits */ /* (runtime version, with table lookaside for small d) */ #if DECDPUN==8 #define D2U(d) ((unsigned)((d)<=DECMAXD2U?d2utable[d]:((d)+7)>>3)) #elif DECDPUN==4 #define D2U(d) ((unsigned)((d)<=DECMAXD2U?d2utable[d]:((d)+3)>>2)) #else #define D2U(d) ((d)<=DECMAXD2U?d2utable[d]:((d)+DECDPUN-1)/DECDPUN) #endif /* SD2U -- static D2U macro (for compile-time calculation) */ #define SD2U(d) (((d)+DECDPUN-1)/DECDPUN) /* MSUDIGITS -- returns digits in msu, from digits, calculated */ /* using D2U */ #define MSUDIGITS(d) ((d)-(D2U(d)-1)*DECDPUN) /* D2N -- return the number of decNumber structs that would be */ /* needed to contain that number of digits (and the initial */ /* decNumber struct) safely. Note that one Unit is included in the */ /* initial structure. Used for allocating space that is aligned on */ /* a decNumber struct boundary. */ #define D2N(d) \ ((((SD2U(d)-1)*sizeof(Unit))+sizeof(decNumber)*2-1)/sizeof(decNumber)) /* TODIGIT -- macro to remove the leading digit from the unsigned */ /* integer u at column cut (counting from the right, LSD=0) and */ /* place it as an ASCII character into the character pointed to by */ /* c. Note that cut must be <= 9, and the maximum value for u is */ /* 2,000,000,000 (as is needed for negative exponents of */ /* subnormals). The unsigned integer pow is used as a temporary */ /* variable. */ #define TODIGIT(u, cut, c, pow) { \ *(c)='0'; \ pow=DECPOWERS[cut]*2; \ if ((u)>pow) { \ pow*=4; \ if ((u)>=pow) {(u)-=pow; *(c)+=8;} \ pow/=2; \ if ((u)>=pow) {(u)-=pow; *(c)+=4;} \ pow/=2; \ } \ if ((u)>=pow) {(u)-=pow; *(c)+=2;} \ pow/=2; \ if ((u)>=pow) {(u)-=pow; *(c)+=1;} \ } /* ---------------------------------------------------------------- */ /* Definitions for fixed-precision modules (only valid after */ /* decSingle.h, decDouble.h, or decQuad.h has been included) */ /* ---------------------------------------------------------------- */ /* bcdnum -- a structure describing a format-independent finite */ /* number, whose coefficient is a string of bcd8 uBytes */ typedef struct { uByte *msd; /* -> most significant digit */ uByte *lsd; /* -> least ditto */ uInt sign; /* 0=positive, DECFLOAT_Sign=negative */ Int exponent; /* Unadjusted signed exponent (q), or */ /* DECFLOAT_NaN etc. for a special */ } bcdnum; /* Test if exponent or bcdnum exponent must be a special, etc. */ #define EXPISSPECIAL(exp) ((exp)>=DECFLOAT_MinSp) #define EXPISINF(exp) (exp==DECFLOAT_Inf) #define EXPISNAN(exp) (exp==DECFLOAT_qNaN || exp==DECFLOAT_sNaN) #define NUMISSPECIAL(num) (EXPISSPECIAL((num)->exponent)) /* Refer to a 32-bit word or byte in a decFloat (df) by big-endian */ /* (array) notation (the 0 word or byte contains the sign bit), */ /* automatically adjusting for endianness; similarly address a word */ /* in the next-wider format (decFloatWider, or dfw) */ #define DECWORDS (DECBYTES/4) #define DECWWORDS (DECWBYTES/4) #if DECLITEND #define DFBYTE(df, off) ((df)->bytes[DECBYTES-1-(off)]) #define DFWORD(df, off) ((df)->words[DECWORDS-1-(off)]) #define DFWWORD(dfw, off) ((dfw)->words[DECWWORDS-1-(off)]) #else #define DFBYTE(df, off) ((df)->bytes[off]) #define DFWORD(df, off) ((df)->words[off]) #define DFWWORD(dfw, off) ((dfw)->words[off]) #endif /* Tests for sign or specials, directly on DECFLOATs */ #define DFISSIGNED(df) ((DFWORD(df, 0)&0x80000000)!=0) #define DFISSPECIAL(df) ((DFWORD(df, 0)&0x78000000)==0x78000000) #define DFISINF(df) ((DFWORD(df, 0)&0x7c000000)==0x78000000) #define DFISNAN(df) ((DFWORD(df, 0)&0x7c000000)==0x7c000000) #define DFISQNAN(df) ((DFWORD(df, 0)&0x7e000000)==0x7c000000) #define DFISSNAN(df) ((DFWORD(df, 0)&0x7e000000)==0x7e000000) /* Shared lookup tables */ extern const uInt DECCOMBMSD[64]; /* Combination field -> MSD */ extern const uInt DECCOMBFROM[48]; /* exp+msd -> Combination */ /* Private generic (utility) routine */ #if DECCHECK || DECTRACE extern void decShowNum(const bcdnum *, const char *); #endif /* Format-dependent macros and constants */ #if defined(DECPMAX) /* Useful constants */ #define DECPMAX9 (ROUNDUP(DECPMAX, 9)/9) /* 'Pmax' in 10**9s */ /* Top words for a zero */ #define SINGLEZERO 0x22500000 #define DOUBLEZERO 0x22380000 #define QUADZERO 0x22080000 /* [ZEROWORD is defined to be one of these in the DFISZERO macro] */ /* Format-dependent common tests: */ /* DFISZERO -- test for (any) zero */ /* DFISCCZERO -- test for coefficient continuation being zero */ /* DFISCC01 -- test for coefficient contains only 0s and 1s */ /* DFISINT -- test for finite and exponent q=0 */ /* DFISUINT01 -- test for sign=0, finite, exponent q=0, and */ /* MSD=0 or 1 */ /* ZEROWORD is also defined here. */ /* */ /* In DFISZERO the first test checks the least-significant word */ /* (most likely to be non-zero); the penultimate tests MSD and */ /* DPDs in the signword, and the final test excludes specials and */ /* MSD>7. DFISINT similarly has to allow for the two forms of */ /* MSD codes. DFISUINT01 only has to allow for one form of MSD */ /* code. */ #if DECPMAX==7 #define ZEROWORD SINGLEZERO /* [test macros not needed except for Zero] */ #define DFISZERO(df) ((DFWORD(df, 0)&0x1c0fffff)==0 \ && (DFWORD(df, 0)&0x60000000)!=0x60000000) #elif DECPMAX==16 #define ZEROWORD DOUBLEZERO #define DFISZERO(df) ((DFWORD(df, 1)==0 \ && (DFWORD(df, 0)&0x1c03ffff)==0 \ && (DFWORD(df, 0)&0x60000000)!=0x60000000)) #define DFISINT(df) ((DFWORD(df, 0)&0x63fc0000)==0x22380000 \ ||(DFWORD(df, 0)&0x7bfc0000)==0x6a380000) #define DFISUINT01(df) ((DFWORD(df, 0)&0xfbfc0000)==0x22380000) #define DFISCCZERO(df) (DFWORD(df, 1)==0 \ && (DFWORD(df, 0)&0x0003ffff)==0) #define DFISCC01(df) ((DFWORD(df, 0)&~0xfffc9124)==0 \ && (DFWORD(df, 1)&~0x49124491)==0) #elif DECPMAX==34 #define ZEROWORD QUADZERO #define DFISZERO(df) ((DFWORD(df, 3)==0 \ && DFWORD(df, 2)==0 \ && DFWORD(df, 1)==0 \ && (DFWORD(df, 0)&0x1c003fff)==0 \ && (DFWORD(df, 0)&0x60000000)!=0x60000000)) #define DFISINT(df) ((DFWORD(df, 0)&0x63ffc000)==0x22080000 \ ||(DFWORD(df, 0)&0x7bffc000)==0x6a080000) #define DFISUINT01(df) ((DFWORD(df, 0)&0xfbffc000)==0x22080000) #define DFISCCZERO(df) (DFWORD(df, 3)==0 \ && DFWORD(df, 2)==0 \ && DFWORD(df, 1)==0 \ && (DFWORD(df, 0)&0x00003fff)==0) #define DFISCC01(df) ((DFWORD(df, 0)&~0xffffc912)==0 \ && (DFWORD(df, 1)&~0x44912449)==0 \ && (DFWORD(df, 2)&~0x12449124)==0 \ && (DFWORD(df, 3)&~0x49124491)==0) #endif /* Macros to test if a certain 10 bits of a uInt or pair of uInts */ /* are a canonical declet [higher or lower bits are ignored]. */ /* declet is at offset 0 (from the right) in a uInt: */ #define CANONDPD(dpd) (((dpd)&0x300)==0 || ((dpd)&0x6e)!=0x6e) /* declet is at offset k (a multiple of 2) in a uInt: */ #define CANONDPDOFF(dpd, k) (((dpd)&(0x300<<(k)))==0 \ || ((dpd)&(((uInt)0x6e)<<(k)))!=(((uInt)0x6e)<<(k))) /* declet is at offset k (a multiple of 2) in a pair of uInts: */ /* [the top 2 bits will always be in the more-significant uInt] */ #define CANONDPDTWO(hi, lo, k) (((hi)&(0x300>>(32-(k))))==0 \ || ((hi)&(0x6e>>(32-(k))))!=(0x6e>>(32-(k))) \ || ((lo)&(((uInt)0x6e)<<(k)))!=(((uInt)0x6e)<<(k))) /* Macro to test whether a full-length (length DECPMAX) BCD8 */ /* coefficient, starting at uByte u, is all zeros */ /* Test just the LSWord first, then the remainder as a sequence */ /* of tests in order to avoid same-level use of UBTOUI */ #if DECPMAX==7 #define ISCOEFFZERO(u) ( \ UBTOUI((u)+DECPMAX-4)==0 \ && UBTOUS((u)+DECPMAX-6)==0 \ && *(u)==0) #elif DECPMAX==16 #define ISCOEFFZERO(u) ( \ UBTOUI((u)+DECPMAX-4)==0 \ && UBTOUI((u)+DECPMAX-8)==0 \ && UBTOUI((u)+DECPMAX-12)==0 \ && UBTOUI(u)==0) #elif DECPMAX==34 #define ISCOEFFZERO(u) ( \ UBTOUI((u)+DECPMAX-4)==0 \ && UBTOUI((u)+DECPMAX-8)==0 \ && UBTOUI((u)+DECPMAX-12)==0 \ && UBTOUI((u)+DECPMAX-16)==0 \ && UBTOUI((u)+DECPMAX-20)==0 \ && UBTOUI((u)+DECPMAX-24)==0 \ && UBTOUI((u)+DECPMAX-28)==0 \ && UBTOUI((u)+DECPMAX-32)==0 \ && UBTOUS(u)==0) #endif /* Macros and masks for the sign, exponent continuation, and MSD */ /* Get the sign as DECFLOAT_Sign or 0 */ #define GETSIGN(df) (DFWORD(df, 0)&0x80000000) /* Get the exponent continuation from a decFloat *df as an Int */ #define GETECON(df) ((Int)((DFWORD((df), 0)&0x03ffffff)>>(32-6-DECECONL))) /* Ditto, from the next-wider format */ #define GETWECON(df) ((Int)((DFWWORD((df), 0)&0x03ffffff)>>(32-6-DECWECONL))) /* Get the biased exponent similarly */ #define GETEXP(df) ((Int)(DECCOMBEXP[DFWORD((df), 0)>>26]+GETECON(df))) /* Get the unbiased exponent similarly */ #define GETEXPUN(df) ((Int)GETEXP(df)-DECBIAS) /* Get the MSD similarly (as uInt) */ #define GETMSD(df) (DECCOMBMSD[DFWORD((df), 0)>>26]) /* Compile-time computes of the exponent continuation field masks */ /* full exponent continuation field: */ #define ECONMASK ((0x03ffffff>>(32-6-DECECONL))<<(32-6-DECECONL)) /* same, not including its first digit (the qNaN/sNaN selector): */ #define ECONNANMASK ((0x01ffffff>>(32-6-DECECONL))<<(32-6-DECECONL)) /* Macros to decode the coefficient in a finite decFloat *df into */ /* a BCD string (uByte *bcdin) of length DECPMAX uBytes. */ /* In-line sequence to convert least significant 10 bits of uInt */ /* dpd to three BCD8 digits starting at uByte u. Note that an */ /* extra byte is written to the right of the three digits because */ /* four bytes are moved at a time for speed; the alternative */ /* macro moves exactly three bytes (usually slower). */ #define dpd2bcd8(u, dpd) memcpy(u, &DPD2BCD8[((dpd)&0x3ff)*4], 4) #define dpd2bcd83(u, dpd) memcpy(u, &DPD2BCD8[((dpd)&0x3ff)*4], 3) /* Decode the declets. After extracting each one, it is decoded */ /* to BCD8 using a table lookup (also used for variable-length */ /* decode). Each DPD decode is 3 bytes BCD8 plus a one-byte */ /* length which is not used, here). Fixed-length 4-byte moves */ /* are fast, however, almost everywhere, and so are used except */ /* for the final three bytes (to avoid overrun). The code below */ /* is 36 instructions for Doubles and about 70 for Quads, even */ /* on IA32. */ /* Two macros are defined for each format: */ /* GETCOEFF extracts the coefficient of the current format */ /* GETWCOEFF extracts the coefficient of the next-wider format. */ /* The latter is a copy of the next-wider GETCOEFF using DFWWORD. */ #if DECPMAX==7 #define GETCOEFF(df, bcd) { \ uInt sourhi=DFWORD(df, 0); \ *(bcd)=(uByte)DECCOMBMSD[sourhi>>26]; \ dpd2bcd8(bcd+1, sourhi>>10); \ dpd2bcd83(bcd+4, sourhi);} #define GETWCOEFF(df, bcd) { \ uInt sourhi=DFWWORD(df, 0); \ uInt sourlo=DFWWORD(df, 1); \ *(bcd)=(uByte)DECCOMBMSD[sourhi>>26]; \ dpd2bcd8(bcd+1, sourhi>>8); \ dpd2bcd8(bcd+4, (sourhi<<2) | (sourlo>>30)); \ dpd2bcd8(bcd+7, sourlo>>20); \ dpd2bcd8(bcd+10, sourlo>>10); \ dpd2bcd83(bcd+13, sourlo);} #elif DECPMAX==16 #define GETCOEFF(df, bcd) { \ uInt sourhi=DFWORD(df, 0); \ uInt sourlo=DFWORD(df, 1); \ *(bcd)=(uByte)DECCOMBMSD[sourhi>>26]; \ dpd2bcd8(bcd+1, sourhi>>8); \ dpd2bcd8(bcd+4, (sourhi<<2) | (sourlo>>30)); \ dpd2bcd8(bcd+7, sourlo>>20); \ dpd2bcd8(bcd+10, sourlo>>10); \ dpd2bcd83(bcd+13, sourlo);} #define GETWCOEFF(df, bcd) { \ uInt sourhi=DFWWORD(df, 0); \ uInt sourmh=DFWWORD(df, 1); \ uInt sourml=DFWWORD(df, 2); \ uInt sourlo=DFWWORD(df, 3); \ *(bcd)=(uByte)DECCOMBMSD[sourhi>>26]; \ dpd2bcd8(bcd+1, sourhi>>4); \ dpd2bcd8(bcd+4, ((sourhi)<<6) | (sourmh>>26)); \ dpd2bcd8(bcd+7, sourmh>>16); \ dpd2bcd8(bcd+10, sourmh>>6); \ dpd2bcd8(bcd+13, ((sourmh)<<4) | (sourml>>28)); \ dpd2bcd8(bcd+16, sourml>>18); \ dpd2bcd8(bcd+19, sourml>>8); \ dpd2bcd8(bcd+22, ((sourml)<<2) | (sourlo>>30)); \ dpd2bcd8(bcd+25, sourlo>>20); \ dpd2bcd8(bcd+28, sourlo>>10); \ dpd2bcd83(bcd+31, sourlo);} #elif DECPMAX==34 #define GETCOEFF(df, bcd) { \ uInt sourhi=DFWORD(df, 0); \ uInt sourmh=DFWORD(df, 1); \ uInt sourml=DFWORD(df, 2); \ uInt sourlo=DFWORD(df, 3); \ *(bcd)=(uByte)DECCOMBMSD[sourhi>>26]; \ dpd2bcd8(bcd+1, sourhi>>4); \ dpd2bcd8(bcd+4, ((sourhi)<<6) | (sourmh>>26)); \ dpd2bcd8(bcd+7, sourmh>>16); \ dpd2bcd8(bcd+10, sourmh>>6); \ dpd2bcd8(bcd+13, ((sourmh)<<4) | (sourml>>28)); \ dpd2bcd8(bcd+16, sourml>>18); \ dpd2bcd8(bcd+19, sourml>>8); \ dpd2bcd8(bcd+22, ((sourml)<<2) | (sourlo>>30)); \ dpd2bcd8(bcd+25, sourlo>>20); \ dpd2bcd8(bcd+28, sourlo>>10); \ dpd2bcd83(bcd+31, sourlo);} #define GETWCOEFF(df, bcd) {??} /* [should never be used] */ #endif /* Macros to decode the coefficient in a finite decFloat *df into */ /* a base-billion uInt array, with the least-significant */ /* 0-999999999 'digit' at offset 0. */ /* Decode the declets. After extracting each one, it is decoded */ /* to binary using a table lookup. Three tables are used; one */ /* the usual DPD to binary, the other two pre-multiplied by 1000 */ /* and 1000000 to avoid multiplication during decode. These */ /* tables can also be used for multiplying up the MSD as the DPD */ /* code for 0 through 9 is the identity. */ #define DPD2BIN0 DPD2BIN /* for prettier code */ #if DECPMAX==7 #define GETCOEFFBILL(df, buf) { \ uInt sourhi=DFWORD(df, 0); \ (buf)[0]=DPD2BIN0[sourhi&0x3ff] \ +DPD2BINK[(sourhi>>10)&0x3ff] \ +DPD2BINM[DECCOMBMSD[sourhi>>26]];} #elif DECPMAX==16 #define GETCOEFFBILL(df, buf) { \ uInt sourhi, sourlo; \ sourlo=DFWORD(df, 1); \ (buf)[0]=DPD2BIN0[sourlo&0x3ff] \ +DPD2BINK[(sourlo>>10)&0x3ff] \ +DPD2BINM[(sourlo>>20)&0x3ff]; \ sourhi=DFWORD(df, 0); \ (buf)[1]=DPD2BIN0[((sourhi<<2) | (sourlo>>30))&0x3ff] \ +DPD2BINK[(sourhi>>8)&0x3ff] \ +DPD2BINM[DECCOMBMSD[sourhi>>26]];} #elif DECPMAX==34 #define GETCOEFFBILL(df, buf) { \ uInt sourhi, sourmh, sourml, sourlo; \ sourlo=DFWORD(df, 3); \ (buf)[0]=DPD2BIN0[sourlo&0x3ff] \ +DPD2BINK[(sourlo>>10)&0x3ff] \ +DPD2BINM[(sourlo>>20)&0x3ff]; \ sourml=DFWORD(df, 2); \ (buf)[1]=DPD2BIN0[((sourml<<2) | (sourlo>>30))&0x3ff] \ +DPD2BINK[(sourml>>8)&0x3ff] \ +DPD2BINM[(sourml>>18)&0x3ff]; \ sourmh=DFWORD(df, 1); \ (buf)[2]=DPD2BIN0[((sourmh<<4) | (sourml>>28))&0x3ff] \ +DPD2BINK[(sourmh>>6)&0x3ff] \ +DPD2BINM[(sourmh>>16)&0x3ff]; \ sourhi=DFWORD(df, 0); \ (buf)[3]=DPD2BIN0[((sourhi<<6) | (sourmh>>26))&0x3ff] \ +DPD2BINK[(sourhi>>4)&0x3ff] \ +DPD2BINM[DECCOMBMSD[sourhi>>26]];} #endif /* Macros to decode the coefficient in a finite decFloat *df into */ /* a base-thousand uInt array (of size DECLETS+1, to allow for */ /* the MSD), with the least-significant 0-999 'digit' at offset 0.*/ /* Decode the declets. After extracting each one, it is decoded */ /* to binary using a table lookup. */ #if DECPMAX==7 #define GETCOEFFTHOU(df, buf) { \ uInt sourhi=DFWORD(df, 0); \ (buf)[0]=DPD2BIN[sourhi&0x3ff]; \ (buf)[1]=DPD2BIN[(sourhi>>10)&0x3ff]; \ (buf)[2]=DECCOMBMSD[sourhi>>26];} #elif DECPMAX==16 #define GETCOEFFTHOU(df, buf) { \ uInt sourhi, sourlo; \ sourlo=DFWORD(df, 1); \ (buf)[0]=DPD2BIN[sourlo&0x3ff]; \ (buf)[1]=DPD2BIN[(sourlo>>10)&0x3ff]; \ (buf)[2]=DPD2BIN[(sourlo>>20)&0x3ff]; \ sourhi=DFWORD(df, 0); \ (buf)[3]=DPD2BIN[((sourhi<<2) | (sourlo>>30))&0x3ff]; \ (buf)[4]=DPD2BIN[(sourhi>>8)&0x3ff]; \ (buf)[5]=DECCOMBMSD[sourhi>>26];} #elif DECPMAX==34 #define GETCOEFFTHOU(df, buf) { \ uInt sourhi, sourmh, sourml, sourlo; \ sourlo=DFWORD(df, 3); \ (buf)[0]=DPD2BIN[sourlo&0x3ff]; \ (buf)[1]=DPD2BIN[(sourlo>>10)&0x3ff]; \ (buf)[2]=DPD2BIN[(sourlo>>20)&0x3ff]; \ sourml=DFWORD(df, 2); \ (buf)[3]=DPD2BIN[((sourml<<2) | (sourlo>>30))&0x3ff]; \ (buf)[4]=DPD2BIN[(sourml>>8)&0x3ff]; \ (buf)[5]=DPD2BIN[(sourml>>18)&0x3ff]; \ sourmh=DFWORD(df, 1); \ (buf)[6]=DPD2BIN[((sourmh<<4) | (sourml>>28))&0x3ff]; \ (buf)[7]=DPD2BIN[(sourmh>>6)&0x3ff]; \ (buf)[8]=DPD2BIN[(sourmh>>16)&0x3ff]; \ sourhi=DFWORD(df, 0); \ (buf)[9]=DPD2BIN[((sourhi<<6) | (sourmh>>26))&0x3ff]; \ (buf)[10]=DPD2BIN[(sourhi>>4)&0x3ff]; \ (buf)[11]=DECCOMBMSD[sourhi>>26];} #endif /* Macros to decode the coefficient in a finite decFloat *df and */ /* add to a base-thousand uInt array (as for GETCOEFFTHOU). */ /* After the addition then most significant 'digit' in the array */ /* might have a value larger then 10 (with a maximum of 19). */ #if DECPMAX==7 #define ADDCOEFFTHOU(df, buf) { \ uInt sourhi=DFWORD(df, 0); \ (buf)[0]+=DPD2BIN[sourhi&0x3ff]; \ if (buf[0]>999) {buf[0]-=1000; buf[1]++;} \ (buf)[1]+=DPD2BIN[(sourhi>>10)&0x3ff]; \ if (buf[1]>999) {buf[1]-=1000; buf[2]++;} \ (buf)[2]+=DECCOMBMSD[sourhi>>26];} #elif DECPMAX==16 #define ADDCOEFFTHOU(df, buf) { \ uInt sourhi, sourlo; \ sourlo=DFWORD(df, 1); \ (buf)[0]+=DPD2BIN[sourlo&0x3ff]; \ if (buf[0]>999) {buf[0]-=1000; buf[1]++;} \ (buf)[1]+=DPD2BIN[(sourlo>>10)&0x3ff]; \ if (buf[1]>999) {buf[1]-=1000; buf[2]++;} \ (buf)[2]+=DPD2BIN[(sourlo>>20)&0x3ff]; \ if (buf[2]>999) {buf[2]-=1000; buf[3]++;} \ sourhi=DFWORD(df, 0); \ (buf)[3]+=DPD2BIN[((sourhi<<2) | (sourlo>>30))&0x3ff]; \ if (buf[3]>999) {buf[3]-=1000; buf[4]++;} \ (buf)[4]+=DPD2BIN[(sourhi>>8)&0x3ff]; \ if (buf[4]>999) {buf[4]-=1000; buf[5]++;} \ (buf)[5]+=DECCOMBMSD[sourhi>>26];} #elif DECPMAX==34 #define ADDCOEFFTHOU(df, buf) { \ uInt sourhi, sourmh, sourml, sourlo; \ sourlo=DFWORD(df, 3); \ (buf)[0]+=DPD2BIN[sourlo&0x3ff]; \ if (buf[0]>999) {buf[0]-=1000; buf[1]++;} \ (buf)[1]+=DPD2BIN[(sourlo>>10)&0x3ff]; \ if (buf[1]>999) {buf[1]-=1000; buf[2]++;} \ (buf)[2]+=DPD2BIN[(sourlo>>20)&0x3ff]; \ if (buf[2]>999) {buf[2]-=1000; buf[3]++;} \ sourml=DFWORD(df, 2); \ (buf)[3]+=DPD2BIN[((sourml<<2) | (sourlo>>30))&0x3ff]; \ if (buf[3]>999) {buf[3]-=1000; buf[4]++;} \ (buf)[4]+=DPD2BIN[(sourml>>8)&0x3ff]; \ if (buf[4]>999) {buf[4]-=1000; buf[5]++;} \ (buf)[5]+=DPD2BIN[(sourml>>18)&0x3ff]; \ if (buf[5]>999) {buf[5]-=1000; buf[6]++;} \ sourmh=DFWORD(df, 1); \ (buf)[6]+=DPD2BIN[((sourmh<<4) | (sourml>>28))&0x3ff]; \ if (buf[6]>999) {buf[6]-=1000; buf[7]++;} \ (buf)[7]+=DPD2BIN[(sourmh>>6)&0x3ff]; \ if (buf[7]>999) {buf[7]-=1000; buf[8]++;} \ (buf)[8]+=DPD2BIN[(sourmh>>16)&0x3ff]; \ if (buf[8]>999) {buf[8]-=1000; buf[9]++;} \ sourhi=DFWORD(df, 0); \ (buf)[9]+=DPD2BIN[((sourhi<<6) | (sourmh>>26))&0x3ff]; \ if (buf[9]>999) {buf[9]-=1000; buf[10]++;} \ (buf)[10]+=DPD2BIN[(sourhi>>4)&0x3ff]; \ if (buf[10]>999) {buf[10]-=1000; buf[11]++;} \ (buf)[11]+=DECCOMBMSD[sourhi>>26];} #endif /* Set a decFloat to the maximum positive finite number (Nmax) */ #if DECPMAX==7 #define DFSETNMAX(df) \ {DFWORD(df, 0)=0x77f3fcff;} #elif DECPMAX==16 #define DFSETNMAX(df) \ {DFWORD(df, 0)=0x77fcff3f; \ DFWORD(df, 1)=0xcff3fcff;} #elif DECPMAX==34 #define DFSETNMAX(df) \ {DFWORD(df, 0)=0x77ffcff3; \ DFWORD(df, 1)=0xfcff3fcf; \ DFWORD(df, 2)=0xf3fcff3f; \ DFWORD(df, 3)=0xcff3fcff;} #endif /* [end of format-dependent macros and constants] */ #endif #else #error decNumberLocal included more than once #endif ================================================ FILE: vendor/decNumber/decPacked.c ================================================ /* ------------------------------------------------------------------ */ /* Packed Decimal conversion module */ /* ------------------------------------------------------------------ */ /* Copyright (c) IBM Corporation, 2000, 2002. All rights reserved. */ /* */ /* This software is made available under the terms of the */ /* ICU License -- ICU 1.8.1 and later. */ /* */ /* The description and User's Guide ("The decNumber C Library") for */ /* this software is called decNumber.pdf. This document is */ /* available, together with arithmetic and format specifications, */ /* testcases, and Web links, on the General Decimal Arithmetic page. */ /* */ /* Please send comments, suggestions, and corrections to the author: */ /* mfc@uk.ibm.com */ /* Mike Cowlishaw, IBM Fellow */ /* IBM UK, PO Box 31, Birmingham Road, Warwick CV34 5JL, UK */ /* ------------------------------------------------------------------ */ /* This module comprises the routines for Packed Decimal format */ /* numbers. Conversions are supplied to and from decNumber, which in */ /* turn supports: */ /* conversions to and from string */ /* arithmetic routines */ /* utilities. */ /* Conversions from decNumber to and from densely packed decimal */ /* formats are provided by the decimal32 through decimal128 modules. */ /* ------------------------------------------------------------------ */ #include // for NULL #include "decNumber.h" // base number library #include "decPacked.h" // packed decimal #include "decNumberLocal.h" // decNumber local types, etc. /* ------------------------------------------------------------------ */ /* decPackedFromNumber -- convert decNumber to BCD Packed Decimal */ /* */ /* bcd is the BCD bytes */ /* length is the length of the BCD array */ /* scale is the scale result */ /* dn is the decNumber */ /* returns bcd, or NULL if error */ /* */ /* The number is converted to a BCD packed decimal byte array, */ /* right aligned in the bcd array, whose length is indicated by the */ /* second parameter. The final 4-bit nibble in the array will be a */ /* sign nibble, C (1100) for + and D (1101) for -. Unused bytes and */ /* nibbles to the left of the number are set to 0. */ /* */ /* scale is set to the scale of the number (this is the exponent, */ /* negated). To force the number to a specified scale, first use the */ /* decNumberRescale routine, which will round and change the exponent */ /* as necessary. */ /* */ /* If there is an error (that is, the decNumber has too many digits */ /* to fit in length bytes, or it is a NaN or Infinity), NULL is */ /* returned and the bcd and scale results are unchanged. Otherwise */ /* bcd is returned. */ /* ------------------------------------------------------------------ */ uByte * decPackedFromNumber(uByte *bcd, Int length, Int *scale, const decNumber *dn) { const Unit *up=dn->lsu; // Unit array pointer uByte obyte, *out; // current output byte, and where it goes Int indigs=dn->digits; // digits processed uInt cut=DECDPUN; // downcounter per Unit uInt u=*up; // work uInt nib; // .. #if DECDPUN<=4 uInt temp; // .. #endif if (dn->digits>length*2-1 // too long .. ||(dn->bits & DECSPECIAL)) return NULL; // .. or special -- hopeless if (dn->bits&DECNEG) obyte=DECPMINUS; // set the sign .. else obyte=DECPPLUS; *scale=-dn->exponent; // .. and scale // loop from lowest (rightmost) byte out=bcd+length-1; // -> final byte for (; out>=bcd; out--) { if (indigs>0) { if (cut==0) { up++; u=*up; cut=DECDPUN; } #if DECDPUN<=4 temp=(u*6554)>>16; // fast /10 nib=u-X10(temp); u=temp; #else nib=u%10; // cannot use *6554 trick :-( u=u/10; #endif obyte|=(nib<<4); indigs--; cut--; } *out=obyte; obyte=0; // assume 0 if (indigs>0) { if (cut==0) { up++; u=*up; cut=DECDPUN; } #if DECDPUN<=4 temp=(u*6554)>>16; // as above obyte=(uByte)(u-X10(temp)); u=temp; #else obyte=(uByte)(u%10); u=u/10; #endif indigs--; cut--; } } // loop return bcd; } // decPackedFromNumber /* ------------------------------------------------------------------ */ /* decPackedToNumber -- convert BCD Packed Decimal to a decNumber */ /* */ /* bcd is the BCD bytes */ /* length is the length of the BCD array */ /* scale is the scale associated with the BCD integer */ /* dn is the decNumber [with space for length*2 digits] */ /* returns dn, or NULL if error */ /* */ /* The BCD packed decimal byte array, together with an associated */ /* scale, is converted to a decNumber. The BCD array is assumed full */ /* of digits, and must be ended by a 4-bit sign nibble in the least */ /* significant four bits of the final byte. */ /* */ /* The scale is used (negated) as the exponent of the decNumber. */ /* Note that zeros may have a sign and/or a scale. */ /* */ /* The decNumber structure is assumed to have sufficient space to */ /* hold the converted number (that is, up to length*2-1 digits), so */ /* no error is possible unless the adjusted exponent is out of range, */ /* no sign nibble was found, or a sign nibble was found before the */ /* final nibble. In these error cases, NULL is returned and the */ /* decNumber will be 0. */ /* ------------------------------------------------------------------ */ decNumber * decPackedToNumber(const uByte *bcd, Int length, const Int *scale, decNumber *dn) { const uByte *last=bcd+length-1; // -> last byte const uByte *first; // -> first non-zero byte uInt nib; // work nibble Unit *up=dn->lsu; // output pointer Int digits; // digits count Int cut=0; // phase of output decNumberZero(dn); // default result last=&bcd[length-1]; nib=*last & 0x0f; // get the sign if (nib==DECPMINUS || nib==DECPMINUSALT) dn->bits=DECNEG; else if (nib<=9) return NULL; // not a sign nibble // skip leading zero bytes [final byte is always non-zero, due to sign] for (first=bcd; *first==0;) first++; digits=(last-first)*2+1; // calculate digits .. if ((*first & 0xf0)==0) digits--; // adjust for leading zero nibble if (digits!=0) dn->digits=digits; // count of actual digits [if 0, // leave as 1] // check the adjusted exponent; note that scale could be unbounded dn->exponent=-*scale; // set the exponent if (*scale>=0) { // usual case if ((dn->digits-*scale-1)<-DECNUMMAXE) { // underflow decNumberZero(dn); return NULL;} } else { // -ve scale; +ve exponent // need to be careful to avoid wrap, here, also BADINT case if ((*scale<-DECNUMMAXE) // overflow even without digits || ((dn->digits-*scale-1)>DECNUMMAXE)) { // overflow decNumberZero(dn); return NULL;} } if (digits==0) return dn; // result was zero // copy the digits to the number's units, starting at the lsu // [unrolled] for (;;) { // forever // left nibble first nib=(unsigned)(*last & 0xf0)>>4; // got a digit, in nib if (nib>9) {decNumberZero(dn); return NULL;} if (cut==0) *up=(Unit)nib; else *up=(Unit)(*up+nib*DECPOWERS[cut]); digits--; if (digits==0) break; // got them all cut++; if (cut==DECDPUN) { up++; cut=0; } last--; // ready for next nib=*last & 0x0f; // get right nibble if (nib>9) {decNumberZero(dn); return NULL;} // got a digit, in nib if (cut==0) *up=(Unit)nib; else *up=(Unit)(*up+nib*DECPOWERS[cut]); digits--; if (digits==0) break; // got them all cut++; if (cut==DECDPUN) { up++; cut=0; } } // forever return dn; } // decPackedToNumber ================================================ FILE: vendor/decNumber/decPacked.h ================================================ /* ------------------------------------------------------------------ */ /* Packed Decimal conversion module header */ /* ------------------------------------------------------------------ */ /* Copyright (c) IBM Corporation, 2000, 2005. All rights reserved. */ /* */ /* This software is made available under the terms of the */ /* ICU License -- ICU 1.8.1 and later. */ /* */ /* The description and User's Guide ("The decNumber C Library") for */ /* this software is called decNumber.pdf. This document is */ /* available, together with arithmetic and format specifications, */ /* testcases, and Web links, on the General Decimal Arithmetic page. */ /* */ /* Please send comments, suggestions, and corrections to the author: */ /* mfc@uk.ibm.com */ /* Mike Cowlishaw, IBM Fellow */ /* IBM UK, PO Box 31, Birmingham Road, Warwick CV34 5JL, UK */ /* ------------------------------------------------------------------ */ #if !defined(DECPACKED) #define DECPACKED #define DECPNAME "decPacked" /* Short name */ #define DECPFULLNAME "Packed Decimal conversions" /* Verbose name */ #define DECPAUTHOR "Mike Cowlishaw" /* Who to blame */ #define DECPACKED_DefP 32 /* default precision */ #ifndef DECNUMDIGITS #define DECNUMDIGITS DECPACKED_DefP /* size if not already defined*/ #endif #include "decNumber.h" /* context and number library */ /* Sign nibble constants */ #if !defined(DECPPLUSALT) #define DECPPLUSALT 0x0A /* alternate plus nibble */ #define DECPMINUSALT 0x0B /* alternate minus nibble */ #define DECPPLUS 0x0C /* preferred plus nibble */ #define DECPMINUS 0x0D /* preferred minus nibble */ #define DECPPLUSALT2 0x0E /* alternate plus nibble */ #define DECPUNSIGNED 0x0F /* alternate plus nibble (unsigned) */ #endif /* ---------------------------------------------------------------- */ /* decPacked public routines */ /* ---------------------------------------------------------------- */ /* Conversions */ uint8_t * decPackedFromNumber(uint8_t *, int32_t, int32_t *, const decNumber *); decNumber * decPackedToNumber(const uint8_t *, int32_t, const int32_t *, decNumber *); #endif ================================================ FILE: vendor/decNumber/decQuad.c ================================================ /* ------------------------------------------------------------------ */ /* decQuad.c -- decQuad operations module */ /* ------------------------------------------------------------------ */ /* Copyright (c) IBM Corporation, 2000, 2010. All rights reserved. */ /* */ /* This software is made available under the terms of the */ /* ICU License -- ICU 1.8.1 and later. */ /* */ /* The description and User's Guide ("The decNumber C Library") for */ /* this software is included in the package as decNumber.pdf. This */ /* document is also available in HTML, together with specifications, */ /* testcases, and Web links, on the General Decimal Arithmetic page. */ /* */ /* Please send comments, suggestions, and corrections to the author: */ /* mfc@uk.ibm.com */ /* Mike Cowlishaw, IBM Fellow */ /* IBM UK, PO Box 31, Birmingham Road, Warwick CV34 5JL, UK */ /* ------------------------------------------------------------------ */ /* This module comprises decQuad operations (including conversions) */ /* ------------------------------------------------------------------ */ /* Constant mappings for shared code */ #define DECPMAX DECQUAD_Pmax #define DECEMIN DECQUAD_Emin #define DECEMAX DECQUAD_Emax #define DECEMAXD DECQUAD_EmaxD #define DECBYTES DECQUAD_Bytes #define DECSTRING DECQUAD_String #define DECECONL DECQUAD_EconL #define DECBIAS DECQUAD_Bias #define DECLETS DECQUAD_Declets #define DECQTINY (-DECQUAD_Bias) /* Type and function mappings for shared code */ #define decFloat decQuad // Type name // Utilities and conversions (binary results, extractors, etc.) #define decFloatFromBCD decQuadFromBCD #define decFloatFromInt32 decQuadFromInt32 #define decFloatFromPacked decQuadFromPacked #define decFloatFromPackedChecked decQuadFromPackedChecked #define decFloatFromString decQuadFromString #define decFloatFromUInt32 decQuadFromUInt32 #define decFloatFromWider decQuadFromWider #define decFloatGetCoefficient decQuadGetCoefficient #define decFloatGetExponent decQuadGetExponent #define decFloatSetCoefficient decQuadSetCoefficient #define decFloatSetExponent decQuadSetExponent #define decFloatShow decQuadShow #define decFloatToBCD decQuadToBCD #define decFloatToEngString decQuadToEngString #define decFloatToInt32 decQuadToInt32 #define decFloatToInt32Exact decQuadToInt32Exact #define decFloatToPacked decQuadToPacked #define decFloatToString decQuadToString #define decFloatToUInt32 decQuadToUInt32 #define decFloatToUInt32Exact decQuadToUInt32Exact #define decFloatToWider decQuadToWider #define decFloatZero decQuadZero // Computational (result is a decFloat) #define decFloatAbs decQuadAbs #define decFloatAdd decQuadAdd #define decFloatAnd decQuadAnd #define decFloatDivide decQuadDivide #define decFloatDivideInteger decQuadDivideInteger #define decFloatFMA decQuadFMA #define decFloatInvert decQuadInvert #define decFloatLogB decQuadLogB #define decFloatMax decQuadMax #define decFloatMaxMag decQuadMaxMag #define decFloatMin decQuadMin #define decFloatMinMag decQuadMinMag #define decFloatMinus decQuadMinus #define decFloatMultiply decQuadMultiply #define decFloatNextMinus decQuadNextMinus #define decFloatNextPlus decQuadNextPlus #define decFloatNextToward decQuadNextToward #define decFloatOr decQuadOr #define decFloatPlus decQuadPlus #define decFloatQuantize decQuadQuantize #define decFloatReduce decQuadReduce #define decFloatRemainder decQuadRemainder #define decFloatRemainderNear decQuadRemainderNear #define decFloatRotate decQuadRotate #define decFloatScaleB decQuadScaleB #define decFloatShift decQuadShift #define decFloatSubtract decQuadSubtract #define decFloatToIntegralValue decQuadToIntegralValue #define decFloatToIntegralExact decQuadToIntegralExact #define decFloatXor decQuadXor // Comparisons #define decFloatCompare decQuadCompare #define decFloatCompareSignal decQuadCompareSignal #define decFloatCompareTotal decQuadCompareTotal #define decFloatCompareTotalMag decQuadCompareTotalMag // Copies #define decFloatCanonical decQuadCanonical #define decFloatCopy decQuadCopy #define decFloatCopyAbs decQuadCopyAbs #define decFloatCopyNegate decQuadCopyNegate #define decFloatCopySign decQuadCopySign // Non-computational #define decFloatClass decQuadClass #define decFloatClassString decQuadClassString #define decFloatDigits decQuadDigits #define decFloatIsCanonical decQuadIsCanonical #define decFloatIsFinite decQuadIsFinite #define decFloatIsInfinite decQuadIsInfinite #define decFloatIsInteger decQuadIsInteger #define decFloatIsLogical decQuadIsLogical #define decFloatIsNaN decQuadIsNaN #define decFloatIsNegative decQuadIsNegative #define decFloatIsNormal decQuadIsNormal #define decFloatIsPositive decQuadIsPositive #define decFloatIsSignaling decQuadIsSignaling #define decFloatIsSignalling decQuadIsSignalling #define decFloatIsSigned decQuadIsSigned #define decFloatIsSubnormal decQuadIsSubnormal #define decFloatIsZero decQuadIsZero #define decFloatRadix decQuadRadix #define decFloatSameQuantum decQuadSameQuantum #define decFloatVersion decQuadVersion /* And now the code itself */ #include "decContext.h" // public includes #include "decQuad.h" // .. #include "decNumberLocal.h" // local includes (need DECPMAX) #include "decCommon.c" // non-arithmetic decFloat routines #include "decBasic.c" // basic formats routines ================================================ FILE: vendor/decNumber/decQuad.h ================================================ /* ------------------------------------------------------------------ */ /* decQuad.h -- Decimal 128-bit format module header */ /* ------------------------------------------------------------------ */ /* Copyright (c) IBM Corporation, 2000, 2010. All rights reserved. */ /* */ /* This software is made available under the terms of the */ /* ICU License -- ICU 1.8.1 and later. */ /* */ /* The description and User's Guide ("The decNumber C Library") for */ /* this software is included in the package as decNumber.pdf. This */ /* document is also available in HTML, together with specifications, */ /* testcases, and Web links, on the General Decimal Arithmetic page. */ /* */ /* Please send comments, suggestions, and corrections to the author: */ /* mfc@uk.ibm.com */ /* Mike Cowlishaw, IBM Fellow */ /* IBM UK, PO Box 31, Birmingham Road, Warwick CV34 5JL, UK */ /* ------------------------------------------------------------------ */ /* This include file is always included by decSingle and decDouble, */ /* and therefore also holds useful constants used by all three. */ #if !defined(DECQUAD) #define DECQUAD #define DECQUADNAME "decimalQuad" /* Short name */ #define DECQUADTITLE "Decimal 128-bit datum" /* Verbose name */ #define DECQUADAUTHOR "Mike Cowlishaw" /* Who to blame */ /* parameters for decQuads */ #define DECQUAD_Bytes 16 /* length */ #define DECQUAD_Pmax 34 /* maximum precision (digits) */ #define DECQUAD_Emin -6143 /* minimum adjusted exponent */ #define DECQUAD_Emax 6144 /* maximum adjusted exponent */ #define DECQUAD_EmaxD 4 /* maximum exponent digits */ #define DECQUAD_Bias 6176 /* bias for the exponent */ #define DECQUAD_String 43 /* maximum string length, +1 */ #define DECQUAD_EconL 12 /* exponent continuation length */ #define DECQUAD_Declets 11 /* count of declets */ /* highest biased exponent (Elimit-1) */ #define DECQUAD_Ehigh (DECQUAD_Emax + DECQUAD_Bias - (DECQUAD_Pmax-1)) /* Required include */ #include "decContext.h" /* The decQuad decimal 128-bit type, accessible by all sizes */ typedef union { uint8_t bytes[DECQUAD_Bytes]; /* fields: 1, 5, 12, 110 bits */ uint16_t shorts[DECQUAD_Bytes/2]; uint32_t words[DECQUAD_Bytes/4]; #if DECUSE64 uint64_t longs[DECQUAD_Bytes/8]; #endif } decQuad; /* ---------------------------------------------------------------- */ /* Shared constants */ /* ---------------------------------------------------------------- */ /* sign and special values [top 32-bits; last two bits are don't-care for Infinity on input, last bit don't-care for NaNs] */ #define DECFLOAT_Sign 0x80000000 /* 1 00000 00 Sign */ #define DECFLOAT_NaN 0x7c000000 /* 0 11111 00 NaN generic */ #define DECFLOAT_qNaN 0x7c000000 /* 0 11111 00 qNaN */ #define DECFLOAT_sNaN 0x7e000000 /* 0 11111 10 sNaN */ #define DECFLOAT_Inf 0x78000000 /* 0 11110 00 Infinity */ #define DECFLOAT_MinSp 0x78000000 /* minimum special value */ /* [specials are all >=MinSp] */ /* Sign nibble constants */ #if !defined(DECPPLUSALT) #define DECPPLUSALT 0x0A /* alternate plus nibble */ #define DECPMINUSALT 0x0B /* alternate minus nibble */ #define DECPPLUS 0x0C /* preferred plus nibble */ #define DECPMINUS 0x0D /* preferred minus nibble */ #define DECPPLUSALT2 0x0E /* alternate plus nibble */ #define DECPUNSIGNED 0x0F /* alternate plus nibble (unsigned) */ #endif /* ---------------------------------------------------------------- */ /* Routines -- implemented as decFloat routines in common files */ /* ---------------------------------------------------------------- */ /* Utilities and conversions, extractors, etc.) */ extern decQuad * decQuadFromBCD(decQuad *, int32_t, const uint8_t *, int32_t); extern decQuad * decQuadFromInt32(decQuad *, int32_t); extern decQuad * decQuadFromPacked(decQuad *, int32_t, const uint8_t *); extern decQuad * decQuadFromPackedChecked(decQuad *, int32_t, const uint8_t *); extern decQuad * decQuadFromString(decQuad *, const char *, decContext *); extern decQuad * decQuadFromUInt32(decQuad *, uint32_t); extern int32_t decQuadGetCoefficient(const decQuad *, uint8_t *); extern int32_t decQuadGetExponent(const decQuad *); extern decQuad * decQuadSetCoefficient(decQuad *, const uint8_t *, int32_t); extern decQuad * decQuadSetExponent(decQuad *, decContext *, int32_t); extern void decQuadShow(const decQuad *, const char *); extern int32_t decQuadToBCD(const decQuad *, int32_t *, uint8_t *); extern char * decQuadToEngString(const decQuad *, char *); extern int32_t decQuadToInt32(const decQuad *, decContext *, enum rounding); extern int32_t decQuadToInt32Exact(const decQuad *, decContext *, enum rounding); extern int32_t decQuadToPacked(const decQuad *, int32_t *, uint8_t *); extern char * decQuadToString(const decQuad *, char *); extern uint32_t decQuadToUInt32(const decQuad *, decContext *, enum rounding); extern uint32_t decQuadToUInt32Exact(const decQuad *, decContext *, enum rounding); extern decQuad * decQuadZero(decQuad *); /* Computational (result is a decQuad) */ extern decQuad * decQuadAbs(decQuad *, const decQuad *, decContext *); extern decQuad * decQuadAdd(decQuad *, const decQuad *, const decQuad *, decContext *); extern decQuad * decQuadAnd(decQuad *, const decQuad *, const decQuad *, decContext *); extern decQuad * decQuadDivide(decQuad *, const decQuad *, const decQuad *, decContext *); extern decQuad * decQuadDivideInteger(decQuad *, const decQuad *, const decQuad *, decContext *); extern decQuad * decQuadFMA(decQuad *, const decQuad *, const decQuad *, const decQuad *, decContext *); extern decQuad * decQuadInvert(decQuad *, const decQuad *, decContext *); extern decQuad * decQuadLogB(decQuad *, const decQuad *, decContext *); extern decQuad * decQuadMax(decQuad *, const decQuad *, const decQuad *, decContext *); extern decQuad * decQuadMaxMag(decQuad *, const decQuad *, const decQuad *, decContext *); extern decQuad * decQuadMin(decQuad *, const decQuad *, const decQuad *, decContext *); extern decQuad * decQuadMinMag(decQuad *, const decQuad *, const decQuad *, decContext *); extern decQuad * decQuadMinus(decQuad *, const decQuad *, decContext *); extern decQuad * decQuadMultiply(decQuad *, const decQuad *, const decQuad *, decContext *); extern decQuad * decQuadNextMinus(decQuad *, const decQuad *, decContext *); extern decQuad * decQuadNextPlus(decQuad *, const decQuad *, decContext *); extern decQuad * decQuadNextToward(decQuad *, const decQuad *, const decQuad *, decContext *); extern decQuad * decQuadOr(decQuad *, const decQuad *, const decQuad *, decContext *); extern decQuad * decQuadPlus(decQuad *, const decQuad *, decContext *); extern decQuad * decQuadQuantize(decQuad *, const decQuad *, const decQuad *, decContext *); extern decQuad * decQuadReduce(decQuad *, const decQuad *, decContext *); extern decQuad * decQuadRemainder(decQuad *, const decQuad *, const decQuad *, decContext *); extern decQuad * decQuadRemainderNear(decQuad *, const decQuad *, const decQuad *, decContext *); extern decQuad * decQuadRotate(decQuad *, const decQuad *, const decQuad *, decContext *); extern decQuad * decQuadScaleB(decQuad *, const decQuad *, const decQuad *, decContext *); extern decQuad * decQuadShift(decQuad *, const decQuad *, const decQuad *, decContext *); extern decQuad * decQuadSubtract(decQuad *, const decQuad *, const decQuad *, decContext *); extern decQuad * decQuadToIntegralValue(decQuad *, const decQuad *, decContext *, enum rounding); extern decQuad * decQuadToIntegralExact(decQuad *, const decQuad *, decContext *); extern decQuad * decQuadXor(decQuad *, const decQuad *, const decQuad *, decContext *); /* Comparisons */ extern decQuad * decQuadCompare(decQuad *, const decQuad *, const decQuad *, decContext *); extern decQuad * decQuadCompareSignal(decQuad *, const decQuad *, const decQuad *, decContext *); extern decQuad * decQuadCompareTotal(decQuad *, const decQuad *, const decQuad *); extern decQuad * decQuadCompareTotalMag(decQuad *, const decQuad *, const decQuad *); /* Copies */ extern decQuad * decQuadCanonical(decQuad *, const decQuad *); extern decQuad * decQuadCopy(decQuad *, const decQuad *); extern decQuad * decQuadCopyAbs(decQuad *, const decQuad *); extern decQuad * decQuadCopyNegate(decQuad *, const decQuad *); extern decQuad * decQuadCopySign(decQuad *, const decQuad *, const decQuad *); /* Non-computational */ extern enum decClass decQuadClass(const decQuad *); extern const char * decQuadClassString(const decQuad *); extern uint32_t decQuadDigits(const decQuad *); extern uint32_t decQuadIsCanonical(const decQuad *); extern uint32_t decQuadIsFinite(const decQuad *); extern uint32_t decQuadIsInteger(const decQuad *); extern uint32_t decQuadIsLogical(const decQuad *); extern uint32_t decQuadIsInfinite(const decQuad *); extern uint32_t decQuadIsNaN(const decQuad *); extern uint32_t decQuadIsNegative(const decQuad *); extern uint32_t decQuadIsNormal(const decQuad *); extern uint32_t decQuadIsPositive(const decQuad *); extern uint32_t decQuadIsSignaling(const decQuad *); extern uint32_t decQuadIsSignalling(const decQuad *); extern uint32_t decQuadIsSigned(const decQuad *); extern uint32_t decQuadIsSubnormal(const decQuad *); extern uint32_t decQuadIsZero(const decQuad *); extern uint32_t decQuadRadix(const decQuad *); extern uint32_t decQuadSameQuantum(const decQuad *, const decQuad *); extern const char * decQuadVersion(void); /* decNumber conversions; these are implemented as macros so as not */ /* to force a dependency on decimal128 and decNumber in decQuad. */ /* decQuadFromNumber returns a decimal128 * to avoid warnings. */ #define decQuadToNumber(dq, dn) decimal128ToNumber((decimal128 *)(dq), dn) #define decQuadFromNumber(dq, dn, set) decimal128FromNumber((decimal128 *)(dq), dn, set) #endif ================================================ FILE: vendor/decNumber/decSingle.c ================================================ /* ------------------------------------------------------------------ */ /* decSingle.c -- decSingle operations module */ /* ------------------------------------------------------------------ */ /* Copyright (c) IBM Corporation, 2000, 2008. All rights reserved. */ /* */ /* This software is made available under the terms of the */ /* ICU License -- ICU 1.8.1 and later. */ /* */ /* The description and User's Guide ("The decNumber C Library") for */ /* this software is included in the package as decNumber.pdf. This */ /* document is also available in HTML, together with specifications, */ /* testcases, and Web links, on the General Decimal Arithmetic page. */ /* */ /* Please send comments, suggestions, and corrections to the author: */ /* mfc@uk.ibm.com */ /* Mike Cowlishaw, IBM Fellow */ /* IBM UK, PO Box 31, Birmingham Road, Warwick CV34 5JL, UK */ /* ------------------------------------------------------------------ */ /* This module comprises decSingle operations (including conversions) */ /* ------------------------------------------------------------------ */ #include "decContext.h" // public includes #include "decSingle.h" // public includes /* Constant mappings for shared code */ #define DECPMAX DECSINGLE_Pmax #define DECEMIN DECSINGLE_Emin #define DECEMAX DECSINGLE_Emax #define DECEMAXD DECSINGLE_EmaxD #define DECBYTES DECSINGLE_Bytes #define DECSTRING DECSINGLE_String #define DECECONL DECSINGLE_EconL #define DECBIAS DECSINGLE_Bias #define DECLETS DECSINGLE_Declets #define DECQTINY (-DECSINGLE_Bias) // parameters of next-wider format #define DECWBYTES DECDOUBLE_Bytes #define DECWPMAX DECDOUBLE_Pmax #define DECWECONL DECDOUBLE_EconL #define DECWBIAS DECDOUBLE_Bias /* Type and function mappings for shared code */ #define decFloat decSingle // Type name #define decFloatWider decDouble // Type name // Utility (binary results, extractors, etc.) #define decFloatFromBCD decSingleFromBCD #define decFloatFromPacked decSingleFromPacked #define decFloatFromPackedChecked decSingleFromPackedChecked #define decFloatFromString decSingleFromString #define decFloatFromWider decSingleFromWider #define decFloatGetCoefficient decSingleGetCoefficient #define decFloatGetExponent decSingleGetExponent #define decFloatSetCoefficient decSingleSetCoefficient #define decFloatSetExponent decSingleSetExponent #define decFloatShow decSingleShow #define decFloatToBCD decSingleToBCD #define decFloatToEngString decSingleToEngString #define decFloatToPacked decSingleToPacked #define decFloatToString decSingleToString #define decFloatToWider decSingleToWider #define decFloatZero decSingleZero // Non-computational #define decFloatRadix decSingleRadix #define decFloatVersion decSingleVersion #include "decNumberLocal.h" // local includes (need DECPMAX) #include "decCommon.c" // non-basic decFloat routines // [Do not include decBasic.c for decimal32] ================================================ FILE: vendor/decNumber/decSingle.h ================================================ /* ------------------------------------------------------------------ */ /* decSingle.h -- Decimal 32-bit format module header */ /* ------------------------------------------------------------------ */ /* Copyright (c) IBM Corporation, 2000, 2008. All rights reserved. */ /* */ /* This software is made available under the terms of the */ /* ICU License -- ICU 1.8.1 and later. */ /* */ /* The description and User's Guide ("The decNumber C Library") for */ /* this software is included in the package as decNumber.pdf. This */ /* document is also available in HTML, together with specifications, */ /* testcases, and Web links, on the General Decimal Arithmetic page. */ /* */ /* Please send comments, suggestions, and corrections to the author: */ /* mfc@uk.ibm.com */ /* Mike Cowlishaw, IBM Fellow */ /* IBM UK, PO Box 31, Birmingham Road, Warwick CV34 5JL, UK */ /* ------------------------------------------------------------------ */ #if !defined(DECSINGLE) #define DECSINGLE #define DECSINGLENAME "decSingle" /* Short name */ #define DECSINGLETITLE "Decimal 32-bit datum" /* Verbose name */ #define DECSINGLEAUTHOR "Mike Cowlishaw" /* Who to blame */ /* parameters for decSingles */ #define DECSINGLE_Bytes 4 /* length */ #define DECSINGLE_Pmax 7 /* maximum precision (digits) */ #define DECSINGLE_Emin -95 /* minimum adjusted exponent */ #define DECSINGLE_Emax 96 /* maximum adjusted exponent */ #define DECSINGLE_EmaxD 3 /* maximum exponent digits */ #define DECSINGLE_Bias 101 /* bias for the exponent */ #define DECSINGLE_String 16 /* maximum string length, +1 */ #define DECSINGLE_EconL 6 /* exponent continuation length */ #define DECSINGLE_Declets 2 /* count of declets */ /* highest biased exponent (Elimit-1) */ #define DECSINGLE_Ehigh (DECSINGLE_Emax + DECSINGLE_Bias - (DECSINGLE_Pmax-1)) /* Required includes */ #include "decContext.h" #include "decQuad.h" #include "decDouble.h" /* The decSingle decimal 32-bit type, accessible by all sizes */ typedef union { uint8_t bytes[DECSINGLE_Bytes]; /* fields: 1, 5, 6, 20 bits */ uint16_t shorts[DECSINGLE_Bytes/2]; uint32_t words[DECSINGLE_Bytes/4]; } decSingle; /* ---------------------------------------------------------------- */ /* Routines -- implemented as decFloat routines in common files */ /* ---------------------------------------------------------------- */ /* Utilities (binary argument(s) or result, extractors, etc.) */ extern decSingle * decSingleFromBCD(decSingle *, int32_t, const uint8_t *, int32_t); extern decSingle * decSingleFromPacked(decSingle *, int32_t, const uint8_t *); extern decSingle * decSingleFromPackedChecked(decSingle *, int32_t, const uint8_t *); extern decSingle * decSingleFromString(decSingle *, const char *, decContext *); extern decSingle * decSingleFromWider(decSingle *, const decDouble *, decContext *); extern int32_t decSingleGetCoefficient(const decSingle *, uint8_t *); extern int32_t decSingleGetExponent(const decSingle *); extern decSingle * decSingleSetCoefficient(decSingle *, const uint8_t *, int32_t); extern decSingle * decSingleSetExponent(decSingle *, decContext *, int32_t); extern void decSingleShow(const decSingle *, const char *); extern int32_t decSingleToBCD(const decSingle *, int32_t *, uint8_t *); extern char * decSingleToEngString(const decSingle *, char *); extern int32_t decSingleToPacked(const decSingle *, int32_t *, uint8_t *); extern char * decSingleToString(const decSingle *, char *); extern decDouble * decSingleToWider(const decSingle *, decDouble *); extern decSingle * decSingleZero(decSingle *); /* (No Arithmetic routines for decSingle) */ /* Non-computational */ extern uint32_t decSingleRadix(const decSingle *); extern const char * decSingleVersion(void); /* decNumber conversions; these are implemented as macros so as not */ /* to force a dependency on decimal32 and decNumber in decSingle. */ /* decSingleFromNumber returns a decimal32 * to avoid warnings. */ #define decSingleToNumber(dq, dn) decimal32ToNumber((decimal32 *)(dq), dn) #define decSingleFromNumber(dq, dn, set) decimal32FromNumber((decimal32 *)(dq), dn, set) #endif ================================================ FILE: vendor/decNumber/decimal128.c ================================================ /* ------------------------------------------------------------------ */ /* Decimal 128-bit format module */ /* ------------------------------------------------------------------ */ /* Copyright (c) IBM Corporation, 2000, 2008. All rights reserved. */ /* */ /* This software is made available under the terms of the */ /* ICU License -- ICU 1.8.1 and later. */ /* */ /* The description and User's Guide ("The decNumber C Library") for */ /* this software is called decNumber.pdf. This document is */ /* available, together with arithmetic and format specifications, */ /* testcases, and Web links, on the General Decimal Arithmetic page. */ /* */ /* Please send comments, suggestions, and corrections to the author: */ /* mfc@uk.ibm.com */ /* Mike Cowlishaw, IBM Fellow */ /* IBM UK, PO Box 31, Birmingham Road, Warwick CV34 5JL, UK */ /* ------------------------------------------------------------------ */ /* This module comprises the routines for decimal128 format numbers. */ /* Conversions are supplied to and from decNumber and String. */ /* */ /* This is used when decNumber provides operations, either for all */ /* operations or as a proxy between decNumber and decSingle. */ /* */ /* Error handling is the same as decNumber (qv.). */ /* ------------------------------------------------------------------ */ #include // [for memset/memcpy] #include // [for printf] #define DECNUMDIGITS 34 // make decNumbers with space for 34 #include "decNumber.h" // base number library #include "decNumberLocal.h" // decNumber local types, etc. #include "decimal128.h" // our primary include /* Utility routines and tables [in decimal64.c] */ // DPD2BIN and the reverse are renamed to prevent link-time conflict // if decQuad is also built in the same executable #define DPD2BIN DPD2BINx #define BIN2DPD BIN2DPDx extern const uInt COMBEXP[32], COMBMSD[32]; extern const uShort DPD2BIN[1024]; extern const uShort BIN2DPD[1000]; // [not used] extern const uByte BIN2CHAR[4001]; extern void decDigitsFromDPD(decNumber *, const uInt *, Int); extern void decDigitsToDPD(const decNumber *, uInt *, Int); #if DECTRACE || DECCHECK void decimal128Show(const decimal128 *); // for debug extern void decNumberShow(const decNumber *); // .. #endif /* Useful macro */ // Clear a structure (e.g., a decNumber) #define DEC_clear(d) memset(d, 0, sizeof(*d)) /* ------------------------------------------------------------------ */ /* decimal128FromNumber -- convert decNumber to decimal128 */ /* */ /* ds is the target decimal128 */ /* dn is the source number (assumed valid) */ /* set is the context, used only for reporting errors */ /* */ /* The set argument is used only for status reporting and for the */ /* rounding mode (used if the coefficient is more than DECIMAL128_Pmax*/ /* digits or an overflow is detected). If the exponent is out of the */ /* valid range then Overflow or Underflow will be raised. */ /* After Underflow a subnormal result is possible. */ /* */ /* DEC_Clamped is set if the number has to be 'folded down' to fit, */ /* by reducing its exponent and multiplying the coefficient by a */ /* power of ten, or if the exponent on a zero had to be clamped. */ /* ------------------------------------------------------------------ */ decimal128 * decimal128FromNumber(decimal128 *d128, const decNumber *dn, decContext *set) { uInt status=0; // status accumulator Int ae; // adjusted exponent decNumber dw; // work decContext dc; // .. uInt comb, exp; // .. uInt uiwork; // for macros uInt targar[4]={0,0,0,0}; // target 128-bit #define targhi targar[3] // name the word with the sign #define targmh targar[2] // name the words #define targml targar[1] // .. #define targlo targar[0] // .. // If the number has too many digits, or the exponent could be // out of range then reduce the number under the appropriate // constraints. This could push the number to Infinity or zero, // so this check and rounding must be done before generating the // decimal128] ae=dn->exponent+dn->digits-1; // [0 if special] if (dn->digits>DECIMAL128_Pmax // too many digits || ae>DECIMAL128_Emax // likely overflow || aeround; // use supplied rounding decNumberPlus(&dw, dn, &dc); // (round and check) // [this changes -0 to 0, so enforce the sign...] dw.bits|=dn->bits&DECNEG; status=dc.status; // save status dn=&dw; // use the work number } // maybe out of range if (dn->bits&DECSPECIAL) { // a special value if (dn->bits&DECINF) targhi=DECIMAL_Inf<<24; else { // sNaN or qNaN if ((*dn->lsu!=0 || dn->digits>1) // non-zero coefficient && (dn->digitsbits&DECNAN) targhi|=DECIMAL_NaN<<24; else targhi|=DECIMAL_sNaN<<24; } // a NaN } // special else { // is finite if (decNumberIsZero(dn)) { // is a zero // set and clamp exponent if (dn->exponent<-DECIMAL128_Bias) { exp=0; // low clamp status|=DEC_Clamped; } else { exp=dn->exponent+DECIMAL128_Bias; // bias exponent if (exp>DECIMAL128_Ehigh) { // top clamp exp=DECIMAL128_Ehigh; status|=DEC_Clamped; } } comb=(exp>>9) & 0x18; // msd=0, exp top 2 bits .. } else { // non-zero finite number uInt msd; // work Int pad=0; // coefficient pad digits // the dn is known to fit, but it may need to be padded exp=(uInt)(dn->exponent+DECIMAL128_Bias); // bias exponent if (exp>DECIMAL128_Ehigh) { // fold-down case pad=exp-DECIMAL128_Ehigh; exp=DECIMAL128_Ehigh; // [to maximum] status|=DEC_Clamped; } // [fastpath for common case is not a win, here] decDigitsToDPD(dn, targar, pad); // save and clear the top digit msd=targhi>>14; targhi&=0x00003fff; // create the combination field if (msd>=8) comb=0x18 | ((exp>>11) & 0x06) | (msd & 0x01); else comb=((exp>>9) & 0x18) | msd; } targhi|=comb<<26; // add combination field .. targhi|=(exp&0xfff)<<14; // .. and exponent continuation } // finite if (dn->bits&DECNEG) targhi|=0x80000000; // add sign bit // now write to storage; this is endian if (DECLITEND) { // lo -> hi UBFROMUI(d128->bytes, targlo); UBFROMUI(d128->bytes+4, targml); UBFROMUI(d128->bytes+8, targmh); UBFROMUI(d128->bytes+12, targhi); } else { // hi -> lo UBFROMUI(d128->bytes, targhi); UBFROMUI(d128->bytes+4, targmh); UBFROMUI(d128->bytes+8, targml); UBFROMUI(d128->bytes+12, targlo); } if (status!=0) decContextSetStatus(set, status); // pass on status // decimal128Show(d128); return d128; } // decimal128FromNumber /* ------------------------------------------------------------------ */ /* decimal128ToNumber -- convert decimal128 to decNumber */ /* d128 is the source decimal128 */ /* dn is the target number, with appropriate space */ /* No error is possible. */ /* ------------------------------------------------------------------ */ decNumber * decimal128ToNumber(const decimal128 *d128, decNumber *dn) { uInt msd; // coefficient MSD uInt exp; // exponent top two bits uInt comb; // combination field Int need; // work uInt uiwork; // for macros uInt sourar[4]; // source 128-bit #define sourhi sourar[3] // name the word with the sign #define sourmh sourar[2] // and the mid-high word #define sourml sourar[1] // and the mod-low word #define sourlo sourar[0] // and the lowest word // load source from storage; this is endian if (DECLITEND) { sourlo=UBTOUI(d128->bytes ); // directly load the low int sourml=UBTOUI(d128->bytes+4 ); // then the mid-low sourmh=UBTOUI(d128->bytes+8 ); // then the mid-high sourhi=UBTOUI(d128->bytes+12); // then the high int } else { sourhi=UBTOUI(d128->bytes ); // directly load the high int sourmh=UBTOUI(d128->bytes+4 ); // then the mid-high sourml=UBTOUI(d128->bytes+8 ); // then the mid-low sourlo=UBTOUI(d128->bytes+12); // then the low int } comb=(sourhi>>26)&0x1f; // combination field decNumberZero(dn); // clean number if (sourhi&0x80000000) dn->bits=DECNEG; // set sign if negative msd=COMBMSD[comb]; // decode the combination field exp=COMBEXP[comb]; // .. if (exp==3) { // is a special if (msd==0) { dn->bits|=DECINF; return dn; // no coefficient needed } else if (sourhi&0x02000000) dn->bits|=DECSNAN; else dn->bits|=DECNAN; msd=0; // no top digit } else { // is a finite number dn->exponent=(exp<<12)+((sourhi>>14)&0xfff)-DECIMAL128_Bias; // unbiased } // get the coefficient sourhi&=0x00003fff; // clean coefficient continuation if (msd) { // non-zero msd sourhi|=msd<<14; // prefix to coefficient need=12; // process 12 declets } else { // msd=0 if (sourhi) need=11; // declets to process else if (sourmh) need=10; else if (sourml) need=7; else if (sourlo) need=4; else return dn; // easy: coefficient is 0 } //msd=0 decDigitsFromDPD(dn, sourar, need); // process declets // decNumberShow(dn); return dn; } // decimal128ToNumber /* ------------------------------------------------------------------ */ /* to-scientific-string -- conversion to numeric string */ /* to-engineering-string -- conversion to numeric string */ /* */ /* decimal128ToString(d128, string); */ /* decimal128ToEngString(d128, string); */ /* */ /* d128 is the decimal128 format number to convert */ /* string is the string where the result will be laid out */ /* */ /* string must be at least 24 characters */ /* */ /* No error is possible, and no status can be set. */ /* ------------------------------------------------------------------ */ char * decimal128ToEngString(const decimal128 *d128, char *string){ decNumber dn; // work decimal128ToNumber(d128, &dn); decNumberToEngString(&dn, string); return string; } // decimal128ToEngString char * decimal128ToString(const decimal128 *d128, char *string){ uInt msd; // coefficient MSD Int exp; // exponent top two bits or full uInt comb; // combination field char *cstart; // coefficient start char *c; // output pointer in string const uByte *u; // work char *s, *t; // .. (source, target) Int dpd; // .. Int pre, e; // .. uInt uiwork; // for macros uInt sourar[4]; // source 128-bit #define sourhi sourar[3] // name the word with the sign #define sourmh sourar[2] // and the mid-high word #define sourml sourar[1] // and the mod-low word #define sourlo sourar[0] // and the lowest word // load source from storage; this is endian if (DECLITEND) { sourlo=UBTOUI(d128->bytes ); // directly load the low int sourml=UBTOUI(d128->bytes+4 ); // then the mid-low sourmh=UBTOUI(d128->bytes+8 ); // then the mid-high sourhi=UBTOUI(d128->bytes+12); // then the high int } else { sourhi=UBTOUI(d128->bytes ); // directly load the high int sourmh=UBTOUI(d128->bytes+4 ); // then the mid-high sourml=UBTOUI(d128->bytes+8 ); // then the mid-low sourlo=UBTOUI(d128->bytes+12); // then the low int } c=string; // where result will go if (((Int)sourhi)<0) *c++='-'; // handle sign comb=(sourhi>>26)&0x1f; // combination field msd=COMBMSD[comb]; // decode the combination field exp=COMBEXP[comb]; // .. if (exp==3) { if (msd==0) { // infinity strcpy(c, "Inf"); strcpy(c+3, "inity"); return string; // easy } if (sourhi&0x02000000) *c++='s'; // sNaN strcpy(c, "NaN"); // complete word c+=3; // step past if (sourlo==0 && sourml==0 && sourmh==0 && (sourhi&0x0003ffff)==0) return string; // zero payload // otherwise drop through to add integer; set correct exp exp=0; msd=0; // setup for following code } else exp=(exp<<12)+((sourhi>>14)&0xfff)-DECIMAL128_Bias; // unbiased // convert 34 digits of significand to characters cstart=c; // save start of coefficient if (msd) *c++='0'+(char)msd; // non-zero most significant digit // Now decode the declets. After extracting each one, it is // decoded to binary and then to a 4-char sequence by table lookup; // the 4-chars are a 1-char length (significant digits, except 000 // has length 0). This allows us to left-align the first declet // with non-zero content, then remaining ones are full 3-char // length. We use fixed-length memcpys because variable-length // causes a subroutine call in GCC. (These are length 4 for speed // and are safe because the array has an extra terminator byte.) #define dpd2char u=&BIN2CHAR[DPD2BIN[dpd]*4]; \ if (c!=cstart) {memcpy(c, u+1, 4); c+=3;} \ else if (*u) {memcpy(c, u+4-*u, 4); c+=*u;} dpd=(sourhi>>4)&0x3ff; // declet 1 dpd2char; dpd=((sourhi&0xf)<<6) | (sourmh>>26); // declet 2 dpd2char; dpd=(sourmh>>16)&0x3ff; // declet 3 dpd2char; dpd=(sourmh>>6)&0x3ff; // declet 4 dpd2char; dpd=((sourmh&0x3f)<<4) | (sourml>>28); // declet 5 dpd2char; dpd=(sourml>>18)&0x3ff; // declet 6 dpd2char; dpd=(sourml>>8)&0x3ff; // declet 7 dpd2char; dpd=((sourml&0xff)<<2) | (sourlo>>30); // declet 8 dpd2char; dpd=(sourlo>>20)&0x3ff; // declet 9 dpd2char; dpd=(sourlo>>10)&0x3ff; // declet 10 dpd2char; dpd=(sourlo)&0x3ff; // declet 11 dpd2char; if (c==cstart) *c++='0'; // all zeros -- make 0 if (exp==0) { // integer or NaN case -- easy *c='\0'; // terminate return string; } /* non-0 exponent */ e=0; // assume no E pre=c-cstart+exp; // [here, pre-exp is the digits count (==1 for zero)] if (exp>0 || pre<-5) { // need exponential form e=pre-1; // calculate E value pre=1; // assume one digit before '.' } // exponential form /* modify the coefficient, adding 0s, '.', and E+nn as needed */ s=c-1; // source (LSD) if (pre>0) { // ddd.ddd (plain), perhaps with E char *dotat=cstart+pre; if (dotat=dotat; s--, t--) *t=*s; // open the gap; leave t at gap *t='.'; // insert the dot c++; // length increased by one } // finally add the E-part, if needed; it will never be 0, and has // a maximum length of 4 digits if (e!=0) { *c++='E'; // starts with E *c++='+'; // assume positive if (e<0) { *(c-1)='-'; // oops, need '-' e=-e; // uInt, please } if (e<1000) { // 3 (or fewer) digits case u=&BIN2CHAR[e*4]; // -> length byte memcpy(c, u+4-*u, 4); // copy fixed 4 characters [is safe] c+=*u; // bump pointer appropriately } else { // 4-digits Int thou=((e>>3)*1049)>>17; // e/1000 Int rem=e-(1000*thou); // e%1000 *c++='0'+(char)thou; u=&BIN2CHAR[rem*4]; // -> length byte memcpy(c, u+1, 4); // copy fixed 3+1 characters [is safe] c+=3; // bump pointer, always 3 digits } } *c='\0'; // add terminator //printf("res %s\n", string); return string; } // pre>0 /* -5<=pre<=0: here for plain 0.ddd or 0.000ddd forms (can never have E) */ t=c+1-pre; *(t+1)='\0'; // can add terminator now for (; s>=cstart; s--, t--) *t=*s; // shift whole coefficient right c=cstart; *c++='0'; // always starts with 0. *c++='.'; for (; pre<0; pre++) *c++='0'; // add any 0's after '.' //printf("res %s\n", string); return string; } // decimal128ToString /* ------------------------------------------------------------------ */ /* to-number -- conversion from numeric string */ /* */ /* decimal128FromString(result, string, set); */ /* */ /* result is the decimal128 format number which gets the result of */ /* the conversion */ /* *string is the character string which should contain a valid */ /* number (which may be a special value) */ /* set is the context */ /* */ /* The context is supplied to this routine is used for error handling */ /* (setting of status and traps) and for the rounding mode, only. */ /* If an error occurs, the result will be a valid decimal128 NaN. */ /* ------------------------------------------------------------------ */ decimal128 * decimal128FromString(decimal128 *result, const char *string, decContext *set) { decContext dc; // work decNumber dn; // .. decContextDefault(&dc, DEC_INIT_DECIMAL128); // no traps, please dc.round=set->round; // use supplied rounding decNumberFromString(&dn, string, &dc); // will round if needed decimal128FromNumber(result, &dn, &dc); if (dc.status!=0) { // something happened decContextSetStatus(set, dc.status); // .. pass it on } return result; } // decimal128FromString /* ------------------------------------------------------------------ */ /* decimal128IsCanonical -- test whether encoding is canonical */ /* d128 is the source decimal128 */ /* returns 1 if the encoding of d128 is canonical, 0 otherwise */ /* No error is possible. */ /* ------------------------------------------------------------------ */ uInt decimal128IsCanonical(const decimal128 *d128) { decNumber dn; // work decimal128 canon; // .. decContext dc; // .. decContextDefault(&dc, DEC_INIT_DECIMAL128); decimal128ToNumber(d128, &dn); decimal128FromNumber(&canon, &dn, &dc);// canon will now be canonical return memcmp(d128, &canon, DECIMAL128_Bytes)==0; } // decimal128IsCanonical /* ------------------------------------------------------------------ */ /* decimal128Canonical -- copy an encoding, ensuring it is canonical */ /* d128 is the source decimal128 */ /* result is the target (may be the same decimal128) */ /* returns result */ /* No error is possible. */ /* ------------------------------------------------------------------ */ decimal128 * decimal128Canonical(decimal128 *result, const decimal128 *d128) { decNumber dn; // work decContext dc; // .. decContextDefault(&dc, DEC_INIT_DECIMAL128); decimal128ToNumber(d128, &dn); decimal128FromNumber(result, &dn, &dc);// result will now be canonical return result; } // decimal128Canonical #if DECTRACE || DECCHECK /* Macros for accessing decimal128 fields. These assume the argument is a reference (pointer) to the decimal128 structure, and the decimal128 is in network byte order (big-endian) */ // Get sign #define decimal128Sign(d) ((unsigned)(d)->bytes[0]>>7) // Get combination field #define decimal128Comb(d) (((d)->bytes[0] & 0x7c)>>2) // Get exponent continuation [does not remove bias] #define decimal128ExpCon(d) ((((d)->bytes[0] & 0x03)<<10) \ | ((unsigned)(d)->bytes[1]<<2) \ | ((unsigned)(d)->bytes[2]>>6)) // Set sign [this assumes sign previously 0] #define decimal128SetSign(d, b) { \ (d)->bytes[0]|=((unsigned)(b)<<7);} // Set exponent continuation [does not apply bias] // This assumes range has been checked and exponent previously 0; // type of exponent must be unsigned #define decimal128SetExpCon(d, e) { \ (d)->bytes[0]|=(uByte)((e)>>10); \ (d)->bytes[1] =(uByte)(((e)&0x3fc)>>2); \ (d)->bytes[2]|=(uByte)(((e)&0x03)<<6);} /* ------------------------------------------------------------------ */ /* decimal128Show -- display a decimal128 in hexadecimal [debug aid] */ /* d128 -- the number to show */ /* ------------------------------------------------------------------ */ // Also shows sign/cob/expconfields extracted void decimal128Show(const decimal128 *d128) { char buf[DECIMAL128_Bytes*2+1]; Int i, j=0; if (DECLITEND) { for (i=0; ibytes[15-i]); } printf(" D128> %s [S:%d Cb:%02x Ec:%02x] LittleEndian\n", buf, d128->bytes[15]>>7, (d128->bytes[15]>>2)&0x1f, ((d128->bytes[15]&0x3)<<10)|(d128->bytes[14]<<2)| (d128->bytes[13]>>6)); } else { for (i=0; ibytes[i]); } printf(" D128> %s [S:%d Cb:%02x Ec:%02x] BigEndian\n", buf, decimal128Sign(d128), decimal128Comb(d128), decimal128ExpCon(d128)); } } // decimal128Show #endif ================================================ FILE: vendor/decNumber/decimal128.h ================================================ /* ------------------------------------------------------------------ */ /* Decimal 128-bit format module header */ /* ------------------------------------------------------------------ */ /* Copyright (c) IBM Corporation, 2000, 2005. All rights reserved. */ /* */ /* This software is made available under the terms of the */ /* ICU License -- ICU 1.8.1 and later. */ /* */ /* The description and User's Guide ("The decNumber C Library") for */ /* this software is called decNumber.pdf. This document is */ /* available, together with arithmetic and format specifications, */ /* testcases, and Web links, on the General Decimal Arithmetic page. */ /* */ /* Please send comments, suggestions, and corrections to the author: */ /* mfc@uk.ibm.com */ /* Mike Cowlishaw, IBM Fellow */ /* IBM UK, PO Box 31, Birmingham Road, Warwick CV34 5JL, UK */ /* ------------------------------------------------------------------ */ #if !defined(DECIMAL128) #define DECIMAL128 #define DEC128NAME "decimal128" /* Short name */ #define DEC128FULLNAME "Decimal 128-bit Number" /* Verbose name */ #define DEC128AUTHOR "Mike Cowlishaw" /* Who to blame */ /* parameters for decimal128s */ #define DECIMAL128_Bytes 16 /* length */ #define DECIMAL128_Pmax 34 /* maximum precision (digits) */ #define DECIMAL128_Emax 6144 /* maximum adjusted exponent */ #define DECIMAL128_Emin -6143 /* minimum adjusted exponent */ #define DECIMAL128_Bias 6176 /* bias for the exponent */ #define DECIMAL128_String 43 /* maximum string length, +1 */ #define DECIMAL128_EconL 12 /* exp. continuation length */ /* highest biased exponent (Elimit-1) */ #define DECIMAL128_Ehigh (DECIMAL128_Emax+DECIMAL128_Bias-DECIMAL128_Pmax+1) /* check enough digits, if pre-defined */ #if defined(DECNUMDIGITS) #if (DECNUMDIGITS=34 for safe use #endif #endif #ifndef DECNUMDIGITS #define DECNUMDIGITS DECIMAL128_Pmax /* size if not already defined*/ #endif #ifndef DECNUMBER #include "decNumber.h" /* context and number library */ #endif /* Decimal 128-bit type, accessible by bytes */ typedef struct { uint8_t bytes[DECIMAL128_Bytes]; /* decimal128: 1, 5, 12, 110 bits*/ } decimal128; /* special values [top byte excluding sign bit; last two bits are */ /* don't-care for Infinity on input, last bit don't-care for NaN] */ #if !defined(DECIMAL_NaN) #define DECIMAL_NaN 0x7c /* 0 11111 00 NaN */ #define DECIMAL_sNaN 0x7e /* 0 11111 10 sNaN */ #define DECIMAL_Inf 0x78 /* 0 11110 00 Infinity */ #endif /* ---------------------------------------------------------------- */ /* Routines */ /* ---------------------------------------------------------------- */ /* String conversions */ decimal128 * decimal128FromString(decimal128 *, const char *, decContext *); char * decimal128ToString(const decimal128 *, char *); char * decimal128ToEngString(const decimal128 *, char *); /* decNumber conversions */ decimal128 * decimal128FromNumber(decimal128 *, const decNumber *, decContext *); decNumber * decimal128ToNumber(const decimal128 *, decNumber *); /* Format-dependent utilities */ uint32_t decimal128IsCanonical(const decimal128 *); decimal128 * decimal128Canonical(decimal128 *, const decimal128 *); #endif ================================================ FILE: vendor/decNumber/decimal32.c ================================================ /* ------------------------------------------------------------------ */ /* Decimal 32-bit format module */ /* ------------------------------------------------------------------ */ /* Copyright (c) IBM Corporation, 2000, 2008. All rights reserved. */ /* */ /* This software is made available under the terms of the */ /* ICU License -- ICU 1.8.1 and later. */ /* */ /* The description and User's Guide ("The decNumber C Library") for */ /* this software is called decNumber.pdf. This document is */ /* available, together with arithmetic and format specifications, */ /* testcases, and Web links, on the General Decimal Arithmetic page. */ /* */ /* Please send comments, suggestions, and corrections to the author: */ /* mfc@uk.ibm.com */ /* Mike Cowlishaw, IBM Fellow */ /* IBM UK, PO Box 31, Birmingham Road, Warwick CV34 5JL, UK */ /* ------------------------------------------------------------------ */ /* This module comprises the routines for decimal32 format numbers. */ /* Conversions are supplied to and from decNumber and String. */ /* */ /* This is used when decNumber provides operations, either for all */ /* operations or as a proxy between decNumber and decSingle. */ /* */ /* Error handling is the same as decNumber (qv.). */ /* ------------------------------------------------------------------ */ #include // [for memset/memcpy] #include // [for printf] #define DECNUMDIGITS 7 // make decNumbers with space for 7 #include "decNumber.h" // base number library #include "decNumberLocal.h" // decNumber local types, etc. #include "decimal32.h" // our primary include /* Utility tables and routines [in decimal64.c] */ // DPD2BIN and the reverse are renamed to prevent link-time conflict // if decQuad is also built in the same executable #define DPD2BIN DPD2BINx #define BIN2DPD BIN2DPDx extern const uInt COMBEXP[32], COMBMSD[32]; extern const uShort DPD2BIN[1024]; extern const uShort BIN2DPD[1000]; extern const uByte BIN2CHAR[4001]; extern void decDigitsToDPD(const decNumber *, uInt *, Int); extern void decDigitsFromDPD(decNumber *, const uInt *, Int); #if DECTRACE || DECCHECK void decimal32Show(const decimal32 *); // for debug extern void decNumberShow(const decNumber *); // .. #endif /* Useful macro */ // Clear a structure (e.g., a decNumber) #define DEC_clear(d) memset(d, 0, sizeof(*d)) /* ------------------------------------------------------------------ */ /* decimal32FromNumber -- convert decNumber to decimal32 */ /* */ /* ds is the target decimal32 */ /* dn is the source number (assumed valid) */ /* set is the context, used only for reporting errors */ /* */ /* The set argument is used only for status reporting and for the */ /* rounding mode (used if the coefficient is more than DECIMAL32_Pmax */ /* digits or an overflow is detected). If the exponent is out of the */ /* valid range then Overflow or Underflow will be raised. */ /* After Underflow a subnormal result is possible. */ /* */ /* DEC_Clamped is set if the number has to be 'folded down' to fit, */ /* by reducing its exponent and multiplying the coefficient by a */ /* power of ten, or if the exponent on a zero had to be clamped. */ /* ------------------------------------------------------------------ */ decimal32 * decimal32FromNumber(decimal32 *d32, const decNumber *dn, decContext *set) { uInt status=0; // status accumulator Int ae; // adjusted exponent decNumber dw; // work decContext dc; // .. uInt comb, exp; // .. uInt uiwork; // for macros uInt targ=0; // target 32-bit // If the number has too many digits, or the exponent could be // out of range then reduce the number under the appropriate // constraints. This could push the number to Infinity or zero, // so this check and rounding must be done before generating the // decimal32] ae=dn->exponent+dn->digits-1; // [0 if special] if (dn->digits>DECIMAL32_Pmax // too many digits || ae>DECIMAL32_Emax // likely overflow || aeround; // use supplied rounding decNumberPlus(&dw, dn, &dc); // (round and check) // [this changes -0 to 0, so enforce the sign...] dw.bits|=dn->bits&DECNEG; status=dc.status; // save status dn=&dw; // use the work number } // maybe out of range if (dn->bits&DECSPECIAL) { // a special value if (dn->bits&DECINF) targ=DECIMAL_Inf<<24; else { // sNaN or qNaN if ((*dn->lsu!=0 || dn->digits>1) // non-zero coefficient && (dn->digitsbits&DECNAN) targ|=DECIMAL_NaN<<24; else targ|=DECIMAL_sNaN<<24; } // a NaN } // special else { // is finite if (decNumberIsZero(dn)) { // is a zero // set and clamp exponent if (dn->exponent<-DECIMAL32_Bias) { exp=0; // low clamp status|=DEC_Clamped; } else { exp=dn->exponent+DECIMAL32_Bias; // bias exponent if (exp>DECIMAL32_Ehigh) { // top clamp exp=DECIMAL32_Ehigh; status|=DEC_Clamped; } } comb=(exp>>3) & 0x18; // msd=0, exp top 2 bits .. } else { // non-zero finite number uInt msd; // work Int pad=0; // coefficient pad digits // the dn is known to fit, but it may need to be padded exp=(uInt)(dn->exponent+DECIMAL32_Bias); // bias exponent if (exp>DECIMAL32_Ehigh) { // fold-down case pad=exp-DECIMAL32_Ehigh; exp=DECIMAL32_Ehigh; // [to maximum] status|=DEC_Clamped; } // fastpath common case if (DECDPUN==3 && pad==0) { targ=BIN2DPD[dn->lsu[0]]; if (dn->digits>3) targ|=(uInt)(BIN2DPD[dn->lsu[1]])<<10; msd=(dn->digits==7 ? dn->lsu[2] : 0); } else { // general case decDigitsToDPD(dn, &targ, pad); // save and clear the top digit msd=targ>>20; targ&=0x000fffff; } // create the combination field if (msd>=8) comb=0x18 | ((exp>>5) & 0x06) | (msd & 0x01); else comb=((exp>>3) & 0x18) | msd; } targ|=comb<<26; // add combination field .. targ|=(exp&0x3f)<<20; // .. and exponent continuation } // finite if (dn->bits&DECNEG) targ|=0x80000000; // add sign bit // now write to storage; this is endian UBFROMUI(d32->bytes, targ); // directly store the int if (status!=0) decContextSetStatus(set, status); // pass on status // decimal32Show(d32); return d32; } // decimal32FromNumber /* ------------------------------------------------------------------ */ /* decimal32ToNumber -- convert decimal32 to decNumber */ /* d32 is the source decimal32 */ /* dn is the target number, with appropriate space */ /* No error is possible. */ /* ------------------------------------------------------------------ */ decNumber * decimal32ToNumber(const decimal32 *d32, decNumber *dn) { uInt msd; // coefficient MSD uInt exp; // exponent top two bits uInt comb; // combination field uInt sour; // source 32-bit uInt uiwork; // for macros // load source from storage; this is endian sour=UBTOUI(d32->bytes); // directly load the int comb=(sour>>26)&0x1f; // combination field decNumberZero(dn); // clean number if (sour&0x80000000) dn->bits=DECNEG; // set sign if negative msd=COMBMSD[comb]; // decode the combination field exp=COMBEXP[comb]; // .. if (exp==3) { // is a special if (msd==0) { dn->bits|=DECINF; return dn; // no coefficient needed } else if (sour&0x02000000) dn->bits|=DECSNAN; else dn->bits|=DECNAN; msd=0; // no top digit } else { // is a finite number dn->exponent=(exp<<6)+((sour>>20)&0x3f)-DECIMAL32_Bias; // unbiased } // get the coefficient sour&=0x000fffff; // clean coefficient continuation if (msd) { // non-zero msd sour|=msd<<20; // prefix to coefficient decDigitsFromDPD(dn, &sour, 3); // process 3 declets return dn; } // msd=0 if (!sour) return dn; // easy: coefficient is 0 if (sour&0x000ffc00) // need 2 declets? decDigitsFromDPD(dn, &sour, 2); // process 2 declets else decDigitsFromDPD(dn, &sour, 1); // process 1 declet return dn; } // decimal32ToNumber /* ------------------------------------------------------------------ */ /* to-scientific-string -- conversion to numeric string */ /* to-engineering-string -- conversion to numeric string */ /* */ /* decimal32ToString(d32, string); */ /* decimal32ToEngString(d32, string); */ /* */ /* d32 is the decimal32 format number to convert */ /* string is the string where the result will be laid out */ /* */ /* string must be at least 24 characters */ /* */ /* No error is possible, and no status can be set. */ /* ------------------------------------------------------------------ */ char * decimal32ToEngString(const decimal32 *d32, char *string){ decNumber dn; // work decimal32ToNumber(d32, &dn); decNumberToEngString(&dn, string); return string; } // decimal32ToEngString char * decimal32ToString(const decimal32 *d32, char *string){ uInt msd; // coefficient MSD Int exp; // exponent top two bits or full uInt comb; // combination field char *cstart; // coefficient start char *c; // output pointer in string const uByte *u; // work char *s, *t; // .. (source, target) Int dpd; // .. Int pre, e; // .. uInt uiwork; // for macros uInt sour; // source 32-bit // load source from storage; this is endian sour=UBTOUI(d32->bytes); // directly load the int c=string; // where result will go if (((Int)sour)<0) *c++='-'; // handle sign comb=(sour>>26)&0x1f; // combination field msd=COMBMSD[comb]; // decode the combination field exp=COMBEXP[comb]; // .. if (exp==3) { if (msd==0) { // infinity strcpy(c, "Inf"); strcpy(c+3, "inity"); return string; // easy } if (sour&0x02000000) *c++='s'; // sNaN strcpy(c, "NaN"); // complete word c+=3; // step past if ((sour&0x000fffff)==0) return string; // zero payload // otherwise drop through to add integer; set correct exp exp=0; msd=0; // setup for following code } else exp=(exp<<6)+((sour>>20)&0x3f)-DECIMAL32_Bias; // unbiased // convert 7 digits of significand to characters cstart=c; // save start of coefficient if (msd) *c++='0'+(char)msd; // non-zero most significant digit // Now decode the declets. After extracting each one, it is // decoded to binary and then to a 4-char sequence by table lookup; // the 4-chars are a 1-char length (significant digits, except 000 // has length 0). This allows us to left-align the first declet // with non-zero content, then remaining ones are full 3-char // length. We use fixed-length memcpys because variable-length // causes a subroutine call in GCC. (These are length 4 for speed // and are safe because the array has an extra terminator byte.) #define dpd2char u=&BIN2CHAR[DPD2BIN[dpd]*4]; \ if (c!=cstart) {memcpy(c, u+1, 4); c+=3;} \ else if (*u) {memcpy(c, u+4-*u, 4); c+=*u;} dpd=(sour>>10)&0x3ff; // declet 1 dpd2char; dpd=(sour)&0x3ff; // declet 2 dpd2char; if (c==cstart) *c++='0'; // all zeros -- make 0 if (exp==0) { // integer or NaN case -- easy *c='\0'; // terminate return string; } /* non-0 exponent */ e=0; // assume no E pre=c-cstart+exp; // [here, pre-exp is the digits count (==1 for zero)] if (exp>0 || pre<-5) { // need exponential form e=pre-1; // calculate E value pre=1; // assume one digit before '.' } // exponential form /* modify the coefficient, adding 0s, '.', and E+nn as needed */ s=c-1; // source (LSD) if (pre>0) { // ddd.ddd (plain), perhaps with E char *dotat=cstart+pre; if (dotat=dotat; s--, t--) *t=*s; // open the gap; leave t at gap *t='.'; // insert the dot c++; // length increased by one } // finally add the E-part, if needed; it will never be 0, and has // a maximum length of 3 digits (E-101 case) if (e!=0) { *c++='E'; // starts with E *c++='+'; // assume positive if (e<0) { *(c-1)='-'; // oops, need '-' e=-e; // uInt, please } u=&BIN2CHAR[e*4]; // -> length byte memcpy(c, u+4-*u, 4); // copy fixed 4 characters [is safe] c+=*u; // bump pointer appropriately } *c='\0'; // add terminator //printf("res %s\n", string); return string; } // pre>0 /* -5<=pre<=0: here for plain 0.ddd or 0.000ddd forms (can never have E) */ t=c+1-pre; *(t+1)='\0'; // can add terminator now for (; s>=cstart; s--, t--) *t=*s; // shift whole coefficient right c=cstart; *c++='0'; // always starts with 0. *c++='.'; for (; pre<0; pre++) *c++='0'; // add any 0's after '.' //printf("res %s\n", string); return string; } // decimal32ToString /* ------------------------------------------------------------------ */ /* to-number -- conversion from numeric string */ /* */ /* decimal32FromString(result, string, set); */ /* */ /* result is the decimal32 format number which gets the result of */ /* the conversion */ /* *string is the character string which should contain a valid */ /* number (which may be a special value) */ /* set is the context */ /* */ /* The context is supplied to this routine is used for error handling */ /* (setting of status and traps) and for the rounding mode, only. */ /* If an error occurs, the result will be a valid decimal32 NaN. */ /* ------------------------------------------------------------------ */ decimal32 * decimal32FromString(decimal32 *result, const char *string, decContext *set) { decContext dc; // work decNumber dn; // .. decContextDefault(&dc, DEC_INIT_DECIMAL32); // no traps, please dc.round=set->round; // use supplied rounding decNumberFromString(&dn, string, &dc); // will round if needed decimal32FromNumber(result, &dn, &dc); if (dc.status!=0) { // something happened decContextSetStatus(set, dc.status); // .. pass it on } return result; } // decimal32FromString /* ------------------------------------------------------------------ */ /* decimal32IsCanonical -- test whether encoding is canonical */ /* d32 is the source decimal32 */ /* returns 1 if the encoding of d32 is canonical, 0 otherwise */ /* No error is possible. */ /* ------------------------------------------------------------------ */ uInt decimal32IsCanonical(const decimal32 *d32) { decNumber dn; // work decimal32 canon; // .. decContext dc; // .. decContextDefault(&dc, DEC_INIT_DECIMAL32); decimal32ToNumber(d32, &dn); decimal32FromNumber(&canon, &dn, &dc);// canon will now be canonical return memcmp(d32, &canon, DECIMAL32_Bytes)==0; } // decimal32IsCanonical /* ------------------------------------------------------------------ */ /* decimal32Canonical -- copy an encoding, ensuring it is canonical */ /* d32 is the source decimal32 */ /* result is the target (may be the same decimal32) */ /* returns result */ /* No error is possible. */ /* ------------------------------------------------------------------ */ decimal32 * decimal32Canonical(decimal32 *result, const decimal32 *d32) { decNumber dn; // work decContext dc; // .. decContextDefault(&dc, DEC_INIT_DECIMAL32); decimal32ToNumber(d32, &dn); decimal32FromNumber(result, &dn, &dc);// result will now be canonical return result; } // decimal32Canonical #if DECTRACE || DECCHECK /* Macros for accessing decimal32 fields. These assume the argument is a reference (pointer) to the decimal32 structure, and the decimal32 is in network byte order (big-endian) */ // Get sign #define decimal32Sign(d) ((unsigned)(d)->bytes[0]>>7) // Get combination field #define decimal32Comb(d) (((d)->bytes[0] & 0x7c)>>2) // Get exponent continuation [does not remove bias] #define decimal32ExpCon(d) ((((d)->bytes[0] & 0x03)<<4) \ | ((unsigned)(d)->bytes[1]>>4)) // Set sign [this assumes sign previously 0] #define decimal32SetSign(d, b) { \ (d)->bytes[0]|=((unsigned)(b)<<7);} // Set exponent continuation [does not apply bias] // This assumes range has been checked and exponent previously 0; // type of exponent must be unsigned #define decimal32SetExpCon(d, e) { \ (d)->bytes[0]|=(uByte)((e)>>4); \ (d)->bytes[1]|=(uByte)(((e)&0x0F)<<4);} /* ------------------------------------------------------------------ */ /* decimal32Show -- display a decimal32 in hexadecimal [debug aid] */ /* d32 -- the number to show */ /* ------------------------------------------------------------------ */ // Also shows sign/cob/expconfields extracted - valid bigendian only void decimal32Show(const decimal32 *d32) { char buf[DECIMAL32_Bytes*2+1]; Int i, j=0; if (DECLITEND) { for (i=0; ibytes[3-i]); } printf(" D32> %s [S:%d Cb:%02x Ec:%02x] LittleEndian\n", buf, d32->bytes[3]>>7, (d32->bytes[3]>>2)&0x1f, ((d32->bytes[3]&0x3)<<4)| (d32->bytes[2]>>4)); } else { for (i=0; ibytes[i]); } printf(" D32> %s [S:%d Cb:%02x Ec:%02x] BigEndian\n", buf, decimal32Sign(d32), decimal32Comb(d32), decimal32ExpCon(d32)); } } // decimal32Show #endif ================================================ FILE: vendor/decNumber/decimal32.h ================================================ /* ------------------------------------------------------------------ */ /* Decimal 32-bit format module header */ /* ------------------------------------------------------------------ */ /* Copyright (c) IBM Corporation, 2000, 2006. All rights reserved. */ /* */ /* This software is made available under the terms of the */ /* ICU License -- ICU 1.8.1 and later. */ /* */ /* The description and User's Guide ("The decNumber C Library") for */ /* this software is called decNumber.pdf. This document is */ /* available, together with arithmetic and format specifications, */ /* testcases, and Web links, on the General Decimal Arithmetic page. */ /* */ /* Please send comments, suggestions, and corrections to the author: */ /* mfc@uk.ibm.com */ /* Mike Cowlishaw, IBM Fellow */ /* IBM UK, PO Box 31, Birmingham Road, Warwick CV34 5JL, UK */ /* ------------------------------------------------------------------ */ #if !defined(DECIMAL32) #define DECIMAL32 #define DEC32NAME "decimal32" /* Short name */ #define DEC32FULLNAME "Decimal 32-bit Number" /* Verbose name */ #define DEC32AUTHOR "Mike Cowlishaw" /* Who to blame */ /* parameters for decimal32s */ #define DECIMAL32_Bytes 4 /* length */ #define DECIMAL32_Pmax 7 /* maximum precision (digits) */ #define DECIMAL32_Emax 96 /* maximum adjusted exponent */ #define DECIMAL32_Emin -95 /* minimum adjusted exponent */ #define DECIMAL32_Bias 101 /* bias for the exponent */ #define DECIMAL32_String 15 /* maximum string length, +1 */ #define DECIMAL32_EconL 6 /* exp. continuation length */ /* highest biased exponent (Elimit-1) */ #define DECIMAL32_Ehigh (DECIMAL32_Emax+DECIMAL32_Bias-DECIMAL32_Pmax+1) /* check enough digits, if pre-defined */ #if defined(DECNUMDIGITS) #if (DECNUMDIGITS=7 for safe use #endif #endif #ifndef DECNUMDIGITS #define DECNUMDIGITS DECIMAL32_Pmax /* size if not already defined*/ #endif #ifndef DECNUMBER #include "decNumber.h" /* context and number library */ #endif /* Decimal 32-bit type, accessible by bytes */ typedef struct { uint8_t bytes[DECIMAL32_Bytes]; /* decimal32: 1, 5, 6, 20 bits*/ } decimal32; /* special values [top byte excluding sign bit; last two bits are */ /* don't-care for Infinity on input, last bit don't-care for NaN] */ #if !defined(DECIMAL_NaN) #define DECIMAL_NaN 0x7c /* 0 11111 00 NaN */ #define DECIMAL_sNaN 0x7e /* 0 11111 10 sNaN */ #define DECIMAL_Inf 0x78 /* 0 11110 00 Infinity */ #endif /* ---------------------------------------------------------------- */ /* Routines */ /* ---------------------------------------------------------------- */ /* String conversions */ decimal32 * decimal32FromString(decimal32 *, const char *, decContext *); char * decimal32ToString(const decimal32 *, char *); char * decimal32ToEngString(const decimal32 *, char *); /* decNumber conversions */ decimal32 * decimal32FromNumber(decimal32 *, const decNumber *, decContext *); decNumber * decimal32ToNumber(const decimal32 *, decNumber *); /* Format-dependent utilities */ uint32_t decimal32IsCanonical(const decimal32 *); decimal32 * decimal32Canonical(decimal32 *, const decimal32 *); #endif ================================================ FILE: vendor/decNumber/decimal64.c ================================================ /* ------------------------------------------------------------------ */ /* Decimal 64-bit format module */ /* ------------------------------------------------------------------ */ /* Copyright (c) IBM Corporation, 2000, 2009. All rights reserved. */ /* */ /* This software is made available under the terms of the */ /* ICU License -- ICU 1.8.1 and later. */ /* */ /* The description and User's Guide ("The decNumber C Library") for */ /* this software is called decNumber.pdf. This document is */ /* available, together with arithmetic and format specifications, */ /* testcases, and Web links, on the General Decimal Arithmetic page. */ /* */ /* Please send comments, suggestions, and corrections to the author: */ /* mfc@uk.ibm.com */ /* Mike Cowlishaw, IBM Fellow */ /* IBM UK, PO Box 31, Birmingham Road, Warwick CV34 5JL, UK */ /* ------------------------------------------------------------------ */ /* This module comprises the routines for decimal64 format numbers. */ /* Conversions are supplied to and from decNumber and String. */ /* */ /* This is used when decNumber provides operations, either for all */ /* operations or as a proxy between decNumber and decSingle. */ /* */ /* Error handling is the same as decNumber (qv.). */ /* ------------------------------------------------------------------ */ #include // [for memset/memcpy] #include // [for printf] #define DECNUMDIGITS 16 // make decNumbers with space for 16 #include "decNumber.h" // base number library #include "decNumberLocal.h" // decNumber local types, etc. #include "decimal64.h" // our primary include /* Utility routines and tables [in decimal64.c]; externs for C++ */ // DPD2BIN and the reverse are renamed to prevent link-time conflict // if decQuad is also built in the same executable #define DPD2BIN DPD2BINx #define BIN2DPD BIN2DPDx extern const uInt COMBEXP[32], COMBMSD[32]; extern const uShort DPD2BIN[1024]; extern const uShort BIN2DPD[1000]; extern const uByte BIN2CHAR[4001]; extern void decDigitsFromDPD(decNumber *, const uInt *, Int); extern void decDigitsToDPD(const decNumber *, uInt *, Int); #if DECTRACE || DECCHECK void decimal64Show(const decimal64 *); // for debug extern void decNumberShow(const decNumber *); // .. #endif /* Useful macro */ // Clear a structure (e.g., a decNumber) #define DEC_clear(d) memset(d, 0, sizeof(*d)) /* define and include the tables to use for conversions */ #define DEC_BIN2CHAR 1 #define DEC_DPD2BIN 1 #define DEC_BIN2DPD 1 // used for all sizes #include "decDPD.h" // lookup tables /* ------------------------------------------------------------------ */ /* decimal64FromNumber -- convert decNumber to decimal64 */ /* */ /* ds is the target decimal64 */ /* dn is the source number (assumed valid) */ /* set is the context, used only for reporting errors */ /* */ /* The set argument is used only for status reporting and for the */ /* rounding mode (used if the coefficient is more than DECIMAL64_Pmax */ /* digits or an overflow is detected). If the exponent is out of the */ /* valid range then Overflow or Underflow will be raised. */ /* After Underflow a subnormal result is possible. */ /* */ /* DEC_Clamped is set if the number has to be 'folded down' to fit, */ /* by reducing its exponent and multiplying the coefficient by a */ /* power of ten, or if the exponent on a zero had to be clamped. */ /* ------------------------------------------------------------------ */ decimal64 * decimal64FromNumber(decimal64 *d64, const decNumber *dn, decContext *set) { uInt status=0; // status accumulator Int ae; // adjusted exponent decNumber dw; // work decContext dc; // .. uInt comb, exp; // .. uInt uiwork; // for macros uInt targar[2]={0, 0}; // target 64-bit #define targhi targar[1] // name the word with the sign #define targlo targar[0] // and the other // If the number has too many digits, or the exponent could be // out of range then reduce the number under the appropriate // constraints. This could push the number to Infinity or zero, // so this check and rounding must be done before generating the // decimal64] ae=dn->exponent+dn->digits-1; // [0 if special] if (dn->digits>DECIMAL64_Pmax // too many digits || ae>DECIMAL64_Emax // likely overflow || aeround; // use supplied rounding decNumberPlus(&dw, dn, &dc); // (round and check) // [this changes -0 to 0, so enforce the sign...] dw.bits|=dn->bits&DECNEG; status=dc.status; // save status dn=&dw; // use the work number } // maybe out of range if (dn->bits&DECSPECIAL) { // a special value if (dn->bits&DECINF) targhi=DECIMAL_Inf<<24; else { // sNaN or qNaN if ((*dn->lsu!=0 || dn->digits>1) // non-zero coefficient && (dn->digitsbits&DECNAN) targhi|=DECIMAL_NaN<<24; else targhi|=DECIMAL_sNaN<<24; } // a NaN } // special else { // is finite if (decNumberIsZero(dn)) { // is a zero // set and clamp exponent if (dn->exponent<-DECIMAL64_Bias) { exp=0; // low clamp status|=DEC_Clamped; } else { exp=dn->exponent+DECIMAL64_Bias; // bias exponent if (exp>DECIMAL64_Ehigh) { // top clamp exp=DECIMAL64_Ehigh; status|=DEC_Clamped; } } comb=(exp>>5) & 0x18; // msd=0, exp top 2 bits .. } else { // non-zero finite number uInt msd; // work Int pad=0; // coefficient pad digits // the dn is known to fit, but it may need to be padded exp=(uInt)(dn->exponent+DECIMAL64_Bias); // bias exponent if (exp>DECIMAL64_Ehigh) { // fold-down case pad=exp-DECIMAL64_Ehigh; exp=DECIMAL64_Ehigh; // [to maximum] status|=DEC_Clamped; } // fastpath common case if (DECDPUN==3 && pad==0) { uInt dpd[6]={0,0,0,0,0,0}; uInt i; Int d=dn->digits; for (i=0; d>0; i++, d-=3) dpd[i]=BIN2DPD[dn->lsu[i]]; targlo =dpd[0]; targlo|=dpd[1]<<10; targlo|=dpd[2]<<20; if (dn->digits>6) { targlo|=dpd[3]<<30; targhi =dpd[3]>>2; targhi|=dpd[4]<<8; } msd=dpd[5]; // [did not really need conversion] } else { // general case decDigitsToDPD(dn, targar, pad); // save and clear the top digit msd=targhi>>18; targhi&=0x0003ffff; } // create the combination field if (msd>=8) comb=0x18 | ((exp>>7) & 0x06) | (msd & 0x01); else comb=((exp>>5) & 0x18) | msd; } targhi|=comb<<26; // add combination field .. targhi|=(exp&0xff)<<18; // .. and exponent continuation } // finite if (dn->bits&DECNEG) targhi|=0x80000000; // add sign bit // now write to storage; this is now always endian if (DECLITEND) { // lo int then hi UBFROMUI(d64->bytes, targar[0]); UBFROMUI(d64->bytes+4, targar[1]); } else { // hi int then lo UBFROMUI(d64->bytes, targar[1]); UBFROMUI(d64->bytes+4, targar[0]); } if (status!=0) decContextSetStatus(set, status); // pass on status // decimal64Show(d64); return d64; } // decimal64FromNumber /* ------------------------------------------------------------------ */ /* decimal64ToNumber -- convert decimal64 to decNumber */ /* d64 is the source decimal64 */ /* dn is the target number, with appropriate space */ /* No error is possible. */ /* ------------------------------------------------------------------ */ decNumber * decimal64ToNumber(const decimal64 *d64, decNumber *dn) { uInt msd; // coefficient MSD uInt exp; // exponent top two bits uInt comb; // combination field Int need; // work uInt uiwork; // for macros uInt sourar[2]; // source 64-bit #define sourhi sourar[1] // name the word with the sign #define sourlo sourar[0] // and the lower word // load source from storage; this is endian if (DECLITEND) { sourlo=UBTOUI(d64->bytes ); // directly load the low int sourhi=UBTOUI(d64->bytes+4); // then the high int } else { sourhi=UBTOUI(d64->bytes ); // directly load the high int sourlo=UBTOUI(d64->bytes+4); // then the low int } comb=(sourhi>>26)&0x1f; // combination field decNumberZero(dn); // clean number if (sourhi&0x80000000) dn->bits=DECNEG; // set sign if negative msd=COMBMSD[comb]; // decode the combination field exp=COMBEXP[comb]; // .. if (exp==3) { // is a special if (msd==0) { dn->bits|=DECINF; return dn; // no coefficient needed } else if (sourhi&0x02000000) dn->bits|=DECSNAN; else dn->bits|=DECNAN; msd=0; // no top digit } else { // is a finite number dn->exponent=(exp<<8)+((sourhi>>18)&0xff)-DECIMAL64_Bias; // unbiased } // get the coefficient sourhi&=0x0003ffff; // clean coefficient continuation if (msd) { // non-zero msd sourhi|=msd<<18; // prefix to coefficient need=6; // process 6 declets } else { // msd=0 if (!sourhi) { // top word 0 if (!sourlo) return dn; // easy: coefficient is 0 need=3; // process at least 3 declets if (sourlo&0xc0000000) need++; // process 4 declets // [could reduce some more, here] } else { // some bits in top word, msd=0 need=4; // process at least 4 declets if (sourhi&0x0003ff00) need++; // top declet!=0, process 5 } } //msd=0 decDigitsFromDPD(dn, sourar, need); // process declets return dn; } // decimal64ToNumber /* ------------------------------------------------------------------ */ /* to-scientific-string -- conversion to numeric string */ /* to-engineering-string -- conversion to numeric string */ /* */ /* decimal64ToString(d64, string); */ /* decimal64ToEngString(d64, string); */ /* */ /* d64 is the decimal64 format number to convert */ /* string is the string where the result will be laid out */ /* */ /* string must be at least 24 characters */ /* */ /* No error is possible, and no status can be set. */ /* ------------------------------------------------------------------ */ char * decimal64ToEngString(const decimal64 *d64, char *string){ decNumber dn; // work decimal64ToNumber(d64, &dn); decNumberToEngString(&dn, string); return string; } // decimal64ToEngString char * decimal64ToString(const decimal64 *d64, char *string){ uInt msd; // coefficient MSD Int exp; // exponent top two bits or full uInt comb; // combination field char *cstart; // coefficient start char *c; // output pointer in string const uByte *u; // work char *s, *t; // .. (source, target) Int dpd; // .. Int pre, e; // .. uInt uiwork; // for macros uInt sourar[2]; // source 64-bit #define sourhi sourar[1] // name the word with the sign #define sourlo sourar[0] // and the lower word // load source from storage; this is endian if (DECLITEND) { sourlo=UBTOUI(d64->bytes ); // directly load the low int sourhi=UBTOUI(d64->bytes+4); // then the high int } else { sourhi=UBTOUI(d64->bytes ); // directly load the high int sourlo=UBTOUI(d64->bytes+4); // then the low int } c=string; // where result will go if (((Int)sourhi)<0) *c++='-'; // handle sign comb=(sourhi>>26)&0x1f; // combination field msd=COMBMSD[comb]; // decode the combination field exp=COMBEXP[comb]; // .. if (exp==3) { if (msd==0) { // infinity strcpy(c, "Inf"); strcpy(c+3, "inity"); return string; // easy } if (sourhi&0x02000000) *c++='s'; // sNaN strcpy(c, "NaN"); // complete word c+=3; // step past if (sourlo==0 && (sourhi&0x0003ffff)==0) return string; // zero payload // otherwise drop through to add integer; set correct exp exp=0; msd=0; // setup for following code } else exp=(exp<<8)+((sourhi>>18)&0xff)-DECIMAL64_Bias; // convert 16 digits of significand to characters cstart=c; // save start of coefficient if (msd) *c++='0'+(char)msd; // non-zero most significant digit // Now decode the declets. After extracting each one, it is // decoded to binary and then to a 4-char sequence by table lookup; // the 4-chars are a 1-char length (significant digits, except 000 // has length 0). This allows us to left-align the first declet // with non-zero content, then remaining ones are full 3-char // length. We use fixed-length memcpys because variable-length // causes a subroutine call in GCC. (These are length 4 for speed // and are safe because the array has an extra terminator byte.) #define dpd2char u=&BIN2CHAR[DPD2BIN[dpd]*4]; \ if (c!=cstart) {memcpy(c, u+1, 4); c+=3;} \ else if (*u) {memcpy(c, u+4-*u, 4); c+=*u;} dpd=(sourhi>>8)&0x3ff; // declet 1 dpd2char; dpd=((sourhi&0xff)<<2) | (sourlo>>30); // declet 2 dpd2char; dpd=(sourlo>>20)&0x3ff; // declet 3 dpd2char; dpd=(sourlo>>10)&0x3ff; // declet 4 dpd2char; dpd=(sourlo)&0x3ff; // declet 5 dpd2char; if (c==cstart) *c++='0'; // all zeros -- make 0 if (exp==0) { // integer or NaN case -- easy *c='\0'; // terminate return string; } /* non-0 exponent */ e=0; // assume no E pre=c-cstart+exp; // [here, pre-exp is the digits count (==1 for zero)] if (exp>0 || pre<-5) { // need exponential form e=pre-1; // calculate E value pre=1; // assume one digit before '.' } // exponential form /* modify the coefficient, adding 0s, '.', and E+nn as needed */ s=c-1; // source (LSD) if (pre>0) { // ddd.ddd (plain), perhaps with E char *dotat=cstart+pre; if (dotat=dotat; s--, t--) *t=*s; // open the gap; leave t at gap *t='.'; // insert the dot c++; // length increased by one } // finally add the E-part, if needed; it will never be 0, and has // a maximum length of 3 digits if (e!=0) { *c++='E'; // starts with E *c++='+'; // assume positive if (e<0) { *(c-1)='-'; // oops, need '-' e=-e; // uInt, please } u=&BIN2CHAR[e*4]; // -> length byte memcpy(c, u+4-*u, 4); // copy fixed 4 characters [is safe] c+=*u; // bump pointer appropriately } *c='\0'; // add terminator //printf("res %s\n", string); return string; } // pre>0 /* -5<=pre<=0: here for plain 0.ddd or 0.000ddd forms (can never have E) */ t=c+1-pre; *(t+1)='\0'; // can add terminator now for (; s>=cstart; s--, t--) *t=*s; // shift whole coefficient right c=cstart; *c++='0'; // always starts with 0. *c++='.'; for (; pre<0; pre++) *c++='0'; // add any 0's after '.' //printf("res %s\n", string); return string; } // decimal64ToString /* ------------------------------------------------------------------ */ /* to-number -- conversion from numeric string */ /* */ /* decimal64FromString(result, string, set); */ /* */ /* result is the decimal64 format number which gets the result of */ /* the conversion */ /* *string is the character string which should contain a valid */ /* number (which may be a special value) */ /* set is the context */ /* */ /* The context is supplied to this routine is used for error handling */ /* (setting of status and traps) and for the rounding mode, only. */ /* If an error occurs, the result will be a valid decimal64 NaN. */ /* ------------------------------------------------------------------ */ decimal64 * decimal64FromString(decimal64 *result, const char *string, decContext *set) { decContext dc; // work decNumber dn; // .. decContextDefault(&dc, DEC_INIT_DECIMAL64); // no traps, please dc.round=set->round; // use supplied rounding decNumberFromString(&dn, string, &dc); // will round if needed decimal64FromNumber(result, &dn, &dc); if (dc.status!=0) { // something happened decContextSetStatus(set, dc.status); // .. pass it on } return result; } // decimal64FromString /* ------------------------------------------------------------------ */ /* decimal64IsCanonical -- test whether encoding is canonical */ /* d64 is the source decimal64 */ /* returns 1 if the encoding of d64 is canonical, 0 otherwise */ /* No error is possible. */ /* ------------------------------------------------------------------ */ uInt decimal64IsCanonical(const decimal64 *d64) { decNumber dn; // work decimal64 canon; // .. decContext dc; // .. decContextDefault(&dc, DEC_INIT_DECIMAL64); decimal64ToNumber(d64, &dn); decimal64FromNumber(&canon, &dn, &dc);// canon will now be canonical return memcmp(d64, &canon, DECIMAL64_Bytes)==0; } // decimal64IsCanonical /* ------------------------------------------------------------------ */ /* decimal64Canonical -- copy an encoding, ensuring it is canonical */ /* d64 is the source decimal64 */ /* result is the target (may be the same decimal64) */ /* returns result */ /* No error is possible. */ /* ------------------------------------------------------------------ */ decimal64 * decimal64Canonical(decimal64 *result, const decimal64 *d64) { decNumber dn; // work decContext dc; // .. decContextDefault(&dc, DEC_INIT_DECIMAL64); decimal64ToNumber(d64, &dn); decimal64FromNumber(result, &dn, &dc);// result will now be canonical return result; } // decimal64Canonical #if DECTRACE || DECCHECK /* Macros for accessing decimal64 fields. These assume the argument is a reference (pointer) to the decimal64 structure, and the decimal64 is in network byte order (big-endian) */ // Get sign #define decimal64Sign(d) ((unsigned)(d)->bytes[0]>>7) // Get combination field #define decimal64Comb(d) (((d)->bytes[0] & 0x7c)>>2) // Get exponent continuation [does not remove bias] #define decimal64ExpCon(d) ((((d)->bytes[0] & 0x03)<<6) \ | ((unsigned)(d)->bytes[1]>>2)) // Set sign [this assumes sign previously 0] #define decimal64SetSign(d, b) { \ (d)->bytes[0]|=((unsigned)(b)<<7);} // Set exponent continuation [does not apply bias] // This assumes range has been checked and exponent previously 0; // type of exponent must be unsigned #define decimal64SetExpCon(d, e) { \ (d)->bytes[0]|=(uByte)((e)>>6); \ (d)->bytes[1]|=(uByte)(((e)&0x3F)<<2);} /* ------------------------------------------------------------------ */ /* decimal64Show -- display a decimal64 in hexadecimal [debug aid] */ /* d64 -- the number to show */ /* ------------------------------------------------------------------ */ // Also shows sign/cob/expconfields extracted void decimal64Show(const decimal64 *d64) { char buf[DECIMAL64_Bytes*2+1]; Int i, j=0; if (DECLITEND) { for (i=0; ibytes[7-i]); } printf(" D64> %s [S:%d Cb:%02x Ec:%02x] LittleEndian\n", buf, d64->bytes[7]>>7, (d64->bytes[7]>>2)&0x1f, ((d64->bytes[7]&0x3)<<6)| (d64->bytes[6]>>2)); } else { // big-endian for (i=0; ibytes[i]); } printf(" D64> %s [S:%d Cb:%02x Ec:%02x] BigEndian\n", buf, decimal64Sign(d64), decimal64Comb(d64), decimal64ExpCon(d64)); } } // decimal64Show #endif /* ================================================================== */ /* Shared utility routines and tables */ /* ================================================================== */ // define and include the conversion tables to use for shared code #if DECDPUN==3 #define DEC_DPD2BIN 1 #else #define DEC_DPD2BCD 1 #endif #include "decDPD.h" // lookup tables // The maximum number of decNumberUnits needed for a working copy of // the units array is the ceiling of digits/DECDPUN, where digits is // the maximum number of digits in any of the formats for which this // is used. decimal128.h must not be included in this module, so, as // a very special case, that number is defined as a literal here. #define DECMAX754 34 #define DECMAXUNITS ((DECMAX754+DECDPUN-1)/DECDPUN) /* ------------------------------------------------------------------ */ /* Combination field lookup tables (uInts to save measurable work) */ /* */ /* COMBEXP - 2-bit most-significant-bits of exponent */ /* [11 if an Infinity or NaN] */ /* COMBMSD - 4-bit most-significant-digit */ /* [0=Infinity, 1=NaN if COMBEXP=11] */ /* */ /* Both are indexed by the 5-bit combination field (0-31) */ /* ------------------------------------------------------------------ */ const uInt COMBEXP[32]={0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 0, 0, 1, 1, 2, 2, 3, 3}; const uInt COMBMSD[32]={0, 1, 2, 3, 4, 5, 6, 7, 0, 1, 2, 3, 4, 5, 6, 7, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 8, 9, 8, 9, 0, 1}; /* ------------------------------------------------------------------ */ /* decDigitsToDPD -- pack coefficient into DPD form */ /* */ /* dn is the source number (assumed valid, max DECMAX754 digits) */ /* targ is 1, 2, or 4-element uInt array, which the caller must */ /* have cleared to zeros */ /* shift is the number of 0 digits to add on the right (normally 0) */ /* */ /* The coefficient must be known small enough to fit. The full */ /* coefficient is copied, including the leading 'odd' digit. This */ /* digit is retrieved and packed into the combination field by the */ /* caller. */ /* */ /* The target uInts are altered only as necessary to receive the */ /* digits of the decNumber. When more than one uInt is needed, they */ /* are filled from left to right (that is, the uInt at offset 0 will */ /* end up with the least-significant digits). */ /* */ /* shift is used for 'fold-down' padding. */ /* */ /* No error is possible. */ /* ------------------------------------------------------------------ */ #if DECDPUN<=4 // Constant multipliers for divide-by-power-of five using reciprocal // multiply, after removing powers of 2 by shifting, and final shift // of 17 [we only need up to **4] static const uInt multies[]={131073, 26215, 5243, 1049, 210}; // QUOT10 -- macro to return the quotient of unit u divided by 10**n #define QUOT10(u, n) ((((uInt)(u)>>(n))*multies[n])>>17) #endif void decDigitsToDPD(const decNumber *dn, uInt *targ, Int shift) { Int cut; // work Int n; // output bunch counter Int digits=dn->digits; // digit countdown uInt dpd; // densely packed decimal value uInt bin; // binary value 0-999 uInt *uout=targ; // -> current output uInt uInt uoff=0; // -> current output offset [from right] const Unit *inu=dn->lsu; // -> current input unit Unit uar[DECMAXUNITS]; // working copy of units, iff shifted #if DECDPUN!=3 // not fast path Unit in; // current unit #endif if (shift!=0) { // shift towards most significant required // shift the units array to the left by pad digits and copy // [this code is a special case of decShiftToMost, which could // be used instead if exposed and the array were copied first] const Unit *source; // .. Unit *target, *first; // .. uInt next=0; // work source=dn->lsu+D2U(digits)-1; // where msu comes from target=uar+D2U(digits)-1+D2U(shift);// where upper part of first cut goes cut=DECDPUN-MSUDIGITS(shift); // where to slice if (cut==0) { // unit-boundary case for (; source>=dn->lsu; source--, target--) *target=*source; } else { first=uar+D2U(digits+shift)-1; // where msu will end up for (; source>=dn->lsu; source--, target--) { // split the source Unit and accumulate remainder for next #if DECDPUN<=4 uInt quot=QUOT10(*source, cut); uInt rem=*source-quot*DECPOWERS[cut]; next+=quot; #else uInt rem=*source%DECPOWERS[cut]; next+=*source/DECPOWERS[cut]; #endif if (target<=first) *target=(Unit)next; // write to target iff valid next=rem*DECPOWERS[DECDPUN-cut]; // save remainder for next Unit } } // shift-move // propagate remainder to one below and clear the rest for (; target>=uar; target--) { *target=(Unit)next; next=0; } digits+=shift; // add count (shift) of zeros added inu=uar; // use units in working array } /* now densely pack the coefficient into DPD declets */ #if DECDPUN!=3 // not fast path in=*inu; // current unit cut=0; // at lowest digit bin=0; // [keep compiler quiet] #endif for(n=0; digits>0; n++) { // each output bunch #if DECDPUN==3 // fast path, 3-at-a-time bin=*inu; // 3 digits ready for convert digits-=3; // [may go negative] inu++; // may need another #else // must collect digit-by-digit Unit dig; // current digit Int j; // digit-in-declet count for (j=0; j<3; j++) { #if DECDPUN<=4 Unit temp=(Unit)((uInt)(in*6554)>>16); dig=(Unit)(in-X10(temp)); in=temp; #else dig=in%10; in=in/10; #endif if (j==0) bin=dig; else if (j==1) bin+=X10(dig); else /* j==2 */ bin+=X100(dig); digits--; if (digits==0) break; // [also protects *inu below] cut++; if (cut==DECDPUN) {inu++; in=*inu; cut=0;} } #endif // here there are 3 digits in bin, or have used all input digits dpd=BIN2DPD[bin]; // write declet to uInt array *uout|=dpd<>(10-uoff); // collect top bits } // n declets return; } // decDigitsToDPD /* ------------------------------------------------------------------ */ /* decDigitsFromDPD -- unpack a format's coefficient */ /* */ /* dn is the target number, with 7, 16, or 34-digit space. */ /* sour is a 1, 2, or 4-element uInt array containing only declets */ /* declets is the number of (right-aligned) declets in sour to */ /* be processed. This may be 1 more than the obvious number in */ /* a format, as any top digit is prefixed to the coefficient */ /* continuation field. It also may be as small as 1, as the */ /* caller may pre-process leading zero declets. */ /* */ /* When doing the 'extra declet' case care is taken to avoid writing */ /* extra digits when there are leading zeros, as these could overflow */ /* the units array when DECDPUN is not 3. */ /* */ /* The target uInts are used only as necessary to process declets */ /* declets into the decNumber. When more than one uInt is needed, */ /* they are used from left to right (that is, the uInt at offset 0 */ /* provides the least-significant digits). */ /* */ /* dn->digits is set, but not the sign or exponent. */ /* No error is possible [the redundant 888 codes are allowed]. */ /* ------------------------------------------------------------------ */ void decDigitsFromDPD(decNumber *dn, const uInt *sour, Int declets) { uInt dpd; // collector for 10 bits Int n; // counter Unit *uout=dn->lsu; // -> current output unit Unit *last=uout; // will be unit containing msd const uInt *uin=sour; // -> current input uInt uInt uoff=0; // -> current input offset [from right] #if DECDPUN!=3 uInt bcd; // BCD result uInt nibble; // work Unit out=0; // accumulator Int cut=0; // power of ten in current unit #endif #if DECDPUN>4 uInt const *pow; // work #endif // Expand the densely-packed integer, right to left for (n=declets-1; n>=0; n--) { // count down declets of 10 bits dpd=*uin>>uoff; uoff+=10; if (uoff>32) { // crossed uInt boundary uin++; uoff-=32; // [if using this code for wider, check this] dpd|=*uin<<(10-uoff); // get waiting bits } dpd&=0x3ff; // clear uninteresting bits #if DECDPUN==3 if (dpd==0) *uout=0; else { *uout=DPD2BIN[dpd]; // convert 10 bits to binary 0-999 last=uout; // record most significant unit } uout++; } // n #else // DECDPUN!=3 if (dpd==0) { // fastpath [e.g., leading zeros] // write out three 0 digits (nibbles); out may have digit(s) cut++; if (cut==DECDPUN) {*uout=out; if (out) {last=uout; out=0;} uout++; cut=0;} if (n==0) break; // [as below, works even if MSD=0] cut++; if (cut==DECDPUN) {*uout=out; if (out) {last=uout; out=0;} uout++; cut=0;} cut++; if (cut==DECDPUN) {*uout=out; if (out) {last=uout; out=0;} uout++; cut=0;} continue; } bcd=DPD2BCD[dpd]; // convert 10 bits to 12 bits BCD // now accumulate the 3 BCD nibbles into units nibble=bcd & 0x00f; if (nibble) out=(Unit)(out+nibble*DECPOWERS[cut]); cut++; if (cut==DECDPUN) {*uout=out; if (out) {last=uout; out=0;} uout++; cut=0;} bcd>>=4; // if this is the last declet and the remaining nibbles in bcd // are 00 then process no more nibbles, because this could be // the 'odd' MSD declet and writing any more Units would then // overflow the unit array if (n==0 && !bcd) break; nibble=bcd & 0x00f; if (nibble) out=(Unit)(out+nibble*DECPOWERS[cut]); cut++; if (cut==DECDPUN) {*uout=out; if (out) {last=uout; out=0;} uout++; cut=0;} bcd>>=4; nibble=bcd & 0x00f; if (nibble) out=(Unit)(out+nibble*DECPOWERS[cut]); cut++; if (cut==DECDPUN) {*uout=out; if (out) {last=uout; out=0;} uout++; cut=0;} } // n if (cut!=0) { // some more left over *uout=out; // write out final unit if (out) last=uout; // and note if non-zero } #endif // here, last points to the most significant unit with digits; // inspect it to get the final digits count -- this is essentially // the same code as decGetDigits in decNumber.c dn->digits=(last-dn->lsu)*DECDPUN+1; // floor of digits, plus // must be at least 1 digit #if DECDPUN>1 if (*last<10) return; // common odd digit or 0 dn->digits++; // must be 2 at least #if DECDPUN>2 if (*last<100) return; // 10-99 dn->digits++; // must be 3 at least #if DECDPUN>3 if (*last<1000) return; // 100-999 dn->digits++; // must be 4 at least #if DECDPUN>4 for (pow=&DECPOWERS[4]; *last>=*pow; pow++) dn->digits++; #endif #endif #endif #endif return; } //decDigitsFromDPD ================================================ FILE: vendor/decNumber/decimal64.h ================================================ /* ------------------------------------------------------------------ */ /* Decimal 64-bit format module header */ /* ------------------------------------------------------------------ */ /* Copyright (c) IBM Corporation, 2000, 2005. All rights reserved. */ /* */ /* This software is made available under the terms of the */ /* ICU License -- ICU 1.8.1 and later. */ /* */ /* The description and User's Guide ("The decNumber C Library") for */ /* this software is called decNumber.pdf. This document is */ /* available, together with arithmetic and format specifications, */ /* testcases, and Web links, on the General Decimal Arithmetic page. */ /* */ /* Please send comments, suggestions, and corrections to the author: */ /* mfc@uk.ibm.com */ /* Mike Cowlishaw, IBM Fellow */ /* IBM UK, PO Box 31, Birmingham Road, Warwick CV34 5JL, UK */ /* ------------------------------------------------------------------ */ #if !defined(DECIMAL64) #define DECIMAL64 #define DEC64NAME "decimal64" /* Short name */ #define DEC64FULLNAME "Decimal 64-bit Number" /* Verbose name */ #define DEC64AUTHOR "Mike Cowlishaw" /* Who to blame */ /* parameters for decimal64s */ #define DECIMAL64_Bytes 8 /* length */ #define DECIMAL64_Pmax 16 /* maximum precision (digits) */ #define DECIMAL64_Emax 384 /* maximum adjusted exponent */ #define DECIMAL64_Emin -383 /* minimum adjusted exponent */ #define DECIMAL64_Bias 398 /* bias for the exponent */ #define DECIMAL64_String 24 /* maximum string length, +1 */ #define DECIMAL64_EconL 8 /* exp. continuation length */ /* highest biased exponent (Elimit-1) */ #define DECIMAL64_Ehigh (DECIMAL64_Emax+DECIMAL64_Bias-DECIMAL64_Pmax+1) /* check enough digits, if pre-defined */ #if defined(DECNUMDIGITS) #if (DECNUMDIGITS=16 for safe use #endif #endif #ifndef DECNUMDIGITS #define DECNUMDIGITS DECIMAL64_Pmax /* size if not already defined*/ #endif #ifndef DECNUMBER #include "decNumber.h" /* context and number library */ #endif /* Decimal 64-bit type, accessible by bytes */ typedef struct { uint8_t bytes[DECIMAL64_Bytes]; /* decimal64: 1, 5, 8, 50 bits*/ } decimal64; /* special values [top byte excluding sign bit; last two bits are */ /* don't-care for Infinity on input, last bit don't-care for NaN] */ #if !defined(DECIMAL_NaN) #define DECIMAL_NaN 0x7c /* 0 11111 00 NaN */ #define DECIMAL_sNaN 0x7e /* 0 11111 10 sNaN */ #define DECIMAL_Inf 0x78 /* 0 11110 00 Infinity */ #endif /* ---------------------------------------------------------------- */ /* Routines */ /* ---------------------------------------------------------------- */ /* String conversions */ decimal64 * decimal64FromString(decimal64 *, const char *, decContext *); char * decimal64ToString(const decimal64 *, char *); char * decimal64ToEngString(const decimal64 *, char *); /* decNumber conversions */ decimal64 * decimal64FromNumber(decimal64 *, const decNumber *, decContext *); decNumber * decimal64ToNumber(const decimal64 *, decNumber *); /* Format-dependent utilities */ uint32_t decimal64IsCanonical(const decimal64 *); decimal64 * decimal64Canonical(decimal64 *, const decimal64 *); #endif ================================================ FILE: vendor/decNumber/example1.c ================================================ /* ------------------------------------------------------------------ */ /* Decimal Number Library Demonstration program */ /* ------------------------------------------------------------------ */ /* Copyright (c) IBM Corporation, 2001, 2007. All rights reserved. */ /* ----------------------------------------------------------------+- */ /* right margin -->| */ // example1.c -- convert the first two argument words to decNumber, // add them together, and display the result #define DECNUMDIGITS 34 // work with up to 34 digits #include "decNumber.h" // base number library #include // for printf int main(int argc, char *argv[]) { decNumber a, b; // working numbers decContext set; // working context char string[DECNUMDIGITS+14]; // conversion buffer decContextTestEndian(0); // warn if DECLITEND is wrong if (argc<3) { // not enough words printf("Please supply two numbers to add.\n"); return 1; } decContextDefault(&set, DEC_INIT_BASE); // initialize set.traps=0; // no traps, thank you set.digits=DECNUMDIGITS; // set precision decNumberFromString(&a, argv[1], &set); decNumberFromString(&b, argv[2], &set); decNumberAdd(&a, &a, &b, &set); // a=a+b decNumberToString(&a, string); printf("%s + %s => %s\n", argv[1], argv[2], string); return 0; } // main ================================================ FILE: vendor/decNumber/example2.c ================================================ /* ------------------------------------------------------------------ */ /* Decimal Number Library Demonstration program */ /* ------------------------------------------------------------------ */ /* Copyright (c) IBM Corporation, 2001. All rights reserved. */ /* ----------------------------------------------------------------+- */ /* right margin -->| */ // example2.c -- calculate compound interest // Arguments are investment, rate (%), and years #define DECNUMDIGITS 38 // work with up to 38 digits #include "decNumber.h" // base number library #include // for printf int main(int argc, char *argv[]) { int need=3; if (argc %s\n", argv[1], argv[2], argv[3], string); } //---------------------------------------------------------------| return 0; } // main ================================================ FILE: vendor/decNumber/example3.c ================================================ /* ------------------------------------------------------------------ */ /* Decimal Number Library Demonstration program */ /* ------------------------------------------------------------------ */ /* Copyright (c) IBM Corporation, 2001. All rights reserved. */ /* ----------------------------------------------------------------+- */ /* right margin -->| */ // example3.c -- calculate compound interest, passive checking // Arguments are investment, rate (%), and years #define DECNUMDIGITS 38 // work with up to 38 digits #include "decNumber.h" // base number library #include // for printf int main(int argc, char *argv[]) { int need=3; if (argc %s\n", argv[1], argv[2], argv[3], string); } //---------------------------------------------------------------| return 0; } // main ================================================ FILE: vendor/decNumber/example4.c ================================================ /* ------------------------------------------------------------------ */ /* Decimal Number Library Demonstration program */ /* ------------------------------------------------------------------ */ /* Copyright (c) IBM Corporation, 2001. All rights reserved. */ /* ----------------------------------------------------------------+- */ /* right margin -->| */ // example4.c -- add two numbers, active error handling // Arguments are two numbers #define DECNUMDIGITS 38 // work with up to 38 digits #include "decNumber.h" // base number library #include // for printf // [snip... #include // signal handling #include // setjmp/longjmp jmp_buf preserve; // stack snapshot void signalHandler(int); // prototype for GCC void signalHandler(int sig) { signal(SIGFPE, signalHandler); // re-enable longjmp(preserve, sig); // branch to preserved point } // ...snip] int main(int argc, char *argv[]) { decNumber a, b; // working numbers decContext set; // working context char string[DECNUMDIGITS+14]; // conversion buffer int value; // work variable if (argc<3) { // not enough words printf("Please supply two numbers to add.\n"); return 1; } decContextDefault(&set, DEC_INIT_BASE); // initialize // [snip... signal(SIGFPE, signalHandler); // set up signal handler value=setjmp(preserve); // preserve and test environment if (value) { // (non-0 after longjmp) set.status &= DEC_Errors; // keep only errors printf("Signal trapped [%s].\n", decContextStatusToString(&set)); return 1; } // ...snip] // [change from Example 1, here] // leave traps enabled set.digits=DECNUMDIGITS; // set precision decNumberFromString(&a, argv[1], &set); decNumberFromString(&b, argv[2], &set); decNumberAdd(&a, &a, &b, &set); // A=A+B decNumberToString(&a, string); printf("%s + %s => %s\n", argv[1], argv[2], string); return 0; } // main ================================================ FILE: vendor/decNumber/example5.c ================================================ /* ------------------------------------------------------------------ */ /* Decimal Number Library Demonstration program */ /* ------------------------------------------------------------------ */ /* Copyright (c) IBM Corporation, 2001, 2007. All rights reserved. */ /* ----------------------------------------------------------------+- */ /* right margin -->| */ // example5.c -- decimal64 conversions #include "decimal64.h" // decimal64 and decNumber library #include // for (s)printf int main(int argc, char *argv[]) { decimal64 a; // working decimal64 number decNumber d; // working number decContext set; // working context char string[DECIMAL64_String]; // number->string buffer char hexes[25]; // decimal64->hex buffer int i; // counter if (argc<2) { // not enough words printf("Please supply a number.\n"); return 1; } decContextDefault(&set, DEC_INIT_DECIMAL64); // initialize decimal64FromString(&a, argv[1], &set); // lay out the decimal64 as eight hexadecimal pairs for (i=0; i<8; i++) { sprintf(&hexes[i*3], "%02x ", a.bytes[i]); } decimal64ToNumber(&a, &d); decNumberToString(&d, string); printf("%s => %s=> %s\n", argv[1], hexes, string); return 0; } // main ================================================ FILE: vendor/decNumber/example6.c ================================================ /* ------------------------------------------------------------------ */ /* Decimal Number Library Demonstration program */ /* ------------------------------------------------------------------ */ /* Copyright (c) IBM Corporation, 2001. All rights reserved. */ /* ----------------------------------------------------------------+- */ /* right margin -->| */ // example6.c -- calculate compound interest, using Packed Decimal // Values are investment, rate (%), and years #include "decPacked.h" // base number library #include // for printf int main(int argc, char *argv[]) { { // excerpt for User's Guide starts here--------------------------| decNumber one, mtwo, hundred; // constants decNumber start, rate, years; // parameters decNumber total; // result decContext set; // working context uint8_t startpack[]={0x01, 0x00, 0x00, 0x0C}; // investment=100000 int32_t startscale=0; uint8_t ratepack[]={0x06, 0x5C}; // rate=6.5% int32_t ratescale=1; uint8_t yearspack[]={0x02, 0x0C}; // years=20 int32_t yearsscale=0; uint8_t respack[16]; // result, packed int32_t resscale; // .. char hexes[49]; // for packed->hex int i; // counter if (argc<0) printf("%s", argv[1]); // noop for warning decContextDefault(&set, DEC_INIT_BASE); // initialize set.traps=0; // no traps set.digits=25; // precision 25 decNumberFromString(&one, "1", &set); // set constants decNumberFromString(&mtwo, "-2", &set); decNumberFromString(&hundred, "100", &set); decPackedToNumber(startpack, sizeof(startpack), &startscale, &start); decPackedToNumber(ratepack, sizeof(ratepack), &ratescale, &rate); decPackedToNumber(yearspack, sizeof(yearspack), &yearsscale, &years); decNumberDivide(&rate, &rate, &hundred, &set); // rate=rate/100 decNumberAdd(&rate, &rate, &one, &set); // rate=rate+1 decNumberPower(&rate, &rate, &years, &set); // rate=rate^years decNumberMultiply(&total, &rate, &start, &set); // total=rate*start decNumberRescale(&total, &total, &mtwo, &set); // two digits please decPackedFromNumber(respack, sizeof(respack), &resscale, &total); // lay out the total as sixteen hexadecimal pairs for (i=0; i<16; i++) { sprintf(&hexes[i*3], "%02x ", respack[i]); } printf("Result: %s (scale=%ld)\n", hexes, (long int)resscale); } //---------------------------------------------------------------| return 0; } // main ================================================ FILE: vendor/decNumber/example7.c ================================================ /* ------------------------------------------------------------------ */ /* Decimal Number Library Demonstration program */ /* ------------------------------------------------------------------ */ /* Copyright (c) IBM Corporation, 2001, 2008. All rights reserved. */ /* ----------------------------------------------------------------+- */ /* right margin -->| */ // example7.c -- using decQuad to add two numbers together // compile: example7.c decContext.c decQuad.c #include "decQuad.h" // decQuad library #include // for printf int main(int argc, char *argv[]) { decQuad a, b; // working decQuads decContext set; // working context char string[DECQUAD_String]; // number->string buffer decContextTestEndian(0); // warn if DECLITEND is wrong if (argc<3) { // not enough words printf("Please supply two numbers to add.\n"); return 1; } decContextDefault(&set, DEC_INIT_DECQUAD); // initialize decQuadFromString(&a, argv[1], &set); decQuadFromString(&b, argv[2], &set); decQuadAdd(&a, &a, &b, &set); // a=a+b decQuadToString(&a, string); printf("%s + %s => %s\n", argv[1], argv[2], string); return 0; } // main ================================================ FILE: vendor/decNumber/example8.c ================================================ /* ------------------------------------------------------------------ */ /* Decimal Number Library Demonstration program */ /* ------------------------------------------------------------------ */ /* Copyright (c) IBM Corporation, 2001, 2007. All rights reserved. */ /* ----------------------------------------------------------------+- */ /* right margin -->| */ // example8.c -- using decQuad with the decNumber module // compile: example8.c decContext.c decQuad.c // and: decNumber.c decimal128.c decimal64.c #include "decQuad.h" // decQuad library #include "decimal128.h" // interface to decNumber #include // for printf int main(int argc, char *argv[]) { decQuad a; // working decQuad decNumber numa, numb; // working decNumbers decContext set; // working context char string[DECQUAD_String]; // number->string buffer if (argc<3) { // not enough words printf("Please supply two numbers for power(2*a, b).\n"); return 1; } decContextDefault(&set, DEC_INIT_DECQUAD); // initialize decQuadFromString(&a, argv[1], &set); // get a decQuadAdd(&a, &a, &a, &set); // double a decQuadToNumber(&a, &numa); // convert to decNumber decNumberFromString(&numb, argv[2], &set); decNumberPower(&numa, &numa, &numb, &set); // numa=numa**numb decQuadFromNumber(&a, &numa, &set); // back via a Quad decQuadToString(&a, string); // .. printf("power(2*%s, %s) => %s\n", argv[1], argv[2], string); return 0; } // main ================================================ FILE: vendor/decNumber/readme.txt ================================================ This is the readme.txt for the decNumber package. It includes instructions for compiling and testing the package; please read them. --------------------------------------------------------------------- decNumber is distributed in two forms; as a complete package from the International Components for Unicode (ICU) site (under an as-is license), or as a collection of Open Source files from the GCC source repository (under the GPL license). If you are using the GCC files, you can obtain the documentation, the example files mentioned below, and this readme from the General Decimal Arithmetic web page -- http://speleotrove.com/decimal/ (the URL for the open source files is also linked from there). The ICU package --------------- The ICU package includes the files: * readme.txt (this file) * ICU-license.html * decNumber.pdf (documentation) * The .c and .h file for each module in the package (see the decNumber documentation), together with other included files. * The .c files for each of the examples (example1.c through example8.c). The ICU package is made available under the terms of the ICU License (ICU 1.8.1 and later) included in the package as ICU-license.html. Your use of that package indicates your acceptance of the terms and conditions of that Agreement. To use and check decNumber -------------------------- Please read the appropriate license and documentation before using this package. If you are upgrading an existing use of decNumber (with version <= 3.37) please read the Changes Appendix for later versions -- you may need to change the DECLITEND flag. 1. Compile and link example1.c, decNumber.c, and decContext.c For instance, use: gcc -o example1 example1.c decNumber.c decContext.c Note: If your compiler does not provide stdint.h or if your C compiler does not handle line comments (// ...), then see the User's Guide section in the documentation for further information (including a sample minimal stdint.h). The use of compiler optimization is strongly recommended (e.g., -O3 for GCC or /O2 for Visual Studio). 2. Run example1 with two numeric arguments, for example: example1 1.23 1.27 this should display: 1.23 + 1.27 => 2.50 3. Similarly, try the other examples, at will. Examples 2->4 require three files to be compiled, like Example 1. Example 5 requires decimal64.c in addition to the core modules. Example 6 requires decPacked.c in addition to the core modules. Example 7 requires only example7.c decContext.c and decQuad.c Example 8 requires example8.c, decContext.c, and decQuad.c, plus decNumber.c, decimal128.c, and decimal64.c (the latter for shared tables and code)