More tweaks for Actions. master
authorWayne Davison <wayne@opencoder.net>
Wed, 10 Apr 2024 20:12:52 +0000 (13:12 -0700)
committerWayne Davison <wayne@opencoder.net>
Wed, 10 Apr 2024 20:24:09 +0000 (13:24 -0700)
- When a .github/workflows/*.yml file changes, skip running unaffected
  builds.
- We need git to be installed for git-version.h generation.

49 files changed:
.cirrus.yml [deleted file]
.github/workflows/build.yml [deleted file]
.github/workflows/cygwin-build.yml [new file with mode: 0644]
.github/workflows/freebsd-build.yml [new file with mode: 0644]
.github/workflows/macos-build.yml [new file with mode: 0644]
.github/workflows/solaris-build.yml [new file with mode: 0644]
.github/workflows/ubuntu-build.yml [new file with mode: 0644]
INSTALL.md
Makefile.in
NEWS.md
README.md
acls.c
checksum.c
config.guess
config.sub
configure.ac
delete.c
exclude.c
fileio.c
flist.c
generator.c
latest-year.h
match.c
maybe-make-man
md-convert
options.c
packaging/auto-Makefile
packaging/lsb/rsync.spec
packaging/pkglib.py
packaging/pre-push [deleted file]
packaging/release-rsync
popt/lookup3.c [new file with mode: 0644]
popt/popt.c
popt/popt.h
popt/poptconfig.c
popt/popthelp.c
popt/poptint.c [new file with mode: 0644]
popt/poptint.h
popt/poptparse.c
popt/system.h
receiver.c
rsync.1.md
rsyncd.conf.5.md
support/install_deps_ubuntu.sh [new file with mode: 0755]
support/mnt-excl
support/rrsync
support/rrsync.1.md
util2.c
version.h

diff --git a/.cirrus.yml b/.cirrus.yml
deleted file mode 100644 (file)
index 33e2685..0000000
+++ /dev/null
@@ -1,23 +0,0 @@
-freebsd_task:
-  name: FreeBSD
-  freebsd_instance:
-    image_family: freebsd-13-1
-  env:
-    PATH: /usr/local/bin:$PATH
-  prep_script:
-    - dd if=/dev/zero of=/tmp/zpool bs=1M count=1024
-    - zpool create -m `pwd`/testtmp zpool /tmp/zpool
-    - pkg install -y bash autotools m4 xxhash zstd liblz4 wget
-    - wget -O git-version.h https://gist.githubusercontent.com/WayneD/c11243fa374fc64d4e42f2855c8e3827/raw/rsync-git-version.h
-  configure_script:
-    - CPPFLAGS=-I/usr/local/include/ LDFLAGS=-L/usr/local/lib/ ./configure --disable-md2man
-  make_script:
-    - make
-  install_script:
-    - make install
-  info_script:
-    - rsync --version
-  test_script:
-    - RSYNC_EXPECT_SKIPPED=acls-default,acls,crtimes,protected-regular make check
-  ssl_file_list_script:
-    - rsync-ssl --no-motd download.samba.org::rsyncftp/ || true
diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml
deleted file mode 100644 (file)
index 3439e18..0000000
+++ /dev/null
@@ -1,125 +0,0 @@
-name: build
-
-on:
-  push:
-    branches: [ master ]
-    paths-ignore: [ .cirrus.yml ]
-  pull_request:
-    branches: [ master ]
-    paths-ignore: [ .cirrus.yml ]
-  schedule:
-    - cron: '42 8 * * *'
-
-jobs:
-
-  ubuntu-build:
-    runs-on: ubuntu-20.04
-    steps:
-    - uses: actions/checkout@v3
-    - name: prep
-      run: |
-        sudo apt-get install acl libacl1-dev attr libattr1-dev liblz4-dev libzstd-dev libxxhash-dev python3-cmarkgfm openssl wget
-        wget -O git-version.h https://gist.githubusercontent.com/WayneD/c11243fa374fc64d4e42f2855c8e3827/raw/rsync-git-version.h
-        echo "/usr/local/bin" >>$GITHUB_PATH
-    - name: configure
-      run: ./configure --with-rrsync
-    - name: make
-      run: make
-    - name: install
-      run: sudo make install
-    - name: info
-      run: rsync --version
-    - name: check
-      run: sudo RSYNC_EXPECT_SKIPPED=crtimes make check
-    - name: check30
-      run: sudo RSYNC_EXPECT_SKIPPED=crtimes make check30
-    - name: check29
-      run: sudo RSYNC_EXPECT_SKIPPED=crtimes make check29
-    - name: ssl file list
-      run: rsync-ssl --no-motd download.samba.org::rsyncftp/ || true
-    - name: save artifact
-      uses: actions/upload-artifact@v3
-      with:
-        name: ubuntu-bin
-        path: |
-          rsync
-          rsync-ssl
-          rsync.1
-          rsync-ssl.1
-          rsyncd.conf.5
-          rrsync.1
-          rrsync
-
-  macos-build:
-    runs-on: macos-latest
-    steps:
-    - uses: actions/checkout@v3
-    - name: prep
-      run: |
-        brew install automake openssl xxhash zstd lz4 wget
-        sudo pip3 install commonmark
-        wget -O git-version.h https://gist.githubusercontent.com/WayneD/c11243fa374fc64d4e42f2855c8e3827/raw/rsync-git-version.h
-        echo "/usr/local/bin" >>$GITHUB_PATH
-    - name: configure
-      run: CPPFLAGS=-I/usr/local/opt/openssl/include/ LDFLAGS=-L/usr/local/opt/openssl/lib/ ./configure --with-rrsync
-    - name: make
-      run: make
-    - name: install
-      run: sudo make install
-    - name: info
-      run: rsync --version
-    - name: check
-      run: sudo RSYNC_EXPECT_SKIPPED=acls-default,chmod-temp-dir,chown-fake,devices-fake,dir-sgid,protected-regular,xattrs-hlink,xattrs make check
-    - name: ssl file list
-      run: rsync-ssl --no-motd download.samba.org::rsyncftp/ || true
-    - name: save artifact
-      uses: actions/upload-artifact@v3
-      with:
-        name: macos-bin
-        path: |
-          rsync
-          rsync-ssl
-          rsync.1
-          rsync-ssl.1
-          rsyncd.conf.5
-          rrsync.1
-          rrsync
-
-  cygwin-build:
-    runs-on: windows-2022
-    if: (github.event_name == 'schedule' || contains(github.event.head_commit.message, '[buildall]'))
-    steps:
-    - uses: actions/checkout@v3
-    - name: cygwin
-      run: choco install -y --no-progress cygwin cyg-get
-    - name: prep
-      run: |
-        cyg-get make autoconf automake gcc-core attr libattr-devel python39 python39-pip libzstd-devel liblz4-devel libssl-devel libxxhash0 libxxhash-devel
-        curl.exe -o git-version.h https://gist.githubusercontent.com/WayneD/c11243fa374fc64d4e42f2855c8e3827/raw/rsync-git-version.h
-        echo "C:/tools/cygwin/bin" >>$Env:GITHUB_PATH
-    - name: commonmark
-      run: bash -c 'python3 -mpip install --user commonmark'
-    - name: configure
-      run: bash -c './configure --with-rrsync'
-    - name: make
-      run: bash -c 'make'
-    - name: install
-      run: bash -c 'make install'
-    - name: info
-      run: bash -c '/usr/local/bin/rsync --version'
-    - name: check
-      run: bash -c 'RSYNC_EXPECT_SKIPPED=acls-default,acls,chown,devices,dir-sgid,protected-regular make check'
-    - name: ssl file list
-      run: bash -c 'PATH="/usr/local/bin:$PATH" rsync-ssl --no-motd download.samba.org::rsyncftp/ || true'
-    - name: save artifact
-      uses: actions/upload-artifact@v3
-      with:
-        name: cygwin-bin
-        path: |
-          rsync.exe
-          rsync-ssl
-          rsync.1
-          rsync-ssl.1
-          rsyncd.conf.5
-          rrsync.1
-          rrsync
diff --git a/.github/workflows/cygwin-build.yml b/.github/workflows/cygwin-build.yml
new file mode 100644 (file)
index 0000000..c6afb11
--- /dev/null
@@ -0,0 +1,56 @@
+name: Test rsync on Cygwin
+
+on:
+  push:
+    branches: [ master ]
+    paths-ignore:
+      - '.github/workflows/*.yml'
+      - '!.github/workflows/cygwin-build.yml'
+  pull_request:
+    branches: [ master ]
+    paths-ignore:
+      - '.github/workflows/*.yml'
+      - '!.github/workflows/cygwin-build.yml'
+  schedule:
+    - cron: '42 8 * * *'
+
+jobs:
+  test:
+    runs-on: windows-2022
+    name: Test rsync on Cygwin
+    steps:
+    - uses: actions/checkout@v4
+      with:
+        fetch-depth: 0
+    - name: cygwin
+      run: choco install -y --no-progress cygwin cyg-get
+    - name: prep
+      run: |
+        cyg-get make autoconf automake gcc-core attr libattr-devel python39 python39-pip libzstd-devel liblz4-devel libssl-devel libxxhash0 libxxhash-devel
+        echo "C:/tools/cygwin/bin" >>$Env:GITHUB_PATH
+    - name: commonmark
+      run: bash -c 'python3 -mpip install --user commonmark'
+    - name: configure
+      run: bash -c './configure --with-rrsync'
+    - name: make
+      run: bash -c 'make'
+    - name: install
+      run: bash -c 'make install'
+    - name: info
+      run: bash -c '/usr/local/bin/rsync --version'
+    - name: check
+      run: bash -c 'RSYNC_EXPECT_SKIPPED=acls-default,acls,chown,devices,dir-sgid,protected-regular make check'
+    - name: ssl file list
+      run: bash -c 'PATH="/usr/local/bin:$PATH" rsync-ssl --no-motd download.samba.org::rsyncftp/ || true'
+    - name: save artifact
+      uses: actions/upload-artifact@v3
+      with:
+        name: cygwin-bin
+        path: |
+          rsync.exe
+          rsync-ssl
+          rsync.1
+          rsync-ssl.1
+          rsyncd.conf.5
+          rrsync.1
+          rrsync
diff --git a/.github/workflows/freebsd-build.yml b/.github/workflows/freebsd-build.yml
new file mode 100644 (file)
index 0000000..1ac2238
--- /dev/null
@@ -0,0 +1,49 @@
+name: Test rsync on FreeBSD
+
+on:
+  push:
+    branches: [ master ]
+    paths-ignore:
+      - '.github/workflows/*.yml'
+      - '!.github/workflows/freebsd-build.yml'
+  pull_request:
+    branches: [ master ]
+    paths-ignore:
+      - '.github/workflows/*.yml'
+      - '!.github/workflows/freebsd-build.yml'
+  schedule:
+    - cron: '42 8 * * *'
+
+jobs:
+  test:
+    runs-on: ubuntu-latest
+    name: Test rsync on FreeBSD
+    steps:
+    - uses: actions/checkout@v4
+      with:
+        fetch-depth: 0
+    - name: Test in FreeBSD VM
+      id: test
+      uses: vmactions/freebsd-vm@v1
+      with:
+        usesh: true
+        prepare: |
+          pkg install -y bash autotools m4 devel/xxhash zstd liblz4 python3 archivers/liblz4 git
+        run: |
+          freebsd-version
+          ./configure --with-rrsync -disable-zstd --disable-md2man --disable-xxhash --disable-lz4
+          make
+          ./rsync --version
+          ./rsync-ssl --no-motd download.samba.org::rsyncftp/ || true
+    - name: save artifact
+      uses: actions/upload-artifact@v3
+      with:
+        name: freebsd-bin
+        path: |
+          rsync
+          rsync-ssl
+          rsync.1
+          rsync-ssl.1
+          rsyncd.conf.5
+          rrsync.1
+          rrsync
diff --git a/.github/workflows/macos-build.yml b/.github/workflows/macos-build.yml
new file mode 100644 (file)
index 0000000..5471bf5
--- /dev/null
@@ -0,0 +1,53 @@
+name: Test rsync on macOS
+
+on:
+  push:
+    branches: [ master ]
+    paths-ignore:
+      - '.github/workflows/*.yml'
+      - '!.github/workflows/macos-build.yml'
+  pull_request:
+    branches: [ master ]
+    paths-ignore:
+      - '.github/workflows/*.yml'
+      - '!.github/workflows/macos-build.yml'
+  schedule:
+    - cron: '42 8 * * *'
+
+jobs:
+  test:
+    runs-on: macos-latest
+    name: Test rsync on macOS
+    steps:
+    - uses: actions/checkout@v4
+      with:
+        fetch-depth: 0
+    - name: prep
+      run: |
+        brew install automake openssl xxhash zstd lz4
+        sudo pip3 install commonmark
+        echo "/usr/local/bin" >>$GITHUB_PATH
+    - name: configure
+      run: CPPFLAGS=-I/usr/local/opt/openssl/include/ LDFLAGS=-L/usr/local/opt/openssl/lib/ ./configure --with-rrsync
+    - name: make
+      run: make
+    - name: install
+      run: sudo make install
+    - name: info
+      run: rsync --version
+    - name: check
+      run: sudo RSYNC_EXPECT_SKIPPED=acls-default,chmod-temp-dir,chown-fake,devices-fake,dir-sgid,protected-regular,xattrs-hlink,xattrs make check
+    - name: ssl file list
+      run: rsync-ssl --no-motd download.samba.org::rsyncftp/ || true
+    - name: save artifact
+      uses: actions/upload-artifact@v3
+      with:
+        name: macos-bin
+        path: |
+          rsync
+          rsync-ssl
+          rsync.1
+          rsync-ssl.1
+          rsyncd.conf.5
+          rrsync.1
+          rrsync
diff --git a/.github/workflows/solaris-build.yml b/.github/workflows/solaris-build.yml
new file mode 100644 (file)
index 0000000..231fbd4
--- /dev/null
@@ -0,0 +1,49 @@
+name: Test rsync on Solaris
+
+on:
+  push:
+    branches: [ master ]
+    paths-ignore:
+      - '.github/workflows/*.yml'
+      - '!.github/workflows/solaris-build.yml'
+  pull_request:
+    branches: [ master ]
+    paths-ignore:
+      - '.github/workflows/*.yml'
+      - '!.github/workflows/solaris-build.yml'
+  schedule:
+    - cron: '42 8 * * *'
+
+jobs:
+  test:
+    runs-on: ubuntu-latest
+    name: Test rsync on Solaris
+    steps:
+    - uses: actions/checkout@v4
+      with:
+        fetch-depth: 0
+    - name: Test in Solaris VM
+      id: test
+      uses: vmactions/solaris-vm@v1
+      with:
+        usesh: true
+        prepare: |
+          pkg install bash automake gnu-m4 pkg://solaris/runtime/python-35 autoconf gcc git
+        run: |
+          uname -a
+          ./configure --with-rrsync -disable-zstd --disable-md2man --disable-xxhash --disable-lz4
+          make
+          ./rsync --version
+          ./rsync-ssl --no-motd download.samba.org::rsyncftp/ || true
+    - name: save artifact
+      uses: actions/upload-artifact@v3
+      with:
+        name: solaris-bin
+        path: |
+          rsync
+          rsync-ssl
+          rsync.1
+          rsync-ssl.1
+          rsyncd.conf.5
+          rrsync.1
+          rrsync
diff --git a/.github/workflows/ubuntu-build.yml b/.github/workflows/ubuntu-build.yml
new file mode 100644 (file)
index 0000000..1db9a48
--- /dev/null
@@ -0,0 +1,56 @@
+name: Test rsync on Ubuntu
+
+on:
+  push:
+    branches: [ master ]
+    paths-ignore:
+      - '.github/workflows/*.yml'
+      - '!.github/workflows/ubuntu-build.yml'
+  pull_request:
+    branches: [ master ]
+    paths-ignore:
+      - '.github/workflows/*.yml'
+      - '!.github/workflows/ubuntu-build.yml'
+  schedule:
+    - cron: '42 8 * * *'
+
+jobs:
+  test:
+    runs-on: ubuntu-20.04
+    name: Test rsync on Ubuntu
+    steps:
+    - uses: actions/checkout@v4
+      with:
+        fetch-depth: 0
+    - name: prep
+      run: |
+        sudo apt-get install acl libacl1-dev attr libattr1-dev liblz4-dev libzstd-dev libxxhash-dev python3-cmarkgfm openssl
+        echo "/usr/local/bin" >>$GITHUB_PATH
+    - name: configure
+      run: ./configure --with-rrsync
+    - name: make
+      run: make
+    - name: install
+      run: sudo make install
+    - name: info
+      run: rsync --version
+    - name: check
+      run: sudo RSYNC_EXPECT_SKIPPED=crtimes make check
+    - name: check30
+      run: sudo RSYNC_EXPECT_SKIPPED=crtimes make check30
+    - name: check29
+      run: sudo RSYNC_EXPECT_SKIPPED=crtimes make check29
+    - name: ssl file list
+      run: rsync-ssl --no-motd download.samba.org::rsyncftp/ || true
+    - name: save artifact
+      uses: actions/upload-artifact@v3
+      with:
+        name: ubuntu-bin
+        path: |
+          rsync
+          rsync-ssl
+          rsync.1
+          rsync-ssl.1
+          rsyncd.conf.5
+          rrsync.1
+          rrsync
index 1605ab435e00f83329e7a52b714a38fdb3396105..8ef574a543cd62da8b2c699e1c08caf8824cb68f 100644 (file)
@@ -104,6 +104,8 @@ like.
     >     sudo apt install -y liblz4-dev
     >     sudo apt install -y libssl-dev
 
+Or run support/install_deps_ubuntu.sh
+
  -  For CentOS (use EPEL for python3-pip):
 
     >     sudo yum -y install epel-release
index a1253e5d5f2da51adad1d6ddb60477464aa49196..d5fefe0456b25b2563247cf393263feebb9bc50c 100644 (file)
@@ -50,7 +50,7 @@ OBJS2=options.o io.o compat.o hlink.o token.o uidlist.o socket.o hashtable.o \
 OBJS3=progress.o pipe.o @MD5_ASM@ @ROLL_SIMD@ @ROLL_ASM@
 DAEMON_OBJ = params.o loadparm.o clientserver.o access.o connection.o authenticate.o
 popt_OBJS=popt/findme.o  popt/popt.o  popt/poptconfig.o \
-       popt/popthelp.o popt/poptparse.o
+       popt/popthelp.o popt/poptparse.o popt/poptint.o
 OBJS=$(OBJS1) $(OBJS2) $(OBJS3) $(DAEMON_OBJ) $(LIBOBJ) @BUILD_ZLIB@ @BUILD_POPT@
 
 TLS_OBJ = tls.o syscall.o util2.o t_stub.o lib/compat.o lib/snprintf.o lib/permstring.o lib/sysxattrs.o @BUILD_POPT@
@@ -184,14 +184,6 @@ conf: configure.sh config.h.in
 .PHONY: gen
 gen: conf proto.h man git-version.h
 
-.PHONY: gensend
-gensend: gen
-       if ! diff git-version.h $(srcdir)/gists/rsync-git-version.h >/dev/null; then \
-           ./rsync -ai git-version.h $(srcdir)/gists/rsync-git-version.h && \
-           (cd $(srcdir)/gists && git commit --allow-empty-message -m '' rsync-git-version.h && git push) ; \
-       fi
-       rsync -aic $(GENFILES) git-version.h $${SAMBA_HOST-samba.org}:/home/ftp/pub/rsync/generated-files/ || true
-
 aclocal.m4: $(srcdir)/m4/*.m4
        aclocal -I $(srcdir)/m4
 
diff --git a/NEWS.md b/NEWS.md
index 555d16f59926c6b849c8b3c4a36ede0cd29efac0..1a88a70d948464024e5f06b160012151213896b7 100644 (file)
--- a/NEWS.md
+++ b/NEWS.md
@@ -1,3 +1,82 @@
+# NEWS for rsync 3.3.1 (UNRELEASED)
+
+## Changes in this version:
+
+### BUG FIXES:
+
+- Fixed the included popt to avoid a memory error on modern gcc versions.
+
+### INTERNAL:
+
+ - Updated included popt to version 1.19.
+
+------------------------------------------------------------------------------
+
+# NEWS for rsync 3.3.0 (6 Apr 2024)
+
+## Changes in this version:
+
+### BUG FIXES:
+
+- Fixed a bug with `--sparse --inplace` where a trailing gap in the source
+  file would not clear out the trailing data in the destination file.
+
+- Fixed an buffer overflow in the checksum2 code if SHA1 is being used for
+  the checksum2 algorithm.
+
+- Fixed an issue when rsync is compiled using `_FORTIFY_SOURCE` so that the
+  extra tests don't complain about a strlcpy() limit value (which was too
+  large, even though it wasn't possible for the larger value to cause an
+  overflow).
+
+- Add a backtick to the list of characters that the filename quoting needs to
+  escape using backslashes.
+
+- Fixed a string-comparison issue in the internal handling of `--progress` (a
+  locale such as tr_TR.utf-8 needed the internal triggering of `--info` options
+  to use upper-case flag names to ensure that they match).
+
+- Make sure that a local transfer marks the sender side as trusted.
+
+- Change the argv handling to work with a newer popt library -- one that likes
+  to free more data than it used to.
+
+- Rsync now calls `OpenSSL_add_all_algorithms()` when compiled against an older
+  openssl library.
+
+- Fixed a problem in the daemon auth for older protocols (29 and before) if the
+  openssl library is being used to compute MD4 checksums.
+
+- Fixed `rsync -VV` on Cygwin -- it needed a flush of stdout.
+
+- Fixed an old stats bug that counted devices as symlinks.
+
+### ENHANCEMENTS:
+
+- Enhanced rrsync with the `-no-overwrite` option that allows you to ensure
+  that existing files on your restricted but writable directory can't be
+  modified.
+
+- Enhanced the manpages to mark links with .UR & .UE. If your nroff doesn't
+  support these idioms, touch the file `.md2man-force` in the source directory
+  so that `md-convert` gets called with the `--force-link-text` option, and
+  that should ensure that your manpages are still readable even with the
+  ignored markup.
+
+- Some manpage improvements on the handling of [global] modules.
+
+- Changed the mapfrom & mapto perl scripts (in the support dir) into a single
+  python script named idmap.  Converted a couple more perl scripts into python.
+
+- Changed the mnt-excl perl script (in the support dir) into a python script.
+
+### DEVELOPER RELATED:
+
+ - Updated config.guess (timestamp 2023-01-01) and config.sub (timestamp
+   2023-01-21).
+
+------------------------------------------------------------------------------
+
 # NEWS for rsync 3.2.7 (20 Oct 2022)
 
 ## Changes in this version:
 
 - The `--fuzzy` option was optimized a bit to try to cut down on the amount of
   computations when considering a big pool of files. The simple heuristic from
-  Kenneth Finnegan resuled in about a 2x speedup.
+  Kenneth Finnegan resulted in about a 2x speedup.
 
 - If rsync is forced to use protocol 29 or before (perhaps due to talking to an
   rsync before 3.0.0), the modify time of a file is limited to 4-bytes.  Rsync
  - A new form of arg protection was added that works similarly to the older
    `--protect-args` ([`-s`](rsync.1#opt)) option but in a way that avoids
    breaking things like rrsync (the restricted rsync script): rsync now uses
-   backslash escaping for sending "shell-active" characters to the remote
-   shell. This includes spaces, so fetching a remote file via a simple quoted
-   filename value now works by default without any extra quoting:
+   backslash escaping for sending "shell-active" characters to the remote shell
+   (such as `$(){}<>#&` and others). This includes spaces, so fetching a remote
+   file via a quoted filename value now works by default without any extra
+   quoting:
 
    ```shell
        rsync -aiv host:'a simple file.pdf' .
 
 | RELEASE DATE | VER.   | DATE OF COMMIT\* | PROTOCOL    |
 |--------------|--------|------------------|-------------|
+| ?? Apr 2024  | 3.3.1  |                  | 31          |
+| 06 Apr 2024  | 3.3.0  |                  | 31          |
 | 20 Oct 2022  | 3.2.7  |                  | 31          |
 | 09 Sep 2022  | 3.2.6  |                  | 31          |
 | 14 Aug 2022  | 3.2.5  |                  | 31          |
index a86c77105dca0afaf629e64b5037cca4bb998a64..82db21575fd8f2ded047d50621bd5f0fc9602419 100644 (file)
--- a/README.md
+++ b/README.md
@@ -34,7 +34,7 @@ If you need to build rsync yourself, check out the [INSTALL][1] page for
 information on what libraries and packages you can use to get the maximum
 features in your build.
 
-[1]: https://github.com/WayneD/rsync/blob/master/INSTALL.md
+[1]: https://github.com/RsyncProject/rsync/blob/master/INSTALL.md
 
 SETUP
 -----
@@ -120,7 +120,7 @@ If you want to get the very latest version of rsync direct from the
 source code repository, then you will need to use git.  The git repo
 is hosted [on GitHub][6] and [on Samba's site][7].
 
-[6]: https://github.com/WayneD/rsync
+[6]: https://github.com/RsyncProject/rsync
 [7]: https://git.samba.org/?p=rsync.git;a=summary
 
 See [the download page][8] for full details on all the ways to grab the
@@ -132,13 +132,12 @@ source.
 COPYRIGHT
 ---------
 
-Rsync was originally written by Andrew Tridgell and is currently
-maintained by Wayne Davison.  It has been improved by many developers
-from around the world.
+Rsync was originally written by Andrew Tridgell and Paul Mackerras.  Many
+people from around the world have helped to maintain and improve it.
 
 Rsync may be used, modified and redistributed only under the terms of
 the GNU General Public License, found in the file [COPYING][9] in this
 distribution, or at [the Free Software Foundation][10].
 
-[9]: https://github.com/WayneD/rsync/blob/master/COPYING
+[9]: https://github.com/RsyncProject/rsync/blob/master/COPYING
 [10]: https://www.fsf.org/licenses/gpl.html
diff --git a/acls.c b/acls.c
index 3cf12eeb07c42238b81236850618bd8c2b1b23ba..a2b0ff3ec683aa29de5fbad96f83eb2e2d9fd7c8 100644 (file)
--- a/acls.c
+++ b/acls.c
@@ -765,6 +765,7 @@ static int recv_rsync_acl(int f, item_list *racl_list, SMB_ACL_TYPE_T type, mode
        /* If we received a superfluous mask, throw it away. */
        duo_item->racl.mask_obj = NO_ENTRY;
        (void)mode;
+       (void)computed_mask_bits;
 #else
        if (duo_item->racl.names.count && duo_item->racl.mask_obj == NO_ENTRY) {
                /* Mask must be non-empty with lists. */
index c6007f36895bba698667377b1f787ea1d1444a95..cb21882c5695dff6c3447e1e6da89c4840722162 100644 (file)
@@ -3,7 +3,7 @@
  *
  * Copyright (C) 1996 Andrew Tridgell
  * Copyright (C) 1996 Paul Mackerras
- * Copyright (C) 2004-2022 Wayne Davison
+ * Copyright (C) 2004-2023 Wayne Davison
  *
  * 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
@@ -300,6 +300,7 @@ uint32 get_checksum1(char *buf1, int32 len)
 }
 #endif
 
+/* The "sum" buffer must be at least MAX_DIGEST_LEN bytes! */
 void get_checksum2(char *buf, int32 len, char *sum)
 {
 #ifdef USE_OPENSSL
index 92bfc33e2962a5837b25f736d8ded00ae4bf81a5..69188da73d74371bc500cc82b4d00a583e21ef3d 100644 (file)
@@ -1,12 +1,14 @@
 #! /bin/sh
 # Attempt to guess a canonical system name.
-#   Copyright 1992-2020 Free Software Foundation, Inc.
+#   Copyright 1992-2023 Free Software Foundation, Inc.
 
-timestamp='2020-04-26'
+# shellcheck disable=SC2006,SC2268 # see below for rationale
+
+timestamp='2023-01-01'
 
 # This file 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
+# 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
@@ -27,11 +29,19 @@ timestamp='2020-04-26'
 # Originally written by Per Bothner; maintained since 2000 by Ben Elliston.
 #
 # You can get the latest version of this script from:
-# https://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.guess
+# https://git.savannah.gnu.org/cgit/config.git/plain/config.guess
 #
 # Please send patches to <config-patches@gnu.org>.
 
 
+# The "shellcheck disable" line above the timestamp inhibits complaints
+# about features and limitations of the classic Bourne shell that were
+# superseded or lifted in POSIX.  However, this script identifies a wide
+# variety of pre-POSIX systems that do not have POSIX shells at all, and
+# even some reasonably current systems (Solaris 10 as case-in-point) still
+# have a pre-POSIX /bin/sh.
+
+
 me=`echo "$0" | sed -e 's,.*/,,'`
 
 usage="\
@@ -50,7 +60,7 @@ version="\
 GNU config.guess ($timestamp)
 
 Originally written by Per Bothner.
-Copyright 1992-2020 Free Software Foundation, Inc.
+Copyright 1992-2023 Free Software Foundation, Inc.
 
 This is free software; see the source for copying conditions.  There is NO
 warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE."
@@ -84,6 +94,9 @@ if test $# != 0; then
   exit 1
 fi
 
+# Just in case it came from the environment.
+GUESS=
+
 # CC_FOR_BUILD -- compiler used by this script. Note that the use of a
 # compiler to aid in system detection is discouraged as it requires
 # temporary files to be created and, as you can see below, it is a
@@ -102,7 +115,7 @@ set_cc_for_build() {
     # prevent multiple calls if $tmp is already set
     test "$tmp" && return 0
     : "${TMPDIR=/tmp}"
-    # shellcheck disable=SC2039
+    # shellcheck disable=SC2039,SC3028
     { tmp=`(umask 077 && mktemp -d "$TMPDIR/cgXXXXXX") 2>/dev/null` && test -n "$tmp" && test -d "$tmp" ; } ||
        { test -n "$RANDOM" && tmp=$TMPDIR/cg$$-$RANDOM && (umask 077 && mkdir "$tmp" 2>/dev/null) ; } ||
        { tmp=$TMPDIR/cg-$$ && (umask 077 && mkdir "$tmp" 2>/dev/null) && echo "Warning: creating insecure temp directory" >&2 ; } ||
@@ -112,7 +125,7 @@ set_cc_for_build() {
        ,,)    echo "int x;" > "$dummy.c"
               for driver in cc gcc c89 c99 ; do
                   if ($driver -c -o "$dummy.o" "$dummy.c") >/dev/null 2>&1 ; then
-                      CC_FOR_BUILD="$driver"
+                      CC_FOR_BUILD=$driver
                       break
                   fi
               done
@@ -133,14 +146,12 @@ fi
 
 UNAME_MACHINE=`(uname -m) 2>/dev/null` || UNAME_MACHINE=unknown
 UNAME_RELEASE=`(uname -r) 2>/dev/null` || UNAME_RELEASE=unknown
-UNAME_SYSTEM=`(uname -s) 2>/dev/null`  || UNAME_SYSTEM=unknown
+UNAME_SYSTEM=`(uname -s) 2>/dev/null` || UNAME_SYSTEM=unknown
 UNAME_VERSION=`(uname -v) 2>/dev/null` || UNAME_VERSION=unknown
 
-case "$UNAME_SYSTEM" in
+case $UNAME_SYSTEM in
 Linux|GNU|GNU/*)
-       # If the system lacks a compiler, then just pick glibc.
-       # We could probably try harder.
-       LIBC=gnu
+       LIBC=unknown
 
        set_cc_for_build
        cat <<-EOF > "$dummy.c"
@@ -149,24 +160,37 @@ Linux|GNU|GNU/*)
        LIBC=uclibc
        #elif defined(__dietlibc__)
        LIBC=dietlibc
-       #else
+       #elif defined(__GLIBC__)
        LIBC=gnu
+       #else
+       #include <stdarg.h>
+       /* First heuristic to detect musl libc.  */
+       #ifdef __DEFINED_va_list
+       LIBC=musl
+       #endif
        #endif
        EOF
-       eval "`$CC_FOR_BUILD -E "$dummy.c" 2>/dev/null | grep '^LIBC' | sed 's, ,,g'`"
+       cc_set_libc=`$CC_FOR_BUILD -E "$dummy.c" 2>/dev/null | grep '^LIBC' | sed 's, ,,g'`
+       eval "$cc_set_libc"
 
-       # If ldd exists, use it to detect musl libc.
-       if command -v ldd >/dev/null && \
-               ldd --version 2>&1 | grep -q ^musl
-       then
-           LIBC=musl
+       # Second heuristic to detect musl libc.
+       if [ "$LIBC" = unknown ] &&
+          command -v ldd >/dev/null &&
+          ldd --version 2>&1 | grep -q ^musl; then
+               LIBC=musl
+       fi
+
+       # If the system lacks a compiler, then just pick glibc.
+       # We could probably try harder.
+       if [ "$LIBC" = unknown ]; then
+               LIBC=gnu
        fi
        ;;
 esac
 
 # Note: order is significant - the case branches are not exclusive.
 
-case "$UNAME_MACHINE:$UNAME_SYSTEM:$UNAME_RELEASE:$UNAME_VERSION" in
+case $UNAME_MACHINE:$UNAME_SYSTEM:$UNAME_RELEASE:$UNAME_VERSION in
     *:NetBSD:*:*)
        # NetBSD (nbsd) targets should (where applicable) match one or
        # more of the tuples: *-*-netbsdelf*, *-*-netbsdaout*,
@@ -178,12 +202,12 @@ case "$UNAME_MACHINE:$UNAME_SYSTEM:$UNAME_RELEASE:$UNAME_VERSION" in
        #
        # Note: NetBSD doesn't particularly care about the vendor
        # portion of the name.  We always set it to "unknown".
-       sysctl="sysctl -n hw.machine_arch"
        UNAME_MACHINE_ARCH=`(uname -p 2>/dev/null || \
-           "/sbin/$sysctl" 2>/dev/null || \
-           "/usr/sbin/$sysctl" 2>/dev/null || \
+           /sbin/sysctl -n hw.machine_arch 2>/dev/null || \
+           /usr/sbin/sysctl -n hw.machine_arch 2>/dev/null || \
            echo unknown)`
-       case "$UNAME_MACHINE_ARCH" in
+       case $UNAME_MACHINE_ARCH in
+           aarch64eb) machine=aarch64_be-unknown ;;
            armeb) machine=armeb-unknown ;;
            arm*) machine=arm-unknown ;;
            sh3el) machine=shl-unknown ;;
@@ -192,13 +216,13 @@ case "$UNAME_MACHINE:$UNAME_SYSTEM:$UNAME_RELEASE:$UNAME_VERSION" in
            earmv*)
                arch=`echo "$UNAME_MACHINE_ARCH" | sed -e 's,^e\(armv[0-9]\).*$,\1,'`
                endian=`echo "$UNAME_MACHINE_ARCH" | sed -ne 's,^.*\(eb\)$,\1,p'`
-               machine="${arch}${endian}"-unknown
+               machine=${arch}${endian}-unknown
                ;;
-           *) machine="$UNAME_MACHINE_ARCH"-unknown ;;
+           *) machine=$UNAME_MACHINE_ARCH-unknown ;;
        esac
        # The Operating System including object format, if it has switched
        # to ELF recently (or will in the future) and ABI.
-       case "$UNAME_MACHINE_ARCH" in
+       case $UNAME_MACHINE_ARCH in
            earm*)
                os=netbsdelf
                ;;
@@ -219,7 +243,7 @@ case "$UNAME_MACHINE:$UNAME_SYSTEM:$UNAME_RELEASE:$UNAME_VERSION" in
                ;;
        esac
        # Determine ABI tags.
-       case "$UNAME_MACHINE_ARCH" in
+       case $UNAME_MACHINE_ARCH in
            earm*)
                expr='s/^earmv[0-9]/-eabi/;s/eb$//'
                abi=`echo "$UNAME_MACHINE_ARCH" | sed -e "$expr"`
@@ -230,7 +254,7 @@ case "$UNAME_MACHINE:$UNAME_SYSTEM:$UNAME_RELEASE:$UNAME_VERSION" in
        # thus, need a distinct triplet. However, they do not need
        # kernel version information, so it can be replaced with a
        # suitable tag, in the style of linux-gnu.
-       case "$UNAME_VERSION" in
+       case $UNAME_VERSION in
            Debian*)
                release='-gnu'
                ;;
@@ -241,51 +265,57 @@ case "$UNAME_MACHINE:$UNAME_SYSTEM:$UNAME_RELEASE:$UNAME_VERSION" in
        # Since CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM:
        # contains redundant information, the shorter form:
        # CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM is used.
-       echo "$machine-${os}${release}${abi-}"
-       exit ;;
+       GUESS=$machine-${os}${release}${abi-}
+       ;;
     *:Bitrig:*:*)
        UNAME_MACHINE_ARCH=`arch | sed 's/Bitrig.//'`
-       echo "$UNAME_MACHINE_ARCH"-unknown-bitrig"$UNAME_RELEASE"
-       exit ;;
+       GUESS=$UNAME_MACHINE_ARCH-unknown-bitrig$UNAME_RELEASE
+       ;;
     *:OpenBSD:*:*)
        UNAME_MACHINE_ARCH=`arch | sed 's/OpenBSD.//'`
-       echo "$UNAME_MACHINE_ARCH"-unknown-openbsd"$UNAME_RELEASE"
-       exit ;;
+       GUESS=$UNAME_MACHINE_ARCH-unknown-openbsd$UNAME_RELEASE
+       ;;
+    *:SecBSD:*:*)
+       UNAME_MACHINE_ARCH=`arch | sed 's/SecBSD.//'`
+       GUESS=$UNAME_MACHINE_ARCH-unknown-secbsd$UNAME_RELEASE
+       ;;
     *:LibertyBSD:*:*)
        UNAME_MACHINE_ARCH=`arch | sed 's/^.*BSD\.//'`
-       echo "$UNAME_MACHINE_ARCH"-unknown-libertybsd"$UNAME_RELEASE"
-       exit ;;
+       GUESS=$UNAME_MACHINE_ARCH-unknown-libertybsd$UNAME_RELEASE
+       ;;
     *:MidnightBSD:*:*)
-       echo "$UNAME_MACHINE"-unknown-midnightbsd"$UNAME_RELEASE"
-       exit ;;
+       GUESS=$UNAME_MACHINE-unknown-midnightbsd$UNAME_RELEASE
+       ;;
     *:ekkoBSD:*:*)
-       echo "$UNAME_MACHINE"-unknown-ekkobsd"$UNAME_RELEASE"
-       exit ;;
+       GUESS=$UNAME_MACHINE-unknown-ekkobsd$UNAME_RELEASE
+       ;;
     *:SolidBSD:*:*)
-       echo "$UNAME_MACHINE"-unknown-solidbsd"$UNAME_RELEASE"
-       exit ;;
+       GUESS=$UNAME_MACHINE-unknown-solidbsd$UNAME_RELEASE
+       ;;
     *:OS108:*:*)
-       echo "$UNAME_MACHINE"-unknown-os108_"$UNAME_RELEASE"
-       exit ;;
+       GUESS=$UNAME_MACHINE-unknown-os108_$UNAME_RELEASE
+       ;;
     macppc:MirBSD:*:*)
-       echo powerpc-unknown-mirbsd"$UNAME_RELEASE"
-       exit ;;
+       GUESS=powerpc-unknown-mirbsd$UNAME_RELEASE
+       ;;
     *:MirBSD:*:*)
-       echo "$UNAME_MACHINE"-unknown-mirbsd"$UNAME_RELEASE"
-       exit ;;
+       GUESS=$UNAME_MACHINE-unknown-mirbsd$UNAME_RELEASE
+       ;;
     *:Sortix:*:*)
-       echo "$UNAME_MACHINE"-unknown-sortix
-       exit ;;
+       GUESS=$UNAME_MACHINE-unknown-sortix
+       ;;
     *:Twizzler:*:*)
-       echo "$UNAME_MACHINE"-unknown-twizzler
-       exit ;;
+       GUESS=$UNAME_MACHINE-unknown-twizzler
+       ;;
     *:Redox:*:*)
-       echo "$UNAME_MACHINE"-unknown-redox
-       exit ;;
+       GUESS=$UNAME_MACHINE-unknown-redox
+       ;;
     mips:OSF1:*.*)
-       echo mips-dec-osf1
-       exit ;;
+       GUESS=mips-dec-osf1
+       ;;
     alpha:OSF1:*:*)
+       # Reset EXIT trap before exiting to avoid spurious non-zero exit code.
+       trap '' 0
        case $UNAME_RELEASE in
        *4.0)
                UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $3}'`
@@ -299,7 +329,7 @@ case "$UNAME_MACHINE:$UNAME_SYSTEM:$UNAME_RELEASE:$UNAME_VERSION" in
        # covers most systems running today.  This code pipes the CPU
        # types through head -n 1, so we only detect the type of CPU 0.
        ALPHA_CPU_TYPE=`/usr/sbin/psrinfo -v | sed -n -e 's/^  The alpha \(.*\) processor.*$/\1/p' | head -n 1`
-       case "$ALPHA_CPU_TYPE" in
+       case $ALPHA_CPU_TYPE in
            "EV4 (21064)")
                UNAME_MACHINE=alpha ;;
            "EV4.5 (21064)")
@@ -336,117 +366,121 @@ case "$UNAME_MACHINE:$UNAME_SYSTEM:$UNAME_RELEASE:$UNAME_VERSION" in
        # A Tn.n version is a released field test version.
        # A Xn.n version is an unreleased experimental baselevel.
        # 1.2 uses "1.2" for uname -r.
-       echo "$UNAME_MACHINE"-dec-osf"`echo "$UNAME_RELEASE" | sed -e 's/^[PVTX]//' | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz`"
-       # Reset EXIT trap before exiting to avoid spurious non-zero exit code.
-       exitcode=$?
-       trap '' 0
-       exit $exitcode ;;
+       OSF_REL=`echo "$UNAME_RELEASE" | sed -e 's/^[PVTX]//' | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz`
+       GUESS=$UNAME_MACHINE-dec-osf$OSF_REL
+       ;;
     Amiga*:UNIX_System_V:4.0:*)
-       echo m68k-unknown-sysv4
-       exit ;;
+       GUESS=m68k-unknown-sysv4
+       ;;
     *:[Aa]miga[Oo][Ss]:*:*)
-       echo "$UNAME_MACHINE"-unknown-amigaos
-       exit ;;
+       GUESS=$UNAME_MACHINE-unknown-amigaos
+       ;;
     *:[Mm]orph[Oo][Ss]:*:*)
-       echo "$UNAME_MACHINE"-unknown-morphos
-       exit ;;
+       GUESS=$UNAME_MACHINE-unknown-morphos
+       ;;
     *:OS/390:*:*)
-       echo i370-ibm-openedition
-       exit ;;
+       GUESS=i370-ibm-openedition
+       ;;
     *:z/VM:*:*)
-       echo s390-ibm-zvmoe
-       exit ;;
+       GUESS=s390-ibm-zvmoe
+       ;;
     *:OS400:*:*)
-       echo powerpc-ibm-os400
-       exit ;;
+       GUESS=powerpc-ibm-os400
+       ;;
     arm:RISC*:1.[012]*:*|arm:riscix:1.[012]*:*)
-       echo arm-acorn-riscix"$UNAME_RELEASE"
-       exit ;;
+       GUESS=arm-acorn-riscix$UNAME_RELEASE
+       ;;
     arm*:riscos:*:*|arm*:RISCOS:*:*)
-       echo arm-unknown-riscos
-       exit ;;
+       GUESS=arm-unknown-riscos
+       ;;
     SR2?01:HI-UX/MPP:*:* | SR8000:HI-UX/MPP:*:*)
-       echo hppa1.1-hitachi-hiuxmpp
-       exit ;;
+       GUESS=hppa1.1-hitachi-hiuxmpp
+       ;;
     Pyramid*:OSx*:*:* | MIS*:OSx*:*:* | MIS*:SMP_DC-OSx*:*:*)
        # akee@wpdis03.wpafb.af.mil (Earle F. Ake) contributed MIS and NILE.
-       if test "`(/bin/universe) 2>/dev/null`" = att ; then
-               echo pyramid-pyramid-sysv3
-       else
-               echo pyramid-pyramid-bsd
-       fi
-       exit ;;
+       case `(/bin/universe) 2>/dev/null` in
+           att) GUESS=pyramid-pyramid-sysv3 ;;
+           *)   GUESS=pyramid-pyramid-bsd   ;;
+       esac
+       ;;
     NILE*:*:*:dcosx)
-       echo pyramid-pyramid-svr4
-       exit ;;
+       GUESS=pyramid-pyramid-svr4
+       ;;
     DRS?6000:unix:4.0:6*)
-       echo sparc-icl-nx6
-       exit ;;
+       GUESS=sparc-icl-nx6
+       ;;
     DRS?6000:UNIX_SV:4.2*:7* | DRS?6000:isis:4.2*:7*)
        case `/usr/bin/uname -p` in
-           sparc) echo sparc-icl-nx7; exit ;;
-       esac ;;
+           sparc) GUESS=sparc-icl-nx7 ;;
+       esac
+       ;;
     s390x:SunOS:*:*)
-       echo "$UNAME_MACHINE"-ibm-solaris2"`echo "$UNAME_RELEASE" | sed -e 's/[^.]*//'`"
-       exit ;;
+       SUN_REL=`echo "$UNAME_RELEASE" | sed -e 's/[^.]*//'`
+       GUESS=$UNAME_MACHINE-ibm-solaris2$SUN_REL
+       ;;
     sun4H:SunOS:5.*:*)
-       echo sparc-hal-solaris2"`echo "$UNAME_RELEASE"|sed -e 's/[^.]*//'`"
-       exit ;;
+       SUN_REL=`echo "$UNAME_RELEASE" | sed -e 's/[^.]*//'`
+       GUESS=sparc-hal-solaris2$SUN_REL
+       ;;
     sun4*:SunOS:5.*:* | tadpole*:SunOS:5.*:*)
-       echo sparc-sun-solaris2"`echo "$UNAME_RELEASE" | sed -e 's/[^.]*//'`"
-       exit ;;
+       SUN_REL=`echo "$UNAME_RELEASE" | sed -e 's/[^.]*//'`
+       GUESS=sparc-sun-solaris2$SUN_REL
+       ;;
     i86pc:AuroraUX:5.*:* | i86xen:AuroraUX:5.*:*)
-       echo i386-pc-auroraux"$UNAME_RELEASE"
-       exit ;;
+       GUESS=i386-pc-auroraux$UNAME_RELEASE
+       ;;
     i86pc:SunOS:5.*:* | i86xen:SunOS:5.*:*)
        set_cc_for_build
        SUN_ARCH=i386
        # If there is a compiler, see if it is configured for 64-bit objects.
        # Note that the Sun cc does not turn __LP64__ into 1 like gcc does.
        # This test works for both compilers.
-       if [ "$CC_FOR_BUILD" != no_compiler_found ]; then
+       if test "$CC_FOR_BUILD" != no_compiler_found; then
            if (echo '#ifdef __amd64'; echo IS_64BIT_ARCH; echo '#endif') | \
-               (CCOPTS="" $CC_FOR_BUILD -E - 2>/dev/null) | \
+               (CCOPTS="" $CC_FOR_BUILD -m64 -E - 2>/dev/null) | \
                grep IS_64BIT_ARCH >/dev/null
            then
                SUN_ARCH=x86_64
            fi
        fi
-       echo "$SUN_ARCH"-pc-solaris2"`echo "$UNAME_RELEASE"|sed -e 's/[^.]*//'`"
-       exit ;;
+       SUN_REL=`echo "$UNAME_RELEASE" | sed -e 's/[^.]*//'`
+       GUESS=$SUN_ARCH-pc-solaris2$SUN_REL
+       ;;
     sun4*:SunOS:6*:*)
        # According to config.sub, this is the proper way to canonicalize
        # SunOS6.  Hard to guess exactly what SunOS6 will be like, but
        # it's likely to be more like Solaris than SunOS4.
-       echo sparc-sun-solaris3"`echo "$UNAME_RELEASE"|sed -e 's/[^.]*//'`"
-       exit ;;
+       SUN_REL=`echo "$UNAME_RELEASE" | sed -e 's/[^.]*//'`
+       GUESS=sparc-sun-solaris3$SUN_REL
+       ;;
     sun4*:SunOS:*:*)
-       case "`/usr/bin/arch -k`" in
+       case `/usr/bin/arch -k` in
            Series*|S4*)
                UNAME_RELEASE=`uname -v`
                ;;
        esac
        # Japanese Language versions have a version number like `4.1.3-JL'.
-       echo sparc-sun-sunos"`echo "$UNAME_RELEASE"|sed -e 's/-/_/'`"
-       exit ;;
+       SUN_REL=`echo "$UNAME_RELEASE" | sed -e 's/-/_/'`
+       GUESS=sparc-sun-sunos$SUN_REL
+       ;;
     sun3*:SunOS:*:*)
-       echo m68k-sun-sunos"$UNAME_RELEASE"
-       exit ;;
+       GUESS=m68k-sun-sunos$UNAME_RELEASE
+       ;;
     sun*:*:4.2BSD:*)
        UNAME_RELEASE=`(sed 1q /etc/motd | awk '{print substr($5,1,3)}') 2>/dev/null`
        test "x$UNAME_RELEASE" = x && UNAME_RELEASE=3
-       case "`/bin/arch`" in
+       case `/bin/arch` in
            sun3)
-               echo m68k-sun-sunos"$UNAME_RELEASE"
+               GUESS=m68k-sun-sunos$UNAME_RELEASE
                ;;
            sun4)
-               echo sparc-sun-sunos"$UNAME_RELEASE"
+               GUESS=sparc-sun-sunos$UNAME_RELEASE
                ;;
        esac
-       exit ;;
+       ;;
     aushp:SunOS:*:*)
-       echo sparc-auspex-sunos"$UNAME_RELEASE"
-       exit ;;
+       GUESS=sparc-auspex-sunos$UNAME_RELEASE
+       ;;
     # The situation for MiNT is a little confusing.  The machine name
     # can be virtually everything (everything which is not
     # "atarist" or "atariste" at least should have a processor
@@ -456,41 +490,41 @@ case "$UNAME_MACHINE:$UNAME_SYSTEM:$UNAME_RELEASE:$UNAME_VERSION" in
     # MiNT.  But MiNT is downward compatible to TOS, so this should
     # be no problem.
     atarist[e]:*MiNT:*:* | atarist[e]:*mint:*:* | atarist[e]:*TOS:*:*)
-       echo m68k-atari-mint"$UNAME_RELEASE"
-       exit ;;
+       GUESS=m68k-atari-mint$UNAME_RELEASE
+       ;;
     atari*:*MiNT:*:* | atari*:*mint:*:* | atarist[e]:*TOS:*:*)
-       echo m68k-atari-mint"$UNAME_RELEASE"
-       exit ;;
+       GUESS=m68k-atari-mint$UNAME_RELEASE
+       ;;
     *falcon*:*MiNT:*:* | *falcon*:*mint:*:* | *falcon*:*TOS:*:*)
-       echo m68k-atari-mint"$UNAME_RELEASE"
-       exit ;;
+       GUESS=m68k-atari-mint$UNAME_RELEASE
+       ;;
     milan*:*MiNT:*:* | milan*:*mint:*:* | *milan*:*TOS:*:*)
-       echo m68k-milan-mint"$UNAME_RELEASE"
-       exit ;;
+       GUESS=m68k-milan-mint$UNAME_RELEASE
+       ;;
     hades*:*MiNT:*:* | hades*:*mint:*:* | *hades*:*TOS:*:*)
-       echo m68k-hades-mint"$UNAME_RELEASE"
-       exit ;;
+       GUESS=m68k-hades-mint$UNAME_RELEASE
+       ;;
     *:*MiNT:*:* | *:*mint:*:* | *:*TOS:*:*)
-       echo m68k-unknown-mint"$UNAME_RELEASE"
-       exit ;;
+       GUESS=m68k-unknown-mint$UNAME_RELEASE
+       ;;
     m68k:machten:*:*)
-       echo m68k-apple-machten"$UNAME_RELEASE"
-       exit ;;
+       GUESS=m68k-apple-machten$UNAME_RELEASE
+       ;;
     powerpc:machten:*:*)
-       echo powerpc-apple-machten"$UNAME_RELEASE"
-       exit ;;
+       GUESS=powerpc-apple-machten$UNAME_RELEASE
+       ;;
     RISC*:Mach:*:*)
-       echo mips-dec-mach_bsd4.3
-       exit ;;
+       GUESS=mips-dec-mach_bsd4.3
+       ;;
     RISC*:ULTRIX:*:*)
-       echo mips-dec-ultrix"$UNAME_RELEASE"
-       exit ;;
+       GUESS=mips-dec-ultrix$UNAME_RELEASE
+       ;;
     VAX*:ULTRIX*:*:*)
-       echo vax-dec-ultrix"$UNAME_RELEASE"
-       exit ;;
+       GUESS=vax-dec-ultrix$UNAME_RELEASE
+       ;;
     2020:CLIX:*:* | 2430:CLIX:*:*)
-       echo clipper-intergraph-clix"$UNAME_RELEASE"
-       exit ;;
+       GUESS=clipper-intergraph-clix$UNAME_RELEASE
+       ;;
     mips:*:*:UMIPS | mips:*:*:RISCos)
        set_cc_for_build
        sed 's/^        //' << EOF > "$dummy.c"
@@ -518,75 +552,76 @@ EOF
          dummyarg=`echo "$UNAME_RELEASE" | sed -n 's/\([0-9]*\).*/\1/p'` &&
          SYSTEM_NAME=`"$dummy" "$dummyarg"` &&
            { echo "$SYSTEM_NAME"; exit; }
-       echo mips-mips-riscos"$UNAME_RELEASE"
-       exit ;;
+       GUESS=mips-mips-riscos$UNAME_RELEASE
+       ;;
     Motorola:PowerMAX_OS:*:*)
-       echo powerpc-motorola-powermax
-       exit ;;
+       GUESS=powerpc-motorola-powermax
+       ;;
     Motorola:*:4.3:PL8-*)
-       echo powerpc-harris-powermax
-       exit ;;
+       GUESS=powerpc-harris-powermax
+       ;;
     Night_Hawk:*:*:PowerMAX_OS | Synergy:PowerMAX_OS:*:*)
-       echo powerpc-harris-powermax
-       exit ;;
+       GUESS=powerpc-harris-powermax
+       ;;
     Night_Hawk:Power_UNIX:*:*)
-       echo powerpc-harris-powerunix
-       exit ;;
+       GUESS=powerpc-harris-powerunix
+       ;;
     m88k:CX/UX:7*:*)
-       echo m88k-harris-cxux7
-       exit ;;
+       GUESS=m88k-harris-cxux7
+       ;;
     m88k:*:4*:R4*)
-       echo m88k-motorola-sysv4
-       exit ;;
+       GUESS=m88k-motorola-sysv4
+       ;;
     m88k:*:3*:R3*)
-       echo m88k-motorola-sysv3
-       exit ;;
+       GUESS=m88k-motorola-sysv3
+       ;;
     AViiON:dgux:*:*)
        # DG/UX returns AViiON for all architectures
        UNAME_PROCESSOR=`/usr/bin/uname -p`
-       if [ "$UNAME_PROCESSOR" = mc88100 ] || [ "$UNAME_PROCESSOR" = mc88110 ]
+       if test "$UNAME_PROCESSOR" = mc88100 || test "$UNAME_PROCESSOR" = mc88110
        then
-           if [ "$TARGET_BINARY_INTERFACE"x = m88kdguxelfx ] || \
-              [ "$TARGET_BINARY_INTERFACE"x = x ]
+           if test "$TARGET_BINARY_INTERFACE"x = m88kdguxelfx || \
+              test "$TARGET_BINARY_INTERFACE"x = x
            then
-               echo m88k-dg-dgux"$UNAME_RELEASE"
+               GUESS=m88k-dg-dgux$UNAME_RELEASE
            else
-               echo m88k-dg-dguxbcs"$UNAME_RELEASE"
+               GUESS=m88k-dg-dguxbcs$UNAME_RELEASE
            fi
        else
-           echo i586-dg-dgux"$UNAME_RELEASE"
+           GUESS=i586-dg-dgux$UNAME_RELEASE
        fi
-       exit ;;
+       ;;
     M88*:DolphinOS:*:*)        # DolphinOS (SVR3)
-       echo m88k-dolphin-sysv3
-       exit ;;
+       GUESS=m88k-dolphin-sysv3
+       ;;
     M88*:*:R3*:*)
        # Delta 88k system running SVR3
-       echo m88k-motorola-sysv3
-       exit ;;
+       GUESS=m88k-motorola-sysv3
+       ;;
     XD88*:*:*:*) # Tektronix XD88 system running UTekV (SVR3)
-       echo m88k-tektronix-sysv3
-       exit ;;
+       GUESS=m88k-tektronix-sysv3
+       ;;
     Tek43[0-9][0-9]:UTek:*:*) # Tektronix 4300 system running UTek (BSD)
-       echo m68k-tektronix-bsd
-       exit ;;
+       GUESS=m68k-tektronix-bsd
+       ;;
     *:IRIX*:*:*)
-       echo mips-sgi-irix"`echo "$UNAME_RELEASE"|sed -e 's/-/_/g'`"
-       exit ;;
+       IRIX_REL=`echo "$UNAME_RELEASE" | sed -e 's/-/_/g'`
+       GUESS=mips-sgi-irix$IRIX_REL
+       ;;
     ????????:AIX?:[12].1:2)   # AIX 2.2.1 or AIX 2.1.1 is RT/PC AIX.
-       echo romp-ibm-aix     # uname -m gives an 8 hex-code CPU id
-       exit ;;               # Note that: echo "'`uname -s`'" gives 'AIX '
+       GUESS=romp-ibm-aix    # uname -m gives an 8 hex-code CPU id
+       ;;                    # Note that: echo "'`uname -s`'" gives 'AIX '
     i*86:AIX:*:*)
-       echo i386-ibm-aix
-       exit ;;
+       GUESS=i386-ibm-aix
+       ;;
     ia64:AIX:*:*)
-       if [ -x /usr/bin/oslevel ] ; then
+       if test -x /usr/bin/oslevel ; then
                IBM_REV=`/usr/bin/oslevel`
        else
-               IBM_REV="$UNAME_VERSION.$UNAME_RELEASE"
+               IBM_REV=$UNAME_VERSION.$UNAME_RELEASE
        fi
-       echo "$UNAME_MACHINE"-ibm-aix"$IBM_REV"
-       exit ;;
+       GUESS=$UNAME_MACHINE-ibm-aix$IBM_REV
+       ;;
     *:AIX:2:3)
        if grep bos325 /usr/include/stdio.h >/dev/null 2>&1; then
                set_cc_for_build
@@ -603,16 +638,16 @@ EOF
 EOF
                if $CC_FOR_BUILD -o "$dummy" "$dummy.c" && SYSTEM_NAME=`"$dummy"`
                then
-                       echo "$SYSTEM_NAME"
+                       GUESS=$SYSTEM_NAME
                else
-                       echo rs6000-ibm-aix3.2.5
+                       GUESS=rs6000-ibm-aix3.2.5
                fi
        elif grep bos324 /usr/include/stdio.h >/dev/null 2>&1; then
-               echo rs6000-ibm-aix3.2.4
+               GUESS=rs6000-ibm-aix3.2.4
        else
-               echo rs6000-ibm-aix3.2
+               GUESS=rs6000-ibm-aix3.2
        fi
-       exit ;;
+       ;;
     *:AIX:*:[4567])
        IBM_CPU_ID=`/usr/sbin/lsdev -C -c processor -S available | sed 1q | awk '{ print $1 }'`
        if /usr/sbin/lsattr -El "$IBM_CPU_ID" | grep ' POWER' >/dev/null 2>&1; then
@@ -620,56 +655,56 @@ EOF
        else
                IBM_ARCH=powerpc
        fi
-       if [ -x /usr/bin/lslpp ] ; then
-               IBM_REV=`/usr/bin/lslpp -Lqc bos.rte.libc |
+       if test -x /usr/bin/lslpp ; then
+               IBM_REV=`/usr/bin/lslpp -Lqc bos.rte.libc | \
                           awk -F: '{ print $3 }' | sed s/[0-9]*$/0/`
        else
-               IBM_REV="$UNAME_VERSION.$UNAME_RELEASE"
+               IBM_REV=$UNAME_VERSION.$UNAME_RELEASE
        fi
-       echo "$IBM_ARCH"-ibm-aix"$IBM_REV"
-       exit ;;
+       GUESS=$IBM_ARCH-ibm-aix$IBM_REV
+       ;;
     *:AIX:*:*)
-       echo rs6000-ibm-aix
-       exit ;;
+       GUESS=rs6000-ibm-aix
+       ;;
     ibmrt:4.4BSD:*|romp-ibm:4.4BSD:*)
-       echo romp-ibm-bsd4.4
-       exit ;;
+       GUESS=romp-ibm-bsd4.4
+       ;;
     ibmrt:*BSD:*|romp-ibm:BSD:*)            # covers RT/PC BSD and
-       echo romp-ibm-bsd"$UNAME_RELEASE"   # 4.3 with uname added to
-       exit ;;                             # report: romp-ibm BSD 4.3
+       GUESS=romp-ibm-bsd$UNAME_RELEASE    # 4.3 with uname added to
+       ;;                                  # report: romp-ibm BSD 4.3
     *:BOSX:*:*)
-       echo rs6000-bull-bosx
-       exit ;;
+       GUESS=rs6000-bull-bosx
+       ;;
     DPX/2?00:B.O.S.:*:*)
-       echo m68k-bull-sysv3
-       exit ;;
+       GUESS=m68k-bull-sysv3
+       ;;
     9000/[34]??:4.3bsd:1.*:*)
-       echo m68k-hp-bsd
-       exit ;;
+       GUESS=m68k-hp-bsd
+       ;;
     hp300:4.4BSD:*:* | 9000/[34]??:4.3bsd:2.*:*)
-       echo m68k-hp-bsd4.4
-       exit ;;
+       GUESS=m68k-hp-bsd4.4
+       ;;
     9000/[34678]??:HP-UX:*:*)
-       HPUX_REV=`echo "$UNAME_RELEASE"|sed -e 's/[^.]*.[0B]*//'`
-       case "$UNAME_MACHINE" in
+       HPUX_REV=`echo "$UNAME_RELEASE" | sed -e 's/[^.]*.[0B]*//'`
+       case $UNAME_MACHINE in
            9000/31?)            HP_ARCH=m68000 ;;
            9000/[34]??)         HP_ARCH=m68k ;;
            9000/[678][0-9][0-9])
-               if [ -x /usr/bin/getconf ]; then
+               if test -x /usr/bin/getconf; then
                    sc_cpu_version=`/usr/bin/getconf SC_CPU_VERSION 2>/dev/null`
                    sc_kernel_bits=`/usr/bin/getconf SC_KERNEL_BITS 2>/dev/null`
-                   case "$sc_cpu_version" in
+                   case $sc_cpu_version in
                      523) HP_ARCH=hppa1.0 ;; # CPU_PA_RISC1_0
                      528) HP_ARCH=hppa1.1 ;; # CPU_PA_RISC1_1
                      532)                      # CPU_PA_RISC2_0
-                       case "$sc_kernel_bits" in
+                       case $sc_kernel_bits in
                          32) HP_ARCH=hppa2.0n ;;
                          64) HP_ARCH=hppa2.0w ;;
                          '') HP_ARCH=hppa2.0 ;;   # HP-UX 10.20
                        esac ;;
                    esac
                fi
-               if [ "$HP_ARCH" = "" ]; then
+               if test "$HP_ARCH" = ""; then
                    set_cc_for_build
                    sed 's/^            //' << EOF > "$dummy.c"
 
@@ -708,7 +743,7 @@ EOF
                    test -z "$HP_ARCH" && HP_ARCH=hppa
                fi ;;
        esac
-       if [ "$HP_ARCH" = hppa2.0w ]
+       if test "$HP_ARCH" = hppa2.0w
        then
            set_cc_for_build
 
@@ -729,12 +764,12 @@ EOF
                HP_ARCH=hppa64
            fi
        fi
-       echo "$HP_ARCH"-hp-hpux"$HPUX_REV"
-       exit ;;
+       GUESS=$HP_ARCH-hp-hpux$HPUX_REV
+       ;;
     ia64:HP-UX:*:*)
-       HPUX_REV=`echo "$UNAME_RELEASE"|sed -e 's/[^.]*.[0B]*//'`
-       echo ia64-hp-hpux"$HPUX_REV"
-       exit ;;
+       HPUX_REV=`echo "$UNAME_RELEASE" | sed -e 's/[^.]*.[0B]*//'`
+       GUESS=ia64-hp-hpux$HPUX_REV
+       ;;
     3050*:HI-UX:*:*)
        set_cc_for_build
        sed 's/^        //' << EOF > "$dummy.c"
@@ -764,36 +799,36 @@ EOF
 EOF
        $CC_FOR_BUILD -o "$dummy" "$dummy.c" && SYSTEM_NAME=`"$dummy"` &&
                { echo "$SYSTEM_NAME"; exit; }
-       echo unknown-hitachi-hiuxwe2
-       exit ;;
+       GUESS=unknown-hitachi-hiuxwe2
+       ;;
     9000/7??:4.3bsd:*:* | 9000/8?[79]:4.3bsd:*:*)
-       echo hppa1.1-hp-bsd
-       exit ;;
+       GUESS=hppa1.1-hp-bsd
+       ;;
     9000/8??:4.3bsd:*:*)
-       echo hppa1.0-hp-bsd
-       exit ;;
+       GUESS=hppa1.0-hp-bsd
+       ;;
     *9??*:MPE/iX:*:* | *3000*:MPE/iX:*:*)
-       echo hppa1.0-hp-mpeix
-       exit ;;
+       GUESS=hppa1.0-hp-mpeix
+       ;;
     hp7??:OSF1:*:* | hp8?[79]:OSF1:*:*)
-       echo hppa1.1-hp-osf
-       exit ;;
+       GUESS=hppa1.1-hp-osf
+       ;;
     hp8??:OSF1:*:*)
-       echo hppa1.0-hp-osf
-       exit ;;
+       GUESS=hppa1.0-hp-osf
+       ;;
     i*86:OSF1:*:*)
-       if [ -x /usr/sbin/sysversion ] ; then
-           echo "$UNAME_MACHINE"-unknown-osf1mk
+       if test -x /usr/sbin/sysversion ; then
+           GUESS=$UNAME_MACHINE-unknown-osf1mk
        else
-           echo "$UNAME_MACHINE"-unknown-osf1
+           GUESS=$UNAME_MACHINE-unknown-osf1
        fi
-       exit ;;
+       ;;
     parisc*:Lites*:*:*)
-       echo hppa1.1-hp-lites
-       exit ;;
+       GUESS=hppa1.1-hp-lites
+       ;;
     C1*:ConvexOS:*:* | convex:ConvexOS:C1*:*)
-       echo c1-convex-bsd
-       exit ;;
+       GUESS=c1-convex-bsd
+       ;;
     C2*:ConvexOS:*:* | convex:ConvexOS:C2*:*)
        if getsysinfo -f scalar_acc
        then echo c32-convex-bsd
@@ -801,17 +836,18 @@ EOF
        fi
        exit ;;
     C34*:ConvexOS:*:* | convex:ConvexOS:C34*:*)
-       echo c34-convex-bsd
-       exit ;;
+       GUESS=c34-convex-bsd
+       ;;
     C38*:ConvexOS:*:* | convex:ConvexOS:C38*:*)
-       echo c38-convex-bsd
-       exit ;;
+       GUESS=c38-convex-bsd
+       ;;
     C4*:ConvexOS:*:* | convex:ConvexOS:C4*:*)
-       echo c4-convex-bsd
-       exit ;;
+       GUESS=c4-convex-bsd
+       ;;
     CRAY*Y-MP:*:*:*)
-       echo ymp-cray-unicos"$UNAME_RELEASE" | sed -e 's/\.[^.]*$/.X/'
-       exit ;;
+       CRAY_REL=`echo "$UNAME_RELEASE" | sed -e 's/\.[^.]*$/.X/'`
+       GUESS=ymp-cray-unicos$CRAY_REL
+       ;;
     CRAY*[A-Z]90:*:*:*)
        echo "$UNAME_MACHINE"-cray-unicos"$UNAME_RELEASE" \
        | sed -e 's/CRAY.*\([A-Z]90\)/\1/' \
@@ -819,112 +855,133 @@ EOF
              -e 's/\.[^.]*$/.X/'
        exit ;;
     CRAY*TS:*:*:*)
-       echo t90-cray-unicos"$UNAME_RELEASE" | sed -e 's/\.[^.]*$/.X/'
-       exit ;;
+       CRAY_REL=`echo "$UNAME_RELEASE" | sed -e 's/\.[^.]*$/.X/'`
+       GUESS=t90-cray-unicos$CRAY_REL
+       ;;
     CRAY*T3E:*:*:*)
-       echo alphaev5-cray-unicosmk"$UNAME_RELEASE" | sed -e 's/\.[^.]*$/.X/'
-       exit ;;
+       CRAY_REL=`echo "$UNAME_RELEASE" | sed -e 's/\.[^.]*$/.X/'`
+       GUESS=alphaev5-cray-unicosmk$CRAY_REL
+       ;;
     CRAY*SV1:*:*:*)
-       echo sv1-cray-unicos"$UNAME_RELEASE" | sed -e 's/\.[^.]*$/.X/'
-       exit ;;
+       CRAY_REL=`echo "$UNAME_RELEASE" | sed -e 's/\.[^.]*$/.X/'`
+       GUESS=sv1-cray-unicos$CRAY_REL
+       ;;
     *:UNICOS/mp:*:*)
-       echo craynv-cray-unicosmp"$UNAME_RELEASE" | sed -e 's/\.[^.]*$/.X/'
-       exit ;;
+       CRAY_REL=`echo "$UNAME_RELEASE" | sed -e 's/\.[^.]*$/.X/'`
+       GUESS=craynv-cray-unicosmp$CRAY_REL
+       ;;
     F30[01]:UNIX_System_V:*:* | F700:UNIX_System_V:*:*)
        FUJITSU_PROC=`uname -m | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz`
        FUJITSU_SYS=`uname -p | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz | sed -e 's/\///'`
        FUJITSU_REL=`echo "$UNAME_RELEASE" | sed -e 's/ /_/'`
-       echo "${FUJITSU_PROC}-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}"
-       exit ;;
+       GUESS=${FUJITSU_PROC}-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}
+       ;;
     5000:UNIX_System_V:4.*:*)
        FUJITSU_SYS=`uname -p | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz | sed -e 's/\///'`
        FUJITSU_REL=`echo "$UNAME_RELEASE" | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz | sed -e 's/ /_/'`
-       echo "sparc-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}"
-       exit ;;
+       GUESS=sparc-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}
+       ;;
     i*86:BSD/386:*:* | i*86:BSD/OS:*:* | *:Ascend\ Embedded/OS:*:*)
-       echo "$UNAME_MACHINE"-pc-bsdi"$UNAME_RELEASE"
-       exit ;;
+       GUESS=$UNAME_MACHINE-pc-bsdi$UNAME_RELEASE
+       ;;
     sparc*:BSD/OS:*:*)
-       echo sparc-unknown-bsdi"$UNAME_RELEASE"
-       exit ;;
+       GUESS=sparc-unknown-bsdi$UNAME_RELEASE
+       ;;
     *:BSD/OS:*:*)
-       echo "$UNAME_MACHINE"-unknown-bsdi"$UNAME_RELEASE"
-       exit ;;
+       GUESS=$UNAME_MACHINE-unknown-bsdi$UNAME_RELEASE
+       ;;
     arm:FreeBSD:*:*)
        UNAME_PROCESSOR=`uname -p`
        set_cc_for_build
        if echo __ARM_PCS_VFP | $CC_FOR_BUILD -E - 2>/dev/null \
            | grep -q __ARM_PCS_VFP
        then
-           echo "${UNAME_PROCESSOR}"-unknown-freebsd"`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'`"-gnueabi
+           FREEBSD_REL=`echo "$UNAME_RELEASE" | sed -e 's/[-(].*//'`
+           GUESS=$UNAME_PROCESSOR-unknown-freebsd$FREEBSD_REL-gnueabi
        else
-           echo "${UNAME_PROCESSOR}"-unknown-freebsd"`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'`"-gnueabihf
+           FREEBSD_REL=`echo "$UNAME_RELEASE" | sed -e 's/[-(].*//'`
+           GUESS=$UNAME_PROCESSOR-unknown-freebsd$FREEBSD_REL-gnueabihf
        fi
-       exit ;;
+       ;;
     *:FreeBSD:*:*)
        UNAME_PROCESSOR=`/usr/bin/uname -p`
-       case "$UNAME_PROCESSOR" in
+       case $UNAME_PROCESSOR in
            amd64)
                UNAME_PROCESSOR=x86_64 ;;
            i386)
                UNAME_PROCESSOR=i586 ;;
        esac
-       echo "$UNAME_PROCESSOR"-unknown-freebsd"`echo "$UNAME_RELEASE"|sed -e 's/[-(].*//'`"
-       exit ;;
+       FREEBSD_REL=`echo "$UNAME_RELEASE" | sed -e 's/[-(].*//'`
+       GUESS=$UNAME_PROCESSOR-unknown-freebsd$FREEBSD_REL
+       ;;
     i*:CYGWIN*:*)
-       echo "$UNAME_MACHINE"-pc-cygwin
-       exit ;;
+       GUESS=$UNAME_MACHINE-pc-cygwin
+       ;;
     *:MINGW64*:*)
-       echo "$UNAME_MACHINE"-pc-mingw64
-       exit ;;
+       GUESS=$UNAME_MACHINE-pc-mingw64
+       ;;
     *:MINGW*:*)
-       echo "$UNAME_MACHINE"-pc-mingw32
-       exit ;;
+       GUESS=$UNAME_MACHINE-pc-mingw32
+       ;;
     *:MSYS*:*)
-       echo "$UNAME_MACHINE"-pc-msys
-       exit ;;
+       GUESS=$UNAME_MACHINE-pc-msys
+       ;;
     i*:PW*:*)
-       echo "$UNAME_MACHINE"-pc-pw32
-       exit ;;
+       GUESS=$UNAME_MACHINE-pc-pw32
+       ;;
+    *:SerenityOS:*:*)
+        GUESS=$UNAME_MACHINE-pc-serenity
+        ;;
     *:Interix*:*)
-       case "$UNAME_MACHINE" in
+       case $UNAME_MACHINE in
            x86)
-               echo i586-pc-interix"$UNAME_RELEASE"
-               exit ;;
+               GUESS=i586-pc-interix$UNAME_RELEASE
+               ;;
            authenticamd | genuineintel | EM64T)
-               echo x86_64-unknown-interix"$UNAME_RELEASE"
-               exit ;;
+               GUESS=x86_64-unknown-interix$UNAME_RELEASE
+               ;;
            IA64)
-               echo ia64-unknown-interix"$UNAME_RELEASE"
-               exit ;;
+               GUESS=ia64-unknown-interix$UNAME_RELEASE
+               ;;
        esac ;;
     i*:UWIN*:*)
-       echo "$UNAME_MACHINE"-pc-uwin
-       exit ;;
+       GUESS=$UNAME_MACHINE-pc-uwin
+       ;;
     amd64:CYGWIN*:*:* | x86_64:CYGWIN*:*:*)
-       echo x86_64-pc-cygwin
-       exit ;;
+       GUESS=x86_64-pc-cygwin
+       ;;
     prep*:SunOS:5.*:*)
-       echo powerpcle-unknown-solaris2"`echo "$UNAME_RELEASE"|sed -e 's/[^.]*//'`"
-       exit ;;
+       SUN_REL=`echo "$UNAME_RELEASE" | sed -e 's/[^.]*//'`
+       GUESS=powerpcle-unknown-solaris2$SUN_REL
+       ;;
     *:GNU:*:*)
        # the GNU system
-       echo "`echo "$UNAME_MACHINE"|sed -e 's,[-/].*$,,'`-unknown-$LIBC`echo "$UNAME_RELEASE"|sed -e 's,/.*$,,'`"
-       exit ;;
+       GNU_ARCH=`echo "$UNAME_MACHINE" | sed -e 's,[-/].*$,,'`
+       GNU_REL=`echo "$UNAME_RELEASE" | sed -e 's,/.*$,,'`
+       GUESS=$GNU_ARCH-unknown-$LIBC$GNU_REL
+       ;;
     *:GNU/*:*:*)
        # other systems with GNU libc and userland
-       echo "$UNAME_MACHINE-unknown-`echo "$UNAME_SYSTEM" | sed 's,^[^/]*/,,' | tr "[:upper:]" "[:lower:]"``echo "$UNAME_RELEASE"|sed -e 's/[-(].*//'`-$LIBC"
-       exit ;;
+       GNU_SYS=`echo "$UNAME_SYSTEM" | sed 's,^[^/]*/,,' | tr "[:upper:]" "[:lower:]"`
+       GNU_REL=`echo "$UNAME_RELEASE" | sed -e 's/[-(].*//'`
+       GUESS=$UNAME_MACHINE-unknown-$GNU_SYS$GNU_REL-$LIBC
+       ;;
+    x86_64:[Mm]anagarm:*:*|i?86:[Mm]anagarm:*:*)
+       GUESS="$UNAME_MACHINE-pc-managarm-mlibc"
+       ;;
+    *:[Mm]anagarm:*:*)
+       GUESS="$UNAME_MACHINE-unknown-managarm-mlibc"
+       ;;
     *:Minix:*:*)
-       echo "$UNAME_MACHINE"-unknown-minix
-       exit ;;
+       GUESS=$UNAME_MACHINE-unknown-minix
+       ;;
     aarch64:Linux:*:*)
-       echo "$UNAME_MACHINE"-unknown-linux-"$LIBC"
-       exit ;;
+       GUESS=$UNAME_MACHINE-unknown-linux-$LIBC
+       ;;
     aarch64_be:Linux:*:*)
        UNAME_MACHINE=aarch64_be
-       echo "$UNAME_MACHINE"-unknown-linux-"$LIBC"
-       exit ;;
+       GUESS=$UNAME_MACHINE-unknown-linux-$LIBC
+       ;;
     alpha:Linux:*:*)
        case `sed -n '/^cpu model/s/^.*: \(.*\)/\1/p' /proc/cpuinfo 2>/dev/null` in
          EV5)   UNAME_MACHINE=alphaev5 ;;
@@ -937,60 +994,63 @@ EOF
        esac
        objdump --private-headers /bin/sh | grep -q ld.so.1
        if test "$?" = 0 ; then LIBC=gnulibc1 ; fi
-       echo "$UNAME_MACHINE"-unknown-linux-"$LIBC"
-       exit ;;
-    arc:Linux:*:* | arceb:Linux:*:*)
-       echo "$UNAME_MACHINE"-unknown-linux-"$LIBC"
-       exit ;;
+       GUESS=$UNAME_MACHINE-unknown-linux-$LIBC
+       ;;
+    arc:Linux:*:* | arceb:Linux:*:* | arc32:Linux:*:* | arc64:Linux:*:*)
+       GUESS=$UNAME_MACHINE-unknown-linux-$LIBC
+       ;;
     arm*:Linux:*:*)
        set_cc_for_build
        if echo __ARM_EABI__ | $CC_FOR_BUILD -E - 2>/dev/null \
            | grep -q __ARM_EABI__
        then
-           echo "$UNAME_MACHINE"-unknown-linux-"$LIBC"
+           GUESS=$UNAME_MACHINE-unknown-linux-$LIBC
        else
            if echo __ARM_PCS_VFP | $CC_FOR_BUILD -E - 2>/dev/null \
                | grep -q __ARM_PCS_VFP
            then
-               echo "$UNAME_MACHINE"-unknown-linux-"$LIBC"eabi
+               GUESS=$UNAME_MACHINE-unknown-linux-${LIBC}eabi
            else
-               echo "$UNAME_MACHINE"-unknown-linux-"$LIBC"eabihf
+               GUESS=$UNAME_MACHINE-unknown-linux-${LIBC}eabihf
            fi
        fi
-       exit ;;
+       ;;
     avr32*:Linux:*:*)
-       echo "$UNAME_MACHINE"-unknown-linux-"$LIBC"
-       exit ;;
+       GUESS=$UNAME_MACHINE-unknown-linux-$LIBC
+       ;;
     cris:Linux:*:*)
-       echo "$UNAME_MACHINE"-axis-linux-"$LIBC"
-       exit ;;
+       GUESS=$UNAME_MACHINE-axis-linux-$LIBC
+       ;;
     crisv32:Linux:*:*)
-       echo "$UNAME_MACHINE"-axis-linux-"$LIBC"
-       exit ;;
+       GUESS=$UNAME_MACHINE-axis-linux-$LIBC
+       ;;
     e2k:Linux:*:*)
-       echo "$UNAME_MACHINE"-unknown-linux-"$LIBC"
-       exit ;;
+       GUESS=$UNAME_MACHINE-unknown-linux-$LIBC
+       ;;
     frv:Linux:*:*)
-       echo "$UNAME_MACHINE"-unknown-linux-"$LIBC"
-       exit ;;
+       GUESS=$UNAME_MACHINE-unknown-linux-$LIBC
+       ;;
     hexagon:Linux:*:*)
-       echo "$UNAME_MACHINE"-unknown-linux-"$LIBC"
-       exit ;;
+       GUESS=$UNAME_MACHINE-unknown-linux-$LIBC
+       ;;
     i*86:Linux:*:*)
-       echo "$UNAME_MACHINE"-pc-linux-"$LIBC"
-       exit ;;
+       GUESS=$UNAME_MACHINE-pc-linux-$LIBC
+       ;;
     ia64:Linux:*:*)
-       echo "$UNAME_MACHINE"-unknown-linux-"$LIBC"
-       exit ;;
+       GUESS=$UNAME_MACHINE-unknown-linux-$LIBC
+       ;;
     k1om:Linux:*:*)
-       echo "$UNAME_MACHINE"-unknown-linux-"$LIBC"
-       exit ;;
+       GUESS=$UNAME_MACHINE-unknown-linux-$LIBC
+       ;;
+    loongarch32:Linux:*:* | loongarch64:Linux:*:*)
+       GUESS=$UNAME_MACHINE-unknown-linux-$LIBC
+       ;;
     m32r*:Linux:*:*)
-       echo "$UNAME_MACHINE"-unknown-linux-"$LIBC"
-       exit ;;
+       GUESS=$UNAME_MACHINE-unknown-linux-$LIBC
+       ;;
     m68*:Linux:*:*)
-       echo "$UNAME_MACHINE"-unknown-linux-"$LIBC"
-       exit ;;
+       GUESS=$UNAME_MACHINE-unknown-linux-$LIBC
+       ;;
     mips:Linux:*:* | mips64:Linux:*:*)
        set_cc_for_build
        IS_GLIBC=0
@@ -1035,123 +1095,135 @@ EOF
        #endif
        #endif
 EOF
-       eval "`$CC_FOR_BUILD -E "$dummy.c" 2>/dev/null | grep '^CPU\|^MIPS_ENDIAN\|^LIBCABI'`"
+       cc_set_vars=`$CC_FOR_BUILD -E "$dummy.c" 2>/dev/null | grep '^CPU\|^MIPS_ENDIAN\|^LIBCABI'`
+       eval "$cc_set_vars"
        test "x$CPU" != x && { echo "$CPU${MIPS_ENDIAN}-unknown-linux-$LIBCABI"; exit; }
        ;;
     mips64el:Linux:*:*)
-       echo "$UNAME_MACHINE"-unknown-linux-"$LIBC"
-       exit ;;
+       GUESS=$UNAME_MACHINE-unknown-linux-$LIBC
+       ;;
     openrisc*:Linux:*:*)
-       echo or1k-unknown-linux-"$LIBC"
-       exit ;;
+       GUESS=or1k-unknown-linux-$LIBC
+       ;;
     or32:Linux:*:* | or1k*:Linux:*:*)
-       echo "$UNAME_MACHINE"-unknown-linux-"$LIBC"
-       exit ;;
+       GUESS=$UNAME_MACHINE-unknown-linux-$LIBC
+       ;;
     padre:Linux:*:*)
-       echo sparc-unknown-linux-"$LIBC"
-       exit ;;
+       GUESS=sparc-unknown-linux-$LIBC
+       ;;
     parisc64:Linux:*:* | hppa64:Linux:*:*)
-       echo hppa64-unknown-linux-"$LIBC"
-       exit ;;
+       GUESS=hppa64-unknown-linux-$LIBC
+       ;;
     parisc:Linux:*:* | hppa:Linux:*:*)
        # Look for CPU level
        case `grep '^cpu[^a-z]*:' /proc/cpuinfo 2>/dev/null | cut -d' ' -f2` in
-         PA7*) echo hppa1.1-unknown-linux-"$LIBC" ;;
-         PA8*) echo hppa2.0-unknown-linux-"$LIBC" ;;
-         *)    echo hppa-unknown-linux-"$LIBC" ;;
+         PA7*) GUESS=hppa1.1-unknown-linux-$LIBC ;;
+         PA8*) GUESS=hppa2.0-unknown-linux-$LIBC ;;
+         *)    GUESS=hppa-unknown-linux-$LIBC ;;
        esac
-       exit ;;
+       ;;
     ppc64:Linux:*:*)
-       echo powerpc64-unknown-linux-"$LIBC"
-       exit ;;
+       GUESS=powerpc64-unknown-linux-$LIBC
+       ;;
     ppc:Linux:*:*)
-       echo powerpc-unknown-linux-"$LIBC"
-       exit ;;
+       GUESS=powerpc-unknown-linux-$LIBC
+       ;;
     ppc64le:Linux:*:*)
-       echo powerpc64le-unknown-linux-"$LIBC"
-       exit ;;
+       GUESS=powerpc64le-unknown-linux-$LIBC
+       ;;
     ppcle:Linux:*:*)
-       echo powerpcle-unknown-linux-"$LIBC"
-       exit ;;
-    riscv32:Linux:*:* | riscv64:Linux:*:*)
-       echo "$UNAME_MACHINE"-unknown-linux-"$LIBC"
-       exit ;;
+       GUESS=powerpcle-unknown-linux-$LIBC
+       ;;
+    riscv32:Linux:*:* | riscv32be:Linux:*:* | riscv64:Linux:*:* | riscv64be:Linux:*:*)
+       GUESS=$UNAME_MACHINE-unknown-linux-$LIBC
+       ;;
     s390:Linux:*:* | s390x:Linux:*:*)
-       echo "$UNAME_MACHINE"-ibm-linux-"$LIBC"
-       exit ;;
+       GUESS=$UNAME_MACHINE-ibm-linux-$LIBC
+       ;;
     sh64*:Linux:*:*)
-       echo "$UNAME_MACHINE"-unknown-linux-"$LIBC"
-       exit ;;
+       GUESS=$UNAME_MACHINE-unknown-linux-$LIBC
+       ;;
     sh*:Linux:*:*)
-       echo "$UNAME_MACHINE"-unknown-linux-"$LIBC"
-       exit ;;
+       GUESS=$UNAME_MACHINE-unknown-linux-$LIBC
+       ;;
     sparc:Linux:*:* | sparc64:Linux:*:*)
-       echo "$UNAME_MACHINE"-unknown-linux-"$LIBC"
-       exit ;;
+       GUESS=$UNAME_MACHINE-unknown-linux-$LIBC
+       ;;
     tile*:Linux:*:*)
-       echo "$UNAME_MACHINE"-unknown-linux-"$LIBC"
-       exit ;;
+       GUESS=$UNAME_MACHINE-unknown-linux-$LIBC
+       ;;
     vax:Linux:*:*)
-       echo "$UNAME_MACHINE"-dec-linux-"$LIBC"
-       exit ;;
+       GUESS=$UNAME_MACHINE-dec-linux-$LIBC
+       ;;
     x86_64:Linux:*:*)
        set_cc_for_build
+       CPU=$UNAME_MACHINE
        LIBCABI=$LIBC
-       if [ "$CC_FOR_BUILD" != no_compiler_found ]; then
-           if (echo '#ifdef __ILP32__'; echo IS_X32; echo '#endif') | \
-               (CCOPTS="" $CC_FOR_BUILD -E - 2>/dev/null) | \
-               grep IS_X32 >/dev/null
-           then
-               LIBCABI="$LIBC"x32
-           fi
+       if test "$CC_FOR_BUILD" != no_compiler_found; then
+           ABI=64
+           sed 's/^        //' << EOF > "$dummy.c"
+           #ifdef __i386__
+           ABI=x86
+           #else
+           #ifdef __ILP32__
+           ABI=x32
+           #endif
+           #endif
+EOF
+           cc_set_abi=`$CC_FOR_BUILD -E "$dummy.c" 2>/dev/null | grep '^ABI' | sed 's, ,,g'`
+           eval "$cc_set_abi"
+           case $ABI in
+               x86) CPU=i686 ;;
+               x32) LIBCABI=${LIBC}x32 ;;
+           esac
        fi
-       echo "$UNAME_MACHINE"-pc-linux-"$LIBCABI"
-       exit ;;
+       GUESS=$CPU-pc-linux-$LIBCABI
+       ;;
     xtensa*:Linux:*:*)
-       echo "$UNAME_MACHINE"-unknown-linux-"$LIBC"
-       exit ;;
+       GUESS=$UNAME_MACHINE-unknown-linux-$LIBC
+       ;;
     i*86:DYNIX/ptx:4*:*)
        # ptx 4.0 does uname -s correctly, with DYNIX/ptx in there.
        # earlier versions are messed up and put the nodename in both
        # sysname and nodename.
-       echo i386-sequent-sysv4
-       exit ;;
+       GUESS=i386-sequent-sysv4
+       ;;
     i*86:UNIX_SV:4.2MP:2.*)
        # Unixware is an offshoot of SVR4, but it has its own version
        # number series starting with 2...
        # I am not positive that other SVR4 systems won't match this,
        # I just have to hope.  -- rms.
        # Use sysv4.2uw... so that sysv4* matches it.
-       echo "$UNAME_MACHINE"-pc-sysv4.2uw"$UNAME_VERSION"
-       exit ;;
+       GUESS=$UNAME_MACHINE-pc-sysv4.2uw$UNAME_VERSION
+       ;;
     i*86:OS/2:*:*)
        # If we were able to find `uname', then EMX Unix compatibility
        # is probably installed.
-       echo "$UNAME_MACHINE"-pc-os2-emx
-       exit ;;
+       GUESS=$UNAME_MACHINE-pc-os2-emx
+       ;;
     i*86:XTS-300:*:STOP)
-       echo "$UNAME_MACHINE"-unknown-stop
-       exit ;;
+       GUESS=$UNAME_MACHINE-unknown-stop
+       ;;
     i*86:atheos:*:*)
-       echo "$UNAME_MACHINE"-unknown-atheos
-       exit ;;
+       GUESS=$UNAME_MACHINE-unknown-atheos
+       ;;
     i*86:syllable:*:*)
-       echo "$UNAME_MACHINE"-pc-syllable
-       exit ;;
+       GUESS=$UNAME_MACHINE-pc-syllable
+       ;;
     i*86:LynxOS:2.*:* | i*86:LynxOS:3.[01]*:* | i*86:LynxOS:4.[02]*:*)
-       echo i386-unknown-lynxos"$UNAME_RELEASE"
-       exit ;;
+       GUESS=i386-unknown-lynxos$UNAME_RELEASE
+       ;;
     i*86:*DOS:*:*)
-       echo "$UNAME_MACHINE"-pc-msdosdjgpp
-       exit ;;
+       GUESS=$UNAME_MACHINE-pc-msdosdjgpp
+       ;;
     i*86:*:4.*:*)
        UNAME_REL=`echo "$UNAME_RELEASE" | sed 's/\/MP$//'`
        if grep Novell /usr/include/link.h >/dev/null 2>/dev/null; then
-               echo "$UNAME_MACHINE"-univel-sysv"$UNAME_REL"
+               GUESS=$UNAME_MACHINE-univel-sysv$UNAME_REL
        else
-               echo "$UNAME_MACHINE"-pc-sysv"$UNAME_REL"
+               GUESS=$UNAME_MACHINE-pc-sysv$UNAME_REL
        fi
-       exit ;;
+       ;;
     i*86:*:5:[678]*)
        # UnixWare 7.x, OpenUNIX and OpenServer 6.
        case `/bin/uname -X | grep "^Machine"` in
@@ -1159,12 +1231,12 @@ EOF
            *Pentium)        UNAME_MACHINE=i586 ;;
            *Pent*|*Celeron) UNAME_MACHINE=i686 ;;
        esac
-       echo "$UNAME_MACHINE-unknown-sysv${UNAME_RELEASE}${UNAME_SYSTEM}${UNAME_VERSION}"
-       exit ;;
+       GUESS=$UNAME_MACHINE-unknown-sysv${UNAME_RELEASE}${UNAME_SYSTEM}${UNAME_VERSION}
+       ;;
     i*86:*:3.2:*)
        if test -f /usr/options/cb.name; then
                UNAME_REL=`sed -n 's/.*Version //p' </usr/options/cb.name`
-               echo "$UNAME_MACHINE"-pc-isc"$UNAME_REL"
+               GUESS=$UNAME_MACHINE-pc-isc$UNAME_REL
        elif /bin/uname -X 2>/dev/null >/dev/null ; then
                UNAME_REL=`(/bin/uname -X|grep Release|sed -e 's/.*= //')`
                (/bin/uname -X|grep i80486 >/dev/null) && UNAME_MACHINE=i486
@@ -1174,11 +1246,11 @@ EOF
                        && UNAME_MACHINE=i686
                (/bin/uname -X|grep '^Machine.*Pentium Pro' >/dev/null) \
                        && UNAME_MACHINE=i686
-               echo "$UNAME_MACHINE"-pc-sco"$UNAME_REL"
+               GUESS=$UNAME_MACHINE-pc-sco$UNAME_REL
        else
-               echo "$UNAME_MACHINE"-pc-sysv32
+               GUESS=$UNAME_MACHINE-pc-sysv32
        fi
-       exit ;;
+       ;;
     pc:*:*:*)
        # Left here for compatibility:
        # uname -m prints for DJGPP always 'pc', but it prints nothing about
@@ -1186,31 +1258,31 @@ EOF
        # Note: whatever this is, it MUST be the same as what config.sub
        # prints for the "djgpp" host, or else GDB configure will decide that
        # this is a cross-build.
-       echo i586-pc-msdosdjgpp
-       exit ;;
+       GUESS=i586-pc-msdosdjgpp
+       ;;
     Intel:Mach:3*:*)
-       echo i386-pc-mach3
-       exit ;;
+       GUESS=i386-pc-mach3
+       ;;
     paragon:*:*:*)
-       echo i860-intel-osf1
-       exit ;;
+       GUESS=i860-intel-osf1
+       ;;
     i860:*:4.*:*) # i860-SVR4
        if grep Stardent /usr/include/sys/uadmin.h >/dev/null 2>&1 ; then
-         echo i860-stardent-sysv"$UNAME_RELEASE" # Stardent Vistra i860-SVR4
+         GUESS=i860-stardent-sysv$UNAME_RELEASE    # Stardent Vistra i860-SVR4
        else # Add other i860-SVR4 vendors below as they are discovered.
-         echo i860-unknown-sysv"$UNAME_RELEASE"  # Unknown i860-SVR4
+         GUESS=i860-unknown-sysv$UNAME_RELEASE     # Unknown i860-SVR4
        fi
-       exit ;;
+       ;;
     mini*:CTIX:SYS*5:*)
        # "miniframe"
-       echo m68010-convergent-sysv
-       exit ;;
+       GUESS=m68010-convergent-sysv
+       ;;
     mc68k:UNIX:SYSTEM5:3.51m)
-       echo m68k-convergent-sysv
-       exit ;;
+       GUESS=m68k-convergent-sysv
+       ;;
     M680?0:D-NIX:5.3:*)
-       echo m68k-diab-dnix
-       exit ;;
+       GUESS=m68k-diab-dnix
+       ;;
     M68*:*:R3V[5678]*:*)
        test -r /sysV68 && { echo 'm68k-motorola-sysv'; exit; } ;;
     3[345]??:*:4.0:3.0 | 3[34]??A:*:4.0:3.0 | 3[34]??,*:*:4.0:3.0 | 3[34]??/*:*:4.0:3.0 | 4400:*:4.0:3.0 | 4850:*:4.0:3.0 | SKA40:*:4.0:3.0 | SDS2:*:4.0:3.0 | SHG2:*:4.0:3.0 | S7501*:*:4.0:3.0)
@@ -1235,113 +1307,119 @@ EOF
        /bin/uname -p 2>/dev/null | /bin/grep pteron >/dev/null \
            && { echo i586-ncr-sysv4.3"$OS_REL"; exit; } ;;
     m68*:LynxOS:2.*:* | m68*:LynxOS:3.0*:*)
-       echo m68k-unknown-lynxos"$UNAME_RELEASE"
-       exit ;;
+       GUESS=m68k-unknown-lynxos$UNAME_RELEASE
+       ;;
     mc68030:UNIX_System_V:4.*:*)
-       echo m68k-atari-sysv4
-       exit ;;
+       GUESS=m68k-atari-sysv4
+       ;;
     TSUNAMI:LynxOS:2.*:*)
-       echo sparc-unknown-lynxos"$UNAME_RELEASE"
-       exit ;;
+       GUESS=sparc-unknown-lynxos$UNAME_RELEASE
+       ;;
     rs6000:LynxOS:2.*:*)
-       echo rs6000-unknown-lynxos"$UNAME_RELEASE"
-       exit ;;
+       GUESS=rs6000-unknown-lynxos$UNAME_RELEASE
+       ;;
     PowerPC:LynxOS:2.*:* | PowerPC:LynxOS:3.[01]*:* | PowerPC:LynxOS:4.[02]*:*)
-       echo powerpc-unknown-lynxos"$UNAME_RELEASE"
-       exit ;;
+       GUESS=powerpc-unknown-lynxos$UNAME_RELEASE
+       ;;
     SM[BE]S:UNIX_SV:*:*)
-       echo mips-dde-sysv"$UNAME_RELEASE"
-       exit ;;
+       GUESS=mips-dde-sysv$UNAME_RELEASE
+       ;;
     RM*:ReliantUNIX-*:*:*)
-       echo mips-sni-sysv4
-       exit ;;
+       GUESS=mips-sni-sysv4
+       ;;
     RM*:SINIX-*:*:*)
-       echo mips-sni-sysv4
-       exit ;;
+       GUESS=mips-sni-sysv4
+       ;;
     *:SINIX-*:*:*)
        if uname -p 2>/dev/null >/dev/null ; then
                UNAME_MACHINE=`(uname -p) 2>/dev/null`
-               echo "$UNAME_MACHINE"-sni-sysv4
+               GUESS=$UNAME_MACHINE-sni-sysv4
        else
-               echo ns32k-sni-sysv
+               GUESS=ns32k-sni-sysv
        fi
-       exit ;;
+       ;;
     PENTIUM:*:4.0*:*)  # Unisys `ClearPath HMP IX 4000' SVR4/MP effort
                        # says <Richard.M.Bartel@ccMail.Census.GOV>
-       echo i586-unisys-sysv4
-       exit ;;
+       GUESS=i586-unisys-sysv4
+       ;;
     *:UNIX_System_V:4*:FTX*)
        # From Gerald Hewes <hewes@openmarket.com>.
        # How about differentiating between stratus architectures? -djm
-       echo hppa1.1-stratus-sysv4
-       exit ;;
+       GUESS=hppa1.1-stratus-sysv4
+       ;;
     *:*:*:FTX*)
        # From seanf@swdc.stratus.com.
-       echo i860-stratus-sysv4
-       exit ;;
+       GUESS=i860-stratus-sysv4
+       ;;
     i*86:VOS:*:*)
        # From Paul.Green@stratus.com.
-       echo "$UNAME_MACHINE"-stratus-vos
-       exit ;;
+       GUESS=$UNAME_MACHINE-stratus-vos
+       ;;
     *:VOS:*:*)
        # From Paul.Green@stratus.com.
-       echo hppa1.1-stratus-vos
-       exit ;;
+       GUESS=hppa1.1-stratus-vos
+       ;;
     mc68*:A/UX:*:*)
-       echo m68k-apple-aux"$UNAME_RELEASE"
-       exit ;;
+       GUESS=m68k-apple-aux$UNAME_RELEASE
+       ;;
     news*:NEWS-OS:6*:*)
-       echo mips-sony-newsos6
-       exit ;;
+       GUESS=mips-sony-newsos6
+       ;;
     R[34]000:*System_V*:*:* | R4000:UNIX_SYSV:*:* | R*000:UNIX_SV:*:*)
-       if [ -d /usr/nec ]; then
-               echo mips-nec-sysv"$UNAME_RELEASE"
+       if test -d /usr/nec; then
+               GUESS=mips-nec-sysv$UNAME_RELEASE
        else
-               echo mips-unknown-sysv"$UNAME_RELEASE"
+               GUESS=mips-unknown-sysv$UNAME_RELEASE
        fi
-       exit ;;
+       ;;
     BeBox:BeOS:*:*)    # BeOS running on hardware made by Be, PPC only.
-       echo powerpc-be-beos
-       exit ;;
+       GUESS=powerpc-be-beos
+       ;;
     BeMac:BeOS:*:*)    # BeOS running on Mac or Mac clone, PPC only.
-       echo powerpc-apple-beos
-       exit ;;
+       GUESS=powerpc-apple-beos
+       ;;
     BePC:BeOS:*:*)     # BeOS running on Intel PC compatible.
-       echo i586-pc-beos
-       exit ;;
+       GUESS=i586-pc-beos
+       ;;
     BePC:Haiku:*:*)    # Haiku running on Intel PC compatible.
-       echo i586-pc-haiku
-       exit ;;
-    x86_64:Haiku:*:*)
-       echo x86_64-unknown-haiku
-       exit ;;
+       GUESS=i586-pc-haiku
+       ;;
+    ppc:Haiku:*:*)     # Haiku running on Apple PowerPC
+       GUESS=powerpc-apple-haiku
+       ;;
+    *:Haiku:*:*)       # Haiku modern gcc (not bound by BeOS compat)
+       GUESS=$UNAME_MACHINE-unknown-haiku
+       ;;
     SX-4:SUPER-UX:*:*)
-       echo sx4-nec-superux"$UNAME_RELEASE"
-       exit ;;
+       GUESS=sx4-nec-superux$UNAME_RELEASE
+       ;;
     SX-5:SUPER-UX:*:*)
-       echo sx5-nec-superux"$UNAME_RELEASE"
-       exit ;;
+       GUESS=sx5-nec-superux$UNAME_RELEASE
+       ;;
     SX-6:SUPER-UX:*:*)
-       echo sx6-nec-superux"$UNAME_RELEASE"
-       exit ;;
+       GUESS=sx6-nec-superux$UNAME_RELEASE
+       ;;
     SX-7:SUPER-UX:*:*)
-       echo sx7-nec-superux"$UNAME_RELEASE"
-       exit ;;
+       GUESS=sx7-nec-superux$UNAME_RELEASE
+       ;;
     SX-8:SUPER-UX:*:*)
-       echo sx8-nec-superux"$UNAME_RELEASE"
-       exit ;;
+       GUESS=sx8-nec-superux$UNAME_RELEASE
+       ;;
     SX-8R:SUPER-UX:*:*)
-       echo sx8r-nec-superux"$UNAME_RELEASE"
-       exit ;;
+       GUESS=sx8r-nec-superux$UNAME_RELEASE
+       ;;
     SX-ACE:SUPER-UX:*:*)
-       echo sxace-nec-superux"$UNAME_RELEASE"
-       exit ;;
+       GUESS=sxace-nec-superux$UNAME_RELEASE
+       ;;
     Power*:Rhapsody:*:*)
-       echo powerpc-apple-rhapsody"$UNAME_RELEASE"
-       exit ;;
+       GUESS=powerpc-apple-rhapsody$UNAME_RELEASE
+       ;;
     *:Rhapsody:*:*)
-       echo "$UNAME_MACHINE"-apple-rhapsody"$UNAME_RELEASE"
-       exit ;;
+       GUESS=$UNAME_MACHINE-apple-rhapsody$UNAME_RELEASE
+       ;;
+    arm64:Darwin:*:*)
+       GUESS=aarch64-apple-darwin$UNAME_RELEASE
+       ;;
     *:Darwin:*:*)
        UNAME_PROCESSOR=`uname -p`
        case $UNAME_PROCESSOR in
@@ -1356,7 +1434,7 @@ EOF
        else
            set_cc_for_build
        fi
-       if [ "$CC_FOR_BUILD" != no_compiler_found ]; then
+       if test "$CC_FOR_BUILD" != no_compiler_found; then
            if (echo '#ifdef __LP64__'; echo IS_64BIT_ARCH; echo '#endif') | \
                   (CCOPTS="" $CC_FOR_BUILD -E - 2>/dev/null) | \
                   grep IS_64BIT_ARCH >/dev/null
@@ -1377,109 +1455,119 @@ EOF
            # uname -m returns i386 or x86_64
            UNAME_PROCESSOR=$UNAME_MACHINE
        fi
-       echo "$UNAME_PROCESSOR"-apple-darwin"$UNAME_RELEASE"
-       exit ;;
+       GUESS=$UNAME_PROCESSOR-apple-darwin$UNAME_RELEASE
+       ;;
     *:procnto*:*:* | *:QNX:[0123456789]*:*)
        UNAME_PROCESSOR=`uname -p`
        if test "$UNAME_PROCESSOR" = x86; then
                UNAME_PROCESSOR=i386
                UNAME_MACHINE=pc
        fi
-       echo "$UNAME_PROCESSOR"-"$UNAME_MACHINE"-nto-qnx"$UNAME_RELEASE"
-       exit ;;
+       GUESS=$UNAME_PROCESSOR-$UNAME_MACHINE-nto-qnx$UNAME_RELEASE
+       ;;
     *:QNX:*:4*)
-       echo i386-pc-qnx
-       exit ;;
+       GUESS=i386-pc-qnx
+       ;;
     NEO-*:NONSTOP_KERNEL:*:*)
-       echo neo-tandem-nsk"$UNAME_RELEASE"
-       exit ;;
+       GUESS=neo-tandem-nsk$UNAME_RELEASE
+       ;;
     NSE-*:NONSTOP_KERNEL:*:*)
-       echo nse-tandem-nsk"$UNAME_RELEASE"
-       exit ;;
+       GUESS=nse-tandem-nsk$UNAME_RELEASE
+       ;;
     NSR-*:NONSTOP_KERNEL:*:*)
-       echo nsr-tandem-nsk"$UNAME_RELEASE"
-       exit ;;
+       GUESS=nsr-tandem-nsk$UNAME_RELEASE
+       ;;
     NSV-*:NONSTOP_KERNEL:*:*)
-       echo nsv-tandem-nsk"$UNAME_RELEASE"
-       exit ;;
+       GUESS=nsv-tandem-nsk$UNAME_RELEASE
+       ;;
     NSX-*:NONSTOP_KERNEL:*:*)
-       echo nsx-tandem-nsk"$UNAME_RELEASE"
-       exit ;;
+       GUESS=nsx-tandem-nsk$UNAME_RELEASE
+       ;;
     *:NonStop-UX:*:*)
-       echo mips-compaq-nonstopux
-       exit ;;
+       GUESS=mips-compaq-nonstopux
+       ;;
     BS2000:POSIX*:*:*)
-       echo bs2000-siemens-sysv
-       exit ;;
+       GUESS=bs2000-siemens-sysv
+       ;;
     DS/*:UNIX_System_V:*:*)
-       echo "$UNAME_MACHINE"-"$UNAME_SYSTEM"-"$UNAME_RELEASE"
-       exit ;;
+       GUESS=$UNAME_MACHINE-$UNAME_SYSTEM-$UNAME_RELEASE
+       ;;
     *:Plan9:*:*)
        # "uname -m" is not consistent, so use $cputype instead. 386
        # is converted to i386 for consistency with other x86
        # operating systems.
-       # shellcheck disable=SC2154
-       if test "$cputype" = 386; then
+       if test "${cputype-}" = 386; then
            UNAME_MACHINE=i386
-       else
-           UNAME_MACHINE="$cputype"
+       elif test "x${cputype-}" != x; then
+           UNAME_MACHINE=$cputype
        fi
-       echo "$UNAME_MACHINE"-unknown-plan9
-       exit ;;
+       GUESS=$UNAME_MACHINE-unknown-plan9
+       ;;
     *:TOPS-10:*:*)
-       echo pdp10-unknown-tops10
-       exit ;;
+       GUESS=pdp10-unknown-tops10
+       ;;
     *:TENEX:*:*)
-       echo pdp10-unknown-tenex
-       exit ;;
+       GUESS=pdp10-unknown-tenex
+       ;;
     KS10:TOPS-20:*:* | KL10:TOPS-20:*:* | TYPE4:TOPS-20:*:*)
-       echo pdp10-dec-tops20
-       exit ;;
+       GUESS=pdp10-dec-tops20
+       ;;
     XKL-1:TOPS-20:*:* | TYPE5:TOPS-20:*:*)
-       echo pdp10-xkl-tops20
-       exit ;;
+       GUESS=pdp10-xkl-tops20
+       ;;
     *:TOPS-20:*:*)
-       echo pdp10-unknown-tops20
-       exit ;;
+       GUESS=pdp10-unknown-tops20
+       ;;
     *:ITS:*:*)
-       echo pdp10-unknown-its
-       exit ;;
+       GUESS=pdp10-unknown-its
+       ;;
     SEI:*:*:SEIUX)
-       echo mips-sei-seiux"$UNAME_RELEASE"
-       exit ;;
+       GUESS=mips-sei-seiux$UNAME_RELEASE
+       ;;
     *:DragonFly:*:*)
-       echo "$UNAME_MACHINE"-unknown-dragonfly"`echo "$UNAME_RELEASE"|sed -e 's/[-(].*//'`"
-       exit ;;
+       DRAGONFLY_REL=`echo "$UNAME_RELEASE" | sed -e 's/[-(].*//'`
+       GUESS=$UNAME_MACHINE-unknown-dragonfly$DRAGONFLY_REL
+       ;;
     *:*VMS:*:*)
        UNAME_MACHINE=`(uname -p) 2>/dev/null`
-       case "$UNAME_MACHINE" in
-           A*) echo alpha-dec-vms ; exit ;;
-           I*) echo ia64-dec-vms ; exit ;;
-           V*) echo vax-dec-vms ; exit ;;
+       case $UNAME_MACHINE in
+           A*) GUESS=alpha-dec-vms ;;
+           I*) GUESS=ia64-dec-vms ;;
+           V*) GUESS=vax-dec-vms ;;
        esac ;;
     *:XENIX:*:SysV)
-       echo i386-pc-xenix
-       exit ;;
+       GUESS=i386-pc-xenix
+       ;;
     i*86:skyos:*:*)
-       echo "$UNAME_MACHINE"-pc-skyos"`echo "$UNAME_RELEASE" | sed -e 's/ .*$//'`"
-       exit ;;
+       SKYOS_REL=`echo "$UNAME_RELEASE" | sed -e 's/ .*$//'`
+       GUESS=$UNAME_MACHINE-pc-skyos$SKYOS_REL
+       ;;
     i*86:rdos:*:*)
-       echo "$UNAME_MACHINE"-pc-rdos
-       exit ;;
-    i*86:AROS:*:*)
-       echo "$UNAME_MACHINE"-pc-aros
-       exit ;;
+       GUESS=$UNAME_MACHINE-pc-rdos
+       ;;
+    i*86:Fiwix:*:*)
+       GUESS=$UNAME_MACHINE-pc-fiwix
+       ;;
+    *:AROS:*:*)
+       GUESS=$UNAME_MACHINE-unknown-aros
+       ;;
     x86_64:VMkernel:*:*)
-       echo "$UNAME_MACHINE"-unknown-esx
-       exit ;;
+       GUESS=$UNAME_MACHINE-unknown-esx
+       ;;
     amd64:Isilon\ OneFS:*:*)
-       echo x86_64-unknown-onefs
-       exit ;;
+       GUESS=x86_64-unknown-onefs
+       ;;
     *:Unleashed:*:*)
-       echo "$UNAME_MACHINE"-unknown-unleashed"$UNAME_RELEASE"
-       exit ;;
+       GUESS=$UNAME_MACHINE-unknown-unleashed$UNAME_RELEASE
+       ;;
 esac
 
+# Do we have a guess based on uname results?
+if test "x$GUESS" != x; then
+    echo "$GUESS"
+    exit
+fi
+
 # No uname command or uname output not recognized.
 set_cc_for_build
 cat > "$dummy.c" <<EOF
@@ -1611,7 +1699,7 @@ main ()
 }
 EOF
 
-$CC_FOR_BUILD -o "$dummy" "$dummy.c" 2>/dev/null && SYSTEM_NAME=`$dummy` &&
+$CC_FOR_BUILD -o "$dummy" "$dummy.c" 2>/dev/null && SYSTEM_NAME=`"$dummy"` &&
        { echo "$SYSTEM_NAME"; exit; }
 
 # Apollos put the system type in the environment.
@@ -1619,7 +1707,7 @@ test -d /usr/apollo && { echo "$ISP-apollo-$SYSTYPE"; exit; }
 
 echo "$0: unable to guess system type" >&2
 
-case "$UNAME_MACHINE:$UNAME_SYSTEM" in
+case $UNAME_MACHINE:$UNAME_SYSTEM in
     mips:Linux | mips64:Linux)
        # If we got here on MIPS GNU/Linux, output extra information.
        cat >&2 <<EOF
@@ -1636,14 +1724,16 @@ This script (version $timestamp), has failed to recognize the
 operating system you are using. If your script is old, overwrite *all*
 copies of config.guess and config.sub with the latest versions from:
 
-  https://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.guess
+  https://git.savannah.gnu.org/cgit/config.git/plain/config.guess
 and
-  https://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.sub
+  https://git.savannah.gnu.org/cgit/config.git/plain/config.sub
 EOF
 
-year=`echo $timestamp | sed 's,-.*,,'`
+our_year=`echo $timestamp | sed 's,-.*,,'`
+thisyear=`date +%Y`
 # shellcheck disable=SC2003
-if test "`expr "\`date +%Y\`" - "$year"`" -lt 3 ; then
+script_age=`expr "$thisyear" - "$our_year"`
+if test "$script_age" -lt 3 ; then
    cat >&2 <<EOF
 
 If $0 has already been updated, send the following data and any
index 973a2980ac3ad53d126199f5b7446e86344347a9..de4259e4047972f77ffc089796b32e325636c207 100644 (file)
@@ -1,12 +1,14 @@
 #! /bin/sh
 # Configuration validation subroutine script.
-#   Copyright 1992-2020 Free Software Foundation, Inc.
+#   Copyright 1992-2023 Free Software Foundation, Inc.
 
-timestamp='2020-05-04'
+# shellcheck disable=SC2006,SC2268 # see below for rationale
+
+timestamp='2023-01-21'
 
 # This file 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
+# 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
@@ -33,7 +35,7 @@ timestamp='2020-05-04'
 # Otherwise, we print the canonical config type on stdout and succeed.
 
 # You can get the latest version of this script from:
-# https://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.sub
+# https://git.savannah.gnu.org/cgit/config.git/plain/config.sub
 
 # This file is supposed to be the same for all GNU packages
 # and recognize all the CPU types, system types and aliases
@@ -50,6 +52,13 @@ timestamp='2020-05-04'
 #      CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM
 # It is wrong to echo any other type of specification.
 
+# The "shellcheck disable" line above the timestamp inhibits complaints
+# about features and limitations of the classic Bourne shell that were
+# superseded or lifted in POSIX.  However, this script identifies a wide
+# variety of pre-POSIX systems that do not have POSIX shells at all, and
+# even some reasonably current systems (Solaris 10 as case-in-point) still
+# have a pre-POSIX /bin/sh.
+
 me=`echo "$0" | sed -e 's,.*/,,'`
 
 usage="\
@@ -67,7 +76,7 @@ Report bugs and patches to <config-patches@gnu.org>."
 version="\
 GNU config.sub ($timestamp)
 
-Copyright 1992-2020 Free Software Foundation, Inc.
+Copyright 1992-2023 Free Software Foundation, Inc.
 
 This is free software; see the source for copying conditions.  There is NO
 warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE."
@@ -112,9 +121,11 @@ esac
 
 # Split fields of configuration type
 # shellcheck disable=SC2162
+saved_IFS=$IFS
 IFS="-" read field1 field2 field3 field4 <<EOF
 $1
 EOF
+IFS=$saved_IFS
 
 # Separate into logical components for further validation
 case $1 in
@@ -124,28 +135,27 @@ case $1 in
                ;;
        *-*-*-*)
                basic_machine=$field1-$field2
-               os=$field3-$field4
+               basic_os=$field3-$field4
                ;;
        *-*-*)
                # Ambiguous whether COMPANY is present, or skipped and KERNEL-OS is two
                # parts
                maybe_os=$field2-$field3
                case $maybe_os in
-                       nto-qnx* | linux-gnu* | linux-android* | linux-dietlibc \
-                       | linux-newlib* | linux-musl* | linux-uclibc* | uclinux-uclibc* \
+                       nto-qnx* | linux-* | uclinux-uclibc* \
                        | uclinux-gnu* | kfreebsd*-gnu* | knetbsd*-gnu* | netbsd*-gnu* \
                        | netbsd*-eabi* | kopensolaris*-gnu* | cloudabi*-eabi* \
-                       | storm-chaos* | os2-emx* | rtmk-nova*)
+                       | storm-chaos* | os2-emx* | rtmk-nova* | managarm-*)
                                basic_machine=$field1
-                               os=$maybe_os
+                               basic_os=$maybe_os
                                ;;
                        android-linux)
                                basic_machine=$field1-unknown
-                               os=linux-android
+                               basic_os=linux-android
                                ;;
                        *)
                                basic_machine=$field1-$field2
-                               os=$field3
+                               basic_os=$field3
                                ;;
                esac
                ;;
@@ -154,7 +164,7 @@ case $1 in
                case $field1-$field2 in
                        decstation-3100)
                                basic_machine=mips-dec
-                               os=
+                               basic_os=
                                ;;
                        *-*)
                                # Second component is usually, but not always the OS
@@ -162,7 +172,11 @@ case $1 in
                                        # Prevent following clause from handling this valid os
                                        sun*os*)
                                                basic_machine=$field1
-                                               os=$field2
+                                               basic_os=$field2
+                                               ;;
+                                       zephyr*)
+                                               basic_machine=$field1-unknown
+                                               basic_os=$field2
                                                ;;
                                        # Manufacturers
                                        dec* | mips* | sequent* | encore* | pc533* | sgi* | sony* \
@@ -175,11 +189,11 @@ case $1 in
                                        | microblaze* | sim | cisco \
                                        | oki | wec | wrs | winbond)
                                                basic_machine=$field1-$field2
-                                               os=
+                                               basic_os=
                                                ;;
                                        *)
                                                basic_machine=$field1
-                                               os=$field2
+                                               basic_os=$field2
                                                ;;
                                esac
                        ;;
@@ -191,447 +205,451 @@ case $1 in
                case $field1 in
                        386bsd)
                                basic_machine=i386-pc
-                               os=bsd
+                               basic_os=bsd
                                ;;
                        a29khif)
                                basic_machine=a29k-amd
-                               os=udi
+                               basic_os=udi
                                ;;
                        adobe68k)
                                basic_machine=m68010-adobe
-                               os=scout
+                               basic_os=scout
                                ;;
                        alliant)
                                basic_machine=fx80-alliant
-                               os=
+                               basic_os=
                                ;;
                        altos | altos3068)
                                basic_machine=m68k-altos
-                               os=
+                               basic_os=
                                ;;
                        am29k)
                                basic_machine=a29k-none
-                               os=bsd
+                               basic_os=bsd
                                ;;
                        amdahl)
                                basic_machine=580-amdahl
-                               os=sysv
+                               basic_os=sysv
                                ;;
                        amiga)
                                basic_machine=m68k-unknown
-                               os=
+                               basic_os=
                                ;;
                        amigaos | amigados)
                                basic_machine=m68k-unknown
-                               os=amigaos
+                               basic_os=amigaos
                                ;;
                        amigaunix | amix)
                                basic_machine=m68k-unknown
-                               os=sysv4
+                               basic_os=sysv4
                                ;;
                        apollo68)
                                basic_machine=m68k-apollo
-                               os=sysv
+                               basic_os=sysv
                                ;;
                        apollo68bsd)
                                basic_machine=m68k-apollo
-                               os=bsd
+                               basic_os=bsd
                                ;;
                        aros)
                                basic_machine=i386-pc
-                               os=aros
+                               basic_os=aros
                                ;;
                        aux)
                                basic_machine=m68k-apple
-                               os=aux
+                               basic_os=aux
                                ;;
                        balance)
                                basic_machine=ns32k-sequent
-                               os=dynix
+                               basic_os=dynix
                                ;;
                        blackfin)
                                basic_machine=bfin-unknown
-                               os=linux
+                               basic_os=linux
                                ;;
                        cegcc)
                                basic_machine=arm-unknown
-                               os=cegcc
+                               basic_os=cegcc
                                ;;
                        convex-c1)
                                basic_machine=c1-convex
-                               os=bsd
+                               basic_os=bsd
                                ;;
                        convex-c2)
                                basic_machine=c2-convex
-                               os=bsd
+                               basic_os=bsd
                                ;;
                        convex-c32)
                                basic_machine=c32-convex
-                               os=bsd
+                               basic_os=bsd
                                ;;
                        convex-c34)
                                basic_machine=c34-convex
-                               os=bsd
+                               basic_os=bsd
                                ;;
                        convex-c38)
                                basic_machine=c38-convex
-                               os=bsd
+                               basic_os=bsd
                                ;;
                        cray)
                                basic_machine=j90-cray
-                               os=unicos
+                               basic_os=unicos
                                ;;
                        crds | unos)
                                basic_machine=m68k-crds
-                               os=
+                               basic_os=
                                ;;
                        da30)
                                basic_machine=m68k-da30
-                               os=
+                               basic_os=
                                ;;
                        decstation | pmax | pmin | dec3100 | decstatn)
                                basic_machine=mips-dec
-                               os=
+                               basic_os=
                                ;;
                        delta88)
                                basic_machine=m88k-motorola
-                               os=sysv3
+                               basic_os=sysv3
                                ;;
                        dicos)
                                basic_machine=i686-pc
-                               os=dicos
+                               basic_os=dicos
                                ;;
                        djgpp)
                                basic_machine=i586-pc
-                               os=msdosdjgpp
+                               basic_os=msdosdjgpp
                                ;;
                        ebmon29k)
                                basic_machine=a29k-amd
-                               os=ebmon
+                               basic_os=ebmon
                                ;;
                        es1800 | OSE68k | ose68k | ose | OSE)
                                basic_machine=m68k-ericsson
-                               os=ose
+                               basic_os=ose
                                ;;
                        gmicro)
                                basic_machine=tron-gmicro
-                               os=sysv
+                               basic_os=sysv
                                ;;
                        go32)
                                basic_machine=i386-pc
-                               os=go32
+                               basic_os=go32
                                ;;
                        h8300hms)
                                basic_machine=h8300-hitachi
-                               os=hms
+                               basic_os=hms
                                ;;
                        h8300xray)
                                basic_machine=h8300-hitachi
-                               os=xray
+                               basic_os=xray
                                ;;
                        h8500hms)
                                basic_machine=h8500-hitachi
-                               os=hms
+                               basic_os=hms
                                ;;
                        harris)
                                basic_machine=m88k-harris
-                               os=sysv3
+                               basic_os=sysv3
                                ;;
                        hp300 | hp300hpux)
                                basic_machine=m68k-hp
-                               os=hpux
+                               basic_os=hpux
                                ;;
                        hp300bsd)
                                basic_machine=m68k-hp
-                               os=bsd
+                               basic_os=bsd
                                ;;
                        hppaosf)
                                basic_machine=hppa1.1-hp
-                               os=osf
+                               basic_os=osf
                                ;;
                        hppro)
                                basic_machine=hppa1.1-hp
-                               os=proelf
+                               basic_os=proelf
                                ;;
                        i386mach)
                                basic_machine=i386-mach
-                               os=mach
+                               basic_os=mach
                                ;;
                        isi68 | isi)
                                basic_machine=m68k-isi
-                               os=sysv
+                               basic_os=sysv
                                ;;
                        m68knommu)
                                basic_machine=m68k-unknown
-                               os=linux
+                               basic_os=linux
                                ;;
                        magnum | m3230)
                                basic_machine=mips-mips
-                               os=sysv
+                               basic_os=sysv
                                ;;
                        merlin)
                                basic_machine=ns32k-utek
-                               os=sysv
+                               basic_os=sysv
                                ;;
                        mingw64)
                                basic_machine=x86_64-pc
-                               os=mingw64
+                               basic_os=mingw64
                                ;;
                        mingw32)
                                basic_machine=i686-pc
-                               os=mingw32
+                               basic_os=mingw32
                                ;;
                        mingw32ce)
                                basic_machine=arm-unknown
-                               os=mingw32ce
+                               basic_os=mingw32ce
                                ;;
                        monitor)
                                basic_machine=m68k-rom68k
-                               os=coff
+                               basic_os=coff
                                ;;
                        morphos)
                                basic_machine=powerpc-unknown
-                               os=morphos
+                               basic_os=morphos
                                ;;
                        moxiebox)
                                basic_machine=moxie-unknown
-                               os=moxiebox
+                               basic_os=moxiebox
                                ;;
                        msdos)
                                basic_machine=i386-pc
-                               os=msdos
+                               basic_os=msdos
                                ;;
                        msys)
                                basic_machine=i686-pc
-                               os=msys
+                               basic_os=msys
                                ;;
                        mvs)
                                basic_machine=i370-ibm
-                               os=mvs
+                               basic_os=mvs
                                ;;
                        nacl)
                                basic_machine=le32-unknown
-                               os=nacl
+                               basic_os=nacl
                                ;;
                        ncr3000)
                                basic_machine=i486-ncr
-                               os=sysv4
+                               basic_os=sysv4
                                ;;
                        netbsd386)
                                basic_machine=i386-pc
-                               os=netbsd
+                               basic_os=netbsd
                                ;;
                        netwinder)
                                basic_machine=armv4l-rebel
-                               os=linux
+                               basic_os=linux
                                ;;
                        news | news700 | news800 | news900)
                                basic_machine=m68k-sony
-                               os=newsos
+                               basic_os=newsos
                                ;;
                        news1000)
                                basic_machine=m68030-sony
-                               os=newsos
+                               basic_os=newsos
                                ;;
                        necv70)
                                basic_machine=v70-nec
-                               os=sysv
+                               basic_os=sysv
                                ;;
                        nh3000)
                                basic_machine=m68k-harris
-                               os=cxux
+                               basic_os=cxux
                                ;;
                        nh[45]000)
                                basic_machine=m88k-harris
-                               os=cxux
+                               basic_os=cxux
                                ;;
                        nindy960)
                                basic_machine=i960-intel
-                               os=nindy
+                               basic_os=nindy
                                ;;
                        mon960)
                                basic_machine=i960-intel
-                               os=mon960
+                               basic_os=mon960
                                ;;
                        nonstopux)
                                basic_machine=mips-compaq
-                               os=nonstopux
+                               basic_os=nonstopux
                                ;;
                        os400)
                                basic_machine=powerpc-ibm
-                               os=os400
+                               basic_os=os400
                                ;;
                        OSE68000 | ose68000)
                                basic_machine=m68000-ericsson
-                               os=ose
+                               basic_os=ose
                                ;;
                        os68k)
                                basic_machine=m68k-none
-                               os=os68k
+                               basic_os=os68k
                                ;;
                        paragon)
                                basic_machine=i860-intel
-                               os=osf
+                               basic_os=osf
                                ;;
                        parisc)
                                basic_machine=hppa-unknown
-                               os=linux
+                               basic_os=linux
+                               ;;
+                       psp)
+                               basic_machine=mipsallegrexel-sony
+                               basic_os=psp
                                ;;
                        pw32)
                                basic_machine=i586-unknown
-                               os=pw32
+                               basic_os=pw32
                                ;;
                        rdos | rdos64)
                                basic_machine=x86_64-pc
-                               os=rdos
+                               basic_os=rdos
                                ;;
                        rdos32)
                                basic_machine=i386-pc
-                               os=rdos
+                               basic_os=rdos
                                ;;
                        rom68k)
                                basic_machine=m68k-rom68k
-                               os=coff
+                               basic_os=coff
                                ;;
                        sa29200)
                                basic_machine=a29k-amd
-                               os=udi
+                               basic_os=udi
                                ;;
                        sei)
                                basic_machine=mips-sei
-                               os=seiux
+                               basic_os=seiux
                                ;;
                        sequent)
                                basic_machine=i386-sequent
-                               os=
+                               basic_os=
                                ;;
                        sps7)
                                basic_machine=m68k-bull
-                               os=sysv2
+                               basic_os=sysv2
                                ;;
                        st2000)
                                basic_machine=m68k-tandem
-                               os=
+                               basic_os=
                                ;;
                        stratus)
                                basic_machine=i860-stratus
-                               os=sysv4
+                               basic_os=sysv4
                                ;;
                        sun2)
                                basic_machine=m68000-sun
-                               os=
+                               basic_os=
                                ;;
                        sun2os3)
                                basic_machine=m68000-sun
-                               os=sunos3
+                               basic_os=sunos3
                                ;;
                        sun2os4)
                                basic_machine=m68000-sun
-                               os=sunos4
+                               basic_os=sunos4
                                ;;
                        sun3)
                                basic_machine=m68k-sun
-                               os=
+                               basic_os=
                                ;;
                        sun3os3)
                                basic_machine=m68k-sun
-                               os=sunos3
+                               basic_os=sunos3
                                ;;
                        sun3os4)
                                basic_machine=m68k-sun
-                               os=sunos4
+                               basic_os=sunos4
                                ;;
                        sun4)
                                basic_machine=sparc-sun
-                               os=
+                               basic_os=
                                ;;
                        sun4os3)
                                basic_machine=sparc-sun
-                               os=sunos3
+                               basic_os=sunos3
                                ;;
                        sun4os4)
                                basic_machine=sparc-sun
-                               os=sunos4
+                               basic_os=sunos4
                                ;;
                        sun4sol2)
                                basic_machine=sparc-sun
-                               os=solaris2
+                               basic_os=solaris2
                                ;;
                        sun386 | sun386i | roadrunner)
                                basic_machine=i386-sun
-                               os=
+                               basic_os=
                                ;;
                        sv1)
                                basic_machine=sv1-cray
-                               os=unicos
+                               basic_os=unicos
                                ;;
                        symmetry)
                                basic_machine=i386-sequent
-                               os=dynix
+                               basic_os=dynix
                                ;;
                        t3e)
                                basic_machine=alphaev5-cray
-                               os=unicos
+                               basic_os=unicos
                                ;;
                        t90)
                                basic_machine=t90-cray
-                               os=unicos
+                               basic_os=unicos
                                ;;
                        toad1)
                                basic_machine=pdp10-xkl
-                               os=tops20
+                               basic_os=tops20
                                ;;
                        tpf)
                                basic_machine=s390x-ibm
-                               os=tpf
+                               basic_os=tpf
                                ;;
                        udi29k)
                                basic_machine=a29k-amd
-                               os=udi
+                               basic_os=udi
                                ;;
                        ultra3)
                                basic_machine=a29k-nyu
-                               os=sym1
+                               basic_os=sym1
                                ;;
                        v810 | necv810)
                                basic_machine=v810-nec
-                               os=none
+                               basic_os=none
                                ;;
                        vaxv)
                                basic_machine=vax-dec
-                               os=sysv
+                               basic_os=sysv
                                ;;
                        vms)
                                basic_machine=vax-dec
-                               os=vms
+                               basic_os=vms
                                ;;
                        vsta)
                                basic_machine=i386-pc
-                               os=vsta
+                               basic_os=vsta
                                ;;
                        vxworks960)
                                basic_machine=i960-wrs
-                               os=vxworks
+                               basic_os=vxworks
                                ;;
                        vxworks68)
                                basic_machine=m68k-wrs
-                               os=vxworks
+                               basic_os=vxworks
                                ;;
                        vxworks29k)
                                basic_machine=a29k-wrs
-                               os=vxworks
+                               basic_os=vxworks
                                ;;
                        xbox)
                                basic_machine=i686-pc
-                               os=mingw32
+                               basic_os=mingw32
                                ;;
                        ymp)
                                basic_machine=ymp-cray
-                               os=unicos
+                               basic_os=unicos
                                ;;
                        *)
                                basic_machine=$1
-                               os=
+                               basic_os=
                                ;;
                esac
                ;;
@@ -683,17 +701,17 @@ case $basic_machine in
        bluegene*)
                cpu=powerpc
                vendor=ibm
-               os=cnk
+               basic_os=cnk
                ;;
        decsystem10* | dec10*)
                cpu=pdp10
                vendor=dec
-               os=tops10
+               basic_os=tops10
                ;;
        decsystem20* | dec20*)
                cpu=pdp10
                vendor=dec
-               os=tops20
+               basic_os=tops20
                ;;
        delta | 3300 | motorola-3300 | motorola-delta \
              | 3300-motorola | delta-motorola)
@@ -703,7 +721,7 @@ case $basic_machine in
        dpx2*)
                cpu=m68k
                vendor=bull
-               os=sysv3
+               basic_os=sysv3
                ;;
        encore | umax | mmax)
                cpu=ns32k
@@ -712,7 +730,7 @@ case $basic_machine in
        elxsi)
                cpu=elxsi
                vendor=elxsi
-               os=${os:-bsd}
+               basic_os=${basic_os:-bsd}
                ;;
        fx2800)
                cpu=i860
@@ -725,7 +743,7 @@ case $basic_machine in
        h3050r* | hiux*)
                cpu=hppa1.1
                vendor=hitachi
-               os=hiuxwe2
+               basic_os=hiuxwe2
                ;;
        hp3k9[0-9][0-9] | hp9[0-9][0-9])
                cpu=hppa1.0
@@ -768,36 +786,36 @@ case $basic_machine in
        i*86v32)
                cpu=`echo "$1" | sed -e 's/86.*/86/'`
                vendor=pc
-               os=sysv32
+               basic_os=sysv32
                ;;
        i*86v4*)
                cpu=`echo "$1" | sed -e 's/86.*/86/'`
                vendor=pc
-               os=sysv4
+               basic_os=sysv4
                ;;
        i*86v)
                cpu=`echo "$1" | sed -e 's/86.*/86/'`
                vendor=pc
-               os=sysv
+               basic_os=sysv
                ;;
        i*86sol2)
                cpu=`echo "$1" | sed -e 's/86.*/86/'`
                vendor=pc
-               os=solaris2
+               basic_os=solaris2
                ;;
        j90 | j90-cray)
                cpu=j90
                vendor=cray
-               os=${os:-unicos}
+               basic_os=${basic_os:-unicos}
                ;;
        iris | iris4d)
                cpu=mips
                vendor=sgi
-               case $os in
+               case $basic_os in
                    irix*)
                        ;;
                    *)
-                       os=irix4
+                       basic_os=irix4
                        ;;
                esac
                ;;
@@ -808,26 +826,26 @@ case $basic_machine in
        *mint | mint[0-9]* | *MiNT | *MiNT[0-9]*)
                cpu=m68k
                vendor=atari
-               os=mint
+               basic_os=mint
                ;;
        news-3600 | risc-news)
                cpu=mips
                vendor=sony
-               os=newsos
+               basic_os=newsos
                ;;
        next | m*-next)
                cpu=m68k
                vendor=next
-               case $os in
+               case $basic_os in
                    openstep*)
                        ;;
                    nextstep*)
                        ;;
                    ns2*)
-                     os=nextstep2
+                     basic_os=nextstep2
                        ;;
                    *)
-                     os=nextstep3
+                     basic_os=nextstep3
                        ;;
                esac
                ;;
@@ -838,12 +856,12 @@ case $basic_machine in
        op50n-* | op60c-*)
                cpu=hppa1.1
                vendor=oki
-               os=proelf
+               basic_os=proelf
                ;;
        pa-hitachi)
                cpu=hppa1.1
                vendor=hitachi
-               os=hiuxwe2
+               basic_os=hiuxwe2
                ;;
        pbd)
                cpu=sparc
@@ -880,12 +898,12 @@ case $basic_machine in
        sde)
                cpu=mipsisa32
                vendor=sde
-               os=${os:-elf}
+               basic_os=${basic_os:-elf}
                ;;
        simso-wrs)
                cpu=sparclite
                vendor=wrs
-               os=vxworks
+               basic_os=vxworks
                ;;
        tower | tower-32)
                cpu=m68k
@@ -902,7 +920,7 @@ case $basic_machine in
        w89k-*)
                cpu=hppa1.1
                vendor=winbond
-               os=proelf
+               basic_os=proelf
                ;;
        none)
                cpu=none
@@ -919,9 +937,11 @@ case $basic_machine in
 
        *-*)
                # shellcheck disable=SC2162
+               saved_IFS=$IFS
                IFS="-" read cpu vendor <<EOF
 $basic_machine
 EOF
+               IFS=$saved_IFS
                ;;
        # We use `pc' rather than `unknown'
        # because (1) that's what they normally are, and
@@ -955,11 +975,11 @@ case $cpu-$vendor in
        # some cases the only manufacturer, in others, it is the most popular.
        craynv-unknown)
                vendor=cray
-               os=${os:-unicosmp}
+               basic_os=${basic_os:-unicosmp}
                ;;
        c90-unknown | c90-cray)
                vendor=cray
-               os=${os:-unicos}
+               basic_os=${Basic_os:-unicos}
                ;;
        fx80-unknown)
                vendor=alliant
@@ -1000,10 +1020,15 @@ case $cpu-$vendor in
                ;;
 
        # Here we normalize CPU types with a missing or matching vendor
+       armh-unknown | armh-alt)
+               cpu=armv7l
+               vendor=alt
+               basic_os=${basic_os:-linux-gnueabihf}
+               ;;
        dpx20-unknown | dpx20-bull)
                cpu=rs6000
                vendor=bull
-               os=${os:-bosx}
+               basic_os=${basic_os:-bosx}
                ;;
 
        # Here we normalize CPU types irrespective of the vendor
@@ -1012,7 +1037,7 @@ case $cpu-$vendor in
                ;;
        blackfin-*)
                cpu=bfin
-               os=linux
+               basic_os=linux
                ;;
        c54x-*)
                cpu=tic54x
@@ -1025,7 +1050,7 @@ case $cpu-$vendor in
                ;;
        e500v[12]-*)
                cpu=powerpc
-               os=$os"spe"
+               basic_os=${basic_os}"spe"
                ;;
        mips3*-*)
                cpu=mips64
@@ -1035,7 +1060,7 @@ case $cpu-$vendor in
                ;;
        m68knommu-*)
                cpu=m68k
-               os=linux
+               basic_os=linux
                ;;
        m9s12z-* | m68hcs12z-* | hcs12z-* | s12z-*)
                cpu=s12z
@@ -1045,12 +1070,12 @@ case $cpu-$vendor in
                ;;
        parisc-*)
                cpu=hppa
-               os=linux
+               basic_os=linux
                ;;
        pentium-* | p5-* | k5-* | k6-* | nexgen-* | viac3-*)
                cpu=i586
                ;;
-       pentiumpro-* | p6-* | 6x86-* | athlon-* | athalon_*-*)
+       pentiumpro-* | p6-* | 6x86-* | athlon-* | athlon_*-*)
                cpu=i686
                ;;
        pentiumii-* | pentium2-* | pentiumiii-* | pentium3-*)
@@ -1101,11 +1126,14 @@ case $cpu-$vendor in
        xscale-* | xscalee[bl]-*)
                cpu=`echo "$cpu" | sed 's/^xscale/arm/'`
                ;;
+       arm64-* | aarch64le-*)
+               cpu=aarch64
+               ;;
 
        # Recognize the canonical CPU Types that limit and/or modify the
        # company names they are paired with.
        cr16-*)
-               os=${os:-elf}
+               basic_os=${basic_os:-elf}
                ;;
        crisv32-* | etraxfs*-*)
                cpu=crisv32
@@ -1116,7 +1144,7 @@ case $cpu-$vendor in
                vendor=axis
                ;;
        crx-*)
-               os=${os:-elf}
+               basic_os=${basic_os:-elf}
                ;;
        neo-tandem)
                cpu=neo
@@ -1138,16 +1166,12 @@ case $cpu-$vendor in
                cpu=nsx
                vendor=tandem
                ;;
-       s390-*)
-               cpu=s390
-               vendor=ibm
-               ;;
-       s390x-*)
-               cpu=s390x
-               vendor=ibm
+       mipsallegrexel-sony)
+               cpu=mipsallegrexel
+               vendor=sony
                ;;
        tile*-*)
-               os=${os:-linux-gnu}
+               basic_os=${basic_os:-linux-gnu}
                ;;
 
        *)
@@ -1163,8 +1187,8 @@ case $cpu-$vendor in
                        | alphapca5[67] | alpha64pca5[67] \
                        | am33_2.0 \
                        | amdgcn \
-                       | arc | arceb \
-                       | arm  | arm[lb]e | arme[lb] | armv* \
+                       | arc | arceb | arc32 | arc64 \
+                       | arm | arm[lb]e | arme[lb] | armv* \
                        | avr | avr32 \
                        | asmjs \
                        | ba \
@@ -1183,6 +1207,7 @@ case $cpu-$vendor in
                        | k1om \
                        | le32 | le64 \
                        | lm32 \
+                       | loongarch32 | loongarch64 \
                        | m32c | m32r | m32rle \
                        | m5200 | m68000 | m680[012346]0 | m68360 | m683?2 | m68k \
                        | m6811 | m68hc11 | m6812 | m68hc12 | m68hcs12x \
@@ -1201,9 +1226,13 @@ case $cpu-$vendor in
                        | mips64vr5900 | mips64vr5900el \
                        | mipsisa32 | mipsisa32el \
                        | mipsisa32r2 | mipsisa32r2el \
+                       | mipsisa32r3 | mipsisa32r3el \
+                       | mipsisa32r5 | mipsisa32r5el \
                        | mipsisa32r6 | mipsisa32r6el \
                        | mipsisa64 | mipsisa64el \
                        | mipsisa64r2 | mipsisa64r2el \
+                       | mipsisa64r3 | mipsisa64r3el \
+                       | mipsisa64r5 | mipsisa64r5el \
                        | mipsisa64r6 | mipsisa64r6el \
                        | mipsisa64sb1 | mipsisa64sb1el \
                        | mipsisa64sr71k | mipsisa64sr71kel \
@@ -1227,8 +1256,9 @@ case $cpu-$vendor in
                        | powerpc | powerpc64 | powerpc64le | powerpcle | powerpcspe \
                        | pru \
                        | pyramid \
-                       | riscv | riscv32 | riscv64 \
+                       | riscv | riscv32 | riscv32be | riscv64 | riscv64be \
                        | rl78 | romp | rs6000 | rx \
+                       | s390 | s390x \
                        | score \
                        | sh | shl \
                        | sh[1234] | sh[24]a | sh[24]ae[lb] | sh[23]e | she[lb] | sh[lb]e \
@@ -1238,6 +1268,7 @@ case $cpu-$vendor in
                        | sparcv8 | sparcv9 | sparcv9b | sparcv9v | sv1 | sx* \
                        | spu \
                        | tahoe \
+                       | thumbv7* \
                        | tic30 | tic4x | tic54x | tic55x | tic6x | tic80 \
                        | tron \
                        | ubicom32 \
@@ -1275,8 +1306,53 @@ esac
 
 # Decode manufacturer-specific aliases for certain operating systems.
 
-if [ x$os != x ]
+if test x$basic_os != x
 then
+
+# First recognize some ad-hoc cases, or perhaps split kernel-os, or else just
+# set os.
+case $basic_os in
+       gnu/linux*)
+               kernel=linux
+               os=`echo "$basic_os" | sed -e 's|gnu/linux|gnu|'`
+               ;;
+       os2-emx)
+               kernel=os2
+               os=`echo "$basic_os" | sed -e 's|os2-emx|emx|'`
+               ;;
+       nto-qnx*)
+               kernel=nto
+               os=`echo "$basic_os" | sed -e 's|nto-qnx|qnx|'`
+               ;;
+       *-*)
+               # shellcheck disable=SC2162
+               saved_IFS=$IFS
+               IFS="-" read kernel os <<EOF
+$basic_os
+EOF
+               IFS=$saved_IFS
+               ;;
+       # Default OS when just kernel was specified
+       nto*)
+               kernel=nto
+               os=`echo "$basic_os" | sed -e 's|nto|qnx|'`
+               ;;
+       linux*)
+               kernel=linux
+               os=`echo "$basic_os" | sed -e 's|linux|gnu|'`
+               ;;
+       managarm*)
+               kernel=managarm
+               os=`echo "$basic_os" | sed -e 's|managarm|mlibc|'`
+               ;;
+       *)
+               kernel=
+               os=$basic_os
+               ;;
+esac
+
+# Now, normalize the OS (knowing we just have one component, it's not a kernel,
+# etc.)
 case $os in
        # First match some system type aliases that might get confused
        # with valid system types.
@@ -1288,7 +1364,7 @@ case $os in
                os=cnk
                ;;
        solaris1 | solaris1.*)
-               os=`echo $os | sed -e 's|solaris1|sunos4|'`
+               os=`echo "$os" | sed -e 's|solaris1|sunos4|'`
                ;;
        solaris)
                os=solaris2
@@ -1296,9 +1372,6 @@ case $os in
        unixware*)
                os=sysv4.2uw
                ;;
-       gnu/linux*)
-               os=`echo $os | sed -e 's|gnu/linux|linux-gnu|'`
-               ;;
        # es1800 is here to avoid being matched by es* (a different OS)
        es1800*)
                os=ose
@@ -1320,12 +1393,9 @@ case $os in
                os=sco3.2v4
                ;;
        sco3.2.[4-9]*)
-               os=`echo $os | sed -e 's/sco3.2./sco3.2v/'`
-               ;;
-       sco3.2v[4-9]* | sco5v6*)
-               # Don't forget version if it is 3.2v4 or newer.
+               os=`echo "$os" | sed -e 's/sco3.2./sco3.2v/'`
                ;;
-       scout)
+       sco*v* | scout)
                # Don't match below
                ;;
        sco*)
@@ -1334,78 +1404,25 @@ case $os in
        psos*)
                os=psos
                ;;
-       # Now accept the basic system types.
-       # The portable systems comes first.
-       # Each alternative MUST end in a * to match a version number.
-       # sysv* is not here because it comes later, after sysvr4.
-       gnu* | bsd* | mach* | minix* | genix* | ultrix* | irix* \
-            | *vms* | esix* | aix* | cnk* | sunos | sunos[34]*\
-            | hpux* | unos* | osf* | luna* | dgux* | auroraux* | solaris* \
-            | sym* | kopensolaris* | plan9* \
-            | amigaos* | amigados* | msdos* | newsos* | unicos* | aof* \
-            | aos* | aros* | cloudabi* | sortix* | twizzler* \
-            | nindy* | vxsim* | vxworks* | ebmon* | hms* | mvs* \
-            | clix* | riscos* | uniplus* | iris* | isc* | rtu* | xenix* \
-            | knetbsd* | mirbsd* | netbsd* \
-            | bitrig* | openbsd* | solidbsd* | libertybsd* | os108* \
-            | ekkobsd* | kfreebsd* | freebsd* | riscix* | lynxos* \
-            | bosx* | nextstep* | cxux* | aout* | elf* | oabi* \
-            | ptx* | coff* | ecoff* | winnt* | domain* | vsta* \
-            | udi* | eabi* | lites* | ieee* | go32* | aux* | hcos* \
-            | chorusrdb* | cegcc* | glidix* \
-            | cygwin* | msys* | pe* | moss* | proelf* | rtems* \
-            | midipix* | mingw32* | mingw64* | linux-gnu* | linux-android* \
-            | linux-newlib* | linux-musl* | linux-uclibc* \
-            | uxpv* | beos* | mpeix* | udk* | moxiebox* \
-            | interix* | uwin* | mks* | rhapsody* | darwin* \
-            | openstep* | oskit* | conix* | pw32* | nonstopux* \
-            | storm-chaos* | tops10* | tenex* | tops20* | its* \
-            | os2* | vos* | palmos* | uclinux* | nucleus* \
-            | morphos* | superux* | rtmk* | windiss* \
-            | powermax* | dnix* | nx6 | nx7 | sei* | dragonfly* \
-            | skyos* | haiku* | rdos* | toppers* | drops* | es* \
-            | onefs* | tirtos* | phoenix* | fuchsia* | redox* | bme* \
-            | midnightbsd* | amdhsa* | unleashed* | emscripten* | wasi* \
-            | nsk* | powerunix* | genode*)
-       # Remember, each alternative MUST END IN *, to match a version number.
-               ;;
        qnx*)
-               case $cpu in
-                   x86 | i*86)
-                       ;;
-                   *)
-                       os=nto-$os
-                       ;;
-               esac
+               os=qnx
                ;;
        hiux*)
                os=hiuxwe2
                ;;
-       nto-qnx*)
-               ;;
-       nto*)
-               os=`echo $os | sed -e 's|nto|nto-qnx|'`
-               ;;
-       sim | xray | os68k* | v88r* \
-           | windows* | osx | abug | netware* | os9* \
-           | macos* | mpw* | magic* | mmixware* | mon960* | lnews*)
-               ;;
-       linux-dietlibc)
-               os=linux-dietlibc
-               ;;
-       linux*)
-               os=`echo $os | sed -e 's|linux|linux-gnu|'`
-               ;;
        lynx*178)
                os=lynxos178
                ;;
        lynx*5)
                os=lynxos5
                ;;
+       lynxos*)
+               # don't get caught up in next wildcard
+               ;;
        lynx*)
                os=lynxos
                ;;
-       mac*)
+       mac[0-9]*)
                os=`echo "$os" | sed -e 's|mac|macos|'`
                ;;
        opened*)
@@ -1452,7 +1469,7 @@ case $os in
                ;;
        # Preserve the version number of sinix5.
        sinix5.*)
-               os=`echo $os | sed -e 's|sinix|sysv|'`
+               os=`echo "$os" | sed -e 's|sinix|sysv|'`
                ;;
        sinix*)
                os=sysv4
@@ -1475,18 +1492,12 @@ case $os in
        sysvr4)
                os=sysv4
                ;;
-       # This must come after sysvr4.
-       sysv*)
-               ;;
        ose*)
                os=ose
                ;;
        *mint | mint[0-9]* | *MiNT | MiNT[0-9]*)
                os=mint
                ;;
-       zvmoe)
-               os=zvmoe
-               ;;
        dicos*)
                os=dicos
                ;;
@@ -1503,19 +1514,11 @@ case $os in
                        ;;
                esac
                ;;
-       nacl*)
-               ;;
-       ios)
-               ;;
-       none)
-               ;;
-       *-eabi)
-               ;;
        *)
-               echo Invalid configuration \`"$1"\': system \`"$os"\' not recognized 1>&2
-               exit 1
+               # No normalization, but not necessarily accepted, that comes below.
                ;;
 esac
+
 else
 
 # Here we handle the default operating systems that come with various machines.
@@ -1528,6 +1531,7 @@ else
 # will signal an error saying that MANUFACTURER isn't an operating
 # system, and we'll never get to this point.
 
+kernel=
 case $cpu-$vendor in
        score-*)
                os=elf
@@ -1539,7 +1543,8 @@ case $cpu-$vendor in
                os=riscix1.2
                ;;
        arm*-rebel)
-               os=linux
+               kernel=linux
+               os=gnu
                ;;
        arm*-semi)
                os=aout
@@ -1705,84 +1710,193 @@ case $cpu-$vendor in
                os=none
                ;;
 esac
+
 fi
 
+# Now, validate our (potentially fixed-up) OS.
+case $os in
+       # Sometimes we do "kernel-libc", so those need to count as OSes.
+       musl* | newlib* | relibc* | uclibc*)
+               ;;
+       # Likewise for "kernel-abi"
+       eabi* | gnueabi*)
+               ;;
+       # VxWorks passes extra cpu info in the 4th filed.
+       simlinux | simwindows | spe)
+               ;;
+       # Now accept the basic system types.
+       # The portable systems comes first.
+       # Each alternative MUST end in a * to match a version number.
+       gnu* | android* | bsd* | mach* | minix* | genix* | ultrix* | irix* \
+            | *vms* | esix* | aix* | cnk* | sunos | sunos[34]* \
+            | hpux* | unos* | osf* | luna* | dgux* | auroraux* | solaris* \
+            | sym* |  plan9* | psp* | sim* | xray* | os68k* | v88r* \
+            | hiux* | abug | nacl* | netware* | windows* \
+            | os9* | macos* | osx* | ios* \
+            | mpw* | magic* | mmixware* | mon960* | lnews* \
+            | amigaos* | amigados* | msdos* | newsos* | unicos* | aof* \
+            | aos* | aros* | cloudabi* | sortix* | twizzler* \
+            | nindy* | vxsim* | vxworks* | ebmon* | hms* | mvs* \
+            | clix* | riscos* | uniplus* | iris* | isc* | rtu* | xenix* \
+            | mirbsd* | netbsd* | dicos* | openedition* | ose* \
+            | bitrig* | openbsd* | secbsd* | solidbsd* | libertybsd* | os108* \
+            | ekkobsd* | freebsd* | riscix* | lynxos* | os400* \
+            | bosx* | nextstep* | cxux* | aout* | elf* | oabi* \
+            | ptx* | coff* | ecoff* | winnt* | domain* | vsta* \
+            | udi* | lites* | ieee* | go32* | aux* | hcos* \
+            | chorusrdb* | cegcc* | glidix* | serenity* \
+            | cygwin* | msys* | pe* | moss* | proelf* | rtems* \
+            | midipix* | mingw32* | mingw64* | mint* \
+            | uxpv* | beos* | mpeix* | udk* | moxiebox* \
+            | interix* | uwin* | mks* | rhapsody* | darwin* \
+            | openstep* | oskit* | conix* | pw32* | nonstopux* \
+            | storm-chaos* | tops10* | tenex* | tops20* | its* \
+            | os2* | vos* | palmos* | uclinux* | nucleus* | morphos* \
+            | scout* | superux* | sysv* | rtmk* | tpf* | windiss* \
+            | powermax* | dnix* | nx6 | nx7 | sei* | dragonfly* \
+            | skyos* | haiku* | rdos* | toppers* | drops* | es* \
+            | onefs* | tirtos* | phoenix* | fuchsia* | redox* | bme* \
+            | midnightbsd* | amdhsa* | unleashed* | emscripten* | wasi* \
+            | nsk* | powerunix* | genode* | zvmoe* | qnx* | emx* | zephyr* \
+            | fiwix* | mlibc* )
+               ;;
+       # This one is extra strict with allowed versions
+       sco3.2v2 | sco3.2v[4-9]* | sco5v6*)
+               # Don't forget version if it is 3.2v4 or newer.
+               ;;
+       none)
+               ;;
+       kernel* )
+               # Restricted further below
+               ;;
+       *)
+               echo Invalid configuration \`"$1"\': OS \`"$os"\' not recognized 1>&2
+               exit 1
+               ;;
+esac
+
+# As a final step for OS-related things, validate the OS-kernel combination
+# (given a valid OS), if there is a kernel.
+case $kernel-$os in
+       linux-gnu* | linux-dietlibc* | linux-android* | linux-newlib* \
+                  | linux-musl* | linux-relibc* | linux-uclibc* | linux-mlibc* )
+               ;;
+       uclinux-uclibc* )
+               ;;
+       managarm-mlibc* | managarm-kernel* )
+               ;;
+       -dietlibc* | -newlib* | -musl* | -relibc* | -uclibc* | -mlibc* )
+               # These are just libc implementations, not actual OSes, and thus
+               # require a kernel.
+               echo "Invalid configuration \`$1': libc \`$os' needs explicit kernel." 1>&2
+               exit 1
+               ;;
+       -kernel* )
+               echo "Invalid configuration \`$1': \`$os' needs explicit kernel." 1>&2
+               exit 1
+               ;;
+       *-kernel* )
+               echo "Invalid configuration \`$1': \`$kernel' does not support \`$os'." 1>&2
+               exit 1
+               ;;
+       kfreebsd*-gnu* | kopensolaris*-gnu*)
+               ;;
+       vxworks-simlinux | vxworks-simwindows | vxworks-spe)
+               ;;
+       nto-qnx*)
+               ;;
+       os2-emx)
+               ;;
+       *-eabi* | *-gnueabi*)
+               ;;
+       -*)
+               # Blank kernel with real OS is always fine.
+               ;;
+       *-*)
+               echo "Invalid configuration \`$1': Kernel \`$kernel' not known to work with OS \`$os'." 1>&2
+               exit 1
+               ;;
+esac
+
 # Here we handle the case where we know the os, and the CPU type, but not the
 # manufacturer.  We pick the logical manufacturer.
 case $vendor in
        unknown)
-               case $os in
-                       riscix*)
+               case $cpu-$os in
+                       *-riscix*)
                                vendor=acorn
                                ;;
-                       sunos*)
+                       *-sunos*)
                                vendor=sun
                                ;;
-                       cnk*|-aix*)
+                       *-cnk* | *-aix*)
                                vendor=ibm
                                ;;
-                       beos*)
+                       *-beos*)
                                vendor=be
                                ;;
-                       hpux*)
+                       *-hpux*)
                                vendor=hp
                                ;;
-                       mpeix*)
+                       *-mpeix*)
                                vendor=hp
                                ;;
-                       hiux*)
+                       *-hiux*)
                                vendor=hitachi
                                ;;
-                       unos*)
+                       *-unos*)
                                vendor=crds
                                ;;
-                       dgux*)
+                       *-dgux*)
                                vendor=dg
                                ;;
-                       luna*)
+                       *-luna*)
                                vendor=omron
                                ;;
-                       genix*)
+                       *-genix*)
                                vendor=ns
                                ;;
-                       clix*)
+                       *-clix*)
                                vendor=intergraph
                                ;;
-                       mvs* | opened*)
+                       *-mvs* | *-opened*)
+                               vendor=ibm
+                               ;;
+                       *-os400*)
                                vendor=ibm
                                ;;
-                       os400*)
+                       s390-* | s390x-*)
                                vendor=ibm
                                ;;
-                       ptx*)
+                       *-ptx*)
                                vendor=sequent
                                ;;
-                       tpf*)
+                       *-tpf*)
                                vendor=ibm
                                ;;
-                       vxsim* | vxworks* | windiss*)
+                       *-vxsim* | *-vxworks* | *-windiss*)
                                vendor=wrs
                                ;;
-                       aux*)
+                       *-aux*)
                                vendor=apple
                                ;;
-                       hms*)
+                       *-hms*)
                                vendor=hitachi
                                ;;
-                       mpw* | macos*)
+                       *-mpw* | *-macos*)
                                vendor=apple
                                ;;
-                       *mint | mint[0-9]* | *MiNT | MiNT[0-9]*)
+                       *-*mint | *-mint[0-9]* | *-*MiNT | *-MiNT[0-9]*)
                                vendor=atari
                                ;;
-                       vos*)
+                       *-vos*)
                                vendor=stratus
                                ;;
                esac
                ;;
 esac
 
-echo "$cpu-$vendor-$os"
+echo "$cpu-$vendor-${kernel:+$kernel-}$os"
 exit
 
 # Local variables:
index ccad7f13205a8f82d800e9cc6f86f228f94734f9..390c5961cffea5823653a0a0597f822e2f229f00 100644 (file)
@@ -392,7 +392,7 @@ AS_HELP_STRING([--disable-ipv6],[disable to omit ipv6 support]),
 #include <stdlib.h>
 #include <sys/types.h>
 #include <sys/socket.h>
-main()
+int main()
 {
    if (socket(AF_INET6, SOCK_STREAM, 0) < 0)
      exit(1);
@@ -573,7 +573,7 @@ if test x"$no_lib" != x; then
     echo ""
     echo "See the INSTALL file for hints on how to install the missing libraries and/or"
     echo "how to generate (or fetch) manpages:"
-    echo "    https://github.com/WayneD/rsync/blob/master/INSTALL.md"
+    echo "    https://github.com/RsyncProject/rsync/blob/master/INSTALL.md"
     echo ""
     echo "To disable one or more features, the relevant configure options are:"
     for lib in $no_lib; do
@@ -870,7 +870,7 @@ AC_CHECK_FUNCS(waitpid wait4 getcwd chown chmod lchmod mknod mkfifo \
     fchmod fstat ftruncate strchr readlink link utime utimes lutimes strftime \
     chflags getattrlist mktime innetgr linkat \
     memmove lchown vsnprintf snprintf vasprintf asprintf setsid strpbrk \
-    strlcat strlcpy strtol mallinfo mallinfo2 getgroups setgroups geteuid getegid \
+    strlcat strlcpy stpcpy strtol mallinfo mallinfo2 getgroups setgroups geteuid getegid \
     setlocale setmode open64 lseek64 mkstemp64 mtrace va_copy __va_copy \
     seteuid strerror putenv iconv_open locale_charset nl_langinfo getxattr \
     extattr_get_link sigaction sigprocmask setattrlist getgrouplist \
@@ -1084,6 +1084,8 @@ if test x"$with_included_popt" = x"yes"; then
     AC_MSG_RESULT($srcdir/popt)
     BUILD_POPT='$(popt_OBJS)'
     CFLAGS="-I$srcdir/popt $CFLAGS"
+    AC_DEFINE(POPT_SYSCONFDIR, "/etc", [sysconfig dir for popt])
+    AC_DEFINE(PACKAGE, "rsync", [package name for rsync])
     if test x"$ALLOCA" != x
     then
        # this can be removed when/if we add an included alloca.c;
index 4a29485302cb8cf0ed6f861d7c2dfc787ad792a7..89c1f8d672f4d7bb4b5ccbbbf600cc67bc3f7662 100644 (file)
--- a/delete.c
+++ b/delete.c
@@ -4,7 +4,7 @@
  * Copyright (C) 1996-2000 Andrew Tridgell
  * Copyright (C) 1996 Paul Mackerras
  * Copyright (C) 2002 Martin Pool <mbp@samba.org>
- * Copyright (C) 2003-2020 Wayne Davison
+ * Copyright (C) 2003-2024 Wayne Davison
  *
  * 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
@@ -188,7 +188,7 @@ enum delret delete_item(char *fbuf, uint16 mode, uint16 flags)
                                stats.deleted_symlinks++;
 #endif
                        else if (IS_DEVICE(mode))
-                               stats.deleted_symlinks++;
+                               stats.deleted_devices++;
                        else
                                stats.deleted_specials++;
                }
index ffe55b167edfdbe1325bcfdbe178f8b7b7017504..87edbcf71b65199d4fb45a93e1b8e712484902f7 100644 (file)
--- a/exclude.c
+++ b/exclude.c
@@ -4,7 +4,7 @@
  * Copyright (C) 1996-2001 Andrew Tridgell <tridge@samba.org>
  * Copyright (C) 1996 Paul Mackerras
  * Copyright (C) 2002 Martin Pool
- * Copyright (C) 2003-2022 Wayne Davison
+ * Copyright (C) 2003-2024 Wayne Davison
  *
  * 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
@@ -720,7 +720,8 @@ static BOOL setup_merge_file(int mergelist_num, filter_rule *ex,
        parent_dirscan = True;
        while (*y) {
                char save[MAXPATHLEN];
-               strlcpy(save, y, MAXPATHLEN);
+               /* copylen is strlen(y) which is < MAXPATHLEN. +1 for \0 */
+               size_t copylen = strlcpy(save, y, MAXPATHLEN) + 1;
                *y = '\0';
                dirbuf_len = y - dirbuf;
                strlcpy(x, ex->pattern, MAXPATHLEN - (x - buf));
@@ -734,7 +735,7 @@ static BOOL setup_merge_file(int mergelist_num, filter_rule *ex,
                        lp->head = NULL;
                }
                lp->tail = NULL;
-               strlcpy(y, save, MAXPATHLEN);
+               strlcpy(y, save, copylen);
                while ((*x++ = *y++) != '/') {}
        }
        parent_dirscan = False;
index f80af19e4e5ea8eca91d932ea185d6faa6fb7ef1..69c9a7b494917bbee44fda0e8f1fca9d31ae463b 100644 (file)
--- a/fileio.c
+++ b/fileio.c
@@ -3,7 +3,7 @@
  *
  * Copyright (C) 1998 Andrew Tridgell
  * Copyright (C) 2002 Martin Pool
- * Copyright (C) 2004-2020 Wayne Davison
+ * Copyright (C) 2004-2023 Wayne Davison
  *
  * 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
@@ -40,30 +40,34 @@ OFF_T preallocated_len = 0;
 static OFF_T sparse_seek = 0;
 static OFF_T sparse_past_write = 0;
 
-int sparse_end(int f, OFF_T size)
+int sparse_end(int f, OFF_T size, int updating_basis_or_equiv)
 {
-       int ret;
-
-       sparse_past_write = 0;
-
-       if (!sparse_seek)
-               return 0;
+       int ret = 0;
 
+       if (updating_basis_or_equiv) {
+               if (sparse_seek && do_punch_hole(f, sparse_past_write, sparse_seek) < 0)
+                       ret = -1;
+#ifdef HAVE_FTRUNCATE /* A compilation formality -- in-place requires ftruncate() */
+               else /* Just in case the original file was longer */
+                       ret = do_ftruncate(f, size);
+#endif
+       } else if (sparse_seek) {
 #ifdef HAVE_FTRUNCATE
-       ret = do_ftruncate(f, size);
+               ret = do_ftruncate(f, size);
 #else
-       if (do_lseek(f, sparse_seek-1, SEEK_CUR) != size-1)
-               ret = -1;
-       else {
-               do {
-                       ret = write(f, "", 1);
-               } while (ret < 0 && errno == EINTR);
-
-               ret = ret <= 0 ? -1 : 0;
-       }
+               if (do_lseek(f, sparse_seek-1, SEEK_CUR) != size-1)
+                       ret = -1;
+               else {
+                       do {
+                               ret = write(f, "", 1);
+                       } while (ret < 0 && errno == EINTR);
+
+                       ret = ret <= 0 ? -1 : 0;
+               }
 #endif
+       }
 
-       sparse_seek = 0;
+       sparse_past_write = sparse_seek = 0;
 
        return ret;
 }
diff --git a/flist.c b/flist.c
index 65b459b1712be7c88f5498b77b43a8955e70a817..464d556ec906a572d2c378ac79e6d0fa169dd003 100644 (file)
--- a/flist.c
+++ b/flist.c
@@ -4,7 +4,7 @@
  * Copyright (C) 1996 Andrew Tridgell
  * Copyright (C) 1996 Paul Mackerras
  * Copyright (C) 2001, 2002 Martin Pool <mbp@samba.org>
- * Copyright (C) 2002-2022 Wayne Davison
+ * Copyright (C) 2002-2023 Wayne Davison
  *
  * 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
@@ -2367,7 +2367,7 @@ struct file_list *send_file_list(int f, int argc, char *argv[])
                }
 
                dirlen = dir ? strlen(dir) : 0;
-               if (dirlen != lastdir_len || memcmp(lastdir, dir, dirlen) != 0) {
+               if (dirlen != lastdir_len || (dirlen && memcmp(lastdir, dir, dirlen) != 0)) {
                        if (!change_pathname(NULL, dir, -dirlen))
                                goto bad_path;
                        lastdir = pathname;
@@ -2659,7 +2659,7 @@ struct file_list *recv_file_list(int f, int dir_ndx)
                } else if (S_ISLNK(file->mode))
                        stats.num_symlinks++;
                else if (IS_DEVICE(file->mode))
-                       stats.num_symlinks++;
+                       stats.num_devices++;
                else
                        stats.num_specials++;
 
index 21c4a595a1cbc148516b138a62384bec1d961915..110db28fc76f097426249a454b9cf999aec56c07 100644 (file)
@@ -4,7 +4,7 @@
  * Copyright (C) 1996-2000 Andrew Tridgell
  * Copyright (C) 1996 Paul Mackerras
  * Copyright (C) 2002 Martin Pool <mbp@samba.org>
- * Copyright (C) 2003-2022 Wayne Davison
+ * Copyright (C) 2003-2023 Wayne Davison
  *
  * 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
@@ -783,7 +783,7 @@ static int generate_and_send_sums(int fd, OFF_T len, int f_out, int f_copy)
        for (i = 0; i < sum.count; i++) {
                int32 n1 = (int32)MIN(len, (OFF_T)sum.blength);
                char *map = map_ptr(mapbuf, offset, n1);
-               char sum2[SUM_LENGTH];
+               char sum2[MAX_DIGEST_LEN];
                uint32 sum1;
 
                len -= n1;
index 37e8efbb85f52cd64323b0d183274a52171456a4..f978fb8b25b531aa3cda8ffae1221f88265f7185 100644 (file)
@@ -1 +1 @@
-#define LATEST_YEAR "2022"
+#define LATEST_YEAR "2024"
diff --git a/match.c b/match.c
index 6243994caa52799cd49d19bf0b5b6a305e7f04d3..cdb30a15e82fe6fc0671d7e7b58eeca97137770f 100644 (file)
--- a/match.c
+++ b/match.c
@@ -3,7 +3,7 @@
  *
  * Copyright (C) 1996 Andrew Tridgell
  * Copyright (C) 1996 Paul Mackerras
- * Copyright (C) 2003-2022 Wayne Davison
+ * Copyright (C) 2003-2023 Wayne Davison
  *
  * 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
@@ -142,7 +142,7 @@ static void hash_search(int f,struct sum_struct *s,
 {
        OFF_T offset, aligned_offset, end;
        int32 k, want_i, aligned_i, backup;
-       char sum2[SUM_LENGTH];
+       char sum2[MAX_DIGEST_LEN];
        uint32 s1, s2, sum;
        int more;
        schar *map;
index 0dc173059bb31008e6670ce06cce7602e81e9740..c7af73934a775ed0f983f988697a16c81e9cfea6 100755 (executable)
@@ -8,6 +8,7 @@ fi
 inname="$1"
 srcdir=`dirname "$0"`
 flagfile="$srcdir/.md2man-works"
+force_flagfile="$srcdir/.md2man-force"
 
 if [ ! -f "$flagfile" ]; then
     # We test our smallest manpage just to see if the python setup works.
@@ -32,4 +33,10 @@ if [ ! -f "$flagfile" ]; then
     fi
 fi
 
-"$srcdir/md-convert" "$srcdir/$inname"
+if [ -f "$force_flagfile" ]; then
+    opt='--force-link-text'
+else
+    opt=''
+fi
+
+"$srcdir/md-convert" $opt "$srcdir/$inname"
index a48689a7871e9e8064e8ac0993a90cf2fc7525a4..5fd63a76d494eec72dca9f79a0bebc70a8fcf7b0 100755 (executable)
@@ -276,7 +276,10 @@ class TransformHtml(HTMLParser):
                 bad_hashtags = set(),
                 latest_targets = [ ],
                 opt_prefix = 'opt',
+                a_href = None,
+                a_href_external = False,
                 a_txt_start = None,
+                after_a_tag = False,
                 target_suf = '',
                 )
 
@@ -315,6 +318,13 @@ class TransformHtml(HTMLParser):
         for bad in st.referenced_hashtags - st.created_hashtags:
             warn('Unknown hashtag link in', self.fn + ':', '#' + bad)
 
+    def handle_UE(self):
+        st = self.state
+        if st.txt.startswith(('.', ',', '!', '?', ';', ':')):
+            st.man_out[-1] = ".UE " + st.txt[0] + "\n"
+            st.txt = st.txt[1:]
+        st.after_a_tag = False
+
     def handle_starttag(self, tag, attrs_list):
         st = self.state
         if args.debug:
@@ -387,13 +397,20 @@ class TransformHtml(HTMLParser):
             for var, val in attrs_list:
                 if var == 'href':
                     if val.startswith(('https://', 'http://', 'mailto:', 'ftp:')):
-                        pass # nothing to check
+                        if st.after_a_tag:
+                            self.handle_UE()
+                        st.man_out.append(manify(st.txt.strip()) + "\n")
+                        st.man_out.append(".UR " + val + "\n")
+                        st.txt = ''
+                        st.a_href = val
+                        st.a_href_external = True
                     elif '#' in val:
                         pg, tgt = val.split('#', 1)
                         if pg and pg not in VALID_PAGES or '#' in tgt:
                             st.bad_hashtags.add(val)
                         elif tgt in ('', 'opt', 'dopt'):
                             st.a_href = val
+                            st.a_href_external = False
                         elif pg == '':
                             st.referenced_hashtags.add(tgt)
                             if tgt in st.latest_targets:
@@ -409,6 +426,8 @@ class TransformHtml(HTMLParser):
         st = self.state
         if args.debug:
             self.output_debug('END', (tag,))
+        if st.after_a_tag:
+            self.handle_UE()
         if tag in CONSUMES_TXT or st.dt_from == tag:
             txt = st.txt.strip()
             st.txt = ''
@@ -473,7 +492,15 @@ class TransformHtml(HTMLParser):
         elif tag == 'hr':
             return
         elif tag == 'a':
-            if st.a_href:
+            if st.a_href_external:
+                st.txt = st.txt.strip()
+                if args.force_link_text or st.a_href != st.txt:
+                    st.man_out.append(manify(st.txt) + "\n")
+                st.man_out.append(".UE\n") # This might get replaced with a punctuation version in handle_UE()
+                st.after_a_tag = True
+                st.a_href_external = False
+                st.txt = ''
+            elif st.a_href:
                 atxt = st.txt[st.a_txt_start:]
                 find = 'href="' + st.a_href + '"'
                 for j in range(len(st.html_out)-1, 0, -1):
@@ -612,6 +639,7 @@ if __name__ == '__main__':
     parser = argparse.ArgumentParser(description="Convert markdown into html and (optionally) nroff. Each input filename must have a .md suffix, which is changed to .html for the output filename. If the input filename ends with .num.md (e.g. foo.1.md) then a nroff file is also output with the input filename's .md suffix removed (e.g. foo.1).", add_help=False)
     parser.add_argument('--test', action='store_true', help="Just test the parsing without outputting any files.")
     parser.add_argument('--dest', metavar='DIR', help="Create files in DIR instead of the current directory.")
+    parser.add_argument('--force-link-text', action='store_true', help="Don't remove the link text if it matches the link href. Useful when nroff doesn't understand .UR and .UE.")
     parser.add_argument('--debug', '-D', action='count', default=0, help='Output copious info on the html parsing. Repeat for even more.')
     parser.add_argument("--help", "-h", action="help", help="Output this help message and exit.")
     parser.add_argument("mdfiles", metavar='FILE.md', nargs='+', help="One or more .md files to convert.")
index ded0e7a301ef69782d5b17556ad289e980ac4b56..fd674754cd5e4992b05050d69c092cf207979c91 100644 (file)
--- a/options.c
+++ b/options.c
@@ -3,7 +3,7 @@
  *
  * Copyright (C) 1998-2001 Andrew Tridgell <tridge@samba.org>
  * Copyright (C) 2000, 2001, 2002 Martin Pool <mbp@samba.org>
- * Copyright (C) 2002-2022 Wayne Davison
+ * Copyright (C) 2002-2023 Wayne Davison
  *
  * 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
@@ -1946,6 +1946,8 @@ int parse_arguments(int *argc_p, const char ***argv_p)
                        goto cleanup;
                max_alloc = size;
        }
+       if (!max_alloc)
+               max_alloc = SIZE_MAX;
 
        if (old_style_args < 0) {
                if (!am_server && protect_args <= 0 && (arg = getenv("RSYNC_OLD_ARGS")) != NULL && *arg) {
@@ -2340,7 +2342,7 @@ int parse_arguments(int *argc_p, const char ***argv_p)
        if (do_progress && !am_server) {
                if (!log_before_transfer && INFO_EQ(NAME, 0))
                        parse_output_words(info_words, info_levels, "name", DEFAULT_PRIORITY);
-               parse_output_words(info_words, info_levels, "flist2,progress", DEFAULT_PRIORITY);
+               parse_output_words(info_words, info_levels, "FLIST2,PROGRESS", DEFAULT_PRIORITY);
        }
 
        if (dry_run)
@@ -2518,7 +2520,7 @@ static char SPLIT_ARG_WHEN_OLD[1];
  **/
 char *safe_arg(const char *opt, const char *arg)
 {
-#define SHELL_CHARS "!#$&;|<>(){}\"' \t\\"
+#define SHELL_CHARS "!#$&;|<>(){}\"'` \t\\"
 #define WILD_CHARS  "*?[]" /* We don't allow remote brace expansion */
        BOOL is_filename_arg = !opt;
        char *escapes = is_filename_arg ? SHELL_CHARS : WILD_CHARS SHELL_CHARS;
index 7f2e2585c674d3ebb8f78c7a9fdfa7a0dae6610f..032913d571e91b0a17dff743d5015974b675bee5 100644 (file)
@@ -1,4 +1,4 @@
-TARGETS := all install install-ssl-daemon install-all install-strip conf gen gensend reconfigure restatus \
+TARGETS := all install install-ssl-daemon install-all install-strip conf gen reconfigure restatus \
        proto man clean cleantests distclean test check check29 check30 installcheck splint \
        doxygen doxygen-upload finddead rrsync
 
index f2d7aa44b696a44b363b426b08bcd54d192c9da4..10385a396937fd41dd2c7bdccf26957480c578db 100644 (file)
@@ -1,6 +1,6 @@
 Summary: A fast, versatile, remote (and local) file-copying tool
 Name: rsync
-Version: 3.2.7
+Version: 3.3.0
 %define fullversion %{version}
 Release: 1
 %define srcdir src
@@ -79,8 +79,8 @@ rm -rf $RPM_BUILD_ROOT
 %dir /etc/rsync-ssl/certs
 
 %changelog
-* Thu Oct 20 2022 Wayne Davison <wayne@opencoder.net>
-Released 3.2.7.
+* Sat Apr 06 2024 Wayne Davison <wayne@opencoder.net>
+Released 3.3.0.
 
 * Fri Mar 21 2008 Wayne Davison <wayne@opencoder.net>
 Added installation of /etc/xinetd.d/rsync file and some commented-out
index c4c5741df1d690115bc342e3e0088075b2ffb7bc..c2b2930748b75ecbfa77bc29fb00cb3c9f81f03c 100644 (file)
@@ -170,17 +170,6 @@ def get_patch_branches(base_branch):
     return branches
 
 
-def mandate_gensend_hook():
-    hook = '.git/hooks/pre-push'
-    if not os.path.exists(hook):
-        print('Creating hook file:', hook)
-        cmd_chk(['./rsync', '-a', 'packaging/pre-push', hook])
-    else:
-        ct = cmd_txt(['grep', 'make gensend', hook], discard='output')
-        if ct.rc:
-            die('Please add a "make gensend" into your', hook, 'script.')
-
-
 # Snag the GENFILES values out of the Makefile file and return them as a list.
 def get_gen_files(want_dir_plus_list=False):
     cont_re = re.compile(r'\\\n')
diff --git a/packaging/pre-push b/packaging/pre-push
deleted file mode 100755 (executable)
index 8a71369..0000000
+++ /dev/null
@@ -1,16 +0,0 @@
-#!/bin/bash -e
-
-cat >/dev/null # Just discard stdin data
-
-if [[ -f /proc/$PPID/cmdline ]]; then
-    while read -d $'\0' arg ; do
-       if [[ "$arg" == '--tags' ]] ; then
-           exit 0
-       fi
-    done </proc/$PPID/cmdline
-fi
-
-branch=`git rev-parse --abbrev-ref HEAD`
-if [[ "$branch" = master && "$*" == *github* ]]; then
-    make gensend
-fi
index 511e90f1ed3fc0ce98057c44986a50f1cc28e666..03d9f6a3ec4ecdf510ded45eac4179a3ecae30dc 100755 (executable)
@@ -27,8 +27,6 @@ def main():
     ztoday = now.strftime('%d %b %Y')
     today = ztoday.lstrip('0')
 
-    mandate_gensend_hook()
-
     curdir = os.getcwd()
 
     signal.signal(signal.SIGINT, signal_handler)
diff --git a/popt/lookup3.c b/popt/lookup3.c
new file mode 100644 (file)
index 0000000..e974cad
--- /dev/null
@@ -0,0 +1,959 @@
+/* -------------------------------------------------------------------- */
+/*
+ * lookup3.c, by Bob Jenkins, May 2006, Public Domain.
+ * 
+ * These are functions for producing 32-bit hashes for hash table lookup.
+ * jlu32w(), jlu32l(), jlu32lpair(), jlu32b(), _JLU3_MIX(), and _JLU3_FINAL() 
+ * are externally useful functions.  Routines to test the hash are included 
+ * if SELF_TEST is defined.  You can use this free for any purpose.  It's in
+ * the public domain.  It has no warranty.
+ * 
+ * You probably want to use jlu32l().  jlu32l() and jlu32b()
+ * hash byte arrays.  jlu32l() is is faster than jlu32b() on
+ * little-endian machines.  Intel and AMD are little-endian machines.
+ * On second thought, you probably want jlu32lpair(), which is identical to
+ * jlu32l() except it returns two 32-bit hashes for the price of one.  
+ * You could implement jlu32bpair() if you wanted but I haven't bothered here.
+ * 
+ * If you want to find a hash of, say, exactly 7 integers, do
+ *   a = i1;  b = i2;  c = i3;
+ *   _JLU3_MIX(a,b,c);
+ *   a += i4; b += i5; c += i6;
+ *   _JLU3_MIX(a,b,c);
+ *   a += i7;
+ *   _JLU3_FINAL(a,b,c);
+ * then use c as the hash value.  If you have a variable size array of
+ * 4-byte integers to hash, use jlu32w().  If you have a byte array (like
+ * a character string), use jlu32l().  If you have several byte arrays, or
+ * a mix of things, see the comments above jlu32l().  
+ * 
+ * Why is this so big?  I read 12 bytes at a time into 3 4-byte integers, 
+ * then mix those integers.  This is fast (you can do a lot more thorough
+ * mixing with 12*3 instructions on 3 integers than you can with 3 instructions
+ * on 1 byte), but shoehorning those bytes into integers efficiently is messy.
+*/
+/* -------------------------------------------------------------------- */
+
+#include <stdint.h>
+
+#if defined(_JLU3_SELFTEST)
+# define _JLU3_jlu32w          1
+# define _JLU3_jlu32l          1
+# define _JLU3_jlu32lpair      1
+# define _JLU3_jlu32b          1
+#endif
+
+static const union _dbswap {
+    const uint32_t ui;
+    const unsigned char uc[4];
+} endian = { .ui = 0x11223344 };
+# define HASH_LITTLE_ENDIAN    (endian.uc[0] == (unsigned char) 0x44)
+# define HASH_BIG_ENDIAN       (endian.uc[0] == (unsigned char) 0x11)
+
+#ifndef ROTL32
+# define ROTL32(x, s) (((x) << (s)) | ((x) >> (32 - (s))))
+#endif
+
+/* NOTE: The _size parameter should be in bytes. */
+#define        _JLU3_INIT(_h, _size)   (0xdeadbeef + ((uint32_t)(_size)) + (_h))
+
+/* -------------------------------------------------------------------- */
+/*
+ * _JLU3_MIX -- mix 3 32-bit values reversibly.
+ * 
+ * This is reversible, so any information in (a,b,c) before _JLU3_MIX() is
+ * still in (a,b,c) after _JLU3_MIX().
+ * 
+ * If four pairs of (a,b,c) inputs are run through _JLU3_MIX(), or through
+ * _JLU3_MIX() in reverse, there are at least 32 bits of the output that
+ * are sometimes the same for one pair and different for another pair.
+ * This was tested for:
+ * * pairs that differed by one bit, by two bits, in any combination
+ *   of top bits of (a,b,c), or in any combination of bottom bits of
+ *   (a,b,c).
+ * * "differ" is defined as +, -, ^, or ~^.  For + and -, I transformed
+ *   the output delta to a Gray code (a^(a>>1)) so a string of 1's (as
+ *   is commonly produced by subtraction) look like a single 1-bit
+ *   difference.
+ * * the base values were pseudorandom, all zero but one bit set, or 
+ *   all zero plus a counter that starts at zero.
+ * 
+ * Some k values for my "a-=c; a^=ROTL32(c,k); c+=b;" arrangement that
+ * satisfy this are
+ *     4  6  8 16 19  4
+ *     9 15  3 18 27 15
+ *    14  9  3  7 17  3
+ * Well, "9 15 3 18 27 15" didn't quite get 32 bits diffing
+ * for "differ" defined as + with a one-bit base and a two-bit delta.  I
+ * used http://burtleburtle.net/bob/hash/avalanche.html to choose 
+ * the operations, constants, and arrangements of the variables.
+ * 
+ * This does not achieve avalanche.  There are input bits of (a,b,c)
+ * that fail to affect some output bits of (a,b,c), especially of a.  The
+ * most thoroughly mixed value is c, but it doesn't really even achieve
+ * avalanche in c.
+ * 
+ * This allows some parallelism.  Read-after-writes are good at doubling
+ * the number of bits affected, so the goal of mixing pulls in the opposite
+ * direction as the goal of parallelism.  I did what I could.  Rotates
+ * seem to cost as much as shifts on every machine I could lay my hands
+ * on, and rotates are much kinder to the top and bottom bits, so I used
+ * rotates.
+ */
+/* -------------------------------------------------------------------- */
+#define _JLU3_MIX(a,b,c) \
+{ \
+  a -= c;  a ^= ROTL32(c, 4);  c += b; \
+  b -= a;  b ^= ROTL32(a, 6);  a += c; \
+  c -= b;  c ^= ROTL32(b, 8);  b += a; \
+  a -= c;  a ^= ROTL32(c,16);  c += b; \
+  b -= a;  b ^= ROTL32(a,19);  a += c; \
+  c -= b;  c ^= ROTL32(b, 4);  b += a; \
+}
+
+/* -------------------------------------------------------------------- */
+/**
+ * _JLU3_FINAL -- final mixing of 3 32-bit values (a,b,c) into c
+ * 
+ * Pairs of (a,b,c) values differing in only a few bits will usually
+ * produce values of c that look totally different.  This was tested for
+ * * pairs that differed by one bit, by two bits, in any combination
+ *   of top bits of (a,b,c), or in any combination of bottom bits of
+ *   (a,b,c).
+ * * "differ" is defined as +, -, ^, or ~^.  For + and -, I transformed
+ *   the output delta to a Gray code (a^(a>>1)) so a string of 1's (as
+ *   is commonly produced by subtraction) look like a single 1-bit
+ *   difference.
+ * * the base values were pseudorandom, all zero but one bit set, or 
+ *   all zero plus a counter that starts at zero.
+ * 
+ * These constants passed:
+ *  14 11 25 16 4 14 24
+ *  12 14 25 16 4 14 24
+ * and these came close:
+ *   4  8 15 26 3 22 24
+ *  10  8 15 26 3 22 24
+ *  11  8 15 26 3 22 24
+ */
+/* -------------------------------------------------------------------- */
+#define _JLU3_FINAL(a,b,c) \
+{ \
+  c ^= b; c -= ROTL32(b,14); \
+  a ^= c; a -= ROTL32(c,11); \
+  b ^= a; b -= ROTL32(a,25); \
+  c ^= b; c -= ROTL32(b,16); \
+  a ^= c; a -= ROTL32(c,4);  \
+  b ^= a; b -= ROTL32(a,14); \
+  c ^= b; c -= ROTL32(b,24); \
+}
+
+#if defined(_JLU3_jlu32w)
+uint32_t jlu32w(uint32_t h, const uint32_t *k, size_t size);
+/* -------------------------------------------------------------------- */
+/**
+ *  This works on all machines.  To be useful, it requires
+ *  -- that the key be an array of uint32_t's, and
+ *  -- that the size be the number of uint32_t's in the key
+ * 
+ *  The function jlu32w() is identical to jlu32l() on little-endian
+ *  machines, and identical to jlu32b() on big-endian machines,
+ *  except that the size has to be measured in uint32_ts rather than in
+ *  bytes.  jlu32l() is more complicated than jlu32w() only because
+ *  jlu32l() has to dance around fitting the key bytes into registers.
+ *
+ * @param h            the previous hash, or an arbitrary value
+ * @param *k           the key, an array of uint32_t values
+ * @param size         the size of the key, in uint32_ts
+ * @return             the lookup3 hash
+ */
+/* -------------------------------------------------------------------- */
+uint32_t jlu32w(uint32_t h, const uint32_t *k, size_t size)
+{
+    uint32_t a = _JLU3_INIT(h, (size * sizeof(*k)));
+    uint32_t b = a;
+    uint32_t c = a;
+
+    if (k == NULL)
+       goto exit;
+
+    /*----------------------------------------------- handle most of the key */
+    while (size > 3) {
+       a += k[0];
+       b += k[1];
+       c += k[2];
+       _JLU3_MIX(a,b,c);
+       size -= 3;
+       k += 3;
+    }
+
+    /*----------------------------------------- handle the last 3 uint32_t's */
+    switch (size) {
+    case 3 : c+=k[2];
+    case 2 : b+=k[1];
+    case 1 : a+=k[0];
+       _JLU3_FINAL(a,b,c);
+       /* fallthrough */
+    case 0:
+       break;
+    }
+    /*---------------------------------------------------- report the result */
+exit:
+    return c;
+}
+#endif /* defined(_JLU3_jlu32w) */
+
+#if defined(_JLU3_jlu32l)
+uint32_t jlu32l(uint32_t h, const void *key, size_t size);
+/* -------------------------------------------------------------------- */
+/*
+ * jlu32l() -- hash a variable-length key into a 32-bit value
+ *   h       : can be any 4-byte value
+ *   k       : the key (the unaligned variable-length array of bytes)
+ *   size    : the size of the key, counting by bytes
+ * Returns a 32-bit value.  Every bit of the key affects every bit of
+ * the return value.  Two keys differing by one or two bits will have
+ * totally different hash values.
+ * 
+ * The best hash table sizes are powers of 2.  There is no need to do
+ * mod a prime (mod is sooo slow!).  If you need less than 32 bits,
+ * use a bitmask.  For example, if you need only 10 bits, do
+ *   h = (h & hashmask(10));
+ * In which case, the hash table should have hashsize(10) elements.
+ * 
+ * If you are hashing n strings (uint8_t **)k, do it like this:
+ *   for (i=0, h=0; i<n; ++i) h = jlu32l(h, k[i], len[i]);
+ * 
+ * By Bob Jenkins, 2006.  bob_jenkins@burtleburtle.net.  You may use this
+ * code any way you wish, private, educational, or commercial.  It's free.
+ * 
+ * Use for hash table lookup, or anything where one collision in 2^^32 is
+ * acceptable.  Do NOT use for cryptographic purposes.
+ *
+ * @param h            the previous hash, or an arbitrary value
+ * @param *k           the key, an array of uint8_t values
+ * @param size         the size of the key
+ * @return             the lookup3 hash
+ */
+/* -------------------------------------------------------------------- */
+uint32_t jlu32l(uint32_t h, const void *key, size_t size)
+{
+    union { const void *ptr; size_t i; } u;
+    uint32_t a = _JLU3_INIT(h, size);
+    uint32_t b = a;
+    uint32_t c = a;
+
+    if (key == NULL)
+       goto exit;
+
+    u.ptr = key;
+    if (HASH_LITTLE_ENDIAN && ((u.i & 0x3) == 0)) {
+       const uint32_t *k = (const uint32_t *)key;      /* read 32-bit chunks */
+#ifdef VALGRIND
+       const uint8_t  *k8;
+#endif
+
+    /*------ all but last block: aligned reads and affect 32 bits of (a,b,c) */
+       while (size > 12) {
+           a += k[0];
+           b += k[1];
+           c += k[2];
+           _JLU3_MIX(a,b,c);
+           size -= 12;
+           k += 3;
+       }
+
+       /*------------------------- handle the last (probably partial) block */
+       /* 
+        * "k[2]&0xffffff" actually reads beyond the end of the string, but
+        * then masks off the part it's not allowed to read.  Because the
+        * string is aligned, the masked-off tail is in the same word as the
+        * rest of the string.  Every machine with memory protection I've seen
+        * does it on word boundaries, so is OK with this.  But VALGRIND will
+        * still catch it and complain.  The masking trick does make the hash
+        * noticeably faster for short strings (like English words).
+        */
+#ifndef VALGRIND
+
+       switch (size) {
+       case 12:        c += k[2]; b+=k[1]; a+=k[0]; break;
+       case 11:        c += k[2]&0xffffff; b+=k[1]; a+=k[0]; break;
+       case 10:        c += k[2]&0xffff; b+=k[1]; a+=k[0]; break;
+       case  9:        c += k[2]&0xff; b+=k[1]; a+=k[0]; break;
+       case  8:        b += k[1]; a+=k[0]; break;
+       case  7:        b += k[1]&0xffffff; a+=k[0]; break;
+       case  6:        b += k[1]&0xffff; a+=k[0]; break;
+       case  5:        b += k[1]&0xff; a+=k[0]; break;
+       case  4:        a += k[0]; break;
+       case  3:        a += k[0]&0xffffff; break;
+       case  2:        a += k[0]&0xffff; break;
+       case  1:        a += k[0]&0xff; break;
+       case  0:        goto exit;
+       }
+
+#else /* make valgrind happy */
+
+       k8 = (const uint8_t *)k;
+       switch (size) {
+       case 12:        c += k[2]; b+=k[1]; a+=k[0]     break;
+       case 11:        c += ((uint32_t)k8[10])<<16;    /* fallthrough */
+       case 10:        c += ((uint32_t)k8[9])<<8;      /* fallthrough */
+       case  9:        c += k8[8];                     /* fallthrough */
+       case  8:        b += k[1]; a+=k[0];             break;
+       case  7:        b += ((uint32_t)k8[6])<<16;     /* fallthrough */
+       case  6:        b += ((uint32_t)k8[5])<<8;      /* fallthrough */
+       case  5:        b += k8[4];                     /* fallthrough */
+       case  4:        a += k[0];                      break;
+       case  3:        a += ((uint32_t)k8[2])<<16;     /* fallthrough */
+       case  2:        a += ((uint32_t)k8[1])<<8;      /* fallthrough */
+       case  1:        a += k8[0];                     break;
+       case  0:        goto exit;
+       }
+
+#endif /* !valgrind */
+
+    } else if (HASH_LITTLE_ENDIAN && ((u.i & 0x1) == 0)) {
+       const uint16_t *k = (const uint16_t *)key;      /* read 16-bit chunks */
+       const uint8_t  *k8;
+
+       /*----------- all but last block: aligned reads and different mixing */
+       while (size > 12) {
+           a += k[0] + (((uint32_t)k[1])<<16);
+           b += k[2] + (((uint32_t)k[3])<<16);
+           c += k[4] + (((uint32_t)k[5])<<16);
+           _JLU3_MIX(a,b,c);
+           size -= 12;
+           k += 6;
+       }
+
+       /*------------------------- handle the last (probably partial) block */
+       k8 = (const uint8_t *)k;
+       switch (size) {
+       case 12:
+           c += k[4]+(((uint32_t)k[5])<<16);
+           b += k[2]+(((uint32_t)k[3])<<16);
+           a += k[0]+(((uint32_t)k[1])<<16);
+           break;
+       case 11:
+           c += ((uint32_t)k8[10])<<16;
+           /* fallthrough */
+       case 10:
+           c += (uint32_t)k[4];
+           b += k[2]+(((uint32_t)k[3])<<16);
+           a += k[0]+(((uint32_t)k[1])<<16);
+           break;
+       case  9:
+           c += (uint32_t)k8[8];
+           /* fallthrough */
+       case  8:
+           b += k[2]+(((uint32_t)k[3])<<16);
+           a += k[0]+(((uint32_t)k[1])<<16);
+           break;
+       case  7:
+           b += ((uint32_t)k8[6])<<16;
+           /* fallthrough */
+       case  6:
+           b += (uint32_t)k[2];
+           a += k[0]+(((uint32_t)k[1])<<16);
+           break;
+       case  5:
+           b += (uint32_t)k8[4];
+           /* fallthrough */
+       case  4:
+           a += k[0]+(((uint32_t)k[1])<<16);
+           break;
+       case  3:
+           a += ((uint32_t)k8[2])<<16;
+           /* fallthrough */
+       case  2:
+           a += (uint32_t)k[0];
+           break;
+       case  1:
+           a += (uint32_t)k8[0];
+           break;
+       case  0:
+           goto exit;
+       }
+
+    } else {           /* need to read the key one byte at a time */
+       const uint8_t *k = (const uint8_t *)key;
+
+       /*----------- all but the last block: affect some 32 bits of (a,b,c) */
+       while (size > 12) {
+           a += (uint32_t)k[0];
+           a += ((uint32_t)k[1])<<8;
+           a += ((uint32_t)k[2])<<16;
+           a += ((uint32_t)k[3])<<24;
+           b += (uint32_t)k[4];
+           b += ((uint32_t)k[5])<<8;
+           b += ((uint32_t)k[6])<<16;
+           b += ((uint32_t)k[7])<<24;
+           c += (uint32_t)k[8];
+           c += ((uint32_t)k[9])<<8;
+           c += ((uint32_t)k[10])<<16;
+           c += ((uint32_t)k[11])<<24;
+           _JLU3_MIX(a,b,c);
+           size -= 12;
+           k += 12;
+       }
+
+       /*---------------------------- last block: affect all 32 bits of (c) */
+       switch (size) {
+       case 12:        c += ((uint32_t)k[11])<<24;     /* fallthrough */
+       case 11:        c += ((uint32_t)k[10])<<16;     /* fallthrough */
+       case 10:        c += ((uint32_t)k[9])<<8;       /* fallthrough */
+       case  9:        c += (uint32_t)k[8];            /* fallthrough */
+       case  8:        b += ((uint32_t)k[7])<<24;      /* fallthrough */
+       case  7:        b += ((uint32_t)k[6])<<16;      /* fallthrough */
+       case  6:        b += ((uint32_t)k[5])<<8;       /* fallthrough */
+       case  5:        b += (uint32_t)k[4];            /* fallthrough */
+       case  4:        a += ((uint32_t)k[3])<<24;      /* fallthrough */
+       case  3:        a += ((uint32_t)k[2])<<16;      /* fallthrough */
+       case  2:        a += ((uint32_t)k[1])<<8;       /* fallthrough */
+       case  1:        a += (uint32_t)k[0];
+           break;
+       case  0:
+           goto exit;
+       }
+    }
+
+    _JLU3_FINAL(a,b,c);
+
+exit:
+    return c;
+}
+#endif /* defined(_JLU3_jlu32l) */
+
+#if defined(_JLU3_jlu32lpair)
+/**
+ * jlu32lpair: return 2 32-bit hash values.
+ *
+ * This is identical to jlu32l(), except it returns two 32-bit hash
+ * values instead of just one.  This is good enough for hash table
+ * lookup with 2^^64 buckets, or if you want a second hash if you're not
+ * happy with the first, or if you want a probably-unique 64-bit ID for
+ * the key.  *pc is better mixed than *pb, so use *pc first.  If you want
+ * a 64-bit value do something like "*pc + (((uint64_t)*pb)<<32)".
+ *
+ * @param h            the previous hash, or an arbitrary value
+ * @param *key         the key, an array of uint8_t values
+ * @param size         the size of the key in bytes
+ * @retval *pc,                IN: primary initval, OUT: primary hash
+ * *retval *pb         IN: secondary initval, OUT: secondary hash
+ */
+void jlu32lpair(const void *key, size_t size, uint32_t *pc, uint32_t *pb)
+{
+    union { const void *ptr; size_t i; } u;
+    uint32_t a = _JLU3_INIT(*pc, size);
+    uint32_t b = a;
+    uint32_t c = a;
+
+    if (key == NULL)
+       goto exit;
+
+    c += *pb;  /* Add the secondary hash. */
+
+    u.ptr = key;
+    if (HASH_LITTLE_ENDIAN && ((u.i & 0x3) == 0)) {
+       const uint32_t *k = (const uint32_t *)key;      /* read 32-bit chunks */
+#ifdef VALGRIND
+       const uint8_t  *k8;
+#endif
+
+       /*-- all but last block: aligned reads and affect 32 bits of (a,b,c) */
+       while (size > (size_t)12) {
+           a += k[0];
+           b += k[1];
+           c += k[2];
+           _JLU3_MIX(a,b,c);
+           size -= 12;
+           k += 3;
+       }
+       /*------------------------- handle the last (probably partial) block */
+       /* 
+        * "k[2]&0xffffff" actually reads beyond the end of the string, but
+        * then masks off the part it's not allowed to read.  Because the
+        * string is aligned, the masked-off tail is in the same word as the
+        * rest of the string.  Every machine with memory protection I've seen
+        * does it on word boundaries, so is OK with this.  But VALGRIND will
+        * still catch it and complain.  The masking trick does make the hash
+        * noticeably faster for short strings (like English words).
+        */
+#ifndef VALGRIND
+
+       switch (size) {
+       case 12:        c += k[2]; b+=k[1]; a+=k[0]; break;
+       case 11:        c += k[2]&0xffffff; b+=k[1]; a+=k[0]; break;
+       case 10:        c += k[2]&0xffff; b+=k[1]; a+=k[0]; break;
+       case  9:        c += k[2]&0xff; b+=k[1]; a+=k[0]; break;
+       case  8:        b += k[1]; a+=k[0]; break;
+       case  7:        b += k[1]&0xffffff; a+=k[0]; break;
+       case  6:        b += k[1]&0xffff; a+=k[0]; break;
+       case  5:        b += k[1]&0xff; a+=k[0]; break;
+       case  4:        a += k[0]; break;
+       case  3:        a += k[0]&0xffffff; break;
+       case  2:        a += k[0]&0xffff; break;
+       case  1:        a += k[0]&0xff; break;
+       case  0:        goto exit;
+       }
+
+#else /* make valgrind happy */
+
+       k8 = (const uint8_t *)k;
+       switch (size) {
+       case 12:        c += k[2]; b+=k[1]; a+=k[0];    break;
+       case 11:        c += ((uint32_t)k8[10])<<16;    /* fallthrough */
+       case 10:        c += ((uint32_t)k8[9])<<8;      /* fallthrough */
+       case  9:        c += k8[8];                     /* fallthrough */
+       case  8:        b += k[1]; a+=k[0];             break;
+       case  7:        b += ((uint32_t)k8[6])<<16;     /* fallthrough */
+       case  6:        b += ((uint32_t)k8[5])<<8;      /* fallthrough */
+       case  5:        b += k8[4];                     /* fallthrough */
+       case  4:        a += k[0];                      break;
+       case  3:        a += ((uint32_t)k8[2])<<16;     /* fallthrough */
+       case  2:        a += ((uint32_t)k8[1])<<8;      /* fallthrough */
+       case  1:        a += k8[0];                     break;
+       case  0:        goto exit;
+       }
+
+#endif /* !valgrind */
+
+    } else if (HASH_LITTLE_ENDIAN && ((u.i & 0x1) == 0)) {
+       const uint16_t *k = (const uint16_t *)key;      /* read 16-bit chunks */
+       const uint8_t  *k8;
+
+       /*----------- all but last block: aligned reads and different mixing */
+       while (size > (size_t)12) {
+           a += k[0] + (((uint32_t)k[1])<<16);
+           b += k[2] + (((uint32_t)k[3])<<16);
+           c += k[4] + (((uint32_t)k[5])<<16);
+           _JLU3_MIX(a,b,c);
+           size -= 12;
+           k += 6;
+       }
+
+       /*------------------------- handle the last (probably partial) block */
+       k8 = (const uint8_t *)k;
+       switch (size) {
+       case 12:
+           c += k[4]+(((uint32_t)k[5])<<16);
+           b += k[2]+(((uint32_t)k[3])<<16);
+           a += k[0]+(((uint32_t)k[1])<<16);
+           break;
+       case 11:
+           c += ((uint32_t)k8[10])<<16;
+           /* fallthrough */
+       case 10:
+           c += k[4];
+           b += k[2]+(((uint32_t)k[3])<<16);
+           a += k[0]+(((uint32_t)k[1])<<16);
+           break;
+       case  9:
+           c += k8[8];
+           /* fallthrough */
+       case  8:
+           b += k[2]+(((uint32_t)k[3])<<16);
+           a += k[0]+(((uint32_t)k[1])<<16);
+           break;
+       case  7:
+           b += ((uint32_t)k8[6])<<16;
+           /* fallthrough */
+       case  6:
+           b += k[2];
+           a += k[0]+(((uint32_t)k[1])<<16);
+           break;
+       case  5:
+           b += k8[4];
+           /* fallthrough */
+       case  4:
+           a += k[0]+(((uint32_t)k[1])<<16);
+           break;
+       case  3:
+           a += ((uint32_t)k8[2])<<16;
+           /* fallthrough */
+       case  2:
+           a += k[0];
+           break;
+       case  1:
+           a += k8[0];
+           break;
+       case  0:
+           goto exit;
+       }
+
+    } else {           /* need to read the key one byte at a time */
+       const uint8_t *k = (const uint8_t *)key;
+
+       /*----------- all but the last block: affect some 32 bits of (a,b,c) */
+       while (size > (size_t)12) {
+           a += k[0];
+           a += ((uint32_t)k[1])<<8;
+           a += ((uint32_t)k[2])<<16;
+           a += ((uint32_t)k[3])<<24;
+           b += k[4];
+           b += ((uint32_t)k[5])<<8;
+           b += ((uint32_t)k[6])<<16;
+           b += ((uint32_t)k[7])<<24;
+           c += k[8];
+           c += ((uint32_t)k[9])<<8;
+           c += ((uint32_t)k[10])<<16;
+           c += ((uint32_t)k[11])<<24;
+           _JLU3_MIX(a,b,c);
+           size -= 12;
+           k += 12;
+       }
+
+       /*---------------------------- last block: affect all 32 bits of (c) */
+       switch (size) {
+       case 12:        c += ((uint32_t)k[11])<<24;     /* fallthrough */
+       case 11:        c += ((uint32_t)k[10])<<16;     /* fallthrough */
+       case 10:        c += ((uint32_t)k[9])<<8;       /* fallthrough */
+       case  9:        c += k[8];                      /* fallthrough */
+       case  8:        b += ((uint32_t)k[7])<<24;      /* fallthrough */
+       case  7:        b += ((uint32_t)k[6])<<16;      /* fallthrough */
+       case  6:        b += ((uint32_t)k[5])<<8;       /* fallthrough */
+       case  5:        b += k[4];                      /* fallthrough */
+       case  4:        a += ((uint32_t)k[3])<<24;      /* fallthrough */
+       case  3:        a += ((uint32_t)k[2])<<16;      /* fallthrough */
+       case  2:        a += ((uint32_t)k[1])<<8;       /* fallthrough */
+       case  1:        a += k[0];
+           break;
+       case  0:
+           goto exit;
+       }
+    }
+
+    _JLU3_FINAL(a,b,c);
+
+exit:
+    *pc = c;
+    *pb = b;
+    return;
+}
+#endif /* defined(_JLU3_jlu32lpair) */
+
+#if defined(_JLU3_jlu32b)
+uint32_t jlu32b(uint32_t h, const void *key, size_t size);
+/*
+ * jlu32b():
+ * This is the same as jlu32w() on big-endian machines.  It is different
+ * from jlu32l() on all machines.  jlu32b() takes advantage of
+ * big-endian byte ordering. 
+ *
+ * @param h            the previous hash, or an arbitrary value
+ * @param *k           the key, an array of uint8_t values
+ * @param size         the size of the key
+ * @return             the lookup3 hash
+ */
+uint32_t jlu32b(uint32_t h, const void *key, size_t size)
+{
+    union { const void *ptr; size_t i; } u;
+    uint32_t a = _JLU3_INIT(h, size);
+    uint32_t b = a;
+    uint32_t c = a;
+
+    if (key == NULL)
+       return h;
+
+    u.ptr = key;
+    if (HASH_BIG_ENDIAN && ((u.i & 0x3) == 0)) {
+       const uint32_t *k = (const uint32_t *)key;      /* read 32-bit chunks */
+#ifdef VALGRIND
+       const uint8_t  *k8;
+#endif
+
+       /*-- all but last block: aligned reads and affect 32 bits of (a,b,c) */
+       while (size > 12) {
+           a += k[0];
+           b += k[1];
+           c += k[2];
+           _JLU3_MIX(a,b,c);
+           size -= 12;
+           k += 3;
+       }
+
+       /*------------------------- handle the last (probably partial) block */
+       /* 
+        * "k[2]<<8" actually reads beyond the end of the string, but
+        * then shifts out the part it's not allowed to read.  Because the
+        * string is aligned, the illegal read is in the same word as the
+        * rest of the string.  Every machine with memory protection I've seen
+        * does it on word boundaries, so is OK with this.  But VALGRIND will
+        * still catch it and complain.  The masking trick does make the hash
+        * noticeably faster for short strings (like English words).
+        */
+#ifndef VALGRIND
+
+       switch (size) {
+       case 12:        c += k[2]; b+=k[1]; a+=k[0]; break;
+       case 11:        c += k[2]&0xffffff00; b+=k[1]; a+=k[0]; break;
+       case 10:        c += k[2]&0xffff0000; b+=k[1]; a+=k[0]; break;
+       case  9:        c += k[2]&0xff000000; b+=k[1]; a+=k[0]; break;
+       case  8:        b += k[1]; a+=k[0]; break;
+       case  7:        b += k[1]&0xffffff00; a+=k[0]; break;
+       case  6:        b += k[1]&0xffff0000; a+=k[0]; break;
+       case  5:        b += k[1]&0xff000000; a+=k[0]; break;
+       case  4:        a += k[0]; break;
+       case  3:        a += k[0]&0xffffff00; break;
+       case  2:        a += k[0]&0xffff0000; break;
+       case  1:        a += k[0]&0xff000000; break;
+       case  0:        goto exit;
+    }
+
+#else  /* make valgrind happy */
+
+       k8 = (const uint8_t *)k;
+       switch (size) { /* all the case statements fall through */
+       case 12:        c += k[2]; b+=k[1]; a+=k[0];    break;
+       case 11:        c += ((uint32_t)k8[10])<<8;     /* fallthrough */
+       case 10:        c += ((uint32_t)k8[9])<<16;     /* fallthrough */
+       case  9:        c += ((uint32_t)k8[8])<<24;     /* fallthrough */
+       case  8:        b += k[1]; a+=k[0];             break;
+       case  7:        b += ((uint32_t)k8[6])<<8;      /* fallthrough */
+       case  6:        b += ((uint32_t)k8[5])<<16;     /* fallthrough */
+       case  5:        b += ((uint32_t)k8[4])<<24;     /* fallthrough */
+       case  4:        a += k[0];                      break;
+       case  3:        a += ((uint32_t)k8[2])<<8;      /* fallthrough */
+       case  2:        a += ((uint32_t)k8[1])<<16;     /* fallthrough */
+       case  1:        a += ((uint32_t)k8[0])<<24;     break;
+       case  0:        goto exit;
+    }
+
+#endif /* !VALGRIND */
+
+    } else {                        /* need to read the key one byte at a time */
+       const uint8_t *k = (const uint8_t *)key;
+
+       /*----------- all but the last block: affect some 32 bits of (a,b,c) */
+       while (size > 12) {
+           a += ((uint32_t)k[0])<<24;
+           a += ((uint32_t)k[1])<<16;
+           a += ((uint32_t)k[2])<<8;
+           a += ((uint32_t)k[3]);
+           b += ((uint32_t)k[4])<<24;
+           b += ((uint32_t)k[5])<<16;
+           b += ((uint32_t)k[6])<<8;
+           b += ((uint32_t)k[7]);
+           c += ((uint32_t)k[8])<<24;
+           c += ((uint32_t)k[9])<<16;
+           c += ((uint32_t)k[10])<<8;
+           c += ((uint32_t)k[11]);
+           _JLU3_MIX(a,b,c);
+           size -= 12;
+           k += 12;
+       }
+
+       /*---------------------------- last block: affect all 32 bits of (c) */
+       switch (size) { /* all the case statements fall through */
+       case 12:        c += k[11];                     /* fallthrough */
+       case 11:        c += ((uint32_t)k[10])<<8;      /* fallthrough */
+       case 10:        c += ((uint32_t)k[9])<<16;      /* fallthrough */
+       case  9:        c += ((uint32_t)k[8])<<24;      /* fallthrough */
+       case  8:        b += k[7];                      /* fallthrough */
+       case  7:        b += ((uint32_t)k[6])<<8;       /* fallthrough */
+       case  6:        b += ((uint32_t)k[5])<<16;      /* fallthrough */
+       case  5:        b += ((uint32_t)k[4])<<24;      /* fallthrough */
+       case  4:        a += k[3];                      /* fallthrough */
+       case  3:        a += ((uint32_t)k[2])<<8;       /* fallthrough */
+       case  2:        a += ((uint32_t)k[1])<<16;      /* fallthrough */
+       case  1:        a += ((uint32_t)k[0])<<24;      /* fallthrough */
+           break;
+       case  0:
+           goto exit;
+       }
+    }
+
+    _JLU3_FINAL(a,b,c);
+
+exit:
+    return c;
+}
+#endif /* defined(_JLU3_jlu32b) */
+
+#if defined(_JLU3_SELFTEST)
+
+/* used for timings */
+static void driver1(void)
+{
+    uint8_t buf[256];
+    uint32_t i;
+    uint32_t h=0;
+    time_t a,z;
+
+    time(&a);
+    for (i=0; i<256; ++i) buf[i] = 'x';
+    for (i=0; i<1; ++i) {
+       h = jlu32l(h, &buf[0], sizeof(buf[0]));
+    }
+    time(&z);
+    if (z-a > 0) printf("time %d %.8x\n", (int)(z-a), h);
+}
+
+/* check that every input bit changes every output bit half the time */
+#define HASHSTATE 1
+#define HASHLEN   1
+#define MAXPAIR 60
+#define MAXLEN  70
+static void driver2(void)
+{
+    uint8_t qa[MAXLEN+1], qb[MAXLEN+2], *a = &qa[0], *b = &qb[1];
+    uint32_t c[HASHSTATE], d[HASHSTATE], i=0, j=0, k, l, m=0, z;
+    uint32_t e[HASHSTATE],f[HASHSTATE],g[HASHSTATE],h[HASHSTATE];
+    uint32_t x[HASHSTATE],y[HASHSTATE];
+    uint32_t hlen;
+
+    printf("No more than %d trials should ever be needed \n",MAXPAIR/2);
+    for (hlen=0; hlen < MAXLEN; ++hlen) {
+       z=0;
+       for (i=0; i<hlen; ++i) {        /*-------------- for each input byte, */
+           for (j=0; j<8; ++j) {       /*--------------- for each input bit, */
+               for (m=1; m<8; ++m) {   /*---- for several possible initvals, */
+                   for (l=0; l<HASHSTATE; ++l)
+                       e[l]=f[l]=g[l]=h[l]=x[l]=y[l]=~((uint32_t)0);
+
+                   /* check that every output bit is affected by that input bit */
+                   for (k=0; k<MAXPAIR; k+=2) { 
+                       uint32_t finished=1;
+                       /* keys have one bit different */
+                       for (l=0; l<hlen+1; ++l) {a[l] = b[l] = (uint8_t)0;}
+                       /* have a and b be two keys differing in only one bit */
+                       a[i] ^= (k<<j);
+                       a[i] ^= (k>>(8-j));
+                       c[0] = jlu32l(m, a, hlen);
+                       b[i] ^= ((k+1)<<j);
+                       b[i] ^= ((k+1)>>(8-j));
+                       d[0] = jlu32l(m, b, hlen);
+                       /* check every bit is 1, 0, set, and not set at least once */
+                       for (l=0; l<HASHSTATE; ++l) {
+                           e[l] &= (c[l]^d[l]);
+                           f[l] &= ~(c[l]^d[l]);
+                           g[l] &= c[l];
+                           h[l] &= ~c[l];
+                           x[l] &= d[l];
+                           y[l] &= ~d[l];
+                           if (e[l]|f[l]|g[l]|h[l]|x[l]|y[l]) finished=0;
+                       }
+                       if (finished) break;
+                   }
+                   if (k>z) z=k;
+                   if (k == MAXPAIR) {
+                       printf("Some bit didn't change: ");
+                       printf("%.8x %.8x %.8x %.8x %.8x %.8x  ",
+                               e[0],f[0],g[0],h[0],x[0],y[0]);
+                       printf("i %u j %u m %u len %u\n", i, j, m, hlen);
+                   }
+                   if (z == MAXPAIR) goto done;
+               }
+           }
+       }
+   done:
+       if (z < MAXPAIR) {
+           printf("Mix success  %2u bytes  %2u initvals  ",i,m);
+           printf("required  %u  trials\n", z/2);
+       }
+    }
+    printf("\n");
+}
+
+/* Check for reading beyond the end of the buffer and alignment problems */
+static void driver3(void)
+{
+    uint8_t buf[MAXLEN+20], *b;
+    uint32_t len;
+    uint8_t q[] = "This is the time for all good men to come to the aid of their country...";
+    uint32_t h;
+    uint8_t qq[] = "xThis is the time for all good men to come to the aid of their country...";
+    uint32_t i;
+    uint8_t qqq[] = "xxThis is the time for all good men to come to the aid of their country...";
+    uint32_t j;
+    uint8_t qqqq[] = "xxxThis is the time for all good men to come to the aid of their country...";
+    uint32_t ref,x,y;
+    uint8_t *p;
+    uint32_t m = 13;
+
+    printf("Endianness.  These lines should all be the same (for values filled in):\n");
+    printf("%.8x                            %.8x                            %.8x\n",
+       jlu32w(m, (const uint32_t *)q, (sizeof(q)-1)/4),
+       jlu32w(m, (const uint32_t *)q, (sizeof(q)-5)/4),
+       jlu32w(m, (const uint32_t *)q, (sizeof(q)-9)/4));
+    p = q;
+    printf("%.8x %.8x %.8x %.8x %.8x %.8x %.8x %.8x %.8x %.8x %.8x %.8x\n",
+       jlu32l(m, p, sizeof(q)-1), jlu32l(m, p, sizeof(q)-2),
+       jlu32l(m, p, sizeof(q)-3), jlu32l(m, p, sizeof(q)-4),
+       jlu32l(m, p, sizeof(q)-5), jlu32l(m, p, sizeof(q)-6),
+       jlu32l(m, p, sizeof(q)-7), jlu32l(m, p, sizeof(q)-8),
+       jlu32l(m, p, sizeof(q)-9), jlu32l(m, p, sizeof(q)-10),
+       jlu32l(m, p, sizeof(q)-11), jlu32l(m, p, sizeof(q)-12));
+    p = &qq[1];
+    printf("%.8x %.8x %.8x %.8x %.8x %.8x %.8x %.8x %.8x %.8x %.8x %.8x\n",
+       jlu32l(m, p, sizeof(q)-1), jlu32l(m, p, sizeof(q)-2),
+       jlu32l(m, p, sizeof(q)-3), jlu32l(m, p, sizeof(q)-4),
+       jlu32l(m, p, sizeof(q)-5), jlu32l(m, p, sizeof(q)-6),
+       jlu32l(m, p, sizeof(q)-7), jlu32l(m, p, sizeof(q)-8),
+       jlu32l(m, p, sizeof(q)-9), jlu32l(m, p, sizeof(q)-10),
+       jlu32l(m, p, sizeof(q)-11), jlu32l(m, p, sizeof(q)-12));
+    p = &qqq[2];
+    printf("%.8x %.8x %.8x %.8x %.8x %.8x %.8x %.8x %.8x %.8x %.8x %.8x\n",
+       jlu32l(m, p, sizeof(q)-1), jlu32l(m, p, sizeof(q)-2),
+       jlu32l(m, p, sizeof(q)-3), jlu32l(m, p, sizeof(q)-4),
+       jlu32l(m, p, sizeof(q)-5), jlu32l(m, p, sizeof(q)-6),
+       jlu32l(m, p, sizeof(q)-7), jlu32l(m, p, sizeof(q)-8),
+       jlu32l(m, p, sizeof(q)-9), jlu32l(m, p, sizeof(q)-10),
+       jlu32l(m, p, sizeof(q)-11), jlu32l(m, p, sizeof(q)-12));
+    p = &qqqq[3];
+    printf("%.8x %.8x %.8x %.8x %.8x %.8x %.8x %.8x %.8x %.8x %.8x %.8x\n",
+       jlu32l(m, p, sizeof(q)-1), jlu32l(m, p, sizeof(q)-2),
+       jlu32l(m, p, sizeof(q)-3), jlu32l(m, p, sizeof(q)-4),
+       jlu32l(m, p, sizeof(q)-5), jlu32l(m, p, sizeof(q)-6),
+       jlu32l(m, p, sizeof(q)-7), jlu32l(m, p, sizeof(q)-8),
+       jlu32l(m, p, sizeof(q)-9), jlu32l(m, p, sizeof(q)-10),
+       jlu32l(m, p, sizeof(q)-11), jlu32l(m, p, sizeof(q)-12));
+    printf("\n");
+    for (h=0, b=buf+1; h<8; ++h, ++b) {
+       for (i=0; i<MAXLEN; ++i) {
+           len = i;
+           for (j=0; j<i; ++j)
+               *(b+j)=0;
+
+           /* these should all be equal */
+           m = 1;
+           ref = jlu32l(m, b, len);
+           *(b+i)=(uint8_t)~0;
+           *(b-1)=(uint8_t)~0;
+           x = jlu32l(m, b, len);
+           y = jlu32l(m, b, len);
+           if ((ref != x) || (ref != y)) 
+               printf("alignment error: %.8x %.8x %.8x %u %u\n",ref,x,y, h, i);
+       }
+    }
+}
+
+/* check for problems with nulls */
+static void driver4(void)
+{
+    uint8_t buf[1];
+    uint32_t h;
+    uint32_t i;
+    uint32_t state[HASHSTATE];
+
+    buf[0] = ~0;
+    for (i=0; i<HASHSTATE; ++i)
+       state[i] = 1;
+    printf("These should all be different\n");
+    h = 0;
+    for (i=0; i<8; ++i) {
+       h = jlu32l(h, buf, 0);
+       printf("%2ld  0-byte strings, hash is  %.8x\n", (long)i, h);
+    }
+}
+
+
+int main(int argc, char ** argv)
+{
+    driver1(); /* test that the key is hashed: used for timings */
+    driver2(); /* test that whole key is hashed thoroughly */
+    driver3(); /* test that nothing but the key is hashed */
+    driver4(); /* test hashing multiple buffers (all buffers are null) */
+    return 1;
+}
+
+#endif  /* _JLU3_SELFTEST */
index 5d927f782dcbad36085db6f607a24509b5e09db9..f3f26a3da1cdd0478edec96910e6c6aa0986f6a3 100644 (file)
@@ -1,5 +1,5 @@
 /** \ingroup popt
- * \file popt/popt.c
+ * @file
  */
 
 /* (C) 1998-2002 Red Hat, Inc. -- Licensing details are in the COPYING
 
 #include "system.h"
 
-#if HAVE_FLOAT_H
 #include <float.h>
-#endif
 #include <math.h>
+#include <unistd.h>
+#include <limits.h>
+#include <errno.h>
 
-#include "findme.h"
 #include "poptint.h"
 
-#ifndef DBL_EPSILON
-#define DBL_EPSILON 2.2204460492503131e-16
+#ifdef HAVE_STDALIGN_H
+#include <stdalign.h>
+#define ALIGNOF(x) alignof(x)
+#elif defined __GNUC__
+#define ALIGNOF(x) __alignof__(x)
+#else
+#define ALIGNOF(x) sizeof(x)
 #endif
 
 #ifdef MYDEBUG
-/*@unchecked@*/
 int _popt_debug = 0;
 #endif
 
-#if !defined(HAVE_STRERROR) && !defined(__LCLINT__)
+unsigned int _poptArgMask = POPT_ARG_MASK;
+unsigned int _poptGroupMask = POPT_GROUP_MASK;
+
+#if !defined(HAVE_STRERROR)
 static char * strerror(int errno)
 {
     extern int sys_nerr;
@@ -41,7 +48,6 @@ static char * strerror(int errno)
 #endif
 
 #ifdef MYDEBUG
-/*@unused@*/
 static void prtcon(const char *msg, poptContext con)
 {
     if (msg) fprintf(stderr, "%s", msg);
@@ -60,119 +66,93 @@ void poptSetExecPath(poptContext con, const char * path, int allowAbsolute)
     con->execPath = _free(con->execPath);
     con->execPath = xstrdup(path);
     con->execAbsolute = allowAbsolute;
-    /*@-nullstate@*/ /* LCL: con->execPath not NULL */
     return;
-    /*@=nullstate@*/
 }
 
 static void invokeCallbacksPRE(poptContext con, const struct poptOption * opt)
-       /*@globals internalState@*/
-       /*@modifies internalState@*/
 {
     if (opt != NULL)
     for (; opt->longName || opt->shortName || opt->arg; opt++) {
-       if (opt->arg == NULL) continue;         /* XXX program error. */
-       if ((opt->argInfo & POPT_ARG_MASK) == POPT_ARG_INCLUDE_TABLE) {
-           void * arg = opt->arg;
-/*@-branchstate@*/
-           /* XXX sick hack to preserve pretense of ABI. */
-           if (arg == poptHelpOptions) arg = poptHelpOptionsI18N;
-/*@=branchstate@*/
-           /* Recurse on included sub-tables. */
-           invokeCallbacksPRE(con, arg);
-       } else if ((opt->argInfo & POPT_ARG_MASK) == POPT_ARG_CALLBACK &&
-                  (opt->argInfo & POPT_CBFLAG_PRE))
-       {   /*@-castfcnptr@*/
-           poptCallbackType cb = (poptCallbackType)opt->arg;
-           /*@=castfcnptr@*/
-           /* Perform callback. */
-           /*@-noeffectuncon @*/
-           cb(con, POPT_CALLBACK_REASON_PRE, NULL, NULL, opt->descrip);
-           /*@=noeffectuncon @*/
+       poptArg arg = { .ptr = opt->arg };
+       if (arg.ptr)
+       switch (poptArgType(opt)) {
+       case POPT_ARG_INCLUDE_TABLE:    /* Recurse on included sub-tables. */
+           poptSubstituteHelpI18N(arg.opt);    /* XXX side effects */
+           invokeCallbacksPRE(con, arg.opt);
+           break;
+       case POPT_ARG_CALLBACK:         /* Perform callback. */
+           if (!CBF_ISSET(opt, PRE))
+               break;
+           arg.cb(con, POPT_CALLBACK_REASON_PRE, NULL, NULL, opt->descrip);
+           break;
        }
     }
 }
 
 static void invokeCallbacksPOST(poptContext con, const struct poptOption * opt)
-       /*@globals internalState@*/
-       /*@modifies internalState@*/
 {
     if (opt != NULL)
     for (; opt->longName || opt->shortName || opt->arg; opt++) {
-       if (opt->arg == NULL) continue;         /* XXX program error. */
-       if ((opt->argInfo & POPT_ARG_MASK) == POPT_ARG_INCLUDE_TABLE) {
-           void * arg = opt->arg;
-/*@-branchstate@*/
-           /* XXX sick hack to preserve pretense of ABI. */
-           if (arg == poptHelpOptions) arg = poptHelpOptionsI18N;
-/*@=branchstate@*/
-           /* Recurse on included sub-tables. */
-           invokeCallbacksPOST(con, arg);
-       } else if ((opt->argInfo & POPT_ARG_MASK) == POPT_ARG_CALLBACK &&
-                  (opt->argInfo & POPT_CBFLAG_POST))
-       {   /*@-castfcnptr@*/
-           poptCallbackType cb = (poptCallbackType)opt->arg;
-           /*@=castfcnptr@*/
-           /* Perform callback. */
-           /*@-noeffectuncon @*/
-           cb(con, POPT_CALLBACK_REASON_POST, NULL, NULL, opt->descrip);
-           /*@=noeffectuncon @*/
+       poptArg arg = { .ptr = opt->arg };
+       if (arg.ptr)
+       switch (poptArgType(opt)) {
+       case POPT_ARG_INCLUDE_TABLE:    /* Recurse on included sub-tables. */
+           poptSubstituteHelpI18N(arg.opt);    /* XXX side effects */
+           invokeCallbacksPOST(con, arg.opt);
+           break;
+       case POPT_ARG_CALLBACK:         /* Perform callback. */
+           if (!CBF_ISSET(opt, POST))
+               break;
+           arg.cb(con, POPT_CALLBACK_REASON_POST, NULL, NULL, opt->descrip);
+           break;
        }
     }
 }
 
 static void invokeCallbacksOPTION(poptContext con,
-                                 const struct poptOption * opt,
-                                 const struct poptOption * myOpt,
-                                 /*@null@*/ const void * myData, int shorty)
-       /*@globals internalState@*/
-       /*@modifies internalState@*/
+                               const struct poptOption * opt,
+                               const struct poptOption * myOpt,
+                               const void * myData, int shorty)
 {
     const struct poptOption * cbopt = NULL;
+    poptArg cbarg = { .ptr = NULL };
 
     if (opt != NULL)
     for (; opt->longName || opt->shortName || opt->arg; opt++) {
-       if ((opt->argInfo & POPT_ARG_MASK) == POPT_ARG_INCLUDE_TABLE) {
-           void * arg = opt->arg;
-/*@-branchstate@*/
-           /* XXX sick hack to preserve pretense of ABI. */
-           if (arg == poptHelpOptions) arg = poptHelpOptionsI18N;
-/*@=branchstate@*/
-           /* Recurse on included sub-tables. */
-           if (opt->arg != NULL)       /* XXX program error */
+       poptArg arg = { .ptr = opt->arg };
+       switch (poptArgType(opt)) {
+       case POPT_ARG_INCLUDE_TABLE:    /* Recurse on included sub-tables. */
+           poptSubstituteHelpI18N(arg.opt);    /* XXX side effects */
+           if (opt->arg != NULL)
                invokeCallbacksOPTION(con, opt->arg, myOpt, myData, shorty);
-       } else if ((opt->argInfo & POPT_ARG_MASK) == POPT_ARG_CALLBACK &&
-                 !(opt->argInfo & POPT_CBFLAG_SKIPOPTION)) {
-           /* Save callback info. */
+           break;
+       case POPT_ARG_CALLBACK:         /* Save callback info. */
+           if (CBF_ISSET(opt, SKIPOPTION))
+               break;
            cbopt = opt;
-       } else if (cbopt != NULL &&
-                  ((myOpt->shortName && opt->shortName && shorty &&
-                       myOpt->shortName == opt->shortName) ||
-                   (myOpt->longName && opt->longName &&
-               /*@-nullpass@*/         /* LCL: opt->longName != NULL */
+           cbarg.ptr = opt->arg;
+           break;
+       default:                /* Perform callback on matching option. */
+           if (cbopt == NULL || cbarg.cb == NULL)
+               break;
+           if ((myOpt->shortName && opt->shortName && shorty &&
+                       myOpt->shortName == opt->shortName)
+            || (myOpt->longName != NULL && opt->longName != NULL &&
                        !strcmp(myOpt->longName, opt->longName)))
-               /*@=nullpass@*/
-                  )
-       {   /*@-castfcnptr@*/
-           poptCallbackType cb = (poptCallbackType)cbopt->arg;
-           /*@=castfcnptr@*/
-           const void * cbData = (cbopt->descrip ? cbopt->descrip : myData);
-           /* Perform callback. */
-           if (cb != NULL) {   /* XXX program error */
-               /*@-noeffectuncon @*/
-               cb(con, POPT_CALLBACK_REASON_OPTION, myOpt,
-                       con->os->nextArg, cbData);
-               /*@=noeffectuncon @*/
+           {   const void *cbData = (cbopt->descrip ? cbopt->descrip : myData);
+               cbarg.cb(con, POPT_CALLBACK_REASON_OPTION,
+                       myOpt, con->os->nextArg, cbData);
+               /* Terminate (unless explcitly continuing). */
+               if (!CBF_ISSET(cbopt, CONTINUE))
+                   return;
            }
-           /* Terminate (unless explcitly continuing). */
-           if (!(cbopt->argInfo & POPT_CBFLAG_CONTINUE))
-               return;
+           break;
        }
     }
 }
 
 poptContext poptGetContext(const char * name, int argc, const char ** argv,
-                          const struct poptOption * options, int flags)
+                       const struct poptOption * options, unsigned int flags)
 {
     poptContext con = malloc(sizeof(*con));
 
@@ -181,58 +161,44 @@ poptContext poptGetContext(const char * name, int argc, const char ** argv,
 
     con->os = con->optionStack;
     con->os->argc = argc;
-    /*@-dependenttrans -assignexpose@*/        /* FIX: W2DO? */
     con->os->argv = argv;
-    /*@=dependenttrans =assignexpose@*/
     con->os->argb = NULL;
 
     if (!(flags & POPT_CONTEXT_KEEP_FIRST))
-       con->os->next = 1;                      /* skip argv[0] */
+       con->os->next = 1;              /* skip argv[0] */
 
-    con->leftovers = calloc( (argc + 1), sizeof(*con->leftovers) );
-    /*@-dependenttrans -assignexpose@*/        /* FIX: W2DO? */
+    con->leftovers = calloc( (size_t)(argc + 1), sizeof(*con->leftovers) );
+    con->allocLeftovers = argc + 1;
     con->options = options;
-    /*@=dependenttrans =assignexpose@*/
     con->aliases = NULL;
     con->numAliases = 0;
     con->flags = flags;
     con->execs = NULL;
     con->numExecs = 0;
+    con->execFail = NULL;
     con->finalArgvAlloced = argc * 2;
-    con->finalArgv = calloc( con->finalArgvAlloced, sizeof(*con->finalArgv) );
+    con->finalArgv = calloc( (size_t)con->finalArgvAlloced, sizeof(*con->finalArgv) );
     con->execAbsolute = 1;
     con->arg_strip = NULL;
 
     if (getenv("POSIXLY_CORRECT") || getenv("POSIX_ME_HARDER"))
        con->flags |= POPT_CONTEXT_POSIXMEHARDER;
 
-    if (name) {
-       size_t bufsize = strlen(name) + 1;
-       char * t = malloc(bufsize);
-       if (t) {
-           strlcpy(t, name, bufsize);
-           con->appName = t;
-       }
-    }
+    if (name)
+       con->appName = xstrdup(name);
 
-    /*@-internalglobs@*/
     invokeCallbacksPRE(con, con->options);
-    /*@=internalglobs@*/
 
     return con;
 }
 
-static void cleanOSE(/*@special@*/ struct optionStackEntry *os)
-       /*@uses os @*/
-       /*@releases os->nextArg, os->argv, os->argb @*/
-       /*@modifies os @*/
+static void cleanOSE(struct optionStackEntry *os)
 {
     os->nextArg = _free(os->nextArg);
     os->argv = _free(os->argv);
     os->argb = PBM_FREE(os->argb);
 }
 
-/*@-boundswrite@*/
 void poptResetContext(poptContext con)
 {
     int i;
@@ -244,36 +210,34 @@ void poptResetContext(poptContext con)
     con->os->argb = PBM_FREE(con->os->argb);
     con->os->currAlias = NULL;
     con->os->nextCharArg = NULL;
-    con->os->nextArg = NULL;
-    con->os->next = 1;                 /* skip argv[0] */
+    con->os->nextArg = _free(con->os->nextArg);
+    if (!(con->flags & POPT_CONTEXT_KEEP_FIRST))
+       con->os->next = 1;              /* skip argv[0] */
+    else
+       con->os->next = 0;
 
+    for (i = 0; i < con->numLeftovers; i++) {
+        con->leftovers[i] = _free(con->leftovers[i]);
+    }
     con->numLeftovers = 0;
     con->nextLeftover = 0;
     con->restLeftover = 0;
     con->doExec = NULL;
+    con->execFail = _free(con->execFail);
 
     if (con->finalArgv != NULL)
     for (i = 0; i < con->finalArgvCount; i++) {
-       /*@-unqualifiedtrans@*/         /* FIX: typedef double indirection. */
        con->finalArgv[i] = _free(con->finalArgv[i]);
-       /*@=unqualifiedtrans@*/
     }
 
     con->finalArgvCount = 0;
     con->arg_strip = PBM_FREE(con->arg_strip);
-    /*@-nullstate@*/   /* FIX: con->finalArgv != NULL */
     return;
-    /*@=nullstate@*/
 }
-/*@=boundswrite@*/
 
 /* Only one of longName, shortName should be set, not both. */
-/*@-boundswrite@*/
-static int handleExec(/*@special@*/ poptContext con,
-               /*@null@*/ const char * longName, char shortName)
-       /*@uses con->execs, con->numExecs, con->flags, con->doExec,
-               con->finalArgv, con->finalArgvAlloced, con->finalArgvCount @*/
-       /*@modifies con @*/
+static int handleExec(poptContext con,
+               const char * longName, char shortName)
 {
     poptItem item;
     int i;
@@ -311,40 +275,75 @@ static int handleExec(/*@special@*/ poptContext con,
 
     i = con->finalArgvCount++;
     if (con->finalArgv != NULL)        /* XXX can't happen */
-    {  size_t bufsize = (longName ? strlen(longName) : 0) + 3;
-       char *s  = malloc(bufsize);
+    {  char *s  = malloc((longName ? strlen(longName) : 0) + sizeof("--"));
        if (s != NULL) {        /* XXX can't happen */
+           con->finalArgv[i] = s;
+           *s++ = '-';
            if (longName)
-               snprintf(s, bufsize, "--%s", longName);
+               s = stpcpy( stpcpy(s, "-"), longName);
            else
-               snprintf(s, bufsize, "-%c", shortName);
-           con->finalArgv[i] = s;
+               *s++ = shortName;
+           *s = '\0';
        } else
            con->finalArgv[i] = NULL;
     }
 
-    /*@-nullstate@*/   /* FIX: con->finalArgv[] == NULL */
     return 1;
-    /*@=nullstate@*/
 }
-/*@=boundswrite@*/
+
+/**
+ * Compare long option for equality, adjusting for POPT_ARGFLAG_TOGGLE.
+ * @param opt           option
+ * @param longName     arg option
+ * @param longNameLen  arg option length
+ * @return             does long option match?
+ */
+static int
+longOptionStrcmp(const struct poptOption * opt,
+               const char * longName, size_t longNameLen)
+{
+    const char * optLongName = opt->longName;
+    int rc;
+
+    if (optLongName == NULL || longName == NULL)       /* XXX can't heppen */
+       return 0;
+
+    if (F_ISSET(opt, TOGGLE)) {
+       if (optLongName[0] == 'n' && optLongName[1] == 'o') {
+           optLongName += sizeof("no") - 1;
+           if (optLongName[0] == '-')
+               optLongName++;
+       }
+       if (longName[0] == 'n' && longName[1] == 'o') {
+           longName += sizeof("no") - 1;
+           longNameLen -= sizeof("no") - 1;
+           if (longName[0] == '-') {
+               longName++;
+               longNameLen--;
+           }
+       }
+    }
+    rc = (int)(strlen(optLongName) == longNameLen);
+    if (rc)
+       rc = (int)(strncmp(optLongName, longName, longNameLen) == 0);
+    return rc;
+}
 
 /* Only one of longName, shortName may be set at a time */
-static int handleAlias(/*@special@*/ poptContext con,
-               /*@null@*/ const char * longName, char shortName,
-               /*@exposed@*/ /*@null@*/ const char * nextCharArg)
-       /*@uses con->aliases, con->numAliases, con->optionStack, con->os,
-               con->os->currAlias, con->os->currAlias->option.longName @*/
-       /*@modifies con @*/
+static int handleAlias(poptContext con,
+               const char * longName, size_t longNameLen,
+               char shortName,
+               const char * nextArg)
 {
     poptItem item = con->os->currAlias;
     int rc;
     int i;
 
     if (item) {
-       if (longName && (item->option.longName &&
-               !strcmp(longName, item->option.longName)))
+       if (longName && item->option.longName != NULL
+        && longOptionStrcmp(&item->option, longName, longNameLen))
            return 0;
+       else
        if (shortName && shortName == item->option.shortName)
            return 0;
     }
@@ -354,10 +353,12 @@ static int handleAlias(/*@special@*/ poptContext con,
 
     for (i = con->numAliases - 1; i >= 0; i--) {
        item = con->aliases + i;
-       if (longName && !(item->option.longName &&
-                       !strcmp(longName, item->option.longName)))
-           continue;
-       else if (shortName != item->option.shortName)
+       if (longName) {
+           if (item->option.longName == NULL)
+               continue;
+           if (!longOptionStrcmp(&item->option, longName, longNameLen))
+               continue;
+       } else if (shortName != item->option.shortName)
            continue;
        break;
     }
@@ -366,10 +367,8 @@ static int handleAlias(/*@special@*/ poptContext con,
     if ((con->os - con->optionStack + 1) == POPT_OPTION_DEPTH)
        return POPT_ERROR_OPTSTOODEEP;
 
-/*@-boundsread@*/
-    if (nextCharArg && *nextCharArg)
-       con->os->nextCharArg = nextCharArg;
-/*@=boundsread@*/
+    if (longName == NULL && nextArg != NULL && *nextArg != '\0')
+       con->os->nextCharArg = nextArg;
 
     con->os++;
     con->os->next = 0;
@@ -377,21 +376,82 @@ static int handleAlias(/*@special@*/ poptContext con,
     con->os->nextArg = NULL;
     con->os->nextCharArg = NULL;
     con->os->currAlias = con->aliases + i;
-    rc = poptDupArgv(con->os->currAlias->argc, con->os->currAlias->argv,
-               &con->os->argc, &con->os->argv);
+    {  const char ** av;
+       int ac = con->os->currAlias->argc;
+       /* Append --foo=bar arg to alias argv array (if present). */ 
+       if (longName && nextArg != NULL && *nextArg != '\0') {
+           av = malloc((ac + 1 + 1) * sizeof(*av));
+           if (av != NULL) {   /* XXX won't happen. */
+               for (i = 0; i < ac; i++) {
+                   av[i] = con->os->currAlias->argv[i];
+               }
+               av[ac++] = nextArg;
+               av[ac] = NULL;
+           } else      /* XXX revert to old popt behavior if malloc fails. */
+               av = con->os->currAlias->argv;
+       } else
+           av = con->os->currAlias->argv;
+       rc = poptDupArgv(ac, av, &con->os->argc, &con->os->argv);
+       if (av != NULL && av != con->os->currAlias->argv)
+           free(av);
+    }
     con->os->argb = NULL;
 
     return (rc ? rc : 1);
 }
 
-/*@-bounds -boundswrite @*/
+/**
+ * Return absolute path to executable by searching PATH.
+ * @param argv0                name of executable
+ * @return             (malloc'd) absolute path to executable (or NULL)
+ */
+static
+const char * findProgramPath(const char * argv0)
+{
+    char *path = NULL, *s = NULL, *se;
+    char *t = NULL;
+
+    if (argv0 == NULL) return NULL;    /* XXX can't happen */
+
+    /* If there is a / in argv[0], it has to be an absolute path. */
+    /* XXX Hmmm, why not if (argv0[0] == '/') ... instead? */
+    if (strchr(argv0, '/'))
+       return xstrdup(argv0);
+
+    if ((path = getenv("PATH")) == NULL || (path = xstrdup(path)) == NULL)
+       return NULL;
+
+    /* The return buffer in t is big enough for any path. */
+    if ((t = malloc(strlen(path) + strlen(argv0) + sizeof("/"))) != NULL)
+    for (s = path; s && *s; s = se) {
+
+       /* Snip PATH element into [s,se). */
+       if ((se = strchr(s, ':')))
+           *se++ = '\0';
+
+       /* Append argv0 to PATH element. */
+       (void) stpcpy(stpcpy(stpcpy(t, s), "/"), argv0);
+
+       /* If file is executable, bingo! */
+       if (!access(t, X_OK))
+           break;
+    }
+
+    /* If no executable was found in PATH, return NULL. */
+    if (!(s && *s) && t != NULL)
+       t = _free(t);
+    path = _free(path);
+
+    return t;
+}
+
 static int execCommand(poptContext con)
-       /*@globals internalState @*/
-       /*@modifies internalState @*/
 {
     poptItem item = con->doExec;
-    const char ** argv;
+    poptArgv argv = NULL;
     int argc = 0;
+    int rc;
+    int ec = POPT_ERROR_ERRNO;
 
     if (item == NULL) /*XXX can't happen*/
        return POPT_ERROR_NOARG;
@@ -405,13 +465,17 @@ static int execCommand(poptContext con)
     if (argv == NULL) return POPT_ERROR_MALLOC;
 
     if (!strchr(item->argv[0], '/') && con->execPath != NULL) {
-       size_t bufsize = strlen(con->execPath) + strlen(item->argv[0]) + sizeof "/";
-       char *s = alloca(bufsize);
-       snprintf(s, bufsize, "%s/%s", con->execPath, item->argv[0]);
+       char *s = malloc(strlen(con->execPath) + strlen(item->argv[0]) + sizeof("/"));
+       if (s)
+           (void)stpcpy(stpcpy(stpcpy(s, con->execPath), "/"), item->argv[0]);
+
        argv[argc] = s;
     } else
        argv[argc] = findProgramPath(item->argv[0]);
-    if (argv[argc++] == NULL) return POPT_ERROR_NOARG;
+    if (argv[argc++] == NULL) {
+       ec = POPT_ERROR_NOARG;
+       goto exit;
+    }
 
     if (item->argc > 1) {
        memcpy(argv + argc, item->argv + 1, sizeof(*argv) * (item->argc - 1));
@@ -431,12 +495,11 @@ static int execCommand(poptContext con)
 
     argv[argc] = NULL;
 
-  {
-#ifdef __hpux
-    int rc = setresgid(getgid(), getgid(),-1);
-    if (rc) return POPT_ERROR_ERRNO;
+#if defined(hpux) || defined(__hpux)
+    rc = setresgid(getgid(), getgid(),-1);
+    if (rc) goto exit;
     rc = setresuid(getuid(), getuid(),-1);
-    if (rc) return POPT_ERROR_ERRNO;
+    if (rc) goto exit;
 #else
 /*
  * XXX " ... on BSD systems setuid() should be preferred over setreuid()"
@@ -444,27 +507,27 @@ static int execCommand(poptContext con)
  * XXX from Norbert Warmuth <nwarmuth@privat.circular.de>
  */
 #if defined(HAVE_SETUID)
-    int rc = setgid(getgid());
-    if (rc) return POPT_ERROR_ERRNO;
+    rc = setgid(getgid());
+    if (rc) goto exit;
     rc = setuid(getuid());
-    if (rc) return POPT_ERROR_ERRNO;
+    if (rc) goto exit;
 #elif defined (HAVE_SETREUID)
-    int rc = setregid(getgid(), getgid());
-    if (rc) return POPT_ERROR_ERRNO;
+    rc = setregid(getgid(), getgid());
+    if (rc) goto exit;
     rc = setreuid(getuid(), getuid());
-    if (rc) return POPT_ERROR_ERRNO;
+    if (rc) goto exit;
 #else
-    ; /* Can't drop privileges */
+    /* refuse to exec if we cannot drop suid/sgid privileges */
+    if (getuid() != geteuid() || getgid() != getegid()) {
+       errno = ENOTSUP;
+       goto exit;
+    }
 #endif
 #endif
-  }
-
-    if (argv[0] == NULL)
-       return POPT_ERROR_NOARG;
 
 #ifdef MYDEBUG
 if (_popt_debug)
-    {  const char ** avp;
+    {  poptArgv avp;
        fprintf(stderr, "==> execvp(%s) argv[%d]:", argv[0], argc);
        for (avp = argv; *avp; avp++)
            fprintf(stderr, " '%s'", *avp);
@@ -472,56 +535,65 @@ if (_popt_debug)
     }
 #endif
 
-    execvp(argv[0], (char *const *)argv);
+    rc = execvp(argv[0], (char *const *)argv);
 
-    return POPT_ERROR_ERRNO;
+    /* only reached on execvp() failure */
+    con->execFail = xstrdup(argv[0]);
+
+exit:
+    if (argv) {
+        if (argv[0])
+            free((void *)argv[0]);
+        free(argv);
+    }
+    return ec;
 }
-/*@=bounds =boundswrite @*/
 
-/*@-boundswrite@*/
-/*@observer@*/ /*@null@*/ static const struct poptOption *
-findOption(const struct poptOption * opt, /*@null@*/ const char * longName,
+static const struct poptOption *
+findOption(const struct poptOption * opt,
+               const char * longName, size_t longNameLen,
                char shortName,
-               /*@null@*/ /*@out@*/ poptCallbackType * callback,
-               /*@null@*/ /*@out@*/ const void ** callbackData,
-               int singleDash)
-       /*@modifies *callback, *callbackData */
+               poptCallbackType * callback,
+               const void ** callbackData,
+               unsigned int argInfo)
 {
     const struct poptOption * cb = NULL;
+    poptArg cbarg = { .ptr = NULL };
 
     /* This happens when a single - is given */
-    if (singleDash && !shortName && (longName && *longName == '\0'))
+    if (LF_ISSET(ONEDASH) && !shortName && (longName && *longName == '\0'))
        shortName = '-';
 
     for (; opt->longName || opt->shortName || opt->arg; opt++) {
+       poptArg arg = { .ptr = opt->arg };
 
-       if ((opt->argInfo & POPT_ARG_MASK) == POPT_ARG_INCLUDE_TABLE) {
-           const struct poptOption * opt2;
-           void * arg = opt->arg;
-
-/*@-branchstate@*/
-           /* XXX sick hack to preserve pretense of ABI. */
-           if (arg == poptHelpOptions) arg = poptHelpOptionsI18N;
-/*@=branchstate@*/
-           /* Recurse on included sub-tables. */
-           if (arg == NULL) continue;  /* XXX program error */
-           opt2 = findOption(arg, longName, shortName, callback,
-                             callbackData, singleDash);
+       switch (poptArgType(opt)) {
+       case POPT_ARG_INCLUDE_TABLE:    /* Recurse on included sub-tables. */
+       {   const struct poptOption * opt2;
+
+           poptSubstituteHelpI18N(arg.opt);    /* XXX side effects */
+           if (arg.ptr == NULL) continue;      /* XXX program error */
+           opt2 = findOption(arg.opt, longName, longNameLen, shortName, callback,
+                             callbackData, argInfo);
            if (opt2 == NULL) continue;
            /* Sub-table data will be inheirited if no data yet. */
-           if (!(callback && *callback)) return opt2;
-           if (!(callbackData && *callbackData == NULL)) return opt2;
-           /*@-observertrans -dependenttrans @*/
-           *callbackData = opt->descrip;
-           /*@=observertrans =dependenttrans @*/
+           if (callback && *callback
+            && callbackData && *callbackData == NULL)
+               *callbackData = opt->descrip;
            return opt2;
-       } else if ((opt->argInfo & POPT_ARG_MASK) == POPT_ARG_CALLBACK) {
+       }   break;
+       case POPT_ARG_CALLBACK:
            cb = opt;
-       } else if (longName && opt->longName &&
-                  (!singleDash || (opt->argInfo & POPT_ARGFLAG_ONEDASH)) &&
-               /*@-nullpass@*/         /* LCL: opt->longName != NULL */
-                  !strcmp(longName, opt->longName))
-               /*@=nullpass@*/
+           cbarg.ptr = opt->arg;
+           continue;
+           break;
+       default:
+           break;
+       }
+
+       if (longName != NULL && opt->longName != NULL &&
+                  (!LF_ISSET(ONEDASH) || F_ISSET(opt, ONEDASH)) &&
+                  longOptionStrcmp(opt, longName, longNameLen))
        {
            break;
        } else if (shortName && shortName == opt->shortName) {
@@ -529,34 +601,19 @@ findOption(const struct poptOption * opt, /*@null@*/ const char * longName,
        }
     }
 
-    if (!opt->longName && !opt->shortName)
+    if (opt->longName == NULL && !opt->shortName)
        return NULL;
-    /*@-modobserver -mods @*/
-    if (callback) *callback = NULL;
-    if (callbackData) *callbackData = NULL;
-    if (cb) {
-       if (callback)
-       /*@-castfcnptr@*/
-           *callback = (poptCallbackType)cb->arg;
-       /*@=castfcnptr@*/
-       if (!(cb->argInfo & POPT_CBFLAG_INC_DATA)) {
-           if (callbackData)
-               /*@-observertrans@*/    /* FIX: typedef double indirection. */
-               *callbackData = cb->descrip;
-               /*@=observertrans@*/
-       }
-    }
-    /*@=modobserver =mods @*/
+
+    if (callback)
+       *callback = (cb ? cbarg.cb : NULL);
+    if (callbackData)
+       *callbackData = (cb && !CBF_ISSET(cb, INC_DATA) ? cb->descrip : NULL);
 
     return opt;
 }
-/*@=boundswrite@*/
 
-static const char * findNextArg(/*@special@*/ poptContext con,
+static const char * findNextArg(poptContext con,
                unsigned argx, int delete_arg)
-       /*@uses con->optionStack, con->os,
-               con->os->next, con->os->argb, con->os->argc, con->os->argv @*/
-       /*@modifies con @*/
 {
     struct optionStackEntry * os = con->os;
     const char * arg;
@@ -568,151 +625,586 @@ static const char * findNextArg(/*@special@*/ poptContext con,
        if (os->next == os->argc && os == con->optionStack) break;
        if (os->argv != NULL)
        for (i = os->next; i < os->argc; i++) {
-           /*@-sizeoftype@*/
            if (os->argb && PBM_ISSET(i, os->argb))
-               /*@innercontinue@*/ continue;
+               continue;
            if (*os->argv[i] == '-')
-               /*@innercontinue@*/ continue;
+               continue;
            if (--argx > 0)
-               /*@innercontinue@*/ continue;
+               continue;
            arg = os->argv[i];
            if (delete_arg) {
                if (os->argb == NULL) os->argb = PBM_ALLOC(os->argc);
                if (os->argb != NULL)   /* XXX can't happen */
-               PBM_SET(i, os->argb);
+                   PBM_SET(i, os->argb);
            }
-           /*@innerbreak@*/ break;
-           /*@=sizeoftype@*/
+           break;
        }
        if (os > con->optionStack) os--;
     } while (arg == NULL);
     return arg;
 }
 
-/*@-boundswrite@*/
-static /*@only@*/ /*@null@*/ const char *
-expandNextArg(/*@special@*/ poptContext con, const char * s)
-       /*@uses con->optionStack, con->os,
-               con->os->next, con->os->argb, con->os->argc, con->os->argv @*/
-       /*@modifies con @*/
+static const char *
+expandNextArg(poptContext con, const char * s)
 {
     const char * a = NULL;
-    size_t alen, pos;
-    char *t, *te;
+    char *t, *t_tmp, *te;
     size_t tn = strlen(s) + 1;
     char c;
 
-    te = t = malloc(tn);;
+    te = t = malloc(tn);
     if (t == NULL) return NULL;                /* XXX can't happen */
+    *t = '\0';
     while ((c = *s++) != '\0') {
        switch (c) {
 #if 0  /* XXX can't do this */
        case '\\':      /* escape */
            c = *s++;
-           /*@switchbreak@*/ break;
+           break;
 #endif
        case '!':
            if (!(s[0] == '#' && s[1] == ':' && s[2] == '+'))
-               /*@switchbreak@*/ break;
+               break;
            /* XXX Make sure that findNextArg deletes only next arg. */
            if (a == NULL) {
-               if ((a = findNextArg(con, 1, 1)) == NULL)
-                   /*@switchbreak@*/ break;
+               if ((a = findNextArg(con, 1U, 1)) == NULL)
+                   break;
+           }
+           s += sizeof("#:+") - 1;
+
+           tn += strlen(a);
+           {   size_t pos = (size_t) (te - t);
+               if ((t_tmp = realloc(t, tn)) == NULL) { /* XXX can't happen */
+                   free(t);
+                   return NULL;
+               }
+               t = t_tmp;
+               te = stpcpy(t + pos, a);
            }
-           s += 3;
-
-           alen = strlen(a);
-           tn += alen;
-           pos = te - t;
-           t = realloc(t, tn);
-           te = t + pos;
-           memcpy(te, a, alen+1); te += alen;
            continue;
-           /*@notreached@*/ /*@switchbreak@*/ break;
+           break;
        default:
-           /*@switchbreak@*/ break;
+           break;
        }
        *te++ = c;
     }
-    *te = '\0';
-    t = realloc(t, strlen(t) + 1);     /* XXX memory leak, hard to plug */
+    *te++ = '\0';
+    /* If the new string is longer than needed, shorten. */
+    if ((t + tn) > te) {
+       if ((te = realloc(t, (size_t)(te - t))) == NULL)
+           free(t);
+       t = te;
+    }
     return t;
 }
-/*@=boundswrite@*/
 
-static void poptStripArg(/*@special@*/ poptContext con, int which)
-       /*@uses con->arg_strip, con->optionStack @*/
-       /*@defines con->arg_strip @*/
-       /*@modifies con @*/
+static void poptStripArg(poptContext con, int which)
 {
-    /*@-sizeoftype@*/
     if (con->arg_strip == NULL)
        con->arg_strip = PBM_ALLOC(con->optionStack[0].argc);
     if (con->arg_strip != NULL)                /* XXX can't happen */
     PBM_SET(which, con->arg_strip);
-    /*@=sizeoftype@*/
-    /*@-compdef@*/ /* LCL: con->arg_strip udefined? */
     return;
-    /*@=compdef@*/
 }
 
-int poptSaveLong(long * arg, int argInfo, long aLong)
+unsigned int _poptBitsN = _POPT_BITS_N;
+unsigned int _poptBitsM = _POPT_BITS_M;
+unsigned int _poptBitsK = _POPT_BITS_K;
+
+static int _poptBitsNew(poptBits *bitsp)
+{
+    if (bitsp == NULL)
+       return POPT_ERROR_NULLARG;
+
+    /* XXX handle negated initialization. */
+    if (*bitsp == NULL) {
+       if (_poptBitsN == 0) {
+           _poptBitsN = _POPT_BITS_N;
+           _poptBitsM = _POPT_BITS_M;
+       }
+       if (_poptBitsM == 0U) _poptBitsM = (3 * _poptBitsN) / 2;
+       if (_poptBitsK == 0U || _poptBitsK > 32U) _poptBitsK = _POPT_BITS_K;
+       *bitsp = PBM_ALLOC(_poptBitsM-1);
+    }
+    return 0;
+}
+
+int poptBitsAdd(poptBits bits, const char * s)
+{
+    size_t ns = (s ? strlen(s) : 0);
+    uint32_t h0 = 0;
+    uint32_t h1 = 0;
+
+    if (bits == NULL || ns == 0)
+       return POPT_ERROR_NULLARG;
+
+    poptJlu32lpair(s, ns, &h0, &h1);
+
+    for (ns = 0; ns < (size_t)_poptBitsK; ns++) {
+        uint32_t h = h0 + ns * h1;
+        uint32_t ix = (h % _poptBitsM);
+        PBM_SET(ix, bits);
+    }
+    return 0;
+}
+
+int poptBitsChk(poptBits bits, const char * s)
+{
+    size_t ns = (s ? strlen(s) : 0);
+    uint32_t h0 = 0;
+    uint32_t h1 = 0;
+    int rc = 1;
+
+    if (bits == NULL || ns == 0)
+       return POPT_ERROR_NULLARG;
+
+    poptJlu32lpair(s, ns, &h0, &h1);
+
+    for (ns = 0; ns < (size_t)_poptBitsK; ns++) {
+        uint32_t h = h0 + ns * h1;
+        uint32_t ix = (h % _poptBitsM);
+        if (PBM_ISSET(ix, bits))
+            continue;
+        rc = 0;
+        break;
+    }
+    return rc;
+}
+
+int poptBitsClr(poptBits bits)
+{
+    static size_t nbw = (__PBM_NBITS/8);
+    size_t nw = (__PBM_IX(_poptBitsM-1) + 1);
+
+    if (bits == NULL)
+       return POPT_ERROR_NULLARG;
+    memset(bits, 0, nw * nbw);
+    return 0;
+}
+
+int poptBitsDel(poptBits bits, const char * s)
+{
+    size_t ns = (s ? strlen(s) : 0);
+    uint32_t h0 = 0;
+    uint32_t h1 = 0;
+
+    if (bits == NULL || ns == 0)
+       return POPT_ERROR_NULLARG;
+
+    poptJlu32lpair(s, ns, &h0, &h1);
+
+    for (ns = 0; ns < (size_t)_poptBitsK; ns++) {
+        uint32_t h = h0 + ns * h1;
+        uint32_t ix = (h % _poptBitsM);
+        PBM_CLR(ix, bits);
+    }
+    return 0;
+}
+
+int poptBitsIntersect(poptBits *ap, const poptBits b)
+{
+    __pbm_bits *abits;
+    __pbm_bits *bbits;
+    __pbm_bits rc = 0;
+    size_t nw = (__PBM_IX(_poptBitsM-1) + 1);
+    size_t i;
+
+    if (ap == NULL || b == NULL || _poptBitsNew(ap))
+       return POPT_ERROR_NULLARG;
+    abits = __PBM_BITS(*ap);
+    bbits = __PBM_BITS(b);
+
+    for (i = 0; i < nw; i++) {
+        abits[i] &= bbits[i];
+       rc |= abits[i];
+    }
+    return (rc ? 1 : 0);
+}
+
+int poptBitsUnion(poptBits *ap, const poptBits b)
+{
+    __pbm_bits *abits;
+    __pbm_bits *bbits;
+    __pbm_bits rc = 0;
+    size_t nw = (__PBM_IX(_poptBitsM-1) + 1);
+    size_t i;
+
+    if (ap == NULL || b == NULL || _poptBitsNew(ap))
+       return POPT_ERROR_NULLARG;
+    abits = __PBM_BITS(*ap);
+    bbits = __PBM_BITS(b);
+
+    for (i = 0; i < nw; i++) {
+        abits[i] |= bbits[i];
+       rc |= abits[i];
+    }
+    return (rc ? 1 : 0);
+}
+
+int poptBitsArgs(poptContext con, poptBits *ap)
+{
+    const char ** av;
+    int rc = 0;
+
+    if (con == NULL || ap == NULL || _poptBitsNew(ap) ||
+       con->leftovers == NULL || con->numLeftovers == con->nextLeftover)
+       return POPT_ERROR_NULLARG;
+
+    /* some apps like [like RPM ;-) ] need this NULL terminated */
+    con->leftovers[con->numLeftovers] = NULL;
+
+    for (av = con->leftovers + con->nextLeftover; *av != NULL; av++) {
+       if ((rc = poptBitsAdd(*ap, *av)) != 0)
+           break;
+    }
+    return rc;
+}
+
+int poptSaveBits(poptBits * bitsp,
+               UNUSED(unsigned int argInfo), const char * s)
+{
+    char *tbuf = NULL;
+    char *t, *te;
+    int rc = 0;
+
+    if (bitsp == NULL || s == NULL || *s == '\0' || _poptBitsNew(bitsp))
+       return POPT_ERROR_NULLARG;
+
+    /* Parse comma separated attributes. */
+    te = tbuf = xstrdup(s);
+    while ((t = te) != NULL && *t) {
+       while (*te != '\0' && *te != ',')
+           te++;
+       if (*te != '\0')
+           *te++ = '\0';
+       /* XXX Ignore empty strings. */
+       if (*t == '\0')
+           continue;
+       /* XXX Permit negated attributes. caveat emptor: false negatives. */
+       if (*t == '!') {
+           t++;
+           if ((rc = poptBitsChk(*bitsp, t)) > 0)
+               rc = poptBitsDel(*bitsp, t);
+       } else
+           rc = poptBitsAdd(*bitsp, t);
+       if (rc)
+           break;
+    }
+    tbuf = _free(tbuf);
+    return rc;
+}
+
+int poptSaveString(const char *** argvp,
+               UNUSED(unsigned int argInfo), const char * val)
+{
+    int argc = 0;
+
+    if (argvp == NULL || val == NULL)
+       return POPT_ERROR_NULLARG;
+
+    /* XXX likely needs an upper bound on argc. */
+    if (*argvp != NULL)
+    while ((*argvp)[argc] != NULL)
+       argc++;
+    if ((*argvp = xrealloc(*argvp, (argc + 1 + 1) * sizeof(**argvp))) != NULL) {
+       (*argvp)[argc++] = xstrdup(val);
+       (*argvp)[argc  ] = NULL;
+    }
+    return 0;
+}
+
+static long long poptRandomValue(long long limit)
+{
+#if defined(HAVE_SRANDOM)
+    static int seed = 1;
+
+    if (seed) {
+       srandom((unsigned)getpid());
+       srandom((unsigned)random());
+       seed = 0;
+    }
+
+    return random() % limit + 1;
+#else
+    /* XXX avoid adding POPT_ERROR_UNIMPLEMENTED to minimize i18n churn. */
+    return POPT_ERROR_BADOPERATION;
+#endif
+}
+
+int poptSaveLongLong(long long * arg, unsigned int argInfo, long long aLongLong)
 {
     /* XXX Check alignment, may fail on funky platforms. */
-    if (arg == NULL || (((unsigned long)arg) & (sizeof(*arg)-1)))
+    if (arg == NULL || (((unsigned long)arg) & (ALIGNOF(*arg)-1)))
        return POPT_ERROR_NULLARG;
 
-    if (argInfo & POPT_ARGFLAG_NOT)
-       aLong = ~aLong;
-    switch (argInfo & POPT_ARGFLAG_LOGICALOPS) {
+    if (aLongLong != 0 && LF_ISSET(RANDOM)) {
+       aLongLong = poptRandomValue(aLongLong);
+       if (aLongLong < 0)
+           return aLongLong;
+    }
+    if (LF_ISSET(NOT))
+       aLongLong = ~aLongLong;
+    switch (LF_ISSET(LOGICALOPS)) {
     case 0:
-       *arg = aLong;
+       *arg = aLongLong;
        break;
     case POPT_ARGFLAG_OR:
-       *arg |= aLong;
+       *(unsigned long long *)arg |= (unsigned long long)aLongLong;
        break;
     case POPT_ARGFLAG_AND:
-       *arg &= aLong;
+       *(unsigned long long *)arg &= (unsigned long long)aLongLong;
        break;
     case POPT_ARGFLAG_XOR:
-       *arg ^= aLong;
+       *(unsigned long long *)arg ^= (unsigned long long)aLongLong;
        break;
     default:
        return POPT_ERROR_BADOPERATION;
-       /*@notreached@*/ break;
+       break;
     }
     return 0;
 }
 
-int poptSaveInt(/*@null@*/ int * arg, int argInfo, long aLong)
+int poptSaveLong(long * arg, unsigned int argInfo, long aLong)
 {
     /* XXX Check alignment, may fail on funky platforms. */
-    if (arg == NULL || (((unsigned long)arg) & (sizeof(*arg)-1)))
+    if (arg == NULL || (((unsigned long)arg) & (ALIGNOF(*arg)-1)))
        return POPT_ERROR_NULLARG;
 
-    if (argInfo & POPT_ARGFLAG_NOT)
+    if (aLong != 0 && LF_ISSET(RANDOM)) {
+       aLong = (long)poptRandomValue(aLong);
+       if (aLong < 0)
+           return aLong;
+    }
+    if (LF_ISSET(NOT))
        aLong = ~aLong;
-    switch (argInfo & POPT_ARGFLAG_LOGICALOPS) {
-    case 0:
-       *arg = aLong;
+    switch (LF_ISSET(LOGICALOPS)) {
+    case 0:               *arg = aLong; break;
+    case POPT_ARGFLAG_OR:  *(unsigned long *)arg |= (unsigned long)aLong; break;
+    case POPT_ARGFLAG_AND: *(unsigned long *)arg &= (unsigned long)aLong; break;
+    case POPT_ARGFLAG_XOR: *(unsigned long *)arg ^= (unsigned long)aLong; break;
+    default:
+       return POPT_ERROR_BADOPERATION;
        break;
-    case POPT_ARGFLAG_OR:
-       *arg |= aLong;
+    }
+    return 0;
+}
+
+int poptSaveInt(int * arg, unsigned int argInfo, long aLong)
+{
+    /* XXX Check alignment, may fail on funky platforms. */
+    if (arg == NULL || (((unsigned long)arg) & (ALIGNOF(*arg)-1)))
+       return POPT_ERROR_NULLARG;
+
+    if (aLong != 0 && LF_ISSET(RANDOM)) {
+       aLong = (int)poptRandomValue(aLong);
+       if (aLong < 0)
+           return aLong;
+    }
+    if (LF_ISSET(NOT))
+       aLong = ~aLong;
+    switch (LF_ISSET(LOGICALOPS)) {
+    case 0:               *arg = (int) aLong;                          break;
+    case POPT_ARGFLAG_OR:  *(unsigned int *)arg |= (unsigned int) aLong; break;
+    case POPT_ARGFLAG_AND: *(unsigned int *)arg &= (unsigned int) aLong; break;
+    case POPT_ARGFLAG_XOR: *(unsigned int *)arg ^= (unsigned int) aLong; break;
+    default:
+       return POPT_ERROR_BADOPERATION;
        break;
-    case POPT_ARGFLAG_AND:
-       *arg &= aLong;
+    }
+    return 0;
+}
+
+int poptSaveShort(short * arg, unsigned int argInfo, long aLong)
+{
+    /* XXX Check alignment, may fail on funky platforms. */
+    if (arg == NULL || (((unsigned long)arg) & (ALIGNOF(*arg)-1)))
+       return POPT_ERROR_NULLARG;
+
+    if (aLong != 0 && LF_ISSET(RANDOM)) {
+       aLong = (short)poptRandomValue(aLong);
+       if (aLong < 0)
+           return aLong;
+    }
+    if (LF_ISSET(NOT))
+       aLong = ~aLong;
+    switch (LF_ISSET(LOGICALOPS)) {
+    case 0:               *arg = (short) aLong;
        break;
-    case POPT_ARGFLAG_XOR:
-       *arg ^= aLong;
+    case POPT_ARGFLAG_OR:  *(unsigned short *)arg |= (unsigned short) aLong;
+       break;
+    case POPT_ARGFLAG_AND: *(unsigned short *)arg &= (unsigned short) aLong;
+       break;
+    case POPT_ARGFLAG_XOR: *(unsigned short *)arg ^= (unsigned short) aLong;
+       break;
+    default: return POPT_ERROR_BADOPERATION;
        break;
-    default:
-       return POPT_ERROR_BADOPERATION;
-       /*@notreached@*/ break;
     }
     return 0;
 }
 
-/*@-boundswrite@*/
+/**
+ * Return argInfo field, handling POPT_ARGFLAG_TOGGLE overrides.
+ * @param con          context
+ * @param opt           option
+ * @return             argInfo
+ */
+static unsigned int poptArgInfo(poptContext con, const struct poptOption * opt)
+{
+    unsigned int argInfo = opt->argInfo;
+
+    if (con->os->argv != NULL && con->os->next > 0 && opt->longName != NULL)
+    if (LF_ISSET(TOGGLE)) {
+       const char * longName = con->os->argv[con->os->next-1];
+       while (*longName == '-') longName++;
+       /* XXX almost good enough but consider --[no]nofoo corner cases. */
+       if (longName[0] != opt->longName[0] || longName[1] != opt->longName[1])
+       {
+           if (!LF_ISSET(XOR)) {       /* XXX dont toggle with XOR */
+               /* Toggle POPT_BIT_SET <=> POPT_BIT_CLR. */
+               if (LF_ISSET(LOGICALOPS))
+                   argInfo ^= (POPT_ARGFLAG_OR|POPT_ARGFLAG_AND);
+               argInfo ^= POPT_ARGFLAG_NOT;
+           }
+       }
+    }
+    return argInfo;
+}
+
+/**
+ * Parse an integer expression.
+ * @retval *llp                integer expression value
+ * @param argInfo      integer expression type
+ * @param val          integer expression string
+ * @return             0 on success, otherwise POPT_* error.
+ */
+static int poptParseInteger(long long * llp,
+               UNUSED(unsigned int argInfo),
+               const char * val)
+{
+    if (val) {
+       char *end = NULL;
+       *llp = strtoll(val, &end, 0);
+
+       /* XXX parse scaling suffixes here. */
+
+       if (!(end && *end == '\0'))
+           return POPT_ERROR_BADNUMBER;
+    } else
+       *llp = 0;
+    return 0;
+}
+
+/**
+ * Save the option argument through the (*opt->arg) pointer.
+ * @param con          context
+ * @param opt           option
+ * @return             0 on success, otherwise POPT_* error.
+ */
+static int poptSaveArg(poptContext con, const struct poptOption * opt)
+{
+    poptArg arg = { .ptr = opt->arg };
+    int rc = 0;                /* assume success */
+
+    switch (poptArgType(opt)) {
+    case POPT_ARG_BITSET:
+       /* XXX memory leak, application is responsible for free. */
+       rc = poptSaveBits(arg.ptr, opt->argInfo, con->os->nextArg);
+       break;
+    case POPT_ARG_ARGV:
+       /* XXX memory leak, application is responsible for free. */
+       rc = poptSaveString(arg.ptr, opt->argInfo, con->os->nextArg);
+       break;
+    case POPT_ARG_STRING:
+       /* XXX memory leak, application is responsible for free. */
+       arg.argv[0] = (con->os->nextArg) ? xstrdup(con->os->nextArg) : NULL;
+       break;
+
+    case POPT_ARG_INT:
+    case POPT_ARG_SHORT:
+    case POPT_ARG_LONG:
+    case POPT_ARG_LONGLONG:
+    {  unsigned int argInfo = poptArgInfo(con, opt);
+       long long aNUM = 0;
+
+       if ((rc = poptParseInteger(&aNUM, argInfo, con->os->nextArg)) != 0)
+           break;
+
+       switch (poptArgType(opt)) {
+       case POPT_ARG_LONGLONG:
+/* XXX let's not demand C99 compiler flags for <limits.h> quite yet. */
+#if !defined(LLONG_MAX)
+#   define LLONG_MAX    9223372036854775807LL
+#   define LLONG_MIN    (-LLONG_MAX - 1LL)
+#endif
+           rc = !(aNUM == LLONG_MIN || aNUM == LLONG_MAX)
+               ? poptSaveLongLong(arg.longlongp, argInfo, aNUM)
+               : POPT_ERROR_OVERFLOW;
+           break;
+       case POPT_ARG_LONG:
+           rc = !(aNUM < (long long)LONG_MIN || aNUM > (long long)LONG_MAX)
+               ? poptSaveLong(arg.longp, argInfo, (long)aNUM)
+               : POPT_ERROR_OVERFLOW;
+           break;
+       case POPT_ARG_INT:
+           rc = !(aNUM < (long long)INT_MIN || aNUM > (long long)INT_MAX)
+               ? poptSaveInt(arg.intp, argInfo, (long)aNUM)
+               : POPT_ERROR_OVERFLOW;
+           break;
+       case POPT_ARG_SHORT:
+           rc = !(aNUM < (long long)SHRT_MIN || aNUM > (long long)SHRT_MAX)
+               ? poptSaveShort(arg.shortp, argInfo, (long)aNUM)
+               : POPT_ERROR_OVERFLOW;
+           break;
+       }
+    }   break;
+
+    case POPT_ARG_FLOAT:
+    case POPT_ARG_DOUBLE:
+    {  char *end = NULL;
+       double aDouble = 0.0;
+
+       if (con->os->nextArg) {
+           int saveerrno = errno;
+           errno = 0;
+           aDouble = strtod(con->os->nextArg, &end);
+           if (errno == ERANGE) {
+               rc = POPT_ERROR_OVERFLOW;
+               break;
+           }
+           errno = saveerrno;
+           if (*end != '\0') {
+               rc = POPT_ERROR_BADNUMBER;
+               break;
+           }
+       }
+
+       switch (poptArgType(opt)) {
+       case POPT_ARG_DOUBLE:
+           arg.doublep[0] = aDouble;
+           break;
+       case POPT_ARG_FLOAT:
+#define POPT_ABS(a)    ((((a) - 0.0) < DBL_EPSILON) ? -(a) : (a))
+           if ((FLT_MIN - POPT_ABS(aDouble)) > DBL_EPSILON
+            || (POPT_ABS(aDouble) - FLT_MAX) > DBL_EPSILON)
+               rc = POPT_ERROR_OVERFLOW;
+           else
+               arg.floatp[0] = (float) aDouble;
+           break;
+       }
+    }   break;
+    case POPT_ARG_MAINCALL:
+       con->maincall = opt->arg;
+       break;
+    default:
+       fprintf(stdout, POPT_("option type (%u) not implemented in popt\n"),
+               poptArgType(opt));
+       exit(EXIT_FAILURE);
+       break;
+    }
+    return rc;
+}
+
 /* returns 'val' element, -1 on last item, POPT_ERROR_* on error */
 int poptGetNextOpt(poptContext con)
 {
@@ -734,24 +1226,27 @@ int poptGetNextOpt(poptContext con)
            cleanOSE(con->os--);
        }
        if (!con->os->nextCharArg && con->os->next == con->os->argc) {
-           /*@-internalglobs@*/
            invokeCallbacksPOST(con, con->options);
-           /*@=internalglobs@*/
+
+           if (con->maincall) {
+               (void) (*con->maincall) (con->finalArgvCount, con->finalArgv);
+               return -1;
+           }
+
            if (con->doExec) return execCommand(con);
            return -1;
        }
 
        /* Process next long option */
        if (!con->os->nextCharArg) {
-           char * localOptString, * optString;
+           const char * optString;
+            size_t optStringLen;
            int thisopt;
 
-           /*@-sizeoftype@*/
            if (con->os->argb && PBM_ISSET(con->os->next, con->os->argb)) {
                con->os->next++;
                continue;
            }
-           /*@=sizeoftype@*/
            thisopt = con->os->next;
            if (con->os->argv != NULL)  /* XXX can't happen */
            origOptString = con->os->argv[con->os->next++];
@@ -759,25 +1254,35 @@ int poptGetNextOpt(poptContext con)
            if (origOptString == NULL)  /* XXX can't happen */
                return POPT_ERROR_BADOPT;
 
-           if (con->restLeftover || *origOptString != '-') {
+           if (con->restLeftover || *origOptString != '-' ||
+               (*origOptString == '-' && origOptString[1] == '\0'))
+           {
                if (con->flags & POPT_CONTEXT_POSIXMEHARDER)
                    con->restLeftover = 1;
                if (con->flags & POPT_CONTEXT_ARG_OPTS) {
                    con->os->nextArg = xstrdup(origOptString);
                    return 0;
                }
-               if (con->leftovers != NULL)     /* XXX can't happen */
-                   con->leftovers[con->numLeftovers++] = origOptString;
+               if (con->leftovers != NULL) {   /* XXX can't happen */
+                   /* One might think we can never overflow the leftovers
+                      array.  Actually, that's true, as long as you don't
+                      use poptStuffArgs()... */
+                   if ((con->numLeftovers + 1) >= (con->allocLeftovers)) {
+                       con->allocLeftovers += 10;
+                       con->leftovers =
+                           realloc(con->leftovers,
+                                   sizeof(*con->leftovers) * con->allocLeftovers);
+                   }
+                   con->leftovers[con->numLeftovers++]
+                       = xstrdup(origOptString); /* so a free of a stuffed
+                                                    argv doesn't give us a
+                                                    dangling pointer */
+               }
                continue;
            }
 
            /* Make a copy we can hack at */
-           {   size_t bufsize = strlen(origOptString) + 1;
-               localOptString = optString = alloca(bufsize);
-               if (optString == NULL) /* XXX can't happen */
-                   return POPT_ERROR_BADOPT;
-               strlcpy(optString, origOptString, bufsize);
-           }
+           optString = origOptString;
 
            if (optString[0] == '\0')
                return POPT_ERROR_BADOPT;
@@ -786,46 +1291,42 @@ int poptGetNextOpt(poptContext con)
                con->restLeftover = 1;
                continue;
            } else {
-               char *oe;
-               int singleDash;
+               const char *oe;
+               unsigned int argInfo = 0;
 
                optString++;
                if (*optString == '-')
-                   singleDash = 0, optString++;
+                   optString++;
                else
-                   singleDash = 1;
+                   argInfo |= POPT_ARGFLAG_ONEDASH;
+
+               /* Check for "--long=arg" option. */
+               for (oe = optString; *oe && *oe != '='; oe++)
+                   {};
+               optStringLen = (size_t)(oe - optString);
+               if (*oe == '=')
+                   longArg = oe + 1;
 
                /* XXX aliases with arg substitution need "--alias=arg" */
-               if (handleAlias(con, optString, '\0', NULL))
+               if (handleAlias(con, optString, optStringLen, '\0', longArg)) {
+                   longArg = NULL;
                    continue;
+               }
 
                if (handleExec(con, optString, '\0'))
                    continue;
 
-               /* Check for "--long=arg" option. */
-               for (oe = optString; *oe && *oe != '='; oe++)
-                   {};
-               if (*oe == '=') {
-                   *oe++ = '\0';
-                   /* XXX longArg is mapped back to persistent storage. */
-                   longArg = origOptString + (oe - localOptString);
-               } else
-                   oe = NULL;
-
-               opt = findOption(con->options, optString, '\0', &cb, &cbData,
-                                singleDash);
-               if (!opt && !singleDash)
+               opt = findOption(con->options, optString, optStringLen, '\0', &cb, &cbData,
+                                argInfo);
+               if (!opt && !LF_ISSET(ONEDASH))
                    return POPT_ERROR_BADOPT;
-               if (!opt && oe)
-                   oe[-1] = '='; /* restore overwritten '=' */
            }
 
            if (!opt) {
                con->os->nextCharArg = origOptString + 1;
                longArg = NULL;
            } else {
-               if (con->os == con->optionStack &&
-                  opt->argInfo & POPT_ARGFLAG_STRIP)
+               if (con->os == con->optionStack && F_ISSET(opt, STRIP))
                {
                    canstrip = 1;
                    poptStripArg(con, thisopt);
@@ -835,66 +1336,63 @@ int poptGetNextOpt(poptContext con)
        }
 
        /* Process next short option */
-       /*@-branchstate@*/              /* FIX: W2DO? */
        if (con->os->nextCharArg) {
-           origOptString = con->os->nextCharArg;
+           const char * nextCharArg = con->os->nextCharArg;
 
            con->os->nextCharArg = NULL;
 
-           if (handleAlias(con, NULL, *origOptString, origOptString + 1))
+           if (handleAlias(con, NULL, 0, *nextCharArg, nextCharArg + 1))
                continue;
 
-           if (handleExec(con, NULL, *origOptString)) {
+           if (handleExec(con, NULL, *nextCharArg)) {
                /* Restore rest of short options for further processing */
-               origOptString++;
-               if (*origOptString != '\0')
-                   con->os->nextCharArg = origOptString;
+               nextCharArg++;
+               if (*nextCharArg != '\0')
+                   con->os->nextCharArg = nextCharArg;
                continue;
            }
 
-           opt = findOption(con->options, NULL, *origOptString, &cb,
+           opt = findOption(con->options, NULL, 0, *nextCharArg, &cb,
                             &cbData, 0);
            if (!opt)
                return POPT_ERROR_BADOPT;
            shorty = 1;
 
-           origOptString++;
-           if (*origOptString != '\0')
-               con->os->nextCharArg = origOptString;
+           nextCharArg++;
+           if (*nextCharArg != '\0')
+               con->os->nextCharArg = nextCharArg;
        }
-       /*@=branchstate@*/
 
        if (opt == NULL) return POPT_ERROR_BADOPT;      /* XXX can't happen */
-       if ((opt->argInfo & POPT_ARG_MASK) == POPT_ARG_NONE
-        || (opt->argInfo & POPT_ARG_MASK) == POPT_ARG_VAL) {
+       if (poptArgType(opt) == POPT_ARG_NONE || poptArgType(opt) == POPT_ARG_VAL) {
            if (longArg || (con->os->nextCharArg && con->os->nextCharArg[0] == '='))
                return POPT_ERROR_UNWANTEDARG;
            if (opt->arg) {
-               long val = (opt->argInfo & POPT_ARG_MASK) == POPT_ARG_VAL ? opt->val : 1;
-               if (poptSaveInt((int *)opt->arg, opt->argInfo, val))
+               long val = poptArgType(opt) == POPT_ARG_VAL ? opt->val : 1;
+               unsigned int argInfo = poptArgInfo(con, opt);
+               if (poptSaveInt((int *)opt->arg, argInfo, val))
                    return POPT_ERROR_BADOPERATION;
            }
        } else {
+           int rc;
+
            con->os->nextArg = _free(con->os->nextArg);
-           /*@-usedef@*/       /* FIX: W2DO? */
            if (longArg) {
-           /*@=usedef@*/
                longArg = expandNextArg(con, longArg);
-               con->os->nextArg = longArg;
+               con->os->nextArg = (char *) longArg;
            } else if (con->os->nextCharArg) {
-               longArg = expandNextArg(con, con->os->nextCharArg + (con->os->nextCharArg[0] == '='));
-               con->os->nextArg = longArg;
+               longArg = expandNextArg(con, con->os->nextCharArg + (int)(*con->os->nextCharArg == '='));
+               con->os->nextArg = (char *) longArg;
                con->os->nextCharArg = NULL;
            } else {
                while (con->os->next == con->os->argc &&
-                      con->os > con->optionStack) {
+                       con->os > con->optionStack)
+               {
                    cleanOSE(con->os--);
                }
                if (con->os->next == con->os->argc) {
-                   if (!(opt->argInfo & POPT_ARGFLAG_OPTIONAL))
-                       /*@-compdef@*/  /* FIX: con->os->argv not defined */
+                   if (!F_ISSET(opt, OPTIONAL))
                        return POPT_ERROR_NOARG;
-                       /*@=compdef@*/
                    con->os->nextArg = NULL;
                } else {
 
@@ -902,98 +1400,35 @@ int poptGetNextOpt(poptContext con)
                     * Make sure this isn't part of a short arg or the
                     * result of an alias expansion.
                     */
-                   if (con->os == con->optionStack &&
-                       (opt->argInfo & POPT_ARGFLAG_STRIP) &&
-                       canstrip) {
+                   if (con->os == con->optionStack
+                    && F_ISSET(opt, STRIP) && canstrip)
+                   {
                        poptStripArg(con, con->os->next);
                    }
                
                    if (con->os->argv != NULL) {        /* XXX can't happen */
-                       /* XXX watchout: subtle side-effects live here. */
-                       longArg = con->os->argv[con->os->next++];
-                       longArg = expandNextArg(con, longArg);
-                       con->os->nextArg = longArg;
+                       if (F_ISSET(opt, OPTIONAL) &&
+                           con->os->argv[con->os->next][0] == '-') {
+                           con->os->nextArg = NULL;
+                       } else {
+                           /* XXX watchout: subtle side-effects live here. */
+                           longArg = con->os->argv[con->os->next++];
+                           longArg = expandNextArg(con, longArg);
+                           con->os->nextArg = (char *) longArg;
+                       }
                    }
                }
            }
            longArg = NULL;
 
-           if (opt->arg) {
-               switch (opt->argInfo & POPT_ARG_MASK) {
-               case POPT_ARG_STRING:
-                   /* XXX memory leak, hard to plug */
-                   *((const char **) opt->arg) = (con->os->nextArg)
-                       ? xstrdup(con->os->nextArg) : NULL;
-                   /*@switchbreak@*/ break;
-
-               case POPT_ARG_INT:
-               case POPT_ARG_LONG:
-               {   long aLong = 0;
-                   char *end;
-
-                   if (con->os->nextArg) {
-                       aLong = strtol(con->os->nextArg, &end, 0);
-                       if (!(end && *end == '\0'))
-                           return POPT_ERROR_BADNUMBER;
-                   }
-
-                   if ((opt->argInfo & POPT_ARG_MASK) == POPT_ARG_LONG) {
-                       if (aLong == LONG_MIN || aLong == LONG_MAX)
-                           return POPT_ERROR_OVERFLOW;
-                       if (poptSaveLong((long *)opt->arg, opt->argInfo, aLong))
-                           return POPT_ERROR_BADOPERATION;
-                   } else {
-                       if (aLong > INT_MAX || aLong < INT_MIN)
-                           return POPT_ERROR_OVERFLOW;
-                       if (poptSaveInt((int *)opt->arg, opt->argInfo, aLong))
-                           return POPT_ERROR_BADOPERATION;
-                   }
-               }   /*@switchbreak@*/ break;
-
-               case POPT_ARG_FLOAT:
-               case POPT_ARG_DOUBLE:
-               {   double aDouble = 0.0;
-                   char *end;
-
-                   if (con->os->nextArg) {
-                       /*@-mods@*/
-                       int saveerrno = errno;
-                       errno = 0;
-                       aDouble = strtod(con->os->nextArg, &end);
-                       if (errno == ERANGE)
-                           return POPT_ERROR_OVERFLOW;
-                       errno = saveerrno;
-                       /*@=mods@*/
-                       if (*end != '\0')
-                           return POPT_ERROR_BADNUMBER;
-                   }
-
-                   if ((opt->argInfo & POPT_ARG_MASK) == POPT_ARG_DOUBLE) {
-                       *((double *) opt->arg) = aDouble;
-                   } else {
-#define MY_ABS(a) ((((a) - 0.0) < DBL_EPSILON) ? -(a) : (a))
-                       if ((MY_ABS(aDouble) - FLT_MAX) > DBL_EPSILON)
-                           return POPT_ERROR_OVERFLOW;
-                       if ((FLT_MIN - MY_ABS(aDouble)) > DBL_EPSILON)
-                           return POPT_ERROR_OVERFLOW;
-                       *((float *) opt->arg) = aDouble;
-                   }
-               }   /*@switchbreak@*/ break;
-               default:
-                   fprintf(stdout,
-                       POPT_("option type (%d) not implemented in popt\n"),
-                       (opt->argInfo & POPT_ARG_MASK));
-                   exit(EXIT_FAILURE);
-                   /*@notreached@*/ /*@switchbreak@*/ break;
-               }
-           }
+          /* Save the option argument through a (*opt->arg) pointer. */
+           if (opt->arg != NULL && (rc = poptSaveArg(con, opt)) != 0)
+               return rc;
        }
 
-       if (cb) {
-           /*@-internalglobs@*/
+       if (cb)
            invokeCallbacksOPTION(con, con->options, opt, cbData, shorty);
-           /*@=internalglobs@*/
-       } else if (opt->val && ((opt->argInfo & POPT_ARG_MASK) != POPT_ARG_VAL))
+       else if (opt->val && (poptArgType(opt) != POPT_ARG_VAL))
            done = 1;
 
        if ((con->finalArgvCount + 2) >= (con->finalArgvAlloced)) {
@@ -1003,46 +1438,43 @@ int poptGetNextOpt(poptContext con)
        }
 
        if (con->finalArgv != NULL)
-       {   ssize_t bufsize = (opt->longName ? strlen(opt->longName) : 0) + 3;
-           char *s = malloc(bufsize);
+       {   char *s = malloc((opt->longName ? strlen(opt->longName) : 0) + sizeof("--"));
            if (s != NULL) {    /* XXX can't happen */
-               if (opt->longName)
-                   snprintf(s, bufsize, "%s%s",
-                       ((opt->argInfo & POPT_ARGFLAG_ONEDASH) ? "-" : "--"),
-                       opt->longName);
-               else
-                   snprintf(s, bufsize, "-%c", opt->shortName);
                con->finalArgv[con->finalArgvCount++] = s;
+               *s++ = '-';
+               if (opt->longName) {
+                   if (!F_ISSET(opt, ONEDASH))
+                       *s++ = '-';
+                   s = stpcpy(s, opt->longName);
+               } else {
+                   *s++ = opt->shortName;
+                   *s = '\0';
+               }
            } else
                con->finalArgv[con->finalArgvCount++] = NULL;
        }
 
-       if (opt->arg && (opt->argInfo & POPT_ARG_MASK) == POPT_ARG_NONE)
-           /*@-ifempty@*/ ; /*@=ifempty@*/
-       else if ((opt->argInfo & POPT_ARG_MASK) == POPT_ARG_VAL)
-           /*@-ifempty@*/ ; /*@=ifempty@*/
-       else if ((opt->argInfo & POPT_ARG_MASK) != POPT_ARG_NONE) {
-           if (con->finalArgv != NULL && con->os->nextArg)
+       if (opt->arg && poptArgType(opt) == POPT_ARG_NONE)
+           ;
+       else if (poptArgType(opt) == POPT_ARG_VAL)
+           ;
+       else if (poptArgType(opt) != POPT_ARG_NONE) {
+           if (con->finalArgv != NULL && con->os->nextArg != NULL)
                con->finalArgv[con->finalArgvCount++] =
-                       /*@-nullpass@*/ /* LCL: con->os->nextArg != NULL */
                        xstrdup(con->os->nextArg);
-                       /*@=nullpass@*/
        }
     }
 
     return (opt ? opt->val : -1);      /* XXX can't happen */
 }
-/*@=boundswrite@*/
 
-const char * poptGetOptArg(poptContext con)
+char * poptGetOptArg(poptContext con)
 {
-    const char * ret = NULL;
-    /*@-branchstate@*/
+    char * ret = NULL;
     if (con) {
        ret = con->os->nextArg;
        con->os->nextArg = NULL;
     }
-    /*@=branchstate@*/
     return ret;
 }
 
@@ -1062,7 +1494,6 @@ const char * poptPeekArg(poptContext con)
     return ret;
 }
 
-/*@-boundswrite@*/
 const char ** poptGetArgs(poptContext con)
 {
     if (con == NULL ||
@@ -1072,46 +1503,44 @@ const char ** poptGetArgs(poptContext con)
     /* some apps like [like RPM ;-) ] need this NULL terminated */
     con->leftovers[con->numLeftovers] = NULL;
 
-    /*@-nullret -nullstate @*/ /* FIX: typedef double indirection. */
     return (con->leftovers + con->nextLeftover);
-    /*@=nullret =nullstate @*/
 }
-/*@=boundswrite@*/
+
+static
+poptItem poptFreeItems(poptItem items, int nitems)
+{
+    if (items != NULL) {
+       poptItem item = items;
+       while (--nitems >= 0) {
+           item->option.longName = _free(item->option.longName);
+           item->option.descrip = _free(item->option.descrip);
+           item->option.argDescrip = _free(item->option.argDescrip);
+           item->argv = _free(item->argv);
+           item++;
+       }
+       _free(items);
+    }
+    return NULL;
+}
 
 poptContext poptFreeContext(poptContext con)
 {
-    poptItem item;
     int i;
 
     if (con == NULL) return con;
     poptResetContext(con);
-    con->os->argb = _free(con->os->argb);
 
-    if (con->aliases != NULL)
-    for (i = 0; i < con->numAliases; i++) {
-       item = con->aliases + i;
-       /*@-modobserver -observertrans -dependenttrans@*/
-       item->option.longName = _free(item->option.longName);
-       item->option.descrip = _free(item->option.descrip);
-       item->option.argDescrip = _free(item->option.argDescrip);
-       /*@=modobserver =observertrans =dependenttrans@*/
-       item->argv = _free(item->argv);
-    }
-    con->aliases = _free(con->aliases);
+    con->aliases = poptFreeItems(con->aliases, con->numAliases);
+    con->numAliases = 0;
 
-    if (con->execs != NULL)
-    for (i = 0; i < con->numExecs; i++) {
-       item = con->execs + i;
-       /*@-modobserver -observertrans -dependenttrans@*/
-       item->option.longName = _free(item->option.longName);
-       item->option.descrip = _free(item->option.descrip);
-       item->option.argDescrip = _free(item->option.argDescrip);
-       /*@=modobserver =observertrans =dependenttrans@*/
-       item->argv = _free(item->argv);
-    }
-    con->execs = _free(con->execs);
+    con->execs = poptFreeItems(con->execs, con->numExecs);
+    con->numExecs = 0;
 
+    for (i = 0; i < con->numLeftovers; i++) {
+        con->leftovers[i] = _free(con->leftovers[i]);
+    }
     con->leftovers = _free(con->leftovers);
+
     con->finalArgv = _free(con->finalArgv);
     con->appName = _free(con->appName);
     con->otherHelp = _free(con->otherHelp);
@@ -1123,9 +1552,10 @@ poptContext poptFreeContext(poptContext con)
 }
 
 int poptAddAlias(poptContext con, struct poptAlias alias,
-               /*@unused@*/ UNUSED(int flags))
+               UNUSED(int flags))
 {
-    poptItem item = (poptItem) alloca(sizeof(*item));
+    struct poptItem_s item_buf;
+    poptItem item = &item_buf;
     memset(item, 0, sizeof(*item));
     item->option.longName = alias.longName;
     item->option.shortName = alias.shortName;
@@ -1139,11 +1569,9 @@ int poptAddAlias(poptContext con, struct poptAlias alias,
     return poptAddItem(con, item, 0);
 }
 
-/*@-boundswrite@*/
-/*@-mustmod@*/ /* LCL: con not modified? */
 int poptAddItem(poptContext con, poptItem newItem, int flags)
 {
-    poptItem * items, item;
+    poptItem * items, item_tmp, item;
     int * nitems;
 
     switch (flags) {
@@ -1157,12 +1585,13 @@ int poptAddItem(poptContext con, poptItem newItem, int flags)
        break;
     default:
        return 1;
-       /*@notreached@*/ break;
+       break;
     }
 
-    *items = realloc((*items), ((*nitems) + 1) * sizeof(**items));
-    if ((*items) == NULL)
+    item_tmp = realloc((*items), ((*nitems) + 1) * sizeof(**items));
+    if (item_tmp == NULL)
        return 1;
+    *items = item_tmp;
 
     item = (*items) + (*nitems);
 
@@ -1183,19 +1612,23 @@ int poptAddItem(poptContext con, poptItem newItem, int flags)
 
     return 0;
 }
-/*@=mustmod@*/
-/*@=boundswrite@*/
 
-const char * poptBadOption(poptContext con, int flags)
+const char * poptBadOption(poptContext con, unsigned int flags)
 {
     struct optionStackEntry * os = NULL;
+    const char *badOpt = NULL;
+
+    if (con != NULL) {
+       /* Stupid hack to return something semi-meaningful from exec failure */
+       if (con->execFail) {
+           badOpt = con->execFail;
+       } else {
+           os = (flags & POPT_BADOPTION_NOALIAS) ? con->optionStack : con->os;
+           badOpt = os->argv[os->next - 1];
+       }
+    }
 
-    if (con != NULL)
-       os = (flags & POPT_BADOPTION_NOALIAS) ? con->optionStack : con->os;
-
-    /*@-nullderef@*/   /* LCL: os->argv != NULL */
-    return (os && os->argv ? os->argv[os->next - 1] : NULL);
-    /*@=nullderef@*/
+    return badOpt;
 }
 
 const char * poptStrerror(const int error)
@@ -1221,6 +1654,8 @@ const char * poptStrerror(const int error)
        return POPT_("number too large or too small");
       case POPT_ERROR_MALLOC:
        return POPT_("memory allocation failed");
+      case POPT_ERROR_BADCONFIG:
+       return POPT_("config file failed sanity test");
       case POPT_ERROR_ERRNO:
        return strerror(errno);
       default:
@@ -1256,14 +1691,12 @@ const char * poptGetInvocationName(poptContext con)
     return (con->os->argv ? con->os->argv[0] : "");
 }
 
-/*@-boundswrite@*/
 int poptStrippedArgv(poptContext con, int argc, char ** argv)
 {
     int numargs = argc;
     int j = 1;
     int i;
     
-    /*@-sizeoftype@*/
     if (con->arg_strip)
     for (i = 1; i < argc; i++) {
        if (PBM_ISSET(i, con->arg_strip))
@@ -1276,8 +1709,6 @@ int poptStrippedArgv(poptContext con, int argc, char ** argv)
        argv[j] = (j < numargs) ? argv[i] : NULL;
        j++;
     }
-    /*@=sizeoftype@*/
     
     return numargs;
 }
-/*@=boundswrite@*/
index 8d85f731294f502115e8d553167dc9531a2a11dd..bd1606110f169ccd889bd4920cc7a8eb94fdff29 100644 (file)
@@ -1,5 +1,4 @@
-/** \file popt/popt.h
- * \ingroup popt
+/** @file
  */
 
 /* (C) 1998-2000 Red Hat, Inc. -- Licensing details are in the COPYING
 
 #define POPT_OPTION_DEPTH      10
 
-/** \ingroup popt
+/**
  * \name Arg type identifiers
  */
-/*@{*/
-#define POPT_ARG_NONE          0       /*!< no arg */
-#define POPT_ARG_STRING                1       /*!< arg will be saved as string */
-#define POPT_ARG_INT           2       /*!< arg will be converted to int */
-#define POPT_ARG_LONG          3       /*!< arg will be converted to long */
-#define POPT_ARG_INCLUDE_TABLE 4       /*!< arg points to table */
-#define POPT_ARG_CALLBACK      5       /*!< table-wide callback... must be
+#define POPT_ARG_NONE           0U     /*!< no arg */
+#define POPT_ARG_STRING                 1U     /*!< arg will be saved as string */
+#define POPT_ARG_INT            2U     /*!< arg ==> int */
+#define POPT_ARG_LONG           3U     /*!< arg ==> long */
+#define POPT_ARG_INCLUDE_TABLE  4U     /*!< arg points to table */
+#define POPT_ARG_CALLBACK       5U     /*!< table-wide callback... must be
                                           set first in table; arg points 
                                           to callback, descrip points to 
                                           callback data to pass */
-#define POPT_ARG_INTL_DOMAIN    6       /*!< set the translation domain
+#define POPT_ARG_INTL_DOMAIN     6U    /*!< set the translation domain
                                           for this table and any
                                           included tables; arg points
                                           to the domain string */
-#define POPT_ARG_VAL           7       /*!< arg should take value val */
-#define        POPT_ARG_FLOAT          8       /*!< arg will be converted to float */
-#define        POPT_ARG_DOUBLE         9       /*!< arg will be converted to double */
+#define POPT_ARG_VAL            7U     /*!< arg should take value val */
+#define        POPT_ARG_FLOAT           8U     /*!< arg ==> float */
+#define        POPT_ARG_DOUBLE          9U     /*!< arg ==> double */
+#define        POPT_ARG_LONGLONG        10U    /*!< arg ==> long long */
+
+#define POPT_ARG_MAINCALL      (16U+11U)       /*!< EXPERIMENTAL: return (*arg) (argc, argv) */
+#define        POPT_ARG_ARGV           12U     /*!< dupe'd arg appended to realloc'd argv array. */
+#define        POPT_ARG_SHORT          13U     /*!< arg ==> short */
+#define        POPT_ARG_BITSET         (16U+14U)       /*!< arg ==> bit set */
 
-#define POPT_ARG_MASK          0x0000FFFF
-/*@}*/
+#define POPT_ARG_MASK          0x000000FFU
+#define POPT_GROUP_MASK                0x0000FF00U
 
-/** \ingroup popt
+/**
  * \name Arg modifiers
  */
-/*@{*/
-#define POPT_ARGFLAG_ONEDASH   0x80000000  /*!< allow -longoption */
-#define POPT_ARGFLAG_DOC_HIDDEN 0x40000000  /*!< don't show in help/usage */
-#define POPT_ARGFLAG_STRIP     0x20000000  /*!< strip this arg from argv(only applies to long args) */
-#define        POPT_ARGFLAG_OPTIONAL   0x10000000  /*!< arg may be missing */
-
-#define        POPT_ARGFLAG_OR         0x08000000  /*!< arg will be or'ed */
-#define        POPT_ARGFLAG_NOR        0x09000000  /*!< arg will be nor'ed */
-#define        POPT_ARGFLAG_AND        0x04000000  /*!< arg will be and'ed */
-#define        POPT_ARGFLAG_NAND       0x05000000  /*!< arg will be nand'ed */
-#define        POPT_ARGFLAG_XOR        0x02000000  /*!< arg will be xor'ed */
-#define        POPT_ARGFLAG_NOT        0x01000000  /*!< arg will be negated */
+#define POPT_ARGFLAG_ONEDASH   0x80000000U  /*!< allow -longoption */
+#define POPT_ARGFLAG_DOC_HIDDEN 0x40000000U  /*!< don't show in help/usage */
+#define POPT_ARGFLAG_STRIP     0x20000000U  /*!< strip this arg from argv(only applies to long args) */
+#define        POPT_ARGFLAG_OPTIONAL   0x10000000U  /*!< arg may be missing */
+
+#define        POPT_ARGFLAG_OR         0x08000000U  /*!< arg will be or'ed */
+#define        POPT_ARGFLAG_NOR        0x09000000U  /*!< arg will be nor'ed */
+#define        POPT_ARGFLAG_AND        0x04000000U  /*!< arg will be and'ed */
+#define        POPT_ARGFLAG_NAND       0x05000000U  /*!< arg will be nand'ed */
+#define        POPT_ARGFLAG_XOR        0x02000000U  /*!< arg will be xor'ed */
+#define        POPT_ARGFLAG_NOT        0x01000000U  /*!< arg will be negated */
 #define POPT_ARGFLAG_LOGICALOPS \
         (POPT_ARGFLAG_OR|POPT_ARGFLAG_AND|POPT_ARGFLAG_XOR)
 
 #define        POPT_BIT_CLR    (POPT_ARG_VAL|POPT_ARGFLAG_NAND)
                                        /*!< clear arg bit(s) */
 
-#define        POPT_ARGFLAG_SHOW_DEFAULT 0x00800000 /*!< show default value in --help */
-
-/*@}*/
+#define        POPT_ARGFLAG_SHOW_DEFAULT 0x00800000U /*!< show default value in --help */
+#define        POPT_ARGFLAG_RANDOM     0x00400000U  /*!< random value in [1,arg] */
+#define        POPT_ARGFLAG_TOGGLE     0x00200000U  /*!< permit --[no]opt prefix toggle */
 
-/** \ingroup popt
+/**
  * \name Callback modifiers
  */
-/*@{*/
-#define POPT_CBFLAG_PRE                0x80000000  /*!< call the callback before parse */
-#define POPT_CBFLAG_POST       0x40000000  /*!< call the callback after parse */
-#define POPT_CBFLAG_INC_DATA   0x20000000  /*!< use data from the include line,
+#define POPT_CBFLAG_PRE                0x80000000U  /*!< call the callback before parse */
+#define POPT_CBFLAG_POST       0x40000000U  /*!< call the callback after parse */
+#define POPT_CBFLAG_INC_DATA   0x20000000U  /*!< use data from the include line,
                                               not the subtable */
-#define POPT_CBFLAG_SKIPOPTION 0x10000000  /*!< don't callback with option */
-#define POPT_CBFLAG_CONTINUE   0x08000000  /*!< continue callbacks with option */
-/*@}*/
+#define POPT_CBFLAG_SKIPOPTION 0x10000000U  /*!< don't callback with option */
+#define POPT_CBFLAG_CONTINUE   0x08000000U  /*!< continue callbacks with option */
 
-/** \ingroup popt
+/**
  * \name Error return values
  */
-/*@{*/
 #define POPT_ERROR_NOARG       -10     /*!< missing argument */
 #define POPT_ERROR_BADOPT      -11     /*!< unknown option */
 #define POPT_ERROR_UNWANTEDARG -12     /*!< option does not take an argument */
 #define POPT_ERROR_OPTSTOODEEP -13     /*!< aliases nested too deeply */
-#define POPT_ERROR_BADQUOTE    -15     /*!< error in paramter quoting */
+#define POPT_ERROR_BADQUOTE    -15     /*!< error in parameter quoting */
 #define POPT_ERROR_ERRNO       -16     /*!< errno set, use strerror(errno) */
 #define POPT_ERROR_BADNUMBER   -17     /*!< invalid numeric value */
 #define POPT_ERROR_OVERFLOW    -18     /*!< number too large or too small */
 #define        POPT_ERROR_BADOPERATION -19     /*!< mutually exclusive logical operations requested */
 #define        POPT_ERROR_NULLARG      -20     /*!< opt->arg should not be NULL */
 #define        POPT_ERROR_MALLOC       -21     /*!< memory allocation failed */
-/*@}*/
+#define        POPT_ERROR_BADCONFIG    -22     /*!< config file failed sanity test */
 
-/** \ingroup popt
+/**
  * \name poptBadOption() flags
  */
-/*@{*/
-#define POPT_BADOPTION_NOALIAS  (1 << 0)  /*!< don't go into an alias */
-/*@}*/
+#define POPT_BADOPTION_NOALIAS  (1U << 0)  /*!< don't go into an alias */
 
-/** \ingroup popt
+/**
  * \name poptGetContext() flags
  */
-/*@{*/
-#define POPT_CONTEXT_NO_EXEC   (1 << 0)  /*!< ignore exec expansions */
-#define POPT_CONTEXT_KEEP_FIRST        (1 << 1)  /*!< pay attention to argv[0] */
-#define POPT_CONTEXT_POSIXMEHARDER (1 << 2) /*!< options can't follow args */
-#define POPT_CONTEXT_ARG_OPTS  (1 << 4) /*!< return args as options with value 0 */
-/*@}*/
+#define POPT_CONTEXT_NO_EXEC   (1U << 0)  /*!< ignore exec expansions */
+#define POPT_CONTEXT_KEEP_FIRST        (1U << 1)  /*!< pay attention to argv[0] */
+#define POPT_CONTEXT_POSIXMEHARDER (1U << 2) /*!< options can't follow args */
+#define POPT_CONTEXT_ARG_OPTS  (1U << 4) /*!< return args as options with value 0 */
 
-/** \ingroup popt
+/**
  */
 struct poptOption {
-/*@observer@*/ /*@null@*/
     const char * longName;     /*!< may be NULL */
-    char shortName;            /*!< may be NUL */
-    int argInfo;
-/*@shared@*/ /*@null@*/
+    char shortName;            /*!< may be '\0' */
+    unsigned int argInfo;      /*!< type of argument expected after the option */
     void * arg;                        /*!< depends on argInfo */
-    int val;                   /*!< 0 means don't return, just update flag */
-/*@observer@*/ /*@null@*/
+    int val;                   /*!< 0 means don't return, just update arg */
     const char * descrip;      /*!< description for autohelp -- may be NULL */
-/*@observer@*/ /*@null@*/
-    const char * argDescrip;   /*!< argument description for autohelp */
+    const char * argDescrip;   /*!< argument description for autohelp -- may be NULL */
 };
 
-/** \ingroup popt
+/**
  * A popt alias argument for poptAddAlias().
  */
 struct poptAlias {
-/*@owned@*/ /*@null@*/
     const char * longName;     /*!< may be NULL */
     char shortName;            /*!< may be NUL */
     int argc;
-/*@owned@*/
     const char ** argv;                /*!< must be free()able */
 };
 
-/** \ingroup popt
+/**
  * A popt alias or exec argument for poptAddItem().
  */
-/*@-exporttype@*/
 typedef struct poptItem_s {
     struct poptOption option;  /*!< alias/exec name(s) and description. */
     int argc;                  /*!< (alias) no. of args. */
-/*@owned@*/
     const char ** argv;                /*!< (alias) args, must be free()able. */
 } * poptItem;
-/*@=exporttype@*/
 
-/** \ingroup popt
+/**
  * \name Auto-generated help/usage
  */
-/*@{*/
 
 /**
  * Empty table marker to enable displaying popt alias/exec options.
  */
-/*@-exportvar@*/
-/*@unchecked@*/ /*@observer@*/
 extern struct poptOption poptAliasOptions[];
-/*@=exportvar@*/
 #define POPT_AUTOALIAS { NULL, '\0', POPT_ARG_INCLUDE_TABLE, poptAliasOptions, \
                        0, "Options implemented via popt alias/exec:", NULL },
 
 /**
  * Auto help table options.
  */
-/*@-exportvar@*/
-/*@unchecked@*/ /*@observer@*/
 extern struct poptOption poptHelpOptions[];
-/*@=exportvar@*/
 
-/*@-exportvar@*/
-/*@unchecked@*/ /*@observer@*/
 extern struct poptOption * poptHelpOptionsI18N;
-/*@=exportvar@*/
 
 #define POPT_AUTOHELP { NULL, '\0', POPT_ARG_INCLUDE_TABLE, poptHelpOptions, \
                        0, "Help options:", NULL },
 
-#define POPT_TABLEEND { NULL, '\0', 0, 0, 0, NULL, NULL }
-/*@}*/
+#define POPT_TABLEEND { NULL, '\0', 0, NULL, 0, NULL, NULL }
 
-/** \ingroup popt
+/**
  */
-/*@-exporttype@*/
-typedef /*@abstract@*/ struct poptContext_s * poptContext;
-/*@=exporttype@*/
+typedef struct poptContext_s * poptContext;
 
-/** \ingroup popt
+/**
  */
 #ifndef __cplusplus
-/*@-exporttype -typeuse@*/
 typedef struct poptOption * poptOption;
-/*@=exporttype =typeuse@*/
 #endif
 
-/*@-exportconst@*/
+/**
+ */
 enum poptCallbackReason {
     POPT_CALLBACK_REASON_PRE   = 0, 
     POPT_CALLBACK_REASON_POST  = 1,
     POPT_CALLBACK_REASON_OPTION = 2
 };
-/*@=exportconst@*/
 
 #ifdef __cplusplus
 extern "C" {
 #endif
-/*@-type@*/
 
-/** \ingroup popt
+/**
  * Table callback prototype.
  * @param con          context
  * @param reason       reason for callback
@@ -221,13 +192,18 @@ extern "C" {
  */
 typedef void (*poptCallbackType) (poptContext con, 
                enum poptCallbackReason reason,
-               /*@null@*/ const struct poptOption * opt,
-               /*@null@*/ const char * arg,
-               /*@null@*/ const void * data)
-       /*@globals internalState @*/
-       /*@modifies internalState @*/;
+               const struct poptOption * opt,
+               const char * arg,
+               const void * data);
 
-/** \ingroup popt
+/**
+ * Destroy context.
+ * @param con          context
+ * @return             NULL always
+ */
+poptContext poptFreeContext( poptContext con);
+
+/**
  * Initialize popt context.
  * @param name         context name (usually argv[0] program name)
  * @param argc         no. of arguments
@@ -236,97 +212,90 @@ typedef void (*poptCallbackType) (poptContext con,
  * @param flags                or'd POPT_CONTEXT_* bits
  * @return             initialized popt context
  */
-/*@only@*/ /*@null@*/
 poptContext poptGetContext(
-               /*@dependent@*/ /*@keep@*/ const char * name,
-               int argc, /*@dependent@*/ /*@keep@*/ const char ** argv,
-               /*@dependent@*/ /*@keep@*/ const struct poptOption * options,
-               int flags)
-       /*@*/;
+               const char * name,
+               int argc, const char ** argv,
+               const struct poptOption * options,
+               unsigned int flags);
 
-/** \ingroup popt
+/**
+ * Destroy context (alternative implementation).
+ * @param con          context
+ * @return             NULL always
+ */
+poptContext poptFini( poptContext con);
+
+/**
+ * Initialize popt context (alternative implementation).
+ * This routine does poptGetContext() and then poptReadConfigFiles().
+ * @param argc         no. of arguments
+ * @param argv         argument array
+ * @param options      address of popt option table
+ * @param configPaths  colon separated file path(s) to read.
+ * @return             initialized popt context (NULL on error).
+ */
+poptContext poptInit(int argc, const char ** argv,
+               const struct poptOption * options,
+               const char * configPaths);
+
+/**
  * Reinitialize popt context.
  * @param con          context
  */
-/*@unused@*/
-void poptResetContext(/*@null@*/poptContext con)
-       /*@modifies con @*/;
+void poptResetContext(poptContext con);
 
-/** \ingroup popt
+/**
  * Return value of next option found.
  * @param con          context
  * @return             next option val, -1 on last item, POPT_ERROR_* on error
  */
-int poptGetNextOpt(/*@null@*/poptContext con)
-       /*@globals fileSystem, internalState @*/
-       /*@modifies con, fileSystem, internalState @*/;
+int poptGetNextOpt(poptContext con);
 
-/** \ingroup popt
+/**
  * Return next option argument (if any).
  * @param con          context
  * @return             option argument, NULL if no argument is available
  */
-/*@observer@*/ /*@null@*/ /*@unused@*/
-const char * poptGetOptArg(/*@null@*/poptContext con)
-       /*@modifies con @*/;
+char * poptGetOptArg(poptContext con);
 
-/** \ingroup popt
+/**
  * Return next argument.
  * @param con          context
  * @return             next argument, NULL if no argument is available
  */
-/*@observer@*/ /*@null@*/ /*@unused@*/
-const char * poptGetArg(/*@null@*/poptContext con)
-       /*@modifies con @*/;
+const char * poptGetArg(poptContext con);
 
-/** \ingroup popt
+/**
  * Peek at current argument.
  * @param con          context
  * @return             current argument, NULL if no argument is available
  */
-/*@observer@*/ /*@null@*/ /*@unused@*/
-const char * poptPeekArg(/*@null@*/poptContext con)
-       /*@*/;
+const char * poptPeekArg(poptContext con);
 
-/** \ingroup popt
+/**
  * Return remaining arguments.
  * @param con          context
  * @return             argument array, NULL terminated
  */
-/*@observer@*/ /*@null@*/
-const char ** poptGetArgs(/*@null@*/poptContext con)
-       /*@modifies con @*/;
+const char ** poptGetArgs(poptContext con);
 
-/** \ingroup popt
+/**
  * Return the option which caused the most recent error.
  * @param con          context
  * @param flags
  * @return             offending option
  */
-/*@observer@*/
-const char * poptBadOption(/*@null@*/poptContext con, int flags)
-       /*@*/;
-
-/** \ingroup popt
- * Destroy context.
- * @param con          context
- * @return             NULL always
- */
-/*@null@*/
-poptContext poptFreeContext( /*@only@*/ /*@null@*/ poptContext con)
-       /*@modifies con @*/;
+const char * poptBadOption(poptContext con, unsigned int flags);
 
-/** \ingroup popt
+/**
  * Add arguments to context.
  * @param con          context
  * @param argv         argument array, NULL terminated
  * @return             0 on success, POPT_ERROR_OPTSTOODEEP on failure
  */
-/*@unused@*/
-int poptStuffArgs(poptContext con, /*@keep@*/ const char ** argv)
-       /*@modifies con @*/;
+int poptStuffArgs(poptContext con, const char ** argv);
 
-/** \ingroup popt
+/**
  * Add alias to context.
  * @todo Pass alias by reference, not value.
  * @deprecated Use poptAddItem instead.
@@ -335,44 +304,64 @@ int poptStuffArgs(poptContext con, /*@keep@*/ const char ** argv)
  * @param flags                (unused)
  * @return             0 on success
  */
-/*@unused@*/
-int poptAddAlias(poptContext con, struct poptAlias alias, int flags)
-       /*@modifies con @*/;
+int poptAddAlias(poptContext con, struct poptAlias alias, int flags);
 
-/** \ingroup popt
+/**
  * Add alias/exec item to context.
  * @param con          context
  * @param newItem      alias/exec item to add
  * @param flags                0 for alias, 1 for exec
  * @return             0 on success
  */
-int poptAddItem(poptContext con, poptItem newItem, int flags)
-       /*@modifies con @*/;
+int poptAddItem(poptContext con, poptItem newItem, int flags);
 
-/** \ingroup popt
+/**
+ * Test path/file for config file sanity (regular file, permissions etc)
+ * @param fn           file name
+ * @return             1 on OK, 0 on NOTOK.
+ */
+int poptSaneFile(const char * fn);
+
+/**
+ * Read a file into a buffer.
+ * @param fn           file name
+ * @retval *bp         buffer (malloc'd) (or NULL)
+ * @retval *nbp                no. of bytes in buffer (including final NUL) (or NULL)
+ * @param flags                1 to trim escaped newlines
+ * return              0 on success
+ */
+int poptReadFile(const char * fn, char ** bp,
+               size_t * nbp, int flags);
+#define        POPT_READFILE_TRIMNEWLINES      1
+
+/**
  * Read configuration file.
  * @param con          context
  * @param fn           file name to read
  * @return             0 on success, POPT_ERROR_ERRNO on failure
  */
-int poptReadConfigFile(poptContext con, const char * fn)
-       /*@globals errno, fileSystem, internalState @*/
-       /*@modifies con->execs, con->numExecs,
-               errno, fileSystem, internalState @*/;
+int poptReadConfigFile(poptContext con, const char * fn);
 
-/** \ingroup popt
+/**
+ * Read configuration file(s).
+ * Colon separated files to read, looping over poptReadConfigFile().
+ * Note that an '@' character preceding a path in the list will
+ * also perform additional sanity checks on the file before reading.
+ * @param con          context
+ * @param paths                colon separated file name(s) to read
+ * @return             0 on success, POPT_ERROR_BADCONFIG on failure
+ */
+int poptReadConfigFiles(poptContext con, const char * paths);
+
+/**
  * Read default configuration from /etc/popt and $HOME/.popt.
  * @param con          context
  * @param useEnv       (unused)
  * @return             0 on success, POPT_ERROR_ERRNO on failure
  */
-/*@unused@*/
-int poptReadDefaultConfig(poptContext con, /*@unused@*/ int useEnv)
-       /*@globals fileSystem, internalState @*/
-       /*@modifies con->execs, con->numExecs,
-               fileSystem, internalState @*/;
+int poptReadDefaultConfig(poptContext con, int useEnv);
 
-/** \ingroup popt
+/**
  * Duplicate an argument array.
  * @note: The argument array is malloc'd as a single area, so only argv must
  * be free'd.
@@ -383,12 +372,11 @@ int poptReadDefaultConfig(poptContext con, /*@unused@*/ int useEnv)
  * @retval argvPtr     address of returned argument array
  * @return             0 on success, POPT_ERROR_NOARG on failure
  */
-int poptDupArgv(int argc, /*@null@*/ const char **argv,
-               /*@null@*/ /*@out@*/ int * argcPtr,
-               /*@null@*/ /*@out@*/ const char *** argvPtr)
-       /*@modifies *argcPtr, *argvPtr @*/;
+int poptDupArgv(int argc, const char **argv,
+               int * argcPtr,
+               const char *** argvPtr);
 
-/** \ingroup popt
+/**
  * Parse a string into an argument array.
  * The parse allows ', ", and \ quoting, but ' is treated the same as " and
  * both may include \ quotes.
@@ -400,10 +388,9 @@ int poptDupArgv(int argc, /*@null@*/ const char **argv,
  * @retval argvPtr     address of returned argument array
  */
 int poptParseArgvString(const char * s,
-               /*@out@*/ int * argcPtr, /*@out@*/ const char *** argvPtr)
-       /*@modifies *argcPtr, *argvPtr @*/;
+               int * argcPtr, const char *** argvPtr);
 
-/** \ingroup popt
+/**
  * Parses an input configuration file and returns an string that is a 
  * command line.  For use with popt.  You must free the return value when done.
  *
@@ -418,8 +405,8 @@ bla=bla
 
 this_is   =   fdsafdas
      bad_line=        
-  reall bad line  
-  reall bad line  = again
+  really bad line
+  really bad line  = again
 5555=   55555   
   test = with lots of spaces
 \endverbatim
@@ -449,83 +436,82 @@ this_is   =   fdsafdas
  * @return             0 on success
  * @see                        poptParseArgvString
  */
-/*@-fcnuse@*/
-int poptConfigFileToString(FILE *fp, /*@out@*/ char ** argstrp, int flags)
-       /*@globals fileSystem @*/
-       /*@modifies *fp, *argstrp, fileSystem @*/;
-/*@=fcnuse@*/
+int poptConfigFileToString(FILE *fp, char ** argstrp, int flags);
 
-/** \ingroup popt
+/**
  * Return formatted error string for popt failure.
  * @param error                popt error
  * @return             error string
  */
-/*@observer@*/
-const char * poptStrerror(const int error)
-       /*@*/;
+const char * poptStrerror(const int error);
 
-/** \ingroup popt
+/**
  * Limit search for executables.
  * @param con          context
  * @param path         single path to search for executables
  * @param allowAbsolute        absolute paths only?
  */
-/*@unused@*/
-void poptSetExecPath(poptContext con, const char * path, int allowAbsolute)
-       /*@modifies con @*/;
+void poptSetExecPath(poptContext con, const char * path, int allowAbsolute);
 
-/** \ingroup popt
+/**
  * Print detailed description of options.
  * @param con          context
- * @param fp           ouput file handle
+ * @param fp           output file handle
  * @param flags                (unused)
  */
-void poptPrintHelp(poptContext con, FILE * fp, /*@unused@*/ int flags)
-       /*@globals fileSystem @*/
-       /*@modifies *fp, fileSystem @*/;
+void poptPrintHelp(poptContext con, FILE * fp, int flags);
 
-/** \ingroup popt
+/**
  * Print terse description of options.
  * @param con          context
- * @param fp           ouput file handle
+ * @param fp           output file handle
  * @param flags                (unused)
  */
-void poptPrintUsage(poptContext con, FILE * fp, /*@unused@*/ int flags)
-       /*@globals fileSystem @*/
-       /*@modifies *fp, fileSystem @*/;
+void poptPrintUsage(poptContext con, FILE * fp, int flags);
 
-/** \ingroup popt
+/**
  * Provide text to replace default "[OPTION...]" in help/usage output.
  * @param con          context
  * @param text         replacement text
  */
-/*@-fcnuse@*/
-void poptSetOtherOptionHelp(poptContext con, const char * text)
-       /*@modifies con @*/;
-/*@=fcnuse@*/
+void poptSetOtherOptionHelp(poptContext con, const char * text);
 
-/** \ingroup popt
+/**
  * Return argv[0] from context.
  * @param con          context
  * @return             argv[0]
  */
-/*@-fcnuse@*/
-/*@observer@*/
-const char * poptGetInvocationName(poptContext con)
-       /*@*/;
-/*@=fcnuse@*/
+const char * poptGetInvocationName(poptContext con);
 
-/** \ingroup popt
+/**
  * Shuffle argv pointers to remove stripped args, returns new argc.
  * @param con          context
  * @param argc         no. of args
  * @param argv         arg vector
  * @return             new argc
  */
-/*@-fcnuse@*/
-int poptStrippedArgv(poptContext con, int argc, char ** argv)
-       /*@modifies *argv @*/;
-/*@=fcnuse@*/
+int poptStrippedArgv(poptContext con, int argc, char ** argv);
+
+/**
+ * Add a string to an argv array.
+ * @retval *argvp      argv array
+ * @param argInfo      (unused)
+ * @param val          string arg to add (using strdup)
+ * @return             0 on success, POPT_ERROR_NULLARG/POPT_ERROR_BADOPERATION
+ */
+int poptSaveString(const char *** argvp, unsigned int argInfo,
+               const char * val);
+
+/**
+ * Save a long long, performing logical operation with value.
+ * @warning Alignment check may be too strict on certain platorms.
+ * @param arg          integer pointer, aligned on int boundary.
+ * @param argInfo      logical operation (see POPT_ARGFLAG_*)
+ * @param aLongLong    value to use
+ * @return             0 on success, POPT_ERROR_NULLARG/POPT_ERROR_BADOPERATION
+ */
+int poptSaveLongLong(long long * arg, unsigned int argInfo,
+               long long aLongLong);
 
 /**
  * Save a long, performing logical operation with value.
@@ -535,12 +521,17 @@ int poptStrippedArgv(poptContext con, int argc, char ** argv)
  * @param aLong                value to use
  * @return             0 on success, POPT_ERROR_NULLARG/POPT_ERROR_BADOPERATION
  */
-/*@-incondefs@*/
-/*@unused@*/
-int poptSaveLong(/*@null@*/ long * arg, int argInfo, long aLong)
-       /*@modifies *arg @*/
-       /*@requires maxSet(arg) >= 0 /\ maxRead(arg) == 0 @*/;
-/*@=incondefs@*/
+int poptSaveLong(long * arg, unsigned int argInfo, long aLong);
+
+/**
+ * Save a short integer, performing logical operation with value.
+ * @warning Alignment check may be too strict on certain platorms.
+ * @param arg          short pointer, aligned on short boundary.
+ * @param argInfo      logical operation (see POPT_ARGFLAG_*)
+ * @param aLong                value to use
+ * @return             0 on success, POPT_ERROR_NULLARG/POPT_ERROR_BADOPERATION
+ */
+int poptSaveShort(short * arg, unsigned int argInfo, long aLong);
 
 /**
  * Save an integer, performing logical operation with value.
@@ -550,14 +541,40 @@ int poptSaveLong(/*@null@*/ long * arg, int argInfo, long aLong)
  * @param aLong                value to use
  * @return             0 on success, POPT_ERROR_NULLARG/POPT_ERROR_BADOPERATION
  */
-/*@-incondefs@*/
-/*@unused@*/
-int poptSaveInt(/*@null@*/ int * arg, int argInfo, long aLong)
-       /*@modifies *arg @*/
-       /*@requires maxSet(arg) >= 0 /\ maxRead(arg) == 0 @*/;
-/*@=incondefs@*/
+int poptSaveInt(int * arg, unsigned int argInfo, long aLong);
+
+/* The bit set typedef. */
+typedef struct poptBits_s {
+    unsigned int bits[1];
+} * poptBits;
+
+#define _POPT_BITS_N    1024U  /*!< estimated population */
+#define _POPT_BITS_M    ((3U * _POPT_BITS_N) / 2U)
+#define _POPT_BITS_K    16U    /*!< no. of linear hash combinations */
+
+extern unsigned int _poptBitsN;
+extern  unsigned int _poptBitsM;
+extern  unsigned int _poptBitsK;
+
+int poptBitsAdd(poptBits bits, const char * s);
+int poptBitsChk(poptBits bits, const char * s);
+int poptBitsClr(poptBits bits);
+int poptBitsDel(poptBits bits, const char * s);
+int poptBitsIntersect(poptBits * ap, const poptBits b);
+int poptBitsUnion(poptBits * ap, const poptBits b);
+int poptBitsArgs(poptContext con, poptBits * ap);
+
+/**
+ * Save a string into a bit set (experimental).
+ * @retval *bits       bit set (lazily malloc'd if NULL)
+ * @param argInfo      logical operation (see POPT_ARGFLAG_*)
+ * @param s            string to add to bit set
+ * @return             0 on success, POPT_ERROR_NULLARG/POPT_ERROR_BADOPERATION
+ */
+int poptSaveBits(poptBits * bitsp, unsigned int argInfo,
+               const char * s);
+
 
-/*@=type@*/
 #ifdef  __cplusplus
 }
 #endif
index 9733d152916a67080f6a4026591bccd9d50f1683..bf201e26fdb615b6b7b2e8718c07ac3494cf4e71 100644 (file)
@@ -1,5 +1,5 @@
 /** \ingroup popt
- * \file popt/poptconfig.c
+ * @file
  */
 
 /* (C) 1998-2002 Red Hat, Inc. -- Licensing details are in the COPYING
 
 #include "system.h"
 #include "poptint.h"
-/*@access poptContext @*/
+#include <sys/stat.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <errno.h>
 
-/*@-compmempass@*/     /* FIX: item->option.longName kept, not dependent. */
-static void configLine(poptContext con, char * line)
-       /*@modifies con @*/
+#if defined(HAVE_FNMATCH_H)
+#include <fnmatch.h>
+
+#endif
+
+#if defined(HAVE_GLOB_H)
+#include <glob.h>
+
+#if !defined(HAVE_GLOB_PATTERN_P)
+/* Return nonzero if PATTERN contains any metacharacters.
+   Metacharacters can be quoted with backslashes if QUOTE is nonzero.  */
+static int
+glob_pattern_p (const char * pattern, int quote)
+{
+    const char * p;
+    int open = 0;
+
+    for (p = pattern; *p != '\0'; ++p)
+    switch (*p) {
+    case '?':
+    case '*':
+       return 1;
+       break;
+    case '\\':
+       if (quote && p[1] != '\0')
+         ++p;
+       break;
+    case '[':
+       open = 1;
+       break;
+    case ']':
+       if (open)
+         return 1;
+       break;
+    }
+    return 0;
+}
+#endif /* !defined(__GLIBC__) */
+
+static int poptGlobFlags = 0;
+
+static int poptGlob_error(UNUSED(const char * epath),
+               UNUSED(int eerrno))
+{
+    return 1;
+}
+#endif /* HAVE_GLOB_H */
+
+/**
+ * Return path(s) from a glob pattern.
+ * @param con          context
+ * @param pattern      glob pattern
+ * @retval *acp                no. of paths
+ * @retval *avp                array of paths
+ * @return             0 on success
+ */
+static int poptGlob(UNUSED(poptContext con), const char * pattern,
+               int * acp, const char *** avp)
+{
+    const char * pat = pattern;
+    int rc = 0;                /* assume success */
+
+#if defined(HAVE_GLOB_H)
+    if (glob_pattern_p(pat, 0)) {
+       glob_t _g, *pglob = &_g;
+
+       if (!(rc = glob(pat, poptGlobFlags, poptGlob_error, pglob))) {
+           if (acp) {
+               *acp = (int) pglob->gl_pathc;
+               pglob->gl_pathc = 0;
+           }
+           if (avp) {
+               *avp = (const char **) pglob->gl_pathv;
+               pglob->gl_pathv = NULL;
+           }
+           globfree(pglob);
+       } else if (rc == GLOB_NOMATCH) {
+           *avp = NULL;
+           *acp = 0;
+           rc = 0;
+       } else
+           rc = POPT_ERROR_ERRNO;
+    } else
+#endif /* HAVE_GLOB_H */
+    {
+       if (acp)
+           *acp = 1;
+       if (avp && (*avp = calloc((size_t)(1 + 1), sizeof (**avp))) != NULL)
+           (*avp)[0] = xstrdup(pat);
+    }
+
+    return rc;
+}
+
+
+int poptSaneFile(const char * fn)
+{
+    struct stat sb;
+
+    if (fn == NULL || strstr(fn, ".rpmnew") || strstr(fn, ".rpmsave"))
+       return 0;
+    if (stat(fn, &sb) == -1)
+       return 0;
+    if (!S_ISREG(sb.st_mode))
+       return 0;
+    if (sb.st_mode & (S_IXUSR|S_IXGRP|S_IXOTH))
+       return 0;
+    return 1;
+}
+
+int poptReadFile(const char * fn, char ** bp, size_t * nbp, int flags)
+{
+    int fdno;
+    char * b = NULL;
+    off_t nb = 0;
+    char * s, * t, * se;
+    int rc = POPT_ERROR_ERRNO; /* assume failure */
+
+    fdno = open(fn, O_RDONLY);
+    if (fdno < 0)
+       goto exit;
+
+    if ((nb = lseek(fdno, 0, SEEK_END)) == (off_t)-1
+     || (uintmax_t)nb >= SIZE_MAX
+     || lseek(fdno, 0, SEEK_SET) == (off_t)-1
+     || (b = calloc(sizeof(*b), (size_t)nb + 1)) == NULL
+     || read(fdno, (char *)b, (size_t)nb) != (ssize_t)nb)
+    {
+       int oerrno = errno;
+       (void) close(fdno);
+       if (nb != (off_t)-1 && (uintmax_t)nb >= SIZE_MAX)
+           errno = -EOVERFLOW;
+       else
+           errno = oerrno;
+       goto exit;
+    }
+    if (close(fdno) == -1)
+       goto exit;
+    if (b == NULL) {
+       rc = POPT_ERROR_MALLOC;
+       goto exit;
+    }
+    rc = 0;
+
+   /* Trim out escaped newlines. */
+    if (flags & POPT_READFILE_TRIMNEWLINES)
+    {
+       for (t = b, s = b, se = b + nb; *s && s < se; s++) {
+           switch (*s) {
+           case '\\':
+               if (s[1] == '\n') {
+                   s++;
+                   continue;
+               }
+               /* fallthrough */
+           default:
+               *t++ = *s;
+               break;
+           }
+       }
+       *t++ = '\0';
+       nb = (off_t)(t - b);
+    }
+
+exit:
+    if (rc != 0) {
+       if (b)
+           free(b);
+       b = NULL;
+       nb = 0;
+    }
+    if (bp)
+       *bp = b;
+    else if (b)
+       free(b);
+    if (nbp)
+       *nbp = (size_t)nb;
+    return rc;
+}
+
+/**
+ * Check for application match.
+ * @param con          context
+ * @param s            config application name
+ * return              0 if config application matches
+ */
+static int configAppMatch(poptContext con, const char * s)
 {
-    size_t nameLength;
+    int rc = 1;
+
+    if (con->appName == NULL)  /* XXX can't happen. */
+       return rc;
+
+#if defined(HAVE_GLOB_H) && defined(HAVE_FNMATCH_H)
+    if (glob_pattern_p(s, 1)) {
+       static int flags = FNM_PATHNAME | FNM_PERIOD;
+#ifdef FNM_EXTMATCH
+       flags |= FNM_EXTMATCH;
+#endif
+       rc = fnmatch(s, con->appName, flags);
+    } else
+#endif
+       rc = strcmp(s, con->appName);
+    return rc;
+}
+
+static int poptConfigLine(poptContext con, char * line)
+{
+    char *b = NULL;
+    size_t nb = 0;
+    char * se = line;
+    const char * appName;
     const char * entryType;
     const char * opt;
-    poptItem item = (poptItem) alloca(sizeof(*item));
+    struct poptItem_s item_buf;
+    poptItem item = &item_buf;
     int i, j;
+    int rc = POPT_ERROR_BADCONFIG;
 
     if (con->appName == NULL)
-       return;
-    nameLength = strlen(con->appName);
+       goto exit;
     
-/*@-boundswrite@*/
     memset(item, 0, sizeof(*item));
 
-    if (strncmp(line, con->appName, nameLength)) return;
+    appName = se;
+    while (*se != '\0' && !_isspaceptr(se)) se++;
+    if (*se == '\0')
+       goto exit;
+    else
+       *se++ = '\0';
 
-    line += nameLength;
-    if (*line == '\0' || !isSpace(line)) return;
+    if (configAppMatch(con, appName)) goto exit;
 
-    while (*line != '\0' && isSpace(line)) line++;
-    entryType = line;
-    while (*line == '\0' || !isSpace(line)) line++;
-    *line++ = '\0';
+    while (*se != '\0' && _isspaceptr(se)) se++;
+    entryType = se;
+    while (*se != '\0' && !_isspaceptr(se)) se++;
+    if (*se != '\0') *se++ = '\0';
 
-    while (*line != '\0' && isSpace(line)) line++;
-    if (*line == '\0') return;
-    opt = line;
-    while (*line == '\0' || !isSpace(line)) line++;
-    *line++ = '\0';
+    while (*se != '\0' && _isspaceptr(se)) se++;
+    if (*se == '\0') goto exit;
+    opt = se;
+    while (*se != '\0' && !_isspaceptr(se)) se++;
+    if (opt[0] == '-' && *se == '\0') goto exit;
+    if (*se != '\0') *se++ = '\0';
 
-    while (*line != '\0' && isSpace(line)) line++;
-    if (*line == '\0') return;
+    while (*se != '\0' && _isspaceptr(se)) se++;
+    if (opt[0] == '-' && *se == '\0') goto exit;
 
-    /*@-temptrans@*/ /* FIX: line alias is saved */
     if (opt[0] == '-' && opt[1] == '-')
        item->option.longName = opt + 2;
     else if (opt[0] == '-' && opt[2] == '\0')
        item->option.shortName = opt[1];
-    /*@=temptrans@*/
+    else {
+       const char * fn = opt;
+
+       /* XXX handle globs and directories in fn? */
+       if ((rc = poptReadFile(fn, &b, &nb, POPT_READFILE_TRIMNEWLINES)) != 0)
+           goto exit;
+       if (b == NULL || nb == 0)
+           goto exit;
+
+       /* Append remaining text to the interpolated file option text. */
+       if (*se != '\0') {
+           size_t nse = strlen(se) + 1;
+           if ((b = realloc(b, (nb + nse))) == NULL)   /* XXX can't happen */
+               goto exit;
+           (void) stpcpy( stpcpy(&b[nb-1], " "), se);
+           nb += nse;
+       }
+       se = b;
+
+       /* Use the basename of the path as the long option name. */
+       {   const char * longName = strrchr(fn, '/');
+           if (longName != NULL)
+               longName++;
+           else
+               longName = fn;
+           if (longName == NULL)       /* XXX can't happen. */
+               goto exit;
+           /* Single character basenames are treated as short options. */
+           if (longName[1] != '\0')
+               item->option.longName = longName;
+           else
+               item->option.shortName = longName[0];
+       }
+    }
 
-    if (poptParseArgvString(line, &item->argc, &item->argv)) return;
+    if (poptParseArgvString(se, &item->argc, &item->argv)) goto exit;
 
-    /*@-modobserver@*/
     item->option.argInfo = POPT_ARGFLAG_DOC_HIDDEN;
     for (i = 0, j = 0; i < item->argc; i++, j++) {
        const char * f;
@@ -81,103 +327,183 @@ static void configLine(poptContext con, char * line)
        item->argv[j] = NULL;
        item->argc = j;
     }
-    /*@=modobserver@*/
-/*@=boundswrite@*/
        
-    /*@-nullstate@*/ /* FIX: item->argv[] may be NULL */
     if (!strcmp(entryType, "alias"))
-       (void) poptAddItem(con, item, 0);
+       rc = poptAddItem(con, item, 0);
     else if (!strcmp(entryType, "exec"))
-       (void) poptAddItem(con, item, 1);
-    /*@=nullstate@*/
+       rc = poptAddItem(con, item, 1);
+exit:
+    rc = 0;    /* XXX for now, always return success */
+    if (b)
+       free(b);
+    return rc;
 }
-/*@=compmempass@*/
 
 int poptReadConfigFile(poptContext con, const char * fn)
 {
-    const char * file, * chptr, * end;
-    char * buf;
-/*@dependent@*/ char * dst;
-    int fd, rc;
-    off_t fileLength;
-
-    fd = open(fn, O_RDONLY);
-    if (fd < 0)
-       return (errno == ENOENT ? 0 : POPT_ERROR_ERRNO);
-
-    fileLength = lseek(fd, 0, SEEK_END);
-    if (fileLength == -1 || lseek(fd, 0, 0) == -1) {
-       rc = errno;
-       (void) close(fd);
-       errno = rc;
-       return POPT_ERROR_ERRNO;
-    }
+    char * b = NULL, *be;
+    size_t nb = 0;
+    const char *se;
+    char *t = NULL, *te;
+    int rc;
 
-    file = alloca(fileLength + 1);
-    if (read(fd, (char *)file, fileLength) != fileLength) {
-       rc = errno;
-       (void) close(fd);
-       errno = rc;
-       return POPT_ERROR_ERRNO;
+    if ((rc = poptReadFile(fn, &b, &nb, POPT_READFILE_TRIMNEWLINES)) != 0)
+       return (errno == ENOENT ? 0 : rc);
+    if (b == NULL || nb == 0) {
+       rc = POPT_ERROR_BADCONFIG;
+       goto exit;
     }
-    if (close(fd) == -1)
-       return POPT_ERROR_ERRNO;
 
-/*@-boundswrite@*/
-    dst = buf = alloca(fileLength + 1);
+    if ((t = malloc(nb + 1)) == NULL)
+       goto exit;
+    te = t;
 
-    chptr = file;
-    end = (file + fileLength);
-    /*@-infloops@*/    /* LCL: can't detect chptr++ */
-    while (chptr < end) {
-       switch (*chptr) {
+    be = (b + nb);
+    for (se = b; se < be; se++) {
+       switch (*se) {
          case '\n':
-           *dst = '\0';
-           dst = buf;
-           while (*dst && isSpace(dst)) dst++;
-           if (*dst && *dst != '#')
-               configLine(con, dst);
-           chptr++;
-           /*@switchbreak@*/ break;
+           *te = '\0';
+           te = t;
+           while (*te && _isspaceptr(te)) te++;
+           if (*te && *te != '#')
+               if ((rc = poptConfigLine(con, te)) != 0)
+                   goto exit;
+           break;
          case '\\':
-           *dst++ = *chptr++;
-           if (chptr < end) {
-               if (*chptr == '\n') 
-                   dst--, chptr++;     
-                   /* \ at the end of a line does not insert a \n */
-               else
-                   *dst++ = *chptr++;
+           *te = *se++;
+           /* \ at the end of a line does not insert a \n */
+           if (se < be && *se != '\n') {
+               te++;
+               *te++ = *se;
            }
-           /*@switchbreak@*/ break;
+           break;
          default:
-           *dst++ = *chptr++;
-           /*@switchbreak@*/ break;
+           *te++ = *se;
+           break;
        }
     }
-    /*@=infloops@*/
-/*@=boundswrite@*/
+    rc = 0;
 
-    return 0;
+exit:
+    free(t);
+    if (b)
+       free(b);
+    return rc;
 }
 
-int poptReadDefaultConfig(poptContext con, /*@unused@*/ UNUSED(int useEnv))
+int poptReadConfigFiles(poptContext con, const char * paths)
 {
-    char * fn, * home;
-    int rc;
+    char * buf = (paths ? xstrdup(paths) : NULL);
+    const char * p;
+    char * pe;
+    int rc = 0;                /* assume success */
+
+    for (p = buf; p != NULL && *p != '\0'; p = pe) {
+       const char ** av = NULL;
+       int ac = 0;
+       int i;
+       int xx;
+
+       /* locate start of next path element */
+       pe = strchr(p, ':');
+       if (pe != NULL && *pe == ':')
+           *pe++ = '\0';
+       else
+           pe = (char *) (p + strlen(p));
+
+       xx = poptGlob(con, p, &ac, &av);
+
+       /* work-off each resulting file from the path element */
+       for (i = 0; i < ac; i++) {
+           const char * fn = av[i];
+           if (!poptSaneFile(fn))
+               continue;
+           xx = poptReadConfigFile(con, fn);
+           if (xx && rc == 0)
+               rc = xx;
+           free((void *)av[i]);
+           av[i] = NULL;
+       }
+       free(av);
+       av = NULL;
+    }
 
-    if (con->appName == NULL) return 0;
+    if (buf)
+       free(buf);
 
-    rc = poptReadConfigFile(con, "/etc/popt");
-    if (rc) return rc;
+    return rc;
+}
+
+int poptReadDefaultConfig(poptContext con, UNUSED(int useEnv))
+{
+    char * home;
+    struct stat sb;
+    int rc = 0;                /* assume success */
+
+    if (con->appName == NULL) goto exit;
+
+    rc = poptReadConfigFile(con, POPT_SYSCONFDIR "/popt");
+    if (rc) goto exit;
+
+#if defined(HAVE_GLOB_H)
+    if (!stat(POPT_SYSCONFDIR "/popt.d", &sb) && S_ISDIR(sb.st_mode)) {
+       const char ** av = NULL;
+       int ac = 0;
+       int i;
+
+       if ((rc = poptGlob(con, POPT_SYSCONFDIR "/popt.d/*", &ac, &av)) == 0) {
+           for (i = 0; rc == 0 && i < ac; i++) {
+               const char * fn = av[i];
+               if (!poptSaneFile(fn))
+                   continue;
+               rc = poptReadConfigFile(con, fn);
+               free((void *)av[i]);
+               av[i] = NULL;
+           }
+           free(av);
+           av = NULL;
+       }
+    }
+    if (rc) goto exit;
+#endif
 
     if ((home = getenv("HOME"))) {
-       size_t bufsize = strlen(home) + 20;
-       fn = alloca(bufsize);
-       if (fn == NULL) return 0;
-       snprintf(fn, bufsize, "%s/.popt", home);
-       rc = poptReadConfigFile(con, fn);
-       if (rc) return rc;
+       char * fn = malloc(strlen(home) + 20);
+       if (fn != NULL) {
+           (void) stpcpy(stpcpy(fn, home), "/.popt");
+           rc = poptReadConfigFile(con, fn);
+           free(fn);
+       } else
+           rc = POPT_ERROR_ERRNO;
+       if (rc) goto exit;
     }
 
-    return 0;
+exit:
+    return rc;
+}
+
+poptContext
+poptFini(poptContext con)
+{
+    return poptFreeContext(con);
+}
+
+poptContext
+poptInit(int argc, const char ** argv,
+               const struct poptOption * options, const char * configPaths)
+{
+    poptContext con = NULL;
+    const char * argv0;
+
+    if (argv == NULL || argv[0] == NULL || options == NULL)
+       return con;
+
+    if ((argv0 = strrchr(argv[0], '/')) != NULL) argv0++;
+    else argv0 = argv[0];
+   
+    con = poptGetContext(argv0, argc, (const char **)argv, options, 0);
+    if (con != NULL&& poptReadConfigFiles(con, configPaths))
+       con = poptFini(con);
+
+    return con;
 }
index 6a009766de3ba5b09066955062fc2f57f7c4b3b5..6738f6addaa4809a30c1ddc6e23adb66cecb9358 100644 (file)
@@ -1,7 +1,7 @@
 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 4 -*- */
 
 /** \ingroup popt
- * \file popt/popthelp.c
+ * @file
  */
 
 /* (C) 1998-2002 Red Hat, Inc. -- Licensing details are in the COPYING
 
 #include "system.h"
 
-/*#define POPT_WCHAR_HACK*/
-#ifdef         POPT_WCHAR_HACK
+#define        POPT_USE_TIOCGWINSZ
+#ifdef POPT_USE_TIOCGWINSZ
+#include <sys/ioctl.h>
+#endif
+
+#ifdef HAVE_MBSRTOWCS
 #include <wchar.h>                     /* for mbsrtowcs */
-/*@access mbstate_t @*/
 #endif
 #include "poptint.h"
 
-/*@access poptContext@*/
 
 /**
  * Display arguments.
  * @param arg          (unused)
  * @param data         (unused)
  */
+NORETURN
 static void displayArgs(poptContext con,
-               /*@unused@*/ UNUSED(enum poptCallbackReason foo),
+               UNUSED(enum poptCallbackReason foo),
                struct poptOption * key, 
-               /*@unused@*/ UNUSED(const char * arg), /*@unused@*/ UNUSED(void * data))
-       /*@globals fileSystem@*/
-       /*@modifies fileSystem@*/
+               UNUSED(const char * arg),
+               UNUSED(void * data))
 {
     if (key->shortName == '?')
        poptPrintHelp(con, stdout, 0);
     else
        poptPrintUsage(con, stdout, 0);
+
+    poptFreeContext(con);
     exit(0);
 }
 
 #ifdef NOTYET
-/*@unchecked@*/
 static int show_option_defaults = 0;
 #endif
 
 /**
  * Empty table marker to enable displaying popt alias/exec options.
  */
-/*@observer@*/ /*@unchecked@*/
 struct poptOption poptAliasOptions[] = {
     POPT_TABLEEND
 };
@@ -57,45 +59,88 @@ struct poptOption poptAliasOptions[] = {
 /**
  * Auto help table options.
  */
-/*@-castfcnptr@*/
-/*@observer@*/ /*@unchecked@*/
 struct poptOption poptHelpOptions[] = {
-  { NULL, '\0', POPT_ARG_CALLBACK, (void *)&displayArgs, '\0', NULL, NULL },
-  { "help", '?', 0, NULL, '?', N_("Show this help message"), NULL },
-  { "usage", '\0', 0, NULL, 'u', N_("Display brief usage message"), NULL },
+  { NULL, '\0', POPT_ARG_CALLBACK, (void *)displayArgs, 0, NULL, NULL },
+  { "help", '?', 0, NULL, (int)'?', N_("Show this help message"), NULL },
+  { "usage", '\0', 0, NULL, (int)'u', N_("Display brief usage message"), NULL },
     POPT_TABLEEND
 } ;
 
-/*@observer@*/ /*@unchecked@*/
 static struct poptOption poptHelpOptions2[] = {
-/*@-readonlytrans@*/
-  { NULL, '\0', POPT_ARG_INTL_DOMAIN, PACKAGE, 0, NULL, NULL},
-/*@=readonlytrans@*/
-  { NULL, '\0', POPT_ARG_CALLBACK, (void *)&displayArgs, '\0', NULL, NULL },
-  { "help", '?', 0, NULL, '?', N_("Show this help message"), NULL },
-  { "usage", '\0', 0, NULL, 'u', N_("Display brief usage message"), NULL },
+  { NULL, '\0', POPT_ARG_INTL_DOMAIN, (void *)PACKAGE, 0, NULL, NULL},
+  { NULL, '\0', POPT_ARG_CALLBACK, (void *)displayArgs, 0, NULL, NULL },
+  { "help", '?', 0, NULL, (int)'?', N_("Show this help message"), NULL },
+  { "usage", '\0', 0, NULL, (int)'u', N_("Display brief usage message"), NULL },
 #ifdef NOTYET
   { "defaults", '\0', POPT_ARG_NONE, &show_option_defaults, 0,
        N_("Display option defaults in message"), NULL },
 #endif
+  { NULL, '\0',        0, NULL, 0, N_("Terminate options"), NULL },
     POPT_TABLEEND
 } ;
 
-/*@observer@*/ /*@unchecked@*/
 struct poptOption * poptHelpOptionsI18N = poptHelpOptions2;
-/*@=castfcnptr@*/
+
+#define        _POPTHELP_MAXLINE       ((size_t)79)
+
+typedef struct columns_s {
+    size_t cur;
+    size_t max;
+} * columns_t;
+
+/** 
+ * Return no. of columns in output window.
+ * @param fp           FILE
+ * @return             no. of columns 
+ */ 
+static size_t maxColumnWidth(FILE *fp)
+{   
+    size_t maxcols = _POPTHELP_MAXLINE;
+#if defined(TIOCGWINSZ)
+    struct winsize ws;
+    int fdno = fileno(fp ? fp : stdout);
+
+    memset(&ws, 0, sizeof(ws));
+    if (fdno >= 0 && !ioctl(fdno, (unsigned long)TIOCGWINSZ, &ws)) {
+       size_t ws_col = (size_t)ws.ws_col;
+       if (ws_col > maxcols && ws_col < (size_t)256)
+           maxcols = ws_col - 1;
+    }
+#endif
+    return maxcols;
+}   
 
 /**
- * @param table                option(s)
+ * Determine number of display characters in a string.
+ * @param s            string
+ * @return             no. of display characters.
  */
-/*@observer@*/ /*@null@*/ static const char *
-getTableTranslationDomain(/*@null@*/ const struct poptOption *table)
-       /*@*/
+static inline size_t stringDisplayWidth(const char *s)
 {
-    const struct poptOption *opt;
+    size_t n = strlen(s);
+#ifdef HAVE_MBSRTOWCS
+    mbstate_t t;
 
-    if (table != NULL)
-    for (opt = table; opt->longName || opt->shortName || opt->arg; opt++) {
+    memset ((void *)&t, 0, sizeof (t));        /* In initial state.  */
+    /* Determine number of display characters.  */
+    n = mbsrtowcs (NULL, &s, n, &t);
+#else
+    n = 0;
+    for (; *s; s = POPT_next_char(s))
+       n++;
+#endif
+
+    return n;
+}
+
+/**
+ * @param opt          option(s)
+ */
+static const char *
+getTableTranslationDomain(const struct poptOption *opt)
+{
+    if (opt != NULL)
+    for (; opt->longName || opt->shortName || opt->arg; opt++) {
        if (opt->argInfo == POPT_ARG_INTL_DOMAIN)
            return opt->arg;
     }
@@ -106,32 +151,46 @@ getTableTranslationDomain(/*@null@*/ const struct poptOption *table)
  * @param opt          option(s)
  * @param translation_domain   translation domain
  */
-/*@observer@*/ /*@null@*/ static const char *
+static const char *
 getArgDescrip(const struct poptOption * opt,
-               /*@-paramuse@*/ /* FIX: i18n macros disabled with lclint */
-               /*@null@*/ UNUSED(const char * translation_domain))
-               /*@=paramuse@*/
-       /*@*/
+               /* FIX: i18n macros disabled with lclint */
+               const char * translation_domain)
 {
-    if (!(opt->argInfo & POPT_ARG_MASK)) return NULL;
-
-    if (opt == (poptHelpOptions + 1) || opt == (poptHelpOptions + 2))
-       if (opt->argDescrip) return POPT_(opt->argDescrip);
-
-    if (opt->argDescrip) return D_(translation_domain, opt->argDescrip);
+    if (!poptArgType(opt)) return NULL;
+
+    if (poptArgType(opt) == POPT_ARG_MAINCALL)
+       return opt->argDescrip;
+    if (poptArgType(opt) == POPT_ARG_ARGV)
+       return opt->argDescrip;
+
+    if (opt->argDescrip) {
+       /* Some strings need popt library, not application, i18n domain. */
+       if (opt == (poptHelpOptions + 1)
+        || opt == (poptHelpOptions + 2)
+        || !strcmp(opt->argDescrip, N_("Help options:"))
+        || !strcmp(opt->argDescrip, N_("Options implemented via popt alias/exec:")))
+           return POPT_(opt->argDescrip);
+
+       /* Use the application i18n domain. */
+       return D_(translation_domain, opt->argDescrip);
+    }
 
-    switch (opt->argInfo & POPT_ARG_MASK) {
-    /*case POPT_ARG_NONE:      return POPT_("NONE");*/ /* impossible */
+    switch (poptArgType(opt)) {
+    case POPT_ARG_NONE:                return POPT_("NONE");
 #ifdef DYING
     case POPT_ARG_VAL:         return POPT_("VAL");
 #else
     case POPT_ARG_VAL:         return NULL;
 #endif
     case POPT_ARG_INT:         return POPT_("INT");
+    case POPT_ARG_SHORT:       return POPT_("SHORT");
     case POPT_ARG_LONG:                return POPT_("LONG");
+    case POPT_ARG_LONGLONG:    return POPT_("LONGLONG");
     case POPT_ARG_STRING:      return POPT_("STRING");
     case POPT_ARG_FLOAT:       return POPT_("FLOAT");
     case POPT_ARG_DOUBLE:      return POPT_("DOUBLE");
+    case POPT_ARG_MAINCALL:    return NULL;
+    case POPT_ARG_ARGV:                return NULL;
     default:                   return POPT_("ARG");
     }
 }
@@ -143,59 +202,62 @@ getArgDescrip(const struct poptOption * opt,
  * @param translation_domain   translation domain
  * @return
  */
-static /*@only@*/ /*@null@*/ char *
+static char *
 singleOptionDefaultValue(size_t lineLength,
                const struct poptOption * opt,
-               /*@-paramuse@*/ /* FIX: i18n macros disabled with lclint */
-               /*@null@*/ UNUSED(const char * translation_domain))
-               /*@=paramuse@*/
-       /*@*/
+               /* FIX: i18n macros disabled with lclint */
+               const char * translation_domain)
 {
     const char * defstr = D_(translation_domain, "default");
-    size_t limit, bufsize = 4*lineLength + 1;
-    char * le = malloc(bufsize);
+    char * le = malloc(4*lineLength + 1);
     char * l = le;
 
     if (le == NULL) return NULL;       /* XXX can't happen */
-/*@-boundswrite@*/
+    *le = '\0';
     *le++ = '(';
-    le += strlcpy(le, defstr, bufsize - 3);
+    le = stpcpy(le, defstr);
     *le++ = ':';
     *le++ = ' ';
-    limit = bufsize - (le - l) - 1; /* -1 for closing paren */
-    if (opt->arg)      /* XXX programmer error */
-    switch (opt->argInfo & POPT_ARG_MASK) {
+  if (opt->arg) {      /* XXX programmer error */
+    poptArg arg = { .ptr = opt->arg };
+    switch (poptArgType(opt)) {
     case POPT_ARG_VAL:
     case POPT_ARG_INT:
-    {  long aLong = *((int *)opt->arg);
-       le += snprintf(le, limit, "%ld", aLong);
-    }  break;
+       le += sprintf(le, "%d", arg.intp[0]);
+       break;
+    case POPT_ARG_SHORT:
+       le += sprintf(le, "%hd", arg.shortp[0]);
+       break;
     case POPT_ARG_LONG:
-    {  long aLong = *((long *)opt->arg);
-       le += snprintf(le, limit, "%ld", aLong);
-    }  break;
+       le += sprintf(le, "%ld", arg.longp[0]);
+       break;
+    case POPT_ARG_LONGLONG:
+       le += sprintf(le, "%lld", arg.longlongp[0]);
+       break;
     case POPT_ARG_FLOAT:
-    {  double aDouble = *((float *)opt->arg);
-       le += snprintf(le, limit, "%g", aDouble);
+    {  double aDouble = (double) arg.floatp[0];
+       le += sprintf(le, "%g", aDouble);
     }  break;
     case POPT_ARG_DOUBLE:
-    {  double aDouble = *((double *)opt->arg);
-       le += snprintf(le, limit, "%g", aDouble);
-    }  break;
+       le += sprintf(le, "%g", arg.doublep[0]);
+       break;
+    case POPT_ARG_MAINCALL:
+       le += sprintf(le, "%p", opt->arg);
+       break;
+    case POPT_ARG_ARGV:
+       le += sprintf(le, "%p", opt->arg);
+       break;
     case POPT_ARG_STRING:
-    {  const char * s = *(const char **)opt->arg;
-       if (s == NULL) {
-           le += strlcpy(le, "null", limit);
-       else {
-           size_t len;
-           limit -= 2; /* make room for quotes */
+    {  const char * s = arg.argv[0];
+       if (s == NULL)
+           le = stpcpy(le, "null");
+       else {
+           size_t limit = 4*lineLength - (le - l) - sizeof("\"\")");
+           size_t slen;
            *le++ = '"';
-           len = strlcpy(le, s, limit);
-           if (len >= limit) {
-               le += limit - 3 - 1;
-               *le++ = '.'; *le++ = '.'; *le++ = '.';
-           } else
-               le += len;
+           strncpy(le, s, limit); le[limit] = '\0'; le += (slen = strlen(le));
+           if (slen == limit && s[limit])
+               le[-1] = le[-2] = le[-3] = '.';
            *le++ = '"';
        }
     }  break;
@@ -203,11 +265,11 @@ singleOptionDefaultValue(size_t lineLength,
     default:
        l = _free(l);
        return NULL;
-       /*@notreached@*/ break;
+       break;
     }
+  }
     *le++ = ')';
     *le = '\0';
-/*@=boundswrite@*/
 
     return l;
 }
@@ -215,80 +277,101 @@ singleOptionDefaultValue(size_t lineLength,
 /**
  * Display help text for an option.
  * @param fp           output file handle
- * @param maxLeftCol   largest argument display width
+ * @param columns      output display width control
  * @param opt          option(s)
  * @param translation_domain   translation domain
  */
-static void singleOptionHelp(FILE * fp, size_t maxLeftCol, 
+static void singleOptionHelp(FILE * fp, columns_t columns,
                const struct poptOption * opt,
-               /*@null@*/ UNUSED(const char * translation_domain))
-       /*@globals fileSystem @*/
-       /*@modifies *fp, fileSystem @*/
+               const char * translation_domain)
 {
+    size_t maxLeftCol = columns->cur;
     size_t indentLength = maxLeftCol + 5;
-    size_t lineLength = 79 - indentLength;
+    size_t lineLength = columns->max - indentLength;
     const char * help = D_(translation_domain, opt->descrip);
     const char * argDescrip = getArgDescrip(opt, translation_domain);
+    /* Display shortName iff printable non-space. */
+    int prtshort = (int)(isprint((int)opt->shortName) && opt->shortName != ' ');
     size_t helpLength;
     char * defs = NULL;
     char * left;
-    size_t lelen, limit;
     size_t nb = maxLeftCol + 1;
     int displaypad = 0;
 
     /* Make sure there's more than enough room in target buffer. */
     if (opt->longName) nb += strlen(opt->longName);
+    if (F_ISSET(opt, TOGGLE)) nb += sizeof("[no]") - 1;
     if (argDescrip)    nb += strlen(argDescrip);
 
-/*@-boundswrite@*/
     left = malloc(nb);
     if (left == NULL) return;  /* XXX can't happen */
     left[0] = '\0';
     left[maxLeftCol] = '\0';
 
-    if (opt->longName && opt->shortName)
-       snprintf(left, nb, "-%c, %s%s", opt->shortName,
-               ((opt->argInfo & POPT_ARGFLAG_ONEDASH) ? "-" : "--"),
-               opt->longName);
-    else if (opt->shortName != '\0') 
-       snprintf(left, nb, "-%c", opt->shortName);
-    else if (opt->longName)
-       snprintf(left, nb, "%s%s",
-               ((opt->argInfo & POPT_ARGFLAG_ONEDASH) ? "-" : "--"),
-               opt->longName);
-    if (!*left) goto out;
+#define        prtlong (opt->longName != NULL) /* XXX splint needs a clue */
+    if (!(prtshort || prtlong))
+       goto out;
+    if (prtshort && prtlong) {
+       const char *dash = F_ISSET(opt, ONEDASH) ? "-" : "--";
+       left[0] = '-';
+       left[1] = opt->shortName;
+       (void) stpcpy(stpcpy(stpcpy(left+2, ", "), dash), opt->longName);
+    } else if (prtshort) {
+       left[0] = '-';
+       left[1] = opt->shortName;
+       left[2] = '\0';
+    } else if (prtlong) {
+       /* XXX --long always padded for alignment with/without "-X, ". */
+       const char *dash = poptArgType(opt) == POPT_ARG_MAINCALL ? ""
+                        : (F_ISSET(opt, ONEDASH) ? "-" : "--");
+       const char *longName = opt->longName;
+       const char *toggle;
+       if (F_ISSET(opt, TOGGLE)) {
+           toggle = "[no]";
+           if (longName[0] == 'n' && longName[1] == 'o') {
+               longName += sizeof("no") - 1;
+               if (longName[0] == '-')
+                   longName++;
+           }
+       } else
+           toggle = "";
+       (void) stpcpy(stpcpy(stpcpy(stpcpy(left, "    "), dash), toggle), longName);
+    }
+#undef prtlong
 
     if (argDescrip) {
        char * le = left + strlen(left);
 
-       if (opt->argInfo & POPT_ARGFLAG_OPTIONAL)
+       if (F_ISSET(opt, OPTIONAL))
            *le++ = '[';
 
        /* Choose type of output */
-       /*@-branchstate@*/
-       if (opt->argInfo & POPT_ARGFLAG_SHOW_DEFAULT) {
+       if (F_ISSET(opt, SHOW_DEFAULT)) {
            defs = singleOptionDefaultValue(lineLength, opt, translation_domain);
            if (defs) {
-               size_t bufsize = (help ? strlen(help) : 0) + sizeof " " + strlen(defs);
-               char * t = malloc(bufsize);
+               char * t = malloc((help ? strlen(help) : 0) +
+                               strlen(defs) + sizeof(" "));
                if (t) {
-                   snprintf(t, bufsize, "%s %s", help ? help : "", defs);
+                   char * te = t;
+                   if (help)
+                       te = stpcpy(te, help);
+                   *te++ = ' ';
+                   strcpy(te, defs);
                    defs = _free(defs);
+                   defs = t;
                }
-               defs = t;
            }
        }
-       /*@=branchstate@*/
 
        if (opt->argDescrip == NULL) {
-           switch (opt->argInfo & POPT_ARG_MASK) {
+           switch (poptArgType(opt)) {
            case POPT_ARG_NONE:
                break;
            case POPT_ARG_VAL:
 #ifdef NOTNOW  /* XXX pug ugly nerdy output */
            {   long aLong = opt->val;
-               int ops = (opt->argInfo & POPT_ARGFLAG_LOGICALOPS);
-               int negate = (opt->argInfo & POPT_ARGFLAG_NOT);
+               int ops = F_ISSET(opt, LOGICALOPS);
+               int negate = F_ISSET(opt, NOT);
 
                /* Don't bother displaying typical values */
                if (!ops && (aLong == 0L || aLong == 1L || aLong == -1L))
@@ -297,111 +380,102 @@ static void singleOptionHelp(FILE * fp, size_t maxLeftCol,
                switch (ops) {
                case POPT_ARGFLAG_OR:
                    *le++ = '|';
-                   /*@innerbreak@*/ break;
+                   break;
                case POPT_ARGFLAG_AND:
                    *le++ = '&';
-                   /*@innerbreak@*/ break;
+                   break;
                case POPT_ARGFLAG_XOR:
                    *le++ = '^';
-                   /*@innerbreak@*/ break;
+                   break;
                default:
-                   /*@innerbreak@*/ break;
+                   break;
                }
                *le++ = (opt->longName != NULL ? '=' : ' ');
                if (negate) *le++ = '~';
-               /*@-formatconst@*/
-               limit = nb - (le - left);
-               lelen = snprintf(le, limit, (ops ? "0x%lx" : "%ld"), aLong);
-               le += lelen >= limit ? limit - 1 : lelen;
-               /*@=formatconst@*/
+               le += sprintf(le, (ops ? "0x%lx" : "%ld"), aLong);
                *le++ = ']';
            }
 #endif
                break;
            case POPT_ARG_INT:
+           case POPT_ARG_SHORT:
            case POPT_ARG_LONG:
+           case POPT_ARG_LONGLONG:
            case POPT_ARG_FLOAT:
            case POPT_ARG_DOUBLE:
            case POPT_ARG_STRING:
                *le++ = (opt->longName != NULL ? '=' : ' ');
-               limit = nb - (le - left);
-               lelen = strlcpy(le, argDescrip, limit);
-               le += lelen >= limit ? limit - 1 : lelen;
+               le = stpcpy(le, argDescrip);
                break;
            default:
                break;
            }
        } else {
+           char *leo;
 
-           *le++ = '=';
-           limit = nb - (le - left);
-           lelen = strlcpy(le, argDescrip, limit);
-           if (lelen >= limit)
-               lelen = limit - 1;
-           le += lelen;
-
-#ifdef POPT_WCHAR_HACK
-           {   const char * scopy = argDescrip;
-               mbstate_t t;
-               size_t n;
-
-               memset ((void *)&t, '\0', sizeof (t));  /* In initial state.  */
-               /* Determine number of characters.  */
-               n = mbsrtowcs (NULL, &scopy, strlen(scopy), &t);
+           /* XXX argDescrip[0] determines "--foo=bar" or "--foo bar". */
+           if (!strchr(" =(", argDescrip[0]))
+               *le++ = ((poptArgType(opt) == POPT_ARG_MAINCALL) ? ' ' :
+                        (poptArgType(opt) == POPT_ARG_ARGV) ? ' ' :
+                        opt->longName == NULL ? ' ' : '=');
+           le = stpcpy(leo = le, argDescrip);
 
-               displaypad = (int) (lelen-n);
-           }
-#endif
+           /* Adjust for (possible) wide characters. */
+           displaypad = (int)((le - leo) - stringDisplayWidth(argDescrip));
        }
-       if (opt->argInfo & POPT_ARGFLAG_OPTIONAL)
+       if (F_ISSET(opt, OPTIONAL))
            *le++ = ']';
        *le = '\0';
     }
-/*@=boundswrite@*/
 
     if (help)
-       fprintf(fp,"  %-*s   ", (int)maxLeftCol+displaypad, left);
+       POPT_fprintf(fp,"  %-*s   ", (int)(maxLeftCol+displaypad), left);
     else {
-       fprintf(fp,"  %s\n", left); 
+       POPT_fprintf(fp,"  %s\n", left);
        goto out;
     }
 
     left = _free(left);
-/*@-branchstate@*/
-    if (defs) {
+    if (defs)
        help = defs;
-       defs = NULL;
-    }
-/*@=branchstate@*/
 
     helpLength = strlen(help);
-/*@-boundsread@*/
     while (helpLength > lineLength) {
        const char * ch;
        char format[16];
 
        ch = help + lineLength - 1;
-       while (ch > help && !isSpace(ch)) ch--;
+       while (ch > help && !_isspaceptr(ch))
+           ch = POPT_prev_char(ch);
        if (ch == help) break;          /* give up */
-       while (ch > (help + 1) && isSpace(ch)) ch--;
-       ch++;
+       while (ch > (help + 1) && _isspaceptr(ch))
+           ch = POPT_prev_char (ch);
+       ch = POPT_next_char(ch);
+
+       /*
+        *  XXX strdup is necessary to add NUL terminator so that an unknown
+        *  no. of (possible) multi-byte characters can be displayed.
+        */
+       {   char * fmthelp = xstrdup(help);
+           if (fmthelp) {
+               fmthelp[ch - help] = '\0';
+               sprintf(format, "%%s\n%%%ds", (int) indentLength);
+               POPT_fprintf(fp, format, fmthelp, " ");
+               free(fmthelp);
+           }
+       }
 
-       snprintf(format, sizeof format, "%%.%ds\n%%%ds", (int) (ch - help), (int) indentLength);
-       /*@-formatconst@*/
-       fprintf(fp, format, help, " ");
-       /*@=formatconst@*/
        help = ch;
-       while (isSpace(help) && *help) help++;
+       while (_isspaceptr(help) && *help)
+           help = POPT_next_char(help);
        helpLength = strlen(help);
     }
-/*@=boundsread@*/
 
     if (helpLength) fprintf(fp, "%s\n", help);
+    help = NULL;
 
 out:
-    /*@-dependenttrans@*/
     defs = _free(defs);
-    /*@=dependenttrans@*/
     left = _free(left);
 }
 
@@ -412,54 +486,45 @@ out:
  * @return             display width
  */
 static size_t maxArgWidth(const struct poptOption * opt,
-                      /*@null@*/ UNUSED(const char * translation_domain))
-       /*@*/
+                      const char * translation_domain)
 {
     size_t max = 0;
     size_t len = 0;
-    const char * s;
+    const char * argDescrip;
     
     if (opt != NULL)
     while (opt->longName || opt->shortName || opt->arg) {
-       if ((opt->argInfo & POPT_ARG_MASK) == POPT_ARG_INCLUDE_TABLE) {
-           if (opt->arg)       /* XXX program error */
-           len = maxArgWidth(opt->arg, translation_domain);
+       if (poptArgType(opt) == POPT_ARG_INCLUDE_TABLE) {
+           void * arg = opt->arg;
+           /* XXX sick hack to preserve pretense of ABI. */
+           if (arg == poptHelpOptions)
+               arg = poptHelpOptionsI18N;
+           if (arg)    /* XXX program error */
+               len = maxArgWidth(arg, translation_domain);
            if (len > max) max = len;
-       } else if (!(opt->argInfo & POPT_ARGFLAG_DOC_HIDDEN)) {
+       } else if (!F_ISSET(opt, DOC_HIDDEN)) {
            len = sizeof("  ")-1;
-           if (opt->shortName != '\0') len += sizeof("-X")-1;
-           if (opt->shortName != '\0' && opt->longName) len += sizeof(", ")-1;
+           /* XXX --long always padded for alignment with/without "-X, ". */
+           len += sizeof("-X, ")-1;
            if (opt->longName) {
-               len += ((opt->argInfo & POPT_ARGFLAG_ONEDASH)
-                       ? sizeof("-")-1 : sizeof("--")-1);
+               len += (F_ISSET(opt, ONEDASH) ? sizeof("-") : sizeof("--")) - 1;
                len += strlen(opt->longName);
            }
 
-           s = getArgDescrip(opt, translation_domain);
-
-#ifdef POPT_WCHAR_HACK
-           /* XXX Calculate no. of display characters. */
-           if (s) {
-               const char * scopy = s;
-               mbstate_t t;
-               size_t n;
-
-/*@-boundswrite@*/
-               memset ((void *)&t, '\0', sizeof (t));  /* In initial state.  */
-/*@=boundswrite@*/
-               /* Determine number of characters.  */
-               n = mbsrtowcs (NULL, &scopy, strlen(scopy), &t);
-               len += sizeof("=")-1 + n;
+           argDescrip = getArgDescrip(opt, translation_domain);
+
+           if (argDescrip) {
+
+               /* XXX argDescrip[0] determines "--foo=bar" or "--foo bar". */
+               if (!strchr(" =(", argDescrip[0])) len += sizeof("=")-1;
+
+               /* Adjust for (possible) wide characters. */
+               len += stringDisplayWidth(argDescrip);
            }
-#else
-           if (s)
-               len += sizeof("=")-1 + strlen(s);
-#endif
 
-           if (opt->argInfo & POPT_ARGFLAG_OPTIONAL) len += sizeof("[]")-1;
+           if (F_ISSET(opt, OPTIONAL)) len += sizeof("[]")-1;
            if (len > max) max = len;
        }
-
        opt++;
     }
     
@@ -471,14 +536,13 @@ static size_t maxArgWidth(const struct poptOption * opt,
  * @param fp           output file handle
  * @param items                alias/exec array
  * @param nitems       no. of alias/exec entries
- * @param left         largest argument display width
+ * @param columns      output display width control
  * @param translation_domain   translation domain
  */
 static void itemHelp(FILE * fp,
-               /*@null@*/ poptItem items, int nitems, size_t left,
-               /*@null@*/ UNUSED(const char * translation_domain))
-       /*@globals fileSystem @*/
-       /*@modifies *fp, fileSystem @*/
+               poptItem items, int nitems,
+               columns_t columns,
+               const char * translation_domain)
 {
     poptItem item;
     int i;
@@ -487,9 +551,8 @@ static void itemHelp(FILE * fp,
     for (i = 0, item = items; i < nitems; i++, item++) {
        const struct poptOption * opt;
        opt = &item->option;
-       if ((opt->longName || opt->shortName) && 
-           !(opt->argInfo & POPT_ARGFLAG_DOC_HIDDEN))
-           singleOptionHelp(fp, left, opt, translation_domain);
+       if ((opt->longName || opt->shortName) && !F_ISSET(opt, DOC_HIDDEN))
+           singleOptionHelp(fp, columns, opt, translation_domain);
     }
 }
 
@@ -498,43 +561,48 @@ static void itemHelp(FILE * fp,
  * @param con          context
  * @param fp           output file handle
  * @param table                option(s)
- * @param left         largest argument display width
+ * @param columns      output display width control
  * @param translation_domain   translation domain
  */
 static void singleTableHelp(poptContext con, FILE * fp,
-               /*@null@*/ const struct poptOption * table, size_t left,
-               /*@null@*/ UNUSED(const char * translation_domain))
-       /*@globals fileSystem @*/
-       /*@modifies *fp, fileSystem @*/
+               const struct poptOption * table,
+               columns_t columns,
+               const char * translation_domain)
 {
     const struct poptOption * opt;
     const char *sub_transdom;
 
     if (table == poptAliasOptions) {
-       itemHelp(fp, con->aliases, con->numAliases, left, NULL);
-       itemHelp(fp, con->execs, con->numExecs, left, NULL);
+       itemHelp(fp, con->aliases, con->numAliases, columns, NULL);
+       itemHelp(fp, con->execs, con->numExecs, columns, NULL);
        return;
     }
 
     if (table != NULL)
-    for (opt = table; (opt->longName || opt->shortName || opt->arg); opt++) {
-       if ((opt->longName || opt->shortName) && 
-           !(opt->argInfo & POPT_ARGFLAG_DOC_HIDDEN))
-           singleOptionHelp(fp, left, opt, translation_domain);
+    for (opt = table; opt->longName || opt->shortName || opt->arg; opt++) {
+       if ((opt->longName || opt->shortName) && !F_ISSET(opt, DOC_HIDDEN))
+           singleOptionHelp(fp, columns, opt, translation_domain);
     }
 
     if (table != NULL)
-    for (opt = table; (opt->longName || opt->shortName || opt->arg); opt++) {
-       if ((opt->argInfo & POPT_ARG_MASK) != POPT_ARG_INCLUDE_TABLE)
+    for (opt = table; opt->longName || opt->shortName || opt->arg; opt++) {
+       void * arg = opt->arg;
+       if (poptArgType(opt) != POPT_ARG_INCLUDE_TABLE)
            continue;
-       sub_transdom = getTableTranslationDomain(opt->arg);
+       /* XXX sick hack to preserve pretense of ABI. */
+       if (arg == poptHelpOptions)
+           arg = poptHelpOptionsI18N;
+       sub_transdom = getTableTranslationDomain(arg);
        if (sub_transdom == NULL)
            sub_transdom = translation_domain;
            
+       /* If no popt aliases/execs, skip poptAliasOption processing. */
+       if (arg == poptAliasOptions && !(con->numAliases || con->numExecs))
+           continue;
        if (opt->descrip)
-           fprintf(fp, "\n%s\n", D_(sub_transdom, opt->descrip));
+           POPT_fprintf(fp, "\n%s\n", D_(sub_transdom, opt->descrip));
 
-       singleTableHelp(con, fp, opt->arg, left, sub_transdom);
+       singleTableHelp(con, fp, arg, columns, sub_transdom);
     }
 }
 
@@ -542,22 +610,18 @@ static void singleTableHelp(poptContext con, FILE * fp,
  * @param con          context
  * @param fp           output file handle
  */
-static int showHelpIntro(poptContext con, FILE * fp)
-       /*@globals fileSystem @*/
-       /*@modifies *fp, fileSystem @*/
+static size_t showHelpIntro(poptContext con, FILE * fp)
 {
-    int len = 6;
-    const char * fn;
+    const char *usage_str = POPT_("Usage:");
+    size_t len = strlen(usage_str);
+    POPT_fprintf(fp, "%s", usage_str);
 
-    fprintf(fp, POPT_("Usage:"));
     if (!(con->flags & POPT_CONTEXT_KEEP_FIRST)) {
-/*@-boundsread@*/
-       /*@-nullderef -type@*/  /* LCL: wazzup? */
-       fn = con->optionStack->argv[0];
-       /*@=nullderef =type@*/
-/*@=boundsread@*/
+       struct optionStackEntry * os = con->optionStack;
+       const char * fn = (os->argv ? os->argv[0] : NULL);
        if (fn == NULL) return len;
        if (strchr(fn, '/')) fn = strrchr(fn, '/') + 1;
+       /* XXX POPT_fprintf not needed for argv[0] display. */
        fprintf(fp, " %s", fn);
        len += strlen(fn) + 1;
     }
@@ -565,126 +629,114 @@ static int showHelpIntro(poptContext con, FILE * fp)
     return len;
 }
 
-void poptPrintHelp(poptContext con, FILE * fp, /*@unused@*/ UNUSED(int flags))
+void poptPrintHelp(poptContext con, FILE * fp, UNUSED(int flags))
 {
-    size_t leftColWidth;
+    columns_t columns = calloc((size_t)1, sizeof(*columns));
 
     (void) showHelpIntro(con, fp);
     if (con->otherHelp)
-       fprintf(fp, " %s\n", con->otherHelp);
+       POPT_fprintf(fp, " %s\n", con->otherHelp);
     else
-       fprintf(fp, " %s\n", POPT_("[OPTION...]"));
+       POPT_fprintf(fp, " %s\n", POPT_("[OPTION...]"));
 
-    leftColWidth = maxArgWidth(con->options, NULL);
-    singleTableHelp(con, fp, con->options, leftColWidth, NULL);
+    if (columns) {
+       columns->cur = maxArgWidth(con->options, NULL);
+       columns->max = maxColumnWidth(fp);
+       singleTableHelp(con, fp, con->options, columns, NULL);
+       free(columns);
+    }
 }
 
 /**
  * Display usage text for an option.
  * @param fp           output file handle
- * @param cursor       current display position
+ * @param columns      output display width control
  * @param opt          option(s)
  * @param translation_domain   translation domain
  */
-static size_t singleOptionUsage(FILE * fp, size_t cursor, 
+static size_t singleOptionUsage(FILE * fp, columns_t columns,
                const struct poptOption * opt,
-               /*@null@*/ const char *translation_domain)
-       /*@globals fileSystem @*/
-       /*@modifies *fp, fileSystem @*/
+               const char *translation_domain)
 {
-    size_t len = 4;
-    char shortStr[2] = { '\0', '\0' };
-    const char * item = shortStr;
+    size_t len = sizeof(" []")-1;
     const char * argDescrip = getArgDescrip(opt, translation_domain);
-
-    if (opt->shortName != '\0' && opt->longName != NULL) {
-       len += 2;
-       if (!(opt->argInfo & POPT_ARGFLAG_ONEDASH)) len++;
+    /* Display shortName iff printable non-space. */
+    int prtshort = (int)(isprint((int)opt->shortName) && opt->shortName != ' ');
+
+#define        prtlong (opt->longName != NULL) /* XXX splint needs a clue */
+    if (!(prtshort || prtlong))
+       return columns->cur;
+
+    len = sizeof(" []")-1;
+    if (prtshort)
+       len += sizeof("-c")-1;
+    if (prtlong) {
+       if (prtshort) len += sizeof("|")-1;
+       len += (F_ISSET(opt, ONEDASH) ? sizeof("-") : sizeof("--")) - 1;
        len += strlen(opt->longName);
-    } else if (opt->shortName != '\0') {
-       len++;
-       shortStr[0] = opt->shortName;
-       shortStr[1] = '\0';
-    } else if (opt->longName) {
-       len += strlen(opt->longName);
-       if (!(opt->argInfo & POPT_ARGFLAG_ONEDASH)) len++;
-       item = opt->longName;
     }
 
-    if (len == 4) return cursor;
-
-#ifdef POPT_WCHAR_HACK
-    /* XXX Calculate no. of display characters. */
     if (argDescrip) {
-       const char * scopy = argDescrip;
-       mbstate_t t;
-       size_t n;
-
-/*@-boundswrite@*/
-       memset ((void *)&t, '\0', sizeof (t));  /* In initial state.  */
-/*@=boundswrite@*/
-       /* Determine number of characters.  */
-       n = mbsrtowcs (NULL, &scopy, strlen(scopy), &t);
-       len += sizeof("=")-1 + n;
+
+       /* XXX argDescrip[0] determines "--foo=bar" or "--foo bar". */
+       if (!strchr(" =(", argDescrip[0])) len += sizeof("=")-1;
+
+       /* Adjust for (possible) wide characters. */
+       len += stringDisplayWidth(argDescrip);
     }
-#else
-    if (argDescrip) 
-       len += sizeof("=")-1 + strlen(argDescrip);
-#endif
 
-    if ((cursor + len) > 79) {
+    if ((columns->cur + len) > columns->max) {
        fprintf(fp, "\n       ");
-       cursor = 7;
+       columns->cur = (size_t)7;
     } 
 
-    if (opt->longName && opt->shortName) {
-       fprintf(fp, " [-%c|-%s%s%s%s]",
-           opt->shortName, ((opt->argInfo & POPT_ARGFLAG_ONEDASH) ? "" : "-"),
-           opt->longName,
-           (argDescrip ? " " : ""),
-           (argDescrip ? argDescrip : ""));
-    } else {
-       fprintf(fp, " [-%s%s%s%s]",
-           ((opt->shortName || (opt->argInfo & POPT_ARGFLAG_ONEDASH)) ? "" : "-"),
-           item,
-           (argDescrip ? (opt->shortName != '\0' ? " " : "=") : ""),
-           (argDescrip ? argDescrip : ""));
+    fprintf(fp, " [");
+    if (prtshort)
+       fprintf(fp, "-%c", opt->shortName);
+    if (prtlong)
+       fprintf(fp, "%s%s%s",
+               (prtshort ? "|" : ""),
+               (F_ISSET(opt, ONEDASH) ? "-" : "--"),
+               opt->longName);
+#undef prtlong
+
+    if (argDescrip) {
+       /* XXX argDescrip[0] determines "--foo=bar" or "--foo bar". */
+       if (!strchr(" =(", argDescrip[0])) fputc(opt->longName == NULL ? ' ' : '=', fp);
+       fprintf(fp, "%s", argDescrip);
     }
+    fprintf(fp, "]");
 
-    return cursor + len + 1;
+    return columns->cur + len + 1;
 }
 
 /**
  * Display popt alias and exec usage.
  * @param fp           output file handle
- * @param cursor       current display position
+ * @param columns      output display width control
  * @param item         alias/exec array
  * @param nitems       no. of ara/exec entries
  * @param translation_domain   translation domain
  */
-static size_t itemUsage(FILE * fp, size_t cursor,
-               /*@null@*/ poptItem item, int nitems,
-               /*@null@*/ UNUSED(const char * translation_domain))
-       /*@globals fileSystem @*/
-       /*@modifies *fp, fileSystem @*/
+static size_t itemUsage(FILE * fp, columns_t columns,
+               poptItem item, int nitems,
+               const char * translation_domain)
 {
     int i;
 
-    /*@-branchstate@*/         /* FIX: W2DO? */
     if (item != NULL)
     for (i = 0; i < nitems; i++, item++) {
        const struct poptOption * opt;
        opt = &item->option;
-        if ((opt->argInfo & POPT_ARG_MASK) == POPT_ARG_INTL_DOMAIN) {
+        if (poptArgType(opt) == POPT_ARG_INTL_DOMAIN) {
            translation_domain = (const char *)opt->arg;
-       } else if ((opt->longName || opt->shortName) &&
-                !(opt->argInfo & POPT_ARGFLAG_DOC_HIDDEN)) {
-           cursor = singleOptionUsage(fp, cursor, opt, translation_domain);
+       } else
+       if ((opt->longName || opt->shortName) && !F_ISSET(opt, DOC_HIDDEN)) {
+           columns->cur = singleOptionUsage(fp, columns, opt, translation_domain);
        }
     }
-    /*@=branchstate@*/
 
-    return cursor;
+    return columns->cur;
 }
 
 /**
@@ -700,53 +752,51 @@ typedef struct poptDone_s {
  * Display usage text for a table of options.
  * @param con          context
  * @param fp           output file handle
- * @param cursor       current display position
+ * @param columns      output display width control
  * @param opt          option(s)
  * @param translation_domain   translation domain
  * @param done         tables already processed
  * @return
  */
-static size_t singleTableUsage(poptContext con, FILE * fp, size_t cursor,
-               /*@null@*/ const struct poptOption * opt,
-               /*@null@*/ UNUSED(const char * translation_domain),
-               /*@null@*/ poptDone done)
-       /*@globals fileSystem @*/
-       /*@modifies *fp, done, fileSystem @*/
+static size_t singleTableUsage(poptContext con, FILE * fp, columns_t columns,
+               const struct poptOption * opt,
+               const char * translation_domain,
+               poptDone done)
 {
-    /*@-branchstate@*/         /* FIX: W2DO? */
     if (opt != NULL)
     for (; (opt->longName || opt->shortName || opt->arg) ; opt++) {
-        if ((opt->argInfo & POPT_ARG_MASK) == POPT_ARG_INTL_DOMAIN) {
+        if (poptArgType(opt) == POPT_ARG_INTL_DOMAIN) {
            translation_domain = (const char *)opt->arg;
-       } else if ((opt->argInfo & POPT_ARG_MASK) == POPT_ARG_INCLUDE_TABLE) {
+       } else
+       if (poptArgType(opt) == POPT_ARG_INCLUDE_TABLE) {
+           void * arg = opt->arg;
+           /* XXX sick hack to preserve pretense of ABI. */
+           if (arg == poptHelpOptions)
+               arg = poptHelpOptionsI18N;
            if (done) {
                int i = 0;
+               if (done->opts != NULL)
                for (i = 0; i < done->nopts; i++) {
-/*@-boundsread@*/
                    const void * that = done->opts[i];
-/*@=boundsread@*/
-                   if (that == NULL || that != opt->arg)
-                       /*@innercontinue@*/ continue;
-                   /*@innerbreak@*/ break;
+                   if (that == NULL || that != arg)
+                       continue;
+                   break;
                }
                /* Skip if this table has already been processed. */
-               if (opt->arg == NULL || i < done->nopts)
+               if (arg == NULL || i < done->nopts)
                    continue;
-/*@-boundswrite@*/
-               if (done->nopts < done->maxopts)
-                   done->opts[done->nopts++] = (const void *) opt->arg;
-/*@=boundswrite@*/
+               if (done->opts != NULL && done->nopts < done->maxopts)
+                   done->opts[done->nopts++] = (const void *) arg;
            }
-           cursor = singleTableUsage(con, fp, cursor, opt->arg,
+           columns->cur = singleTableUsage(con, fp, columns, opt->arg,
                        translation_domain, done);
-       } else if ((opt->longName || opt->shortName) &&
-                !(opt->argInfo & POPT_ARGFLAG_DOC_HIDDEN)) {
-           cursor = singleOptionUsage(fp, cursor, opt, translation_domain);
+       } else
+       if ((opt->longName || opt->shortName) && !F_ISSET(opt, DOC_HIDDEN)) {
+           columns->cur = singleOptionUsage(fp, columns, opt, translation_domain);
        }
     }
-    /*@=branchstate@*/
 
-    return cursor;
+    return columns->cur;
 }
 
 /**
@@ -757,66 +807,78 @@ static size_t singleTableUsage(poptContext con, FILE * fp, size_t cursor,
  * @retval str         concatenation of short options
  * @return             length of display string
  */
-static int showShortOptions(const struct poptOption * opt, FILE * fp,
-               /*@null@*/ char * str)
-       /*@globals fileSystem @*/
-       /*@modifies *str, *fp, fileSystem @*/
-       /*@requires maxRead(str) >= 0 @*/
+static size_t showShortOptions(const struct poptOption * opt, FILE * fp,
+               char * str)
 {
-    /* bufsize larger then the ascii set, lazy alloca on top level call. */
-    char * s = (str != NULL ? str : memset(alloca(300), 0, 300));
-    int len = 0;
+    /* bufsize larger then the ascii set, lazy allocation on top level call. */
+    size_t nb = (size_t)300;
+    char * s = (str != NULL ? str : calloc((size_t)1, nb));
+    size_t len = (size_t)0;
 
     if (s == NULL)
        return 0;
 
-/*@-boundswrite@*/
     if (opt != NULL)
     for (; (opt->longName || opt->shortName || opt->arg); opt++) {
-       if (opt->shortName && !(opt->argInfo & POPT_ARG_MASK))
-           s[strlen(s)] = opt->shortName;
-       else if ((opt->argInfo & POPT_ARG_MASK) == POPT_ARG_INCLUDE_TABLE)
-           if (opt->arg)       /* XXX program error */
-               len = showShortOptions(opt->arg, fp, s);
+       if (!F_ISSET(opt, DOC_HIDDEN) && opt->shortName && !poptArgType(opt))
+       {
+           /* Display shortName iff unique printable non-space. */
+           if (!strchr(s, opt->shortName) && isprint((int)opt->shortName)
+            && opt->shortName != ' ')
+               s[strlen(s)] = opt->shortName;
+       } else if (poptArgType(opt) == POPT_ARG_INCLUDE_TABLE) {
+           void * arg = opt->arg;
+           /* XXX sick hack to preserve pretense of ABI. */
+           if (arg == poptHelpOptions)
+               arg = poptHelpOptionsI18N;
+           if (arg)    /* XXX program error */
+               len = showShortOptions(arg, fp, s);
+       }
     } 
-/*@=boundswrite@*/
 
     /* On return to top level, print the short options, return print length. */
-    if (s == str && *s != '\0') {
+    if (s != str && *s != '\0') {
        fprintf(fp, " [-%s]", s);
        len = strlen(s) + sizeof(" [-]")-1;
     }
+    if (s != str)
+       free(s);
     return len;
 }
 
-void poptPrintUsage(poptContext con, FILE * fp, /*@unused@*/ UNUSED(int flags))
+void poptPrintUsage(poptContext con, FILE * fp, UNUSED(int flags))
 {
-    poptDone done = memset(alloca(sizeof(*done)), 0, sizeof(*done));
-    size_t cursor;
+    columns_t columns = calloc((size_t)1, sizeof(*columns));
+    struct poptDone_s done_buf;
+    poptDone done = &done_buf;
 
+    memset(done, 0, sizeof(*done));
     done->nopts = 0;
     done->maxopts = 64;
-    cursor = done->maxopts * sizeof(*done->opts);
-/*@-boundswrite@*/
-    done->opts = memset(alloca(cursor), 0, cursor);
-    /*@-keeptrans@*/
-    done->opts[done->nopts++] = (const void *) con->options;
-    /*@=keeptrans@*/
-/*@=boundswrite@*/
-
-    cursor = showHelpIntro(con, fp);
-    cursor += showShortOptions(con->options, fp, NULL);
-    cursor = singleTableUsage(con, fp, cursor, con->options, NULL, done);
-    cursor = itemUsage(fp, cursor, con->aliases, con->numAliases, NULL);
-    cursor = itemUsage(fp, cursor, con->execs, con->numExecs, NULL);
+  if (columns) {
+    columns->cur = done->maxopts * sizeof(*done->opts);
+    columns->max = maxColumnWidth(fp);
+    done->opts = calloc((size_t)1, columns->cur);
+    if (done->opts != NULL)
+       done->opts[done->nopts++] = (const void *) con->options;
+
+    columns->cur = showHelpIntro(con, fp);
+    columns->cur += showShortOptions(con->options, fp, NULL);
+    columns->cur = singleTableUsage(con, fp, columns, con->options, NULL, done);
+    columns->cur = itemUsage(fp, columns, con->aliases, con->numAliases, NULL);
+    columns->cur = itemUsage(fp, columns, con->execs, con->numExecs, NULL);
 
     if (con->otherHelp) {
-       cursor += strlen(con->otherHelp) + 1;
-       if (cursor > 79) fprintf(fp, "\n       ");
+       columns->cur += strlen(con->otherHelp) + 1;
+       if (columns->cur > columns->max) fprintf(fp, "\n       ");
        fprintf(fp, " %s", con->otherHelp);
     }
 
     fprintf(fp, "\n");
+    if (done->opts != NULL)
+       free(done->opts);
+    free(columns);
+  }
 }
 
 void poptSetOtherOptionHelp(poptContext con, const char * text)
diff --git a/popt/poptint.c b/popt/poptint.c
new file mode 100644 (file)
index 0000000..b8dc90f
--- /dev/null
@@ -0,0 +1,194 @@
+#include "system.h"
+#include <stdarg.h>
+#include <errno.h>
+#ifdef HAVE_LANGINFO_H
+#include <langinfo.h>
+#endif
+#include "poptint.h"
+
+/* Any pair of 32 bit hashes can be used. lookup3.c generates pairs, will do. */
+#define _JLU3_jlu32lpair        1
+#define        jlu32lpair      poptJlu32lpair
+#include "lookup3.c"
+
+const char *
+POPT_prev_char (const char *str)
+{
+    const char *p = str;
+
+    while (1) {
+       p--;
+       if (((unsigned)*p & 0xc0) != (unsigned)0x80)
+           return p;
+    }
+}
+
+const char *
+POPT_next_char (const char *str)
+{
+    const char *p = str;
+
+    while (*p != '\0') {
+       p++;
+       if (((unsigned)*p & 0xc0) != (unsigned)0x80)
+           break;
+    }
+    return p;
+}
+
+#if !defined(POPT_fprintf)     /* XXX lose all the goop ... */
+
+#if defined(ENABLE_NLS) && defined(HAVE_LIBINTL_H) && defined(HAVE_DCGETTEXT)
+/*
+ * Rebind a "UTF-8" codeset for popt's internal use.
+ */
+char *
+POPT_dgettext(const char * dom, const char * str)
+{
+    char * codeset = NULL;
+    char * retval = NULL;
+
+    if (!dom) 
+       dom = textdomain(NULL);
+    codeset = bind_textdomain_codeset(dom, NULL);
+    bind_textdomain_codeset(dom, "UTF-8");
+    retval = dgettext(dom, str);
+    bind_textdomain_codeset(dom, codeset);
+
+    return retval;
+}
+#endif
+
+#ifdef HAVE_ICONV
+/**
+ * Return malloc'd string converted from UTF-8 to current locale.
+ * @param istr         input string (UTF-8 encoding assumed)
+ * @return             localized string
+ */
+static char *
+strdup_locale_from_utf8 (char * istr)
+{
+    char * codeset = NULL;
+    char * ostr = NULL;
+    iconv_t cd;
+
+    if (istr == NULL)
+       return NULL;
+
+#ifdef HAVE_LANGINFO_H
+    codeset = nl_langinfo ((nl_item)CODESET);
+#endif
+
+    if (codeset != NULL && strcmp(codeset, "UTF-8") != 0
+     && (cd = iconv_open(codeset, "UTF-8")) != (iconv_t)-1)
+    {
+       char * shift_pin = NULL;
+       size_t db = strlen(istr);
+       char * dstr = malloc((db + 1) * sizeof(*dstr));
+       char * dstr_tmp;
+       char * pin = istr;
+       char * pout = dstr;
+       size_t ib = db;
+       size_t ob = db;
+       size_t err;
+
+       if (dstr == NULL) {
+           (void) iconv_close(cd);
+           return NULL;
+       }
+       err = iconv(cd, NULL, NULL, NULL, NULL);
+       while (1) {
+           *pout = '\0';
+           err = iconv(cd, &pin, &ib, &pout, &ob);
+           if (err != (size_t)-1) {
+               if (shift_pin == NULL) {
+                   shift_pin = pin;
+                   pin = NULL;
+                   ib = 0;
+                   continue;
+               }
+           } else
+           switch (errno) {
+           case E2BIG:
+           {   size_t used = (size_t)(pout - dstr);
+               db *= 2;
+               dstr_tmp = realloc(dstr, (db + 1) * sizeof(*dstr));
+               if (dstr_tmp == NULL) {
+                   free(dstr);
+                   (void) iconv_close(cd);
+                   return NULL;
+               }
+               dstr = dstr_tmp;
+               pout = dstr + used;
+               ob = db - used;
+               continue;
+           }   break;
+           case EINVAL:
+           case EILSEQ:
+           default:
+               break;
+           }
+           break;
+       }
+       (void) iconv_close(cd);
+       *pout = '\0';
+       ostr = xstrdup(dstr);
+       free(dstr);
+    } else
+       ostr = xstrdup(istr);
+
+    return ostr;
+}
+#endif
+
+int
+POPT_fprintf (FILE * stream, const char * format, ...)
+{
+    char * b = NULL, * ob = NULL;
+    int rc;
+    va_list ap;
+
+#if defined(HAVE_VASPRINTF)
+    va_start(ap, format);
+    if ((rc = vasprintf(&b, format, ap)) < 0)
+       b = NULL;
+    va_end(ap);
+#else
+    size_t nb = (size_t)1;
+
+    /* HACK: add +1 to the realloc no. of bytes "just in case". */
+    /* XXX Likely unneeded, the issues wrto vsnprintf(3) return b0rkage have
+     * to do with whether the final '\0' is counted (or not). The code
+     * below already adds +1 for the (possibly already counted) trailing NUL.
+     */
+    while ((b = realloc(b, nb+1)) != NULL) {
+       va_start(ap, format);
+       rc = vsnprintf(b, nb, format, ap);
+       va_end(ap);
+       if (rc > -1) {  /* glibc 2.1 */
+           if ((size_t)rc < nb)
+               break;
+           nb = (size_t)(rc + 1);      /* precise buffer length known */
+       } else          /* glibc 2.0 */
+           nb += (nb < (size_t)100 ? (size_t)100 : nb);
+       ob = b;
+    }
+#endif
+
+    rc = 0;
+    if (b != NULL) {
+#ifdef HAVE_ICONV
+       ob = strdup_locale_from_utf8(b);
+       if (ob != NULL) {
+           rc = fprintf(stream, "%s", ob);
+           free(ob);
+       } else
+#endif
+           rc = fprintf(stream, "%s", b);
+       free (b);
+    }
+
+    return rc;
+}
+
+#endif /* !defined(POPT_fprintf) */
index bec7c976943208aaa6cabdad0d2e9ff72a534859..001c5c35d66a7aefc486ed11bb28bbf12fd1aecb 100644 (file)
@@ -1,5 +1,5 @@
 /** \ingroup popt
- * \file popt/poptint.h
+ * @file
  */
 
 /* (C) 1998-2000 Red Hat, Inc. -- Licensing details are in the COPYING
 #ifndef H_POPTINT
 #define H_POPTINT
 
+#include <stdint.h>
+
 /**
  * Wrapper to free(3), hides const compilation noise, permit NULL, return NULL.
  * @param p            memory to free
  * @retval             NULL always
  */
-/*@unused@*/ static inline /*@null@*/ void *
-_free(/*@only@*/ /*@null@*/ const void * p)
-       /*@modifies p @*/
+static inline void *
+_free(const void * p)
 {
     if (p != NULL)     free((void *)p);
     return NULL;
 }
 
-static inline int
-isSpace(const char *ptr)
-{
-    return isspace(*(unsigned char *)ptr);
-}
-
 /* Bit mask macros. */
-/*@-exporttype -redef @*/
 typedef        unsigned int __pbm_bits;
-/*@=exporttype =redef @*/
 #define        __PBM_NBITS             (8 * sizeof (__pbm_bits))
 #define        __PBM_IX(d)             ((d) / __PBM_NBITS)
 #define __PBM_MASK(d)          ((__pbm_bits) 1 << (((unsigned)(d)) % __PBM_NBITS))
-/*@-exporttype -redef @*/
 typedef struct {
     __pbm_bits bits[1];
 } pbm_set;
-/*@=exporttype =redef @*/
 #define        __PBM_BITS(set) ((set)->bits)
 
-#define        PBM_ALLOC(d)    calloc(__PBM_IX (d) + 1, sizeof(__pbm_bits))
+#define        PBM_ALLOC(d)    calloc(__PBM_IX (d) + 1, sizeof(pbm_set))
 #define        PBM_FREE(s)     _free(s);
 #define PBM_SET(d, s)   (__PBM_BITS (s)[__PBM_IX (d)] |= __PBM_MASK (d))
 #define PBM_CLR(d, s)   (__PBM_BITS (s)[__PBM_IX (d)] &= ~__PBM_MASK (d))
 #define PBM_ISSET(d, s) ((__PBM_BITS (s)[__PBM_IX (d)] & __PBM_MASK (d)) != 0)
 
+extern void poptJlu32lpair(const void *key, size_t size,
+                uint32_t *pc, uint32_t *pb);
+
+/** \ingroup popt
+ * Typedef's for string and array of strings.
+ */
+typedef const char * poptString;
+typedef poptString * poptArgv;
+
+/** \ingroup popt
+ * A union to simplify opt->arg access without casting.
+ */
+typedef union poptArg_u {
+    void * ptr;
+    int * intp;
+    short * shortp;
+    long * longp;
+    long long * longlongp;
+    float * floatp;
+    double * doublep;
+    const char ** argv;
+    poptCallbackType cb;
+    poptOption opt;
+} poptArg;
+
+extern unsigned int _poptArgMask;
+extern unsigned int _poptGroupMask;
+
+#define        poptArgType(_opt)       ((_opt)->argInfo & _poptArgMask)
+#define        poptGroup(_opt)         ((_opt)->argInfo & _poptGroupMask)
+
+#define        F_ISSET(_opt, _FLAG)    ((_opt)->argInfo & POPT_ARGFLAG_##_FLAG)
+#define        LF_ISSET(_FLAG)         (argInfo & POPT_ARGFLAG_##_FLAG)
+#define        CBF_ISSET(_opt, _FLAG)  ((_opt)->argInfo & POPT_CBFLAG_##_FLAG)
+
+/* XXX sick hack to preserve pretense of a popt-1.x ABI. */
+#define        poptSubstituteHelpI18N(opt) \
+  { if ((opt) == poptHelpOptions) (opt) = poptHelpOptionsI18N; }
+
 struct optionStackEntry {
     int argc;
-/*@only@*/ /*@null@*/
-    const char ** argv;
-/*@only@*/ /*@null@*/
+    poptArgv argv;
     pbm_set * argb;
     int next;
-/*@only@*/ /*@null@*/
-    const char * nextArg;
-/*@observer@*/ /*@null@*/
+    char * nextArg;
     const char * nextCharArg;
-/*@dependent@*/ /*@null@*/
     poptItem currAlias;
     int stuffed;
 };
 
 struct poptContext_s {
     struct optionStackEntry optionStack[POPT_OPTION_DEPTH];
-/*@dependent@*/
     struct optionStackEntry * os;
-/*@owned@*/ /*@null@*/
-    const char ** leftovers;
+    poptArgv leftovers;
     int numLeftovers;
+    int allocLeftovers;
     int nextLeftover;
-/*@keep@*/
     const struct poptOption * options;
     int restLeftover;
-/*@only@*/ /*@null@*/
     const char * appName;
-/*@only@*/ /*@null@*/
     poptItem aliases;
     int numAliases;
-    int flags;
-/*@owned@*/ /*@null@*/
+    unsigned int flags;
     poptItem execs;
     int numExecs;
-/*@only@*/ /*@null@*/
-    const char ** finalArgv;
+    char * execFail;
+    poptArgv finalArgv;
     int finalArgvCount;
     int finalArgvAlloced;
-/*@dependent@*/ /*@null@*/
+    int (*maincall) (int argc, const char **argv);
     poptItem doExec;
-/*@only@*/
     const char * execPath;
     int execAbsolute;
-/*@only@*/ /*@relnull@*/
     const char * otherHelp;
-/*@null@*/
     pbm_set * arg_strip;
 };
 
-#ifdef HAVE_LIBINTL_H
+#if defined(POPT_fprintf)
+#define        POPT_dgettext   dgettext
+#else
+#ifdef HAVE_ICONV
+#include <iconv.h>
+#endif
+
+#if defined(HAVE_DCGETTEXT)
+char *POPT_dgettext(const char * dom, const char * str);
+#endif
+
+FORMAT(printf, 2, 3)
+int   POPT_fprintf (FILE* stream, const char *format, ...);
+#endif /* !defined(POPT_fprintf) */
+
+const char *POPT_prev_char (const char *str);
+const char *POPT_next_char (const char *str);
+
+#endif
+
+#if defined(ENABLE_NLS) && defined(HAVE_LIBINTL_H)
 #include <libintl.h>
 #endif
 
-#if defined(HAVE_GETTEXT) && !defined(__LCLINT__)
+#if defined(ENABLE_NLS) && defined(HAVE_GETTEXT)
 #define _(foo) gettext(foo)
 #else
 #define _(foo) foo
 #endif
 
-#if defined(HAVE_DCGETTEXT) && !defined(__LCLINT__)
-#define D_(dom, str) dgettext(dom, str)
+#if defined(ENABLE_NLS) && defined(HAVE_LIBINTL_H) && defined(HAVE_DCGETTEXT)
+#define D_(dom, str) POPT_dgettext(dom, str)
 #define POPT_(foo) D_("popt", foo)
 #else
 #define D_(dom, str) str
@@ -119,4 +156,3 @@ struct poptContext_s {
 
 #define N_(foo) foo
 
-#endif
index e003a04a959ed97b0945da269ab0d17c9cb90903..5afc6c551f83ca4f2675435bf1bc1e0fe9721b96 100644 (file)
@@ -1,5 +1,5 @@
 /** \ingroup popt
- * \file popt/poptparse.c
+ * @file
  */
 
 /* (C) 1998-2002 Red Hat, Inc. -- Licensing details are in the COPYING
@@ -8,11 +8,8 @@
 
 #include "system.h"
 
-#include "poptint.h"
-
 #define POPT_ARGV_ARRAY_GROW_DELTA 5
 
-/*@-boundswrite@*/
 int poptDupArgv(int argc, const char **argv,
                int * argcPtr, const char *** argvPtr)
 {
@@ -34,13 +31,13 @@ int poptDupArgv(int argc, const char **argv,
        return POPT_ERROR_MALLOC;
     argv2 = (void *) dst;
     dst += (argc + 1) * sizeof(*argv);
+    *dst = '\0';
 
-    /*@-branchstate@*/
     for (i = 0; i < argc; i++) {
        argv2[i] = dst;
-       dst += strlcpy(dst, argv[i], nb) + 1;
+       dst = stpcpy(dst, argv[i]);
+       dst++;  /* trailing NUL */
     }
-    /*@=branchstate@*/
     argv2[argc] = NULL;
 
     if (argvPtr) {
@@ -53,21 +50,25 @@ int poptDupArgv(int argc, const char **argv,
        *argcPtr = argc;
     return 0;
 }
-/*@=boundswrite@*/
 
-/*@-bounds@*/
 int poptParseArgvString(const char * s, int * argcPtr, const char *** argvPtr)
 {
     const char * src;
     char quote = '\0';
     int argvAlloced = POPT_ARGV_ARRAY_GROW_DELTA;
     const char ** argv = malloc(sizeof(*argv) * argvAlloced);
+    const char ** argv_tmp;
     int argc = 0;
-    int buflen = strlen(s) + 1;
-    char * buf = memset(alloca(buflen), 0, buflen);
+    size_t buflen = strlen(s) + 1;
+    char * buf, * bufOrig = NULL;
     int rc = POPT_ERROR_MALLOC;
 
     if (argv == NULL) return rc;
+    buf = bufOrig = calloc((size_t)1, buflen);
+    if (buf == NULL) {
+       free(argv);
+       return rc;
+    }
     argv[argc] = buf;
 
     for (src = s; *src != '\0'; src++) {
@@ -83,13 +84,14 @@ int poptParseArgvString(const char * s, int * argcPtr, const char *** argvPtr)
                if (*src != quote) *buf++ = '\\';
            }
            *buf++ = *src;
-       } else if (isSpace(src)) {
+       } else if (_isspaceptr(src)) {
            if (*argv[argc] != '\0') {
                buf++, argc++;
                if (argc == argvAlloced) {
                    argvAlloced += POPT_ARGV_ARRAY_GROW_DELTA;
-                   argv = realloc(argv, sizeof(*argv) * argvAlloced);
-                   if (argv == NULL) goto exit;
+                   argv_tmp = realloc(argv, sizeof(*argv) * argvAlloced);
+                   if (argv_tmp == NULL) goto exit;
+                   argv = argv_tmp;
                }
                argv[argc] = buf;
            }
@@ -97,17 +99,17 @@ int poptParseArgvString(const char * s, int * argcPtr, const char *** argvPtr)
          case '"':
          case '\'':
            quote = *src;
-           /*@switchbreak@*/ break;
+           break;
          case '\\':
            src++;
            if (!*src) {
                rc = POPT_ERROR_BADQUOTE;
                goto exit;
            }
-           /*@fallthrough@*/
+           /* fallthrough */
          default:
            *buf++ = *src;
-           /*@switchbreak@*/ break;
+           break;
        }
     }
 
@@ -118,29 +120,30 @@ int poptParseArgvString(const char * s, int * argcPtr, const char *** argvPtr)
     rc = poptDupArgv(argc, argv, argcPtr, argvPtr);
 
 exit:
+    if (bufOrig) free(bufOrig);
     if (argv) free(argv);
     return rc;
 }
-/*@=bounds@*/
 
 /* still in the dev stage.
- * return values, perhaps 1== file erro
+ * return values, perhaps 1== file error
  * 2== line to long
  * 3== umm.... more?
  */
-int poptConfigFileToString(FILE *fp, char ** argstrp, /*@unused@*/ UNUSED(int flags))
+int poptConfigFileToString(FILE *fp, char ** argstrp,
+               UNUSED(int flags))
 {
     char line[999];
     char * argstr;
+    char * argstr_tmp;
     char * p;
     char * q;
     char * x;
-    int t;
-    int argvlen = 0;
+    size_t t;
+    size_t argvlen = 0;
     size_t maxlinelen = sizeof(line);
     size_t linelen;
-    int maxargvlen = 480;
-    int linenum = 0;
+    size_t maxargvlen = (size_t)480;
 
     *argstrp = NULL;
 
@@ -155,11 +158,10 @@ int poptConfigFileToString(FILE *fp, char ** argstrp, /*@unused@*/ UNUSED(int fl
     if (argstr == NULL) return POPT_ERROR_MALLOC;
 
     while (fgets(line, (int)maxlinelen, fp) != NULL) {
-       linenum++;
        p = line;
 
        /* loop until first non-space char or EOL */
-       while( *p != '\0' && isSpace(p) )
+       while( *p != '\0' && _isspaceptr(p) )
            p++;
 
        linelen = strlen(p);
@@ -173,25 +175,29 @@ int poptConfigFileToString(FILE *fp, char ** argstrp, /*@unused@*/ UNUSED(int fl
 
        q = p;
 
-       while (*q != '\0' && (!isSpace(q)) && *q != '=')
+       while (*q != '\0' && (!_isspaceptr(q)) && *q != '=')
            q++;
 
-       if (isSpace(q)) {
+       if (_isspaceptr(q)) {
            /* a space after the name, find next non space */
            *q++='\0';
-           while( *q != '\0' && isSpace(q) ) q++;
+           while( *q != '\0' && _isspaceptr(q) ) q++;
        }
        if (*q == '\0') {
            /* single command line option (ie, no name=val, just name) */
            q[-1] = '\0';               /* kill off newline from fgets() call */
-           argvlen += (t = q - p) + (sizeof(" --")-1);
+           argvlen += (t = (size_t)(q - p)) + (sizeof(" --")-1);
            if (argvlen >= maxargvlen) {
                maxargvlen = (t > maxargvlen) ? t*2 : maxargvlen*2;
-               argstr = realloc(argstr, maxargvlen);
-               if (argstr == NULL) return POPT_ERROR_MALLOC;
+               argstr_tmp = realloc(argstr, maxargvlen);
+               if (argstr_tmp == NULL) {
+                   free(argstr);
+                   return POPT_ERROR_MALLOC;
+               }
+               argstr = argstr_tmp;
            }
-           strlcat(argstr, " --", maxargvlen);
-           strlcat(argstr, p, maxargvlen);
+           strcat(argstr, " --");
+           strcat(argstr, p);
            continue;
        }
        if (*q != '=')
@@ -201,29 +207,33 @@ int poptConfigFileToString(FILE *fp, char ** argstrp, /*@unused@*/ UNUSED(int fl
        *q++ = '\0';
 
        /* find next non-space letter of value */
-       while (*q != '\0' && isSpace(q))
+       while (*q != '\0' && _isspaceptr(q))
            q++;
        if (*q == '\0')
            continue;   /* XXX silently ignore missing value */
 
        /* now, loop and strip all ending whitespace */
        x = p + linelen;
-       while (isSpace(--x))
-           *x = 0;     /* null out last char if space (including fgets() NL) */
+       while (_isspaceptr(--x))
+           *x = '\0';  /* null out last char if space (including fgets() NL) */
 
        /* rest of line accept */
-       t = x - p;
+       t = (size_t)(x - p);
        argvlen += t + (sizeof("' --='")-1);
        if (argvlen >= maxargvlen) {
            maxargvlen = (t > maxargvlen) ? t*2 : maxargvlen*2;
-           argstr = realloc(argstr, maxargvlen);
-           if (argstr == NULL) return POPT_ERROR_MALLOC;
+           argstr_tmp = realloc(argstr, maxargvlen);
+           if (argstr_tmp == NULL) {
+               free(argstr);
+               return POPT_ERROR_MALLOC;
+           }
+           argstr = argstr_tmp;
        }
-       strlcat(argstr, " --", maxargvlen);
-       strlcat(argstr, p, maxargvlen);
-       strlcat(argstr, "=\"", maxargvlen);
-       strlcat(argstr, q, maxargvlen);
-       strlcat(argstr, "\"", maxargvlen);
+       strcat(argstr, " --");
+       strcat(argstr, p);
+       strcat(argstr, "=\"");
+       strcat(argstr, q);
+       strcat(argstr, "\"");
     }
 
     *argstrp = argstr;
index 25c22daeef3b1d889de3cb711ee4698755207234..f731d206d2573de2e4faeb8efcb91044067f0b71 100644 (file)
+/**
+ * @file
+ */
+
 #ifdef HAVE_CONFIG_H
 #include "config.h"
 #endif
 
-#if defined (__GLIBC__) && defined(__LCLINT__)
-/*@-declundef@*/
-/*@unchecked@*/
-extern __const __int32_t *__ctype_tolower;
-/*@unchecked@*/
-extern __const __int32_t *__ctype_toupper;
-/*@=declundef@*/
-#endif
-
-#ifdef __TANDEM
-# include <floss.h(floss_execvp,floss_read)>
-#endif
-
 #include <ctype.h>
 
-#include <errno.h>
-#include <fcntl.h>
-#include <limits.h>
+/* XXX isspace(3) has i18n encoding signedness issues on Solaris. */
+#define        _isspaceptr(_chp)       isspace((int)(*(unsigned const char *)(_chp)))
 
-#if HAVE_MCHECK_H 
+#ifdef HAVE_MCHECK_H
 #include <mcheck.h>
 #endif
 
-#include <stdio.h>
-#ifdef HAVE_SYS_TYPES_H
-# include <sys/types.h>
-#endif
-#ifdef STDC_HEADERS
-# include <stdlib.h>
-# include <stddef.h>
-#else
-# ifdef HAVE_STDLIB_H
-#  include <stdlib.h>
-# endif
-#endif
-#ifdef HAVE_STRING_H
-# if !defined STDC_HEADERS && defined HAVE_MEMORY_H
-#  include <memory.h>
-# endif
-# include <string.h>
-#endif
-#ifdef HAVE_STRINGS_H
-# include <strings.h>
-#endif
-#ifdef HAVE_UNISTD_H
-# include <unistd.h>
-#endif
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
 
-#ifndef __GNUC__
-#define __attribute__(x) 
-#endif
+void * xmalloc (size_t size);
 
-#ifdef __NeXT
-/* access macros are not declared in non posix mode in unistd.h -
- don't try to use posix on NeXTstep 3.3 ! */
-#include <libc.h>
-#endif
+void * xcalloc (size_t nmemb, size_t size);
 
-#if defined(__LCLINT__)
-/*@-declundef -incondefs @*/ /* LCL: missing annotation */
-/*@only@*/ /*@out@*/
-void * alloca (size_t __size)
-       /*@ensures MaxSet(result) == (__size - 1) @*/
-       /*@*/;
-/*@=declundef =incondefs @*/
-#endif
+void * xrealloc (void * ptr, size_t size);
 
-/* AIX requires this to be the first thing in the file.  */ 
-#ifndef __GNUC__
-# if HAVE_ALLOCA_H
-#  include <alloca.h>
-# else
-#  ifdef _AIX
-#pragma alloca
-#  else
-#   ifdef HAVE_ALLOCA
-#    ifndef alloca /* predefined by HP cc +Olibcalls */
-char *alloca(size_t size);
-#    endif
-#   else
-#    ifdef alloca
-#     undef alloca
-#    endif
-#    define alloca(sz) malloc(sz) /* Kludge this for now */
-#   endif
-#  endif
-# endif
-#elif !defined(alloca)
-#define alloca __builtin_alloca
-#endif
+char * xstrdup (const char *str);
 
-#ifndef HAVE_STRLCPY
-size_t strlcpy(char *d, const char *s, size_t bufsize);
-#endif
+#if !defined(HAVE_STPCPY)
+/* Copy SRC to DEST, returning the address of the terminating '\0' in DEST.  */
+static inline char * stpcpy (char *dest, const char * src) {
+    register char *d = dest;
+    register const char *s = src;
 
-#ifndef HAVE_STRLCAT
-size_t strlcat(char *d, const char *s, size_t bufsize);
+    do
+       *d++ = *s;
+    while (*s++ != '\0');
+    return d - 1;
+}
 #endif
 
-#if HAVE_MCHECK_H && defined(__GNUC__)
-static inline char *
-xstrdup(const char *s)
-{
-    size_t memsize = strlen(s) + 1;
-    char *ptr = malloc(memsize);
-    if (!ptr) {
-       fprintf(stderr, "virtual memory exhausted.\n");
-       exit(EXIT_FAILURE);
-    }
-    strlcpy(ptr, s, memsize);
-    return ptr;
-}
+/* Memory allocation via macro defs to get meaningful locations from mtrace() */
+#if defined(HAVE_MCHECK_H) && defined(__GNUC__)
+#define        vmefail()       (fprintf(stderr, "virtual memory exhausted.\n"), exit(EXIT_FAILURE), NULL)
+#define        xmalloc(_size)          (malloc(_size) ? : vmefail())
+#define        xcalloc(_nmemb, _size)  (calloc((_nmemb), (_size)) ? : vmefail())
+#define        xrealloc(_ptr, _size)   (realloc((_ptr), (_size)) ? : vmefail())
+#define xstrdup(_str)   (strcpy((malloc(strlen(_str)+1) ? : vmefail()), (_str)))
 #else
+#define        xmalloc(_size)          malloc(_size)
+#define        xcalloc(_nmemb, _size)  calloc((_nmemb), (_size))
+#define        xrealloc(_ptr, _size)   realloc((_ptr), (_size))
 #define        xstrdup(_str)   strdup(_str)
-#endif  /* HAVE_MCHECK_H && defined(__GNUC__) */
+#endif  /* defined(HAVE_MCHECK_H) && defined(__GNUC__) */
 
-#if HAVE___SECURE_GETENV && !defined(__LCLINT__)
+#if defined(HAVE_SECURE_GETENV)
+#define getenv(_s)     secure_getenv(_s)
+#elif defined(HAVE___SECURE_GETENV)
 #define        getenv(_s)      __secure_getenv(_s)
 #endif
 
-#if !defined HAVE_SNPRINTF || !defined HAVE_C99_VSNPRINTF
-#define snprintf rsync_snprintf
-int snprintf(char *str,size_t count,const char *fmt,...);
+#if !defined(__GNUC__) && !defined(__attribute__)
+#define __attribute__(x) 
 #endif
-
 #define UNUSED(x) x __attribute__((__unused__))
-
-#define PACKAGE "rsync"
+#define FORMAT(a, b, c) __attribute__((__format__ (a, b, c)))
+#define NORETURN __attribute__((__noreturn__))
 
 #include "popt.h"
index c9d7e01d7fe01f90ca6eeff58a1f511397b675f8..6b4b369ee8a5ebde0f63aeb78cc0374ac9e89066 100644 (file)
@@ -3,7 +3,7 @@
  *
  * Copyright (C) 1996-2000 Andrew Tridgell
  * Copyright (C) 1996 Paul Mackerras
- * Copyright (C) 2003-2022 Wayne Davison
+ * Copyright (C) 2003-2023 Wayne Davison
  *
  * 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
@@ -372,7 +372,7 @@ static int receive_data(int f_in, char *fname_r, int fd_r, OFF_T size_r,
 
        if (fd != -1 && offset > 0) {
                if (sparse_files > 0) {
-                       if (sparse_end(fd, offset) != 0)
+                       if (sparse_end(fd, offset, updating_basis_or_equiv) != 0)
                                goto report_write_error;
                } else if (flush_write_file(fd) < 0) {
                    report_write_error:
index ee0a4f39463dab133880643cbae0a0362608671c..4407a013f777bc4fd80d6d3467410e20e6332337 100644 (file)
@@ -245,7 +245,7 @@ to be copied to different destination directories using more than one copy.
 
 While a copy of a case-ignoring filesystem to a case-ignoring filesystem can
 work out fairly well, if no `--delete-during` or `--delete-before` option is
-active, rsync can potentially update an existing file on the receiveing side
+active, rsync can potentially update an existing file on the receiving side
 without noticing that the upper-/lower-case of the filename should be changed
 to match the sender.
 
@@ -1636,7 +1636,9 @@ expand it.
 0.  `--crtimes`, `-N,`
 
     This tells rsync to set the create times (newness) of the destination
-    files to the same value as the source files.
+    files to the same value as the source files. Your OS & filesystem must
+    support the setting of arbitrary creation (birth) times for this option
+    to be supported.
 
 0.  `--omit-dir-times`, `-O`
 
@@ -2104,7 +2106,8 @@ expand it.
     See the [`--max-size`](#opt) option for a description of how SIZE can be
     specified.  The default suffix if none is given is bytes.
 
-    Beginning in 3.2.3, a value of 0 specifies no limit.
+    Beginning in 3.2.7, a value of 0 is an easy way to specify SIZE_MAX (the
+    largest limit possible).
 
     You can set a default value using the environment variable
     [`RSYNC_MAX_ALLOC`](#) using the same SIZE values as supported by this
@@ -4815,7 +4818,7 @@ An rsync web site is available at <https://rsync.samba.org/>.  The site
 includes an FAQ-O-Matic which may cover questions unanswered by this manual
 page.
 
-The rsync github project is <https://github.com/WayneD/rsync>.
+The rsync github project is <https://github.com/RsyncProject/rsync>.
 
 We would be delighted to hear from you if you like this program.  Please
 contact the mailing-list at <rsync@lists.samba.org>.
@@ -4835,8 +4838,7 @@ David Bell.  I've probably missed some people, my apologies if I have.
 ## AUTHOR
 
 Rsync was originally written by Andrew Tridgell and Paul Mackerras.  Many
-people have later contributed to it. It is currently maintained by Wayne
-Davison.
+people from around the world have helped to maintain and improve it.
 
 Mailing lists for support and development are available at
 <https://lists.samba.org/>.
index 3d91cd93dcb57774d6d3fb18a2c9f22dea09ad4f..2f257659db7a6ab4599fde25a6775e05bd9ea76b 100644 (file)
@@ -1023,7 +1023,7 @@ in the values of parameters.  See that section for details.
     _not_ displayed if the script returns success.  The other programs cannot
     send any text to the user.  All output except for the `pre-xfer exec`
     stdout goes to the corresponding daemon's stdout/stderr, which is typically
-    discarded.  See the `--no-detatch` option for a way to see the daemon's
+    discarded.  See the `--no-detach` option for a way to see the daemon's
     output, which can assist with debugging.
 
     Note that the `early exec` command runs before any part of the transfer
@@ -1188,6 +1188,9 @@ An example nginx proxy setup is as follows:
 > }
 > ```
 
+If rsyncd should be accessible encrypted and unencrypted at the same time make
+the proxy listen on port 873 as well and let it handle both streams.
+
 ## DAEMON CONFIG EXAMPLES
 
 A simple rsyncd.conf file that allow anonymous rsync to a ftp area at
@@ -1260,7 +1263,7 @@ Rsync is distributed under the GNU General Public License.  See the file
 [COPYING](COPYING) for details.
 
 An rsync web site is available at <https://rsync.samba.org/> and its github
-project is <https://github.com/WayneD/rsync>.
+project is <https://github.com/RsyncProject/rsync>.
 
 ## THANKS
 
@@ -1270,8 +1273,7 @@ Thanks to Karsten Thygesen for his many suggestions and documentation!
 ## AUTHOR
 
 Rsync was originally written by Andrew Tridgell and Paul Mackerras.  Many
-people have later contributed to it. It is currently maintained by Wayne
-Davison.
+people from around the world have helped to maintain and improve it.
 
 Mailing lists for support and development are available at
 <https://lists.samba.org/>.
diff --git a/support/install_deps_ubuntu.sh b/support/install_deps_ubuntu.sh
new file mode 100755 (executable)
index 0000000..ac49055
--- /dev/null
@@ -0,0 +1,11 @@
+#!/bin/bash
+
+# install script for build dependencies for ubuntu/debian systems
+
+sudo apt install -y gcc g++ gawk autoconf automake python3-cmarkgfm
+sudo apt install -y acl libacl1-dev
+sudo apt install -y attr libattr1-dev
+sudo apt install -y libxxhash-dev
+sudo apt install -y libzstd-dev
+sudo apt install -y liblz4-dev
+sudo apt install -y libssl-dev
index ed7b49ba5e15f1a3448f19a741fffad342a7037a..bc8b5bcd8ef040e0bb89e535bff5d778686bc8a0 100755 (executable)
@@ -1,4 +1,4 @@
-#!/usr/bin/env perl
+#!/usr/bin/env python3
 # This script takes a command-line arg of a source directory
 # that will be passed to rsync, and generates a set of excludes
 # that will exclude all mount points from the list.  This is
 # awk '{print $2}' /proc/mounts | grep -v '^/$' | \
 #   rsync -avf 'merge,/- -' /dir host:/dest/
 
-use strict;
-use warnings;
-use Cwd 'abs_path';
+import os, argparse
 
-my $file = '/proc/mounts';
-my $dir = shift || '/';
-my $trailing_slash = $dir =~ m{./$} ? '/' : '';
-$dir = abs_path($dir) . $trailing_slash;
-$dir =~ s{([^/]*)$}{};
-my $trailing = $1;
-$trailing = '' if $trailing eq '.' || !-d "$dir$trailing";
-$trailing .= '/' if $trailing ne '';
+MNT_FILE = '/proc/mounts';
 
-open(IN, $file) or die "Unable to open $file: $!\n";
-while (<IN>) {
-    $_ = (split)[1];
-    next unless s{^\Q$dir$trailing\E}{}o && $_ ne '';
-    print "- /$trailing$_\n";
-}
-close IN;
+def main():
+    trailing_slash = '/' if args.path.endswith(('/', '/.')) and args.path != '/' else ''
+    args.path = os.path.realpath(args.path) + trailing_slash
+    parent_dir = os.path.dirname(args.path)
+    trailing = os.path.basename(args.path)
+    if not os.path.isdir(args.path):
+        trailing = ''
+    elif trailing != '':
+        trailing += '/'
+    want_path = os.path.join(parent_dir, trailing)
+    wp_len = len(want_path)
+
+    with open(MNT_FILE) as fh:
+        for line in fh:
+            mnt_path = line.split()[1]
+            if mnt_path.startswith(want_path) and mnt_path != want_path:
+                print(f"- /{trailing}{mnt_path[wp_len:]}")
+
+if __name__ == '__main__':
+    parser = argparse.ArgumentParser(description="Output mount points as rsync excludes.", add_help=False)
+    parser.add_argument("--help", "-h", action="help", help="Output this help message and exit.")
+    parser.add_argument('path', metavar='PATH', nargs='?', default='/', help="Limit output to those within the PATH hierarchy.")
+    args = parser.parse_args()
+    main()
+
+# vim: sw=4 et
index 94c85f597107186f4bc3b699f9716a72bfa6712c..4b4b87c55c9f89d6779179d035be12aa1e1f7ae8 100755 (executable)
@@ -258,6 +258,9 @@ def main():
 
     if args.munge:
         rsync_opts.append('--munge-links')
+    
+    if args.no_overwrite:
+      rsync_opts.append('--ignore-existing')
 
     if not rsync_args:
         rsync_args = [ '.' ]
@@ -364,6 +367,7 @@ if __name__ == '__main__':
     arg_parser.add_argument('-munge', action='store_true', help="Enable rsync's --munge-links on the server side.")
     arg_parser.add_argument('-no-del', action='store_true', help="Disable rsync's --delete* and --remove* options.")
     arg_parser.add_argument('-no-lock', action='store_true', help="Avoid the single-run (per-user) lock check.")
+    arg_parser.add_argument('-no-overwrite', action='store_true', help="Prevent overwriting existing files by enforcing --ignore-existing")
     arg_parser.add_argument('-help', '-h', action='help', help="Output this help message and exit.")
     arg_parser.add_argument('dir', metavar='DIR', help="The restricted directory to use.")
     args = arg_parser.parse_args()
index 98f2cab0572d978c93bfe70ec452313a21245346..5f33930e28a4c5e7a2590a45faa31859e25b3274 100644 (file)
@@ -5,7 +5,7 @@ rrsync - a script to setup restricted rsync users via ssh logins
 ## SYNOPSIS
 
 ```
-rrsync [-ro|-rw] [-munge] [-no-del] [-no-lock] DIR
+rrsync [-ro|-rw] [-munge] [-no-del] [-no-lock] [-no-overwrite]  DIR
 ```
 
 The single non-option argument specifies the restricted _DIR_ to use. It can be
@@ -85,6 +85,11 @@ The remainder of this manpage is dedicated to using the rrsync script.
 
     Avoid the single-run (per-user) lock check.  Useful with [`-munge`](#opt).
 
+0.  `-no-overwrite`
+
+    Enforce `--ignore-existing` on the server. Prevents overwriting existing
+    files when the server is the receiver.
+
 0.  `-help`, `-h`
 
     Output this help message and exit.
@@ -158,7 +163,7 @@ rsync is distributed under the GNU General Public License.  See the file
 [COPYING](COPYING) for details.
 
 An rsync web site is available at <https://rsync.samba.org/> and its github
-project is <https://github.com/WayneD/rsync>.
+project is <https://github.com/RsyncProject/rsync>.
 
 ## AUTHOR
 
diff --git a/util2.c b/util2.c
index a8609a5d5931d60e7907265f94868ef585df785e..b59bff0a0b541b8f6837f6d87938ced8e5bac9b9 100644 (file)
--- a/util2.c
+++ b/util2.c
@@ -4,7 +4,7 @@
  * Copyright (C) 1996-2000 Andrew Tridgell
  * Copyright (C) 1996 Paul Mackerras
  * Copyright (C) 2001, 2002 Martin Pool <mbp@samba.org>
- * Copyright (C) 2003-2020 Wayne Davison
+ * Copyright (C) 2003-2024 Wayne Davison
  *
  * 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
@@ -72,7 +72,7 @@ int msleep(int t)
 
 void *my_alloc(void *ptr, size_t num, size_t size, const char *file, int line)
 {
-       if (max_alloc && num >= max_alloc/size) {
+       if (num >= max_alloc/size) {
                if (!file)
                        return NULL;
                rprintf(FERROR, "[%s] exceeded --max-alloc=%s setting (file=%s, line=%d)\n",
index fdfce4c40032f177175f84b881d91f426b2a9e99..c6515f6893f685513b07cbcefe10cf5c96b65b6d 100644 (file)
--- a/version.h
+++ b/version.h
@@ -1,2 +1,2 @@
-#define RSYNC_VERSION "3.2.7"
+#define RSYNC_VERSION "3.3.1dev"
 #define MAINTAINER_TZ_OFFSET -7.0