summaryrefslogtreecommitdiffstats
path: root/tests
diff options
context:
space:
mode:
Diffstat (limited to 'tests')
-rw-r--r--tests/Coreutils.pm629
-rw-r--r--tests/CuSkip.pm39
-rw-r--r--tests/CuTmpdir.pm111
-rw-r--r--tests/GNUmakefile20
-rwxr-xr-xtests/cat/cat-E.sh42
-rwxr-xr-xtests/cat/cat-buf.sh47
-rwxr-xr-xtests/cat/cat-proc.sh38
-rwxr-xr-xtests/cat/cat-self.sh33
-rwxr-xr-xtests/chcon/chcon-fail.sh37
-rwxr-xr-xtests/chcon/chcon.sh78
-rwxr-xr-xtests/chgrp/basic.sh110
-rwxr-xr-xtests/chgrp/default-no-deref.sh34
-rwxr-xr-xtests/chgrp/deref.sh60
-rwxr-xr-xtests/chgrp/no-x.sh55
-rwxr-xr-xtests/chgrp/posix-H.sh71
-rwxr-xr-xtests/chgrp/recurse.sh54
-rwxr-xr-xtests/chmod/c-option.sh51
-rwxr-xr-xtests/chmod/equal-x.sh34
-rwxr-xr-xtests/chmod/equals.sh46
-rwxr-xr-xtests/chmod/ignore-symlink.sh31
-rwxr-xr-xtests/chmod/inaccessible.sh28
-rwxr-xr-xtests/chmod/no-x.sh56
-rwxr-xr-xtests/chmod/octal.sh29
-rwxr-xr-xtests/chmod/setgid.sh63
-rwxr-xr-xtests/chmod/silent.sh29
-rwxr-xr-xtests/chmod/thru-dangling.sh31
-rwxr-xr-xtests/chmod/umask-x.sh26
-rwxr-xr-xtests/chmod/usage.sh86
-rwxr-xr-xtests/chown/basic.sh59
-rwxr-xr-xtests/chown/deref.sh38
-rwxr-xr-xtests/chown/preserve-root.sh66
-rwxr-xr-xtests/chown/separator.sh69
-rwxr-xr-xtests/chroot/chroot-credentials.sh123
-rwxr-xr-xtests/chroot/chroot-fail.sh63
-rwxr-xr-xtests/cksum/b2sum.sh70
-rwxr-xr-xtests/cksum/cksum-a.sh61
-rwxr-xr-xtests/cksum/cksum-base64.pl99
-rwxr-xr-xtests/cksum/cksum-c.sh59
-rwxr-xr-xtests/cksum/cksum-raw.sh60
-rwxr-xr-xtests/cksum/cksum.sh74
-rwxr-xr-xtests/cksum/md5sum-bsd.sh101
-rwxr-xr-xtests/cksum/md5sum-newline.pl46
-rwxr-xr-xtests/cksum/md5sum-parallel.sh36
-rwxr-xr-xtests/cksum/md5sum.pl194
-rwxr-xr-xtests/cksum/sha1sum-vec.pl534
-rwxr-xr-xtests/cksum/sha1sum.pl94
-rwxr-xr-xtests/cksum/sha224sum.pl49
-rwxr-xr-xtests/cksum/sha256sum.pl55
-rwxr-xr-xtests/cksum/sha384sum.pl55
-rwxr-xr-xtests/cksum/sha512sum.pl55
-rwxr-xr-xtests/cksum/sm3sum.pl56
-rwxr-xr-xtests/cksum/sum-sysv.sh50
-rwxr-xr-xtests/cksum/sum.pl61
-rwxr-xr-xtests/cp/abuse.sh50
-rwxr-xr-xtests/cp/acl.sh60
-rwxr-xr-xtests/cp/attr-existing.sh44
-rwxr-xr-xtests/cp/backup-1.sh37
-rwxr-xr-xtests/cp/backup-dir.sh38
-rwxr-xr-xtests/cp/backup-is-src.sh36
-rwxr-xr-xtests/cp/capability.sh52
-rwxr-xr-xtests/cp/copy-FMR.sh31
-rwxr-xr-xtests/cp/cp-HL.sh40
-rwxr-xr-xtests/cp/cp-a-selinux.sh228
-rwxr-xr-xtests/cp/cp-deref.sh34
-rwxr-xr-xtests/cp/cp-i.sh71
-rwxr-xr-xtests/cp/cp-mv-backup.sh92
-rwxr-xr-xtests/cp/cp-mv-enotsup-xattr.sh132
-rwxr-xr-xtests/cp/cp-parents.sh75
-rwxr-xr-xtests/cp/cross-dev-symlink.sh38
-rwxr-xr-xtests/cp/debug.sh32
-rwxr-xr-xtests/cp/deref-slink.sh28
-rwxr-xr-xtests/cp/dir-rm-dest.sh35
-rwxr-xr-xtests/cp/dir-slash.sh35
-rwxr-xr-xtests/cp/dir-vs-file.sh33
-rwxr-xr-xtests/cp/existing-perm-dir.sh31
-rwxr-xr-xtests/cp/existing-perm-race.sh94
-rwxr-xr-xtests/cp/fail-perm.sh66
-rwxr-xr-xtests/cp/file-perm-race.sh58
-rwxr-xr-xtests/cp/into-self.sh57
-rwxr-xr-xtests/cp/link-deref.sh126
-rwxr-xr-xtests/cp/link-heap.sh42
-rwxr-xr-xtests/cp/link-no-deref.sh29
-rwxr-xr-xtests/cp/link-preserve.sh91
-rwxr-xr-xtests/cp/link-symlink.sh41
-rwxr-xr-xtests/cp/link.sh31
-rwxr-xr-xtests/cp/nfs-removal-race.sh75
-rwxr-xr-xtests/cp/no-ctx.sh65
-rwxr-xr-xtests/cp/no-deref-link1.sh37
-rwxr-xr-xtests/cp/no-deref-link2.sh37
-rwxr-xr-xtests/cp/no-deref-link3.sh34
-rwxr-xr-xtests/cp/parent-perm-race.sh59
-rwxr-xr-xtests/cp/parent-perm.sh53
-rwxr-xr-xtests/cp/perm.sh77
-rwxr-xr-xtests/cp/preserve-2.sh29
-rwxr-xr-xtests/cp/preserve-gid.sh146
-rwxr-xr-xtests/cp/preserve-link.sh92
-rwxr-xr-xtests/cp/preserve-mode.sh66
-rwxr-xr-xtests/cp/preserve-slink-time.sh51
-rwxr-xr-xtests/cp/proc-short-read.sh43
-rwxr-xr-xtests/cp/proc-zero-len.sh47
-rwxr-xr-xtests/cp/r-vs-symlink.sh41
-rwxr-xr-xtests/cp/reflink-auto.sh45
-rwxr-xr-xtests/cp/reflink-perm.sh45
-rwxr-xr-xtests/cp/same-file.sh255
-rwxr-xr-xtests/cp/slink-2-slink.sh32
-rwxr-xr-xtests/cp/sparse-2.sh56
-rwxr-xr-xtests/cp/sparse-extents-2.sh116
-rwxr-xr-xtests/cp/sparse-extents.sh83
-rwxr-xr-xtests/cp/sparse-perf.sh40
-rwxr-xr-xtests/cp/sparse-to-pipe.sh38
-rwxr-xr-xtests/cp/sparse.sh77
-rwxr-xr-xtests/cp/special-bits.sh51
-rwxr-xr-xtests/cp/special-f.sh33
-rwxr-xr-xtests/cp/src-base-dot.sh28
-rwxr-xr-xtests/cp/symlink-slash.sh36
-rwxr-xr-xtests/cp/thru-dangling.sh51
-rwxr-xr-xtests/csplit/csplit-1000.sh29
-rwxr-xr-xtests/csplit/csplit-heap.sh32
-rwxr-xr-xtests/csplit/csplit-io-err.sh92
-rwxr-xr-xtests/csplit/csplit-suppress-matched.pl218
-rwxr-xr-xtests/csplit/csplit.sh103
-rwxr-xr-xtests/cut/cut-huge-range.sh47
-rwxr-xr-xtests/cut/cut.pl255
-rw-r--r--tests/d_type-check69
-rwxr-xr-xtests/date/date-debug.sh311
-rwxr-xr-xtests/date/date-next-dow.pl78
-rwxr-xr-xtests/date/date-sec.sh49
-rwxr-xr-xtests/date/date-tz.sh26
-rwxr-xr-xtests/date/date.pl381
-rwxr-xr-xtests/dd/ascii.sh74
-rwxr-xr-xtests/dd/bytes.sh75
-rwxr-xr-xtests/dd/direct.sh35
-rwxr-xr-xtests/dd/misc.sh127
-rwxr-xr-xtests/dd/no-allocate.sh76
-rwxr-xr-xtests/dd/nocache.sh58
-rwxr-xr-xtests/dd/nocache_eof.sh97
-rwxr-xr-xtests/dd/not-rewound.sh31
-rwxr-xr-xtests/dd/reblock.sh72
-rwxr-xr-xtests/dd/skip-seek-past-dev.sh58
-rwxr-xr-xtests/dd/skip-seek-past-file.sh92
-rwxr-xr-xtests/dd/skip-seek.pl88
-rwxr-xr-xtests/dd/skip-seek2.sh38
-rwxr-xr-xtests/dd/sparse.sh93
-rwxr-xr-xtests/dd/stats.sh76
-rwxr-xr-xtests/dd/stderr.sh43
-rwxr-xr-xtests/dd/unblock-sync.sh35
-rwxr-xr-xtests/dd/unblock.pl59
-rwxr-xr-xtests/df/df-P.sh37
-rwxr-xr-xtests/df/df-output.sh140
-rwxr-xr-xtests/df/df-symlink.sh48
-rwxr-xr-xtests/df/header.sh28
-rwxr-xr-xtests/df/no-mtab-status.sh125
-rwxr-xr-xtests/df/over-mount-device.sh59
-rwxr-xr-xtests/df/problematic-chars.sh65
-rwxr-xr-xtests/df/skip-duplicates.sh191
-rwxr-xr-xtests/df/skip-rootfs.sh53
-rwxr-xr-xtests/df/total-unprocessed.sh44
-rwxr-xr-xtests/df/total-verify.sh67
-rwxr-xr-xtests/df/unreadable.sh32
-rwxr-xr-xtests/du/2g.sh71
-rwxr-xr-xtests/du/8gb.sh54
-rwxr-xr-xtests/du/apparent.sh33
-rwxr-xr-xtests/du/basic.sh91
-rwxr-xr-xtests/du/bigtime.sh52
-rwxr-xr-xtests/du/bind-mount-dir-cycle-v2.sh38
-rwxr-xr-xtests/du/bind-mount-dir-cycle.sh37
-rwxr-xr-xtests/du/deref-args.sh48
-rwxr-xr-xtests/du/deref.sh48
-rwxr-xr-xtests/du/exclude.sh58
-rwxr-xr-xtests/du/fd-leak.sh43
-rwxr-xr-xtests/du/files0-from-dir.sh39
-rwxr-xr-xtests/du/files0-from.pl94
-rwxr-xr-xtests/du/hard-link.sh64
-rwxr-xr-xtests/du/inacc-dest.sh56
-rwxr-xr-xtests/du/inacc-dir.sh42
-rwxr-xr-xtests/du/inaccessible-cwd.sh40
-rwxr-xr-xtests/du/inodes.sh140
-rwxr-xr-xtests/du/long-from-unreadable.sh74
-rwxr-xr-xtests/du/long-sloop.sh72
-rwxr-xr-xtests/du/max-depth.sh39
-rwxr-xr-xtests/du/move-dir-while-traversing.sh99
-rwxr-xr-xtests/du/no-deref.sh33
-rwxr-xr-xtests/du/no-x.sh49
-rwxr-xr-xtests/du/one-file-system.sh57
-rwxr-xr-xtests/du/restore-wd.sh31
-rwxr-xr-xtests/du/slash.sh33
-rwxr-xr-xtests/du/threshold.sh263
-rwxr-xr-xtests/du/trailing-slash.sh47
-rwxr-xr-xtests/du/two-args.sh40
-rwxr-xr-xtests/env/env-S-script.sh147
-rwxr-xr-xtests/env/env-S.pl289
-rwxr-xr-xtests/env/env-null.sh58
-rwxr-xr-xtests/env/env-signal-handler.sh126
-rwxr-xr-xtests/env/env.sh166
-rw-r--r--tests/envvar-check63
-rwxr-xr-xtests/expr/expr-multibyte.pl226
-rwxr-xr-xtests/expr/expr.pl238
-rwxr-xr-xtests/factor/create-test.sh83
-rwxr-xr-xtests/factor/factor-parallel.sh34
-rwxr-xr-xtests/factor/factor.pl125
-rwxr-xr-xtests/factor/run.sh34
-rw-r--r--tests/filefrag-extent-compare85
-rwxr-xr-xtests/fmt/base.pl67
-rwxr-xr-xtests/fmt/goal-option.sh56
-rwxr-xr-xtests/fmt/long-line.sh61
-rwxr-xr-xtests/fmt/non-space.sh49
-rwxr-xr-xtests/groups/groups-dash.sh33
-rwxr-xr-xtests/groups/groups-process-all.sh26
-rwxr-xr-xtests/groups/groups-version.sh27
-rwxr-xr-xtests/head/head-c.sh59
-rwxr-xr-xtests/head/head-elide-tail.pl110
-rwxr-xr-xtests/head/head-pos.sh44
-rwxr-xr-xtests/head/head-write-error.sh51
-rwxr-xr-xtests/head/head.pl87
-rwxr-xr-xtests/help/help-version-getopt.sh74
-rwxr-xr-xtests/help/help-version.sh273
-rwxr-xr-xtests/id/context.sh35
-rwxr-xr-xtests/id/gnu-zero-uids.sh29
-rwxr-xr-xtests/id/no-context.sh35
-rwxr-xr-xtests/id/setgid.sh46
-rwxr-xr-xtests/id/smack.sh37
-rwxr-xr-xtests/id/uid.sh42
-rwxr-xr-xtests/id/zero.sh105
-rwxr-xr-xtests/init.sh706
-rwxr-xr-xtests/install/basic-1.sh151
-rwxr-xr-xtests/install/create-leading.sh42
-rwxr-xr-xtests/install/d-slashdot.sh29
-rwxr-xr-xtests/install/install-C-root.sh77
-rwxr-xr-xtests/install/install-C-selinux.sh51
-rwxr-xr-xtests/install/install-C.sh115
-rwxr-xr-xtests/install/install-Z-selinux.sh57
-rwxr-xr-xtests/install/strip-program.sh48
-rwxr-xr-xtests/install/trap.sh33
-rw-r--r--tests/lang-default10
-rwxr-xr-xtests/ln/backup-1.sh30
-rwxr-xr-xtests/ln/hard-backup.sh32
-rwxr-xr-xtests/ln/hard-to-sym.sh83
-rwxr-xr-xtests/ln/misc.sh124
-rwxr-xr-xtests/ln/relative.sh53
-rwxr-xr-xtests/ln/sf-1.sh49
-rwxr-xr-xtests/ln/slash-decorated-nonexistent-dest.sh29
-rwxr-xr-xtests/ln/target-1.sh30
-rw-r--r--tests/local.mk926
-rwxr-xr-xtests/ls/a-option.sh27
-rwxr-xr-xtests/ls/abmon-align.sh53
-rwxr-xr-xtests/ls/birthtime.sh27
-rwxr-xr-xtests/ls/block-size.sh186
-rwxr-xr-xtests/ls/capability.sh63
-rwxr-xr-xtests/ls/classify.sh63
-rwxr-xr-xtests/ls/color-clear-to-eol.sh41
-rwxr-xr-xtests/ls/color-dtype-dir.sh64
-rwxr-xr-xtests/ls/color-ext.sh85
-rwxr-xr-xtests/ls/color-norm.sh84
-rwxr-xr-xtests/ls/color-term.sh48
-rwxr-xr-xtests/ls/dangle.sh64
-rwxr-xr-xtests/ls/dired.sh35
-rwxr-xr-xtests/ls/file-type.sh65
-rwxr-xr-xtests/ls/follow-slink.sh63
-rwxr-xr-xtests/ls/getxattr-speedup.sh66
-rwxr-xr-xtests/ls/group-dirs.sh43
-rwxr-xr-xtests/ls/hex-option.sh24
-rwxr-xr-xtests/ls/hyperlink.sh63
-rwxr-xr-xtests/ls/infloop.sh41
-rwxr-xr-xtests/ls/inode.sh65
-rwxr-xr-xtests/ls/ls-misc.pl375
-rwxr-xr-xtests/ls/ls-time.sh145
-rwxr-xr-xtests/ls/m-option.sh40
-rwxr-xr-xtests/ls/multihardlink.sh80
-rwxr-xr-xtests/ls/nameless-uid.sh40
-rwxr-xr-xtests/ls/no-arg.sh56
-rwxr-xr-xtests/ls/no-cap.sh33
-rwxr-xr-xtests/ls/quote-align.sh62
-rwxr-xr-xtests/ls/readdir-mountpoint-inode.sh73
-rwxr-xr-xtests/ls/recursive.sh62
-rwxr-xr-xtests/ls/removed-directory.sh38
-rwxr-xr-xtests/ls/root-rel-symlink-color.sh51
-rwxr-xr-xtests/ls/rt-1.sh46
-rwxr-xr-xtests/ls/selinux-segfault.sh33
-rwxr-xr-xtests/ls/slink-acl.sh33
-rwxr-xr-xtests/ls/sort-width-option.sh41
-rwxr-xr-xtests/ls/stat-dtype.sh60
-rwxr-xr-xtests/ls/stat-failed.sh57
-rwxr-xr-xtests/ls/stat-free-color.sh89
-rwxr-xr-xtests/ls/stat-free-symlinks.sh76
-rwxr-xr-xtests/ls/stat-vs-dirent.sh60
-rwxr-xr-xtests/ls/symlink-loop.sh35
-rwxr-xr-xtests/ls/symlink-quote.sh30
-rwxr-xr-xtests/ls/symlink-slash.sh30
-rwxr-xr-xtests/ls/time-style-diag.sh38
-rwxr-xr-xtests/ls/w-option.sh48
-rwxr-xr-xtests/ls/x-option.sh37
-rwxr-xr-xtests/ls/zero-option.sh41
-rwxr-xr-xtests/misc/arch.sh27
-rwxr-xr-xtests/misc/base64.pl214
-rwxr-xr-xtests/misc/basename.pl92
-rwxr-xr-xtests/misc/basenc.pl292
-rwxr-xr-xtests/misc/close-stdout.sh65
-rwxr-xr-xtests/misc/comm.pl186
-rwxr-xr-xtests/misc/coreutils.sh36
-rwxr-xr-xtests/misc/dircolors.pl76
-rwxr-xr-xtests/misc/dirname.pl72
-rwxr-xr-xtests/misc/echo.sh99
-rwxr-xr-xtests/misc/expand.pl191
-rwxr-xr-xtests/misc/false-status.sh31
-rwxr-xr-xtests/misc/fold.pl39
-rwxr-xr-xtests/misc/invalid-opt.pl103
-rwxr-xr-xtests/misc/join.pl342
-rwxr-xr-xtests/misc/kill.sh63
-rwxr-xr-xtests/misc/mknod.sh39
-rwxr-xr-xtests/misc/mktemp.pl206
-rwxr-xr-xtests/misc/nl.sh113
-rwxr-xr-xtests/misc/nohup.sh125
-rwxr-xr-xtests/misc/numfmt.pl1125
-rwxr-xr-xtests/misc/paste.pl74
-rwxr-xr-xtests/misc/pathchk.sh38
-rwxr-xr-xtests/misc/printenv.sh83
-rwxr-xr-xtests/misc/read-errors.sh95
-rwxr-xr-xtests/misc/realpath.sh111
-rwxr-xr-xtests/misc/selinux.sh65
-rwxr-xr-xtests/misc/sleep.sh55
-rwxr-xr-xtests/misc/stdbuf.sh125
-rwxr-xr-xtests/misc/sync.sh58
-rwxr-xr-xtests/misc/tee.sh145
-rwxr-xr-xtests/misc/time-style.sh119
-rwxr-xr-xtests/misc/tsort.pl66
-rwxr-xr-xtests/misc/unexpand.pl135
-rwxr-xr-xtests/misc/usage_vs_getopt.sh96
-rwxr-xr-xtests/misc/write-errors.sh65
-rwxr-xr-xtests/misc/xattr.sh130
-rwxr-xr-xtests/misc/xstrtol.pl49
-rwxr-xr-xtests/misc/yes.sh59
-rwxr-xr-xtests/mkdir/p-1.sh25
-rwxr-xr-xtests/mkdir/p-2.sh25
-rwxr-xr-xtests/mkdir/p-3.sh52
-rwxr-xr-xtests/mkdir/p-acl.sh35
-rwxr-xr-xtests/mkdir/p-slashdot.sh29
-rwxr-xr-xtests/mkdir/p-thru-slink.sh27
-rwxr-xr-xtests/mkdir/p-v.sh32
-rwxr-xr-xtests/mkdir/parents.sh52
-rwxr-xr-xtests/mkdir/perm.sh85
-rwxr-xr-xtests/mkdir/restorecon.sh72
-rwxr-xr-xtests/mkdir/selinux.sh56
-rwxr-xr-xtests/mkdir/smack-no-root.sh39
-rwxr-xr-xtests/mkdir/smack-root.sh36
-rwxr-xr-xtests/mkdir/special-1.sh51
-rwxr-xr-xtests/mkdir/t-slash.sh31
-rwxr-xr-xtests/mkdir/writable-under-readonly.sh52
-rwxr-xr-xtests/mv/acl.sh67
-rwxr-xr-xtests/mv/atomic.sh46
-rwxr-xr-xtests/mv/atomic2.sh45
-rwxr-xr-xtests/mv/backup-dir.sh45
-rwxr-xr-xtests/mv/backup-is-src.sh46
-rwxr-xr-xtests/mv/childproof.sh83
-rwxr-xr-xtests/mv/diag.sh48
-rwxr-xr-xtests/mv/dir-file.sh30
-rwxr-xr-xtests/mv/dir2dir.sh42
-rwxr-xr-xtests/mv/dup-source.sh91
-rwxr-xr-xtests/mv/force.sh43
-rwxr-xr-xtests/mv/hard-2.sh77
-rwxr-xr-xtests/mv/hard-3.sh69
-rwxr-xr-xtests/mv/hard-4.sh41
-rwxr-xr-xtests/mv/hard-link-1.sh41
-rwxr-xr-xtests/mv/hardlink-case.sh37
-rwxr-xr-xtests/mv/i-1.pl44
-rwxr-xr-xtests/mv/i-2.sh52
-rwxr-xr-xtests/mv/i-3.sh72
-rwxr-xr-xtests/mv/i-4.sh47
-rwxr-xr-xtests/mv/i-5.sh29
-rwxr-xr-xtests/mv/i-link-no.sh43
-rwxr-xr-xtests/mv/into-self-2.sh52
-rwxr-xr-xtests/mv/into-self-3.sh41
-rwxr-xr-xtests/mv/into-self-4.sh34
-rwxr-xr-xtests/mv/into-self.sh53
-rwxr-xr-xtests/mv/leak-fd.sh55
-rwxr-xr-xtests/mv/mv-n.sh64
-rwxr-xr-xtests/mv/mv-special-1.sh75
-rwxr-xr-xtests/mv/no-copy.sh33
-rwxr-xr-xtests/mv/no-target-dir.sh51
-rwxr-xr-xtests/mv/part-fail.sh55
-rwxr-xr-xtests/mv/part-hardlink.sh43
-rwxr-xr-xtests/mv/part-rename.sh57
-rwxr-xr-xtests/mv/part-symlink.sh262
-rwxr-xr-xtests/mv/partition-perm.sh37
-rwxr-xr-xtests/mv/perm-1.sh35
-rwxr-xr-xtests/mv/sticky-to-xpart.sh68
-rwxr-xr-xtests/mv/symlink-onto-hardlink-to-self.sh63
-rwxr-xr-xtests/mv/symlink-onto-hardlink.sh41
-rwxr-xr-xtests/mv/to-symlink.sh43
-rwxr-xr-xtests/mv/trailing-slash.sh65
-rwxr-xr-xtests/mv/update.sh69
-rwxr-xr-xtests/nice/nice-fail.sh32
-rwxr-xr-xtests/nice/nice.sh93
-rw-r--r--tests/no-perl6
-rwxr-xr-xtests/nproc/nproc-avail.sh27
-rwxr-xr-xtests/nproc/nproc-override.sh58
-rwxr-xr-xtests/nproc/nproc-positive.sh44
-rwxr-xr-xtests/od/od-N.sh32
-rwxr-xr-xtests/od/od-endian.sh49
-rwxr-xr-xtests/od/od-float.sh72
-rwxr-xr-xtests/od/od-j.sh39
-rwxr-xr-xtests/od/od-multiple-t.sh42
-rwxr-xr-xtests/od/od-x8.sh43
-rwxr-xr-xtests/od/od.pl74
-rw-r--r--tests/other-fs-tmpdir55
-rw-r--r--tests/pr/0F330
-rw-r--r--tests/pr/0FF396
-rw-r--r--tests/pr/0FFnt36
-rw-r--r--tests/pr/0FFt35
-rw-r--r--tests/pr/0FnFnt37
-rw-r--r--tests/pr/0FnFt36
-rw-r--r--tests/pr/0Fnt36
-rw-r--r--tests/pr/0Ft35
-rw-r--r--tests/pr/2-S_f-t_notab9
-rw-r--r--tests/pr/2-Sf-t_notab9
-rw-r--r--tests/pr/2f-t_notab9
-rw-r--r--tests/pr/2s_f-t_notab9
-rw-r--r--tests/pr/2s_w60f-t_nota9
-rw-r--r--tests/pr/2sf-t_notab9
-rw-r--r--tests/pr/2sw60f-t_notab9
-rw-r--r--tests/pr/2w60f-t_notab9
-rw-r--r--tests/pr/3-0F198
-rw-r--r--tests/pr/3-5l24f-t51
-rw-r--r--tests/pr/3-FF462
-rw-r--r--tests/pr/3a2l17-FF119
-rw-r--r--tests/pr/3a3f-0F24
-rw-r--r--tests/pr/3a3l15-t45
-rw-r--r--tests/pr/3a3l15f-t27
-rw-r--r--tests/pr/3b2l17-FF119
-rw-r--r--tests/pr/3b3f-0F24
-rw-r--r--tests/pr/3b3f-0FF34
-rw-r--r--tests/pr/3b3f-FF56
-rw-r--r--tests/pr/3b3l15-t45
-rw-r--r--tests/pr/3b3l15f-t27
-rw-r--r--tests/pr/3f-0F36
-rw-r--r--tests/pr/3f-FF85
-rw-r--r--tests/pr/3l24-t72
-rw-r--r--tests/pr/3l24f-t51
-rw-r--r--tests/pr/3ml24-FF168
-rw-r--r--tests/pr/3ml24-t72
-rw-r--r--tests/pr/3ml24-t-FF168
-rw-r--r--tests/pr/3ml24f-t51
-rw-r--r--tests/pr/4-7l24-FF96
-rw-r--r--tests/pr/4l24-FF144
-rw-r--r--tests/pr/FF594
-rw-r--r--tests/pr/FFn64
-rw-r--r--tests/pr/FFtn60
-rw-r--r--tests/pr/FnFn68
-rw-r--r--tests/pr/Ja3l24f-lm72
-rw-r--r--tests/pr/Jb3l24f-lm72
-rw-r--r--tests/pr/Jml24f-lm-lo136
-rw-r--r--tests/pr/W-72l24f-ll110
-rw-r--r--tests/pr/W20l24f-ll110
-rw-r--r--tests/pr/W26l24f-ll110
-rw-r--r--tests/pr/W27l24f-ll110
-rw-r--r--tests/pr/W28l24f-ll110
-rw-r--r--tests/pr/W35Ja3l24f-lm72
-rw-r--r--tests/pr/W35Jb3l24f-lm72
-rw-r--r--tests/pr/W35Jml24f-lmlo136
-rw-r--r--tests/pr/W35a3l24f-lm72
-rw-r--r--tests/pr/W35b3l24f-lm72
-rw-r--r--tests/pr/W35ml24f-lm-lo136
-rw-r--r--tests/pr/W72Jl24f-ll110
-rw-r--r--tests/pr/a2l15-FF195
-rw-r--r--tests/pr/a2l17-FF153
-rw-r--r--tests/pr/a3-0F330
-rw-r--r--tests/pr/a3f-0F40
-rw-r--r--tests/pr/a3f-0FF46
-rw-r--r--tests/pr/a3f-FF72
-rw-r--r--tests/pr/a3l15-t75
-rw-r--r--tests/pr/a3l15f-t47
-rw-r--r--tests/pr/a3l24f-lm72
-rw-r--r--tests/pr/b2l15-FF195
-rw-r--r--tests/pr/b2l17-FF153
-rw-r--r--tests/pr/b3-0F330
-rw-r--r--tests/pr/b3f-0F40
-rw-r--r--tests/pr/b3f-0FF46
-rw-r--r--tests/pr/b3f-FF72
-rw-r--r--tests/pr/b3l15-t75
-rw-r--r--tests/pr/b3l15f-t47
-rw-r--r--tests/pr/b3l24f-lm72
-rw-r--r--tests/pr/l24-FF216
-rw-r--r--tests/pr/l24-t120
-rw-r--r--tests/pr/l24f-t89
-rw-r--r--tests/pr/loli63
-rw-r--r--tests/pr/ml20-FF-t260
-rw-r--r--tests/pr/ml24-FF216
-rw-r--r--tests/pr/ml24-t120
-rw-r--r--tests/pr/ml24-t-FF216
-rw-r--r--tests/pr/ml24f-0F61
-rw-r--r--tests/pr/ml24f-lm-lo136
-rw-r--r--tests/pr/ml24f-t89
-rw-r--r--tests/pr/ml24f-t-0F89
-rw-r--r--tests/pr/n+2-5l24f-0FF51
-rw-r--r--tests/pr/n+2l24f-0FF61
-rw-r--r--tests/pr/n+2l24f-bl112
-rw-r--r--tests/pr/n+3-7l24-FF120
-rw-r--r--tests/pr/n+3l24f-0FF55
-rw-r--r--tests/pr/n+3l24f-bl106
-rw-r--r--tests/pr/n+3ml20f-bl-FF127
-rw-r--r--tests/pr/n+3ml24f-bl-tn119
-rw-r--r--tests/pr/n+3ml24f-tn-bl119
-rw-r--r--tests/pr/n+4-8a2l17-FF85
-rw-r--r--tests/pr/n+4b2l17f-0FF27
-rw-r--r--tests/pr/n+5-8b3l17f-FF33
-rw-r--r--tests/pr/n+5a3l13f-0FF29
-rw-r--r--tests/pr/n+6a2l17-FF68
-rw-r--r--tests/pr/n+6b3l13f-FF56
-rw-r--r--tests/pr/n+7l24-FF72
-rw-r--r--tests/pr/n+8l20-FF120
-rw-r--r--tests/pr/nJml24f-lmlmlo136
-rw-r--r--tests/pr/nJml24f-lmlolm136
-rw-r--r--tests/pr/nN1+3l24f-bl106
-rw-r--r--tests/pr/nN15l24f-bl131
-rw-r--r--tests/pr/nSml20-bl-FF151
-rw-r--r--tests/pr/nSml20-t-t-FF160
-rw-r--r--tests/pr/nSml20-t-tFFFF160
-rw-r--r--tests/pr/nSml24-bl-FF131
-rw-r--r--tests/pr/nSml24-t-t-FF136
-rw-r--r--tests/pr/nSml24-t-tFFFF136
-rw-r--r--tests/pr/nl24f-bl131
-rw-r--r--tests/pr/o3Jml24f-lm-lo136
-rw-r--r--tests/pr/o3a3Sl24f-tn32
-rw-r--r--tests/pr/o3a3Snl24f-tn32
-rw-r--r--tests/pr/o3a3l24f-tn32
-rw-r--r--tests/pr/o3b3Sl24f-tn32
-rw-r--r--tests/pr/o3b3Snl24f-tn32
-rw-r--r--tests/pr/o3b3l24f-tn32
-rw-r--r--tests/pr/o3mSl24f-bl-tn157
-rw-r--r--tests/pr/o3mSnl24fbltn157
-rw-r--r--tests/pr/o3ml24f-bl-tn157
-rwxr-xr-xtests/pr/pr-tests.pl524
-rw-r--r--tests/pr/t-0FF33
-rw-r--r--tests/pr/t-FF60
-rw-r--r--tests/pr/t-bl77
-rw-r--r--tests/pr/t-t63
-rw-r--r--tests/pr/tFFn60
-rw-r--r--tests/pr/tFFt56
-rw-r--r--tests/pr/tFFt-bl74
-rw-r--r--tests/pr/tFFt-ll56
-rw-r--r--tests/pr/tFFt-lm56
-rw-r--r--tests/pr/tFnFt63
-rw-r--r--tests/pr/t_notab5
-rw-r--r--tests/pr/t_tab4
-rw-r--r--tests/pr/t_tab_4
-rw-r--r--tests/pr/ta3-0FF12
-rw-r--r--tests/pr/ta3-FF22
-rw-r--r--tests/pr/tb3-0FF12
-rw-r--r--tests/pr/tb3-FF22
-rw-r--r--tests/pr/tn63
-rw-r--r--tests/pr/tn2e5o3-t_tab2
-rw-r--r--tests/pr/tn2e8-t_tab2
-rw-r--r--tests/pr/tn2e8o3-t_tab2
-rw-r--r--tests/pr/tn_2e8-t_tab2
-rw-r--r--tests/pr/tn_2e8S-t_tab2
-rw-r--r--tests/pr/tne8-t_tab4
-rw-r--r--tests/pr/tne8o3-t_tab4
-rw-r--r--tests/pr/tt-0FF33
-rw-r--r--tests/pr/tt-FF60
-rw-r--r--tests/pr/tt-bl76
-rw-r--r--tests/pr/tt-t63
-rw-r--r--tests/pr/tta3-0FF12
-rw-r--r--tests/pr/tta3-FF22
-rw-r--r--tests/pr/ttb3-0FF12
-rw-r--r--tests/pr/ttb3-FF22
-rw-r--r--tests/pr/w72l24f-ll110
-rwxr-xr-xtests/printf/printf-cov.pl106
-rwxr-xr-xtests/printf/printf-hex.sh29
-rwxr-xr-xtests/printf/printf-mb.sh64
-rwxr-xr-xtests/printf/printf-quote.sh57
-rwxr-xr-xtests/printf/printf-surprise.sh98
-rwxr-xr-xtests/printf/printf.sh128
-rwxr-xr-xtests/ptx/ptx-overrun.sh49
-rwxr-xr-xtests/ptx/ptx.pl57
-rwxr-xr-xtests/pwd/pwd-long.sh123
-rwxr-xr-xtests/pwd/pwd-option.sh62
-rwxr-xr-xtests/readlink/can-e.sh104
-rwxr-xr-xtests/readlink/can-f.sh153
-rwxr-xr-xtests/readlink/can-m.sh141
-rwxr-xr-xtests/readlink/multi.sh46
-rwxr-xr-xtests/readlink/readlink-fp-loop.sh68
-rwxr-xr-xtests/readlink/readlink-root.sh92
-rwxr-xr-xtests/readlink/rl-1.sh43
-rwxr-xr-xtests/rm/cycle.sh36
-rwxr-xr-xtests/rm/d-1.sh38
-rwxr-xr-xtests/rm/d-2.sh37
-rwxr-xr-xtests/rm/d-3.sh37
-rwxr-xr-xtests/rm/dangling-symlink.sh46
-rwxr-xr-xtests/rm/deep-1.sh53
-rwxr-xr-xtests/rm/deep-2.sh53
-rwxr-xr-xtests/rm/dir-no-w.sh42
-rwxr-xr-xtests/rm/dir-nonrecur.sh34
-rwxr-xr-xtests/rm/dot-rel.sh29
-rwxr-xr-xtests/rm/empty-immutable-skip.sh46
-rwxr-xr-xtests/rm/empty-inacc.sh61
-rwxr-xr-xtests/rm/empty-name.pl60
-rwxr-xr-xtests/rm/ext3-perf.sh83
-rwxr-xr-xtests/rm/f-1.sh26
-rwxr-xr-xtests/rm/fail-2eperm.sh57
-rwxr-xr-xtests/rm/fail-eacces.sh54
-rwxr-xr-xtests/rm/fail-eperm.xpl150
-rwxr-xr-xtests/rm/hash.sh37
-rwxr-xr-xtests/rm/i-1.sh40
-rwxr-xr-xtests/rm/i-never.sh33
-rwxr-xr-xtests/rm/i-no-r.sh34
-rwxr-xr-xtests/rm/ignorable.sh30
-rwxr-xr-xtests/rm/inaccessible.sh49
-rwxr-xr-xtests/rm/interactive-always.sh87
-rwxr-xr-xtests/rm/interactive-once.sh149
-rwxr-xr-xtests/rm/ir-1.sh56
-rwxr-xr-xtests/rm/isatty.sh55
-rwxr-xr-xtests/rm/many-dir-entries-vs-OOM.sh47
-rwxr-xr-xtests/rm/no-give-up.sh42
-rwxr-xr-xtests/rm/one-file-system.sh51
-rwxr-xr-xtests/rm/one-file-system2.sh27
-rwxr-xr-xtests/rm/r-1.sh40
-rwxr-xr-xtests/rm/r-2.sh45
-rwxr-xr-xtests/rm/r-3.sh48
-rwxr-xr-xtests/rm/r-4.sh51
-rwxr-xr-xtests/rm/r-root.sh325
-rwxr-xr-xtests/rm/read-only.sh52
-rwxr-xr-xtests/rm/readdir-bug.sh41
-rwxr-xr-xtests/rm/rm-readdir-fail.sh121
-rwxr-xr-xtests/rm/rm1.sh48
-rwxr-xr-xtests/rm/rm2.sh55
-rwxr-xr-xtests/rm/rm3.sh73
-rwxr-xr-xtests/rm/rm4.sh31
-rwxr-xr-xtests/rm/rm5.sh52
-rwxr-xr-xtests/rm/sunos-1.sh29
-rwxr-xr-xtests/rm/unread2.sh35
-rwxr-xr-xtests/rm/unread3.sh43
-rwxr-xr-xtests/rm/unreadable.pl50
-rwxr-xr-xtests/rm/v-slash.sh34
-rwxr-xr-xtests/rmdir/fail-perm.sh32
-rwxr-xr-xtests/rmdir/ignore.sh56
-rwxr-xr-xtests/rmdir/symlink-errors.sh66
-rwxr-xr-xtests/rmdir/t-slash.sh29
-rwxr-xr-xtests/runcon/runcon-compute.sh30
-rwxr-xr-xtests/runcon/runcon-no-reorder.sh44
-rw-r--r--tests/sample-test36
-rw-r--r--tests/seek-data-capable33
-rwxr-xr-xtests/seq/seq-epipe.sh42
-rwxr-xr-xtests/seq/seq-extra-number.sh47
-rwxr-xr-xtests/seq/seq-io-errors.sh46
-rwxr-xr-xtests/seq/seq-locale.sh28
-rwxr-xr-xtests/seq/seq-long-double.sh46
-rwxr-xr-xtests/seq/seq-precision.sh85
-rwxr-xr-xtests/seq/seq.pl202
-rwxr-xr-xtests/shred/shred-exact.sh49
-rwxr-xr-xtests/shred/shred-passes.sh91
-rwxr-xr-xtests/shred/shred-remove.sh70
-rwxr-xr-xtests/shred/shred-size.sh34
-rwxr-xr-xtests/shuf/shuf-reservoir.sh73
-rwxr-xr-xtests/shuf/shuf.sh178
-rwxr-xr-xtests/sort/sort-NaN-infloop.sh31
-rwxr-xr-xtests/sort/sort-benchmark-random.sh54
-rwxr-xr-xtests/sort/sort-compress-hang.sh57
-rwxr-xr-xtests/sort/sort-compress-proc.sh90
-rwxr-xr-xtests/sort/sort-compress.sh72
-rwxr-xr-xtests/sort/sort-continue.sh53
-rwxr-xr-xtests/sort/sort-debug-keys.sh341
-rwxr-xr-xtests/sort/sort-debug-warn.sh185
-rwxr-xr-xtests/sort/sort-discrim.sh87
-rwxr-xr-xtests/sort/sort-exit-early.sh37
-rwxr-xr-xtests/sort/sort-files0-from.pl96
-rwxr-xr-xtests/sort/sort-float.sh90
-rwxr-xr-xtests/sort/sort-h-thousands-sep.sh50
-rwxr-xr-xtests/sort/sort-merge-fdlimit.sh79
-rwxr-xr-xtests/sort/sort-merge.pl84
-rwxr-xr-xtests/sort/sort-month.sh34
-rwxr-xr-xtests/sort/sort-rand.sh52
-rwxr-xr-xtests/sort/sort-spinlock-abuse.sh48
-rwxr-xr-xtests/sort/sort-stale-thread-mem.sh52
-rwxr-xr-xtests/sort/sort-u-FMR.sh29
-rwxr-xr-xtests/sort/sort-unique-segv.sh48
-rwxr-xr-xtests/sort/sort-unique.sh42
-rwxr-xr-xtests/sort/sort-version.sh114
-rwxr-xr-xtests/sort/sort.pl440
-rwxr-xr-xtests/split/additional-suffix.sh47
-rwxr-xr-xtests/split/b-chunk.sh91
-rwxr-xr-xtests/split/fail.sh61
-rwxr-xr-xtests/split/filter.sh80
-rwxr-xr-xtests/split/guard-input.sh33
-rwxr-xr-xtests/split/l-chunk-root.sh44
-rwxr-xr-xtests/split/l-chunk.sh129
-rwxr-xr-xtests/split/line-bytes.sh87
-rwxr-xr-xtests/split/lines.sh42
-rwxr-xr-xtests/split/numeric.sh51
-rwxr-xr-xtests/split/r-chunk.sh64
-rwxr-xr-xtests/split/record-sep.sh78
-rwxr-xr-xtests/split/suffix-auto-length.sh59
-rwxr-xr-xtests/split/suffix-length.sh76
-rwxr-xr-xtests/stat/stat-birthtime.sh51
-rwxr-xr-xtests/stat/stat-fmt.sh47
-rwxr-xr-xtests/stat/stat-hyphen.sh30
-rwxr-xr-xtests/stat/stat-mount.sh28
-rwxr-xr-xtests/stat/stat-nanoseconds.sh46
-rwxr-xr-xtests/stat/stat-printf.pl64
-rwxr-xr-xtests/stat/stat-slash.sh44
-rwxr-xr-xtests/stty/stty-invalid.sh60
-rwxr-xr-xtests/stty/stty-pairs.sh65
-rwxr-xr-xtests/stty/stty-row-col.sh91
-rwxr-xr-xtests/stty/stty.sh98
-rwxr-xr-xtests/tac/tac-2-nonseekable.sh45
-rwxr-xr-xtests/tac/tac-continue.sh76
-rwxr-xr-xtests/tac/tac.pl89
-rwxr-xr-xtests/tail/F-headers.sh59
-rwxr-xr-xtests/tail/F-vs-missing.sh59
-rwxr-xr-xtests/tail/F-vs-rename.sh90
-rwxr-xr-xtests/tail/append-only.sh46
-rwxr-xr-xtests/tail/assert-2.sh57
-rwxr-xr-xtests/tail/assert.sh68
-rwxr-xr-xtests/tail/big-4gb.sh50
-rwxr-xr-xtests/tail/descriptor-vs-rename.sh56
-rwxr-xr-xtests/tail/end-of-device.sh48
-rwxr-xr-xtests/tail/flush-initial.sh44
-rwxr-xr-xtests/tail/follow-name.sh35
-rwxr-xr-xtests/tail/follow-stdin.sh85
-rwxr-xr-xtests/tail/inotify-dir-recreate.sh88
-rwxr-xr-xtests/tail/inotify-hash-abuse.sh71
-rwxr-xr-xtests/tail/inotify-hash-abuse2.sh46
-rwxr-xr-xtests/tail/inotify-only-regular.sh32
-rwxr-xr-xtests/tail/inotify-race.sh101
-rwxr-xr-xtests/tail/inotify-race2.sh106
-rwxr-xr-xtests/tail/inotify-rotate-resources.sh108
-rwxr-xr-xtests/tail/inotify-rotate.sh77
-rwxr-xr-xtests/tail/overlay-headers.sh81
-rwxr-xr-xtests/tail/pid.sh49
-rwxr-xr-xtests/tail/pipe-f.sh67
-rwxr-xr-xtests/tail/pipe-f2.sh47
-rwxr-xr-xtests/tail/proc-ksyms.sh28
-rwxr-xr-xtests/tail/retry.sh184
-rwxr-xr-xtests/tail/start-middle.sh33
-rwxr-xr-xtests/tail/symlink.sh94
-rwxr-xr-xtests/tail/tail-c.sh38
-rwxr-xr-xtests/tail/tail-n0f.sh62
-rwxr-xr-xtests/tail/tail.pl148
-rwxr-xr-xtests/tail/truncate.sh56
-rwxr-xr-xtests/tail/wait.sh90
-rwxr-xr-xtests/test/test-N.sh54
-rwxr-xr-xtests/test/test-diag.pl38
-rwxr-xr-xtests/test/test.pl197
-rwxr-xr-xtests/timeout/timeout-blocked.pl48
-rwxr-xr-xtests/timeout/timeout-group.sh103
-rwxr-xr-xtests/timeout/timeout-large-parameters.sh46
-rwxr-xr-xtests/timeout/timeout-parameters.sh50
-rwxr-xr-xtests/timeout/timeout.sh74
-rwxr-xr-xtests/touch/60-seconds.sh33
-rwxr-xr-xtests/touch/dangling-symlink.sh49
-rwxr-xr-xtests/touch/dir-1.sh9
-rwxr-xr-xtests/touch/empty-file.sh80
-rwxr-xr-xtests/touch/fail-diag.sh32
-rwxr-xr-xtests/touch/fifo.sh27
-rwxr-xr-xtests/touch/no-create-missing.sh37
-rwxr-xr-xtests/touch/no-dereference.sh82
-rwxr-xr-xtests/touch/no-rights.sh40
-rwxr-xr-xtests/touch/not-owner.sh55
-rwxr-xr-xtests/touch/now-owned-by-other.sh34
-rwxr-xr-xtests/touch/obsolescent.sh41
-rwxr-xr-xtests/touch/read-only.sh31
-rwxr-xr-xtests/touch/relative.sh38
-rwxr-xr-xtests/touch/trailing-slash.sh70
-rwxr-xr-xtests/tr/tr-case-class.sh116
-rwxr-xr-xtests/tr/tr.pl174
-rwxr-xr-xtests/truncate/truncate-dangling-symlink.sh28
-rwxr-xr-xtests/truncate/truncate-dir-fail.sh25
-rwxr-xr-xtests/truncate/truncate-fail-diag.sh43
-rwxr-xr-xtests/truncate/truncate-fifo.sh27
-rwxr-xr-xtests/truncate/truncate-no-create-missing.sh26
-rwxr-xr-xtests/truncate/truncate-overflow.sh39
-rwxr-xr-xtests/truncate/truncate-owned-by-other.sh35
-rwxr-xr-xtests/truncate/truncate-parameters.sh54
-rwxr-xr-xtests/truncate/truncate-relative.sh35
-rwxr-xr-xtests/tty/tty-eof.pl118
-rwxr-xr-xtests/tty/tty.sh43
-rwxr-xr-xtests/uniq/uniq-collate.sh63
-rwxr-xr-xtests/uniq/uniq-perf.sh25
-rwxr-xr-xtests/uniq/uniq.pl272
-rwxr-xr-xtests/wc/wc-files0-from.pl93
-rwxr-xr-xtests/wc/wc-files0.sh62
-rwxr-xr-xtests/wc/wc-nbsp.sh52
-rwxr-xr-xtests/wc/wc-parallel.sh36
-rwxr-xr-xtests/wc/wc-proc.sh64
-rwxr-xr-xtests/wc/wc-total.sh60
-rwxr-xr-xtests/wc/wc.pl50
784 files changed, 60704 insertions, 0 deletions
diff --git a/tests/Coreutils.pm b/tests/Coreutils.pm
new file mode 100644
index 0000000..f147401
--- /dev/null
+++ b/tests/Coreutils.pm
@@ -0,0 +1,629 @@
+package Coreutils;
+# This is a testing framework.
+
+# Copyright (C) 1998-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+use strict;
+use vars qw($VERSION @ISA @EXPORT);
+
+use FileHandle;
+use File::Compare qw(compare);
+
+@ISA = qw(Exporter);
+($VERSION = '$Revision: 1.5 $ ') =~ tr/[0-9].//cd;
+@EXPORT = qw (run_tests triple_test getlimits);
+
+my $debug = $ENV{DEBUG};
+
+my @Types = qw (IN IN_PIPE OUT ERR AUX CMP EXIT PRE POST OUT_SUBST
+ ERR_SUBST ENV ENV_DEL);
+my %Types = map {$_ => 1} @Types;
+my %Zero_one_type = map {$_ => 1}
+ qw (OUT ERR EXIT PRE POST OUT_SUBST ERR_SUBST ENV);
+my $srcdir = "$ENV{srcdir}";
+my $Global_count = 1;
+
+# When running in a DJGPP environment, make $ENV{SHELL} point to bash.
+# Otherwise, a bad shell might be used (e.g. command.com) and many
+# tests would fail.
+defined $ENV{DJDIR}
+ and $ENV{SHELL} = "$ENV{DJDIR}/bin/bash.exe";
+
+# Perl 5.22.2 was seen to default to TERM=dumb on Solaris 11 OpenIndiana
+# So ensure this variable is unset.
+defined $ENV{TERM}
+ and delete $ENV{TERM};
+
+# A file spec: a scalar or a reference to a single-keyed hash
+# ================
+# 'contents' contents only (file name is derived from test name)
+# {filename => 'contents'} filename and contents
+# {filename => undef} filename only -- $(srcdir)/tests/filename must exist
+#
+# FIXME: If there is more than one input file, then you can't specify 'REDIR'.
+# PIPE is still ok.
+#
+# I/O spec: a hash ref with the following properties
+# ================
+# - one key/value pair
+# - the key must be one of these strings: IN, OUT, ERR, AUX, CMP, EXIT
+# - the value must be a file spec
+# {OUT => 'data'} put data in a temp file and compare it to stdout from cmd
+# {OUT => {'filename'=>undef}} compare contents of existing filename to
+# stdout from cmd
+# {OUT => {'filename'=>[$CTOR, $DTOR]}} $CTOR and $DTOR are references to
+# functions, each which is passed the single argument 'filename'.
+# $CTOR must create 'filename'.
+# DTOR may be omitted in which case 'sub{unlink @_[0]}' is used.
+# FIXME: implement this
+# {ERR => ...}
+# Same as for OUT, but compare with stderr, not stdout.
+# {OUT_SUBST => 's/variable_output/expected_output/'}
+# Transform actual standard output before comparing it against expected.
+# This is useful e.g. for programs like du that produce output that
+# varies a lot from system. E.g., an empty file may consume zero file
+# blocks, or more, depending on the OS and on the file system type.
+# {ERR_SUBST => 's/variable_output/expected_output/'}
+# Transform actual stderr output before comparing it against expected.
+# This is useful when verifying that we get a meaningful diagnostic.
+# For example, in rm/fail-2eperm, we have to account for three different
+# diagnostics: Operation not permitted, Not owner, and Permission denied.
+# {EXIT => N} expect exit status of cmd to be N
+# {ENV => 'VAR=val ...'}
+# Prepend 'VAR=val ...' to the command that we execute via 'system'.
+# {ENV_DEL => 'VAR'}
+# Remove VAR from the environment just before running the corresponding
+# command, and restore any value just afterwards.
+#
+# There may be many input file specs. File names from the input specs
+# are concatenated in order on the command line.
+# There may be at most one of the OUT-, ERR-, and EXIT-keyed specs.
+# If the OUT-(or ERR)-keyed hash ref is omitted, then expect no output
+# on stdout (or stderr).
+# If the EXIT-keyed one is omitted, then expect the exit status to be zero.
+
+# FIXME: Make sure that no junkfile is also listed as a
+# non-junkfile (i.e., with undef for contents)
+
+sub _shell_quote ($)
+{
+ my ($string) = @_;
+ $string =~ s/\'/\'\\\'\'/g;
+ return "'$string'";
+}
+
+sub _create_file ($$$$)
+{
+ my ($program_name, $test_name, $file_name, $data) = @_;
+ my $file;
+ if (defined $file_name)
+ {
+ $file = $file_name;
+ }
+ else
+ {
+ $file = "$test_name.$Global_count";
+ ++$Global_count;
+ }
+
+ warn "creating file '$file' with contents '$data'\n" if $debug;
+
+ # The test spec gave a string.
+ # Write it to a temp file and return tempfile name.
+ my $fh = new FileHandle "> $file";
+ die "$program_name: $file: $!\n" if ! $fh;
+ print $fh $data;
+ $fh->close || die "$program_name: $file: $!\n";
+
+ return $file;
+}
+
+sub _compare_files ($$$$$)
+{
+ my ($program_name, $test_name, $in_or_out, $actual, $expected) = @_;
+
+ my $differ = compare ($actual, $expected);
+ if ($differ)
+ {
+ my $info = (defined $in_or_out ? "std$in_or_out " : '');
+ warn "$program_name: test $test_name: ${info}mismatch, comparing "
+ . "$expected (expected) and $actual (actual)\n";
+ # Ignore any failure, discard stderr.
+ system "diff -c $expected $actual 2>/dev/null";
+ }
+
+ return $differ;
+}
+
+sub _process_file_spec ($$$$$)
+{
+ my ($program_name, $test_name, $file_spec, $type, $junk_files) = @_;
+
+ my ($file_name, $contents);
+ if (!ref $file_spec)
+ {
+ ($file_name, $contents) = (undef, $file_spec);
+ }
+ elsif (ref $file_spec eq 'HASH')
+ {
+ my $n = keys %$file_spec;
+ die "$program_name: $test_name: $type spec has $n elements --"
+ . " expected 1\n"
+ if $n != 1;
+ ($file_name, $contents) = each %$file_spec;
+
+ # This happens for the AUX hash in an io_spec like this:
+ # {CMP=> ['zy123utsrqponmlkji', {'@AUX@'=> undef}]},
+ defined $contents
+ or return $file_name;
+ }
+ else
+ {
+ die "$program_name: $test_name: invalid RHS in $type-spec\n"
+ }
+
+ my $is_junk_file = (! defined $file_name
+ || (($type eq 'IN' || $type eq 'AUX' || $type eq 'CMP')
+ && defined $contents));
+ my $file = _create_file ($program_name, $test_name,
+ $file_name, $contents);
+
+ if ($is_junk_file)
+ {
+ push @$junk_files, $file
+ }
+ else
+ {
+ # FIXME: put $srcdir in here somewhere
+ warn "$program_name: $test_name: specified file '$file' does"
+ . " not exist\n"
+ if ! -f "$srcdir/tests/$file";
+ }
+
+ return $file;
+}
+
+sub _at_replace ($$)
+{
+ my ($map, $s) = @_;
+ foreach my $eo (qw (AUX OUT ERR))
+ {
+ my $f = $map->{$eo};
+ $f
+ and $s =~ /\@$eo\@/
+ and $s =~ s/\@$eo\@/$f/g;
+ }
+ return $s;
+}
+
+sub getlimits()
+{
+ my $NV;
+ open $NV, "getlimits |" or die "Error running getlimits\n";
+ my %limits = map {split /=|\n/} <$NV>;
+ return \%limits;
+}
+
+# FIXME: cleanup on interrupt
+# FIXME: extract 'do_1_test' function
+
+# FIXME: having to include $program_name here is an expedient kludge.
+# Library code doesn't 'die'.
+sub run_tests ($$$$$)
+{
+ my ($program_name, $prog, $t_spec, $save_temps, $verbose) = @_;
+
+ # To indicate that $prog is a shell built-in, you'd make it a string 'ref'.
+ # E.g., call run_tests ($prog, \$prog, \@Tests, $save_temps, $verbose);
+ # If it's a ref, invoke it via "env":
+ my $built_prog = ref $prog ? $$prog : $prog;
+ my @prog = ref $prog ? (qw(env --), $$prog) : $prog;
+
+ # Warn about empty t_spec.
+ # FIXME
+
+ # Remove all temp files upon interrupt.
+ # FIXME
+
+ # Verify that test names are distinct.
+ my $bad_test_name = 0;
+ my %seen;
+ my %seen_8dot3;
+ my $t;
+ foreach $t (@$t_spec)
+ {
+ my $test_name = $t->[0];
+ if ($seen{$test_name})
+ {
+ warn "$program_name: $test_name: duplicate test name\n";
+ $bad_test_name = 1;
+ }
+ $seen{$test_name} = 1;
+
+ if (0)
+ {
+ my $t8 = lc substr $test_name, 0, 8;
+ if ($seen_8dot3{$t8})
+ {
+ warn "$program_name: 8.3 test name conflict: "
+ . "$test_name, $seen_8dot3{$t8}\n";
+ $bad_test_name = 1;
+ }
+ $seen_8dot3{$t8} = $test_name;
+ }
+
+ # The test name may be no longer than 30 bytes.
+ # Yes, this is an arbitrary limit. If it causes trouble,
+ # consider removing it.
+ my $max = 30;
+ if ($max < length $test_name)
+ {
+ warn "$program_name: $test_name: test name is too long (> $max)\n";
+ $bad_test_name = 1;
+ }
+ }
+ return 1 if $bad_test_name;
+
+ $ENV{built_programs} =~ /\b$built_prog\b/ ||
+ CuSkip::skip "required program(s) not built [$built_prog]\n";
+
+ # FIXME check exit status
+ system (@prog, '--version') if $verbose;
+
+ my @junk_files;
+ my $fail = 0;
+ foreach my $tt (@$t_spec)
+ {
+ my @post_compare;
+ my @dummy = @$tt;
+ my $t = \@dummy;
+ my $test_name = shift @$t;
+ my $expect = {};
+ my ($pre, $post);
+
+ # FIXME: maybe don't reset this.
+ $Global_count = 1;
+ my @args;
+ my $io_spec;
+ my %seen_type;
+ my @env_delete;
+ my $env_prefix = '';
+ my $input_pipe_cmd;
+ foreach $io_spec (@$t)
+ {
+ if (!ref $io_spec)
+ {
+ push @args, $io_spec;
+ next;
+ }
+
+ if (ref $io_spec ne 'HASH')
+ {
+ eval 'use Data::Dumper';
+ die "$program_name: $test_name: invalid entry in test spec; "
+ . "expected HASH-ref,\nbut got this:\n"
+ . Data::Dumper->Dump ([\$io_spec], ['$io_spec']) . "\n";
+ }
+
+ my $n = keys %$io_spec;
+ die "$program_name: $test_name: spec has $n elements --"
+ . " expected 1\n"
+ if $n != 1;
+ my ($type, $val) = each %$io_spec;
+ die "$program_name: $test_name: invalid key '$type' in test spec\n"
+ if ! $Types{$type};
+
+ # Make sure there's no more than one of OUT, ERR, EXIT, etc.
+ die "$program_name: $test_name: more than one $type spec\n"
+ if $Zero_one_type{$type} and $seen_type{$type}++;
+
+ if ($type eq 'PRE' or $type eq 'POST')
+ {
+ $expect->{$type} = $val;
+ next;
+ }
+
+ if ($type eq 'CMP')
+ {
+ my $t = ref $val;
+ $t && $t eq 'ARRAY'
+ or die "$program_name: $test_name: invalid CMP spec\n";
+ @$val == 2
+ or die "$program_name: $test_name: invalid CMP list; must have"
+ . " exactly 2 elements\n";
+ my @cmp_files;
+ foreach my $e (@$val)
+ {
+ my $r = ref $e;
+ $r && $r ne 'HASH'
+ and die "$program_name: $test_name: invalid element ($r)"
+ . " in CMP list; only scalars and hash references "
+ . "are allowed\n";
+ if ($r && $r eq 'HASH')
+ {
+ my $n = keys %$e;
+ $n == 1
+ or die "$program_name: $test_name: CMP spec has $n "
+ . "elements -- expected 1\n";
+
+ # Replace any '@AUX@' in the key of %$e.
+ my ($ff, $val) = each %$e;
+ my $new_ff = _at_replace $expect, $ff;
+ if ($new_ff ne $ff)
+ {
+ $e->{$new_ff} = $val;
+ delete $e->{$ff};
+ }
+ }
+ my $cmp_file = _process_file_spec ($program_name, $test_name,
+ $e, $type, \@junk_files);
+ push @cmp_files, $cmp_file;
+ }
+ push @post_compare, [@cmp_files];
+
+ $expect->{$type} = $val;
+ next;
+ }
+
+ if ($type eq 'EXIT')
+ {
+ die "$program_name: $test_name: invalid EXIT code\n"
+ if $val !~ /^\d+$/;
+ # FIXME: make sure $data is numeric
+ $expect->{EXIT} = $val;
+ next;
+ }
+
+ if ($type =~ /^(OUT|ERR)_SUBST$/)
+ {
+ $expect->{RESULT_SUBST} ||= {};
+ $expect->{RESULT_SUBST}->{$1} = $val;
+ next;
+ }
+
+ if ($type eq 'ENV')
+ {
+ $env_prefix = "$val ";
+ next;
+ }
+
+ if ($type eq 'ENV_DEL')
+ {
+ push @env_delete, $val;
+ next;
+ }
+
+ my $file = _process_file_spec ($program_name, $test_name, $val,
+ $type, \@junk_files);
+
+ if ($type eq 'IN' || $type eq 'IN_PIPE')
+ {
+ my $quoted_file = _shell_quote $file;
+ if ($type eq 'IN_PIPE')
+ {
+ defined $input_pipe_cmd
+ and die "$program_name: $test_name: only one input"
+ . " may be specified with IN_PIPE\n";
+ $input_pipe_cmd = "cat $quoted_file |";
+ }
+ else
+ {
+ push @args, $quoted_file;
+ }
+ }
+ elsif ($type eq 'AUX' || $type eq 'OUT' || $type eq 'ERR')
+ {
+ $expect->{$type} = $file;
+ }
+ else
+ {
+ die "$program_name: $test_name: invalid type: $type\n"
+ }
+ }
+
+ # Expect an exit status of zero if it's not specified.
+ $expect->{EXIT} ||= 0;
+
+ # Allow ERR to be omitted -- in that case, expect no error output.
+ foreach my $eo (qw (OUT ERR))
+ {
+ if (!exists $expect->{$eo})
+ {
+ $expect->{$eo} = _create_file ($program_name, $test_name,
+ undef, '');
+ push @junk_files, $expect->{$eo};
+ }
+ }
+
+ # FIXME: Does it ever make sense to specify a filename *and* contents
+ # in OUT or ERR spec?
+
+ # FIXME: this is really suboptimal...
+ my @new_args;
+ foreach my $a (@args)
+ {
+ $a = _at_replace $expect, $a;
+ push @new_args, $a;
+ }
+ @args = @new_args;
+
+ warn "$test_name...\n" if $verbose;
+ &{$expect->{PRE}} if $expect->{PRE};
+ my %actual;
+ $actual{OUT} = "$test_name.O";
+ $actual{ERR} = "$test_name.E";
+ push @junk_files, $actual{OUT}, $actual{ERR};
+ my @cmd = (@prog, @args, "> $actual{OUT}", "2> $actual{ERR}");
+ $env_prefix
+ and unshift @cmd, $env_prefix;
+ defined $input_pipe_cmd
+ and unshift @cmd, $input_pipe_cmd;
+ my $cmd_str = join (' ', @cmd);
+
+ # Delete from the environment any symbols specified by syntax
+ # like this: {ENV_DEL => 'TZ'}.
+ my %pushed_env;
+ foreach my $env_sym (@env_delete)
+ {
+ my $val = delete $ENV{$env_sym};
+ defined $val
+ and $pushed_env{$env_sym} = $val;
+ }
+
+ warn "Running command: '$cmd_str'\n" if $debug;
+ my $rc = 0xffff & system $cmd_str;
+
+ # Restore any environment setting we changed via a deletion.
+ foreach my $env_sym (keys %pushed_env)
+ {
+ $ENV{$env_sym} = $pushed_env{$env_sym};
+ }
+
+ if ($rc == 0xff00)
+ {
+ warn "$program_name: test $test_name failed: command failed:\n"
+ . " '$cmd_str': $!\n";
+ $fail = 1;
+ goto cleanup;
+ }
+ $rc >>= 8 if $rc > 0x80;
+ if ($expect->{EXIT} != $rc)
+ {
+ warn "$program_name: test $test_name failed: exit status mismatch:"
+ . " expected $expect->{EXIT}, got $rc\n";
+ $fail = 1;
+ goto cleanup;
+ }
+
+ my %actual_data;
+ # Record actual stdout and stderr contents, if POST may need them.
+ if ($expect->{POST})
+ {
+ foreach my $eo (qw (OUT ERR))
+ {
+ my $out_file = $actual{$eo};
+ open IN, $out_file
+ or (warn
+ "$program_name: cannot open $out_file for reading: $!\n"),
+ $fail = 1, next;
+ $actual_data{$eo} = <IN>;
+ close IN
+ or (warn "$program_name: failed to read $out_file: $!\n"),
+ $fail = 1;
+ }
+ }
+
+ foreach my $eo (qw (OUT ERR))
+ {
+ my $subst_expr = $expect->{RESULT_SUBST}->{$eo};
+ if (defined $subst_expr)
+ {
+ my $out = $actual{$eo};
+ my $orig = "$out.orig";
+
+ # Move $out aside (to $orig), then recreate $out
+ # by transforming each line of $orig via $subst_expr.
+ rename $out, $orig
+ or (warn "$program_name: cannot rename $out to $orig: $!\n"),
+ $fail = 1, next;
+ open IN, $orig
+ or (warn "$program_name: cannot open $orig for reading: $!\n"),
+ $fail = 1, (unlink $orig), next;
+ unlink $orig
+ or (warn "$program_name: cannot unlink $orig: $!\n"),
+ $fail = 1;
+ open OUT, ">$out"
+ or (warn "$program_name: cannot open $out for writing: $!\n"),
+ $fail = 1, next;
+ while (defined (my $line = <IN>))
+ {
+ eval "\$_ = \$line; $subst_expr; \$line = \$_";
+ print OUT $line;
+ }
+ close IN;
+ close OUT
+ or (warn "$program_name: failed to write $out: $!\n"),
+ $fail = 1, next;
+ }
+
+ my $eo_lower = lc $eo;
+ _compare_files ($program_name, $test_name, $eo_lower,
+ $actual{$eo}, $expect->{$eo})
+ and $fail = 1;
+ }
+
+ foreach my $pair (@post_compare)
+ {
+ my ($expected, $actual) = @$pair;
+ _compare_files $program_name, $test_name, undef, $actual, $expected
+ and $fail = 1;
+ }
+
+ cleanup:
+ $expect->{POST}
+ and &{$expect->{POST}} ($actual_data{OUT}, $actual_data{ERR});
+
+ }
+
+ # FIXME: maybe unlink files inside the big foreach loop?
+ unlink @junk_files if ! $save_temps;
+
+ return $fail;
+}
+
+# For each test in @$TESTS, generate two additional tests,
+# one using stdin, the other using a pipe. I.e., given this one
+# ['idem-0', {IN=>''}, {OUT=>''}],
+# generate these:
+# ['idem-0.r', '<', {IN=>''}, {OUT=>''}],
+# ['idem-0.p', {IN_PIPE=>''}, {OUT=>''}],
+# Generate new tests only if there is exactly one input spec.
+# The returned list of tests contains each input test, followed
+# by zero or two derived tests.
+sub triple_test($)
+{
+ my ($tests) = @_;
+ my @new;
+ foreach my $t (@$tests)
+ {
+ push @new, $t;
+
+ my @in;
+ my @args;
+ my @list_of_hash;
+ foreach my $e (@$t)
+ {
+ !ref $e
+ and push (@args, $e), next;
+
+ ref $e && ref $e eq 'HASH'
+ or (warn "$0: $t->[0]: unexpected entry type\n"), next;
+ defined $e->{IN}
+ and (push @in, $e->{IN}), next;
+ push @list_of_hash, $e;
+ }
+ # Add variants IFF there is exactly one input file.
+ @in == 1
+ or next;
+ shift @args; # discard test name
+ push @new, ["$t->[0].r", @args, '<', {IN => $in[0]}, @list_of_hash];
+ push @new, ["$t->[0].p", @args, {IN_PIPE => $in[0]}, @list_of_hash];
+ }
+ return @new;
+}
+
+## package return
+1;
diff --git a/tests/CuSkip.pm b/tests/CuSkip.pm
new file mode 100644
index 0000000..10b5e01
--- /dev/null
+++ b/tests/CuSkip.pm
@@ -0,0 +1,39 @@
+package CuSkip;
+# Skip a test: emit diag to log and to stderr, and exit 77
+
+# Copyright (C) 2011-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+use strict;
+use warnings;
+
+our $ME = $0 || "<???>";
+
+# Emit a diagnostic both to stderr and to $stderr_fileno_.
+# FIXME: don't hard-code that value (9), since it's already defined in init.cfg.
+sub skip ($)
+{
+ my ($msg) = @_;
+ my $stderr_fileno_ = 9;
+ warn $msg;
+ open FH, ">&$stderr_fileno_"
+ or warn "$ME: failed to dup stderr\n";
+ print FH $msg;
+ close FH
+ or warn "$ME: failed to close FD $stderr_fileno_\n";
+ exit 77;
+}
+
+1;
diff --git a/tests/CuTmpdir.pm b/tests/CuTmpdir.pm
new file mode 100644
index 0000000..10766dd
--- /dev/null
+++ b/tests/CuTmpdir.pm
@@ -0,0 +1,111 @@
+package CuTmpdir;
+# create, then chdir into a temporary sub-directory
+
+# Copyright (C) 2007-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+use strict;
+use warnings;
+
+use File::Temp;
+use File::Find;
+
+our $ME = $0 || "<???>";
+
+my $dir;
+
+sub skip_test($)
+{
+ warn "$ME: skipping test: unsafe working directory name: '$_[0]'\n";
+ exit 77;
+}
+
+sub chmod_1
+{
+ my $name = $_;
+
+ # Skip symlinks and non-directories.
+ -l $name || !-d _
+ and return;
+
+ chmod 0700, $name;
+}
+
+sub chmod_tree
+{
+ # When tempdir fails, it croaks, which leaves $dir undefined.
+ defined $dir
+ or return;
+
+ # Perform the equivalent of find "$dir" -type d -print0|xargs -0 chmod -R 700.
+ my $options = {untaint => 1, wanted => \&chmod_1};
+ find ($options, $dir);
+}
+
+sub import {
+ my $prefix = $_[1];
+
+ $ME eq '-' && defined $prefix
+ and $ME = $prefix;
+
+ if ($prefix !~ /^\//)
+ {
+ eval 'use Cwd';
+ my $cwd = $@ ? '.' : Cwd::getcwd();
+ $prefix = "$cwd/$prefix";
+ }
+
+ # Untaint for the upcoming mkdir.
+ $prefix =~ m!^([-+\@\w./]+)$!
+ or skip_test $prefix;
+ $prefix = $1;
+
+ my $original_pid = $$;
+
+ my $on_sig_remove_tmpdir = sub {
+ my ($sig) = @_;
+ if ($$ == $original_pid and defined $dir)
+ {
+ chmod_tree;
+ # Older versions of File::Temp lack this method.
+ exists &File::Temp::cleanup
+ and &File::Temp::cleanup;
+ }
+ $SIG{$sig} = 'DEFAULT';
+ kill $sig, $$;
+ };
+
+ foreach my $sig (qw (INT TERM HUP))
+ {
+ $SIG{$sig} = $on_sig_remove_tmpdir;
+ }
+
+ $dir = File::Temp::tempdir("$prefix.tmp-XXXX", CLEANUP => 1 );
+ chdir $dir
+ or warn "$ME: failed to chdir to $dir: $!\n";
+}
+
+END {
+ # Move cwd out of the directory we're about to remove.
+ # This is required on some systems, and by some versions of File::Temp.
+ chdir '..'
+ or warn "$ME: failed to chdir to .. from $dir: $!\n";
+
+ my $saved_errno = $?;
+ chmod_tree;
+ $? = $saved_errno;
+}
+
+1;
diff --git a/tests/GNUmakefile b/tests/GNUmakefile
new file mode 100644
index 0000000..3c178a2
--- /dev/null
+++ b/tests/GNUmakefile
@@ -0,0 +1,20 @@
+# Provide a compatibility layer so that the commands used before the
+# conversion of tests/ to non-recursive make still work. To do that, we
+# must rerun the "make check" from the parent, and with tests/ prefixed
+# onto any TESTS values. The SUBDIRS=. is to prevent the top-level check
+# rules from descending into e.g., gnulib-test/.
+
+.PHONY: all
+all:
+ @echo 'tests/GNUmakefile: did you mean to make "check"?' 1>&2
+ @exit 1
+
+ifeq ($(TESTS),)
+tests =
+else
+tests = TESTS=$(addprefix tests/,$(TESTS))
+endif
+
+.PHONY: check
+check:
+ cd .. && $(MAKE) $@ $(tests) SUBDIRS=.
diff --git a/tests/cat/cat-E.sh b/tests/cat/cat-E.sh
new file mode 100755
index 0000000..28c02c1
--- /dev/null
+++ b/tests/cat/cat-E.sh
@@ -0,0 +1,42 @@
+#!/bin/sh
+# Copyright (C) 2021-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ cat
+
+# \r followed by \n is displayed as ^M$
+# Up to and including 8.32 the $ would have displayed at the start of the line
+# overwriting the first character
+printf 'a\rb\r\nc\n\r\nd\r' > 'in' || framework_failure_
+printf 'a\rb^M$\nc$\n^M$\nd\r' > 'exp' || framework_failure_
+cat -E 'in' > out || fail=1
+compare exp out || fail=1
+
+# Ensure \r\n spanning files (or buffers) is handled
+printf '1\r' > in2 || framework_failure_
+printf '\n2\r\n' > in2b || framework_failure_
+printf '1^M$\n2^M$\n' > 'exp' || framework_failure_
+cat -E 'in2' 'in2b' > out || fail=1
+compare exp out || fail=1
+
+# Ensure \r at end of buffer is handled
+printf '1\r' > in2 || framework_failure_
+printf '2\r\n' > in2b || framework_failure_
+printf '1\r2^M$\n' > 'exp' || framework_failure_
+cat -E 'in2' 'in2b' > out || fail=1
+compare exp out || fail=1
+
+Exit $fail
diff --git a/tests/cat/cat-buf.sh b/tests/cat/cat-buf.sh
new file mode 100755
index 0000000..c8bd697
--- /dev/null
+++ b/tests/cat/cat-buf.sh
@@ -0,0 +1,47 @@
+#!/bin/sh
+# Ensure that cat outputs processed data immediately.
+
+# Copyright (C) 2009-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ cat
+
+# Use a fifo rather than a pipe in the tests below
+# so that the producer (cat) will wait until the
+# consumer (dd) opens the fifo therefore increasing
+# the chance that dd will read the data from each
+# write separately.
+mkfifo_or_skip_ fifo
+
+# Terminate any background cp process
+cleanup_() { kill $pid 2>/dev/null && wait $pid; }
+
+echo 1 > exp
+
+cat_buf_1()
+{
+ local delay="$1"
+
+ > out || framework_failure_
+ dd count=1 if=fifo > out & pid=$!
+ (echo 1; sleep $delay; echo 2) | cat -v > fifo
+ wait $pid
+ compare exp out
+}
+
+retry_delay_ cat_buf_1 .1 6 || fail=1
+
+Exit $fail
diff --git a/tests/cat/cat-proc.sh b/tests/cat/cat-proc.sh
new file mode 100755
index 0000000..b5b0e57
--- /dev/null
+++ b/tests/cat/cat-proc.sh
@@ -0,0 +1,38 @@
+#!/bin/sh
+# Ensure that cat -E produces same output as cat, modulo '$'s,
+# even when applied to a file in /proc.
+
+# Copyright (C) 2006-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ cat
+
+
+f=/proc/cpuinfo
+test -f $f \
+ || skip_ "no $f"
+
+
+# Yes, parts of /proc/cpuinfo might change between cat runs.
+# If that happens, consider choosing a file that's less likely to change,
+# or just filter out the changing lines. The sed filter should help
+# to avoid any spurious numeric differences.
+cat -E $f | sed 's/[0-9][0-9]*/D/g' | tr -d '$' > out || fail=1
+cat $f | sed 's/[0-9][0-9]*/D/g' | tr -d '$' > exp || fail=1
+
+compare exp out || fail=1
+
+Exit $fail
diff --git a/tests/cat/cat-self.sh b/tests/cat/cat-self.sh
new file mode 100755
index 0000000..ff2afdc
--- /dev/null
+++ b/tests/cat/cat-self.sh
@@ -0,0 +1,33 @@
+#!/bin/sh
+# Check that cat operates correctly when the input is the same as the output.
+
+# Copyright 2014-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ cat
+
+echo x >out || framework_failure_
+echo x >out1 || framework_failure_
+returns_ 1 cat out >>out || fail=1
+compare out out1 || fail=1
+
+# This example is taken from the POSIX spec for 'cat'.
+echo x >doc || framework_failure_
+echo y >doc.end || framework_failure_
+cat doc doc.end >doc || fail=1
+compare doc doc.end || fail=1
+
+Exit $fail
diff --git a/tests/chcon/chcon-fail.sh b/tests/chcon/chcon-fail.sh
new file mode 100755
index 0000000..e70417d
--- /dev/null
+++ b/tests/chcon/chcon-fail.sh
@@ -0,0 +1,37 @@
+#!/bin/sh
+# Ensure that chcon fails when it should.
+# These tests don't use any actual SE Linux syscalls.
+
+# Copyright (C) 2007-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ chcon
+
+
+# neither context nor file
+returns_ 1 chcon 2> /dev/null || fail=1
+
+# No file
+returns_ 1 chcon CON 2> /dev/null || fail=1
+
+# No file
+touch f
+returns_ 1 chcon --reference=f 2> /dev/null || fail=1
+
+# No file
+returns_ 1 chcon -u anyone 2> /dev/null || fail=1
+
+Exit $fail
diff --git a/tests/chcon/chcon.sh b/tests/chcon/chcon.sh
new file mode 100755
index 0000000..7028a95
--- /dev/null
+++ b/tests/chcon/chcon.sh
@@ -0,0 +1,78 @@
+#!/bin/sh
+# exercise chcon
+
+# Copyright (C) 2007-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ chcon
+require_root_
+require_selinux_
+skip_if_mcstransd_is_running_
+mls_enabled_ || skip_ 'MLS is disabled'
+
+mkdir -p d/sub/s2 || framework_failure_
+touch f g d/sub/1 d/sub/2 || framework_failure_
+
+
+# Set to a specified context.
+# Use root:object_r:tmp_t:s0. It is special in that
+# it works even when mcstransd isn't running.
+u1=root
+r1=object_r
+t1=tmp_t
+range=s0
+ctx=$u1:$r1:$t1:$range
+chcon $ctx f || skip_ "Failed to set context: $ctx"
+stat --printf='f|%C\n' f > out || fail=1
+
+# Use --reference.
+chcon --ref=f g || fail=1
+stat --printf='g|%C\n' g >> out || fail=1
+
+# Change the individual parts of the context, one by one.
+u2=user_u
+r2=object_r
+t2=unlabeled_t
+for i in --user=$u2 --role=$r2 --type=$t2 --range=$range; do
+ chcon $i f || fail=1
+ stat --printf="f|$i|"'%C\n' f >> out || fail=1
+done
+
+# Same, but change back using the short-named options.
+for i in -u$u1 -r$r1 -t$t1; do
+ chcon $i f || fail=1
+ stat --printf="f|$i|"'%C\n' f >> out || fail=1
+done
+
+cat <<EOF > exp || framework_failure_
+f|$ctx
+g|$ctx
+f|--user=$u2|$u2:$r1:$t1:$range
+f|--role=$r2|$u2:$r2:$t1:$range
+f|--type=$t2|$u2:$r2:$t2:$range
+f|--range=$range|$u2:$r2:$t2:$range
+f|-uroot|root:object_r:$t2:$range
+f|-robject_r|root:object_r:$t2:$range
+f|-ttmp_t|root:object_r:tmp_t:$range
+EOF
+
+compare exp out || fail=1
+
+chcon --verbose -u$u1 f > out || fail=1
+echo "changing security context of 'f'" > exp || framework_failure_
+compare exp out || fail=1
+
+Exit $fail
diff --git a/tests/chgrp/basic.sh b/tests/chgrp/basic.sh
new file mode 100755
index 0000000..f3a3597
--- /dev/null
+++ b/tests/chgrp/basic.sh
@@ -0,0 +1,110 @@
+#!/bin/sh
+# make sure chgrp is reasonable
+
+# Copyright (C) 2000-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ chgrp
+require_membership_in_two_groups_
+require_local_dir_
+
+set _ $groups; shift
+g1=$1
+g2=$2
+mkdir d
+touch f f2 d/f3
+chgrp $g1 f || fail=1
+chgrp $g2 f || fail=1
+chgrp $g2 f2 || fail=1
+chgrp -R $g1 d || fail=1
+
+d_files='d d/f3'
+
+chgrp $g1 f || fail=1 ; test $(stat --p=%g f) = $g1 || fail=1
+chgrp $g2 f || fail=1 ; test $(stat --p=%g f) = $g2 || fail=1
+chgrp $g2 f || fail=1 ; test $(stat --p=%g f) = $g2 || fail=1
+chgrp '' f || fail=1 ; test $(stat --p=%g f) = $g2 || fail=1
+chgrp $g1 f || fail=1 ; test $(stat --p=%g f) = $g1 || fail=1
+chgrp $g1 f || fail=1 ; test $(stat --p=%g f) = $g1 || fail=1
+chgrp --reference=f2 f ; test $(stat --p=%g f) = $g2 || fail=1
+
+chgrp -R $g2 d ||fail=1; test $(stat --p=%g: $d_files) = "$g2:$g2:" || fail=1
+chgrp -R $g1 d ||fail=1; test $(stat --p=%g: $d_files) = "$g1:$g1:" || fail=1
+chgrp -R $g2 d ||fail=1; test $(stat --p=%g: $d_files) = "$g2:$g2:" || fail=1
+chgrp -R $g1 d ||fail=1; test $(stat --p=%g: $d_files) = "$g1:$g1:" || fail=1
+chgrp $g2 d ||fail=1; test $(stat --p=%g: $d_files) = "$g2:$g1:" || fail=1
+
+rm -f f
+touch f
+ln -s f symlink
+chgrp $g1 f
+test $(stat --printf=%g f) = $g1 || fail=1
+
+# This should not change the group of f.
+chgrp -h $g2 symlink
+test $(stat --printf=%g f) = $g1 || fail=1
+
+# Don't fail if chgrp failed to set the group of a symlink.
+# Some systems don't support that.
+test $(stat --printf=%g symlink) = $g2 ||
+ echo 'info: failed to set group of symlink' 1>&2
+
+chown --from=:$g1 :$g2 f; test $(stat --printf=%g f) = $g2 || fail=1
+
+# This *should* change the group of f.
+# Though note that the diagnostic is misleading in that
+# it says the 'group of 'symlink'' has been changed.
+chgrp $g1 symlink; test $(stat --printf=%g f) = $g1 || fail=1
+chown --from=:$g1 :$g2 f; test $(stat --printf=%g f) = $g2 || fail=1
+
+# If -R is specified without -H or L, -h is assumed.
+chgrp -h $g1 f symlink; test $(stat --printf=%g symlink) = $g1 || fail=1
+chgrp -R $g2 symlink
+chown --from=:$g1 :$g2 f; test $(stat --printf=%g f) = $g2 || fail=1
+
+# Make sure we can change the group of inaccessible files.
+chmod a-r f
+chown --from=:$g2 :$g1 f; test $(stat --printf=%g f) = $g1 || fail=1
+chmod 0 f
+chown --from=:$g1 :$g2 f; test $(stat --printf=%g f) = $g2 || fail=1
+
+# chown() must not be optimized away even when
+# the file's owner and group already have the desired value.
+rm -f f g
+touch f g
+chgrp $g1 f g
+chgrp $g2 g
+sleep 1
+chgrp $g1 f
+
+# The following no-change chgrp command is supposed to update f's ctime,
+# but on OpenBSD and Darwin 7.9.0-8.11.1 (aka MacOS X 10.3.9 - 10.4.11)
+# it appears to be a no-op for some file system types (at least NFS) so g's
+# ctime is more recent. This is not a big deal;
+# this test works fine when the files are on a local file system (/tmp).
+chgrp '' f
+test "$(ls -C -c -t f g)" = 'f g' || \
+ {
+ case $host_triplet in
+ *openbsd*) echo ignoring known OpenBSD-specific chgrp failure 1>&2 ;;
+ *darwin7.9.*|*darwin8.*)
+ echo ignoring known MacOS X-specific chgrp failure 1>&2 ;;
+ *) echo $host_triplet: no-change chgrp failed to update ctime 1>&2;
+ fail=1 ;;
+ esac
+ }
+
+Exit $fail
diff --git a/tests/chgrp/default-no-deref.sh b/tests/chgrp/default-no-deref.sh
new file mode 100755
index 0000000..22a439a
--- /dev/null
+++ b/tests/chgrp/default-no-deref.sh
@@ -0,0 +1,34 @@
+#!/bin/sh
+# Ensure that chgrp -R does not dereference symlinks.
+
+# Copyright (C) 2006-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ chgrp
+require_membership_in_two_groups_
+require_local_dir_
+
+set _ $groups; shift
+g2=$2
+
+mkdir d && touch f && ln -s ../f d/s || framework_failure_
+
+
+g_init=$(stat --printf=%g f)
+chgrp -R $g2 d || fail=1
+test $(stat --printf=%g f) = $g_init || fail=1
+
+Exit $fail
diff --git a/tests/chgrp/deref.sh b/tests/chgrp/deref.sh
new file mode 100755
index 0000000..ef10444
--- /dev/null
+++ b/tests/chgrp/deref.sh
@@ -0,0 +1,60 @@
+#!/bin/sh
+# see if chgrp can change the group of a symlink
+
+# Copyright (C) 2000-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ chgrp
+require_membership_in_two_groups_
+
+set _ $groups; shift
+g1=$1
+g2=$2
+
+touch f
+ln -s f symlink
+
+chgrp -h $g2 symlink 2> /dev/null
+set _ $(ls -ln symlink)
+g=$5
+test "$g" = $g2 ||
+ skip_ "your system doesn't support changing the owner or group" \
+ "of a symbolic link."
+
+
+chgrp $g1 f
+set _ $(ls -ln f); g=$5; test "$g" = $g1 || fail=1
+
+chgrp -h $g2 symlink || fail=1
+set _ $(ls -ln f); g=$5; test "$g" = $g1 || fail=1
+set _ $(ls -ln symlink); g=$5; test "$g" = $g2 || fail=1
+
+# This should not change the group of f.
+chgrp -h $g2 symlink || fail=1
+set _ $(ls -ln f); g=$5; test "$g" = $g1 || fail=1
+set _ $(ls -ln symlink); g=$5; test "$g" = $g2 || fail=1
+
+chgrp $g2 f
+set _ $(ls -ln f); g=$5; test "$g" = $g2 || fail=1
+
+# This *should* change the group of f.
+# Though note that the diagnostic you'd get with -c is misleading in that
+# it says the 'group of 'symlink'' has been changed.
+chgrp --dereference $g1 symlink
+set _ $(ls -ln f); g=$5; test "$g" = $g1 || fail=1
+set _ $(ls -ln symlink); g=$5; test "$g" = $g2 || fail=1
+
+Exit $fail
diff --git a/tests/chgrp/no-x.sh b/tests/chgrp/no-x.sh
new file mode 100755
index 0000000..8397d80
--- /dev/null
+++ b/tests/chgrp/no-x.sh
@@ -0,0 +1,55 @@
+#!/bin/sh
+# Make sure chgrp gives the right diagnostic for a readable,
+# but inaccessible directory.
+
+# Copyright (C) 2003-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ chgrp
+require_membership_in_two_groups_
+skip_if_root_
+require_local_dir_
+
+set _ $groups; shift
+g1=$1
+g2=$2
+
+mkdir -p d/no-x/y || framework_failure_
+chmod u=rw d/no-x || framework_failure_
+
+
+# This must exit nonzero.
+chgrp -R $g2 d >/dev/null 2>out && fail=1
+
+prog=chgrp
+# NOTE: this code is the same for all tests/*/no-x tests.
+# Depending on whether fts is using native fdopendir, we see one
+# of the following diagnostics (note also the /y suffix in one case):
+# prog: 'd/no-x': Permission denied
+# prog: cannot access 'd/no-x/y': Permission denied
+# prog: cannot read directory 'd/no-x': Permission denied
+# Convert either of the latter two to the first one.
+sed "s/^$prog: cannot access /$prog: /" out > t && mv t out
+sed "s/^$prog: cannot read directory /$prog: /" out > t && mv t out
+sed 's,d/no-x/y,d/no-x,' out > t && mv t out
+
+cat <<EOF > exp
+$prog: 'd/no-x': Permission denied
+EOF
+
+compare exp out || fail=1
+
+Exit $fail
diff --git a/tests/chgrp/posix-H.sh b/tests/chgrp/posix-H.sh
new file mode 100755
index 0000000..e57e250
--- /dev/null
+++ b/tests/chgrp/posix-H.sh
@@ -0,0 +1,71 @@
+#!/bin/sh
+# Test POSIX-mandated -H option.
+
+# Copyright (C) 2003-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ chgrp
+require_membership_in_two_groups_
+require_local_dir_
+
+set _ $groups; shift
+g1=$1
+g2=$2
+
+mkdir 1 2 3 || framework_failure_
+touch 1/1F 2/2F 3/3F || framework_failure_
+ln -s 1 1s || framework_failure_
+ln -s ../3 2/2s || framework_failure_
+chgrp -R $g1 1 2 3 || framework_failure_
+
+
+chgrp --preserve-root -H -R $g2 1s 2 || fail=1
+
+# These must have group $g2.
+# =========================
+changed='
+1
+1/1F
+2
+2/2F
+3
+'
+for i in $changed; do
+ # Filter out symlinks (entries that end in 's'), since it's not
+ # possible to change their group/owner information on some systems.
+ case $i in *s) continue;; esac
+ set _ $(ls -dgn $i); shift
+ group=$3
+ test $group = $g2 || fail=1
+done
+
+# These must have group $g1.
+# =========================
+not_changed='
+1s
+2/2s
+3/3F
+'
+for i in $not_changed; do
+ # Filter out symlinks (entries that end in 's'), since it's not
+ # possible to change their group/owner information on some systems.
+ case $i in *s) continue;; esac
+ set _ $(ls -dgn $i); shift
+ group=$3
+ test $group = $g1 || fail=1
+done
+
+Exit $fail
diff --git a/tests/chgrp/recurse.sh b/tests/chgrp/recurse.sh
new file mode 100755
index 0000000..3a8b365
--- /dev/null
+++ b/tests/chgrp/recurse.sh
@@ -0,0 +1,54 @@
+#!/bin/sh
+# ad-hoc tests of chgrp with -R and -H or -L and symlinks
+
+# Copyright (C) 2000-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ chgrp
+require_membership_in_two_groups_
+require_local_dir_
+
+set _ $groups; shift
+g1=$1
+g2=$2
+
+
+# chgrp -R should not traverse a symlink to a directory.
+mkdir d e
+touch d/dd e/ee
+ln -s ../e d/s
+chgrp -R $g1 e/ee || fail=1
+# This should not should change the group of e/ee
+chgrp -R $g2 d
+set _ $(ls -ln e/ee); g=$5; test "$g" = $g1 || fail=1
+# This must change the group of e/ee, since -L makes
+# chgrp traverse the symlink from d/s into e.
+chgrp -L -R $g2 d
+set _ $(ls -ln e/ee); g=$5; test "$g" = $g2 || fail=1
+
+# This must *not* change the group of e/ee
+chgrp -H -R $g1 d
+set _ $(ls -ln e/ee); g=$5; test "$g" = $g2 || fail=1
+
+ln -s d link
+
+# This shouldn't change the group of e/ee either.
+chgrp -H -R $g1 link || fail=1
+set _ $(ls -ln e/ee); g=$5; test "$g" = $g2 || fail=1
+# But it *should* change d/dd.
+set _ $(ls -ln d/dd); g=$5; test "$g" = $g1 || fail=1
+
+Exit $fail
diff --git a/tests/chmod/c-option.sh b/tests/chmod/c-option.sh
new file mode 100755
index 0000000..c683d12
--- /dev/null
+++ b/tests/chmod/c-option.sh
@@ -0,0 +1,51 @@
+#!/bin/sh
+# Verify that chmod's --changes (-c) option works.
+
+# Copyright (C) 2000-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ chmod
+
+umask 0
+file=f
+touch $file || framework_failure_
+chmod 444 $file || framework_failure_
+
+skip_if_setgid_
+
+
+chmod u=rwx $file || fail=1
+chmod -c g=rwx $file > out || fail=1
+chmod -c g=rwx $file > empty || fail=1
+
+compare /dev/null empty || fail=1
+case "$(cat out)" in
+ "mode of 'f' changed from 0744 "?rwxr--r--?" to 0774 "?rwxrwxr--?) ;;
+ *) cat out; fail=1 ;;
+esac
+
+# From V5.1.0 to 8.22 this would stat the wrong file and
+# give an erroneous ENOENT diagnostic
+mkdir -p a/b || framework_failure_
+# chmod g+s might fail as detailed in setgid.sh
+# but we don't care about those edge cases here
+chmod g+s a/b
+# This should never warn, but it did when special
+# bits are set on b (the common case under test)
+chmod -c -R g+w a 2>err
+compare /dev/null err || fail=1
+
+Exit $fail
diff --git a/tests/chmod/equal-x.sh b/tests/chmod/equal-x.sh
new file mode 100755
index 0000000..6a8de0f
--- /dev/null
+++ b/tests/chmod/equal-x.sh
@@ -0,0 +1,34 @@
+#!/bin/sh
+# Test "chmod =x" and the like.
+
+# Copyright (C) 1999-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ chmod
+
+file=f
+touch $file || framework_failure_
+
+umask 005
+for mode in =x =xX =Xx =x,=X =X,=x; do
+ chmod a=r,$mode $file || fail=1
+ case "$(ls -l $file)" in
+ ---x--x---*) ;;
+ *) fail=1; echo "after 'chmod $mode $file':"; ls -l $file ;;
+ esac
+done
+
+Exit $fail
diff --git a/tests/chmod/equals.sh b/tests/chmod/equals.sh
new file mode 100755
index 0000000..c343e9c
--- /dev/null
+++ b/tests/chmod/equals.sh
@@ -0,0 +1,46 @@
+#!/bin/sh
+# Make sure chmod mode arguments of the form A=B work properly.
+# Before fileutils-4.1.2, some of them didn't.
+# Also, before coreutils-5.3.1, =[ugo] sometimes didn't work.
+
+# Copyright (C) 2001-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ chmod
+
+touch f || framework_failure_
+
+
+expected_u=-rwx------
+expected_g=----rwx---
+expected_o=-------rwx
+
+for src in u g o; do
+ for dest in u g o; do
+ test $dest = $src && continue
+ chmod a=,$src=rwx,$dest=$src,$src= f || fail=1
+ actual_perms=$(ls -l f|cut -b-10)
+ expected_perms=$(eval 'echo $expected_'$dest)
+ test "$actual_perms" = "$expected_perms" || fail=1
+ done
+done
+
+umask 027
+chmod a=,u=rwx,=u f || fail=1
+actual_perms=$(ls -l f|cut -b-10)
+test "$actual_perms" = "-rwxr-x---" || fail=1
+
+Exit $fail
diff --git a/tests/chmod/ignore-symlink.sh b/tests/chmod/ignore-symlink.sh
new file mode 100755
index 0000000..5ee561b
--- /dev/null
+++ b/tests/chmod/ignore-symlink.sh
@@ -0,0 +1,31 @@
+#!/bin/sh
+# Test for proper exit code of chmod on a processed symlink.
+
+# Copyright (C) 2021-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ chmod
+
+mkdir dir || framework_failure_
+touch dir/f || framework_failure_
+ln -s f dir/l || framework_failure_
+
+# This operation ignores symlinks but should succeed.
+chmod u+w -R dir 2> out || fail=1
+
+compare /dev/null out || fail=1
+
+Exit $fail
diff --git a/tests/chmod/inaccessible.sh b/tests/chmod/inaccessible.sh
new file mode 100755
index 0000000..340f75d
--- /dev/null
+++ b/tests/chmod/inaccessible.sh
@@ -0,0 +1,28 @@
+#!/bin/sh
+# Test for the bug fixed on 2006-09-20.
+
+# Copyright (C) 2006-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ chmod
+
+mkdir -p d/e || framework_failure_
+chmod 0 d/e d || framework_failure_
+
+
+chmod u+rwx d d/e || fail=1
+
+Exit $fail
diff --git a/tests/chmod/no-x.sh b/tests/chmod/no-x.sh
new file mode 100755
index 0000000..50c2480
--- /dev/null
+++ b/tests/chmod/no-x.sh
@@ -0,0 +1,56 @@
+#!/bin/sh
+# Make sure chmod gives the right diagnostic for a readable,
+# but inaccessible directory.
+
+# Copyright (C) 2003-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ chmod
+skip_if_root_
+
+mkdir -p d/no-x/y a/b || framework_failure_
+chmod u=rw d/no-x || framework_failure_
+
+
+# This must exit nonzero.
+chmod -R o=r d >/dev/null 2>out && fail=1
+
+prog=chmod
+# NOTE: this code is the same for all tests/*/no-x tests.
+# Depending on whether fts is using native fdopendir, we see one
+# of the following diagnostics (note also the /y suffix in one case):
+# prog: 'd/no-x': Permission denied
+# prog: cannot access 'd/no-x/y': Permission denied
+# prog: cannot read directory 'd/no-x': Permission denied
+# Convert either of the latter two to the first one.
+sed "s/^$prog: cannot access /$prog: /" out > t && mv t out
+sed "s/^$prog: cannot read directory /$prog: /" out > t && mv t out
+sed 's,d/no-x/y,d/no-x,' out > t && mv t out
+
+cat <<EOF > exp
+$prog: 'd/no-x': Permission denied
+EOF
+
+compare exp out || fail=1
+
+cd a
+# This will fail with ''chmod: fts_read failed: Permission denied''
+# chmod must exit with status 1.
+# Due to a bug in coreutils-5.93's fts.c, chmod would provoke
+# an abort (exit with status 134) on recent glibc-based systems.
+returns_ 1 chmod a-x . b 2> /dev/null || fail=1
+
+Exit $fail
diff --git a/tests/chmod/octal.sh b/tests/chmod/octal.sh
new file mode 100755
index 0000000..0cecda4
--- /dev/null
+++ b/tests/chmod/octal.sh
@@ -0,0 +1,29 @@
+#!/bin/sh
+# ensure that chmod diagnoses a certain type of invalid mode string
+
+# Copyright (C) 2005-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ chmod
+
+
+# Before coreutils-5.92, this would mistakenly succeed,
+# and act like 'chmod 0 .'.
+for mode in '0-anything' '7-anything' '8'; do
+ returns_ 1 chmod "$mode" . 2>/dev/null || fail=1
+done
+
+Exit $fail
diff --git a/tests/chmod/setgid.sh b/tests/chmod/setgid.sh
new file mode 100755
index 0000000..d7a4b3e
--- /dev/null
+++ b/tests/chmod/setgid.sh
@@ -0,0 +1,63 @@
+#!/bin/sh
+# Make sure GNU chmod works the same way as those of Solaris, HPUX, AIX
+# on directories with the setgid bit set. Also, check that the GNU octal
+# notations work.
+
+# Copyright (C) 2001-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ chmod
+
+umask 0
+mkdir -m 755 d || framework_failure_
+
+# "chmod g+s d" does nothing on some NFS file systems.
+chmod g+s d 2> /dev/null && env -- test -g d ||
+ {
+ # This is required because on some systems (at least NetBSD 1.4.2A),
+ # it may happen that when you create a directory, its group isn't one
+ # to which you belong. When that happens, the above chmod fails. So
+ # here, upon failure, we try to set the group, then rerun the chmod command.
+
+ for id_g in $(id -g) $(id -G) ''; do
+ test -n "$id_g" || break
+ chgrp "$id_g" d && chmod g+s d && env -- test -g d && break
+ done
+ test -n "$id_g"
+ } ||
+ skip_ 'cannot create setgid directories'
+
+for mode in \
+ + - g-s 00755 000755 =755 -2000 -7022 755 0755 \
+ +2000 -5022 =7777,-5022
+do
+ chmod $mode d || fail=1
+
+ case $mode in
+ g-s | 00*755 | =755 | -2000 | -7022)
+ expected_mode=drwxr-xr-x ;;
+ *) expected_mode=drwxr-sr-x ;;
+ esac
+ ls_output=$(ls -ld d)
+ case $ls_output in
+ $expected_mode*) ;;
+ *) fail=1 ;;
+ esac
+
+ chmod =2755 d || fail=1
+done
+
+Exit $fail
diff --git a/tests/chmod/silent.sh b/tests/chmod/silent.sh
new file mode 100755
index 0000000..b2ed3e7
--- /dev/null
+++ b/tests/chmod/silent.sh
@@ -0,0 +1,29 @@
+#!/bin/sh
+# ensure that chgrp, chmod, chown -f don't print some diagnostics
+
+# Copyright (C) 2008-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ chgrp chmod chown
+
+chmod -f 0 no-such 2> out && fail=1
+chgrp -f 0 no-such 2>> out && fail=1
+chown -f 0:0 no-such 2>> out && fail=1
+touch exp || fail=1
+
+compare exp out || fail=1
+
+Exit $fail
diff --git a/tests/chmod/thru-dangling.sh b/tests/chmod/thru-dangling.sh
new file mode 100755
index 0000000..284c68b
--- /dev/null
+++ b/tests/chmod/thru-dangling.sh
@@ -0,0 +1,31 @@
+#!/bin/sh
+# Test for proper error and exit code of chmod on a dangling symlink.
+
+# Copyright (C) 2007-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ chmod
+
+ln -s non-existent dangle || framework_failure_
+
+
+# This operation cannot succeed since the symbolic link dangles.
+chmod 644 dangle 2> out && fail=1
+
+echo "chmod: cannot operate on dangling symlink 'dangle'" > exp
+compare exp out || fail=1
+
+Exit $fail
diff --git a/tests/chmod/umask-x.sh b/tests/chmod/umask-x.sh
new file mode 100755
index 0000000..cd8c275
--- /dev/null
+++ b/tests/chmod/umask-x.sh
@@ -0,0 +1,26 @@
+#!/bin/sh
+# Test that chmod -x file reports an error if the result is executable.
+
+# Copyright (C) 2005-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ chmod
+
+touch file
+chmod 755 file
+(umask 77 && returns_ 1 chmod -x file) 2>/dev/null || fail=1
+
+Exit $fail
diff --git a/tests/chmod/usage.sh b/tests/chmod/usage.sh
new file mode 100755
index 0000000..e83270b
--- /dev/null
+++ b/tests/chmod/usage.sh
@@ -0,0 +1,86 @@
+#!/bin/sh
+# Verify that chmod works correctly with odd option combinations.
+
+# Copyright (C) 2004-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ chmod
+
+
+# Each line in this list is a set of arguments, followed by :,
+# followed by the set of files it will attempt to chmod,
+# or empty if the usage is erroneous.
+# Many of these test cases are due to Glenn Fowler.
+# These test cases assume GNU behavior for "options" like -w.
+cases='
+ -- :
+ -- -- :
+ -- -- -- f : -- f
+ -- -- -w f : -w f
+ -- -- f : f
+ -- -w :
+ -- -w -- f : -- f
+ -- -w -w f : -w f
+ -- -w f : f
+ -- f :
+ -w :
+ -w -- :
+ -w -- -- f : -- f
+ -w -- -w f : -w f
+ -w -- f : f
+ -w -w :
+ -w -w -- f : f
+ -w -w -w f : f
+ -w -w f : f
+ -w f : f
+ f :
+ f -- :
+ f -w : f
+ f f :
+ u+gr f :
+ ug,+x f :
+'
+
+all_files=$(echo "$cases" | sed 's/.*://'|sort -u)
+
+old_IFS=$IFS
+IFS='
+'
+for case in $cases; do
+ IFS=$old_IFS
+ args=$(expr "$case" : ' *\(.*[^ ]\) *:')
+ files=$(expr "$case" : '.*: *\(.*\)')
+
+ case $files in
+ '')
+ touch -- $all_files || framework_failure_
+ returns_ 1 chmod $args 2>/dev/null || fail=1
+ ;;
+ ?*)
+ touch -- $files || framework_failure_
+ chmod $args || fail=1
+ for file in $files; do
+ # Test for misparsing args by creating all $files but $file.
+ # chmod has a bug if it succeeds even though $file is absent.
+ rm -f -- $all_files && touch -- $files && rm -- $file \
+ || framework_failure_
+ returns_ 1 chmod $args 2>/dev/null || fail=1
+ done
+ ;;
+ esac
+done
+
+Exit $fail
diff --git a/tests/chown/basic.sh b/tests/chown/basic.sh
new file mode 100755
index 0000000..2db9ef7
--- /dev/null
+++ b/tests/chown/basic.sh
@@ -0,0 +1,59 @@
+#!/bin/sh
+# make sure chown --from=... works
+
+# Copyright (C) 2001-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ chown
+require_root_
+
+touch f || framework_failure_
+
+chown -R --preserve-root 0:1 f
+
+# Make sure the owner and group are 0 and 1 respectively.
+set _ $(ls -n f); shift; test "$3:$4" = 0:1 || fail=1
+
+# Make sure the correct diagnostic is output
+# Note we output a name even though an id was specified.
+chown -v --from=42 43 f > out || fail=1
+printf "ownership of 'f' retained as $(id -nu)\n" > exp
+compare exp out || fail=1
+
+# Ensure diagnostics work for non existent files.
+returns_ 1 chown -v 0 nf > out || fail=1
+printf "failed to change ownership of 'nf' to 0\n" > exp
+compare exp out || fail=1
+
+chown --from=0:1 2:010 f || fail=1
+
+# And now they should be 2 and 10 respectively.
+set _ $(ls -n f); shift; test "$3:$4" = 2:10 || fail=1
+
+ln -s f slink
+# Applying chown to a symlink with --no-dereference
+# should change only the link.
+chown --no-dereference 0:1 slink || fail=1
+# owner/group on the symlink should be set
+set _ $(ls -n slink); shift; test "$3:$4" = 0:1 || fail=1
+# owner/group on the referent should remain unchanged
+set _ $(ls -n f); shift; test "$3:$4" = 2:10 || fail=1
+
+chown --no-dereference --from=0:1 2:010 slink || fail=1
+# owner/group on the symlink should be changed
+set _ $(ls -n slink); shift; test "$3:$4" = 2:10 || fail=1
+
+Exit $fail
diff --git a/tests/chown/deref.sh b/tests/chown/deref.sh
new file mode 100755
index 0000000..d669a7c
--- /dev/null
+++ b/tests/chown/deref.sh
@@ -0,0 +1,38 @@
+#!/bin/sh
+# For coreutils-5.2.1 and earlier, chown --dereference would skip
+# symlinks having owner/group matching the specified owner/group.
+
+# Copyright (C) 2004-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ chown
+
+ln -s no-such dangle || framework_failure_
+
+
+set _ $(ls -ldo dangle); shift; user=$3
+
+# With 5.2.1 and earlier, this command would mistakenly succeed.
+chown --dereference $user dangle 2> out1 && fail=1
+sed 's/: [^:]*$//' out1 > out
+
+cat <<\EOF > exp || framework_failure_
+chown: cannot dereference 'dangle'
+EOF
+
+compare exp out || fail=1
+
+Exit $fail
diff --git a/tests/chown/preserve-root.sh b/tests/chown/preserve-root.sh
new file mode 100755
index 0000000..4ef8662
--- /dev/null
+++ b/tests/chown/preserve-root.sh
@@ -0,0 +1,66 @@
+#!/bin/sh
+# Verify that --preserve-root works.
+
+# Copyright (C) 2006-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ chown
+skip_if_root_
+
+mkdir d && ln -s / d/slink-to-root
+
+
+# Even if --preserve-root were to malfunction, allowing the chown or
+# chgrp to traverse through "/", since we're running as non-root,
+# they would be very unlikely to cause any changes.
+chown -R --preserve-root 0 / > out 2>&1 && fail=1
+chgrp -R --preserve-root 0 / >> out 2>&1 && fail=1
+
+# Here, if --preserve-root were to malfunction, chmod could make changes,
+# but only to files owned and unreadable by the user running this test,
+# and then, only to make them readable by owner.
+chmod -R --preserve-root u+r / >> out 2>&1 && fail=1
+
+# With -RHh, --preserve-root should trigger nothing,
+# since the symlink in question is not a command line argument.
+# Contrary to the above commands, these two should succeed.
+echo '==== test -RHh' >> out || framework_failure_
+chown -RHh --preserve-root $(id -u) d >> out 2>&1 || fail=1
+chgrp -RHh --preserve-root $(id -g) d >> out 2>&1 || fail=1
+
+# These must fail.
+echo '==== test -RLh' >> out || framework_failure_
+chown -RLh --preserve-root $(id -u) d >> out 2>&1 && fail=1
+chgrp -RLh --preserve-root $(id -g) d >> out 2>&1 && fail=1
+
+cat <<\EOF > exp || framework_failure_
+chown: it is dangerous to operate recursively on '/'
+chown: use --no-preserve-root to override this failsafe
+chgrp: it is dangerous to operate recursively on '/'
+chgrp: use --no-preserve-root to override this failsafe
+chmod: it is dangerous to operate recursively on '/'
+chmod: use --no-preserve-root to override this failsafe
+==== test -RHh
+==== test -RLh
+chown: it is dangerous to operate recursively on 'd/slink-to-root' (same as '/')
+chown: use --no-preserve-root to override this failsafe
+chgrp: it is dangerous to operate recursively on 'd/slink-to-root' (same as '/')
+chgrp: use --no-preserve-root to override this failsafe
+EOF
+
+compare exp out || fail=1
+
+Exit $fail
diff --git a/tests/chown/separator.sh b/tests/chown/separator.sh
new file mode 100755
index 0000000..7901cf8
--- /dev/null
+++ b/tests/chown/separator.sh
@@ -0,0 +1,69 @@
+#!/bin/sh
+# Make sure "chown USER:GROUP FILE" works, and similar tests with separators.
+
+# Copyright (C) 2004-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ chown
+
+id_u=$(id -u) || framework_failure_
+test -n "$id_u" || framework_failure_
+
+id_un=$(id -un) || framework_failure_
+test -n "$id_un" || framework_failure_
+
+id_g=$(id -g) || framework_failure_
+test -n "$id_g" || framework_failure_
+
+id_gn=$(id -gn) || framework_failure_
+test -n "$id_gn" || framework_failure_
+
+# Systems with both local and external groups with conflicting IDs,
+# were seen to fail this test erroneously with EPERM errors.
+test $(getent group | grep "^$id_gn:" | wc -l) = 1 ||
+ skip_ "group '$id_gn' not unique: " \
+ "$(getent group | grep "^$id_gn:" | tr '\n' ',')"
+
+# FreeBSD 6.x's getgrnam fails to look up a group name containing
+# a space. On such a system, skip this test if the group name contains
+# a byte not in the portable filename character set.
+case $host_triplet in
+ *-freebsd6.*)
+ case $id_gn in
+ *[^a-zA-Z0-9._-]*) skip_ "invalid group name: $id_gn";;
+ esac;;
+ *) ;;
+esac
+
+
+chown '' . || fail=1
+
+for u in $id_u "$id_un" ''; do
+ for g in $id_g "$id_gn" ''; do
+ case $u$g in
+ *.*) seps=':' ;;
+ *) seps=': .' ;;
+ esac
+ for sep in $seps; do
+ case $u$sep$g in
+ [0-9]*$sep) returns_ 1 chown "$u$sep$g" . 2>/dev/null || fail=1 ;;
+ *) chown "$u$sep$g" . || fail=1 ;;
+ esac
+ done
+ done
+done
+
+Exit $fail
diff --git a/tests/chroot/chroot-credentials.sh b/tests/chroot/chroot-credentials.sh
new file mode 100755
index 0000000..19f4219
--- /dev/null
+++ b/tests/chroot/chroot-credentials.sh
@@ -0,0 +1,123 @@
+#!/bin/sh
+# Verify that the credentials are changed correctly.
+
+# Copyright (C) 2009-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ chroot
+
+require_root_
+
+EXIT_CANCELED=125
+
+grep '^#define HAVE_SETGROUPS 1' "$CONFIG_HEADER" >/dev/null \
+ && HAVE_SETGROUPS=1
+
+root=$(id -nu 0) || skip_ "Couldn't look up root username"
+
+# verify numeric IDs looked up similarly to names
+NON_ROOT_UID=$(id -u $NON_ROOT_USERNAME)
+NON_ROOT_GROUP=$NON_ROOT_GID # Used where we want name lookups to occur
+
+# "uid:" is supported (unlike chown etc.) since we treat it like "uid"
+chroot --userspec=$NON_ROOT_UID: / true || fail=1
+
+# verify that invalid groups are diagnosed
+for g in ' ' ',' '0trail'; do
+ returns_ $EXIT_CANCELED chroot --groups="$g" / id -G >invalid || fail=1
+ compare /dev/null invalid || fail=1
+done
+
+# Verify that root credentials are kept.
+test $(chroot / whoami) = "$root" || fail=1
+test "$(groups)" = "$(chroot / groups)" || fail=1
+
+# Verify that credentials are changed correctly.
+whoami_after_chroot=$(
+ chroot --userspec=$NON_ROOT_USERNAME:$NON_ROOT_GROUP / whoami
+)
+test "$whoami_after_chroot" != "$root" || fail=1
+
+# Verify that when specifying only a group we don't change the
+# list of supplemental groups
+test "$(chroot --userspec=:$NON_ROOT_GROUP / id -G)" = \
+ "$NON_ROOT_GID $(id -G)" || fail=1
+
+if ! test "$HAVE_SETGROUPS"; then
+ Exit $fail
+fi
+
+# Change all whitespaces to newlines, then sort the input.
+# Use for tests with more groups in 'id' output.
+num_sort() { tr -s ' ' '\n' | sort -n; }
+
+# Verify that there are no additional groups.
+id_G_after_chroot=$(
+ chroot --userspec=$NON_ROOT_USERNAME:$NON_ROOT_GROUP \
+ --groups=$NON_ROOT_GROUP / id -G
+)
+test "$id_G_after_chroot" = $NON_ROOT_GID || fail=1
+
+# Verify that when specifying only the user name we get all their groups
+test "$(chroot --userspec=$NON_ROOT_USERNAME / id -G | num_sort)" = \
+ "$(id -G $NON_ROOT_USERNAME | num_sort)" || fail=1
+
+# Ditto with trailing : on the user name.
+test "$(chroot --userspec=$NON_ROOT_USERNAME: / id -G | num_sort)" = \
+ "$(id -G $NON_ROOT_USERNAME | num_sort)" || fail=1
+
+# Verify that when specifying only the user and clearing supplemental groups
+# that we only get the primary group
+test "$(chroot --userspec=$NON_ROOT_USERNAME --groups='' / id -G)" = \
+ $NON_ROOT_GID || fail=1
+
+# Verify that when specifying only the UID we get all their groups
+test "$(chroot --userspec=$NON_ROOT_UID / id -G | num_sort)" = \
+ "$(id -G $NON_ROOT_USERNAME | num_sort)" || fail=1
+
+# Verify that when specifying only the user and clearing supplemental groups
+# that we only get the primary group. Note this variant with prepended '+'
+# results in no lookups in the name database which could be useful depending
+# on your chroot setup.
+test "$(chroot --userspec=+$NON_ROOT_UID:+$NON_ROOT_GID --groups='' / id -G)" =\
+ $NON_ROOT_GID || fail=1
+
+# Verify that when specifying only a group we get the current user ID
+test "$(chroot --userspec=:$NON_ROOT_GROUP / id -u)" = "$(id -u)" \
+ || fail=1
+
+# verify that arbitrary numeric IDs are supported
+test "$(chroot --userspec=1234:+5678 --groups=' +8765,4321' / id -G)" \
+ || fail=1
+
+# demonstrate that extraneous commas are supported
+test "$(chroot --userspec=1234:+5678 --groups=',8765,,4321,' / id -G)" \
+ || fail=1
+
+# demonstrate that --groups is not cumulative
+test "$(chroot --groups='invalid ignored' --groups='' / id -G)" \
+ || fail=1
+
+if ! id -u +12342; then
+ # Ensure supplemental groups cleared from some arbitrary unknown ID
+ test "$(chroot --userspec=+12342:+5678 / id -G)" = '5678' || fail=1
+
+ # Ensure we fail when we don't know what groups to set for an unknown ID
+ returns_ $EXIT_CANCELED chroot --userspec=+12342 / true || fail=1
+fi
+
+Exit $fail
diff --git a/tests/chroot/chroot-fail.sh b/tests/chroot/chroot-fail.sh
new file mode 100755
index 0000000..e5d671e
--- /dev/null
+++ b/tests/chroot/chroot-fail.sh
@@ -0,0 +1,63 @@
+#!/bin/sh
+# Verify that internal failure in chroot gives exact status.
+
+# Copyright (C) 2009-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ chroot pwd
+
+# These tests verify exact status of internal failure; since none of
+# them actually run a command, we don't need root privileges
+returns_ 125 chroot || fail=1 # missing argument
+returns_ 125 chroot --- / true || fail=1 # unknown option
+
+# chroot("/") succeeds for non-root users on some systems, but not all.
+if chroot / true ; then
+ can_chroot_root=1
+ returns_ 2 chroot / sh -c 'exit 2' || fail=1 # exit status propagation
+ returns_ 126 chroot / . || fail=1# invalid command
+ returns_ 127 chroot / no_such || fail=1 # no such command
+else
+ test $? = 125 || fail=1
+ can_chroot_root=0
+fi
+
+# Ensure that --skip-chdir fails with a non-"/" argument.
+cat <<\EOF > exp || framework_failure_
+chroot: option --skip-chdir only permitted if NEWROOT is old '/'
+Try 'chroot --help' for more information.
+EOF
+chroot --skip-chdir . env pwd >out 2>err && fail=1
+compare /dev/null out || fail=1
+compare exp err || fail=1
+
+# Ensure we chdir("/") appropriately when NEWROOT is old "/".
+if test $can_chroot_root = 1; then
+ ln -s / isroot || framework_failure_
+ for dir in '/' '/.' '/../' isroot; do
+ # Verify that chroot(1) succeeds and performs chdir("/")
+ # (chroot(1) of coreutils-8.23 failed to run the latter).
+ curdir=$(chroot "$dir" env pwd) || fail=1
+ test "$curdir" = '/' || fail=1
+
+ # Test the "--skip-chdir" option.
+ curdir=$(chroot --skip-chdir "$dir" env pwd) || fail=1
+ test "$curdir" = '/' && fail=1
+ done
+fi
+
+Exit $fail
diff --git a/tests/cksum/b2sum.sh b/tests/cksum/b2sum.sh
new file mode 100755
index 0000000..475faa2
--- /dev/null
+++ b/tests/cksum/b2sum.sh
@@ -0,0 +1,70 @@
+#!/bin/sh
+# 'b2sum' tests
+
+# Copyright (C) 2016-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ cksum
+
+for prog in 'b2sum' 'cksum -a blake2b'; do
+# Also check b2sum if built
+[ "$prog" = 'b2sum' ] && { $prog --version || continue; }
+
+# Ensure we can --check the --tag format we produce
+rm -f check.b2sum || framework_failure_
+[ "$prog" = 'b2sum' ] && tag_opt='--tag' || tag_opt=''
+for i in 'a' ' b' '*c' '44' ' '; do
+ echo "$i" > "$i"
+ for l in 0 128; do
+ $prog -l $l $tag_opt "$i" >> check.b2sum
+ done
+done
+# Note -l is inferred from the tags in the mixed format file
+$prog --strict -c check.b2sum || fail=1
+# Also ensure the openssl tagged variant works
+sed 's/ //; s/ =/=/' < check.b2sum > openssl.b2sum || framework_failure_
+$prog --strict -c openssl.b2sum || fail=1
+
+rm -f check.vals || framework_failure_
+# Ensure we can check non tagged format
+[ "$prog" != 'b2sum' ] && tag_opt='--untagged' || tag_opt=''
+for l in 0 128; do
+ $prog $tag_opt --text -l $l /dev/null | tee -a check.vals > check.b2sum
+ $prog -l $l --strict -c check.b2sum || fail=1
+ $prog --strict -c check.b2sum || fail=1
+done
+
+# Ensure the checksum values are correct. The reference
+# check.vals was created with the upstream SSE reference implementation.
+[ "$prog" != 'b2sum' ] && tag_opt='--untagged' || tag_opt=''
+$prog $tag_opt --length=128 check.vals > out.tmp || fail=1
+tr '*' ' ' < out.tmp > out || framework_failure_ # Remove binary tag on cygwin
+printf '%s\n' '796485dd32fe9b754ea5fd6c721271d9 check.vals' > exp
+compare exp out || fail=1
+
+# This would segfault from coreutils-8.26 to coreutils-8.28
+printf '%s\n' 'BLAKE2' 'BLAKE2b' 'BLAKE2-' 'BLAKE2(' 'BLAKE2 (' > crash.check \
+ || framework_failure_
+returns_ 1 $prog -c crash.check || fail=1
+
+# This would read unallocated memory from coreutils-9.2 to coreutils-9.3
+# which would trigger with ASAN or valgrind
+printf '0A0BA0' > overflow.check || framework_failure_
+returns_ 1 $prog -c overflow.check || fail=1
+
+done
+
+Exit $fail
diff --git a/tests/cksum/cksum-a.sh b/tests/cksum/cksum-a.sh
new file mode 100755
index 0000000..ec93fdd
--- /dev/null
+++ b/tests/cksum/cksum-a.sh
@@ -0,0 +1,61 @@
+#!/bin/sh
+# Validate cksum --algorithm operation
+
+# Copyright (C) 2021-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ cksum
+
+cat > input_options <<\EOF || framework_failure_
+bsd sum -r
+sysv sum -s
+crc cksum
+md5 md5sum MODE
+sha1 sha1sum MODE
+sha224 sha224sum MODE
+sha256 sha256sum MODE
+sha384 sha384sum MODE
+sha512 sha512sum MODE
+blake2b b2sum MODE
+EOF
+
+while read algo prog mode; do
+ for cmode in '-b' '-t'; do
+ pmode="$mode"
+ case $pmode in MODE) pmode=$cmode;; esac
+
+ $prog $pmode /dev/null >> out || continue
+ cksum --untagged $cmode --algorithm=$algo /dev/null > out-c || fail=1
+
+ case "$algo" in
+ bsd) ;;
+ sysv) ;;
+ crc) ;;
+ *) cksum --check --algorithm=$algo out-c || fail=1 ;;
+ esac
+
+ cat out-c >> out-a || framework_failure_
+ done
+done < input_options
+compare out out-a || fail=1
+
+# Ensure --check not allowed with older (non tagged) algorithms
+returns_ 1 cksum -a bsd --check </dev/null || fail=1
+
+# Ensure abbreviations not supported for algorithm selection
+returns_ 1 cksum -a sha22 </dev/null || fail=1
+
+Exit $fail
diff --git a/tests/cksum/cksum-base64.pl b/tests/cksum/cksum-base64.pl
new file mode 100755
index 0000000..0c4dd1e
--- /dev/null
+++ b/tests/cksum/cksum-base64.pl
@@ -0,0 +1,99 @@
+#!/usr/bin/perl
+# Exercise cksum's --base64 option.
+
+# Copyright (C) 2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+use strict;
+
+(my $program_name = $0) =~ s|.*/||;
+
+# Turn off localization of executable's output.
+@ENV{qw(LANGUAGE LANG LC_ALL)} = ('C') x 3;
+
+# Pairs of hash,degenerate_output, given file name of "f":
+my @pairs =
+ (
+ ['sysv', "0 0 f"],
+ ['bsd', "00000 0 f"],
+ ['crc', "4294967295 0 f"],
+ ['md5', "1B2M2Y8AsgTpgAmY7PhCfg=="],
+ ['sha1', "2jmj7l5rSw0yVb/vlWAYkK/YBwk="],
+ ['sha224', "0UoCjCo6K8lHYQK7KII0xBWisB+CjqYqxbPkLw=="],
+ ['sha256', "47DEQpj8HBSa+/TImW+5JCeuQeRkm5NMpJWZG3hSuFU="],
+ ['sha384', "OLBgp1GsljhM2TJ+sbHjaiH9txEUvgdDTAzHv2P24donTt6/529l+9Ua0vFImLlb"],
+ ['sha512', "z4PhNX7vuL3xVChQ1m2AB9Yg5AULVxXcg/SpIdNs6c5H0NE8XYXysP+DGNKHfuwvY7kxvUdBeoGlODJ6+SfaPg=="],
+ ['blake2b', "eGoC90IBWQPGxv2FJVLScpEvR0DhWEdhiobiF/cfVBnSXhAxr+5YUxOJZESTTrBLkDpoWxRIt1XVb3Aa/pvizg=="],
+ ['sm3', "GrIdg1XPoX+OYRlIMegajyK+yMco/vt0ftA161CCqis="],
+ );
+
+# Return the formatted output for a given hash name/value pair.
+# Use the hard-coded "f" as file name.
+sub fmt ($$) {
+ my ($h, $v) = @_;
+ $h !~ m{^(sysv|bsd|crc)$} and $v = uc($h). " (f) = $v";
+ # BLAKE2b is inconsistent:
+ $v =~ s{BLAKE2B}{BLAKE2b};
+ return "$v"
+}
+
+my @Tests =
+ (
+ # Ensure that each of the above works with --base64:
+ (map {my ($h,$v)= @$_; my $o=fmt $h,$v;
+ [$h, "--base64 -a $h", {IN=>{f=>''}}, {OUT=>"$o\n"}]} @pairs),
+
+ # For each that accepts --check, ensure that works with base64 digests:
+ (map {my ($h,$v)= @$_; my $o=fmt $h,$v;
+ ["chk-".$h, "--check --strict", {IN=>$o},
+ {AUX=>{f=>''}}, {OUT=>"f: OK\n"}]}
+ grep { $_->[0] !~ m{^(sysv|bsd|crc)$} } @pairs),
+
+ # For digests ending in "=", ensure --check fails if any "=" is removed.
+ (map {my ($h,$v)= @$_; my $o=fmt $h,$v;
+ ["chk-eq1-".$h, "--check", {IN=>$o}, {AUX=>{f=>''}},
+ {ERR_SUBST=>"s/.*: //"}, {OUT=>''}, {EXIT=>1},
+ {ERR=>"no properly formatted checksum lines found\n"}]}
+ ( map {my ($h,$v)=@$_; $v =~ s/=$//; [$h,$v] }
+ grep { $_->[1] =~ m{=$} } @pairs)),
+
+ # Same as above, but for those ending in "==":
+ (map {my ($h,$v)= @$_; my $o=fmt $h,$v;
+ ["chk-eq2-".$h, "--check", {IN=>$o}, {AUX=>{f=>''}},
+ {ERR_SUBST=>"s/.*: //"}, {OUT=>''}, {EXIT=>1},
+ {ERR=>"no properly formatted checksum lines found\n"}]}
+ ( map {my ($h,$v)=@$_; $v =~ s/==$//; [$h,$v] }
+ grep { $_->[1] =~ m{==$} } @pairs)),
+
+ # Trigger a read-buffer-overrun error in an early (not committed)
+ # version of the --base64-adding patch.
+ ['nul', '-a sha1 --check', {IN=>'\0\0\0'},
+ {ERR=>"no properly formatted checksum lines found\n"},
+ {ERR_SUBST=>"s/.*: //"}, {OUT=>''}, {EXIT=>1}],
+ );
+
+my $save_temps = $ENV{DEBUG};
+my $verbose = $ENV{VERBOSE};
+
+my $prog = 'cksum';
+my $fail = run_tests ($program_name, $prog, \@Tests, $save_temps, $verbose);
+
+# Ensure hash names from cksum --help match those in @pairs above.
+my $help_algs = join ' ', map { m{^ ([[:alpha:]]\S+)} }
+ grep { m{^ ([[:alpha:]]\S+)} } split ('\n', `cksum --help`);
+my $test_algs = join ' ', map {$_->[0]} @pairs;
+$help_algs eq $test_algs or die "$help_algs not equal to\n$test_algs";
+
+exit $fail;
diff --git a/tests/cksum/cksum-c.sh b/tests/cksum/cksum-c.sh
new file mode 100755
index 0000000..d645c1b
--- /dev/null
+++ b/tests/cksum/cksum-c.sh
@@ -0,0 +1,59 @@
+#!/bin/sh
+# Validate cksum --check dynamic operation
+
+# Copyright (C) 2021-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ cksum shuf
+
+shuf -i 1-10 > input || framework_failure_
+
+for args in '-a sha384' '-a blake2b' '-a blake2b -l 384' '-a sm3'; do
+ cksum $args 'input' >> CHECKSUMS || fail=1
+done
+cksum --strict --check CHECKSUMS || fail=1
+
+# Ensure leading whitespace and \ ignored
+sed 's/^/ \\/' CHECKSUMS | cksum --strict -c || fail=1
+
+# Check common signed checksums format works in non strict mode
+cat >> signed_CHECKSUMS <<\EOF
+-----BEGIN PGP SIGNED MESSAGE-----
+Hash: SHA384
+
+# ignored comment
+EOF
+cat CHECKSUMS >> signed_CHECKSUMS
+cat >> signed_CHECKSUMS <<\EOF
+-----BEGIN PGP SIGNATURE-----
+
+# Note base64 doesn't have ambiguous delimiters in its charset
+SHA384+BCAAdFiEEjFummQvbJuGfKhqAEWGuaUVxmjkFAmCDId0ACgkQEWGuaUVx
+BLAKE2b/00001EuON62pTEnqrJ5lav61QxRByiuDp/6VODrRL2JWM6Stxu1Myws=
+=AWU7
+-----END PGP SIGNATURE-----
+EOF
+cksum --check signed_CHECKSUMS || fail=1
+
+# Can check individual digests in a mixed file
+cksum --check -a sm3 CHECKSUMS || fail=1
+
+# Checks against older (non hex) checksum formats not supported
+returns_ 1 cksum -a crc -c CHECKSUMS || fail=1
+cksum -a crc 'input' > CHECKSUMS.crc || fail=1
+returns_ 1 cksum -c CHECKSUMS.crc || fail=1
+
+Exit $fail
diff --git a/tests/cksum/cksum-raw.sh b/tests/cksum/cksum-raw.sh
new file mode 100755
index 0000000..a5f14be
--- /dev/null
+++ b/tests/cksum/cksum-raw.sh
@@ -0,0 +1,60 @@
+#!/bin/sh
+# Validate cksum --raw operation
+
+# Copyright (C) 2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ cksum date od
+
+cat > digest_types <<\EOF || framework_failure_
+bsd u2
+sysv u2
+crc u4
+md5 x1
+sha1 x1
+sha224 x1
+sha256 x1
+sha384 x1
+sha512 x1
+blake2b x1
+sm3 x1
+EOF
+
+date > file.in || framework_failure_
+
+while read algo type; do
+ # Binary converted back to text
+ cksum --raw --algorithm $algo file.in > digest.bin || fail=1
+ d='digest.bin.txt'
+ od --endian=big -An -w1024 -t$type < digest.bin | tr -d ' ' \
+ > "$d" || framework_failure_
+ # Pad the bsd checksum with leading 0's, if needed.
+ case $algo in bsd) n=$(cat "$d"); printf '%05d\n' "$n" > "$d" ;; esac
+
+ # Standard text output
+ cksum --untagged --algorithm $algo < file.in | cut -d ' ' -f1 \
+ > digest.txt || fail=1
+
+ compare digest.txt "$d" || fail=1
+done < digest_types
+
+# Ensure --base64 and --raw not used together
+returns_ 1 cksum --base64 --raw </dev/null || fail=1
+
+# Ensure --raw not supported with multiple files
+returns_ 1 cksum --raw /dev/null /dev/null || fail=1
+
+Exit $fail
diff --git a/tests/cksum/cksum.sh b/tests/cksum/cksum.sh
new file mode 100755
index 0000000..21869fa
--- /dev/null
+++ b/tests/cksum/cksum.sh
@@ -0,0 +1,74 @@
+#!/bin/sh
+# Validate cksum operation
+
+# Copyright (C) 2020-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ cksum printf
+
+returns_ 1 cksum missing || fail=1
+
+{
+ for offset in $(seq -1 6); do
+ env printf $(env printf '\\%03o' $(seq 0 $offset));
+ env printf $(env printf '\\%03o' $(seq 0 255));
+ done
+} > in || framework_failure_
+
+cksum in > out || fail=1
+printf '%s\n' '4097727897 2077 in' > exp || framework_failure_
+compare exp out || fail=1
+
+# Make sure crc is correct for files larger than 128 bytes (4 fold pclmul)
+{
+ env printf $(env printf '\\%03o' $(seq 0 130));
+} > in || framework_failure_
+
+cksum in > out || fail=1
+printf '%s\n' '3800919234 131 in' > exp || framework_failure_
+compare exp out || fail=1
+
+# Make sure crc is correct for files larger than 32 bytes
+# but <128 bytes (1 fold pclmul)
+{
+ env printf $(env printf '\\%03o' $(seq 0 64));
+} > in || framework_failure_
+
+cksum in > out || fail=1
+printf '%s\n' '796287823 65 in' > exp || framework_failure_
+compare exp out || fail=1
+
+# Make sure crc is still handled correctly when next 65k buffer is read
+# (>32 bytes more than 65k)
+{
+ seq 1 12780
+} > in || framework_failure_
+
+cksum in > out || fail=1
+printf '%s\n' '3720986905 65574 in' > exp || framework_failure_
+compare exp out || fail=1
+
+# Make sure crc is still handled correctly when next 65k buffer is read
+# (>=128 bytes more than 65k)
+{
+ seq 1 12795
+} > in || framework_failure_
+
+cksum in > out || fail=1
+printf '%s\n' '4278270357 65664 in' > exp || framework_failure_
+compare exp out || fail=1
+
+Exit $fail
diff --git a/tests/cksum/md5sum-bsd.sh b/tests/cksum/md5sum-bsd.sh
new file mode 100755
index 0000000..2c7cd4d
--- /dev/null
+++ b/tests/cksum/md5sum-bsd.sh
@@ -0,0 +1,101 @@
+#!/bin/sh
+# 'md5sum' tests for generation and checking of
+# BSD traditional and alternate formats (md5 [-r])
+
+# Copyright (C) 2011-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ md5sum
+
+## BSD alternate format tests ##
+
+# Ensure we can --check BSD alternate format.
+# Note we start this list with a name
+# that's unambiguous in BSD format.
+# I.e., one not starting with ' ' or '*'
+for i in 'a' ' b' '*c' 'dd' ' '; do
+ echo "$i" > "$i"
+ md5sum --text "$i" >> check.md5sum || fail=1
+done
+sed 's/ / /' check.md5sum > check.md5
+
+# Note only a single format is supported per run
+md5sum --strict -c check.md5sum || fail=1
+md5sum --strict -c check.md5 || fail=1
+
+# Ensure we don't trigger BSD reversed format with GPG headers etc.
+{ echo '____not_all_hex_so_no_match_____ blah';
+ cat check.md5sum; } > check2.md5sum || framework_failure_
+md5sum -c check2.md5sum 2>check2.err || fail=1
+echo 'md5sum: WARNING: 1 line is improperly formatted' >check2.exp
+compare check2.exp check2.err || fail=1
+
+# If we skip the first entry in the BSD format checksums
+# then it'll be detected as standard format and error.
+# This unlikely caveat was thought better than mandating
+# an option to avoid the ambiguity.
+tail -n+2 check.md5 | returns_ 1 md5sum --strict -c || fail=1
+
+
+## BSD traditional format tests (--tag option) ##
+
+# Ensure --tag and --check are mutually exclusive
+returns_ 1 md5sum --tag --check /dev/null || fail=1
+
+# Ensure --tag and --text are mutually exclusive
+# We don't support --text with BSD tradition format,
+# as that would complicate the output format,
+# while providing little benefit over --text processing
+# available with the default md5sum output format.
+returns_ 1 md5sum --tag --text /dev/null || fail=1
+
+# Ensure we can --check BSD traditional format we produce
+rm check.md5
+for i in 'a' ' b' '*c' 'dd' ' '; do
+ echo "$i" > "$i"
+ md5sum --tag "$i" >> check.md5 || fail=1
+done
+md5sum --strict -c check.md5 || fail=1
+
+if : > 'backslash\is\not\dir\sep'; then
+ # Ensure we can --check BSD traditional format we produce
+ # with the GNU extension of escaped newlines
+ nl='
+'
+ t=' '
+ rm check.md5
+ for i in 'a\b' 'a\' '\a' "a${nl}b" "a${t}b"; do
+ : > "$i"
+ md5sum --tag "$i" >> check.md5 || fail=1
+ done
+ md5sum --strict -c check.md5 > out || fail=1
+ printf '%s: OK\n' '\a\\b' '\a\\' '\\\a' '\a\nb' "a${t}b" > exp ||
+ framework_failure_
+ compare exp out || fail=1
+
+
+ # Ensure BSD traditional format with GNU extension escapes
+ # is in the expected format
+ ex_file='test
+\\file'
+ ex_output='\MD5 (test\n\\\\file) = d41d8cd98f00b204e9800998ecf8427e'
+ touch "$ex_file"
+ printf "%s\n" "$ex_output" > exp
+ md5sum --tag "$ex_file" > out || fail=1
+ compare exp out || fail=1
+fi
+
+Exit $fail
diff --git a/tests/cksum/md5sum-newline.pl b/tests/cksum/md5sum-newline.pl
new file mode 100755
index 0000000..feaebb4
--- /dev/null
+++ b/tests/cksum/md5sum-newline.pl
@@ -0,0 +1,46 @@
+#!/usr/bin/perl
+# Newline tests for "md5sum".
+
+# Copyright (C) 1999-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+use strict;
+
+(my $ME = $0) =~ s|.*/||;
+
+# Turn off localization of executable's output.
+@ENV{qw(LANGUAGE LANG LC_ALL)} = ('C') x 3;
+
+# See if we can create a file name that contains a newline.
+# Use system, since Perl doesn't let you do this with "open".
+system ('touch', "a\nb") == 0
+ or CuSkip::skip "$ME: failed to create newline-containing file name\n";
+
+my $degenerate = "d41d8cd98f00b204e9800998ecf8427e";
+my $t = '--text';
+my $z = '--zero';
+
+my @Tests =
+ (
+ ['newline', $t, {IN=> {"a\nb"=> ''}}, {OUT=>"\\$degenerate a\\nb\n"}],
+ ['zero', "$t $z", {IN=> {"a\nb"=> ''}}, {OUT=>"$degenerate a\nb\0"}],
+ );
+
+my $save_temps = $ENV{DEBUG};
+my $verbose = $ENV{VERBOSE};
+
+my $prog = 'md5sum';
+my $fail = run_tests ($ME, $prog, \@Tests, $save_temps, $verbose);
+exit $fail;
diff --git a/tests/cksum/md5sum-parallel.sh b/tests/cksum/md5sum-parallel.sh
new file mode 100755
index 0000000..99da9ad
--- /dev/null
+++ b/tests/cksum/md5sum-parallel.sh
@@ -0,0 +1,36 @@
+#!/bin/sh
+# Ensure that md5sum prints each checksum atomically
+# so that concurrent md5sums don't intersperse their output
+
+# Copyright (C) 2009-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ md5sum
+
+xargs -P2 </dev/null >/dev/null 2>&1 \
+ || skip_ 'xargs -P is required'
+
+(mkdir tmp && cd tmp && seq 500 | xargs touch)
+
+# This will output at least 16KiB per process
+# and start 3 processes, with 2 running concurrently,
+# which triggers often on Fedora 11 at least.
+(find tmp tmp tmp -type f | xargs -n500 -P2 md5sum 2>err) |
+sed -n '/[0-9a-f]\{32\} /!p' |
+grep . > /dev/null && fail=1
+compare /dev/null err || fail=1
+
+Exit $fail
diff --git a/tests/cksum/md5sum.pl b/tests/cksum/md5sum.pl
new file mode 100755
index 0000000..d712664
--- /dev/null
+++ b/tests/cksum/md5sum.pl
@@ -0,0 +1,194 @@
+#!/usr/bin/perl
+# Basic tests for "md5sum".
+
+# Copyright (C) 1998-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+use strict;
+
+my $prog = 'md5sum';
+
+# Turn off localization of executable's output.
+@ENV{qw(LANGUAGE LANG LC_ALL)} = ('C') x 3;
+
+my $degenerate = "d41d8cd98f00b204e9800998ecf8427e";
+
+my $try_help = "Try 'md5sum --help' for more information.\n";
+
+my @Tests =
+ (
+ ['1', {IN=> {f=> ''}}, {OUT=>"$degenerate f\n"}],
+ ['2', {IN=> {f=> 'a'}}, {OUT=>"0cc175b9c0f1b6a831c399e269772661 f\n"}],
+ ['3', {IN=> {f=> 'abc'}}, {OUT=>"900150983cd24fb0d6963f7d28e17f72 f\n"}],
+ ['4', {IN=> {f=> 'message digest'}},
+ {OUT=>"f96b697d7cb7938d525a2f31aaf161d0 f\n"}],
+ ['5', {IN=> {f=> 'abcdefghijklmnopqrstuvwxyz'}},
+ {OUT=>"c3fcd3d76192e4007dfb496cca67e13b f\n"}],
+ ['6', {IN=> {f=> join ('', 'A'..'Z', 'a'..'z', '0'..'9')}},
+ {OUT=>"d174ab98d277d9f5a5611c2c9f419d9f f\n"}],
+ ['7', {IN=> {f=> '1234567890' x 8}},
+ {OUT=>"57edf4a22be3c955ac49da2e2107b67a f\n"}],
+ ['backslash-1', {IN=> {".\nfoo"=> ''}},
+ {OUT=>"\\$degenerate .\\nfoo\n"}],
+ ['backslash-2', {IN=> {".\\foo"=> ''}},
+ {OUT=>"\\$degenerate .\\\\foo\n"}],
+ ['backslash-3', {IN=> {".\rfoo"=> ''}},
+ {OUT=>"\\$degenerate .\\rfoo\n"}],
+ ['check-1', '--check', {AUX=> {f=> ''}},
+ {IN=> {'f.md5' => "$degenerate f\n"}},
+ {OUT=>"f: OK\n"}],
+ ['check-windows', '--check', {AUX=> {f=> ''}},
+ {IN=> {'f.md5' => "$degenerate f\r\n"}},
+ {OUT=>"f: OK\n"}],
+
+ # Same as above, but with an added empty line, to test --strict.
+ ['ck-strict-1', '--check --strict', {AUX=> {f=> ''}},
+ {IN=> {'f.md5' => "$degenerate f\n\n"}},
+ {OUT=>"f: OK\n"}],
+
+ # As above, but with the invalid line first, to ensure that following
+ # lines are processed in spite of the preceding invalid input line.
+ ['ck-strict-2', '--check --strict', {AUX=> {f=> ''}},
+ {IN=> {'in.md5' => "ERR\n$degenerate f\n"}},
+ {OUT=>"f: OK\n"},
+ {ERR=>"md5sum: "
+ . "WARNING: 1 line is improperly formatted\n"},
+ {EXIT=> 1}],
+ ['check-2', '--check', '--status', {IN=>{'f.md5' => "$degenerate f\n"}},
+ {AUX=> {f=> 'foo'}}, {EXIT=> 1}],
+ ['check-quiet1', '--check', '--quiet', {AUX=> {f=> ''}},
+ {IN=> {'f.md5' => "$degenerate f\n"}},
+ {OUT=>""}],
+ ['check-quiet2', '--check', '--quiet',
+ {IN=>{'f.md5' => "$degenerate f\n"}},
+ {AUX=> {f=> 'foo'}}, {OUT=>"f: FAILED\n"},
+ {ERR=>"md5sum: WARNING: 1 computed"
+ . " checksum did NOT match\n"},
+ {EXIT=> 1}],
+ # Exercise new-after-8.6, easier-to-translate diagnostics.
+ ['check-multifail', '--check',
+ {IN=>{'f.md5' =>
+ "$degenerate f\n"
+ . "$degenerate f\n"
+ . "invalid\n" }},
+ {AUX=> {f=> 'foo'}},
+ {OUT=>"f: FAILED\nf: FAILED\n"},
+ {ERR=>"md5sum: WARNING: 1 line is improperly formatted\n"
+ . "md5sum: WARNING: 2 computed checksums did NOT match\n"},
+ {EXIT=> 1}],
+ # Similar to the above, but use --warn to evoke one more diagnostic.
+ ['check-multifail-warn', '--check', '--warn',
+ {IN=>{'f.md5' =>
+ "$degenerate f\n"
+ . "$degenerate f\n"
+ . "invalid\n" }},
+ {AUX=> {f=> 'foo'}},
+ {OUT=>"f: FAILED\nf: FAILED\n"},
+ {ERR=>"md5sum: f.md5: 3: "
+ . "improperly formatted MD5 checksum line\n"
+ . "md5sum: WARNING: 1 line is improperly formatted\n"
+ . "md5sum: WARNING: 2 computed checksums did NOT match\n"},
+ {EXIT=> 1}],
+ # Ensure we use appropriate state to track failures (broken in 9.2)
+ ['check-multifail-state', '--check', '--warn',
+ {IN=>{'f.md5' =>
+ "$degenerate f\n"
+ . "$degenerate g\n"
+ . "$degenerate f\n" }},
+ {AUX=> {f=> ''}}, {AUX=> {g=> 'a'}},
+ {OUT=>"f: OK\ng: FAILED\nf: OK\n"},
+ {ERR=>"md5sum: WARNING: 1 computed checksum did NOT match\n"},
+ {EXIT=> 1}],
+ # The sha1sum and md5sum drivers share a lot of code.
+ # Ensure that md5sum does *not* share the part that makes
+ # sha1sum accept BSD format.
+ ['check-bsd', '--check', {IN=> {'f.sha1' => "SHA1 (f) = $degenerate\n"}},
+ {AUX=> {f=> ''}},
+ {ERR=>"md5sum: f.sha1: no properly formatted "
+ . "checksum lines found\n"},
+ {EXIT=> 1}],
+ ['check-bsd2', '--check', {IN=> {'f.md5' => "MD5 (f) = $degenerate\n"}},
+ {AUX=> {f=> ''}}, {OUT=>"f: OK\n"}],
+ ['check-bsd3', '--check', '--status',
+ {IN=> {'f.md5' => "MD5 (f) = $degenerate\n"}},
+ {AUX=> {f=> 'bar'}}, {EXIT=> 1}],
+ ['check-openssl', '--check', {IN=> {'f.sha1' => "SHA1(f)= $degenerate\n"}},
+ {AUX=> {f=> ''}},
+ {ERR=>"md5sum: f.sha1: no properly formatted "
+ . "checksum lines found\n"},
+ {EXIT=> 1}],
+ ['check-openssl2', '--check', {IN=> {'f.md5' => "MD5(f)= $degenerate\n"}},
+ {AUX=> {f=> ''}}, {OUT=>"f: OK\n"}],
+ ['check-openssl3', '--check', '--status',
+ {IN=> {'f.md5' => "MD5(f)= $degenerate\n"}},
+ {AUX=> {f=> 'bar'}}, {EXIT=> 1}],
+ ['check-ignore-missing-1', '--check', '--ignore-missing',
+ {AUX=> {f=> ''}},
+ {IN=> {'f.md5' => "$degenerate f\n".
+ "$degenerate f.missing\n"}},
+ {OUT=>"f: OK\n"}],
+ ['check-ignore-missing-2', '--check', '--ignore-missing',
+ {AUX=> {f=> ''}},
+ {IN=> {'f.md5' => "$degenerate f\n".
+ "$degenerate f.missing\n"}},
+ {OUT=>"f: OK\n"}],
+ ['check-ignore-missing-3', '--check', '--quiet', '--ignore-missing',
+ {AUX=> {f=> ''}},
+ {IN=> {'f.md5' => "$degenerate missing/f\n".
+ "$degenerate f\n"}},
+ {OUT=>""}],
+ ['check-ignore-missing-4', '--ignore-missing',
+ {IN=> {f=> ''}},
+ {ERR=>"md5sum: the --ignore-missing option is ".
+ "meaningful only when verifying checksums\n".
+ $try_help},
+ {EXIT=> 1}],
+ ['check-ignore-missing-5', '--check', '--ignore-missing',
+ {AUX=> {f=> ''}},
+ {IN=> {'f.md5' => "$degenerate missing\n"}},
+ {ERR=>
+ "md5sum: f.md5: no file was verified\n"},
+ {EXIT=> 1}],
+ # coreutils-8.25 with --ignore-missing treated checksums starting with 00
+ # as if the file was not present
+ ['check-ignore-missing-6', '--check', '--ignore-missing',
+ {AUX=> {f=> '9t'}},
+ {IN=> {'f.md5' =>
+ "006999e6df389641adf1fa3a74801d9d f\n"}},
+ {OUT=>"f: OK\n"}],
+ ['bsd-segv', '--check', {IN=> {'z' => "MD5 ("}}, {EXIT=> 1},
+ {ERR=> "$prog: z: no properly formatted checksum lines found\n"}],
+
+ # Ensure that when there's a NUL byte among the checksum hex digits
+ # we detect the invalid formatting and don't even open the file.
+ # Up to coreutils-6.10, this would report:
+ # h: FAILED
+ # md5sum: WARNING: 1 of 1 computed checksum did NOT match
+ ['nul-in-cksum', '--check', {IN=> {'h'=>("\0"x32)." h\n"}}, {EXIT=> 1},
+ {ERR=> "$prog: h: no properly formatted checksum lines found\n"}],
+ );
+
+# Insert the '--text' argument for each test.
+my $t;
+foreach $t (@Tests)
+ {
+ splice @$t, 1, 0, '--text' unless @$t[1] =~ /--check/;
+ }
+
+my $save_temps = $ENV{DEBUG};
+my $verbose = $ENV{VERBOSE};
+
+my $fail = run_tests ($prog, $prog, \@Tests, $save_temps, $verbose);
+exit $fail;
diff --git a/tests/cksum/sha1sum-vec.pl b/tests/cksum/sha1sum-vec.pl
new file mode 100755
index 0000000..7fed5fe
--- /dev/null
+++ b/tests/cksum/sha1sum-vec.pl
@@ -0,0 +1,534 @@
+#!/usr/bin/perl
+# Sample vectors for "sha1sum".
+
+# Copyright (C) 2000-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+use strict;
+
+(my $program_name = $0) =~ s|.*/||;
+
+# Turn off localization of executable's output.
+@ENV{qw(LANGUAGE LANG LC_ALL)} = ('C') x 3;
+
+# The data from which these tests were derived came from here:
+# https://web.archive.org/web/20060505234703/http://csrc.nist.gov/cryptval/shs/sha1-vectors.zip
+
+my @Tests =
+ (
+ ['1', {IN=> {f=> '0 1 ^'}},
+ {OUT=>'DA39A3EE5E6B4B0D3255BFEF95601890AFD80709'}],
+ ['2', {IN=> {f=> '5 0 2 1 2 1 2 ^'}},
+ {OUT=>'3CDF2936DA2FC556BFA533AB1EB59CE710AC80E5'}],
+ ['3', {IN=> {f=> '5 0 1 3 4 4 4 ^'}},
+ {OUT=>'19C1E2048FA7393CFBF2D310AD8209EC11D996E5'}],
+ ['4', {IN=> {f=> '7 0 4 3 4 4 1 4 4 ^'}},
+ {OUT=>'CA775D8C80FAA6F87FA62BECA6CA6089D63B56E5'}],
+ ['5', {IN=> {f=> '10 0 4 1 5 3 4 4 3 1 3 4 ^'}},
+ {OUT=>'71AC973D0E4B50AE9E5043FF4D615381120A25A0'}],
+ ['6', {IN=> {f=> '10 0 3 1 6 5 5 1 3 6 6 4 ^'}},
+ {OUT=>'A6B5B9F854CFB76701C3BDDBF374B3094EA49CBA'}],
+ ['7', {IN=> {f=> '13 1 3 2 5 3 3 3 4 6 6 1 4 6 2 ^'}},
+ {OUT=>'D87A0EE74E4B9AD72E6847C87BDEEB3D07844380'}],
+ ['8', {IN=> {f=> '16 1 3 5 5 1 2 1 3 3 6 3 5 2 3 5 7 2 ^'}},
+ {OUT=>'1976B8DD509FE66BF09C9A8D33534D4EF4F63BFD'}],
+ ['9', {IN=> {f=> '15 1 8 1 5 3 2 7 4 5 6 7 3 3 1 6 3 ^'}},
+ {OUT=>'5A78F439B6DB845BB8A558E4CEB106CD7B7FF783'}],
+ ['10', {IN=> {f=> '15 1 4 6 8 2 1 4 2 5 1 6 8 8 6 4 7 ^'}},
+ {OUT=>'F871BCE62436C1E280357416695EE2EF9B83695C'}],
+ ['11', {IN=> {f=> '18 1 1 2 7 3 8 6 7 5 4 3 4 3 5 3 3 2 6 8 ^'}},
+ {OUT=>'62B243D1B780E1D31CF1BA2DE3F01C72AEEA0E47'}],
+ ['12', {IN=> {f=> '16 0 9 8 1 8 1 7 6 7 7 1 2 6 9 5 4 7 ^'}},
+ {OUT=>'1698994A273404848E56E7FDA4457B5900DE1342'}],
+ ['13', {IN=> {f=> '18 0 7 1 7 3 9 4 7 7 5 2 8 1 7 8 2 7 2 9 ^'}},
+ {OUT=>'056F4CDC02791DA7ED1EB2303314F7667518DEEF'}],
+ ['14', {IN=> {f=> '19 1 2 3 1 8 8 6 9 10 3 10 8 9 2 4 1 5 1 5 9 ^'}},
+ {OUT=>'9FE2DA967BD8441EEA1C32DF68DDAA9DC1FC8E4B'}],
+ ['15', {IN=> {f=> '19 1 8 5 4 8 1 3 9 5 7 7 2 7 2 7 8 7 4 8 10 ^'}},
+ {OUT=>'73A31777B4ACE9384EFA8BBEAD45C51A71ABA6DD'}],
+ ['16', {IN=> {f=> '20 1 1 9 7 4 1 4 5 1 10 8 6 4 4 9 9 9 8 2 9 10 ^'}},
+ {OUT=>'3F9D7C4E2384EDDABFF5DD8A31E23DE3D03F42AC'}],
+ ['17', {IN=> {f=> '19 1 11 6 7 7 2 6 2 6 10 6 9 10 5 11 1 6 8 11 4 ^'}},
+ {OUT=>'4814908F72B93FFD011135BEE347DE9A08DA838F'}],
+ ['18', {IN=> {f=> '22 0 10 5 10 3 7 8 9 9 1 1 1 10 2 1 5 10 2 9 9 9 7 8 ^'}},
+ {OUT=>'0978374B67A412A3102C5AA0B10E1A6596FC68EB'}],
+ ['19', {IN=> {f=> '21 0 1 10 1 6 9 4 2 5 2 11 8 12 12 9 8 1 3 10 7 11 12 ^'}},
+ {OUT=>'44AD6CB618BD935460D46D3F921D87B99AB91C1E'}],
+ ['20', {IN=> {f=> '24 1 3 9 5 12 3 4 2 9 12 11 6 6 1 1 9 5 9 1 4 9 4 10 8 9 ^'}},
+ {OUT=>'02DC989AF265B09CF8485640842128DCF95E9F39'}],
+ ['21', {IN=> {f=> '25 1 3 2 3 11 1 12 5 6 2 7 8 4 8 8 9 9 8 4 9 1 4 8 10 9 9 ^'}},
+ {OUT=>'67507B8D497B35D6E99FC01976D73F54AECA75CF'}],
+ ['22', {IN=> {f=> '23 0 11 10 7 10 10 6 10 9 4 5 10 5 8 4 1 10 12 4 6 1 8 11 6 ^'}},
+ {OUT=>'1EAE0373C1317CB60C36A42A867B716039D441F5'}],
+ ['23', {IN=> {f=> '22 0 12 8 10 4 3 8 5 5 7 11 13 11 12 11 4 12 3 6 5 11 10 5 ^'}},
+ {OUT=>'9C3834589E5BFFAC9F50950E0199B3EC2620BEC8'}],
+ ['24', {IN=> {f=> '26 1 10 9 6 9 7 2 10 4 4 5 5 2 12 13 5 3 1 10 1 4 7 8 13 13 12 9 ^'}},
+ {OUT=>'209F7ABC7F3B878EE46CDF3A1FBB9C21C3474F32'}],
+ ['25', {IN=> {f=> '31 0 2 6 5 4 7 3 10 6 13 6 3 9 6 2 10 5 3 8 4 1 11 3 5 3 7 11 1 12 9 12 5 ^'}},
+ {OUT=>'05FC054B00D97753A9B3E2DA8FBBA3EE808CEF22'}],
+ ['26', {IN=> {f=> '27 1 14 5 1 3 7 2 3 9 3 4 14 4 4 10 8 5 14 1 11 12 12 10 4 13 7 11 9 ^'}},
+ {OUT=>'0C4980EA3A46C757DFBFC5BAA38AC6C8E72DDCE7'}],
+ ['27', {IN=> {f=> '30 1 4 9 5 5 8 9 5 10 4 2 4 7 9 9 6 3 5 1 8 3 2 13 3 14 9 8 9 10 14 10 ^'}},
+ {OUT=>'96A460D2972D276928B69864445BEA353BDCFFD2'}],
+ ['28', {IN=> {f=> '27 0 12 9 5 8 7 2 14 12 3 8 14 6 6 4 7 5 7 10 7 11 10 1 9 6 7 12 14 ^'}},
+ {OUT=>'F3EF04D8FA8C6FA9850F394A4554C080956FA64B'}],
+ ['29', {IN=> {f=> '24 0 12 9 9 2 11 13 12 11 11 6 14 13 10 5 6 8 10 4 3 11 11 14 5 14 ^'}},
+ {OUT=>'F2A31D875D1D7B30874D416C4D2EA6BAF0FFBAFE'}],
+ ['30', {IN=> {f=> '24 0 15 4 5 3 8 12 15 8 14 15 9 12 12 3 10 13 6 11 10 4 13 14 8 8 ^'}},
+ {OUT=>'F4942D3B9E9588DCFDC6312A84DF75D05F111C20'}],
+ ['31', {IN=> {f=> '28 1 1 8 1 5 11 4 9 12 4 13 15 5 9 11 7 14 11 1 11 7 8 8 11 1 13 15 12 13 ^'}},
+ {OUT=>'310207DF35B014E4676D30806FA34424813734DD'}],
+ ['32', {IN=> {f=> '32 1 5 8 3 8 10 7 8 1 5 13 12 14 5 3 6 4 12 15 6 6 10 11 13 9 1 11 6 10 3 7 14 2 ^'}},
+ {OUT=>'4DA1955B2FA7C7E74E3F47D7360CE530BBF57CA3'}],
+ ['33', {IN=> {f=> '31 0 10 3 5 1 14 11 11 16 1 2 2 11 6 13 15 12 6 5 16 2 14 2 10 12 2 5 5 6 10 13 15 ^'}},
+ {OUT=>'74C4BC5B26FB4A08602D40CCEC6C6161B6C11478'}],
+ ['34', {IN=> {f=> '34 0 3 10 8 16 9 5 12 15 4 11 13 3 6 5 10 8 1 3 9 3 11 1 2 16 12 10 6 1 9 1 16 5 6 14 ^'}},
+ {OUT=>'0B103CE297338DFC7395F7715EE47539B556DDB6'}],
+ ['35', {IN=> {f=> '30 1 1 12 4 4 2 15 13 15 11 15 5 11 9 7 15 16 6 16 12 3 2 10 16 5 5 7 1 7 11 16 ^'}},
+ {OUT=>'EFC72D99E3D2311CE14190C0B726BDC68F4B0821'}],
+ ['36', {IN=> {f=> '34 0 7 9 11 2 5 5 5 4 13 13 14 4 7 12 6 4 8 2 9 9 13 13 3 3 6 7 16 7 6 15 5 8 15 14 ^'}},
+ {OUT=>'660EDAC0A8F4CE33DA0D8DBAE597650E97687250'}],
+ ['37', {IN=> {f=> '36 1 4 6 16 15 11 14 14 4 7 10 3 4 10 3 6 7 14 4 6 6 5 2 7 8 16 2 12 16 10 14 3 2 3 7 14 3 ^'}},
+ {OUT=>'FE0A55A988B3B93946A63EB36B23785A5E6EFC3E'}],
+ ['38', {IN=> {f=> '32 0 15 10 9 1 14 10 14 6 6 16 3 2 3 8 3 12 8 11 17 3 9 7 16 14 4 11 15 5 13 9 5 17 ^'}},
+ {OUT=>'0CBDF2A5781C59F907513147A0DE3CC774B54BF3'}],
+ ['39', {IN=> {f=> '30 0 17 17 13 8 2 6 8 16 1 12 5 17 2 9 8 10 13 14 11 17 12 5 14 9 11 9 11 4 11 12 ^'}},
+ {OUT=>'663E40FEE5A44BFCB1C99EA5935A6B5BC9F583B0'}],
+ ['40', {IN=> {f=> '30 1 16 6 10 5 8 3 17 16 14 1 15 15 15 6 13 2 11 6 13 11 13 4 6 7 11 11 12 16 13 16 ^'}},
+ {OUT=>'00162134256952DD9AE6B51EFB159B35C3C138C7'}],
+ ['41', {IN=> {f=> '33 1 16 16 14 16 2 4 16 11 6 15 7 4 17 6 5 7 6 3 14 16 5 17 11 13 1 1 14 13 3 6 14 5 16 ^'}},
+ {OUT=>'CEB88E4736E354416E2010FC1061B3B53B81664B'}],
+ ['42', {IN=> {f=> '39 1 2 16 13 7 8 6 2 15 1 9 12 4 4 11 13 7 2 11 9 18 4 5 4 8 2 14 9 9 1 8 13 11 15 8 5 9 10 16 7 ^'}},
+ {OUT=>'A6A2C4B6BCC41DDC67278F3DF4D8D0B9DD7784EF'}],
+ ['43', {IN=> {f=> '34 0 2 7 1 1 17 13 6 11 10 8 5 12 15 6 15 10 12 4 18 1 2 8 11 12 16 10 12 18 11 16 12 11 17 6 ^'}},
+ {OUT=>'C23D083CD8820B57800A869F5F261D45E02DC55D'}],
+ ['44', {IN=> {f=> '34 1 4 7 13 7 10 7 10 6 1 12 7 18 11 18 2 10 15 10 14 8 18 9 9 12 12 3 13 12 6 4 9 17 13 17 ^'}},
+ {OUT=>'E8AC31927B78DDEC41A31CA7A44EB7177165E7AB'}],
+ ['45', {IN=> {f=> '40 0 5 7 3 2 1 17 14 4 16 6 13 1 13 6 6 10 1 3 18 3 11 7 9 5 7 11 17 1 9 16 5 15 10 17 3 8 15 17 8 12 ^'}},
+ {OUT=>'E864EC5DBAB0F9FF6984AB6AD43A8C9B81CC9F9C'}],
+ ['46', {IN=> {f=> '40 0 11 3 15 17 11 1 1 4 3 14 18 4 2 18 8 15 6 4 6 3 15 11 16 10 17 17 9 6 3 2 6 16 4 9 12 6 8 1 11 17 ^'}},
+ {OUT=>'CFED6269069417A84D6DE2347220F4B858BCD530'}],
+ ['47', {IN=> {f=> '37 1 2 19 12 8 16 14 2 9 16 2 6 6 7 9 10 9 11 9 14 11 15 5 16 9 2 17 2 8 15 8 4 3 14 14 16 16 12 ^'}},
+ {OUT=>'D9217BFB46C96348722C3783D29D4B1A3FEDA38C'}],
+ ['48', {IN=> {f=> '37 1 11 10 16 12 11 7 14 14 14 6 10 10 1 6 13 19 5 6 4 7 12 12 10 5 10 15 15 8 5 13 17 13 5 6 14 1 19 ^'}},
+ {OUT=>'DEC24E5554F79697218D317315FA986229CE3350'}],
+ ['49', {IN=> {f=> '38 1 2 6 5 17 9 11 18 18 8 6 13 15 3 3 15 5 13 18 3 2 5 5 14 7 13 4 17 7 2 17 3 18 15 7 15 16 18 11 ^'}},
+ {OUT=>'83A099DF7071437BA5495A5B0BFBFEFE1C0EF7F3'}],
+ ['50', {IN=> {f=> '38 1 12 8 6 3 17 12 13 19 15 9 7 17 16 15 3 11 11 5 2 13 19 16 2 4 16 7 8 1 2 9 17 12 3 5 18 19 11 9 ^'}},
+ {OUT=>'AA3198E30891A83E33CE3BFA0587D86A197D4F80'}],
+ ['51', {IN=> {f=> '39 1 14 16 14 8 9 16 5 1 6 3 17 18 16 9 1 15 9 10 9 19 1 3 3 20 11 13 17 1 19 8 3 4 3 7 1 14 19 19 19 ^'}},
+ {OUT=>'9B6ACBEB4989CBEE7015C7D515A75672FFDE3442'}],
+ ['52', {IN=> {f=> '37 1 18 13 11 5 18 4 19 10 6 19 11 17 10 10 7 9 13 16 9 10 18 4 12 5 16 5 20 12 3 8 10 1 18 1 6 20 14 ^'}},
+ {OUT=>'B021EB08A436B02658EAA7BA3C88D49F1219C035'}],
+ ['53', {IN=> {f=> '36 0 8 9 6 12 11 7 7 3 17 13 6 20 17 9 20 16 10 12 17 8 11 8 11 10 5 10 14 18 8 19 9 12 12 2 20 19 ^'}},
+ {OUT=>'CAE36DAB8AEA29F62E0855D9CB3CD8E7D39094B1'}],
+ ['54', {IN=> {f=> '39 0 12 16 20 3 9 9 19 17 13 13 4 17 2 11 7 14 3 6 16 13 10 13 5 16 10 2 8 2 17 19 4 17 7 19 6 9 15 15 6 ^'}},
+ {OUT=>'02DE8BA699F3C1B0CB5AD89A01F2346E630459D7'}],
+ ['55', {IN=> {f=> '43 0 7 2 18 5 7 18 5 2 15 7 11 10 9 3 2 14 19 3 11 8 18 15 5 3 5 12 15 16 10 17 7 19 16 2 1 16 6 3 19 12 5 18 16 ^'}},
+ {OUT=>'88021458847DD39B4495368F7254941859FAD44B'}],
+ ['56', {IN=> {f=> '49 1 9 11 2 1 12 11 14 12 14 10 4 11 6 8 16 7 5 11 20 8 17 4 14 4 15 3 2 2 4 3 2 3 14 15 10 2 12 7 3 7 20 20 19 10 2 3 1 10 20 ^'}},
+ {OUT=>'91A165295C666FE85C2ADBC5A10329DAF0CB81A0'}],
+ ['57', {IN=> {f=> '36 0 19 20 12 5 19 21 5 21 11 14 19 1 17 8 9 4 19 3 17 1 14 21 14 7 6 5 20 14 21 20 4 6 21 7 11 12 ^'}},
+ {OUT=>'4B31312EAF8B506811151A9DBD162961F7548C4B'}],
+ ['58', {IN=> {f=> '41 0 12 9 11 6 16 18 18 10 11 20 6 12 11 5 7 21 19 18 6 15 21 10 4 14 9 19 10 3 3 5 13 1 8 12 3 13 9 7 10 17 14 ^'}},
+ {OUT=>'3FE70971B20558F7E9BAC303ED2BC14BDE659A62'}],
+ ['59', {IN=> {f=> '45 0 10 6 8 3 17 18 3 21 19 6 17 15 4 9 15 9 15 14 4 7 14 8 10 13 4 11 10 7 6 21 1 14 5 11 7 7 2 13 13 3 9 13 8 14 20 ^'}},
+ {OUT=>'93FB769D5BF49D6C563685954E2AECC024DC02D6'}],
+ ['60', {IN=> {f=> '39 1 3 7 18 4 9 9 5 15 13 17 10 15 16 20 8 19 9 10 9 1 19 14 21 2 18 13 10 4 18 16 4 21 15 10 18 19 3 12 18 ^'}},
+ {OUT=>'BC8827C3E614D515E83DEA503989DEA4FDA6EA13'}],
+ ['61', {IN=> {f=> '41 0 14 4 13 11 1 11 1 10 2 12 4 21 10 21 18 9 2 16 7 20 6 7 12 19 20 1 13 12 10 8 21 15 7 19 13 6 8 19 20 18 19 ^'}},
+ {OUT=>'E83868DBE4A389AB48E61CFC4ED894F32AE112AC'}],
+ ['62', {IN=> {f=> '37 0 11 18 1 17 14 15 20 16 20 8 2 17 10 4 21 5 19 19 14 22 21 18 13 14 1 3 12 11 11 4 22 13 5 18 7 21 21 ^'}},
+ {OUT=>'55C95459CDE4B33791B4B2BCAAF840930AF3F3BD'}],
+ ['63', {IN=> {f=> '48 0 9 22 19 12 8 16 5 17 5 9 1 2 9 6 12 6 1 7 4 3 15 1 14 1 12 3 10 2 10 14 21 13 17 6 6 17 1 21 2 14 16 17 9 11 20 21 11 18 ^'}},
+ {OUT=>'36BB0E2BA438A3E03214D9ED2B28A4D5C578FCAA'}],
+ ['64', {IN=> {f=> '50 1 12 8 20 13 2 9 20 9 14 10 1 16 2 22 6 4 16 14 15 1 12 4 14 9 21 3 3 9 8 21 15 14 8 4 14 4 2 3 8 12 8 6 1 2 18 20 15 3 19 10 ^'}},
+ {OUT=>'3ACBF874199763EBA20F3789DFC59572ACA4CF33'}],
+ ['65', {IN=> {f=> '44 0 10 20 14 6 3 4 21 1 12 4 18 2 6 7 6 9 20 14 10 10 19 17 21 12 15 17 7 10 11 8 10 12 1 19 19 9 18 21 4 18 11 9 22 5 ^'}},
+ {OUT=>'86BE037C4D509C9202020767D860DAB039CADACE'}],
+ ['66', {IN=> {f=> '47 0 15 8 15 3 5 6 2 19 12 17 4 20 8 11 20 2 18 4 16 20 12 9 9 6 16 21 16 3 16 18 3 19 5 16 2 4 2 12 11 15 11 14 17 2 10 18 8 ^'}},
+ {OUT=>'51B57D7080A87394EEC3EB2E0B242E553F2827C9'}],
+ ['67', {IN=> {f=> '48 1 5 13 3 21 5 3 6 18 18 10 1 21 21 7 1 13 12 19 1 14 6 8 21 19 21 11 19 13 2 13 4 1 10 22 16 4 9 4 10 16 3 7 15 11 9 13 17 12 ^'}},
+ {OUT=>'1EFBFA78866315CE6A71E457F3A750A38FACAB41'}],
+ ['68', {IN=> {f=> '45 0 14 7 6 2 20 3 6 19 19 10 2 22 12 17 12 1 20 7 7 15 20 6 18 8 3 14 23 18 15 4 7 5 23 15 7 14 10 10 19 17 2 4 15 17 21 ^'}},
+ {OUT=>'57D6CB41AEEC20236F365B3A490C61D0CFA39611'}],
+ ['69', {IN=> {f=> '45 1 15 11 8 9 17 5 12 18 14 6 20 17 21 12 16 9 22 9 20 15 2 22 11 2 6 11 9 8 2 4 14 19 3 21 21 23 8 2 11 4 8 4 20 22 11 ^'}},
+ {OUT=>'C532CB64B4BA826372BCCF2B4B5793D5B88BB715'}],
+ ['70', {IN=> {f=> '38 0 21 18 22 10 19 9 14 17 23 21 10 7 15 13 16 5 4 10 13 14 20 23 12 20 23 18 10 12 8 21 11 6 12 7 19 14 18 17 ^'}},
+ {OUT=>'15833B5631032663E783686A209C6A2B47A1080E'}],
+ ['71', {IN=> {f=> '40 0 18 22 6 9 22 5 23 13 6 8 23 20 22 5 22 15 19 20 9 9 1 13 13 10 14 13 5 22 14 21 9 21 19 14 14 4 18 13 12 14 ^'}},
+ {OUT=>'D04F2043C96E10CD83B574B1E1C217052CD4A6B2'}],
+ ['72', {IN=> {f=> '48 1 7 3 15 5 17 14 23 14 5 17 22 11 1 8 13 23 6 21 3 6 11 7 23 8 6 21 4 4 22 19 13 8 5 19 7 5 23 1 4 19 11 23 11 21 14 1 3 21 ^'}},
+ {OUT=>'E8882627C64DB743F7DB8B4413DD033FC63BEB20'}],
+ ['73', {IN=> {f=> '43 0 22 14 11 7 18 16 17 24 12 12 3 13 19 16 22 4 16 4 6 23 8 18 11 2 3 20 22 9 21 8 23 1 23 20 7 16 13 23 4 13 3 7 22 ^'}},
+ {OUT=>'CD2D32286B8867BC124A0AF2236FC74BE3622199'}],
+ ['74', {IN=> {f=> '47 1 23 6 13 19 2 3 7 2 9 9 15 6 13 4 22 6 19 20 1 9 7 14 1 15 3 23 24 22 18 12 12 17 19 10 8 11 22 12 10 2 20 15 18 17 18 7 19 ^'}},
+ {OUT=>'019B70D745375091ED5C7B218445EC986D0F5A82'}],
+ ['75', {IN=> {f=> '47 1 12 21 6 12 4 7 18 17 3 2 14 24 14 1 23 1 11 15 10 6 18 20 7 1 8 1 16 6 20 23 23 21 10 10 12 24 10 11 23 2 12 23 9 3 24 24 10 ^'}},
+ {OUT=>'E5FF5FEC1DADBAED02BF2DAD4026BE6A96B3F2AF'}],
+ ['76', {IN=> {f=> '52 0 14 10 18 15 14 5 16 11 22 2 15 24 8 22 1 4 24 9 10 15 3 9 5 4 17 15 9 12 19 19 1 3 10 6 8 3 17 8 18 24 19 3 4 15 4 9 2 24 5 20 13 13 ^'}},
+ {OUT=>'6F4E23B3F2E2C068D13921FE4E5E053FFED4E146'}],
+ ['77', {IN=> {f=> '42 0 20 17 19 22 13 8 10 19 15 11 1 14 17 20 22 10 7 11 16 9 21 22 17 23 12 15 4 24 7 21 18 2 21 16 1 19 18 20 11 3 15 17 ^'}},
+ {OUT=>'25E179602A575C915067566FBA6DA930E97F8678'}],
+ ['78', {IN=> {f=> '50 0 18 1 6 14 5 5 5 19 13 10 24 19 16 24 15 13 2 19 15 24 21 17 4 13 17 1 1 9 1 10 2 18 1 21 19 5 18 12 2 22 16 23 15 19 6 18 9 1 23 5 ^'}},
+ {OUT=>'67DED0E68E235C8A523E051E86108EEB757EFBFD'}],
+ ['79', {IN=> {f=> '51 0 21 13 14 11 18 12 13 3 19 9 20 22 20 2 11 12 6 1 12 16 18 2 9 8 4 3 11 17 11 5 4 19 16 11 23 13 18 1 20 8 2 16 16 21 4 19 5 5 20 24 16 ^'}},
+ {OUT=>'AF78536EA83C822796745556D62A3EE82C7BE098'}],
+ ['80', {IN=> {f=> '53 1 20 25 17 11 8 4 19 25 17 7 16 21 6 4 8 2 15 9 2 9 19 3 6 3 3 10 25 13 15 7 8 20 21 12 10 12 5 24 11 20 3 13 13 16 9 13 10 3 9 16 3 7 25 ^'}},
+ {OUT=>'64D7AC52E47834BE72455F6C64325F9C358B610D'}],
+ ['81', {IN=> {f=> '49 1 9 9 14 2 13 17 25 2 18 5 19 23 9 25 9 10 23 12 12 7 13 8 15 7 1 6 21 2 8 7 6 16 14 14 12 15 13 24 10 15 11 10 8 14 15 21 25 21 25 ^'}},
+ {OUT=>'9D4866BAA3639C13E541F250FFA3D8BC157A491F'}],
+ ['82', {IN=> {f=> '47 0 9 18 20 22 21 20 11 14 23 22 10 13 14 8 19 12 2 11 20 23 13 4 10 6 5 7 23 11 3 16 8 21 4 8 18 5 12 14 8 6 20 19 24 8 23 17 23 ^'}},
+ {OUT=>'2E258811961D3EB876F30E7019241A01F9517BEC'}],
+ ['83', {IN=> {f=> '48 1 7 19 1 18 1 14 22 13 14 5 8 22 18 14 25 17 11 12 22 2 12 12 16 12 13 18 17 12 17 14 18 8 25 9 23 5 3 8 14 24 17 7 3 3 23 17 22 19 ^'}},
+ {OUT=>'8E0EBC487146F83BC9077A1630E0FB3AB3C89E63'}],
+ ['84', {IN=> {f=> '51 1 19 17 16 22 24 14 16 20 23 20 9 19 16 7 12 16 5 8 9 7 10 21 24 10 11 19 1 21 14 14 19 3 22 8 12 20 1 18 5 6 5 12 14 1 1 11 9 22 3 24 4 ^'}},
+ {OUT=>'CE8953741FFF3425D2311FBBF4AB481B669DEF70'}],
+ ['85', {IN=> {f=> '52 1 6 1 11 16 1 12 8 11 11 17 10 22 7 3 10 2 6 4 24 16 24 19 4 5 18 11 12 9 20 21 25 2 21 18 10 20 25 21 3 17 17 5 8 22 25 19 8 10 19 7 11 18 ^'}},
+ {OUT=>'789D1D2DAB52086BD90C0E137E2515ED9C6B59B5'}],
+ ['86', {IN=> {f=> '44 0 26 14 21 25 25 4 9 13 5 8 9 21 8 12 26 24 9 24 15 1 23 22 16 14 8 22 15 19 24 20 7 8 15 24 12 4 4 23 21 13 19 15 21 12 ^'}},
+ {OUT=>'B76CE7472700DD68D6328B7AA8437FB051D15745'}],
+ ['87', {IN=> {f=> '59 1 15 7 3 21 20 8 22 14 23 26 19 2 10 18 3 5 3 1 9 15 15 3 7 13 23 9 7 1 13 17 14 25 9 16 2 2 6 13 7 19 25 17 1 5 21 2 7 22 5 6 25 3 12 19 6 2 4 24 17 ^'}},
+ {OUT=>'F218669B596C5FFB0B1C14BD03C467FC873230A0'}],
+ ['88', {IN=> {f=> '60 0 9 18 20 19 4 11 14 1 6 8 26 6 9 22 4 10 2 7 21 9 8 24 25 14 22 12 22 3 23 3 3 20 6 11 23 6 1 7 5 18 5 15 25 26 1 1 10 11 11 4 12 11 20 3 14 2 3 2 23 15 ^'}},
+ {OUT=>'1FF3BDBE0D504CB0CDFAB17E6C37ABA6B3CFFDED'}],
+ ['89', {IN=> {f=> '49 0 12 17 24 11 8 6 24 16 15 22 21 14 6 12 20 19 5 5 12 11 6 23 2 16 23 7 24 6 21 2 17 17 5 25 11 25 20 25 24 18 6 12 19 25 7 6 5 2 25 ^'}},
+ {OUT=>'2F3CBACBB14405A4652ED52793C1814FD8C4FCE0'}],
+ ['90', {IN=> {f=> '54 1 12 16 1 15 7 1 26 19 19 13 20 11 17 6 20 5 24 24 1 21 11 9 20 21 15 10 19 26 3 2 6 7 12 9 10 8 14 10 15 5 17 8 21 1 20 25 6 19 8 3 22 16 16 20 ^'}},
+ {OUT=>'982C8AB6CE164F481915AF59AAED9FFF2A391752'}],
+ ['91', {IN=> {f=> '63 0 17 13 11 10 17 15 12 6 13 14 17 4 12 10 24 5 13 24 3 5 2 5 11 14 8 5 10 17 16 8 4 14 21 15 3 6 17 25 8 2 3 3 19 10 13 22 22 8 2 13 25 17 2 1 19 1 14 20 2 5 4 15 24 ^'}},
+ {OUT=>'5CD92012D488A07ECE0E47901D0E083B6BD93E3F'}],
+ ['92', {IN=> {f=> '49 0 14 20 7 25 20 26 20 16 7 17 17 22 1 13 6 5 1 18 14 15 23 15 10 5 19 18 18 26 12 13 3 25 12 21 16 24 4 16 3 6 26 26 10 20 13 1 20 24 15 ^'}},
+ {OUT=>'69603FEC02920851D4B3B8782E07B92BB2963009'}],
+ ['93', {IN=> {f=> '56 0 3 8 14 5 5 7 11 13 11 26 11 4 26 17 20 19 11 10 3 10 14 9 6 9 7 16 10 4 4 19 19 2 26 13 19 17 15 24 15 4 21 22 13 13 12 22 2 14 20 5 18 7 17 24 20 20 ^'}},
+ {OUT=>'3E90F76437B1EA44CF98A08D83EA24CECF6E6191'}],
+ ['94', {IN=> {f=> '58 1 6 17 9 20 2 10 19 3 22 4 1 11 3 5 3 21 11 15 12 23 26 5 2 27 6 5 16 6 3 2 23 5 3 20 20 4 24 2 18 21 7 14 10 27 23 6 24 6 19 23 3 9 22 16 21 17 19 23 ^'}},
+ {OUT=>'34C09F107C42D990EB4881D4BF2DDDCAB01563AE'}],
+ ['95', {IN=> {f=> '58 1 17 7 21 19 6 16 15 15 20 14 2 25 19 14 18 19 7 9 1 14 11 10 16 3 23 14 26 10 11 1 18 1 12 24 19 19 1 7 2 3 24 7 12 9 2 8 16 20 24 5 26 26 4 9 2 7 25 17 ^'}},
+ {OUT=>'474BE0E5892EB2382109BFC5E3C8249A9283B03D'}],
+ ['96', {IN=> {f=> '54 1 8 12 18 14 26 7 17 18 4 20 1 16 14 21 26 4 6 8 24 11 25 15 24 16 23 4 10 23 21 24 15 10 9 26 7 14 24 21 6 20 5 17 16 17 1 3 12 1 4 13 3 9 21 26 ^'}},
+ {OUT=>'A04B4F75051786682483252438F6A75BF4705EC6'}],
+ ['97', {IN=> {f=> '56 1 7 18 11 1 19 20 23 12 12 27 13 13 15 16 13 1 16 15 12 26 3 16 16 8 17 13 21 4 6 5 19 14 16 4 16 11 14 18 18 27 9 13 21 3 26 22 3 7 6 4 26 3 15 8 25 21 ^'}},
+ {OUT=>'BE88A6716083EB50ED9416719D6A247661299383'}],
+ ['98', {IN=> {f=> '50 1 20 13 9 11 20 6 11 21 27 25 20 7 4 18 26 16 27 5 12 19 7 23 6 25 25 2 11 13 25 21 18 17 6 12 14 13 24 11 14 19 26 27 25 6 1 15 4 7 27 15 ^'}},
+ {OUT=>'C67E38717FEE1A5F65EC6C7C7C42AFC00CD37F04'}],
+ ['99', {IN=> {f=> '51 0 15 16 26 27 23 14 12 28 22 15 8 19 2 20 13 1 24 2 25 1 6 19 19 8 11 24 24 21 13 27 5 11 28 17 7 25 6 23 24 14 25 12 5 13 26 2 5 8 10 16 17 ^'}},
+ {OUT=>'959AC4082388E19E9BE5DE571C047EF10C174A8D'}],
+ ['100', {IN=> {f=> '58 1 5 26 18 19 21 3 12 11 13 4 14 22 22 14 16 13 3 22 16 23 5 19 6 13 10 26 17 27 26 4 3 25 6 14 2 3 5 7 23 11 22 8 25 2 9 25 18 17 8 2 14 4 19 1 5 27 13 24 ^'}},
+ {OUT=>'BAA7AA7B7753FA0ABDC4A541842B5D238D949F0A'}],
+ ['101', {IN=> {f=> '53 0 2 27 28 2 17 23 10 27 18 26 7 22 16 3 27 1 26 21 28 10 3 6 2 2 10 17 13 16 6 17 21 23 13 20 22 5 6 11 12 12 8 23 13 17 9 23 20 3 28 27 12 17 22 ^'}},
+ {OUT=>'351394DCEBC08155D100FCD488578E6AE71D0E9C'}],
+ ['102', {IN=> {f=> '59 0 28 19 5 21 4 27 8 1 19 14 20 6 7 9 1 6 22 3 19 26 14 8 6 7 19 15 23 1 17 16 6 26 14 5 22 25 4 7 10 16 21 10 18 19 24 16 23 8 3 17 28 18 10 2 5 3 21 21 15 ^'}},
+ {OUT=>'AB8BE94C5AF60D9477EF1252D604E58E27B2A9EE'}],
+ ['103', {IN=> {f=> '58 0 6 24 1 4 24 18 10 22 1 21 12 5 4 4 20 25 24 26 8 25 11 2 7 27 22 19 4 18 27 10 28 4 12 24 8 16 12 11 16 17 25 8 12 16 1 9 9 10 5 24 23 18 5 14 18 8 4 28 ^'}},
+ {OUT=>'3429EC74A695FDD3228F152564952308AFE0680A'}],
+ ['104', {IN=> {f=> '61 0 5 17 8 28 1 22 4 11 3 2 17 3 14 9 27 13 18 24 9 8 7 28 25 14 21 27 24 6 18 16 2 12 15 9 14 10 1 8 17 4 6 15 26 11 15 2 28 20 26 16 3 7 5 8 9 26 10 12 25 11 22 ^'}},
+ {OUT=>'907FA46C029BC67EAA8E4F46E3C2A232F85BD122'}],
+ ['105', {IN=> {f=> '53 0 9 13 24 15 20 2 4 8 2 22 20 19 4 15 14 28 13 25 10 10 12 28 24 22 26 28 15 9 11 26 19 22 27 2 21 8 20 23 26 12 10 21 9 15 13 25 7 26 1 13 5 9 20 ^'}},
+ {OUT=>'2644C87D1FBBBC0FC8D65F64BCA2492DA15BAAE4'}],
+ ['106', {IN=> {f=> '58 0 3 9 21 22 7 1 23 28 1 2 8 22 12 18 28 5 18 14 7 11 17 20 20 7 21 13 8 28 21 22 2 16 20 15 28 9 3 22 13 10 23 4 16 11 14 1 10 8 14 14 15 18 13 12 21 18 25 28 ^'}},
+ {OUT=>'110A3EEB408756E2E81ABAF4C5DCD4D4C6AFCF6D'}],
+ ['107', {IN=> {f=> '60 1 29 20 2 29 22 8 16 20 4 12 9 6 12 16 16 7 9 20 29 11 9 4 1 15 25 16 29 10 22 7 2 8 5 18 14 23 24 4 6 26 3 11 6 12 1 7 14 24 14 6 10 21 16 23 29 25 6 14 17 24 ^'}},
+ {OUT=>'CD4FDC35FAC7E1ADB5DE40F47F256EF74D584959'}],
+ ['108', {IN=> {f=> '64 0 12 10 5 10 15 25 8 15 3 7 13 25 16 14 1 29 22 26 15 27 9 1 8 8 28 6 13 5 13 3 15 5 23 8 23 2 5 5 4 17 13 14 7 17 12 27 3 18 5 7 5 26 18 15 22 28 16 13 7 2 23 19 25 15 ^'}},
+ {OUT=>'8E6E273208AC256F9ECCF296F3F5A37BC8A0F9F7'}],
+ ['109', {IN=> {f=> '56 1 17 7 16 25 23 11 11 15 2 13 9 26 2 24 26 7 28 11 2 29 7 22 23 5 28 19 1 27 29 1 24 11 18 20 3 13 11 7 3 15 17 24 1 18 13 6 3 25 27 16 28 18 24 8 23 22 ^'}},
+ {OUT=>'FE0606100BDBC268DB39B503E0FDFE3766185828'}],
+ ['110', {IN=> {f=> '51 1 29 28 6 28 14 12 28 27 22 4 14 25 1 3 9 7 11 14 15 16 10 19 12 19 11 20 13 28 4 27 28 7 27 12 4 28 21 17 22 20 17 15 15 23 22 13 12 21 22 21 29 ^'}},
+ {OUT=>'6C63C3E58047BCDB35A17F74EEBA4E9B14420809'}],
+ ['111', {IN=> {f=> '64 1 12 14 12 18 27 8 7 4 9 14 16 15 8 11 21 20 10 10 21 23 20 2 11 23 1 11 1 5 3 23 16 15 27 14 5 16 3 22 2 3 24 3 19 29 4 4 10 8 20 14 15 1 26 12 27 25 4 28 22 11 19 19 24 9 ^'}},
+ {OUT=>'BCC2BD305F0BCDA8CF2D478EF9FE080486CB265F'}],
+ ['112', {IN=> {f=> '60 1 20 8 9 5 25 19 17 19 15 7 24 24 21 3 20 16 8 3 17 28 18 29 9 23 9 10 29 4 12 24 15 5 8 22 17 29 12 3 8 29 15 21 21 4 7 20 7 10 7 26 10 16 24 6 7 12 8 12 15 17 ^'}},
+ {OUT=>'CE5223FD3DD920A3B666481D5625B16457DCB5E8'}],
+ ['113', {IN=> {f=> '60 0 9 17 11 28 12 26 26 6 29 13 10 20 6 23 10 4 3 26 26 14 20 20 25 14 13 15 24 14 11 4 23 27 24 20 9 16 17 24 13 12 6 1 14 26 25 7 8 21 1 19 3 2 2 17 21 13 5 9 21 11 ^'}},
+ {OUT=>'948886776E42E4F5FAE1B2D0C906AC3759E3F8B0'}],
+ ['114', {IN=> {f=> '54 0 25 1 27 24 6 23 16 5 1 20 29 22 25 9 25 10 3 28 28 25 19 18 16 24 14 15 5 28 12 28 26 29 2 15 15 9 5 18 19 22 12 15 4 6 15 24 16 9 4 26 25 18 27 12 ^'}},
+ {OUT=>'4C12A51FCFE242F832E3D7329304B11B75161EFB'}],
+ ['115', {IN=> {f=> '61 1 20 4 26 12 3 22 1 22 30 3 28 10 9 24 14 29 6 30 3 10 20 14 6 3 19 21 21 28 16 18 11 30 11 20 30 1 9 8 11 5 19 10 24 4 22 4 2 26 5 15 20 8 3 13 30 18 8 1 25 28 19 ^'}},
+ {OUT=>'C54BDD2050504D92F551D378AD5FC72C9ED03932'}],
+ ['116', {IN=> {f=> '56 1 20 15 21 18 18 12 16 13 24 9 21 2 28 6 1 23 9 18 27 27 4 9 13 10 8 14 16 15 12 11 14 21 14 10 11 25 17 17 30 21 13 27 26 26 22 14 13 17 21 19 9 9 20 23 13 28 ^'}},
+ {OUT=>'8F53E8FA79EA09FD1B682AF5ED1515ECA965604C'}],
+ ['117', {IN=> {f=> '59 1 10 28 24 10 22 27 23 27 8 17 14 6 4 21 26 15 1 8 29 27 6 28 15 3 27 25 25 14 19 13 29 8 24 2 8 2 4 12 19 11 10 6 26 14 22 24 30 10 11 12 2 12 17 23 8 8 12 28 12 ^'}},
+ {OUT=>'2D7E17F6294524CE78B33EAB72CDD08E5FF6E313'}],
+ ['118', {IN=> {f=> '56 0 14 28 2 17 4 8 3 26 9 23 21 30 30 20 4 13 28 29 9 3 17 7 19 30 28 1 2 20 9 12 24 15 30 20 27 3 23 11 6 29 25 23 26 17 20 10 22 15 23 6 25 5 4 30 2 29 ^'}},
+ {OUT=>'64582B4B57F782C9302BFE7D07F74AA176627A3A'}],
+ ['119', {IN=> {f=> '63 1 23 15 27 14 26 1 1 7 19 12 7 6 20 18 14 4 15 17 28 7 11 7 8 9 22 17 12 5 23 18 25 18 6 12 26 30 12 30 14 3 1 18 10 20 27 21 8 6 24 26 20 11 24 7 2 4 18 15 14 30 16 19 14 ^'}},
+ {OUT=>'6D88795B71D3E386BBD1EB830FB9F161BA98869F'}],
+ ['120', {IN=> {f=> '52 0 27 15 4 19 25 29 29 7 14 18 9 11 9 27 11 15 29 9 28 20 2 30 26 21 17 8 28 17 22 29 24 8 11 18 29 15 6 7 27 27 17 24 18 23 11 19 8 30 5 24 22 24 ^'}},
+ {OUT=>'86AD34A6463F12CEE6DE9596ABA72F0DF1397FD1'}],
+ ['121', {IN=> {f=> '66 1 25 15 28 23 5 10 21 5 8 7 3 10 19 17 6 9 15 29 10 7 4 1 16 21 16 29 13 18 5 3 8 15 8 21 29 20 5 27 2 13 27 7 7 30 2 18 26 10 2 5 29 21 15 25 26 24 8 12 20 3 9 10 30 7 12 29 ^'}},
+ {OUT=>'7EB46685A57C0D466152DC339C8122548C757ED1'}],
+ ['122', {IN=> {f=> '53 1 30 26 20 11 22 19 27 2 16 10 6 4 24 17 20 25 20 15 8 23 23 20 30 18 16 3 30 15 26 23 28 7 21 8 7 31 31 14 26 18 3 1 26 28 15 25 11 31 3 25 9 21 30 ^'}},
+ {OUT=>'E7A98FB0692684054407CC221ABC60C199D6F52A'}],
+ ['123', {IN=> {f=> '67 0 2 6 14 4 9 5 28 8 17 22 1 4 8 7 10 14 19 10 14 8 27 9 24 26 4 30 11 8 19 5 21 7 2 27 20 16 20 20 22 14 13 16 26 14 10 3 25 22 25 23 21 10 15 15 29 8 13 4 2 13 22 20 7 4 20 31 23 ^'}},
+ {OUT=>'34DF1306662206FD0A5FC2969A4BEEC4EB0197F7'}],
+ ['124', {IN=> {f=> '65 0 2 2 28 13 19 14 12 23 27 6 2 14 2 22 6 25 30 29 31 13 14 16 31 12 16 30 5 14 31 11 4 1 1 25 21 13 26 22 21 5 22 14 29 1 21 3 14 30 4 2 29 12 15 23 3 15 5 1 6 23 22 13 1 14 23 ^'}},
+ {OUT=>'56CF7EBF08D10F0CB9FE7EE3B63A5C3A02BCB450'}],
+ ['125', {IN=> {f=> '59 1 25 5 15 6 13 3 22 11 23 31 24 6 5 20 4 14 3 29 8 29 19 7 29 23 25 28 19 11 15 27 21 14 1 19 20 26 12 7 12 1 18 13 29 28 23 29 14 23 7 1 9 29 24 5 30 18 5 25 30 ^'}},
+ {OUT=>'3BAE5CB8226642088DA760A6F78B0CF8EDDEA9F1'}],
+ ['126', {IN=> {f=> '55 1 31 25 13 7 24 25 24 1 12 19 9 7 6 28 20 14 28 21 19 31 20 20 6 24 18 27 24 4 18 21 1 31 15 1 15 2 27 4 26 25 4 23 19 2 31 22 30 21 22 5 27 12 30 28 31 ^'}},
+ {OUT=>'6475DF681E061FA506672C27CBABFA9AA6DDFF62'}],
+ ['127', {IN=> {f=> '62 0 27 15 18 14 25 15 17 7 28 11 28 29 30 1 17 12 10 2 18 20 21 2 11 12 5 4 12 25 14 5 5 24 22 18 31 15 22 29 11 3 21 31 21 27 3 28 7 10 25 2 15 30 9 30 7 22 15 9 3 20 24 14 ^'}},
+ {OUT=>'79D81991FA4E4957C8062753439DBFD47BBB277D'}],
+ ['128', {IN=> {f=> '60 0 28 14 18 9 27 14 22 27 31 10 8 14 7 15 7 20 5 26 1 29 7 17 17 8 3 13 27 18 8 31 27 28 22 22 17 19 18 18 11 19 13 25 10 19 6 28 4 31 23 10 18 26 31 5 10 13 12 8 15 27 ^'}},
+ {OUT=>'BAE224477B20302E881F5249F52EC6C34DA8ECEF'}],
+ ['129', {IN=> {f=> '60 1 24 22 4 29 22 31 28 20 4 16 21 3 1 15 5 15 6 30 3 29 29 7 27 20 2 20 31 22 26 9 29 16 4 26 32 17 20 14 28 17 19 6 24 11 26 28 5 18 15 8 16 20 21 4 9 12 4 8 17 29 ^'}},
+ {OUT=>'EDE4DEB4293CFE4138C2C056B7C46FF821CC0ACC'}],
+ ['130', {IN=> {f=> '69 1 5 3 11 15 12 24 31 23 1 6 28 2 8 31 6 7 30 5 19 23 12 6 9 31 19 17 24 25 22 6 12 16 3 7 9 9 11 29 4 11 2 5 13 29 10 12 30 32 18 28 18 27 3 30 4 4 26 6 13 31 13 2 11 7 24 4 17 29 12 ^'}},
+ {OUT=>'A771FA5C812BD0C9596D869EC99E4F4AC988B13F'}],
+ ['131', {IN=> {f=> '95 0 21 19 21 23 11 42 36 2 13 4 1 33 22 16 27 9 4 33 16 3 30 15 11 32 13 17 38 32 9 38 4 36 15 32 27 19 42 18 6 36 22 10 29 12 25 40 15 29 23 28 30 4 8 11 24 9 10 31 28 43 23 16 29 33 5 40 26 3 19 12 36 43 5 35 37 5 14 11 45 35 16 10 8 32 4 15 35 26 2 39 22 37 22 30 29 ^'}},
+ {OUT=>'E99D566212BBBCEEE903946F6100C9C96039A8F4'}],
+ ['132', {IN=> {f=> '106 1 18 14 51 2 6 32 51 9 32 50 44 46 51 8 11 53 45 55 16 10 3 52 8 20 20 46 46 13 32 2 46 50 43 25 54 9 31 29 2 47 15 29 24 45 44 18 37 14 28 39 36 44 47 16 50 10 44 24 53 35 22 40 20 15 51 22 18 22 42 6 54 49 38 21 7 13 30 16 7 52 16 22 13 38 7 11 44 33 9 25 13 37 42 14 45 53 30 38 5 25 5 35 38 22 28 53 ^'}},
+ {OUT=>'B48CE6B1D13903E3925AE0C88CB931388C013F9C'}],
+ ['133', {IN=> {f=> '127 0 58 35 43 28 5 28 63 8 12 25 9 47 53 29 62 7 37 2 3 48 5 12 55 56 28 35 12 63 6 58 27 27 48 44 35 14 17 22 56 10 8 1 16 15 42 63 14 51 57 19 41 7 8 56 47 34 52 22 48 60 43 9 1 52 4 21 49 61 18 50 23 13 46 62 23 45 62 9 56 18 23 31 8 30 27 36 13 38 4 58 53 47 24 18 41 58 19 12 18 52 42 29 44 45 26 63 34 32 41 64 15 26 55 19 2 49 6 30 53 13 54 12 53 37 12 37 43 ^'}},
+ {OUT=>'E647D5BAF670D4BF3AFC0A6B72A2424B0C64F194'}],
+ ['134', {IN=> {f=> '148 0 60 4 51 47 58 38 17 63 33 23 28 43 12 69 70 33 17 12 50 18 18 36 45 2 67 4 45 20 4 33 38 29 45 8 22 58 39 71 38 32 53 35 19 53 31 29 51 35 4 63 18 33 26 47 70 9 64 62 63 30 15 1 35 28 16 40 20 14 50 33 19 38 30 27 55 10 16 46 47 7 55 12 53 26 56 33 29 55 25 17 48 43 21 43 18 24 63 27 68 46 38 33 35 10 18 11 27 5 9 58 35 70 36 36 39 47 2 10 66 47 5 18 21 44 71 51 57 3 22 7 56 55 28 25 14 40 16 24 48 37 66 50 24 45 18 39 53 55 ^'}},
+ {OUT=>'65C1CD932A06B05CD0B43AFB3BC7891F6BCEF45C'}],
+ ['135', {IN=> {f=> '165 1 15 62 35 29 15 40 19 76 67 4 5 71 46 61 26 8 77 48 1 23 12 60 40 24 44 33 29 42 73 66 49 61 20 30 1 54 52 42 39 64 23 65 37 24 20 11 26 66 22 77 22 57 7 38 57 33 61 73 7 64 1 49 35 76 14 27 21 45 68 38 58 73 13 72 47 73 33 8 66 23 38 4 56 77 47 10 71 13 20 31 41 6 51 3 18 17 61 47 14 48 76 46 28 34 43 1 56 4 25 7 65 41 1 34 37 23 59 59 27 26 13 15 14 75 60 14 1 28 59 26 65 61 16 23 17 28 6 19 2 35 49 30 29 48 2 63 73 59 1 3 76 41 11 19 18 43 54 63 67 51 4 9 78 60 66 ^'}},
+ {OUT=>'70FFAE353A5CD0F8A65A8B2746D0F16281B25EC7'}],
+ ['136', {IN=> {f=> '181 0 18 19 84 17 12 10 57 18 77 51 52 16 39 74 49 52 63 38 72 2 15 64 83 62 49 56 11 26 68 58 83 33 23 50 63 71 53 27 84 22 39 41 52 58 11 64 7 60 45 70 22 5 73 38 30 30 48 21 75 80 40 21 8 53 9 26 30 34 81 71 71 51 23 75 33 41 23 32 5 8 66 40 72 40 16 66 45 14 48 34 21 41 27 3 55 27 37 23 41 65 4 57 51 74 22 19 75 42 16 19 46 16 10 48 20 19 37 41 14 57 9 17 55 38 5 60 7 46 20 43 36 39 52 20 10 62 45 23 46 7 35 75 29 70 35 36 34 25 12 15 84 26 10 6 71 29 79 33 32 25 59 76 82 64 58 7 8 19 41 74 2 53 65 24 1 55 51 36 21 79 7 ^'}},
+ {OUT=>'CC8221F2B829B8CF39646BF46888317C3EB378EA'}],
+ ['137', {IN=> {f=> '184 1 60 66 66 6 3 9 73 12 7 40 70 18 71 70 65 51 14 14 27 50 9 87 81 50 22 19 40 37 16 79 12 34 37 76 82 10 61 7 81 49 67 26 45 82 50 81 63 45 69 31 31 76 51 9 59 34 51 54 34 83 10 33 51 86 81 82 69 18 8 22 64 19 86 62 58 33 37 17 34 5 29 83 42 76 50 54 66 39 9 1 36 43 17 65 6 35 56 72 71 83 88 10 1 8 87 22 6 21 78 25 89 43 62 40 55 85 31 89 74 63 46 28 24 26 31 17 7 8 27 19 12 85 17 20 27 77 10 2 54 80 17 52 74 76 69 78 11 20 80 4 29 24 85 75 18 39 23 70 83 29 57 67 72 70 33 4 15 46 42 2 69 13 53 33 69 64 33 64 14 40 69 59 78 54 ^'}},
+ {OUT=>'26ACCC2D6D51FF7BF3E5895588907765111BB69B'}],
+ ['138', {IN=> {f=> '193 1 68 43 95 53 38 58 55 28 20 16 67 48 17 86 32 44 68 67 28 16 14 79 25 15 72 67 50 80 18 30 10 75 1 60 45 87 78 28 95 49 63 70 59 26 6 51 73 60 65 18 26 8 87 5 58 31 25 57 40 46 78 57 34 78 61 36 66 57 38 80 22 32 68 71 30 74 37 81 66 77 66 55 2 51 24 93 61 40 68 45 61 12 63 24 89 59 52 72 43 20 20 69 36 40 88 46 9 62 55 77 84 20 18 6 77 15 52 39 75 3 26 4 85 17 62 29 11 92 46 58 29 59 28 42 80 71 96 2 49 85 37 63 4 61 14 2 53 87 25 86 6 75 76 93 41 39 93 92 42 56 41 63 26 28 18 77 11 50 78 79 1 12 12 91 29 13 58 5 56 92 66 59 4 39 47 95 5 5 62 33 13 80 27 ^'}},
+ {OUT=>'01072915B8E868D9B28E759CF2BC1AEA4BB92165'}],
+ ['139', {IN=> {f=> '203 1 35 28 11 7 20 7 17 3 3 30 89 13 65 56 66 63 22 82 16 31 55 56 77 91 91 71 101 13 10 85 101 95 17 99 98 91 33 14 20 48 32 7 64 29 38 35 25 4 95 23 34 1 85 81 23 31 96 71 84 50 15 79 47 25 51 45 35 66 19 61 60 9 31 93 64 70 30 42 86 53 1 71 46 42 22 38 96 10 99 34 76 26 55 73 63 63 97 23 92 81 64 46 1 30 31 35 86 91 88 64 87 16 37 69 84 94 60 100 3 47 52 8 71 87 57 29 76 43 18 45 46 15 65 12 44 42 66 60 15 68 19 58 39 62 76 9 92 101 57 32 4 34 15 41 62 32 89 71 43 35 31 41 21 17 82 33 96 27 62 29 82 57 46 62 15 24 99 37 83 40 52 46 56 80 98 3 91 74 6 27 7 58 94 10 41 79 97 84 77 74 26 99 35 ^'}},
+ {OUT=>'3016115711D74236ADF0C371E47992F87A428598'}],
+ ['140', {IN=> {f=> '212 1 26 101 17 91 45 97 80 59 102 30 68 4 85 9 4 39 16 18 85 70 11 87 62 72 78 38 3 41 53 82 82 35 18 13 94 64 52 39 77 59 26 9 65 46 64 98 32 29 86 79 16 63 54 76 56 98 16 98 78 22 72 33 103 104 52 84 12 65 15 85 101 97 84 31 51 26 100 100 38 80 13 2 78 7 24 44 84 103 27 7 28 16 33 99 25 103 54 14 42 62 87 92 27 22 42 5 52 100 84 73 72 63 24 48 56 52 23 5 17 76 31 1 95 58 43 60 50 62 30 23 35 79 20 35 3 72 32 45 51 87 41 84 27 79 77 70 102 15 54 15 100 8 52 69 105 3 30 84 42 93 66 89 69 74 24 33 42 97 4 38 99 106 13 93 6 106 74 100 54 45 21 59 56 37 9 50 32 75 79 31 77 9 61 1 8 68 6 60 81 7 100 99 14 61 48 25 73 26 70 72 94 34 ^'}},
+ {OUT=>'BF30417999C1368F008C1F19FECA4D18A5E1C3C9'}],
+ ['141', {IN=> {f=> '233 0 11 98 110 88 35 110 35 64 49 88 93 28 85 6 78 65 90 52 24 97 51 39 51 59 23 1 3 49 33 11 78 27 35 55 64 5 102 4 70 25 56 58 38 66 11 31 96 66 104 59 41 86 58 29 79 41 40 72 51 12 92 34 52 44 69 104 21 97 89 96 48 21 4 61 40 28 67 34 23 85 44 22 62 52 33 84 23 30 73 74 4 79 12 81 47 80 53 47 89 40 19 80 62 34 61 29 41 95 43 1 70 63 55 53 18 19 13 48 10 19 89 49 4 52 53 56 76 10 8 104 77 15 28 38 75 109 3 85 90 8 40 8 93 90 43 39 14 60 17 36 78 56 105 80 35 75 36 58 82 50 100 98 45 74 13 66 95 72 71 95 34 14 98 72 33 38 37 52 6 14 107 59 3 29 61 67 98 92 5 93 17 98 36 87 41 75 71 57 88 17 25 91 84 3 58 20 92 69 51 50 36 31 14 25 18 30 18 1 41 104 30 82 59 87 70 34 96 28 47 62 81 103 48 ^'}},
+ {OUT=>'62BA49087185F2742C26E1C1F4844112178BF673'}],
+ ['142', {IN=> {f=> '234 1 63 90 108 108 102 64 82 88 4 111 76 97 22 1 108 41 34 91 33 20 25 24 26 8 83 11 31 7 85 109 106 4 105 85 68 28 33 99 53 8 16 12 11 74 17 83 66 70 16 30 9 67 68 34 24 81 47 92 72 47 37 33 38 92 17 8 28 88 22 62 69 32 89 75 3 72 96 85 13 105 24 38 37 94 115 83 72 108 114 24 93 76 103 60 99 102 9 43 10 59 95 46 33 93 15 26 69 44 2 86 107 55 45 61 65 92 66 9 55 39 70 83 29 98 67 13 111 15 20 31 62 8 2 51 20 19 33 44 14 115 71 112 97 10 41 28 53 51 26 57 15 38 98 55 106 22 56 31 50 95 107 110 84 70 10 108 96 73 100 25 36 55 88 71 63 96 30 90 96 79 22 7 30 23 28 59 89 8 51 99 47 86 34 18 43 65 98 104 107 49 7 79 71 8 57 21 29 80 2 74 78 44 57 9 61 22 13 68 52 91 74 98 43 30 58 68 95 101 72 102 76 42 99 61 ^'}},
+ {OUT=>'E1F6B9536F384DD3098285BBFD495A474140DC5A'}],
+ ['143', {IN=> {f=> '249 0 27 117 45 119 80 2 59 52 8 76 20 94 102 69 96 42 46 106 67 9 110 89 71 69 34 31 15 85 16 29 100 82 37 62 68 95 108 44 23 114 34 36 56 93 11 30 96 12 31 67 14 114 14 66 70 30 81 46 53 119 85 6 104 47 92 72 70 5 70 15 115 68 105 33 97 13 85 106 14 61 29 22 86 45 57 69 91 38 38 28 66 13 60 95 103 3 15 5 113 38 23 62 5 65 94 107 73 104 37 47 102 117 3 78 35 7 95 56 78 45 52 28 46 43 37 32 53 19 55 29 47 97 76 115 83 71 11 45 62 73 99 116 2 24 116 7 28 41 2 29 37 52 23 5 118 79 31 57 89 61 24 101 78 50 93 73 41 7 33 45 47 24 1 48 73 36 3 25 87 46 28 108 54 68 53 67 119 28 36 118 104 42 88 27 112 4 74 85 1 63 39 97 71 74 75 76 10 49 12 79 11 50 103 118 94 117 118 37 27 12 94 60 28 51 47 82 110 17 15 105 23 52 43 12 21 22 81 41 12 74 90 42 108 117 98 67 4 69 85 ^'}},
+ {OUT=>'B522DAE1D67726EBA7C4136D4E2F6D6D645AC43E'}],
+ ['144', {IN=> {f=> '243 0 76 81 26 101 13 68 62 106 87 19 98 32 81 63 79 93 31 121 123 75 52 11 66 41 54 87 38 5 104 62 51 38 55 29 31 120 44 16 48 94 46 105 91 66 78 27 43 6 64 2 55 79 75 84 113 22 4 113 109 31 33 17 96 11 29 63 98 103 107 116 34 14 9 95 38 18 51 75 33 109 118 55 66 4 76 7 75 70 82 74 23 1 26 69 40 112 99 47 65 31 70 119 52 103 88 85 86 28 16 12 76 25 22 78 64 21 86 27 61 77 72 108 2 18 106 119 121 54 16 85 72 2 73 26 88 66 60 80 35 24 117 63 24 44 67 52 122 119 33 72 16 99 98 69 54 19 42 28 53 114 32 117 81 100 57 49 123 56 21 68 80 53 95 1 45 95 107 98 87 1 27 24 99 116 16 67 1 113 91 84 25 40 25 72 3 28 90 87 112 80 16 117 45 77 36 90 105 59 88 122 64 108 108 71 98 18 50 115 93 105 77 35 6 46 55 47 102 4 26 87 111 120 81 113 4 57 105 3 84 94 115 61 73 ^'}},
+ {OUT=>'E9A021C3EB0B9F2C710554D4BF21B19F78E09478'}],
+ ['145', {IN=> {f=> '255 1 91 47 51 9 57 9 55 94 61 61 68 46 107 6 35 81 114 78 96 74 14 89 73 67 67 69 113 107 11 98 113 109 20 92 17 67 70 88 57 10 124 9 60 122 93 91 45 7 15 24 51 5 98 115 24 49 90 104 117 66 128 94 64 80 12 43 91 46 111 59 58 77 30 14 88 60 123 68 41 44 68 40 104 118 41 43 93 90 105 92 16 127 26 54 125 114 79 71 24 48 21 25 118 40 103 49 91 44 67 65 25 119 109 18 48 23 69 112 38 61 64 87 84 104 119 110 122 92 22 1 8 83 34 100 32 62 41 46 112 34 102 76 56 39 4 127 30 13 19 110 124 7 16 128 95 4 124 11 104 116 126 49 95 3 55 96 70 90 101 4 122 96 75 118 39 128 99 92 18 42 20 87 83 35 75 111 61 67 71 28 101 9 56 34 105 95 71 23 73 71 26 57 15 23 76 55 99 89 128 98 117 68 43 88 62 38 62 39 2 83 36 15 26 60 128 96 73 74 10 1 12 42 22 2 77 33 33 32 57 13 14 82 57 12 39 3 58 80 14 87 85 44 69 109 119 ^'}},
+ {OUT=>'DF13573188F3BF705E697A3E1F580145F2183377'}],
+ ['146', {IN=> {f=> '283 0 102 55 53 41 60 88 25 67 58 76 44 22 68 118 108 40 95 96 81 90 85 28 77 18 11 37 72 93 60 110 124 119 95 131 91 37 109 126 8 73 69 72 80 17 83 5 76 20 32 15 10 1 103 18 22 116 98 9 51 104 102 44 33 15 12 24 31 89 1 6 28 101 8 64 72 106 30 5 52 89 111 39 108 64 85 17 57 124 22 105 78 115 3 40 108 66 108 77 128 103 44 35 38 13 95 10 111 63 98 117 61 51 126 69 96 70 70 59 39 13 97 33 112 2 77 7 123 70 83 29 66 67 49 79 19 104 115 14 60 2 55 40 71 33 28 114 51 91 17 46 45 128 57 87 62 25 115 38 50 55 90 74 8 51 102 79 43 94 36 122 94 12 41 36 25 104 91 24 7 99 80 30 126 32 63 122 107 114 27 28 79 41 12 35 51 115 122 70 22 79 65 2 88 27 17 59 15 23 44 57 5 65 6 26 78 80 125 93 84 100 45 22 129 68 36 111 74 118 11 50 42 120 47 21 8 86 112 26 67 60 99 45 93 47 8 38 59 52 56 124 20 82 18 117 24 18 46 106 19 117 26 41 47 45 130 7 15 1 4 5 100 10 85 50 44 11 48 92 119 108 42 118 125 ^'}},
+ {OUT=>'188835CFE52ECFA0C4135C2825F245DC29973970'}],
+ ['147', {IN=> {f=> '272 0 8 61 99 70 96 20 87 123 134 82 22 2 110 118 33 86 5 7 5 94 56 15 60 96 54 13 22 55 99 4 25 105 17 37 69 10 38 117 117 30 70 13 9 109 115 62 94 52 66 117 100 135 7 75 23 5 81 110 31 118 29 1 62 11 41 88 109 119 102 37 3 30 123 47 31 56 134 29 124 116 118 99 21 56 77 91 23 37 135 81 44 51 67 95 51 133 30 57 67 116 122 48 100 7 132 97 106 69 93 4 95 125 102 103 119 81 57 133 96 37 118 50 117 113 81 127 17 45 103 32 121 129 60 43 65 127 30 36 132 110 52 53 35 71 12 76 22 72 130 112 99 76 26 21 73 63 63 97 23 58 115 132 114 1 132 31 35 18 23 54 30 53 118 37 35 84 94 60 100 3 47 18 110 105 87 57 63 76 43 52 45 46 49 65 12 10 42 66 60 117 34 19 92 5 28 76 9 126 101 125 32 38 34 15 7 62 32 21 3 43 69 31 109 123 51 116 135 130 129 130 63 14 57 80 62 15 126 31 105 83 108 120 80 124 46 98 105 91 6 6 27 7 58 128 78 7 79 63 84 77 74 128 65 61 95 121 17 24 123 117 51 122 ^'}},
+ {OUT=>'41B615A34EE2CEC9D84A91B141CFAB115821950B'}],
+ ['148', {IN=> {f=> '284 0 44 71 43 20 126 58 53 47 98 18 19 119 93 29 70 39 94 112 44 115 135 98 82 10 67 29 102 113 68 80 19 75 1 91 114 87 80 7 40 37 86 120 16 104 136 117 82 138 32 65 114 119 137 121 8 12 46 126 26 119 73 130 60 76 113 100 14 133 26 116 34 120 80 95 84 53 15 24 44 51 4 10 23 77 24 99 66 37 54 63 42 136 21 34 76 5 17 128 101 1 59 40 113 112 32 97 31 93 105 79 91 18 39 1 103 132 51 68 124 111 13 97 43 128 69 84 85 72 15 12 26 87 16 16 92 101 13 77 4 118 89 103 56 42 16 60 44 39 126 46 18 83 93 41 105 3 82 106 115 91 6 4 54 115 15 120 109 113 48 41 9 95 20 62 67 105 111 25 132 7 116 46 138 44 83 61 124 131 35 107 6 109 81 114 67 41 137 77 56 74 73 34 12 14 69 52 11 98 47 54 83 81 6 1 15 88 35 139 80 83 49 89 27 47 130 92 133 87 51 112 76 49 109 49 57 93 73 22 117 50 64 58 97 139 36 131 111 133 58 33 8 88 55 38 90 46 30 118 57 29 82 74 41 117 38 46 94 92 5 105 15 117 70 103 68 60 120 48 21 110 85 40 81 66 ^'}},
+ {OUT=>'AB3DD6221D2AFE6613B815DA1C389EEC74AA0337'}],
+ ['149', {IN=> {f=> '291 0 46 113 52 134 79 74 64 57 18 23 9 52 8 16 103 57 138 59 59 65 92 2 7 130 92 8 34 40 86 131 140 100 112 4 42 1 110 108 43 37 15 67 19 35 94 61 130 98 35 88 34 65 104 56 126 118 50 87 10 81 109 90 86 118 32 6 114 88 39 38 39 62 3 12 134 72 137 35 75 81 115 106 140 112 11 123 41 103 45 95 84 71 107 13 26 110 96 62 16 109 84 59 53 38 27 8 28 13 32 137 17 138 41 122 36 99 65 99 83 36 112 29 49 70 96 126 136 131 116 3 18 17 126 142 14 37 141 141 123 42 13 20 83 42 139 83 54 49 58 42 7 137 29 48 16 121 127 34 52 140 106 128 58 36 124 83 24 69 54 61 112 17 6 95 97 24 57 86 124 59 71 119 67 1 109 54 68 49 57 132 32 5 71 113 40 80 104 75 106 133 31 126 130 104 62 9 39 44 66 116 141 135 96 132 19 41 121 126 124 77 8 4 60 82 6 101 124 89 51 123 48 40 85 77 21 112 10 69 66 115 87 16 108 30 84 65 80 103 32 131 134 73 47 10 63 39 50 93 37 135 114 69 48 34 58 23 27 133 37 9 40 98 41 115 99 70 83 29 42 67 133 55 79 80 91 122 12 2 115 112 47 ^'}},
+ {OUT=>'0706D414B4AA7FB4A9051AA70D6856A7264054FB'}],
+ ['150', {IN=> {f=> '293 1 33 13 99 138 1 42 89 118 87 113 99 12 134 142 100 38 5 55 75 14 110 108 42 64 130 79 138 62 64 69 57 11 123 25 59 16 111 94 24 65 30 51 119 48 107 92 84 69 28 136 143 54 20 6 70 47 142 64 4 65 59 73 99 134 146 102 125 116 57 137 137 72 48 128 78 5 80 63 54 85 30 22 129 68 21 21 74 28 128 107 27 60 2 93 95 71 37 11 37 15 39 102 3 104 65 80 59 52 113 34 20 67 60 27 81 135 46 106 106 102 68 128 17 15 100 124 15 43 136 122 100 67 142 35 14 53 120 2 89 93 99 73 9 122 39 77 15 96 90 43 79 134 60 92 105 55 96 31 119 77 97 72 23 140 38 30 43 83 136 88 107 117 72 109 118 58 91 119 73 95 100 59 138 123 54 49 143 50 133 66 106 45 80 88 42 93 5 59 77 101 74 110 104 40 92 19 77 76 86 102 129 3 144 101 139 134 56 90 18 91 94 85 55 10 137 11 58 1 107 113 70 22 7 56 29 143 111 8 46 45 116 122 129 89 7 121 53 95 14 49 118 62 125 91 37 97 15 35 100 63 140 63 50 51 58 26 127 6 45 59 102 121 114 85 141 135 10 72 19 106 66 66 41 53 13 38 1 21 103 50 108 46 119 ^'}},
+ {OUT=>'3CBF8151F3A00B1D5A809CBB8C4F3135055A6BD1'}],
+ ['151', {IN=> {f=> '297 1 46 31 132 112 28 63 124 97 129 43 40 72 99 107 132 137 96 139 99 145 121 144 118 37 81 39 94 60 55 109 47 109 110 75 42 12 139 137 43 128 106 107 19 126 12 101 148 127 15 117 125 125 62 96 13 76 70 96 101 110 138 8 95 76 143 17 32 97 79 149 39 31 94 123 21 41 135 55 84 70 33 135 118 50 62 121 81 1 45 144 93 60 5 64 137 8 105 91 82 67 27 113 119 53 18 98 79 48 84 32 135 128 5 1 20 76 17 85 108 72 36 141 140 49 150 105 104 3 149 14 54 18 148 64 49 125 37 28 28 101 22 104 91 32 82 117 12 114 69 58 2 58 115 9 108 47 59 65 14 92 7 4 86 98 16 82 92 95 38 94 10 10 48 97 104 66 115 97 142 115 122 119 40 97 16 32 47 34 88 89 26 50 12 76 80 51 40 9 133 24 44 40 122 84 108 22 142 140 99 44 15 54 8 42 125 150 130 21 79 124 62 46 119 15 29 91 57 150 42 138 71 61 68 80 114 6 1 70 121 18 35 113 56 87 86 10 73 14 29 41 72 89 1 133 87 101 123 59 90 142 77 133 52 78 48 34 138 134 27 17 60 131 147 61 93 148 39 132 49 62 71 36 91 4 139 49 100 120 43 113 144 30 94 73 127 40 125 ^'}},
+ {OUT=>'DA5D6A0319272BBCCEA63ACFA6799756FFDA6840'}],
+ ['152', {IN=> {f=> '313 1 35 97 95 76 105 88 32 138 30 69 61 40 47 21 107 6 39 81 114 53 125 53 147 14 4 73 146 96 98 13 136 11 98 117 138 153 67 146 71 99 88 7 139 24 13 35 47 97 145 74 36 119 3 51 84 48 119 53 49 15 79 17 120 103 148 64 30 41 97 120 75 111 63 58 131 134 18 13 10 48 18 16 48 43 15 54 18 41 47 122 144 80 92 145 77 1 33 89 54 46 78 48 21 54 43 40 53 24 16 73 42 94 29 44 34 151 152 23 123 12 142 140 43 37 88 29 19 35 72 96 151 130 62 112 34 36 91 120 50 112 138 2 105 60 68 137 131 5 17 19 139 74 11 120 78 149 58 128 15 104 16 126 78 20 57 134 71 49 90 76 108 126 100 54 68 39 132 153 42 147 146 124 62 87 35 75 61 65 46 100 82 105 113 31 63 5 95 54 71 77 127 150 80 36 144 2 130 59 74 39 3 152 121 122 18 117 12 117 141 118 135 62 36 69 5 39 53 150 52 153 143 30 66 96 126 131 56 137 8 7 86 142 14 7 111 141 93 136 137 134 43 12 89 23 44 9 152 146 121 97 19 38 110 91 67 14 32 110 66 68 8 130 84 73 118 59 24 41 72 121 150 55 37 138 27 104 66 124 9 51 109 47 125 109 148 8 29 47 72 146 149 61 93 10 20 54 15 76 133 125 106 110 67 ^'}},
+ {OUT=>'FB4429C95F6277B346D3B389413758DFFFEEDC98'}],
+ ['153', {IN=> {f=> '330 0 23 9 26 136 27 51 115 122 44 106 6 146 108 113 85 51 8 96 47 56 137 62 59 89 143 71 140 14 85 156 139 99 154 30 53 115 35 147 108 148 58 52 28 103 19 92 95 152 152 10 11 13 155 67 11 83 101 69 153 152 45 141 14 120 129 140 119 59 2 89 73 70 83 29 16 67 81 29 1 54 65 96 117 2 37 47 128 33 3 89 108 98 139 49 78 27 103 39 119 94 132 90 38 132 55 65 131 90 58 2 54 100 69 118 22 44 19 7 148 93 25 29 123 81 64 131 55 30 1 89 38 97 82 64 9 28 86 123 151 10 133 40 154 102 4 111 65 9 63 59 124 116 72 105 76 57 137 97 32 145 108 78 112 50 43 34 75 20 22 129 68 11 118 74 125 118 57 17 20 129 53 65 61 144 1 17 142 156 52 100 54 15 20 59 52 63 131 20 57 124 31 125 46 106 76 92 8 98 154 152 80 114 15 140 136 112 100 17 92 25 151 150 80 99 69 83 49 43 156 102 19 57 122 96 30 3 39 134 40 32 75 5 76 127 138 99 17 57 52 150 130 18 127 33 23 116 107 78 77 77 42 69 68 48 41 69 33 75 40 49 128 103 4 146 93 10 83 66 96 152 30 38 12 33 5 39 47 41 34 60 74 20 42 156 67 46 56 102 89 3 124 81 99 104 56 50 8 61 74 55 15 87 108 28 138 47 93 60 2 124 46 126 103 91 145 36 25 116 122 51 ^'}},
+ {OUT=>'2C6E30D9C895B42DCCCFC84C906EC88C09B20DE1'}],
+ ['154', {IN=> {f=> '322 0 75 7 107 158 81 105 154 90 20 125 77 114 69 92 7 58 21 98 154 50 128 149 117 127 153 45 3 18 121 86 29 71 79 101 2 5 22 143 10 27 53 146 157 148 112 33 22 80 123 24 147 1 112 82 159 63 74 97 109 33 151 32 89 87 132 117 46 129 59 115 91 114 118 37 21 9 94 60 25 89 47 79 110 55 12 143 99 87 43 88 56 57 160 76 12 71 128 77 146 117 95 105 42 66 3 76 20 76 101 100 118 149 45 26 143 148 32 57 39 129 19 31 84 123 1 152 135 5 54 30 13 125 68 30 62 101 51 142 5 94 83 20 116 24 107 109 105 91 42 17 27 93 69 3 139 68 79 38 84 2 85 128 126 122 131 46 17 35 98 42 26 111 100 29 120 55 84 114 109 145 14 18 138 14 9 85 7 18 129 91 2 94 51 133 82 87 123 64 39 8 103 38 75 110 78 7 9 45 115 42 138 135 86 78 16 62 52 75 159 54 151 121 149 77 74 16 85 47 102 105 82 119 10 67 137 153 148 135 28 49 26 151 153 36 80 11 130 113 24 44 30 102 24 58 133 122 140 99 24 156 54 119 42 115 140 90 132 19 94 2 157 99 136 19 71 7 130 153 108 51 21 58 70 74 137 1 40 111 149 5 103 6 27 76 141 23 125 140 1 72 29 152 103 87 51 93 29 80 132 77 123 153 68 159 14 98 114 158 121 158 81 131 ^'}},
+ {OUT=>'3DE3189A5E19F225CDCE254DFF23DACD22C61363'}],
+ ['155', {IN=> {f=> '322 0 35 93 109 125 119 10 10 19 135 26 4 74 135 35 120 129 113 92 17 29 47 88 14 159 149 87 45 36 75 68 22 138 20 59 61 144 151 11 107 6 153 81 114 43 85 157 97 148 118 73 126 56 58 137 96 11 98 67 98 103 57 146 21 59 88 151 139 148 127 25 17 47 115 34 160 109 107 51 64 28 69 13 49 149 69 141 90 93 118 64 10 1 67 80 35 111 13 58 101 124 132 147 154 18 162 6 162 33 5 34 142 41 161 82 114 70 92 145 57 155 137 114 79 44 36 48 48 21 14 13 40 33 14 150 33 32 54 143 14 4 101 142 23 93 136 132 120 147 17 38 163 143 5 52 46 151 130 32 72 34 124 150 51 100 112 128 126 65 10 28 87 81 159 131 19 99 54 125 110 58 119 28 78 129 104 140 126 38 154 27 114 61 153 90 66 98 76 50 158 48 39 82 123 22 147 136 114 52 37 35 75 41 15 150 60 52 55 103 21 23 129 95 24 71 47 97 130 50 140 144 106 100 9 64 19 117 122 71 92 8 77 156 97 121 98 85 2 36 39 109 143 23 120 156 133 93 154 36 66 116 131 160 127 162 161 46 142 14 141 81 141 63 86 117 104 3 146 39 127 34 133 102 106 91 57 9 28 60 61 7 158 12 80 26 8 122 80 44 63 68 49 158 21 32 81 150 15 141 108 161 64 46 124 123 31 99 27 105 109 98 112 144 ^'}},
+ {OUT=>'93530A9BC9A817F6922518A73A1505C411D05DA2'}],
+ ['156', {IN=> {f=> '336 1 34 161 107 149 48 67 138 109 156 104 37 133 60 80 84 81 160 9 16 96 164 1 95 112 4 86 163 116 98 103 55 31 8 56 37 36 127 32 9 89 103 31 100 161 85 106 119 89 154 43 115 162 137 108 128 38 42 155 103 9 62 65 102 122 10 138 160 125 47 158 43 91 69 123 132 35 121 4 110 89 130 69 29 139 69 53 70 83 29 163 67 41 9 108 34 45 76 87 2 144 164 98 33 160 79 78 48 89 9 38 134 93 146 79 54 122 80 38 112 55 55 101 70 8 129 44 70 59 98 149 24 136 124 138 63 25 166 83 51 34 91 45 30 118 59 28 87 72 44 116 28 36 103 101 113 10 114 62 111 71 65 126 53 19 114 86 42 85 36 57 137 57 159 95 88 78 72 20 23 14 65 10 22 129 68 1 68 74 75 108 7 7 147 109 13 35 51 104 158 164 122 126 2 50 4 132 127 59 52 13 81 20 47 107 74 148 115 46 106 46 82 115 68 144 142 60 104 15 90 136 102 100 134 42 15 141 100 40 49 49 73 166 13 156 82 166 37 82 96 137 130 166 134 20 139 45 122 56 107 98 79 124 17 32 130 120 165 77 23 130 96 67 68 47 37 12 29 18 38 158 19 160 55 147 39 118 83 121 96 43 137 33 66 86 112 147 155 149 140 5 19 17 148 161 10 44 159 146 57 16 26 102 49 3 104 61 59 74 56 10 165 31 54 25 142 157 37 58 165 128 154 73 50 149 94 137 ^'}},
+ {OUT=>'E31354345F832D31E05C1B842D405D4BD4588EC8'}],
+ ['157', {IN=> {f=> '330 1 61 51 65 132 23 169 116 122 14 66 7 98 131 72 69 127 72 163 125 68 69 51 47 159 31 164 71 118 50 83 113 81 127 153 45 137 134 121 68 163 26 43 65 127 166 138 98 144 18 53 137 139 148 76 158 4 62 78 167 102 144 94 55 141 63 29 97 91 24 115 166 80 69 132 99 1 120 23 88 64 87 118 37 137 152 94 60 168 71 47 52 110 37 155 125 63 42 43 52 11 12 151 31 12 44 110 32 128 117 68 87 24 39 164 76 145 58 101 91 100 140 151 143 130 32 21 3 111 1 31 75 123 153 116 135 130 27 164 165 116 23 12 62 83 24 133 139 49 74 154 80 158 80 64 105 91 6 142 27 75 24 128 112 41 79 29 84 145 40 128 99 95 95 19 17 160 89 15 17 84 64 11 93 10 66 78 73 127 148 18 129 139 143 49 150 9 84 82 154 85 15 88 82 60 87 19 12 133 58 20 39 65 51 141 134 27 70 167 120 117 86 60 16 44 16 57 132 18 142 85 104 59 47 141 58 2 66 96 46 119 153 40 110 126 103 90 144 13 26 106 144 80 145 134 103 95 24 44 21 84 140 13 97 104 140 99 6 147 54 83 42 106 131 54 96 135 67 118 121 81 109 10 53 132 112 117 81 33 155 49 61 38 119 1 13 102 131 148 94 131 143 67 123 148 89 104 135 72 145 152 76 87 6 66 2 71 123 77 114 108 59 123 166 62 96 140 94 149 116 169 ^'}},
+ {OUT=>'3FF76957E80B60CF74D015AD431FCA147B3AF232'}],
+ ['158', {IN=> {f=> '349 0 125 17 93 82 80 110 156 147 156 99 154 4 29 90 163 120 84 113 56 8 157 29 61 169 141 113 78 48 50 13 138 11 50 61 99 106 2 107 6 117 81 114 34 49 112 52 130 82 73 108 20 22 110 60 11 98 22 62 58 48 146 149 23 88 142 139 121 91 16 163 2 88 171 133 100 62 51 46 10 24 150 49 131 60 114 63 84 91 64 165 138 40 44 172 111 141 58 74 115 96 129 145 164 153 170 126 24 169 16 115 41 125 46 87 61 92 145 39 155 92 78 70 35 27 21 48 21 151 159 40 15 5 132 170 23 18 107 160 150 56 133 23 66 109 123 102 102 172 166 145 116 151 34 1 151 130 5 36 34 97 114 15 82 128 112 119 99 29 138 165 42 36 159 95 19 63 36 89 101 40 92 1 33 93 104 113 126 2 136 96 52 108 90 57 89 31 5 113 30 39 37 96 4 147 127 105 43 165 35 75 23 143 105 24 25 10 94 12 160 102 95 170 71 20 70 112 23 95 144 61 73 137 55 1 81 95 26 65 172 41 147 79 103 80 40 121 36 12 64 98 169 93 111 115 48 127 9 39 107 131 115 118 162 161 10 142 14 123 54 141 36 41 99 77 140 128 167 82 25 106 57 70 64 21 19 15 34 126 149 167 53 163 127 86 35 8 54 23 40 140 3 169 45 150 152 96 81 143 28 28 124 87 13 90 9 87 109 53 67 164 28 131 89 149 42 55 126 79 132 74 19 133 30 68 72 75 148 9 10 72 152 144 83 106 153 74 163 98 152 ^'}},
+ {OUT=>'34AE3B806BE143A84DCE82E4B830EB7D3D2BAC69'}],
+ ['159', {IN=> {f=> '375 1 94 28 13 8 20 28 18 118 5 140 89 67 171 64 152 85 61 101 80 154 149 34 115 135 128 108 110 20 33 128 103 35 38 57 95 10 111 151 98 29 149 7 82 69 96 114 26 103 171 101 53 121 24 2 121 51 35 70 83 29 154 67 5 167 63 16 27 58 60 2 99 128 71 33 160 70 51 3 44 149 2 89 84 101 43 18 113 71 38 94 55 46 74 52 139 102 35 43 50 80 122 6 100 88 129 36 25 148 47 24 7 55 36 30 82 32 19 78 63 26 71 28 167 85 56 167 95 159 78 26 66 35 65 90 44 159 105 59 15 67 57 137 21 132 50 70 78 36 169 5 172 56 1 22 129 68 168 23 74 30 99 138 174 120 91 153 8 42 68 158 155 104 99 133 5 135 96 82 59 52 144 36 20 38 62 29 112 106 46 106 19 73 70 41 135 133 42 95 15 45 136 93 100 98 173 6 132 55 4 4 31 64 130 162 156 64 157 19 46 96 92 103 139 134 2 94 18 86 38 89 62 61 79 157 14 112 111 156 32 14 85 78 31 59 20 1 161 169 149 29 122 150 133 37 102 30 109 65 85 51 174 110 164 66 77 76 111 119 131 95 5 1 166 103 134 141 17 158 123 137 48 165 175 102 13 3 86 43 23 47 56 150 165 4 36 174 115 157 168 13 147 119 109 55 41 140 67 27 31 27 53 126 17 163 116 122 160 60 7 92 113 66 45 109 60 151 125 62 39 39 17 153 13 152 53 94 50 53 89 57 127 153 45 119 104 121 56 145 172 19 41 103 166 108 68 126 12 53 131 127 148 52 134 168 50 48 155 72 132 82 37 129 63 175 160 ^'}},
+ {OUT=>'D7447E53D66BB5E4C26E8B41F83EFD107BF4ADDA'}],
+ ['160', {IN=> {f=> '366 1 73 15 79 139 71 51 132 81 135 111 166 61 37 60 118 37 92 134 94 60 150 53 47 25 110 19 137 107 27 176 43 16 145 146 142 165 12 17 92 166 110 117 41 69 6 12 164 76 109 40 101 82 82 131 134 115 143 112 32 164 146 93 162 31 66 123 144 80 135 94 137 156 107 157 173 62 65 176 124 112 4 65 127 44 131 53 19 105 91 149 106 27 57 158 92 85 14 79 20 84 127 174 128 72 68 59 171 17 124 80 167 8 57 28 172 66 144 48 42 37 109 121 18 120 103 116 13 132 39 73 145 76 158 43 82 33 51 153 164 97 13 2 3 20 24 114 98 9 25 131 102 99 86 42 16 26 159 39 105 161 133 49 59 41 20 105 31 136 30 87 10 119 135 13 83 99 58 45 99 156 26 61 135 143 80 118 107 76 77 24 44 12 66 95 147 61 86 140 99 167 138 54 47 42 97 122 18 60 90 40 73 85 63 82 1 35 96 94 81 54 15 128 40 52 2 101 1 165 93 113 130 85 95 98 58 105 112 53 68 108 72 100 152 49 87 140 39 154 62 114 77 105 63 50 87 157 26 78 122 67 140 71 170 119 5 93 64 50 104 144 129 138 75 130 4 178 60 139 120 54 113 32 2 133 17 43 163 129 89 72 149 155 30 38 7 138 5 44 61 69 76 175 107 6 93 81 114 28 25 82 22 118 58 73 96 175 177 92 36 11 98 171 38 28 42 146 125 178 88 136 139 103 67 10 151 151 70 153 115 94 32 51 34 177 173 132 49 119 54 96 45 78 73 64 159 120 22 20 154 111 117 58 56 109 72 143 ^'}},
+ {OUT=>'77DD2A4482705BC2E9DC96EC0A13395771AC850C'}],
+ ['161', {IN=> {f=> '372 1 136 146 144 170 90 15 169 180 88 41 89 10 60 52 92 145 21 155 47 42 61 26 18 176 48 21 124 141 40 179 178 114 143 14 164 71 142 132 11 124 23 39 82 114 84 57 163 130 127 89 133 16 138 151 130 160 34 70 78 161 64 92 112 110 72 175 102 138 179 173 159 59 19 27 18 53 92 22 65 156 170 57 104 86 126 148 118 155 78 43 63 90 48 80 168 142 68 12 39 174 69 168 147 118 96 34 129 35 75 5 107 60 170 180 147 85 3 133 75 95 152 71 175 43 94 178 50 144 16 46 101 46 165 45 68 163 38 172 5 138 61 85 62 177 76 36 167 19 53 151 66 66 97 3 100 164 12 98 131 70 109 162 161 156 142 14 105 27 141 9 178 81 50 113 110 131 37 16 79 12 34 37 167 173 10 152 7 81 140 158 26 136 82 50 172 154 45 160 31 122 167 142 9 150 125 51 54 125 174 10 124 51 177 81 173 69 109 8 22 155 19 86 62 149 33 37 108 34 96 29 174 133 167 50 54 66 130 9 1 36 134 108 65 97 126 56 163 71 83 88 10 1 8 178 22 6 112 169 116 89 43 153 40 146 85 31 89 74 154 137 28 115 117 122 108 98 8 27 110 103 176 17 20 27 77 10 93 145 80 17 143 165 76 69 78 102 20 91 171 95 29 115 176 166 109 39 23 70 83 29 148 67 163 161 33 4 15 46 42 2 69 104 53 33 160 64 33 155 14 131 160 59 78 71 19 176 107 65 38 82 55 40 56 40 115 84 29 25 44 68 104 176 76 64 123 18 25 136 23 6 171 31 30 30 58 14 13 72 57 14 41 177 ^'}},
+ {OUT=>'EAA1465DB1F59DE3F25EB8629602B568E693BB57'}],
+ ['162', {IN=> {f=> '363 0 135 69 16 167 79 143 46 178 26 3 65 58 36 135 97 35 175 51 152 57 137 173 108 10 54 78 4 153 173 164 48 177 22 129 68 168 167 74 174 91 106 174 96 75 129 168 34 36 158 147 88 75 101 149 103 64 42 59 52 112 180 20 30 22 173 80 98 46 106 179 65 30 17 127 125 26 87 15 5 136 85 100 66 141 182 124 15 156 148 15 56 98 146 156 48 149 3 14 96 52 79 115 134 170 54 178 54 22 73 30 45 39 133 182 96 103 148 176 6 45 62 183 51 180 153 145 145 117 21 90 118 109 21 62 22 101 49 53 11 142 86 132 66 69 44 79 87 115 55 5 169 150 63 110 109 177 150 91 129 40 149 159 102 165 3 70 27 175 23 56 126 165 164 20 158 91 157 136 157 131 111 69 39 33 132 43 19 175 179 37 118 9 155 116 122 128 52 7 84 89 58 13 85 44 135 125 54 183 23 161 145 173 136 29 62 50 13 57 25 127 153 45 95 64 121 40 121 140 171 9 71 166 68 28 102 4 53 123 111 148 20 102 160 34 8 139 32 116 66 13 113 63 143 97 63 10 59 124 66 41 132 71 115 106 151 46 22 45 118 37 67 124 94 60 140 43 47 10 110 9 127 97 7 156 43 180 125 126 137 145 12 2 82 146 100 117 26 59 180 181 164 76 89 30 101 77 72 126 114 95 143 102 32 149 131 83 157 31 61 123 139 60 135 74 169 122 151 102 137 168 62 55 166 119 97 163 60 112 24 116 38 178 105 91 134 86 27 47 138 72 70 183 79 15 84 117 154 128 57 53 39 161 88 ^'}},
+ {OUT=>'9329D5B40E0DC43AA25FED69A0FA9C211A948411'}],
+ ['163', {IN=> {f=> '393 1 92 72 151 33 183 164 42 112 32 10 5 93 97 18 112 71 92 168 116 179 186 65 137 68 134 3 82 9 19 121 148 65 160 173 158 167 90 66 180 172 99 86 83 86 26 16 10 135 23 81 137 125 17 19 25 183 73 7 104 185 79 165 119 119 176 59 75 18 5 59 132 26 21 127 119 80 94 83 52 61 24 44 4 50 55 115 29 70 140 99 159 130 54 15 42 89 114 173 28 50 16 33 53 47 58 180 19 64 78 49 30 186 104 32 44 157 85 1 149 85 97 114 77 63 58 50 89 80 21 36 84 72 60 152 25 87 108 15 138 54 106 77 97 23 42 55 149 181 62 106 43 132 31 138 111 176 93 40 10 96 128 105 114 43 98 4 146 20 107 120 14 113 181 101 1 19 155 113 57 64 117 131 6 22 186 138 184 36 61 29 36 175 107 6 61 81 114 20 180 42 169 102 26 73 80 151 153 68 4 11 98 139 6 175 34 146 93 154 88 128 139 79 35 2 135 119 46 129 91 86 179 51 18 169 141 108 49 103 46 72 21 70 49 64 151 96 185 175 130 111 85 58 32 101 40 101 131 136 139 170 70 10 169 175 73 41 69 177 45 47 92 145 11 155 22 22 56 21 13 166 48 21 109 131 40 174 178 104 128 9 149 51 132 122 173 119 23 24 67 109 74 32 158 110 117 74 123 6 118 151 130 150 167 34 55 58 146 54 72 112 105 57 160 82 123 159 153 159 39 19 7 8 33 87 12 50 146 150 37 104 71 126 133 108 145 68 38 38 90 43 75 148 122 43 2 39 154 54 163 147 113 91 29 109 35 75 182 87 35 155 170 127 80 185 118 60 95 142 71 165 28 84 168 25 144 178 31 81 41 160 25 53 143 ^'}},
+ {OUT=>'E94C0B6AA62AA08C625FAF817DDF8F51EC645273'}],
+ ['164', {IN=> {f=> '381 1 14 172 163 130 45 69 46 145 36 36 151 169 13 135 42 26 81 153 76 148 178 90 131 30 101 162 161 132 142 14 89 3 141 175 146 65 26 89 94 99 187 8 55 162 2 13 143 173 2 120 173 41 132 150 2 112 42 18 140 130 37 128 23 106 159 118 167 150 101 11 30 109 150 184 124 19 169 73 165 53 109 158 172 147 11 46 38 149 25 21 92 184 64 179 158 133 135 34 38 58 114 9 183 4 118 76 49 89 102 40 163 47 75 80 176 175 8 154 14 180 104 153 84 89 11 129 8 138 85 181 73 66 154 121 20 115 93 114 108 82 182 19 86 103 176 183 186 177 53 10 69 137 56 1 135 141 68 69 54 86 12 75 171 87 187 107 144 150 93 23 7 70 83 29 140 67 139 153 183 178 189 30 18 2 29 72 29 33 160 56 9 123 164 107 136 19 70 31 177 152 99 57 38 66 55 32 32 24 83 60 21 1 36 52 80 168 44 32 115 184 25 120 181 172 155 189 22 30 26 180 5 64 49 188 1 28 111 57 176 167 67 131 22 160 186 169 65 34 30 117 91 17 163 39 134 57 137 155 90 170 42 78 170 141 167 158 42 177 22 129 68 168 143 74 150 85 82 174 78 63 111 156 28 12 158 141 76 57 77 125 79 40 12 59 52 88 156 20 24 182 149 56 92 46 106 167 59 189 121 119 14 81 15 165 136 79 100 42 117 182 118 175 138 124 3 50 74 134 156 36 143 181 180 96 22 61 97 134 164 24 166 30 10 61 6 33 9 115 176 84 97 142 152 15 50 165 45 168 135 133 127 93 15 66 94 91 9 32 16 95 37 29 171 118 68 108 66 63 20 55 186 ^'}},
+ {OUT=>'7FF02B909D82AD668E31E547E0FB66CB8E213771'}],
+ ['165', {IN=> {f=> '396 1 97 10 5 160 132 18 83 73 159 141 55 120 31 131 141 102 138 3 52 9 148 189 56 99 165 146 2 140 64 157 100 121 113 102 24 21 24 123 16 10 139 152 19 109 146 116 122 92 43 7 75 62 49 170 58 26 117 125 45 147 5 125 136 155 118 2 26 50 161 21 182 127 153 45 68 19 121 22 94 104 144 166 35 166 23 176 75 188 53 114 93 148 177 66 151 16 156 121 180 98 48 179 95 63 107 97 45 1 23 97 57 23 132 53 79 97 124 19 188 18 118 37 22 106 94 60 122 25 47 176 110 184 109 79 164 120 43 153 89 90 128 109 12 168 64 110 82 117 192 41 171 163 164 76 53 12 101 68 54 117 78 59 143 84 32 122 104 65 148 31 52 123 130 24 135 38 151 95 142 93 101 159 62 37 148 110 70 127 51 85 181 89 11 142 105 91 107 50 27 29 102 36 43 165 79 6 84 99 118 128 30 26 3 143 17 68 66 139 187 15 165 158 24 88 20 179 174 81 79 18 106 47 74 150 104 179 162 59 131 62 116 166 82 184 188 97 136 41 136 167 140 143 175 72 42 174 148 75 74 71 86 14 16 191 117 11 63 119 119 186 182 13 171 49 182 80 167 73 147 119 107 164 41 57 181 168 29 114 26 184 121 101 80 76 65 34 49 24 44 191 38 25 91 5 58 140 99 153 124 54 184 42 83 108 155 4 20 191 3 29 35 40 180 7 40 66 25 12 180 86 26 38 139 73 1 137 79 85 102 71 39 28 44 77 56 190 12 66 72 30 152 7 87 84 190 126 48 100 77 91 186 36 31 143 163 50 94 25 126 1 114 105 170 93 22 173 90 116 87 96 19 74 4 122 183 83 120 177 113 169 181 77 182 1 149 186 ^'}},
+ {OUT=>'5BB3570858FA1744123BAC2873B0BB9810F53FA1'}],
+ ['166', {IN=> {f=> '384 1 25 56 85 107 177 6 186 138 184 28 61 184 191 175 107 6 29 81 114 12 156 2 137 86 189 73 64 127 129 44 167 11 98 107 169 143 26 146 61 130 88 120 139 55 3 189 119 87 22 105 67 78 147 51 2 161 109 84 49 87 38 48 192 62 25 64 143 72 169 151 106 111 53 58 8 93 8 85 123 120 131 170 38 2 169 167 49 41 37 153 21 39 92 145 190 155 177 185 48 13 5 150 48 21 85 115 40 166 178 88 104 1 125 19 116 106 141 111 23 43 101 58 187 150 78 101 50 107 185 86 151 130 134 143 34 31 26 122 38 40 112 97 33 136 50 99 127 121 159 7 19 170 187 1 79 191 26 130 118 5 104 47 126 109 92 129 52 30 193 90 35 67 116 90 3 181 39 122 30 155 147 105 83 21 77 35 75 174 55 190 131 154 95 72 185 94 36 95 126 71 149 4 68 152 180 144 146 7 49 33 152 188 29 111 194 172 148 125 35 59 36 125 11 36 141 149 183 125 27 1 71 133 61 138 168 85 131 5 96 162 161 117 142 14 79 183 141 165 126 55 11 74 84 79 167 3 40 142 177 193 128 173 192 100 163 16 127 145 182 97 17 193 120 115 32 108 18 96 154 103 152 150 86 181 15 99 135 179 124 194 164 68 160 43 109 138 152 142 6 21 23 149 20 11 82 164 44 159 148 133 115 24 28 53 104 9 183 179 108 56 39 84 87 30 163 32 70 75 166 170 8 139 9 175 99 143 64 89 186 114 183 133 85 161 63 61 154 111 15 115 78 109 108 72 177 14 71 103 176 173 176 157 38 10 54 132 41 186 130 126 63 69 39 76 7 65 171 82 172 102 124 140 83 113 ^'}},
+ {OUT=>'905F43940B3591CE39D1145ACB1ECA80AB5E43CD'}],
+ ['167', {IN=> {f=> '396 1 189 70 83 29 132 67 115 145 151 170 181 14 192 2 187 40 5 33 160 48 183 91 132 83 112 177 62 189 153 128 91 49 38 50 55 24 8 8 51 36 13 175 28 36 56 160 12 107 168 25 104 157 156 139 165 14 30 192 164 195 56 41 180 159 28 79 41 144 167 51 115 188 136 154 145 65 2 22 93 83 191 147 23 110 57 137 131 66 138 26 78 146 125 159 150 34 177 22 129 68 168 111 74 118 77 50 174 54 47 87 140 20 178 158 133 60 33 45 93 47 8 170 59 52 56 124 20 16 150 117 24 84 46 106 151 51 158 173 113 111 196 73 15 133 136 71 100 10 85 182 110 143 114 92 185 42 42 118 156 20 135 173 156 96 180 37 73 134 156 182 150 196 192 45 172 17 167 91 168 68 89 134 120 190 173 34 141 37 152 111 117 103 61 7 34 62 67 191 190 8 87 21 195 139 86 44 76 66 55 186 23 31 87 183 5 155 122 191 68 53 149 136 35 115 26 121 131 102 123 3 42 197 133 179 56 84 165 136 190 130 49 157 80 101 103 97 197 11 19 118 1 5 119 137 9 104 193 141 116 122 72 38 7 70 47 44 155 43 16 107 125 40 127 193 105 131 145 108 185 6 50 141 1 167 127 153 45 53 192 121 12 79 84 129 151 15 166 196 156 60 188 53 109 83 148 162 46 146 6 136 111 160 88 38 169 85 63 87 97 35 194 3 82 52 13 132 43 59 92 109 4 178 3 118 37 195 96 94 60 112 15 47 166 110 179 99 69 149 100 43 138 69 70 123 89 12 158 54 90 72 117 182 31 166 153 164 76 33 2 101 63 44 112 58 39 143 74 32 107 89 55 143 31 47 123 125 4 135 18 141 80 137 88 81 154 187 ^'}},
+ {OUT=>'336C79FBD82F33E490C577E3F791C3CBFE842AFF'}],
+ ['168', {IN=> {f=> '406 0 23 134 103 49 99 44 64 160 68 190 114 105 91 86 22 27 15 74 8 22 151 79 199 84 85 90 128 9 5 175 129 17 40 59 125 187 194 144 151 3 60 6 158 153 67 58 18 99 19 53 129 90 179 134 52 124 55 95 138 82 170 167 69 122 13 108 160 119 115 161 51 14 167 120 47 60 57 86 16 184 96 197 42 98 112 165 154 199 157 21 168 52 146 66 126 119 93 150 20 36 153 140 194 93 26 156 114 80 80 55 44 13 35 24 44 191 24 190 63 177 44 140 99 146 117 54 163 42 76 101 134 176 185 177 168 1 21 19 180 193 12 52 197 191 173 65 19 31 118 59 1 123 72 71 88 64 11 193 37 63 28 169 184 45 72 195 152 186 87 56 176 112 41 93 77 84 158 29 3 136 142 36 80 4 119 166 86 98 163 93 1 145 83 102 66 75 191 46 4 94 155 55 120 149 113 148 181 49 175 180 142 87 5 51 65 92 167 196 186 138 184 23 61 164 171 175 107 6 9 81 114 7 141 177 117 76 174 73 54 112 114 29 152 11 98 87 154 123 21 146 41 115 88 115 139 40 183 189 109 67 7 90 52 73 127 51 192 156 89 69 49 77 33 33 182 57 10 64 138 57 159 136 91 111 33 58 193 88 188 75 118 110 126 170 18 197 169 162 34 41 17 138 6 34 92 145 185 155 157 170 43 8 140 48 21 70 105 40 161 178 78 89 196 110 199 106 96 121 106 23 185 28 96 48 167 145 58 91 35 97 180 66 151 130 124 128 34 16 6 107 28 20 112 92 18 121 30 84 107 101 159 187 19 155 182 181 74 186 11 120 98 185 104 32 126 94 82 119 42 25 173 90 30 62 96 70 178 176 39 102 15 150 147 100 78 16 57 35 75 169 35 170 116 144 75 146 ^'}},
+ {OUT=>'5C6D07A6B44F7A75A64F6CE592F3BAE91E022210'}],
+ ['169', {IN=> {f=> '409 1 185 70 12 95 110 71 133 183 52 136 148 144 114 186 17 25 144 164 5 79 178 172 124 117 19 43 20 93 174 36 125 117 151 109 3 164 55 101 37 122 152 77 131 168 88 162 161 93 142 14 63 167 141 149 94 39 190 50 68 47 135 198 16 110 153 177 104 173 192 68 147 179 119 137 166 73 180 169 88 91 24 76 10 80 146 79 128 150 62 149 194 83 111 171 124 170 156 60 152 27 109 106 120 134 201 184 202 149 12 198 66 132 12 127 132 133 83 8 12 45 88 9 183 155 92 24 23 76 63 14 163 8 62 67 150 162 8 115 1 167 91 127 32 89 162 90 159 125 85 129 47 53 154 95 7 115 54 101 108 56 169 6 47 103 176 157 160 125 14 10 30 124 17 178 122 102 55 69 15 60 202 49 171 74 148 94 92 124 67 200 184 70 83 29 127 67 100 140 131 165 176 4 182 2 167 20 193 33 160 43 173 71 112 68 97 157 57 169 138 113 86 44 38 40 55 19 196 201 31 21 8 165 23 26 41 155 195 183 102 158 25 94 142 146 129 150 9 30 177 154 195 51 36 175 139 28 59 31 124 167 41 105 173 121 134 130 65 185 17 78 78 181 137 13 95 57 137 116 51 118 16 78 131 115 154 145 29 177 22 129 68 168 91 74 98 72 30 174 39 37 72 130 15 163 158 128 50 18 25 73 27 191 150 59 52 36 104 20 11 130 97 4 79 46 106 141 46 138 163 108 106 191 68 15 113 136 66 100 193 65 182 105 123 99 72 180 37 22 108 156 10 130 168 141 96 160 22 58 134 151 162 140 181 187 35 157 7 147 76 163 58 84 129 100 190 153 24 126 32 142 96 107 88 41 2 14 42 52 186 170 3 82 11 180 119 66 29 56 66 50 171 3 11 77 163 5 150 112 128 ^'}},
+ {OUT=>'7E0D3E9D33127F4A30EB8D9C134A58409FA8695B'}],
+ ['170', {IN=> {f=> '413 1 47 25 135 129 7 108 19 107 117 102 102 3 28 190 112 165 56 63 165 122 183 116 28 157 52 73 89 90 169 202 12 111 185 203 91 116 200 97 193 134 116 122 44 31 7 63 26 37 134 22 2 93 125 33 99 186 77 124 131 94 171 183 50 113 178 146 127 153 45 32 164 121 203 58 56 108 130 192 166 168 128 39 188 53 102 69 148 141 18 139 197 108 97 132 74 24 155 71 63 59 97 21 194 180 61 45 204 132 29 31 85 88 188 164 187 118 37 167 82 94 60 98 1 47 152 110 172 85 55 128 72 43 117 41 42 116 61 12 144 40 62 58 117 168 17 159 139 164 76 5 193 101 56 30 105 30 11 143 60 32 86 68 41 136 31 40 123 118 181 135 195 127 59 130 81 53 147 62 13 124 98 34 79 39 49 145 53 180 94 105 91 71 2 27 5 54 193 7 141 79 199 84 75 70 128 199 195 160 119 17 20 54 115 187 184 129 146 193 40 201 143 138 57 43 18 94 204 38 114 80 179 114 47 119 50 80 118 82 160 152 49 112 198 88 155 104 95 151 36 199 162 100 27 50 47 86 195 16 179 81 192 27 83 107 150 134 194 147 1 158 32 131 61 111 119 83 140 5 21 133 120 174 78 26 136 109 65 80 40 29 203 25 24 44 191 14 170 43 162 34 140 99 141 112 54 148 42 71 96 119 161 165 167 148 186 11 4 180 188 197 42 182 181 168 50 14 26 103 49 1 113 67 61 78 59 196 173 32 53 8 154 169 30 72 175 152 176 87 36 166 102 36 88 77 79 138 24 188 131 127 26 70 194 114 146 66 93 158 93 191 125 78 92 51 60 176 26 4 74 135 35 120 129 113 133 181 29 170 170 137 77 190 46 45 77 157 191 186 138 184 18 61 144 151 175 107 6 194 81 114 2 126 110 ^'}},
+ {OUT=>'9A5F50DFCFB19286206C229019F0ABF25283028C'}],
+ ['171', {IN=> {f=> '427 1 85 60 150 73 38 88 90 5 128 11 98 55 130 91 13 146 9 91 88 107 139 16 159 189 93 35 191 66 28 65 95 51 184 148 57 45 49 61 25 9 166 49 194 64 130 33 143 112 67 111 1 58 177 80 164 59 110 94 118 170 194 197 169 154 10 41 193 114 190 26 92 145 177 155 125 146 35 200 124 48 21 46 89 40 153 178 62 65 196 86 175 90 80 89 98 23 169 4 88 32 135 137 26 75 11 81 172 34 151 130 108 104 34 200 182 83 12 196 112 84 202 97 206 60 75 69 159 163 19 131 174 157 66 178 195 104 66 161 104 8 126 70 66 103 26 17 141 90 22 54 64 38 146 168 39 70 199 142 147 92 70 8 25 35 75 161 3 138 92 128 43 59 185 55 205 95 100 71 123 173 42 126 128 144 94 176 205 20 139 149 198 59 168 172 109 112 9 33 10 73 154 36 115 97 131 99 196 144 45 81 22 112 142 72 131 148 83 162 161 78 142 14 53 157 141 139 74 29 180 35 58 27 115 198 1 90 138 167 89 173 192 48 137 159 114 132 156 58 160 154 68 76 19 56 5 70 141 64 113 150 47 129 184 73 96 166 124 155 151 55 147 17 109 86 100 129 201 164 192 149 7 193 56 112 200 107 122 133 63 206 2 40 78 9 183 140 82 4 13 71 48 4 163 201 57 62 140 157 8 100 204 162 86 117 12 89 147 75 144 120 85 109 37 48 154 85 2 115 39 96 108 46 164 1 32 103 176 147 150 105 207 10 15 119 2 173 117 87 50 69 50 202 39 171 69 133 89 72 114 57 195 179 70 83 29 122 67 85 135 111 160 171 202 172 2 147 183 33 160 38 163 51 92 53 82 137 52 149 123 98 81 39 38 30 55 14 186 196 11 6 3 155 18 16 26 150 180 168 97 148 25 84 127 136 119 135 4 30 162 144 195 46 31 170 119 28 190 ^'}},
+ {OUT=>'DCA737E269F9D8626D488988C996E06B352C0708'}],
+ ['172', {IN=> {f=> '443 1 17 96 167 27 91 152 100 106 109 65 164 10 57 71 167 123 209 74 57 137 95 30 90 2 78 110 101 147 138 22 177 22 129 68 168 63 74 70 65 2 174 18 23 51 116 8 142 158 121 36 207 207 45 209 170 122 59 52 8 76 20 4 102 69 186 72 46 106 127 39 110 149 101 99 184 61 15 85 136 59 100 172 37 182 98 95 78 44 173 30 204 94 156 206 123 161 120 96 132 1 37 134 144 134 126 160 180 21 136 203 119 55 156 44 77 122 72 190 125 10 105 25 128 75 93 67 13 205 196 14 31 179 142 206 75 207 159 91 38 8 28 66 43 150 185 193 63 135 5 143 98 143 32 5 125 124 197 103 14 97 107 102 87 3 18 185 97 155 56 48 165 112 178 106 13 157 32 53 79 85 149 197 7 106 175 203 71 101 195 92 193 129 116 122 24 26 7 58 11 32 119 7 202 83 125 28 79 181 57 119 121 84 161 168 50 93 163 131 127 153 45 17 144 121 198 43 36 93 115 177 166 148 108 24 188 53 97 59 148 126 208 134 192 88 87 112 64 14 145 61 63 39 97 11 194 165 46 40 199 132 19 11 80 73 178 154 177 118 37 147 72 94 60 88 201 47 142 110 167 75 45 113 52 43 102 21 22 111 41 12 134 30 42 48 117 158 7 154 129 164 76 195 188 101 51 20 100 10 201 143 50 32 71 53 31 131 31 35 123 113 166 135 180 117 44 125 76 33 142 62 3 114 93 19 59 34 34 130 38 170 74 105 91 56 192 27 205 34 178 202 131 79 199 84 65 50 128 189 185 145 109 17 49 105 187 174 114 141 183 20 196 128 123 47 28 18 89 189 23 99 70 179 94 42 114 45 65 98 82 150 137 29 102 183 68 150 89 75 141 21 184 157 80 7 40 37 86 190 16 174 66 187 12 68 102 135 114 189 137 191 148 12 116 56 96 119 73 130 200 6 113 100 154 63 26 116 104 50 80 25 14 193 83 ^'}},
+ {OUT=>'B8FFC1D4972FCE63241E0E77850AC46DDE75DBFA'}],
+ ['173', {IN=> {f=> '436 1 24 44 191 211 138 11 138 18 140 99 133 104 54 124 42 63 88 95 137 133 151 116 162 208 193 180 180 173 26 158 165 160 26 6 18 79 33 1 97 59 45 62 51 172 141 24 37 189 130 145 6 72 143 152 160 87 4 150 86 28 80 77 71 106 16 164 123 103 10 54 178 106 114 34 85 150 93 175 93 70 76 27 36 152 207 4 42 103 3 120 97 113 109 181 210 162 154 129 61 166 38 13 53 141 183 186 138 184 10 61 112 119 175 107 6 170 81 114 207 102 125 65 50 135 73 28 73 75 203 113 11 98 35 115 71 8 146 202 76 88 102 139 1 144 189 83 15 181 51 13 60 75 51 179 143 37 30 49 51 20 207 156 44 184 64 125 18 133 97 52 111 194 58 167 75 149 49 105 84 113 170 179 197 169 149 208 41 178 99 180 21 92 145 172 155 105 131 30 208 200 114 48 21 31 79 40 148 178 52 50 196 71 160 80 70 69 93 23 159 202 83 22 115 132 6 65 209 71 167 14 151 130 98 89 34 190 167 68 2 181 112 79 192 82 191 45 55 49 159 148 19 116 169 142 61 173 185 94 46 146 104 206 126 55 56 93 16 12 121 90 17 49 44 18 126 163 39 50 189 137 147 87 65 3 5 35 75 156 196 118 77 118 23 54 185 40 195 95 90 71 113 163 32 116 108 144 74 166 190 15 134 134 188 39 158 172 94 107 212 23 53 134 36 105 77 111 89 186 124 35 61 7 102 132 67 131 128 78 162 161 63 142 14 43 147 141 129 54 19 170 20 48 7 95 198 199 70 123 157 74 173 192 28 127 139 109 127 146 43 140 139 48 61 14 36 60 136 49 98 150 32 109 174 63 81 161 124 140 146 50 142 7 109 66 80 124 201 144 182 149 2 188 46 92 185 87 112 133 43 201 205 35 68 9 183 125 72 197 3 66 33 207 163 191 52 57 130 152 8 85 204 157 81 107 205 187 ^'}},
+ {OUT=>'E9C9BF41C8549354151B977003CE1D830BE667DB'}],
+ ['174', {IN=> {f=> '462 1 126 54 123 113 85 81 23 41 154 71 210 115 18 89 108 32 157 209 11 103 176 133 136 77 193 10 209 112 196 166 110 66 43 69 194 36 202 25 171 62 112 82 44 100 43 188 172 70 83 29 115 67 64 128 83 153 164 195 158 2 119 187 169 33 160 31 149 23 64 32 61 109 45 121 102 77 74 32 38 16 55 7 172 189 198 200 211 141 11 2 5 143 159 147 90 134 25 70 106 122 105 114 212 30 141 130 195 39 24 163 91 28 11 7 76 167 17 81 137 85 86 94 65 149 5 42 66 157 113 204 59 57 137 80 15 70 207 78 95 91 142 133 17 177 22 129 68 168 43 74 50 60 197 174 3 13 36 106 3 127 158 116 26 197 192 25 194 155 102 59 52 203 56 20 214 82 49 171 67 46 106 117 34 90 139 96 94 179 56 15 65 136 54 100 157 17 182 93 75 63 24 168 25 189 84 156 201 118 156 105 96 112 201 22 134 139 114 116 145 175 11 121 198 99 40 151 34 72 117 52 190 105 90 20 118 60 83 52 208 205 181 209 16 174 122 206 70 202 144 71 18 208 8 66 38 135 170 178 53 115 5 138 88 123 17 200 115 119 182 98 9 87 97 102 72 3 8 180 82 145 56 33 165 102 173 96 213 157 12 33 69 80 129 192 2 101 165 203 51 86 190 87 193 124 116 122 4 21 7 53 211 27 104 207 197 73 125 23 59 176 37 114 111 74 151 153 50 73 148 116 127 153 45 2 124 121 193 28 16 78 100 162 166 128 88 9 188 53 92 49 148 111 193 129 187 68 77 92 54 4 135 51 63 19 97 1 194 150 31 35 194 132 9 206 75 58 168 144 167 118 37 127 62 94 60 78 196 47 132 110 162 65 35 98 32 43 87 1 2 106 21 12 124 20 22 38 117 148 212 149 119 164 76 180 183 101 46 10 95 205 186 143 40 32 56 38 21 126 31 30 123 108 151 135 165 107 29 120 71 13 137 62 208 104 88 4 39 29 19 115 23 160 54 105 91 41 177 27 200 14 163 124 ^'}},
+ {OUT=>'0942908960B54F96CB43452E583F4F9CB66E398A'}],
+ ['175', {IN=> {f=> '453 0 115 79 199 84 49 18 128 173 169 121 93 17 186 41 89 187 158 90 133 167 206 188 104 99 31 4 18 81 165 217 75 54 179 62 34 106 37 41 66 82 134 113 215 86 159 36 142 65 43 125 215 160 149 48 193 24 21 86 182 16 166 42 179 206 44 94 111 82 181 121 167 132 198 92 48 72 119 57 114 184 200 81 68 122 39 26 84 96 26 80 1 208 177 217 24 44 191 206 118 209 123 8 140 99 128 99 54 109 42 58 83 80 122 113 141 96 147 203 183 180 175 158 16 143 155 155 11 1 13 64 23 1 87 54 35 52 46 157 121 19 27 174 115 130 209 72 123 152 150 87 202 140 76 23 75 77 66 86 11 149 118 88 44 168 101 94 14 80 145 93 165 73 65 66 12 21 137 192 4 22 83 201 120 77 113 94 181 195 157 144 124 51 151 33 211 38 131 178 186 138 184 5 61 92 99 175 107 6 155 81 114 207 87 105 45 40 120 73 18 58 60 193 98 11 98 15 100 51 3 146 187 61 88 97 139 204 129 189 73 213 171 36 216 55 55 51 174 138 17 15 49 41 15 197 146 39 174 64 120 3 123 82 37 111 179 58 157 70 134 39 100 74 108 170 164 197 169 144 198 41 163 84 170 16 92 145 167 155 85 116 25 208 200 104 48 21 16 69 40 143 178 42 35 196 56 145 70 60 49 88 23 149 192 78 12 95 127 204 55 199 61 162 212 151 130 88 74 34 180 152 53 210 166 112 74 182 67 176 30 35 29 159 133 19 101 164 127 56 168 175 84 26 131 104 196 126 40 46 83 6 7 101 90 12 44 24 216 106 158 39 30 179 132 147 82 60 216 203 35 75 151 181 98 62 108 3 49 185 25 185 95 80 71 103 153 22 106 88 144 54 156 175 10 129 119 178 19 148 172 79 102 207 13 208 33 114 36 95 57 91 79 176 104 25 41 210 92 122 62 131 108 73 162 161 48 142 14 33 137 141 119 34 9 160 5 38 205 75 198 189 50 108 112 ^'}},
+ {OUT=>'FCE34051C34D4B81B85DDC4B543CDE8007E284B3'}],
+ ['176', {IN=> {f=> '454 1 53 173 192 113 111 102 120 132 22 112 118 20 40 7 8 213 46 129 28 77 150 11 81 160 49 60 154 124 119 139 43 135 213 109 38 52 117 201 116 168 149 215 181 32 64 164 59 98 133 15 194 198 28 54 9 183 104 58 176 209 59 12 200 163 177 45 50 116 145 8 64 204 150 74 93 184 89 111 39 108 108 85 61 13 36 154 61 210 115 3 84 108 22 152 209 216 103 176 123 126 57 183 10 199 107 186 161 105 51 38 69 184 26 202 15 171 57 97 77 24 90 33 183 167 70 83 29 110 67 49 123 63 148 159 190 148 2 99 172 159 33 160 26 139 3 44 17 46 89 40 101 87 62 69 27 38 6 55 2 162 184 183 190 211 131 6 212 210 138 144 132 85 124 25 60 91 112 95 99 212 30 126 120 195 34 19 158 71 28 211 217 56 167 7 71 122 70 66 79 65 134 27 61 147 103 199 44 57 137 65 50 202 78 80 81 137 128 12 177 22 129 68 168 23 74 30 55 182 174 208 3 21 96 218 112 158 111 16 187 177 5 179 140 82 59 52 188 36 20 214 62 29 156 62 46 106 107 29 70 129 91 89 174 51 15 45 136 49 100 142 217 182 88 55 48 4 163 20 174 74 156 196 113 151 90 96 92 191 7 134 134 94 106 130 170 1 106 193 79 25 146 24 67 112 32 190 85 210 75 15 108 45 73 37 193 205 166 194 1 169 102 206 65 197 129 51 218 198 208 66 33 120 155 163 43 95 5 133 78 103 2 185 105 114 167 93 4 77 87 102 57 3 218 175 67 135 56 18 165 92 168 86 203 157 212 13 59 75 109 187 217 96 155 203 31 71 185 82 193 119 116 122 204 16 7 48 201 22 89 197 192 63 125 18 39 171 17 109 101 64 141 138 50 53 133 101 127 153 45 207 104 121 188 13 216 63 85 147 166 108 68 214 188 53 87 39 148 96 178 124 182 48 67 72 44 214 125 41 63 219 97 211 194 135 16 30 189 132 219 191 70 43 158 181 ^'}},
+ {OUT=>'61E8916532503627F4024D13884640A46F1D61D4'}],
+ ['177', {IN=> {f=> '475 0 153 118 37 99 48 94 60 64 189 47 118 110 155 51 21 77 4 43 66 195 196 99 215 12 110 6 216 24 117 134 205 142 105 164 76 159 176 101 39 218 88 184 165 143 26 32 35 17 7 119 31 23 123 101 130 135 144 93 8 113 64 207 130 62 201 90 81 205 11 22 220 94 2 146 26 105 91 20 156 27 193 208 142 178 107 79 199 84 41 2 128 165 161 109 85 17 174 37 81 187 150 78 129 159 194 184 92 87 23 214 18 77 153 209 63 46 179 46 30 102 33 29 50 82 126 101 203 78 147 20 138 53 27 117 207 148 145 32 181 16 13 86 178 16 162 30 175 198 32 90 99 66 177 113 155 124 186 80 44 60 119 49 106 176 192 65 52 106 27 26 68 92 14 80 211 200 169 213 24 44 191 202 102 197 111 140 99 124 95 54 97 42 54 79 68 110 97 133 80 135 199 175 180 171 146 8 131 147 151 221 219 9 52 15 1 79 50 27 44 42 145 105 15 19 162 103 118 201 72 107 152 142 87 190 132 68 19 71 77 62 70 7 137 114 76 214 36 160 97 78 220 76 141 93 157 57 61 58 9 125 180 4 6 67 189 120 61 113 82 181 183 153 136 120 43 139 29 199 26 123 174 186 138 184 1 61 76 83 175 107 6 143 81 114 207 75 89 29 32 108 73 10 46 48 185 86 11 98 221 88 35 221 146 175 49 88 93 139 196 117 189 65 201 163 24 208 51 39 51 170 134 1 3 49 33 11 189 138 35 166 64 116 213 115 70 25 111 167 58 149 66 122 31 96 66 104 170 152 197 169 140 190 41 151 72 162 12 92 145 163 155 69 104 21 208 200 96 48 21 4 61 40 139 178 34 23 196 44 133 62 52 33 84 23 141 184 74 4 79 123 192 47 191 53 158 200 151 130 80 62 34 172 140 41 206 154 112 70 174 55 164 18 19 13 159 121 19 89 160 115 52 164 167 76 10 119 104 188 126 28 38 75 220 3 85 90 8 40 8 204 90 154 39 14 171 128 147 78 56 216 191 35 75 147 169 82 50 100 209 45 185 13 177 95 150 ^'}},
+ {OUT=>'F008D5D7853B6A17B7466CD9E18BD135E520FAF4'}],
+ ['178', {IN=> {f=> '471 0 71 89 139 8 92 60 144 26 142 154 3 122 98 164 216 134 172 58 95 200 224 201 5 86 36 81 29 63 65 162 76 11 13 196 78 108 55 131 80 66 162 161 27 142 14 19 123 141 105 6 220 146 209 24 184 47 198 175 22 87 133 38 173 192 205 103 91 97 115 122 7 92 103 25 2 213 213 36 124 13 62 150 221 61 150 39 45 149 124 104 134 38 130 208 109 18 32 112 201 96 158 149 215 176 22 44 149 39 88 133 220 189 193 23 44 9 183 89 48 161 204 54 222 195 163 167 40 45 106 140 8 49 204 145 69 83 169 89 96 24 93 103 85 41 3 31 154 51 210 115 213 79 108 12 147 209 206 103 176 113 116 37 173 10 189 102 176 156 100 36 33 69 174 16 202 5 171 52 82 72 4 80 23 178 162 70 83 29 105 67 34 118 43 143 154 185 138 2 79 157 149 33 160 21 129 208 24 2 31 69 35 81 72 47 64 22 38 221 55 222 152 179 168 180 211 121 1 207 200 133 129 117 80 114 25 50 76 102 85 84 212 30 111 110 195 29 14 153 51 28 196 212 36 167 222 61 107 55 46 64 65 119 220 12 56 137 93 194 29 57 137 50 210 30 197 78 65 71 132 123 7 177 22 129 68 168 3 74 10 50 167 174 198 218 6 86 218 97 158 106 6 177 162 210 164 125 62 59 52 173 16 20 214 42 9 141 57 46 106 97 24 50 119 86 84 169 46 15 25 136 44 100 127 202 182 83 35 33 209 158 15 159 64 156 191 108 146 75 96 72 181 217 134 129 74 96 115 165 216 91 188 59 10 141 14 62 107 12 190 65 205 60 10 98 30 63 22 178 205 151 179 211 164 82 206 60 192 114 31 203 188 193 66 28 105 140 148 33 75 5 128 68 83 212 170 95 109 152 88 224 67 77 102 42 3 213 170 52 125 56 3 165 82 163 76 193 157 197 218 49 70 89 182 217 91 145 203 11 56 180 77 193 114 116 122 189 11 7 43 191 17 74 187 187 53 125 13 19 166 222 104 91 54 131 123 50 33 118 86 127 167 ^'}},
+ {OUT=>'BD8D2E873CF659B5C77AAC1616827EF8A3B1A3B3'}],
+ ['179', {IN=> {f=> '480 1 45 193 76 121 181 219 195 42 64 126 166 80 40 200 188 53 80 25 148 75 157 117 175 20 53 44 30 207 111 27 63 198 97 204 194 114 222 23 182 132 212 170 63 22 144 120 143 118 37 79 38 94 60 54 184 47 108 110 150 41 11 62 211 43 51 180 181 94 200 12 100 223 201 14 117 124 200 137 95 164 76 144 171 101 34 213 83 169 150 143 16 32 20 2 224 114 31 18 123 96 115 135 129 83 220 108 59 192 125 62 196 80 76 195 218 17 210 79 214 136 6 105 91 5 141 27 188 193 127 168 97 79 199 84 31 209 128 155 151 94 75 17 159 32 71 187 140 63 124 149 179 179 77 72 13 204 18 72 138 199 48 36 179 26 25 97 28 14 30 82 116 86 188 68 132 133 38 7 107 197 133 140 12 166 6 3 86 173 16 157 15 170 188 17 85 84 46 172 103 140 114 171 65 39 45 119 39 96 166 182 45 32 86 12 26 48 87 226 80 201 190 159 208 24 44 191 197 82 182 96 217 140 99 119 90 54 82 42 49 74 53 95 77 123 60 120 194 165 180 166 131 225 116 137 146 211 219 4 37 5 1 69 45 17 34 37 130 85 10 9 147 88 103 191 72 87 152 132 87 175 122 58 14 66 77 57 50 2 122 109 61 209 26 150 92 58 205 71 136 93 147 37 56 48 212 221 110 165 4 213 47 174 120 41 113 67 181 168 148 126 115 33 124 24 184 11 113 169 186 138 184 223 61 56 63 175 107 6 128 81 114 207 60 69 9 22 93 73 31 33 175 71 11 98 206 73 15 221 146 160 34 88 88 139 186 102 189 55 186 153 9 198 46 19 51 165 129 208 215 49 23 6 179 128 30 156 64 111 203 105 55 10 111 152 58 139 61 107 21 91 56 99 170 137 197 169 135 180 41 136 57 152 7 92 145 158 155 49 89 16 208 200 86 48 21 216 51 40 134 178 24 8 196 29 118 52 42 13 79 23 131 174 69 221 59 118 177 37 181 43 153 185 151 130 70 47 34 162 125 26 201 139 112 65 164 40 149 3 226 220 159 106 19 74 155 100 47 159 157 193 ^'}},
+ {OUT=>'B25A04DD425302ED211A1C2412D2410FA10C63B6'}],
+ ['180', {IN=> {f=> '471 0 211 98 104 174 126 7 24 61 213 225 57 90 1 33 209 183 62 147 39 215 157 121 147 71 49 216 170 35 75 140 148 54 29 86 188 38 185 221 163 95 58 71 81 131 84 44 144 10 134 142 228 118 86 156 204 126 172 46 91 196 220 197 218 70 36 73 13 47 57 154 60 3 226 188 70 100 51 131 64 62 162 161 15 142 14 11 115 141 97 219 216 138 201 16 172 31 198 167 6 75 125 26 173 192 193 95 75 93 111 114 224 76 91 213 13 227 201 213 28 120 1 50 150 213 45 142 31 33 145 124 92 130 34 126 204 109 2 16 108 201 80 150 149 215 172 14 28 137 23 80 133 208 185 189 19 36 9 183 77 40 149 200 50 214 191 163 159 36 41 98 136 8 37 204 141 65 75 157 89 84 12 81 99 85 25 224 27 154 43 210 115 205 75 108 4 143 209 198 103 176 105 108 21 165 10 181 98 168 152 96 24 29 69 166 8 202 226 171 48 70 68 217 72 15 174 158 70 83 29 101 67 22 114 27 139 150 181 130 2 63 145 141 33 160 17 121 196 8 219 19 53 31 65 60 35 60 18 38 217 55 222 144 175 156 172 211 113 226 203 192 129 117 105 76 106 25 42 64 94 77 72 212 30 99 102 195 25 10 149 35 28 184 208 20 167 218 53 95 43 30 52 65 107 220 52 129 85 190 17 57 137 38 202 14 193 78 53 63 128 119 3 177 22 129 68 168 216 74 223 46 155 174 190 214 223 78 218 85 158 102 227 169 150 198 152 113 46 59 52 161 20 214 26 222 129 53 46 106 89 20 34 111 82 80 165 42 15 9 136 40 100 115 190 182 79 19 21 197 154 11 147 56 156 187 104 142 63 96 56 173 209 134 125 58 88 103 161 212 79 184 43 227 137 6 58 103 225 190 49 201 48 6 90 18 55 10 166 205 139 167 203 160 66 206 56 188 102 15 191 180 181 66 24 93 128 136 25 59 5 124 60 67 204 158 87 105 140 84 224 59 69 102 30 3 209 166 40 117 56 220 165 74 159 68 185 157 185 206 41 66 167 ^'}},
+ {OUT=>'A404E21588123E0893718B4B44E91414A785B91F'}],
+ ['181', {IN=> {f=> '490 1 176 217 85 133 203 218 38 174 71 193 108 116 122 171 5 7 37 179 11 56 175 181 41 125 7 226 160 204 98 79 42 119 105 50 9 100 68 127 153 45 185 60 121 177 211 183 30 52 114 166 64 24 192 188 53 76 17 148 63 145 113 171 4 45 28 22 203 103 19 63 186 97 200 194 102 214 19 178 132 208 158 59 10 136 112 135 118 37 63 30 94 60 46 180 47 100 110 146 33 3 50 199 43 39 168 169 90 188 12 92 219 189 6 117 116 196 133 87 164 76 132 167 101 30 209 79 157 138 143 8 32 8 221 220 110 31 14 123 92 103 135 117 75 212 104 55 180 121 62 192 72 72 187 206 13 202 67 206 128 221 105 91 224 129 27 184 181 115 160 89 79 199 84 23 197 128 147 143 82 67 17 147 28 63 187 132 51 120 141 167 175 65 60 5 196 18 68 126 191 36 28 179 10 21 93 24 2 14 82 108 74 176 60 120 215 129 26 222 99 189 121 136 227 154 229 226 86 169 16 153 3 166 180 5 81 72 30 168 95 128 106 159 53 35 33 119 31 88 158 174 29 16 70 26 32 83 218 80 193 182 151 204 24 44 191 193 66 170 84 213 140 99 115 86 54 70 42 45 70 41 83 61 115 44 108 190 157 180 162 119 221 104 129 142 203 219 25 228 1 61 41 9 26 33 118 69 6 1 135 76 91 183 72 71 152 124 87 163 114 50 10 62 77 53 34 229 110 105 49 205 18 142 88 42 193 67 132 93 139 21 52 40 204 213 98 153 4 201 31 162 120 25 113 55 181 156 144 118 111 25 112 20 172 230 105 165 186 138 184 223 61 40 47 175 107 6 116 81 114 207 48 53 224 14 81 73 223 19 21 167 59 11 98 194 61 230 221 146 148 22 88 84 139 178 90 189 47 174 145 228 190 42 3 51 161 125 196 207 49 15 2 171 120 26 148 64 107 195 97 43 229 111 140 58 131 57 95 13 87 48 95 170 125 197 169 131 172 41 124 45 144 3 92 145 154 155 33 77 12 208 200 78 48 21 208 43 40 130 178 16 227 196 17 106 44 34 228 75 23 123 166 65 217 43 114 165 29 173 35 200 ^'}},
+ {OUT=>'A1E13BC55BF6DAD83CF3AABDA3287AD68681EA64'}],
+ ['182', {IN=> {f=> '479 0 167 151 130 58 29 34 150 107 8 195 121 112 59 152 22 131 218 208 202 159 88 19 56 149 82 41 153 145 54 199 86 104 166 126 228 16 53 209 225 41 90 230 29 197 171 46 143 39 203 149 117 147 67 45 216 158 35 75 136 136 38 17 78 176 34 185 213 155 95 50 71 73 123 225 76 28 144 227 126 130 228 114 74 148 192 118 172 34 87 192 216 193 206 54 36 65 230 31 49 146 44 228 214 180 62 92 47 131 48 58 162 161 3 142 14 3 107 141 89 207 212 130 193 8 160 15 198 159 223 63 117 14 173 192 181 87 59 89 107 106 216 60 79 201 1 227 189 213 20 116 222 38 150 205 29 134 23 21 141 124 80 126 30 122 200 109 219 104 201 64 142 149 215 168 6 12 125 7 72 133 196 181 185 15 28 9 183 65 32 137 196 46 206 187 163 151 32 37 90 132 8 25 204 137 61 67 145 89 72 69 95 85 9 220 23 154 35 210 115 197 71 108 229 139 209 190 103 176 97 100 5 157 10 173 94 160 148 92 12 25 69 158 202 222 171 44 58 64 205 64 7 170 154 70 83 29 97 67 10 110 11 135 146 177 122 2 47 133 133 33 160 13 113 184 225 211 7 37 27 49 48 23 56 14 38 213 55 222 136 171 144 164 211 105 226 199 184 125 105 93 72 98 25 34 52 86 69 60 212 30 87 94 195 21 6 145 19 28 172 204 4 167 214 45 83 31 14 40 65 95 220 221 48 121 77 186 5 57 137 26 194 231 189 78 41 55 124 115 232 177 22 129 68 168 204 74 211 42 143 174 182 210 215 70 218 73 158 98 223 161 138 186 140 101 30 59 52 149 217 20 214 10 210 117 49 46 106 81 16 18 103 78 76 161 38 15 226 136 36 100 103 178 182 75 3 9 185 150 7 135 48 156 183 100 138 51 96 40 165 201 134 121 42 80 91 157 208 67 180 27 219 133 231 54 99 213 190 33 197 36 2 82 6 47 231 154 205 127 155 195 156 50 206 52 184 90 232 179 172 169 66 20 81 116 124 17 43 5 120 52 51 196 146 79 101 128 80 224 65 ^'}},
+ {OUT=>'D5FD35FFABED6733C92365929DF0FB4CAE864D15'}],
+ ['183', {IN=> {f=> '503 1 55 102 9 3 202 159 19 103 56 206 165 60 152 54 171 157 164 185 27 59 45 171 217 80 123 203 203 23 169 66 193 103 116 122 156 7 32 169 6 41 165 176 31 125 2 211 155 189 93 69 32 109 90 50 225 85 53 127 153 45 175 40 121 172 201 168 15 37 99 166 44 4 182 188 53 71 7 148 48 130 108 166 220 35 8 12 198 93 9 63 171 97 195 194 87 204 14 173 132 203 143 54 231 126 102 125 118 37 43 20 94 60 36 175 47 90 110 141 23 229 35 184 43 24 153 154 85 173 12 82 214 174 232 117 106 191 128 77 164 76 117 162 101 25 204 74 142 123 143 234 32 229 211 215 105 31 9 123 87 88 135 102 65 202 99 50 165 116 62 187 62 67 177 191 8 192 52 196 118 206 105 91 214 114 27 179 166 100 150 79 79 199 84 13 182 128 137 133 67 57 17 132 23 53 187 122 36 115 131 152 170 50 45 231 186 18 63 111 181 21 18 179 226 16 88 19 223 230 82 98 59 161 50 105 200 124 11 207 89 179 106 131 212 139 224 221 86 164 16 148 224 161 170 226 76 57 10 163 85 113 96 144 38 30 18 119 21 78 148 164 9 232 50 221 26 12 78 208 80 183 172 141 199 24 44 191 188 46 155 69 208 140 99 110 81 54 55 42 40 65 26 68 41 105 24 93 185 147 180 157 104 216 89 119 137 193 219 231 10 223 1 51 36 235 16 28 103 49 1 227 120 61 76 173 72 51 152 114 87 148 104 40 5 57 77 48 14 229 95 100 34 200 8 132 83 22 178 62 127 93 129 1 47 30 194 203 83 138 4 186 11 147 120 5 113 40 181 141 139 108 106 15 97 15 157 220 95 160 186 138 184 223 61 20 27 175 107 6 101 81 114 207 33 33 209 4 66 73 218 4 6 157 44 11 98 179 46 215 221 146 133 7 88 79 139 168 75 189 37 159 135 218 180 37 219 51 156 120 181 197 49 5 233 161 110 21 138 64 102 185 87 28 219 111 125 58 121 52 80 3 82 38 90 170 110 197 169 126 162 41 109 30 134 234 92 145 149 155 13 62 7 208 200 68 48 21 198 33 40 125 178 6 217 196 2 91 34 24 213 70 23 113 161 ^'}},
+ {OUT=>'C12E9C280EE9C079E0506FF89F9B20536E0A83EF'}],
+ ['184', {IN=> {f=> '470 0 58 210 15 107 144 15 159 21 142 152 151 130 48 14 34 140 92 231 190 106 112 54 142 7 116 208 193 187 159 73 19 41 144 67 36 148 135 44 184 71 104 156 126 218 6 43 204 225 21 90 230 24 182 156 26 138 39 188 139 112 147 62 40 216 143 35 75 131 121 18 2 68 161 29 185 203 145 95 40 71 63 113 220 66 8 144 212 116 115 228 109 59 138 177 108 172 19 82 187 211 188 191 34 36 55 215 11 39 136 24 223 199 170 52 82 42 131 28 53 162 161 226 142 14 231 97 141 79 192 207 120 183 236 145 233 198 149 208 48 107 237 173 192 166 77 39 84 102 96 206 40 64 186 224 227 174 213 10 111 212 23 150 195 9 124 13 6 136 124 65 121 25 117 195 109 204 218 99 201 44 132 149 215 163 234 230 110 225 62 133 181 176 180 10 18 9 183 50 22 122 191 41 196 182 163 141 27 32 80 127 8 10 204 132 56 57 130 89 57 223 54 90 85 227 215 18 154 25 210 115 187 66 108 224 134 209 180 103 176 87 90 223 147 10 163 89 150 143 87 235 20 69 148 228 202 217 171 39 43 59 190 54 235 165 149 70 83 29 92 67 233 105 229 130 141 172 112 2 27 118 123 33 160 8 103 169 210 201 230 17 22 29 33 8 51 9 38 208 55 222 126 166 129 154 211 95 226 194 174 120 90 78 67 88 25 24 37 76 59 45 212 30 72 84 195 16 1 140 237 28 157 199 222 167 209 35 68 16 232 25 65 80 220 211 43 111 67 181 228 57 137 11 184 216 184 78 26 45 119 110 232 177 22 129 68 168 189 74 196 37 128 174 172 205 205 60 218 58 158 93 218 151 123 171 125 86 10 59 52 134 202 20 214 228 195 102 44 46 106 71 11 236 93 73 71 156 33 15 211 136 31 100 88 163 182 70 221 232 170 145 2 120 38 156 178 95 133 36 96 20 155 191 134 116 22 70 76 152 203 52 175 7 209 128 226 49 94 198 190 13 192 21 235 72 229 37 221 139 205 112 140 185 151 30 206 47 179 75 217 101 ^'}},
+ {OUT=>'E22769DC00748A9BBD6C05BBC8E81F2CD1DC4E2D'}],
+ ['185', {IN=> {f=> '502 0 158 148 66 13 60 95 103 3 15 5 113 38 23 182 125 65 94 107 73 224 37 47 102 237 3 198 155 7 95 56 198 165 52 148 46 163 157 152 173 19 55 29 167 217 76 115 203 191 11 165 62 193 99 116 122 144 236 7 28 161 2 29 157 172 23 125 238 199 151 177 89 61 24 101 78 50 213 73 41 127 153 45 167 24 121 168 193 156 3 25 87 166 28 228 174 188 53 67 239 148 36 118 104 162 208 27 232 4 194 85 1 63 159 97 191 194 75 196 10 169 132 199 131 50 223 118 94 117 118 37 27 12 94 60 28 171 47 82 110 137 15 225 23 172 43 12 141 142 81 161 12 74 210 162 228 117 98 187 124 69 164 76 105 158 101 21 200 70 130 111 143 230 32 221 203 211 101 31 5 123 83 76 135 90 57 194 95 46 153 112 62 183 54 63 169 179 4 184 40 188 110 194 105 91 206 102 27 175 154 88 142 71 79 199 84 5 170 128 129 125 55 49 17 120 19 45 187 114 24 111 123 140 166 38 33 227 178 18 59 99 173 9 10 179 214 12 84 15 215 218 82 90 47 149 42 93 188 120 239 195 81 171 94 127 200 127 220 217 86 160 16 144 216 157 162 218 72 45 234 159 77 101 88 132 26 26 6 119 13 70 140 156 233 220 34 213 26 236 74 200 80 175 164 133 195 24 44 191 184 30 143 57 204 140 99 106 77 54 43 42 36 61 14 56 25 97 8 81 181 139 180 153 92 212 77 111 133 185 219 231 238 219 1 43 32 231 8 24 91 33 237 223 108 49 64 165 72 35 152 106 87 136 96 32 1 53 77 44 238 229 83 96 22 196 124 79 6 166 58 123 93 121 225 43 22 186 195 71 126 4 174 235 135 120 229 113 28 181 129 135 100 102 7 85 11 145 212 87 156 186 138 184 223 61 4 11 175 107 6 89 81 114 207 21 17 197 236 54 73 214 232 234 149 32 11 98 167 34 203 221 146 121 235 88 75 139 160 63 189 29 147 127 210 172 33 207 51 152 116 169 189 49 237 233 153 102 17 130 64 98 177 79 16 211 111 113 58 113 48 68 235 78 30 86 170 98 197 169 122 154 41 97 18 126 234 92 145 145 155 237 50 209 ^'}},
+ {OUT=>'F29835A93475740E888E8C14318F3CA45A3C8606'}],
+ ['186', {IN=> {f=> '481 1 208 200 56 48 21 186 21 40 119 178 236 205 196 226 73 22 12 195 64 23 101 144 54 206 241 103 132 7 151 13 138 140 151 130 40 2 34 132 80 223 186 94 112 50 134 237 104 200 181 175 159 61 19 29 140 55 32 144 127 36 172 59 104 148 126 210 240 35 200 225 5 90 230 20 170 144 10 134 39 176 131 108 147 58 36 216 131 35 75 127 109 2 232 60 149 25 185 195 137 95 32 71 55 105 216 58 234 144 200 108 103 228 105 47 130 165 100 172 7 78 183 207 184 179 18 36 47 203 237 31 128 8 219 187 162 44 74 38 131 12 49 162 161 218 142 14 227 89 141 71 180 203 112 175 232 133 221 198 141 196 36 99 229 173 192 154 69 23 80 98 88 198 24 52 174 216 227 162 213 2 107 204 11 150 187 235 116 5 236 132 124 53 117 21 113 191 109 192 206 95 201 28 124 149 215 159 230 218 98 213 54 133 169 172 176 6 10 9 183 38 14 110 187 37 188 178 163 133 23 28 72 123 8 240 204 128 52 49 118 89 45 215 42 86 85 215 211 14 154 17 210 115 179 62 108 220 130 209 172 103 176 79 82 211 139 10 155 85 142 139 83 227 16 69 140 224 202 213 171 35 31 55 178 46 231 161 145 70 83 29 88 67 225 101 217 126 137 168 104 2 11 106 115 33 160 4 95 157 198 193 222 1 18 13 21 238 47 5 38 204 55 222 118 162 117 146 211 87 226 190 166 116 78 66 63 80 25 16 25 68 51 33 212 30 60 76 195 12 239 136 225 28 145 195 210 167 205 27 56 4 220 13 65 68 220 203 39 103 59 177 220 57 137 241 176 204 180 78 14 37 115 106 232 177 22 129 68 168 177 74 184 33 116 174 164 201 197 52 218 46 158 89 214 143 111 159 113 74 236 59 52 122 190 20 214 216 183 90 40 46 106 63 7 224 85 69 67 152 29 15 199 136 27 100 76 151 182 66 209 224 158 141 240 108 30 156 174 91 129 24 96 4 147 183 134 112 6 62 64 148 199 40 171 233 201 124 222 45 90 186 190 239 188 9 235 64 221 29 213 127 178 ^'}},
+ {OUT=>'1A1D77C6D0F97C4B620FAA90F3F8644408E4B13D'}],
+ ['187', {IN=> {f=> '508 1 94 122 173 145 6 206 41 173 57 199 146 150 136 66 9 48 83 91 239 243 5 109 30 7 174 113 57 90 95 69 224 29 39 102 229 3 194 151 239 87 56 190 165 44 144 38 155 157 140 161 11 51 13 163 217 72 107 203 179 243 161 58 193 95 116 122 132 236 7 24 153 242 17 149 168 15 125 238 187 147 165 85 53 16 93 66 50 201 61 29 127 153 45 159 8 121 164 185 144 235 13 75 166 12 216 166 188 53 63 235 148 24 106 100 158 196 19 220 240 190 77 237 63 147 97 187 194 63 188 6 165 132 195 119 46 215 110 86 109 118 37 11 4 94 60 20 167 47 74 110 133 7 221 11 160 43 129 130 77 149 12 66 206 150 224 117 90 183 120 61 164 76 93 154 101 17 196 66 118 99 143 226 32 213 195 207 97 31 1 123 79 64 135 78 49 186 91 42 141 108 62 179 46 59 161 167 176 28 180 102 182 105 91 198 90 27 171 142 76 134 63 79 199 84 241 158 128 121 117 43 41 17 108 15 37 187 106 12 107 115 128 162 26 21 223 170 18 55 87 165 241 2 179 202 8 80 11 207 206 82 82 35 137 34 81 176 116 231 183 73 163 82 123 188 115 216 213 86 156 16 140 208 153 154 210 68 33 222 155 69 89 80 120 14 22 238 119 5 62 132 148 221 208 18 205 26 224 70 192 80 167 156 125 191 24 44 191 180 14 131 45 200 140 99 102 73 54 31 42 32 57 2 44 9 89 236 69 177 131 180 149 80 208 65 103 129 177 219 231 230 215 1 35 28 227 20 79 17 237 219 96 37 52 157 72 19 152 98 87 124 88 24 241 49 77 40 226 229 71 92 10 192 236 116 75 234 154 54 119 93 113 213 39 14 178 187 59 114 4 162 223 123 120 217 113 16 181 117 131 92 98 243 73 7 133 204 79 152 186 138 184 223 61 232 239 175 107 6 77 81 114 207 9 1 185 232 42 73 210 224 226 141 20 11 98 155 22 191 221 146 109 227 88 71 139 152 51 189 21 135 119 202 164 29 195 51 148 112 157 181 49 233 233 145 94 13 122 64 94 169 71 4 203 111 101 58 105 44 56 231 74 22 82 170 86 197 169 118 146 41 85 6 118 234 92 145 141 149 ^'}},
+ {OUT=>'4EC84870E9BDD25F523C6DFB6EDD605052CA4EAA'}],
+ ['188', {IN=> {f=> '484 1 219 32 243 208 200 48 48 21 178 13 40 115 178 232 197 196 218 61 14 4 183 60 23 93 136 50 202 229 99 120 245 143 5 134 128 151 130 32 236 34 124 68 215 182 82 112 46 126 229 92 192 169 163 159 49 19 17 136 43 28 140 119 28 160 47 104 140 126 202 236 27 196 225 235 90 230 16 158 132 240 130 39 164 123 104 147 54 32 216 119 35 75 123 97 232 224 52 137 21 185 187 129 95 24 71 47 97 212 50 222 144 188 100 91 228 101 35 122 153 92 172 241 74 179 203 180 167 2 36 39 191 225 23 120 238 215 175 154 36 66 34 131 242 45 162 161 210 142 14 223 81 141 63 168 199 104 167 228 121 209 198 133 184 24 91 221 173 192 142 61 7 76 94 80 190 8 40 162 208 227 150 213 240 103 196 245 150 179 223 108 243 228 128 124 41 113 17 109 187 109 180 194 91 201 12 116 149 215 155 226 206 86 201 46 133 157 168 172 2 2 9 183 26 6 98 183 33 180 174 163 125 19 24 64 119 8 232 204 124 48 41 106 89 33 207 30 82 85 203 207 10 154 9 210 115 171 58 108 216 126 209 164 103 176 71 74 199 131 10 147 81 134 135 79 219 12 69 132 220 202 209 171 31 19 51 166 38 227 157 141 70 83 29 84 67 217 97 205 122 133 164 96 2 241 94 107 33 160 87 145 186 185 214 231 14 243 9 230 43 1 38 200 55 222 110 158 105 138 211 79 226 186 158 112 66 54 59 72 25 8 13 60 43 21 212 30 48 68 195 8 239 132 213 28 133 191 198 167 201 19 44 238 208 1 65 56 220 195 35 95 51 173 212 57 137 233 168 192 176 78 2 29 111 102 232 177 22 129 68 168 165 74 172 29 104 174 156 197 189 44 218 34 158 85 210 135 99 147 101 62 224 59 52 110 178 20 214 204 171 78 36 46 106 55 3 212 77 65 63 148 25 15 187 136 23 100 64 139 182 62 197 216 146 137 240 96 22 156 170 87 125 12 96 234 139 175 134 108 236 54 52 144 195 28 167 221 193 120 218 41 86 174 190 227 184 243 235 56 213 21 205 115 205 71 ^'}},
+ {OUT=>'D689513FED08B80C39B67371959BC4E3FECB0537'}],
+ ['189', {IN=> {f=> '506 0 110 165 141 238 206 37 169 45 187 134 142 124 66 5 36 71 79 235 231 5 105 22 239 166 101 49 86 83 65 224 21 31 102 221 3 190 147 231 79 56 182 165 36 140 30 147 157 128 149 3 47 245 159 217 68 99 203 167 235 157 54 193 91 116 122 120 236 7 20 145 242 5 141 164 7 125 238 175 143 153 81 45 8 85 54 50 189 49 17 127 153 45 151 240 121 160 177 132 227 1 63 166 244 204 158 188 53 59 231 148 12 94 96 154 184 11 208 236 186 69 233 63 135 97 183 194 51 180 2 161 132 191 107 42 207 102 78 101 118 37 243 244 94 60 12 163 47 66 110 129 247 217 247 148 43 236 117 118 73 137 12 58 202 138 220 117 82 179 116 53 164 76 81 150 101 13 192 62 106 87 143 222 32 205 187 203 93 31 245 123 75 52 135 66 41 178 87 38 129 104 62 175 38 55 153 155 244 168 16 172 94 170 105 91 190 78 27 167 130 64 126 55 79 199 84 237 146 128 113 109 31 33 17 96 11 29 187 98 103 107 116 158 14 9 219 162 18 51 75 157 233 242 179 190 4 76 7 199 194 82 74 23 125 26 69 164 112 223 171 65 155 70 119 176 103 212 209 86 152 16 136 200 149 146 202 64 21 210 151 61 77 72 108 2 18 230 119 245 54 124 140 209 196 2 197 26 212 66 184 80 159 148 117 187 24 44 191 176 246 119 33 196 140 99 98 69 54 19 42 28 53 238 32 241 81 224 57 173 123 180 145 68 204 53 95 125 169 219 231 222 211 1 27 24 223 240 16 67 1 237 215 84 25 40 149 72 3 152 90 87 112 80 16 241 45 77 36 214 229 59 88 246 188 232 108 71 222 142 50 115 93 105 201 35 6 170 179 47 102 4 150 211 111 120 205 113 4 181 105 127 84 94 239 61 3 121 196 71 148 186 138 184 223 61 220 227 175 107 6 65 81 114 207 245 233 173 228 30 73 206 216 218 133 8 11 98 143 10 179 221 146 97 219 88 67 139 144 39 189 13 123 111 194 156 25 183 51 144 108 145 173 49 229 233 137 86 9 114 64 90 161 63 240 195 111 89 58 97 40 44 227 70 14 78 170 74 197 169 114 138 41 73 242 110 234 177 ^'}},
+ {OUT=>'C4FED58F209FC3C34AD19F86A6DACADC86C04D33'}],
+ ['190', {IN=> {f=> '491 0 145 135 155 207 20 243 208 200 40 48 21 170 5 40 111 178 228 189 196 210 49 6 246 171 56 23 85 128 46 198 217 95 108 241 135 247 130 116 151 130 24 228 34 116 56 207 178 70 112 42 118 221 80 184 157 151 159 37 19 5 132 31 24 136 111 20 148 35 104 132 126 194 232 19 192 225 223 90 230 12 146 120 228 126 39 152 115 100 147 50 28 216 107 35 75 119 85 220 216 44 125 17 185 179 121 95 16 71 39 89 208 42 210 144 176 92 79 228 97 23 114 141 84 172 233 70 175 199 176 155 236 36 31 179 213 15 112 226 211 163 146 28 58 30 131 230 41 162 161 202 142 14 219 73 141 55 156 195 96 159 224 109 197 198 125 172 12 83 213 173 192 130 53 241 72 90 72 182 242 28 150 200 227 138 213 236 99 188 237 150 171 211 100 239 220 124 124 29 109 13 105 183 109 168 182 87 201 246 108 149 215 151 222 194 74 189 38 133 145 164 168 248 244 9 183 14 248 86 179 29 172 170 163 117 15 20 56 115 8 224 204 120 44 33 94 89 21 199 18 78 85 191 203 6 154 1 210 115 163 54 108 212 122 209 156 103 176 63 66 187 123 10 139 77 126 131 75 211 8 69 124 216 202 205 171 27 7 47 154 30 223 153 137 70 83 29 80 67 209 93 193 118 129 160 88 2 229 82 99 33 160 246 79 133 174 177 206 219 10 231 247 222 39 247 38 196 55 222 102 154 93 130 211 71 226 182 150 108 54 42 55 64 25 1 52 35 9 212 30 36 60 195 4 239 128 201 28 121 187 186 167 197 11 32 230 196 239 65 44 220 187 31 87 43 169 204 57 137 225 160 180 172 78 240 21 107 98 232 177 22 129 68 168 153 74 160 25 92 174 148 193 181 36 218 22 158 81 206 127 87 135 89 50 212 59 52 98 166 20 214 192 159 66 32 46 106 47 249 200 69 61 59 144 21 15 175 136 19 100 52 127 182 58 185 208 134 133 240 84 14 156 166 83 121 96 222 131 167 134 104 224 46 40 140 191 16 163 209 185 116 214 37 82 162 190 215 180 235 235 48 205 13 197 103 205 76 104 161 139 232 146 ^'}},
+ {OUT=>'051888C6D00029C176DE792B84DECE2DC1C74B00'}],
+ ['191', {IN=> {f=> '516 0 33 165 33 175 122 134 112 66 1 24 59 67 231 219 5 101 14 227 158 89 41 82 71 61 224 13 23 102 213 3 186 143 223 71 56 174 165 28 136 22 139 157 116 137 247 43 233 155 217 64 91 203 155 227 153 50 193 87 116 122 108 236 7 16 137 242 245 133 160 251 125 238 163 139 141 77 37 77 42 50 177 37 5 127 153 45 143 228 121 156 169 120 219 241 51 166 232 192 150 188 53 55 227 148 82 92 150 172 3 196 232 182 61 229 63 123 97 179 194 39 172 250 157 132 187 95 38 199 94 70 93 118 37 231 240 94 60 4 159 47 58 110 125 243 213 239 136 43 228 105 106 69 125 12 50 198 126 216 117 74 175 112 45 164 76 69 146 101 9 188 58 94 75 143 218 32 197 179 199 89 31 245 123 71 40 135 54 33 170 83 34 117 100 62 171 30 51 145 143 244 160 4 164 86 158 105 91 182 66 27 163 118 52 118 47 79 199 84 233 134 128 105 101 19 25 17 84 7 21 187 90 240 99 99 104 154 2 249 215 154 18 47 63 149 225 238 179 178 72 3 191 182 82 66 11 113 18 57 152 108 215 159 57 147 58 115 164 91 208 205 86 148 16 132 192 145 138 194 60 9 198 147 53 65 64 96 242 14 222 119 241 46 116 132 197 184 238 189 26 200 62 176 80 151 140 109 183 24 44 191 172 234 107 21 192 140 99 94 65 54 7 42 24 49 230 20 229 73 212 45 169 115 180 141 56 200 41 87 121 161 219 231 214 207 1 19 20 219 236 12 55 237 237 211 72 13 28 141 72 239 152 82 87 100 72 8 241 41 77 32 202 229 47 84 238 184 228 100 67 210 130 46 111 93 97 189 31 250 162 171 35 90 4 138 199 99 120 193 113 244 181 93 123 76 90 235 49 251 109 188 63 144 186 138 184 223 61 208 215 175 107 6 53 81 114 207 237 221 161 224 18 73 202 208 210 125 248 11 98 131 250 167 221 146 85 211 88 63 139 136 27 189 5 111 103 186 148 21 171 51 140 104 133 165 49 225 233 129 78 5 106 64 86 153 55 232 187 111 77 58 89 36 32 223 66 6 74 170 62 197 169 110 130 41 61 234 102 234 92 145 133 155 201 14 243 208 200 36 48 21 166 1 40 109 178 147 ^'}},
+ {OUT=>'1A3540BEE05518505827954F58B751C475AEECE0'}],
+ ['192', {IN=> {f=> '522 0 179 196 200 34 251 241 156 51 23 75 118 41 193 202 90 93 236 125 242 125 101 151 130 14 218 34 106 41 197 173 55 112 37 108 211 65 174 142 136 159 22 19 245 127 16 19 131 101 10 133 20 104 122 126 184 227 9 187 225 208 90 230 7 131 105 213 121 39 137 105 95 147 45 23 216 92 35 75 114 70 205 206 34 110 12 185 169 111 95 6 71 29 79 203 32 195 144 161 82 64 228 92 8 104 126 74 172 223 65 170 194 171 140 221 36 21 164 198 5 102 211 206 148 136 18 48 25 131 215 36 162 161 192 142 14 214 63 141 45 141 190 86 149 219 94 182 198 115 157 252 73 203 173 192 115 43 226 67 85 62 172 227 13 135 190 227 123 213 231 94 178 227 150 161 196 90 234 210 119 124 14 104 8 100 178 109 153 167 82 201 231 98 149 215 146 217 179 59 174 28 133 130 159 163 248 239 9 183 254 243 71 174 24 162 165 163 107 10 15 46 110 8 214 204 115 39 23 79 89 6 189 3 73 85 176 198 1 154 246 210 115 153 49 108 207 117 209 146 103 176 53 56 172 113 10 129 72 116 126 70 201 3 69 114 211 202 200 171 22 247 42 139 20 218 148 132 70 83 29 75 67 199 88 178 113 124 155 78 2 214 67 89 33 160 246 69 118 159 167 196 204 5 216 237 212 34 247 38 191 55 222 92 149 78 120 211 61 226 177 140 103 39 27 50 54 25 245 241 42 25 249 212 30 21 50 195 254 239 123 186 28 106 182 171 167 192 1 17 220 181 229 65 29 220 177 26 77 33 164 194 57 137 215 150 165 167 78 230 11 102 93 232 177 22 129 68 168 138 74 145 20 77 174 138 188 171 26 218 7 158 76 201 117 72 120 74 35 197 59 52 83 151 20 214 177 144 51 27 46 106 37 249 185 59 56 54 139 16 15 160 136 14 100 37 112 182 53 170 198 119 128 240 69 4 156 161 78 116 240 96 207 121 157 134 99 209 36 25 135 186 1 158 194 175 111 209 32 77 147 190 200 175 225 235 38 195 3 187 88 205 61 89 151 134 217 206 30 162 24 166 113 128 103 66 253 15 50 58 228 210 5 98 8 218 152 80 35 79 62 58 224 7 17 102 207 3 183 140 217 65 56 168 165 22 133 16 133 157 107 128 244 12 ^'}},
+ {OUT=>'DFA19180359D5A7A38E842F172359CAF4208FC05'}],
+ ['193', {IN=> {f=> '517 1 218 150 217 59 81 203 140 217 148 45 193 82 116 122 93 236 7 11 127 242 235 123 155 246 125 238 148 134 126 72 27 247 67 27 50 162 22 247 127 153 45 133 213 121 151 159 105 209 231 36 166 217 177 140 188 53 50 222 148 242 67 87 145 157 250 181 227 177 51 224 63 108 97 174 194 24 162 250 152 132 182 80 33 189 84 60 83 118 37 216 235 94 60 251 154 47 48 110 120 238 208 229 121 43 218 90 91 64 110 12 40 193 111 211 117 64 170 107 35 164 76 54 141 101 4 183 53 79 60 143 213 32 187 169 194 84 31 245 123 66 25 135 39 23 160 78 29 102 95 62 166 20 46 135 128 244 150 246 154 76 143 105 91 172 51 27 158 103 37 108 37 79 199 84 228 119 128 95 91 4 15 17 69 2 11 187 80 230 94 89 89 149 244 239 210 144 18 42 48 139 215 233 179 163 252 67 255 181 167 82 56 253 98 8 42 137 103 205 144 47 137 43 110 149 76 203 200 86 143 16 127 182 140 128 184 55 251 183 142 43 50 54 81 232 9 212 119 236 36 106 122 182 169 223 179 26 185 57 166 80 141 130 99 178 24 44 191 167 219 92 6 187 140 99 89 60 54 249 42 19 44 220 5 214 63 197 30 164 105 180 136 41 195 26 77 116 151 219 231 204 202 1 9 15 214 231 7 40 222 237 206 57 255 13 131 72 224 152 72 87 85 62 255 241 36 77 27 187 229 32 79 228 179 223 90 62 195 115 41 106 93 87 174 26 245 152 161 20 75 4 123 184 84 120 178 113 234 181 78 118 66 85 230 34 251 94 178 53 139 186 138 184 223 61 193 200 175 107 6 38 81 114 207 227 206 146 219 3 73 197 198 200 115 238 11 98 116 240 152 221 146 70 201 88 58 139 126 12 189 252 96 93 176 138 16 156 51 135 99 118 155 49 220 233 119 68 96 64 81 143 45 222 177 111 62 58 79 31 17 218 61 253 69 170 47 197 169 105 120 41 46 224 92 234 92 145 128 155 186 256 243 208 200 26 48 21 156 248 40 104 178 221 175 196 196 28 249 239 150 49 23 71 114 39 191 196 88 87 234 121 240 123 95 151 130 10 214 34 102 35 193 171 49 112 35 104 207 59 170 136 130 159 16 19 241 125 213 ^'}},
+ {OUT=>'7B0FA84EBBCFF7D7F4500F73D79660C4A3431B67'}],
+ ['194', {IN=> {f=> '529 1 15 127 93 2 121 8 104 114 126 176 223 1 183 225 196 90 230 3 119 93 201 117 39 125 97 91 147 41 19 216 80 35 75 110 58 193 198 26 98 8 185 161 103 95 257 71 21 71 199 24 183 144 149 74 52 228 88 255 96 114 66 172 215 61 166 190 167 128 209 36 13 152 186 256 94 199 202 136 128 10 40 21 131 203 32 162 161 184 142 14 210 55 141 37 129 186 78 141 215 82 170 198 107 145 244 65 195 173 192 103 35 214 63 81 54 164 215 1 123 182 227 111 213 227 90 170 219 150 153 184 82 230 202 115 124 2 100 4 96 174 109 141 155 78 201 219 90 149 215 142 213 167 47 162 20 133 118 155 159 248 235 9 183 246 239 59 170 20 154 161 163 99 6 11 38 106 8 206 204 111 35 15 67 89 253 181 250 69 85 164 194 256 154 242 210 115 145 45 108 203 113 209 138 103 176 45 48 160 105 10 121 68 108 122 66 193 258 69 106 207 202 196 171 18 239 38 127 12 214 144 128 70 83 29 71 67 191 84 166 109 120 151 70 2 202 55 81 33 160 246 61 106 147 159 188 192 1 204 229 204 30 247 38 187 55 222 84 145 66 112 211 53 226 173 132 99 27 15 46 46 25 241 233 34 17 241 212 30 9 42 195 254 239 119 174 28 94 178 159 167 188 252 5 212 169 221 65 17 220 169 22 69 25 160 186 57 137 207 142 153 163 78 222 3 98 89 232 177 22 129 68 168 126 74 133 16 65 174 130 184 163 18 218 254 158 72 197 109 60 108 62 23 185 59 52 71 139 20 214 165 132 39 23 46 106 29 249 173 51 52 50 135 12 15 148 136 10 100 25 100 182 49 158 190 107 124 240 57 255 156 157 74 112 232 96 195 113 149 134 95 197 28 13 131 182 248 154 182 167 107 205 28 73 135 190 188 171 217 235 30 187 254 179 76 205 49 77 143 130 205 206 26 158 12 154 101 120 91 66 253 3 38 46 224 198 5 94 206 144 68 27 75 50 54 224 258 9 102 199 3 179 136 209 57 56 160 165 14 129 8 125 157 95 116 240 36 212 148 217 57 77 203 134 213 146 43 193 80 116 122 87 236 7 9 123 242 231 119 153 244 125 238 142 132 120 70 23 245 63 21 50 156 16 243 127 153 45 129 207 121 149 155 99 205 227 30 166 211 57 ^'}},
+ {OUT=>'9E886081C9ACAAD0F97B10810D1DE6FCDCE6B5F4'}],
+ ['195', {IN=> {f=> '548 0 134 188 53 47 219 148 236 58 84 142 148 247 172 224 174 45 221 63 99 97 171 194 15 156 250 149 132 179 71 30 183 78 54 77 118 37 207 232 94 60 248 151 47 42 110 117 235 205 223 112 43 212 81 82 61 101 12 34 190 102 208 117 58 167 104 29 164 76 45 138 101 1 180 50 70 51 143 210 32 181 163 191 81 31 245 123 63 16 135 30 17 154 75 26 93 92 62 163 14 43 129 119 244 144 240 148 70 134 105 91 166 42 27 155 94 28 102 31 79 199 84 225 110 128 89 85 255 9 17 60 259 5 187 74 224 91 83 80 146 238 233 207 138 18 39 39 133 209 230 179 154 252 64 255 175 158 82 50 247 89 2 33 128 100 199 135 41 131 34 107 140 67 200 197 86 140 16 124 176 137 122 178 52 245 174 139 37 41 48 72 226 6 206 119 233 30 100 116 173 160 214 173 26 176 54 160 80 135 124 93 175 24 44 191 164 210 83 257 184 140 99 86 57 54 243 42 16 41 214 256 205 57 188 21 161 99 180 133 32 192 17 71 113 145 219 231 198 199 1 3 12 211 228 4 31 213 237 203 48 249 4 125 72 215 152 66 87 76 56 252 241 33 77 24 178 229 23 76 222 176 220 84 59 186 106 38 103 93 81 165 23 242 146 155 11 66 4 114 175 75 120 169 113 228 181 69 115 60 82 227 25 251 85 172 47 136 186 138 184 223 61 184 191 175 107 6 29 81 114 207 221 197 137 216 254 73 194 192 194 109 232 11 98 107 234 143 221 146 61 195 88 55 139 120 3 189 249 87 87 170 132 13 147 51 132 96 109 149 49 217 233 113 62 257 90 64 78 137 39 216 171 111 53 58 73 28 8 215 58 250 66 170 38 197 169 102 114 41 37 218 86 234 92 145 125 155 177 250 243 208 200 20 48 21 150 245 40 101 178 218 169 196 190 19 246 236 141 46 23 65 108 36 188 187 85 78 231 115 237 120 86 151 130 4 208 34 96 26 187 168 40 112 32 98 201 50 164 127 121 159 7 19 235 122 1 14 126 91 118 5 104 112 126 174 222 259 182 225 193 90 230 2 116 90 198 116 39 122 95 90 147 40 18 216 77 35 75 109 55 190 196 24 95 7 185 159 101 95 256 71 19 69 198 22 180 144 146 72 49 228 87 253 94 111 64 172 213 60 165 189 166 125 206 36 11 149 183 255 92 196 201 133 126 8 38 20 131 213 ^'}},
+ {OUT=>'A4D46E4BA0AE4B012F75B1B50D0534D578AE9CB6'}],
+ ['196', {IN=> {f=> '547 0 29 162 161 178 142 14 207 49 141 31 120 183 72 135 212 73 161 198 101 136 238 59 189 173 192 94 29 205 60 78 48 158 206 254 114 176 227 102 213 224 87 164 213 150 147 175 76 227 196 112 124 255 97 1 93 171 109 132 146 75 201 210 84 149 215 139 210 158 38 153 14 133 109 152 156 248 232 9 183 240 236 50 167 17 148 158 163 93 3 8 32 103 8 200 204 108 32 9 58 89 247 175 244 66 85 155 191 256 154 239 210 115 139 42 108 200 110 209 132 103 176 39 42 151 99 10 115 65 102 119 63 187 258 69 100 204 202 193 171 15 233 35 118 6 211 141 125 70 83 29 68 67 185 81 157 106 117 148 64 2 193 46 75 33 160 246 55 97 138 153 182 183 260 195 223 198 27 247 38 184 55 222 78 142 57 106 211 47 226 170 126 96 18 6 43 40 25 238 227 28 11 235 212 30 36 195 254 239 116 165 28 85 175 150 167 185 249 258 206 160 215 65 8 220 163 19 63 19 157 180 57 137 201 136 144 160 78 216 259 95 86 232 177 22 129 68 168 117 74 124 13 56 174 124 181 157 12 218 248 158 69 194 103 51 99 53 14 176 59 52 62 130 20 214 156 123 30 20 46 106 23 249 164 45 49 47 132 9 15 139 136 7 100 16 91 182 46 149 184 98 121 240 48 252 156 154 71 109 226 96 186 107 143 134 92 188 22 4 128 179 242 151 173 161 104 202 25 70 126 190 179 168 211 235 24 181 251 173 67 205 40 68 137 127 196 206 23 155 3 145 92 114 82 66 253 256 29 37 221 189 5 91 256 197 138 59 21 72 41 51 224 255 3 102 193 3 176 133 203 51 56 154 165 8 126 2 119 157 86 107 237 33 203 145 217 54 71 203 125 207 143 40 193 77 116 122 78 236 7 6 117 242 225 113 150 241 125 238 133 129 111 67 17 242 57 12 50 147 7 237 127 153 45 123 198 121 146 149 90 199 221 21 166 202 162 130 188 53 45 217 148 232 52 82 140 142 245 166 222 172 41 219 63 93 97 169 194 9 152 250 147 132 177 65 28 179 74 50 73 118 37 201 230 94 60 246 149 47 38 110 115 233 203 219 106 43 208 75 76 59 95 12 30 188 96 206 117 54 165 102 25 164 76 39 136 101 261 178 48 64 45 143 208 32 177 159 189 79 31 245 123 61 10 135 24 13 150 73 24 87 90 62 161 10 41 125 209 ^'}},
+ {OUT=>'6342B199EE64C7B2C9CBCD4F2DCB65ACEF51516F'}],
+ ['197', {IN=> {f=> '542 1 244 136 232 140 62 122 105 91 158 30 27 151 82 16 94 23 79 199 84 221 98 128 81 77 247 1 17 48 259 261 187 66 216 87 75 68 142 230 225 203 130 18 35 27 125 201 226 179 142 252 60 255 167 146 82 42 239 77 258 21 116 96 191 123 33 123 22 103 128 55 196 193 86 136 16 120 168 133 114 170 48 237 162 135 29 29 40 60 218 2 198 119 229 22 92 108 161 148 202 165 26 164 50 152 80 127 116 85 171 24 44 191 160 198 71 249 180 140 99 82 53 54 235 42 12 37 206 248 193 49 176 9 157 91 180 129 20 188 5 63 109 137 219 231 190 195 1 259 8 207 224 19 201 237 199 36 241 256 117 72 203 152 58 87 64 48 248 241 29 77 20 166 229 11 72 214 172 216 76 55 174 94 34 99 93 73 153 19 238 138 147 263 54 4 102 163 63 120 157 113 220 181 57 111 52 78 223 13 251 73 164 39 132 186 138 184 223 61 172 179 175 107 6 17 81 114 207 213 185 125 212 246 73 190 184 186 101 224 11 98 95 226 131 221 146 49 187 88 51 139 112 255 189 245 75 79 162 124 9 135 51 128 92 97 141 49 213 233 105 54 257 82 64 74 129 31 208 163 111 41 58 65 24 260 211 54 246 62 170 26 197 169 98 106 41 25 210 78 234 92 145 121 155 165 242 243 208 200 12 48 21 142 241 40 97 178 214 161 196 182 7 242 232 129 42 23 57 100 32 184 175 81 66 227 107 233 116 74 151 130 260 200 34 88 14 179 164 28 112 28 90 193 38 156 115 109 159 259 19 227 118 253 10 122 83 256 106 257 104 104 126 166 218 255 178 225 181 90 230 262 104 78 186 112 39 110 87 86 147 36 14 216 65 35 75 105 43 178 188 16 83 3 185 151 93 95 252 71 11 61 194 14 168 144 134 64 37 228 83 245 86 99 56 172 205 56 161 185 162 113 194 36 3 137 171 251 84 184 197 121 118 30 16 131 188 27 162 161 174 142 14 205 45 141 27 114 181 68 131 210 67 155 198 97 130 234 55 185 173 192 88 25 199 58 76 44 154 200 250 108 172 227 96 213 222 85 160 209 150 143 169 72 225 192 110 124 251 95 263 91 169 109 126 140 73 201 204 80 149 215 137 208 152 32 147 10 133 103 150 154 248 230 9 183 236 234 44 165 15 144 156 163 89 1 6 28 101 8 196 204 106 164 ^'}},
+ {OUT=>'AABFD63688EB678357869130083E1B52F6EA861D'}],
+ ['198', {IN=> {f=> '567 0 1 46 89 239 167 236 62 85 143 187 256 154 235 210 115 131 38 108 196 106 209 124 103 176 31 34 139 91 10 107 61 94 115 59 179 258 69 92 200 202 189 171 11 225 31 106 264 207 137 121 70 83 29 64 67 177 77 145 102 113 144 56 2 181 34 67 33 160 246 47 85 126 145 174 171 260 183 215 190 23 247 38 180 55 222 70 138 45 98 211 39 226 166 118 92 6 260 39 32 25 234 219 20 3 227 212 30 254 28 195 254 239 112 153 28 73 171 138 167 181 245 250 198 148 207 65 262 220 155 15 55 11 153 172 57 137 193 128 132 156 78 208 255 91 82 232 177 22 129 68 168 105 74 112 9 44 174 116 177 149 4 218 240 158 65 190 95 39 87 41 2 164 59 52 50 118 20 214 144 111 18 16 46 106 15 249 152 37 45 43 128 5 15 127 136 3 100 4 79 182 42 137 176 86 117 240 36 248 156 150 67 105 218 96 174 99 135 134 88 176 14 258 124 175 234 147 161 153 100 198 21 66 114 190 167 164 203 235 16 173 247 165 55 205 28 56 129 123 184 206 19 151 257 133 80 106 70 66 253 248 17 25 217 177 5 87 252 185 130 47 13 68 29 47 224 251 261 102 185 3 172 129 195 43 56 146 165 122 260 111 157 74 95 233 29 191 141 217 50 63 203 113 199 139 36 193 73 116 122 66 236 7 2 109 242 217 105 146 237 125 238 121 125 99 63 9 238 49 50 135 261 229 127 153 45 115 186 121 142 141 78 191 213 9 166 190 150 122 188 53 41 213 148 224 40 78 136 130 241 154 218 168 33 215 63 81 97 165 194 263 144 250 143 132 173 53 24 171 66 42 65 118 37 189 226 94 60 242 145 47 30 110 111 229 199 211 94 43 200 63 64 55 83 12 22 184 84 202 117 46 161 98 17 164 76 27 132 101 261 174 44 52 33 143 204 32 169 151 185 75 31 245 123 57 264 135 12 5 142 69 20 75 86 62 157 2 37 117 101 244 132 228 136 58 116 105 91 154 24 27 149 76 10 90 19 79 199 84 219 92 128 77 73 243 263 17 42 259 259 187 62 212 85 71 62 140 226 221 201 126 18 33 21 121 197 224 179 136 252 58 255 163 140 82 38 235 71 256 15 110 94 187 117 29 119 16 101 122 49 194 191 86 134 16 118 164 131 110 166 46 233 156 133 25 23 36 54 214 194 119 227 18 88 104 155 142 196 161 26 158 48 148 80 123 112 81 169 24 44 191 158 192 65 245 178 140 223 ^'}},
+ {OUT=>'F732B7372DAF44801F81EFFE3108726239837936'}],
+ ['199', {IN=> {f=> '551 1 78 49 54 227 42 8 33 198 240 181 41 164 265 153 83 180 125 8 184 261 55 105 129 219 231 182 191 1 255 4 203 220 264 7 189 237 195 24 233 248 109 72 191 152 50 87 52 40 244 241 25 77 16 154 229 267 68 206 168 212 68 51 162 82 30 95 93 65 141 15 234 130 139 255 42 4 90 151 51 120 145 113 212 181 45 107 44 74 219 1 251 61 156 31 128 186 138 184 223 61 160 167 175 107 6 5 81 114 207 205 173 113 208 238 73 186 176 178 93 216 11 98 83 218 119 221 146 37 179 88 47 139 104 247 189 241 63 71 154 116 5 123 51 124 88 85 133 49 209 233 97 46 257 74 64 70 121 23 200 155 111 29 58 57 20 252 207 50 242 58 170 14 197 169 94 98 41 13 202 70 234 92 145 117 155 153 234 243 208 200 4 48 21 134 237 40 93 178 210 153 196 174 263 238 228 117 38 23 49 92 28 180 163 77 54 223 99 229 112 62 151 130 256 192 34 80 2 171 160 16 112 24 82 185 26 148 103 97 159 251 19 219 114 245 6 118 75 252 94 249 104 96 126 158 214 251 174 225 169 90 230 262 92 66 174 108 39 98 79 82 147 32 10 216 53 35 75 101 31 166 180 8 71 267 185 143 85 95 248 71 3 53 190 6 156 144 122 56 25 228 79 237 78 87 48 172 197 52 157 181 158 101 182 36 263 125 159 247 76 172 193 109 110 260 22 12 131 176 23 162 161 166 142 14 201 37 141 19 102 177 60 123 206 55 143 198 89 118 226 47 177 173 192 76 17 187 54 72 36 146 188 242 96 164 227 84 213 218 81 152 201 150 135 157 64 221 184 106 124 243 91 263 87 165 109 114 128 69 201 192 72 149 215 133 204 140 20 135 2 133 91 146 150 248 226 9 183 228 230 32 161 11 136 152 163 81 265 2 20 97 8 188 204 102 26 265 40 89 235 163 232 60 85 137 185 256 154 233 210 115 127 36 108 194 104 209 120 103 176 27 30 133 87 10 103 59 90 113 57 175 258 69 88 198 202 187 171 9 221 29 100 262 205 135 119 70 83 29 62 67 173 75 139 100 111 142 52 2 175 28 63 33 160 246 43 79 120 141 170 165 260 177 211 186 21 247 38 178 55 222 66 136 39 94 211 35 226 164 114 90 256 37 28 25 232 215 16 267 223 212 30 250 24 195 254 239 110 147 28 67 169 132 167 179 243 246 194 142 203 65 263 ^'}},
+ {OUT=>'5E9347FE4574CDCB80281ED092191199BADD7B42'}],
+ ['200', {IN=> {f=> '578 0 220 147 11 47 3 149 164 57 137 185 120 120 152 78 200 251 87 78 232 177 22 129 68 168 93 74 100 5 32 174 108 173 141 266 218 232 158 61 186 87 27 75 29 260 152 59 52 38 106 20 214 132 99 6 12 46 106 7 249 140 29 41 39 124 1 15 115 136 269 100 262 67 182 38 125 168 74 113 240 24 244 156 146 63 101 210 96 162 91 127 134 84 164 6 250 120 171 226 143 149 145 96 194 17 62 102 190 155 160 195 235 8 165 243 157 43 205 16 44 121 119 172 206 15 147 249 121 68 98 58 66 253 240 5 13 213 165 5 83 248 173 122 35 5 64 17 43 224 247 257 102 177 3 168 125 187 35 56 138 165 262 118 256 103 157 62 83 229 25 179 137 217 46 55 203 101 191 135 32 193 69 116 122 54 236 7 268 101 242 209 97 142 233 125 238 109 121 87 59 1 234 41 258 50 123 253 221 127 153 45 107 174 121 138 133 66 183 205 267 166 178 138 114 188 53 37 209 148 216 28 74 132 118 237 142 214 164 25 211 63 69 97 161 194 255 136 250 139 132 169 41 20 163 58 34 57 118 37 177 222 94 60 238 141 47 22 110 107 225 195 203 82 43 192 51 52 51 71 12 14 180 72 198 117 38 157 94 9 164 76 15 128 101 261 170 40 40 21 143 200 32 161 143 181 71 31 245 123 53 256 135 267 134 65 16 63 82 62 153 264 33 109 89 244 124 220 128 50 104 105 91 146 12 27 145 64 268 82 11 79 199 84 215 80 128 69 65 235 259 17 30 259 255 187 54 204 81 63 50 136 218 213 197 118 18 29 9 113 189 220 179 124 252 54 255 155 128 82 30 227 59 252 3 98 90 179 105 21 111 4 97 110 37 190 187 86 130 16 114 156 127 102 158 42 225 144 129 17 11 28 42 206 266 186 119 223 10 80 96 143 130 184 153 26 146 44 140 80 115 104 73 165 24 44 191 154 180 53 237 174 140 99 76 47 54 223 42 6 31 194 236 175 37 158 261 151 79 180 123 2 182 257 51 103 125 219 231 178 189 1 253 2 201 218 264 1 183 237 193 18 229 244 105 72 185 152 46 87 46 36 242 241 23 77 14 148 229 263 66 202 166 210 64 49 156 76 28 93 93 61 135 13 232 126 135 251 36 4 84 145 45 120 139 113 208 181 39 105 40 72 217 265 251 55 152 27 126 186 138 184 223 61 154 161 175 107 6 269 81 114 207 201 167 107 206 234 73 184 172 174 89 212 11 98 77 214 113 221 146 31 175 88 45 139 100 243 189 213 ^'}},
+ {OUT=>'D5776B7DFFF75C1358ABDBBB3F27A20BB6CA7C55'}],
+ ['201', {IN=> {f=> '578 1 51 63 146 108 1 111 51 120 84 73 125 49 205 233 89 38 257 66 64 66 113 15 192 147 111 17 58 49 16 244 203 46 238 54 170 2 197 169 90 90 41 1 194 62 234 92 145 113 155 141 226 243 208 200 268 48 21 126 233 40 89 178 206 145 196 166 255 234 224 105 34 23 41 84 24 176 151 73 42 219 91 225 108 50 151 130 252 184 34 72 262 163 156 4 112 20 74 177 14 140 91 85 159 243 19 211 110 237 2 114 67 248 82 241 104 88 126 150 210 247 170 225 157 90 230 262 80 54 162 104 39 86 71 78 147 28 6 216 41 35 75 97 19 154 172 59 267 185 135 77 95 244 71 267 45 186 270 144 144 110 48 13 228 75 229 70 75 40 172 189 48 153 177 154 89 170 36 259 113 147 243 68 160 189 97 102 256 14 8 131 164 19 162 161 158 142 14 197 29 141 11 90 173 52 115 202 43 131 198 81 106 218 39 169 173 192 64 9 175 50 68 28 138 176 234 84 156 227 72 213 214 77 144 193 150 127 145 56 217 176 102 124 235 87 263 83 161 109 102 116 65 201 180 64 149 215 129 200 128 8 123 266 133 79 142 146 248 222 9 183 220 226 20 157 7 128 148 163 73 265 270 12 93 8 180 204 98 22 261 28 89 227 155 224 56 85 125 181 256 154 229 210 115 119 32 108 190 100 209 112 103 176 19 22 121 79 10 95 55 82 109 53 167 258 69 80 194 202 183 171 5 213 25 88 258 201 131 115 70 83 29 58 67 165 71 127 96 107 138 44 2 163 16 55 33 160 246 35 67 108 133 162 153 260 165 203 178 17 247 38 174 55 222 58 132 27 86 211 27 226 160 106 86 260 248 33 20 25 228 207 8 263 215 212 30 242 16 195 254 239 106 135 28 55 165 120 167 175 239 238 186 130 195 65 250 220 143 9 43 271 147 160 57 137 181 116 114 150 78 196 249 85 76 232 177 22 129 68 168 87 74 94 3 26 174 104 171 137 264 218 228 158 59 184 83 21 69 23 256 146 59 52 32 100 20 214 126 93 10 46 106 3 249 134 25 39 37 122 271 15 109 136 269 100 258 61 182 36 119 164 68 111 240 18 242 156 144 61 99 206 96 156 87 123 134 82 158 2 246 118 169 222 141 143 141 94 192 15 60 96 190 149 158 191 235 4 161 241 153 37 205 10 38 117 117 166 206 13 145 245 115 62 94 52 66 253 236 271 7 211 159 5 81 246 167 118 29 1 62 11 41 224 245 255 102 173 3 166 123 183 31 56 134 165 260 116 254 81 ^'}},
+ {OUT=>'022B7ADA472FB7A9DA9219621C9C5F563D3792F6'}],
+ ['202', {IN=> {f=> '583 1 157 50 71 225 21 167 133 217 42 47 203 89 183 131 28 193 65 116 122 42 236 7 268 93 242 201 89 138 229 125 238 97 117 75 55 267 230 33 250 50 111 245 213 127 153 45 99 162 121 134 125 54 175 197 259 166 166 126 106 188 53 33 205 148 208 16 70 128 106 233 130 210 160 17 207 63 57 97 157 194 247 128 250 135 132 165 29 16 155 50 26 49 118 37 165 218 94 60 234 137 47 14 110 103 221 191 195 70 43 184 39 40 47 59 12 6 176 60 194 117 30 153 90 1 164 76 3 124 101 261 166 36 28 9 143 196 32 153 135 177 67 31 245 123 49 248 135 262 263 126 61 12 51 78 62 149 260 29 101 77 244 116 212 120 42 92 105 91 138 27 141 52 260 74 3 79 199 84 211 68 128 61 57 227 255 17 18 259 251 187 46 196 77 55 38 132 210 205 193 110 18 25 271 105 181 216 179 112 252 50 255 147 116 82 22 219 47 248 265 86 86 171 93 13 103 266 93 98 25 186 183 86 126 16 110 148 123 94 150 38 217 132 125 9 273 20 30 198 266 178 119 219 2 72 88 131 118 172 145 26 134 40 132 80 107 96 65 161 24 44 191 150 168 41 229 170 140 99 72 43 54 215 42 2 27 186 228 163 29 146 253 147 71 180 119 264 178 249 43 99 117 219 231 170 185 1 249 272 197 214 264 263 171 237 189 6 221 236 97 72 173 152 38 87 34 28 238 241 19 77 10 136 229 255 62 194 162 206 56 45 144 64 24 89 93 53 123 9 228 118 127 243 24 4 72 133 33 120 127 113 200 181 27 101 32 68 213 257 251 43 144 19 122 186 138 184 223 61 142 149 175 107 6 261 81 114 207 193 155 95 202 226 73 180 164 166 81 204 11 98 65 206 101 221 146 19 167 88 41 139 92 235 189 235 45 59 142 104 273 105 51 118 82 67 121 49 203 233 85 34 257 62 64 64 109 11 188 143 111 11 58 45 14 240 201 44 236 52 170 270 197 169 88 86 41 269 190 58 234 92 145 111 155 135 222 243 208 200 266 48 21 122 231 40 87 178 204 141 196 162 251 232 222 99 32 23 37 80 22 174 145 71 36 217 87 223 106 44 151 130 250 180 34 68 258 159 154 272 112 18 70 173 8 136 85 79 159 239 19 207 108 233 112 63 246 76 237 104 84 126 146 208 245 168 225 151 90 230 262 74 48 156 102 39 80 67 76 147 26 4 216 35 35 75 95 13 148 168 270 53 267 185 131 73 95 242 71 265 41 184 268 138 144 104 44 7 228 73 225 66 69 36 272 ^'}},
+ {OUT=>'7F1DE4ECA20362DA624653D225A5B3F7964A9FF2'}],
+ ['203', {IN=> {f=> '588 0 181 44 149 173 150 77 158 36 255 101 135 239 60 148 185 85 94 252 6 4 131 152 15 162 161 150 142 14 193 21 141 3 78 169 44 107 198 31 119 198 73 94 210 31 161 173 192 52 1 163 46 64 20 130 164 226 72 148 227 60 213 210 73 136 185 150 119 133 48 213 168 98 124 227 83 263 79 157 109 90 104 61 201 168 56 149 215 125 196 116 272 111 262 133 67 138 142 248 218 9 183 212 222 8 153 3 120 144 163 65 265 270 4 89 8 172 204 94 18 257 16 89 219 147 216 52 85 113 177 256 154 225 210 115 111 28 108 186 96 209 104 103 176 11 14 109 71 10 87 51 74 105 49 159 258 69 72 190 202 179 171 1 205 21 76 254 197 127 111 70 83 29 54 67 157 67 115 92 103 134 36 2 151 4 47 33 160 246 27 55 96 125 154 141 260 153 195 170 13 247 38 170 55 222 50 128 15 78 211 19 226 156 98 82 252 240 29 12 25 224 199 259 207 212 30 234 8 195 254 239 102 123 28 43 161 108 167 171 235 230 178 118 187 65 242 220 135 5 35 267 143 152 57 137 173 108 102 146 78 188 245 81 72 232 177 22 129 68 168 75 74 82 275 14 174 96 167 129 260 218 220 158 55 180 75 9 57 11 248 134 59 52 20 88 20 214 114 81 264 6 46 106 271 249 122 17 35 33 118 271 15 97 136 269 100 250 49 182 32 107 156 56 107 240 6 238 156 140 57 95 198 96 144 79 115 134 78 146 270 238 114 165 214 137 131 133 90 188 11 56 84 190 137 154 183 235 272 153 237 145 25 205 274 26 109 113 154 206 9 141 237 103 50 86 40 66 253 228 263 271 207 147 5 77 242 155 110 17 269 58 275 37 224 241 251 102 165 3 162 119 175 23 56 126 165 256 112 250 91 157 44 65 223 19 161 131 217 40 43 203 83 179 129 26 193 63 116 122 36 236 7 268 89 242 197 85 136 227 125 238 91 115 69 53 265 228 29 246 50 105 241 209 127 153 45 95 156 121 132 121 48 171 193 255 166 160 120 102 188 53 31 203 148 204 10 68 126 100 231 124 208 158 13 205 63 51 97 155 194 243 124 250 133 132 163 23 14 151 46 22 45 118 37 159 216 94 60 232 135 47 10 110 101 219 189 191 64 43 180 33 34 45 53 12 2 174 54 192 117 26 151 88 273 164 76 273 122 101 261 164 34 22 3 143 194 32 149 131 175 65 31 245 123 47 244 135 258 261 122 59 10 45 76 62 147 258 27 97 71 244 112 208 116 38 86 105 91 134 270 27 139 46 256 70 275 79 199 160 ^'}},
+ {OUT=>'CA0F2B1BFB4469C11ED006A994734F0F2F5EFD17'}],
+ ['204', {IN=> {f=> '594 0 207 56 128 53 49 219 251 17 6 259 247 187 38 188 73 47 26 128 202 197 189 102 18 21 263 97 173 212 179 100 252 46 255 139 104 82 14 211 35 244 257 74 82 163 81 5 95 258 89 86 13 182 179 86 122 16 106 140 119 86 142 34 209 120 121 1 265 12 18 190 266 170 119 215 272 64 80 119 106 160 137 26 122 36 124 80 99 88 57 157 24 44 191 146 156 29 221 166 140 99 68 39 54 207 42 276 23 178 220 151 21 134 245 143 63 180 115 256 174 241 35 95 109 219 231 162 181 1 245 272 193 210 264 255 159 237 185 272 213 228 89 72 161 152 30 87 22 20 234 241 15 77 6 124 229 247 58 186 158 202 48 41 132 52 20 85 93 45 111 5 224 110 119 235 12 4 60 121 21 120 115 113 192 181 15 97 24 64 209 249 251 31 136 11 118 186 138 184 223 61 130 137 175 107 6 253 81 114 207 185 143 83 198 218 73 176 156 158 73 196 11 98 53 198 89 221 146 7 159 88 37 139 84 227 189 231 33 51 134 96 273 93 51 114 78 55 113 49 199 233 77 26 257 54 64 60 101 3 180 135 111 277 58 37 10 232 197 40 232 48 170 262 197 169 84 78 41 261 182 50 234 92 145 107 155 123 214 243 208 200 262 48 21 114 227 40 83 178 200 133 196 154 243 228 218 87 28 23 29 72 18 170 133 67 24 213 79 219 102 32 151 130 246 172 34 60 250 151 150 264 112 14 62 165 274 128 73 67 159 231 19 199 104 225 274 108 55 242 64 229 104 76 126 138 204 241 164 225 139 90 230 262 62 36 144 98 39 68 59 72 147 22 216 23 35 75 91 1 136 160 266 41 267 185 123 65 95 238 71 261 33 180 264 126 144 92 36 273 228 69 217 58 57 28 172 177 42 147 171 148 71 152 36 253 95 129 237 56 142 183 79 90 250 2 2 131 146 13 162 161 146 142 14 191 17 141 277 72 167 40 103 196 25 113 198 69 88 206 27 157 173 192 46 275 157 44 62 16 126 158 222 66 144 227 54 213 208 71 132 181 150 115 127 44 211 164 96 124 223 81 263 77 155 109 84 98 59 201 162 52 149 215 123 194 110 268 105 260 133 61 136 140 248 216 9 183 208 220 2 151 1 116 142 163 61 265 270 87 8 168 204 92 16 255 10 89 215 143 212 50 85 107 175 256 154 223 210 115 107 26 108 184 94 209 100 103 176 7 10 103 67 10 83 49 70 103 47 155 258 69 68 188 202 177 171 277 201 19 70 252 195 125 109 70 83 29 52 67 153 65 109 90 101 132 32 2 145 276 43 33 160 246 23 259 ^'}},
+ {OUT=>'833D63F5C2EA0CD43EC15F2B9DD97FF12B030479'}],
+ ['205', {IN=> {f=> '600 1 87 119 148 132 260 144 189 164 10 247 38 167 55 222 44 125 6 72 211 13 226 153 92 79 246 234 26 6 25 221 193 273 256 201 212 30 228 2 195 254 239 99 114 28 34 158 99 167 168 232 224 172 109 181 65 236 220 129 2 29 264 140 146 57 137 167 102 93 143 78 182 242 78 69 232 177 22 129 68 168 66 74 73 275 5 174 90 164 123 257 218 214 158 52 177 69 48 2 242 125 59 52 11 79 20 214 105 72 258 3 46 106 268 249 113 11 32 30 115 271 15 88 136 269 100 244 40 182 29 98 150 47 104 240 276 235 156 137 54 92 192 96 135 73 109 134 75 137 267 232 111 162 208 134 122 127 87 185 8 53 75 190 128 151 177 235 269 147 234 139 16 205 268 17 103 110 145 206 6 138 231 94 41 80 31 66 253 222 257 265 204 138 5 74 239 146 104 8 266 55 269 34 224 238 248 102 159 3 159 116 169 17 56 120 165 253 109 247 85 157 35 56 220 16 152 128 217 37 37 203 74 173 126 23 193 60 116 122 27 236 7 268 83 242 191 79 133 224 125 238 82 112 60 50 262 225 23 240 50 96 235 203 127 153 45 89 147 121 129 115 39 165 187 249 166 151 111 96 188 53 28 200 148 198 1 65 123 91 228 115 205 155 7 202 63 42 97 152 194 237 118 250 130 132 160 14 11 145 40 16 39 118 37 150 213 94 60 229 132 47 4 110 98 216 186 185 55 43 174 24 25 42 44 12 275 171 45 189 117 20 148 85 270 164 76 267 119 101 261 161 31 13 273 143 191 32 143 125 172 62 31 245 123 44 238 135 252 258 116 56 7 36 73 62 144 255 24 91 62 244 106 202 110 32 77 105 91 128 264 27 136 37 250 64 272 79 199 84 206 53 128 51 47 217 250 17 3 259 246 187 36 186 72 45 23 127 200 195 188 100 18 20 261 95 171 211 179 97 252 45 255 137 101 82 12 209 32 243 255 71 81 161 78 3 93 256 88 83 10 181 178 86 121 16 105 138 118 84 140 33 207 117 120 278 263 10 15 188 266 168 119 214 271 62 78 116 103 157 135 26 119 35 122 80 97 86 55 156 24 44 191 145 153 26 219 165 140 99 67 38 54 205 42 276 22 176 218 148 19 131 243 142 61 180 114 254 173 239 33 94 107 219 231 160 180 1 244 272 192 209 264 253 156 237 184 270 211 226 87 72 158 152 28 87 19 18 233 241 14 77 5 121 229 245 57 184 157 201 46 40 129 49 19 84 93 43 108 4 223 108 117 233 9 4 57 118 18 120 112 113 190 181 12 96 22 63 208 247 251 28 134 9 117 186 138 184 223 61 127 216 ^'}},
+ {OUT=>'14FD356190416C00592B86FF7CA50B622F85593A'}],
+ ['206', {IN=> {f=> '590 1 175 107 6 247 81 114 207 179 134 74 195 212 73 173 150 152 67 190 11 98 44 192 80 221 146 279 153 88 34 139 78 221 189 228 24 45 128 90 273 84 51 111 75 46 107 49 196 233 71 20 257 48 64 57 95 278 174 129 111 271 58 31 7 226 194 37 229 45 170 256 197 169 81 72 41 255 176 44 234 92 145 104 155 114 208 243 208 200 259 48 21 108 224 40 80 178 197 127 196 148 237 225 215 78 25 23 23 66 15 167 124 64 15 210 73 216 99 23 151 130 243 166 34 54 244 145 147 258 112 11 56 159 268 122 64 58 159 225 19 193 101 219 274 105 49 239 55 223 104 70 126 132 201 238 161 225 130 90 230 262 53 27 135 95 39 59 53 69 147 19 278 216 14 35 75 88 273 127 154 263 32 267 185 117 59 95 235 71 258 27 177 261 117 144 83 30 267 228 66 211 52 48 22 172 171 39 144 168 145 62 143 36 250 86 120 234 50 133 180 70 84 247 277 280 131 137 10 162 161 140 142 14 188 11 141 274 63 164 34 97 193 16 104 198 63 79 200 21 151 173 192 37 272 148 41 59 10 120 149 216 57 138 227 45 213 205 68 126 175 150 109 118 38 208 158 93 124 217 78 263 74 152 109 75 89 56 201 153 46 149 215 120 191 101 262 96 257 133 52 133 137 248 213 9 183 202 217 274 148 279 110 139 163 55 265 270 275 84 8 162 204 89 13 252 1 89 209 137 206 47 85 98 172 256 154 220 210 115 101 23 108 181 91 209 94 103 176 1 4 94 61 10 77 46 64 100 44 149 258 69 62 185 202 174 171 277 195 16 61 249 192 122 106 70 83 29 49 67 147 62 100 87 98 129 26 2 136 270 37 33 160 246 17 40 81 115 144 126 260 138 185 160 8 247 38 165 55 222 40 123 68 211 9 226 151 88 77 242 230 24 2 25 219 189 271 254 197 212 30 224 279 195 254 239 97 108 28 28 156 93 167 166 230 220 168 103 177 65 232 220 125 25 262 138 142 57 137 163 98 87 141 78 178 240 76 67 232 177 22 129 68 168 60 74 67 275 280 174 86 162 119 255 218 210 158 50 175 65 275 42 277 238 119 59 52 5 73 20 214 99 66 254 1 46 106 266 249 107 7 30 28 113 271 15 82 136 269 100 240 34 182 27 92 146 41 102 240 272 233 156 135 52 90 188 96 129 69 105 134 73 131 265 228 109 160 204 132 116 123 85 183 6 51 69 190 122 149 173 235 267 143 232 135 10 205 264 11 99 108 139 206 4 136 227 88 35 76 25 66 253 218 253 261 202 132 5 72 237 140 203 ^'}},
+ {OUT=>'4AB6B57EDDEF1CE935622F935C1619AE7C1667D6'}],
+ ['207', {IN=> {f=> '620 0 279 262 51 261 30 224 234 244 102 151 3 155 112 161 9 56 112 165 249 105 243 77 157 23 44 216 12 140 124 217 33 29 203 62 165 122 19 193 56 116 122 15 236 7 268 75 242 183 71 129 220 125 238 70 108 48 46 258 221 15 232 50 84 227 195 127 153 45 81 135 121 125 107 27 157 179 241 166 139 99 88 188 53 24 196 148 190 272 61 119 79 224 103 201 151 282 198 63 30 97 148 194 229 110 250 126 132 156 2 7 137 32 8 31 118 37 138 209 94 60 225 128 47 279 110 94 212 182 177 43 43 166 12 13 38 32 12 271 167 33 185 117 12 144 81 266 164 76 259 115 101 261 157 27 1 265 143 187 32 135 117 168 58 31 245 123 40 230 135 244 254 108 52 3 24 69 62 140 251 20 83 50 244 98 194 102 24 65 105 91 120 256 27 132 25 242 56 268 79 199 84 202 41 128 43 39 209 246 17 274 259 242 187 28 178 68 37 11 123 192 187 184 92 18 16 253 87 163 207 179 85 252 41 255 129 89 82 4 201 20 239 247 59 77 153 66 278 85 248 84 71 281 177 174 86 117 16 101 130 114 76 132 29 199 105 116 274 255 2 3 180 266 160 119 210 267 54 70 104 91 145 127 26 107 31 114 80 89 78 47 152 24 44 191 141 141 14 211 161 140 99 63 34 54 197 42 276 18 168 210 136 11 119 235 138 53 180 110 246 169 231 25 90 99 219 231 152 176 1 240 272 188 205 264 245 144 237 180 262 203 218 79 72 146 152 20 87 7 10 229 241 10 77 1 109 229 237 53 176 153 197 38 36 117 37 15 80 93 35 96 219 100 109 225 280 4 45 106 6 120 100 113 182 181 92 14 59 204 239 251 16 126 1 113 186 138 184 223 61 115 122 175 107 6 243 81 114 207 175 128 68 193 208 73 171 146 148 63 186 11 98 38 188 74 221 146 275 149 88 32 139 74 217 189 226 18 41 124 86 273 78 51 109 73 40 103 49 194 233 67 16 257 44 64 55 91 276 170 125 111 267 58 27 5 222 192 35 227 43 170 252 197 169 79 68 41 251 172 40 234 92 145 102 155 108 204 243 208 200 257 48 21 104 222 40 78 178 195 123 196 144 233 223 213 72 23 23 19 62 13 165 118 62 9 208 69 214 97 17 151 130 241 162 34 50 240 141 145 254 112 9 52 155 264 118 58 52 159 221 19 189 99 215 274 103 45 237 49 219 104 66 126 128 199 236 159 225 124 90 230 262 47 21 129 93 39 53 49 67 147 17 278 216 8 35 75 86 269 121 150 261 26 267 185 113 55 95 233 71 256 23 175 259 111 144 77 26 263 228 64 207 48 42 18 172 167 37 142 166 143 56 137 36 248 80 114 232 46 127 257 ^'}},
+ {OUT=>'B456A6A968ACD66CAA974F96A9A916E700AA3C5D'}],
+ ['208', {IN=> {f=> '605 1 58 76 243 273 280 131 125 6 162 161 132 142 14 184 3 141 270 51 160 26 89 189 4 92 198 55 67 192 13 143 173 192 25 268 136 37 55 2 112 137 208 45 130 227 33 213 201 64 118 167 150 101 106 30 204 150 89 124 209 74 263 70 148 109 63 77 52 201 141 38 149 215 116 187 89 254 84 253 133 40 129 133 248 209 9 183 194 213 266 144 279 102 135 163 47 265 270 271 80 8 154 204 85 9 248 274 89 201 129 198 43 85 86 168 256 154 216 210 115 93 19 108 177 87 209 86 103 176 278 281 82 53 10 69 42 56 96 40 141 258 69 54 181 202 170 171 277 187 12 49 245 188 118 102 70 83 29 45 67 139 58 88 83 94 125 18 2 124 262 29 33 160 246 9 28 69 107 136 114 260 126 177 152 4 247 38 161 55 222 32 119 273 60 211 1 226 147 80 73 234 222 20 279 25 215 181 267 250 189 212 30 216 275 195 254 239 93 96 28 16 152 81 167 162 226 212 160 91 169 65 224 220 117 281 17 258 134 134 57 137 155 90 75 137 78 170 236 72 63 232 177 22 129 68 168 48 74 55 275 272 174 78 158 111 251 218 202 158 46 171 57 267 30 269 230 107 59 52 278 61 20 214 87 54 246 282 46 106 262 249 95 284 26 24 109 271 15 70 136 269 100 232 22 182 23 80 138 29 98 240 264 229 156 131 48 86 180 96 117 61 97 134 69 119 261 220 105 156 196 128 104 115 81 179 2 47 57 190 110 145 165 235 263 135 228 127 283 205 256 284 91 104 127 206 132 219 76 23 68 13 66 253 210 245 253 198 120 5 68 233 128 92 275 260 49 257 28 224 232 242 102 147 3 153 110 157 5 56 108 165 247 103 241 73 157 17 38 214 10 134 122 217 31 25 203 56 161 120 17 193 54 116 122 9 236 7 268 71 242 179 67 127 218 125 238 64 106 42 44 256 219 11 228 50 78 223 191 127 153 45 77 129 121 123 103 21 153 175 237 166 133 93 84 188 53 22 194 148 186 268 59 117 73 222 97 199 149 280 196 63 24 97 146 194 225 106 250 124 132 154 281 5 133 28 4 27 118 37 132 207 94 60 223 126 47 277 110 92 210 180 173 37 43 162 6 7 36 26 12 269 165 27 183 117 8 142 79 264 164 76 255 113 101 261 155 25 280 261 143 185 32 131 113 166 56 31 245 123 38 226 135 240 252 104 50 1 18 67 62 138 249 18 79 44 244 94 190 98 20 59 105 91 116 252 27 130 19 238 52 266 79 199 84 200 35 128 39 35 205 244 17 270 259 240 187 24 174 66 33 5 121 188 183 182 88 18 14 249 83 159 205 179 79 252 186 ^'}},
+ {OUT=>'FD1C257FE046B2A27E2F0CD55ED2DECA845F01D7'}],
+ ['209', {IN=> {f=> '615 0 255 121 77 82 283 193 8 235 239 47 73 145 54 274 77 240 80 59 273 173 170 86 113 16 97 122 110 68 124 25 191 93 112 270 247 281 278 172 266 152 119 206 263 46 62 92 79 133 119 26 95 27 106 80 81 70 39 148 24 44 191 137 129 2 203 157 140 99 59 30 54 189 42 276 14 160 202 124 3 107 227 134 45 180 106 238 165 223 17 86 91 219 231 144 172 1 236 272 184 201 264 237 132 237 176 254 195 210 71 72 134 152 12 87 282 2 225 241 6 77 284 97 229 229 49 168 149 193 30 32 105 25 11 76 93 27 84 283 215 92 101 217 272 4 33 94 281 120 88 113 174 181 275 88 6 55 200 231 251 4 118 280 109 186 138 184 223 61 103 110 175 107 6 235 81 114 207 167 116 56 189 200 73 167 138 140 55 178 11 98 26 180 62 221 146 267 141 88 28 139 66 209 189 222 6 33 116 78 273 66 51 105 69 28 95 49 190 233 59 8 257 36 64 51 83 272 162 117 111 259 58 19 1 214 188 31 223 39 170 244 197 169 75 60 41 243 164 32 234 92 145 98 155 96 196 243 208 200 253 48 21 96 218 40 74 178 191 115 196 136 225 219 209 60 19 23 11 54 9 161 106 58 284 204 61 210 93 5 151 130 237 154 34 42 232 133 141 246 112 5 44 147 256 110 46 40 159 213 19 181 95 207 274 99 37 233 37 211 104 58 126 120 195 232 155 225 112 90 230 262 35 9 117 89 39 41 41 63 147 13 278 216 283 35 75 82 261 109 142 257 14 267 185 105 47 95 229 71 252 15 171 255 99 144 65 18 255 228 60 199 40 30 10 172 159 33 138 162 139 44 125 36 244 68 102 228 38 115 174 52 72 241 271 280 131 119 4 162 161 128 142 14 182 286 141 268 45 158 22 85 187 285 86 198 51 61 188 9 139 173 192 19 266 130 35 53 285 108 131 204 39 126 227 27 213 199 62 114 163 150 97 100 26 202 146 87 124 205 72 263 68 146 109 57 71 50 201 135 34 149 215 114 185 83 250 78 251 133 34 127 131 248 207 9 183 190 211 262 142 279 98 133 163 43 265 270 269 78 8 150 204 83 7 246 270 89 197 125 194 41 85 80 166 256 154 214 210 115 89 17 108 175 85 209 82 103 176 276 279 76 49 10 65 40 52 94 38 137 258 69 50 179 202 168 171 277 183 10 43 243 186 116 100 70 83 29 43 67 135 56 82 81 92 123 14 2 118 258 25 33 160 246 5 22 63 103 132 108 260 120 173 148 2 247 38 159 55 222 28 117 269 56 211 284 226 145 76 71 230 218 18 277 25 213 177 265 248 185 212 30 212 273 195 254 239 91 90 28 10 150 75 167 160 224 175 ^'}},
+ {OUT=>'66E0D01780F1063E2929EAAD74826BC64060E38C'}],
+ ['210', {IN=> {f=> '613 0 152 79 161 65 216 220 109 281 9 254 130 126 57 137 147 82 63 133 78 162 232 68 59 232 177 22 129 68 168 36 74 43 275 264 174 70 154 103 247 218 194 158 42 167 49 259 18 261 222 95 59 52 270 49 20 214 75 42 238 282 46 106 258 249 83 280 22 20 105 271 15 58 136 269 100 224 10 182 19 68 130 17 94 240 256 225 156 127 44 82 172 96 105 53 89 134 65 107 257 212 101 152 188 124 92 107 77 175 287 43 45 190 98 141 157 235 259 127 224 119 275 205 248 276 83 100 115 206 285 128 211 64 11 60 1 66 253 202 237 245 194 108 5 64 229 116 84 267 256 45 249 24 224 228 238 102 139 3 149 106 149 286 56 100 165 243 99 237 65 157 5 26 210 6 122 118 217 27 17 203 44 153 116 13 193 50 116 122 286 236 7 268 63 242 171 59 123 214 125 238 52 102 30 40 252 215 3 220 50 66 215 183 127 153 45 69 117 121 119 95 9 145 167 229 166 121 81 76 188 53 18 190 148 178 260 55 113 61 218 85 195 145 276 192 63 12 97 142 194 217 98 250 120 132 150 273 1 125 20 285 19 118 37 120 203 94 60 219 122 47 273 110 88 206 176 165 25 43 154 283 284 32 14 12 265 161 15 179 117 138 75 260 164 76 247 109 101 261 151 21 272 253 143 181 32 123 105 162 52 31 245 123 34 218 135 232 248 96 46 286 6 63 62 134 245 14 71 32 244 86 182 90 12 47 105 91 108 244 27 126 7 230 44 262 79 199 84 196 23 128 31 27 197 240 17 262 259 236 187 16 166 62 25 282 117 180 175 178 80 18 10 241 75 151 201 179 67 252 35 255 117 71 82 281 189 2 233 235 41 71 141 48 272 73 236 78 53 269 171 168 86 111 16 95 118 108 64 120 23 187 87 110 268 243 279 274 168 266 148 119 204 261 42 58 86 73 127 115 26 89 25 102 80 77 66 35 146 24 44 191 135 123 285 199 155 140 99 57 28 54 185 42 276 12 156 198 118 288 101 223 132 41 180 104 234 163 219 13 84 87 219 231 140 170 1 234 272 182 199 264 233 126 237 174 250 191 206 67 72 128 152 8 87 278 287 223 241 4 77 284 91 229 225 47 164 147 191 26 30 99 19 9 74 93 23 78 283 213 88 97 213 268 4 27 88 277 120 82 113 170 181 271 86 2 53 198 227 251 287 114 278 107 186 138 184 223 61 97 104 175 107 6 231 81 114 207 163 110 50 187 196 73 165 134 136 51 174 11 98 20 176 56 221 146 263 137 88 26 139 62 205 189 220 29 112 74 273 60 51 103 67 22 91 49 188 233 55 4 257 32 64 49 79 270 158 113 111 255 58 15 288 210 213 ^'}},
+ {OUT=>'A8478DF406F179FD4EF97F4574D7F99EA1CE9EB8'}],
+ ['211', {IN=> {f=> '624 1 28 220 36 170 238 197 169 72 54 41 237 158 26 234 92 145 95 155 87 190 243 208 200 250 48 21 90 215 40 71 178 188 109 196 130 219 216 206 51 16 23 5 48 6 158 97 55 278 201 55 207 90 286 151 130 234 148 34 36 226 127 138 240 112 2 38 141 250 104 37 31 159 207 19 175 92 201 274 96 31 230 28 205 104 52 126 114 192 229 152 225 103 90 230 262 26 108 86 39 32 35 60 147 10 278 216 277 35 75 79 255 100 136 254 5 267 185 99 41 95 226 71 249 9 168 252 90 144 56 12 249 228 57 193 34 21 4 172 153 30 135 159 136 35 116 36 241 59 93 225 32 106 171 43 66 238 268 280 131 110 1 162 161 122 142 14 179 283 141 265 36 155 16 79 184 279 77 198 45 52 182 3 133 173 192 10 263 121 32 50 282 102 122 198 30 120 227 18 213 196 59 108 157 150 91 91 20 199 140 84 124 199 69 263 65 143 109 48 62 47 201 126 28 149 215 111 182 74 244 69 248 133 25 124 128 248 204 9 183 184 208 256 139 279 92 130 163 37 265 270 266 75 8 144 204 80 4 243 264 89 191 119 188 38 85 71 163 256 154 211 210 115 83 14 108 172 82 209 76 103 176 273 276 67 43 10 59 37 46 91 35 131 258 69 44 176 202 165 171 277 177 7 34 240 183 113 97 70 83 29 40 67 129 53 73 78 89 120 8 2 109 252 19 33 160 246 289 13 54 97 126 99 260 111 167 142 289 247 38 156 55 222 22 114 263 50 211 281 226 142 70 68 224 212 15 274 25 210 171 262 245 179 212 30 206 270 195 254 239 88 81 28 1 147 66 167 157 221 202 150 76 159 65 214 220 107 281 7 253 129 124 57 137 145 80 60 132 78 160 231 67 58 232 177 22 129 68 168 33 74 40 275 262 174 68 153 101 246 218 192 158 41 166 47 257 15 259 220 92 59 52 268 46 20 214 72 39 236 282 46 106 257 249 80 279 21 19 104 271 15 55 136 269 100 222 7 182 18 65 128 14 93 240 254 224 156 126 43 81 170 96 102 51 87 134 64 104 256 210 100 151 186 123 89 105 76 174 287 42 42 190 95 140 155 235 258 125 223 117 273 205 246 274 81 99 112 206 285 127 209 61 8 58 288 66 253 200 235 243 193 105 5 63 228 113 82 265 255 44 247 23 224 227 237 102 137 3 148 105 147 285 56 98 165 242 98 236 63 157 2 23 209 5 119 117 217 26 15 203 41 151 115 12 193 49 116 122 284 236 7 268 61 242 169 57 122 213 125 238 49 101 27 39 251 214 1 218 50 63 213 181 127 153 45 67 114 121 118 93 6 143 165 227 166 118 78 74 188 53 17 189 148 176 258 54 112 58 217 82 194 144 275 191 141 ^'}},
+ {OUT=>'248E58CF09A372114FC2F93B09C5FC14F3D0059E'}],
+ ['212', {IN=> {f=> '628 1 3 97 139 194 211 92 250 117 132 147 267 290 119 14 282 13 118 37 111 200 94 60 216 119 47 270 110 85 203 173 159 16 43 148 277 278 29 5 12 262 158 6 176 117 286 135 72 257 164 76 241 106 101 261 148 18 266 247 143 178 32 117 99 159 49 31 245 123 31 212 135 226 245 90 43 286 289 60 62 131 242 11 65 23 244 80 176 84 6 38 105 91 102 238 27 123 290 224 38 259 79 199 84 193 14 128 25 21 191 237 17 256 259 233 187 10 160 59 19 276 114 174 169 175 74 18 7 235 69 145 198 179 58 252 32 255 111 62 82 278 183 285 230 229 32 68 135 39 269 67 230 75 44 263 168 165 86 108 16 92 112 105 58 114 20 181 78 107 265 237 276 268 162 266 142 119 201 258 36 52 77 64 118 109 26 80 22 96 80 71 60 29 143 24 44 191 132 114 279 193 152 140 99 54 25 54 179 42 276 9 150 192 109 285 92 217 129 35 180 101 228 160 213 7 81 81 219 231 134 167 1 231 272 179 196 264 227 117 237 171 244 185 200 61 72 119 152 2 87 272 284 220 241 1 77 284 82 229 219 44 158 144 188 20 27 90 10 6 71 93 17 69 283 210 82 91 207 262 4 18 79 271 120 73 113 164 181 265 83 288 50 195 221 251 281 108 275 104 186 138 184 223 61 88 95 175 107 6 225 81 114 207 157 101 41 184 190 73 162 128 130 45 168 11 98 11 170 47 221 146 257 131 88 23 139 56 199 189 217 283 23 106 68 273 51 51 100 64 13 85 49 185 233 49 290 257 26 64 46 73 267 152 107 111 249 58 9 288 204 183 26 218 34 170 234 197 169 70 50 41 233 154 22 234 92 145 93 155 81 186 243 208 200 248 48 21 86 213 40 69 178 186 105 196 126 215 214 204 45 14 23 1 44 4 156 91 53 274 199 51 205 88 282 151 130 232 144 34 32 222 123 136 236 112 34 137 246 100 31 25 159 203 19 171 90 197 274 94 27 228 22 201 104 48 126 110 190 227 150 225 97 90 230 262 20 286 102 84 39 26 31 58 147 8 278 216 273 35 75 77 251 94 132 252 291 267 185 95 37 95 224 71 247 5 166 250 84 144 50 8 245 228 55 189 30 15 172 149 28 133 157 134 29 110 36 239 53 87 223 28 100 169 37 62 236 266 280 131 104 291 162 161 118 142 14 177 281 141 263 30 153 12 75 182 275 71 198 41 46 178 291 129 173 192 4 261 115 30 48 280 98 116 194 24 116 227 12 213 194 57 104 153 150 87 85 16 197 136 82 124 195 67 263 63 141 109 42 56 45 201 120 24 149 215 109 180 68 240 63 246 133 19 122 126 248 202 9 183 180 206 252 137 279 88 128 163 33 265 270 264 73 8 140 204 78 2 241 76 ^'}},
+ {OUT=>'F15767DE91796A6816977EFA4FCED4B7FD9B8A57'}],
+ ['213', {IN=> {f=> '622 0 89 183 111 180 34 85 59 159 256 154 207 210 115 75 10 108 168 78 209 68 103 176 269 272 55 35 10 51 33 38 87 31 123 258 69 36 172 202 161 171 277 169 3 22 236 179 109 93 70 83 29 36 67 121 49 61 74 85 116 2 97 244 11 33 160 246 285 1 42 89 118 87 260 99 159 134 289 247 38 152 55 222 14 110 255 42 211 277 226 138 62 64 216 204 11 270 25 206 163 258 241 171 212 30 198 266 195 254 239 84 69 28 283 143 54 167 153 217 194 142 64 151 65 206 220 99 281 293 249 125 116 57 137 137 72 48 128 78 152 227 63 54 232 177 22 129 68 168 21 74 28 275 254 174 60 149 93 242 218 184 158 37 162 39 249 3 251 212 80 59 52 260 34 20 214 60 27 228 282 46 106 253 249 68 275 17 15 100 271 15 43 136 269 100 214 289 182 14 53 120 2 89 240 246 220 156 122 39 77 162 96 90 43 79 134 60 92 252 202 96 147 178 119 77 97 72 170 287 38 30 190 83 136 147 235 254 117 219 109 265 205 238 266 73 95 100 206 285 123 201 49 290 50 280 66 253 192 227 235 189 93 5 59 224 101 74 257 251 40 239 19 224 223 233 102 129 3 144 101 139 281 56 90 165 238 94 232 55 157 284 11 205 1 107 113 217 22 7 203 29 143 111 8 193 45 116 122 276 236 7 268 53 242 161 49 118 209 125 238 37 97 15 35 247 210 287 210 50 51 205 173 127 153 45 59 102 121 114 85 288 135 157 219 166 106 66 66 188 53 13 185 148 168 250 50 108 46 213 70 190 140 271 187 63 291 97 137 194 207 88 250 115 132 145 263 290 115 10 280 9 118 37 105 198 94 60 214 117 47 268 110 83 201 171 155 10 43 144 273 274 27 293 12 260 156 174 117 284 133 70 255 164 76 237 104 101 261 146 16 262 243 143 176 32 113 95 157 47 31 245 123 29 208 135 222 243 86 41 286 285 58 62 129 240 9 61 17 244 76 172 80 2 32 105 91 98 234 27 121 286 220 34 257 79 199 84 191 8 128 21 17 187 235 17 252 259 231 187 6 156 57 15 272 112 170 165 173 70 18 5 231 65 141 196 179 52 252 30 255 107 56 82 276 179 281 228 225 26 66 131 33 267 63 226 73 38 259 166 163 86 106 16 90 108 103 54 110 18 177 72 105 263 233 274 264 158 266 138 119 199 256 32 48 71 58 112 105 26 74 20 92 80 67 56 25 141 24 44 191 130 108 275 189 150 140 99 52 23 54 175 42 276 7 146 188 103 283 86 213 127 31 180 99 224 158 209 3 79 77 219 231 130 165 1 229 272 177 194 264 223 111 237 169 240 181 196 57 72 113 152 292 87 268 282 218 241 293 77 284 76 229 80 ^'}},
+ {OUT=>'36A6BC5E680E15675D9696338C88B36248BBBAF4'}],
+ ['214', {IN=> {f=> '635 1 40 150 140 184 12 23 78 294 2 67 93 9 57 283 206 74 83 199 254 4 6 67 263 120 61 113 156 181 257 79 284 46 191 213 251 273 100 271 100 186 138 184 223 61 76 83 175 107 6 217 81 114 207 149 89 29 180 182 73 158 120 122 37 160 11 98 295 162 35 221 146 249 123 88 19 139 48 191 189 213 275 15 98 60 273 39 51 96 60 1 77 49 181 233 41 286 257 18 64 42 65 263 144 99 111 241 58 1 288 196 179 22 214 30 170 226 197 169 66 42 41 225 146 14 234 92 145 89 155 69 178 243 208 200 244 48 21 78 209 40 65 178 182 97 196 118 207 210 200 33 10 23 289 36 152 79 49 266 195 43 201 84 274 151 130 228 136 34 24 214 115 132 228 112 292 26 129 238 92 19 13 159 195 19 163 86 189 274 90 19 224 10 193 104 40 126 102 186 223 146 225 85 90 230 262 8 278 90 80 39 14 23 54 147 4 278 216 265 35 75 73 243 82 124 248 283 267 185 87 29 95 220 71 243 293 162 246 72 144 38 237 228 51 181 22 3 288 172 141 24 129 153 130 17 98 36 235 41 75 219 20 88 165 25 54 232 262 280 131 92 291 162 161 110 142 14 173 277 141 259 18 149 4 67 178 267 59 198 33 34 170 287 121 173 192 288 257 103 26 44 276 90 104 186 12 108 227 213 190 53 96 145 150 79 73 8 193 128 78 124 187 63 263 59 137 109 30 44 41 201 108 16 149 215 105 176 56 232 51 242 133 7 118 122 248 198 9 183 172 202 244 133 279 80 124 163 25 265 270 260 69 8 132 204 74 294 237 252 89 179 107 176 32 85 53 157 256 154 205 210 115 71 8 108 166 76 209 64 103 176 267 270 49 31 10 47 31 34 85 29 119 258 69 32 170 202 159 171 277 165 1 16 234 177 107 91 70 83 29 34 67 117 47 55 72 83 114 292 2 91 240 7 33 160 246 283 291 36 85 114 81 260 93 155 130 289 247 38 150 55 222 10 108 251 38 211 275 226 136 58 62 212 200 9 268 25 204 159 256 239 167 212 30 194 264 195 254 239 82 63 28 279 141 48 167 151 215 190 138 58 147 65 202 220 95 281 291 247 123 112 57 137 133 68 42 126 78 148 225 61 52 232 177 22 129 68 168 15 74 22 275 250 174 56 147 89 240 218 180 158 35 160 35 245 293 247 208 74 59 52 256 28 20 214 54 21 224 282 46 106 251 249 62 273 15 13 98 271 15 37 136 269 100 210 285 182 12 47 116 292 87 240 242 218 156 120 37 75 158 96 84 39 75 134 58 86 250 198 94 145 174 117 71 93 70 168 287 36 24 190 77 134 143 235 252 113 217 105 261 205 234 262 69 93 94 206 285 121 197 43 286 46 276 66 253 188 223 231 187 87 5 57 222 95 285 ^'}},
+ {OUT=>'4DEA6251B2A6DF017A8093AB066EE3863A4EC369'}],
+ ['215', {IN=> {f=> '636 0 251 248 37 233 16 224 220 230 102 123 3 141 98 133 278 56 84 165 235 91 229 49 157 278 2 202 295 98 110 217 19 1 203 20 137 108 5 193 42 116 122 270 236 7 268 47 242 155 43 115 206 125 238 28 94 6 32 244 207 284 204 50 42 199 167 127 153 45 53 93 121 111 79 282 129 151 213 166 97 57 60 188 53 10 182 148 162 244 47 105 37 210 61 187 137 268 184 63 285 97 134 194 201 82 250 112 132 142 257 290 109 4 277 3 118 37 96 195 94 60 211 114 47 265 110 80 198 168 149 1 43 138 267 268 24 287 12 257 153 288 171 117 281 130 67 252 164 76 231 101 101 261 143 13 256 237 143 173 32 107 89 154 44 31 245 123 26 202 135 216 240 80 38 286 279 55 62 126 237 6 55 8 244 70 166 74 293 23 105 91 92 228 27 118 280 214 28 254 79 199 84 188 296 128 15 11 181 232 17 246 259 228 187 150 54 9 266 109 164 159 170 64 18 2 225 59 135 193 179 43 252 27 255 101 47 82 273 173 275 225 219 17 63 125 24 264 57 220 70 29 253 163 160 86 103 16 87 102 100 48 104 15 171 63 102 260 227 271 258 152 266 132 119 196 253 26 42 62 49 103 99 26 65 17 86 80 61 50 19 138 24 44 191 127 99 269 183 147 140 99 49 20 54 169 42 276 4 140 182 94 280 77 207 124 25 180 96 218 155 203 294 76 71 219 231 124 162 1 226 272 174 191 264 217 102 237 166 234 175 190 51 72 104 152 289 87 262 279 215 241 293 77 284 67 229 209 39 148 139 183 10 22 75 292 1 66 93 7 54 283 205 72 81 197 252 4 3 64 261 120 58 113 154 181 255 78 283 45 190 211 251 271 98 270 99 186 138 184 223 61 73 80 175 107 6 215 81 114 207 147 86 26 179 180 73 157 118 120 35 158 11 98 293 160 32 221 146 247 121 88 18 139 46 189 189 212 273 13 96 58 273 36 51 95 59 295 75 49 180 233 39 285 257 16 64 41 63 262 142 97 111 239 58 296 288 194 178 21 213 29 170 224 197 169 65 40 41 223 144 12 234 92 145 88 155 66 176 243 208 200 243 48 21 76 208 40 64 178 181 95 196 116 205 209 199 30 9 23 288 34 296 151 76 48 264 194 41 200 83 272 151 130 227 134 34 22 212 113 131 226 112 292 24 127 236 90 16 10 159 193 19 161 85 187 274 89 17 223 7 191 104 38 126 100 185 222 145 225 82 90 230 262 5 276 87 79 39 11 21 53 147 3 278 216 263 35 75 72 241 79 122 247 281 267 185 85 27 95 219 71 242 292 161 245 69 144 35 295 235 228 50 179 20 287 172 139 23 128 152 129 14 95 36 234 38 72 218 18 85 164 22 52 231 261 280 131 89 291 162 161 108 142 14 172 276 91 ^'}},
+ {OUT=>'D30E70E357D57E3D82CA554B8A3D58DFF528FA94'}],
+ ['216', {IN=> {f=> '635 1 256 9 146 297 61 175 261 50 198 27 25 164 284 115 173 192 282 254 94 23 41 273 84 95 180 3 102 227 290 213 187 50 90 139 150 73 64 2 190 122 75 124 181 60 263 56 134 109 21 35 38 201 99 10 149 215 102 173 47 226 42 239 133 297 115 119 248 195 9 183 166 199 238 130 279 74 121 163 19 265 270 257 66 8 126 204 71 294 234 246 89 173 101 170 29 85 44 154 256 154 202 210 115 65 5 108 163 73 209 58 103 176 264 267 40 25 10 41 28 28 82 26 113 258 69 26 167 202 156 171 277 159 297 7 231 174 104 88 70 83 29 31 67 111 44 46 69 80 111 289 2 82 234 1 33 160 246 280 285 27 79 108 72 260 84 149 124 289 247 38 147 55 222 4 105 245 32 211 272 226 133 52 59 206 194 6 265 25 201 153 253 236 161 212 30 188 261 195 254 239 79 54 28 273 138 39 167 148 212 184 132 49 141 65 196 220 89 281 288 244 120 106 57 137 127 62 33 123 78 142 222 58 49 232 177 22 129 68 168 6 74 13 275 244 174 50 144 83 237 218 174 158 32 157 29 239 287 241 202 65 59 52 250 19 20 214 45 12 218 282 46 106 248 249 53 270 12 10 95 271 15 28 136 269 100 204 279 182 9 38 110 286 84 240 236 215 156 117 34 72 152 96 75 33 69 134 55 77 247 192 91 142 168 114 62 87 67 165 287 33 15 190 68 131 137 235 249 107 214 99 255 205 228 256 63 90 85 206 285 118 191 34 280 40 270 66 253 182 217 225 184 78 5 54 219 86 64 247 246 35 229 14 224 218 228 102 119 3 139 96 129 276 56 80 165 233 89 227 45 157 274 295 200 295 92 108 217 17 296 203 14 133 106 3 193 40 116 122 266 236 7 268 43 242 151 39 113 204 125 238 22 92 30 242 205 282 200 50 36 195 163 127 153 45 49 87 121 109 75 278 125 147 209 166 91 51 56 188 53 8 180 148 158 240 45 103 31 208 55 185 135 266 182 63 281 97 132 194 197 78 250 110 132 140 253 290 105 275 298 118 37 90 193 94 60 209 112 47 263 110 78 196 166 145 294 43 134 263 264 22 283 12 255 151 284 169 117 279 128 65 250 164 76 227 99 101 261 141 11 252 233 143 171 32 103 85 152 42 31 245 123 24 198 135 212 238 76 36 286 275 53 62 124 235 4 51 2 244 66 162 70 291 17 105 91 88 224 27 116 276 210 24 252 79 199 84 186 292 128 11 7 177 230 17 242 259 226 187 295 146 52 5 262 107 160 155 168 60 18 221 55 131 191 179 37 252 25 255 97 41 82 271 169 271 223 215 11 61 121 18 262 53 216 68 23 249 161 158 86 101 16 85 98 98 44 100 13 167 57 100 258 223 269 254 148 266 128 119 194 251 22 38 56 43 275 ^'}},
+ {OUT=>'70CA84D827F7FD61446233F88CF2F990B0F3E2AA'}],
+ ['217', {IN=> {f=> '642 0 91 26 53 13 78 80 53 42 11 134 24 44 191 123 87 261 175 143 140 99 45 16 54 161 42 276 132 174 82 276 65 199 120 17 180 92 210 151 195 290 72 63 219 231 116 158 1 222 272 170 187 264 209 90 237 162 226 167 182 43 72 92 152 285 87 254 275 211 241 293 77 284 55 229 201 35 140 135 179 2 18 63 284 298 62 93 300 42 283 201 64 73 189 244 4 292 52 253 120 46 113 146 181 247 74 279 41 186 203 251 263 90 266 95 186 138 184 223 61 61 68 175 107 6 207 81 114 207 139 74 14 175 172 73 153 110 112 27 150 11 98 285 152 20 221 146 239 113 88 14 139 38 181 189 208 265 5 88 50 273 24 51 91 55 287 67 49 176 233 31 281 257 8 64 37 55 258 134 89 111 231 58 292 288 186 174 17 209 25 170 216 197 169 61 32 41 215 136 4 234 92 145 84 155 54 168 243 208 200 239 48 21 68 204 40 60 178 177 87 196 108 197 205 195 18 5 23 284 26 296 147 64 44 256 190 33 196 79 264 151 130 223 126 34 14 204 105 127 218 112 292 16 119 228 82 4 299 159 185 19 153 81 179 274 85 9 219 296 183 104 30 126 92 181 218 141 225 70 90 230 262 294 268 75 75 39 300 13 49 147 300 278 216 255 35 75 68 233 67 114 243 273 267 185 77 19 95 215 71 238 288 157 241 57 144 23 291 227 228 46 171 12 289 283 172 131 19 124 148 125 2 83 36 230 26 60 214 10 73 160 10 44 227 257 280 131 77 291 162 161 100 142 14 168 272 141 254 3 144 295 57 173 257 44 198 23 19 160 282 111 173 192 278 252 88 21 39 271 80 89 176 298 98 227 286 213 185 48 86 135 150 69 58 299 188 118 73 124 177 58 263 54 132 109 15 29 36 201 93 6 149 215 100 171 41 222 36 237 133 293 113 117 248 193 9 183 162 197 234 128 279 70 119 163 15 265 270 255 64 8 122 204 69 294 232 242 89 169 97 166 27 85 38 152 256 154 200 210 115 61 3 108 161 71 209 54 103 176 262 265 34 21 10 37 26 24 80 24 109 258 69 22 165 202 154 171 277 155 297 1 229 172 102 86 70 83 29 29 67 107 42 40 67 78 109 287 2 76 230 298 33 160 246 278 281 21 75 104 66 260 78 145 120 289 247 38 145 55 222 103 241 28 211 270 226 131 48 57 202 190 4 263 25 199 149 251 234 157 212 30 184 259 195 254 239 77 48 28 269 136 33 167 146 210 180 128 43 137 65 192 220 85 281 286 242 118 102 57 137 123 58 27 121 78 138 220 56 47 232 177 22 129 68 168 74 7 275 240 174 46 142 79 235 218 170 158 30 155 25 235 283 237 198 59 59 52 246 13 20 214 39 6 214 282 46 106 246 249 47 268 10 8 93 271 15 22 136 269 100 200 275 42 ^'}},
+ {OUT=>'8D500C9CFDE0288530A2106B70BED39326C52C3C'}],
+ ['218', {IN=> {f=> '644 0 6 29 104 280 81 240 230 212 156 114 31 69 146 96 66 27 63 134 52 68 244 186 88 139 162 111 53 81 64 162 287 30 6 190 59 128 131 235 246 101 211 93 249 205 222 250 57 87 76 206 285 115 185 25 274 34 264 66 253 176 211 219 181 69 5 51 216 77 58 241 243 32 223 11 224 215 225 102 113 3 136 93 123 273 56 74 165 230 86 224 39 157 268 289 197 295 83 105 217 14 293 203 5 127 103 193 37 116 122 260 236 7 268 37 242 145 33 110 201 125 238 13 89 293 27 239 202 279 194 50 27 189 157 127 153 45 43 78 121 106 69 272 119 141 203 166 82 42 50 188 53 5 177 148 152 234 42 100 22 205 46 182 132 263 179 63 275 97 129 194 191 72 250 107 132 137 247 290 99 296 272 295 118 37 81 190 94 60 206 109 47 260 110 75 193 163 139 288 43 128 257 258 19 277 12 252 148 278 166 117 276 125 62 247 164 76 221 96 101 261 138 8 246 227 143 168 32 97 79 149 39 31 245 123 21 192 135 206 235 70 33 286 269 50 62 121 232 1 45 295 244 60 156 64 288 8 105 91 82 218 27 113 270 204 18 249 79 199 84 183 286 128 5 1 171 227 17 236 259 223 187 292 140 49 301 256 104 154 149 165 54 18 299 215 49 125 188 179 28 252 22 255 91 32 82 268 163 265 220 209 2 58 115 9 259 47 210 65 14 243 158 155 86 98 16 82 92 95 38 94 10 161 48 97 255 217 266 248 142 266 122 119 191 248 16 32 47 34 88 89 26 50 12 76 80 51 40 9 133 24 44 191 122 84 259 173 142 140 99 44 15 54 159 42 276 301 130 172 79 275 62 197 119 15 180 91 208 150 193 289 71 61 219 231 114 157 1 221 272 169 186 264 207 87 237 161 224 165 180 41 72 89 152 284 87 252 274 210 241 293 77 284 52 229 199 34 138 134 178 17 60 282 298 61 93 299 39 283 200 62 71 187 242 4 290 49 251 120 43 113 144 181 245 73 278 40 185 201 251 261 88 265 94 186 138 184 223 61 58 65 175 107 6 205 81 114 207 137 71 11 174 170 73 152 108 110 25 148 11 98 283 150 17 221 146 237 111 88 13 139 36 179 189 207 263 3 86 48 273 21 51 90 54 285 65 49 175 233 29 280 257 6 64 36 53 257 132 87 111 229 58 291 288 184 173 16 208 24 170 214 197 169 60 30 41 213 134 2 234 92 145 83 155 51 166 243 208 200 238 48 21 66 203 40 59 178 176 85 196 106 195 204 194 15 4 23 283 24 296 146 61 43 254 189 31 195 78 262 151 130 222 124 34 12 202 103 126 216 112 292 14 117 226 80 1 297 159 183 19 151 80 177 274 84 7 218 294 181 104 28 126 90 180 217 140 225 67 90 230 262 292 266 72 74 39 298 11 48 147 300 278 216 253 265 ^'}},
+ {OUT=>'F3D4D139EDFC24596377BC97A96FB7621F27FFC7'}],
+ ['219', {IN=> {f=> '638 1 75 65 227 58 108 240 267 267 185 71 13 95 212 71 235 285 154 238 48 144 14 288 221 228 43 165 6 283 280 172 125 16 121 145 122 297 74 36 227 17 51 211 4 64 157 1 38 224 254 280 131 68 291 162 161 94 142 14 165 269 141 251 298 141 292 51 170 251 35 198 17 10 154 279 105 173 192 272 249 79 18 36 268 74 80 170 292 92 227 280 213 182 45 80 129 150 63 49 296 185 112 70 124 171 55 263 51 129 109 6 20 33 201 84 149 215 97 168 32 216 27 234 133 287 110 114 248 190 9 183 156 194 228 125 279 64 116 163 9 265 270 252 61 8 116 204 66 294 229 236 89 163 91 160 24 85 29 149 256 154 197 210 115 55 108 158 68 209 48 103 176 259 262 25 15 10 31 23 18 77 21 103 258 69 16 162 202 151 171 277 149 297 296 226 169 99 83 70 83 29 26 67 101 39 31 64 75 106 284 2 67 224 295 33 160 246 275 275 12 69 98 57 260 69 139 114 289 247 38 142 55 222 298 100 235 22 211 267 226 128 42 54 196 184 1 260 25 196 143 248 231 151 212 30 178 256 195 254 239 74 39 28 263 133 24 167 143 207 174 122 34 131 65 186 220 79 281 283 239 115 96 57 137 117 52 18 118 78 132 217 53 44 232 177 22 129 68 168 295 74 302 275 234 174 40 139 73 232 218 164 158 27 152 19 229 277 231 192 50 59 52 240 4 20 214 30 301 208 282 46 106 243 249 38 265 7 5 90 271 15 13 136 269 100 194 269 182 4 23 100 276 79 240 226 210 156 112 29 67 142 96 60 23 59 134 50 62 242 182 86 137 158 109 47 77 62 160 287 28 190 53 126 127 235 244 97 209 89 245 205 218 246 53 85 70 206 285 113 181 19 270 30 260 66 253 172 207 215 179 63 5 49 214 71 54 237 241 30 219 9 224 213 223 102 109 3 134 91 119 271 56 70 165 228 84 222 35 157 264 285 195 295 77 103 217 12 291 203 303 123 101 302 193 35 116 122 256 236 7 268 33 242 141 29 108 199 125 238 7 87 289 25 237 200 277 190 50 21 185 153 127 153 45 39 72 121 104 65 268 115 137 199 166 76 36 46 188 53 3 175 148 148 230 40 98 16 203 40 180 130 261 177 63 271 97 127 194 187 68 250 105 132 135 243 290 95 294 270 293 118 37 75 188 94 60 204 107 47 258 110 73 191 161 135 284 43 124 253 254 17 273 12 250 146 274 164 117 274 123 60 245 164 76 217 94 101 261 136 6 242 223 143 166 32 93 75 147 37 31 245 123 19 188 135 202 233 66 31 286 265 48 62 119 230 303 41 291 244 56 152 60 286 2 105 91 78 214 27 111 266 200 14 247 79 199 84 181 282 128 1 301 167 225 17 232 259 221 187 290 136 47 299 252 102 150 145 163 157 ^'}},
+ {OUT=>'5509BAFFAC6D507860CEFC5AB5832CB63CD4B687'}],
+ ['220', {IN=> {f=> '653 0 18 299 207 41 117 184 179 16 252 18 255 83 20 82 264 155 257 216 201 296 54 107 303 255 39 202 61 2 235 154 151 86 94 16 78 84 91 30 86 6 153 36 93 251 209 262 240 134 266 114 119 187 244 8 24 35 22 76 81 26 38 8 68 80 43 32 1 129 24 44 191 118 72 251 165 138 140 99 40 11 54 151 42 276 301 122 164 67 271 50 189 115 7 180 87 200 146 185 285 67 53 219 231 106 153 1 217 272 165 182 264 199 75 237 157 216 157 172 33 72 77 152 280 87 244 270 206 241 293 77 284 40 229 191 30 130 130 174 298 13 48 274 298 57 93 295 27 283 196 54 63 179 234 4 282 37 243 120 31 113 136 181 237 69 274 36 181 193 251 253 80 261 90 186 138 184 223 61 46 53 175 107 6 197 81 114 207 129 59 305 170 162 73 148 100 102 17 140 11 98 275 142 5 221 146 229 103 88 9 139 28 171 189 203 255 301 78 40 273 9 51 86 50 277 57 49 171 233 21 276 257 304 64 32 45 253 124 79 111 221 58 287 288 176 169 12 204 20 170 206 197 169 56 22 41 205 126 300 234 92 145 79 155 39 158 243 208 200 234 48 21 58 199 40 55 178 172 77 196 98 187 200 190 3 23 279 16 296 142 49 39 246 185 23 191 74 254 151 130 218 116 34 4 194 95 122 208 112 292 6 109 218 72 295 289 159 175 19 143 76 169 274 80 305 214 286 173 104 20 126 82 176 213 136 225 55 90 230 262 284 258 60 70 39 290 3 44 147 300 278 216 245 35 75 63 223 52 104 238 263 267 185 67 9 95 210 71 233 283 152 236 42 144 8 286 217 228 41 161 2 279 278 172 121 14 119 143 120 293 68 36 225 11 45 209 58 155 301 34 222 252 280 131 62 291 162 161 90 142 14 163 267 141 249 294 139 290 47 168 247 29 198 13 4 150 277 101 173 192 268 247 73 16 34 266 70 74 166 288 88 227 276 213 180 43 76 125 150 59 43 294 183 108 68 124 167 53 263 49 127 109 14 31 201 78 302 149 215 95 166 26 212 21 232 133 283 108 112 248 188 9 183 152 192 224 123 279 60 114 163 5 265 270 250 59 8 112 204 64 294 227 232 89 159 87 156 22 85 23 147 256 154 195 210 115 51 304 108 156 66 209 44 103 176 257 260 19 11 10 27 21 14 75 19 99 258 69 12 160 202 149 171 277 145 297 292 224 167 97 81 70 83 29 24 67 97 37 25 62 73 104 282 2 61 220 293 33 160 246 273 271 6 65 94 51 260 63 135 110 289 247 38 140 55 222 296 98 231 18 211 265 226 126 38 52 192 180 305 258 25 194 139 246 229 147 212 30 174 254 195 254 239 72 33 28 259 131 18 167 141 205 170 118 28 127 65 182 220 75 281 281 237 113 92 57 137 113 48 12 116 78 128 215 51 42 232 177 22 129 68 168 291 161 ^'}},
+ {OUT=>'0C0AEA0C2FD7A620C77866B1A177481E26B4F592'}],
+ ['221', {IN=> {f=> '653 0 296 275 228 174 34 136 67 229 218 158 158 24 149 13 223 271 225 186 41 59 52 234 302 20 214 21 295 202 282 46 106 240 249 29 262 4 2 87 271 15 4 136 269 100 188 263 182 1 14 94 270 76 240 220 207 156 109 26 64 136 96 51 17 53 134 47 53 239 176 83 134 152 106 38 71 59 157 287 25 298 190 44 123 121 235 241 91 206 83 239 205 212 240 47 82 61 206 285 110 175 10 264 24 254 66 253 166 201 209 176 54 5 46 211 62 48 231 238 27 213 6 224 210 220 102 103 3 131 88 113 268 56 64 165 225 81 219 29 157 258 279 192 295 68 100 217 9 288 203 297 117 98 302 193 32 116 122 250 236 7 268 27 242 135 23 105 196 125 238 305 84 283 22 234 197 274 184 50 12 179 147 127 153 45 33 63 121 101 59 262 109 131 193 166 67 27 40 188 53 172 148 142 224 37 95 7 200 31 177 127 258 174 63 265 97 124 194 181 62 250 102 132 132 237 290 89 291 267 290 118 37 66 185 94 60 201 104 47 255 110 70 188 158 129 278 43 118 247 248 14 267 12 247 143 268 161 117 271 120 57 242 164 76 211 91 101 261 133 3 236 217 143 163 32 87 69 144 34 31 245 123 16 182 135 196 230 60 28 286 259 45 62 116 227 303 35 285 244 50 146 54 283 300 105 91 72 208 27 108 260 194 8 244 79 199 84 178 276 128 302 298 161 222 17 226 259 218 187 287 130 44 296 246 99 144 139 160 44 18 299 205 39 115 183 179 13 252 17 255 81 17 82 263 153 255 215 199 294 53 105 301 254 37 200 60 306 233 153 150 86 93 16 77 82 90 28 84 5 151 33 92 250 207 261 238 132 266 112 119 186 243 6 22 32 19 73 79 26 35 7 66 80 41 30 306 128 24 44 191 117 69 249 163 137 140 99 39 10 54 149 42 276 301 120 162 64 270 47 187 114 5 180 86 198 145 183 284 66 51 219 231 104 152 1 216 272 164 181 264 197 72 237 156 214 155 170 31 72 74 152 279 87 242 269 205 241 293 77 284 37 229 189 29 128 129 173 297 12 45 272 298 56 93 294 24 283 195 52 61 177 232 4 280 34 241 120 28 113 134 181 235 68 273 35 180 191 251 251 78 260 89 186 138 184 223 61 43 50 175 107 6 195 81 114 207 127 56 303 169 160 73 147 98 100 15 138 11 98 273 140 2 221 146 227 101 88 8 139 26 169 189 202 253 300 76 38 273 6 51 85 49 275 55 49 170 233 19 275 257 303 64 31 43 252 122 77 111 219 58 286 288 174 168 11 203 19 170 204 197 169 55 20 41 203 124 299 234 92 145 78 155 36 156 243 208 200 233 48 21 56 198 40 54 178 171 75 196 96 185 199 189 306 23 278 14 296 141 46 38 244 184 21 190 73 252 151 130 217 114 34 2 192 93 121 206 112 292 4 107 216 70 293 112 ^'}},
+ {OUT=>'149176007FEE58A591E3F00F8DB658B605F8390C'}],
+ ['222', {IN=> {f=> '646 1 159 169 19 137 73 163 274 77 302 211 280 167 104 14 126 76 173 210 133 225 46 90 230 262 278 252 51 67 39 284 306 41 147 300 278 216 239 35 75 60 217 43 98 235 257 267 185 61 3 95 207 71 230 280 149 233 33 144 308 283 211 228 38 155 305 273 275 172 115 11 116 140 117 287 59 36 222 2 36 206 303 49 152 295 28 219 249 280 131 53 291 162 161 84 142 14 160 264 141 246 288 136 287 41 165 241 20 198 7 304 144 274 95 173 192 262 244 64 13 31 263 64 65 160 282 82 227 270 213 177 40 70 119 150 53 34 291 180 102 65 124 161 50 263 46 124 109 300 5 28 201 69 299 149 215 92 163 17 206 12 229 133 277 105 109 248 185 9 183 146 189 218 120 279 54 111 163 308 265 270 247 56 8 106 204 61 294 224 226 89 153 81 150 19 85 14 144 256 154 192 210 115 45 304 108 153 63 209 38 103 176 254 257 10 5 10 21 18 8 72 16 93 258 69 6 157 202 146 171 277 139 297 286 221 164 94 78 70 83 29 21 67 91 34 16 59 70 101 279 2 52 214 290 33 160 246 270 265 306 59 88 42 260 54 129 104 289 247 38 137 55 222 293 95 225 12 211 262 226 123 32 49 186 174 305 255 25 191 133 243 226 141 212 30 168 251 195 254 239 69 24 28 253 128 9 167 138 202 164 112 19 121 65 176 220 69 281 278 234 110 86 57 137 107 42 3 113 78 122 212 48 39 232 177 22 129 68 168 285 74 292 275 224 174 30 134 63 227 218 154 158 22 147 9 219 267 221 182 35 59 52 230 298 20 214 15 291 198 282 46 106 238 249 23 260 2 85 271 15 307 136 269 100 184 259 182 308 8 90 266 74 240 216 205 156 107 24 62 132 96 45 13 49 134 45 47 237 172 81 132 148 104 32 67 57 155 287 23 294 190 38 121 117 235 239 87 204 79 235 205 208 236 43 80 55 206 285 108 171 4 260 20 250 66 253 162 197 205 174 48 5 44 209 56 44 227 236 25 209 4 224 208 218 102 99 3 129 86 109 266 56 60 165 223 79 217 25 157 254 275 190 295 62 98 217 7 286 203 293 113 96 302 193 30 116 122 246 236 7 268 23 242 131 19 103 194 125 238 301 82 279 20 232 195 272 180 50 6 175 143 127 153 45 29 57 121 99 55 258 105 127 189 166 61 21 36 188 53 307 170 148 138 220 35 93 1 198 25 175 125 256 172 63 261 97 122 194 177 58 250 100 132 130 233 290 85 289 265 288 118 37 60 183 94 60 199 102 47 253 110 68 186 156 125 274 43 114 243 244 12 263 12 245 141 264 159 117 269 118 55 240 164 76 207 89 101 261 131 1 232 213 143 161 32 83 65 142 32 31 245 123 14 178 135 192 228 56 26 286 255 43 62 114 225 303 31 281 244 46 142 50 281 296 105 91 238 ^'}},
+ {OUT=>'17C0D7B0256159F3626786FFDB20237AE154FA84'}],
+ ['223', {IN=> {f=> '647 0 200 27 104 252 186 240 79 199 84 174 268 128 298 294 153 218 17 218 259 214 187 283 122 40 292 238 95 136 131 156 36 18 299 197 31 107 179 179 1 252 13 255 73 5 82 259 145 247 211 191 286 49 97 293 250 29 192 56 298 225 149 146 86 89 16 73 74 86 20 76 1 143 21 88 246 199 257 230 124 266 104 119 182 239 309 14 20 7 61 71 26 23 3 58 80 33 22 302 124 24 44 191 113 57 241 155 133 140 99 35 6 54 141 42 276 301 112 154 52 266 35 179 110 308 180 82 190 141 175 280 62 43 219 231 96 148 1 212 272 160 177 264 189 60 237 152 206 147 162 23 72 62 152 275 87 234 265 201 241 293 77 284 25 229 181 25 120 125 169 293 8 33 264 298 52 93 290 12 283 191 44 53 169 224 4 272 22 233 120 16 113 126 181 227 64 269 31 176 183 251 243 70 256 85 186 138 184 223 61 31 38 175 107 6 187 81 114 207 119 44 295 165 152 73 143 90 92 7 130 11 98 265 132 301 221 146 219 93 88 4 139 18 161 189 198 245 296 68 30 273 305 51 81 45 267 47 49 166 233 11 271 257 299 64 27 35 248 114 69 111 211 58 282 288 166 164 7 199 15 170 196 197 169 51 12 41 195 116 295 234 92 145 74 155 24 148 243 208 200 229 48 21 48 194 40 50 178 167 67 196 88 177 195 185 299 306 23 274 6 296 137 34 34 236 180 13 186 69 244 151 130 213 106 34 305 184 85 117 198 112 292 307 99 208 62 285 279 159 165 19 133 71 159 274 75 300 209 276 163 104 10 126 72 171 208 131 225 40 90 230 262 274 248 45 65 39 280 304 39 147 300 278 216 235 35 75 58 213 37 94 233 253 267 185 57 310 95 205 71 228 278 147 231 27 144 304 281 207 228 36 151 303 269 273 172 111 9 114 138 115 283 53 36 220 307 30 204 301 43 150 291 24 217 247 280 131 47 291 162 161 80 142 14 158 262 141 244 284 134 285 37 163 237 14 198 3 300 140 272 91 173 192 258 242 58 11 29 261 60 59 156 278 78 227 266 213 175 38 66 115 150 49 28 289 178 98 63 124 157 48 263 44 122 109 296 310 26 201 63 297 149 215 90 161 11 202 6 227 133 273 103 107 248 183 9 183 142 187 214 118 279 50 109 163 306 265 270 245 54 8 102 204 59 294 222 222 89 149 77 146 17 85 8 142 256 154 190 210 115 41 304 108 151 61 209 34 103 176 252 255 4 1 10 17 16 4 70 14 89 258 69 2 155 202 144 171 277 135 297 282 219 162 92 76 70 83 29 19 67 87 32 10 57 68 99 277 2 46 210 288 33 160 246 268 261 302 55 84 36 260 48 125 100 289 247 38 135 55 222 291 93 221 8 211 260 226 121 28 47 182 170 305 253 25 189 129 241 224 137 212 30 164 249 195 254 239 86 ^'}},
+ {OUT=>'741A58618ABEB1D983D67AFDCBC49AA397A3B8E0'}],
+ ['224', {IN=> {f=> '665 0 15 28 247 125 167 135 199 158 106 10 115 65 170 220 63 281 275 231 107 80 57 137 101 36 306 110 78 116 209 45 36 232 177 22 129 68 168 279 74 286 275 218 174 24 131 57 224 218 148 158 19 144 3 213 261 215 176 26 59 52 224 292 20 214 6 285 192 282 46 106 235 249 14 257 311 309 82 271 15 301 136 269 100 178 253 182 308 311 84 260 71 240 210 202 156 104 21 59 126 96 36 7 43 134 42 38 234 166 78 129 142 101 23 61 54 152 287 20 288 190 29 118 111 235 236 81 201 73 229 205 202 230 37 77 46 206 285 105 165 307 254 14 244 66 253 156 191 199 171 39 5 41 206 47 38 221 233 22 203 1 224 205 215 102 93 3 126 83 103 263 56 54 165 220 76 214 19 157 248 269 187 295 53 95 217 4 283 203 287 107 93 302 193 27 116 122 240 236 7 268 17 242 125 13 100 191 125 238 295 79 273 17 229 192 269 174 50 309 169 137 127 153 45 23 48 121 96 49 252 99 121 183 166 52 12 30 188 53 307 167 148 132 214 32 90 304 195 16 172 122 253 169 63 255 97 119 194 171 52 250 97 132 127 227 290 79 286 262 285 118 37 51 180 94 60 196 99 47 250 110 65 183 153 119 268 43 108 237 238 9 257 12 242 138 258 156 117 266 115 52 237 164 76 201 86 101 261 128 310 226 207 143 158 32 77 59 139 29 31 245 123 11 172 135 186 225 50 23 286 249 40 62 111 222 303 25 275 244 40 136 44 278 290 105 91 62 198 27 103 250 184 310 239 79 199 84 173 266 128 297 293 151 217 17 216 259 213 187 282 120 39 291 236 94 134 129 155 34 18 299 195 29 105 178 179 310 252 12 255 71 2 82 258 143 245 210 189 284 48 95 291 249 27 190 55 296 223 148 145 86 88 16 72 72 85 18 74 141 18 87 245 197 256 228 122 266 102 119 181 238 308 12 17 4 58 69 26 20 2 56 80 31 20 301 123 24 44 191 112 54 239 153 132 140 99 34 5 54 139 42 276 301 110 152 49 265 32 177 109 307 180 81 188 140 173 279 61 41 219 231 94 147 1 211 272 159 176 264 187 57 237 151 204 145 160 21 72 59 152 274 87 232 264 200 241 293 77 284 22 229 179 24 118 124 168 292 7 30 262 298 51 93 289 9 283 190 42 51 167 222 4 270 19 231 120 13 113 124 181 225 63 268 30 175 181 251 241 68 255 84 186 138 184 223 61 28 35 175 107 6 185 81 114 207 117 41 293 164 150 73 142 88 90 5 128 11 98 263 130 299 221 146 217 91 88 3 139 16 159 189 197 243 295 66 28 273 303 51 80 44 265 45 49 165 233 9 270 257 298 64 26 33 247 112 67 111 209 58 281 288 164 163 6 198 14 170 194 197 169 50 10 41 193 114 294 234 92 145 73 155 21 146 243 208 200 228 48 21 46 193 40 49 178 166 65 196 86 175 194 184 297 306 23 273 206 ^'}},
+ {OUT=>'B738D6B3409EB9ED2F1719B84D13F7C36169CDEC'}],
+ ['225', {IN=> {f=> '641 0 296 134 25 31 230 177 7 183 66 238 151 130 210 100 34 302 178 79 114 192 112 292 304 93 202 56 279 273 159 159 19 127 68 153 274 72 297 206 270 157 104 4 126 66 168 205 128 225 31 90 230 262 268 242 36 62 39 274 301 36 147 300 278 216 229 35 75 55 207 28 88 230 247 267 185 51 307 95 202 71 225 275 144 228 18 144 298 278 201 228 33 145 300 263 270 172 105 6 111 135 112 277 44 36 217 301 21 201 298 34 147 285 18 214 244 280 131 38 291 162 161 74 142 14 155 259 141 241 278 131 282 31 160 231 5 198 311 294 134 269 85 173 192 252 239 49 8 26 258 54 50 150 272 72 227 260 213 172 35 60 109 150 43 19 286 175 92 60 124 151 45 263 41 119 109 290 304 23 201 54 294 149 215 87 158 2 196 311 224 133 267 100 104 248 180 9 183 136 184 208 115 279 44 106 163 303 265 270 242 51 8 96 204 56 294 219 216 89 143 71 140 14 85 313 139 256 154 187 210 115 35 304 108 148 58 209 28 103 176 249 252 309 309 10 11 13 312 67 11 83 258 69 310 152 202 141 171 277 129 297 276 216 159 89 73 70 83 29 16 67 81 29 1 54 65 96 274 2 37 204 285 33 160 246 265 255 296 49 78 27 260 39 119 94 289 247 38 132 55 222 288 90 215 2 211 257 226 118 22 44 176 164 305 250 25 186 123 238 221 131 212 30 158 246 195 254 239 64 9 28 243 123 308 167 133 197 154 102 4 111 65 166 220 59 281 273 229 105 76 57 137 97 32 302 108 78 112 207 43 34 232 177 22 129 68 168 275 74 282 275 214 174 20 129 53 222 218 144 158 17 142 313 209 257 211 172 20 59 52 220 288 20 214 281 188 282 46 106 233 249 8 255 311 309 80 271 15 297 136 269 100 174 249 182 308 307 80 256 69 240 206 200 156 102 19 57 122 96 30 3 39 134 40 32 232 162 76 127 138 99 17 57 52 150 287 18 284 190 23 116 107 235 234 77 199 69 225 205 198 226 33 75 40 206 285 103 161 303 250 10 240 66 253 152 187 195 169 33 5 39 204 41 34 217 231 20 199 313 224 203 213 102 89 3 124 81 99 261 56 50 165 218 74 212 15 157 244 265 185 295 47 93 217 2 281 203 283 103 91 302 193 25 116 122 236 236 7 268 13 242 121 9 98 189 125 238 291 77 269 15 227 190 267 170 50 305 165 133 127 153 45 19 42 121 94 45 248 95 117 179 166 46 6 26 188 53 307 165 148 128 210 30 88 300 193 10 170 120 251 167 63 251 97 117 194 167 48 250 95 132 125 223 290 75 284 260 283 118 37 45 178 94 60 194 97 47 248 110 63 181 151 115 264 43 104 233 234 7 253 12 240 136 254 154 117 264 113 50 235 164 76 197 84 101 261 126 310 222 203 143 276 ^'}},
+ {OUT=>'3D33DE31F64055D3B128AC9A6AA3F92DFD4F5330'}],
+ ['226', {IN=> {f=> '656 0 32 69 51 135 25 31 245 123 7 164 135 178 221 42 19 286 241 36 62 107 218 303 17 267 244 32 128 36 274 282 105 91 54 190 27 99 242 176 306 235 79 199 84 169 258 128 293 289 143 213 17 208 259 209 187 278 112 35 287 228 90 126 121 151 26 18 299 187 21 97 174 179 302 252 8 255 63 306 82 254 135 237 206 181 276 44 87 283 245 19 182 51 288 215 144 141 86 84 16 68 64 81 10 66 312 133 6 83 241 189 252 220 114 266 94 119 177 234 304 4 5 308 46 61 26 8 314 48 80 23 12 297 119 24 44 191 108 42 231 145 128 140 99 30 1 54 131 42 276 301 102 144 37 261 20 169 105 303 180 77 180 136 165 275 57 33 219 231 86 143 1 207 272 155 172 264 179 45 237 147 196 137 152 13 72 47 152 270 87 224 260 196 241 293 77 284 10 229 171 20 110 120 164 288 3 18 254 298 47 93 285 313 283 186 34 43 159 214 4 262 7 223 120 1 113 116 181 217 59 264 26 171 173 251 233 60 251 80 186 138 184 223 61 16 23 175 107 6 177 81 114 207 109 29 285 160 142 73 138 80 82 313 120 11 98 255 122 291 221 146 209 83 88 315 139 8 151 189 193 235 291 58 20 273 295 51 76 40 257 37 49 161 233 1 266 257 294 64 22 25 243 104 59 111 201 58 277 288 156 159 2 194 10 170 186 197 169 46 2 41 185 106 290 234 92 145 69 155 9 138 243 208 200 224 48 21 38 189 40 45 178 162 57 196 78 167 190 180 289 306 23 269 312 296 132 19 29 226 175 3 181 64 234 151 130 208 96 34 300 174 75 112 188 112 292 302 89 198 52 275 269 159 155 19 123 66 149 274 70 295 204 266 153 104 126 62 166 203 126 225 25 90 230 262 264 238 30 60 39 270 299 34 147 300 278 216 225 35 75 53 203 22 84 228 243 267 185 47 305 95 200 71 223 273 142 226 12 144 294 276 197 228 31 141 298 259 268 172 101 4 109 133 110 273 38 36 215 297 15 199 296 28 145 281 14 212 242 280 131 32 291 162 161 70 142 14 153 257 141 239 274 129 280 27 158 227 315 198 309 290 130 267 81 173 192 248 237 43 6 24 256 50 44 146 268 68 227 256 213 170 33 56 105 150 39 13 284 173 88 58 124 147 43 263 39 117 109 286 300 21 201 48 292 149 215 85 156 312 192 307 222 133 263 98 102 248 178 9 183 132 182 204 113 279 40 104 163 301 265 270 240 49 8 92 204 54 294 217 212 89 139 67 136 12 85 309 137 256 154 185 210 115 31 304 108 146 56 209 24 103 176 247 250 305 307 10 7 11 310 65 9 79 258 69 308 150 202 139 171 277 125 297 272 214 157 87 71 70 83 29 14 67 77 27 311 52 63 94 272 2 31 200 283 33 160 246 263 251 292 45 74 21 260 33 115 90 289 247 38 130 55 222 286 88 211 227 ^'}},
+ {OUT=>'B6925F4DF94949B8844C867428BA3DEDF4CF2B51'}],
+ ['227', {IN=> {f=> '668 0 211 254 226 115 16 41 170 158 305 247 25 183 117 235 218 125 212 30 152 243 195 254 239 61 28 237 120 302 167 130 194 148 96 312 105 65 160 220 53 281 270 226 102 70 57 137 91 26 296 105 78 106 204 40 31 232 177 22 129 68 168 269 74 276 275 208 174 14 126 47 219 218 138 158 14 139 310 203 251 205 166 11 59 52 214 282 20 214 308 275 182 282 46 106 230 249 316 252 311 309 77 271 15 291 136 269 100 168 243 182 308 301 74 250 66 240 200 197 156 99 16 54 116 96 21 314 33 134 37 23 229 156 73 124 132 96 8 51 49 147 287 15 278 190 14 113 101 235 231 71 196 63 219 205 192 220 27 72 31 206 285 100 155 297 244 4 234 66 253 146 181 189 166 24 5 36 201 32 28 211 228 17 193 313 224 200 210 102 83 3 121 78 93 258 56 44 165 215 71 209 9 157 238 259 182 295 38 90 217 316 278 203 277 97 88 302 193 22 116 122 230 236 7 268 7 242 115 3 95 186 125 238 285 74 263 12 224 187 264 164 50 299 159 127 127 153 45 13 33 121 91 39 242 89 111 173 166 37 314 20 188 53 307 162 148 122 204 27 85 294 190 1 167 117 248 164 63 245 97 114 194 161 42 250 92 132 122 217 290 69 281 257 280 118 37 36 175 94 60 191 94 47 245 110 60 178 148 109 258 43 98 227 228 4 247 12 237 133 248 151 117 261 110 47 232 164 76 191 81 101 261 123 310 216 197 143 153 32 67 49 134 24 31 245 123 6 162 135 176 220 40 18 286 239 35 62 106 217 303 15 265 244 30 126 34 273 280 105 91 52 188 27 98 240 174 305 234 79 199 84 168 256 128 292 288 141 212 17 206 259 208 187 277 110 34 286 226 89 124 119 150 24 18 299 185 19 95 173 179 300 252 7 255 61 304 82 253 133 235 205 179 274 43 85 281 244 17 180 50 286 213 143 140 86 83 16 67 62 80 8 64 312 131 3 82 240 187 251 218 112 266 92 119 176 233 303 2 2 306 43 59 26 5 314 46 80 21 10 296 118 24 44 191 107 39 229 143 127 140 99 29 54 129 42 276 301 100 142 34 260 17 167 104 302 180 76 178 135 163 274 56 31 219 231 84 142 1 206 272 154 171 264 177 42 237 146 194 135 150 11 72 44 152 269 87 222 259 195 241 293 77 284 7 229 169 19 108 119 163 287 2 15 252 298 46 93 284 311 283 185 32 41 157 212 4 260 4 221 120 315 113 114 181 215 58 263 25 170 171 251 231 58 250 79 186 138 184 223 61 13 20 175 107 6 175 81 114 207 107 26 283 159 140 73 137 78 80 312 118 11 98 253 120 289 221 146 207 81 88 315 139 6 149 189 192 233 290 56 18 273 293 51 75 39 255 35 49 160 233 316 265 257 293 64 21 23 242 102 57 111 199 58 276 288 154 158 1 193 9 170 184 197 169 45 41 183 104 289 234 92 145 68 155 6 136 243 208 203 ^'}},
+ {OUT=>'CF5E7256292ABEC431D8E8B9CBEAF22AF072377E'}],
+ ['228', {IN=> {f=> '656 0 221 48 21 32 186 40 42 178 159 51 196 72 161 187 177 283 306 23 266 309 296 129 10 26 220 172 316 178 61 228 151 130 205 90 34 297 168 69 109 182 112 292 299 83 192 46 269 263 159 149 19 117 63 143 274 67 292 201 260 147 104 313 126 56 163 200 123 225 16 90 230 262 258 232 21 57 39 264 296 31 147 300 278 216 219 35 75 50 197 13 78 225 237 267 185 41 302 95 197 71 220 270 139 223 3 144 288 273 191 228 28 135 295 253 265 172 95 1 106 130 107 267 29 36 212 291 6 196 293 19 142 275 8 209 239 280 131 23 291 162 161 64 142 14 150 254 141 236 268 126 277 21 155 221 309 198 306 284 124 264 75 173 192 242 234 34 3 21 253 44 35 140 262 62 227 250 213 167 30 50 99 150 33 4 281 170 82 55 124 141 40 263 36 114 109 280 294 18 201 39 289 149 215 82 153 306 186 301 219 133 257 95 99 248 175 9 183 126 179 198 110 279 34 101 163 298 265 270 237 46 8 86 204 51 294 214 206 89 133 61 130 9 85 303 134 256 154 182 210 115 25 304 108 143 53 209 18 103 176 244 247 299 304 10 1 8 307 62 6 73 258 69 305 147 202 136 171 277 119 297 266 211 154 84 68 70 83 29 11 67 71 24 305 49 60 91 269 2 22 194 280 33 160 246 260 245 286 39 68 12 260 24 109 84 289 247 38 127 55 222 283 85 205 311 211 252 226 113 12 39 166 154 305 245 25 181 113 233 216 121 212 30 148 241 195 254 239 59 313 28 233 118 298 167 128 192 144 92 308 101 65 156 220 49 281 268 224 100 66 57 137 87 22 292 103 78 102 202 38 29 232 177 22 129 68 168 265 74 272 275 204 174 10 124 43 217 218 134 158 12 137 308 199 247 201 162 5 59 52 210 278 20 214 304 271 178 282 46 106 228 249 312 250 311 309 75 271 15 287 136 269 100 164 239 182 308 297 70 246 64 240 196 195 156 97 14 52 112 96 15 312 29 134 35 17 227 152 71 122 128 94 2 47 47 145 287 13 274 190 8 111 97 235 229 67 194 59 215 205 188 216 23 70 25 206 285 98 151 293 240 230 66 253 142 177 185 164 18 5 34 199 26 24 207 226 15 189 313 224 198 208 102 79 3 119 76 89 256 56 40 165 213 69 207 5 157 234 255 180 295 32 88 217 316 276 203 273 93 86 302 193 20 116 122 226 236 7 268 3 242 111 318 93 184 125 238 281 72 259 10 222 185 262 160 50 295 155 123 127 153 45 9 27 121 89 35 238 85 107 169 166 31 310 16 188 53 307 160 148 118 200 25 83 290 188 314 165 115 246 162 63 241 97 112 194 157 38 250 90 132 120 213 290 65 279 255 278 118 37 30 173 94 60 189 92 47 243 110 58 176 146 105 254 43 94 223 224 2 243 12 235 131 244 149 117 259 108 45 230 164 76 187 79 101 261 109 ^'}},
+ {OUT=>'975DCE94902923977F129C0E4ACF40AD28DDB9AA'}],
+ ['229', {IN=> {f=> '656 0 310 208 189 143 149 32 59 41 130 20 31 245 123 2 154 135 168 216 32 14 286 231 31 62 102 213 303 7 257 244 22 118 26 269 272 105 91 44 180 27 94 232 166 301 230 79 199 84 164 248 128 288 284 133 208 17 198 259 204 187 273 102 30 282 218 85 116 111 146 16 18 299 177 11 87 169 179 292 252 3 255 53 296 82 249 125 227 201 171 266 39 77 273 240 9 172 46 278 205 139 136 86 79 16 63 54 76 56 312 123 312 78 236 179 247 210 104 266 84 119 172 229 299 315 311 298 31 51 26 314 314 38 80 13 2 292 114 24 44 191 103 27 221 135 123 140 99 25 317 54 121 42 276 301 92 134 22 256 5 159 100 298 180 72 170 131 155 270 52 23 219 231 76 138 1 202 272 150 167 264 169 30 237 142 186 127 142 3 72 32 152 265 87 214 255 191 241 293 77 284 316 229 161 15 100 115 159 283 319 3 244 298 42 93 280 303 283 181 24 33 149 204 4 252 313 213 120 307 113 106 181 207 54 259 21 166 163 251 223 50 246 75 186 138 184 223 61 1 8 175 107 6 167 81 114 207 99 14 275 155 132 73 133 70 72 308 110 11 98 245 112 281 221 146 199 73 88 315 139 319 141 189 188 225 286 48 10 273 285 51 71 35 247 27 49 156 233 312 261 257 289 64 17 15 238 94 49 111 191 58 272 288 146 154 318 189 5 170 176 197 169 41 313 41 175 96 285 234 92 145 64 155 315 128 243 208 200 219 48 21 28 184 40 40 178 157 47 196 68 157 185 175 279 306 23 264 307 296 127 4 24 216 170 314 176 59 224 151 130 203 86 34 295 164 65 107 178 112 292 297 79 188 42 265 259 159 145 19 113 61 139 274 65 290 199 256 143 104 311 126 52 161 198 121 225 10 90 230 262 254 228 15 55 39 260 294 29 147 300 278 216 215 35 75 48 193 7 74 223 233 267 185 37 300 95 195 71 218 268 137 221 318 144 284 271 187 228 26 131 293 249 263 172 91 320 104 128 105 263 23 36 210 287 194 291 13 140 271 4 207 237 280 131 17 291 162 161 60 142 14 148 252 141 234 264 124 275 17 153 217 305 198 304 280 120 262 71 173 192 238 232 28 1 19 251 40 29 136 258 58 227 246 213 165 28 46 95 150 29 319 279 168 78 53 124 137 38 263 34 112 109 276 290 16 201 33 287 149 215 80 151 302 182 297 217 133 253 93 97 248 173 9 183 122 177 194 108 279 30 99 163 296 265 270 235 44 8 82 204 49 294 212 202 89 129 57 126 7 85 299 132 256 154 180 210 115 21 304 108 141 51 209 14 103 176 242 245 295 302 10 318 6 305 60 4 69 258 69 303 145 202 134 171 277 115 297 262 209 152 82 66 70 83 29 9 67 67 22 301 47 58 89 267 2 16 190 278 33 160 246 258 241 282 35 64 6 260 18 105 80 289 247 38 125 55 292 ^'}},
+ {OUT=>'333B0259B18CE64D6B52CF563DD3041E5F63A516'}],
+ );
+
+sub binary_expand ($$)
+{
+ my ($test_name, $line) = @_;
+ my ($n, $b, $rest) = split ' ', $line, 3;
+ defined $n && defined $b or die "$test_name: too few args\n";
+ my @a = split ' ', $rest, $n + 1;
+ my $caret = pop @a;
+ $caret eq '^' or die "test $test_name: @a missing '^'\n";
+ $b eq '1' || $b eq '0' or die "test $test_name: bad 'b'=$b\n";
+ my $n_bad = @a;
+ @a == $n or
+ die "test $test_name: wrong number of args (expected $n, found $n_bad)\n";
+ my $bit_string = '';
+ foreach my $a (@a)
+ {
+ $bit_string .= $b x $a;
+ $b = 1 - $b;
+ }
+ my $t = pack ("B*", $bit_string);
+ # print "$bit_string\n $t\n";
+ return $t;
+}
+
+my $t;
+foreach $t (@Tests)
+ {
+ # Expand each input.
+ my $in = $t->[1]->{IN};
+ $in->{f} = binary_expand $t->[0], $in->{f};
+
+ # Convert each expected output string to lower case, and append " f\n".
+ my $h = $t->[2];
+ $h->{OUT} = lc $h->{OUT} . " f\n";
+
+ # Insert the '--text' argument for each test.
+ splice @$t, 1, 0, '--text';
+ }
+
+my $save_temps = $ENV{DEBUG};
+my $verbose = $ENV{VERBOSE};
+
+my $prog = 'sha1sum';
+my $fail = run_tests ($program_name, $prog, \@Tests, $save_temps, $verbose);
+exit $fail;
diff --git a/tests/cksum/sha1sum.pl b/tests/cksum/sha1sum.pl
new file mode 100755
index 0000000..40675cf
--- /dev/null
+++ b/tests/cksum/sha1sum.pl
@@ -0,0 +1,94 @@
+#!/usr/bin/perl
+# Test "sha1sum".
+
+# Copyright (C) 2000-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+use strict;
+
+my $prog = 'sha1sum';
+
+# Turn off localization of executable's output.
+@ENV{qw(LANGUAGE LANG LC_ALL)} = ('C') x 3;
+
+my $sha_degenerate = "da39a3ee5e6b4b0d3255bfef95601890afd80709";
+
+my @Tests =
+ (
+ ['s1', {IN=> {f=> ''}},
+ {OUT=>"$sha_degenerate f\n"}],
+ ['s2', {IN=> {f=> 'a'}},
+ {OUT=>"86f7e437faa5a7fce15d1ddcb9eaeaea377667b8 f\n"}],
+ ['s3', {IN=> {f=> 'abc'}},
+ {OUT=>"a9993e364706816aba3e25717850c26c9cd0d89d f\n"}],
+ ['s4',
+ {IN=> {f=> 'abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq'}},
+ {OUT=>"84983e441c3bd26ebaae4aa1f95129e5e54670f1 f\n"}],
+ ['s5', {IN=> {f=> 'abcdefghijklmnopqrstuvwxyz'}},
+ {OUT=>"32d10c7b8cf96570ca04ce37f2a19d84240d3a89 f\n"}],
+ ['s6', {IN=> {f=> join ('', 'A'..'Z', 'a'..'z', '0'..'9')}},
+ {OUT=>"761c457bf73b14d27e9e9265c46f4b4dda11f940 f\n"}],
+ ['s7', {IN=> {f=> '1234567890' x 8}},
+ {OUT=>"50abf5706a150990a08b2c5ea40fa0e585554732 f\n"}],
+ ['million-a', {IN=> {f=> 'a' x 1000000}},
+ {OUT=>"34aa973cd4c4daa4f61eeb2bdbad27316534016f f\n"}],
+ ['bs-sha-1', {IN=> {".\nfoo"=> ''}},
+ {OUT=>"\\$sha_degenerate .\\nfoo\n"}],
+ ['bs-sha-2', {IN=> {".\\foo"=> ''}},
+ {OUT=>"\\$sha_degenerate .\\\\foo\n"}],
+ ['bs-sha-3', {IN=> {".\rfoo"=> ''}},
+ {OUT=>"\\$sha_degenerate .\\rfoo\n"}],
+ # The sha1sum and md5sum drivers share a lot of code.
+ # Ensure that sha1sum does *not* share the part that makes
+ # md5sum accept BSD format.
+ ['check-bsd', '--check', {IN=> {'f.md5' => "MD5 (f) = $sha_degenerate\n"}},
+ {AUX=> {f=> ''}},
+ {ERR=>"sha1sum: f.md5: no properly formatted "
+ . "checksum lines found\n"},
+ {EXIT=> 1}],
+ ['check-bsd2', '--check',
+ {IN=> {'f.sha1' => "SHA1 (f) = $sha_degenerate\n"}},
+ {AUX=> {f=> ''}}, {OUT=>"f: OK\n"}],
+ ['check-bsd3', '--check', '--status',
+ {IN=> {'f.sha1' => "SHA1 (f) = $sha_degenerate\n"}},
+ {AUX=> {f=> 'bar'}}, {EXIT=> 1}],
+ ['check-openssl', '--check',
+ {IN=> {'f.md5' => "MD5(f)= $sha_degenerate\n"}},
+ {AUX=> {f=> ''}},
+ {ERR=>"sha1sum: f.md5: no properly formatted "
+ . "checksum lines found\n"},
+ {EXIT=> 1}],
+ ['check-openssl2', '--check',
+ {IN=> {'f.sha1' => "SHA1(f)= $sha_degenerate\n"}},
+ {AUX=> {f=> ''}}, {OUT=>"f: OK\n"}],
+ ['check-openssl3', '--check', '--status',
+ {IN=> {'f.sha1' => "SHA1(f)= $sha_degenerate\n"}},
+ {AUX=> {f=> 'bar'}}, {EXIT=> 1}],
+ ['bsd-segv', '--check', {IN=> {'z' => "SHA1 ("}}, {EXIT=> 1},
+ {ERR=> "$prog: z: no properly formatted checksum lines found\n"}],
+ );
+
+# Insert the '--text' argument for each test.
+my $t;
+foreach $t (@Tests)
+ {
+ splice @$t, 1, 0, '--text' unless @$t[1] =~ /--check/;
+ }
+
+my $save_temps = $ENV{DEBUG};
+my $verbose = $ENV{VERBOSE};
+
+my $fail = run_tests ($prog, $prog, \@Tests, $save_temps, $verbose);
+exit $fail;
diff --git a/tests/cksum/sha224sum.pl b/tests/cksum/sha224sum.pl
new file mode 100755
index 0000000..62710d7
--- /dev/null
+++ b/tests/cksum/sha224sum.pl
@@ -0,0 +1,49 @@
+#!/usr/bin/perl
+# Test "sha224sum".
+
+# Copyright (C) 2005-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+use strict;
+
+(my $program_name = $0) =~ s|.*/||;
+
+# Turn off localization of executable's output.
+@ENV{qw(LANGUAGE LANG LC_ALL)} = ('C') x 3;
+
+my @Tests =
+ (
+ ['s3', {IN=> {f=> 'abc'}},
+ {OUT=>"23097d223405d8228642a477bda255b32aadbce4bda0b3f7e36c9da7 f\n"}],
+ ['s4',
+ {IN=> {f=> 'abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq'}},
+ {OUT=>"75388b16512776cc5dba5da1fd890150b0c6455cb4f58b1952522525 f\n"}],
+ ['s8', {IN=> {f=> 'a' x 1000000}},
+ {OUT=>"20794655980c91d8bbb4c1ea97618a4bf03f42581948b2ee4ee7ad67 f\n"}],
+ );
+
+# Insert the '--text' argument for each test.
+my $t;
+foreach $t (@Tests)
+ {
+ splice @$t, 1, 0, '--text' unless @$t[1] =~ /--check/;
+ }
+
+my $save_temps = $ENV{DEBUG};
+my $verbose = $ENV{VERBOSE};
+
+my $prog = 'sha224sum';
+my $fail = run_tests ($program_name, $prog, \@Tests, $save_temps, $verbose);
+exit $fail;
diff --git a/tests/cksum/sha256sum.pl b/tests/cksum/sha256sum.pl
new file mode 100755
index 0000000..7fa0b8a
--- /dev/null
+++ b/tests/cksum/sha256sum.pl
@@ -0,0 +1,55 @@
+#!/usr/bin/perl
+# Test "sha256sum".
+
+# Copyright (C) 2005-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+use strict;
+
+(my $program_name = $0) =~ s|.*/||;
+
+# Turn off localization of executable's output.
+@ENV{qw(LANGUAGE LANG LC_ALL)} = ('C') x 3;
+
+my $sha_degenerate = "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855";
+
+my @Tests =
+ (
+ ['s1', {IN=> {f=> ''}},
+ {OUT=>"$sha_degenerate f\n"}],
+ ['s2', {IN=> {f=> 'a'}},
+ {OUT=>"ca978112ca1bbdcafac231b39a23dc4da786eff8147c4e72b9807785afee48bb f\n"}],
+ ['s3', {IN=> {f=> 'abc'}},
+ {OUT=>"ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad f\n"}],
+ ['s4',
+ {IN=> {f=> 'abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq'}},
+ {OUT=>"248d6a61d20638b8e5c026930c3e6039a33ce45964ff2167f6ecedd419db06c1 f\n"}],
+ ['s8', {IN=> {f=> 'a' x 1000000}},
+ {OUT=>"cdc76e5c9914fb9281a1c7e284d73e67f1809a48a497200e046d39ccc7112cd0 f\n"}],
+ );
+
+# Insert the '--text' argument for each test.
+my $t;
+foreach $t (@Tests)
+ {
+ splice @$t, 1, 0, '--text' unless @$t[1] =~ /--check/;
+ }
+
+my $save_temps = $ENV{DEBUG};
+my $verbose = $ENV{VERBOSE};
+
+my $prog = 'sha256sum';
+my $fail = run_tests ($program_name, $prog, \@Tests, $save_temps, $verbose);
+exit $fail;
diff --git a/tests/cksum/sha384sum.pl b/tests/cksum/sha384sum.pl
new file mode 100755
index 0000000..dd0b1c9
--- /dev/null
+++ b/tests/cksum/sha384sum.pl
@@ -0,0 +1,55 @@
+#!/usr/bin/perl
+# Test "sha384sum".
+
+# Copyright (C) 2005-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+use strict;
+
+(my $program_name = $0) =~ s|.*/||;
+
+# Turn off localization of executable's output.
+@ENV{qw(LANGUAGE LANG LC_ALL)} = ('C') x 3;
+
+my $sha_degenerate = "38b060a751ac96384cd9327eb1b1e36a21fdb71114be07434c0cc7bf63f6e1da274edebfe76f65fbd51ad2f14898b95b";
+
+my @Tests =
+ (
+ ['s1', {IN=> {f=> ''}},
+ {OUT=>"$sha_degenerate f\n"}],
+ ['s2', {IN=> {f=> 'a'}},
+ {OUT=>"54a59b9f22b0b80880d8427e548b7c23abd873486e1f035dce9cd697e85175033caa88e6d57bc35efae0b5afd3145f31 f\n"}],
+ ['s3', {IN=> {f=> 'abc'}},
+ {OUT=>"cb00753f45a35e8bb5a03d699ac65007272c32ab0eded1631a8b605a43ff5bed8086072ba1e7cc2358baeca134c825a7 f\n"}],
+ ['s4',
+ {IN=> {f=> 'abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu'}},
+ {OUT=>"09330c33f71147e83d192fc782cd1b4753111b173b3b05d22fa08086e3b0f712fcc7c71a557e2db966c3e9fa91746039 f\n"}],
+ ['s8', {IN=> {f=> 'a' x 1000000}},
+ {OUT=>"9d0e1809716474cb086e834e310a4a1ced149e9c00f248527972cec5704c2a5b07b8b3dc38ecc4ebae97ddd87f3d8985 f\n"}],
+ );
+
+# Insert the '--text' argument for each test.
+my $t;
+foreach $t (@Tests)
+ {
+ splice @$t, 1, 0, '--text' unless @$t[1] =~ /--check/;
+ }
+
+my $save_temps = $ENV{DEBUG};
+my $verbose = $ENV{VERBOSE};
+
+my $prog = 'sha384sum';
+my $fail = run_tests ($program_name, $prog, \@Tests, $save_temps, $verbose);
+exit $fail;
diff --git a/tests/cksum/sha512sum.pl b/tests/cksum/sha512sum.pl
new file mode 100755
index 0000000..8cabe36
--- /dev/null
+++ b/tests/cksum/sha512sum.pl
@@ -0,0 +1,55 @@
+#!/usr/bin/perl
+# Test "sha512sum".
+
+# Copyright (C) 2005-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+use strict;
+
+(my $program_name = $0) =~ s|.*/||;
+
+# Turn off localization of executable's output.
+@ENV{qw(LANGUAGE LANG LC_ALL)} = ('C') x 3;
+
+my $sha_degenerate = "cf83e1357eefb8bdf1542850d66d8007d620e4050b5715dc83f4a921d36ce9ce47d0d13c5d85f2b0ff8318d2877eec2f63b931bd47417a81a538327af927da3e";
+
+my @Tests =
+ (
+ ['s1', {IN=> {f=> ''}},
+ {OUT=>"$sha_degenerate f\n"}],
+ ['s2', {IN=> {f=> 'a'}},
+ {OUT=>"1f40fc92da241694750979ee6cf582f2d5d7d28e18335de05abc54d0560e0f5302860c652bf08d560252aa5e74210546f369fbbbce8c12cfc7957b2652fe9a75 f\n"}],
+ ['s3', {IN=> {f=> 'abc'}},
+ {OUT=>"ddaf35a193617abacc417349ae20413112e6fa4e89a97ea20a9eeee64b55d39a2192992a274fc1a836ba3c23a3feebbd454d4423643ce80e2a9ac94fa54ca49f f\n"}],
+ ['s4',
+ {IN=> {f=> 'abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu'}},
+ {OUT=>"8e959b75dae313da8cf4f72814fc143f8f7779c6eb9f7fa17299aeadb6889018501d289e4900f7e4331b99dec4b5433ac7d329eeb6dd26545e96e55b874be909 f\n"}],
+ ['s8', {IN=> {f=> 'a' x 1000000}},
+ {OUT=>"e718483d0ce769644e2e42c7bc15b4638e1f98b13b2044285632a803afa973ebde0ff244877ea60a4cb0432ce577c31beb009c5c2c49aa2e4eadb217ad8cc09b f\n"}],
+ );
+
+# Insert the '--text' argument for each test.
+my $t;
+foreach $t (@Tests)
+ {
+ splice @$t, 1, 0, '--text' unless @$t[1] =~ /--check/;
+ }
+
+my $save_temps = $ENV{DEBUG};
+my $verbose = $ENV{VERBOSE};
+
+my $prog = 'sha512sum';
+my $fail = run_tests ($program_name, $prog, \@Tests, $save_temps, $verbose);
+exit $fail;
diff --git a/tests/cksum/sm3sum.pl b/tests/cksum/sm3sum.pl
new file mode 100755
index 0000000..6356ae4
--- /dev/null
+++ b/tests/cksum/sm3sum.pl
@@ -0,0 +1,56 @@
+#!/usr/bin/perl
+# Test "cksum -a sm3".
+
+# Copyright (C) 2021-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+use strict;
+
+(my $program_name = $0) =~ s|.*/||;
+
+# Turn off localization of executable's output.
+@ENV{qw(LANGUAGE LANG LC_ALL)} = ('C') x 3;
+
+my $sha_degenerate =
+ "1ab21d8355cfa17f8e61194831e81a8f22bec8c728fefb747ed035eb5082aa2b";
+
+my @Tests =
+ (
+ ['s1', {IN=> {f=> ''}},
+{OUT=>"$sha_degenerate f\n"}],
+ ['s2', {IN=> {f=> 'a'}},
+{OUT=>"623476ac18f65a2909e43c7fec61b49c7e764a91a18ccb82f1917a29c86c5e88 f\n"}],
+ ['s3', {IN=> {f=> 'abc'}},
+{OUT=>"66c7f0f462eeedd9d1f2d46bdc10e4e24167c4875cf2f7a2297da02b8f4ba8e0 f\n"}],
+ ['s4',
+ {IN=> {f=> 'abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq'}},
+{OUT=>"639b6cc5e64d9e37a390b192df4fa1ea0720ab747ff692b9f38c4e66ad7b8c05 f\n"}],
+ ['s8', {IN=> {f=> 'a' x 1000000}},
+{OUT=>"c8aaf89429554029e231941a2acc0ad61ff2a5acd8fadd25847a3a732b3b02c3 f\n"}],
+ );
+
+# Insert the arguments for each test.
+my $t;
+foreach $t (@Tests)
+ {
+ splice @$t, 1, 0, '--untagged --text -a sm3'
+ }
+
+my $save_temps = $ENV{DEBUG};
+my $verbose = $ENV{VERBOSE};
+
+my $prog = 'cksum';
+my $fail = run_tests ($program_name, $prog, \@Tests, $save_temps, $verbose);
+exit $fail;
diff --git a/tests/cksum/sum-sysv.sh b/tests/cksum/sum-sysv.sh
new file mode 100755
index 0000000..bb39190
--- /dev/null
+++ b/tests/cksum/sum-sysv.sh
@@ -0,0 +1,50 @@
+#!/bin/sh
+# make sure 'sum -s' works for input whose sum of bytes is larger than 2^32
+
+# Copyright (C) 2001-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+# Avoid a problem when run in a UTF-8 locale.
+# Otherwise, Perl would try to (and fail to) interpret
+# each string below as a sequence of multi-byte characters.
+LC_ALL=C
+export LC_ALL
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ sum
+
+require_perl_
+
+# FYI, 16843009 is floor (2^32 / 255).
+
+# aka: perl -e 'print chr(255) x 16843009'
+$PERL -e '$s = chr(255) x 65537; foreach (1..257) {print $s}' \
+ | sum -s > out || fail=1
+cat > exp <<\EOF
+65535 32897
+EOF
+compare exp out || fail=1
+
+rm -f out exp
+
+# aka: perl -e 'print chr(255) x 16843010'
+$PERL -e '$s = chr(255) x 65537; foreach (1..257) {print $s}; print chr(255)' \
+ | sum -s > out || fail=1
+cat > exp <<\EOF
+254 32897
+EOF
+compare exp out || fail=1
+
+Exit $fail
diff --git a/tests/cksum/sum.pl b/tests/cksum/sum.pl
new file mode 100755
index 0000000..abcecbc
--- /dev/null
+++ b/tests/cksum/sum.pl
@@ -0,0 +1,61 @@
+#!/usr/bin/perl
+# Test "sum".
+
+# Copyright (C) 2000-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+use strict;
+
+(my $program_name = $0) =~ s|.*/||;
+
+# Turn off localization of executable's output.
+@ENV{qw(LANGUAGE LANG LC_ALL)} = ('C') x 3;
+
+my $in_1k = 'a' x 1024;
+my $in_2k = 'b' x 2048;
+
+my @Tests =
+ (
+ ['1', {IN=> {f=> ''}}, {OUT=>"00000 0 f\n"}],
+ ['2', {IN=> {f=> 'a'}}, {OUT=>"00097 1 f\n"}],
+ ['3', {IN=> {f=> 'abc'}}, {OUT=>"16556 1 f\n"}],
+ ['4', {IN=> {f=> 'message digest'}}, {OUT=>"26423 1 f\n"}],
+ ['5', {IN=> {f=> 'abcdefghijklmnopqrstuvwxyz'}}, {OUT=>"53553 1 f\n"}],
+ ['6', {IN=> {f=> join ('', 'A'..'Z', 'a'..'z', '0'..'9')}},
+ {OUT=>"25587 1 f\n"}],
+ ['7', {IN=> {f=> '1234567890' x 8}}, {OUT=>"21845 1 f\n"}],
+
+ ['a-r-1k', '-r', {IN=> {f=> $in_1k}}, {OUT=>"65409 1 f\n"}],
+ ['a-s-1k', '-s', {IN=> {f=> $in_1k}}, {OUT=>"33793 2 f\n"}],
+ ['b-r-2k', '-r', {IN=> {f=> $in_2k}}, {OUT=>"65223 2 f\n"}],
+ ['b-s-2k', '-s', {IN=> {f=> $in_2k}}, {OUT=>"4099 4 f\n"}],
+
+ ['1s', '-s', {IN=> {f=> ''}}, {OUT=>"0 0 f\n"}],
+ ['2s', '-s', {IN=> {f=> 'a'}}, {OUT=>"97 1 f\n"}],
+ ['3s', '-s', {IN=> {f=> 'abc'}}, {OUT=>"294 1 f\n"}],
+ ['4s', '-s', {IN=> {f=> 'message digest'}}, {OUT=>"1413 1 f\n"}],
+ ['5s', '-s', {IN=> {f=> 'abcdefghijklmnopqrstuvwxyz'}},
+ {OUT=>"2847 1 f\n"}],
+ ['6s', '-s', {IN=> {f=> join ('', 'A'..'Z', 'a'..'z', '0'..'9')}},
+ {OUT=>"5387 1 f\n"}],
+ ['7s', '-s', {IN=> {f=> '1234567890' x 8}}, {OUT=>"4200 1 f\n"}],
+ );
+
+my $save_temps = $ENV{DEBUG};
+my $verbose = $ENV{VERBOSE};
+
+my $prog = 'sum';
+my $fail = run_tests ($program_name, $prog, \@Tests, $save_temps, $verbose);
+exit $fail;
diff --git a/tests/cp/abuse.sh b/tests/cp/abuse.sh
new file mode 100755
index 0000000..8c3eee1
--- /dev/null
+++ b/tests/cp/abuse.sh
@@ -0,0 +1,50 @@
+#!/bin/sh
+# ensure that cp does not write through a just-copied symlink
+
+# Copyright (C) 2007-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ cp
+
+mkdir a b c || framework_failure_
+ln -s ../t a/1 || framework_failure_
+echo payload > b/1 || framework_failure_
+
+echo "cp: will not copy 'b/1' through just-created symlink 'c/1'" \
+ > exp || framework_failure_
+
+# Check both cases: a dangling symlink, and one pointing to a writable file.
+
+for i in dangling-dest existing-dest; do
+ test $i = existing-dest && echo i > t
+ test $i = dangling-dest && rm -f t
+
+ cp -dR a/1 b/1 c 2> out && fail=1
+
+ compare exp out || fail=1
+
+ # When the destination is a dangling symlink,
+ # ensure that cp does not create it.
+ test $i = dangling-dest \
+ && test -f t && fail=1
+
+ # When the destination symlink points to a writable file,
+ # ensure that cp does not change it.
+ test $i = existing-dest \
+ && case $(cat t) in i);; *) fail=1;; esac
+done
+
+Exit $fail
diff --git a/tests/cp/acl.sh b/tests/cp/acl.sh
new file mode 100755
index 0000000..6d0170d
--- /dev/null
+++ b/tests/cp/acl.sh
@@ -0,0 +1,60 @@
+#!/bin/sh
+# copy files/directories across file system boundaries
+# and make sure acls are preserved appropriately
+
+# Copyright (C) 2005-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ cp
+
+require_acl_
+
+# Skip this test if cp was built without ACL support:
+grep '^#define USE_ACL 1' $CONFIG_HEADER > /dev/null ||
+ skip_ "insufficient ACL support"
+
+mkdir -p a b || framework_failure_
+touch a/file || framework_failure_
+
+# Ensure that setfacl and getfacl work on this file system.
+skip=no
+acl1=$(cd a && getfacl file) || skip=yes
+setfacl -m user:bin:rw- a/file 2> /dev/null || skip=yes
+test $skip = yes &&
+ skip_ "'.' is not on a suitable file system for this test"
+
+# copy a file without preserving permissions
+cp a/file b/ || fail=1
+acl2=$(cd b && getfacl file) || framework_failure_
+test "$acl1" = "$acl2" || fail=1
+
+# Update with acl set above
+acl1=$(cd a && getfacl file) || framework_failure_
+
+# copy a file, preserving permissions
+cp -p a/file b/ || fail=1
+acl2=$(cd b && getfacl file) || framework_failure_
+test "$acl1" = "$acl2" || fail=1
+
+# copy a file, preserving permissions, with --attributes-only
+echo > a/file || framework_failure_ # add some data
+test -s a/file || framework_failure_
+cp -p --attributes-only a/file b/ || fail=1
+compare /dev/null b/file || fail=1
+acl2=$(cd b && getfacl file) || framework_failure_
+test "$acl1" = "$acl2" || fail=1
+
+Exit $fail
diff --git a/tests/cp/attr-existing.sh b/tests/cp/attr-existing.sh
new file mode 100755
index 0000000..47772ab
--- /dev/null
+++ b/tests/cp/attr-existing.sh
@@ -0,0 +1,44 @@
+#!/bin/sh
+# Make sure cp --attributes-only doesn't truncate existing data
+
+# Copyright 2012-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ cp
+
+printf '1' > file1 || framework_failure_
+printf '2' > file2 || framework_failure_
+printf '2' > file2.exp || framework_failure_
+
+cp --attributes-only file1 file2 || fail=1
+cmp file2 file2.exp || fail=1
+
+# coreutils v8.32 and before would remove destination files
+# if hardlinked or the source was not a regular file.
+ln file2 link2 || framework_failure_
+cp -a --attributes-only file1 file2 || fail=1
+cmp file2 file2.exp || fail=1
+
+ln -s file1 sym1 || framework_failure_
+returns_ 1 cp -a --attributes-only sym1 file2 || fail=1
+cmp file2 file2.exp || fail=1
+
+# One can still force removal though
+cp -a --remove-destination --attributes-only sym1 file2 || fail=1
+test -L file2 || fail=1
+cmp file1 file2 || fail=1
+
+Exit $fail
diff --git a/tests/cp/backup-1.sh b/tests/cp/backup-1.sh
new file mode 100755
index 0000000..613d3a4
--- /dev/null
+++ b/tests/cp/backup-1.sh
@@ -0,0 +1,37 @@
+#!/bin/sh
+# Test cp backup.
+
+# Copyright (C) 1997-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ cp
+
+suffix=.b
+file=F
+file_backup="$file$suffix"
+
+echo test > $file || framework_failure_
+
+# Specify both version control and suffix so the environment variables
+# (possibly set by the user running these tests) aren't used.
+cp --force --backup=simple --suffix=$suffix $file $file || fail=1
+cp -T --force --backup=simple --suffix=$suffix $file $file || fail=1
+
+test -f $file || fail=1
+test -f $file_backup || fail=1
+compare $file $file_backup > /dev/null || fail=1
+
+Exit $fail
diff --git a/tests/cp/backup-dir.sh b/tests/cp/backup-dir.sh
new file mode 100755
index 0000000..c05d956
--- /dev/null
+++ b/tests/cp/backup-dir.sh
@@ -0,0 +1,38 @@
+#!/bin/sh
+# Ensure that cp -b handles directories appropriately
+
+# Copyright (C) 2006-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ cp
+
+mkdir x y || framework_failure_
+
+
+cp -a x y || fail=1
+
+# This would mistakenly create a backup of y/x (y/x~) in coreutils-6.3.
+cp -ab x y || fail=1
+test -d y/x || fail=1
+test -d y/x~ && fail=1
+
+# Bug 62607.
+# This would fail to backup using rename, and thus fail to replace the file
+mkdir -p src/foo dst/foo || framework_failure_
+touch src/foo/bar dst/foo/bar || framework_failure_
+cp --recursive --backup src/* dst || fail=1
+
+Exit $fail
diff --git a/tests/cp/backup-is-src.sh b/tests/cp/backup-is-src.sh
new file mode 100755
index 0000000..6534f5e
--- /dev/null
+++ b/tests/cp/backup-is-src.sh
@@ -0,0 +1,36 @@
+#!/bin/sh
+# Test cp backup to source file.
+
+# Copyright (C) 1998-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ cp
+
+echo a > a || framework_failure_
+echo a-tilde > a~ || framework_failure_
+
+# This cp command should exit nonzero.
+cp --b=simple a~ a > out 2>&1 && fail=1
+
+sed "s,cp:,XXX:," out > out2
+
+cat > exp <<\EOF
+XXX: backing up 'a' might destroy source; 'a~' not copied
+EOF
+
+compare exp out2 || fail=1
+
+Exit $fail
diff --git a/tests/cp/capability.sh b/tests/cp/capability.sh
new file mode 100755
index 0000000..be3a7f8
--- /dev/null
+++ b/tests/cp/capability.sh
@@ -0,0 +1,52 @@
+#!/bin/sh
+# Ensure cp --preserves copies capabilities
+
+# Copyright (C) 2010-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ cp
+require_root_
+working_umask_or_skip_
+
+
+grep '^#define HAVE_CAP 1' $CONFIG_HEADER > /dev/null \
+ || skip_ "configured without libcap support"
+
+(setcap --help) 2>&1 |grep 'usage: setcap' > /dev/null \
+ || skip_ "setcap utility not found"
+(getcap --help) 2>&1 |grep 'usage: getcap' > /dev/null \
+ || skip_ "getcap utility not found"
+
+
+touch file || framework_failure_
+chown $NON_ROOT_USERNAME file || framework_failure_
+
+setcap 'cap_net_bind_service=ep' file ||
+ skip_ "setcap doesn't work"
+getcap file | grep cap_net_bind_service >/dev/null ||
+ skip_ "getcap doesn't work"
+
+cp --preserve=xattr file copy1 || fail=1
+
+# Before coreutils 8.5 the capabilities would not be preserved,
+# as the owner was set _after_ copying xattrs, thus clearing any capabilities.
+cp --preserve=all file copy2 || fail=1
+
+for file in copy1 copy2; do
+ getcap $file | grep cap_net_bind_service >/dev/null || fail=1
+done
+
+Exit $fail
diff --git a/tests/cp/copy-FMR.sh b/tests/cp/copy-FMR.sh
new file mode 100755
index 0000000..56d2d64
--- /dev/null
+++ b/tests/cp/copy-FMR.sh
@@ -0,0 +1,31 @@
+#!/bin/sh
+# Trigger a free-memory read bug in cp from coreutils-[8.11..8.19]
+
+# Copyright (C) 2012-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ cp
+
+require_valgrind_
+require_perl_
+
+# Trigger FMR in fiemap logic from v8.11..v8.19
+$PERL -e 'for (1..600) { sysseek (*STDOUT, 4096, 1)' \
+ -e '&& syswrite (*STDOUT, "a" x 1024) or die "$!"}' > j || fail=1
+valgrind --quiet --error-exitcode=3 cp --reflink=never j j2 || fail=1
+cmp j j2 || fail=1
+
+Exit $fail
diff --git a/tests/cp/cp-HL.sh b/tests/cp/cp-HL.sh
new file mode 100755
index 0000000..d5bbedd
--- /dev/null
+++ b/tests/cp/cp-HL.sh
@@ -0,0 +1,40 @@
+#!/bin/sh
+# test cp's -H and -L options
+
+# Copyright (C) 2000-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ cp
+
+mkdir src-dir dest-dir || framework_failure_
+echo f > f || framework_failure_
+ln -s f slink || framework_failure_
+ln -s no-such-file src-dir/slink || framework_failure_
+
+
+cp -H -R slink src-dir dest-dir || fail=1
+test -d src-dir || fail=1
+test -d dest-dir/src-dir || fail=1
+
+# Expect this to succeed since this slink is not a symlink
+cat dest-dir/slink > /dev/null 2>&1 || fail=1
+
+# Expect this to fail since *this* slink is a dangling symlink.
+returns_ 1 cat dest-dir/src-dir/slink >/dev/null 2>&1 || fail=1
+
+# FIXME: test -L, too.
+
+Exit $fail
diff --git a/tests/cp/cp-a-selinux.sh b/tests/cp/cp-a-selinux.sh
new file mode 100755
index 0000000..8679a01
--- /dev/null
+++ b/tests/cp/cp-a-selinux.sh
@@ -0,0 +1,228 @@
+#!/bin/sh
+# Ensure that cp -Z, -a and cp --preserve=context work properly.
+# In particular, test on a writable NFS partition.
+# Check also locally if --preserve=context, -a and --preserve=all
+# does work
+
+# Copyright (C) 2007-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ cp
+require_root_
+require_selinux_
+
+cwd=$(pwd)
+cleanup_() { cd /; umount "$cwd/mnt"; }
+
+# This context is special: it works even when mcstransd isn't running.
+ctx='root:object_r:tmp_t'
+mls_enabled_ && ctx="$ctx:s0"
+
+# Check basic functionality - before check on fixed context mount
+touch c || framework_failure_
+chcon $ctx c || skip_ "Failed to set context: $ctx"
+cp -a c d 2>err || framework_failure_
+cp --preserve=context c e || framework_failure_
+cp --preserve=all c f || framework_failure_
+ls -Z d | grep $ctx || fail=1
+# there must be no stderr output for -a
+compare /dev/null err || fail=1
+ls -Z e | grep $ctx || fail=1
+ls -Z f | grep $ctx || fail=1
+rm -f f
+
+# Check handling of existing dirs which requires specific handling
+# due to recursion, and was handled incorrectly in coreutils-8.22
+# Note standard permissions are updated for existing directories
+# in the destination, so SELinux contexts should be updated too.
+mkdir -p backup/existing_dir/ || framework_failure_
+ls -Zd backup/existing_dir > ed_ctx || fail=1
+grep $ctx ed_ctx && framework_failure_
+touch backup/existing_dir/file || framework_failure_
+chcon $ctx backup/existing_dir/file || framework_failure_
+# Set the dir context to ensure it is reset
+mkdir -p --context="$ctx" restore/existing_dir || framework_failure_
+# Copy and ensure existing directories updated
+cp -a backup/. restore/ || fail=1
+ls -Zd restore/existing_dir > ed_ctx || fail=1
+grep $ctx ed_ctx &&
+ { ls -lZd restore/existing_dir; fail=1; }
+
+# Check context preserved with directories created with --parents,
+# which was not handled before coreutils-8.27
+mkdir -p parents/a/b || framework_failure_
+ls -Zd parents/a/b > ed_ctx || fail=1
+grep $ctx ed_ctx && framework_failure_
+touch parents/a/b/file || framework_failure_
+chcon $ctx parents/a/b || framework_failure_
+# Set the dir context to ensure it is reset
+mkdir -p --context="$ctx" parents_dest/parents/a || framework_failure_
+# Copy and ensure existing directories updated
+cp -r --parents --preserve=context parents/a/b/file parents_dest || fail=1
+# Check new context
+ls -Zd parents_dest/parents/a/b > ed_ctx || fail=1
+grep $ctx ed_ctx ||
+ { ls -lZd parents_dest/parents/a/b; fail=1; }
+# Check updated context
+ls -Zd parents_dest/parents/a > ed_ctx || fail=1
+grep $ctx ed_ctx &&
+ { ls -lZd parents_dest/parents/a; fail=1; }
+
+# Check restorecon (-Z) functionality for file and directory
+# Also make a dir with our known context
+mkdir c_d || framework_failure_
+chcon $ctx c_d || framework_failure_
+# Get the type of this known context for file and dir for tracing
+old_type_f=$(get_selinux_type c)
+old_type_d=$(get_selinux_type c_d)
+# Setup copies for manipulation with restorecon
+# and get the adjusted type for comparison
+cp -a c Z1 || fail=1
+cp -a c_d Z1_d || fail=1
+if restorecon Z1 Z1_d 2>restorecon.err \
+ && compare /dev/null restorecon.err; then
+ new_type_f=$(get_selinux_type Z1)
+ new_type_d=$(get_selinux_type Z1_d)
+
+ # Ensure -Z sets the type like restorecon does
+ cp -Z c Z2 || fail=1
+ cpZ_type_f=$(get_selinux_type Z2)
+ test "$cpZ_type_f" = "$new_type_f" || fail=1
+
+ # Ensure -Z overrides -a and that dirs are handled too
+ cp -aZ c Z3 || fail=1
+ cp -aZ c_d Z3_d || fail=1
+ cpaZ_type_f=$(get_selinux_type Z3)
+ cpaZ_type_d=$(get_selinux_type Z3_d)
+ test "$cpaZ_type_f" = "$new_type_f" || fail=1
+ test "$cpaZ_type_d" = "$new_type_d" || fail=1
+
+ # Ensure -Z sets the type for existing files
+ mkdir -p existing/c_d || framework_failure_
+ touch existing/c || framework_failure_
+ cp -aZ c c_d existing || fail=1
+ cpaZ_type_f=$(get_selinux_type existing/c)
+ cpaZ_type_d=$(get_selinux_type existing/c_d)
+ test "$cpaZ_type_f" = "$new_type_f" || fail=1
+ test "$cpaZ_type_d" = "$new_type_d" || fail=1
+fi
+
+skip=0
+# Create a file system, then mount it with the context=... option.
+dd if=/dev/zero of=blob bs=8192 count=200 || skip=1
+mkdir mnt || skip=1
+mkfs -t ext2 -F blob ||
+ skip_ "failed to create an ext2 file system"
+
+mount -oloop,context=$ctx blob mnt || skip=1
+test $skip = 1 \
+ && skip_ "insufficient mount/ext2 support"
+
+cd mnt || framework_failure_
+
+# Create files with hopefully different contexts
+echo > ../f || framework_failure_
+echo > g || framework_failure_
+test "$(stat -c%C ../f)" = "$(stat -c%C g)" &&
+ skip_ "files on separate file systems have the same security context"
+
+# /bin/cp from coreutils-6.7-3.fc7 would fail this test by letting cp
+# succeed (giving no diagnostics), yet leaving the destination file empty.
+cp -a ../f g 2>err || fail=1
+test -s g || fail=1 # The destination file must not be empty.
+compare /dev/null err || fail=1
+
+# =====================================================
+# Here, we expect cp to succeed and not warn with "Operation not supported"
+rm -f g
+echo > g
+cp --preserve=all ../f g 2>err || fail=1
+test -s g || fail=1
+grep "Operation not supported" err && fail=1
+
+# =====================================================
+# The same as above except destination does not exist
+rm -f g
+cp --preserve=all ../f g 2>err || fail=1
+test -s g || fail=1
+grep "Operation not supported" err && fail=1
+
+# An alternative to the following approach would be to run in a confined
+# domain (maybe creating/loading it) that lacks the required permissions
+# to the file type.
+# Note: this test could also be run by a regular (non-root) user in an
+# NFS mounted directory. When doing that, I get this diagnostic:
+# cp: failed to set the security context of 'g' to 'system_u:object_r:nfs_t': \
+# Operation not supported
+cat <<\EOF > exp || framework_failure_
+cp: failed to set the security context of
+EOF
+
+rm -f g
+echo > g
+# =====================================================
+# Here, we expect cp to fail, because it cannot set the SELinux
+# security context through NFS or a mount with fixed context.
+cp --preserve=context ../f g 2> out && fail=1
+# Here, we *do* expect the destination to be empty.
+compare /dev/null g || fail=1
+sed "s/ .g'.*//" out > k
+mv k out
+compare exp out || fail=1
+
+rm -f g
+echo > g
+# Check if -a option doesn't silence --preserve=context option diagnostics
+cp -a --preserve=context ../f g 2> out2 && fail=1
+# Here, we *do* expect the destination to be empty.
+compare /dev/null g || fail=1
+sed "s/ .g'.*//" out2 > k
+mv k out2
+compare exp out2 || fail=1
+
+for no_g_cmd in '' 'rm -f g'; do
+ # restorecon equivalent. Note even though the context
+ # returned from matchpathcon() will not match $ctx
+ # the resulting ENOTSUP warning will be suppressed.
+
+ # With absolute path
+ $no_g_cmd
+ cp -Z ../f $(realpath g) || fail=1
+ # With relative path
+ $no_g_cmd
+ cp -Z ../f g || fail=1
+ # -Z overrides -a
+ $no_g_cmd
+ cp -Z -a ../f g || fail=1
+ # -Z doesn't take an arg
+ $no_g_cmd
+ returns_ 1 cp -Z "$ctx" ../f g || fail=1
+
+ # Explicit context
+ $no_g_cmd
+ # Explicitly defaulting to the global $ctx should work
+ cp --context="$ctx" ../f g || fail=1
+ # --context overrides -a
+ $no_g_cmd
+ cp -a --context="$ctx" ../f g || fail=1
+done
+
+# Mutually exclusive options
+returns_ 1 cp -Z --preserve=context ../f g || fail=1
+returns_ 1 cp --preserve=context -Z ../f g || fail=1
+returns_ 1 cp --preserve=context --context="$ctx" ../f g || fail=1
+
+Exit $fail
diff --git a/tests/cp/cp-deref.sh b/tests/cp/cp-deref.sh
new file mode 100755
index 0000000..783ec07
--- /dev/null
+++ b/tests/cp/cp-deref.sh
@@ -0,0 +1,34 @@
+#!/bin/sh
+# cp -RL dir1 dir2' must handle the case in which each of dir1 and dir2
+# contain a symlink pointing to some third directory.
+
+# Copyright (C) 2006-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ cp
+
+mkdir a b c d || framework_failure_
+ln -s ../c a || framework_failure_
+ln -s ../c b || framework_failure_
+
+
+# Before coreutils-5.94, the following would fail with this message:
+# cp: will not create hard link 'd/b/c' to directory 'd/a/c'
+cp -RL a b d || fail=1
+test -d a/c || fail=1
+test -d b/c || fail=1
+
+Exit $fail
diff --git a/tests/cp/cp-i.sh b/tests/cp/cp-i.sh
new file mode 100755
index 0000000..a9178a9
--- /dev/null
+++ b/tests/cp/cp-i.sh
@@ -0,0 +1,71 @@
+#!/bin/sh
+# Test whether cp -i prompts in the right place.
+
+# Copyright (C) 2006-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ cp
+
+mkdir -p a b/a/c || framework_failure_
+touch a/c || framework_failure_
+
+
+# coreutils 6.2 cp would neglect to prompt in this case.
+echo n | returns_ 1 cp -iR a b 2>/dev/null || fail=1
+
+# test miscellaneous combinations of -f -i -n parameters
+touch c d || framework_failure_
+echo "'c' -> 'd'" > out_copy || framework_failure_
+echo "cp: not replacing 'd'" > err_skip || framework_failure_
+touch out_empty || framework_failure_
+
+# ask for overwrite, answer no
+echo n | returns_ 1 cp -vi c d 2>/dev/null > out1 || fail=1
+compare out1 out_empty || fail=1
+
+# ask for overwrite, answer yes
+echo y | cp -vi c d 2>/dev/null > out2 || fail=1
+compare out2 out_copy || fail=1
+
+# -i wins over -n
+echo y | cp -vni c d 2>/dev/null > out3 || fail=1
+compare out3 out_copy || fail=1
+
+# -n wins over -i
+echo y | returns_ 1 cp -vin c d 2>/dev/null > out4 || fail=1
+compare out4 out_empty || fail=1
+
+# -n wins over -i non verbose
+echo y | returns_ 1 cp -in c d 2>err4 > out4 || fail=1
+compare err4 err_skip || fail=1
+compare out4 out_empty || fail=1
+
+# ask for overwrite, answer yes
+echo y | cp -vfi c d 2>/dev/null > out5 || fail=1
+compare out5 out_copy || fail=1
+
+# do not ask, prevent from overwrite
+echo n | returns_ 1 cp -vfn c d 2>/dev/null > out6 || fail=1
+compare out6 out_empty || fail=1
+
+# do not ask, prevent from overwrite
+echo n | returns_ 1 cp -vnf c d 2>/dev/null > out7 || fail=1
+compare out7 out_empty || fail=1
+
+# options --backup and --no-clobber are mutually exclusive
+returns_ 1 cp -bn c d 2>/dev/null || fail=1
+
+Exit $fail
diff --git a/tests/cp/cp-mv-backup.sh b/tests/cp/cp-mv-backup.sh
new file mode 100755
index 0000000..5c3e4fc
--- /dev/null
+++ b/tests/cp/cp-mv-backup.sh
@@ -0,0 +1,92 @@
+#!/bin/sh
+# Test basic --backup functionality for both cp and mv.
+
+# Copyright (C) 1999-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ cp
+
+umask 022
+
+# Be careful to close $actual before removing the containing directory.
+# Use '1>&2' rather than '1<&-' since the latter appears not to work
+# with /bin/sh from powerpc-ibm-aix4.2.0.0.
+
+actual=actual
+expected=expected
+
+exec 3>&1 1> $actual
+
+for prog in cp mv; do
+ for initial_files in 'x' 'x y' 'x y y~' 'x y y.~1~' 'x y y~ y.~1~'; do
+ for opt in none off numbered t existing nil simple never; do
+ touch $initial_files
+ $prog --backup=$opt x y || fail=1
+ echo $initial_files $opt: $(ls [xy]*); rm -f x y y~ y.~?~
+ done
+ done
+done
+
+cat <<\EOF > $expected-tmp
+x none: x y
+x off: x y
+x numbered: x y
+x t: x y
+x existing: x y
+x nil: x y
+x simple: x y
+x never: x y
+x y none: x y
+x y off: x y
+x y numbered: x y y.~1~
+x y t: x y y.~1~
+x y existing: x y y~
+x y nil: x y y~
+x y simple: x y y~
+x y never: x y y~
+x y y~ none: x y y~
+x y y~ off: x y y~
+x y y~ numbered: x y y.~1~ y~
+x y y~ t: x y y.~1~ y~
+x y y~ existing: x y y~
+x y y~ nil: x y y~
+x y y~ simple: x y y~
+x y y~ never: x y y~
+x y y.~1~ none: x y y.~1~
+x y y.~1~ off: x y y.~1~
+x y y.~1~ numbered: x y y.~1~ y.~2~
+x y y.~1~ t: x y y.~1~ y.~2~
+x y y.~1~ existing: x y y.~1~ y.~2~
+x y y.~1~ nil: x y y.~1~ y.~2~
+x y y.~1~ simple: x y y.~1~ y~
+x y y.~1~ never: x y y.~1~ y~
+x y y~ y.~1~ none: x y y.~1~ y~
+x y y~ y.~1~ off: x y y.~1~ y~
+x y y~ y.~1~ numbered: x y y.~1~ y.~2~ y~
+x y y~ y.~1~ t: x y y.~1~ y.~2~ y~
+x y y~ y.~1~ existing: x y y.~1~ y.~2~ y~
+x y y~ y.~1~ nil: x y y.~1~ y.~2~ y~
+x y y~ y.~1~ simple: x y y.~1~ y~
+x y y~ y.~1~ never: x y y.~1~ y~
+EOF
+
+sed 's/: x/:/' $expected-tmp |cat $expected-tmp - > $expected
+
+exec 1>&3 3>&-
+
+compare $expected $actual || fail=1
+
+Exit $fail
diff --git a/tests/cp/cp-mv-enotsup-xattr.sh b/tests/cp/cp-mv-enotsup-xattr.sh
new file mode 100755
index 0000000..4b967eb
--- /dev/null
+++ b/tests/cp/cp-mv-enotsup-xattr.sh
@@ -0,0 +1,132 @@
+#!/bin/sh
+# Ensure that mv, cp -a and cp --preserve=xattr(all) options do work
+# as expected on file systems without their support and do show correct
+# diagnostics when required
+
+# Copyright (C) 2009-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ cp mv
+
+require_root_
+
+cwd=$(pwd)
+cleanup_() { cd /; umount "$cwd/noxattr"; umount "$cwd/xattr"; }
+
+skip=0
+
+# Mount an ext2 loopback file system at $WHERE with $OPTS
+make_fs() {
+ where="$1"
+ opts="$2"
+
+ fs="$where.bin"
+
+ dd if=/dev/zero of="$fs" bs=8192 count=200 > /dev/null 2>&1 \
+ || skip=1
+ mkdir "$where" || skip=1
+ mkfs -t ext2 -F "$fs" ||
+ skip_ "failed to create ext2 file system"
+ mount -oloop,$opts "$fs" "$where" || skip=1
+ echo test > "$where"/f || skip=1
+ test -s "$where"/f || skip=1
+
+ test $skip = 1 &&
+ skip_ "insufficient mount/ext2 support"
+}
+
+make_fs noxattr nouser_xattr
+make_fs xattr user_xattr
+
+# testing xattr name-value pair
+xattr_name="user.foo"
+xattr_value="bar"
+xattr_pair="$xattr_name=\"$xattr_value\""
+
+echo test > xattr/a || framework_failure_
+getfattr -d xattr/a >out_a || skip_ "failed to get xattr of file"
+grep -F "$xattr_pair" out_a >/dev/null && framework_failure_
+setfattr -n "$xattr_name" -v "$xattr_value" xattr/a >out_a \
+ || skip_ "failed to set xattr of file"
+getfattr -d xattr/a >out_a || skip_ "failed to get xattr of file"
+grep -F "$xattr_pair" out_a >/dev/null \
+ || skip_ "failed to set xattr of file"
+
+
+# This should pass without diagnostics
+cp -a xattr/a noxattr/ 2>err || fail=1
+test -s noxattr/a || fail=1 # destination file must not be empty
+compare /dev/null err || fail=1
+
+rm -f err noxattr/a
+
+# This should pass without diagnostics (new file)
+cp --preserve=all xattr/a noxattr/ 2>err || fail=1
+test -s noxattr/a || fail=1 # destination file must not be empty
+compare /dev/null err || fail=1
+
+# This should pass without diagnostics (existing file)
+cp --preserve=all xattr/a noxattr/ 2>err || fail=1
+test -s noxattr/a || fail=1 # destination file must not be empty
+compare /dev/null err || fail=1
+
+rm -f err noxattr/a
+
+# This should fail with corresponding diagnostics
+cp -a --preserve=xattr xattr/a noxattr/ 2>err && fail=1
+if grep '^#define USE_XATTR 1' $CONFIG_HEADER > /dev/null; then
+cat <<\EOF > exp
+cp: setting attributes for 'noxattr/a': Operation not supported
+EOF
+else
+cat <<\EOF > exp
+cp: cannot preserve extended attributes, cp is built without xattr support
+EOF
+fi
+
+compare exp err || fail=1
+
+rm -f err noxattr/a
+
+# This should pass without diagnostics
+mv xattr/a noxattr/ 2>err || fail=1
+test -s noxattr/a || fail=1 # destination file must not be empty
+compare /dev/null err || fail=1
+
+# This should pass and copy xattrs of the symlink
+# since the xattrs used here are not in the 'user.' namespace.
+# Up to and including coreutils-8.22 xattrs of symlinks
+# were not copied across file systems.
+ln -s 'foo' xattr/symlink || framework_failure_
+# Note 'user.' namespace is only supported on regular files/dirs
+# so use the 'trusted.' namespace here
+txattr='trusted.overlay.whiteout'
+if setfattr -hn "$txattr" -v y xattr/symlink; then
+ # Note only root can read the 'trusted.' namespace
+ if getfattr -h -m- -d xattr/symlink | grep -F "$txattr"; then
+ mv xattr/symlink noxattr/ 2>err || fail=1
+ if grep '^#define USE_XATTR 1' $CONFIG_HEADER > /dev/null; then
+ getfattr -h -m- -d noxattr/symlink | grep -F "$txattr" || fail=1
+ fi
+ compare /dev/null err || fail=1
+ else
+ echo "failed to get '$txattr' xattr. skipping symlink check" >&2
+ fi
+else
+ echo "failed to set '$txattr' xattr. skipping symlink check" >&2
+fi
+
+Exit $fail
diff --git a/tests/cp/cp-parents.sh b/tests/cp/cp-parents.sh
new file mode 100755
index 0000000..9437504
--- /dev/null
+++ b/tests/cp/cp-parents.sh
@@ -0,0 +1,75 @@
+#!/bin/sh
+
+# Copyright (C) 2000-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ cp
+
+working_umask_or_skip_
+
+# Run the setgid check from the just-created directory.
+skip_if_setgid_
+
+{
+ mkdir foo bar
+ mkdir -p a/b/c d e g
+ ln -s d/a sym
+ touch f
+} || framework_failure_
+
+# With 4.0.37 and earlier (back to when?), this would fail
+# with the failed assertion from dirname.c due to the trailing slash.
+cp -R --parents foo/ bar || fail=1
+
+# Exercise the make_path and re_protect code in cp.c.
+# FIXME: compare verbose output with expected output.
+cp --verbose -a --parents a/b/c d > /dev/null 2>&1 || fail=1
+test -d d/a/b/c || fail=1
+
+# With 6.7 and earlier, cp --parents f/g d would mistakenly create a
+# directory d/f, even though f is a regular file.
+returns_ 1 cp --parents f/g d 2>/dev/null || fail=1
+test -d d/f && fail=1
+
+# Check that re_protect works.
+chmod go=w d/a || framework_failure_
+cp -a --parents d/a/b/c e || fail=1
+cp -a --parents sym/b/c g || fail=1
+p=$(ls -ld e/d|cut -b-10); case $p in drwxr-xr-x);; *) fail=1;; esac
+p=$(ls -ld e/d/a|cut -b-10); case $p in drwx-w--w-);; *) fail=1;; esac
+p=$(ls -ld g/sym|cut -b-10); case $p in drwx-w--w-);; *) fail=1;; esac
+p=$(ls -ld e/d/a/b/c|cut -b-10); case $p in drwxr-xr-x);; *) fail=1;; esac
+p=$(ls -ld g/sym/b/c|cut -b-10); case $p in drwxr-xr-x);; *) fail=1;; esac
+
+# Before 8.25 cp --parents --no-preserve=mode would copy
+# the mode bits from the source directories
+{
+ mkdir -p np/b &&
+ chmod 0700 np &&
+ touch np/b/file &&
+ chmod 775 np/b/file &&
+ mkdir np_dest
+} || framework_failure_
+cp --parents --no-preserve=mode np/b/file np_dest/ || fail=1
+p=$(ls -ld np_dest/np|cut -b-10); case $p in drwxr-xr-x);; *) fail=1;; esac
+
+# coreutils 9.1-9.3 inclusive would fail to copy acls for absolute dirs
+mkdir dest || framework_failure_
+if test -f /bin/ls; then
+ cp -t dest --parents -p /bin/ls || fail=1
+fi
+
+Exit $fail
diff --git a/tests/cp/cross-dev-symlink.sh b/tests/cp/cross-dev-symlink.sh
new file mode 100755
index 0000000..21340b4
--- /dev/null
+++ b/tests/cp/cross-dev-symlink.sh
@@ -0,0 +1,38 @@
+#!/bin/sh
+# Ensure symlinks can be replaced across devices
+
+# Copyright (C) 2018-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ cp
+require_root_
+
+cwd=$(pwd)
+cleanup_() { cd /; umount "$cwd/mnt"; }
+
+truncate -s100M fs.img || framework_failure_
+mkfs -t ext4 fs.img || skip_ 'failed to create ext4 file system'
+mkdir mnt || framework_failure_
+mount fs.img mnt || skip_ 'failed to mount ext4 file system'
+
+mkdir mnt/path1 || framework_failure_
+touch mnt/path1/file || framework_failure_
+mkdir path2 || framework_failure_
+cd path2 && ln -s ../mnt/path1/file || framework_failure_
+
+cp -dsf ../mnt/path1/file . || fail=1
+
+Exit $fail
diff --git a/tests/cp/debug.sh b/tests/cp/debug.sh
new file mode 100755
index 0000000..242894d
--- /dev/null
+++ b/tests/cp/debug.sh
@@ -0,0 +1,32 @@
+#!/bin/sh
+# Ensure that cp --debug works as documented
+
+# Copyright (C) 2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ cp
+
+touch file || framework_failure_
+cp --debug file file.cp >cp.out || fail=1
+grep 'copy offload:.*reflink:.*sparse detection:' cp.out || fail=1
+cp --debug --attributes-only file file.cp >cp.out || fail=1
+returns_ 1 grep 'copy offload:.*reflink:.*sparse detection:' cp.out || fail=1
+
+touch file.cp || framework_failure_
+cp --debug --update=none file file.cp >cp.out || fail=1
+grep 'skipped' cp.out || fail=1
+
+Exit $fail
diff --git a/tests/cp/deref-slink.sh b/tests/cp/deref-slink.sh
new file mode 100755
index 0000000..a0088c3
--- /dev/null
+++ b/tests/cp/deref-slink.sh
@@ -0,0 +1,28 @@
+#!/bin/sh
+# Demonstrate bug when using -d with an existing destination file
+# that is a symlink.
+
+# Copyright (C) 2000-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ cp
+
+touch f slink-target || framework_failure_
+ln -s slink-target slink || framework_failure_
+
+cp -d f slink || fail=1
+
+Exit $fail
diff --git a/tests/cp/dir-rm-dest.sh b/tests/cp/dir-rm-dest.sh
new file mode 100755
index 0000000..5a8233d
--- /dev/null
+++ b/tests/cp/dir-rm-dest.sh
@@ -0,0 +1,35 @@
+#!/bin/sh
+# verify cp's --remove-destination option
+
+# Copyright (C) 2000-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ cp
+
+mkdir d e || framework_failure_
+
+# Do it once with no destination...
+cp -R --remove-destination d e || fail=1
+
+# ...and again, with an existing destination.
+cp -R --remove-destination d e || fail=1
+
+# verify no ELOOP which was the case in <= 8.29
+ln -s loop loop || framework_failure_
+touch file || framework_failure_
+cp --remove-destination file loop || fail=1
+
+Exit $fail
diff --git a/tests/cp/dir-slash.sh b/tests/cp/dir-slash.sh
new file mode 100755
index 0000000..d69b802
--- /dev/null
+++ b/tests/cp/dir-slash.sh
@@ -0,0 +1,35 @@
+#!/bin/sh
+# Make sure that cp -R DIR1 DIR2 does the right thing
+# when DIR1 is written with a trailing slash.
+
+# Copyright (C) 2000-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ cp
+
+mkdir dir1 dir2 || framework_failure_
+touch dir1/file || framework_failure_
+
+cp -R dir1/ dir2 || fail=1
+
+# This file should not exist, but it did with fileutils-4.0w.
+test -r dir2/file && fail=1
+
+# These two should.
+test -r dir2/dir1/file || fail=1
+test -r dir1/file || fail=1
+
+Exit $fail
diff --git a/tests/cp/dir-vs-file.sh b/tests/cp/dir-vs-file.sh
new file mode 100755
index 0000000..f4ce100
--- /dev/null
+++ b/tests/cp/dir-vs-file.sh
@@ -0,0 +1,33 @@
+#!/bin/sh
+# A directory may not replace an existing file.
+
+# Copyright (C) 2001-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ cp
+
+mkdir dir || framework_failure_
+touch file || framework_failure_
+
+
+# In 4.0.35, this cp invocation silently succeeded.
+returns_ 1 cp -R dir file 2>/dev/null || fail=1
+
+# Make sure file is not replaced with a directory.
+# In 4.0.35, it was.
+test -f file || fail=1
+
+Exit $fail
diff --git a/tests/cp/existing-perm-dir.sh b/tests/cp/existing-perm-dir.sh
new file mode 100755
index 0000000..16d5f6c
--- /dev/null
+++ b/tests/cp/existing-perm-dir.sh
@@ -0,0 +1,31 @@
+#!/bin/sh
+# Make sure cp -p doesn't "restore" permissions it shouldn't (Bug#9170).
+
+# Copyright 2011-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ cp
+
+umask 002
+mkdir -p -m ug-s,u=rwx,g=rwx,o=rx src/dir || fail=1
+mkdir -p -m ug-s,u=rwx,g=,o= dst/dir || fail=1
+
+cp -r src/. dst/ || fail=1
+
+mode=$(stat --p=%A dst/dir)
+test "$mode" = drwx------ || fail=1
+
+Exit $fail
diff --git a/tests/cp/existing-perm-race.sh b/tests/cp/existing-perm-race.sh
new file mode 100755
index 0000000..44641b4
--- /dev/null
+++ b/tests/cp/existing-perm-race.sh
@@ -0,0 +1,94 @@
+#!/bin/sh
+# Make sure cp -p isn't too generous with existing file permissions.
+
+# Copyright (C) 2006-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ cp
+
+require_membership_in_two_groups_
+
+# cp -p gives ENOTSUP on NFS on Linux 2.6.9 at least
+require_local_dir_
+
+require_no_default_acl_ .
+
+set _ $groups; shift
+g1=$1
+g2=$2
+
+
+umask 077
+mkfifo_or_skip_ fifo
+
+touch fifo-copy &&
+chgrp $g1 fifo &&
+chgrp $g2 fifo-copy &&
+chmod g+r fifo-copy || framework-failure
+
+# Terminate any background cp process
+cleanup_() { kill $pid 2>/dev/null && wait $pid; }
+
+# Copy a fifo's contents. That way, we can examine the
+# destination permissions before they're finalized.
+cp -p --copy-contents fifo fifo-copy & pid=$!
+
+(
+ # Now 'cp' is reading the fifo. Wait for the destination file to
+ # be written to, encouraging things along by echoing to the fifo.
+ while test ! -s fifo-copy; do
+ echo foo
+ done
+
+ # Check the permissions of the destination.
+ ls -l -n fifo-copy >ls.out &&
+
+ # Close the fifo so that "cp" can continue. But output first,
+ # before exiting, otherwise some shells would optimize away the file
+ # descriptor that holds the fifo open.
+ echo foo
+) >fifo || fail=1
+
+# Check that the destination mode is safe while the file is being copied.
+read mode links owner group etc <ls.out || fail=1
+case $mode in
+ -rw-------*) ;;
+
+ # FIXME: Remove the following case; the file mode should always be
+ # 600 while the data are being copied. This will require changing
+ # cp so that it also does not put $g1's data in a file that is
+ # accessible to $g2. This fix will not close a security hole, since
+ # a $g2 process can maintain an open file descriptor to the
+ # destination, but it's safer anyway.
+ -rw-r-----*)
+ # If the file has group $g1 and is group-readable, that is definitely bogus,
+ # as neither the source nor the destination was readable to group $g1.
+ test "$group" = "$g1" && fail=1;;
+
+ *) fail=1;;
+esac
+
+wait $pid || fail=1
+
+# Check that the final mode and group are right.
+ls -l -n fifo-copy >ls.out &&
+read mode links owner group etc <ls.out || fail=1
+case $mode in
+ -rw-------*) test "$group" = "$g1" || fail=1;;
+ *) fail=1;;
+esac
+
+Exit $fail
diff --git a/tests/cp/fail-perm.sh b/tests/cp/fail-perm.sh
new file mode 100755
index 0000000..be32d5d
--- /dev/null
+++ b/tests/cp/fail-perm.sh
@@ -0,0 +1,66 @@
+#!/bin/sh
+
+# Copyright (C) 2000-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ cp
+skip_if_root_
+
+chmod g-s . || framework_failure_
+mkdir D D/D || framework_failure_
+touch D/a || framework_failure_
+chmod 0 D/a || framework_failure_
+chmod u=rx,go=,-st D || framework_failure_
+
+
+# This is expected to exit non-zero, because it can't read D/a.
+returns_ 1 cp -pR D DD > /dev/null 2>&1 || fail=1
+
+# Permissions on DD must be 'dr-x------'
+
+mode=$(ls -ld DD|cut -b-10)
+test "$mode" = dr-x------ || fail=1
+
+chmod 0 D
+ln -s D/D symlink
+touch F
+cat > exp <<\EOF
+cp: cannot stat 'symlink': Permission denied
+EOF
+
+cp F symlink 2> out && fail=1
+# HPUX appears to fail with EACCES rather than EPERM.
+# Transform their diagnostic
+# ...: The file access permissions do not allow the specified action.
+# to the expected one:
+sed 's/: The file access permissions.*/: Permission denied/'<out>o1;mv o1 out
+compare exp out || fail=1
+
+cp --no-target-directory F symlink 2> out && fail=1
+sed 's/: The file access permissions.*/: Permission denied/'<out>o1;mv o1 out
+compare exp out || fail=1
+
+cat > exp <<\EOF
+cp: target directory 'symlink': Permission denied
+EOF
+
+cp --target-directory=symlink F 2> out && fail=1
+sed 's/: The file access permissions.*/: Permission denied/'<out>o1;mv o1 out
+compare exp out || fail=1
+
+chmod 700 D
+
+Exit $fail
diff --git a/tests/cp/file-perm-race.sh b/tests/cp/file-perm-race.sh
new file mode 100755
index 0000000..7036884
--- /dev/null
+++ b/tests/cp/file-perm-race.sh
@@ -0,0 +1,58 @@
+#!/bin/sh
+# Make sure cp -p isn't too generous with file permissions.
+
+# Copyright (C) 2006-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ cp
+
+# cp -p gives ENOTSUP on NFS on Linux 2.6.9 at least
+require_local_dir_
+
+umask 022
+mkfifo_or_skip_ fifo
+
+# Terminate any background cp process
+cleanup_() { kill $pid 2>/dev/null && wait $pid; }
+
+# Copy a fifo's contents. That way, we can examine the
+# destination permissions before they're finalized.
+cp -p --copy-contents fifo fifo-copy & pid=$!
+
+(
+ # Now 'cp' is reading the fifo. Wait for the destination file to
+ # be created, encouraging things along by echoing to the fifo.
+ while test ! -f fifo-copy; do
+ echo foo
+ done
+
+ # Check the permissions of the destination.
+ ls -l fifo-copy >ls.out
+
+ # Close the fifo so that "cp" can continue. But output first,
+ # before exiting, otherwise some shells would optimize away the file
+ # descriptor that holds the fifo open.
+ echo foo
+) >fifo
+
+case $(cat ls.out) in
+-???------*) ;;
+*) fail=1;;
+esac
+
+wait $pid || fail=1
+
+Exit $fail
diff --git a/tests/cp/into-self.sh b/tests/cp/into-self.sh
new file mode 100755
index 0000000..fb2e820
--- /dev/null
+++ b/tests/cp/into-self.sh
@@ -0,0 +1,57 @@
+#!/bin/sh
+# Confirm that copying a directory into itself gets a proper diagnostic.
+
+# Copyright (C) 2001-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+# In 4.0.35 and earlier, 'mkdir dir && cp -R dir dir' would produce this:
+# cp: won't create hard link 'dir/dir/dir' to directory ''
+# Now it gives this:
+# cp: can't copy a directory 'dir' into itself 'dir/dir'
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ cp
+
+mkdir a dir || framework_failure_
+
+
+# This command should exit nonzero.
+cp -R dir dir 2> out && fail=1
+echo 1 >> out
+
+# This should, too. However, with coreutils-7.1 it would infloop.
+cp -rl dir dir 2>> out && fail=1
+echo 2 >> out
+
+cp -rl a dir dir 2>> out && fail=1
+echo 3 >> out
+cp -rl a dir dir 2>> out && fail=1
+echo 4 >> out
+
+cat > exp <<\EOF
+cp: cannot copy a directory, 'dir', into itself, 'dir/dir'
+1
+cp: cannot copy a directory, 'dir', into itself, 'dir/dir'
+2
+cp: cannot copy a directory, 'dir', into itself, 'dir/dir'
+3
+cp: cannot copy a directory, 'dir', into itself, 'dir/dir'
+4
+EOF
+#'
+
+compare exp out || fail=1
+
+Exit $fail
diff --git a/tests/cp/link-deref.sh b/tests/cp/link-deref.sh
new file mode 100755
index 0000000..28b20a2
--- /dev/null
+++ b/tests/cp/link-deref.sh
@@ -0,0 +1,126 @@
+#!/bin/sh
+# Exercise cp --link's behavior regarding the dereferencing of symbolic links.
+
+# Copyright (C) 2013-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ cp
+
+if { grep '^#define HAVE_LINKAT 1' "$CONFIG_HEADER" > /dev/null \
+ && grep '#undef LINKAT_SYMLINK_NOTSUP' "$CONFIG_HEADER" > /dev/null; } \
+ || grep '^#define LINK_FOLLOWS_SYMLINKS 0' "$CONFIG_HEADER" > /dev/null; then
+ # With this config cp will attempt to linkat() to hardlink a symlink.
+ # So now double check the current file system supports this operation.
+ ln -s testtarget test_sl || framework_failure_
+ ln -P test_sl test_hl_sl || framework_failure_
+ ino_sl="$(stat -c '%i' test_sl)" || framework_failure_
+ ino_hl="$(stat -c '%i' test_hl_sl)" || framework_failure_
+ test "$ino_sl" = "$ino_hl" && can_hardlink_to_symlink=1
+fi
+
+mkdir dir || framework_failure_
+> file || framework_failure_
+ln -s dir dirlink || framework_failure_
+ln -s file filelink || framework_failure_
+ln -s nowhere danglink || framework_failure_
+
+# printf format of the output line.
+outformat='%s|result=%s|inode=%s|type=%s|error=%s\n'
+
+for src in dirlink filelink danglink; do
+ # Get symlink's target.
+ tgt=$(readlink $src) || framework_failure_
+ # Get inodes and file type of the symlink (src) and its target (tgt).
+ # Note: this will fail for 'danglink'; catch it.
+ ino_src="$(stat -c '%i' $src)" || framework_failure_
+ typ_src="$(stat -c '%F' $src)" || framework_failure_
+ ino_tgt="$(stat -c '%i' $tgt 2>/dev/null)" || ino_tgt=
+ typ_tgt="$(stat -c '%F' $tgt 2>/dev/null)" || typ_tgt=
+
+ for o in '' -L -H -P; do
+
+ # Skip the -P case where we don't or can't hardlink symlinks
+ ! test "$can_hardlink_to_symlink" && test "$o" = '-P' && continue
+
+ for r in '' -R; do
+
+ command="cp --link $o $r $src dst"
+ $command 2> err
+ result=$?
+
+ # Get inode and file type of the destination (which may fail, too).
+ ino_dst="$(stat -c '%i' dst 2>/dev/null)" || ini_dst=
+ typ_dst="$(stat -c '%F' dst 2>/dev/null)" || typ_dst=
+
+ # Print the actual result in a certain format.
+ printf "$outformat" \
+ "$command" \
+ "$result" \
+ "$ino_dst" \
+ "$typ_dst" \
+ "$(cat err)" \
+ > out
+
+ # What was expected?
+ if [ "$o" = "-P" ]; then
+ # cp --link should not dereference if -P is given.
+ exp_result=0
+ exp_inode=$ino_src
+ exp_ftype=$typ_src
+ exp_error=
+ elif [ "$src" = 'danglink' ]; then
+ # Dereferencing should fail for the 'danglink'.
+ exp_result=1
+ exp_inode=
+ exp_ftype=
+ exp_error="cp: cannot stat 'danglink': No such file or directory"
+ elif [ "$src" = 'dirlink' ] && [ "$r" != '-R' ]; then
+ # Dereferencing should fail for the 'dirlink' without -R.
+ exp_result=1
+ exp_inode=
+ exp_ftype=
+ exp_error="cp: -r not specified; omitting directory 'dirlink'"
+ elif [ "$src" = 'dirlink' ]; then
+ # cp --link -R 'dirlink' should create a new directory.
+ exp_result=0
+ exp_inode=$ino_dst
+ exp_ftype=$typ_dst
+ exp_error=
+ else
+ # cp --link 'filelink' should create a hard link to the target.
+ exp_result=0
+ exp_inode=$ino_tgt
+ exp_ftype=$typ_tgt
+ exp_error=
+ fi
+
+ # Print the expected result in a certain format.
+ printf "$outformat" \
+ "$command" \
+ "$exp_result" \
+ "$exp_inode" \
+ "$exp_ftype" \
+ "$exp_error" \
+ > exp
+
+ compare exp out || { ls -lid $src $tgt dst; fail=1; }
+
+ rm -rf dst err exp out || framework_failure_
+ done
+ done
+done
+
+Exit $fail
diff --git a/tests/cp/link-heap.sh b/tests/cp/link-heap.sh
new file mode 100755
index 0000000..42ac9a9
--- /dev/null
+++ b/tests/cp/link-heap.sh
@@ -0,0 +1,42 @@
+#!/bin/sh
+# ensure that cp --preserve=link --link doesn't waste heap
+
+# Copyright (C) 2008-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ cp
+expensive_
+
+# Determine basic amount of memory needed for 'cp -al'.
+touch f || framework_failure_
+vm=$(get_min_ulimit_v_ cp -al f f2) \
+ || skip_ "this shell lacks ulimit support"
+rm f f2 || framework_failure_
+
+a=$(printf %031d 0)
+b=$(printf %031d 1)
+(mkdir $a \
+ && cd $a \
+ && seq --format=%031g 10000 |xargs touch \
+ && seq --format=d%030g 10000 |xargs mkdir ) || framework_failure_
+cp -al $a $b || framework_failure_
+mkdir e || framework_failure_
+mv $a $b e || framework_failure_
+
+# Allow cp(1) to use 4MiB more virtual memory than for the above trivial case.
+(ulimit -v $(($vm+4000)) && cp -al e f) || fail=1
+
+Exit $fail
diff --git a/tests/cp/link-no-deref.sh b/tests/cp/link-no-deref.sh
new file mode 100755
index 0000000..2c60ef6
--- /dev/null
+++ b/tests/cp/link-no-deref.sh
@@ -0,0 +1,29 @@
+#!/bin/sh
+# Ensure that cp --link --no-dereference works properly
+
+# Copyright (C) 2006-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ cp
+
+ln -s no-such-file dangling-slink || framework_failure_
+
+
+# Prior to coreutils-6.0, this would fail on non-Linux kernels,
+# with link being applied to the dangling symlink.
+cp --link --no-dereference dangling-slink d2 || fail=1
+
+Exit $fail
diff --git a/tests/cp/link-preserve.sh b/tests/cp/link-preserve.sh
new file mode 100755
index 0000000..c938a94
--- /dev/null
+++ b/tests/cp/link-preserve.sh
@@ -0,0 +1,91 @@
+#!/bin/sh
+# ensure that 'cp -d' preserves hard-links between command line arguments
+# ensure that --preserve=links works with -RH and -RL
+
+# Copyright (C) 2001-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ cp
+
+touch a || framework_failure_
+ln a b || framework_failure_
+mkdir c || framework_failure_
+cp -d a b c || framework_failure_
+test -f c/a || framework_failure_
+test -f c/b || framework_failure_
+
+
+a_inode=$(ls -i c/a|sed 's,c/.*,,')
+b_inode=$(ls -i c/b|sed 's,c/.*,,')
+test "$a_inode" = "$b_inode" || fail=1
+# --------------------------------------
+
+rm -rf a b c
+touch a
+ln -s a b
+mkdir c
+cp --preserve=links -R -H a b c || fail=1
+a_inode=$(ls -i c/a|sed 's,c/.*,,')
+b_inode=$(ls -i c/b|sed 's,c/.*,,')
+test "$a_inode" = "$b_inode" || fail=1
+# --------------------------------------
+
+# Ensure that -L makes cp follow the b->a symlink
+# and translates to hard-linked a and b in the destination dir.
+rm -rf a b c d; mkdir d; (cd d; touch a; ln -s a b)
+cp --preserve=links -R -L d c || fail=1
+a_inode=$(ls -i c/a|sed 's,c/.*,,')
+b_inode=$(ls -i c/b|sed 's,c/.*,,')
+test "$a_inode" = "$b_inode" || fail=1
+# --------------------------------------
+
+# Same as above, but starting with a/b hard linked.
+rm -rf a b c d; mkdir d; (cd d; touch a; ln a b)
+cp --preserve=links -R -L d c || fail=1
+a_inode=$(ls -i c/a|sed 's,c/.*,,')
+b_inode=$(ls -i c/b|sed 's,c/.*,,')
+test "$a_inode" = "$b_inode" || fail=1
+# --------------------------------------
+
+# Ensure that --no-preserve=links works.
+rm -rf a b c d; mkdir d; (cd d; touch a; ln a b)
+cp -dR --no-preserve=links d c || fail=1
+a_inode=$(ls -i c/a|sed 's,c/.*,,')
+b_inode=$(ls -i c/b|sed 's,c/.*,,')
+test "$a_inode" = "$b_inode" && fail=1
+# --------------------------------------
+
+# Ensure that -d still preserves hard links.
+rm -rf a b c d
+touch a; ln a b
+mkdir c
+cp -d a b c || fail=1
+a_inode=$(ls -i c/a|sed 's,c/.*,,')
+b_inode=$(ls -i c/b|sed 's,c/.*,,')
+test "$a_inode" = "$b_inode" || fail=1
+# --------------------------------------
+
+# Ensure that --no-preserve=mode works
+rm -rf a b c d
+touch a; chmod 731 a
+umask 077
+cp -a --no-preserve=mode a b || fail=1
+mode=$(ls -l b|cut -b-10)
+test "$mode" = "-rw-------" || fail=1
+umask 022
+# --------------------------------------
+
+Exit $fail
diff --git a/tests/cp/link-symlink.sh b/tests/cp/link-symlink.sh
new file mode 100755
index 0000000..8df5384
--- /dev/null
+++ b/tests/cp/link-symlink.sh
@@ -0,0 +1,41 @@
+#!/bin/sh
+# Ensure that cp -a --link maintains timestamps if possible
+
+# Copyright (C) 2011-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ cp
+
+# Check that the timestamps of the symlink are copied
+# if we're using hardlink to symlink emulation.
+touch file
+ln -s file link || framework_failure_
+touch -m -h -d 2011-01-01 link ||
+ skip_ "Your system doesn't support updating symlink timestamps"
+case $(stat --format=%y link) in
+ 2011-01-01*) ;;
+ *) skip_ "Your system doesn't support updating symlink timestamps" ;;
+esac
+
+# link.cp is probably a hardlink, but may also be a symlink
+# In either case the timestamp should match the original.
+cp -al link link.cp || fail=1
+case $(stat --format=%y link.cp) in
+ 2011-01-01*) ;;
+ *) fail=1 ;;
+esac
+
+Exit $fail
diff --git a/tests/cp/link.sh b/tests/cp/link.sh
new file mode 100755
index 0000000..e560154
--- /dev/null
+++ b/tests/cp/link.sh
@@ -0,0 +1,31 @@
+#!/bin/sh
+# Make sure cp --link -f works when the target exists.
+# This failed for 4.0z (due to a bug introduced in that test release).
+
+# Copyright (C) 2000-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ cp
+
+touch src || framework_failure_
+touch dest || framework_failure_
+touch dest2 || framework_failure_
+
+
+cp -f --link src dest || fail=1
+cp -f --symbolic-link src dest2 || fail=1
+
+Exit $fail
diff --git a/tests/cp/nfs-removal-race.sh b/tests/cp/nfs-removal-race.sh
new file mode 100755
index 0000000..679397e
--- /dev/null
+++ b/tests/cp/nfs-removal-race.sh
@@ -0,0 +1,75 @@
+#!/bin/sh
+# Running cp S D on an NFS client while another client has just removed D
+# would lead (w/coreutils-8.16 and earlier) to cp's initial stat call
+# seeing (via stale NFS cache) that D exists, so that cp would then call
+# open without the O_CREAT flag. Yet, the open must actually consult
+# the server, which confesses that D has been deleted, thus causing the
+# open call to fail with ENOENT.
+#
+# This test simulates that situation by intercepting stat for a nonexistent
+# destination, D, and making the stat fill in the result struct for another
+# file and return 0.
+#
+# This test is skipped on systems that lack LD_PRELOAD support; that's fine.
+# Similarly, on a system that lacks <dlfcn.h> or __xstat, skipping it is fine.
+
+# Copyright (C) 2012-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ cp
+require_gcc_shared_
+
+# Replace each stat call with a call to this wrapper.
+cat > k.c <<'EOF' || framework_failure_
+#define _GNU_SOURCE
+#include <stdio.h>
+#include <sys/types.h>
+#include <dlfcn.h>
+
+#define __xstat __xstat_orig
+
+#include <sys/stat.h>
+#include <stddef.h>
+
+#undef __xstat
+
+int
+__xstat (int ver, const char *path, struct stat *st)
+{
+ static int (*real_stat)(int ver, const char *path, struct stat *st) = NULL;
+ fclose(fopen("preloaded", "w"));
+ if (!real_stat)
+ real_stat = dlsym (RTLD_NEXT, "__xstat");
+ /* When asked to stat nonexistent "d",
+ return results suggesting it exists. */
+ return real_stat (ver, *path == 'd' && path[1] == 0 ? "d2" : path, st);
+}
+EOF
+
+# Then compile/link it:
+gcc_shared_ k.c k.so \
+ || framework_failure_ 'failed to build shared library'
+
+touch d2 || framework_failure_
+echo xyz > src || framework_failure_
+
+# Finally, run the test:
+LD_PRELOAD=$LD_PRELOAD:./k.so cp src d || fail=1
+
+test -f preloaded || skip_ 'LD_PRELOAD was ineffective?'
+
+compare src d || fail=1
+Exit $fail
diff --git a/tests/cp/no-ctx.sh b/tests/cp/no-ctx.sh
new file mode 100755
index 0000000..8c69bf3
--- /dev/null
+++ b/tests/cp/no-ctx.sh
@@ -0,0 +1,65 @@
+#!/bin/sh
+# Ensure we handle file systems returning no SELinux context,
+# which triggered a segmentation fault in coreutils-8.22.
+# This test is skipped on systems that lack LD_PRELOAD support; that's fine.
+# Similarly, on a system that lacks lgetfilecon altogether, skipping it is fine.
+
+# Copyright (C) 2014-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ cp
+require_gcc_shared_
+require_selinux_
+
+# Replace each getfilecon and lgetfilecon call with a call to these stubs.
+cat > k.c <<'EOF' || framework_failure_
+#include <stdio.h>
+#include <selinux/selinux.h>
+#include <errno.h>
+
+int getfilecon (const char *path, char **con)
+{
+ /* Leave a marker so we can identify if the function was intercepted. */
+ fclose(fopen("preloaded", "w"));
+
+ errno=ENODATA;
+ return -1;
+}
+
+int lgetfilecon (const char *path, char **con)
+{ return getfilecon (path, con); }
+EOF
+
+# Then compile/link it:
+gcc_shared_ k.c k.so \
+ || skip_ 'failed to build SELinux shared library'
+
+touch file_src
+
+# New file with SELinux context optionally included
+LD_PRELOAD=$LD_PRELOAD:./k.so cp -a file_src file_dst || fail=1
+
+# Existing file with SELinux context optionally included
+LD_PRELOAD=$LD_PRELOAD:./k.so cp -a file_src file_dst || fail=1
+
+# ENODATA should give an immediate error when required to preserve ctx
+# This is debatable, and maybe we should not fail when no context available?
+( export LD_PRELOAD=$LD_PRELOAD:./k.so
+ returns_ 1 cp --preserve=context file_src file_dst ) || fail=1
+
+test -e preloaded || skip_ 'LD_PRELOAD interception failed'
+
+Exit $fail
diff --git a/tests/cp/no-deref-link1.sh b/tests/cp/no-deref-link1.sh
new file mode 100755
index 0000000..3b3d992
--- /dev/null
+++ b/tests/cp/no-deref-link1.sh
@@ -0,0 +1,37 @@
+#!/bin/sh
+# cp from 3.16 fails this test
+
+# Copyright (C) 1997-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ cp
+
+mkdir a b
+msg=bar
+echo $msg > a/foo
+cd b
+ln -s ../a/foo .
+cd ..
+
+
+# It should fail with a message something like this:
+# ./cp: 'a/foo' and 'b/foo' are the same file
+# Fail this test if the exit status is not 1
+returns_ 1 cp -d a/foo b 2>/dev/null || fail=1
+
+test "$(cat a/foo)" = $msg || fail=1
+
+Exit $fail
diff --git a/tests/cp/no-deref-link2.sh b/tests/cp/no-deref-link2.sh
new file mode 100755
index 0000000..6eb47a8
--- /dev/null
+++ b/tests/cp/no-deref-link2.sh
@@ -0,0 +1,37 @@
+#!/bin/sh
+# cp from 3.16 fails this test
+
+# Copyright (C) 1997-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ cp
+
+mkdir b
+msg=bar
+echo $msg > a
+cd b
+ln -s ../a .
+cd ..
+
+
+# It should fail with a message something like this:
+# cp: 'a' and 'b/foo' are the same file
+# Fail this test if the exit status is not 1
+returns_ 1 cp -d a b 2>/dev/null || fail=1
+
+test "$(cat a)" = $msg || fail=1
+
+Exit $fail
diff --git a/tests/cp/no-deref-link3.sh b/tests/cp/no-deref-link3.sh
new file mode 100755
index 0000000..1d7d704
--- /dev/null
+++ b/tests/cp/no-deref-link3.sh
@@ -0,0 +1,34 @@
+#!/bin/sh
+# cp from 3.16 fails this test
+
+# Copyright (C) 1997-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ cp
+
+msg=bar
+echo $msg > a
+ln -s a b
+
+
+# It should fail with a message something like this:
+# cp: 'a' and 'b' are the same file
+# Fail this test if the exit status is not 1
+returns_ 1 cp -d a b 2>/dev/null || fail=1
+
+test "$(cat a)" = $msg || fail=1
+
+Exit $fail
diff --git a/tests/cp/parent-perm-race.sh b/tests/cp/parent-perm-race.sh
new file mode 100755
index 0000000..694ffd9
--- /dev/null
+++ b/tests/cp/parent-perm-race.sh
@@ -0,0 +1,59 @@
+#!/bin/sh
+# Make sure cp -pR --parents isn't too generous with parent permissions.
+
+# Copyright (C) 2006-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ cp
+
+# cp -p gives ENOTSUP on NFS on Linux 2.6.9 at least
+require_local_dir_
+
+umask 002
+mkdir mode ownership d || framework_failure_
+chmod g+s d 2>/dev/null # The cp test is valid either way.
+
+# Terminate any background cp process.
+pid=
+cleanup_() { kill $pid 2>/dev/null && wait $pid; }
+
+for attr in mode ownership
+do
+ mkfifo_or_skip_ $attr/fifo
+
+ # Copy a fifo's contents. That way, we can examine d/$attr's
+ # state while cp is running.
+ timeout 10 cp --preserve=$attr -R --copy-contents --parents $attr d & pid=$!
+
+ # Check the permissions of the destination directory that 'cp' has made.
+ # 'ls' won't start until after 'cp' has made the destination directory
+ # $d/attr and has started to read the source file $attr/fifo.
+ timeout 10 sh -c "ls -ld d/$attr >$attr/fifo" || fail=1
+
+ wait $pid || fail=1
+
+ ls_output=$(cat d/$attr/fifo) || fail=1
+ case $attr,$ls_output in
+ ownership,d???--[-S]--[-S]* | \
+ mode,d????-??-?* | \
+ mode,d??[-x]?w[-x]?-[-x]* )
+ ;;
+ *)
+ fail=1;;
+ esac
+done
+
+Exit $fail
diff --git a/tests/cp/parent-perm.sh b/tests/cp/parent-perm.sh
new file mode 100755
index 0000000..a79164e
--- /dev/null
+++ b/tests/cp/parent-perm.sh
@@ -0,0 +1,53 @@
+#!/bin/sh
+# Ensure that cp --parents works properly with a preexisting dest. directory
+
+# Copyright (C) 2008-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ cp
+
+working_umask_or_skip_
+# cp -p gives ENOTSUP on NFS on Linux 2.6.9 at least
+require_local_dir_
+
+mkdir -p a/b/c a/b/d e || framework_failure_
+touch a/b/c/foo a/b/d/foo || framework_failure_
+cp -p --parent a/b/c/foo e || framework_failure_
+
+# Make permissions of e/a different, so that we exercise the
+# code in cp -p --parents that propagates permissions even
+# to a destination directory that it doesn't create.
+chmod g-rx e/a e/a/b || framework_failure_
+
+cp -p --parent a/b/d/foo e || fail=1
+
+# Ensure that permissions on just-created directory, e/a/,
+# are the same as those on original, a/.
+
+# The sed filter maps any 's' from an inherited set-GID bit
+# to the usual 'x'. Otherwise, under unusual circumstances, this
+# test would fail with e.g., drwxr-sr-x != drwxr-xr-x .
+# For reference, the unusual circumstances is: build dir is set-gid,
+# so "a/" inherits that. However, when the user does not belong to
+# the group of the build directory, chmod ("a/e", 02755) returns 0,
+# yet fails to set the S_ISGID bit.
+for dir in a a/b a/b/d; do
+ test $(stat --printf %A $dir|sed s/s/x/g) \
+ = $(stat --printf %A e/$dir|sed s/s/x/g) ||
+ fail=1
+done
+
+Exit $fail
diff --git a/tests/cp/perm.sh b/tests/cp/perm.sh
new file mode 100755
index 0000000..c6414aa
--- /dev/null
+++ b/tests/cp/perm.sh
@@ -0,0 +1,77 @@
+#!/bin/sh
+# Make sure the permission-preserving code in copy.c (mv, cp, install) works.
+
+# Copyright (C) 2000-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ cp mv
+
+very_expensive_
+
+umask 037
+
+
+# Now, try it with 'mv', with combinations of --force, no-f and
+# existing-destination and not.
+for u in 31 37 2; do
+ echo umask: $u
+ umask $u
+ for cmd in mv 'cp -p' cp; do
+ for force in '' -f; do
+ for existing_dest in yes no; do
+ for g_perm in r w x rw wx xr rwx; do
+ for o_perm in r w x rw wx xr rwx; do
+ touch src || exit 1
+ chmod u=r,g=rx,o= src || exit 1
+ expected_perms=$(stat --format=%A src)
+ rm -f dest
+ test $existing_dest = yes && {
+ touch dest || exit 1
+ chmod u=rw,g=$g_perm,o=$o_perm dest || exit 1
+ }
+ $cmd $force src dest || exit 1
+ test "$cmd" = mv && test -f src && exit 1
+ test "$cmd" = cp && { test -f src || exit 1; }
+ actual_perms=$(stat --format=%A dest)
+
+ case "$cmd:$force:$existing_dest" in
+ cp:*:yes)
+ _g_perm=$(echo rwx|sed 's/[^'$g_perm']/-/g')
+ _o_perm=$(echo rwx|sed 's/[^'$o_perm']/-/g')
+ expected_perms=-rw-$_g_perm$_o_perm
+ ;;
+ cp:*:no)
+ test $u = 37 &&
+ expected_perms=$(
+ echo $expected_perms | sed 's/.....$/-----/'
+ )
+ test $u = 31 &&
+ expected_perms=$(
+ echo $expected_perms | sed 's/..\(..\).$/--\1-/'
+ )
+ ;;
+ esac
+ test _$actual_perms = _$expected_perms || exit 1
+ # Perform only one iteration when there's no existing destination.
+ test $existing_dest = no && break 3
+ done
+ done
+ done
+ done
+ done
+done
+
+Exit $fail
diff --git a/tests/cp/preserve-2.sh b/tests/cp/preserve-2.sh
new file mode 100755
index 0000000..ed1a9c1
--- /dev/null
+++ b/tests/cp/preserve-2.sh
@@ -0,0 +1,29 @@
+#!/bin/sh
+# ensure that cp's --preserve=X,Y option is parsed properly
+
+# Copyright (C) 2002-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ cp
+
+# cp -p gives ENOTSUP on NFS on Linux 2.6.9 at least
+require_local_dir_
+
+touch f || framework_failure_
+
+cp --preserve=mode,links f g || fail=1
+
+Exit $fail
diff --git a/tests/cp/preserve-gid.sh b/tests/cp/preserve-gid.sh
new file mode 100755
index 0000000..4add028
--- /dev/null
+++ b/tests/cp/preserve-gid.sh
@@ -0,0 +1,146 @@
+#!/bin/sh
+# Verify that cp -p preserves GID when it is possible.
+
+# Copyright (C) 2007-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ cp
+
+require_perl_
+require_root_
+
+# Some of the tests expect a umask that grants group and/or world read access.
+working_umask_or_skip_
+
+# Record primary group number, usually 0.
+# This is the group ID used when cp (without -p) creates a new file.
+primary_group_num=$(id -g)
+
+create() {
+ echo "$1" > "$1" || exit 1
+ chown "+$2:+$3" "$1" || exit 1
+}
+
+t0() {
+ f=$1; shift
+ u=$1; shift
+ g=$1; shift
+ rm -f b || exit 1
+ "$@" "$f" b || exit 1
+ s=$(stat -c '%u %g' b)
+ if test "x$s" != "x$u $g"; then
+ # Allow the actual group to match that of the parent directory
+ # (it was set to 0 above).
+ if test "x$s" = "x$u $primary_group_num"; then
+ :
+ else
+ echo "$0: $* $f b: $u $g != $s" 1>&2
+ Exit 1
+ fi
+ fi
+}
+
+nameless_uid=$($PERL -le '
+ foreach my $i (1000..16*1024-1)
+ {
+ getpwuid $i or (print $i), exit
+ }
+')
+nameless_gid1=$($PERL -le '
+ foreach my $i (1000..16*1024)
+ {
+ getgrgid $i or (print $i), exit
+ }
+')
+nameless_gid2=$($PERL -le '
+ foreach my $i ('"$nameless_gid1"'+1..16*1024)
+ {
+ getgrgid $i or (print $i), exit
+ }
+')
+
+if test -z "$nameless_uid" \
+ || test -z "$nameless_gid1" \
+ || test -z "$nameless_gid2"; then
+ skip_ "couldn't find a nameless UID or GID"
+fi
+
+chown "+$nameless_uid:+0" .
+
+create a0 0 0
+create b0 "$nameless_uid" "$nameless_gid1"
+create b1 "$nameless_uid" "$nameless_gid2"
+create c0 0 "$nameless_gid1"
+create c1 0 "$nameless_gid2"
+
+t0 a0 0 0 cp
+t0 b0 0 0 cp
+t0 b1 0 0 cp
+t0 c0 0 0 cp
+t0 c1 0 0 cp
+
+t0 a0 0 0 cp -p
+t0 b0 "$nameless_uid" "$nameless_gid1" cp -p
+t0 b1 "$nameless_uid" "$nameless_gid2" cp -p
+t0 c0 0 "$nameless_gid1" cp -p
+t0 c1 0 "$nameless_gid2" cp -p
+
+# For the remaining tests, we need a cp binary that is accessible to a user
+# with UID of $nameless_uid. The build directory may not be accessible,
+# so create a temporary directory and copy cp into it, ensure that
+# $nameless_uid can access it and then make that directory the search path.
+tmp_path=
+cleanup_() { rm -rf "$tmp_path"; }
+
+# Cause mktemp to create a directory directly under /tmp.
+# Setting TMPDIR explicitly is required here, in case $TMPDIR
+# is not readable by our nameless IDs.
+test -d /tmp && TMPDIR=/tmp
+tmp_path=$(mktemp -d) || fail_ "failed to create temporary directory"
+if test -x "$abs_path_dir_/coreutils" &&
+ { test -L "$abs_path_dir_/cp" ||
+ test $(wc -l < "$abs_path_dir_/cp") = 1; } then
+ # if configured with --enable-single-binary we need to use the single binary
+ cp "$abs_path_dir_/coreutils" "$tmp_path/cp" || framework_failure_
+else
+ cp "$abs_path_dir_/cp" "$tmp_path"
+fi
+chmod -R a+rx "$tmp_path"
+
+t1() {
+ f=$1; shift
+ u=$1; shift
+ g=$1; shift
+ t0 "$f" "$u" "$g" \
+ chroot --skip-chdir \
+ --user=+$nameless_uid:+$nameless_gid1 \
+ --groups="+$nameless_gid1,+$nameless_gid2" \
+ / env PATH="$tmp_path" "$@"
+}
+
+t1 a0 "$nameless_uid" "$nameless_gid1" cp
+t1 b0 "$nameless_uid" "$nameless_gid1" cp
+t1 b1 "$nameless_uid" "$nameless_gid1" cp
+t1 c0 "$nameless_uid" "$nameless_gid1" cp
+t1 c1 "$nameless_uid" "$nameless_gid1" cp
+
+t1 a0 "$nameless_uid" "$nameless_gid1" cp -p
+t1 b0 "$nameless_uid" "$nameless_gid1" cp -p
+t1 b1 "$nameless_uid" "$nameless_gid2" cp -p
+t1 c0 "$nameless_uid" "$nameless_gid1" cp -p
+t1 c1 "$nameless_uid" "$nameless_gid2" cp -p
+
+Exit $fail
diff --git a/tests/cp/preserve-link.sh b/tests/cp/preserve-link.sh
new file mode 100755
index 0000000..83b3467
--- /dev/null
+++ b/tests/cp/preserve-link.sh
@@ -0,0 +1,92 @@
+#!/bin/sh
+# Exercise the fix for https://bugs.gnu.org/8419
+
+# Copyright (C) 2011-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ cp
+
+same_inode()
+{
+ local u v
+ u=$(stat --format %i "$1") &&
+ v=$(stat --format %i "$2") && test "$u" = "$v"
+}
+
+create_source_tree()
+{
+ rm -Rf s
+ mkdir s || framework_failure_
+
+ # a missing link in dest will be created
+ touch s/f || framework_failure_
+ ln s/f s/linkm || framework_failure_
+
+ # an existing link in dest will be maintained
+ ln s/f s/linke || framework_failure_
+
+ # a separate older file in dest will be overwritten
+ ln s/f s/fileo || framework_failure_
+
+ # a separate newer file in dest will be overwritten!
+ ln s/f s/fileu || framework_failure_
+}
+
+create_target_tree()
+{
+ f=$1 # which of f or linkm to create in t/
+
+ rm -Rf t
+ mkdir -p t/s/ || framework_failure_
+
+ # a missing link in dest must be created
+ touch t/s/$f || framework_failure_
+
+ # an existing link must be maintained
+ ln t/s/$f t/s/linke || framework_failure_
+
+ # a separate older file in dest will be overwritten
+ touch -d '-1 hour' t/s/fileo || framework_failure_
+
+ # a separate newer file in dest will be overwritten!
+ touch -d '+1 hour' t/s/fileu || framework_failure_
+}
+
+
+# Note we repeat this, creating either one of
+# two hard linked files from source in the dest, so as to
+# test both paths in $(cp) for creating the hard links.
+# The path taken by cp is dependent on which cp encounters
+# first in the source, which is non deterministic currently
+# (I'm guessing that results are sorted by inode and
+# because they're the same here, and due to the sort
+# being unstable, either can be processed first).
+create_source_tree
+
+for f in f linkm; do
+ create_target_tree $f
+
+ # Copy all the hard links across. With cp from coreutils-8.12
+ # and prior, it would sometimes mistakenly copy rather than link.
+ cp -au s t || fail=1
+
+ same_inode t/s/f t/s/linkm || fail=1
+ same_inode t/s/f t/s/linke || fail=1
+ same_inode t/s/f t/s/fileo || fail=1
+ same_inode t/s/f t/s/fileu || fail=1
+done
+
+Exit $fail
diff --git a/tests/cp/preserve-mode.sh b/tests/cp/preserve-mode.sh
new file mode 100755
index 0000000..d27801c
--- /dev/null
+++ b/tests/cp/preserve-mode.sh
@@ -0,0 +1,66 @@
+#!/bin/sh
+# Check whether cp generates files with correct modes.
+
+# Copyright (C) 2002-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ cp
+
+get_mode() { stat -c%f "$1"; }
+
+umask 0022 || framework_failure_
+
+#regular file test
+touch a b || framework_failure_
+chmod 600 b || framework_failure_
+cp --no-preserve=mode b c || fail=1
+test "$(get_mode a)" = "$(get_mode c)" || fail=1
+
+#existing destination test
+chmod 600 c || framework_failure_
+cp --no-preserve=mode a b || fail=1
+test "$(get_mode b)" = "$(get_mode c)" || fail=1
+
+#directory test
+mkdir d1 d2 || framework_failure_
+chmod 705 d2 || framework_failure_
+cp --no-preserve=mode -r d2 d3 || fail=1
+test "$(get_mode d1)" = "$(get_mode d3)" || fail=1
+
+#contradicting options test
+rm -f a b || framework_failure_
+touch a || framework_failure_
+chmod 600 a || framework_failure_
+cp --no-preserve=mode --preserve=all a b || fail=1
+test "$(get_mode a)" = "$(get_mode b)" || fail=1
+
+#fifo test
+if mkfifo fifo; then
+ cp -a --no-preserve=mode fifo fifo_copy || fail=1
+ #ensure default perms set appropriate for non regular files
+ #which wasn't done between v8.20 and 8.29 inclusive
+ test "$(get_mode fifo)" = "$(get_mode fifo_copy)" || fail=1
+fi
+
+# Test that plain --preserve=ownership does not affect destination mode.
+rm -f a b c || framework_failure_
+touch a || framework_failure_
+chmod 660 a || framework_failure_
+cp a b || fail=1
+cp --preserve=ownership a c || fail=1
+test "$(get_mode b)" = "$(get_mode c)" || fail=1
+
+Exit $fail
diff --git a/tests/cp/preserve-slink-time.sh b/tests/cp/preserve-slink-time.sh
new file mode 100755
index 0000000..e689f0d
--- /dev/null
+++ b/tests/cp/preserve-slink-time.sh
@@ -0,0 +1,51 @@
+#!/bin/sh
+# Verify that cp -Pp preserves times even on symlinks.
+
+# Copyright (C) 2009-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ cp
+
+grep '^#define HAVE_UTIMENSAT 1' "$CONFIG_HEADER" > /dev/null ||
+grep '^#define HAVE_LUTIMES 1' "$CONFIG_HEADER" > /dev/null ||
+ skip_ 'this system lacks the utimensat function'
+
+ln -s no-such dangle || framework_failure_
+
+# If the current file system lacks sub-second resolution, sleep for 2s to
+# ensure that the times on the copy are different from those of the original.
+case $(stat --format=%y dangle) in
+ ??:??:??.000000000) sleep 2;;
+esac
+
+copy_timestamp_() {
+ sleep $1
+ rm -f d2
+ cp -Pp dangle d2 || framework_failure_
+ # Can't use --format=%x, as lstat() modifies atime on some platforms.
+ stat --format=%y dangle > t1 || framework_failure_
+ stat --format=%y d2 > t2 || framework_failure_
+ compare t1 t2
+}
+
+# We retry with a delay at least 1.5s because on GPFS
+# it was seen that the timestamp wasn't updated unless there
+# was sufficient delay between the ln and cp.
+# I.e., if there wasn't sufficient difference in
+# the timestamp being updated, the update was discarded.
+retry_delay_ copy_timestamp_ .1 4 || fail=1
+
+Exit $fail
diff --git a/tests/cp/proc-short-read.sh b/tests/cp/proc-short-read.sh
new file mode 100755
index 0000000..806fe28
--- /dev/null
+++ b/tests/cp/proc-short-read.sh
@@ -0,0 +1,43 @@
+#!/bin/sh
+# exercise cp's short-read failure when operating on >4KB files in /proc
+
+# Copyright (C) 2009-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ cp
+
+proc_large=/proc/cpuinfo # usually > 4KiB
+
+test -r $proc_large || skip_ "your system lacks $proc_large"
+
+# Before coreutils-7.3, cp would copy less than 4KiB of this file.
+# Skip this test when run under QEmu emulation where emulated /proc files
+# have unstable inode numbers.
+cp $proc_large 1 2>err \
+ || { fail=1
+ grep 'replaced while being copied' err \
+ && skip_ "File $proc_large is being replaced while being copied"; }
+
+cat $proc_large > 2 || fail=1
+
+# adjust varying parts
+del_varying='/MHz/d; /[Bb][Oo][Gg][Oo][Mm][Ii][Pp][Ss]/d;'
+sed "$del_varying" 1 > proc.cp || framework_failure_
+sed "$del_varying" 2 > proc.cat || framework_failure_
+
+compare proc.cp proc.cat || fail=1
+
+Exit $fail
diff --git a/tests/cp/proc-zero-len.sh b/tests/cp/proc-zero-len.sh
new file mode 100755
index 0000000..243fb40
--- /dev/null
+++ b/tests/cp/proc-zero-len.sh
@@ -0,0 +1,47 @@
+#!/bin/sh
+# Ensure that cp copies contents of non-empty "regular" file with st_size==0
+
+# Copyright (C) 2007-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ cp
+
+touch empty || framework_failure_
+
+f=/proc/cpuinfo
+test -r $f || f=empty
+
+cat $f > out || fail=1
+
+# With coreutils-6.9, this would create a zero-length "exp" file.
+# Skip this test on architectures like aarch64 where the inode
+# number of the file changed during the cp run.
+cp $f exp 2>err \
+ || { fail=1;
+ grep 'replaced while being copied' err \
+ && skip_ "File $f is being replaced while being copied"; }
+
+# Don't simply compare contents; they might differ,
+# e.g., if CPU freq changes between cat and cp invocations.
+# Instead, simply compare whether they're both nonempty.
+test -s out \
+ && { rm -f out; echo nonempty > out; }
+test -s exp \
+ && { rm -f exp; echo nonempty > exp; }
+
+compare exp out || fail=1
+
+Exit $fail
diff --git a/tests/cp/r-vs-symlink.sh b/tests/cp/r-vs-symlink.sh
new file mode 100755
index 0000000..64b23dc
--- /dev/null
+++ b/tests/cp/r-vs-symlink.sh
@@ -0,0 +1,41 @@
+#!/bin/sh
+# cp -r should not create symlinks. Fixed in fileutils-4.1.5.
+
+# Copyright (C) 2001-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+# Restored old behavior (whereby cp -r preserves symlinks) in 4.1.6,
+# though now such usage evokes a warning:
+# cp: 'slink': WARNING: using -r to copy symbolic links is not portable
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ cp
+
+echo abc > foo || framework_failure_
+ln -s foo slink || framework_failure_
+ln -s no-such-file no-file || framework_failure_
+
+
+# This would fail in 4.1.5, not in 4.1.6.
+cp -r no-file junk 2>/dev/null || fail=1
+
+cp -r slink bar 2>/dev/null || fail=1
+set x $(ls -l bar); shift; mode=$1
+case $mode in
+ l*) ;;
+ *) fail=1;;
+esac
+
+Exit $fail
diff --git a/tests/cp/reflink-auto.sh b/tests/cp/reflink-auto.sh
new file mode 100755
index 0000000..dcf6e23
--- /dev/null
+++ b/tests/cp/reflink-auto.sh
@@ -0,0 +1,45 @@
+#!/bin/sh
+# Test cp --reflink=auto
+
+# Copyright (C) 2009-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ cp
+
+cleanup_() { rm -rf "$other_partition_tmpdir"; }
+. "$abs_srcdir/tests/other-fs-tmpdir"
+a_other="$other_partition_tmpdir/a"
+rm -f "$a_other" || framework_failure_
+
+echo non_zero_size > "$a_other" || framework_failure_
+
+# we shouldn't be able to reflink() files on separate partitions
+returns_ 1 cp --reflink "$a_other" b || fail=1
+
+# --reflink=auto should fall back to a normal copy
+cp --reflink=auto "$a_other" b || fail=1
+test -s b || fail=1
+
+# --reflink=auto should allow --sparse for fallback copies.
+# This command can be used to create minimal sized copies.
+cp --reflink=auto --sparse=always "$a_other" b || fail=1
+test -s b || fail=1
+
+# --reflink=auto should be overridden by --reflink=never
+cp --reflink=auto --reflink=never "$a_other" b || fail=1
+test -s b || fail=1
+
+Exit $fail
diff --git a/tests/cp/reflink-perm.sh b/tests/cp/reflink-perm.sh
new file mode 100755
index 0000000..480076f
--- /dev/null
+++ b/tests/cp/reflink-perm.sh
@@ -0,0 +1,45 @@
+#!/bin/sh
+# Test cp --reflink copies permissions
+
+# Copyright (C) 2009-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ cp
+
+
+> time_check
+> file
+ts='2009-08-28 19:00'
+touch -d "$ts" file || framework_failure_
+test time_check -nt file || skip_ "The system clock is wrong"
+
+chmod a=rwx file || framework_failure_
+umask 077
+cp --reflink=auto --preserve file copy || fail=1
+
+mode=$(stat --printf "%A" copy)
+test "$mode" = "-rwxrwxrwx" || fail=1
+
+test copy -nt file && fail=1
+
+# Ensure that --attributes-only overrides --reflink completely
+echo > file2 # file with data
+cp --reflink=auto --preserve --attributes-only file2 empty_copy || fail=1
+compare /dev/null empty_copy || fail=1
+cp --reflink=always --preserve --attributes-only file2 empty_copy || fail=1
+compare /dev/null empty_copy || fail=1
+
+Exit $fail
diff --git a/tests/cp/same-file.sh b/tests/cp/same-file.sh
new file mode 100755
index 0000000..03f66ba
--- /dev/null
+++ b/tests/cp/same-file.sh
@@ -0,0 +1,255 @@
+#!/bin/sh
+# Test some of cp's options and how cp handles situations in
+# which a naive implementation might overwrite the source file.
+
+# Copyright (C) 1998-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ cp
+
+# Unset CDPATH. Otherwise, output from the 'cd dir' command
+# can make this test fail.
+(unset CDPATH) >/dev/null 2>&1 && unset CDPATH
+
+VERSION_CONTROL=numbered; export VERSION_CONTROL
+
+# Determine whether a hard link to a symlink points to the symlink
+# itself or to its referent. For example, the link from FreeBSD6.1
+# does dereference a symlink, but the one from Linux does not.
+ln -s no-such dangling-slink
+ln dangling-slink hard-link > /dev/null 2>&1 \
+ && hard_link_to_symlink_does_the_deref=no \
+ || hard_link_to_symlink_does_the_deref=yes
+rm -f no-such dangling-slink hard-link
+
+test $hard_link_to_symlink_does_the_deref = yes \
+ && remove_these_sed='/^0 -[bf]*l .*sl1 ->/d; /hlsl/d' \
+ || remove_these_sed='/^ELIDE NO TEST OUTPUT/d'
+
+exec 3>&1 1> actual
+
+# FIXME: This should be bigger: like more than 8k
+contents=XYZ
+
+for args in 'foo symlink' 'symlink foo' 'foo foo' 'sl1 sl2' \
+ 'foo hardlink' 'hlsl sl2'; do
+ for options in '' -d -f -df --rem -b -bd -bf -bdf \
+ -l -dl -fl -dfl -bl -bdl -bfl -bdfl -s -sf; do
+ case $args$options in
+ # These tests are not portable.
+ # They all involve making a hard link to a symbolic link.
+ # In the past, we've skipped the tests that are not portable,
+ # by doing "continue" here and eliminating the corresponding
+ # expected output lines below. Don't do that anymore.
+ 'symlink foo'-dfl)
+ continue;;
+ 'symlink foo'-bdl)
+ continue;;
+ 'symlink foo'-bdfl)
+ continue;;
+ 'sl1 sl2'-dfl)
+ continue;;
+ 'sl1 sl2'-bd*l)
+ continue;;
+ 'sl1 sl2'-dl)
+ continue;;
+ esac
+
+ # cont'd Instead, skip them only on systems for which link does
+ # dereference a symlink. Detect and skip such tests here.
+ case $hard_link_to_symlink_does_the_deref:$args:$options in
+ 'yes:sl1 sl2:-fl')
+ continue ;;
+ 'yes:sl1 sl2:-bl')
+ continue ;;
+ 'yes:sl1 sl2:-bfl')
+ continue ;;
+ yes:hlsl*)
+ continue ;;
+ esac
+
+ rm -rf dir
+ mkdir dir
+ cd dir
+ echo $contents > foo
+ case "$args" in *symlink*) ln -s foo symlink ;; esac
+ case "$args" in *hardlink*) ln foo hardlink ;; esac
+ case "$args" in *sl1*) ln -s foo sl1;; esac
+ case "$args" in *sl2*) ln -s foo sl2;; esac
+ case "$args" in *hlsl*) ln sl2 hlsl;; esac
+ (
+ (
+ # echo 1>&2 cp $options $args
+ cp $options $args 2>_err
+ echo $? $options
+
+ # Normalize the program name and diagnostics in the error output,
+ # and put brackets around the output.
+ if test -s _err; then
+ sed '
+ s/symbolic link/symlink/
+ s/^[^:]*:\([^:]*\).*/cp:\1/
+ 1s/^/[/
+ $s/$/]/
+ ' _err
+ fi
+ # Strip off all but the file names.
+ ls=$(ls -gG --ignore=_err . \
+ | sed \
+ -e '/^total /d' \
+ -e 's/^[^ ]* *[^ ]* *[^ ]* *[^ ]* *[^ ]* *[^ ]* *//')
+ echo "($ls)"
+ # Make sure the original is unchanged and that
+ # the destination is a copy.
+ for f in $args; do
+ if test -f $f; then
+ case "$(cat $f)" in
+ "$contents") ;;
+ *) echo cp FAILED;;
+ esac
+ else
+ echo symlink-loop
+ fi
+ done
+ ) | tr '\n' ' '
+ echo
+ ) | sed 's/ *$//'
+ cd ..
+ done
+ echo
+done
+
+cat <<\EOF | sed "$remove_these_sed" > expected
+1 [cp: 'foo' and 'symlink' are the same file] (foo symlink -> foo)
+1 -d [cp: 'foo' and 'symlink' are the same file] (foo symlink -> foo)
+1 -f [cp: 'foo' and 'symlink' are the same file] (foo symlink -> foo)
+1 -df [cp: 'foo' and 'symlink' are the same file] (foo symlink -> foo)
+0 --rem (foo symlink)
+0 -b (foo symlink symlink.~1~ -> foo)
+0 -bd (foo symlink symlink.~1~ -> foo)
+0 -bf (foo symlink symlink.~1~ -> foo)
+0 -bdf (foo symlink symlink.~1~ -> foo)
+1 -l [cp: cannot create hard link 'symlink' to 'foo'] (foo symlink -> foo)
+1 -dl [cp: cannot create hard link 'symlink' to 'foo'] (foo symlink -> foo)
+0 -fl (foo symlink)
+0 -dfl (foo symlink)
+0 -bl (foo symlink symlink.~1~ -> foo)
+0 -bdl (foo symlink symlink.~1~ -> foo)
+0 -bfl (foo symlink symlink.~1~ -> foo)
+0 -bdfl (foo symlink symlink.~1~ -> foo)
+1 -s [cp: cannot create symlink 'symlink' to 'foo'] (foo symlink -> foo)
+0 -sf (foo symlink -> foo)
+
+1 [cp: 'symlink' and 'foo' are the same file] (foo symlink -> foo)
+1 -d [cp: 'symlink' and 'foo' are the same file] (foo symlink -> foo)
+1 -f [cp: 'symlink' and 'foo' are the same file] (foo symlink -> foo)
+1 -df [cp: 'symlink' and 'foo' are the same file] (foo symlink -> foo)
+1 --rem [cp: 'symlink' and 'foo' are the same file] (foo symlink -> foo)
+1 -b [cp: 'symlink' and 'foo' are the same file] (foo symlink -> foo)
+0 -bd (foo -> foo foo.~1~ symlink -> foo) symlink-loop symlink-loop
+1 -bf [cp: 'symlink' and 'foo' are the same file] (foo symlink -> foo)
+0 -bdf (foo -> foo foo.~1~ symlink -> foo) symlink-loop symlink-loop
+0 -l (foo symlink -> foo)
+0 -dl (foo symlink -> foo)
+0 -fl (foo symlink -> foo)
+0 -bl (foo symlink -> foo)
+0 -bfl (foo symlink -> foo)
+1 -s [cp: 'symlink' and 'foo' are the same file] (foo symlink -> foo)
+1 -sf [cp: 'symlink' and 'foo' are the same file] (foo symlink -> foo)
+
+1 [cp: 'foo' and 'foo' are the same file] (foo)
+1 -d [cp: 'foo' and 'foo' are the same file] (foo)
+1 -f [cp: 'foo' and 'foo' are the same file] (foo)
+1 -df [cp: 'foo' and 'foo' are the same file] (foo)
+1 --rem [cp: 'foo' and 'foo' are the same file] (foo)
+1 -b [cp: 'foo' and 'foo' are the same file] (foo)
+1 -bd [cp: 'foo' and 'foo' are the same file] (foo)
+0 -bf (foo foo.~1~)
+0 -bdf (foo foo.~1~)
+0 -l (foo)
+0 -dl (foo)
+0 -fl (foo)
+0 -dfl (foo)
+0 -bl (foo)
+0 -bdl (foo)
+0 -bfl (foo foo.~1~)
+0 -bdfl (foo foo.~1~)
+1 -s [cp: 'foo' and 'foo' are the same file] (foo)
+1 -sf [cp: 'foo' and 'foo' are the same file] (foo)
+
+1 [cp: 'sl1' and 'sl2' are the same file] (foo sl1 -> foo sl2 -> foo)
+0 -d (foo sl1 -> foo sl2 -> foo)
+1 -f [cp: 'sl1' and 'sl2' are the same file] (foo sl1 -> foo sl2 -> foo)
+0 -df (foo sl1 -> foo sl2 -> foo)
+0 --rem (foo sl1 -> foo sl2)
+0 -b (foo sl1 -> foo sl2 sl2.~1~ -> foo)
+0 -bd (foo sl1 -> foo sl2 -> foo sl2.~1~ -> foo)
+0 -bf (foo sl1 -> foo sl2 sl2.~1~ -> foo)
+0 -bdf (foo sl1 -> foo sl2 -> foo sl2.~1~ -> foo)
+1 -l [cp: cannot create hard link 'sl2' to 'sl1'] (foo sl1 -> foo sl2 -> foo)
+0 -fl (foo sl1 -> foo sl2)
+0 -bl (foo sl1 -> foo sl2 sl2.~1~ -> foo)
+0 -bfl (foo sl1 -> foo sl2 sl2.~1~ -> foo)
+1 -s [cp: cannot create symlink 'sl2' to 'sl1'] (foo sl1 -> foo sl2 -> foo)
+0 -sf (foo sl1 -> foo sl2 -> sl1)
+
+1 [cp: 'foo' and 'hardlink' are the same file] (foo hardlink)
+1 -d [cp: 'foo' and 'hardlink' are the same file] (foo hardlink)
+1 -f [cp: 'foo' and 'hardlink' are the same file] (foo hardlink)
+1 -df [cp: 'foo' and 'hardlink' are the same file] (foo hardlink)
+0 --rem (foo hardlink)
+0 -b (foo hardlink hardlink.~1~)
+0 -bd (foo hardlink hardlink.~1~)
+0 -bf (foo hardlink hardlink.~1~)
+0 -bdf (foo hardlink hardlink.~1~)
+0 -l (foo hardlink)
+0 -dl (foo hardlink)
+0 -fl (foo hardlink)
+0 -dfl (foo hardlink)
+0 -bl (foo hardlink)
+0 -bdl (foo hardlink)
+0 -bfl (foo hardlink)
+0 -bdfl (foo hardlink)
+1 -s [cp: 'foo' and 'hardlink' are the same file] (foo hardlink)
+1 -sf [cp: 'foo' and 'hardlink' are the same file] (foo hardlink)
+
+1 [cp: 'hlsl' and 'sl2' are the same file] (foo hlsl -> foo sl2 -> foo)
+0 -d (foo hlsl -> foo sl2 -> foo)
+1 -f [cp: 'hlsl' and 'sl2' are the same file] (foo hlsl -> foo sl2 -> foo)
+0 -df (foo hlsl -> foo sl2 -> foo)
+0 --rem (foo hlsl -> foo sl2)
+0 -b (foo hlsl -> foo sl2 sl2.~1~ -> foo)
+0 -bd (foo hlsl -> foo sl2 -> foo sl2.~1~ -> foo)
+0 -bf (foo hlsl -> foo sl2 sl2.~1~ -> foo)
+0 -bdf (foo hlsl -> foo sl2 -> foo sl2.~1~ -> foo)
+1 -l [cp: cannot create hard link 'sl2' to 'hlsl'] (foo hlsl -> foo sl2 -> foo)
+0 -dl (foo hlsl -> foo sl2 -> foo)
+0 -fl (foo hlsl -> foo sl2)
+0 -dfl (foo hlsl -> foo sl2 -> foo)
+0 -bl (foo hlsl -> foo sl2 sl2.~1~ -> foo)
+0 -bdl (foo hlsl -> foo sl2 -> foo)
+0 -bfl (foo hlsl -> foo sl2 sl2.~1~ -> foo)
+0 -bdfl (foo hlsl -> foo sl2 -> foo)
+1 -s [cp: cannot create symlink 'sl2' to 'hlsl'] (foo hlsl -> foo sl2 -> foo)
+0 -sf (foo hlsl -> foo sl2 -> hlsl)
+
+EOF
+
+exec 1>&3 3>&-
+
+compare expected actual 1>&2 || fail=1
+
+Exit $fail
diff --git a/tests/cp/slink-2-slink.sh b/tests/cp/slink-2-slink.sh
new file mode 100755
index 0000000..00e3fee
--- /dev/null
+++ b/tests/cp/slink-2-slink.sh
@@ -0,0 +1,32 @@
+#!/bin/sh
+# 'test cp --update A B' where A and B are both symlinks that point
+# to the same file
+
+# Copyright (C) 2000-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ cp
+
+touch file || framework_failure_
+ln -s file a || framework_failure_
+ln -s file b || framework_failure_
+ln -s no-such-file c || framework_failure_
+ln -s no-such-file d || framework_failure_
+
+cp --update --no-dereference a b || fail=1
+cp --update --no-dereference c d || fail=1
+
+Exit $fail
diff --git a/tests/cp/sparse-2.sh b/tests/cp/sparse-2.sh
new file mode 100755
index 0000000..5d3c5ec
--- /dev/null
+++ b/tests/cp/sparse-2.sh
@@ -0,0 +1,56 @@
+#!/bin/sh
+# Exercise a few more corners of the copying code.
+
+# Copyright (C) 2011-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ cp dd
+
+touch sparse_chk
+seek_data_capable_ sparse_chk \
+ || skip_ "insufficient SEEK_DATA support"
+
+# Exercise the code that handles a file ending in a hole.
+printf x > k || framework_failure_
+dd bs=1k seek=128 of=k < /dev/null || framework_failure_
+
+# The first time through the outer loop, the input file, K, ends with a hole.
+# The second time through, we append a byte so that it does not.
+for append in no yes; do
+ test $append = yes && printf y >> k
+ for i in always never; do
+ cp --reflink=never --sparse=$i k k2 || fail=1
+ cmp k k2 || fail=1
+ done
+done
+
+# Ensure that --sparse=always can restore holes.
+rm -f k
+# Create a file starting with an "x", followed by 256K-1 0 bytes.
+printf x > k || framework_failure_
+dd bs=1k seek=1 of=k count=255 < /dev/zero || framework_failure_
+
+# cp should detect the all-zero blocks and convert some of them to holes.
+cp --debug --reflink=never --sparse=always k k2 >cp.out || fail=1
+cmp k k2 || fail=1
+grep 'sparse detection: .*zeros' cp.out || { cat cp.out; fail=1; }
+
+# cp should disable reflink AND copy offload with --sparse=never
+cp --debug --sparse=never k k2 >cp.out || fail=1
+cmp k k2 || fail=1
+grep 'copy offload: avoided, reflink: no' cp.out || { cat cp.out; fail=1; }
+
+Exit $fail
diff --git a/tests/cp/sparse-extents-2.sh b/tests/cp/sparse-extents-2.sh
new file mode 100755
index 0000000..575dbbf
--- /dev/null
+++ b/tests/cp/sparse-extents-2.sh
@@ -0,0 +1,116 @@
+#!/bin/sh
+# Test cp --sparse=always through SEEK_DATA copy
+
+# Copyright (C) 2010-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ cp
+require_perl_
+
+# The test was seen to fail on ext3 so exclude that type
+# (or any file system where the type can't be determined)
+touch sparse_chk
+if seek_data_capable_ sparse_chk && ! df -t ext3 . >/dev/null; then
+ : # Current partition has working extents. Good!
+else
+ skip_ "insufficient SEEK_DATA support"
+
+ # It's not; we need to create one, hence we need root access.
+ require_root_
+
+ cwd=$PWD
+ cleanup_() { cd /; umount "$cwd/mnt"; }
+
+ skip=0
+ # Create an ext4 loopback file system
+ dd if=/dev/zero of=blob bs=32k count=1000 || skip=1
+ mkdir mnt
+ mkfs -t ext4 -F blob ||
+ skip_ "failed to create ext4 file system"
+ mount -oloop blob mnt || skip=1
+ cd mnt || skip=1
+ echo test > f || skip=1
+ test -s f || skip=1
+
+ test $skip = 1 &&
+ skip_ "insufficient mount/ext4 support"
+fi
+
+# =================================================
+# The data below was set up to ensure that the original FIEMAP-copying code
+# was exercised enough to provoke at least two iterations of the do...while loop
+# in which it calls ioctl (fd, FS_IOC_FIEMAP,...
+# This also verifies that non-trivial extents are preserved.
+
+# Extract logical block number and length pairs from filefrag -v output.
+# The initial sed is to remove the "eof" from the normally-empty "flags" field.
+# Similarly, remove flags values like "unknown,delalloc,eof".
+# That is required when that final extent has no number in the "expected" field.
+f()
+{
+ sed 's/ [a-z,][a-z,]*$//' $@ \
+ | $AWK '/^ *[0-9]/ {printf "%d %d ", $2, (NF>=6 ? $6 : (NF<5 ? $NF : $5)) }
+ END {print ""}'
+}
+
+for i in $(seq 1 2 21); do
+ for j in 1 2 31 100; do
+ $PERL -e '$n = '$i' * 1024; *F = *STDOUT;' \
+ -e 'for (1..'$j') { sysseek (*F, $n, 1)' \
+ -e '&& syswrite (*F, chr($_)x$n) or die "$!"}' > j1 || fail=1
+
+ # Note there is an implicit sync performed by cp on Linux kernels
+ # before 2.6.39 to work around bugs in EXT4 and BTRFS.
+ # (this was removed in the release after coreutils-8.32).
+ # Note also the -s parameter to the filefrag commands below
+ # for the same reasons.
+ cp --reflink=never --sparse=always j1 j2 || fail=1
+
+ cmp j1 j2 || fail_ "data loss i=$i j=$j"
+ if ! filefrag -vs j1 | grep -F extent >/dev/null; then
+ test $skip != 1 && warn_ 'skipping part; you lack filefrag'
+ skip=1
+ else
+ # Here is sample filefrag output:
+ # $ perl -e 'BEGIN{$n=16*1024; *F=*STDOUT}' \
+ # -e 'for (1..5) { sysseek(*F,$n,1)' \
+ # -e '&& syswrite *F,"."x$n or die "$!"}' > j
+ # $ filefrag -v j
+ # File system type is: ef53
+ # File size of j is 163840 (40 blocks, blocksize 4096)
+ # ext logical physical expected length flags
+ # 0 4 6258884 4
+ # 1 12 6258892 6258887 4
+ # 2 20 6258900 6258895 4
+ # 3 28 6258908 6258903 4
+ # 4 36 6258916 6258911 4 eof
+ # j: 6 extents found
+
+ # exclude the physical block numbers; they always differ
+ filefrag -v j1 > ff1 || framework_failure_
+ filefrag -vs j2 > ff2 || framework_failure_
+ { f ff1; f ff2; } | $PERL $abs_srcdir/tests/filefrag-extent-compare \
+ || {
+ warn_ ignoring filefrag-reported extent map differences
+ # Show the differing extent maps.
+ head -n99 ff1 ff2
+ }
+ fi
+ test $fail = 1 && break 2
+ done
+done
+
+Exit $fail
diff --git a/tests/cp/sparse-extents.sh b/tests/cp/sparse-extents.sh
new file mode 100755
index 0000000..5009f09
--- /dev/null
+++ b/tests/cp/sparse-extents.sh
@@ -0,0 +1,83 @@
+#!/bin/sh
+# Test cp handles extents correctly
+
+# Copyright (C) 2011-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ cp
+
+require_sparse_support_
+
+touch sparse_chk || framework_failure_
+seek_data_capable_ sparse_chk ||
+ skip_ 'insufficient SEEK_DATA support'
+
+fallocate --help >/dev/null || skip_ 'The fallocate utility is required'
+touch falloc.test || framework_failure_
+fallocate -l 1 -o 1 -n falloc.test ||
+ skip_ 'this file system lacks FALLOCATE support'
+rm falloc.test
+
+# We don't currently handle unwritten extents specially
+if false; then
+# Require more space than we'll actually use, so that
+# tests run in parallel do not run out of space.
+# Otherwise, with inadequate space, simply running the following
+# fallocate command would induce a temporary file-system-full condition,
+# which would cause failure of unrelated tests run in parallel.
+require_file_system_bytes_free_ 800000000
+
+fallocate -l 1MiB num.test ||
+ skip_ "this fallocate doesn't support numbers with IEX suffixes"
+
+fallocate -l 600MiB space.test ||
+ skip_ 'this test needs at least 600MiB free space'
+
+# Disable this test on old BTRFS (e.g. Fedora 14)
+# which reports ordinary extents for unwritten ones.
+filefrag space.test || skip_ 'the 'filefrag' utility is missing'
+filefrag -v space.test | grep -F 'unwritten' > /dev/null ||
+ skip_ 'this file system does not report empty extents as "unwritten"'
+
+rm space.test
+
+# Ensure we read a large empty file quickly
+fallocate -l 300MiB empty.big || framework_failure_
+timeout 3 cp --reflink=never --sparse=always empty.big cp.test || fail=1
+test $(stat -c %s empty.big) = $(stat -c %s cp.test) || fail=1
+rm empty.big cp.test
+fi
+
+# Ensure we handle extents beyond file size correctly.
+# Note until we support fallocate, we will not maintain
+# the file allocation. FIXME: amend this test if fallocate is supported.
+# Note currently this only uses SEEK_DATA logic when the allocation (-l)
+# is smaller than the size, thus identifying the file as sparse.
+# Note the '-l 1' case is an effective noop, and just checks
+# a file with a trailing hole is copied correctly.
+for sparse_arg in always auto never; do
+ for alloc in '-l 4194304' '-l 1048576 -o 4194304' '-l 1'; do
+ dd count=10 if=/dev/urandom iflag=fullblock of=unwritten.withdata
+ truncate -s 2MiB unwritten.withdata || framework_failure_
+ fallocate $alloc -n unwritten.withdata || framework_failure_
+ cp --reflink=never --sparse=$sparse_arg unwritten.withdata cp.test || fail=1
+ test $(stat -c %s unwritten.withdata) = $(stat -c %s cp.test) || fail=1
+ cmp unwritten.withdata cp.test || fail=1
+ rm unwritten.withdata cp.test || framework_failure_
+ done
+done
+
+Exit $fail
diff --git a/tests/cp/sparse-perf.sh b/tests/cp/sparse-perf.sh
new file mode 100755
index 0000000..793ecee
--- /dev/null
+++ b/tests/cp/sparse-perf.sh
@@ -0,0 +1,40 @@
+#!/bin/sh
+# ensure that a sparse file is copied efficiently, by default
+
+# Copyright (C) 2021-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ cp
+
+# Create a large-but-sparse file.
+timeout 10 truncate -s1T f ||
+ skip_ "unable to create a 1 TiB sparse file"
+
+# Note zfs with zfs_dmu_offset_next_sync=0 (the default)
+# will generally skip here, due to needing about 5 seconds
+# between the creation of the file and the use of SEEK_DATA,
+# for it to determine it's an empty file (return ENXIO).
+seek_data_capable_ f ||
+ skip_ "insufficient SEEK_DATA support"
+
+# Nothing can read that many bytes in so little time.
+timeout 10 cp --reflink=never f f2 || fail=1
+
+# Ensure that the sparse file copied through SEEK_DATA has the same size
+# in bytes as the original.
+test "$(stat --printf %s f)" = "$(stat --printf %s f2)" || fail=1
+
+Exit $fail
diff --git a/tests/cp/sparse-to-pipe.sh b/tests/cp/sparse-to-pipe.sh
new file mode 100755
index 0000000..a33a7b3
--- /dev/null
+++ b/tests/cp/sparse-to-pipe.sh
@@ -0,0 +1,38 @@
+#!/bin/sh
+# copy a sparse file to a pipe, to exercise some seldom-used parts of copy.c
+
+# Copyright (C) 2011-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ cp
+
+require_sparse_support_
+
+# Terminate any background cp process
+cleanup_() { kill $pid 2>/dev/null && wait $pid; }
+
+mkfifo_or_skip_ pipe
+timeout 10 cat pipe > copy & pid=$!
+
+truncate -s1M sparse || framework_failure_
+timeout 10 cp sparse pipe || fail=1
+
+# Ensure that the cat has completed before comparing.
+wait $pid
+
+cmp sparse copy || fail=1
+
+Exit $fail
diff --git a/tests/cp/sparse.sh b/tests/cp/sparse.sh
new file mode 100755
index 0000000..12a4380
--- /dev/null
+++ b/tests/cp/sparse.sh
@@ -0,0 +1,77 @@
+#!/bin/sh
+# Test cp --sparse=always
+
+# Copyright (C) 2006-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ cp
+require_sparse_support_
+
+# Create a sparse file.
+# It has to be at least 128K in order to be sparse on some systems.
+# Make its size one larger than 128K, in order to tickle the
+# bug in coreutils-6.0.
+size=$(expr 128 \* 1024 + 1)
+dd bs=1 seek=$size of=sparse < /dev/null 2> /dev/null || framework_failure_
+
+# Avoid reflinking. We want to test hole navigation here.
+cp_no_reflink() {
+ cp --reflink=never "$@"
+}
+
+cp_no_reflink --sparse=always sparse copy || fail=1
+
+# Ensure that the copy has the same block count as the original.
+test $(stat --printf %b copy) -le $(stat --printf %b sparse) || fail=1
+
+# Ensure that --sparse={always,never} with --reflink fail.
+returns_ 1 cp --sparse=always --reflink sparse copy || fail=1
+returns_ 1 cp --sparse=never --reflink sparse copy || fail=1
+
+
+# Ensure we handle sparse/non-sparse transitions correctly
+maxn=128 # how many $hole_size chunks per file
+hole_size=$(stat -c %o copy)
+dd if=/dev/zero bs=$hole_size count=$maxn of=zeros || framework_failure_
+tr '\0' 'U' < zeros > nonzero || framework_failure_
+
+for pattern in 1 0; do
+ test "$pattern" = 1 && pattern="$(printf '%s\n%s' nonzero zeros)"
+ test "$pattern" = 0 && pattern="$(printf '%s\n%s' zeros nonzero)"
+
+ for n in 1 2 4 11 32 $maxn; do
+ parts=$(expr $maxn / $n)
+
+ rm -f file.in
+
+ # Generate non sparse file for copying with alternating
+ # hole/data patterns of size n * $hole_size
+ for i in $(yes "$pattern" | head -n$parts); do
+ dd iflag=fullblock if=$i of=file.in conv=notrunc oflag=append \
+ bs=$hole_size count=$n status=none || framework_failure_
+ done
+
+ cp_no_reflink --sparse=always file.in sparse.out || fail=1 # non sparse in
+ cp_no_reflink --sparse=always sparse.out sparse.out2 || fail=1 # sparse in
+
+ cmp file.in sparse.out || fail=1
+ cmp file.in sparse.out2 || fail=1
+
+ ls -lsh file.in sparse.*
+ done
+done
+
+Exit $fail
diff --git a/tests/cp/special-bits.sh b/tests/cp/special-bits.sh
new file mode 100755
index 0000000..a9288f5
--- /dev/null
+++ b/tests/cp/special-bits.sh
@@ -0,0 +1,51 @@
+#!/bin/sh
+# make sure 'cp -p' preserves special bits
+# This works only when run as root.
+
+# Copyright (C) 2000-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+# This test would fail due to a bug introduced in 4.0y.
+# The bug was fixed in 4.0z.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ cp
+require_root_
+
+touch a b c || framework_failure_
+chmod u+sx,go= a || framework_failure_
+chmod u=rwx,g=sx,o= b || framework_failure_
+chmod a=r,ug+sx c || framework_failure_
+chown $NON_ROOT_USERNAME . || framework_failure_
+chmod u=rwx,g=rx,o=rx . || framework_failure_
+
+
+cp -p a a2 || fail=1
+set _ $(ls -l a); shift; p1=$1
+set _ $(ls -l a2); shift; p2=$1
+test $p1 = $p2 || fail=1
+
+cp -p b b2 || fail=1
+set _ $(ls -l b); shift; p1=$1
+set _ $(ls -l b2); shift; p2=$1
+test $p1 = $p2 || fail=1
+
+chroot --skip-chdir --user=$NON_ROOT_USERNAME / env PATH="$PATH" cp -p c c2 \
+ || fail=1
+set _ $(ls -l c); shift; p1=$1
+set _ $(ls -l c2); shift; p2=$1
+test $p1 = $p2 && fail=1
+
+Exit $fail
diff --git a/tests/cp/special-f.sh b/tests/cp/special-f.sh
new file mode 100755
index 0000000..ed70d7a
--- /dev/null
+++ b/tests/cp/special-f.sh
@@ -0,0 +1,33 @@
+#!/bin/sh
+# Ensure that "cp -Rf fifo E" unlinks E and retries.
+# Up until coreutils-6.10.171, it would not.
+
+# Copyright (C) 2008-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ cp
+
+mkfifo_or_skip_ fifo
+
+touch e || framework-failure
+
+for force in '' '-f'; do
+ # Second time through will need to unlink fifo e
+ timeout 10 cp -R $force fifo e || fail=1
+ test -p fifo || fail=1
+done
+
+Exit $fail
diff --git a/tests/cp/src-base-dot.sh b/tests/cp/src-base-dot.sh
new file mode 100755
index 0000000..70f8921
--- /dev/null
+++ b/tests/cp/src-base-dot.sh
@@ -0,0 +1,28 @@
+#!/bin/sh
+# Ensure that "mkdir x y; cd y; cp -ab ../x/. ." is a successful, silent, no-op.
+
+# Copyright (C) 2006-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ cp
+
+mkdir x y || framework_failure_
+
+cd y
+cp --verbose -ab ../x/. . > out 2>&1 || fail=1
+compare /dev/null out || fail=1
+
+Exit $fail
diff --git a/tests/cp/symlink-slash.sh b/tests/cp/symlink-slash.sh
new file mode 100755
index 0000000..5a8cb4f
--- /dev/null
+++ b/tests/cp/symlink-slash.sh
@@ -0,0 +1,36 @@
+#!/bin/sh
+# Make sure that cp -dR dereferences a symlink arg if its name is
+# written with a trailing slash.
+
+# Copyright (C) 2000-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ cp
+
+mkdir dir || framework_failure_
+ln -s dir symlink || framework_failure_
+
+cp -dR symlink/ s || fail=1
+set $(ls -l s)
+
+# Prior to fileutils-4.0q, the following would have output ...'s -> dir'
+# because the trailing slash was removed unconditionally (now you have to
+# use the new --strip-trailing-slash option) causing cp to reproduce the
+# symlink. Now, the trailing slash is interpreted by the stat library
+# call and so cp ends up dereferencing the symlink and copying the directory.
+test "$*" = 'total 0' && : || fail=1
+
+Exit $fail
diff --git a/tests/cp/thru-dangling.sh b/tests/cp/thru-dangling.sh
new file mode 100755
index 0000000..1cbb12d
--- /dev/null
+++ b/tests/cp/thru-dangling.sh
@@ -0,0 +1,51 @@
+#!/bin/sh
+# Ensure that cp works as documented, when the destination is a dangling symlink
+
+# Copyright (C) 2007-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ cp
+
+ln -s no-such dangle || framework_failure_
+echo hi > f || framework_failure_
+echo hi > exp || framework_failure_
+echo "cp: not writing through dangling symlink 'dangle'" \
+ > exp-err || framework_failure_
+
+
+# Starting with 6.9.90, this usage fails, by default:
+for opt in '' '-f'; do
+ returns_ 1 cp $opt f dangle > err 2>&1 || fail=1
+ compare exp-err err || fail=1
+ test -f no-such && fail=1
+done
+
+
+# But you can set POSIXLY_CORRECT to get the historical behavior.
+env POSIXLY_CORRECT=1 cp f dangle > out 2>&1 || fail=1
+cat no-such >> out || fail=1
+compare exp out || fail=1
+
+
+# Starting with 8.30 we treat ELOOP as existing and so
+# remove the symlink
+ln -s loop loop || framework_failure_
+cp -f f loop > err 2>&1 || fail=1
+compare /dev/null err || fail=1
+compare exp loop || fail=1
+test -f loop || fail=1
+
+Exit $fail
diff --git a/tests/csplit/csplit-1000.sh b/tests/csplit/csplit-1000.sh
new file mode 100755
index 0000000..bc34a24
--- /dev/null
+++ b/tests/csplit/csplit-1000.sh
@@ -0,0 +1,29 @@
+#!/bin/sh
+# cause a 1-byte heap buffer overrun
+
+# Copyright (C) 2010-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ csplit
+
+# Before coreutils-8.7, this would overrun the 6-byte filename_space buffer.
+# It's hard to detect that without using valgrind, so here, we simply
+# run the demonstrator.
+seq 1000 | csplit - '/./' '{*}' || fail=1
+test -f xx1000 || fail=1
+test -f xx1001 && fail=1
+
+Exit $fail
diff --git a/tests/csplit/csplit-heap.sh b/tests/csplit/csplit-heap.sh
new file mode 100755
index 0000000..36b286b
--- /dev/null
+++ b/tests/csplit/csplit-heap.sh
@@ -0,0 +1,32 @@
+#!/bin/sh
+# ensure that csplit uses a bounded amount of memory
+
+# Copyright (C) 2010-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ csplit
+
+# Determine basic amount of memory needed.
+{ echo y; echo n; } > f || framework_failure_
+vm=$(get_min_ulimit_v_ csplit -z f %n%1) \
+ || skip_ "this shell lacks ulimit support"
+
+(
+ ulimit -v $(($vm + 4000)) \
+ && { yes | head -n2500000; echo n; } | csplit -z - %n%1
+) || fail=1
+
+Exit $fail
diff --git a/tests/csplit/csplit-io-err.sh b/tests/csplit/csplit-io-err.sh
new file mode 100755
index 0000000..04c0ce0
--- /dev/null
+++ b/tests/csplit/csplit-io-err.sh
@@ -0,0 +1,92 @@
+#!/bin/sh
+# Ensure we handle i/o errors correctly in csplit
+
+# Copyright (C) 2015-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ csplit
+require_gcc_shared_
+
+if ! test -w /dev/full || ! test -c /dev/full; then
+ skip_ '/dev/full is required'
+fi
+
+# Ensure error messages are in English
+LC_ALL=C
+export LC_ALL
+
+# Replace fwrite and ferror, always returning an error
+cat > k.c <<'EOF' || framework_failure_
+#include <stdio.h>
+#include <errno.h>
+
+#undef fwrite
+#undef fwrite_unlocked
+
+size_t
+fwrite (const void *ptr, size_t size, size_t nitems, FILE *stream)
+{
+ if (stream == stderr)
+ {
+ /* Perform the normal operation of fwrite. */
+ const char *p = ptr;
+ size_t count = size * nitems;
+ size_t i;
+ for (i = 0; i < count; i++)
+ if (putc ((unsigned char) *p++, stream) == EOF)
+ break;
+ return i / size;
+ }
+ else
+ {
+ fclose (fopen ("preloaded","w")); /* marker for preloaded interception */
+ errno = ENOSPC;
+ return 0;
+ }
+}
+
+size_t
+fwrite_unlocked (const void *ptr, size_t size, size_t nitems, FILE *stream)
+{
+ return fwrite (ptr, size, nitems, stream);
+}
+EOF
+
+# Get the wording of the OS-dependent ENOSPC message
+returns_ 1 seq 1 >/dev/full 2>msgt || framework_failure_
+sed 's/seq: write error: //' msgt > msg || framework_failure_
+
+# Create the expected error message
+{ printf "%s" "csplit: write error for 'xx01': " ; cat msg ; } > exp \
+ || framework_failure_
+
+# compile/link the interception shared library:
+gcc_shared_ k.c k.so \
+ || skip_ 'failed to build forced-fwrite-failure shared library'
+
+# Split the input, and force fwrite() failure -
+# the 'csplit' command should fail with exit code 1
+# (checked with 'returns_ 1 ... || fail=1')
+seq 10 |
+(export LD_PRELOAD=$LD_PRELOAD:./k.so
+ returns_ 1 csplit - 1 4 2>out) || fail=1
+
+test -e preloaded || skip_ 'LD_PRELOAD interception failed'
+
+# Ensure we got the expected error message
+compare exp out || fail=1
+
+Exit $fail
diff --git a/tests/csplit/csplit-suppress-matched.pl b/tests/csplit/csplit-suppress-matched.pl
new file mode 100755
index 0000000..80db7fc
--- /dev/null
+++ b/tests/csplit/csplit-suppress-matched.pl
@@ -0,0 +1,218 @@
+#!/usr/bin/perl
+
+# Copyright (C) 2013-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+use strict;
+
+my $limits = getlimits ();
+
+my $prog = 'csplit';
+
+# Turn off localization of executable's output.
+@ENV{qw(LANGUAGE LANG LC_ALL)} = ('C') x 3;
+
+# Input from 'seq 6'
+my $IN_SEQ_6 =<<EOF;
+1
+2
+3
+4
+5
+6
+EOF
+
+# Input from a possible run of 'uniq --group'
+# (groups separated by empty lines)
+my $IN_UNIQ =<<EOF;
+a
+a
+YY
+
+XX
+b
+b
+YY
+
+XX
+c
+YY
+
+XX
+d
+d
+d
+EOF
+
+# Standard Coreutils::run_tests() structure, except the addition of
+# "OUTPUTS" array, containing the expected content of the output files.
+# See code below for conversion into PRE/CMP/POST checks.
+my @csplit_tests =
+(
+ # without --suppress-matched,
+ # the newline (matched line) appears in the output files
+ ["re-base", "-q - '/^\$/' '{*}'", {IN_PIPE => $IN_UNIQ},
+ {OUTPUTS => [ "a\na\nYY\n", "\nXX\nb\nb\nYY\n","\nXX\nc\nYY\n",
+ "\nXX\nd\nd\nd\n" ] }],
+
+ # the newline (matched line) does not appear in the output files
+ ["re-1", " --suppress-matched -q - '/^\$/' '{*}'", {IN_PIPE => $IN_UNIQ},
+ {OUTPUTS => ["a\na\nYY\n", "XX\nb\nb\nYY\n", "XX\nc\nYY\n",
+ "XX\nd\nd\nd\n"]}],
+
+ # the 'XX' (matched line + offset 1) does not appear in the output files.
+ # the newline appears in the files (before each split, at the end of the file)
+ ["re-2", "--suppress-matched -q - '/^\$/1' '{*}'", {IN_PIPE => $IN_UNIQ},
+ {OUTPUTS => ["a\na\nYY\n\n","b\nb\nYY\n\n","c\nYY\n\n","d\nd\nd\n"]}],
+
+ # the 'YY' (matched line + offset of -1) does not appear in the output files
+ # the newline appears in the files (as the first line of the new split)
+ ["re-3", " --suppress-matched -q - '/^\$/-1' '{*}'", {IN_PIPE => $IN_UNIQ},
+ {OUTPUTS => ["a\na\n", "\nXX\nb\nb\n", "\nXX\nc\n", "\nXX\nd\nd\nd\n"]}],
+
+ # the last matched line for a non infinite match repetition is suppressed.
+ # Up to and including coreutils 8.32, the last match was output.
+ ["re-4", " --suppress-matched -q - '/^\$/' '{2}'", {IN_PIPE => $IN_UNIQ},
+ {OUTPUTS => ["a\na\nYY\n", "XX\nb\nb\nYY\n", "XX\nc\nYY\n",
+ "XX\nd\nd\nd\n"]}],
+
+ # Test two consecutive matched lines
+ # without suppress-matched, the second file should contain a single newline.
+ ["re-4.1", "-q - '/^\$/' '{*}'", {IN_PIPE => "a\n\n\nb\n"},
+ {OUTPUTS => [ "a\n", "\n", "\nb\n" ]}],
+ # suppress-matched will cause the second file to be empty.
+ ["re-4.2", "--suppress-match -q - '/^\$/' '{*}'", {IN_PIPE => "a\n\n\nb\n"},
+ {OUTPUTS => [ "a\n", "", "b\n" ]}],
+ # suppress-matched + elide-empty should output just two files.
+ ["re-4.3", "--suppress-match -zq - '/^\$/' '{*}'", {IN_PIPE => "a\n\n\nb\n"},
+ {OUTPUTS => [ "a\n", "b\n" ]}],
+
+
+ # Test a matched-line as the last line
+ # default: last file with newline should be created.
+ ["re-5.1", "-q - '/^\$/' '{*}'", {IN_PIPE => "a\n\nb\n\n"},
+ {OUTPUTS => [ "a\n", "\nb\n", "\n" ]}],
+ # suppress-matched - last empty files should be created.
+ ["re-5.2", "--suppress-match -q - '/^\$/' '{*}'", {IN_PIPE => "a\n\nb\n\n"},
+ {OUTPUTS => [ "a\n", "b\n", "" ]}],
+ # suppress-matched + elide-empty: just two files should be created.
+ ["re-5.3", "--suppress-match -zq - '/^\$/' '{*}'", {IN_PIPE => "a\n\nb\n\n"},
+ {OUTPUTS => [ "a\n", "b\n" ]}],
+
+ # without suppress-matched,
+ # the matched lines (2/4/6) appears in the output files
+ ["int-base", '-q - 2 4 6', {IN_PIPE => $IN_SEQ_6},
+ {OUTPUTS => [ "1\n", "2\n3\n", "4\n5\n", "6\n" ]}],
+ # suppress matched - the matching lines (2/4/6) should not appear.
+ ["int-1", '--suppress-matched -q - 2 4 6', {IN_PIPE => $IN_SEQ_6},
+ {OUTPUTS => [ "1\n", "3\n", "5\n", "" ]}],
+ # suppress matched + elide-empty
+ ["int-2", '--suppress-matched -zq - 2 4 6', {IN_PIPE => $IN_SEQ_6},
+ {OUTPUTS => [ "1\n", "3\n", "5\n" ]}],
+);
+
+
+
+=pod
+The following loop translate the above @Tests to a Coreutils::run_tests()
+compatible structure. It converts "OUTPUTS" key into "CMP" + "POST" keys:
+1. Each element in the OUTPUTS key is expected to be an output file
+ from csplit (named xx00, xx01, xx02...)
+ create a "CMP" key for each one, with the output and the filename.
+2. Add a "POST" key, ensuring no extra files have been created.
+ (e.g. if there are 4 expected outputs, xx00 to xx03,
+ ensure xx04 doesn't exist).
+3. Add a "PRE" key, deleting all existing 'xx*' files.
+
+Example:
+
+Before conversion:
+ my @csplit_tests =
+ (
+ ["1", '-z -q - 2 4 6',
+ {IN_PIPE => "1\n2\n3\n4\n5\n6\n"},
+ {OUTPUTS => [ "1\n", "2\n3\n", "4\n5\n", "6\n" ],
+ ]
+ )
+
+After conversion:
+
+ my @csplit_tests =
+ (
+ ["1", '-z -q - 2 4 6',
+ {IN_PIPE => "1\n2\n3\n4\n5\n6\n"},
+ {PRE => sub { unlink glob './xx??' ; }},
+ {CMP => ["1\n", {'xx00'=> undef}]},
+ {CMP => ["2\n3\n", {'xx01'=> undef}]},
+ {CMP => ["4\n5\n", {'xx02'=> undef}]},
+ {CMP => ["6\n", {'xx03'=> undef}]},
+ {POST => sub { die "extra file" if -e 'xx04'}},
+ ],
+ );
+=cut
+my @Tests;
+foreach my $t (@csplit_tests)
+ {
+ my ($test_name, $cmdline, @others) = @$t;
+ my $new_ent = [$test_name, $cmdline];
+
+ my $out_file_num = 0 ;
+
+ foreach my $e (@others)
+ {
+ die "Internal error: expecting a hash (e.g. IN_PIPE/OUTPUTS/ERR)" .
+ "in test '$test_name', got $e"
+ unless ref $e && (ref $e eq 'HASH');
+
+ my ($key, $value) = each %$e;
+ if ($key eq 'OUTPUTS')
+ {
+ # Convert each expected OUTPUT to a 'CMP' key.
+ foreach my $output (@$value)
+ {
+ my $filename = sprintf("xx%02d",$out_file_num++);
+ my $cmp = {CMP => [ $output, { $filename => undef}]};
+ push @$new_ent, $cmp;
+ }
+
+ # Add a 'POST' check
+ # Ensure no extra files have been created.
+ my $filename = sprintf("xx%02d",$out_file_num++);
+ my $post = { POST => sub { die "Test failed: an extraneous file " .
+ "'$filename' has been created\n"
+ if -e $filename; } } ;
+ push @$new_ent, $post;
+
+ # before running each test, cleanup the 'xx00' files
+ # from previous runs.
+ my $pre = { PRE => sub { unlink glob "./xx??"; } };
+ push @$new_ent, $pre;
+ }
+ else
+ {
+ # pass other entities as-is (e.g. OUT, ERR, OUT_SUBST, EXIT)
+ # run_tests() will know how to handle them.
+ push @$new_ent, $e;
+ }
+ }
+
+ push @Tests, $new_ent;
+ }
+
+my $save_temps = $ENV{DEBUG};
+my $verbose = $ENV{VERBOSE};
+
+my $fail = run_tests ($prog, $prog, \@Tests, $save_temps, $verbose);
+exit $fail;
diff --git a/tests/csplit/csplit.sh b/tests/csplit/csplit.sh
new file mode 100755
index 0000000..a27f61e
--- /dev/null
+++ b/tests/csplit/csplit.sh
@@ -0,0 +1,103 @@
+#!/bin/sh
+# various csplit tests
+
+# Copyright (C) 2001-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ csplit
+
+
+# csplit could get a failed assertion to 2.0.17
+(echo a; echo; echo) > in
+csplit in '/^$/' 2 > out || fail=1
+cat <<EOF > exp
+2
+0
+2
+EOF
+compare exp out || fail=1
+rm -f in out exp
+
+# Ensure that xx02 contains just two newlines.
+# This would fail due to reading from freed buffer with coreutils-5.0.91.
+printf '\n\n' > exp
+cp xx02 out || fail=1
+compare exp out || fail=1
+rm -f in out exp
+
+# csplit would infloop
+(echo; echo a) > in
+csplit in '/a/-1' '{*}' > out || fail=1
+cat <<EOF > exp
+0
+3
+EOF
+compare exp out || fail=1
+rm -f in out exp
+
+# 'echo |csplit - 1 1' used to abort.
+echo > in
+csplit in 1 1 > out 2> err || fail=1
+cat <<EOF > exp
+0
+0
+1
+EOF
+compare exp out || fail=1
+cat <<\EOF > experr
+csplit: warning: line number '1' is the same as preceding line number
+EOF
+compare experr err || fail=1
+rm -f in out exp err experr
+
+# 'echo | csplit -b '%0#6.3x' - 1' incorrectly warned about the format
+# up through coreutils 8.6.
+echo > in
+csplit -b '%0#6.3x' in 1 > out 2> err || fail=1
+cat <<EOF > exp
+0
+1
+EOF
+compare exp out || fail=1
+touch experr
+compare experr err || fail=1
+compare 'xx 000' experr || fail=1
+compare 'xx 0x001' in || fail=1
+rm -f in out exp err experr xx*
+
+# make sure 'csplit FILE 0' fails.
+echo > in
+csplit in 0 > out 2> err && fail=1
+csplit in 2 1 > out 2>> err && fail=1
+csplit in 3 3 > out 2>> err && fail=1
+cat <<\EOF > experr
+csplit: 0: line number must be greater than zero
+csplit: line number '1' is smaller than preceding line number, 2
+csplit: warning: line number '3' is the same as preceding line number
+csplit: '3': line number out of range
+EOF
+compare experr err || fail=1
+
+# Ensure that lines longer than the initial buffer length don't cause
+# trouble (e.g. reading from freed memory, resulting in corrupt output).
+# This test failed at least in coreutils-5.2.1 and 5.3.0, and was fixed
+# in 5.3.1.
+rm -f in out exp err experr xx??
+printf 'x%8199s\nx\n%8199s\nx\n' x x > in
+csplit in '/x\{1\}/' '{*}' > /dev/null || fail=1
+cat xx?? | compare - in || fail=1
+
+Exit $fail
diff --git a/tests/cut/cut-huge-range.sh b/tests/cut/cut-huge-range.sh
new file mode 100755
index 0000000..453108c
--- /dev/null
+++ b/tests/cut/cut-huge-range.sh
@@ -0,0 +1,47 @@
+#!/bin/sh
+# Ensure that cut does not allocate mem for large ranges
+
+# Copyright (C) 2012-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ cut
+getlimits_
+
+vm=$(get_min_ulimit_v_ returns_ 0 cut -b1 /dev/null) \
+ || skip_ "this shell lacks ulimit support"
+
+# Ensure we can cut up to our sentinel value.
+# Don't use expr to subtract one,
+# since UINTMAX_MAX may exceed its maximum value.
+CUT_MAX=$(expr $UINTMAX_MAX - 1) || framework_failure_
+
+# From coreutils-8.10 through 8.20, this would make cut try to allocate
+# a 256MiB bit vector.
+(ulimit -v $vm && cut -b$CUT_MAX- /dev/null > err 2>&1) || fail=1
+
+# Up to and including coreutils-8.21, cut would allocate possibly needed
+# memory upfront. Subsequently extra memory is no longer needed.
+(ulimit -v $vm && cut -b1-$CUT_MAX /dev/null >> err 2>&1) || fail=1
+
+# Explicitly disallow values above CUT_MAX
+(ulimit -v $vm && returns_ 1 cut -b$UINTMAX_MAX /dev/null 2>/dev/null) ||
+ fail=1
+(ulimit -v $vm && returns_ 1 cut -b$UINTMAX_OFLOW /dev/null 2>/dev/null) ||
+ fail=1
+
+compare /dev/null err || fail=1
+
+Exit $fail
diff --git a/tests/cut/cut.pl b/tests/cut/cut.pl
new file mode 100755
index 0000000..2e01907
--- /dev/null
+++ b/tests/cut/cut.pl
@@ -0,0 +1,255 @@
+#!/usr/bin/perl
+# Test "cut".
+
+# Copyright (C) 2006-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+use strict;
+
+(my $ME = $0) =~ s|.*/||;
+
+# Turn off localization of executable's output.
+@ENV{qw(LANGUAGE LANG LC_ALL)} = ('C') x 3;
+
+my $mb_locale = $ENV{LOCALE_FR_UTF8};
+! defined $mb_locale || $mb_locale eq 'none'
+ and $mb_locale = 'C';
+
+my $prog = 'cut';
+my $try = "Try '$prog --help' for more information.\n";
+my $from_field1 = "$prog: fields are numbered from 1\n$try";
+my $from_pos1 = "$prog: byte/character positions are numbered from 1\n$try";
+my $inval_fld = "$prog: invalid field range\n$try";
+my $inval_pos = "$prog: invalid byte or character range\n$try";
+my $no_endpoint = "$prog: invalid range with no endpoint: -\n$try";
+my $nofield = "$prog: an input delimiter may be specified only when " .
+ "operating on fields\n$try";
+
+my @Tests =
+ (
+ # Provoke a double-free in cut from coreutils-6.7.
+ ['dbl-free', '-f2-', {IN=>{f=>'x'}}, {IN=>{g=>'y'}}, {OUT=>"x\ny\n"}],
+
+ # This failed (as it should) even before coreutils-6.9.90,
+ # but cut from 6.9.90 produces a more useful diagnostic.
+ ['zero-1', '-b0', {ERR=>$from_pos1}, {EXIT => 1} ],
+
+ # Up to coreutils-6.9, specifying a range of 0-2 was not an error.
+ # It was treated just like "-2".
+ ['zero-2', '-f0-2', {ERR=>$from_field1}, {EXIT => 1} ],
+
+ # Up to coreutils-8.20, specifying a range of 0- was not an error.
+ ['zero-3b', '-b0-', {ERR=>$from_pos1}, {EXIT => 1} ],
+ ['zero-3c', '-c0-', {ERR=>$from_pos1}, {EXIT => 1} ],
+ ['zero-3f', '-f0-', {ERR=>$from_field1}, {EXIT => 1} ],
+
+ ['1', '-d:', '-f1,3-', {IN=>"a:b:c\n"}, {OUT=>"a:c\n"}],
+ ['2', '-d:', '-f1,3-', {IN=>"a:b:c\n"}, {OUT=>"a:c\n"}],
+ ['3', qw(-d: -f2-), {IN=>"a:b:c\n"}, {OUT=>"b:c\n"}],
+ ['4', qw(-d: -f4), {IN=>"a:b:c\n"}, {OUT=>"\n"}],
+ ['5', qw(-d: -f4), {IN=>""}, {OUT=>""}],
+ ['6', '-c4', {IN=>"123\n"}, {OUT=>"\n"}],
+ ['7', '-c4', {IN=>"123"}, {OUT=>"\n"}],
+ ['8', '-c4', {IN=>"123\n1"}, {OUT=>"\n\n"}],
+ ['9', '-c4', {IN=>""}, {OUT=>""}],
+ ['a', qw(-s -d:), '-f3-', {IN=>"a:b:c\n"}, {OUT=>"c\n"}],
+ ['b', qw(-s -d:), '-f2,3', {IN=>"a:b:c\n"}, {OUT=>"b:c\n"}],
+ ['c', qw(-s -d:), '-f1,3', {IN=>"a:b:c\n"}, {OUT=>"a:c\n"}],
+ # Trailing colon should not be output
+ ['d', qw(-s -d:), '-f1,3', {IN=>"a:b:c:\n"}, {OUT=>"a:c\n"}],
+ ['e', qw(-s -d:), '-f3-', {IN=>"a:b:c:\n"}, {OUT=>"c:\n"}],
+ ['f', qw(-s -d:), '-f3-4', {IN=>"a:b:c:\n"}, {OUT=>"c:\n"}],
+ ['g', qw(-s -d:), '-f3,4', {IN=>"a:b:c:\n"}, {OUT=>"c:\n"}],
+ # Make sure -s suppresses non-delimited lines
+ ['h', qw(-s -d:), '-f2,3', {IN=>"abc\n"}, {OUT=>""}],
+ #
+ ['i', qw(-d: -f1-3), {IN=>":::\n"}, {OUT=>"::\n"}],
+ ['j', qw(-d: -f1-4), {IN=>":::\n"}, {OUT=>":::\n"}],
+ ['k', qw(-d: -f2-3), {IN=>":::\n"}, {OUT=>":\n"}],
+ ['l', qw(-d: -f2-4), {IN=>":::\n"}, {OUT=>"::\n"}],
+ ['m', qw(-s -d: -f1-3), {IN=>":::\n"}, {OUT=>"::\n"}],
+ ['n', qw(-s -d: -f1-4), {IN=>":::\n"}, {OUT=>":::\n"}],
+ ['o', qw(-s -d: -f2-3), {IN=>":::\n"}, {OUT=>":\n"}],
+ ['p', qw(-s -d: -f2-4), {IN=>":::\n"}, {OUT=>"::\n"}],
+ ['q', qw(-s -d: -f2-4), {IN=>":::\n:\n"}, {OUT=>"::\n\n"}],
+ ['r', qw(-s -d: -f2-4), {IN=>":::\n:1\n"}, {OUT=>"::\n1\n"}],
+ ['s', qw(-s -d: -f1-4), {IN=>":::\n:a\n"}, {OUT=>":::\n:a\n"}],
+ ['t', qw(-s -d: -f3-), {IN=>":::\n:1\n"}, {OUT=>":\n\n"}],
+ # Make sure it handles empty input properly, with and without -s.
+ ['u', qw(-s -f3-), {IN=>""}, {OUT=>""}],
+ ['v', '-f3-', {IN=>""}, {OUT=>""}],
+ # Make sure it handles empty input properly.
+ ['w', qw(-b 1), {IN=>""}, {OUT=>""}],
+ ['x', qw(-s -d: -f2-4), {IN=>":\n"}, {OUT=>"\n"}],
+ # Errors
+ # -s may be used only with -f
+ ['y', qw(-s -b4), {IN=>":\n"}, {OUT=>""}, {EXIT=>1},
+ {ERR=>"$prog: suppressing non-delimited lines makes sense\n"
+ . "\tonly when operating on fields\n$try"}],
+ # You must specify bytes or fields (or chars)
+ ['z', '', {IN=>":\n"}, {OUT=>""}, {EXIT=>1},
+ {ERR=>"$prog: you must specify a list of bytes, characters, or fields\n$try"}
+ ],
+ # Empty field list
+ ['empty-fl', qw(-f ''), {IN=>":\n"}, {OUT=>""}, {EXIT=>1},
+ {ERR=>$from_field1}],
+ # Missing field list
+ ['missing-fl', qw(-f --), {IN=>":\n"}, {OUT=>""}, {EXIT=>1},
+ {ERR=>$inval_fld}],
+ # Empty byte list
+ ['empty-bl', qw(-b ''), {IN=>":\n"}, {OUT=>""}, {EXIT=>1}, {ERR=>$from_pos1}],
+ # Missing byte list
+ ['missing-bl', qw(-b --), {IN=>":\n"}, {OUT=>""}, {EXIT=>1},
+ {ERR=>$inval_pos}],
+
+ # This test fails with cut from textutils-1.22.
+ ['empty-f1', '-f1', {IN=>""}, {OUT=>""}],
+
+ ['empty-f2', '-f2', {IN=>""}, {OUT=>""}],
+
+ ['o-delim', qw(-d: --out=_), '-f2,3', {IN=>"a:b:c\n"}, {OUT=>"b_c\n"}],
+ ['nul-idelim', qw(-d '' --out=_), '-f2,3', {IN=>"a\0b\0c\n"}, {OUT=>"b_c\n"}],
+ ['nul-odelim', qw(-d: --out=), '-f2,3', {IN=>"a:b:c\n"}, {OUT=>"b\0c\n"}],
+ ['multichar-od', qw(-d: --out=_._), '-f2,3', {IN=>"a:b:c\n"},
+ {OUT=>"b_._c\n"}],
+
+ # Ensure delim is not allowed without a field
+ # Prior to 8.21, a NUL delim was allowed without a field
+ ['delim-no-field1', qw(-d ''), '-b1', {EXIT=>1}, {ERR=>$nofield}],
+ ['delim-no-field2', qw(-d:), '-b1', {EXIT=>1}, {ERR=>$nofield}],
+
+ # Prior to 1.22i, you couldn't use a delimiter that would sign-extend.
+ ['8bit-delim', '-d', "\255", '--out=_', '-f2,3', {IN=>"a\255b\255c\n"},
+ {OUT=>"b_c\n"}],
+
+ # newline processing for fields
+ ['newline-1', '-f1-', {IN=>"a\nb"}, {OUT=>"a\nb\n"}],
+ ['newline-2', '-f1-', {IN=>""}, {OUT=>""}],
+ ['newline-3', '-d:', '-f1', {IN=>"a:1\nb:2\n"}, {OUT=>"a\nb\n"}],
+ ['newline-4', '-d:', '-f1', {IN=>"a:1\nb:2"}, {OUT=>"a\nb\n"}],
+ ['newline-5', '-d:', '-f2', {IN=>"a:1\nb:2\n"}, {OUT=>"1\n2\n"}],
+ ['newline-6', '-d:', '-f2', {IN=>"a:1\nb:2"}, {OUT=>"1\n2\n"}],
+ ['newline-7', '-s', '-d:', '-f1', {IN=>"a:1\nb:2"}, {OUT=>"a\nb\n"}],
+ ['newline-8', '-s', '-d:', '-f1', {IN=>"a:1\nb:2\n"}, {OUT=>"a\nb\n"}],
+ ['newline-9', '-s', '-d:', '-f1', {IN=>"a1\nb2"}, {OUT=>""}],
+ ['newline-10', '-s', '-d:', '-f1,2', {IN=>"a:1\nb:2"}, {OUT=>"a:1\nb:2\n"}],
+ ['newline-11', '-s', '-d:', '-f1,2', {IN=>"a:1\nb:2\n"}, {OUT=>"a:1\nb:2\n"}],
+ ['newline-12', '-s', '-d:', '-f1', {IN=>"a:1\nb:"}, {OUT=>"a\nb\n"}],
+ ['newline-13', '-d:', '-f1-', {IN=>"a1:\n:"}, {OUT=>"a1:\n:\n"}],
+ # newline processing for fields when -d == '\n'
+ ['newline-14', "-d'\n'", '-f1', {IN=>"a:1\nb:"}, {OUT=>"a:1\n"}],
+ ['newline-15', '-s', "-d'\n'", '-f1', {IN=>"a:1\nb:"}, {OUT=>"a:1\n"}],
+ ['newline-16', '-s', "-d'\n'", '-f2', {IN=>"\nb"}, {OUT=>"b\n"}],
+ ['newline-17', '-s', "-d'\n'", '-f1', {IN=>"\nb"}, {OUT=>"\n"}],
+ ['newline-18', "-d'\n'", '-f2', {IN=>"\nb"}, {OUT=>"b\n"}],
+ ['newline-19', "-d'\n'", '-f1', {IN=>"\nb"}, {OUT=>"\n"}],
+ ['newline-20', '-s', "-d'\n'", '-f1-', {IN=>"\n"}, {OUT=>"\n"}],
+ ['newline-21', '-s', "-d'\n'", '-f1-', {IN=>"\nb"}, {OUT=>"\nb\n"}],
+ ['newline-22', "-d'\n'", '-f1-', {IN=>"\nb"}, {OUT=>"\nb\n"}],
+ ['newline-23', "-d'\n'", '-f1-', '--ou=:', {IN=>"a\nb\n"}, {OUT=>"a:b\n"}],
+ ['newline-24', "-d'\n'", '-f1,2', '--ou=:', {IN=>"a\nb\n"}, {OUT=>"a:b\n"}],
+
+ # --zero-terminated
+ ['zerot-1', "-z", '-c1', {IN=>"ab\0cd\0"}, {OUT=>"a\0c\0"}],
+ ['zerot-2', "-z", '-c1', {IN=>"ab\0cd"}, {OUT=>"a\0c\0"}],
+ ['zerot-3', '-z -f1-', {IN=>""}, {OUT=>""}],
+ ['zerot-4', '-z -d:', '-f1', {IN=>"a:1\0b:2"}, {OUT=>"a\0b\0"}],
+ ['zerot-5', '-z -d:', '-f1-', {IN=>"a1:\0:"}, {OUT=>"a1:\0:\0"}],
+ ['zerot-6', "-z -d ''", '-f1,2', '--ou=:', {IN=>"a\0b\0"}, {OUT=>"a:b\0"}],
+
+ # New functionality:
+ ['out-delim1', '-c1-3,5-', '--output-d=:', {IN=>"abcdefg\n"},
+ {OUT=>"abc:efg\n"}],
+ # A totally overlapped field shouldn't change anything:
+ ['out-delim2', '-c1-3,2,5-', '--output-d=:', {IN=>"abcdefg\n"},
+ {OUT=>"abc:efg\n"}],
+ # Partial overlap: index '2' is not at the start of a range.
+ ['out-delim3', '-c1-3,2-4,6', '--output-d=:', {IN=>"abcdefg\n"},
+ {OUT=>"abcd:f\n"}],
+ ['out-delim3a', '-c1-3,2-4,6-', '--output-d=:', {IN=>"abcdefg\n"},
+ {OUT=>"abcd:fg\n"}],
+ # Ensure that the following two commands produce the same output.
+ # Before an off-by-1 fix, the output from the former would not contain a ':'.
+ ['out-delim4', '-c4-,2-3', '--output-d=:',
+ {IN=>"abcdefg\n"}, {OUT=>"bc:defg\n"}],
+ ['out-delim5', '-c2-3,4-', '--output-d=:',
+ {IN=>"abcdefg\n"}, {OUT=>"bc:defg\n"}],
+ # This test would fail for cut from coreutils-5.0.1 and earlier.
+ ['out-delim6', '-c2,1-3', '--output-d=:', {IN=>"abc\n"}, {OUT=>"abc\n"}],
+ #
+ ['od-abut', '-b1-2,3-4', '--output-d=:', {IN=>"abcd\n"}, {OUT=>"ab:cd\n"}],
+ ['od-overlap', '-b1-2,2', '--output-d=:', {IN=>"abc\n"}, {OUT=>"ab\n"}],
+ ['od-overlap2', '-b1-2,2-', '--output-d=:', {IN=>"abc\n"}, {OUT=>"abc\n"}],
+ ['od-overlap3', '-b1-3,2-', '--output-d=:', {IN=>"abcd\n"}, {OUT=>"abcd\n"}],
+ ['od-overlap4', '-b1-3,2-3', '--output-d=:', {IN=>"abcd\n"}, {OUT=>"abc\n"}],
+ ['od-overlap5', '-b1-3,1-4', '--output-d=:',
+ {IN=>"abcde\n"}, {OUT=>"abcd\n"}],
+
+ # None of the following invalid ranges provoked an error up to coreutils-6.9.
+ ['inval1', qw(-f 2-0), {IN=>''}, {OUT=>''}, {EXIT=>1},
+ {ERR=>"$prog: invalid decreasing range\n$try"}],
+ ['inval2', qw(-f -), {IN=>''}, {OUT=>''}, {EXIT=>1}, {ERR=>$no_endpoint}],
+ ['inval3', '-f', '4,-', {IN=>''}, {OUT=>''}, {EXIT=>1}, {ERR=>$no_endpoint}],
+ ['inval4', '-f', '1-2,-', {IN=>''}, {OUT=>''}, {EXIT=>1},
+ {ERR=>$no_endpoint}],
+ ['inval5', '-f', '1-,-', {IN=>''}, {OUT=>''}, {EXIT=>1}, {ERR=>$no_endpoint}],
+ ['inval6', '-f', '-1,-', {IN=>''}, {OUT=>''}, {EXIT=>1}, {ERR=>$no_endpoint}],
+ # This would evoke a segfault from 5.3.0..8.10
+ ['big-unbounded-b', '--output-d=:', '-b1234567890-', {IN=>''}, {OUT=>''}],
+ ['big-unbounded-b2a', '--output-d=:', '-b1,9-', {IN=>'123456789'},
+ {OUT=>"1:9\n"}],
+ ['big-unbounded-b2b', '--output-d=:', '-b1,1234567890-', {IN=>''}, {OUT=>''}],
+ ['big-unbounded-c', '--output-d=:', '-c1234567890-', {IN=>''}, {OUT=>''}],
+ ['big-unbounded-f', '--output-d=:', '-f1234567890-', {IN=>''}, {OUT=>''}],
+
+ ['overlapping-unbounded-1', '-b3-,2-', {IN=>"1234\n"}, {OUT=>"234\n"}],
+ ['overlapping-unbounded-2', '-b2-,3-', {IN=>"1234\n"}, {OUT=>"234\n"}],
+
+ # When printing output delimiters, and with one or more ranges subsumed
+ # by a to-EOL range, cut 8.20 and earlier would print extraneous delimiters.
+ ['EOL-subsumed-1', '--output-d=: -b2-,3,4-4,5',
+ {IN=>"123456\n"}, {OUT=>"23456\n"}],
+ ['EOL-subsumed-2', '--output-d=: -b3,4-4,5,2-',
+ {IN=>"123456\n"}, {OUT=>"23456\n"}],
+ ['EOL-subsumed-3', '--complement -b3,4-4,5,2-',
+ {IN=>"123456\n"}, {OUT=>"1\n"}],
+ ['EOL-subsumed-4', '--output-d=: -b1-2,2-3,3-',
+ {IN=>"1234\n"}, {OUT=>"1234\n"}],
+ );
+
+if ($mb_locale ne 'C')
+ {
+ # Duplicate each test vector, appending "-mb" to the test name and
+ # inserting {ENV => "LC_ALL=$mb_locale"} in the copy, so that we
+ # provide coverage for the distro-added multi-byte code paths.
+ my @new;
+ foreach my $t (@Tests)
+ {
+ my @new_t = @$t;
+ my $test_name = shift @new_t;
+
+ push @new, ["$test_name-mb", @new_t, {ENV => "LC_ALL=$mb_locale"}];
+ }
+ push @Tests, @new;
+ }
+
+
+@Tests = triple_test \@Tests;
+
+my $save_temps = $ENV{DEBUG};
+my $verbose = $ENV{VERBOSE};
+
+my $fail = run_tests ($ME, $prog, \@Tests, $save_temps, $verbose);
+exit $fail;
diff --git a/tests/d_type-check b/tests/d_type-check
new file mode 100644
index 0000000..1a2f76f
--- /dev/null
+++ b/tests/d_type-check
@@ -0,0 +1,69 @@
+#!/usr/bin/python
+# Exit 0 if "." and "./tempfile" have useful d_type information, else 1.
+# Intended to exit 0 only on Linux/GNU systems.
+import os
+import sys
+import tempfile
+
+fail = 1
+fname = None
+
+try:
+ import ctypes.util
+
+ (DT_UNKNOWN, DT_DIR, DT_REG) = (0, 4, 8)
+
+ class dirent(ctypes.Structure):
+ _fields_ = [
+ ("d_ino", ctypes.c_long),
+ ("d_off", ctypes.c_long),
+ ("d_reclen", ctypes.c_ushort),
+ ("d_type", ctypes.c_ubyte),
+ ("d_name", ctypes.c_char*256)]
+
+ # Pass NULL to dlopen, assuming the python
+ # interpreter is linked with the C runtime
+ libc = ctypes.CDLL(None)
+
+ # Setup correct types for all args and returns
+ # even if only passing, to avoid truncation etc.
+ dirp = ctypes.c_void_p
+ direntp = ctypes.POINTER(dirent)
+
+ libc.readdir.argtypes = [dirp]
+ libc.readdir.restype = direntp
+
+ libc.opendir.restype = dirp
+
+ # Ensure a file is present
+ f, fname = tempfile.mkstemp(dir='.')
+ fname = os.path.basename(fname)
+
+ dirp = libc.opendir(".")
+ if dirp:
+ while True:
+ ep = libc.readdir(dirp)
+ if not ep: break
+ d_type = ep.contents.d_type
+ name = ep.contents.d_name
+ if name == "." or name == "..":
+ if d_type != DT_DIR: break
+ # Check files too since on XFS, only dirs have DT_DIR
+ # while everything else has DT_UNKNOWN
+ elif name == fname:
+ if d_type == DT_REG:
+ fail = 0
+ break
+ elif d_type != DT_DIR and d_type != DT_UNKNOWN:
+ fail = 0
+ break
+except:
+ pass
+
+try:
+ if fname:
+ os.unlink(fname);
+except:
+ pass
+
+sys.exit(fail)
diff --git a/tests/date/date-debug.sh b/tests/date/date-debug.sh
new file mode 100755
index 0000000..f9e42f9
--- /dev/null
+++ b/tests/date/date-debug.sh
@@ -0,0 +1,311 @@
+#!/bin/sh
+# Test 'date --debug' option.
+
+# Copyright (C) 2016-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ date
+
+export LC_ALL=C
+
+## Ensure timezones are supported.
+## (NOTE: America/Belize timezone does not change on DST)
+test "$(TZ=America/Belize date +%z)" = '-0600' \
+ || skip_ 'Timezones database not found'
+
+date --debug >/dev/null 2>d_t_fmt.err || fail=1
+d_t_fmt=$(sed -n "s/.*'\(.*\)'$/\1/p" < d_t_fmt.err) || framework_failure_
+test -n "$d_t_fmt" || fail=1
+
+##
+## Test 1: complex date string
+##
+in1='TZ="Asia/Tokyo" Sun, 90-12-11 + 3 days - 90 minutes'
+
+cat<<EOF>exp1
+date: parsed day part: Sun (day ordinal=0 number=0)
+date: parsed date part: (Y-M-D) 0090-12-11
+date: parsed relative part: +3 day(s)
+date: parsed relative part: +3 day(s) -90 minutes
+date: input timezone: TZ="Asia/Tokyo" in date string
+date: warning: adjusting year value 90 to 1990
+date: warning: using midnight as starting time: 00:00:00
+date: warning: day (Sun) ignored when explicit dates are given
+date: starting date/time: '(Y-M-D) 1990-12-11 00:00:00'
+date: warning: when adding relative days, it is recommended to specify noon
+date: after date adjustment (+0 years, +0 months, +3 days),
+date: new date/time = '(Y-M-D) 1990-12-14 00:00:00'
+date: '(Y-M-D) 1990-12-14 00:00:00' = 661100400 epoch-seconds
+date: after time adjustment (+0 hours, -90 minutes, +0 seconds, +0 ns),
+date: new time = 661095000 epoch-seconds
+date: timezone: TZ="Asia/Tokyo" environment value
+date: final: 661095000.000000000 (epoch-seconds)
+date: final: (Y-M-D) 1990-12-13 13:30:00 (UTC)
+date: final: (Y-M-D) 1990-12-13 22:30:00 (UTC+09)
+date: output format: '%a %b %e %T %z %Y'
+Thu Dec 13 07:30:00 -0600 1990
+EOF
+
+TZ=America/Belize date --debug -d "$in1" +'%a %b %e %T %z %Y' >out1 2>&1 ||
+ fail=1
+
+compare exp1 out1 || fail=1
+
+##
+## Test 2: Invalid date from Coreutils' FAQ
+## (with explicit timezone added)
+in2='TZ="America/Edmonton" 2006-04-02 02:30:00'
+cat<<EOF>exp2
+date: parsed date part: (Y-M-D) 2006-04-02
+date: parsed time part: 02:30:00
+date: input timezone: TZ="America/Edmonton" in date string
+date: using specified time as starting value: '02:30:00'
+date: error: invalid date/time value:
+date: user provided time: '(Y-M-D) 2006-04-02 02:30:00'
+date: normalized time: '(Y-M-D) 2006-04-02 XX:XX:XX'
+date: --
+date: possible reasons:
+date: nonexistent due to daylight-saving time;
+date: numeric values overflow;
+date: missing timezone
+date: invalid date 'TZ="America/Edmonton" 2006-04-02 02:30:00'
+EOF
+
+# date should return 1 (error) for invalid date
+returns_ 1 date --debug -d "$in2" >out2-t 2>&1 || fail=1
+
+# The output line of "normalized time" can differ between systems
+# (e.g. glibc vs musl) and should not be checked.
+# See: https://lists.gnu.org/archive/html/coreutils/2019-05/msg00039.html
+sed '/normalized time:/s/ [0-9][0-9]:[0-9][0-9]:[0-9][0-9]/ XX:XX:XX/' \
+ out2-t > out2 || framework_failure_
+
+compare exp2 out2 || fail=1
+
+##
+## Test 3: timespec (input always UTC, output is TZ-dependent)
+##
+in3='@1'
+cat<<EOF>exp3
+date: parsed number of seconds part: number of seconds: 1
+date: input timezone: '@timespec' - always UTC
+date: timezone: TZ="America/Lima" environment value
+date: final: 1.000000000 (epoch-seconds)
+date: final: (Y-M-D) 1970-01-01 00:00:01 (UTC)
+date: final: (Y-M-D) 1969-12-31 19:00:01 (UTC-05)
+date: output format: '%a %b %e %T %z %Y'
+Wed Dec 31 19:00:01 -0500 1969
+EOF
+
+TZ=America/Lima date --debug -d "$in3" +'%a %b %e %T %z %Y' >out3 2>&1 || fail=1
+compare exp3 out3 || fail=1
+
+##
+## Parsing a lone number.
+## Fixed in gnulib v0.1-1099-gf2d4b5c
+## https://git.savannah.gnu.org/cgit/gnulib.git/commit/?id=f2d4b5caa
+cat<<EOF>exp4
+date: parsed number part: (Y-M-D) 2013-01-01
+date: input timezone: TZ="UTC0" environment value or -u
+date: warning: using midnight as starting time: 00:00:00
+date: starting date/time: '(Y-M-D) 2013-01-01 00:00:00'
+date: '(Y-M-D) 2013-01-01 00:00:00' = 1356998400 epoch-seconds
+date: timezone: Universal Time
+date: final: 1356998400.000000000 (epoch-seconds)
+date: final: (Y-M-D) 2013-01-01 00:00:00 (UTC)
+date: final: (Y-M-D) 2013-01-01 00:00:00 (UTC+00)
+date: output format: '$d_t_fmt'
+Tue Jan 1 00:00:00 UTC 2013
+EOF
+
+date -u --debug -d '20130101' >out4 2>&1 || fail=1
+compare exp4 out4 || fail=1
+
+
+##
+## Parsing a relative number after a timezone string
+## Fixed in gnulib v0.1-1100-g5c438e8
+## https://git.savannah.gnu.org/cgit/gnulib.git/commit/?id=5c438e8ce7d
+cat<<EOF>exp5
+date: parsed date part: (Y-M-D) 2013-10-30
+date: parsed time part: 00:00:00
+date: parsed relative part: -8 day(s)
+date: parsed zone part: UTC+00
+date: input timezone: parsed date/time string (+00)
+date: using specified time as starting value: '00:00:00'
+date: starting date/time: '(Y-M-D) 2013-10-30 00:00:00 TZ=+00'
+date: warning: when adding relative days, it is recommended to specify noon
+date: after date adjustment (+0 years, +0 months, -8 days),
+date: new date/time = '(Y-M-D) 2013-10-22 00:00:00 TZ=+00'
+date: '(Y-M-D) 2013-10-22 00:00:00 TZ=+00' = 1382400000 epoch-seconds
+date: timezone: Universal Time
+date: final: 1382400000.000000000 (epoch-seconds)
+date: final: (Y-M-D) 2013-10-22 00:00:00 (UTC)
+date: final: (Y-M-D) 2013-10-22 00:00:00 (UTC+00)
+date: output format: '%F'
+2013-10-22
+EOF
+
+in5='2013-10-30 00:00:00 UTC -8 days'
+date -u --debug +%F -d "$in5" >out5 2>&1 || fail=1
+compare exp5 out5 || fail=1
+
+##
+## Explicitly warn about unexpected day/month shifts.
+## added in gnulib v0.1-1101-gf14eff1
+## https://git.savannah.gnu.org/cgit/gnulib.git/commit/?id=f14eff1b3cde2b
+TOOLONG='it is recommended to specify the 15th of the months'
+cat<<EOF>exp6
+date: parsed date part: (Y-M-D) 2016-10-31
+date: parsed relative part: -1 month(s)
+date: input timezone: TZ="UTC0" environment value or -u
+date: warning: using midnight as starting time: 00:00:00
+date: starting date/time: '(Y-M-D) 2016-10-31 00:00:00'
+date: warning: when adding relative months/years, $TOOLONG
+date: after date adjustment (+0 years, -1 months, +0 days),
+date: new date/time = '(Y-M-D) 2016-10-01 00:00:00'
+date: warning: month/year adjustment resulted in shifted dates:
+date: adjusted Y M D: 2016 09 31
+date: normalized Y M D: 2016 10 01
+date: '(Y-M-D) 2016-10-01 00:00:00' = 1475280000 epoch-seconds
+date: timezone: Universal Time
+date: final: 1475280000.000000000 (epoch-seconds)
+date: final: (Y-M-D) 2016-10-01 00:00:00 (UTC)
+date: final: (Y-M-D) 2016-10-01 00:00:00 (UTC+00)
+date: output format: '$d_t_fmt'
+Sat Oct 1 00:00:00 UTC 2016
+EOF
+
+date -u --debug -d '2016-10-31 - 1 month' >out6 2>&1 || fail=1
+compare exp6 out6 || fail=1
+
+
+##
+## Explicitly warn about crossing DST boundaries.
+## added in gnulib v0.1-1102-g30a55dd
+## https://git.savannah.gnu.org/cgit/gnulib.git/commit/?id=30a55dd72dad2
+TOOLONG2='it is recommended to specify the 15th of the months'
+cat<<EOF>exp7
+date: parsed date part: (Y-M-D) 2016-06-01
+date: parsed local_zone part: isdst=1
+date: parsed relative part: +6 month(s)
+date: input timezone: TZ="America/New_York" environment value, dst
+date: warning: using midnight as starting time: 00:00:00
+date: starting date/time: '(Y-M-D) 2016-06-01 00:00:00'
+date: warning: when adding relative months/years, $TOOLONG2
+date: after date adjustment (+0 years, +6 months, +0 days),
+date: new date/time = '(Y-M-D) 2016-11-30 23:00:00'
+date: warning: daylight saving time changed after date adjustment
+date: warning: month/year adjustment resulted in shifted dates:
+date: adjusted Y M D: 2016 12 01
+date: normalized Y M D: 2016 11 30
+date: '(Y-M-D) 2016-11-30 23:00:00' = 1480564800 epoch-seconds
+date: timezone: TZ="America/New_York" environment value
+date: final: 1480564800.000000000 (epoch-seconds)
+date: final: (Y-M-D) 2016-12-01 04:00:00 (UTC)
+date: final: (Y-M-D) 2016-11-30 23:00:00 (UTC-05)
+date: output format: '%F'
+2016-11-30
+EOF
+
+in7='2016-06-01 EDT + 6 months'
+TZ=America/New_York date --debug -d "$in7" +%F >out7 2>&1 || fail=1
+compare exp7 out7 || fail=1
+
+
+## fix local timezone debug messages.
+## fixed in git v0.1-1103-gc56e7fb
+## https://git.savannah.gnu.org/cgit/gnulib.git/commit/?id=c56e7fbb032
+
+cat<<EOF>exp8_1
+date: parsed date part: (Y-M-D) 2011-12-11
+date: parsed local_zone part: isdst=0
+date: input timezone: TZ="Europe/Helsinki" environment value
+date: warning: using midnight as starting time: 00:00:00
+date: starting date/time: '(Y-M-D) 2011-12-11 00:00:00'
+date: '(Y-M-D) 2011-12-11 00:00:00' = 1323554400 epoch-seconds
+date: timezone: TZ="Europe/Helsinki" environment value
+date: final: 1323554400.000000000 (epoch-seconds)
+date: final: (Y-M-D) 2011-12-10 22:00:00 (UTC)
+date: final: (Y-M-D) 2011-12-11 00:00:00 (UTC+02)
+date: output format: '$d_t_fmt'
+Sun Dec 11 00:00:00 EET 2011
+EOF
+
+TZ=Europe/Helsinki date --debug -d '2011-12-11 EET' >out8_1 2>&1 || fail=1
+compare exp8_1 out8_1 || fail=1
+
+cat<<EOF>exp8_2
+date: parsed date part: (Y-M-D) 2011-06-11
+date: parsed local_zone part: isdst=1
+date: input timezone: TZ="Europe/Helsinki" environment value, dst
+date: warning: using midnight as starting time: 00:00:00
+date: starting date/time: '(Y-M-D) 2011-06-11 00:00:00'
+date: '(Y-M-D) 2011-06-11 00:00:00' = 1307739600 epoch-seconds
+date: timezone: TZ="Europe/Helsinki" environment value
+date: final: 1307739600.000000000 (epoch-seconds)
+date: final: (Y-M-D) 2011-06-10 21:00:00 (UTC)
+date: final: (Y-M-D) 2011-06-11 00:00:00 (UTC+03)
+date: output format: '$d_t_fmt'
+Sat Jun 11 00:00:00 EEST 2011
+EOF
+
+TZ=Europe/Helsinki date --debug -d '2011-06-11 EEST' >out8_2 2>&1 || fail=1
+compare exp8_2 out8_2 || fail=1
+
+
+
+## fix debug message on lone year number (The "2011" part).
+## fixed in gnulib v0.1-1104-g15b8f30
+## https://git.savannah.gnu.org/cgit/gnulib.git/commit/?id=15b8f3046a25
+##
+## NOTE:
+## When the date 'Apr 11' is parsed, the year part will be the
+## current year. The expected output thus depends on the year
+## the test is being run. We'll use sed to change it to XXXX.
+cat<<EOF>exp9
+date: parsed date part: (Y-M-D) XXXX-04-11
+date: parsed time part: 22:59:00
+date: parsed number part: year: 2011
+date: input timezone: TZ="UTC0" environment value or -u
+date: using specified time as starting value: '22:59:00'
+date: starting date/time: '(Y-M-D) 2011-04-11 22:59:00'
+date: '(Y-M-D) 2011-04-11 22:59:00' = 1302562740 epoch-seconds
+date: timezone: Universal Time
+date: final: 1302562740.000000000 (epoch-seconds)
+date: final: (Y-M-D) 2011-04-11 22:59:00 (UTC)
+date: final: (Y-M-D) 2011-04-11 22:59:00 (UTC+00)
+date: output format: '$d_t_fmt'
+Mon Apr 11 22:59:00 UTC 2011
+EOF
+
+date -u --debug -d 'Apr 11 22:59:00 2011' >out9_t 2>&1 || fail=1
+sed '1s/(Y-M-D) [0-9][0-9][0-9][0-9]-/(Y-M-D) XXXX-/' out9_t > out9 \
+ || framework_failure_
+compare exp9 out9 || fail=1
+
+
+# Diagnose discarded -d arguments
+echo 'date: only using last of multiple -d options' > exp10 \
+ || framework_failure_
+cat exp9 >> exp10 || framework_failure_
+date -u --debug -d 'discard' -d 'Apr 11 22:59:00 2011' > out10_t 2>&1 || fail=1
+sed '2s/(Y-M-D) [0-9][0-9][0-9][0-9]-/(Y-M-D) XXXX-/' out10_t >> out10 \
+ || framework_failure_
+compare exp10 out10 || fail=1
+
+
+Exit $fail
diff --git a/tests/date/date-next-dow.pl b/tests/date/date-next-dow.pl
new file mode 100755
index 0000000..ec414c7
--- /dev/null
+++ b/tests/date/date-next-dow.pl
@@ -0,0 +1,78 @@
+#!/usr/bin/perl
+# Test "date".
+
+# Copyright (C) 2005-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+use strict;
+use POSIX qw(strftime);
+
+(my $ME = $0) =~ s|.*/||;
+
+# Turn off localization of executable's output.
+@ENV{qw(LANGUAGE LANG LC_ALL)} = ('C') x 3;
+
+# Export TZ=UTC0 so that zone-dependent strings match.
+$ENV{TZ} = 'UTC0';
+
+my $now = time;
+my @d = localtime ($now);
+my @d_week = localtime ($now + 7 * 24 * 3600);
+my $wday = $d[6];
+my $wday_str = qw(sun mon tue wed thu fri sat)[$wday];
+
+my @Tests =
+ (
+ # test-name, [option, option, ...] {OUT=>"expected-output"}
+ #
+
+ # Running "date -d mon +%a" on a Monday must print Mon.
+ ['dow', "-d $wday_str +%a", {OUT => ucfirst $wday_str}],
+ # It had better be the same date, too.
+ ['dow2', "-d $wday_str +%Y-%m-%d", {OUT => strftime("%Y-%m-%d", @d)}],
+
+ ['next-dow', "-d 'next $wday_str' +%Y-%m-%d",
+ {OUT => strftime("%Y-%m-%d", @d_week)}],
+ );
+
+# Append "\n" to each OUT=> RHS if the expected exit value is either
+# zero or not specified (defaults to zero).
+foreach my $t (@Tests)
+ {
+ my $exit_val;
+ foreach my $e (@$t)
+ {
+ ref $e && ref $e eq 'HASH' && defined $e->{EXIT}
+ and $exit_val = $e->{EXIT};
+ }
+ foreach my $e (@$t)
+ {
+ ref $e && ref $e eq 'HASH' && defined $e->{OUT} && ! $exit_val
+ and $e->{OUT} .= "\n";
+ }
+ }
+
+my $save_temps = $ENV{DEBUG};
+my $verbose = $ENV{VERBOSE};
+
+my $prog = 'date';
+my $fail = run_tests ($ME, $prog, \@Tests, $save_temps, $verbose);
+
+# Skip the test if the starting and stopping day numbers differ.
+my @d_post = localtime (time);
+$d_post[7] == $d[7]
+ or CuSkip::skip "$ME: test straddled a day boundary; skipped";
+
+exit $fail;
diff --git a/tests/date/date-sec.sh b/tests/date/date-sec.sh
new file mode 100755
index 0000000..f18590e
--- /dev/null
+++ b/tests/date/date-sec.sh
@@ -0,0 +1,49 @@
+#!/bin/sh
+# Ensure that a command like
+# date --date="21:04 +0100" +%S' always prints '00'.
+# Before coreutils-5.2.1, it would print the seconds from the current time.
+
+# Copyright (C) 2004-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ date
+
+
+
+# It would be easier simply to sleep for two seconds between two runs
+# of $(date --date="21:04 +0100" +%S) and ensure that both outputs
+# are '00', but I prefer not to sleep unconditionally. 'make check'
+# takes long enough as it is.
+
+n=0
+# See if the current number of seconds is '00' or just before.
+s=$(date +%S)
+case "$s" in
+ 58) n=3;;
+ 59) n=2;;
+ 00) n=1;;
+esac
+
+# If necessary, wait for the system clock to pass the minute mark.
+test $n = 0 || sleep $n
+
+s=$(date --date="21:04 +0100" +%S)
+case "$s" in
+ 00) ;;
+ *) fail=1;;
+esac
+
+Exit $fail
diff --git a/tests/date/date-tz.sh b/tests/date/date-tz.sh
new file mode 100755
index 0000000..f6cf071
--- /dev/null
+++ b/tests/date/date-tz.sh
@@ -0,0 +1,26 @@
+#!/bin/sh
+# Verify TZ processing.
+
+# Copyright (C) 2017-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ date
+
+# coreutils-8.27 would overwrite the heap with large TZ values
+tz_long=$(printf '%2000s' | tr ' ' a)
+date -d "TZ=\"${tz_long}0\" 2017" || fail=1
+
+Exit $fail
diff --git a/tests/date/date.pl b/tests/date/date.pl
new file mode 100755
index 0000000..d18f8b1
--- /dev/null
+++ b/tests/date/date.pl
@@ -0,0 +1,381 @@
+#!/usr/bin/perl
+# Test "date".
+
+# Copyright (C) 2005-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+use strict;
+
+(my $ME = $0) =~ s|.*/||;
+
+# Turn off localization of executable's output.
+@ENV{qw(LANGUAGE LANG LC_ALL)} = ('C') x 3;
+
+# Export TZ=UTC0 so that zone-dependent strings match.
+$ENV{TZ} = 'UTC0';
+
+my $t0 = '08:17:48';
+my $d0 = '1997-01-19';
+my $d1 = "$d0 $t0 +0";
+my $dT = "${d0}T$t0+0"; # ISO 8601 with "T" separator
+
+my $ts = '08:17:49'; # next second
+my $tm = '08:18:48'; # next minute
+my $th = '09:17:48'; # next hour
+
+my $dd = '1997-01-20'; # next day
+my $dw = '1997-01-26'; # next week
+my $dm = '1997-02-19'; # next month
+my $dy = '1998-01-19'; # next month
+
+my $fmt = "'+%Y-%m-%d %T'";
+
+my @Tests =
+ (
+ # test-name, [option, option, ...] {OUT=>"expected-output"}
+ #
+ ['1', "-d '$d1' +'%% %a %A %b %B'", {OUT=>"% Sun Sunday Jan January"}],
+
+ # [Actually, skip it on *all* systems. -- this Perl code is run at
+ # distribution-build-time, not at configure/test time. ]
+
+ # Skip the test of %c on SunOS4 systems. Such systems would fail this
+ # test because their underlying strftime doesn't handle the %c format
+ # properly. GNU strftime must rely on the underlying host library
+ # function to get locale-dependent behavior, as strftime is the only
+ # portable interface to that behavior.
+ # ['2', "-d '$d1' +'%c'", {OUT=>"Sun Jan 19 $t0 1997"}],
+
+ ['3', "-d '$d1' +'%d_%D_%e_%h_%H'", {OUT=>"19_01/19/97_19_Jan_08"}],
+ ['3T',"-d '$dT' +'%d_%D_%e_%h_%H'", {OUT=>"19_01/19/97_19_Jan_08"}],
+
+ ['4', "-d '$d1' +'%I_%j_%k_%l_%m'", {OUT=>"08_019_ 8_ 8_01"}],
+ ['5', "-d '$d1' +'%M_%n_%p_%r'", {OUT=>"17_\n_AM_$t0 AM"}],
+ ['6', "-d '$d1' +'%s_%S_%t_%T'", {OUT=>"853661868_48_\t_$t0"}],
+ ['7', "-d '$d1' +'%U_%V_%w_%W'", {OUT=>"03_03_0_02"}],
+ ['8', "-d '$d1' +'%x_%X_%y_%Y'", {OUT=>"01/19/97_${t0}_97_1997"}],
+ ['9', "-d '$d1' +'%z'", {OUT=>"+0000"}],
+
+ ['leap-1', "--date '02/29/1996 1 year' +%Y-%m-%d", {OUT=>"1997-03-01"}],
+
+ ['U95-1', "--date '1995-1-1' +%U", {OUT=>"01"}],
+ ['U95-2', "--date '1995-1-7' +%U", {OUT=>"01"}],
+ ['U95-3', "--date '1995-1-8' +%U", {OUT=>"02"}],
+
+ ['U92-1', "--date '1992-1-1' +%U", {OUT=>"00"}],
+ ['U92-2', "--date '1992-1-4' +%U", {OUT=>"00"}],
+ ['U92-3', "--date '1992-1-5' +%U", {OUT=>"01"}],
+
+ ['V92-1', "--date '1992-1-1' +%V", {OUT=>"01"}],
+ ['V92-2', "--date '1992-1-5' +%V", {OUT=>"01"}],
+ ['V92-3', "--date '1992-1-6' +%V", {OUT=>"02"}],
+
+ ['W92-1', "--date '1992-1-1' +%W", {OUT=>"00"}],
+ ['W92-2', "--date '1992-1-5' +%W", {OUT=>"00"}],
+ ['W92-3', "--date '1992-1-6' +%W", {OUT=>"01"}],
+
+ ['q-1', "--date '2016-1-1' +%q", {OUT=>"1"}],
+ ['q-2', "--date '2016-4-1' +%q", {OUT=>"2"}],
+ ['q-3', "--date '2016-7-1' +%q", {OUT=>"3"}],
+ ['q-4', "--date '2016-10-1' +%q", {OUT=>"4"}],
+
+ ['millen-1', "--date '1998-1-1 3 years' +%Y", {OUT=>"2001"}],
+
+ ['rel-0', "-d '$d1 now' '+%Y-%m-%d %T'", {OUT=>"$d0 $t0"}],
+
+ ['rel-1a', "-d '$d1 yesterday' $fmt", {OUT=>"1997-01-18 $t0"}],
+ ['rel-1b', "-d '$d1 tomorrow' $fmt", {OUT=>"1997-01-20 $t0"}],
+
+ ['rel-2a', "-d '$d1 6 years ago' $fmt", {OUT=>"1991-01-19 $t0"}],
+ ['rel-2b', "-d '$d1 7 months ago' $fmt", {OUT=>"1996-06-19 $t0"}],
+ ['rel-2c', "-d '$d1 8 weeks ago' $fmt", {OUT=>"1996-11-24 $t0"}],
+ ['rel-2d', "-d '$d1 1 day ago' $fmt", {OUT=>"1997-01-18 $t0"}],
+ ['rel-2e', "-d '$d1 2 hours ago' $fmt", {OUT=>"$d0 06:17:48"}],
+ ['rel-2f', "-d '$d1 3 minutes ago' $fmt", {OUT=>"$d0 08:14:48"}],
+ ['rel-2g', "-d '$d1 4 seconds ago' $fmt", {OUT=>"$d0 08:17:44"}],
+
+ ['rel-3a', "-d '$d1 4 seconds ago' $fmt", {OUT=>"$d0 08:17:44"}],
+
+ # This has always worked, ...
+ ['rel-1day', "-d '20050101 1 day' +%F", {OUT=>"2005-01-02"}],
+ # ...but up to coreutils-6.9, this was rejected due to the "+".
+ ['rel-plus1', "-d '20050101 +1 day' +%F", {OUT=>"2005-01-02"}],
+
+ ['next-s', "-d '$d1 next second' '+%Y-%m-%d %T'", {OUT=>"$d0 $ts"}],
+ ['next-m', "-d '$d1 next minute' '+%Y-%m-%d %T'", {OUT=>"$d0 $tm"}],
+ ['next-h', "-d '$d1 next hour' '+%Y-%m-%d %T'", {OUT=>"$d0 $th"}],
+ ['next-d', "-d '$d1 next day' '+%Y-%m-%d %T'", {OUT=>"$dd $t0"}],
+ ['next-w', "-d '$d1 next week' '+%Y-%m-%d %T'", {OUT=>"$dw $t0"}],
+ ['next-mo', "-d '$d1 next month' '+%Y-%m-%d %T'", {OUT=>"$dm $t0"}],
+ ['next-y', "-d '$d1 next year' '+%Y-%m-%d %T'", {OUT=>"$dy $t0"}],
+
+ ['utc-0', "-u -d '08/01/97 6:00' '+%D,%H:%M'", {OUT=>"08/01/97,06:00"},
+ {ENV => 'TZ=UTC+4'}],
+
+ ['utc-0a', "-u -d '08/01/97 6:00 UTC +4 hours' '+%D,%H:%M'",
+ {OUT=>"08/01/97,10:00"}],
+ # Make sure --file=FILE works with -u.
+ ['utc-1', "-u --file=f '+%Y-%m-%d %T'",
+ {AUX=>{f=>"$d0 $t0\n$d0 $t0"}},
+ {OUT=>"$d0 $t0\n$d0 $t0"},
+ {ENV => 'TZ=UTC+1'}],
+
+ ['utc-1a', "-u --file=f '+%Y-%m-%d %T'",
+ {AUX=>{f=>"$d0 $t0 UTC +1 hour\n$d0 $t0 UTC +1 hour"}},
+ {OUT=>"$d0 $th\n$d0 $th"}],
+
+ # From the examples in the documentation.
+ ['date2sec-0', "-d '1970-01-01 00:00:01' +%s", {OUT=>"7201"},
+ {ENV => 'TZ=UTC+2'}],
+
+ # Same as above, but don't rely on TZ in environment.
+ ['date2sec-0a', "-d '1970-01-01 00:00:01 UTC +2 hours' +%s",
+ {OUT=>"7201"}],
+
+ ['date2sec-1', "-d 2000-01-01 +%s", {OUT=>"946684800"}],
+ ['sec2date-0', "-d '1970-01-01 UTC 946684800 sec' +'%Y-%m-%d %T %z'",
+ {OUT=>"2000-01-01 00:00:00 +0000"}],
+
+ ['this-m', "-d '$d0 $t0 this minute' $fmt", {OUT=>"$d0 $t0"}],
+ ['this-h', "-d '$d0 $t0 this hour' $fmt", {OUT=>"$d0 $t0"}],
+ ['this-w', "-d '$d0 $t0 this week' $fmt", {OUT=>"$d0 $t0"}],
+ ['this-mo', "-d '$d0 $t0 this month' $fmt", {OUT=>"$d0 $t0"}],
+ ['this-y', "-d '$d0 $t0 this year' $fmt", {OUT=>"$d0 $t0"}],
+
+ ['risks-1', "-d 'Nov 10 1996' $fmt", {OUT=>"1996-11-10 00:00:00"}],
+
+ # This one would pass if TZ (with any, or even no, value) were in
+ # the environment.
+ ['regress-1', "-u -d '1996-11-10 0:00:00 +0' $fmt",
+ {OUT=>"1996-11-10 00:00:00"},
+ {ENV =>'LANG=C'}],
+
+
+ ['datevtime-1', "-d 000909 $fmt", {OUT=>"2000-09-09 00:00:00"}],
+
+ # test for RFC-822 conformance
+ ['rfc822-1', "-R -d '$d1'", {OUT=>"Sun, 19 Jan 1997 08:17:48 +0000"},
+ # Solaris 5.9's /bin/sh emits this diagnostic to stderr
+ # if you don't have support for the named locale.
+ {ERR_SUBST => q!s/^couldn't set locale correctly\n//!},
+ {ENV => 'LC_ALL=de_DE TZ=UTC0'}],
+
+ # Relative seconds, with time. fixed in 2.0j
+ ['relative-1', "--utc -d '1970-01-01 00:00:00 UTC +961062237 sec' $fmt",
+ {OUT=>"2000-06-15 09:43:57"}],
+
+ # Relative seconds, no time.
+ ['relative-2', "--utc -d '1970-01-01 UTC +961062237 sec' $fmt",
+ {OUT=>"2000-06-15 09:43:57"},
+ {ENV => 'TZ=UTC+1'}],
+
+ # Relative days, no time, across time zones.
+ ['relative-3', "-I -d '2006-04-23 21 days ago'", {OUT=>"2006-04-02"},
+ {ENV=>'TZ=PST8PDT,M4.1.0,M10.5.0'}],
+
+ # This would infloop (or appear to) prior to coreutils-4.5.5,
+ # due to a bug in strftime.c.
+ ['wide-fmt', "-d '1999-06-01'", '+%3004Y', {OUT=>'0' x 3000 . "1999"}],
+
+ # Ensure that we can parse MONTHNAME-DAY-YEAR.
+ ['moname-d-y', '--iso -d May-23-2003', {OUT=>"2003-05-23"}],
+ ['moname-d-y-r', '--rfc-3339=date -d May-23-2003', {OUT=>"2003-05-23"}],
+
+ ['epoch', '--iso=sec -d @31536000',
+ {OUT=>"1971-01-01T00:00:00+00:00"}],
+ ['epoch-r', '--rfc-3339=sec -d @31536000',
+ {OUT=>"1971-01-01 00:00:00+00:00"}],
+
+ ['ns-10', '--iso=ns', '-d "1969-12-31 13:00:00.00000001-1100"',
+ {OUT=>"1970-01-01T00:00:00,000000010+00:00"}],
+ ['ns-10-r', '--rfc-3339=ns', '-d "1969-12-31 13:00:00.00000001-1100"',
+ {OUT=>"1970-01-01 00:00:00.000000010+00:00"}],
+
+ ['ns-max32', '--iso=ns', '-d "2038-01-19 03:14:07.999999999"',
+ {OUT=>"2038-01-19T03:14:07,999999999+00:00"}],
+ ['ns-max32-r', '--rfc-3339=ns', '-d "2038-01-19 03:14:07.999999999"',
+ {OUT=>"2038-01-19 03:14:07.999999999+00:00"}],
+
+ ['tz-1', '+%:::z', {OUT=>"-12:34:56"}, {ENV=>'TZ=XXX12:34:56'}],
+
+ ['tz-2', '+%:::z', {OUT=>"+12:34:56"}, {ENV=>'TZ=XXX-12:34:56'}],
+
+ ['tz-3', '+%::z', {OUT=>"+01:02:03"}, {ENV=>'TZ=XXX-1:02:03'}],
+
+ ['tz-4', '+%:::z', {OUT=>"+12"}, {ENV=>'TZ=XXX-12'}],
+
+ ['tz-5', '+%:z', {OUT=>"-00:01"}, {ENV=>'TZ=XXX0:01'}],
+
+ # Accept %:z with a field width before the ':'.
+ ['tz-5w','+%8:z', {OUT=>"-0000:01"}, {ENV=>'TZ=XXX0:01'}],
+ # Don't recognize %:z with a field width between the ':' and the 'z'.
+ ['tz-5wf', '+%:8z', {OUT=>"%:8z"}, {ENV=>'TZ=XXX0:01'}],
+
+ # Test alphabetic timezone abbrv
+ ['tz-6', '+%Z', {OUT=>"UTC"}],
+ ['tz-7', '+%Z', {OUT=>"JST"}, {ENV=>'TZ=JST-9'}],
+
+ ['ns-relative',
+ '--iso=ns',
+ "-d'1970-01-01 00:00:00.1234567 UTC +961062237.987654321 sec'",
+ {OUT=>"2000-06-15T09:43:58,111111021+00:00"}],
+ ['ns-relativer', '--rfc-3339=ns',
+ "-d'1970-01-01 00:00:00.1234567 UTC +961062237.987654321 sec'",
+ {OUT=>"2000-06-15 09:43:58.111111021+00:00"}],
+
+ # Since coreutils/lib/getdate.y revision 1.96 (post-coreutils-5.3.0),
+ # a command like the following would mistakenly exit nonzero with an
+ # 'invalid date ...' diagnostic, but when run in a time zone for
+ # which daylight savings time is in effect for the starting date.
+ # Unfortunately (for ease of testing), if you set TZ at all, this
+ # failure is not triggered, hence the removal of TZ from the environment.
+ ['cross-dst', "-d'2005-03-27 +1 day'", '+%Y', {OUT=>"2005"},
+ {ENV_DEL => 'TZ'},
+ ],
+
+ ['empty-fmt', '+', {OUT=>""}],
+
+ ['neg-secs', '-d @-22 +%05s', {OUT=>"-0022"}],
+ ['neg-secs2', '-d @-22 +%_5s', {OUT=>" -22"}],
+
+ # FIXME: Ensure date doesn't print uninitialized data
+ # for an out-of-range date. This test is currently
+ # disabled as various systems have different limits
+ # for localtime(), and we can't use perl for example
+ # to determine those limits as it doesn't always call
+ # down to the system localtime() as it has configure
+ # time checks and settings itself for these limits.
+ #['uninit-64', "-d \@72057594037927935",
+ # {OUT=>''},
+ # # Use ERR_SUBST to get around fact that the diagnostic
+ # # you get on a system with 32-bit time_t is not the same as
+ # # the one you get for a system where it's 64 bits wide:
+ # # - date: time 72057594037927935 is out of range
+ # # + date: invalid date '@72057594037927935'
+ # {ERR_SUBST => 's/.*//'},
+ # {ERR => "\n"},
+ # {EXIT => 1},
+ #],
+
+ ['fill-1', '-d 1999-12-08 +%_3d', {OUT=>' 8'}],
+ ['fill-2', '-d 1999-12-08 +%03d', {OUT=>'008'}],
+
+ # Test the combination of the to-upper-case modifier (^) and a conversion
+ # specifier that expands to a string containing lower case characters.
+ ['subfmt-up1', '-d "1999-12-08 7:30" "+%^c"',
+ # Solaris 5.9 prints 'WED DEC 08 07:30:00 1999', while
+ # most others print 'WED DEC 8 07:30:00 1999'.
+ {OUT_SUBST => 's/ [ 0]8.*//'},
+ {OUT=>'WED DEC'}],
+
+ ['invalid-high-bit-set', "-d '\xb0'",
+ {ERR => "date: invalid date '\\260'\n"},
+ {EXIT => 1},
+ ],
+
+ # From coreutils-5.3.0 to 8.22 inclusive
+ # this would either infinite loop or crash
+ ['invalid-TZ-crash', "-d 'TZ=\"\"\"'",
+ {ERR => "date: invalid date 'TZ=\"\"\"'\n"},
+ {EXIT => 1},
+ ],
+
+ # https://bugs.debian.org/851934#10
+ ['cross-TZ-mishandled', "-d 'TZ=\"EST5\" 1970-01-01 00:00'",
+ {ENV => 'TZ=PST8'},
+ {OUT => 'Wed Dec 31 21:00:00 PST 1969'},
+ ],
+
+ # https://bugs.gnu.org/34608
+ ['date-century-plus', '-d @0 +.%+4C.', {OUT => '.+019.'}],
+
+ # https://bugs.gnu.org/50115
+ ['date-epoch-minus-1', '-u -d "1970-12-31T23:59:59+00:00 - 1 year"',
+ {OUT => 'Wed Dec 31 23:59:59 UTC 1969'}],
+
+ # Military time zones, new behavior (since 8.32)
+ # https://lists.gnu.org/r/bug-gnulib/2019-08/msg00005.html
+ ['mtz1', '-u -d "09:00B" +%T', {OUT => '07:00:00'}],
+ ['mtz2', '-u -d "09:00L" +%T', {OUT => '22:00:00'}],
+ ['mtz3', '-u -d "09:00N" +%T', {OUT => '10:00:00'}],
+ ['mtz4', '-u -d "09:00T" +%T', {OUT => '16:00:00'}],
+ ['mtz5', '-u -d "09:00X" +%T', {OUT => '20:00:00'}],
+ ['mtz6', '-u -d "09:00Z" +%T', {OUT => '09:00:00'}],
+
+ # test with %%-N
+ ['pct-pct', '+%%-N', {OUT => '%-N'}],
+ );
+
+# Repeat the cross-dst test, using Jan 1, 2005 and every interval from 1..364.
+foreach my $i (1..364)
+ {
+ push @Tests, ["cross-dst$i",
+ "-d'2005-01-01 +$i day'", '+%Y', {OUT=>"2005"},
+ {ENV_DEL => 'TZ'},
+ ];
+ }
+
+# Append "\n" to each OUT=> RHS if the expected exit value is either
+# zero or not specified (defaults to zero).
+foreach my $t (@Tests)
+ {
+ my $exit_val;
+ foreach my $e (@$t)
+ {
+ ref $e && ref $e eq 'HASH' && defined $e->{EXIT}
+ and $exit_val = $e->{EXIT};
+ }
+ foreach my $e (@$t)
+ {
+ ref $e && ref $e eq 'HASH' && defined $e->{OUT} && ! $exit_val
+ and $e->{OUT} .= "\n";
+ }
+ }
+
+# Repeat all tests with --debug option, ensure it does not cause any regression
+my @debug_tests;
+foreach my $t (@Tests)
+ {
+ # Skip tests with EXIT!=0 or ERR_SUBST part
+ # (as '--debug' requires its own ERR_SUBST).
+ my $exit_val;
+ my $have_err_subst;
+ foreach my $e (@$t)
+ {
+ next unless ref $e && ref $e eq 'HASH';
+ $exit_val = $e->{EXIT} if defined $e->{EXIT};
+ $have_err_subst = 1 if defined $e->{ERR_SUBST};
+ }
+ next if $exit_val || $have_err_subst;
+
+ # Duplicate the test, add '--debug' argument
+ my @newt = @$t;
+ $newt[0] = 'dbg_' . $newt[0];
+ $newt[1] = '--debug ' . $newt[1];
+
+ # Discard all debug printouts before comparing output
+ push @newt, {ERR_SUBST => q!s/^date: .*\n//m!};
+
+ push @debug_tests, \@newt;
+ }
+push @Tests, @debug_tests;
+
+
+my $save_temps = $ENV{DEBUG};
+my $verbose = $ENV{VERBOSE};
+
+my $prog = 'date';
+my $fail = run_tests ($ME, $prog, \@Tests, $save_temps, $verbose);
+exit $fail;
diff --git a/tests/dd/ascii.sh b/tests/dd/ascii.sh
new file mode 100755
index 0000000..ccf079f
--- /dev/null
+++ b/tests/dd/ascii.sh
@@ -0,0 +1,74 @@
+#!/bin/sh
+# test conv=ascii
+
+# Copyright (C) 2014-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ dd printf
+
+{
+ # Two lines, EBCDIC " A A" and " A ", followed by all the bytes in order.
+ env printf '\100\301\100\301\100\301\100\100' &&
+ env printf $(env printf '\\%03o' $(seq 0 255));
+} >in || framework_failure_
+
+{
+ # The converted lines, with trailing spaces removed.
+env printf \
+' A A\n A\n'\
+'\000\001\002\003\n\234\011\206\177\n'\
+'\227\215\216\013\n\014\015\016\017\n'\
+'\020\021\022\023\n\235\205\010\207\n'\
+'\030\031\222\217\n\034\035\036\037\n'\
+'\200\201\202\203\n\204\012\027\033\n'\
+'\210\211\212\213\n\214\005\006\007\n'\
+'\220\221\026\223\n\224\225\226\004\n'\
+'\230\231\232\233\n\024\025\236\032\n'\
+'\040\240\241\242\n\243\244\245\246\n'\
+'\247\250\325\056\n\074\050\053\174\n'\
+'\046\251\252\253\n\254\255\256\257\n'\
+'\260\261\041\044\n\052\051\073\176\n'\
+'\055\057\262\263\n\264\265\266\267\n'\
+'\270\271\313\054\n\045\137\076\077\n'\
+'\272\273\274\275\n\276\277\300\301\n'\
+'\302\140\072\043\n\100\047\075\042\n'\
+'\303\141\142\143\n\144\145\146\147\n'\
+'\150\151\304\305\n\306\307\310\311\n'\
+'\312\152\153\154\n\155\156\157\160\n'\
+'\161\162\136\314\n\315\316\317\320\n'\
+'\321\345\163\164\n\165\166\167\170\n'\
+'\171\172\322\323\n\324\133\326\327\n'\
+'\330\331\332\333\n\334\335\336\337\n'\
+'\340\341\342\343\n\344\135\346\347\n'\
+'\173\101\102\103\n\104\105\106\107\n'\
+'\110\111\350\351\n\352\353\354\355\n'\
+'\175\112\113\114\n\115\116\117\120\n'\
+'\121\122\356\357\n\360\361\362\363\n'\
+'\134\237\123\124\n\125\126\127\130\n'\
+'\131\132\364\365\n\366\367\370\371\n'\
+'\060\061\062\063\n\064\065\066\067\n'\
+'\070\071\372\373\n\374\375\376\377\n';
+} >exp || framework_failure_
+
+dd if=in of=out conv=ascii cbs=4 || fail=1
+
+compare exp out \
+ || { od -v -to1 exp > exp2 || framework_failure_;
+ od -v -to1 out > out2 || framework_failure_;
+ compare exp2 out2;
+ fail=1; }
+
+Exit $fail
diff --git a/tests/dd/bytes.sh b/tests/dd/bytes.sh
new file mode 100755
index 0000000..d6105cc
--- /dev/null
+++ b/tests/dd/bytes.sh
@@ -0,0 +1,75 @@
+#!/bin/sh
+
+# Copyright (C) 2012-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ dd
+
+echo 0123456789abcdefghijklm > in || framework_failure_
+
+# count bytes
+for operands in "count=14B" "count=14 iflag=count_bytes"; do
+ dd $operands conv=swab < in > out 2> /dev/null || fail=1
+ case $(cat out) in
+ 1032547698badc) ;;
+ *) fail=1 ;;
+ esac
+done
+
+for operands in "iseek=10B" "skip=10 iflag=skip_bytes"; do
+ # skip bytes
+ dd $operands < in > out 2> /dev/null || fail=1
+ case $(cat out) in
+ abcdefghijklm) ;;
+ *) fail=1 ;;
+ esac
+
+ # skip records and bytes from pipe
+ echo 0123456789abcdefghijklm |
+ dd $operands bs=2 > out 2> /dev/null || fail=1
+ case $(cat out) in
+ abcdefghijklm) ;;
+ *) fail=1 ;;
+ esac
+done
+
+truncate -s8 expected2
+printf '\0\0\0\0\0\0\0\0abcdefghijklm\n' > expected
+
+for operands in "oseek=8B" "seek=8 oflag=seek_bytes"; do
+ # seek bytes
+ echo abcdefghijklm |
+ dd $operands bs=5 > out 2> /dev/null || fail=1
+ compare expected out || fail=1
+
+ # Just truncation, no I/O
+ dd $operands bs=5 of=out2 count=0 2> /dev/null || fail=1
+ compare expected2 out2 || fail=1
+done
+
+# Check recursive integer parsing
+for oseek in '1x2x4 oflag=seek_bytes' '1Bx2x4' '1Bx8' '2Bx4B' '2x4B'; do
+ # seek bytes
+ echo abcdefghijklm |
+ dd oseek=$oseek bs=5 > out 2> /dev/null || fail=1
+ compare expected out || fail=1
+done
+
+# Negative checks for integer parsing
+for count in B B1 Bx1 KBB BB KBb KBx x1 1x 1xx1; do
+ returns_ 1 dd count=$count </dev/null >/dev/null || fail=1
+done
+Exit $fail
diff --git a/tests/dd/direct.sh b/tests/dd/direct.sh
new file mode 100755
index 0000000..720966b
--- /dev/null
+++ b/tests/dd/direct.sh
@@ -0,0 +1,35 @@
+#!/bin/sh
+# ensure that dd's iflag=direct and oflag=direct work
+
+# Copyright (C) 2009-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ dd
+
+truncate -s 8192 in || framework_failure_
+dd if=in oflag=direct of=out 2> /dev/null \
+ || skip_ '512 byte aligned O_DIRECT is not supported on this (file) system'
+
+truncate -s 511 short || framework_failure_
+truncate -s 8191 m1 || framework_failure_
+truncate -s 8193 p1 || framework_failure_
+
+for i in short m1 p1; do
+ rm -f out
+ dd if=$i iflag=direct oflag=direct of=out || fail=1
+done
+
+Exit $fail
diff --git a/tests/dd/misc.sh b/tests/dd/misc.sh
new file mode 100755
index 0000000..695a1ba
--- /dev/null
+++ b/tests/dd/misc.sh
@@ -0,0 +1,127 @@
+#!/bin/sh
+# Ensure dd treats '--' properly.
+# Also test some flag values.
+
+# Copyright (C) 1999-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ dd
+export LC_ALL=C
+
+tmp_in=dd-in
+tmp_in2=dd-in2
+tmp_sym=dd-sym
+tmp_out=dd-out
+
+warn=0
+echo data > $tmp_in || framework_failure_
+ln $tmp_in $tmp_in2 || framework_failure_
+ln -s $tmp_in $tmp_sym || framework_failure_
+
+# check status=none suppresses all output to stderr
+dd status=none if=$tmp_in of=/dev/null 2> err || fail=1
+compare /dev/null err || fail=1
+dd status=none if=$tmp_in skip=2 of=/dev/null 2> err || fail=1
+compare /dev/null err || fail=1
+# check later status=none overrides earlier status=noxfer
+dd status=noxfer status=none if=$tmp_in of=/dev/null 2> err || fail=1
+compare /dev/null err || fail=1
+# check later status=noxfer overrides earlier status=none
+dd status=none status=noxfer if=$tmp_in of=/dev/null 2> err || fail=1
+compare /dev/null err && fail=1
+
+dd if=$tmp_in of=$tmp_out 2> /dev/null || fail=1
+compare $tmp_in $tmp_out || fail=1
+
+rm $tmp_out
+dd -- if=$tmp_in of=$tmp_out 2> /dev/null || fail=1
+compare $tmp_in $tmp_out || fail=1
+
+if dd oflag=append if=$tmp_in of=$tmp_out 2> /dev/null; then
+ compare $tmp_in $tmp_out || fail=1
+fi
+
+case $(cat /dev/stdin <$tmp_in 2>/dev/null) in
+(data)
+ rm -f $tmp_out
+ dd if=/dev/stdin of=$tmp_out <$tmp_in || fail=1
+ compare $tmp_in $tmp_out || fail=1
+esac
+
+if dd iflag=nofollow if=$tmp_in count=0 2> /dev/null; then
+ returns_ 1 dd iflag=nofollow if=$tmp_sym count=0 2> /dev/null || fail=1
+fi
+
+if dd iflag=directory if=. count=0 2> /dev/null; then
+ dd iflag=directory count=0 <. 2> /dev/null || fail=1
+ returns_ 1 dd iflag=directory count=0 <$tmp_in 2> /dev/null || fail=1
+fi
+
+old_ls=$(ls -u --full-time $tmp_in)
+sleep 1
+if dd iflag=noatime if=$tmp_in of=$tmp_out 2> /dev/null; then
+ new_ls=$(ls -u --full-time $tmp_in)
+ if test "x$old_ls" != "x$new_ls"; then
+ cat >&2 <<EOF
+=================================================================
+$0: WARNING!!!
+This operating system has the O_NOATIME file status flag,
+but it is silently ignored in some cases.
+Therefore, dd options like iflag=noatime may be silently ignored.
+=================================================================
+EOF
+ warn=77
+ fi
+fi
+
+if dd oflag=nolinks if=$tmp_in of=$tmp_out 2> /dev/null; then
+ returns_ 1 dd iflag=nolinks if=$tmp_in > /dev/null 2>&1 || fail=1
+ returns_ 1 dd iflag=nolinks < $tmp_in > /dev/null 2>&1 || fail=1
+ dd oflag=nolinks < $tmp_in > $tmp_out 2>&1 || fail=1
+fi
+
+outbytes=$(echo x | dd bs=3 ibs=10 obs=10 conv=sync 2>/dev/null | wc -c)
+test "$outbytes" -eq 3 || fail=1
+
+# A delay is required to trigger a failure.
+# There might be some missed failures but it's unlikely.
+(echo a; sleep .1; echo b) \
+ | dd bs=4 status=noxfer iflag=fullblock >out 2>err || fail=1
+printf 'a\nb\n' > out_ok || framework_failure_
+echo "1+0 records in
+1+0 records out" > err_ok || framework_failure_
+compare out_ok out || fail=1
+compare err_ok err || fail=1
+
+test $fail -eq 0 && fail=$warn
+
+# Check a warning is issued for ambiguous 0x... numbers
+dd if=/dev/null count=0x1 seek=0x1 skip=0x1 status=none 2>err || fail=1
+cat <<\EOF >exp
+dd: warning: '0x' is a zero multiplier; use '00x' if that is intended
+dd: warning: '0x' is a zero multiplier; use '00x' if that is intended
+dd: warning: '0x' is a zero multiplier; use '00x' if that is intended
+EOF
+compare exp err || fail=1
+
+echo "0+0 records in
+0+0 records out" >err_ok || framework_failure_
+big=9999999999999999999999999999999999999999999999999999999999999
+dd if=$tmp_in of=$tmp_out count=00x$big status=noxfer 2>err || fail=1
+compare /dev/null $tmp_out || fail=1
+compare err_ok err || fail=1
+
+Exit $fail
diff --git a/tests/dd/no-allocate.sh b/tests/dd/no-allocate.sh
new file mode 100755
index 0000000..5328a4c
--- /dev/null
+++ b/tests/dd/no-allocate.sh
@@ -0,0 +1,76 @@
+#!/bin/sh
+# make sure that dd doesn't allocate memory unnecessarily
+
+# Copyright (C) 2013-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ dd
+
+# Determine basic amount of memory needed.
+echo . > f || framework_failure_
+vm=$(get_min_ulimit_v_ timeout 10 dd if=f of=f2 status=none) \
+ || skip_ "this shell lacks ulimit support"
+rm f f2 || framework_failure_
+
+# count and skip are zero, we don't need to allocate memory
+(ulimit -v $vm && dd bs=30M count=0) || fail=1
+(ulimit -v $vm && dd ibs=30M count=0) || fail=1
+(ulimit -v $vm && dd obs=30M count=0) || fail=1
+
+check_dd_seek_alloc() {
+ local file="$1"
+ local buf="$2"
+ test "$file" = 'in' && { dd_file=if; dd_op=skip; }
+ test "$file" = 'out' && { dd_file=of; dd_op=seek; }
+ test "$buf" = 'in' && { dd_buf=ibs; }
+ test "$buf" = 'out' && { dd_buf=obs; }
+ test "$buf" = 'both' && { dd_buf=bs; }
+
+ # Provide input to the "tape"
+ timeout 10 dd count=1 if=/dev/zero of=tape&
+
+ # Allocate buffer and read from the "tape"
+ (ulimit -v $vm \
+ && timeout 10 dd $dd_buf=30M $dd_op=1 count=0 $dd_file=tape)
+ local ret=$?
+
+ # Be defensive in case the tape reader is blocked for some reason
+ test $ret = 124 && framework_failure_
+
+ # This should happen without delay,
+ # and is used to ensure we've not multiple writers to the "tape"
+ wait
+
+ # We want the "tape" reader to fail iff allocating
+ # a large buffer corresponding to the file being read
+ case "$file$buf" in
+ inout|outin) test $ret = 0;;
+ *) test $ret != 0;;
+ esac
+}
+
+# Use a fifo for which seek fails, but read does not.
+# For non seekable output we need to allocate a buffer
+# when simulating seeking with a read.
+if mkfifo tape; then
+ for file in 'in' 'out'; do
+ for buf in 'both' 'in' 'out'; do
+ check_dd_seek_alloc "$file" "$buf" || fail=1
+ done
+ done
+fi
+
+Exit $fail
diff --git a/tests/dd/nocache.sh b/tests/dd/nocache.sh
new file mode 100755
index 0000000..029db66
--- /dev/null
+++ b/tests/dd/nocache.sh
@@ -0,0 +1,58 @@
+#!/bin/sh
+# Ensure dd handles the 'nocache' flag
+
+# Copyright (C) 2011-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ dd
+
+# This should not call posix_fadvise
+dd iflag=nocache oflag=nocache if=/dev/null of=/dev/null || fail=1
+
+# We should get an error for trying to process a pipe
+dd count=0 | returns_ 1 dd iflag=nocache count=0 || fail=1
+
+# O_DIRECT is orthogonal to drop cache so mutually exclusive
+returns_ 1 dd iflag=nocache,direct if=/dev/null || fail=1
+
+# The rest ensure that the documented uses cases
+# proceed without error
+for f in ifile ofile; do
+ dd if=/dev/zero of=$f conv=fdatasync count=100 || framework_failure_
+done
+
+# Advise to drop cache for whole file
+if ! dd if=ifile iflag=nocache count=0 2>err; then
+ # We could check for 'Operation not supported' in err here,
+ # but that was seen to be brittle. HPUX returns ENOTTY for example.
+ # So assume that if this basic operation fails, it's due to lack
+ # of support by the system.
+ warn_ 'skipping part; this file system lacks support for posix_fadvise()'
+ skip=1
+fi
+
+if test "$skip" != 1; then
+ # Ensure drop cache for whole file
+ dd of=ofile oflag=nocache conv=notrunc,fdatasync count=0 || fail=1
+
+ # Drop cache for part of file
+ dd if=ifile iflag=nocache skip=10 count=10 of=/dev/null || fail=1
+
+ # Stream data just using readahead cache
+ dd if=ifile of=ofile iflag=nocache oflag=nocache || fail=1
+fi
+
+Exit $fail
diff --git a/tests/dd/nocache_eof.sh b/tests/dd/nocache_eof.sh
new file mode 100755
index 0000000..ca36032
--- /dev/null
+++ b/tests/dd/nocache_eof.sh
@@ -0,0 +1,97 @@
+#!/bin/sh
+# Ensure dd invalidates to EOF when appropriate
+
+# Copyright (C) 2017-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ dd
+require_strace_ fadvise64,fadvise64_64
+
+head -c1234567 /dev/zero > in.f || framework_failure_
+
+# Check basic operation or skip.
+# We could check for 'Operation not supported' error here,
+# but that was seen to be brittle. HPUX returns ENOTTY for example.
+# So assume that if this basic operation fails, it's due to lack
+# of support by the system.
+dd if=in.f iflag=nocache count=0 ||
+ skip_ 'this file system lacks support for posix_fadvise()'
+
+strace_dd() {
+ strace -o dd.strace -e fadvise64,fadvise64_64 dd status=none "$@" || fail=1
+}
+
+advised_to_eof() {
+ grep -F ' 0, POSIX_FADV_DONTNEED' dd.strace >/dev/null
+}
+
+# The commented fadvise64 calls are what are expected with
+# a 4KiB page size and 128KiB IO_BUFSIZE.
+
+strace_dd if=in.f of=out.f bs=1M oflag=nocache,sync
+#fadvise64(1, 0, 1048576, POSIX_FADV_DONTNEED) = 0
+#fadvise64(1, 1048576, 131072, POSIX_FADV_DONTNEED) = 0
+#fadvise64(1, 1179648, 0, POSIX_FADV_DONTNEED) = 0
+advised_to_eof || fail=1
+
+strace_dd if=in.f count=0 iflag=nocache
+#fadvise64(0, 0, 0, POSIX_FADV_DONTNEED) = 0
+advised_to_eof || fail=1
+
+strace_dd if=in.f of=/dev/null iflag=nocache skip=10 count=300
+#fadvise64(0, 5120, 131072, POSIX_FADV_DONTNEED) = 0
+#fadvise64(0, 136192, 22528, POSIX_FADV_DONTNEED) = 0
+returns_ 1 advised_to_eof || fail=1
+
+strace_dd if=in.f of=/dev/null iflag=nocache bs=1M count=3000
+#fadvise64(0, 0, 1048576, POSIX_FADV_DONTNEED) = 0
+#fadvise64(0, 1048576, 131072, POSIX_FADV_DONTNEED) = 0
+#fadvise64(0, 1179648, 0, POSIX_FADV_DONTNEED) = 0
+advised_to_eof || fail=1
+
+strace_dd if=in.f of=/dev/null bs=1M count=1 iflag=nocache
+#fadvise64(0, 0, 1048576, POSIX_FADV_DONTNEED) = 0
+returns_ 1 advised_to_eof || fail=1
+
+strace_dd if=in.f of=out.f bs=1M iflag=nocache oflag=nocache,sync
+#fadvise64(0, 0, 1048576, POSIX_FADV_DONTNEED) = 0
+#fadvise64(1, 0, 1048576, POSIX_FADV_DONTNEED) = 0
+#fadvise64(0, 1048576, 131072, POSIX_FADV_DONTNEED) = 0
+#fadvise64(1, 1048576, 131072, POSIX_FADV_DONTNEED) = 0
+#fadvise64(0, 1179648, 0, POSIX_FADV_DONTNEED) = 0
+#fadvise64(1, 1179648, 0, POSIX_FADV_DONTNEED) = 0
+advised_to_eof || fail=1
+
+# Ensure sub page size offsets are handled.
+# I.e., only page aligned offsets are sent to fadvise.
+if ! strace -o dd.strace -e fadvise64,fadvise64_64 dd status=none \
+ if=in.f of=out.f bs=1M oflag=direct oseek=512B; then
+ warn_ '512 byte aligned O_DIRECT is not supported on this (file) system'
+ # The current file system may not support O_DIRECT,
+ # or older XFS had a page size alignment requirement
+else
+ #The first call is redundant but inconsequential
+ #fadvise64(1, 1048576, 0, POSIX_FADV_DONTNEED) = 0
+ #fadvise64(1, 1048576, 0, POSIX_FADV_DONTNEED) = 0
+ advised_to_eof || fail=1
+
+ strace_dd if=in.f of=out.f bs=1M oflag=direct
+ #fadvise64(1, 1048576, 0, POSIX_FADV_DONTNEED) = 0
+ #fadvise64(1, 1048576, 0, POSIX_FADV_DONTNEED) = 0
+ advised_to_eof || fail=1
+fi
+
+Exit $fail
diff --git a/tests/dd/not-rewound.sh b/tests/dd/not-rewound.sh
new file mode 100755
index 0000000..278e6ca
--- /dev/null
+++ b/tests/dd/not-rewound.sh
@@ -0,0 +1,31 @@
+#!/bin/sh
+# Make sure dd does the right thing when the input file descriptor
+# is not rewound.
+
+# Copyright (C) 2000-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ dd
+
+
+echo abcde > in
+(dd skip=1 count=1 bs=1; dd skip=1 bs=1) < in > out 2> /dev/null || fail=1
+case $(cat out) in
+ bde) ;;
+ *) fail=1 ;;
+esac
+
+Exit $fail
diff --git a/tests/dd/reblock.sh b/tests/dd/reblock.sh
new file mode 100755
index 0000000..125f0d4
--- /dev/null
+++ b/tests/dd/reblock.sh
@@ -0,0 +1,72 @@
+#!/bin/sh
+# test dd reblocking vs. bs=
+
+# Copyright (C) 2008-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ dd
+
+# 2 short reads -> 1 full write + 1 partial write
+cat <<\EOF > exp-reblock || framework_failure_
+0+2 records in
+1+1 records out
+4 bytes copied
+EOF
+
+# 2 short reads -> 2 partial writes
+cat <<\EOF > exp-no-reblock || framework_failure_
+0+2 records in
+0+2 records out
+4 bytes copied
+EOF
+
+
+# Use a fifo rather than a pipe in the tests below
+# so that the producer (printf subshell) will wait
+# until the consumer (dd) opens the fifo therefore
+# increasing the chance that dd will read the data
+# from each printf separately.
+mkfifo_or_skip_ dd.fifo
+
+dd_reblock_1()
+{
+ local delay="$1"
+
+ # ensure that dd reblocks when bs= is not specified
+ dd ibs=3 obs=3 if=dd.fifo > out 2> err&
+ (printf 'ab'; sleep $delay; printf 'cd') > dd.fifo
+ wait #for dd to complete
+ sed 's/,.*//' err > k && mv k err
+ compare exp-reblock err
+}
+
+retry_delay_ dd_reblock_1 .1 6 || fail=1
+
+dd_reblock_2()
+{
+ local delay="$1"
+
+ # Demonstrate that bs=N supersedes even following ibs= and obs= settings.
+ dd bs=3 ibs=1 obs=1 if=dd.fifo > out 2> err&
+ (printf 'ab'; sleep $delay; printf 'cd') > dd.fifo
+ wait #for dd to complete
+ sed 's/,.*//' err > k && mv k err
+ compare exp-no-reblock err
+}
+
+retry_delay_ dd_reblock_2 .1 6 || fail=1
+
+Exit $fail
diff --git a/tests/dd/skip-seek-past-dev.sh b/tests/dd/skip-seek-past-dev.sh
new file mode 100755
index 0000000..6e92df3
--- /dev/null
+++ b/tests/dd/skip-seek-past-dev.sh
@@ -0,0 +1,58 @@
+#!/bin/sh
+# test diagnostics are printed immediately when seeking beyond device.
+
+# Copyright (C) 2008-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ dd
+
+# need write access to local device
+# (even though we don't actually write anything)
+require_root_
+require_local_dir_
+
+get_device_size() {
+ BLOCKDEV=blockdev
+ $BLOCKDEV -V >/dev/null 2>&1 || BLOCKDEV=/sbin/blockdev
+ $BLOCKDEV --getsize64 "$1"
+}
+
+
+# Get path to device the current dir is on.
+# Note df can only get fs size, not device size.
+device=$(df --output=source . | tail -n1) || framework_failure_
+
+dev_size=$(get_device_size "$device") ||
+ skip_ "failed to determine size of $device"
+
+# Don't use shell arithmetic as older versions of dash use longs
+DEV_OFLOW=$(expr $dev_size + 1) || framework_failure_
+
+timeout 10 dd bs=1 skip=$DEV_OFLOW count=0 status=noxfer < "$device" 2> err
+test "$?" = "1" || fail=1
+echo "dd: 'standard input': cannot skip: Invalid argument
+0+0 records in
+0+0 records out" > err_ok || framework_failure_
+compare err_ok err || fail=1
+
+timeout 10 dd bs=1 seek=$DEV_OFLOW count=0 status=noxfer > "$device" 2> err
+test "$?" = "1" || fail=1
+echo "dd: 'standard output': cannot seek: Invalid argument
+0+0 records in
+0+0 records out" > err_ok || framework_failure_
+compare err_ok err || fail=1
+
+Exit $fail
diff --git a/tests/dd/skip-seek-past-file.sh b/tests/dd/skip-seek-past-file.sh
new file mode 100755
index 0000000..943057c
--- /dev/null
+++ b/tests/dd/skip-seek-past-file.sh
@@ -0,0 +1,92 @@
+#!/bin/sh
+# test diagnostics are printed when seeking too far in seekable files.
+
+# Copyright (C) 2008-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ dd
+require_sparse_support_ # for 'truncate --size=$OFF_T_MAX'
+eval $(getlimits) # for OFF_T limits
+export LC_ALL=C
+
+printf "1234" > file || framework_failure_
+
+echo "\
+dd: 'standard input': cannot skip to specified offset
+0+0 records in
+0+0 records out" > skip_err || framework_failure_
+
+# skipping beyond number of blocks in file should issue a warning
+dd bs=1 skip=5 count=0 status=noxfer < file 2> err || fail=1
+compare skip_err err || fail=1
+
+# skipping beyond number of bytes in file should issue a warning
+dd bs=3 skip=2 count=0 status=noxfer < file 2> err || fail=1
+compare skip_err err || fail=1
+
+# skipping beyond number of blocks in pipe should issue a warning
+cat file | dd bs=1 skip=5 count=0 status=noxfer 2> err || fail=1
+compare skip_err err || fail=1
+
+# skipping beyond number of bytes in pipe should issue a warning
+cat file | dd bs=3 skip=2 count=0 status=noxfer 2> err || fail=1
+compare skip_err err || fail=1
+
+# Check seeking beyond file already offset into
+# skipping beyond number of blocks in file should issue a warning
+(dd bs=1 skip=1 count=0 2>/dev/null &&
+ dd bs=1 skip=4 status=noxfer 2> err) < file || fail=1
+compare skip_err err || fail=1
+
+# Check seeking beyond file already offset into
+# skipping beyond number of bytes in file should issue a warning
+(dd bs=1 skip=1 count=0 2>/dev/null &&
+ dd bs=2 skip=2 status=noxfer 2> err) < file || fail=1
+compare skip_err err || fail=1
+
+# seeking beyond end of file is OK
+dd bs=1 seek=5 count=0 status=noxfer > file 2> err || fail=1
+echo "0+0 records in
+0+0 records out" > err_ok || framework_failure_
+compare err_ok err || fail=1
+
+# skipping > OFF_T_MAX should fail immediately
+dd bs=1 skip=$OFF_T_OFLOW count=0 status=noxfer < file 2> err && fail=1
+# error message should be "... invalid number: strerror(EOVERFLOW)"
+grep "invalid number:" err >/dev/null || fail=1
+dd bs=1 skip=${OFF_T_OFLOW}x$OFF_T_OFLOW count=0 status=noxfer < file 2> err &&
+ fail=1
+grep "invalid number:" err >/dev/null || fail=1
+
+# skipping > max file size should fail immediately
+if ! truncate --size=$OFF_T_MAX in 2>/dev/null; then
+ # truncate is to ensure file system doesn't actually support OFF_T_MAX files
+ dd bs=1 skip=$OFF_T_MAX count=0 status=noxfer < file 2> err \
+ && lseek_ok=yes \
+ || lseek_ok=no
+
+ if test $lseek_ok = yes; then
+ # On Solaris 10 at least, lseek(>max file size) succeeds,
+ # so just check for the skip warning.
+ compare skip_err err || fail=1
+ else
+ # On Linux kernels at least, lseek(>max file size) fails.
+ # error message should be "... cannot skip: strerror(EINVAL)"
+ grep "cannot skip:" err >/dev/null || fail=1
+ fi
+fi
+
+Exit $fail
diff --git a/tests/dd/skip-seek.pl b/tests/dd/skip-seek.pl
new file mode 100755
index 0000000..d53daf0
--- /dev/null
+++ b/tests/dd/skip-seek.pl
@@ -0,0 +1,88 @@
+#!/usr/bin/perl
+# Test dd's skip and seek options.
+
+# Copyright (C) 2000-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+use strict;
+
+(my $program_name = $0) =~ s|.*/||;
+
+# Turn off localization of executable's output.
+@ENV{qw(LANGUAGE LANG LC_ALL)} = ('C') x 3;
+my $out = 'out';
+
+my @Tests =
+ (
+ [
+ 'sk-seek1',
+ qw (bs=1 skip=1 seek=2 conv=notrunc count=3 status=noxfer of=@AUX@ < ),
+ {IN=> '0123456789abcdef'},
+ {AUX=> 'zyxwvutsrqponmlkji'},
+ {OUT=> ''},
+ {ERR=> "3+0 records in\n3+0 records out\n"},
+ {CMP=> ['zy123utsrqponmlkji', {'@AUX@'=> undef}]},
+ ],
+ [
+ 'sk-seek2',
+ qw (bs=5 skip=1 seek=1 conv=notrunc count=1 status=noxfer of=@AUX@ < ),
+ {IN=> '0123456789abcdef'},
+ {AUX=> 'zyxwvutsrqponmlkji'},
+ {OUT=> ''},
+ {ERR=> "1+0 records in\n1+0 records out\n"},
+ {CMP=> ['zyxwv56789ponmlkji', {'@AUX@'=> undef}]},
+ ],
+ [
+ 'sk-seek3',
+ qw (bs=5 skip=1 seek=1 count=1 status=noxfer of=@AUX@ < ),
+ {IN=> '0123456789abcdef'},
+ {AUX=> 'zyxwvutsrqponmlkji'},
+ {OUT=> ''},
+ {ERR=> "1+0 records in\n1+0 records out\n"},
+ {CMP=> ['zyxwv56789', {'@AUX@'=> undef}]},
+ ],
+ [
+ # Before fileutils-4.0.45, the last 10 bytes of output
+ # were these "\0\0\0\0\0\0\0\0 ".
+ 'block-sync-1', qw(ibs=10 cbs=10 status=noxfer), 'conv=block,sync', '<',
+ {IN=> "01234567\nabcdefghijkl\n"},
+ {OUT=> "01234567 abcdefghij "},
+ {ERR=> "2+1 records in\n0+1 records out\n1 truncated record\n"},
+ ],
+ [
+ # Before coreutils-5.93, this would output just "c\n".
+ 'sk-seek4', qw(bs=1 skip=1 status=noxfer),
+ {IN_PIPE=> "abc\n"},
+ {OUT=> "bc\n"},
+ {ERR=> "3+0 records in\n3+0 records out\n"},
+ ],
+ [
+ # Check that iseek and oseek aliases work too.
+ 'sk-seek5',
+ qw (bs=1 iseek=1 oseek=2 conv=notrunc count=3 status=noxfer of=@AUX@ < ),
+ {IN=> '0123456789abcdef'},
+ {AUX=> 'zyxwvutsrqponmlkji'},
+ {OUT=> ''},
+ {ERR=> "3+0 records in\n3+0 records out\n"},
+ {CMP=> ['zy123utsrqponmlkji', {'@AUX@'=> undef}]},
+ ],
+ );
+
+my $save_temps = $ENV{DEBUG};
+my $verbose = $ENV{VERBOSE};
+
+my $prog = 'dd';
+my $fail = run_tests ($program_name, $prog, \@Tests, $save_temps, $verbose);
+exit $fail;
diff --git a/tests/dd/skip-seek2.sh b/tests/dd/skip-seek2.sh
new file mode 100755
index 0000000..5abdb4c
--- /dev/null
+++ b/tests/dd/skip-seek2.sh
@@ -0,0 +1,38 @@
+#!/bin/sh
+# show how to skip an amount that is smaller than the nominal block size.
+# There's a more realistic example in the documentation.
+
+# Copyright (C) 2000-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ dd
+
+
+echo LA:3456789abcdef > in || framework_failure_
+(dd bs=1 skip=3 count=0 && dd bs=5) < in > out 2> /dev/null || fail=1
+case $(cat out) in
+ 3456789abcdef) ;;
+ *) fail=1 ;;
+esac
+
+echo LA:3456789abcdef > in || framework_failure_
+(dd bs=1 skip=3 count=0 && dd bs=5 count=2) < in > out 2> /dev/null || fail=1
+case $(cat out) in
+ 3456789abc) ;;
+ *) fail=1 ;;
+esac
+
+Exit $fail
diff --git a/tests/dd/sparse.sh b/tests/dd/sparse.sh
new file mode 100755
index 0000000..c459f4d
--- /dev/null
+++ b/tests/dd/sparse.sh
@@ -0,0 +1,93 @@
+#!/bin/sh
+
+# Copyright (C) 2012-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ dd
+is_local_dir_ . || very_expensive_
+require_sparse_support_
+
+# Ensure basic sparse generation works
+truncate -s1M sparse
+dd bs=32K if=sparse of=sparse.dd conv=sparse
+test $(stat -c %s sparse) = $(stat -c %s sparse.dd) || fail=1
+
+# Demonstrate that conv=sparse with oflag=append,
+# will do ineffective seeks in the output
+printf 'a\000\000b' > file.in
+printf 'ab' > exp
+dd if=file.in bs=1 conv=sparse oflag=append > out
+compare exp out || fail=1
+
+# Demonstrate conv=sparse with conv=notrunc,
+# where data in file.out is not overwritten with NULs
+printf '____' > out
+printf 'a__b' > exp
+dd if=file.in bs=1 conv=sparse,notrunc of=out
+compare exp out || fail=1
+
+# Ensure we fall back to write if seek fails
+dd if=file.in bs=1 conv=sparse | cat > file.out
+cmp file.in file.out || fail=1
+
+# Setup for block size tests: create a 3MiB file with a 1MiB
+# stretch of NUL bytes in the middle.
+rm -f file.in
+dd if=/dev/urandom of=file.in bs=1M count=3 iflag=fullblock || fail=1
+dd if=/dev/zero of=file.in bs=1M count=1 seek=1 conv=notrunc || fail=1
+
+kb_alloc() { du -k "$1"|cut -f1; }
+
+# sync out data for async allocators like NFS/BTRFS
+# sync file.in || fail=1
+
+# If our just-created input file appears to be too small,
+# skip the remaining tests. On at least Solaris 10 with NFS,
+# file.in is reported to occupy <= 1KiB for about 50 seconds
+# after its creation.
+if test $(kb_alloc file.in) -gt 3000; then
+
+ # Ensure NUL blocks smaller than the *output* block size are not made sparse.
+ # Here, with a 2MiB block size, dd's conv=sparse must *not* introduce a hole.
+ dd if=file.in of=file.out ibs=1M obs=2M conv=sparse || fail=1
+
+ # Intermittently BTRFS returns 0 allocation for file.out unless synced
+ sync file.out || framework_failure_
+ test 2500 -lt $(kb_alloc file.out) || fail=1
+
+ # Note we recreate a sparse file first to avoid
+ # speculative preallocation seen in XFS, where a write() that
+ # extends a file can preallocate some extra space that
+ # a subsequent seek will not convert to a hole.
+ rm -f file.out
+ truncate --size=3M file.out
+
+ # Ensure that this 1MiB *output* block of NULs *is* converted to a hole.
+ dd if=file.in of=file.out ibs=2M obs=1M conv=sparse,notrunc
+ if test $(kb_alloc file.out) -ge 2500; then
+ # Double check the failure by creating a sparse file in
+ # the traditional manner for comparison, as we're not guaranteed
+ # that seek=1M will create a hole. apfs on darwin 19.2.0 for example
+ # was seen to not to create holes < 16MiB.
+ dd if=file.in of=manual.out bs=1M count=1 || fail=1
+ dd if=file.in of=manual.out bs=1M count=1 seek=2 conv=notrunc || fail=1
+
+ test $(kb_alloc file.out) -eq $(kb_alloc manual.out) || fail=1
+ fi
+
+fi
+
+Exit $fail
diff --git a/tests/dd/stats.sh b/tests/dd/stats.sh
new file mode 100755
index 0000000..d486e71
--- /dev/null
+++ b/tests/dd/stats.sh
@@ -0,0 +1,76 @@
+#!/bin/sh
+# Check stats output for SIG{INFO,USR1} and status=progress
+
+# Copyright (C) 2014-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ dd
+require_trap_signame_
+
+kill -l | grep 'INFO' && SIGINFO='INFO' || SIGINFO='USR1'
+
+# This to avoid races in the USR1 case
+# as the dd process will terminate by default until
+# it has its handler enabled.
+trap '' $SIGINFO
+
+mkfifo_or_skip_ fifo
+
+# Terminate any background processes
+cleanup_()
+{
+ kill $pid 2>/dev/null
+ kill $pid2 2>/dev/null
+ wait
+}
+
+for open in '' '1'; do
+ > err || framework_failure_
+
+ # Run dd with the fullblock iflag to avoid short reads
+ # which can be triggered by reception of signals
+ dd iflag=fullblock if=/dev/zero of=fifo count=50 bs=5000000 2>err & pid=$!
+
+ # Note if we sleep here we give dd a chance to exec and block on open.
+ # Otherwise we're probably testing SIG_IGN in the forked shell or early dd.
+ test "$open" && sleep .1
+
+ # dd will block on open until fifo is opened for reading.
+ # Timeout in case dd goes away erroneously which we check for below.
+ timeout 60 sh -c 'wc -c < fifo > nwritten' & pid2=$!
+
+ # Send lots of signals immediately to ensure dd not killed due
+ # to race setting handler, or blocking on open of fifo.
+ # Many signals also check that short reads are handled.
+ until ! kill -s $SIGINFO $pid 2>/dev/null; do
+ sleep .01
+ done
+
+ wait
+
+ # Ensure all data processed and at least last status written
+ grep '250000000 bytes (250 MB, 238 MiB) copied' err || { cat err; fail=1; }
+done
+
+progress_output()
+{
+ { sleep $1; echo 1; } | dd bs=1 status=progress of=/dev/null 2>err
+ # Progress output should be for "byte copied", while final is "bytes ..."
+ grep 'byte copied' err
+}
+retry_delay_ progress_output 1 4 || { cat err; fail=1; }
+
+Exit $fail
diff --git a/tests/dd/stderr.sh b/tests/dd/stderr.sh
new file mode 100755
index 0000000..e117708
--- /dev/null
+++ b/tests/dd/stderr.sh
@@ -0,0 +1,43 @@
+#!/bin/sh
+# Ensure dd recognizes failure to write to stderr.
+
+# Copyright (C) 2009-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ dd
+
+p=$abs_top_builddir
+
+
+# Ensure this exits successfully, even though stderr is closed,
+# because it generates no stderr output.
+dd --help >/dev/null 2>&- || fail=1
+
+# If 2>&- works, ensure this fails, because stderr is closed and it
+# *does* generate output. 2>&- apparently does not work in HP-UX 11.23.
+# This test is ineffective unless /dev/stderr also works.
+# This exposes a failure present in 6.11 through 7.5.
+if "$p/src/test" -w /dev/stderr 2>/dev/null &&
+ "$p/src/test" ! -w /dev/stderr 2>&-; then
+ : | returns_ 1 dd 2>&- || fail=1
+fi
+
+# Likewise for /dev/full, if /dev/full works.
+if test -w /dev/full && test -c /dev/full; then
+ : | returns_ 1 dd 2>/dev/full || fail=1
+fi
+
+Exit $fail
diff --git a/tests/dd/unblock-sync.sh b/tests/dd/unblock-sync.sh
new file mode 100755
index 0000000..323416d
--- /dev/null
+++ b/tests/dd/unblock-sync.sh
@@ -0,0 +1,35 @@
+#!/bin/sh
+# Ensure that dd conv=unblock,sync works.
+
+# Copyright (C) 2003-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ dd
+
+printf 000100020003xx > in || framework_failure_
+
+
+dd cbs=4 ibs=4 conv=unblock,sync < in > out 2> /dev/null || fail=1
+cat <<\EOF > exp || framework_failure_
+0001
+0002
+0003
+xx
+EOF
+
+compare exp out || fail=1
+
+Exit $fail
diff --git a/tests/dd/unblock.pl b/tests/dd/unblock.pl
new file mode 100755
index 0000000..0e7bcc6
--- /dev/null
+++ b/tests/dd/unblock.pl
@@ -0,0 +1,59 @@
+#!/usr/bin/perl
+# Exercise dd's conv=unblock mode
+
+# Copyright (C) 2009-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+use strict;
+
+(my $program_name = $0) =~ s|.*/||;
+
+# Turn off localization of executable's output.
+@ENV{qw(LANGUAGE LANG LC_ALL)} = ('C') x 3;
+my $out = 'out';
+
+my @t =
+ (
+ # An empty test name signals that these are the arguments to use for the
+ # following tests.
+ ['', [qw (cbs=3 conv=unblock status=noxfer < )]],
+ ['0', '', ''],
+ ['1', "a\n ", "a\n\n\n"],
+ ['2', "a\n ", "a\n\n"],
+ ['3', "a ", "a\n"],
+ ['4', "a \n ", "a \n\n\n"],
+ ['5', "a \n", "a \n\n"],
+ ['6', "a ", "a\n\n"],
+ ['7', "a \n", "a\n\n\n"],
+ );
+
+my @Tests;
+my $args;
+foreach my $t (@t)
+ {
+ $t->[0] eq ''
+ and $args = $t->[1], next;
+
+ push @Tests, [$t->[0], @$args, {IN=>$t->[1]}, {OUT=>$t->[2]},
+ {ERR_SUBST=>'s/^\d+\+\d+ records (?:in|out)$//'},
+ {ERR=>"\n\n"}];
+ }
+
+my $save_temps = $ENV{DEBUG};
+my $verbose = $ENV{VERBOSE};
+
+my $prog = 'dd';
+my $fail = run_tests ($program_name, $prog, \@Tests, $save_temps, $verbose);
+exit $fail;
diff --git a/tests/df/df-P.sh b/tests/df/df-P.sh
new file mode 100755
index 0000000..f51942c
--- /dev/null
+++ b/tests/df/df-P.sh
@@ -0,0 +1,37 @@
+#!/bin/sh
+# Ensure that df -P is not affected by BLOCK_SIZE settings
+
+# Copyright (C) 2007-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ df
+
+
+ df -P . > t1 || fail=1
+BLOCK_SIZE=1M df -P . > t2 || fail=1
+
+# Since file system utilization may be changing, compare only df's header line.
+# That records the block size. E.g., for "1M", it would be:
+# Filesystem 1048576-blocks Used Available Capacity Mounted on
+# while for 1K, it would be
+# Filesystem 1024-blocks Used Available Capacity Mounted on
+
+head -n1 t1 > exp || fail=1
+head -n1 t2 > out || fail=1
+
+compare exp out || fail=1
+
+Exit $fail
diff --git a/tests/df/df-output.sh b/tests/df/df-output.sh
new file mode 100755
index 0000000..6ec6019
--- /dev/null
+++ b/tests/df/df-output.sh
@@ -0,0 +1,140 @@
+#!/bin/sh
+# Exercise df's --output option.
+
+# Copyright (C) 2012-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ df
+
+# Ensure that --output is mutually exclusive with -i, -P, and -T.
+# Ensure that this limitation is not depending on the order of options.
+cat <<\EOF > exp || framework_failure_
+df: options OPT and --output are mutually exclusive
+Try 'df --help' for more information.
+EOF
+
+df -i --output '.' 2>out && fail=1
+sed 's/ -i / OPT /' out > out2
+compare exp out2 || fail=1
+
+df --output -i '.' 2>out && fail=1
+sed 's/ -i / OPT /' out > out2
+compare exp out2 || fail=1
+
+df -P --output '.' 2>out && fail=1
+sed 's/ -P / OPT /' out > out2
+compare exp out2 || fail=1
+
+df --output -P '.' 2>out && fail=1
+sed 's/ -P / OPT /' out > out2
+compare exp out2 || fail=1
+
+df -T --output '.' 2>out && fail=1
+sed 's/ -T / OPT /' out > out2
+compare exp out2 || fail=1
+
+df --output -T '.' 2>out && fail=1
+sed 's/ -T / OPT /' out > out2
+compare exp out2 || fail=1
+
+# Ensure that each field is only used once for the --output argument.
+cat <<\EOF > exp || framework_failure_
+df: option --output: field 'target' used more than once
+Try 'df --help' for more information.
+EOF
+
+df --output=target,source,target '.' 2>out && fail=1
+compare exp out || fail=1
+
+# Ensure that this limitation also works for split --output options.
+df --out=target,source --out=target '.' 2>out && fail=1
+compare exp out || fail=1
+
+# Ensure that the full output includes all fields, and
+# that --o (without argument) is identical to the full list.
+
+cat <<\EOF > exp || framework_failure_
+Filesystem Type Inodes IUsed IFree IUse% Size Used Avail Use% File Mounted on
+EOF
+
+df -h --o=source,fstype,itotal,iused,iavail,ipcent \
+ --o=size,used,avail,pcent,file,target '.' >out || fail=1
+sed -e '1 {
+ s/ [ ]*/ /g
+ q
+ }' out > out2
+compare exp out2 || fail=1
+
+df -h --output '.' >out || fail=1
+sed -e '1 {
+ s/ [ ]*/ /g
+ q
+ }' out > out2
+compare exp out2 || fail=1
+
+# Ensure that --output indicates the block size
+# when not using --human-readable
+cat <<\EOF > exp || framework_failure_
+1K-blocks
+EOF
+
+df -B1K --output=size '.' >out || fail=1
+sed -e '1 {
+ s/ *//
+ q
+ }' out > out2
+compare exp out2 || fail=1
+
+# Ensure that the grand total line now contains a "-" in the TARGET field ...
+cat <<\EOF > exp || framework_failure_
+-
+EOF
+
+df --output=source,target --total '.' >out || fail=1
+sed -n -e '3 {
+ s/^total[ ]*//
+ p
+ q
+ }' out > out2
+compare exp out2 || fail=1
+
+# ... but it should read "total" if there is no SOURCE field.
+cat <<\EOF > exp || framework_failure_
+total
+EOF
+
+df --output=target --total '.' >out || fail=1
+sed -n -e '3 {
+ p
+ q
+ }' out > out2
+compare exp out2 || fail=1
+
+# Ensure that --output is mentioned in the usage.
+df --help > out || fail=1
+grep ' --output' out >/dev/null || { fail=1; cat out; }
+
+# Ensure that the FILE field contains the argument.
+cat <<\EOF > exp || framework_failure_
+.
+exp
+EOF
+
+df --output=file '.' exp >out || fail=1
+sed '1d' out > out2
+compare exp out2 || fail=1
+
+Exit $fail
diff --git a/tests/df/df-symlink.sh b/tests/df/df-symlink.sh
new file mode 100755
index 0000000..1b24429
--- /dev/null
+++ b/tests/df/df-symlink.sh
@@ -0,0 +1,48 @@
+#!/bin/sh
+# Ensure that df dereferences symlinks to file system nodes
+
+# Copyright (C) 2013-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ df
+
+file_system=$(df --out=source '.' | tail -n1) ||
+ skip_ "cannot determine '.' file system"
+
+ln -s "$file_system" symlink || framework_failure_
+
+df --out=source,target "$file_system" > exp ||
+ skip_ "cannot get info for $file_system"
+df --out=source,target symlink > out || fail=1
+compare exp out || fail=1
+
+# Ensure we output the same values for device nodes and '.'
+# This was not the case in coreutils-8.22 on systems
+# where the device in the mount list was a symlink itself.
+# I.e., '.' => /dev/mapper/fedora-home -> /dev/dm-2
+# Restrict this test to systems with a 1:1 mapping between
+# source and target. This excludes for example BTRFS sub-volumes.
+if test "$(df --output=source | grep -F "$file_system" | wc -l)" = 1; then
+ # Restrict to systems with a single file system root (and have findmnt(1))
+ if test "$(findmnt -nro FSROOT | uniq | wc -l)" = 1; then
+ df --out=source,target '.' > out || fail=1
+ compare exp out || fail=1
+ fi
+fi
+
+test "$fail" = 1 && dump_mount_list_
+
+Exit $fail
diff --git a/tests/df/header.sh b/tests/df/header.sh
new file mode 100755
index 0000000..a3a6588
--- /dev/null
+++ b/tests/df/header.sh
@@ -0,0 +1,28 @@
+#!/bin/sh
+# Ensure that "df ." outputs a header.
+
+# Copyright (C) 2006-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ df
+
+case $(df .) in
+*'
+'*) ;;
+*) fail=1;;
+esac
+
+Exit $fail
diff --git a/tests/df/no-mtab-status.sh b/tests/df/no-mtab-status.sh
new file mode 100755
index 0000000..fbc8d0a
--- /dev/null
+++ b/tests/df/no-mtab-status.sh
@@ -0,0 +1,125 @@
+#!/bin/sh
+# Test df's behavior when the mount list cannot be read.
+# This test is skipped on systems that lack LD_PRELOAD support; that's fine.
+
+# Copyright (C) 2012-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ df
+require_gcc_shared_
+
+# Protect against inaccessible remote mounts etc.
+timeout 10 df || skip_ "df fails"
+
+grep '^#define HAVE_MNTENT_H 1' $CONFIG_HEADER > /dev/null \
+ || skip_ "no mntent.h available to confirm the interface"
+
+grep '^#define HAVE_GETMNTENT 1' $CONFIG_HEADER > /dev/null \
+ || skip_ "getmntent is not used on this system"
+
+# Simulate "mtab" failure.
+cat > k.c <<EOF || framework_failure_
+#define _GNU_SOURCE
+#include <stdio.h>
+#include <errno.h>
+#include <mntent.h>
+#include <string.h>
+#include <dlfcn.h>
+
+#define STREQ(a, b) (strcmp (a, b) == 0)
+
+FILE* fopen(const char *path, const char *mode)
+{
+ static FILE* (*fopen_func)(char const *, char const *);
+
+ /* get reference to original (libc provided) fopen */
+ if (!fopen_func)
+ {
+ fopen_func = (FILE*(*)(char const *, char const *))
+ dlsym(RTLD_NEXT, "fopen");
+ if (!fopen_func)
+ {
+ fprintf (stderr, "Failed to find fopen()\n");
+ errno = ESRCH;
+ return NULL;
+ }
+ }
+
+ /* Returning ENOENT here will get read_file_system_list()
+ to fall back to using getmntent() below. */
+ if (STREQ (path, "/proc/self/mountinfo"))
+ {
+ errno = ENOENT;
+ return NULL;
+ }
+ else
+ return fopen_func(path, mode);
+}
+
+struct mntent *getmntent (FILE *fp)
+{
+ /* Prove that LD_PRELOAD works. */
+ static int done = 0;
+ if (!done)
+ {
+ fclose (fopen ("x", "w"));
+ ++done;
+ }
+ /* Now simulate the failure. */
+ errno = ENOENT;
+ return NULL;
+}
+EOF
+
+# Then compile/link it:
+gcc_shared_ k.c k.so \
+ || framework_failure_ 'failed to build shared library'
+
+cleanup_() { unset LD_PRELOAD; }
+
+export LD_PRELOAD=$LD_PRELOAD:./k.so
+
+# Test if LD_PRELOAD works:
+df 2>/dev/null
+test -f x || skip_ "internal test failure: maybe LD_PRELOAD doesn't work?"
+
+# These tests are supposed to succeed:
+df '.' || fail=1
+df -i '.' || fail=1
+df -T '.' || fail=1
+df -Ti '.' || fail=1
+df --total '.' || fail=1
+
+# These tests are supposed to fail:
+returns_ 1 df || fail=1
+returns_ 1 df -i || fail=1
+returns_ 1 df -T || fail=1
+returns_ 1 df -Ti || fail=1
+returns_ 1 df --total || fail=1
+
+returns_ 1 df -a || fail=1
+returns_ 1 df -a '.' || fail=1
+
+returns_ 1 df -l || fail=1
+returns_ 1 df -l '.' || fail=1
+
+returns_ 1 df -t hello || fail=1
+returns_ 1 df -t hello '.' || fail=1
+
+returns_ 1 df -x hello || fail=1
+returns_ 1 df -x hello '.' || fail=1
+
+Exit $fail
diff --git a/tests/df/over-mount-device.sh b/tests/df/over-mount-device.sh
new file mode 100755
index 0000000..d6d40ac
--- /dev/null
+++ b/tests/df/over-mount-device.sh
@@ -0,0 +1,59 @@
+#!/bin/sh
+# Ensure that df /dev/loop0 errors out if overmounted by another device
+
+# Copyright (C) 2014-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ df
+require_root_
+
+cwd=$(pwd)
+cleanup_() { cd /; umount "$cwd/mnt"; umount "$cwd/mnt"; }
+
+skip=0
+
+# Create 2 file systems
+for i in 1 2; do
+ dd if=/dev/zero of=blob$i bs=8192 count=200 > /dev/null 2>&1 \
+ || skip=1
+ mkfs -t ext2 -F blob$i \
+ || skip_ "failed to create ext2 file system"
+done
+
+# Mount both at the same place (eclipsing the first)
+mkdir mnt || skip=1
+mount -oloop blob1 mnt || skip=1
+eclipsed_dev=$(df --o=source mnt | tail -n1) || skip=1
+mount -oloop blob2 mnt || skip=1
+
+test $skip = 1 \
+ && skip_ "insufficient mount/ext2 support"
+
+df . || skip_ "failed to lookup the device for the current dir"
+
+echo "df: cannot access '$eclipsed_dev': over-mounted by another device" > exp
+
+# We should get an error for the eclipsed device and continue
+df $eclipsed_dev . > out 2> err && fail=1
+
+# header and single entry in output
+test $(wc -l < out) = 2 || fail=1
+
+compare exp err || fail=1
+
+test "$fail" = 1 && dump_mount_list_
+
+Exit $fail
diff --git a/tests/df/problematic-chars.sh b/tests/df/problematic-chars.sh
new file mode 100755
index 0000000..3fb9a48
--- /dev/null
+++ b/tests/df/problematic-chars.sh
@@ -0,0 +1,65 @@
+#!/bin/sh
+# Ensure that df outputs one line per entry
+
+# Copyright (C) 2012-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ df printf
+require_root_
+
+
+# Ensure a new line in a mount point only outputs a single line
+
+mnt='mount
+point'
+
+cwd=$(pwd)
+cleanup_() { umount "$cwd/$mnt"; }
+
+skip=0
+# Create a file system, then mount it.
+dd if=/dev/zero of=blob bs=8192 count=200 > /dev/null 2>&1 \
+ || skip=1
+mkdir "$mnt" || skip=1
+mkfs -t ext2 -F blob \
+ || skip_ "failed to create ext2 file system"
+mount -oloop blob "$mnt" || skip=1
+test $skip = 1 \
+ && skip_ "insufficient mount/ext2 support"
+test $(df "$mnt" | wc -l) = 2 || fail=1
+test "$fail" = 1 && dump_mount_list_
+
+
+# Ensure mount points not matching the current user encoding are output
+
+unset LC_ALL
+f=$LOCALE_FR_UTF8
+: ${LOCALE_FR_UTF8=none}
+if test "$LOCALE_FR_UTF8" != "none"; then
+
+ cleanup_ || framework_failure_
+
+ # Create a non UTF8 mount point
+ mnt="$(env printf 'm\xf3unt p\xf3int')"
+ mkdir "$mnt" || framework_failure_
+ mount -oloop blob "$mnt" || skip_ "unable to mount $mnt"
+
+ LC_ALL=$f df --output=target "$mnt" > df.out || fail=1
+ test "$(basename "$(tail -n1 df.out)")" = "$mnt" || fail=1
+fi
+
+
+Exit $fail
diff --git a/tests/df/skip-duplicates.sh b/tests/df/skip-duplicates.sh
new file mode 100755
index 0000000..06c03e8
--- /dev/null
+++ b/tests/df/skip-duplicates.sh
@@ -0,0 +1,191 @@
+#!/bin/sh
+# Test df's behavior when the mount list contains duplicate entries.
+# This test is skipped on systems that lack LD_PRELOAD support; that's fine.
+
+# Copyright (C) 2012-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ df
+require_gcc_shared_
+
+# We use --local here so as to not activate
+# potentially very many remote mounts.
+df --local --output=target >LOCAL_FS || skip_ 'df fails'
+grep '^/$' LOCAL_FS || skip_ 'no root file system found'
+
+# Get real targets to substitute for /NONROOT and /REMOTE below.
+export CU_NONROOT_FS=$(grep /. LOCAL_FS | head -n1)
+export CU_REMOTE_FS=$(grep /. LOCAL_FS | tail -n+2 | head -n1)
+
+unique_entries=1
+test -z "$CU_NONROOT_FS" || unique_entries=$(expr $unique_entries + 1)
+test -z "$CU_REMOTE_FS" || unique_entries=$(expr $unique_entries + 2)
+
+grep '^#define HAVE_MNTENT_H 1' $CONFIG_HEADER > /dev/null \
+ || skip_ "no mntent.h available to confirm the interface"
+
+grep '^#define HAVE_GETMNTENT 1' $CONFIG_HEADER > /dev/null \
+ || skip_ "getmntent is not used on this system"
+
+# Simulate an mtab file to test various cases.
+cat > k.c <<EOF || framework_failure_
+#define _GNU_SOURCE
+#include <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <mntent.h>
+#include <string.h>
+#include <dlfcn.h>
+
+#define STREQ(a, b) (strcmp (a, b) == 0)
+
+FILE* fopen(const char *path, const char *mode)
+{
+ static FILE* (*fopen_func)(char const *, char const *);
+
+ /* get reference to original (libc provided) fopen */
+ if (!fopen_func)
+ {
+ fopen_func = (FILE*(*)(char const *, char const *))
+ dlsym(RTLD_NEXT, "fopen");
+ if (!fopen_func)
+ {
+ fprintf (stderr, "Failed to find fopen()\n");
+ errno = ESRCH;
+ return NULL;
+ }
+ }
+
+ /* Returning ENOENT here will get read_file_system_list()
+ to fall back to using getmntent() below. */
+ if (STREQ (path, "/proc/self/mountinfo"))
+ {
+ errno = ENOENT;
+ return NULL;
+ }
+ else
+ return fopen_func(path, mode);
+}
+
+#define STREQ(a, b) (strcmp (a, b) == 0)
+
+struct mntent *getmntent (FILE *fp)
+{
+ static char *nonroot_fs;
+ static char *remote_fs;
+ static int done;
+
+ /* Prove that LD_PRELOAD works. */
+ if (!done)
+ {
+ fclose (fopen ("x", "w"));
+ ++done;
+ }
+
+ static struct mntent mntents[] = {
+ {.mnt_fsname="/short", .mnt_dir="/invalid/mount/dir", .mnt_opts=""},
+ {.mnt_fsname="fsname", .mnt_dir="/", .mnt_opts=""},
+ {.mnt_fsname="/fsname", .mnt_dir="/.", .mnt_opts=""},
+ {.mnt_fsname="/fsname", .mnt_dir="/", .mnt_opts=""},
+ {.mnt_fsname="virtfs", .mnt_dir="/NONROOT", .mnt_type="t1", .mnt_opts=""},
+ {.mnt_fsname="virtfs2", .mnt_dir="/NONROOT", .mnt_type="t2", .mnt_opts=""},
+ {.mnt_fsname="netns", .mnt_dir="net:[1234567]", .mnt_opts=""},
+ {.mnt_fsname="rem:ote1",.mnt_dir="/REMOTE", .mnt_opts=""},
+ {.mnt_fsname="rem:ote1",.mnt_dir="/REMOTE", .mnt_opts=""},
+ {.mnt_fsname="rem:ote2",.mnt_dir="/REMOTE", .mnt_opts=""},
+ };
+
+ if (done == 1)
+ {
+ nonroot_fs = getenv ("CU_NONROOT_FS");
+ if (!nonroot_fs || !*nonroot_fs)
+ nonroot_fs = "/"; /* merge into / entries. */
+
+ remote_fs = getenv ("CU_REMOTE_FS");
+ }
+
+ if (done == 1 && !getenv ("CU_TEST_DUPE_INVALID"))
+ done++; /* skip the first entry. */
+
+ while (done++ <= 10)
+ {
+ if (!mntents[done-2].mnt_type)
+ mntents[done-2].mnt_type = "-";
+ if (!mntents[done-2].mnt_opts)
+ mntents[done-2].mnt_opts = "-";
+ if (STREQ (mntents[done-2].mnt_dir, "/NONROOT"))
+ mntents[done-2].mnt_dir = nonroot_fs;
+ if (STREQ (mntents[done-2].mnt_dir, "/REMOTE"))
+ {
+ if (!remote_fs || !*remote_fs)
+ continue;
+ else
+ mntents[done-2].mnt_dir = remote_fs;
+ }
+ return &mntents[done-2];
+ }
+
+ return NULL;
+}
+EOF
+
+# Then compile/link it:
+gcc_shared_ k.c k.so \
+ || framework_failure_ 'failed to build shared library'
+
+# Test if LD_PRELOAD works:
+LD_PRELOAD=$LD_PRELOAD:./k.so df
+test -f x || skip_ "internal test failure: maybe LD_PRELOAD doesn't work?"
+
+# The fake mtab file should only contain entries
+# having the same device number; thus the output should
+# consist of a header and unique entries.
+LD_PRELOAD=$LD_PRELOAD:./k.so df -T >out || fail=1
+test $(wc -l <out) -eq $(expr 1 + $unique_entries) || { fail=1; cat out; }
+
+# With --total we should suppress the duplicate but separate remote file system
+LD_PRELOAD=$LD_PRELOAD:./k.so df --total >out || fail=1
+test "$CU_REMOTE_FS" && elide_remote=1 || elide_remote=0
+test $(wc -l <out) -eq $(expr 2 + $unique_entries - $elide_remote) ||
+ { fail=1; cat out; }
+
+# Ensure we don't fail when unable to stat (currently) unavailable entries
+LD_PRELOAD=$LD_PRELOAD:./k.so CU_TEST_DUPE_INVALID=1 df -T >out || fail=1
+test $(wc -l <out) -eq $(expr 1 + $unique_entries) || { fail=1; cat out; }
+
+# df should also prefer "/fsname" over "fsname"
+if test "$unique_entries" = 2; then
+ test $(grep -c '/fsname' <out) -eq 1 || { fail=1; cat out; }
+ # ... and "/fsname" with '/' as Mounted on over '/.'
+ test $(grep -cF '/.' <out) -eq 0 || { fail=1; cat out; }
+fi
+
+# df should use the last seen devname (mnt_fsname) and devtype (mnt_type)
+test $(grep -c 'virtfs2.*t2' <out) -eq 1 || { fail=1; cat out; }
+
+# Ensure that filtering duplicates does not affect -a processing.
+LD_PRELOAD=$LD_PRELOAD:./k.so df -a >out || fail=1
+total_fs=6; test "$CU_REMOTE_FS" && total_fs=$(expr $total_fs + 3)
+test $(wc -l <out) -eq $total_fs || { fail=1; cat out; }
+# Ensure placeholder "-" values used for the eclipsed "virtfs"
+test $(grep -c 'virtfs *-' <out) -eq 1 || { fail=1; cat out; }
+
+# Ensure that filtering duplicates does not affect
+# argument processing (now without the fake getmntent()).
+df '.' '.' >out || fail=1
+test $(wc -l <out) -eq 3 || { fail=1; cat out; }
+
+Exit $fail
diff --git a/tests/df/skip-rootfs.sh b/tests/df/skip-rootfs.sh
new file mode 100755
index 0000000..98e58df
--- /dev/null
+++ b/tests/df/skip-rootfs.sh
@@ -0,0 +1,53 @@
+#!/bin/sh
+# Test df's behavior for skipping the pseudo "rootfs" file system.
+
+# Copyright (C) 2012-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ df
+
+# Protect against inaccessible remote mounts etc.
+timeout 10 df || skip_ "df fails"
+
+# Verify that rootfs is in mtab (and shown when the -a option is specified).
+# Note this is the case when /proc/self/mountinfo is parsed
+# rather than /proc/mounts. I.e., when libmount is being used.
+df -a >out || fail=1
+grep '^rootfs' out || skip_ 'no rootfs in mtab'
+
+# Ensure that rootfs is suppressed when no options is specified.
+df >out || fail=1
+grep '^rootfs' out && { fail=1; cat out; }
+
+# Ensure that rootfs is yet skipped when explicitly specifying "-t rootfs".
+# As df emits "no file systems processed" in this case, it would be a failure
+# if df exited with status Zero.
+returns_ 1 df -t rootfs >out || fail=1
+grep '^rootfs' out && { fail=1; cat out; }
+
+# Ensure that the rootfs is shown when explicitly both specifying "-t rootfs"
+# and the -a option.
+df -t rootfs -a >out || fail=1
+grep '^rootfs' out || { fail=1; cat out; }
+
+# Ensure that the rootfs is omitted in all_fs mode when it is explicitly
+# black-listed.
+df -a -x rootfs >out || fail=1
+grep '^rootfs' out && { fail=1; cat out; }
+
+test "$fail" = 1 && dump_mount_list_
+
+Exit $fail
diff --git a/tests/df/total-unprocessed.sh b/tests/df/total-unprocessed.sh
new file mode 100755
index 0000000..eae9d5f
--- /dev/null
+++ b/tests/df/total-unprocessed.sh
@@ -0,0 +1,44 @@
+#!/bin/sh
+# Ensure that df exits non-Zero and writes an error message when
+# --total is used but no file system has been processed.
+
+# Copyright (C) 2012-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ df
+require_mount_list_
+
+cat <<\EOF > exp || framework_failure_
+df: no file systems processed
+EOF
+
+# Check we exit with non-Zero.
+# Note we don't check when the file system can't be determined
+# as -t filtering is not applied in that case.
+if test "$(df --output=fstype . | tail -n1)" != '-'; then
+ df -t _non_existent_fstype_ --total . 2>out && fail=1
+ compare exp out || fail=1
+fi
+
+cat <<\EOF > exp || framework_failure_
+df: _does_not_exist_: No such file or directory
+EOF
+
+# Ensure that df writes the error message also in the following case.
+df --total _does_not_exist_ 2>out && fail=1
+compare exp out || fail=1
+
+Exit $fail
diff --git a/tests/df/total-verify.sh b/tests/df/total-verify.sh
new file mode 100755
index 0000000..dafc301
--- /dev/null
+++ b/tests/df/total-verify.sh
@@ -0,0 +1,67 @@
+#!/bin/sh
+# Ensure "df --total" computes accurate totals
+
+# Copyright (C) 2008-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ df
+require_perl_
+
+# Protect against inaccessible remote mounts etc.
+timeout 10 df || skip_ "df fails"
+
+cat <<\EOF > check-df || framework_failure_
+my ($total, $used, $avail) = (0, 0, 0);
+while (<>)
+ {
+ $. == 1
+ and next; # skip first (header) line
+ # Recognize df output lines like these:
+ # /dev/sdc1 0 0 0 - /c
+ # tmpfs 1536000 12965 1523035 1% /tmp
+ # total 5285932 787409 4498523 15% -
+ /^(.*?) +(-?\d+|-) +(-?\d+|-) +(-?\d+|-) +(?:-|[0-9]+%) (.*)$/
+ or die "$0: invalid input line\n: $_";
+ if ($1 eq 'total' && $5 eq '-')
+ {
+ $total == $2 or die "$total != $2";
+ $used == $3 or die "$used != $3";
+ $avail == $4 or die "$avail != $4";
+ my $line = <>;
+ defined $line
+ and die "$0: extra line(s) after totals\n";
+ exit 0;
+ }
+ $total += $2 unless $2 eq '-';
+ $used += $3 unless $3 eq '-';
+ $avail += $4 unless $4 eq '-';
+ }
+die "$0: missing line of totals\n";
+EOF
+
+# Use --block-size=512 to keep df from printing rounded-to-kilobyte
+# numbers which wouldn't necessarily add up to the displayed total.
+df --total -P --block-size=512 > space || framework_failure_
+cat space # this helps when debugging any test failure
+df --total -i -P > inode || framework_failure_
+cat inode
+
+$PERL check-df space || fail=1
+$PERL check-df inode || fail=1
+
+test "$fail" = 1 && dump_mount_list_
+
+Exit $fail
diff --git a/tests/df/unreadable.sh b/tests/df/unreadable.sh
new file mode 100755
index 0000000..44bcd19
--- /dev/null
+++ b/tests/df/unreadable.sh
@@ -0,0 +1,32 @@
+#!/bin/sh
+# ensure that df can handle an unreadable argument
+
+# Copyright (C) 2009-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ df
+skip_if_root_
+
+touch unreadable || fail=1
+chmod a-r unreadable || fail=1
+df unreadable || fail=1
+
+mkfifo_or_skip_ fifo
+timeout 10 df fifo || fail=1
+
+test "$fail" = 1 && dump_mount_list_
+
+Exit $fail
diff --git a/tests/du/2g.sh b/tests/du/2g.sh
new file mode 100755
index 0000000..fe514a7
--- /dev/null
+++ b/tests/du/2g.sh
@@ -0,0 +1,71 @@
+#!/bin/sh
+# Ensure that du can handle a 2GB file (i.e., a file of size 2^31 bytes)
+# Before coreutils-5.93, on systems with a signed, 32-bit stat.st_blocks
+# one of du's computations would overflow.
+
+# Copyright (C) 2005-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ du
+
+# Creating a 2GB file counts as 'very expensive'.
+very_expensive_
+
+# Get number of free kilobytes on current partition, so we can
+# skip this test if there is insufficient free space.
+free_kb=$(df -k --output=avail . | tail -n1)
+case "$free_kb" in
+ [0-9]*) ;;
+ *) skip_ "invalid size from df: $free_kb";;
+esac
+
+# Require about 3GB free.
+min_kb=3000000
+test $min_kb -lt $free_kb ||
+{
+ skip_ \
+ "too little free space on current partition: $free_kb (need $min_kb KB)"
+}
+
+big=big
+
+if ! fallocate -l2G $big; then
+ rm -f $big
+ {
+ is_local_dir_ . || skip_ 'Not writing 2GB data to remote'
+ for i in $(seq 100); do
+ # Note: 2147483648 == 2^31. Print floor(2^31/100) per iteration.
+ printf %21474836s x || fail=1
+ done
+ # After the final iteration, append the remaining 48 bytes.
+ printf %48s x || fail=1
+ } > $big || fail=1
+fi
+
+# The allocation may be done asynchronously (BTRFS for example)
+sync $big || framework_failure_
+
+du -k $big > out1 || fail=1
+rm -f $big
+sed 's/^2[0-9][0-9][0-9][0-9][0-9][0-9] '$big'$/~2M/' out1 > out
+
+cat <<\EOF > exp || framework_failure_
+~2M
+EOF
+
+compare exp out || fail=1
+
+Exit $fail
diff --git a/tests/du/8gb.sh b/tests/du/8gb.sh
new file mode 100755
index 0000000..04173d6
--- /dev/null
+++ b/tests/du/8gb.sh
@@ -0,0 +1,54 @@
+#!/bin/sh
+# Ensure that du does not rely on narrow types like size_t for
+# file sizes or sums.
+
+# Copyright (C) 2003-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ du
+require_sparse_support_
+
+# timeout to avoid hang on GNU/Hurd from 2019
+timeout 10 dd bs=1 seek=8G of=big < /dev/null 2> /dev/null
+if test $? != 0; then
+ skip_ 'cannot create a file large enough for this test; possibly
+because file offsets are only 32 bits on this file system'
+fi
+
+# FIXME: this should be a test of dd.
+# On some systems (at least linux-2.4.18 + NFS to Solaris system)
+# the 'dd' command above mistakenly creates a file of length '0', yet
+# doesn't fail. The root of that failure is that the ftruncate call
+# returns zero but doesn't do its job. Detect this failure.
+set x $(ls -gG big)
+size=$4
+if test "$size" = 0; then
+ skip_ "cannot create a file large enough for this test
+possibly because this system's NFS support is buggy
+Consider rerunning this test on a different file system."
+fi
+
+
+# This would print '0 big' with coreutils-4.5.8.
+du -ab big > out || fail=1
+
+cat <<\EOF > exp
+8589934592 big
+EOF
+
+compare exp out || fail=1
+
+Exit $fail
diff --git a/tests/du/apparent.sh b/tests/du/apparent.sh
new file mode 100755
index 0000000..dba3031
--- /dev/null
+++ b/tests/du/apparent.sh
@@ -0,0 +1,33 @@
+#!/bin/sh
+# Exercise du's --apparent-size option.
+
+# Copyright 2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ du
+
+mkdir -p d || framework_failure_
+for f in $(seq 100); do
+ echo foo >d/$f || framework_failure_
+done
+
+du -b d/* >separate || fail=1
+du -b d >together || fail=1
+separate_sum=$($AWK '{sum+=$1}END{print sum}' separate) || framework_failure_
+together_sum=$($AWK '{sum+=$1}END{print sum}' together) || framework_failure_
+test $separate_sum -eq $together_sum || fail=1
+
+Exit $fail
diff --git a/tests/du/basic.sh b/tests/du/basic.sh
new file mode 100755
index 0000000..28eeb59
--- /dev/null
+++ b/tests/du/basic.sh
@@ -0,0 +1,91 @@
+#!/bin/sh
+# Compare actual numbers from du, assuming block size matches mine.
+
+# Copyright (C) 2003-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ du
+
+mkdir -p a/b d d/sub || framework_failure_
+
+# Ensure that these files contain more than 64 bytes, so that we don't
+# immediately disqualify file systems (e.g., NetApp) on which smaller
+# files take up zero file system blocks.
+printf '%*s' 257 make-sure-the-file-is-non-empty > a/b/F || framework_failure_
+printf %4096s x > d/1
+cp d/1 d/sub/2
+
+
+B=$(stat --format=%B a/b/F)
+
+du --block-size=$B -a a > out || fail=1
+echo === >> out
+du --block-size=$B -a -S a >> out || fail=1
+echo === >> out
+du --block-size=$B -s a >> out || fail=1
+
+f=$(stat --format=%b a/b/F)
+b=$(stat --format=%b a/b)
+a=$(stat --format=%b a)
+bf=$(expr $b + $f)
+tot=$(expr $bf + $a)
+
+cat <<EOF | sed 's/ *#.*//' > exp
+$f a/b/F
+$bf a/b
+$tot a
+===
+$f a/b/F # size of file, a/b/F
+$bf a/b # size of dir entry, a/b, + size of file, a/b/F
+$a a # size of dir entry, a
+===
+$tot a
+EOF
+
+compare exp out || fail=1
+
+# Perform this test only if "." is on a local file system.
+# Otherwise, it would fail e.g., on an NFS-mounted Solaris ZFS file system.
+# Also skip local ZFS as that was seen to fail intermittently
+# (perhaps due to async compression affecting allocations)
+if is_local_dir_ . && ! df -T -t zfs .; then
+ rm -f out exp
+ du --block-size=$B -a d | sort -r -k2,2 > out || fail=1
+ echo === >> out
+ du --block-size=$B -S d | sort -r -k2,2 >> out || fail=1
+
+ t2=$(stat --format=%b d/sub/2)
+ ts=$(stat --format=%b d/sub)
+ t1=$(stat --format=%b d/1)
+ td=$(stat --format=%b d)
+ tot=$(expr $t1 + $t2 + $ts + $td)
+ d1=$(expr $td + $t1)
+ s2=$(expr $ts + $t2)
+
+ cat <<EOF | sed 's/ *#.*//' > exp
+$t2 d/sub/2
+$s2 d/sub
+$t1 d/1
+$tot d
+===
+$s2 d/sub
+$d1 d # d + d/1; don't count the dir. entry for d/sub
+EOF
+
+ compare exp out || fail=1
+fi
+
+Exit $fail
diff --git a/tests/du/bigtime.sh b/tests/du/bigtime.sh
new file mode 100755
index 0000000..1ad56eb
--- /dev/null
+++ b/tests/du/bigtime.sh
@@ -0,0 +1,52 @@
+#!/bin/sh
+# Exercise du on a file with a big timestamp.
+
+# Copyright (C) 2010-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ du
+
+export LC_ALL=C
+export TZ=UTC0
+
+# 2**63 - 1
+bignum=9223372036854775807
+
+touch -d @$bignum future 2>/dev/null &&
+future_time=$(ls -l future) &&
+case "$future_time" in
+*" $bignum "*)
+ : ;;
+*' Dec 4 300627798676 '*)
+ skip_ "file system and localtime both handle big timestamps" ;;
+*)
+ skip_ "file system or localtime mishandles big timestamps:" \
+ "$future_time" ;;
+esac || skip_ "file system cannot represent big timestamps"
+
+printf "0\t$bignum\tfuture\n" > exp || framework_failure_
+printf "du: time '$bignum' is out of range\n" > err_ok || framework_failure_
+
+du --time future >out 2>err || fail=1
+
+# On some systems an empty file occupies 4 blocks.
+# Map the number of blocks to 0.
+sed 's/^[0-9][0-9]*/0/' out > k && mv k out
+
+compare exp out || fail=1
+compare err err_ok || fail=1
+
+Exit $fail
diff --git a/tests/du/bind-mount-dir-cycle-v2.sh b/tests/du/bind-mount-dir-cycle-v2.sh
new file mode 100755
index 0000000..18e40d2
--- /dev/null
+++ b/tests/du/bind-mount-dir-cycle-v2.sh
@@ -0,0 +1,38 @@
+#!/bin/sh
+# Check that du can handle sub-bind-mounts cycles as well.
+
+# Copyright (C) 2014-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ du
+require_root_
+
+cleanup_() { umount a/b/c; }
+
+mkdir -p a/b/c || framework_failure_
+mount --bind a a/b/c \
+ || skip_ 'This test requires mount with a working --bind option.'
+
+echo a/b/c > exp || framework_failure_
+echo a/b >> exp || framework_failure_
+
+du a/b > out 2> err || fail=1
+sed 's/^[0-9][0-9]* //' out > k && mv k out
+
+compare /dev/null err || fail=1
+compare exp out || fail=1
+
+Exit $fail
diff --git a/tests/du/bind-mount-dir-cycle.sh b/tests/du/bind-mount-dir-cycle.sh
new file mode 100755
index 0000000..f2a74fd
--- /dev/null
+++ b/tests/du/bind-mount-dir-cycle.sh
@@ -0,0 +1,37 @@
+#!/bin/sh
+# Exercise du's new ability to handle bind-mount-induced dir cycles.
+
+# Copyright (C) 2012-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ du
+require_root_
+
+cleanup_() { umount a/b; }
+
+mkdir -p a/b || framework_failure_
+mount --bind a a/b \
+ || skip_ "This test requires mount with a working --bind option."
+
+echo a > exp || framework_failure_
+
+du a > out 2> err || fail=1
+sed 's/^[0-9][0-9]* //' out > k && mv k out
+
+compare /dev/null err || fail=1
+compare exp out || fail=1
+
+Exit $fail
diff --git a/tests/du/deref-args.sh b/tests/du/deref-args.sh
new file mode 100755
index 0000000..64bf6ae
--- /dev/null
+++ b/tests/du/deref-args.sh
@@ -0,0 +1,48 @@
+#!/bin/sh
+# Ensure that --dereference-args (-D) gives reasonable names.
+# This test would fail for coreutils-5.0.91.
+
+# Copyright (C) 2003-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ du
+
+mkdir -p dir/a || framework_failure_
+ln -s dir slink || framework_failure_
+printf %65536s x > 64k || framework_failure_
+ln -s 64k slink-to-64k || framework_failure_
+
+
+du -D slink | sed 's/^[0-9][0-9]* //' > out
+# Ensure that the trailing slash is preserved and handled properly.
+du -D slink/ | sed 's/^[0-9][0-9]* //' >> out
+
+# Ensure that -D makes du dereference even symlinks to non-directories.
+# Be sure to use --apparent-size. Otherwise, we'd get varying block counts
+# depending on file system type (e.g. 68 on ext3 vs. 64 on tmpfs and 72
+# on SELinux-enabled systems).
+du --apparent-size --block-size=1K -D slink-to-64k >> out
+cat <<\EOF > exp
+slink/a
+slink
+slink/a
+slink/
+64 slink-to-64k
+EOF
+
+compare exp out || fail=1
+
+Exit $fail
diff --git a/tests/du/deref.sh b/tests/du/deref.sh
new file mode 100755
index 0000000..f16d87a
--- /dev/null
+++ b/tests/du/deref.sh
@@ -0,0 +1,48 @@
+#!/bin/sh
+# prior to coreutils-4.5.3, du -D didn't work in some cases
+# Based on an example from Andreas Schwab and/or Michal Svec.
+# Also, up to coreutils-8.5, du -L sometimes incorrectly
+# counted the space of the followed symlinks.
+
+# Copyright (C) 2002-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ du
+
+mkdir -p a/sub || framework_failure_
+ln -s a/sub slink || framework_failure_
+touch b || framework_failure_
+ln -s .. a/sub/dotdot || framework_failure_
+ln -s nowhere dangle || framework_failure_
+
+
+# This used to fail with the following diagnostic:
+# du: 'b': No such file or directory
+du -sD slink b > /dev/null 2>&1 || fail=1
+
+# This used to fail to report the dangling symlink.
+returns_ 1 du -L dangle > /dev/null 2>&1 || fail=1
+
+# du -L used to mess up, either by counting the symlink's file system space
+# itself (-L should follow symlinks, not count their space)
+# or (briefly in July 2010) by omitting the entry for "a".
+du_L_output=$(du -L a) || fail=1
+du_lL_output=$(du -lL a) || fail=1
+du_x_output=$(du --exclude=dotdot a) || fail=1
+test "X$du_L_output" = "X$du_x_output" || fail=1
+test "X$du_lL_output" = "X$du_x_output" || fail=1
+
+Exit $fail
diff --git a/tests/du/exclude.sh b/tests/du/exclude.sh
new file mode 100755
index 0000000..2fea396
--- /dev/null
+++ b/tests/du/exclude.sh
@@ -0,0 +1,58 @@
+#!/bin/sh
+# make sure du's --exclude option works
+
+# Copyright (C) 2003-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ du
+
+mkdir -p a/b/c a/x/y a/u/v || framework_failure_
+
+
+du --exclude=x a | sed 's/^[0-9][0-9]* //' | sort > out || fail=1
+printf '===\n' >> out
+printf 'b\n' > excl
+du --exclude-from=excl a | sed 's/^[0-9][0-9]* //' | sort >> out || fail=1
+printf '===\n' >> out
+# Make sure that we can exclude an entire hierarchy.
+du --exclude=a a >> out || fail=1
+# Make sure that we can exclude based on more than one component.
+# Before coreutils-5.3.0, this part would fail.
+printf '===\n' >> out
+du --exclude=a/u --exclude=a/b a \
+ | sed 's/^[0-9][0-9]* //' | sort >> out || fail=1
+cat <<\EOF > exp
+a
+a/b
+a/b/c
+a/u
+a/u/v
+===
+a
+a/u
+a/u/v
+a/x
+a/x/y
+===
+===
+a
+a/x
+a/x/y
+EOF
+
+compare exp out || fail=1
+
+Exit $fail
diff --git a/tests/du/fd-leak.sh b/tests/du/fd-leak.sh
new file mode 100755
index 0000000..4b5c607
--- /dev/null
+++ b/tests/du/fd-leak.sh
@@ -0,0 +1,43 @@
+#!/bin/sh
+# check for file descriptor leak
+
+# Copyright (C) 2003-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ du
+
+# Call this an expensive test. It's not that expensive, but command line
+# limitations might induce failure on some losing systems.
+expensive_
+
+# Create 1296 (36^2) files.
+# Their names and separating spaces take up 3887 bytes.
+x='a b c d e f g h i j k l m n o p q r s t u v w x y z 0 1 2 3 4 5 6 7 8 9'
+f=
+for i in $x; do
+ for j in $x; do
+ f="$f $i$j"
+ done
+done
+
+# This may fail due to command line limitations.
+touch $f || framework_failure_
+
+
+# With coreutils-5.0, this would fail due to a file descriptor leak.
+du $f > out || fail=1
+
+Exit $fail
diff --git a/tests/du/files0-from-dir.sh b/tests/du/files0-from-dir.sh
new file mode 100755
index 0000000..352a059
--- /dev/null
+++ b/tests/du/files0-from-dir.sh
@@ -0,0 +1,39 @@
+#!/bin/sh
+# ensure that du and wc handle --files0-from=DIR
+
+# Copyright (C) 2011-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ du wc
+
+mkdir dir
+
+# Skip this test if reading from a directory succeeds.
+# In that case, using --files0-from=dir would yield garbage,
+# interpreting the directory entry as a sequence of
+# NUL-separated file names.
+cat dir > /dev/null && skip_ "cat dir/ succeeds"
+
+for prog in du wc; do
+ $prog --files0-from=dir > /dev/null 2>err && fail=1
+ printf "$prog: dir:\n" > exp || fail=1
+ # The diagnostic string is usually "Is a directory" (ENOTDIR),
+ # but accept a different string or errno value.
+ sed "s/dir:.*/dir:/" err > k; mv k err
+ compare exp err || fail=1
+done
+
+Exit $fail
diff --git a/tests/du/files0-from.pl b/tests/du/files0-from.pl
new file mode 100755
index 0000000..ffaae85
--- /dev/null
+++ b/tests/du/files0-from.pl
@@ -0,0 +1,94 @@
+#!/usr/bin/perl
+# Exercise du's --files0-from option.
+# FIXME: keep this file in sync with tests/misc/wc-files0-from.
+
+# Copyright (C) 2004-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+use strict;
+
+(my $program_name = $0) =~ s|.*/||;
+
+my $prog = 'du';
+
+# Turn off localization of executable's output.
+@ENV{qw(LANGUAGE LANG LC_ALL)} = ('C') x 3;
+
+my @Tests =
+ (
+ # invalid extra command line argument
+ ['f-extra-arg', '--files0-from=- no-such', {IN=>"a"}, {EXIT=>1},
+ {ERR => "$prog: extra operand 'no-such'\n"
+ . "file operands cannot be combined with --files0-from\n"
+ . "Try '$prog --help' for more information.\n"}
+ ],
+
+ # missing input file
+ ['missing', '--files0-from=missing', {EXIT=>1},
+ {ERR => "$prog: cannot open 'missing' for reading: "
+ . "No such file or directory\n"}],
+
+ # input file name of '-'
+ ['minus-in-stdin', '--files0-from=-', '<', {IN=>{f=>'-'}}, {EXIT=>1},
+ {ERR => "$prog: when reading file names from stdin, no file name of"
+ . " '-' allowed\n"}],
+
+ # empty input, regular file
+ ['empty', '--files0-from=@AUX@', {AUX=>''}],
+
+ # empty input, from non-regular file
+ ['empty-nonreg', '--files0-from=/dev/null'],
+
+ # one NUL
+ ['nul-1', '--files0-from=-', '<', {IN=>"\0"}, {EXIT=>1},
+ {ERR => "$prog: -:1: invalid zero-length file name\n"}],
+
+ # two NULs
+ ['nul-2', '--files0-from=-', '<', {IN=>"\0\0"}, {EXIT=>1},
+ {ERR => "$prog: -:1: invalid zero-length file name\n"
+ . "$prog: -:2: invalid zero-length file name\n"}],
+
+ # one file name, no NUL
+ ['1', '--files0-from=-', '<',
+ {IN=>{f=>"g"}}, {AUX=>{g=>''}},
+ {OUT=>"0\tg\n"}, {OUT_SUBST=>'s/^\d+/0/'} ],
+
+ # one file name, with NUL
+ ['1a', '--files0-from=-', '<',
+ {IN=>{f=>"g\0"}}, {AUX=>{g=>''}},
+ {OUT=>"0\tg\n"}, {OUT_SUBST=>'s/^\d+/0/'} ],
+
+ # two identical file names, no final NUL
+ ['2', '--files0-from=-', '<',
+ {IN=>{f=>"g\0g"}}, {AUX=>{g=>''}},
+ {OUT=>"0\tg\n"}, {OUT_SUBST=>'s/^\d+/0/'} ],
+
+ # two identical file names, with final NUL
+ ['2a', '--files0-from=-', '<',
+ {IN=>{f=>"g\0g\0"}}, {AUX=>{g=>''}},
+ {OUT=>"0\tg\n"}, {OUT_SUBST=>'s/^\d+/0/'} ],
+
+ # Ensure that $prog processes FILEs following a zero-length name.
+ ['zero-len', '--files0-from=-', '<',
+ {IN=>{f=>"\0g\0"}}, {AUX=>{g=>''}},
+ {OUT=>"0\tg\n"}, {OUT_SUBST=>'s/^\d+/0/'},
+ {ERR => "$prog: -:1: invalid zero-length file name\n"}, {EXIT=>1} ],
+ );
+
+my $save_temps = $ENV{DEBUG};
+my $verbose = $ENV{VERBOSE};
+
+my $fail = run_tests ($program_name, $prog, \@Tests, $save_temps, $verbose);
+exit $fail;
diff --git a/tests/du/hard-link.sh b/tests/du/hard-link.sh
new file mode 100755
index 0000000..783003e
--- /dev/null
+++ b/tests/du/hard-link.sh
@@ -0,0 +1,64 @@
+#!/bin/sh
+# Ensure that hard-linked files are counted (and listed) only once.
+# Likewise for excluded directories.
+# Ensure that hard links _are_ listed twice when using --count-links.
+
+# Copyright (C) 2003-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ du
+
+mkdir -p dir/sub
+( cd dir &&
+ { echo non-empty > f1
+ ln f1 f2
+ ln -s f1 f3
+ echo non-empty > sub/F; } )
+
+du -a -L --exclude=sub --count-links dir \
+ | sed 's/^[0-9][0-9]* //' | sort -r > out || fail=1
+
+# For these tests, transform f1 or f2 or f3 (whichever name is find
+# first) to f_. That is necessary because, depending on the type of
+# file system, du could encounter any of those linked files first,
+# thus listing that one and not the others.
+for args in '-L' 'dir' '-L dir'
+do
+ echo === >> out
+ du -a --exclude=sub $args dir \
+ | sed 's/^[0-9][0-9]* //' | sed 's/f[123]/f_/' >> out || fail=1
+done
+
+cat <<\EOF > exp
+dir/f3
+dir/f2
+dir/f1
+dir
+===
+dir/f_
+dir
+===
+dir/f_
+dir/f_
+dir
+===
+dir/f_
+dir
+EOF
+
+compare exp out || fail=1
+
+Exit $fail
diff --git a/tests/du/inacc-dest.sh b/tests/du/inacc-dest.sh
new file mode 100755
index 0000000..e6049ca
--- /dev/null
+++ b/tests/du/inacc-dest.sh
@@ -0,0 +1,56 @@
+#!/bin/sh
+# Prior to coreutils-6.5, an inaccessible destination dir (chmod a-x)
+# would cause du to exit prematurely on systems with native openat support.
+
+# Copyright (C) 2006-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ du
+skip_if_root_
+
+mkdir f && cd f && mkdir a b c d e && touch c/j && chmod a-x c \
+ || framework_failure_
+
+du > ../t 2>&1 && fail=1
+
+# Accept either of the following outputs.
+# You get the first from a system with openat _emulation_ (via /proc),
+# the second from a system with native openat support.
+# FIXME: there may well be a third output, for systems with neither
+# /proc support, nor native openat support.
+
+sed 's/^[0-9][0-9]* //' ../t | sort -u > out
+cat <<\EOF > exp || framework_failure_
+.
+./a
+./b
+./c
+./d
+./e
+du: cannot read directory './c': Permission denied
+EOF
+
+# Map a diagnostic like this
+# du: cannot access './c/j': Permission denied
+# to this:
+# du: cannot access './c': Permission denied
+# And accept "cannot read directory" in place of "cannot access"
+sed "s,/c/j': ,/c': ," out > t && mv t out
+sed 's,cannot access,cannot read directory,' out > t && mv t out
+
+compare exp out || fail=1
+
+Exit $fail
diff --git a/tests/du/inacc-dir.sh b/tests/du/inacc-dir.sh
new file mode 100755
index 0000000..5e320b1
--- /dev/null
+++ b/tests/du/inacc-dir.sh
@@ -0,0 +1,42 @@
+#!/bin/sh
+# Ensure that du counts the size of an inaccessible directory.
+# Copyright (C) 2007-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ du
+skip_if_root_
+
+mkdir -p a/sub || framework_failure_
+
+
+du -s a > exp || fail=1
+chmod 0 a/sub || fail=1
+# Expect failure, ignore diagnostics.
+du -s a > out 2> /dev/null && fail=1
+
+compare exp out || fail=1
+
+# Same as above, but don't use -s, so we print
+# an entry for the unreadable "sub", too.
+chmod 700 a/sub || fail=1
+du -k a > exp || fail=1
+chmod 0 a/sub || fail=1
+# Expect failure, ignore diagnostics.
+du -k a > out 2> /dev/null && fail=1
+
+compare exp out || fail=1
+
+Exit $fail
diff --git a/tests/du/inaccessible-cwd.sh b/tests/du/inaccessible-cwd.sh
new file mode 100755
index 0000000..be0e684
--- /dev/null
+++ b/tests/du/inaccessible-cwd.sh
@@ -0,0 +1,40 @@
+#!/bin/sh
+# Ensure that even when run from an inaccessible directory, du can still
+# operate on accessible directories elsewhere.
+
+# Copyright (C) 2003-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+# Before the switch to an fts-based implementation in coreutils 5.0.92,
+# this test would fail.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ du
+
+# Skip this test if your system has neither the openat-style functions
+# nor /proc/self/fd support with which to emulate them.
+require_openat_support_
+
+skip_if_root_
+
+cwd=$(pwd)
+mkdir -p no-x a/b || framework_failure_
+cd no-x || framework_failure_
+chmod 0 . || framework_failure_
+
+
+du "$cwd/a" > /dev/null || fail=1
+
+Exit $fail
diff --git a/tests/du/inodes.sh b/tests/du/inodes.sh
new file mode 100755
index 0000000..1067d0e
--- /dev/null
+++ b/tests/du/inodes.sh
@@ -0,0 +1,140 @@
+#!/bin/sh
+# exercise du's --inodes option
+
+# Copyright (C) 2010-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ du
+
+# An empty directory uses only 1 inode.
+mkdir d || framework_failure_
+printf '1\td\n' > exp || framework_failure_
+
+du --inodes d > out 2>err || fail=1
+compare exp out || fail=1
+compare /dev/null err || fail=1
+
+# Add a regular file: 2 inodes used.
+touch d/f || framework_failure_
+printf '2\td\n' > exp || framework_failure_
+
+du --inodes d > out 2>err || fail=1
+compare exp out || fail=1
+compare /dev/null err || fail=1
+
+# Add a hardlink to the file: still only 2 inodes used.
+ln -v d/f d/h || framework_failure_
+du --inodes d > out 2>err || fail=1
+compare exp out || fail=1
+compare /dev/null err || fail=1
+
+# Now count also hardlinks (-l,--count-links): 3 inodes.
+printf '3\td\n' > exp || framework_failure_
+du --inodes -l d > out 2>err || fail=1
+compare exp out || fail=1
+compare /dev/null err || fail=1
+
+# Create a directory and summarize: 3 inodes.
+mkdir d/d || framework_failure_
+du --inodes -s d > out 2>err || fail=1
+compare exp out || fail=1
+compare /dev/null err || fail=1
+
+# Count inodes separated: 1-2.
+printf '1\td/d\n2\td\n' > exp || framework_failure_
+du --inodes -S d > out 2>err || fail=1
+compare exp out || fail=1
+compare /dev/null err || fail=1
+
+# Count inodes cumulative (default): 1-3.
+printf '1\td/d\n3\td\n' > exp || framework_failure_
+du --inodes d > out 2>err || fail=1
+compare exp out || fail=1
+compare /dev/null err || fail=1
+
+# Count all items: 1-1-3.
+# Sort output because the directory entry order is not defined.
+# Also replace the hardlink with the original file name because
+# the system may either return 'd/f' or 'd/h' first, and du(1)
+# will ignore the other one.
+printf '1\td/d\n1\td/f\n3\td\n' | sort > exp || framework_failure_
+du --inodes -a d > out.tmp 2>err || fail=1
+sed 's/h$/f/' out.tmp | sort >out || framework_failure_
+compare exp out || fail=1
+compare /dev/null err || fail=1
+
+# Count all items and hardlinks again: 1-1-1-4
+# Sort output because the directory entry order is not defined.
+printf '1\td/d\n1\td/h\n1\td/f\n4\td\n' | sort > exp || framework_failure_
+du --inodes -al d > out.tmp 2>err || fail=1
+sort <out.tmp >out || framework_failure_
+compare exp out || fail=1
+compare /dev/null err || fail=1
+
+# Run with total (-c) line: 1-3-3
+printf '1\td/d\n3\td\n3\ttotal\n' > exp || framework_failure_
+du --inodes -c d > out 2>err || fail=1
+compare exp out || fail=1
+compare /dev/null err || fail=1
+
+# Create another file in the subdirectory: 2-4
+touch d/d/f || framework_failure_
+printf '2\td/d\n4\td\n' > exp || framework_failure_
+du --inodes d > out 2>err || fail=1
+compare exp out || fail=1
+compare /dev/null err || fail=1
+
+# Ensure human output (-h, --si) works.
+rm -rf d || framework_failure_
+mkdir d || framework_failure_
+seq --format="d/file%g" 1023 | xargs touch || framework_failure_
+printf '1.0K\td\n' > exp || framework_failure_
+du --inodes -h d > out 2>err || fail=1
+compare exp out || fail=1
+compare /dev/null err || fail=1
+
+printf '1.1k\td\n' > exp || framework_failure_
+du --inodes --si d > out 2>err || fail=1
+compare exp out || fail=1
+compare /dev/null err || fail=1
+
+# Verify --inodes ignores -B.
+printf '1024\td\n' > exp || framework_failure_
+du --inodes -B10 d > out 2>err || fail=1
+compare exp out || fail=1
+compare /dev/null err || fail=1
+
+# Verify --inodes works with --threshold.
+printf '1024\td\n' > exp || framework_failure_
+du --inodes --threshold=1000 d > out 2>err || fail=1
+compare exp out || fail=1
+compare /dev/null err || fail=1
+
+du --inodes --threshold=-1000 d > out 2>err || fail=1
+compare /dev/null out || fail=1
+compare /dev/null err || fail=1
+
+# Verify --inodes raises a warning for --apparent-size and -b.
+du --inodes -b d > out 2>err || fail=1
+grep ' ineffective ' err >/dev/null || { fail=1; cat out err; }
+
+du --inodes --apparent-size d > out 2>err || fail=1
+grep ' ineffective ' err >/dev/null || { fail=1; cat out err; }
+
+# Ensure that --inodes is mentioned in the usage.
+du --help > out || fail=1
+grep ' --inodes ' out >/dev/null || { fail=1; cat out; }
+Exit $fail
diff --git a/tests/du/long-from-unreadable.sh b/tests/du/long-from-unreadable.sh
new file mode 100755
index 0000000..b7763f4
--- /dev/null
+++ b/tests/du/long-from-unreadable.sh
@@ -0,0 +1,74 @@
+#!/bin/sh
+# Show fts fails on old-fashioned systems.
+
+# Copyright (C) 2006-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+# Show that fts (hence du, chmod, chgrp, chown) fails when all of the
+# following are true:
+# - '.' is not readable
+# - operating on a hierarchy containing a relative name longer than PATH_MAX
+# - run on a system where gnulib's openat emulation must resort to using
+# save_cwd and restore_cwd (which fail if '.' is not readable).
+# Thus, the following du invocation should succeed on newer Linux and
+# Solaris systems, yet it must fail on systems lacking both openat and
+# /proc support. However, before coreutils-6.0 this test would fail even
+# on Linux+PROC_FS systems because its fts implementation would revert
+# unnecessarily to using FTS_NOCHDIR mode in this corner case.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ du
+
+require_perl_
+
+# ecryptfs for example uses some of the file name space
+# for encrypting filenames, so we must check dynamically.
+name_max=$(stat -f -c %l .)
+test "$name_max" -ge '200' || skip_ "NAME_MAX=$name_max is not sufficient"
+
+proc_file=/proc/self/fd
+if test ! -d $proc_file; then
+ skip_ 'This test would fail, since your system lacks /proc support.'
+fi
+
+dir=$(printf '%200s\n' ' '|tr ' ' x)
+
+# Construct a hierarchy containing a relative file with a name
+# longer than PATH_MAX.
+# for i in $(seq 52); do
+# mkdir $dir || framework_failure_
+# cd $dir || framework_failure_
+# done
+# cd $tmp || framework_failure_
+
+# Sheesh. Bash 3.1.5 can't create this hierarchy. I get
+# cd: error retrieving current directory: getcwd:
+# cannot access parent directories:
+# (all on one line).
+
+cwd=$(pwd)
+# Use perl instead:
+$PERL \
+ -e 'my $d = '$dir'; foreach my $i (1..52)' \
+ -e ' { mkdir ($d, 0700) && chdir $d or die "$!" }' \
+ || framework_failure_
+
+mkdir inaccessible || framework_failure_
+cd inaccessible || framework_failure_
+chmod 0 . || framework_failure_
+
+du -s "$cwd/$dir" > /dev/null || fail=1
+
+Exit $fail
diff --git a/tests/du/long-sloop.sh b/tests/du/long-sloop.sh
new file mode 100755
index 0000000..16da216
--- /dev/null
+++ b/tests/du/long-sloop.sh
@@ -0,0 +1,72 @@
+#!/bin/sh
+# Use du to exercise a corner of fts's FTS_LOGICAL code.
+# Show that du fails with ELOOP (Too many levels of symbolic links)
+# when it encounters that condition.
+
+# Copyright (C) 2006-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ du
+
+# Create lots of directories, each containing a single symlink
+# pointing at the next directory in the list.
+
+# This number should be larger than the number of symlinks allowed in
+# file name resolution, but not too large as a number of entries
+# in a single directory.
+n=400
+
+dir_list=$(seq $n)
+mkdir $dir_list || framework_failure_
+file=1
+i_minus_1=0
+for i in $dir_list $(expr $n + 1); do
+ case $i_minus_1 in
+ 0) ;;
+ *)
+ ln -s ../$i $i_minus_1/s || framework_failure_
+ file=$file/s;;
+ esac
+ i_minus_1=$i
+done
+echo foo > $i || framework_failure_
+
+# If a system can handle this many symlinks in a file name,
+# just skip this test.
+
+# The following also serves to record in 'err' the string
+# corresponding to strerror (ELOOP). This is necessary because while
+# Linux/libc gives 'Too many levels of symbolic links', Solaris
+# renders it as "Number of symbolic links encountered during path
+# name traversal exceeds MAXSYMLINKS".
+
+cat $file > /dev/null 2> err &&
+ skip_ 'Your system appears to be able to handle more than $n symlinks
+in file name resolution'
+too_many=$(sed 's/.*: //' err)
+
+
+# With coreutils-5.93 there was no failure.
+# With coreutils-5.94 we get the desired diagnostic:
+# du: cannot access '1/s/s/s/.../s': Too many levels of symbolic links
+du -L 1 > /dev/null 2> out1 && fail=1
+sed "s, .1/s/s/s/[/s]*',," out1 > out || framework_failure_
+
+echo "du: cannot access: $too_many" > exp || framework_failure_
+
+compare exp out || fail=1
+
+Exit $fail
diff --git a/tests/du/max-depth.sh b/tests/du/max-depth.sh
new file mode 100755
index 0000000..c3ac8c6
--- /dev/null
+++ b/tests/du/max-depth.sh
@@ -0,0 +1,39 @@
+#!/bin/sh
+# exercise du's --max-depth=N option
+
+# Copyright (C) 2010-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ du
+
+mkdir -p a/b/c/d/e || framework_failure_
+printf 'a/b/c\na/b\na\n' > exp || framework_failure_
+
+du --max-depth=2 a > out 2>err || fail=1
+
+# Remove the sizes. They vary between file systems.
+cut -f2- out > k && mv k out
+compare exp out || fail=1
+compare /dev/null err || fail=1
+
+# Repeat, but use -d 1.
+printf 'a/b\na\n' > exp || framework_failure_
+du -d 1 a > out 2>err || fail=1
+cut -f2- out > k && mv k out
+compare exp out || fail=1
+compare /dev/null err || fail=1
+
+Exit $fail
diff --git a/tests/du/move-dir-while-traversing.sh b/tests/du/move-dir-while-traversing.sh
new file mode 100755
index 0000000..aee9065
--- /dev/null
+++ b/tests/du/move-dir-while-traversing.sh
@@ -0,0 +1,99 @@
+#!/bin/sh
+# Trigger a failed assertion in coreutils-8.9 and earlier.
+
+# Copyright (C) 2011-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ du
+require_trap_signame_
+
+# We use a python-inotify script, so...
+python -m pyinotify -h > /dev/null \
+ || skip_ 'python inotify package not installed'
+
+# Move a directory "up" while du is processing its sub-directories.
+# While du is processing a hierarchy .../B/C/D/... this script
+# detects when du opens D/, and then moves C/ "up" one level
+# so that it is a sibling of B/.
+# Given the inherent race condition, we have to add enough "weight"
+# under D/ so that in most cases, the monitor performs the single
+# rename syscall before du finishes processing the subtree under D/.
+
+cat <<'EOF' > inotify-watch-for-dir-access.py
+#!/usr/bin/env python
+import pyinotify as pn
+import os,sys
+
+dir = sys.argv[1]
+dest_parent = os.path.dirname(os.path.dirname(dir))
+dest = os.path.join(dest_parent, os.path.basename(dir))
+
+class ProcessDir(pn.ProcessEvent):
+
+ def process_IN_OPEN(self, event):
+ os.rename(dir, dest)
+ sys.exit(0)
+
+ def process_default(self, event):
+ pass
+
+wm = pn.WatchManager()
+notifier = pn.Notifier(wm)
+wm.watch_transient_file(dir, pn.IN_OPEN, ProcessDir)
+sys.stdout.write('started\n')
+sys.stdout.flush()
+notifier.loop()
+EOF
+chmod a+x inotify-watch-for-dir-access.py
+
+t=T/U
+mkdir d2 || framework_failure_
+long=d/e/f/g/h/i/j/k/l/m/n/o/p/q/r/s/t/u/v/w/x/y/z
+# One iteration of this loop creates a tree with which
+# du sometimes completes its traversal before the above rename.
+# Five iterations was not enough in 2 of 7 "make -j20 check" runs on a
+# 6/12-core system. However, using "10", I saw no failure in 20 trials.
+# Using 10 iterations was not enough, either.
+# Using 50, I saw no failure in 200 trials.
+for i in $(seq 50); do
+ mkdir -p $t/3/a/b/c/$i/$long || framework_failure_
+done
+
+# Terminate any background cp process
+cleanup_() { kill $pid 2>/dev/null && wait $pid; }
+
+# Prohibit suspension, which could otherwise cause a timeout-induced FP failure.
+trap '' TSTP
+
+timeout 6 ./inotify-watch-for-dir-access.py $t/3/a/b > start-msg & pid=$!
+
+# Wait for the watcher to start...
+nonempty() { sleep $1; test -s start-msg; }
+retry_delay_ nonempty .1 5 || fail=1
+
+# The above watches for an IN_OPEN event on $t/3/a/b,
+# and when it triggers, moves the parent, $t/3/a, up one level
+# so it's directly under $t.
+
+# Before coreutils-8.10, du would abort.
+returns_ 1 du -a $t d2 2> err || fail=1
+
+# check for the new diagnostic
+printf "du: fts_read failed: $t/3/a/b: No such file or directory\n" > exp \
+ || fail=1
+compare exp err || fail=1
+
+Exit $fail
diff --git a/tests/du/no-deref.sh b/tests/du/no-deref.sh
new file mode 100755
index 0000000..afcdc5d
--- /dev/null
+++ b/tests/du/no-deref.sh
@@ -0,0 +1,33 @@
+#!/bin/sh
+# Ensure that by default, du doesn't dereference command-line symlinks.
+
+# Copyright (C) 2003-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ du
+
+mkdir -p dir/a/b || framework_failure_
+ln -s dir slink || framework_failure_
+
+
+du slink | sed 's/^[0-9][0-9]* //' > out
+cat <<\EOF > exp
+slink
+EOF
+
+compare exp out || fail=1
+
+Exit $fail
diff --git a/tests/du/no-x.sh b/tests/du/no-x.sh
new file mode 100755
index 0000000..c21f06c
--- /dev/null
+++ b/tests/du/no-x.sh
@@ -0,0 +1,49 @@
+#!/bin/sh
+# Make sure du gives the right diagnostic for a readable,
+# but inaccessible directory.
+
+# Copyright (C) 2003-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ du
+skip_if_root_
+
+mkdir -p d/no-x/y || framework_failure_
+chmod u=rw d/no-x || framework_failure_
+
+
+# This must exit nonzero.
+du d >/dev/null 2>out && fail=1
+
+prog=du
+# NOTE: this code is the same for all tests/*/no-x tests.
+# Depending on whether fts is using native fdopendir, we see one
+# of the following diagnostics (note also the /y suffix in one case):
+# prog: 'd/no-x': Permission denied
+# prog: cannot access 'd/no-x/y': Permission denied
+# prog: cannot read directory 'd/no-x': Permission denied
+# Convert either of the latter two to the first one.
+sed "s/^$prog: cannot access /$prog: /" out > t && mv t out
+sed "s/^$prog: cannot read directory /$prog: /" out > t && mv t out
+sed 's,d/no-x/y,d/no-x,' out > t && mv t out
+
+cat <<EOF > exp
+$prog: 'd/no-x': Permission denied
+EOF
+
+compare exp out || fail=1
+
+Exit $fail
diff --git a/tests/du/one-file-system.sh b/tests/du/one-file-system.sh
new file mode 100755
index 0000000..cdb868a
--- /dev/null
+++ b/tests/du/one-file-system.sh
@@ -0,0 +1,57 @@
+#!/bin/sh
+# Test for bugs in du's --one-file-system (-x) option.
+
+# Copyright (C) 2006-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ du
+cleanup_() { rm -rf "$other_partition_tmpdir"; }
+. "$abs_srcdir/tests/other-fs-tmpdir"
+
+mkdir -p b/c y/z d "$other_partition_tmpdir/x" || framework_failure_
+ln -s "$other_partition_tmpdir/x" d || framework_failure_
+
+# Due to a used-uninitialized variable, the "du -x" from coreutils-6.6
+# would not traverse into second and subsequent directories listed
+# on the command line.
+du -ax b y > t || fail=1
+sed 's/^[0-9][0-9]* //' t > out || framework_failure_
+cat <<\EOF > exp || framework_failure_
+b/c
+b
+y/z
+y
+EOF
+
+compare exp out || fail=1
+
+# "du -xL" reported a zero count for a file in a different file system,
+# instead of ignoring it.
+du -xL d > u || fail=1
+sed 's/^[0-9][0-9]* //' u > out1 || framework_failure_
+echo d > exp1 || framework_failure_
+compare exp1 out1 || fail=1
+
+# With coreutils-8.15, "du -xs FILE" would print no output.
+touch f
+for opt in -x -xs; do
+ du $opt f > u || fail=1
+ sed 's/^[0-9][0-9]* //' u > out2 || framework_failure_
+ echo f > exp2 || framework_failure_
+ compare exp2 out2 || fail=1
+done
+
+Exit $fail
diff --git a/tests/du/restore-wd.sh b/tests/du/restore-wd.sh
new file mode 100755
index 0000000..e4a87a8
--- /dev/null
+++ b/tests/du/restore-wd.sh
@@ -0,0 +1,31 @@
+#!/bin/sh
+# due to a bug in glibc's ftw.c, in some cases, nftw w/FTW_CHDIR
+# would not restore the working directory.
+
+# Copyright (C) 2003-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ du
+
+mkdir a b || framework_failure_
+
+
+# With du from coreutils-4.5.5 and 4.5.6, this would fail with
+# du: 'b': No such file or directory
+
+du a b > out || fail=1
+
+Exit $fail
diff --git a/tests/du/slash.sh b/tests/du/slash.sh
new file mode 100755
index 0000000..e61f26d
--- /dev/null
+++ b/tests/du/slash.sh
@@ -0,0 +1,33 @@
+#!/bin/sh
+# 'du /' would omit the '/' on the last line.
+
+# Copyright (C) 2003-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ du
+require_readable_root_
+
+
+du --exclude='[^/]*' -x / > out-t || fail=1
+sed 's/^[0-9][0-9]* //' out-t > out
+rm -f out-t
+cat <<\EOF > exp
+/
+EOF
+
+compare exp out || fail=1
+
+Exit $fail
diff --git a/tests/du/threshold.sh b/tests/du/threshold.sh
new file mode 100755
index 0000000..c112f08
--- /dev/null
+++ b/tests/du/threshold.sh
@@ -0,0 +1,263 @@
+#!/bin/sh
+# Exercise du's --threshold option.
+
+# Copyright (C) 2013-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ du
+
+mkdir -p a/b a/c || framework_failure_
+
+touch a/b/0 || framework_failure_
+printf '%1s' x > a/b/1 || framework_failure_
+printf '%2s' x > a/b/2 || framework_failure_
+printf '%3s' x > a/b/3 || framework_failure_
+
+Ba=$(stat --format="%B * %b" a | xargs expr)
+Bb=$(stat --format="%B * %b" a/b | xargs expr)
+Bc=$(stat --format="%B * %b" a/c | xargs expr)
+B0=$(stat --format="%B * %b" a/b/0 | xargs expr)
+B1=$(stat --format="%B * %b" a/b/1 | xargs expr)
+B2=$(stat --format="%B * %b" a/b/2 | xargs expr)
+B3=$(stat --format="%B * %b" a/b/3 | xargs expr)
+
+Sa=0 # du always assumes st_size=0 for dirs
+Sb=0
+Sc=0
+S0=$(stat --format=%s a/b/0)
+S1=$(stat --format=%s a/b/1)
+S2=$(stat --format=%s a/b/2)
+S3=$(stat --format=%s a/b/3)
+
+Bb0123=$(expr $Bb + $B0 + $B1 + $B2 + $B3)
+Sb0123=$(expr $Sb + $S0 + $S1 + $S2 + $S3)
+
+Bab0123=$(expr $Ba + $Bc + $Bb0123)
+
+# Sanity checks
+test $Ba -gt 4 || skip_ "block size of a directory is smaller than 4 bytes"
+test $Bc -gt 4 || skip_ "block size of an empty directory is smaller than 4 \
+bytes"
+test $B1 -gt 4 || skip_ "block size of small file smaller than 4 bytes"
+test $S3 -eq 3 || framework_failure_
+test $S2 -eq 2 || framework_failure_
+test $S1 -eq 1 || framework_failure_
+test $S0 -eq 0 || framework_failure_
+test $B0 -eq 0 || skip_ "block size of an empty file unequal Zero"
+# block size of a/b/1 == a/b/2
+test $B1 -eq $B2 || framework_failure_
+# a is bigger than a/b.
+test $Bab0123 -gt $Bb0123 || framework_failure_
+# a/b is bigger than empty a/c.
+test $Sb0123 -gt $Sc || framework_failure_
+test $Bb0123 -gt $Bc || framework_failure_
+
+# Exercise a bad argument: unparsable number.
+cat <<EOF > exp
+du: invalid --threshold argument 'SIZE'
+EOF
+du --threshold=SIZE a > out 2>&1 && fail=1
+compare exp out || fail=1
+
+cat <<EOF > exp
+du: invalid -t argument 'SIZE'
+EOF
+du -t SIZE a > out 2>&1 && fail=1
+compare exp out || fail=1
+
+# Exercise a bad argument: -0 is not valid.
+cat <<EOF > exp
+du: invalid --threshold argument '-0'
+EOF
+du --threshold=-0 a > out 2>&1 && fail=1
+compare exp out || fail=1
+
+du -t -0 a > out 2>&1 && fail=1
+compare exp out || fail=1
+
+du -t-0 a > out 2>&1 && fail=1
+compare exp out || fail=1
+
+# Exercise a bad argument: empty argument.
+cat <<EOF > exp
+du: invalid --threshold argument ''
+EOF
+du --threshold= a > out 2>&1 && fail=1
+compare exp out || fail=1
+
+# Exercise a bad argument: no argument.
+du --threshold > out.tmp 2>&1 && fail=1
+sed 's/argument.*/argument/; s/option.*requires/option requires/' \
+ < out.tmp > out || framework_failure_
+cat <<EOF > exp
+du: option requires an argument
+Try 'du --help' for more information.
+EOF
+compare exp out || fail=1
+rm -f out
+
+dutest ()
+{
+ args="$1"
+ exp="$2"
+
+ rm -f exp out
+
+ # Expected output.
+ if [ "$exp" = "" ] ; then
+ touch exp
+ else
+ printf "%s\n" $exp > exp
+ fi
+
+ rc=0
+ du -B1 $args a > out1 2>&1 || { cat out1 ; rc=1 ; }
+
+ # Remove the size column and sort the output.
+ cut -f2- out1 | sort > out || framework_failure_
+
+ compare exp out || { cat out1 ; rc=1 ; }
+ return $rc
+}
+
+# Check numbers around the total size of the main directory 'a'.
+# One byte greater than 'a'.
+s=$(expr $Bab0123 + 1) # block size
+dutest " -t $s" '' || fail=1
+dutest " -a -t $s" '' || fail=1
+dutest " -S -t $s" '' || fail=1
+dutest " -a -S -t $s" '' || fail=1
+dutest " -t -$s" 'a a/b a/c' || fail=1
+dutest " -a -t -$s" 'a a/b a/b/0 a/b/1 a/b/2 a/b/3 a/c' || fail=1
+dutest " -S -t -$s" 'a a/b a/c' || fail=1
+dutest " -a -S -t -$s" 'a a/b a/b/0 a/b/1 a/b/2 a/b/3 a/c' || fail=1
+
+# Exactly the size of 'a'.
+s=$Bab0123 # block size
+dutest " --th=$s" 'a' || fail=1
+dutest " -a --th=$s" 'a' || fail=1
+dutest " -S --th=$s" '' || fail=1
+dutest " -a -S --th=$s" '' || fail=1
+dutest " --th=-$s" 'a a/b a/c' || fail=1
+dutest " -a --th=-$s" 'a a/b a/b/0 a/b/1 a/b/2 a/b/3 a/c' || fail=1
+dutest " -S --th=-$s" 'a a/b a/c' || fail=1
+dutest " -a -S --th=-$s" 'a a/b a/b/0 a/b/1 a/b/2 a/b/3 a/c' || fail=1
+
+# One byte smaller than 'a'.
+s=$(expr $Bab0123 - 1) # block size
+dutest " --th=$s" 'a' || fail=1
+dutest " -a --th=$s" 'a' || fail=1
+dutest " -S --th=$s" '' || fail=1
+dutest " -a -S --th=$s" '' || fail=1
+dutest " --th=-$s" 'a/b a/c' || fail=1
+dutest " -a --th=-$s" 'a/b a/b/0 a/b/1 a/b/2 a/b/3 a/c' || fail=1
+dutest " -S --th=-$s" 'a a/b a/c' || fail=1
+dutest " -a -S --th=-$s" 'a a/b a/b/0 a/b/1 a/b/2 a/b/3 a/c' || fail=1
+
+
+# Check numbers around the total size of the sub directory 'a/b'.
+# One byte greater than 'a/b'.
+s=$(expr $Bb0123 + 1) # block size
+dutest " --th=$s" 'a' || fail=1
+dutest " -a --th=$s" 'a' || fail=1
+dutest " -S --th=$s" '' || fail=1
+dutest " -a -S --th=$s" '' || fail=1
+dutest " --th=-$s" 'a/b a/c' || fail=1
+dutest " -a --th=-$s" 'a/b a/b/0 a/b/1 a/b/2 a/b/3 a/c' || fail=1
+dutest " -S --th=-$s" 'a a/b a/c' || fail=1
+dutest " -a -S --th=-$s" 'a a/b a/b/0 a/b/1 a/b/2 a/b/3 a/c' || fail=1
+
+# Exactly the size of 'a/b'.
+s=$Bb0123 # block size
+dutest " --th=$s" 'a a/b' || fail=1
+dutest " -a --th=$s" 'a a/b' || fail=1
+dutest " -S --th=$s" 'a/b' || fail=1
+dutest " -a -S --th=$s" 'a/b' || fail=1
+dutest " --th=-$s" 'a/b a/c' || fail=1
+dutest " -a --th=-$s" 'a/b a/b/0 a/b/1 a/b/2 a/b/3 a/c' || fail=1
+dutest " -S --th=-$s" 'a a/b a/c' || fail=1
+dutest " -a -S --th=-$s" 'a a/b a/b/0 a/b/1 a/b/2 a/b/3 a/c' || fail=1
+
+# One byte smaller than 'a/b'.
+s=$(expr $Bb0123 - 1) # block size
+dutest " --th=$s" 'a a/b' || fail=1
+dutest " -a --th=$s" 'a a/b' || fail=1
+dutest " -S --th=$s" 'a/b' || fail=1
+dutest " -a -S --th=$s" 'a/b' || fail=1
+dutest " --th=-$s" 'a/c' || fail=1
+dutest " -a --th=-$s" 'a/b/0 a/b/1 a/b/2 a/b/3 a/c' || fail=1
+dutest " -S --th=-$s" 'a a/c' || fail=1
+dutest " -a -S --th=-$s" 'a a/b/0 a/b/1 a/b/2 a/b/3 a/c' || fail=1
+
+
+# Check numbers around the total size of the files a/b/[0123]'.
+echo One byte greater than 'a/b/3'.
+s=$(expr $B3 + 1) # block size
+dutest " --th=$s" 'a a/b' || fail=1
+dutest " -a --th=$s" 'a a/b' || fail=1
+dutest " -S --th=$s" 'a/b' || fail=1
+dutest " -a -S --th=$s" 'a/b' || fail=1
+dutest " --th=-$s" 'a/c' || fail=1
+dutest " -a --th=-$s" 'a/b/0 a/b/1 a/b/2 a/b/3 a/c' || fail=1
+dutest " -S --th=-$s" 'a a/c' || fail=1
+dutest " -a -S --th=-$s" 'a a/b/0 a/b/1 a/b/2 a/b/3 a/c' || fail=1
+
+# Exactly the size of 'a/b/3'.
+echo Exactly the size of 'a/b/3'.
+s=$B3 # block size
+dutest " --th=$s" 'a a/b a/c' || fail=1
+dutest " -a --th=$s" 'a a/b a/b/1 a/b/2 a/b/3 a/c' || fail=1
+dutest " -S --th=$s" 'a a/b a/c' || fail=1
+dutest " -a -S --th=$s" 'a a/b a/b/1 a/b/2 a/b/3 a/c' || fail=1
+dutest " --th=-$s" 'a/c' || fail=1
+dutest " -a --th=-$s" 'a/b/0 a/b/1 a/b/2 a/b/3 a/c' || fail=1
+dutest " -S --th=-$s" 'a a/c' || fail=1
+dutest " -a -S --th=-$s" 'a a/b/0 a/b/1 a/b/2 a/b/3 a/c' || fail=1
+
+# Exactly the size of 'a/b/2'.
+echo Exactly the size of 'a/b/2'.
+s=$B2 # block size
+dutest " --th=$s" 'a a/b a/c' || fail=1
+dutest " -a --th=$s" 'a a/b a/b/1 a/b/2 a/b/3 a/c' || fail=1
+dutest " -S --th=$s" 'a a/b a/c' || fail=1
+dutest " -a -S --th=$s" 'a a/b a/b/1 a/b/2 a/b/3 a/c' || fail=1
+dutest " --th=-$s" 'a/c' || fail=1
+dutest " -a --th=-$s" 'a/b/0 a/b/1 a/b/2 a/b/3 a/c' || fail=1
+dutest " -S --th=-$s" 'a a/c' || fail=1
+dutest " -a -S --th=-$s" 'a a/b/0 a/b/1 a/b/2 a/b/3 a/c' || fail=1
+
+# Exactly the size of 'a/b/1'.
+echo Exactly the size of 'a/b/1'.
+s=$B1 # block size
+dutest " --th=$s" 'a a/b a/c' || fail=1
+dutest " -a --th=$s" 'a a/b a/b/1 a/b/2 a/b/3 a/c' || fail=1
+dutest " -S --th=$s" 'a a/b a/c' || fail=1
+dutest " -a -S --th=$s" 'a a/b a/b/1 a/b/2 a/b/3 a/c' || fail=1
+dutest " --th=-$s" 'a/c' || fail=1
+dutest " -a --th=-$s" 'a/b/0 a/b/1 a/b/2 a/b/3 a/c' || fail=1
+dutest " -S --th=-$s" 'a a/c' || fail=1
+dutest " -a -S --th=-$s" 'a a/b/0 a/b/1 a/b/2 a/b/3 a/c' || fail=1
+
+# Exactly the size of 'a/b/0'.
+echo Exactly the size of 'a/b/0'.
+s=$B0 # block size
+dutest " --th=$s" 'a a/b a/c' || fail=1
+dutest " -a --th=$s" 'a a/b a/b/0 a/b/1 a/b/2 a/b/3 a/c' || fail=1
+dutest " -S --th=$s" 'a a/b a/c' || fail=1
+dutest " -a -S --th=$s" 'a a/b a/b/0 a/b/1 a/b/2 a/b/3 a/c' || fail=1
+# (maximum tests (-0) not possible).
+
+Exit $fail
diff --git a/tests/du/trailing-slash.sh b/tests/du/trailing-slash.sh
new file mode 100755
index 0000000..bc55fb9
--- /dev/null
+++ b/tests/du/trailing-slash.sh
@@ -0,0 +1,47 @@
+#!/bin/sh
+# Ensure that du works properly for an argument that refers to a
+# symbolic link, and that is specified with a trailing slash.
+
+# Copyright (C) 2002-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+# Before coreutils-4.5.3, it would remove a single trailing slash.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ du
+
+mkdir -p dir/1/2 || framework_failure_
+ln -s dir slink || framework_failure_
+
+
+du slink/ | sed 's/^[0-9][0-9]* //' > out
+echo === >> out
+
+# Ensure that with -L we get the same results (modulo the trailing slash
+# on the third line) even without the trailing slash on the command line.
+du -L slink | sed 's/^[0-9][0-9]* //' >> out
+cat <<\EOF > exp
+slink/1/2
+slink/1
+slink/
+===
+slink/1/2
+slink/1
+slink
+EOF
+
+compare exp out || fail=1
+
+Exit $fail
diff --git a/tests/du/two-args.sh b/tests/du/two-args.sh
new file mode 100755
index 0000000..693d53c
--- /dev/null
+++ b/tests/du/two-args.sh
@@ -0,0 +1,40 @@
+#!/bin/sh
+# Make sure 'du d/1 d/2' works.
+# That command failed with du from fileutils-4.0q.
+
+# Copyright (C) 2000-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ du
+
+# Run this test from a sub-directory one level deeper than normal,
+# so that the "du .." below doesn't traverse sibling directories
+# that may be inaccessible due concurrently-running tests.
+mkdir sub || framework_failure_
+cd sub || framework_failure_
+
+t=t
+mkdir -p $t/1 $t/2 || framework_failure_
+
+test -d $t || fail=1
+du $t/1 $t/2 > /dev/null || fail=1
+
+# Make sure 'du . $t' and 'du .. $t' work.
+# These would fail prior to fileutils-4.0y.
+du . $t > /dev/null || fail=1
+du .. $t > /dev/null || fail=1
+
+Exit $fail
diff --git a/tests/env/env-S-script.sh b/tests/env/env-S-script.sh
new file mode 100755
index 0000000..1d9b3e2
--- /dev/null
+++ b/tests/env/env-S-script.sh
@@ -0,0 +1,147 @@
+#!/bin/sh
+# Test env -S in a #! line of a script.
+
+# Copyright (C) 2018-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ env
+print_ver_ printf
+
+require_perl_
+
+# a shortcut to avoid long lines
+dir="$abs_top_builddir/src"
+
+cat <<EOF > shebang || framework_failure_
+#!$SHELL
+EOF
+cat <<\EOF >> shebang || framework_failure_
+# Execute a script as per 3 argument shebang
+# but without length limits (127 on Linux for example).
+script="$1"; shift
+shebang=$(sed -n 's/^#!//p;q' < "$script")
+interp=$(printf '%s' "$shebang" | cut -d' ' -f1)
+rest=$(printf '%s' "$shebang" | cut -s -d' ' -f2-)
+test "$rest" && exec "$interp" "$rest" "$script" "$@"
+exec "$interp" "$script" "$@"
+EOF
+chmod a+x shebang || framework_failure_
+
+# A simple shebang program to call our new "env"
+printf "#!$dir/env sh\necho hello\n" > env_test || framework_failure_
+chmod a+x env_test || framework_failure_
+
+# Verify we can run the shebang which is not the case if
+# there are spaces in $abs_top_builddir.
+./shebang ./env_test || skip_ "Error running env_test script"
+
+# env should execute 'printf' with 7 parameters:
+# 'x%sx\n', 'A', 'B' from the "-S" argument,
+# the name of the executed script, and its 3 parameters (C,D,'E F').
+# Ignoring the absolute paths, the script is:
+# #!env -S printf x%sx\n A B
+printf "#!$dir/env -S $dir/printf "'x%%sx\\n A B\n' > env1 || framework_failure_
+chmod a+x env1 || framework_failure_
+cat<<\EOF>exp1 || framework_failure_
+xAx
+xBx
+x./env1x
+xCx
+xDx
+xE Fx
+EOF
+./shebang ./env1 C D "E F" > out1 || fail=1
+compare exp1 out1 || fail=1
+
+
+# similar to the above test but with quotes, the first parameter should be
+# 'A B' and not two parameters 'A','B'.
+# Ignoring the absolute paths, the script is:
+# #!env -S printf x%sx\n "A B"
+printf "#!$dir/env -S $dir/printf "'x%%sx\\n "A B"\n' > env2 ||
+ framework_failure_
+chmod a+x env2 || framework_failure_
+cat<<\EOF>exp2 || framework_failure_
+xA Bx
+x./env2x
+EOF
+./shebang ./env2 > out2 || fail=1
+compare exp2 out2 || fail=1
+
+
+# backslash-underscore instead of spaces.
+# Ignoring the absolute paths, the script is:
+# #!env -Sprintf\_x%sx\n\_Y
+printf "#!$dir/env -S$dir/printf"'\\_x%%sx\\n\\_Y\n' > env3 ||
+ framework_failure_
+chmod a+x env3 || framework_failure_
+cat<<\EOF>exp3 || framework_failure_
+xYx
+x./env3x
+xWx
+EOF
+./shebang ./env3 W > out3 || fail=1
+compare exp3 out3 || fail=1
+
+
+
+# Test comments - The "#C D" should be ignored.
+# Ignoring the absolute paths, the script is:
+# #!env -Sprintf x%sx\n A#B #C D
+printf "#!$dir/env -S$dir/printf"' x%%sx\\n A#B #C D\n' > env4 \
+ || framework_failure_
+chmod a+x env4 || framework_failure_
+cat<<\EOF>exp4 || framework_failure_
+xA#Bx
+x./env4x
+xZx
+EOF
+./shebang ./env4 Z > out4 || fail=1
+compare exp4 out4 || fail=1
+
+
+# Test with a simple Perl usage.
+# (assume Perl is in $PATH, as it is required for the test suite).
+# Ignoring the absolute paths, the script is:
+# #!env -S perl -w -T
+# print "hello\n";
+{ printf "#!$dir/env -S $PERL -w -T\n" ;
+ printf 'print "hello\\n";\n' ; } > env5 || framework_failure_
+chmod a+x env5 || framework_failure_
+cat<<\EOF>exp5 || framework_failure_
+hello
+EOF
+./shebang ./env5 > out5 || fail=1
+compare exp5 out5 || fail=1
+
+
+# Test with a more complex Perl usage.
+# Ignoring the absolute paths, the script is:
+# #!env -S perl -mFile::Basename=basename -e "print basename(\$ARGV[0]);"
+# The backslash before the '$' is required to prevent env(1) from treating
+# $ARGV as an (invalid syntax) envvar, and pass it as-is to Perl.
+{ printf "#!$dir/env -S " ;
+ printf "$PERL -mFile::Basename=basename -e " ;
+ printf '"print basename(\\$ARGV[0]);"\n' ; } > env6 || framework_failure_
+chmod a+x env6 || framework_failure_
+# Note: the perl script does not output a newline.
+printf "env6" > exp6 || framework_failure_
+./shebang ./env6 > out6 || fail=1
+compare exp6 out6 || fail=1
+
+
+Exit $fail
diff --git a/tests/env/env-S.pl b/tests/env/env-S.pl
new file mode 100755
index 0000000..710ca82
--- /dev/null
+++ b/tests/env/env-S.pl
@@ -0,0 +1,289 @@
+#!/usr/bin/perl
+# Test 'env -S' feature
+
+# Copyright (C) 2018-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+use strict;
+
+(my $program_name = $0) =~ s|.*/||;
+my $prog = 'env';
+
+my $env = "$ENV{abs_top_builddir}/src/env";
+# Ensure no whitespace or other problematic chars in path
+$env =~ m!^([-+\@\w./]+)$!
+ or CuSkip::skip "unusual absolute builddir name; skipping this test\n";
+$env = $1;
+
+# Turn off localization of executable's output.
+@ENV{qw(LANGUAGE LANG LC_ALL)} = ('C') x 3;
+
+# This envvar is somehow set at least on macOS 11.6, and would
+# otherwise cause failure of q*, t* and more tests below. Ignore it.
+my $cf = '__CF_USER_TEXT_ENCODING';
+exists $ENV{$cf} and $env .= " -u$cf";
+# Likewise for these Cygwin env vars
+my $cf = 'SYSTEMROOT';
+exists $ENV{$cf} and $env .= " -u$cf";
+my $cf = 'WINDIR';
+exists $ENV{$cf} and $env .= " -u$cf";
+
+my @Tests =
+ (
+ # Test combination of -S and regular arguments
+ ['1', q[-ufoo A=B FOO=AR sh -c 'echo $A$FOO'], {OUT=>"BAR"}],
+ ['2', q[-ufoo -S'A=B FOO=AR sh -c "echo \\$A\\$FOO"'], {OUT=>"BAR"}],
+ ['3', q[-ufoo -S'A=B FOO=AR' sh -c 'echo $A$FOO'], {OUT=>"BAR"}],
+ ['4', q[-ufoo -S'A=B' FOO=AR sh -c 'echo $A$FOO'], {OUT=>"BAR"}],
+ ['5', q[-S'-ufoo A=B FOO=AR sh -c "echo \\$A\\$FOO"'], {OUT=>"BAR"}],
+
+ # Test quoting inside -S
+ ['q1', q[-S'-i A="B C" ]."$env'", {OUT=>"A=B C"}],
+ ['q2', q[-S"-i A='B C' ]."$env\"", {OUT=>"A=B C"}],
+ ['q3', q[-S"-i A=\"B C\" ]."$env\"", {OUT=>"A=B C"}],
+ # Test backslash-quoting inside quoting inside -S
+ ['q4', q[-S'-i A="B \" C" ]."$env'", {OUT=>'A=B " C'}],
+ ['q5', q[-S"-i A='B \\' C' ]."$env\"", {OUT=>"A=B ' C"}],
+ # Single-quotes in double-quotes and vice-versa
+ ['q6', q[-S'-i A="B'"'"'C" ]."$env'", {OUT=>"A=B'C"}],
+ ['q7', q[-S"-i A='B\\"C' ]."$env\"", {OUT=>'A=B"C'}],
+
+ # Test tab and space (note: tab here is expanded by perl
+ # and sent to the shell as ASCII 0x9 inside single-quotes).
+ ['t1', qq[-S'-i\tA="B \tC" $env'], {OUT=>"A=B \tC"}],
+ # Here '\\t' is not interpolated by perl/shell, passed as two characters
+ # (backslash, 't') to env, resulting in one argument ("A<tab>B").
+ ['t2', qq[-S'printf x%sx\\n A\\tB'], {OUT=>"xA\tBx"}],
+ # Here '\t' is interpolated by perl, passed as literal tab (ASCII 0x9)
+ # to env, resulting in two arguments ("A" <whitespace> "B").
+ ['t3', qq[-S'printf x%sx\\n A\tB'], {OUT=>"xAx\nxBx"}],
+ ['t4', qq[-S'printf x%sx\\n A \t B'], {OUT=>"xAx\nxBx"}],
+ # Ensure \v\f\r\n treated like other whitespace.
+ # From 8.30 - 8.32 these would introduce arguments to printf,
+ # and also crash ASAN builds with out of bounds access.
+ ['t5', qq[-S'printf x%sx\\n A \t B \013\f\r\n'], {OUT=>"xAx\nxBx"}],
+
+
+ # Test empty strings
+ ['m1', qq[-i -S"" A=B $env], {OUT=>"A=B"}],
+ ['m2', qq[-i -S" \t" A=B $env], {OUT=>"A=B"}],
+
+ # Test escape sequences.
+ # note: in the following, there is no interpolation by perl due
+ # to q[], and no interpolation by the shell due to single-quotes.
+ # env will receive the backslash character followed by t/f/r/n/v.
+ # Also: Perl does not recognize "\v", so use "\013" for vertical tab.
+ ['e1', q[-i -S'A="B\tC" ]."$env'", {OUT=>"A=B\tC"}],
+ ['e2', q[-i -S'A="B\fC" ]."$env'", {OUT=>"A=B\fC"}],
+ ['e3', q[-i -S'A="B\rC" ]."$env'", {OUT=>"A=B\rC"}],
+ ['e4', q[-i -S'A="B\nC" ]."$env'", {OUT=>"A=B\nC"}],
+ ['e5', q[-i -S'A="B\vC" ]."$env'", {OUT=>"A=B\013C"}],
+ ['e6', q[-i -S'A="B\$C" ]."$env'", {OUT=>'A=B$C'}],
+ ['e7', q[-i -S'A=B\$C ]."$env'", {OUT=>'A=B$C'}],
+ ['e8', q[-i -S'A="B\#C" ]."$env'", {OUT=>'A=B#C'}],
+ ['e9', q[-i -S'A="B\\\\C" ]."$env'", {OUT=>'A=B\\C'}],
+ ['e10',q[-i -S"A='B\\\\\\\\C' ]."$env\"", {OUT=>'A=B\\C'}],
+
+ # Escape in single-quoted string - passed as-is
+ # (the multiple pairs of backslashes are to survive two interpolations:
+ # by perl and then by the shell due to double-quotes).
+ ['e11',q[-i -S"A='B\\\\tC' ]."$env\"", {OUT=>'A=B\tC'}],
+ ['e12',q[-i -S"A='B\\\\#C' ]."$env\"", {OUT=>'A=B\#C'}],
+ ['e13',q[-i -S"A='B\\\\\\$C' ]."$env\"", {OUT=>'A=B\$C'}],
+ ['e14',q[-i -S"A='B\\\\\\"C' ]."$env\"", {OUT=>'A=B\"C'}],
+
+ # Special escape sequences:
+ # \_ in double-quotes is a space - result is just one envvar 'A'
+ ['e20', q[-i -S'A="B\_C=D" ]."$env'", {OUT=>'A=B C=D'}],
+ # \_ outside double-quotes is arg separator, the command to
+ # execute should be 'env env'
+ ['e21', q[-i -S'A=B]."\\_$env\\_$env'", {OUT=>"A=B"}],
+
+ # Test -C inside -S
+ ['c1', q["-S-C/ pwd"], {OUT=>"/"}],
+ ['c2', q["-S -C / pwd"], {OUT=>"/"}],
+ ['c3', q["-S --ch'dir='/ pwd"], {OUT=>"/"}],
+
+ # Test -u inside and outside -S
+ # u1,u2 - establish a baseline, without -S
+ ['u1', q[ sh -c 'echo =$FOO='], {ENV=>"FOO=BAR"}, {OUT=>"=BAR="}],
+ ['u2', q[-uFOO sh -c 'echo =$FOO='], {ENV=>"FOO=BAR"}, {OUT=>"=="}],
+ # u3,u4: ${FOO} expanded by env itself before executing sh.
+ # \\$FOO expanded by sh.
+ # ${FOO} should have value of the original environment
+ # and \\$FOO should be unset, regardless where -uFOO is used.
+ # 'u3' behavior differs from FreeBSD's but deemed preferable, in
+ # https://lists.gnu.org/r/coreutils/2018-04/msg00014.html
+ ['u3', q[-uFOO -S'sh -c "echo x${FOO}x =\\$FOO="'],
+ {ENV=>"FOO=BAR"}, {OUT=>"xBARx =="}],
+ ['u4', q[-S'-uFOO sh -c "echo x${FOO}x =\\$FOO="'],
+ {ENV=>"FOO=BAR"}, {OUT=>"xBARx =="}],
+
+ # Test ENVVAR expansion
+ ['v1', q[-i -S'A=${FOO} ]."$env'", {ENV=>"FOO=BAR"}, {OUT=>"A=BAR"}],
+ ['v2', q[-i -S'A=x${FOO}x ]."$env'", {ENV=>"FOO=BAR"}, {OUT=>"A=xBARx"}],
+ ['v3', q[-i -S'A=x${FOO}x ]."$env'", {ENV=>"FOO="}, {OUT=>"A=xx"}],
+ ['v4', q[-i -S'A=x${FOO}x ]."$env'", {OUT=>"A=xx"}],
+ ['v5', q[-i -S'A="x${FOO}x" ]."$env'", {ENV=>"FOO=BAR"}, {OUT=>"A=xBARx"}],
+ ['v6', q[-i -S'${FOO}=A ]."$env'", {ENV=>"FOO=BAR"}, {OUT=>"BAR=A"}],
+ # No expansion inside single-quotes
+ ['v7', q[-i -S"A='x\${FOO}x' ]."$env\"", {OUT=>'A=x${FOO}x'}],
+ ['v8', q[-i -S'A="${_FOO}" ]."$env'", {ENV=>"_FOO=BAR"}, {OUT=>"A=BAR"}],
+ ['v9', q[-i -S'A="${F_OO}" ]."$env'", {ENV=>"F_OO=BAR"}, {OUT=>"A=BAR"}],
+ ['v10', q[-i -S'A="${FOO1}" ]."$env'", {ENV=>"FOO1=BAR"}, {OUT=>"A=BAR"}],
+
+ # Test end-of-string '#" and '\c'
+ ['d1', q[-i -S'A=B #C=D' ]."$env", {OUT=>"A=B"}],
+ ['d2', q[-i -S'#A=B C=D' ]."$env", {OUT=>""}],
+ ['d3', q[-i -S'A=B#' ]."$env", {OUT=>"A=B#"}],
+ ['d4', q[-i -S'A=B #' ]."$env", {OUT=>"A=B"}],
+
+ ['d5', q[-i -S'A=B\cC=D' ]."$env", {OUT=>"A=B"}],
+ ['d6', q[-i -S'\cA=B C=D' ]."$env", {OUT=>""}],
+ ['d7', q[-i -S'A=B\c' ]."$env", {OUT=>"A=B"}],
+ ['d8', q[-i -S'A=B \c' ]."$env", {OUT=>"A=B"}],
+
+ ['d10', q[-S'echo FOO #BAR'], {OUT=>"FOO"}],
+ ['d11', q[-S'echo FOO \\#BAR'], {OUT=>"FOO #BAR"}],
+ ['d12', q[-S'echo FOO#BAR'], {OUT=>"FOO#BAR"}],
+
+ # Test underscore as space/separator in double/single/no quotes
+ ['s1', q[-S'printf x%sx\\n "A\\_B"'], {OUT=>"xA Bx"}],
+ ['s2', q[-S"printf x%sx\\n 'A\\_B'"], {OUT=>"xA\\_Bx"}],
+ ['s3', q[-S"printf x%sx\\n A\\_B"], {OUT=>"xAx\nxBx"}],
+ ['s4', q[-S"printf x%sx\\n A B"], {OUT=>"xAx\nxBx"}],
+ ['s5', q[-S"printf x%sx\\n A B"], {OUT=>"xAx\nxBx"}],
+ # test underscore/spaces variations -
+ # ensure they don't generate empty arguments.
+ ['s6', q[-S"\\_printf x%sx\\n FOO"], {OUT=>"xFOOx"}],
+ ['s7', q[-S"printf x%sx\\n FOO\\_"], {OUT=>"xFOOx"}],
+ ['s8', q[-S"\\_printf x%sx\\n FOO\\_"], {OUT=>"xFOOx"}],
+ ['s9', q[-S"\\_\\_printf x%sx\\n FOO\\_\\_"], {OUT=>"xFOOx"}],
+ ['s10', q[-S" printf x%sx\\n FOO"], {OUT=>"xFOOx"}],
+ ['s11', q[-S"printf x%sx\\n FOO "], {OUT=>"xFOOx"}],
+ ['s12', q[-S" printf x%sx\\n FOO "], {OUT=>"xFOOx"}],
+ ['s13', q[-S" printf x%sx\\n FOO "], {OUT=>"xFOOx"}],
+ ['s14', q[-S'printf\\_x%sx\\n\\_FOO'], {OUT=>"xFOOx"}],
+ ['s15', q[-S"printf x%sx\\n \\_ FOO"], {OUT=>"xFOOx"}],
+ ['s16', q[-S"printf x%sx\\n\\_ \\_FOO"], {OUT=>"xFOOx"}],
+ ['s17', q[-S"\\_ \\_ printf x%sx\\n FOO \\_ \\_"], {OUT=>"xFOOx"}],
+
+ # Check for empty quotes
+ ['eq1', q[-S'printf x%sx\\n A "" B'], {OUT=>"xAx\nxx\nxBx"}],
+ ['eq2', q[-S'printf x%sx\\n A"" B'], {OUT=>"xAx\nxBx"}],
+ ['eq3', q[-S'printf x%sx\\n A""B'], {OUT=>"xABx"}],
+ ['eq4', q[-S'printf x%sx\\n A ""B'], {OUT=>"xAx\nxBx"}],
+ ['eq5', q[-S'printf x%sx\\n ""'], {OUT=>"xx"}],
+ ['eq6', q[-S'printf x%sx\\n "" '], {OUT=>"xx"}],
+ ['eq10', q[-S"printf x%sx\\n A '' B"], {OUT=>"xAx\nxx\nxBx"}],
+ ['eq11', q[-S"printf x%sx\\n A'' B"], {OUT=>"xAx\nxBx"}],
+ ['eq12', q[-S"printf x%sx\\n A''B"], {OUT=>"xABx"}],
+ ['eq13', q[-S"printf x%sx\\n A ''B"], {OUT=>"xAx\nxBx"}],
+ ['eq14', q[-S'printf x%sx\\n ""'], {OUT=>"xx"}],
+ ['eq15', q[-S'printf x%sx\\n "" '], {OUT=>"xx"}],
+
+ # extreme example - such as could be found on a #! line.
+ ['p10', q[-S"\\_ \\_perl\_-w\_-T\_-e\_'print \"hello\n\";'\\_ \\_"],
+ {OUT=>"hello"}],
+
+ # Test Error Conditions
+ ['err1', q[-S'"\\c"'], {EXIT=>125},
+ {ERR=>"$prog: '\\c' must not appear in double-quoted -S string\n"}],
+ ['err2', q[-S'A=B\\'], {EXIT=>125},
+ {ERR=>"$prog: invalid backslash at end of string in -S\n"}],
+ ['err3', q[-S'"A=B\\"'], {EXIT=>125},
+ {ERR=>"$prog: no terminating quote in -S string\n"}],
+ ['err4', q[-S"'A=B\\\\'"], {EXIT=>125},
+ {ERR=>"$prog: no terminating quote in -S string\n"}],
+ ['err5', q[-S'A=B\\q'], {EXIT=>125},
+ {ERR=>"$prog: invalid sequence '\\q' in -S\n"}],
+ ['err6', q[-S'A=$B'], {EXIT=>125},
+ {ERR=>"$prog: only \${VARNAME} expansion is supported, error at: \$B\n"}],
+ ['err7', q[-S'A=${B'], {EXIT=>125},
+ {ERR=>"$prog: only \${VARNAME} expansion is supported, " .
+ "error at: \${B\n"}],
+ ['err8', q[-S'A=${B%B}'], {EXIT=>125},
+ {ERR=>"$prog: only \${VARNAME} expansion is supported, " .
+ "error at: \${B%B}\n"}],
+ ['err9', q[-S'A=${9B}'], {EXIT=>125},
+ {ERR=>"$prog: only \${VARNAME} expansion is supported, " .
+ "error at: \${9B}\n"}],
+
+ # Test incorrect shebang usage (extraneous whitespace).
+ ['err_sp2', q['-v -S cat -n'], {EXIT=>125},
+ {ERR=>"env: invalid option -- ' '\n" .
+ "env: use -[v]S to pass options in shebang lines\n" .
+ "Try 'env --help' for more information.\n"}],
+ ['err_sp3', q['-v -S cat -n'], {EXIT=>125}, # embedded tab after -v
+ {ERR=>"env: invalid option -- '\t'\n" .
+ "env: use -[v]S to pass options in shebang lines\n" .
+ "Try 'env --help' for more information.\n"}],
+
+ # Also diagnose incorrect shebang usage when failing to exec.
+ # This typically happens with:
+ #
+ # $ cat xxx
+ # #!env -v -S cat -n
+ #
+ # $ ./xxx
+ #
+ # in which case:
+ # argv[0] = env
+ # argv[1] = '-v -S cat -n'
+ # argv[2] = './xxx'
+ ['err_sp5', q['cat -n' ./xxx], {EXIT=>127},
+ {ERR=>"env: 'cat -n': No such file or directory\n" .
+ "env: use -[v]S to pass options in shebang lines\n"}],
+
+ ['err_sp6', q['cat -n' ./xxx arg], {EXIT=>127},
+ {ERR=>"env: 'cat -n': No such file or directory\n" .
+ "env: use -[v]S to pass options in shebang lines\n"}],
+ );
+
+# Append a newline to end of each expected 'OUT' string.
+my $t;
+foreach $t (@Tests)
+ {
+ my $arg1 = $t->[1];
+ my $e;
+ foreach $e (@$t)
+ {
+ $e->{OUT} .= "\n"
+ if ref $e eq 'HASH' and exists $e->{OUT} and length($e->{OUT})>0;
+ }
+ }
+
+# Repeat above tests with "--debug" option (but discard STDERR).
+my @new;
+foreach my $t (@Tests)
+{
+ #skip tests that are expected to fail
+ next if $t->[0] =~ /^err/;
+
+ my @new_t = @$t;
+ my $test_name = shift @new_t;
+ my $args = shift @new_t;
+ push @new, ["$test_name-debug",
+ "--debug " . $args,
+ @new_t,
+ {ERR_SUBST => 's/.*//ms'}];
+}
+push @Tests, @new;
+
+my $save_temps = $ENV{SAVE_TEMPS};
+my $verbose = $ENV{VERBOSE};
+
+my $fail = run_tests ($program_name, $prog, \@Tests, $save_temps, $verbose);
+exit $fail;
diff --git a/tests/env/env-null.sh b/tests/env/env-null.sh
new file mode 100755
index 0000000..fac6675
--- /dev/null
+++ b/tests/env/env-null.sh
@@ -0,0 +1,58 @@
+#!/bin/sh
+# Verify behavior of env -0 and printenv -0.
+
+# Copyright (C) 2009-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ env printenv
+
+# POSIX is clear that environ may, but need not be, sorted.
+# Environment variable values may contain newlines, which cannot be
+# observed by merely inspecting output from env.
+# Cygwin requires a minimal environment to launch new processes: execve
+# adds missing variables SYSTEMROOT and WINDIR, which show up in a
+# subsequent env. Cygwin also requires /bin to always be part of PATH,
+# and attempts to unset or reduce PATH may cause execve to fail.
+#
+# For these reasons, it is better to compare two outputs from distinct
+# programs that should be the same, rather than building an exp file.
+env -i PATH="$PATH" env -0 > out1 || fail=1
+env -i PATH="$PATH" printenv -0 > out2 || fail=1
+compare out1 out2 || fail=1
+env -i PATH="$PATH" env --null > out2 || fail=1
+compare out1 out2 || fail=1
+env -i PATH="$PATH" printenv --null > out2 || fail=1
+compare out1 out2 || fail=1
+
+# env -0 does not work if a command is specified.
+returns_ 125 env -0 echo hi > out || fail=1
+compare /dev/null out || fail=1
+
+# Test env -0 on a one-variable environment.
+printf 'a=b\nc=\0' > exp || framework_failure_
+env -i -0 "$(printf 'a=b\nc=')" > out || fail=1
+compare exp out || fail=1
+
+# Test printenv -0 on particular values.
+printf 'b\nc=\0' > exp || framework_failure_
+env "$(printf 'a=b\nc=')" printenv -0 a > out || fail=1
+compare exp out || fail=1
+returns_ 1 env -u a printenv -0 a > out || fail=1
+compare /dev/null out || fail=1
+returns_ 1 env -u b "$(printf 'a=b\nc=')" printenv -0 b a > out || fail=1
+compare exp out || fail=1
+
+Exit $fail
diff --git a/tests/env/env-signal-handler.sh b/tests/env/env-signal-handler.sh
new file mode 100755
index 0000000..7fc7fd6
--- /dev/null
+++ b/tests/env/env-signal-handler.sh
@@ -0,0 +1,126 @@
+#!/bin/sh
+# Test env --default-signal=PIPE feature.
+
+# Copyright (C) 2019-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ env seq test timeout printf
+trap_sigpipe_or_skip_
+
+# /bin/sh has an intermittent failure in ignoring SIGPIPE on OpenIndiana 11
+# so we require bash as discussed at:
+# https://lists.gnu.org/archive/html/coreutils/2020-03/msg00004.html
+require_bash_as_SHELL_
+
+# Paraphrasing https://bugs.gnu.org/34488#8:
+# POSIX requires that sh started with an inherited ignored SIGPIPE must
+# silently ignore all attempts from within the shell to restore SIGPIPE
+# handling to child processes of the shell:
+#
+# $ (trap '' PIPE; bash -c 'trap - PIPE; seq inf | head -n1')
+# 1
+# seq: write error: Broken pipe
+#
+# With 'env --default-signal=PIPE', the signal handler can be reset to its
+# default.
+
+# Baseline Test - default signal handler
+# --------------------------------------
+# Ensure this results in a "broken pipe" error (the first 'trap'
+# sets SIGPIPE to ignore, and the second 'trap' becomes a no-op instead
+# of resetting SIGPIPE to its default). Upon a SIGPIPE 'seq' will not be
+# terminated, instead its write(2) call will return an error.
+(trap '' PIPE; $SHELL -c 'trap - PIPE; seq 999999 2>err1t | head -n1 > out1')
+
+# The exact broken pipe message depends on the operating system, just ensure
+# there was a 'write error' message in stderr:
+sed 's/^\(seq: write error:\) .*/\1/' err1t > err1 || framework_failure_
+
+printf "1\n" > exp-out || framework_failure_
+printf "seq: write error:\n" > exp-err1 || framework_failure_
+
+compare exp-out out1 || framework_failure_
+compare exp-err1 err1 || framework_failure_
+
+
+# env test - default signal handler
+# ---------------------------------
+# With env resetting the signal handler to its defaults, there should be no
+# error message (because the default SIGPIPE action is to terminate the
+# 'seq' program):
+(trap '' PIPE;
+ env --default-signal=PIPE \
+ $SHELL -c 'trap - PIPE; seq 999999 2>err2 | head -n1 > out2')
+
+compare exp-out out2 || fail=1
+compare /dev/null err2 || fail=1
+
+# env test - default signal handler (3)
+# -------------------------------------
+# Repeat the previous test, using --default-signal with no signal names,
+# i.e., all signals.
+(trap '' PIPE;
+ env --default-signal \
+ $SHELL -c 'trap - PIPE; seq 999999 2>err4 | head -n1 > out4')
+
+compare exp-out out4 || fail=1
+compare /dev/null err4 || fail=1
+
+# env test - block signal handler
+env --block-signal true || fail=1
+
+env_ignore_delay_()
+{
+ local delay="$1"
+
+ # The first 'env' is just to ensure timeout is not a shell built-in.
+ env timeout --verbose --kill-after=.1 --signal=INT $delay \
+ env $env_opt sleep 10 > /dev/null 2>outt
+ # check only the first two lines from stderr, which are printed by timeout.
+ # (operating systems might add more messages, like "killed").
+ sed -n '1,2p' outt > out || framework_failure_
+ compare exp out
+}
+
+# Baseline test - ignore signal handler
+# -------------------------------------
+# Terminate 'sleep' with SIGINT
+# (SIGINT's default action is to terminate a program).
+cat <<\EOF >exp || framework_failure_
+timeout: sending signal INT to command 'env'
+EOF
+env_opt='' retry_delay_ env_ignore_delay_ .1 6 || fail=1
+
+# env test - ignore signal handler
+# --------------------------------
+# Use env to ignore SIGINT - "sleep" should continue running
+# after timeout sends SIGINT, and be killed using SIGKILL.
+cat <<\EOF >exp || framework_failure_
+timeout: sending signal INT to command 'env'
+timeout: sending signal KILL to command 'env'
+EOF
+env_opt='--ignore-signal=INT' retry_delay_ env_ignore_delay_ .1 6 || fail=1
+env_opt='--ignore-signal' retry_delay_ env_ignore_delay_ .1 6 || fail=1
+
+# env test --list-signal-handling
+env --default-signal --ignore-signal=INT --list-signal-handling true \
+ 2> err8t || fail=1
+sed 's/(.*)/()/' err8t > err8 || framework_failure_
+env printf 'INT (): IGNORE\n' > exp-err8 || framework_failure_
+compare exp-err8 err8 || fail=1
+
+
+Exit $fail
diff --git a/tests/env/env.sh b/tests/env/env.sh
new file mode 100755
index 0000000..25241af
--- /dev/null
+++ b/tests/env/env.sh
@@ -0,0 +1,166 @@
+#!/bin/sh
+# Verify behavior of env.
+
+# Copyright (C) 2009-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ env pwd nice
+
+# A simple shebang program to call "echo" from symlinks like "./-u" or "./--".
+echo "#!$abs_top_builddir/src/echo simple_echo" > simple_echo \
+ || framework_failure_
+chmod a+x simple_echo || framework_failure_
+
+# Verify we can run the shebang which is not the case if
+# there are spaces in $abs_top_builddir.
+./simple_echo || skip_ "Error running simple_echo script"
+
+# Verify clearing the environment
+a=1
+export a
+env - > out || fail=1
+compare /dev/null out || fail=1
+env -i > out || fail=1
+compare /dev/null out || fail=1
+env -u a -i -u a -- > out || fail=1
+compare /dev/null out || fail=1
+env -i -- a=b > out || fail=1
+echo a=b > exp || framework_failure_
+compare exp out || fail=1
+
+# These tests verify exact status of internal failure.
+returns_ 125 env --- || fail=1 # unknown option
+returns_ 125 env -u || fail=1 # missing option argument
+returns_ 2 env sh -c 'exit 2' || fail=1 # exit status propagation
+returns_ 126 nice . && { returns_ 126 env . || fail=1; } # invalid command
+returns_ 127 env no_such || fail=1 # no such command
+
+# POSIX is clear that environ may, but need not be, sorted.
+# Environment variable values may contain newlines, which cannot be
+# observed by merely inspecting output from env.
+# Cygwin requires a minimal environment to launch new processes: execve
+# adds missing variables SYSTEMROOT and WINDIR, which show up in a
+# subsequent env. Cygwin also requires /bin to always be part of PATH,
+# and attempts to unset or reduce PATH may cause execve to fail.
+#
+# For these reasons, it is more portable to grep that our desired changes
+# took place, rather than comparing output of env over an entire environment.
+if env | grep '^ENV_TEST' >/dev/null ; then
+ skip_ "environment has potential interference from ENV_TEST*"
+fi
+
+ENV_TEST1=a
+export ENV_TEST1
+>out || framework_failure_
+env ENV_TEST2= > all || fail=1
+grep '^ENV_TEST' all | LC_ALL=C sort >> out || framework_failure_
+env -u ENV_TEST1 ENV_TEST3=c > all || fail=1
+grep '^ENV_TEST' all | LC_ALL=C sort >> out || framework_failure_
+env ENV_TEST1=b > all || fail=1
+grep '^ENV_TEST' all | LC_ALL=C sort >> out || framework_failure_
+env ENV_TEST2= env > all || fail=1
+grep '^ENV_TEST' all | LC_ALL=C sort >> out || framework_failure_
+env -u ENV_TEST1 ENV_TEST3=c env > all || fail=1
+grep '^ENV_TEST' all | LC_ALL=C sort >> out || framework_failure_
+env ENV_TEST1=b env > all || fail=1
+grep '^ENV_TEST' all | LC_ALL=C sort >> out || framework_failure_
+cat <<EOF >exp || framework_failure_
+ENV_TEST1=a
+ENV_TEST2=
+ENV_TEST3=c
+ENV_TEST1=b
+ENV_TEST1=a
+ENV_TEST2=
+ENV_TEST3=c
+ENV_TEST1=b
+EOF
+compare exp out || fail=1
+
+# PATH modifications affect exec.
+mkdir unlikely_name || framework_failure_
+cat <<EOF > unlikely_name/also_unlikely || framework_failure_
+#!/bin/sh
+echo pass
+EOF
+chmod +x unlikely_name/also_unlikely || framework_failure_
+returns_ 127 env also_unlikely || fail=1
+test x$(PATH=$PATH:unlikely_name env also_unlikely) = xpass || fail=1
+test x$(env PATH="$PATH":unlikely_name also_unlikely) = xpass || fail=1
+
+# Explicitly put . on the PATH for the rest of this test.
+PATH=$PATH:
+export PATH
+
+# Use -- to end options (but not variable assignments).
+# On some systems, execve("-i") invokes a shebang script ./-i on PATH as
+# '/bin/sh -i', rather than '/bin/sh -- -i', which doesn't do what we want.
+# Avoid the issue by using a shebang to 'echo' passing a second parameter
+# before the '-i'. See the definition of simple_echo before.
+# Test -u, rather than -i, to minimize PATH problems.
+ln -s "simple_echo" ./-u || framework_failure_
+case $(env -u echo echo good) in
+ good) ;;
+ *) fail=1 ;;
+esac
+case $(env -u echo -- echo good) in
+ good) ;;
+ *) fail=1 ;;
+esac
+case $(env -- -u pass) in
+ *pass) ;;
+ *) fail=1 ;;
+esac
+
+# After options have ended, the first argument not containing = is a program.
+returns_ 127 env a=b -- true || fail=1
+ln -s "simple_echo" ./-- || framework_failure_
+case $(env a=b -- true || echo fail) in
+ *true) ;;
+ *) fail=1 ;;
+esac
+
+# No way to directly invoke program name containing =.
+cat <<EOF >./c=d || framework_failure_
+#!/bin/sh
+echo pass
+EOF
+chmod +x c=d || framework_failure_
+test "x$(env c=d echo fail)" = xfail || fail=1
+test "x$(env -- c=d echo fail)" = xfail || fail=1
+test "x$(env ./c=d echo fail)" = xfail || fail=1
+test "x$(env sh -c 'exec "$@"' sh c=d echo fail)" = xpass || fail=1
+test "x$(sh -c '\c=d echo fail')" = xpass && #dash 0.5.4 fails so check first
+ { test "x$(env sh -c '\c=d echo fail')" = xpass || fail=1; }
+
+# catch unsetenv failure, broken through coreutils 8.0
+returns_ 125 env -u a=b true || fail=1
+returns_ 125 env -u '' true || fail=1
+
+# Verify changing directory.
+mkdir empty || framework_failure_
+returns_ 125 env --chdir=empty/nonexistent true || fail=1
+returns_ 125 env -C empty 2>out || fail=1
+printf '%s\n' \
+ 'env: must specify command with --chdir (-C)' \
+ "Try 'env --help' for more information." > exp ||
+ framework_failure_
+compare exp out || fail=1
+exp=$(cd empty && env pwd) || framework_failure_
+got=$(env --chdir=empty pwd) || fail=1
+test "$exp" = "$got" || fail=1
+
+Exit $fail
diff --git a/tests/envvar-check b/tests/envvar-check
new file mode 100644
index 0000000..0c9a730
--- /dev/null
+++ b/tests/envvar-check
@@ -0,0 +1,63 @@
+# -*- sh -*-
+# Check environment variables for sane values while testing.
+
+# Copyright (C) 2000-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+if (FOO=FOO; unset FOO) >/dev/null 2>&1; then
+ as_unset=unset
+else
+ as_unset=false
+fi
+
+envvar_check_fail=0
+vars='
+ _POSIX2_VERSION
+ _STDBUF_E
+ _STDBUF_I
+ _STDBUF_O
+ BASH_ENV
+ BLOCKSIZE
+ BLOCK_SIZE
+ CDPATH
+ COLUMNS
+ DF_BLOCK_SIZE
+ DU_BLOCK_SIZE
+ ENV
+ LANGUAGE
+ LS_BLOCK_SIZE
+ LS_COLORS
+ OMP_NUM_THREADS
+ POSIXLY_CORRECT
+ QUOTING_STYLE
+ SIMPLE_BACKUP_SUFFIX
+ TABSIZE
+ TERM
+ COLORTERM
+ TIME_STYLE
+ TMPDIR
+ VERSION_CONTROL
+'
+for var in $vars
+do
+ $as_unset $var
+ if eval test \"\${$var+set}\" = set; then
+ echo "$0: the $var environment variable is set --" \
+ ' unset it and rerun this test' >&2
+ envvar_check_fail=1
+ fi
+done
+
+test "$envvar_check_fail" = 1 && exit 1
diff --git a/tests/expr/expr-multibyte.pl b/tests/expr/expr-multibyte.pl
new file mode 100755
index 0000000..4d763d6
--- /dev/null
+++ b/tests/expr/expr-multibyte.pl
@@ -0,0 +1,226 @@
+#!/usr/bin/perl
+# Exercise expr with multibyte input
+
+# Copyright (C) 2017-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+use strict;
+
+(my $ME = $0) =~ s|.*/||;
+
+my $limits = getlimits ();
+my $UINTMAX_OFLOW = $limits->{UINTMAX_OFLOW};
+
+(my $program_name = $0) =~ s|.*/||;
+my $prog = 'expr';
+
+my $locale = $ENV{LOCALE_FR_UTF8};
+! defined $locale || $locale eq 'none'
+ and CuSkip::skip "$ME: this test requires FR-UTF8 locale\n";
+
+
+=pod
+ἔκφρασις (ekphrasis) - "expression" in Ancient Greek.
+=cut
+my $expression = "\x{1F14}\x{3BA}\x{3C6}\x{3C1}\x{3B1}\x{3C3}\x{3B9}\x{3C2}";
+
+
+## NOTE about tests locales:
+## Tests starting with 'mb' will have {ENV=>"LC_ALL=$locale"}
+## added to them automatically - results are multibyte-aware.
+## Tests starting with 'sb' have the same input but will be
+## run under C locale and will be treated as single-bytes.
+## This enables interleaving C/UTF8 tests
+## (for easier comparison of expected results).
+
+my @Tests =
+ (
+ ### length expressions ###
+
+ # sanity check
+ ['mb-l1', 'length abcdef', {OUT=>"6"}],
+ ['st-l1', 'length abcdef', {OUT=>"6"}],
+
+ # A single multibyte character in the beginning of the string
+ # \xCE\xB1 is UTF-8 for "U+03B1 GREEK SMALL LETTER ALPHA"
+ ['mb-l2', "length \xCE\xB1bcdef", {OUT=>"6"}],
+ ['st-l2', "length \xCE\xB1bcdef", {OUT=>"7"}],
+
+ # A single multibyte character in the middle of the string
+ # \xCE\xB4 is UTF-8 for "U+03B4 GREEK SMALL LETTER DELTA"
+ ['mb-l3', "length abc\xCE\xB4ef", {OUT=>"6"}],
+ ['st-l3', "length abc\xCE\xB4ef", {OUT=>"7"}],
+
+ # A single multibyte character in the end of the string
+ ['mb-l4', "length fedcb\xCE\xB1", {OUT=>"6"}],
+ ['st-l4', "length fedcb\xCE\xB1", {OUT=>"7"}],
+
+ # A invalid multibyte sequence
+ ['mb-l5', "length \xB1aaa", {OUT=>"4"}],
+ ['st-l5', "length \xB1aaa", {OUT=>"4"}],
+
+ # An incomplete multibyte sequence at the end of the string
+ ['mb-l6', "length aaa\xCE", {OUT=>"4"}],
+ ['st-l6', "length aaa\xCE", {OUT=>"4"}],
+
+ # An incomplete multibyte sequence at the end of the string
+ ['mb-l7', "length $expression", {OUT=>"8"}],
+ ['st-l7', "length $expression", {OUT=>"17"}],
+
+
+
+ ### index expressions ###
+
+ # sanity check
+ ['mb-i1', 'index abcdef fb', {OUT=>"2"}],
+ ['st-i1', 'index abcdef fb', {OUT=>"2"}],
+
+ # Search for a single-octet
+ ['mb-i2', "index \xCE\xB1bc\xCE\xB4ef b", {OUT=>"2"}],
+ ['st-i2', "index \xCE\xB1bc\xCE\xB4ef b", {OUT=>"3"}],
+ ['mb-i3', "index \xCE\xB1bc\xCE\xB4ef f", {OUT=>"6"}],
+ ['st-i3', "index \xCE\xB1bc\xCE\xB4ef f", {OUT=>"8"}],
+
+ # Search for multibyte character.
+ # In the C locale, the search string is treated as two octets.
+ # the first of them (\xCE) matches the first octet of the input string.
+ ['mb-i4', "index \xCE\xB1bc\xCE\xB4ef \xCE\xB4", {OUT=>"4"}],
+ ['st-i4', "index \xCE\xB1bc\xCE\xB4ef \xCE\xB4", {OUT=>"1"}],
+
+ # Invalid multibyte sequence in the input string, treated as a single octet.
+ ['mb-i5', "index \xCEbc\xCE\xB4ef \xCE\xB4", {OUT=>"4"}],
+ ['st-i5', "index \xCEbc\xCE\xB4ef \xCE\xB4", {OUT=>"1"}],
+
+ # Invalid multibyte sequence in the search string, treated as a single octet.
+ # In multibyte locale, there should be no match, expr returns and prints
+ # zero, and terminates with exit-code 1 (as per POSIX).
+ ['mb-i6', "index \xCE\xB1bc\xCE\xB4ef \xB4", {OUT=>"0"}, {EXIT=>1}],
+ ['st-i6', "index \xCE\xB1bc\xCE\xB4ef \xB4", {OUT=>"6"}],
+
+ # Edge-case: invalid multibyte sequence BOTH in the input string
+ # and in the search string: expr should find a match.
+ ['mb-i7', "index \xCE\xB1bc\xB4ef \xB4", {OUT=>"4"}],
+
+
+ ### substr expressions ###
+
+ # sanity check
+ ['mb-s1', 'substr abcdef 2 3', {OUT=>"bcd"}],
+ ['st-s1', 'substr abcdef 2 3', {OUT=>"bcd"}],
+
+ ['mb-s2', "substr \xCE\xB1bc\xCE\xB4ef 1 1", {OUT=>"\xCE\xB1"}],
+ ['st-s2', "substr \xCE\xB1bc\xCE\xB4ef 1 1", {OUT=>"\xCE"}],
+
+ ['mb-s3', "substr \xCE\xB1bc\xCE\xB4ef 3 2", {OUT=>"c\xCE\xB4"}],
+ ['st-s3', "substr \xCE\xB1bc\xCE\xB4ef 3 2", {OUT=>"bc"}],
+
+ ['mb-s4', "substr \xCE\xB1bc\xCE\xB4ef 4 1", {OUT=>"\xCE\xB4"}],
+ ['st-s4', "substr \xCE\xB1bc\xCE\xB4ef 4 1", {OUT=>"c"}],
+
+ ['mb-s5', "substr \xCE\xB1bc\xCE\xB4ef 4 2", {OUT=>"\xCE\xB4e"}],
+ ['st-s5', "substr \xCE\xB1bc\xCE\xB4ef 4 2", {OUT=>"c\xCE"}],
+
+ ['mb-s6', "substr \xCE\xB1bc\xCE\xB4ef 6 1", {OUT=>"f"}],
+ ['st-s6', "substr \xCE\xB1bc\xCE\xB4ef 6 1", {OUT=>"\xB4"}],
+
+ ['mb-s7', "substr \xCE\xB1bc\xCE\xB4ef 7 1", {OUT=>""}, {EXIT=>1}],
+ ['st-s7', "substr \xCE\xB1bc\xCE\xB4ef 7 1", {OUT=>"e"}],
+
+ # Invalid multibyte sequences
+ ['mb-s8', "substr \xCE\xB1bc\xB4ef 3 3", {OUT=>"c\xB4e"}],
+ ['st-s8', "substr \xCE\xB1bc\xB4ef 3 3", {OUT=>"bc\xB4"}],
+
+
+ ### match expressions ###
+
+ # sanity check
+ ['mb-m1', 'match abcdef ab', {OUT=>"2"}],
+ ['st-m1', 'match abcdef ab', {OUT=>"2"}],
+ ['mb-m2', 'match abcdef "\(ab\)"', {OUT=>"ab"}],
+ ['st-m2', 'match abcdef "\(ab\)"', {OUT=>"ab"}],
+
+ # The regex engine should match the '.' to the first multibyte character.
+ ['mb-m3', "match \xCE\xB1bc\xCE\xB4ef .bc", {OUT=>"3"}],
+ ['st-m3', "match \xCE\xB1bc\xCE\xB4ef .bc", {OUT=>"0"}, {EXIT=>1}],
+
+ # The opposite of the previous test: two dots should only match
+ # the two octets in single-byte locale.
+ ['mb-m4', "match \xCE\xB1bc\xCE\xB4ef ..bc", {OUT=>"0"}, {EXIT=>1}],
+ ['st-m4', "match \xCE\xB1bc\xCE\xB4ef ..bc", {OUT=>"4"}],
+
+ # Match with grouping - a single dot should return the two octets
+ ['mb-m5', "match \xCE\xB1bc\xCE\xB4ef '\\(.b\\)c'", {OUT=>"\xCE\xB1b"}],
+ ['st-m5', "match \xCE\xB1bc\xCE\xB4ef '\\(.b\\)c'", {OUT=>""}, {EXIT=>1}],
+
+ # Invalid multibyte sequences - regex should not match in multibyte locale
+ # (POSIX requirement)
+ ['mb-m6', "match \xCEbc\xCE\xB4ef '\\(.\\)'", {OUT=>""}, {EXIT=>1}],
+ ['st-m6', "match \xCEbc\xCE\xB4ef '\\(.\\)'", {OUT=>"\xCE"}],
+
+
+ # Character classes: in the multibyte case, the regex engine understands
+ # there is a single multibyte character in the brackets.
+ # In the single byte case, the regex engine sees two octets in the character
+ # class ('\xCE' and '\xB1') - and it matches the first one.
+ ['mb-m7', "match \xCE\xB1bc\xCE\xB4e '\\([\xCE\xB1]\\)'", {OUT=>"\xCE\xB1"}],
+ ['st-m7', "match \xCE\xB1bc\xCE\xB4e '\\([\xCE\xB1]\\)'", {OUT=>"\xCE"}],
+
+ );
+
+
+# Append a newline to end of each expected 'OUT' string.
+my $t;
+foreach $t (@Tests)
+ {
+ my $arg1 = $t->[1];
+ my $e;
+ foreach $e (@$t)
+ {
+ $e->{OUT} .= "\n"
+ if ref $e eq 'HASH' and exists $e->{OUT};
+ }
+ }
+
+
+# Force multibyte locale in all tests.
+#
+# NOTE about the ERR_SUBST:
+# The error tests above (e1/e2/e3/e4) expect error messages in C locale
+# having single-quote character (ASCII 0x27).
+# In UTF-8 locale, the error messages will use:
+# 'LEFT SINGLE QUOTATION MARK' (U+2018) (UTF8: 0xE2 0x80 0x98)
+# 'RIGHT SINGLE QUOTATION MARK' (U+2019) (UTF8: 0xE2 0x80 0x99)
+# So we replace them with ascii single-quote and the results will
+# match the expected error string.
+if ($locale ne 'C')
+ {
+ my @new;
+ foreach my $t (@Tests)
+ {
+ my ($tname) = @$t;
+ if ($tname =~ /^mb/)
+ {
+ push @$t, ({ENV => "LC_ALL=$locale"},
+ {ERR_SUBST => "s/\xe2\x80[\x98\x99]/'/g"});
+ }
+ }
+ }
+
+
+my $save_temps = $ENV{DEBUG};
+my $verbose = $ENV{VERBOSE};
+
+my $fail = run_tests ($program_name, $prog, \@Tests, $save_temps, $verbose);
+exit $fail;
diff --git a/tests/expr/expr.pl b/tests/expr/expr.pl
new file mode 100755
index 0000000..f4863b1
--- /dev/null
+++ b/tests/expr/expr.pl
@@ -0,0 +1,238 @@
+#!/usr/bin/perl
+# Basic tests for "expr".
+
+# Copyright (C) 2001-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+use strict;
+
+(my $program_name = $0) =~ s|.*/||;
+my $prog = 'expr';
+
+# Turn off localization of executable's output.
+@ENV{qw(LANGUAGE LANG LC_ALL)} = ('C') x 3;
+
+my $mb_locale = $ENV{LOCALE_FR_UTF8};
+! defined $mb_locale || $mb_locale eq 'none'
+ and $mb_locale = 'C';
+
+my $big = '98782897298723498732987928734';
+my $big_p1 = '98782897298723498732987928735';
+my $big_sum = '197565794597446997465975857469';
+my $big_prod = '9758060798730154302876482828124348356960410232492450771490';
+
+my @Tests =
+ (
+ ['a', '5 + 6', {OUT => '11'}],
+ ['b', '5 - 6', {OUT => '-1'}],
+ ['c', '5 \* 6', {OUT => '30'}],
+ ['d', '100 / 6', {OUT => '16'}],
+ ['e', '100 % 6', {OUT => '4'}],
+ ['f', '3 + -2', {OUT => '1'}],
+ ['g', '-2 + -2', {OUT => '-4'}],
+
+ # Verify option processing.
+ # Added when option processing broke in the 7.0 beta release
+ ['opt1', '-- -11 + 12', {OUT => '1'}],
+ ['opt2', '-11 + 12', {OUT => '1'}],
+ ['opt3', '-- -1 + 2', {OUT => '1'}],
+ ['opt4', '-1 + 2', {OUT => '1'}],
+ # This evoked a syntax error diagnostic before 2.0.12.
+ ['opt5', '-- 2 + 2', {OUT => '4'}],
+
+ ['paren1', '\( 100 % 6 \)', {OUT => '4'}],
+ ['paren2', '\( 100 % 6 \) - 8', {OUT => '-4'}],
+ ['paren3', '9 / \( 100 % 6 \) - 8', {OUT => '-6'}],
+ ['paren4', '9 / \( \( 100 % 6 \) - 8 \)', {OUT => '-2'}],
+ ['paren5', '9 + \( 100 % 6 \)', {OUT => '13'}],
+
+ # Before 2.0.12, this would output '1'.
+ ['0bang', '00 \< 0!', {OUT => '0'}, {EXIT => 1}],
+
+ # In 5.1.3 and earlier, these would exit with status 0.
+ ['00', '00', {OUT => '00'}, {EXIT => 1}],
+ ['minus0', '-0', {OUT => '-0'}, {EXIT => 1}],
+
+ # In 5.1.3 and earlier, these would report errors.
+ ['andand', '0 \& 1 / 0', {OUT => '0'}, {EXIT => 1}],
+ ['oror', '1 \| 1 / 0', {OUT => '1'}, {EXIT => 0}],
+
+ # In 5.1.3 and earlier, this would output the empty string.
+ ['orempty', '"" \| ""', {OUT => '0'}, {EXIT => 1}],
+
+
+ # This erroneously succeeded and output '3' before 2.0.12.
+ ['fail-a', '3 + -', {ERR => "$prog: non-integer argument\n"},
+ {EXIT => 2}],
+
+ # This erroneously succeeded before 5.3.1.
+ ['bigcmp', '-- -2417851639229258349412352 \< 2417851639229258349412352',
+ {OUT => '1'}, {EXIT => 0}],
+
+ # In 5.94 and earlier, anchors incorrectly matched newlines.
+ ['anchor', "'a\nb' : 'a\$'", {OUT => '0'}, {EXIT => 1}],
+
+ # In 8.32, \( ... \) that did not match caused memory errors.
+ ['emptysub', '"a" : "\\(b\\)*"', {OUT => ''}, {EXIT => 1}],
+
+ # These tests are taken from grep/tests/bre.tests.
+ ['bre1', '"abc" : "a\\(b\\)c"', {OUT => 'b'}],
+ ['bre2', '"a(" : "a("', {OUT => '2'}],
+ ['bre3', '_ : "a\\("',
+ {ERR => "$prog: Unmatched ( or \\(\n"}, {EXIT => 2}],
+ ['bre4', '_ : "a\\(b"',
+ {ERR => "$prog: Unmatched ( or \\(\n"}, {EXIT => 2}],
+ ['bre5', '"a(b" : "a(b"', {OUT => '3'}],
+ ['bre6', '"a)" : "a)"', {OUT => '2'}],
+ ['bre7', '_ : "a\\)"',
+ {ERR => "$prog: Unmatched ) or \\)\n"}, {EXIT => 2}],
+ ['bre8', '_ : "\\)"',
+ {ERR => "$prog: Unmatched ) or \\)\n"}, {EXIT => 2}],
+ ['bre9', '"ab" : "a\\(\\)b"', {OUT => ''}, {EXIT => 1}],
+ ['bre10', '"a^b" : "a^b"', {OUT => '3'}],
+ ['bre11', '"a\$b" : "a\$b"', {OUT => '3'}],
+ ['bre12', '"" : "\\($\\)\\(^\\)"', {OUT => ''}, {EXIT => 1}],
+ ['bre13', '"b" : "a*\\(^b\$\\)c*"', {OUT => 'b'}],
+ ['bre14', '"X|" : "X\\(|\\)" : "(" "X|" : "X\\(|\\)" ")"', {OUT => '1'}],
+ ['bre15', '"X*" : "X\\(*\\)" : "(" "X*" : "X\\(*\\)" ")"', {OUT => '1'}],
+ ['bre16', '"abc" : "\\(\\)"', {OUT => ''}, {EXIT => 1}],
+ ['bre17', '"{1}a" : "\\(\\{1\\}a\\)"', {OUT => '{1}a'}],
+ ['bre18', '"X*" : "X\\(*\\)" : "^*"', {OUT => '1'}],
+ ['bre19', '"{1}" : "^\\{1\\}"', {OUT => '3'}],
+ ['bre20', '"{" : "{"', {OUT => '1'}],
+ ['bre21', '"abbcbd" : "a\\(b*\\)c\\1d"', {OUT => ''}, {EXIT => 1}],
+ ['bre22', '"abbcbbbd" : "a\\(b*\\)c\\1d"', {OUT => ''}, {EXIT => 1}],
+ ['bre23', '"abc" : "\\(.\\)\\1"', {OUT => ''}, {EXIT => 1}],
+ ['bre24', '"abbccd" : "a\\(\\([bc]\\)\\2\\)*d"', {OUT => 'cc'}],
+ ['bre25', '"abbcbd" : "a\\(\\([bc]\\)\\2\\)*d"',
+ {OUT => ''}, {EXIT => 1}],
+ ['bre26', '"abbbd" : "a\\(\\(b\\)*\\2\\)*d"', {OUT => 'bbb'}],
+ ['bre27', '"aabcd" : "\\(a\\)\\1bcd"', {OUT => 'a'}],
+ ['bre28', '"aabcd" : "\\(a\\)\\1bc*d"', {OUT => 'a'}],
+ ['bre29', '"aabd" : "\\(a\\)\\1bc*d"', {OUT => 'a'}],
+ ['bre30', '"aabcccd" : "\\(a\\)\\1bc*d"', {OUT => 'a'}],
+ ['bre31', '"aabcccd" : "\\(a\\)\\1bc*[ce]d"', {OUT => 'a'}],
+ ['bre32', '"aabcccd" : "\\(a\\)\\1b\\(c\\)*cd\$"', {OUT => 'a'}],
+ ['bre33', '"a*b" : "a\\(*\\)b"', {OUT => '*'}],
+ ['bre34', '"ab" : "a\\(**\\)b"', {OUT => ''}, {EXIT => 1}],
+ ['bre35', '"ab" : "a\\(***\\)b"', {OUT => ''}, {EXIT => 1}],
+ ['bre36', '"*a" : "*a"', {OUT => '2'}],
+ ['bre37', '"a" : "**a"', {OUT => '1'}],
+ ['bre38', '"a" : "***a"', {OUT => '1'}],
+ ['bre39', '"ab" : "a\\{1\\}b"', {OUT => '2'}],
+ ['bre40', '"ab" : "a\\{1,\\}b"', {OUT => '2'}],
+ ['bre41', '"aab" : "a\\{1,2\\}b"', {OUT => '3'}],
+ ['bre42', '_ : "a\\{1"',
+ {ERR => "$prog: Unmatched \\{\n"}, {EXIT => 2}],
+ ['bre43', '_ : "a\\{1a"',
+ {ERR => "$prog: Unmatched \\{\n"}, {EXIT => 2}],
+ ['bre44', '_ : "a\\{1a\\}"',
+ {ERR => "$prog: Invalid content of \\{\\}\n"}, {EXIT => 2}],
+ ['bre45', '"a" : "a\\{,2\\}"', {OUT => '1'}],
+ ['bre46', '"a" : "a\\{,\\}"', {OUT => '1'}],
+ ['bre47', '_ : "a\\{1,x\\}"',
+ {ERR => "$prog: Invalid content of \\{\\}\n"}, {EXIT => 2}],
+ ['bre48', '_ : "a\\{1,x"',
+ {ERR => "$prog: Unmatched \\{\n"}, {EXIT => 2}],
+ ['bre49', '_ : "a\\{32768\\}"',
+ {ERR => "$prog: Invalid content of \\{\\}\n"}, {EXIT => 2},
+ # Map AIX-6's different diagnostic to the one we expect:
+ {ERR_SUBST =>
+ 's,Regular expression too big,Invalid content of \\\\{\\\\},'},
+ ],
+ ['bre50', '_ : "a\\{1,0\\}"',
+ {ERR => "$prog: Invalid content of \\{\\}\n"}, {EXIT => 2}],
+ ['bre51', '"acabc" : ".*ab\\{0,0\\}c"', {OUT => '2'}],
+ ['bre52', '"abcac" : "ab\\{0,1\\}c"', {OUT => '3'}],
+ ['bre53', '"abbcac" : "ab\\{0,3\\}c"', {OUT => '4'}],
+ ['bre54', '"abcac" : ".*ab\\{1,1\\}c"', {OUT => '3'}],
+ ['bre55', '"abcac" : ".*ab\\{1,3\\}c"', {OUT => '3'}],
+ ['bre56', '"abbcabc" : ".*ab\{2,2\}c"', {OUT => '4'}],
+ ['bre57', '"abbcabc" : ".*ab\{2,4\}c"', {OUT => '4'}],
+ ['bre58', '"aa" : "a\\{1\\}\\{1\\}"', {OUT => '1'}],
+ ['bre59', '"aa" : "a*\\{1\\}"', {OUT => '2'}],
+ ['bre60', '"aa" : "a\\{1\\}*"', {OUT => '2'}],
+ ['bre61', '"acd" : "a\\(b\\)?c\\1d"', {OUT => ''}, {EXIT => 1}],
+ ['bre62', '-- "-5" : "-\\{0,1\\}[0-9]*\$"', {OUT => '2'}],
+
+ ['fail-c', {ERR => "$prog: missing operand\n"
+ . "Try '$prog --help' for more information.\n"},
+ {EXIT => 2}],
+
+ ['bignum-add', "$big + 1", {OUT => $big_p1}],
+ ['bignum-add2', "$big + $big_p1", {OUT => $big_sum}],
+ ['bignum-sub', "$big_p1 - 1", {OUT => $big}],
+ ['bignum-sub2', "$big_sum - $big", {OUT => $big_p1}],
+ ['bignum-mul', "$big_p1 '*' $big", {OUT => $big_prod}],
+ ['bignum-div', "$big_prod / $big", {OUT => $big_p1}],
+
+
+ # Test syntax error messages
+ ['se0', '9 9',
+ {ERR => "$prog: syntax error: unexpected argument '9'\n"}, {EXIT => 2}],
+ ['se1', "2 a", {EXIT=>2},
+ {ERR=>"$prog: syntax error: unexpected argument 'a'\n"}],
+ ['se2', "2 '+'", {EXIT=>2},
+ {ERR=>"$prog: syntax error: missing argument after '+'\n"}],
+ ['se3', "2 :", {EXIT=>2},
+ {ERR=>"$prog: syntax error: missing argument after ':'\n"}],
+ ['se4', "length", {EXIT=>2},
+ {ERR=>"$prog: syntax error: missing argument after 'length'\n"}],
+ ['se5', "'(' 2 ", {EXIT=>2},
+ {ERR=>"$prog: syntax error: expecting ')' after '2'\n"}],
+ ['se6', "'(' 2 a", {EXIT=>2},
+ {ERR=>"$prog: syntax error: expecting ')' instead of 'a'\n"}],
+ );
+
+# Append a newline to end of each expected 'OUT' string.
+my $t;
+foreach $t (@Tests)
+ {
+ my $arg1 = $t->[1];
+ my $e;
+ foreach $e (@$t)
+ {
+ $e->{OUT} .= "\n"
+ if ref $e eq 'HASH' and exists $e->{OUT};
+ }
+ }
+
+# Try multibyte locale in most tests.
+#
+if ($mb_locale ne 'C')
+ {
+ # Duplicate each test vector, appending "-mb" to the test name and
+ # inserting {ENV => "LC_ALL=$mb_locale"} in the copy, so that we
+ # provide coverage for the distro-added multi-byte code paths.
+ my @new;
+ foreach my $t (@Tests)
+ {
+ # Don't add the quote varying tests to the multi-byte set
+ $t->[0] =~ /^se/
+ and next;
+
+ my @new_t = @$t;
+ my $test_name = shift @new_t;
+
+ push @new, ["$test_name-mb", @new_t, {ENV => "LC_ALL=$mb_locale"}];
+ }
+ push @Tests, @new;
+ }
+
+my $save_temps = $ENV{SAVE_TEMPS};
+my $verbose = $ENV{VERBOSE};
+
+my $fail = run_tests ($program_name, $prog, \@Tests, $save_temps, $verbose);
+exit $fail;
diff --git a/tests/factor/create-test.sh b/tests/factor/create-test.sh
new file mode 100755
index 0000000..25885aa
--- /dev/null
+++ b/tests/factor/create-test.sh
@@ -0,0 +1,83 @@
+#!/bin/sh
+# Create the factor test scripts.
+
+# Copyright (C) 2012-2023 Free Software Foundation, Inc.
+
+test_name=$1
+template=$2
+
+# Extract the test name: remove .sh suffix from the basename.
+t=`echo "$test_name"|sed 's,.*/,,;s,\.sh$,,'`
+
+# prefix of 2^64
+p=184467440737
+
+# prefix of 2^96
+q=79228162514264337593543
+
+# Each of these numbers has a Pollard rho factor larger than 2^64,
+# and thus exercises some hard-to-reach code in factor.c.
+t1=170141183460469225450570946617781744489
+t2=170141183460469229545748130981302223887
+
+# Factors of the above:
+# t1: 9223372036854775421 18446744073709551709
+# t2: 9223372036854775643 18446744073709551709
+
+# Each test is a triple: lo, hi, sha1 of result.
+# The test script, run.sh, runs seq lo hi|factor|sha1sum
+# and verifies that the actual and expected checksums are the same.
+# New tests must be added to tests/local.mk (factor_tests), too.
+case $t in
+ t00) set 0 10000000 a451244522b1b662c86cb3cbb55aee3e085a61a0 ;;
+ t01) set 10000000 20000000 c792a2e02f1c8536b5121f624b04039d20187016 ;;
+ t02) set 20000000 30000000 8115e8dff97d1674134ec054598d939a2a5f6113 ;;
+ t03) set 30000000 40000000 fe7b832c8e0ed55035152c0f9ebd59de73224a60 ;;
+ t04) set 40000000 50000000 b8786d66c432e48bc5b342ee3c6752b7f096f206 ;;
+ t05) set 50000000 60000000 a74fe518c5f79873c2b9016745b88b42c8fd3ede ;;
+ t06) set 60000000 70000000 689bc70d681791e5d1b8ac1316a05d0c4473d6db ;;
+ t07) set 70000000 80000000 d370808f2ab8c865f64c2ff909c5722db5b7d58d ;;
+ t08) set 80000000 90000000 7978aa66bf2bdb446398336ea6f02605e9a77581 ;;
+ t09) set $t1 $t1 4622287c5f040cdb7b3bbe4d19d29a71ab277827 ;;
+ t10) set $t2 $t2 dea308253708b57afad357e8c0d2a111460ef50e ;;
+ t11) set ${p}08551616 ${p}08651615 66c57cd58f4fb572df7f088d17e4f4c1d4f01bb1 ;;
+ t12) set ${p}08651616 ${p}08751615 729228e693b1a568ecc85b199927424c7d16d410 ;;
+ t13) set ${p}08751616 ${p}08851615 5a0c985017c2d285e4698f836f5a059e0b684563 ;;
+ t14) set ${p}08851616 ${p}08951615 0482295c514e371c98ce9fd335deed0c9c44a4f4 ;;
+ t15) set ${p}08951616 ${p}09051615 9c0e1105ac7c45e27e7bbeb5e213f530d2ad1a71 ;;
+ t16) set ${p}09051616 ${p}09151615 604366d2b1d75371d0679e6a68962d66336cd383 ;;
+ t17) set ${p}09151616 ${p}09251615 9192d2bdee930135b28d7160e6d395a7027871da ;;
+ t18) set ${p}09251616 ${p}09351615 bcf56ae55d20d700690cff4d3327b78f83fc01bf ;;
+ t19) set ${p}09351616 ${p}09451615 16b106398749e5f24d278ba7c58229ae43f650ac ;;
+ t20) set ${p}09451616 ${p}09551615 ad2c6ed63525f8e7c83c4c416e7715fa1bebc54c ;;
+ t21) set ${p}09551616 ${p}09651615 2b6f9c11742d9de045515a6627c27a042c49f8ba ;;
+ t22) set ${p}09651616 ${p}09751615 54851acd51c4819beb666e26bc0100dc9adbc310 ;;
+ t23) set ${p}09751616 ${p}09851615 6939c2a7afd2d81f45f818a159b7c5226f83a50b ;;
+ t24) set ${p}09851616 ${p}09951615 0f2c8bc011d2a45e2afa01459391e68873363c6c ;;
+ t25) set ${p}09951616 ${p}10051615 630dc2ad72f4c222bad1405e6c5bea590f92a98c ;;
+ t26) set ${q}940336 ${q}942335 63cbd6313d78247b04d63bbbac50cb8f8d33ff71 ;;
+ t27) set ${q}942336 ${q}944335 0d03d63653767173182491b86fa18f8f680bb036 ;;
+ t28) set ${q}944336 ${q}946335 ca43bd38cd9f97cc5bb63613cb19643578640f0b ;;
+ t29) set ${q}946336 ${q}948335 86d59545a0c13567fa96811821ea5cde950611b1 ;;
+ t30) set ${q}948336 ${q}950335 c3740e702fa9c97e6cf00150860e0b936a141a6b ;;
+ t31) set ${q}950336 ${q}952335 551c3c4c4640d86fda311b5c3006dac45505c0ce ;;
+ t32) set ${q}952336 ${q}954335 b1b0b00463c2f853d70ef9c4f7a96de5cb614156 ;;
+ t33) set ${q}954336 ${q}956335 8938a484a9ef6bb16478091d294fcde9f8ecea69 ;;
+ t34) set ${q}956336 ${q}958335 d1ae6bc712d994f35edf55c785d71ddf31f16535 ;;
+ t35) set ${q}958336 ${q}960335 2374919a89196e1fce93adfe779cb4664556d4b6 ;;
+ t36) set ${q}960336 ${q}962335 569e4363e8d9e8830a187d9ab27365eef08abde1 ;;
+ *)
+ echo "$0: error: unknown test: '$test_name' -> '$t'" >&2
+ exit 1
+ ;;
+esac
+
+TEMPLATE="TEST SCRIPT DERIVED FROM THE TEMPLATE $template"
+
+# Create the test script from the template for this test
+# by substituting the START, the END and the CKSUM.
+exec sed \
+ -e "s/__START__/$1/" \
+ -e "s/__END__/$2/" \
+ -e "s/__CKSUM__/$3/" \
+ -e "s!__TEMPLATE__!$TEMPLATE!" "$template"
diff --git a/tests/factor/factor-parallel.sh b/tests/factor/factor-parallel.sh
new file mode 100755
index 0000000..9a3d62a
--- /dev/null
+++ b/tests/factor/factor-parallel.sh
@@ -0,0 +1,34 @@
+#!/bin/sh
+# Test for complete lines on output
+
+# Copyright (C) 2015-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ factor
+
+
+odd() { LC_ALL=C sed '/[24680]$/d'; }
+primes() { LC_ALL=C sed 's/.*: //; / /d'; }
+
+# Before v8.24 the number reported here would vary
+# Note -u not supplied to split, increased batching of quickly processed items.
+# As processing cost increases it becomes advantageous to use -u to keep
+# the factor processes supplied with data.
+nprimes=$(seq 1e6 | odd | split -nr/4 --filter='factor' | primes | wc -l)
+
+test "$nprimes" = '78498' || fail=1
+
+Exit $fail
diff --git a/tests/factor/factor.pl b/tests/factor/factor.pl
new file mode 100755
index 0000000..6e612e4
--- /dev/null
+++ b/tests/factor/factor.pl
@@ -0,0 +1,125 @@
+#!/usr/bin/perl
+# Basic tests for "factor".
+
+# Copyright (C) 1998-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+use strict;
+
+(my $program_name = $0) =~ s|.*/||;
+my $prog = 'factor';
+
+# Turn off localization of executable's output.
+@ENV{qw(LANGUAGE LANG LC_ALL)} = ('C') x 3;
+
+my @Tests =
+ (
+ ['1', '9', {OUT => '3 3'}],
+ ['1a', '7', {OUT => '7'}],
+ ['1b', ' +7', {OUT => '7'}],
+ ['2', '4294967291', {OUT => '4294967291'}],
+ ['3', '4294967292', {OUT => '2 2 3 3 7 11 31 151 331'}],
+ ['4', '4294967293', {OUT => '9241 464773'}],
+
+ ['a', '4294966201', {OUT => '12197 352133'}],
+ ['b', '4294966339', {OUT => '13187 325697'}],
+ ['c', '4294966631', {OUT => '13729 312839'}],
+ ['d', '4294966457', {OUT => '14891 288427'}],
+ ['e', '4294966759', {OUT => '21649 198391'}],
+ ['f', '4294966573', {OUT => '23071 186163'}],
+ ['g', '4294967101', {OUT => '23603 181967'}],
+ ['h', '4294966519', {OUT => '34583 124193'}],
+ ['i', '4294966561', {OUT => '36067 119083'}],
+ ['j', '4294966901', {OUT => '37747 113783'}],
+ ['k', '4294966691', {OUT => '39241 109451'}],
+ ['l', '4294966969', {OUT => '44201 97169'}],
+ ['m', '4294967099', {OUT => '44483 96553'}],
+ ['n', '4294966271', {OUT => '44617 96263'}],
+ ['o', '4294966789', {OUT => '50411 85199'}],
+ ['p', '4294966189', {OUT => '53197 80737'}],
+ ['q', '4294967213', {OUT => '57139 75167'}],
+ ['s', '4294967071', {OUT => '65521 65551'}],
+ ['t', '4294966194', {OUT => '2 3 3 3 3 3 3 3 53 97 191'}],
+ ['u', '4294966272', {OUT => '2 2 2 2 2 2 2 2 2 2 3 23 89 683'}],
+ ['v', '4294966400', {OUT => '2 2 2 2 2 2 2 5 5 1342177'}],
+ ['w', '4294966464', {OUT => '2 2 2 2 2 2 3 3 3 2485513'}],
+ ['x', '4294966896', {OUT => '2 2 2 2 3 3 3 11 607 1489'}],
+ ['y', '4294966998', {OUT => '2 3 7 3917 26107'}],
+ ['z', '-1',
+ # Map newer glibc diagnostic to expected.
+ # Also map OpenBSD 5.1's "unknown option" to expected "invalid option".
+ {ERR_SUBST => q!s/'1'/1/;s/unknown/invalid/!},
+ {ERR => "$prog: invalid option -- 1\n"
+ . "Try '$prog --help' for more information.\n"},
+ {EXIT => 1}],
+ ['cont', 'a 4',
+ {OUT => "4: 2 2\n"},
+ {ERR => "$prog: 'a' is not a valid positive integer\n"},
+ {EXIT => 1}],
+ ['bug-2012-a', '465658903', {OUT => '15259 30517'}],
+ ['bug-2012-b', '2242724851', {OUT => '33487 66973'}],
+ ['bug-2012-c', '6635692801', {OUT => '57601 115201'}],
+ ['bug-2012-d', '17709149503', {OUT => '94099 188197'}],
+ ['bug-2012-e', '17754345703', {OUT => '94219 188437'}],
+ # Infinite loop bugs in v8.20 to 8.26 inclusive
+ ['bug-2016-a', '158909489063877810457',
+ {OUT => '3401347 3861211 12099721'}],
+ ['bug-2016-b', '222087527029934481871',
+ {OUT => '15601 26449 111427 4830277'}],
+ ['bug-2016-c', '12847291069740315094892340035',
+ {OUT => '5 4073 18899 522591721 63874247821'}],
+ ['bug-gmp-2_sup_128', '340282366920938463463374607431768211456',
+ {OUT => '2 'x127 . '2'}],
+ ['bug-gmp-2_sup_256',
+ '115792089237316195423570985008687907853'
+ . '269984665640564039457584007913129639936',
+ {OUT => '2 'x255 . '2'}],
+ ['bug-gmp-plus_2_sup_128_plus_1',
+ '+170141183460469231731687303715884105729',
+ {OUT => '3 56713727820156410577229101238628035243'}],
+ ['h-1', '-h 3000', {OUT => '2^3 3 5^3'}],
+ ['h-2', '3000 --exponents', {OUT => '2^3 3 5^3'}],
+ );
+
+
+# Prepend the command line argument and append a newline to end
+# of each expected 'OUT' string.
+my $t;
+
+Test:
+foreach $t (@Tests)
+ {
+ (my $arg1 = $t->[1]) =~ s| *\+?||; # strip '+'
+ (my $arg1 = $arg1) =~ s| *-[^ ]+ *||; # strip option
+
+ # Don't fiddle with expected OUT string if there's a nonzero exit status.
+ foreach my $e (@$t)
+ {
+ ref $e eq 'HASH' && exists $e->{EXIT} && $e->{EXIT}
+ and next Test;
+ }
+
+ foreach my $e (@$t)
+ {
+ ref $e eq 'HASH' && exists $e->{OUT}
+ and $e->{OUT} = "$arg1: $e->{OUT}\n"
+ }
+ }
+
+my $save_temps = $ENV{SAVE_TEMPS};
+my $verbose = $ENV{VERBOSE};
+
+my $fail = run_tests ($program_name, $prog, \@Tests, $save_temps, $verbose);
+exit $fail;
diff --git a/tests/factor/run.sh b/tests/factor/run.sh
new file mode 100755
index 0000000..1f9be3d
--- /dev/null
+++ b/tests/factor/run.sh
@@ -0,0 +1,34 @@
+#!/bin/sh
+
+# === THIS IS A __TEMPLATE__ ===
+
+# Test the factor rewrite.
+# The test is to run this command
+# seq $START $END | factor | shasum -c --status <(echo $CKSUM -)
+# I.e., to ensure that the factorizations of integers $1..$2
+# match what we expect.
+#
+# See: tests/factor/create-test.sh
+
+# Copyright (C) 2012-2023 Free Software Foundation, Inc.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+
+# Don't run these tests by default.
+very_expensive_
+
+print_ver_ factor seq sha1sum
+
+# Template variables.
+START=__START__
+ END=__END__
+CKSUM=__CKSUM__
+
+test "$START" = '__ST''ART__' && skip_ 'ignoring factor test template'
+
+echo "$CKSUM -" > exp
+
+f=1
+seq $START $END | factor | sha1sum -c --status exp && f=0
+
+Exit $f
diff --git a/tests/filefrag-extent-compare b/tests/filefrag-extent-compare
new file mode 100644
index 0000000..155e7ff
--- /dev/null
+++ b/tests/filefrag-extent-compare
@@ -0,0 +1,85 @@
+eval '(exit $?0)' && eval 'exec perl -wS "$0" ${1+"$@"}'
+ & eval 'exec perl -wS "$0" $argv:q'
+ if 0;
+# Determine whether two files have the same extents by comparing
+# the logical block numbers and lengths from filefrag -v for each.
+
+# Invoke like this:
+# This helper function, f, extracts logical block number and lengths.
+# f() { awk '/^ *[0-9]/ {printf "%d %d ",$2,NF<5?$NF:$5} END {print ""}'; }
+# { filefrag -v j1 | f; filefrag -v j2 | f; } | ./filefrag-extent-compare
+
+use warnings;
+use strict;
+(my $ME = $0) =~ s|.*/||;
+
+my @line = <>;
+my $n_lines = @line;
+$n_lines == 2
+ or die "$ME: expected exactly two input lines; got $n_lines\n";
+
+my @A = split ' ', $line[0];
+my @B = split ' ', $line[1];
+@A % 2 || @B % 2
+ and die "$ME: unexpected input: odd number of numbers; expected even\n";
+
+my @a;
+my @b;
+foreach my $i (0..@A/2-1) { $a[$i] = { L_BLK => $A[2*$i], LEN => $A[2*$i+1] } };
+foreach my $i (0..@B/2-1) { $b[$i] = { L_BLK => $B[2*$i], LEN => $B[2*$i+1] } };
+
+# Merge adjacent extents in array E.
+sub merge_extents($)
+{
+ my ($e) = @_;
+
+ my $i = 0;
+ while (1)
+ {
+ !defined $e->[$i+1]
+ and last;
+ $e->[$i]->{L_BLK} + $e->[$i]->{LEN} != $e->[$i+1]->{L_BLK}
+ and ++$i, next;
+
+ $e->[$i]->{LEN} += $e->[$i+1]->{LEN};
+ # Remove $e->[$i+1]
+ splice @$e, $i+1, 1;
+ }
+}
+
+merge_extents \@a;
+merge_extents \@b;
+
+@a == @b
+ or die "$ME: extent counts differ, even after adjustment\n";
+
+my $i = 0;
+while (defined $a[$i])
+ {
+ my $start_match = $a[$i]->{L_BLK} == $b[$i]->{L_BLK};
+ my $len_match = $a[$i]->{LEN} == $b[$i]->{LEN};
+ if ( ! ($start_match && ($len_match || $i == (@a - 1))))
+ {
+ # On XFS on Linux kernel 2.6.38, it was seen that the size of the
+ # last extent can vary, and can extend beyond the length of the file.
+ # So we ignore the length of the last extent, because if the
+ # file is the wrong length we'll get failures elsewhere.
+ die "$ME: differing extent:\n"
+ . " [$i]=$a[$i]->{L_BLK} $a[$i]->{LEN}\n"
+ . " [$i]=$b[$i]->{L_BLK} $b[$i]->{LEN}\n";
+ }
+ $i++;
+ }
+
+### Setup "GNU" style for perl-mode and cperl-mode.
+## Local Variables:
+## mode: perl
+## perl-indent-level: 2
+## perl-continued-statement-offset: 2
+## perl-continued-brace-offset: 0
+## perl-brace-offset: 0
+## perl-brace-imaginary-offset: 0
+## perl-label-offset: -2
+## perl-extra-newline-before-brace: t
+## perl-merge-trailing-else: nil
+## End:
diff --git a/tests/fmt/base.pl b/tests/fmt/base.pl
new file mode 100755
index 0000000..667a97d
--- /dev/null
+++ b/tests/fmt/base.pl
@@ -0,0 +1,67 @@
+#!/usr/bin/perl
+# Basic tests for "fmt".
+
+# Copyright (C) 2001-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+use strict;
+
+(my $program_name = $0) =~ s|.*/||;
+my $normalize_strerror = "s/': .*/'/";
+
+my @Tests =
+ (
+ ['8-bit-pfx', qw (-p 'ç'),
+ {IN=> "ça\nçb\n"},
+ {OUT=>"ça b\n"}],
+ ['wide-1', '-w 32768',
+ {ERR => "fmt: invalid width: '32768'\n"}, {EXIT => 1},
+ {ERR_SUBST => $normalize_strerror}],
+ ['wide-2', '-w 2147483647',
+ {ERR => "fmt: invalid width: '2147483647'\n"}, {EXIT => 1},
+ {ERR_SUBST => $normalize_strerror}],
+ ['bad-suffix', '-72x', {IN=> ''},
+ {ERR => "fmt: invalid width: '72x'\n"}, {EXIT => 1}],
+ ['no-file', 'no-such-file',
+ {ERR => "fmt: cannot open 'no-such-file' for reading:"
+ . " No such file or directory\n"}, {EXIT => 1}],
+ ['obs-1', '-c -72',
+ {ERR => "fmt: invalid option -- 7; -WIDTH is recognized only when it"
+ . " is the first\noption; use -w N instead\n"
+ . "Try 'fmt --help' for more information.\n" }, {EXIT => 1}],
+
+ # With --prefix=P, do not remove leading space on lines without the prefix.
+ ['pfx-1', qw (-p '>'),
+ {IN=> " 1\n 2\n\t3\n\t\t4\n> quoted\n> text\n"},
+ {OUT=> " 1\n 2\n\t3\n\t\t4\n> quoted text\n"}],
+
+ # Don't remove prefix from a prefix-only line.
+ ['pfx-only', qw (-p '>'),
+ {IN=> ">\n"},
+ {OUT=> ">\n"}],
+
+ # With a multi-byte prefix, say, "foo", don't empty a line that
+ # starts with a strict prefix (e.g. "fo") of that prefix.
+ # With fmt from coreutils-6.7, it would mistakenly output an empty line.
+ ['pfx-of-pfx', qw (-p 'foo'),
+ {IN=> "fo\n"},
+ {OUT=> "fo\n"}],
+);
+
+my $save_temps = $ENV{DEBUG};
+my $verbose = $ENV{VERBOSE};
+my $prog = 'fmt';
+my $fail = run_tests ($program_name, $prog, \@Tests, $save_temps, $verbose);
+exit $fail;
diff --git a/tests/fmt/goal-option.sh b/tests/fmt/goal-option.sh
new file mode 100755
index 0000000..60e3512
--- /dev/null
+++ b/tests/fmt/goal-option.sh
@@ -0,0 +1,56 @@
+#!/bin/sh
+# Exercise the fmt -g option.
+
+# Copyright (C) 2012-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ fmt
+
+cat <<\_EOF_ > base || framework_failure_
+
+@command{fmt} prefers breaking lines at the end of a sentence, and tries to
+avoid line breaks after the first word of a sentence or before the last word
+of a sentence. A @dfn{sentence break} is defined as either the end of a
+paragraph or a word ending in any of @samp{.?!}, followed by two spaces or end
+of line, ignoring any intervening parentheses or quotes. Like @TeX{},
+@command{fmt} reads entire ''paragraphs'' before choosing line breaks; the
+algorithm is a variant of that given by
+Donald E. Knuth and Michael F. Plass
+in ''Breaking Paragraphs Into Lines'',
+@cite{Software---Practice & Experience}
+@b{11}, 11 (November 1981), 1119--1184.
+_EOF_
+
+fmt -g 60 -w 72 base > out || fail=1
+
+cat <<\_EOF_ > exp || framework_failure_
+
+@command{fmt} prefers breaking lines at the end of a sentence,
+and tries to avoid line breaks after the first word of a sentence
+or before the last word of a sentence. A @dfn{sentence break}
+is defined as either the end of a paragraph or a word ending
+in any of @samp{.?!}, followed by two spaces or end of line,
+ignoring any intervening parentheses or quotes. Like @TeX{},
+@command{fmt} reads entire ''paragraphs'' before choosing line
+breaks; the algorithm is a variant of that given by Donald
+E. Knuth and Michael F. Plass in ''Breaking Paragraphs Into
+Lines'', @cite{Software---Practice & Experience} @b{11}, 11
+(November 1981), 1119--1184.
+_EOF_
+
+compare exp out || fail=1
+
+Exit $fail
diff --git a/tests/fmt/long-line.sh b/tests/fmt/long-line.sh
new file mode 100755
index 0000000..9bfc181
--- /dev/null
+++ b/tests/fmt/long-line.sh
@@ -0,0 +1,61 @@
+#!/bin/sh
+# make sure fmt -s works even on long lines
+
+# Copyright (C) 2002-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ fmt
+
+printf '%2030s\n' ' '|sed 's/../ y/g' > in || framework_failure_
+
+cat <<\EOF > exp || framework_failure_
+ y y y y y y y y y y y y y y y y y y y y y y y y y y y y y y y y y y y
+ y y y y y y y y y y y y y y y y y y y y y y y y y y y y y y y y y y y
+ y y y y y y y y y y y y y y y y y y y y y y y y y y y y y y y y y y y
+ y y y y y y y y y y y y y y y y y y y y y y y y y y y y y y y y y y y
+ y y y y y y y y y y y y y y y y y y y y y y y y y y y y y y y y y y y
+ y y y y y y y y y y y y y y y y y y y y y y y y y y y y y y y y y y y
+ y y y y y y y y y y y y y y y y y y y y y y y y y y y y y y y y y y y
+ y y y y y y y y y y y y y y y y y y y y y y y y y y y y y y y y y y y
+ y y y y y y y y y y y y y y y y y y y y y y y y y y y y y y y y y y y
+ y y y y y y y y y y y y y y y y y y y y y y y y y y y y y y y y y y y
+ y y y y y y y y y y y y y y y y y y y y y y y y y y y y y y y y y y y
+ y y y y y y y y y y y y y y y y y y y y y y y y y y y y y y y y y y y
+ y y y y y y y y y y y y y y y y y y y y y y y y y y y y y y y y y y y
+ y y y y y y y y y y y y y y y y y y y y y y y y y y y y y y y y y y y
+ y y y y y y y y y y y y y y y y y y y y y y y y y y y y y y y y y y y
+ y y y y y y y y y y y y y y y y y y y y y y y y y y y y y y y y y y y
+ y y y y y y y y y y y y y y y y y y y y y y y y y y y y y y y y y y y
+ y y y y y y y y y y y y y y y y y y y y y y y y y y y y y y y y y y y
+ y y y y y y y y y y y y y y y y y y y y y y y y y y y y y y y y y y y
+ y y y y y y y y y y y y y y y y y y y y y y y y y y y y y y y y y y y
+ y y y y y y y y y y y y y y y y y y y y y y y y y y y y y y y y y y y
+ y y y y y y y y y y y y y y y y y y y y y y y y y y y y y y y y y y y
+ y y y y y y y y y y y y y y y y y y y y y y y y y y y y y y y y y y y
+ y y y y y y y y y y y y y y y y y y y y y y y y y y y y y y y y y y y
+ y y y y y y y y y y y y y y y y y y y y y y y y y y y y y y y y y y y
+ y y y y y y y y y y y y y y y y y y y y y y y y y y y y y y y y y y y
+ y y y y y y y y y y y y y y y y y y y y y y y y y y y y y y y y y y y
+ y y y y y y y y y y y y y y y y y y y y y y y y y y y y y y y y y y y
+ y y y y y y y y y y y y y y y y y y y y y y y y y y y y y y y y y y y
+EOF
+
+
+fmt -s in > out || fail=1
+
+compare exp out || fail=1
+
+Exit $fail
diff --git a/tests/fmt/non-space.sh b/tests/fmt/non-space.sh
new file mode 100755
index 0000000..584e8b1
--- /dev/null
+++ b/tests/fmt/non-space.sh
@@ -0,0 +1,49 @@
+#!/bin/sh
+# Test fmt space handling
+
+# Copyright (C) 2022-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ fmt printf
+
+# Before coreutils 9.1 macOS treated bytes like 0x85
+# as space characters in multi-byte locales (including UTF-8)
+
+check_non_space() {
+ char="$1"
+ test "$(env printf "=$char=" | fmt -s -w1 | wc -l)" = 1 || fail=1
+}
+
+export LC_ALL=en_US.iso8859-1 # only lowercase form works on macOS 10.15.7
+if test "$(locale charmap 2>/dev/null | sed 's/iso/ISO-/')" = ISO-8859-1; then
+ check_non_space '\xA0'
+fi
+
+export LC_ALL=en_US.UTF-8
+if test "$(locale charmap 2>/dev/null)" = UTF-8; then
+ check_non_space '\u00A0' # No break space
+ check_non_space '\u2007' # TODO: should probably split on figure space
+ check_non_space '\u202F' # Narrow no break space
+ check_non_space '\u2060' # zero-width no break space
+ check_non_space '\u0445' # Cyrillic kha, for which macOS isspace(0x85)==true
+fi
+
+export LC_ALL=ru_RU.KOI8-R
+if test "$(locale charmap 2>/dev/null)" = KOI8-R; then
+ check_non_space '\x9A'
+fi
+
+Exit $fail
diff --git a/tests/groups/groups-dash.sh b/tests/groups/groups-dash.sh
new file mode 100755
index 0000000..a979bc8
--- /dev/null
+++ b/tests/groups/groups-dash.sh
@@ -0,0 +1,33 @@
+#!/bin/sh
+# ensure groups handles -- sanely
+
+# Copyright (C) 2007-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ groups
+
+# An invalid user name
+user=:invalid
+
+printf '%s\n' "groups: ':invalid': no such user" > exp || framework_failure_
+
+# Coreutils 6.9 and earlier failed to display information on first argument
+# if later argument was --.
+returns_ 1 groups $user -- > out 2>&1 || fail=1
+
+compare exp out || fail=1
+
+Exit $fail
diff --git a/tests/groups/groups-process-all.sh b/tests/groups/groups-process-all.sh
new file mode 100755
index 0000000..2e455c7
--- /dev/null
+++ b/tests/groups/groups-process-all.sh
@@ -0,0 +1,26 @@
+#!/bin/sh
+# Ensure groups processes all arguments before exiting.
+# With coreutils-2.27 and prior, it would exit upon first failure.
+
+# Copyright (C) 2017-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ groups
+
+returns_ 1 groups :1 :2 :3 2> err || fail=1
+test $(wc -l < err) = 3 || fail=1
+
+Exit $fail
diff --git a/tests/groups/groups-version.sh b/tests/groups/groups-version.sh
new file mode 100755
index 0000000..c177e32
--- /dev/null
+++ b/tests/groups/groups-version.sh
@@ -0,0 +1,27 @@
+#!/bin/sh
+# ensure groups --version output is similar to id --version
+
+# Copyright (C) 2007-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ groups
+
+groups --version | sed 's/^groups/id/; /^$/q' > out || fail=1
+id --version | sed '/^$/q' > exp || fail=1
+
+compare exp out || fail=1
+
+Exit $fail
diff --git a/tests/head/head-c.sh b/tests/head/head-c.sh
new file mode 100755
index 0000000..052caa7
--- /dev/null
+++ b/tests/head/head-c.sh
@@ -0,0 +1,59 @@
+#!/bin/sh
+# exercise head -c
+
+# Copyright (C) 2001-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ head
+getlimits_
+
+vm=$(get_min_ulimit_v_ head -c1 /dev/null) \
+ || skip_ "this shell lacks ulimit support"
+
+# exercise the fix of 2001-08-18, based on test case from Ian Bruce
+echo abc > in || framework_failure_
+(head -c1; head -c1) < in > out || fail=1
+case "$(cat out)" in
+ ab) ;;
+ *) fail=1 ;;
+esac
+
+# Test for a bug in coreutils 5.0.1 through 8.22.
+printf 'abc\ndef\n' > in1 || framework_failure_
+(dd bs=1 skip=1 count=0 status=none && head -c-4) < in1 > out1 || fail=1
+case "$(cat out1)" in
+ bc) ;;
+ *) fail=1 ;;
+esac
+
+# Only allocate memory as needed.
+# Coreutils <= 8.21 would allocate memory up front
+# based on the value passed to -c
+(ulimit -v $(($vm+8000)) && head --bytes=-$SSIZE_MAX < /dev/null) || fail=1
+
+# Make sure it works on funny files in /proc and /sys.
+
+for file in /proc/version /sys/kernel/profiling; do
+ if test -r $file; then
+ cp -f $file copy &&
+ head -c -1 copy > exp1 || framework_failure_
+
+ head -c -1 $file > out1 || fail=1
+ compare exp1 out1 || fail=1
+ fi
+done
+
+Exit $fail
diff --git a/tests/head/head-elide-tail.pl b/tests/head/head-elide-tail.pl
new file mode 100755
index 0000000..221b45a
--- /dev/null
+++ b/tests/head/head-elide-tail.pl
@@ -0,0 +1,110 @@
+#!/usr/bin/perl
+# Exercise head's --bytes=-N option.
+
+# Copyright (C) 2003-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+use strict;
+
+(my $program_name = $0) =~ s|.*/||;
+
+$ENV{PROG} = 'head';
+
+# Turn off localization of executable's output.
+@ENV{qw(LANGUAGE LANG LC_ALL)} = ('C') x 3;
+
+# This should match the definition in head.c.
+my $READ_BUFSIZE = 8192;
+
+my @Tests =
+ (
+ # Elide the exact size of the file.
+ ['elide-b1', "--bytes=-2", {IN=>"a\n"}, {OUT=>''}],
+ # Elide more than the size of the file.
+ ['elide-b2', "--bytes=-2", {IN=>"a"}, {OUT=>''}],
+ # Leave just one byte.
+ ['elide-b3', "--bytes=-2", {IN=>"abc"}, {OUT=>'a'}],
+ # Make it so the elided bytes straddle the end of the first
+ # $READ_BUFSIZE block.
+ ['elide-b4', "--bytes=-2",
+ {IN=> 'a' x ($READ_BUFSIZE-3) . "\nbcd"},
+ {OUT=>'a' x ($READ_BUFSIZE-3) . "\nb"}],
+ # Make it so the elided bytes straddle the end of the 2nd
+ # $READ_BUFSIZE block.
+ ['elide-b5', "--bytes=-2",
+ {IN=> 'a' x (2 * $READ_BUFSIZE - 2) . 'bcd'},
+ {OUT=>'a' x (2 * $READ_BUFSIZE - 2) . 'b'}],
+
+ ['elide-l0', "--lines=-1", {IN=>''}, {OUT=>''}],
+ ['elide-l1', "--lines=-1", {IN=>"a\n"}, {OUT=>''}],
+ ['elide-l2', "--lines=-1", {IN=>"a"}, {OUT=>''}],
+ ['elide-l3', "--lines=-1", {IN=>"a\nb"}, {OUT=>"a\n"}],
+ ['elide-l4', "--lines=-1", {IN=>"a\nb\n"}, {OUT=>"a\n"}],
+ ['elide-l5', "--lines=-0", {IN=>"a\nb\n"}, {OUT=>"a\nb\n"}],
+ ['elide-l6', "--lines=-0", {IN=>"a\nb"}, {OUT=>"a\nb"}],
+ );
+
+if ($ENV{RUN_EXPENSIVE_TESTS})
+ {
+ # Brute force: use all combinations of file sizes [0..20] and
+ # number of bytes to elide [0..20]. For better coverage, recompile
+ # head with -DHEAD_TAIL_PIPE_READ_BUFSIZE=4 and
+ # -DHEAD_TAIL_PIPE_BYTECOUNT_THRESHOLD=8
+ my $s = "abcdefghijklmnopqrst";
+ for my $file_size (0..20)
+ {
+ for my $n_elide (0..20)
+ {
+ my $input = substr $s, 0, $file_size;
+ my $out_len = $n_elide < $file_size ? $file_size - $n_elide : 0;
+ my $output = substr $input, 0, $out_len;
+ my $t = ["elideb$file_size-$n_elide", "--bytes=-$n_elide",
+ {IN=>$input}, {OUT=>$output}];
+ push @Tests, $t;
+ my @u = @$t;
+ # Insert the ---presume-input-pipe option.
+ $u[0] .= 'p';
+ $u[1] .= ' ---presume-input-pipe';
+ push @Tests, \@u;
+ }
+ }
+
+ $s =~ s/(.)/$1\n/g;
+ $s .= 'u'; # test without trailing '\n'
+ for my $file_size (0..21)
+ {
+ for my $n_elide (0..21)
+ {
+ my $input = substr $s, 0, 2 * $file_size;
+ my $out_len = $n_elide < $file_size ? $file_size - $n_elide : 0;
+ my $output = substr $input, 0, 2 * $out_len;
+ my $t = ["elidel$file_size-$n_elide", "--lines=-$n_elide",
+ {IN=>$input}, {OUT=>$output}];
+ push @Tests, $t;
+ my @u = @$t;
+ # Insert the ---presume-input-pipe option.
+ $u[0] .= 'p';
+ $u[1] .= ' ---presume-input-pipe';
+ push @Tests, \@u;
+ }
+ }
+ }
+
+my $save_temps = $ENV{DEBUG};
+my $verbose = $ENV{VERBOSE};
+
+my $prog = $ENV{PROG} || die "$0: \$PROG not specified in environment\n";
+my $fail = run_tests ($program_name, $prog, \@Tests, $save_temps, $verbose);
+exit $fail;
diff --git a/tests/head/head-pos.sh b/tests/head/head-pos.sh
new file mode 100755
index 0000000..c24edd1
--- /dev/null
+++ b/tests/head/head-pos.sh
@@ -0,0 +1,44 @@
+#!/bin/sh
+# When reading a specified number of lines, ensure that the output
+# file pointer is positioned just after those lines.
+
+# Copyright (C) 2002-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ head
+
+(echo a; echo b) > in || framework_failure_
+echo b > exp || framework_failure_
+
+for i in -1 1; do
+ (head -n $i >/dev/null; cat) < in > out || fail=1
+ compare exp out || fail=1
+done
+
+# Exercise the (start_pos < pos) block in elide_tail_lines_seekable.
+# So far, this is the only test to do that.
+# Do that by creating a file larger than BUFSIZ (I've seen 128K) and
+# elide a suffix of it (by line count) that is also larger than BUFSIZ.
+# 50000 lines times 6 bytes per line gives us enough leeway even on a
+# system with a BUFSIZ of 256K.
+n_lines=50000
+seq 70000 > in2 || framework_failure_
+echo $n_lines > exp-n || framework_failure_
+
+(head -n-$n_lines>/dev/null; wc -l) < in2 > n
+compare exp-n n || fail=1
+
+Exit $fail
diff --git a/tests/head/head-write-error.sh b/tests/head/head-write-error.sh
new file mode 100755
index 0000000..25cebe1
--- /dev/null
+++ b/tests/head/head-write-error.sh
@@ -0,0 +1,51 @@
+#!/bin/sh
+# Ensure we diagnose and not continue writing to
+# the output if we get a write error.
+
+# Copyright (C) 2014-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ head
+
+if ! test -w /dev/full || ! test -c /dev/full; then
+ skip_ '/dev/full is required'
+fi
+
+# We can't use /dev/zero as that's bypassed in the --lines case
+# due to lseek() indicating it has a size of zero.
+yes | head -c10M > bigseek || framework_failure_
+
+# This is the single output diagnostic expected,
+# (without the possibly varying :strerror(ENOSPC) suffix).
+printf '%s\n' "head: error writing 'standard output'" > exp
+
+# Memory is bounded in these cases
+for item in lines bytes; do
+ for N in 0 1; do
+ # pipe case
+ yes | returns_ 1 timeout 10s head --$item=-$N > /dev/full 2> errt || fail=1
+ sed 's/\(head:.*\):.*/\1/' errt > err
+ compare exp err || fail=1
+
+ # seekable case
+ returns_ 1 timeout 10s head --$item=-$N bigseek > /dev/full 2> errt \
+ || fail=1
+ sed 's/\(head:.*\):.*/\1/' errt > err
+ compare exp err || fail=1
+ done
+done
+
+Exit $fail
diff --git a/tests/head/head.pl b/tests/head/head.pl
new file mode 100755
index 0000000..56a1b35
--- /dev/null
+++ b/tests/head/head.pl
@@ -0,0 +1,87 @@
+#!/usr/bin/perl
+# test head
+
+# Copyright (C) 2008-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+use strict;
+
+my $prog = 'head';
+
+# Turn off localization of executable's output.
+@ENV{qw(LANGUAGE LANG LC_ALL)} = ('C') x 3;
+
+my $in = join ('', map { "$_\n" } 0..600);
+my $in_1024 = substr $in, 0, 1024;
+
+# FIXME: set this properly
+my $x32_bit_long = 0;
+
+my @Tests =
+(
+ ['idem-0', {IN=>''}, {OUT=>''}],
+ ['idem-1', {IN=>'a'}, {OUT=>'a'}],
+ ['idem-2', {IN=>"\n"}, {OUT=>"\n"}],
+ ['idem-3', {IN=>"a\n"}, {OUT=>"a\n"}],
+
+ ['basic-10',
+ {IN=>"1\n2\n3\n4\n5\n6\n7\n8\n9\n0\n"},
+ {OUT=>"1\n2\n3\n4\n5\n6\n7\n8\n9\n0\n"}],
+
+ ['basic-09',
+ {IN=>"1\n2\n3\n4\n5\n6\n7\n8\n9\n"},
+ {OUT=>"1\n2\n3\n4\n5\n6\n7\n8\n9\n"}],
+
+ ['basic-11',
+ {IN=>"1\n2\n3\n4\n5\n6\n7\n8\n9\n0\nb\n"},
+ {OUT=>"1\n2\n3\n4\n5\n6\n7\n8\n9\n0\n"}],
+
+ ['obs-0', '-1', {IN=>"1\n2\n"}, {OUT=>"1\n"}],
+ ['obs-1', '-1c', {IN=>''}, {OUT=>''}],
+ ['obs-2', '-1c', {IN=>'12'}, {OUT=>'1'}],
+ ['obs-3', '-14c', {IN=>'1234567890abcdefg'}, {OUT=>'1234567890abcd'}],
+ ['obs-4', '-2b', {IN=>$in}, {OUT=>$in_1024}],
+ ['obs-5', '-1k', {IN=>$in}, {OUT=>$in_1024}],
+
+ # This test fails for textutils-1.22, because head let 4096m overflow to 0
+ # and did not fail. Now head fails with a diagnostic.
+ # Disable this test because it fails on systems with 64-bit uintmax_t.
+ # ['fail-0', qw(-n 4096m), {IN=>"a\n"}, {EXIT=>1}],
+
+ # In spite of its name, this test passes -- just to contrast with the above.
+ ['fail-1', qw(-n 2048m), {IN=>"a\n"}, {OUT=>"a\n"}],
+
+ # Make sure we don't break like AIX 4.3.1 on files with \0 in them.
+ ['null-1', {IN=>"a\0a\n"}, {OUT=>"a\0a\n"}],
+
+ # Make sure counts are interpreted as decimal.
+ # Before 2.0f, these would have been interpreted as octal
+ ['no-oct-1', '-08', {IN=>"\n"x12}, {OUT=>"\n"x8}],
+ ['no-oct-2', '-010', {IN=>"\n"x12}, {OUT=>"\n"x10}],
+ ['no-oct-3', '-n 08', {IN=>"\n"x12}, {OUT=>"\n"x8}],
+ ['no-oct-4', '-c 08', {IN=>"\n"x12}, {OUT=>"\n"x8}],
+
+ # --zero-terminated
+ ['zero-1', '-z -n 1', {IN=>"x\0y"}, {OUT=>"x\0"}],
+ ['zero-2', '-z -n 2', {IN=>"x\0y"}, {OUT=>"x\0y"}],
+);
+
+@Tests = triple_test \@Tests;
+
+my $save_temps = $ENV{DEBUG};
+my $verbose = $ENV{VERBOSE};
+
+my $fail = run_tests ($prog, $prog, \@Tests, $save_temps, $verbose);
+exit $fail;
diff --git a/tests/help/help-version-getopt.sh b/tests/help/help-version-getopt.sh
new file mode 100755
index 0000000..6e61b0f
--- /dev/null
+++ b/tests/help/help-version-getopt.sh
@@ -0,0 +1,74 @@
+#!/bin/sh
+# Ensure --version and --help options are processed before
+# any other options by some programs.
+
+# Copyright (C) 2019-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ yes
+
+programs="cksum dd hostid hostname link logname nohup
+sleep tsort unlink uptime users whoami yes"
+
+# All these variations should show the help/version screen
+# regardless of their position on the command line arguments.
+for prog in $programs; do
+ # skip if the program is not built (e.g., hostname)
+ case " $built_programs " in
+ *" $prog "*) ;;
+ *) continue;;
+ esac
+
+ for opt in --help --version; do
+ rm -f exp out1 out2 out3 || framework_failure_
+
+ # Get the reference output
+ env $prog $opt >exp || fail=1
+
+ # Test: some other argument AFTER --help/--version.
+ env $prog $opt AFTER > out1 || fail=1
+ compare exp out1 || fail=1
+
+ # nohup is an exception: stops processing after first non-option parameter.
+ # E.g., "nohup df --help" should run "df --help", not "df --help".
+ if [ "$prog" = nohup ]; then
+ rm -f exp || framework_failure_
+ df $opt > exp || framework_failure_
+ BEFORE=df
+ else
+ BEFORE=BEFORE
+ fi
+
+ # Test: some other argument BEFORE --help/--version.
+ env $prog $BEFORE $opt > out2 || fail=1
+ compare exp out2 || fail=1
+
+ # Test: some other arguments BEFORE and AFTER --help/--version.
+ env $prog $BEFORE $opt AFTER > out3 || fail=1
+ compare exp out3 || fail=1
+ done
+done
+
+# After end-of-options marker (--), the options should not be parsed.
+# Test with 'yes', and assume the common code will work the
+# same for the other programs.
+cat >exp <<\EOF || framework_failure_
+--help
+EOF
+env yes -- --help | head -n1 > out
+compare exp out || fail=1
+
+Exit $fail
diff --git a/tests/help/help-version.sh b/tests/help/help-version.sh
new file mode 100755
index 0000000..f0ef475
--- /dev/null
+++ b/tests/help/help-version.sh
@@ -0,0 +1,273 @@
+#!/bin/sh
+# Make sure all of these programs work properly
+# when invoked with --help or --version.
+
+# Copyright (C) 2000-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+
+# Terminate any background processes
+cleanup_() { kill $pid 2>/dev/null && wait $pid; }
+
+expected_failure_status_chroot=125
+expected_failure_status_env=125
+expected_failure_status_nice=125
+expected_failure_status_nohup=125
+expected_failure_status_runcon=125
+expected_failure_status_stdbuf=125
+expected_failure_status_timeout=125
+expected_failure_status_printenv=2
+expected_failure_status_tty=3
+expected_failure_status_sort=2
+expected_failure_status_expr=3
+expected_failure_status_lbracket=2
+expected_failure_status_dir=2
+expected_failure_status_ls=2
+expected_failure_status_vdir=2
+
+expected_failure_status_cmp=2
+expected_failure_status_zcmp=2
+expected_failure_status_sdiff=2
+expected_failure_status_diff3=2
+expected_failure_status_diff=2
+expected_failure_status_zdiff=2
+expected_failure_status_zgrep=2
+expected_failure_status_zegrep=2
+expected_failure_status_zfgrep=2
+
+expected_failure_status_grep=2
+expected_failure_status_egrep=2
+expected_failure_status_fgrep=2
+
+test "$built_programs" \
+ || fail_ "built_programs not specified!?!"
+
+test "$VERSION" \
+ || fail_ "set envvar VERSION; it is required for a PATH sanity-check"
+
+# Extract version from --version output of the first program
+for i in $built_programs; do
+ v=$(env $i --version | sed -n '1s/.* //p;q')
+ break
+done
+
+# Ensure that it matches $VERSION.
+test "x$v" = "x$VERSION" \
+ || fail_ "--version-\$VERSION mismatch"
+
+for i in $built_programs; do
+
+ # Skip 'test'; it doesn't accept --help or --version.
+ test $i = test && continue
+
+ # false fails even when invoked with --help or --version.
+ # true and false are tested with these options separately.
+ test $i = false || test $i = true && continue
+
+ # The just-built install executable is always named 'ginstall'.
+ test $i = install && i=ginstall
+
+ # Make sure they exit successfully, under normal conditions.
+ env $i --help >/dev/null || fail=1
+ env $i --version >/dev/null || fail=1
+
+ # Make sure they fail upon 'file system full' error.
+ if test -w /dev/full && test -c /dev/full &&
+ ! printf x >/dev/full 2>/dev/null; then
+ test $i = [ && prog=lbracket || prog=$(echo $i|sed "s/$EXEEXT$//")
+ eval "expected=\$expected_failure_status_$prog"
+ test x$expected = x && expected=1
+
+ returns_ $expected env $i --help >/dev/full 2>/dev/null &&
+ returns_ $expected env $i --version >/dev/full 2>/dev/null ||
+ {
+ fail=1
+ env $i --help >/dev/full 2>/dev/null
+ status=$?
+ echo "*** $i: bad exit status '$status' (expected $expected)," 1>&2
+ echo " with --help or --version output redirected to /dev/full" 1>&2
+ }
+ fi
+done
+
+bigZ_in=bigZ-in.Z
+zin=zin.gz
+zin2=zin2.gz
+
+tmp=tmp-$$
+tmp_in=in-$$
+tmp_in2=in2-$$
+tmp_dir=dir-$$
+tmp_out=out-$$
+mkdir $tmp || fail=1
+cd $tmp || fail=1
+
+comm_setup () { args="$tmp_in $tmp_in"; }
+csplit_setup () { args="$tmp_in //"; }
+cut_setup () { args='-f 1'; }
+join_setup () { args="$tmp_in $tmp_in"; }
+tr_setup () { args='a a'; }
+
+chmod_setup () { args="a+x $tmp_in"; }
+# Punt on these.
+chgrp_setup () { args=--version; }
+chown_setup () { args=--version; }
+mkfifo_setup () { args=--version; }
+mknod_setup () { args=--version; }
+# Punt on uptime, since it fails (e.g., failing to get boot time)
+# on some systems, and we shouldn't let that stop 'make check'.
+uptime_setup () { args=--version; }
+
+# Create a file in the current directory, not in $TMPDIR.
+mktemp_setup () { args=mktemp.XXXX; }
+
+cmp_setup () { args="$tmp_in $tmp_in2"; }
+
+# Tell dd not to print the line with transfer rate and total.
+# The transfer rate would vary between runs.
+dd_setup () { args=status=noxfer; }
+
+zdiff_setup () { args="$zin $zin2"; }
+zcmp_setup () { zdiff_setup; }
+zcat_setup () { TERM=dumb; export TERM; args=$zin; }
+gunzip_setup () { zcat_setup; }
+zmore_setup () { zcat_setup; }
+zless_setup () { zcat_setup; }
+znew_setup () { args=$bigZ_in; }
+zforce_setup () { zcat_setup; }
+zgrep_setup () { args="z $zin"; }
+zegrep_setup () { zgrep_setup; }
+zfgrep_setup () { zgrep_setup; }
+gzexe_setup () { args=$tmp_in; }
+
+# We know that $tmp_in contains a "0"
+grep_setup () { args="0 $tmp_in"; }
+egrep_setup () { args="0 $tmp_in"; }
+fgrep_setup () { args="0 $tmp_in"; }
+
+diff_setup () { args="$tmp_in $tmp_in2"; }
+sdiff_setup () { args="$tmp_in $tmp_in2"; }
+diff3_setup () { args="$tmp_in $tmp_in2 $tmp_in2"; }
+cp_setup () { args="$tmp_in $tmp_in2"; }
+ln_setup () { args="$tmp_in ln-target"; }
+ginstall_setup () { args="$tmp_in $tmp_in2"; }
+mv_setup () { args="$tmp_in $tmp_in2"; }
+mkdir_setup () { args=$tmp_dir/subdir; }
+realpath_setup () { args=$tmp_in; }
+rmdir_setup () { args=$tmp_dir; }
+rm_setup () { args=$tmp_in; }
+shred_setup () { args=$tmp_in; }
+touch_setup () { args=$tmp_in2; }
+truncate_setup () { args="--reference=$tmp_in $tmp_in2"; }
+
+mkid_setup () { printf 'f(){}\ntypedef int t;\n' > f.c; args=. ; }
+lid_setup () { args=; }
+fid_setup () { args=f.c; }
+fnid_setup () { args=; }
+xtokid_setup () { args=; }
+aid_setup () { args=f; }
+eid_setup () { args=--version; }
+gid_setup () { args=f; }
+defid_setup () { args=t; }
+
+basename_setup () { args=$tmp_in; }
+dirname_setup () { args=$tmp_in; }
+expr_setup () { args=foo; }
+basenc_setup () { args=--version; }
+
+# Punt, in case GNU 'id' hasn't been installed yet.
+groups_setup () { args=--version; }
+
+pathchk_setup () { args=$tmp_in; }
+yes_setup () { args=--version; }
+logname_setup () { args=--version; }
+nohup_setup () { args=--version; }
+printf_setup () { args=foo; }
+seq_setup () { args=10; }
+sleep_setup () { args=0; }
+stdbuf_setup () { args="-oL true"; }
+timeout_setup () { args=--version; }
+
+# I'd rather not run sync, since it spins up disks that I've
+# deliberately caused to spin down (but not unmounted).
+sync_setup () { args=--version; }
+
+test_setup () { args=foo; }
+
+# This is necessary in the unusual event that there is
+# no valid entry in /etc/mtab.
+df_setup () { args=/; }
+
+# This is necessary in the unusual event that getpwuid (getuid ()) fails.
+id_setup () { args=-u; }
+
+# Use env to avoid invoking built-in sleep of Solaris 11's /bin/sh.
+kill_setup () {
+ external=env
+ $external sleep 10m & pid=$!
+ args=$pid
+}
+
+link_setup () { args="$tmp_in link-target"; }
+unlink_setup () { args=$tmp_in; }
+
+readlink_setup () {
+ ln -s . slink
+ args=slink;
+}
+
+stat_setup () { args=$tmp_in; }
+unlink_setup () { args=$tmp_in; }
+lbracket_setup () { args=": ]"; }
+
+parted_setup () { args="-s $tmp_in mklabel gpt"
+ dd if=/dev/null of=$tmp_in seek=2000; }
+
+# Ensure that each program "works" (exits successfully) when doing
+# something more than --help or --version.
+for i in $built_programs; do
+ # Skip these.
+ case $i in chroot|stty|tty|false|chcon|runcon|coreutils) continue;; esac
+
+ rm -rf $tmp_in $tmp_in2 $tmp_dir $tmp_out $bigZ_in $zin $zin2
+ echo z |gzip > $zin
+ cp $zin $zin2
+ cp $zin $bigZ_in
+
+ # This is sort of kludgey: use numbers so this is valid input for factor,
+ # and two tokens so it's valid input for tsort.
+ echo 2147483647 0 > $tmp_in
+ # Make $tmp_in2 identical. Then, using $tmp_in and $tmp_in2 as arguments
+ # to the likes of cmp and diff makes them exit successfully.
+ cp $tmp_in $tmp_in2
+ mkdir $tmp_dir
+ # echo ================== $i
+ test $i = [ && prog=lbracket || prog=$(echo $i|sed "s/$EXEEXT$//")
+ if type ${prog}_setup > /dev/null 2>&1; then
+ ${prog}_setup
+ else
+ args=
+ fi
+ if env $i $args < $tmp_in > $tmp_out; then
+ : # ok
+ else
+ echo FAIL: $i
+ fail=1
+ fi
+ rm -rf $tmp_in $tmp_in2 $tmp_out $tmp_dir
+done
+
+Exit $fail
diff --git a/tests/id/context.sh b/tests/id/context.sh
new file mode 100755
index 0000000..ad7867b
--- /dev/null
+++ b/tests/id/context.sh
@@ -0,0 +1,35 @@
+#!/bin/sh
+# Ensure that "id" outputs SELinux context only without specified user
+# Copyright (C) 2008-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ id
+# Require selinux - when selinux is disabled, id never prints scontext.
+require_selinux_
+
+
+# Check without specified user, context string should be present.
+id | grep context= >/dev/null || fail=1
+
+# Check with specified user, no context string should be present.
+# But if the current user is nameless, skip this part.
+name=$(id -nu) || { test $? -ne 1 && fail=1; }
+if test "$name"; then
+ id "$name" > id_name || fail=1
+ grep context= id_name >/dev/null && fail=1
+fi
+
+Exit $fail
diff --git a/tests/id/gnu-zero-uids.sh b/tests/id/gnu-zero-uids.sh
new file mode 100755
index 0000000..10e028f
--- /dev/null
+++ b/tests/id/gnu-zero-uids.sh
@@ -0,0 +1,29 @@
+#!/bin/sh
+# On GNU, 'id' must fail for processes with zero UIDs.
+
+# Copyright (C) 2011-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ id
+
+require_gnu_
+
+sush - true || skip_ "the 'sush' command does not work"
+
+# Run 'id' with zero UIDs. It should exit with a non-zero status.
+returns_ 1 sush - id > out || fail=1
+
+Exit $fail
diff --git a/tests/id/no-context.sh b/tests/id/no-context.sh
new file mode 100755
index 0000000..449938b
--- /dev/null
+++ b/tests/id/no-context.sh
@@ -0,0 +1,35 @@
+#!/bin/sh
+# With POSIXLY_CORRECT, id must not print context=...
+
+# Copyright (C) 2009-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ id
+
+# We don't need selinux *FS* support to test id,
+# but this is as good a witness as any, in general.
+require_selinux_
+
+
+# Require the context=... part by default.
+id > out || fail=1
+grep context= out || fail=1
+
+# Require no context=... part in conforming mode.
+POSIXLY_CORRECT=1 id > out || fail=1
+grep context= out && fail=1
+
+Exit $fail
diff --git a/tests/id/setgid.sh b/tests/id/setgid.sh
new file mode 100755
index 0000000..f106b13
--- /dev/null
+++ b/tests/id/setgid.sh
@@ -0,0 +1,46 @@
+#!/bin/sh
+# Verify that id [-G] prints the right group when run set-GID.
+
+# Copyright (C) 2012-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ id
+require_root_
+
+getlimits_
+
+# Construct a different group number
+gp1=$NON_ROOT_GID
+gp1=$(expr $gp1 + 1) || framework_failure_
+
+test "$gp1" -lt $GID_T_MAX ||
+ skip_ "GID $gp1 is reserved on some systems"
+
+echo $gp1 > exp || framework_failure_
+
+# With coreutils-8.16 and earlier, id -G would print both:
+# $gp1 $NON_ROOT_GID
+chroot --skip-chdir --user=$NON_ROOT_USERNAME:+$gp1 --groups='' / \
+ env PATH="$PATH" id -G > out || fail=1
+compare exp out || fail=1
+
+# With coreutils-8.22 and earlier, id would erroneously print
+# groups=$NON_ROOT_GID
+chroot --skip-chdir --user=$NON_ROOT_USERNAME:+$gp1 --groups='' / \
+ env PATH="$PATH" id > out || fail=1
+grep -F "groups=$gp1" out || { cat out; fail=1; }
+
+Exit $fail
diff --git a/tests/id/smack.sh b/tests/id/smack.sh
new file mode 100755
index 0000000..d86726e
--- /dev/null
+++ b/tests/id/smack.sh
@@ -0,0 +1,37 @@
+#!/bin/sh
+# SMACK test for the id-command.
+# Derived from tests/id/context.sh and tests/id/no-context.sh.
+# Copyright (C) 2014-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ id
+
+require_smack_
+
+# Check the string "context=" presence without specified user.
+id > out || fail=1
+grep 'context=' out || { cat out; fail=1; }
+
+# Check context=" is absent without specified user in conforming mode.
+POSIXLY_CORRECT=1 id > out || fail=1
+grep 'context=' out && fail=1
+
+# Check the string "context=" absence with specified user.
+# But if the current user is nameless, skip this part.
+id -nu > /dev/null && id $(id -nu) > out
+grep 'context=' out && fail=1
+
+Exit $fail
diff --git a/tests/id/uid.sh b/tests/id/uid.sh
new file mode 100755
index 0000000..41353a8
--- /dev/null
+++ b/tests/id/uid.sh
@@ -0,0 +1,42 @@
+#!/bin/sh
+# Ensure that "id" works with numeric user ids
+# Copyright (C) 2013-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ id
+
+uid=$(id -u) || fail=1
+user=$(id -nu) || fail=1
+
+# Ensure the empty user spec is discarded
+returns_ 1 id '' || fail=1
+
+# Ensure we don't exit early, and process all users
+id $user > user_out || fail=1
+returns_ 1 id '' $user >multi_user_out || fail=1
+compare user_out multi_user_out || fail=1
+
+for mode in '' '-G' '-g'; do
+ id $mode $user > user_out || fail=1 # lookup name for comparison
+
+ id $mode $uid > uid_out || fail=1 # lookup name "$uid" before id "$uid"
+ compare user_out uid_out || fail=1
+
+ id $mode +$uid > uid_out || fail=1 # lookup only id "$uid"
+ compare user_out uid_out || fail=1
+done
+
+Exit $fail
diff --git a/tests/id/zero.sh b/tests/id/zero.sh
new file mode 100755
index 0000000..3813fcd
--- /dev/null
+++ b/tests/id/zero.sh
@@ -0,0 +1,105 @@
+#!/bin/sh
+# Exercise "id --zero".
+
+# Copyright (C) 2013-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ id
+
+u="$( id -nu )"
+id || fail=1
+id "$u" || fail=1
+
+# id(1) should refuse --zero in default format.
+echo 'id: option --zero not permitted in default format' > err-exp \
+ || framework_failure_
+id --zero > out 2>err && fail=1
+compare /dev/null out || fail=1
+compare err-exp err || fail=1
+
+# Create a nice list of users.
+# Add $USER to ensure we have at least one explicit entry.
+users="$u"
+# Add a few typical users to test single group and multiple groups.
+for u in root man postfix sshd nobody ; do
+ id $u >/dev/null 2>&1 && users="$users $u"
+done
+# Add $users and '' (implicit $USER) to list to process.
+printf '%s\n' $users '' >> users || framework_failure_
+
+# Exercise "id -z" with various options.
+printf '\n' > exp || framework_failure_
+> out || framework_failure_
+
+while read u ; do
+ for o in g gr G Gr u ur ; do
+ for n in '' n ; do
+ printf '%s: ' "id -${o}${n}[z] $u" >> exp || framework_failure_
+ printf '\n%s: ' "id -${o}${n}[z] $u" >> out || framework_failure_
+ # There may be no name corresponding to an id, so don't check
+ # exit status when in name lookup mode
+ id -${o}${n} $u >> exp ||
+ { test $? -ne 1 || test -z "$n" && fail=1; }
+ id -${o}${n}z $u > tmp ||
+ { test $? -ne 1 || test -z "$n" && fail=1; }
+ head -c-1 < tmp >> out || framework_failure_
+ done
+ done
+done < users
+printf '\n' >> out || framework_failure_
+tr '\0' ' ' < out > out2 || framework_failure_
+compare exp out2 || fail=1
+
+# multiuser testing with -z
+# test if the options work, these tests should pass if the above tests
+# do.
+
+for o in g gr u ur ; do
+ for n in '' n ; do
+ id -${o}${n} $users >> tmp1 ||
+ { test $? -ne 1 || test -z "$n" && fail=1; }
+ id -${o}${n}z $users > tmp2 ||
+ { test $? -ne 1 || test -z "$n" && fail=1; }
+ tr '\0' '\n' < tmp2 >> tmp3
+ done
+done
+compare tmp1 tmp3 || fail=1
+
+# Separate checks when we are testing for multiple users && -G.
+# This is done because we terminate the records with two NULs
+# instead of a regular single NUL.
+
+NL='
+'
+
+for o in G Gr ; do
+ for n in '' n ; do
+ id -${o}${n} $users >> gtmp1 ||
+ { test $? -ne 1 || test -z "$n" && fail=1; }
+ echo >> gtmp1 || framework_failure_
+
+ id -${o}${n}z $users > gtmp2 ||
+ { test $? -ne 1 || test -z "$n" && fail=1; }
+ # we replace all NULs with spaces, the result we get is there are two
+ # consecutive spaces instead of two NUL's, we pass this to sed
+ # to replace more than 1 space with a newline. This is ideally where a new
+ # line should be. This should make the output similar to without -z.
+ { tr '\0' ' ' < gtmp2; echo; } | sed "s/ /\\$NL/g" >> gtmp3
+ done
+done
+compare gtmp1 gtmp3 || fail=1
+
+Exit $fail
diff --git a/tests/init.sh b/tests/init.sh
new file mode 100755
index 0000000..0494097
--- /dev/null
+++ b/tests/init.sh
@@ -0,0 +1,706 @@
+# source this file; set up for tests
+
+# Copyright (C) 2009-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+# Using this file in a test
+# =========================
+#
+# The typical skeleton of a test looks like this:
+#
+# #!/bin/sh
+# . "${srcdir=.}/init.sh"; path_prepend_ .
+# Execute some commands.
+# Note that these commands are executed in a subdirectory, therefore you
+# need to prepend "../" to relative filenames in the build directory.
+# Note that the "path_prepend_ ." is useful only if the body of your
+# test invokes programs residing in the initial directory.
+# For example, if the programs you want to test are in src/, and this test
+# script is named tests/test-1, then you would use "path_prepend_ ../src",
+# or perhaps export PATH='$(abs_top_builddir)/src$(PATH_SEPARATOR)'"$$PATH"
+# to all tests via automake's TESTS_ENVIRONMENT.
+# Set the exit code 0 for success, 77 for skipped, or 1 or other for failure.
+# Use the skip_ and fail_ functions to print a diagnostic and then exit
+# with the corresponding exit code.
+# Exit $?
+
+# Executing a test that uses this file
+# ====================================
+#
+# Running a single test:
+# $ make check TESTS=test-foo.sh
+#
+# Running a single test, with verbose output:
+# $ make check TESTS=test-foo.sh VERBOSE=yes
+#
+# Running a single test, keeping the temporary directory:
+# $ make check TESTS=test-foo.sh KEEP=yes
+#
+# Running a single test, with single-stepping:
+# 1. Go into a sub-shell:
+# $ bash
+# 2. Set relevant environment variables from TESTS_ENVIRONMENT in the
+# Makefile:
+# $ export srcdir=../../tests # this is an example
+# 3. Execute the commands from the test, copy&pasting them one by one:
+# $ . "$srcdir/init.sh"; path_prepend_ .
+# ...
+# 4. Finally
+# $ exit
+
+# =============================================================================
+# Elementary diagnostics
+
+ME_=`expr "./$0" : '.*/\(.*\)$'`
+
+# Prepare PATH_SEPARATOR.
+# The user is always right.
+if test "${PATH_SEPARATOR+set}" != set; then
+ # Determine PATH_SEPARATOR by trying to find /bin/sh in a PATH which
+ # contains only /bin. Note that ksh looks also at the FPATH variable,
+ # so we have to set that as well for the test.
+ PATH_SEPARATOR=:
+ (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 \
+ && { (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 \
+ || PATH_SEPARATOR=';'
+ }
+fi
+
+# We use a trap below for cleanup. This requires us to go through
+# hoops to get the right exit status transported through the handler.
+# So use 'Exit STATUS' instead of 'exit STATUS' inside of the tests.
+# Turn off errexit here so that we don't trip the bug with OSF1/Tru64
+# sh inside this function.
+Exit () { set +e; (exit $1); exit $1; }
+
+# Print warnings (e.g., about skipped and failed tests) to this file number.
+# Override by defining to say, 9, in init.cfg, and putting say,
+# export ...ENVVAR_SETTINGS...; $(SHELL) 9>&2
+# in the definition of TESTS_ENVIRONMENT in your tests/Makefile.am file.
+# This is useful when using automake's parallel tests mode, to print
+# the reason for skip/failure to console, rather than to the .log files.
+: ${stderr_fileno_=2}
+
+# Note that correct expansion of "$*" depends on IFS starting with ' '.
+# Always write the full diagnostic to stderr.
+# When stderr_fileno_ is not 2, also emit the first line of the
+# diagnostic to that file descriptor.
+warn_ ()
+{
+ # If IFS does not start with ' ', set it and emit the warning in a subshell.
+ case $IFS in
+ ' '*) printf '%s\n' "$*" >&2
+ test $stderr_fileno_ = 2 \
+ || { printf '%s\n' "$*" | sed 1q >&$stderr_fileno_ ; } ;;
+ *) (IFS=' '; warn_ "$@");;
+ esac
+}
+fail_ () { warn_ "$ME_: failed test: $@"; Exit 1; }
+skip_ () { warn_ "$ME_: skipped test: $@"; Exit 77; }
+fatal_ () { warn_ "$ME_: hard error: $@"; Exit 99; }
+framework_failure_ () { warn_ "$ME_: set-up failure: $@"; Exit 99; }
+
+# =============================================================================
+# Ensure the shell supports modern syntax.
+
+# Sanitize this shell to POSIX mode, if possible.
+DUALCASE=1; export DUALCASE
+if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then
+ emulate sh
+ NULLCMD=:
+ alias -g '${1+"$@"}'='"$@"'
+ setopt NO_GLOB_SUBST
+else
+ case `(set -o) 2>/dev/null` in
+ *posix*) set -o posix ;;
+ esac
+fi
+
+# We require $(...) support unconditionally.
+# We require that the printf built-in work correctly regarding octal escapes;
+# this eliminates /bin/sh on AIX 7.2.
+# We require non-surprising "local" semantics (this eliminates dash).
+# This takes the admittedly draconian step of eliminating dash, because the
+# assignment tab=$(printf '\t') works fine, yet preceding it with "local "
+# transforms it into an assignment that sets the variable to the empty string.
+# That is too counter-intuitive, and can lead to subtle run-time malfunction.
+# The example below is less subtle in that with dash, it evokes the run-time
+# exception "dash: 1: local: 1: bad variable name".
+# We require a few additional shell features only when $EXEEXT is nonempty,
+# in order to support automatic $EXEEXT emulation:
+# - hyphen-containing alias names
+# - we prefer to use ${var#...} substitution, rather than having
+# to work around lack of support for that feature.
+# The following code attempts to find a shell with support for these features.
+# If the current shell passes the test, we're done. Otherwise, test other
+# shells until we find one that passes. If one is found, re-exec it.
+# If no acceptable shell is found, skip the current test.
+#
+# The "...set -x; P=1 true 2>err..." test is to disqualify any shell that
+# emits "P=1" into err, as /bin/sh from SunOS 5.11 and OpenBSD 4.7 do.
+#
+# Use "9" to indicate success (rather than 0), in case some shell acts
+# like Solaris 10's /bin/sh but exits successfully instead of with status 2.
+
+# Eval this code in a subshell to determine a shell's suitability.
+# 10 - passes all tests; ok to use
+# 9 - ok, but enabling "set -x" corrupts app stderr; prefer higher score
+# ? - not ok
+gl_shell_test_script_='
+test $(echo y) = y || exit 1
+LC_ALL=en_US.UTF-8 printf "\\351" 2>/dev/null \
+ | LC_ALL=C tr "\\351" x | LC_ALL=C grep "^x$" > /dev/null \
+ || exit 1
+printf "\\351" 2>/dev/null \
+ | LC_ALL=C tr "\\351" x | LC_ALL=C grep "^x$" > /dev/null \
+ || exit 1
+f_local_() { local v=1; }; f_local_ || exit 1
+f_dash_local_fail_() { local t=$(printf " 1"); }; f_dash_local_fail_
+score_=10
+if test "$VERBOSE" = yes; then
+ test -n "$( (exec 3>&1; set -x; P=1 true 2>&3) 2> /dev/null)" && score_=9
+fi
+test -z "$EXEEXT" && exit $score_
+shopt -s expand_aliases
+alias a-b="echo zoo"
+v=abx
+ test ${v%x} = ab \
+ && test ${v#a} = bx \
+ && test $(a-b) = zoo \
+ && exit $score_
+'
+
+if test "x$1" = "x--no-reexec"; then
+ shift
+else
+ # Assume a working shell. Export to subshells (setup_ needs this).
+ gl_set_x_corrupts_stderr_=false
+ export gl_set_x_corrupts_stderr_
+
+ # Record the first marginally acceptable shell.
+ marginal_=
+
+ # Search for a shell that meets our requirements.
+ for re_shell_ in __current__ "${CONFIG_SHELL:-no_shell}" \
+ /bin/sh bash dash zsh pdksh fail
+ do
+ test "$re_shell_" = no_shell && continue
+
+ # If we've made it all the way to the sentinel, "fail" without
+ # finding even a marginal shell, skip this test.
+ if test "$re_shell_" = fail; then
+ test -z "$marginal_" && skip_ failed to find an adequate shell
+ re_shell_=$marginal_
+ break
+ fi
+
+ # When testing the current shell, simply "eval" the test code.
+ # Otherwise, run it via $re_shell_ -c ...
+ if test "$re_shell_" = __current__; then
+ # 'eval'ing this code makes Solaris 10's /bin/sh exit with
+ # $? set to 2. It does not evaluate any of the code after the
+ # "unexpected" first '('. Thus, we must run it in a subshell.
+ ( eval "$gl_shell_test_script_" ) > /dev/null 2>&1
+ else
+ "$re_shell_" -c "$gl_shell_test_script_" 2>/dev/null
+ fi
+
+ st_=$?
+
+ # $re_shell_ works just fine. Use it.
+ if test $st_ = 10; then
+ gl_set_x_corrupts_stderr_=false
+ break
+ fi
+
+ # If this is our first marginally acceptable shell, remember it.
+ if test "$st_:$marginal_" = 9: ; then
+ marginal_="$re_shell_"
+ gl_set_x_corrupts_stderr_=true
+ fi
+ done
+
+ if test "$re_shell_" != __current__; then
+ # Found a usable shell. Preserve -v and -x.
+ case $- in
+ *v*x* | *x*v*) opts_=-vx ;;
+ *v*) opts_=-v ;;
+ *x*) opts_=-x ;;
+ *) opts_= ;;
+ esac
+ re_shell=$re_shell_
+ export re_shell
+ exec "$re_shell_" $opts_ "$0" --no-reexec "$@"
+ echo "$ME_: exec failed" 1>&2
+ exit 127
+ fi
+fi
+
+# =============================================================================
+# Ensure the shell behaves reasonably.
+
+# If this is bash, turn off all aliases.
+test -n "$BASH_VERSION" && unalias -a
+
+# Note that when supporting $EXEEXT (transparently mapping from PROG_NAME to
+# PROG_NAME.exe), we want to support hyphen-containing names like test-acos.
+# That is part of the shell-selection test above. Why use aliases rather
+# than functions? Because support for hyphen-containing aliases is more
+# widespread than that for hyphen-containing function names.
+test -n "$EXEEXT" && test -n "$BASH_VERSION" && shopt -s expand_aliases
+
+# =============================================================================
+# Creating a temporary directory (needed by the core test framework)
+
+# Create a temporary directory, much like mktemp -d does.
+# Written by Jim Meyering.
+#
+# Usage: mktempd_ /tmp phoey.XXXXXXXXXX
+#
+# First, try to use the mktemp program.
+# Failing that, we'll roll our own mktemp-like function:
+# - try to get random bytes from /dev/urandom, mapping them to file-name bytes
+# - failing that, generate output from a combination of quickly-varying
+# sources and awk.
+# - try to create the desired directory.
+# - make only $MAX_TRIES_ attempts
+
+# Helper function. Print $N pseudo-random bytes from a-zA-Z0-9.
+rand_bytes_ ()
+{
+ n_=$1
+
+ # Maybe try openssl rand -base64 $n_prime_|tr '+/=\012' abcd first?
+ # But if they have openssl, they probably have mktemp, too.
+
+ chars_=abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789
+ dev_rand_=/dev/urandom
+ if test -r "$dev_rand_"; then
+ # Note: 256-length($chars_) == 194; 3 copies of $chars_ is 186 + 8 = 194.
+ dd ibs=$n_ count=1 if=$dev_rand_ 2>/dev/null \
+ | LC_ALL=C tr -c $chars_ 01234567$chars_$chars_$chars_
+ return
+ fi
+
+ # Fall back on quickly-varying sources + awk.
+ # Limit awk program to 7th Edition Unix so that it works even on Solaris 10.
+
+ (date; date +%N; free; who -a; w; ps auxww; ps -ef) 2>&1 | awk '
+ BEGIN {
+ n = '"$n_"'
+ for (i = 0; i < 256; i++)
+ ordinal[sprintf ("%c", i)] = i
+ }
+ {
+ for (i = 1; i <= length; i++)
+ a[ai++ % n] += ordinal[substr ($0, i, 1)]
+ }
+ END {
+ chars = "'"$chars_"'"
+ charslen = length (chars)
+ for (i = 0; i < n; i++)
+ printf "%s", substr (chars, a[i] % charslen + 1, 1)
+ printf "\n"
+ }
+ '
+}
+
+mktempd_ ()
+{
+ case $# in
+ 2);;
+ *) fail_ "Usage: mktempd_ DIR TEMPLATE";;
+ esac
+
+ destdir_=$1
+ template_=$2
+
+ MAX_TRIES_=4
+
+ # Disallow any trailing slash on specified destdir:
+ # it would subvert the post-mktemp "case"-based destdir test.
+ case $destdir_ in
+ / | //) destdir_slash_=$destdir;;
+ */) fail_ "invalid destination dir: remove trailing slash(es)";;
+ *) destdir_slash_=$destdir_/;;
+ esac
+
+ case $template_ in
+ *XXXX) ;;
+ *) fail_ \
+ "invalid template: $template_ (must have a suffix of at least 4 X's)";;
+ esac
+
+ # First, try to use mktemp.
+ d=`unset TMPDIR; { mktemp -d -t -p "$destdir_" "$template_"; } 2>/dev/null` &&
+
+ # The resulting name must be in the specified directory.
+ case $d in "$destdir_slash_"*) :;; *) false;; esac &&
+
+ # It must have created the directory.
+ test -d "$d" &&
+
+ # It must have 0700 permissions. Handle sticky "S" bits.
+ perms=`ls -dgo "$d" 2>/dev/null` &&
+ case $perms in drwx--[-S]---*) :;; *) false;; esac && {
+ echo "$d"
+ return
+ }
+
+ # If we reach this point, we'll have to create a directory manually.
+
+ # Get a copy of the template without its suffix of X's.
+ base_template_=`echo "$template_"|sed 's/XX*$//'`
+
+ # Calculate how many X's we've just removed.
+ template_length_=`echo "$template_" | wc -c`
+ nx_=`echo "$base_template_" | wc -c`
+ nx_=`expr $template_length_ - $nx_`
+
+ err_=
+ i_=1
+ while :; do
+ X_=`rand_bytes_ $nx_`
+ candidate_dir_="$destdir_slash_$base_template_$X_"
+ err_=`mkdir -m 0700 "$candidate_dir_" 2>&1` \
+ && { echo "$candidate_dir_"; return; }
+ test $MAX_TRIES_ -le $i_ && break;
+ i_=`expr $i_ + 1`
+ done
+ fail_ "$err_"
+}
+
+# =============================================================================
+# Core test framework
+
+# An arbitrary prefix to help distinguish test directories.
+testdir_prefix_ () { printf gt; }
+
+# Set up the environment for the test to run in.
+setup_ ()
+{
+ if test "$VERBOSE" = yes; then
+ # Test whether set -x may cause the selected shell to corrupt an
+ # application's stderr. Many do, including zsh-4.3.10 and the /bin/sh
+ # from SunOS 5.11, OpenBSD 4.7 and Irix 6.5.
+ # If enabling verbose output this way would cause trouble, simply
+ # issue a warning and refrain.
+ if $gl_set_x_corrupts_stderr_; then
+ warn_ "using SHELL=$SHELL with 'set -x' corrupts stderr"
+ else
+ set -x
+ fi
+ fi
+
+ initial_cwd_=$PWD
+
+ # Create and enter the temporary directory.
+ pfx_=`testdir_prefix_`
+ test_dir_=`mktempd_ "$initial_cwd_" "$pfx_-$ME_.XXXX"` \
+ || fail_ "failed to create temporary directory in $initial_cwd_"
+ cd "$test_dir_" || fail_ "failed to cd to temporary directory"
+ # Set variables srcdir, builddir, for the convenience of the test.
+ case $srcdir in
+ /* | ?:*) ;;
+ *) srcdir="../$srcdir" ;;
+ esac
+ builddir=".."
+ export srcdir builddir
+
+ # As autoconf-generated configure scripts do, ensure that IFS
+ # is defined initially, so that saving and restoring $IFS works.
+ gl_init_sh_nl_='
+'
+ IFS=" "" $gl_init_sh_nl_"
+
+ # This trap statement, along with a trap on 0 below, ensure that the
+ # temporary directory, $test_dir_, is removed upon exit as well as
+ # upon receipt of any of the listed signals.
+ for sig_ in 1 2 3 13 15; do
+ eval "trap 'Exit $(expr $sig_ + 128)' $sig_"
+ done
+
+ # Remove relative and non-accessible directories from PATH, including '.'
+ # and Zero-length entries.
+ saved_IFS="$IFS"
+ IFS=:
+ new_PATH=
+ sep_=
+ for dir in $PATH; do
+ case "$dir" in
+ /*) test -d "$dir/." || continue
+ new_PATH="${new_PATH}${sep_}${dir}"
+ sep_=':';;
+ esac
+ done
+ IFS="$saved_IFS"
+ PATH="$new_PATH"
+ export PATH
+}
+
+# This is a stub function that is run upon trap (upon regular exit and
+# interrupt). Override it with a per-test function, e.g., to unmount
+# a partition, or to undo any other global state changes.
+cleanup_ () { :; }
+
+# Run the user-overridable cleanup_ function, remove the temporary
+# directory and exit with the incoming value of $?.
+remove_tmp_ ()
+{
+ __st=$?
+ cleanup_
+ if test "$KEEP" = yes; then
+ echo "Not removing temporary directory $test_dir_"
+ else
+ # cd out of the directory we're about to remove
+ cd "$initial_cwd_" || cd / || cd /tmp
+ chmod -R u+rwx "$test_dir_"
+ # If removal fails and exit status was to be 0, then change it to 1.
+ rm -rf "$test_dir_" || { test $__st = 0 && __st=1; }
+ fi
+ exit $__st
+}
+
+# =============================================================================
+# Prepending directories to PATH
+
+# Given a directory name, DIR, if every entry in it that matches *.exe
+# contains only the specified bytes (see the case stmt below), then print
+# a space-separated list of those names and return 0. Otherwise, don't
+# print anything and return 1. Naming constraints apply also to DIR.
+find_exe_basenames_ ()
+{
+ feb_dir_=$1
+ feb_fail_=0
+ feb_result_=
+ feb_sp_=
+ for feb_file_ in $feb_dir_/*.exe; do
+ # If there was no *.exe file, or there existed a file named "*.exe" that
+ # was deleted between the above glob expansion and the existence test
+ # below, just skip it.
+ test "x$feb_file_" = "x$feb_dir_/*.exe" && test ! -f "$feb_file_" \
+ && continue
+ # Exempt [.exe, since we can't create a function by that name, yet
+ # we can't invoke [ by PATH search anyways due to shell builtins.
+ test "x$feb_file_" = "x$feb_dir_/[.exe" && continue
+ case $feb_file_ in
+ *[!-a-zA-Z/0-9_.+]*) feb_fail_=1; break;;
+ *) # Remove leading file name components as well as the .exe suffix.
+ feb_file_=${feb_file_##*/}
+ feb_file_=${feb_file_%.exe}
+ feb_result_="$feb_result_$feb_sp_$feb_file_";;
+ esac
+ feb_sp_=' '
+ done
+ test $feb_fail_ = 0 && printf %s "$feb_result_"
+ return $feb_fail_
+}
+
+# Consider the files in directory, $1.
+# For each file name of the form PROG.exe, create an alias named
+# PROG that simply invokes PROG.exe, then return 0. If any selected
+# file name or the directory name, $1, contains an unexpected character,
+# define no alias and return 1.
+create_exe_shims_ ()
+{
+ case $EXEEXT in
+ '') return 0 ;;
+ .exe) ;;
+ *) echo "$0: unexpected \$EXEEXT value: $EXEEXT" 1>&2; return 1 ;;
+ esac
+
+ base_names_=`find_exe_basenames_ $1` \
+ || { echo "$0 (exe_shim): skipping directory: $1" 1>&2; return 0; }
+
+ if test -n "$base_names_"; then
+ for base_ in $base_names_; do
+ alias "$base_"="$base_$EXEEXT"
+ done
+ fi
+
+ return 0
+}
+
+# Use this function to prepend to PATH an absolute name for each
+# specified, possibly-$initial_cwd_-relative, directory.
+path_prepend_ ()
+{
+ while test $# != 0; do
+ path_dir_=$1
+ case $path_dir_ in
+ '') fail_ "invalid path dir: '$1'";;
+ /* | ?:*) abs_path_dir_=$path_dir_;;
+ *) abs_path_dir_=$initial_cwd_/$path_dir_;;
+ esac
+ case $abs_path_dir_ in
+ *$PATH_SEPARATOR*) fail_ "invalid path dir: '$abs_path_dir_'";;
+ esac
+ PATH="$abs_path_dir_$PATH_SEPARATOR$PATH"
+
+ # Create an alias, FOO, for each FOO.exe in this directory.
+ create_exe_shims_ "$abs_path_dir_" \
+ || fail_ "something failed (above): $abs_path_dir_"
+ shift
+ done
+ export PATH
+}
+
+# =============================================================================
+# Convenience environment variables for the tests
+
+# -----------------------------------------------------------------------------
+
+# Enable glibc's malloc-perturbing option.
+# This is useful for exposing code that depends on the fact that
+# malloc-related functions often return memory that is mostly zeroed.
+# If you have the time and cycles, use valgrind to do an even better job.
+: ${MALLOC_PERTURB_=87}
+export MALLOC_PERTURB_
+
+# -----------------------------------------------------------------------------
+
+# The interpreter for Bourne-shell scripts.
+# No special standards compatibility requirements.
+# Some environments, such as Android, don't have /bin/sh.
+if test -f /bin/sh$EXEEXT; then
+ BOURNE_SHELL=/bin/sh
+else
+ BOURNE_SHELL=sh
+fi
+
+# =============================================================================
+# Convenience functions for the tests
+
+# -----------------------------------------------------------------------------
+# Return value checking
+
+# This is used to simplify checking of the return value
+# which is useful when ensuring a command fails as desired.
+# I.e., just doing `command ... &&fail=1` will not catch
+# a segfault in command for example. With this helper you
+# instead check an explicit exit code like
+# returns_ 1 command ... || fail
+returns_ () {
+ # Disable tracing so it doesn't interfere with stderr of the wrapped command
+ { set +x; } 2>/dev/null
+
+ local exp_exit="$1"
+ shift
+ "$@"
+ test $? -eq $exp_exit && ret_=0 || ret_=1
+
+ if test "$VERBOSE" = yes && test "$gl_set_x_corrupts_stderr_" = false; then
+ set -x
+ fi
+ { return $ret_; } 2>/dev/null
+}
+
+# -----------------------------------------------------------------------------
+# Text file comparison
+
+# Emit a header similar to that from diff -u; Print the simulated "diff"
+# command so that the order of arguments is clear. Don't bother with @@ lines.
+emit_diff_u_header_ ()
+{
+ printf '%s\n' "diff -u $*" \
+ "--- $1 1970-01-01" \
+ "+++ $2 1970-01-01"
+}
+
+# Arrange not to let diff or cmp operate on /dev/null,
+# since on some systems (at least OSF/1 5.1), that doesn't work.
+# When there are not two arguments, or no argument is /dev/null, return 2.
+# When one argument is /dev/null and the other is not empty,
+# cat the nonempty file to stderr and return 1.
+# Otherwise, return 0.
+compare_dev_null_ ()
+{
+ test $# = 2 || return 2
+
+ if test "x$1" = x/dev/null; then
+ test -s "$2" || return 0
+ emit_diff_u_header_ "$@"; sed 's/^/+/' "$2"
+ return 1
+ fi
+
+ if test "x$2" = x/dev/null; then
+ test -s "$1" || return 0
+ emit_diff_u_header_ "$@"; sed 's/^/-/' "$1"
+ return 1
+ fi
+
+ return 2
+}
+
+for diff_opt_ in -u -U3 -c '' no; do
+ test "$diff_opt_" != no &&
+ diff_out_=`exec 2>/dev/null
+ LC_ALL=C diff $diff_opt_ "$0" "$0" < /dev/null` &&
+ break
+done
+if test "$diff_opt_" != no; then
+ if test -z "$diff_out_"; then
+ compare_ () { LC_ALL=C diff $diff_opt_ "$@"; }
+ else
+ compare_ ()
+ {
+ # If no differences were found, AIX and HP-UX 'diff' produce output
+ # like "No differences encountered". Hide this output.
+ LC_ALL=C diff $diff_opt_ "$@" > diff.out
+ diff_status_=$?
+ test $diff_status_ -eq 0 || cat diff.out || diff_status_=2
+ rm -f diff.out || diff_status_=2
+ return $diff_status_
+ }
+ fi
+elif cmp -s /dev/null /dev/null 2>/dev/null; then
+ compare_ () { cmp -s "$@"; }
+else
+ compare_ () { cmp "$@"; }
+fi
+
+# Usage: compare EXPECTED ACTUAL
+#
+# Given compare_dev_null_'s preprocessing, defer to compare_ if 2 or more.
+# Otherwise, propagate $? to caller: any diffs have already been printed.
+compare ()
+{
+ # This looks like it can be factored to use a simple "case $?"
+ # after unchecked compare_dev_null_ invocation, but that would
+ # fail in a "set -e" environment.
+ if compare_dev_null_ "$@"; then
+ return 0
+ else
+ case $? in
+ 1) return 1;;
+ *) compare_ "$@";;
+ esac
+ fi
+}
+
+# -----------------------------------------------------------------------------
+
+# If you want to override the testdir_prefix_ function,
+# or to add more utility functions, use this file.
+test -f "$srcdir/init.cfg" \
+ && . "$srcdir/init.cfg"
+
+# =============================================================================
+# Set up the environment for the test to run in.
+
+setup_ "$@"
+# This trap is here, rather than in the setup_ function, because some
+# shells run the exit trap at shell function exit, rather than script exit.
+trap remove_tmp_ EXIT
diff --git a/tests/install/basic-1.sh b/tests/install/basic-1.sh
new file mode 100755
index 0000000..349c1a7
--- /dev/null
+++ b/tests/install/basic-1.sh
@@ -0,0 +1,151 @@
+#!/bin/sh
+# Basic tests for "install".
+
+# Copyright (C) 1998-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ ginstall
+skip_if_root_
+
+dir=dir
+file=file
+
+rm -rf $dir $file || framework_failure_
+mkdir -p $dir || framework_failure_
+echo foo > $file || framework_failure_
+
+ginstall $file $dir || fail=1
+# Make sure the source file still exists.
+test -f $file || fail=1
+# Make sure the dest file has been created.
+test -f $dir/$file || fail=1
+
+# Make sure strip works.
+dd=dd$EXEEXT
+dd2=dd2$EXEEXT
+
+just_built_dd=$abs_top_builddir/src/$dd
+
+test -r "$just_built_dd" \
+ || warn_ "WARNING!!! Your just-built dd binary, $just_built_dd
+is not readable, so skipping the remaining tests in this file."
+
+cp "$just_built_dd" . || fail=1
+cp $dd $dd2 || fail=1
+
+strip=-s
+if ! strip $dd2; then
+ ! test -e $abs_top_builddir/src/coreutils \
+ && warn_ "WARNING!!! Your strip command doesn't seem to work,
+so skipping the test of install's --strip option."
+ strip=
+fi
+
+# This test would fail with 3.16s when using versions of strip that
+# don't work on read-only files (the one from binutils works fine).
+ginstall $strip -c -m 555 $dd $dir || fail=1
+# Make sure the source file is still around.
+test -f $dd || fail=1
+
+# Make sure that the destination file has the requested permissions.
+mode=$(ls -l $dir/$dd|cut -b-10)
+test "$mode" = -r-xr-xr-x || fail=1
+
+# These failed in coreutils CVS from 2004-06-25 to 2004-08-11.
+ginstall -d . || fail=1
+ginstall -d newdir || fail=1
+test -d newdir || fail=1
+ginstall -d newdir1 newdir2 newdir3 || fail=1
+test -d newdir1 || fail=1
+test -d newdir2 || fail=1
+test -d newdir3 || fail=1
+
+# This fails because mkdir-p.c's make_dir_parents fails to return to its
+# initial working directory ($iwd) after creating the first argument, and
+# hence cannot do anything meaningful with the following relative-named dirs.
+iwd=$(pwd)
+mkdir sub || fail=1
+(cd sub &&
+ chmod 0 . &&
+ returns_ 1 ginstall -d "$iwd/xx/yy" rel/sub1 rel/sub2 2> /dev/null
+) || fail=1
+chmod 755 sub
+
+# Ensure that the first argument-dir has been created.
+test -d xx/yy || fail=1
+
+# Make sure that the 'rel' directory was not created...
+test -d sub/rel && fail=1
+# and make sure it was not created in the wrong place.
+test -d xx/rel && fail=1
+
+# Test that we can install from an unreadable directory with an
+# inaccessible parent. coreutils 5.97 fails this test.
+# Perform this test only if "." is on a local file system.
+# Otherwise, it would fail e.g., on an NFS-mounted file system.
+if is_local_dir_ .; then
+ mkdir -p sub1/d || fail=1
+ (cd sub1/d && chmod a-r . && chmod a-rx .. &&
+ ginstall -d "$iwd/xx/zz" rel/a rel/b) || fail=1
+ chmod 755 sub1 sub1/d || fail=1
+ test -d xx/zz || fail=1
+ test -d sub1/d/rel/a || fail=1
+ test -d sub1/d/rel/b || fail=1
+fi
+
+touch file || fail=1
+ginstall -Dv file sub3/a/b/c/file >out 2>&1 || fail=1
+compare - out <<\EOF || fail=1
+ginstall: creating directory 'sub3'
+ginstall: creating directory 'sub3/a'
+ginstall: creating directory 'sub3/a/b'
+ginstall: creating directory 'sub3/a/b/c'
+'file' -> 'sub3/a/b/c/file'
+EOF
+
+# Test -D together with -t (available since coreutils >= 8.23).
+# Let ginstall create a completely new destination hierarchy.
+ginstall -t sub4/a/b/c -Dv file >out 2>&1 || fail=1
+compare - out <<\EOF || fail=1
+ginstall: creating directory 'sub4'
+ginstall: creating directory 'sub4/a'
+ginstall: creating directory 'sub4/a/b'
+ginstall: creating directory 'sub4/a/b/c'
+'file' -> 'sub4/a/b/c/file'
+EOF
+
+# Ensure that -D with an already existing file as -t's option argument fails.
+touch sub4/file_exists || framework_failure_
+ginstall -t sub4/file_exists -Dv file >out 2>&1 && fail=1
+compare - out <<\EOF || fail=1
+ginstall: failed to access 'sub4/file_exists': Not a directory
+EOF
+
+# Ensure that -D with an already existing directory for -t's option argument
+# succeeds.
+mkdir sub4/dir_exists || framework_failure_
+touch sub4/dir_exists || framework_failure_
+ginstall -t sub4/dir_exists -Dv file >out 2>&1 || fail=1
+compare - out <<\EOF || fail=1
+'file' -> 'sub4/dir_exists/file'
+EOF
+
+# Ensure omitted directories are diagnosed
+returns_ 1 ginstall . . 2>err || fail=1
+printf '%s\n' "ginstall: omitting directory '.'" >exp || framework_failure_
+compare exp err || fail=1
+
+Exit $fail
diff --git a/tests/install/create-leading.sh b/tests/install/create-leading.sh
new file mode 100755
index 0000000..8dcfdb1
--- /dev/null
+++ b/tests/install/create-leading.sh
@@ -0,0 +1,42 @@
+#!/bin/sh
+# Test -D option.
+
+# Copyright (C) 2000-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+# Note that the tests below use 'ginstall', not install, because
+# that's the name of the binary in ../../src.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ ginstall
+
+
+file=file
+echo foo > $file || framework_failure_
+
+# Before 4.0q, this would mistakenly create $file, not 'dest'
+# in no-dir1/no-dir2/.
+ginstall -D $file no-dir1/no-dir2/dest || fail=1
+test -d no-dir1/no-dir2 || fail=1
+test -r no-dir1/no-dir2/dest || fail=1
+
+# Between 6.1 and 8.24, this would not copy $file
+# due to incorrectly modified working directory
+mkdir dir1 || framework_failure_
+touch dir1/file1 || framework_failure_
+ginstall -D "$PWD/dir1/file1" $file -t "$PWD/no-dir2/" || fail=1
+test -r no-dir2/$file && test -r no-dir2/file1 || fail=1
+
+Exit $fail
diff --git a/tests/install/d-slashdot.sh b/tests/install/d-slashdot.sh
new file mode 100755
index 0000000..e86a934
--- /dev/null
+++ b/tests/install/d-slashdot.sh
@@ -0,0 +1,29 @@
+#!/bin/sh
+# Ensure that ginstall -d works with arguments specified with a trailing "/.".
+
+# Copyright (C) 2005-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ ginstall
+
+
+ginstall -d d1/. || fail=1
+test -d d1 || fail=1
+
+ginstall -d d2/.. || fail=1
+test -d d2 || fail=1
+
+Exit $fail
diff --git a/tests/install/install-C-root.sh b/tests/install/install-C-root.sh
new file mode 100755
index 0000000..edf6e7e
--- /dev/null
+++ b/tests/install/install-C-root.sh
@@ -0,0 +1,77 @@
+#!/bin/sh
+# Ensure "install -C" compares owner and group.
+
+# Copyright (C) 2008-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ ginstall
+require_root_
+skip_if_setgid_
+skip_if_nondefault_group_
+
+u1=1
+u2=2
+g1=1
+g2=2
+
+
+echo test > a || framework_failure_
+echo "'a' -> 'b'" > out_installed_first
+echo "removed 'b'
+'a' -> 'b'" > out_installed_second
+> out_empty
+
+# destination file does not exist
+ginstall -Cv -o$u1 -g$g1 a b > out || fail=1
+compare out out_installed_first || fail=1
+
+# destination file exists
+ginstall -Cv -o$u1 -g$g1 a b > out || fail=1
+compare out out_empty || fail=1
+
+# destination file exists but -C is not given
+ginstall -v -o$u1 -g$g1 a b > out || fail=1
+compare out out_installed_second || fail=1
+
+# destination file exists but owner differs
+ginstall -Cv -o$u2 -g$g1 a b > out || fail=1
+compare out out_installed_second || fail=1
+ginstall -Cv -o$u2 -g$g1 a b > out || fail=1
+compare out out_empty || fail=1
+
+# destination file exists but group differs
+ginstall -Cv -o$u2 -g$g2 a b > out || fail=1
+compare out out_installed_second || fail=1
+ginstall -Cv -o$u2 -g$g2 a b > out || fail=1
+compare out out_empty || fail=1
+
+# destination file exists but owner differs from getuid ()
+ginstall -Cv -o$u2 a b > out || fail=1
+compare out out_installed_second || fail=1
+ginstall -Cv a b > out || fail=1
+compare out out_installed_second || fail=1
+ginstall -Cv a b > out || fail=1
+compare out out_empty || fail=1
+
+# destination file exists but group differs from getgid ()
+ginstall -Cv -g$g2 a b > out || fail=1
+compare out out_installed_second || fail=1
+ginstall -Cv a b > out || fail=1
+compare out out_installed_second || fail=1
+ginstall -Cv a b > out || fail=1
+compare out out_empty || fail=1
+
+Exit $fail
diff --git a/tests/install/install-C-selinux.sh b/tests/install/install-C-selinux.sh
new file mode 100755
index 0000000..8441c07
--- /dev/null
+++ b/tests/install/install-C-selinux.sh
@@ -0,0 +1,51 @@
+#!/bin/sh
+# Ensure "install -C" compares SELinux context.
+
+# Copyright (C) 2008-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ ginstall
+require_selinux_
+skip_if_nondefault_group_
+
+echo test > a || framework_failure_
+chcon -u system_u a || skip_ "chcon doesn't work"
+
+echo "'a' -> 'b'" > out_installed_first
+echo "removed 'b'
+'a' -> 'b'" > out_installed_second
+> out_empty
+
+# destination file does not exist
+ginstall -Cv --preserve-context a b > out || fail=1
+compare out out_installed_first || fail=1
+
+# destination file exists
+ginstall -Cv --preserve-context a b > out || fail=1
+compare out out_empty || fail=1
+
+# destination file exists but -C is not given
+ginstall -v --preserve-context a b > out || fail=1
+compare out out_installed_second || fail=1
+
+# destination file exists but SELinux context differs
+chcon -u unconfined_u a || skip_ "chcon doesn't work"
+ginstall -Cv --preserve-context a b > out || fail=1
+compare out out_installed_second || fail=1
+ginstall -Cv --preserve-context a b > out || fail=1
+compare out out_empty || fail=1
+
+Exit $fail
diff --git a/tests/install/install-C.sh b/tests/install/install-C.sh
new file mode 100755
index 0000000..9f49ca6
--- /dev/null
+++ b/tests/install/install-C.sh
@@ -0,0 +1,115 @@
+#!/bin/sh
+# Ensure "install -C" works. (basic tests)
+
+# Copyright (C) 2008-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ ginstall
+skip_if_setgid_
+skip_if_nondefault_group_
+
+# Note if a group is not specified, install(1) will assume that a file
+# would be installed with the current user's group ID, and thus if the
+# file is the same except that it does have a different group due to
+# its parent directory being g+s for example, then the copy will be
+# done again redundantly in a futile attempt to reset the group ID to
+# that of the current user.
+#
+# install -d -g wheel -m 2775 test # Create setgid dir
+# touch test/a # Create source
+# install -Cv -m664 test/a test/i1 # install source with mode
+# install -Cv -m664 test/i1 test/i2 # install dest
+# install -Cv -m664 test/i1 test/i2 # again to see redundant install
+#
+# Similarly if an existing file exists that is the same and has the
+# current users group ID, but when an actual install of the file would
+# reset to a different group ID due to the directory being g+s for example,
+# then the install will not be done when it should.
+#
+# install -Cv -m664 -g "$(id -nrg)" test/i1 test/i2 # set i2 to uesr's gid
+# install -Cv -m664 test/i1 test/i2 # this should install but doesn't
+#
+# Therefore we skip the test in the presence of setgid dirs
+# An additional complication on HFS is that it...
+
+mode1=0644
+mode2=0755
+mode3=2755
+
+
+echo test > a || framework_failure_
+echo "'a' -> 'b'" > out_installed_first || framework_failure_
+echo "removed 'b'
+'a' -> 'b'" > out_installed_second || framework_failure_
+> out_empty || framework_failure_
+
+# destination file does not exist
+ginstall -Cv -m$mode1 a b > out || fail=1
+compare out out_installed_first || fail=1
+
+# destination file exists
+ginstall -Cv -m$mode1 a b > out || fail=1
+compare out out_empty || fail=1
+
+# destination file exists (long option)
+ginstall -v --compare -m$mode1 a b > out || fail=1
+compare out out_empty || fail=1
+
+# destination file exists but -C is not given
+ginstall -v -m$mode1 a b > out || fail=1
+compare out out_installed_second || fail=1
+
+# option -C ignored if any non-permission mode should be set
+ginstall -Cv -m$mode3 a b > out || fail=1
+compare out out_installed_second || fail=1
+ginstall -Cv -m$mode3 a b > out || fail=1
+compare out out_installed_second || fail=1
+
+# files are not regular files
+ln -s a c || framework_failure_
+ln -s b d || framework_failure_
+ginstall -Cv -m$mode1 c d > out || fail=1
+echo "removed 'd'
+'c' -> 'd'" > out_installed_second_cd
+compare out out_installed_second_cd || fail=1
+
+# destination file exists but content differs
+echo test1 > a || framework_failure_
+ginstall -Cv -m$mode1 a b > out || fail=1
+compare out out_installed_second || fail=1
+ginstall -Cv -m$mode1 a b > out || fail=1
+compare out out_empty || fail=1
+
+# destination file exists but content differs (same size)
+echo test2 > a || framework_failure_
+ginstall -Cv -m$mode1 a b > out || fail=1
+compare out out_installed_second || fail=1
+ginstall -Cv -m$mode1 a b > out || fail=1
+compare out out_empty || fail=1
+
+# destination file exists but mode differs
+ginstall -Cv -m$mode2 a b > out || fail=1
+compare out out_installed_second || fail=1
+ginstall -Cv -m$mode2 a b > out || fail=1
+compare out out_empty || fail=1
+
+# options -C and --preserve-timestamps are mutually exclusive
+returns_ 1 ginstall -C --preserve-timestamps a b || fail=1
+
+# options -C and --strip are mutually exclusive
+returns_ 1 ginstall -C --strip --strip-program=echo a b || fail=1
+
+Exit $fail
diff --git a/tests/install/install-Z-selinux.sh b/tests/install/install-Z-selinux.sh
new file mode 100755
index 0000000..f291d8f
--- /dev/null
+++ b/tests/install/install-Z-selinux.sh
@@ -0,0 +1,57 @@
+#!/bin/sh
+# test 'install -Z -D' and 'install -Z -d'
+# based on tests/mkdir/restorecon.sh
+
+# Copyright (C) 2013-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ ginstall
+require_selinux_
+
+mkdir subdir || framework_failure_
+ctx='root:object_r:tmp_t'
+mls_enabled_ && ctx="$ctx:s0"
+chcon "$ctx" subdir || skip_ "Failed to set context: $ctx"
+cd subdir
+
+# Since in a tmp_t dir, dirs can be created as user_tmp_t ...
+touch standard || framework_failure_
+mkdir restored || framework_failure_
+if restorecon restored 2>/dev/null; then
+ # ... but when restored can be set to user_home_t
+ # So ensure the type for these mkdir -Z cases matches
+ # the directory type as set by restorecon.
+ ginstall -Z standard single || fail=1
+ ginstall -Z -d single_d || fail=1
+ # Run these as separate processes in case global context
+ # set for an arg, impacts on another arg
+ # TODO: Have the defaultcon() vary over these directories
+ for dst in single_d/existing/file multi/ple/file; do
+ ginstall -Z -D standard "$dst" || fail=1
+ done
+ restored_type=$(get_selinux_type 'restored')
+ test "$(get_selinux_type 'single')" = "$restored_type" || fail=1
+ test "$(get_selinux_type 'single_d')" = "$restored_type" || fail=1
+ test "$(get_selinux_type 'single_d/existing')" = "$restored_type" || fail=1
+ test "$(get_selinux_type 'multi')" = "$restored_type" || fail=1
+ test "$(get_selinux_type 'multi/ple')" = "$restored_type" || fail=1
+fi
+if test "$fail" = '1'; then
+ ls -UZd standard restored
+ ls -UZd single single_d single_d/existing multi multi/ple
+fi
+
+Exit $fail
diff --git a/tests/install/strip-program.sh b/tests/install/strip-program.sh
new file mode 100755
index 0000000..1b7de52
--- /dev/null
+++ b/tests/install/strip-program.sh
@@ -0,0 +1,48 @@
+#!/bin/sh
+# Ensure "install -s --strip-program=PROGRAM" uses the program to strip
+
+# Copyright (C) 2008-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ ginstall
+
+working_umask_or_skip_
+
+cat <<EOF > b || framework_failure_
+#!$SHELL
+sed s/b/B/ \$1 > \$1.t && mv \$1.t \$1
+EOF
+chmod a+x b || framework_failure_
+
+echo abc > src || framework_failure_
+echo aBc > exp || framework_failure_
+ginstall src dest -s --strip-program=./b || fail=1
+compare exp dest || fail=1
+
+# Check that install cleans up properly if strip fails.
+returns_ 1 ginstall src dest2 -s --strip-program=./FOO || fail=1
+test -e dest2 && fail=1
+
+# Ensure naked hyphens not passed
+cat <<EOF > no-hyphen || framework_failure_
+#!$SHELL
+printf -- '%s\\n' "\$1" | grep '^[^-]'
+EOF
+chmod a+x no-hyphen || framework_failure_
+
+ginstall -s --strip-program=./no-hyphen -- src -dest || fail=1
+
+Exit $fail
diff --git a/tests/install/trap.sh b/tests/install/trap.sh
new file mode 100755
index 0000000..4e1c5eb
--- /dev/null
+++ b/tests/install/trap.sh
@@ -0,0 +1,33 @@
+#!/bin/sh
+# Ensure that 'install -s' doesn't infloop when its parent
+# process traps CHLD signal.
+
+# Copyright (C) 2004-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ ginstall
+require_trap_signame_
+
+
+# Use a subshell and an exec to work around a bug in FreeBSD 5.0 /bin/sh.
+(
+ trap '' CHLD
+
+ # Before 2004-04-21, install would infloop, in the 'while (wait...' loop:
+ exec ginstall -s "$abs_top_builddir/src/ginstall$EXEEXT" .
+)
+
+Exit $fail
diff --git a/tests/lang-default b/tests/lang-default
new file mode 100644
index 0000000..882672f
--- /dev/null
+++ b/tests/lang-default
@@ -0,0 +1,10 @@
+#!/bin/sh
+# Set locale-related environment variables so we get consistent
+# message translations, time formats, sort orderings, etc.
+
+LC_ALL=C
+export LC_ALL
+unset LANGUAGE NLSPATH
+
+# These settings shouldn't matter, but unset them anyway just in case.
+unset LANG LC_COLLATE LC_CTYPE LC_MESSAGES LC_MONETARY LC_NUMERIC LC_TIME
diff --git a/tests/ln/backup-1.sh b/tests/ln/backup-1.sh
new file mode 100755
index 0000000..0874d9d
--- /dev/null
+++ b/tests/ln/backup-1.sh
@@ -0,0 +1,30 @@
+#!/bin/sh
+# Try to create a symlink with backup where the destination file exists
+# and the backup file name is a hard link to the destination file.
+
+# Copyright (C) 1999-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+# Based on a problem report from Jamie Lokier.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ ln
+
+touch a b || framework_failure_
+
+ln b b~ || fail=1
+ln -f --b=simple a b || fail=1
+
+Exit $fail
diff --git a/tests/ln/hard-backup.sh b/tests/ln/hard-backup.sh
new file mode 100755
index 0000000..855fab5
--- /dev/null
+++ b/tests/ln/hard-backup.sh
@@ -0,0 +1,32 @@
+#!/bin/sh
+# Ensure that 'ln --backup F F' gives a proper diagnostic.
+
+# Copyright (C) 2006-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ ln
+
+touch f || framework_failure_
+
+
+ln --backup f f 2> out && fail=1
+cat <<\EOF > exp || framework_failure_
+ln: 'f' and 'f' are the same file
+EOF
+
+compare exp out || fail=1
+
+Exit $fail
diff --git a/tests/ln/hard-to-sym.sh b/tests/ln/hard-to-sym.sh
new file mode 100755
index 0000000..e458553
--- /dev/null
+++ b/tests/ln/hard-to-sym.sh
@@ -0,0 +1,83 @@
+#!/bin/sh
+# Tests for ln -L/-P.
+
+# Copyright (C) 2009-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ ln
+
+
+# ===================================================
+# ensure -s silently overrides -L, -P
+touch a || framework_failure_
+ln -L -s a symlink1 || fail=1
+ln -P -s symlink1 symlink2 || fail=1
+ln -s -L -P symlink2 symlink3 || fail=1
+
+# ===================================================
+# ensure that -L follows symlinks, and overrides -P
+if ln -P -L symlink3 hard-to-a; then
+ ls=$(ls -lG hard-to-a)x
+ case "$ls" in
+ *'hard-to-ax') ;;
+ *'hard-to-a -> '*x) fail=1 ;;
+ *) framework_failure_ ;;
+ esac
+else
+ fail=1
+fi
+
+# ===================================================
+# ensure that -P links (or at least duplicates) symlinks, and overrides -L
+if ln -L -P symlink3 hard-to-3; then
+ ls=$(ls -lG hard-to-3)x
+ case "$ls" in
+ *'hard-to-3 -> symlink2x') ;;
+ *'hard-to-3x') fail=1 ;;
+ *'hard-to-3 -> '*x) fail=1 ;;
+ *) framework_failure_ ;;
+ esac
+else
+ fail=1
+fi
+
+# ===================================================
+# Create a hard link to a dangling symlink.
+ln -s /no-such-dir || framework_failure_
+ln -L no-such-dir hard-to-dangle 2>err && fail=1
+case $(cat err) in
+ *" failed to access 'no-such-dir'":*) ;;
+ *) fail=1 ;;
+esac
+ln -P no-such-dir hard-to-dangle || fail=1
+
+# ===================================================
+# Create a hard link to a symlink to a directory.
+mkdir d || framework_failure_
+ln -s d link-to-dir || framework_failure_
+ln -L link-to-dir hard-to-dir-link 2>err && fail=1
+case $(cat err) in
+ *": link-to-dir: hard link not allowed for directory"*) ;;
+ *) fail=1 ;;
+esac
+ln -P link-to-dir/ hard-to-dir-link 2>err && fail=1
+case $(cat err) in
+ *": link-to-dir/: hard link not allowed for directory"*) ;;
+ *) fail=1 ;;
+esac
+ln -P link-to-dir hard-to-dir-link || fail=1
+
+Exit $fail
diff --git a/tests/ln/misc.sh b/tests/ln/misc.sh
new file mode 100755
index 0000000..e509c1c
--- /dev/null
+++ b/tests/ln/misc.sh
@@ -0,0 +1,124 @@
+#!/bin/sh
+# Miscellaneous tests for "ln".
+
+# Copyright (C) 1998-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ ln
+
+t=tln-symlink
+d=tln-subdir
+ld=tln-symlink-to-subdir
+f=tln-file
+
+# Create a simple symlink with both source and destination files
+# in current directory.
+touch $f || framework_failure_
+rm -f $t || framework_failure_
+ln -s $f $t || fail=1
+test -f $t || fail=1
+rm $t $f
+
+# Create a symlink with source file and explicit destination directory/file.
+touch $f || framework_failure_
+rm -rf $d || framework_failure_
+mkdir $d || framework_failure_
+ln -s ../$f $d/$t || fail=1
+test -f $d/$t || fail=1
+rm -rf $d $f
+
+# Create a symlink with source file and destination directory.
+touch $f || framework_failure_
+rm -rf $d || framework_failure_
+mkdir $d || framework_failure_
+ln -s ../$f $d || fail=1
+test -f $d/$f || fail=1
+rm -rf $d $f
+
+# See whether a trailing slash is followed too far.
+touch $f || framework_failure_
+rm -rf $d || framework_failure_
+mkdir $d $d/$f || framework_failure_
+returns_ 1 ln $f $d/ 2> /dev/null || fail=1
+returns_ 1 ln -s $f $d/ 2> /dev/null || fail=1
+rm -rf $d $f
+
+# Make sure we get a failure with existing dest without -f option
+touch $t || framework_failure_
+# FIXME: don't ignore the error message but rather test
+# it to make sure it's the right one.
+returns_ 1 ln -s $t $t 2> /dev/null || fail=1
+rm $t
+
+# Make sure -sf fails when src and dest are the same
+touch $t || framework_failure_
+returns_ 1 ln -sf $t $t 2> /dev/null || fail=1
+rm $t
+
+# Create a symlink with source file and no explicit directory
+rm -rf $d || framework_failure_
+mkdir $d || framework_failure_
+touch $d/$f || framework_failure_
+ln -s $d/$f || fail=1
+test -f $f || fail=1
+rm -rf $d $f
+
+# Create a symlink with source file and destination symlink-to-directory.
+rm -rf $d $f $ld || framework_failure_
+touch $f || framework_failure_
+mkdir $d || framework_failure_
+ln -s $d $ld
+ln -s ../$f $ld || fail=1
+test -f $d/$f || fail=1
+rm -rf $d $f $ld
+
+# Create a symlink with source file and destination symlink-to-directory.
+# BUT use the new --no-dereference option.
+rm -rf $d $f $ld || framework_failure_
+touch $f || framework_failure_
+mkdir $d || framework_failure_
+ln -s $d $ld
+af=$(pwd)/$f
+ln --no-dereference -fs "$af" $ld || fail=1
+test -f $ld || fail=1
+rm -rf $d $f $ld
+
+# Try to create a symlink with backup where the destination file exists
+# and the backup file name is a hard link to the destination file.
+touch a b || framework_failure_
+ln b b~ || framework_failure_
+ln -f --b=simple a b || fail=1
+
+# ===================================================
+
+# Make sure ln can make simple backups.
+# This was fixed in 4.0.34. Broken in 4.0r.
+for cmd in ln cp mv ginstall; do
+ rm -rf a x a.orig
+ touch a x || framework_failure_
+ $cmd --backup=simple --suffix=.orig x a || fail=1
+ test -f a.orig || fail=1
+done
+
+# ===================================================
+# With coreutils-5.2.1, this would mistakenly access argv[1][-1].
+# I'm including it here, in case some day programs like valgrind detect that.
+# Purify probably would have done so.
+ln foo '' 2> /dev/null
+
+# ===================================================
+
+Exit $fail
diff --git a/tests/ln/relative.sh b/tests/ln/relative.sh
new file mode 100755
index 0000000..73bfd9e
--- /dev/null
+++ b/tests/ln/relative.sh
@@ -0,0 +1,53 @@
+#!/bin/sh
+# Test "ln --relative".
+
+# Copyright (C) 2012-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ ln
+
+mkdir -p usr/bin || framework_failure_
+mkdir -p usr/lib/foo || framework_failure_
+touch usr/lib/foo/foo || framework_failure_
+
+ln -sr usr/lib/foo/foo usr/bin/foo
+test $(readlink usr/bin/foo) = '../lib/foo/foo' || fail=1
+
+ln -sr usr/bin/foo usr/lib/foo/link-to-foo
+test $(readlink usr/lib/foo/link-to-foo) = 'foo' || fail=1
+
+# Correctly update an existing link, which was broken in <= 8.21
+ln -s dir1/dir2/f existing_link
+ln -srf here existing_link
+test $(readlink existing_link) = 'here' || fail=1
+
+# Demonstrate resolved symlinks used to generate relative links
+# so here, 'web/latest' will not be linked to the intermediate 'latest' link.
+# You'd probably want to use realpath(1) in conjunction
+# with ln(1) without --relative to give greater control.
+ln -s release1 alpha
+ln -s release2 beta
+ln -s beta latest
+mkdir web
+ln -sr latest web/latest
+test $(readlink web/latest) = '../release2' || fail=1
+
+# Expect this to fail with exit status 1, or to succeed quietly (freebsd).
+# Prior to coreutils-8.23, it would segfault.
+ln -sr '' F
+case $? in [01]) ;; *) fail=1;; esac
+
+Exit $fail
diff --git a/tests/ln/sf-1.sh b/tests/ln/sf-1.sh
new file mode 100755
index 0000000..e7781eb
--- /dev/null
+++ b/tests/ln/sf-1.sh
@@ -0,0 +1,49 @@
+#!/bin/sh
+# Test "ln -sf".
+
+# Copyright (C) 1997-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ ln
+
+echo foo > a || framework_failure_
+
+# Check that a target directory of '.' is supported
+# and that indirectly specifying the same target and link name
+# through that is detected.
+ln -s . b || framework_failure_
+ln -sf a b > err 2>&1 && fail=1
+case $(cat err) in
+ *'are the same file') ;;
+ *) fail=1 ;;
+esac
+
+# Ensure we replace symlinks that don't or can't link to an existing target.
+# coreutils-8.22 would fail to replace {ENOTDIR,ELOOP,ENAMETOOLONG}_link below.
+# We apply a limit since AIX returns 2^32-1 which would trigger resource issues.
+name_max=$(stat -f -c %l .) && test "$name_max" -lt $((1024*1024)) ||
+ name_max=1 # skip this portion of the test
+name_max_plus1=$(expr $name_max + 1)
+long_name=$(printf '%*s' $name_max_plus1 | tr ' ' '0')
+
+for f in '' f; do
+ ln -s$f missing ENOENT_link || fail=1
+ ln -s$f a/b ENOTDIR_link || fail=1
+ ln -s$f ELOOP_link ELOOP_link || fail=1
+ ln -s$f "$long_name" ENAMETOOLONG_link || fail=1
+done
+
+Exit $fail
diff --git a/tests/ln/slash-decorated-nonexistent-dest.sh b/tests/ln/slash-decorated-nonexistent-dest.sh
new file mode 100755
index 0000000..8e872d4
--- /dev/null
+++ b/tests/ln/slash-decorated-nonexistent-dest.sh
@@ -0,0 +1,29 @@
+#!/bin/sh
+# ensure that touch f; ln -T f no-such-file/ does not mistakenly succeed
+
+# Copyright (C) 2009-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ ln
+
+touch f || framework_failure_
+
+
+# Before coreutils-7.6, this would succeed on Solaris 10
+returns_ 1 ln -T f no-such-file/ || fail=1
+test -e no-such-file && fail=1
+
+Exit $fail
diff --git a/tests/ln/target-1.sh b/tests/ln/target-1.sh
new file mode 100755
index 0000000..59e3b46
--- /dev/null
+++ b/tests/ln/target-1.sh
@@ -0,0 +1,30 @@
+#!/bin/sh
+# Test "ln --target-dir" with one file.
+
+# Copyright (C) 2002-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+# Before coreutils-4.5.3, --target-dir didn't work with one file.
+# It would create the desired link, but would fail with a diagnosis like this:
+# ln: 'd/.': cannot overwrite directory
+# Based on a test case from Dmitry V. Levin.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ ln
+
+mkdir d || framework_failure_
+ln -s --target-dir=d ../f || fail=1
+
+Exit $fail
diff --git a/tests/local.mk b/tests/local.mk
new file mode 100644
index 0000000..b74a4a2
--- /dev/null
+++ b/tests/local.mk
@@ -0,0 +1,926 @@
+## Process this file with automake to produce Makefile.in -*-Makefile-*-.
+
+## Copyright (C) 2007-2023 Free Software Foundation, Inc.
+
+## This program is free software: you can redistribute it and/or modify
+## it under the terms of the GNU General Public License as published by
+## the Free Software Foundation, either version 3 of the License, or
+## (at your option) any later version.
+
+## This program is distributed in the hope that it will be useful,
+## but WITHOUT ANY WARRANTY; without even the implied warranty of
+## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+## GNU General Public License for more details.
+
+## You should have received a copy of the GNU General Public License
+## along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+# Indirection required so that we'll still be able to know the
+# complete list of our tests even if the user overrides TESTS
+# from the command line (as permitted by the test harness API).
+TESTS = $(all_tests) $(factor_tests)
+root_tests = $(all_root_tests)
+
+EXTRA_DIST += $(all_tests)
+
+TEST_EXTENSIONS = .sh .pl .xpl
+
+if HAVE_PERL
+TESTSUITE_PERL = $(PERL)
+else
+TESTSUITE_PERL = $(SHELL) $(srcdir)/tests/no-perl
+endif
+
+# Options passed to the perl invocations running the perl test scripts.
+TESTSUITE_PERL_OPTIONS = -w -I$(srcdir)/tests -MCuSkip -MCoreutils
+# '$f' is set by the Automake-generated test harness to the path of the
+# current test script stripped of VPATH components, and is used by the
+# CuTmpdir module to determine the name of the temporary files to be
+# used. Note that $f is a shell variable, not a make macro, so the use
+# of '$$f' below is correct, and not a typo.
+TESTSUITE_PERL_OPTIONS += -M"CuTmpdir qw($$f)"
+
+SH_LOG_COMPILER = $(SHELL)
+PL_LOG_COMPILER = $(TESTSUITE_PERL) $(TESTSUITE_PERL_OPTIONS)
+# Perl scripts that must be run in tainted mode.
+XPL_LOG_COMPILER = $(TESTSUITE_PERL) -T $(TESTSUITE_PERL_OPTIONS)
+
+# We don't want this to go in the top-level directory.
+TEST_SUITE_LOG = tests/test-suite.log
+
+# Note that the first lines are statements. They ensure that environment
+# variables that can perturb tests are unset or set to expected values.
+# The rest are envvar settings that propagate build-related Makefile
+# variables to test scripts.
+TESTS_ENVIRONMENT = \
+ . $(srcdir)/tests/lang-default; \
+ tmp__=$${TMPDIR-/tmp}; \
+ test -d "$$tmp__" && test -w "$$tmp__" || tmp__=.; \
+ . $(srcdir)/tests/envvar-check; \
+ TMPDIR=$$tmp__; export TMPDIR; \
+ export \
+ VERSION='$(VERSION)' \
+ LOCALE_FR='$(LOCALE_FR)' \
+ LOCALE_FR_UTF8='$(LOCALE_FR_UTF8)' \
+ abs_top_builddir='$(abs_top_builddir)' \
+ abs_top_srcdir='$(abs_top_srcdir)' \
+ abs_srcdir='$(abs_srcdir)' \
+ built_programs='$(built_programs) $(single_binary_progs)' \
+ fail=0 \
+ host_os=$(host_os) \
+ host_triplet='$(host_triplet)' \
+ srcdir='$(srcdir)' \
+ top_srcdir='$(top_srcdir)' \
+ CONFIG_HEADER='$(abs_top_builddir)/$(CONFIG_INCLUDE)' \
+ CU_TEST_NAME=`basename '$(abs_srcdir)'`,`echo $$tst|sed 's,^\./,,;s,/,-,g'` \
+ CC='$(CC)' \
+ AWK='$(AWK)' \
+ EGREP='$(EGREP)' \
+ EXEEXT='$(EXEEXT)' \
+ MAKE=$(MAKE) \
+ PACKAGE_VERSION=$(PACKAGE_VERSION) \
+ PERL='$(PERL)' \
+ SHELL='$(PREFERABLY_POSIX_SHELL)' \
+ ; test -d /usr/xpg4/bin && PATH='/usr/xpg4/bin$(PATH_SEPARATOR)'"$$PATH"; \
+ PATH='$(abs_top_builddir)/src$(PATH_SEPARATOR)'"$$PATH" \
+ ; 9>&2
+
+# On failure, display the global testsuite log on stdout.
+VERBOSE = yes
+
+EXTRA_DIST += \
+ init.cfg \
+ tests/Coreutils.pm \
+ tests/CuSkip.pm \
+ tests/CuTmpdir.pm \
+ tests/d_type-check \
+ tests/envvar-check \
+ tests/factor/run.sh \
+ tests/factor/create-test.sh \
+ tests/filefrag-extent-compare \
+ tests/seek-data-capable \
+ tests/init.sh \
+ tests/lang-default \
+ tests/no-perl \
+ tests/other-fs-tmpdir \
+ tests/sample-test \
+ $(pr_data)
+
+all_root_tests = \
+ tests/chown/basic.sh \
+ tests/cp/cp-a-selinux.sh \
+ tests/cp/preserve-gid.sh \
+ tests/cp/special-bits.sh \
+ tests/cp/cp-mv-enotsup-xattr.sh \
+ tests/cp/capability.sh \
+ tests/cp/sparse-extents-2.sh \
+ tests/cp/cross-dev-symlink.sh \
+ tests/dd/skip-seek-past-dev.sh \
+ tests/df/problematic-chars.sh \
+ tests/df/over-mount-device.sh \
+ tests/du/bind-mount-dir-cycle.sh \
+ tests/du/bind-mount-dir-cycle-v2.sh \
+ tests/id/setgid.sh \
+ tests/install/install-C-root.sh \
+ tests/ls/capability.sh \
+ tests/ls/nameless-uid.sh \
+ tests/chcon/chcon.sh \
+ tests/chroot/chroot-credentials.sh \
+ tests/misc/selinux.sh \
+ tests/truncate/truncate-owned-by-other.sh \
+ tests/mkdir/writable-under-readonly.sh \
+ tests/mkdir/smack-root.sh \
+ tests/mv/hardlink-case.sh \
+ tests/mv/sticky-to-xpart.sh \
+ tests/rm/fail-2eperm.sh \
+ tests/rm/no-give-up.sh \
+ tests/rm/one-file-system.sh \
+ tests/rm/read-only.sh \
+ tests/rm/empty-immutable-skip.sh \
+ tests/split/l-chunk-root.sh \
+ tests/tail/append-only.sh \
+ tests/tail/end-of-device.sh \
+ tests/touch/now-owned-by-other.sh
+
+ALL_RECURSIVE_TARGETS += check-root
+.PHONY: check-root
+check-root:
+ $(MAKE) check TESTS='$(root_tests)' SUBDIRS=.
+
+# Do not choose a name that is a shell keyword like 'if', or a
+# commonly-used utility like 'cat' or 'test', as the name of a test.
+# Otherwise, VPATH builds will fail on hosts like Solaris, since they
+# will expand 'if test ...' to 'if .../test ...', and the '.../test'
+# will execute the test script rather than the standard utility.
+
+# Notes on the ordering of these tests:
+# Place early in the list tests of the tools that
+# are most commonly used in test scripts themselves.
+# E.g., nearly every test script uses rm and chmod.
+# help-version comes early because it's a basic sanity test.
+# Put seq early, since lots of other tests use it.
+# Put tests that sleep early, but not all together, so in parallel builds
+# they share time with tests that burn CPU, not with others that sleep.
+# Put head-elide-tail early, because it's long-running.
+
+all_tests = \
+ tests/help/help-version.sh \
+ tests/help/help-version-getopt.sh \
+ tests/tail/inotify-race.sh \
+ tests/tail/inotify-race2.sh \
+ tests/misc/invalid-opt.pl \
+ tests/rm/ext3-perf.sh \
+ tests/rm/cycle.sh \
+ tests/cp/link-heap.sh \
+ tests/cp/no-ctx.sh \
+ tests/tty/tty-eof.pl \
+ tests/misc/read-errors.sh \
+ tests/misc/write-errors.sh \
+ tests/tail/inotify-hash-abuse.sh \
+ tests/tail/inotify-hash-abuse2.sh \
+ tests/tail/F-vs-missing.sh \
+ tests/tail/F-vs-rename.sh \
+ tests/tail/F-headers.sh \
+ tests/tail/descriptor-vs-rename.sh \
+ tests/tail/inotify-rotate.sh \
+ tests/tail/inotify-rotate-resources.sh \
+ tests/tail/inotify-dir-recreate.sh \
+ tests/tail/inotify-only-regular.sh \
+ tests/chmod/no-x.sh \
+ tests/chgrp/basic.sh \
+ tests/rm/dangling-symlink.sh \
+ tests/ls/ls-time.sh \
+ tests/rm/d-1.sh \
+ tests/rm/d-2.sh \
+ tests/rm/d-3.sh \
+ tests/rm/deep-1.sh \
+ tests/rm/deep-2.sh \
+ tests/rm/dir-no-w.sh \
+ tests/rm/dir-nonrecur.sh \
+ tests/rm/dot-rel.sh \
+ tests/rm/isatty.sh \
+ tests/rm/empty-inacc.sh \
+ tests/rm/empty-name.pl \
+ tests/rm/f-1.sh \
+ tests/rm/fail-eacces.sh \
+ tests/rm/fail-eperm.xpl \
+ tests/tail/assert.sh \
+ tests/rm/hash.sh \
+ tests/rm/i-1.sh \
+ tests/rm/i-never.sh \
+ tests/rm/i-no-r.sh \
+ tests/rm/ignorable.sh \
+ tests/rm/inaccessible.sh \
+ tests/rm/interactive-always.sh \
+ tests/rm/interactive-once.sh \
+ tests/rm/ir-1.sh \
+ tests/rm/one-file-system2.sh \
+ tests/rm/r-1.sh \
+ tests/rm/r-2.sh \
+ tests/rm/r-3.sh \
+ tests/rm/r-4.sh \
+ tests/rm/r-root.sh \
+ tests/rm/readdir-bug.sh \
+ tests/rm/rm1.sh \
+ tests/touch/empty-file.sh \
+ tests/rm/rm2.sh \
+ tests/rm/rm3.sh \
+ tests/rm/rm4.sh \
+ tests/rm/rm5.sh \
+ tests/rm/sunos-1.sh \
+ tests/rm/unread2.sh \
+ tests/rm/unread3.sh \
+ tests/rm/unreadable.pl \
+ tests/rm/v-slash.sh \
+ tests/rm/many-dir-entries-vs-OOM.sh \
+ tests/rm/rm-readdir-fail.sh \
+ tests/chgrp/default-no-deref.sh \
+ tests/chgrp/deref.sh \
+ tests/chgrp/no-x.sh \
+ tests/chgrp/posix-H.sh \
+ tests/chgrp/recurse.sh \
+ tests/fmt/base.pl \
+ tests/fmt/goal-option.sh \
+ tests/fmt/long-line.sh \
+ tests/fmt/non-space.sh \
+ tests/misc/echo.sh \
+ tests/env/env.sh \
+ tests/env/env-signal-handler.sh \
+ tests/ptx/ptx.pl \
+ tests/test/test.pl \
+ tests/seq/seq.pl \
+ tests/seq/seq-epipe.sh \
+ tests/seq/seq-extra-number.sh \
+ tests/seq/seq-io-errors.sh \
+ tests/seq/seq-locale.sh \
+ tests/seq/seq-long-double.sh \
+ tests/seq/seq-precision.sh \
+ tests/head/head.pl \
+ tests/head/head-elide-tail.pl \
+ tests/tail/tail-n0f.sh \
+ tests/ls/ls-misc.pl \
+ tests/date/date.pl \
+ tests/date/date-next-dow.pl \
+ tests/ptx/ptx-overrun.sh \
+ tests/misc/xstrtol.pl \
+ tests/tail/overlay-headers.sh \
+ tests/tail/pid.sh \
+ tests/od/od.pl \
+ tests/od/od-endian.sh \
+ tests/od/od-float.sh \
+ tests/misc/mktemp.pl \
+ tests/misc/arch.sh \
+ tests/misc/join.pl \
+ tests/pr/pr-tests.pl \
+ tests/pwd/pwd-option.sh \
+ tests/chcon/chcon-fail.sh \
+ tests/misc/coreutils.sh \
+ tests/cut/cut.pl \
+ tests/cut/cut-huge-range.sh \
+ tests/wc/wc.pl \
+ tests/wc/wc-files0-from.pl \
+ tests/wc/wc-files0.sh \
+ tests/wc/wc-nbsp.sh \
+ tests/wc/wc-parallel.sh \
+ tests/wc/wc-proc.sh \
+ tests/wc/wc-total.sh \
+ tests/cat/cat-E.sh \
+ tests/cat/cat-proc.sh \
+ tests/cat/cat-buf.sh \
+ tests/cat/cat-self.sh \
+ tests/misc/base64.pl \
+ tests/misc/basename.pl \
+ tests/misc/basenc.pl \
+ tests/misc/close-stdout.sh \
+ tests/chroot/chroot-fail.sh \
+ tests/cksum/cksum.sh \
+ tests/cksum/cksum-a.sh \
+ tests/cksum/cksum-c.sh \
+ tests/cksum/cksum-base64.pl \
+ tests/cksum/cksum-raw.sh \
+ tests/misc/comm.pl \
+ tests/csplit/csplit.sh \
+ tests/csplit/csplit-1000.sh \
+ tests/csplit/csplit-heap.sh \
+ tests/csplit/csplit-io-err.sh \
+ tests/csplit/csplit-suppress-matched.pl \
+ tests/date/date-debug.sh \
+ tests/date/date-sec.sh \
+ tests/date/date-tz.sh \
+ tests/misc/dircolors.pl \
+ tests/misc/dirname.pl \
+ tests/env/env-null.sh \
+ tests/env/env-S.pl \
+ tests/env/env-S-script.sh \
+ tests/misc/expand.pl \
+ tests/expr/expr.pl \
+ tests/expr/expr-multibyte.pl \
+ tests/factor/factor.pl \
+ tests/factor/factor-parallel.sh \
+ tests/misc/false-status.sh \
+ tests/misc/fold.pl \
+ tests/groups/groups-dash.sh \
+ tests/groups/groups-process-all.sh \
+ tests/groups/groups-version.sh \
+ tests/head/head-c.sh \
+ tests/head/head-pos.sh \
+ tests/head/head-write-error.sh \
+ tests/misc/kill.sh \
+ tests/cksum/b2sum.sh \
+ tests/cksum/md5sum.pl \
+ tests/cksum/md5sum-bsd.sh \
+ tests/cksum/md5sum-newline.pl \
+ tests/cksum/md5sum-parallel.sh \
+ tests/misc/mknod.sh \
+ tests/nice/nice.sh \
+ tests/nice/nice-fail.sh \
+ tests/misc/nl.sh \
+ tests/misc/nohup.sh \
+ tests/nproc/nproc-avail.sh \
+ tests/nproc/nproc-positive.sh \
+ tests/nproc/nproc-override.sh \
+ tests/misc/numfmt.pl \
+ tests/od/od-N.sh \
+ tests/od/od-j.sh \
+ tests/od/od-multiple-t.sh \
+ tests/od/od-x8.sh \
+ tests/misc/paste.pl \
+ tests/misc/pathchk.sh \
+ tests/misc/printenv.sh \
+ tests/printf/printf.sh \
+ tests/printf/printf-cov.pl \
+ tests/printf/printf-hex.sh \
+ tests/printf/printf-mb.sh \
+ tests/printf/printf-surprise.sh \
+ tests/printf/printf-quote.sh \
+ tests/pwd/pwd-long.sh \
+ tests/readlink/readlink-fp-loop.sh \
+ tests/readlink/readlink-root.sh \
+ tests/misc/realpath.sh \
+ tests/runcon/runcon-compute.sh \
+ tests/runcon/runcon-no-reorder.sh \
+ tests/cksum/sha1sum.pl \
+ tests/cksum/sha1sum-vec.pl \
+ tests/cksum/sha224sum.pl \
+ tests/cksum/sha256sum.pl \
+ tests/cksum/sha384sum.pl \
+ tests/cksum/sha512sum.pl \
+ tests/shred/shred-exact.sh \
+ tests/shred/shred-passes.sh \
+ tests/shred/shred-remove.sh \
+ tests/shred/shred-size.sh \
+ tests/shuf/shuf.sh \
+ tests/shuf/shuf-reservoir.sh \
+ tests/misc/sleep.sh \
+ tests/cksum/sm3sum.pl \
+ tests/sort/sort.pl \
+ tests/sort/sort-benchmark-random.sh \
+ tests/sort/sort-compress.sh \
+ tests/sort/sort-compress-hang.sh \
+ tests/sort/sort-compress-proc.sh \
+ tests/sort/sort-continue.sh \
+ tests/sort/sort-debug-keys.sh \
+ tests/sort/sort-debug-warn.sh \
+ tests/sort/sort-discrim.sh \
+ tests/sort/sort-files0-from.pl \
+ tests/sort/sort-float.sh \
+ tests/sort/sort-h-thousands-sep.sh \
+ tests/sort/sort-merge.pl \
+ tests/sort/sort-merge-fdlimit.sh \
+ tests/sort/sort-month.sh \
+ tests/sort/sort-exit-early.sh \
+ tests/sort/sort-rand.sh \
+ tests/sort/sort-spinlock-abuse.sh \
+ tests/sort/sort-stale-thread-mem.sh \
+ tests/sort/sort-unique.sh \
+ tests/sort/sort-unique-segv.sh \
+ tests/sort/sort-version.sh \
+ tests/sort/sort-NaN-infloop.sh \
+ tests/sort/sort-u-FMR.sh \
+ tests/split/filter.sh \
+ tests/split/suffix-auto-length.sh \
+ tests/split/suffix-length.sh \
+ tests/split/additional-suffix.sh \
+ tests/split/b-chunk.sh \
+ tests/split/fail.sh \
+ tests/split/lines.sh \
+ tests/split/line-bytes.sh \
+ tests/split/l-chunk.sh \
+ tests/split/r-chunk.sh \
+ tests/split/record-sep.sh \
+ tests/split/numeric.sh \
+ tests/split/guard-input.sh \
+ tests/stat/stat-birthtime.sh \
+ tests/stat/stat-fmt.sh \
+ tests/stat/stat-hyphen.sh \
+ tests/stat/stat-mount.sh \
+ tests/stat/stat-nanoseconds.sh \
+ tests/stat/stat-printf.pl \
+ tests/stat/stat-slash.sh \
+ tests/misc/stdbuf.sh \
+ tests/stty/stty.sh \
+ tests/stty/stty-invalid.sh \
+ tests/stty/stty-pairs.sh \
+ tests/stty/stty-row-col.sh \
+ tests/cksum/sum.pl \
+ tests/cksum/sum-sysv.sh \
+ tests/misc/sync.sh \
+ tests/tac/tac.pl \
+ tests/tac/tac-continue.sh \
+ tests/tac/tac-2-nonseekable.sh \
+ tests/tail/tail.pl \
+ tests/misc/tee.sh \
+ tests/test/test-N.sh \
+ tests/test/test-diag.pl \
+ tests/misc/time-style.sh \
+ tests/timeout/timeout.sh \
+ tests/timeout/timeout-blocked.pl \
+ tests/timeout/timeout-group.sh \
+ tests/timeout/timeout-large-parameters.sh \
+ tests/timeout/timeout-parameters.sh \
+ tests/tr/tr.pl \
+ tests/tr/tr-case-class.sh \
+ tests/truncate/truncate-dangling-symlink.sh \
+ tests/truncate/truncate-dir-fail.sh \
+ tests/truncate/truncate-fail-diag.sh \
+ tests/truncate/truncate-fifo.sh \
+ tests/truncate/truncate-no-create-missing.sh \
+ tests/truncate/truncate-overflow.sh \
+ tests/truncate/truncate-parameters.sh \
+ tests/truncate/truncate-relative.sh \
+ tests/misc/tsort.pl \
+ tests/tty/tty.sh \
+ tests/misc/usage_vs_getopt.sh \
+ tests/misc/unexpand.pl \
+ tests/uniq/uniq.pl \
+ tests/uniq/uniq-perf.sh \
+ tests/uniq/uniq-collate.sh \
+ tests/misc/xattr.sh \
+ tests/misc/yes.sh \
+ tests/tail/wait.sh \
+ tests/tail/retry.sh \
+ tests/tail/symlink.sh \
+ tests/tail/tail-c.sh \
+ tests/tail/truncate.sh \
+ tests/chmod/c-option.sh \
+ tests/chmod/equal-x.sh \
+ tests/chmod/equals.sh \
+ tests/chmod/ignore-symlink.sh \
+ tests/chmod/inaccessible.sh \
+ tests/chmod/octal.sh \
+ tests/chmod/setgid.sh \
+ tests/chmod/silent.sh \
+ tests/chmod/thru-dangling.sh \
+ tests/chmod/umask-x.sh \
+ tests/chmod/usage.sh \
+ tests/chown/deref.sh \
+ tests/chown/preserve-root.sh \
+ tests/chown/separator.sh \
+ tests/cp/abuse.sh \
+ tests/cp/acl.sh \
+ tests/cp/attr-existing.sh \
+ tests/cp/backup-1.sh \
+ tests/cp/backup-dir.sh \
+ tests/cp/backup-is-src.sh \
+ tests/cp/cp-HL.sh \
+ tests/cp/cp-deref.sh \
+ tests/cp/cp-i.sh \
+ tests/cp/cp-mv-backup.sh \
+ tests/cp/cp-parents.sh \
+ tests/cp/debug.sh \
+ tests/cp/deref-slink.sh \
+ tests/cp/dir-rm-dest.sh \
+ tests/cp/dir-slash.sh \
+ tests/cp/dir-vs-file.sh \
+ tests/cp/existing-perm-dir.sh \
+ tests/cp/existing-perm-race.sh \
+ tests/cp/fail-perm.sh \
+ tests/cp/sparse-extents.sh \
+ tests/cp/copy-FMR.sh \
+ tests/cp/sparse-perf.sh \
+ tests/cp/sparse-2.sh \
+ tests/cp/file-perm-race.sh \
+ tests/cp/into-self.sh \
+ tests/cp/link.sh \
+ tests/cp/link-deref.sh \
+ tests/cp/link-no-deref.sh \
+ tests/cp/link-preserve.sh \
+ tests/cp/link-symlink.sh \
+ tests/cp/nfs-removal-race.sh \
+ tests/cp/no-deref-link1.sh \
+ tests/cp/no-deref-link2.sh \
+ tests/cp/no-deref-link3.sh \
+ tests/cp/parent-perm.sh \
+ tests/cp/parent-perm-race.sh \
+ tests/cp/perm.sh \
+ tests/cp/preserve-2.sh \
+ tests/cp/preserve-link.sh \
+ tests/cp/preserve-mode.sh \
+ tests/cp/preserve-slink-time.sh \
+ tests/cp/proc-short-read.sh \
+ tests/cp/proc-zero-len.sh \
+ tests/cp/r-vs-symlink.sh \
+ tests/cp/reflink-auto.sh \
+ tests/cp/reflink-perm.sh \
+ tests/cp/same-file.sh \
+ tests/cp/slink-2-slink.sh \
+ tests/cp/sparse.sh \
+ tests/cp/sparse-to-pipe.sh \
+ tests/cp/special-f.sh \
+ tests/cp/src-base-dot.sh \
+ tests/cp/symlink-slash.sh \
+ tests/cp/thru-dangling.sh \
+ tests/df/header.sh \
+ tests/df/df-P.sh \
+ tests/df/df-output.sh \
+ tests/df/df-symlink.sh \
+ tests/df/unreadable.sh \
+ tests/df/total-unprocessed.sh \
+ tests/df/no-mtab-status.sh \
+ tests/df/skip-duplicates.sh \
+ tests/df/skip-rootfs.sh \
+ tests/dd/ascii.sh \
+ tests/dd/direct.sh \
+ tests/dd/misc.sh \
+ tests/dd/no-allocate.sh \
+ tests/dd/nocache.sh \
+ tests/dd/nocache_eof.sh \
+ tests/dd/not-rewound.sh \
+ tests/dd/reblock.sh \
+ tests/dd/skip-seek.pl \
+ tests/dd/skip-seek2.sh \
+ tests/dd/bytes.sh \
+ tests/dd/skip-seek-past-file.sh \
+ tests/dd/sparse.sh \
+ tests/dd/stderr.sh \
+ tests/dd/unblock.pl \
+ tests/dd/unblock-sync.sh \
+ tests/dd/stats.sh \
+ tests/df/total-verify.sh \
+ tests/du/2g.sh \
+ tests/du/8gb.sh \
+ tests/du/apparent.sh \
+ tests/du/basic.sh \
+ tests/du/bigtime.sh \
+ tests/du/deref.sh \
+ tests/du/deref-args.sh \
+ tests/du/exclude.sh \
+ tests/du/fd-leak.sh \
+ tests/du/files0-from.pl \
+ tests/du/files0-from-dir.sh \
+ tests/du/hard-link.sh \
+ tests/du/inacc-dest.sh \
+ tests/du/inacc-dir.sh \
+ tests/du/inaccessible-cwd.sh \
+ tests/du/inodes.sh \
+ tests/du/long-from-unreadable.sh \
+ tests/du/long-sloop.sh \
+ tests/du/max-depth.sh \
+ tests/du/move-dir-while-traversing.sh \
+ tests/du/no-deref.sh \
+ tests/du/no-x.sh \
+ tests/du/one-file-system.sh \
+ tests/du/restore-wd.sh \
+ tests/du/slash.sh \
+ tests/du/threshold.sh \
+ tests/du/trailing-slash.sh \
+ tests/du/two-args.sh \
+ tests/id/gnu-zero-uids.sh \
+ tests/id/no-context.sh \
+ tests/id/context.sh \
+ tests/id/uid.sh \
+ tests/id/zero.sh \
+ tests/id/smack.sh \
+ tests/install/basic-1.sh \
+ tests/install/create-leading.sh \
+ tests/install/d-slashdot.sh \
+ tests/install/install-C.sh \
+ tests/install/install-C-selinux.sh \
+ tests/install/install-Z-selinux.sh \
+ tests/install/strip-program.sh \
+ tests/install/trap.sh \
+ tests/ln/backup-1.sh \
+ tests/ln/hard-backup.sh \
+ tests/ln/hard-to-sym.sh \
+ tests/ln/misc.sh \
+ tests/ln/relative.sh \
+ tests/ln/sf-1.sh \
+ tests/ln/slash-decorated-nonexistent-dest.sh \
+ tests/ln/target-1.sh \
+ tests/ls/a-option.sh \
+ tests/ls/abmon-align.sh \
+ tests/ls/birthtime.sh \
+ tests/ls/block-size.sh \
+ tests/ls/classify.sh \
+ tests/ls/color-clear-to-eol.sh \
+ tests/ls/color-dtype-dir.sh \
+ tests/ls/color-norm.sh \
+ tests/ls/color-term.sh \
+ tests/ls/color-ext.sh \
+ tests/ls/dangle.sh \
+ tests/ls/dired.sh \
+ tests/ls/file-type.sh \
+ tests/ls/follow-slink.sh \
+ tests/ls/getxattr-speedup.sh \
+ tests/ls/group-dirs.sh \
+ tests/ls/hex-option.sh \
+ tests/ls/hyperlink.sh \
+ tests/ls/infloop.sh \
+ tests/ls/inode.sh \
+ tests/ls/m-option.sh \
+ tests/ls/w-option.sh \
+ tests/ls/multihardlink.sh \
+ tests/ls/no-arg.sh \
+ tests/ls/no-cap.sh \
+ tests/ls/selinux-segfault.sh \
+ tests/ls/quote-align.sh \
+ tests/ls/readdir-mountpoint-inode.sh \
+ tests/ls/recursive.sh \
+ tests/ls/removed-directory.sh \
+ tests/ls/root-rel-symlink-color.sh \
+ tests/ls/rt-1.sh \
+ tests/ls/slink-acl.sh \
+ tests/ls/stat-dtype.sh \
+ tests/ls/stat-failed.sh \
+ tests/ls/stat-free-color.sh \
+ tests/ls/stat-free-symlinks.sh \
+ tests/ls/stat-vs-dirent.sh \
+ tests/ls/symlink-loop.sh \
+ tests/ls/symlink-quote.sh \
+ tests/ls/symlink-slash.sh \
+ tests/ls/time-style-diag.sh \
+ tests/ls/sort-width-option.sh \
+ tests/ls/x-option.sh \
+ tests/ls/zero-option.sh \
+ tests/mkdir/p-1.sh \
+ tests/mkdir/p-2.sh \
+ tests/mkdir/p-3.sh \
+ tests/mkdir/p-acl.sh \
+ tests/mkdir/p-slashdot.sh \
+ tests/mkdir/p-thru-slink.sh \
+ tests/mkdir/p-v.sh \
+ tests/mkdir/parents.sh \
+ tests/mkdir/perm.sh \
+ tests/mkdir/selinux.sh \
+ tests/mkdir/restorecon.sh \
+ tests/mkdir/special-1.sh \
+ tests/mkdir/t-slash.sh \
+ tests/mkdir/smack-no-root.sh \
+ tests/mv/acl.sh \
+ tests/mv/atomic.sh \
+ tests/mv/atomic2.sh \
+ tests/mv/backup-dir.sh \
+ tests/mv/backup-is-src.sh \
+ tests/mv/childproof.sh \
+ tests/mv/diag.sh \
+ tests/mv/dir-file.sh \
+ tests/mv/dir2dir.sh \
+ tests/mv/dup-source.sh \
+ tests/mv/force.sh \
+ tests/mv/hard-2.sh \
+ tests/mv/hard-3.sh \
+ tests/mv/hard-4.sh \
+ tests/mv/hard-link-1.sh \
+ tests/mv/i-1.pl \
+ tests/mv/i-2.sh \
+ tests/mv/i-3.sh \
+ tests/mv/i-4.sh \
+ tests/mv/i-5.sh \
+ tests/mv/i-link-no.sh \
+ tests/mv/into-self.sh \
+ tests/mv/into-self-2.sh \
+ tests/mv/into-self-3.sh \
+ tests/mv/into-self-4.sh \
+ tests/mv/leak-fd.sh \
+ tests/mv/mv-n.sh \
+ tests/mv/mv-special-1.sh \
+ tests/mv/no-copy.sh \
+ tests/mv/no-target-dir.sh \
+ tests/mv/part-fail.sh \
+ tests/mv/part-hardlink.sh \
+ tests/mv/part-rename.sh \
+ tests/mv/part-symlink.sh \
+ tests/mv/partition-perm.sh \
+ tests/mv/perm-1.sh \
+ tests/mv/symlink-onto-hardlink.sh \
+ tests/mv/symlink-onto-hardlink-to-self.sh \
+ tests/mv/to-symlink.sh \
+ tests/mv/trailing-slash.sh \
+ tests/mv/update.sh \
+ tests/readlink/can-e.sh \
+ tests/readlink/can-f.sh \
+ tests/readlink/can-m.sh \
+ tests/readlink/multi.sh \
+ tests/readlink/rl-1.sh \
+ tests/rmdir/fail-perm.sh \
+ tests/rmdir/ignore.sh \
+ tests/rmdir/symlink-errors.sh \
+ tests/rmdir/t-slash.sh \
+ tests/tail/assert-2.sh \
+ tests/tail/big-4gb.sh \
+ tests/tail/flush-initial.sh \
+ tests/tail/follow-name.sh \
+ tests/tail/follow-stdin.sh \
+ tests/tail/pipe-f.sh \
+ tests/tail/pipe-f2.sh \
+ tests/tail/proc-ksyms.sh \
+ tests/tail/start-middle.sh \
+ tests/touch/60-seconds.sh \
+ tests/touch/dangling-symlink.sh \
+ tests/touch/dir-1.sh \
+ tests/touch/fail-diag.sh \
+ tests/touch/fifo.sh \
+ tests/touch/no-create-missing.sh \
+ tests/touch/no-dereference.sh \
+ tests/touch/no-rights.sh \
+ tests/touch/not-owner.sh \
+ tests/touch/obsolescent.sh \
+ tests/touch/read-only.sh \
+ tests/touch/relative.sh \
+ tests/touch/trailing-slash.sh \
+ $(all_root_tests)
+
+# See tests/factor/create-test.sh.
+tf = tests/factor
+factor_tests = \
+ $(tf)/t00.sh $(tf)/t01.sh $(tf)/t02.sh $(tf)/t03.sh $(tf)/t04.sh \
+ $(tf)/t05.sh $(tf)/t06.sh $(tf)/t07.sh $(tf)/t08.sh $(tf)/t09.sh \
+ $(tf)/t10.sh $(tf)/t11.sh $(tf)/t12.sh $(tf)/t13.sh $(tf)/t14.sh \
+ $(tf)/t15.sh $(tf)/t16.sh $(tf)/t17.sh $(tf)/t18.sh $(tf)/t19.sh \
+ $(tf)/t20.sh $(tf)/t21.sh $(tf)/t22.sh $(tf)/t23.sh $(tf)/t24.sh \
+ $(tf)/t25.sh $(tf)/t26.sh $(tf)/t27.sh $(tf)/t28.sh $(tf)/t29.sh \
+ $(tf)/t30.sh $(tf)/t31.sh $(tf)/t32.sh $(tf)/t33.sh $(tf)/t34.sh \
+ $(tf)/t35.sh $(tf)/t36.sh
+
+$(factor_tests): $(tf)/run.sh $(tf)/create-test.sh
+ $(AM_V_GEN)$(MKDIR_P) $(tf)
+ $(AM_V_at)$(SHELL) $(srcdir)/$(tf)/create-test.sh $@ \
+ $(srcdir)/$(tf)/run.sh > $@-t
+ $(AM_V_at)chmod a+x $@-t
+ $(AM_V_at)mv -f $@-t $@
+
+CLEANFILES += $(factor_tests)
+
+pr_data = \
+ tests/pr/0F \
+ tests/pr/0FF \
+ tests/pr/0FFnt \
+ tests/pr/0FFt \
+ tests/pr/0FnFnt \
+ tests/pr/0FnFt \
+ tests/pr/0Fnt \
+ tests/pr/0Ft \
+ tests/pr/2-S_f-t_notab \
+ tests/pr/2-Sf-t_notab \
+ tests/pr/2f-t_notab \
+ tests/pr/2s_f-t_notab \
+ tests/pr/2s_w60f-t_nota \
+ tests/pr/2sf-t_notab \
+ tests/pr/2sw60f-t_notab \
+ tests/pr/2w60f-t_notab \
+ tests/pr/3-0F \
+ tests/pr/3-5l24f-t \
+ tests/pr/3-FF \
+ tests/pr/3a2l17-FF \
+ tests/pr/3a3f-0F \
+ tests/pr/3a3l15-t \
+ tests/pr/3a3l15f-t \
+ tests/pr/3b2l17-FF \
+ tests/pr/3b3f-0F \
+ tests/pr/3b3f-0FF \
+ tests/pr/3b3f-FF \
+ tests/pr/3b3l15-t \
+ tests/pr/3b3l15f-t \
+ tests/pr/3f-0F \
+ tests/pr/3f-FF \
+ tests/pr/3l24-t \
+ tests/pr/3l24f-t \
+ tests/pr/3ml24-FF \
+ tests/pr/3ml24-t \
+ tests/pr/3ml24-t-FF \
+ tests/pr/3ml24f-t \
+ tests/pr/4-7l24-FF \
+ tests/pr/4l24-FF \
+ tests/pr/FF \
+ tests/pr/FFn \
+ tests/pr/FFtn \
+ tests/pr/FnFn \
+ tests/pr/Ja3l24f-lm \
+ tests/pr/Jb3l24f-lm \
+ tests/pr/Jml24f-lm-lo \
+ tests/pr/W-72l24f-ll \
+ tests/pr/W20l24f-ll \
+ tests/pr/W26l24f-ll \
+ tests/pr/W27l24f-ll \
+ tests/pr/W28l24f-ll \
+ tests/pr/W35Ja3l24f-lm \
+ tests/pr/W35Jb3l24f-lm \
+ tests/pr/W35Jml24f-lmlo \
+ tests/pr/W35a3l24f-lm \
+ tests/pr/W35b3l24f-lm \
+ tests/pr/W35ml24f-lm-lo \
+ tests/pr/W72Jl24f-ll \
+ tests/pr/a2l15-FF \
+ tests/pr/a2l17-FF \
+ tests/pr/a3-0F \
+ tests/pr/a3f-0F \
+ tests/pr/a3f-0FF \
+ tests/pr/a3f-FF \
+ tests/pr/a3l15-t \
+ tests/pr/a3l15f-t \
+ tests/pr/a3l24f-lm \
+ tests/pr/b2l15-FF \
+ tests/pr/b2l17-FF \
+ tests/pr/b3-0F \
+ tests/pr/b3f-0F \
+ tests/pr/b3f-0FF \
+ tests/pr/b3f-FF \
+ tests/pr/b3l15-t \
+ tests/pr/b3l15f-t \
+ tests/pr/b3l24f-lm \
+ tests/pr/l24-FF \
+ tests/pr/l24-t \
+ tests/pr/l24f-t \
+ tests/pr/loli \
+ tests/pr/ml20-FF-t \
+ tests/pr/ml24-FF \
+ tests/pr/ml24-t \
+ tests/pr/ml24-t-FF \
+ tests/pr/ml24f-0F \
+ tests/pr/ml24f-lm-lo \
+ tests/pr/ml24f-t \
+ tests/pr/ml24f-t-0F \
+ tests/pr/n+2-5l24f-0FF \
+ tests/pr/n+2l24f-0FF \
+ tests/pr/n+2l24f-bl \
+ tests/pr/n+3-7l24-FF \
+ tests/pr/n+3l24f-0FF \
+ tests/pr/n+3l24f-bl \
+ tests/pr/n+3ml20f-bl-FF \
+ tests/pr/n+3ml24f-bl-tn \
+ tests/pr/n+3ml24f-tn-bl \
+ tests/pr/n+4-8a2l17-FF \
+ tests/pr/n+4b2l17f-0FF \
+ tests/pr/n+5-8b3l17f-FF \
+ tests/pr/n+5a3l13f-0FF \
+ tests/pr/n+6a2l17-FF \
+ tests/pr/n+6b3l13f-FF \
+ tests/pr/n+7l24-FF \
+ tests/pr/n+8l20-FF \
+ tests/pr/nJml24f-lmlmlo \
+ tests/pr/nJml24f-lmlolm \
+ tests/pr/nN1+3l24f-bl \
+ tests/pr/nN15l24f-bl \
+ tests/pr/nSml20-bl-FF \
+ tests/pr/nSml20-t-t-FF \
+ tests/pr/nSml20-t-tFFFF \
+ tests/pr/nSml24-bl-FF \
+ tests/pr/nSml24-t-t-FF \
+ tests/pr/nSml24-t-tFFFF \
+ tests/pr/nl24f-bl \
+ tests/pr/o3Jml24f-lm-lo \
+ tests/pr/o3a3Sl24f-tn \
+ tests/pr/o3a3Snl24f-tn \
+ tests/pr/o3a3l24f-tn \
+ tests/pr/o3b3Sl24f-tn \
+ tests/pr/o3b3Snl24f-tn \
+ tests/pr/o3b3l24f-tn \
+ tests/pr/o3mSl24f-bl-tn \
+ tests/pr/o3mSnl24fbltn \
+ tests/pr/o3ml24f-bl-tn \
+ tests/pr/t-0FF \
+ tests/pr/t-FF \
+ tests/pr/t-bl \
+ tests/pr/t-t \
+ tests/pr/tFFn \
+ tests/pr/tFFt \
+ tests/pr/tFFt-bl \
+ tests/pr/tFFt-ll \
+ tests/pr/tFFt-lm \
+ tests/pr/tFnFt \
+ tests/pr/t_notab \
+ tests/pr/t_tab \
+ tests/pr/t_tab_ \
+ tests/pr/ta3-0FF \
+ tests/pr/ta3-FF \
+ tests/pr/tb3-0FF \
+ tests/pr/tb3-FF \
+ tests/pr/tn \
+ tests/pr/tn2e5o3-t_tab \
+ tests/pr/tn2e8-t_tab \
+ tests/pr/tn2e8o3-t_tab \
+ tests/pr/tn_2e8-t_tab \
+ tests/pr/tn_2e8S-t_tab \
+ tests/pr/tne8-t_tab \
+ tests/pr/tne8o3-t_tab \
+ tests/pr/tt-0FF \
+ tests/pr/tt-FF \
+ tests/pr/tt-bl \
+ tests/pr/tt-t \
+ tests/pr/tta3-0FF \
+ tests/pr/tta3-FF \
+ tests/pr/ttb3-0FF \
+ tests/pr/ttb3-FF \
+ tests/pr/w72l24f-ll
+
+$(TEST_LOGS): $(PROGRAMS)
diff --git a/tests/ls/a-option.sh b/tests/ls/a-option.sh
new file mode 100755
index 0000000..c154666
--- /dev/null
+++ b/tests/ls/a-option.sh
@@ -0,0 +1,27 @@
+#!/bin/sh
+# exercise the -a option
+
+# Copyright 2018-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ ls
+
+mkdir d || framework_failure_
+
+ls -aA d >out || framework_failure_
+compare /dev/null out || fail=1
+
+Exit $fail
diff --git a/tests/ls/abmon-align.sh b/tests/ls/abmon-align.sh
new file mode 100755
index 0000000..73308dc
--- /dev/null
+++ b/tests/ls/abmon-align.sh
@@ -0,0 +1,53 @@
+#!/bin/sh
+# Ensure ls output is aligned when using abbreviated months from the locale
+
+# Copyright (C) 2009-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ ls
+
+mid_month="$(date +%Y-%m-15)" || framework_failure_
+for mon in $(seq -w 12); do
+ touch -d"$mid_month +$mon month" $mon.ts || framework_failure_
+done
+
+
+# Note some of the following locales may be missing but if so
+# we should fail back to the C locale which should be aligned
+
+for format in "%b" "[%b" "%b]" "[%b]"; do
+ for LOC in C gv_GB ga_IE fi_FI.utf8 zh_CN ar_SY $LOCALE_FR_UTF8; do
+ # The sed usage here is slightly different from the original,
+ # removing the \(.*\), to avoid triggering misbehavior in at least
+ # GNU sed 4.2 (possibly miscompiled) on Mac OS X (Darwin 9.8.0).
+ months="$(
+ LC_ALL=$LOC TIME_STYLE=+"$format" ls -lgG *.ts |
+ LC_ALL=C sed 's/.\{15\}//;s/ ..\.ts$//;s/ /./g')"
+ n_widths=$(echo "$months" |
+ while read mon; do echo "$mon" | LC_ALL=$LOC wc -L; done |
+ uniq | wc -l
+ )
+ n_dupes=$(echo "$months" | sort | uniq -d | wc -l)
+ test "$n_widths" = "1" || { fail=1; break 2; }
+ test "$n_dupes" = "0" || { fail=1; break 2; }
+ done
+done
+if test "$fail" = "1"; then
+ echo "misalignment or ambiguous output in $LOC locale:"
+ LC_ALL=$LOC TIME_STYLE=+%b ls -lgG *.ts
+fi
+
+Exit $fail
diff --git a/tests/ls/birthtime.sh b/tests/ls/birthtime.sh
new file mode 100755
index 0000000..7f6347f
--- /dev/null
+++ b/tests/ls/birthtime.sh
@@ -0,0 +1,27 @@
+#!/bin/sh
+# ensure that ls attempts birthtime access
+
+# Copyright (C) 2020-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ ls
+
+# ls should not fail, even if birth time not available
+touch a || framework_failure_
+ls --time=birth -l a || fail=1
+ls --time=creation -t a || fail=1
+
+Exit $fail
diff --git a/tests/ls/block-size.sh b/tests/ls/block-size.sh
new file mode 100755
index 0000000..3dfd5fe
--- /dev/null
+++ b/tests/ls/block-size.sh
@@ -0,0 +1,186 @@
+#!/bin/sh
+# Exercise ls --block-size and related options.
+
+# Copyright (C) 2011-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ ls
+
+TZ=UTC0
+export TZ
+
+mkdir sub
+cd sub
+
+for size in 1024 4096 262144; do
+ echo foo | dd conv=sync bs=$size >file$size || fail=1
+done
+touch -d '2001-01-01 00:00' file* || fail=1
+
+size_etc='s/[^ ]* *[^ ]* *//'
+
+ls -og * | sed "$size_etc" >../out || fail=1
+POSIXLY_CORRECT=1 ls -og * | sed "$size_etc" >>../out || fail=1
+POSIXLY_CORRECT=1 ls -k -og * | sed "$size_etc" >>../out || fail=1
+
+for var in BLOCKSIZE BLOCK_SIZE LS_BLOCK_SIZE; do
+ for blocksize in 1 512 1K 1KiB; do
+ (eval $var=$blocksize && export $var &&
+ echo "x x # $var=$blocksize" &&
+ ls -og * &&
+ ls -og -k * &&
+ ls -og -k --block-size=$blocksize *
+ ) | sed "$size_etc" >>../out || fail=1
+ done
+done
+
+cd ..
+
+cat >exp <<'EOF'
+1024 Jan 1 2001 file1024
+262144 Jan 1 2001 file262144
+4096 Jan 1 2001 file4096
+1024 Jan 1 2001 file1024
+262144 Jan 1 2001 file262144
+4096 Jan 1 2001 file4096
+1024 Jan 1 2001 file1024
+262144 Jan 1 2001 file262144
+4096 Jan 1 2001 file4096
+# BLOCKSIZE=1
+1024 Jan 1 2001 file1024
+262144 Jan 1 2001 file262144
+4096 Jan 1 2001 file4096
+1024 Jan 1 2001 file1024
+262144 Jan 1 2001 file262144
+4096 Jan 1 2001 file4096
+1024 Jan 1 2001 file1024
+262144 Jan 1 2001 file262144
+4096 Jan 1 2001 file4096
+# BLOCKSIZE=512
+1024 Jan 1 2001 file1024
+262144 Jan 1 2001 file262144
+4096 Jan 1 2001 file4096
+1024 Jan 1 2001 file1024
+262144 Jan 1 2001 file262144
+4096 Jan 1 2001 file4096
+2 Jan 1 2001 file1024
+512 Jan 1 2001 file262144
+8 Jan 1 2001 file4096
+# BLOCKSIZE=1K
+1024 Jan 1 2001 file1024
+262144 Jan 1 2001 file262144
+4096 Jan 1 2001 file4096
+1024 Jan 1 2001 file1024
+262144 Jan 1 2001 file262144
+4096 Jan 1 2001 file4096
+1 Jan 1 2001 file1024
+256 Jan 1 2001 file262144
+4 Jan 1 2001 file4096
+# BLOCKSIZE=1KiB
+1024 Jan 1 2001 file1024
+262144 Jan 1 2001 file262144
+4096 Jan 1 2001 file4096
+1024 Jan 1 2001 file1024
+262144 Jan 1 2001 file262144
+4096 Jan 1 2001 file4096
+1 Jan 1 2001 file1024
+256 Jan 1 2001 file262144
+4 Jan 1 2001 file4096
+# BLOCK_SIZE=1
+1024 Jan 1 2001 file1024
+262144 Jan 1 2001 file262144
+4096 Jan 1 2001 file4096
+1024 Jan 1 2001 file1024
+262144 Jan 1 2001 file262144
+4096 Jan 1 2001 file4096
+1024 Jan 1 2001 file1024
+262144 Jan 1 2001 file262144
+4096 Jan 1 2001 file4096
+# BLOCK_SIZE=512
+2 Jan 1 2001 file1024
+512 Jan 1 2001 file262144
+8 Jan 1 2001 file4096
+2 Jan 1 2001 file1024
+512 Jan 1 2001 file262144
+8 Jan 1 2001 file4096
+2 Jan 1 2001 file1024
+512 Jan 1 2001 file262144
+8 Jan 1 2001 file4096
+# BLOCK_SIZE=1K
+1 Jan 1 2001 file1024
+256 Jan 1 2001 file262144
+4 Jan 1 2001 file4096
+1 Jan 1 2001 file1024
+256 Jan 1 2001 file262144
+4 Jan 1 2001 file4096
+1 Jan 1 2001 file1024
+256 Jan 1 2001 file262144
+4 Jan 1 2001 file4096
+# BLOCK_SIZE=1KiB
+1 Jan 1 2001 file1024
+256 Jan 1 2001 file262144
+4 Jan 1 2001 file4096
+1 Jan 1 2001 file1024
+256 Jan 1 2001 file262144
+4 Jan 1 2001 file4096
+1 Jan 1 2001 file1024
+256 Jan 1 2001 file262144
+4 Jan 1 2001 file4096
+# LS_BLOCK_SIZE=1
+1024 Jan 1 2001 file1024
+262144 Jan 1 2001 file262144
+4096 Jan 1 2001 file4096
+1024 Jan 1 2001 file1024
+262144 Jan 1 2001 file262144
+4096 Jan 1 2001 file4096
+1024 Jan 1 2001 file1024
+262144 Jan 1 2001 file262144
+4096 Jan 1 2001 file4096
+# LS_BLOCK_SIZE=512
+2 Jan 1 2001 file1024
+512 Jan 1 2001 file262144
+8 Jan 1 2001 file4096
+2 Jan 1 2001 file1024
+512 Jan 1 2001 file262144
+8 Jan 1 2001 file4096
+2 Jan 1 2001 file1024
+512 Jan 1 2001 file262144
+8 Jan 1 2001 file4096
+# LS_BLOCK_SIZE=1K
+1 Jan 1 2001 file1024
+256 Jan 1 2001 file262144
+4 Jan 1 2001 file4096
+1 Jan 1 2001 file1024
+256 Jan 1 2001 file262144
+4 Jan 1 2001 file4096
+1 Jan 1 2001 file1024
+256 Jan 1 2001 file262144
+4 Jan 1 2001 file4096
+# LS_BLOCK_SIZE=1KiB
+1 Jan 1 2001 file1024
+256 Jan 1 2001 file262144
+4 Jan 1 2001 file4096
+1 Jan 1 2001 file1024
+256 Jan 1 2001 file262144
+4 Jan 1 2001 file4096
+1 Jan 1 2001 file1024
+256 Jan 1 2001 file262144
+4 Jan 1 2001 file4096
+EOF
+
+compare exp out || fail=1
+
+Exit $fail
diff --git a/tests/ls/capability.sh b/tests/ls/capability.sh
new file mode 100755
index 0000000..0ccceda
--- /dev/null
+++ b/tests/ls/capability.sh
@@ -0,0 +1,63 @@
+#!/bin/sh
+# Ensure "ls --color" properly colors name of file with capability.
+
+# Copyright (C) 2008-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ ls printf
+require_root_
+
+grep '^#define HAVE_CAP 1' $CONFIG_HEADER > /dev/null \
+ || skip_ "configured without libcap support"
+
+(setcap --help) 2>&1 |grep 'usage: setcap' > /dev/null \
+ || skip_ "setcap utility not found"
+
+# Don't let a different umask perturb the results.
+umask 22
+
+# We create 2 files of the same name as
+# before coreutils 8.1 only the name rather than
+# the full path was used to read the capabilities
+# thus giving false positives and negatives.
+mkdir test test/dir
+cd test
+touch cap_pos dir/cap_pos dir/cap_neg
+for file in cap_pos dir/cap_neg; do
+ setcap 'cap_net_bind_service=ep' $file ||
+ skip_ "setcap doesn't work"
+done
+
+code='30;41'
+# Note we explicitly disable "executable" coloring
+# so that capability coloring is not dependent on it,
+# as was the case before coreutils 8.1
+for ex in '' ex=:; do
+ LS_COLORS="di=:${ex}ca=$code" \
+ ls --color=always cap_pos dir > out || fail=1
+
+ env printf "\
+\e[0m\e[${code}mcap_pos\e[0m
+
+dir:
+\e[${code}mcap_neg\e[0m
+cap_pos
+" > out_ok || framework_failure_
+
+ compare out out_ok || fail=1
+done
+
+Exit $fail
diff --git a/tests/ls/classify.sh b/tests/ls/classify.sh
new file mode 100755
index 0000000..8645ab5
--- /dev/null
+++ b/tests/ls/classify.sh
@@ -0,0 +1,63 @@
+#!/bin/sh
+# Test --classify processing
+
+# Copyright (C) 2020-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ ls
+
+mkdir testdir || framework_failure_
+cd testdir || framework_failure_
+mkdir dir || framework_failure_
+touch regular executable || framework_failure_
+chmod a+x executable || framework_failure_
+ln -s regular slink-reg || framework_failure_
+ln -s dir slink-dir || framework_failure_
+ln -s nowhere slink-dangle || framework_failure_
+mknod block b 20 20 2> /dev/null && block="block
+"
+mknod char c 10 10 2> /dev/null && char="char
+"
+mkfifo_or_skip_ fifo
+cd ..
+
+cat <<EOF > exp
+$block${char}dir/
+executable*
+fifo|
+regular
+slink-dangle@
+slink-dir@
+slink-reg@
+EOF
+sed 's/[*/@|]//' exp > exp2 || framework_failure_
+
+ls --classify testdir > out || fail=1
+ls --classify=always testdir > out2 || fail=1
+ls --classify=auto testdir > out3 || fail=1
+ls --classify=never testdir > out4 || fail=1
+
+compare exp out || fail=1
+
+compare exp out2 || fail=1
+
+compare exp2 out3 || fail=1
+
+compare exp2 out4 || fail=1
+
+returns_ 1 ls --classify=invalid || fail=1
+
+Exit $fail
diff --git a/tests/ls/color-clear-to-eol.sh b/tests/ls/color-clear-to-eol.sh
new file mode 100755
index 0000000..dc4bcd2
--- /dev/null
+++ b/tests/ls/color-clear-to-eol.sh
@@ -0,0 +1,41 @@
+#!/bin/sh
+# ensure that ls --color works well when a colored name is wrapped
+
+# Copyright (C) 2009-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ ls
+
+long_name=zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz.foo
+touch $long_name || framework_failure_
+
+e='\33'
+color_code='0;31;42'
+c_pre="$e[0m$e[${color_code}m"
+c_post="$e[0m$e[K\n"
+printf "$c_pre$long_name$c_post\n" > exp || framework_failure_
+
+env TERM=xterm COLUMNS=80 LS_COLORS="*.foo=$color_code" TIME_STYLE=+T \
+ ls -og --color=always $long_name > out || fail=1
+
+# Append a newline, to accommodate less-capable versions of sed.
+echo >> out || framework_failure_
+
+sed 's/.*T //' out > k && mv k out
+
+compare exp out || fail=1
+
+Exit $fail
diff --git a/tests/ls/color-dtype-dir.sh b/tests/ls/color-dtype-dir.sh
new file mode 100755
index 0000000..d51cbaf
--- /dev/null
+++ b/tests/ls/color-dtype-dir.sh
@@ -0,0 +1,64 @@
+#!/bin/sh
+# Ensure "ls --color" properly colors other-writable and sticky directories.
+# Before coreutils-6.2, this test would fail, coloring all three
+# directories the same as the first one -- but only on a file system
+# with dirent.d_type support.
+
+# Copyright (C) 2006-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ ls
+
+# Don't let a different umask perturb the results.
+umask 22
+
+mkdir d other-writable sticky || framework_failure_
+chmod o+w other-writable || framework_failure_
+chmod o+t sticky || framework_failure_
+
+
+TERM=xterm ls --color=always > out || fail=1
+cat -A out > o1 || framework_failure_
+mv o1 out || framework_failure_
+
+cat <<\EOF > exp || framework_failure_
+^[[0m^[[01;34md^[[0m$
+^[[34;42mother-writable^[[0m$
+out$
+^[[37;44msticky^[[0m$
+EOF
+
+compare exp out || fail=1
+
+rm exp || framework_failure_
+
+# Turn off colors for other-writable dirs and ensure
+# we fall back to the color for standard directories.
+
+LS_COLORS="ow=:" ls --color=always > out || fail=1
+cat -A out > o1 || fail=1
+mv o1 out || fail=1
+
+cat <<\EOF > exp || framework_failure_
+^[[0m^[[01;34md^[[0m$
+^[[01;34mother-writable^[[0m$
+out$
+^[[37;44msticky^[[0m$
+EOF
+
+compare exp out || fail=1
+
+Exit $fail
diff --git a/tests/ls/color-ext.sh b/tests/ls/color-ext.sh
new file mode 100755
index 0000000..dbc0d0a
--- /dev/null
+++ b/tests/ls/color-ext.sh
@@ -0,0 +1,85 @@
+#!/bin/sh
+# Ensure "ls --color" properly colors file name extensions.
+
+# Copyright (C) 2018-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ ls
+working_umask_or_skip_
+
+touch img1.jpg IMG2.JPG img3.JpG file1.z file2.Z || framework_failure_
+code_jpg='01;35'
+code_JPG='01;35;46'
+code_z='01;31'
+c0=$(printf '\033[0m')
+c_jpg=$(printf '\033[%sm' $code_jpg)
+c_JPG=$(printf '\033[%sm' $code_JPG)
+c_z=$(printf '\033[%sm' $code_z)
+
+# Case insensitive extensions
+LS_COLORS="*.jpg=$code_jpg:*.Z=$code_z" ls -U1 --color=always \
+ img1.jpg IMG2.JPG file1.z file2.Z > out || fail=1
+printf "$c0\
+${c_jpg}img1.jpg$c0
+${c_jpg}IMG2.JPG$c0
+${c_z}file1.z$c0
+${c_z}file2.Z$c0
+" > out_ok || framework_failure_
+compare out out_ok || fail=1
+
+# Case sensitive extensions
+LS_COLORS="*.jpg=$code_jpg:*.JPG=$code_JPG" ls -U1 --color=always \
+ img1.jpg IMG2.JPG img3.JpG > out || fail=1
+printf "$c0\
+${c_jpg}img1.jpg$c0
+${c_JPG}IMG2.JPG$c0
+img3.JpG
+" > out_ok || framework_failure_
+compare out out_ok || fail=1
+
+# Case insensitive extensions (due to same sequences)
+LS_COLORS="*.jpg=$code_jpg:*.JPG=$code_jpg" ls -U1 --color=always \
+ img1.jpg IMG2.JPG img3.JpG > out || fail=1
+printf "$c0\
+${c_jpg}img1.jpg$c0
+${c_jpg}IMG2.JPG$c0
+${c_jpg}img3.JpG$c0
+" > out_ok || framework_failure_
+compare out out_ok || fail=1
+
+# Case insensitive extensions (due to same sequences (after ignored sequences))
+# Note later entries in LS_COLORS take precedence.
+LS_COLORS="*.jpg=$code_jpg:*.jpg=$code_JPG:*.JPG=$code_JPG" \
+ ls -U1 --color=always img1.jpg IMG2.JPG img3.JpG > out || fail=1
+printf "$c0\
+${c_JPG}img1.jpg$c0
+${c_JPG}IMG2.JPG$c0
+${c_JPG}img3.JpG$c0
+" > out_ok || framework_failure_
+compare out out_ok || fail=1
+
+# Case sensitive extensions (due to diff sequences (after ignored sequences))
+# Note later entries in LS_COLORS take precedence.
+LS_COLORS="*.jpg=$code_JPG:*.jpg=$code_jpg:*.JPG=$code_JPG" \
+ ls -U1 --color=always img1.jpg IMG2.JPG img3.JpG > out || fail=1
+printf "$c0\
+${c_jpg}img1.jpg$c0
+${c_JPG}IMG2.JPG$c0
+img3.JpG
+" > out_ok || framework_failure_
+compare out out_ok || fail=1
+
+Exit $fail
diff --git a/tests/ls/color-norm.sh b/tests/ls/color-norm.sh
new file mode 100755
index 0000000..09b52f3
--- /dev/null
+++ b/tests/ls/color-norm.sh
@@ -0,0 +1,84 @@
+#!/bin/sh
+# Ensure "ls --color" properly colors "normal" text and files.
+# I.e., that it uses NORMAL to style non file name output and
+# file names with no associated color (unless FILE is also set).
+
+# Copyright (C) 2010-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ ls
+
+# Don't let a different umask perturb the results.
+umask 22
+
+# Output time as something constant
+export TIME_STYLE="+norm"
+
+# helper to strip ls columns up to "norm" time
+qls() { sed 's/-r.*norm/norm/'; }
+
+touch exe || framework_failure_
+chmod u+x exe || framework_failure_
+touch nocolor || framework_failure_
+
+TCOLORS="no=7:ex=01;32"
+
+# Uncolored file names inherit NORMAL attributes.
+LS_COLORS=$TCOLORS ls -gGU --color exe nocolor | qls >> out || fail=1
+LS_COLORS=$TCOLORS ls -xU --color exe nocolor >> out || fail=1
+LS_COLORS=$TCOLORS ls -gGU --color nocolor exe | qls >> out || fail=1
+LS_COLORS=$TCOLORS ls -xU --color nocolor exe >> out || fail=1
+
+# NORMAL does not override FILE though
+LS_COLORS=$TCOLORS:fi=1 ls -gGU --color nocolor exe | qls >> out || fail=1
+
+# Support uncolored ordinary files that do _not_ inherit from NORMAL.
+# Note there is a redundant RESET output before a non colored
+# file in this case which may be removed in future.
+LS_COLORS=$TCOLORS:fi= ls -gGU --color nocolor exe | qls >> out || fail=1
+LS_COLORS=$TCOLORS:fi=0 ls -gGU --color nocolor exe | qls >> out || fail=1
+
+# A caveat worth noting is that commas (-m), indicator chars (-F)
+# and the "total" line, do not currently use NORMAL attributes
+LS_COLORS=$TCOLORS ls -mFU --color nocolor exe >> out || fail=1
+
+# Ensure no coloring is done unless enabled
+LS_COLORS=$TCOLORS ls -gGU nocolor exe | qls >> out || fail=1
+
+cat -A out > out.display || framework_failure_
+mv out.display out || framework_failure_
+
+cat <<\EOF > exp || framework_failure_
+^[[0m^[[7mnorm ^[[m^[[01;32mexe^[[0m$
+^[[7mnorm nocolor^[[0m$
+^[[0m^[[7m^[[m^[[01;32mexe^[[0m ^[[7mnocolor^[[0m$
+^[[0m^[[7mnorm nocolor^[[0m$
+^[[7mnorm ^[[m^[[01;32mexe^[[0m$
+^[[0m^[[7mnocolor^[[0m ^[[7m^[[m^[[01;32mexe^[[0m$
+^[[0m^[[7mnorm ^[[m^[[1mnocolor^[[0m$
+^[[7mnorm ^[[m^[[01;32mexe^[[0m$
+^[[0m^[[7mnorm ^[[m^[[mnocolor^[[0m$
+^[[7mnorm ^[[m^[[01;32mexe^[[0m$
+^[[0m^[[7mnorm ^[[m^[[0mnocolor^[[0m$
+^[[7mnorm ^[[m^[[01;32mexe^[[0m$
+^[[0m^[[7mnocolor^[[0m, ^[[7m^[[m^[[01;32mexe^[[0m*$
+norm nocolor$
+norm exe$
+EOF
+
+compare exp out || fail=1
+
+Exit $fail
diff --git a/tests/ls/color-term.sh b/tests/ls/color-term.sh
new file mode 100755
index 0000000..3e5aca0
--- /dev/null
+++ b/tests/ls/color-term.sh
@@ -0,0 +1,48 @@
+#!/bin/sh
+# Ensure "ls --color" doesn't output colors for TERM=dumb
+
+# Copyright (C) 2014-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ ls
+
+# Output time as something constant
+export TIME_STYLE="+norm"
+
+touch exe || framework_failure_
+chmod u+x exe || framework_failure_
+
+# output colors
+LS_COLORS='' COLORTERM='nonempty' TERM='' ls --color=always exe >> out || fail=1
+LS_COLORS='' COLORTERM='' TERM='xterm' ls --color=always exe >> out || fail=1
+
+# Don't output colors
+LS_COLORS='' COLORTERM='' TERM='dumb' ls --color=always exe >> out || fail=1
+LS_COLORS='' COLORTERM='' TERM='' ls --color=always exe >> out || fail=1
+
+cat -A out > out.display || framework_failure_
+mv out.display out || framework_failure_
+
+cat <<\EOF > exp || framework_failure_
+^[[0m^[[01;32mexe^[[0m$
+^[[0m^[[01;32mexe^[[0m$
+exe$
+exe$
+EOF
+
+compare exp out || fail=1
+
+Exit $fail
diff --git a/tests/ls/dangle.sh b/tests/ls/dangle.sh
new file mode 100755
index 0000000..0e59e86
--- /dev/null
+++ b/tests/ls/dangle.sh
@@ -0,0 +1,64 @@
+#!/bin/sh
+# Make sure ls properly handles dangling symlinks vs. ls's -L, -H, options.
+
+# Copyright (C) 2003-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ ls
+
+LS_MINOR_PROBLEM=1
+LS_FAILURE=2
+
+ln -s no-such-file dangle || framework_failure_
+mkdir -p dir/sub || framework_failure_
+ln -s dir slink-to-dir || framework_failure_
+mkdir d || framework_failure_
+ln -s no-such d/dangle || framework_failure_
+printf '? dangle\n' > subdir_Li_exp || framework_failure_
+printf 'total 0\n? dangle\n' > subdir_Ls_exp || framework_failure_
+
+# This must exit nonzero.
+returns_ $LS_FAILURE ls -L dangle > /dev/null 2>&1 || fail=1
+# So must this.
+returns_ $LS_FAILURE ls -H dangle > /dev/null 2>&1 || fail=1
+
+# This must exit successfully.
+ls dangle >> out || fail=1
+
+ls slink-to-dir >> out 2>&1 || fail=1
+ls -H slink-to-dir >> out 2>&1 || fail=1
+ls -L slink-to-dir >> out 2>&1 || fail=1
+
+cat <<\EOF > exp
+dangle
+sub
+sub
+sub
+EOF
+
+compare exp out || fail=1
+
+# Ensure that ls -Li prints "?" as the inode of a dangling symlink.
+rm -f out
+returns_ $LS_MINOR_PROBLEM ls -Li d > out 2>/dev/null || fail=1
+compare subdir_Li_exp out || fail=1
+
+# Ensure that ls -Ls prints "?" as the allocation of a dangling symlink.
+rm -f out
+returns_ $LS_MINOR_PROBLEM ls -Ls d > out 2>/dev/null || fail=1
+compare subdir_Ls_exp out || fail=1
+
+Exit $fail
diff --git a/tests/ls/dired.sh b/tests/ls/dired.sh
new file mode 100755
index 0000000..150fff2
--- /dev/null
+++ b/tests/ls/dired.sh
@@ -0,0 +1,35 @@
+#!/bin/sh
+# make sure --dired option works
+
+# Copyright (C) 2001-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ ls
+
+mkdir dir || framework_failure_
+
+
+LC_MESSAGES=C ls -lR --dired dir > out || fail=1
+cat <<EOF > exp
+ dir:
+ total 0
+//SUBDIRED// 2 5
+//DIRED-OPTIONS// --quoting-style=literal
+EOF
+
+compare exp out || fail=1
+
+Exit $fail
diff --git a/tests/ls/file-type.sh b/tests/ls/file-type.sh
new file mode 100755
index 0000000..1df2074
--- /dev/null
+++ b/tests/ls/file-type.sh
@@ -0,0 +1,65 @@
+#!/bin/sh
+# contrast ls -F, ls -p, and ls --indicator-style=file-type
+
+# Copyright (C) 2002-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ ls
+
+mkdir sub
+cd sub
+mkdir dir
+touch regular executable
+chmod a+x executable
+ln -s regular slink-reg
+ln -s dir slink-dir
+ln -s nowhere slink-dangle
+mknod block b 20 20 2> /dev/null && block="block
+"
+mknod char c 10 10 2> /dev/null && char="char
+"
+mkfifo_or_skip_ fifo
+cd ..
+
+
+
+ls -F sub > out || fail=1
+cat <<EOF > exp
+$block${char}dir/
+executable*
+fifo|
+regular
+slink-dangle@
+slink-dir@
+slink-reg@
+EOF
+
+sed 's/\*//' exp > exp2
+ls --indicator-style=file-type sub > out2 || fail=1
+
+sed 's/[@|]$//' exp2 > exp3
+ls -p sub > out3 || fail=1
+
+compare exp out || fail=1
+
+compare exp2 out2 || fail=1
+
+compare exp3 out3 || fail=1
+
+ls --color=auto -F sub > out || fail=1
+compare exp out || fail=1
+
+Exit $fail
diff --git a/tests/ls/follow-slink.sh b/tests/ls/follow-slink.sh
new file mode 100755
index 0000000..38ee0af
--- /dev/null
+++ b/tests/ls/follow-slink.sh
@@ -0,0 +1,63 @@
+#!/bin/sh
+# make sure ls -L always follows symlinks
+
+# Copyright (C) 2000-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ ls
+
+LS_FAILURE=2
+
+# Isolate output files from directory being listed
+mkdir dir dir/sub dir1 || framework_failure_
+cd dir || framework_failure_
+ln -s link link || framework_failure_
+ln -s ../../dir1 sub/link-to-dir || framework_failure_
+
+# Make sure the symlink was created.
+# 'ln -s link link' succeeds, but creates no file on
+# systems running some DJGPP-2.03 libc.
+ls -F link > /dev/null || framework_failure_
+
+
+# When explicitly listing a broken link, the command must fail.
+returns_ $LS_FAILURE ls -L link 2> /dev/null || fail=1
+
+# When encountering a broken link implicitly, Solaris 9 and OpenBSD 3.4
+# list the link, provided no further information about the link needed
+# to be printed. Since POSIX does not specify one way or the other, we
+# opt for compatibility (this was broken in 5.3.0 through 5.94).
+LC_ALL=C ls -L > ../out-L || fail=1
+LC_ALL=C ls -FLR sub > ../out-FLR-sub || fail=1
+
+cd .. || fail=1
+
+cat <<\EOF > exp-L
+link
+sub
+EOF
+
+cat <<\EOF > exp-FLR-sub
+sub:
+link-to-dir/
+
+sub/link-to-dir:
+EOF
+
+compare exp-L out-L || fail=1
+compare exp-FLR-sub out-FLR-sub || fail=1
+
+Exit $fail
diff --git a/tests/ls/getxattr-speedup.sh b/tests/ls/getxattr-speedup.sh
new file mode 100755
index 0000000..5665e39
--- /dev/null
+++ b/tests/ls/getxattr-speedup.sh
@@ -0,0 +1,66 @@
+#!/bin/sh
+# Show that we've eliminated most of ls' failing getxattr syscalls,
+# regardless of how many files are in a directory we list.
+# This test is skipped on systems that lack LD_PRELOAD support; that's fine.
+# Similarly, on a system that lacks getxattr altogether, skipping it is fine.
+
+# Copyright (C) 2012-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ ls
+require_gcc_shared_
+
+# Replace each getxattr and lgetxattr call with a call to these stubs.
+# Count those and write the total number of calls to the file "x"
+# via a global destructor.
+cat > k.c <<'EOF' || framework_failure_
+#include <errno.h>
+#include <stdio.h>
+#include <sys/types.h>
+
+static unsigned long int n_calls;
+
+static void __attribute__ ((destructor))
+print_call_count (void)
+{
+ FILE *fp = fopen ("x", "w"); if (!fp) return;
+ fprintf (fp, "%lu\n", n_calls); fclose (fp);
+}
+
+static ssize_t incr () { ++n_calls; errno = ENOTSUP; return -1; }
+ssize_t getxattr (const char *path, const char *name, void *value, size_t size)
+{ return incr (); }
+ssize_t lgetxattr(const char *path, const char *name, void *value, size_t size)
+{ return incr (); }
+EOF
+
+# Then compile/link it:
+gcc_shared_ k.c k.so \
+ || framework_failure_ 'failed to build shared library'
+
+# Create a few files:
+seq 20 | xargs touch || framework_failure_
+
+# Finally, run the test:
+LD_PRELOAD=$LD_PRELOAD:./k.so ls --color=always -l . || fail=1
+
+test -f x || skip_ "internal test failure: maybe LD_PRELOAD doesn't work?"
+
+# Ensure that there were no more than 3 *getxattr calls.
+n_calls=$(cat x)
+test "$n_calls" -le 3 || fail=1
+
+Exit $fail
diff --git a/tests/ls/group-dirs.sh b/tests/ls/group-dirs.sh
new file mode 100755
index 0000000..c13a94e
--- /dev/null
+++ b/tests/ls/group-dirs.sh
@@ -0,0 +1,43 @@
+#!/bin/sh
+# test --group-directories-first
+
+# Copyright (C) 2018-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ ls
+
+# Isolate output files from directory being listed
+mkdir dir dir/b || framework_failure_
+touch dir/a || framework_failure_
+ln -s b dir/bl || framework_failure_
+
+ls --group dir > out || fail=1
+cat <<\EOF > exp
+b
+bl
+a
+EOF
+compare exp out || fail=1
+
+ls --group -d dir/* > out || fail=1
+cat <<\EOF > exp
+dir/b
+dir/bl
+dir/a
+EOF
+compare exp out || fail=1
+
+Exit $fail
diff --git a/tests/ls/hex-option.sh b/tests/ls/hex-option.sh
new file mode 100755
index 0000000..2a09309
--- /dev/null
+++ b/tests/ls/hex-option.sh
@@ -0,0 +1,24 @@
+#!/bin/sh
+# accept hex/oct numbers to -w and -T
+
+# Copyright (C) 2014-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ ls
+
+ls -x -T0x10 -w010 || fail=1
+
+Exit $fail
diff --git a/tests/ls/hyperlink.sh b/tests/ls/hyperlink.sh
new file mode 100755
index 0000000..970e062
--- /dev/null
+++ b/tests/ls/hyperlink.sh
@@ -0,0 +1,63 @@
+#!/bin/sh
+# Test --hyperlink processing
+
+# Copyright (C) 2017-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ ls
+
+# lookup based on first letter
+encode() {
+ printf '%s\n' \
+ 'sp%20ace' 'ques%3ftion' 'back%5cslash' 'encoded%253Fquestion' 'testdir' \
+ "$1" |
+ sort -k1,1.1 -s | uniq -w1 -d
+}
+
+ls_encoded() {
+ ef=$(encode "$1")
+ echo "$ef" | grep 'dir$' >/dev/null && dir=: || dir=''
+ printf '\033]8;;file:///%s\a%s\033]8;;\a%s\n' \
+ "$ef" "$1" "$dir"
+}
+
+# These could be encoded, so remove from consideration
+strip_host_and_path() {
+ sed 's|file://.*/|file:///|'
+}
+
+mkdir testdir || framework_failure_
+(
+cd testdir
+ls_encoded "testdir" > ../exp.t || framework_failure_
+for f in 'back\slash' 'encoded%3Fquestion' 'ques?tion' 'sp ace'; do
+ touch "$f" || framework_failure_
+ ls_encoded "$f" >> ../exp.t || framework_failure_
+done
+)
+ln -s testdir testdirl || framework_failure_
+(cat exp.t && printf '\n' && sed 's/[^\/]testdir/&l/' exp.t) > exp \
+ || framework_failure_
+ls --hyper testdir testdirl >out.t || fail=1
+strip_host_and_path <out.t >out || framework_failure_
+compare exp out || fail=1
+
+ln -s '/probably_missing' testlink || framework_failure_
+ls -l --hyper testlink > out.t || fail=1
+strip_host_and_path <out.t >out || framework_failure_
+grep 'file:///probably_missing' out || fail=1
+
+Exit $fail
diff --git a/tests/ls/infloop.sh b/tests/ls/infloop.sh
new file mode 100755
index 0000000..d59ba81
--- /dev/null
+++ b/tests/ls/infloop.sh
@@ -0,0 +1,41 @@
+#!/bin/sh
+# show that the following no longer makes ls infloop
+# mkdir loop; cd loop; ln -s ../loop sub; ls -RL
+# Also ensure ls exits with status = 2 in that case.
+# Copyright (C) 2001-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ ls
+
+mkdir loop || framework_failure_
+ln -s ../loop loop/sub || framework_failure_
+
+cat <<\EOF > exp-out || framework_failure_
+loop:
+sub
+EOF
+
+cat <<\EOF > exp-err || framework_failure_
+ls: loop/sub: not listing already-listed directory
+EOF
+
+# Ensure that ls exits with status 2 upon detecting a cycle
+returns_ 2 timeout 10 ls -RL loop >out 2>err || fail=1
+
+compare exp-err err || fail=1
+compare exp-out out || fail=1
+
+Exit $fail
diff --git a/tests/ls/inode.sh b/tests/ls/inode.sh
new file mode 100755
index 0000000..5060a96
--- /dev/null
+++ b/tests/ls/inode.sh
@@ -0,0 +1,65 @@
+#!/bin/sh
+# Make sure that ls -i works properly on symlinks.
+
+# Copyright (C) 2003-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ ls
+
+touch f || framework_failure_
+ln -s f slink || framework_failure_
+
+
+# When listed explicitly:
+
+set x $(ls -Ci f slink); shift
+test $# = 4 || fail=1
+# The inode numbers should differ.
+test "$1" != "$3" || fail=1
+
+set x $(ls -CLi f slink); shift
+test $# = 4 || fail=1
+# With -L, they must be the same.
+test "$1" = "$3" || fail=1
+
+set x $(ls -CHi f slink); shift
+test $# = 4 || fail=1
+# With -H, they must be the same, too, from the command line.
+# Note that POSIX says -H must make ls dereference only
+# symlinks (specified on the command line) to directories,
+# but the historical BSD meaning of -H is to dereference
+# any symlink given on the command line. For compatibility GNU ls
+# implements the BSD semantics.
+test "$1" = "$3" || fail=1
+
+# When listed from a directory:
+
+set x $(ls -Ci); shift
+test $# = 4 || fail=1
+# The inode numbers should differ.
+test "$1" != "$3" || fail=1
+
+set x $(ls -CLi); shift
+test $# = 4 || fail=1
+# With -L, they must be the same.
+test "$1" = "$3" || fail=1
+
+set x $(ls -CHi); shift
+test $# = 4 || fail=1
+# With -H, they must be different from inside a directory.
+test "$1" != "$3" || fail=1
+
+Exit $fail
diff --git a/tests/ls/ls-misc.pl b/tests/ls/ls-misc.pl
new file mode 100755
index 0000000..f3f09c4
--- /dev/null
+++ b/tests/ls/ls-misc.pl
@@ -0,0 +1,375 @@
+#!/usr/bin/perl
+
+# Copyright (C) 1998-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+use strict;
+
+(my $ME = $0) =~ s|.*/||;
+my $prog = 'ls';
+
+# Turn off localization of executable's output.
+@ENV{qw(LANGUAGE LANG LC_ALL)} = ('C') x 3;
+
+my $saved_ls_colors;
+
+sub push_ls_colors($)
+{
+ $saved_ls_colors = $ENV{LS_COLORS} || '';
+ $ENV{LS_COLORS} = $_[0];
+}
+
+sub restore_ls_colors()
+{
+ $ENV{LS_COLORS} = $saved_ls_colors;
+}
+
+# If the string $S is a well-behaved file name, simply return it.
+# If it contains white space, quotes, etc., quote it, and return the new string.
+sub shell_quote($)
+{
+ my ($s) = @_;
+ if ($s =~ m![^\w+/.,-]!)
+ {
+ # Convert each single quote to '\''
+ $s =~ s/\'/\'\\\'\'/g;
+ # Then single quote the string.
+ $s = "'$s'";
+ }
+ return $s;
+}
+
+# Set up files used by the setuid-etc tests; skip this entire test if
+# that cannot be done.
+sub setuid_setup()
+{
+ my $test = 'env test';
+ system (qq(touch setuid && chmod u+s setuid && $test -u setuid &&
+ touch setgid && chmod g+s setgid && $test -g setgid &&
+ mkdir sticky && chmod +t sticky && $test -k sticky &&
+ mkdir owt && chmod +t,o+w owt && $test -k owt &&
+ mkdir owr && chmod o+w owr)) == 0
+ or CuSkip::skip "$ME: cannot create setuid/setgid/sticky files,"
+ . "so can't run this test\n";
+}
+
+sub mk_file(@)
+{
+ foreach my $f (@_)
+ {
+ open (F, '>', $f) && close F
+ or die "creating $f: $!\n";
+ }
+}
+
+sub mkdir_d {mkdir 'd',0755 or die "d: $!\n"}
+sub rmdir_d {rmdir 'd' or die "d: $!\n"}
+my $mkdir = {PRE => sub {mkdir_d}};
+my $rmdir = {POST => sub {rmdir_d}};
+my $mkdir_reg = {PRE => sub {mkdir_d; mk_file 'd/f' }};
+my $rmdir_reg = {POST => sub {unlink 'd/f' or die "d/f: $!\n";
+ rmdir 'd' or die "d: $!\n"}};
+
+my $mkdir2 = {PRE => sub {mkdir 'd',0755 or die "d: $!\n";
+ mkdir 'd/e',0755 or die "d/e: $!\n" }};
+my $rmdir2 = {POST => sub {rmdir 'd/e' or die "d/e: $!\n";
+ rmdir 'd' or die "d: $!\n" }};
+
+my $target = {PRE => sub {
+ mkdir 'd',0755 or die "d: $!\n";
+ symlink '.', 'd/X' or die "d/X: $!\n";
+ push_ls_colors('ln=target')
+ }};
+my $target2 = {POST => sub {unlink 'd/X' or die "d/X: $!\n";
+ rmdir 'd' or die "d: $!\n";
+ restore_ls_colors
+ }};
+my $slink_d = {PRE => sub {symlink '/', 'd' or die "d: $!\n";
+ push_ls_colors('ln=01;36:di=01;34:or=40;31;01')
+ }};
+my $unlink_d = {POST => sub {unlink 'd' or die "d: $!\n"; restore_ls_colors}};
+
+my $mkdir_d_slink = {PRE => sub {mkdir 'd',0755 or die "d: $!\n";
+ symlink '/', 'd/s' or die "d/s: $!\n" }};
+my $rmdir_d_slink = {POST => sub {unlink 'd/s' or die "d/s: $!\n";
+ rmdir 'd' or die "d: $!\n" }};
+
+sub make_j_d ()
+{
+ mkdir 'j', 0700 or die "creating j: $!\n";
+ mk_file 'j/d';
+ chmod 0555, 'j/d' or die "making j/d executable: $!\n";
+}
+
+my @v_files = (
+ '.0', '.9',
+ '.A', '.Z', '.a', '.z', '.zz~', '.zz', '.zz.~1~', '.zz.0',
+ '0', '9',
+ 'A', 'Z', 'a', 'z', 'zz~', 'zz', 'zz.~1~', 'zz.0');
+my $exe_in_subdir = {PRE => sub { make_j_d (); push_ls_colors('ex=01;32') }};
+my $remove_j = {POST => sub {unlink 'j/d' or die "j/d: $!\n";
+ rmdir 'j' or die "j: $!\n";
+ restore_ls_colors }};
+
+my $e = "\e[0m";
+my $q_bell = {IN => {"q\a" => ''}};
+my @Tests =
+ (
+ # test-name options input expected-output
+ #
+ # quoting tests............................................
+ ['q-', $q_bell, {OUT => "q\a\n"}, {EXIT => 0}],
+ ['q-N', '-N', $q_bell, {OUT => "q\a\n"}, {ERR => ''}],
+ ['q-q', '-q', $q_bell, {OUT => "q?\n"}],
+ ['q-Q', '-Q', $q_bell, {OUT => "\"q\\a\"\n"}],
+
+ ['q-qs-lit', '--quoting=literal', $q_bell, {OUT => "q\a\n"}],
+ ['q-qs-sh', '--quoting=shell', $q_bell, {OUT => "q\a\n"}],
+ ['q-qs-sh-a', '--quoting=shell-always',$q_bell, {OUT => "'q\a'\n"}],
+ ['q-qs-sh-e', '--quoting=shell-escape',$q_bell, {OUT => "'q'\$'\\a'\n"}],
+ ['q-qs-c', '--quoting=c', $q_bell, {OUT => "\"q\\a\"\n"}],
+ ['q-qs-esc', '--quoting=escape', $q_bell, {OUT => "q\\a\n"}],
+ ['q-qs-loc', '--quoting=locale', $q_bell, {OUT => "'q\\a'\n"}],
+ ['q-qs-cloc', '--quoting=clocale', $q_bell, {OUT => "\"q\\a\"\n"}],
+
+ ['q-qs-lit-q', '--quoting=literal -q', $q_bell, {OUT => "q?\n"}],
+ ['q-qs-sh-q', '--quoting=shell -q', $q_bell, {OUT => "q?\n"}],
+ ['q-qs-sh-a-q', '--quoting=shell-al -q', $q_bell, {OUT => "'q?'\n"}],
+ ['q-qs-sh-e-q', '--quoting=shell-escape -q',
+ $q_bell, {OUT => "'q'\$'\\a'\n"}],
+ ['q-qs-c-q', '--quoting=c -q', $q_bell, {OUT => "\"q\\a\"\n"}],
+ ['q-qs-esc-q', '--quoting=escape -q', $q_bell, {OUT => "q\\a\n"}],
+ ['q-qs-loc-q', '--quoting=locale -q', $q_bell, {OUT => "'q\\a'\n"}],
+ ['q-qs-cloc-q', '--quoting=clocale -q', $q_bell, {OUT => "\"q\\a\"\n"}],
+
+ ['q-qs-c-1', '--quoting=c',
+ {IN => {"t\004" => ''}}, {OUT => "\"t\\004\"\n"}],
+
+ ['emptydir', 'd', {OUT => ''}, $mkdir, $rmdir],
+ ['emptydir-x2', 'd d', {OUT => "d:\n\nd:\n"}, $mkdir, $rmdir],
+ ['emptydir-R', '-R d', {OUT => "d:\n"}, $mkdir, $rmdir],
+
+ # test 'ls -R .' ............................................
+ ['R-dot', '--ignore="[a-ce-zA-Z]*" -R .', {OUT => ".:\nd\n\n\./d:\n"},
+ $mkdir, $rmdir],
+
+ ['slink-dir-F', '-F d', {OUT => "d@\n"}, $slink_d, $unlink_d],
+ ['slink-dir-dF', '-dF d', {OUT => "d@\n"}, $slink_d, $unlink_d],
+ ['slinkdir-dFH', '-dFH d', {OUT => "d/\n"}, $slink_d, $unlink_d],
+ ['slinkdir-dFL', '-dFL d', {OUT => "d/\n"}, $slink_d, $unlink_d],
+
+ # Test for a bug that was fixed in coreutils-4.5.4.
+ ['sl-F-color', '-F --color=always d',
+ {OUT => "$e\e[01;36md$e\@\n"},
+ $slink_d, $unlink_d],
+ ['sl-dF-color', '-dF --color=always d',
+ {OUT => "$e\e[01;36md$e\@\n"},
+ $slink_d, $unlink_d],
+
+ # A listing with no output should have no color sequences at all.
+ ['no-c-empty', '--color=always d', {OUT => ""}, $mkdir, $rmdir],
+ # A listing with only regular files should have no color sequences at all.
+ ['no-c-reg', '--color=always d', {OUT => "f\n"}, $mkdir_reg, $rmdir_reg],
+
+ # Test for a bug fixed after coreutils-6.9.
+ ['sl-target', '--color=always d',
+ {OUT => "$e\e[01;34mX$e\n"}, $target, $target2],
+
+ # Test for another bug fixed after coreutils-6.9.
+ # This one bites only for a system/file system with d_type support.
+ ['sl-dangle', '--color=always d',
+ {OUT => "$e\e[40;31;01mX$e\n"},
+ {PRE => sub {
+ mkdir 'd',0755 or die "d: $!\n";
+ symlink 'non-existent', 'd/X' or die "d/X: $!\n";
+ push_ls_colors('or=40;31;01')
+ }},
+ {POST => sub {unlink 'd/X' or die "d/X: $!\n";
+ rmdir 'd' or die "d: $!\n";
+ restore_ls_colors; }},
+ ],
+
+ # Test for a bug fixed after coreutils-8.2.
+ ['sl-dangle2', '-o --time-style=+:TIME: --color=always l',
+ {OUT_SUBST => 's/.*:TIME: //'},
+ {OUT => "l -> nowhere\n"},
+ {PRE => sub {symlink 'nowhere', 'l' or die "l: $!\n";
+ push_ls_colors('ln=target')
+ }},
+ {POST => sub {unlink 'l' or die "l: $!\n";
+ restore_ls_colors; }},
+ ],
+ ['sl-dangle3', '-o --time-style=+:TIME: --color=always l',
+ {OUT_SUBST => 's/.*:TIME: //'},
+ {OUT => "$e\e[40ml$e -> \e[34mnowhere$e\n"},
+ {PRE => sub {symlink 'nowhere', 'l' or die "l: $!\n";
+ push_ls_colors('ln=target:or=40:mi=34:')
+ }},
+ {POST => sub {unlink 'l' or die "l: $!\n";
+ restore_ls_colors; }},
+ ],
+ ['sl-dangle4', '-o --time-style=+:TIME: --color=always l',
+ {OUT_SUBST => 's/.*:TIME: //'},
+ {OUT => "$e\e[36ml$e -> \e[35mnowhere$e\n"},
+ {PRE => sub {symlink 'nowhere', 'l' or die "l: $!\n";
+ push_ls_colors('ln=34:mi=35:or=36:')
+ }},
+ {POST => sub {unlink 'l' or die "l: $!\n";
+ restore_ls_colors; }},
+ ],
+ ['sl-dangle5', '-o --time-style=+:TIME: --color=always l',
+ {OUT_SUBST => 's/.*:TIME: //'},
+ {OUT => "$e\e[34ml$e -> \e[35mnowhere$e\n"},
+ {PRE => sub {symlink 'nowhere', 'l' or die "l: $!\n";
+ push_ls_colors('ln=34:mi=35:')
+ }},
+ {POST => sub {unlink 'l' or die "l: $!\n";
+ restore_ls_colors; }},
+ ],
+
+ # Test for a bug fixed after coreutils-8.13
+ # where 'argetm' was erroneously printed for dangling links
+ # when ln=target was used in LS_COLORS
+ ['sl-dangle6', '-L --color=always d',
+ {OUT => "s\n"},
+ {PRE => sub {mkdir 'd',0755 or die "d: $!\n";
+ symlink 'dangle', 'd/s' or die "d/s: $!\n";
+ push_ls_colors('ln=target')
+ }},
+ {POST => sub {unlink 'd/s' or die "d/s: $!\n";
+ rmdir 'd' or die "d: $!\n";
+ restore_ls_colors; }},
+ {ERR => "ls: cannot access 'd/s': No such file or directory\n"},
+ {EXIT => 1}
+ ],
+ # Related to the above fix, is this case where
+ # the code simulates "linkok". In this case "linkmode"
+ # should always be zero, and hence not trigger any
+ # issues with type being set to C_LINK
+ ['sl-dangle7', '--color=always d',
+ {OUT => "$e\e[ms$e\n"},
+ {PRE => sub {mkdir 'd',0755 or die "d: $!\n";
+ symlink 'dangle', 'd/s' or die "d/s: $!\n";
+ push_ls_colors('ln=target:or=:ex=:')
+ }},
+ {POST => sub {unlink 'd/s' or die "d/s: $!\n";
+ rmdir 'd' or die "d: $!\n";
+ restore_ls_colors; }},
+ ],
+ # Another case with simulated "linkok", that does
+ # actually use the value of 'ln' from $LS_COLORS.
+ # This path is not taken though when 'ln=target'.
+ ['sl-dangle8', '--color=always s',
+ {OUT => "$e\e[1;36ms$e\n"},
+ {PRE => sub {symlink 'dangle', 's' or die "s: $!\n";
+ push_ls_colors('ln=1;36:or=:')
+ }},
+ {POST => sub {unlink 's' or die "s: $!\n";
+ restore_ls_colors; }},
+ ],
+ # The patch associated with sl-dangle[678] introduced a regression
+ # that was fixed after coreutils-8.19. This edge case triggers when
+ # listing a dir containing dangling symlinks, but with orphans uncolored.
+ # I.e., the same as the previous test, but listing the directory
+ # rather than the symlink directly.
+ ['sl-dangle9', '--color=always d',
+ {OUT => "$e\e[1;36ms$e\n"},
+ {PRE => sub {mkdir 'd',0755 or die "d: $!\n";
+ symlink 'dangle', 'd/s' or die "d/s: $!\n";
+ push_ls_colors('ln=1;36:or=:')
+ }},
+ {POST => sub {unlink 'd/s' or die "d/s: $!\n";
+ rmdir 'd' or die "d: $!\n";
+ restore_ls_colors; }},
+ ],
+
+ # Test for a bug that was introduced in coreutils-4.5.4; fixed in 4.5.5.
+ # To demonstrate it, the file in question (with executable bit set)
+ # must not be a command line argument.
+ ['color-exe1', '--color=always j',
+ {OUT => "$e\e[01;32md$e\n"},
+ $exe_in_subdir, $remove_j],
+
+ # From Stéphane Chazelas.
+ ['no-a-isdir-b', 'no-dir d',
+ {OUT => "d:\n"},
+ {ERR => "ls: cannot access 'no-dir': No such file or directory\n"},
+ $mkdir, $rmdir, {EXIT => 2}],
+
+ ['recursive-2', '-R d', {OUT => "d:\ne\n\nd/e:\n"}, $mkdir2, $rmdir2],
+
+ ['setuid-etc', '-1 -d --color=always owr owt setgid setuid sticky',
+ {OUT =>
+ "$e\e[34;42mowr$e\n"
+ . "\e[30;42mowt$e\n"
+ . "\e[30;43msetgid$e\n"
+ . "\e[37;41msetuid$e\n"
+ . "\e[37;44msticky$e\n"
+ },
+
+ {PRE => sub {
+ push_ls_colors('ow=34;42:tw=30;42:sg=30;43:su=37;41:st=37;44'); }},
+ {POST => sub {
+ unlink qw(setuid setgid);
+ foreach my $dir (qw(owr owt sticky)) {rmdir $dir}
+ restore_ls_colors; }},
+ ],
+
+ # For 5.97 and earlier, --file-type acted like --indicator-style=slash.
+ ['file-type', '--file-type d', {OUT => "s@\n"},
+ $mkdir_d_slink, $rmdir_d_slink],
+
+ # 7.1 had a regression in how -v -a ordered some files
+ ['version-sort', '-v -A ' . join (' ', @v_files),
+ {OUT => join ("\n", @v_files) . "\n"},
+ {PRE => sub { mk_file @v_files }},
+ {POST => sub { unlink @v_files }},
+ ],
+
+ # Test for the ls -1U bug fixed in coreutils-7.5.
+ # It is triggered only with -1U and with two or more arguments,
+ # at least one of which is a nonempty directory.
+ ['multi-arg-U1', '-U1 d no-such',
+ {OUT => "d:\nf\n"},
+ {ERR_SUBST=>"s/ch':.*/ch':/"},
+ {ERR => "$prog: cannot access 'no-such':\n"},
+ $mkdir_reg,
+ $rmdir_reg,
+ {EXIT => 2},
+ ],
+ );
+
+umask 022;
+
+# Start with an unset LS_COLORS environment variable.
+delete $ENV{LS_COLORS};
+
+my $save_temps = $ENV{SAVE_TEMPS};
+my $verbose = $ENV{VERBOSE};
+
+setuid_setup;
+my $fail = run_tests ($ME, $prog, \@Tests, $save_temps, $verbose);
+$fail
+ and exit 1;
+
+# Be careful to use the just-build dircolors.
+my $env = qx/dircolors -b/;
+$env =~ s/^LS_COLORS=\'//;
+$env =~ s/\';.*//sm;
+$ENV{LS_COLORS} = $env;
+
+setuid_setup;
+$fail = run_tests ($ME, $prog, \@Tests, $save_temps, $verbose);
+exit $fail;
diff --git a/tests/ls/ls-time.sh b/tests/ls/ls-time.sh
new file mode 100755
index 0000000..5585d62
--- /dev/null
+++ b/tests/ls/ls-time.sh
@@ -0,0 +1,145 @@
+#!/bin/sh
+# Test some of ls's sorting options.
+
+# Copyright (C) 1998-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ ls
+
+# Avoid any possible glitches due to daylight-saving changes near the
+# timestamps used during the test.
+TZ=UTC0
+export TZ
+
+t1='1998-01-15 21:00'
+t2='1998-01-15 22:00'
+t3='1998-01-15 23:00'
+
+u1='1998-01-14 11:00'
+u2='1998-01-14 12:00'
+u3='1998-01-14 13:00'
+
+touch -m -d "$t3" a || framework_failure_
+touch -m -d "$t2" b || framework_failure_
+touch -m -d "$t1" c || framework_failure_
+
+touch -a -d "$u3" c || framework_failure_
+touch -a -d "$u2" b || framework_failure_
+# Make sure A has ctime at least 1 second more recent than C's.
+sleep 2
+touch -a -d "$u1" a || framework_failure_
+# Updating the atime is usually enough to update the ctime, but on
+# Solaris 10's tmpfs, ctime is not updated, so force an update here:
+{ ln a a-ctime && rm a-ctime; } || framework_failure_
+
+
+# A has ctime more recent than C.
+set $(ls -c a c)
+test "$*" = 'a c' || fail=1
+
+# Sleep so long in an attempt to avoid spurious failures
+# due to NFS caching and/or clock skew.
+sleep 2
+
+# Create a link, updating c's ctime.
+ln c d || framework_failure_
+
+# Before we go any further, verify that touch's -m option works.
+set -- $(ls --full -l --time=mtime a)
+case "$*" in
+ *" $t3:00.000000000 +0000 a") ;;
+ *)
+ # This might be what's making HPUX 11 systems fail this test.
+ cat >&2 << EOF
+A basic test of touch -m has just failed, so the subsequent
+tests in this file will not be run.
+
+In the output below, the date of last modification for 'a' should
+have been $t3.
+EOF
+ ls --full -l a
+ skip_ "touch -m -d '$t3' didn't work"
+ ;;
+esac
+
+# Ensure that touch's -a option works.
+set -- $(ls --full -lu a)
+case "$*" in
+ *" $u1:00.000000000 +0000 a") ;;
+ *)
+ # This might be what's making HPUX 11 systems fail this test.
+ cat >&2 << EOF
+A fundamental touch -a test has just failed, so the subsequent
+tests in this file will not be run.
+
+In the output below, the date of last access for 'a' should
+have been $u1.
+EOF
+ ls --full -lu a
+ Exit 77
+ ;;
+esac
+
+set $(ls -ut a b c)
+test "$*" = 'c b a' && : || fail=1
+test $fail = 1 && ls -l --full-time --time=access a b c
+
+set $(ls -t a b c)
+test "$*" = 'a b c' && : || fail=1
+test $fail = 1 && ls -l --full-time a b c
+
+# Now, C should have ctime more recent than A.
+set $(ls -ct a c)
+if test "$*" = 'c a'; then
+ : ok
+else
+ # In spite of documentation, (e.g., stat(2)), neither link nor chmod
+ # update a file's st_ctime on SunOS4.1.4.
+ cat >&2 << \EOF
+failed ls ctime test -- this failure is expected at least for SunOS4.1.4
+and for tmpfs file systems on Solaris 5.5.1.
+It is also expected to fail on a btrfs file system until
+https://bugzilla.redhat.com/591068 is addressed.
+
+In the output below, 'c' should have had a ctime more recent than
+that of 'a', but does not.
+EOF
+ #'
+ ls -ctl --full-time a c
+ fail=1
+fi
+
+# This check is ineffective if:
+# en_US locale is not on the system.
+# The system en_US message catalog has a specific TIME_FMT translation,
+# which was inadvertently the case between coreutils 8.1 and 8.5 inclusive.
+
+if gettext --version >/dev/null 2>&1; then
+
+ default_tf1='%b %e %Y'
+ en_tf1=$(LC_ALL=en_US gettext coreutils "$default_tf1")
+
+ if test "$default_tf1" = "$en_tf1"; then
+ LC_ALL=en_US ls -l c >en_output
+ ls -l --time-style=long-iso c >liso_output
+ if compare en_output liso_output; then
+ fail=1
+ echo "Long ISO TIME_FMT being used for en_US locale." >&2
+ fi
+ fi
+fi
+
+Exit $fail
diff --git a/tests/ls/m-option.sh b/tests/ls/m-option.sh
new file mode 100755
index 0000000..3b8cdcd
--- /dev/null
+++ b/tests/ls/m-option.sh
@@ -0,0 +1,40 @@
+#!/bin/sh
+# exercise the -m option
+
+# Copyright (C) 2003-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ ls
+
+seq 2000 > b || framework_failure_
+touch a || framework_failure_
+
+
+# Before coreutils-5.1.1, the following would output a space after the comma.
+ls -w2 -m a b > out || fail=1
+
+# Before coreutils-5.1.1, the following would produce leading white space.
+# All of the sed business is because the sizes are not portable.
+ls -sm a b | sed 's/^[0-9]/0/;s/, [0-9][0-9]* b/, 12 b/' >> out || fail=1
+cat <<\EOF > exp || framework_failure_
+a,
+b
+0 a, 12 b
+EOF
+
+compare exp out || fail=1
+
+Exit $fail
diff --git a/tests/ls/multihardlink.sh b/tests/ls/multihardlink.sh
new file mode 100755
index 0000000..0d35981
--- /dev/null
+++ b/tests/ls/multihardlink.sh
@@ -0,0 +1,80 @@
+#!/bin/sh
+# Ensure "ls --color" properly colors names of hard linked files.
+
+# Copyright (C) 2008-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ ls
+working_umask_or_skip_
+
+touch file file1 || framework_failure_
+ln file1 file2 || skip_ "can't create hard link"
+code_mh='44;37'
+code_ex='01;32'
+code_png='01;35'
+c0=$(printf '\033[0m')
+c_mh=$(printf '\033[%sm' $code_mh)
+c_ex=$(printf '\033[%sm' $code_ex)
+c_png=$(printf '\033[%sm' $code_png)
+
+# regular file - not hard linked
+LS_COLORS="mh=$code_mh" ls -U1 --color=always file > out || fail=1
+printf "file\n" > out_ok || framework_failure_
+compare out out_ok || fail=1
+
+# hard links
+LS_COLORS="mh=$code_mh" ls -U1 --color=always file1 file2 > out || fail=1
+printf "$c0${c_mh}file1$c0
+${c_mh}file2$c0
+" > out_ok || framework_failure_
+compare out out_ok || fail=1
+
+# hard links and png (hard link coloring takes precedence)
+mv file2 file2.png || framework_failure_
+LS_COLORS="mh=$code_mh:*.png=$code_png" ls -U1 --color=always file1 file2.png \
+ > out || fail=1
+printf "$c0${c_mh}file1$c0
+${c_mh}file2.png$c0
+" > out_ok || framework_failure_
+compare out out_ok || fail=1
+
+# hard links and exe (exe coloring takes precedence)
+chmod a+x file2.png || framework_failure_
+LS_COLORS="mh=$code_mh:*.png=$code_png:ex=$code_ex" \
+ ls -U1 --color=always file1 file2.png > out || fail=1
+chmod a-x file2.png || framework_failure_
+printf "$c0${c_ex}file1$c0
+${c_ex}file2.png$c0
+" > out_ok || framework_failure_
+compare out out_ok || fail=1
+
+# hard links and png (hard link coloring disabled => png coloring enabled)
+LS_COLORS="mh=00:*.png=$code_png" ls -U1 --color=always file1 file2.png > out \
+ || fail=1
+printf "file1
+$c0${c_png}file2.png$c0
+" > out_ok || framework_failure_
+compare out out_ok || fail=1
+
+# hard links and png (hard link coloring not enabled explicitly => png coloring)
+LS_COLORS="*.png=$code_png" ls -U1 --color=always file1 file2.png > out \
+ || fail=1
+printf "file1
+$c0${c_png}file2.png$c0
+" > out_ok || framework_failure_
+compare out out_ok || fail=1
+
+Exit $fail
diff --git a/tests/ls/nameless-uid.sh b/tests/ls/nameless-uid.sh
new file mode 100755
index 0000000..94cdf40
--- /dev/null
+++ b/tests/ls/nameless-uid.sh
@@ -0,0 +1,40 @@
+#!/bin/sh
+# Ensure that ls -l works on files with nameless uid and/or gid
+
+# Copyright (C) 2006-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ ls
+
+require_root_
+require_perl_
+
+nameless_uid=$($PERL -e '
+ foreach my $i (1000..16*1024) { getpwuid $i or (print "$i\n"), exit }
+')
+
+if test x$nameless_uid = x; then
+ skip_ "couldn't find a nameless UID"
+fi
+
+touch f || framework_failure_
+chown $nameless_uid f || framework_failure_
+
+
+set -- $(ls -o f) || fail=1
+test $3 = $nameless_uid || fail=1
+
+Exit $fail
diff --git a/tests/ls/no-arg.sh b/tests/ls/no-arg.sh
new file mode 100755
index 0000000..bb72d83
--- /dev/null
+++ b/tests/ls/no-arg.sh
@@ -0,0 +1,56 @@
+#!/bin/sh
+# make sure ls and 'ls -R' do the right thing when invoked with no arguments.
+
+# Copyright (C) 2001-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ ls
+
+mkdir -p dir/subdir || framework_failure_
+touch dir/subdir/file2 || framework_failure_
+ln -s f symlink || framework_failure_
+
+cat > exp <<\EOF || framework_failure_
+dir
+exp
+out
+symlink
+EOF
+
+
+ls -1 > out || fail=1
+
+compare exp out || fail=1
+
+cat > exp <<\EOF
+.:
+dir
+exp
+out
+symlink
+
+./dir:
+subdir
+
+./dir/subdir:
+file2
+EOF
+
+ls -R1 > out || fail=1
+
+compare exp out || fail=1
+
+Exit $fail
diff --git a/tests/ls/no-cap.sh b/tests/ls/no-cap.sh
new file mode 100755
index 0000000..bee7bee
--- /dev/null
+++ b/tests/ls/no-cap.sh
@@ -0,0 +1,33 @@
+#!/bin/sh
+# ensure that an empty "ca=" attribute disables ls's capability-checking
+
+# Copyright (C) 2008-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ ls
+require_strace_ capget
+
+LS_COLORS=ca=1; export LS_COLORS
+strace -e capget ls --color=always > /dev/null 2> out || fail=1
+$EGREP 'capget\(' out || skip_ "your ls doesn't call capget"
+
+rm -f out
+
+LS_COLORS=ca=:; export LS_COLORS
+strace -e capget ls --color=always > /dev/null 2> out || fail=1
+$EGREP 'capget\(' out && fail=1
+
+Exit $fail
diff --git a/tests/ls/quote-align.sh b/tests/ls/quote-align.sh
new file mode 100755
index 0000000..54a6fd0
--- /dev/null
+++ b/tests/ls/quote-align.sh
@@ -0,0 +1,62 @@
+#!/bin/sh
+# test quote alignment combinations
+
+# Copyright (C) 2016-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ ls
+
+dirname='dir:name'
+mkdir "$dirname" || framework_failure_
+touch "$dirname/a b" "$dirname/c.foo" || framework_failure_
+
+e=$(printf '\033')
+color_code='0;31;42'
+c_pre="$e[0m$e[${color_code}m"
+c_post="$e[0m"
+
+cat <<EOF >exp || framework_failure_
+'$dirname':
+'a b' ${c_pre}c.foo${c_post}
+'$dirname':
+'a b' ${c_pre}c.foo${c_post}
+'$dirname':
+'a b'
+ ${c_pre}c.foo${c_post}
+'$dirname':
+'a b'
+${c_pre}c.foo${c_post}
+'$dirname':
+'a b', ${c_pre}c.foo${c_post}
+'$dirname':
+'a b' ${c_pre}c.foo${c_post}
+
+EOF
+
+for opt in '-w0 -x' '-x' '-og' '-1' '-m' '-C'; do
+ env TERM=xterm LS_COLORS="*.foo=$color_code" TIME_STYLE=+T \
+ ls $opt -R --quoting=shell-escape --color=always "$dirname" >> out || fail=1
+done
+
+# Append a newline, to accommodate less-capable versions of sed.
+echo >> out || framework_failure_
+
+# Strip possible varying portion of long format
+sed -e 's/.*T //' -e '/^total/d' out > k && mv k out
+
+compare exp out || fail=1
+
+Exit $fail
diff --git a/tests/ls/readdir-mountpoint-inode.sh b/tests/ls/readdir-mountpoint-inode.sh
new file mode 100755
index 0000000..18c5d53
--- /dev/null
+++ b/tests/ls/readdir-mountpoint-inode.sh
@@ -0,0 +1,73 @@
+#!/bin/sh
+# ensure that ls -i works also for mount points
+
+# Copyright (C) 2009-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ ls
+
+# We use --local here so as to not activate
+# potentially very many remote mounts.
+df --local --out=target | sed -n '/^\/./p' > mount_points
+test -s mount_points ||
+ skip_ "this test requires a non-root mount point"
+
+# Given e.g., /dev/shm, produce the list of GNU ls options that
+# let us list just that entry using readdir data from its parent:
+# ls -i -I '[^s]*' -I 's[^h]*' -I 'sh[^m]*' -I 'shm?*' -I '.?*' \
+# -I '?' -I '??' /dev
+
+ls_ignore_options()
+{
+ name=$1
+ opts="-I '.?*' -I '$name?*'"
+ while :; do
+ glob=$(echo "$name"|sed 's/\(.*\)\(.\)$/\1[^\2]*/')
+ opts="$opts -I '$glob'"
+ name=$(echo "$name"|sed 's/.$//')
+ test -z "$name" && break
+ glob=$(echo "$name"|sed 's/./?/g')
+ opts="$opts -I '$glob'"
+ done
+ echo "$opts"
+}
+
+inode_via_readdir()
+{
+ mount_point=$1
+ base=$(basename "$mount_point")
+ case "$base" in
+ .*) skip_ 'mount point component starts with "."' ;;
+ *[*?]*) skip_ 'mount point component contains "?" or "*"' ;;
+ esac
+ opts=$(ls_ignore_options "$base")
+ parent_dir=$(dirname "$mount_point")
+ ls_out=$(eval "ls -i $opts '$parent_dir'")
+ test $? -eq 0 || \
+ skip_ "'$parent_dir' is not readable for current user"
+ echo $ls_out | sed 's/ .*//'
+}
+
+while read dir; do
+ readdir_inode=$(inode_via_readdir "$dir")
+ test $? = 77 && continue
+ stat_inode=$(timeout 1 stat --format=%i "$dir")
+ # If stat fails or says the inode is 0, skip $dir.
+ case $stat_inode in 0|'') continue;; esac
+ test "$readdir_inode" = "$stat_inode" || fail=1
+done < mount_points
+
+Exit $fail
diff --git a/tests/ls/recursive.sh b/tests/ls/recursive.sh
new file mode 100755
index 0000000..16554a8
--- /dev/null
+++ b/tests/ls/recursive.sh
@@ -0,0 +1,62 @@
+#!/bin/sh
+# 4.1.1 and 4.1.2 had a bug whereby some recursive listings
+# didn't include a blank line between per-directory groups of files.
+
+# Copyright (C) 2001-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ ls
+
+mkdir x y a b c a/1 a/2 a/3 || framework_failure_
+touch f a/1/I a/1/II || framework_failure_
+
+
+# This first example is from Andreas Schwab's bug report.
+ls -R1 a b c > out || fail=1
+cat <<EOF > exp
+a:
+1
+2
+3
+
+a/1:
+I
+II
+
+a/2:
+
+a/3:
+
+b:
+
+c:
+EOF
+
+compare exp out || fail=1
+
+rm -rf out exp
+ls -R1 x y f > out || fail=1
+cat <<EOF > exp
+f
+
+x:
+
+y:
+EOF
+
+compare exp out || fail=1
+
+Exit $fail
diff --git a/tests/ls/removed-directory.sh b/tests/ls/removed-directory.sh
new file mode 100755
index 0000000..692d05d
--- /dev/null
+++ b/tests/ls/removed-directory.sh
@@ -0,0 +1,38 @@
+#!/bin/sh
+# If ls is asked to list a removed directory (e.g., the parent process's
+# current working directory has been removed by another process), it
+# should not emit an error message merely because the directory is removed.
+
+# Copyright (C) 2020-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ ls
+
+cwd=$(pwd)
+mkdir d || framework_failure_
+cd d || framework_failure_
+rmdir ../d || skip_ "can't remove working directory on this platform"
+
+# On NFS, 'ls' would run into the error "Stale file handle".
+test -d . || skip_ "can't examine removed working directory on this platform"
+
+ls >"$cwd"/out 2>"$cwd"/err || fail=1
+cd "$cwd" || framework_failure_
+
+compare /dev/null out || fail=1
+compare /dev/null err || fail=1
+
+Exit $fail
diff --git a/tests/ls/root-rel-symlink-color.sh b/tests/ls/root-rel-symlink-color.sh
new file mode 100755
index 0000000..d8663e4
--- /dev/null
+++ b/tests/ls/root-rel-symlink-color.sh
@@ -0,0 +1,51 @@
+#!/bin/sh
+# Exercise the 8.17 ls bug with coloring relative-named symlinks in "/".
+
+# Copyright (C) 2012-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ ls test
+
+symlink_to_rel=
+for i in /*; do
+ # Skip non-symlinks:
+ env test -h "$i" || continue
+
+ # Skip dangling symlinks:
+ env test -e "$i" || continue
+
+ # Skip any symlink-to-absolute-name:
+ case $(readlink "$i") in /*) continue ;; esac
+
+ symlink_to_rel=$i
+ break
+done
+
+test -z "$symlink_to_rel" \
+ && skip_ no relative symlink in /
+
+e='\33'
+color_code='01;36'
+c_pre="$e[0m$e[${color_code}m"
+c_post="$e[0m"
+printf "$c_pre$symlink_to_rel$c_post\n" > exp || framework_failure_
+
+env TERM=xterm LS_COLORS="ln=$color_code:or=1;31;42" \
+ ls -d --color=always "$symlink_to_rel" > out || fail=1
+
+compare exp out || fail=1
+
+Exit $fail
diff --git a/tests/ls/rt-1.sh b/tests/ls/rt-1.sh
new file mode 100755
index 0000000..4a8b948
--- /dev/null
+++ b/tests/ls/rt-1.sh
@@ -0,0 +1,46 @@
+#!/bin/sh
+# Make sure name is used as secondary key when sorting on mtime or ctime.
+
+# Copyright (C) 1998-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ ls touch
+
+date=1998-01-15
+
+touch -d "$date" c || framework_failure_
+touch -d "$date" a || framework_failure_
+touch -d "$date" b || framework_failure_
+
+
+ls -1t a b c > out || fail=1
+cat <<EOF > exp
+a
+b
+c
+EOF
+compare exp out || fail=1
+
+rm -rf out exp
+ls -1rt a b c > out || fail=1
+cat <<EOF > exp
+c
+b
+a
+EOF
+compare exp out || fail=1
+
+Exit $fail
diff --git a/tests/ls/selinux-segfault.sh b/tests/ls/selinux-segfault.sh
new file mode 100755
index 0000000..4e0d551
--- /dev/null
+++ b/tests/ls/selinux-segfault.sh
@@ -0,0 +1,33 @@
+#!/bin/sh
+# Ensure we don't segfault in selinux handling
+
+# Copyright (C) 2008-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ ls
+
+# ls -l /proc/sys would segfault when built against libselinux1 2.0.15-2+b1
+f=/proc/sys
+test -r $f || f=.
+ls -l $f > out || fail=1
+
+# ls <= 8.32 would segfault when printing
+# the security context of broken symlink targets
+mkdir sedir || framework_failure_
+ln -sf missing sedir/broken || framework_failure_
+returns_ 1 ls -L -R -Z -m sedir > out || fail=1
+
+Exit $fail
diff --git a/tests/ls/slink-acl.sh b/tests/ls/slink-acl.sh
new file mode 100755
index 0000000..ab9fb8f
--- /dev/null
+++ b/tests/ls/slink-acl.sh
@@ -0,0 +1,33 @@
+#!/bin/sh
+# verify that ls -lL works when applied to a symlink to an ACL'd file
+
+# Copyright (C) 2011-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ ls
+
+require_setfacl_
+
+touch k || framework_failure_
+setfacl -m user::r-- k || framework_failure_
+ln -s k s || framework_failure_
+
+set _ $(ls -Log s); shift; link=$1
+set _ $(ls -og k); shift; reg=$1
+
+test "$link" = "$reg" || fail=1
+
+Exit $fail
diff --git a/tests/ls/sort-width-option.sh b/tests/ls/sort-width-option.sh
new file mode 100755
index 0000000..bffd2e9
--- /dev/null
+++ b/tests/ls/sort-width-option.sh
@@ -0,0 +1,41 @@
+#!/bin/sh
+# Exercise the --sort=width option.
+
+# Copyright (C) 2021-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ ls
+
+mkdir subdir || framework_failure_
+touch subdir/aaaaa || framework_failure_
+touch subdir/bbb || framework_failure_
+touch subdir/cccc || framework_failure_
+touch subdir/d || framework_failure_
+touch subdir/zz || framework_failure_
+
+
+ls --sort=width subdir > out || fail=1
+cat <<\EOF > exp || framework_failure_
+d
+zz
+bbb
+cccc
+aaaaa
+EOF
+
+compare exp out || fail=1
+
+Exit $fail
diff --git a/tests/ls/stat-dtype.sh b/tests/ls/stat-dtype.sh
new file mode 100755
index 0000000..794fcef
--- /dev/null
+++ b/tests/ls/stat-dtype.sh
@@ -0,0 +1,60 @@
+#!/bin/sh
+# Ensure that ls --file-type does not call stat unnecessarily.
+# Also check for the dtype-related (and fs-type dependent) bug
+# in coreutils-6.0 that made ls -CF columns misaligned.
+
+# Copyright (C) 2006-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+# The trick is to create an un-stat'able symlink and to see if ls
+# can report its type nonetheless, using dirent.d_type.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ ls
+
+# Skip this test unless "." is on a file system with useful d_type info.
+# FIXME: This uses "ls -p" to decide whether to test "ls" with other options,
+# but if ls's d_type code is buggy then "ls -p" might be buggy too.
+mkdir -p c/d || framework_failure_
+chmod a-x c || framework_failure_
+if test "X$(ls -p c 2>&1)" != Xd/; then
+ skip_ "'.' is not on a suitable file system for this test"
+fi
+
+mkdir d || framework_failure_
+ln -s / d/s || framework_failure_
+chmod 600 d || framework_failure_
+
+mkdir -p e/a2345 e/b || framework_failure_
+chmod 600 e || framework_failure_
+
+
+ls --file-type d > out || fail=1
+cat <<\EOF > exp || framework_failure_
+s@
+EOF
+
+compare exp out || fail=1
+
+# Check for the ls -CF misaligned-columns bug:
+ls -CF e > out || fail=1
+
+# coreutils-6.0 would print two spaces after the first slash,
+# rather than the appropriate TAB.
+printf 'a2345/\tb/\n' > exp || framework_failure_
+
+compare exp out || fail=1
+
+Exit $fail
diff --git a/tests/ls/stat-failed.sh b/tests/ls/stat-failed.sh
new file mode 100755
index 0000000..642ac4a
--- /dev/null
+++ b/tests/ls/stat-failed.sh
@@ -0,0 +1,57 @@
+#!/bin/sh
+# Verify that ls works properly when it fails to stat a file that is
+# not mentioned on the command line.
+
+# Copyright (C) 2006-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ ls
+skip_if_root_
+
+LS_MINOR_PROBLEM=1
+
+mkdir d || framework_failure_
+ln -s / d/s || framework_failure_
+chmod 600 d || framework_failure_
+
+
+returns_ 1 ls -Log d > out || fail=1
+
+# Linux 2.6.32 client with Isilon OneFS always returns d_type==DT_DIR ('d')
+# Newer Linux 3.10.0 returns the more correct DT_UNKNOWN ('?')
+grep '^[l?]?' out || skip_ 'unrecognized d_type returned'
+
+cat <<\EOF > exp || framework_failure_
+total 0
+?????????? ? ? ? s
+EOF
+
+sed 's/^l/?/' out | compare exp - || fail=1
+
+# Ensure that the offsets in --dired output are accurate.
+rm -f out exp
+returns_ $LS_MINOR_PROBLEM ls --dired -l d > out || fail=1
+
+cat <<\EOF > exp || framework_failure_
+ total 0
+ ?????????? ? ? ? ? ? s
+//DIRED// 44 45
+//DIRED-OPTIONS// --quoting-style=literal
+EOF
+
+sed 's/^ l/ ?/' out | compare exp - || fail=1
+
+Exit $fail
diff --git a/tests/ls/stat-free-color.sh b/tests/ls/stat-free-color.sh
new file mode 100755
index 0000000..b02c06b
--- /dev/null
+++ b/tests/ls/stat-free-color.sh
@@ -0,0 +1,89 @@
+#!/bin/sh
+# Show that --color need not use stat, as long as we have d_type support.
+
+# Copyright (C) 2011-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ ls
+require_strace_ stat
+require_dirent_d_type_
+
+stats='stat'
+# List of other _file name_ stat functions to increase coverage.
+other_stats='statx lstat stat64 lstat64 newfstatat fstatat64'
+for stat in $other_stats; do
+ strace -qe "$stat" true > /dev/null 2>&1 &&
+ stats="$stats,$stat"
+done
+
+# Disable enough features via LS_COLORS so that ls --color
+# can do its job without calling stat (other than the obligatory
+# one-call-per-command-line argument).
+cat <<EOF > color-without-stat || framework_failure_
+RESET 0
+DIR 01;34
+LINK 01;36
+FIFO 40;33
+SOCK 01;35
+DOOR 01;35
+BLK 40;33;01
+CHR 40;33;01
+ORPHAN 00
+SETUID 00
+SETGID 00
+CAPABILITY 00
+STICKY_OTHER_WRITABLE 00
+OTHER_WRITABLE 00
+STICKY 00
+EXEC 00
+MULTIHARDLINK 00
+EOF
+eval $(dircolors -b color-without-stat)
+
+# The system may perform additional stat-like calls before main.
+# Furthermore, underlying library functions may also implicitly
+# add an extra stat call, e.g. opendir since glibc-2.21-360-g46f894d.
+# Finally, ls(1) makes a stat call for stdout, but only in the case
+# when there is something to output.
+# To get the comparison right, first get a baseline count for running
+# 'ls -a' with one empty directory argument. Then, compare that with
+# the invocation under test.
+mkdir d || framework_failure_
+
+count_stats() { grep -vE '\+\+\+|ENOSYS|NOTSUP' "$1" | wc -l; }
+strace -q -o log1 -e $stats ls -a --color=always d || fail=1
+n_stat1=$(count_stats log1) || framework_failure_
+
+test $n_stat1 = 0 \
+ && skip_ 'No stat calls recognized on this platform'
+
+# Populate the test directory.
+mkdir d/subdir \
+ && touch d/regf \
+ && ln d/regf d/hlink \
+ && ln -s regf d/slink \
+ && ln -s nowhere d/dangle \
+ || framework_failure_
+
+# Invocation under test.
+strace -q -o log2 -e $stats ls --color=always d || fail=1
+n_stat2=$(count_stats log2) || framework_failure_
+
+# Expect the same number of stat calls.
+test $n_stat1 = $n_stat2 \
+ || { fail=1; head -n30 log*; }
+
+Exit $fail
diff --git a/tests/ls/stat-free-symlinks.sh b/tests/ls/stat-free-symlinks.sh
new file mode 100755
index 0000000..27f3414
--- /dev/null
+++ b/tests/ls/stat-free-symlinks.sh
@@ -0,0 +1,76 @@
+#!/bin/sh
+# ensure that ls does not stat a symlink in an unusual case
+
+# Copyright (C) 2007-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ ls
+require_strace_ stat
+
+stats='stat'
+# List of other _file name_ stat functions to increase coverage.
+other_stats='statx lstat stat64 lstat64 newfstatat fstatat64'
+for stat in $other_stats; do
+ strace -qe "$stat" true > /dev/null 2>&1 &&
+ stats="$stats,$stat"
+done
+
+# The system may perform additional stat-like calls before main.
+# Furthermore, underlying library functions may also implicitly
+# add an extra stat call, e.g. opendir since glibc-2.21-360-g46f894d.
+# To avoid counting those, first get a baseline count for running
+# ls with one empty directory argument. Then, compare that with the
+# invocation under test.
+count_stats() { grep -vE '\+\+\+|ENOSYS|NOTSUP' "$1" | wc -l; }
+mkdir d || framework_failure_
+strace -q -o log1 -e $stats ls -F --color=always d || fail=1
+n_stat1=$(count_stats log1) || framework_failure_
+
+test $n_stat1 = 0 \
+ && skip_ 'No stat calls recognized on this platform'
+
+
+touch x || framework_failure_
+chmod a+x x || framework_failure_
+ln -s x link-to-x || framework_failure_
+
+
+# ls from coreutils 6.9 would unnecessarily stat a symlink in an unusual case:
+# When not coloring orphan and missing entries, and without ln=target,
+# ensure that ls -F (or -d, or -l: i.e., when not dereferencing)
+# does not stat a symlink to directory, and does still color that
+# symlink and an executable file properly.
+
+LS_COLORS='or=0:mi=0:ex=01;32:ln=01;35' \
+ strace -qe $stats -o log2 ls -F --color=always x link-to-x > out.tmp || fail=1
+n_stat2=$(count_stats log2) || framework_failure_
+
+# Expect one more stat call,
+# which failed with coreutils 6.9 and earlier, which had 2.
+test $n_stat1 = $(($n_stat2 - 1)) \
+ || { fail=1; head -n30 log*; }
+
+# Check that output is colored, as requested, too.
+{
+ printf '\033[0m\033[01;35mlink-to-x\033[0m@\n'
+ printf '\033[01;32mx\033[0m*\n'
+} > exp || fail=1
+# Elide info messages strace can send to stdout of the form:
+# [ Process PID=1234 runs in 32 bit mode. ]
+sed '/Process PID=/d' out.tmp > out
+compare exp out || fail=1
+
+Exit $fail
diff --git a/tests/ls/stat-vs-dirent.sh b/tests/ls/stat-vs-dirent.sh
new file mode 100755
index 0000000..b29889c
--- /dev/null
+++ b/tests/ls/stat-vs-dirent.sh
@@ -0,0 +1,60 @@
+#!/bin/sh
+# Ensure that d_ino (from ls -di) and st_ino (from stat --format=%i) match.
+
+# Copyright (C) 2006-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ ls
+
+
+root_dev_ino=$(stat --format=%d-%i /)
+t=$(pwd)
+while :; do
+ if ls -i1 "$t" > tmp; then
+ # Extract the inode number from the first line of output from ls -i1.
+ # This value comes from dirent.d_ino, on systems with d_ino support.
+ d_ino=$(sed -n '1s/^ *\([0-9][0-9]*\) .*/\1/p;q' tmp)
+
+ # Extract the name of the corresponding directory entry.
+ file=$(sed -n '1s/^ *[0-9][0-9]* //p;q' tmp)
+
+ # Get its inode number (stat.st_ino) via stat(1)'s call to lstat.
+ st_ino=$(stat --format=%i "$t/$file") ||
+ skip_ "error stating: $t/$file" # removed or newlines in name etc.
+
+ # Make sure that they are the same.
+ # We know from experience that there may be mismatches on some
+ # buggy file systems, at mount points.
+ # Note that when a directory contains only entries whose names
+ # start with ".", d_ino and file will both be empty. In that case,
+ # skip the test.
+ if test -n "$d_ino" && test "$d_ino" != "$st_ino"; then
+ echo "$0: test failed: $t/$file: d_ino($d_ino) != st_ino($st_ino)
+ This may indicate a flaw in your kernel or file system implementation.
+ The flaw isn't serious for coreutils, but it might break other tools,
+ so you should report it to your operating system vendor." 1>&2
+
+ fail=1
+ break
+ fi
+ fi
+
+ t=$(cd "$t/.."; pwd)
+ dev_ino=$(stat --format=%d-%i "$t")
+ test $dev_ino = $root_dev_ino && break
+done
+
+Exit $fail
diff --git a/tests/ls/symlink-loop.sh b/tests/ls/symlink-loop.sh
new file mode 100755
index 0000000..0e0b0bf
--- /dev/null
+++ b/tests/ls/symlink-loop.sh
@@ -0,0 +1,35 @@
+#!/bin/sh
+# Exercise ls symlink ELOOP handling
+
+# Copyright (C) 2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ ls
+
+ln -s loop loop || framework_failure_
+cat loop >/dev/null 2>&1 && skip_ 'symlink loops not detected'
+
+# With coreutils <= 9.3 we would dereference symlinks on the command line
+# and thus fail to display a symlink that could not be traversed.
+ls loop || fail=1
+ls -l loop || fail=1
+ls -l --color=always loop || fail=1
+
+# Ensure these still fail
+returns_ 2 ls -H loop || fail=1
+returns_ 2 ls -L loop || fail=1
+
+Exit $fail
diff --git a/tests/ls/symlink-quote.sh b/tests/ls/symlink-quote.sh
new file mode 100755
index 0000000..ba45de5
--- /dev/null
+++ b/tests/ls/symlink-quote.sh
@@ -0,0 +1,30 @@
+#!/bin/sh
+# Ensure symlinks are quoted appropriately
+
+# Copyright (C) 2017-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ ls
+
+ln -s 'needs quoting' symlink || framework_failure_
+
+ls -l --quoting-style='shell-escape' symlink >out || fail=1
+
+# Coreutils v8.26 and 8.27 failed to quote the target name
+grep "symlink -> 'needs quoting'\$" out >/dev/null ||
+ { cat out; fail=1; }
+
+Exit $fail
diff --git a/tests/ls/symlink-slash.sh b/tests/ls/symlink-slash.sh
new file mode 100755
index 0000000..f62e44d
--- /dev/null
+++ b/tests/ls/symlink-slash.sh
@@ -0,0 +1,30 @@
+#!/bin/sh
+# Do dereference a symlink arg if its name is written with a trailing slash.
+
+# Copyright (C) 1999-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ ls
+
+mkdir dir || framework_failure_
+ln -s dir symlink || framework_failure_
+
+set $(ls -l symlink/)
+
+# Prior to fileutils-4.0k, the following would have output '... symlink -> dir'.
+test "$*" = 'total 0' && : || fail=1
+
+Exit $fail
diff --git a/tests/ls/time-style-diag.sh b/tests/ls/time-style-diag.sh
new file mode 100755
index 0000000..af53ba3
--- /dev/null
+++ b/tests/ls/time-style-diag.sh
@@ -0,0 +1,38 @@
+#!/bin/sh
+# Ensure that an invalid --time-style=ARG is diagnosed the way we want.
+
+# Copyright (C) 2011-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ ls
+
+returns_ 2 ls -l --time-style=XX > out 2> err || fail=1
+
+cat <<\EOF > exp || framework_failure_
+ls: invalid argument 'XX' for 'time style'
+Valid arguments are:
+ - [posix-]full-iso
+ - [posix-]long-iso
+ - [posix-]iso
+ - [posix-]locale
+ - +FORMAT (e.g., +%H:%M) for a 'date'-style format
+Try 'ls --help' for more information.
+EOF
+
+compare exp err || fail=1
+compare /dev/null out || fail=1
+
+Exit $fail
diff --git a/tests/ls/w-option.sh b/tests/ls/w-option.sh
new file mode 100755
index 0000000..555e98c
--- /dev/null
+++ b/tests/ls/w-option.sh
@@ -0,0 +1,48 @@
+#!/bin/sh
+# exercise the -w option
+
+# Copyright (C) 2015-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ ls
+getlimits_
+
+touch a b || framework_failure_
+chmod a+x a || framework_failure_
+
+# Negative values disallowed
+returns_ 2 ls -w-1 || fail=1
+
+# Verify octal parsing (especially since 0 is allowed)
+returns_ 2 ls -w08 || fail=1
+
+# Overflowed values are capped at SIZE_MAX
+ls -w$SIZE_OFLOW || fail=1
+
+# After coreutils 8.24 -w0 means no limit
+# and delimiting with spaces
+ls -w0 -x -T1 a b > out || fail=1
+printf '%s\n' 'a b' > exp || framework_failure_
+compare exp out || fail=1
+
+# Ensure that 0 line length doesn't cause division by zero
+TERM=xterm ls -w0 -x --color=always || fail=1
+
+# coreutils <= 8.24 could display 1 column too few
+ls -w4 -x -T0 a b > out || fail=1
+compare exp out || fail=1
+
+Exit $fail
diff --git a/tests/ls/x-option.sh b/tests/ls/x-option.sh
new file mode 100755
index 0000000..30c2e7c
--- /dev/null
+++ b/tests/ls/x-option.sh
@@ -0,0 +1,37 @@
+#!/bin/sh
+# Exercise the -x option.
+
+# Copyright (C) 2007-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ ls
+
+mkdir subdir || framework_failure_
+touch subdir/b || framework_failure_
+touch subdir/a || framework_failure_
+
+
+# Coreutils 6.8 and 6.9 would output this in the wrong order.
+ls -x subdir > out || fail=1
+ls -rx subdir >> out || fail=1
+cat <<\EOF > exp || framework_failure_
+a b
+b a
+EOF
+
+compare exp out || fail=1
+
+Exit $fail
diff --git a/tests/ls/zero-option.sh b/tests/ls/zero-option.sh
new file mode 100755
index 0000000..d3c9f0d
--- /dev/null
+++ b/tests/ls/zero-option.sh
@@ -0,0 +1,41 @@
+#!/bin/sh
+# Verify behavior of ls --zero.
+
+# Copyright 2021-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ ls
+
+mkdir dir && touch dir/a dir/b dir/cc || framework_failure_
+
+allowed_options='-l' # explicit -l with --zero is allowed
+LC_ALL=C ls $allowed_options --zero dir >out || fail=1
+grep '^total' out || fail=1 # Ensure -l honored
+
+disallowed_options='-l --dired' # dired only enabled with -l
+returns_ 2 ls $disallowed_options --zero dir || fail=1
+
+disabled_options='--color=always -x -m -C -Q -q'
+LC_ALL=C ls $disabled_options --zero dir >out || fail=1
+tr '\n' '\0' <<EOF >exp
+a
+b
+cc
+EOF
+
+compare exp out || fail=1
+
+Exit $fail
diff --git a/tests/misc/arch.sh b/tests/misc/arch.sh
new file mode 100755
index 0000000..ec240d1
--- /dev/null
+++ b/tests/misc/arch.sh
@@ -0,0 +1,27 @@
+#!/bin/sh
+# Ensure that arch output is equal to uname -m
+
+# Copyright (C) 2007-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ arch
+
+arch > out || fail=1
+uname -m > exp || fail=1
+
+compare exp out || fail=1
+
+Exit $fail
diff --git a/tests/misc/base64.pl b/tests/misc/base64.pl
new file mode 100755
index 0000000..63e6c6b
--- /dev/null
+++ b/tests/misc/base64.pl
@@ -0,0 +1,214 @@
+#!/usr/bin/perl
+# Exercise base{32,64}.
+
+# Copyright (C) 2006-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+use strict;
+
+(my $program_name = $0) =~ s|.*/||;
+
+# Turn off localization of executable's output.
+@ENV{qw(LANGUAGE LANG LC_ALL)} = ('C') x 3;
+
+# Return the encoding of a string of N 'a's.
+sub enc64($)
+{
+ my ($n) = @_;
+ my %remainder = ( 0 => '', 1 => 'YQ==', 2 => 'YWE=' );
+ return 'YWFh' x ($n / 3) . $remainder{$n % 3};
+}
+
+sub enc32($)
+{
+ my ($n) = @_;
+ my %remainder = ( 0 => '', 1 => 'ME======', 2 => 'MFQQ====',
+ 3 => 'MFQWC===', 4 => 'MFQWCYI=');
+ return 'MFQWCYLB' x ($n / 5) . $remainder{$n % 5};
+}
+
+# Function reference to appropriate encoder
+my $enc;
+
+# An encoded string of length 4KB, using 3K "a"s.
+my $a3k;
+my @a3k_nl;
+
+# Return a copy of S, with newlines inserted every WIDTH bytes.
+# Ensure that the result (if not the empty string) is newline-terminated.
+sub wrap($$)
+{
+ my ($s, $width) = @_;
+ $s =~ s/(.{$width})/$1\n/g;
+ substr ($s, -1, 1) ne "\n"
+ and $s .= "\n";
+ return $s;
+}
+
+my @Tests;
+
+sub gen_tests($)
+{
+ my ($prog) = @_;
+ my $try_help = "Try '$prog --help' for more information.\n";
+ @Tests=
+ (
+ ['empty', {IN=>''}, {OUT=>""}],
+ ['inout1', {IN=>'a'x1}, {OUT=>&$enc(1)."\n"}],
+ ['inout2', {IN=>'a'x2}, {OUT=>&$enc(2)."\n"}],
+ ['inout3', {IN=>'a'x3}, {OUT=>&$enc(3)."\n"}],
+ ['inout4', {IN=>'a'x4}, {OUT=>&$enc(4)."\n"}],
+ ['inout5', {IN=>'a'x5}, {OUT=>&$enc(5)."\n"}],
+ ['wrap', '--wrap 0', {IN=>'a'}, {OUT=>&$enc(1)}],
+ ['wrap-zero', '--wrap 08', {IN=>'a'}, {OUT=>&$enc(1)."\n"}],
+ ['wrap5-39', '--wrap=5', {IN=>'a' x 39}, {OUT=>wrap &$enc(39),5}],
+ ['wrap5-40', '--wrap=5', {IN=>'a' x 40}, {OUT=>wrap &$enc(40),5}],
+ ['wrap5-41', '--wrap=5', {IN=>'a' x 41}, {OUT=>wrap &$enc(41),5}],
+ ['wrap5-42', '--wrap=5', {IN=>'a' x 42}, {OUT=>wrap &$enc(42),5}],
+ ['wrap5-43', '--wrap=5', {IN=>'a' x 43}, {OUT=>wrap &$enc(43),5}],
+ ['wrap5-44', '--wrap=5', {IN=>'a' x 44}, {OUT=>wrap &$enc(44),5}],
+ ['wrap5-45', '--wrap=5', {IN=>'a' x 45}, {OUT=>wrap &$enc(45),5}],
+ ['wrap5-46', '--wrap=5', {IN=>'a' x 46}, {OUT=>wrap &$enc(46),5}],
+
+ ['wrap-bad-1', '-w0x0', {IN=>''}, {OUT=>""},
+ {ERR_SUBST => 's/base..:/base..:/'},
+ {ERR => "base..: invalid wrap size: '0x0'\n"}, {EXIT => 1}],
+ ['wrap-bad-2', '-w1k', {IN=>''}, {OUT=>""},
+ {ERR_SUBST => 's/base..:/base..:/'},
+ {ERR => "base..: invalid wrap size: '1k'\n"}, {EXIT => 1}],
+ ['wrap-bad-3', '-w-1', {IN=>''}, {OUT=>""},
+ {ERR_SUBST => 's/base..:/base..:/'},
+ {ERR => "base..: invalid wrap size: '-1'\n"}, {EXIT => 1}],
+
+ ['buf-1', '--decode', {IN=>&$enc(1)}, {OUT=>'a' x 1}],
+ ['buf-2', '--decode', {IN=>&$enc(2)}, {OUT=>'a' x 2}],
+ ['buf-3', '--decode', {IN=>&$enc(3)}, {OUT=>'a' x 3}],
+ ['buf-4', '--decode', {IN=>&$enc(4)}, {OUT=>'a' x 4}],
+ # 4KB worth of input.
+ ['buf-4k0', '--decode', {IN=>&$enc(3072+0)}, {OUT=>'a' x (3072+0)}],
+ ['buf-4k1', '--decode', {IN=>&$enc(3072+1)}, {OUT=>'a' x (3072+1)}],
+ ['buf-4k2', '--decode', {IN=>&$enc(3072+2)}, {OUT=>'a' x (3072+2)}],
+ ['buf-4k3', '--decode', {IN=>&$enc(3072+3)}, {OUT=>'a' x (3072+3)}],
+ ['buf-4km1','--decode', {IN=>&$enc(3072-1)}, {OUT=>'a' x (3072-1)}],
+ ['buf-4km2','--decode', {IN=>&$enc(3072-2)}, {OUT=>'a' x (3072-2)}],
+ ['buf-4km3','--decode', {IN=>&$enc(3072-3)}, {OUT=>'a' x (3072-3)}],
+ ['buf-4km4','--decode', {IN=>&$enc(3072-4)}, {OUT=>'a' x (3072-4)}],
+
+ # Exercise the case in which the final base-64 byte is
+ # in a buffer all by itself.
+ ['b4k-1', '--decode', {IN=>$a3k_nl[1]}, {OUT=>'a' x (3072+0)}],
+ ['b4k-2', '--decode', {IN=>$a3k_nl[2]}, {OUT=>'a' x (3072+0)}],
+ ['b4k-3', '--decode', {IN=>$a3k_nl[3]}, {OUT=>'a' x (3072+0)}],
+
+ ['ext-op1', 'a b', {IN=>''}, {EXIT=>1},
+ {ERR => "$prog: extra operand 'b'\n" . $try_help}],
+ # Again, with more option arguments
+ ['ext-op2', '-di --wrap=40 a b', {IN=>''}, {EXIT=>1},
+ {ERR => "$prog: extra operand 'b'\n" . $try_help}],
+ );
+
+ if ($prog eq "base64")
+ {
+ push @Tests, (
+ ['baddecode', '--decode', {IN=>'a'}, {OUT=>""},
+ {ERR_SUBST => 's/.*: invalid input//'}, {ERR => "\n"}, {EXIT => 1}],
+ ['baddecode2', '--decode', {IN=>'ab'}, {OUT=>"i"},
+ {ERR_SUBST => 's/.*: invalid input//'}, {ERR => "\n"}, {EXIT => 1}],
+ ['baddecode3', '--decode', {IN=>'Zzz'}, {OUT=>"g<"},
+ {ERR_SUBST => 's/.*: invalid input//'}, {ERR => "\n"}, {EXIT => 1}],
+ ['baddecode4', '--decode', {IN=>'Zz='}, {OUT=>"g"},
+ {ERR_SUBST => 's/.*: invalid input//'}, {ERR => "\n"}, {EXIT => 1}],
+ ['baddecode5', '--decode', {IN=>'Z==='}, {OUT=>""},
+ {ERR_SUBST => 's/.*: invalid input//'}, {ERR => "\n"}, {EXIT => 1}]
+ );
+ }
+
+ # For each non-failing test, create a --decode test using the
+ # expected output as input. Also, add tests inserting newlines.
+ my @new;
+ foreach my $t (@Tests)
+ {
+ my $exit_val;
+ my $in;
+ my @out;
+
+ # If the test has a single option of "--decode", then skip it.
+ !ref $t->[1] && $t->[1] eq '--decode'
+ and next;
+
+ foreach my $e (@$t)
+ {
+ ref $e && ref $e eq 'HASH'
+ or next;
+ defined $e->{EXIT}
+ and $exit_val = $e->{EXIT};
+ defined $e->{IN}
+ and $in = $e->{IN};
+ if (defined $e->{OUT})
+ {
+ my $t = $e->{OUT};
+ push @out, $t;
+ my $len = length $t;
+ foreach my $i (0..$len)
+ {
+ my $u = $t;
+ substr ($u, $i, 0) = "\n";
+ push @out, $u;
+ 10 <= $i
+ and last;
+ }
+ }
+ }
+ $exit_val
+ and next;
+
+ my $i = 0;
+ foreach my $o (@out)
+ {
+ push @new, ["d$i-$t->[0]", '--decode', {IN => $o}, {OUT => $in}];
+ ++$i;
+ }
+ }
+ push @Tests, @new;
+}
+
+my $save_temps = $ENV{DEBUG};
+my $verbose = $ENV{VERBOSE};
+
+my $fail = 0;
+foreach my $prog (qw(base32 base64))
+ {
+ $enc = $prog eq "base32" ? \&enc32 : \&enc64;
+
+ # Construct an encoded string of length 4KB, using 3K "a"s.
+ $a3k = &$enc(3072);
+ @a3k_nl = ();
+ # A few copies, each with different number of newlines at the start.
+ for my $k (0..3)
+ {
+ (my $t = $a3k) =~ s/^/"\n"x $k/e;
+ push @a3k_nl, $t;
+ }
+
+ gen_tests($prog);
+
+ $fail = run_tests ($program_name, $prog, \@Tests, $save_temps, $verbose);
+ if ($fail != 0)
+ {
+ last;
+ }
+ }
+
+exit $fail;
diff --git a/tests/misc/basename.pl b/tests/misc/basename.pl
new file mode 100755
index 0000000..4f76a21
--- /dev/null
+++ b/tests/misc/basename.pl
@@ -0,0 +1,92 @@
+#!/usr/bin/perl
+# Test basename.
+# Copyright (C) 2006-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+use strict;
+use File::stat;
+
+(my $program_name = $0) =~ s|.*/||;
+
+# Turn off localization of executable's output.
+@ENV{qw(LANGUAGE LANG LC_ALL)} = ('C') x 3;
+
+my $stat_single = stat('/');
+my $stat_double = stat('//');
+my $double_slash = ($stat_single->dev == $stat_double->dev
+ && $stat_single->ino == $stat_double->ino) ? '/' : '//';
+
+my $prog = 'basename';
+
+my @Tests =
+ (
+ ['fail-1', {ERR => "$prog: missing operand\n"
+ . "Try '$prog --help' for more information.\n"}, {EXIT => '1'}],
+ ['fail-2', qw(a b c), {ERR => "$prog: extra operand 'c'\n"
+ . "Try '$prog --help' for more information.\n"}, {EXIT => '1'}],
+
+ ['a', qw(d/f), {OUT => 'f'}],
+ ['b', qw(/d/f), {OUT => 'f'}],
+ ['c', qw(d/f/), {OUT => 'f'}],
+ ['d', qw(d/f//), {OUT => 'f'}],
+ ['e', qw(f), {OUT => 'f'}],
+ ['f', qw(/), {OUT => '/'}],
+ ['g', qw(//), {OUT => "$double_slash"}],
+ ['h', qw(///), {OUT => '/'}],
+ ['i', qw(///a///), {OUT => 'a'}],
+ ['j', qw(''), {OUT => ''}],
+ ['k', qw(aa a), {OUT => 'a'}],
+ ['l', qw(-a a b), {OUT => "a\nb"}],
+ ['m', qw(-s a aa ba ab), {OUT => "a\nb\nab"}],
+ ['n', qw(a-a -a), {OUT => 'a'}],
+ ['1', qw(f.s .s), {OUT => 'f'}],
+ ['2', qw(fs s), {OUT => 'f'}],
+ ['3', qw(fs fs), {OUT => 'fs'}],
+ ['4', qw(fs/ s), {OUT => 'f'}],
+ ['5', qw(dir/file.suf .suf), {OUT => 'file'}],
+ ['6', qw(// /), {OUT => "$double_slash"}],
+ ['7', qw(// //), {OUT => "$double_slash"}],
+ ['8', qw(fs x), {OUT => 'fs'}],
+ ['9', qw(fs ''), {OUT => 'fs'}],
+ ['10', qw(fs/ s/), {OUT => 'fs'}],
+
+ # Exercise -z option.
+ ['z0', qw(-z a), {OUT => "a\0"}],
+ ['z1', qw(--zero a), {OUT => "a\0"}],
+ ['z2', qw(-za a b), {OUT => "a\0b\0"}],
+ ['z3', qw(-z ba a), {OUT => "b\0"}],
+ ['z4', qw(-z -s a ba), {OUT => "b\0"}],
+ );
+
+# Append a newline to end of each expected 'OUT' string.
+# Skip -z tests, i.e., those whose 'OUT' string has a trailing '\0'.
+my $t;
+foreach $t (@Tests)
+ {
+ my $arg1 = $t->[1];
+ my $e;
+ foreach $e (@$t)
+ {
+ $e->{OUT} = "$e->{OUT}\n"
+ if ref $e eq 'HASH' and exists $e->{OUT}
+ and not $e->{OUT} =~ /\0$/;
+ }
+ }
+
+my $save_temps = $ENV{SAVE_TEMPS};
+my $verbose = $ENV{VERBOSE};
+
+my $fail = run_tests ($program_name, $prog, \@Tests, $save_temps, $verbose);
+exit $fail;
diff --git a/tests/misc/basenc.pl b/tests/misc/basenc.pl
new file mode 100755
index 0000000..de20d2d
--- /dev/null
+++ b/tests/misc/basenc.pl
@@ -0,0 +1,292 @@
+#!/usr/bin/perl
+# Exercise basenc.
+
+# Copyright (C) 2006-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+# This test exercises the various encoding (other than base64/32).
+# It also does not test the general options (e.g. --wrap), as that code is
+# shared and tested in base64.
+
+use strict;
+
+(my $program_name = $0) =~ s|.*/||;
+my $prog = 'basenc';
+
+# Turn off localization of executable's output.
+@ENV{qw(LANGUAGE LANG LC_ALL)} = ('C') x 3;
+
+
+my $base64_in = "\x54\x0f\xdc\xf0\x0f\xaf\x4a";
+my $base64_out = "VA/c8A+vSg==";
+my $base64url_out = $base64_out;
+$base64url_out =~ y|+/|-_|;
+my $base64url_out_nl = $base64url_out;
+$base64url_out_nl =~ s/(..)/\1\n/g; # add newline every two characters
+
+
+# Bug 49741:
+# The input is 'abc' in base64, in an 8K buffer (larger than 1024*5,
+# the buffer size which caused the bug).
+my $base64_bug49741_in = "YWJj" x 2000 ;
+my $base64_bug49741_out = "abc" x 2000 ;
+
+
+my $base32_in = "\xfd\xd8\x07\xd1\xa5";
+my $base32_out = "7XMAPUNF";
+my $x = $base32_out;
+$x =~ y|ABCDEFGHIJKLMNOPQRSTUVWXYZ234567|0123456789ABCDEFGHIJKLMNOPQRSTUV|;
+my $base32hex_out = $x;
+
+# base32 with padding and newline
+my $base32_in2 = "\xFF\x00";
+my $base32_out2 = "74AA====";
+$x = $base32_out2;
+$x =~ y|ABCDEFGHIJKLMNOPQRSTUVWXYZ234567|0123456789ABCDEFGHIJKLMNOPQRSTUV|;
+my $base32hex_out2 = $x;
+my $base32hex_out2_nl = $x;
+$base32hex_out2_nl =~ s/(...)/\1\n/g; # Add newline every 3 characters
+
+my $base16_in = "\xfd\xd8\x07\xd1\xa5";
+my $base16_out = "FDD807D1A5";
+
+my $z85_in = "\x86\x4F\xD2\x6F\xB5\x59\xF7\x5B";
+my $z85_out = 'HelloWorld';
+
+my $base2lsbf_ab = "1000011001000110";
+my $base2lsbf_ab_nl = $base2lsbf_ab;
+$base2lsbf_ab_nl =~ s/(...)/\1\n/g; # Add newline every 3 characters
+my $base2msbf_ab = "0110000101100010";
+my $base2msbf_ab_nl = $base2msbf_ab;
+$base2msbf_ab_nl =~ s/(...)/\1\n/g; # Add newline every 3 characters
+
+my $try_help = "Try '$prog --help' for more information.\n";
+
+my @Tests =
+(
+ # These are mainly for higher coverage
+ ['help', '--help', {IN=>''}, {OUT=>""}, {OUT_SUBST=>'s/.*//sm'}],
+
+ # Typical message is " unrecognized option '--foobar'", but on
+ # Open/NetBSD it is " unknown option -- foobar".
+ ['error', '--foobar', {IN=>''}, {OUT=>""}, {EXIT=>1},
+ {ERR=>"$prog: foobar\n" . $try_help },
+ {ERR_SUBST=>"s/(unrecognized|unknown) option [-' ]*foobar[' ]*/foobar/"}],
+
+ ['noenc', '', {IN=>''}, {EXIT=>1},
+ {ERR=>"$prog: missing encoding type\n" . $try_help }],
+
+ ['extra', '--base64 A B', {IN=>''}, {EXIT=>1},
+ {ERR=>"$prog: extra operand 'B'\n" . $try_help}],
+
+
+ ['empty1', '--base64', {IN=>''}, {OUT=>""}],
+ ['empty2', '--base64url', {IN=>''}, {OUT=>""}],
+ ['empty3', '--base32', {IN=>''}, {OUT=>""}],
+ ['empty4', '--base32hex', {IN=>''}, {OUT=>""}],
+ ['empty5', '--base16', {IN=>''}, {OUT=>""}],
+ ['empty6', '--base2msbf', {IN=>''}, {OUT=>""}],
+ ['empty7', '--base2lsbf', {IN=>''}, {OUT=>""}],
+ ['empty8', '--z85', {IN=>''}, {OUT=>""}],
+
+
+
+
+ ['b64_1', '--base64', {IN=>$base64_in}, {OUT=>$base64_out}],
+ ['b64_2', '--base64 -d', {IN=>$base64_out}, {OUT=>$base64_in}],
+ ['b64_3', '--base64 -d -i', {IN=>'&'.$base64_out},{OUT=>$base64_in}],
+
+ ['b64u_1', '--base64url', {IN=>$base64_in}, {OUT=>$base64url_out}],
+ ['b64u_2', '--base64url -d', {IN=>$base64url_out}, {OUT=>$base64_in}],
+ ['b64u_3', '--base64url -di', {IN=>'&'.$base64url_out} , {OUT=>$base64_in}],
+ ['b64u_4', '--base64url -di', {IN=>'/'.$base64url_out.'+'},{OUT=>$base64_in}],
+ ['b64u_5', '--base64url -d', {IN=>$base64url_out_nl}, {OUT=>$base64_in}],
+ ['b64u_6', '--base64url -di', {IN=>$base64url_out_nl}, {OUT=>$base64_in}],
+ # ensure base64url fails to decode base64 input with "+" and "/"
+ ['b64u_7', '--base64url -d', {IN=>$base64_out},
+ {EXIT=>1}, {ERR=>"$prog: invalid input\n"}],
+
+ ['b64_bug49741', '--base64 -d', {IN=>$base64_bug49741_in},
+ {OUT=>$base64_bug49741_out}],
+
+
+
+ ['b32_1', '--base32', {IN=>$base32_in}, {OUT=>$base32_out}],
+ ['b32_2', '--base32 -d', {IN=>$base32_out}, {OUT=>$base32_in}],
+ ['b32_3', '--base32 -d -i', {IN=>'&'.$base32_out},{OUT=>$base32_in}],
+ ['b32_4', '--base32', {IN=>$base32_in2}, {OUT=>$base32_out2}],
+ ['b32_5', '--base32 -d', {IN=>$base32_out2}, {OUT=>$base32_in2}],
+ ['b32_6', '--base32 -d -i', {IN=>$base32_out2}, {OUT=>$base32_in2}],
+
+
+
+ ['b32h_1', '--base32hex', {IN=>$base32_in}, {OUT=>$base32hex_out}],
+ ['b32h_2', '--base32hex -d', {IN=>$base32hex_out}, {OUT=>$base32_in}],
+ ['b32h_3', '--base32hex -d -i', {IN=>'/'.$base32hex_out}, {OUT=>$base32_in}],
+ ['b32h_4', '--base32hex -d -i', {IN=>'W'.$base32hex_out}, {OUT=>$base32_in}],
+ ['b32h_5', '--base32hex -d', {IN=>$base32hex_out.'W'}, , {OUT=>$base32_in},
+ {EXIT=>1}, {ERR=>"$prog: invalid input\n"}],
+ ['b32h_6', '--base32hex -d', {IN=>$base32hex_out.'/'}, {OUT=>$base32_in},
+ {EXIT=>1}, {ERR=>"$prog: invalid input\n"}],
+ ['b32h_7', '--base32hex', {IN=>$base32_in2}, {OUT=>$base32hex_out2}],
+ ['b32h_8', '--base32hex -d', {IN=>$base32hex_out2}, {OUT=>$base32_in2}],
+ ['b32h_9', '--base32hex -di', {IN=>$base32hex_out2}, {OUT=>$base32_in2}],
+ ['b32h_10', '--base32hex -d', {IN=>$base32hex_out2_nl}, {OUT=>$base32_in2}],
+ ['b32h_11', '--base32hex -di', {IN=>$base32hex_out2_nl}, {OUT=>$base32_in2}],
+
+
+
+ ['b16_1', '--base16', {IN=>$base16_in}, {OUT=>$base16_out}],
+ ['b16_2', '--base16 -d', {IN=>$base16_out}, {OUT=>$base16_in}],
+ ['b16_3', '--base16 -d -i', {IN=>'&'. $base16_out}, {OUT=>$base16_in}],
+ ['b16_4', '--base16 -d -i', {IN=>$base16_out.'G'}, {OUT=>$base16_in}],
+ ['b16_5', '--base16 -d', {IN=>'.'}, {EXIT=>1},
+ {ERR=>"$prog: invalid input\n"}],
+ ['b16_6', '--base16 -d', {IN=>'='}, {EXIT=>1},
+ {ERR=>"$prog: invalid input\n"}],
+ ['b16_7', '--base16 -d', {IN=>'G'}, {EXIT=>1},
+ {ERR=>"$prog: invalid input\n"}],
+ ['b16_8', '--base16 -d', {IN=>"AB\nCD"}, {OUT=>"\xAB\xCD"}],
+
+
+
+ ['b2m_1', '--base2m', {IN=>"\xC1"}, {OUT=>"11000001"}],
+ ['b2m_2', '--base2m -d', {IN=>'11000001'}, {OUT=>"\xC1"}],
+ ['b2m_3', '--base2m -d', {IN=>"110\n00001"}, {OUT=>"\xC1"}],
+ ['b2m_4', '--base2m -di', {IN=>"110x00001"}, {OUT=>"\xC1"}],
+ ['b2m_5', '--base2m -d', {IN=>"110x00001"}, {EXIT=>1},
+ {ERR=>"$prog: invalid input\n"}],
+ ['b2m_6', '--base2m -d', {IN=>"11000001x"}, {OUT=>"\xC1"}, {EXIT=>1},
+ {ERR=>"$prog: invalid input\n"}],
+ ['b2m_7', '--base2m -d', {IN=>"1"}, {EXIT=>1},
+ {ERR=>"$prog: invalid input\n"}],
+ ['b2m_8', '--base2m -d', {IN=>"1000100"}, {EXIT=>1},
+ {ERR=>"$prog: invalid input\n"}],
+ ['b2m_9', '--base2m -d', {IN=>"100010000000000"}, {OUT=>"\x88"}, {EXIT=>1},
+ {ERR=>"$prog: invalid input\n"}],
+ ['b2m_10','--base2m', {IN=>"ab"}, {OUT=>$base2msbf_ab}],
+ ['b2m_11','--base2m -d', {IN=>$base2msbf_ab}, {OUT=>"ab"}],
+ ['b2m_12','--base2m -d', {IN=>$base2msbf_ab_nl}, {OUT=>"ab"}],
+
+
+ ['b2l_1', '--base2l', {IN=>"\x83"}, {OUT=>"11000001"}],
+ ['b2l_2', '--base2l -d', {IN=>'11000001'}, {OUT=>"\x83"}],
+ ['b2l_3', '--base2l -d', {IN=>"110\n00001"}, {OUT=>"\x83"}],
+ ['b2l_4', '--base2l -di', {IN=>"110x00001"}, {OUT=>"\x83"}],
+ ['b2l_5', '--base2l -d', {IN=>"110x00001"}, {EXIT=>1},
+ {ERR=>"$prog: invalid input\n"}],
+ ['b2l_6', '--base2l -d', {IN=>"11000001x"}, {OUT=>"\x83"}, {EXIT=>1},
+ {ERR=>"$prog: invalid input\n"}],
+ ['b2l_7', '--base2l -d', {IN=>"1"}, {EXIT=>1},
+ {ERR=>"$prog: invalid input\n"}],
+ ['b2l_8', '--base2l -d', {IN=>"1000100"}, {EXIT=>1},
+ {ERR=>"$prog: invalid input\n"}],
+ ['b2l_9', '--base2l -d', {IN=>"100010000000000"}, {OUT=>"\x11"}, {EXIT=>1},
+ {ERR=>"$prog: invalid input\n"}],
+ ['b2l_10','--base2l', {IN=>"ab"}, {OUT=>$base2lsbf_ab}],
+ ['b2l_11','--base2l -d', {IN=>$base2lsbf_ab}, {OUT=>"ab"}],
+ ['b2l_12','--base2l -d', {IN=>$base2lsbf_ab_nl}, {OUT=>"ab"}],
+
+
+
+
+
+ ['z85_1', '--z85', {IN=>$z85_in}, {OUT=>$z85_out}],
+ ['z85_2', '--z85 -d', {IN=>$z85_out}, {OUT=>$z85_in}],
+ ['z85_3', '--z85 -d -i', {IN=>'~'. $z85_out}, {OUT=>$z85_in}],
+ ['z85_4', '--z85 -d -i', {IN=>' '. $z85_out}, {OUT=>$z85_in}],
+ ['z85_5', '--z85 -d', {IN=>'%j$qP'}, {OUT=>"\xFF\xDD\xBB\x99"}],
+ ['z85_6', '--z85 -d -i', {IN=>'%j~$qP'}, {OUT=>"\xFF\xDD\xBB\x99"}],
+
+ # z85 encoding require input to be multiple of 5 octets
+ ['z85_7', '--z85 -d', {IN=>'hello'}, {OUT=>"5jXu"}],
+ ['z85_8', '--z85 -d', {IN=>'helloX'}, {OUT=>"5jXu"}, {EXIT=>1},
+ {ERR=>"$prog: invalid input\n"}],
+ ['z85_9', '--z85 -d', {IN=>"he\nl\nlo"}, {OUT=>"5jXu"}],
+
+ # Invalid input characters (space ~ ")
+ ['z85_10', '--z85 -d', {IN=>' j$qP'}, {EXIT=>1},
+ {ERR=>"$prog: invalid input\n"}],
+ ['z85_11', '--z85 -d', {IN=>'%j$q~'}, {EXIT=>1},
+ {ERR=>"$prog: invalid input\n"}],
+ ['z85_12', '--z85 -d', {IN=>'%j$"P'}, {EXIT=>1},
+ {ERR=>"$prog: invalid input\n"}],
+
+ # Invalid length (binary input must be a multiple of 4 octets,
+ # z85-encoded input must be a multiple of 5 octets)
+ ['z85_20', '--z85', {IN=>'A'}, {EXIT=>1},
+ {ERR=>"$prog: invalid input (length must be multiple of 4 characters)\n"}],
+ ['z85_21', '--z85', {IN=>'AB'}, {EXIT=>1},
+ {ERR=>"$prog: invalid input (length must be multiple of 4 characters)\n"}],
+ ['z85_22', '--z85', {IN=>'ABC'}, {EXIT=>1},
+ {ERR=>"$prog: invalid input (length must be multiple of 4 characters)\n"}],
+ ['z85_23', '--z85', {IN=>'ABCD'}, {OUT=>'k%^}b'}],
+ ['z85_24', '--z85', {IN=>'ABCDE'}, {EXIT=>1},
+ {ERR=>"$prog: invalid input (length must be multiple of 4 characters)\n"}],
+
+ ['z85_30', '--z85 -d', {IN=>'A'}, {EXIT=>1},
+ {ERR=>"$prog: invalid input\n"}],
+ ['z85_31', '--z85 -d', {IN=>'AB'}, {EXIT=>1},
+ {ERR=>"$prog: invalid input\n"}],
+ ['z85_32', '--z85 -d', {IN=>'ABC'}, {EXIT=>1},
+ {ERR=>"$prog: invalid input\n"}],
+ ['z85_33', '--z85 -d', {IN=>'ABCD'}, {EXIT=>1},
+ {ERR=>"$prog: invalid input\n"}],
+ ['z85_34', '--z85 -d', {IN=>'ABCDE'}, {OUT=>"\x71\x61\x9e\xb6"}],
+ ['z85_35', '--z85 -d', {IN=>'ABCDEF'},{OUT=>"\x71\x61\x9e\xb6"},
+ {EXIT=>1}, {ERR=>"$prog: invalid input\n"}],
+
+ # largest possible value
+ ['z85_40', '--z85', {IN=>"\xFF\xFF\xFF\xFF"},{OUT=>"%nSc0"}],
+ ['z85_41', '--z85 -d', {IN=>"%nSc0"}, {OUT=>"\xFF\xFF\xFF\xFF"}],
+ # Invalid encoded data - will decode to more than 0xFFFFFFFF
+ ['z85_42', '--z85 -d', {IN=>"%nSc1"}, {EXIT=>1},
+ {ERR=>"$prog: invalid input\n"}],
+ ['z85_43', '--z85 -d', {IN=>"%nSd0"}, {EXIT=>1},
+ {ERR=>"$prog: invalid input\n"}],
+ ['z85_44', '--z85 -d', {IN=>"%nTc0"}, {EXIT=>1},
+ {ERR=>"$prog: invalid input\n"}],
+ ['z85_45', '--z85 -d', {IN=>"%oSc0"}, {EXIT=>1},
+ {ERR=>"$prog: invalid input\n"}],
+ ['z85_46', '--z85 -d', {IN=>'$nSc0'}, {EXIT=>1},
+ {ERR=>"$prog: invalid input\n"}],
+ ['z85_47', '--z85 -d', {IN=>'#0000'}, {EXIT=>1},
+ {ERR=>"$prog: invalid input\n"}],
+);
+
+# Prepend the command line argument and append a newline to end
+# of each expected 'OUT' string.
+my $t;
+
+Test:
+foreach $t (@Tests)
+ {
+ foreach my $e (@$t)
+ {
+ ref $e && ref $e eq 'HASH' && defined $e->{OUT_SUBST}
+ and next Test;
+ }
+
+ push @$t, {OUT_SUBST=>'s/\n$//s'};
+ }
+
+
+
+my $save_temps = $ENV{DEBUG};
+my $verbose = $ENV{VERBOSE};
+
+my $fail = run_tests ($program_name, $prog, \@Tests, $save_temps, $verbose);
+
+exit $fail;
diff --git a/tests/misc/close-stdout.sh b/tests/misc/close-stdout.sh
new file mode 100755
index 0000000..4bff9e2
--- /dev/null
+++ b/tests/misc/close-stdout.sh
@@ -0,0 +1,65 @@
+#!/bin/sh
+# Ensure that several programs work fine, even with stdout initially closed.
+# This is effectively a test of closeout.c's close_stdout function.
+
+# Copyright (C) 2004-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ rm
+
+p=$abs_top_builddir
+
+
+# Ensure these exit successfully, even though stdout is closed,
+# because they generate no output.
+touch a
+cp a b >&- || fail=1
+test -f b || fail=1
+chmod o-w . >&- || fail=1
+ln a c >&- || fail=1
+rm c >&- || fail=1
+mkdir d >&- || fail=1
+mv d e >&- || fail=1
+rmdir e >&- || fail=1
+touch e >&- || fail=1
+sleep 0 >&- || fail=1
+"$p/src/true" >&- || fail=1
+"$p/src/printf" '' >&- || fail=1
+
+# If >&- works, ensure these fail, because stdout is closed and they
+# *do* generate output. >&- apparently does not work in HP-UX 11.23.
+# This test is ineffective unless /dev/stdout also works.
+if "$p/src/test" -w /dev/stdout >/dev/null &&
+ "$p/src/test" ! -w /dev/stdout >&-; then
+ returns_ 1 "$p/src/printf" 'foo' >&- 2>/dev/null || fail=1
+ returns_ 1 cp --verbose a b >&- 2>/dev/null || fail=1
+ rm -Rf tmpfile-?????? || fail=1
+ returns_ 1 mktemp tmpfile-XXXXXX >&- 2>/dev/null || fail=1
+ returns_ 1 mktemp tmpfile-XXXXXX -q >&- 2>/dev/null || fail=1
+ case $(echo tmpfile-??????) in 'tmpfile-??????') ;; *) fail=1 ;; esac
+fi
+
+# Likewise for /dev/full, if /dev/full works.
+if test -w /dev/full && test -c /dev/full; then
+ returns_ 1 "$p/src/printf" 'foo' >/dev/full 2>/dev/null || fail=1
+ returns_ 1 cp --verbose a b >/dev/full 2>/dev/null || fail=1
+ rm -Rf tmpdir-?????? || fail=1
+ returns_ 1 mktemp -d tmpdir-XXXXXX >/dev/full 2>/dev/null || fail=1
+ returns_ 1 mktemp -d -q tmpdir-XXXXXX >/dev/full 2>/dev/null || fail=1
+ case $(echo tmpfile-??????) in 'tmpfile-??????') ;; *) fail=1 ;; esac
+fi
+
+Exit $fail
diff --git a/tests/misc/comm.pl b/tests/misc/comm.pl
new file mode 100755
index 0000000..aaaf465
--- /dev/null
+++ b/tests/misc/comm.pl
@@ -0,0 +1,186 @@
+#!/usr/bin/perl
+# -*- perl -*-
+# Test comm
+
+# Copyright (C) 2008-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+require 5.003;
+use strict;
+
+(my $program_name = $0) =~ s|.*/||;
+
+my $prog = 'comm';
+
+# Turn off localization of executable's output.
+@ENV{qw(LANGUAGE LANG LC_ALL)} = ('C') x 3;
+
+my @inputs = ({IN=>{a=>"1\n3\n3\n3"}}, {IN=>{b=>"2\n2\n3\n3\n3"}});
+my @zinputs = ({IN=>{za=>"1\0003\0003\0003"}},
+ {IN=>{zb=>"2\0002\0003\0003\0003"}});
+
+my @Tests =
+ (
+ # basic operation
+ ['basic', @inputs, {OUT=>"1\n\t2\n\t2\n\t\t3\n\t\t3\n\t\t3\n"} ],
+ ['zbasic', '-z', @zinputs, {OUT=>"1\0\t2\0\t2\0\t\t3\0\t\t3\0\t\t3\0"} ],
+
+ # suppress lines unique to file 1
+ ['opt-1', '-1', @inputs, {OUT=>"2\n2\n\t3\n\t3\n\t3\n"} ],
+ ['zopt-1', '-z', '-1', @zinputs, {OUT=>"2\0002\000\t3\000\t3\000\t3\000"} ],
+
+ # suppress lines unique to file 2
+ ['opt-2', '-2', @inputs, {OUT=>"1\n\t3\n\t3\n\t3\n"} ],
+ ['zopt-2', '-z', '-2', @zinputs, {OUT=>"1\000\t3\000\t3\000\t3\000"} ],
+
+ # suppress lines that appear in both files
+ ['opt-3', '-3', @inputs, {OUT=>"1\n\t2\n\t2\n"} ],
+ ['zopt-3', '-z', '-3', @zinputs, {OUT=>"1\000\t2\000\t2\000"} ],
+
+ # suppress lines unique to file 1 and lines unique to file 2
+ ['opt-12', '-1', '-2', @inputs, {OUT=>"3\n3\n3\n"} ],
+ ['zopt-12', '-12z', @zinputs, {OUT=>"3\0003\0003\000"} ],
+
+ # suppress lines unique to file 1 and those that appear in both files
+ ['opt-13', '-1', '-3', @inputs, {OUT=>"2\n2\n"} ],
+ ['zopt-13', '-13z', @zinputs, {OUT=>"2\0002\000"} ],
+
+ # suppress lines unique to file 2 and those that appear in both files
+ ['opt-23', '-2', '-3', @inputs, {OUT=>"1\n"} ],
+ ['zopt-23', '-23z', @zinputs, {OUT=>"1\000"} ],
+
+ # suppress all output
+ ['opt-123', '-1', '-2', '-3', @inputs, {OUT=>""} ],
+
+ # show summary: 1 only in file1, 2 only in file2, 3 in both files
+ ['total-all', '--total', @inputs, {OUT=>"1\n\t2\n\t2\n\t\t3\n\t\t3\n\t\t3\n"
+ . "1\t2\t3\ttotal\n"} ],
+
+ # show summary only, suppressing regular output
+ ['total-123', '--total', '-123', @inputs, {OUT=>"1\t2\t3\ttotal\n"} ],
+
+ # invalid missing command line argument (1)
+ ['missing-arg1', $inputs[0], {EXIT=>1},
+ {ERR => "$prog: missing operand after 'a'\n"
+ . "Try '$prog --help' for more information.\n"}],
+
+ # invalid missing command line argument (both)
+ ['missing-arg2', {EXIT=>1},
+ {ERR => "$prog: missing operand\n"
+ . "Try '$prog --help' for more information.\n"}],
+
+ # invalid extra command line argument
+ ['extra-arg', @inputs, 'no-such', {EXIT=>1},
+ {ERR => "$prog: extra operand 'no-such'\n"
+ . "Try '$prog --help' for more information.\n"}],
+
+ # out-of-order input
+ ['ooo', {IN=>{a=>"1\n3"}}, {IN=>{b=>"3\n2"}}, {EXIT=>1},
+ {OUT => "1\n\t\t3\n\t2\n"},
+ {ERR => "$prog: file 2 is not in sorted order\n"
+ . "$prog: input is not in sorted order\n"}],
+
+ # out-of-order input, fatal
+ ['ooo2', '--check-order', {IN=>{a=>"1\n3"}}, {IN=>{b=>"3\n2"}}, {EXIT=>1},
+ {OUT => "1\n\t\t3\n"},
+ {ERR => "$prog: file 2 is not in sorted order\n"}],
+
+ # out-of-order input, ignored
+ ['ooo3', '--nocheck-order', {IN=>{a=>"1\n3"}}, {IN=>{b=>"3\n2"}},
+ {OUT => "1\n\t\t3\n\t2\n"}],
+
+ # both inputs out-of-order
+ ['ooo4', {IN=>{a=>"3\n1\n0"}}, {IN=>{b=>"3\n2\n0"}}, {EXIT=>1},
+ {OUT => "\t\t3\n1\n0\n\t2\n\t0\n"},
+ {ERR => "$prog: file 1 is not in sorted order\n".
+ "$prog: file 2 is not in sorted order\n"
+ . "$prog: input is not in sorted order\n"}],
+
+ # both inputs out-of-order on last pair
+ ['ooo5', {IN=>{a=>"3\n1"}}, {IN=>{b=>"3\n2"}}, {EXIT=>1},
+ {OUT => "\t\t3\n1\n\t2\n"},
+ {ERR => "$prog: file 1 is not in sorted order\n".
+ "$prog: file 2 is not in sorted order\n"
+ . "$prog: input is not in sorted order\n"}],
+
+ # first input out-of-order extended
+ ['ooo5b', {IN=>{a=>"0\n3\n1"}}, {IN=>{b=>"2\n3"}}, {EXIT=>1},
+ {OUT => "0\n\t2\n\t\t3\n1\n"},
+ {ERR => "$prog: file 1 is not in sorted order\n"
+ . "$prog: input is not in sorted order\n"}],
+
+ # second input out-of-order extended
+ ['ooo5c', {IN=>{a=>"0\n3"}}, {IN=>{b=>"2\n3\n1"}}, {EXIT=>1},
+ {OUT => "0\n\t2\n\t\t3\n\t1\n"},
+ {ERR => "$prog: file 2 is not in sorted order\n"
+ . "$prog: input is not in sorted order\n"}],
+
+ # both inputs out-of-order, but fully pairable
+ ['ooo6', {IN=>{a=>"2\n1\n0"}}, {IN=>{b=>"2\n1\n0"}}, {EXIT=>0},
+ {OUT => "\t\t2\n\t\t1\n\t\t0\n"}],
+
+ # both inputs out-of-order, fully pairable, but forced to fail
+ ['ooo7', '--check-order', {IN=>{a=>"2\n1\n0"}}, {IN=>{b=>"2\n1\n0"}},
+ {EXIT=>1},
+ {OUT => "\t\t2\n"},
+ {ERR => "$prog: file 1 is not in sorted order\n"}],
+
+ # out-of-order, line 2 is a prefix of line 1
+ # until coreutils-7.2, this test would fail -- no disorder detected
+ ['ooo-prefix', '--check-order', {IN=>{a=>"Xa\nX\n"}}, {IN=>{b=>""}},
+ {EXIT=>1},
+ {OUT => "Xa\n"},
+ {ERR => "$prog: file 1 is not in sorted order\n"}],
+
+ # alternate delimiter: ','
+ ['delim-comma', '--output-delimiter=,', @inputs,
+ {OUT=>"1\n,2\n,2\n,,3\n,,3\n,,3\n"} ],
+
+ # two-character alternate delimiter: '++'
+ ['delim-2char', '--output-delimiter=++', @inputs,
+ {OUT=>"1\n++2\n++2\n++++3\n++++3\n++++3\n"} ],
+
+ # NUL delimiter
+ ['delim-empty', '--output-delimiter=', @inputs,
+ {OUT=>"1\n\0002\n\0002\n\000\0003\n\000\0003\n\000\0003\n"} ],
+ ['zdelim-empty', '-z', '-z --output-delimiter=', @zinputs,
+ {OUT=>"1\000\0002\000\0002\000\000\0003\000\000\0003\000\000\0003\000"} ],
+ ['total-delim-empty', '--total --output-delimiter=', @inputs,
+ {OUT=>"1\n\0002\n\0002\n\000\0003\n\000\0003\n\000\0003\n"
+ . "1\0002\0003\000total\n"} ],
+
+ # invalid dual delimiter
+ ['delim-dual', '--output-delimiter=,', '--output-delimiter=+', @inputs,
+ {EXIT=>1}, {ERR => "$prog: multiple output delimiters specified\n"}],
+
+ # valid dual delimiter specification
+ ['delim-dual2', '--output-delimiter=,', '--output-delimiter=,', @inputs,
+ {OUT=>"1\n,2\n,2\n,,3\n,,3\n,,3\n"} ],
+
+ # show summary, zero-terminated
+ ['totalz-all', '--total', '-z', @zinputs,
+ {OUT=>"1\000\t2\000\t2\000\t\t3\000\t\t3\000\t\t3\000"
+ . "1\t2\t3\ttotal\000"} ],
+
+ # show summary only (-123), zero-terminated and with ',' as delimiter
+ ['totalz-123', '--total', '-z123', '--output-delimiter=,', @zinputs,
+ {OUT=>"1,2,3,total\000"} ],
+ );
+
+my $save_temps = $ENV{DEBUG};
+my $verbose = $ENV{VERBOSE};
+
+my $fail = run_tests ($program_name, $prog, \@Tests, $save_temps, $verbose);
+exit $fail;
diff --git a/tests/misc/coreutils.sh b/tests/misc/coreutils.sh
new file mode 100755
index 0000000..ffcce84
--- /dev/null
+++ b/tests/misc/coreutils.sh
@@ -0,0 +1,36 @@
+#!/bin/sh
+# Verify behavior of separate coreutils multicall binary
+
+# Copyright (C) 2014-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ coreutils
+
+test -s "$abs_top_builddir/src/coreutils.h" \
+ || skip_ "multicall binary is disabled"
+
+# Yes outputs all its params so is good to verify argv manipulations
+echo 'y' > exp
+coreutils --coreutils-prog=yes | head -n10 | uniq > out
+compare exp out || fail=1
+
+# Ensure if incorrect program passed, we diagnose
+echo "coreutils: unknown program 'blah'" > exp
+coreutils --coreutils-prog='blah' --help 2>err && fail=1
+compare exp err || fail=1
+
+Exit $fail
diff --git a/tests/misc/dircolors.pl b/tests/misc/dircolors.pl
new file mode 100755
index 0000000..f33e893
--- /dev/null
+++ b/tests/misc/dircolors.pl
@@ -0,0 +1,76 @@
+#!/usr/bin/perl
+# Simple dircolors tests.
+
+# Copyright (C) 1998-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+use strict;
+
+(my $program_name = $0) =~ s|.*/||;
+
+# Turn off localization of executable's output.
+@ENV{qw(LANGUAGE LANG LC_ALL)} = ('C') x 3;
+
+my @Tests =
+ (
+ ['a', '-b', {IN => {k => "exec\n"}},
+ {ERR => "dircolors: k:1: invalid line; missing second token\n"},
+ {EXIT => 1}],
+ ['quote', '-b', {IN => "exec 'echo Hello;:'\n"},
+ {OUT => "LS_COLORS='ex='\\''echo Hello;\\:'\\'':';\n"
+ . "export LS_COLORS\n"}],
+ ['other-wr', '-b', {IN => "owt 40;33\n"},
+ {OUT => "LS_COLORS='tw=40;33:';\nexport LS_COLORS\n"}],
+ ['term-1', '-b', {IN => "TERM none\nowt 40;33\n"},
+ {OUT => "LS_COLORS='tw=40;33:';\nexport LS_COLORS\n"}],
+ ['term-2', '-b', {IN => "TERM non*\nowt 40;33\n"},
+ {OUT => "LS_COLORS='tw=40;33:';\nexport LS_COLORS\n"}],
+ ['term-3', '-b', {IN => "TERM nomatch\nowt 40;33\n"},
+ {OUT => "LS_COLORS='';\nexport LS_COLORS\n"}],
+ ['term-4', '-b', {IN => "TERM N*match\nowt 40;33\n"},
+ {OUT => "LS_COLORS='';\nexport LS_COLORS\n"}],
+
+ ['colorterm-1', '-b', {ENV => 'COLORTERM=any'},
+ {IN => "COLORTERM ?*\nowt 40;33\n"},
+ {OUT => "LS_COLORS='tw=40;33:';\nexport LS_COLORS\n"}],
+
+ ['colorterm-2', '-b', {ENV => 'COLORTERM='},
+ {IN => "COLORTERM ?*\nowt 40;33\n"},
+ {OUT => "LS_COLORS='';\nexport LS_COLORS\n"}],
+
+ ['print-clash1', '-p', '--print-ls',
+ {ERR => "dircolors: options --print-database and --print-ls-colors " .
+ "are mutually exclusive\n" .
+ "Try 'dircolors --help' for more information.\n"},
+ {EXIT => 1}],
+ ['print-clash2', '-b', '--print-database',
+ {ERR => "dircolors: the options to output non shell syntax,\n" .
+ "and to select a shell syntax are mutually exclusive\n" .
+ "Try 'dircolors --help' for more information.\n"},
+ {EXIT => 1}],
+
+ ['print-ls-colors', '--print-ls-colors', {IN => "OWT 40;33\n"},
+ {OUT => "\x1B[40;33mtw\t40;33\x1B[0m\n"}],
+
+ # CAREFUL: always specify the -b option, unless explicitly testing
+ # for csh syntax output, or --print-ls-color output.
+ );
+
+my $save_temps = $ENV{DEBUG};
+my $verbose = $ENV{VERBOSE};
+
+my $prog = 'dircolors';
+my $fail = run_tests ($program_name, $prog, \@Tests, $save_temps, $verbose);
+exit $fail;
diff --git a/tests/misc/dirname.pl b/tests/misc/dirname.pl
new file mode 100755
index 0000000..e509c6b
--- /dev/null
+++ b/tests/misc/dirname.pl
@@ -0,0 +1,72 @@
+#!/usr/bin/perl
+# Test "dirname".
+
+# Copyright (C) 2006-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+use strict;
+use File::stat;
+
+(my $program_name = $0) =~ s|.*/||;
+
+# Turn off localization of executable's output.
+@ENV{qw(LANGUAGE LANG LC_ALL)} = ('C') x 3;
+
+my $stat_single = stat('/');
+my $stat_double = stat('//');
+my $double_slash = ($stat_single->dev == $stat_double->dev
+ && $stat_single->ino == $stat_double->ino) ? '/' : '//';
+
+my $prog = 'dirname';
+
+my @Tests =
+ (
+ ['fail-1', {ERR => "$prog: missing operand\n"
+ . "Try '$prog --help' for more information.\n"}, {EXIT => '1'}],
+
+ ['a', qw(d/f), {OUT => 'd'}],
+ ['b', qw(/d/f), {OUT => '/d'}],
+ ['c', qw(d/f/), {OUT => 'd'}],
+ ['d', qw(d/f//), {OUT => 'd'}],
+ ['e', qw(f), {OUT => '.'}],
+ ['f', qw(/), {OUT => '/'}],
+ ['g', qw(//), {OUT => "$double_slash"}],
+ ['h', qw(///), {OUT => '/'}],
+ ['i', qw(//a//), {OUT => "$double_slash"}],
+ ['j', qw(///a///), {OUT => '/'}],
+ ['k', qw(///a///b), {OUT => '///a'}],
+ ['l', qw(///a//b/), {OUT => '///a'}],
+ ['m', qw(''), {OUT => '.'}],
+ ['n', qw(a/b c/d), {OUT => "a\nc"}],
+ );
+
+# Append a newline to end of each expected 'OUT' string.
+my $t;
+foreach $t (@Tests)
+ {
+ my $arg1 = $t->[1];
+ my $e;
+ foreach $e (@$t)
+ {
+ $e->{OUT} = "$e->{OUT}\n"
+ if ref $e eq 'HASH' and exists $e->{OUT};
+ }
+ }
+
+my $save_temps = $ENV{SAVE_TEMPS};
+my $verbose = $ENV{VERBOSE};
+
+my $fail = run_tests ($program_name, $prog, \@Tests, $save_temps, $verbose);
+exit $fail;
diff --git a/tests/misc/echo.sh b/tests/misc/echo.sh
new file mode 100755
index 0000000..1cd9231
--- /dev/null
+++ b/tests/misc/echo.sh
@@ -0,0 +1,99 @@
+#!/bin/sh
+# basic tests for echo
+
+# Copyright (C) 2018-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+prog='env echo'
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ echo
+
+
+# Verify the methods of specifying "Escape":
+# Note 4 octal digits are allowed (unlike printf which uses up to 3)
+printf '%s\n' . . . . . | tr . '\033' > exp
+$prog -n -e '\x1b\n\e\n\33\n\033\n\0033\n' > out || fail=1
+compare exp out || fail=1
+
+# Incomplete hex escapes are output as is (unlike printf)
+printf '\\x\n' > exp
+$prog -n -e '\x\n' > out || fail=1
+compare exp out || fail=1
+
+# Always output -- (unlike printf)
+$prog -- 'foo' > out || fail=1
+$prog -n -e -- 'foo\n' >> out || fail=1
+cat <<\EOF > exp
+-- foo
+-- foo
+EOF
+compare exp out || fail=1
+
+# Ensure \c stops processing
+$prog -e 'foo\n\cbar' > out || fail=1
+printf 'foo\n' > exp
+compare exp out || fail=1
+
+# With POSIXLY_CORRECT:
+# only -n as the first (separate) option enables option processing
+# -E is ignored
+# escapes are processed by default
+POSIXLY_CORRECT=1 $prog -n -E 'foo\n' > out || fail=1
+POSIXLY_CORRECT=1 $prog -nE 'foo' >> out || fail=1
+POSIXLY_CORRECT=1 $prog -E -n 'foo' >> out || fail=1
+POSIXLY_CORRECT=1 $prog --version >> out || fail=1
+cat <<\EOF > exp
+foo
+-nE foo
+-E -n foo
+--version
+EOF
+compare exp out || fail=1
+
+# Further test coverage.
+# Output a literal '-' (on a line itself).
+$prog - > out || fail=1
+# Output a literal backslash '\', no newline.
+$prog -n -e '\\' >> out || fail=1
+# Output an empty line (merely to have a newline after the previous test).
+$prog >> out || fail=1
+# Test other characters escaped by a backslash:
+# \a hex 07 alert, bell
+# \b hex 08 backspace
+# \e hex 1b escape
+# \f hex 0c form feed
+# \n hex 0a new line
+# \r hex 0d carriage return
+# \t hex 09 horizontal tab
+# \v hex 0b vertical tab
+# Convert output, yet checking the exit status of $prog.
+{ $prog -n -e '\a\b\e\f\n\r\t\v' || touch fail; } | od -tx1 >> out || fail=1
+test '!' -f fail || fail=1
+# Output hex values which contain hexadecimal characters to test hextobin().
+# Hex values 4a through 4f are ASCII "JKLMNO".
+$prog -n -e '\x4a\x4b\x4c\x4d\x4e\x4f\x4A\x4B\x4C\x4D\x4E\x4F' >> out || fail=1
+# Output another newline.
+$prog >> out || fail=1
+cat <<\EOF > exp
+-
+\
+0000000 07 08 1b 0c 0a 0d 09 0b
+0000010
+JKLMNOJKLMNO
+EOF
+compare exp out || fail=1
+
+Exit $fail
diff --git a/tests/misc/expand.pl b/tests/misc/expand.pl
new file mode 100755
index 0000000..06261ac
--- /dev/null
+++ b/tests/misc/expand.pl
@@ -0,0 +1,191 @@
+#!/usr/bin/perl
+# Exercise expand.
+
+# Copyright (C) 2004-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+use strict;
+
+my $limits = getlimits ();
+my $UINTMAX_OFLOW = $limits->{UINTMAX_OFLOW};
+
+(my $program_name = $0) =~ s|.*/||;
+my $prog = 'expand';
+
+# Turn off localization of executable's output.
+@ENV{qw(LANGUAGE LANG LC_ALL)} = ('C') x 3;
+
+my @Tests =
+ (
+ ['t1', '--tabs=3', {IN=>"a\tb"}, {OUT=>"a b"}],
+ ['t2', '--tabs=3,6,9', {IN=>"a\tb\tc\td\te"}, {OUT=>"a b c d e"}],
+ ['t3', '--tabs="3 6 9"', {IN=>"a\tb\tc\td\te"}, {OUT=>"a b c d e"}],
+ # Leading space/commas are silently ignored; Mixing space/commas is allowed.
+ # (a side-effect of allowing direct "-3,9" parameter).
+ ['t4', '--tabs=", 3,6 9"', {IN=>"a\tb\tc\td\te"}, {OUT=>"a b c d e"}],
+ # tab stops parameter without values
+ ['t5', '--tabs=""', {IN=>"a\tb\tc"}, {OUT=>"a b c"}],
+ ['t6', '--tabs=","', {IN=>"a\tb\tc"}, {OUT=>"a b c"}],
+ ['t7', '--tabs=" "', {IN=>"a\tb\tc"}, {OUT=>"a b c"}],
+ ['t8', '--tabs="/"', {IN=>"a\tb\tc"}, {OUT=>"a b c"}],
+
+ # Input field wider than the specified tab list
+ ['if', '--tabs=6,9', {IN=>"a\tbbbbbbbbbbbbb\tc"},
+ {OUT=>"a bbbbbbbbbbbbb c"}],
+
+ ['i1', '--tabs=3 -i', {IN=>"\ta\tb"}, {OUT=>" a\tb"}],
+ ['i2', '--tabs=3 -i', {IN=>" \ta\tb"}, {OUT=>" a\tb"}],
+
+ # Undocumented feature:
+ # treat "expand -7" as "expand --tabs 7" ,
+ # and "expand -90" as "expand --tabs 90",
+ ['u1', '-3', {IN=>"a\tb\tc"}, {OUT=>"a b c"}],
+ ['u2', '-4 -9', {IN=>"a\tb\tc"}, {OUT=>"a b c"}],
+ ['u3', '-11', {IN=>"a\tb\tc"}, {OUT=>"a b c"}],
+ # Test all digits (for full code coverage)
+ ['u4', '-2 -6', {IN=>"a\tb\tc"}, {OUT=>"a b c"}],
+ ['u5', '-7', {IN=>"a\tb"}, {OUT=>"a b"}],
+ ['u6', '-8', {IN=>"a\tb"}, {OUT=>"a b"}],
+ # This syntax is handled internally as "-3, -9"
+ ['u7', '-3,9', {IN=>"a\tb\tc"}, {OUT=>"a b c"}],
+
+ # Multiple non-empty files
+ ['f1', '--tabs=4',
+ {IN=>{"in1" => "a\tb\n"}}, {IN=>{"in2" => "c\td\n"}},
+ {OUT=>"a b\nc d\n"}],
+ # Multiple files, first file is empty
+ ['f2', '--tabs=4',
+ {IN=>{"in1" => ""}}, {IN=>{"in2" => "c\td\n"}},
+ {OUT=>"c d\n"}],
+ # Multiple files, second file is empty
+ ['f3', '--tabs=4',
+ {IN=>{"in1" => "a\tb\n"}}, {IN=>{"in2" => ""}},
+ {OUT=>"a b\n"}],
+
+
+ # Test '\b' (back-space) - subtract one column.
+ #
+ # Note:
+ # In a terminal window, 'expand' will appear to erase the 'a' characters
+ # due to overwriting them with spaces:
+ #
+ # $ printf 'aaa\b\b\bc\td\n'
+ # caa d
+ # $ printf 'aaa\b\b\bc\td\n' | expand
+ # c d
+ #
+ # However the characters are all printed:
+ #
+ # $ printf 'aaa\b\b\bc\td\n' | expand | od -An -ta
+ # a a a bs bs bs c sp sp sp sp sp sp sp d nl
+ #
+ # If users ever report a problem with these tests and just
+ # copy&paste from the terminal, their report will be confusing
+ # (the 'a' will not appear).
+ #
+ # To see an example, enable the 'b-confusing' test, and examine the
+ # reported log:
+ #
+ # expand.pl: test b-confusing: stdout mismatch
+ # *** b-confusing.2 Fri Jun 24 15:43:21 2016
+ # --- b-confusing.O Fri Jun 24 15:43:21 2016
+ # ***************
+ # *** 1 ****
+ # ! c d
+ # --- 1 ----
+ # ! c d
+ #
+ # ['b-confusing','', {IN=>"aaa\b\b\bc\td\n"}, {OUT=>"c d\n"}],
+
+ ['b1','', {IN=>"aaa\b\b\bc\td\n"}, {OUT=>"aaa\b\b\bc d\n"}],
+
+ # \b as first character, when column is zero
+ ['b2','', {IN=>"\bc\td"}, {OUT=>"\bc d"}],
+
+ # Testing tab list adjusted due to backspaces
+ # ('b3' is the baseline without backspaces).
+ ['b3','--tabs 2,4,6,10',
+ {IN=>"1\t2\t3\t4\t5\n" .
+ "a\tb\tc\td\te\n"},
+ {OUT=>"1 2 3 4 5\n" .
+ "a b c d e\n"}],
+
+ # On screen this will appear the same as 'b3'
+ ['b4','--tabs 2,4,6,10',
+ {IN=>"1\t2\t3\t4\t5\n" .
+ "a\tbHELLO\b\b\b\b\b\tc\td\te\n"},
+ {OUT=>"1 2 3 4 5\n" .
+ "a bHELLO\b\b\b\b\b c d e\n"}],
+
+ # On screen on 'bHE' will appear (LLO overwritten by spaces),
+ # 'c' should align with 4, 'd' with 5:
+ # 1 2 3 4 5
+ # a bHE c d e
+ ['b5','--tabs 2,4,6,10',
+ {IN=>"1\t2\t3\t4\t5\n" .
+ "a\tbHELLO\b\b\b\tc\td\te\n"},
+ {OUT=>"1 2 3 4 5\n" .
+ "a bHELLO\b\b\b c d e\n"}],
+
+ # Test the trailing '/' feature which specifies the
+ # tab size to use after the last specified stop
+ ['trail1', '--tabs=1,/5', {IN=>"\ta\tb\tc"}, {OUT=>" a b c"}],
+ ['trail2', '--tabs=2,/5', {IN=>"\ta\tb\tc"}, {OUT=>" a b c"}],
+ ['trail3', '--tabs=1,2,/5', {IN=>"\ta\tb\tc"}, {OUT=>" a b c"}],
+ ['trail4', '--tabs=/5', {IN=>"\ta\tb"}, {OUT=>" a b"}],
+ ['trail5', '--tabs=//5', {IN=>"\ta\tb"}, {OUT=>" a b"}],
+ ['trail5a','--tabs=+/5', {IN=>"\ta\tb"}, {OUT=>" a b"}],
+ ['trail6', '--tabs=/,/5', {IN=>"\ta\tb"}, {OUT=>" a b"}],
+ ['trail7', '--tabs=,/5', {IN=>"\ta\tb"}, {OUT=>" a b"}],
+ ['trail8', '--tabs=1 -t/5', {IN=>"\ta\tb\tc"}, {OUT=>" a b c"}],
+ ['trail9', '--tab=1,2 -t/5',{IN=>"\ta\tb\tc"}, {OUT=>" a b c"}],
+
+ # Test incremental trailing '+' feature which specifies that
+ # tab stops should continue every increment
+ ['incre0', '--tab=1,+5', {IN=>"+\t\ta\tb"}, {OUT=>"+ a b"}],
+ ['incre1', '--tabs=1,+5', {IN=>"\ta\tb\tc"}, {OUT=>" a b c"}],
+ ['incre2', '--tabs=2,+5', {IN=>"\ta\tb\tc"}, {OUT=>" a b c"}],
+ ['incre3', '--tabs=1,2,+5', {IN=>"\ta\tb\tc"}, {OUT=>" a b c"}],
+ ['incre4', '--tabs=+5', {IN=>"\ta\tb"}, {OUT=>" a b"}],
+ ['incre5', '--tabs=++5', {IN=>"\ta\tb"}, {OUT=>" a b"}],
+ ['incre5a','--tabs=/+5', {IN=>"\ta\tb"}, {OUT=>" a b"}],
+ ['incre6', '--tabs=+,+5', {IN=>"\ta\tb"}, {OUT=>" a b"}],
+ ['incre7', '--tabs=,+5', {IN=>"\ta\tb"}, {OUT=>" a b"}],
+ ['incre8', '--tabs=1 -t+5', {IN=>"\ta\tb\tc"}, {OUT=>" a b c"}],
+ ['incre9', '--tab=1,2 -t+5',{IN=>"\ta\tb\tc"}, {OUT=>" a b c"}],
+
+
+ # Test errors
+ ['e1', '--tabs="a"', {IN=>''}, {OUT=>''}, {EXIT=>1},
+ {ERR => "$prog: tab size contains invalid character(s): 'a'\n"}],
+ ['e2', "-t $UINTMAX_OFLOW", {IN=>''}, {OUT=>''}, {EXIT=>1},
+ {ERR => "$prog: tab stop is too large '$UINTMAX_OFLOW'\n"}],
+ ['e3', '--tabs=0', {IN=>''}, {OUT=>''}, {EXIT=>1},
+ {ERR => "$prog: tab size cannot be 0\n"}],
+ ['e4', '--tabs=3,3', {IN=>''}, {OUT=>''}, {EXIT=>1},
+ {ERR => "$prog: tab sizes must be ascending\n"}],
+ ['e5', '--tabs=/3,6,8', {IN=>''}, {OUT=>''}, {EXIT=>1},
+ {ERR => "$prog: '/' specifier only allowed with the last value\n"}],
+ ['e6', '-t/3 -t/6', {IN=>''}, {OUT=>''}, {EXIT=>1},
+ {ERR => "$prog: '/' specifier only allowed with the last value\n"}],
+ ['e7', '--tabs=3/', {IN=>''}, {OUT=>''}, {EXIT=>1},
+ {ERR => "$prog: '/' specifier not at start of number: '/'\n"}],
+ );
+
+my $save_temps = $ENV{DEBUG};
+my $verbose = $ENV{VERBOSE};
+
+my $fail = run_tests ($program_name, $prog, \@Tests, $save_temps, $verbose);
+exit $fail;
diff --git a/tests/misc/false-status.sh b/tests/misc/false-status.sh
new file mode 100755
index 0000000..7c4f8e2
--- /dev/null
+++ b/tests/misc/false-status.sh
@@ -0,0 +1,31 @@
+#!/bin/sh
+# ensure that false exits nonzero even with --help or --version
+# and ensure that true exits nonzero when it can't write --help or --version
+
+# Copyright (C) 2003-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ false true
+
+returns_ 1 env false --version > /dev/null || fail=1
+returns_ 1 env false --help > /dev/null || fail=1
+
+if test -w /dev/full && test -c /dev/full; then
+ returns_ 1 env true --version > /dev/full || fail=1
+ returns_ 1 env true --help > /dev/full || fail=1
+fi
+
+Exit $fail
diff --git a/tests/misc/fold.pl b/tests/misc/fold.pl
new file mode 100755
index 0000000..a94072f
--- /dev/null
+++ b/tests/misc/fold.pl
@@ -0,0 +1,39 @@
+#!/usr/bin/perl
+# Exercise fold.
+
+# Copyright (C) 2003-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+use strict;
+
+(my $program_name = $0) =~ s|.*/||;
+
+# Turn off localization of executable's output.
+@ENV{qw(LANGUAGE LANG LC_ALL)} = ('C') x 3;
+
+my @Tests =
+ (
+ ['s1', '-w2 -s', {IN=>"a\t"}, {OUT=>"a\n\t"}],
+ ['s2', '-w4 -s', {IN=>"abcdef d\n"}, {OUT=>"abcd\nef d\n"}],
+ ['s3', '-w4 -s', {IN=>"a cd fgh\n"}, {OUT=>"a \ncd \nfgh\n"}],
+ ['s4', '-w4 -s', {IN=>"abc ef\n"}, {OUT=>"abc \nef\n"}],
+ );
+
+my $save_temps = $ENV{DEBUG};
+my $verbose = $ENV{VERBOSE};
+
+my $prog = 'fold';
+my $fail = run_tests ($program_name, $prog, \@Tests, $save_temps, $verbose);
+exit $fail;
diff --git a/tests/misc/invalid-opt.pl b/tests/misc/invalid-opt.pl
new file mode 100755
index 0000000..872cbf8
--- /dev/null
+++ b/tests/misc/invalid-opt.pl
@@ -0,0 +1,103 @@
+#!/usr/bin/perl
+# exercise the 'invalid option' handling code in each program
+
+# Copyright (C) 2008-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+require 5.003;
+use strict;
+
+# Turn off localization of executable's output.
+@ENV{qw(LANGUAGE LANG LC_ALL)} = ('C') x 3;
+
+my %exit_status =
+ (
+ ls => 2,
+ dir => 2,
+ vdir => 2,
+ test => 2,
+ chroot => 125,
+ echo => 0,
+ env => 125,
+ expr => 0,
+ nice => 125,
+ nohup => 125,
+ runcon => 125,
+ sort => 2,
+ stdbuf => 125,
+ test => 0,
+ timeout => 125,
+ true => 0,
+ tty => 2,
+ printf => 0,
+ printenv => 2,
+ );
+
+my %expected_out =
+ (
+ echo => "-/\n",
+ expr => "-/\n",
+ printf => "-/",
+ );
+
+my %expected_err =
+ (
+ false => '',
+ stty => '',
+ );
+
+my $fail = 0;
+my @built_programs = split ' ', $ENV{built_programs};
+foreach my $prog (@built_programs)
+ {
+ $prog eq '['
+ and next;
+
+ my $try = "Try '$prog --help' for more information.\n";
+ my $x = $exit_status{$prog};
+ defined $x
+ or $x = 1;
+
+ my $out = $expected_out{$prog};
+ defined $out
+ or $out = '';
+
+ my $err = $expected_err{$prog};
+ defined $err
+ or $err = $x == 0 ? '' : "$prog: invalid option -- /\n$try";
+
+ # Accommodate different syntax in glibc's getopt
+ # diagnostics by filtering out single quotes.
+ # Also accommodate BSD getopt.
+ my $err_subst = "s,'/',/,; s,unknown,invalid,";
+
+ # Depending on how this script is run, stty emits different
+ # diagnostics. Don't bother checking them.
+ $prog eq 'stty'
+ and $err_subst = 's/(.|\n)*//ms';
+
+ my @Tests = (["$prog-invalid-opt", '-/', {OUT=>$out},
+ {ERR_SUBST => $err_subst},
+ {EXIT=>$x}, {ERR=>$err}]);
+
+ my $save_temps = $ENV{DEBUG};
+ my $verbose = $ENV{VERBOSE};
+
+ my $f = run_tests ($prog, \$prog, \@Tests, $save_temps, $verbose);
+ $f
+ and $fail = 1;
+ }
+
+exit $fail;
diff --git a/tests/misc/join.pl b/tests/misc/join.pl
new file mode 100755
index 0000000..2ca8567
--- /dev/null
+++ b/tests/misc/join.pl
@@ -0,0 +1,342 @@
+#!/usr/bin/perl
+# Test join.
+
+# Copyright (C) 2008-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+use strict;
+
+my $limits = getlimits ();
+
+# Turn off localization of executable's output.
+@ENV{qw(LANGUAGE LANG LC_ALL)} = ('C') x 3;
+
+my $prog = 'join';
+
+my $delim = chr 0247;
+sub t_subst ($)
+{
+ (my $s = $_[0]) =~ s/:/$delim/g;
+ return $s;
+}
+
+my @tv = (
+# test name
+# flags file-1 file-2 expected output expected return code
+#
+['1a', '-a1', ["a 1\n", "b\n"], "a 1\n", 0],
+['1b', '-a2', ["a 1\n", "b\n"], "b\n", 0], # Got "\n"
+['1c', '-a1 -a2', ["a 1\n", "b\n"], "a 1\nb\n", 0], # Got "a 1\n\n"
+['1d', '-a1', ["a 1\nb\n", "b\n"], "a 1\nb\n", 0],
+['1e', '-a2', ["a 1\nb\n", "b\n"], "b\n", 0],
+['1f', '-a2', ["b\n", "a\nb\n"], "a\nb\n", 0],
+
+['2a', '-a1 -e .', ["a\nb\nc\n", "a x y\nb\nc\n"], "a x y\nb\nc\n", 0],
+['2b', '-a1 -e . -o 2.1,2.2,2.3', ["a\nb\nc\n", "a x y\nb\nc\n"],
+ "a x y\nb . .\nc . .\n", 0],
+['2c', '-a1 -e . -o 2.1,2.2,2.3', ["a\nb\nc\nd\n", "a x y\nb\nc\n"],
+ "a x y\nb . .\nc . .\n. . .\n", 0],
+
+['3a', '-t:', ["a:1\nb:1\n", "a:2:\nb:2:\n"], "a:1:2:\nb:1:2:\n", 0],
+
+# operate on whole line (as sort does by default)
+['3b', '-t ""', ["a 1\nb 1\n", "a 1\nb 2\n"], "a 1\n", 0],
+# use NUL as the field delimiter
+['3c', '-t "\\0"', ["a\0a\n", "a\0b\n"], "a\0a\0b\n", 0],
+
+# Just like -a1 and -a2 when there are no pairable lines
+['4a', '-v 1', ["a 1\n", "b\n"], "a 1\n", 0],
+['4b', '-v 2', ["a 1\n", "b\n"], "b\n", 0],
+
+['4c', '-v 1', ["a 1\nb\n", "b\n"], "a 1\n", 0],
+['4d', '-v 2', ["a 1\nb\n", "b\n"], "", 0],
+['4e', '-v 2', ["b\n", "a 1\nb\n"], "a 1\n", 0],
+['5a', '-a1 -e - -o 1.1,2.2',
+ ["a 1\nb 2\n", "a 11\nb\n"], "a 11\nb -\n", 0],
+['5b', '-a1 -e - -o 1.1,2.2',
+ ["apr 15\naug 20\ndec 18\nfeb 05\n", "apr 06\naug 14\ndate\nfeb 15"],
+ "apr 06\naug 14\ndec -\nfeb 15\n", 0],
+['5c', '-a1 -e - -o 1.1,2.2',
+ ["aug 20\ndec 18\n", "aug 14\ndate\nfeb 15"],
+ "aug 14\ndec -\n", 0],
+['5d', '-a1 -e - -o 1.1,2.2',
+ ["dec 18\n", ""], "dec -\n", 0],
+['5e', '-a2 -e - -o 1.1,2.2',
+ ["apr 15\naug 20\ndec 18\nfeb 05\n", "apr 06\naug 14\ndate\nfeb 15\n"],
+ "apr 06\naug 14\n- -\nfeb 15\n", 0],
+['5f', '-a2 -e - -o 2.2,1.1',
+ ["apr 15\naug 20\ndec 18\nfeb 05\n", "apr 06\naug 14\ndate\nfeb 15\n"],
+ "06 apr\n14 aug\n- -\n15 feb\n", 0],
+['5g', '-a1 -e - -o 2.2,1.1',
+ ["apr 15\naug 20\ndec 18\nfeb 05\n", "apr 06\naug 14\ndate\nfeb 15\n"],
+ "06 apr\n14 aug\n- dec\n15 feb\n", 0],
+
+['5h', '-a1 -e - -o 2.2,1.1',
+ ["apr 15\naug 20\ndec 18\nfeb 05\n", "apr 06\naug 14\ndate\n"],
+ "06 apr\n14 aug\n- dec\n- feb\n", 0],
+['5i', '-a1 -e - -o 1.1,2.2',
+ ["apr 15\naug 20\ndec 18\nfeb 05\n", "apr 06\naug 14\ndate\n"],
+ "apr 06\naug 14\ndec -\nfeb -\n", 0],
+
+['5j', '-a2 -e - -o 2.2,1.1',
+ ["apr 15\naug 20\ndec 18\nfeb 05\n", "apr 06\naug 14\ndate\n"],
+ "06 apr\n14 aug\n- -\n", 0],
+['5k', '-a2 -e - -o 2.2,1.1',
+ ["apr 15\naug 20\ndec 18\nfeb 05\n", "apr 06\naug 14\ndate\n"],
+ "06 apr\n14 aug\n- -\n", 0],
+
+['5l', '-a1 -e - -o 2.2,1.1',
+ ["apr 15\naug 20\ndec 18\n", "apr 06\naug 14\ndate\nfeb 15\n"],
+ "06 apr\n14 aug\n- dec\n", 0],
+['5m', '-a2 -e - -o 2.2,1.1',
+ ["apr 15\naug 20\ndec 18\n", "apr 06\naug 14\ndate\nfeb 15\n"],
+ "06 apr\n14 aug\n- -\n15 -\n", 0],
+
+['6a', '-e -',
+ ["a 1\nb 2\nd 4\n", "a 21\nb 22\nc 23\nf 26\n"],
+ "a 1 21\nb 2 22\n", 0],
+['6b', '-a1 -e -',
+ ["a 1\nb 2\nd 4\n", "a 21\nb 22\nc 23\nf 26\n"],
+ "a 1 21\nb 2 22\nd 4\n", 0],
+['6c', '-a1 -e -',
+ ["a 21\nb 22\nc 23\nf 26\n", "a 1\nb 2\nd 4\n"],
+ "a 21 1\nb 22 2\nc 23\nf 26\n", 0],
+
+['7a', '-a1 -e . -o 2.7',
+ ["a\nb\nc\n", "a x y\nb\nc\n"], ".\n.\n.\n", 0],
+
+['8a', '-a1 -e . -o 0,1.2',
+ ["a\nb\nc\nd G\n", "a x y\nb\nc\ne\n"],
+ "a .\nb .\nc .\nd G\n", 0],
+['8b', '-a1 -a2 -e . -o 0,1.2',
+ ["a\nb\nc\nd G\n", "a x y\nb\nc\ne\n"],
+ "a .\nb .\nc .\nd G\ne .\n", 0],
+
+# From David Dyck
+['9a', '', [" a 1\n b 2\n", " a Y\n b Z\n"], "a 1 Y\nb 2 Z\n", 0],
+
+# -o 'auto'
+['10a', '-a1 -a2 -e . -o auto',
+ ["a 1 2\nb 1\nd 1 2\n", "a 3 4\nb 3 4\nc 3 4\n"],
+ "a 1 2 3 4\nb 1 . 3 4\nc . . 3 4\nd 1 2 . .\n", 0],
+['10b', '-a1 -a2 -j3 -e . -o auto',
+ ["a 1 2\nb 1\nd 1 2\n", "a 3 4\nb 3 4\nc 3 4\n"],
+ "2 a 1 . .\n. b 1 . .\n2 d 1 . .\n4 . . a 3\n4 . . b 3\n4 . . c 3\n"],
+['10c', '-a1 -1 1 -2 4 -e. -o auto',
+ ["a 1 2\nb 1\nd 1 2\n", "a 3 4\nb 3 4\nc 3 4\n"],
+ "a 1 2 . . .\nb 1 . . . .\nd 1 2 . . .\n"],
+['10d', '-a2 -1 1 -2 4 -e. -o auto',
+ ["a 1 2\nb 1\nd 1 2\n", "a 3 4\nb 3 4\nc 3 4\n"],
+ ". . . a 3 4\n. . . b 3 4\n. . . c 3 4\n"],
+['10e', '-o auto',
+ ["a 1 2\nb 1 2 discard\n", "a 3 4\nb 3 4 discard\n"],
+ "a 1 2 3 4\nb 1 2 3 4\n"],
+['10f', '-t, -o auto',
+ ["a,1,,2\nb,1,2\n", "a,3,4\nb,3,4\n"],
+ "a,1,,2,3,4\nb,1,2,,3,4\n"],
+
+# For -v2, print the match field correctly with the default output format,
+# when that match field is different between file 1 and file 2. Fixed in 8.10
+['v2-order', '-v2 -2 2', ["", "2 1\n"], "1 2\n", 0],
+
+# From Tim Smithers: fixed in 1.22l
+['trailing-sp', '-t: -1 1 -2 1', ["a:x \n", "a:y \n"], "a:x :y \n", 0],
+
+# From Paul Eggert: fixed in 1.22n
+['sp-vs-blank', '', ["\f 1\n", "\f 2\n"], "\f 1 2\n", 0],
+
+# From Paul Eggert: fixed in 1.22n (this would fail on Solaris7,
+# with LC_ALL set to en_US).
+# Unfortunately, that Solaris7's en_US locale folds case (making
+# the first input file sorted) is not portable, so this test would
+# fail on e.g. Linux systems, because the input to join isn't sorted.
+# ['lc-collate', '', ["a 1a\nB 1B\n", "B 2B\n"], "B 1B 2B\n", 0],
+
+# Based on a report from Antonio Rendas. Fixed in 2.0.9.
+['8-bit-t', t_subst "-t:",
+ [t_subst "a:1\nb:1\n", t_subst "a:2:\nb:2:\n"],
+ t_subst "a:1:2:\nb:1:2:\n", 0],
+
+# fields > SIZE_MAX are silently interpreted as SIZE_MAX
+['bigfield1', "-1 $limits->{UINTMAX_OFLOW} -2 2",
+ ["a\n", "b\n"], " a b\n", 0],
+['bigfield2', "-1 $limits->{SIZE_OFLOW} -2 2",
+ ["a\n", "b\n"], " a b\n", 0],
+
+# FIXME: change this to ensure the diagnostic makes sense
+['invalid-j', '-j x', ["", ""], "", 1,
+ "$prog: invalid field number: 'x'\n"],
+
+# With ordering check, inputs in order
+['chkodr-1', '--check-order',
+ [" a 1\n b 2\n", " a Y\n b Z\n"], "a 1 Y\nb 2 Z\n", 0],
+
+# Without check, inputs in order
+['chkodr-2', '--nocheck-order',
+ [" a 1\n b 2\n", " a Y\n b Z\n"], "a 1 Y\nb 2 Z\n", 0],
+
+# Without check, both inputs out of order (in fact, in reverse order)
+# but all pairable. Support for this is a GNU extension.
+['chkodr-3', '--nocheck-order',
+ [" b 1\n a 2\n", " b Y\n a Z\n"], "b 1 Y\na 2 Z\n", 0],
+
+# The extension should work without --nocheck-order, since that is the
+# default.
+['chkodr-4', '',
+ [" b 1\n a 2\n", " b Y\n a Z\n"], "b 1 Y\na 2 Z\n", 0],
+
+# With check, both inputs out of order (in fact, in reverse order)
+['chkodr-5', '--check-order',
+ [" b 1\n a 2\n", " b Y\n a Z\n"], "", 1,
+ "$prog: chkodr-5.1:2: is not sorted: a 2\n"],
+
+# Similar, but with only file 2 not sorted.
+['chkodr-5b', '--check-order',
+ [" a 2\n b 1\n", " b Y\n a Z\n"], "", 1,
+ "$prog: chkodr-5b.2:2: is not sorted: a Z\n"],
+
+# Similar, but with the offending line having length 0 (excluding newline).
+['chkodr-5c', '--check-order',
+ [" a 2\n b 1\n", " b Y\n\n"], "", 1,
+ "$prog: chkodr-5c.2:2: is not sorted: \n"],
+
+# Similar, but elicit a warning for each input file (without --check-order).
+['chkodr-5d', '',
+ ["a\nx\n\n", "b\ny\n\n"], "", 1,
+ "$prog: chkodr-5d.1:3: is not sorted: \n" .
+ "$prog: chkodr-5d.2:3: is not sorted: \n" .
+ "$prog: input is not in sorted order\n"
+ ],
+
+# Similar, but make it so each offending line has no newline.
+['chkodr-5e', '',
+ ["a\nx\no", "b\ny\np"], "", 1,
+ "$prog: chkodr-5e.1:3: is not sorted: o\n" .
+ "$prog: chkodr-5e.2:3: is not sorted: p\n" .
+ "$prog: input is not in sorted order\n"
+ ],
+
+# Without order check, both inputs out of order and some lines
+# unpairable. This is NOT supported by the GNU extension. All that
+# we really care about for this test is that the return status is
+# zero, since that is the only way to actually verify that the
+# --nocheck-order option had any effect. We don't actually want to
+# guarantee that join produces this output on stdout.
+['chkodr-6', '--nocheck-order',
+ [" b 1\n a 2\n", " b Y\n c Z\n"], "b 1 Y\n", 0],
+
+# Before 6.10.143, this would mistakenly fail with the diagnostic:
+# join: File 1 is not in sorted order
+['chkodr-7', '-12', ["2 a\n1 b\n", "2 c\n1 d"], "", 0],
+
+# After 8.9, join doesn't report disorder by default
+# when comparing against an empty input file.
+['chkodr-8', '', ["2 a\n1 b\n", ""], "", 0],
+
+# Test '--header' feature
+['header-1', '--header',
+ [ "ID Name\n1 A\n2 B\n", "ID Color\n1 red\n"], "ID Name Color\n1 A red\n", 0],
+
+# '--header' with '--check-order' : The header line is out-of-order but the
+# actual data is in order. This join should succeed.
+['header-2', '--header --check-order',
+ ["ID Name\n1 A\n2 B\n", "ID Color\n2 green\n"],
+ "ID Name Color\n2 B green\n", 0],
+
+# '--header' with '--check-order' : The header line is out-of-order AND the
+# actual data out-of-order. This join should fail.
+['header-3', '--header --check-order',
+ ["ID Name\n2 B\n1 A\n", "ID Color\n2 blue\n"], "ID Name Color\n", 1,
+ "$prog: header-3.1:3: is not sorted: 1 A\n"],
+
+# '--header' with specific output format '-o'.
+# output header line should respect the requested format
+['header-4', '--header -o "0,1.3,2.2"',
+ ["ID Group Name\n1 Foo A\n2 Bar B\n", "ID Color\n2 blue\n"],
+ "ID Name Color\n2 B blue\n", 0],
+
+# '--header' always outputs headers from the first file
+# even if the headers from the second file don't match
+['header-5', '--header',
+ [ "ID1 Name\n1 A\n2 B\n", "ID2 Color\n1 red\n"],
+ "ID1 Name Color\n1 A red\n", 0],
+
+# '--header' doesn't check order of a header
+# even if there is no header in the second file
+['header-6', '--header -a1',
+ [ "ID1 Name\n1 A\n", ""],
+ "ID1 Name\n1 A\n", 0],
+
+# Zero-terminated lines
+['z1', '-z',
+ ["a\0c\0e\0", "a\0b\0c\0"], "a\0c\0", 0],
+
+# not zero-terminated, but related to the code change:
+# the old readlinebuffer() auto-added '\n' to the last line.
+# the new readlinebuffer_delim() does not.
+# Ensure it doesn't matter.
+['z2', '',
+ ["a\nc\ne\n", "a\nb\nc"], "a\nc\n", 0],
+['z3', '',
+ ["a\nc\ne", "a\nb\nc"], "a\nc\n", 0],
+# missing last NUL at the end of the last line (=end of file)
+['z4', '-z',
+ ["a\0c\0e", "a\0b\0c"], "a\0c\0", 0],
+# With -z, embedded newlines are treated as field separators.
+# Note '\n' are converted to ' ' in this case.
+['z5', '-z -a1 -a2',
+ ["a\n\n1\0c 3\0", "a 2\0b\n8\0c 9\0"], "a 1 2\0b 8\0c 3 9\0"],
+# One can avoid field processing like:
+['z6', '-z -t ""',
+ ["a\n1\n\0", "a\n1\n\0"], "a\n1\n\0"],
+
+);
+
+# Convert the above old-style test vectors to the newer
+# format used by Coreutils.pm.
+
+my @Tests;
+foreach my $t (@tv)
+ {
+ my ($test_name, $flags, $in, $exp, $ret, $err_msg) = @$t;
+ my $new_ent = [$test_name, $flags];
+ if (!ref $in)
+ {
+ push @$new_ent, {IN=>$in};
+ }
+ elsif (ref $in eq 'HASH')
+ {
+ # ignore
+ }
+ else
+ {
+ foreach my $e (@$in)
+ {
+ push @$new_ent, {IN=>$e};
+ }
+ }
+ push @$new_ent, {OUT=>$exp};
+ $ret
+ and push @$new_ent, {EXIT=>$ret}, {ERR=>$err_msg};
+ push @Tests, $new_ent;
+ }
+
+@Tests = triple_test \@Tests;
+
+my $save_temps = $ENV{DEBUG};
+my $verbose = $ENV{VERBOSE};
+
+my $fail = run_tests ($prog, $prog, \@Tests, $save_temps, $verbose);
+exit $fail;
diff --git a/tests/misc/kill.sh b/tests/misc/kill.sh
new file mode 100755
index 0000000..34d6578
--- /dev/null
+++ b/tests/misc/kill.sh
@@ -0,0 +1,63 @@
+#!/bin/sh
+# Validate kill operation
+
+# Copyright (C) 2015-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ kill
+
+# params required
+returns_ 1 env kill || fail=1
+returns_ 1 env kill -TERM || fail=1
+
+# Invalid combinations
+returns_ 1 env kill -l -l || fail=1
+returns_ 1 env kill -l -t || fail=1
+returns_ 1 env kill -l -s 1 || fail=1
+returns_ 1 env kill -t -s 1 || fail=1
+
+# signal sending
+returns_ 1 env kill -0 no_pid || fail=1
+env kill -0 $$ || fail=1
+env kill -s0 $$ || fail=1
+env kill -n0 $$ || fail=1 # bash compat
+env kill -CONT $$ || fail=1
+env kill -Cont $$ || fail=1
+returns_ 1 env kill -cont $$ || fail=1
+env kill -0 -1 || fail=1 # to group
+
+# table listing
+env kill -l || fail=1
+env kill -t || fail=1
+env kill -L || fail=1 # bash compat
+env kill -t TERM HUP || fail=1
+
+# Verify (multi) name to signal number and vice versa
+SIGTERM=$(env kill -l HUP TERM | tail -n1) || fail=1
+test $(env kill -l "$SIGTERM") = TERM || fail=1
+
+# Verify we only consider the lower "signal" bits,
+# to support ksh which just adds 256 to the signal value
+STD_TERM_STATUS=$(expr "$SIGTERM" + 128)
+KSH_TERM_STATUS=$(expr "$SIGTERM" + 256)
+test $(env kill -l $STD_TERM_STATUS $KSH_TERM_STATUS | uniq) = TERM || fail=1
+
+# Verify invalid signal spec is diagnosed
+returns_ 1 env kill -l -1 || fail=1
+returns_ 1 env kill -l -1 0 || fail=1
+returns_ 1 env kill -l INVALID TERM || fail=1
+
+Exit $fail
diff --git a/tests/misc/mknod.sh b/tests/misc/mknod.sh
new file mode 100755
index 0000000..de8d4f6
--- /dev/null
+++ b/tests/misc/mknod.sh
@@ -0,0 +1,39 @@
+#!/bin/sh
+# Ensure that mknod, mkfifo, mkdir -m MODE work with a restrictive umask
+
+# Copyright (C) 2004-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ mknod
+
+# Ensure fifos are supported
+mkfifo_or_skip_ fifo
+
+umask 777
+
+mknod -m 734 f1 p || fail=1
+mode=$(ls -dgo f1|cut -b-10)
+test $mode = prwx-wxr-- || fail=1
+
+mkfifo -m 734 f2 || fail=1
+mode=$(ls -dgo f2|cut -b-10)
+test $mode = prwx-wxr-- || fail=1
+
+mkdir -m 734 f3 || fail=1
+mode=$(ls -dgo f3|cut -b-10)
+test $mode = drwx-wxr-- || test $mode = drwx-wsr-- || fail=1
+
+Exit $fail
diff --git a/tests/misc/mktemp.pl b/tests/misc/mktemp.pl
new file mode 100755
index 0000000..01dcf61
--- /dev/null
+++ b/tests/misc/mktemp.pl
@@ -0,0 +1,206 @@
+#!/usr/bin/perl
+# Test "mktemp".
+
+# Copyright (C) 2007-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+use strict;
+
+(my $ME = $0) =~ s|.*/||;
+
+sub check_tmp($$)
+{
+ my ($file, $file_or_dir) = @_;
+
+ my (undef, undef, $mode, undef) = stat $file
+ or die "$ME: failed to stat $file: $!\n";
+ my $required_mode;
+ if ($file_or_dir eq 'D') {
+ -d $file or die "$ME: $file isn't a directory\n";
+ -x $file or die "$ME: $file isn't owner-searchable\n";
+ $required_mode = 0700;
+ } elsif ($file_or_dir eq 'F') {
+ -f $file or die "$ME: $file isn't a regular file\n";
+ $required_mode = 0600;
+ }
+ -r $file or die "$ME: $file isn't owner-readable\n";
+ -w $file or die "$ME: $file isn't owner-writable\n";
+ ($mode & 0777) == $required_mode
+ or die "$ME: $file doesn't have required permissions\n";
+
+ $file_or_dir eq 'D'
+ and do { rmdir $file or die "$ME: failed to rmdir $file: $!\n" };
+ $file_or_dir eq 'F'
+ and do { unlink $file or die "$ME: failed to unlink $file: $!\n" };
+}
+
+# Turn off localization of executable's output.
+@ENV{qw(LANGUAGE LANG LC_ALL)} = ('C') x 3;
+my $prog = 'mktemp';
+my $bad_dir = 'no/such/dir';
+
+my @Tests =
+ (
+ # test-name, [option, option, ...] {OUT=>"expected-output"}
+ #
+ ['too-many', '-q a b',
+ {ERR=>"$prog: too many templates\n"
+ . "Try '$prog --help' for more information.\n"}, {EXIT => 1} ],
+
+ ['too-few-x', '-q foo.XX', {EXIT => 1},
+ {ERR=>"$prog: too few X's in template 'foo.XX'\n"}],
+
+ ['1f', 'bar.XXXX', {OUT => "bar.ZZZZ\n"},
+ {OUT_SUBST => 's,\.....$,.ZZZZ,'},
+ {POST => sub { my ($f) = @_; defined $f or return; chomp $f;
+ check_tmp $f, 'F'; }}
+ ],
+
+ ['2f', '-- -XXXX', {OUT => "-ZZZZ\n"},
+ {OUT_SUBST => 's,-....$,-ZZZZ,'},
+ {POST => sub { my ($f) = @_; defined $f or return; chomp $f;
+ check_tmp $f, 'F'; }}
+ ],
+
+ # Create a temporary directory.
+ ['1d', '-d f.XXXX', {OUT => "f.ZZZZ\n"},
+ {OUT_SUBST => 's,\.....$,.ZZZZ,'},
+ {POST => sub { my ($f) = @_; defined $f or return; chomp $f;
+ check_tmp $f, 'D'; }}
+ ],
+
+ # Use a template consisting solely of X's
+ ['1d-allX', '-d XXXX', {OUT => "ZZZZ\n"},
+ {PRE => sub {mkdir 'XXXX',0755 or die "XXXX: $!\n"}},
+ {OUT_SUBST => 's,^....$,ZZZZ,'},
+ {POST => sub { my ($f) = @_; defined $f or return; chomp $f;
+ check_tmp $f, 'D'; rmdir 'XXXX' or die "rmdir XXXX: $!\n"; }}
+ ],
+
+ # Test -u
+ ['uf', '-u f.XXXX', {OUT => "f.ZZZZ\n"},
+ {OUT_SUBST => 's,\.....$,.ZZZZ,'},
+ {POST => sub { my ($f) = @_; defined $f or return; chomp $f;
+ -e $f and die "dry-run created file"; }}],
+ ['ud', '-d --dry-run d.XXXX', {OUT => "d.ZZZZ\n"},
+ {OUT_SUBST => 's,\.....$,.ZZZZ,'},
+ {POST => sub { my ($f) = @_; defined $f or return; chomp $f;
+ -e $f and die "dry-run created directory"; }}],
+
+ # Test bad templates
+ ['invalid-tl', '-t a/bXXXX',
+ {ERR=>"$prog: invalid template, 'a/bXXXX', "
+ . "contains directory separator\n"}, {EXIT => 1} ],
+
+ ['invalid-t2', '--tmpdir=a /bXXXX',
+ {ERR=>"$prog: invalid template, '/bXXXX'; "
+ . "with --tmpdir, it may not be absolute\n"}, {EXIT => 1} ],
+
+ # Suffix after X.
+ ['suffix1f', 'aXXXXb', {OUT=>"aZZZZb\n"},
+ {OUT_SUBST=>'s,a....b,aZZZZb,'},
+ {POST => sub { my ($f) = @_; defined $f or return; chomp $f;
+ check_tmp $f, 'F'; }}],
+ ['suffix1d', '-d aXXXXb', {OUT=>"aZZZZb\n"},
+ {OUT_SUBST=>'s,a....b,aZZZZb,'},
+ {POST => sub { my ($f) = @_; defined $f or return; chomp $f;
+ check_tmp $f, 'D'; }}],
+ ['suffix1u', '-u aXXXXb', {OUT=>"aZZZZb\n"},
+ {OUT_SUBST=>'s,a....b,aZZZZb,'},
+ {POST => sub { my ($f) = @_; defined $f or return; chomp $f;
+ -e $f and die "dry-run created file"; }}],
+
+ ['suffix2f', 'aXXXXaaXXXXa', {OUT=>"aXXXXaaZZZZa\n"},
+ {OUT_SUBST=>'s,a....a$,aZZZZa,'},
+ {POST => sub { my ($f) = @_; defined $f or return; chomp $f;
+ check_tmp $f, 'F'; }}],
+ ['suffix2d', '-d --suffix= aXXXXaaXXXX', {OUT=>"aXXXXaaZZZZ\n"},
+ {OUT_SUBST=>'s,a....$,aZZZZ,'},
+ {POST => sub { my ($f) = @_; defined $f or return; chomp $f;
+ check_tmp $f, 'D'; }}],
+
+ ['suffix3f', '--suffix=b aXXXX', {OUT=>"aZZZZb\n"},
+ {OUT_SUBST=>'s,a....b,aZZZZb,'},
+ {POST => sub { my ($f) = @_; defined $f or return; chomp $f;
+ check_tmp $f, 'F'; }}],
+
+ ['suffix4f', '--suffix=X aXXXX', {OUT=>"aZZZZX\n"},
+ {OUT_SUBST=>'s,^a....,aZZZZ,'},
+ {POST => sub { my ($f) = @_; defined $f or return; chomp $f;
+ check_tmp $f, 'F'; }}],
+
+ ['suffix5f', '--suffix /b aXXXX', {EXIT=>1},
+ {ERR=>"$prog: invalid suffix '/b', contains directory separator\n"}],
+
+ ['suffix6f', 'aXXXX/b', {EXIT=>1},
+ {ERR=>"$prog: invalid suffix '/b', contains directory separator\n"}],
+
+ ['suffix7f', '--suffix= aXXXXb', {EXIT=>1},
+ {ERR=>"$prog: with --suffix, template 'aXXXXb' must end in X\n"}],
+ ['suffix7d', '-d --suffix=aXXXXb ""', {EXIT=>1},
+ {ERR=>"$prog: with --suffix, template '' must end in X\n"}],
+
+ ['suffix8f', 'aXXXX --suffix=b', {OUT=>"aZZZZb\n"},
+ {OUT_SUBST=>'s,^a....,aZZZZ,'},
+ {POST => sub { my ($f) = @_; defined $f or return; chomp $f;
+ check_tmp $f, 'F'; }}],
+
+ ['suffix9f', 'aXXXX --suffix=b', {EXIT=>1},
+ {ENV=>"POSIXLY_CORRECT=1"},
+ {ERR=>"$prog: too many templates\n"
+ . "Try '$prog --help' for more information.\n"}],
+
+ ['suffix10f', 'aXXb', {EXIT => 1},
+ {ERR=>"$prog: too few X's in template 'aXXb'\n"}],
+ ['suffix10d', '-d --suffix=X aXX', {EXIT => 1},
+ {ERR=>"$prog: too few X's in template 'aXXX'\n"}],
+
+ ['suffix11f', '--suffix=.txt', {OUT=>"./tmp.ZZZZZZZZZZ.txt\n"},
+ {ENV=>"TMPDIR=."},
+ {OUT_SUBST=>'s,\..{10}\.,.ZZZZZZZZZZ.,'},
+ {POST => sub { my ($f) = @_; defined $f or return; chomp $f;
+ check_tmp $f, 'F'; }}],
+
+
+ # Test template with subdirectory
+ ['tmp-w-slash', '--tmpdir=. a/bXXXX',
+ {PRE => sub {mkdir 'a',0755 or die "a: $!\n"}},
+ {OUT_SUBST => 's,b....$,bZZZZ,'},
+ {OUT => "./a/bZZZZ\n"},
+ {POST => sub { my ($f) = @_; defined $f or return; chomp $f;
+ check_tmp $f, 'F'; unlink $f; rmdir 'a' or die "rmdir a: $!\n" }}
+ ],
+
+ ['priority-t-tmpdir', "-t -p $bad_dir foo.XXX",
+ {ENV=>"TMPDIR=."},
+ {OUT_SUBST => 's,....$,.ZZZ,'},
+ {OUT => "./foo.ZZZ\n"},
+ ],
+
+ ['pipe-bad-tmpdir',
+ {ENV => "TMPDIR=$bad_dir"},
+ {ERR_SUBST => "s,($bad_dir/)[^']+': .*,\$1...,"},
+ {ERR => "$prog: failed to create file via template '$bad_dir/...\n"},
+ {EXIT => 1}],
+ ['pipe-bad-tmpdir-u', '-u', {OUT => "$bad_dir/tmp.ZZZZZZZZZZ\n"},
+ {ENV => "TMPDIR=$bad_dir"},
+ {OUT_SUBST => 's,\..{10}$,.ZZZZZZZZZZ,'}],
+ );
+
+my $save_temps = $ENV{DEBUG};
+my $verbose = $ENV{VERBOSE};
+
+my $fail = run_tests ($ME, $prog, \@Tests, $save_temps, $verbose);
+exit $fail;
diff --git a/tests/misc/nl.sh b/tests/misc/nl.sh
new file mode 100755
index 0000000..a1e9480
--- /dev/null
+++ b/tests/misc/nl.sh
@@ -0,0 +1,113 @@
+#!/bin/sh
+# exercise nl functionality
+
+# Copyright (C) 2002-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ nl
+getlimits_
+
+echo a | nl > out || fail=1
+echo b | nl -s%n >> out || fail=1
+echo c | nl -n ln >> out || fail=1
+echo d | nl -n rn >> out || fail=1
+echo e | nl -n rz >> out || fail=1
+echo === >> out
+printf 'a\n\n' | nl > t || fail=1; cat -A t >> out
+cat <<\EOF > exp
+ 1 a
+ 1%nb
+1 c
+ 1 d
+000001 e
+===
+ 1^Ia$
+ $
+EOF
+compare exp out || fail=1
+
+# Ensure numbering reset at each delimiter.
+# coreutils <= v8.25 only reset at a page header.
+printf '%s\n' '\:\:\:' a '\:\:' b '\:' c > in.txt || framework_failure_
+nl -ha -fa in.txt > out.tmp || fail=1
+nl -p -ha -fa in.txt >> out.tmp || fail=1
+sed '/^$/d' < out.tmp > out || framework_failure_
+cat <<\EOF > exp
+ 1 a
+ 1 b
+ 1 c
+ 1 a
+ 2 b
+ 3 c
+EOF
+compare exp out || fail=1
+
+# Ensure we only indicate overflow when needing to output overflowed numbers
+returns_ 1 nl -v$INTMAX_OFLOW /dev/null || fail=1
+printf '%s\n' a \\:\\: b > in.txt || framework_failure_
+nl -v$INTMAX_MAX in.txt > out || fail=1
+cat <<EOF > exp
+$INTMAX_MAX a
+
+$INTMAX_MAX b
+EOF
+compare exp out || fail=1
+returns_ 1 nl -p -v$INTMAX_MAX in.txt > out || fail=1
+
+# Test negative iteration
+returns_ 1 nl -i$INTMAX_UFLOW /dev/null || fail=1
+printf '%s\n' a b > in.txt || framework_failure_
+nl -v$INTMAX_MAX -i$INTMAX_MIN in.txt > out || fail=1
+cat <<EOF > exp
+$INTMAX_MAX a
+ -1 b
+EOF
+compare exp out || fail=1
+printf '%s\n' a b c > in.txt || framework_failure_
+returns_ 1 nl -v$INTMAX_MAX -i$INTMAX_MIN in.txt > out || fail=1
+
+# Test GNU extension to --section-delimiter, of disabling section matching
+printf '%s\n' a '\:\:' c > in.txt || framework_failure_
+nl -d '' in.txt > out || fail=1
+cat <<\EOF > exp
+ 1 a
+ 2 \:\:
+ 3 c
+EOF
+compare exp out || fail=1
+
+# Test GNU extension to --section-delimiter, of supporting strings longer than 2
+printf '%s\n' a foofoo c > in.txt || framework_failure_
+nl -d 'foo' in.txt > out || fail=1
+cat <<EOF > exp
+ 1 a
+
+ 1 c
+EOF
+compare exp out || fail=1
+
+# Ensure single char delimiters assume a following ':' character (as per POSIX)
+# coreutils <= v8.32 didn't match single char delimiters at all
+printf '%s\n' a x:x: c > in.txt || framework_failure_
+nl -d 'x' in.txt > out || fail=1
+cat <<EOF > exp
+ 1 a
+
+ 1 c
+EOF
+compare exp out || fail=1
+
+Exit $fail
diff --git a/tests/misc/nohup.sh b/tests/misc/nohup.sh
new file mode 100755
index 0000000..3a598af
--- /dev/null
+++ b/tests/misc/nohup.sh
@@ -0,0 +1,125 @@
+#!/bin/sh
+# test nohup
+
+# Copyright (C) 2003-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ nohup
+
+
+nohup sh -c 'echo stdout; echo stderr 1>&2' 2>err || fail=1
+
+# Be careful. The results of the above nohup command
+# change depending on whether stdin and stdout are redirected.
+if test -t 1; then
+ test "$(cat nohup.out)" = stdout || fail=1
+ if test -t 0; then
+ echo 'nohup: ignoring input and appending output to 'nohup.out'\'
+ else
+ echo 'nohup: appending output to 'nohup.out'\'
+ fi >exp || framework_failure_
+else
+ # Here it should not even exist.
+ test -f nohup.out && fail=1
+ if test -t 0; then
+ echo 'nohup: ignoring input' >exp
+ else
+ rm -f exp
+ fi || framework_failure_
+fi
+echo 'stderr' >> exp || framework_failure_
+
+compare exp err || fail=1
+rm -f nohup.out err exp
+# ----------------------
+
+# Be careful. The results of the following nohup command
+# change depending on whether stderr is redirected.
+nohup sh -c 'echo stdout; echo stderr 1>&2' >out || fail=1
+if test -t 2; then
+ test "$(cat out|tr '\n' -)" = stdout-stderr- || fail=1
+else
+ test "$(cat out|tr '\n' -)" = stdout- || fail=1
+fi
+# It must *not* exist.
+test -f nohup.out && fail=1
+rm -f nohup.out err
+# ----------------------
+
+# Bug present through coreutils 8.0: failure to print advisory message
+# to stderr must be fatal. Requires stdout to be terminal.
+if test -w /dev/full && test -c /dev/full; then
+(
+ # POSIX shells immediately exit the subshell on exec error.
+ # So check we can write to /dev/tty before the exec, which
+ # isn't possible if we've no controlling tty for example.
+ test -c /dev/tty && >/dev/tty || exit 0
+
+ exec >/dev/tty
+ test -t 1 || exit 0
+ returns_ 125 nohup echo hi 2> /dev/full || fail=1
+ test -f nohup.out || fail=1
+ compare /dev/null nohup.out || fail=1
+ rm -f nohup.out
+ exit $fail
+) || fail=1
+fi
+
+nohup no-such-command 2> err
+errno=$?
+if test -t 1; then
+ test $errno = 127 || fail=1
+ # It must exist.
+ test -f nohup.out || fail=1
+ # It must be empty.
+ compare /dev/null nohup.out || fail=1
+fi
+
+cat <<\EOF > exp || framework_failure_
+nohup: appending output to 'nohup.out'
+nohup: cannot run command 'no-such-command': No such file or directory
+EOF
+# Disable these comparisons. Too much variation in 2nd line.
+# compare exp err || fail=1
+rm -f nohup.out err exp
+# ----------------------
+
+touch k; chmod 0 k
+nohup ./k 2> err
+errno=$?
+test $errno = 126 || fail=1
+if test -t 1; then
+ # It must exist.
+ test -f nohup.out || fail=1
+ # It must be empty.
+ compare /dev/null nohup.out || fail=1
+fi
+
+cat <<\EOF > exp || framework_failure_
+nohup: appending output to 'nohup.out'
+nohup: cannot run command './k': Permission denied
+EOF
+# Disable these comparisons. Too much variation in 2nd line.
+# compare exp err || fail=1
+
+# Make sure it fails with exit status of 125 when given too few arguments,
+# except that POSIX requires 127 in this case.
+returns_ 125 nohup >/dev/null 2>&1 || fail=1
+export POSIXLY_CORRECT=1
+returns_ 127 nohup >/dev/null 2>&1 || fail=1
+unset POSIXLY_CORRECT
+
+Exit $fail
diff --git a/tests/misc/numfmt.pl b/tests/misc/numfmt.pl
new file mode 100755
index 0000000..86fb78f
--- /dev/null
+++ b/tests/misc/numfmt.pl
@@ -0,0 +1,1125 @@
+#!/usr/bin/perl
+# Basic tests for "numfmt".
+
+# Copyright (C) 2012-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+use strict;
+
+(my $program_name = $0) =~ s|.*/||;
+my $prog = 'numfmt';
+
+my $limits = getlimits ();
+
+# TODO: add localization tests with "grouping"
+# Turn off localization of executable's output.
+@ENV{qw(LANGUAGE LANG LC_ALL)} = ('C') x 3;
+
+my $locale = $ENV{LOCALE_FR_UTF8};
+! defined $locale || $locale eq 'none'
+ and $locale = 'C';
+
+my $try = "Try '$prog --help' for more information.\n";
+
+my @Tests =
+ (
+ ['1', '1234', {OUT => "1234"}],
+ ['2', '--from=si 1K', {OUT => "1000"}],
+ ['3', '--from=iec 1K', {OUT => "1024"}],
+ ['4', '--from=auto 1K', {OUT => "1000"}],
+ ['5', '--from=auto 1Ki', {OUT => "1024"}],
+ ['5.1', '--from=iec-i 1Ki', {OUT => "1024"}],
+
+ ['6', {IN_PIPE => "1234\n"}, {OUT => "1234"}],
+ ['7', '--from=si', {IN_PIPE => "2K\n"}, {OUT => "2000"}],
+ ['7a', '--invalid=fail', {IN_PIPE => "no_NL"}, {OUT => "no_NL"},
+ {ERR => "$prog: invalid number: 'no_NL'\n"},
+ {EXIT => '2'}],
+
+ ['8', '--to=si 2000', {OUT => "2.0K"}],
+ ['9', '--to=si 2001', {OUT => "2.1K"}],
+ ['10', '--to=si 1999', {OUT => "2.0K"}],
+ ['11', '--to=si --round=down 2001', {OUT => "2.0K"}],
+ ['12', '--to=si --round=down 1999', {OUT => "1.9K"}],
+ ['13', '--to=si --round=up 1901', {OUT => "2.0K"}],
+ ['14', '--to=si --round=down 1901', {OUT => "1.9K"}],
+ ['15', '--to=si --round=nearest 1901', {OUT => "1.9K"}],
+ ['16', '--to=si --round=nearest 1945', {OUT => "1.9K"}],
+ ['17', '--to=si --round=nearest 1955', {OUT => "2.0K"}],
+
+ ['18', '--to=iec 2048', {OUT => "2.0K"}],
+ ['19', '--to=iec 2049', {OUT => "2.1K"}],
+ ['20', '--to=iec 2047', {OUT => "2.0K"}],
+ ['21', '--to=iec --round=down 2049', {OUT => "2.0K"}],
+ ['22', '--to=iec --round=down 2047', {OUT => "1.9K"}],
+ ['23', '--to=iec --round=up 2040', {OUT => "2.0K"}],
+ ['24', '--to=iec --round=down 2040', {OUT => "1.9K"}],
+ ['25', '--to=iec --round=nearest 1996', {OUT => "1.9K"}],
+ ['26', '--to=iec --round=nearest 1997', {OUT => "2.0K"}],
+ ['27', '--to=iec-i 2048', {OUT => "2.0Ki"}],
+
+ ['neg-1', '-- -1234', {OUT => "-1234"}],
+ ['neg-2', '--padding=5 -- -1234', {OUT => "-1234"}],
+ ['neg-3', '--padding=6 -- -1234', {OUT => " -1234"}],
+ ['neg-4', '--to=iec -- 9100 -9100', {OUT => "8.9K\n-8.9K"}],
+ ['neg-5', '-- -0.1', {OUT => "-0.1"}],
+ ['neg-6', '-- -0', {OUT => "0"}],
+ ['neg-7', '-- -0.-1',
+ {ERR => "$prog: invalid number: '-0.-1'\n"},
+ {EXIT => '2'}],
+
+ ['float-1', '1.1', {OUT => "1.1"}],
+ ['float-2', '1.22', {OUT => "1.22"}],
+ ['float-3', '1.22.',
+ {ERR => "$prog: invalid suffix in input: '1.22.'\n"},
+ {EXIT => '2'}],
+
+ ['unit-1', '--from-unit=512 4', {OUT => "2048"}],
+ ['unit-2', '--to-unit=512 2048', {OUT => "4"}],
+ ['unit-3', '--from-unit=512 --from=si 4M', {OUT => "2048000000"}],
+ ['unit-4', '--from-unit=512 --from=iec --to=iec 4M', {OUT => "2.0G"}],
+ ['unit-5', '--from-unit=AA --from=iec --to=iec 4M',
+ {ERR => "$prog: invalid unit size: 'AA'\n"},
+ {EXIT => '1'}],
+ ['unit-6', '--from-unit=54W --from=iec --to=iec 4M',
+ {ERR => "$prog: invalid unit size: '54W'\n"},
+ {EXIT => '1'}],
+ ['unit-7', '--from-unit=K 30', {OUT=>"30000"}],
+ ['unit-7.1', '--from-unit=Ki 30', {OUT=>"30720"}],
+ ['unit-7.2', '--from-unit=i 0',
+ {ERR => "$prog: invalid unit size: 'i'\n"},
+ {EXIT => '1'}],
+ ['unit-7.3', '--from-unit=1i 0',
+ {ERR => "$prog: invalid unit size: '1i'\n"},
+ {EXIT => '1'}],
+ ['unit-8', '--from-unit='.$limits->{UINTMAX_OFLOW}.' --to=iec 30',
+ {ERR => "$prog: invalid unit size: '$limits->{UINTMAX_OFLOW}'\n"},
+ {EXIT => '1'}],
+ ['unit-9', '--from-unit=0 1',
+ {ERR => "$prog: invalid unit size: '0'\n"},
+ {EXIT => '1'}],
+ ['unit-10', '--to-unit=0 1',
+ {ERR => "$prog: invalid unit size: '0'\n"},
+ {EXIT => '1'}],
+
+ # Test Suffix logic
+ ['suf-1', '4000', {OUT=>'4000'}],
+ ['suf-2', '4J',
+ {ERR => "$prog: invalid suffix in input: '4J'\n"},
+ {EXIT => '2'}],
+ ['suf-2.1', '4M',
+ {ERR => "$prog: rejecting suffix " .
+ "in input: '4M' (consider using --from)\n"},
+ {EXIT => '2'}],
+ ['suf-3', '--from=si 4M', {OUT=>'4000000'}],
+ ['suf-4', '--from=si 4J',
+ {ERR => "$prog: invalid suffix in input: '4J'\n"},
+ {EXIT => '2'}],
+ ['suf-5', '--from=si 4MJ',
+ {ERR => "$prog: invalid suffix in input '4MJ': 'J'\n"},
+ {EXIT => '2'}],
+
+ ['suf-6', '--from=iec 4M', {OUT=>'4194304'}],
+ ['suf-7', '--from=auto 4M', {OUT=>'4000000'}],
+ ['suf-8', '--from=auto 4Mi', {OUT=>'4194304'}],
+ ['suf-9', '--from=auto 4MiJ',
+ {ERR => "$prog: invalid suffix in input '4MiJ': 'J'\n"},
+ {EXIT => '2'}],
+ ['suf-10', '--from=auto 4JiJ',
+ {ERR => "$prog: invalid suffix in input: '4JiJ'\n"},
+ {EXIT => '2'}],
+
+ # characters after a white space are OK - printed as-is
+ ['suf-11', '"4 M"', {OUT=>'4 M'}],
+
+ # Custom suffix
+ ['suf-12', '--suffix=Foo 70Foo', {OUT=>'70Foo'}],
+ ['suf-13', '--suffix=Foo 70', {OUT=>'70Foo'}],
+ ['suf-14', '--suffix=Foo --from=si 70K', {OUT=>'70000Foo'}],
+ ['suf-15', '--suffix=Foo --from=si 70KFoo', {OUT=>'70000Foo'}],
+ ['suf-16', '--suffix=Foo --to=si 7000Foo', {OUT=>'7.0KFoo'}],
+ ['suf-17', '--suffix=Foo --to=si 7000Bar',
+ {ERR => "$prog: invalid suffix in input: '7000Bar'\n"},
+ {EXIT => '2'}],
+ ['suf-18', '--suffix=Foo --to=si 7000FooF',
+ {ERR => "$prog: invalid suffix in input: '7000FooF'\n"},
+ {EXIT => '2'}],
+ # space(s) between number and suffix. Note only field 1 is used
+ # by default so specify the NUL delimiter to consider the whole "line".
+ ['suf-19', "-d '' --from=si '4.0 K'", {OUT => "4000"}],
+
+ ## GROUPING
+
+ # "C" locale - no grouping (locale-specific tests, below)
+ ['grp-1', '--from=si --grouping 7M', {OUT=>'7000000'}],
+ ['grp-2', '--from=si --to=si --grouping 7M',
+ {ERR => "$prog: grouping cannot be combined with --to\n"},
+ {EXIT => '1'}],
+
+
+ ## Padding
+ ['pad-1', '--padding=10 5', {OUT=>' 5'}],
+ ['pad-2', '--padding=-10 5', {OUT=>'5 '}],
+ ['pad-3', '--padding=A 5',
+ {ERR => "$prog: invalid padding value 'A'\n"},
+ {EXIT => '1'}],
+ ['pad-3.1', '--padding=0 5',
+ {ERR => "$prog: invalid padding value '0'\n"},
+ {EXIT => '1'}],
+ ['pad-3.2', "--padding=$limits->{LONG_MIN} 0",
+ {ERR => "$prog: invalid padding value '$limits->{LONG_MIN}'\n"},
+ {EXIT => '1'}],
+ ['pad-4', '--padding=10 --to=si 50000', {OUT=>' 50K'}],
+ ['pad-5', '--padding=-10 --to=si 50000', {OUT=>'50K '}],
+
+ # padding too narrow
+ ['pad-6', '--padding=2 --to=si 1000', {OUT=>'1.0K'}],
+
+
+ # Padding + suffix
+ ['pad-7', '--padding=10 --suffix=foo --to=si 50000',
+ {OUT=>' 50Kfoo'}],
+ ['pad-8', '--padding=-10 --suffix=foo --to=si 50000',
+ {OUT=>'50Kfoo '}],
+
+
+ # Delimiters
+ ['delim-1', '--delimiter=: --from=auto 40M:', {OUT=>'40000000:'}],
+ ['delim-2', '--delimiter="" --from=auto "40 M"',{OUT=>'40000000'}],
+ ['delim-3', '--delimiter=" " --from=auto "40M Foo"',{OUT=>'40000000 Foo'}],
+ ['delim-4', '--delimiter=: --from=auto 40M:60M', {OUT=>'40000000:60M'}],
+ ['delim-5', '-d: --field=2 --from=auto :40M:60M', {OUT=>':40000000:60M'}],
+ ['delim-6', '-d: --field 3 --from=auto 40M:60M', {OUT=>"40M:60M"}],
+ ['delim-err-1', '-d,, --to=si 1', {EXIT=>1},
+ {ERR => "$prog: the delimiter must be a single character\n"}],
+
+ #Fields
+ ['field-1', '--field A',
+ {ERR => "$prog: invalid field value 'A'\n$try"},
+ {EXIT => '1'}],
+ ['field-2', '--field 2 --from=auto "Hello 40M World 90G"',
+ {OUT=>'Hello 40000000 World 90G'}],
+ ['field-3', '--field 3 --from=auto "Hello 40M World 90G"',
+ {OUT=>"Hello 40M "},
+ {ERR=>"$prog: invalid number: 'World'\n"},
+ {EXIT => 2},],
+ # Last field - no text after number
+ ['field-4', '--field 4 --from=auto "Hello 40M World 90G"',
+ {OUT=>"Hello 40M World 90000000000"}],
+ # Last field - a delimiter after the number
+ ['field-5', '--field 4 --from=auto "Hello 40M World 90G "',
+ {OUT=>"Hello 40M World 90000000000 "}],
+
+ # Mix Fields + Delimiters
+ ['field-6', '--delimiter=: --field 2 --from=auto "Hello:40M:World:90G"',
+ {OUT=>"Hello:40000000:World:90G"}],
+
+ # not enough fields
+ ['field-8', '--field 3 --to=si "Hello World"', {OUT=>"Hello World"}],
+
+ # Multiple fields
+ ['field-range-1', '--field 2,4 --to=si "1000 2000 3000 4000 5000"',
+ {OUT=>"1000 2.0K 3000 4.0K 5000"}],
+
+ ['field-range-2', '--field 2-4 --to=si "1000 2000 3000 4000 5000"',
+ {OUT=>"1000 2.0K 3.0K 4.0K 5000"}],
+
+ ['field-range-3', '--field 1,2,3-5 --to=si "1000 2000 3000 4000 5000"',
+ {OUT=>"1.0K 2.0K 3.0K 4.0K 5.0K"}],
+
+ ['field-range-4', '--field 1-5 --to=si "1000 2000 3000 4000 5000"',
+ {OUT=>"1.0K 2.0K 3.0K 4.0K 5.0K"}],
+
+ ['field-range-5', '--field 1-3,5 --to=si "1000 2000 3000 4000 5000"',
+ {OUT=>"1.0K 2.0K 3.0K 4000 5.0K"}],
+
+ ['field-range-6', '--field 3- --to=si "1000 2000 3000 4000 5000"',
+ {OUT=>"1000 2000 3.0K 4.0K 5.0K"}],
+
+ ['field-range-7', '--field -3 --to=si "1000 2000 3000 4000 5000"',
+ {OUT=>"1.0K 2.0K 3.0K 4000 5000"}],
+
+ ['field-range-8', '--field 1-2,4-5 --to=si "1000 2000 3000 4000 5000"',
+ {OUT=>"1.0K 2.0K 3000 4.0K 5.0K"}],
+ ['field-range-9', '--field 4-5,1-2 --to=si "1000 2000 3000 4000 5000"',
+ {OUT=>"1.0K 2.0K 3000 4.0K 5.0K"}],
+
+ ['field-range-10','--field 1-3,2-4 --to=si "1000 2000 3000 4000 5000"',
+ {OUT=>"1.0K 2.0K 3.0K 4.0K 5000"}],
+ ['field-range-11','--field 2-4,1-3 --to=si "1000 2000 3000 4000 5000"',
+ {OUT=>"1.0K 2.0K 3.0K 4.0K 5000"}],
+
+ ['field-range-12','--field 1-1,3-3 --to=si "1000 2000 3000 4000 5000"',
+ {OUT=>"1.0K 2000 3.0K 4000 5000"}],
+
+ ['field-range-13', '--field 1,-2 --to=si "1000 2000 3000"',
+ {OUT=>"1.0K 2.0K 3000"}],
+
+ ['field-range-14', '--field -2,4- --to=si "1000 2000 3000 4000 5000"',
+ {OUT=>"1.0K 2.0K 3000 4.0K 5.0K"}],
+ ['field-range-15', '--field -2,-4 --to=si "1000 2000 3000 4000 5000"',
+ {OUT=>"1.0K 2.0K 3.0K 4.0K 5000"}],
+ ['field-range-16', '--field 2-,4- --to=si "1000 2000 3000 4000 5000"',
+ {OUT=>"1000 2.0K 3.0K 4.0K 5.0K"}],
+ ['field-range-17', '--field 4-,2- --to=si "1000 2000 3000 4000 5000"',
+ {OUT=>"1000 2.0K 3.0K 4.0K 5.0K"}],
+
+ # white space are valid field separators
+ # (undocumented? but works in cut as well).
+ ['field-range-18', '--field "1,2 4" --to=si "1000 2000 3000 4000 5000"',
+ {OUT=>"1.0K 2.0K 3000 4.0K 5000"}],
+
+ # Unlike 'cut', a lone '-' means 'all fields', even as part of a list
+ # of fields.
+ ['field-range-19','--field 3,- --to=si "1000 2000 3000 4000 5000"',
+ {OUT=>"1.0K 2.0K 3.0K 4.0K 5.0K"}],
+
+ ['all-fields-1', '--field=- --to=si "1000 2000 3000 4000 5000"',
+ {OUT=>"1.0K 2.0K 3.0K 4.0K 5.0K"}],
+
+ ['field-range-err-1', '--field -foo --to=si 10',
+ {EXIT=>1}, {ERR=>"$prog: invalid field value 'foo'\n$try"}],
+ ['field-range-err-2', '--field --3 --to=si 10',
+ {EXIT=>1}, {ERR=>"$prog: invalid field range\n$try"}],
+ ['field-range-err-3', '--field 0 --to=si 10',
+ {EXIT=>1}, {ERR=>"$prog: fields are numbered from 1\n$try"}],
+ ['field-range-err-4', '--field 3-2 --to=si 10',
+ {EXIT=>1}, {ERR=>"$prog: invalid decreasing range\n$try"}],
+ ['field-range-err-6', '--field - --field 1- --to=si 10',
+ {EXIT=>1}, {ERR=>"$prog: multiple field specifications\n"}],
+ ['field-range-err-7', '--field -1 --field 1- --to=si 10',
+ {EXIT=>1}, {ERR=>"$prog: multiple field specifications\n"}],
+ ['field-range-err-8', '--field -1 --field 1,2,3 --to=si 10',
+ {EXIT=>1}, {ERR=>"$prog: multiple field specifications\n"}],
+ ['field-range-err-9', '--field 1- --field 1,2,3 --to=si 10',
+ {EXIT=>1}, {ERR=>"$prog: multiple field specifications\n"}],
+ ['field-range-err-10','--field 1,2,3 --field 1- --to=si 10',
+ {EXIT=>1}, {ERR=>"$prog: multiple field specifications\n"}],
+ ['field-range-err-11','--field 1-2-3 --to=si 10',
+ {EXIT=>1}, {ERR=>"$prog: invalid field range\n$try"}],
+ ['field-range-err-12','--field 0-1 --to=si 10',
+ {EXIT=>1}, {ERR=>"$prog: fields are numbered from 1\n$try"}],
+ ['field-range-err-13','--field '.$limits->{UINTMAX_MAX}.',22 --to=si 10',
+ {EXIT=>1}, {ERR=>"$prog: field number " .
+ "'".$limits->{UINTMAX_MAX}."' is too large\n$try"}],
+
+ # Auto-consume white-space, setup auto-padding
+ ['whitespace-1', '--to=si --field 2 "A 500 B"', {OUT=>"A 500 B"}],
+ ['whitespace-2', '--to=si --field 2 "A 5000 B"', {OUT=>"A 5.0K B"}],
+ ['whitespace-3', '--to=si " 500"', {OUT=>" 500"}],
+ ['whitespace-4', '--to=si " 6500"', {OUT=>" 6.5K"}],
+ # NOTE: auto-padding is not enabled if the value is on the first
+ # field and there's no white-space before it.
+ ['whitespace-5', '--to=si "6000000"', {OUT=>"6.0M"}],
+ # but if there is whitespace, assume auto-padding is desired.
+ ['whitespace-6', '--to=si " 6000000"', {OUT=>" 6.0M"}],
+
+ # auto-padding - lines have same padding-width
+ # (padding_buffer will be alloc'd just once)
+ ['whitespace-7', '--to=si --field 2',
+ {IN_PIPE=>"rootfs 100000\n" .
+ "udevxx 2000000\n"},
+ {OUT =>"rootfs 100K\n" .
+ "udevxx 2.0M"}],
+ # auto-padding - second line requires a
+ # larger padding (padding-buffer needs to be realloc'd)
+ ['whitespace-8', '--to=si --field 2',
+ {IN_PIPE=>"rootfs 100000\n" .
+ "udev 20000000\n"},
+ {OUT =>"rootfs 100K\n" .
+ "udev 20M"}],
+
+
+ # Corner-cases:
+ # weird mix of identical suffix,delimiters
+ # The priority is:
+ # 1. delimiters (and fields) are parsed (in process_line()
+ # 2. optional custom suffix is removed (in process_suffixed_number())
+ # 3. Remaining suffixes must be valid SI/IEC (in human_xstrtol())
+
+ # custom suffix comes BEFORE SI/IEC suffix,
+ # so these are 40 of "M", not 40,000,000.
+ ['mix-1', '--suffix=M --from=si 40M', {OUT=>"40M"}],
+
+ # These are forty-million Ms .
+ ['mix-2', '--suffix=M --from=si 40MM', {OUT=>"40000000M"}],
+
+ ['mix-3', '--suffix=M --from=auto 40MM', {OUT=>"40000000M"}],
+ ['mix-4', '--suffix=M --from=auto 40MiM', {OUT=>"41943040M"}],
+ ['mix-5', '--suffix=M --to=si --from=si 4MM', {OUT=>"4.0MM"}],
+
+ # This might be confusing to the user, but it's legit:
+ # The M in the output is the custom suffix, not Mega.
+ ['mix-6', '--suffix=M 40', {OUT=>"40M"}],
+ ['mix-7', '--suffix=M 4000000', {OUT=>"4000000M"}],
+ ['mix-8', '--suffix=M --to=si 4000000', {OUT=>"4.0MM"}],
+
+ # The output 'M' is the custom suffix.
+ ['mix-10', '--delimiter=M --suffix=M 40', {OUT=>"40M"}],
+
+ # The INPUT 'M' is a delimiter (delimiters are top priority)
+ # The output contains one M for custom suffix, and one 'M' delimiter.
+ ['mix-11', '--delimiter=M --suffix=M 40M', {OUT=>"40MM"}],
+
+ # Same as above, the "M" is NOT treated as a mega SI prefix,
+ ['mix-12', '--delimiter=M --from=si --suffix=M 40M', {OUT=>"40MM"}],
+
+ # The 'M' is treated as a delimiter, and so the input value is '4000'
+ ['mix-13', '--delimiter=M --to=si --from=auto 4000M5000M9000',
+ {OUT=>"4.0KM5000M9000"}],
+ # 'M' is the delimiter, so the second input field is '5000'
+ ['mix-14', '--delimiter=M --field 2 --from=auto --to=si 4000M5000M9000',
+ {OUT=>"4000M5.0KM9000"}],
+
+
+
+ ## Header testing
+
+ # header - silently ignored with command line parameters
+ ['header-1', '--header --to=iec 4096', {OUT=>"4.0K"}],
+
+ # header warning with --debug
+ ['header-2', '--debug --header --to=iec 4096', {OUT=>"4.0K"},
+ {ERR=>"$prog: --header ignored with command-line input\n"}],
+
+ ['header-3', '--header=A',
+ {ERR=>"$prog: invalid header value 'A'\n"},
+ {EXIT => 1},],
+ ['header-4', '--header=0',
+ {ERR=>"$prog: invalid header value '0'\n"},
+ {EXIT => 1},],
+ ['header-5', '--header=-6',
+ {ERR=>"$prog: invalid header value '-6'\n"},
+ {EXIT => 1},],
+ ['header-6', '--debug --header --to=iec',
+ {IN_PIPE=>"size\n5000\n90000\n"},
+ {OUT=>"size\n4.9K\n88K"}],
+ ['header-7', '--debug --header=3 --to=iec',
+ {IN_PIPE=>"hello\nworld\nsize\n5000\n90000\n"},
+ {OUT=>"hello\nworld\nsize\n4.9K\n88K"}],
+ # header, but no actual content
+ ['header-8', '--header=2 --to=iec',
+ {IN_PIPE=>"hello\nworld\n"},
+ {OUT=>"hello\nworld"}],
+ # not enough header lines
+ ['header-9', '--header=3 --to=iec',
+ {IN_PIPE=>"hello\nworld\n"},
+ {OUT=>"hello\nworld"}],
+
+
+ ## human_strtod testing
+
+ # NO_DIGITS_FOUND
+ ['strtod-1', '--from=si "foo"',
+ {ERR=>"$prog: invalid number: 'foo'\n"},
+ {EXIT=> 2}],
+ ['strtod-2', '--from=si ""',
+ {ERR=>"$prog: invalid number: ''\n"},
+ {EXIT=> 2}],
+
+ # FRACTION_NO_DIGITS_FOUND
+ ['strtod-5', '--from=si 12.',
+ {ERR=>"$prog: invalid number: '12.'\n"},
+ {EXIT=>2}],
+ ['strtod-6', '--from=si 12.K',
+ {ERR=>"$prog: invalid number: '12.K'\n"},
+ {EXIT=>2}],
+
+ # whitespace is not allowed after decimal-point
+ ['strtod-6.1', '--from=si --delimiter=, "12. 2"',
+ {ERR=>"$prog: invalid number: '12. 2'\n"},
+ {EXIT=>2}],
+
+ # INVALID_SUFFIX
+ ['strtod-9', '--from=si 12.2J',
+ {ERR=>"$prog: invalid suffix in input: '12.2J'\n"},
+ {EXIT=>2}],
+
+ # VALID_BUT_FORBIDDEN_SUFFIX
+ ['strtod-10', '12M',
+ {ERR => "$prog: rejecting suffix " .
+ "in input: '12M' (consider using --from)\n"},
+ {EXIT=>2}],
+
+ # MISSING_I_SUFFIX
+ ['strtod-11', '--from=iec-i 12M',
+ {ERR => "$prog: missing 'i' suffix in input: " .
+ "'12M' (e.g Ki/Mi/Gi)\n"},
+ {EXIT=>2}],
+
+ #
+ # Test double_to_human()
+ #
+
+ # 1K and smaller
+ ['dbl-to-human-1','--to=si 800', {OUT=>"800"}],
+ ['dbl-to-human-2','--to=si 0', {OUT=>"0"}],
+ ['dbl-to-human-2.1','--to=si 999', {OUT=>"999"}],
+ ['dbl-to-human-2.2','--to=si 1000', {OUT=>"1.0K"}],
+ #NOTE: the following are consistent with "ls -lh" output
+ ['dbl-to-human-2.3','--to=iec 999', {OUT=>"999"}],
+ ['dbl-to-human-2.4','--to=iec 1023', {OUT=>"1023"}],
+ ['dbl-to-human-2.5','--to=iec 1024', {OUT=>"1.0K"}],
+ ['dbl-to-human-2.6','--to=iec 1025', {OUT=>"1.1K"}],
+ ['dbl-to-human-2.7','--to=iec 0', {OUT=>"0"}],
+ # no "i" suffix if output has no suffix
+ ['dbl-to-human-2.8','--to=iec-i 0', {OUT=>"0"}],
+
+ # values resulting in "N.Nx" output
+ ['dbl-to-human-3','--to=si 8000', {OUT=>"8.0K"}],
+ ['dbl-to-human-3.1','--to=si 8001', {OUT=>"8.1K"}],
+ ['dbl-to-human-4','--to=si --round=down 8001', {OUT=>"8.0K"}],
+
+ ['dbl-to-human-5','--to=si --round=down 3500', {OUT=>"3.5K"}],
+ ['dbl-to-human-6','--to=si --round=nearest 3500', {OUT=>"3.5K"}],
+ ['dbl-to-human-7','--to=si --round=up 3500', {OUT=>"3.5K"}],
+
+ ['dbl-to-human-8','--to=si --round=down 3501', {OUT=>"3.5K"}],
+ ['dbl-to-human-9','--to=si --round=nearest 3501', {OUT=>"3.5K"}],
+ ['dbl-to-human-10','--to=si --round=up 3501', {OUT=>"3.6K"}],
+
+ ['dbl-to-human-11','--to=si --round=nearest 3550', {OUT=>"3.6K"}],
+ ['dbl-to-human-12','--to=si --from=si 999.89K', {OUT=>"1.0M"}],
+ ['dbl-to-human-13','--to=si --from=si 9.9K', {OUT=>"9.9K"}],
+ ['dbl-to-human-14','--to=si 9900', {OUT=>"9.9K"}],
+ ['dbl-to-human-15','--to=iec --from=si 3.3K', {OUT=>"3.3K"}],
+ ['dbl-to-human-16','--to=iec --round=down --from=si 3.3K', {OUT=>"3.2K"}],
+
+ # values resulting in 'NNx' output
+ ['dbl-to-human-17','--to=si 9999', {OUT=>"10K"}],
+ ['dbl-to-human-18','--to=si --round=down 35000', {OUT=>"35K"}],
+ ['dbl-to-human-19','--to=iec 35000', {OUT=>"35K"}],
+ ['dbl-to-human-20','--to=iec --round=down 35000', {OUT=>"34K"}],
+ ['dbl-to-human-21','--to=iec 35000000', {OUT=>"34M"}],
+ ['dbl-to-human-22','--to=iec --round=down 35000000', {OUT=>"33M"}],
+ ['dbl-to-human-23','--to=si 35000001', {OUT=>"36M"}],
+ ['dbl-to-human-24','--to=si --from=si 9.99M', {OUT=>"10M"}],
+ ['dbl-to-human-25','--to=si --from=iec 9.99M', {OUT=>"11M"}],
+ ['dbl-to-human-25.1','--to=iec 99999', {OUT=>"98K"}],
+
+ # values resulting in 'NNNx' output
+ ['dbl-to-human-26','--to=si 999000000000', {OUT=>"999G"}],
+ ['dbl-to-human-27','--to=iec 999000000000', {OUT=>"931G"}],
+ ['dbl-to-human-28','--to=si 123600000000000', {OUT=>"124T"}],
+ ['dbl-to-human-29','--to=si 998123', {OUT=>"999K"}],
+ ['dbl-to-human-30','--to=si --round=nearest 998123', {OUT=>"998K"}],
+ ['dbl-to-human-31','--to=si 99999', {OUT=>"100K"}],
+ ['dbl-to-human-32','--to=iec 102399', {OUT=>"100K"}],
+ ['dbl-to-human-33','--to=iec-i 102399', {OUT=>"100Ki"}],
+
+
+ # Default --round=from-zero
+ ['round-1','--to-unit=1024 -- 6000 -6000',
+ {OUT=>"6\n-6"}],
+ ['round-2','--to-unit=1024 -- 6000.0 -6000.0',
+ {OUT=>"5.9\n-5.9"}],
+ ['round-3','--to-unit=1024 -- 6000.00 -6000.00',
+ {OUT=>"5.86\n-5.86"}],
+ ['round-4','--to-unit=1024 -- 6000.000 -6000.000',
+ {OUT=>"5.860\n-5.860"}],
+ ['round-5','--to-unit=1024 -- 6000.0000 -6000.0000',
+ {OUT=>"5.8594\n-5.8594"}],
+ # --round=up
+ ['round-1-up','--round=up --to-unit=1024 -- 6000 -6000',
+ {OUT=>"6\n-5"}],
+ ['round-2-up','--round=up --to-unit=1024 -- 6000.0 -6000.0',
+ {OUT=>"5.9\n-5.8"}],
+ ['round-3-up','--round=up --to-unit=1024 -- 6000.00 -6000.00',
+ {OUT=>"5.86\n-5.85"}],
+ ['round-4-up','--round=up --to-unit=1024 -- 6000.000 -6000.000',
+ {OUT=>"5.860\n-5.859"}],
+ ['round-5-up','--round=up --to-unit=1024 -- 6000.0000 -6000.0000',
+ {OUT=>"5.8594\n-5.8593"}],
+ # --round=down
+ ['round-1-down','--round=down --to-unit=1024 -- 6000 -6000',
+ {OUT=>"5\n-6"}],
+ ['round-2-down','--round=down --to-unit=1024 -- 6000.0 -6000.0',
+ {OUT=>"5.8\n-5.9"}],
+ ['round-3-down','--round=down --to-unit=1024 -- 6000.00 -6000.00',
+ {OUT=>"5.85\n-5.86"}],
+ ['round-4-down','--round=down --to-unit=1024 -- 6000.000 -6000.000',
+ {OUT=>"5.859\n-5.860"}],
+ ['round-5-down','--round=down --to-unit=1024 -- 6000.0000 -6000.0000',
+ {OUT=>"5.8593\n-5.8594"}],
+ # --round=towards-zero
+ ['round-1-to-zero','--ro=towards-zero --to-u=1024 -- 6000 -6000',
+ {OUT=>"5\n-5"}],
+ ['round-2-to-zero','--ro=towards-zero --to-u=1024 -- 6000.0 -6000.0',
+ {OUT=>"5.8\n-5.8"}],
+ ['round-3-to-zero','--ro=towards-zero --to-u=1024 -- 6000.00 -6000.00',
+ {OUT=>"5.85\n-5.85"}],
+ ['round-4-to-zero','--ro=towards-zero --to-u=1024 -- 6000.000 -6000.000',
+ {OUT=>"5.859\n-5.859"}],
+ ['round-5-to-zero','--ro=towards-zero --to-u=1024 -- 6000.0000 -6000.0000',
+ {OUT=>"5.8593\n-5.8593"}],
+ # --round=nearest
+ ['round-1-near','--ro=nearest --to-u=1024 -- 6000 -6000',
+ {OUT=>"6\n-6"}],
+ ['round-2-near','--ro=nearest --to-u=1024 -- 6000.0 -6000.0',
+ {OUT=>"5.9\n-5.9"}],
+ ['round-3-near','--ro=nearest --to-u=1024 -- 6000.00 -6000.00',
+ {OUT=>"5.86\n-5.86"}],
+ ['round-4-near','--ro=nearest --to-u=1024 -- 6000.000 -6000.000',
+ {OUT=>"5.859\n-5.859"}],
+ ['round-5-near','--ro=nearest --to-u=1024 -- 6000.0000 -6000.0000',
+ {OUT=>"5.8594\n-5.8594"}],
+
+
+ # Leading zeros weren't handled appropriately before 8.24
+ ['leading-1','0000000000000000000000000001', {OUT=>"1"}],
+ ['leading-2','.1', {OUT=>"0.1"}],
+ ['leading-3','bad.1',
+ {ERR => "$prog: invalid number: 'bad.1'\n"},
+ {EXIT => 2}],
+ ['leading-4','..1',
+ {ERR => "$prog: invalid suffix in input: '..1'\n"},
+ {EXIT => 2}],
+ ['leading-5','1.',
+ {ERR => "$prog: invalid number: '1.'\n"},
+ {EXIT => 2}],
+
+ # precision override
+ ['precision-1','--format=%.4f 9991239123 --to=si', {OUT=>"9.9913G"}],
+ ['precision-2','--format=%.1f 9991239123 --to=si', {OUT=>"10.0G"}],
+ ['precision-3','--format=%.1f 1', {OUT=>"1.0"}],
+ ['precision-4','--format=%.1f 1.12', {OUT=>"1.2"}],
+ ['precision-5','--format=%.1f 9991239123 --to-unit=G', {OUT=>"10.0"}],
+ ['precision-6','--format="% .1f" 9991239123 --to-unit=G', {OUT=>"10.0"}],
+ ['precision-7','--format=%.-1f 1.1',
+ {ERR => "$prog: invalid precision in format '%.-1f'\n"},
+ {EXIT => 1}],
+ ['precision-8','--format=%.+1f 1.1',
+ {ERR => "$prog: invalid precision in format '%.+1f'\n"},
+ {EXIT => 1}],
+ ['precision-9','--format="%. 1f" 1.1',
+ {ERR => "$prog: invalid precision in format '%. 1f'\n"},
+ {EXIT => 1}],
+
+ # debug warnings
+ ['debug-1', '--debug 4096', {OUT=>"4096"},
+ {ERR=>"$prog: no conversion option specified\n"}],
+ # '--padding' is a valid conversion option - no warning should be printed
+ ['debug-1.1', '--debug --padding 10 4096', {OUT=>" 4096"}],
+ ['debug-2', '--debug --grouping --from=si 4.0K', {OUT=>"4000"},
+ {ERR=>"$prog: grouping has no effect in this locale\n"}],
+
+ # dev-debug messages - the actual messages don't matter
+ # just ensure the program works, and for code coverage testing.
+ ['devdebug-1', '---debug --from=si 4.9K', {OUT=>"4900"},
+ {ERR=>""},
+ {ERR_SUBST=>"s/.*//msg"}],
+ ['devdebug-2', '---debug 4900', {OUT=>"4900"},
+ {ERR=>""},
+ {ERR_SUBST=>"s/.*//msg"}],
+ ['devdebug-3', '---debug --from=auto 4Mi', {OUT=>"4194304"},
+ {ERR=>""},
+ {ERR_SUBST=>"s/.*//msg"}],
+ ['devdebug-4', '---debug --to=si 4000000', {OUT=>"4.0M"},
+ {ERR=>""},
+ {ERR_SUBST=>"s/.*//msg"}],
+ ['devdebug-5', '---debug --to=si --padding=5 4000000', {OUT=>" 4.0M"},
+ {ERR=>""},
+ {ERR_SUBST=>"s/.*//msg"}],
+ ['devdebug-6', '---debug --suffix=Foo 1234Foo', {OUT=>"1234Foo"},
+ {ERR=>""},
+ {ERR_SUBST=>"s/.*//msg"}],
+ ['devdebug-7', '---debug --suffix=Foo 1234', {OUT=>"1234Foo"},
+ {ERR=>""},
+ {ERR_SUBST=>"s/.*//msg"}],
+ ['devdebug-9', '---debug --grouping 10000', {OUT=>"10000"},
+ {ERR=>""},
+ {ERR_SUBST=>"s/.*//msg"}],
+ ['devdebug-10', '---debug --format %f 10000', {OUT=>"10000"},
+ {ERR=>""},
+ {ERR_SUBST=>"s/.*//msg"}],
+ ['devdebug-11', '---debug --format "%\'-10f" 10000',{OUT=>"10000 "},
+ {ERR=>""},
+ {ERR_SUBST=>"s/.*//msg"}],
+
+ # Invalid parameters
+ ['help-1', '--foobar',
+ {ERR=>"$prog: unrecognized option\n$try"},
+ {ERR_SUBST=>"s/option.*/option/; s/unknown/unrecognized/"},
+ {EXIT=>1}],
+
+ ## Format string - check error detection
+ ['fmt-err-1', '--format ""',
+ {ERR=>"$prog: format '' has no % directive\n"},
+ {EXIT=>1}],
+ ['fmt-err-2', '--format "hello"',
+ {ERR=>"$prog: format 'hello' has no % directive\n"},
+ {EXIT=>1}],
+ ['fmt-err-3', '--format "hello%"',
+ {ERR=>"$prog: format 'hello%' ends in %\n"},
+ {EXIT=>1}],
+ ['fmt-err-4', '--format "%d"',
+ {ERR=>"$prog: invalid format '%d', " .
+ "directive must be %[0]['][-][N][.][N]f\n"},
+ {EXIT=>1}],
+ ['fmt-err-5', '--format "% -43 f"',
+ {ERR=>"$prog: invalid format '% -43 f', " .
+ "directive must be %[0]['][-][N][.][N]f\n"},
+ {EXIT=>1}],
+ ['fmt-err-6', '--format "%f %f"',
+ {ERR=>"$prog: format '%f %f' has too many % directives\n"},
+ {EXIT=>1}],
+ ['fmt-err-7', '--format "%'.$limits->{LONG_OFLOW}.'f"',
+ {ERR=>"$prog: invalid format '%$limits->{LONG_OFLOW}f'".
+ " (width overflow)\n"},
+ {EXIT=>1}],
+ ['fmt-err-9', '--format "%f" --grouping',
+ {ERR=>"$prog: --grouping cannot be combined with --format\n"},
+ {EXIT=>1}],
+ ['fmt-err-10', '--format "%\'f" --to=si',
+ {ERR=>"$prog: grouping cannot be combined with --to\n"},
+ {EXIT=>1}],
+ ['fmt-err-11', '--debug --format "%\'f" 5000', {OUT=>"5000"},
+ {ERR=>"$prog: grouping has no effect in this locale\n"}],
+
+ ## Format string - check some corner cases
+ ['fmt-1', '--format "%% %f" 5000', {OUT=>"%%5000"}],
+ ['fmt-2', '--format "%f %%" 5000', {OUT=>"5000 %%"}],
+
+ ['fmt-3', '--format "--%f--" 5000000', {OUT=>"--5000000--"}],
+ ['fmt-4', '--format "--%f--" --to=si 5000000', {OUT=>"--5.0M--"}],
+
+ ['fmt-5', '--format "--%10f--" --to=si 5000000',{OUT=>"-- 5.0M--"}],
+ ['fmt-6', '--format "--%-10f--" --to=si 5000000',{OUT=>"--5.0M --"}],
+ ['fmt-7', '--format "--%10f--" 5000000',{OUT=>"-- 5000000--"}],
+ ['fmt-8', '--format "--%-10f--" 5000000',{OUT=>"--5000000 --"}],
+
+ # too-short width
+ ['fmt-9', '--format "--%5f--" 5000000',{OUT=>"--5000000--"}],
+
+ # Format + Suffix
+ ['fmt-10', '--format "--%10f--" --suffix Foo 50', {OUT=>"-- 50Foo--"}],
+ ['fmt-11', '--format "--%-10f--" --suffix Foo 50',{OUT=>"--50Foo --"}],
+
+ # Grouping in C locale - no grouping effect
+ ['fmt-12', '--format "%\'f" 50000',{OUT=>"50000"}],
+ ['fmt-13', '--format "%\'10f" 50000', {OUT=>" 50000"}],
+ ['fmt-14', '--format "%\'-10f" 50000',{OUT=>"50000 "}],
+
+ # Very large format strings
+ ['fmt-15', '--format "--%100000f--" --to=si 4200',
+ {OUT=>"--" . " " x 99996 . "4.2K--" }],
+
+ # --format padding overrides --padding
+ ['fmt-16', '--format="%6f" --padding=66 1234',{OUT=>" 1234"}],
+
+ # zero padding
+ ['fmt-17', '--format="%06f" 1234',{OUT=>"001234"}],
+ # also support spaces (which are ignored as spacing is handled separately)
+ ['fmt-18', '--format="%0 6f" 1234',{OUT=>"001234"}],
+ # handle generic padding in combination
+ ['fmt-22', '--format="%06f" --padding=7 1234',{OUT=>" 001234"}],
+ ['fmt-23', '--format="%06f" --padding=-7 1234',{OUT=>"001234 "}],
+
+
+ ## Check all errors again, this time with --invalid=fail
+ ## Input will be printed without conversion,
+ ## and exit code will be 2
+ ['ign-err-1', '--invalid=fail 4J',
+ {ERR => "$prog: invalid suffix in input: '4J'\n"},
+ {OUT => "4J\n"},
+ {EXIT => 2}],
+ ['ign-err-2', '--invalid=fail 4M',
+ {ERR => "$prog: rejecting suffix " .
+ "in input: '4M' (consider using --from)\n"},
+ {OUT => "4M\n"},
+ {EXIT => 2}],
+ ['ign-err-3', '--invalid=fail --from=si 4MJ',
+ {ERR => "$prog: invalid suffix in input '4MJ': 'J'\n"},
+ {OUT => "4MJ\n"},
+ {EXIT => 2}],
+ ['ign-err-4', '--invalid=fail --suffix=Foo --to=si 7000FooF',
+ {ERR => "$prog: invalid suffix in input: '7000FooF'\n"},
+ {OUT => "7000FooF\n"},
+ {EXIT => 2}],
+ ['ign-err-5','--invalid=fail --field 3 --from=auto "Hello 40M World 90G"',
+ {ERR => "$prog: invalid number: 'World'\n"},
+ {OUT => "Hello 40M World 90G\n"},
+ {EXIT => 2}],
+ ['ign-err-7', '--invalid=fail --from=si "foo"',
+ {ERR => "$prog: invalid number: 'foo'\n"},
+ {OUT => "foo\n"},
+ {EXIT=> 2}],
+ ['ign-err-8', '--invalid=fail 12M',
+ {ERR => "$prog: rejecting suffix " .
+ "in input: '12M' (consider using --from)\n"},
+ {OUT => "12M\n"},
+ {EXIT => 2}],
+ ['ign-err-9', '--invalid=fail --from=iec-i 12M',
+ {ERR => "$prog: missing 'i' suffix in input: " .
+ "'12M' (e.g Ki/Mi/Gi)\n"},
+ {OUT => "12M\n"},
+ {EXIT=>2}],
+
+ ## Ignore Errors with multiple conversions
+ ['ign-err-m1', '--invalid=ignore --to=si 1000 2000 bad 3000',
+ {OUT => "1.0K\n2.0K\nbad\n3.0K"},
+ {EXIT => 0}],
+ ['ign-err-m1.1', '--invalid=ignore --to=si',
+ {IN_PIPE => "1000\n2000\nbad\n3000\n"},
+ {OUT => "1.0K\n2.0K\nbad\n3.0K"},
+ {EXIT => 0}],
+ ['ign-err-m1.3', '--invalid=fail --debug --to=si 1000 2000 3000',
+ {OUT => "1.0K\n2.0K\n3.0K"},
+ {EXIT => 0}],
+ ['ign-err-m2', '--invalid=fail --to=si 1000 Foo 3000',
+ {OUT => "1.0K\nFoo\n3.0K\n"},
+ {ERR => "$prog: invalid number: 'Foo'\n"},
+ {EXIT => 2}],
+ ['ign-err-m2.1', '--invalid=warn --to=si',
+ {IN_PIPE => "1000\nFoo\n3000\n"},
+ {OUT => "1.0K\nFoo\n3.0K"},
+ {ERR => "$prog: invalid number: 'Foo'\n"},
+ {EXIT => 0}],
+
+ # --debug will trigger a final warning at EOF
+ ['ign-err-m2.2', '--invalid=fail --debug --to=si 1000 Foo 3000',
+ {OUT => "1.0K\nFoo\n3.0K\n"},
+ {ERR => "$prog: invalid number: 'Foo'\n" .
+ "$prog: failed to convert some of the input numbers\n"},
+ {EXIT => 2}],
+
+ ['ign-err-m3', '--invalid=fail --field 2 --from=si --to=iec',
+ {IN_PIPE => "A 1K x\nB 2M y\nC 3G z\n"},
+ {OUT => "A 1000 x\nB 2.0M y\nC 2.8G z"},
+ {EXIT => 0}],
+ # invalid input on one of the fields
+ ['ign-err-m3.1', '--invalid=fail --field 2 --from=si --to=iec',
+ {IN_PIPE => "A 1K x\nB Foo y\nC 3G z\n"},
+ {OUT => "A 1000 x\nB Foo y\nC 2.8G z\n"},
+ {ERR => "$prog: invalid number: 'Foo'\n"},
+ {EXIT => 2}],
+ );
+
+# test null-terminated lines
+my @NullDelim_Tests =
+ (
+ # Input from STDIN
+ ['z1', '-z --to=iec',
+ {IN_PIPE => "1025\x002048\x00"}, {OUT=>"1.1K\x002.0K\x00"}],
+
+ # Input from the commandline - terminated by NULL vs NL
+ ['z3', ' --to=iec 1024', {OUT=>"1.0K\n"}],
+ ['z2', '-z --to=iec 1024', {OUT=>"1.0K\x00"}],
+
+ # Input from STDIN, with fields
+ ['z4', '-z --field=3 --to=si',
+ {IN_PIPE => "A B 1001 C\x00" .
+ "D E 2002 F\x00"},
+ {OUT => "A B 1.1K C\x00" .
+ "D E 2.1K F\x00"}],
+
+ # Input from STDIN, with fields and embedded NL
+ ['z5', '-z --field=3 --to=si',
+ {IN_PIPE => "A\nB 1001 C\x00" .
+ "D E\n2002 F\x00"},
+ {OUT => "A B 1.1K C\x00" .
+ "D E 2.1K F\x00"}],
+ );
+
+my @Limit_Tests =
+ (
+ # Large Values
+ ['large-1','1000000000000000', {OUT=>"1000000000000000"}],
+ # 18 digits is OK
+ ['large-2','1000000000000000000', {OUT=>"1000000000000000000"}],
+ # 19 digits is too much (without output scaling)
+ ['large-3','10000000000000000000',
+ {ERR => "$prog: value too large to be printed: '1e+19' " .
+ "(consider using --to)\n"},
+ {EXIT=>2}],
+ ['large-4','1000000000000000000.0',
+ {ERR => "$prog: value/precision too large to be printed: " .
+ "'1e+18/1' (consider using --to)\n"},
+ {EXIT=>2}],
+
+
+ # Test input:
+ # Up to 33 digits is OK.
+ ['large-3.1', '--to=si 1', {OUT=> "1"}],
+ ['large-3.2', '--to=si 10', {OUT=> "10"}],
+ ['large-3.3', '--to=si 100', {OUT=> "100"}],
+ ['large-3.4', '--to=si 1000', {OUT=>"1.0K"}],
+ ['large-3.5', '--to=si 10000', {OUT=> "10K"}],
+ ['large-3.6', '--to=si 100000', {OUT=>"100K"}],
+ ['large-3.7', '--to=si 1000000', {OUT=>"1.0M"}],
+ ['large-3.8', '--to=si 10000000', {OUT=> "10M"}],
+ ['large-3.9', '--to=si 100000000', {OUT=>"100M"}],
+ ['large-3.10','--to=si 1000000000', {OUT=>"1.0G"}],
+ ['large-3.11','--to=si 10000000000', {OUT=> "10G"}],
+ ['large-3.12','--to=si 100000000000', {OUT=>"100G"}],
+ ['large-3.13','--to=si 1000000000000', {OUT=>"1.0T"}],
+ ['large-3.14','--to=si 10000000000000', {OUT=> "10T"}],
+ ['large-3.15','--to=si 100000000000000', {OUT=>"100T"}],
+ ['large-3.16','--to=si 1000000000000000', {OUT=>"1.0P"}],
+ ['large-3.17','--to=si 10000000000000000', {OUT=> "10P"}],
+ ['large-3.18','--to=si 100000000000000000', {OUT=>"100P"}],
+ ['large-3.19','--to=si 1000000000000000000', {OUT=>"1.0E"}],
+ ['large-3.20','--to=si 10000000000000000000', {OUT=> "10E"}],
+ ['large-3.21','--to=si 210000000000000000000', {OUT=>"210E"}],
+ ['large-3.22','--to=si 3210000000000000000000', {OUT=>"3.3Z"}],
+ ['large-3.23','--to=si 43210000000000000000000', {OUT=> "44Z"}],
+ ['large-3.24','--to=si 543210000000000000000000', {OUT=>"544Z"}],
+ ['large-3.25','--to=si 6543210000000000000000000', {OUT=>"6.6Y"}],
+ ['large-3.26','--to=si 76543210000000000000000000', {OUT=> "77Y"}],
+ ['large-3.27','--to=si 876543210000000000000000000', {OUT=>"877Y"}],
+ ['large-3.28','--to=si 9876543210000000000000000000', {OUT=>"9.9R"}],
+ ['large-3.29','--to=si 19876543210000000000000000000', {OUT=> "20R"}],
+ ['large-3.30','--to=si 219876543210000000000000000000', {OUT=>"220R"}],
+ ['large-3.31','--to=si 3219876543210000000000000000000', {OUT=>"3.3Q"}],
+ ['large-3.32','--to=si 43219876543210000000000000000000', {OUT=> "44Q"}],
+ ['large-3.33','--to=si 543219876543210000000000000000000', {OUT=>"544Q"}],
+
+ # More than 33 digits is not OK
+ ['large-3.34','--to=si 6543219876543210000000000000000000',
+ {ERR => "$prog: value too large to be converted: " .
+ "'6543219876543210000000000000000000'\n"},
+ {EXIT => 2}],
+
+ # Test Output
+ ['large-4.1', '--from=si 9.7M', {OUT=>"9700000"}],
+ ['large-4.2', '--from=si 10M', {OUT =>"10000000"}],
+ ['large-4.3', '--from=si 200M', {OUT =>"200000000"}],
+ ['large-4.4', '--from=si 3G', {OUT =>"3000000000"}],
+ ['large-4.5', '--from=si 40G', {OUT =>"40000000000"}],
+ ['large-4.6', '--from=si 500G', {OUT =>"500000000000"}],
+ ['large-4.7', '--from=si 6T', {OUT =>"6000000000000"}],
+ ['large-4.8', '--from=si 70T', {OUT =>"70000000000000"}],
+ ['large-4.9', '--from=si 800T', {OUT =>"800000000000000"}],
+ ['large-4.10','--from=si 9P', {OUT =>"9000000000000000"}],
+ ['large-4.11','--from=si 10P', {OUT =>"10000000000000000"}],
+ ['large-4.12','--from=si 200P', {OUT =>"200000000000000000"}],
+ ['large-4.13','--from=si 3E', {OUT =>"3000000000000000000"}],
+
+ # More than 18 digits of output without scaling - no good.
+ ['large-4.14','--from=si 40E',
+ {ERR => "$prog: value too large to be printed: '4e+19' " .
+ "(consider using --to)\n"},
+ {EXIT => 2}],
+ ['large-4.15','--from=si 500E',
+ {ERR => "$prog: value too large to be printed: '5e+20' " .
+ "(consider using --to)\n"},
+ {EXIT => 2}],
+ ['large-4.16','--from=si 6Z',
+ {ERR => "$prog: value too large to be printed: '6e+21' " .
+ "(consider using --to)\n"},
+ {EXIT => 2}],
+ ['large-4.17','--from=si 70Z',
+ {ERR => "$prog: value too large to be printed: '7e+22' " .
+ "(consider using --to)\n"},
+ {EXIT => 2}],
+ ['large-4.18','--from=si 800Z',
+ {ERR => "$prog: value too large to be printed: '8e+23' " .
+ "(consider using --to)\n"},
+ {EXIT => 2}],
+ ['large-4.19','--from=si 9Y',
+ {ERR => "$prog: value too large to be printed: '9e+24' " .
+ "(consider using --to)\n"},
+ {EXIT => 2}],
+ ['large-4.20','--from=si 10Y',
+ {ERR => "$prog: value too large to be printed: '1e+25' " .
+ "(consider using --to)\n"},
+ {EXIT => 2}],
+ ['large-4.21','--from=si 200Y',
+ {ERR => "$prog: value too large to be printed: '2e+26' " .
+ "(consider using --to)\n"},
+ {EXIT => 2}],
+
+ ['large-5.1','--to=si 1000000000000000000', {OUT=>"1.0E"}],
+ ['large-5','--from=si --to=si 2E', {OUT=>"2.0E"}],
+ ['large-6','--from=si --to=si 3.4Z', {OUT=>"3.4Z"}],
+ ['large-7','--from=si --to=si 80Y', {OUT=>"80Y"}],
+ ['large-8','--from=si --to=si 9000Z', {OUT=>"9.0Y"}],
+
+ ['large-10','--from=si --to=si 999Q', {OUT=>"999Q"}],
+ ['large-11','--from=si --to=iec 999Q', {OUT=>"789Q"}],
+ ['large-12','--from=si --round=down --to=iec 999Q', {OUT=>"788Q"}],
+
+ # units can also affect the output
+ ['large-13','--from=si --from-unit=1000000 9P',
+ {ERR => "$prog: value too large to be printed: '9e+21' " .
+ "(consider using --to)\n"},
+ {EXIT => 2}],
+ ['large-13.1','--from=si --from-unit=1000000 --to=si 9P', {OUT=>"9.0Z"}],
+
+ # Numbers>999Q are never acceptable, regardless of scaling
+ ['large-14','--from=si --to=si 999Q', {OUT=>"999Q"}],
+ ['large-14.1','--from=si --to=si 1000Q',
+ {ERR => "$prog: value too large to be printed: '1e+33' " .
+ "(cannot handle values > 999Q)\n"},
+ {EXIT => 2}],
+ ['large-14.2','--from=si --to=si --from-unit=10000 1Q',
+ {ERR => "$prog: value too large to be printed: '1e+34' " .
+ "(cannot handle values > 999Q)\n"},
+ {EXIT => 2}],
+
+ # intmax_t overflow when rounding caused this to fail before 8.24
+ ['large-15',$limits->{INTMAX_OFLOW}, {OUT=>$limits->{INTMAX_OFLOW}}],
+ ['large-16','9.300000000000000000', {OUT=>'9.300000000000000000'}],
+
+ # INTEGRAL_OVERFLOW
+ ['strtod-3', '--from=si "1234567890123456789012345678901234567890'.
+ '1234567890123456789012345678901234567890"',
+ {ERR=>"$prog: value too large to be converted: '" .
+ "1234567890123456789012345678901234567890" .
+ "1234567890123456789012345678901234567890'\n",
+ },
+ {EXIT=> 2}],
+
+ # FRACTION_OVERFLOW
+ ['strtod-7', '--from=si "12.1234567890123456789012345678901234567890'.
+ '1234567890123456789012345678901234567890"',
+ {ERR=>"$prog: value too large to be converted: '" .
+ "12.1234567890123456789012345678901234567890" .
+ "1234567890123456789012345678901234567890'\n",
+ },
+ {EXIT=> 2}],
+
+ ['debug-4', '--to=si --debug 12345678901234567890',
+ {OUT=>"13E"},
+ {ERR=>"$prog: large input value '12345678901234567890':" .
+ " possible precision loss\n"}],
+ ['debug-5', '--to=si --from=si --debug 1.12345678901234567890Y',
+ {OUT=>"1.2Y"},
+ {ERR=>"$prog: large input value '1.12345678901234567890Y':" .
+ " possible precision loss\n"}],
+
+ ['ign-err-10','--invalid=fail 10000000000000000000',
+ {ERR => "$prog: value too large to be printed: '1e+19' " .
+ "(consider using --to)\n"},
+ {OUT => "10000000000000000000\n"},
+ {EXIT=>2}],
+ ['ign-err-11','--invalid=fail --to=si 6543219876543210000000000000000000',
+ {ERR => "$prog: value too large to be converted: " .
+ "'6543219876543210000000000000000000'\n"},
+ {OUT => "6543219876543210000000000000000000\n"},
+ {EXIT => 2}],
+ );
+# Restrict these tests to systems with LDBL_DIG == 18
+(system "$prog ---debug 1 2>&1|grep 'MAX_UNSCALED_DIGITS: 18' > /dev/null") == 0
+ and push @Tests, @Limit_Tests;
+
+my @Locale_Tests =
+ (
+ # Locale that supports grouping, but without '--grouping' parameter
+ ['lcl-grp-1', '--from=si 7M', {OUT=>"7000000"},
+ {ENV=>"LC_ALL=$locale"}],
+
+ # Locale with grouping
+ ['lcl-grp-2', '--from=si --grouping 7M', {OUT=>"7 000 000"},
+ {ENV=>"LC_ALL=$locale"}],
+
+ # Locale with grouping and debug - no debug warning message
+ ['lcl-grp-3', '--from=si --debug --grouping 7M', {OUT=>"7 000 000"},
+ {ENV=>"LC_ALL=$locale"}],
+
+ # Input with locale'd decimal-point
+ ['lcl-stdtod-1', '--from=si 12,2K', {OUT=>"12200"},
+ {ENV=>"LC_ALL=$locale"}],
+
+ ['lcl-dbl-to-human-1', '--to=si 1100', {OUT=>"1,1K"},
+ {ENV=>"LC_ALL=$locale"}],
+
+ # Format + Grouping
+ ['lcl-fmt-1', '--format "%\'f" 50000',{OUT=>"50 000"},
+ {ENV=>"LC_ALL=$locale"}],
+ ['lcl-fmt-2', '--format "--%\'10f--" 50000', {OUT=>"-- 50 000--"},
+ {ENV=>"LC_ALL=$locale"}],
+ ['lcl-fmt-3', '--format "--%\'-10f--" 50000',{OUT=>"--50 000 --"},
+ {ENV=>"LC_ALL=$locale"}],
+ ['lcl-fmt-4', '--format "--%-10f--" --to=si 5000000',
+ {OUT=>"--5,0M --"},
+ {ENV=>"LC_ALL=$locale"}],
+ # handle zero/grouping in combination
+ ['lcl-fmt-5', '--format="%\'06f" 1234',{OUT=>"01 234"},
+ {ENV=>"LC_ALL=$locale"}],
+ ['lcl-fmt-6', '--format="%0\'6f" 1234',{OUT=>"01 234"},
+ {ENV=>"LC_ALL=$locale"}],
+ ['lcl-fmt-7', '--format="%0\'\'6f" 1234',{OUT=>"01 234"},
+ {ENV=>"LC_ALL=$locale"}],
+
+ );
+if ($locale ne 'C')
+ {
+ # Reset locale to 'C' if LOCALE_FR_UTF8 doesn't output as expected
+ # as determined by the separate printf program.
+ open(LOC_NUM, "env LC_ALL=$locale printf \"%'d\" 1234|")
+ or die "Can't fork command: $!";
+ my $loc_num = <LOC_NUM>;
+ close(LOC_NUM) || die "Failed to read grouped number from printf";
+ if ($loc_num ne '1 234')
+ {
+ warn "skipping locale grouping tests as 1234 groups like $loc_num\n";
+ $locale = 'C';
+ }
+ }
+push @Tests, @Locale_Tests if $locale ne 'C';
+
+## Check all valid/invalid suffixes
+foreach my $suf ( 'A' .. 'Z', 'a' .. 'z' ) {
+ if ( $suf =~ /^[KMGTPEZYRQ]$/ )
+ {
+ push @Tests, ["auto-suf-si-$suf","--from=si --to=si 1$suf",
+ {OUT=>"1.0$suf"}];
+ push @Tests, ["auto-suf-iec-$suf","--from=iec --to=iec 1$suf",
+ {OUT=>"1.0$suf"}];
+ push @Tests, ["auto-suf-auto-$suf","--from=auto --to=iec 1${suf}i",
+ {OUT=>"1.0$suf"}];
+ push @Tests, ["auto-suf-iec-to-ieci-$suf","--from=iec --to=iec-i 1${suf}",
+ {OUT=>"1.0${suf}i"}];
+ push @Tests, ["auto-suf-ieci-to-iec-$suf",
+ "--from=iec-i --to=iec 1${suf}i",{OUT=>"1.0${suf}"}];
+ }
+ else
+ {
+ push @Tests, ["auto-suf-si-$suf","--from=si --to=si 1$suf",
+ {ERR=>"$prog: invalid suffix in input: '1${suf}'\n"},
+ {EXIT=>2}];
+ }
+}
+
+# Prepend the command line argument and append a newline to end
+# of each expected 'OUT' string.
+my $t;
+
+Test:
+foreach $t (@Tests)
+ {
+ # Don't fiddle with expected OUT string if there's a nonzero exit status.
+ foreach my $e (@$t)
+ {
+ ref $e eq 'HASH' && exists $e->{EXIT} && $e->{EXIT}
+ and next Test;
+ }
+
+ foreach my $e (@$t)
+ {
+ ref $e eq 'HASH' && exists $e->{OUT}
+ and $e->{OUT} .= "\n"
+ }
+ }
+
+# Add test for null-terminated lines (after adjusting the OUT string, above).
+push @Tests, @NullDelim_Tests;
+
+my $save_temps = $ENV{SAVE_TEMPS};
+my $verbose = $ENV{VERBOSE};
+
+my $fail = run_tests ($program_name, $prog, \@Tests, $save_temps, $verbose);
+exit $fail;
diff --git a/tests/misc/paste.pl b/tests/misc/paste.pl
new file mode 100755
index 0000000..e14ef1c
--- /dev/null
+++ b/tests/misc/paste.pl
@@ -0,0 +1,74 @@
+#!/usr/bin/perl
+# Test paste.
+
+# Copyright (C) 2003-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+use strict;
+
+(my $program_name = $0) =~ s|.*/||;
+
+# Turn off localization of executable's output.
+@ENV{qw(LANGUAGE LANG LC_ALL)} = ('C') x 3;
+
+my $prog = 'paste';
+my $msg = "$prog: delimiter list ends with an unescaped backslash: ";
+
+my @Tests =
+ (
+ # Ensure that paste properly handles files lacking a final newline.
+ ['no-nl-1', {IN=>"a"}, {IN=>"b"}, {OUT=>"a\tb\n"}],
+ ['no-nl-2', {IN=>"a\n"}, {IN=>"b"}, {OUT=>"a\tb\n"}],
+ ['no-nl-3', {IN=>"a"}, {IN=>"b\n"}, {OUT=>"a\tb\n"}],
+ ['no-nl-4', {IN=>"a\n"}, {IN=>"b\n"}, {OUT=>"a\tb\n"}],
+
+ ['zno-nl-1', '-z', {IN=>"a"}, {IN=>"b"}, {OUT=>"a\tb\0"}],
+ ['zno-nl-2', '-z', {IN=>"a\0"}, {IN=>"b"}, {OUT=>"a\tb\0"}],
+ ['zno-nl-3', '-z', {IN=>"a"}, {IN=>"b\0"}, {OUT=>"a\tb\0"}],
+ ['zno-nl-4', '-z', {IN=>"a\0"}, {IN=>"b\0"}, {OUT=>"a\tb\0"}],
+
+ # Same as above, but with a two lines in each input file and
+ # the addition of the -d option to make SPACE be the output delimiter.
+ ['no-nla1', '-d" "', {IN=>"1\na"}, {IN=>"2\nb"}, {OUT=>"1 2\na b\n"}],
+ ['no-nla2', '-d" "', {IN=>"1\na\n"}, {IN=>"2\nb"}, {OUT=>"1 2\na b\n"}],
+ ['no-nla3', '-d" "', {IN=>"1\na"}, {IN=>"2\nb\n"}, {OUT=>"1 2\na b\n"}],
+ ['no-nla4', '-d" "', {IN=>"1\na\n"}, {IN=>"2\nb\n"}, {OUT=>"1 2\na b\n"}],
+
+ ['zno-nla1', '-zd" "', {IN=>"1\0a"}, {IN=>"2\0b"}, {OUT=>"1 2\0a b\0"}],
+ ['zno-nla2', '-zd" "', {IN=>"1\0a\0"}, {IN=>"2\0b"}, {OUT=>"1 2\0a b\0"}],
+ ['zno-nla3', '-zd" "', {IN=>"1\0a"}, {IN=>"2\0b\0"}, {OUT=>"1 2\0a b\0"}],
+ ['zno-nla4', '-zd" "', {IN=>"1\0a\0"}, {IN=>"2\0b\0"}, {OUT=>"1 2\0a b\0"}],
+
+ # Specifying a delimiter with a trailing backslash would overrun a
+ # malloc'd buffer.
+ ['delim-bs1', q!-d'\'!, {IN=>{'a'x50=>''}}, {EXIT => 1},
+ # We print a single backslash into the expected output
+ {ERR => $msg . q!\\! . "\n"} ],
+
+ # Prior to coreutils-5.1.2, this sort of abuse would make paste
+ # scribble on command-line arguments. With paste from coreutils-5.1.0,
+ # this example would mangle the first file name argument, if it contains
+ # accepted backslash-escapes:
+ # $ paste -d\\ '123\b\b\b.....@' 2>&1 |cat -A
+ # paste: 23^H^H^H.....@...@: No such file or directory$
+ ['delim-bs2', q!-d'\'!, {IN=>{'123\b\b\b.....@'=>''}}, {EXIT => 1},
+ {ERR => $msg . q!\\! . "\n"} ],
+ );
+
+my $save_temps = $ENV{DEBUG};
+my $verbose = $ENV{VERBOSE};
+
+my $fail = run_tests ($program_name, $prog, \@Tests, $save_temps, $verbose);
+exit $fail;
diff --git a/tests/misc/pathchk.sh b/tests/misc/pathchk.sh
new file mode 100755
index 0000000..b0892ac
--- /dev/null
+++ b/tests/misc/pathchk.sh
@@ -0,0 +1,38 @@
+#!/bin/sh
+# pathchk tests
+
+# Copyright (C) 2002-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ pathchk
+skip_if_root_
+
+touch file || framework_failure_
+
+
+# This should exit nonzero. Before 2.0.13, it gave a diagnostic,
+# but exited successfully.
+returns_ 1 pathchk file/x > /dev/null 2>&1 || fail=1
+
+# This should exit nonzero. Through 5.3.0 it exited with status zero.
+returns_ 1 pathchk -p '' > /dev/null 2>&1 || fail=1
+
+# This tests the new -P option.
+returns_ 1 pathchk -P '' > /dev/null 2>&1 || fail=1
+returns_ 1 pathchk -P -- - > /dev/null 2>&1 || fail=1
+returns_ 1 pathchk -p -P x/- > /dev/null 2>&1 || fail=1
+
+Exit $fail
diff --git a/tests/misc/printenv.sh b/tests/misc/printenv.sh
new file mode 100755
index 0000000..708f92b
--- /dev/null
+++ b/tests/misc/printenv.sh
@@ -0,0 +1,83 @@
+#!/bin/sh
+# Verify behavior of printenv.
+
+# Copyright (C) 2009-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ printenv
+
+# Without arguments, printenv behaves like env. Some shells provide
+# printenv as a builtin, so we must invoke it via "env".
+# But beware of $_, set by many shells to the last command run.
+# Also, filter out LD_PRELOAD, which is set when running under valgrind.
+# Note the apparently redundant "env env": this is to ensure to get
+# env's output the same way as that of printenv and works around a bug
+# on aarch64 at least where libc's execvp reverses the order of the
+# output.
+env -- env | grep -Ev '^(_|LD_PRELOAD)=' > exp || framework_failure_
+env -- printenv | grep -Ev '^(_|LD_PRELOAD)=' > out || fail=1
+compare exp out || fail=1
+
+# POSIX is clear that environ may, but need not be, sorted.
+# Environment variable values may contain newlines, which cannot be
+# observed by merely inspecting output from printenv.
+if env -- printenv | grep '^ENV_TEST' >/dev/null ; then
+ skip_ "environment has potential interference from ENV_TEST*"
+fi
+
+# Printing a single variable's value.
+returns_ 1 env -- printenv ENV_TEST > out || fail=1
+compare /dev/null out || fail=1
+echo a > exp || framework_failure_
+ENV_TEST=a env -- printenv ENV_TEST > out || fail=1
+compare exp out || fail=1
+
+# Printing multiple variables. Order follows command line.
+ENV_TEST1=a ENV_TEST2=b env -- printenv ENV_TEST2 ENV_TEST1 ENV_TEST2 > out \
+ || fail=1
+ENV_TEST1=a ENV_TEST2=b env -- printenv ENV_TEST1 ENV_TEST2 >> out || fail=1
+cat <<EOF > exp || framework_failure_
+b
+a
+b
+a
+b
+EOF
+compare exp out || fail=1
+
+# Exit status reflects missing variable, but remaining arguments processed.
+export ENV_TEST1=a
+returns_ 1 env -- printenv ENV_TEST2 ENV_TEST1 > out || fail=1
+returns_ 1 env -- printenv ENV_TEST1 ENV_TEST2 >> out || fail=1
+unset ENV_TEST1
+cat <<EOF > exp || framework_failure_
+a
+a
+EOF
+compare exp out || fail=1
+
+# Non-standard environment variable name. Shells won't create it, but
+# env can, and printenv must be able to deal with it.
+echo b > exp || framework_failure_
+env -- -a=b printenv -- -a > out || fail=1
+compare exp out || fail=1
+
+# Silently reject invalid env-var names.
+# Bug present through coreutils 8.0.
+returns_ 1 env a=b=c printenv a=b > out || fail=1
+compare /dev/null out || fail=1
+
+Exit $fail
diff --git a/tests/misc/read-errors.sh b/tests/misc/read-errors.sh
new file mode 100755
index 0000000..7f395bb
--- /dev/null
+++ b/tests/misc/read-errors.sh
@@ -0,0 +1,95 @@
+#!/bin/sh
+# Make sure all of these programs diagnose read errors
+
+# Copyright (C) 2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+
+! cat . >/dev/null 2>&1 || skip_ "Need unreadable directories"
+
+echo "\
+basenc --base32 .
+basenc -d --base64 .
+cat .
+cksum -a blake2b .
+cksum -a bsd .
+cksum -a crc .
+cksum -a md5 .
+cksum -a sha1 .
+cksum -a sha224 .
+cksum -a sha256 .
+cksum -a sha384 .
+cksum -a sha512 .
+cksum -a sm3 .
+cksum -a sysv .
+comm . .
+csplit . 1
+cut -c1 .
+cut -f1 .
+date -f .
+dd if=.
+dircolors .
+expand .
+factor < .
+fmt .
+fold .
+head -n1 .
+head -n-1 .
+head -c1 .
+head -c-1 .
+join . .
+nl .
+numfmt < .
+od .
+paste .
+pr .
+ptx .
+shuf -r .
+shuf -n1 .
+sort .
+split -l1 .
+split -b1 .
+split -C1 .
+split -n1 .
+split -nl/1 .
+split -nr/1 .
+tac .
+tail -n1 .
+tail -c1 .
+tail -n+1 .
+tail -c+1 .
+tee < .
+tr 1 1 < .
+tsort .
+unexpand .
+uniq .
+uniq -c .
+wc .
+wc -c .
+wc -l .
+" |
+sort -k 1b,1 > all_readers || framework_failure_
+
+printf '%s\n' $built_programs |
+sort -k 1b,1 > built_programs || framework_failure_
+
+join all_readers built_programs > built_readers || framework_failure_
+
+while read reader; do
+ eval $reader >/dev/null && { fail=1; echo "$reader: exited with 0" >&2; }
+done < built_readers
+
+Exit $fail
diff --git a/tests/misc/realpath.sh b/tests/misc/realpath.sh
new file mode 100755
index 0000000..251ea19
--- /dev/null
+++ b/tests/misc/realpath.sh
@@ -0,0 +1,111 @@
+#!/bin/sh
+# Validate realpath operation
+
+# Copyright (C) 2011-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ realpath
+
+stat_single=$(stat -c %d:%i /) || framework_failure_
+stat_double=$(stat -c %d:%i //) || framework_failure_
+double_slash=//
+if test x"$stat_single" = x"$stat_double"; then
+ double_slash=/
+fi
+nl='
+'
+
+test -d /dev || framework_failure_
+
+# Setup dir, file, symlink structure
+
+mkdir -p dir1/dir2 || framework_failure_
+ln -s dir1/dir2 ldir2 || framework_failure_
+touch dir1/f dir1/dir2/f || framework_failure_
+ln -s / one || framework_failure_
+ln -s // two || framework_failure_
+ln -s /// three || framework_failure_
+
+# Basic operation
+realpath -Pqz . >/dev/null || fail=1
+# Operand is required
+returns_ 1 realpath >/dev/null || fail=1
+returns_ 1 realpath --relative-base . --relative-to . || fail=1
+returns_ 1 realpath --relative-base . || fail=1
+
+# -e --relative-* require directories
+returns_ 1 realpath -e --relative-to=dir1/f --relative-base=. . || fail=1
+realpath -e --relative-to=dir1/ --relative-base=. . || fail=1
+
+# Note NUL params are unconditionally rejected by canonicalize_filename_mode
+returns_ 1 realpath -m '' || fail=1
+returns_ 1 realpath --relative-base= --relative-to=. . || fail=1
+
+# symlink resolution
+this=$(realpath .)
+test "$(realpath ldir2/..)" = "$this/dir1" || fail=1
+test "$(realpath -L ldir2/..)" = "$this" || fail=1
+test "$(realpath -s ldir2)" = "$this/ldir2" || fail=1
+
+# relative string handling
+test $(realpath -m --relative-to=prefix prefixed/1) = '../prefixed/1' || fail=1
+test $(realpath -m --relative-to=prefixed prefix/1) = '../prefix/1' || fail=1
+test $(realpath -m --relative-to=prefixed prefixed/1) = '1' || fail=1
+
+# Ensure no redundant trailing '/' present, as was the case in v8.15
+test $(realpath -sm --relative-to=/usr /) = '..' || fail=1
+# Ensure no redundant leading '../' present, as was the case in v8.15
+test $(realpath -sm --relative-to=/ /usr) = 'usr' || fail=1
+
+# Ensure --relative-base works
+out=$(realpath -sm --relative-base=/usr --relative-to=/usr /tmp /usr) || fail=1
+test "$out" = "/tmp$nl." || fail=1
+out=$(realpath -sm --relative-base=/ --relative-to=/ / /usr) || fail=1
+test "$out" = ".${nl}usr" || fail=1
+# --relative-to defaults to the value of --relative-base
+out=$(realpath -sm --relative-base=/usr /tmp /usr) || fail=1
+test "$out" = "/tmp$nl." || fail=1
+out=$(realpath -sm --relative-base=/ / /usr) || fail=1
+test "$out" = ".${nl}usr" || fail=1
+# For now, --relative-base must be a prefix of --relative-to, or all output
+# will be absolute (compare to MacOS 'relpath -d dir start end').
+out=$(realpath -sm --relative-base=/usr/local --relative-to=/usr \
+ /usr /usr/local) || fail=1
+test "$out" = "/usr${nl}/usr/local" || fail=1
+
+# Ensure // is handled correctly.
+test "$(realpath / // ///)" = "/$nl$double_slash$nl/" || fail=1
+test "$(realpath one two three)" = "/$nl$double_slash$nl/" || fail=1
+out=$(realpath -sm --relative-to=/ / // /dev //dev) || fail=1
+if test $double_slash = //; then
+ test "$out" = ".$nl//${nl}dev$nl//dev" || fail=1
+else
+ test "$out" = ".$nl.${nl}dev${nl}dev" || fail=1
+fi
+out=$(realpath -sm --relative-to=// / // /dev //dev) || fail=1
+if test $double_slash = //; then
+ test "$out" = "/$nl.$nl/dev${nl}dev" || fail=1
+else
+ test "$out" = ".$nl.${nl}dev${nl}dev" || fail=1
+fi
+out=$(realpath --relative-base=/ --relative-to=// / //) || fail=1
+if test $double_slash = //; then
+ test "$out" = "/$nl//" || fail=1
+else
+ test "$out" = ".$nl." || fail=1
+fi
+
+Exit $fail
diff --git a/tests/misc/selinux.sh b/tests/misc/selinux.sh
new file mode 100755
index 0000000..35ad5f8
--- /dev/null
+++ b/tests/misc/selinux.sh
@@ -0,0 +1,65 @@
+#!/bin/sh
+# Test SELinux-related options.
+
+# Copyright (C) 2007-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ chcon cp ls mv stat
+
+require_root_
+require_selinux_
+skip_if_mcstransd_is_running_
+
+# Create a regular file, dir, fifo.
+touch f || framework_failure_
+mkdir d s1 s2 || framework_failure_
+mkfifo_or_skip_ p
+
+
+# special context that works both with and without mcstransd
+ctx='root:object_r:tmp_t'
+mls_enabled_ && ctx="$ctx:s0"
+
+chcon $ctx f d p || skip_ "Failed to set context: $ctx"
+
+# inspect that context with both ls -Z and stat.
+for i in d f p; do
+ c=$(ls -dogZ $i|cut -d' ' -f3); test x$c = x$ctx || fail=1
+ c=$(stat --printf %C $i); test x$c = x$ctx || fail=1
+done
+
+# ensure that ls -l output includes the ".".
+c=$(ls -l f|cut -c11); test "$c" = . || fail=1
+
+# Copy with an invalid context and ensure it fails
+# Note this may succeed when root and selinux is in permissive mode
+if test "$(getenforce)" = Enforcing; then
+ returns_ 1 cp --context='invalid-selinux-context' f f.cp || fail=1
+fi
+
+# Copy each to a new directory and ensure that context is preserved.
+cp -r --preserve=all d f p s1 || fail=1
+for i in d f p; do
+ c=$(stat --printf %C s1/$i); test x$c = x$ctx || fail=1
+done
+
+# Now, move each to a new directory and ensure that context is preserved.
+mv d f p s2 || fail=1
+for i in d f p; do
+ c=$(stat --printf %C s2/$i); test x$c = x$ctx || fail=1
+done
+
+Exit $fail
diff --git a/tests/misc/sleep.sh b/tests/misc/sleep.sh
new file mode 100755
index 0000000..9082853
--- /dev/null
+++ b/tests/misc/sleep.sh
@@ -0,0 +1,55 @@
+#!/bin/sh
+# Validate sleep parameters
+
+# Copyright (C) 2016-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ sleep printf
+getlimits_
+
+# invalid timeouts
+returns_ 1 timeout 10 sleep invalid || fail=1
+returns_ 1 timeout 10 sleep -- -1 || fail=1
+returns_ 1 timeout 10 sleep 42D || fail=1
+returns_ 1 timeout 10 sleep 42d 42day || fail=1
+returns_ 1 timeout 10 sleep nan || fail=1
+returns_ 1 timeout 10 sleep '' || fail=1
+returns_ 1 timeout 10 sleep || fail=1
+
+# subsecond actual sleep
+timeout 10 sleep 0.001 || fail=1
+timeout 10 sleep 0x.002p1 || fail=1
+
+# Using small timeouts for larger sleeps is racy,
+# but false positives should be avoided on most systems
+returns_ 124 timeout 0.1 sleep 1d 2h 3m 4s || fail=1
+returns_ 124 timeout 0.1 sleep inf || fail=1
+returns_ 124 timeout 0.1 sleep $LDBL_MAX || fail=1
+
+# Test locale decimal handling for printf, sleep, timeout
+: ${LOCALE_FR_UTF8=none}
+if test "$LOCALE_FR_UTF8" != "none"; then
+ f=$LOCALE_FR_UTF8
+ locale_decimal=$(LC_ALL=$f env printf '%0.3f' 0.001) || fail=1
+ locale_decimal=$(LC_ALL=$f env printf '%0.3f' "$locale_decimal") || fail=1
+ case "$locale_decimal" in
+ 0?001)
+ LC_ALL=$f timeout 1$locale_decimal sleep "$locale_decimal" || fail=1 ;;
+ *) fail=1 ;;
+ esac
+fi
+
+Exit $fail
diff --git a/tests/misc/stdbuf.sh b/tests/misc/stdbuf.sh
new file mode 100755
index 0000000..c4369f7
--- /dev/null
+++ b/tests/misc/stdbuf.sh
@@ -0,0 +1,125 @@
+#!/bin/sh
+# Exercise stdbuf functionality
+
+# Copyright (C) 2009-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ stdbuf env
+
+getlimits_
+
+# stdbuf fails when the absolute top build dir name contains e.g.,
+# space, TAB, NL
+lf='
+'
+case $abs_top_builddir in
+ *[\\\"\#\$\&\'\`$lf\ \ ]*)
+ skip_ "unsafe absolute build directory name: $abs_top_builddir";;
+esac
+
+# Use a fifo rather than a pipe in the tests below
+# so that the producer (uniq) will wait until the
+# consumer (dd) opens the fifo therefore increasing
+# the chance that dd will read the data from each
+# write separately.
+mkfifo_or_skip_ fifo
+
+
+# Verify input parameter checking
+stdbuf -o1 true || fail=1 # verify size syntax
+stdbuf -oK true || fail=1 # verify size syntax
+stdbuf -o0 true || fail=1 # verify unbuffered syntax
+stdbuf -oL true || fail=1 # verify line buffered syntax
+
+# Capital 'L' required
+# Internal error is a particular status
+returns_ 125 stdbuf -ol true || fail=1
+
+returns_ 125 stdbuf -o$SIZE_OFLOW true || fail=1 # size too large
+returns_ 125 stdbuf -iL true || fail=1 # line buffering stdin disallowed
+returns_ 125 stdbuf true || fail=1 # a buffering mode must be specified
+stdbuf -i0 -o0 -e0 true || fail=1 #check all files
+returns_ 126 env . && { returns_ 126 stdbuf -o1 . || fail=1; } # invalid command
+returns_ 127 stdbuf -o1 no_such || fail=1 # no such command
+
+# Terminate any background processes
+cleanup_() { kill $pid 2>/dev/null && wait $pid; }
+
+# Ensure line buffering stdout takes effect
+stdbuf_linebuffer()
+{
+ local delay="$1"
+
+ printf '1\n' > exp
+ > out || framework_failure_
+ dd count=1 if=fifo > out 2> err & pid=$!
+ (printf '1\n'; sleep $delay; printf '2\n') | stdbuf -oL uniq > fifo
+ wait $pid
+ compare exp out
+}
+
+retry_delay_ stdbuf_linebuffer .1 6 || fail=1
+
+stdbuf_unbuffer()
+{
+ local delay="$1"
+
+ # Ensure un buffering stdout takes effect
+ printf '1\n' > exp
+ > out || framework_failure_
+ dd count=1 if=fifo > out 2> err & pid=$!
+ (printf '1\n'; sleep $delay; printf '2\n') | stdbuf -o0 uniq > fifo
+ wait $pid
+ compare exp out
+}
+
+retry_delay_ stdbuf_unbuffer .1 6 || fail=1
+
+# Ensure un buffering stdin takes effect
+# The following works for me, but is racy. I.e., we're depending
+# on dd to run and close the fifo before the second write by uniq.
+# If we add a sleep, then we're just testing -oL
+ # printf '3\n' > exp
+ # dd count=1 if=fifo > /dev/null 2> err &
+ # printf '1\n\2\n3\n' | (stdbuf -i0 -oL uniq > fifo; cat) > out
+ # wait # for dd to complete
+ # compare exp out || fail=1
+# One could remove the need for dd (used to close the fifo to get uniq to quit
+# early), if head -n1 read stdin char by char. Note uniq | head -c2 doesn't
+# suffice due to the buffering implicit in the pipe. sed currently does read
+# stdin char by char, so we can test with 'sed 1q'. However I'm wary about
+# adding this dependency on a program outside of coreutils.
+ # printf '2\n' > exp
+ # printf '1\n2\n' | (stdbuf -i0 sed 1q >/dev/null; cat) > out
+ # compare exp out || fail=1
+
+# Ensure block buffering stdout takes effect
+# We don't currently test block buffering failures as
+# this doesn't work on GLIBC-2.7 or GLIBC-2.9 at least.
+ # stdbuf_blockbuffer()
+ # {
+ # local delay="$1"
+ #
+ # printf '1\n2\n' > exp
+ # dd count=1 if=fifo > out 2> err &
+ # (printf '1\n'; sleep $delay; printf '2\n') | stdbuf -o4 uniq > fifo
+ # wait # for dd to complete
+ # compare exp out
+ # }
+ #
+ # retry_delay_ stdbuf_blockbuffer .1 6 || fail=1
+
+Exit $fail
diff --git a/tests/misc/sync.sh b/tests/misc/sync.sh
new file mode 100755
index 0000000..daedf41
--- /dev/null
+++ b/tests/misc/sync.sh
@@ -0,0 +1,58 @@
+#!/bin/sh
+# Test various sync(1) operations
+
+# Copyright (C) 2015-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ sync
+
+touch file || framework_failure_
+
+# fdatasync+syncfs is nonsensical
+returns_ 1 sync --data --file-system || fail=1
+
+# fdatasync needs an operand
+returns_ 1 sync -d || fail=1
+
+# Test syncing of file (fsync) (little side effects)
+sync file || fail=1
+
+# Test syncing of write-only file - which failed since adding argument
+# support to sync in coreutils-8.24.
+chmod 0200 file || framework_failure_
+sync file || fail=1
+
+# Ensure multiple args are processed and diagnosed
+returns_ 1 sync file nofile || fail=1
+
+# Ensure inaccessible dirs give an appropriate error
+mkdir norw || framework_failure_
+chmod 0 norw || framework_failure_
+if ! test -r norw; then
+ returns_ 1 sync norw 2>errt || fail=1
+ # AIX gives "Is a directory"
+ sed 's/Is a directory/Permission denied/' <errt >err || framework_failure_
+ printf "sync: error opening 'norw': Permission denied\n" >exp
+ compare exp err || fail=1
+fi
+
+if test "$fail" != '1'; then
+ # Ensure a fifo doesn't block
+ mkfifo_or_skip_ fifo
+ returns_ 124 timeout 10 sync fifo && fail=1
+fi
+
+Exit $fail
diff --git a/tests/misc/tee.sh b/tests/misc/tee.sh
new file mode 100755
index 0000000..3daf610
--- /dev/null
+++ b/tests/misc/tee.sh
@@ -0,0 +1,145 @@
+#!/bin/sh
+# test for basic tee functionality.
+
+# Copyright (C) 2005-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ tee
+
+echo line >sample || framework_failure_
+
+# POSIX says: "Processing of at least 13 file operands shall be supported."
+for n in 0 1 2 12 13; do
+ files=$(seq $n)
+ rm -f $files
+ tee $files <sample >out || fail=1
+ for f in out $files; do
+ compare sample $f || fail=1
+ done
+done
+
+# Ensure tee treats '-' as the name of a file, as mandated by POSIX.
+# Between v5.3.0 and v8.23, a '-' argument caused tee to send another
+# copy of input to standard output.
+tee - <sample >out 2>err || fail=1
+compare sample ./- || fail=1
+compare sample out || fail=1
+compare /dev/null err || fail=1
+
+# Ensure tee exits early if no more writable outputs
+if test -w /dev/full && test -c /dev/full; then
+ yes | returns_ 1 timeout 10 tee /dev/full 2>err >/dev/full || fail=1
+ # Ensure an error for each of the 2 outputs
+ # (and no redundant errors for stdout).
+ test $(wc -l < err) = 2 || { cat err; fail=1; }
+
+
+ # Ensure we continue with outputs that are OK
+ seq 10000 > multi_read || framework_failure_
+
+ returns_ 1 tee /dev/full out2 2>err >out1 <multi_read || fail=1
+ cmp multi_read out1 || fail=1
+ cmp multi_read out2 || fail=1
+ # Ensure an error for failing output
+ test $(wc -l < err) = 1 || { cat err; fail=1; }
+
+ returns_ 1 tee out1 out2 2>err >/dev/full <multi_read || fail=1
+ cmp multi_read out1 || fail=1
+ cmp multi_read out2 || fail=1
+ # Ensure an error for failing output
+ test $(wc -l < err) = 1 || { cat err; fail=1; }
+fi
+
+case $host_triplet in
+ *aix*) echo 'avoiding due to no way to detect closed outputs on AIX' ;;
+ *)
+# Test iopoll-powered early exit for closed pipes
+tee_exited() { sleep $1; test -f tee.exited; }
+# Currently this functionality is most useful with
+# intermittent input from a terminal, but here we
+# use an input pipe that doesn't write anything
+# but will exit as soon as tee does, or it times out
+retry_delay_ tee_exited .1 7 | # 12.7s (Must be > following timeout)
+{ timeout 10 tee -p 2>err && touch tee.exited; } | :
+test $(wc -l < err) = 0 || { cat err; fail=1; }
+test -f tee.exited || fail=1 ;;
+esac
+
+# Test with unwritable files
+if ! uid_is_privileged_; then # root does not get EPERM.
+ touch file.ro || framework_failure_
+ chmod a-w file.ro || framework_failure_
+ returns_ 1 tee -p </dev/null file.ro || fail=1
+fi
+
+mkfifo_or_skip_ fifo
+
+# Ensure tee handles nonblocking output correctly
+# Terminate any background processes
+cleanup_() { kill $pid 2>/dev/null && wait $pid; }
+read_fifo_delayed() {
+ { sleep .1; timeout 10 dd of=/dev/null status=none; } <fifo
+}
+read_fifo_delayed & pid=$!
+dd count=20 bs=100K if=/dev/zero status=none |
+{
+ dd count=0 oflag=nonblock status=none
+ tee || { cleanup_; touch tee.fail; }
+} >fifo
+test -f tee.fail && fail=1 || cleanup_
+
+# Ensure tee honors --output-error modes
+read_fifo() { timeout 10 dd count=1 if=fifo of=/dev/null status=none & }
+
+# Determine platform sigpipe exit status
+read_fifo
+yes >fifo
+pipe_status=$?
+
+# Default operation is to continue on output errors but exit silently on SIGPIPE
+read_fifo
+yes | returns_ $pipe_status timeout 10 tee ./e/noent 2>err >fifo || fail=1
+test $(wc -l < err) = 1 || { cat err; fail=1; }
+
+# With -p, SIGPIPE is suppressed, exit 0 for EPIPE when all outputs finished
+read_fifo
+yes | timeout 10 tee -p 2>err >fifo || fail=1
+test $(wc -l < err) = 0 || { cat err; fail=1; }
+
+# With --output-error=warn, exit 1 for EPIPE when all outputs finished
+read_fifo
+yes | returns_ 1 timeout 10 tee --output-error=warn 2>err >fifo || fail=1
+test $(wc -l < err) = 1 || { cat err; fail=1; }
+
+# With --output-error=exit, exit 1 immediately for EPIPE
+read_fifo
+yes | returns_ 1 timeout 10 tee --output-error=exit /dev/null 2>err >fifo \
+ || fail=1
+test $(wc -l < err) = 1 || { cat err; fail=1; }
+
+# With --output-error=exit, exit 1 immediately on output error
+read_fifo
+yes | returns_ 1 timeout 10 tee --output-error=exit ./e/noent 2>err >fifo \
+ || fail=1
+test $(wc -l < err) = 1 || { cat err; fail=1; }
+
+# With --output-error=exit-nopipe, exit 0 for EPIPE
+read_fifo
+yes | timeout 10 tee --output-error=exit-nopipe 2>err >fifo || fail=1
+test $(wc -l < err) = 0 || { cat err; fail=1; }
+
+wait
+Exit $fail
diff --git a/tests/misc/time-style.sh b/tests/misc/time-style.sh
new file mode 100755
index 0000000..3433836
--- /dev/null
+++ b/tests/misc/time-style.sh
@@ -0,0 +1,119 @@
+#!/bin/sh
+# Test --time-style in programs like 'ls'.
+
+# Copyright (C) 2016-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ du
+print_ver_ ls
+print_ver_ pr
+
+echo hello >a || framework_failure_
+
+# The tests assume this is an old timestamp in northern hemisphere summer.
+TZ=UTC0 touch -d '1970-07-08 09:10:11' a || framework_failure_
+
+for tz in UTC0 PST8 PST8PDT,M3.2.0,M11.1.0 XXXYYY-12:30; do
+ for style in full-iso long-iso iso locale '+%Y-%m-%d %H:%M:%S %z (%Z)' \
+ +%%b%b%%b%b; do
+ test "$style" = locale ||
+ TZ=$tz LC_ALL=C du --time --time-style="$style" a >>duout 2>>err || fail=1
+ TZ=$tz LC_ALL=C ls -no --time-style="$style" a >>lsout 2>>err || fail=1
+ case $style in
+ (+*) TZ=$tz LC_ALL=C pr -D"$style" a >>prout 2>>err || fail=1 ;;
+ esac
+ done
+done
+
+sed 's/[^ ]* //' duout >dued || framework_failure_
+sed 's/[^ ]* *[^ ]* *[^ ]* *[^ ]* *//' lsout >lsed || framework_failure_
+sed '/^$/d' prout >pred || framework_failure_
+
+cat <<\EOF > duexp || framework_failure_
+1970-07-08 09:10:11.000000000 +0000 a
+1970-07-08 09:10 a
+1970-07-08 a
+1970-07-08 09:10:11 +0000 (UTC) a
+%bJul%bJul a
+1970-07-08 01:10:11.000000000 -0800 a
+1970-07-08 01:10 a
+1970-07-08 a
+1970-07-08 01:10:11 -0800 (PST) a
+%bJul%bJul a
+1970-07-08 02:10:11.000000000 -0700 a
+1970-07-08 02:10 a
+1970-07-08 a
+1970-07-08 02:10:11 -0700 (PDT) a
+%bJul%bJul a
+1970-07-08 21:40:11.000000000 +1230 a
+1970-07-08 21:40 a
+1970-07-08 a
+1970-07-08 21:40:11 +1230 (XXXYYY) a
+%bJul%bJul a
+EOF
+
+cat <<\EOF > lsexp || framework_failure_
+1970-07-08 09:10:11.000000000 +0000 a
+1970-07-08 09:10 a
+1970-07-08 a
+Jul 8 1970 a
+1970-07-08 09:10:11 +0000 (UTC) a
+%bJul%bJul a
+1970-07-08 01:10:11.000000000 -0800 a
+1970-07-08 01:10 a
+1970-07-08 a
+Jul 8 1970 a
+1970-07-08 01:10:11 -0800 (PST) a
+%bJul%bJul a
+1970-07-08 02:10:11.000000000 -0700 a
+1970-07-08 02:10 a
+1970-07-08 a
+Jul 8 1970 a
+1970-07-08 02:10:11 -0700 (PDT) a
+%bJul%bJul a
+1970-07-08 21:40:11.000000000 +1230 a
+1970-07-08 21:40 a
+1970-07-08 a
+Jul 8 1970 a
+1970-07-08 21:40:11 +1230 (XXXYYY) a
+%bJul%bJul a
+EOF
+
+cat <<\EOF > prexp || framework_failure_
++1970-07-08 09:10:11 +0000 (UTC) a Page 1
+hello
++%bJul%bJul a Page 1
+hello
++1970-07-08 01:10:11 -0800 (PST) a Page 1
+hello
++%bJul%bJul a Page 1
+hello
++1970-07-08 02:10:11 -0700 (PDT) a Page 1
+hello
++%bJul%bJul a Page 1
+hello
++1970-07-08 21:40:11 +1230 (XXXYYY) a Page 1
+hello
++%bJul%bJul a Page 1
+hello
+EOF
+
+compare duexp dued || fail=1
+compare lsexp lsed || fail=1
+compare prexp pred || fail=1
+compare /dev/null err || fail=1
+
+Exit $fail
diff --git a/tests/misc/tsort.pl b/tests/misc/tsort.pl
new file mode 100755
index 0000000..ca3aa3b
--- /dev/null
+++ b/tests/misc/tsort.pl
@@ -0,0 +1,66 @@
+#!/usr/bin/perl
+# Test "tsort".
+
+# Copyright (C) 1999-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+use strict;
+
+(my $program_name = $0) =~ s|.*/||;
+
+# Turn off localization of executable's output.
+@ENV{qw(LANGUAGE LANG LC_ALL)} = ('C') x 3;
+
+my @Tests =
+ (
+ ['cycle-1', {IN => {f => "t b\nt s\ns t\n"}}, {OUT => "s\nt\nb\n"},
+ {EXIT => 1},
+ {ERR => "tsort: f: input contains a loop:\ntsort: s\ntsort: t\n"} ],
+ ['cycle-2', {IN => {f => "t x\nt s\ns t\n"}}, {OUT => "s\nt\nx\n"},
+ {EXIT => 1},
+ {ERR => "tsort: f: input contains a loop:\ntsort: s\ntsort: t\n"} ],
+
+ ['posix-1', {IN => "a b c c d e\ng g\nf g e f\nh h\n"},
+ {OUT => "a\nc\nd\nh\nb\ne\nf\ng\n"}],
+ ['posix-2', {IN => "b a\nd c\nz h x h r h\n"},
+ {OUT => "b\nd\nr\nx\nz\na\nc\nh\n"}],
+
+ ['linear-1', {IN => "a b b c c d d e e f f g\n"},
+ {OUT => "a\nb\nc\nd\ne\nf\ng\n"}],
+
+ ['tree-1', {IN => "a b b c c d d e e f f g\nc x x y y z\n"},
+ {OUT => "a\nb\nc\nx\nd\ny\ne\nz\nf\ng\n"}],
+ ['tree-2', {IN => "a b b c c d d e e f f g\nc x x y y z\nf r r s s t\n"},
+ {OUT => "a\nb\nc\nx\nd\ny\ne\nz\nf\nr\ng\ns\nt\n"}],
+
+ # Before coreutils-5.0.1, given an odd number of input tokens,
+ # tsort would accept that and treat the input as if an additional
+ # copy of the final token were appended.
+ ['odd', {IN => "a\n"},
+ {EXIT => 1},
+ {ERR => "tsort: odd.1: input contains an odd number of tokens\n"}],
+
+ ['only-one', {IN => {f => ""}}, {IN => {g => ""}},
+ {EXIT => 1},
+ {ERR => "tsort: extra operand 'g'\n"
+ . "Try 'tsort --help' for more information.\n"}],
+ );
+
+my $save_temps = $ENV{DEBUG};
+my $verbose = $ENV{VERBOSE};
+
+my $prog = 'tsort';
+my $fail = run_tests ($program_name, $prog, \@Tests, $save_temps, $verbose);
+exit $fail;
diff --git a/tests/misc/unexpand.pl b/tests/misc/unexpand.pl
new file mode 100755
index 0000000..d78a1bc
--- /dev/null
+++ b/tests/misc/unexpand.pl
@@ -0,0 +1,135 @@
+#!/usr/bin/perl
+# Test "unexpand".
+
+# Copyright (C) 2000-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+use strict;
+
+my $limits = getlimits ();
+
+(my $program_name = $0) =~ s|.*/||;
+
+# Turn off localization of executable's output.
+@ENV{qw(LANGUAGE LANG LC_ALL)} = ('C') x 3;
+
+my $prog = 'unexpand';
+
+my @Tests =
+ (
+ ['a1', {IN=> ' 'x 1 ."y\n"}, {OUT=> ' 'x 1 ."y\n"}],
+ ['a2', {IN=> ' 'x 2 ."y\n"}, {OUT=> ' 'x 2 ."y\n"}],
+ ['a3', {IN=> ' 'x 3 ."y\n"}, {OUT=> ' 'x 3 ."y\n"}],
+ ['a4', {IN=> ' 'x 4 ."y\n"}, {OUT=> ' 'x 4 ."y\n"}],
+ ['a5', {IN=> ' 'x 5 ."y\n"}, {OUT=> ' 'x 5 ."y\n"}],
+ ['a6', {IN=> ' 'x 6 ."y\n"}, {OUT=> ' 'x 6 ."y\n"}],
+ ['a7', {IN=> ' 'x 7 ."y\n"}, {OUT=> ' 'x 7 ."y\n"}],
+ ['a8', {IN=> ' 'x 8 ."y\n"}, {OUT=> "\ty\n"}],
+
+ ['aa-1', '-a', {IN=> 'w'.' 'x 1 ."y\n"}, {OUT=> 'w'.' 'x 1 ."y\n"}],
+ ['aa-2', '-a', {IN=> 'w'.' 'x 2 ."y\n"}, {OUT=> 'w'.' 'x 2 ."y\n"}],
+ ['aa-3', '-a', {IN=> 'w'.' 'x 3 ."y\n"}, {OUT=> 'w'.' 'x 3 ."y\n"}],
+ ['aa-4', '-a', {IN=> 'w'.' 'x 4 ."y\n"}, {OUT=> 'w'.' 'x 4 ."y\n"}],
+ ['aa-5', '-a', {IN=> 'w'.' 'x 5 ."y\n"}, {OUT=> 'w'.' 'x 5 ."y\n"}],
+ ['aa-6', '-a', {IN=> 'w'.' 'x 6 ."y\n"}, {OUT=> 'w'.' 'x 6 ."y\n"}],
+ ['aa-7', '-a', {IN=> 'w'.' 'x 7 ."y\n"}, {OUT=> "w\ty\n"}],
+ ['aa-8', '-a', {IN=> 'w'.' 'x 8 ."y\n"}, {OUT=> "w\t y\n"}],
+
+ ['b-1', '-t', '2,4', {IN=> " ."}, {OUT=>"\t\t ."}],
+ # These would infloop prior to textutils-2.0d.
+
+ ['infloop-1', '-t', '1,2', {IN=> " \t\t .\n"}, {OUT=>"\t\t\t .\n"}],
+ ['infloop-2', '-t', '4,5', {IN=> ' 'x4 . "\t\t \n"}, {OUT=>"\t\t\t \n"}],
+ ['infloop-3', '-t', '2,3', {IN=> "x \t\t \n"}, {OUT=>"x\t\t\t \n"}],
+ ['infloop-4', '-t', '1,2', {IN=> " \t\t \n"}, {OUT=>"\t\t\t \n"}],
+ ['c-1', '-t', '1,2', {IN=> "x\t\t .\n"}, {OUT=>"x\t\t .\n"}],
+
+ # -t implies -a
+ # Feature addition (--first-only) prompted by a report from Jie Xu.
+ ['tabs-1', qw(-t 3), {IN=> " a b\n"}, {OUT=>"\ta\tb\n"}],
+ ['tabs-2', qw(-t 3 --first-only), {IN=> " a b\n"}, {OUT=>"\ta b\n"}],
+
+ # blanks
+ ['blanks-1', qw(-t 1), {IN=> " b c d\n"}, {OUT=> "\tb\t\tc\t\t\td\n"}],
+ ['blanks-2', qw(-t 1), {IN=> "a \n"}, {OUT=> "a \n"}],
+ ['blanks-3', qw(-t 1), {IN=> "a \n"}, {OUT=> "a\t\t\n"}],
+ ['blanks-4', qw(-t 1), {IN=> "a \n"}, {OUT=> "a\t\t\t\n"}],
+ ['blanks-5', qw(-t 1), {IN=> "a "}, {OUT=> "a "}],
+ ['blanks-6', qw(-t 1), {IN=> "a "}, {OUT=> "a\t\t"}],
+ ['blanks-7', qw(-t 1), {IN=> "a "}, {OUT=> "a\t\t\t"}],
+ ['blanks-8', qw(-t 1), {IN=> " a a a\n"}, {OUT=> "\ta a\t\ta\n"}],
+ ['blanks-9', qw(-t 2), {IN=> " a a a\n"}, {OUT=> "\t a\ta\t a\n"}],
+ ['blanks-10', '-t', '3,4', {IN=> "0 2 4 6\t8\n"}, {OUT=> "0 2 4 6\t8\n"}],
+ ['blanks-11', '-t', '3,4', {IN=> " 4\n"}, {OUT=> "\t\t4\n"}],
+ ['blanks-12', '-t', '3,4', {IN=> "01 4\n"}, {OUT=> "01\t\t4\n"}],
+ ['blanks-13', '-t', '3,4', {IN=> "0 4\n"}, {OUT=> "0\t\t4\n"}],
+
+ # POSIX says spaces should only follow tabs. Also a single
+ # trailing space is not converted to a tab, when before
+ # a field starting with non blanks
+ ['posix-1', '-a', {IN=> "1234567 \t1\n"}, {OUT=>"1234567\t\t1\n"}],
+ ['posix-2', '-a', {IN=> "1234567 \t1\n"}, {OUT=>"1234567\t\t1\n"}],
+ ['posix-3', '-a', {IN=> "1234567 \t1\n"}, {OUT=>"1234567\t\t1\n"}],
+ ['posix-4', '-a', {IN=> "1234567\t1\n"}, {OUT=>"1234567\t1\n"}],
+ ['posix-5', '-a', {IN=> "1234567 1\n"}, {OUT=>"1234567\t 1\n"}],
+ ['posix-6', '-a', {IN=> "1234567 1\n"}, {OUT=>"1234567 1\n"}],
+
+ # It is debatable whether this test should require an environment
+ # setting of e.g., _POSIX2_VERSION=1.
+ ['obs-ovflo', "-$limits->{UINTMAX_OFLOW}", {IN=>''}, {OUT=>''},
+ {EXIT => 1}, {ERR => "$prog: tab stop value is too large\n"}],
+
+
+ # Test input with backspaces '\b' ('bs1' is the baseline, without \b)
+ # Note: If users report errors in these tests, copy&pasting results from
+ # their terminate output might be confusing due to '\b' overriding
+ # characters. For details see '\b' tests in 'expand.pl'.
+ ['bs1', '-a -t4', {IN=>"aa c\n"}, {OUT=>"aa\tc\n"}],
+ ['bs2', '-a -t4', {IN=>"aa\b c\n"}, {OUT=>"aa\b c\n"}],
+ ['bs3', '-a -t4', {IN=>"aa\b c\n"}, {OUT=>"aa\b\tc\n"}],
+ ['bs4', '-a -t3', {IN=>"aa\b c\n"}, {OUT=>"aa\b\tc\n"}],
+
+ # Undocumented feature:
+ # treat "unexpand -7" as "unexpand --first-only --tabs 7" ,
+ # and "unexpand -90" as "unexpand --first-only --tabs 90",
+ ['u1', '-a -3', {IN=>"a b c"}, {OUT=>"a\tb\tc"}],
+ ['u2', '-a -4,9', {IN=>"a b c"}, {OUT=>"a\tb\tc"}],
+ ['u3', '-a -11', {IN=>"a b"}, {OUT=>"a\tb"}],
+ # Test all digits (for full code coverage)
+ ['u4', '-a -2,6', {IN=>"a b c"}, {OUT=>"a b\tc"}],
+ ['u5', '-a -7', {IN=>"a b"}, {OUT=>"a\tb"}],
+ ['u6', '-a -8', {IN=>"a b"}, {OUT=>"a\tb"}],
+ # This syntax is handled internally as "-3, -9"
+ ['u7', '-a -3,9', {IN=>"a b c"}, {OUT=>"a\tb\tc"}],
+ # Default (without -a) is --first-only:
+ ['u8', '-3', {IN=>" a b"}, {OUT=>"\ta b"}],
+
+ # Arguably this should minimize translation as is done on Solaris.
+ # I.e., not modify the input. But since the result is equivalent,
+ # and to be consistent in output with older versions, we output
+ # a '\t' rather than a space for the second tab position.
+ # For more detailed comparison with other implementations see:
+ # https://lists.gnu.org/r/coreutils/2016-06/msg00015.html
+ # https://lists.gnu.org/r/coreutils/2016-07/msg00011.html
+ ['ts1', '-t8,9', {IN=>"x\t \t y\n"}, {OUT=>"x\t\t\t y\n"}],
+ # There is no ambiguity here. This should always be the output.
+ ['ts2', '-t5,8', {IN=>"x\t \t y\n"}, {OUT=>"x\t\t y\n"}],
+ );
+
+my $save_temps = $ENV{DEBUG};
+my $verbose = $ENV{VERBOSE};
+
+my $fail = run_tests ($program_name, $prog, \@Tests, $save_temps, $verbose);
+exit $fail;
diff --git a/tests/misc/usage_vs_getopt.sh b/tests/misc/usage_vs_getopt.sh
new file mode 100755
index 0000000..f4f1213
--- /dev/null
+++ b/tests/misc/usage_vs_getopt.sh
@@ -0,0 +1,96 @@
+#!/bin/sh
+# Verify that all options mentioned in usage are recognized by getopt.
+
+# Copyright (C) 2017-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+
+checkprg () {
+ prg="$1"
+
+ # Get stderr output for unrecognized options for later use as a pattern.
+ # Also consider the expected exit status of each program.
+ rcexp=1
+ case "$prg" in
+ dir | ls | printenv | sort | tty | vdir ) rcexp=2 ;;
+ env | chroot | nice | nohup | runcon | stdbuf | timeout ) rcexp=125 ;;
+ esac
+ # Write the pattern for a long, unknown option into a pattern file.
+ o='thisoptiondoesnotexist'
+ returns_ $rcexp $prg --$o >/dev/null 2> err || fail=1
+ grep -F "$o" err || framework_failure_
+ sed -n "1s/--$o/OPT/p" < err > pat || framework_failure_
+
+ # Append the pattern for a short unknown option.
+ returns_ $rcexp $prg -/ >/dev/null 2> err || fail=1
+ grep " '*/'*" err || framework_failure_
+ # The following only handles the common case that has single quotes,
+ # as it simplifies to identify missing options only on common systems.
+ sed -n "1s/'\/'/'OPT'/p" < err >> pat || framework_failure_
+
+ # Get output for --help.
+ $prg --help > help || fail=1
+
+ # Extract all options mention in the above --help output.
+ nl="
+ "
+ sed -n -e '/--version/q' \
+ -e 's/^ \{2,6\}-/-/; s/ .*//; s/[=[].*//; s/, /\'"$nl"'/g; s/^-/-/p' help \
+ > opts || framework_failure_
+ cat opts # for debugging purposes
+
+ # Test all options mentioned in usage (but --version).
+ while read opt; do
+ test "x$opt" = 'x--help' \
+ && continue
+ # Append --help to be on the safe side: the option under test either
+ # requires a further argument, or --help triggers usage(); so $prg should
+ # exit without performing its regular operation.
+ # Add a 2nd --help for the 'env -u --help' case.
+ $prg "$opt" --help --help </dev/null >out 2>err1
+ rc=$?
+ # In the --help case, i.e., when the option under test has been accepted,
+ # the exit code should be Zero.
+ if [ $rc = 0 ]; then
+ compare help out || fail=1
+ else
+ # Else $prg should have complained about a missing argument.
+ # Catch false positives.
+ case "$prg/$opt" in
+ 'pr/-COLUMN') continue;;
+ esac
+ # Replace $opt in stderr output by the neutral placeholder.
+ # Handle both long and short option error messages.
+ sed -e "s/$opt/OPT/" -e "s/'.'/'OPT'/" < err1 > err || framework_failure_
+ # Fail if the stderr output matches the above provoked error.
+ grep -Ff pat err && { fail=1; cat err1; }
+ fi
+ done < opts
+}
+
+for prg in $built_programs; do
+ case "$prg" in
+ # Skip utilities entirely which have special option parsing.
+ '[' | expr | stty )
+ continue;;
+ # Wrap some utilities known by the shell by env.
+ echo | false | kill | printf | pwd | sleep | test | true )
+ prg="env $prg";;
+ esac
+ checkprg $prg
+done
+
+Exit $fail
diff --git a/tests/misc/write-errors.sh b/tests/misc/write-errors.sh
new file mode 100755
index 0000000..4f17028
--- /dev/null
+++ b/tests/misc/write-errors.sh
@@ -0,0 +1,65 @@
+#!/bin/sh
+# Make sure all of these programs promptly diagnose write errors.
+
+# Copyright (C) 2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ timeout
+
+if ! test -w /dev/full || ! test -c /dev/full; then
+ skip_ '/dev/full is required'
+fi
+
+# Writers that may output data indefinitely
+# First word in command line is checked against built programs
+echo "\
+cat /dev/zero
+comm -z /dev/zero /dev/zero
+cut -z -c1- /dev/zero
+cut -z -f1- /dev/zero
+dd if=/dev/zero
+expand /dev/zero
+factor --version; yes 1 | factor
+# TODO: fmt /dev/zero
+# TODO: fold -b /dev/zero
+head -z -n-1 /dev/zero
+join -a 1 -z /dev/zero /dev/null
+# TODO: nl --version; yes | nl
+# TODO: numfmt --version; yes 1 | numfmt
+od -v /dev/zero
+paste /dev/zero
+# TODO: pr /dev/zero
+seq inf
+tail -n+1 -z /dev/zero
+tee < /dev/zero
+tr . . < /dev/zero
+unexpand /dev/zero
+uniq -z -D /dev/zero
+yes
+" |
+sort -k 1b,1 > all_writers || framework_failure_
+
+printf '%s\n' $built_programs |
+sort -k 1b,1 > built_programs || framework_failure_
+
+join all_writers built_programs > built_writers || framework_failure_
+
+while read writer; do
+ timeout 10 $SHELL -c "$writer > /dev/full"
+ test $? = 124 && { fail=1; echo "$writer: failed to exit" >&2; }
+done < built_writers
+
+Exit $fail
diff --git a/tests/misc/xattr.sh b/tests/misc/xattr.sh
new file mode 100755
index 0000000..1416578
--- /dev/null
+++ b/tests/misc/xattr.sh
@@ -0,0 +1,130 @@
+#!/bin/sh
+# Ensure that cp --preserve=xattr, cp --preserve=all and mv preserve extended
+# attributes and install does not preserve extended attributes.
+# cp -a should preserve xattr, error diagnostics should not be displayed
+
+# Copyright (C) 2009-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ cp mv ginstall
+
+# Skip this test if cp was built without xattr support:
+touch src dest || framework_failure_
+cp --preserve=xattr -n src dest \
+ || skip_ "coreutils built without xattr support"
+
+# this code was taken from test mv/backup-is-src
+cleanup_() { rm -rf "$other_partition_tmpdir"; }
+. "$abs_srcdir/tests/other-fs-tmpdir"
+b_other="$other_partition_tmpdir/b"
+rm -f "$b_other" || framework_failure_
+
+# testing xattr name-value pair
+xattr_name="user.foo"
+xattr_value="bar"
+xattr_pair="$xattr_name=\"$xattr_value\""
+
+# create new file and check its xattrs
+touch a || framework_failure_
+getfattr -d a >out_a || skip_ "failed to get xattr of file"
+grep -F "$xattr_pair" out_a && framework_failure_
+
+# try to set user xattr on file
+setfattr -n "$xattr_name" -v "$xattr_value" a >out_a \
+ || skip_ "failed to set xattr of file"
+getfattr -d a >out_a || skip_ "failed to get xattr of file"
+grep -F "$xattr_pair" out_a \
+ || skip_ "failed to set xattr of file"
+
+
+# cp should not preserve xattr by default
+cp a b || fail=1
+getfattr -d b >out_b || skip_ "failed to get xattr of file"
+grep -F "$xattr_pair" out_b && fail=1
+
+# test if --preserve=xattr option works
+cp --preserve=xattr a b || fail=1
+getfattr -d b >out_b || skip_ "failed to get xattr of file"
+grep -F "$xattr_pair" out_b || fail=1
+
+# test if --preserve=all option works
+cp --preserve=all a c || fail=1
+getfattr -d c >out_c || skip_ "failed to get xattr of file"
+grep -F "$xattr_pair" out_c || fail=1
+
+# cp's -a option must produce no diagnostics.
+cp -a a d 2>err && { compare /dev/null err || fail=1; }
+getfattr -d d >out_d || skip_ "failed to get xattr of file"
+grep -F "$xattr_pair" out_d || fail=1
+
+# test if --preserve=xattr works even for files without write access
+chmod a-w a || framework_failure_
+rm -f e
+cp --preserve=xattr a e || fail=1
+getfattr -d e >out_e || skip_ "failed to get xattr of file"
+grep -F "$xattr_pair" out_e || fail=1
+
+# Ensure that permission bits are preserved, too.
+src_perm=$(stat --format=%a a)
+dst_perm=$(stat --format=%a e)
+test "$dst_perm" = "$src_perm" || fail=1
+
+chmod u+w a || framework_failure_
+
+rm b || framework_failure_
+
+# install should never preserve xattr
+ginstall a b || fail=1
+getfattr -d b >out_b || skip_ "failed to get xattr of file"
+grep -F "$xattr_pair" out_b && fail=1
+
+# mv should preserve xattr when renaming within a file system.
+# This is implicitly done by rename () and doesn't need explicit
+# xattr support in mv.
+mv a b || fail=1
+getfattr -d b >out_b || skip_ "failed to get xattr of file"
+grep -F "$xattr_pair" out_b || cat >&2 <<EOF
+=================================================================
+$0: WARNING!!!
+rename () does not preserve extended attributes
+=================================================================
+EOF
+
+# try to set user xattr on file on other partition
+test_mv=1
+touch "$b_other" || framework_failure_
+setfattr -n "$xattr_name" -v "$xattr_value" "$b_other" >out_a \
+ || test_mv=0
+getfattr -d "$b_other" >out_b || test_mv=0
+grep -F "$xattr_pair" out_b || test_mv=0
+rm -f "$b_other" || framework_failure_
+
+if test $test_mv -eq 1; then
+ # mv should preserve xattr when copying content from one partition to another
+ mv b "$b_other" || fail=1
+ getfattr -d "$b_other" >out_b ||
+ skip_ "failed to get xattr of file"
+ grep -F "$xattr_pair" out_b || fail=1
+else
+ cat >&2 <<EOF
+=================================================================
+$0: WARNING!!!
+failed to set xattr of file $b_other
+=================================================================
+EOF
+fi
+
+Exit $fail
diff --git a/tests/misc/xstrtol.pl b/tests/misc/xstrtol.pl
new file mode 100755
index 0000000..dfdaee0
--- /dev/null
+++ b/tests/misc/xstrtol.pl
@@ -0,0 +1,49 @@
+#!/usr/bin/perl
+# exercise xstrtol's diagnostics via pr
+
+# Copyright (C) 2007-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+use strict;
+
+(my $ME = $0) =~ s|.*/||;
+
+# Turn off localization of executable's output.
+@ENV{qw(LANGUAGE LANG LC_ALL)} = ('C') x 3;
+
+my $prog = 'pr';
+my $too_big = '9' x 81; # Big enough to overflow a 256-bit integer.
+my @Tests =
+ (
+ # test-name, [option, option, ...] {OUT=>"expected-output"}
+
+ ['inval-suffix', "--pages=${too_big}h", {EXIT => 1},
+ {ERR=>"$prog: invalid suffix in --pages argument '${too_big}h'\n"}],
+
+ ['too-big', "--pages=$too_big", {EXIT => 1},
+ {ERR=>"$prog: --pages argument '$too_big' too large\n"}],
+
+ ['simply-inval', "--pages=x", {EXIT => 1},
+ {ERR=>"$prog: invalid --pages argument 'x'\n"}],
+
+ ['inv-pg-range', "--pages=9x", {EXIT => 1},
+ {ERR=>"$prog: invalid page range '9x'\n"}],
+ );
+
+my $save_temps = $ENV{DEBUG};
+my $verbose = $ENV{VERBOSE};
+
+my $fail = run_tests ($ME, $prog, \@Tests, $save_temps, $verbose);
+exit $fail;
diff --git a/tests/misc/yes.sh b/tests/misc/yes.sh
new file mode 100755
index 0000000..9cd07d4
--- /dev/null
+++ b/tests/misc/yes.sh
@@ -0,0 +1,59 @@
+#!/bin/sh
+# Validate yes buffer handling
+
+# Copyright (C) 2015-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ yes
+
+# Check basic operation
+test "$(yes | head -n1)" = 'y' || fail=1
+
+# Check various single item sizes, with the most important
+# size being BUFSIZ used for the local buffer to yes(1).
+# Note a \n is added, so actual sizes required internally
+# are 1 more than the size used here.
+for size in 1 1999 4095 4096 8191 8192 16383 16384; do
+ printf "%${size}s\n" '' > out.1
+ yes "$(printf %${size}s '')" | head -n2 | uniq > out.2
+ compare out.1 out.2 || fail=1
+done
+
+# Check the many small items case,
+# both fitting and overflowing the internal buffer.
+# First check that 4000 arguments supported.
+if test 4000 -eq $(sh -c 'echo $#' 0 $(seq 4000)); then
+ for i in 100 4000; do
+ seq $i | paste -s -d ' ' | sed p > out.1
+ yes $(seq $i) | head -n2 > out.2
+ compare out.1 out.2 || fail=1
+ done
+fi
+
+# Check a single appropriate diagnostic is output on write error
+if test -w /dev/full && test -c /dev/full; then
+ # The single output diagnostic expected,
+ # (without the possibly varying :strerror(ENOSPC) suffix).
+ printf '%s\n' "yes: standard output" > exp
+
+ for size in 1 16384; do
+ returns_ 1 yes "$(printf %${size}s '')" >/dev/full 2>errt || fail=1
+ sed 's/\(yes:.*\):.*/\1/' errt > err
+ compare exp err || fail=1
+ done
+fi
+
+Exit $fail
diff --git a/tests/mkdir/p-1.sh b/tests/mkdir/p-1.sh
new file mode 100755
index 0000000..e2d020c
--- /dev/null
+++ b/tests/mkdir/p-1.sh
@@ -0,0 +1,25 @@
+#!/bin/sh
+# Test "mkdir -p".
+
+# Copyright (C) 1997-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ mkdir
+
+mkdir --parents "$(pwd)/t" || fail=1
+test -d t || fail=1
+
+Exit $fail
diff --git a/tests/mkdir/p-2.sh b/tests/mkdir/p-2.sh
new file mode 100755
index 0000000..8a5a50d
--- /dev/null
+++ b/tests/mkdir/p-2.sh
@@ -0,0 +1,25 @@
+#!/bin/sh
+# Just like p-1, but with an absolute path.
+
+# Copyright (C) 1997-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ mkdir
+
+mkdir --parents "$(pwd)/t/u" || fail=1
+test -d t/u || fail=1
+
+Exit $fail
diff --git a/tests/mkdir/p-3.sh b/tests/mkdir/p-3.sh
new file mode 100755
index 0000000..30645e3
--- /dev/null
+++ b/tests/mkdir/p-3.sh
@@ -0,0 +1,52 @@
+#!/bin/sh
+# Ensure that mkdir-p.c's fail-to-return-to-initial-working-directory
+# causes immediate failure. Also, ensure that we don't create
+# subsequent, relative command-line arguments in the wrong place.
+
+# Copyright (C) 2005-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ mkdir
+skip_if_root_
+
+mkdir no-access || framework_failure_
+mkdir no-acce2s || framework_failure_
+mkdir -p no-acce3s/d || framework_failure_
+
+p=$(pwd)
+(cd no-access && chmod 0 . && mkdir -p "$p/a/b" u/v) 2> /dev/null
+test $? -eq 1 || fail=1
+test -d "$p/a/b" || fail=1
+
+# Same as above, but with a following *absolute* name, it should succeed
+(cd no-acce2s && chmod 0 . && mkdir -p "$p/b/b" "$p/z") || fail=1
+test -d "$p/b/b" && test -d "$p/z" || fail=1
+
+# Same as above, but a trailing relative name in an unreadable directory
+# whose parent is inaccessible. coreutils 5.97 fails this test.
+# Perform this test only if "." is on a local file system.
+# Otherwise, it would fail e.g., on an NFS-mounted file system.
+if is_local_dir_ .; then
+ (cd no-acce3s/d && chmod a-r . && chmod a-rx .. &&
+ mkdir -p a/b "$p/b/c" d/e && test -d a/b && test -d d/e) || fail=1
+ test -d "$p/b/c" || fail=1
+fi
+
+b=$(ls "$p/a" | tr -d '\n')
+# With coreutils-5.3.0, this would fail with $b=bu.
+test "x$b" = xb || fail=1
+
+Exit $fail
diff --git a/tests/mkdir/p-acl.sh b/tests/mkdir/p-acl.sh
new file mode 100755
index 0000000..b562105
--- /dev/null
+++ b/tests/mkdir/p-acl.sh
@@ -0,0 +1,35 @@
+#!/bin/sh
+# Test "mkdir -p" with default ACLs.
+
+# Copyright (C) 1997-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ mkdir
+
+require_setfacl_
+
+mkdir d || framework_failure_
+setfacl -d -m group::rwx d || framework_failure_
+umask 077
+
+mkdir --parents d/e || fail=1
+ls_l=$(ls -ld d/e) || fail=1
+case $ls_l in
+ d???rw[sx]*) ;;
+ *) fail=1 ;;
+esac
+
+Exit $fail
diff --git a/tests/mkdir/p-slashdot.sh b/tests/mkdir/p-slashdot.sh
new file mode 100755
index 0000000..f50fa44
--- /dev/null
+++ b/tests/mkdir/p-slashdot.sh
@@ -0,0 +1,29 @@
+#!/bin/sh
+# Ensure that mkdir -p works with arguments specified with a trailing "/.".
+
+# Copyright (C) 2005-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ mkdir
+
+
+mkdir -p d1/. || fail=1
+test -d d1 || fail=1
+
+mkdir -p d2/.. || fail=1
+test -d d2 || fail=1
+
+Exit $fail
diff --git a/tests/mkdir/p-thru-slink.sh b/tests/mkdir/p-thru-slink.sh
new file mode 100755
index 0000000..15a764e
--- /dev/null
+++ b/tests/mkdir/p-thru-slink.sh
@@ -0,0 +1,27 @@
+#!/bin/sh
+# Ensure that mkdir -p foo/bar works when foo is a symbolic link to a directory
+
+# Copyright (C) 2005-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ mkdir
+
+ln -s . slink || framework_failure_
+
+mkdir -p slink/x || fail=1
+test -d x || fail=1
+
+Exit $fail
diff --git a/tests/mkdir/p-v.sh b/tests/mkdir/p-v.sh
new file mode 100755
index 0000000..4fa619e
--- /dev/null
+++ b/tests/mkdir/p-v.sh
@@ -0,0 +1,32 @@
+#!/bin/sh
+# Test mkdir -pv.
+
+# Copyright (C) 2006-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ mkdir
+
+mkdir -pv foo/a/b/c/d >out || fail=1
+
+compare - out <<\EOF || fail=1
+mkdir: created directory 'foo'
+mkdir: created directory 'foo/a'
+mkdir: created directory 'foo/a/b'
+mkdir: created directory 'foo/a/b/c'
+mkdir: created directory 'foo/a/b/c/d'
+EOF
+
+Exit $fail
diff --git a/tests/mkdir/parents.sh b/tests/mkdir/parents.sh
new file mode 100755
index 0000000..c6c0a0b
--- /dev/null
+++ b/tests/mkdir/parents.sh
@@ -0,0 +1,52 @@
+#!/bin/sh
+# make sure mkdir's -p options works properly
+
+# Copyright (C) 2000-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ mkdir
+skip_if_setgid_
+require_no_default_acl_ .
+
+mkdir -m 700 e-dir || framework_failure_
+
+
+# Make sure 'mkdir -p existing-dir' succeeds
+# and that 'mkdir existing-dir' fails.
+mkdir -p e-dir || fail=1
+returns_ 1 mkdir e-dir > /dev/null 2>&1 || fail=1
+
+# Create an existing directory.
+umask 077
+mode_str=drwxr-x-wx
+mode_arg=$(rwx_to_mode_ $mode_str)
+mkdir -m $mode_arg a || fail=1
+
+# this 'mkdir -p ...' shouldn't change perms of existing dir 'a'.
+d_mode_str=drwx-w--wx
+d_mode_arg=$(rwx_to_mode_ $d_mode_str)
+mkdir -p -m $d_mode_arg a/b/c/d
+
+# Make sure the permissions of 'a' haven't been changed.
+p=$(ls -ld a|cut -b-10); case $p in $mode_str);; *) fail=1;; esac
+# 'b's and 'c's should reflect the umask
+p=$(ls -ld a/b|cut -b-10); case $p in drwx------);; *) fail=1;; esac
+p=$(ls -ld a/b/c|cut -b-10); case $p in drwx------);; *) fail=1;; esac
+
+# 'd's perms are determined by the -m argument.
+p=$(ls -ld a/b/c/d|cut -b-10); case $p in $d_mode_str);; *) fail=1;; esac
+
+Exit $fail
diff --git a/tests/mkdir/perm.sh b/tests/mkdir/perm.sh
new file mode 100755
index 0000000..62ded0f
--- /dev/null
+++ b/tests/mkdir/perm.sh
@@ -0,0 +1,85 @@
+#!/bin/sh
+# Verify that mkdir's '-m MODE' option works properly
+# with various umask settings.
+
+# Copyright (C) 2000-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ mkdir
+skip_if_setgid_
+require_no_default_acl_ .
+
+working_umask_or_skip_
+
+
+# parent parent/dir
+# umask -m option resulting perm resulting perm
+tests='
+ 000 : empty : drwxrwxrwx : drwxrwxrwx :
+ 000 : -m 016 : drwxrwxrwx : d-----xrw- :
+ 077 : empty : drwx------ : drwx------ :
+ 050 : empty : drwx-w-rwx : drwx-w-rwx :
+ 050 : -m 312 : drwx-w-rwx : d-wx--x-w- :
+ 160 : empty : drwx--xrwx : drw---xrwx :
+ 160 : -m 743 : drwx--xrwx : drwxr---wx :
+ 022 : -m o-w : drwxr-xr-x : drwxrwxr-x :
+ 027 : -m =+x : drwxr-x--- : d--x--x--- :
+ 027 : -m =+X : drwxr-x--- : d--x--x--- :
+ - : - : last : last :
+ '
+colon_tests=$(echo $tests | sed 's/^ *//; s/ *: */:/g')
+
+for p in empty -p; do
+ test _$p = _empty && p=
+
+ old_IFS=$IFS
+ IFS=':'
+ set $colon_tests
+ IFS=$old_IFS
+
+ while :; do
+ test "$VERBOSE" = yes && set -x
+ umask=$1 mode=$2 parent_perms=$3 sub_perms=$4
+ test "_$mode" = _empty && mode=
+ test $sub_perms = last && break
+ # echo p=$p umask=$1 mode=$2 parent_perms=$3 sub_perms=$4
+ shift; shift; shift; shift
+ umask $umask
+
+ # If we're not using -p, then create the parent manually,
+ # and adjust expectations accordingly.
+ test x$p = x &&
+ {
+ mkdir -m =,u=rwx parent || fail=1
+ parent_perms=drwx------
+ }
+
+ mkdir $p $mode parent/sub || fail=1
+
+ perms=$(stat --printf %A parent)
+ test "$parent_perms" = "$perms" \
+ || { fail=1; echo parent: expected $parent_perms, got $perms; }
+
+ perms=$(stat --printf %A parent/sub)
+ test "$sub_perms" = "$perms" \
+ || { fail=1; echo parent/sub: expected $sub_perms, got $perms; }
+
+ chmod -R u+rwx parent
+ rm -rf parent || fail=1
+ done
+done
+
+Exit $fail
diff --git a/tests/mkdir/restorecon.sh b/tests/mkdir/restorecon.sh
new file mode 100755
index 0000000..7ac9aa3
--- /dev/null
+++ b/tests/mkdir/restorecon.sh
@@ -0,0 +1,72 @@
+#!/bin/sh
+# test mkdir, mknod, mkfifo -Z
+
+# Copyright (C) 2013-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ mkdir mknod mkfifo
+require_selinux_
+
+mkdir subdir || framework_failure_
+ctx='root:object_r:tmp_t'
+mls_enabled_ && ctx="$ctx:s0"
+chcon "$ctx" subdir || skip_ "Failed to set context: $ctx"
+cd subdir
+
+# --- mkdir -Z ---
+# Since in a tmp_t dir, dirs can be created as user_tmp_t ...
+mkdir standard || framework_failure_
+mkdir restored || framework_failure_
+if restorecon restored 2>/dev/null; then
+ # ... but when restored can be set to user_home_t
+ # So ensure the type for these mkdir -Z cases matches
+ # the directory type as set by restorecon.
+ mkdir -Z single || fail=1
+ # Run these as separate processes in case global context
+ # set for an arg, impacts on another arg
+ # TODO: Have the defaultcon() vary over these directories
+ for dir in single_p single_p/existing multi/ple; do
+ mkdir -Zp "$dir" || fail=1
+ done
+ restored_type=$(get_selinux_type 'restored')
+ test "$(get_selinux_type 'single')" = "$restored_type" || fail=1
+ test "$(get_selinux_type 'single_p')" = "$restored_type" || fail=1
+ test "$(get_selinux_type 'single_p/existing')" = "$restored_type" || fail=1
+ test "$(get_selinux_type 'multi')" = "$restored_type" || fail=1
+ test "$(get_selinux_type 'multi/ple')" = "$restored_type" || fail=1
+fi
+if test "$fail" = '1'; then
+ ls -UZd standard restored
+ ls -UZd single single_p single_p/existing multi multi/ple
+fi
+
+# --- mknod -Z and mkfifo -Z ---
+# Assume if selinux present that we can create fifos
+for cmd_w_arg in 'mknod' 'mkfifo'; do
+ # In OpenBSD's /bin/sh, mknod is a shell built-in.
+ # Running via "env" ensures we run our program and not the built-in.
+ basename="$cmd_w_arg"
+ test "$basename" = 'mknod' && nt='p' || nt=''
+ env -- $cmd_w_arg $basename $nt || fail=1
+ env -- $cmd_w_arg ${basename}_restore $nt || fail=1
+ if restorecon ${basename}_restore 2>/dev/null; then
+ env -- $cmd_w_arg -Z ${basename}_Z $nt || fail=1
+ restored_type=$(get_selinux_type "${basename}_restore")
+ test "$(get_selinux_type ${basename}_Z)" = "$restored_type" || fail=1
+ fi
+done
+
+Exit $fail
diff --git a/tests/mkdir/selinux.sh b/tests/mkdir/selinux.sh
new file mode 100755
index 0000000..58d280a
--- /dev/null
+++ b/tests/mkdir/selinux.sh
@@ -0,0 +1,56 @@
+#!/bin/sh
+# ensure that an invalid context doesn't cause a segfault
+
+# Copyright (C) 2008-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ mkdir mkfifo mknod
+
+# Note: on an SELinux/enforcing system running mcstransd older than
+# mcstrans-0.2.8-1.fc9, the following commands may mistakenly exit
+# successfully, in spite of the invalid context string.
+require_selinux_enforcing_
+
+c=invalid-selinux-context
+msg="failed to set default file creation context to '$c':"
+
+# Test each of mkdir, mknod, mkfifo with "-Z invalid-context".
+
+for cmd_w_arg in 'mkdir dir' 'mknod b p' 'mkfifo f'; do
+ # In OpenBSD's /bin/sh, mknod is a shell built-in.
+ # Running via "env" ensures we run our program and not the built-in.
+ env -- $cmd_w_arg --context=$c 2> out && fail=1
+ set $cmd_w_arg; cmd=$1
+ echo "$cmd: $msg" > exp || framework_failure_
+
+ # Some systems fail with ENOTSUP, EINVAL, ENOENT, or even
+ # "Unknown system error", or "Function not implemented".
+ # For AIX 5.3: "Unsupported attribute value"
+ # For HP-UX 11.23: Unknown error (252)
+ sed \
+ -e 's/ Not supported$//' \
+ -e 's/ Invalid argument$//' \
+ -e 's/ Unknown system error$//' \
+ -e 's/ Operation not supported$//' \
+ -e 's/ Function not implemented$//' \
+ -e 's/ Unsupported attribute value$//' \
+ -e 's/ Unknown error .*$//' \
+ -e 's/ No such file or directory$//' out > k || framework_failure_
+ mv k out || fail=1
+ compare exp out || fail=1
+done
+
+Exit $fail
diff --git a/tests/mkdir/smack-no-root.sh b/tests/mkdir/smack-no-root.sh
new file mode 100755
index 0000000..9d3f48f
--- /dev/null
+++ b/tests/mkdir/smack-no-root.sh
@@ -0,0 +1,39 @@
+#!/bin/sh
+# SMACK test for the mkdir,mknod, mkfifo commands.
+# Derived from tests/mkdir/selinux.sh.
+# Ensure that an unsettable SMACK label doesn't cause a segfault.
+
+# Copyright (C) 2014-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ mkdir mkfifo mknod
+
+require_smack_
+
+c=arbitrary-smack-label
+msg="failed to set default file creation context to '$c':"
+
+for cmd in 'mkdir dir' 'mknod b p' 'mkfifo f'; do
+ $cmd --context="$c" 2> out && fail=1
+ set $cmd
+ echo "$1: $msg" > exp || framework_failure_
+
+ sed -e 's/ Operation not permitted$//' out > k || framework_failure_
+ mv k out || fail=1
+ compare exp out || fail=1
+done
+
+Exit $fail
diff --git a/tests/mkdir/smack-root.sh b/tests/mkdir/smack-root.sh
new file mode 100755
index 0000000..8a10c73
--- /dev/null
+++ b/tests/mkdir/smack-root.sh
@@ -0,0 +1,36 @@
+#!/bin/sh
+# SMACK test for the mkdir,mknod, mkfifo commands.
+# Derived from tests/mkdir/selinux.sh.
+# Ensure that SMACK label gets set.
+
+# Copyright (C) 2014-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ mkdir mkfifo mknod
+
+require_smack_
+require_root_
+
+c=arbitrary-smack-label
+
+for cmd in 'mkdir dir' 'mknod b p' 'mkfifo f'; do
+ $cmd --context="$c" || { fail=1; continue; }
+ set $cmd
+ ls -dZ $2 > out || fail=1
+ test "$(cut -f1 -d' ' out)" = "$c" || { cat out; fail=1; }
+done
+
+Exit $fail
diff --git a/tests/mkdir/special-1.sh b/tests/mkdir/special-1.sh
new file mode 100755
index 0000000..00833b1
--- /dev/null
+++ b/tests/mkdir/special-1.sh
@@ -0,0 +1,51 @@
+#!/bin/sh
+# verify that mkdir honors special bits in MODE
+
+# Copyright (C) 2000-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ mkdir
+
+set_mode_string=u=rwx,g=rx,o=w,-s,+t
+output_mode_string=drwxr-x-wT
+
+tmp=t
+mkdir -m$set_mode_string $tmp || fail=1
+
+test -d $tmp || fail=1
+mode=$(ls -ld $tmp|cut -b-10)
+case "$mode" in
+ $output_mode_string) ;;
+ *) fail=1 ;;
+esac
+
+rmdir $tmp || fail=1
+tmp2=$tmp/sub
+
+# This should fail.
+returns_ 1 mkdir -m$set_mode_string $tmp2 2> /dev/null || fail=1
+
+# Now test the --parents option.
+mkdir --parents -m$set_mode_string $tmp2 || fail=1
+
+test -d $tmp2 || fail=1
+mode=$(ls -ld $tmp2|cut -b-10)
+case "$mode" in
+ $output_mode_string) ;;
+ *) fail=1 ;;
+esac
+
+Exit $fail
diff --git a/tests/mkdir/t-slash.sh b/tests/mkdir/t-slash.sh
new file mode 100755
index 0000000..55f1c3d
--- /dev/null
+++ b/tests/mkdir/t-slash.sh
@@ -0,0 +1,31 @@
+#!/bin/sh
+# Ensure that mkdir works with arguments specified with and without
+# a trailing slash.
+
+# Copyright (C) 2000-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ mkdir
+
+
+mkdir -p dir/ || fail=1
+test -d dir || fail=1
+
+# This failed on NetBSD for fileutils-4.0.33.
+mkdir d2/ || fail=1
+test -d d2 || fail=1
+
+Exit $fail
diff --git a/tests/mkdir/writable-under-readonly.sh b/tests/mkdir/writable-under-readonly.sh
new file mode 100755
index 0000000..ee7caa6
--- /dev/null
+++ b/tests/mkdir/writable-under-readonly.sh
@@ -0,0 +1,52 @@
+#!/bin/sh
+# FIXME: convert this to a root-only test.
+
+# Copyright (C) 2005-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+# Test for the 2005-10-13 patch to lib/mkdir-p.c that fixed this sort
+# of bug in mkdir:
+#
+# "mkdir -p /a/b/c" no longer fails merely because a leading prefix
+# directory (e.g., /a or /a/b) exists on a read-only file system.
+#
+# Demonstrate the problem, as root:
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ mkdir
+require_root_
+
+# FIXME: for now, skip it unconditionally
+skip_ temporarily disabled
+
+# FIXME: define cleanup_ to do the umount
+
+# FIXME: use mktemp
+cd /tmp \
+ && dd if=/dev/zero of=1 bs=8192 count=50 \
+ && dd if=/dev/zero of=2 bs=8192 count=50 \
+ && mkdir -p mnt-ro && mkfs -t ext2 1 && mkfs -t ext2 2 \
+ && mount -o loop=/dev/loop3 1 mnt-ro \
+ && mkdir -p mnt-ro/rw \
+ && mount -o remount,ro mnt-ro \
+ && mount -o loop=/dev/loop4 2 mnt-ro/rw
+
+mkdir -p mnt-ro/rw/sub || fail=1
+
+# To clean up
+umount /tmp/2
+umount /tmp/1
+
+Exit $fail
diff --git a/tests/mv/acl.sh b/tests/mv/acl.sh
new file mode 100755
index 0000000..8065a3a
--- /dev/null
+++ b/tests/mv/acl.sh
@@ -0,0 +1,67 @@
+#!/bin/sh
+# move files/directories across file system boundaries
+# and make sure acls are preserved
+
+# Copyright (C) 2005-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ mv
+
+require_acl_
+
+# Skip this test if cp was built without ACL support:
+grep '^#define USE_ACL 1' $CONFIG_HEADER > /dev/null ||
+ skip_ "insufficient ACL support"
+
+cleanup_() { rm -rf "$other_partition_tmpdir"; }
+. "$abs_srcdir/tests/other-fs-tmpdir"
+
+touch file || framework_failure_
+t1=$other_partition_tmpdir/t1
+touch $t1 || framework_failure_
+
+skip_partition=none
+# Ensure that setfacl and getfacl work on this file system.
+setfacl -m user:bin:rw- file 2> /dev/null || skip_partition=.
+# And on the destination file system.
+setfacl -m user:bin:rw- $t1 || skip_partition=$other_partition_tmpdir
+acl1=$(getfacl file) || skip_partition=.
+
+test $skip_partition != none &&
+ skip_ "'$skip_partition' is not on a suitable file system for this test"
+
+# move the access acl of a file
+mv file "$other_partition_tmpdir" || fail=1
+acl2=$(cd "$other_partition_tmpdir" && getfacl file) || framework_failure_
+test "$acl1" = "$acl2" || fail=1
+
+# move the access acl of a directory
+mkdir dir || framework_failure_
+setfacl -m user:bin:rw- dir || framework_failure_
+acl1=$(getfacl dir) || framework_failure_
+mv dir "$other_partition_tmpdir" || fail=1
+acl2=$(cd "$other_partition_tmpdir" && getfacl dir) || framework_failure_
+test "$acl1" = "$acl2" || fail=1
+
+# move the default acl of a directory
+mkdir dir2 || framework_failure_
+setfacl -d -m user:bin:rw- dir2 || framework_failure_
+acl1=$(getfacl dir2) || framework_failure_
+mv dir2 "$other_partition_tmpdir" || fail=1
+acl2=$(cd "$other_partition_tmpdir" && getfacl dir2) || framework_failure_
+test "$acl1" = "$acl2" || fail=1
+
+Exit $fail
diff --git a/tests/mv/atomic.sh b/tests/mv/atomic.sh
new file mode 100755
index 0000000..145e89d
--- /dev/null
+++ b/tests/mv/atomic.sh
@@ -0,0 +1,46 @@
+#!/bin/sh
+# ensure that mv doesn't first unlink its destination in one particular case
+
+# Copyright (C) 2006-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ mv
+require_strace_ unlink
+
+# Before the fix, mv would unnecessarily unlink the destination symlink:
+# $ rm -rf s[12]; ln -s / s1; ln -s /tmp s2
+# $ strace -qe unlink /bin/mv -T s1 s2
+# unlink("s2") = 0
+#
+# With the fix, it doesn't call unlink:
+# $ rm -rf s[12]; ln -s / s1; ln -s /tmp s2
+# $ strace -qe unlink ./mv -T s1 s2
+# $
+
+ln -s t1 s1 || framework_failure_
+ln -s t2 s2 || framework_failure_
+
+
+strace -qe unlink mv -T s1 s2 > out 2>&1 || fail=1
+$EGREP 'unlink.*"s1"' out && fail=1
+
+# Ensure that the source, s1, is gone.
+ls -dl s1 > /dev/null 2>&1 && fail=1
+
+# Ensure that the destination, s2, contains the link from s1.
+test "$(readlink s2)" = t1 || fail=1
+
+Exit $fail
diff --git a/tests/mv/atomic2.sh b/tests/mv/atomic2.sh
new file mode 100755
index 0000000..fedf392
--- /dev/null
+++ b/tests/mv/atomic2.sh
@@ -0,0 +1,45 @@
+#!/bin/sh
+# ensure that mv doesn't first unlink a multi-hard-linked destination
+
+# Copyright (C) 2008-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ mv
+require_strace_ unlink
+
+# Before the fix, mv would unnecessarily unlink the destination symlink:
+# $ rm -f a b b2; touch a b; ln b b2; strace -e unlink /p/bin/mv a b
+# unlink("b") = 0
+#
+# With the fix, it doesn't call unlink:
+# $ rm -f a b b2; touch a b; ln b b2; strace -e unlink ./mv a b
+# $
+
+touch a b || framework_failure_
+ln b b2 || framework_failure_
+
+
+strace -qe unlink mv a b > out 2>&1 || fail=1
+$EGREP 'unlink.*"b"' out && fail=1
+
+# Ensure that the source, "a", is gone.
+ls -dl a > /dev/null 2>&1 && fail=1
+
+# Ensure that the destination, "b", has link count 1.
+n_links=$(stat --printf=%h b) || fail=1
+test "$n_links" = 1 || fail=1
+
+Exit $fail
diff --git a/tests/mv/backup-dir.sh b/tests/mv/backup-dir.sh
new file mode 100755
index 0000000..d967b45
--- /dev/null
+++ b/tests/mv/backup-dir.sh
@@ -0,0 +1,45 @@
+#!/bin/sh
+# Ensure "mv --verbose --backup" works the same for dirs and non-dirs.
+
+# Copyright (C) 2006-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ mv
+
+mkdir A B || framework_failure_
+touch X Y || framework_failure_
+
+
+# Before coreutils-6.2, the " (backup: 'B.~1~')" suffix was not printed.
+mv --verbose --backup=numbered -T A B > out || fail=1
+cat <<\EOF > exp || framework_failure_
+renamed 'A' -> 'B' (backup: 'B.~1~')
+EOF
+
+compare exp out || fail=1
+
+# Bug#52410
+mkdir C D E || framework_failure_
+mv -T --backup=numbered C E/ || fail=1
+mv -T --backup=numbered D E/ || fail=1
+
+# Bug#55029
+mkdir F && echo 1 >1 && echo 2 >2 && cp 1 F/X && cp 2 X || framework_failure_
+mv --backup=simple X F/ || fail=1
+compare 1 F/X~ || fail=1
+compare 2 F/X || fail=1
+
+Exit $fail
diff --git a/tests/mv/backup-is-src.sh b/tests/mv/backup-is-src.sh
new file mode 100755
index 0000000..0a4110c
--- /dev/null
+++ b/tests/mv/backup-is-src.sh
@@ -0,0 +1,46 @@
+#!/bin/sh
+# Force mv to use the copying code.
+
+# Copyright (C) 1998-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ mv
+cleanup_() { rm -rf "$other_partition_tmpdir"; }
+. "$abs_srcdir/tests/other-fs-tmpdir"
+
+a="$other_partition_tmpdir/a"
+a2="$other_partition_tmpdir/a~"
+
+rm -f "$a" "$a2" || framework_failure_
+echo a > "$a" || framework_failure_
+echo a2 > "$a2" || framework_failure_
+
+# This mv command should exit nonzero.
+mv --b=simple "$a2" "$a" > out 2>&1 && fail=1
+
+sed \
+ -e "s,mv:,XXX:," \
+ -e "s,$a,YYY," \
+ -e "s,$a2,ZZZ," \
+ out > out2
+
+cat > exp <<\EOF
+XXX: backing up 'YYY' might destroy source; 'ZZZ' not moved
+EOF
+
+compare exp out2 || fail=1
+
+Exit $fail
diff --git a/tests/mv/childproof.sh b/tests/mv/childproof.sh
new file mode 100755
index 0000000..a5a830e
--- /dev/null
+++ b/tests/mv/childproof.sh
@@ -0,0 +1,83 @@
+#!/bin/sh
+# Ensure that cp/mv/ln don't clobber a just-copied/moved/linked file.
+# With fileutils-4.1 and earlier, this test would fail for cp and mv.
+# With coreutils-6.9 and earlier, this test would fail for ln.
+
+# Copyright (C) 2001-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ cp mv ln
+
+skip_if_root_
+
+mkdir a b c || framework_failure_
+echo a > a/f || framework_failure_
+echo b > b/f || framework_failure_
+
+
+returns_ 1 cp a/f b/f c 2> /dev/null || fail=1
+test -f a/f || fail=1
+test -f b/f || fail=1
+test -f c/f || fail=1
+test "$(cat c/f)" = a || fail=1
+rm -f c/f
+
+# With --backup=numbered, it should succeed
+cp --backup=numbered a/f b/f c || fail=1
+test -f a/f || fail=1
+test -f b/f || fail=1
+test -f c/f || fail=1
+test -f c/f.~1~ || fail=1
+rm -f c/f*
+
+returns_ 1 mv a/f b/f c 2> /dev/null || fail=1
+test -f a/f && fail=1
+test -f b/f || fail=1
+test -f c/f || fail=1
+test "$(cat c/f)" = a || fail=1
+
+# Make sure mv still works when moving hard links.
+# This is where the same_file test is necessary, and why
+# we save file names in addition to dev/ino.
+rm -f c/f* b/f
+touch a/f
+ln a/f b/g
+mv a/f b/g c || fail=1
+test -f a/f && fail=1
+test -f b/g && fail=1
+test -f c/f || fail=1
+test -f c/g || fail=1
+
+touch a/f b/f b/g
+returns_ 1 mv a/f b/f b/g c 2> /dev/null || fail=1
+test -f a/f && fail=1 # a/f should have been moved
+test -f b/f || fail=1 # b/f should remain
+test -f b/g && fail=1 # b/g should have been moved
+test -f c/f || fail=1
+test -f c/g || fail=1
+
+# Test ln -f.
+
+rm -f a/f b/f c/f
+echo a > a/f || framework_failure_
+echo b > b/f || framework_failure_
+returns_ 1 ln -f a/f b/f c 2> /dev/null || fail=1
+# a/f and c/f must be linked
+test $(stat --format %i a/f) = $(stat --format %i c/f) || fail=1
+# b/f and c/f must not be linked
+test $(stat --format %i b/f) = $(stat --format %i c/f) && fail=1
+
+Exit $fail
diff --git a/tests/mv/diag.sh b/tests/mv/diag.sh
new file mode 100755
index 0000000..abcb335
--- /dev/null
+++ b/tests/mv/diag.sh
@@ -0,0 +1,48 @@
+#!/bin/sh
+# make sure we get proper diagnostics: e.g., with --target-dir=d but no args
+
+# Copyright (C) 2000-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ mv
+
+touch f1 || framework_failure_
+touch f2 || framework_failure_
+touch d || framework_failure_
+
+# These mv commands should all exit nonzero.
+
+# Too few args. This first one did fail, but with an incorrect diagnostic
+# until fileutils-4.0u.
+mv --target=. >> out 2>&1 && fail=1
+mv no-file >> out 2>&1 && fail=1
+
+# Target is not a directory.
+mv f1 f2 f1 >> out 2>&1 && fail=1
+mv --target=f2 f1 >> out 2>&1 && fail=1
+
+cat > exp <<\EOF
+mv: missing file operand
+Try 'mv --help' for more information.
+mv: missing destination file operand after 'no-file'
+Try 'mv --help' for more information.
+mv: target 'f1': Not a directory
+mv: target directory 'f2': Not a directory
+EOF
+
+compare exp out || fail=1
+
+Exit $fail
diff --git a/tests/mv/dir-file.sh b/tests/mv/dir-file.sh
new file mode 100755
index 0000000..e70f63e
--- /dev/null
+++ b/tests/mv/dir-file.sh
@@ -0,0 +1,30 @@
+#!/bin/sh
+# mv must fail when src and dest are mismatched directory/non-directory.
+
+# Copyright (C) 2000-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ mv
+
+mkdir -p dir/file || framework_failure_
+> file || framework_failure_
+
+
+# These should both fail, but until fileutils-4.0q only the second one did.
+returns_ 1 mv dir file > /dev/null 2>&1 || fail=1
+returns_ 1 mv file dir > /dev/null 2>&1 || fail=1
+
+Exit $fail
diff --git a/tests/mv/dir2dir.sh b/tests/mv/dir2dir.sh
new file mode 100755
index 0000000..da6a518
--- /dev/null
+++ b/tests/mv/dir2dir.sh
@@ -0,0 +1,42 @@
+#!/bin/sh
+# Ensure that mv prints the right diagnostic for a dir->dir move
+# where the destination directory is not empty.
+
+# Copyright (C) 2006-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ mv
+
+mkdir -p a/t b/t || framework_failure_
+touch a/t/f || framework_failure_
+
+
+# Expect this to fail with the expected diagnostic.
+# For an interim (pre-6.0) release, it would give an erroneous
+# diagnostic about moving one directory to a subdirectory of itself.
+mv b/t a 2> out && fail=1
+
+# Accept any of these: EEXIST, ENOTEMPTY, EBUSY.
+sed 's/: File exists/: Directory not empty/'<out>o1;mv o1 out
+sed 's/: Device or resource busy/: Directory not empty/'<out>o1;mv o1 out
+
+cat <<\EOF > exp || framework_failure_
+mv: cannot overwrite 'a/t': Directory not empty
+EOF
+
+compare exp out || fail=1
+
+Exit $fail
diff --git a/tests/mv/dup-source.sh b/tests/mv/dup-source.sh
new file mode 100755
index 0000000..7f95086
--- /dev/null
+++ b/tests/mv/dup-source.sh
@@ -0,0 +1,91 @@
+#!/bin/sh
+# Ensure that cp merely warns when a non-directory source file is
+# listed on the command line more than once. fileutils-4.1.1
+# made this fail: cp a a d/
+# Ensure that mv fails with a similar command.
+
+# Copyright (C) 2001-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ cp mv
+
+skip_if_root_
+
+reset_files() { rm -fr a b d; touch a; mkdir b d; }
+
+for i in cp; do
+
+ # cp may not fail in this case.
+ reset_files
+ $i a a d/ 2> out || fail=1
+ reset_files
+ $i ./a a d/ 2>> out || fail=1
+
+ # Similarly for directories, but handle
+ # source == dest appropriately.
+ reset_files
+ $i -a ./b b d/ 2>> out || fail=1
+ reset_files
+ returns_ 1 $i -a ./b b b/ 2>> out || fail=1
+
+ # cp succeeds with --backup=numbered.
+ reset_files
+ $i --backup=numbered a a d/ 2>> out || fail=1
+
+ # But not with plain '--backup'
+ reset_files
+ returns_ 1 $i --backup a a d/ 2>> out || fail=1
+
+ cat <<EOF > exp
+$i: warning: source file 'a' specified more than once
+$i: warning: source file 'a' specified more than once
+$i: warning: source directory 'b' specified more than once
+$i: cannot copy a directory, './b', into itself, 'b/b'
+$i: warning: source directory 'b' specified more than once
+$i: will not overwrite just-created 'd/a' with 'a'
+EOF
+ compare exp out || fail=1
+done
+
+for i in mv; do
+ # But mv *does* fail in this case (it has to).
+ reset_files
+ returns_ 1 $i a a d/ 2> out || fail=1
+ returns_ 1 test -e a || fail=1
+ reset_files
+ returns_ 1 $i ./a a d/ 2>> out || fail=1
+ returns_ 1 test -e a || fail=1
+
+ # Similarly for directories, also handling
+ # source == dest appropriately.
+ reset_files
+ returns_ 1 $i ./b b d/ 2>> out || fail=1
+ returns_ 1 test -e b || fail=1
+ reset_files
+ returns_ 1 $i --verbose ./b b b/ 2>> out || fail=1
+ test -d b || fail=1
+
+ cat <<EOF > exp
+$i: cannot stat 'a': No such file or directory
+$i: cannot stat 'a': No such file or directory
+$i: cannot stat 'b': No such file or directory
+$i: cannot move './b' to a subdirectory of itself, 'b/b'
+$i: warning: source directory 'b' specified more than once
+EOF
+ compare exp out || fail=1
+done
+
+Exit $fail
diff --git a/tests/mv/force.sh b/tests/mv/force.sh
new file mode 100755
index 0000000..427cc88
--- /dev/null
+++ b/tests/mv/force.sh
@@ -0,0 +1,43 @@
+#!/bin/sh
+# move a file onto itself
+
+# Copyright (C) 1999-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ mv
+
+ff=mvforce
+ff2=mvforce2
+
+echo force-contents > $ff || framework_failure_
+ln $ff $ff2 || framework_failure_
+
+# mv should fail for the same name, or separate hardlinks as in
+# both cases rename() will do nothing and return success.
+# One could unlink(src) in the hardlink case, but that would
+# introduce races with overlapping mv instances removing both hardlinks.
+
+for dest in $ff $ff2; do
+ # This mv command should exit nonzero.
+ mv $ff $dest > out 2>&1 && fail=1
+
+ printf "mv: '$ff' and '$dest' are the same file\n" > exp
+ compare exp out || fail=1
+
+ test $(cat $ff) = force-contents || fail=1
+done
+
+Exit $fail
diff --git a/tests/mv/hard-2.sh b/tests/mv/hard-2.sh
new file mode 100755
index 0000000..f0a683e
--- /dev/null
+++ b/tests/mv/hard-2.sh
@@ -0,0 +1,77 @@
+#!/bin/sh
+# Ensure that moving hard-linked arguments onto existing destinations works.
+# Likewise when using cp --preserve=link.
+
+# Copyright (C) 2003-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ cp mv
+
+skip_if_root_
+
+mkdir dst || framework_failure_
+(cd dst && touch a b c) || framework_failure_
+touch a || framework_failure_
+ln a b || framework_failure_
+ln a c || framework_failure_
+
+
+# ======================================
+cp --preserve=link a b c dst || fail=1
+# The source files must remain.
+test -f a || fail=1
+test -f b || fail=1
+test -f c || fail=1
+cd dst
+
+# Three destination files must exist.
+test -f a || fail=1
+test -f b || fail=1
+test -f c || fail=1
+
+# The three i-node numbers must be the same.
+ia=$(ls -i a|sed 's/ a//')
+ib=$(ls -i b|sed 's/ b//')
+ic=$(ls -i c|sed 's/ c//')
+test $ia = $ib || fail=1
+test $ia = $ic || fail=1
+
+cd ..
+rm -f dst/[abc]
+(cd dst && touch a b c)
+
+# ======================================
+mv a b c dst || fail=1
+
+# The source files must be gone.
+test -f a && fail=1
+test -f b && fail=1
+test -f c && fail=1
+cd dst
+
+# Three destination files must exist.
+test -f a || fail=1
+test -f b || fail=1
+test -f c || fail=1
+
+# The three i-node numbers must be the same.
+ia=$(ls -i a|sed 's/ a//')
+ib=$(ls -i b|sed 's/ b//')
+ic=$(ls -i c|sed 's/ c//')
+test $ia = $ib || fail=1
+test $ia = $ic || fail=1
+
+Exit $fail
diff --git a/tests/mv/hard-3.sh b/tests/mv/hard-3.sh
new file mode 100755
index 0000000..2d22c40
--- /dev/null
+++ b/tests/mv/hard-3.sh
@@ -0,0 +1,69 @@
+#!/bin/sh
+# Ensure that using 'cp --preserve=link' to copy hard-linked arguments
+# onto existing destinations works, even when one of the link operations fails.
+
+# Copyright (C) 2003-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+
+# This bug was fixed in coreutils-4.5.9.
+# To exercise this bug is non-trivial:
+# Set-up requires at least three hard-linked files. In copying them,
+# while preserving links, the initial copy must succeed, the attempt
+# to create the second file via 'link' must fail, and the final 'link'
+# (to create the third) must succeed. Before the corresponding fix,
+# the first and third destination files would not be linked.
+#
+# Note that this is nominally a test of 'cp', yet it is in the tests/mv
+# directory, because it requires use of the --preserve=link option that
+# mv enables by default.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ cp
+skip_if_root_
+
+mkdir -p x dst/x || framework_failure_
+touch dst/x/b || framework_failure_
+chmod a-w dst/x
+touch a || framework_failure_
+ln a x/b || framework_failure_
+ln a c || framework_failure_
+
+
+# ======================================
+# This must fail -- because x/b cannot be unlinked.
+cp --preserve=link --parents a x/b c dst 2> /dev/null && fail=1
+
+# Source files must remain.
+test -f a || fail=1
+test -f x/b || fail=1
+test -f c || fail=1
+cd dst
+
+# Three destination files must exist.
+test -f a || fail=1
+test -f x/b || fail=1
+test -f c || fail=1
+
+# The i-node numbers of a and c must be the same.
+ia=$(ls -i a) || fail=1; set x $ia; ia=$2
+ic=$(ls -i c) || fail=1; set x $ic; ic=$2
+test "$ia" = "$ic" || fail=1
+
+# The i-node number of x/b must be different.
+ib=$(ls -i x/b) || fail=1; set x $ib; ib=$2
+test "$ia" = "$ib" && fail=1
+
+Exit $fail
diff --git a/tests/mv/hard-4.sh b/tests/mv/hard-4.sh
new file mode 100755
index 0000000..7621f6d
--- /dev/null
+++ b/tests/mv/hard-4.sh
@@ -0,0 +1,41 @@
+#!/bin/sh
+# ensure that mv maintains a in this case: touch a; ln a b; mv a b
+
+# Copyright (C) 2003-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ mv
+touch a || framework_failure_
+ln a b || framework_failure_
+
+# Between coreutils-5.0 and coreutils-8.24, 'a' would be removed.
+# Before coreutils-5.0.1 the issue would not have been diagnosed.
+# We don't emulate the rename(a,b) with unlink(a) as that would
+# introduce races with overlapping mv instances removing both links.
+mv a b 2>err && fail=1
+printf "mv: 'a' and 'b' are the same file\n" > exp
+compare exp err || fail=1
+
+test -r a || fail=1
+test -r b || fail=1
+
+# Make sure it works with --backup.
+mv --backup=simple a b || fail=1
+test -r a && fail=1
+test -r b || fail=1
+test -r b~ || fail=1
+
+Exit $fail
diff --git a/tests/mv/hard-link-1.sh b/tests/mv/hard-link-1.sh
new file mode 100755
index 0000000..94599f2
--- /dev/null
+++ b/tests/mv/hard-link-1.sh
@@ -0,0 +1,41 @@
+#!/bin/sh
+# move a directory containing hard-linked files and
+# make sure the links are preserved
+
+# Copyright (C) 1998-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ mv
+cleanup_() { rm -rf "$other_partition_tmpdir"; }
+. "$abs_srcdir/tests/other-fs-tmpdir"
+
+dir=hlink
+
+mkdir $dir || framework_failure_
+> $dir/a || framework_failure_
+ln $dir/a $dir/b || framework_failure_
+
+mv $dir "$other_partition_tmpdir" || fail=1
+
+# Display inode numbers, one per line.
+ls -1i "$other_partition_tmpdir/$dir" > out || fail=1
+
+# Make sure the inode numbers are the same.
+a=$(sed -n 's/ a$//p' out)
+b=$(sed -n 's/ b$//p' out)
+test "$a" = "$b" || fail=1
+
+Exit $fail
diff --git a/tests/mv/hardlink-case.sh b/tests/mv/hardlink-case.sh
new file mode 100755
index 0000000..ad0cfdf
--- /dev/null
+++ b/tests/mv/hardlink-case.sh
@@ -0,0 +1,37 @@
+#!/bin/sh
+# Ensure multi-hardlinked files are not lost on case insensitive file systems
+
+# Copyright (C) 2014-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ mv
+require_root_
+
+cwd=$(pwd)
+cleanup_() { cd /; umount "$cwd/mnt"; }
+
+truncate -s100M hfs.img || framework_failure_
+mkfs -t hfsplus hfs.img || skip_ 'failed to create hfs file system'
+mkdir mnt || framework_failure_
+mount hfs.img mnt || skip_ 'failed to mount hfs file system'
+
+cd mnt
+touch foo
+ln foo whatever
+returns_ 1 mv foo Foo || fail=1
+test -r foo || fail=1
+
+Exit $fail
diff --git a/tests/mv/i-1.pl b/tests/mv/i-1.pl
new file mode 100755
index 0000000..f2ee0e9
--- /dev/null
+++ b/tests/mv/i-1.pl
@@ -0,0 +1,44 @@
+#!/usr/bin/perl
+# Make sure a 'n' reply to 'mv -i...' aborts the move operation.
+
+# Copyright (C) 2001-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+use strict;
+
+(my $program_name = $0) =~ s|.*/||;
+
+# Turn off localization of executable's output.
+@ENV{qw(LANGUAGE LANG LC_ALL)} = ('C') x 3;
+
+my $test_a = 'a';
+
+my @Tests =
+ (
+ # Make sure a 'n' reply to 'mv -i...' aborts the move operation.
+ [$test_a, '-i',
+ {IN => {src => "a\n"}}, {IN => {dst => "b\n"}}, '<', {IN => "n\n"},
+ {ERR => "mv: overwrite 'dst'? "},
+ {POST => sub { -r 'src' or die "test $test_a failed\n"}},
+ {EXIT => 1},
+ ],
+ );
+
+my $save_temps = $ENV{DEBUG};
+my $verbose = $ENV{VERBOSE};
+
+my $prog = 'mv';
+my $fail = run_tests ($program_name, $prog, \@Tests, $save_temps, $verbose);
+exit $fail;
diff --git a/tests/mv/i-2.sh b/tests/mv/i-2.sh
new file mode 100755
index 0000000..d8e0524
--- /dev/null
+++ b/tests/mv/i-2.sh
@@ -0,0 +1,52 @@
+#!/bin/sh
+# Test both cp and mv for their behavior with -if and -fi
+# The standards (POSIX and SuS) dictate annoyingly inconsistent behavior.
+
+# Copyright (C) 2000-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ cp mv
+
+skip_if_root_
+
+for i in a b c d e f g h; do
+ echo $i > $i || framework_failure_
+done
+chmod 0 b d f h || framework_failure_
+echo y > y || framework_failure_
+
+mv -if a b || fail=1
+mv -fi c d < y >/dev/null 2>&1 || fail=1
+
+# Before 4.0s, this would not prompt.
+cp -if e f < y > out 2>&1 || fail=1
+
+# Make sure out contains the prompt.
+case "$(cat out)" in
+ "cp: replace 'f', overriding mode 0000 (---------)?"*) ;;
+ *) fail=1 ;;
+esac
+
+test -f e || fail=1
+test -f f || fail=1
+compare e f || fail=1
+
+cp -fi g h < y > out 2>&1 || fail=1
+test -f g || fail=1
+test -f h || fail=1
+compare g h || fail=1
+
+Exit $fail
diff --git a/tests/mv/i-3.sh b/tests/mv/i-3.sh
new file mode 100755
index 0000000..4162d16
--- /dev/null
+++ b/tests/mv/i-3.sh
@@ -0,0 +1,72 @@
+#!/bin/sh
+# Make sure that 'mv file unwritable-file' prompts the user
+# and that 'mv -f file unwritable-file' doesn't.
+
+# Copyright (C) 2001-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ mv
+require_controlling_input_terminal_
+skip_if_root_
+trap '' TTIN # Ignore SIGTTIN
+
+uname -s | grep 'BSD$' && skip_ 'known spurious failure on *BSD'
+
+touch f g h i || framework_failure_
+chmod 0 g i || framework_failure_
+
+
+ls /dev/stdin >/dev/null 2>&1 \
+ || skip_ 'there is no /dev/stdin file'
+
+# work around a dash bug when redirecting
+# from symlinked ttys in the background
+tty=$(readlink -f /dev/stdin)
+
+test -r "$tty" 2>&1 \
+ || skip_ '/dev/stdin is not readable'
+
+# Terminate any background processes
+cleanup_() { kill $pid 2>/dev/null && wait $pid; }
+
+mv f g < $tty > out 2>&1 & pid=$!
+
+# Test for the expected prompt; sleep upon non-match.
+check_overwrite_prompt()
+{
+ local delay="$1"
+ case "$(cat out)" in
+ "mv: replace 'g', overriding mode 0000"*) ;;
+ *) sleep $delay; return 1;;
+ esac
+}
+
+# Wait for up to 12.7 seconds for the expected prompt.
+retry_delay_ check_overwrite_prompt .1 7 || { fail=1; cat out; }
+
+cleanup_
+
+mv -f h i > out 2>&1 || fail=1
+test -f i || fail=1
+test -f h && fail=1
+
+# Make sure there was no prompt.
+case "$(cat out)" in
+ '') ;;
+ *) fail=1 ;;
+esac
+
+Exit $fail
diff --git a/tests/mv/i-4.sh b/tests/mv/i-4.sh
new file mode 100755
index 0000000..4b90342
--- /dev/null
+++ b/tests/mv/i-4.sh
@@ -0,0 +1,47 @@
+#!/bin/sh
+# make sure 'mv -i a b' does its job with a positive response
+
+# Copyright (C) 2001-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ mv
+
+for i in a b; do
+ echo $i > $i || framework_failure_
+done
+echo y > y || framework_failure_
+echo n > n || framework_failure_
+
+mv -i a b < y >/dev/null 2>&1 || fail=1
+
+# Make sure out contains the prompt.
+case "$(cat b)" in
+ a) ;;
+ *) fail=1 ;;
+esac
+
+# Ensure that mv -i a b works properly with 'n' and 'y' responses,
+# when a and b are hard links to the same file.
+rm -f a b
+echo a > a
+ln a b
+mv -i a b < y 2>err && fail=1
+test -r a || fail=1
+test -r b || fail=1
+printf "mv: 'a' and 'b' are the same file\n" > exp
+compare exp err || fail=1
+
+Exit $fail
diff --git a/tests/mv/i-5.sh b/tests/mv/i-5.sh
new file mode 100755
index 0000000..fabb275
--- /dev/null
+++ b/tests/mv/i-5.sh
@@ -0,0 +1,29 @@
+#!/bin/sh
+# Make sure 'mv -i dir file' prompts before failing.
+
+# Copyright (C) 2006-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ mv
+
+mkdir a || framework_failure_
+touch b || framework_failure_
+
+
+# coreutils 6.2 mv would neglect to prompt in this case.
+echo n | returns_ 1 mv -i a b 2>/dev/null || fail=1
+
+Exit $fail
diff --git a/tests/mv/i-link-no.sh b/tests/mv/i-link-no.sh
new file mode 100755
index 0000000..747c542
--- /dev/null
+++ b/tests/mv/i-link-no.sh
@@ -0,0 +1,43 @@
+#!/bin/sh
+# Show that mv doesn't preserve links to files the user has declined to move.
+
+# Copyright (C) 2002-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ mv
+
+mkdir a b || framework_failure_
+echo foo > a/foo || framework_failure_
+ln a/foo a/bar || framework_failure_
+echo FUBAR > b/FUBAR || framework_failure_
+ln b/FUBAR b/bar || framework_failure_
+chmod a-w b/bar || framework_failure_
+echo n > no || framework_failure_
+
+
+mv a/bar a/foo b < no > out 2> err || fail=1
+touch exp
+touch exp_err
+
+compare exp out || fail=1
+compare exp_err err || fail=1
+
+case "$(cat b/foo)" in
+ foo) ;;
+ *) fail=1;;
+esac
+
+Exit $fail
diff --git a/tests/mv/into-self-2.sh b/tests/mv/into-self-2.sh
new file mode 100755
index 0000000..337d2b2
--- /dev/null
+++ b/tests/mv/into-self-2.sh
@@ -0,0 +1,52 @@
+#!/bin/sh
+# Force mv to use the copying code.
+# Consider the case where SRC and DEST are on different
+# partitions and DEST is a symlink to SRC.
+
+# Copyright (C) 1998-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ mv
+cleanup_() { rm -rf "$other_partition_tmpdir"; }
+. "$abs_srcdir/tests/other-fs-tmpdir"
+
+file="$other_partition_tmpdir/file"
+symlink=symlink
+
+
+echo whatever > $file || framework_failure_
+ln -s $file $symlink || framework_failure_
+
+# This mv command should exit nonzero.
+mv $symlink $file > out 2>&1 && fail=1
+
+# This should succeed.
+mv $file $symlink || fail=1
+
+sed \
+ -e "s,mv:,XXX:," \
+ -e "s,$file,YYY," \
+ -e "s,$symlink,ZZZ," \
+ out > out2
+
+cat > exp <<\EOF
+XXX: 'ZZZ' and 'YYY' are the same file
+EOF
+#'
+
+compare exp out2 || fail=1
+
+Exit $fail
diff --git a/tests/mv/into-self-3.sh b/tests/mv/into-self-3.sh
new file mode 100755
index 0000000..31612d6
--- /dev/null
+++ b/tests/mv/into-self-3.sh
@@ -0,0 +1,41 @@
+#!/bin/sh
+# move a directory into itself, with a twist
+
+# Copyright (C) 1998-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ mv
+
+dir1=is3-dir1
+dir2=is3-dir2
+
+mkdir $dir1 $dir2 || framework_failure_
+
+# This mv command should exit nonzero.
+mv $dir1 $dir2 $dir2 > out 2>&1 && fail=1
+
+sed \
+ -e "s,mv:,XXX:,g" \
+ -e "s,$dir2,ZZZ,g" \
+ out > out2
+
+cat > exp <<\EOF
+XXX: cannot move 'ZZZ' to a subdirectory of itself, 'ZZZ/ZZZ'
+EOF
+
+compare exp out2 || fail=1
+
+Exit $fail
diff --git a/tests/mv/into-self-4.sh b/tests/mv/into-self-4.sh
new file mode 100755
index 0000000..0b2664a
--- /dev/null
+++ b/tests/mv/into-self-4.sh
@@ -0,0 +1,34 @@
+#!/bin/sh
+# confirm that 'mv symlink symlink' doesn't remove symlink
+# Based on an example from David Luyer.
+
+# Copyright (C) 2001-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ mv
+
+touch file || framework_failure_
+ln -s file s || framework_failure_
+
+
+# This must fail.
+returns_ 1 mv s s 2> /dev/null || fail=1
+
+# But the symlink, s, must not be removed.
+# Before 4.0.36, 's' would have been removed.
+test -f s || fail=1
+
+Exit $fail
diff --git a/tests/mv/into-self.sh b/tests/mv/into-self.sh
new file mode 100755
index 0000000..66b65ce
--- /dev/null
+++ b/tests/mv/into-self.sh
@@ -0,0 +1,53 @@
+#!/bin/sh
+# Demonstrate how mv fails when it tries to move a directory into itself.
+
+# Copyright (C) 1998-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ mv
+
+dir=toself-dir
+file=toself-file
+
+rm -rf $dir $file || framework_failure_
+mkdir -p $dir/a/b || framework_failure_
+touch $file || framework_failure_
+
+
+# This mv command should fail.
+mv $dir $file $dir > out 2>&1 && fail=1
+
+sed \
+ -e "s,mv:,XXX:," \
+ -e "s,$dir,SRC," \
+ -e "s,$dir/$dir,DEST," \
+ out > out2
+
+cat > exp <<\EOF
+XXX: cannot move 'SRC' to a subdirectory of itself, 'DEST'
+EOF
+
+compare exp out2 || fail=1
+
+# Make sure the file is gone.
+test -f $file && fail=1
+# Make sure the directory is *not* moved.
+test -d $dir || fail=1
+test -d $dir/$dir && fail=1
+# Make sure the file has been moved to the right place.
+test -f $dir/$file || fail=1
+
+Exit $fail
diff --git a/tests/mv/leak-fd.sh b/tests/mv/leak-fd.sh
new file mode 100755
index 0000000..d976627
--- /dev/null
+++ b/tests/mv/leak-fd.sh
@@ -0,0 +1,55 @@
+#!/bin/sh
+# Exercise mv's file-descriptor-leak bug, reported against coreutils-5.2.1
+# and fixed (properly) on 2004-10-21.
+
+# Copyright (C) 2004-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+# limit so don't run it by default.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ mv
+skip_if_root_
+cleanup_() { rm -rf "$other_partition_tmpdir"; }
+. "$abs_srcdir/tests/other-fs-tmpdir"
+
+# This test is relatively expensive, and might well evoke a
+# framework-failure on systems with a smaller command-line length
+expensive_
+
+b="0 1 2 3 4 5 6 7 8 9
+a b c d e f g h i j k l m n o p q r s t u v w x y z
+_A _B _C _D _E _F _G _H _I _J _K _L _M _N _O _P _Q _R _S _T _U _V _W _X _Y _Z"
+
+for i in $(echo $b); do
+ echo $i
+ for j in $b; do
+ echo $i$j
+ done
+done > .dirs
+mkdir $(cat .dirs) || framework_failure_
+sed 's,$,/f,' .dirs | xargs touch
+
+last_file=$(tail -n1 .dirs)/f
+test -f $last_file || framework_failure_
+
+
+mv * "$other_partition_tmpdir" || fail=1
+test -f $last_file/f && fail=1
+rm .dirs
+
+out=$(ls -A) || fail=1
+test -z "$out" || fail=1
+
+Exit $fail
diff --git a/tests/mv/mv-n.sh b/tests/mv/mv-n.sh
new file mode 100755
index 0000000..6054780
--- /dev/null
+++ b/tests/mv/mv-n.sh
@@ -0,0 +1,64 @@
+#!/bin/sh
+# Test whether mv -n works as documented (not overwrite target).
+
+# Copyright (C) 2006-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ mv
+
+
+# test miscellaneous combinations of -f -i -n parameters
+touch a b || framework_failure_
+echo "renamed 'a' -> 'b'" > out_move
+echo "mv: not replacing 'b'" > err_skip || framework_failure_
+> out_empty
+
+# ask for overwrite, answer no
+touch a b || framework_failure_
+echo n | returns_ 1 mv -vi a b 2>/dev/null > out1 || fail=1
+compare out1 out_empty || fail=1
+
+# ask for overwrite, answer yes
+touch a b || framework_failure_
+echo y | mv -vi a b 2>/dev/null > out2 || fail=1
+compare out2 out_move || fail=1
+
+# -n wins (as the last option)
+touch a b || framework_failure_
+echo y | returns_ 1 mv -vin a b 2>/dev/null > out3 || fail=1
+compare out3 out_empty || fail=1
+
+# -n wins (non verbose)
+touch a b || framework_failure_
+echo y | returns_ 1 mv -in a b 2>err3 > out3 || fail=1
+compare out3 out_empty || fail=1
+compare err3 err_skip || fail=1
+
+# -n wins (as the last option)
+touch a b || framework_failure_
+echo y | returns_ 1 mv -vfn a b 2>/dev/null > out4 || fail=1
+compare out4 out_empty || fail=1
+
+# -n wins (as the last option)
+touch a b || framework_failure_
+echo y | returns_ 1 mv -vifn a b 2>/dev/null > out5 || fail=1
+compare out5 out_empty || fail=1
+
+# options --backup and --no-clobber are mutually exclusive
+touch a || framework_failure_
+returns_ 1 mv -bn a b 2>/dev/null || fail=1
+
+Exit $fail
diff --git a/tests/mv/mv-special-1.sh b/tests/mv/mv-special-1.sh
new file mode 100755
index 0000000..af1b793
--- /dev/null
+++ b/tests/mv/mv-special-1.sh
@@ -0,0 +1,75 @@
+#!/bin/sh
+# Test "mv" with special files.
+
+# Copyright (C) 1998-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ mv
+cleanup_() { rm -rf "$other_partition_tmpdir"; }
+. "$abs_srcdir/tests/other-fs-tmpdir"
+
+null=mv-null
+dir=mv-dir
+
+rm -f $null || framework_failure_
+mknod $null p || framework_failure_
+test -p $null || framework_failure_
+mkdir -p $dir/a/b/c $dir/d/e/f || framework_failure_
+touch $dir/a/b/c/file1 $dir/d/e/f/file2 || framework_failure_
+
+# We used to...
+# exit 77 here to indicate that we couldn't run the test.
+# At least running on SunOS 4.1.4, using a directory NFS mounted
+# from an OpenBSD system, the above mknod fails.
+# It's not worth making an exception any more.
+
+mv --verbose $null $dir "$other_partition_tmpdir" > out || fail=1
+# Make sure the files are gone.
+test -p $null && fail=1
+test -d $dir && fail=1
+# Make sure they were moved.
+test -p "$other_partition_tmpdir/$null" || fail=1
+test -d "$other_partition_tmpdir/$dir/a/b/c" || fail=1
+
+# POSIX says rename (A, B) can succeed if A and B are on different file systems,
+# so ignore chatter about when files are removed and copied rather than renamed.
+sed "
+ /^removed /d
+ s,renamed ,,
+ s,copied ,,
+ s,$other_partition_tmpdir,XXX,
+ s,created directory 'XXX/\(.*\)','\1' -> 'XXX/\1',
+" out | sort > out2
+
+cat <<EOF | sort > exp
+'$null' -> 'XXX/$null'
+'$dir' -> 'XXX/$dir'
+'$dir/a' -> 'XXX/$dir/a'
+'$dir/a/b' -> 'XXX/$dir/a/b'
+'$dir/a/b/c' -> 'XXX/$dir/a/b/c'
+'$dir/a/b/c/file1' -> 'XXX/$dir/a/b/c/file1'
+'$dir/d' -> 'XXX/$dir/d'
+'$dir/d/e' -> 'XXX/$dir/d/e'
+'$dir/d/e/f' -> 'XXX/$dir/d/e/f'
+'$dir/d/e/f/file2' -> 'XXX/$dir/d/e/f/file2'
+EOF
+
+compare exp out2 || fail=1
+
+# cd "$other_partition_tmpdir"
+# ls -l -A -R "$other_partition_tmpdir"
+
+Exit $fail
diff --git a/tests/mv/no-copy.sh b/tests/mv/no-copy.sh
new file mode 100755
index 0000000..5a55fdf
--- /dev/null
+++ b/tests/mv/no-copy.sh
@@ -0,0 +1,33 @@
+#!/bin/sh
+# Test mv --no-copy.
+
+# Copyright (C) 2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ mv
+cleanup_() { rm -rf "$other_partition_tmpdir"; }
+. "$abs_srcdir/tests/other-fs-tmpdir"
+
+mkdir dir || framework_failure_
+> dir/a || framework_failure_
+> file || framework_failure_
+
+returns_ 1 mv --no-copy dir "$other_partition_tmpdir" || fail=1
+returns_ 1 mv --no-copy file "$other_partition_tmpdir" || fail=1
+mv dir "$other_partition_tmpdir" || fail=1
+mv file "$other_partition_tmpdir" || fail=1
+
+Exit $fail
diff --git a/tests/mv/no-target-dir.sh b/tests/mv/no-target-dir.sh
new file mode 100755
index 0000000..82df49b
--- /dev/null
+++ b/tests/mv/no-target-dir.sh
@@ -0,0 +1,51 @@
+#!/bin/sh
+# ensure that --no-target-directory (-T) works when the destination is
+# an empty directory.
+
+# Copyright (C) 2006-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ mv
+
+LS_FAILURE=2
+
+mkdir -p d/sub empty src d2/sub e2 || framework_failure_
+touch f || framework_failure_
+
+# Skip this test if there's an underlying kernel bug.
+mkdir a b b/a || framework_failure_
+
+mv a b ||
+ skip_ "your kernel's rename syscall is buggy"
+
+
+# This should succeed, since both src and dest are directories,
+# and the dest dir is empty.
+mv -fT d empty || fail=1
+
+# Ensure that the source, d, is gone.
+returns_ $LS_FAILURE ls -d d > /dev/null 2>&1 || fail=1
+
+# Ensure that the dest dir now has a subdirectory.
+test -d empty/sub || fail=1
+
+# rename must fail, since the dest is non-empty.
+returns_ 1 mv -fT src d2 2> /dev/null || fail=1
+
+# rename must fail, since the src is not a directory.
+returns_ 1 mv -fT f e2 2> /dev/null || fail=1
+
+Exit $fail
diff --git a/tests/mv/part-fail.sh b/tests/mv/part-fail.sh
new file mode 100755
index 0000000..19c4140
--- /dev/null
+++ b/tests/mv/part-fail.sh
@@ -0,0 +1,55 @@
+#!/bin/sh
+# Make sure we give a sensible diagnostic when a cross-device 'mv'
+# fails, e.g., because the destination cannot be unlinked.
+# This is a bit fragile since it relies on the string used
+# for EPERM: 'permission denied'.
+
+# Copyright (C) 2002-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ mv
+skip_if_root_
+cleanup_() { t=$other_partition_tmpdir; chmod -R 700 "$t"; rm -rf "$t"; }
+. "$abs_srcdir/tests/other-fs-tmpdir"
+
+touch k "$other_partition_tmpdir/k" || framework_failure_
+chmod u-w "$other_partition_tmpdir" || framework_failure_
+
+
+mv -f k "$other_partition_tmpdir" 2> out && fail=1
+printf \
+"mv: inter-device move failed: '%s' to '%s';"\
+' unable to remove target: Permission denied\n' \
+ k "$other_partition_tmpdir/k" >exp
+
+# On some (less-compliant) systems, we get EPERM in this case.
+# Accept either diagnostic.
+cat <<EOF > exp2
+mv: cannot move 'k' to '$other_partition_tmpdir/k': Permission denied
+EOF
+
+if cmp out exp >/dev/null 2>&1; then
+ :
+else
+ if cmp out exp2; then
+ :
+ else
+ fail=1
+ fi
+fi
+test $fail = 1 && compare exp out
+
+Exit $fail
diff --git a/tests/mv/part-hardlink.sh b/tests/mv/part-hardlink.sh
new file mode 100755
index 0000000..9c65684
--- /dev/null
+++ b/tests/mv/part-hardlink.sh
@@ -0,0 +1,43 @@
+#!/bin/sh
+# Ensure that hard links are preserved when moving between partitions
+# and when the links are in separate command line arguments.
+# For additional constraints, see the comment in copy.c.
+# Before coreutils-5.2.1, this test would fail.
+
+# Copyright (C) 2004-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ mv
+cleanup_() { rm -rf "$other_partition_tmpdir"; }
+. "$abs_srcdir/tests/other-fs-tmpdir"
+
+touch f || framework_failure_
+ln f g || framework_failure_
+mkdir a b || framework_failure_
+touch a/1 || framework_failure_
+ln a/1 b/1 || framework_failure_
+
+
+mv f g "$other_partition_tmpdir" || fail=1
+mv a b "$other_partition_tmpdir" || fail=1
+
+cd "$other_partition_tmpdir"
+set $(ls -Ci f g)
+test $1 = $3 || fail=1
+set $(ls -Ci a/1 b/1)
+test $1 = $3 || fail=1
+
+Exit $fail
diff --git a/tests/mv/part-rename.sh b/tests/mv/part-rename.sh
new file mode 100755
index 0000000..5f88550
--- /dev/null
+++ b/tests/mv/part-rename.sh
@@ -0,0 +1,57 @@
+#!/bin/sh
+# Test various cases for moving directories across file systems
+
+# Copyright (C) 2000-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ mv
+cleanup_() { rm -rf "$other_partition_tmpdir"; }
+. "$abs_srcdir/tests/other-fs-tmpdir"
+
+
+# Moving a directory specified with a trailing slash from one partition to
+# another, and giving it a different name at the destination would cause mv
+# to get a failed assertion.
+mkdir foo || framework_failure_
+mv foo/ "$other_partition_tmpdir/bar" || fail=1
+
+
+# Moving a non directory from source shouldn't replace empty dir in dest
+touch bar || framework_failure_
+returns_ 1 mv bar "$other_partition_tmpdir/" || fail=1
+
+
+# Moving a directory from source shouldn't replace non directory in dest
+mkdir bar2
+touch "$other_partition_tmpdir/bar2"
+returns_ 1 mv bar2 "$other_partition_tmpdir/" || fail=1
+
+
+# As per POSIX moving directory from source should replace empty dir in dest
+mkdir bar3
+touch bar3/file
+mkdir "$other_partition_tmpdir/bar3"
+mv bar3 "$other_partition_tmpdir/" || fail=1
+test -e "$other_partition_tmpdir/bar3/file" || fail=1
+
+
+# As per POSIX moving directory from source shouldn't update dir in dest
+mkdir bar3
+touch bar3/file2
+returns_ 1 mv bar3 "$other_partition_tmpdir/" || fail=1
+test -e "$other_partition_tmpdir/bar3/file2" && fail=1
+
+Exit $fail
diff --git a/tests/mv/part-symlink.sh b/tests/mv/part-symlink.sh
new file mode 100755
index 0000000..d6cd836
--- /dev/null
+++ b/tests/mv/part-symlink.sh
@@ -0,0 +1,262 @@
+#!/bin/sh
+# make sure cp and mv can handle many combinations of local and
+# other-partition regular/symlink'd files.
+
+# Copyright (C) 2000-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ cp mv
+
+cleanup_() { rm -rf "$other_partition_tmpdir"; }
+. "$abs_srcdir/tests/other-fs-tmpdir"
+
+# On NFS on Linux 2.6.9 at least we get:
+# mv: preserving permissions for 'rem_sl': Operation not supported
+require_local_dir_
+
+pwd_tmp=$(pwd)
+
+# Unset CDPATH. Otherwise, output from the 'cd dir' command
+# can make this test fail.
+(unset CDPATH) >/dev/null 2>&1 && unset CDPATH
+
+
+# Four cases:
+# local regular file w/symlink on another partition
+# (loc_reg, rem_sl)
+# (rem_sl, loc_reg)
+# local symlink to regular file on another partition
+# (loc_sl, rem_reg)
+# (rem_reg, loc_sl)
+
+# Exercise those four cases for each of
+# cp and mv, with lots of combinations of options.
+
+exec 1> actual
+
+# FIXME: This should be bigger: like more than 8k
+contents=XYZ
+
+loc_reg=loc_reg
+loc_sl=loc_sl
+rem_reg=$other_partition_tmpdir/rem_reg
+rem_sl=$other_partition_tmpdir/rem_sl
+
+for copy in cp mv; do
+ for args in \
+ 'loc_reg rem_sl' \
+ 'rem_sl loc_reg' \
+ 'loc_sl rem_reg' \
+ 'rem_reg loc_sl' \
+ ; do
+ for options in '' --rem '--rem -d' '--rem -b' -b -bd -d; do
+ case "$options" in *d*|*--rem*) test $copy = mv && continue;; esac
+ rm -rf dir || fail=1
+ rm -f "$other_partition_tmpdir"/* || fail=1
+ mkdir dir || fail=1
+ cd dir || fail=1
+ case "$args" in *loc_reg*) reg_abs="$(pwd)/$loc_reg" ;; esac
+ case "$args" in *rem_reg*) reg_abs=$rem_reg ;; esac
+ case "$args" in *loc_sl*) slink=$loc_sl ;; esac
+ case "$args" in *rem_sl*) slink=$rem_sl ;; esac
+
+ echo $contents > "$reg_abs" || framework_failure_
+ ln -nsf "$reg_abs" $slink || fail=1
+ actual_args=$(echo $args|sed 's,^,$,;s/ / $/')
+ actual_args=$(eval echo $actual_args)
+
+ (
+ (
+ # echo 1>&2 cp $options $args
+ $copy $options $actual_args 2>.err
+ copy_status=$?
+ echo $copy_status $copy $options $args
+
+ # Normalize the program name in the error output,
+ # remove any site-dependent part of other-partition file name,
+ # and put brackets around the output.
+ test -s .err \
+ && {
+ echo ' [' | tr -d '\n'
+ sed 's/^[^:][^:]*\(..\):/\1:/;s,'"$other_partition_tmpdir/,," .err |
+ tr -d '\n'
+ echo ']'
+ }
+ # Strip off all but the file names.
+ # Remove any site-dependent part of each file name.
+ ls=$(ls -gG --ignore=.err . \
+ | sed \
+ -e '/^total /d' \
+ -e "s,$other_partition_tmpdir/,," \
+ -e "s,$pwd_tmp/,," \
+ -e 's/^[^ ]* *[^ ]* *[^ ]* *[^ ]* *[^ ]* *[^ ]* *//')
+ ls2=$(cd "$other_partition_tmpdir" && ls -gG --ignore=.err . \
+ | sed \
+ -e '/^total /d' \
+ -e "s,$other_partition_tmpdir/,," \
+ -e "s,$pwd_tmp/,," \
+ -e 's/^[^ ]* *[^ ]* *[^ ]* *[^ ]* *[^ ]* *[^ ]* *//')
+ echo " ("$ls") ("$ls2")"
+
+ # If the command failed, then it must not have changed the files.
+ if test $copy_status != 0; then
+ for f in $actual_args; do
+ test -f $f ||
+ { echo " $copy FAILED but removed $f"; continue; }
+ case "$(cat $f)" in
+ "$contents") ;;
+ *) echo " $copy FAILED but modified $f";;
+ esac
+ done
+ fi
+
+ if test $copy = cp; then
+ # Make sure the original is unchanged and that
+ # the destination is a copy.
+ for f in $actual_args; do
+ if test -f $f; then
+ if test $copy_status != 0; then
+ test
+ fi
+ case "$(cat $f)" in
+ "$contents") ;;
+ *) echo " $copy FAILED";;
+ esac
+ else
+ echo " symlink-loop"
+ fi
+ done
+ fi
+ )
+ ) | sed 's/ *$//'
+ cd ..
+ done
+ echo
+ done
+done
+
+test $fail = 1 &&
+ { (exit 1); exit; }
+
+cat <<\EOF > expected || framework_failure_
+1 cp loc_reg rem_sl
+ [cp: 'loc_reg' and 'rem_sl' are the same file]
+ (loc_reg) (rem_sl -> dir/loc_reg)
+0 cp --rem loc_reg rem_sl
+ (loc_reg) (rem_sl)
+0 cp --rem -d loc_reg rem_sl
+ (loc_reg) (rem_sl)
+0 cp --rem -b loc_reg rem_sl
+ (loc_reg) (rem_sl rem_sl~ -> dir/loc_reg)
+0 cp -b loc_reg rem_sl
+ (loc_reg) (rem_sl rem_sl~ -> dir/loc_reg)
+0 cp -bd loc_reg rem_sl
+ (loc_reg) (rem_sl rem_sl~ -> dir/loc_reg)
+1 cp -d loc_reg rem_sl
+ [cp: 'loc_reg' and 'rem_sl' are the same file]
+ (loc_reg) (rem_sl -> dir/loc_reg)
+
+1 cp rem_sl loc_reg
+ [cp: 'rem_sl' and 'loc_reg' are the same file]
+ (loc_reg) (rem_sl -> dir/loc_reg)
+1 cp --rem rem_sl loc_reg
+ [cp: 'rem_sl' and 'loc_reg' are the same file]
+ (loc_reg) (rem_sl -> dir/loc_reg)
+1 cp --rem -d rem_sl loc_reg
+ [cp: 'rem_sl' and 'loc_reg' are the same file]
+ (loc_reg) (rem_sl -> dir/loc_reg)
+1 cp --rem -b rem_sl loc_reg
+ [cp: 'rem_sl' and 'loc_reg' are the same file]
+ (loc_reg) (rem_sl -> dir/loc_reg)
+1 cp -b rem_sl loc_reg
+ [cp: 'rem_sl' and 'loc_reg' are the same file]
+ (loc_reg) (rem_sl -> dir/loc_reg)
+0 cp -bd rem_sl loc_reg
+ (loc_reg -> dir/loc_reg loc_reg~) (rem_sl -> dir/loc_reg)
+ symlink-loop
+ symlink-loop
+1 cp -d rem_sl loc_reg
+ [cp: 'rem_sl' and 'loc_reg' are the same file]
+ (loc_reg) (rem_sl -> dir/loc_reg)
+
+1 cp loc_sl rem_reg
+ [cp: 'loc_sl' and 'rem_reg' are the same file]
+ (loc_sl -> rem_reg) (rem_reg)
+1 cp --rem loc_sl rem_reg
+ [cp: 'loc_sl' and 'rem_reg' are the same file]
+ (loc_sl -> rem_reg) (rem_reg)
+1 cp --rem -d loc_sl rem_reg
+ [cp: 'loc_sl' and 'rem_reg' are the same file]
+ (loc_sl -> rem_reg) (rem_reg)
+1 cp --rem -b loc_sl rem_reg
+ [cp: 'loc_sl' and 'rem_reg' are the same file]
+ (loc_sl -> rem_reg) (rem_reg)
+1 cp -b loc_sl rem_reg
+ [cp: 'loc_sl' and 'rem_reg' are the same file]
+ (loc_sl -> rem_reg) (rem_reg)
+0 cp -bd loc_sl rem_reg
+ (loc_sl -> rem_reg) (rem_reg -> rem_reg rem_reg~)
+ symlink-loop
+ symlink-loop
+1 cp -d loc_sl rem_reg
+ [cp: 'loc_sl' and 'rem_reg' are the same file]
+ (loc_sl -> rem_reg) (rem_reg)
+
+1 cp rem_reg loc_sl
+ [cp: 'rem_reg' and 'loc_sl' are the same file]
+ (loc_sl -> rem_reg) (rem_reg)
+0 cp --rem rem_reg loc_sl
+ (loc_sl) (rem_reg)
+0 cp --rem -d rem_reg loc_sl
+ (loc_sl) (rem_reg)
+0 cp --rem -b rem_reg loc_sl
+ (loc_sl loc_sl~ -> rem_reg) (rem_reg)
+0 cp -b rem_reg loc_sl
+ (loc_sl loc_sl~ -> rem_reg) (rem_reg)
+0 cp -bd rem_reg loc_sl
+ (loc_sl loc_sl~ -> rem_reg) (rem_reg)
+1 cp -d rem_reg loc_sl
+ [cp: 'rem_reg' and 'loc_sl' are the same file]
+ (loc_sl -> rem_reg) (rem_reg)
+
+0 mv loc_reg rem_sl
+ () (rem_sl)
+0 mv -b loc_reg rem_sl
+ () (rem_sl rem_sl~ -> dir/loc_reg)
+
+1 mv rem_sl loc_reg
+ [mv: 'rem_sl' and 'loc_reg' are the same file]
+ (loc_reg) (rem_sl -> dir/loc_reg)
+0 mv -b rem_sl loc_reg
+ (loc_reg -> dir/loc_reg loc_reg~) ()
+
+1 mv loc_sl rem_reg
+ [mv: 'loc_sl' and 'rem_reg' are the same file]
+ (loc_sl -> rem_reg) (rem_reg)
+0 mv -b loc_sl rem_reg
+ () (rem_reg -> rem_reg rem_reg~)
+
+0 mv rem_reg loc_sl
+ (loc_sl) ()
+0 mv -b rem_reg loc_sl
+ (loc_sl loc_sl~ -> rem_reg) ()
+
+EOF
+
+# Redirect to stderr, since stdout is already taken.
+compare expected actual 1>&2 || fail=1
+
+Exit $fail
diff --git a/tests/mv/partition-perm.sh b/tests/mv/partition-perm.sh
new file mode 100755
index 0000000..566346c
--- /dev/null
+++ b/tests/mv/partition-perm.sh
@@ -0,0 +1,37 @@
+#!/bin/sh
+# Make sure permissions are preserved when moving from one partition to another.
+
+# Copyright (C) 1999-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ mv
+cleanup_() { rm -rf "$other_partition_tmpdir"; }
+. "$abs_srcdir/tests/other-fs-tmpdir"
+
+> file || framework_failure_
+chmod a=rwx file || framework_failure_
+
+umask 077
+mv file "$other_partition_tmpdir" || framework_failure_
+
+test -f file && fail=1
+test -f "$other_partition_tmpdir/file" || fail=1
+
+# This would have failed with the mv from fileutils-4.0i.
+mode=$(ls -l "$other_partition_tmpdir/file" | cut -b-10)
+test "$mode" = "-rwxrwxrwx" || fail=1
+
+Exit $fail
diff --git a/tests/mv/perm-1.sh b/tests/mv/perm-1.sh
new file mode 100755
index 0000000..50eb0a2
--- /dev/null
+++ b/tests/mv/perm-1.sh
@@ -0,0 +1,35 @@
+#!/bin/sh
+# ensure that mv gives one diagnostic, not two, when failing
+# due to lack of permissions
+
+# Copyright (C) 2002-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ mv
+skip_if_root_
+
+mkdir -p no-write/dir || framework_failure_
+chmod ug-w no-write || framework_failure_
+
+
+mv no-write/dir . > out 2>&1 && fail=1
+cat <<\EOF > exp
+mv: cannot move 'no-write/dir' to './dir': Permission denied
+EOF
+
+compare exp out || fail=1
+
+Exit $fail
diff --git a/tests/mv/sticky-to-xpart.sh b/tests/mv/sticky-to-xpart.sh
new file mode 100755
index 0000000..860ddd3
--- /dev/null
+++ b/tests/mv/sticky-to-xpart.sh
@@ -0,0 +1,68 @@
+#!/bin/sh
+# A cross-partition move of a file in a sticky tmpdir and owned by
+# someone else would evoke an invalid diagnostic:
+# mv: cannot remove 'x': Operation not permitted
+# Affects coreutils-6.0-6.9.
+
+# Copyright (C) 2007-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ mv
+require_root_
+
+cleanup_() { rm -rf "$other_partition_tmpdir"; }
+. "$abs_srcdir/tests/other-fs-tmpdir"
+
+# Set up to run a test where non-root user tries to move a root-owned
+# file from a sticky tmpdir to a directory owned by that user on
+# a different partition.
+
+mkdir t || framework_failure_
+chmod a=rwx,o+t t || framework_failure_
+echo > t/root-owned || framework_failure_
+chmod a+r t/root-owned || framework_failure_
+chown "$NON_ROOT_USERNAME" "$other_partition_tmpdir" || framework_failure_
+
+# We have to allow $NON_ROOT_USERNAME access to ".".
+chmod go+x . || framework_failure_
+
+
+# Ensure that $NON_ROOT_USERNAME can access the required version of mv.
+version=$(
+ chroot --skip-chdir --user=$NON_ROOT_USERNAME / env PATH="$PATH" \
+ mv --version |
+ sed -n '1s/.* //p'
+)
+case $version in
+ $PACKAGE_VERSION) ;;
+ *) skip_ "cannot access just-built mv as user $NON_ROOT_USERNAME";;
+esac
+
+chroot --skip-chdir --user=$NON_ROOT_USERNAME / env PATH="$PATH" \
+ mv t/root-owned "$other_partition_tmpdir" 2> out-t && fail=1
+
+# On some systems, we get 'Not owner'. Convert it.
+# On other systems (HPUX), we get 'Permission denied'. Convert it, too.
+onp='Operation not permitted'
+sed "s/Not owner/$onp/;s/Permission denied/$onp/" out-t > out
+
+cat <<\EOF > exp
+mv: cannot remove 't/root-owned': Operation not permitted
+EOF
+
+compare exp out || fail=1
+
+Exit $fail
diff --git a/tests/mv/symlink-onto-hardlink-to-self.sh b/tests/mv/symlink-onto-hardlink-to-self.sh
new file mode 100755
index 0000000..b53a41a
--- /dev/null
+++ b/tests/mv/symlink-onto-hardlink-to-self.sh
@@ -0,0 +1,63 @@
+#!/bin/sh
+# Demonstrate that when moving a symlink onto a hardlink-to-that-symlink,
+# an error is presented. Depending on your kernel (e.g., Linux, Solaris,
+# but not NetBSD), prior to coreutils-8.16, the mv would successfully perform
+# a no-op. I.e., surprisingly, mv s1 s2 would succeed, yet fail to remove s1.
+
+# Copyright (C) 2012-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ mv
+
+# Create a file f, and a symlink s1 to that file.
+touch f || framework_failure_
+ln -s f s2 || framework_failure_
+
+# Attempt to create a hard link to that symlink.
+# On some systems, it's not possible: they create a hard link to the referent.
+ln s2 s1 || framework_failure_
+
+# If s1 is not a symlink, skip this test.
+test -h s1 \
+ || skip_ your kernel or file system cannot create a hard link to a symlink
+
+for opt in '' --backup; do
+
+ if test "$opt" = --backup; then
+ mv $opt s1 s2 > out 2>&1 || fail=1
+ compare /dev/null out || fail=1
+
+ # Ensure that s1 is gone.
+ test -e s1 && fail=1
+
+ # With --backup, ensure that the backup file was created.
+ ref=$(readlink s2~) || fail=1
+ test "$ref" = f || fail=1
+ else
+ echo "mv: 's1' and 's2' are the same file" > exp
+ mv $opt s1 s2 2>err && fail=1
+ compare exp err || fail=1
+
+ # Ensure that s1 is still present.
+ test -e s1 || fail=1
+
+ # Without --backup, ensure there is no backup file.
+ test -e s2~ && fail=1
+ fi
+
+done
+
+Exit $fail
diff --git a/tests/mv/symlink-onto-hardlink.sh b/tests/mv/symlink-onto-hardlink.sh
new file mode 100755
index 0000000..01c138a
--- /dev/null
+++ b/tests/mv/symlink-onto-hardlink.sh
@@ -0,0 +1,41 @@
+#!/bin/sh
+# Ensure that mv works with a few symlink-onto-hard-link cases.
+
+# Copyright (C) 2012-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ mv
+
+touch f || framework_failure_
+ln f h || framework_failure_
+ln -s f s || framework_failure_
+
+# Given two links f and h to some important content, and a symlink s to f,
+# "mv s f" must fail because it might then be hard to find the link, h.
+# "mv s l" may succeed because then, s (now "l") still points to f.
+# Of course, if the symlink were being moved into a different destination
+# directory, things would be very different, and, I suspect, implausible.
+
+echo "mv: 's' and 'f' are the same file" > exp || framework_failure_
+mv s f > out 2> err && fail=1
+compare /dev/null out || fail=1
+compare exp err || fail=1
+
+mv s l > out 2> err || fail=1
+compare /dev/null out || fail=1
+compare /dev/null err || fail=1
+
+Exit $fail
diff --git a/tests/mv/to-symlink.sh b/tests/mv/to-symlink.sh
new file mode 100755
index 0000000..018bfe2
--- /dev/null
+++ b/tests/mv/to-symlink.sh
@@ -0,0 +1,43 @@
+#!/bin/sh
+# Make sure that the copying code used in an inter-partition
+# move unlinks a destination symlink before opening it.
+
+# Copyright (C) 1999-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ mv
+cleanup_() { rm -rf "$other_partition_tmpdir"; }
+. "$abs_srcdir/tests/other-fs-tmpdir"
+
+rem_file="$other_partition_tmpdir/file"
+rem_symlink="$other_partition_tmpdir/symlink"
+file=to-sym
+
+echo local > $file || framework_failure_
+echo remote > $rem_file || framework_failure_
+ln -s $rem_file $rem_symlink || framework_failure_
+
+# This mv command should succeed, unlinking the symlink
+# before copying.
+mv $file $rem_symlink || fail=1
+
+# Make sure $file is gone.
+test -f $file && fail=1
+
+# Make sure $rem_file is unmodified.
+test $(cat $rem_file) = remote || fail=1
+
+Exit $fail
diff --git a/tests/mv/trailing-slash.sh b/tests/mv/trailing-slash.sh
new file mode 100755
index 0000000..3d41085
--- /dev/null
+++ b/tests/mv/trailing-slash.sh
@@ -0,0 +1,65 @@
+#!/bin/sh
+# On some operating systems, e.g. SunOS-4.1.1_U1 on sun3x,
+# rename() doesn't accept trailing slashes.
+# Also, ensure that "mv dir non-exist-dir/" works.
+# Also, ensure that "cp dir non-exist-dir/" works.
+
+# Copyright (C) 2004-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ mv
+
+mkdir foo || framework_failure_
+
+
+mv foo/ bar || fail=1
+
+# mv and cp would misbehave for coreutils versions [5.3.0..5.97], 6.0 and 6.1
+for cmd in mv 'cp -r'; do
+ for opt in '' -T -u; do
+ rm -rf d e || framework_failure_
+ mkdir d || framework_failure_
+
+ $cmd $opt d e/ || fail=1
+ if test "$cmd" = mv; then
+ test -d d && fail=1
+ else
+ test -d d || fail=1
+ fi
+ test -d e || fail=1
+ done
+done
+
+# We would like the erroneous-looking "mv any non-dir/" to fail,
+# but with the current implementation, it depends on how the
+# underlying rename syscall handles the trailing slash.
+# It does fail, as desired, on recent Linux and Solaris systems.
+#touch a a2
+#returns_ 1 mv a a2/ || fail=1
+
+# Test for a cp-specific diagnostic introduced after coreutils-8.7:
+printf '%s\n' \
+ "cp: cannot create regular file 'no-such/': Not a directory" \
+> expected-err
+touch b
+cp b no-such/ 2> err
+
+# Map "No such file..." diagnostic to the expected "Not a directory"
+sed 's/No such file or directory/Not a directory/' err > k && mv k err
+
+compare expected-err err || fail=1
+
+Exit $fail
diff --git a/tests/mv/update.sh b/tests/mv/update.sh
new file mode 100755
index 0000000..ab7309f
--- /dev/null
+++ b/tests/mv/update.sh
@@ -0,0 +1,69 @@
+#!/bin/sh
+# make sure --update works as advertised
+
+# Copyright (C) 2001-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ cp mv
+
+test_reset() {
+ echo old > old || framework_failure_
+ touch -d yesterday old || framework_failure_
+ echo new > new || framework_failure_
+}
+
+test_reset
+for interactive in '' -i; do
+ for cp_or_mv in cp mv; do
+ # This is a no-op, with no prompt.
+ # With coreutils-6.9 and earlier, using --update with -i would
+ # mistakenly elicit a prompt.
+ $cp_or_mv $interactive --update old new < /dev/null > out 2>&1 || fail=1
+ compare /dev/null out || fail=1
+ case "$(cat new)" in new) ;; *) fail=1 ;; esac
+ case "$(cat old)" in old) ;; *) fail=1 ;; esac
+ done
+done
+
+# These should perform the rename / copy
+for update_option in '--update' '--update=older' '--update=all' \
+ '--update=none --update=all'; do
+ test_reset
+ mv $update_option new old || fail=1
+ test -f new && fail=1
+ case "$(cat old)" in new) ;; *) fail=1 ;; esac
+
+ test_reset
+ cp $update_option new old || fail=1
+ case "$(cat old)" in new) ;; *) fail=1 ;; esac
+ case "$(cat new)" in new) ;; *) fail=1 ;; esac
+done
+
+# These should not perform the rename / copy
+for update_option in '--update=none' \
+ '--update=all --update=none'; do
+ test_reset
+ mv $update_option new old || fail=1
+ case "$(cat new)" in new) ;; *) fail=1 ;; esac
+ case "$(cat old)" in old) ;; *) fail=1 ;; esac
+
+ test_reset
+ cp $update_option new old || fail=1
+ case "$(cat new)" in new) ;; *) fail=1 ;; esac
+ case "$(cat old)" in old) ;; *) fail=1 ;; esac
+done
+
+Exit $fail
diff --git a/tests/nice/nice-fail.sh b/tests/nice/nice-fail.sh
new file mode 100755
index 0000000..5ba7f5a
--- /dev/null
+++ b/tests/nice/nice-fail.sh
@@ -0,0 +1,32 @@
+#!/bin/sh
+# Verify that internal failure in nice gives exact status.
+
+# Copyright (C) 2009-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ nice env
+
+
+# These tests verify exact status of internal failure.
+returns_ 125 nice -n 1 || fail=1 # missing command
+returns_ 125 nice --- || fail=1 # unknown option
+returns_ 125 nice -n 1a || fail=1 # invalid adjustment
+returns_ 2 nice sh -c 'exit 2' || fail=1 # exit status propagation
+returns_ 126 env . && { returns_ 126 nice . || fail=1; } # invalid command
+returns_ 127 nice no_such || fail=1 # no such command
+
+Exit $fail
diff --git a/tests/nice/nice.sh b/tests/nice/nice.sh
new file mode 100755
index 0000000..2df94f3
--- /dev/null
+++ b/tests/nice/nice.sh
@@ -0,0 +1,93 @@
+#!/bin/sh
+# Test "nice".
+
+# Copyright (C) 2002-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ nice
+
+tests='
+0 empty 10
+1 -1 1
+2 -12 12
+3 -1:-2 2
+4 -n:1 1
+5 -n:1:-2 2
+6 -n:1:-+12 12
+7 -2:-n:1 1
+8 -2:-n:12 12
+9 -+1 1
+10 -+12 12
+11 -+1:-+12 12
+12 -n:+1 1
+13 --1:-2 2
+14 --1:-2:-13 13
+15 --1:-n:2 2
+16 --1:-n:2:-3 3
+17 --1:-n:2:-13 13
+18 -n:-1:-12 12
+19 --1:-12 12
+NA LAST NA
+'
+set $tests
+
+# Require that this test be run at 'nice' level 0.
+niceness=$(nice)
+if test "$niceness" = 0; then
+ : ok
+else
+ skip_ "this test must be run at nice level 0"
+fi
+
+while :; do
+ test_name=$1
+ args=$2
+ expected_result=$3
+ test $args = empty && args=''
+ test x$args = xLAST && break
+ args=$(echo x$args|tr : ' '|sed 's/^x//')
+ if test "$VERBOSE" = yes; then
+ #echo "testing \$(nice $args nice\) = $expected_result ..."
+ echo "test $test_name... " | tr -d '\n'
+ fi
+ test x$(nice $args nice 2> /dev/null) = x$expected_result \
+ && ok=ok || ok=FAIL fail=1
+ test "$VERBOSE" = yes && echo $ok
+ shift; shift; shift
+done
+
+# Test negative niceness - command must be run whether or not change happens.
+if test x$(nice -n -1 nice 2> /dev/null) = x0 ; then
+ # unprivileged user - warn about failure to change
+ nice -n -1 true 2> err || fail=1
+ compare /dev/null err && fail=1
+ mv err exp || framework_failure_
+ nice --1 true 2> err || fail=1
+ compare exp err || fail=1
+ # Failure to write advisory message is fatal. Buggy through coreutils 8.0.
+ if test -w /dev/full && test -c /dev/full; then
+ returns_ 125 nice -n -1 nice > out 2> /dev/full || fail=1
+ compare /dev/null out || fail=1
+ fi
+else
+ # superuser - change succeeds
+ nice -n -1 nice 2> err || fail=1
+ compare /dev/null err || fail=1
+ test x$(nice -n -1 nice) = x-1 || fail=1
+ test x$(nice --1 nice) = x-1 || fail=1
+fi
+
+Exit $fail
diff --git a/tests/no-perl b/tests/no-perl
new file mode 100644
index 0000000..19cfcfb
--- /dev/null
+++ b/tests/no-perl
@@ -0,0 +1,6 @@
+#!/bin/sh
+# Perl is not available, the test should be considered skipped.
+# FD 9 should have been opened by the test suite harness, pointing
+# to the original stderr (usually, the user's terminal).
+echo "test skipped: no usable version of Perl found" >&9
+exit 77
diff --git a/tests/nproc/nproc-avail.sh b/tests/nproc/nproc-avail.sh
new file mode 100755
index 0000000..271ba6a
--- /dev/null
+++ b/tests/nproc/nproc-avail.sh
@@ -0,0 +1,27 @@
+#!/bin/sh
+# Ensure that "nproc" is less than or equal to "nproc --all".
+
+# Copyright (C) 2009-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ nproc
+
+all=$(nproc --all)
+available=$(OMP_NUM_THREADS= nproc)
+
+test $available -le $all || fail=1
+
+Exit $fail
diff --git a/tests/nproc/nproc-override.sh b/tests/nproc/nproc-override.sh
new file mode 100755
index 0000000..e643bc3
--- /dev/null
+++ b/tests/nproc/nproc-override.sh
@@ -0,0 +1,58 @@
+#!/bin/sh
+# Test the various OpenMP override options
+
+# Copyright (C) 2017-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ nproc
+
+unset OMP_NUM_THREADS
+unset OMP_THREADS_LIMIT
+
+avail=$(nproc) || fail=1
+test $(($avail > 0)) || fail=1
+
+#OMP_THREAD_LIMIT OMP_NUM_THREADS NPROC
+echo "\
+ - - $avail
+ 1 - 1
+ 1 0 1
+ - 0 $avail
+ - 2,2,1 2
+ - 2,ignored 2
+ - 2bad $avail
+ - -2 $avail
+ 1 2,2,1 1
+ 0 2,2,1 2
+ 1bad 2,2,1 2
+ 1bad $(($avail+1)),2,1 $(($avail+1))
+ 1 $(($avail+1)) 1
+ $(($avail+2)) $(($avail+1)) $(($avail+1))
+ $(($avail+1)) $(($avail+2)) $(($avail+1))
+ - $(($avail+1)) $(($avail+1))" |
+
+while read OMP_THREAD_LIMIT OMP_NUM_THREADS NPROC; do
+ test $OMP_THREAD_LIMIT = '-' && unset OMP_THREAD_LIMIT
+ test $OMP_NUM_THREADS = '-' && unset OMP_NUM_THREADS
+ export OMP_THREAD_LIMIT
+ export OMP_NUM_THREADS
+ test $(nproc) = $NPROC ||
+ echo "[$OMP_THREAD_LIMIT] [$OMP_NUM_THREADS]" >> failed
+done
+
+test -e failed && fail=1
+
+Exit $fail
diff --git a/tests/nproc/nproc-positive.sh b/tests/nproc/nproc-positive.sh
new file mode 100755
index 0000000..d4936a1
--- /dev/null
+++ b/tests/nproc/nproc-positive.sh
@@ -0,0 +1,44 @@
+#!/bin/sh
+# Ensure that nproc prints a number > 0
+
+# Copyright (C) 2009-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ nproc
+
+for mode in --all ''; do
+ procs=$(nproc $mode)
+ test "$procs" -gt 0 || fail=1
+done
+
+for i in -1000 0 1 1000; do
+ procs=$(OMP_NUM_THREADS=$i nproc)
+ test "$procs" -gt 0 || fail=1
+done
+
+for i in 0 ' 1' 1000; do
+ procs=$(nproc --ignore="$i")
+ test "$procs" -gt 0 || fail=1
+done
+
+for i in -1 N; do
+ returns_ 1 nproc --ignore=$i || fail=1
+done
+
+procs=$(OMP_NUM_THREADS=42 nproc --ignore=40)
+test "$procs" -eq 2 || fail=1
+
+Exit $fail
diff --git a/tests/od/od-N.sh b/tests/od/od-N.sh
new file mode 100755
index 0000000..9e8c061
--- /dev/null
+++ b/tests/od/od-N.sh
@@ -0,0 +1,32 @@
+#!/bin/sh
+# Verify that 'od -N N' reads no more than N bytes of input.
+
+# Copyright (C) 2001-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ od
+
+echo abcdefg > in || framework_failure_
+
+
+(od -An -N3 -c; od -An -N3 -c) < in > out
+cat <<EOF > exp || framework_failure_
+ a b c
+ d e f
+EOF
+compare exp out || fail=1
+
+Exit $fail
diff --git a/tests/od/od-endian.sh b/tests/od/od-endian.sh
new file mode 100755
index 0000000..6154894
--- /dev/null
+++ b/tests/od/od-endian.sh
@@ -0,0 +1,49 @@
+#!/bin/sh
+# verify that od --endian works properly
+
+# Copyright (C) 2014-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ od
+
+in='0123456789abcdef'
+
+NL='
+'
+
+# rev(1) is not generally available, so here's a simplistic
+# implementation sufficient for our purposes.
+rev() {
+ while read line; do
+ printf '%s' "$line" | sed "s/./&\\$NL/g" | tac | paste -s -d ''
+ done
+}
+
+in_swapped() { printf '%s' "$in" | sed "s/.\{$1\}/&\\$NL/g" | rev |tr -d '\n'; }
+
+for e in little big; do
+ test $e = little && eo=big || eo=little
+ for s in 1 2 4 8 16; do
+ for t in x f; do
+ od -t $t$s --endian=$e /dev/null > /dev/null 2>&1 || continue
+ printf '%s' "$in" | od -An -t $t$s --endian=$e > out1
+ in_swapped "$s" | od -An -t $t$s --endian=$eo > out2
+ compare out1 out2 || fail=1
+ done
+ done
+done
+
+Exit $fail
diff --git a/tests/od/od-float.sh b/tests/od/od-float.sh
new file mode 100755
index 0000000..a651cec
--- /dev/null
+++ b/tests/od/od-float.sh
@@ -0,0 +1,72 @@
+#!/bin/sh
+# Test od on floating-point values.
+
+# Copyright (C) 2010-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ od
+
+export LC_ALL=C
+
+# Test for a bug in coreutils up through 8.7: od was losing
+# information when asked to parse floating-point values. The numeric
+# tests are valid only on Intel-like hosts, but that should be good
+# enough to detect regressions, as they are designed to succeed on
+# non-Intel-like hosts. Also, test for another bug in coreutils 8.7
+# on x86: sometimes there was no space between the columns.
+
+set x $(echo aaaabaaa | tr ab '\376\377' | od -t fF) ||
+ fail=1
+case "$*" in
+*0-*) fail=1;;
+esac
+case $3,$4 in
+-1.694740e+38,-1.694740e+38) fail=1;;
+esac
+
+set x $(echo aaaaaaaabaaaaaaa | tr ab '\376\377' | od -t fD) ||
+ fail=1
+case "$*" in
+*0-*) fail=1;;
+esac
+case $3,$4 in
+-5.314010372517808e+303,-5.314010372517808e+303) fail=1;;
+esac
+
+set x $(echo aaaaaaaaaaaaaaaabaaaaaaaaaaaaaaa | tr ab '\376\377' | od -t fL) ||
+ fail=1
+case "$*" in
+*0-*) fail=1;;
+esac
+case $3,$4 in
+-1.023442870282055988e+4855,-1.023442870282055988e+4855) fail=1;;
+esac
+
+# Ensure od doesn't crash as it did on glibc <= 2.5:
+# https://sourceware.org/bugzilla/show_bug.cgi?id=4586
+set x $(printf 00000000ff000000 | tr 0f '\000\377' | od -t fL) || fail=1
+# With coreutils <= 8.7 we used to print "nan" for the above invalid value.
+# However since v8.7-22-ga71c22f we deferred to the system printf routines
+# through the use of the ftoastr module. So the following check would only
+# be valid on x86_64 if we again handle the conversion internally or
+# if this glibc bug is resolved:
+# https://sourceware.org/bugzilla/show_bug.cgi?id=17661
+#case "$*" in
+#*nan*) ;;
+#*) fail=1;;
+#esac
+
+Exit $fail
diff --git a/tests/od/od-j.sh b/tests/od/od-j.sh
new file mode 100755
index 0000000..1c402cb
--- /dev/null
+++ b/tests/od/od-j.sh
@@ -0,0 +1,39 @@
+#!/bin/sh
+# Verify that 'od -j N' skips N bytes of input.
+
+# Copyright 2014-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ od
+
+for file in ${srcdir=.}/tests/init.sh /proc/version /sys/kernel/profiling; do
+ test -r $file || continue
+
+ cp -f $file copy &&
+ bytes=$(wc -c < copy) || framework_failure_
+
+ od -An $file > exp || fail=1
+ od -An -j $bytes $file $file > out || fail=1
+ compare exp out || fail=1
+
+ od -An -j 4096 copy copy > exp1 2> experr1; expstatus=$?
+ od -An -j 4096 $file $file > out1 2> err1; status=$?
+ test $status -eq $expstatus || fail=1
+ compare exp1 out1 || fail=1
+ compare experr1 err1 || fail=1
+done
+
+Exit $fail
diff --git a/tests/od/od-multiple-t.sh b/tests/od/od-multiple-t.sh
new file mode 100755
index 0000000..729cdb2
--- /dev/null
+++ b/tests/od/od-multiple-t.sh
@@ -0,0 +1,42 @@
+#!/bin/sh
+# verify that multiple -t specifiers to od align well
+# This would fail before coreutils-6.13.
+
+# Copyright (C) 2008-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ od
+
+# Choose 48 bytes for the input, as that is lcm for 1, 2, 4, 8, 12, 16;
+# we don't anticipate any other native object size on modern hardware.
+seq 19 > in || framework_failure_
+test $(wc -c < in) -eq 48 || framework_failure_
+
+
+list='a c dC dS dI dL oC oS oI oL uC uS uI uL xC xS xI xL fF fD fL'
+for format1 in $list; do
+ for format2 in $list; do
+ od -An -t${format1}z -t${format2}z in > out-raw || fail=1
+ linewidth=$(head -n1 out-raw | wc -c)
+ linecount=$(wc -l < out-raw)
+ echo $format1 $format2 $(wc -c < out-raw) >> out
+ echo $format1 $format2 $(expr $linewidth '*' $linecount) >> exp
+ done
+done
+
+compare exp out || fail=1
+
+Exit $fail
diff --git a/tests/od/od-x8.sh b/tests/od/od-x8.sh
new file mode 100755
index 0000000..3b11bf7
--- /dev/null
+++ b/tests/od/od-x8.sh
@@ -0,0 +1,43 @@
+#!/bin/sh
+# verify that od -t x8 works properly
+# This would fail before coreutils-4.5.2.
+
+# Copyright (C) 2002-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ od
+
+od -t x8 /dev/null >/dev/null ||
+ skip_ "od lacks support for 8-byte quantities"
+
+echo abcdefgh |tr -d '\n' > in || framework_failure_
+
+
+od -An -t x8 in > out-raw || fail=1
+sed 's/^ //;s/\(..\)/\1 /g;s/ $//' out-raw \
+ | tr ' ' '\n' \
+ | sort -n \
+ > out
+
+od -An -t x1 in \
+ | sed 's/^ //' \
+ | tr ' ' '\n' \
+ | sort -n \
+ > exp
+
+compare exp out || fail=1
+
+Exit $fail
diff --git a/tests/od/od.pl b/tests/od/od.pl
new file mode 100755
index 0000000..7936ddb
--- /dev/null
+++ b/tests/od/od.pl
@@ -0,0 +1,74 @@
+#!/usr/bin/perl
+# Exercise od
+
+# Copyright (C) 2006-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+use strict;
+
+(my $program_name = $0) =~ s|.*/||;
+
+# Turn off localization of executable's output.
+@ENV{qw(LANGUAGE LANG LC_ALL)} = ('C') x 3;
+
+# Use a file in /proc whose size is not likely to
+# change between the wc and od invocations.
+my $proc_file = '/proc/version';
+-f $proc_file
+ or $proc_file = '/dev/null';
+
+# Count the bytes in $proc_file, _by reading_.
+my $len = 0;
+open FH, '<', $proc_file
+ or die "$program_name: can't open '$proc_file' for reading: $!\n";
+while (defined (my $line = <FH>))
+ {
+ $len += length $line;
+ }
+close FH;
+my $proc_file_byte_count = $len;
+
+my @Tests =
+ (
+ # Skip the exact length of the input file.
+ # Up to coreutils-6.9, this would ignore the "-j 1".
+ ['j-bug1', '-c -j 1 -An', {IN=>{g=>'a'}}, {OUT=>''}],
+ ['j-bug2', '-c -j 2 -An', {IN=>{g=>'a'}}, {IN=>{h=>'b'}}, {OUT=>''}],
+ # Skip the sum of the lengths of the first three inputs.
+ ['j-bug3', '-c -j 3 -An', {IN=>{g=>'a'}}, {IN=>{h=>'b'}},
+ {IN=>{i=>'c'}}, {OUT=>''}],
+ # Skip the sum of the lengths of the first three inputs, printing the 4th.
+ ['j-bug4', '-c -j 3 -An', {IN=>{g=>'a'}}, {IN=>{h=>'b'}},
+ {IN=>{i=>'c'}}, {IN=>{j=>'d'}}, {OUT=>" d\n"}],
+
+ # Ensure that od -j doesn't fseek across a nonempty file in /proc,
+ # even if the kernel reports that the file has stat.st_size = 0.
+ ['j-proc', "-An -c -j $proc_file_byte_count $proc_file",
+ {IN=>{f2=>'e'}}, {OUT=>" e\n"}],
+
+ # Ensure that a large width does not cause trouble.
+ # From coreutils-7.0 through coreutils-8.21, these would print
+ # approximately 128KiB of padding.
+ ['wide-a', '-a -w65537 -An', {IN=>{g=>'x'}}, {OUT=>" x\n"}],
+ ['wide-c', '-c -w65537 -An', {IN=>{g=>'x'}}, {OUT=>" x\n"}],
+ ['wide-x', '-tx1 -w65537 -An', {IN=>{g=>'B'}}, {OUT=>" 42\n"}],
+ );
+
+my $save_temps = $ENV{DEBUG};
+my $verbose = $ENV{VERBOSE};
+
+my $prog = 'od';
+my $fail = run_tests ($program_name, $prog, \@Tests, $save_temps, $verbose);
+exit $fail;
diff --git a/tests/other-fs-tmpdir b/tests/other-fs-tmpdir
new file mode 100644
index 0000000..b4d270e
--- /dev/null
+++ b/tests/other-fs-tmpdir
@@ -0,0 +1,55 @@
+#!/bin/sh
+
+# Use stat to find a writable directory on a file system different from that
+# of the current directory. If one is found, create a temporary directory
+# inside it.
+
+# Copyright (C) 1998-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+test "${CANDIDATE_TMP_DIRS+set}" = set \
+ || CANDIDATE_TMP_DIRS="$TMPDIR /tmp /dev/shm /var/tmp /usr/tmp $HOME"
+
+other_partition_tmpdir=
+
+dot_mount_point=$(stat -c %d .)
+for d in $CANDIDATE_TMP_DIRS; do
+
+ # Skip nonexistent directories.
+ test -d "$d" || continue
+
+ d_mount_point=$(stat -L -c %d "$d")
+
+ # Same partition? Skip it.
+ test "x$d_mount_point" = "x$dot_mount_point" && continue
+
+ # See if we can create a directory in it.
+ if mkdir "$d/tmp$$" > /dev/null 2>&1; then
+ other_partition_tmpdir="$d/tmp$$"
+ break
+ fi
+
+done
+
+if test -z "$other_partition_tmpdir"; then
+ skip_ \
+"requires a writable directory on a different file system,
+and I couldn't find one. I tried these:
+ $CANDIDATE_TMP_DIRS
+Set your environment variable CANDIDATE_TMP_DIRS to make
+this test use a different list."
+fi
+
+test "$VERBOSE" = yes && set -x
diff --git a/tests/pr/0F b/tests/pr/0F
new file mode 100644
index 0000000..680117c
--- /dev/null
+++ b/tests/pr/0F
@@ -0,0 +1,330 @@
+
+
+-- Date/Time -- x Page 1
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+-- Date/Time -- x Page 2
+
+
+1 FF-Test: FF's at Start of File V
+2 Options -b -3 / -a -3 / ...
+3 --------------------------------------------
+4 3456789 123456789 123456789 123456789 12345678
+5 3 Columns downwards ..., <= 5 lines per page
+6 FF-Arangements: Empty Pages at start
+7 \ftext; \f\ntext;
+8 \f\ftext; \f\f\ntext; \f\n\ftext; \f\n\f\n;
+9 3456789 123456789 123456789
+10 zzzzzzzzzzzzzzzzzzzzzzzzzz123456789
+1 12345678
+2 12345678
+3 line truncation before FF; r_r_o_l-test:
+14 456789 123456789 123456789 123456789
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+-- Date/Time -- x Page 3
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+-- Date/Time -- x Page 4
+
+
+15 xyzxyzxyz XYZXYZXYZ abcabcab
+16 456789 123456789 xyzxyzxyz XYZXYZXYZ
+7 12345678
+8 12345678
+9 3456789 ab
+20 DEFGHI 123
+1 12345678
+2 12345678
+3 12345678
+4 12345678
+5 12345678
+6 12345678
+27 no truncation before FF; (r_l-test):
+28 no trunc
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+-- Date/Time -- x Page 5
+
+
+29 xyzxyzxyz XYZXYZXYZ abcabcab
+30 456789 123456789 xyzxyzxyz XYZXYZXYZ
+1 12345678
+2 3456789 abcdefghi
+3 12345678
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/tests/pr/0FF b/tests/pr/0FF
new file mode 100644
index 0000000..934512b
--- /dev/null
+++ b/tests/pr/0FF
@@ -0,0 +1,396 @@
+
+
+-- Date/Time -- x Page 1
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+-- Date/Time -- x Page 2
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+-- Date/Time -- x Page 3
+
+
+1 FF-Test: FF's at Start of File V
+2 Options -b -3 / -a -3 / ...
+3 --------------------------------------------
+4 3456789 123456789 123456789 123456789 12345678
+5 3 Columns downwards ..., <= 5 lines per page
+6 FF-Arangements: Empty Pages at start
+7 \ftext; \f\ntext;
+8 \f\ftext; \f\f\ntext; \f\n\ftext; \f\n\f\n;
+9 3456789 123456789 123456789
+10 zzzzzzzzzzzzzzzzzzzzzzzzzz123456789
+1 12345678
+2 12345678
+3 line truncation before FF; r_r_o_l-test:
+14 456789 123456789 123456789 123456789
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+-- Date/Time -- x Page 4
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+-- Date/Time -- x Page 5
+
+
+15 xyzxyzxyz XYZXYZXYZ abcabcab
+16 456789 123456789 xyzxyzxyz XYZXYZXYZ
+7 12345678
+8 12345678
+9 3456789 ab
+20 DEFGHI 123
+1 12345678
+2 12345678
+3 12345678
+4 12345678
+5 12345678
+6 12345678
+27 no truncation before FF; (r_l-test):
+28 no trunc
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+-- Date/Time -- x Page 6
+
+
+29 xyzxyzxyz XYZXYZXYZ abcabcab
+30 456789 123456789 xyzxyzxyz XYZXYZXYZ
+1 12345678
+2 3456789 abcdefghi
+3 12345678
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/tests/pr/0FFnt b/tests/pr/0FFnt
new file mode 100644
index 0000000..19ecc4f
--- /dev/null
+++ b/tests/pr/0FFnt
@@ -0,0 +1,36 @@
+
+1 FF-Test: FF's at Start of File V
+2 Options -b -3 / -a -3 / ...
+3 --------------------------------------------
+4 3456789 123456789 123456789 123456789 12345678
+5 3 Columns downwards ..., <= 5 lines per page
+6 FF-Arangements: Empty Pages at start
+7 \ftext; \f\ntext;
+8 \f\ftext; \f\f\ntext; \f\n\ftext; \f\n\f\n;
+9 3456789 123456789 123456789
+10 zzzzzzzzzzzzzzzzzzzzzzzzzz123456789
+1 12345678
+2 12345678
+3 line truncation before FF; r_r_o_l-test:
+14 456789 123456789 123456789 123456789
+
+15 xyzxyzxyz XYZXYZXYZ abcabcab
+16 456789 123456789 xyzxyzxyz XYZXYZXYZ
+7 12345678
+8 12345678
+9 3456789 ab
+20 DEFGHI 123
+1 12345678
+2 12345678
+3 12345678
+4 12345678
+5 12345678
+6 12345678
+27 no truncation before FF; (r_l-test):
+28 no trunc
+
+29 xyzxyzxyz XYZXYZXYZ abcabcab
+30 456789 123456789 xyzxyzxyz XYZXYZXYZ
+1 12345678
+2 3456789 abcdefghi
+3 12345678
diff --git a/tests/pr/0FFt b/tests/pr/0FFt
new file mode 100644
index 0000000..38e91e2
--- /dev/null
+++ b/tests/pr/0FFt
@@ -0,0 +1,35 @@
+ 1 FF-Test: FF's at Start of File V
+2 Options -b -3 / -a -3 / ...
+3 --------------------------------------------
+4 3456789 123456789 123456789 123456789 12345678
+5 3 Columns downwards ..., <= 5 lines per page
+6 FF-Arangements: Empty Pages at start
+7 \ftext; \f\ntext;
+8 \f\ftext; \f\f\ntext; \f\n\ftext; \f\n\f\n;
+9 3456789 123456789 123456789
+10 zzzzzzzzzzzzzzzzzzzzzzzzzz123456789
+1 12345678
+2 12345678
+3 line truncation before FF; r_r_o_l-test:
+14 456789 123456789 123456789 123456789
+
+15 xyzxyzxyz XYZXYZXYZ abcabcab
+16 456789 123456789 xyzxyzxyz XYZXYZXYZ
+7 12345678
+8 12345678
+9 3456789 ab
+20 DEFGHI 123
+1 12345678
+2 12345678
+3 12345678
+4 12345678
+5 12345678
+6 12345678
+27 no truncation before FF; (r_l-test):
+28 no trunc
+
+29 xyzxyzxyz XYZXYZXYZ abcabcab
+30 456789 123456789 xyzxyzxyz XYZXYZXYZ
+1 12345678
+2 3456789 abcdefghi
+3 12345678
diff --git a/tests/pr/0FnFnt b/tests/pr/0FnFnt
new file mode 100644
index 0000000..364bd94
--- /dev/null
+++ b/tests/pr/0FnFnt
@@ -0,0 +1,37 @@
+
+
+1 FF-Test: FF's at Start of File V
+2 Options -b -3 / -a -3 / ...
+3 --------------------------------------------
+4 3456789 123456789 123456789 123456789 12345678
+5 3 Columns downwards ..., <= 5 lines per page
+6 FF-Arangements: Empty Pages at start
+7 \ftext; \f\ntext;
+8 \f\ftext; \f\f\ntext; \f\n\ftext; \f\n\f\n;
+9 3456789 123456789 123456789
+10 zzzzzzzzzzzzzzzzzzzzzzzzzz123456789
+1 12345678
+2 12345678
+3 line truncation before FF; r_r_o_l-test:
+14 456789 123456789 123456789 123456789
+
+15 xyzxyzxyz XYZXYZXYZ abcabcab
+16 456789 123456789 xyzxyzxyz XYZXYZXYZ
+7 12345678
+8 12345678
+9 3456789 ab
+20 DEFGHI 123
+1 12345678
+2 12345678
+3 12345678
+4 12345678
+5 12345678
+6 12345678
+27 no truncation before FF; (r_l-test):
+28 no trunc
+
+29 xyzxyzxyz XYZXYZXYZ abcabcab
+30 456789 123456789 xyzxyzxyz XYZXYZXYZ
+1 12345678
+2 3456789 abcdefghi
+3 12345678
diff --git a/tests/pr/0FnFt b/tests/pr/0FnFt
new file mode 100644
index 0000000..eb01651
--- /dev/null
+++ b/tests/pr/0FnFt
@@ -0,0 +1,36 @@
+
+ 1 FF-Test: FF's at Start of File V
+2 Options -b -3 / -a -3 / ...
+3 --------------------------------------------
+4 3456789 123456789 123456789 123456789 12345678
+5 3 Columns downwards ..., <= 5 lines per page
+6 FF-Arangements: Empty Pages at start
+7 \ftext; \f\ntext;
+8 \f\ftext; \f\f\ntext; \f\n\ftext; \f\n\f\n;
+9 3456789 123456789 123456789
+10 zzzzzzzzzzzzzzzzzzzzzzzzzz123456789
+1 12345678
+2 12345678
+3 line truncation before FF; r_r_o_l-test:
+14 456789 123456789 123456789 123456789
+
+15 xyzxyzxyz XYZXYZXYZ abcabcab
+16 456789 123456789 xyzxyzxyz XYZXYZXYZ
+7 12345678
+8 12345678
+9 3456789 ab
+20 DEFGHI 123
+1 12345678
+2 12345678
+3 12345678
+4 12345678
+5 12345678
+6 12345678
+27 no truncation before FF; (r_l-test):
+28 no trunc
+
+29 xyzxyzxyz XYZXYZXYZ abcabcab
+30 456789 123456789 xyzxyzxyz XYZXYZXYZ
+1 12345678
+2 3456789 abcdefghi
+3 12345678
diff --git a/tests/pr/0Fnt b/tests/pr/0Fnt
new file mode 100644
index 0000000..9ba3a90
--- /dev/null
+++ b/tests/pr/0Fnt
@@ -0,0 +1,36 @@
+
+1 FF-Test: FF's at Start of File V
+2 Options -b -3 / -a -3 / ...
+3 --------------------------------------------
+4 3456789 123456789 123456789 123456789 12345678
+5 3 Columns downwards ..., <= 5 lines per page
+6 FF-Arangements: Empty Pages at start
+7 \ftext; \f\ntext;
+8 \f\ftext; \f\f\ntext; \f\n\ftext; \f\n\f\n;
+9 3456789 123456789 123456789
+10 zzzzzzzzzzzzzzzzzzzzzzzzzz123456789
+1 12345678
+2 12345678
+3 line truncation before FF; r_r_o_l-test:
+14 456789 123456789 123456789 123456789
+
+15 xyzxyzxyz XYZXYZXYZ abcabcab
+16 456789 123456789 xyzxyzxyz XYZXYZXYZ
+7 12345678
+8 12345678
+9 3456789 ab
+20 DEFGHI 123
+1 12345678
+2 12345678
+3 12345678
+4 12345678
+5 12345678
+6 12345678
+27 no truncation before FF; (r_l-test):
+28 no trunc
+
+29 xyzxyzxyz XYZXYZXYZ abcabcab
+30 456789 123456789 xyzxyzxyz XYZXYZXYZ
+1 12345678
+2 3456789 abcdefghi
+3 12345678
diff --git a/tests/pr/0Ft b/tests/pr/0Ft
new file mode 100644
index 0000000..bdd599d
--- /dev/null
+++ b/tests/pr/0Ft
@@ -0,0 +1,35 @@
+ 1 FF-Test: FF's at Start of File V
+2 Options -b -3 / -a -3 / ...
+3 --------------------------------------------
+4 3456789 123456789 123456789 123456789 12345678
+5 3 Columns downwards ..., <= 5 lines per page
+6 FF-Arangements: Empty Pages at start
+7 \ftext; \f\ntext;
+8 \f\ftext; \f\f\ntext; \f\n\ftext; \f\n\f\n;
+9 3456789 123456789 123456789
+10 zzzzzzzzzzzzzzzzzzzzzzzzzz123456789
+1 12345678
+2 12345678
+3 line truncation before FF; r_r_o_l-test:
+14 456789 123456789 123456789 123456789
+
+15 xyzxyzxyz XYZXYZXYZ abcabcab
+16 456789 123456789 xyzxyzxyz XYZXYZXYZ
+7 12345678
+8 12345678
+9 3456789 ab
+20 DEFGHI 123
+1 12345678
+2 12345678
+3 12345678
+4 12345678
+5 12345678
+6 12345678
+27 no truncation before FF; (r_l-test):
+28 no trunc
+
+29 xyzxyzxyz XYZXYZXYZ abcabcab
+30 456789 123456789 xyzxyzxyz XYZXYZXYZ
+1 12345678
+2 3456789 abcdefghi
+3 12345678
diff --git a/tests/pr/2-S_f-t_notab b/tests/pr/2-S_f-t_notab
new file mode 100644
index 0000000..63db297
--- /dev/null
+++ b/tests/pr/2-S_f-t_notab
@@ -0,0 +1,9 @@
+
+
+-- Date/Time -- x Page 1
+
+
+aaaa.bcde-fghijklmn-opqrstuvw-xyzzz:dddd.bcde-fghijklmn-opqrstuvw-xyzzz
+bbbb.bcde-fghijklmn-opqrstuvw-xyzzz:eeee.bcde-fghijklmn-opqrstuvw-xyzzz
+cccc.bcde-fghijklmn-opqrstuvw-xyzzz
+ \ No newline at end of file
diff --git a/tests/pr/2-Sf-t_notab b/tests/pr/2-Sf-t_notab
new file mode 100644
index 0000000..e1ded49
--- /dev/null
+++ b/tests/pr/2-Sf-t_notab
@@ -0,0 +1,9 @@
+
+
+-- Date/Time -- x Page 1
+
+
+aaaa.bcde-fghijklmn-opqrstuvw-xyzzzzdddd.bcde-fghijklmn-opqrstuvw-xyzzzz
+bbbb.bcde-fghijklmn-opqrstuvw-xyzzzzeeee.bcde-fghijklmn-opqrstuvw-xyzzzz
+cccc.bcde-fghijklmn-opqrstuvw-xyzzzz
+ \ No newline at end of file
diff --git a/tests/pr/2f-t_notab b/tests/pr/2f-t_notab
new file mode 100644
index 0000000..aa41590
--- /dev/null
+++ b/tests/pr/2f-t_notab
@@ -0,0 +1,9 @@
+
+
+-- Date/Time -- x Page 1
+
+
+aaaa.bcde-fghijklmn-opqrstuvw-xyzzz dddd.bcde-fghijklmn-opqrstuvw-xyzzz
+bbbb.bcde-fghijklmn-opqrstuvw-xyzzz eeee.bcde-fghijklmn-opqrstuvw-xyzzz
+cccc.bcde-fghijklmn-opqrstuvw-xyzzz
+ \ No newline at end of file
diff --git a/tests/pr/2s_f-t_notab b/tests/pr/2s_f-t_notab
new file mode 100644
index 0000000..6ff05f9
--- /dev/null
+++ b/tests/pr/2s_f-t_notab
@@ -0,0 +1,9 @@
+
+
+-- Date/Time -- x Page 1
+
+
+aaaa.bcde-fghijklmn-opqrstuvw-xyzzzzzzz-aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa:dddd.bcde-fghijklmn-opqrstuvw-xyzzzzzzz-dddddddddddddddddddddddddddddddddddddddd
+bbbb.bcde-fghijklmn-opqrstuvw-xyzzzzzzz-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb:eeee.bcde-fghijklmn-opqrstuvw-xyzzzzzzz-eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee
+cccc.bcde-fghijklmn-opqrstuvw-xyzzzzzzz-cccccccccccccccccccccccccccccccccccccccc
+ \ No newline at end of file
diff --git a/tests/pr/2s_w60f-t_nota b/tests/pr/2s_w60f-t_nota
new file mode 100644
index 0000000..658df5f
--- /dev/null
+++ b/tests/pr/2s_w60f-t_nota
@@ -0,0 +1,9 @@
+
+
+-- Date/Time -- x Page 1
+
+
+aaaa.bcde-fghijklmn-opqrstuvw:dddd.bcde-fghijklmn-opqrstuvw
+bbbb.bcde-fghijklmn-opqrstuvw:eeee.bcde-fghijklmn-opqrstuvw
+cccc.bcde-fghijklmn-opqrstuvw
+ \ No newline at end of file
diff --git a/tests/pr/2sf-t_notab b/tests/pr/2sf-t_notab
new file mode 100644
index 0000000..dcfe5b1
--- /dev/null
+++ b/tests/pr/2sf-t_notab
@@ -0,0 +1,9 @@
+
+
+-- Date/Time -- x Page 1
+
+
+aaaa.bcde-fghijklmn-opqrstuvw-xyzzzzzzz-aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa dddd.bcde-fghijklmn-opqrstuvw-xyzzzzzzz-dddddddddddddddddddddddddddddddddddddddd
+bbbb.bcde-fghijklmn-opqrstuvw-xyzzzzzzz-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb eeee.bcde-fghijklmn-opqrstuvw-xyzzzzzzz-eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee
+cccc.bcde-fghijklmn-opqrstuvw-xyzzzzzzz-cccccccccccccccccccccccccccccccccccccccc
+ \ No newline at end of file
diff --git a/tests/pr/2sw60f-t_notab b/tests/pr/2sw60f-t_notab
new file mode 100644
index 0000000..3215794
--- /dev/null
+++ b/tests/pr/2sw60f-t_notab
@@ -0,0 +1,9 @@
+
+
+-- Date/Time -- x Page 1
+
+
+aaaa.bcde-fghijklmn-opqrstuvw-dddd.bcde-fghijklmn-opqrstuvw-
+bbbb.bcde-fghijklmn-opqrstuvw-eeee.bcde-fghijklmn-opqrstuvw-
+cccc.bcde-fghijklmn-opqrstuvw-
+ \ No newline at end of file
diff --git a/tests/pr/2w60f-t_notab b/tests/pr/2w60f-t_notab
new file mode 100644
index 0000000..b0ca20c
--- /dev/null
+++ b/tests/pr/2w60f-t_notab
@@ -0,0 +1,9 @@
+
+
+-- Date/Time -- x Page 1
+
+
+aaaa.bcde-fghijklmn-opqrstuvw dddd.bcde-fghijklmn-opqrstuvw
+bbbb.bcde-fghijklmn-opqrstuvw eeee.bcde-fghijklmn-opqrstuvw
+cccc.bcde-fghijklmn-opqrstuvw
+ \ No newline at end of file
diff --git a/tests/pr/3-0F b/tests/pr/3-0F
new file mode 100644
index 0000000..eff257a
--- /dev/null
+++ b/tests/pr/3-0F
@@ -0,0 +1,198 @@
+
+
+-- Date/Time -- x Page 3
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+-- Date/Time -- x Page 4
+
+
+15 xyzxyzxyz XYZXYZXYZ abcabcab
+16 456789 123456789 xyzxyzxyz XYZXYZXYZ
+7 12345678
+8 12345678
+9 3456789 ab
+20 DEFGHI 123
+1 12345678
+2 12345678
+3 12345678
+4 12345678
+5 12345678
+6 12345678
+27 no truncation before FF; (r_l-test):
+28 no trunc
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+-- Date/Time -- x Page 5
+
+
+29 xyzxyzxyz XYZXYZXYZ abcabcab
+30 456789 123456789 xyzxyzxyz XYZXYZXYZ
+1 12345678
+2 3456789 abcdefghi
+3 12345678
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/tests/pr/3-5l24f-t b/tests/pr/3-5l24f-t
new file mode 100644
index 0000000..6f35bd2
--- /dev/null
+++ b/tests/pr/3-5l24f-t
@@ -0,0 +1,51 @@
+
+
+-- Date/Time -- x Page 3
+
+
+29 xyzxyzxyz XYZXYZXYZ abcabcab
+30 456789 123456789 xyzxyzxyz XYZXYZXYZ
+1 12345678
+2 3456789 abcdefghi
+3 12345678
+4 12345678
+5 12345678
+6 12345678
+7 12345678
+8 12345678
+9 3456789 abcdefghi
+40 DEFGHI 123456789
+41 yzxyzxyz XYZXYZXYZ abcabcab
+42 456789 123456789 abcdefghi ABCDEDFHI
+
+
+-- Date/Time -- x Page 4
+
+
+43 xyzxyzxyz XYZXYZXYZ abcabcab
+44 456789 123456789 xyzxyzxyz XYZXYZXYZ
+5 12345678
+6 12345678
+7 12345678
+8 12345678
+9 12345678
+50 12345678
+1 12345678
+2 12345678
+3 12345678
+4 12345678
+55 yzxyzxyz XYZXYZXYZ abcabcab
+56 456789 123456789 abcdefghi ABCDEDFHI
+
+
+-- Date/Time -- x Page 5
+
+
+57 xyzxyzxyz XYZXYZXYZ abcabcab
+58 456789 123456789 xyzxyzxyz XYZXYZXYZ
+9 12345678
+60 DEFGHI 123456789
+1
+2
+3 ------- EOF -------- EOF -------- EOF -------
+ \ No newline at end of file
diff --git a/tests/pr/3-FF b/tests/pr/3-FF
new file mode 100644
index 0000000..b7afab0
--- /dev/null
+++ b/tests/pr/3-FF
@@ -0,0 +1,462 @@
+
+
+-- Date/Time -- x Page 3
+
+
+15 xyzxyzxyz XYZXYZXYZ abcabcab
+16 456789 123456789 xyzxyzxyz XYZXYZXYZ
+7 12345678
+8 12345678
+9 3456789 ab
+20 DEFGHI 123
+1 12345678
+2 12345678
+3 12345678
+4 12345678
+5 12345678
+6 12345678
+27 no truncation before FF; (r_l-test):
+28 no trunc
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+-- Date/Time -- x Page 4
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+-- Date/Time -- x Page 5
+
+
+29 xyzxyzxyz XYZXYZXYZ abcabcab
+30 456789 123456789 xyzxyzxyz XYZXYZXYZ
+1 12345678
+2 3456789 abcdefghi
+3 12345678
+4 12345678
+5 12345678
+6 12345678
+7 12345678
+8 12345678
+9 3456789 abcdefghi
+40 DEFGHI 123456789
+41 yzxyzxyz XYZXYZXYZ abcabcab
+42 456789 123456789 abcdefghi ABCDEDFHI
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+-- Date/Time -- x Page 6
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+-- Date/Time -- x Page 7
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+-- Date/Time -- x Page 8
+
+
+43 xyzxyzxyz XYZXYZXYZ abcabcab
+44 456789 123456789 xyzxyzxyz XYZXYZXYZ
+5 12345678
+6 12345678
+7 12345678
+8 12345678
+9 12345678
+50 12345678
+1 12345678
+2 12345678
+3 12345678
+4 12345678
+55 yzxyzxyz XYZXYZXYZ abcabcab
+56 456789 123456789 abcdefghi ABCDEDFHI
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+-- Date/Time -- x Page 9
+
+
+57 xyzxyzxyz XYZXYZXYZ abcabcab
+58 456789 123456789 xyzxyzxyz XYZXYZXYZ
+9 12345678
+60 DEFGHI 123456789
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/tests/pr/3a2l17-FF b/tests/pr/3a2l17-FF
new file mode 100644
index 0000000..b019823
--- /dev/null
+++ b/tests/pr/3a2l17-FF
@@ -0,0 +1,119 @@
+
+
+-- Date/Time -- x Page 3
+
+
+15 xyzxyzxyz XYZXYZXYZ abcabcab 16 456789 123456789 xyzxyzxyz XYZXY
+7 8
+9 3456789 ab 20 DEFGHI 123
+1 2
+3 4
+5 6
+27 no truncation before FF; (r_l-te 28 no trunc
+
+
+
+
+
+
+
+-- Date/Time -- x Page 4
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+-- Date/Time -- x Page 5
+
+
+29 xyzxyzxyz XYZXYZXYZ abcabcab 30 456789 123456789 xyzxyzxyz XYZXY
+1 2 3456789 abcdefghi
+3 4
+5 6
+7 8
+9 3456789 abcdefghi 40 DEFGHI 123456789
+41 yzxyzxyz XYZXYZXYZ abcabcab 42 456789 123456789 abcdefghi ABCDE
+
+
+
+
+
+
+
+-- Date/Time -- x Page 6
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+-- Date/Time -- x Page 7
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+-- Date/Time -- x Page 8
+
+
+43 xyzxyzxyz XYZXYZXYZ abcabcab 44 456789 123456789 xyzxyzxyz XYZXY
+5 6
+7 8
+9 50
+1 2
+3 4
+55 yzxyzxyz XYZXYZXYZ abcabcab 56 456789 123456789 abcdefghi ABCDE
+
+
+
+
+
+
+
+-- Date/Time -- x Page 9
+
+
+57 xyzxyzxyz XYZXYZXYZ abcabcab 58 456789 123456789 xyzxyzxyz XYZXY
+9 60 DEFGHI 123456789
+
+
+
+
+
+
+
+
+
+
diff --git a/tests/pr/3a3f-0F b/tests/pr/3a3f-0F
new file mode 100644
index 0000000..f8ff094
--- /dev/null
+++ b/tests/pr/3a3f-0F
@@ -0,0 +1,24 @@
+
+
+-- Date/Time -- x Page 3
+
+
+
+
+
+-- Date/Time -- x Page 4
+
+
+15 xyzxyzxyz XYZXYZXYZ 16 456789 123456789 xyz 7
+8 9 3456789 ab 20 DEFGHI 123
+1 2 3
+4 5 6
+27 no truncation before 28 no trunc
+
+
+-- Date/Time -- x Page 5
+
+
+29 xyzxyzxyz XYZXYZXYZ 30 456789 123456789 xyz 1
+2 3456789 abcdefghi 3
+ \ No newline at end of file
diff --git a/tests/pr/3a3l15-t b/tests/pr/3a3l15-t
new file mode 100644
index 0000000..9d555f1
--- /dev/null
+++ b/tests/pr/3a3l15-t
@@ -0,0 +1,45 @@
+
+
+-- Date/Time -- x Page 3
+
+
+1 2 3456789 abcdefghi 3
+4 5 6
+7 8 9 3456789 abcdefghi
+40 DEFGHI 123456789 41 yzxyzxyz XYZXYZXYZ a 42 456789 123456789 abc
+43 xyzxyzxyz XYZXYZXYZ 44 456789 123456789 xyz 5
+
+
+
+
+
+
+
+-- Date/Time -- x Page 4
+
+
+6 7 8
+9 50 1
+2 3 4
+55 yzxyzxyz XYZXYZXYZ a 56 456789 123456789 abc 57 xyzxyzxyz XYZXYZXYZ
+58 456789 123456789 xyz 9 60 DEFGHI 123456789
+
+
+
+
+
+
+
+-- Date/Time -- x Page 5
+
+
+1 2 3 ------- EOF --------
+
+
+
+
+
+
+
+
+
diff --git a/tests/pr/3a3l15f-t b/tests/pr/3a3l15f-t
new file mode 100644
index 0000000..99f5a6b
--- /dev/null
+++ b/tests/pr/3a3l15f-t
@@ -0,0 +1,27 @@
+
+
+-- Date/Time -- x Page 3
+
+
+1 2 3456789 abcdefghi 3
+4 5 6
+7 8 9 3456789 abcdefghi
+40 DEFGHI 123456789 41 yzxyzxyz XYZXYZXYZ a 42 456789 123456789 abc
+43 xyzxyzxyz XYZXYZXYZ 44 456789 123456789 xyz 5
+
+
+-- Date/Time -- x Page 4
+
+
+6 7 8
+9 50 1
+2 3 4
+55 yzxyzxyz XYZXYZXYZ a 56 456789 123456789 abc 57 xyzxyzxyz XYZXYZXYZ
+58 456789 123456789 xyz 9 60 DEFGHI 123456789
+
+
+-- Date/Time -- x Page 5
+
+
+1 2 3 ------- EOF --------
+ \ No newline at end of file
diff --git a/tests/pr/3b2l17-FF b/tests/pr/3b2l17-FF
new file mode 100644
index 0000000..0ec3097
--- /dev/null
+++ b/tests/pr/3b2l17-FF
@@ -0,0 +1,119 @@
+
+
+-- Date/Time -- x Page 3
+
+
+15 xyzxyzxyz XYZXYZXYZ abcabcab 2
+16 456789 123456789 xyzxyzxyz XYZXY 3
+7 4
+8 5
+9 3456789 ab 6
+20 DEFGHI 123 27 no truncation before FF; (r_l-te
+1 28 no trunc
+
+
+
+
+
+
+
+-- Date/Time -- x Page 4
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+-- Date/Time -- x Page 5
+
+
+29 xyzxyzxyz XYZXYZXYZ abcabcab 6
+30 456789 123456789 xyzxyzxyz XYZXY 7
+1 8
+2 3456789 abcdefghi 9 3456789 abcdefghi
+3 40 DEFGHI 123456789
+4 41 yzxyzxyz XYZXYZXYZ abcabcab
+5 42 456789 123456789 abcdefghi ABCDE
+
+
+
+
+
+
+
+-- Date/Time -- x Page 6
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+-- Date/Time -- x Page 7
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+-- Date/Time -- x Page 8
+
+
+43 xyzxyzxyz XYZXYZXYZ abcabcab 50
+44 456789 123456789 xyzxyzxyz XYZXY 1
+5 2
+6 3
+7 4
+8 55 yzxyzxyz XYZXYZXYZ abcabcab
+9 56 456789 123456789 abcdefghi ABCDE
+
+
+
+
+
+
+
+-- Date/Time -- x Page 9
+
+
+57 xyzxyzxyz XYZXYZXYZ abcabcab 9
+58 456789 123456789 xyzxyzxyz XYZXY 60 DEFGHI 123456789
+
+
+
+
+
+
+
+
+
+
diff --git a/tests/pr/3b3f-0F b/tests/pr/3b3f-0F
new file mode 100644
index 0000000..58aff18
--- /dev/null
+++ b/tests/pr/3b3f-0F
@@ -0,0 +1,24 @@
+
+
+-- Date/Time -- x Page 3
+
+
+
+
+
+-- Date/Time -- x Page 4
+
+
+15 xyzxyzxyz XYZXYZXYZ 20 DEFGHI 123 5
+16 456789 123456789 xyz 1 6
+7 2 27 no truncation before
+8 3 28 no trunc
+9 3456789 ab 4
+
+
+-- Date/Time -- x Page 5
+
+
+29 xyzxyzxyz XYZXYZXYZ 1 3
+30 456789 123456789 xyz 2 3456789 abcdefghi
+ \ No newline at end of file
diff --git a/tests/pr/3b3f-0FF b/tests/pr/3b3f-0FF
new file mode 100644
index 0000000..463d8bb
--- /dev/null
+++ b/tests/pr/3b3f-0FF
@@ -0,0 +1,34 @@
+
+
+-- Date/Time -- x Page 3
+
+
+1 FF-Test: FF's at St 6 FF-Arangements: Emp 1
+2 Options -b -3 / -a 7 \ftext; \f\ntext; 2
+3 ------------------- 8 \f\ftext; \f\f\ntex 3 line truncation befor
+4 3456789 123456789 123 9 3456789 123456789 123 14 456789 123456789 123
+5 3 Columns downwards 10 zzzzzzzzzzzzzzzzzzz
+
+
+-- Date/Time -- x Page 4
+
+
+
+
+
+-- Date/Time -- x Page 5
+
+
+15 xyzxyzxyz XYZXYZXYZ 20 DEFGHI 123 5
+16 456789 123456789 xyz 1 6
+7 2 27 no truncation before
+8 3 28 no trunc
+9 3456789 ab 4
+
+
+-- Date/Time -- x Page 6
+
+
+29 xyzxyzxyz XYZXYZXYZ 1 3
+30 456789 123456789 xyz 2 3456789 abcdefghi
+ \ No newline at end of file
diff --git a/tests/pr/3b3f-FF b/tests/pr/3b3f-FF
new file mode 100644
index 0000000..6b22767
--- /dev/null
+++ b/tests/pr/3b3f-FF
@@ -0,0 +1,56 @@
+
+
+-- Date/Time -- x Page 3
+
+
+15 xyzxyzxyz XYZXYZXYZ 20 DEFGHI 123 5
+16 456789 123456789 xyz 1 6
+7 2 27 no truncation before
+8 3 28 no trunc
+9 3456789 ab 4
+
+
+-- Date/Time -- x Page 4
+
+
+
+
+
+-- Date/Time -- x Page 5
+
+
+29 xyzxyzxyz XYZXYZXYZ 4 9 3456789 abcdefghi
+30 456789 123456789 xyz 5 40 DEFGHI 123456789
+1 6 41 yzxyzxyz XYZXYZXYZ a
+2 3456789 abcdefghi 7 42 456789 123456789 abc
+3 8
+
+
+-- Date/Time -- x Page 6
+
+
+
+
+
+-- Date/Time -- x Page 7
+
+
+
+
+
+-- Date/Time -- x Page 8
+
+
+43 xyzxyzxyz XYZXYZXYZ 8 3
+44 456789 123456789 xyz 9 4
+5 50 55 yzxyzxyz XYZXYZXYZ a
+6 1 56 456789 123456789 abc
+7 2
+
+
+-- Date/Time -- x Page 9
+
+
+57 xyzxyzxyz XYZXYZXYZ 9 60 DEFGHI 123456789
+58 456789 123456789 xyz
+ \ No newline at end of file
diff --git a/tests/pr/3b3l15-t b/tests/pr/3b3l15-t
new file mode 100644
index 0000000..dbec31d
--- /dev/null
+++ b/tests/pr/3b3l15-t
@@ -0,0 +1,45 @@
+
+
+-- Date/Time -- x Page 3
+
+
+1 6 41 yzxyzxyz XYZXYZXYZ a
+2 3456789 abcdefghi 7 42 456789 123456789 abc
+3 8 43 xyzxyzxyz XYZXYZXYZ
+4 9 3456789 abcdefghi 44 456789 123456789 xyz
+5 40 DEFGHI 123456789 5
+
+
+
+
+
+
+
+-- Date/Time -- x Page 4
+
+
+6 1 56 456789 123456789 abc
+7 2 57 xyzxyzxyz XYZXYZXYZ
+8 3 58 456789 123456789 xyz
+9 4 9
+50 55 yzxyzxyz XYZXYZXYZ a 60 DEFGHI 123456789
+
+
+
+
+
+
+
+-- Date/Time -- x Page 5
+
+
+1 2 3 ------- EOF --------
+
+
+
+
+
+
+
+
+
diff --git a/tests/pr/3b3l15f-t b/tests/pr/3b3l15f-t
new file mode 100644
index 0000000..1a49dcb
--- /dev/null
+++ b/tests/pr/3b3l15f-t
@@ -0,0 +1,27 @@
+
+
+-- Date/Time -- x Page 3
+
+
+1 6 41 yzxyzxyz XYZXYZXYZ a
+2 3456789 abcdefghi 7 42 456789 123456789 abc
+3 8 43 xyzxyzxyz XYZXYZXYZ
+4 9 3456789 abcdefghi 44 456789 123456789 xyz
+5 40 DEFGHI 123456789 5
+
+
+-- Date/Time -- x Page 4
+
+
+6 1 56 456789 123456789 abc
+7 2 57 xyzxyzxyz XYZXYZXYZ
+8 3 58 456789 123456789 xyz
+9 4 9
+50 55 yzxyzxyz XYZXYZXYZ a 60 DEFGHI 123456789
+
+
+-- Date/Time -- x Page 5
+
+
+1 2 3 ------- EOF --------
+ \ No newline at end of file
diff --git a/tests/pr/3f-0F b/tests/pr/3f-0F
new file mode 100644
index 0000000..39a32c1
--- /dev/null
+++ b/tests/pr/3f-0F
@@ -0,0 +1,36 @@
+
+
+-- Date/Time -- x Page 3
+
+
+
+
+
+-- Date/Time -- x Page 4
+
+
+15 xyzxyzxyz XYZXYZXYZ abcabcab
+16 456789 123456789 xyzxyzxyz XYZXYZXYZ
+7 12345678
+8 12345678
+9 3456789 ab
+20 DEFGHI 123
+1 12345678
+2 12345678
+3 12345678
+4 12345678
+5 12345678
+6 12345678
+27 no truncation before FF; (r_l-test):
+28 no trunc
+
+
+-- Date/Time -- x Page 5
+
+
+29 xyzxyzxyz XYZXYZXYZ abcabcab
+30 456789 123456789 xyzxyzxyz XYZXYZXYZ
+1 12345678
+2 3456789 abcdefghi
+3 12345678
+ \ No newline at end of file
diff --git a/tests/pr/3f-FF b/tests/pr/3f-FF
new file mode 100644
index 0000000..52b881c
--- /dev/null
+++ b/tests/pr/3f-FF
@@ -0,0 +1,85 @@
+
+
+-- Date/Time -- x Page 3
+
+
+15 xyzxyzxyz XYZXYZXYZ abcabcab
+16 456789 123456789 xyzxyzxyz XYZXYZXYZ
+7 12345678
+8 12345678
+9 3456789 ab
+20 DEFGHI 123
+1 12345678
+2 12345678
+3 12345678
+4 12345678
+5 12345678
+6 12345678
+27 no truncation before FF; (r_l-test):
+28 no trunc
+
+
+-- Date/Time -- x Page 4
+
+
+
+
+
+-- Date/Time -- x Page 5
+
+
+29 xyzxyzxyz XYZXYZXYZ abcabcab
+30 456789 123456789 xyzxyzxyz XYZXYZXYZ
+1 12345678
+2 3456789 abcdefghi
+3 12345678
+4 12345678
+5 12345678
+6 12345678
+7 12345678
+8 12345678
+9 3456789 abcdefghi
+40 DEFGHI 123456789
+41 yzxyzxyz XYZXYZXYZ abcabcab
+42 456789 123456789 abcdefghi ABCDEDFHI
+
+
+-- Date/Time -- x Page 6
+
+
+
+
+
+-- Date/Time -- x Page 7
+
+
+
+
+
+-- Date/Time -- x Page 8
+
+
+43 xyzxyzxyz XYZXYZXYZ abcabcab
+44 456789 123456789 xyzxyzxyz XYZXYZXYZ
+5 12345678
+6 12345678
+7 12345678
+8 12345678
+9 12345678
+50 12345678
+1 12345678
+2 12345678
+3 12345678
+4 12345678
+55 yzxyzxyz XYZXYZXYZ abcabcab
+56 456789 123456789 abcdefghi ABCDEDFHI
+
+
+-- Date/Time -- x Page 9
+
+
+57 xyzxyzxyz XYZXYZXYZ abcabcab
+58 456789 123456789 xyzxyzxyz XYZXYZXYZ
+9 12345678
+60 DEFGHI 123456789
+ \ No newline at end of file
diff --git a/tests/pr/3l24-t b/tests/pr/3l24-t
new file mode 100644
index 0000000..6645155
--- /dev/null
+++ b/tests/pr/3l24-t
@@ -0,0 +1,72 @@
+
+
+-- Date/Time -- x Page 3
+
+
+29 xyzxyzxyz XYZXYZXYZ abcabcab
+30 456789 123456789 xyzxyzxyz XYZXYZXYZ
+1 12345678
+2 3456789 abcdefghi
+3 12345678
+4 12345678
+5 12345678
+6 12345678
+7 12345678
+8 12345678
+9 3456789 abcdefghi
+40 DEFGHI 123456789
+41 yzxyzxyz XYZXYZXYZ abcabcab
+42 456789 123456789 abcdefghi ABCDEDFHI
+
+
+
+
+
+
+
+-- Date/Time -- x Page 4
+
+
+43 xyzxyzxyz XYZXYZXYZ abcabcab
+44 456789 123456789 xyzxyzxyz XYZXYZXYZ
+5 12345678
+6 12345678
+7 12345678
+8 12345678
+9 12345678
+50 12345678
+1 12345678
+2 12345678
+3 12345678
+4 12345678
+55 yzxyzxyz XYZXYZXYZ abcabcab
+56 456789 123456789 abcdefghi ABCDEDFHI
+
+
+
+
+
+
+
+-- Date/Time -- x Page 5
+
+
+57 xyzxyzxyz XYZXYZXYZ abcabcab
+58 456789 123456789 xyzxyzxyz XYZXYZXYZ
+9 12345678
+60 DEFGHI 123456789
+1
+2
+3 ------- EOF -------- EOF -------- EOF -------
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/tests/pr/3l24f-t b/tests/pr/3l24f-t
new file mode 100644
index 0000000..6f35bd2
--- /dev/null
+++ b/tests/pr/3l24f-t
@@ -0,0 +1,51 @@
+
+
+-- Date/Time -- x Page 3
+
+
+29 xyzxyzxyz XYZXYZXYZ abcabcab
+30 456789 123456789 xyzxyzxyz XYZXYZXYZ
+1 12345678
+2 3456789 abcdefghi
+3 12345678
+4 12345678
+5 12345678
+6 12345678
+7 12345678
+8 12345678
+9 3456789 abcdefghi
+40 DEFGHI 123456789
+41 yzxyzxyz XYZXYZXYZ abcabcab
+42 456789 123456789 abcdefghi ABCDEDFHI
+
+
+-- Date/Time -- x Page 4
+
+
+43 xyzxyzxyz XYZXYZXYZ abcabcab
+44 456789 123456789 xyzxyzxyz XYZXYZXYZ
+5 12345678
+6 12345678
+7 12345678
+8 12345678
+9 12345678
+50 12345678
+1 12345678
+2 12345678
+3 12345678
+4 12345678
+55 yzxyzxyz XYZXYZXYZ abcabcab
+56 456789 123456789 abcdefghi ABCDEDFHI
+
+
+-- Date/Time -- x Page 5
+
+
+57 xyzxyzxyz XYZXYZXYZ abcabcab
+58 456789 123456789 xyzxyzxyz XYZXYZXYZ
+9 12345678
+60 DEFGHI 123456789
+1
+2
+3 ------- EOF -------- EOF -------- EOF -------
+ \ No newline at end of file
diff --git a/tests/pr/3ml24-FF b/tests/pr/3ml24-FF
new file mode 100644
index 0000000..6939741
--- /dev/null
+++ b/tests/pr/3ml24-FF
@@ -0,0 +1,168 @@
+
+
+-- Date/Time -- x Page 3
+
+
+15 xyzxyzxyz XYZXYZXYZ abcabcab 15 xyzxyzxyz XYZXYZXYZ abcabcab
+16 456789 123456789 xyzxyzxyz XYZXY 16 456789 123456789 xyzxyzxyz XYZXY
+7 7
+8 8
+9 3456789 ab 9 3456789 ab
+20 DEFGHI 123 20 DEFGHI 123
+1 1
+2 2
+3 3
+4 4
+5 5
+6 6
+27 no truncation before FF; (r_l-te 27 no truncation before FF; (r_l-te
+28 no trunc 28 no trunc
+
+
+
+
+
+
+
+-- Date/Time -- x Page 4
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+-- Date/Time -- x Page 5
+
+
+29 xyzxyzxyz XYZXYZXYZ abcabcab 29 xyzxyzxyz XYZXYZXYZ abcabcab
+30 456789 123456789 xyzxyzxyz XYZXY 30 456789 123456789 xyzxyzxyz XYZXY
+1 1
+2 3456789 abcdefghi 2 3456789 abcdefghi
+3 3
+4 4
+5 5
+6 6
+7 7
+8 8
+9 3456789 abcdefghi 9 3456789 abcdefghi
+40 DEFGHI 123456789 40 DEFGHI 123456789
+41 yzxyzxyz XYZXYZXYZ abcabcab 41 yzxyzxyz XYZXYZXYZ abcabcab
+42 456789 123456789 abcdefghi ABCDE 42 456789 123456789 abcdefghi ABCDE
+
+
+
+
+
+
+
+-- Date/Time -- x Page 6
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+-- Date/Time -- x Page 7
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+-- Date/Time -- x Page 8
+
+
+43 xyzxyzxyz XYZXYZXYZ abcabcab 43 xyzxyzxyz XYZXYZXYZ abcabcab
+44 456789 123456789 xyzxyzxyz XYZXY 44 456789 123456789 xyzxyzxyz XYZXY
+5 5
+6 6
+7 7
+8 8
+9 9
+50 50
+1 1
+2 2
+3 3
+4 4
+55 yzxyzxyz XYZXYZXYZ abcabcab 55 yzxyzxyz XYZXYZXYZ abcabcab
+56 456789 123456789 abcdefghi ABCDE 56 456789 123456789 abcdefghi ABCDE
+
+
+
+
+
+
+
+-- Date/Time -- x Page 9
+
+
+57 xyzxyzxyz XYZXYZXYZ abcabcab 57 xyzxyzxyz XYZXYZXYZ abcabcab
+58 456789 123456789 xyzxyzxyz XYZXY 58 456789 123456789 xyzxyzxyz XYZXY
+9 9
+60 DEFGHI 123456789 60 DEFGHI 123456789
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/tests/pr/3ml24-t b/tests/pr/3ml24-t
new file mode 100644
index 0000000..1b58463
--- /dev/null
+++ b/tests/pr/3ml24-t
@@ -0,0 +1,72 @@
+
+
+-- Date/Time -- x Page 3
+
+
+29 xyzxyzxyz XYZXYZXYZ abcabcab 29 xyzxyzxyz XYZXYZXYZ abcabcab
+30 456789 123456789 xyzxyzxyz XYZXY 30 456789 123456789 xyzxyzxyz XYZXY
+1 1
+2 3456789 abcdefghi 2 3456789 abcdefghi
+3 3
+4 4
+5 5
+6 6
+7 7
+8 8
+9 3456789 abcdefghi 9 3456789 abcdefghi
+40 DEFGHI 123456789 40 DEFGHI 123456789
+41 yzxyzxyz XYZXYZXYZ abcabcab 41 yzxyzxyz XYZXYZXYZ abcabcab
+42 456789 123456789 abcdefghi ABCDE 42 456789 123456789 abcdefghi ABCDE
+
+
+
+
+
+
+
+-- Date/Time -- x Page 4
+
+
+43 xyzxyzxyz XYZXYZXYZ abcabcab 43 xyzxyzxyz XYZXYZXYZ abcabcab
+44 456789 123456789 xyzxyzxyz XYZXY 44 456789 123456789 xyzxyzxyz XYZXY
+5 5
+6 6
+7 7
+8 8
+9 9
+50 50
+1 1
+2 2
+3 3
+4 4
+55 yzxyzxyz XYZXYZXYZ abcabcab 55 yzxyzxyz XYZXYZXYZ abcabcab
+56 456789 123456789 abcdefghi ABCDE 56 456789 123456789 abcdefghi ABCDE
+
+
+
+
+
+
+
+-- Date/Time -- x Page 5
+
+
+57 xyzxyzxyz XYZXYZXYZ abcabcab 57 xyzxyzxyz XYZXYZXYZ abcabcab
+58 456789 123456789 xyzxyzxyz XYZXY 58 456789 123456789 xyzxyzxyz XYZXY
+9 9
+60 DEFGHI 123456789 60 DEFGHI 123456789
+1 1
+2 2
+3 ------- EOF -------- EOF ------- 3 ------- EOF -------- EOF -------
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/tests/pr/3ml24-t-FF b/tests/pr/3ml24-t-FF
new file mode 100644
index 0000000..0bf5d5f
--- /dev/null
+++ b/tests/pr/3ml24-t-FF
@@ -0,0 +1,168 @@
+
+
+-- Date/Time -- x Page 3
+
+
+29 xyzxyzxyz XYZXYZXYZ abcabcab 15 xyzxyzxyz XYZXYZXYZ abcabcab
+30 456789 123456789 xyzxyzxyz XYZXY 16 456789 123456789 xyzxyzxyz XYZXY
+1 7
+2 3456789 abcdefghi 8
+3 9 3456789 ab
+4 20 DEFGHI 123
+5 1
+6 2
+7 3
+8 4
+9 3456789 abcdefghi 5
+40 DEFGHI 123456789 6
+41 yzxyzxyz XYZXYZXYZ abcabcab 27 no truncation before FF; (r_l-te
+42 456789 123456789 abcdefghi ABCDE 28 no trunc
+
+
+
+
+
+
+
+-- Date/Time -- x Page 4
+
+
+43 xyzxyzxyz XYZXYZXYZ abcabcab
+44 456789 123456789 xyzxyzxyz XYZXY
+5
+6
+7
+8
+9
+50
+1
+2
+3
+4
+55 yzxyzxyz XYZXYZXYZ abcabcab
+56 456789 123456789 abcdefghi ABCDE
+
+
+
+
+
+
+
+-- Date/Time -- x Page 5
+
+
+57 xyzxyzxyz XYZXYZXYZ abcabcab 29 xyzxyzxyz XYZXYZXYZ abcabcab
+58 456789 123456789 xyzxyzxyz XYZXY 30 456789 123456789 xyzxyzxyz XYZXY
+9 1
+60 DEFGHI 123456789 2 3456789 abcdefghi
+1 3
+2 4
+3 ------- EOF -------- EOF ------- 5
+ 6
+ 7
+ 8
+ 9 3456789 abcdefghi
+ 40 DEFGHI 123456789
+ 41 yzxyzxyz XYZXYZXYZ abcabcab
+ 42 456789 123456789 abcdefghi ABCDE
+
+
+
+
+
+
+
+-- Date/Time -- x Page 6
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+-- Date/Time -- x Page 7
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+-- Date/Time -- x Page 8
+
+
+ 43 xyzxyzxyz XYZXYZXYZ abcabcab
+ 44 456789 123456789 xyzxyzxyz XYZXY
+ 5
+ 6
+ 7
+ 8
+ 9
+ 50
+ 1
+ 2
+ 3
+ 4
+ 55 yzxyzxyz XYZXYZXYZ abcabcab
+ 56 456789 123456789 abcdefghi ABCDE
+
+
+
+
+
+
+
+-- Date/Time -- x Page 9
+
+
+ 57 xyzxyzxyz XYZXYZXYZ abcabcab
+ 58 456789 123456789 xyzxyzxyz XYZXY
+ 9
+ 60 DEFGHI 123456789
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/tests/pr/3ml24f-t b/tests/pr/3ml24f-t
new file mode 100644
index 0000000..6f92748
--- /dev/null
+++ b/tests/pr/3ml24f-t
@@ -0,0 +1,51 @@
+
+
+-- Date/Time -- x Page 3
+
+
+29 xyzxyzxyz XYZXYZXYZ abcabcab 29 xyzxyzxyz XYZXYZXYZ abcabcab
+30 456789 123456789 xyzxyzxyz XYZXY 30 456789 123456789 xyzxyzxyz XYZXY
+1 1
+2 3456789 abcdefghi 2 3456789 abcdefghi
+3 3
+4 4
+5 5
+6 6
+7 7
+8 8
+9 3456789 abcdefghi 9 3456789 abcdefghi
+40 DEFGHI 123456789 40 DEFGHI 123456789
+41 yzxyzxyz XYZXYZXYZ abcabcab 41 yzxyzxyz XYZXYZXYZ abcabcab
+42 456789 123456789 abcdefghi ABCDE 42 456789 123456789 abcdefghi ABCDE
+
+
+-- Date/Time -- x Page 4
+
+
+43 xyzxyzxyz XYZXYZXYZ abcabcab 43 xyzxyzxyz XYZXYZXYZ abcabcab
+44 456789 123456789 xyzxyzxyz XYZXY 44 456789 123456789 xyzxyzxyz XYZXY
+5 5
+6 6
+7 7
+8 8
+9 9
+50 50
+1 1
+2 2
+3 3
+4 4
+55 yzxyzxyz XYZXYZXYZ abcabcab 55 yzxyzxyz XYZXYZXYZ abcabcab
+56 456789 123456789 abcdefghi ABCDE 56 456789 123456789 abcdefghi ABCDE
+
+
+-- Date/Time -- x Page 5
+
+
+57 xyzxyzxyz XYZXYZXYZ abcabcab 57 xyzxyzxyz XYZXYZXYZ abcabcab
+58 456789 123456789 xyzxyzxyz XYZXY 58 456789 123456789 xyzxyzxyz XYZXY
+9 9
+60 DEFGHI 123456789 60 DEFGHI 123456789
+1 1
+2 2
+3 ------- EOF -------- EOF ------- 3 ------- EOF -------- EOF -------
+ \ No newline at end of file
diff --git a/tests/pr/4-7l24-FF b/tests/pr/4-7l24-FF
new file mode 100644
index 0000000..13b106e
--- /dev/null
+++ b/tests/pr/4-7l24-FF
@@ -0,0 +1,96 @@
+
+
+-- Date/Time -- x Page 4
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+-- Date/Time -- x Page 5
+
+
+29 xyzxyzxyz XYZXYZXYZ abcabcab
+30 456789 123456789 xyzxyzxyz XYZXYZXYZ
+1 12345678
+2 3456789 abcdefghi
+3 12345678
+4 12345678
+5 12345678
+6 12345678
+7 12345678
+8 12345678
+9 3456789 abcdefghi
+40 DEFGHI 123456789
+41 yzxyzxyz XYZXYZXYZ abcabcab
+42 456789 123456789 abcdefghi ABCDEDFHI
+
+
+
+
+
+
+
+-- Date/Time -- x Page 6
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+-- Date/Time -- x Page 7
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/tests/pr/4l24-FF b/tests/pr/4l24-FF
new file mode 100644
index 0000000..7bd96a5
--- /dev/null
+++ b/tests/pr/4l24-FF
@@ -0,0 +1,144 @@
+
+
+-- Date/Time -- x Page 4
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+-- Date/Time -- x Page 5
+
+
+29 xyzxyzxyz XYZXYZXYZ abcabcab
+30 456789 123456789 xyzxyzxyz XYZXYZXYZ
+1 12345678
+2 3456789 abcdefghi
+3 12345678
+4 12345678
+5 12345678
+6 12345678
+7 12345678
+8 12345678
+9 3456789 abcdefghi
+40 DEFGHI 123456789
+41 yzxyzxyz XYZXYZXYZ abcabcab
+42 456789 123456789 abcdefghi ABCDEDFHI
+
+
+
+
+
+
+
+-- Date/Time -- x Page 6
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+-- Date/Time -- x Page 7
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+-- Date/Time -- x Page 8
+
+
+43 xyzxyzxyz XYZXYZXYZ abcabcab
+44 456789 123456789 xyzxyzxyz XYZXYZXYZ
+5 12345678
+6 12345678
+7 12345678
+8 12345678
+9 12345678
+50 12345678
+1 12345678
+2 12345678
+3 12345678
+4 12345678
+55 yzxyzxyz XYZXYZXYZ abcabcab
+56 456789 123456789 abcdefghi ABCDEDFHI
+
+
+
+
+
+
+
+-- Date/Time -- x Page 9
+
+
+57 xyzxyzxyz XYZXYZXYZ abcabcab
+58 456789 123456789 xyzxyzxyz XYZXYZXYZ
+9 12345678
+60 DEFGHI 123456789
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/tests/pr/FF b/tests/pr/FF
new file mode 100644
index 0000000..6fc2703
--- /dev/null
+++ b/tests/pr/FF
@@ -0,0 +1,594 @@
+
+
+-- Date/Time -- x Page 1
+
+
+1 FF-Test: FF's in Text V
+2 Options -b -3 / -a -3 / ...
+3 --------------------------------------------
+4 3456789 123456789 123456789 123456789 12345678
+5 3 Columns downwards ..., <= 5 lines per page
+6 FF-Arangements: One Empty Page
+7 text\f\f\n; text\f\n\ftext; \f\ftext;
+8 \f\f\n; \f\n\f\n;
+9
+10 zzzzzzzzzzzzzzzzzzzzzzzzzz123456789
+1 12345678
+2 12345678
+3 line truncation before FF; r_r_o_l-test:
+14 456789 123456789 123456789 123456789
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+-- Date/Time -- x Page 2
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+-- Date/Time -- x Page 3
+
+
+15 xyzxyzxyz XYZXYZXYZ abcabcab
+16 456789 123456789 xyzxyzxyz XYZXYZXYZ
+7 12345678
+8 12345678
+9 3456789 ab
+20 DEFGHI 123
+1 12345678
+2 12345678
+3 12345678
+4 12345678
+5 12345678
+6 12345678
+27 no truncation before FF; (r_l-test):
+28 no trunc
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+-- Date/Time -- x Page 4
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+-- Date/Time -- x Page 5
+
+
+29 xyzxyzxyz XYZXYZXYZ abcabcab
+30 456789 123456789 xyzxyzxyz XYZXYZXYZ
+1 12345678
+2 3456789 abcdefghi
+3 12345678
+4 12345678
+5 12345678
+6 12345678
+7 12345678
+8 12345678
+9 3456789 abcdefghi
+40 DEFGHI 123456789
+41 yzxyzxyz XYZXYZXYZ abcabcab
+42 456789 123456789 abcdefghi ABCDEDFHI
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+-- Date/Time -- x Page 6
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+-- Date/Time -- x Page 7
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+-- Date/Time -- x Page 8
+
+
+43 xyzxyzxyz XYZXYZXYZ abcabcab
+44 456789 123456789 xyzxyzxyz XYZXYZXYZ
+5 12345678
+6 12345678
+7 12345678
+8 12345678
+9 12345678
+50 12345678
+1 12345678
+2 12345678
+3 12345678
+4 12345678
+55 yzxyzxyz XYZXYZXYZ abcabcab
+56 456789 123456789 abcdefghi ABCDEDFHI
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+-- Date/Time -- x Page 9
+
+
+57 xyzxyzxyz XYZXYZXYZ abcabcab
+58 456789 123456789 xyzxyzxyz XYZXYZXYZ
+9 12345678
+60 DEFGHI 123456789
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/tests/pr/FFn b/tests/pr/FFn
new file mode 100644
index 0000000..ab7c036
--- /dev/null
+++ b/tests/pr/FFn
@@ -0,0 +1,64 @@
+1 FF-Test: FF's in Text V
+2 Options -b -3 / -a -3 / ...
+3 --------------------------------------------
+4 3456789 123456789 123456789 123456789 12345678
+5 3 Columns downwards ..., <= 5 lines per page
+6 FF-Arangements: One Empty Page
+7 text\f\f\n; text\f\n\ftext; \f\ftext;
+8 \f\f\n; \f\n\f\n;
+9
+10 zzzzzzzzzzzzzzzzzzzzzzzzzz123456789
+1 12345678
+2 12345678
+3 line truncation before FF; r_r_o_l-test:
+14 456789 123456789 123456789 123456789
+
+15 xyzxyzxyz XYZXYZXYZ abcabcab
+16 456789 123456789 xyzxyzxyz XYZXYZXYZ
+7 12345678
+8 12345678
+9 3456789 ab
+20 DEFGHI 123
+1 12345678
+2 12345678
+3 12345678
+4 12345678
+5 12345678
+6 12345678
+27 no truncation before FF; (r_l-test):
+28 no trunc
+
+29 xyzxyzxyz XYZXYZXYZ abcabcab
+30 456789 123456789 xyzxyzxyz XYZXYZXYZ
+1 12345678
+2 3456789 abcdefghi
+3 12345678
+4 12345678
+5 12345678
+6 12345678
+7 12345678
+8 12345678
+9 3456789 abcdefghi
+40 DEFGHI 123456789
+41 yzxyzxyz XYZXYZXYZ abcabcab
+42 456789 123456789 abcdefghi ABCDEDFHI
+
+43 xyzxyzxyz XYZXYZXYZ abcabcab
+44 456789 123456789 xyzxyzxyz XYZXYZXYZ
+5 12345678
+6 12345678
+7 12345678
+8 12345678
+9 12345678
+50 12345678
+1 12345678
+2 12345678
+3 12345678
+4 12345678
+55 yzxyzxyz XYZXYZXYZ abcabcab
+56 456789 123456789 abcdefghi ABCDEDFHI
+
+57 xyzxyzxyz XYZXYZXYZ abcabcab
+58 456789 123456789 xyzxyzxyz XYZXYZXYZ
+9 12345678
+60 DEFGHI 123456789
diff --git a/tests/pr/FFtn b/tests/pr/FFtn
new file mode 100644
index 0000000..dfd229b
--- /dev/null
+++ b/tests/pr/FFtn
@@ -0,0 +1,60 @@
+1 FF-Test: FF's in Text V
+2 Options -b -3 / -a -3 / ...
+3 --------------------------------------------
+4 3456789 123456789 123456789 123456789 12345678
+5 3 Columns downwards ..., <= 5 lines per page
+6 FF-Arangements: One Empty Page
+7 text\f\f\n; text\f\n\ftext; \f\ftext;
+8 \f\f\n; \f\n\f\n;
+9
+10 zzzzzzzzzzzzzzzzzzzzzzzzzz123456789
+1 12345678
+2 12345678
+3 line truncation before FF; r_r_o_l-test:
+14 456789 123456789 123456789 123456789
+ 15 xyzxyzxyz XYZXYZXYZ abcabcab
+16 456789 123456789 xyzxyzxyz XYZXYZXYZ
+7 12345678
+8 12345678
+9 3456789 ab
+20 DEFGHI 123
+1 12345678
+2 12345678
+3 12345678
+4 12345678
+5 12345678
+6 12345678
+27 no truncation before FF; (r_l-test):
+28 no trunc
+ 29 xyzxyzxyz XYZXYZXYZ abcabcab
+30 456789 123456789 xyzxyzxyz XYZXYZXYZ
+1 12345678
+2 3456789 abcdefghi
+3 12345678
+4 12345678
+5 12345678
+6 12345678
+7 12345678
+8 12345678
+9 3456789 abcdefghi
+40 DEFGHI 123456789
+41 yzxyzxyz XYZXYZXYZ abcabcab
+42 456789 123456789 abcdefghi ABCDEDFHI
+ 43 xyzxyzxyz XYZXYZXYZ abcabcab
+44 456789 123456789 xyzxyzxyz XYZXYZXYZ
+5 12345678
+6 12345678
+7 12345678
+8 12345678
+9 12345678
+50 12345678
+1 12345678
+2 12345678
+3 12345678
+4 12345678
+55 yzxyzxyz XYZXYZXYZ abcabcab
+56 456789 123456789 abcdefghi ABCDEDFHI
+ 57 xyzxyzxyz XYZXYZXYZ abcabcab
+58 456789 123456789 xyzxyzxyz XYZXYZXYZ
+9 12345678
+60 DEFGHI 123456789
diff --git a/tests/pr/FnFn b/tests/pr/FnFn
new file mode 100644
index 0000000..fa91aba
--- /dev/null
+++ b/tests/pr/FnFn
@@ -0,0 +1,68 @@
+1 FF-Test: FF's in Text V
+2 Options -b -3 / -a -3 / ...
+3 --------------------------------------------
+4 3456789 123456789 123456789 123456789 12345678
+5 3 Columns downwards ..., <= 5 lines per page
+6 FF-Arangements: One Empty Page
+7 text\f\f\n; text\f\n\ftext; \f\ftext;
+8 \f\f\n; \f\n\f\n;
+9
+10 zzzzzzzzzzzzzzzzzzzzzzzzzz123456789
+1 12345678
+2 12345678
+3 line truncation before FF; r_r_o_l-test:
+14 456789 123456789 123456789 123456789
+
+
+15 xyzxyzxyz XYZXYZXYZ abcabcab
+16 456789 123456789 xyzxyzxyz XYZXYZXYZ
+7 12345678
+8 12345678
+9 3456789 ab
+20 DEFGHI 123
+1 12345678
+2 12345678
+3 12345678
+4 12345678
+5 12345678
+6 12345678
+27 no truncation before FF; (r_l-test):
+28 no trunc
+
+
+29 xyzxyzxyz XYZXYZXYZ abcabcab
+30 456789 123456789 xyzxyzxyz XYZXYZXYZ
+1 12345678
+2 3456789 abcdefghi
+3 12345678
+4 12345678
+5 12345678
+6 12345678
+7 12345678
+8 12345678
+9 3456789 abcdefghi
+40 DEFGHI 123456789
+41 yzxyzxyz XYZXYZXYZ abcabcab
+42 456789 123456789 abcdefghi ABCDEDFHI
+
+
+
+43 xyzxyzxyz XYZXYZXYZ abcabcab
+44 456789 123456789 xyzxyzxyz XYZXYZXYZ
+5 12345678
+6 12345678
+7 12345678
+8 12345678
+9 12345678
+50 12345678
+1 12345678
+2 12345678
+3 12345678
+4 12345678
+55 yzxyzxyz XYZXYZXYZ abcabcab
+56 456789 123456789 abcdefghi ABCDEDFHI
+
+57 xyzxyzxyz XYZXYZXYZ abcabcab
+58 456789 123456789 xyzxyzxyz XYZXYZXYZ
+9 12345678
+60 DEFGHI 123456789
diff --git a/tests/pr/Ja3l24f-lm b/tests/pr/Ja3l24f-lm
new file mode 100644
index 0000000..a6b7df7
--- /dev/null
+++ b/tests/pr/Ja3l24f-lm
@@ -0,0 +1,72 @@
+
+
+-- Date/Time -- x Page 1
+
+
+1<<< -Test: FF's in Text >>> 2<<< -b -3 / -a -3 / ... >>> 3<<< >>>
+4<<< 123456789 123456789 123456789 12345678 >>> 6<<< -Arangements: One Empty Page >>>
+7<<< \f\f\n; text\f\n\ftext; \f\ftext; >>> 8<<< f\f\n; \f\n\f\n; >>> 9<<< >>>
+10<<< >>> 1<<< >>> 2<<< >>>
+3<<< truncation before FF; r_r_o_l-test: >>> 14<<< 123456789 123456789 123456789 >>>
+
+
+-- Date/Time -- x Page 2
+
+
+
+
+
+-- Date/Time -- x Page 3
+
+
+15<<< xyzxyzxyz XYZXYZXYZ abcabcab >>> 16<<< 123456789 xyzxyzxyz XYZXYZXYZ >>> 7<<< >>>
+8<<< >>> 9<<< >>> 20<<< >>>
+1<<< >>>
+4<<< >>> 5<<< >>> 6<<< >>>
+27<<< truncation before FF; (r_l-test): >>> 28<<< trunc
+
+
+-- Date/Time -- x Page 4
+
+
+
+
+
+-- Date/Time -- x Page 5
+
+
+29<<<xyzxyzxyz XYZXYZXYZ abcabcab >>> 30<<< 123456789 xyzxyzxyz XYZXYZXYZ >>> 1<<< >>>
+2<<< abcdefghi >>> 3<<< >>> 4<<< >>>
+5<<< >>> 6<<< >>> 7<<< >>>
+8<<< >>> 9<<< abcdefghi >>> 40<<< 123456789 >>>
+41<<< XYZXYZXYZ abcabcab >>> 42<<< 123456789 abcdefghi ABCDEDFHI >>>
+
+
+-- Date/Time -- x Page 6
+
+
+
+
+
+-- Date/Time -- x Page 7
+
+
+
+
+
+-- Date/Time -- x Page 8
+
+
+43<<< xyzxyzxyz XYZXYZXYZ abcabcab >>> 44<<< 123456789 xyzxyzxyz XYZXYZXYZ >>> 5<<< >>>
+6<<< >>> 7<<< >>> 8<<< >>>
+9<<< >>> 50<<< >>> 1<<< >>>
+2<<< >>> 3<<< >>> 4<<< >>>
+55<<< XYZXYZXYZ abcabcab >>> 56<<< 123456789 abcdefghi ABCDEDFHI >>>
+
+
+-- Date/Time -- x Page 9
+
+
+57<<< xyzxyzxyz XYZXYZXYZ abcabcab >>> 58<<< 123456789 xyzxyzxyz XYZXYZXYZ >>> 9<<< >>>
+60<<< 123456789 >>>
+ \ No newline at end of file
diff --git a/tests/pr/Jb3l24f-lm b/tests/pr/Jb3l24f-lm
new file mode 100644
index 0000000..220b058
--- /dev/null
+++ b/tests/pr/Jb3l24f-lm
@@ -0,0 +1,72 @@
+
+
+-- Date/Time -- x Page 1
+
+
+1<<< -Test: FF's in Text >>> 6<<< -Arangements: One Empty Page >>> 1<<< >>>
+2<<< -b -3 / -a -3 / ... >>> 7<<< \f\f\n; text\f\n\ftext; \f\ftext; >>> 2<<< >>>
+3<<< >>> 8<<< f\f\n; \f\n\f\n; >>> 3<<< truncation before FF; r_r_o_l-test: >>>
+4<<< 123456789 123456789 123456789 12345678 >>> 9<<< >>> 14<<< 123456789 123456789 123456789 >>>
+ 10<<< >>>
+
+
+-- Date/Time -- x Page 2
+
+
+
+
+
+-- Date/Time -- x Page 3
+
+
+15<<< xyzxyzxyz XYZXYZXYZ abcabcab >>> 20<<< >>> 5<<< >>>
+16<<< 123456789 xyzxyzxyz XYZXYZXYZ >>> 1<<< >>> 6<<< >>>
+7<<< >>> 27<<< truncation before FF; (r_l-test): >>>
+8<<< >>> 28<<< trunc
+9<<< >>> 4<<< >>>
+
+
+-- Date/Time -- x Page 4
+
+
+
+
+
+-- Date/Time -- x Page 5
+
+
+29<<<xyzxyzxyz XYZXYZXYZ abcabcab >>> 4<<< >>> 9<<< abcdefghi >>>
+30<<< 123456789 xyzxyzxyz XYZXYZXYZ >>> 5<<< >>> 40<<< 123456789 >>>
+1<<< >>> 6<<< >>> 41<<< XYZXYZXYZ abcabcab >>>
+2<<< abcdefghi >>> 7<<< >>> 42<<< 123456789 abcdefghi ABCDEDFHI >>>
+3<<< >>> 8<<< >>>
+
+
+-- Date/Time -- x Page 6
+
+
+
+
+
+-- Date/Time -- x Page 7
+
+
+
+
+
+-- Date/Time -- x Page 8
+
+
+43<<< xyzxyzxyz XYZXYZXYZ abcabcab >>> 8<<< >>> 3<<< >>>
+44<<< 123456789 xyzxyzxyz XYZXYZXYZ >>> 9<<< >>> 4<<< >>>
+5<<< >>> 50<<< >>> 55<<< XYZXYZXYZ abcabcab >>>
+6<<< >>> 1<<< >>> 56<<< 123456789 abcdefghi ABCDEDFHI >>>
+7<<< >>> 2<<< >>>
+
+
+-- Date/Time -- x Page 9
+
+
+57<<< xyzxyzxyz XYZXYZXYZ abcabcab >>> 9<<< >>> 60<<< 123456789 >>>
+58<<< 123456789 xyzxyzxyz XYZXYZXYZ >>>
+ \ No newline at end of file
diff --git a/tests/pr/Jml24f-lm-lo b/tests/pr/Jml24f-lm-lo
new file mode 100644
index 0000000..66af2d4
--- /dev/null
+++ b/tests/pr/Jml24f-lm-lo
@@ -0,0 +1,136 @@
+
+
+-- Date/Time -- x Page 1
+
+
+1<<< -Test: FF's in Text >>> 1::: Test-INPUT: "Without FF set by Hand" :::
+2<<< -b -3 / -a -3 / ... >>> 2::: Options -b -3 [+2|+3] [-l 15|8] [-f] :::
+3<<< >>> 3::: Options -a -3 [+2|+3] [-l 15|8] [-f] :::
+4<<< 123456789 123456789 123456789 12345678 >>> 4::: Options [+2|+3] [-l 24|17] [-f] :::
+ 5::: :::
+6<<< -Arangements: One Empty Page >>> 6::: -------------------------------------------- :::
+7<<< \f\f\n; text\f\n\ftext; \f\ftext; >>> 7::: 789 123456789 123456789 123456789 123456789 123456789 123456789 1234567890 :::
+8<<< f\f\n; \f\n\f\n; >>> 8::: 3 Columns downwards, across, ...: :::
+9<<< >>> 9::: With columns use <= 5 text lines/page, :::
+10<<< >>> 10::: without -f e.g.: -l 15 = total lines/page, :::
+1<<< >>> 1::: with -f e.g. : -l 8 -f :::
+2<<< >>> 2::: :::
+3<<< truncation before FF; r_r_o_l-test: >>> 3::: line truncation before new page; r_r_o_l-test: :::
+14<<< 123456789 123456789 123456789 >>> 14::: 89 123456789 123456789 123456789 123456789 123456789 123456789 1234567890 :::
+
+
+-- Date/Time -- x Page 2
+
+
+ 15::: xyzxyzxyz XYZXYZXYZ abcabcab :::
+ 16::: 456789 123456789 xyzxyzxyz XYZXYZXYZ :::
+ 7::: 12345678 :::
+ 8::: 12345678 :::
+ 9::: 3456789 ab :::
+ 20::: DEFGHI 123 :::
+ 21::: 89 123456789 123456789 123456789 123456789 123456789 123456789 1234567890 :::
+ 2::: 12345678 :::
+ 3::: 12345678 :::
+ 4::: 12345678 :::
+ 5::: 12345678 :::
+ 6::: 12345678 :::
+ 27::: no truncation before nwe page; (r_l-test): :::
+ 28::: 89 123456789 123456789 123456789 123456789 123456789 123456789 1234567890 :::
+
+
+-- Date/Time -- x Page 3
+
+
+15<<< xyzxyzxyz XYZXYZXYZ abcabcab >>> 29::: xyzxyzxyz XYZXYZXYZ abcabcab :::
+16<<< 123456789 xyzxyzxyz XYZXYZXYZ >>> 30::: 456789 123456789 xyzxyzxyz XYZXYZXYZ :::
+7<<< >>> 1::: 12345678 :::
+8<<< >>> 2::: 3456789 abcdefghi :::
+9<<< >>> 3::: 12345678 :::
+20<<< >>> 4::: 12345678 :::
+1<<< >>> 35::: 89 123456789 123456789 123456789 123456789 123456789 123456789 1234567890 :::
+ 6::: 12345678 :::
+ 7::: 12345678 :::
+4<<< >>> 8::: 12345678 :::
+5<<< >>> 9::: 3456789 abcdefghi :::
+6<<< >>> 40::: DEFGHI 123456789 :::
+27<<< truncation before FF; (r_l-test): >>> 41::: yzxyzxyz XYZXYZXYZ abcabcab :::
+28<<< trunc 42::: 89 123456789 123456789 123456789 123456789 123456789 123456789 1234567890 :::
+
+
+-- Date/Time -- x Page 4
+
+
+ 43::: xyzxyzxyz XYZXYZXYZ abcabcab :::
+ 44::: 456789 123456789 xyzxyzxyz XYZXYZXYZ :::
+ 5::: 12345678 :::
+ 6::: 12345678 :::
+ 7::: 12345678 :::
+ 8::: 12345678 :::
+ 49::: 89 123456789 123456789 123456789 123456789 123456789 123456789 1234567890 :::
+ 50::: 12345678 :::
+ 1::: 12345678 :::
+ 2::: 12345678 :::
+ 3::: 12345678 :::
+ 4::: 12345678 :::
+ 55::: yzxyzxyz XYZXYZXYZ abcabcab :::
+ 56::: 89 123456789 123456789 123456789 123456789 123456789 123456789 1234567890 :::
+
+
+-- Date/Time -- x Page 5
+
+
+29<<<xyzxyzxyz XYZXYZXYZ abcabcab >>> 57::: xyzxyzxyz XYZXYZXYZ abcabcab :::
+30<<< 123456789 xyzxyzxyz XYZXYZXYZ >>> 58::: 456789 123456789 xyzxyzxyz XYZXYZXYZ :::
+1<<< >>> 9::: 12345678 :::
+2<<< abcdefghi >>> 60::: DEFGHI 123456789 :::
+3<<< >>> 1::: :::
+4<<< >>> 2::: :::
+5<<< >>> 3::: ------- EOF -------- EOF -------- EOF ------- EOF ------- EOF ------- EOF :::
+6<<< >>>
+7<<< >>>
+8<<< >>>
+9<<< abcdefghi >>>
+40<<< 123456789 >>>
+41<<< XYZXYZXYZ abcabcab >>>
+42<<< 123456789 abcdefghi ABCDEDFHI >>>
+
+
+-- Date/Time -- x Page 6
+
+
+
+
+
+-- Date/Time -- x Page 7
+
+
+
+
+
+-- Date/Time -- x Page 8
+
+
+43<<< xyzxyzxyz XYZXYZXYZ abcabcab >>>
+44<<< 123456789 xyzxyzxyz XYZXYZXYZ >>>
+5<<< >>>
+6<<< >>>
+7<<< >>>
+8<<< >>>
+9<<< >>>
+50<<< >>>
+1<<< >>>
+2<<< >>>
+3<<< >>>
+4<<< >>>
+55<<< XYZXYZXYZ abcabcab >>>
+56<<< 123456789 abcdefghi ABCDEDFHI >>>
+
+
+-- Date/Time -- x Page 9
+
+
+57<<< xyzxyzxyz XYZXYZXYZ abcabcab >>>
+58<<< 123456789 xyzxyzxyz XYZXYZXYZ >>>
+9<<< >>>
+60<<< 123456789 >>>
+ \ No newline at end of file
diff --git a/tests/pr/W-72l24f-ll b/tests/pr/W-72l24f-ll
new file mode 100644
index 0000000..a2f9a4e
--- /dev/null
+++ b/tests/pr/W-72l24f-ll
@@ -0,0 +1,110 @@
+
+
+-- Date/Time -- x Page 1
+
+
+1<<< -Test: FF's in Text >>>
+2<<< -b -3 / -a -3 / ... >>>
+3<<< >>>
+4<<< 123456789 123456789 123456789 123456789 123456789 123456789 123456
+
+6<<< -Arangements: One Empty Page >>>
+7<<< \f\f\n; text\f\n\ftext; \f\ftext; >>>
+8<<< f\f\n; \f\n\f\n; >>>
+9<<< >>>
+10<<< >>>
+1<<< >>>
+2<<< >>>
+3<<< truncation before FF; r_r_o_l-test: >>>
+14<<< 123456789 123456789 123456789 >>>
+
+
+-- Date/Time -- x Page 2
+
+
+
+
+
+-- Date/Time -- x Page 3
+
+
+15<<< xyzxyzxyz XYZXYZXYZ abcabcab >>>
+16<<< 123456789 xyzxyzxyz XYZXYZXYZ >>>
+7<<< >>>
+8<<< >>>
+9<<< >>>
+20<<< >>>
+1<<< >>>
+
+
+4<<< >>>
+5<<< >>>
+6<<< >>>
+27<<< truncation before FF; (r_l-test): >>>
+28<<< trunc
+
+
+-- Date/Time -- x Page 4
+
+
+
+
+
+-- Date/Time -- x Page 5
+
+
+29<<<xyzxyzxyz XYZXYZXYZ abcabcab >>>
+30<<< 123456789 xyzxyzxyz XYZXYZXYZ >>>
+1<<< >>>
+2<<< abcdefghi >>>
+3<<< >>>
+4<<< >>>
+5<<< >>>
+6<<< >>>
+7<<< >>>
+8<<< >>>
+9<<< abcdefghi >>>
+40<<< 123456789 >>>
+41<<< XYZXYZXYZ abcabcab >>>
+42<<< 123456789 abcdefghi ABCDEDFHI >>>
+
+
+-- Date/Time -- x Page 6
+
+
+
+
+
+-- Date/Time -- x Page 7
+
+
+
+
+
+-- Date/Time -- x Page 8
+
+
+43<<< xyzxyzxyz XYZXYZXYZ abcabcab >>>
+44<<< 123456789 xyzxyzxyz XYZXYZXYZ >>>
+5<<< >>>
+6<<< >>>
+7<<< >>>
+8<<< >>>
+9<<< >>>
+50<<< >>>
+1<<< >>>
+2<<< >>>
+3<<< >>>
+4<<< >>>
+55<<< XYZXYZXYZ abcabcab >>>
+56<<< 123456789 abcdefghi ABCDEDFHI >>>
+
+
+-- Date/Time -- x Page 9
+
+
+57<<< xyzxyzxyz XYZXYZXYZ abcabcab >>>
+58<<< 123456789 xyzxyzxyz XYZXYZXYZ >>>
+9<<< >>>
+60<<< 123456789 >>>
+ \ No newline at end of file
diff --git a/tests/pr/W20l24f-ll b/tests/pr/W20l24f-ll
new file mode 100644
index 0000000..ecc9a7a
--- /dev/null
+++ b/tests/pr/W20l24f-ll
@@ -0,0 +1,110 @@
+
+
+-- Date/Time -- x Page 1
+
+
+1<<< -Test: FF's in
+2<<< -b -3 / -a -3
+3<<< >>>
+4<<< 123456789 1234
+
+6<<< -Arangements:
+7<<< \f\f\n; text\f
+8<<< f\f\n; \f\n\f\
+9<<< >>>
+10<<< >>>
+1<<< >>>
+2<<< >>>
+3<<< truncation bef
+14<<< 123456789 123
+
+
+-- Date/Time -- x Page 2
+
+
+
+
+
+-- Date/Time -- x Page 3
+
+
+15<<< xyzxyzxyz XYZ
+16<<< 123456789 xyz
+7<<< >>>
+8<<< >>>
+9<<< >>>
+20<<< >>>
+1<<< >>>
+
+
+4<<< >>>
+5<<< >>>
+6<<< >>>
+27<<< truncation be
+28<<< trunc
+
+
+-- Date/Time -- x Page 4
+
+
+
+
+
+-- Date/Time -- x Page 5
+
+
+29<<<xyzxyzxyz XYZXY
+30<<< 123456789 xyz
+1<<< >>>
+2<<< abcdefghi >>>
+3<<< >>>
+4<<< >>>
+5<<< >>>
+6<<< >>>
+7<<< >>>
+8<<< >>>
+9<<< abcdefghi >>>
+40<<< 123456789 >>
+41<<< XYZXYZXYZ abc
+42<<< 123456789 abc
+
+
+-- Date/Time -- x Page 6
+
+
+
+
+
+-- Date/Time -- x Page 7
+
+
+
+
+
+-- Date/Time -- x Page 8
+
+
+43<<< xyzxyzxyz XYZ
+44<<< 123456789 xyz
+5<<< >>>
+6<<< >>>
+7<<< >>>
+8<<< >>>
+9<<< >>>
+50<<< >>>
+1<<< >>>
+2<<< >>>
+3<<< >>>
+4<<< >>>
+55<<< XYZXYZXYZ abc
+56<<< 123456789 abc
+
+
+-- Date/Time -- x Page 9
+
+
+57<<< xyzxyzxyz XYZ
+58<<< 123456789 xyz
+9<<< >>>
+60<<< 123456789 >>
+ \ No newline at end of file
diff --git a/tests/pr/W26l24f-ll b/tests/pr/W26l24f-ll
new file mode 100644
index 0000000..accf48e
--- /dev/null
+++ b/tests/pr/W26l24f-ll
@@ -0,0 +1,110 @@
+
+
+-- Date/Time -- x Page 1
+
+
+1<<< -Test: FF's in Text
+2<<< -b -3 / -a -3 / ...
+3<<< >>>
+4<<< 123456789 123456789
+
+6<<< -Arangements: One Em
+7<<< \f\f\n; text\f\n\fte
+8<<< f\f\n; \f\n\f\n; >>
+9<<< >>>
+10<<< >>>
+1<<< >>>
+2<<< >>>
+3<<< truncation before FF
+14<<< 123456789 123456789
+
+
+-- Date/Time -- x Page 2
+
+
+
+
+
+-- Date/Time -- x Page 3
+
+
+15<<< xyzxyzxyz XYZXYZXYZ
+16<<< 123456789 xyzxyzxyz
+7<<< >>>
+8<<< >>>
+9<<< >>>
+20<<< >>>
+1<<< >>>
+
+
+4<<< >>>
+5<<< >>>
+6<<< >>>
+27<<< truncation before F
+28<<< trunc
+
+
+-- Date/Time -- x Page 4
+
+
+
+
+
+-- Date/Time -- x Page 5
+
+
+29<<<xyzxyzxyz XYZXYZXYZ a
+30<<< 123456789 xyzxyzxyz
+1<<< >>>
+2<<< abcdefghi >>>
+3<<< >>>
+4<<< >>>
+5<<< >>>
+6<<< >>>
+7<<< >>>
+8<<< >>>
+9<<< abcdefghi >>>
+40<<< 123456789 >>>
+41<<< XYZXYZXYZ abcabcab
+42<<< 123456789 abcdefghi
+
+
+-- Date/Time -- x Page 6
+
+
+
+
+
+-- Date/Time -- x Page 7
+
+
+
+
+
+-- Date/Time -- x Page 8
+
+
+43<<< xyzxyzxyz XYZXYZXYZ
+44<<< 123456789 xyzxyzxyz
+5<<< >>>
+6<<< >>>
+7<<< >>>
+8<<< >>>
+9<<< >>>
+50<<< >>>
+1<<< >>>
+2<<< >>>
+3<<< >>>
+4<<< >>>
+55<<< XYZXYZXYZ abcabcab
+56<<< 123456789 abcdefghi
+
+
+-- Date/Time -- x Page 9
+
+
+57<<< xyzxyzxyz XYZXYZXYZ
+58<<< 123456789 xyzxyzxyz
+9<<< >>>
+60<<< 123456789 >>>
+ \ No newline at end of file
diff --git a/tests/pr/W27l24f-ll b/tests/pr/W27l24f-ll
new file mode 100644
index 0000000..2c1e230
--- /dev/null
+++ b/tests/pr/W27l24f-ll
@@ -0,0 +1,110 @@
+
+
+-- Date/Time -- x Page 1
+
+
+1<<< -Test: FF's in Text
+2<<< -b -3 / -a -3 / ...
+3<<< >>>
+4<<< 123456789 123456789 1
+
+6<<< -Arangements: One Emp
+7<<< \f\f\n; text\f\n\ftex
+8<<< f\f\n; \f\n\f\n; >>>
+9<<< >>>
+10<<< >>>
+1<<< >>>
+2<<< >>>
+3<<< truncation before FF;
+14<<< 123456789 123456789
+
+
+-- Date/Time -- x Page 2
+
+
+
+
+
+-- Date/Time -- x Page 3
+
+
+15<<< xyzxyzxyz XYZXYZXYZ
+16<<< 123456789 xyzxyzxyz
+7<<< >>>
+8<<< >>>
+9<<< >>>
+20<<< >>>
+1<<< >>>
+
+
+4<<< >>>
+5<<< >>>
+6<<< >>>
+27<<< truncation before FF
+28<<< trunc
+
+
+-- Date/Time -- x Page 4
+
+
+
+
+
+-- Date/Time -- x Page 5
+
+
+29<<<xyzxyzxyz XYZXYZXYZ ab
+30<<< 123456789 xyzxyzxyz
+1<<< >>>
+2<<< abcdefghi >>>
+3<<< >>>
+4<<< >>>
+5<<< >>>
+6<<< >>>
+7<<< >>>
+8<<< >>>
+9<<< abcdefghi >>>
+40<<< 123456789 >>>
+41<<< XYZXYZXYZ abcabcab
+42<<< 123456789 abcdefghi
+
+
+-- Date/Time -- x Page 6
+
+
+
+
+
+-- Date/Time -- x Page 7
+
+
+
+
+
+-- Date/Time -- x Page 8
+
+
+43<<< xyzxyzxyz XYZXYZXYZ
+44<<< 123456789 xyzxyzxyz
+5<<< >>>
+6<<< >>>
+7<<< >>>
+8<<< >>>
+9<<< >>>
+50<<< >>>
+1<<< >>>
+2<<< >>>
+3<<< >>>
+4<<< >>>
+55<<< XYZXYZXYZ abcabcab
+56<<< 123456789 abcdefghi
+
+
+-- Date/Time -- x Page 9
+
+
+57<<< xyzxyzxyz XYZXYZXYZ
+58<<< 123456789 xyzxyzxyz
+9<<< >>>
+60<<< 123456789 >>>
+ \ No newline at end of file
diff --git a/tests/pr/W28l24f-ll b/tests/pr/W28l24f-ll
new file mode 100644
index 0000000..5731fd0
--- /dev/null
+++ b/tests/pr/W28l24f-ll
@@ -0,0 +1,110 @@
+
+
+-- Date/Time -- x Page 1
+
+
+1<<< -Test: FF's in Text
+2<<< -b -3 / -a -3 / ... >
+3<<< >>>
+4<<< 123456789 123456789 12
+
+6<<< -Arangements: One Empt
+7<<< \f\f\n; text\f\n\ftext
+8<<< f\f\n; \f\n\f\n; >>>
+9<<< >>>
+10<<< >>>
+1<<< >>>
+2<<< >>>
+3<<< truncation before FF;
+14<<< 123456789 123456789 1
+
+
+-- Date/Time -- x Page 2
+
+
+
+
+
+-- Date/Time -- x Page 3
+
+
+15<<< xyzxyzxyz XYZXYZXYZ a
+16<<< 123456789 xyzxyzxyz X
+7<<< >>>
+8<<< >>>
+9<<< >>>
+20<<< >>>
+1<<< >>>
+
+
+4<<< >>>
+5<<< >>>
+6<<< >>>
+27<<< truncation before FF;
+28<<< trunc
+
+
+-- Date/Time -- x Page 4
+
+
+
+
+
+-- Date/Time -- x Page 5
+
+
+29<<<xyzxyzxyz XYZXYZXYZ abc
+30<<< 123456789 xyzxyzxyz X
+1<<< >>>
+2<<< abcdefghi >>>
+3<<< >>>
+4<<< >>>
+5<<< >>>
+6<<< >>>
+7<<< >>>
+8<<< >>>
+9<<< abcdefghi >>>
+40<<< 123456789 >>>
+41<<< XYZXYZXYZ abcabcab
+42<<< 123456789 abcdefghi A
+
+
+-- Date/Time -- x Page 6
+
+
+
+
+
+-- Date/Time -- x Page 7
+
+
+
+
+
+-- Date/Time -- x Page 8
+
+
+43<<< xyzxyzxyz XYZXYZXYZ a
+44<<< 123456789 xyzxyzxyz X
+5<<< >>>
+6<<< >>>
+7<<< >>>
+8<<< >>>
+9<<< >>>
+50<<< >>>
+1<<< >>>
+2<<< >>>
+3<<< >>>
+4<<< >>>
+55<<< XYZXYZXYZ abcabcab >
+56<<< 123456789 abcdefghi A
+
+
+-- Date/Time -- x Page 9
+
+
+57<<< xyzxyzxyz XYZXYZXYZ a
+58<<< 123456789 xyzxyzxyz X
+9<<< >>>
+60<<< 123456789 >>>
+ \ No newline at end of file
diff --git a/tests/pr/W35Ja3l24f-lm b/tests/pr/W35Ja3l24f-lm
new file mode 100644
index 0000000..138f4c8
--- /dev/null
+++ b/tests/pr/W35Ja3l24f-lm
@@ -0,0 +1,72 @@
+
+
+-- Date/Time -- x Page 1
+
+
+1<<< -Test: FF's in Text >>> 2<<< -b -3 / -a -3 / ... >>> 3<<< >>>
+4<<< 123456789 123456789 123456789 12345678 >>> 6<<< -Arangements: One Empty Page >>>
+7<<< \f\f\n; text\f\n\ftext; \f\ftext; >>> 8<<< f\f\n; \f\n\f\n; >>> 9<<< >>>
+10<<< >>> 1<<< >>> 2<<< >>>
+3<<< truncation before FF; r_r_o_l-test: >>> 14<<< 123456789 123456789 123456789 >>>
+
+
+-- Date/Time -- x Page 2
+
+
+
+
+
+-- Date/Time -- x Page 3
+
+
+15<<< xyzxyzxyz XYZXYZXYZ abcabcab >>> 16<<< 123456789 xyzxyzxyz XYZXYZXYZ >>> 7<<< >>>
+8<<< >>> 9<<< >>> 20<<< >>>
+1<<< >>>
+4<<< >>> 5<<< >>> 6<<< >>>
+27<<< truncation before FF; (r_l-test): >>> 28<<< trunc
+
+
+-- Date/Time -- x Page 4
+
+
+
+
+
+-- Date/Time -- x Page 5
+
+
+29<<<xyzxyzxyz XYZXYZXYZ abcabcab >>> 30<<< 123456789 xyzxyzxyz XYZXYZXYZ >>> 1<<< >>>
+2<<< abcdefghi >>> 3<<< >>> 4<<< >>>
+5<<< >>> 6<<< >>> 7<<< >>>
+8<<< >>> 9<<< abcdefghi >>> 40<<< 123456789 >>>
+41<<< XYZXYZXYZ abcabcab >>> 42<<< 123456789 abcdefghi ABCDEDFHI >>>
+
+
+-- Date/Time -- x Page 6
+
+
+
+
+
+-- Date/Time -- x Page 7
+
+
+
+
+
+-- Date/Time -- x Page 8
+
+
+43<<< xyzxyzxyz XYZXYZXYZ abcabcab >>> 44<<< 123456789 xyzxyzxyz XYZXYZXYZ >>> 5<<< >>>
+6<<< >>> 7<<< >>> 8<<< >>>
+9<<< >>> 50<<< >>> 1<<< >>>
+2<<< >>> 3<<< >>> 4<<< >>>
+55<<< XYZXYZXYZ abcabcab >>> 56<<< 123456789 abcdefghi ABCDEDFHI >>>
+
+
+-- Date/Time -- x Page 9
+
+
+57<<< xyzxyzxyz XYZXYZXYZ abcabcab >>> 58<<< 123456789 xyzxyzxyz XYZXYZXYZ >>> 9<<< >>>
+60<<< 123456789 >>>
+ \ No newline at end of file
diff --git a/tests/pr/W35Jb3l24f-lm b/tests/pr/W35Jb3l24f-lm
new file mode 100644
index 0000000..bd80436
--- /dev/null
+++ b/tests/pr/W35Jb3l24f-lm
@@ -0,0 +1,72 @@
+
+
+-- Date/Time -- x Page 1
+
+
+1<<< -Test: FF's in Text >>> 6<<< -Arangements: One Empty Page >>> 1<<< >>>
+2<<< -b -3 / -a -3 / ... >>> 7<<< \f\f\n; text\f\n\ftext; \f\ftext; >>> 2<<< >>>
+3<<< >>> 8<<< f\f\n; \f\n\f\n; >>> 3<<< truncation before FF; r_r_o_l-test: >>>
+4<<< 123456789 123456789 123456789 12345678 >>> 9<<< >>> 14<<< 123456789 123456789 123456789 >>>
+ 10<<< >>>
+
+
+-- Date/Time -- x Page 2
+
+
+
+
+
+-- Date/Time -- x Page 3
+
+
+15<<< xyzxyzxyz XYZXYZXYZ abcabcab >>> 20<<< >>> 5<<< >>>
+16<<< 123456789 xyzxyzxyz XYZXYZXYZ >>> 1<<< >>> 6<<< >>>
+7<<< >>> 27<<< truncation before FF; (r_l-test): >>>
+8<<< >>> 28<<< trunc
+9<<< >>> 4<<< >>>
+
+
+-- Date/Time -- x Page 4
+
+
+
+
+
+-- Date/Time -- x Page 5
+
+
+29<<<xyzxyzxyz XYZXYZXYZ abcabcab >>> 4<<< >>> 9<<< abcdefghi >>>
+30<<< 123456789 xyzxyzxyz XYZXYZXYZ >>> 5<<< >>> 40<<< 123456789 >>>
+1<<< >>> 6<<< >>> 41<<< XYZXYZXYZ abcabcab >>>
+2<<< abcdefghi >>> 7<<< >>> 42<<< 123456789 abcdefghi ABCDEDFHI >>>
+3<<< >>> 8<<< >>>
+
+
+-- Date/Time -- x Page 6
+
+
+
+
+
+-- Date/Time -- x Page 7
+
+
+
+
+
+-- Date/Time -- x Page 8
+
+
+43<<< xyzxyzxyz XYZXYZXYZ abcabcab >>> 8<<< >>> 3<<< >>>
+44<<< 123456789 xyzxyzxyz XYZXYZXYZ >>> 9<<< >>> 4<<< >>>
+5<<< >>> 50<<< >>> 55<<< XYZXYZXYZ abcabcab >>>
+6<<< >>> 1<<< >>> 56<<< 123456789 abcdefghi ABCDEDFHI >>>
+7<<< >>> 2<<< >>>
+
+
+-- Date/Time -- x Page 9
+
+
+57<<< xyzxyzxyz XYZXYZXYZ abcabcab >>> 9<<< >>> 60<<< 123456789 >>>
+58<<< 123456789 xyzxyzxyz XYZXYZXYZ >>>
+ \ No newline at end of file
diff --git a/tests/pr/W35Jml24f-lmlo b/tests/pr/W35Jml24f-lmlo
new file mode 100644
index 0000000..0097993
--- /dev/null
+++ b/tests/pr/W35Jml24f-lmlo
@@ -0,0 +1,136 @@
+
+
+-- Date/Time -- x Page 1
+
+
+1<<< -Test: FF's in Text >>> 1::: Test-INPUT: "Without FF set by Hand" :::
+2<<< -b -3 / -a -3 / ... >>> 2::: Options -b -3 [+2|+3] [-l 15|8] [-f] :::
+3<<< >>> 3::: Options -a -3 [+2|+3] [-l 15|8] [-f] :::
+4<<< 123456789 123456789 123456789 12345678 >>> 4::: Options [+2|+3] [-l 24|17] [-f] :::
+ 5::: :::
+6<<< -Arangements: One Empty Page >>> 6::: -------------------------------------------- :::
+7<<< \f\f\n; text\f\n\ftext; \f\ftext; >>> 7::: 789 123456789 123456789 123456789 123456789 123456789 123456789 1234567890 :::
+8<<< f\f\n; \f\n\f\n; >>> 8::: 3 Columns downwards, across, ...: :::
+9<<< >>> 9::: With columns use <= 5 text lines/page, :::
+10<<< >>> 10::: without -f e.g.: -l 15 = total lines/page, :::
+1<<< >>> 1::: with -f e.g. : -l 8 -f :::
+2<<< >>> 2::: :::
+3<<< truncation before FF; r_r_o_l-test: >>> 3::: line truncation before new page; r_r_o_l-test: :::
+14<<< 123456789 123456789 123456789 >>> 14::: 89 123456789 123456789 123456789 123456789 123456789 123456789 1234567890 :::
+
+
+-- Date/Time -- x Page 2
+
+
+ 15::: xyzxyzxyz XYZXYZXYZ abcabcab :::
+ 16::: 456789 123456789 xyzxyzxyz XYZXYZXYZ :::
+ 7::: 12345678 :::
+ 8::: 12345678 :::
+ 9::: 3456789 ab :::
+ 20::: DEFGHI 123 :::
+ 21::: 89 123456789 123456789 123456789 123456789 123456789 123456789 1234567890 :::
+ 2::: 12345678 :::
+ 3::: 12345678 :::
+ 4::: 12345678 :::
+ 5::: 12345678 :::
+ 6::: 12345678 :::
+ 27::: no truncation before nwe page; (r_l-test): :::
+ 28::: 89 123456789 123456789 123456789 123456789 123456789 123456789 1234567890 :::
+
+
+-- Date/Time -- x Page 3
+
+
+15<<< xyzxyzxyz XYZXYZXYZ abcabcab >>> 29::: xyzxyzxyz XYZXYZXYZ abcabcab :::
+16<<< 123456789 xyzxyzxyz XYZXYZXYZ >>> 30::: 456789 123456789 xyzxyzxyz XYZXYZXYZ :::
+7<<< >>> 1::: 12345678 :::
+8<<< >>> 2::: 3456789 abcdefghi :::
+9<<< >>> 3::: 12345678 :::
+20<<< >>> 4::: 12345678 :::
+1<<< >>> 35::: 89 123456789 123456789 123456789 123456789 123456789 123456789 1234567890 :::
+ 6::: 12345678 :::
+ 7::: 12345678 :::
+4<<< >>> 8::: 12345678 :::
+5<<< >>> 9::: 3456789 abcdefghi :::
+6<<< >>> 40::: DEFGHI 123456789 :::
+27<<< truncation before FF; (r_l-test): >>> 41::: yzxyzxyz XYZXYZXYZ abcabcab :::
+28<<< trunc 42::: 89 123456789 123456789 123456789 123456789 123456789 123456789 1234567890 :::
+
+
+-- Date/Time -- x Page 4
+
+
+ 43::: xyzxyzxyz XYZXYZXYZ abcabcab :::
+ 44::: 456789 123456789 xyzxyzxyz XYZXYZXYZ :::
+ 5::: 12345678 :::
+ 6::: 12345678 :::
+ 7::: 12345678 :::
+ 8::: 12345678 :::
+ 49::: 89 123456789 123456789 123456789 123456789 123456789 123456789 1234567890 :::
+ 50::: 12345678 :::
+ 1::: 12345678 :::
+ 2::: 12345678 :::
+ 3::: 12345678 :::
+ 4::: 12345678 :::
+ 55::: yzxyzxyz XYZXYZXYZ abcabcab :::
+ 56::: 89 123456789 123456789 123456789 123456789 123456789 123456789 1234567890 :::
+
+
+-- Date/Time -- x Page 5
+
+
+29<<<xyzxyzxyz XYZXYZXYZ abcabcab >>> 57::: xyzxyzxyz XYZXYZXYZ abcabcab :::
+30<<< 123456789 xyzxyzxyz XYZXYZXYZ >>> 58::: 456789 123456789 xyzxyzxyz XYZXYZXYZ :::
+1<<< >>> 9::: 12345678 :::
+2<<< abcdefghi >>> 60::: DEFGHI 123456789 :::
+3<<< >>> 1::: :::
+4<<< >>> 2::: :::
+5<<< >>> 3::: ------- EOF -------- EOF -------- EOF ------- EOF ------- EOF ------- EOF :::
+6<<< >>>
+7<<< >>>
+8<<< >>>
+9<<< abcdefghi >>>
+40<<< 123456789 >>>
+41<<< XYZXYZXYZ abcabcab >>>
+42<<< 123456789 abcdefghi ABCDEDFHI >>>
+
+
+-- Date/Time -- x Page 6
+
+
+
+
+
+-- Date/Time -- x Page 7
+
+
+
+
+
+-- Date/Time -- x Page 8
+
+
+43<<< xyzxyzxyz XYZXYZXYZ abcabcab >>>
+44<<< 123456789 xyzxyzxyz XYZXYZXYZ >>>
+5<<< >>>
+6<<< >>>
+7<<< >>>
+8<<< >>>
+9<<< >>>
+50<<< >>>
+1<<< >>>
+2<<< >>>
+3<<< >>>
+4<<< >>>
+55<<< XYZXYZXYZ abcabcab >>>
+56<<< 123456789 abcdefghi ABCDEDFHI >>>
+
+
+-- Date/Time -- x Page 9
+
+
+57<<< xyzxyzxyz XYZXYZXYZ abcabcab >>>
+58<<< 123456789 xyzxyzxyz XYZXYZXYZ >>>
+9<<< >>>
+60<<< 123456789 >>>
+ \ No newline at end of file
diff --git a/tests/pr/W35a3l24f-lm b/tests/pr/W35a3l24f-lm
new file mode 100644
index 0000000..1a228df
--- /dev/null
+++ b/tests/pr/W35a3l24f-lm
@@ -0,0 +1,72 @@
+
+
+-- Date/Time -- x Page 1
+
+
+1<<< -Test 2<<< -b -3 3<<< >>>
+4<<< 12345 6<<< -Aran
+7<<< \f\f\ 8<<< f\f\n 9<<< >>>
+10<<< >>> 1<<< >>> 2<<< >>>
+3<<< trunc 14<<< 1234
+
+
+-- Date/Time -- x Page 2
+
+
+
+
+
+-- Date/Time -- x Page 3
+
+
+15<<< xyzx 16<<< 1234 7<<< >>>
+8<<< >>> 9<<< >>> 20<<< >>>
+1<<< >>>
+4<<< >>> 5<<< >>> 6<<< >>>
+27<<< trun 28<<< trun
+
+
+-- Date/Time -- x Page 4
+
+
+
+
+
+-- Date/Time -- x Page 5
+
+
+29<<<xyzxyz 30<<< 1234 1<<< >>>
+2<<< abcde 3<<< >>> 4<<< >>>
+5<<< >>> 6<<< >>> 7<<< >>>
+8<<< >>> 9<<< abcde 40<<< 1234
+41<<< XYZX 42<<< 1234
+
+
+-- Date/Time -- x Page 6
+
+
+
+
+
+-- Date/Time -- x Page 7
+
+
+
+
+
+-- Date/Time -- x Page 8
+
+
+43<<< xyzx 44<<< 1234 5<<< >>>
+6<<< >>> 7<<< >>> 8<<< >>>
+9<<< >>> 50<<< >>> 1<<< >>>
+2<<< >>> 3<<< >>> 4<<< >>>
+55<<< XYZX 56<<< 1234
+
+
+-- Date/Time -- x Page 9
+
+
+57<<< xyzx 58<<< 1234 9<<< >>>
+60<<< 1234
+ \ No newline at end of file
diff --git a/tests/pr/W35b3l24f-lm b/tests/pr/W35b3l24f-lm
new file mode 100644
index 0000000..3ec5d3f
--- /dev/null
+++ b/tests/pr/W35b3l24f-lm
@@ -0,0 +1,72 @@
+
+
+-- Date/Time -- x Page 1
+
+
+1<<< -Test 6<<< -Aran 1<<< >>>
+2<<< -b -3 7<<< \f\f\ 2<<< >>>
+3<<< >>> 8<<< f\f\n 3<<< trunc
+4<<< 12345 9<<< >>> 14<<< 1234
+ 10<<< >>>
+
+
+-- Date/Time -- x Page 2
+
+
+
+
+
+-- Date/Time -- x Page 3
+
+
+15<<< xyzx 20<<< >>> 5<<< >>>
+16<<< 1234 1<<< >>> 6<<< >>>
+7<<< >>> 27<<< trun
+8<<< >>> 28<<< trun
+9<<< >>> 4<<< >>>
+
+
+-- Date/Time -- x Page 4
+
+
+
+
+
+-- Date/Time -- x Page 5
+
+
+29<<<xyzxyz 4<<< >>> 9<<< abcde
+30<<< 1234 5<<< >>> 40<<< 1234
+1<<< >>> 6<<< >>> 41<<< XYZX
+2<<< abcde 7<<< >>> 42<<< 1234
+3<<< >>> 8<<< >>>
+
+
+-- Date/Time -- x Page 6
+
+
+
+
+
+-- Date/Time -- x Page 7
+
+
+
+
+
+-- Date/Time -- x Page 8
+
+
+43<<< xyzx 8<<< >>> 3<<< >>>
+44<<< 1234 9<<< >>> 4<<< >>>
+5<<< >>> 50<<< >>> 55<<< XYZX
+6<<< >>> 1<<< >>> 56<<< 1234
+7<<< >>> 2<<< >>>
+
+
+-- Date/Time -- x Page 9
+
+
+57<<< xyzx 9<<< >>> 60<<< 1234
+58<<< 1234
+ \ No newline at end of file
diff --git a/tests/pr/W35ml24f-lm-lo b/tests/pr/W35ml24f-lm-lo
new file mode 100644
index 0000000..8b4e701
--- /dev/null
+++ b/tests/pr/W35ml24f-lm-lo
@@ -0,0 +1,136 @@
+
+
+-- Date/Time -- x Page 1
+
+
+1<<< -Test: FF's 1::: Test-INPUT:
+2<<< -b -3 / -a 2::: Options -b
+3<<< >>> 3::: Options -a
+4<<< 123456789 1 4::: Options
+ 5::: :::
+6<<< -Arangement 6::: -----------
+7<<< \f\f\n; tex 7::: 789 1234567
+8<<< f\f\n; \f\n 8::: 3 Columns d
+9<<< >>> 9::: With column
+10<<< >>> 10::: without -f
+1<<< >>> 1::: with -f e.g
+2<<< >>> 2::: :::
+3<<< truncation 3::: line trunca
+14<<< 123456789 14::: 89 1234567
+
+
+-- Date/Time -- x Page 2
+
+
+ 15::: xyzxyzxyz
+ 16::: 456789 123
+ 7::: 12345678 :
+ 8::: 12345678 :
+ 9::: 3456789 ab
+ 20::: DEFGHI 123
+ 21::: 89 1234567
+ 2::: 12345678 :
+ 3::: 12345678 :
+ 4::: 12345678 :
+ 5::: 12345678 :
+ 6::: 12345678 :
+ 27::: no truncat
+ 28::: 89 1234567
+
+
+-- Date/Time -- x Page 3
+
+
+15<<< xyzxyzxyz 29::: xyzxyzxyz
+16<<< 123456789 30::: 456789 123
+7<<< >>> 1::: 12345678 :
+8<<< >>> 2::: 3456789 abc
+9<<< >>> 3::: 12345678 :
+20<<< >>> 4::: 12345678 :
+1<<< >>> 35::: 89 1234567
+ 6::: 12345678 :
+ 7::: 12345678 :
+4<<< >>> 8::: 12345678 :
+5<<< >>> 9::: 3456789 abc
+6<<< >>> 40::: DEFGHI 123
+27<<< truncation 41::: yzxyzxyz X
+28<<< trunc 42::: 89 1234567
+
+
+-- Date/Time -- x Page 4
+
+
+ 43::: xyzxyzxyz
+ 44::: 456789 123
+ 5::: 12345678 :
+ 6::: 12345678 :
+ 7::: 12345678 :
+ 8::: 12345678 :
+ 49::: 89 1234567
+ 50::: 12345678
+ 1::: 12345678 :
+ 2::: 12345678 :
+ 3::: 12345678 :
+ 4::: 12345678 :
+ 55::: yzxyzxyz X
+ 56::: 89 1234567
+
+
+-- Date/Time -- x Page 5
+
+
+29<<<xyzxyzxyz XY 57::: xyzxyzxyz
+30<<< 123456789 58::: 456789 123
+1<<< >>> 9::: 12345678 :
+2<<< abcdefghi 60::: DEFGHI 123
+3<<< >>> 1::: :::
+4<<< >>> 2::: :::
+5<<< >>> 3::: ------- EOF
+6<<< >>>
+7<<< >>>
+8<<< >>>
+9<<< abcdefghi
+40<<< 123456789
+41<<< XYZXYZXYZ
+42<<< 123456789
+
+
+-- Date/Time -- x Page 6
+
+
+
+
+
+-- Date/Time -- x Page 7
+
+
+
+
+
+-- Date/Time -- x Page 8
+
+
+43<<< xyzxyzxyz
+44<<< 123456789
+5<<< >>>
+6<<< >>>
+7<<< >>>
+8<<< >>>
+9<<< >>>
+50<<< >>>
+1<<< >>>
+2<<< >>>
+3<<< >>>
+4<<< >>>
+55<<< XYZXYZXYZ
+56<<< 123456789
+
+
+-- Date/Time -- x Page 9
+
+
+57<<< xyzxyzxyz
+58<<< 123456789
+9<<< >>>
+60<<< 123456789
+ \ No newline at end of file
diff --git a/tests/pr/W72Jl24f-ll b/tests/pr/W72Jl24f-ll
new file mode 100644
index 0000000..109cbaa
--- /dev/null
+++ b/tests/pr/W72Jl24f-ll
@@ -0,0 +1,110 @@
+
+
+-- Date/Time -- x Page 1
+
+
+1<<< -Test: FF's in Text >>>
+2<<< -b -3 / -a -3 / ... >>>
+3<<< >>>
+4<<< 123456789 123456789 123456789 123456789 123456789 123456789 123456789 >>>
+
+6<<< -Arangements: One Empty Page >>>
+7<<< \f\f\n; text\f\n\ftext; \f\ftext; >>>
+8<<< f\f\n; \f\n\f\n; >>>
+9<<< >>>
+10<<< >>>
+1<<< >>>
+2<<< >>>
+3<<< truncation before FF; r_r_o_l-test: >>>
+14<<< 123456789 123456789 123456789 >>>
+
+
+-- Date/Time -- x Page 2
+
+
+
+
+
+-- Date/Time -- x Page 3
+
+
+15<<< xyzxyzxyz XYZXYZXYZ abcabcab >>>
+16<<< 123456789 xyzxyzxyz XYZXYZXYZ >>>
+7<<< >>>
+8<<< >>>
+9<<< >>>
+20<<< >>>
+1<<< >>>
+
+
+4<<< >>>
+5<<< >>>
+6<<< >>>
+27<<< truncation before FF; (r_l-test): >>>
+28<<< trunc
+
+
+-- Date/Time -- x Page 4
+
+
+
+
+
+-- Date/Time -- x Page 5
+
+
+29<<<xyzxyzxyz XYZXYZXYZ abcabcab >>>
+30<<< 123456789 xyzxyzxyz XYZXYZXYZ >>>
+1<<< >>>
+2<<< abcdefghi >>>
+3<<< >>>
+4<<< >>>
+5<<< >>>
+6<<< >>>
+7<<< >>>
+8<<< >>>
+9<<< abcdefghi >>>
+40<<< 123456789 >>>
+41<<< XYZXYZXYZ abcabcab >>>
+42<<< 123456789 abcdefghi ABCDEDFHI >>>
+
+
+-- Date/Time -- x Page 6
+
+
+
+
+
+-- Date/Time -- x Page 7
+
+
+
+
+
+-- Date/Time -- x Page 8
+
+
+43<<< xyzxyzxyz XYZXYZXYZ abcabcab >>>
+44<<< 123456789 xyzxyzxyz XYZXYZXYZ >>>
+5<<< >>>
+6<<< >>>
+7<<< >>>
+8<<< >>>
+9<<< >>>
+50<<< >>>
+1<<< >>>
+2<<< >>>
+3<<< >>>
+4<<< >>>
+55<<< XYZXYZXYZ abcabcab >>>
+56<<< 123456789 abcdefghi ABCDEDFHI >>>
+
+
+-- Date/Time -- x Page 9
+
+
+57<<< xyzxyzxyz XYZXYZXYZ abcabcab >>>
+58<<< 123456789 xyzxyzxyz XYZXYZXYZ >>>
+9<<< >>>
+60<<< 123456789 >>>
+ \ No newline at end of file
diff --git a/tests/pr/a2l15-FF b/tests/pr/a2l15-FF
new file mode 100644
index 0000000..d3bc77f
--- /dev/null
+++ b/tests/pr/a2l15-FF
@@ -0,0 +1,195 @@
+
+
+-- Date/Time -- x Page 1
+
+
+1 FF-Test: FF's in Text 2 Options -b -3 / -a -3 / ...
+3 ------------------------------- 4 3456789 123456789 123456789 12345
+5 3 Columns downwards ..., <= 5 l 6 FF-Arangements: One Empty Page
+7 text\f\f\n; text\f\n\ftext; \f\ 8 \f\f\n; \f\n\f\n;
+9 10 zzzzzzzzzzzzzzzzzzzzzzzzzz12345
+
+
+
+
+
+
+
+-- Date/Time -- x Page 2
+
+
+1 2
+3 line truncation before FF; r_r_o_ 14 456789 123456789 123456789 12345
+
+
+
+
+
+
+
+
+
+
+-- Date/Time -- x Page 3
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+-- Date/Time -- x Page 4
+
+
+15 xyzxyzxyz XYZXYZXYZ abcabcab 16 456789 123456789 xyzxyzxyz XYZXY
+7 8
+9 3456789 ab 20 DEFGHI 123
+1 2
+3 4
+
+
+
+
+
+
+
+-- Date/Time -- x Page 5
+
+
+5 6
+27 no truncation before FF; (r_l-te 28 no trunc
+
+
+
+
+
+
+
+
+
+
+-- Date/Time -- x Page 6
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+-- Date/Time -- x Page 7
+
+
+29 xyzxyzxyz XYZXYZXYZ abcabcab 30 456789 123456789 xyzxyzxyz XYZXY
+1 2 3456789 abcdefghi
+3 4
+5 6
+7 8
+
+
+
+
+
+
+
+-- Date/Time -- x Page 8
+
+
+9 3456789 abcdefghi 40 DEFGHI 123456789
+41 yzxyzxyz XYZXYZXYZ abcabcab 42 456789 123456789 abcdefghi ABCDE
+
+
+
+
+
+
+
+
+
+
+-- Date/Time -- x Page 9
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+-- Date/Time -- x Page 10
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+-- Date/Time -- x Page 11
+
+
+43 xyzxyzxyz XYZXYZXYZ abcabcab 44 456789 123456789 xyzxyzxyz XYZXY
+5 6
+7 8
+9 50
+1 2
+
+
+
+
+
+
+
+-- Date/Time -- x Page 12
+
+
+3 4
+55 yzxyzxyz XYZXYZXYZ abcabcab 56 456789 123456789 abcdefghi ABCDE
+
+
+
+
+
+
+
+
+
+
+-- Date/Time -- x Page 13
+
+
+57 xyzxyzxyz XYZXYZXYZ abcabcab 58 456789 123456789 xyzxyzxyz XYZXY
+9 60 DEFGHI 123456789
+
+
+
+
+
+
+
+
diff --git a/tests/pr/a2l17-FF b/tests/pr/a2l17-FF
new file mode 100644
index 0000000..c6700e6
--- /dev/null
+++ b/tests/pr/a2l17-FF
@@ -0,0 +1,153 @@
+
+
+-- Date/Time -- x Page 1
+
+
+1 FF-Test: FF's in Text 2 Options -b -3 / -a -3 / ...
+3 ------------------------------- 4 3456789 123456789 123456789 12345
+5 3 Columns downwards ..., <= 5 l 6 FF-Arangements: One Empty Page
+7 text\f\f\n; text\f\n\ftext; \f\ 8 \f\f\n; \f\n\f\n;
+9 10 zzzzzzzzzzzzzzzzzzzzzzzzzz12345
+1 2
+3 line truncation before FF; r_r_o_ 14 456789 123456789 123456789 12345
+
+
+
+
+
+
+
+-- Date/Time -- x Page 2
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+-- Date/Time -- x Page 3
+
+
+15 xyzxyzxyz XYZXYZXYZ abcabcab 16 456789 123456789 xyzxyzxyz XYZXY
+7 8
+9 3456789 ab 20 DEFGHI 123
+1 2
+3 4
+5 6
+27 no truncation before FF; (r_l-te 28 no trunc
+
+
+
+
+
+
+
+-- Date/Time -- x Page 4
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+-- Date/Time -- x Page 5
+
+
+29 xyzxyzxyz XYZXYZXYZ abcabcab 30 456789 123456789 xyzxyzxyz XYZXY
+1 2 3456789 abcdefghi
+3 4
+5 6
+7 8
+9 3456789 abcdefghi 40 DEFGHI 123456789
+41 yzxyzxyz XYZXYZXYZ abcabcab 42 456789 123456789 abcdefghi ABCDE
+
+
+
+
+
+
+
+-- Date/Time -- x Page 6
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+-- Date/Time -- x Page 7
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+-- Date/Time -- x Page 8
+
+
+43 xyzxyzxyz XYZXYZXYZ abcabcab 44 456789 123456789 xyzxyzxyz XYZXY
+5 6
+7 8
+9 50
+1 2
+3 4
+55 yzxyzxyz XYZXYZXYZ abcabcab 56 456789 123456789 abcdefghi ABCDE
+
+
+
+
+
+
+
+-- Date/Time -- x Page 9
+
+
+57 xyzxyzxyz XYZXYZXYZ abcabcab 58 456789 123456789 xyzxyzxyz XYZXY
+9 60 DEFGHI 123456789
+
+
+
+
+
+
+
+
+
+
diff --git a/tests/pr/a3-0F b/tests/pr/a3-0F
new file mode 100644
index 0000000..0cb5573
--- /dev/null
+++ b/tests/pr/a3-0F
@@ -0,0 +1,330 @@
+
+
+-- Date/Time -- x Page 1
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+-- Date/Time -- x Page 2
+
+
+1 FF-Test: FF's at St 2 Options -b -3 / -a 3 -------------------
+4 3456789 123456789 123 5 3 Columns downwards 6 FF-Arangements: Emp
+7 \ftext; \f\ntext; 8 \f\ftext; \f\f\ntex 9 3456789 123456789 123
+10 zzzzzzzzzzzzzzzzzzz 1 2
+3 line truncation befor 14 456789 123456789 123
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+-- Date/Time -- x Page 3
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+-- Date/Time -- x Page 4
+
+
+15 xyzxyzxyz XYZXYZXYZ 16 456789 123456789 xyz 7
+8 9 3456789 ab 20 DEFGHI 123
+1 2 3
+4 5 6
+27 no truncation before 28 no trunc
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+-- Date/Time -- x Page 5
+
+
+29 xyzxyzxyz XYZXYZXYZ 30 456789 123456789 xyz 1
+2 3456789 abcdefghi 3
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/tests/pr/a3f-0F b/tests/pr/a3f-0F
new file mode 100644
index 0000000..5a11e10
--- /dev/null
+++ b/tests/pr/a3f-0F
@@ -0,0 +1,40 @@
+
+
+-- Date/Time -- x Page 1
+
+
+
+
+
+-- Date/Time -- x Page 2
+
+
+1 FF-Test: FF's at St 2 Options -b -3 / -a 3 -------------------
+4 3456789 123456789 123 5 3 Columns downwards 6 FF-Arangements: Emp
+7 \ftext; \f\ntext; 8 \f\ftext; \f\f\ntex 9 3456789 123456789 123
+10 zzzzzzzzzzzzzzzzzzz 1 2
+3 line truncation befor 14 456789 123456789 123
+
+
+-- Date/Time -- x Page 3
+
+
+
+
+
+-- Date/Time -- x Page 4
+
+
+15 xyzxyzxyz XYZXYZXYZ 16 456789 123456789 xyz 7
+8 9 3456789 ab 20 DEFGHI 123
+1 2 3
+4 5 6
+27 no truncation before 28 no trunc
+
+
+-- Date/Time -- x Page 5
+
+
+29 xyzxyzxyz XYZXYZXYZ 30 456789 123456789 xyz 1
+2 3456789 abcdefghi 3
+ \ No newline at end of file
diff --git a/tests/pr/a3f-0FF b/tests/pr/a3f-0FF
new file mode 100644
index 0000000..4f4ed40
--- /dev/null
+++ b/tests/pr/a3f-0FF
@@ -0,0 +1,46 @@
+
+
+-- Date/Time -- x Page 1
+
+
+
+
+
+-- Date/Time -- x Page 2
+
+
+
+
+
+-- Date/Time -- x Page 3
+
+
+1 FF-Test: FF's at St 2 Options -b -3 / -a 3 -------------------
+4 3456789 123456789 123 5 3 Columns downwards 6 FF-Arangements: Emp
+7 \ftext; \f\ntext; 8 \f\ftext; \f\f\ntex 9 3456789 123456789 123
+10 zzzzzzzzzzzzzzzzzzz 1 2
+3 line truncation befor 14 456789 123456789 123
+
+
+-- Date/Time -- x Page 4
+
+
+
+
+
+-- Date/Time -- x Page 5
+
+
+15 xyzxyzxyz XYZXYZXYZ 16 456789 123456789 xyz 7
+8 9 3456789 ab 20 DEFGHI 123
+1 2 3
+4 5 6
+27 no truncation before 28 no trunc
+
+
+-- Date/Time -- x Page 6
+
+
+29 xyzxyzxyz XYZXYZXYZ 30 456789 123456789 xyz 1
+2 3456789 abcdefghi 3
+ \ No newline at end of file
diff --git a/tests/pr/a3f-FF b/tests/pr/a3f-FF
new file mode 100644
index 0000000..ee7325f
--- /dev/null
+++ b/tests/pr/a3f-FF
@@ -0,0 +1,72 @@
+
+
+-- Date/Time -- x Page 1
+
+
+1 FF-Test: FF's in Te 2 Options -b -3 / -a 3 -------------------
+4 3456789 123456789 123 5 3 Columns downwards 6 FF-Arangements: One
+7 text\f\f\n; text\f\ 8 \f\f\n; \f\n\f\n; 9
+10 zzzzzzzzzzzzzzzzzzz 1 2
+3 line truncation befor 14 456789 123456789 123
+
+
+-- Date/Time -- x Page 2
+
+
+
+
+
+-- Date/Time -- x Page 3
+
+
+15 xyzxyzxyz XYZXYZXYZ 16 456789 123456789 xyz 7
+8 9 3456789 ab 20 DEFGHI 123
+1 2 3
+4 5 6
+27 no truncation before 28 no trunc
+
+
+-- Date/Time -- x Page 4
+
+
+
+
+
+-- Date/Time -- x Page 5
+
+
+29 xyzxyzxyz XYZXYZXYZ 30 456789 123456789 xyz 1
+2 3456789 abcdefghi 3 4
+5 6 7
+8 9 3456789 abcdefghi 40 DEFGHI 123456789
+41 yzxyzxyz XYZXYZXYZ a 42 456789 123456789 abc
+
+
+-- Date/Time -- x Page 6
+
+
+
+
+
+-- Date/Time -- x Page 7
+
+
+
+
+
+-- Date/Time -- x Page 8
+
+
+43 xyzxyzxyz XYZXYZXYZ 44 456789 123456789 xyz 5
+6 7 8
+9 50 1
+2 3 4
+55 yzxyzxyz XYZXYZXYZ a 56 456789 123456789 abc
+
+
+-- Date/Time -- x Page 9
+
+
+57 xyzxyzxyz XYZXYZXYZ 58 456789 123456789 xyz 9
+60 DEFGHI 123456789
+ \ No newline at end of file
diff --git a/tests/pr/a3l15-t b/tests/pr/a3l15-t
new file mode 100644
index 0000000..7bd4b52
--- /dev/null
+++ b/tests/pr/a3l15-t
@@ -0,0 +1,75 @@
+
+
+-- Date/Time -- x Page 1
+
+
+1 Test-INPUT: "Withou 2 Options -b -3 [+2|+ 3 Options -a -3 [+2|+
+4 Options [+2|+ 5 6 -------------------
+7 3456789 123456789 123 8 3 Columns downwards 9 With columns use <
+10 without -f e.g.: - 1 with -f e.g. : - 2
+3 line truncation befor 14 456789 123456789 123 15 xyzxyzxyz XYZXYZXYZ
+
+
+
+
+
+
+
+-- Date/Time -- x Page 2
+
+
+16 456789 123456789 xyz 7 8
+9 3456789 ab 20 DEFGHI 123 1
+2 3 4
+5 6 27 no truncation before
+28 no trunc 29 xyzxyzxyz XYZXYZXYZ 30 456789 123456789 xyz
+
+
+
+
+
+
+
+-- Date/Time -- x Page 3
+
+
+1 2 3456789 abcdefghi 3
+4 5 6
+7 8 9 3456789 abcdefghi
+40 DEFGHI 123456789 41 yzxyzxyz XYZXYZXYZ a 42 456789 123456789 abc
+43 xyzxyzxyz XYZXYZXYZ 44 456789 123456789 xyz 5
+
+
+
+
+
+
+
+-- Date/Time -- x Page 4
+
+
+6 7 8
+9 50 1
+2 3 4
+55 yzxyzxyz XYZXYZXYZ a 56 456789 123456789 abc 57 xyzxyzxyz XYZXYZXYZ
+58 456789 123456789 xyz 9 60 DEFGHI 123456789
+
+
+
+
+
+
+
+-- Date/Time -- x Page 5
+
+
+1 2 3 ------- EOF --------
+
+
+
+
+
+
+
+
+
diff --git a/tests/pr/a3l15f-t b/tests/pr/a3l15f-t
new file mode 100644
index 0000000..21c210a
--- /dev/null
+++ b/tests/pr/a3l15f-t
@@ -0,0 +1,47 @@
+
+
+-- Date/Time -- x Page 1
+
+
+1 Test-INPUT: "Withou 2 Options -b -3 [+2|+ 3 Options -a -3 [+2|+
+4 Options [+2|+ 5 6 -------------------
+7 3456789 123456789 123 8 3 Columns downwards 9 With columns use <
+10 without -f e.g.: - 1 with -f e.g. : - 2
+3 line truncation befor 14 456789 123456789 123 15 xyzxyzxyz XYZXYZXYZ
+
+
+-- Date/Time -- x Page 2
+
+
+16 456789 123456789 xyz 7 8
+9 3456789 ab 20 DEFGHI 123 1
+2 3 4
+5 6 27 no truncation before
+28 no trunc 29 xyzxyzxyz XYZXYZXYZ 30 456789 123456789 xyz
+
+
+-- Date/Time -- x Page 3
+
+
+1 2 3456789 abcdefghi 3
+4 5 6
+7 8 9 3456789 abcdefghi
+40 DEFGHI 123456789 41 yzxyzxyz XYZXYZXYZ a 42 456789 123456789 abc
+43 xyzxyzxyz XYZXYZXYZ 44 456789 123456789 xyz 5
+
+
+-- Date/Time -- x Page 4
+
+
+6 7 8
+9 50 1
+2 3 4
+55 yzxyzxyz XYZXYZXYZ a 56 456789 123456789 abc 57 xyzxyzxyz XYZXYZXYZ
+58 456789 123456789 xyz 9 60 DEFGHI 123456789
+
+
+-- Date/Time -- x Page 5
+
+
+1 2 3 ------- EOF --------
+ \ No newline at end of file
diff --git a/tests/pr/a3l24f-lm b/tests/pr/a3l24f-lm
new file mode 100644
index 0000000..0fdbfa3
--- /dev/null
+++ b/tests/pr/a3l24f-lm
@@ -0,0 +1,72 @@
+
+
+-- Date/Time -- x Page 1
+
+
+1<<< -Test: FF's in Te 2<<< -b -3 / -a -3 / . 3<<< >>>
+4<<< 123456789 1234567 6<<< -Arangements: One
+7<<< \f\f\n; text\f\n\ 8<<< f\f\n; \f\n\f\n; 9<<< >>>
+10<<< >>> 1<<< >>> 2<<< >>>
+3<<< truncation before 14<<< 123456789 123456
+
+
+-- Date/Time -- x Page 2
+
+
+
+
+
+-- Date/Time -- x Page 3
+
+
+15<<< xyzxyzxyz XYZXYZ 16<<< 123456789 xyzxyz 7<<< >>>
+8<<< >>> 9<<< >>> 20<<< >>>
+1<<< >>>
+4<<< >>> 5<<< >>> 6<<< >>>
+27<<< truncation befor 28<<< trunc
+
+
+-- Date/Time -- x Page 4
+
+
+
+
+
+-- Date/Time -- x Page 5
+
+
+29<<<xyzxyzxyz XYZXYZXY 30<<< 123456789 xyzxyz 1<<< >>>
+2<<< abcdefghi >>> 3<<< >>> 4<<< >>>
+5<<< >>> 6<<< >>> 7<<< >>>
+8<<< >>> 9<<< abcdefghi >>> 40<<< 123456789 >>>
+41<<< XYZXYZXYZ abcabc 42<<< 123456789 abcdef
+
+
+-- Date/Time -- x Page 6
+
+
+
+
+
+-- Date/Time -- x Page 7
+
+
+
+
+
+-- Date/Time -- x Page 8
+
+
+43<<< xyzxyzxyz XYZXYZ 44<<< 123456789 xyzxyz 5<<< >>>
+6<<< >>> 7<<< >>> 8<<< >>>
+9<<< >>> 50<<< >>> 1<<< >>>
+2<<< >>> 3<<< >>> 4<<< >>>
+55<<< XYZXYZXYZ abcabc 56<<< 123456789 abcdef
+
+
+-- Date/Time -- x Page 9
+
+
+57<<< xyzxyzxyz XYZXYZ 58<<< 123456789 xyzxyz 9<<< >>>
+60<<< 123456789 >>>
+ \ No newline at end of file
diff --git a/tests/pr/b2l15-FF b/tests/pr/b2l15-FF
new file mode 100644
index 0000000..c3008c1
--- /dev/null
+++ b/tests/pr/b2l15-FF
@@ -0,0 +1,195 @@
+
+
+-- Date/Time -- x Page 1
+
+
+1 FF-Test: FF's in Text 6 FF-Arangements: One Empty Page
+2 Options -b -3 / -a -3 / ... 7 text\f\f\n; text\f\n\ftext; \f\
+3 ------------------------------- 8 \f\f\n; \f\n\f\n;
+4 3456789 123456789 123456789 12345 9
+5 3 Columns downwards ..., <= 5 l 10 zzzzzzzzzzzzzzzzzzzzzzzzzz12345
+
+
+
+
+
+
+
+-- Date/Time -- x Page 2
+
+
+1 3 line truncation before FF; r_r_o_
+2 14 456789 123456789 123456789 12345
+
+
+
+
+
+
+
+
+
+
+-- Date/Time -- x Page 3
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+-- Date/Time -- x Page 4
+
+
+15 xyzxyzxyz XYZXYZXYZ abcabcab 20 DEFGHI 123
+16 456789 123456789 xyzxyzxyz XYZXY 1
+7 2
+8 3
+9 3456789 ab 4
+
+
+
+
+
+
+
+-- Date/Time -- x Page 5
+
+
+5 27 no truncation before FF; (r_l-te
+6 28 no trunc
+
+
+
+
+
+
+
+
+
+
+-- Date/Time -- x Page 6
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+-- Date/Time -- x Page 7
+
+
+29 xyzxyzxyz XYZXYZXYZ abcabcab 4
+30 456789 123456789 xyzxyzxyz XYZXY 5
+1 6
+2 3456789 abcdefghi 7
+3 8
+
+
+
+
+
+
+
+-- Date/Time -- x Page 8
+
+
+9 3456789 abcdefghi 41 yzxyzxyz XYZXYZXYZ abcabcab
+40 DEFGHI 123456789 42 456789 123456789 abcdefghi ABCDE
+
+
+
+
+
+
+
+
+
+
+-- Date/Time -- x Page 9
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+-- Date/Time -- x Page 10
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+-- Date/Time -- x Page 11
+
+
+43 xyzxyzxyz XYZXYZXYZ abcabcab 8
+44 456789 123456789 xyzxyzxyz XYZXY 9
+5 50
+6 1
+7 2
+
+
+
+
+
+
+
+-- Date/Time -- x Page 12
+
+
+3 55 yzxyzxyz XYZXYZXYZ abcabcab
+4 56 456789 123456789 abcdefghi ABCDE
+
+
+
+
+
+
+
+
+
+
+-- Date/Time -- x Page 13
+
+
+57 xyzxyzxyz XYZXYZXYZ abcabcab 9
+58 456789 123456789 xyzxyzxyz XYZXY 60 DEFGHI 123456789
+
+
+
+
+
+
+
+
diff --git a/tests/pr/b2l17-FF b/tests/pr/b2l17-FF
new file mode 100644
index 0000000..1eec2e7
--- /dev/null
+++ b/tests/pr/b2l17-FF
@@ -0,0 +1,153 @@
+
+
+-- Date/Time -- x Page 1
+
+
+1 FF-Test: FF's in Text 8 \f\f\n; \f\n\f\n;
+2 Options -b -3 / -a -3 / ... 9
+3 ------------------------------- 10 zzzzzzzzzzzzzzzzzzzzzzzzzz12345
+4 3456789 123456789 123456789 12345 1
+5 3 Columns downwards ..., <= 5 l 2
+6 FF-Arangements: One Empty Page 3 line truncation before FF; r_r_o_
+7 text\f\f\n; text\f\n\ftext; \f\ 14 456789 123456789 123456789 12345
+
+
+
+
+
+
+
+-- Date/Time -- x Page 2
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+-- Date/Time -- x Page 3
+
+
+15 xyzxyzxyz XYZXYZXYZ abcabcab 2
+16 456789 123456789 xyzxyzxyz XYZXY 3
+7 4
+8 5
+9 3456789 ab 6
+20 DEFGHI 123 27 no truncation before FF; (r_l-te
+1 28 no trunc
+
+
+
+
+
+
+
+-- Date/Time -- x Page 4
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+-- Date/Time -- x Page 5
+
+
+29 xyzxyzxyz XYZXYZXYZ abcabcab 6
+30 456789 123456789 xyzxyzxyz XYZXY 7
+1 8
+2 3456789 abcdefghi 9 3456789 abcdefghi
+3 40 DEFGHI 123456789
+4 41 yzxyzxyz XYZXYZXYZ abcabcab
+5 42 456789 123456789 abcdefghi ABCDE
+
+
+
+
+
+
+
+-- Date/Time -- x Page 6
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+-- Date/Time -- x Page 7
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+-- Date/Time -- x Page 8
+
+
+43 xyzxyzxyz XYZXYZXYZ abcabcab 50
+44 456789 123456789 xyzxyzxyz XYZXY 1
+5 2
+6 3
+7 4
+8 55 yzxyzxyz XYZXYZXYZ abcabcab
+9 56 456789 123456789 abcdefghi ABCDE
+
+
+
+
+
+
+
+-- Date/Time -- x Page 9
+
+
+57 xyzxyzxyz XYZXYZXYZ abcabcab 9
+58 456789 123456789 xyzxyzxyz XYZXY 60 DEFGHI 123456789
+
+
+
+
+
+
+
+
+
+
diff --git a/tests/pr/b3-0F b/tests/pr/b3-0F
new file mode 100644
index 0000000..a75b6b3
--- /dev/null
+++ b/tests/pr/b3-0F
@@ -0,0 +1,330 @@
+
+
+-- Date/Time -- x Page 1
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+-- Date/Time -- x Page 2
+
+
+1 FF-Test: FF's at St 6 FF-Arangements: Emp 1
+2 Options -b -3 / -a 7 \ftext; \f\ntext; 2
+3 ------------------- 8 \f\ftext; \f\f\ntex 3 line truncation befor
+4 3456789 123456789 123 9 3456789 123456789 123 14 456789 123456789 123
+5 3 Columns downwards 10 zzzzzzzzzzzzzzzzzzz
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+-- Date/Time -- x Page 3
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+-- Date/Time -- x Page 4
+
+
+15 xyzxyzxyz XYZXYZXYZ 20 DEFGHI 123 5
+16 456789 123456789 xyz 1 6
+7 2 27 no truncation before
+8 3 28 no trunc
+9 3456789 ab 4
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+-- Date/Time -- x Page 5
+
+
+29 xyzxyzxyz XYZXYZXYZ 1 3
+30 456789 123456789 xyz 2 3456789 abcdefghi
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/tests/pr/b3f-0F b/tests/pr/b3f-0F
new file mode 100644
index 0000000..af54e9a
--- /dev/null
+++ b/tests/pr/b3f-0F
@@ -0,0 +1,40 @@
+
+
+-- Date/Time -- x Page 1
+
+
+
+
+
+-- Date/Time -- x Page 2
+
+
+1 FF-Test: FF's at St 6 FF-Arangements: Emp 1
+2 Options -b -3 / -a 7 \ftext; \f\ntext; 2
+3 ------------------- 8 \f\ftext; \f\f\ntex 3 line truncation befor
+4 3456789 123456789 123 9 3456789 123456789 123 14 456789 123456789 123
+5 3 Columns downwards 10 zzzzzzzzzzzzzzzzzzz
+
+
+-- Date/Time -- x Page 3
+
+
+
+
+
+-- Date/Time -- x Page 4
+
+
+15 xyzxyzxyz XYZXYZXYZ 20 DEFGHI 123 5
+16 456789 123456789 xyz 1 6
+7 2 27 no truncation before
+8 3 28 no trunc
+9 3456789 ab 4
+
+
+-- Date/Time -- x Page 5
+
+
+29 xyzxyzxyz XYZXYZXYZ 1 3
+30 456789 123456789 xyz 2 3456789 abcdefghi
+ \ No newline at end of file
diff --git a/tests/pr/b3f-0FF b/tests/pr/b3f-0FF
new file mode 100644
index 0000000..a97c9df
--- /dev/null
+++ b/tests/pr/b3f-0FF
@@ -0,0 +1,46 @@
+
+
+-- Date/Time -- x Page 1
+
+
+
+
+
+-- Date/Time -- x Page 2
+
+
+
+
+
+-- Date/Time -- x Page 3
+
+
+1 FF-Test: FF's at St 6 FF-Arangements: Emp 1
+2 Options -b -3 / -a 7 \ftext; \f\ntext; 2
+3 ------------------- 8 \f\ftext; \f\f\ntex 3 line truncation befor
+4 3456789 123456789 123 9 3456789 123456789 123 14 456789 123456789 123
+5 3 Columns downwards 10 zzzzzzzzzzzzzzzzzzz
+
+
+-- Date/Time -- x Page 4
+
+
+
+
+
+-- Date/Time -- x Page 5
+
+
+15 xyzxyzxyz XYZXYZXYZ 20 DEFGHI 123 5
+16 456789 123456789 xyz 1 6
+7 2 27 no truncation before
+8 3 28 no trunc
+9 3456789 ab 4
+
+
+-- Date/Time -- x Page 6
+
+
+29 xyzxyzxyz XYZXYZXYZ 1 3
+30 456789 123456789 xyz 2 3456789 abcdefghi
+ \ No newline at end of file
diff --git a/tests/pr/b3f-FF b/tests/pr/b3f-FF
new file mode 100644
index 0000000..b2afdb0
--- /dev/null
+++ b/tests/pr/b3f-FF
@@ -0,0 +1,72 @@
+
+
+-- Date/Time -- x Page 1
+
+
+1 FF-Test: FF's in Te 6 FF-Arangements: One 1
+2 Options -b -3 / -a 7 text\f\f\n; text\f\ 2
+3 ------------------- 8 \f\f\n; \f\n\f\n; 3 line truncation befor
+4 3456789 123456789 123 9 14 456789 123456789 123
+5 3 Columns downwards 10 zzzzzzzzzzzzzzzzzzz
+
+
+-- Date/Time -- x Page 2
+
+
+
+
+
+-- Date/Time -- x Page 3
+
+
+15 xyzxyzxyz XYZXYZXYZ 20 DEFGHI 123 5
+16 456789 123456789 xyz 1 6
+7 2 27 no truncation before
+8 3 28 no trunc
+9 3456789 ab 4
+
+
+-- Date/Time -- x Page 4
+
+
+
+
+
+-- Date/Time -- x Page 5
+
+
+29 xyzxyzxyz XYZXYZXYZ 4 9 3456789 abcdefghi
+30 456789 123456789 xyz 5 40 DEFGHI 123456789
+1 6 41 yzxyzxyz XYZXYZXYZ a
+2 3456789 abcdefghi 7 42 456789 123456789 abc
+3 8
+
+
+-- Date/Time -- x Page 6
+
+
+
+
+
+-- Date/Time -- x Page 7
+
+
+
+
+
+-- Date/Time -- x Page 8
+
+
+43 xyzxyzxyz XYZXYZXYZ 8 3
+44 456789 123456789 xyz 9 4
+5 50 55 yzxyzxyz XYZXYZXYZ a
+6 1 56 456789 123456789 abc
+7 2
+
+
+-- Date/Time -- x Page 9
+
+
+57 xyzxyzxyz XYZXYZXYZ 9 60 DEFGHI 123456789
+58 456789 123456789 xyz
+ \ No newline at end of file
diff --git a/tests/pr/b3l15-t b/tests/pr/b3l15-t
new file mode 100644
index 0000000..a2ee3fd
--- /dev/null
+++ b/tests/pr/b3l15-t
@@ -0,0 +1,75 @@
+
+
+-- Date/Time -- x Page 1
+
+
+1 Test-INPUT: "Withou 6 ------------------- 1 with -f e.g. : -
+2 Options -b -3 [+2|+ 7 3456789 123456789 123 2
+3 Options -a -3 [+2|+ 8 3 Columns downwards 3 line truncation befor
+4 Options [+2|+ 9 With columns use < 14 456789 123456789 123
+5 10 without -f e.g.: - 15 xyzxyzxyz XYZXYZXYZ
+
+
+
+
+
+
+
+-- Date/Time -- x Page 2
+
+
+16 456789 123456789 xyz 1 6
+7 2 27 no truncation before
+8 3 28 no trunc
+9 3456789 ab 4 29 xyzxyzxyz XYZXYZXYZ
+20 DEFGHI 123 5 30 456789 123456789 xyz
+
+
+
+
+
+
+
+-- Date/Time -- x Page 3
+
+
+1 6 41 yzxyzxyz XYZXYZXYZ a
+2 3456789 abcdefghi 7 42 456789 123456789 abc
+3 8 43 xyzxyzxyz XYZXYZXYZ
+4 9 3456789 abcdefghi 44 456789 123456789 xyz
+5 40 DEFGHI 123456789 5
+
+
+
+
+
+
+
+-- Date/Time -- x Page 4
+
+
+6 1 56 456789 123456789 abc
+7 2 57 xyzxyzxyz XYZXYZXYZ
+8 3 58 456789 123456789 xyz
+9 4 9
+50 55 yzxyzxyz XYZXYZXYZ a 60 DEFGHI 123456789
+
+
+
+
+
+
+
+-- Date/Time -- x Page 5
+
+
+1 2 3 ------- EOF --------
+
+
+
+
+
+
+
+
+
diff --git a/tests/pr/b3l15f-t b/tests/pr/b3l15f-t
new file mode 100644
index 0000000..7f2bbc4
--- /dev/null
+++ b/tests/pr/b3l15f-t
@@ -0,0 +1,47 @@
+
+
+-- Date/Time -- x Page 1
+
+
+1 Test-INPUT: "Withou 6 ------------------- 1 with -f e.g. : -
+2 Options -b -3 [+2|+ 7 3456789 123456789 123 2
+3 Options -a -3 [+2|+ 8 3 Columns downwards 3 line truncation befor
+4 Options [+2|+ 9 With columns use < 14 456789 123456789 123
+5 10 without -f e.g.: - 15 xyzxyzxyz XYZXYZXYZ
+
+
+-- Date/Time -- x Page 2
+
+
+16 456789 123456789 xyz 1 6
+7 2 27 no truncation before
+8 3 28 no trunc
+9 3456789 ab 4 29 xyzxyzxyz XYZXYZXYZ
+20 DEFGHI 123 5 30 456789 123456789 xyz
+
+
+-- Date/Time -- x Page 3
+
+
+1 6 41 yzxyzxyz XYZXYZXYZ a
+2 3456789 abcdefghi 7 42 456789 123456789 abc
+3 8 43 xyzxyzxyz XYZXYZXYZ
+4 9 3456789 abcdefghi 44 456789 123456789 xyz
+5 40 DEFGHI 123456789 5
+
+
+-- Date/Time -- x Page 4
+
+
+6 1 56 456789 123456789 abc
+7 2 57 xyzxyzxyz XYZXYZXYZ
+8 3 58 456789 123456789 xyz
+9 4 9
+50 55 yzxyzxyz XYZXYZXYZ a 60 DEFGHI 123456789
+
+
+-- Date/Time -- x Page 5
+
+
+1 2 3 ------- EOF --------
+ \ No newline at end of file
diff --git a/tests/pr/b3l24f-lm b/tests/pr/b3l24f-lm
new file mode 100644
index 0000000..97fabc2
--- /dev/null
+++ b/tests/pr/b3l24f-lm
@@ -0,0 +1,72 @@
+
+
+-- Date/Time -- x Page 1
+
+
+1<<< -Test: FF's in Te 6<<< -Arangements: One 1<<< >>>
+2<<< -b -3 / -a -3 / . 7<<< \f\f\n; text\f\n\ 2<<< >>>
+3<<< >>> 8<<< f\f\n; \f\n\f\n; 3<<< truncation before
+4<<< 123456789 1234567 9<<< >>> 14<<< 123456789 123456
+ 10<<< >>>
+
+
+-- Date/Time -- x Page 2
+
+
+
+
+
+-- Date/Time -- x Page 3
+
+
+15<<< xyzxyzxyz XYZXYZ 20<<< >>> 5<<< >>>
+16<<< 123456789 xyzxyz 1<<< >>> 6<<< >>>
+7<<< >>> 27<<< truncation befor
+8<<< >>> 28<<< trunc
+9<<< >>> 4<<< >>>
+
+
+-- Date/Time -- x Page 4
+
+
+
+
+
+-- Date/Time -- x Page 5
+
+
+29<<<xyzxyzxyz XYZXYZXY 4<<< >>> 9<<< abcdefghi >>>
+30<<< 123456789 xyzxyz 5<<< >>> 40<<< 123456789 >>>
+1<<< >>> 6<<< >>> 41<<< XYZXYZXYZ abcabc
+2<<< abcdefghi >>> 7<<< >>> 42<<< 123456789 abcdef
+3<<< >>> 8<<< >>>
+
+
+-- Date/Time -- x Page 6
+
+
+
+
+
+-- Date/Time -- x Page 7
+
+
+
+
+
+-- Date/Time -- x Page 8
+
+
+43<<< xyzxyzxyz XYZXYZ 8<<< >>> 3<<< >>>
+44<<< 123456789 xyzxyz 9<<< >>> 4<<< >>>
+5<<< >>> 50<<< >>> 55<<< XYZXYZXYZ abcabc
+6<<< >>> 1<<< >>> 56<<< 123456789 abcdef
+7<<< >>> 2<<< >>>
+
+
+-- Date/Time -- x Page 9
+
+
+57<<< xyzxyzxyz XYZXYZ 9<<< >>> 60<<< 123456789 >>>
+58<<< 123456789 xyzxyz
+ \ No newline at end of file
diff --git a/tests/pr/l24-FF b/tests/pr/l24-FF
new file mode 100644
index 0000000..e9f3154
--- /dev/null
+++ b/tests/pr/l24-FF
@@ -0,0 +1,216 @@
+
+
+-- Date/Time -- x Page 1
+
+
+1 FF-Test: FF's in Text V
+2 Options -b -3 / -a -3 / ...
+3 --------------------------------------------
+4 3456789 123456789 123456789 123456789 12345678
+5 3 Columns downwards ..., <= 5 lines per page
+6 FF-Arangements: One Empty Page
+7 text\f\f\n; text\f\n\ftext; \f\ftext;
+8 \f\f\n; \f\n\f\n;
+9
+10 zzzzzzzzzzzzzzzzzzzzzzzzzz123456789
+1 12345678
+2 12345678
+3 line truncation before FF; r_r_o_l-test:
+14 456789 123456789 123456789 123456789
+
+
+
+
+
+
+
+-- Date/Time -- x Page 2
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+-- Date/Time -- x Page 3
+
+
+15 xyzxyzxyz XYZXYZXYZ abcabcab
+16 456789 123456789 xyzxyzxyz XYZXYZXYZ
+7 12345678
+8 12345678
+9 3456789 ab
+20 DEFGHI 123
+1 12345678
+2 12345678
+3 12345678
+4 12345678
+5 12345678
+6 12345678
+27 no truncation before FF; (r_l-test):
+28 no trunc
+
+
+
+
+
+
+
+-- Date/Time -- x Page 4
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+-- Date/Time -- x Page 5
+
+
+29 xyzxyzxyz XYZXYZXYZ abcabcab
+30 456789 123456789 xyzxyzxyz XYZXYZXYZ
+1 12345678
+2 3456789 abcdefghi
+3 12345678
+4 12345678
+5 12345678
+6 12345678
+7 12345678
+8 12345678
+9 3456789 abcdefghi
+40 DEFGHI 123456789
+41 yzxyzxyz XYZXYZXYZ abcabcab
+42 456789 123456789 abcdefghi ABCDEDFHI
+
+
+
+
+
+
+
+-- Date/Time -- x Page 6
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+-- Date/Time -- x Page 7
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+-- Date/Time -- x Page 8
+
+
+43 xyzxyzxyz XYZXYZXYZ abcabcab
+44 456789 123456789 xyzxyzxyz XYZXYZXYZ
+5 12345678
+6 12345678
+7 12345678
+8 12345678
+9 12345678
+50 12345678
+1 12345678
+2 12345678
+3 12345678
+4 12345678
+55 yzxyzxyz XYZXYZXYZ abcabcab
+56 456789 123456789 abcdefghi ABCDEDFHI
+
+
+
+
+
+
+
+-- Date/Time -- x Page 9
+
+
+57 xyzxyzxyz XYZXYZXYZ abcabcab
+58 456789 123456789 xyzxyzxyz XYZXYZXYZ
+9 12345678
+60 DEFGHI 123456789
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/tests/pr/l24-t b/tests/pr/l24-t
new file mode 100644
index 0000000..d07b88d
--- /dev/null
+++ b/tests/pr/l24-t
@@ -0,0 +1,120 @@
+
+
+-- Date/Time -- x Page 1
+
+
+1 Test-INPUT: "Without FF set by Hand" V
+2 Options -b -3 [+2|+3] [-l 15|8] [-f]
+3 Options -a -3 [+2|+3] [-l 15|8] [-f]
+4 Options [+2|+3] [-l 24|17] [-f]
+5
+6 --------------------------------------------
+7 3456789 123456789 123456789 123456789 12345678
+8 3 Columns downwards, across, ...:
+9 With columns use <= 5 text lines/page,
+10 without -f e.g.: -l 15 = total lines/page,
+1 with -f e.g. : -l 8 -f
+2
+3 line truncation before new page; r_r_o_l-test:
+14 456789 123456789 123456789 123456789
+
+
+
+
+
+
+
+-- Date/Time -- x Page 2
+
+
+15 xyzxyzxyz XYZXYZXYZ abcabcab
+16 456789 123456789 xyzxyzxyz XYZXYZXYZ
+7 12345678
+8 12345678
+9 3456789 ab
+20 DEFGHI 123
+1 12345678
+2 12345678
+3 12345678
+4 12345678
+5 12345678
+6 12345678
+27 no truncation before nwe page; (r_l-test):
+28 no trunc
+
+
+
+
+
+
+
+-- Date/Time -- x Page 3
+
+
+29 xyzxyzxyz XYZXYZXYZ abcabcab
+30 456789 123456789 xyzxyzxyz XYZXYZXYZ
+1 12345678
+2 3456789 abcdefghi
+3 12345678
+4 12345678
+5 12345678
+6 12345678
+7 12345678
+8 12345678
+9 3456789 abcdefghi
+40 DEFGHI 123456789
+41 yzxyzxyz XYZXYZXYZ abcabcab
+42 456789 123456789 abcdefghi ABCDEDFHI
+
+
+
+
+
+
+
+-- Date/Time -- x Page 4
+
+
+43 xyzxyzxyz XYZXYZXYZ abcabcab
+44 456789 123456789 xyzxyzxyz XYZXYZXYZ
+5 12345678
+6 12345678
+7 12345678
+8 12345678
+9 12345678
+50 12345678
+1 12345678
+2 12345678
+3 12345678
+4 12345678
+55 yzxyzxyz XYZXYZXYZ abcabcab
+56 456789 123456789 abcdefghi ABCDEDFHI
+
+
+
+
+
+
+
+-- Date/Time -- x Page 5
+
+
+57 xyzxyzxyz XYZXYZXYZ abcabcab
+58 456789 123456789 xyzxyzxyz XYZXYZXYZ
+9 12345678
+60 DEFGHI 123456789
+1
+2
+3 ------- EOF -------- EOF -------- EOF -------
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/tests/pr/l24f-t b/tests/pr/l24f-t
new file mode 100644
index 0000000..3546282
--- /dev/null
+++ b/tests/pr/l24f-t
@@ -0,0 +1,89 @@
+
+
+-- Date/Time -- x Page 1
+
+
+1 Test-INPUT: "Without FF set by Hand" V
+2 Options -b -3 [+2|+3] [-l 15|8] [-f]
+3 Options -a -3 [+2|+3] [-l 15|8] [-f]
+4 Options [+2|+3] [-l 24|17] [-f]
+5
+6 --------------------------------------------
+7 3456789 123456789 123456789 123456789 12345678
+8 3 Columns downwards, across, ...:
+9 With columns use <= 5 text lines/page,
+10 without -f e.g.: -l 15 = total lines/page,
+1 with -f e.g. : -l 8 -f
+2
+3 line truncation before new page; r_r_o_l-test:
+14 456789 123456789 123456789 123456789
+
+
+-- Date/Time -- x Page 2
+
+
+15 xyzxyzxyz XYZXYZXYZ abcabcab
+16 456789 123456789 xyzxyzxyz XYZXYZXYZ
+7 12345678
+8 12345678
+9 3456789 ab
+20 DEFGHI 123
+1 12345678
+2 12345678
+3 12345678
+4 12345678
+5 12345678
+6 12345678
+27 no truncation before nwe page; (r_l-test):
+28 no trunc
+
+
+-- Date/Time -- x Page 3
+
+
+29 xyzxyzxyz XYZXYZXYZ abcabcab
+30 456789 123456789 xyzxyzxyz XYZXYZXYZ
+1 12345678
+2 3456789 abcdefghi
+3 12345678
+4 12345678
+5 12345678
+6 12345678
+7 12345678
+8 12345678
+9 3456789 abcdefghi
+40 DEFGHI 123456789
+41 yzxyzxyz XYZXYZXYZ abcabcab
+42 456789 123456789 abcdefghi ABCDEDFHI
+
+
+-- Date/Time -- x Page 4
+
+
+43 xyzxyzxyz XYZXYZXYZ abcabcab
+44 456789 123456789 xyzxyzxyz XYZXYZXYZ
+5 12345678
+6 12345678
+7 12345678
+8 12345678
+9 12345678
+50 12345678
+1 12345678
+2 12345678
+3 12345678
+4 12345678
+55 yzxyzxyz XYZXYZXYZ abcabcab
+56 456789 123456789 abcdefghi ABCDEDFHI
+
+
+-- Date/Time -- x Page 5
+
+
+57 xyzxyzxyz XYZXYZXYZ abcabcab
+58 456789 123456789 xyzxyzxyz XYZXYZXYZ
+9 12345678
+60 DEFGHI 123456789
+1
+2
+3 ------- EOF -------- EOF -------- EOF -------
+ \ No newline at end of file
diff --git a/tests/pr/loli b/tests/pr/loli
new file mode 100644
index 0000000..08120c0
--- /dev/null
+++ b/tests/pr/loli
@@ -0,0 +1,63 @@
+1::: Test-INPUT: "Without FF set by Hand" :::
+2::: Options -b -3 [+2|+3] [-l 15|8] [-f] :::
+3::: Options -a -3 [+2|+3] [-l 15|8] [-f] :::
+4::: Options [+2|+3] [-l 24|17] [-f] :::
+5::: :::
+6::: -------------------------------------------- :::
+7::: 789 123456789 123456789 123456789 123456789 123456789 123456789 1234567890 :::
+8::: 3 Columns downwards, across, ...: :::
+9::: With columns use <= 5 text lines/page, :::
+10::: without -f e.g.: -l 15 = total lines/page, :::
+1::: with -f e.g. : -l 8 -f :::
+2::: :::
+3::: line truncation before new page; r_r_o_l-test: :::
+14::: 89 123456789 123456789 123456789 123456789 123456789 123456789 1234567890 :::
+15::: xyzxyzxyz XYZXYZXYZ abcabcab :::
+16::: 456789 123456789 xyzxyzxyz XYZXYZXYZ :::
+7::: 12345678 :::
+8::: 12345678 :::
+9::: 3456789 ab :::
+20::: DEFGHI 123 :::
+21::: 89 123456789 123456789 123456789 123456789 123456789 123456789 1234567890 :::
+2::: 12345678 :::
+3::: 12345678 :::
+4::: 12345678 :::
+5::: 12345678 :::
+6::: 12345678 :::
+27::: no truncation before nwe page; (r_l-test): :::
+28::: 89 123456789 123456789 123456789 123456789 123456789 123456789 1234567890 :::
+29::: xyzxyzxyz XYZXYZXYZ abcabcab :::
+30::: 456789 123456789 xyzxyzxyz XYZXYZXYZ :::
+1::: 12345678 :::
+2::: 3456789 abcdefghi :::
+3::: 12345678 :::
+4::: 12345678 :::
+35::: 89 123456789 123456789 123456789 123456789 123456789 123456789 1234567890 :::
+6::: 12345678 :::
+7::: 12345678 :::
+8::: 12345678 :::
+9::: 3456789 abcdefghi :::
+40::: DEFGHI 123456789 :::
+41::: yzxyzxyz XYZXYZXYZ abcabcab :::
+42::: 89 123456789 123456789 123456789 123456789 123456789 123456789 1234567890 :::
+43::: xyzxyzxyz XYZXYZXYZ abcabcab :::
+44::: 456789 123456789 xyzxyzxyz XYZXYZXYZ :::
+5::: 12345678 :::
+6::: 12345678 :::
+7::: 12345678 :::
+8::: 12345678 :::
+49::: 89 123456789 123456789 123456789 123456789 123456789 123456789 1234567890 :::
+50::: 12345678 :::
+1::: 12345678 :::
+2::: 12345678 :::
+3::: 12345678 :::
+4::: 12345678 :::
+55::: yzxyzxyz XYZXYZXYZ abcabcab :::
+56::: 89 123456789 123456789 123456789 123456789 123456789 123456789 1234567890 :::
+57::: xyzxyzxyz XYZXYZXYZ abcabcab :::
+58::: 456789 123456789 xyzxyzxyz XYZXYZXYZ :::
+9::: 12345678 :::
+60::: DEFGHI 123456789 :::
+1::: :::
+2::: :::
+3::: ------- EOF -------- EOF -------- EOF ------- EOF ------- EOF ------- EOF :::
diff --git a/tests/pr/ml20-FF-t b/tests/pr/ml20-FF-t
new file mode 100644
index 0000000..53cb6eb
--- /dev/null
+++ b/tests/pr/ml20-FF-t
@@ -0,0 +1,260 @@
+
+
+-- Date/Time -- x Page 1
+
+
+1 FF-Test: FF's in Text 1 Test-INPUT: "Without FF set by
+2 Options -b -3 / -a -3 / ... 2 Options -b -3 [+2|+3] [-l 15|8]
+3 ------------------------------- 3 Options -a -3 [+2|+3] [-l 15|8]
+4 3456789 123456789 123456789 12345 4 Options [+2|+3] [-l 24|17
+5 3 Columns downwards ..., <= 5 l 5
+6 FF-Arangements: One Empty Page 6 -------------------------------
+7 text\f\f\n; text\f\n\ftext; \f\ 7 3456789 123456789 123456789 12345
+8 \f\f\n; \f\n\f\n; 8 3 Columns downwards, across, ..
+9 9 With columns use <= 5 text lin
+10 zzzzzzzzzzzzzzzzzzzzzzzzzz12345 10 without -f e.g.: -l 15 = total
+
+
+
+
+
+
+
+-- Date/Time -- x Page 2
+
+
+1 1 with -f e.g. : -l 8 -f
+2 2
+3 line truncation before FF; r_r_o_ 3 line truncation before new page;
+14 456789 123456789 123456789 12345 14 456789 123456789 123456789 12345
+ 15 xyzxyzxyz XYZXYZXYZ abcabcab
+ 16 456789 123456789 xyzxyzxyz XYZXY
+ 7
+ 8
+ 9 3456789 ab
+ 20 DEFGHI 123
+
+
+
+
+
+
+
+-- Date/Time -- x Page 3
+
+
+ 1
+ 2
+ 3
+ 4
+ 5
+ 6
+ 27 no truncation before nwe page; (
+ 28 no trunc
+ 29 xyzxyzxyz XYZXYZXYZ abcabcab
+ 30 456789 123456789 xyzxyzxyz XYZXY
+
+
+
+
+
+
+
+-- Date/Time -- x Page 4
+
+
+15 xyzxyzxyz XYZXYZXYZ abcabcab 1
+16 456789 123456789 xyzxyzxyz XYZXY 2 3456789 abcdefghi
+7 3
+8 4
+9 3456789 ab 5
+20 DEFGHI 123 6
+1 7
+2 8
+3 9 3456789 abcdefghi
+4 40 DEFGHI 123456789
+
+
+
+
+
+
+
+-- Date/Time -- x Page 5
+
+
+5 41 yzxyzxyz XYZXYZXYZ abcabcab
+6 42 456789 123456789 abcdefghi ABCDE
+27 no truncation before FF; (r_l-te 43 xyzxyzxyz XYZXYZXYZ abcabcab
+28 no trunc 44 456789 123456789 xyzxyzxyz XYZXY
+ 5
+ 6
+ 7
+ 8
+ 9
+ 50
+
+
+
+
+
+
+
+-- Date/Time -- x Page 6
+
+
+ 1
+ 2
+ 3
+ 4
+ 55 yzxyzxyz XYZXYZXYZ abcabcab
+ 56 456789 123456789 abcdefghi ABCDE
+ 57 xyzxyzxyz XYZXYZXYZ abcabcab
+ 58 456789 123456789 xyzxyzxyz XYZXY
+ 9
+ 60 DEFGHI 123456789
+
+
+
+
+
+
+
+-- Date/Time -- x Page 7
+
+
+29 xyzxyzxyz XYZXYZXYZ abcabcab 1
+30 456789 123456789 xyzxyzxyz XYZXY 2
+1 3 ------- EOF -------- EOF -------
+2 3456789 abcdefghi
+3
+4
+5
+6
+7
+8
+
+
+
+
+
+
+
+-- Date/Time -- x Page 8
+
+
+9 3456789 abcdefghi
+40 DEFGHI 123456789
+41 yzxyzxyz XYZXYZXYZ abcabcab
+42 456789 123456789 abcdefghi ABCDE
+
+
+
+
+
+
+
+
+
+
+
+
+
+-- Date/Time -- x Page 9
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+-- Date/Time -- x Page 10
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+-- Date/Time -- x Page 11
+
+
+43 xyzxyzxyz XYZXYZXYZ abcabcab
+44 456789 123456789 xyzxyzxyz XYZXY
+5
+6
+7
+8
+9
+50
+1
+2
+
+
+
+
+
+
+
+-- Date/Time -- x Page 12
+
+
+3
+4
+55 yzxyzxyz XYZXYZXYZ abcabcab
+56 456789 123456789 abcdefghi ABCDE
+
+
+
+
+
+
+
+
+
+
+
+
+
+-- Date/Time -- x Page 13
+
+
+57 xyzxyzxyz XYZXYZXYZ abcabcab
+58 456789 123456789 xyzxyzxyz XYZXY
+9
+60 DEFGHI 123456789
+
+
+
+
+
+
+
+
+
+
+
diff --git a/tests/pr/ml24-FF b/tests/pr/ml24-FF
new file mode 100644
index 0000000..c36edb7
--- /dev/null
+++ b/tests/pr/ml24-FF
@@ -0,0 +1,216 @@
+
+
+-- Date/Time -- x Page 1
+
+
+1 FF-Test: FF's in Text 1 FF-Test: FF's in Text
+2 Options -b -3 / -a -3 / ... 2 Options -b -3 / -a -3 / ...
+3 ------------------------------- 3 -------------------------------
+4 3456789 123456789 123456789 12345 4 3456789 123456789 123456789 12345
+5 3 Columns downwards ..., <= 5 l 5 3 Columns downwards ..., <= 5 l
+6 FF-Arangements: One Empty Page 6 FF-Arangements: One Empty Page
+7 text\f\f\n; text\f\n\ftext; \f\ 7 text\f\f\n; text\f\n\ftext; \f\
+8 \f\f\n; \f\n\f\n; 8 \f\f\n; \f\n\f\n;
+9 9
+10 zzzzzzzzzzzzzzzzzzzzzzzzzz12345 10 zzzzzzzzzzzzzzzzzzzzzzzzzz12345
+1 1
+2 2
+3 line truncation before FF; r_r_o_ 3 line truncation before FF; r_r_o_
+14 456789 123456789 123456789 12345 14 456789 123456789 123456789 12345
+
+
+
+
+
+
+
+-- Date/Time -- x Page 2
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+-- Date/Time -- x Page 3
+
+
+15 xyzxyzxyz XYZXYZXYZ abcabcab 15 xyzxyzxyz XYZXYZXYZ abcabcab
+16 456789 123456789 xyzxyzxyz XYZXY 16 456789 123456789 xyzxyzxyz XYZXY
+7 7
+8 8
+9 3456789 ab 9 3456789 ab
+20 DEFGHI 123 20 DEFGHI 123
+1 1
+2 2
+3 3
+4 4
+5 5
+6 6
+27 no truncation before FF; (r_l-te 27 no truncation before FF; (r_l-te
+28 no trunc 28 no trunc
+
+
+
+
+
+
+
+-- Date/Time -- x Page 4
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+-- Date/Time -- x Page 5
+
+
+29 xyzxyzxyz XYZXYZXYZ abcabcab 29 xyzxyzxyz XYZXYZXYZ abcabcab
+30 456789 123456789 xyzxyzxyz XYZXY 30 456789 123456789 xyzxyzxyz XYZXY
+1 1
+2 3456789 abcdefghi 2 3456789 abcdefghi
+3 3
+4 4
+5 5
+6 6
+7 7
+8 8
+9 3456789 abcdefghi 9 3456789 abcdefghi
+40 DEFGHI 123456789 40 DEFGHI 123456789
+41 yzxyzxyz XYZXYZXYZ abcabcab 41 yzxyzxyz XYZXYZXYZ abcabcab
+42 456789 123456789 abcdefghi ABCDE 42 456789 123456789 abcdefghi ABCDE
+
+
+
+
+
+
+
+-- Date/Time -- x Page 6
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+-- Date/Time -- x Page 7
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+-- Date/Time -- x Page 8
+
+
+43 xyzxyzxyz XYZXYZXYZ abcabcab 43 xyzxyzxyz XYZXYZXYZ abcabcab
+44 456789 123456789 xyzxyzxyz XYZXY 44 456789 123456789 xyzxyzxyz XYZXY
+5 5
+6 6
+7 7
+8 8
+9 9
+50 50
+1 1
+2 2
+3 3
+4 4
+55 yzxyzxyz XYZXYZXYZ abcabcab 55 yzxyzxyz XYZXYZXYZ abcabcab
+56 456789 123456789 abcdefghi ABCDE 56 456789 123456789 abcdefghi ABCDE
+
+
+
+
+
+
+
+-- Date/Time -- x Page 9
+
+
+57 xyzxyzxyz XYZXYZXYZ abcabcab 57 xyzxyzxyz XYZXYZXYZ abcabcab
+58 456789 123456789 xyzxyzxyz XYZXY 58 456789 123456789 xyzxyzxyz XYZXY
+9 9
+60 DEFGHI 123456789 60 DEFGHI 123456789
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/tests/pr/ml24-t b/tests/pr/ml24-t
new file mode 100644
index 0000000..392adbf
--- /dev/null
+++ b/tests/pr/ml24-t
@@ -0,0 +1,120 @@
+
+
+-- Date/Time -- x Page 1
+
+
+1 Test-INPUT: "Without FF set by 1 Test-INPUT: "Without FF set by
+2 Options -b -3 [+2|+3] [-l 15|8] 2 Options -b -3 [+2|+3] [-l 15|8]
+3 Options -a -3 [+2|+3] [-l 15|8] 3 Options -a -3 [+2|+3] [-l 15|8]
+4 Options [+2|+3] [-l 24|17 4 Options [+2|+3] [-l 24|17
+5 5
+6 ------------------------------- 6 -------------------------------
+7 3456789 123456789 123456789 12345 7 3456789 123456789 123456789 12345
+8 3 Columns downwards, across, .. 8 3 Columns downwards, across, ..
+9 With columns use <= 5 text lin 9 With columns use <= 5 text lin
+10 without -f e.g.: -l 15 = total 10 without -f e.g.: -l 15 = total
+1 with -f e.g. : -l 8 -f 1 with -f e.g. : -l 8 -f
+2 2
+3 line truncation before new page; 3 line truncation before new page;
+14 456789 123456789 123456789 12345 14 456789 123456789 123456789 12345
+
+
+
+
+
+
+
+-- Date/Time -- x Page 2
+
+
+15 xyzxyzxyz XYZXYZXYZ abcabcab 15 xyzxyzxyz XYZXYZXYZ abcabcab
+16 456789 123456789 xyzxyzxyz XYZXY 16 456789 123456789 xyzxyzxyz XYZXY
+7 7
+8 8
+9 3456789 ab 9 3456789 ab
+20 DEFGHI 123 20 DEFGHI 123
+1 1
+2 2
+3 3
+4 4
+5 5
+6 6
+27 no truncation before nwe page; ( 27 no truncation before nwe page; (
+28 no trunc 28 no trunc
+
+
+
+
+
+
+
+-- Date/Time -- x Page 3
+
+
+29 xyzxyzxyz XYZXYZXYZ abcabcab 29 xyzxyzxyz XYZXYZXYZ abcabcab
+30 456789 123456789 xyzxyzxyz XYZXY 30 456789 123456789 xyzxyzxyz XYZXY
+1 1
+2 3456789 abcdefghi 2 3456789 abcdefghi
+3 3
+4 4
+5 5
+6 6
+7 7
+8 8
+9 3456789 abcdefghi 9 3456789 abcdefghi
+40 DEFGHI 123456789 40 DEFGHI 123456789
+41 yzxyzxyz XYZXYZXYZ abcabcab 41 yzxyzxyz XYZXYZXYZ abcabcab
+42 456789 123456789 abcdefghi ABCDE 42 456789 123456789 abcdefghi ABCDE
+
+
+
+
+
+
+
+-- Date/Time -- x Page 4
+
+
+43 xyzxyzxyz XYZXYZXYZ abcabcab 43 xyzxyzxyz XYZXYZXYZ abcabcab
+44 456789 123456789 xyzxyzxyz XYZXY 44 456789 123456789 xyzxyzxyz XYZXY
+5 5
+6 6
+7 7
+8 8
+9 9
+50 50
+1 1
+2 2
+3 3
+4 4
+55 yzxyzxyz XYZXYZXYZ abcabcab 55 yzxyzxyz XYZXYZXYZ abcabcab
+56 456789 123456789 abcdefghi ABCDE 56 456789 123456789 abcdefghi ABCDE
+
+
+
+
+
+
+
+-- Date/Time -- x Page 5
+
+
+57 xyzxyzxyz XYZXYZXYZ abcabcab 57 xyzxyzxyz XYZXYZXYZ abcabcab
+58 456789 123456789 xyzxyzxyz XYZXY 58 456789 123456789 xyzxyzxyz XYZXY
+9 9
+60 DEFGHI 123456789 60 DEFGHI 123456789
+1 1
+2 2
+3 ------- EOF -------- EOF ------- 3 ------- EOF -------- EOF -------
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/tests/pr/ml24-t-FF b/tests/pr/ml24-t-FF
new file mode 100644
index 0000000..08c6f05
--- /dev/null
+++ b/tests/pr/ml24-t-FF
@@ -0,0 +1,216 @@
+
+
+-- Date/Time -- x Page 1
+
+
+1 Test-INPUT: "Without FF set by 1 FF-Test: FF's in Text
+2 Options -b -3 [+2|+3] [-l 15|8] 2 Options -b -3 / -a -3 / ...
+3 Options -a -3 [+2|+3] [-l 15|8] 3 -------------------------------
+4 Options [+2|+3] [-l 24|17 4 3456789 123456789 123456789 12345
+5 5 3 Columns downwards ..., <= 5 l
+6 ------------------------------- 6 FF-Arangements: One Empty Page
+7 3456789 123456789 123456789 12345 7 text\f\f\n; text\f\n\ftext; \f\
+8 3 Columns downwards, across, .. 8 \f\f\n; \f\n\f\n;
+9 With columns use <= 5 text lin 9
+10 without -f e.g.: -l 15 = total 10 zzzzzzzzzzzzzzzzzzzzzzzzzz12345
+1 with -f e.g. : -l 8 -f 1
+2 2
+3 line truncation before new page; 3 line truncation before FF; r_r_o_
+14 456789 123456789 123456789 12345 14 456789 123456789 123456789 12345
+
+
+
+
+
+
+
+-- Date/Time -- x Page 2
+
+
+15 xyzxyzxyz XYZXYZXYZ abcabcab
+16 456789 123456789 xyzxyzxyz XYZXY
+7
+8
+9 3456789 ab
+20 DEFGHI 123
+1
+2
+3
+4
+5
+6
+27 no truncation before nwe page; (
+28 no trunc
+
+
+
+
+
+
+
+-- Date/Time -- x Page 3
+
+
+29 xyzxyzxyz XYZXYZXYZ abcabcab 15 xyzxyzxyz XYZXYZXYZ abcabcab
+30 456789 123456789 xyzxyzxyz XYZXY 16 456789 123456789 xyzxyzxyz XYZXY
+1 7
+2 3456789 abcdefghi 8
+3 9 3456789 ab
+4 20 DEFGHI 123
+5 1
+6 2
+7 3
+8 4
+9 3456789 abcdefghi 5
+40 DEFGHI 123456789 6
+41 yzxyzxyz XYZXYZXYZ abcabcab 27 no truncation before FF; (r_l-te
+42 456789 123456789 abcdefghi ABCDE 28 no trunc
+
+
+
+
+
+
+
+-- Date/Time -- x Page 4
+
+
+43 xyzxyzxyz XYZXYZXYZ abcabcab
+44 456789 123456789 xyzxyzxyz XYZXY
+5
+6
+7
+8
+9
+50
+1
+2
+3
+4
+55 yzxyzxyz XYZXYZXYZ abcabcab
+56 456789 123456789 abcdefghi ABCDE
+
+
+
+
+
+
+
+-- Date/Time -- x Page 5
+
+
+57 xyzxyzxyz XYZXYZXYZ abcabcab 29 xyzxyzxyz XYZXYZXYZ abcabcab
+58 456789 123456789 xyzxyzxyz XYZXY 30 456789 123456789 xyzxyzxyz XYZXY
+9 1
+60 DEFGHI 123456789 2 3456789 abcdefghi
+1 3
+2 4
+3 ------- EOF -------- EOF ------- 5
+ 6
+ 7
+ 8
+ 9 3456789 abcdefghi
+ 40 DEFGHI 123456789
+ 41 yzxyzxyz XYZXYZXYZ abcabcab
+ 42 456789 123456789 abcdefghi ABCDE
+
+
+
+
+
+
+
+-- Date/Time -- x Page 6
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+-- Date/Time -- x Page 7
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+-- Date/Time -- x Page 8
+
+
+ 43 xyzxyzxyz XYZXYZXYZ abcabcab
+ 44 456789 123456789 xyzxyzxyz XYZXY
+ 5
+ 6
+ 7
+ 8
+ 9
+ 50
+ 1
+ 2
+ 3
+ 4
+ 55 yzxyzxyz XYZXYZXYZ abcabcab
+ 56 456789 123456789 abcdefghi ABCDE
+
+
+
+
+
+
+
+-- Date/Time -- x Page 9
+
+
+ 57 xyzxyzxyz XYZXYZXYZ abcabcab
+ 58 456789 123456789 xyzxyzxyz XYZXY
+ 9
+ 60 DEFGHI 123456789
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/tests/pr/ml24f-0F b/tests/pr/ml24f-0F
new file mode 100644
index 0000000..18b5760
--- /dev/null
+++ b/tests/pr/ml24f-0F
@@ -0,0 +1,61 @@
+
+
+-- Date/Time -- x Page 1
+
+
+
+
+
+-- Date/Time -- x Page 2
+
+
+1 FF-Test: FF's at Start of File 1 FF-Test: FF's at Start of File
+2 Options -b -3 / -a -3 / ... 2 Options -b -3 / -a -3 / ...
+3 ------------------------------- 3 -------------------------------
+4 3456789 123456789 123456789 12345 4 3456789 123456789 123456789 12345
+5 3 Columns downwards ..., <= 5 l 5 3 Columns downwards ..., <= 5 l
+6 FF-Arangements: Empty Pages at 6 FF-Arangements: Empty Pages at
+7 \ftext; \f\ntext; 7 \ftext; \f\ntext;
+8 \f\ftext; \f\f\ntext; \f\n\ftex 8 \f\ftext; \f\f\ntext; \f\n\ftex
+9 3456789 123456789 123456789 9 3456789 123456789 123456789
+10 zzzzzzzzzzzzzzzzzzzzzzzzzz12345 10 zzzzzzzzzzzzzzzzzzzzzzzzzz12345
+1 1
+2 2
+3 line truncation before FF; r_r_o_ 3 line truncation before FF; r_r_o_
+14 456789 123456789 123456789 12345 14 456789 123456789 123456789 12345
+
+
+-- Date/Time -- x Page 3
+
+
+
+
+
+-- Date/Time -- x Page 4
+
+
+15 xyzxyzxyz XYZXYZXYZ abcabcab 15 xyzxyzxyz XYZXYZXYZ abcabcab
+16 456789 123456789 xyzxyzxyz XYZXY 16 456789 123456789 xyzxyzxyz XYZXY
+7 7
+8 8
+9 3456789 ab 9 3456789 ab
+20 DEFGHI 123 20 DEFGHI 123
+1 1
+2 2
+3 3
+4 4
+5 5
+6 6
+27 no truncation before FF; (r_l-te 27 no truncation before FF; (r_l-te
+28 no trunc 28 no trunc
+
+
+-- Date/Time -- x Page 5
+
+
+29 xyzxyzxyz XYZXYZXYZ abcabcab 29 xyzxyzxyz XYZXYZXYZ abcabcab
+30 456789 123456789 xyzxyzxyz XYZXY 30 456789 123456789 xyzxyzxyz XYZXY
+1 1
+2 3456789 abcdefghi 2 3456789 abcdefghi
+3 3
+ \ No newline at end of file
diff --git a/tests/pr/ml24f-lm-lo b/tests/pr/ml24f-lm-lo
new file mode 100644
index 0000000..3fed7d3
--- /dev/null
+++ b/tests/pr/ml24f-lm-lo
@@ -0,0 +1,136 @@
+
+
+-- Date/Time -- x Page 1
+
+
+1<<< -Test: FF's in Text 1::: Test-INPUT: "Without FF set b
+2<<< -b -3 / -a -3 / ... >>> 2::: Options -b -3 [+2|+3] [-l 15|
+3<<< >>> 3::: Options -a -3 [+2|+3] [-l 15|
+4<<< 123456789 123456789 123456789 4::: Options [+2|+3] [-l 24|
+ 5::: :::
+6<<< -Arangements: One Empty Page 6::: -----------------------------
+7<<< \f\f\n; text\f\n\ftext; \f\ft 7::: 789 123456789 123456789 12345
+8<<< f\f\n; \f\n\f\n; >>> 8::: 3 Columns downwards, across,
+9<<< >>> 9::: With columns use <= 5 text l
+10<<< >>> 10::: without -f e.g.: -l 15 = to
+1<<< >>> 1::: with -f e.g. : -l 8 -f ::
+2<<< >>> 2::: :::
+3<<< truncation before FF; r_r_o_l 3::: line truncation before new pa
+14<<< 123456789 123456789 12345678 14::: 89 123456789 123456789 12345
+
+
+-- Date/Time -- x Page 2
+
+
+ 15::: xyzxyzxyz XYZXYZXYZ abcabcab
+ 16::: 456789 123456789 xyzxyzxyz X
+ 7::: 12345678 :::
+ 8::: 12345678 :::
+ 9::: 3456789 ab :::
+ 20::: DEFGHI 123 :::
+ 21::: 89 123456789 123456789 12345
+ 2::: 12345678 :::
+ 3::: 12345678 :::
+ 4::: 12345678 :::
+ 5::: 12345678 :::
+ 6::: 12345678 :::
+ 27::: no truncation before nwe pag
+ 28::: 89 123456789 123456789 12345
+
+
+-- Date/Time -- x Page 3
+
+
+15<<< xyzxyzxyz XYZXYZXYZ abcabcab 29::: xyzxyzxyz XYZXYZXYZ abcabcab
+16<<< 123456789 xyzxyzxyz XYZXYZXY 30::: 456789 123456789 xyzxyzxyz X
+7<<< >>> 1::: 12345678 :::
+8<<< >>> 2::: 3456789 abcdefghi :::
+9<<< >>> 3::: 12345678 :::
+20<<< >>> 4::: 12345678 :::
+1<<< >>> 35::: 89 123456789 123456789 12345
+ 6::: 12345678 :::
+ 7::: 12345678 :::
+4<<< >>> 8::: 12345678 :::
+5<<< >>> 9::: 3456789 abcdefghi :::
+6<<< >>> 40::: DEFGHI 123456789 :::
+27<<< truncation before FF; (r_l-t 41::: yzxyzxyz XYZXYZXYZ abcabcab
+28<<< trunc 42::: 89 123456789 123456789 12345
+
+
+-- Date/Time -- x Page 4
+
+
+ 43::: xyzxyzxyz XYZXYZXYZ abcabcab
+ 44::: 456789 123456789 xyzxyzxyz X
+ 5::: 12345678 :::
+ 6::: 12345678 :::
+ 7::: 12345678 :::
+ 8::: 12345678 :::
+ 49::: 89 123456789 123456789 12345
+ 50::: 12345678 :::
+ 1::: 12345678 :::
+ 2::: 12345678 :::
+ 3::: 12345678 :::
+ 4::: 12345678 :::
+ 55::: yzxyzxyz XYZXYZXYZ abcabcab
+ 56::: 89 123456789 123456789 12345
+
+
+-- Date/Time -- x Page 5
+
+
+29<<<xyzxyzxyz XYZXYZXYZ abcabcab 57::: xyzxyzxyz XYZXYZXYZ abcabcab
+30<<< 123456789 xyzxyzxyz XYZXYZXY 58::: 456789 123456789 xyzxyzxyz X
+1<<< >>> 9::: 12345678 :::
+2<<< abcdefghi >>> 60::: DEFGHI 123456789 :::
+3<<< >>> 1::: :::
+4<<< >>> 2::: :::
+5<<< >>> 3::: ------- EOF -------- EOF ----
+6<<< >>>
+7<<< >>>
+8<<< >>>
+9<<< abcdefghi >>>
+40<<< 123456789 >>>
+41<<< XYZXYZXYZ abcabcab >>>
+42<<< 123456789 abcdefghi ABCDEDFH
+
+
+-- Date/Time -- x Page 6
+
+
+
+
+
+-- Date/Time -- x Page 7
+
+
+
+
+
+-- Date/Time -- x Page 8
+
+
+43<<< xyzxyzxyz XYZXYZXYZ abcabcab
+44<<< 123456789 xyzxyzxyz XYZXYZXY
+5<<< >>>
+6<<< >>>
+7<<< >>>
+8<<< >>>
+9<<< >>>
+50<<< >>>
+1<<< >>>
+2<<< >>>
+3<<< >>>
+4<<< >>>
+55<<< XYZXYZXYZ abcabcab >>>
+56<<< 123456789 abcdefghi ABCDEDFH
+
+
+-- Date/Time -- x Page 9
+
+
+57<<< xyzxyzxyz XYZXYZXYZ abcabcab
+58<<< 123456789 xyzxyzxyz XYZXYZXY
+9<<< >>>
+60<<< 123456789 >>>
+ \ No newline at end of file
diff --git a/tests/pr/ml24f-t b/tests/pr/ml24f-t
new file mode 100644
index 0000000..b856214
--- /dev/null
+++ b/tests/pr/ml24f-t
@@ -0,0 +1,89 @@
+
+
+-- Date/Time -- x Page 1
+
+
+1 Test-INPUT: "Without FF set by 1 Test-INPUT: "Without FF set by
+2 Options -b -3 [+2|+3] [-l 15|8] 2 Options -b -3 [+2|+3] [-l 15|8]
+3 Options -a -3 [+2|+3] [-l 15|8] 3 Options -a -3 [+2|+3] [-l 15|8]
+4 Options [+2|+3] [-l 24|17 4 Options [+2|+3] [-l 24|17
+5 5
+6 ------------------------------- 6 -------------------------------
+7 3456789 123456789 123456789 12345 7 3456789 123456789 123456789 12345
+8 3 Columns downwards, across, .. 8 3 Columns downwards, across, ..
+9 With columns use <= 5 text lin 9 With columns use <= 5 text lin
+10 without -f e.g.: -l 15 = total 10 without -f e.g.: -l 15 = total
+1 with -f e.g. : -l 8 -f 1 with -f e.g. : -l 8 -f
+2 2
+3 line truncation before new page; 3 line truncation before new page;
+14 456789 123456789 123456789 12345 14 456789 123456789 123456789 12345
+
+
+-- Date/Time -- x Page 2
+
+
+15 xyzxyzxyz XYZXYZXYZ abcabcab 15 xyzxyzxyz XYZXYZXYZ abcabcab
+16 456789 123456789 xyzxyzxyz XYZXY 16 456789 123456789 xyzxyzxyz XYZXY
+7 7
+8 8
+9 3456789 ab 9 3456789 ab
+20 DEFGHI 123 20 DEFGHI 123
+1 1
+2 2
+3 3
+4 4
+5 5
+6 6
+27 no truncation before nwe page; ( 27 no truncation before nwe page; (
+28 no trunc 28 no trunc
+
+
+-- Date/Time -- x Page 3
+
+
+29 xyzxyzxyz XYZXYZXYZ abcabcab 29 xyzxyzxyz XYZXYZXYZ abcabcab
+30 456789 123456789 xyzxyzxyz XYZXY 30 456789 123456789 xyzxyzxyz XYZXY
+1 1
+2 3456789 abcdefghi 2 3456789 abcdefghi
+3 3
+4 4
+5 5
+6 6
+7 7
+8 8
+9 3456789 abcdefghi 9 3456789 abcdefghi
+40 DEFGHI 123456789 40 DEFGHI 123456789
+41 yzxyzxyz XYZXYZXYZ abcabcab 41 yzxyzxyz XYZXYZXYZ abcabcab
+42 456789 123456789 abcdefghi ABCDE 42 456789 123456789 abcdefghi ABCDE
+
+
+-- Date/Time -- x Page 4
+
+
+43 xyzxyzxyz XYZXYZXYZ abcabcab 43 xyzxyzxyz XYZXYZXYZ abcabcab
+44 456789 123456789 xyzxyzxyz XYZXY 44 456789 123456789 xyzxyzxyz XYZXY
+5 5
+6 6
+7 7
+8 8
+9 9
+50 50
+1 1
+2 2
+3 3
+4 4
+55 yzxyzxyz XYZXYZXYZ abcabcab 55 yzxyzxyz XYZXYZXYZ abcabcab
+56 456789 123456789 abcdefghi ABCDE 56 456789 123456789 abcdefghi ABCDE
+
+
+-- Date/Time -- x Page 5
+
+
+57 xyzxyzxyz XYZXYZXYZ abcabcab 57 xyzxyzxyz XYZXYZXYZ abcabcab
+58 456789 123456789 xyzxyzxyz XYZXY 58 456789 123456789 xyzxyzxyz XYZXY
+9 9
+60 DEFGHI 123456789 60 DEFGHI 123456789
+1 1
+2 2
+3 ------- EOF -------- EOF ------- 3 ------- EOF -------- EOF -------
+ \ No newline at end of file
diff --git a/tests/pr/ml24f-t-0F b/tests/pr/ml24f-t-0F
new file mode 100644
index 0000000..bd803e2
--- /dev/null
+++ b/tests/pr/ml24f-t-0F
@@ -0,0 +1,89 @@
+
+
+-- Date/Time -- x Page 1
+
+
+1 Test-INPUT: "Without FF set by
+2 Options -b -3 [+2|+3] [-l 15|8]
+3 Options -a -3 [+2|+3] [-l 15|8]
+4 Options [+2|+3] [-l 24|17
+5
+6 -------------------------------
+7 3456789 123456789 123456789 12345
+8 3 Columns downwards, across, ..
+9 With columns use <= 5 text lin
+10 without -f e.g.: -l 15 = total
+1 with -f e.g. : -l 8 -f
+2
+3 line truncation before new page;
+14 456789 123456789 123456789 12345
+
+
+-- Date/Time -- x Page 2
+
+
+15 xyzxyzxyz XYZXYZXYZ abcabcab 1 FF-Test: FF's at Start of File
+16 456789 123456789 xyzxyzxyz XYZXY 2 Options -b -3 / -a -3 / ...
+7 3 -------------------------------
+8 4 3456789 123456789 123456789 12345
+9 3456789 ab 5 3 Columns downwards ..., <= 5 l
+20 DEFGHI 123 6 FF-Arangements: Empty Pages at
+1 7 \ftext; \f\ntext;
+2 8 \f\ftext; \f\f\ntext; \f\n\ftex
+3 9 3456789 123456789 123456789
+4 10 zzzzzzzzzzzzzzzzzzzzzzzzzz12345
+5 1
+6 2
+27 no truncation before nwe page; ( 3 line truncation before FF; r_r_o_
+28 no trunc 14 456789 123456789 123456789 12345
+
+
+-- Date/Time -- x Page 3
+
+
+29 xyzxyzxyz XYZXYZXYZ abcabcab
+30 456789 123456789 xyzxyzxyz XYZXY
+1
+2 3456789 abcdefghi
+3
+4
+5
+6
+7
+8
+9 3456789 abcdefghi
+40 DEFGHI 123456789
+41 yzxyzxyz XYZXYZXYZ abcabcab
+42 456789 123456789 abcdefghi ABCDE
+
+
+-- Date/Time -- x Page 4
+
+
+43 xyzxyzxyz XYZXYZXYZ abcabcab 15 xyzxyzxyz XYZXYZXYZ abcabcab
+44 456789 123456789 xyzxyzxyz XYZXY 16 456789 123456789 xyzxyzxyz XYZXY
+5 7
+6 8
+7 9 3456789 ab
+8 20 DEFGHI 123
+9 1
+50 2
+1 3
+2 4
+3 5
+4 6
+55 yzxyzxyz XYZXYZXYZ abcabcab 27 no truncation before FF; (r_l-te
+56 456789 123456789 abcdefghi ABCDE 28 no trunc
+
+
+-- Date/Time -- x Page 5
+
+
+57 xyzxyzxyz XYZXYZXYZ abcabcab 29 xyzxyzxyz XYZXYZXYZ abcabcab
+58 456789 123456789 xyzxyzxyz XYZXY 30 456789 123456789 xyzxyzxyz XYZXY
+9 1
+60 DEFGHI 123456789 2 3456789 abcdefghi
+1 3
+2
+3 ------- EOF -------- EOF -------
+ \ No newline at end of file
diff --git a/tests/pr/n+2-5l24f-0FF b/tests/pr/n+2-5l24f-0FF
new file mode 100644
index 0000000..653d578
--- /dev/null
+++ b/tests/pr/n+2-5l24f-0FF
@@ -0,0 +1,51 @@
+
+
+-- Date/Time -- x Page 2
+
+
+
+
+
+-- Date/Time -- x Page 3
+
+
+ 1.1 FF-Test: FF's at Start of File V
+ 2.2 Options -b -3 / -a -3 / ...
+ 3.3 --------------------------------------------
+ 4.4 3456789 123456789 123456789 123456789 12345678
+ 5.5 3 Columns downwards ..., <= 5 lines per page
+ 6.6 FF-Arangements: Empty Pages at start
+ 7.7 \ftext; \f\ntext;
+ 8.8 \f\ftext; \f\f\ntext; \f\n\ftext; \f\n\f\n;
+ 9.9 3456789 123456789 123456789
+ 10.10 zzzzzzzzzzzzzzzzzzzzzzzzzz123456789
+ 11.1 12345678
+ 12.2 12345678
+ 13.3 line truncation before FF; r_r_o_l-test:
+ 14.14 456789 123456789 123456789 123456789
+
+
+-- Date/Time -- x Page 4
+
+
+
+
+
+-- Date/Time -- x Page 5
+
+
+ 15.15 xyzxyzxyz XYZXYZXYZ abcabcab
+ 16.16 456789 123456789 xyzxyzxyz XYZXYZXYZ
+ 17.7 12345678
+ 18.8 12345678
+ 19.9 3456789 ab
+ 20.20 DEFGHI 123
+ 21.1 12345678
+ 22.2 12345678
+ 23.3 12345678
+ 24.4 12345678
+ 25.5 12345678
+ 26.6 12345678
+ 27.27 no truncation before FF; (r_l-test):
+ 28.28 no trunc
+ \ No newline at end of file
diff --git a/tests/pr/n+2l24f-0FF b/tests/pr/n+2l24f-0FF
new file mode 100644
index 0000000..4394e63
--- /dev/null
+++ b/tests/pr/n+2l24f-0FF
@@ -0,0 +1,61 @@
+
+
+-- Date/Time -- x Page 2
+
+
+
+
+
+-- Date/Time -- x Page 3
+
+
+ 1.1 FF-Test: FF's at Start of File V
+ 2.2 Options -b -3 / -a -3 / ...
+ 3.3 --------------------------------------------
+ 4.4 3456789 123456789 123456789 123456789 12345678
+ 5.5 3 Columns downwards ..., <= 5 lines per page
+ 6.6 FF-Arangements: Empty Pages at start
+ 7.7 \ftext; \f\ntext;
+ 8.8 \f\ftext; \f\f\ntext; \f\n\ftext; \f\n\f\n;
+ 9.9 3456789 123456789 123456789
+ 10.10 zzzzzzzzzzzzzzzzzzzzzzzzzz123456789
+ 11.1 12345678
+ 12.2 12345678
+ 13.3 line truncation before FF; r_r_o_l-test:
+ 14.14 456789 123456789 123456789 123456789
+
+
+-- Date/Time -- x Page 4
+
+
+
+
+
+-- Date/Time -- x Page 5
+
+
+ 15.15 xyzxyzxyz XYZXYZXYZ abcabcab
+ 16.16 456789 123456789 xyzxyzxyz XYZXYZXYZ
+ 17.7 12345678
+ 18.8 12345678
+ 19.9 3456789 ab
+ 20.20 DEFGHI 123
+ 21.1 12345678
+ 22.2 12345678
+ 23.3 12345678
+ 24.4 12345678
+ 25.5 12345678
+ 26.6 12345678
+ 27.27 no truncation before FF; (r_l-test):
+ 28.28 no trunc
+
+
+-- Date/Time -- x Page 6
+
+
+ 29.29 xyzxyzxyz XYZXYZXYZ abcabcab
+ 30.30 456789 123456789 xyzxyzxyz XYZXYZXYZ
+ 31.1 12345678
+ 32.2 3456789 abcdefghi
+ 33.3 12345678
+ \ No newline at end of file
diff --git a/tests/pr/n+2l24f-bl b/tests/pr/n+2l24f-bl
new file mode 100644
index 0000000..7eb114b
--- /dev/null
+++ b/tests/pr/n+2l24f-bl
@@ -0,0 +1,112 @@
+
+
+-- Date/Time -- x Page 2
+
+
+
+
+
+-- Date/Time -- x Page 3
+
+
+ 15.15 xyzxyzxyz XYZXYZXYZ abcabcab
+ 16.16 456789 123456789 xyzxyzxyz XYZXYZXYZ
+ 17.7 12345678
+ 18.8 12345678
+ 19.9 3456789 ab
+ 20.20 DEFGHI 123
+ 21.1 12345678
+ 22.
+ 23.
+ 24.4 12345678
+ 25.5 12345678
+ 26.6 12345678
+ 27.27 no truncation before FF; (r_l-test):
+ 28.
+
+
+-- Date/Time -- x Page 4
+
+
+
+
+
+-- Date/Time -- x Page 5
+
+
+ 29.29 xyzxyzxyz XYZXYZXYZ abcabcab
+ 30.30 456789 123456789 xyzxyzxyz XYZXYZXYZ
+ 31.1 12345678
+ 32.2 3456789 abcdefghi
+ 33.3 12345678
+ 34.4 12345678
+ 35.
+ 36.6 12345678
+ 37.7 12345678
+ 38.8 12345678
+ 39.9 3456789 abcdefghi
+ 40.40 DEFGHI 123456789
+ 41.41 yzxyzxyz XYZXYZXYZ abcabcab
+ 42.42 456789 123456789 abcdefghi ABCDEDFHI
+
+
+-- Date/Time -- x Page 6
+
+
+
+
+
+-- Date/Time -- x Page 7
+
+
+
+
+
+-- Date/Time -- x Page 8
+
+
+ 43.43 xyzxyzxyz XYZXYZXYZ abcabcab
+ 44.44 456789 123456789 xyzxyzxyz XYZXYZXYZ
+ 45.5 12345678
+ 46.6 12345678
+ 47.7 12345678
+ 48.8 12345678
+ 49.9 12345678
+ 50.50 12345678
+ 51.1 12345678
+ 52.
+ 53.
+ 54.
+ 55.55 yzxyzxyz XYZXYZXYZ abcabcab
+ 56.56 456789 123456789 abcdefghi ABCDEDFHI
+
+
+-- Date/Time -- x Page 9
+
+
+ 57.
+ 58.58 456789 123456789 xyzxyzxyz XYZXYZXYZ
+ 59.9 12345678
+ 60.60 DEFGHI 123456789
+ 61.61 yzxyzxyz XYZXYZXYZ abcabcab
+ 62.62 456789 123456789 abcdefghi ABCDEDFHI
+ 63.63 xyzxyzxyz XYZXYZXYZ abcabcab
+ 64.64 456789 123456789 xyzxyzxyz XYZXYZXYZ
+ 65.5 12345678
+ 66.6 12345678
+ 67.7 12345678
+ 68.8 12345678
+ 69.9 12345678
+ 70.70 456789 123456789 abcdefghi ABCDEDFHI
+
+
+-- Date/Time -- x Page 10
+
+
+ 71.1 12345678
+ 72.
+ 73.
+ 74.
+ 75.74 yzxyzxyz XYZXYZXYZ abcabcab
+ 76.75 456789 123456789 abcdefghi ABCDEDFHI
+ \ No newline at end of file
diff --git a/tests/pr/n+3-7l24-FF b/tests/pr/n+3-7l24-FF
new file mode 100644
index 0000000..b2cc15f
--- /dev/null
+++ b/tests/pr/n+3-7l24-FF
@@ -0,0 +1,120 @@
+
+
+-- Date/Time -- x Page 3
+
+
+ 15.15 xyzxyzxyz XYZXYZXYZ abcabcab
+ 16.16 456789 123456789 xyzxyzxyz XYZXYZXYZ
+ 17.7 12345678
+ 18.8 12345678
+ 19.9 3456789 ab
+ 20.20 DEFGHI 123
+ 21.1 12345678
+ 22.2 12345678
+ 23.3 12345678
+ 24.4 12345678
+ 25.5 12345678
+ 26.6 12345678
+ 27.27 no truncation before FF; (r_l-test):
+ 28.28 no trunc
+
+
+
+
+
+
+
+-- Date/Time -- x Page 4
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+-- Date/Time -- x Page 5
+
+
+ 29.29 xyzxyzxyz XYZXYZXYZ abcabcab
+ 30.30 456789 123456789 xyzxyzxyz XYZXYZXYZ
+ 31.1 12345678
+ 32.2 3456789 abcdefghi
+ 33.3 12345678
+ 34.4 12345678
+ 35.5 12345678
+ 36.6 12345678
+ 37.7 12345678
+ 38.8 12345678
+ 39.9 3456789 abcdefghi
+ 40.40 DEFGHI 123456789
+ 41.41 yzxyzxyz XYZXYZXYZ abcabcab
+ 42.42 456789 123456789 abcdefghi ABCDEDFHI
+
+
+
+
+
+
+
+-- Date/Time -- x Page 6
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+-- Date/Time -- x Page 7
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/tests/pr/n+3l24f-0FF b/tests/pr/n+3l24f-0FF
new file mode 100644
index 0000000..7440d4c
--- /dev/null
+++ b/tests/pr/n+3l24f-0FF
@@ -0,0 +1,55 @@
+
+
+-- Date/Time -- x Page 3
+
+
+ 1.1 FF-Test: FF's at Start of File V
+ 2.2 Options -b -3 / -a -3 / ...
+ 3.3 --------------------------------------------
+ 4.4 3456789 123456789 123456789 123456789 12345678
+ 5.5 3 Columns downwards ..., <= 5 lines per page
+ 6.6 FF-Arangements: Empty Pages at start
+ 7.7 \ftext; \f\ntext;
+ 8.8 \f\ftext; \f\f\ntext; \f\n\ftext; \f\n\f\n;
+ 9.9 3456789 123456789 123456789
+ 10.10 zzzzzzzzzzzzzzzzzzzzzzzzzz123456789
+ 11.1 12345678
+ 12.2 12345678
+ 13.3 line truncation before FF; r_r_o_l-test:
+ 14.14 456789 123456789 123456789 123456789
+
+
+-- Date/Time -- x Page 4
+
+
+
+
+
+-- Date/Time -- x Page 5
+
+
+ 15.15 xyzxyzxyz XYZXYZXYZ abcabcab
+ 16.16 456789 123456789 xyzxyzxyz XYZXYZXYZ
+ 17.7 12345678
+ 18.8 12345678
+ 19.9 3456789 ab
+ 20.20 DEFGHI 123
+ 21.1 12345678
+ 22.2 12345678
+ 23.3 12345678
+ 24.4 12345678
+ 25.5 12345678
+ 26.6 12345678
+ 27.27 no truncation before FF; (r_l-test):
+ 28.28 no trunc
+
+
+-- Date/Time -- x Page 6
+
+
+ 29.29 xyzxyzxyz XYZXYZXYZ abcabcab
+ 30.30 456789 123456789 xyzxyzxyz XYZXYZXYZ
+ 31.1 12345678
+ 32.2 3456789 abcdefghi
+ 33.3 12345678
+ \ No newline at end of file
diff --git a/tests/pr/n+3l24f-bl b/tests/pr/n+3l24f-bl
new file mode 100644
index 0000000..0675c5a
--- /dev/null
+++ b/tests/pr/n+3l24f-bl
@@ -0,0 +1,106 @@
+
+
+-- Date/Time -- x Page 3
+
+
+ 15.15 xyzxyzxyz XYZXYZXYZ abcabcab
+ 16.16 456789 123456789 xyzxyzxyz XYZXYZXYZ
+ 17.7 12345678
+ 18.8 12345678
+ 19.9 3456789 ab
+ 20.20 DEFGHI 123
+ 21.1 12345678
+ 22.
+ 23.
+ 24.4 12345678
+ 25.5 12345678
+ 26.6 12345678
+ 27.27 no truncation before FF; (r_l-test):
+ 28.
+
+
+-- Date/Time -- x Page 4
+
+
+
+
+
+-- Date/Time -- x Page 5
+
+
+ 29.29 xyzxyzxyz XYZXYZXYZ abcabcab
+ 30.30 456789 123456789 xyzxyzxyz XYZXYZXYZ
+ 31.1 12345678
+ 32.2 3456789 abcdefghi
+ 33.3 12345678
+ 34.4 12345678
+ 35.
+ 36.6 12345678
+ 37.7 12345678
+ 38.8 12345678
+ 39.9 3456789 abcdefghi
+ 40.40 DEFGHI 123456789
+ 41.41 yzxyzxyz XYZXYZXYZ abcabcab
+ 42.42 456789 123456789 abcdefghi ABCDEDFHI
+
+
+-- Date/Time -- x Page 6
+
+
+
+
+
+-- Date/Time -- x Page 7
+
+
+
+
+
+-- Date/Time -- x Page 8
+
+
+ 43.43 xyzxyzxyz XYZXYZXYZ abcabcab
+ 44.44 456789 123456789 xyzxyzxyz XYZXYZXYZ
+ 45.5 12345678
+ 46.6 12345678
+ 47.7 12345678
+ 48.8 12345678
+ 49.9 12345678
+ 50.50 12345678
+ 51.1 12345678
+ 52.
+ 53.
+ 54.
+ 55.55 yzxyzxyz XYZXYZXYZ abcabcab
+ 56.56 456789 123456789 abcdefghi ABCDEDFHI
+
+
+-- Date/Time -- x Page 9
+
+
+ 57.
+ 58.58 456789 123456789 xyzxyzxyz XYZXYZXYZ
+ 59.9 12345678
+ 60.60 DEFGHI 123456789
+ 61.61 yzxyzxyz XYZXYZXYZ abcabcab
+ 62.62 456789 123456789 abcdefghi ABCDEDFHI
+ 63.63 xyzxyzxyz XYZXYZXYZ abcabcab
+ 64.64 456789 123456789 xyzxyzxyz XYZXYZXYZ
+ 65.5 12345678
+ 66.6 12345678
+ 67.7 12345678
+ 68.8 12345678
+ 69.9 12345678
+ 70.70 456789 123456789 abcdefghi ABCDEDFHI
+
+
+-- Date/Time -- x Page 10
+
+
+ 71.1 12345678
+ 72.
+ 73.
+ 74.
+ 75.74 yzxyzxyz XYZXYZXYZ abcabcab
+ 76.75 456789 123456789 abcdefghi ABCDEDFHI
+ \ No newline at end of file
diff --git a/tests/pr/n+3ml20f-bl-FF b/tests/pr/n+3ml20f-bl-FF
new file mode 100644
index 0000000..fc2e720
--- /dev/null
+++ b/tests/pr/n+3ml20f-bl-FF
@@ -0,0 +1,127 @@
+
+
+-- Date/Time -- x Page 3
+
+
+
+
+
+-- Date/Time -- x Page 4
+
+
+ 15.15 xyzxyzxyz XYZXYZXYZ abcabcab 15 xyzxyzxyz XYZXYZXYZ abcabcab
+ 16.16 456789 123456789 xyzxyzxyz XYZ 16 456789 123456789 xyzxyzxyz XYZ
+ 17.7 7
+ 18.8 8
+ 19.9 3456789 ab 9 3456789 ab
+ 20.20 DEFGHI 123 20 DEFGHI 123
+ 21.1 1
+ 22. 2
+ 23. 3
+ 24.4 4
+
+
+-- Date/Time -- x Page 5
+
+
+ 25.5 5
+ 26.6 6
+ 27.27 no truncation before FF; (r_l- 27 no truncation before FF; (r_l-
+ 28. 28 no trunc
+
+
+-- Date/Time -- x Page 6
+
+
+
+
+
+-- Date/Time -- x Page 7
+
+
+ 29.29 xyzxyzxyz XYZXYZXYZ abcabcab 29 xyzxyzxyz XYZXYZXYZ abcabcab
+ 30.30 456789 123456789 xyzxyzxyz XYZ 30 456789 123456789 xyzxyzxyz XYZ
+ 31.1 1
+ 32.2 3456789 abcdefghi 2 3456789 abcdefghi
+ 33.3 3
+ 34.4 4
+ 35. 5
+ 36.6 6
+ 37.7 7
+ 38.8 8
+
+
+-- Date/Time -- x Page 8
+
+
+ 39.9 3456789 abcdefghi 9 3456789 abcdefghi
+ 40.40 DEFGHI 123456789 40 DEFGHI 123456789
+ 41.41 yzxyzxyz XYZXYZXYZ abcabcab 41 yzxyzxyz XYZXYZXYZ abcabcab
+ 42.42 456789 123456789 abcdefghi ABC 42 456789 123456789 abcdefghi ABC
+
+
+-- Date/Time -- x Page 9
+
+
+
+
+
+-- Date/Time -- x Page 10
+
+
+
+
+
+-- Date/Time -- x Page 11
+
+
+ 43.43 xyzxyzxyz XYZXYZXYZ abcabcab 43 xyzxyzxyz XYZXYZXYZ abcabcab
+ 44.44 456789 123456789 xyzxyzxyz XYZ 44 456789 123456789 xyzxyzxyz XYZ
+ 45.5 5
+ 46.6 6
+ 47.7 7
+ 48.8 8
+ 49.9 9
+ 50.50 50
+ 51.1 1
+ 52. 2
+
+
+-- Date/Time -- x Page 12
+
+
+ 53. 3
+ 54. 4
+ 55.55 yzxyzxyz XYZXYZXYZ abcabcab 55 yzxyzxyz XYZXYZXYZ abcabcab
+ 56.56 456789 123456789 abcdefghi ABC 56 456789 123456789 abcdefghi ABC
+
+
+-- Date/Time -- x Page 13
+
+
+ 57. 57 xyzxyzxyz XYZXYZXYZ abcabcab
+ 58.58 456789 123456789 xyzxyzxyz XYZ 58 456789 123456789 xyzxyzxyz XYZ
+ 59.9 9
+ 60.60 DEFGHI 123456789 60 DEFGHI 123456789
+ 61.61 yzxyzxyz XYZXYZXYZ abcabcab
+ 62.62 456789 123456789 abcdefghi ABC
+ 63.63 xyzxyzxyz XYZXYZXYZ abcabcab
+ 64.64 456789 123456789 xyzxyzxyz XYZ
+ 65.5
+ 66.6
+
+
+-- Date/Time -- x Page 14
+
+
+ 67.7
+ 68.8
+ 69.9
+ 70.70 456789 123456789 abcdefghi AB
+ 71.1
+ 72.
+ 73.
+ 74.
+ 75.74 yzxyzxyz XYZXYZXYZ abcabcab
+ 76.75 456789 123456789 abcdefghi ABC
+ \ No newline at end of file
diff --git a/tests/pr/n+3ml24f-bl-tn b/tests/pr/n+3ml24f-bl-tn
new file mode 100644
index 0000000..4346035
--- /dev/null
+++ b/tests/pr/n+3ml24f-bl-tn
@@ -0,0 +1,119 @@
+
+
+-- Date/Time -- x Page 3
+
+
+ 15.15 xyzxyzxyz XYZXYZXYZ abcabcab 29 xyzxyzxyz XYZXYZXYZ abcabcab
+ 16.16 456789 123456789 xyzxyzxyz XYZ 30 456789 123456789 xyzxyzxyz XYZ
+ 17.7 1
+ 18.8 2 3456789 abcdefghi
+ 19.9 3456789 ab 3
+ 20.20 DEFGHI 123 4
+ 21.1 5
+ 22. 6
+ 23. 7
+ 24.4 8
+ 25.5 9 3456789 abcdefghi
+ 26.6 40 DEFGHI 123456789
+ 27.27 no truncation before FF; (r_l- 41 yzxyzxyz XYZXYZXYZ abcabcab
+ 28. 42 456789 123456789 abcdefghi ABC
+
+
+-- Date/Time -- x Page 4
+
+
+ 29. 43 xyzxyzxyz XYZXYZXYZ abcabcab
+ 30. 44 456789 123456789 xyzxyzxyz XYZ
+ 31. 5
+ 32. 6
+ 33. 7
+ 34. 8
+ 35. 9
+ 36. 50
+ 37. 1
+ 38. 2
+ 39. 3
+ 40. 4
+ 41. 55 yzxyzxyz XYZXYZXYZ abcabcab
+ 42. 56 456789 123456789 abcdefghi ABC
+
+
+-- Date/Time -- x Page 5
+
+
+ 43.29 xyzxyzxyz XYZXYZXYZ abcabcab 57 xyzxyzxyz XYZXYZXYZ abcabcab
+ 44.30 456789 123456789 xyzxyzxyz XYZ 58 456789 123456789 xyzxyzxyz XYZ
+ 45.1 9
+ 46.2 3456789 abcdefghi 60 DEFGHI 123456789
+ 47.3 1
+ 48.4 2
+ 49. 3 ------- EOF -------- EOF -----
+ 50.6
+ 51.7
+ 52.8
+ 53.9 3456789 abcdefghi
+ 54.40 DEFGHI 123456789
+ 55.41 yzxyzxyz XYZXYZXYZ abcabcab
+ 56.42 456789 123456789 abcdefghi ABC
+
+
+-- Date/Time -- x Page 6
+
+
+
+
+
+-- Date/Time -- x Page 7
+
+
+
+
+
+-- Date/Time -- x Page 8
+
+
+ 57.43 xyzxyzxyz XYZXYZXYZ abcabcab
+ 58.44 456789 123456789 xyzxyzxyz XYZ
+ 59.5
+ 60.6
+ 61.7
+ 62.8
+ 63.9
+ 64.50
+ 65.1
+ 66.
+ 67.
+ 68.
+ 69.55 yzxyzxyz XYZXYZXYZ abcabcab
+ 70.56 456789 123456789 abcdefghi ABC
+
+
+-- Date/Time -- x Page 9
+
+
+ 71.
+ 72.58 456789 123456789 xyzxyzxyz XYZ
+ 73.9
+ 74.60 DEFGHI 123456789
+ 75.61 yzxyzxyz XYZXYZXYZ abcabcab
+ 76.62 456789 123456789 abcdefghi ABC
+ 77.63 xyzxyzxyz XYZXYZXYZ abcabcab
+ 78.64 456789 123456789 xyzxyzxyz XYZ
+ 79.5
+ 80.6
+ 81.7
+ 82.8
+ 83.9
+ 84.70 456789 123456789 abcdefghi AB
+
+
+-- Date/Time -- x Page 10
+
+
+ 85.1
+ 86.
+ 87.
+ 88.
+ 89.74 yzxyzxyz XYZXYZXYZ abcabcab
+ 90.75 456789 123456789 abcdefghi ABC
+ \ No newline at end of file
diff --git a/tests/pr/n+3ml24f-tn-bl b/tests/pr/n+3ml24f-tn-bl
new file mode 100644
index 0000000..76bcf93
--- /dev/null
+++ b/tests/pr/n+3ml24f-tn-bl
@@ -0,0 +1,119 @@
+
+
+-- Date/Time -- x Page 3
+
+
+ 29.29 xyzxyzxyz XYZXYZXYZ abcabcab 15 xyzxyzxyz XYZXYZXYZ abcabcab
+ 30.30 456789 123456789 xyzxyzxyz XYZ 16 456789 123456789 xyzxyzxyz XYZ
+ 31.1 7
+ 32.2 3456789 abcdefghi 8
+ 33.3 9 3456789 ab
+ 34.4 20 DEFGHI 123
+ 35.5 1
+ 36.6
+ 37.7
+ 38.8 4
+ 39.9 3456789 abcdefghi 5
+ 40.40 DEFGHI 123456789 6
+ 41.41 yzxyzxyz XYZXYZXYZ abcabcab 27 no truncation before FF; (r_l-
+ 42.42 456789 123456789 abcdefghi ABC
+
+
+-- Date/Time -- x Page 4
+
+
+ 43.43 xyzxyzxyz XYZXYZXYZ abcabcab
+ 44.44 456789 123456789 xyzxyzxyz XYZ
+ 45.5
+ 46.6
+ 47.7
+ 48.8
+ 49.9
+ 50.50
+ 51.1
+ 52.2
+ 53.3
+ 54.4
+ 55.55 yzxyzxyz XYZXYZXYZ abcabcab
+ 56.56 456789 123456789 abcdefghi ABC
+
+
+-- Date/Time -- x Page 5
+
+
+ 57.57 xyzxyzxyz XYZXYZXYZ abcabcab 29 xyzxyzxyz XYZXYZXYZ abcabcab
+ 58.58 456789 123456789 xyzxyzxyz XYZ 30 456789 123456789 xyzxyzxyz XYZ
+ 59.9 1
+ 60.60 DEFGHI 123456789 2 3456789 abcdefghi
+ 61.1 3
+ 62.2 4
+ 63.3 ------- EOF -------- EOF -----
+ 64. 6
+ 65. 7
+ 66. 8
+ 67. 9 3456789 abcdefghi
+ 68. 40 DEFGHI 123456789
+ 69. 41 yzxyzxyz XYZXYZXYZ abcabcab
+ 70. 42 456789 123456789 abcdefghi ABC
+
+
+-- Date/Time -- x Page 6
+
+
+
+
+
+-- Date/Time -- x Page 7
+
+
+
+
+
+-- Date/Time -- x Page 8
+
+
+ 71. 43 xyzxyzxyz XYZXYZXYZ abcabcab
+ 72. 44 456789 123456789 xyzxyzxyz XYZ
+ 73. 5
+ 74. 6
+ 75. 7
+ 76. 8
+ 77. 9
+ 78. 50
+ 79. 1
+ 80.
+ 81.
+ 82.
+ 83. 55 yzxyzxyz XYZXYZXYZ abcabcab
+ 84. 56 456789 123456789 abcdefghi ABC
+
+
+-- Date/Time -- x Page 9
+
+
+ 85.
+ 86. 58 456789 123456789 xyzxyzxyz XYZ
+ 87. 9
+ 88. 60 DEFGHI 123456789
+ 89. 61 yzxyzxyz XYZXYZXYZ abcabcab
+ 90. 62 456789 123456789 abcdefghi ABC
+ 91. 63 xyzxyzxyz XYZXYZXYZ abcabcab
+ 92. 64 456789 123456789 xyzxyzxyz XYZ
+ 93. 5
+ 94. 6
+ 95. 7
+ 96. 8
+ 97. 9
+ 98. 70 456789 123456789 abcdefghi AB
+
+
+-- Date/Time -- x Page 10
+
+
+ 99. 1
+100.
+101.
+102.
+103. 74 yzxyzxyz XYZXYZXYZ abcabcab
+104. 75 456789 123456789 abcdefghi ABC
+ \ No newline at end of file
diff --git a/tests/pr/n+4-8a2l17-FF b/tests/pr/n+4-8a2l17-FF
new file mode 100644
index 0000000..09b76fc
--- /dev/null
+++ b/tests/pr/n+4-8a2l17-FF
@@ -0,0 +1,85 @@
+
+
+-- Date/Time -- x Page 4
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+-- Date/Time -- x Page 5
+
+
+ 29.29 xyzxyzxyz XYZXYZXYZ abcabcab 30.30 456789 123456789 xyzxyzxyz X
+ 31.1 32.2 3456789 abcdefghi
+ 33.3 34.4
+ 35.5 36.6
+ 37.7 38.8
+ 39.9 3456789 abcdefghi 40.40 DEFGHI 123456789
+ 41.41 yzxyzxyz XYZXYZXYZ abcabcab 42.42 456789 123456789 abcdefghi A
+
+
+
+
+
+
+
+-- Date/Time -- x Page 6
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+-- Date/Time -- x Page 7
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+-- Date/Time -- x Page 8
+
+
+ 43.43 xyzxyzxyz XYZXYZXYZ abcabcab 44.44 456789 123456789 xyzxyzxyz X
+ 45.5 46.6
+ 47.7 48.8
+ 49.9 50.50
+ 51.1 52.2
+ 53.3 54.4
+ 55.55 yzxyzxyz XYZXYZXYZ abcabcab 56.56 456789 123456789 abcdefghi A
+
+
+
+
+
diff --git a/tests/pr/n+4b2l17f-0FF b/tests/pr/n+4b2l17f-0FF
new file mode 100644
index 0000000..ecc974d
--- /dev/null
+++ b/tests/pr/n+4b2l17f-0FF
@@ -0,0 +1,27 @@
+
+
+-- Date/Time -- x Page 4
+
+
+
+
+
+-- Date/Time -- x Page 5
+
+
+ 15.15 xyzxyzxyz XYZXYZXYZ abcabcab 22.2
+ 16.16 456789 123456789 xyzxyzxyz X 23.3
+ 17.7 24.4
+ 18.8 25.5
+ 19.9 3456789 ab 26.6
+ 20.20 DEFGHI 123 27.27 no truncation before FF; (r_
+ 21.1 28.28 no trunc
+
+
+-- Date/Time -- x Page 6
+
+
+ 29.29 xyzxyzxyz XYZXYZXYZ abcabcab 32.2 3456789 abcdefghi
+ 30.30 456789 123456789 xyzxyzxyz X 33.3
+ 31.1
+ \ No newline at end of file
diff --git a/tests/pr/n+5-8b3l17f-FF b/tests/pr/n+5-8b3l17f-FF
new file mode 100644
index 0000000..2fb2286
--- /dev/null
+++ b/tests/pr/n+5-8b3l17f-FF
@@ -0,0 +1,33 @@
+
+
+-- Date/Time -- x Page 5
+
+
+ 29.29 xyzxyzxyz XYZXYZ 34.4 39.9 3456789 abcdefghi
+ 30.30 456789 123456789 35.5 40.40 DEFGHI 123456789
+ 31.1 36.6 41.41 yzxyzxyz XYZXYZX
+ 32.2 3456789 abcdefghi 37.7 42.42 456789 123456789
+ 33.3 38.8
+
+
+-- Date/Time -- x Page 6
+
+
+
+
+
+-- Date/Time -- x Page 7
+
+
+
+
+
+-- Date/Time -- x Page 8
+
+
+ 43.43 xyzxyzxyz XYZXYZ 48.8 53.3
+ 44.44 456789 123456789 49.9 54.4
+ 45.5 50.50 55.55 yzxyzxyz XYZXYZX
+ 46.6 51.1 56.56 456789 123456789
+ 47.7 52.2
+ \ No newline at end of file
diff --git a/tests/pr/n+5a3l13f-0FF b/tests/pr/n+5a3l13f-0FF
new file mode 100644
index 0000000..db19871
--- /dev/null
+++ b/tests/pr/n+5a3l13f-0FF
@@ -0,0 +1,29 @@
+
+
+-- Date/Time -- x Page 5
+
+
+
+
+
+-- Date/Time -- x Page 6
+
+
+ 15.15 xyzxyzxyz XYZXYZ 16.16 456789 123456789 17.7
+ 18.8 19.9 3456789 ab 20.20 DEFGHI 123
+ 21.1 22.2 23.3
+
+
+-- Date/Time -- x Page 7
+
+
+ 24.4 25.5 26.6
+ 27.27 no truncation be 28.28 no trunc
+
+
+-- Date/Time -- x Page 8
+
+
+ 29.29 xyzxyzxyz XYZXYZ 30.30 456789 123456789 31.1
+ 32.2 3456789 abcdefghi 33.3
+ \ No newline at end of file
diff --git a/tests/pr/n+6a2l17-FF b/tests/pr/n+6a2l17-FF
new file mode 100644
index 0000000..1cd68f7
--- /dev/null
+++ b/tests/pr/n+6a2l17-FF
@@ -0,0 +1,68 @@
+
+
+-- Date/Time -- x Page 6
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+-- Date/Time -- x Page 7
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+-- Date/Time -- x Page 8
+
+
+ 43.43 xyzxyzxyz XYZXYZXYZ abcabcab 44.44 456789 123456789 xyzxyzxyz X
+ 45.5 46.6
+ 47.7 48.8
+ 49.9 50.50
+ 51.1 52.2
+ 53.3 54.4
+ 55.55 yzxyzxyz XYZXYZXYZ abcabcab 56.56 456789 123456789 abcdefghi A
+
+
+
+
+
+
+
+-- Date/Time -- x Page 9
+
+
+ 57.57 xyzxyzxyz XYZXYZXYZ abcabcab 58.58 456789 123456789 xyzxyzxyz X
+ 59.9 60.60 DEFGHI 123456789
+
+
+
+
+
+
+
+
+
+
diff --git a/tests/pr/n+6b3l13f-FF b/tests/pr/n+6b3l13f-FF
new file mode 100644
index 0000000..0795673
--- /dev/null
+++ b/tests/pr/n+6b3l13f-FF
@@ -0,0 +1,56 @@
+
+
+-- Date/Time -- x Page 6
+
+
+
+
+
+-- Date/Time -- x Page 7
+
+
+ 29.29 xyzxyzxyz XYZXYZ 32.2 3456789 abcdefghi 35.5
+ 30.30 456789 123456789 33.3 36.6
+ 31.1 34.4 37.7
+
+
+-- Date/Time -- x Page 8
+
+
+ 38.8 40.40 DEFGHI 123456789 42.42 456789 123456789
+ 39.9 3456789 abcdefghi 41.41 yzxyzxyz XYZXYZX
+
+
+-- Date/Time -- x Page 9
+
+
+
+
+
+-- Date/Time -- x Page 10
+
+
+
+
+
+-- Date/Time -- x Page 11
+
+
+ 43.43 xyzxyzxyz XYZXYZ 46.6 49.9
+ 44.44 456789 123456789 47.7 50.50
+ 45.5 48.8 51.1
+
+
+-- Date/Time -- x Page 12
+
+
+ 52.2 54.4 56.56 456789 123456789
+ 53.3 55.55 yzxyzxyz XYZXYZX
+
+
+-- Date/Time -- x Page 13
+
+
+ 57.57 xyzxyzxyz XYZXYZ 59.9 60.60 DEFGHI 123456789
+ 58.58 456789 123456789
+ \ No newline at end of file
diff --git a/tests/pr/n+7l24-FF b/tests/pr/n+7l24-FF
new file mode 100644
index 0000000..e4a6e01
--- /dev/null
+++ b/tests/pr/n+7l24-FF
@@ -0,0 +1,72 @@
+
+
+-- Date/Time -- x Page 7
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+-- Date/Time -- x Page 8
+
+
+ 43.43 xyzxyzxyz XYZXYZXYZ abcabcab
+ 44.44 456789 123456789 xyzxyzxyz XYZXYZXYZ
+ 45.5 12345678
+ 46.6 12345678
+ 47.7 12345678
+ 48.8 12345678
+ 49.9 12345678
+ 50.50 12345678
+ 51.1 12345678
+ 52.2 12345678
+ 53.3 12345678
+ 54.4 12345678
+ 55.55 yzxyzxyz XYZXYZXYZ abcabcab
+ 56.56 456789 123456789 abcdefghi ABCDEDFHI
+
+
+
+
+
+
+
+-- Date/Time -- x Page 9
+
+
+ 57.57 xyzxyzxyz XYZXYZXYZ abcabcab
+ 58.58 456789 123456789 xyzxyzxyz XYZXYZXYZ
+ 59.9 12345678
+ 60.60 DEFGHI 123456789
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/tests/pr/n+8l20-FF b/tests/pr/n+8l20-FF
new file mode 100644
index 0000000..cad0470
--- /dev/null
+++ b/tests/pr/n+8l20-FF
@@ -0,0 +1,120 @@
+
+
+-- Date/Time -- x Page 8
+
+
+ 39.9 3456789 abcdefghi
+ 40.40 DEFGHI 123456789
+ 41.41 yzxyzxyz XYZXYZXYZ abcabcab
+ 42.42 456789 123456789 abcdefghi ABCDEDFHI
+
+
+
+
+
+
+
+
+
+
+
+
+
+-- Date/Time -- x Page 9
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+-- Date/Time -- x Page 10
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+-- Date/Time -- x Page 11
+
+
+ 43.43 xyzxyzxyz XYZXYZXYZ abcabcab
+ 44.44 456789 123456789 xyzxyzxyz XYZXYZXYZ
+ 45.5 12345678
+ 46.6 12345678
+ 47.7 12345678
+ 48.8 12345678
+ 49.9 12345678
+ 50.50 12345678
+ 51.1 12345678
+ 52.2 12345678
+
+
+
+
+
+
+
+-- Date/Time -- x Page 12
+
+
+ 53.3 12345678
+ 54.4 12345678
+ 55.55 yzxyzxyz XYZXYZXYZ abcabcab
+ 56.56 456789 123456789 abcdefghi ABCDEDFHI
+
+
+
+
+
+
+
+
+
+
+
+
+
+-- Date/Time -- x Page 13
+
+
+ 57.57 xyzxyzxyz XYZXYZXYZ abcabcab
+ 58.58 456789 123456789 xyzxyzxyz XYZXYZXYZ
+ 59.9 12345678
+ 60.60 DEFGHI 123456789
+
+
+
+
+
+
+
+
+
+
+
diff --git a/tests/pr/nJml24f-lmlmlo b/tests/pr/nJml24f-lmlmlo
new file mode 100644
index 0000000..0b515db
--- /dev/null
+++ b/tests/pr/nJml24f-lmlmlo
@@ -0,0 +1,136 @@
+
+
+-- Date/Time -- x Page 1
+
+
+ 1.1<<< -Test: FF's in Text >>> 1<<< -Test: FF's in Text >>> 1::: Test-INPUT: "Without FF set by Hand" :::
+ 2.2<<< -b -3 / -a -3 / ... >>> 2<<< -b -3 / -a -3 / ... >>> 2::: Options -b -3 [+2|+3] [-l 15|8] [-f] :::
+ 3.3<<< >>> 3<<< >>> 3::: Options -a -3 [+2|+3] [-l 15|8] [-f] :::
+ 4.4<<< 123456789 123456789 123456789 12345678 >>> 4<<< 123456789 123456789 123456789 12345678 >>> 4::: Options [+2|+3] [-l 24|17] [-f] :::
+ 5. 5::: :::
+ 6.6<<< -Arangements: One Empty Page >>> 6<<< -Arangements: One Empty Page >>> 6::: -------------------------------------------- :::
+ 7.7<<< \f\f\n; text\f\n\ftext; \f\ftext; >>> 7<<< \f\f\n; text\f\n\ftext; \f\ftext; >>> 7::: 789 123456789 123456789 123456789 123456789 123456789 123456789 1234567890 :::
+ 8.8<<< f\f\n; \f\n\f\n; >>> 8<<< f\f\n; \f\n\f\n; >>> 8::: 3 Columns downwards, across, ...: :::
+ 9.9<<< >>> 9<<< >>> 9::: With columns use <= 5 text lines/page, :::
+ 10.10<<< >>> 10<<< >>> 10::: without -f e.g.: -l 15 = total lines/page, :::
+ 11.1<<< >>> 1<<< >>> 1::: with -f e.g. : -l 8 -f :::
+ 12.2<<< >>> 2<<< >>> 2::: :::
+ 13.3<<< truncation before FF; r_r_o_l-test: >>> 3<<< truncation before FF; r_r_o_l-test: >>> 3::: line truncation before new page; r_r_o_l-test: :::
+ 14.14<<< 123456789 123456789 123456789 >>> 14<<< 123456789 123456789 123456789 >>> 14::: 89 123456789 123456789 123456789 123456789 123456789 123456789 1234567890 :::
+
+
+-- Date/Time -- x Page 2
+
+
+ 15. 15::: xyzxyzxyz XYZXYZXYZ abcabcab :::
+ 16. 16::: 456789 123456789 xyzxyzxyz XYZXYZXYZ :::
+ 17. 7::: 12345678 :::
+ 18. 8::: 12345678 :::
+ 19. 9::: 3456789 ab :::
+ 20. 20::: DEFGHI 123 :::
+ 21. 21::: 89 123456789 123456789 123456789 123456789 123456789 123456789 1234567890 :::
+ 22. 2::: 12345678 :::
+ 23. 3::: 12345678 :::
+ 24. 4::: 12345678 :::
+ 25. 5::: 12345678 :::
+ 26. 6::: 12345678 :::
+ 27. 27::: no truncation before nwe page; (r_l-test): :::
+ 28. 28::: 89 123456789 123456789 123456789 123456789 123456789 123456789 1234567890 :::
+
+
+-- Date/Time -- x Page 3
+
+
+ 29.15<<< xyzxyzxyz XYZXYZXYZ abcabcab >>> 15<<< xyzxyzxyz XYZXYZXYZ abcabcab >>> 29::: xyzxyzxyz XYZXYZXYZ abcabcab :::
+ 30.16<<< 123456789 xyzxyzxyz XYZXYZXYZ >>> 16<<< 123456789 xyzxyzxyz XYZXYZXYZ >>> 30::: 456789 123456789 xyzxyzxyz XYZXYZXYZ :::
+ 31.7<<< >>> 7<<< >>> 1::: 12345678 :::
+ 32.8<<< >>> 8<<< >>> 2::: 3456789 abcdefghi :::
+ 33.9<<< >>> 9<<< >>> 3::: 12345678 :::
+ 34.20<<< >>> 20<<< >>> 4::: 12345678 :::
+ 35.1<<< >>> 1<<< >>> 35::: 89 123456789 123456789 123456789 123456789 123456789 123456789 1234567890 :::
+ 36. 6::: 12345678 :::
+ 37. 7::: 12345678 :::
+ 38.4<<< >>> 4<<< >>> 8::: 12345678 :::
+ 39.5<<< >>> 5<<< >>> 9::: 3456789 abcdefghi :::
+ 40.6<<< >>> 6<<< >>> 40::: DEFGHI 123456789 :::
+ 41.27<<< truncation before FF; (r_l-test): >>> 27<<< truncation before FF; (r_l-test): >>> 41::: yzxyzxyz XYZXYZXYZ abcabcab :::
+ 42.28<<< trunc 28<<< trunc 42::: 89 123456789 123456789 123456789 123456789 123456789 123456789 1234567890 :::
+
+
+-- Date/Time -- x Page 4
+
+
+ 43. 43::: xyzxyzxyz XYZXYZXYZ abcabcab :::
+ 44. 44::: 456789 123456789 xyzxyzxyz XYZXYZXYZ :::
+ 45. 5::: 12345678 :::
+ 46. 6::: 12345678 :::
+ 47. 7::: 12345678 :::
+ 48. 8::: 12345678 :::
+ 49. 49::: 89 123456789 123456789 123456789 123456789 123456789 123456789 1234567890 :::
+ 50. 50::: 12345678 :::
+ 51. 1::: 12345678 :::
+ 52. 2::: 12345678 :::
+ 53. 3::: 12345678 :::
+ 54. 4::: 12345678 :::
+ 55. 55::: yzxyzxyz XYZXYZXYZ abcabcab :::
+ 56. 56::: 89 123456789 123456789 123456789 123456789 123456789 123456789 1234567890 :::
+
+
+-- Date/Time -- x Page 5
+
+
+ 57.29<<<xyzxyzxyz XYZXYZXYZ abcabcab >>> 29<<<xyzxyzxyz XYZXYZXYZ abcabcab >>> 57::: xyzxyzxyz XYZXYZXYZ abcabcab :::
+ 58.30<<< 123456789 xyzxyzxyz XYZXYZXYZ >>> 30<<< 123456789 xyzxyzxyz XYZXYZXYZ >>> 58::: 456789 123456789 xyzxyzxyz XYZXYZXYZ :::
+ 59.1<<< >>> 1<<< >>> 9::: 12345678 :::
+ 60.2<<< abcdefghi >>> 2<<< abcdefghi >>> 60::: DEFGHI 123456789 :::
+ 61.3<<< >>> 3<<< >>> 1::: :::
+ 62.4<<< >>> 4<<< >>> 2::: :::
+ 63.5<<< >>> 5<<< >>> 3::: ------- EOF -------- EOF -------- EOF ------- EOF ------- EOF ------- EOF :::
+ 64.6<<< >>> 6<<< >>>
+ 65.7<<< >>> 7<<< >>>
+ 66.8<<< >>> 8<<< >>>
+ 67.9<<< abcdefghi >>> 9<<< abcdefghi >>>
+ 68.40<<< 123456789 >>> 40<<< 123456789 >>>
+ 69.41<<< XYZXYZXYZ abcabcab >>> 41<<< XYZXYZXYZ abcabcab >>>
+ 70.42<<< 123456789 abcdefghi ABCDEDFHI >>> 42<<< 123456789 abcdefghi ABCDEDFHI >>>
+
+
+-- Date/Time -- x Page 6
+
+
+
+
+
+-- Date/Time -- x Page 7
+
+
+
+
+
+-- Date/Time -- x Page 8
+
+
+ 71.43<<< xyzxyzxyz XYZXYZXYZ abcabcab >>> 43<<< xyzxyzxyz XYZXYZXYZ abcabcab >>>
+ 72.44<<< 123456789 xyzxyzxyz XYZXYZXYZ >>> 44<<< 123456789 xyzxyzxyz XYZXYZXYZ >>>
+ 73.5<<< >>> 5<<< >>>
+ 74.6<<< >>> 6<<< >>>
+ 75.7<<< >>> 7<<< >>>
+ 76.8<<< >>> 8<<< >>>
+ 77.9<<< >>> 9<<< >>>
+ 78.50<<< >>> 50<<< >>>
+ 79.1<<< >>> 1<<< >>>
+ 80.2<<< >>> 2<<< >>>
+ 81.3<<< >>> 3<<< >>>
+ 82.4<<< >>> 4<<< >>>
+ 83.55<<< XYZXYZXYZ abcabcab >>> 55<<< XYZXYZXYZ abcabcab >>>
+ 84.56<<< 123456789 abcdefghi ABCDEDFHI >>> 56<<< 123456789 abcdefghi ABCDEDFHI >>>
+
+
+-- Date/Time -- x Page 9
+
+
+ 85.57<<< xyzxyzxyz XYZXYZXYZ abcabcab >>> 57<<< xyzxyzxyz XYZXYZXYZ abcabcab >>>
+ 86.58<<< 123456789 xyzxyzxyz XYZXYZXYZ >>> 58<<< 123456789 xyzxyzxyz XYZXYZXYZ >>>
+ 87.9<<< >>> 9<<< >>>
+ 88.60<<< 123456789 >>> 60<<< 123456789 >>>
+ \ No newline at end of file
diff --git a/tests/pr/nJml24f-lmlolm b/tests/pr/nJml24f-lmlolm
new file mode 100644
index 0000000..84dd27c
--- /dev/null
+++ b/tests/pr/nJml24f-lmlolm
@@ -0,0 +1,136 @@
+
+
+-- Date/Time -- x Page 1
+
+
+ 1.1<<< -Test: FF's in Text >>> 1::: Test-INPUT: "Without FF set by Hand" ::: 1<<< -Test: FF's in Text >>>
+ 2.2<<< -b -3 / -a -3 / ... >>> 2::: Options -b -3 [+2|+3] [-l 15|8] [-f] ::: 2<<< -b -3 / -a -3 / ... >>>
+ 3.3<<< >>> 3::: Options -a -3 [+2|+3] [-l 15|8] [-f] ::: 3<<< >>>
+ 4.4<<< 123456789 123456789 123456789 12345678 >>> 4::: Options [+2|+3] [-l 24|17] [-f] ::: 4<<< 123456789 123456789 123456789 12345678 >>>
+ 5. 5::: :::
+ 6.6<<< -Arangements: One Empty Page >>> 6::: -------------------------------------------- ::: 6<<< -Arangements: One Empty Page >>>
+ 7.7<<< \f\f\n; text\f\n\ftext; \f\ftext; >>> 7::: 789 123456789 123456789 123456789 123456789 123456789 123456789 1234567890 ::: 7<<< \f\f\n; text\f\n\ftext; \f\ftext; >>>
+ 8.8<<< f\f\n; \f\n\f\n; >>> 8::: 3 Columns downwards, across, ...: ::: 8<<< f\f\n; \f\n\f\n; >>>
+ 9.9<<< >>> 9::: With columns use <= 5 text lines/page, ::: 9<<< >>>
+ 10.10<<< >>> 10::: without -f e.g.: -l 15 = total lines/page, ::: 10<<< >>>
+ 11.1<<< >>> 1::: with -f e.g. : -l 8 -f ::: 1<<< >>>
+ 12.2<<< >>> 2::: ::: 2<<< >>>
+ 13.3<<< truncation before FF; r_r_o_l-test: >>> 3::: line truncation before new page; r_r_o_l-test: ::: 3<<< truncation before FF; r_r_o_l-test: >>>
+ 14.14<<< 123456789 123456789 123456789 >>> 14::: 89 123456789 123456789 123456789 123456789 123456789 123456789 1234567890 ::: 14<<< 123456789 123456789 123456789 >>>
+
+
+-- Date/Time -- x Page 2
+
+
+ 15. 15::: xyzxyzxyz XYZXYZXYZ abcabcab :::
+ 16. 16::: 456789 123456789 xyzxyzxyz XYZXYZXYZ :::
+ 17. 7::: 12345678 :::
+ 18. 8::: 12345678 :::
+ 19. 9::: 3456789 ab :::
+ 20. 20::: DEFGHI 123 :::
+ 21. 21::: 89 123456789 123456789 123456789 123456789 123456789 123456789 1234567890 :::
+ 22. 2::: 12345678 :::
+ 23. 3::: 12345678 :::
+ 24. 4::: 12345678 :::
+ 25. 5::: 12345678 :::
+ 26. 6::: 12345678 :::
+ 27. 27::: no truncation before nwe page; (r_l-test): :::
+ 28. 28::: 89 123456789 123456789 123456789 123456789 123456789 123456789 1234567890 :::
+
+
+-- Date/Time -- x Page 3
+
+
+ 29.15<<< xyzxyzxyz XYZXYZXYZ abcabcab >>> 29::: xyzxyzxyz XYZXYZXYZ abcabcab ::: 15<<< xyzxyzxyz XYZXYZXYZ abcabcab >>>
+ 30.16<<< 123456789 xyzxyzxyz XYZXYZXYZ >>> 30::: 456789 123456789 xyzxyzxyz XYZXYZXYZ ::: 16<<< 123456789 xyzxyzxyz XYZXYZXYZ >>>
+ 31.7<<< >>> 1::: 12345678 ::: 7<<< >>>
+ 32.8<<< >>> 2::: 3456789 abcdefghi ::: 8<<< >>>
+ 33.9<<< >>> 3::: 12345678 ::: 9<<< >>>
+ 34.20<<< >>> 4::: 12345678 ::: 20<<< >>>
+ 35.1<<< >>> 35::: 89 123456789 123456789 123456789 123456789 123456789 123456789 1234567890 ::: 1<<< >>>
+ 36. 6::: 12345678 :::
+ 37. 7::: 12345678 :::
+ 38.4<<< >>> 8::: 12345678 ::: 4<<< >>>
+ 39.5<<< >>> 9::: 3456789 abcdefghi ::: 5<<< >>>
+ 40.6<<< >>> 40::: DEFGHI 123456789 ::: 6<<< >>>
+ 41.27<<< truncation before FF; (r_l-test): >>> 41::: yzxyzxyz XYZXYZXYZ abcabcab ::: 27<<< truncation before FF; (r_l-test): >>>
+ 42.28<<< trunc 42::: 89 123456789 123456789 123456789 123456789 123456789 123456789 1234567890 ::: 28<<< trunc
+
+
+-- Date/Time -- x Page 4
+
+
+ 43. 43::: xyzxyzxyz XYZXYZXYZ abcabcab :::
+ 44. 44::: 456789 123456789 xyzxyzxyz XYZXYZXYZ :::
+ 45. 5::: 12345678 :::
+ 46. 6::: 12345678 :::
+ 47. 7::: 12345678 :::
+ 48. 8::: 12345678 :::
+ 49. 49::: 89 123456789 123456789 123456789 123456789 123456789 123456789 1234567890 :::
+ 50. 50::: 12345678 :::
+ 51. 1::: 12345678 :::
+ 52. 2::: 12345678 :::
+ 53. 3::: 12345678 :::
+ 54. 4::: 12345678 :::
+ 55. 55::: yzxyzxyz XYZXYZXYZ abcabcab :::
+ 56. 56::: 89 123456789 123456789 123456789 123456789 123456789 123456789 1234567890 :::
+
+
+-- Date/Time -- x Page 5
+
+
+ 57.29<<<xyzxyzxyz XYZXYZXYZ abcabcab >>> 57::: xyzxyzxyz XYZXYZXYZ abcabcab ::: 29<<<xyzxyzxyz XYZXYZXYZ abcabcab >>>
+ 58.30<<< 123456789 xyzxyzxyz XYZXYZXYZ >>> 58::: 456789 123456789 xyzxyzxyz XYZXYZXYZ ::: 30<<< 123456789 xyzxyzxyz XYZXYZXYZ >>>
+ 59.1<<< >>> 9::: 12345678 ::: 1<<< >>>
+ 60.2<<< abcdefghi >>> 60::: DEFGHI 123456789 ::: 2<<< abcdefghi >>>
+ 61.3<<< >>> 1::: ::: 3<<< >>>
+ 62.4<<< >>> 2::: ::: 4<<< >>>
+ 63.5<<< >>> 3::: ------- EOF -------- EOF -------- EOF ------- EOF ------- EOF ------- EOF ::: 5<<< >>>
+ 64.6<<< >>> 6<<< >>>
+ 65.7<<< >>> 7<<< >>>
+ 66.8<<< >>> 8<<< >>>
+ 67.9<<< abcdefghi >>> 9<<< abcdefghi >>>
+ 68.40<<< 123456789 >>> 40<<< 123456789 >>>
+ 69.41<<< XYZXYZXYZ abcabcab >>> 41<<< XYZXYZXYZ abcabcab >>>
+ 70.42<<< 123456789 abcdefghi ABCDEDFHI >>> 42<<< 123456789 abcdefghi ABCDEDFHI >>>
+
+
+-- Date/Time -- x Page 6
+
+
+
+
+
+-- Date/Time -- x Page 7
+
+
+
+
+
+-- Date/Time -- x Page 8
+
+
+ 71.43<<< xyzxyzxyz XYZXYZXYZ abcabcab >>> 43<<< xyzxyzxyz XYZXYZXYZ abcabcab >>>
+ 72.44<<< 123456789 xyzxyzxyz XYZXYZXYZ >>> 44<<< 123456789 xyzxyzxyz XYZXYZXYZ >>>
+ 73.5<<< >>> 5<<< >>>
+ 74.6<<< >>> 6<<< >>>
+ 75.7<<< >>> 7<<< >>>
+ 76.8<<< >>> 8<<< >>>
+ 77.9<<< >>> 9<<< >>>
+ 78.50<<< >>> 50<<< >>>
+ 79.1<<< >>> 1<<< >>>
+ 80.2<<< >>> 2<<< >>>
+ 81.3<<< >>> 3<<< >>>
+ 82.4<<< >>> 4<<< >>>
+ 83.55<<< XYZXYZXYZ abcabcab >>> 55<<< XYZXYZXYZ abcabcab >>>
+ 84.56<<< 123456789 abcdefghi ABCDEDFHI >>> 56<<< 123456789 abcdefghi ABCDEDFHI >>>
+
+
+-- Date/Time -- x Page 9
+
+
+ 85.57<<< xyzxyzxyz XYZXYZXYZ abcabcab >>> 57<<< xyzxyzxyz XYZXYZXYZ abcabcab >>>
+ 86.58<<< 123456789 xyzxyzxyz XYZXYZXYZ >>> 58<<< 123456789 xyzxyzxyz XYZXYZXYZ >>>
+ 87.9<<< >>> 9<<< >>>
+ 88.60<<< 123456789 >>> 60<<< 123456789 >>>
+ \ No newline at end of file
diff --git a/tests/pr/nN1+3l24f-bl b/tests/pr/nN1+3l24f-bl
new file mode 100644
index 0000000..38b793a
--- /dev/null
+++ b/tests/pr/nN1+3l24f-bl
@@ -0,0 +1,106 @@
+
+
+-- Date/Time -- x Page 3
+
+
+ 1.15 xyzxyzxyz XYZXYZXYZ abcabcab
+ 2.16 456789 123456789 xyzxyzxyz XYZXYZXYZ
+ 3.7 12345678
+ 4.8 12345678
+ 5.9 3456789 ab
+ 6.20 DEFGHI 123
+ 7.1 12345678
+ 8.
+ 9.
+ 10.4 12345678
+ 11.5 12345678
+ 12.6 12345678
+ 13.27 no truncation before FF; (r_l-test):
+ 14.
+
+
+-- Date/Time -- x Page 4
+
+
+
+
+
+-- Date/Time -- x Page 5
+
+
+ 15.29 xyzxyzxyz XYZXYZXYZ abcabcab
+ 16.30 456789 123456789 xyzxyzxyz XYZXYZXYZ
+ 17.1 12345678
+ 18.2 3456789 abcdefghi
+ 19.3 12345678
+ 20.4 12345678
+ 21.
+ 22.6 12345678
+ 23.7 12345678
+ 24.8 12345678
+ 25.9 3456789 abcdefghi
+ 26.40 DEFGHI 123456789
+ 27.41 yzxyzxyz XYZXYZXYZ abcabcab
+ 28.42 456789 123456789 abcdefghi ABCDEDFHI
+
+
+-- Date/Time -- x Page 6
+
+
+
+
+
+-- Date/Time -- x Page 7
+
+
+
+
+
+-- Date/Time -- x Page 8
+
+
+ 29.43 xyzxyzxyz XYZXYZXYZ abcabcab
+ 30.44 456789 123456789 xyzxyzxyz XYZXYZXYZ
+ 31.5 12345678
+ 32.6 12345678
+ 33.7 12345678
+ 34.8 12345678
+ 35.9 12345678
+ 36.50 12345678
+ 37.1 12345678
+ 38.
+ 39.
+ 40.
+ 41.55 yzxyzxyz XYZXYZXYZ abcabcab
+ 42.56 456789 123456789 abcdefghi ABCDEDFHI
+
+
+-- Date/Time -- x Page 9
+
+
+ 43.
+ 44.58 456789 123456789 xyzxyzxyz XYZXYZXYZ
+ 45.9 12345678
+ 46.60 DEFGHI 123456789
+ 47.61 yzxyzxyz XYZXYZXYZ abcabcab
+ 48.62 456789 123456789 abcdefghi ABCDEDFHI
+ 49.63 xyzxyzxyz XYZXYZXYZ abcabcab
+ 50.64 456789 123456789 xyzxyzxyz XYZXYZXYZ
+ 51.5 12345678
+ 52.6 12345678
+ 53.7 12345678
+ 54.8 12345678
+ 55.9 12345678
+ 56.70 456789 123456789 abcdefghi ABCDEDFHI
+
+
+-- Date/Time -- x Page 10
+
+
+ 57.1 12345678
+ 58.
+ 59.
+ 60.
+ 61.74 yzxyzxyz XYZXYZXYZ abcabcab
+ 62.75 456789 123456789 abcdefghi ABCDEDFHI
+ \ No newline at end of file
diff --git a/tests/pr/nN15l24f-bl b/tests/pr/nN15l24f-bl
new file mode 100644
index 0000000..b4356eb
--- /dev/null
+++ b/tests/pr/nN15l24f-bl
@@ -0,0 +1,131 @@
+
+
+-- Date/Time -- x Page 1
+
+
+ 15.1 FF-Test: FF's in Text V
+ 16.2 Options -n;
+ 17.3 numbering lines with skiped pages;
+ 18.4 numbering blanc lines (no. 5,12,13,23,28)
+ 19.
+ 20.6 3456789 123456789 123456789 123456789 12345678
+ 21.7 3 Columns downwards ..., <= 5 lines per page
+ 22.8
+ 23.9
+ 24.10 zzzzzzzzzzzzzzzzzzzzzzzzzz123456789
+ 25.1 12345678
+ 26.
+ 27.
+ 28.14 456789 123456789 123456789 123456789
+
+
+-- Date/Time -- x Page 2
+
+
+
+
+
+-- Date/Time -- x Page 3
+
+
+ 29.15 xyzxyzxyz XYZXYZXYZ abcabcab
+ 30.16 456789 123456789 xyzxyzxyz XYZXYZXYZ
+ 31.7 12345678
+ 32.8 12345678
+ 33.9 3456789 ab
+ 34.20 DEFGHI 123
+ 35.1 12345678
+ 36.
+ 37.
+ 38.4 12345678
+ 39.5 12345678
+ 40.6 12345678
+ 41.27 no truncation before FF; (r_l-test):
+ 42.
+
+
+-- Date/Time -- x Page 4
+
+
+
+
+
+-- Date/Time -- x Page 5
+
+
+ 43.29 xyzxyzxyz XYZXYZXYZ abcabcab
+ 44.30 456789 123456789 xyzxyzxyz XYZXYZXYZ
+ 45.1 12345678
+ 46.2 3456789 abcdefghi
+ 47.3 12345678
+ 48.4 12345678
+ 49.
+ 50.6 12345678
+ 51.7 12345678
+ 52.8 12345678
+ 53.9 3456789 abcdefghi
+ 54.40 DEFGHI 123456789
+ 55.41 yzxyzxyz XYZXYZXYZ abcabcab
+ 56.42 456789 123456789 abcdefghi ABCDEDFHI
+
+
+-- Date/Time -- x Page 6
+
+
+
+
+
+-- Date/Time -- x Page 7
+
+
+
+
+
+-- Date/Time -- x Page 8
+
+
+ 57.43 xyzxyzxyz XYZXYZXYZ abcabcab
+ 58.44 456789 123456789 xyzxyzxyz XYZXYZXYZ
+ 59.5 12345678
+ 60.6 12345678
+ 61.7 12345678
+ 62.8 12345678
+ 63.9 12345678
+ 64.50 12345678
+ 65.1 12345678
+ 66.
+ 67.
+ 68.
+ 69.55 yzxyzxyz XYZXYZXYZ abcabcab
+ 70.56 456789 123456789 abcdefghi ABCDEDFHI
+
+
+-- Date/Time -- x Page 9
+
+
+ 71.
+ 72.58 456789 123456789 xyzxyzxyz XYZXYZXYZ
+ 73.9 12345678
+ 74.60 DEFGHI 123456789
+ 75.61 yzxyzxyz XYZXYZXYZ abcabcab
+ 76.62 456789 123456789 abcdefghi ABCDEDFHI
+ 77.63 xyzxyzxyz XYZXYZXYZ abcabcab
+ 78.64 456789 123456789 xyzxyzxyz XYZXYZXYZ
+ 79.5 12345678
+ 80.6 12345678
+ 81.7 12345678
+ 82.8 12345678
+ 83.9 12345678
+ 84.70 456789 123456789 abcdefghi ABCDEDFHI
+
+
+-- Date/Time -- x Page 10
+
+
+ 85.1 12345678
+ 86.
+ 87.
+ 88.
+ 89.74 yzxyzxyz XYZXYZXYZ abcabcab
+ 90.75 456789 123456789 abcdefghi ABCDEDFHI
+ \ No newline at end of file
diff --git a/tests/pr/nSml20-bl-FF b/tests/pr/nSml20-bl-FF
new file mode 100644
index 0000000..18036e2
--- /dev/null
+++ b/tests/pr/nSml20-bl-FF
@@ -0,0 +1,151 @@
+
+
+-- Date/Time -- x Page 1
+
+
+ 1.1 FF-Test: FF's in Text :--:1 FF-Test: FF's in Text
+ 2.2 Options -n; :--:2 Options -b -3 / -a -3 / ...
+ 3.3 numbering lines with skiped :--:3 ----------------------------
+ 4.4 numbering blanc lines (no. 5:--:4 3456789 123456789 123456789 12
+ 5. :--:5 3 Columns downwards ..., <=
+ 6.6 3456789 123456789 123456789 12:--:6 FF-Arangements: One Empty Pa
+ 7.7 3 Columns downwards ..., <= :--:7 text\f\f\n; text\f\n\ftext;
+ 8.8 :--:8 \f\f\n; \f\n\f\n;
+ 9.9 :--:9
+ 10.10 zzzzzzzzzzzzzzzzzzzzzzzzzz12:--:10 zzzzzzzzzzzzzzzzzzzzzzzzzz12
+
+
+-- Date/Time -- x Page 2
+
+
+ 11.1 :--:1
+ 12. :--:2
+ 13. :--:3 line truncation before FF; r_r
+ 14.14 456789 123456789 123456789 12:--:14 456789 123456789 123456789 12
+
+
+-- Date/Time -- x Page 3
+
+
+
+
+
+-- Date/Time -- x Page 4
+
+
+ 15.15 xyzxyzxyz XYZXYZXYZ abcabcab :--:15 xyzxyzxyz XYZXYZXYZ abcabcab
+ 16.16 456789 123456789 xyzxyzxyz XY:--:16 456789 123456789 xyzxyzxyz XY
+ 17.7 :--:7
+ 18.8 :--:8
+ 19.9 3456789 ab :--:9 3456789 ab
+ 20.20 DEFGHI 123 :--:20 DEFGHI 123
+ 21.1 :--:1
+ 22. :--:2
+ 23. :--:3
+ 24.4 :--:4
+
+
+-- Date/Time -- x Page 5
+
+
+ 25.5 :--:5
+ 26.6 :--:6
+ 27.27 no truncation before FF; (r_l:--:27 no truncation before FF; (r_l
+ 28. :--:28 no trunc
+
+
+-- Date/Time -- x Page 6
+
+
+
+
+
+-- Date/Time -- x Page 7
+
+
+ 29.29 xyzxyzxyz XYZXYZXYZ abcabcab :--:29 xyzxyzxyz XYZXYZXYZ abcabcab
+ 30.30 456789 123456789 xyzxyzxyz XY:--:30 456789 123456789 xyzxyzxyz XY
+ 31.1 :--:1
+ 32.2 3456789 abcdefghi :--:2 3456789 abcdefghi
+ 33.3 :--:3
+ 34.4 :--:4
+ 35. :--:5
+ 36.6 :--:6
+ 37.7 :--:7
+ 38.8 :--:8
+
+
+-- Date/Time -- x Page 8
+
+
+ 39.9 3456789 abcdefghi :--:9 3456789 abcdefghi
+ 40.40 DEFGHI 123456789 :--:40 DEFGHI 123456789
+ 41.41 yzxyzxyz XYZXYZXYZ abcabcab :--:41 yzxyzxyz XYZXYZXYZ abcabcab
+ 42.42 456789 123456789 abcdefghi AB:--:42 456789 123456789 abcdefghi AB
+
+
+-- Date/Time -- x Page 9
+
+
+
+
+
+-- Date/Time -- x Page 10
+
+
+
+
+
+-- Date/Time -- x Page 11
+
+
+ 43.43 xyzxyzxyz XYZXYZXYZ abcabcab :--:43 xyzxyzxyz XYZXYZXYZ abcabcab
+ 44.44 456789 123456789 xyzxyzxyz XY:--:44 456789 123456789 xyzxyzxyz XY
+ 45.5 :--:5
+ 46.6 :--:6
+ 47.7 :--:7
+ 48.8 :--:8
+ 49.9 :--:9
+ 50.50 :--:50
+ 51.1 :--:1
+ 52. :--:2
+
+
+-- Date/Time -- x Page 12
+
+
+ 53. :--:3
+ 54. :--:4
+ 55.55 yzxyzxyz XYZXYZXYZ abcabcab :--:55 yzxyzxyz XYZXYZXYZ abcabcab
+ 56.56 456789 123456789 abcdefghi AB:--:56 456789 123456789 abcdefghi AB
+
+
+-- Date/Time -- x Page 13
+
+
+ 57. :--:57 xyzxyzxyz XYZXYZXYZ abcabcab
+ 58.58 456789 123456789 xyzxyzxyz XY:--:58 456789 123456789 xyzxyzxyz XY
+ 59.9 :--:9
+ 60.60 DEFGHI 123456789 :--:60 DEFGHI 123456789
+ 61.61 yzxyzxyz XYZXYZXYZ abcabcab :--:
+ 62.62 456789 123456789 abcdefghi AB:--:
+ 63.63 xyzxyzxyz XYZXYZXYZ abcabcab :--:
+ 64.64 456789 123456789 xyzxyzxyz XY:--:
+ 65.5 :--:
+ 66.6 :--:
+
+
+-- Date/Time -- x Page 14
+
+
+ 67.7 :--:
+ 68.8 :--:
+ 69.9 :--:
+ 70.70 456789 123456789 abcdefghi A:--:
+ 71.1 :--:
+ 72. :--:
+ 73. :--:
+ 74. :--:
+ 75.74 yzxyzxyz XYZXYZXYZ abcabcab :--:
+ 76.75 456789 123456789 abcdefghi AB
+ \ No newline at end of file
diff --git a/tests/pr/nSml20-t-t-FF b/tests/pr/nSml20-t-t-FF
new file mode 100644
index 0000000..abe6652
--- /dev/null
+++ b/tests/pr/nSml20-t-t-FF
@@ -0,0 +1,160 @@
+
+
+-- Date/Time -- x Page 1
+
+
+ 1.1 Test-INPUT: "Wit:--:1 Test-INPUT: "Wit:--:1 FF-Test: FF's in
+ 2.2 Options -b -3 [+:--:2 Options -b -3 [+:--:2 Options -b -3 /
+ 3.3 Options -a -3 [+:--:3 Options -a -3 [+:--:3 ----------------
+ 4.4 Options [+:--:4 Options [+:--:4 3456789 123456789
+ 5.5 :--:5 :--:5 3 Columns downwa
+ 6.6 ----------------:--:6 ----------------:--:6 FF-Arangements:
+ 7.7 3456789 123456789 :--:7 3456789 123456789 :--:7 text\f\f\n; text
+ 8.8 3 Columns downwa:--:8 3 Columns downwa:--:8 \f\f\n; \f\n\f\n
+ 9.9 With columns use:--:9 With columns use:--:9
+ 10.10 without -f e.g.::--:10 without -f e.g.::--:10 zzzzzzzzzzzzzzzz
+
+
+-- Date/Time -- x Page 2
+
+
+ 11.1 with -f e.g. ::--:1 with -f e.g. ::--:1
+ 12.2 :--:2 :--:2
+ 13.3 line truncation be:--:3 line truncation be:--:3 line truncation be
+ 14.14 456789 123456789 :--:14 456789 123456789 :--:14 456789 123456789
+ 15.15 xyzxyzxyz XYZXYZX:--:15 xyzxyzxyz XYZXYZX:--:
+ 16.16 456789 123456789 :--:16 456789 123456789 :--:
+ 17.7 :--:7 :--:
+ 18.8 :--:8 :--:
+ 19.9 3456789 ab :--:9 3456789 ab :--:
+ 20.20 DEFGHI 123 :--:20 DEFGHI 123 :--:
+
+
+-- Date/Time -- x Page 3
+
+
+ 21.1 :--:1 :--:
+ 22.2 :--:2 :--:
+ 23.3 :--:3 :--:
+ 24.4 :--:4 :--:
+ 25.5 :--:5 :--:
+ 26.6 :--:6 :--:
+ 27.27 no truncation bef:--:27 no truncation bef:--:
+ 28.28 no trunc :--:28 no trunc :--:
+ 29.29 xyzxyzxyz XYZXYZX:--:29 xyzxyzxyz XYZXYZX:--:
+ 30.30 456789 123456789 :--:30 456789 123456789 :--:
+
+
+-- Date/Time -- x Page 4
+
+
+ 31.1 :--:1 :--:15 xyzxyzxyz XYZXYZX
+ 32.2 3456789 abcdefghi :--:2 3456789 abcdefghi :--:16 456789 123456789
+ 33.3 :--:3 :--:7
+ 34.4 :--:4 :--:8
+ 35.5 :--:5 :--:9 3456789 ab
+ 36.6 :--:6 :--:20 DEFGHI 123
+ 37.7 :--:7 :--:1
+ 38.8 :--:8 :--:2
+ 39.9 3456789 abcdefghi :--:9 3456789 abcdefghi :--:3
+ 40.40 DEFGHI 123456789 :--:40 DEFGHI 123456789 :--:4
+
+
+-- Date/Time -- x Page 5
+
+
+ 41.41 yzxyzxyz XYZXYZXY:--:41 yzxyzxyz XYZXYZXY:--:5
+ 42.42 456789 123456789 :--:42 456789 123456789 :--:6
+ 43.43 xyzxyzxyz XYZXYZX:--:43 xyzxyzxyz XYZXYZX:--:27 no truncation bef
+ 44.44 456789 123456789 :--:44 456789 123456789 :--:28 no trunc
+ 45.5 :--:5 :--:
+ 46.6 :--:6 :--:
+ 47.7 :--:7 :--:
+ 48.8 :--:8 :--:
+ 49.9 :--:9 :--:
+ 50.50 :--:50 :--:
+
+
+-- Date/Time -- x Page 6
+
+
+ 51.1 :--:1 :--:
+ 52.2 :--:2 :--:
+ 53.3 :--:3 :--:
+ 54.4 :--:4 :--:
+ 55.55 yzxyzxyz XYZXYZXY:--:55 yzxyzxyz XYZXYZXY:--:
+ 56.56 456789 123456789 :--:56 456789 123456789 :--:
+ 57.57 xyzxyzxyz XYZXYZX:--:57 xyzxyzxyz XYZXYZX:--:
+ 58.58 456789 123456789 :--:58 456789 123456789 :--:
+ 59.9 :--:9 :--:
+ 60.60 DEFGHI 123456789 :--:60 DEFGHI 123456789 :--:
+
+
+-- Date/Time -- x Page 7
+
+
+ 61.1 :--:1 :--:29 xyzxyzxyz XYZXYZX
+ 62.2 :--:2 :--:30 456789 123456789
+ 63.3 ------- EOF -----:--:3 ------- EOF -----:--:1
+ 64. :--: :--:2 3456789 abcdefghi
+ 65. :--: :--:3
+ 66. :--: :--:4
+ 67. :--: :--:5
+ 68. :--: :--:6
+ 69. :--: :--:7
+ 70. :--: :--:8
+
+
+-- Date/Time -- x Page 8
+
+
+ 71. :--: :--:9 3456789 abcdefghi
+ 72. :--: :--:40 DEFGHI 123456789
+ 73. :--: :--:41 yzxyzxyz XYZXYZXY
+ 74. :--: :--:42 456789 123456789
+
+
+-- Date/Time -- x Page 9
+
+
+
+
+
+-- Date/Time -- x Page 10
+
+
+
+
+
+-- Date/Time -- x Page 11
+
+
+ 75. :--: :--:43 xyzxyzxyz XYZXYZX
+ 76. :--: :--:44 456789 123456789
+ 77. :--: :--:5
+ 78. :--: :--:6
+ 79. :--: :--:7
+ 80. :--: :--:8
+ 81. :--: :--:9
+ 82. :--: :--:50
+ 83. :--: :--:1
+ 84. :--: :--:2
+
+
+-- Date/Time -- x Page 12
+
+
+ 85. :--: :--:3
+ 86. :--: :--:4
+ 87. :--: :--:55 yzxyzxyz XYZXYZXY
+ 88. :--: :--:56 456789 123456789
+
+
+-- Date/Time -- x Page 13
+
+
+ 89. :--: :--:57 xyzxyzxyz XYZXYZX
+ 90. :--: :--:58 456789 123456789
+ 91. :--: :--:9
+ 92. :--: :--:60 DEFGHI 123456789
+ \ No newline at end of file
diff --git a/tests/pr/nSml20-t-tFFFF b/tests/pr/nSml20-t-tFFFF
new file mode 100644
index 0000000..4091d01
--- /dev/null
+++ b/tests/pr/nSml20-t-tFFFF
@@ -0,0 +1,160 @@
+
+
+-- Date/Time -- x Page 1
+
+
+ 1.1 Test-INPUT:--:1 Test-INPUT:--:1 FF-Test: F:--:1 FF-Test: F
+ 2.2 Options -b:--:2 Options -b:--:2 Options -b:--:2 Options -b
+ 3.3 Options -a:--:3 Options -a:--:3 ----------:--:3 ----------
+ 4.4 Options :--:4 Options :--:4 3456789 1234:--:4 3456789 1234
+ 5.5 :--:5 :--:5 3 Columns :--:5 3 Columns
+ 6.6 ----------:--:6 ----------:--:6 FF-Arangem:--:6 FF-Arangem
+ 7.7 3456789 1234:--:7 3456789 1234:--:7 text\f\f\n:--:7 text\f\f\n
+ 8.8 3 Columns :--:8 3 Columns :--:8 \f\f\n; \f:--:8 \f\f\n; \f
+ 9.9 With colum:--:9 With colum:--:9 :--:9
+ 10.10 without -f:--:10 without -f:--:10 zzzzzzzzzz:--:10 zzzzzzzzzz
+
+
+-- Date/Time -- x Page 2
+
+
+ 11.1 with -f e.:--:1 with -f e.:--:1 :--:1
+ 12.2 :--:2 :--:2 :--:2
+ 13.3 line truncat:--:3 line truncat:--:3 line truncat:--:3 line truncat
+ 14.14 456789 1234:--:14 456789 1234:--:14 456789 1234:--:14 456789 1234
+ 15.15 xyzxyzxyz X:--:15 xyzxyzxyz X:--: :--:
+ 16.16 456789 1234:--:16 456789 1234:--: :--:
+ 17.7 :--:7 :--: :--:
+ 18.8 :--:8 :--: :--:
+ 19.9 3456789 ab :--:9 3456789 ab :--: :--:
+ 20.20 DEFGHI 123 :--:20 DEFGHI 123 :--: :--:
+
+
+-- Date/Time -- x Page 3
+
+
+ 21.1 :--:1 :--: :--:
+ 22.2 :--:2 :--: :--:
+ 23.3 :--:3 :--: :--:
+ 24.4 :--:4 :--: :--:
+ 25.5 :--:5 :--: :--:
+ 26.6 :--:6 :--: :--:
+ 27.27 no truncati:--:27 no truncati:--: :--:
+ 28.28 no trunc :--:28 no trunc :--: :--:
+ 29.29 xyzxyzxyz X:--:29 xyzxyzxyz X:--: :--:
+ 30.30 456789 1234:--:30 456789 1234:--: :--:
+
+
+-- Date/Time -- x Page 4
+
+
+ 31.1 :--:1 :--:15 xyzxyzxyz X:--:15 xyzxyzxyz X
+ 32.2 3456789 abcd:--:2 3456789 abcd:--:16 456789 1234:--:16 456789 1234
+ 33.3 :--:3 :--:7 :--:7
+ 34.4 :--:4 :--:8 :--:8
+ 35.5 :--:5 :--:9 3456789 ab :--:9 3456789 ab
+ 36.6 :--:6 :--:20 DEFGHI 123 :--:20 DEFGHI 123
+ 37.7 :--:7 :--:1 :--:1
+ 38.8 :--:8 :--:2 :--:2
+ 39.9 3456789 abcd:--:9 3456789 abcd:--:3 :--:3
+ 40.40 DEFGHI 1234:--:40 DEFGHI 1234:--:4 :--:4
+
+
+-- Date/Time -- x Page 5
+
+
+ 41.41 yzxyzxyz XY:--:41 yzxyzxyz XY:--:5 :--:5
+ 42.42 456789 1234:--:42 456789 1234:--:6 :--:6
+ 43.43 xyzxyzxyz X:--:43 xyzxyzxyz X:--:27 no truncati:--:27 no truncati
+ 44.44 456789 1234:--:44 456789 1234:--:28 no trunc :--:28 no trunc
+ 45.5 :--:5 :--: :--:
+ 46.6 :--:6 :--: :--:
+ 47.7 :--:7 :--: :--:
+ 48.8 :--:8 :--: :--:
+ 49.9 :--:9 :--: :--:
+ 50.50 :--:50 :--: :--:
+
+
+-- Date/Time -- x Page 6
+
+
+ 51.1 :--:1 :--: :--:
+ 52.2 :--:2 :--: :--:
+ 53.3 :--:3 :--: :--:
+ 54.4 :--:4 :--: :--:
+ 55.55 yzxyzxyz XY:--:55 yzxyzxyz XY:--: :--:
+ 56.56 456789 1234:--:56 456789 1234:--: :--:
+ 57.57 xyzxyzxyz X:--:57 xyzxyzxyz X:--: :--:
+ 58.58 456789 1234:--:58 456789 1234:--: :--:
+ 59.9 :--:9 :--: :--:
+ 60.60 DEFGHI 1234:--:60 DEFGHI 1234:--: :--:
+
+
+-- Date/Time -- x Page 7
+
+
+ 61.1 :--:1 :--:29 xyzxyzxyz X:--:29 xyzxyzxyz X
+ 62.2 :--:2 :--:30 456789 1234:--:30 456789 1234
+ 63.3 ------- EOF:--:3 ------- EOF:--:1 :--:1
+ 64. :--: :--:2 3456789 abcd:--:2 3456789 abcd
+ 65. :--: :--:3 :--:3
+ 66. :--: :--:4 :--:4
+ 67. :--: :--:5 :--:5
+ 68. :--: :--:6 :--:6
+ 69. :--: :--:7 :--:7
+ 70. :--: :--:8 :--:8
+
+
+-- Date/Time -- x Page 8
+
+
+ 71. :--: :--:9 3456789 abcd:--:9 3456789 abcd
+ 72. :--: :--:40 DEFGHI 1234:--:40 DEFGHI 1234
+ 73. :--: :--:41 yzxyzxyz XY:--:41 yzxyzxyz XY
+ 74. :--: :--:42 456789 1234:--:42 456789 1234
+
+
+-- Date/Time -- x Page 9
+
+
+
+
+
+-- Date/Time -- x Page 10
+
+
+
+
+
+-- Date/Time -- x Page 11
+
+
+ 75. :--: :--:43 xyzxyzxyz X:--:43 xyzxyzxyz X
+ 76. :--: :--:44 456789 1234:--:44 456789 1234
+ 77. :--: :--:5 :--:5
+ 78. :--: :--:6 :--:6
+ 79. :--: :--:7 :--:7
+ 80. :--: :--:8 :--:8
+ 81. :--: :--:9 :--:9
+ 82. :--: :--:50 :--:50
+ 83. :--: :--:1 :--:1
+ 84. :--: :--:2 :--:2
+
+
+-- Date/Time -- x Page 12
+
+
+ 85. :--: :--:3 :--:3
+ 86. :--: :--:4 :--:4
+ 87. :--: :--:55 yzxyzxyz XY:--:55 yzxyzxyz XY
+ 88. :--: :--:56 456789 1234:--:56 456789 1234
+
+
+-- Date/Time -- x Page 13
+
+
+ 89. :--: :--:57 xyzxyzxyz X:--:57 xyzxyzxyz X
+ 90. :--: :--:58 456789 1234:--:58 456789 1234
+ 91. :--: :--:9 :--:9
+ 92. :--: :--:60 DEFGHI 1234:--:60 DEFGHI 1234
+ \ No newline at end of file
diff --git a/tests/pr/nSml24-bl-FF b/tests/pr/nSml24-bl-FF
new file mode 100644
index 0000000..e8d7c13
--- /dev/null
+++ b/tests/pr/nSml24-bl-FF
@@ -0,0 +1,131 @@
+
+
+-- Date/Time -- x Page 1
+
+
+ 1.1 FF-Test: FF's in Text :--:1 FF-Test: FF's in Text
+ 2.2 Options -n; :--:2 Options -b -3 / -a -3 / ...
+ 3.3 numbering lines with skiped :--:3 ----------------------------
+ 4.4 numbering blanc lines (no. 5:--:4 3456789 123456789 123456789 12
+ 5. :--:5 3 Columns downwards ..., <=
+ 6.6 3456789 123456789 123456789 12:--:6 FF-Arangements: One Empty Pa
+ 7.7 3 Columns downwards ..., <= :--:7 text\f\f\n; text\f\n\ftext;
+ 8.8 :--:8 \f\f\n; \f\n\f\n;
+ 9.9 :--:9
+ 10.10 zzzzzzzzzzzzzzzzzzzzzzzzzz12:--:10 zzzzzzzzzzzzzzzzzzzzzzzzzz12
+ 11.1 :--:1
+ 12. :--:2
+ 13. :--:3 line truncation before FF; r_r
+ 14.14 456789 123456789 123456789 12:--:14 456789 123456789 123456789 12
+
+
+-- Date/Time -- x Page 2
+
+
+
+
+
+-- Date/Time -- x Page 3
+
+
+ 15.15 xyzxyzxyz XYZXYZXYZ abcabcab :--:15 xyzxyzxyz XYZXYZXYZ abcabcab
+ 16.16 456789 123456789 xyzxyzxyz XY:--:16 456789 123456789 xyzxyzxyz XY
+ 17.7 :--:7
+ 18.8 :--:8
+ 19.9 3456789 ab :--:9 3456789 ab
+ 20.20 DEFGHI 123 :--:20 DEFGHI 123
+ 21.1 :--:1
+ 22. :--:2
+ 23. :--:3
+ 24.4 :--:4
+ 25.5 :--:5
+ 26.6 :--:6
+ 27.27 no truncation before FF; (r_l:--:27 no truncation before FF; (r_l
+ 28. :--:28 no trunc
+
+
+-- Date/Time -- x Page 4
+
+
+
+
+
+-- Date/Time -- x Page 5
+
+
+ 29.29 xyzxyzxyz XYZXYZXYZ abcabcab :--:29 xyzxyzxyz XYZXYZXYZ abcabcab
+ 30.30 456789 123456789 xyzxyzxyz XY:--:30 456789 123456789 xyzxyzxyz XY
+ 31.1 :--:1
+ 32.2 3456789 abcdefghi :--:2 3456789 abcdefghi
+ 33.3 :--:3
+ 34.4 :--:4
+ 35. :--:5
+ 36.6 :--:6
+ 37.7 :--:7
+ 38.8 :--:8
+ 39.9 3456789 abcdefghi :--:9 3456789 abcdefghi
+ 40.40 DEFGHI 123456789 :--:40 DEFGHI 123456789
+ 41.41 yzxyzxyz XYZXYZXYZ abcabcab :--:41 yzxyzxyz XYZXYZXYZ abcabcab
+ 42.42 456789 123456789 abcdefghi AB:--:42 456789 123456789 abcdefghi AB
+
+
+-- Date/Time -- x Page 6
+
+
+
+
+
+-- Date/Time -- x Page 7
+
+
+
+
+
+-- Date/Time -- x Page 8
+
+
+ 43.43 xyzxyzxyz XYZXYZXYZ abcabcab :--:43 xyzxyzxyz XYZXYZXYZ abcabcab
+ 44.44 456789 123456789 xyzxyzxyz XY:--:44 456789 123456789 xyzxyzxyz XY
+ 45.5 :--:5
+ 46.6 :--:6
+ 47.7 :--:7
+ 48.8 :--:8
+ 49.9 :--:9
+ 50.50 :--:50
+ 51.1 :--:1
+ 52. :--:2
+ 53. :--:3
+ 54. :--:4
+ 55.55 yzxyzxyz XYZXYZXYZ abcabcab :--:55 yzxyzxyz XYZXYZXYZ abcabcab
+ 56.56 456789 123456789 abcdefghi AB:--:56 456789 123456789 abcdefghi AB
+
+
+-- Date/Time -- x Page 9
+
+
+ 57. :--:57 xyzxyzxyz XYZXYZXYZ abcabcab
+ 58.58 456789 123456789 xyzxyzxyz XY:--:58 456789 123456789 xyzxyzxyz XY
+ 59.9 :--:9
+ 60.60 DEFGHI 123456789 :--:60 DEFGHI 123456789
+ 61.61 yzxyzxyz XYZXYZXYZ abcabcab :--:
+ 62.62 456789 123456789 abcdefghi AB:--:
+ 63.63 xyzxyzxyz XYZXYZXYZ abcabcab :--:
+ 64.64 456789 123456789 xyzxyzxyz XY:--:
+ 65.5 :--:
+ 66.6 :--:
+ 67.7 :--:
+ 68.8 :--:
+ 69.9 :--:
+ 70.70 456789 123456789 abcdefghi A:--:
+
+
+-- Date/Time -- x Page 10
+
+
+ 71.1 :--:
+ 72. :--:
+ 73. :--:
+ 74. :--:
+ 75.74 yzxyzxyz XYZXYZXYZ abcabcab :--:
+ 76.75 456789 123456789 abcdefghi AB
+ \ No newline at end of file
diff --git a/tests/pr/nSml24-t-t-FF b/tests/pr/nSml24-t-t-FF
new file mode 100644
index 0000000..e28b754
--- /dev/null
+++ b/tests/pr/nSml24-t-t-FF
@@ -0,0 +1,136 @@
+
+
+-- Date/Time -- x Page 1
+
+
+ 1.1 Test-INPUT: "Wit:--:1 Test-INPUT: "Wit:--:1 FF-Test: FF's in
+ 2.2 Options -b -3 [+:--:2 Options -b -3 [+:--:2 Options -b -3 /
+ 3.3 Options -a -3 [+:--:3 Options -a -3 [+:--:3 ----------------
+ 4.4 Options [+:--:4 Options [+:--:4 3456789 123456789
+ 5.5 :--:5 :--:5 3 Columns downwa
+ 6.6 ----------------:--:6 ----------------:--:6 FF-Arangements:
+ 7.7 3456789 123456789 :--:7 3456789 123456789 :--:7 text\f\f\n; text
+ 8.8 3 Columns downwa:--:8 3 Columns downwa:--:8 \f\f\n; \f\n\f\n
+ 9.9 With columns use:--:9 With columns use:--:9
+ 10.10 without -f e.g.::--:10 without -f e.g.::--:10 zzzzzzzzzzzzzzzz
+ 11.1 with -f e.g. ::--:1 with -f e.g. ::--:1
+ 12.2 :--:2 :--:2
+ 13.3 line truncation be:--:3 line truncation be:--:3 line truncation be
+ 14.14 456789 123456789 :--:14 456789 123456789 :--:14 456789 123456789
+
+
+-- Date/Time -- x Page 2
+
+
+ 15.15 xyzxyzxyz XYZXYZX:--:15 xyzxyzxyz XYZXYZX:--:
+ 16.16 456789 123456789 :--:16 456789 123456789 :--:
+ 17.7 :--:7 :--:
+ 18.8 :--:8 :--:
+ 19.9 3456789 ab :--:9 3456789 ab :--:
+ 20.20 DEFGHI 123 :--:20 DEFGHI 123 :--:
+ 21.1 :--:1 :--:
+ 22.2 :--:2 :--:
+ 23.3 :--:3 :--:
+ 24.4 :--:4 :--:
+ 25.5 :--:5 :--:
+ 26.6 :--:6 :--:
+ 27.27 no truncation bef:--:27 no truncation bef:--:
+ 28.28 no trunc :--:28 no trunc :--:
+
+
+-- Date/Time -- x Page 3
+
+
+ 29.29 xyzxyzxyz XYZXYZX:--:29 xyzxyzxyz XYZXYZX:--:15 xyzxyzxyz XYZXYZX
+ 30.30 456789 123456789 :--:30 456789 123456789 :--:16 456789 123456789
+ 31.1 :--:1 :--:7
+ 32.2 3456789 abcdefghi :--:2 3456789 abcdefghi :--:8
+ 33.3 :--:3 :--:9 3456789 ab
+ 34.4 :--:4 :--:20 DEFGHI 123
+ 35.5 :--:5 :--:1
+ 36.6 :--:6 :--:2
+ 37.7 :--:7 :--:3
+ 38.8 :--:8 :--:4
+ 39.9 3456789 abcdefghi :--:9 3456789 abcdefghi :--:5
+ 40.40 DEFGHI 123456789 :--:40 DEFGHI 123456789 :--:6
+ 41.41 yzxyzxyz XYZXYZXY:--:41 yzxyzxyz XYZXYZXY:--:27 no truncation bef
+ 42.42 456789 123456789 :--:42 456789 123456789 :--:28 no trunc
+
+
+-- Date/Time -- x Page 4
+
+
+ 43.43 xyzxyzxyz XYZXYZX:--:43 xyzxyzxyz XYZXYZX:--:
+ 44.44 456789 123456789 :--:44 456789 123456789 :--:
+ 45.5 :--:5 :--:
+ 46.6 :--:6 :--:
+ 47.7 :--:7 :--:
+ 48.8 :--:8 :--:
+ 49.9 :--:9 :--:
+ 50.50 :--:50 :--:
+ 51.1 :--:1 :--:
+ 52.2 :--:2 :--:
+ 53.3 :--:3 :--:
+ 54.4 :--:4 :--:
+ 55.55 yzxyzxyz XYZXYZXY:--:55 yzxyzxyz XYZXYZXY:--:
+ 56.56 456789 123456789 :--:56 456789 123456789 :--:
+
+
+-- Date/Time -- x Page 5
+
+
+ 57.57 xyzxyzxyz XYZXYZX:--:57 xyzxyzxyz XYZXYZX:--:29 xyzxyzxyz XYZXYZX
+ 58.58 456789 123456789 :--:58 456789 123456789 :--:30 456789 123456789
+ 59.9 :--:9 :--:1
+ 60.60 DEFGHI 123456789 :--:60 DEFGHI 123456789 :--:2 3456789 abcdefghi
+ 61.1 :--:1 :--:3
+ 62.2 :--:2 :--:4
+ 63.3 ------- EOF -----:--:3 ------- EOF -----:--:5
+ 64. :--: :--:6
+ 65. :--: :--:7
+ 66. :--: :--:8
+ 67. :--: :--:9 3456789 abcdefghi
+ 68. :--: :--:40 DEFGHI 123456789
+ 69. :--: :--:41 yzxyzxyz XYZXYZXY
+ 70. :--: :--:42 456789 123456789
+
+
+-- Date/Time -- x Page 6
+
+
+
+
+
+-- Date/Time -- x Page 7
+
+
+
+
+
+-- Date/Time -- x Page 8
+
+
+ 71. :--: :--:43 xyzxyzxyz XYZXYZX
+ 72. :--: :--:44 456789 123456789
+ 73. :--: :--:5
+ 74. :--: :--:6
+ 75. :--: :--:7
+ 76. :--: :--:8
+ 77. :--: :--:9
+ 78. :--: :--:50
+ 79. :--: :--:1
+ 80. :--: :--:2
+ 81. :--: :--:3
+ 82. :--: :--:4
+ 83. :--: :--:55 yzxyzxyz XYZXYZXY
+ 84. :--: :--:56 456789 123456789
+
+
+-- Date/Time -- x Page 9
+
+
+ 85. :--: :--:57 xyzxyzxyz XYZXYZX
+ 86. :--: :--:58 456789 123456789
+ 87. :--: :--:9
+ 88. :--: :--:60 DEFGHI 123456789
+ \ No newline at end of file
diff --git a/tests/pr/nSml24-t-tFFFF b/tests/pr/nSml24-t-tFFFF
new file mode 100644
index 0000000..74538ad
--- /dev/null
+++ b/tests/pr/nSml24-t-tFFFF
@@ -0,0 +1,136 @@
+
+
+-- Date/Time -- x Page 1
+
+
+ 1.1 Test-INPUT:--:1 Test-INPUT:--:1 FF-Test: F:--:1 FF-Test: F
+ 2.2 Options -b:--:2 Options -b:--:2 Options -b:--:2 Options -b
+ 3.3 Options -a:--:3 Options -a:--:3 ----------:--:3 ----------
+ 4.4 Options :--:4 Options :--:4 3456789 1234:--:4 3456789 1234
+ 5.5 :--:5 :--:5 3 Columns :--:5 3 Columns
+ 6.6 ----------:--:6 ----------:--:6 FF-Arangem:--:6 FF-Arangem
+ 7.7 3456789 1234:--:7 3456789 1234:--:7 text\f\f\n:--:7 text\f\f\n
+ 8.8 3 Columns :--:8 3 Columns :--:8 \f\f\n; \f:--:8 \f\f\n; \f
+ 9.9 With colum:--:9 With colum:--:9 :--:9
+ 10.10 without -f:--:10 without -f:--:10 zzzzzzzzzz:--:10 zzzzzzzzzz
+ 11.1 with -f e.:--:1 with -f e.:--:1 :--:1
+ 12.2 :--:2 :--:2 :--:2
+ 13.3 line truncat:--:3 line truncat:--:3 line truncat:--:3 line truncat
+ 14.14 456789 1234:--:14 456789 1234:--:14 456789 1234:--:14 456789 1234
+
+
+-- Date/Time -- x Page 2
+
+
+ 15.15 xyzxyzxyz X:--:15 xyzxyzxyz X:--: :--:
+ 16.16 456789 1234:--:16 456789 1234:--: :--:
+ 17.7 :--:7 :--: :--:
+ 18.8 :--:8 :--: :--:
+ 19.9 3456789 ab :--:9 3456789 ab :--: :--:
+ 20.20 DEFGHI 123 :--:20 DEFGHI 123 :--: :--:
+ 21.1 :--:1 :--: :--:
+ 22.2 :--:2 :--: :--:
+ 23.3 :--:3 :--: :--:
+ 24.4 :--:4 :--: :--:
+ 25.5 :--:5 :--: :--:
+ 26.6 :--:6 :--: :--:
+ 27.27 no truncati:--:27 no truncati:--: :--:
+ 28.28 no trunc :--:28 no trunc :--: :--:
+
+
+-- Date/Time -- x Page 3
+
+
+ 29.29 xyzxyzxyz X:--:29 xyzxyzxyz X:--:15 xyzxyzxyz X:--:15 xyzxyzxyz X
+ 30.30 456789 1234:--:30 456789 1234:--:16 456789 1234:--:16 456789 1234
+ 31.1 :--:1 :--:7 :--:7
+ 32.2 3456789 abcd:--:2 3456789 abcd:--:8 :--:8
+ 33.3 :--:3 :--:9 3456789 ab :--:9 3456789 ab
+ 34.4 :--:4 :--:20 DEFGHI 123 :--:20 DEFGHI 123
+ 35.5 :--:5 :--:1 :--:1
+ 36.6 :--:6 :--:2 :--:2
+ 37.7 :--:7 :--:3 :--:3
+ 38.8 :--:8 :--:4 :--:4
+ 39.9 3456789 abcd:--:9 3456789 abcd:--:5 :--:5
+ 40.40 DEFGHI 1234:--:40 DEFGHI 1234:--:6 :--:6
+ 41.41 yzxyzxyz XY:--:41 yzxyzxyz XY:--:27 no truncati:--:27 no truncati
+ 42.42 456789 1234:--:42 456789 1234:--:28 no trunc :--:28 no trunc
+
+
+-- Date/Time -- x Page 4
+
+
+ 43.43 xyzxyzxyz X:--:43 xyzxyzxyz X:--: :--:
+ 44.44 456789 1234:--:44 456789 1234:--: :--:
+ 45.5 :--:5 :--: :--:
+ 46.6 :--:6 :--: :--:
+ 47.7 :--:7 :--: :--:
+ 48.8 :--:8 :--: :--:
+ 49.9 :--:9 :--: :--:
+ 50.50 :--:50 :--: :--:
+ 51.1 :--:1 :--: :--:
+ 52.2 :--:2 :--: :--:
+ 53.3 :--:3 :--: :--:
+ 54.4 :--:4 :--: :--:
+ 55.55 yzxyzxyz XY:--:55 yzxyzxyz XY:--: :--:
+ 56.56 456789 1234:--:56 456789 1234:--: :--:
+
+
+-- Date/Time -- x Page 5
+
+
+ 57.57 xyzxyzxyz X:--:57 xyzxyzxyz X:--:29 xyzxyzxyz X:--:29 xyzxyzxyz X
+ 58.58 456789 1234:--:58 456789 1234:--:30 456789 1234:--:30 456789 1234
+ 59.9 :--:9 :--:1 :--:1
+ 60.60 DEFGHI 1234:--:60 DEFGHI 1234:--:2 3456789 abcd:--:2 3456789 abcd
+ 61.1 :--:1 :--:3 :--:3
+ 62.2 :--:2 :--:4 :--:4
+ 63.3 ------- EOF:--:3 ------- EOF:--:5 :--:5
+ 64. :--: :--:6 :--:6
+ 65. :--: :--:7 :--:7
+ 66. :--: :--:8 :--:8
+ 67. :--: :--:9 3456789 abcd:--:9 3456789 abcd
+ 68. :--: :--:40 DEFGHI 1234:--:40 DEFGHI 1234
+ 69. :--: :--:41 yzxyzxyz XY:--:41 yzxyzxyz XY
+ 70. :--: :--:42 456789 1234:--:42 456789 1234
+
+
+-- Date/Time -- x Page 6
+
+
+
+
+
+-- Date/Time -- x Page 7
+
+
+
+
+
+-- Date/Time -- x Page 8
+
+
+ 71. :--: :--:43 xyzxyzxyz X:--:43 xyzxyzxyz X
+ 72. :--: :--:44 456789 1234:--:44 456789 1234
+ 73. :--: :--:5 :--:5
+ 74. :--: :--:6 :--:6
+ 75. :--: :--:7 :--:7
+ 76. :--: :--:8 :--:8
+ 77. :--: :--:9 :--:9
+ 78. :--: :--:50 :--:50
+ 79. :--: :--:1 :--:1
+ 80. :--: :--:2 :--:2
+ 81. :--: :--:3 :--:3
+ 82. :--: :--:4 :--:4
+ 83. :--: :--:55 yzxyzxyz XY:--:55 yzxyzxyz XY
+ 84. :--: :--:56 456789 1234:--:56 456789 1234
+
+
+-- Date/Time -- x Page 9
+
+
+ 85. :--: :--:57 xyzxyzxyz X:--:57 xyzxyzxyz X
+ 86. :--: :--:58 456789 1234:--:58 456789 1234
+ 87. :--: :--:9 :--:9
+ 88. :--: :--:60 DEFGHI 1234:--:60 DEFGHI 1234
+ \ No newline at end of file
diff --git a/tests/pr/nl24f-bl b/tests/pr/nl24f-bl
new file mode 100644
index 0000000..5546ad2
--- /dev/null
+++ b/tests/pr/nl24f-bl
@@ -0,0 +1,131 @@
+
+
+-- Date/Time -- x Page 1
+
+
+ 1.1 FF-Test: FF's in Text V
+ 2.2 Options -n;
+ 3.3 numbering lines with skiped pages;
+ 4.4 numbering blanc lines (no. 5,12,13,23,28)
+ 5.
+ 6.6 3456789 123456789 123456789 123456789 12345678
+ 7.7 3 Columns downwards ..., <= 5 lines per page
+ 8.8
+ 9.9
+ 10.10 zzzzzzzzzzzzzzzzzzzzzzzzzz123456789
+ 11.1 12345678
+ 12.
+ 13.
+ 14.14 456789 123456789 123456789 123456789
+
+
+-- Date/Time -- x Page 2
+
+
+
+
+
+-- Date/Time -- x Page 3
+
+
+ 15.15 xyzxyzxyz XYZXYZXYZ abcabcab
+ 16.16 456789 123456789 xyzxyzxyz XYZXYZXYZ
+ 17.7 12345678
+ 18.8 12345678
+ 19.9 3456789 ab
+ 20.20 DEFGHI 123
+ 21.1 12345678
+ 22.
+ 23.
+ 24.4 12345678
+ 25.5 12345678
+ 26.6 12345678
+ 27.27 no truncation before FF; (r_l-test):
+ 28.
+
+
+-- Date/Time -- x Page 4
+
+
+
+
+
+-- Date/Time -- x Page 5
+
+
+ 29.29 xyzxyzxyz XYZXYZXYZ abcabcab
+ 30.30 456789 123456789 xyzxyzxyz XYZXYZXYZ
+ 31.1 12345678
+ 32.2 3456789 abcdefghi
+ 33.3 12345678
+ 34.4 12345678
+ 35.
+ 36.6 12345678
+ 37.7 12345678
+ 38.8 12345678
+ 39.9 3456789 abcdefghi
+ 40.40 DEFGHI 123456789
+ 41.41 yzxyzxyz XYZXYZXYZ abcabcab
+ 42.42 456789 123456789 abcdefghi ABCDEDFHI
+
+
+-- Date/Time -- x Page 6
+
+
+
+
+
+-- Date/Time -- x Page 7
+
+
+
+
+
+-- Date/Time -- x Page 8
+
+
+ 43.43 xyzxyzxyz XYZXYZXYZ abcabcab
+ 44.44 456789 123456789 xyzxyzxyz XYZXYZXYZ
+ 45.5 12345678
+ 46.6 12345678
+ 47.7 12345678
+ 48.8 12345678
+ 49.9 12345678
+ 50.50 12345678
+ 51.1 12345678
+ 52.
+ 53.
+ 54.
+ 55.55 yzxyzxyz XYZXYZXYZ abcabcab
+ 56.56 456789 123456789 abcdefghi ABCDEDFHI
+
+
+-- Date/Time -- x Page 9
+
+
+ 57.
+ 58.58 456789 123456789 xyzxyzxyz XYZXYZXYZ
+ 59.9 12345678
+ 60.60 DEFGHI 123456789
+ 61.61 yzxyzxyz XYZXYZXYZ abcabcab
+ 62.62 456789 123456789 abcdefghi ABCDEDFHI
+ 63.63 xyzxyzxyz XYZXYZXYZ abcabcab
+ 64.64 456789 123456789 xyzxyzxyz XYZXYZXYZ
+ 65.5 12345678
+ 66.6 12345678
+ 67.7 12345678
+ 68.8 12345678
+ 69.9 12345678
+ 70.70 456789 123456789 abcdefghi ABCDEDFHI
+
+
+-- Date/Time -- x Page 10
+
+
+ 71.1 12345678
+ 72.
+ 73.
+ 74.
+ 75.74 yzxyzxyz XYZXYZXYZ abcabcab
+ 76.75 456789 123456789 abcdefghi ABCDEDFHI
+ \ No newline at end of file
diff --git a/tests/pr/o3Jml24f-lm-lo b/tests/pr/o3Jml24f-lm-lo
new file mode 100644
index 0000000..e0aa4a4
--- /dev/null
+++ b/tests/pr/o3Jml24f-lm-lo
@@ -0,0 +1,136 @@
+
+
+ -- Date/Time -- x Page 1
+
+
+ 1<<< -Test: FF's in Text >>> 1::: Test-INPUT: "Without FF set by Hand" :::
+ 2<<< -b -3 / -a -3 / ... >>> 2::: Options -b -3 [+2|+3] [-l 15|8] [-f] :::
+ 3<<< >>> 3::: Options -a -3 [+2|+3] [-l 15|8] [-f] :::
+ 4<<< 123456789 123456789 123456789 12345678 >>> 4::: Options [+2|+3] [-l 24|17] [-f] :::
+ 5::: :::
+ 6<<< -Arangements: One Empty Page >>> 6::: -------------------------------------------- :::
+ 7<<< \f\f\n; text\f\n\ftext; \f\ftext; >>> 7::: 789 123456789 123456789 123456789 123456789 123456789 123456789 1234567890 :::
+ 8<<< f\f\n; \f\n\f\n; >>> 8::: 3 Columns downwards, across, ...: :::
+ 9<<< >>> 9::: With columns use <= 5 text lines/page, :::
+ 10<<< >>> 10::: without -f e.g.: -l 15 = total lines/page, :::
+ 1<<< >>> 1::: with -f e.g. : -l 8 -f :::
+ 2<<< >>> 2::: :::
+ 3<<< truncation before FF; r_r_o_l-test: >>> 3::: line truncation before new page; r_r_o_l-test: :::
+ 14<<< 123456789 123456789 123456789 >>> 14::: 89 123456789 123456789 123456789 123456789 123456789 123456789 1234567890 :::
+
+
+ -- Date/Time -- x Page 2
+
+
+ 15::: xyzxyzxyz XYZXYZXYZ abcabcab :::
+ 16::: 456789 123456789 xyzxyzxyz XYZXYZXYZ :::
+ 7::: 12345678 :::
+ 8::: 12345678 :::
+ 9::: 3456789 ab :::
+ 20::: DEFGHI 123 :::
+ 21::: 89 123456789 123456789 123456789 123456789 123456789 123456789 1234567890 :::
+ 2::: 12345678 :::
+ 3::: 12345678 :::
+ 4::: 12345678 :::
+ 5::: 12345678 :::
+ 6::: 12345678 :::
+ 27::: no truncation before nwe page; (r_l-test): :::
+ 28::: 89 123456789 123456789 123456789 123456789 123456789 123456789 1234567890 :::
+
+
+ -- Date/Time -- x Page 3
+
+
+ 15<<< xyzxyzxyz XYZXYZXYZ abcabcab >>> 29::: xyzxyzxyz XYZXYZXYZ abcabcab :::
+ 16<<< 123456789 xyzxyzxyz XYZXYZXYZ >>> 30::: 456789 123456789 xyzxyzxyz XYZXYZXYZ :::
+ 7<<< >>> 1::: 12345678 :::
+ 8<<< >>> 2::: 3456789 abcdefghi :::
+ 9<<< >>> 3::: 12345678 :::
+ 20<<< >>> 4::: 12345678 :::
+ 1<<< >>> 35::: 89 123456789 123456789 123456789 123456789 123456789 123456789 1234567890 :::
+ 6::: 12345678 :::
+ 7::: 12345678 :::
+ 4<<< >>> 8::: 12345678 :::
+ 5<<< >>> 9::: 3456789 abcdefghi :::
+ 6<<< >>> 40::: DEFGHI 123456789 :::
+ 27<<< truncation before FF; (r_l-test): >>> 41::: yzxyzxyz XYZXYZXYZ abcabcab :::
+ 28<<< trunc 42::: 89 123456789 123456789 123456789 123456789 123456789 123456789 1234567890 :::
+
+
+ -- Date/Time -- x Page 4
+
+
+ 43::: xyzxyzxyz XYZXYZXYZ abcabcab :::
+ 44::: 456789 123456789 xyzxyzxyz XYZXYZXYZ :::
+ 5::: 12345678 :::
+ 6::: 12345678 :::
+ 7::: 12345678 :::
+ 8::: 12345678 :::
+ 49::: 89 123456789 123456789 123456789 123456789 123456789 123456789 1234567890 :::
+ 50::: 12345678 :::
+ 1::: 12345678 :::
+ 2::: 12345678 :::
+ 3::: 12345678 :::
+ 4::: 12345678 :::
+ 55::: yzxyzxyz XYZXYZXYZ abcabcab :::
+ 56::: 89 123456789 123456789 123456789 123456789 123456789 123456789 1234567890 :::
+
+
+ -- Date/Time -- x Page 5
+
+
+ 29<<<xyzxyzxyz XYZXYZXYZ abcabcab >>> 57::: xyzxyzxyz XYZXYZXYZ abcabcab :::
+ 30<<< 123456789 xyzxyzxyz XYZXYZXYZ >>> 58::: 456789 123456789 xyzxyzxyz XYZXYZXYZ :::
+ 1<<< >>> 9::: 12345678 :::
+ 2<<< abcdefghi >>> 60::: DEFGHI 123456789 :::
+ 3<<< >>> 1::: :::
+ 4<<< >>> 2::: :::
+ 5<<< >>> 3::: ------- EOF -------- EOF -------- EOF ------- EOF ------- EOF ------- EOF :::
+ 6<<< >>>
+ 7<<< >>>
+ 8<<< >>>
+ 9<<< abcdefghi >>>
+ 40<<< 123456789 >>>
+ 41<<< XYZXYZXYZ abcabcab >>>
+ 42<<< 123456789 abcdefghi ABCDEDFHI >>>
+
+
+ -- Date/Time -- x Page 6
+
+
+
+
+
+ -- Date/Time -- x Page 7
+
+
+
+
+
+ -- Date/Time -- x Page 8
+
+
+ 43<<< xyzxyzxyz XYZXYZXYZ abcabcab >>>
+ 44<<< 123456789 xyzxyzxyz XYZXYZXYZ >>>
+ 5<<< >>>
+ 6<<< >>>
+ 7<<< >>>
+ 8<<< >>>
+ 9<<< >>>
+ 50<<< >>>
+ 1<<< >>>
+ 2<<< >>>
+ 3<<< >>>
+ 4<<< >>>
+ 55<<< XYZXYZXYZ abcabcab >>>
+ 56<<< 123456789 abcdefghi ABCDEDFHI >>>
+
+
+ -- Date/Time -- x Page 9
+
+
+ 57<<< xyzxyzxyz XYZXYZXYZ abcabcab >>>
+ 58<<< 123456789 xyzxyzxyz XYZXYZXYZ >>>
+ 9<<< >>>
+ 60<<< 123456789 >>>
+ \ No newline at end of file
diff --git a/tests/pr/o3a3Sl24f-tn b/tests/pr/o3a3Sl24f-tn
new file mode 100644
index 0000000..0064f2f
--- /dev/null
+++ b/tests/pr/o3a3Sl24f-tn
@@ -0,0 +1,32 @@
+
+
+ -- Date/Time -- x Page 1
+
+
+ 1 Test-INPUT: "With:--:2 Options -b -3 [+2:--:3 Options -a -3 [+2
+ 4 Options [+2:--:5 :--:6 -----------------
+ 7 3456789 123456789 1:--:8 3 Columns downwar:--:9 With columns use
+ 10 without -f e.g.: :--:1 with -f e.g. : :--:2
+ 3 line truncation bef:--:14 456789 123456789 1:--:15 xyzxyzxyz XYZXYZXY
+ 16 456789 123456789 x:--:7 :--:8
+ 9 3456789 ab :--:20 DEFGHI 123 :--:1
+ 2 :--:3 :--:4
+ 5 :--:6 :--:27 no truncation befo
+ 28 no trunc :--:29 xyzxyzxyz XYZXYZXY:--:30 456789 123456789 x
+ 1 :--:2 3456789 abcdefghi :--:3
+ 4 :--:5 :--:6
+ 7 :--:8 :--:9 3456789 abcdefghi
+ 40 DEFGHI 123456789 :--:41 yzxyzxyz XYZXYZXYZ:--:42 456789 123456789 a
+
+
+ -- Date/Time -- x Page 2
+
+
+ 43 xyzxyzxyz XYZXYZXY:--:44 456789 123456789 x:--:5
+ 6 :--:7 :--:8
+ 9 :--:50 :--:1
+ 2 :--:3 :--:4
+ 55 yzxyzxyz XYZXYZXYZ:--:56 456789 123456789 a:--:57 xyzxyzxyz XYZXYZXY
+ 58 456789 123456789 x:--:9 :--:60 DEFGHI 123456789
+ 1 :--:2 :--:3 ------- EOF ------
+ \ No newline at end of file
diff --git a/tests/pr/o3a3Snl24f-tn b/tests/pr/o3a3Snl24f-tn
new file mode 100644
index 0000000..5a8f263
--- /dev/null
+++ b/tests/pr/o3a3Snl24f-tn
@@ -0,0 +1,32 @@
+
+
+ -- Date/Time -- x Page 1
+
+
+ 1.1 Test-INPUT::--: 2.2 Options -b :--: 3.3 Options -a
+ 4.4 Options :--: 5.5 :--: 6.6 -----------
+ 7.7 3456789 12345:--: 8.8 3 Columns d:--: 9.9 With column
+ 10.10 without -f :--: 11.1 with -f e.g:--: 12.2
+ 13.3 line truncati:--: 14.14 456789 12345:--: 15.15 xyzxyzxyz XY
+ 16.16 456789 12345:--: 17.7 :--: 18.8
+ 19.9 3456789 ab :--: 20.20 DEFGHI 123 :--: 21.1
+ 22.2 :--: 23.3 :--: 24.4
+ 25.5 :--: 26.6 :--: 27.27 no truncatio
+ 28.28 no trunc :--: 29.29 xyzxyzxyz XY:--: 30.30 456789 12345
+ 31.1 :--: 32.2 3456789 abcde:--: 33.3
+ 34.4 :--: 35.5 :--: 36.6
+ 37.7 :--: 38.8 :--: 39.9 3456789 abcde
+ 40.40 DEFGHI 12345:--: 41.41 yzxyzxyz XYZ:--: 42.42 456789 12345
+
+
+ -- Date/Time -- x Page 2
+
+
+ 43.43 xyzxyzxyz XY:--: 44.44 456789 12345:--: 45.5
+ 46.6 :--: 47.7 :--: 48.8
+ 49.9 :--: 50.50 :--: 51.1
+ 52.2 :--: 53.3 :--: 54.4
+ 55.55 yzxyzxyz XYZ:--: 56.56 456789 12345:--: 57.57 xyzxyzxyz XY
+ 58.58 456789 12345:--: 59.9 :--: 60.60 DEFGHI 12345
+ 61.1 :--: 62.2 :--: 63.3 ------- EOF
+ \ No newline at end of file
diff --git a/tests/pr/o3a3l24f-tn b/tests/pr/o3a3l24f-tn
new file mode 100644
index 0000000..9adbe67
--- /dev/null
+++ b/tests/pr/o3a3l24f-tn
@@ -0,0 +1,32 @@
+
+
+ -- Date/Time -- x Page 1
+
+
+ 1 Test-INPUT: "Withou 2 Options -b -3 [+2|+ 3 Options -a -3 [+2|+
+ 4 Options [+2|+ 5 6 -------------------
+ 7 3456789 123456789 123 8 3 Columns downwards 9 With columns use <
+ 10 without -f e.g.: - 1 with -f e.g. : - 2
+ 3 line truncation befor 14 456789 123456789 123 15 xyzxyzxyz XYZXYZXYZ
+ 16 456789 123456789 xyz 7 8
+ 9 3456789 ab 20 DEFGHI 123 1
+ 2 3 4
+ 5 6 27 no truncation before
+ 28 no trunc 29 xyzxyzxyz XYZXYZXYZ 30 456789 123456789 xyz
+ 1 2 3456789 abcdefghi 3
+ 4 5 6
+ 7 8 9 3456789 abcdefghi
+ 40 DEFGHI 123456789 41 yzxyzxyz XYZXYZXYZ a 42 456789 123456789 abc
+
+
+ -- Date/Time -- x Page 2
+
+
+ 43 xyzxyzxyz XYZXYZXYZ 44 456789 123456789 xyz 5
+ 6 7 8
+ 9 50 1
+ 2 3 4
+ 55 yzxyzxyz XYZXYZXYZ a 56 456789 123456789 abc 57 xyzxyzxyz XYZXYZXYZ
+ 58 456789 123456789 xyz 9 60 DEFGHI 123456789
+ 1 2 3 ------- EOF --------
+ \ No newline at end of file
diff --git a/tests/pr/o3b3Sl24f-tn b/tests/pr/o3b3Sl24f-tn
new file mode 100644
index 0000000..2e11983
--- /dev/null
+++ b/tests/pr/o3b3Sl24f-tn
@@ -0,0 +1,32 @@
+
+
+ -- Date/Time -- x Page 1
+
+
+ 1 Test-INPUT: "With:--:15 xyzxyzxyz XYZXYZXY:--:29 xyzxyzxyz XYZXYZXY
+ 2 Options -b -3 [+2:--:16 456789 123456789 x:--:30 456789 123456789 x
+ 3 Options -a -3 [+2:--:7 :--:1
+ 4 Options [+2:--:8 :--:2 3456789 abcdefghi
+ 5 :--:9 3456789 ab :--:3
+ 6 -----------------:--:20 DEFGHI 123 :--:4
+ 7 3456789 123456789 1:--:1 :--:5
+ 8 3 Columns downwar:--:2 :--:6
+ 9 With columns use :--:3 :--:7
+ 10 without -f e.g.: :--:4 :--:8
+ 1 with -f e.g. : :--:5 :--:9 3456789 abcdefghi
+ 2 :--:6 :--:40 DEFGHI 123456789
+ 3 line truncation bef:--:27 no truncation befo:--:41 yzxyzxyz XYZXYZXYZ
+ 14 456789 123456789 1:--:28 no trunc :--:42 456789 123456789 a
+
+
+ -- Date/Time -- x Page 2
+
+
+ 43 xyzxyzxyz XYZXYZXY:--:50 :--:57 xyzxyzxyz XYZXYZXY
+ 44 456789 123456789 x:--:1 :--:58 456789 123456789 x
+ 5 :--:2 :--:9
+ 6 :--:3 :--:60 DEFGHI 123456789
+ 7 :--:4 :--:1
+ 8 :--:55 yzxyzxyz XYZXYZXYZ:--:2
+ 9 :--:56 456789 123456789 a:--:3 ------- EOF ------
+ \ No newline at end of file
diff --git a/tests/pr/o3b3Snl24f-tn b/tests/pr/o3b3Snl24f-tn
new file mode 100644
index 0000000..1b945fe
--- /dev/null
+++ b/tests/pr/o3b3Snl24f-tn
@@ -0,0 +1,32 @@
+
+
+ -- Date/Time -- x Page 1
+
+
+ 1.1 Test-INPUT::--: 15.15 xyzxyzxyz XY:--: 29.29 xyzxyzxyz XY
+ 2.2 Options -b :--: 16.16 456789 12345:--: 30.30 456789 12345
+ 3.3 Options -a :--: 17.7 :--: 31.1
+ 4.4 Options :--: 18.8 :--: 32.2 3456789 abcde
+ 5.5 :--: 19.9 3456789 ab :--: 33.3
+ 6.6 -----------:--: 20.20 DEFGHI 123 :--: 34.4
+ 7.7 3456789 12345:--: 21.1 :--: 35.5
+ 8.8 3 Columns d:--: 22.2 :--: 36.6
+ 9.9 With column:--: 23.3 :--: 37.7
+ 10.10 without -f :--: 24.4 :--: 38.8
+ 11.1 with -f e.g:--: 25.5 :--: 39.9 3456789 abcde
+ 12.2 :--: 26.6 :--: 40.40 DEFGHI 12345
+ 13.3 line truncati:--: 27.27 no truncatio:--: 41.41 yzxyzxyz XYZ
+ 14.14 456789 12345:--: 28.28 no trunc :--: 42.42 456789 12345
+
+
+ -- Date/Time -- x Page 2
+
+
+ 43.43 xyzxyzxyz XY:--: 50.50 :--: 57.57 xyzxyzxyz XY
+ 44.44 456789 12345:--: 51.1 :--: 58.58 456789 12345
+ 45.5 :--: 52.2 :--: 59.9
+ 46.6 :--: 53.3 :--: 60.60 DEFGHI 12345
+ 47.7 :--: 54.4 :--: 61.1
+ 48.8 :--: 55.55 yzxyzxyz XYZ:--: 62.2
+ 49.9 :--: 56.56 456789 12345:--: 63.3 ------- EOF
+ \ No newline at end of file
diff --git a/tests/pr/o3b3l24f-tn b/tests/pr/o3b3l24f-tn
new file mode 100644
index 0000000..0d237bb
--- /dev/null
+++ b/tests/pr/o3b3l24f-tn
@@ -0,0 +1,32 @@
+
+
+ -- Date/Time -- x Page 1
+
+
+ 1 Test-INPUT: "Withou 15 xyzxyzxyz XYZXYZXYZ 29 xyzxyzxyz XYZXYZXYZ
+ 2 Options -b -3 [+2|+ 16 456789 123456789 xyz 30 456789 123456789 xyz
+ 3 Options -a -3 [+2|+ 7 1
+ 4 Options [+2|+ 8 2 3456789 abcdefghi
+ 5 9 3456789 ab 3
+ 6 ------------------- 20 DEFGHI 123 4
+ 7 3456789 123456789 123 1 5
+ 8 3 Columns downwards 2 6
+ 9 With columns use < 3 7
+ 10 without -f e.g.: - 4 8
+ 1 with -f e.g. : - 5 9 3456789 abcdefghi
+ 2 6 40 DEFGHI 123456789
+ 3 line truncation befor 27 no truncation before 41 yzxyzxyz XYZXYZXYZ a
+ 14 456789 123456789 123 28 no trunc 42 456789 123456789 abc
+
+
+ -- Date/Time -- x Page 2
+
+
+ 43 xyzxyzxyz XYZXYZXYZ 50 57 xyzxyzxyz XYZXYZXYZ
+ 44 456789 123456789 xyz 1 58 456789 123456789 xyz
+ 5 2 9
+ 6 3 60 DEFGHI 123456789
+ 7 4 1
+ 8 55 yzxyzxyz XYZXYZXYZ a 2
+ 9 56 456789 123456789 abc 3 ------- EOF --------
+ \ No newline at end of file
diff --git a/tests/pr/o3mSl24f-bl-tn b/tests/pr/o3mSl24f-bl-tn
new file mode 100644
index 0000000..c90a2b4
--- /dev/null
+++ b/tests/pr/o3mSl24f-bl-tn
@@ -0,0 +1,157 @@
+
+
+ -- Date/Time -- x Page 1
+
+
+ 1 FF-Test: FF's in Text :--:1 Test-INPUT: "Without FF set by
+ 2 Options -n; :--:2 Options -b -3 [+2|+3] [-l 15|8
+ 3 numbering lines with skiped pa:--:3 Options -a -3 [+2|+3] [-l 15|8
+ 4 numbering blanc lines (no. 5,1:--:4 Options [+2|+3] [-l 24|1
+ :--:5
+ 6 3456789 123456789 123456789 1234:--:6 ------------------------------
+ 7 3 Columns downwards ..., <= 5 :--:7 3456789 123456789 123456789 1234
+ 8 :--:8 3 Columns downwards, across, .
+ 9 :--:9 With columns use <= 5 text li
+ 10 zzzzzzzzzzzzzzzzzzzzzzzzzz1234:--:10 without -f e.g.: -l 15 = tota
+ 1 :--:1 with -f e.g. : -l 8 -f
+ :--:2
+ :--:3 line truncation before new page;
+ 14 456789 123456789 123456789 1234:--:14 456789 123456789 123456789 1234
+
+
+ -- Date/Time -- x Page 2
+
+
+ :--:15 xyzxyzxyz XYZXYZXYZ abcabcab
+ :--:16 456789 123456789 xyzxyzxyz XYZX
+ :--:7
+ :--:8
+ :--:9 3456789 ab
+ :--:20 DEFGHI 123
+ :--:1
+ :--:2
+ :--:3
+ :--:4
+ :--:5
+ :--:6
+ :--:27 no truncation before nwe page;
+ :--:28 no trunc
+
+
+ -- Date/Time -- x Page 3
+
+
+ 15 xyzxyzxyz XYZXYZXYZ abcabcab :--:29 xyzxyzxyz XYZXYZXYZ abcabcab
+ 16 456789 123456789 xyzxyzxyz XYZX:--:30 456789 123456789 xyzxyzxyz XYZX
+ 7 :--:1
+ 8 :--:2 3456789 abcdefghi
+ 9 3456789 ab :--:3
+ 20 DEFGHI 123 :--:4
+ 1 :--:5
+ :--:6
+ :--:7
+ 4 :--:8
+ 5 :--:9 3456789 abcdefghi
+ 6 :--:40 DEFGHI 123456789
+ 27 no truncation before FF; (r_l-t:--:41 yzxyzxyz XYZXYZXYZ abcabcab
+ :--:42 456789 123456789 abcdefghi ABCD
+
+
+ -- Date/Time -- x Page 4
+
+
+ :--:43 xyzxyzxyz XYZXYZXYZ abcabcab
+ :--:44 456789 123456789 xyzxyzxyz XYZX
+ :--:5
+ :--:6
+ :--:7
+ :--:8
+ :--:9
+ :--:50
+ :--:1
+ :--:2
+ :--:3
+ :--:4
+ :--:55 yzxyzxyz XYZXYZXYZ abcabcab
+ :--:56 456789 123456789 abcdefghi ABCD
+
+
+ -- Date/Time -- x Page 5
+
+
+ 29 xyzxyzxyz XYZXYZXYZ abcabcab :--:57 xyzxyzxyz XYZXYZXYZ abcabcab
+ 30 456789 123456789 xyzxyzxyz XYZX:--:58 456789 123456789 xyzxyzxyz XYZX
+ 1 :--:9
+ 2 3456789 abcdefghi :--:60 DEFGHI 123456789
+ 3 :--:1
+ 4 :--:2
+ :--:3 ------- EOF -------- EOF ------
+ 6 :--:
+ 7 :--:
+ 8 :--:
+ 9 3456789 abcdefghi :--:
+ 40 DEFGHI 123456789 :--:
+ 41 yzxyzxyz XYZXYZXYZ abcabcab :--:
+ 42 456789 123456789 abcdefghi ABCD
+
+
+ -- Date/Time -- x Page 6
+
+
+
+
+
+ -- Date/Time -- x Page 7
+
+
+
+
+
+ -- Date/Time -- x Page 8
+
+
+ 43 xyzxyzxyz XYZXYZXYZ abcabcab :--:
+ 44 456789 123456789 xyzxyzxyz XYZX:--:
+ 5 :--:
+ 6 :--:
+ 7 :--:
+ 8 :--:
+ 9 :--:
+ 50 :--:
+ 1 :--:
+ :--:
+ :--:
+ :--:
+ 55 yzxyzxyz XYZXYZXYZ abcabcab :--:
+ 56 456789 123456789 abcdefghi ABCD
+
+
+ -- Date/Time -- x Page 9
+
+
+ :--:
+ 58 456789 123456789 xyzxyzxyz XYZX:--:
+ 9 :--:
+ 60 DEFGHI 123456789 :--:
+ 61 yzxyzxyz XYZXYZXYZ abcabcab :--:
+ 62 456789 123456789 abcdefghi ABCD:--:
+ 63 xyzxyzxyz XYZXYZXYZ abcabcab :--:
+ 64 456789 123456789 xyzxyzxyz XYZX:--:
+ 5 :--:
+ 6 :--:
+ 7 :--:
+ 8 :--:
+ 9 :--:
+ 70 456789 123456789 abcdefghi ABC:--:
+
+
+ -- Date/Time -- x Page 10
+
+
+ 1 :--:
+ :--:
+ :--:
+ :--:
+ 74 yzxyzxyz XYZXYZXYZ abcabcab :--:
+ 75 456789 123456789 abcdefghi ABCD
+ \ No newline at end of file
diff --git a/tests/pr/o3mSnl24fbltn b/tests/pr/o3mSnl24fbltn
new file mode 100644
index 0000000..655b56f
--- /dev/null
+++ b/tests/pr/o3mSnl24fbltn
@@ -0,0 +1,157 @@
+
+
+ -- Date/Time -- x Page 1
+
+
+ 1.1 FF-Test: FF's in Text :--:1 Test-INPUT: "Without FF set
+ 2.2 Options -n; :--:2 Options -b -3 [+2|+3] [-l 1
+ 3.3 numbering lines with skiped:--:3 Options -a -3 [+2|+3] [-l 1
+ 4.4 numbering blanc lines (no. :--:4 Options [+2|+3] [-l 2
+ 5. :--:5
+ 6.6 3456789 123456789 123456789 1:--:6 ---------------------------
+ 7.7 3 Columns downwards ..., <=:--:7 3456789 123456789 123456789 1
+ 8.8 :--:8 3 Columns downwards, across
+ 9.9 :--:9 With columns use <= 5 text
+ 10.10 zzzzzzzzzzzzzzzzzzzzzzzzzz1:--:10 without -f e.g.: -l 15 = t
+ 11.1 :--:1 with -f e.g. : -l 8 -f
+ 12. :--:2
+ 13. :--:3 line truncation before new pa
+ 14.14 456789 123456789 123456789 1:--:14 456789 123456789 123456789 1
+
+
+ -- Date/Time -- x Page 2
+
+
+ 15. :--:15 xyzxyzxyz XYZXYZXYZ abcabcab
+ 16. :--:16 456789 123456789 xyzxyzxyz X
+ 17. :--:7
+ 18. :--:8
+ 19. :--:9 3456789 ab
+ 20. :--:20 DEFGHI 123
+ 21. :--:1
+ 22. :--:2
+ 23. :--:3
+ 24. :--:4
+ 25. :--:5
+ 26. :--:6
+ 27. :--:27 no truncation before nwe pag
+ 28. :--:28 no trunc
+
+
+ -- Date/Time -- x Page 3
+
+
+ 29.15 xyzxyzxyz XYZXYZXYZ abcabcab:--:29 xyzxyzxyz XYZXYZXYZ abcabcab
+ 30.16 456789 123456789 xyzxyzxyz X:--:30 456789 123456789 xyzxyzxyz X
+ 31.7 :--:1
+ 32.8 :--:2 3456789 abcdefghi
+ 33.9 3456789 ab :--:3
+ 34.20 DEFGHI 123 :--:4
+ 35.1 :--:5
+ 36. :--:6
+ 37. :--:7
+ 38.4 :--:8
+ 39.5 :--:9 3456789 abcdefghi
+ 40.6 :--:40 DEFGHI 123456789
+ 41.27 no truncation before FF; (r_:--:41 yzxyzxyz XYZXYZXYZ abcabcab
+ 42. :--:42 456789 123456789 abcdefghi A
+
+
+ -- Date/Time -- x Page 4
+
+
+ 43. :--:43 xyzxyzxyz XYZXYZXYZ abcabcab
+ 44. :--:44 456789 123456789 xyzxyzxyz X
+ 45. :--:5
+ 46. :--:6
+ 47. :--:7
+ 48. :--:8
+ 49. :--:9
+ 50. :--:50
+ 51. :--:1
+ 52. :--:2
+ 53. :--:3
+ 54. :--:4
+ 55. :--:55 yzxyzxyz XYZXYZXYZ abcabcab
+ 56. :--:56 456789 123456789 abcdefghi A
+
+
+ -- Date/Time -- x Page 5
+
+
+ 57.29 xyzxyzxyz XYZXYZXYZ abcabcab:--:57 xyzxyzxyz XYZXYZXYZ abcabcab
+ 58.30 456789 123456789 xyzxyzxyz X:--:58 456789 123456789 xyzxyzxyz X
+ 59.1 :--:9
+ 60.2 3456789 abcdefghi :--:60 DEFGHI 123456789
+ 61.3 :--:1
+ 62.4 :--:2
+ 63. :--:3 ------- EOF -------- EOF ---
+ 64.6 :--:
+ 65.7 :--:
+ 66.8 :--:
+ 67.9 3456789 abcdefghi :--:
+ 68.40 DEFGHI 123456789 :--:
+ 69.41 yzxyzxyz XYZXYZXYZ abcabcab :--:
+ 70.42 456789 123456789 abcdefghi A
+
+
+ -- Date/Time -- x Page 6
+
+
+
+
+
+ -- Date/Time -- x Page 7
+
+
+
+
+
+ -- Date/Time -- x Page 8
+
+
+ 71.43 xyzxyzxyz XYZXYZXYZ abcabcab:--:
+ 72.44 456789 123456789 xyzxyzxyz X:--:
+ 73.5 :--:
+ 74.6 :--:
+ 75.7 :--:
+ 76.8 :--:
+ 77.9 :--:
+ 78.50 :--:
+ 79.1 :--:
+ 80. :--:
+ 81. :--:
+ 82. :--:
+ 83.55 yzxyzxyz XYZXYZXYZ abcabcab :--:
+ 84.56 456789 123456789 abcdefghi A
+
+
+ -- Date/Time -- x Page 9
+
+
+ 85. :--:
+ 86.58 456789 123456789 xyzxyzxyz X:--:
+ 87.9 :--:
+ 88.60 DEFGHI 123456789 :--:
+ 89.61 yzxyzxyz XYZXYZXYZ abcabcab :--:
+ 90.62 456789 123456789 abcdefghi A:--:
+ 91.63 xyzxyzxyz XYZXYZXYZ abcabcab:--:
+ 92.64 456789 123456789 xyzxyzxyz X:--:
+ 93.5 :--:
+ 94.6 :--:
+ 95.7 :--:
+ 96.8 :--:
+ 97.9 :--:
+ 98.70 456789 123456789 abcdefghi :--:
+
+
+ -- Date/Time -- x Page 10
+
+
+ 99.1 :--:
+ 100. :--:
+ 101. :--:
+ 102. :--:
+ 103.74 yzxyzxyz XYZXYZXYZ abcabcab :--:
+ 104.75 456789 123456789 abcdefghi A
+ \ No newline at end of file
diff --git a/tests/pr/o3ml24f-bl-tn b/tests/pr/o3ml24f-bl-tn
new file mode 100644
index 0000000..5109be0
--- /dev/null
+++ b/tests/pr/o3ml24f-bl-tn
@@ -0,0 +1,157 @@
+
+
+ -- Date/Time -- x Page 1
+
+
+ 1 FF-Test: FF's in Text 1 Test-INPUT: "Without FF set by
+ 2 Options -n; 2 Options -b -3 [+2|+3] [-l 15|8]
+ 3 numbering lines with skiped pag 3 Options -a -3 [+2|+3] [-l 15|8]
+ 4 numbering blanc lines (no. 5,12 4 Options [+2|+3] [-l 24|17
+ 5
+ 6 3456789 123456789 123456789 12345 6 -------------------------------
+ 7 3 Columns downwards ..., <= 5 l 7 3456789 123456789 123456789 12345
+ 8 8 3 Columns downwards, across, ..
+ 9 9 With columns use <= 5 text lin
+ 10 zzzzzzzzzzzzzzzzzzzzzzzzzz12345 10 without -f e.g.: -l 15 = total
+ 1 1 with -f e.g. : -l 8 -f
+ 2
+ 3 line truncation before new page;
+ 14 456789 123456789 123456789 12345 14 456789 123456789 123456789 12345
+
+
+ -- Date/Time -- x Page 2
+
+
+ 15 xyzxyzxyz XYZXYZXYZ abcabcab
+ 16 456789 123456789 xyzxyzxyz XYZXY
+ 7
+ 8
+ 9 3456789 ab
+ 20 DEFGHI 123
+ 1
+ 2
+ 3
+ 4
+ 5
+ 6
+ 27 no truncation before nwe page; (
+ 28 no trunc
+
+
+ -- Date/Time -- x Page 3
+
+
+ 15 xyzxyzxyz XYZXYZXYZ abcabcab 29 xyzxyzxyz XYZXYZXYZ abcabcab
+ 16 456789 123456789 xyzxyzxyz XYZXY 30 456789 123456789 xyzxyzxyz XYZXY
+ 7 1
+ 8 2 3456789 abcdefghi
+ 9 3456789 ab 3
+ 20 DEFGHI 123 4
+ 1 5
+ 6
+ 7
+ 4 8
+ 5 9 3456789 abcdefghi
+ 6 40 DEFGHI 123456789
+ 27 no truncation before FF; (r_l-te 41 yzxyzxyz XYZXYZXYZ abcabcab
+ 42 456789 123456789 abcdefghi ABCDE
+
+
+ -- Date/Time -- x Page 4
+
+
+ 43 xyzxyzxyz XYZXYZXYZ abcabcab
+ 44 456789 123456789 xyzxyzxyz XYZXY
+ 5
+ 6
+ 7
+ 8
+ 9
+ 50
+ 1
+ 2
+ 3
+ 4
+ 55 yzxyzxyz XYZXYZXYZ abcabcab
+ 56 456789 123456789 abcdefghi ABCDE
+
+
+ -- Date/Time -- x Page 5
+
+
+ 29 xyzxyzxyz XYZXYZXYZ abcabcab 57 xyzxyzxyz XYZXYZXYZ abcabcab
+ 30 456789 123456789 xyzxyzxyz XYZXY 58 456789 123456789 xyzxyzxyz XYZXY
+ 1 9
+ 2 3456789 abcdefghi 60 DEFGHI 123456789
+ 3 1
+ 4 2
+ 3 ------- EOF -------- EOF -------
+ 6
+ 7
+ 8
+ 9 3456789 abcdefghi
+ 40 DEFGHI 123456789
+ 41 yzxyzxyz XYZXYZXYZ abcabcab
+ 42 456789 123456789 abcdefghi ABCDE
+
+
+ -- Date/Time -- x Page 6
+
+
+
+
+
+ -- Date/Time -- x Page 7
+
+
+
+
+
+ -- Date/Time -- x Page 8
+
+
+ 43 xyzxyzxyz XYZXYZXYZ abcabcab
+ 44 456789 123456789 xyzxyzxyz XYZXY
+ 5
+ 6
+ 7
+ 8
+ 9
+ 50
+ 1
+
+
+
+ 55 yzxyzxyz XYZXYZXYZ abcabcab
+ 56 456789 123456789 abcdefghi ABCDE
+
+
+ -- Date/Time -- x Page 9
+
+
+
+ 58 456789 123456789 xyzxyzxyz XYZXY
+ 9
+ 60 DEFGHI 123456789
+ 61 yzxyzxyz XYZXYZXYZ abcabcab
+ 62 456789 123456789 abcdefghi ABCDE
+ 63 xyzxyzxyz XYZXYZXYZ abcabcab
+ 64 456789 123456789 xyzxyzxyz XYZXY
+ 5
+ 6
+ 7
+ 8
+ 9
+ 70 456789 123456789 abcdefghi ABCD
+
+
+ -- Date/Time -- x Page 10
+
+
+ 1
+
+
+
+ 74 yzxyzxyz XYZXYZXYZ abcabcab
+ 75 456789 123456789 abcdefghi ABCDE
+ \ No newline at end of file
diff --git a/tests/pr/pr-tests.pl b/tests/pr/pr-tests.pl
new file mode 100755
index 0000000..eafc13d
--- /dev/null
+++ b/tests/pr/pr-tests.pl
@@ -0,0 +1,524 @@
+#!/usr/bin/perl
+# Test pr.
+
+# Copyright (C) 2008-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+use strict;
+
+# Turn off localization of executable's output.
+@ENV{qw(LANGUAGE LANG LC_ALL)} = ('C') x 3;
+
+my $prog = 'pr';
+my $normalize_strerror = "s/': .*/'/";
+
+my @tv = (
+
+# -b option is no longer an official option. But it's still working to
+# get a downward compatibility. Now (version 1.19m or newer) -COLUMN
+# only is equivalent to -b -COLUMN.
+#
+# test_name options input-file-name(s) expected-output-group-file-name
+# expected-return-code
+# -------------------------------------------------------------------------
+# Following tests with "FF set" don't contain a complete set of all
+# combinations of options and FF-arrangements
+#
+# One FF at start of file (one empty page)
+# ['1a', '', [\'0Ft'], [\'0F'], 0],
+['1b', '', [\'0Fnt'], [\'0F'], 0],
+['1c', '+3', [\'0Ft'], [\'3-0F'], 0],
+['1d', '+3 -f', [\'0Ft'], [\'3f-0F'], 0],
+['1e', '-a -3', [\'0Ft'], [\'a3-0F'], 0],
+['1f', '-a -3 -f', [\'0Ft'], [\'a3f-0F'], 0],
+['1g', '-a -3 -f', [\'0Fnt'], [\'a3f-0F'], 0],
+['1h', '+3 -a -3 -f', [\'0Ft'], [\'3a3f-0F'], 0],
+['1i', '-b -3', [\'0Ft'], [\'b3-0F'], 0],
+['1j', '-b -3 -f', [\'0Ft'], [\'b3f-0F'], 0],
+['1k', '-b -3 -f', [\'0Fnt'], [\'b3f-0F'], 0],
+['1l', '+3 -b -3 -f', [\'0Ft'], [\'3b3f-0F'], 0],
+# Two FF at start of file (two empty page)
+['2a', '', [\'0FFt'], [\'0FF'], 0],
+['2b', '', [\'0FnFnt'], [\'0FF'], 0],
+['2c', '-a -3 -f', [\'0FFt'], [\'a3f-0FF'], 0],
+['2d', '-a -3 -f', [\'0FFnt'], [\'a3f-0FF'], 0],
+['2e', '-b -3 -f', [\'0FFt'], [\'b3f-0FF'], 0],
+['2f', '-b -3 -f', [\'0FFnt'], [\'b3f-0FF'], 0],
+['2g', '-b -3 -f', [\'0FnFt'], [\'b3f-0FF'], 0],
+['2h', '-b -3 -f', [\'0FnFnt'], [\'b3f-0FF'], 0],
+['2i', '+3 -b -3 -f', [\'0FFt'], [\'3b3f-0FF'], 0],
+['2j', '+3 -b -3 -f', [\'0FFnt'], [\'3b3f-0FF'], 0],
+#
+# FFs in text (none / one / two empty page(s))
+['3a', '', [\'FFn'], [\'FF'], 0],
+['3b', '', [\'FnFn'], [\'FF'], 0],
+['3c', '+3', [\'FFn'], [\'3-FF'], 0],
+['3d', '+3 -f', [\'FFn'], [\'3f-FF'], 0],
+['3e', '-a -3 -f', [\'FFn'], [\'a3f-FF'], 0],
+['3f', '-a -3 -f', [\'FFtn'], [\'a3f-FF'], 0],
+['3g', '-b -3 -f', [\'FFn'], [\'b3f-FF'], 0],
+['3h', '-b -3 -f', [\'FFtn'], [\'b3f-FF'], 0],
+['3i', '-b -3 -f', [\'FnFn'], [\'b3f-FF'], 0],
+['3j', '-b -3 -f', [\'tFFn'], [\'b3f-FF'], 0],
+['3k', '-b -3 -f', [\'tFnFt'], [\'b3f-FF'], 0],
+['3l', '+3 -b -3 -f', [\'FFn'], [\'3b3f-FF'], 0],
+['3m', '+3 -b -3 -f', [\'FFtn'], [\'3b3f-FF'], 0],
+# A full page printed (lines_left_on_page = 0) without a FF found.
+# Avoid an extra empty page if a FF follows in the next input line.
+['3la', '-l 24', [\'FFn'], [\'l24-FF'], 0],
+['3lb', '-l 24', [\'FFtn'], [\'l24-FF'], 0],
+['3lc', '-l 24', [\'FnFn'], [\'l24-FF'], 0],
+['3ld', '-l 24', [\'tFFn'], [\'l24-FF'], 0],
+['3le', '-l 24', [\'tFnFt'], [\'l24-FF'], 0],
+['3lf', '-l 24', [\'tFFt'], [\'l24-FF'], 0],
+['3aa', '-a -2 -l 17', [\'FFn'], [\'a2l17-FF'], 0],
+['3ab', '-a -2 -l 17', [\'FFtn'], [\'a2l17-FF'], 0],
+['3ac', '-a -2 -l 17', [\'FnFn'], [\'a2l17-FF'], 0],
+['3ad', '-a -2 -l 17', [\'tFFn'], [\'a2l17-FF'], 0],
+['3ae', '-a -2 -l 17', [\'tFnFt'], [\'a2l17-FF'], 0],
+['3af', '-a -2 -l 17', [\'tFFt'], [\'a2l17-FF'], 0],
+['3ag', '-a -2 -l 15', [\'FFn'], [\'a2l15-FF'], 0],
+['3ah', '-a -2 -l 15', [\'FFtn'], [\'a2l15-FF'], 0],
+['3ai', '-a -2 -l 15', [\'FnFn'], [\'a2l15-FF'], 0],
+['3aj', '-a -2 -l 15', [\'tFFn'], [\'a2l15-FF'], 0],
+['3ak', '-a -2 -l 15', [\'tFnFt'], [\'a2l15-FF'], 0],
+['3ba', '-b -2 -l 17', [\'FFn'], [\'b2l17-FF'], 0],
+['3bb', '-b -2 -l 17', [\'FFtn'], [\'b2l17-FF'], 0],
+['3bc', '-b -2 -l 17', [\'FnFn'], [\'b2l17-FF'], 0],
+['3bd', '-b -2 -l 17', [\'tFFn'], [\'b2l17-FF'], 0],
+['3be', '-b -2 -l 17', [\'tFnFt'], [\'b2l17-FF'], 0],
+['3bf', '-b -2 -l 17', [\'tFFt'], [\'b2l17-FF'], 0],
+['3bg', '-b -2 -l 15', [\'FFn'], [\'b2l15-FF'], 0],
+['3bh', '-b -2 -l 15', [\'FFtn'], [\'b2l15-FF'], 0],
+['3bi', '-b -2 -l 15', [\'FnFn'], [\'b2l15-FF'], 0],
+['3bj', '-b -2 -l 15', [\'tFFn'], [\'b2l15-FF'], 0],
+['3bk', '-b -2 -l 15', [\'tFnFt'], [\'b2l15-FF'], 0],
+['3Pa', '+4 -l 24', [\'FFn'], [\'4l24-FF'], 0],
+['3Pb', '+4 -l 24', [\'FFtn'], [\'4l24-FF'], 0],
+['3Pc', '+4 -l 24', [\'FnFn'], [\'4l24-FF'], 0],
+['3Pd', '+4 -l 24', [\'tFFn'], [\'4l24-FF'], 0],
+['3Pe', '+4 -l 24', [\'tFnFt'], [\'4l24-FF'], 0],
+['3Pf', '+4 -l 24', [\'tFFt'], [\'4l24-FF'], 0],
+['3Pg', '+4:7 -l 24', [\'tFFt'], [\'4-7l24-FF'], 0],
+['3Paa', '+3 -a -2 -l 17', [\'FFn'], [\'3a2l17-FF'], 0],
+['3Pab', '+3 -a -2 -l 17', [\'FFtn'], [\'3a2l17-FF'], 0],
+['3Pac', '+3 -a -2 -l 17', [\'FnFn'], [\'3a2l17-FF'], 0],
+['3Pad', '+3 -a -2 -l 17', [\'tFFn'], [\'3a2l17-FF'], 0],
+['3Pae', '+3 -a -2 -l 17', [\'tFnFt'], [\'3a2l17-FF'], 0],
+['3Paf', '+3 -a -2 -l 17', [\'tFFt'], [\'3a2l17-FF'], 0],
+['3Pba', '+3 -b -2 -l 17', [\'FFn'], [\'3b2l17-FF'], 0],
+['3Pbb', '+3 -b -2 -l 17', [\'FFtn'], [\'3b2l17-FF'], 0],
+['3Pbc', '+3 -b -2 -l 17', [\'FnFn'], [\'3b2l17-FF'], 0],
+['3Pbd', '+3 -b -2 -l 17', [\'tFFn'], [\'3b2l17-FF'], 0],
+['3Pbe', '+3 -b -2 -l 17', [\'tFnFt'], [\'3b2l17-FF'], 0],
+['3Pbf', '+3 -b -2 -l 17', [\'tFFt'], [\'3b2l17-FF'], 0],
+#
+# Without "FF set by hand"
+['4a', '-l 24', [\'tn'], [\'l24-t'], 0],
+['4b', '-l 24 -f', [\'tn'], [\'l24f-t'], 0],
+['4c', '+3 -l 24', [\'tn'], [\'3l24-t'], 0],
+['4d', '+3 -l 24 -f', [\'tn'], [\'3l24f-t'], 0],
+['4e', '+3:5 -l 24 -f', [\'tn'], [\'3-5l24f-t'], 0],
+['4f', '-a -3 -l 15', [\'tn'], [\'a3l15-t'], 0],
+['4g', '-a -3 -l 15 -f', [\'tn'], [\'a3l15f-t'], 0],
+['4h', '+3 -a -3 -l 15', [\'tn'], [\'3a3l15-t'], 0],
+['4i', '+3 -a -3 -l 15 -f', [\'tn'], [\'3a3l15f-t'], 0],
+['4j', '-b -3 -l 15', [\'tn'], [\'b3l15-t'], 0],
+['4k', '-b -3 -l 15 -f', [\'tn'], [\'b3l15f-t'], 0],
+['4l', '+3 -b -3 -l 15', [\'tn'], [\'3b3l15-t'], 0],
+['4m', '+3 -b -3 -l 15 -f', [\'tn'], [\'3b3l15f-t'], 0],
+#
+# Merge input files (-m option)
+['5a', '-m -l 24', [\'tn', \'tn'], [\'ml24-t'], 0],
+['5b', '-m -l 24 -f', [\'tn', \'tn'], [\'ml24f-t'], 0],
+['5c', '+3 -m -l 24', [\'tn', \'tn'], [\'3ml24-t'], 0],
+['5d', '+3 -m -l 24 -f', [\'tn', \'tn'], [\'3ml24f-t'], 0],
+['5e', '-m -l 24 -f', [\'0Ft', \'0Ft'], [\'ml24f-0F'], 0],
+['5f', '-m -l 24 -f', [\'0Ft', \'0Fnt'], [\'ml24f-0F'], 0],
+['5g', '-m -l 24 -f', [\'tn', \'0Ft'], [\'ml24f-t-0F'], 0],
+# A full page printed (lines_left_on_page = 0) without a FF found.
+# Avoid an extra empty page if a FF follows in the next input line.
+['5ma', '-m -l 24', [\'tFFn', \'tFnFt'], [\'ml24-FF'], 0],
+['5mb', '-m -l 24', [\'tFFn', \'FFn'], [\'ml24-FF'], 0],
+['5mc', '-m -l 24', [\'tn', \'FFn'], [\'ml24-t-FF'], 0],
+['5md', '-m -l 20', [\'FFn', \'tn'], [\'ml20-FF-t'], 0],
+['5Pma', '+3 -m -l 24', [\'FFn', \'FnFn'], [\'3ml24-FF'], 0],
+['5Pmb', '+3 -m -l 24', [\'tFFn', \'FFn'], [\'3ml24-FF'], 0],
+['5Pmc', '+3 -m -l 24', [\'tn', \'FFn'], [\'3ml24-t-FF'], 0],
+#
+# Do not print header and footer but retain "FF set by Hand"
+# (-t option)
+['6a', '-t -l 24', [\'tn'], [\'t-t'], 0],
+['6b', '-t -l 24 -f', [\'tn'], [\'t-t'], 0],
+['6c', '-t -l 24 -f', [\'tFFt-bl'], [\'t-bl'], 0],
+['6d', '-t -l 24', [\'0FnFnt'], [\'t-0FF'], 0],
+['6e', '-t -l 24', [\'FFn'], [\'t-FF'], 0],
+['6f', '-t -l 24', [\'FnFn'], [\'t-FF'], 0],
+['6g', '-t -l 24 -f', [\'FFn'], [\'t-FF'], 0],
+['6aa', '-t -a -3', [\'0FnFnt'], [\'ta3-0FF'], 0],
+['6ab', '-t -a -3', [\'FFn'], [\'ta3-FF'], 0],
+['6ac', '-t -a -3 -l 24', [\'FnFn'], [\'ta3-FF'], 0],
+['6ba', '-t -b -3', [\'0FnFnt'], [\'tb3-0FF'], 0],
+['6bb', '-t -b -3', [\'FFn'], [\'tb3-FF'], 0],
+['6bc', '-t -b -3 -l 24', [\'FnFn'], [\'tb3-FF'], 0],
+#
+# Do not print header and footer nor "FF set by Hand" (-T option)
+['7a', '-T -l 24', [\'tn'], [\'tt-t'], 0],
+['7b', '-T -l 24 -f', [\'tn'], [\'tt-t'], 0],
+['7c', '-T -l 24 -f', [\'tFFt-bl'], [\'tt-bl'], 0],
+['7d', '-T -l 24', [\'0FnFnt'], [\'tt-0FF'], 0],
+['7e', '-T -l 24', [\'FFn'], [\'tt-FF'], 0],
+['7f', '-T -l 24', [\'FnFn'], [\'tt-FF'], 0],
+['7g', '-T -l 24 -f', [\'FFn'], [\'tt-FF'], 0],
+['7aa', '-T -a -3', [\'0FnFnt'], [\'tta3-0FF'], 0],
+['7ab', '-T -a -3', [\'FFn'], [\'tta3-FF'], 0],
+['7ac', '-T -a -3 -l 24', [\'FnFn'], [\'tta3-FF'], 0],
+['7ba', '-T -b -3', [\'0FnFnt'], [\'ttb3-0FF'], 0],
+['7bb', '-T -b -3', [\'FFn'], [\'ttb3-FF'], 0],
+['7bc', '-T -b -3 -l 24', [\'FnFn'], [\'ttb3-FF'], 0],
+#
+# lhs-truncation of header
+# pr-1.19m: Text line truncation only with column output
+#
+# numbering lines (-n -N option)
+# skip pages (+FIRST_PAGE[:LAST_PAGE] option)
+['9a', '-n.3 -l 24 -f', [\'tFFt-bl'], [\'nl24f-bl'], 0],
+['9b', '-n.3 -N 15 -l 24 -f', [\'tFFt-bl'], [\'nN15l24f-bl'], 0],
+['9Pa', '-n.3 +2 -l 24 -f', [\'tFFt-bl'], [\'n+2l24f-bl'], 0],
+['9Pb', '-n.3 +3 -l 24 -f', [\'tFFt-bl'], [\'n+3l24f-bl'], 0],
+['9Pc', '-n.3 -N 1 +3 -l 24 -f', [\'tFFt-bl'], [\'nN1+3l24f-bl'], 0],
+['9Pe', '-n.3 +2 -l 24 -f', [\'0FFt'], [\'n+2l24f-0FF'], 0],
+['9Pf', '-n.3 +2 -l 24 -f', [\'0FFnt'], [\'n+2l24f-0FF'], 0],
+['9Pg', '-n.3 +2 -l 24 -f', [\'0FnFt'], [\'n+2l24f-0FF'], 0],
+['9Ph', '-n.3 +2 -l 24 -f', [\'0FnFnt'], [\'n+2l24f-0FF'], 0],
+['9Pi', '-n.3 +2:5 -l 24 -f', [\'0FFt'], [\'n+2-5l24f-0FF'], 0],
+['9Pj', '-n.3 +3 -l 24 -f', [\'0FFt'], [\'n+3l24f-0FF'], 0],
+['9Pk', '-n.3 +3 -l 24 -f', [\'0FFnt'], [\'n+3l24f-0FF'], 0],
+['9Pl', '-n.3 +3 -l 24 -f', [\'0FnFt'], [\'n+3l24f-0FF'], 0],
+['9Pm', '-n.3 +3 -l 24 -f', [\'0FnFnt'], [\'n+3l24f-0FF'], 0],
+['9Pn', '-n.3 +7 -l 24', [\'FFn'], [\'n+7l24-FF'], 0],
+['9Po', '-n.3 +7 -l 24', [\'FFtn'], [\'n+7l24-FF'], 0],
+['9Pp', '-n.3 +7 -l 24', [\'FnFn'], [\'n+7l24-FF'], 0],
+['9Pq', '-n.3 +3:7 -l 24', [\'FnFn'], [\'n+3-7l24-FF'], 0],
+['9Pr', '-n.3 +8 -l 20', [\'tFFn'], [\'n+8l20-FF'], 0],
+['9Ps', '-n.3 +8 -l 20', [\'tFnFt'], [\'n+8l20-FF'], 0],
+['9Pt', '-n.3 +8 -l 20', [\'tFFt'], [\'n+8l20-FF'], 0],
+['9Paa', '-n.3 +5 -a -3 -l 13 -f', [\'0FFt'], [\'n+5a3l13f-0FF'], 0],
+['9Pab', '-n.3 +5 -a -3 -l 13 -f', [\'0FFnt'], [\'n+5a3l13f-0FF'], 0],
+['9Pac', '-n.3 +5 -a -3 -l 13 -f', [\'0FnFt'], [\'n+5a3l13f-0FF'], 0],
+['9Pad', '-n.3 +5 -a -3 -l 13 -f', [\'0FnFnt'], [\'n+5a3l13f-0FF'], 0],
+['9Pae', '-n.3 +6 -a -2 -l 17', [\'FFn'], [\'n+6a2l17-FF'], 0],
+['9Paf', '-n.3 +6 -a -2 -l 17', [\'FFtn'], [\'n+6a2l17-FF'], 0],
+['9Pag', '-n.3 +6 -a -2 -l 17', [\'FnFn'], [\'n+6a2l17-FF'], 0],
+['9Pah', '-n.3 +6 -a -2 -l 17', [\'tFFn'], [\'n+6a2l17-FF'], 0],
+['9Pai', '-n.3 +6 -a -2 -l 17', [\'tFnFt'], [\'n+6a2l17-FF'], 0],
+['9Paj', '-n.3 +6 -a -2 -l 17', [\'tFFt'], [\'n+6a2l17-FF'], 0],
+['9Pak', '-n.3 +4:8 -a -2 -l 17', [\'tFFt'], [\'n+4-8a2l17-FF'], 0],
+['9Pba', '-n.3 +4 -b -2 -l 17 -f', [\'0FFt'], [\'n+4b2l17f-0FF'], 0],
+['9Pbb', '-n.3 +4 -b -2 -l 17 -f', [\'0FFnt'], [\'n+4b2l17f-0FF'], 0],
+['9Pbc', '-n.3 +4 -b -2 -l 17 -f', [\'0FnFt'], [\'n+4b2l17f-0FF'], 0],
+['9Pbd', '-n.3 +4 -b -2 -l 17 -f', [\'0FnFnt'], [\'n+4b2l17f-0FF'], 0],
+['9Pbe', '-n.3 +6 -b -3 -l 13 -f', [\'FFn'], [\'n+6b3l13f-FF'], 0],
+['9Pbf', '-n.3 +6 -b -3 -l 13 -f', [\'FFtn'], [\'n+6b3l13f-FF'], 0],
+['9Pbg', '-n.3 +6 -b -3 -l 13 -f', [\'FnFn'], [\'n+6b3l13f-FF'], 0],
+['9Pbh', '-n.3 +6 -b -3 -l 13 -f', [\'tFFn'], [\'n+6b3l13f-FF'], 0],
+['9Pbi', '-n.3 +6 -b -3 -l 13 -f', [\'tFnFt'], [\'n+6b3l13f-FF'], 0],
+['9Pbj', '-n.3 +6 -b -3 -l 13 -f', [\'tFFt'], [\'n+6b3l13f-FF'], 0],
+['9Pbk', '-n.3 +5:8 -b -3 -l 17 -f', [\'FnFn'], [\'n+5-8b3l17f-FF'], 0],
+['9Pma', '-n.3 +3 -m -l 20 -f', [\'tFFt-bl', \'FnFn'], [\'n+3ml20f-bl-FF'], 0],
+['9Pmb', '-n.3 +3 -m -l 24 -f', [\'tFFt-bl', \'tn'], [\'n+3ml24f-bl-tn'], 0],
+['9Pmc', '-n.3 +3 -m -l 24 -f', [\'tn', \'tFFt-bl'], [\'n+3ml24f-tn-bl'], 0],
+#
+# line truncation column alignment; header line truncation
+# -w/W PAGE_WIDTH [-J] options
+['10wa', '-W 72 -J -l24 -f', [\'tFFt-ll'], [\'W72Jl24f-ll'], 0],
+['10wb', '-w 72 -J -l24 -f', [\'tFFt-ll'], [\'W72Jl24f-ll'], 0],
+['10wc', '-W 72 -l24 -f', [\'tFFt-ll'], [\'W-72l24f-ll'], 0],
+['10wd', '-w 72 -l24 -f', [\'tFFt-ll'], [\'w72l24f-ll'], 0],
+['10we', '-W 28 -l24 -f', [\'tFFt-ll'], [\'W28l24f-ll'], 0],
+['10wf', '-W 27 -l24 -f', [\'tFFt-ll'], [\'W27l24f-ll'], 0],
+['10wg', '-W 26 -l24 -f', [\'tFFt-ll'], [\'W26l24f-ll'], 0],
+['10wh', '-W 20 -l24 -f', [\'tFFt-ll'], [\'W20l24f-ll'], 0],
+['10ma', '-m -l 24 -f', [\'tFFt-lm', \'loli'], [\'ml24f-lm-lo'], 0],
+['10mb', '-W 35 -m -l 24 -f', [\'tFFt-lm', \'loli'], [\'W35ml24f-lm-lo'], 0],
+['10mc', '-w 35 -m -l 24 -f', [\'tFFt-lm', \'loli'], [\'W35ml24f-lm-lo'], 0],
+['10md', '-J -m -l 24 -f', [\'tFFt-lm', \'loli'], [\'Jml24f-lm-lo'], 0],
+['10me', '-W 35 -J -m -l 24 -f', [\'tFFt-lm', \'loli'], [\'W35Jml24f-lmlo'], 0],
+['10mf', '-w 35 -J -m -l 24 -f', [\'tFFt-lm', \'loli'], [\'W35Jml24f-lmlo'], 0],
+['10mg', '-n.3 -J -m -l 24 -f', [\'tFFt-lm', \'tFFt-lm', \'loli'],
+ [\'nJml24f-lmlmlo'], 0],
+['10mh', '-n.3 -J -m -l 24 -f', [\'tFFt-lm', \'loli', \'tFFt-lm'],
+ [\'nJml24f-lmlolm'], 0],
+['10aa', '-a -3 -l 24 -f', [\'tFFt-lm'], [\'a3l24f-lm'], 0],
+['10ab', '-W 35 -a -3 -l 24 -f', [\'tFFt-lm'], [\'W35a3l24f-lm'], 0],
+['10ac', '-J -a -3 -l 24 -f', [\'tFFt-lm'], [\'Ja3l24f-lm'], 0],
+['10ad', '-W 35 -J -a -3 -l 24 -f', [\'tFFt-lm'], [\'W35Ja3l24f-lm'], 0],
+['10ba', '-b -3 -l 24 -f', [\'tFFt-lm'], [\'b3l24f-lm'], 0],
+['10bb', '-W 35 -b -3 -l 24 -f', [\'tFFt-lm'], [\'W35b3l24f-lm'], 0],
+['10bc', '-J -b -3 -l 24 -f', [\'tFFt-lm'], [\'Jb3l24f-lm'], 0],
+['10bd', '-W 35 -J -b -3 -l 24 -f', [\'tFFt-lm'], [\'W35Jb3l24f-lm'], 0],
+#
+# merge files (-m option) use separator string (-S option)
+['11sa', '-n.3 -S:--: -m -l 20 -f', [\'tFFt-bl', \'FnFn'],
+ [\'nSml20-bl-FF'], 0],
+['11sb', '-n.3 -S:--: -m -l 24 -f', [\'tFFt-bl', \'FnFn'],
+ [\'nSml24-bl-FF'], 0],
+['11se', '-n.3 -S:--: -m -l 20 -f', [\'tn', \'tn', \'FnFn'],
+ [\'nSml20-t-t-FF'], 0],
+['11sf', '-n.3 -S:--: -m -l 24 -f', [\'tn', \'tn', \'FnFn'],
+ [\'nSml24-t-t-FF'], 0],
+['11sg', '-n.3 -S:--: -m -l 20 -f', [\'tn', \'tn', \'FnFn', \'FnFn'],
+ [\'nSml20-t-tFFFF'], 0],
+['11sh', '-n.3 -S:--: -m -l 24 -f', [\'tn', \'tn', \'FnFn', \'FnFn'],
+ [\'nSml24-t-tFFFF'], 0],
+#
+# left margin (-o option) and separator string (-S option)
+['12aa', '-o3 -a -3 -l24 -f', [\'tn'], [\'o3a3l24f-tn'], 0],
+['12ab', '-o3 -a -3 -S:--: -l24 -f', [\'tn'], [\'o3a3Sl24f-tn'], 0],
+['12ac', '-o3 -a -3 -S:--: -n. -l24 -f', [\'tn'], [\'o3a3Snl24f-tn'], 0],
+['12ba', '-o3 -b -3 -l24 -f', [\'tn'], [\'o3b3l24f-tn'], 0],
+['12bb', '-o3 -b -3 -S:--: -l24 -f', [\'tn'], [\'o3b3Sl24f-tn'], 0],
+['12bc', '-o3 -b -3 -S:--: -n. -l24 -f', [\'tn'], [\'o3b3Snl24f-tn'], 0],
+['12ma', '-o3 -m -l24 -f', [\'tFFt-bl', \'tn'], [\'o3ml24f-bl-tn'], 0],
+['12mb', '-o3 -m -S:--: -l24 -f', [\'tFFt-bl', \'tn'], [\'o3mSl24f-bl-tn'], 0],
+['12mc', '-o3 -m -S:--: -n. -l24 -f', [\'tFFt-bl', \'tn'],
+ [\'o3mSnl24fbltn'], 0],
+['12md', '-o3 -J -m -l24 -f', [\'tFFt-lm', \'loli'], [\'o3Jml24f-lm-lo'], 0],
+#
+#
+# Single column output: POSIX compliant, adapt other UNIXes (SunOS.5.5.1 e.g.)
+# number-separator TAB always an output TAB --> varying number/text-spacing
+['13a', '-t -n -e8', [\'t_tab'], [\'tne8-t_tab'], 0],
+['13b', '-t -n -e8 -o3', [\'t_tab'], [\'tne8o3-t_tab'], 0],
+#
+# POSIX compliant: multi-columns of equal width (unlike SunOS.5.5.1 e.g.)
+# text-tab handling
+['13ba', '-t -n -2 -e8', [\'t_tab'], [\'tn2e8-t_tab'], 0],
+['13bb', '-t -n: -2 -e8', [\'t_tab'], [\'tn_2e8-t_tab'], 0],
+['13bc', '-t -n: -2 -e8 -S----', [\'t_tab'], [\'tn_2e8S-t_tab'], 0],
+['13bd', '-t -n -2 -e8 -o3', [\'t_tab'], [\'tn2e8o3-t_tab'], 0],
+# number-separator TAB not treated as input text-tab, no '-e' expansion
+['13be', '-t -n -2 -e5 -o3', [\'t_tab'], [\'tn2e5o3-t_tab'], 0],
+# input-tab-char ':' not equal default (text) TABs
+['13bf', '-t -n -2 -e:8', [\'t_tab_'], [\'tn2e8-t_tab'], 0],
+#
+# options -w/-s: POSIX-compliant, means adapting the interference of -w/-s
+# with multi-column output from other UNIXes (SunOS e.g.);
+# columns, truncated = 72 / separator = space :
+['14a', '-2 -f', [\'t_notab'], [\'2f-t_notab'], 0],
+# full lines, no truncation / separator = TAB :
+['14b', '-2 -s -f', [\'t_notab'], [\'2sf-t_notab'], 0],
+# full lines, no truncation / separator = ':' :
+['14c', '-2 -s: -f', [\'t_notab'], [\'2s_f-t_notab'], 0],
+# columns, truncated = 60 / separator = space :
+['14d', '-2 -w60 -f', [\'t_notab'], [\'2w60f-t_notab'], 0],
+# columns, truncated = 60 / no separator (SunOS-BUG: line width to small):
+['14e', '-2 -s -w60 -f', [\'t_notab'], [\'2sw60f-t_notab'], 0],
+# columns, truncated = 60 / separator = ':' (HP-UX.10.20-2-BUG:
+# ':' missing with -m option):
+['14f', '-2 -s: -w60 -f', [\'t_notab'], [\'2s_w60f-t_nota'], 0],
+#
+# new long-options -W/-S/-J disentangle those options (see also No.'10*')
+# columns, truncated = 72 / no separator :
+['14g', '-2 -S -f', [\'t_notab'], [\'2-Sf-t_notab'], 0],
+# full lines, no truncation / separator = TAB : (Input: -S"<TAB>")
+['14h', '-2 -S" " -J -f', [\'t_notab'], [\'2sf-t_notab'], 0],
+# columns, truncated = 72 / separator ':' :
+['14i', '-2 -S: -f', [\'t_notab'], [\'2-S_f-t_notab'], 0],
+# full lines, no truncation / separator = ':' :
+['14j', '-2 -S: -J -f', [\'t_notab'], [\'2s_f-t_notab'], 0],
+# columns, truncated = 60 / separator = space:
+['14k', '-2 -W60 -f', [\'t_notab'], [\'2w60f-t_notab'], 0],
+# columns, truncated = 60 / no separator :
+['14l', '-2 -S -W60 -f', [\'t_notab'], [\'2sw60f-t_notab'], 0],
+# columns, truncated = 60 / separator = ':' :
+['14m', '-2 -S: -W60 -f', [\'t_notab'], [\'2s_w60f-t_nota'], 0],
+#
+# Tabify multiple spaces, -i option
+# number of input spaces between a and b must not change; be careful
+# comparing with other UNIXes (some other SunOS examples are OK !?)
+# SunOS.5.5.1-BUG: 8 input spaces --> 11 output spaces between a and b;
+['i-opt-a', '-tn -i5 -h ""', "a b\n", " 1 a b\n", 0],
+# SunOS.5.5.1-BUG: 8 input spaces --> 9 output spaces between a and b;
+['i-opt-b', '-tn -i5 -o9 -h ""', "a b\n",
+ " 1 a b\n", 0],
+#
+# line number overflow not allowed: cut off leading digits;
+# don't adapt other UNIXes, no real standard to follow, a consequent
+# programming of column handling may change the GNU pr concept.
+['ncut-a', '-tn2 -N98', "y\ny\ny\ny\ny\n",
+ "98 y\n99 y\n00 y\n01 y\n02 y\n", 0],
+['ncut-b', '-tn:2 -N98', "y\ny\ny\ny\ny\n",
+ "98:y\n99:y\n00:y\n01:y\n02:y\n", 0],
+
+['margin-0', '-o 0', '', '', 0],
+
+# BUG fixed: that leading space on 3rd line of output should not be there
+['dbl-sp-a', '-d -l 14 -h ""', "1\n2\n",
+ "\n\n-- Date/Time -- "
+ . "Page 1\n\n\n1\n\n2\n\n\n\n\n\n\n", 0],
+# This test failed with 1.22e and earlier.
+['dbl-sp-b', '-d -t', "1\n2\n", "1\n\n2\n\n", 0],
+
+# This test would segfault with 2.0f and earlier.
+['narrow-1', '-W1 -t', "12345\n", "1\n", 0],
+
+# This test would fail with textutils-2.1 and earlier.
+['col-last', '-W3 -t2', "a\nb\nc\n", "a c\nb\n", 0],
+
+# Make sure that -02 is treated just like -2.
+['col-02', '-W3 -t -02', "a\nb\nc\n", "a c\nb\n", 0],
+# The -2 must override preceding column-count-specifying options.
+['col-2', '-W3 -t -4 --columns=1 -2', "a\nb\nc\n", "a c\nb\n", 0],
+# The --columns=2 must override preceding column-count-specifying options.
+['col-long', '-W3 -t -1 --columns=2', "a\nb\nc\n", "a c\nb\n", 0],
+# Make sure these fail.
+['col-0', '-0', '', '', 1,
+ "$prog: invalid number of columns: '0'\n", $normalize_strerror],
+['col-inval', '-'.'9'x100, '', '', 1,
+ "$prog: invalid number of columns: '". ('9'x100) ."'\n", $normalize_strerror],
+
+# Before coreutils-5.3.1, --pages=1:-1 would be treated like
+# --pages=1:18446744073709551615.
+['neg-page', '--pages=1:-1', '', '', 1,
+ "$prog: invalid --pages argument '1:-1'\n"],
+
+# Up to coreutils-6.10, this would cause pr to decrement its
+# internal "input_position" below zero and sometimes segfault.
+['neg-inp-pos1', '-t -e', "\b\b\b\b\b\b\tx\n", " x\n", 0],
+# NB: while there are 4 backspaces in the input, there are only 3 in the output
+['neg-inp-pos2', '-t -e', "abc\b\b\b\b\tx", "abc\b\b\b x\n", 0],
+
+# This would clobber so much of the heap, it'd segfault or abort every time.
+['smash-heap', '-t -e300', "a".("\b"x50)."\t", "a\b".(" "x300)."\n", 0],
+['smash-heap8', '-t -e', "a".("\b"x50)."\t", "a\b".(" "x 8)."\n", 0],
+
+# Before coreutils-8.13 page numbers were not handled correctly when
+# headers were not printed (when -l <= 10 or -t or -T specified)
+['page-range', '+1:1 -2 -l1 -s" "', "a\nb\nc\n", "a b\n", 0],
+
+# This padded with zeros before coreutils-8.21
+['padding1', '-t -n,15', "1\n", (" "x 14)."1,1\n", 0],
+# This crashed with divide by zero before coreutils-8.21
+['padding2', '-t -n,64', "1\n", (" "x 63)."1,1\n", 0],
+# Ensure we handle buffer truncation correctly
+['padding3', '-t -N1000000 -n,1', "1\n", "0,1\n", 0],
+
+# This entered an infinite loop before coreutils-9.4
+['page-length1', '-dl1', "", "", 0],
+);
+
+# Convert the above old-style test vectors to the newer
+# format used by Coreutils.pm.
+
+my $pfx = "$ENV{abs_srcdir}/tests/pr";
+
+# Normalize otherwise-variable output page headers.
+my $common_option_prefix = '--date-format="-- Date/Time --" -h x';
+
+my @Tests;
+foreach my $t (@tv)
+ {
+ my ($test_name, $flags, $in, $exp, $ret, $err_msg, $err_sub) = @$t;
+ my $new_ent = [$test_name, $common_option_prefix, $flags];
+ if (!ref $in)
+ {
+ push @$new_ent, {IN=>$in};
+ }
+ else
+ {
+ foreach my $e (@$in)
+ {
+ my $file_name = $$e;
+ push @$new_ent, {IN=>{"$pfx/$file_name"=>undef}};
+ }
+ }
+ if (!ref $exp)
+ {
+ push @$new_ent, {OUT=>$exp};
+ }
+ else
+ {
+ foreach my $e (@$exp)
+ {
+ my $file_name = $$e;
+ push @$new_ent, {OUT=>{"$pfx/$file_name"=>undef}};
+ }
+ }
+ $ret
+ and push @$new_ent, {EXIT=>$ret}, {ERR=>$err_msg}, {ERR_SUBST=>$err_sub};
+ push @Tests, $new_ent;
+ }
+
+# Exercise a bug with pr -m -s (commit 553d347)
+push @Tests,
+ ['merge-w-tabs', '-m -s -t',
+ {IN=>{1=>"a\tb\tc\n"}},
+ {IN=>{2=>"m\tn\to\n"}},
+ {IN=>{3=>"x\ty\tz\n"}},
+ {OUT=>join("\t", qw(a b c m n o x y z)) . "\n"} ];
+# -s and -s$'\t' use different code paths
+push @Tests,
+ ['merge-w-tabs-sepstr', "-m -s'\t' -t",
+ {IN=>{1=>"a\tb\tc\n"}},
+ {IN=>{2=>"m\tn\to\n"}},
+ {IN=>{3=>"x\ty\tz\n"}},
+ {OUT=>join("\t", qw(a b c m n o x y z)) . "\n"} ];
+
+# Exercise a variant of the bug with pr -m -s (commit 553d347)
+# test 2 files, too (merging 3 files automatically aligns columns on TAB stops)
+push @Tests,
+ ['merge-2-w-tabs', '-m -s -t',
+ {IN=>{1=>"a\tb\tc\n"}},
+ {IN=>{2=>"m\tn\to\n"}},
+ {OUT=>join("\t", qw(a b c m n o)) . "\n"} ];
+# -s and -s$'\t' use different code paths
+push @Tests,
+ ['merge-2-w-tabs-sepstr', "-m -s'\t' -t",
+ {IN=>{1=>"a\tb\tc\n"}},
+ {IN=>{2=>"m\tn\to\n"}},
+ {OUT=>join("\t", qw(a b c m n o)) . "\n"} ];
+
+# This resulted in reading invalid memory before coreutils-8.26
+push @Tests,
+ ['asan1', "-m -S'\t\t\t' -t",
+ {IN=>{1=>"a\n"}},
+ {IN=>{2=>"a\n"}},
+ {OUT=>"a\t\t\t\t \t\t\ta\n"} ];
+
+# Exercise a bug with pr -t -2 (bug #46422)
+push @Tests,
+ ['mcol-w-tabs', '-t -2',
+ {IN=>"x\tx\tx\tx\tx\nx\tx\tx\tx\tx\n"},
+ {OUT=>"x\tx\tx\tx\tx x\t x\t x\t x\t x\n"} ];
+
+# generalize case from commit 553d347 (problem results from -s, not -m)
+push @Tests,
+ ['mcol-w-tabs-w-tabsep', '-t -2 -s',
+ {IN=>"x\tx\tx\tx\tx\nx\tx\tx\tx\tx\n"},
+ {OUT=>"x\tx\tx\tx\tx\tx\tx\tx\tx\tx\n"} ];
+# -s and -s$'\t' use different code paths
+push @Tests,
+ ['mcol-w-tabs-w-tabsep-sepstr', "-t -2 -s'\t'",
+ {IN=>"x\tx\tx\tx\tx\nx\tx\tx\tx\tx\n"},
+ {OUT=>"x\tx\tx\tx\tx\tx\tx\tx\tx\tx\n"} ];
+
+@Tests = triple_test \@Tests;
+
+my $save_temps = $ENV{DEBUG};
+my $verbose = $ENV{VERBOSE};
+
+my $fail = run_tests ($prog, $prog, \@Tests, $save_temps, $verbose);
+exit $fail;
diff --git a/tests/pr/t-0FF b/tests/pr/t-0FF
new file mode 100644
index 0000000..7ce1144
--- /dev/null
+++ b/tests/pr/t-0FF
@@ -0,0 +1,33 @@
+ 1 FF-Test: FF's at Start of File V
+2 Options -b -3 / -a -3 / ...
+3 --------------------------------------------
+4 3456789 123456789 123456789 123456789 12345678
+5 3 Columns downwards ..., <= 5 lines per page
+6 FF-Arangements: Empty Pages at start
+7 \ftext; \f\ntext;
+8 \f\ftext; \f\f\ntext; \f\n\ftext; \f\n\f\n;
+9 3456789 123456789 123456789
+10 zzzzzzzzzzzzzzzzzzzzzzzzzz123456789
+1 12345678
+2 12345678
+3 line truncation before FF; r_r_o_l-test:
+14 456789 123456789 123456789 123456789
+ 15 xyzxyzxyz XYZXYZXYZ abcabcab
+16 456789 123456789 xyzxyzxyz XYZXYZXYZ
+7 12345678
+8 12345678
+9 3456789 ab
+20 DEFGHI 123
+1 12345678
+2 12345678
+3 12345678
+4 12345678
+5 12345678
+6 12345678
+27 no truncation before FF; (r_l-test):
+28 no trunc
+ 29 xyzxyzxyz XYZXYZXYZ abcabcab
+30 456789 123456789 xyzxyzxyz XYZXYZXYZ
+1 12345678
+2 3456789 abcdefghi
+3 12345678
diff --git a/tests/pr/t-FF b/tests/pr/t-FF
new file mode 100644
index 0000000..dfd229b
--- /dev/null
+++ b/tests/pr/t-FF
@@ -0,0 +1,60 @@
+1 FF-Test: FF's in Text V
+2 Options -b -3 / -a -3 / ...
+3 --------------------------------------------
+4 3456789 123456789 123456789 123456789 12345678
+5 3 Columns downwards ..., <= 5 lines per page
+6 FF-Arangements: One Empty Page
+7 text\f\f\n; text\f\n\ftext; \f\ftext;
+8 \f\f\n; \f\n\f\n;
+9
+10 zzzzzzzzzzzzzzzzzzzzzzzzzz123456789
+1 12345678
+2 12345678
+3 line truncation before FF; r_r_o_l-test:
+14 456789 123456789 123456789 123456789
+ 15 xyzxyzxyz XYZXYZXYZ abcabcab
+16 456789 123456789 xyzxyzxyz XYZXYZXYZ
+7 12345678
+8 12345678
+9 3456789 ab
+20 DEFGHI 123
+1 12345678
+2 12345678
+3 12345678
+4 12345678
+5 12345678
+6 12345678
+27 no truncation before FF; (r_l-test):
+28 no trunc
+ 29 xyzxyzxyz XYZXYZXYZ abcabcab
+30 456789 123456789 xyzxyzxyz XYZXYZXYZ
+1 12345678
+2 3456789 abcdefghi
+3 12345678
+4 12345678
+5 12345678
+6 12345678
+7 12345678
+8 12345678
+9 3456789 abcdefghi
+40 DEFGHI 123456789
+41 yzxyzxyz XYZXYZXYZ abcabcab
+42 456789 123456789 abcdefghi ABCDEDFHI
+ 43 xyzxyzxyz XYZXYZXYZ abcabcab
+44 456789 123456789 xyzxyzxyz XYZXYZXYZ
+5 12345678
+6 12345678
+7 12345678
+8 12345678
+9 12345678
+50 12345678
+1 12345678
+2 12345678
+3 12345678
+4 12345678
+55 yzxyzxyz XYZXYZXYZ abcabcab
+56 456789 123456789 abcdefghi ABCDEDFHI
+ 57 xyzxyzxyz XYZXYZXYZ abcabcab
+58 456789 123456789 xyzxyzxyz XYZXYZXYZ
+9 12345678
+60 DEFGHI 123456789
diff --git a/tests/pr/t-bl b/tests/pr/t-bl
new file mode 100644
index 0000000..a7da0a6
--- /dev/null
+++ b/tests/pr/t-bl
@@ -0,0 +1,77 @@
+1 FF-Test: FF's in Text V
+2 Options -n;
+3 numbering lines with skiped pages;
+4 numbering blanc lines (no. 5,12,13,23,28)
+
+6 3456789 123456789 123456789 123456789 12345678
+7 3 Columns downwards ..., <= 5 lines per page
+8
+9
+10 zzzzzzzzzzzzzzzzzzzzzzzzzz123456789
+1 12345678
+
+
+14 456789 123456789 123456789 123456789
+ 15 xyzxyzxyz XYZXYZXYZ abcabcab
+16 456789 123456789 xyzxyzxyz XYZXYZXYZ
+7 12345678
+8 12345678
+9 3456789 ab
+20 DEFGHI 123
+1 12345678
+
+
+4 12345678
+5 12345678
+6 12345678
+27 no truncation before FF; (r_l-test):
+
+ 29 xyzxyzxyz XYZXYZXYZ abcabcab
+30 456789 123456789 xyzxyzxyz XYZXYZXYZ
+1 12345678
+2 3456789 abcdefghi
+3 12345678
+4 12345678
+
+6 12345678
+7 12345678
+8 12345678
+9 3456789 abcdefghi
+40 DEFGHI 123456789
+41 yzxyzxyz XYZXYZXYZ abcabcab
+42 456789 123456789 abcdefghi ABCDEDFHI
+ 43 xyzxyzxyz XYZXYZXYZ abcabcab
+44 456789 123456789 xyzxyzxyz XYZXYZXYZ
+5 12345678
+6 12345678
+7 12345678
+8 12345678
+9 12345678
+50 12345678
+1 12345678
+
+
+
+55 yzxyzxyz XYZXYZXYZ abcabcab
+56 456789 123456789 abcdefghi ABCDEDFHI
+
+58 456789 123456789 xyzxyzxyz XYZXYZXYZ
+9 12345678
+60 DEFGHI 123456789
+61 yzxyzxyz XYZXYZXYZ abcabcab
+62 456789 123456789 abcdefghi ABCDEDFHI
+63 xyzxyzxyz XYZXYZXYZ abcabcab
+64 456789 123456789 xyzxyzxyz XYZXYZXYZ
+5 12345678
+6 12345678
+7 12345678
+8 12345678
+9 12345678
+70 456789 123456789 abcdefghi ABCDEDFHI
+1 12345678
+
+
+
+74 yzxyzxyz XYZXYZXYZ abcabcab
+75 456789 123456789 abcdefghi ABCDEDFHI
+ \ No newline at end of file
diff --git a/tests/pr/t-t b/tests/pr/t-t
new file mode 100644
index 0000000..8bd50ba
--- /dev/null
+++ b/tests/pr/t-t
@@ -0,0 +1,63 @@
+1 Test-INPUT: "Without FF set by Hand" V
+2 Options -b -3 [+2|+3] [-l 15|8] [-f]
+3 Options -a -3 [+2|+3] [-l 15|8] [-f]
+4 Options [+2|+3] [-l 24|17] [-f]
+5
+6 --------------------------------------------
+7 3456789 123456789 123456789 123456789 12345678
+8 3 Columns downwards, across, ...:
+9 With columns use <= 5 text lines/page,
+10 without -f e.g.: -l 15 = total lines/page,
+1 with -f e.g. : -l 8 -f
+2
+3 line truncation before new page; r_r_o_l-test:
+14 456789 123456789 123456789 123456789
+15 xyzxyzxyz XYZXYZXYZ abcabcab
+16 456789 123456789 xyzxyzxyz XYZXYZXYZ
+7 12345678
+8 12345678
+9 3456789 ab
+20 DEFGHI 123
+1 12345678
+2 12345678
+3 12345678
+4 12345678
+5 12345678
+6 12345678
+27 no truncation before nwe page; (r_l-test):
+28 no trunc
+29 xyzxyzxyz XYZXYZXYZ abcabcab
+30 456789 123456789 xyzxyzxyz XYZXYZXYZ
+1 12345678
+2 3456789 abcdefghi
+3 12345678
+4 12345678
+5 12345678
+6 12345678
+7 12345678
+8 12345678
+9 3456789 abcdefghi
+40 DEFGHI 123456789
+41 yzxyzxyz XYZXYZXYZ abcabcab
+42 456789 123456789 abcdefghi ABCDEDFHI
+43 xyzxyzxyz XYZXYZXYZ abcabcab
+44 456789 123456789 xyzxyzxyz XYZXYZXYZ
+5 12345678
+6 12345678
+7 12345678
+8 12345678
+9 12345678
+50 12345678
+1 12345678
+2 12345678
+3 12345678
+4 12345678
+55 yzxyzxyz XYZXYZXYZ abcabcab
+56 456789 123456789 abcdefghi ABCDEDFHI
+57 xyzxyzxyz XYZXYZXYZ abcabcab
+58 456789 123456789 xyzxyzxyz XYZXYZXYZ
+9 12345678
+60 DEFGHI 123456789
+1
+2
+3 ------- EOF -------- EOF -------- EOF -------
diff --git a/tests/pr/tFFn b/tests/pr/tFFn
new file mode 100644
index 0000000..779e260
--- /dev/null
+++ b/tests/pr/tFFn
@@ -0,0 +1,60 @@
+1 FF-Test: FF's in Text V
+2 Options -b -3 / -a -3 / ...
+3 --------------------------------------------
+4 3456789 123456789 123456789 123456789 12345678
+5 3 Columns downwards ..., <= 5 lines per page
+6 FF-Arangements: One Empty Page
+7 text\f\f\n; text\f\n\ftext; \f\ftext;
+8 \f\f\n; \f\n\f\n;
+9
+10 zzzzzzzzzzzzzzzzzzzzzzzzzz123456789
+1 12345678
+2 12345678
+3 line truncation before FF; r_r_o_l-test:
+14 456789 123456789 123456789 123456789
+15 xyzxyzxyz XYZXYZXYZ abcabcab
+16 456789 123456789 xyzxyzxyz XYZXYZXYZ
+7 12345678
+8 12345678
+9 3456789 ab
+20 DEFGHI 123
+1 12345678
+2 12345678
+3 12345678
+4 12345678
+5 12345678
+6 12345678
+27 no truncation before FF; (r_l-test):
+28 no trunc
+29 xyzxyzxyz XYZXYZXYZ abcabcab
+30 456789 123456789 xyzxyzxyz XYZXYZXYZ
+1 12345678
+2 3456789 abcdefghi
+3 12345678
+4 12345678
+5 12345678
+6 12345678
+7 12345678
+8 12345678
+9 3456789 abcdefghi
+40 DEFGHI 123456789
+41 yzxyzxyz XYZXYZXYZ abcabcab
+42 456789 123456789 abcdefghi ABCDEDFHI
+43 xyzxyzxyz XYZXYZXYZ abcabcab
+44 456789 123456789 xyzxyzxyz XYZXYZXYZ
+5 12345678
+6 12345678
+7 12345678
+8 12345678
+9 12345678
+50 12345678
+1 12345678
+2 12345678
+3 12345678
+4 12345678
+55 yzxyzxyz XYZXYZXYZ abcabcab
+56 456789 123456789 abcdefghi ABCDEDFHI
+57 xyzxyzxyz XYZXYZXYZ abcabcab
+58 456789 123456789 xyzxyzxyz XYZXYZXYZ
+9 12345678
+60 DEFGHI 123456789
diff --git a/tests/pr/tFFt b/tests/pr/tFFt
new file mode 100644
index 0000000..6a8682c
--- /dev/null
+++ b/tests/pr/tFFt
@@ -0,0 +1,56 @@
+1 FF-Test: FF's in Text V
+2 Options -b -3 / -a -3 / ...
+3 --------------------------------------------
+4 3456789 123456789 123456789 123456789 12345678
+5 3 Columns downwards ..., <= 5 lines per page
+6 FF-Arangements: One Empty Page
+7 text\f\f\n; text\f\n\ftext; \f\ftext;
+8 \f\f\n; \f\n\f\n;
+9
+10 zzzzzzzzzzzzzzzzzzzzzzzzzz123456789
+1 12345678
+2 12345678
+3 line truncation before FF; r_r_o_l-test:
+14 456789 123456789 123456789 123456789 15 xyzxyzxyz XYZXYZXYZ abcabcab
+16 456789 123456789 xyzxyzxyz XYZXYZXYZ
+7 12345678
+8 12345678
+9 3456789 ab
+20 DEFGHI 123
+1 12345678
+2 12345678
+3 12345678
+4 12345678
+5 12345678
+6 12345678
+27 no truncation before FF; (r_l-test):
+28 no trunc 29 xyzxyzxyz XYZXYZXYZ abcabcab
+30 456789 123456789 xyzxyzxyz XYZXYZXYZ
+1 12345678
+2 3456789 abcdefghi
+3 12345678
+4 12345678
+5 12345678
+6 12345678
+7 12345678
+8 12345678
+9 3456789 abcdefghi
+40 DEFGHI 123456789
+41 yzxyzxyz XYZXYZXYZ abcabcab
+42 456789 123456789 abcdefghi ABCDEDFHI 43 xyzxyzxyz XYZXYZXYZ abcabcab
+44 456789 123456789 xyzxyzxyz XYZXYZXYZ
+5 12345678
+6 12345678
+7 12345678
+8 12345678
+9 12345678
+50 12345678
+1 12345678
+2 12345678
+3 12345678
+4 12345678
+55 yzxyzxyz XYZXYZXYZ abcabcab
+56 456789 123456789 abcdefghi ABCDEDFHI 57 xyzxyzxyz XYZXYZXYZ abcabcab
+58 456789 123456789 xyzxyzxyz XYZXYZXYZ
+9 12345678
+60 DEFGHI 123456789
diff --git a/tests/pr/tFFt-bl b/tests/pr/tFFt-bl
new file mode 100644
index 0000000..25bcf67
--- /dev/null
+++ b/tests/pr/tFFt-bl
@@ -0,0 +1,74 @@
+1 FF-Test: FF's in Text V
+2 Options -n;
+3 numbering lines with skiped pages;
+4 numbering blanc lines (no. 5,12,13,23,28)
+
+6 3456789 123456789 123456789 123456789 12345678
+7 3 Columns downwards ..., <= 5 lines per page
+8
+9
+10 zzzzzzzzzzzzzzzzzzzzzzzzzz123456789
+1 12345678
+
+
+14 456789 123456789 123456789 123456789 15 xyzxyzxyz XYZXYZXYZ abcabcab
+16 456789 123456789 xyzxyzxyz XYZXYZXYZ
+7 12345678
+8 12345678
+9 3456789 ab
+20 DEFGHI 123
+1 12345678
+
+
+4 12345678
+5 12345678
+6 12345678
+27 no truncation before FF; (r_l-test):
+
+
+29 xyzxyzxyz XYZXYZXYZ abcabcab
+30 456789 123456789 xyzxyzxyz XYZXYZXYZ
+1 12345678
+2 3456789 abcdefghi
+3 12345678
+4 12345678
+
+6 12345678
+7 12345678
+8 12345678
+9 3456789 abcdefghi
+40 DEFGHI 123456789
+41 yzxyzxyz XYZXYZXYZ abcabcab
+42 456789 123456789 abcdefghi ABCDEDFHI 43 xyzxyzxyz XYZXYZXYZ abcabcab
+44 456789 123456789 xyzxyzxyz XYZXYZXYZ
+5 12345678
+6 12345678
+7 12345678
+8 12345678
+9 12345678
+50 12345678
+1 12345678
+
+
+
+55 yzxyzxyz XYZXYZXYZ abcabcab
+56 456789 123456789 abcdefghi ABCDEDFHI
+58 456789 123456789 xyzxyzxyz XYZXYZXYZ
+9 12345678
+60 DEFGHI 123456789
+61 yzxyzxyz XYZXYZXYZ abcabcab
+62 456789 123456789 abcdefghi ABCDEDFHI
+63 xyzxyzxyz XYZXYZXYZ abcabcab
+64 456789 123456789 xyzxyzxyz XYZXYZXYZ
+5 12345678
+6 12345678
+7 12345678
+8 12345678
+9 12345678
+70 456789 123456789 abcdefghi ABCDEDFHI
+1 12345678
+
+
+
+74 yzxyzxyz XYZXYZXYZ abcabcab
+75 456789 123456789 abcdefghi ABCDEDFHI
diff --git a/tests/pr/tFFt-ll b/tests/pr/tFFt-ll
new file mode 100644
index 0000000..39eca65
--- /dev/null
+++ b/tests/pr/tFFt-ll
@@ -0,0 +1,56 @@
+1<<< -Test: FF's in Text >>>
+2<<< -b -3 / -a -3 / ... >>>
+3<<< >>>
+4<<< 123456789 123456789 123456789 123456789 123456789 123456789 123456789 >>>
+
+6<<< -Arangements: One Empty Page >>>
+7<<< \f\f\n; text\f\n\ftext; \f\ftext; >>>
+8<<< f\f\n; \f\n\f\n; >>>
+9<<< >>>
+10<<< >>>
+1<<< >>>
+2<<< >>>
+3<<< truncation before FF; r_r_o_l-test: >>>
+14<<< 123456789 123456789 123456789 >>> 15<<< xyzxyzxyz XYZXYZXYZ abcabcab >>>
+16<<< 123456789 xyzxyzxyz XYZXYZXYZ >>>
+7<<< >>>
+8<<< >>>
+9<<< >>>
+20<<< >>>
+1<<< >>>
+
+
+4<<< >>>
+5<<< >>>
+6<<< >>>
+27<<< truncation before FF; (r_l-test): >>>
+28<<< trunc 29<<<xyzxyzxyz XYZXYZXYZ abcabcab >>>
+30<<< 123456789 xyzxyzxyz XYZXYZXYZ >>>
+1<<< >>>
+2<<< abcdefghi >>>
+3<<< >>>
+4<<< >>>
+5<<< >>>
+6<<< >>>
+7<<< >>>
+8<<< >>>
+9<<< abcdefghi >>>
+40<<< 123456789 >>>
+41<<< XYZXYZXYZ abcabcab >>>
+42<<< 123456789 abcdefghi ABCDEDFHI >>> 43<<< xyzxyzxyz XYZXYZXYZ abcabcab >>>
+44<<< 123456789 xyzxyzxyz XYZXYZXYZ >>>
+5<<< >>>
+6<<< >>>
+7<<< >>>
+8<<< >>>
+9<<< >>>
+50<<< >>>
+1<<< >>>
+2<<< >>>
+3<<< >>>
+4<<< >>>
+55<<< XYZXYZXYZ abcabcab >>>
+56<<< 123456789 abcdefghi ABCDEDFHI >>> 57<<< xyzxyzxyz XYZXYZXYZ abcabcab >>>
+58<<< 123456789 xyzxyzxyz XYZXYZXYZ >>>
+9<<< >>>
+60<<< 123456789 >>>
diff --git a/tests/pr/tFFt-lm b/tests/pr/tFFt-lm
new file mode 100644
index 0000000..3fb566d
--- /dev/null
+++ b/tests/pr/tFFt-lm
@@ -0,0 +1,56 @@
+1<<< -Test: FF's in Text >>>
+2<<< -b -3 / -a -3 / ... >>>
+3<<< >>>
+4<<< 123456789 123456789 123456789 12345678 >>>
+
+6<<< -Arangements: One Empty Page >>>
+7<<< \f\f\n; text\f\n\ftext; \f\ftext; >>>
+8<<< f\f\n; \f\n\f\n; >>>
+9<<< >>>
+10<<< >>>
+1<<< >>>
+2<<< >>>
+3<<< truncation before FF; r_r_o_l-test: >>>
+14<<< 123456789 123456789 123456789 >>> 15<<< xyzxyzxyz XYZXYZXYZ abcabcab >>>
+16<<< 123456789 xyzxyzxyz XYZXYZXYZ >>>
+7<<< >>>
+8<<< >>>
+9<<< >>>
+20<<< >>>
+1<<< >>>
+
+
+4<<< >>>
+5<<< >>>
+6<<< >>>
+27<<< truncation before FF; (r_l-test): >>>
+28<<< trunc 29<<<xyzxyzxyz XYZXYZXYZ abcabcab >>>
+30<<< 123456789 xyzxyzxyz XYZXYZXYZ >>>
+1<<< >>>
+2<<< abcdefghi >>>
+3<<< >>>
+4<<< >>>
+5<<< >>>
+6<<< >>>
+7<<< >>>
+8<<< >>>
+9<<< abcdefghi >>>
+40<<< 123456789 >>>
+41<<< XYZXYZXYZ abcabcab >>>
+42<<< 123456789 abcdefghi ABCDEDFHI >>> 43<<< xyzxyzxyz XYZXYZXYZ abcabcab >>>
+44<<< 123456789 xyzxyzxyz XYZXYZXYZ >>>
+5<<< >>>
+6<<< >>>
+7<<< >>>
+8<<< >>>
+9<<< >>>
+50<<< >>>
+1<<< >>>
+2<<< >>>
+3<<< >>>
+4<<< >>>
+55<<< XYZXYZXYZ abcabcab >>>
+56<<< 123456789 abcdefghi ABCDEDFHI >>> 57<<< xyzxyzxyz XYZXYZXYZ abcabcab >>>
+58<<< 123456789 xyzxyzxyz XYZXYZXYZ >>>
+9<<< >>>
+60<<< 123456789 >>>
diff --git a/tests/pr/tFnFt b/tests/pr/tFnFt
new file mode 100644
index 0000000..46965cd
--- /dev/null
+++ b/tests/pr/tFnFt
@@ -0,0 +1,63 @@
+1 FF-Test: FF's in Text V
+2 Options -b -3 / -a -3 / ...
+3 --------------------------------------------
+4 3456789 123456789 123456789 123456789 12345678
+5 3 Columns downwards ..., <= 5 lines per page
+6 FF-Arangements: One Empty Page
+7 text\f\f\n; text\f\n\ftext; \f\ftext;
+8 \f\f\n; \f\n\f\n;
+9
+10 zzzzzzzzzzzzzzzzzzzzzzzzzz123456789
+1 12345678
+2 12345678
+3 line truncation before FF; r_r_o_l-test:
+14 456789 123456789 123456789 123456789
+
+15 xyzxyzxyz XYZXYZXYZ abcabcab
+16 456789 123456789 xyzxyzxyz XYZXYZXYZ
+7 12345678
+8 12345678
+9 3456789 ab
+20 DEFGHI 123
+1 12345678
+2 12345678
+3 12345678
+4 12345678
+5 12345678
+6 12345678
+27 no truncation before FF; (r_l-test):
+28 no trunc
+
+29 xyzxyzxyz XYZXYZXYZ abcabcab
+30 456789 123456789 xyzxyzxyz XYZXYZXYZ
+1 12345678
+2 3456789 abcdefghi
+3 12345678
+4 12345678
+5 12345678
+6 12345678
+7 12345678
+8 12345678
+9 3456789 abcdefghi
+40 DEFGHI 123456789
+41 yzxyzxyz XYZXYZXYZ abcabcab
+42 456789 123456789 abcdefghi ABCDEDFHI
+
+43 xyzxyzxyz XYZXYZXYZ abcabcab
+44 456789 123456789 xyzxyzxyz XYZXYZXYZ
+5 12345678
+6 12345678
+7 12345678
+8 12345678
+9 12345678
+50 12345678
+1 12345678
+2 12345678
+3 12345678
+4 12345678
+55 yzxyzxyz XYZXYZXYZ abcabcab
+56 456789 123456789 abcdefghi ABCDEDFHI
+57 xyzxyzxyz XYZXYZXYZ abcabcab
+58 456789 123456789 xyzxyzxyz XYZXYZXYZ
+9 12345678
+60 DEFGHI 123456789
diff --git a/tests/pr/t_notab b/tests/pr/t_notab
new file mode 100644
index 0000000..e5d39f2
--- /dev/null
+++ b/tests/pr/t_notab
@@ -0,0 +1,5 @@
+aaaa.bcde-fghijklmn-opqrstuvw-xyzzzzzzz-aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+bbbb.bcde-fghijklmn-opqrstuvw-xyzzzzzzz-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb
+cccc.bcde-fghijklmn-opqrstuvw-xyzzzzzzz-cccccccccccccccccccccccccccccccccccccccc
+dddd.bcde-fghijklmn-opqrstuvw-xyzzzzzzz-dddddddddddddddddddddddddddddddddddddddd
+eeee.bcde-fghijklmn-opqrstuvw-xyzzzzzzz-eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee
diff --git a/tests/pr/t_tab b/tests/pr/t_tab
new file mode 100644
index 0000000..5ff2d46
--- /dev/null
+++ b/tests/pr/t_tab
@@ -0,0 +1,4 @@
+aaa abcde fghijklmnopqrstuvw
+bbb abcde fghijklmnopqrstuvw
+ccc abcde fghijklmnopqrstuvw
+ddd abcde fghijklmnopqrstuvw
diff --git a/tests/pr/t_tab_ b/tests/pr/t_tab_
new file mode 100644
index 0000000..8463899
--- /dev/null
+++ b/tests/pr/t_tab_
@@ -0,0 +1,4 @@
+aaa:abcde fghijklmnopqrstuvw
+bbb:abcde fghijklmnopqrstuvw
+ccc abcde fghijklmnopqrstuvw
+ddd abcde fghijklmnopqrstuvw
diff --git a/tests/pr/ta3-0FF b/tests/pr/ta3-0FF
new file mode 100644
index 0000000..ead4067
--- /dev/null
+++ b/tests/pr/ta3-0FF
@@ -0,0 +1,12 @@
+ 1 FF-Test: FF's at St 2 Options -b -3 / -a 3 -------------------
+4 3456789 123456789 123 5 3 Columns downwards 6 FF-Arangements: Emp
+7 \ftext; \f\ntext; 8 \f\ftext; \f\f\ntex 9 3456789 123456789 123
+10 zzzzzzzzzzzzzzzzzzz 1 2
+3 line truncation befor 14 456789 123456789 123
+ 15 xyzxyzxyz XYZXYZXYZ 16 456789 123456789 xyz 7
+8 9 3456789 ab 20 DEFGHI 123
+1 2 3
+4 5 6
+27 no truncation before 28 no trunc
+ 29 xyzxyzxyz XYZXYZXYZ 30 456789 123456789 xyz 1
+2 3456789 abcdefghi 3
diff --git a/tests/pr/ta3-FF b/tests/pr/ta3-FF
new file mode 100644
index 0000000..d4485c7
--- /dev/null
+++ b/tests/pr/ta3-FF
@@ -0,0 +1,22 @@
+1 FF-Test: FF's in Te 2 Options -b -3 / -a 3 -------------------
+4 3456789 123456789 123 5 3 Columns downwards 6 FF-Arangements: One
+7 text\f\f\n; text\f\ 8 \f\f\n; \f\n\f\n; 9
+10 zzzzzzzzzzzzzzzzzzz 1 2
+3 line truncation befor 14 456789 123456789 123
+ 15 xyzxyzxyz XYZXYZXYZ 16 456789 123456789 xyz 7
+8 9 3456789 ab 20 DEFGHI 123
+1 2 3
+4 5 6
+27 no truncation before 28 no trunc
+ 29 xyzxyzxyz XYZXYZXYZ 30 456789 123456789 xyz 1
+2 3456789 abcdefghi 3 4
+5 6 7
+8 9 3456789 abcdefghi 40 DEFGHI 123456789
+41 yzxyzxyz XYZXYZXYZ a 42 456789 123456789 abc
+ 43 xyzxyzxyz XYZXYZXYZ 44 456789 123456789 xyz 5
+6 7 8
+9 50 1
+2 3 4
+55 yzxyzxyz XYZXYZXYZ a 56 456789 123456789 abc
+ 57 xyzxyzxyz XYZXYZXYZ 58 456789 123456789 xyz 9
+60 DEFGHI 123456789
diff --git a/tests/pr/tb3-0FF b/tests/pr/tb3-0FF
new file mode 100644
index 0000000..c9f0a6e
--- /dev/null
+++ b/tests/pr/tb3-0FF
@@ -0,0 +1,12 @@
+ 1 FF-Test: FF's at St 6 FF-Arangements: Emp 1
+2 Options -b -3 / -a 7 \ftext; \f\ntext; 2
+3 ------------------- 8 \f\ftext; \f\f\ntex 3 line truncation befor
+4 3456789 123456789 123 9 3456789 123456789 123 14 456789 123456789 123
+5 3 Columns downwards 10 zzzzzzzzzzzzzzzzzzz
+ 15 xyzxyzxyz XYZXYZXYZ 20 DEFGHI 123 5
+16 456789 123456789 xyz 1 6
+7 2 27 no truncation before
+8 3 28 no trunc
+9 3456789 ab 4
+ 29 xyzxyzxyz XYZXYZXYZ 1 3
+30 456789 123456789 xyz 2 3456789 abcdefghi
diff --git a/tests/pr/tb3-FF b/tests/pr/tb3-FF
new file mode 100644
index 0000000..a439f22
--- /dev/null
+++ b/tests/pr/tb3-FF
@@ -0,0 +1,22 @@
+1 FF-Test: FF's in Te 6 FF-Arangements: One 1
+2 Options -b -3 / -a 7 text\f\f\n; text\f\ 2
+3 ------------------- 8 \f\f\n; \f\n\f\n; 3 line truncation befor
+4 3456789 123456789 123 9 14 456789 123456789 123
+5 3 Columns downwards 10 zzzzzzzzzzzzzzzzzzz
+ 15 xyzxyzxyz XYZXYZXYZ 20 DEFGHI 123 5
+16 456789 123456789 xyz 1 6
+7 2 27 no truncation before
+8 3 28 no trunc
+9 3456789 ab 4
+ 29 xyzxyzxyz XYZXYZXYZ 4 9 3456789 abcdefghi
+30 456789 123456789 xyz 5 40 DEFGHI 123456789
+1 6 41 yzxyzxyz XYZXYZXYZ a
+2 3456789 abcdefghi 7 42 456789 123456789 abc
+3 8
+ 43 xyzxyzxyz XYZXYZXYZ 8 3
+44 456789 123456789 xyz 9 4
+5 50 55 yzxyzxyz XYZXYZXYZ a
+6 1 56 456789 123456789 abc
+7 2
+ 57 xyzxyzxyz XYZXYZXYZ 9 60 DEFGHI 123456789
+58 456789 123456789 xyz
diff --git a/tests/pr/tn b/tests/pr/tn
new file mode 100644
index 0000000..8bd50ba
--- /dev/null
+++ b/tests/pr/tn
@@ -0,0 +1,63 @@
+1 Test-INPUT: "Without FF set by Hand" V
+2 Options -b -3 [+2|+3] [-l 15|8] [-f]
+3 Options -a -3 [+2|+3] [-l 15|8] [-f]
+4 Options [+2|+3] [-l 24|17] [-f]
+5
+6 --------------------------------------------
+7 3456789 123456789 123456789 123456789 12345678
+8 3 Columns downwards, across, ...:
+9 With columns use <= 5 text lines/page,
+10 without -f e.g.: -l 15 = total lines/page,
+1 with -f e.g. : -l 8 -f
+2
+3 line truncation before new page; r_r_o_l-test:
+14 456789 123456789 123456789 123456789
+15 xyzxyzxyz XYZXYZXYZ abcabcab
+16 456789 123456789 xyzxyzxyz XYZXYZXYZ
+7 12345678
+8 12345678
+9 3456789 ab
+20 DEFGHI 123
+1 12345678
+2 12345678
+3 12345678
+4 12345678
+5 12345678
+6 12345678
+27 no truncation before nwe page; (r_l-test):
+28 no trunc
+29 xyzxyzxyz XYZXYZXYZ abcabcab
+30 456789 123456789 xyzxyzxyz XYZXYZXYZ
+1 12345678
+2 3456789 abcdefghi
+3 12345678
+4 12345678
+5 12345678
+6 12345678
+7 12345678
+8 12345678
+9 3456789 abcdefghi
+40 DEFGHI 123456789
+41 yzxyzxyz XYZXYZXYZ abcabcab
+42 456789 123456789 abcdefghi ABCDEDFHI
+43 xyzxyzxyz XYZXYZXYZ abcabcab
+44 456789 123456789 xyzxyzxyz XYZXYZXYZ
+5 12345678
+6 12345678
+7 12345678
+8 12345678
+9 12345678
+50 12345678
+1 12345678
+2 12345678
+3 12345678
+4 12345678
+55 yzxyzxyz XYZXYZXYZ abcabcab
+56 456789 123456789 abcdefghi ABCDEDFHI
+57 xyzxyzxyz XYZXYZXYZ abcabcab
+58 456789 123456789 xyzxyzxyz XYZXYZXYZ
+9 12345678
+60 DEFGHI 123456789
+1
+2
+3 ------- EOF -------- EOF -------- EOF -------
diff --git a/tests/pr/tn2e5o3-t_tab b/tests/pr/tn2e5o3-t_tab
new file mode 100644
index 0000000..5d9207e
--- /dev/null
+++ b/tests/pr/tn2e5o3-t_tab
@@ -0,0 +1,2 @@
+ 1 aaa abcde fghij 3 ccc abcde fghij
+ 2 bbb abcde fghij 4 ddd abcde fghij
diff --git a/tests/pr/tn2e8-t_tab b/tests/pr/tn2e8-t_tab
new file mode 100644
index 0000000..c8ddb6d
--- /dev/null
+++ b/tests/pr/tn2e8-t_tab
@@ -0,0 +1,2 @@
+ 1 aaa abcde fgh 3 ccc abcde fgh
+ 2 bbb abcde fgh 4 ddd abcde fgh
diff --git a/tests/pr/tn2e8o3-t_tab b/tests/pr/tn2e8o3-t_tab
new file mode 100644
index 0000000..e901d5f
--- /dev/null
+++ b/tests/pr/tn2e8o3-t_tab
@@ -0,0 +1,2 @@
+ 1 aaa abcde fgh 3 ccc abcde fgh
+ 2 bbb abcde fgh 4 ddd abcde fgh
diff --git a/tests/pr/tn_2e8-t_tab b/tests/pr/tn_2e8-t_tab
new file mode 100644
index 0000000..c0b85a0
--- /dev/null
+++ b/tests/pr/tn_2e8-t_tab
@@ -0,0 +1,2 @@
+ 1:aaa abcde fgh 3:ccc abcde fgh
+ 2:bbb abcde fgh 4:ddd abcde fgh
diff --git a/tests/pr/tn_2e8S-t_tab b/tests/pr/tn_2e8S-t_tab
new file mode 100644
index 0000000..debb335
--- /dev/null
+++ b/tests/pr/tn_2e8S-t_tab
@@ -0,0 +1,2 @@
+ 1:aaa abcde fg---- 3:ccc abcde fg
+ 2:bbb abcde fg---- 4:ddd abcde fg
diff --git a/tests/pr/tne8-t_tab b/tests/pr/tne8-t_tab
new file mode 100644
index 0000000..a38d0c5
--- /dev/null
+++ b/tests/pr/tne8-t_tab
@@ -0,0 +1,4 @@
+ 1 aaa abcde fghijklmnopqrstuvw
+ 2 bbb abcde fghijklmnopqrstuvw
+ 3 ccc abcde fghijklmnopqrstuvw
+ 4 ddd abcde fghijklmnopqrstuvw
diff --git a/tests/pr/tne8o3-t_tab b/tests/pr/tne8o3-t_tab
new file mode 100644
index 0000000..69aff8f
--- /dev/null
+++ b/tests/pr/tne8o3-t_tab
@@ -0,0 +1,4 @@
+ 1 aaa abcde fghijklmnopqrstuvw
+ 2 bbb abcde fghijklmnopqrstuvw
+ 3 ccc abcde fghijklmnopqrstuvw
+ 4 ddd abcde fghijklmnopqrstuvw
diff --git a/tests/pr/tt-0FF b/tests/pr/tt-0FF
new file mode 100644
index 0000000..67802ac
--- /dev/null
+++ b/tests/pr/tt-0FF
@@ -0,0 +1,33 @@
+1 FF-Test: FF's at Start of File V
+2 Options -b -3 / -a -3 / ...
+3 --------------------------------------------
+4 3456789 123456789 123456789 123456789 12345678
+5 3 Columns downwards ..., <= 5 lines per page
+6 FF-Arangements: Empty Pages at start
+7 \ftext; \f\ntext;
+8 \f\ftext; \f\f\ntext; \f\n\ftext; \f\n\f\n;
+9 3456789 123456789 123456789
+10 zzzzzzzzzzzzzzzzzzzzzzzzzz123456789
+1 12345678
+2 12345678
+3 line truncation before FF; r_r_o_l-test:
+14 456789 123456789 123456789 123456789
+15 xyzxyzxyz XYZXYZXYZ abcabcab
+16 456789 123456789 xyzxyzxyz XYZXYZXYZ
+7 12345678
+8 12345678
+9 3456789 ab
+20 DEFGHI 123
+1 12345678
+2 12345678
+3 12345678
+4 12345678
+5 12345678
+6 12345678
+27 no truncation before FF; (r_l-test):
+28 no trunc
+29 xyzxyzxyz XYZXYZXYZ abcabcab
+30 456789 123456789 xyzxyzxyz XYZXYZXYZ
+1 12345678
+2 3456789 abcdefghi
+3 12345678
diff --git a/tests/pr/tt-FF b/tests/pr/tt-FF
new file mode 100644
index 0000000..b60ab95
--- /dev/null
+++ b/tests/pr/tt-FF
@@ -0,0 +1,60 @@
+1 FF-Test: FF's in Text V
+2 Options -b -3 / -a -3 / ...
+3 --------------------------------------------
+4 3456789 123456789 123456789 123456789 12345678
+5 3 Columns downwards ..., <= 5 lines per page
+6 FF-Arangements: One Empty Page
+7 text\f\f\n; text\f\n\ftext; \f\ftext;
+8 \f\f\n; \f\n\f\n;
+9
+10 zzzzzzzzzzzzzzzzzzzzzzzzzz123456789
+1 12345678
+2 12345678
+3 line truncation before FF; r_r_o_l-test:
+14 456789 123456789 123456789 123456789
+15 xyzxyzxyz XYZXYZXYZ abcabcab
+16 456789 123456789 xyzxyzxyz XYZXYZXYZ
+7 12345678
+8 12345678
+9 3456789 ab
+20 DEFGHI 123
+1 12345678
+2 12345678
+3 12345678
+4 12345678
+5 12345678
+6 12345678
+27 no truncation before FF; (r_l-test):
+28 no trunc
+29 xyzxyzxyz XYZXYZXYZ abcabcab
+30 456789 123456789 xyzxyzxyz XYZXYZXYZ
+1 12345678
+2 3456789 abcdefghi
+3 12345678
+4 12345678
+5 12345678
+6 12345678
+7 12345678
+8 12345678
+9 3456789 abcdefghi
+40 DEFGHI 123456789
+41 yzxyzxyz XYZXYZXYZ abcabcab
+42 456789 123456789 abcdefghi ABCDEDFHI
+43 xyzxyzxyz XYZXYZXYZ abcabcab
+44 456789 123456789 xyzxyzxyz XYZXYZXYZ
+5 12345678
+6 12345678
+7 12345678
+8 12345678
+9 12345678
+50 12345678
+1 12345678
+2 12345678
+3 12345678
+4 12345678
+55 yzxyzxyz XYZXYZXYZ abcabcab
+56 456789 123456789 abcdefghi ABCDEDFHI
+57 xyzxyzxyz XYZXYZXYZ abcabcab
+58 456789 123456789 xyzxyzxyz XYZXYZXYZ
+9 12345678
+60 DEFGHI 123456789
diff --git a/tests/pr/tt-bl b/tests/pr/tt-bl
new file mode 100644
index 0000000..0195727
--- /dev/null
+++ b/tests/pr/tt-bl
@@ -0,0 +1,76 @@
+1 FF-Test: FF's in Text V
+2 Options -n;
+3 numbering lines with skiped pages;
+4 numbering blanc lines (no. 5,12,13,23,28)
+
+6 3456789 123456789 123456789 123456789 12345678
+7 3 Columns downwards ..., <= 5 lines per page
+8
+9
+10 zzzzzzzzzzzzzzzzzzzzzzzzzz123456789
+1 12345678
+
+
+14 456789 123456789 123456789 123456789
+15 xyzxyzxyz XYZXYZXYZ abcabcab
+16 456789 123456789 xyzxyzxyz XYZXYZXYZ
+7 12345678
+8 12345678
+9 3456789 ab
+20 DEFGHI 123
+1 12345678
+
+
+4 12345678
+5 12345678
+6 12345678
+27 no truncation before FF; (r_l-test):
+
+29 xyzxyzxyz XYZXYZXYZ abcabcab
+30 456789 123456789 xyzxyzxyz XYZXYZXYZ
+1 12345678
+2 3456789 abcdefghi
+3 12345678
+4 12345678
+
+6 12345678
+7 12345678
+8 12345678
+9 3456789 abcdefghi
+40 DEFGHI 123456789
+41 yzxyzxyz XYZXYZXYZ abcabcab
+42 456789 123456789 abcdefghi ABCDEDFHI
+43 xyzxyzxyz XYZXYZXYZ abcabcab
+44 456789 123456789 xyzxyzxyz XYZXYZXYZ
+5 12345678
+6 12345678
+7 12345678
+8 12345678
+9 12345678
+50 12345678
+1 12345678
+
+
+
+55 yzxyzxyz XYZXYZXYZ abcabcab
+56 456789 123456789 abcdefghi ABCDEDFHI
+
+58 456789 123456789 xyzxyzxyz XYZXYZXYZ
+9 12345678
+60 DEFGHI 123456789
+61 yzxyzxyz XYZXYZXYZ abcabcab
+62 456789 123456789 abcdefghi ABCDEDFHI
+63 xyzxyzxyz XYZXYZXYZ abcabcab
+64 456789 123456789 xyzxyzxyz XYZXYZXYZ
+5 12345678
+6 12345678
+7 12345678
+8 12345678
+9 12345678
+70 456789 123456789 abcdefghi ABCDEDFHI
+1 12345678
+
+
+
+74 yzxyzxyz XYZXYZXYZ abcabcab
+75 456789 123456789 abcdefghi ABCDEDFHI
diff --git a/tests/pr/tt-t b/tests/pr/tt-t
new file mode 100644
index 0000000..8bd50ba
--- /dev/null
+++ b/tests/pr/tt-t
@@ -0,0 +1,63 @@
+1 Test-INPUT: "Without FF set by Hand" V
+2 Options -b -3 [+2|+3] [-l 15|8] [-f]
+3 Options -a -3 [+2|+3] [-l 15|8] [-f]
+4 Options [+2|+3] [-l 24|17] [-f]
+5
+6 --------------------------------------------
+7 3456789 123456789 123456789 123456789 12345678
+8 3 Columns downwards, across, ...:
+9 With columns use <= 5 text lines/page,
+10 without -f e.g.: -l 15 = total lines/page,
+1 with -f e.g. : -l 8 -f
+2
+3 line truncation before new page; r_r_o_l-test:
+14 456789 123456789 123456789 123456789
+15 xyzxyzxyz XYZXYZXYZ abcabcab
+16 456789 123456789 xyzxyzxyz XYZXYZXYZ
+7 12345678
+8 12345678
+9 3456789 ab
+20 DEFGHI 123
+1 12345678
+2 12345678
+3 12345678
+4 12345678
+5 12345678
+6 12345678
+27 no truncation before nwe page; (r_l-test):
+28 no trunc
+29 xyzxyzxyz XYZXYZXYZ abcabcab
+30 456789 123456789 xyzxyzxyz XYZXYZXYZ
+1 12345678
+2 3456789 abcdefghi
+3 12345678
+4 12345678
+5 12345678
+6 12345678
+7 12345678
+8 12345678
+9 3456789 abcdefghi
+40 DEFGHI 123456789
+41 yzxyzxyz XYZXYZXYZ abcabcab
+42 456789 123456789 abcdefghi ABCDEDFHI
+43 xyzxyzxyz XYZXYZXYZ abcabcab
+44 456789 123456789 xyzxyzxyz XYZXYZXYZ
+5 12345678
+6 12345678
+7 12345678
+8 12345678
+9 12345678
+50 12345678
+1 12345678
+2 12345678
+3 12345678
+4 12345678
+55 yzxyzxyz XYZXYZXYZ abcabcab
+56 456789 123456789 abcdefghi ABCDEDFHI
+57 xyzxyzxyz XYZXYZXYZ abcabcab
+58 456789 123456789 xyzxyzxyz XYZXYZXYZ
+9 12345678
+60 DEFGHI 123456789
+1
+2
+3 ------- EOF -------- EOF -------- EOF -------
diff --git a/tests/pr/tta3-0FF b/tests/pr/tta3-0FF
new file mode 100644
index 0000000..bbddda1
--- /dev/null
+++ b/tests/pr/tta3-0FF
@@ -0,0 +1,12 @@
+1 FF-Test: FF's at St 2 Options -b -3 / -a 3 -------------------
+4 3456789 123456789 123 5 3 Columns downwards 6 FF-Arangements: Emp
+7 \ftext; \f\ntext; 8 \f\ftext; \f\f\ntex 9 3456789 123456789 123
+10 zzzzzzzzzzzzzzzzzzz 1 2
+3 line truncation befor 14 456789 123456789 123
+15 xyzxyzxyz XYZXYZXYZ 16 456789 123456789 xyz 7
+8 9 3456789 ab 20 DEFGHI 123
+1 2 3
+4 5 6
+27 no truncation before 28 no trunc
+29 xyzxyzxyz XYZXYZXYZ 30 456789 123456789 xyz 1
+2 3456789 abcdefghi 3
diff --git a/tests/pr/tta3-FF b/tests/pr/tta3-FF
new file mode 100644
index 0000000..42b6ee2
--- /dev/null
+++ b/tests/pr/tta3-FF
@@ -0,0 +1,22 @@
+1 FF-Test: FF's in Te 2 Options -b -3 / -a 3 -------------------
+4 3456789 123456789 123 5 3 Columns downwards 6 FF-Arangements: One
+7 text\f\f\n; text\f\ 8 \f\f\n; \f\n\f\n; 9
+10 zzzzzzzzzzzzzzzzzzz 1 2
+3 line truncation befor 14 456789 123456789 123
+15 xyzxyzxyz XYZXYZXYZ 16 456789 123456789 xyz 7
+8 9 3456789 ab 20 DEFGHI 123
+1 2 3
+4 5 6
+27 no truncation before 28 no trunc
+29 xyzxyzxyz XYZXYZXYZ 30 456789 123456789 xyz 1
+2 3456789 abcdefghi 3 4
+5 6 7
+8 9 3456789 abcdefghi 40 DEFGHI 123456789
+41 yzxyzxyz XYZXYZXYZ a 42 456789 123456789 abc
+43 xyzxyzxyz XYZXYZXYZ 44 456789 123456789 xyz 5
+6 7 8
+9 50 1
+2 3 4
+55 yzxyzxyz XYZXYZXYZ a 56 456789 123456789 abc
+57 xyzxyzxyz XYZXYZXYZ 58 456789 123456789 xyz 9
+60 DEFGHI 123456789
diff --git a/tests/pr/ttb3-0FF b/tests/pr/ttb3-0FF
new file mode 100644
index 0000000..cc953a5
--- /dev/null
+++ b/tests/pr/ttb3-0FF
@@ -0,0 +1,12 @@
+1 FF-Test: FF's at St 6 FF-Arangements: Emp 1
+2 Options -b -3 / -a 7 \ftext; \f\ntext; 2
+3 ------------------- 8 \f\ftext; \f\f\ntex 3 line truncation befor
+4 3456789 123456789 123 9 3456789 123456789 123 14 456789 123456789 123
+5 3 Columns downwards 10 zzzzzzzzzzzzzzzzzzz
+15 xyzxyzxyz XYZXYZXYZ 20 DEFGHI 123 5
+16 456789 123456789 xyz 1 6
+7 2 27 no truncation before
+8 3 28 no trunc
+9 3456789 ab 4
+29 xyzxyzxyz XYZXYZXYZ 1 3
+30 456789 123456789 xyz 2 3456789 abcdefghi
diff --git a/tests/pr/ttb3-FF b/tests/pr/ttb3-FF
new file mode 100644
index 0000000..eda20a4
--- /dev/null
+++ b/tests/pr/ttb3-FF
@@ -0,0 +1,22 @@
+1 FF-Test: FF's in Te 6 FF-Arangements: One 1
+2 Options -b -3 / -a 7 text\f\f\n; text\f\ 2
+3 ------------------- 8 \f\f\n; \f\n\f\n; 3 line truncation befor
+4 3456789 123456789 123 9 14 456789 123456789 123
+5 3 Columns downwards 10 zzzzzzzzzzzzzzzzzzz
+15 xyzxyzxyz XYZXYZXYZ 20 DEFGHI 123 5
+16 456789 123456789 xyz 1 6
+7 2 27 no truncation before
+8 3 28 no trunc
+9 3456789 ab 4
+29 xyzxyzxyz XYZXYZXYZ 4 9 3456789 abcdefghi
+30 456789 123456789 xyz 5 40 DEFGHI 123456789
+1 6 41 yzxyzxyz XYZXYZXYZ a
+2 3456789 abcdefghi 7 42 456789 123456789 abc
+3 8
+43 xyzxyzxyz XYZXYZXYZ 8 3
+44 456789 123456789 xyz 9 4
+5 50 55 yzxyzxyz XYZXYZXYZ a
+6 1 56 456789 123456789 abc
+7 2
+57 xyzxyzxyz XYZXYZXYZ 9 60 DEFGHI 123456789
+58 456789 123456789 xyz
diff --git a/tests/pr/w72l24f-ll b/tests/pr/w72l24f-ll
new file mode 100644
index 0000000..109cbaa
--- /dev/null
+++ b/tests/pr/w72l24f-ll
@@ -0,0 +1,110 @@
+
+
+-- Date/Time -- x Page 1
+
+
+1<<< -Test: FF's in Text >>>
+2<<< -b -3 / -a -3 / ... >>>
+3<<< >>>
+4<<< 123456789 123456789 123456789 123456789 123456789 123456789 123456789 >>>
+
+6<<< -Arangements: One Empty Page >>>
+7<<< \f\f\n; text\f\n\ftext; \f\ftext; >>>
+8<<< f\f\n; \f\n\f\n; >>>
+9<<< >>>
+10<<< >>>
+1<<< >>>
+2<<< >>>
+3<<< truncation before FF; r_r_o_l-test: >>>
+14<<< 123456789 123456789 123456789 >>>
+
+
+-- Date/Time -- x Page 2
+
+
+
+
+
+-- Date/Time -- x Page 3
+
+
+15<<< xyzxyzxyz XYZXYZXYZ abcabcab >>>
+16<<< 123456789 xyzxyzxyz XYZXYZXYZ >>>
+7<<< >>>
+8<<< >>>
+9<<< >>>
+20<<< >>>
+1<<< >>>
+
+
+4<<< >>>
+5<<< >>>
+6<<< >>>
+27<<< truncation before FF; (r_l-test): >>>
+28<<< trunc
+
+
+-- Date/Time -- x Page 4
+
+
+
+
+
+-- Date/Time -- x Page 5
+
+
+29<<<xyzxyzxyz XYZXYZXYZ abcabcab >>>
+30<<< 123456789 xyzxyzxyz XYZXYZXYZ >>>
+1<<< >>>
+2<<< abcdefghi >>>
+3<<< >>>
+4<<< >>>
+5<<< >>>
+6<<< >>>
+7<<< >>>
+8<<< >>>
+9<<< abcdefghi >>>
+40<<< 123456789 >>>
+41<<< XYZXYZXYZ abcabcab >>>
+42<<< 123456789 abcdefghi ABCDEDFHI >>>
+
+
+-- Date/Time -- x Page 6
+
+
+
+
+
+-- Date/Time -- x Page 7
+
+
+
+
+
+-- Date/Time -- x Page 8
+
+
+43<<< xyzxyzxyz XYZXYZXYZ abcabcab >>>
+44<<< 123456789 xyzxyzxyz XYZXYZXYZ >>>
+5<<< >>>
+6<<< >>>
+7<<< >>>
+8<<< >>>
+9<<< >>>
+50<<< >>>
+1<<< >>>
+2<<< >>>
+3<<< >>>
+4<<< >>>
+55<<< XYZXYZXYZ abcabcab >>>
+56<<< 123456789 abcdefghi ABCDEDFHI >>>
+
+
+-- Date/Time -- x Page 9
+
+
+57<<< xyzxyzxyz XYZXYZXYZ abcabcab >>>
+58<<< 123456789 xyzxyzxyz XYZXYZXYZ >>>
+9<<< >>>
+60<<< 123456789 >>>
+ \ No newline at end of file
diff --git a/tests/printf/printf-cov.pl b/tests/printf/printf-cov.pl
new file mode 100755
index 0000000..988c2a7
--- /dev/null
+++ b/tests/printf/printf-cov.pl
@@ -0,0 +1,106 @@
+#!/usr/bin/perl
+# improve printf.c test coverage
+
+# Copyright (C) 2008-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+use strict;
+
+my $prog = 'printf';
+my $try = "Try '$prog --help' for more information.\n";
+my $pow_2_31 = 2**31;
+
+# Turn off localization of executable's output.
+@ENV{qw(LANGUAGE LANG LC_ALL)} = ('C') x 3;
+
+my @Tests =
+(
+ ['no-args', {EXIT=>1}, {ERR=>"$prog: missing operand\n$try"}],
+ ['no-arg2', '--', {EXIT=>1}, {ERR=>"$prog: missing operand\n$try"}],
+ ['escape-1', q('\a\b\f\n\r\t\v\z\c'), {OUT=>"\a\b\f\n\r\t\x0b\\z"}],
+ ['hex-ucX', '%X 999', {OUT=>"3E7"}],
+ ['hex-ucXw', '%4X 999', {OUT=>" 3E7"}],
+ ['hex-ucXp', '%.4X 999', {OUT=>"03E7"}],
+ ['hex-ucXwp', '%5.4X 999', {OUT=>" 03E7"}],
+ ['hex-vw', '%*X 4 42', {OUT=>" 2A"}],
+ ['hex-vp', '%.*X 4 42', {OUT=>"002A"}],
+ ['hex-vwvp', '%*.*X 3 2 15', {OUT=>" 0F"}],
+ ['b', q('nl\ntab\tx'), {OUT=>"nl\ntab\tx"}],
+ ['c1', '%c 123', {OUT=>"1"}],
+ ['cw', '%\*c 3 123', {OUT=>" 1"}],
+ ['d-ucXwp', '%5.4d 999', {OUT=>" 0999"}],
+ ['d-vw', '%*d 4 42', {OUT=>" 42"}],
+ ['d-vp', '%.*d 4 42', {OUT=>"0042"}],
+ ['d-vwvp', '%*.*d 3 2 15', {OUT=>" 15"}],
+ ['d-neg-prec', '%.*d -3 15', {OUT=>"15"}],
+ ['d-big-prec', "%.*d $pow_2_31 15", # INT_MAX
+ {EXIT=>1}, {ERR=>"$prog: invalid precision: '$pow_2_31'\n"}],
+ ['d-big-fwidth', "%*d $pow_2_31 15", # INT_MAX
+ {EXIT=>1}, {ERR=>"$prog: invalid field width: '$pow_2_31'\n"}],
+ ['F', '%F 1', {OUT=>"1.000000"}],
+ ['LF', '%LF 1', {OUT=>"1.000000"}],
+ ['E', '%E 2', {OUT=>"2.000000E+00"}],
+ ['LE', '%LE 2', {OUT=>"2.000000E+00"}],
+ ['s', '%s x', {OUT=>"x"}],
+ ['sw', '%\*s 2 x', {OUT=>" x"}],
+ ['sp', '%.\*s 2 abcd', {OUT=>"ab"}],
+ ['swp', '%\*.\*s 2 2 abcd', {OUT=>"ab"}],
+ ['sw-no-args', '%\*s'],
+ ['sw-no-args2', '%.\*s'],
+ ['G-ucXwp', '%5.4G 3', {OUT=>" 3"}],
+ ['G-vw', '%*G 4 42', {OUT=>" 42"}],
+ ['G-vp', '%.*G 4 42', {OUT=>"42"}],
+ ['G-vwvp', '%*.*G 5 3 15', {OUT=>" 15"}],
+ ['esc', q('\xaa\0377'), {OUT=>"\xaa\0377"}],
+ ['esc-bad-hex', q('\x'), {EXIT=>1},
+ {ERR=>"$prog: missing hexadecimal number in escape\n"}],
+ ['u-bad-hex', q('\u00'), {EXIT=>1},
+ {ERR=>"$prog: missing hexadecimal number in escape\n"}],
+ ['U-bad-hex', q('\U0000'), {EXIT=>1},
+ {ERR=>"$prog: missing hexadecimal number in escape\n"}],
+ ['u4', q('\u0030'), {OUT=>"0"}],
+ ['U8', q('\U00000030'), {OUT=>"0"}],
+ ['u-invalid', q('\ud800'), {EXIT=>1},
+ {ERR=>"$prog: invalid universal character name \\ud800\n"}],
+ ['u-missing', q('\u'), {EXIT=>1},
+ {ERR=>"$prog: missing hexadecimal number in escape\n"}],
+ ['d-invalid', '%d no-num', {OUT=>'0'}, {EXIT=>1},
+ # Depending on the strtol implementation we expect one of these:
+ # no-num: Invalid argument (FreeBSD6)
+ # no-num: expected a numeric value (glibc, Solaris 10)
+ {ERR_SUBST => 's/Invalid argument$/expected a numeric value/'},
+ {ERR=>"$prog: 'no-num': expected a numeric value\n"}],
+ ['d-bad-suffix', '%d 9z', {OUT=>'9'}, {EXIT=>1},
+ {ERR=>"$prog: '9z': value not completely converted\n"}],
+ ['d-out-of-range', '%d '.('9'x30), {EXIT=>1},
+ {OUT=>"inaccurate"}, {OUT_SUBST => 's/\d+/inaccurate/'},
+ {ERR=>"$prog: 9...9\n"}, {ERR_SUBST => "s/'9+.*/9...9/"}],
+ ['excess', 'B 1', {OUT=>'B'},
+ {ERR=>"$prog: warning: ignoring excess arguments, starting with '1'\n"}],
+ ['percent', '%%', {OUT=>'%'}],
+ ['d-sp', q('% d' 33), {OUT=>' 33'}],
+ ['d-plus', q('%+d' 33), {OUT=>'+33'}],
+ ['d-minus', q('%-d' 33), {OUT=> '33'}],
+ ['d-zero', q('%02d' 1), {OUT=> '01'}],
+ ['d-quote', q("%'d" 3333), {OUT=> '3333'}, {OUT_SUBST => 'tr/3//c'}],
+ ['d-hash', q("%#d" 3333), {EXIT=>1},
+ {ERR=>"$prog: %#d: invalid conversion specification\n"}],
+);
+
+my $save_temps = $ENV{DEBUG};
+my $verbose = $ENV{VERBOSE};
+
+my $fail = run_tests ($prog, \$prog, \@Tests, $save_temps, $verbose);
+exit $fail;
diff --git a/tests/printf/printf-hex.sh b/tests/printf/printf-hex.sh
new file mode 100755
index 0000000..3aa9472
--- /dev/null
+++ b/tests/printf/printf-hex.sh
@@ -0,0 +1,29 @@
+#!/bin/sh
+# make sure that only two hex. digits are consumed in a \xHHH sequence
+
+# Copyright (C) 2002-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ printf
+
+env printf '\x7e3\n' > out || fail=1
+cat <<\EOF > exp
+~3
+EOF
+
+compare exp out || fail=1
+
+Exit $fail
diff --git a/tests/printf/printf-mb.sh b/tests/printf/printf-mb.sh
new file mode 100755
index 0000000..418ad35
--- /dev/null
+++ b/tests/printf/printf-mb.sh
@@ -0,0 +1,64 @@
+#!/bin/sh
+# tests for printing multi-byte values of characters
+
+# Copyright (C) 2022-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ printf
+
+prog='env printf'
+
+unset LC_ALL
+f=$LOCALE_FR_UTF8
+: ${LOCALE_FR_UTF8=none}
+if test "$LOCALE_FR_UTF8" != "none"; then
+ (
+ #valid multi-byte
+ LC_ALL=$f $prog '%04x\n' '"á' >>out 2>>err
+ #invalid multi-byte
+ LC_ALL=$f $prog '%04x\n' "'$($prog '\xe1')" >>out 2>>err
+ #uni-byte
+ LC_ALL=C $prog '%04x\n' "'$($prog '\xe1')" >>out 2>>err
+ #valid multi-byte, with trailing
+ LC_ALL=$f $prog '%04x\n' '"á=' >>out 2>>err
+ #invalid multi-byte, with trailing
+ LC_ALL=$f $prog '%04x\n' "'$($prog '\xe1')=" >>out 2>>err
+ )
+ cat <<\EOF > exp || framework_failure_
+00e1
+00e1
+00e1
+00e1
+00e1
+EOF
+ compare exp out || fail=1
+
+ # Disparate LC_CTYPE and LC_MESSAGES problematic on macos,
+ # so just look for character in warning message,
+ # and normalize to LC_MESSAGES=C
+ C_WARNING='printf: '\
+'warning: =: character(s) following character constant have been ignored'
+
+ sed "s/printf:.*=.*/$C_WARNING/" < err > c_err || framework_failure_
+
+ cat <<EOF > exp_err
+$C_WARNING
+$C_WARNING
+EOF
+ compare exp_err c_err || fail=1
+fi
+
+Exit $fail
diff --git a/tests/printf/printf-quote.sh b/tests/printf/printf-quote.sh
new file mode 100755
index 0000000..d1671bd
--- /dev/null
+++ b/tests/printf/printf-quote.sh
@@ -0,0 +1,57 @@
+#!/bin/sh
+# tests for printf %q
+
+# Copyright (C) 2015-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ printf
+
+prog='env printf'
+
+# Equivalent output to ls --quoting=shell-escape
+$prog '%q\n' '' "'" a 'a b' '~a' 'a~' "$($prog %b 'a\r')" > out
+cat <<\EOF > exp || framework_failure_
+''
+"'"
+a
+'a b'
+'~a'
+a~
+'a'$'\r'
+EOF
+compare exp out || fail=1
+
+unset LC_ALL
+f=$LOCALE_FR_UTF8
+: ${LOCALE_FR_UTF8=none}
+if test "$LOCALE_FR_UTF8" != "none"; then
+ (
+ #printable multi-byte
+ LC_ALL=$f $prog '%q\n' 'áḃç' > out
+ #non-printable multi-byte
+ LC_ALL=$f $prog '%q\n' "$($prog '\xc2\x81')" >> out
+ #printable multi-byte in C locale
+ LC_ALL=C $prog '%q\n' 'áḃç' >> out
+ )
+ cat <<\EOF > exp || framework_failure_
+áḃç
+''$'\302\201'
+''$'\303\241\341\270\203\303\247'
+EOF
+ compare exp out || fail=1
+fi
+
+Exit $fail
diff --git a/tests/printf/printf-surprise.sh b/tests/printf/printf-surprise.sh
new file mode 100755
index 0000000..fc3c064
--- /dev/null
+++ b/tests/printf/printf-surprise.sh
@@ -0,0 +1,98 @@
+#!/bin/sh
+# Detect printf(3) failure even when it doesn't set stream error indicator
+
+# Copyright (C) 2007-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+prog=printf
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ printf
+
+vm=$(get_min_ulimit_v_ env $prog %20f 0) \
+ || skip_ "this shell lacks ulimit support"
+
+# Up to coreutils-6.9, "printf %.Nf 0" would encounter an ENOMEM internal
+# error from glibc's printf(3) function whenever N was large relative to
+# the size of available memory. As of Oct 2007, that internal stream-
+# related failure was not reflected (for any libc I know of) in the usual
+# stream error indicator that is tested by ferror. The result was that
+# while the printf command obviously failed (generated no output),
+# it mistakenly exited successfully (exit status of 0).
+
+# Testing it is tricky, because there is so much variance
+# in quality for this corner of printf(3) implementations.
+# Most implementations do attempt to allocate N bytes of storage.
+# Using the maximum value for N (2^31-1) causes glibc-2.7 to try to
+# allocate almost 2^64 bytes, while freeBSD 6.1's implementation
+# correctly outputs almost 2GB worth of 0's, which takes too long.
+# We want to test implementations that allocate N bytes, but without
+# triggering the above extremes.
+
+# Some other versions of glibc-2.7 have a snprintf function that segfaults
+# when an internal (technically unnecessary!) memory allocation fails.
+
+# The compromise is to limit virtual memory to something reasonable,
+# and to make an N-byte-allocating-printf require more than that, thus
+# triggering the printf(3) misbehavior -- which, btw, is required by ISO C99.
+
+mkfifo_or_skip_ fifo
+trap_sigpipe_or_skip_
+
+# Disable MALLOC_PERTURB_, to avoid triggering this bug
+# https://bugs.debian.org/481543#77
+export MALLOC_PERTURB_=0
+
+# Terminate any background process
+cleanup_() { kill $pid 2>/dev/null && wait $pid; }
+
+head -c 10 fifo > out & pid=$!
+
+# Trigger large mem allocation failure
+( trap '' PIPE && ulimit -v $vm && env $prog %20000000f 0 2>err-msg > fifo )
+exit=$?
+
+# Map this longer, and rarer, diagnostic to the common one.
+# printf: cannot perform formatted output: Cannot allocate memory"
+sed 's/cannot perform .*/write error/' err-msg > k && mv k err-msg
+err_msg=$(tr '\n' : < err-msg)
+
+# By some bug, on Solaris 11 (5.11 snv_86), err_msg ends up
+# containing '1> fifo:printf: write error:'. Recognize that, too.
+
+case $err_msg in
+ "$prog: write error:"*) diagnostic=y ;;
+ "1> fifo:$prog: write error:") diagnostic=y ;;
+ '') diagnostic=n ;;
+ *) diagnostic=unexpected ;;
+esac
+n_out=$(wc -c < out)
+
+case $n_out:$diagnostic:$exit in
+ 10:n:0) ;; # ok, succeeds w/no diagnostic: FreeBSD 6.1
+ 10:y:1) ;; # ok, fails with EPIPE diagnostic: musl libc
+ 0:y:1) ;; # ok, glibc-2.8 and newer, when printf(3) fails with ENOMEM
+
+ # With MALLOC_PERTURB_=0, this no longer happens.
+ # *:139) # segfault; known bug at least in debian unstable's libc6 2.7-11
+ # echo 1>&2 "$0: bug in snprintf causes low-mem use of printf to segfault"
+ # fail=77;;
+
+ # 10:y) ;; # Fail: doesn't happen: nobody succeeds with a diagnostic
+ # 0:n) ;; # Fail pre-patch: no output, no diag
+ *) fail=1;;
+esac
+
+Exit $fail
diff --git a/tests/printf/printf.sh b/tests/printf/printf.sh
new file mode 100755
index 0000000..834012c
--- /dev/null
+++ b/tests/printf/printf.sh
@@ -0,0 +1,128 @@
+#!/bin/sh
+# basic tests for printf
+
+# Copyright (C) 2002-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+prog='env printf'
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ printf
+
+getlimits_
+
+
+# Verify the 3 methods of specifying "Escape":
+printf '%s\n' . . . | tr . '\033' > exp
+$prog '\x1b\n\33\n\e\n' > out || fail=1
+compare exp out || fail=1
+
+# This would fail (by printing the '--') for printf in sh-utils
+# and in coreutils 4.5.1.
+$prog -- 'foo\n' > out || fail=1
+cat <<\EOF > exp
+foo
+EOF
+
+compare exp out || fail=1
+
+rm -f out exp
+# Until coreutils-4.5.10, this would elicit a segfault.
+$prog '1 %*sy\n' -3 x > out || fail=1
+
+# Until coreutils 5.2.2, this would succeed.
+if POSIXLY_CORRECT=1 $prog '2 \x' >/dev/null 2>&1; then
+ fail=1
+else
+ echo '2 failed, as expected' >> out
+fi
+
+# Until coreutils-4.5.12, these would fail.
+$prog '3 \x40\n' >> out || fail=1
+POSIXLY_CORRECT=1 \
+$prog '4 \x40\n' >> out || fail=1
+$prog '5 % +d\n' 234 >> out || fail=1
+
+# This should print "6 !\n", but don't rely on '!' being the
+# one-byte representation of octal 041. With printf prior to
+# coreutils-5.0.1, it would print six bytes: "6 \41\n".
+$prog '6 \41\n' | tr '\41' '!' >> out
+
+# Note that as of coreutils-5.0.1, printf with a format of '\0002y'
+# prints a NUL byte followed by the digit '2' and a 'y'.
+$prog '7 \2y \02y \002y \0002y\n' |tr '\0\2' '*=' >> out
+
+$prog '8 %b %b %b %b\n' '\1y' '\01y' '\001y' '\0001y'|tr '\1' = >> out
+
+$prog '9 %*dx\n' -2 0 >>out || fail=1
+
+$prog '10 %.*dx\n' $INT_UFLOW 0 >>out || fail=1
+returns_ 1 $prog '%.*dx\n' $INT_OFLOW 0 >>out 2> /dev/null || fail=1
+
+$prog '11 %*c\n' 2 x >>out || fail=1
+
+returns_ 1 $prog '%#d\n' 0 >>out 2> /dev/null || fail=1
+
+returns_ 1 $prog '%0s\n' 0 >>out 2> /dev/null || fail=1
+
+returns_ 1 $prog '%.9c\n' 0 >>out 2> /dev/null || fail=1
+
+returns_ 1 $prog '%'\''s\n' 0 >>out 2> /dev/null || fail=1
+
+cat <<\EOF > exp
+1 x y
+2 failed, as expected
+3 @
+4 @
+5 +234
+6 !
+7 =y =y =y *2y
+8 =y =y =y =y
+9 0 x
+10 0x
+11 x
+EOF
+
+compare exp out || fail=1
+
+# Verify handling of single quote chars (\' or \")
+
+$prog '%d\n' '"a' >out 2>err # valid
+$prog '%d\n' '"a"' >>out 2>>err # invalid
+$prog '%d\n' '"' >>out 2>>err # invalid
+$prog '%d\n' 'a' >>out 2>>err # invalid
+
+cat <<EOF > exp
+97
+97
+0
+0
+EOF
+
+# POSIX says strtoimax *may* set errno to EINVAL in the latter
+# two cases. So far, that happens at least on MacOS X 10.5.
+# Map that output to the more common expected output.
+sed 's/: Invalid.*/: expected a numeric value/' err > k && mv k err
+
+cat <<EOF > exp_err
+printf: warning: ": character(s) following character constant have been ignored
+printf: '"': expected a numeric value
+printf: 'a': expected a numeric value
+EOF
+
+compare exp out || fail=1
+compare exp_err err || fail=1
+
+Exit $fail
diff --git a/tests/ptx/ptx-overrun.sh b/tests/ptx/ptx-overrun.sh
new file mode 100755
index 0000000..cfd655f
--- /dev/null
+++ b/tests/ptx/ptx-overrun.sh
@@ -0,0 +1,49 @@
+#!/bin/sh
+
+# Copyright (C) 2008-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ ptx
+
+# Trigger a heap-clobbering bug in ptx from coreutils-6.10 and earlier.
+# Using a long file name makes an abort more likely.
+# Even with no file name, valgrind detects the buffer overrun.
+f=01234567890123456789012345678901234567890123456789
+touch $f empty || framework_failure_
+
+# Specifying a regular expression ending in a lone backslash
+# would cause ptx to write beyond the end of a malloc'd buffer.
+ptx -F '\' $f < /dev/null > out || fail=1
+ptx -S 'foo\' $f < /dev/null >> out || fail=1
+ptx -W 'bar\\\' $f < /dev/null >> out || fail=1
+compare out empty || fail=1
+
+
+# Trigger an invalid heap reference noticed by gcc -fsanitize=address
+# from coreutils-8.22 and earlier. As well as an invalid memory reference,
+# the issue can be seen in the output, with nondeterministic whitespace
+# trimming when multiple files are specified.
+printf '%s\n' 'This is a ptx whitespace Trimming test' > ws.in
+ptx ws.in ws.in | sort | uniq -u > out
+compare /dev/null out || fail=1
+
+
+# Trigger an invalid heap reference noticed by gcc -fsanitize=address
+# from coreutils-8.25 and earlier.
+echo a > a
+ptx -w1 -A "$PWD/a" >/dev/null || fail=1
+
+Exit $fail
diff --git a/tests/ptx/ptx.pl b/tests/ptx/ptx.pl
new file mode 100755
index 0000000..46f88d8
--- /dev/null
+++ b/tests/ptx/ptx.pl
@@ -0,0 +1,57 @@
+#!/usr/bin/perl
+
+# Copyright (C) 2008-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+use strict;
+
+my $prog = 'ptx';
+
+# Turn off localization of executable's output.
+@ENV{qw(LANGUAGE LANG LC_ALL)} = ('C') x 3;
+
+my @Tests =
+(
+["1tok", '-w10', {IN=>"bar\n"}, {OUT=>" bar\n"}],
+["2tok", '-w10', {IN=>"foo bar\n"}, {OUT=>" / bar\n foo/\n"}],
+
+# with coreutils-6.12 and earlier, this would infloop with -wN, N < 10
+["narrow", '-w2', {IN=>"qux\n"}, {OUT=>" qux\n"}],
+["narrow-g", '-g1 -w2', {IN=>"ta\n"}, {OUT=>" ta\n"}],
+
+# with coreutils-6.12 and earlier, this would act like "ptx F1 F1"
+["2files", '-g1 -w1', {IN=>{F1=>"a"}}, {IN=>{F2=>"b"}}, {OUT=>" a\n b\n"}],
+
+# with coreutils-8.22 and earlier, the --format long option would
+# fall through into the --help case.
+["format-r", '--format=roff', {IN=>"foo\n"},
+ {OUT=>".xx \"\" \"\" \"foo\" \"\"\n"}],
+["format-t", '--format=tex', {IN=>"foo\n"},
+ {OUT=>"\\xx {}{}{foo}{}{}\n"}],
+
+# with coreutils-8.28 and earlier, the -S option would infloop with
+# matches of zero-length.
+["S-infloop", '-S \^', {IN=>"a\n"}, {EXIT=>1},
+ {ERR_SUBST=>'s/^.*reg.*ex.*length zero.*$/regexlzero/'},
+ {ERR=>"regexlzero\n"}],
+);
+
+@Tests = triple_test \@Tests;
+
+my $save_temps = $ENV{DEBUG};
+my $verbose = $ENV{VERBOSE};
+
+my $fail = run_tests ($prog, $prog, \@Tests, $save_temps, $verbose);
+exit $fail;
diff --git a/tests/pwd/pwd-long.sh b/tests/pwd/pwd-long.sh
new file mode 100755
index 0000000..480cc19
--- /dev/null
+++ b/tests/pwd/pwd-long.sh
@@ -0,0 +1,123 @@
+#!/bin/sh
+# -*- perl -*-
+# Ensure that pwd works even when run from a very deep directory.
+
+# Copyright (C) 2006-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ pwd
+
+require_readable_root_
+require_perl_
+
+ARGV_0=$0
+export ARGV_0
+
+# Don't use CuTmpdir here, since File::Temp's use of rmtree can't
+# remove the deep tree we create.
+$PERL -Tw -I"$abs_srcdir/tests" -MCuSkip -- - <<\EOF
+
+# Show that pwd works even when the length of the resulting
+# directory name is longer than PATH_MAX.
+use strict;
+
+(my $ME = $ENV{ARGV_0}) =~ s|.*/||;
+
+sub normalize_to_cwd_relative ($$$)
+{
+ my ($dir, $dev, $ino) = @_;
+ my $slash = -1;
+ my $next_slash;
+ while (1)
+ {
+ $slash = index $dir, '/', $slash + 1;
+ $slash <= -1
+ and die "$ME: $dir does not contain old CWD\n";
+ my $dir_prefix = $slash ? substr ($dir, 0, $slash) : '/';
+ my ($d, $i) = (stat $dir_prefix)[0, 1];
+ defined $d && defined $i
+ or die "$ME: $dir_prefix: stat failed: $!\n";
+ $d eq $dev && $i eq $ino
+ and return substr $dir, $slash + 1;
+ }
+}
+
+# Set up a safe, well-known environment
+$ENV{IFS} = '';
+
+# Taint checking requires a sanitized $PATH. This script performs no $PATH
+# search, so on most Unix-based systems, it is fine simply to clear $ENV{PATH}.
+# However, on Cygwin, it's used to find cygwin1.dll, so set it.
+$ENV{PATH} = '/bin:/usr/bin';
+
+# Save CWD's device and inode numbers.
+my ($dev, $ino) = (stat '.')[0, 1];
+
+# Construct the expected "."-relative part of pwd's output.
+my $z = 'z' x 31;
+my $n = 256;
+my $expected = "/$z" x $n;
+# Remove the leading "/".
+substr ($expected, 0, 1) = '';
+
+my $i = 0;
+do
+ {
+ mkdir $z, 0700
+ or CuSkip::skip "$ME: skipping this test; cannot create long "
+ . "directory name at depth $i: $!\n";
+ chdir $z
+ }
+until (++$i == $n);
+
+my $abs_top_builddir = $ENV{abs_top_builddir};
+$abs_top_builddir
+ or die "$ME: envvar abs_top_builddir not defined\n";
+my $build_src_dir = "$abs_top_builddir/src";
+$build_src_dir =~ m!^([-+.:/\w]+)$!
+ or CuSkip::skip "$ME: skipping this test; odd build source directory name:\n"
+ . "$build_src_dir\n";
+$build_src_dir = $1;
+
+my $pwd_binary = "$build_src_dir/pwd";
+
+-x $pwd_binary
+ or die "$ME: $pwd_binary is not an executable file\n";
+chomp (my $actual = qx!$pwd_binary!);
+
+# Convert the absolute name from pwd into a $CWD-relative name.
+# This is necessary in order to avoid a spurious failure when run
+# from a directory in a bind-mounted partition. What happens is
+# pwd reads a ".." that contains two or more entries with identical
+# dev,ino that match the ones we're looking for, and it chooses a
+# name that does not correspond to the one already recorded in $CWD.
+$actual = normalize_to_cwd_relative $actual, $dev, $ino;
+
+if ($expected ne $actual)
+ {
+ my $e_len = length $expected;
+ my $a_len = length $actual;
+ warn "expected len: $e_len\n";
+ warn "actual len: $a_len\n";
+ warn "expected: $expected\n";
+ warn "actual: $actual\n";
+ exit 1;
+ }
+EOF
+
+fail=$?
+
+Exit $fail
diff --git a/tests/pwd/pwd-option.sh b/tests/pwd/pwd-option.sh
new file mode 100755
index 0000000..50fc957
--- /dev/null
+++ b/tests/pwd/pwd-option.sh
@@ -0,0 +1,62 @@
+#!/bin/sh
+# Ensure that pwd options work.
+
+# Copyright (C) 2009-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ pwd
+
+mkdir -p a/b || framework_failure_
+ln -s a/b c || framework_failure_
+base=$(env -- pwd -P)
+
+# Remove any logical paths from $PWD.
+cd "$base" || framework_failure_
+test "x$PWD" = "x$base" || framework_failure_
+
+# Enter a logical directory.
+cd c || framework_failure_
+test "x$PWD" = "x$base/c" || skip_ "cd does not properly update \$PWD"
+
+env -- pwd -L > out || fail=1
+printf %s\\n "$base/c" > exp || fail=1
+
+env -- pwd --logical -P >> out || fail=1
+printf %s\\n "$base/a/b" >> exp || fail=1
+
+env -- pwd --physical >> out || fail=1
+printf %s\\n "$base/a/b" >> exp || fail=1
+
+# By default, we use -P unless POSIXLY_CORRECT.
+env -- pwd >> out || fail=1
+printf %s\\n "$base/a/b" >> exp || fail=1
+
+env -- POSIXLY_CORRECT=1 pwd >> out || fail=1
+printf %s\\n "$base/c" >> exp || fail=1
+
+# Make sure we reject bogus values, and silently fall back to -P.
+env -- PWD="$PWD/." pwd -L >> out || fail=1
+printf %s\\n "$base/a/b" >> exp || fail=1
+
+env -- PWD=bogus pwd -L >> out || fail=1
+printf %s\\n "$base/a/b" >> exp || fail=1
+
+env -- PWD="$base/a/../c" pwd -L >> out || fail=1
+printf %s\\n "$base/a/b" >> exp || fail=1
+
+compare exp out || fail=1
+
+Exit $fail
diff --git a/tests/readlink/can-e.sh b/tests/readlink/can-e.sh
new file mode 100755
index 0000000..6237e8d
--- /dev/null
+++ b/tests/readlink/can-e.sh
@@ -0,0 +1,104 @@
+#!/bin/sh
+# tests for canonicalize-existing mode (readlink -e).
+
+# Copyright (C) 2004-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ readlink pwd
+
+pwd=$(pwd)
+my_pwd=$(env pwd -P)
+tmp=d
+
+mkdir $tmp || framework_failure_
+cd $tmp || framework_failure_
+
+mkdir subdir removed || framework_failure_
+touch regfile || framework_failure_
+
+ln -s regfile link1 || framework_failure_
+ln -s subdir link2 || framework_failure_
+ln -s missing link3 || framework_failure_
+ln -s subdir/missing link4 || framework_failure_
+
+cd "$pwd/$tmp/removed" || framework_failure_
+
+# Skip this test if the system doesn't let you remove the working directory.
+if rmdir ../removed 2>/dev/null; then
+ v=$(returns_ 1 readlink -e .) || fail=1
+ test -z "$v" || fail=1
+fi
+
+cd "$pwd/$tmp" || fail=1
+
+for p in "" "$pwd/$tmp/"; do
+
+ v=$(readlink -e "${p}regfile") || fail=1
+ test "$v" = "$my_pwd/$tmp/regfile" || fail=1
+
+ v=$(returns_ 1 readlink -e "${p}./regfile/") || fail=1
+ test -z "$v" || fail=1
+
+ v=$(readlink -e "${p}subdir") || fail=1
+ test "$v" = "$my_pwd/$tmp/subdir" || fail=1
+
+ v=$(readlink -e "${p}./subdir/") || fail=1
+ test "$v" = "$my_pwd/$tmp/subdir" || fail=1
+
+ v=$(returns_ 1 readlink -e "${p}missing") || fail=1
+ test -z "$v" || fail=1
+
+ v=$(returns_ 1 readlink -e "${p}./missing/") || fail=1
+ test -z "$v" || fail=1
+
+ v=$(readlink -e "${p}link1") || fail=1
+ test "$v" = "$my_pwd/$tmp/regfile" || fail=1
+
+ v=$(returns_ 1 readlink -e "${p}./link1/") || fail=1
+ test -z "$v" || fail=1
+
+ v=$(returns_ 1 readlink -e "${p}link1/more") || fail=1
+ test -z "$v" || fail=1
+
+ v=$(readlink -e "${p}link2") || fail=1
+ test "$v" = "$my_pwd/$tmp/subdir" || fail=1
+
+ v=$(readlink -e "${p}./link2/") || fail=1
+ test "$v" = "$my_pwd/$tmp/subdir" || fail=1
+
+ v=$(returns_ 1 readlink -e "${p}link2/more") || fail=1
+ test -z "$v" || fail=1
+
+ v=$(returns_ 1 readlink -e "${p}link3") || fail=1
+ test -z "$v" || fail=1
+
+ v=$(returns_ 1 readlink -e "${p}./link3/") || fail=1
+ test -z "$v" || fail=1
+
+ v=$(returns_ 1 readlink -e "${p}link3/more") || fail=1
+ test -z "$v" || fail=1
+
+ v=$(returns_ 1 readlink -e "${p}link4") || fail=1
+ test -z "$v" || fail=1
+
+ v=$(returns_ 1 readlink -e "${p}./link4/") || fail=1
+ test -z "$v" || fail=1
+
+ v=$(returns_ 1 readlink -e "${p}link4/more") || fail=1
+ test -z "$v" || fail=1
+done
+
+Exit $fail
diff --git a/tests/readlink/can-f.sh b/tests/readlink/can-f.sh
new file mode 100755
index 0000000..83460e5
--- /dev/null
+++ b/tests/readlink/can-f.sh
@@ -0,0 +1,153 @@
+#!/bin/sh
+# tests for canonicalize mode (readlink -f).
+
+# Copyright (C) 2004-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ readlink pwd
+
+pwd=$(pwd)
+my_pwd=$(env pwd -P)
+tmp=d
+
+mkdir $tmp || framework_failure_
+cd $tmp || framework_failure_
+
+mkdir subdir removed || framework_failure_
+touch regfile || framework_failure_
+
+ln -s regfile link1 || framework_failure_
+ln -s subdir link2 || framework_failure_
+ln -s missing link3 || framework_failure_
+ln -s subdir/missing link4 || framework_failure_
+ln -s link5 link5 || framework_failure_
+
+cd "$pwd/$tmp/removed" || framework_failure_
+
+# Skip this test if the system doesn't let you remove the working directory.
+if rmdir ../removed 2>/dev/null; then
+ v=$(returns_ 1 readlink -e .) || fail=1
+ test -z "$v" || fail=1
+fi
+
+cd "$pwd/$tmp" || fail=1
+
+for p in "" "$pwd/$tmp/"; do
+
+ v=$(readlink -f "${p}regfile") || fail=1
+ test "$v" = "$my_pwd/$tmp/regfile" || fail=1
+
+ v=$(returns_ 1 readlink -f "${p}./regfile/") || fail=1
+ test -z "$v" || fail=1
+
+ v=$(returns_ 1 readlink -f "${p}regfile/more") || fail=1
+ test -z "$v" || fail=1
+
+ v=$(returns_ 1 readlink -f "${p}./regfile/more/") || fail=1
+ test -z "$v" || fail=1
+
+ v=$(readlink -f "${p}subdir") || fail=1
+ test "$v" = "$my_pwd/$tmp/subdir" || fail=1
+
+ v=$(readlink -f "${p}./subdir/") || fail=1
+ test "$v" = "$my_pwd/$tmp/subdir" || fail=1
+
+ v=$(readlink -f "${p}subdir/more") || fail=1
+ test "$v" = "$my_pwd/$tmp/subdir/more" || fail=1
+
+ v=$(readlink -f "${p}./subdir/more/") || fail=1
+ test "$v" = "$my_pwd/$tmp/subdir/more" || fail=1
+
+ v=$(readlink -f "${p}missing") || fail=1
+ test "$v" = "$my_pwd/$tmp/missing" || fail=1
+
+ v=$(readlink -f "${p}./missing/") || fail=1
+ test "$v" = "$my_pwd/$tmp/missing" || fail=1
+
+ v=$(returns_ 1 readlink -f "${p}missing/more") || fail=1
+ test -z "$v" || fail=1
+
+ v=$(returns_ 1 readlink -f "${p}./missing/more/") || fail=1
+ test -z "$v" || fail=1
+
+ v=$(readlink -f "${p}link1") || fail=1
+ test "$v" = "$my_pwd/$tmp/regfile" || fail=1
+
+ v=$(returns_ 1 readlink -f "${p}./link1/") || fail=1
+ test -z "$v" || fail=1
+
+ v=$(returns_ 1 readlink -f "${p}link1/more") || fail=1
+ test -z "$v" || fail=1
+
+ v=$(returns_ 1 readlink -f "${p}./link1/more/") || fail=1
+ test -z "$v" || fail=1
+
+ v=$(readlink -f "${p}link2") || fail=1
+ test "$v" = "$my_pwd/$tmp/subdir" || fail=1
+
+ v=$(readlink -f "${p}./link2/") || fail=1
+ test "$v" = "$my_pwd/$tmp/subdir" || fail=1
+
+ v=$(readlink -f "${p}link2/more") || fail=1
+ test "$v" = "$my_pwd/$tmp/subdir/more" || fail=1
+
+ v=$(readlink -f "${p}./link2/more/") || fail=1
+ test "$v" = "$my_pwd/$tmp/subdir/more" || fail=1
+
+ v=$(returns_ 1 readlink -f "${p}link2/more/more2") || fail=1
+ test -z "$v" || fail=1
+
+ v=$(returns_ 1 readlink -f "${p}./link2/more/more2/") || fail=1
+ test -z "$v" || fail=1
+
+ v=$(readlink -f "${p}link3") || fail=1
+ test "$v" = "$my_pwd/$tmp/missing" || fail=1
+
+ v=$(readlink -f "${p}./link3/") || fail=1
+ test "$v" = "$my_pwd/$tmp/missing" || fail=1
+
+ v=$(returns_ 1 readlink -f "${p}link3/more") || fail=1
+ test -z "$v" || fail=1
+
+ v=$(returns_ 1 readlink -f "${p}./link3/more/") || fail=1
+ test -z "$v" || fail=1
+
+ v=$(readlink -f "${p}link4") || fail=1
+ test "$v" = "$my_pwd/$tmp/subdir/missing" || fail=1
+
+ v=$(readlink -f "${p}./link4/") || fail=1
+ test "$v" = "$my_pwd/$tmp/subdir/missing" || fail=1
+
+ v=$(returns_ 1 readlink -f "${p}link4/more") || fail=1
+ test -z "$v" || fail=1
+
+ v=$(returns_ 1 readlink -f "${p}./link4/more") || fail=1
+ test -z "$v" || fail=1
+
+ v=$(returns_ 1 readlink -f "${p}link5") || fail=1
+ test -z "$v" || fail=1
+
+ v=$(returns_ 1 readlink -f "${p}./link5/") || fail=1
+ test -z "$v" || fail=1
+
+ v=$(returns_ 1 readlink -f "${p}link5/more") || fail=1
+ test -z "$v" || fail=1
+
+ v=$(returns_ 1 readlink -f "${p}./link5/more") || fail=1
+ test -z "$v" || fail=1
+done
+
+Exit $fail
diff --git a/tests/readlink/can-m.sh b/tests/readlink/can-m.sh
new file mode 100755
index 0000000..4cc3122
--- /dev/null
+++ b/tests/readlink/can-m.sh
@@ -0,0 +1,141 @@
+#!/bin/sh
+# tests for canonicalize-missing mode (readlink -m).
+
+# Copyright (C) 2004-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ readlink pwd
+
+pwd=$(pwd)
+my_pwd=$(env pwd -P)
+tmp=d
+
+mkdir $tmp || framework_failure_
+cd $tmp || framework_failure_
+
+mkdir subdir removed || framework_failure_
+touch regfile || framework_failure_
+
+ln -s regfile link1 || framework_failure_
+ln -s subdir link2 || framework_failure_
+ln -s missing link3 || framework_failure_
+ln -s subdir/missing link4 || framework_failure_
+
+cd "$pwd/$tmp/removed" || framework_failure_
+
+# Skip this test if the system doesn't let you remove the working directory.
+if rmdir ../removed 2>/dev/null; then
+ v=$(returns_ 1 readlink -e .) || fail=1
+ test -z "$v" || fail=1
+fi
+
+cd "$pwd/$tmp" || fail=1
+
+for p in "" "$pwd/$tmp/"; do
+
+ v=$(readlink -m "${p}regfile") || fail=1
+ test "$v" = "$my_pwd/$tmp/regfile" || fail=1
+
+ v=$(readlink -m "${p}./regfile/") || fail=1
+ test "$v" = "$my_pwd/$tmp/regfile" || fail=1
+
+ v=$(readlink -m "${p}regfile/more") || fail=1
+ test "$v" = "$my_pwd/$tmp/regfile/more" || fail=1
+
+ v=$(readlink -m "${p}./regfile/more/") || fail=1
+ test "$v" = "$my_pwd/$tmp/regfile/more" || fail=1
+
+ v=$(readlink -m "${p}subdir") || fail=1
+ test "$v" = "$my_pwd/$tmp/subdir" || fail=1
+
+ v=$(readlink -m "${p}./subdir/") || fail=1
+ test "$v" = "$my_pwd/$tmp/subdir" || fail=1
+
+ v=$(readlink -m "${p}subdir/more") || fail=1
+ test "$v" = "$my_pwd/$tmp/subdir/more" || fail=1
+
+ v=$(readlink -m "${p}./subdir/more/") || fail=1
+ test "$v" = "$my_pwd/$tmp/subdir/more" || fail=1
+
+ v=$(readlink -m "${p}missing") || fail=1
+ test "$v" = "$my_pwd/$tmp/missing" || fail=1
+
+ v=$(readlink -m "${p}./missing/") || fail=1
+ test "$v" = "$my_pwd/$tmp/missing" || fail=1
+
+ v=$(readlink -m "${p}missing/more") || fail=1
+ test "$v" = "$my_pwd/$tmp/missing/more" || fail=1
+
+ v=$(readlink -m "${p}./missing/more/") || fail=1
+ test "$v" = "$my_pwd/$tmp/missing/more" || fail=1
+
+ v=$(readlink -m "${p}link1") || fail=1
+ test "$v" = "$my_pwd/$tmp/regfile" || fail=1
+
+ v=$(readlink -m "${p}./link1/") || fail=1
+ test "$v" = "$my_pwd/$tmp/regfile" || fail=1
+
+ v=$(readlink -m "${p}link1/more") || fail=1
+ test "$v" = "$my_pwd/$tmp/regfile/more" || fail=1
+
+ v=$(readlink -m "${p}./link1/more/") || fail=1
+ test "$v" = "$my_pwd/$tmp/regfile/more" || fail=1
+
+ v=$(readlink -m "${p}link2") || fail=1
+ test "$v" = "$my_pwd/$tmp/subdir" || fail=1
+
+ v=$(readlink -m "${p}./link2/") || fail=1
+ test "$v" = "$my_pwd/$tmp/subdir" || fail=1
+
+ v=$(readlink -m "${p}link2/more") || fail=1
+ test "$v" = "$my_pwd/$tmp/subdir/more" || fail=1
+
+ v=$(readlink -m "${p}./link2/more/") || fail=1
+ test "$v" = "$my_pwd/$tmp/subdir/more" || fail=1
+
+ v=$(readlink -m "${p}link2/more/more2") || fail=1
+ test "$v" = "$my_pwd/$tmp/subdir/more/more2" || fail=1
+
+ v=$(readlink -m "${p}./link2/more/more2/") || fail=1
+ test "$v" = "$my_pwd/$tmp/subdir/more/more2" || fail=1
+
+ v=$(readlink -m "${p}link3") || fail=1
+ test "$v" = "$my_pwd/$tmp/missing" || fail=1
+
+ v=$(readlink -m "${p}./link3/") || fail=1
+ test "$v" = "$my_pwd/$tmp/missing" || fail=1
+
+ v=$(readlink -m "${p}link3/more") || fail=1
+ test "$v" = "$my_pwd/$tmp/missing/more" || fail=1
+
+ v=$(readlink -m "${p}./link3/more/") || fail=1
+ test "$v" = "$my_pwd/$tmp/missing/more" || fail=1
+
+ v=$(readlink -m "${p}link4") || fail=1
+ test "$v" = "$my_pwd/$tmp/subdir/missing" || fail=1
+
+ v=$(readlink -m "${p}./link4/") || fail=1
+ test "$v" = "$my_pwd/$tmp/subdir/missing" || fail=1
+
+ v=$(readlink -m "${p}link4/more") || fail=1
+ test "$v" = "$my_pwd/$tmp/subdir/missing/more" || fail=1
+
+ v=$(readlink -m "${p}./link4/more/") || fail=1
+ test "$v" = "$my_pwd/$tmp/subdir/missing/more" || fail=1
+
+done
+
+Exit $fail
diff --git a/tests/readlink/multi.sh b/tests/readlink/multi.sh
new file mode 100755
index 0000000..5de903d
--- /dev/null
+++ b/tests/readlink/multi.sh
@@ -0,0 +1,46 @@
+#!/bin/sh
+# test multiple argument handling.
+
+# Copyright (C) 2012-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ readlink
+
+touch regfile || framework_failure_
+ln -s regfile link1 || framework_failure_
+
+readlink link1 link1 || fail=1
+returns_ 1 readlink link1 link2 || fail=1
+returns_ 1 readlink link1 link2 link1 || fail=1
+readlink -m link1 link2 || fail=1
+
+printf '/1\0/1\0' > exp || framework_failure_
+readlink -m --zero /1 /1 > out || fail=1
+compare exp out || fail=1
+
+# The largely redundant --no-newline option is ignored with multiple args.
+# Note BSD's readlink suppresses all delimiters, even with multiple args,
+# but that functionality was not thought useful.
+readlink -n -m --zero /1 /1 > out || fail=1
+compare exp out || fail=1
+
+# Note the edge case that the last xargs run may not have a delimiter
+rm out || framework_failure_
+printf '/1\0/1\0/1' > exp || framework_failure_
+printf '/1 /1 /1 ' | xargs -n2 readlink -n -m --zero >> out || fail=1
+compare exp out || fail=1
+
+Exit $fail
diff --git a/tests/readlink/readlink-fp-loop.sh b/tests/readlink/readlink-fp-loop.sh
new file mode 100755
index 0000000..f1e277a
--- /dev/null
+++ b/tests/readlink/readlink-fp-loop.sh
@@ -0,0 +1,68 @@
+#!/bin/sh
+# readlink from 6.9 would fail with a false-positive symlink loop error
+
+# Copyright (C) 2007-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ readlink pwd
+cwd=$(env pwd -P)
+
+# To trigger this bug, we have to construct a name/situation during
+# the resolution of which the code dereferences the same symlink (S)
+# two different times with no actual loop. In addition, arrange
+# so that the second and fourth calls to readlink operate on S.
+
+ln -s s p || framework_failure_
+ln -s d s || framework_failure_
+mkdir d || framework_failure_
+echo 2 > d/2 || framework_failure_
+ln -s ../s/2 d/1 || framework_failure_
+
+# With coreutils-6.9, this would fail with ELOOP.
+readlink -v -e p/1 > out || fail=1
+# readlink -e d/2 > exp || fail=1
+echo "$cwd/d/2" > exp || framework_failure_
+compare exp out || fail=1
+
+# Construct a real loop and make sure readlink still detects it.
+ln -sf ../s/1 d/2 || framework_failure_
+readlink -v -e p/1 2> out && fail=1
+readlink_msg=$(cat out)
+case $readlink_msg in
+ "readlink: p/1: "*) ;;
+ *) fail=1;;
+esac
+symlink_loop_msg=${readlink_msg#"readlink: p/1: "}
+
+# Exercise the hash table code.
+ln -nsf ../s/3 d/2 || framework_failure_
+ln -nsf ../p/4 d/3 || framework_failure_
+ln -nsf ../p/5 d/4 || framework_failure_
+ln -nsf ../p/6 d/5 || framework_failure_
+ln -nsf ../p/7 d/6 || framework_failure_
+ln -nsf ../p/8 d/7 || framework_failure_
+echo x > d/8 || framework_failure_
+readlink -v -e p/1 > out || fail=1
+echo "$cwd/d/8" > exp || framework_failure_
+compare exp out || fail=1
+
+# A trivial loop
+ln -s loop loop
+readlink -v -e loop 2> out && fail=1
+echo "readlink: loop: $symlink_loop_msg" > exp || framework_failure_
+compare exp out || fail=1
+
+Exit $fail
diff --git a/tests/readlink/readlink-root.sh b/tests/readlink/readlink-root.sh
new file mode 100755
index 0000000..0015d3d
--- /dev/null
+++ b/tests/readlink/readlink-root.sh
@@ -0,0 +1,92 @@
+#!/bin/sh
+# tests for canonicalize-existing mode (readlink -e) on /.
+
+# Copyright (C) 2012-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ readlink
+
+stat_single=$(stat -c %d:%i /) || framework_failure_
+stat_double=$(stat -c %d:%i //) || framework_failure_
+double_slash=//
+if test x"$stat_single" = x"$stat_double"; then
+ double_slash=/
+fi
+
+test -d /dev || framework_failure_
+
+ln -s / one || framework_failure_
+ln -s // two || framework_failure_
+ln -s /// three || framework_failure_
+ln -s /./..// one-dots || framework_failure_
+ln -s //./..// two-dots || framework_failure_
+ln -s ///./..// three-dots || framework_failure_
+ln -s /dev one-dev || framework_failure_
+ln -s //dev two-dev || framework_failure_
+ln -s ///dev three-dev || framework_failure_
+
+cat >exp <<EOF || framework_failure_
+/
+$double_slash
+/
+/
+$double_slash
+/
+/
+$double_slash
+/
+/
+$double_slash
+/
+/dev
+${double_slash}dev
+/dev
+/dev
+${double_slash}dev
+/dev
+/dev
+${double_slash}dev
+/dev
+EOF
+
+{
+ readlink -e / || fail=1
+ readlink -e // || fail=1
+ readlink -e /// || fail=1
+ readlink -e /.//.. || fail=1
+ readlink -e //.//.. || fail=1
+ readlink -e ///.//.. || fail=1
+ readlink -e one || fail=1
+ readlink -e two || fail=1
+ readlink -e three || fail=1
+ readlink -e one-dots || fail=1
+ readlink -e two-dots || fail=1
+ readlink -e three-dots || fail=1
+ readlink -e one-dev || fail=1
+ # We know /dev exists, but cannot assume //dev exists
+ readlink -f two-dev || fail=1
+ readlink -e three-dev || fail=1
+ readlink -e one/dev || fail=1
+ readlink -f two/dev || fail=1
+ readlink -e three/dev || fail=1
+ readlink -e one-dots/dev || fail=1
+ readlink -f two-dots/dev || fail=1
+ readlink -e three-dots/dev || fail=1
+} > out
+
+compare exp out || fail=1
+
+Exit $fail
diff --git a/tests/readlink/rl-1.sh b/tests/readlink/rl-1.sh
new file mode 100755
index 0000000..3bdb033
--- /dev/null
+++ b/tests/readlink/rl-1.sh
@@ -0,0 +1,43 @@
+#!/bin/sh
+# test for readlink mode.
+
+# Copyright (C) 2004-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ readlink
+
+mkdir subdir || framework_failure_
+touch regfile || framework_failure_
+ln -s regfile link1 || framework_failure_
+ln -s missing link2 || framework_failure_
+
+
+v=$(readlink link1) || fail=1
+test "$v" = regfile || fail=1
+
+v=$(readlink link2) || fail=1
+test "$v" = missing || fail=1
+
+v=$(returns_ 1 readlink subdir) || fail=1
+test -z "$v" || fail=1
+
+v=$(returns_ 1 readlink regfile) || fail=1
+test -z "$v" || fail=1
+
+v=$(returns_ 1 readlink missing) || fail=1
+test -z "$v" || fail=1
+
+Exit $fail
diff --git a/tests/rm/cycle.sh b/tests/rm/cycle.sh
new file mode 100755
index 0000000..e967ce5
--- /dev/null
+++ b/tests/rm/cycle.sh
@@ -0,0 +1,36 @@
+#!/bin/sh
+# rm (coreutils-4.5.4) could be tricked into mistakenly reporting a cycle.
+
+# Copyright (C) 2003-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ rm
+skip_if_root_
+
+mkdir -p a/b
+touch a/b/file
+chmod ug-w a/b
+
+
+rm -rf a a 2>&1 | sed 's/:[^:]*$//' > out || fail=1
+cat <<\EOF > exp
+rm: cannot remove 'a/b/file'
+rm: cannot remove 'a/b/file'
+EOF
+
+compare exp out || fail=1
+
+Exit $fail
diff --git a/tests/rm/d-1.sh b/tests/rm/d-1.sh
new file mode 100755
index 0000000..7b57786
--- /dev/null
+++ b/tests/rm/d-1.sh
@@ -0,0 +1,38 @@
+#!/bin/sh
+# Test "rm --dir --verbose".
+
+# Copyright (C) 2012-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ rm
+
+mkdir a || framework_failure_
+> b || framework_failure_
+
+rm --verbose --dir a b > out || fail=1
+
+cat <<\EOF > exp || framework_failure_
+removed directory 'a'
+removed 'b'
+EOF
+
+test -e a && fail=1
+test -e b && fail=1
+
+# Compare expected and actual output.
+compare exp out || fail=1
+
+Exit $fail
diff --git a/tests/rm/d-2.sh b/tests/rm/d-2.sh
new file mode 100755
index 0000000..e235508
--- /dev/null
+++ b/tests/rm/d-2.sh
@@ -0,0 +1,37 @@
+#!/bin/sh
+# Ensure that 'rm -d dir' (i.e., without --recursive) gives a reasonable
+# diagnostic when failing.
+
+# Copyright (C) 2012-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ rm
+
+mkdir d || framework_failure_
+> d/a || framework_failure_
+
+rm -d d 2> out && fail=1
+
+# Accept any of these: EEXIST, ENOTEMPTY
+sed 's/: File exists/: Directory not empty/' out > out2
+
+printf "%s\n" \
+ "rm: cannot remove 'd': Directory not empty" \
+ > exp || framework_failure_
+
+compare exp out2 || fail=1
+
+Exit $fail
diff --git a/tests/rm/d-3.sh b/tests/rm/d-3.sh
new file mode 100755
index 0000000..ed6f171
--- /dev/null
+++ b/tests/rm/d-3.sh
@@ -0,0 +1,37 @@
+#!/bin/sh
+# Ensure that 'rm -d -i dir' (i.e., without --recursive) gives a prompt and
+# then deletes the directory if it is empty
+
+# Copyright (C) 2012-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ rm
+
+mkdir d || framework_failure_
+
+echo "y" | rm -i -d --verbose d > out 2> out.err || fail=1
+printf "%s" \
+ "rm: remove directory 'd'? " \
+ > exp.err || framework_failure_
+
+printf "%s\n" \
+ "removed directory 'd'" \
+ > exp || framework_failure_
+
+compare exp out || fail=1
+compare exp.err out.err || fail=1
+
+Exit $fail
diff --git a/tests/rm/dangling-symlink.sh b/tests/rm/dangling-symlink.sh
new file mode 100755
index 0000000..ce82e0d
--- /dev/null
+++ b/tests/rm/dangling-symlink.sh
@@ -0,0 +1,46 @@
+#!/bin/sh
+# rm should not prompt before removing a dangling symlink.
+# Likewise for a non-dangling symlink.
+# But for fileutils-4.1.9, it would do the former and
+# for fileutils-4.1.10 the latter.
+
+# Copyright (C) 2002-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ rm
+
+ln -s no-file dangle
+ln -s / symlink
+
+# Terminate any background processes
+cleanup_() { kill $pid 2>/dev/null && wait $pid; }
+
+rm ---presume-input-tty dangle symlink & pid=$!
+# The buggy rm (fileutils-4.1.9) would hang here, waiting for input.
+
+# Wait up to 6.3s for rm to remove the files
+check_files_removed() {
+ local present=0
+ sleep $1
+ ls -l dangle > /dev/null 2>&1 && present=1
+ ls -l symlink > /dev/null 2>&1 && present=1
+ test $present = 0
+}
+retry_delay_ check_files_removed .1 6 || fail=1
+
+cleanup_
+
+Exit $fail
diff --git a/tests/rm/deep-1.sh b/tests/rm/deep-1.sh
new file mode 100755
index 0000000..8741835
--- /dev/null
+++ b/tests/rm/deep-1.sh
@@ -0,0 +1,53 @@
+#!/bin/sh
+# Test "rm" with a deep hierarchy.
+
+# Copyright (C) 1997-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+# This is a bit of a torture test for mkdir -p, too.
+# GNU rm performs *much* better on systems that have a d_type member
+# in the directory structure because then it does only one stat per
+# command line argument.
+
+# If this test takes too long on your system, blame the OS.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ rm
+
+umask 022
+
+
+k20=/k/k/k/k/k/k/k/k/k/k/k/k/k/k/k/k/k/k/k/k
+k200=$k20$k20$k20$k20$k20$k20$k20$k20$k20$k20
+
+# Be careful not to exceed max file name length (usu 512?).
+# Doing so wouldn't affect GNU mkdir or GNU rm, but any tool that
+# operates on the full pathname (like 'test') would choke.
+k_deep=$k200$k200
+
+t=t
+# Create a directory in $t with lots of 'k' components.
+deep=$t$k_deep
+mkdir -p $deep || fail=1
+
+# Make sure the deep dir was created.
+test -d $deep || fail=1
+
+rm -r $t || fail=1
+
+# Make sure all of $t was deleted.
+test -d $t && fail=1
+
+Exit $fail
diff --git a/tests/rm/deep-2.sh b/tests/rm/deep-2.sh
new file mode 100755
index 0000000..ddf8564
--- /dev/null
+++ b/tests/rm/deep-2.sh
@@ -0,0 +1,53 @@
+#!/bin/sh
+# Ensure rm -r DIR does not prompt for very long full relative names in DIR.
+
+# Copyright (C) 2008-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ rm
+require_perl_
+
+# Root can run this test, but it always succeeds, since for root, all
+# files are writable, and write_protected_non_symlink never reaches
+# the offending euidaccess_stat call.
+skip_if_root_
+
+# ecryptfs for example uses some of the file name space
+# for encrypting filenames, so we must check dynamically.
+name_max=$(stat -f -c %l .)
+test "$name_max" -ge '200' || skip_ "NAME_MAX=$name_max is not sufficient"
+
+mkdir x || framework_failure_
+cd x || framework_failure_
+
+# Construct a hierarchy containing a relative file with a long name
+$PERL \
+ -e 'my $d = "x" x 200; foreach my $i (1..52)' \
+ -e ' { mkdir ($d, 0700) && chdir $d or die "$!" }' \
+ || framework_failure_
+
+cd .. || framework_failure_
+echo n > no || framework_failure_
+
+rm ---presume-input-tty -r x < no > out || fail=1
+
+# expect empty output
+compare /dev/null out || fail=1
+
+# the directory must have been removed
+test -d x && fail=1
+
+Exit $fail
diff --git a/tests/rm/dir-no-w.sh b/tests/rm/dir-no-w.sh
new file mode 100755
index 0000000..26692ea
--- /dev/null
+++ b/tests/rm/dir-no-w.sh
@@ -0,0 +1,42 @@
+#!/bin/sh
+# rm (without -r) must give a diagnostic for any directory.
+# It must not prompt, even if that directory is unwritable.
+
+# Copyright (C) 2003-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ rm
+
+mkdir --mode=0500 unwritable-dir || framework_failure_
+
+
+# For rm from coreutils-5.0.1, this would prompt.
+rm ---presume-input-tty unwritable-dir < /dev/null > out-t 2>&1 && fail=1
+cat <<\EOF > exp || framework_failure_
+rm: cannot remove 'unwritable-dir': Is a directory
+EOF
+
+# When run by a non-privileged user we get this:
+# rm: cannot remove directory 'unwritable-dir': Is a directory
+# When run by root we get this:
+# rm: cannot remove 'unwritable-dir': Is a directory
+# Normalize the message.
+sed 's/remove directory/remove/' out-t > out
+rm -f out-t
+
+compare exp out || fail=1
+
+Exit $fail
diff --git a/tests/rm/dir-nonrecur.sh b/tests/rm/dir-nonrecur.sh
new file mode 100755
index 0000000..31b4c70
--- /dev/null
+++ b/tests/rm/dir-nonrecur.sh
@@ -0,0 +1,34 @@
+#!/bin/sh
+# Ensure that 'rm dir' (i.e., without --recursive) gives a reasonable
+# diagnostic when failing.
+
+# Copyright (C) 2005-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ rm
+
+mkdir d || framework_failure_
+
+
+rm d 2> out && fail=1
+cat <<\EOF > exp || framework_failure_
+rm: cannot remove 'd': Is a directory
+EOF
+
+# Before coreutils-5.93 this test would fail on Solaris 9 and newer.
+compare exp out || fail=1
+
+Exit $fail
diff --git a/tests/rm/dot-rel.sh b/tests/rm/dot-rel.sh
new file mode 100755
index 0000000..b145cd6
--- /dev/null
+++ b/tests/rm/dot-rel.sh
@@ -0,0 +1,29 @@
+#!/bin/sh
+# Use rm -r to remove two non-empty dot-relative directories.
+# This would have failed between 2004-10-18 and 2004-10-21.
+
+# Copyright (C) 2004-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ rm
+
+mkdir a b || framework_failure_
+touch a/f b/f || framework_failure_
+
+
+rm -r a b || fail=1
+
+Exit $fail
diff --git a/tests/rm/empty-immutable-skip.sh b/tests/rm/empty-immutable-skip.sh
new file mode 100755
index 0000000..151db4c
--- /dev/null
+++ b/tests/rm/empty-immutable-skip.sh
@@ -0,0 +1,46 @@
+#!/bin/sh
+# Ensure that rm does not skip extra files after hitting an empty immutable dir.
+# Requires root access to do chattr +i, as well as an ext[23] or xfs file system
+
+# Copyright (C) 2020-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ rm
+require_root_
+
+# These simple one-file operations are expected to work even in the
+# presence of this bug, and we need them to set up the rest of the test.
+chattr_i_works=1
+touch f
+chattr +i f 2>/dev/null || chattr_i_works=0
+rm f 2>/dev/null
+test -f f || chattr_i_works=0
+chattr -i f 2>/dev/null || chattr_i_works=0
+rm f 2>/dev/null || chattr_i_works=0
+test -f f && chattr_i_works=0
+
+if test $chattr_i_works = 0; then
+ skip_ "chattr +i doesn't work on this file system"
+fi
+
+mkdir empty || framework_failure_
+touch x y || framework_failure_
+chattr +i empty || framework_failure_
+rm -rf empty x y
+{ test -f x || test -f y; } && fail=1
+chattr -i empty
+
+Exit $fail
diff --git a/tests/rm/empty-inacc.sh b/tests/rm/empty-inacc.sh
new file mode 100755
index 0000000..56f7ef3
--- /dev/null
+++ b/tests/rm/empty-inacc.sh
@@ -0,0 +1,61 @@
+#!/bin/sh
+# Ensure that rm -rf removes an empty-and-inaccessible directory.
+
+# Copyright (C) 2006-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ rm
+skip_if_root_
+
+mkdir -m0 inacc || framework_failure_
+
+# Also exercise the different code path that's taken for a directory
+# that is empty (hence removable) and unreadable.
+mkdir -m a-r -p a/unreadable || framework_failure_
+
+# This would fail for e.g., coreutils-5.93.
+rm -rf inacc || fail=1
+test -d inacc && fail=1
+
+# This would fail for e.g., coreutils-5.97.
+rm -rf a || fail=1
+test -d a && fail=1
+
+# Ensure that using rm -d removes an unreadable empty directory.
+mkdir -m a-r unreadable2 || framework_failure_
+mkdir -m0 inacc2 || framework_failure_
+
+# These would fail for coreutils-9.1 and prior.
+rm -d unreadable2 < /dev/null || fail=1
+test -d unreadable2 && fail=1
+rm -d inacc2 < /dev/null || fail=1
+test -d inacc2 && fail=1
+
+# Test the interactive code paths that are new with 9.2:
+mkdir -m0 inacc3 || framework_failure_
+
+echo n | rm ---presume-input-tty -di inacc3 > out 2>&1 || fail=1
+# decline: ensure it was not deleted, and the prompt was as expected.
+printf "rm: attempt removal of inaccessible directory 'inacc3'? " > exp
+test -d inacc3 || fail=1
+compare exp out || fail=1
+
+echo y | rm ---presume-input-tty -di inacc3 > out 2>&1 || fail=1
+# accept: ensure it **was** deleted, and the prompt was as expected.
+test -d inacc3 && fail=1
+compare exp out || fail=1
+
+Exit $fail
diff --git a/tests/rm/empty-name.pl b/tests/rm/empty-name.pl
new file mode 100755
index 0000000..d818dbd
--- /dev/null
+++ b/tests/rm/empty-name.pl
@@ -0,0 +1,60 @@
+#!/usr/bin/perl
+# Make sure that rm -r '' fails.
+
+# Copyright (C) 1998-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+# On SunOS 4.1.3, running rm -r '' in a nonempty directory may
+# actually remove files with names of entries in the current directory
+# but relative to '/' rather than relative to the current directory.
+
+use strict;
+
+(my $program_name = $0) =~ s|.*/||;
+
+# Turn off localization of executable's output.
+@ENV{qw(LANGUAGE LANG LC_ALL)} = ('C') x 3;
+
+my $prog = 'rm';
+
+# FIXME: copied from misc/ls-misc; factor into Coreutils.pm?
+sub mk_file(@)
+{
+ foreach my $f (@_)
+ {
+ open (F, '>', $f) && close F
+ or die "creating $f: $!\n";
+ }
+}
+
+my @Tests =
+ (
+ # test-name options input expected-output
+ #
+ ['empty-name-1', "''", {EXIT => 1},
+ {ERR => "$prog: cannot remove '': No such file or directory\n"}],
+
+ ['empty-name-2', "a '' b", {EXIT => 1},
+ {ERR => "$prog: cannot remove '': No such file or directory\n"},
+ {PRE => sub { mk_file qw(a b) }},
+ {POST => sub {-f 'a' || -f 'b' and die "a or b remain\n" }},
+ ],
+ );
+
+my $save_temps = $ENV{SAVE_TEMPS};
+my $verbose = $ENV{VERBOSE};
+
+my $fail = run_tests ($program_name, $prog, \@Tests, $save_temps, $verbose);
+exit $fail;
diff --git a/tests/rm/ext3-perf.sh b/tests/rm/ext3-perf.sh
new file mode 100755
index 0000000..73aa85e
--- /dev/null
+++ b/tests/rm/ext3-perf.sh
@@ -0,0 +1,83 @@
+#!/bin/sh
+# ensure that "rm -rf DIR-with-many-entries" is not O(N^2)
+
+# Copyright (C) 2008-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ rm
+
+very_expensive_
+
+# In a circa 2008 benchmark, using rm -rf to remove a 400k-entry directory took:
+# - 9 seconds with the patch, on a 2-yr-old system
+# - 350 seconds without the patch, on a high-end system (disk 20-30% faster)
+threshold_seconds=60
+
+# The number of entries in our test directory.
+n=400000
+
+# Choose a value that is large enough to ensure an accidentally
+# regressed rm would require much longer than $threshold_seconds to remove
+# the directory. With n=400k, pre-patch GNU rm would require about 350
+# seconds even on a fast disk. On a circa 2006 system, the
+# patched version of rm requires about 10 seconds, so even if you
+# choose to enable very expensive tests with a device that is much slower,
+# the test should still succeed.
+
+# Skip unless "." is on an ext[34] file system.
+# FIXME-maybe: try to find a suitable file system or allow
+# the user to specify it via an envvar.
+df -T -t ext3 -t ext4dev -t ext4 . \
+ || skip_ 'this test runs only on an ext3 or ext4 file system'
+
+# Skip if there are too few inodes free. Require some slack.
+free_inodes=$(stat -f --format=%d .) || framework_failure_
+min_free_inodes=$(expr 12 \* $n / 10)
+test $min_free_inodes -lt $free_inodes \
+ || skip_ "too few free inodes on '.': $free_inodes;" \
+ "this test requires at least $min_free_inodes"
+
+ok=0
+start=$(date +%s)
+mkdir d &&
+ cd d &&
+ seq $n | xargs touch &&
+ test -f 1 &&
+ test -f $n &&
+ cd .. &&
+ ok=1
+test $ok = 1 || framework_failure_
+setup_duration=$(expr $(date +%s) - $start)
+echo creating a $n-entry directory took $setup_duration seconds
+
+# If set-up took longer than the default $threshold_seconds,
+# use the longer set-up duration as the limit.
+test $threshold_seconds -lt $setup_duration \
+ && threshold_seconds=$setup_duration
+
+start=$(date +%s)
+timeout ${threshold_seconds}s rm -rf d; err=$?
+duration=$(expr $(date +%s) - $start)
+
+case $err in
+ 124) fail=1; echo rm took longer than $threshold_seconds seconds;;
+ 0) ;;
+ *) fail=1;;
+esac
+
+echo removing a $n-entry directory took $duration seconds
+
+Exit $fail
diff --git a/tests/rm/f-1.sh b/tests/rm/f-1.sh
new file mode 100755
index 0000000..8d119f7
--- /dev/null
+++ b/tests/rm/f-1.sh
@@ -0,0 +1,26 @@
+#!/bin/sh
+# Test "rm -f" with a nonexistent file.
+
+# Copyright (C) 1997-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ rm
+
+mkdir -p d || framework_failure_
+
+rm -f d/no-such-file || fail=1
+
+Exit $fail
diff --git a/tests/rm/fail-2eperm.sh b/tests/rm/fail-2eperm.sh
new file mode 100755
index 0000000..9e5cdb1
--- /dev/null
+++ b/tests/rm/fail-2eperm.sh
@@ -0,0 +1,57 @@
+#!/bin/sh
+# Like fail-eperm, but the failure must be for a file encountered
+# while trying to remove the containing directory with the sticky bit set.
+
+# Copyright (C) 2003-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ rm
+require_root_
+
+# The containing directory must be owned by the user who eventually runs rm.
+chown $NON_ROOT_USERNAME .
+
+mkdir a || framework_failure_
+chmod 1777 a || framework_failure_
+touch a/b || framework_failure_
+
+
+# Try to ensure that $NON_ROOT_USERNAME can access
+# the required version of rm.
+rm_version=$(
+ chroot --skip-chdir --user=$NON_ROOT_USERNAME / env PATH="$PATH" \
+ rm --version |
+ sed -n '1s/.* //p'
+)
+case $rm_version in
+ $PACKAGE_VERSION) ;;
+ *) skip_ "cannot access just-built rm as user $NON_ROOT_USERNAME";;
+esac
+chroot --skip-chdir --user=$NON_ROOT_USERNAME / \
+ env PATH="$PATH" rm -rf a 2> out-t && fail=1
+
+# On some systems, we get 'Not owner'. Convert it.
+# On other systems (HPUX), we get 'Permission denied'. Convert it, too.
+onp='Operation not permitted'
+sed "s/Not owner/$onp/;s/Permission denied/$onp/" out-t > out
+
+cat <<\EOF > exp
+rm: cannot remove 'a/b': Operation not permitted
+EOF
+
+compare exp out || fail=1
+
+Exit $fail
diff --git a/tests/rm/fail-eacces.sh b/tests/rm/fail-eacces.sh
new file mode 100755
index 0000000..d438d17
--- /dev/null
+++ b/tests/rm/fail-eacces.sh
@@ -0,0 +1,54 @@
+#!/bin/sh
+# Ensure that rm -rf unremovable-non-dir gives a diagnostic.
+# Test both a regular file and a symlink -- it makes a difference to rm.
+# With the symlink, rm from coreutils-6.9 would fail with a misleading
+# ELOOP diagnostic.
+
+# Copyright (C) 2006-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ rm
+skip_if_root_
+
+ok=0
+mkdir d &&
+ touch d/f &&
+ ln -s f d/slink &&
+ chmod a-w d &&
+ ok=1
+test $ok = 1 || framework_failure_
+
+mkdir e &&
+ ln -s f e/slink &&
+ chmod a-w e &&
+ ok=1
+test $ok = 1 || framework_failure_
+
+
+rm -rf d/f 2> out && fail=1
+cat <<\EOF > exp
+rm: cannot remove 'd/f': Permission denied
+EOF
+compare exp out || fail=1
+
+# This used to fail with ELOOP.
+rm -rf e 2> out && fail=1
+cat <<\EOF > exp
+rm: cannot remove 'e/slink': Permission denied
+EOF
+compare exp out || fail=1
+
+Exit $fail
diff --git a/tests/rm/fail-eperm.xpl b/tests/rm/fail-eperm.xpl
new file mode 100755
index 0000000..5511d30
--- /dev/null
+++ b/tests/rm/fail-eperm.xpl
@@ -0,0 +1,150 @@
+#!/usr/bin/perl -Tw
+# Ensure that rm gives the expected diagnostic when failing to remove a file
+# owned by some other user in a directory with the sticky bit set.
+
+# Copyright (C) 2002-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+use strict;
+
+(my $ME = $0) =~ s|.*/||;
+
+my $uid = $<;
+# skip if root
+$uid == 0
+ and CuSkip::skip "$ME: can't run this test as root: skipping this test";
+
+my $verbose = $ENV{VERBOSE} && $ENV{VERBOSE} eq 'yes';
+
+# Ensure that the diagnostics are in English.
+$ENV{LC_ALL} = 'C';
+
+# Set up a safe, well-known environment
+$ENV{IFS} = '';
+
+# Taint checking requires a sanitized $PATH. This script performs no $PATH
+# search, so on most Unix-based systems, it is fine simply to clear $ENV{PATH}.
+# However, on Cygwin, it's used to find cygwin1.dll, so set it.
+$ENV{PATH} = '/bin:/usr/bin';
+
+my @dir_list = qw(/tmp /var/tmp /usr/tmp);
+my $rm = "$ENV{abs_top_builddir}/src/rm";
+
+# Untaint for upcoming popen.
+$rm =~ m!^([-+\@\w./]+)$!
+ or CuSkip::skip "$ME: unusual absolute builddir name; skipping this test\n";
+$rm = $1;
+
+# Find a directory with the sticky bit set.
+my $found_dir;
+my $found_file;
+foreach my $dir (@dir_list)
+ {
+ if (-d $dir && -k _ && -r _ && -w _ && -x _)
+ {
+ $found_dir = 1;
+
+ # Find a non-directory there that is owned by some other user.
+ opendir DIR_HANDLE, $dir
+ or die "$ME: couldn't open $dir: $!\n";
+
+ foreach my $f (readdir DIR_HANDLE)
+ {
+ # Consider only names containing "safe" characters.
+ $f =~ /^([-\@\w.]+)$/
+ or next;
+ $f = $1; # untaint $f
+
+ my $target_file = "$dir/$f";
+ $verbose
+ and warn "$ME: considering $target_file\n";
+
+ # Skip files owned by self, symlinks, and directories.
+ # It's not technically necessary to skip symlinks, but it's simpler.
+ # SVR4-like systems (e.g., Solaris 9) let you unlink files that
+ # you can write, so skip writable files too.
+ -l $target_file || -o _ || -d _ || -w _
+ and next;
+
+ $found_file = 1;
+
+ # Invoke rm on this file and ensure that we get the
+ # expected exit code and diagnostic.
+ my $cmd = "$rm -f -- $target_file";
+ open RM, "$cmd 2>&1 |"
+ or die "$ME: cannot execute '$cmd'\n";
+
+ my $line = <RM>;
+
+ close RM;
+ my $rc = $?;
+ # This test opportunistically looks for files that can't
+ # be removed but those files may already have been removed
+ # by their owners by the time we get to them. It is a
+ # race condition. If so then the rm is successful and our
+ # test is thwarted. Detect this case and ignore.
+ if ($rc == 0)
+ {
+ next if ! -e $target_file;
+ die "$ME: unexpected exit status from '$cmd';\n"
+ . " got 0, expected 1\n";
+ }
+ if (0x80 < $rc)
+ {
+ my $status = $rc >> 8;
+ $status == 1
+ or die "$ME: unexpected exit status from '$cmd';\n"
+ . " got $status, expected 1\n";
+ }
+ else
+ {
+ # Terminated by a signal.
+ my $sig_num = $rc & 0x7F;
+ die "$ME: command '$cmd' died with signal $sig_num\n";
+ }
+
+ my $exp = "rm: cannot remove '$target_file':";
+ $line
+ or die "$ME: no output from '$cmd';\n"
+ . "expected something like '$exp ...'\n";
+
+ # Transform the actual diagnostic so that it starts with "rm:".
+ # Depending on your system, it might be "rm:" already, or
+ # "../../src/rm:".
+ $line =~ s,^\Q$rm\E:,rm:,;
+
+ my $regex = quotemeta $exp;
+ $line =~ /^$regex/
+ or die "$ME: unexpected diagnostic from '$cmd';\n"
+ . " got $line"
+ . " expected $exp ...\n";
+
+ last;
+ }
+
+ closedir DIR_HANDLE;
+ $found_file
+ and last;
+ }
+ }
+
+$found_dir
+ or CuSkip::skip "$ME: couldn't find a directory with the sticky bit set;"
+ . " skipping this test\n";
+
+$found_file
+ or CuSkip::skip "$ME: couldn't find a file not owned by you\n"
+ . " in any of the following directories:\n @dir_list\n"
+ . "...so, skipping this test\n";
diff --git a/tests/rm/hash.sh b/tests/rm/hash.sh
new file mode 100755
index 0000000..5ff3c19
--- /dev/null
+++ b/tests/rm/hash.sh
@@ -0,0 +1,37 @@
+#!/bin/sh
+# Exercise a bug that was fixed in 4.0s.
+# Before then, rm would fail occasionally, sometimes via
+# a failed assertion, others with a seg fault.
+
+# Copyright (C) 2000-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ rm
+expensive_
+
+# Create a hierarchy with 3*26 leaf directories, each at depth 153.
+echo "$0: creating 78 trees, each of depth 153; this will take a while..." >&2
+y=$(seq 1 150|tr -sc '\n' y|tr '\n' /)
+for i in 1 2 3; do
+ for j in a b c d e f g h i j k l m n o p q r s t u v w x y z; do
+ mkdir -p t/$i/$j/$y || framework_failure_
+ done
+done
+
+
+rm -r t || fail=1
+
+Exit $fail
diff --git a/tests/rm/i-1.sh b/tests/rm/i-1.sh
new file mode 100755
index 0000000..96fb98e
--- /dev/null
+++ b/tests/rm/i-1.sh
@@ -0,0 +1,40 @@
+#!/bin/sh
+# Test "rm -i".
+
+# Copyright (C) 1997-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ rm
+
+t=t
+mkdir -p $t || framework_failure_
+echo > $t/a || framework_failure_
+test -f $t/a || framework_failure_
+
+echo y > $t/in-y
+echo n > $t/in-n
+
+rm -i $t/a < $t/in-n > /dev/null 2>&1 || fail=1
+# The file should not have been removed.
+test -f $t/a || fail=1
+
+rm -i $t/a < $t/in-y > /dev/null 2>&1 || fail=1
+# The file should have been removed this time.
+test -f $t/a && fail=1
+
+rm -rf $t
+
+Exit $fail
diff --git a/tests/rm/i-never.sh b/tests/rm/i-never.sh
new file mode 100755
index 0000000..471a8f4
--- /dev/null
+++ b/tests/rm/i-never.sh
@@ -0,0 +1,33 @@
+#!/bin/sh
+# Ensure that rm --interactive=never works does not prompt, even for
+# an unwritable file.
+
+# Copyright (C) 2007-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ rm
+skip_if_root_
+
+touch f || framework_failure_
+chmod 0 f || framework_failure_
+touch exp || framework_failure_
+
+
+rm --interactive=never f > out || fail=1
+
+compare exp out || fail=1
+
+Exit $fail
diff --git a/tests/rm/i-no-r.sh b/tests/rm/i-no-r.sh
new file mode 100755
index 0000000..89bda8e
--- /dev/null
+++ b/tests/rm/i-no-r.sh
@@ -0,0 +1,34 @@
+#!/bin/sh
+# Since the rewrite for fileutils-4.1.9, 'rm -i DIR' would mistakenly
+# recurse into directory DIR. rm -i (without -r) must fail in that case.
+# Fixed in coreutils-4.5.2.
+
+# Copyright (C) 2002-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ rm
+
+mkdir dir || framework_failure_
+echo y > y || framework_failure_
+
+
+# This must fail.
+returns_ 1 rm -i dir < y > /dev/null 2>&1 || fail=1
+
+# The directory must remain.
+test -d dir || fail=1
+
+Exit $fail
diff --git a/tests/rm/ignorable.sh b/tests/rm/ignorable.sh
new file mode 100755
index 0000000..68a555f
--- /dev/null
+++ b/tests/rm/ignorable.sh
@@ -0,0 +1,30 @@
+#!/bin/sh
+# Ensure that rm -f existing-non-dir/anything exits successfully
+
+# Copyright (C) 2006-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ rm
+skip_if_root_
+
+touch existing-non-dir || framework_failure_
+
+
+# With coreutils-6.3, this would exit nonzero. It should not.
+# Example from Andreas Schwab.
+rm -f existing-non-dir/f > out 2>&1 || fail=1
+
+Exit $fail
diff --git a/tests/rm/inaccessible.sh b/tests/rm/inaccessible.sh
new file mode 100755
index 0000000..da82fe6
--- /dev/null
+++ b/tests/rm/inaccessible.sh
@@ -0,0 +1,49 @@
+#!/bin/sh
+# Ensure that rm works even when run from a directory
+# for which the user has no access at all.
+
+# Copyright (C) 2004-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ rm
+
+# Skip this test if your system has neither the openat-style functions
+# nor /proc/self/fd support with which to emulate them.
+require_openat_support_
+skip_if_root_
+
+p=$(pwd)
+mkdir abs1 abs2 no-access || framework_failure_
+
+
+set +x
+(cd no-access; chmod 0 . && rm -r "$p/abs1" rel "$p/abs2") 2> out && fail=1
+test -d "$p/abs1" && fail=1
+test -d "$p/abs2" && fail=1
+
+cat <<\EOF > exp || framework_failure_
+rm: cannot remove 'rel': Permission denied
+EOF
+
+# AIX 4.3.3 fails with a different diagnostic.
+# Transform their diagnostic
+# ...: The file access permissions do not allow the specified action.
+# to the expected one:
+sed 's/: The file access permissions.*/: Permission denied/'<out>o1;mv o1 out
+
+compare exp out || fail=1
+
+Exit $fail
diff --git a/tests/rm/interactive-always.sh b/tests/rm/interactive-always.sh
new file mode 100755
index 0000000..7223b0d
--- /dev/null
+++ b/tests/rm/interactive-always.sh
@@ -0,0 +1,87 @@
+#!/bin/sh
+# Test the --interactive[=WHEN] changes added to coreutils 6.0
+
+# Copyright (C) 2006-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ rm
+
+touch file1-1 file1-2 file2-1 file2-2 file3-1 file3-2 file4-1 file4-2 \
+ || framework_failure_
+# If asked, answer no to first question, then yes to second.
+echo 'n
+y' > in || framework_failure_
+rm -f out err || framework_failure_
+
+
+# The prompt has a trailing space, and no newline, so an extra
+# 'echo .' is inserted after each rm to make it obvious what was asked.
+
+echo 'no WHEN' > err || framework_failure_
+rm -R --interactive file1-* < in >> out 2>> err || fail=1
+echo . >> err || framework_failure_
+test -f file1-1 || fail=1
+test -f file1-2 && fail=1
+
+echo 'WHEN=never' >> err || framework_failure_
+rm -R --interactive=never file2-* < in >> out 2>> err || fail=1
+echo . >> err || framework_failure_
+test -f file2-1 && fail=1
+test -f file2-2 && fail=1
+
+echo 'WHEN=once' >> err || framework_failure_
+rm -R --interactive=once file3-* < in >> out 2>> err || fail=1
+echo . >> err || framework_failure_
+test -f file3-1 || fail=1
+test -f file3-2 || fail=1
+
+echo 'WHEN=always' >> err || framework_failure_
+rm -R --interactive=always file4-* < in >> out 2>> err || fail=1
+echo . >> err || framework_failure_
+test -f file4-1 || fail=1
+test -f file4-2 && fail=1
+
+echo '-f overrides --interactive' >> err || framework_failure_
+rm -R --interactive=once -f file1-* < in >> out 2>> err || fail=1
+echo . >> err || framework_failure_
+test -f file1-1 && fail=1
+
+echo '--interactive overrides -f' >> err || framework_failure_
+rm -R -f --interactive=once file4-* < in >> out 2>> err || fail=1
+echo . >> err || framework_failure_
+test -f file4-1 || fail=1
+
+cat <<\EOF > experr.t || framework_failure_
+no WHEN
+@remove_empty 'file1-1'? @remove_empty 'file1-2'? .
+WHEN=never
+.
+WHEN=once
+rm: remove 2 arguments recursively? .
+WHEN=always
+@remove_empty 'file4-1'? @remove_empty 'file4-2'? .
+-f overrides --interactive
+.
+--interactive overrides -f
+rm: remove 1 argument recursively? .
+EOF
+sed 's/@remove_empty/rm: remove regular empty file/g' < experr.t > experr ||
+ framework_failure_
+
+compare /dev/null out || fail=1
+compare experr err || fail=1
+
+Exit $fail
diff --git a/tests/rm/interactive-once.sh b/tests/rm/interactive-once.sh
new file mode 100755
index 0000000..54b288f
--- /dev/null
+++ b/tests/rm/interactive-once.sh
@@ -0,0 +1,149 @@
+#!/bin/sh
+# Test the -I option added to coreutils 6.0
+
+# Copyright (C) 2006-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ rm
+
+mkdir -p dir1-1 dir2-1 dir2-2 || framework_failure_
+touch file1-1 file2-1 file2-2 file2-3 file3-1 file3-2 file3-3 file3-4 \
+ || framework_failure_
+echo y > in-y || framework_failure_
+echo n > in-n || framework_failure_
+rm -f out err || framework_failure_
+
+
+# The prompt has a trailing space, and no newline, so an extra
+# 'echo .' is inserted after each rm to make it obvious what was asked.
+
+echo 'one file, no recursion' > err || framework_failure_
+rm -I file1-* < in-n >> out 2>> err || fail=1
+echo . >> err || framework_failure_
+test -f file1-1 && fail=1
+
+write_prot_msg1=
+echo 'one file, read only, answer no' >> err || framework_failure_
+if ls /dev/stdin >/dev/null 2>&1; then
+ touch file1-1 || framework_failure_
+ chmod a-w file1-1 || framework_failure_
+ if ! test -w file1-1; then
+ # root won't get prompted
+ write_prot_msg1="rm: remove write-protected regular empty file 'file1-1'? "
+ fi
+ rm ---presume-input-tty -I file1-* < in-n >> out 2>> err || fail=1
+ echo . >> err || framework_failure_
+ if test "$write_prot_msg1"; then
+ test -f file1-1 || fail=1
+ fi
+else
+ echo '.' >> err || framework_failure_
+fi
+
+echo 'three files, no recursion' >> err || framework_failure_
+rm -I file2-* < in-n >> out 2>> err || fail=1
+echo . >> err || framework_failure_
+test -f file2-1 && fail=1
+test -f file2-2 && fail=1
+test -f file2-3 && fail=1
+
+echo 'four files, no recursion, answer no' >> err || framework_failure_
+rm -I file3-* < in-n >> out 2>> err || fail=1
+echo . >> err || framework_failure_
+test -f file3-1 || fail=1
+test -f file3-2 || fail=1
+test -f file3-3 || fail=1
+test -f file3-4 || fail=1
+
+echo 'four files, no recursion, answer yes' >> err || framework_failure_
+rm -I file3-* < in-y >> out 2>> err || fail=1
+echo . >> err || framework_failure_
+test -f file3-1 && fail=1
+test -f file3-2 && fail=1
+test -f file3-3 && fail=1
+test -f file3-4 && fail=1
+
+echo 'four files, no recursion, 1 read only, answer yes no' >> err \
+ || framework_failure_
+if ls /dev/stdin >/dev/null 2>&1; then
+ touch file3-1 file3-2 file3-3 file3-4 || framework_failure_
+ echo non_empty > file3-4 || framework_failure_ # to shorten diagnostic
+ chmod a-w file3-4 || framework_failure_
+ if ! test -w file3-4; then
+ # root won't get prompted
+ write_prot_msg2="rm: remove write-protected regular file 'file3-4'? "
+ fi
+ cat in-y in-n | rm ---presume-input-tty -I file3-* >> out 2>> err || fail=1
+ echo . >> err || framework_failure_
+ test -f file3-1 && fail=1
+ test -f file3-2 && fail=1
+ test -f file3-3 && fail=1
+ if test "$write_prot_msg2"; then
+ test -f file3-4 || fail=1
+ fi
+else
+ echo 'rm: remove 4 arguments? .' >> err || framework_failure_
+fi
+
+echo 'one file, recursion, answer no' >> err || framework_failure_
+rm -I -R dir1-* < in-n >> out 2>> err || fail=1
+echo . >> err || framework_failure_
+test -d dir1-1 || fail=1
+
+echo 'one file, recursion, answer yes' >> err || framework_failure_
+rm -I -R dir1-* < in-y >> out 2>> err || fail=1
+echo . >> err || framework_failure_
+test -d dir1-1 && fail=1
+
+echo 'multiple files, recursion, answer no' >> err || framework_failure_
+rm -I -R dir2-* < in-n >> out 2>> err || fail=1
+echo . >> err || framework_failure_
+test -d dir2-1 || fail=1
+test -d dir2-2 || fail=1
+
+echo 'multiple files, recursion, answer yes' >> err || framework_failure_
+rm -I -R dir2-* < in-y >> out 2>> err || fail=1
+echo . >> err || framework_failure_
+test -d dir2-1 && fail=1
+test -d dir2-2 && fail=1
+
+cat <<EOF > experr || framework_failure_
+one file, no recursion
+.
+one file, read only, answer no
+$write_prot_msg1.
+three files, no recursion
+.
+four files, no recursion, answer no
+rm: remove 4 arguments? .
+four files, no recursion, answer yes
+rm: remove 4 arguments? .
+four files, no recursion, 1 read only, answer yes no
+rm: remove 4 arguments? $write_prot_msg2.
+one file, recursion, answer no
+rm: remove 1 argument recursively? .
+one file, recursion, answer yes
+rm: remove 1 argument recursively? .
+multiple files, recursion, answer no
+rm: remove 2 arguments recursively? .
+multiple files, recursion, answer yes
+rm: remove 2 arguments recursively? .
+EOF
+
+compare /dev/null out || fail=1
+compare experr err || fail=1
+
+Exit $fail
diff --git a/tests/rm/ir-1.sh b/tests/rm/ir-1.sh
new file mode 100755
index 0000000..247a12b
--- /dev/null
+++ b/tests/rm/ir-1.sh
@@ -0,0 +1,56 @@
+#!/bin/sh
+# Test "rm -ir".
+
+# Copyright (C) 1997-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ rm
+
+t=t
+mkdir -p $t $t/a $t/b $t/c || framework_failure_
+> $t/a/a || framework_failure_
+> $t/b/bb || framework_failure_
+> $t/c/cc || framework_failure_
+
+cat <<EOF > in
+y
+y
+y
+y
+y
+y
+y
+y
+n
+n
+n
+EOF
+
+# Remove all but one of a, b, c -- I doubt that this test can portably
+# determine which one was removed based on order of dir entries.
+# This is a good argument for switching to a dejagnu-style test suite.
+rm --verbose -i -r $t < in > /dev/null 2>&1 || fail=1
+
+# $t should not have been removed.
+test -d $t || fail=1
+
+# There should be only one directory left.
+case $(echo $t/*) in
+ $t/[abc]) ;;
+ *) fail=1 ;;
+esac
+
+Exit $fail
diff --git a/tests/rm/isatty.sh b/tests/rm/isatty.sh
new file mode 100755
index 0000000..8bf13f0
--- /dev/null
+++ b/tests/rm/isatty.sh
@@ -0,0 +1,55 @@
+#!/bin/sh
+# Make sure 'chown 0 f; rm f' prompts before removing f.
+
+# Copyright (C) 2001-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ rm
+skip_if_root_
+
+
+# Skip this test if there is no /dev/stdin file.
+ls /dev/stdin >/dev/null 2>&1 \
+ || skip_ 'there is no /dev/stdin file'
+
+# Terminate any background processes
+cleanup_() { kill $pid 2>/dev/null && wait $pid; }
+
+touch f
+chmod 0 f
+rm ---presume-input-tty f > out 2>&1 & pid=$!
+
+# Wait a second, to give a buggy rm (as in fileutils-4.0.40)
+# enough time to remove the file.
+sleep 1
+
+# The file must still exist.
+test -f f || fail=1
+
+cleanup_
+
+# Note the trailing 'x' -- so I don't have to have a trailing
+# blank in this file :-)
+cat > exp <<\EOF
+rm: remove write-protected regular empty file 'f'? x
+EOF
+
+# Append an 'x' and a newline.
+echo x >> out
+
+compare exp out || fail=1
+
+Exit $fail
diff --git a/tests/rm/many-dir-entries-vs-OOM.sh b/tests/rm/many-dir-entries-vs-OOM.sh
new file mode 100755
index 0000000..5cc25ab
--- /dev/null
+++ b/tests/rm/many-dir-entries-vs-OOM.sh
@@ -0,0 +1,47 @@
+#!/bin/sh
+# In coreutils-8.12, rm,du,chmod, etc. would use too much memory
+# when processing a directory with many entries (as in > 100,000).
+
+# Copyright (C) 2011-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ rm du chmod
+expensive_
+
+mkdir d2 \
+ && touch d2/f || framework_failure_
+
+# Restrict memory. Each of these coreutils-8.12 programs would fail
+# with a diagnostic like "rm: fts_read failed: Cannot allocate memory".
+vm=$(get_min_ulimit_v_ du -sh d2) \
+ || skip_ "this shell lacks ulimit support"
+
+# With many files in a single directory...
+mkdir d || framework_failure_
+seq --format="d/%06g" 200000 | xargs touch || framework_failure_
+
+# Allow 35MiB more memory as for the trivial case above.
+(ulimit -v $(($vm + 35000)) && du -sh d) || fail=1
+
+vm=$(get_min_ulimit_v_ chmod -R 700 d2) \
+ || skip_ "this shell lacks ulimit support"
+(ulimit -v $(($vm + 35000)) && chmod -R 700 d) || fail=1
+
+vm=$(get_min_ulimit_v_ rm -rf d2) \
+ || skip_ "this shell lacks ulimit support"
+(ulimit -v $(($vm + 35000)) && rm -rf d) || fail=1
+
+Exit $fail
diff --git a/tests/rm/no-give-up.sh b/tests/rm/no-give-up.sh
new file mode 100755
index 0000000..f4ac7a2
--- /dev/null
+++ b/tests/rm/no-give-up.sh
@@ -0,0 +1,42 @@
+#!/bin/sh
+# With rm from coreutils-5.2.1 and earlier, 'rm -r' would mistakenly
+# give up too early under some conditions.
+
+# Copyright (C) 2004-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ rm
+require_root_
+
+mkdir d || framework_failure_
+touch d/f || framework_failure_
+chown -R $NON_ROOT_USERNAME d || framework_failure_
+
+# Ensure that non-root can access files in root-owned ".".
+chmod go=x . || framework_failure_
+
+
+# This must fail, since '.' is not writable by $NON_ROOT_USERNAME.
+returns_ 1 chroot --skip-chdir --user=$NON_ROOT_USERNAME / env PATH="$PATH" \
+ rm -rf d 2>/dev/null || fail=1
+
+# d must remain.
+test -d d || fail=1
+
+# f must have been removed.
+test -f d/f && fail=1
+
+Exit $fail
diff --git a/tests/rm/one-file-system.sh b/tests/rm/one-file-system.sh
new file mode 100755
index 0000000..5ab75bb
--- /dev/null
+++ b/tests/rm/one-file-system.sh
@@ -0,0 +1,51 @@
+#!/bin/sh
+# Demonstrate rm's new --one-file-system option.
+
+# Copyright (C) 2006-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ rm
+require_root_
+
+cleanup_()
+{
+ # When you take the undesirable shortcut of making /etc/mtab a link
+ # to /proc/mounts, unmounting "$other_partition_tmpdir" would fail.
+ # So, here we unmount a/b instead.
+ umount a/b
+ rm -rf "$other_partition_tmpdir"
+}
+. "$abs_srcdir/tests/other-fs-tmpdir"
+
+t=$other_partition_tmpdir
+mkdir -p a/b $t/y
+mount --bind $t a/b \
+ || skip_ "This test requires mount with a working --bind option."
+
+cat <<\EOF > exp || framework_failure_
+rm: skipping 'a/b', since it's on a different device
+EOF
+returns_ 1 rm --one-file-system -rf a 2> out || fail=1
+test -d $t/y || fail=1
+compare exp out || fail=1
+
+cat <<\EOF >> exp || framework_failure_
+rm: and --preserve-root=all is in effect
+EOF
+returns_ 1 rm --preserve-root=all -rf a/b 2>out || fail=1
+compare exp out || fail=1
+
+Exit $fail
diff --git a/tests/rm/one-file-system2.sh b/tests/rm/one-file-system2.sh
new file mode 100755
index 0000000..4bca2f4
--- /dev/null
+++ b/tests/rm/one-file-system2.sh
@@ -0,0 +1,27 @@
+#!/bin/sh
+# Verify --one-file-system does delete within a file system
+
+# Copyright (C) 2009-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ rm
+
+mkdir -p a/b
+
+rm --one-file-system -rf a || fail=1
+test -d a && fail=1
+
+Exit $fail
diff --git a/tests/rm/r-1.sh b/tests/rm/r-1.sh
new file mode 100755
index 0000000..e0a8716
--- /dev/null
+++ b/tests/rm/r-1.sh
@@ -0,0 +1,40 @@
+#!/bin/sh
+# Test "rm -r --verbose".
+
+# Copyright (C) 1997-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ rm
+
+mkdir a a/a || framework_failure_
+> b || framework_failure_
+
+cat <<\EOF > exp || framework_failure_
+removed directory 'a/a'
+removed directory 'a'
+removed 'b'
+EOF
+
+rm --verbose -r a b > out || fail=1
+
+for d in $dirs; do
+ test -d $d && fail=1
+done
+
+# Compare expected and actual output.
+compare exp out || fail=1
+
+Exit $fail
diff --git a/tests/rm/r-2.sh b/tests/rm/r-2.sh
new file mode 100755
index 0000000..78040d3
--- /dev/null
+++ b/tests/rm/r-2.sh
@@ -0,0 +1,45 @@
+#!/bin/sh
+# Test "rm -r --verbose".
+
+# Copyright (C) 1997-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ rm
+
+mkdir t t/a t/a/b || framework_failure_
+> t/a/f || framework_failure_
+> t/a/b/g || framework_failure_
+
+# FIXME: if this fails, it's a framework failure
+cat <<\EOF | sort > t/E || framework_failure_
+removed directory 't/a'
+removed directory 't/a/b'
+removed 't/a/b/g'
+removed 't/a/f'
+EOF
+
+# Note that both the expected output (above) and the actual output lines
+# are sorted, because directory entries may be processed in arbitrary order.
+rm --verbose -r t/a | sort > t/O || fail=1
+
+if test -d t/a; then
+ fail=1
+fi
+
+# Compare expected and actual output.
+cmp t/E t/O || fail=1
+
+Exit $fail
diff --git a/tests/rm/r-3.sh b/tests/rm/r-3.sh
new file mode 100755
index 0000000..f2d4c5b
--- /dev/null
+++ b/tests/rm/r-3.sh
@@ -0,0 +1,48 @@
+#!/bin/sh
+# Create and remove a directory with more than 254 files.
+
+# Copyright (C) 1997-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+
+# An early version of my rewritten rm failed to remove all of
+# the files on SunOS4 when there were 254 or more in a directory.
+
+# And the rm from coreutils-5.0 exposes the same problem when there
+# are 338 or more files in a directory on a Darwin-6.5 system
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ rm
+
+mkdir t || framework_failure_
+cd t || framework_failure_
+
+# Create 500 files (20 * 25).
+for i in 0 1 2 3 4 5 6 7 8 9 a b c d e f g h i j; do
+ files=
+ for j in a b c d e f g h i j k l m n o p q r s t u v w x y; do
+ files="$files $i$j"
+ done
+ touch $files || framework_failure_
+done
+
+test -f 0a || framework_failure_
+test -f by || framework_failure_
+cd .. || framework_failure_
+
+rm -rf t || fail=1
+test -d t && fail=1
+
+Exit $fail
diff --git a/tests/rm/r-4.sh b/tests/rm/r-4.sh
new file mode 100755
index 0000000..7acf52d
--- /dev/null
+++ b/tests/rm/r-4.sh
@@ -0,0 +1,51 @@
+#!/bin/sh
+# Try to remove '.' and '..' recursively.
+
+# Copyright (C) 2006-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ rm
+
+mkdir d || framework_failure_
+touch d/a || framework_failure_
+
+# Expected error diagnostic as grep pattern.
+exp="^rm: refusing to remove '\.' or '\.\.' directory: skipping '.*'\$"
+
+rmtest()
+{
+ # Try removing - expecting failure.
+ rm -fr "$1" 2> err && fail=1
+
+ # Ensure the expected error diagnostic is output.
+ grep "$exp" err || { cat err; fail=1; }
+
+ return $fail
+}
+
+rmtest 'd/.' || fail=1
+rmtest 'd/./' || fail=1
+rmtest 'd/.////' || fail=1
+rmtest 'd/..' || fail=1
+rmtest 'd/../' || fail=1
+
+
+# This test is handled more carefully in r-root.sh
+# returns_ 1 rm -fr / 2>/dev/null || fail=1
+
+test -f d/a || fail=1
+
+Exit $fail
diff --git a/tests/rm/r-root.sh b/tests/rm/r-root.sh
new file mode 100755
index 0000000..d60c5e7
--- /dev/null
+++ b/tests/rm/r-root.sh
@@ -0,0 +1,325 @@
+#!/bin/sh
+# Try to remove '/' recursively.
+
+# Copyright (C) 2013-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ rm
+
+# POSIX mandates rm(1) to skip '/' arguments. This test verifies this mandated
+# behavior as well as the --preserve-root and --no-preserve-root options.
+# Especially the latter case is a live fire exercise as rm(1) is supposed to
+# enter the unlinkat() system call. Therefore, limit the risk as much
+# as possible -- if there's a bug this test would wipe the system out!
+
+# Fainthearted: skip this test for the 'root' user.
+skip_if_root_
+
+# Pull the teeth from rm(1) by intercepting the unlinkat() system call via the
+# LD_PRELOAD environment variable. This requires shared libraries to work.
+require_gcc_shared_
+
+# Ensure this variable is unset as it's
+# used later in the unlinkat() wrapper.
+unset CU_TEST_SKIP_EXIT
+
+# Set this to 0 if you don't have a working gdb but would
+# still like to run the test
+USE_GDB=1
+
+if test $USE_GDB = 1; then
+ case $host_triplet in
+ *darwin*) skip_ 'avoiding due to potentially non functioning gdb' ;;
+ *) ;;
+ esac
+
+ # Use gdb to provide further protection by limiting calls to unlinkat().
+ ( timeout 10s gdb --version ) > gdb.out 2>&1
+ case $(cat gdb.out) in
+ *'GNU gdb'*) ;;
+ *) skip_ "can't run gdb";;
+ esac
+fi
+
+# Break on a line rather than a symbol, to cater for inline functions
+break_src="$abs_top_srcdir/src/remove.c"
+break_line=$(grep -n ^excise "$break_src") || framework_failure_
+break_line=$(echo "$break_line" | cut -d: -f1) || framework_failure_
+break_line="$break_src:$break_line"
+
+
+cat > k.c <<'EOF' || framework_failure_
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+int unlinkat (int dirfd, const char *pathname, int flags)
+{
+ /* Prove that LD_PRELOAD works: create the evidence file "x". */
+ fclose (fopen ("x", "w"));
+
+ /* Immediately terminate, unless indicated otherwise. */
+ if (! getenv("CU_TEST_SKIP_EXIT"))
+ _exit (0);
+
+ /* Pretend success. */
+ return 0;
+}
+EOF
+
+# Then compile/link it:
+gcc_shared_ k.c k.so \
+ || framework_failure_ 'failed to build shared library'
+
+# Note breakpoint commands don't work in batch mode
+# https://sourceware.org/bugzilla/show_bug.cgi?id=10079
+# So we use python to script behavior upon hitting the breakpoint
+cat > bp.py <<'EOF.py' || framework_failure_
+def breakpoint_handler (event):
+ if not isinstance(event, gdb.BreakpointEvent):
+ return
+ hit_count = event.breakpoints[0].hit_count
+ if hit_count == 1:
+ gdb.execute('shell touch excise.break')
+ gdb.execute('continue')
+ elif hit_count > 2:
+ gdb.write('breakpoint hit twice already')
+ gdb.execute('quit 1')
+ else:
+ gdb.execute('continue')
+
+gdb.events.stop.connect(breakpoint_handler)
+EOF.py
+
+# In order of the sed expressions below, this cleans:
+#
+# 1. gdb uses the full path when running rm, so remove the leading dirs.
+# 2. For some of the "/" synonyms, the error diagnostic slightly differs from
+# that of the basic "/" case (see gnulib's fts_open' and ROOT_DEV_INO_WARN):
+# rm: it is dangerous to operate recursively on 'FILE' (same as '/')
+# Strip that part off for the following comparison.
+clean_rm_err_()
+{
+ sed "s/.*rm: /rm: /; \
+ s/\(rm: it is dangerous to operate recursively on\).*$/\1 '\/'/"
+}
+
+#-------------------------------------------------------------------------------
+# exercise_rm_r_root: shell function to test "rm -r '/'"
+# The caller must provide the FILE to remove as well as any options
+# which should be passed to 'rm'.
+# Paranoia mode on:
+# For the worst case where both rm(1) would fail to refuse to process the "/"
+# argument (in the cases without the --no-preserve-root option), and
+# intercepting the unlinkat(1) system call would fail (which actually already
+# has been proven to work above), and the current non root user has
+# write access to "/", limit the damage to the current file system via
+# the --one-file-system option.
+# Furthermore, run rm(1) via gdb that limits the number of unlinkat() calls.
+exercise_rm_r_root ()
+{
+ # Remove the evidence files; verify that.
+ rm -f x excise.break || framework_failure_
+ test -f x && framework_failure_
+ test -f excise.break && framework_failure_
+
+ local skip_exit=
+ if [ "$CU_TEST_SKIP_EXIT" = 1 ]; then
+ # Pass on this variable into 'rm's environment.
+ skip_exit='CU_TEST_SKIP_EXIT=1'
+ fi
+
+ if test $USE_GDB = 1; then
+ gdb -nx --batch-silent -return-child-result \
+ --eval-command="set exec-wrapper \
+ env 'LD_PRELOAD=$LD_PRELOAD:./k.so' $skip_exit" \
+ --eval-command="break '$break_line'" \
+ --eval-command='source bp.py' \
+ --eval-command="run -rv --one-file-system $*" \
+ --eval-command='quit' \
+ rm < /dev/null > out 2> err.t
+ else
+ touch excise.break
+ env LD_PRELOAD=$LD_PRELOAD:./k.so $skip_exit \
+ rm -rv --one-file-system $* < /dev/null > out 2> err.t
+ fi
+
+ ret=$?
+
+ clean_rm_err_ < err.t > err || ret=$?
+
+ return $ret
+}
+
+# Verify that "rm -r dir" basically works.
+mkdir dir || framework_failure_
+rm -r dir || framework_failure_
+test -d dir && framework_failure_
+
+# Now verify that intercepting unlinkat() works:
+# rm(1) must succeed as before, but this time both the evidence file "x"
+# and the test file / directory must still exist afterward.
+mkdir dir || framework_failure_
+> file || framework_failure_
+
+skip=
+for file in dir file ; do
+ exercise_rm_r_root "$file" || skip=1
+ test -e "$file" || skip=1
+ test -f x || skip=1
+ test -f excise.break || skip=1 # gdb works and breakpoint hit
+ compare /dev/null err || skip=1
+
+ test "$skip" = 1 \
+ && { cat out; cat err; \
+ skip_ "internal test failure: maybe LD_PRELOAD or gdb doesn't work?"; }
+done
+
+# "rm -r /" without --no-preserve-root should output the following
+# diagnostic error message.
+cat <<EOD > exp || framework_failure_
+rm: it is dangerous to operate recursively on '/'
+rm: use --no-preserve-root to override this failsafe
+EOD
+
+#-------------------------------------------------------------------------------
+# Exercise "rm -r /" without and with the --preserve-root option.
+# Exercise various synonyms of "/" including symlinks to it.
+# Expect a non-Zero exit status.
+# Prepare a few symlinks to "/".
+ln -s / rootlink || framework_failure_
+ln -s rootlink rootlink2 || framework_failure_
+ln -sr / rootlink3 || framework_failure_
+
+for opts in \
+ '/' \
+ '--preserve-root /' \
+ '//' \
+ '///' \
+ '////' \
+ 'rootlink/' \
+ 'rootlink2/' \
+ 'rootlink3/' ; do
+
+ returns_ 1 exercise_rm_r_root $opts || fail=1
+
+ # Expect nothing in 'out' and the above error diagnostic in 'err'.
+ # As rm(1) should have skipped the "/" argument, it does not call unlinkat().
+ # Therefore, the evidence file "x" should not exist.
+ compare /dev/null out || fail=1
+ compare exp err || fail=1
+ test -f x && fail=1
+
+ # Do nothing more if this test failed.
+ test $fail = 1 && { cat out; cat err; Exit $fail; }
+done
+
+#-------------------------------------------------------------------------------
+# Exercise with --no-preserve to ensure shortened equivalent is not allowed.
+cat <<EOD > exp_opt || framework_failure_
+rm: you may not abbreviate the --no-preserve-root option
+EOD
+returns_ 1 exercise_rm_r_root --no-preserve / || fail=1
+compare exp_opt err || fail=1
+test -f x && fail=1
+
+#-------------------------------------------------------------------------------
+# Exercise "rm -r file1 / file2".
+# Expect a non-Zero exit status representing failure to remove "/",
+# yet 'file1' and 'file2' should be removed.
+> file1 || framework_failure_
+> file2 || framework_failure_
+
+# Now that we know that 'rm' won't call the unlinkat() system function for "/",
+# we could probably execute it without the LD_PRELOAD'ed safety net.
+# Nevertheless, it's still better to use it for this test.
+# Tell the unlinkat() replacement function to not _exit(0) immediately
+# by setting the following variable.
+CU_TEST_SKIP_EXIT=1
+
+returns_ 1 exercise_rm_r_root --preserve-root file1 '/' file2 || fail=1
+
+unset CU_TEST_SKIP_EXIT
+
+cat <<EOD > out_removed
+removed 'file1'
+removed 'file2'
+EOD
+
+# The above error diagnostic should appear in 'err'.
+# Both 'file1' and 'file2' should be removed. Simply verify that in the
+# "out" file, as the replacement unlinkat() dummy did not remove them.
+# Expect the evidence file "x" to exist.
+compare out_removed out || fail=1
+compare exp err || fail=1
+test -f x || fail=1
+
+# Do nothing more if this test failed.
+test $fail = 1 && { cat out; cat err; Exit $fail; }
+
+#-------------------------------------------------------------------------------
+# Exercise various synonyms of "/" having a trailing "." or ".." in the name.
+# This triggers another check in the code first and therefore leads to a
+# different diagnostic. However, we want to test anyway to protect against
+# future reordering of the checks in the code.
+# Expect that other error diagnostic in 'err' and nothing in 'out'.
+# Expect a non-Zero exit status. The evidence file "x" should not exist.
+for file in \
+ '//.' \
+ '/./' \
+ '/.//' \
+ '/../' \
+ '/.././' \
+ '/etc/..' \
+ 'rootlink/..' \
+ 'rootlink2/.' \
+ 'rootlink3/./' ; do
+
+ test -d "$file" || continue # if e.g. /etc does not exist.
+
+ returns_ 1 exercise_rm_r_root --preserve-root "$file" || fail=1
+
+ grep "rm: refusing to remove '\.' or '\.\.' directory: skipping" err \
+ || fail=1
+
+ compare /dev/null out || fail=1
+ test -f x && fail=1
+
+ # Do nothing more if this test failed.
+ test $fail = 1 && { cat out; cat err; Exit $fail; }
+done
+
+#-------------------------------------------------------------------------------
+# Until now, it was all just fun.
+# Now exercise the --no-preserve-root option with which rm(1) should enter
+# the intercepted unlinkat() system call.
+# As the interception code terminates the process immediately via _exit(0),
+# the exit status should be 0.
+# Use the option --interactive=never to bypass the following prompt:
+# "rm: descend into write-protected directory '/'?"
+exercise_rm_r_root --interactive=never --no-preserve-root '/' \
+ || fail=1
+
+# The 'err' file should not contain the above error diagnostic.
+grep "rm: it is dangerous to operate recursively on '/'" err && fail=1
+
+# Instead, rm(1) should have called the intercepted unlinkat() function,
+# i.e., the evidence file "x" should exist.
+test -f x || fail=1
+
+test $fail = 1 && { cat out; cat err; }
+
+Exit $fail
diff --git a/tests/rm/read-only.sh b/tests/rm/read-only.sh
new file mode 100755
index 0000000..9598dfc
--- /dev/null
+++ b/tests/rm/read-only.sh
@@ -0,0 +1,52 @@
+#!/bin/sh
+# Ensure that rm -f nonexistent-file-on-read-only-fs succeeds.
+
+# Copyright (C) 2009-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ rm
+require_root_
+
+cwd=$(pwd)
+cleanup_() { cd /; umount "$cwd/mnt"; }
+
+skip=0
+# Create a file system, then mount it.
+dd if=/dev/zero of=blob bs=8192 count=200 > /dev/null 2>&1 \
+ || skip=1
+mkdir mnt || skip=1
+mkfs -t ext2 -F blob \
+ || skip_ "failed to create ext2 file system"
+
+mount -oloop blob mnt || skip=1
+echo test > mnt/f || skip=1
+test -s mnt/f || skip=1
+mount -o remount,loop,ro mnt || skip=1
+
+test $skip = 1 \
+ && skip_ "insufficient mount/ext2 support"
+
+# Applying rm -f to a nonexistent file on a read-only file system must succeed.
+rm -f mnt/no-such > out 2>&1 || fail=1
+# It must produce no diagnostic.
+compare /dev/null out || fail=1
+
+# However, trying to remove an existing file must fail.
+rm -f mnt/f > out 2>&1 && fail=1
+# with a diagnostic.
+compare /dev/null out && fail=1
+
+Exit $fail
diff --git a/tests/rm/readdir-bug.sh b/tests/rm/readdir-bug.sh
new file mode 100755
index 0000000..6d07180
--- /dev/null
+++ b/tests/rm/readdir-bug.sh
@@ -0,0 +1,41 @@
+#!/bin/sh
+# Exercise the Darwin/MacOS bug worked around on 2006-09-29,
+# whereby rm would fail to remove all entries in a directory.
+
+# Copyright (C) 2006-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ rm
+
+# Create a directory containing many files.
+# What counts is a combination of the number of files and
+# the lengths of their names. For details, see
+# https://lists.gnu.org/r/bug-coreutils/2006-09/msg00326.html
+mkdir b || framework_failure_
+cd b || framework_failure_
+for i in $(seq 1 250); do
+ touch $(printf %040d $i) || framework_failure_
+done
+cd .. || framework_failure_
+
+
+# On a buggy system, this would fail with the diagnostic,
+# "cannot remove directory 'b': Directory not empty"
+rm -rf b || fail=1
+
+test -d b && fail=1
+
+Exit $fail
diff --git a/tests/rm/rm-readdir-fail.sh b/tests/rm/rm-readdir-fail.sh
new file mode 100755
index 0000000..e68f2a5
--- /dev/null
+++ b/tests/rm/rm-readdir-fail.sh
@@ -0,0 +1,121 @@
+#!/bin/sh
+# Test rm's behavior when the directory cannot be read.
+# This test is skipped on systems that lack LD_PRELOAD support.
+
+# Copyright (C) 2016-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ rm
+require_gcc_shared_
+
+mkdir -p dir/notempty || framework_failure_
+
+# Simulate "readdir" failure.
+cat > k.c <<\EOF || framework_failure_
+#define _GNU_SOURCE
+
+/* Setup so we don't have to worry about readdir64. */
+#ifndef __LP64__
+# define _FILE_OFFSET_BITS 64
+#endif
+
+#include <dlfcn.h>
+#include <dirent.h>
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+struct dirent *readdir (DIR *dirp)
+{
+ static int count = 1;
+
+#ifndef __LP64__
+ if (count == 1)
+ fclose (fopen ("32bit", "w"));
+ errno = ENOSYS;
+ return NULL;
+#endif
+
+ static struct dirent *(*real_readdir)(DIR *dirp);
+ if (! real_readdir && ! (real_readdir = dlsym (RTLD_NEXT, "readdir")))
+ {
+ fprintf (stderr, "Failed to find readdir()\n");
+ errno = ESRCH;
+ return NULL;
+ }
+ struct dirent* d;
+ if (! (d = real_readdir (dirp)))
+ {
+ fprintf (stderr, "Failed to get dirent\n");
+ errno = ENOENT;
+ return NULL;
+ }
+
+ /* Flag that LD_PRELOAD and above functions work. */
+ if (count == 1)
+ fclose (fopen ("preloaded", "w"));
+
+ /* Return some entries to trigger partial read failure,
+ ensuring we don't return ignored '.' or '..' */
+ char const *readdir_partial = getenv ("READDIR_PARTIAL");
+ if (readdir_partial && *readdir_partial && count <= 3)
+ {
+ count++;
+ d->d_name[0]='0'+count; d->d_name[1]='\0';
+#ifdef _DIRENT_HAVE_D_NAMLEN
+ d->d_namlen = 1;
+#endif
+ errno = 0;
+ return d;
+ };
+
+ /* Fail. */
+ errno = ENOENT;
+ return NULL;
+}
+EOF
+
+# Then compile/link it:
+gcc_shared_ k.c k.so \
+ || framework_failure_ 'failed to build shared library'
+
+# Test if LD_PRELOAD works:
+export READDIR_PARTIAL
+for READDIR_PARTIAL in '' '1'; do
+ rm -f preloaded
+ (export LD_PRELOAD=$LD_PRELOAD:./k.so
+ returns_ 1 rm -Rf dir 2>>errt) || fail=1
+ if test -f 32bit; then
+ skip_ 'This test only supports 64 bit systems'
+ elif ! test -f preloaded; then
+ cat errt
+ skip_ "internal test failure: maybe LD_PRELOAD doesn't work?"
+ fi
+done
+
+# First case is failure to read any items from dir, then assume empty.
+# Generally that will be diagnosed when rm tries to rmdir().
+# Second case is more general error where we fail immediately
+# (with ENOENT in this case but it could be anything).
+cat <<EOF > exp
+rm: cannot remove 'dir'
+Failed to get dirent
+rm: traversal failed: dir
+EOF
+sed 's/\(rm:.*\):.*/\1/' errt > err || framework_failure_
+compare exp err || fail=1
+
+Exit $fail
diff --git a/tests/rm/rm1.sh b/tests/rm/rm1.sh
new file mode 100755
index 0000000..ba231a3
--- /dev/null
+++ b/tests/rm/rm1.sh
@@ -0,0 +1,48 @@
+#!/bin/sh
+# exercise another small part of remove.c
+
+# Copyright (C) 2002-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ rm
+skip_if_root_
+
+mkdir -p b/a/p b/c b/d || framework_failure_
+chmod ug-w b/a || framework_failure_
+
+
+# This should fail.
+rm -rf b > out 2>&1 && fail=1
+cat <<\EOF > exp
+rm: cannot remove directory 'b/a/p': Permission denied
+EOF
+
+# On some systems, rm doesn't have enough information to
+# say it's a directory.
+cat <<\EOF > exp2
+rm: cannot remove 'b/a/p': Permission denied
+EOF
+
+cmp out exp > /dev/null 2>&1 || {
+ cmp out exp2 || fail=1
+ }
+test $fail = 1 && compare exp out
+
+test -d b/a/p || fail=1
+test -d b/c && fail=1
+test -d b/d && fail=1
+
+Exit $fail
diff --git a/tests/rm/rm2.sh b/tests/rm/rm2.sh
new file mode 100755
index 0000000..dc19b9c
--- /dev/null
+++ b/tests/rm/rm2.sh
@@ -0,0 +1,55 @@
+#!/bin/sh
+# exercise another small part of remove.c
+
+# Copyright (C) 2002-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ rm
+skip_if_root_
+
+mkdir -p a/0 || framework_failure_
+mkdir -p a/1/2 b/3 || framework_failure_
+mkdir a/2 a/3 || framework_failure_
+chmod u-x a/1 b || framework_failure_
+
+
+# Exercise two separate code paths -- though both result
+# in the same sort of diagnostic.
+# Both of these should fail.
+rm -rf a b > out 2>&1 && fail=1
+cat <<\EOF > exp
+rm: cannot remove 'a/1': Permission denied
+rm: cannot remove 'b': Permission denied
+EOF
+
+cat <<\EOF > exp-solaris
+rm: cannot remove 'a/1/2': Permission denied
+rm: cannot remove 'b/3': Permission denied
+EOF
+
+cmp out exp > /dev/null 2>&1 \
+ || { cmp out exp-solaris > /dev/null 2>&1 || fail=1; }
+test $fail = 1 && compare exp out
+
+test -d a/0 && fail=1
+test -d a/1 || fail=1
+test -d a/2 && fail=1
+test -d a/3 && fail=1
+
+chmod u+x b
+test -d b/3 || fail=1
+
+Exit $fail
diff --git a/tests/rm/rm3.sh b/tests/rm/rm3.sh
new file mode 100755
index 0000000..555c92e
--- /dev/null
+++ b/tests/rm/rm3.sh
@@ -0,0 +1,73 @@
+#!/bin/sh
+# exercise another small part of remove.c
+
+# Copyright (C) 2002-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ rm
+skip_if_root_
+
+mkdir -p z || framework_failure_
+cd z || framework_failure_
+touch empty empty-u || framework_failure_
+echo not-empty > fu
+ln -s empty-f slink
+ln -s . slinkdot
+mkdir d du || framework_failure_
+chmod u-w fu du empty-u || framework_failure_
+cd ..
+
+
+cat <<EOF > in || framework_failure_
+y
+y
+y
+y
+y
+y
+y
+y
+y
+EOF
+
+# Both of these should fail.
+rm -ir z < in > out 2>&1 || fail=1
+
+# Given input like 'rm: ...? rm: ...? ' (no trailing newline),
+# the 'head...' part of the pipeline below removes the trailing space, so
+# that sed doesn't have to deal with a line lacking a terminating newline.
+# This avoids a bug whereby some vendor-provided (Tru64) versions of sed
+# would mistakenly tack a newline onto the end of the output.
+tr '?' '\n' < out | head --bytes=-1 | sed 's/^ //' |sort > o2
+mv o2 out || framework_failure_
+
+sort <<EOF > exp || framework_failure_
+rm: descend into directory 'z'
+rm: remove regular empty file 'z/empty'
+rm: remove write-protected regular file 'z/fu'
+rm: remove write-protected regular empty file 'z/empty-u'
+rm: remove symbolic link 'z/slink'
+rm: remove symbolic link 'z/slinkdot'
+rm: remove directory 'z/d'
+rm: remove write-protected directory 'z/du'
+rm: remove directory 'z'
+EOF
+
+compare exp out || fail=1
+
+test -d z && fail=1
+
+Exit $fail
diff --git a/tests/rm/rm4.sh b/tests/rm/rm4.sh
new file mode 100755
index 0000000..782453c
--- /dev/null
+++ b/tests/rm/rm4.sh
@@ -0,0 +1,31 @@
+#!/bin/sh
+# ensure that 'rm dir' fails without --recursive
+
+# Copyright (C) 2002-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ rm
+skip_if_root_
+
+mkdir dir || framework_failure_
+
+
+# This should fail.
+returns_ 1 rm dir > /dev/null 2>&1 || fail=1
+
+test -d dir || fail=1
+
+Exit $fail
diff --git a/tests/rm/rm5.sh b/tests/rm/rm5.sh
new file mode 100755
index 0000000..2f6cb3f
--- /dev/null
+++ b/tests/rm/rm5.sh
@@ -0,0 +1,52 @@
+#!/bin/sh
+# a basic test of rm -ri
+
+# Copyright (C) 2002-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ rm
+skip_if_root_
+
+mkdir -p d/e || framework_failure_
+cat <<EOF > in || framework_failure_
+y
+y
+y
+EOF
+
+cat <<\EOF > exp || framework_failure_
+rm: descend into directory 'd'
+rm: remove directory 'd/e'
+rm: remove directory 'd'
+EOF
+
+
+rm -ir d < in > out 2>&1 || fail=1
+
+# Given input like 'rm: ...? rm: ...? ' (no trailing newline),
+# the 'head...' part of the pipeline below removes the trailing space, so
+# that sed doesn't have to deal with a line lacking a terminating newline.
+# This avoids a bug whereby some vendor-provided (Tru64) versions of sed
+# would mistakenly tack a newline onto the end of the output.
+tr '?' '\n' < out | head --bytes=-1 | sed 's/^ //' > o2
+mv o2 out
+
+# Make sure it's been removed.
+test -d d && fail=1
+
+compare exp out || fail=1
+
+Exit $fail
diff --git a/tests/rm/sunos-1.sh b/tests/rm/sunos-1.sh
new file mode 100755
index 0000000..96fd0db
--- /dev/null
+++ b/tests/rm/sunos-1.sh
@@ -0,0 +1,29 @@
+#!/bin/sh
+# Make sure that rm -r '' fails.
+
+# Copyright (C) 1997-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+
+# On SunOS 4.1.3, running rm -r '' in a nonempty directory may
+# actually remove files with names of entries in the current directory
+# but relative to '/' rather than relative to the current directory.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ rm
+
+returns_ 1 rm -r '' > /dev/null 2>&1 || fail=1
+
+Exit $fail
diff --git a/tests/rm/unread2.sh b/tests/rm/unread2.sh
new file mode 100755
index 0000000..7b59849
--- /dev/null
+++ b/tests/rm/unread2.sh
@@ -0,0 +1,35 @@
+#!/bin/sh
+# exercise one small part of remove.c
+
+# Copyright (C) 2002-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ rm
+skip_if_root_
+
+mkdir -p a/b || framework_failure_
+chmod u-r a
+
+
+# This should fail.
+rm -rf a > out 2>&1 && fail=1
+cat <<\EOF > exp
+rm: cannot remove 'a': Permission denied
+EOF
+
+compare exp out || fail=1
+
+Exit $fail
diff --git a/tests/rm/unread3.sh b/tests/rm/unread3.sh
new file mode 100755
index 0000000..5c7edbd
--- /dev/null
+++ b/tests/rm/unread3.sh
@@ -0,0 +1,43 @@
+#!/bin/sh
+# Ensure that rm works even from an unreadable working directory.
+
+# Copyright (C) 2004-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ rm
+skip_if_root_
+
+mkdir -p a/1 b c d/2 e/3 || framework_failure_
+
+
+t=$(pwd)
+cd c
+chmod u=x,go= .
+
+# With coreutils-5.2.1, this would get a failed assertion.
+rm -r "$t/a" "$t/b" || fail=1
+
+# With coreutils-5.2.1, this would get the following:
+# rm: cannot get current directory: Permission denied
+# rm: failed to return to initial working directory: Bad file descriptor
+rm -r "$t/d" "$t/e" || fail=1
+
+test -d "$t/a" && fail=1
+test -d "$t/b" && fail=1
+test -d "$t/d" && fail=1
+test -d "$t/e" && fail=1
+
+Exit $fail
diff --git a/tests/rm/unreadable.pl b/tests/rm/unreadable.pl
new file mode 100755
index 0000000..57a7c2c
--- /dev/null
+++ b/tests/rm/unreadable.pl
@@ -0,0 +1,50 @@
+#!/usr/bin/perl
+# Test "rm" and unreadable directories.
+
+# Copyright (C) 1998-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+use strict;
+
+(my $program_name = $0) =~ s|.*/||;
+
+# Turn off localization of executable's output.
+@ENV{qw(LANGUAGE LANG LC_ALL)} = ('C') x 3;
+
+my $d = "dir-$$";
+my $mkdir = {PRE => sub {mkdir $d,0100 or die "$d: $!\n"}};
+my $prog = 'rm';
+my $uid = $<;
+
+my @Tests =
+ (
+ # test-name options input expected-output
+ #
+ # Removing an empty, unwritable directory succeeds.
+ ['unreadable-1', '-rf', $d, {EXIT => 0}, $mkdir],
+
+ ['unreadable-2', '-rf', $d,
+ {EXIT => $uid == 0 ? 0 : 1},
+ {ERR => $uid == 0 ? ''
+ : "$prog: cannot remove '$d': Permission denied\n"},
+ {PRE => sub { (mkdir $d,0700 and mkdir "$d/x",0700 and chmod 0100,$d)
+ or die "$d: $!\n"}} ],
+ );
+
+my $save_temps = $ENV{SAVE_TEMPS};
+my $verbose = $ENV{VERBOSE};
+
+my $fail = run_tests ($program_name, $prog, \@Tests, $save_temps, $verbose);
+exit $fail;
diff --git a/tests/rm/v-slash.sh b/tests/rm/v-slash.sh
new file mode 100755
index 0000000..c590f4e
--- /dev/null
+++ b/tests/rm/v-slash.sh
@@ -0,0 +1,34 @@
+#!/bin/sh
+# avoid extra slashes in --verbose output
+
+# Copyright (C) 2007-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ rm
+
+mkdir a || framework_failure_
+touch a/x || framework_failure_
+
+
+rm --verbose -r a/// > out || fail=1
+cat <<\EOF > exp || framework_failure_
+removed 'a/x'
+removed directory 'a/'
+EOF
+
+compare exp out || fail=1
+
+Exit $fail
diff --git a/tests/rmdir/fail-perm.sh b/tests/rmdir/fail-perm.sh
new file mode 100755
index 0000000..8257499
--- /dev/null
+++ b/tests/rmdir/fail-perm.sh
@@ -0,0 +1,32 @@
+#!/bin/sh
+# For unwritable directory 'd', 'rmdir -p d d/e/f' would emit
+# diagnostics but would not fail. Fixed in 5.1.2.
+
+# Copyright (C) 2004-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ rmdir
+
+mkdir d d/e d/e/f || framework_failure_
+chmod a-w d || framework_failure_
+
+
+# This rmdir command outputs two diagnostics.
+# Before coreutils-5.1.2, it would mistakenly exit successfully.
+# As of coreutils-5.1.2, it fails, as required.
+returns_ 1 rmdir -p d d/e/f 2> /dev/null || fail=1
+
+Exit $fail
diff --git a/tests/rmdir/ignore.sh b/tests/rmdir/ignore.sh
new file mode 100755
index 0000000..c0a00ee
--- /dev/null
+++ b/tests/rmdir/ignore.sh
@@ -0,0 +1,56 @@
+#!/bin/sh
+# make sure rmdir's --ignore-fail-on-non-empty option works
+
+# Copyright (C) 1999-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ rmdir
+
+cwd=$(pwd)
+mkdir -p "$cwd/a/b/c" "$cwd/a/x" || framework_failure_
+
+rmdir -p --ignore-fail-on-non-empty "$cwd/a/b/c" || fail=1
+# $cwd/a/x should remain
+test -d "$cwd/a/x" || fail=1
+# $cwd/a/b and $cwd/a/b/c should be gone
+test -d "$cwd/a/b" && fail=1
+test -d "$cwd/a/b/c" && fail=1
+
+# Ensure that with --ignore-fail-on-non-empty, we still fail, e.g., for EPERM.
+# Between 6.11 and 8.31, the following rmdir would mistakenly succeed.
+mkdir -p x/y || framework_failure_
+chmod a-w x || framework_failure_
+
+if ! uid_is_privileged_; then # root does not get EPERM.
+ returns_ 1 rmdir --ignore-fail-on-non-empty x/y || fail=1
+fi
+
+test -d x/y || fail=1
+# Between 6.11 and 8.31, the following rmdir would mistakenly fail,
+# and also give a nondescript error
+touch x/y/z || framework_failure_
+rmdir --ignore-fail-on-non-empty x/y || fail=1
+test -d x/y || fail=1
+
+if ! uid_is_privileged_; then # root does not get EPERM.
+ # assume empty dir if unreadable entries (so failure to remove diagnosed)
+ rm x/y/z || framework_failure_
+ chmod a-r x/y || framework_failure_
+ returns_ 1 rmdir --ignore-fail-on-non-empty x/y || fail=1
+ test -d x/y || fail=1
+fi
+
+Exit $fail
diff --git a/tests/rmdir/symlink-errors.sh b/tests/rmdir/symlink-errors.sh
new file mode 100755
index 0000000..969c80c
--- /dev/null
+++ b/tests/rmdir/symlink-errors.sh
@@ -0,0 +1,66 @@
+#!/bin/sh
+# make sure rmdir outputs clear errors in the presence of symlinks
+
+# Copyright (C) 2021-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ rmdir
+
+mkdir dir || framework_failure_
+ln -s dir sl || framework_failure_
+ln -s missing dl || framework_failure_
+touch file || framework_failure_
+ln -s file fl || framework_failure_
+
+# Ensure a we maintain ENOTDIR so that we provide
+# accurate errors on systems on which rmdir(2) does following the symlink/
+returns_ 1 rmdir fl/ 2> err || fail=1
+# Ensure we diagnose symlink behavior.
+printf '%s\n' "rmdir: failed to remove 'fl/': Not a directory" > exp
+compare exp err || fail=1
+
+# Also ensure accurate errors from rmdir -p when traversing symlinks
+# Up to and including 8.32 rmdir would fail like:
+# rmdir: failed to remove directory 'sl': Not a directory
+mkdir dir/dir2 || framework_failure_
+returns_ 1 rmdir -p sl/dir2 2> err || fail=1
+# Ensure we diagnose symlink behavior.
+printf '%s\n' "rmdir: failed to remove 'sl': Not a directory" > exp
+compare exp err || fail=1
+
+# Only perform the following on systems that don't follow the symlink
+if ! rmdir sl/ 2>/dev/null; then
+ # Up to and including 8.32 rmdir would fail like:
+ # rmdir: failed to remove 'sl/': Not a directory
+ # That's inconsistent though as rm sl/ gives:
+ # rm: cannot remove 'sl/': Is a directory
+ # Also this is inconsistent with other systems
+ # which do follow the symlink and rmdir the target.
+
+ new_error="rmdir: failed to remove '%s': Symbolic link not followed\\n"
+
+ # Ensure we diagnose symlink behavior.
+ returns_ 1 rmdir sl/ 2> err || fail=1
+ printf "$new_error" 'sl/' > exp || framework_failure_
+ compare exp err || fail=1
+
+ # Ensure a consistent diagnosis for dangling symlinks etc.
+ returns_ 1 rmdir dl/ 2> err || fail=1
+ printf "$new_error" 'dl/' > exp || framework_failure_
+ compare exp err || fail=1
+fi
+
+Exit $fail
diff --git a/tests/rmdir/t-slash.sh b/tests/rmdir/t-slash.sh
new file mode 100755
index 0000000..d78e75b
--- /dev/null
+++ b/tests/rmdir/t-slash.sh
@@ -0,0 +1,29 @@
+#!/bin/sh
+# make sure rmdir -p works on a directory specified with a trailing slash
+
+# Copyright (C) 2002-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ rmdir
+
+mkdir dir || framework_failure_
+
+
+# Prior to coreutils-4.5.2, this would fail with the following:
+# rmdir: 'dir': No such file or directory
+rmdir -p dir/ || fail=1
+
+Exit $fail
diff --git a/tests/runcon/runcon-compute.sh b/tests/runcon/runcon-compute.sh
new file mode 100755
index 0000000..bc3cd8c
--- /dev/null
+++ b/tests/runcon/runcon-compute.sh
@@ -0,0 +1,30 @@
+#!/bin/sh
+# Ensure that runcon -c uses absolute file names
+
+# Copyright (C) 2022-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ runcon
+
+# Create an executable that's sure to fail
+printf '%s\n' '#!/bin/sh' 'exit 1' >> 'true' || framework_failure_
+chmod a+x 'true' || framework_failure_
+
+runcon -c true; ret=$?
+test "$ret" = 125 && skip_ 'runcon setup failed'
+test "$ret" = 1 || fail=1
+
+Exit $fail
diff --git a/tests/runcon/runcon-no-reorder.sh b/tests/runcon/runcon-no-reorder.sh
new file mode 100755
index 0000000..f07a4e5
--- /dev/null
+++ b/tests/runcon/runcon-no-reorder.sh
@@ -0,0 +1,44 @@
+#!/bin/sh
+# Ensure that runcon does not reorder its arguments.
+
+# Copyright (C) 2007-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ runcon
+
+diag='runcon: runcon may be used only on a SELinux kernel'
+echo "$diag" > exp || framework_failure_
+
+
+# This test works even on systems without SELinux.
+# On such a system it fails with the above diagnostic, which is fine.
+# Before the no-reorder change, it would have failed with a diagnostic
+# about -j being an invalid option.
+runcon $(id -Z) true -j 2> out && > exp
+# Ensure we fail appropriately for invalid options
+returns_ 125 runcon -j true || fail=1
+
+# When run on a system with no /selinux/context (i.e., in a chroot),
+# it fails with this: "runcon: invalid context: \
+# root:system_r:unconfined_t:s0-s0:c0.c1023: No such file or directory"
+# That diagnostic is ok, too, so map it to the more common one.
+case $(cat out) in
+ 'runcon: invalid context: '*) echo "$diag" > out;;
+esac
+
+compare exp out || fail=1
+
+Exit $fail
diff --git a/tests/sample-test b/tests/sample-test
new file mode 100644
index 0000000..ab44eb8
--- /dev/null
+++ b/tests/sample-test
@@ -0,0 +1,36 @@
+#!/bin/sh
+# FIXME
+
+# Copyright (C) 2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ FIXME
+
+# FIXME: skip_if_root_
+# FIXME: require_root_
+
+# If used, these must *follow* init.sh.
+# FIXME: cleanup_() { rm -rf "$other_partition_tmpdir"; }
+# FIXME: . "$abs_srcdir/tests/other-fs-tmpdir"
+
+FIXME > out || fail=1
+cat <<\EOF > exp || framework_failure_
+FIXME
+EOF
+
+compare exp out || fail=1
+
+Exit $fail
diff --git a/tests/seek-data-capable b/tests/seek-data-capable
new file mode 100644
index 0000000..cc63722
--- /dev/null
+++ b/tests/seek-data-capable
@@ -0,0 +1,33 @@
+import sys, os, errno, platform
+
+# Pass an _empty_ file
+if len(sys.argv) != 2:
+ sys.exit(1)
+
+if not hasattr(os, 'SEEK_DATA'):
+ # Not available on python 2, or on darwin python 3
+ # Also Darwin swaps SEEK_DATA/SEEK_HOLE definitions
+ if platform.system() == "Darwin":
+ SEEK_DATA = 4
+ else:
+ SEEK_DATA = 3 # Valid on Linux, FreeBSD, Solaris
+else:
+ SEEK_DATA = os.SEEK_DATA
+
+# Even if os supports SEEK_DATA or SEEK_HOLE,
+# the file system may not, in which case it would report
+# current and eof positions respectively.
+# Therefore work with an empty file,
+# ensuring SEEK_DATA returns ENXIO (no more data)
+try:
+ fd = os.open(sys.argv[1], os.O_RDONLY)
+except:
+ sys.exit(1)
+
+try:
+ data = os.lseek(fd, 0, SEEK_DATA)
+except OSError as e:
+ if e.errno == errno.ENXIO:
+ sys.exit(0)
+
+sys.exit(1)
diff --git a/tests/seq/seq-epipe.sh b/tests/seq/seq-epipe.sh
new file mode 100755
index 0000000..32e4a3a
--- /dev/null
+++ b/tests/seq/seq-epipe.sh
@@ -0,0 +1,42 @@
+#!/bin/sh
+# Test for proper detection of EPIPE with ignored SIGPIPE
+
+# Copyright (C) 2016-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ seq
+trap_sigpipe_or_skip_
+
+# /bin/sh has an intermittent failure in ignoring SIGPIPE on OpenIndiana 11
+# so we require bash as discussed at:
+# https://lists.gnu.org/archive/html/coreutils/2020-03/msg00004.html
+require_bash_as_SHELL_
+
+# upon EPIPE with signals ignored, 'seq' should exit with an error.
+timeout 10 $SHELL -c \
+ 'trap "" PIPE && { seq inf 2>err; echo $? >code; } | head -n1' >out
+
+# Exit-code must be 1, indicating 'write error'
+echo 1 > exp || framework_failure_
+compare exp out || fail=1
+compare exp code || fail=1
+
+grep '^seq: write error: ' err \
+ || { warn_ "seq emitted incorrect error on EPIPE"; \
+ cat err;\
+ fail=1; }
+
+Exit $fail
diff --git a/tests/seq/seq-extra-number.sh b/tests/seq/seq-extra-number.sh
new file mode 100755
index 0000000..0fe70a7
--- /dev/null
+++ b/tests/seq/seq-extra-number.sh
@@ -0,0 +1,47 @@
+#!/bin/sh
+# Test the "print_extra_number" logic seq.c:print_numbers()
+
+# Copyright (C) 2019-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ seq
+
+##
+## Test 1: the documented reason for the logic
+##
+cat<<'EOF'>exp1 || framework_failure_
+0.000000
+0.000001
+0.000002
+0.000003
+EOF
+
+seq 0 0.000001 0.000003 > out1 || fail=1
+compare exp1 out1 || fail=1
+
+
+##
+## Test 2: before 8.32, this resulted in TWO lines
+## (print_extra_number was erroneously set to true)
+## The '=' is there instead of a space to ease visual inspection.
+cat<<'EOF'>exp2 || framework_failure_
+1e+06=
+EOF
+
+seq -f "%g=" 1000000 1000000 > out2 || fail=1
+compare exp2 out2 || fail=1
+
+Exit $fail
diff --git a/tests/seq/seq-io-errors.sh b/tests/seq/seq-io-errors.sh
new file mode 100755
index 0000000..08bea76
--- /dev/null
+++ b/tests/seq/seq-io-errors.sh
@@ -0,0 +1,46 @@
+#!/bin/sh
+# Test for proper detection of I/O errors in seq
+
+# Copyright (C) 2016-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ seq
+
+if ! test -w /dev/full || ! test -c /dev/full; then
+ skip_ '/dev/full is required'
+fi
+
+# Run 'seq' with a timeout, preventing infinite-loop run.
+# expected returned codes:
+# 1 - seq detected an I/O error and exited with an error.
+# 124 - timed-out (seq likely infloop)
+# other - unexpected error
+timed_seq_fail() { timeout 10 seq "$@" >/dev/full 2>/dev/null; }
+
+
+# Test infinite sequence, using fast-path method (seq_fast).
+returns_ 1 timed_seq_fail 1 inf || fail=1
+
+# Test infinite sequence, using slow-path method (print_numbers).
+returns_ 1 timed_seq_fail 1.1 .1 inf || fail=1
+
+# Test non-infinite sequence, using slow-path method (print_numbers).
+# (despite being non-infinite, the entire sequence should take long time to
+# print. Thus, either an I/O error is detected immediately, or seq will
+# timeout).
+returns_ 1 timed_seq_fail 1 0.0001 99999999 || fail=1
+
+Exit $fail
diff --git a/tests/seq/seq-locale.sh b/tests/seq/seq-locale.sh
new file mode 100755
index 0000000..6c42271
--- /dev/null
+++ b/tests/seq/seq-locale.sh
@@ -0,0 +1,28 @@
+#!/bin/sh
+# Test for output with appropriate precision
+
+# Copyright (C) 2019-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ seq
+
+# With coreutils-8.30 and earlier, the last decimal point would be ','
+# when setlocale(LC_ALL, "") failed, but setlocale(LC_NUMERIC, "") succeeded.
+LC_ALL= LANG=invalid LC_NUMERIC=$LOCALE_FR_UTF8 seq 0.1 0.2 0.7 > out || fail=1
+uniq -w2 out > out-merge || framework_failure_
+test "$(wc -l < out-merge)" = 1 || { fail=1; cat out; }
+
+Exit $fail
diff --git a/tests/seq/seq-long-double.sh b/tests/seq/seq-long-double.sh
new file mode 100755
index 0000000..76b0a93
--- /dev/null
+++ b/tests/seq/seq-long-double.sh
@@ -0,0 +1,46 @@
+#!/bin/sh
+# Test for this fix: 461231f022bdb3ee392622d31dc475034adceeb2.
+# Ensure that seq prints exactly two numbers for a 2-number integral
+# range at the limit of floating point precision.
+
+# Copyright (C) 2008-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ seq
+getlimits_
+
+# Run this test only with glibc and sizeof (long double) > sizeof (double).
+# Otherwise, there are known failures.
+cat <<\EOF > long.c
+#include <features.h>
+#if defined __GNU_LIBRARY__ && __GLIBC__ >= 2
+int foo[sizeof (long double) - sizeof (double) - 1];
+#else
+"run this test only with glibc"
+#endif
+EOF
+$CC -c long.c \
+ || skip_ \
+ 'this test runs only on systems with glibc and long double != double'
+
+a=$INTMAX_MAX
+b=$INTMAX_OFLOW
+
+seq $a $b > out || fail=1
+printf "$a\n$b\n" > exp || fail=1
+compare exp out || fail=1
+
+Exit $fail
diff --git a/tests/seq/seq-precision.sh b/tests/seq/seq-precision.sh
new file mode 100755
index 0000000..25678aa
--- /dev/null
+++ b/tests/seq/seq-precision.sh
@@ -0,0 +1,85 @@
+#!/bin/sh
+# Test for output with appropriate precision
+
+# Copyright (C) 2015-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ seq
+getlimits_
+
+# Integer only. Before v8.24 these would switch output format
+
+seq 999999 inf | head -n2 > out || fail=1
+printf "%s\n" 999999 1000000 > exp || framework_failure_
+compare exp out || fail=1
+
+# Exercise buffer handling in non floating point output
+for i in $(seq 100); do
+ n1="$(printf '%*s' $i '' | tr ' ' 9)"
+ n2="1$(echo $n1 | tr 9 0)"
+
+ seq $n1 $n2 > out || fail=1
+ printf "%s\n" "$n1" "$n2" > exp || framework_failure_
+ compare exp out || fail=1
+done
+
+seq 0xF423F 0xF4240 > out || fail=1
+printf "%s\n" 999999 1000000 > exp || framework_failure_
+compare exp out || fail=1
+
+# Ensure consistent precision for inf
+seq 1 .1 inf | head -n2 > out || fail=1
+printf "%s\n" 1.0 1.1 > exp || framework_failure_
+compare exp out || fail=1
+
+# Ensure standard output methods with inf start
+seq inf inf | head -n2 | uniq > out || fail=1
+test "$(wc -l < out)" = 1 || fail=1
+
+# Ensure auto precision for hex float
+seq 1 0x1p-1 2 > out || fail=1
+printf "%s\n" 1 1.5 2 > exp || framework_failure_
+compare exp out || fail=1
+
+# Ensure consistent precision for hex
+seq 1 .1 0x2 | head -n2 > out || fail=1
+printf "%s\n" 1.0 1.1 > exp || framework_failure_
+compare exp out || fail=1
+
+# Ensure consistent handling of precision/width for exponents
+
+seq 1.1e1 12 > out || fail=1
+printf "%s\n" 11 12 > exp || framework_failure_
+compare exp out || fail=1
+
+seq 11 1.2e1 > out || fail=1
+printf "%s\n" 11 12 > exp || framework_failure_
+compare exp out || fail=1
+
+seq -w 1.1e4 | head -n1 > out || fail=1
+printf "%s\n" 00001 > exp || framework_failure_
+compare exp out || fail=1
+
+seq -w 1.10000e5 1.10000e5 > out || fail=1
+printf "%s\n" 110000 > exp || framework_failure_
+compare exp out || fail=1
+
+# Ensure no undefined behavior which failed with <= 8.32
+# This test would fail with: -fsanitize=undefined
+seq 1e$LONG_MIN 2> err || fail=1
+compare /dev/null err || fail=1
+
+Exit $fail
diff --git a/tests/seq/seq.pl b/tests/seq/seq.pl
new file mode 100755
index 0000000..e7fc8ef
--- /dev/null
+++ b/tests/seq/seq.pl
@@ -0,0 +1,202 @@
+#!/usr/bin/perl
+# Test "seq".
+
+# Copyright (C) 1999-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+use strict;
+
+(my $program_name = $0) =~ s|.*/||;
+
+# Turn off localization of executable's output.
+@ENV{qw(LANGUAGE LANG LC_ALL)} = ('C') x 3;
+
+my $prog = 'seq';
+my $try_help = "Try '$prog --help' for more information.\n";
+my $err_inc_zero = "seq: invalid Zero increment value: '0'\n".$try_help;
+my $err_nan_arg = "seq: invalid 'not-a-number' argument: 'nan'\n".$try_help;
+
+my $locale = $ENV{LOCALE_FR_UTF8};
+! defined $locale || $locale eq 'none'
+ and $locale = 'C';
+
+my $p = '9' x 81;
+(my $q = $p) =~ s/9/0/g;
+$q = "1$q";
+(my $r = $q) =~ s/0$/1/;
+
+my @Tests =
+ (
+ ['onearg-1', qw(10), {OUT => [(1..10)]}],
+ ['onearg-2', qw(-1)],
+ ['empty-rev', qw(1 -1 3)],
+ ['neg-1', qw(-10 10 10), {OUT => [qw(-10 0 10)]}],
+ # ['neg-2', qw(-.1 .1 .11), {OUT => [qw(-0.1 0.0 0.1)]}],
+ ['neg-3', qw(1 -1 0), {OUT => [qw(1 0)]}],
+ ['neg-4', qw(1 -1 -1), {OUT => [qw(1 0 -1)]}],
+
+ ['float-1', qw(0.8 0.1 0.9), {OUT => [qw(0.8 0.9)]}],
+ ['float-2', qw(0.1 0.99 1.99), {OUT => [qw(0.10 1.09)]}],
+ ['float-3', qw(10.8 0.1 10.95), {OUT => [qw(10.8 10.9)]}],
+ ['float-4', qw(0.1 -0.1 -0.2), {OUT => [qw(0.1 0.0 -0.1 -0.2)]},
+ {OUT_SUBST => 's,^-0\.0$,0.0,'},
+ ],
+ ['float-5', qw(0.8 1e-1 0.9), {OUT => [qw(0.8 0.9)]}],
+ # Don't append lots of zeros to that 0.9000...; for example, changing the
+ # number to 0.90000000000000000000 tickles a bug in Solaris 8 strtold
+ # that would cause the test to fail.
+ ['float-6', qw(0.8 0.1 0.9000000000000), {OUT => [qw(0.8 0.9)]}],
+
+ ['wid-1', qw(.8 1e-2 .81), {OUT => [qw(0.80 0.81)]}],
+ ['wid-2', qw(.89999 1e-7 .8999901), {OUT => [qw(0.8999900 0.8999901)]}],
+
+ ['eq-wid-1', qw(-w 1 -1 -1), {OUT => [qw(01 00 -1)]}],
+ # Prior to 2.0g, this test would fail on e.g., HPUX systems
+ # because it'd end up using %3.1f as the format instead of %4.1f.
+ ['eq-wid-2', qw(-w -.1 .1 .11),{OUT => [qw(-0.1 00.0 00.1)]}],
+ ['eq-wid-3', qw(-w 1 3.0), {OUT => [qw(1 2 3)]}],
+ ['eq-wid-4', qw(-w .8 1e-2 .81), {OUT => [qw(0.80 0.81)]}],
+ ['eq-wid-5', qw(-w 1 .5 2), {OUT => [qw(1.0 1.5 2.0)]}],
+ ['eq-wid-6', qw(-w +1 2), {OUT => [qw(1 2)]}],
+ ['eq-wid-7', qw(-w " .1" " .1"), {OUT => [qw(0.1)]}],
+ ['eq-wid-8', qw(-w 9 0.5 10), {OUT => [qw(09.0 09.5 10.0)]}],
+ # Prior to 8.21, these tests involving numbers in scientific notation
+ # would fail with misalignment or wrong widths.
+ ['eq-wid-9', qw(-w -1e-3 1), {OUT => [qw(-0.001 00.999)]}],
+ ['eq-wid-10',qw(-w -1e-003 1), {OUT => [qw(-0.001 00.999)]}],
+ ['eq-wid-11',qw(-w -1.e-3 1), {OUT => [qw(-0.001 00.999)]}],
+ ['eq-wid-12',qw(-w -1.0e-4 1), {OUT => [qw(-0.00010 00.99990)]}],
+ ['eq-wid-13',qw(-w 999 1e3), {OUT => [qw(0999 1000)]}],
+ # Prior to 8.21, if the start value hadn't a precision, while step did,
+ # then misalignment would occur if the sequence narrowed.
+ ['eq-wid-14',qw(-w -1 1.0 0), {OUT => [qw(-1.0 00.0)]}],
+ ['eq-wid-15',qw(-w 10 -.1 9.9), {OUT => [qw(10.0 09.9)]}],
+
+ # Prior to coreutils-4.5.11, some of these were not accepted.
+ ['fmt-1', qw(-f %2.1f 1.5 .5 2),{OUT => [qw(1.5 2.0)]}],
+ ['fmt-2', qw(-f %0.1f 1.5 .5 2),{OUT => [qw(1.5 2.0)]}],
+ ['fmt-3', qw(-f %.1f 1.5 .5 2),{OUT => [qw(1.5 2.0)]}],
+
+ ['fmt-4', qw(-f %3.0f 1 2), {OUT => [' 1', ' 2']}],
+ ['fmt-5', qw(-f %-3.0f 1 2), {OUT => ['1 ', '2 ']}],
+ ['fmt-6', qw(-f %+3.0f 1 2), {OUT => [' +1', ' +2']}],
+ ['fmt-7', qw(-f %0+3.0f 1 2), {OUT => [qw(+01 +02)]}],
+ ['fmt-8', qw(-f %0+.0f 1 2), {OUT => [qw(+1 +2)]}],
+ ['fmt-9', '-f "% -3.0f"', qw(-1 0), {OUT => ['-1 ', ' 0 ']}],
+ ['fmt-a', '-f "% -.0f"',qw(-1 0), {OUT => ['-1', ' 0']}],
+ ['fmt-b', qw(-f %%%g%% 1), {OUT => ['%1%']}],
+
+ # In coreutils-[6.0..6.9], this would mistakenly succeed and print "%Lg".
+ ['fmt-c', qw(-f %%g 1), {EXIT => 1},
+ {ERR => "seq: format '%%g' has no % directive\n"}],
+
+ # In coreutils-6.9..6.10, this would fail with an erroneous diagnostic:
+ # "seq: memory exhausted". In coreutils-6.0..6.8, it would mistakenly
+ # succeed and print a blank line.
+ ['fmt-eos1', qw(-f % 1), {EXIT => 1},
+ {ERR => "seq: format '%' ends in %\n"}],
+ ['fmt-eos2', qw(-f %g% 1), {EXIT => 1},
+ {ERR => "seq: format '%g%' has too many % directives\n"}],
+
+ ['fmt-d', qw(-f "" 1), {EXIT => 1},
+ {ERR => "seq: format '' has no % directive\n"}],
+ ['fmt-e', qw(-f %g%g 1), {EXIT => 1},
+ {ERR => "seq: format '%g%g' has too many % directives\n"}],
+
+ # With coreutils-6.12 and earlier, with a UTF8 numeric locale that uses
+ # something other than "." as the decimal point, this use of seq would
+ # fail to print the "2,0" endpoint.
+ ['locale-dec-pt', qw(-0.1 0.1 2),
+ {OUT => [qw(-0.1 0.0 0.1 0.2 0.3 0.4 0.5 0.6 0.7 0.8 0.9 1.0
+ 1.1 1.2 1.3 1.4 1.5 1.6 1.7 1.8 1.9 2.0)]},
+
+ {ENV => "LC_ALL=$locale"},
+ {OUT_SUBST => 's/,/./g'},
+ ],
+
+ # With coreutils-8.19 and prior, this would infloop.
+ ['long-1', "$p $r", {OUT => [$p, $q, $r]}],
+
+ # Exercise the code that trims leading zeros.
+ ['long-leading-zeros1', qw(000 2), {OUT => [qw(0 1 2)]}],
+ ['long-leading-zeros2', qw(000 02), {OUT => [qw(0 1 2)]}],
+ ['long-leading-zeros3', qw(00 02), {OUT => [qw(0 1 2)]}],
+ ['long-leading-zeros4', qw(0 02), {OUT => [qw(0 1 2)]}],
+
+ # Exercise the -s option, which was broken in 8.20
+ ['sep-1', qw(-s, 1 3), {OUT => [qw(1,2,3)]}],
+ ['sep-2', qw(-s, 1 1), {OUT => [qw(1)]}],
+ ['sep-3', qw(-s,, 1 3), {OUT => [qw(1,,2,,3)]}],
+
+ # Exercise fast path avoidance logic.
+ # In 8.20 a step value != 1, with positive integer start and end was broken
+ ['not-fast-1', qw(1 3 1), {OUT => [qw(1)]}],
+ ['not-fast-2', qw(1 1 4.2), {OUT => [qw(1 2 3 4)]}],
+ ['not-fast-3', qw(1 1 0)],
+ # In 8.20..8.22 a start or end of -0 was broken
+ ['not-fast-4', qw(-0 10), {OUT => [qw(-0 1 2 3 4 5 6 7 8 9 10)]}],
+ ['not-fast-5', qw(1 -0)],
+
+ # Ensure the correct parameters are passed to the fast path
+ ['fast-1', qw(4), {OUT => [qw(1 2 3 4)]}],
+ ['fast-2', qw(1 4), {OUT => [qw(1 2 3 4)]}],
+ ['fast-3', qw(1 1 4), {OUT => [qw(1 2 3 4)]}],
+ ['fast-4', qw(1 2 4), {OUT => [qw(1 3)]}],
+ ['fast-5', qw(1 4 4), {OUT => [qw(1)]}],
+ ['fast-6', qw(1 1e0 4), {OUT => [qw(1 2 3 4)]}],
+
+ # Ensure an INCREMENT of Zero is rejected.
+ ['inc-zero-1', qw(1 0 10), {EXIT => 1}, {ERR => $err_inc_zero}],
+ ['inc-zero-2', qw(0 -0 0), {EXIT => 1}, {ERR => $err_inc_zero},
+ {ERR_SUBST => 's/-0/0/'}],
+ ['inc-zero-3', qw(1 0.0 10), {EXIT => 1},{ERR => $err_inc_zero},
+ {ERR_SUBST => 's/0.0/0/'}],
+ ['inc-zero-4', qw(1 -0.0e-10 10), {EXIT => 1},{ERR => $err_inc_zero},
+ {ERR_SUBST => 's/-0\.0e-10/0/'}],
+
+ # Ensure NaN arguments rejected.
+ ['nan-first-1', qw(nan), {EXIT => 1}, {ERR => $err_nan_arg}],
+ ['nan-first-2', qw(NaN 2), {EXIT => 1}, {ERR => $err_nan_arg},
+ {ERR_SUBST => 's/NaN/nan/'}],
+ ['nan-first-3', qw(nan 1 2), {EXIT => 1}, {ERR => $err_nan_arg}],
+ ['nan-first-4', qw(-- -nan), {EXIT => 1}, {ERR => $err_nan_arg},
+ {ERR_SUBST => 's/-nan/nan/'}],
+ ['nan-inc-1', qw(1 nan 2), {EXIT => 1}, {ERR => $err_nan_arg}],
+ ['nan-inc-2', qw(1 -NaN 2), {EXIT => 1}, {ERR => $err_nan_arg},
+ {ERR_SUBST => 's/-NaN/nan/'}],
+ ['nan-last-1', qw(1 1 nan), {EXIT => 1}, {ERR => $err_nan_arg}],
+ ['nan-last-2', qw(1 NaN), {EXIT => 1}, {ERR => $err_nan_arg},
+ {ERR_SUBST => 's/NaN/nan/'}],
+ ['nan-last-3', qw(0 -1 -NaN), {EXIT => 1}, {ERR => $err_nan_arg},
+ {ERR_SUBST => 's/-NaN/nan/'}],
+ );
+
+# Append a newline to each entry in the OUT array.
+my $t;
+foreach $t (@Tests)
+ {
+ my $e;
+ foreach $e (@$t)
+ {
+ $e->{OUT} = join ("\n", @{$e->{OUT}}) . "\n"
+ if ref $e eq 'HASH' and exists $e->{OUT};
+ }
+ }
+
+my $save_temps = $ENV{SAVE_TEMPS};
+my $verbose = $ENV{VERBOSE};
+
+my $fail = run_tests ($program_name, $prog, \@Tests, $save_temps, $verbose);
+exit $fail;
diff --git a/tests/shred/shred-exact.sh b/tests/shred/shred-exact.sh
new file mode 100755
index 0000000..17a8b05
--- /dev/null
+++ b/tests/shred/shred-exact.sh
@@ -0,0 +1,49 @@
+#!/bin/sh
+# Test functionality of --exact
+
+# Copyright (C) 2000-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ shred
+
+
+# make sure that neither --exact nor --zero gobbles a command line argument
+for opt in --exact --zero; do
+ echo a > a || framework_failure_
+ echo bb > b || framework_failure_
+ echo ccc > c || framework_failure_
+
+ shred --remove $opt a b || fail=1
+ test -f a && fail=1
+ test -f b && fail=1
+
+ shred --remove $opt c || fail=1
+ test -f c && fail=1
+done
+
+
+# make sure direct I/O is handled appropriately at end of file
+# Create a 1MiB file as we'll probably not be using blocks larger than that
+# (i.e., we want to test failed writes not at the start).
+truncate -s1MiB file.slop || framework_failure_
+truncate -s+1 file.slop || framework_failure_
+shred --exact -n2 file.slop || fail=1
+
+# make sure direct I/O is handled appropriately at start of file
+truncate -s1 file.slop || framework_failure_
+shred --exact -n2 file.slop || fail=1
+
+Exit $fail
diff --git a/tests/shred/shred-passes.sh b/tests/shred/shred-passes.sh
new file mode 100755
index 0000000..020cf68
--- /dev/null
+++ b/tests/shred/shred-passes.sh
@@ -0,0 +1,91 @@
+#!/bin/sh
+# Verify the operations done by shred
+
+# Copyright (C) 2009-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ shred
+
+
+# shred a single letter, which should result in
+# 3 random passes and a single rename.
+printf 1 > f || framework_failure_
+echo "\
+shred: f: pass 1/3 (random)...
+shred: f: pass 2/3 (random)...
+shred: f: pass 3/3 (random)...
+shred: f: removing
+shred: f: renamed to 0
+shred: f: removed" > exp || framework_failure_
+
+shred -v -u f 2>out || fail=1
+compare exp out || fail=1
+
+
+# Likewise but for a zero length file
+# to bypass the data passes
+touch f || framework_failure_
+echo "\
+shred: f: removing
+shred: f: renamed to 0
+shred: f: removed" > exp || framework_failure_
+
+shred -v -u f 2>out || fail=1
+compare exp out || fail=1
+
+
+# shred data 20 times and verify the passes used.
+# This would consume all random data between 5.93 and 8.24 inclusive.
+dd bs=100K count=1 if=/dev/zero | tr '\0' 'U' > Us || framework_failure_
+printf 1 > f || framework_failure_
+echo "\
+shred: f: pass 1/20 (random)...
+shred: f: pass 2/20 (ffffff)...
+shred: f: pass 3/20 (924924)...
+shred: f: pass 4/20 (888888)...
+shred: f: pass 5/20 (db6db6)...
+shred: f: pass 6/20 (777777)...
+shred: f: pass 7/20 (492492)...
+shred: f: pass 8/20 (bbbbbb)...
+shred: f: pass 9/20 (555555)...
+shred: f: pass 10/20 (aaaaaa)...
+shred: f: pass 11/20 (random)...
+shred: f: pass 12/20 (6db6db)...
+shred: f: pass 13/20 (249249)...
+shred: f: pass 14/20 (999999)...
+shred: f: pass 15/20 (111111)...
+shred: f: pass 16/20 (000000)...
+shred: f: pass 17/20 (b6db6d)...
+shred: f: pass 18/20 (eeeeee)...
+shred: f: pass 19/20 (333333)...
+shred: f: pass 20/20 (random)...
+shred: f: removing
+shred: f: renamed to 0
+shred: f: removed" > exp || framework_failure_
+
+shred -v -u -n20 -s4096 --random-source=Us f 2>out || fail=1
+compare exp out || fail=1
+
+# Trigger an issue in shred before v8.27 where single
+# bytes in the pattern space were not initialized correctly
+# for particular sizes, like 7,13,...
+# This failed under both valgrind and ASAN.
+for size in 1 2 6 7 8; do
+ touch shred.pattern.umr.size
+ shred -n4 -s$size shred.pattern.umr.size || fail=1
+done
+
+Exit $fail
diff --git a/tests/shred/shred-remove.sh b/tests/shred/shred-remove.sh
new file mode 100755
index 0000000..25d58db
--- /dev/null
+++ b/tests/shred/shred-remove.sh
@@ -0,0 +1,70 @@
+#!/bin/sh
+# Exercise shred --remove
+
+# Copyright (C) 1999-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ shred
+skip_if_root_
+
+# The length of the basename is what matters.
+# In this case, shred-4.0l would try to rename the file 256^10 times
+# before terminating.
+file=0123456789
+touch $file || framework_failure_
+chmod u-w $file || framework_failure_
+
+# This would take so long that it appears to infloop
+# when using version from fileutils-4.0k.
+# When the command completes, expect it to fail.
+returns_ 1 shred -u $file > /dev/null 2>&1 || fail=1
+rm -f $file || framework_failure_
+
+# Ensure all --remove methods at least unlink the file
+for mode in '' '=unlink' '=wipe' '=wipesync'; do
+ touch $file || framework_failure_
+ shred -n0 --remove"$mode" $file || fail=1
+ test -e $file && fail=1
+done
+
+# Ensure incorrect params are diagnosed
+touch $file || framework_failure_
+returns_ 1 shred -n0 --remove=none $file 2>/dev/null || fail=1
+
+# Ensure rename passes complete.
+# coreutils-8.28 did not do the decreasing length rename
+# which may have leaked the length of the removed file name
+ # test level exhaustion
+touch \
+ 0 1 2 3 4 5 6 7 8 9 \
+ a b c d e f g h i j k l m n o p q r s t u v w x y z \
+ A B C D E F G H I J K L M N O P Q R S T U V W X Y Z _ || framework_failure_
+touch test 000 || framework_failure_ # test level increment
+shred -vu test 2>out || fail=1
+cat <<\EOF >exp || framework_failure_
+shred: test: removing
+shred: test: renamed to 0000
+shred: 0000: renamed to 001
+shred: 001: renamed to 00
+shred: test: removed
+EOF
+compare exp out || fail=1
+
+# Ensure renames are only retried for EEXIST
+mkdir rodir && cd rodir && touch $file && chmod a-w . || framework_failure_
+returns_ 1 timeout 10 shred -u $file || fail=1
+
+Exit $fail
diff --git a/tests/shred/shred-size.sh b/tests/shred/shred-size.sh
new file mode 100755
index 0000000..8690582
--- /dev/null
+++ b/tests/shred/shred-size.sh
@@ -0,0 +1,34 @@
+#!/bin/sh
+# Exercise shred --size
+
+# Copyright (C) 2014-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ shred
+
+# Negative size
+echo "shred: invalid file size: '-2'" > exp || framework_failure_
+echo 1234 > f || framework_failure_
+shred -s-2 f 2>err && fail=1
+compare exp err || fail=1
+
+# Octal/Hex
+shred -s010 f || fail=1
+test $(stat --printf=%s f) = 8 || fail=1
+shred -s0x10 f || fail=1
+test $(stat --printf=%s f) = 16 || fail=1
+
+Exit $fail
diff --git a/tests/shuf/shuf-reservoir.sh b/tests/shuf/shuf-reservoir.sh
new file mode 100755
index 0000000..2edfe50
--- /dev/null
+++ b/tests/shuf/shuf-reservoir.sh
@@ -0,0 +1,73 @@
+#!/bin/sh
+# Exercise shuf's reservoir-sampling code
+# NOTE:
+# These tests do not check valid randomness,
+# they just check memory allocation related code.
+
+# Copyright (C) 2013-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ shuf
+expensive_
+require_valgrind_
+
+# Only exit with error for leaks when in development mode
+# in which case we enable code to suppress inconsequential leaks.
+grep '^#define lint 1' "$CONFIG_HEADER" && leaklevel=full || leaklevel=summary
+
+# Run "shuf" with specific number of input lines and output lines
+# Check the output for expected number of lines.
+run_shuf_n()
+{
+ INPUT_LINES="$1"
+ OUTPUT_LINES="$2"
+
+ # Critical memory-related bugs will cause a segfault here
+ # (with varying numbers of input/output lines)
+ seq "$INPUT_LINES" | valgrind --leak-check=$leaklevel --error-exitcode=1 \
+ shuf -n "$OUTPUT_LINES" -o "out_${INPUT_LINES}_${OUTPUT_LINES}" || return 1
+
+ EXPECTED_LINES="$OUTPUT_LINES"
+ test "$INPUT_LINES" -lt "$OUTPUT_LINES" && EXPECTED_LINES="$INPUT_LINES"
+
+ # There is no sure way to verify shuffled output (as it is random).
+ # Ensure we have the correct number of all numeric lines non duplicated lines.
+ GOOD_LINES=$(grep '^[0-9][0-9]*$' "out_${INPUT_LINES}_${OUTPUT_LINES}" |
+ sort -un | wc -l) || framework_failure_
+ LINES=$(wc -l < "out_${INPUT_LINES}_${OUTPUT_LINES}") || framework_failure_
+
+ test "$EXPECTED_LINES" -eq "$GOOD_LINES" || return 1
+ test "$EXPECTED_LINES" -eq "$LINES" || return 1
+
+ return 0
+}
+
+# Test multiple combinations of input lines and output lines.
+# (e.g. small number of input lines and large number of output lines,
+# and vice-versa. Also, each reservoir allocation uses a 1024-lines batch,
+# so test 1023/1024/1025 and related values).
+TEST_LINES="0 1 5 1023 1024 1025 3071 3072 3073"
+
+for IN_N in $TEST_LINES; do
+ for OUT_N in $TEST_LINES; do
+ run_shuf_n "$IN_N" "$OUT_N" || {
+ fail=1
+ echo "shuf-reservoir-sampling failed with IN_N=$IN_N OUT_N=$OUT_N" >&2;
+ }
+ done
+done
+
+Exit $fail
diff --git a/tests/shuf/shuf.sh b/tests/shuf/shuf.sh
new file mode 100755
index 0000000..fd57dfe
--- /dev/null
+++ b/tests/shuf/shuf.sh
@@ -0,0 +1,178 @@
+#!/bin/sh
+# Ensure that shuf randomizes its input.
+
+# Copyright (C) 2006-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ shuf
+getlimits_
+
+seq 100 > in || framework_failure_
+
+shuf in >out || fail=1
+
+# Fail if the input is the same as the output.
+# This is a probabilistic test :-)
+# However, the odds of failure are very low: 1 in 100! (~ 1 in 10^158)
+compare in out > /dev/null && { fail=1; echo "not random?" 1>&2; }
+
+# Fail if the sorted output is not the same as the input.
+sort -n out > out1
+compare in out1 || { fail=1; echo "not a permutation" 1>&2; }
+
+# Exercise shuf's -i option.
+shuf -i 1-100 > out || fail=1
+compare in out > /dev/null && { fail=1; echo "not random?" 1>&2; }
+sort -n out > out1
+compare in out1 || { fail=1; echo "not a permutation" 1>&2; }
+
+# Exercise shuf's -r -n 0 options, with no standard input.
+shuf -r -n 0 in <&- >out || fail=1
+compare /dev/null out || fail=1
+
+# Exercise shuf's -e option.
+t=$(shuf -e a b c d e | sort | fmt)
+test "$t" = 'a b c d e' || { fail=1; echo "not a permutation" 1>&2; }
+
+# coreutils-8.22 dumps core.
+shuf -er
+test $? -eq 1 || fail=1
+
+# coreutils-8.22 and 8.23 dump core
+# with a single redundant operand with --input-range
+shuf -i0-0 1
+test $? -eq 1 || fail=1
+
+# Before coreutils-6.3, this would infloop.
+# "seq 1860" produces 8193 (8K + 1) bytes of output.
+seq 1860 | shuf > /dev/null || fail=1
+
+# coreutils-6.12 and earlier would output a newline terminator, not \0.
+shuf --zero-terminated -i 1-1 > out || fail=1
+printf '1\0' > exp || framework_failure_
+cmp out exp || { fail=1; echo "missing NUL terminator?" 1>&2; }
+
+# Ensure shuf -n operates efficiently for small n. Before coreutils-8.13
+# this would try to allocate $SIZE_MAX * sizeof(size_t)
+timeout 10 shuf -i1-$SIZE_MAX -n2 >/dev/null ||
+ { fail=1; echo "couldn't get a small subset" >&2; }
+
+# Ensure shuf -n0 doesn't read any input or open specified files
+touch unreadable || framework_failure_
+chmod 0 unreadable || framework_failure_
+if ! test -r unreadable; then
+ shuf -n0 unreadable || fail=1
+ { shuf -n1 unreadable || test $? -ne 1; } && fail=1
+fi
+
+# Multiple -n is accepted, should use the smallest value
+shuf -n10 -i0-9 -n3 -n20 > exp || framework_failure_
+c=$(wc -l < exp) || framework_failure_
+test "$c" -eq 3 || { fail=1; echo "Multiple -n failed">&2 ; }
+
+# Test error conditions
+
+# -i and -e must not be used together
+: | { shuf -i0-9 -e A B || test $? -ne 1; } &&
+ { fail=1; echo "shuf did not detect erroneous -e and -i usage.">&2 ; }
+# Test invalid value for -n
+: | { shuf -nA || test $? -ne 1; } &&
+ { fail=1; echo "shuf did not detect erroneous -n usage.">&2 ; }
+# Test multiple -i
+{ shuf -i0-9 -n10 -i8-90 || test $? -ne 1; } &&
+ { fail=1; echo "shuf did not detect multiple -i usage.">&2 ; }
+# Test invalid range
+for ARG in '1' 'A' '1-' '1-A'; do
+ { shuf -i$ARG || test $? -ne 1; } &&
+ { fail=1; echo "shuf did not detect erroneous -i$ARG usage.">&2 ; }
+done
+
+# multiple -o are forbidden
+{ shuf -i0-9 -o A -o B || test $? -ne 1; } &&
+ { fail=1; echo "shuf did not detect erroneous multiple -o usage.">&2 ; }
+# multiple random-sources are forbidden
+{ shuf -i0-9 --random-source A --random-source B || test $? -ne 1; } &&
+ { fail=1; echo "shuf did not detect multiple --random-source usage.">&2 ; }
+
+# Test --repeat option
+
+# --repeat without count should return an indefinite number of lines
+shuf --rep -i 0-10 | head -n 1000 > exp || framework_failure_
+c=$(wc -l < exp) || framework_failure_
+test "$c" -eq 1000 \
+ || { fail=1; echo "--repeat does not repeat indefinitely">&2 ; }
+
+# --repeat can output more values than the input range
+shuf --rep -i0-9 -n1000 > exp || framework_failure_
+c=$(wc -l < exp) || framework_failure_
+test "$c" -eq 1000 || { fail=1; echo "--repeat with --count failed">&2 ; }
+
+# Check output values (this is not bullet-proof, but drawing 1000 values
+# between 0 and 9 should produce all values, unless there's a bug in shuf
+# or a very poor random source, or extremely bad luck)
+c=$(sort -nu exp | paste -s -d ' ') || framework_failure_
+test "$c" = "0 1 2 3 4 5 6 7 8 9" ||
+ { fail=1; echo "--repeat produced bad output">&2 ; }
+
+# check --repeat with non-zero low value
+shuf --rep -i222-233 -n2000 > exp || framework_failure_
+c=$(sort -nu exp | paste -s -d ' ') || framework_failure_
+test "$c" = "222 223 224 225 226 227 228 229 230 231 232 233" ||
+ { fail=1; echo "--repeat produced bad output with non-zero low">&2 ; }
+
+# --repeat,-i,count=0 should not fail and produce no output
+shuf --rep -i0-9 -n0 > exp || framework_failure_
+# file size should be zero (no output from shuf)
+test \! -s exp ||
+ { fail=1; echo "--repeat,-i0-9,-n0 produced bad output">&2 ; }
+
+# --repeat with -e, without count, should repeat indefinitely
+shuf --rep -e A B C D | head -n 1000 > exp || framework_failure_
+c=$(wc -l < exp) || framework_failure_
+test "$c" -eq 1000 ||
+ { fail=1; echo "--repeat,-e does not repeat indefinitely">&2 ; }
+
+# --repeat with STDIN, without count, should repeat indefinitely
+printf "A\nB\nC\nD\nE\n" | shuf --rep | head -n 1000 > exp || framework_failure_
+c=$(wc -l < exp) || framework_failure_
+test "$c" -eq 1000 ||
+ { fail=1; echo "--repeat,STDIN does not repeat indefinitely">&2 ; }
+
+# --repeat with STDIN,count - can return move values than input lines
+printf "A\nB\nC\nD\nE\n" | shuf --rep -n2000 > exp || framework_failure_
+c=$(wc -l < exp) || framework_failure_
+test "$c" -eq 2000 ||
+ { fail=1; echo "--repeat,STDIN,count failed">&2 ; }
+
+# Check output values (this is not bullet-proof, but drawing 2000 values
+# between A and E should produce all values, unless there's a bug in shuf
+# or a very poor random source, or extremely bad luck)
+c=$(sort -u exp | paste -s -d ' ') || framework_failure_
+test "$c" = "A B C D E" ||
+ { fail=1; echo "--repeat,STDIN,count produced bad output">&2 ; }
+
+# --repeat,stdin,count=0 should not fail and produce no output
+printf "A\nB\nC\nD\nE\n" | shuf --rep -n0 > exp || framework_failure_
+# file size should be zero (no output from shuf)
+test \! -s exp ||
+ { fail=1; echo "--repeat,STDIN,-n0 produced bad output">&2 ; }
+
+# shuf 8.25 mishandles input if stdin is closed, due to glibc bug#15589.
+# See coreutils bug#25029.
+shuf /dev/null <&- >out || fail=1
+compare /dev/null out || fail=1
+
+Exit $fail
diff --git a/tests/sort/sort-NaN-infloop.sh b/tests/sort/sort-NaN-infloop.sh
new file mode 100755
index 0000000..9048865
--- /dev/null
+++ b/tests/sort/sort-NaN-infloop.sh
@@ -0,0 +1,31 @@
+#!/bin/sh
+# exercise the NaN-infloop bug in coreutils-8.13
+
+# Copyright (C) 2011-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ sort
+
+echo nan > F || framework_failure_
+printf 'nan\nnan\n' > exp || framework_failure_
+timeout 10 sort -g -m F F > out || fail=1
+
+# This was seen to infloop on some systems until coreutils v9.2 (bug 55212)
+yes nan | head -n128095 | timeout 60 sort -g > /dev/null || fail=1
+
+compare exp out || fail=1
+
+Exit $fail
diff --git a/tests/sort/sort-benchmark-random.sh b/tests/sort/sort-benchmark-random.sh
new file mode 100755
index 0000000..cf26726
--- /dev/null
+++ b/tests/sort/sort-benchmark-random.sh
@@ -0,0 +1,54 @@
+#!/bin/sh
+# Benchmark sort on randomly generated data.
+
+# Copyright (C) 2010-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+# Written by Glen Lenker.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ sort
+require_perl_
+
+very_expensive_
+
+$PERL -e '
+my $num_lines = 500000;
+my $length = 100;
+
+for (my $i=0; $i < $num_lines; $i++)
+{
+ for (my $j=0; $j < $length; $j++)
+ {
+ printf "%c", 32 + rand(94);
+ }
+ print "\n";
+}' > in || framework_failure_
+
+# We need to generate a lot of data for sort to show a noticeable
+# improvement in performance. Sorting it in PERL may take awhile.
+
+$PERL -e '
+open (FILE, "<in");
+my @list = <FILE>;
+print sort(@list);
+close (FILE);
+' > exp || framework_failure_
+
+time sort in > out || fail=1
+
+compare exp out || fail=1
+
+Exit $fail
diff --git a/tests/sort/sort-compress-hang.sh b/tests/sort/sort-compress-hang.sh
new file mode 100755
index 0000000..93c6feb
--- /dev/null
+++ b/tests/sort/sort-compress-hang.sh
@@ -0,0 +1,57 @@
+#!/bin/sh
+# Test for sort --compress hang
+
+# Copyright (C) 2010-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ sort
+very_expensive_
+
+cat <<EOF >compress || framework_failure_
+#!$SHELL
+tr 41 14 || exit
+touch ok
+EOF
+
+chmod +x compress
+
+seq -w 200000 > exp || fail=1
+tac exp > in || fail=1
+
+# When the bug occurs, 'sort' hangs forever. When it doesn't occur,
+# 'sort' could be running slowly on an overburdened machine.
+# On a circa-2010 Linux server using NFS, a successful test completes
+# in about 170 seconds, so specify 1700 seconds as a safety margin.
+# Note --foreground will not kill any of the "compress" sub processes,
+# assuming they're well behaved and exit in a timely manner, but will
+# allow this command to be responsive to Ctrl-C
+timeout --foreground 1700 sort --compress-program=./compress -S 1k in > out \
+ || fail=1
+
+compare exp out || fail=1
+test -f ok || fail=1
+rm -f compress ok
+
+# If $TMPDIR is relative, give subprocesses time to react when 'sort' exits.
+# Otherwise, under NFS, when 'sort' unlinks the temp files and they
+# are renamed to .nfsXXXX instead of being removed, the parent cleanup
+# of this directory will fail because the files are still open.
+case $TMPDIR in
+/*) ;;
+*) sleep 1;;
+esac
+
+Exit $fail
diff --git a/tests/sort/sort-compress-proc.sh b/tests/sort/sort-compress-proc.sh
new file mode 100755
index 0000000..07035be
--- /dev/null
+++ b/tests/sort/sort-compress-proc.sh
@@ -0,0 +1,90 @@
+#!/bin/sh
+# Test use of compression subprocesses by sort
+
+# Copyright (C) 2010-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ sort
+expensive_
+
+# Terminate any background processes
+cleanup_() { kill $pid 2>/dev/null && wait $pid; }
+
+SORT_FAILURE=2
+
+seq -w 2000 > exp || fail=1
+tac exp > in || fail=1
+insize=$(stat -c %s - <in) || fail=1
+
+# This compressor's behavior is adjustable via environment variables.
+export PRE_COMPRESS=
+export POST_COMPRESS=
+
+printf '%s\n' '#!'"$SHELL" >compress || framework_failure_
+cat <<\EOF >>compress || framework_failure_
+eval "$PRE_COMPRESS"
+tr 41 14 || exit
+eval "$POST_COMPRESS"
+EOF
+
+chmod +x compress
+
+# "Impatient exit" tests
+#
+# In these test cases, the biggest compressor (or decompressor) exits
+# with nonzero status, after sleeping a bit. Until coreutils 8.7
+# 'sort' impatiently exited without waiting for its decompression
+# subprocesses in these cases. Check compression too, while we're here.
+#
+for compress_arg in '' '-d'
+do
+ POST_COMPRESS='
+ test "X$1" != "X'$compress_arg'" || {
+ test "X$1" = "X" && exec <&1
+ size=$(stat -c %s -)
+ exec >/dev/null 2>&1 <&1 || exit
+ expr $size "<" '"$insize"' / 2 || { sleep 1; exit 1; }
+ }
+ ' sort --compress-program=./compress -S 1k --batch-size=2 in > out
+ test $? -eq $SORT_FAILURE || fail=1
+done
+
+# "Pre-exec child" test
+#
+# Ignore a random child process created before 'sort' was exec'ed.
+# This bug was also present in coreutils 8.7.
+#
+( (sleep 1; exec false) & pid=$!
+ PRE_COMPRESS='test -f ok || sleep 2'
+ POST_COMPRESS='touch ok'
+ exec sort --compress-program=./compress -S 1k in >out
+) || fail=1
+compare exp out || fail=1
+test -f ok || fail=1
+rm -f ok
+
+rm -f compress
+
+# If $TMPDIR is relative, give subprocesses time to react when 'sort' exits.
+# Otherwise, under NFS, when 'sort' unlinks the temp files and they
+# are renamed to .nfsXXXX instead of being removed, the parent cleanup
+# of this directory will fail because the files are still open.
+case $TMPDIR in
+/*) ;;
+*) sleep 1;;
+esac
+
+Exit $fail
diff --git a/tests/sort/sort-compress.sh b/tests/sort/sort-compress.sh
new file mode 100755
index 0000000..fea4f07
--- /dev/null
+++ b/tests/sort/sort-compress.sh
@@ -0,0 +1,72 @@
+#!/bin/sh
+# Test use of compression by sort
+
+# Copyright (C) 2007-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ sort
+require_trap_signame_
+
+seq -w 2000 > exp || framework_failure_
+tac exp > in || framework_failure_
+
+# This should force the use of temp files
+sort -S 1k in > out || fail=1
+compare exp out || fail=1
+
+# Create our own gzip program that will be used as the default
+cat <<EOF > gzip || framework_failure_
+#!$SHELL
+tr 41 14
+touch ok
+EOF
+
+chmod +x gzip
+
+# Ensure 'sort' is immune to parent's SIGCHLD handler
+# Use a subshell and an exec to work around a bug in FreeBSD 5.0 /bin/sh.
+(
+ trap '' CHLD
+
+ # This should force the use of child processes for "compression"
+ PATH=.:$PATH exec sort -S 1k --compress-program=gzip in > /dev/null
+) || fail=1
+
+# This will find our new gzip in PATH
+PATH=.:$PATH sort -S 1k --compress-program=gzip in > out || fail=1
+compare exp out || fail=1
+test -f ok || fail=1
+rm -f ok
+
+# This is to make sure it works with no compression.
+PATH=.:$PATH sort -S 1k in > out || fail=1
+compare exp out || fail=1
+test -f ok && fail=1
+
+# This is to make sure we can use something other than gzip
+mv gzip dzip || fail=1
+sort --compress-program=./dzip -S 1k in > out || fail=1
+compare exp out || fail=1
+test -f ok || fail=1
+rm -f ok
+
+# Make sure it can find other programs in PATH correctly
+PATH=.:$PATH sort --compress-program=dzip -S 1k in > out || fail=1
+compare exp out || fail=1
+test -f ok || fail=1
+rm -f dzip ok
+
+Exit $fail
diff --git a/tests/sort/sort-continue.sh b/tests/sort/sort-continue.sh
new file mode 100755
index 0000000..5326bfe
--- /dev/null
+++ b/tests/sort/sort-continue.sh
@@ -0,0 +1,53 @@
+#!/bin/sh
+# Tests for file descriptor exhaustion.
+
+# Copyright (C) 2009-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ sort
+
+# This script uses 'ulimit -n 7' to limit 'sort' to at most 7 open files:
+# stdin, stdout, stderr, two input and one output files when merging,
+# and an extra. The extra is for old-fashioned platforms like Solaris 10
+# where opening a temp file also requires opening /dev/urandom to
+# calculate the temp file's name.
+
+# Skip the test when running under valgrind.
+( ulimit -n 7; sort 3<&- 4<&- 5<&- 6<&- < /dev/null ) \
+ || skip_ 'fd-limited sort failed; are you running under valgrind?'
+
+for i in $(seq 31); do
+ echo $i | tee -a in > __test.$i || framework_failure_
+done
+
+# glob before ulimit to avoid issues on bash 3.2 on OS X 10.6.8 at least
+test_files=$(echo __test.*)
+
+(
+ ulimit -n 7
+ sort -n -m $test_files 3<&- 4<&- 5<&- 6<&- < /dev/null > out
+) &&
+compare in out ||
+ { fail=1; echo 'file descriptor exhaustion not handled' 1>&2; }
+
+echo 32 | tee -a in > in1
+(
+ ulimit -n 7
+ sort -n -m $test_files - 3<&- 4<&- 5<&- 6<&- < in1 > out
+) &&
+compare in out || { fail=1; echo 'stdin not handled properly' 1>&2; }
+
+Exit $fail
diff --git a/tests/sort/sort-debug-keys.sh b/tests/sort/sort-debug-keys.sh
new file mode 100755
index 0000000..3397ef8
--- /dev/null
+++ b/tests/sort/sort-debug-keys.sh
@@ -0,0 +1,341 @@
+#!/bin/sh
+# Test annotation of sort keys
+
+# Copyright (C) 2010-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ sort printf
+
+number() { cat -n | sed 's/^ *//'; }
+
+cat <<\EOF > exp
+1
+ ^ no match for key
+
+^ no match for key
+44
+ ^ no match for key
+33
+ ^ no match for key
+2
+ ^ no match for key
+1
+ ^ no match for key
+
+^ no match for key
+44
+ ^ no match for key
+33
+ ^ no match for key
+2
+ ^ no match for key
+
+^ no match for key
+1
+_
+2
+_
+33
+__
+44
+__
+2>
+ ^ no match for key
+3>1
+ _
+1>2
+ _
+1
+ ^ no match for key
+
+^ no match for key
+44
+ ^ no match for key
+33
+ ^ no match for key
+2
+ ^ no match for key
+1
+ ^ no match for key
+
+^ no match for key
+44
+ ^ no match for key
+33
+ ^ no match for key
+2
+ ^ no match for key
+
+^ no match for key
+1
+_
+2
+_
+33
+__
+44
+__
+2>
+ ^ no match for key
+3>1
+ _
+1>2
+ _
+1
+ ^ no match for key
+
+^ no match for key
+44
+ ^ no match for key
+33
+ ^ no match for key
+2
+ ^ no match for key
+1
+ ^ no match for key
+
+^ no match for key
+44
+ ^ no match for key
+33
+ ^ no match for key
+2
+ ^ no match for key
+
+^ no match for key
+1
+_
+2
+_
+33
+__
+44
+__
+2>
+ ^ no match for key
+3>1
+ _
+1>2
+ _
+
+^ no match for key
+JAN
+___
+FEB
+___
+FEB
+ ^ no match for key
+
+^ no match for key
+JAN
+ ^ no match for key
+JAZZ
+^ no match for key
+
+^ no match for key
+JAN
+___
+FEB
+___
+2>JAZZ
+ ^ no match for key
+3>
+ ^ no match for key
+4>JAN
+ ___
+1>FEB
+ ___
+
+^ no match for key
+JANZ
+___
+JAN
+___
+FEB
+___
+3>
+ ^ no match for key
+2>JANZ
+ ___
+4>JAN
+ ___
+1>FEB
+ ___
+ 1.2ignore
+ ___
+ 1.1e4ignore
+ _____
+>>a
+___
+>b
+__
+a
+ ^ no match for key
+
+^ no match for key
+a
+_
+b
+_
+-3
+__
+-2
+__
+-0
+__
+--Mi-1
+^ no match for key
+-0
+__
+1
+_
+ 1
+ _
+__
+1
+_
+_
+ 1
+ _
+1
+_
+ 1
+__
+1
+_
+2,5
+_
+2.4
+___
+2.,,3
+__
+2.4
+___
+2,,3
+_
+2.4
+___
+1a
+_
+2b
+_
+>a
+ _
+A>chr10
+ ^ no match for key
+B>chr1
+ ^ no match for key
+1 2
+ __
+1 3
+ __
+EOF
+
+(
+for type in n h g; do
+ printf '1\n\n44\n33\n2\n' | sort -s -k2$type --debug
+ printf '1\n\n44\n33\n2\n' | sort -s -k1.3$type --debug
+ printf '1\n\n44\n33\n2\n' | sort -s -k1$type --debug
+ printf '2\n\n1\n' | number | sort -s -k2g --debug
+done
+
+printf 'FEB\n\nJAN\n' | sort -s -k1M --debug
+printf 'FEB\n\nJAN\n' | sort -s -k2,2M --debug
+printf 'FEB\nJAZZ\n\nJAN\n' | sort -s -k1M --debug
+printf 'FEB\nJAZZ\n\nJAN\n' | number | sort -s -k2,2M --debug
+printf 'FEB\nJANZ\n\nJAN\n' | sort -s -k1M --debug
+printf 'FEB\nJANZ\n\nJAN\n' | number | sort -s -k2,2M --debug
+
+printf ' 1.2ignore\n 1.1e4ignore\n' | sort -s -g --debug
+
+printf '\tb\n\t\ta\n' | sort -s -d --debug # ignore = 1
+
+printf 'a\n\n' | sort -s -k2,2 --debug #lena = 0
+
+printf 'b\na\n' | sort -s -k1 --debug #otherwise key compare
+
+printf -- '-0\n1\n-2\n--Mi-1\n-3\n-0\n' | sort -s --debug -k1,1h
+
+printf ' 1\n1\n' | sort -b --debug
+printf ' 1\n1\n' | sort -sb --debug
+printf ' 1\n1\n' | sort --debug
+
+# strnumcmp is a bit weird, so we don't match exactly
+printf '2,5\n2.4\n' | sort -s -k1n --debug
+printf '2.,,3\n2.4\n' | sort -s -k1n --debug
+printf '2,,3\n2.4\n' | sort -s -k1n --debug
+
+# -z means we convert \0 to \n
+env printf '1a\x002b\x00' | sort -s -n -z --debug
+
+# Check that \0 and \t intermix.
+printf '\0\ta\n' | sort -s -k2b,2 --debug | tr -d '\0'
+
+# Check that key end before key start is not underlined
+printf 'A\tchr10\nB\tchr1\n' | sort -s -k2.4b,2.3n --debug
+
+# Ensure that -b applied before -k offsets
+printf '1 2\n1 3\n' | sort -s -k1.2b --debug
+) > out
+
+compare exp out || fail=1
+
+cat <<\EOF > exp
+ 1²---++3 1,234 Mi
+ _
+ _________
+________________________
+ 1²---++3 1,234 Mi
+ _____
+ ________
+_______________________
++1234 1234Gi 1,234M
+^ no match for key
+_____
+^ no match for key
+ ____
+ ____
+ _____
+ _____
+ _____
+ ______
+___________________
+EOF
+
+unset LC_ALL
+f=$LOCALE_FR_UTF8
+
+: ${LOCALE_FR_UTF8=none}
+if test "$LOCALE_FR_UTF8" != "none"; then
+ LC_NUMERIC=$f LC_MESSAGES=C sort -g --debug /dev/null 2> debug.out
+ if grep 'numbers use .*,.* as a decimal point' debug.out >/dev/null; then
+ (
+ echo ' 1²---++3 1,234 Mi' |
+ LC_ALL=C sort --debug -k2g -k1b,1
+ echo ' 1²---++3 1,234 Mi' |
+ LC_ALL=$f sort --debug -k2g -k1b,1
+ echo '+1234 1234Gi 1,234M' |
+ LC_ALL=$f sort --debug \
+ -k1,1n -k1,1g -k1,1h \
+ -k2,2n -k2,2g -k2,2h \
+ -k3,3n -k3,3g -k3,3h
+ ) | sed 's/^^ .*/^ no match for key/' > out
+ compare exp out || touch locale_fail
+ fi
+ test -f locale_fail && fail=1
+fi
+
+Exit $fail
diff --git a/tests/sort/sort-debug-warn.sh b/tests/sort/sort-debug-warn.sh
new file mode 100755
index 0000000..ff0da95
--- /dev/null
+++ b/tests/sort/sort-debug-warn.sh
@@ -0,0 +1,185 @@
+#!/bin/sh
+# Test warnings for sort options
+
+# Copyright (C) 2010-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ sort
+
+cat <<\EOF > exp
+1
+sort: text ordering performed using simple byte comparison
+sort: key 1 has zero width and will be ignored
+2
+sort: text ordering performed using simple byte comparison
+sort: key 1 has zero width and will be ignored
+sort: note numbers use '.' as a decimal point in this locale
+3
+sort: text ordering performed using simple byte comparison
+sort: key 1 is numeric and spans multiple fields
+sort: note numbers use '.' as a decimal point in this locale
+4
+sort: text ordering performed using simple byte comparison
+sort: note numbers use '.' as a decimal point in this locale
+sort: options '-bghMRrV' are ignored
+5
+sort: text ordering performed using simple byte comparison
+sort: note numbers use '.' as a decimal point in this locale
+sort: options '-bghMRV' are ignored
+sort: option '-r' only applies to last-resort comparison
+6
+sort: text ordering performed using simple byte comparison
+sort: note numbers use '.' as a decimal point in this locale
+sort: option '-r' only applies to last-resort comparison
+7
+sort: text ordering performed using simple byte comparison
+sort: leading blanks are significant in key 2; consider also specifying 'b'
+sort: note numbers use '.' as a decimal point in this locale
+sort: options '-bg' are ignored
+8
+sort: text ordering performed using simple byte comparison
+sort: note numbers use '.' as a decimal point in this locale
+9
+sort: text ordering performed using simple byte comparison
+sort: note numbers use '.' as a decimal point in this locale
+sort: option '-b' is ignored
+10
+sort: text ordering performed using simple byte comparison
+sort: note numbers use '.' as a decimal point in this locale
+11
+sort: text ordering performed using simple byte comparison
+sort: leading blanks are significant in key 1; consider also specifying 'b'
+12
+sort: text ordering performed using simple byte comparison
+sort: leading blanks are significant in key 1; consider also specifying 'b'
+13
+sort: text ordering performed using simple byte comparison
+sort: leading blanks are significant in key 1; consider also specifying 'b'
+sort: option '-d' is ignored
+14
+sort: text ordering performed using simple byte comparison
+sort: leading blanks are significant in key 1; consider also specifying 'b'
+sort: option '-i' is ignored
+15
+sort: text ordering performed using simple byte comparison
+16
+sort: text ordering performed using simple byte comparison
+17
+sort: text ordering performed using simple byte comparison
+EOF
+
+echo 1 >> out
+sort -s -k2,1 --debug /dev/null 2>>out || fail=1
+echo 2 >> out
+sort -s -k2,1n --debug /dev/null 2>>out || fail=1
+echo 3 >> out
+sort -s -k1,2n --debug /dev/null 2>>out || fail=1
+echo 4 >> out
+sort -s -rRVMhgb -k1,1n --debug /dev/null 2>>out || fail=1
+echo 5 >> out
+sort -rRVMhgb -k1,1n --debug /dev/null 2>>out || fail=1
+echo 6 >> out
+sort -r -k1,1n --debug /dev/null 2>>out || fail=1
+echo 7 >> out
+sort -gbr -k1,1n -k1,1r --debug /dev/null 2>>out || fail=1
+echo 8 >> out
+sort -b -k1b,1bn --debug /dev/null 2>>out || fail=1 # no warning
+echo 9 >> out
+sort -b -k1,1bn --debug /dev/null 2>>out || fail=1
+echo 10 >> out
+sort -b -k1,1bn -k2b,2 --debug /dev/null 2>>out || fail=1 # no warning
+echo 11 >> out
+sort -r -k1,1r --debug /dev/null 2>>out || fail=1 # no warning for redundant opt
+echo 12 >> out
+sort -i -k1,1i --debug /dev/null 2>>out || fail=1 # no warning
+echo 13 >> out
+sort -d -k1,1b --debug /dev/null 2>>out || fail=1
+echo 14 >> out
+sort -i -k1,1d --debug /dev/null 2>>out || fail=1
+echo 15 >> out
+sort -r --debug /dev/null 2>>out || fail=1 #no warning
+echo 16 >> out
+sort -rM --debug /dev/null 2>>out || fail=1 #no warning
+echo 17 >> out
+sort -rM -k1,1 --debug /dev/null 2>>out || fail=1 #no warning
+compare exp out || fail=1
+
+
+cat <<\EOF > exp
+sort: failed to set locale
+sort: text ordering performed using simple byte comparison
+EOF
+LC_ALL=missing sort --debug /dev/null 2>out || fail=1
+# musl libc maps unknown locales to the default utf8 locale
+# with no way to determine failures. This is discussed at:
+# https://www.openwall.com/lists/musl/2016/04/02/1
+if ! grep -E 'using .*(missing|C.UTF-8).* sorting rules' out; then
+ compare exp out || fail=1
+fi
+
+
+cat <<\EOF > exp
+sort: text ordering performed using simple byte comparison
+sort: key 1 is numeric and spans multiple fields
+sort: obsolescent key '+2 -1' used; consider '-k 3,1' instead
+sort: key 2 has zero width and will be ignored
+sort: note numbers use '.' as a decimal point in this locale
+sort: option '-b' is ignored
+sort: option '-r' only applies to last-resort comparison
+EOF
+sort --debug -rb -k2n +2.2 -1b /dev/null 2>out || fail=1
+compare exp out || fail=1
+
+
+# check sign, decimal point, and grouping character warnings
+cat <<\EOF > exp
+sort: text ordering performed using simple byte comparison
+sort: key 1 is numeric and spans multiple fields
+sort: field separator ',' is treated as a group separator in numbers
+EOF
+if test $(printf '0,9\n0,8\n' | sort -ns | tail -n1) = '0,9'; then
+ # thousands_sep == ,
+ sort -nk1 -t, --debug /dev/null 2>out || fail=1
+ compare exp out || fail=1
+fi
+
+cat <<\EOF > exp
+sort: text ordering performed using simple byte comparison
+sort: key 1 is numeric and spans multiple fields
+sort: field separator '.' is treated as a decimal point in numbers
+EOF
+sort -nk1 -t. --debug /dev/null 2>out || fail=1
+compare exp out || fail=1
+
+cat <<\EOF > exp
+sort: text ordering performed using simple byte comparison
+sort: key 1 is numeric and spans multiple fields
+sort: field separator '-' is treated as a minus sign in numbers
+sort: note numbers use '.' as a decimal point in this locale
+EOF
+sort -nk1 -t- --debug /dev/null 2>out || fail=1
+compare exp out || fail=1
+
+cat <<\EOF > exp
+sort: text ordering performed using simple byte comparison
+sort: key 1 is numeric and spans multiple fields
+sort: field separator '+' is treated as a plus sign in numbers
+sort: note numbers use '.' as a decimal point in this locale
+EOF
+sort -gk1 -t+ --debug /dev/null 2>out || fail=1
+compare exp out || fail=1
+
+Exit $fail
diff --git a/tests/sort/sort-discrim.sh b/tests/sort/sort-discrim.sh
new file mode 100755
index 0000000..9912ea9
--- /dev/null
+++ b/tests/sort/sort-discrim.sh
@@ -0,0 +1,87 @@
+#!/bin/sh
+# Test discriminator-based sorting.
+
+# Copyright (C) 2012-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ sort
+
+# Set limit variables.
+getlimits_
+
+# These tests are designed for a 'sort' implementation that uses a
+# discriminator, i.e., a brief summary of a key that may have lost info,
+# but whose ordering is consistent with that of the original key.
+# The tests are useful even if 'sort' does not use this representation.
+
+# Test lexicographic sorting.
+
+# A long-enough string so that it overruns a small discriminator buffer size.
+long_prefix='aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa'
+seq -f "$long_prefix%5.0f" 10000 > exp || fail=1
+sort -R exp | LC_ALL=C sort > out || fail=1
+compare exp out || fail=1
+
+
+# Test numeric sorting.
+
+# These tests are designed for an internal representation that ordinarily
+# looks at the number plus two decimal digits, but if -h is
+# used it looks at one decimal place plus a 4-bit SI prefix value.
+# In both cases, there's an extra factor of 2 for the sign.
+max_int200=$(expr $UINTMAX_MAX / 200) &&
+max_frac200=$(printf '%.2d' $(expr $UINTMAX_MAX / 2 % 100)) &&
+max_int320=$(expr $UINTMAX_MAX / 320) &&
+max_frac320=$(expr $UINTMAX_MAX / 32 % 10) &&
+{ printf -- "\
+ -$UINTMAX_OFLOW
+ -$UINTMAX_MAX
+ -${max_int200}0.1
+ -${max_int200}0
+ -${max_int200}0.0
+ -${max_int320}0.1
+ -${max_int320}0
+ -${max_int320}0.0
+ -$max_int200.${max_frac200}1
+ -$max_int200.$max_frac200
+ -$max_int320.${max_frac320}1
+ -$max_int320.$max_frac320
+" &&
+ seq -- -10 .001 10 &&
+ printf "\
+ $max_int320
+ $max_int320.$max_frac320
+ $max_int320.${max_frac320}1
+ $max_int200
+ $max_int200.$max_frac200
+ $max_int200.${max_frac200}1
+ ${max_int320}0
+ ${max_int320}0.0
+ ${max_int320}0.1
+ ${max_int200}0
+ ${max_int200}0.0
+ ${max_int200}0.1
+ $UINTMAX_MAX
+ $UINTMAX_OFLOW
+"
+} > exp || fail=1
+
+for opts in -n -h; do
+ sort -R exp | LC_ALL=C sort $opts > out || fail=1
+ compare exp out || fail=1
+done
+
+Exit $fail
diff --git a/tests/sort/sort-exit-early.sh b/tests/sort/sort-exit-early.sh
new file mode 100755
index 0000000..bd012a9
--- /dev/null
+++ b/tests/sort/sort-exit-early.sh
@@ -0,0 +1,37 @@
+#!/bin/sh
+# Test 'sort' exits early on inaccessible inputs or output
+
+# Copyright (C) 2012-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ sort
+skip_if_root_
+
+SORT_FAILURE=2
+
+# Check output is writable before starting to sort
+touch input
+chmod a-w input
+returns_ $SORT_FAILURE timeout 10 sort -o input || fail=1
+
+# Check all inputs are readable before starting to sort
+# Also ensure the output isn't created in this case
+touch output
+chmod a-r output
+returns_ $SORT_FAILURE timeout 10 sort -o typo - output || fail=1
+test -e typo && fail=1
+
+Exit $fail
diff --git a/tests/sort/sort-files0-from.pl b/tests/sort/sort-files0-from.pl
new file mode 100755
index 0000000..56b28c0
--- /dev/null
+++ b/tests/sort/sort-files0-from.pl
@@ -0,0 +1,96 @@
+#!/usr/bin/perl
+# Exercise sort's --files0-from option.
+# FIXME: keep this file in sync with tests/du/files0-from.
+
+# Copyright (C) 2006-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+use strict;
+
+(my $program_name = $0) =~ s|.*/||;
+
+my $prog = 'sort';
+
+# Turn off localization of executable's output.
+@ENV{qw(LANGUAGE LANG LC_ALL)} = ('C') x 3;
+
+my @Tests =
+ (
+ # invalid extra command line argument
+ ['f-extra-arg', '--files0-from=- no-such', {IN=>"a"}, {EXIT=>2},
+ {ERR => "$prog: extra operand 'no-such'\n"
+ . "file operands cannot be combined with --files0-from\n"
+ . "Try '$prog --help' for more information.\n"}
+ ],
+
+ # missing input file
+ ['missing', '--files0-from=missing', {EXIT=>2},
+ {ERR => "$prog: open failed: missing: "
+ . "No such file or directory\n"}],
+
+ # input file name of '-'
+ ['minus-in-stdin', '--files0-from=-', '<', {IN=>{f=>'-'}}, {EXIT=>2},
+ {ERR => "$prog: when reading file names from stdin, no file name of"
+ . " '-' allowed\n"}],
+
+ # empty input, regular file
+ ['empty', '--files0-from=@AUX@', {AUX=>''}, {EXIT=>2},
+ {ERR_SUBST => 's/no input from.+$//'}, {ERR => "$prog: \n"}],
+
+ # empty input, from non-regular file
+ ['empty-nonreg', '--files0-from=/dev/null', {EXIT=>2},
+ {ERR => "$prog: no input from '/dev/null'\n"}],
+
+ # one NUL
+ ['nul-1', '--files0-from=-', '<', {IN=>"\0"}, {EXIT=>2},
+ {ERR => "$prog: -:1: invalid zero-length file name\n"}],
+
+ # two NULs
+ # Note that the behavior here differs from 'wc' in that the
+ # first zero-length file name is treated as fatal, so there
+ # is only one line of diagnostic output.
+ ['nul-2', '--files0-from=-', '<', {IN=>"\0\0"}, {EXIT=>2},
+ {ERR => "$prog: -:1: invalid zero-length file name\n"}],
+
+ # one file name, no NUL
+ ['1', '--files0-from=-', '<',
+ {IN=>{f=>"g"}}, {AUX=>{g=>'a'}}, {OUT=>"a\n"} ],
+
+ # one file name, with NUL
+ ['1a', '--files0-from=-', '<',
+ {IN=>{f=>"g\0"}}, {AUX=>{g=>'a'}}, {OUT=>"a\n"} ],
+
+ # two file names, no final NUL
+ ['2', '--files0-from=-', '<',
+ {IN=>{f=>"g\0g"}}, {AUX=>{g=>'a'}}, {OUT=>"a\na\n"} ],
+
+ # two file names, with final NUL
+ ['2a', '--files0-from=-', '<',
+ {IN=>{f=>"g\0g\0"}}, {AUX=>{g=>'a'}}, {OUT=>"a\na\n"} ],
+
+ # Ensure that $prog does nothing when there is a zero-length filename.
+ # Note that the behavior here differs from 'wc' in that the
+ # first zero-length file name is treated as fatal, so there
+ # should be no output on STDOUT.
+ ['zero-len', '--files0-from=-', '<',
+ {IN=>{f=>"\0g\0"}}, {AUX=>{g=>''}},
+ {ERR => "$prog: -:1: invalid zero-length file name\n"}, {EXIT=>2} ],
+ );
+
+my $save_temps = $ENV{DEBUG};
+my $verbose = $ENV{VERBOSE};
+
+my $fail = run_tests ($program_name, $prog, \@Tests, $save_temps, $verbose);
+exit $fail;
diff --git a/tests/sort/sort-float.sh b/tests/sort/sort-float.sh
new file mode 100755
index 0000000..5570968
--- /dev/null
+++ b/tests/sort/sort-float.sh
@@ -0,0 +1,90 @@
+#!/bin/sh
+# Ensure sort -g sorts floating point limits correctly
+
+# Copyright (C) 2010-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ sort
+
+# Return 0 if LDBL_MIN is smaller than DBL_MIN, else 1.
+# Dissect numbers like these, comparing first exponent, then
+# whole part of mantissa, then fraction, until finding enough
+# of a difference to determine the relative order of the numbers.
+# These are "reversed":
+# $ ./getlimits |grep DBL_MIN
+# DBL_MIN=2.225074e-308
+# LDBL_MIN=2.004168e-292
+#
+# These are in the expected order:
+# $ ./getlimits|grep DBL_MIN
+# DBL_MIN=2.225074e-308
+# LDBL_MIN=3.362103e-4932
+
+dbl_minima_order()
+{
+ LC_ALL=C getlimits_
+ set -- $(echo $LDBL_MIN | tr .e- ' ')
+ local ldbl_whole=$1 ldbl_frac=$2 ldbl_exp=$3
+
+ set -- $(echo $DBL_MIN |tr .e- ' ')
+ local dbl_whole=$1 dbl_frac=$2 dbl_exp=$3
+
+ test "$dbl_exp" -lt "$ldbl_exp" && return 0
+ test "$ldbl_exp" -lt "$dbl_exp" && return 1
+ test "$ldbl_whole" -lt "$dbl_whole" && return 0
+ test "$dbl_whole" -lt "$ldbl_whole" && return 1
+ test "$ldbl_frac" -le "$dbl_frac" && return 0
+ return 1
+}
+
+# On some systems, DBL_MIN < LDBL_MIN. Detect that.
+dbl_minima_order; reversed=$?
+
+for LOC in C $LOCALE_FR; do
+
+ LC_ALL=$LOC getlimits_
+
+ # If DBL_MIN happens to be smaller than LDBL_MIN, swap them,
+ # so that out expected output is sorted.
+ if test $reversed = 1; then
+ t=$LDBL_MIN
+ LDBL_MIN=$DBL_MIN
+ DBL_MIN=$t
+ fi
+
+ printf -- "\
+-$LDBL_MAX
+-$DBL_MAX
+-$FLT_MAX
+-$FLT_MIN
+-$DBL_MIN
+-$LDBL_MIN
+0
+$LDBL_MIN
+$DBL_MIN
+$FLT_MIN
+$FLT_MAX
+$DBL_MAX
+$LDBL_MAX
+" |
+ grep '^[0-9.,e+-]*$' > exp # restrict to numeric just in case
+
+ tac exp | LC_ALL=$LOC sort -sg > out || fail=1
+
+ compare exp out || fail=1
+done
+
+Exit $fail
diff --git a/tests/sort/sort-h-thousands-sep.sh b/tests/sort/sort-h-thousands-sep.sh
new file mode 100755
index 0000000..5d1ff4f
--- /dev/null
+++ b/tests/sort/sort-h-thousands-sep.sh
@@ -0,0 +1,50 @@
+#!/bin/sh
+# exercise 'sort -h' in locales where thousands separator is blank
+
+# Copyright (C) 2016-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ sort
+
+TEST_LOCALE='sv_SE'
+
+test "$(LC_ALL="$TEST_LOCALE" locale thousands_sep)" = ' ' ||
+ skip_ 'The Swedish locale with blank thousands separator is unavailable.'
+
+tee exp1 exp3 > in << _EOF_
+1 1k 1 M 4 003 1M
+2k 2M 2 k 4 002 2
+3M 3 3 G 4 001 3k
+_EOF_
+
+cat > exp2 << _EOF_
+3M 3 3 G 4 001 3k
+1 1k 1 M 4 003 1M
+2k 2M 2 k 4 002 2
+_EOF_
+
+cat > exp5 << _EOF_
+3M 3 3 G 4 001 3k
+2k 2M 2 k 4 002 2
+1 1k 1 M 4 003 1M
+_EOF_
+
+for i in 1 2 3 5; do
+ LC_ALL="$TEST_LOCALE" sort -h -k $i "in" > "out${i}" || fail=1
+ compare "exp${i}" "out${i}" || fail=1
+done
+
+Exit $fail
diff --git a/tests/sort/sort-merge-fdlimit.sh b/tests/sort/sort-merge-fdlimit.sh
new file mode 100755
index 0000000..7dda7f8
--- /dev/null
+++ b/tests/sort/sort-merge-fdlimit.sh
@@ -0,0 +1,79 @@
+#!/bin/sh
+# Test whether sort avoids opening more file descriptors than it is
+# allowed when merging files.
+
+# Copyright (C) 2009-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ sort
+
+mkdir in err || framework_failure_
+
+
+for i in $(seq 17); do
+ echo $i >in/$i
+done
+seq 17 >some-data
+
+# When these tests are run inside the automated testing framework, they
+# have one less available file descriptor than when run outside the
+# automated testing framework. If a test with a batch size of b fails
+# inside the ATF, then the same test with batch size b+1 may pass outside
+# the ATF but fail inside it.
+
+# The default batch size (nmerge) is 16.
+(ulimit -n 19 \
+ && sort -m --batch-size=16 in/* 2>err/merge-default-err \
+ || ! grep "open failed" err/merge-default-err) || fail=1
+
+# If sort opens a file to sort by random hashes of keys,
+# it needs to consider this file against its limit on open file
+# descriptors. Test once with the default random source
+# and once with an explicit source.
+for randsource in '' --random-source=some-data; do
+ (ulimit -n 20 \
+ && sort -mR $randsource --batch-size=16 in/* 2>err/merge-random-err \
+ || ! grep "open failed" err/merge-random-err) || fail=1
+done
+
+# 'sort -m' should work in a limited file descriptor
+# environment when the output is repeatedly one of its inputs.
+# In coreutils 8.7 and earlier, 'sort' would dump core on this test.
+#
+# This test uses 'exec' to redirect file descriptors rather than
+# ordinary redirection on the 'sort' command. This is intended to
+# work around bugs in OpenBSD /bin/sh, and some other sh variants,
+# that squirrel away file descriptors before closing them; see
+# <https://lists.gnu.org/r/bug-tar/2010-10/msg00075.html>.
+# This test finds the bug only with shells that do not close FDs on
+# exec, and will miss the bug (if present) on other shells, but it's
+# not easy to fix this without running afoul of the OpenBSD-like sh bugs.
+#
+# This script uses 'ulimit -n 10' with 7, 8 and 9 open
+# to limit 'sort' to at most 7 open files:
+# stdin, stdout, stderr, two input and one output files when merging,
+# and an extra. The extra is for old-fashioned platforms like Solaris 10
+# where opening a temp file also requires opening /dev/urandom to
+# calculate the temp file's name.
+(seq 6 && echo 6) >exp || framework_failure_
+echo 6 >out || framework_failure_
+(exec 3<&- 4<&- 5<&- 6<&- 7</dev/null 8<&7 9<&7 &&
+ ulimit -n 10 &&
+ sort -n -m --batch-size=7 -o out out in/1 in/2 in/3 in/4 in/5 out
+) &&
+compare exp out || fail=1
+
+Exit $fail
diff --git a/tests/sort/sort-merge.pl b/tests/sort/sort-merge.pl
new file mode 100755
index 0000000..bd439ef
--- /dev/null
+++ b/tests/sort/sort-merge.pl
@@ -0,0 +1,84 @@
+#!/usr/bin/perl
+# Test "sort -m".
+
+# Copyright (C) 2002-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+use strict;
+
+my $limits = getlimits ();
+
+(my $program_name = $0) =~ s|.*/||;
+my $prog = 'sort';
+
+# Turn off localization of executable's output.
+@ENV{qw(LANGUAGE LANG LC_ALL)} = ('C') x 3;
+
+# three empty files and one that says 'foo'
+my @inputs = (+(map{{IN=> {"empty$_"=> ''}}}1..3), {IN=> {foo=> "foo\n"}});
+
+my $big_input = "aaa\n" x 1024;
+
+# don't need to check for existence, since we're running in a temp dir
+my $badtmp = 'does/not/exist';
+
+my $bigint = $limits->{UINTMAX_OFLOW};
+
+my @Tests =
+ (
+ ['m1', '-m', @inputs, {OUT=>"foo\n"}],
+
+ # check validation of --batch-size option
+ ['nmerge-0', "-m --batch-size=0", @inputs,
+ {ERR=>"$prog: invalid --batch-size argument '0'\n".
+ "$prog: minimum --batch-size argument is '2'\n"}, {EXIT=>2}],
+
+ ['nmerge-1', "-m --batch-size=1", @inputs,
+ {ERR=>"$prog: invalid --batch-size argument '1'\n".
+ "$prog: minimum --batch-size argument is '2'\n"}, {EXIT=>2}],
+
+ ['nmerge-neg', "-m --batch-size=-1", @inputs,
+ {ERR=>"$prog: invalid --batch-size argument '-1'\n"}, {EXIT=>2}],
+
+ ['nmerge-nan', "-m --batch-size=a", @inputs,
+ {ERR=>"$prog: invalid --batch-size argument 'a'\n"}, {EXIT=>2}],
+
+ ['nmerge-big', "-m --batch-size=$bigint", @inputs,
+ {ERR_SUBST=>'s/(current rlimit is) \d+/$1/'},
+ {ERR=>"$prog: --batch-size argument '$bigint' too large\n".
+ "$prog: maximum --batch-size argument with current rlimit is\n"},
+ {EXIT=>2}],
+
+ # This should work since nmerge >= the number of input files
+ ['nmerge-yes', "-m --batch-size=4 -T$badtmp", @inputs, {OUT=>"foo\n"}],
+
+ # this should fail since nmerge < # of input files, so
+ # temp files are needed
+ ['nmerge-no', "-m --batch-size=2 -T$badtmp", @inputs,
+ {ERR_SUBST=>"s|': .*|':|"},
+ {ERR=>"$prog: cannot create temporary file in '$badtmp':\n"},
+ {EXIT=>2}],
+
+ # This used to fail because setting batch-size without also setting
+ # buffer size would cause the buffer size to be set to the minimum.
+ ['batch-size', "--batch-size=16 -T$badtmp", {IN=> {big=> $big_input}},
+ {OUT=>$big_input}],
+ );
+
+my $save_temps = $ENV{DEBUG};
+my $verbose = $ENV{VERBOSE};
+
+my $fail = run_tests ($program_name, $prog, \@Tests, $save_temps, $verbose);
+exit $fail;
diff --git a/tests/sort/sort-month.sh b/tests/sort/sort-month.sh
new file mode 100755
index 0000000..4fa7464
--- /dev/null
+++ b/tests/sort/sort-month.sh
@@ -0,0 +1,34 @@
+#!/bin/sh
+# Test sorting of abbreviated months from the locale
+
+# Copyright (C) 2010-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ sort
+
+locale --version >/dev/null 2>&1 ||
+ skip_ 'The locale utility is not present'
+
+# C will be used if the locale is not present
+for LOC in "$LOCALE_FR" "$LOCALE_FR_UTF8" "ja_JP.utf8"; do
+ mon="$(LC_ALL=$LOC locale abmon 2>/dev/null);"
+ smon=$(LC_ALL=$LOC locale abmon 2>/dev/null |
+ tr ';' '\n' | shuf | nl | LC_ALL=$LOC sort -k2,2M |
+ cut -f2 | tr '\n' ';')
+ test "$mon" = "$smon" || { fail=1; break; }
+done
+
+Exit $fail
diff --git a/tests/sort/sort-rand.sh b/tests/sort/sort-rand.sh
new file mode 100755
index 0000000..a80a767
--- /dev/null
+++ b/tests/sort/sort-rand.sh
@@ -0,0 +1,52 @@
+#!/bin/sh
+# Ensure that sort --sort-random doesn't sort.
+
+# Copyright (C) 2005-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ sort
+
+seq 100 > in || framework_failure_
+
+
+sort --random-sort in > out || fail=1
+
+# Fail if the input is the same as the output.
+# This is a probabilistic test :-)
+# However, the odds of failure are very low: 1 in 100! (~ 1 in 10^158)
+compare in out > /dev/null && { fail=1; echo "not random?" 1>&2; }
+
+# Fail if the sorted output is not the same as the input.
+sort -n out > out1
+compare in out1 || { fail=1; echo "not a permutation" 1>&2; }
+
+# If locale is available then use it to find a random non-C locale.
+if (locale --version) > /dev/null 2>&1; then
+ locale=$(locale -a | sort --random-sort | $AWK '/^.._/{print;exit}')
+ LC_ALL=$locale sort --random-sort in > out1 || fail=1
+ LC_ALL=$locale sort --random-sort in > out2 || fail=1
+
+ # Fail if the output "randomly" is the same twice in a row.
+ compare out1 out2 > /dev/null &&
+ { fail=1; echo "not random with LC_ALL=$locale" 1>&2; }
+
+ # Fail if the sorted output is not the same as the input.
+ sort -n out > out1
+ compare in out1 ||
+ { fail=1; echo "not a permutation with LC_ALL=$locale" 1>&2; }
+fi
+
+Exit $fail
diff --git a/tests/sort/sort-spinlock-abuse.sh b/tests/sort/sort-spinlock-abuse.sh
new file mode 100755
index 0000000..e590213
--- /dev/null
+++ b/tests/sort/sort-spinlock-abuse.sh
@@ -0,0 +1,48 @@
+#!/bin/sh
+# trigger a bug that would make parallel sort use 100% of one or more
+# CPU while blocked on output.
+
+# Copyright (C) 2010-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ sort
+
+# This isn't terribly expensive, but it must not be run under heavy load.
+# Since the "very expensive" tests are already run only with -j1, adding
+# this test to the list ensures it still gets _some_ (albeit minimal)
+# coverage while not causing false-positive failures in day to day runs.
+very_expensive_
+
+grep '^#define HAVE_PTHREAD_T 1' "$CONFIG_HEADER" > /dev/null ||
+ skip_ 'requires pthreads'
+
+# Terminate any background processes
+cleanup_() { kill $pid 2>/dev/null && wait $pid; }
+
+seq 100000 > in || framework_failure_
+mkfifo_or_skip_ fifo
+
+# Arrange for sort to require 8.0+ seconds of wall-clock time,
+# while actually using far less than 1 second of CPU time.
+(for i in $(seq 80); do read line; echo $i; sleep .1; done
+ cat > /dev/null) < fifo & pid=$!
+
+# However, under heavy load, it can easily take more than
+# one second of CPU time, so set a permissive limit:
+ulimit -t 7
+sort --parallel=2 in > fifo || fail=1
+
+Exit $fail
diff --git a/tests/sort/sort-stale-thread-mem.sh b/tests/sort/sort-stale-thread-mem.sh
new file mode 100755
index 0000000..27d92c8
--- /dev/null
+++ b/tests/sort/sort-stale-thread-mem.sh
@@ -0,0 +1,52 @@
+#!/bin/sh
+# Trigger a bug that would cause 'sort' to reference stale thread stack memory.
+
+# Copyright (C) 2010-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+# written by Jim Meyering and Paul Eggert
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ sort
+
+very_expensive_
+require_valgrind_
+
+grep '^#define HAVE_PTHREAD_T 1' "$CONFIG_HEADER" > /dev/null ||
+ skip_ 'requires pthreads'
+
+# gensort output seems to trigger the failure more often,
+# so prefer gensort if it is available.
+(gensort -a 10000 in) 2>/dev/null ||
+ seq -f %-98f 10000 | shuf > in ||
+ framework_failure_
+
+# On Fedora-17-beta (valgrind-3.7.0-2.fc17.x86_64), this evokes two complaints
+# that a conditional jump or move depends on uninitialized values,
+# each originating from _dl_start.
+valgrind --quiet --error-exitcode=3 sort --version > /dev/null ||
+ framework_failure_ 'valgrind fails for trivial sort invocation'
+
+# With the bug, 'sort' would fail under valgrind about half the time,
+# on some circa-2010 multicore Linux platforms. Run the test 100 times
+# so that the probability of missing the bug should be about 1 in
+# 2**100 on these hosts.
+for i in $(seq 100); do
+ valgrind --quiet --error-exitcode=3 \
+ sort -S 100K --parallel=2 in > /dev/null ||
+ { fail=$?; echo iteration $i failed; Exit $fail; }
+done
+
+Exit $fail
diff --git a/tests/sort/sort-u-FMR.sh b/tests/sort/sort-u-FMR.sh
new file mode 100755
index 0000000..71a2186
--- /dev/null
+++ b/tests/sort/sort-u-FMR.sh
@@ -0,0 +1,29 @@
+#!/bin/sh
+# Before 8.19, this would trigger a free-memory read.
+
+# Copyright (C) 2012-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ sort
+require_valgrind_
+
+{ echo 0; printf '%0900d\n' 1; } > in || framework_failure_
+
+valgrind --error-exitcode=1 sort --p=1 -S32b -u in > out || fail=1
+
+compare in out || fail=1
+
+Exit $fail
diff --git a/tests/sort/sort-unique-segv.sh b/tests/sort/sort-unique-segv.sh
new file mode 100755
index 0000000..8e332bb
--- /dev/null
+++ b/tests/sort/sort-unique-segv.sh
@@ -0,0 +1,48 @@
+#!/bin/sh
+# parallel sort with --unique (-u) would segfault
+
+# Copyright (C) 2010-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ sort
+
+grep '^#define HAVE_PTHREAD_T 1' "$CONFIG_HEADER" > /dev/null ||
+ skip_ 'requires pthreads'
+
+cat <<\EOF > in || framework_failure_
+
+
+
+
+
+
+
+z
+zzzzzz
+zzzzzzz
+zzzzzzz
+zzzzzzz
+zzzzzzzzz
+zzzzzzzzzzz
+zzzzzzzzzzzz
+EOF
+
+sort --parallel=1 -u in > exp || fail=1
+
+sort --parallel=2 -u -S 10b < in > out || fail=1
+compare exp out || fail=1
+
+Exit $fail
diff --git a/tests/sort/sort-unique.sh b/tests/sort/sort-unique.sh
new file mode 100755
index 0000000..df5b174
--- /dev/null
+++ b/tests/sort/sort-unique.sh
@@ -0,0 +1,42 @@
+#!/bin/sh
+# Test 'sort -u'.
+
+# Copyright (C) 2010-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ sort
+
+cat > in <<\EOF
+1
+2
+1
+3
+EOF
+
+cat > exp <<\EOF
+1
+2
+3
+EOF
+
+for LOC in C "$LOCALE_FR" "$LOCALE_FR_UTF8"; do
+ test -z "$LOC" && continue
+
+ LC_ALL=$LOC sort -u in > out || { fail=1; break; }
+ compare exp out || { fail=1; break; }
+done
+
+Exit $fail
diff --git a/tests/sort/sort-version.sh b/tests/sort/sort-version.sh
new file mode 100755
index 0000000..9a02729
--- /dev/null
+++ b/tests/sort/sort-version.sh
@@ -0,0 +1,114 @@
+#!/bin/sh
+# exercise sort's --sort=version option
+
+# Copyright (C) 2008-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ sort
+
+cat > in << _EOF_
+gcc-c++-10.fc9.tar.gz
+gcc-c++-10.8.12-0.7rc2.fc9.tar.bz2
+glibc-2-0.1.beta1.fc10.rpm
+glibc-common-5-0.2.beta2.fc9.ebuild
+glibc-common-5-0.2b.deb
+glibc-common-11b.ebuild
+glibc-common-11-0.6rc2.ebuild
+libstdc++-0.5.8.11-0.7rc2.fc10.tar.gz
+libstdc++-4a.fc8.tar.gz
+libstdc++-4.10.4.20040204svn.rpm
+libstdc++-devel-3.fc8.ebuild
+libstdc++-devel-3a.fc9.tar.gz
+libstdc++-devel-8.fc8.deb
+libstdc++-devel-8.6.2-0.4b.fc8
+nss_ldap-1-0.2b.fc9.tar.bz2
+nss_ldap-1-0.6rc2.fc8.tar.gz
+nss_ldap-1.0-0.1a.tar.gz
+nss_ldap-10beta1.fc8.tar.gz
+nss_ldap-10.11.8.6.20040204cvs.fc10.ebuild
+string start 5.0.0 end of str
+string start 5.1.0 end of str
+string start 5.10.0 end of str
+string start 5.2.0 end of str
+string start 5.20.0 end of str
+string start 5.3.0 end of str
+string start 5.30.0 end of str
+string start 5.4.0 end of str
+string start 5.40.0 end of str
+string start 5.5.0 end of str
+string start 5.50.0 end of str
+string start 5.6.0 end of str
+string start 5.60.0 end of str
+string start 5.7.0 end of str
+string start 5.70.0 end of str
+string start 5.8.0 end of str
+string start 5.80.0 end of str
+string start 5.9.0 end of str
+string start 5.90.0 end of str
+string start 5.04.0 end of str
+_EOF_
+
+cat > exp << _EOF_
+gcc-c++-10.fc9.tar.gz
+gcc-c++-10.8.12-0.7rc2.fc9.tar.bz2
+glibc-2-0.1.beta1.fc10.rpm
+glibc-common-5-0.2.beta2.fc9.ebuild
+glibc-common-5-0.2b.deb
+glibc-common-11b.ebuild
+glibc-common-11-0.6rc2.ebuild
+libstdc++-0.5.8.11-0.7rc2.fc10.tar.gz
+libstdc++-4a.fc8.tar.gz
+libstdc++-4.10.4.20040204svn.rpm
+libstdc++-devel-3.fc8.ebuild
+libstdc++-devel-3a.fc9.tar.gz
+libstdc++-devel-8.fc8.deb
+libstdc++-devel-8.6.2-0.4b.fc8
+nss_ldap-1-0.2b.fc9.tar.bz2
+nss_ldap-1-0.6rc2.fc8.tar.gz
+nss_ldap-1.0-0.1a.tar.gz
+nss_ldap-10beta1.fc8.tar.gz
+nss_ldap-10.11.8.6.20040204cvs.fc10.ebuild
+string start 5.0.0 end of str
+string start 5.1.0 end of str
+string start 5.2.0 end of str
+string start 5.3.0 end of str
+string start 5.4.0 end of str
+string start 5.04.0 end of str
+string start 5.5.0 end of str
+string start 5.6.0 end of str
+string start 5.7.0 end of str
+string start 5.8.0 end of str
+string start 5.9.0 end of str
+string start 5.10.0 end of str
+string start 5.20.0 end of str
+string start 5.30.0 end of str
+string start 5.40.0 end of str
+string start 5.50.0 end of str
+string start 5.60.0 end of str
+string start 5.70.0 end of str
+string start 5.80.0 end of str
+string start 5.90.0 end of str
+_EOF_
+
+sort --stable --sort=version -o out in || fail=1
+compare exp out || fail=1
+
+tr ' ' '\0' <in >in0 || framework_failure_
+sort --stable --sort=version -o out0 in0 || fail=1
+tr '\0' ' ' <out0 >out1 || framework_failure_
+compare exp out1 || fail=1
+
+Exit $fail
diff --git a/tests/sort/sort.pl b/tests/sort/sort.pl
new file mode 100755
index 0000000..46f1d7a
--- /dev/null
+++ b/tests/sort/sort.pl
@@ -0,0 +1,440 @@
+#!/usr/bin/perl
+
+# Copyright (C) 2008-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+use strict;
+
+my $limits = getlimits ();
+
+my $prog = 'sort';
+
+# Turn off localization of executable's output.
+@ENV{qw(LANGUAGE LANG LC_ALL)} = ('C') x 3;
+
+my $mb_locale = $ENV{LOCALE_FR_UTF8};
+! defined $mb_locale || $mb_locale eq 'none'
+ and $mb_locale = 'C';
+
+# Since each test is run with a file name and with redirected stdin,
+# the name in the diagnostic is either the file name or "-".
+# Normalize each diagnostic to use '-'.
+my $normalize_filename = {ERR_SUBST => 's/^$prog: .*?:/$prog: -:/'};
+
+my $no_file = "$prog: cannot read: no-file: No such file or directory\n";
+
+my @Tests =
+(
+["n1", '-n', {IN=>".01\n0\n"}, {OUT=>"0\n.01\n"}],
+["n2", '-n', {IN=>".02\n.01\n"}, {OUT=>".01\n.02\n"}],
+["n3", '-n', {IN=>".02\n.00\n"}, {OUT=>".00\n.02\n"}],
+["n4", '-n', {IN=>".02\n.000\n"}, {OUT=>".000\n.02\n"}],
+["n5", '-n', {IN=>".021\n.029\n"}, {OUT=>".021\n.029\n"}],
+
+["n6", '-n', {IN=>".02\n.0*\n"}, {OUT=>".0*\n.02\n"}],
+["n7", '-n', {IN=>".02\n.*\n"}, {OUT=>".*\n.02\n"}],
+["n8a", '-s -n -k1,1', {IN=>".0a\n.0b\n"}, {OUT=>".0a\n.0b\n"}],
+["n8b", '-s -n -k1,1', {IN=>".0b\n.0a\n"}, {OUT=>".0b\n.0a\n"}],
+["n9a", '-s -n -k1,1', {IN=>".000a\n.000b\n"}, {OUT=>".000a\n.000b\n"}],
+["n9b", '-s -n -k1,1', {IN=>".000b\n.000a\n"}, {OUT=>".000b\n.000a\n"}],
+["n10a", '-s -n -k1,1', {IN=>".00a\n.000b\n"}, {OUT=>".00a\n.000b\n"}],
+["n10b", '-s -n -k1,1', {IN=>".00b\n.000a\n"}, {OUT=>".00b\n.000a\n"}],
+["n11a", '-s -n -k1,1', {IN=>".01a\n.010\n"}, {OUT=>".01a\n.010\n"}],
+["n11b", '-s -n -k1,1', {IN=>".010\n.01a\n"}, {OUT=>".010\n.01a\n"}],
+
+# human readable suffixes
+["h1", '-h',
+ {IN=>"1Q\n1R\n1Y\n1Z\n1E\n1P\n1T\n1G\n1M\n1K\n02\n1\nY\n-1k\n-1M\n-1G\n-1T\n"
+ . "-1P\n-1E\n-1Z\n-1Y\n-1Q\n-1R\n"},
+ {OUT=>"-1Q\n-1R\n-1Y\n-1Z\n-1E\n-1P\n-1T\n-1G\n-1M\n-1k\n"
+ . "Y\n1\n02\n1K\n1M\n1G\n1T\n1P\n1E\n1Z\n1Y\n1R\n1Q\n"}],
+["h2", '-h', {IN=>"1M\n-2G\n-3K"}, {OUT=>"-2G\n-3K\n1M\n"}],
+# check that it works with powers of 1024
+["h3", '-k 2,2h -k 1,1', {IN=>"a 1G\nb 1023M\n"}, {OUT=>"b 1023M\na 1G\n"}],
+# decimal at end => allowed
+["h4", '-h', {IN=>"1.E\n2.M\n"}, {OUT=>"2.M\n1.E\n"}],
+# double decimal => ignore suffix
+["h5", '-h', {IN=>"1..2E\n2..2M\n"}, {OUT=>"1..2E\n2..2M\n"}],
+# "M" sorts before "G" regardless of the positive number attached.
+["h6", '-h', {IN=>"1GiB\n1030MiB\n"}, {OUT=>"1030MiB\n1GiB\n"}],
+# check option incompatibility
+["h7", '-hn', {IN=>""}, {OUT=>""}, {EXIT=>2},
+ {ERR=>"$prog: options '-hn' are incompatible\n"}],
+# check key processing
+["h8", '-n -k2,2h', {IN=>"1 1E\n2 2M\n"}, {OUT=>"2 2M\n1 1E\n"}],
+# SI and IEC prefixes on separate keys allowed
+["h9", '-h -k1,1 -k2,2', {IN=>"1M 1Mi\n1M 1Mi\n"}, {OUT=>"1M 1Mi\n1M 1Mi\n"}],
+# This invalid SI and IEC prefix mixture is not significant so not noticed
+["h10", '-h -k1,1 -k2,2', {IN=>"1M 2M\n2M 1Mi\n"}, {OUT=>"1M 2M\n2M 1Mi\n"}],
+
+["01a", '', {IN=>"A\nB\nC\n"}, {OUT=>"A\nB\nC\n"}],
+#
+["02a", '-c', {IN=>"A\nB\nC\n"}, {OUT=>''}],
+["02b", '-c', {IN=>"A\nC\nB\n"}, {OUT=>''}, {EXIT=>1},
+ {ERR=>"$prog: -:3: disorder: B\n"}, $normalize_filename],
+["02c", '-c -k1,1', {IN=>"a\na b\n"}, {OUT=>''}],
+["02d", '-C', {IN=>"A\nB\nC\n"}, {OUT=>''}],
+["02e", '-C', {IN=>"A\nC\nB\n"}, {OUT=>''}, {EXIT=>1}],
+# This should fail because there are duplicate keys
+["02m", '-cu', {IN=>"A\nA\n"}, {OUT=>''}, {EXIT=>1},
+ {ERR=>"$prog: -:2: disorder: A\n"}, $normalize_filename],
+["02n", '-cu', {IN=>"A\nB\n"}, {OUT=>''}],
+["02o", '-cu', {IN=>"A\nB\nB\n"}, {OUT=>''}, {EXIT=>1},
+ {ERR=>"$prog: -:3: disorder: B\n"}, $normalize_filename],
+["02p", '-cu', {IN=>"B\nA\nB\n"}, {OUT=>''}, {EXIT=>1},
+ {ERR=>"$prog: -:2: disorder: A\n"}, $normalize_filename],
+["02q", '-c -k 1,1fR', {IN=>"ABC\nABc\nAbC\nAbc\naBC\naBc\nabC\nabc\n"}],
+["02r", '-c -k 1,1fV', {IN=>"ABC\nABc\nAbC\nAbc\naBC\naBc\nabC\nabc\n"}],
+["02s", '-c -k 1,1dfR',
+ {IN=>".ABC\n.ABc.\nA.bC\nA.bc.\naB.C\naB.c.\nabC.\nabc..\n"}],
+#
+["03a", '-k1', {IN=>"B\nA\n"}, {OUT=>"A\nB\n"}],
+["03b", '-k1,1', {IN=>"B\nA\n"}, {OUT=>"A\nB\n"}],
+["03c", '-k1 -k2', {IN=>"A b\nA a\n"}, {OUT=>"A a\nA b\n"}],
+# Fail with a diagnostic when -k specifies field == 0.
+["03d", '-k0', {EXIT=>2},
+ {ERR=>"$prog: -: invalid field specification '0'\n"},
+ $normalize_filename],
+# Fail with a diagnostic when -k specifies character == 0.
+["03e", '-k1.0', {EXIT=>2},
+ {ERR=>"$prog: character offset is zero: invalid field specification '1.0'\n"}],
+["03f", '-k1.1,-k0', {EXIT=>2},
+ {ERR=>"$prog: invalid number after ',': invalid count at start of '-k0'\n"}],
+# This is ok.
+["03g", '-k1.1,1.0', {IN=>''}],
+# This is equivalent to 3f.
+["03h", '-k1.1,1', {IN=>''}],
+# This too, is equivalent to 3f.
+["03i", '-k1,1', {IN=>''}],
+#
+["04a", '-nc', {IN=>"2\n11\n"}],
+["04b", '-n', {IN=>"11\n2\n"}, {OUT=>"2\n11\n"}],
+["04c", '-k1n', {IN=>"11\n2\n"}, {OUT=>"2\n11\n"}],
+["04d", '-k1', {IN=>"11\n2\n"}, {OUT=>"11\n2\n"}],
+["04e", '-k2', {IN=>"ignored B\nz-ig A\n"}, {OUT=>"z-ig A\nignored B\n"}],
+#
+["05a", '-k1,2', {IN=>"A B\nA A\n"}, {OUT=>"A A\nA B\n"}],
+["05b", '-k1,2', {IN=>"A B A\nA A Z\n"}, {OUT=>"A A Z\nA B A\n"}],
+["05c", '-k1 -k2', {IN=>"A B A\nA A Z\n"}, {OUT=>"A A Z\nA B A\n"}],
+["05d", '-k2,2', {IN=>"A B A\nA A Z\n"}, {OUT=>"A A Z\nA B A\n"}],
+["05e", '-k2,2', {IN=>"A B Z\nA A A\n"}, {OUT=>"A A A\nA B Z\n"}],
+["05f", '-k2,2', {IN=>"A B A\nA A Z\n"}, {OUT=>"A A Z\nA B A\n"}],
+#
+["06a", '-k 1,2', {IN=>"A B\nA A\n"}, {OUT=>"A A\nA B\n"}],
+["06b", '-k 1,2', {IN=>"A B A\nA A Z\n"}, {OUT=>"A A Z\nA B A\n"}],
+["06c", '-k 1 -k 2', {IN=>"A B A\nA A Z\n"}, {OUT=>"A A Z\nA B A\n"}],
+["06d", '-k 2,2', {IN=>"A B A\nA A Z\n"}, {OUT=>"A A Z\nA B A\n"}],
+["06e", '-k 2,2', {IN=>"A B Z\nA A A\n"}, {OUT=>"A A A\nA B Z\n"}],
+["06f", '-k 2,2', {IN=>"A B A\nA A Z\n"}, {OUT=>"A A Z\nA B A\n"}],
+#
+["07a", '-k 2,3', {IN=>"9 a b\n7 a a\n"}, {OUT=>"7 a a\n9 a b\n"}],
+["07b", '-k 2,3', {IN=>"a a b\nz a a\n"}, {OUT=>"z a a\na a b\n"}],
+["07c", '-k 2,3', {IN=>"y k b\nz k a\n"}, {OUT=>"z k a\ny k b\n"}],
+["07d", '+1 -3', {IN=>"y k b\nz k a\n"}, {OUT=>"z k a\ny k b\n"}],
+# ensure a character position of 0 includes whole field
+["07e", '-k 2,3.0', {IN=>"a a b\nz a a\n"}, {OUT=>"z a a\na a b\n"}],
+# ensure fields with end position before start are ignored
+["07f", '-n -k1.3,1.1', {IN=>"a 2\nb 1\n"}, {OUT=>"a 2\nb 1\n"}],
+["07g", '-n -k2.2,1.2', {IN=>"aa 2\nbb 1\n"}, {OUT=>"aa 2\nbb 1\n"}],
+["07h", '-k1.3nb,1.3', {IN=>" a 2\n b 1\n"}, {OUT=>" a 2\n b 1\n"}],
+# ensure obsolescent key limits are handled correctly
+["07i", '-s +0 -1', {IN=>"a c\na b\n"}, {OUT=>"a c\na b\n"}],
+["07j", '-s +0 -1.0', {IN=>"a c\na b\n"}, {OUT=>"a c\na b\n"}],
+["07k", '-s +0 -1.1', {IN=>"a c\na b\n"}, {OUT=>"a c\na b\n"}],
+["07l", '-s +0 -1.2', {IN=>"a c\na b\n"}, {OUT=>"a b\na c\n"}],
+["07m", '-s +0 -1.1b', {IN=>"a c\na b\n"}, {OUT=>"a b\na c\n"}],
+#
+# report an error for '.' without following char spec
+["08a", '-k 2.,3', {EXIT=>2},
+ {ERR=>"$prog: invalid number after '.': invalid count at start of ',3'\n"}],
+# report an error for ',' without following POS2
+["08b", '-k 2,', {EXIT=>2},
+ {ERR=>"$prog: invalid number after ',': invalid count at start of ''\n"}],
+#
+# Test new -g option.
+["09a", '-g', {IN=>"1e2\n2e1\n"}, {OUT=>"2e1\n1e2\n"}],
+# Make sure -n works how we expect.
+["09b", '-n', {IN=>"1e2\n2e1\n"}, {OUT=>"1e2\n2e1\n"}],
+["09c", '-n', {IN=>"2e1\n1e2\n"}, {OUT=>"1e2\n2e1\n"}],
+["09d", '-k2g', {IN=>"a 1e2\nb 2e1\n"}, {OUT=>"b 2e1\na 1e2\n"}],
+#
+# Bug reported by Roger Peel <R.Peel@ee.surrey.ac.uk>
+["10a", '-t : -k 2.2,2.2', {IN=>":ba\n:ab\n"}, {OUT=>":ba\n:ab\n"}],
+# Equivalent to above, but using obsolescent '+pos -pos' option syntax.
+["10b", '-t : +1.1 -1.2', {IN=>":ba\n:ab\n"}, {OUT=>":ba\n:ab\n"}],
+#
+# The same as the preceding two, but with input lines reversed.
+["10c", '-t : -k 2.2,2.2', {IN=>":ab\n:ba\n"}, {OUT=>":ba\n:ab\n"}],
+# Equivalent to above, but using obsolescent '+pos -pos' option syntax.
+["10d", '-t : +1.1 -1.2', {IN=>":ab\n:ba\n"}, {OUT=>":ba\n:ab\n"}],
+# Try without -t...
+# But note that we have to count the delimiting space at the beginning
+# of each field that has it.
+["10a0", '-k 2.3,2.3', {IN=>"z ba\nz ab\n"}, {OUT=>"z ba\nz ab\n"}],
+["10a1", '-k 1.2,1.2', {IN=>"ba\nab\n"}, {OUT=>"ba\nab\n"}],
+["10a2", '-b -k 2.2,2.2', {IN=>"z ba\nz ab\n"}, {OUT=>"z ba\nz ab\n"}],
+#
+# An even simpler example demonstrating the bug.
+["10e", '-k 1.2,1.2', {IN=>"ab\nba\n"}, {OUT=>"ba\nab\n"}],
+#
+# The way sort works on these inputs (10f and 10g) seems wrong to me.
+# See https://git.sv.gnu.org/gitweb/?p=coreutils.git;a=commitdiff;h=3c467c0d223
+# POSIX doesn't seem to say one way or the other, but that's the way all
+# other sort implementations work.
+["10f", '-t : -k 1.3,1.3', {IN=>":ab\n:ba\n"}, {OUT=>":ba\n:ab\n"}],
+["10g", '-k 1.4,1.4', {IN=>"a ab\nb ba\n"}, {OUT=>"b ba\na ab\n"}],
+#
+# Exercise bug re using -b to skip trailing blanks.
+["11a", '-t: -k1,1b -k2,2', {IN=>"a\t:a\na :b\n"}, {OUT=>"a\t:a\na :b\n"}],
+["11b", '-t: -k1,1b -k2,2', {IN=>"a :b\na\t:a\n"}, {OUT=>"a\t:a\na :b\n"}],
+["11c", '-t: -k2,2b -k3,3', {IN=>"z:a\t:a\na :b\n"}, {OUT=>"z:a\t:a\na :b\n"}],
+# Before 1.22m, the first key comparison reported equality.
+# With 1.22m, they compare different: "a" sorts before "a\n",
+# and the second key spec isn't even used.
+["11d", '-t: -k2,2b -k3,3', {IN=>"z:a :b\na\t:a\n"}, {OUT=>"a\t:a\nz:a :b\n"}],
+#
+# Exercise bug re comparing '-' and integers.
+["12a", '-n -t: +1', {IN=>"a:1\nb:-\n"}, {OUT=>"b:-\na:1\n"}],
+["12b", '-n -t: +1', {IN=>"b:-\na:1\n"}, {OUT=>"b:-\na:1\n"}],
+# Try some other (e.g. 'X') invalid character.
+["12c", '-n -t: +1', {IN=>"a:1\nb:X\n"}, {OUT=>"b:X\na:1\n"}],
+["12d", '-n -t: +1', {IN=>"b:X\na:1\n"}, {OUT=>"b:X\na:1\n"}],
+# From Karl Heuer
+["13a", '+0.1n', {IN=>"axx\nb-1\n"}, {OUT=>"b-1\naxx\n"}],
+["13b", '+0.1n', {IN=>"b-1\naxx\n"}, {OUT=>"b-1\naxx\n"}],
+#
+# From Carl Johnson <carlj@cjlinux.home.org>
+["14a", '-d -u', {IN=>"mal\nmal-\nmala\n"}, {OUT=>"mal\nmala\n"}],
+# Be sure to fix the (translate && ignore) case in keycompare.
+["14b", '-f -d -u', {IN=>"mal\nmal-\nmala\n"}, {OUT=>"mal\nmala\n"}],
+#
+# Experiment with -i.
+["15a", '-i -u', {IN=>"a\na\1\n"}, {OUT=>"a\n"}],
+["15b", '-i -u', {IN=>"a\n\1a\n"}, {OUT=>"a\n"}],
+["15c", '-i -u', {IN=>"a\1\na\n"}, {OUT=>"a\1\n"}],
+["15d", '-i -u', {IN=>"\1a\na\n"}, {OUT=>"\1a\n"}],
+["15e", '-i -u', {IN=>"a\n\1\1\1\1\1a\1\1\1\1\n"}, {OUT=>"a\n"}],
+
+# This would fail (printing only the 7) for 8.6..8.18.
+# Use --parallel=1 for reproducibility, and a small buffer size
+# to let us trigger the problem with a smaller input.
+["unique-1", '--p=1 -S32b -u', {IN=>"7\n"x11 . "1\n"}, {OUT=>"1\n7\n"}],
+# Demonstrate that 8.19's key-spec-adjusting code is required.
+# These are more finicky in that they are arch-dependent.
+["unique-key-i686", '-u -k2,2 --p=1 -S32b',
+ {IN=>"a 7\n"x10 . "b 1\n"}, {OUT=>"b 1\na 7\n"}],
+["unique-key-x86_64", '-u -k2,2 --p=1 -S32b',
+ {IN=>"a 7\n"x11 . "b 1\n"}, {OUT=>"b 1\na 7\n"}],
+# Before 8.19, this would trigger a free-memory read.
+["unique-free-mem-read", '-u --p=1 -S32b',
+ {IN=>"a\n"."b"x900 ."\n"},
+ {OUT=>"a\n"."b"x900 ."\n"}],
+
+# From Erick Branderhorst -- fixed around 1.19e
+["16a", '-f',
+ {IN=>"éminence\nüberhaupt\n's-Gravenhage\naëroclub\nAag\naagtappels\n"},
+ {OUT=>"'s-Gravenhage\nAag\naagtappels\naëroclub\néminence\nüberhaupt\n"}],
+
+# This provokes a one-byte memory overrun of a malloc'd block for versions
+# of sort from textutils-1.19p and before.
+["17", '-c', {IN=>"xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx\n"}],
+
+# POSIX says -n no longer implies -b, so here we're comparing ' 9' and '10'.
+["18a", '-k1.1,1.2n', {IN=>" 901\n100\n"}, {OUT=>" 901\n100\n"}],
+
+# Just like above, because the global '-b' has no effect on the
+# key specifier when a key-specific option ('n' in this case) is used.
+["18b", '-b -k1.1,1.2n', {IN=>" 901\n100\n"}, {OUT=>" 901\n100\n"}],
+
+# Here we're comparing ' 90' and '10', because the 'b' on the key-end specifier
+# makes sort ignore leading blanks when determining that key's *end*.
+["18c", '-k1.1,1.2nb', {IN=>" 901\n100\n"}, {OUT=>"100\n 901\n"}],
+
+# Here we're comparing '9' and '10', because the 'b' on the key-start specifier
+# makes sort ignore leading blanks when determining that key's *start*.
+["18d", '-k1.1b,1.2n', {IN=>" 901\n100\n"}, {OUT=>" 901\n100\n"}],
+
+# This compares '90' and '10', as it ignores leading blanks for both
+# key start and key end.
+["18e", '-nb -k1.1,1.2', {IN=>" 901\n100\n"}, {OUT=>"100\n 901\n"}],
+
+# When ignoring leading blanks for end position, ensure blanks from
+# next field are not included in the sort. I.e., order should not change here.
+["18f", '-k1,1b', {IN=>"a y\na z\n"}, {OUT=>"a y\na z\n"}],
+
+# When ignoring leading blanks for start position, ensure blanks from
+# next field are not included in the sort. I.e., order should not change here.
+# This was noticed as an issue on fedora 8 (only in multibyte locales).
+["18g", '-k1b,1', {IN=>"a y\na z\n"}, {OUT=>"a y\na z\n"},
+ {ENV => "LC_ALL=$mb_locale"}],
+
+# This looks odd, but works properly -- 2nd keyspec is never
+# used because all lines are different.
+["19a", '+0 +1nr', {IN=>"b 2\nb 1\nb 3\n"}, {OUT=>"b 1\nb 2\nb 3\n"}],
+
+# The test *intended* by the author of the above, but using the
+# more-intuitive POSIX-style -k options.
+["19b", '-k1,1 -k2nr', {IN=>"b 2\nb 1\nb 3\n"}, {OUT=>"b 3\nb 2\nb 1\n"}],
+
+# This test failed when sort-1.22 was compiled on a Next x86 system
+# without optimization. Without optimization gcc uses the buggy version
+# of memcmp in the Next C library. With optimization, gcc uses its
+# (working) builtin version. Test case form William Lewis.
+["20a", '',
+ {IN=>"_________U__free\n_________U__malloc\n_________U__abort\n"
+ . "_________U__memcpy\n_________U__memset\n"
+ . "_________U_dyld_stub_binding_helper\n_________U__malloc\n"
+ . "_________U___iob\n_________U__abort\n_________U__fprintf\n"},
+ {OUT=>"_________U___iob\n_________U__abort\n_________U__abort\n"
+ . "_________U__fprintf\n_________U__free\n_________U__malloc\n"
+ . "_________U__malloc\n_________U__memcpy\n_________U__memset\n"
+ . "_________U_dyld_stub_binding_helper\n"}],
+
+# Demonstrate that folding changes the ordering of e.g. A, a, and _
+# because while they normally (in the C locale) collate like A, _, a,
+# when using -f, 'a' is compared as if it were 'A'.
+["21a", '', {IN=>"A\na\n_\n"}, {OUT=>"A\n_\na\n"}],
+["21b", '-f', {IN=>"A\na\n_\n"}, {OUT=>"A\na\n_\n"}],
+["21c", '-f', {IN=>"a\nA\n_\n"}, {OUT=>"A\na\n_\n"}],
+["21d", '-f', {IN=>"_\na\nA\n"}, {OUT=>"A\na\n_\n"}],
+["21e", '-f', {IN=>"a\n_\nA\n"}, {OUT=>"A\na\n_\n"}],
+["21f", '-fs', {IN=>"A\na\n_\n"}, {OUT=>"A\na\n_\n"}],
+["21g", '-fu', {IN=>"a\n_\n"}, {OUT=>"a\n_\n"}],
+
+# This test failed until 1.22f. From Zvi Har'El.
+["22a", '-k 2,2fd -k 1,1r', {IN=>"3 b\n4 B\n"}, {OUT=>"4 B\n3 b\n"}],
+["22b", '-k 2,2d -k 1,1r', {IN=>"3 b\n4 b\n"}, {OUT=>"4 b\n3 b\n"}],
+
+# This fails in Fedora 20, per Göran Uddeborg in: https://bugs.gnu.org/18540
+["23", '-s -k1,1 -t/', {IN=>"a b/x\na-b-c/x\n"}, {OUT=>"a b/x\na-b-c/x\n"},
+ {ENV => "LC_ALL=$mb_locale"}],
+
+["no-file1", 'no-file', {EXIT=>2}, {ERR=>$no_file}],
+# This test failed until 1.22f. Sort didn't give an error.
+# From Will Edgington.
+["o-no-file1", qw(-o no-file no-file), {EXIT=>2}, {ERR=>$no_file}],
+
+["create-empty", qw(-o no/such/file /dev/null), {EXIT=>2},
+ {ERR=>"$prog: open failed: no/such/file: No such file or directory\n"}],
+
+# From Paul Eggert. This was fixed in textutils-1.22k.
+["neg-nls", '-n', {IN=>"-1\n-9\n"}, {OUT=>"-9\n-1\n"}],
+
+# From Paul Eggert. This was fixed in textutils-1.22m.
+# The bug was visible only when using the internationalized sorting code
+# (i.e., not when configured with --disable-nls).
+["nul-nls", '', {IN=>"\0b\n\0a\n"}, {OUT=>"\0a\n\0b\n"}],
+
+# Paul Eggert wrote:
+# A previous version of POSIX incorrectly required that the newline
+# at the end of the input line contributed to the sort, which would
+# mean that an empty line should sort after a line starting with a tab
+# (because \t precedes \n in the ASCII collating sequence).
+# GNU 'sort' was altered to do this, but was changed back once it
+# was discovered to be a POSIX bug (and the POSIX bug was fixed).
+# Check that 'sort' conforms to the fixed POSIX, not to the buggy one.
+["use-nl", '', {IN=>"\n\t\n"}, {OUT=>"\n\t\n"}],
+
+# Specifying two -o options should evoke a failure
+["o2", qw(-o x -o y), {EXIT=>2},
+ {ERR=>"foo\n"}, {ERR_SUBST => 's/^$prog: .*/foo/'}],
+
+# Specifying incompatible options should evoke a failure.
+["incompat1", '-in', {EXIT=>2},
+ {ERR=>"$prog: options '-in' are incompatible\n"}],
+["incompat2", '-nR', {EXIT=>2},
+ {ERR=>"$prog: options '-nR' are incompatible\n"}],
+["incompat3", '-dfgiMnR', {EXIT=>2},
+ {ERR=>"$prog: options '-dfgMnR' are incompatible\n"}],
+["incompat4", qw(-c -o /dev/null), {EXIT=>2},
+ {ERR=>"$prog: options '-co' are incompatible\n"}],
+["incompat5", qw(-C -o /dev/null), {EXIT=>2},
+ {ERR=>"$prog: options '-Co' are incompatible\n"}],
+["incompat6", '-cC', {EXIT=>2},
+ {ERR=>"$prog: options '-cC' are incompatible\n"}],
+["incompat7", qw(--sort=random -n), {EXIT=>2},
+ {ERR=>"$prog: options '-nR' are incompatible\n"}],
+
+# -t '\0' is accepted, as of coreutils-5.0.91
+['nul-tab', "-k2,2 -t '\\0'",
+ {IN=>"a\0z\01\nb\0y\02\n"}, {OUT=>"b\0y\02\na\0z\01\n"}],
+
+# fields > SIZE_MAX are silently interpreted as SIZE_MAX
+["bigfield1", "-k $limits->{UINTMAX_OFLOW}",
+ {IN=>"2\n1\n"}, {OUT=>"1\n2\n"}],
+["bigfield2", "-k $limits->{SIZE_OFLOW}",
+ {IN=>"2\n1\n"}, {OUT=>"1\n2\n"}],
+
+# Using an old-style key-specifying option like +1 with an invalid
+# ordering-option character would cause sort to try to free an invalid
+# (non-malloc'd) pointer. This bug affects coreutils-6.5 through 6.9.
+['obs-inval', '+1x', {EXIT=>2},
+ {ERR=>"foo\n"}, {ERR_SUBST => 's/^$prog: .*/foo/'}],
+
+# Exercise the code that enlarges the line buffer.
+['realloc-buf', '-S1', {IN=>'a'x4000 ."\n"}, {OUT=>'a'x4000 ."\n"}],
+['realloc-buf-2', '-S1', {IN=>'a'x5 ."\n"}, {OUT=>'a'x5 ."\n"}],
+
+["sort-numeric", '--sort=numeric', {IN=>".01\n0\n"}, {OUT=>"0\n.01\n"}],
+["sort-gennum", '--sort=general-numeric',
+ {IN=>"1e2\n2e1\n"}, {OUT=>"2e1\n1e2\n"}],
+
+# -m with output file also used as an input file
+# In coreutils-7.2, this caused a segfault.
+# This test looks a little strange. Here's why:
+# since we're using "-o f", standard output will be empty, hence OUT=>''
+# We still want to ensure that the output file, "f" has expected contents,
+# hence the added CMP=> directive.
+["output-is-input", '-m -o f', {IN=> {f=> "a\n"}}, {OUT=>''},
+ {CMP=> ["a\n", {'f'=> undef}]} ],
+["output-is-input-2", '-m -o f', {OUT=>''},
+ {IN=> {f=> "a\n"}}, {IN=> {g=> "b\n"}}, {IN=> {h=> "c\n"}},
+ {CMP=> ["a\nb\nc\n", {'f'=> undef}]} ],
+["output-is-input-3", '-m -o f', {OUT=>''},
+ {IN=> {g=> "a\n"}}, {IN=> {h=> "b\n"}}, {IN=> {f=> "c\n"}},
+ {CMP=> ["a\nb\nc\n", {'f'=> undef}]} ],
+
+# --zero-terminated
+['zero-1', '-z', {IN=>"2\0001\000"}, {OUT=>"1\0002\000"}],
+['zero-2', '-z -k2,2', {IN=>"1\n2\0002\n1\000"}, {OUT=>"2\n1\0001\n2\000"}],
+['zero-3', '-zb -k2,2', {IN=>"1\n\n2\0002\n1\0"}, {OUT=>"2\n1\0001\n\n2\0"}],
+);
+
+# Add _POSIX2_VERSION=199209 to the environment of each test
+# that uses an old-style option like +1.
+foreach my $t (@Tests)
+ {
+ foreach my $e (@$t)
+ {
+ !ref $e && $e =~ /\+\d/
+ and push (@$t, {ENV=>'_POSIX2_VERSION=199209'}), last;
+ }
+ }
+
+@Tests = triple_test \@Tests;
+
+# Remember that triple_test creates from each test with exactly one "IN"
+# file two more tests (.p and .r suffix on name) corresponding to reading
+# input from a file and from a pipe. The pipe-reading test would fail
+# due to a race condition about 1 in 20 times.
+# Remove the IN_PIPE version of the "output-is-input" test above.
+# The others aren't susceptible because they have three inputs each.
+@Tests = grep {$_->[0] ne 'output-is-input.p'} @Tests;
+
+my $save_temps = $ENV{DEBUG};
+my $verbose = $ENV{VERBOSE};
+
+my $fail = run_tests ($prog, $prog, \@Tests, $save_temps, $verbose);
+exit $fail;
diff --git a/tests/split/additional-suffix.sh b/tests/split/additional-suffix.sh
new file mode 100755
index 0000000..9da8b35
--- /dev/null
+++ b/tests/split/additional-suffix.sh
@@ -0,0 +1,47 @@
+#!/bin/sh
+# show that 'split --additional-suffix=SUFFIX' works.
+
+# Copyright (C) 2012-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ split
+
+printf '1\n2\n3\n4\n5\n' > in || framework_failure_
+
+split --lines=2 --additional-suffix=.txt in > out || fail=1
+cat <<\EOF > exp-1
+1
+2
+EOF
+cat <<\EOF > exp-2
+3
+4
+EOF
+cat <<\EOF > exp-3
+5
+EOF
+
+compare exp-1 xaa.txt || fail=1
+compare exp-2 xab.txt || fail=1
+compare exp-3 xac.txt || fail=1
+
+# Additional suffix must not contain slash
+returns_ 1 split --lines=2 --additional-suffix=a/b in 2>err >out || fail=1
+grep 'contains directory separator' err || fail=1
+returns_ 1 split --lines=2 --additional-suffix=a/ in 2>err >out || fail=1
+grep 'contains directory separator' err || fail=1
+
+Exit $fail
diff --git a/tests/split/b-chunk.sh b/tests/split/b-chunk.sh
new file mode 100755
index 0000000..1e9a6f6
--- /dev/null
+++ b/tests/split/b-chunk.sh
@@ -0,0 +1,91 @@
+#!/bin/sh
+# test splitting into 3 chunks
+
+# Copyright (C) 2010-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ split
+
+# N can be greater than the file size
+# in which case no data is extracted, or empty files are written
+split -n 10 /dev/null || fail=1
+test "$(stat -c %s x* | uniq -c | sed 's/^ *//; s/ /x/')" = "10x0" || fail=1
+rm -f x??
+
+printf 'abc' > abc || framework_failure_
+printf 'a' > exp-a || framework_failure_
+printf 'b' > exp-b || framework_failure_
+printf 'c' > exp-c || framework_failure_
+printf 'ab' > exp-ab || framework_failure_
+split -n 4 abc || fail=1
+compare exp-a xaa || fail=1
+compare exp-b xab || fail=1
+compare exp-c xac || fail=1
+compare /dev/null xad || fail=1
+test ! -f xae || fail=1
+rm -f x??
+split -n 2 abc || fail=1
+compare exp-ab xaa || fail=1
+compare exp-c xab || fail=1
+test ! -f xac || fail=1
+rm -f x??
+
+# When extracting K of N where N > file size
+# no data is extracted, and no files are written
+split -n 2/3 /dev/null || fail=1
+returns_ 1 stat x?? 2>/dev/null || fail=1
+
+# Ensure --elide-empty-files is honored
+split -e -n 10 /dev/null || fail=1
+returns_ 1 stat x?? 2>/dev/null || fail=1
+
+printf '1\n2\n3\n4\n5\n' > input || framework_failure_
+printf '1\n2\n' > exp-1 || framework_failure_
+printf '3\n4' > exp-2 || framework_failure_
+printf '\n5\n' > exp-3 || framework_failure_
+
+for file in input /proc/version /sys/kernel/profiling; do
+ test -f $file || continue
+
+ for blksize in 1 2 4096; do
+ if ! test "$file" = 'input'; then
+ # For /proc like files we must be able to read all
+ # into the internal buffer to be able to determine size.
+ test "$blksize" = 4096 || continue
+ fi
+
+ split -n 3 ---io-blksize=$blksize $file > out || fail=1
+ split -n 1/3 ---io-blksize=$blksize $file > b1 || fail=1
+ split -n 2/3 ---io-blksize=$blksize $file > b2 || fail=1
+ split -n 3/3 ---io-blksize=$blksize $file > b3 || fail=1
+
+ case $file in
+ input)
+ compare exp-1 xaa || fail=1
+ compare exp-2 xab || fail=1
+ compare exp-3 xac || fail=1
+ ;;
+ esac
+
+ compare xaa b1 || fail=1
+ compare xab b2 || fail=1
+ compare xac b3 || fail=1
+ cat xaa xab xac | compare - $file || fail=1
+ test -f xad && fail=1
+ done
+done
+
+Exit $fail
diff --git a/tests/split/fail.sh b/tests/split/fail.sh
new file mode 100755
index 0000000..0884d62
--- /dev/null
+++ b/tests/split/fail.sh
@@ -0,0 +1,61 @@
+#!/bin/sh
+# split must fail when given length/count of zero.
+
+# Copyright (C) 2003-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ split
+getlimits_
+
+touch in || framework_failure_
+
+
+split -a 0 in 2> /dev/null || fail=1
+returns_ 1 split -b 0 in 2> /dev/null || fail=1
+returns_ 1 split -C 0 in 2> /dev/null || fail=1
+returns_ 1 split -l 0 in 2> /dev/null || fail=1
+returns_ 1 split -n 0 in 2> /dev/null || fail=1
+returns_ 1 split -n 1/0 in 2> /dev/null || fail=1
+returns_ 1 split -n 0/1 in 2> /dev/null || fail=1
+returns_ 1 split -n 2/1 in 2> /dev/null || fail=1
+
+# Make sure -C doesn't create empty files.
+rm -f x?? || fail=1
+echo x | split -C 1 || fail=1
+test -f xaa && test -f xab || fail=1
+test -f xac && fail=1
+
+# Make sure that the obsolete -N notation still works
+split -1 in 2> /dev/null || fail=1
+
+# Then make sure that -0 evokes a failure.
+returns_ 1 split -0 in 2> /dev/null || fail=1
+
+split --lines=$UINTMAX_MAX in || fail=1
+split --bytes=$OFF_T_MAX in || fail=1
+split --line-bytes=$OFF_T_OFLOW in || fail=1
+split --line-bytes=$SIZE_OFLOW in || fail=1
+if truncate -s$SIZE_OFLOW large; then
+ # Ensure we can split chunks of a large file on 32 bit hosts
+ split --number=$SIZE_OFLOW/$SIZE_OFLOW large >/dev/null || fail=1
+fi
+split --number=r/$INTMAX_MAX/$UINTMAX_MAX </dev/null >/dev/null || fail=1
+returns_ 1 split --number=r/$UINTMAX_OFLOW </dev/null 2>/dev/null || fail=1
+
+# Make sure that a huge obsolete option does the right thing.
+split -99999999999999999991 in || fail=1
+
+Exit $fail
diff --git a/tests/split/filter.sh b/tests/split/filter.sh
new file mode 100755
index 0000000..605721c
--- /dev/null
+++ b/tests/split/filter.sh
@@ -0,0 +1,80 @@
+#!/bin/sh
+# Exercise split's new --filter option.
+
+# Copyright (C) 2011-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ split
+require_sparse_support_ # for 'truncate --size=$LARGE'
+xz --version || skip_ 'xz required'
+
+for total_n_lines in 5 3000 20000; do
+ seq $total_n_lines > in || framework_failure_
+ for i in 2 51 598; do
+
+ # Don't create too many files/processes.
+ # Starting 10k (or even "only" 1500) processes would take a long time,
+ # and would provide little added benefit.
+ case $i:$total_n_lines in 2:5);; *) continue;; esac
+
+ split -l$i --filter='xz -1 > $FILE.xz' in out- || fail=1
+ xz -dc out-* > out || fail=1
+ compare in out || fail=1
+ rm -f out*
+ done
+ rm -f in
+done
+
+# Show how --elide-empty-files works with --filter:
+# split does not run the command (and effectively elides the file)
+# only when the output to that command would have been empty.
+split -e -n 10 --filter='xz > $FILE.xz' /dev/null || fail=1
+returns_ 1 stat x?? 2>/dev/null || fail=1
+
+# Ensure this invalid combination is flagged
+returns_ 1 split -n 1/2 --filter='true' /dev/null 2>&1 || fail=1
+
+# Ensure SIGPIPEs sent by the children don't propagate back
+# where they would result in a non zero exit from split.
+yes | head -n200K | split -b1G --filter='head -c1 >/dev/null' || fail=1
+
+# Ensure that "endless" input is ignored when all filters finish
+for mode in '' 'r/'; do
+ in_file='-'
+ in_cmd='yes'
+ if test "$mode" = ''; then
+ in_file='zero.in'
+ in_cmd='true'
+ truncate -s10T "$FILE" || continue
+ fi
+ for N in 1 2; do
+ rm -f x??.n || framework_failure_
+ $in_cmd |
+ timeout 10 split --filter='head -c1 >$FILE.n' -n $mode$N $in_file || fail=1
+ # Also ensure we get appropriate output from each filter
+ seq 1 $N | tr '0-9' 1 > stat.exp
+ stat -c%s x??.n > stat.out || framework_failure_
+ compare stat.exp stat.out || fail=1
+ done
+done
+
+# Ensure that "endless" input _is_ processed for unbounded number of filters
+for buf in 1000 1000000; do
+ returns_ 124 timeout .5 sh -c \
+ "yes | split --filter='head -c1 >/dev/null' -b $buf" || fail=1
+done
+
+Exit $fail
diff --git a/tests/split/guard-input.sh b/tests/split/guard-input.sh
new file mode 100755
index 0000000..d0a78c3
--- /dev/null
+++ b/tests/split/guard-input.sh
@@ -0,0 +1,33 @@
+#!/bin/sh
+# ensure split doesn't overwrite input with output.
+
+# Copyright (C) 2012-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ split
+
+seq 10 | tee exp-1 > xaa
+ln -s xaa in2
+ln xaa in3
+
+returns_ 1 split -C 6 xaa || fail=1
+returns_ 1 split -C 6 in2 || fail=1
+returns_ 1 split -C 6 in3 || fail=1
+returns_ 1 split -C 6 - < xaa || fail=1
+
+compare exp-1 xaa || fail=1
+
+Exit $fail
diff --git a/tests/split/l-chunk-root.sh b/tests/split/l-chunk-root.sh
new file mode 100755
index 0000000..e439bfb
--- /dev/null
+++ b/tests/split/l-chunk-root.sh
@@ -0,0 +1,44 @@
+#!/bin/sh
+# test splitting into newline delineated chunks from infinite imput
+
+# Copyright (C) 2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ split
+require_root_
+
+cwd=$(pwd)
+cleanup_() { cd /; umount "$cwd/mnt"; }
+
+# Create a file system to provide an isolated $TMPDIR
+dd if=/dev/zero of=blob bs=8192 count=200 &&
+mkdir mnt &&
+mkfs -t ext2 -F blob &&
+mount -oloop blob mnt ||
+ skip_ "insufficient mount/ext2 support"
+export TMPDIR="$cwd/mnt"
+
+# 'split' should fail eventually when
+# creating an infinitely long output file.
+
+returns_ 1 split -n l/2 /dev/zero || fail=1
+rm x??
+
+# Repeat the above, but with 1/2, not l/2:
+returns_ 1 split -n 1/2 /dev/zero || fail=1
+rm x??
+
+Exit $fail
diff --git a/tests/split/l-chunk.sh b/tests/split/l-chunk.sh
new file mode 100755
index 0000000..23c7878
--- /dev/null
+++ b/tests/split/l-chunk.sh
@@ -0,0 +1,129 @@
+#!/bin/sh
+# test splitting into newline delineated chunks (-n l/...)
+
+# Copyright (C) 2010-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ split
+
+# invalid number of chunks
+echo "split: invalid number of chunks: '1o'" > exp
+returns_ 1 split -n l/1o 2>err || fail=1
+compare exp err || fail=1
+
+rm -f x* || fail=1
+: | split -n l/1 || fail=1
+compare /dev/null xaa || fail=1
+test ! -f xab || fail=1
+
+# N can be greater than the file size
+# in which case no data is extracted, or empty files are written
+split -n l/10 /dev/null || fail=1
+test "$(stat -c %s x* | uniq -c | sed 's/^ *//; s/ /x/')" = "10x0" || fail=1
+rm x??
+
+# Ensure --elide-empty-files is honored
+split -e -n l/10 /dev/null || fail=1
+returns_ 1 stat x?? 2>/dev/null || fail=1
+
+# 80 bytes. ~ transformed to \n below
+lines=\
+12345~1~12345~1~12345~1~12345~1~12345~~~12345~1~12345~1~12345~1~12345~1~12345~1~
+
+printf "%s" "$lines" | tr '~' '\n' > in || framework_failure_
+
+echo "split: invalid chunk number: '16'" > exp
+returns_ 1 split -n l/16/15 in 2>err.t || fail=1
+sed "s/': .*/'/" < err.t > err || framework_failure_
+compare exp err || fail=1
+
+printf '%s' "\
+14 16 16 08 16 10
+14 08 08 10 14 08 08 10
+08 06 08 08 08 08 08 02 06 08 08 02
+06 08 08 02 06 08 02 06 08 02 06 08 00 08 02
+06 02 06 02 06 02 06 02 06 02 06 02 06 02 06 00 08 00 02 06 00 02
+" > exp || framework_failure_
+
+sed 's/00 *//g' exp > exp.elide_empty || framework_failure_
+
+test "$DEBUG" && test "$VERBOSE" && set +x
+for ELIDE_EMPTY in '' '-e'; do
+ for IO_BLKSIZE in 1 2 5 10 80 100; do
+ > out
+ test "$DEBUG" && printf "\n---io-blk-size=$IO_BLKSIZE $ELIDE_EMPTY\n"
+ for N in 6 8 12 15 22; do
+ rm -f x*
+
+ if test -z "$ELIDE_EMPTY"; then
+ split ---io-blksize=$IO_BLKSIZE -n l/2/$N in > chunk.k
+ returns_ 1 stat x* 2>/dev/null || fail=1
+ fi
+
+ split ---io-blksize=$IO_BLKSIZE $ELIDE_EMPTY -n l/$N in
+ echo $(stat -c "%02s" x*) >> out
+
+ if test -z "$ELIDE_EMPTY"; then
+ compare chunk.k xab || fail=1
+ fi
+
+ if test "$DEBUG"; then
+ # Output partition pattern
+ size=$(printf "%s" "$lines" | wc -c)
+ chunk_size=$(($size/$N))
+ end_size=$(($chunk_size + ($size % $N)))
+ {
+ yes "$(printf %${chunk_size}s ])" | head -n$(($N-1))
+ printf %${end_size}s ]
+ } | tr -d '\n' | sed "s/\\(^.\\{1,$size\\}\\).*/\\1/"
+ echo
+
+ # Output pattern generated for comparison
+ for s in $(stat -c "%s" x*); do
+ #s=0 transitions are not shown
+ test "$m" = "_" && m=- || m=_
+ printf "%${s}s" '' | tr ' ' $m
+ done
+ echo
+
+ # Output lines for reference
+ echo "$lines"
+ fi
+ done
+ test -z "$ELIDE_EMPTY" && EXP=exp || EXP=exp.elide_empty
+ compare out $EXP || fail=1
+ done
+done
+test "$DEBUG" && test "$VERBOSE" && set -x
+
+
+# Check extraction of particular chunks
+split -n l/13/15 in > out &&
+compare /dev/null out || fail=1
+printf '1\n12345\n' > exp || framework_failure_
+split -n l/14/15 in > out &&
+compare exp out || fail=1
+printf '1\n' > exp || framework_failure_
+split -n l/15/15 in > out &&
+compare exp out || fail=1
+
+# test input with no \n at end
+printf '12\n34\n5' > in
+printf '5' > exp
+split -n l/7/7 in > out
+compare exp out || fail=1
+
+Exit $fail
diff --git a/tests/split/line-bytes.sh b/tests/split/line-bytes.sh
new file mode 100755
index 0000000..a710136
--- /dev/null
+++ b/tests/split/line-bytes.sh
@@ -0,0 +1,87 @@
+#!/bin/sh
+# test -C, --lines-bytes
+
+# Copyright (C) 2013-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ split
+
+vm=$(get_min_ulimit_v_ split -C 'K' /dev/null) \
+ || skip_ "this shell lacks ulimit support"
+
+# Ensure memory is not allocated up front
+(ulimit -v $vm && split -C 'G' /dev/null) || fail=1
+
+
+# Ensure correct operation with various split and buffer size combinations
+
+lines=\
+1~2222~3~4
+
+printf '%s' "$lines" | tr '~' '\n' > in || framework_failure_
+
+cat <<\EOF > splits_exp
+1 1 1 1 1 1 1 1 1 1
+2 2 2 1 2 1
+2 3 2 2 1
+2 4 3 1
+2 5 3
+2 5 3
+7 3
+7 3
+9 1
+9 1
+10
+EOF
+
+seq 0 9 | tr -d '\n' > no_eol_in
+
+cat <<\EOF > no_eol_splits_exp
+1 1 1 1 1 1 1 1 1 1
+2 2 2 2 2
+3 3 3 1
+4 4 2
+5 5
+6 4
+7 3
+8 2
+9 1
+10
+10
+EOF
+
+for b in $(seq 10); do
+ > splits
+ > no_eol_splits
+ for s in $(seq 11); do
+ rm x??
+ split ---io=$b -C$s in || fail=1
+ cat x* > out || framework_failure_
+ compare in out || fail=1
+ stat -c %s x* | paste -s -d ' ' >> splits
+
+ rm x??
+ split ---io=$b -C$s no_eol_in || fail=1
+ cat x* > out || framework_failure_
+ cat xaa
+ compare no_eol_in out || fail=1
+ stat -c %s x* | paste -s -d ' ' >> no_eol_splits
+ done
+ compare splits_exp splits || fail=1
+ compare no_eol_splits_exp no_eol_splits || fail=1
+done
+
+Exit $fail
diff --git a/tests/split/lines.sh b/tests/split/lines.sh
new file mode 100755
index 0000000..16f9c69
--- /dev/null
+++ b/tests/split/lines.sh
@@ -0,0 +1,42 @@
+#!/bin/sh
+# show that 'split --lines=2' works.
+
+# Copyright (C) 2002-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ split
+
+printf '1\n2\n3\n4\n5\n' > in || framework_failure_
+
+split --lines=2 in > out || fail=1
+cat <<\EOF > exp-1
+1
+2
+EOF
+cat <<\EOF > exp-2
+3
+4
+EOF
+cat <<\EOF > exp-3
+5
+EOF
+
+compare exp-1 xaa || fail=1
+compare exp-2 xab || fail=1
+compare exp-3 xac || fail=1
+test -f xad && fail=1
+
+Exit $fail
diff --git a/tests/split/numeric.sh b/tests/split/numeric.sh
new file mode 100755
index 0000000..f0b0857
--- /dev/null
+++ b/tests/split/numeric.sh
@@ -0,0 +1,51 @@
+#!/bin/sh
+# Test --{hex,numeric}-suffixes[=from]
+
+# Copyright (C) 2012-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ split
+
+printf '1\n2\n3\n4\n5\n' > in || framework_failure_
+
+printf '%s\n' 1 2 > exp-0 || framework_failure_
+printf '%s\n' 3 4 > exp-1 || framework_failure_
+printf '%s\n' 5 > exp-2 || framework_failure_
+
+for mode in 'numeric' 'hex'; do
+
+ for start in 0 9; do
+ mode_option="--$mode-suffixes"
+ # check with and without specified start value
+ test $start != '0' && mode_option="$mode_option=$start"
+ split $mode_option --lines=2 in || fail=1
+
+ test $mode = 'hex' && format=x || format=d
+ for i in $(seq $start $(($start+2))); do
+ compare exp-$(($i-$start)) x$(printf %02$format $i) || fail=1
+ done
+ done
+
+ # Check that split failed when suffix length is not large enough for
+ # the numerical suffix start value
+ returns_ 1 split -a 3 --$mode-suffixes=1000 in 2>/dev/null || fail=1
+
+ # check invalid --$mode-suffixes start values are flagged
+ returns_ 1 split --$mode-suffixes=-1 in 2> /dev/null || fail=1
+ returns_ 1 split --$mode-suffixes=one in 2> /dev/null || fail=1
+done
+
+Exit $fail
diff --git a/tests/split/r-chunk.sh b/tests/split/r-chunk.sh
new file mode 100755
index 0000000..2d4a60f
--- /dev/null
+++ b/tests/split/r-chunk.sh
@@ -0,0 +1,64 @@
+#!/bin/sh
+# test splitting into round-robin chunks
+
+# Copyright (C) 2010-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ split
+
+# N can be greater than the file size
+# in which case no data is extracted, or empty files are written
+split -n r/10 /dev/null || fail=1
+test "$(stat -c %s x* | uniq -c | sed 's/^ *//; s/ /x/')" = "10x0" || fail=1
+rm x??
+
+# Ensure --elide-empty-files is honored
+split -e -n r/10 /dev/null || fail=1
+stat x?? 2>/dev/null && fail=1
+
+printf '1\n2\n3\n4\n5\n' > in || framework_failure_
+
+split -n r/3 in > out || fail=1
+compare /dev/null out || fail=1
+
+split -n r/1/3 in > r1 || fail=1
+split -n r/2/3 in > r2 || fail=1
+split -n r/3/3 in > r3 || fail=1
+
+printf '1\n4\n' > exp-1
+printf '2\n5\n' > exp-2
+printf '3\n' > exp-3
+
+compare exp-1 xaa || fail=1
+compare exp-2 xab || fail=1
+compare exp-3 xac || fail=1
+compare exp-1 r1 || fail=1
+compare exp-2 r2 || fail=1
+compare exp-3 r3 || fail=1
+test -f xad && fail=1
+
+# Test input without trailing \n
+printf '1\n2\n3\n4\n5' | split -n r/2/3 > out
+printf '2\n5' > exp
+compare exp out || fail=1
+
+# Ensure we fall back to appending to a file at a time
+# if we hit the limit for the number of open files.
+rm x*
+(ulimit -n 20 && yes | head -n90 | split -n r/30 ) || fail=1
+test "$(stat -c %s x* | uniq -c | sed 's/^ *//; s/ /x/')" = "30x6" || fail=1
+
+Exit $fail
diff --git a/tests/split/record-sep.sh b/tests/split/record-sep.sh
new file mode 100755
index 0000000..3827d15
--- /dev/null
+++ b/tests/split/record-sep.sh
@@ -0,0 +1,78 @@
+#!/bin/sh
+# test split with custom record separators
+
+# Copyright (C) 2015-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ split
+
+NL='
+'
+
+for sep in "$NL" '\0' ':'; do
+
+ test "$sep" = "$NL" && tr='\n' || tr="$sep"
+
+ for mode in '--lines=2' '--line-bytes=4' '--number=l/3' '--number=r/3'; do
+
+ # Generate in default mode for comparison
+ printf '1\n2\n3\n4\n5\n' > in || framework_failure_
+ split $mode in || fail=1
+ tr '\n' "$tr" < xaa > exp1
+ tr '\n' "$tr" < xab > exp2
+ tr '\n' "$tr" < xac > exp3
+
+ rm -f x??
+
+ # Generate output with specified --separator
+ printf '1\n2\n3\n4\n5\n' | tr '\n' "$tr" > in || framework_failure_
+ split $mode -t "$sep" in || fail=1
+
+ compare exp1 xaa || fail=1
+ compare exp2 xab || fail=1
+ compare exp3 xac || fail=1
+ test -f xad && fail=1
+ done
+
+done
+
+
+#
+# Test usage edge cases
+#
+
+# Should fail: '-t' requires an argument
+returns_ 1 split -t </dev/null ||
+ { warn_ "-t without argument did not trigger an error" ; fail=1 ; }
+
+# should fail: multi-character separator
+returns_ 1 split -txx </dev/null ||
+ { warn_ "-txx did not trigger an error" ; fail=1 ; }
+
+# should fail: different separators used
+returns_ 1 split -ta -tb </dev/null ||
+ { warn_ "-ta -tb did not trigger an error" ; fail=1 ; }
+
+# should fail: different separators used, including default
+returns_ 1 split -t"$NL" -tb </dev/null ||
+ { warn_ "-t\$NL -tb did not trigger an error" ; fail=1 ; }
+
+# should not fail: same separator used multiple times
+split -t: -t: </dev/null ||
+ { warn_ "-t: -t: triggered an error" ; fail=1 ; }
+
+
+Exit $fail
diff --git a/tests/split/suffix-auto-length.sh b/tests/split/suffix-auto-length.sh
new file mode 100755
index 0000000..8bbb26f
--- /dev/null
+++ b/tests/split/suffix-auto-length.sh
@@ -0,0 +1,59 @@
+#!/bin/sh
+# Test the suffix auto width functionality
+
+# Copyright (C) 2012-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ split
+
+
+# ensure auto widening is off when start number specified
+truncate -s12 file.in || framework_failure_
+returns_ 1 split file.in -b1 --numeric=89 || fail=1
+test "$(ls -1 x* | wc -l)" = 11 || fail=1
+rm -f x*
+
+# ensure auto widening works when no start num specified
+truncate -s91 file.in || framework_failure_
+for prefix in 'x' 'xx' ''; do
+ for add_suffix in '.txt' ''; do
+ split file.in "$prefix" -b1 --numeric --additional-suffix="$add_suffix" \
+ || fail=1
+ test "$(ls -1 $prefix*[0-9]*$add_suffix | wc -l)" = 91 || fail=1
+ test -e "${prefix}89$add_suffix" || fail=1
+ test -e "${prefix}9000$add_suffix" || fail=1
+ rm -f $prefix*[0-9]*$add_suffix
+ done
+done
+
+# ensure auto width with --number and start num < number of files
+# That's the single run use case which is valid to adjust suffix len
+truncate -s100 file.in || framework_failure_
+split --numeric-suffixes=1 --number=r/100 file.in || fail=1
+rm -f x*
+
+# ensure no auto width with --number and start num >= number of files
+# That's the multi run use case which is invalid to adjust suffix len
+# as that would result in an incorrect order for the total output file set
+returns_ 1 split --numeric-suffixes=100 --number=r/100 file.in || fail=1
+
+# coreutils v8.24 - v8.31 inclusive would incorrectly auto calculate
+# a suffix length that was too small, when the number of files was
+# evenly divisible by the suffix base (10,16,26).
+truncate -s0 file.in || framework_failure_
+split --numeric-suffixes --number=110 file.in || fail=1
+
+Exit $fail
diff --git a/tests/split/suffix-length.sh b/tests/split/suffix-length.sh
new file mode 100755
index 0000000..75c7bd1
--- /dev/null
+++ b/tests/split/suffix-length.sh
@@ -0,0 +1,76 @@
+#!/bin/sh
+# Show that split -a works.
+
+# Copyright (C) 2002-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ split
+
+a_z='a b c d e f g h i j k l m n o p q r s t u v w x y z'
+
+# Generate a 27-byte file
+printf %s $a_z 0 |tr -d ' ' > in || framework_failure_
+
+files=
+for i in $a_z; do
+ files="${files}xa$i "
+done
+files="${files}xba"
+
+for f in $files; do
+ printf "creating file '%s'"'\n' $f
+done > exp || framework_failure_
+
+echo split: output file suffixes exhausted \
+ > exp-too-short || framework_failure_
+
+
+# This should fail.
+split -b 1 -a 1 in 2> err && fail=1
+test -f xa || fail=1
+test -f xz || fail=1
+test -f xaa && fail=1
+test -f xaz && fail=1
+rm -f x*
+compare exp-too-short err || fail=1
+
+# With a longer suffix, it must succeed.
+split --verbose -b 1 -a 2 in > err || fail=1
+compare exp err || fail=1
+
+# Ensure that xbb is *not* created.
+test -f xbb && fail=1
+
+# Ensure that the 27 others files *were* created, and with expected contents.
+n=1
+for f in $files; do
+ expected_byte=$(cut -b $n in)
+ b=$(cat $f) || fail=1
+ test "$b" = "$expected_byte" || fail=1
+ n=$(expr $n + 1)
+done
+
+# Ensure that -a is independent of -[bCl]
+split -a2 -b1000 < /dev/null || fail=1
+split -a2 -l1000 < /dev/null || fail=1
+split -a2 -C1000 < /dev/null || fail=1
+
+# Ensure that -a fails early with a -n that is too large
+rm -f x*
+returns_ 1 split -a2 -n1000 < /dev/null || fail=1
+test -f xaa && fail=1
+
+Exit $fail
diff --git a/tests/stat/stat-birthtime.sh b/tests/stat/stat-birthtime.sh
new file mode 100755
index 0000000..8d2e661
--- /dev/null
+++ b/tests/stat/stat-birthtime.sh
@@ -0,0 +1,51 @@
+#!/bin/sh
+# ensure that stat attempts birthtime access
+
+# Copyright (C) 2010-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ stat
+
+# Whether birthtime is supported or not, it better not change even when
+# [acm]time are modified. :)
+touch a || fail=1
+btime=$(stat --format %W a) || fail=1
+atime=$(stat --format %X a) || fail=1
+mtime=$(stat --format %Y a) || fail=1
+ctime=$(stat --format %Z a) || fail=1
+
+# Wait up to 2.17s for timestamps to change.
+# ----------------------------------------
+# iterations file system resolution e.g.
+# ----------------------------------------
+# 1 nano or micro second ext4
+# 4 1 second ext3
+# 5 2 second FAT
+# ----------------------------------------
+check_timestamps_updated()
+{
+ local delay="$1"
+ sleep $delay
+ touch a || fail=1
+
+ test "x$btime" = x$(stat --format %W a) &&
+ test "x$atime" != x$(stat --format %X a) &&
+ test "x$mtime" != x$(stat --format %Y a) &&
+ test "x$ctime" != x$(stat --format %Z a)
+}
+retry_delay_ check_timestamps_updated .07 5 || fail=1
+
+Exit $fail
diff --git a/tests/stat/stat-fmt.sh b/tests/stat/stat-fmt.sh
new file mode 100755
index 0000000..df50973
--- /dev/null
+++ b/tests/stat/stat-fmt.sh
@@ -0,0 +1,47 @@
+#!/bin/sh
+# stat --format tests
+
+# Copyright (C) 2003-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ stat
+
+
+# ensure that stat properly handles a format string ending with %
+for i in $(seq 50); do
+ fmt=$(printf "%${i}s" %)
+ out=$(stat --form="$fmt" .)
+ test "$out" = "$fmt" || fail=1
+done
+
+
+# ensure QUOTING_STYLE is honored by %N
+touch "'" || framework_failure_
+# Default since v8.25
+stat -c%N \' >> out || fail=1
+# Default before v8.25
+QUOTING_STYLE=locale stat -c%N \' >> out || fail=1
+cat <<\EOF >exp
+"'"
+'\''
+EOF
+compare exp out || fail=1
+
+# ensure %H and %L modifiers are handled
+stat -c '%r %R %Hd,%Ld %Hr,%Lr' . > out || fail=1
+grep -F '?' out && fail=1
+
+Exit $fail
diff --git a/tests/stat/stat-hyphen.sh b/tests/stat/stat-hyphen.sh
new file mode 100755
index 0000000..ea65c20
--- /dev/null
+++ b/tests/stat/stat-hyphen.sh
@@ -0,0 +1,30 @@
+#!/bin/sh
+# demonstrate that stat - works and stat -f - does not.
+
+# Copyright (C) 2009-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ stat
+
+printf -- '-\n' > exp || framework_failure_
+touch f || framework_failure_
+
+stat --format=%n - < f > out || fail=1
+returns_ 1 stat -f - < f || fail=1
+
+compare exp out || fail=1
+
+Exit $fail
diff --git a/tests/stat/stat-mount.sh b/tests/stat/stat-mount.sh
new file mode 100755
index 0000000..e07e89a
--- /dev/null
+++ b/tests/stat/stat-mount.sh
@@ -0,0 +1,28 @@
+#!/bin/sh
+# Test stat -c%m
+
+# Copyright (C) 2010-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ stat
+
+stat_mnt=$(stat -c%m .) || fail=1
+case "$stat_mnt" in
+ /*) ;;
+ *) fail=1;;
+esac
+
+Exit $fail
diff --git a/tests/stat/stat-nanoseconds.sh b/tests/stat/stat-nanoseconds.sh
new file mode 100755
index 0000000..d42626e
--- /dev/null
+++ b/tests/stat/stat-nanoseconds.sh
@@ -0,0 +1,46 @@
+#!/bin/sh
+# Exercise format strings involving %:X, %:Y, etc.
+
+# Copyright (C) 2010-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+print_ver_ stat
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+
+# Set this to avoid problems with weird time zones.
+TZ=UTC0
+export TZ
+
+# Use a timestamp near the Epoch to avoid trouble with leap seconds.
+touch -d '1970-01-01 18:43:33.023456789' k || framework_failure_
+
+ls --full-time | grep 18:43:33.023456789 \
+ || skip_ this file system does not support sub-second timestamps
+
+test "$(stat -c %X k)" = 67413 || fail=1
+test "$(stat -c %.X k)" = 67413.023456789 || fail=1
+test "$(stat -c %.1X k)" = 67413.0 || fail=1
+test "$(stat -c %.3X k)" = 67413.023 || fail=1
+test "$(stat -c %.6X k)" = 67413.023456 || fail=1
+test "$(stat -c %.9X k)" = 67413.023456789 || fail=1
+test "$(stat -c %13.6X k)" = ' 67413.023456' || fail=1
+test "$(stat -c %013.6X k)" = 067413.023456 || fail=1
+test "$(stat -c %-13.6X k)" = '67413.023456 ' || fail=1
+test "$(stat -c %18.10X k)" = ' 67413.0234567890' || fail=1
+test "$(stat -c %I18.10X k)" = ' 67413.0234567890' || fail=1
+test "$(stat -c %018.10X k)" = 0067413.0234567890 || fail=1
+test "$(stat -c %-18.10X k)" = '67413.0234567890 ' || fail=1
+
+Exit $fail
diff --git a/tests/stat/stat-printf.pl b/tests/stat/stat-printf.pl
new file mode 100755
index 0000000..491fb36
--- /dev/null
+++ b/tests/stat/stat-printf.pl
@@ -0,0 +1,64 @@
+#!/usr/bin/perl
+# Test "stat --printf".
+
+# Copyright (C) 2005-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+use strict;
+
+(my $ME = $0) =~ s|.*/||;
+my $prog = 'stat';
+
+# Turn off localization of executable's output.
+@ENV{qw(LANGUAGE LANG LC_ALL)} = ('C') x 3;
+
+my @Tests =
+ (
+ # test-name, [option, option, ...] {OUT=>"expected-output"}
+ #
+ ['nl', q!--printf='\n' .!, {OUT=>"\n"}],
+ ['no-nl', "--printf=%n .", {OUT=>"."}],
+ ['pct-and-esc', q!--printf='\0%n\0' .!, {OUT=>"\0.\0"}],
+ ['backslash', q!--printf='\\\\' .!, {OUT=>"\\"}],
+ ['nul', q!--printf='\0' .!, {OUT=>"\0"}],
+ # Don't bother testing \v, since Perl doesn't handle it.
+ ['bel-etc', q!--printf='\a\b\f\n\r\t' .!, {OUT=>"\a\b\f\n\r\t"}],
+ ['octal-1', q!--printf='\012\377' .!, {OUT=>"\012\377"}],
+ ['octal-2', q!--printf='.\012a\377b' .!, {OUT=>".\012a\377b"}],
+ ['hex-1', q!--printf='\x34\xf' .!, {OUT=>"\x34\xf"}],
+ ['hex-2', q!--printf='.\x18p\xfq' .!, {OUT=>".\x18p\x0fq"}],
+ ['hex-3', q!--printf='\x' .!, {OUT=>'x'},
+ {ERR=>"$prog: warning: unrecognized escape '\\x'\n"}],
+
+ # With --format, there *is* a trailing newline.
+ ['f-nl', "--format=%n .", {OUT=>".\n"}],
+ ['f-nl2', "--format=%n . .", {OUT=>".\n.\n"}],
+
+ ['end-pct', "--printf=% .", {OUT=>"%"}],
+ ['pct-pct', "--printf=%% .", {OUT=>"%"}],
+ ['end-bs', "--printf='\\' .", {OUT=>'\\'},
+ {ERR=>"$prog: warning: backslash at end of format\n"}],
+
+ ['err-1', "--printf=%9% .", {EXIT => 1},
+ {ERR=>"$prog: '%9%': invalid directive\n"}],
+ ['err-2', "--printf=%9 .", {EXIT => 1},
+ {ERR=>"$prog: '%9': invalid directive\n"}],
+ );
+
+my $save_temps = $ENV{DEBUG};
+my $verbose = $ENV{VERBOSE};
+
+my $fail = run_tests ($ME, $prog, \@Tests, $save_temps, $verbose);
+exit $fail;
diff --git a/tests/stat/stat-slash.sh b/tests/stat/stat-slash.sh
new file mode 100755
index 0000000..16ecce8
--- /dev/null
+++ b/tests/stat/stat-slash.sh
@@ -0,0 +1,44 @@
+#!/bin/sh
+# demonstrate that stat handles trailing slashes correctly
+
+# Copyright (C) 2009-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ stat
+
+touch file || framework_failure_
+mkdir dir || framework_failure_
+ln -s file link1 || framework_failure_
+ln -s dir link2 || framework_failure_
+
+cat <<EOF > exp || framework_failure_
+link1
+symbolic link
+directory
+directory
+EOF
+
+# This failed on Solaris 9 for coreutils 8.0.
+stat --format=%n link1 > out || fail=1
+returns_ 1 stat --format=%n link1/ >> out || fail=1
+
+stat --format=%F link2 >> out || fail=1
+stat -L --format=%F link2 >> out || fail=1
+stat --format=%F link2/ >> out || fail=1
+
+compare exp out || fail=1
+
+Exit $fail
diff --git a/tests/stty/stty-invalid.sh b/tests/stty/stty-invalid.sh
new file mode 100755
index 0000000..7b65d0c
--- /dev/null
+++ b/tests/stty/stty-invalid.sh
@@ -0,0 +1,60 @@
+#!/bin/sh
+# Ensure that stty diagnoses invalid inputs, rather than silently misbehaving.
+
+# Copyright (C) 2007-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ stty
+require_controlling_input_terminal_
+require_trap_signame_
+
+trap '' TTOU # Ignore SIGTTOU
+
+
+saved_state=$(stty -g) || fail=1
+stty $saved_state || fail=1
+
+# Before coreutils-6.9.90, if stty were given an argument with 35 colons
+# separating 36 hexadecimal strings, stty would fail to diagnose as invalid
+# any number that was out of range as long as sscanf happened to
+# overflow/wrap it back into the range of the corresponding type (either
+# tcflag_t or cc_t).
+
+# For each of the following, with coreutils-6.9 and earlier,
+# stty would fail to diagnose the error on at least Solaris 10.
+hex_2_64=10000000000000000
+returns_ 1 stty $(echo $saved_state |sed 's/^[^:]*:/'$hex_2_64:/) \
+ 2>/dev/null || fail=1
+returns_ 1 stty $(echo $saved_state |sed 's/:[0-9a-f]*$/:'$hex_2_64/) \
+ 2>/dev/null || fail=1
+
+# From coreutils 5.3.0 to 8.28, the following would crash
+# due to incorrect argument handling.
+if tty -s </dev/tty; then
+ returns_ 1 stty eol -F /dev/tty || fail=1
+ returns_ 1 stty -F /dev/tty eol || fail=1
+ returns_ 1 stty -F/dev/tty eol || fail=1
+ returns_ 1 stty eol -F/dev/tty eol || fail=1
+fi
+
+# coreutils <= 9.1 would not validate speeds to ispeed or ospeed
+returns_ 1 stty ispeed 420 || fail=1
+
+# Just in case either of the above mistakenly succeeds (and changes
+# the state of our tty), try to restore the initial state.
+stty $saved_state || fail=1
+
+Exit $fail
diff --git a/tests/stty/stty-pairs.sh b/tests/stty/stty-pairs.sh
new file mode 100755
index 0000000..fd32ba2
--- /dev/null
+++ b/tests/stty/stty-pairs.sh
@@ -0,0 +1,65 @@
+#!/bin/sh
+# Make sure stty can parse most of its options - in pairs [expensive].
+
+# Copyright (C) 1998-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ stty
+
+expensive_
+
+# Make sure there's a tty on stdin.
+require_controlling_input_terminal_
+require_trap_signame_
+
+trap '' TTOU # Ignore SIGTTOU
+
+# Get the reversible settings from stty.c.
+stty_reversible_init_
+
+saved_state=.saved-state
+stty --save > $saved_state || fail=1
+stty $(cat $saved_state) || fail=1
+
+# Build a list of all boolean options stty accepts on this system.
+# Don't depend on terminal width. Put each option on its own line,
+# remove all non-boolean ones, remove 'parenb' and 'cread' explicitly,
+# then remove any leading hyphens.
+sed_del='/^speed/d;/^rows/d;/^columns/d;/ = /d;s/parenb//;s/cread//'
+options=$(stty -a | tr -s ';' '\n' | sed "s/^ //;$sed_del;s/-//g")
+
+# Take them in pairs, with and without the leading '-'.
+for opt1 in $options; do
+ for opt2 in $options; do
+
+ stty $opt1 $opt2 || fail=1
+
+ if stty_reversible_query_ "$opt1" ; then
+ stty -$opt1 $opt2 || fail=1
+ fi
+ if stty_reversible_query_ "$opt2" ; then
+ stty $opt1 -$opt2 || fail=1
+ fi
+ if stty_reversible_query_ "$opt1" \
+ && stty_reversible_query_ "$opt2" ; then
+ stty -$opt1 -$opt2 || fail=1
+ fi
+ done
+done
+
+stty $(cat $saved_state)
+
+Exit $fail
diff --git a/tests/stty/stty-row-col.sh b/tests/stty/stty-row-col.sh
new file mode 100755
index 0000000..2b336e5
--- /dev/null
+++ b/tests/stty/stty-row-col.sh
@@ -0,0 +1,91 @@
+#!/bin/sh
+# Test "stty" with rows and columns.
+
+# Copyright (C) 1998-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+# Setting this envvar to a very small value used to cause e.g., 'stty size'
+# to generate slightly different output on certain systems.
+COLUMNS=80
+export COLUMNS
+
+# Make sure we get English-language behavior.
+# See the report about a possibly-related Solaris problem by Alexandre Peshansky
+# <https://lists.gnu.org/r/bug-coreutils/2004-10/msg00035.html>.
+# Currently stty isn't localized, but it might be in the future.
+LC_ALL=C
+export LC_ALL
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ stty
+
+require_controlling_input_terminal_
+require_trap_signame_
+
+trap '' TTOU # Ignore SIGTTOU
+
+# Versions of GNU stty from shellutils-1.9.2c and earlier failed
+# tests #2 and #4 when run on SunOS 4.1.3.
+
+tests='
+1 rows_40_columns_80 40_80
+2 rows_1_columns_1 1_1
+3 rows_40_columns_80 40_80
+4 rows_1 1_80
+5 columns_1 1_1
+6 rows_40 40_1
+7 rows_1 1_1
+8 columns_80 1_80
+9 rows_30 30_80
+10 rows_0x1E 30_80
+11 rows_036 30_80
+NA LAST NA
+'
+set $tests
+
+saved_size=$(stty size) && test -n "$saved_size" \
+ || skip_ "can't get window size"
+
+# Linux virtual consoles issue an error if you
+# try to increase their size. So skip in that case.
+if test "x$saved_size" != "x0 0"; then
+ srow=$(echo $saved_size | cut -d ' ' -f1)
+ scol=$(echo $saved_size | cut -d ' ' -f2)
+ stty rows $(expr $srow + 1) cols $(expr $scol + 1) ||
+ skip_ "can't increase window size"
+fi
+
+while :; do
+ test_name=$1
+ args=$2
+ expected_result="$(echo $3|tr _ ' ')"
+ test "$args" = empty && args=''
+ test "x$args" = xLAST && break
+ args=$(echo x$args|tr _ ' '|sed 's/^x//')
+ if test "$VERBOSE" = yes; then
+ # echo "testing \$(stty $args; stty size\) = $expected_result ..."
+ echo "test $test_name... " | tr -d '\n'
+ fi
+ stty $args || exit 1
+ test x"$(stty size 2> /dev/null)" = "x$expected_result" \
+ && ok=ok || ok=FAIL fail=1
+ test "$VERBOSE" = yes && echo $ok
+ shift; shift; shift
+done
+
+set x $saved_size
+stty rows $2 columns $3 || exit 1
+
+Exit $fail
diff --git a/tests/stty/stty.sh b/tests/stty/stty.sh
new file mode 100755
index 0000000..6254ab8
--- /dev/null
+++ b/tests/stty/stty.sh
@@ -0,0 +1,98 @@
+#!/bin/sh
+# Make sure stty can parse most of its options.
+
+# Copyright (C) 1998-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+# Make sure there's a tty on stdin.
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ stty
+
+require_controlling_input_terminal_
+require_trap_signame_
+require_strace_ ioctl
+
+trap '' TTOU # Ignore SIGTTOU
+
+# Get the reversible settings from stty.c.
+stty_reversible_init_
+
+saved_state=.saved-state
+stty --save > $saved_state || fail=1
+stty $(cat $saved_state) || fail=1
+
+# This would segfault prior to sh-utils-2.0j.
+stty erase - || fail=1
+
+# Ensure "immediate" and "wait" mode supported, with and without settings
+for mode in '-drain' 'drain'; do
+ for opt in 'echo' ''; do
+ stty "$mode" $opt || fail=1
+ done
+done
+
+# These would improperly ignore invalid options through coreutils 5.2.1.
+returns_ 1 stty -F 2>/dev/null || fail=1
+returns_ 1 stty -raw -F no/such/file 2>/dev/null || fail=1
+returns_ 1 stty -raw -a 2>/dev/null || fail=1
+
+# Build a list of all boolean options stty accepts on this system.
+# Don't depend on terminal width. Put each option on its own line,
+# remove all non-boolean ones, then remove any leading hyphens.
+sed_del='/^speed/d;/^rows/d;/^columns/d;/ = /d'
+options=$(stty -a | tr -s ';' '\n' | sed "s/^ //;$sed_del;s/-//g")
+
+# Take them one at a time, with and without the leading '-'.
+for opt in $options; do
+ # 'stty parenb' and 'stty -parenb' fail with this message
+ # stty: standard input: unable to perform all requested operations
+ # on Linux 2.2.0-pre4 kernels. Also since around Linux 2.6.30
+ # other serial control settings give the same error. So skip them.
+ # Also on ppc*|sparc* glibc platforms 'icanon' gives the same error.
+ # See: https://bugs.gnu.org/7228#14
+ case $opt in
+ parenb|parodd|cmspar) continue;;
+ cstopb|crtscts|cdtrdsr|icanon) continue;;
+ esac
+
+ # This is listed as supported on FreeBSD
+ # but the ioctl returns ENOTTY.
+ test $opt = extproc && continue
+
+ stty $opt || fail=1
+
+ # Likewise, 'stty -cread' would fail, so skip that, too.
+ test $opt = cread && continue
+ if stty_reversible_query_ "$opt" ; then
+ stty -$opt || { fail=1; echo -$opt; }
+ fi
+done
+
+stty $(cat $saved_state)
+
+# Ensure we validate options before accessing the device
+strace -o log1 -e ioctl stty --version || fail=1
+n_ioctl1=$(wc -l < log1) || framework_failure_
+returns_ 1 strace -o log2 -e ioctl stty -blahblah || fail=1
+n_ioctl2=$(wc -l < log2) || framework_failure_
+test "$n_ioctl1" = "$n_ioctl2" || fail=1
+
+# Ensure we wrap output appropriately
+for W in $(seq 80 90); do
+ output_width=$(COLUMNS="$W" stty -a | wc -L)
+ test "$output_width" -le "$W" || fail=1
+done
+
+Exit $fail
diff --git a/tests/tac/tac-2-nonseekable.sh b/tests/tac/tac-2-nonseekable.sh
new file mode 100755
index 0000000..8e8075f
--- /dev/null
+++ b/tests/tac/tac-2-nonseekable.sh
@@ -0,0 +1,45 @@
+#!/bin/sh
+# ensure that tac works with non-seekable or quasi-seekable inputs
+
+# Copyright (C) 2011-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ tac
+
+echo x | tac - - > out 2> err || fail=1
+echo x > exp || framework_failure_
+compare exp out || fail=1
+compare /dev/null err || fail=1
+
+# Make sure it works on funny files in /proc and /sys.
+
+for file in /proc/version /sys/kernel/profiling; do
+ if test -r $file; then
+ cp -f $file copy &&
+ tac copy > exp1 || framework_failure_
+
+ tac $file > out1 || fail=1
+ compare exp1 out1 || fail=1
+ fi
+done
+
+# Assume timeout is due to failure to close stdin with <&-
+# which was seen on NetBSD 7.1 / x86_64
+returns_ 124 timeout 10 tac - - <&- 2>err && skip_ 'error closing stdin'
+# This failed due to heap corruption from v8.15-v8.25 inclusive.
+returns_ 1 timeout 10 tac - - <&- 2>err || fail=1
+
+Exit $fail
diff --git a/tests/tac/tac-continue.sh b/tests/tac/tac-continue.sh
new file mode 100755
index 0000000..f01a772
--- /dev/null
+++ b/tests/tac/tac-continue.sh
@@ -0,0 +1,76 @@
+#!/bin/sh
+# Ensure that tac processes all command line arguments, even
+# when it encounters an error with say the first one.
+# With coreutils-5.2.1 and earlier, this test would fail.
+
+# Copyright (C) 2004-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ tac
+
+# See if the envvar is defined.
+if test x = "x$FULL_PARTITION_TMPDIR"; then
+ skip_ "FULL_PARTITION_TMPDIR not defined"
+fi
+
+if ! test -d "$FULL_PARTITION_TMPDIR"; then
+ echo "$0: $FULL_PARTITION_TMPDIR:" \
+ "\$FULL_PARTITION_TMPDIR does not specify a directory" 1>&2
+ Exit 1
+fi
+
+fp_tmp="$FULL_PARTITION_TMPDIR/tac-cont-$$"
+cleanup_()
+{
+ # Terminate any background process
+ # and remove tmp dir
+ rm -f "$fp_tmp"
+ kill $pid 2>/dev/null && wait $pid
+}
+
+# Make sure we can create an empty file there (i.e., no shortage of inodes).
+if ! touch $fp_tmp; then
+ echo "$0: $fp_tmp: cannot create empty file" 1>&2
+ Exit 1
+fi
+
+# Make sure that we fail when trying to create a file large enough
+# to consume a non-inode block.
+if seq 1000 > $fp_tmp 2>/dev/null; then
+ echo "$0: $FULL_PARTITION_TMPDIR: not a full partition" 1>&2
+ Exit 1
+fi
+
+seq 5 > in
+
+
+# Give tac a fifo command line argument.
+# This makes it try to create a temporary file in $TMPDIR.
+mkfifo_or_skip_ fifo
+seq 1000 > fifo & pid=$!
+TMPDIR=$FULL_PARTITION_TMPDIR tac fifo in >out 2>err && fail=1
+
+cat <<\EOF > exp || framework_failure_
+5
+4
+3
+2
+1
+EOF
+
+compare exp out || fail=1
+
+Exit $fail
diff --git a/tests/tac/tac.pl b/tests/tac/tac.pl
new file mode 100755
index 0000000..dd67c80
--- /dev/null
+++ b/tests/tac/tac.pl
@@ -0,0 +1,89 @@
+#!/usr/bin/perl
+
+# Copyright (C) 2008-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+use strict;
+
+my $prog = 'tac';
+
+# Turn off localization of executable's output.
+@ENV{qw(LANGUAGE LANG LC_ALL)} = ('C') x 3;
+
+my $bad_dir = 'no/such/dir';
+
+# This must be longer than 16KiB to trigger the double free in coreutils-8.5.
+my $long_line = 'o' x (16 * 1024 + 1);
+
+my @Tests =
+(
+ ['segfault', '-r', {IN=>"a\n"}, {IN=>"b\n"}, {OUT=>"a\nb\n"}],
+ ['segfault2','-r', {IN=>"a\nb\n"}, {IN=>"1\n2\n"}, {OUT=>"b\na\n2\n1\n"}],
+
+ ['basic-0', '', {IN=>""}, {OUT=>""}],
+ ['basic-a', '', {IN=>"a"}, {OUT=>"a"}],
+ ['basic-b', '', {IN=>"\n"}, {OUT=>"\n"}],
+ ['basic-c', '', {IN=>"a\n"}, {OUT=>"a\n"}],
+ ['basic-d', '', {IN=>"a\nb"}, {OUT=>"ba\n"}],
+ ['basic-e', '', {IN=>"a\nb\n"}, {OUT=>"b\na\n"}],
+ ['basic-f', '', {IN=>"1234567\n8\n"}, {OUT=>"8\n1234567\n"}],
+ ['basic-g', '', {IN=>"12345678\n9\n"}, {OUT=>"9\n12345678\n"}],
+ ['basic-h', '', {IN=>"123456\n8\n"}, {OUT=>"8\n123456\n"}],
+ ['basic-i', '', {IN=>"12345\n8\n"}, {OUT=>"8\n12345\n"}],
+ ['basic-j', '', {IN=>"1234\n8\n"}, {OUT=>"8\n1234\n"}],
+ ['basic-k', '', {IN=>"123\n8\n"}, {OUT=>"8\n123\n"}],
+
+ ['nul-0', '-s ""', {IN=>""}, {OUT=>""}],
+ ['nul-a', '-s ""', {IN=>"a"}, {OUT=>"a"}],
+ ['nul-b', '-s ""', {IN=>"\0"}, {OUT=>"\0"}],
+ ['nul-c', '-s ""', {IN=>"a\0"}, {OUT=>"a\0"}],
+ ['nul-d', '-s ""', {IN=>"a\0b"}, {OUT=>"ba\0"}],
+ ['nul-e', '-s ""', {IN=>"a\0b\0"}, {OUT=>"b\0a\0"}],
+
+ ['opt-b', '-b', {IN=>"\na\nb\nc"}, {OUT=>"\nc\nb\na"}],
+ ['opt-s', '-s:', {IN=>"a:b:c:"}, {OUT=>"c:b:a:"}],
+ ['opt-sb', qw(-s : -b), {IN=>":a:b:c"}, {OUT=>":c:b:a"}],
+ ['opt-r', qw(-r -s '\._+'),
+ {IN=>"1._2.__3.___4._"},
+ {OUT=>"4._3.___2.__1._"}],
+
+ ['opt-r2', qw(-r -s '\._+'),
+ {IN=>"a.___b.__1._2.__3.___4._"},
+ {OUT=>"4._3.___2.__1._b.__a.___"}],
+
+ # This gave incorrect output (.___4._2.__3._1) with tac-1.22.
+ ['opt-br', qw(-b -r -s '\._+'),
+ {IN=>"._1._2.__3.___4"}, {OUT=>".___4.__3._2._1"}],
+
+ ['opt-br2', qw(-b -r -s '\._+'),
+ {IN=>".__x.___y.____z._1._2.__3.___4"},
+ {OUT=>".___4.__3._2._1.____z.___y.__x"}],
+
+ ['pipe-bad-tmpdir',
+ {ENV => "TMPDIR=$bad_dir"},
+ {IN_PIPE => "a\n"},
+ {OUT=>"a\n"}],
+
+ # coreutils-8.5's tac would double-free its primary buffer.
+ ['double-free', {IN=>$long_line}, {OUT=>$long_line}],
+);
+
+@Tests = triple_test \@Tests;
+
+my $save_temps = $ENV{DEBUG};
+my $verbose = $ENV{VERBOSE};
+
+my $fail = run_tests ($prog, $prog, \@Tests, $save_temps, $verbose);
+exit $fail;
diff --git a/tests/tail/F-headers.sh b/tests/tail/F-headers.sh
new file mode 100755
index 0000000..ef4b9bc
--- /dev/null
+++ b/tests/tail/F-headers.sh
@@ -0,0 +1,59 @@
+#!/bin/sh
+# Ensure tail -F distinguishes output with the correct headers
+# Between coreutils 7.5 and 8.23 inclusive, 'tail -F ...' would
+# not output headers for or created/renamed files in certain cases.
+
+# Copyright (C) 2015-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ tail
+
+check_tail_output()
+{
+ local delay="$1"
+ grep "$tail_re" out ||
+ { sleep $delay; return 1; }
+}
+
+# Terminate any background tail process
+cleanup_() { kill $pid 2>/dev/null && wait $pid; }
+
+# Speedup the non inotify case
+fastpoll='-s.1 --max-unchanged-stats=1'
+
+for mode in '' '---disable-inotify'; do
+ rm -f a b out
+
+ tail $mode -F $fastpoll a b > out 2>&1 & pid=$!
+
+ # Wait up to 12.7s for tail to start.
+ tail_re="cannot open 'b'" retry_delay_ check_tail_output .1 7 ||
+ { cat out; fail=1; }
+
+ echo x > a
+ # Wait up to 12.7s for a's header to appear in the output:
+ tail_re='==> a <==' retry_delay_ check_tail_output .1 7 ||
+ { echo "$0: a: unexpected delay?"; cat out; fail=1; }
+
+ echo y > b
+ # Wait up to 12.7s for b's header to appear in the output:
+ tail_re='==> b <==' retry_delay_ check_tail_output .1 7 ||
+ { echo "$0: b: unexpected delay?"; cat out; fail=1; }
+
+ cleanup_
+done
+
+Exit $fail
diff --git a/tests/tail/F-vs-missing.sh b/tests/tail/F-vs-missing.sh
new file mode 100755
index 0000000..da4d4f7
--- /dev/null
+++ b/tests/tail/F-vs-missing.sh
@@ -0,0 +1,59 @@
+#!/bin/sh
+# demonstrate that tail -F works for currently missing dirs
+# Before coreutils-8.6, tail -F missing/file would not
+# notice any subsequent availability of the missing/file.
+
+# Copyright (C) 2010-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ tail
+
+check_tail_output()
+{
+ local delay="$1"
+ grep "$tail_re" out > /dev/null ||
+ { sleep $delay; return 1; }
+}
+
+# Terminate any background tail process
+cleanup_() { kill $pid 2>/dev/null && wait $pid; }
+
+# Speedup the non inotify case
+fastpoll='-s.1 --max-unchanged-stats=1'
+
+for mode in '' '---disable-inotify'; do
+ rm -rf out missing
+
+ tail $mode -F $fastpoll missing/file > out 2>&1 & pid=$!
+
+ # Wait up to 12.7s for tail to start with diagnostic:
+ # tail: cannot open 'missing/file' for reading: No such file or directory
+ tail_re='cannot open' retry_delay_ check_tail_output .1 7 ||
+ { cat out; fail=1; }
+
+ mkdir missing || framework_failure_
+ (cd missing && echo x > file) || framework_failure_
+
+ # Wait up to 12.7s for this to appear in the output:
+ # "tail: '...' has appeared; following new file"
+ tail_re='has appeared' retry_delay_ check_tail_output .1 7 ||
+ { echo "$0: file: unexpected delay?"; cat out; fail=1; }
+
+ cleanup_
+done
+
+
+Exit $fail
diff --git a/tests/tail/F-vs-rename.sh b/tests/tail/F-vs-rename.sh
new file mode 100755
index 0000000..1048054
--- /dev/null
+++ b/tests/tail/F-vs-rename.sh
@@ -0,0 +1,90 @@
+#!/bin/sh
+# Demonstrate that tail -F works when renaming the tailed files.
+# Between coreutils 7.5 and 8.2 inclusive, 'tail -F a b' would
+# stop tracking additions to b after 'mv a b'.
+
+# Copyright (C) 2009-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ tail
+
+check_tail_output() {
+ local delay="$1"
+ if [ "$tail_re" ]; then
+ grep "$tail_re" err ||
+ { sleep $delay; return 1; }
+ else
+ local tail_re="==> $file <==@$data@"
+ tr '\n' @ < out | grep "$tail_re" > /dev/null ||
+ { sleep $delay; return 1; }
+ fi
+ unset tail_re
+}
+
+# Terminate any background tail process
+cleanup_() { kill $pid 2>/dev/null && wait $pid; }
+
+# Speedup the non inotify case
+fastpoll='-s.1 --max-unchanged-stats=1'
+
+for mode in '' '---disable-inotify'; do
+ rm -f a b out err
+ touch a b || framework_failure_
+
+ tail $mode -F $fastpoll a b >out 2>err & pid=$!
+
+ # Wait up to 12.7s for tail to start.
+ echo x > a
+ file=a data=x retry_delay_ check_tail_output .1 7 || { cat out; fail=1; }
+
+ mv a b || framework_failure_
+
+ # Wait 12.7s for this diagnostic:
+ # tail: 'a' has become inaccessible: No such file or directory
+ tail_re='inaccessible' retry_delay_ check_tail_output .1 7 ||
+ { cat out; fail=1; }
+
+ # Wait 12.7s for this diagnostic:
+ # tail: 'b' has been replaced; following new file
+ tail_re='replaced' retry_delay_ check_tail_output .1 7 ||
+ { cat out; fail=1; }
+ # Wait up to 12.7s for "x" to be displayed:
+ file='b' data='x' retry_delay_ check_tail_output .1 7 ||
+ { echo "$0: b: unexpected delay?"; cat out; fail=1; }
+
+ echo x2 > a
+ # Wait up to 12.7s for this to appear in the output:
+ # "tail: '...' has appeared; following new file"
+ tail_re='has appeared' retry_delay_ check_tail_output .1 7 ||
+ { echo "$0: a: unexpected delay?"; cat out; fail=1; }
+ # Wait up to 12.7s for "x2" to be displayed:
+ file='a' data='x2' retry_delay_ check_tail_output .1 7 ||
+ { echo "$0: a: unexpected delay 2?"; cat out; fail=1; }
+
+ echo y >> b
+ # Wait up to 12.7s for "y" to appear in the output:
+ file='b' data='y' retry_delay_ check_tail_output .1 7 ||
+ { echo "$0: b: unexpected delay 2?"; cat out; fail=1; }
+
+ echo z >> a
+ # Wait up to 12.7s for "z" to appear in the output:
+ file='a' data='z' retry_delay_ check_tail_output .1 7 ||
+ { echo "$0: a: unexpected delay 3?"; cat out; fail=1; }
+
+ cleanup_
+done
+
+Exit $fail
diff --git a/tests/tail/append-only.sh b/tests/tail/append-only.sh
new file mode 100755
index 0000000..9ce855b
--- /dev/null
+++ b/tests/tail/append-only.sh
@@ -0,0 +1,46 @@
+#!/bin/sh
+# Ensure that tail -f works on an append-only file
+# Requires root access to do chattr +a, as well as an ext[23] or xfs file system
+
+# Copyright (C) 2006-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ tail
+require_root_
+
+# Terminate any background tail process
+cleanup_() { kill $pid 2>/dev/null && wait $pid; }
+
+chattr_a_works=1
+touch f
+chattr +a f 2>/dev/null || chattr_a_works=0
+( echo x > f ) 2>/dev/null && chattr_a_works=0
+echo x >> f || chattr_a_works=0
+
+if test $chattr_a_works = 0; then
+ skip_ "chattr +a doesn't work on this file system"
+fi
+
+
+for mode in '' '---disable-inotify'; do
+ sleep 1 & pid=$!
+ tail --pid=$pid -f $mode f || fail=1
+ cleanup_
+done
+
+chattr -a f 2>/dev/null
+
+Exit $fail
diff --git a/tests/tail/assert-2.sh b/tests/tail/assert-2.sh
new file mode 100755
index 0000000..4592c8c
--- /dev/null
+++ b/tests/tail/assert-2.sh
@@ -0,0 +1,57 @@
+#!/bin/sh
+# This variant of 'assert' would get a Uninit Mem Read reliably in 2.0.9.
+# Due to a race condition in the test, the 'assert' script would get
+# the UMR on Solaris only some of the time, and not at all on Linux/GNU.
+
+# Copyright (C) 2000-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ tail
+
+check_tail_output()
+{
+ local delay="$1"
+ grep "$tail_re" out ||
+ { sleep $delay; return 1; }
+}
+
+# Terminate any background tail process
+cleanup_() { kill $pid 2>/dev/null && wait $pid; }
+
+# Speedup the non inotify case
+fastpoll='-s.1 --max-unchanged-stats=1'
+
+for mode in '' '---disable-inotify'; do
+ rm -f a foo out
+ touch a || framework_failure_
+
+ tail $mode $fastpoll -F a foo > out 2>&1 & pid=$!
+
+ # Wait up to 12.7s for tail to start.
+ echo x > a || framework_failure_
+ tail_re='^x$' retry_delay_ check_tail_output .1 7 ||
+ { cat out; fail=1; break; }
+
+ # Wait up to 12.7s for tail to notice new foo file
+ ok='ok ok ok'
+ echo "$ok" > foo || framework_failure_
+ tail_re="^$ok$" retry_delay_ check_tail_output .1 7 ||
+ { echo "$0: foo: unexpected delay?"; cat out; fail=1; break; }
+
+ cleanup_
+done
+
+Exit $fail
diff --git a/tests/tail/assert.sh b/tests/tail/assert.sh
new file mode 100755
index 0000000..dda9904
--- /dev/null
+++ b/tests/tail/assert.sh
@@ -0,0 +1,68 @@
+#!/bin/sh
+# Test for assertion failure in "test".
+
+# Copyright (C) 1999-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+
+# This test fails with tail from textutils-2.0.
+# It would get something like this:
+# tail: tail.c:718: recheck: Assertion 'valid_file_spec (f)' failed.
+# Aborted
+# due to a race condition in which a dev/inode pair is reused.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ tail
+
+check_tail_output()
+{
+ local delay="$1"
+ grep "$tail_re" out ||
+ { sleep $delay; return 1; }
+}
+
+# Terminate any background tail process
+cleanup_() { kill $pid 2>/dev/null && wait $pid; }
+
+# Speedup the non inotify case
+fastpoll='-s.1 --max-unchanged-stats=1'
+
+for mode in '' '---disable-inotify'; do
+ rm -f a foo out
+ touch a foo || framework_failure_
+
+ tail $mode --follow=name $fastpoll a foo > out 2>&1 & pid=$!
+
+ # Wait up to 12.7s for tail to start.
+ echo x > a || framework_failure_
+ tail_re='^x$' retry_delay_ check_tail_output .1 7 ||
+ { cat out; fail=1; break; }
+
+ # Wait 12.7s for this diagnostic:
+ # tail: foo: No such file or directory
+ rm foo || framework_failure_
+ tail_re='No such file' retry_delay_ check_tail_output .1 7 ||
+ { cat out; fail=1; break; }
+
+ # Wait up to 12.7s for tail to notice new foo file
+ ok='ok ok ok'
+ echo "$ok" > foo || framework_failure_
+ tail_re="^$ok$" retry_delay_ check_tail_output .1 7 ||
+ { echo "$0: foo: unexpected delay?"; cat out; fail=1; break; }
+
+ cleanup_
+done
+
+Exit $fail
diff --git a/tests/tail/big-4gb.sh b/tests/tail/big-4gb.sh
new file mode 100755
index 0000000..2e8379b
--- /dev/null
+++ b/tests/tail/big-4gb.sh
@@ -0,0 +1,50 @@
+#!/bin/sh
+# Demonstrate a bug in 'tail -cN' when operating on files of size 4G and larger
+# Fixed in coreutils-4.5.2.
+
+# Copyright (C) 2002-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ tail
+expensive_
+
+# Create a file of size exactly 4GB (2^32) with 8 bytes
+# at the beginning and another set of 8 bytes at the end.
+# The rest will be NUL bytes. On most modern systems, the following
+# creates a file that takes up only a few KB. Here, du -sh says 16K.
+echo abcdefgh | tr -d '\n' > big || framework_failure_
+echo 87654321 | tr -d '\n' > tmp || framework_failure_
+# Seek 4GB - 8
+dd bs=1 seek=4294967288 if=tmp of=big 2> err || dd_failed=1
+if test "$dd_failed" = 1; then
+ cat err 1>&2
+ skip_ \
+'cannot create a file large enough for this test,
+possibly because this system does not support large files;
+Consider rerunning this test on a different file system.'
+fi
+
+
+tail -c1 big > out || fail=1
+# Append a newline.
+echo >> out
+cat <<\EOF > exp
+1
+EOF
+
+compare exp out || fail=1
+
+Exit $fail
diff --git a/tests/tail/descriptor-vs-rename.sh b/tests/tail/descriptor-vs-rename.sh
new file mode 100755
index 0000000..f99a4af
--- /dev/null
+++ b/tests/tail/descriptor-vs-rename.sh
@@ -0,0 +1,56 @@
+#!/bin/sh
+# Demonstrate that tail -f works when renaming the tailed files.
+# Between coreutils 7.5 and 8.23 inclusive, 'tail -f a' would
+# stop tracking additions to b after 'mv a b'.
+
+# Copyright (C) 2015-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ tail
+
+check_tail_output()
+{
+ local delay="$1"
+ grep "$tail_re" out ||
+ { sleep $delay; return 1; }
+}
+
+# Terminate any background tail process
+cleanup_() { kill $pid 2>/dev/null && wait $pid; }
+
+# Speedup the non inotify case
+fastpoll='-s.1 --max-unchanged-stats=1'
+
+for mode in '' '---disable-inotify'; do
+ rm -f a out
+ touch a || framework_failure_
+
+ tail $mode $fastpoll -f a > out 2>&1 & pid=$!
+
+ # Wait up to 12.7s for tail to start.
+ echo x > a
+ tail_re='^x$' retry_delay_ check_tail_output .1 7 || { cat out; fail=1; }
+
+ mv a b || framework_failure_
+
+ echo y >> b
+ # Wait up to 12.7s for "y" to appear in the output:
+ tail_re='^y$' retry_delay_ check_tail_output .1 7 || { cat out; fail=1; }
+
+ cleanup_
+done
+
+Exit $fail
diff --git a/tests/tail/end-of-device.sh b/tests/tail/end-of-device.sh
new file mode 100755
index 0000000..8c0da1d
--- /dev/null
+++ b/tests/tail/end-of-device.sh
@@ -0,0 +1,48 @@
+#!/bin/sh
+# Ensure that tail seeks to the end of a device
+
+# Copyright (C) 2017-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ tail
+
+# need write access to local device
+# (even though we don't actually write anything)
+require_root_
+require_local_dir_
+
+get_device_size() {
+ BLOCKDEV=blockdev
+ $BLOCKDEV -V >/dev/null 2>&1 || BLOCKDEV=/sbin/blockdev
+ $BLOCKDEV --getsize64 "$1"
+}
+
+# Get path to device the current dir is on.
+# Note df can only get fs size, not device size.
+device=$(df --output=source . | tail -n1) || framework_failure_
+
+dev_size=$(get_device_size "$device") ||
+ skip_ "failed to determine size of $device"
+
+tail_offset=$(expr $dev_size - 1023) ||
+ skip_ "failed to determine tail offset"
+
+timeout 10 tail -c 1024 "$device" > end1 || fail=1
+timeout 10 tail -c +"$tail_offset" "$device" > end2 || fail=1
+test $(wc -c < end1) = 1024 || fail=1
+cmp end1 end2 || fail=1
+
+Exit $fail
diff --git a/tests/tail/flush-initial.sh b/tests/tail/flush-initial.sh
new file mode 100755
index 0000000..00ca535
--- /dev/null
+++ b/tests/tail/flush-initial.sh
@@ -0,0 +1,44 @@
+#!/bin/sh
+# inotify-based tail -f didn't flush its initial output before blocking
+
+# Copyright (C) 2009-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ tail
+
+# Speedup the non inotify case
+fastpoll='-s.1 --max-unchanged-stats=1'
+
+# Terminate any background tail process
+cleanup_() { kill $pid 2>/dev/null && wait $pid; }
+
+echo line > in || framework_failure_
+# Output should be buffered since we're writing to file
+# so we're depending on the flush to write out
+tail $fastpoll -f in > out & pid=$!
+
+# Wait for 3.1s for the file to be flushed.
+tail_flush()
+{
+ local delay="$1"
+ sleep $delay
+ test -s out
+}
+retry_delay_ tail_flush .1 5 || fail=1
+
+cleanup_
+
+Exit $fail
diff --git a/tests/tail/follow-name.sh b/tests/tail/follow-name.sh
new file mode 100755
index 0000000..a414b69
--- /dev/null
+++ b/tests/tail/follow-name.sh
@@ -0,0 +1,35 @@
+#!/bin/sh
+# ensure that --follow=name does not imply --retry
+
+# Copyright (C) 2011-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ tail
+
+cat <<\EOF > exp || framework_failure_
+tail: cannot open 'no-such' for reading: No such file or directory
+tail: no files remaining
+EOF
+
+returns_ 1 timeout 10 tail --follow=name no-such > out 2> err || fail=1
+
+# Remove an inconsequential inotify warning so
+# we can compare against the above error
+sed '/inotify cannot be used/d' err > k && mv k err
+
+compare exp err || fail=1
+
+Exit $fail
diff --git a/tests/tail/follow-stdin.sh b/tests/tail/follow-stdin.sh
new file mode 100755
index 0000000..0c415d3
--- /dev/null
+++ b/tests/tail/follow-stdin.sh
@@ -0,0 +1,85 @@
+#!/bin/sh
+# Test tail -f -
+
+# Copyright (C) 2009-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ tail
+
+#################
+# tail -f - would fail with the initial inotify implementation
+
+check_tail_output()
+{
+ local delay="$1"
+ grep "$tail_re" out ||
+ { sleep $delay; return 1; }
+}
+
+# Terminate any background tail process
+cleanup_() { kill $pid 2>/dev/null && wait $pid; }
+
+# Speedup the non inotify case
+fastpoll='-s.1 --max-unchanged-stats=1'
+
+echo line > in || framework_failure_
+echo line > exp || framework_failure_
+
+for mode in '' '---disable-inotify'; do
+ > out || framework_failure_
+
+ tail $mode -f $fastpoll < in > out 2> err & pid=$!
+
+ # Wait up to 12.7s for output to appear:
+ tail_re='line' retry_delay_ check_tail_output .1 7 ||
+ { echo "$0: a: unexpected delay?"; cat out; fail=1; }
+
+ # Ensure there was no error output.
+ compare /dev/null err || fail=1
+
+ cleanup_
+done
+
+
+#################
+# Before coreutils-8.26 this would induce an UMR under UBSAN
+returns_ 1 timeout 10 tail -f - <&- 2>errt || fail=1
+cat <<\EOF >exp || framework_failure_
+tail: cannot fstat 'standard input'
+tail: error reading 'standard input'
+tail: no files remaining
+tail: -
+EOF
+sed 's/\(tail:.*\):.*/\1/' errt > err || framework_failure_
+compare exp err || fail=1
+
+
+#################
+# Before coreutils-8.28 this would erroneously issue a warning
+if tty -s </dev/tty && test -t 0; then
+ for input in '' '-' '/dev/tty'; do
+ returns_ 124 timeout 0.1 tail -f $input 2>err || fail=1
+ compare /dev/null err || fail=1
+ done
+
+ tail -f - /dev/null </dev/tty 2> out & pid=$!
+ # Wait up to 12.7s for output to appear:
+ tail_re='ineffective' retry_delay_ check_tail_output .1 7 ||
+ { cat out; fail=1; }
+ cleanup_
+fi
+
+Exit $fail
diff --git a/tests/tail/inotify-dir-recreate.sh b/tests/tail/inotify-dir-recreate.sh
new file mode 100755
index 0000000..3d2ce99
--- /dev/null
+++ b/tests/tail/inotify-dir-recreate.sh
@@ -0,0 +1,88 @@
+#!/bin/sh
+# Makes sure, inotify will switch to polling mode if directory
+# of the watched file was removed and recreated.
+# (...instead of getting stuck forever)
+
+# Copyright (C) 2017-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ tail
+
+grep '^#define HAVE_INOTIFY 1' "$CONFIG_HEADER" >/dev/null && is_local_dir_ . \
+ || skip_ 'inotify is not supported'
+
+# Terminate any background tail process
+cleanup_() { kill $pid 2>/dev/null && wait $pid; }
+
+cleanup_fail_ ()
+{
+ warn_ $1
+ cleanup_
+ fail=1
+}
+
+# $check_re - string to be found
+# $check_f - file to be searched
+check_tail_output_ ()
+{
+ local delay="$1"
+ grep $check_re $check_f > /dev/null ||
+ { sleep $delay ; return 1; }
+}
+
+grep_timeout_ ()
+{
+ check_re="$1"
+ check_f="$2"
+ retry_delay_ check_tail_output_ .1 5
+}
+
+# Prepare the file to be watched
+mkdir dir && echo 'inotify' > dir/file || framework_failure_
+
+#tail must print content of the file to stdout, verify
+timeout 60 tail --pid=$$ -F dir/file >out 2>&1 & pid=$!
+grep_timeout_ 'inotify' 'out' ||
+{ cleanup_fail_ 'file to be tailed does not exist'; }
+
+inotify_failed_re='inotify (resources exhausted|cannot be used)'
+grep -E "$inotify_failed_re" out &&
+ skip_ "inotify can't be used"
+
+# Remove the directory, should get the message about the deletion
+rm -r dir || framework_failure_
+grep_timeout_ 'polling' 'out' ||
+{ cleanup_fail_ 'tail did not switch to polling mode'; }
+
+# Recreate the dir, must get a message about recreation
+mkdir dir && touch dir/file || framework_failure_
+grep_timeout_ 'appeared' 'out' ||
+{ cleanup_fail_ 'previously removed file did not appear'; }
+
+cleanup_
+
+# Expected result for the whole process
+cat <<\EOF > exp || framework_failure_
+inotify
+tail: 'dir/file' has become inaccessible: No such file or directory
+tail: directory containing watched file was removed
+tail: inotify cannot be used, reverting to polling
+tail: 'dir/file' has appeared; following new file
+EOF
+
+compare exp out || fail=1
+
+Exit $fail
diff --git a/tests/tail/inotify-hash-abuse.sh b/tests/tail/inotify-hash-abuse.sh
new file mode 100755
index 0000000..26af820
--- /dev/null
+++ b/tests/tail/inotify-hash-abuse.sh
@@ -0,0 +1,71 @@
+#!/bin/sh
+# Exercise an abort-inducing flaw in inotify-enabled tail -F.
+
+# Copyright (C) 2009-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ tail
+
+# 9 is a magic number, related to internal details of tail.c and hash.c
+n=9
+seq $n | xargs touch || framework_failure_
+
+check_tail_output()
+{
+ local delay="$1"
+ grep "$tail_re" out > /dev/null ||
+ { sleep $delay; return 1; }
+}
+
+# Terminate any background tail process
+cleanup_() { kill $pid 2>/dev/null && wait $pid; }
+
+# Speedup the non inotify case
+fastpoll='-s.1 --max-unchanged-stats=1'
+
+for mode in '' '---disable-inotify'; do
+ rm -f out
+
+ tail $mode $fastpoll -qF $(seq $n) > out 2>&1 & pid=$!
+
+ # Wait up to 12.7s for tail to start
+ echo x > $n
+ tail_re='^x$' retry_delay_ check_tail_output .1 7 ||
+ { cat out; fail=1; }
+
+ mv 1 f || framework_failure_
+
+ # Wait 12.7s for this diagnostic:
+ # tail: '1' has become inaccessible: No such file or directory
+ tail_re='inaccessible' retry_delay_ check_tail_output .1 7 ||
+ { cat out; fail=1; }
+
+ # Trigger the bug. Before the fix, this would provoke the abort.
+ echo a > 1 || framework_failure_
+
+ # Wait up to 6.3s for the "tail: '1' has appeared; ..." message
+ # (or for the buggy tail to die)
+ tail_re='has appeared' retry_delay_ check_tail_output .1 6 ||
+ { cat out; fail=1; }
+
+ # Double check that tail hasn't aborted
+ kill -0 $pid || fail=1
+
+ cleanup_
+done
+
+
+Exit $fail
diff --git a/tests/tail/inotify-hash-abuse2.sh b/tests/tail/inotify-hash-abuse2.sh
new file mode 100755
index 0000000..ba97d3b
--- /dev/null
+++ b/tests/tail/inotify-hash-abuse2.sh
@@ -0,0 +1,46 @@
+#!/bin/sh
+# Exercise an abort-inducing flaw in inotify-enabled tail -F.
+# Like inotify-hash-abuse, but without a hard-coded "9".
+
+# Copyright (C) 2009-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ tail
+
+# Terminate any background tail process
+cleanup_() { kill $pid 2>/dev/null && wait $pid; }
+
+# Speedup the non inotify case
+fastpoll='-s.1 --max-unchanged-stats=1'
+
+for mode in '' '---disable-inotify'; do
+ touch f || framework_failure_
+
+ tail $mode $fastpoll -F f & pid=$!
+
+ for i in $(seq 200); do
+ kill -0 $pid || break;
+ touch g
+ mv g f
+ done
+
+ # Ensure tail hasn't aborted
+ kill -0 $pid || fail=1
+
+ cleanup_
+done
+
+Exit $fail
diff --git a/tests/tail/inotify-only-regular.sh b/tests/tail/inotify-only-regular.sh
new file mode 100755
index 0000000..2ecf66b
--- /dev/null
+++ b/tests/tail/inotify-only-regular.sh
@@ -0,0 +1,32 @@
+#!/bin/sh
+# ensure that tail -f only uses inotify for regular files or fifos
+
+# Copyright (C) 2017-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ tail
+
+grep '^#define HAVE_INOTIFY 1' "$CONFIG_HEADER" >/dev/null \
+ || skip_ 'inotify support required'
+
+require_strace_ 'inotify_add_watch'
+
+returns_ 124 timeout .1 strace -e inotify_add_watch -o strace.out \
+ tail -f /dev/null || fail=1
+
+grep 'inotify' strace.out && fail=1
+
+Exit $fail
diff --git a/tests/tail/inotify-race.sh b/tests/tail/inotify-race.sh
new file mode 100755
index 0000000..63f9065
--- /dev/null
+++ b/tests/tail/inotify-race.sh
@@ -0,0 +1,101 @@
+#!/bin/sh
+# Ensure that tail does not ignore data that is appended to a tailed-forever
+# file between tail's initial read-to-EOF, and when the inotify watches
+# are established in tail_forever_inotify. That data could be ignored
+# indefinitely if no *other* data is appended, but it would be printed as
+# soon as any additional appended data is detected.
+
+# Copyright (C) 2009-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ tail sleep
+
+grep '^#define HAVE_INOTIFY 1' "$CONFIG_HEADER" >/dev/null && is_local_dir_ . \
+ || skip_ 'inotify is not supported'
+
+# Terminate any background gdb/tail process
+cleanup_() {
+ kill $pid 2>/dev/null && wait $pid
+ kill $sleep 2>/dev/null && wait $sleep
+}
+
+touch file || framework_failure_
+touch tail.out || framework_failure_
+
+( timeout 10s gdb --version ) > gdb.out 2>&1
+case $(cat gdb.out) in
+ *'GNU gdb'*) ;;
+ *) skip_ "can't run gdb";;
+esac
+
+# Break on a line rather than a symbol, to cater for inline functions
+break_src="$abs_top_srcdir/src/tail.c"
+break_line=$(grep -n ^tail_forever_inotify "$break_src") || framework_failure_
+break_line=$(echo "$break_line" | cut -d: -f1) || framework_failure_
+
+
+# Note we get tail to monitor a background sleep process
+# rather than using timeout(1), as timeout sends SIGCONT
+# signals to its monitored process, and gdb (7.9 at least)
+# has _intermittent_ issues with this.
+# Sending SIGCONT resulted in either delayed child termination,
+# or no child termination resulting in a hung test.
+# See https://sourceware.org/bugzilla/show_bug.cgi?id=18364
+
+env sleep 10 & sleep=$!
+
+# See if gdb works and
+# tail_forever_inotify is compiled and run
+gdb -nx --batch-silent \
+ --eval-command="break $break_line" \
+ --eval-command="run --pid=$sleep -f file" \
+ --eval-command='quit' \
+ tail < /dev/null > gdb.out 2>&1
+
+kill $sleep || skip_ 'breakpoint not hit'
+wait $sleep
+
+# FIXME: The above is seen to _intermittently_ fail with:
+# warning: .dynamic section for "/lib/libc.so.6" is not at the expected address
+# warning: difference appears to be caused by prelink, adjusting expectations
+compare /dev/null gdb.out || skip_ "can't set breakpoints in tail"
+
+env sleep 10 & sleep=$!
+
+# Run "tail -f file", stopping to append a line just before
+# inotify initialization, and then continue. Before the fix,
+# that just-appended line would never be output.
+gdb -nx --batch-silent \
+ --eval-command="break $break_line" \
+ --eval-command="run --pid=$sleep -f file >> tail.out" \
+ --eval-command='shell echo never-seen-with-tail-7.5 >> file' \
+ --eval-command='continue' \
+ --eval-command='quit' \
+ tail < /dev/null > /dev/null 2>&1 & pid=$!
+
+tail --pid=$pid -f tail.out | (read REPLY; kill $pid)
+
+# gdb has a bug in Debian's gdb-6.8-3 at least that causes it to not
+# cleanup and exit correctly when it receives a SIGTERM, but
+# killing sleep, should cause the tail process and thus gdb to exit.
+kill $sleep
+wait $sleep
+
+wait $pid
+
+compare /dev/null tail.out && fail=1
+
+Exit $fail
diff --git a/tests/tail/inotify-race2.sh b/tests/tail/inotify-race2.sh
new file mode 100755
index 0000000..19219b7
--- /dev/null
+++ b/tests/tail/inotify-race2.sh
@@ -0,0 +1,106 @@
+#!/bin/sh
+# Ensure that tail does not ignore a tailed-forever file that has been
+# replaced between tail's initial read-to-EOF, and when the inotify watches
+# are established in tail_forever_inotify. That new file would be ignored
+# indefinitely.
+
+# Copyright (C) 2015-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ tail sleep
+
+grep '^#define HAVE_INOTIFY 1' "$CONFIG_HEADER" >/dev/null && is_local_dir_ . \
+ || skip_ 'inotify is not supported'
+
+# Terminate any background gdb/tail process
+cleanup_() {
+ kill $pid 2>/dev/null && wait $pid
+ kill $sleep 2>/dev/null && wait $sleep
+}
+
+touch file || framework_failure_
+touch tail.out || framework_failure_
+
+( timeout 10s gdb --version ) > gdb.out 2>&1
+case $(cat gdb.out) in
+ *'GNU gdb'*) ;;
+ *) skip_ "can't run gdb";;
+esac
+
+# Break on a line rather than a symbol, to cater for inline functions
+break_src="$abs_top_srcdir/src/tail.c"
+break_line=$(grep -n ^tail_forever_inotify "$break_src") || framework_failure_
+break_line=$(echo "$break_line" | cut -d: -f1) || framework_failure_
+
+
+# Note we get tail to monitor a background sleep process
+# rather than using timeout(1), as timeout sends SIGCONT
+# signals to its monitored process, and gdb (7.9 at least)
+# has _intermittent_ issues with this.
+# Sending SIGCONT resulted in either delayed child termination,
+# or no child termination resulting in a hung test.
+# See https://sourceware.org/bugzilla/show_bug.cgi?id=18364
+
+env sleep 10 & sleep=$!
+
+# See if gdb works and
+# tail_forever_inotify is compiled and run
+gdb -nx --batch-silent \
+ --eval-command="break $break_line" \
+ --eval-command="run --pid=$sleep -f file" \
+ --eval-command='quit' \
+ tail < /dev/null > gdb.out 2>&1
+
+kill $sleep || skip_ 'breakpoint not hit'
+wait $sleep
+
+# FIXME: The above is seen to _intermittently_ fail with:
+# warning: .dynamic section for "/lib/libc.so.6" is not at the expected address
+# warning: difference appears to be caused by prelink, adjusting expectations
+compare /dev/null gdb.out || skip_ "can't set breakpoints in tail"
+
+env sleep 10 & sleep=$!
+
+echo never-seen-with-tail-8.23 > file.new || framework_failure_
+
+# Run "tail -F file", stopping to replace with a new file before
+# inotify initialization, and then continue. Before the fix,
+# changes to the new file would effectively be ignored.
+gdb -nx --batch-silent \
+ --eval-command="break $break_line" \
+ --eval-command="run --pid=$sleep -F file 2>tail.err >>tail.out" \
+ --eval-command='shell mv file.new file' \
+ --eval-command='continue' \
+ --eval-command='quit' \
+ tail < /dev/null > /dev/null 2>&1 & pid=$!
+
+# Note even updating the watched 'file' wouldn't have output
+# anything between coreutils 7.5 and 8.23 inclusive as
+# The old file descriptor (still held open by tail) was being fstat().
+
+tail --pid=$pid -f tail.out | (read REPLY; kill $pid)
+
+# gdb has a bug in Debian's gdb-6.8-3 at least that causes it to not
+# cleanup and exit correctly when it receives a SIGTERM, but
+# killing sleep, should cause the tail process and thus gdb to exit.
+kill $sleep
+wait $sleep
+
+wait $pid
+
+compare /dev/null tail.out && { cat tail.err; fail=1; }
+
+Exit $fail
diff --git a/tests/tail/inotify-rotate-resources.sh b/tests/tail/inotify-rotate-resources.sh
new file mode 100755
index 0000000..543529e
--- /dev/null
+++ b/tests/tail/inotify-rotate-resources.sh
@@ -0,0 +1,108 @@
+#!/bin/sh
+# ensure that tail -F doesn't leak inotify resources
+
+# Copyright (C) 2015-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ tail
+
+# Inotify not used on remote file systems
+require_local_dir_
+
+grep '^#define HAVE_INOTIFY 1' "$CONFIG_HEADER" >/dev/null \
+ || skip_ 'inotify required'
+
+require_strace_ 'inotify_add_watch,inotify_rm_watch'
+
+check_tail_output()
+{
+ local delay="$1"
+ grep "$tail_re" out > /dev/null ||
+ { sleep $delay; return 1; }
+}
+
+# Wait up to 25.5 seconds for grep REGEXP 'out' to succeed.
+grep_timeout() { tail_re="$1" retry_delay_ check_tail_output .1 8; }
+
+check_strace()
+{
+ local delay="$1"
+ grep "$strace_re" strace.out > /dev/null ||
+ { sleep $delay; return 1; }
+}
+
+cleanup_fail()
+{
+ cat out
+ warn_ $1
+ fail=1
+}
+
+# Terminate any background tail process
+cleanup_() { kill $pid 2>/dev/null && wait $pid; }
+
+fastpoll='-s.1 --max-unchanged-stats=1'
+
+touch k || framework_failure_
+
+# Note the timeout guard isn't strictly necessary here,
+# however without it strace will ignore SIGTERM.
+# strace does always honor SIGTERM with the -I2 option,
+# though that's not available on RHEL6 for example.
+timeout 180 strace -e inotify_add_watch,inotify_rm_watch -o strace.out \
+ tail -F $fastpoll k >> out 2>&1 & pid=$!
+
+reverted_to_polling_=0
+for i in $(seq 2); do
+ echo $i
+
+ echo 'tailed' > k;
+
+ # Wait for watch on (new) file
+ strace_re='inotify_add_watch.*MODIFY' retry_delay_ check_strace .1 8 ||
+ no_watch_=1
+
+ # Assume this is not because we're leaking
+ # (resources may already be depleted)
+ # The explicit check for inotify_rm_watch should confirm that.
+ grep -F 'reverting to polling' out >/dev/null && skip_ 'inotify unused'
+
+ # Otherwise failure is unknown
+ test "$no_watch_" && { cat out; framework_failure_ 'no inotify_add_watch'; }
+
+ mv k k.tmp
+ # wait for tail to detect the rename
+ grep_timeout 'inaccessible' ||
+ { cleanup_fail 'failed to detect rename'; break; }
+
+ # Note we strace here rather than consuming all available watches
+ # to be more efficient, but more importantly avoid depleting resources.
+ # Note also available resources can currently be tuned with:
+ # sudo sysctl -w fs.inotify.max_user_watches=$smallish_number
+ # However that impacts all processes for the current user, and also
+ # may not be supported in future, instead being auto scaled to RAM
+ # like the Linux epoll resources were.
+ if test "$i" -gt 1; then
+ strace_re='inotify_rm_watch' retry_delay_ check_strace .1 8 ||
+ { cleanup_fail 'failed to find inotify_rm_watch syscall'; break; }
+ fi
+
+ >out && >strace.out || framework_failure_ 'failed to reset output files'
+done
+
+cleanup_
+
+Exit $fail
diff --git a/tests/tail/inotify-rotate.sh b/tests/tail/inotify-rotate.sh
new file mode 100755
index 0000000..55338b5
--- /dev/null
+++ b/tests/tail/inotify-rotate.sh
@@ -0,0 +1,77 @@
+#!/bin/sh
+# ensure that tail -F handles rotation
+
+# Copyright (C) 2009-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ tail
+
+grep '^#define HAVE_INOTIFY 1' "$CONFIG_HEADER" >/dev/null \
+ || expensive_
+
+check_tail_output()
+{
+ local delay="$1"
+ grep "$tail_re" out > /dev/null ||
+ { sleep $delay; return 1; }
+}
+
+# Wait up to 25.5 seconds for grep REGEXP 'out' to succeed.
+grep_timeout() { tail_re="$1" retry_delay_ check_tail_output .1 8; }
+
+# Terminate any background tail process
+cleanup_() { kill $pid 2>/dev/null && wait $pid; }
+
+cleanup_fail()
+{
+ cat out
+ warn_ $1
+ cleanup_
+ fail=1
+}
+
+# Speedup the non inotify case
+fastpoll='-s.1 --max-unchanged-stats=1'
+
+# Perform at least this many iterations, because on multi-core systems
+# the offending sequence of events can be surprisingly uncommon.
+# See: https://lists.gnu.org/r/bug-coreutils/2009-11/msg00213.html
+for i in $(seq 50); do
+ echo $i
+ rm -f k x out
+
+ # Normally less than a second is required here, but with heavy load
+ # and a lot of file system activity, even 20 seconds is insufficient, which
+ # leads to this timeout killing tail before the "ok" is written below.
+ >k && >x || framework_failure_ failed to initialize files
+ timeout 60 tail $fastpoll -F k > out 2>&1 & pid=$!
+
+ echo 'tailed' > k;
+ # wait for 'tailed' to appear in out
+ grep_timeout 'tailed' || { cleanup_fail 'failed to find "tailed"'; break; }
+
+ mv x k
+ # wait for tail to detect the rename
+ grep_timeout 'tail:' || { cleanup_fail 'failed to detect rename'; break; }
+
+ echo ok >> k
+ # wait for "ok" to appear in 'out'
+ grep_timeout 'ok' || { cleanup_fail 'failed to detect echoed ok'; break; }
+
+ cleanup_
+done
+
+Exit $fail
diff --git a/tests/tail/overlay-headers.sh b/tests/tail/overlay-headers.sh
new file mode 100755
index 0000000..59f6e1e
--- /dev/null
+++ b/tests/tail/overlay-headers.sh
@@ -0,0 +1,81 @@
+#!/bin/sh
+# inotify-based tail would output redundant headers for
+# overlapping inotify events while it was suspended
+
+# Copyright (C) 2017-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ tail sleep
+
+# Function to count number of lines from tail
+# while ignoring transient errors due to resource limits
+countlines_ ()
+{
+ grep -Ev 'inotify (resources exhausted|cannot be used)' out | wc -l
+}
+
+# Function to check the expected line count in 'out'.
+# Called via retry_delay_(). Sleep some time - see retry_delay_() - if the
+# line count is still smaller than expected.
+wait4lines_ ()
+{
+ local delay=$1
+ local elc=$2 # Expected line count.
+ [ "$(countlines_)" -ge "$elc" ] || { sleep $delay; return 1; }
+}
+
+# Speedup the non inotify case
+fastpoll='---dis -s.1 --max-unchanged-stats=1'
+
+# Terminate any background tail process
+cleanup_() {
+ kill $pid 2>/dev/null && wait $pid;
+ kill $sleep 2>/dev/null && wait $sleep
+}
+
+echo start > file1 || framework_failure_
+echo start > file2 || framework_failure_
+
+# Use this as a way to gracefully terminate tail
+env sleep 20 & sleep=$!
+
+tail $fastpoll --pid=$sleep -f file1 file2 > out & pid=$!
+
+kill -0 $pid || fail=1
+
+# Wait for 5 initial lines
+retry_delay_ wait4lines_ .1 6 5 || fail=1
+
+# Suspend tail so single read() caters for multiple inotify events
+kill -STOP $pid || fail=1
+
+# Interleave writes to files to generate overlapping inotify events
+echo line >> file1 || framework_failure_
+echo line >> file2 || framework_failure_
+echo line >> file1 || framework_failure_
+echo line >> file2 || framework_failure_
+
+# Resume tail processing
+kill -CONT $pid || fail=1
+
+# Wait for 8 more lines
+retry_delay_ wait4lines_ .1 6 13 || fail=1
+
+kill $sleep && wait || framework_failure_
+
+test "$(countlines_)" = 13 || fail=1
+
+Exit $fail
diff --git a/tests/tail/pid.sh b/tests/tail/pid.sh
new file mode 100755
index 0000000..f931b2c
--- /dev/null
+++ b/tests/tail/pid.sh
@@ -0,0 +1,49 @@
+#!/bin/sh
+# Test the --pid option of tail.
+
+# Copyright (C) 2003-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ tail
+getlimits_
+
+touch empty here || framework_failure_
+
+# Terminate any background tail process
+cleanup_() { kill $pid 2>/dev/null && wait $pid; }
+
+for mode in '' '---disable-inotify'; do
+ # Use tail itself to create a background process to monitor,
+ # which will auto exit when "here" is removed.
+ tail -f $mode here & pid=$!
+
+ # Ensure that tail --pid=PID does not exit when PID is alive.
+ returns_ 124 timeout 1 tail -f -s.1 --pid=$pid $mode here || fail=1
+
+ cleanup_
+
+ # Ensure that tail --pid=PID exits with success status when PID is dead.
+ # Use an unlikely-to-be-live PID
+ timeout 10 tail -f -s.1 --pid=$PID_T_MAX $mode empty
+ ret=$?
+ test $ret = 124 && skip_ "pid $PID_T_MAX present or tail too slow"
+ test $ret = 0 || fail=1
+
+ # Ensure tail doesn't wait for data when PID is dead
+ returns_ 124 timeout 10 tail -f -s10 --pid=$PID_T_MAX $mode empty && fail=1
+done
+
+Exit $fail
diff --git a/tests/tail/pipe-f.sh b/tests/tail/pipe-f.sh
new file mode 100755
index 0000000..46bcbbe
--- /dev/null
+++ b/tests/tail/pipe-f.sh
@@ -0,0 +1,67 @@
+#!/bin/sh
+# ensure that tail -f doesn't hang in various cases
+
+# Copyright (C) 2009-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ tail test head
+trap_sigpipe_or_skip_
+
+# Speedup the non inotify case
+fastpoll='-s.1 --max-unchanged-stats=1'
+
+for mode in '' '---disable-inotify'; do
+# Ensure :|tail -f doesn't hang, per POSIX
+echo oo > exp || framework_failure_
+echo foo | timeout 10 tail -f $mode $fastpoll -c3 > out || fail=1
+compare exp out || fail=1
+cat <<\EOF > exp || framework_failure_
+==> standard input <==
+ar
+EOF
+echo bar | returns_ 1 \
+ timeout 10 tail -f $mode $fastpoll -c3 - missing > out || fail=1
+compare exp out || fail=1
+
+# This would wait indefinitely before v8.28 due to no EPIPE being
+# generated due to no data written after the first small amount.
+# Also check tail exits if SIGPIPE is being ignored.
+# Note 'trap - SIGPIPE' is ineffective if the initiating shell
+# has ignored SIGPIPE, but that's not the normal case.
+case $host_triplet in
+ *aix*) echo 'avoiding due to no way to detect closed outputs on AIX' ;;
+ *)
+for disposition in '' '-'; do
+ (trap "$disposition" PIPE;
+ returns_ 124 timeout 10 \
+ tail -n2 -f $mode $fastpoll out && touch timed_out) |
+ head -n2 > out2
+ test -e timed_out && fail=1
+ compare exp out2 || fail=1
+ rm -f timed_out
+done ;;
+esac
+
+# This would wait indefinitely before v8.28 (until first write)
+# test -w /dev/stdout is used to check that >&- is effective
+# which was seen not to be the case on NetBSD 7.1 / x86_64:
+if env test -w /dev/stdout >/dev/null &&
+ env test ! -w /dev/stdout >&-; then
+ (returns_ 1 timeout 10 tail -f $mode $fastpoll /dev/null >&-) || fail=1
+fi
+done
+
+Exit $fail
diff --git a/tests/tail/pipe-f2.sh b/tests/tail/pipe-f2.sh
new file mode 100755
index 0000000..edbe3ff
--- /dev/null
+++ b/tests/tail/pipe-f2.sh
@@ -0,0 +1,47 @@
+#!/bin/sh
+# Ensure that "tail -f fifo" tails indefinitely.
+
+# Copyright (C) 2009-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ tail
+
+mkfifo_or_skip_ fifo
+
+echo 1 > fifo &
+echo 1 > exp || framework_failure_
+
+# Terminate any background tail process
+cleanup_() { kill $pid 2>/dev/null && wait $pid; }
+
+# Speedup the non inotify case
+fastpoll='-s.1 --max-unchanged-stats=1'
+
+timeout 10 tail $fastpoll -f fifo > out & pid=$!
+
+check_tail_output() { sleep $1; test -s out; }
+
+# Wait 12.7s for tail to write something.
+retry_delay_ check_tail_output .1 7 || fail=1
+
+compare exp out || fail=1
+
+# Ensure tail is still running
+kill -0 $pid || fail=1
+
+cleanup_
+
+Exit $fail
diff --git a/tests/tail/proc-ksyms.sh b/tests/tail/proc-ksyms.sh
new file mode 100755
index 0000000..5f9b239
--- /dev/null
+++ b/tests/tail/proc-ksyms.sh
@@ -0,0 +1,28 @@
+#!/bin/sh
+# Prior to textutils-2.0.17, 'tail /proc/ksyms' would segfault on Linux.
+
+# Copyright (C) 2001-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ tail
+
+
+ksyms=/proc/ksyms
+if test -r $ksyms; then
+ tail $ksyms > /dev/null || fail=1
+fi
+
+Exit $fail
diff --git a/tests/tail/retry.sh b/tests/tail/retry.sh
new file mode 100755
index 0000000..cb75e05
--- /dev/null
+++ b/tests/tail/retry.sh
@@ -0,0 +1,184 @@
+#!/bin/sh
+# Exercise tail's behavior regarding missing files with/without --retry.
+
+# Copyright (C) 2013-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ tail
+
+# Function to count number of lines from tail
+# while ignoring transient errors due to resource limits
+countlines_ ()
+{
+ grep -Ev 'inotify (resources exhausted|cannot be used)' out | wc -l
+}
+
+# Function to check the expected line count in 'out'.
+# Called via retry_delay_(). Sleep some time - see retry_delay_() - if the
+# line count is still smaller than expected.
+wait4lines_ ()
+{
+ local delay=$1
+ local elc=$2 # Expected line count.
+ [ "$(countlines_)" -ge "$elc" ] || { sleep $delay; return 1; }
+}
+
+# Terminate any background tail process
+cleanup_() { kill $pid 2>/dev/null && wait $pid; }
+
+# Speedup the non inotify case
+fastpoll='-s.1 --max-unchanged-stats=1'
+
+# === Test:
+# Retry without --follow results in a warning.
+touch file
+tail --retry file > out 2>&1 || fail=1
+[ "$(countlines_)" = 1 ] || { cat out; fail=1; }
+grep -F 'tail: warning: --retry ignored' out || { cat out; fail=1; }
+
+# === Test:
+# The same with a missing file: expect error message and exit 1.
+returns_ 1 tail --retry missing > out 2>&1 || fail=1
+[ "$(countlines_)" = 2 ] || { cat out; fail=1; }
+grep -F 'tail: warning: --retry ignored' out || { cat out; fail=1; }
+
+for mode in '' '---disable-inotify'; do
+
+# === Test:
+# Ensure that "tail --retry --follow=name" waits for the file to appear.
+# Clear 'out' so that we can check its contents without races
+>out || framework_failure_
+timeout 10 \
+ tail $mode $fastpoll --follow=name --retry missing >out 2>&1 & pid=$!
+# Wait for "cannot open" error.
+retry_delay_ wait4lines_ .1 6 1 || { cat out; fail=1; }
+echo "X" > missing || framework_failure_
+# Wait for the expected output.
+retry_delay_ wait4lines_ .1 6 3 || { cat out; fail=1; }
+cleanup_
+# Expect 3 lines in the output file.
+[ "$(countlines_)" = 3 ] || { fail=1; cat out; }
+grep -F 'cannot open' out || { fail=1; cat out; }
+grep -F 'has appeared' out || { fail=1; cat out; }
+grep '^X$' out || { fail=1; cat out; }
+rm -f missing out || framework_failure_
+
+# === Test:
+# Ensure that "tail --retry --follow=descriptor" waits for the file to appear.
+# tail-8.21 failed at this (since the implementation of the inotify support).
+timeout 10 \
+ tail $mode $fastpoll --follow=descriptor --retry missing >out 2>&1 & pid=$!
+# Wait for "cannot open" error.
+retry_delay_ wait4lines_ .1 6 2 || { cat out; fail=1; }
+echo "X1" > missing || framework_failure_
+# Wait for the expected output.
+retry_delay_ wait4lines_ .1 6 4 || { cat out; fail=1; }
+# Ensure truncation is detected
+# tail-8.25 failed at this (as assumed non file and went into blocking mode)
+echo "X" > missing || framework_failure_
+retry_delay_ wait4lines_ .1 6 6 || { cat out; fail=1; }
+cleanup_
+[ "$(countlines_)" = 6 ] || { fail=1; cat out; }
+grep -F 'retry only effective for the initial open' out \
+ || { fail=1; cat out; }
+grep -F 'cannot open' out || { fail=1; cat out; }
+grep -F 'has appeared' out || { fail=1; cat out; }
+grep '^X1$' out || { fail=1; cat out; }
+grep -F 'file truncated' out || { fail=1; cat out; }
+grep '^X$' out || { fail=1; cat out; }
+rm -f missing out || framework_failure_
+
+# === Test:
+# Ensure that tail --follow=descriptor --retry exits when the file appears
+# untailable. Expect exit status 1.
+timeout 10 \
+ tail $mode $fastpoll --follow=descriptor --retry missing >out 2>&1 & pid=$!
+# Wait for "cannot open" error.
+retry_delay_ wait4lines_ .1 6 2 || { cat out; fail=1; }
+mkdir missing || framework_failure_ # Create untailable
+# Wait for the expected output.
+retry_delay_ wait4lines_ .1 6 4 || { cat out; fail=1; }
+wait $pid
+rc=$?
+[ "$(countlines_)" = 4 ] || { fail=1; cat out; }
+grep -F 'retry only effective for the initial open' out \
+ || { fail=1; cat out; }
+grep -F 'cannot open' out || { fail=1; cat out; }
+grep -F 'replaced with an untailable file' out || { fail=1; cat out; }
+grep -F 'no files remaining' out || { fail=1; cat out; }
+[ $rc = 1 ] || { fail=1; cat out; }
+rm -fd missing out || framework_failure_
+
+# === Test:
+# Ensure that --follow=descriptor (without --retry) does *not* try
+# to open a file after an initial fail, even when there are other
+# tailable files. This was an issue in <= 8.25.
+touch existing || framework_failure_
+tail $mode $fastpoll --follow=descriptor missing existing >out 2>&1 & pid=$!
+retry_delay_ wait4lines_ .1 6 2 || { cat out; fail=1; }
+[ "$(countlines_)" = 2 ] || { fail=1; cat out; }
+grep -F 'cannot open' out || { fail=1; cat out; }
+echo "Y" > missing || framework_failure_
+echo "X" > existing || framework_failure_
+retry_delay_ wait4lines_ .1 6 3 || { cat out; fail=1; }
+[ "$(countlines_)" = 3 ] || { fail=1; cat out; }
+grep '^X$' out || { fail=1; cat out; }
+grep '^Y$' out && { fail=1; cat out; }
+cleanup_
+rm -f missing out existing || framework_failure_
+
+# === Test:
+# Ensure that --follow=descriptor (without --retry) does *not wait* for the
+# file to appear. Expect 2 lines in the output file ("cannot open" +
+# "no files remaining") and exit status 1.
+returns_ 1 tail $mode --follow=descriptor missing >out 2>&1 || fail=1
+[ "$(countlines_)" = 2 ] || { fail=1; cat out; }
+grep -F 'cannot open' out || { fail=1; cat out; }
+grep -F 'no files remaining' out || { fail=1; cat out; }
+rm -f out || framework_failure_
+
+# === Test:
+# Likewise for --follow=name (without --retry).
+returns_ 1 tail $mode --follow=name missing >out 2>&1 || fail=1
+[ "$(countlines_)" = 2 ] || { fail=1; cat out; }
+grep -F 'cannot open' out || { fail=1; cat out; }
+grep -F 'no files remaining' out || { fail=1; cat out; }
+rm -f out || framework_failure_
+
+# === Test:
+# Ensure that tail -F retries when the file is initially untailable.
+if ! cat . >/dev/null; then
+mkdir untailable || framework_failure_
+timeout 10 \
+ tail $mode $fastpoll -F untailable >out 2>&1 & pid=$!
+# Wait for "cannot follow" error.
+retry_delay_ wait4lines_ .1 6 2 || { cat out; fail=1; }
+{ rmdir untailable; echo foo > untailable; } || framework_failure_
+# Wait for the expected output.
+retry_delay_ wait4lines_ .1 6 4 || { cat out; fail=1; }
+cleanup_
+[ "$(countlines_)" = 4 ] || { fail=1; cat out; }
+grep -F 'cannot follow' out || { fail=1; cat out; }
+# The first is the common case, "has appeared" arises with slow rmdir.
+grep -E 'become accessible|has appeared' out || { fail=1; cat out; }
+grep -F 'giving up' out && { fail=1; cat out; }
+grep -F 'foo' out || { fail=1; cat out; }
+rm -fd untailable out || framework_failure_
+fi
+
+done
+
+Exit $fail
diff --git a/tests/tail/start-middle.sh b/tests/tail/start-middle.sh
new file mode 100755
index 0000000..a64bb2d
--- /dev/null
+++ b/tests/tail/start-middle.sh
@@ -0,0 +1,33 @@
+#!/bin/sh
+# Verify that tail works even when it's reading from a file
+# that is not at its beginning. Based on a report from John Roll.
+
+# Copyright (C) 2001-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ tail
+
+(echo 1; echo 2) > k || framework_failure_
+
+
+sh -c 'read x; tail' < k > out || fail=1
+cat <<EOF > exp
+2
+EOF
+
+compare exp out || fail=1
+
+Exit $fail
diff --git a/tests/tail/symlink.sh b/tests/tail/symlink.sh
new file mode 100755
index 0000000..97184d4
--- /dev/null
+++ b/tests/tail/symlink.sh
@@ -0,0 +1,94 @@
+#!/bin/sh
+# Ensure tail tracks symlinks properly.
+
+# Copyright (C) 2013-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ tail
+
+# Function to count number of lines from tail
+# while ignoring transient errors due to resource limits
+countlines_ ()
+{
+ grep -Ev 'inotify (resources exhausted|cannot be used)' out | wc -l
+}
+
+# Function to check the expected line count in 'out'.
+# Called via retry_delay_(). Sleep some time - see retry_delay_() - if the
+# line count is still smaller than expected.
+wait4lines_ ()
+{
+ local delay=$1
+ local elc=$2 # Expected line count.
+ [ "$(countlines_)" -ge "$elc" ] || { sleep $delay; return 1; }
+}
+
+# Terminate any background tail process
+cleanup_() { kill $pid 2>/dev/null && wait $pid; }
+
+# speedup non inotify case
+fastpoll='-s.1 --max-unchanged-stats=1'
+
+# Ensure changing targets of cli specified symlinks are handled.
+# Prior to v8.22, inotify would fail to recognize changes in the targets.
+# Clear 'out' so that we can check its contents without races.
+>out || framework_failure_
+ln -nsf target symlink || framework_failure_
+timeout 10 tail $fastpoll -F symlink >out 2>&1 & pid=$!
+# Wait for "cannot open..."
+retry_delay_ wait4lines_ .1 6 1 || { cat out; fail=1; }
+echo "X" > target || framework_failure_
+# Wait for the expected output.
+retry_delay_ wait4lines_ .1 6 3 || { cat out; fail=1; }
+cleanup_
+# Expect 3 lines in the output file.
+[ "$(countlines_)" = 3 ] || { fail=1; cat out; }
+grep -F 'cannot open' out || { fail=1; cat out; }
+grep -F 'has appeared' out || { fail=1; cat out; }
+grep '^X$' out || { fail=1; cat out; }
+rm -f target out || framework_failure_
+
+# Ensure we correctly handle the source symlink itself changing.
+# I.e., that we don't operate solely on the targets.
+# Clear 'out' so that we can check its contents without races.
+>out || framework_failure_
+echo "X1" > target1 || framework_failure_
+ln -nsf target1 symlink || framework_failure_
+timeout 10 tail $fastpoll -F symlink >out 2>&1 & pid=$!
+# Wait for the expected output.
+retry_delay_ wait4lines_ .1 6 1 || { cat out; fail=1; }
+ln -nsf target2 symlink || framework_failure_
+# Wait for "become inaccess..."
+retry_delay_ wait4lines_ .1 6 2 || { cat out; fail=1; }
+echo "X2" > target2 || framework_failure_
+# Wait for the expected output.
+retry_delay_ wait4lines_ .1 6 4 || { cat out; fail=1; }
+cleanup_
+# Expect 4 lines in the output file.
+[ "$(countlines_)" = 4 ] || { fail=1; cat out; }
+grep -F 'become inacce' out || { fail=1; cat out; }
+grep -F 'has appeared' out || { fail=1; cat out; }
+grep '^X1$' out || { fail=1; cat out; }
+grep '^X2$' out || { fail=1; cat out; }
+rm -f target1 target2 out || framework_failure_
+
+# Note other symlink edge cases are currently just diagnosed
+# rather than being handled. I.e., if you specify a missing item,
+# or existing file that later change to a symlink, if inotify
+# is in use, you'll get a diagnostic saying that link will
+# no longer be tailed.
+
+Exit $fail
diff --git a/tests/tail/tail-c.sh b/tests/tail/tail-c.sh
new file mode 100755
index 0000000..cd92909
--- /dev/null
+++ b/tests/tail/tail-c.sh
@@ -0,0 +1,38 @@
+#!/bin/sh
+# exercise tail -c
+
+# Copyright 2014-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ tail
+
+# Make sure it works on funny files in /proc and /sys.
+for file in /proc/version /sys/kernel/profiling; do
+ if test -r $file; then
+ cp -f $file copy &&
+ tail -c -1 copy > exp || framework_failure_
+
+ tail -c -1 $file > out || fail=1
+ compare exp out || fail=1
+ fi
+done
+
+# Make sure it works for pipes
+printf '123456' | tail -c3 > out || fail=1
+printf '456' > exp || framework_failure_
+compare exp out || fail=1
+
+Exit $fail
diff --git a/tests/tail/tail-n0f.sh b/tests/tail/tail-n0f.sh
new file mode 100755
index 0000000..a3ce5f8
--- /dev/null
+++ b/tests/tail/tail-n0f.sh
@@ -0,0 +1,62 @@
+#!/bin/sh
+# Make sure that 'tail -n0 -f' and 'tail -c0 -f' sleep
+# rather than doing what amounted to a busy-wait.
+
+# Copyright (C) 2003-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+# This bug was fixed for 5.0.91
+# It skips the test if your system lacks a /proc/$pid/status
+# file, or if its contents don't look right.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ tail
+
+require_proc_pid_status_
+
+touch empty || framework_failure_
+echo anything > nonempty || framework_failure_
+
+# First verify that -[nc]0 without -f, exit without reading
+touch unreadable || framework_failure_
+chmod 0 unreadable || framework_failure_
+tail -c0 unreadable || fail=1
+tail -n0 unreadable || fail=1
+
+# Terminate any background tail process
+cleanup_() { kill $pid 2>/dev/null && wait $pid; }
+
+for mode in '' '---disable-inotify'; do
+ for file in empty nonempty; do
+ for c_or_n in c n; do
+ tail --sleep=4 -${c_or_n} 0 -f $mode $file & pid=$!
+ tail_sleeping()
+ {
+ local delay="$1"; sleep $delay
+ state=$(get_process_status_ $pid)
+ case $state in
+ S*) ;;
+ *) return 1;;
+ esac
+ }
+ # Wait up to 1.5s for tail to sleep
+ retry_delay_ tail_sleeping .1 4 ||
+ { echo $0: process in unexpected state: $state >&2; fail=1; }
+ cleanup_
+ done
+ done
+done
+
+Exit $fail
diff --git a/tests/tail/tail.pl b/tests/tail/tail.pl
new file mode 100755
index 0000000..1ff1a90
--- /dev/null
+++ b/tests/tail/tail.pl
@@ -0,0 +1,148 @@
+#!/usr/bin/perl
+# Test tail.
+
+# Copyright (C) 2008-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+use strict;
+
+my $prog = 'tail';
+my $normalize_strerror = "s/': .*/'/";
+
+# Turn off localization of executable's output.
+@ENV{qw(LANGUAGE LANG LC_ALL)} = ('C') x 3;
+
+my @tv = (
+# test name, options, input, expected output, expected return code
+#
+['obs-plus-c1', '+2c', 'abcd', 'bcd', 0],
+['obs-plus-c2', '+8c', 'abcd', '', 0],
+['obs-c3', '-1c', 'abcd', 'd', 0],
+['obs-c4', '-9c', 'abcd', 'abcd', 0],
+['obs-c5', '-12c', 'x' . ('y' x 12) . 'z', ('y' x 11) . 'z', 0],
+
+['obs-l1', '-1l', 'x', 'x', 0],
+['obs-l2', '-1l', "x\ny\n", "y\n", 0],
+['obs-l3', '-1l', "x\ny", "y", 0],
+['obs-plus-l4', '+1l', "x\ny\n", "x\ny\n", 0],
+['obs-plus-l5', '+2l', "x\ny\n", "y\n", 0],
+
+# Same as -l tests, but without the 'l'.
+['obs-1', '-1', 'x', 'x', 0],
+['obs-2', '-1', "x\ny\n", "y\n", 0],
+['obs-3', '-1', "x\ny", "y", 0],
+['obs-plus-4', '+1', "x\ny\n", "x\ny\n", 0],
+['obs-plus-5', '+2', "x\ny\n", "y\n", 0],
+
+# This is equivalent to +10c
+['obs-plus-x1', '+c', 'x' . ('y' x 10) . 'z', 'yyz', 0],
+# This is equivalent to +10l
+['obs-plus-x2', '+l', "x\n" . ("y\n" x 10) . 'z', "y\ny\nz", 0],
+# With no number, this is like -10l
+['obs-l', '-l', "x\n" . ("y\n" x 10) . 'z', ("y\n" x 9) . 'z', 0],
+
+['obs-b', '-b', "x\n" x (512 * 10 / 2 + 1), "x\n" x (512 * 10 / 2), 0],
+
+['err-1', '+cl', '', '', 1,
+ "$prog: cannot open '+cl' for reading: No such file or directory\n"],
+
+['err-2', '-cl', '', '', 1,
+ "$prog: invalid number of bytes: 'l'\n", $normalize_strerror],
+
+['err-3', '+2cz', '', '', 1,
+ "$prog: cannot open '+2cz' for reading: No such file or directory\n"],
+
+# This should get 'tail: invalid option -- 2'
+['err-4', '-2cX', '', '', 1,
+ "$prog: option used in invalid context -- 2\n"],
+
+# Since the number is larger than 2^64, this should provoke
+# the diagnostic: 'tail: 99999999999999999999: invalid number of bytes'
+# on all systems... probably, for now, maybe.
+['err-5', '-c99999999999999999999', '', '', 1,
+ "$prog: invalid number of bytes: '99999999999999999999'\n",
+ $normalize_strerror],
+['err-6', '-c --', '', '', 1,
+ "$prog: invalid number of bytes: '-'\n", $normalize_strerror],
+
+# Same as -n 10
+['minus-1', '-', '', '', 0],
+['minus-2', '-', "x\n" . ("y\n" x 10) . 'z', ("y\n" x 9) . 'z', 0],
+
+['c-2', '-c 2', "abcd\n", "d\n", 0],
+['c-2-minus', '-c 2 --', "abcd\n", "d\n", 0],
+['c2', '-c2', "abcd\n", "d\n", 0],
+['c2-minus', '-c2 --', "abcd\n", "d\n", 0],
+
+['n-1', '-n 10', "x\n" . ("y\n" x 10) . 'z', ("y\n" x 9) . 'z', 0],
+['n-2', '-n -10', "x\n" . ("y\n" x 10) . 'z', ("y\n" x 9) . 'z', 0],
+['n-3', '-n +10', "x\n" . ("y\n" x 10) . 'z', "y\ny\nz", 0],
+
+# Accept +0 as synonym for +1.
+['n-4', '-n +0', "y\n" x 5, "y\n" x 5, 0],
+['n-4a', '-n +1', "y\n" x 5, "y\n" x 5, 0],
+
+# Note that -0 is *not* a synonym for -1.
+['n-5', '-n -0', "y\n" x 5, '', 0],
+['n-5a', '-n -1', "y\n" x 5, "y\n", 0],
+['n-5b', '-n 0', "y\n" x 5, '', 0],
+
+# With textutils-1.22, this failed.
+['f-pipe-1', '-f -n 1', "a\nb\n", "b\n", 0],
+
+# --zero-terminated
+['zero-1', '-z -n 1', "x\0y", "y", 0],
+['zero-2', '-z -n 2', "x\0y", "x\0y", 0],
+);
+
+my @Tests;
+
+foreach my $t (@tv)
+ {
+ my ($test_name, $flags, $in, $exp, $ret, $err_msg, $err_sub) = @$t;
+ my $e = [$test_name, $flags, {IN=>$in}, {OUT=>$exp}];
+ $ret
+ and push @$e, {EXIT=>$ret}, {ERR=>$err_msg}, {ERR_SUBST=>$err_sub};
+
+ $test_name =~ /^minus-/
+ and push @$e, {ENV=>'_POSIX2_VERSION=199209'};
+
+ $test_name =~ /^(err-6|c-2)$/
+ and push @$e, {ENV=>'_POSIX2_VERSION=200112'};
+
+ $test_name =~ /^obs-plus-/
+ and push @$e, {ENV=>'_POSIX2_VERSION=200809'};
+
+ $test_name =~ /^f-pipe-/
+ and push @$e, {ENV=>'POSIXLY_CORRECT=1'};
+
+ push @Tests, $e;
+ }
+
+@Tests = triple_test \@Tests;
+
+# If you run the minus* tests with a FILE arg they'd hang.
+# If you run the err-1 or err-3 tests with a FILE, they'd misinterpret
+# the arg unless we are using the obsolete form.
+@Tests = grep { $_->[0] !~ /^(minus|err-[13])/ || $_->[0] =~ /\.[rp]$/ } @Tests;
+
+# Using redirection or a file would make this hang.
+@Tests = grep { $_->[0] !~ /^f-/ || $_->[0] =~ /\.p$/ } @Tests;
+
+my $save_temps = $ENV{DEBUG};
+my $verbose = $ENV{VERBOSE};
+
+my $fail = run_tests ($prog, $prog, \@Tests, $save_temps, $verbose);
+exit $fail;
diff --git a/tests/tail/truncate.sh b/tests/tail/truncate.sh
new file mode 100755
index 0000000..7c9fbfc
--- /dev/null
+++ b/tests/tail/truncate.sh
@@ -0,0 +1,56 @@
+#!/bin/sh
+# Ensure all logs are output upon file truncation
+
+# Copyright (C) 2015-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ tail
+
+check_tail_output()
+{
+ local delay="$1"
+ grep "$tail_re" out > /dev/null ||
+ { sleep $delay; return 1; }
+}
+
+# Terminate any background tail process
+cleanup_() { kill $pid 2>/dev/null && wait $pid; }
+
+# Speedup the non inotify case
+fastpoll='-s.1 --max-unchanged-stats=1'
+
+for follow in '-f' '-F'; do
+ for mode in '' '---disable-inotify'; do
+ rm -f out
+ seq 10 > f || framework_failure_
+
+ tail $follow $mode $fastpoll f > out 2>&1 & pid=$!
+
+ # Wait up to 12.7s for tail to start
+ tail_re='^10$' retry_delay_ check_tail_output .1 7 ||
+ { cat out; fail=1; }
+
+ seq 11 15 > f || framework_failure_
+
+ # Wait up to 12.7s for new data
+ tail_re='^15$' retry_delay_ check_tail_output .1 7 ||
+ { cat out; fail=1; }
+
+ cleanup_
+ done
+done
+
+Exit $fail
diff --git a/tests/tail/wait.sh b/tests/tail/wait.sh
new file mode 100755
index 0000000..12b906b
--- /dev/null
+++ b/tests/tail/wait.sh
@@ -0,0 +1,90 @@
+#!/bin/sh
+# Make sure that 'tail -f' returns immediately if a file doesn't exist
+# while 'tail -F' waits for it to appear.
+
+# Copyright (C) 2003-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ tail
+
+grep '^#define HAVE_INOTIFY 1' "$CONFIG_HEADER" >/dev/null \
+ && HAVE_INOTIFY=1
+
+inotify_failed_re='inotify (resources exhausted|cannot be used)'
+
+touch here || framework_failure_
+{ touch unreadable && chmod a-r unreadable; } || framework_failure_
+
+# Terminate any background tail process
+cleanup_() { kill $pid 2>/dev/null && wait $pid; }
+
+# speedup non inotify case
+fastpoll='-s.1 --max-unchanged-stats=1'
+
+for mode in '' '---disable-inotify'; do
+ returns_ 124 timeout 10 tail $fastpoll -f $mode not_here && fail=1
+
+ if test ! -r unreadable; then # can't test this when root
+ returns_ 124 timeout 10 tail $fastpoll -f $mode unreadable && fail=1
+ fi
+
+ returns_ 124 timeout .1 tail $fastpoll -f $mode here 2>tail.err || fail=1
+
+ # 'tail -F' must wait in any case.
+
+ returns_ 124 timeout .1 tail $fastpoll -F $mode here 2>>tail.err || fail=1
+
+ if test ! -r unreadable; then # can't test this when root
+ returns_ 124 timeout .1 tail $fastpoll -F $mode unreadable || fail=1
+ fi
+
+ returns_ 124 timeout .1 tail $fastpoll -F $mode not_here || fail=1
+
+ grep -Ev "$inotify_failed_re" tail.err > x
+ mv x tail.err
+ compare /dev/null tail.err || fail=1
+ >tail.err
+done
+
+if test "$HAVE_INOTIFY" && test -z "$mode" && is_local_dir_ .; then
+ # Ensure -F never follows a descriptor after rename
+ # either with tiny or significant delays between operations
+ tail_F()
+ {
+ local delay="$1"
+
+ > k && > tail.out && > tail.err || framework_failure_
+ tail $fastpoll -F $mode k >tail.out 2>tail.err & pid=$!
+ sleep $delay
+ mv k l
+ sleep $delay
+ touch k
+ mv k l
+ sleep $delay
+ echo NO >> l
+ sleep $delay
+ cleanup_
+ rm -f k l
+
+ test -s tail.out \
+ && ! grep -E "$inotify_failed_re" tail.err >/dev/null
+ }
+
+ retry_delay_ tail_F 0 1 && { cat tail.out; fail=1; }
+ retry_delay_ tail_F .2 1 && { cat tail.out; fail=1; }
+fi
+
+Exit $fail
diff --git a/tests/test/test-N.sh b/tests/test/test-N.sh
new file mode 100755
index 0000000..58b3976
--- /dev/null
+++ b/tests/test/test-N.sh
@@ -0,0 +1,54 @@
+#!/bin/sh
+# Test 'test -N file'.
+
+# Copyright (C) 2018-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ test stat
+
+stat_test_N() {
+ mtime=$(env stat -c '%.Y' "$1")
+ atime=$(env stat -c '%.X' "$1")
+ test "$mtime" = "$atime" && return 1
+ latest=$(printf '%s\n' "$mtime" "$atime" | sort -g | tail -n1)
+ test "$mtime" = "$latest"
+}
+
+# For a freshly touched file, atime should equal mtime: 'test -N' returns 1.
+touch file || framework_failure_
+if ! stat_test_N file; then
+ returns_ 1 env test -N file || fail=1
+fi
+
+# Set access time to 2 days ago: 'test -N' returns 0.
+touch -a -d '12:00 today -2 days' file || framework_failure_
+if stat_test_N file; then
+ env test -N file || fail=1
+fi
+
+# Set mtime to 2 days before atime: 'test -N' returns 1;
+touch -m -d '12:00 today -4 days' file || framework_failure_
+if ! stat_test_N file; then
+ returns_ 1 env test -N file || fail=1
+fi
+
+# Now modify the file: 'test -N' returns 0.
+echo 'data' > file || framework_failure_
+if stat_test_N file; then
+ env test -N file || fail=1
+fi
+
+Exit $fail
diff --git a/tests/test/test-diag.pl b/tests/test/test-diag.pl
new file mode 100755
index 0000000..5210203
--- /dev/null
+++ b/tests/test/test-diag.pl
@@ -0,0 +1,38 @@
+#!/usr/bin/perl
+# Test the diagnostics of "test".
+
+# Copyright (C) 2006-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+use strict;
+
+(my $program_name = $0) =~ s|.*/||;
+
+# Turn off localization of executable's output.
+@ENV{qw(LANGUAGE LANG LC_ALL)} = ('C') x 3;
+
+my @Tests =
+ (
+ # In coreutils-5.93, this diagnostic lacked the newline.
+ ['o', '-o arg', {ERR => "test: '-o': unary operator expected\n"},
+ {ERR_SUBST => 's!^.*test:!test:!'},
+ {EXIT => 2}],
+ );
+
+my $save_temps = $ENV{DEBUG};
+my $verbose = $ENV{VERBOSE};
+my $prog = 'test';
+my $fail = run_tests ($program_name, \$prog, \@Tests, $save_temps, $verbose);
+exit $fail;
diff --git a/tests/test/test.pl b/tests/test/test.pl
new file mode 100755
index 0000000..dfc3968
--- /dev/null
+++ b/tests/test/test.pl
@@ -0,0 +1,197 @@
+#!/usr/bin/perl
+
+# Copyright (C) 2008-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+use strict;
+
+my $limits = getlimits ();
+
+my $prog = 'test';
+
+# Turn off localization of executable's output.
+@ENV{qw(LANGUAGE LANG LC_ALL)} = ('C') x 3;
+
+sub digest_test ($)
+{
+ my ($t) = @_;
+ my @args;
+ my $ret = 0;
+ my @list_of_hashref;
+ foreach my $e (@$t)
+ {
+ !ref $e
+ and push (@args, $e), next;
+ ref $e eq 'HASH'
+ or (warn "$0: $t->[0]: unexpected entry type\n"), next;
+
+ exists $e->{EXIT}
+ and $ret = $e->{EXIT}, next;
+
+ push @list_of_hashref, $e;
+ }
+ shift @args; # discard test name
+ my $flags = join ' ', @args;
+
+ return ($flags, $ret, \@list_of_hashref);
+}
+
+sub add_inverse_op_tests($)
+{
+ my ($tests) = @_;
+ my @new;
+
+ my %inverse_op =
+ (
+ eq => 'ne',
+ lt => 'ge',
+ gt => 'le',
+ );
+
+ foreach my $t (@$tests)
+ {
+ push @new, $t;
+
+ my $test_name = $t->[0];
+ my ($flags, $ret, $LoH) = digest_test $t;
+
+ # Generate corresponding tests of inverse ops.
+ # E.g. generate tests of '-ge' from those of '-lt'.
+ foreach my $op (qw(gt lt eq))
+ {
+ if ($test_name =~ /$op-/ && $flags =~ / -$op /)
+ {
+ my $inv = $inverse_op{$op};
+ $test_name =~ s/$op/$inv/;
+ $flags =~ s/-$op/-$inv/;
+ $ret = 1 - $ret;
+ push (@new, [$test_name, $flags, {EXIT=>$ret}, @$LoH]);
+ }
+ }
+ }
+ return @new;
+}
+
+sub add_pn_tests($)
+{
+ my ($tests) = @_;
+ my @new;
+
+ # Generate parenthesized and negated versions of each test.
+ # There are a few exceptions.
+ my %not_N = map {$_ => 1} qw (1a);
+ my %not_P = map {$_ => 1} qw (1a
+ streq-6 strne-6
+ paren-1 paren-2 paren-3 paren-4 paren-5);
+ foreach my $t (@$tests)
+ {
+ push @new, $t;
+
+ my $test_name = $t->[0];
+ my ($flags, $ret, $LoH) = digest_test $t;
+ next if $ret == 2;
+
+ push (@new, ["N-$test_name", "! $flags", {EXIT=>1-$ret}, @$LoH])
+ unless $not_N{$test_name};
+ push (@new, ["P-$test_name", "'(' $flags ')'", {EXIT=>$ret}, @$LoH])
+ unless $not_P{$test_name};
+ push (@new, ["NP-$test_name", "! '(' $flags ')'", {EXIT=>1-$ret}, @$LoH])
+ unless $not_P{$test_name};
+ push (@new, ["NNP-$test_name", "! ! '(' $flags ')'", {EXIT=>$ret, @$LoH}])
+ unless $not_P{$test_name};
+ }
+
+ return @new;
+}
+
+my @Tests =
+(
+ ['1a', {EXIT=>1}],
+ ['1b', qw(-z '')],
+ ['1c', 'any-string'],
+ ['1d', qw(-n any-string)],
+ ['1e', "''", {EXIT=>1}],
+ ['1f', '-'],
+ ['1g', '--'],
+ ['1h', '-0'],
+ ['1i', '-f'],
+ ['1j', '--help'],
+ ['1k', '--version'],
+
+ ['streq-1', qw(t = t)],
+ ['streq-2', qw(t = f), {EXIT=>1}],
+ ['streqeq-1', qw(t == t)],
+ ['streqeq-2', qw(t == f), {EXIT=>1}],
+ ['streq-3', qw(! = !)],
+ ['streq-4', qw(= = =)],
+ ['streq-5', "'(' = '('"],
+ ['streq-6', "'(' = ')'", {EXIT=>1}],
+ ['strne-1', qw(t != t), {EXIT=>1}],
+ ['strne-2', qw(t != f)],
+ ['strne-3', qw(! != !), {EXIT=>1}],
+ ['strne-4', qw(= != =), {EXIT=>1}],
+ ['strne-5', "'(' != '('", {EXIT=>1}],
+ ['strne-6', "'(' != ')'"],
+
+ ['and-1', qw(t -a t)],
+ ['and-2', qw('' -a t), {EXIT=>1}],
+ ['and-3', qw(t -a ''), {EXIT=>1}],
+ ['and-4', qw('' -a ''), {EXIT=>1}],
+
+ ['or-1', qw(t -o t)],
+ ['or-2', qw('' -o t)],
+ ['or-3', qw(t -o '')],
+ ['or-4', qw('' -o ''), {EXIT=>1}],
+
+ ['eq-1', qw(9 -eq 9)],
+ ['eq-2', qw(0 -eq 0)],
+ ['eq-3', qw(0 -eq 00)],
+ ['eq-4', qw(8 -eq 9), {EXIT=>1}],
+ ['eq-5', qw(1 -eq 0), {EXIT=>1}],
+ ['eq-6', "$limits->{UINTMAX_OFLOW} -eq 0", {EXIT=>1}],
+
+ ['gt-1', qw(5 -gt 5), {EXIT=>1}],
+ ['gt-2', qw(5 -gt 4)],
+ ['gt-3', qw(4 -gt 5), {EXIT=>1}],
+ ['gt-4', qw(-1 -gt -2)],
+ ['gt-5', "$limits->{UINTMAX_OFLOW} -gt $limits->{INTMAX_UFLOW}"],
+
+ ['lt-1', qw(5 -lt 5), {EXIT=>1}],
+ ['lt-2', qw(5 -lt 4), {EXIT=>1}],
+ ['lt-3', qw(4 -lt 5)],
+ ['lt-4', qw(-1 -lt -2), {EXIT=>1}],
+ ['lt-5', "$limits->{INTMAX_UFLOW} -lt $limits->{UINTMAX_OFLOW}"],
+
+ ['inv-1', qw(0x0 -eq 00), {EXIT=>2},
+ {ERR=>"$prog: invalid integer '0x0'\n"}],
+
+ ['t1', "-t"],
+ ['t2', qw(-t 1), {EXIT=>1}],
+
+ ['paren-1', "'(' '' ')'", {EXIT=>1}],
+ ['paren-2', "'(' '(' ')'"],
+ ['paren-3', "'(' ')' ')'"],
+ ['paren-4', "'(' ! ')'"],
+ ['paren-5', "'(' -a ')'"],
+);
+
+@Tests = add_inverse_op_tests \@Tests;
+@Tests = add_pn_tests \@Tests;
+
+my $save_temps = $ENV{DEBUG};
+my $verbose = $ENV{VERBOSE};
+
+my $fail = run_tests ($prog, \$prog, \@Tests, $save_temps, $verbose);
+exit $fail;
diff --git a/tests/timeout/timeout-blocked.pl b/tests/timeout/timeout-blocked.pl
new file mode 100755
index 0000000..2ec865f
--- /dev/null
+++ b/tests/timeout/timeout-blocked.pl
@@ -0,0 +1,48 @@
+#!/usr/bin/perl
+# Test that timeout handles blocked SIGALRM from its parent.
+
+# Copyright (C) 2013-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+use strict;
+
+(my $ME = $0) =~ s|.*/||;
+
+eval { require POSIX; };
+$@
+ and CuSkip::skip "$ME: this script requires Perl's POSIX module\n";
+
+use POSIX qw(:signal_h);
+my $sigset = POSIX::SigSet->new(SIGALRM); # define the signals to block
+my $old_sigset = POSIX::SigSet->new; # where the old sigmask will be kept
+unless (defined sigprocmask(SIG_BLOCK, $sigset, $old_sigset)) {
+ CuSkip::skip "$ME: sigprocmask failed; skipped";
+}
+
+my @Tests =
+ (
+ # test-name, [option, option, ...] {OUT=>"expected-output"}
+ #
+
+ ['block-alrm', ".1 sleep 10", {EXIT => 124}],
+ );
+
+my $save_temps = $ENV{DEBUG};
+my $verbose = $ENV{VERBOSE};
+
+my $prog = 'timeout';
+my $fail = run_tests ($ME, $prog, \@Tests, $save_temps, $verbose);
+
+exit $fail;
diff --git a/tests/timeout/timeout-group.sh b/tests/timeout/timeout-group.sh
new file mode 100755
index 0000000..053abc9
--- /dev/null
+++ b/tests/timeout/timeout-group.sh
@@ -0,0 +1,103 @@
+#!/bin/sh
+# test program group handling
+
+# Copyright (C) 2011-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ timeout
+require_trap_signame_
+require_kill_group_
+
+# construct a program group hierarchy as follows:
+# timeout-group - foreground group
+# group.sh - separate group
+# timeout.cmd - same group as group.sh
+#
+# We then send a SIGINT to the "separate group"
+# to simulate what happens when a Ctrl-C
+# is sent to the foreground group.
+
+setsid true || skip_ "setsid required to control groups"
+
+printf '%s\n' '#!'"$SHELL" > timeout.cmd || framework_failure_
+cat >> timeout.cmd <<\EOF
+trap 'touch int.received; exit' INT
+touch timeout.running
+count=$1
+until test -e int.received || test $count = 0; do
+ sleep 1
+ count=$(expr $count - 1)
+done
+EOF
+chmod a+x timeout.cmd
+
+cat > group.sh <<EOF
+#!$SHELL
+trap '' INT
+timeout --foreground 25 ./timeout.cmd 20&
+wait
+EOF
+chmod a+x group.sh
+
+check_timeout_cmd_running()
+{
+ local delay="$1"
+ test -e timeout.running ||
+ { sleep $delay; return 1; }
+}
+
+# Terminate any background processes
+cleanup_() { kill $pid 2>/dev/null && wait $pid; }
+
+# Start above script in its own group.
+# We could use timeout for this, but that assumes an implementation.
+setsid ./group.sh & pid=$!
+# Wait 6.3s for timeout.cmd to start
+retry_delay_ check_timeout_cmd_running .1 6 || fail=1
+# Simulate a Ctrl-C to the group to test timely exit
+kill -INT -- -$pid
+wait
+test -e int.received || fail=1
+
+rm -f int.received timeout.running
+
+
+# Ensure cascaded timeouts work
+# or more generally, ensure we timeout
+# commands that create their own group
+# This didn't work before 8.13.
+
+start=$(date +%s)
+
+# Note the first timeout must send a signal that
+# the second is handling for it to be propagated to the command.
+# SIGINT, SIGTERM, SIGALRM etc. are implicit.
+timeout -sALRM 30 timeout -sINT 25 ./timeout.cmd 20 & pid=$!
+# Wait 6.3s for timeout.cmd to start
+retry_delay_ check_timeout_cmd_running .1 6 || fail=1
+kill -ALRM $pid # trigger the alarm of the first timeout command
+wait $pid
+ret=$?
+test $ret -eq 124 ||
+ skip_ "timeout returned $ret. SIGALRM not handled?"
+test -e int.received || fail=1
+
+end=$(date +%s)
+
+test $(expr $end - $start) -lt 20 ||
+ skip_ "timeout.cmd didn't receive a signal until after sleep?"
+
+Exit $fail
diff --git a/tests/timeout/timeout-large-parameters.sh b/tests/timeout/timeout-large-parameters.sh
new file mode 100755
index 0000000..510d985
--- /dev/null
+++ b/tests/timeout/timeout-large-parameters.sh
@@ -0,0 +1,46 @@
+#!/bin/sh
+# Validate large timeout parameters
+# Separated from standard parameter testing due to kernel overflow bugs.
+
+# Copyright (C) 2008-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ timeout
+getlimits_
+
+# It was seen on 32 bit Linux/HPPA and OpenIndiana 11
+# that a kernel time_t overflowing cause the timer to fire immediately.
+# This is still racy, but unlikely to cause an issue unless
+# timeout can't process the timer firing within 3 seconds.
+timeout $TIME_T_OFLOW sleep 3
+if test $? = 124; then
+ skip_ 'timeout $TIME_T_OFLOW ..., timed out immediately!'
+fi
+
+# timeout overflow
+timeout $UINT_OFLOW sleep 0 || fail=1
+
+# timeout overflow
+timeout ${TIME_T_OFLOW}d sleep 0 || fail=1
+
+# floating point notation
+timeout 2.34e+5d sleep 0 || fail=1
+
+# floating point overflow
+timeout $LDBL_MAX sleep 0 || fail=1
+returns_ 125 timeout -- -$LDBL_MAX sleep 0 || fail=1
+
+Exit $fail
diff --git a/tests/timeout/timeout-parameters.sh b/tests/timeout/timeout-parameters.sh
new file mode 100755
index 0000000..8bb74c5
--- /dev/null
+++ b/tests/timeout/timeout-parameters.sh
@@ -0,0 +1,50 @@
+#!/bin/sh
+# Validate timeout parameter combinations
+
+# Copyright (C) 2008-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ timeout env
+getlimits_
+
+
+# internal errors are 125, distinct from execution failure
+
+# invalid timeout
+returns_ 125 timeout invalid sleep 0 || fail=1
+
+# invalid kill delay
+returns_ 125 timeout --kill-after=invalid 1 sleep 0 || fail=1
+
+# invalid timeout suffix
+returns_ 125 timeout 42D sleep 0 || fail=1
+
+# floating point notation
+timeout 10.34 sleep 0 || fail=1
+
+# nanoseconds potentially supported
+timeout 9.999999999 sleep 0 || fail=1
+
+# invalid signal spec
+returns_ 125 timeout --signal=invalid 1 sleep 0 || fail=1
+
+# invalid command
+returns_ 126 env . && { returns_ 126 timeout 10 . || fail=1; }
+
+# no such command
+returns_ 127 timeout 10 no_such || fail=1
+
+Exit $fail
diff --git a/tests/timeout/timeout.sh b/tests/timeout/timeout.sh
new file mode 100755
index 0000000..0881770
--- /dev/null
+++ b/tests/timeout/timeout.sh
@@ -0,0 +1,74 @@
+#!/bin/sh
+# Validate timeout basic operation
+
+# Copyright (C) 2008-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ timeout
+require_trap_signame_
+
+# no timeout
+timeout 10 true || fail=1
+
+# no timeout (suffix check)
+timeout 1d true || fail=1
+
+# disabled timeout
+timeout 0 true || fail=1
+
+# exit status propagation
+returns_ 2 timeout 10 sh -c 'exit 2' || fail=1
+
+# timeout
+returns_ 124 timeout .1 sleep 10 || fail=1
+
+# exit status propagation even on timeout
+# exit status should be 128+TERM
+returns_ 124 timeout --preserve-status .1 sleep 10 && fail=1
+
+# kill delay. Note once the initial timeout triggers,
+# the exit status will be 124 even if the command
+# exits on its own accord.
+# exit status should be 128+KILL
+returns_ 124 timeout -s0 -k1 .1 sleep 10 && fail=1
+# Ensure a consistent exit status with --foreground
+returns_ 124 timeout --foreground -s0 -k1 .1 sleep 10 && fail=1
+
+# Ensure 'timeout' is immune to parent's SIGCHLD handler
+# Use a subshell and an exec to work around a bug in FreeBSD 5.0 /bin/sh.
+(
+ trap '' CHLD
+
+ exec timeout 10 true
+) || fail=1
+
+# Don't be confused when starting off with a child (Bug#9098).
+out=$(sleep .1 & exec timeout .5 sh -c 'sleep 2; echo foo')
+status=$?
+test "$out" = "" && test $status = 124 || fail=1
+
+# Verify --verbose output
+cat > exp <<\EOF
+timeout: sending signal EXIT to command 'sleep'
+timeout: sending signal KILL to command 'sleep'
+EOF
+for opt in -v --verbose; do
+ timeout $opt -s0 -k .1 .1 sleep 10 2> errt
+ sed '/^Killed/d' < errt > err || framework_failure_
+ compare exp err || fail=1
+done
+
+Exit $fail
diff --git a/tests/touch/60-seconds.sh b/tests/touch/60-seconds.sh
new file mode 100755
index 0000000..9c59856
--- /dev/null
+++ b/tests/touch/60-seconds.sh
@@ -0,0 +1,33 @@
+#!/bin/sh
+# touch -t would mistakenly reject a time specifying "60" seconds
+
+# Copyright (C) 2009-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ touch
+
+echo 60.000000000 > exp || framework_failure_
+
+
+# Before coreutils-7.7, this would fail, complaining of
+# an 'invalid date format'. Specifying 60 seconds *is* valid.
+TZ=UTC0 touch -t 197001010000.60 f || fail=1
+
+stat --p='%.9Y\n' f > out || fail=1
+
+compare exp out || fail=1
+
+Exit $fail
diff --git a/tests/touch/dangling-symlink.sh b/tests/touch/dangling-symlink.sh
new file mode 100755
index 0000000..0904e3e
--- /dev/null
+++ b/tests/touch/dangling-symlink.sh
@@ -0,0 +1,49 @@
+#!/bin/sh
+# Make sure touch can create a file through a dangling symlink.
+# This was broken in the 4.0[e-i] test releases.
+
+# Copyright (C) 1999-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ touch
+
+rm -f touch-target t-symlink
+ln -s touch-target t-symlink
+
+# This used to infloop.
+touch t-symlink || fail=1
+
+test -f touch-target || fail=1
+rm -f touch-target t-symlink
+
+if test $fail = 1; then
+ case $host_triplet in
+ *linux-gnu*)
+ case "$(uname -r)" in
+ 2.3.9[0-9]*)
+ skip_ \
+'****************************************************
+WARNING!!!
+This version of the Linux kernel causes touch to fail
+when operating on dangling symlinks.
+****************************************************'
+ ;;
+ esac
+ ;;
+ esac
+fi
+
+Exit $fail
diff --git a/tests/touch/dir-1.sh b/tests/touch/dir-1.sh
new file mode 100755
index 0000000..cb0e172
--- /dev/null
+++ b/tests/touch/dir-1.sh
@@ -0,0 +1,9 @@
+#!/bin/sh
+# Make sure touch can operate on a directory.
+# This was broken in the 4.0[efg] test releases.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ touch
+
+touch . || fail=1
+Exit $fail
diff --git a/tests/touch/empty-file.sh b/tests/touch/empty-file.sh
new file mode 100755
index 0000000..6946ae3
--- /dev/null
+++ b/tests/touch/empty-file.sh
@@ -0,0 +1,80 @@
+#!/bin/sh
+# Make sure touch can set the mtime on an empty file.
+
+# Copyright (C) 1998-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+
+# Volker Borchert reported that touch 3.16r (and presumably all before that)
+# fails to work on SunOS 4.1.3 with 'most of the recommended patches' when
+# the empty file is on an NFS-mounted 4.2 volume.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ touch
+
+DEFAULT_SLEEP_SECONDS=2
+SLEEP_SECONDS=${SLEEP_SECONDS=$DEFAULT_SLEEP_SECONDS}
+
+
+# FIXME: find writable directories on other partitions
+# and run the test in those directories, too.
+
+: ${TOUCH_DIR_LIST=.}
+
+
+for d in $TOUCH_DIR_LIST; do
+ rm -rf $d/a $d/b $d/c
+ > $d/a || framework_failure_
+ test -f $d/a || framework_failure_
+ > $d/b || framework_failure_
+ test -f $d/b || framework_failure_
+ > $d/c || framework_failure_
+ test -f $d/c || framework_failure_
+done
+
+echo sleeping for $SLEEP_SECONDS seconds...
+sleep $SLEEP_SECONDS
+for d in $TOUCH_DIR_LIST; do
+ touch $d/a || fail=1
+ set x $(ls -t $d/a $d/b)
+ test "$*" = "x $d/a $d/b" || fail=1
+done
+
+echo sleeping for $SLEEP_SECONDS seconds...
+sleep $SLEEP_SECONDS
+for d in $TOUCH_DIR_LIST; do
+ touch $d/b
+ set x $(ls -t $d/a $d/b)
+ test "$*" = "x $d/b $d/a" || fail=1
+
+ if touch - 1< $d/c 2> /dev/null; then
+ set x $(ls -t $d/a $d/c)
+ test "$*" = "x $d/c $d/a" || fail=1
+ fi
+
+ rm -rf $d/a $d/b $d/c
+done
+
+if test $fail != 0; then
+ cat 1>&2 <<EOF
+*** This test has just failed. That can happen when the test is run in an
+*** NFS-mounted directory on a system whose clock is not well synchronized
+*** with that of the NFS server. If you think that is the reason, set the
+*** environment variable SLEEP_SECONDS to some number of seconds larger than
+*** the default of $DEFAULT_SLEEP_SECONDS and rerun the test.
+EOF
+fi
+
+Exit $fail
diff --git a/tests/touch/fail-diag.sh b/tests/touch/fail-diag.sh
new file mode 100755
index 0000000..73d6e39
--- /dev/null
+++ b/tests/touch/fail-diag.sh
@@ -0,0 +1,32 @@
+#!/bin/sh
+# make sure touch gives reasonable diagnostics
+
+# Copyright (C) 2001-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ touch
+skip_if_root_
+
+file=/no-such-dir/file
+
+touch $file > out 2>&1 && fail=1
+cat <<EOF > exp
+touch: cannot touch '$file': No such file or directory
+EOF
+
+compare exp out || fail=1
+
+Exit $fail
diff --git a/tests/touch/fifo.sh b/tests/touch/fifo.sh
new file mode 100755
index 0000000..f05f5e8
--- /dev/null
+++ b/tests/touch/fifo.sh
@@ -0,0 +1,27 @@
+#!/bin/sh
+# Make sure touch works on fifos without hanging.
+
+# Copyright (C) 2000-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ touch
+
+mkfifo_or_skip_ fifo
+
+
+touch fifo || fail=1
+
+Exit $fail
diff --git a/tests/touch/no-create-missing.sh b/tests/touch/no-create-missing.sh
new file mode 100755
index 0000000..0351b9d
--- /dev/null
+++ b/tests/touch/no-create-missing.sh
@@ -0,0 +1,37 @@
+#!/bin/sh
+# Ensure that touch -c no-such-file no longer fails (it did in 4.1.8).
+
+# Copyright (C) 2002-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ touch test
+
+
+touch -c no-file > /dev/null 2>&1 || fail=1
+touch -cm no-file > /dev/null 2>&1 || fail=1
+touch -ca no-file > /dev/null 2>&1 || fail=1
+
+# If >&- works, test "touch -c -" etc.
+# >&- apparently does not work in HP-UX 11.23.
+# This test is ineffective unless /dev/stdout also works.
+if env test -w /dev/stdout >/dev/null &&
+ env test ! -w /dev/stdout >&-; then
+ touch -c - >&- 2> /dev/null || fail=1
+ touch -cm - >&- 2> /dev/null || fail=1
+ touch -ca - >&- 2> /dev/null || fail=1
+fi
+
+Exit $fail
diff --git a/tests/touch/no-dereference.sh b/tests/touch/no-dereference.sh
new file mode 100755
index 0000000..adbf1f7
--- /dev/null
+++ b/tests/touch/no-dereference.sh
@@ -0,0 +1,82 @@
+#!/bin/sh
+# Ensure that touch -h works.
+
+# Copyright (C) 2009-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ touch test
+
+ln -s nowhere dangling || framework_failure_
+touch file || framework_failure_
+ln -s file link || framework_failure_
+
+
+# These first tests should work on every platform.
+# -h does not create files, but it warns. Use -c to silence warning.
+returns_ 1 touch -h no-file 2> err || fail=1
+compare /dev/null err && fail=1
+touch -h -c no-file 2> err || fail=1
+compare /dev/null err || fail=1
+
+# -h works on regular files
+touch -h file || fail=1
+
+# -h coupled with -r uses timestamp of the symlink, not the referent.
+touch -h -r dangling file || fail=1
+test -f nowhere && fail=1
+
+# The remaining tests of -h require kernel support for changing symlink times.
+grep '^#define HAVE_UTIMENSAT 1' "$CONFIG_HEADER" > /dev/null ||
+grep '^#define HAVE_LUTIMES 1' "$CONFIG_HEADER" > /dev/null ||
+ skip_ 'this system lacks the utimensat function'
+
+# Changing time of dangling symlink is okay.
+# Skip the test if this fails, but the error text corresponds to
+# ENOSYS (possible with old kernel but new glibc).
+touch -h dangling 2> err
+case $? in
+ 0) test -f nowhere && fail=1
+ compare /dev/null err || fail=1;;
+ 1) grep 'Function not implemented' err \
+ && skip_ 'this system lacks the utimensat function'
+ fail=1;;
+ *) fail=1;;
+esac
+
+# Change the mtime of a symlink.
+touch -m -h -d 2009-10-10 link || fail=1
+case $(stat --format=%y link) in
+ 2009-10-10*) ;;
+ *) fail=1 ;;
+esac
+case $(stat --format=%y file) in
+ 2009-10-10*) fail=1;;
+esac
+
+# Test interactions with -.
+touch -h - > file || fail=1
+
+# If >&- works, test "touch -ch -" etc.
+# >&- apparently does not work in HP-UX 11.23.
+# This test is ineffective unless /dev/stdout also works.
+# If stdout is open, it is not a symlink.
+if env test -w /dev/stdout >/dev/null &&
+ env test ! -w /dev/stdout >&-; then
+ returns_ 1 touch -h - >&- || fail=1
+ touch -h -c - >&- || fail=1
+fi
+
+Exit $fail
diff --git a/tests/touch/no-rights.sh b/tests/touch/no-rights.sh
new file mode 100755
index 0000000..8dec177
--- /dev/null
+++ b/tests/touch/no-rights.sh
@@ -0,0 +1,40 @@
+#!/bin/sh
+# Make sure touch can update the times on a file that is neither
+# readable nor writable.
+
+# Copyright (C) 1999-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ touch
+
+# Make sure t2 is newer than t1.
+touch -d '2000-01-01 00:00' t1 || framework_failure_
+touch -d '2000-01-02 00:00' t2 || framework_failure_
+
+set x $(ls -t t1 t2)
+test "$*" = "x t2 t1" || framework_failure_
+
+
+chmod 0 t1
+touch -d '2000-01-03 00:00' -c t1 || fail=1
+
+set x $(ls -t t1 t2)
+test "$*" = "x t1 t2" || fail=1
+
+# Also test the combination of --no-create and -a.
+touch -a --no-create t1 || fail=1
+
+Exit $fail
diff --git a/tests/touch/not-owner.sh b/tests/touch/not-owner.sh
new file mode 100755
index 0000000..c9428de
--- /dev/null
+++ b/tests/touch/not-owner.sh
@@ -0,0 +1,55 @@
+#!/bin/sh
+# Make sure that touch gives reasonable diagnostics when applied
+# to an unwritable directory owned by some other user.
+
+# Copyright (C) 2003-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ touch
+
+if env -- test -w /; then
+ skip_ you have write access to /.
+fi
+
+if env -- test -O / || env -- test -G /; then
+ skip_ "you own /."
+fi
+
+skip_if_root_
+
+
+# Before fileutils-4.1, we'd get the following misleading
+# diagnostic instead of '...: Permission denied'.
+# touch: creating '/': Is a directory
+touch / > out 2>&1 && fail=1
+
+# On SunOS4, EPERM is 'Not owner'.
+# On some *BSD systems it's 'Operation not permitted'.
+# On a system where root file system is mounted read-only
+# it's 'Read-only file system'.
+for msg in 'Not owner' 'Operation not permitted' 'Permission denied' \
+ 'Read-only file system'; do
+ cat > exp <<EOF
+touch: setting times of '/': $msg
+EOF
+
+ cmp out exp > /dev/null 2>&1 && { match=1; break; }
+done
+test "$match" = 1 || fail=1
+
+test $fail = 1 && compare exp out
+
+Exit $fail
diff --git a/tests/touch/now-owned-by-other.sh b/tests/touch/now-owned-by-other.sh
new file mode 100755
index 0000000..ad4901c
--- /dev/null
+++ b/tests/touch/now-owned-by-other.sh
@@ -0,0 +1,34 @@
+#!/bin/sh
+# Demonstrate that "touch -d now writable-but-owned-by-other" works.
+
+# Copyright (C) 2008-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ touch
+require_root_
+
+# Create a file owned by root, and writable by $NON_ROOT_USERNAME.
+echo > root-owned || framework_failure_
+chgrp +$NON_ROOT_GID . root-owned || framework_failure_
+chmod g+w root-owned
+
+# Ensure that the current directory is searchable by $NON_ROOT_USERNAME.
+chmod g+x .
+
+chroot --skip-chdir --user=$NON_ROOT_USERNAME / env PATH="$PATH" \
+ touch -d now root-owned || fail=1
+
+Exit $fail
diff --git a/tests/touch/obsolescent.sh b/tests/touch/obsolescent.sh
new file mode 100755
index 0000000..76d55aa
--- /dev/null
+++ b/tests/touch/obsolescent.sh
@@ -0,0 +1,41 @@
+#!/bin/sh
+# Test touch with obsolescent 8- or 10-digit timestamps.
+
+# Copyright (C) 2000-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ touch
+
+_POSIX2_VERSION=199209; export _POSIX2_VERSION
+POSIXLY_CORRECT=1; export POSIXLY_CORRECT
+
+
+yearstart=01010000
+
+for ones in 11111111 1111111111; do
+ for args in $ones "-- $ones" "$yearstart $ones" "-- $yearstart $ones"; do
+ touch $args || fail=1
+ test -f $ones || fail=1
+ test -f $yearstart && fail=1
+ rm -f $ones || fail=1
+ done
+done
+
+y2000=0101000000
+rm -f $y2000 file || fail=1
+touch $y2000 file && test -f $y2000 && test -f file || fail=1
+
+Exit $fail
diff --git a/tests/touch/read-only.sh b/tests/touch/read-only.sh
new file mode 100755
index 0000000..18e2c6a
--- /dev/null
+++ b/tests/touch/read-only.sh
@@ -0,0 +1,31 @@
+#!/bin/sh
+# ensure that touch can operate on read-only files
+
+# Copyright (C) 2005-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ touch
+skip_if_root_
+
+> read-only || framework_failure_
+chmod 444 read-only || framework_failure_
+
+
+touch read-only || fail=1
+
+touch - 1< read-only 2> /dev/null && { test ! -f - || fail=1; }
+
+Exit $fail
diff --git a/tests/touch/relative.sh b/tests/touch/relative.sh
new file mode 100755
index 0000000..03ce8de
--- /dev/null
+++ b/tests/touch/relative.sh
@@ -0,0 +1,38 @@
+#!/bin/sh
+# Demonstrate using a combination of --reference and --date to
+# set the time of a file back by an arbitrary amount.
+
+# Copyright (C) 2004-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ touch
+
+TZ=UTC0 touch --date='2004-01-16 12:00 +0000' f || framework_failure_
+
+
+# Set times back by 5 days.
+touch --ref f --date='-5 days' f || fail=1
+
+TZ=UTC0 ls -og --time-style=+%Y-%m-%d f > out.1 || fail=1
+sed 's/ f$//;s/.* //' out.1 > out
+
+cat <<\EOF > exp || framework_failure_
+2004-01-11
+EOF
+
+compare exp out || fail=1
+
+Exit $fail
diff --git a/tests/touch/trailing-slash.sh b/tests/touch/trailing-slash.sh
new file mode 100755
index 0000000..0c48f3d
--- /dev/null
+++ b/tests/touch/trailing-slash.sh
@@ -0,0 +1,70 @@
+#!/bin/sh
+# Ensure that touch honors trailing slash.
+
+# Copyright (C) 2009-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ touch
+
+ln -s nowhere dangling || framework_failure_
+ln -s loop loop || framework_failure_
+touch file || framework_failure_
+ln -s file link1 || framework_failure_
+mkdir dir || framework_failure_
+ln -s dir link2 || framework_failure_
+
+
+# Trailing slash can only appear on directory or symlink-to-directory.
+# Up through coreutils 8.0, Solaris 9 failed these tests.
+returns_ 1 touch no-file/ || fail=1
+returns_ 1 touch file/ || fail=1
+returns_ 1 touch dangling/ || fail=1
+returns_ 1 touch loop/ || fail=1
+if returns_ 2 ls link1/; then # darwin allows trailing slash to files
+ returns_ 1 touch link1/ || fail=1
+fi
+touch dir/ || fail=1
+
+# -c silences ENOENT, but not ENOTDIR or ELOOP
+touch -c no-file/ || fail=1
+returns_ 1 touch -c file/ || fail=1
+touch -c dangling/ || fail=1
+returns_ 1 touch -c loop/ || fail=1
+if returns_ 2 ls link1/; then
+ returns_ 1 touch -c link1/ || fail=1
+fi
+touch -c dir/ || fail=1
+returns_ 1 test -f no-file || fail=1
+returns_ 1 test -f nowhere || fail=1
+
+# Trailing slash dereferences a symlink, even with -h.
+# mtime is sufficient to show pass (besides, lstat changes atime of
+# symlinks and directories under Cygwin 1.5).
+touch -d 2009-10-10 -h link2/ || fail=1
+touch -h -r link2/ file || fail=1
+case $(stat --format=%y dir) in
+ 2009-10-10*) ;;
+ *) fail=1 ;;
+esac
+case $(stat --format=%y link2) in
+ 2009-10-10*) fail=1 ;;
+esac
+case $(stat --format=%y file) in
+ 2009-10-10*) ;;
+ *) fail=1 ;;
+esac
+
+Exit $fail
diff --git a/tests/tr/tr-case-class.sh b/tests/tr/tr-case-class.sh
new file mode 100755
index 0000000..6f15b8a
--- /dev/null
+++ b/tests/tr/tr-case-class.sh
@@ -0,0 +1,116 @@
+#!/bin/sh
+# Test case conversion classes
+
+# Copyright (C) 2010-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ tr
+
+# Ensure we support translation of case classes with extension
+echo '01234567899999999999999999' > exp
+echo 'abcdefghijklmnopqrstuvwxyz' |
+tr '[:lower:]' '0-9' > out || fail=1
+compare exp out || fail=1
+echo 'abcdefghijklmnopqrstuvwxyz' |
+tr '[:lower:][:lower:]' '[:upper:]0-9' > out || fail=1
+compare exp out || fail=1
+
+# Validate the alignment of case classes
+returns_ 1 tr 'A-Z[:lower:]' 'a-y[:upper:]' </dev/null || fail=1
+returns_ 1 tr '[:upper:][:lower:]' 'a-y[:upper:]' </dev/null || fail=1
+returns_ 1 tr 'A-Y[:lower:]' 'a-z[:upper:]' </dev/null || fail=1
+returns_ 1 tr 'A-Z[:lower:]' '[:lower:][:upper:]' </dev/null || fail=1
+returns_ 1 tr 'A-Z[:lower:]' '[:lower:]A-Z' </dev/null || fail=1
+tr '[:upper:][:lower:]' 'a-z[:upper:]' < /dev/null || fail=1
+tr '[:upper:][:lower:]' '[:upper:]a-z' < /dev/null || fail=1
+
+# Before coreutils 8.6 the trailing space in string1
+# caused the case class in string2 to be extended.
+# However that was not portable, dependent on locale
+# and in contravention of POSIX.
+tr '[:upper:] ' '[:lower:]' < /dev/null 2>out && fail=1
+echo 'tr: when translating with string1 longer than string2,
+the latter string must not end with a character class' > exp
+compare exp out || fail=1
+
+# Up to coreutils-6.9, tr rejected an unmatched [:lower:] or [:upper:] in SET1.
+echo '#$%123abcABC' | tr '[:lower:]' '[.*]' > out || fail=1
+echo '#$%123...ABC' > exp
+compare exp out || fail=1
+echo '#$%123abcABC' | tr '[:upper:]' '[.*]' > out || fail=1
+echo '#$%123abc...' > exp
+compare exp out || fail=1
+
+# When doing a case-converting translation with something after the
+# [:upper:] and [:lower:] elements, ensure that tr honors the following byte.
+echo 'abc.' | tr '[:lower:].' '[:upper:]x' > out || fail=1
+echo 'ABCx' > exp
+compare exp out || fail=1
+
+# Before coreutils 8.6 the disparate number of upper and lower
+# characters in some locales, triggered abort()s and invalid behavior
+export LC_ALL=en_US.ISO-8859-1
+
+if test "$(locale charmap 2>/dev/null)" = ISO-8859-1; then
+ # Up to coreutils-6.9.91, this would fail with the diagnostic:
+ # tr: misaligned [:upper:] and/or [:lower:] construct
+ # with LC_CTYPE=en_US.ISO-8859-1.
+ tr '[:upper:]' '[:lower:]' < /dev/null || fail=1
+
+ tr '[:upper:] ' '[:lower:]' < /dev/null 2>out && fail=1
+ echo 'tr: when translating with string1 longer than string2,
+the latter string must not end with a character class' > exp
+ compare exp out || fail=1
+
+ # Ensure when there are a different number of elements
+ # in each string, we validate the case mapping correctly
+ echo 'abc.xyz' |
+ tr 'ab[:lower:]' '0-1[:upper:]' > out || fail=1
+ echo 'ABC.XYZ' > exp
+ compare exp out || fail=1
+
+ # Ensure we extend string2 appropriately
+ echo 'ABC- XYZ' |
+ tr '[:upper:]- ' '[:lower:]_' > out || fail=1
+ echo 'abc__xyz' > exp
+ compare exp out || fail=1
+
+ # Ensure the size of the case classes are accounted
+ # for as a unit.
+ echo 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' |
+ tr '[:upper:]A-B' '[:lower:]0' >out || fail=1
+ echo '00cdefghijklmnopqrstuvwxyz' > exp
+ compare exp out || fail=1
+
+ # Ensure the size of the case classes are accounted
+ # for as a unit.
+ echo 'a' |
+ tr -t '[:lower:]a' '[:upper:]0' >out || fail=1
+ echo '0' > exp
+ compare exp out || fail=1
+
+ # Ensure the size of the case classes are accounted
+ # for as a unit.
+ echo 'a' |
+ tr -t '[:lower:][:lower:]a' '[:lower:][:upper:]0' >out || fail=1
+ echo '0' > exp
+ compare exp out || fail=1
+fi
+
+# coreutils 8.6 - 8.32 inclusive, would abort trying to validate the following
+returns_ 1 tr -c '[:upper:]\000-\370' '[:lower:]' < /dev/null || fail=1
+
+Exit $fail
diff --git a/tests/tr/tr.pl b/tests/tr/tr.pl
new file mode 100755
index 0000000..997b8a6
--- /dev/null
+++ b/tests/tr/tr.pl
@@ -0,0 +1,174 @@
+#!/usr/bin/perl
+
+# Copyright (C) 2008-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+use strict;
+
+my $prog = 'tr';
+
+# Turn off localization of executable's output.
+@ENV{qw(LANGUAGE LANG LC_ALL)} = ('C') x 3;
+
+my $map_all_to_1 =
+ "$prog: when translating with complemented character classes,\n"
+ . "string2 must map all characters in the domain to one\n";
+
+my @Tests =
+(
+ ['1', qw(abcd '[]*]'), {IN=>'abcd'}, {OUT=>']]]]'}],
+ ['2', qw(abc '[%*]xyz'), {IN=>'abc'}, {OUT=>'xyz'}],
+ ['3', qw('' '[.*]'), {IN=>'abc'}, {OUT=>'abc'}],
+
+ # Test --truncate-set1 behavior when string1 is longer than string2
+ ['4', qw(-t abcd xy), {IN=>'abcde'}, {OUT=>'xycde'}],
+ # Test bsd behavior (the default) when string1 is longer than string2
+ ['5', qw(abcd xy), {IN=>'abcde'}, {OUT=>'xyyye'}],
+ # Do it the posix way
+ ['6', qw(abcd 'x[y*]'), {IN=>'abcde'}, {OUT=>'xyyye'}],
+ ['7', qw(-s a-p '%[.*]$'), {IN=>'abcdefghijklmnop'}, {OUT=>'%.$'}],
+ ['8', qw(-s a-p '[.*]$'), {IN=>'abcdefghijklmnop'}, {OUT=>'.$'}],
+ ['9', qw(-s a-p '%[.*]'), {IN=>'abcdefghijklmnop'}, {OUT=>'%.'}],
+ ['a', qw(-s '[a-z]'), {IN=>'aabbcc'}, {OUT=>'abc'}],
+ ['b', qw(-s '[a-c]'), {IN=>'aabbcc'}, {OUT=>'abc'}],
+ ['c', qw(-s '[a-b]'), {IN=>'aabbcc'}, {OUT=>'abcc'}],
+ ['d', qw(-s '[b-c]'), {IN=>'aabbcc'}, {OUT=>'aabc'}],
+ ['e', qw(-s '[\0-\5]'),
+ {IN=>"\0\0a\1\1b\2\2\2c\3\3\3d\4\4\4\4e\5\5"}, {OUT=>"\0a\1b\2c\3d\4e\5"}],
+ # tests of delete
+ ['f', qw(-d '[=[=]'), {IN=>'[[[[[[[]]]]]]]]'}, {OUT=>']]]]]]]]'}],
+ ['g', qw(-d '[=]=]'), {IN=>'[[[[[[[]]]]]]]]'}, {OUT=>'[[[[[[['}],
+ ['h', qw(-d '[:xdigit:]'), {IN=>'0123456789acbdefABCDEF'}, {OUT=>''}],
+ ['i', qw(-d '[:xdigit:]'), {IN=>'w0x1y2z3456789acbdefABCDEFz'},
+ {OUT=>'wxyzz'}],
+ ['j', qw(-d '[:digit:]'), {IN=>'0123456789'}, {OUT=>''}],
+ ['k', qw(-d '[:digit:]'),
+ {IN=>'a0b1c2d3e4f5g6h7i8j9k'}, {OUT=>'abcdefghijk'}],
+ ['l', qw(-d '[:lower:]'), {IN=>'abcdefghijklmnopqrstuvwxyz'}, {OUT=>''}],
+ ['m', qw(-d '[:upper:]'), {IN=>'ABCDEFGHIJKLMNOPQRSTUVWXYZ'}, {OUT=>''}],
+ ['n', qw(-d '[:lower:][:upper:]'),
+ {IN=>'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'}, {OUT=>''}],
+ ['o', qw(-d '[:alpha:]'),
+ {IN=>'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'}, {OUT=>''}],
+ ['p', qw(-d '[:alnum:]'),
+ {IN=>'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789'},
+ {OUT=>''}],
+ ['q', qw(-d '[:alnum:]'),
+ {IN=>'.abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789.'},
+ {OUT=>'..'}],
+ ['r', qw(-ds '[:alnum:]' .),
+ {IN=>'.abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789.'},
+ {OUT=>'.'}],
+
+ # The classic example, with string2 BSD-style
+ ['s', qw(-cs '[:alnum:]' '\n'),
+ {IN=>'The big black fox jumped over the fence.'},
+ {OUT=>"The\nbig\nblack\nfox\njumped\nover\nthe\nfence\n"}],
+
+ # The classic example, POSIX-style
+ ['t', qw(-cs '[:alnum:]' '[\n*]'),
+ {IN=>'The big black fox jumped over the fence.'},
+ {OUT=>"The\nbig\nblack\nfox\njumped\nover\nthe\nfence\n"}],
+ ['u', qw(-ds b a), {IN=>'aabbaa'}, {OUT=>'a'}],
+ ['v', qw(-ds '[:xdigit:]' Z), {IN=>'ZZ0123456789acbdefABCDEFZZ'}, {OUT=>'Z'}],
+
+ # Try some data with 8th bit set in case something is mistakenly
+ # sign-extended.
+ ['w', qw(-ds '\350' '\345'),
+ {IN=>"\300\301\377\345\345\350\345"},
+ {OUT=>"\300\301\377\345"}],
+ ['x', qw(-s abcdefghijklmn '[:*016]'),
+ {IN=>'abcdefghijklmnop'}, {OUT=>':op'}],
+ ['y', qw(-d a-z), {IN=>'abc $code'}, {OUT=>' $'}],
+ ['z', qw(-ds a-z '$.'), {IN=>'a.b.c $$$$code\\'}, {OUT=>'. $\\'}],
+
+ # Make sure that a-a is accepted.
+ ['range-a-a', qw(a-a z), {IN=>'abc'}, {OUT=>'zbc'}],
+ #
+ ['null', qw(a ''), {IN=>''}, {OUT=>''}, {EXIT=>1},
+ {ERR=>"$prog: when not truncating set1, string2 must be non-empty\n"}],
+ ['upcase', qw('[:lower:]' '[:upper:]'),
+ {IN=>'abcxyzABCXYZ'},
+ {OUT=>'ABCXYZABCXYZ'}],
+ ['dncase', qw('[:upper:]' '[:lower:]'),
+ {IN=>'abcxyzABCXYZ'},
+ {OUT=>'abcxyzabcxyz'}],
+ #
+ ['rep-cclass', qw('a[=*2][=c=]' xyyz), {IN=>'a=c'}, {OUT=>'xyz'}],
+ ['rep-1', qw('[:*3][:digit:]' a-m), {IN=>':1239'}, {OUT=>'cefgm'}],
+ ['rep-2', qw('a[b*512]c' '1[x*]2'), {IN=>'abc'}, {OUT=>'1x2'}],
+ ['rep-3', qw('a[b*513]c' '1[x*]2'), {IN=>'abc'}, {OUT=>'1x2'}],
+ # Another couple octal repeat count tests.
+ ['o-rep-1', qw('[b*08]' '[x*]'), {IN=>''}, {OUT=>''}, {EXIT=>1},
+ {ERR=>"$prog: invalid repeat count '08' in [c*n] construct\n"}],
+ ['o-rep-2', qw('[b*010]cd' '[a*7]BC[x*]'), {IN=>'bcd'}, {OUT=>'BCx'}],
+
+ ['esc', qw('a\-z' A-Z), {IN=>'abc-z'}, {OUT=>'AbcBC'}],
+ ['bs-055', qw('a\055b' def), {IN=>"a\055b"}, {OUT=>'def'}],
+ ['bs-at-end', qw('\\' x), {IN=>"\\"}, {OUT=>'x'},
+ {ERR=>"$prog: warning: an unescaped backslash at end of "
+ . "string is not portable\n"}],
+
+ #
+ # From Ross
+ ['ross-0a', qw(-cs '[:upper:]' 'X[Y*]'), {IN=>''}, {OUT=>''}, {EXIT=>1},
+ {ERR=>$map_all_to_1}],
+ ['ross-0b', qw(-cs '[:cntrl:]' 'X[Y*]'), {IN=>''}, {OUT=>''}, {EXIT=>1},
+ {ERR=>$map_all_to_1}],
+ ['ross-1a', qw(-cs '[:upper:]' '[X*]'),
+ {IN=>'AMZamz123.-+AMZ'}, {OUT=>'AMZXAMZ'}],
+ ['ross-1b', qw(-cs '[:upper:][:digit:]' '[Z*]'), {IN=>''}, {OUT=>''}],
+ ['ross-2', qw(-dcs '[:lower:]' n-rs-z),
+ {IN=>'amzAMZ123.-+amz'}, {OUT=>'amzamz'}],
+ ['ross-3', qw(-ds '[:xdigit:]' '[:alnum:]'),
+ {IN=>'.ZABCDEFGzabcdefg.0123456788899.GG'}, {OUT=>'.ZGzg..G'}],
+ ['ross-4', qw(-dcs '[:alnum:]' '[:digit:]'), {IN=>''}, {OUT=>''}],
+ ['ross-5', qw(-dc '[:lower:]'), {IN=>''}, {OUT=>''}],
+ ['ross-6', qw(-dc '[:upper:]'), {IN=>''}, {OUT=>''}],
+
+ # Ensure that these fail.
+ # Prior to 2.0.20, each would evoke a failed assertion.
+ ['empty-eq', qw('[==]' x), {IN=>''}, {OUT=>''}, {EXIT=>1},
+ {ERR=>"$prog: missing equivalence class character '[==]'\n"}],
+ ['empty-cc', qw('[::]' x), {IN=>''}, {OUT=>''}, {EXIT=>1},
+ {ERR=>"$prog: missing character class name '[::]'\n"}],
+
+ # Weird repeat counts.
+ ['repeat-bs-9', qw(abc '[b*\9]'), {IN=>'abcd'}, {OUT=>'[b*d'}],
+ ['repeat-0', qw(abc '[b*0]'), {IN=>'abcd'}, {OUT=>'bbbd'}],
+ ['repeat-zeros', qw(abc '[b*00000000000000000000]'),
+ {IN=>'abcd'}, {OUT=>'bbbd'}],
+ ['repeat-compl', qw(-c '[a*65536]\n' '[b*]'), {IN=>'abcd'}, {OUT=>'abbb'}],
+ ['repeat-xC', qw(-C '[a*65536]\n' '[b*]'), {IN=>'abcd'}, {OUT=>'abbb'}],
+
+ # From Glenn Fowler.
+ ['fowler-1', qw(ah -H), {IN=>'aha'}, {OUT=>'-H-'}],
+
+ # Up to coreutils-6.9, this would provoke a failed assertion.
+ ['no-abort-1', qw(-c a '[b*256]'), {IN=>'abc'}, {OUT=>'abb'}],
+);
+
+@Tests = triple_test \@Tests;
+
+# tr takes its input only from stdin, not from a file argument, so
+# remove the tests that provide file arguments and keep only the ones
+# generated by triple_test (identifiable by their .r and .p suffixes).
+@Tests = grep {$_->[0] =~ /\.[pr]$/} @Tests;
+
+my $save_temps = $ENV{DEBUG};
+my $verbose = $ENV{VERBOSE};
+
+my $fail = run_tests ($prog, $prog, \@Tests, $save_temps, $verbose);
+exit $fail;
diff --git a/tests/truncate/truncate-dangling-symlink.sh b/tests/truncate/truncate-dangling-symlink.sh
new file mode 100755
index 0000000..d2e3b79
--- /dev/null
+++ b/tests/truncate/truncate-dangling-symlink.sh
@@ -0,0 +1,28 @@
+#!/bin/sh
+# Make sure truncate can create a file through a dangling symlink.
+
+# Copyright (C) 2008-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ truncate
+
+ln -s truncate-target t-symlink
+
+truncate -s0 t-symlink || fail=1
+
+test -f truncate-target || fail=1
+
+Exit $fail
diff --git a/tests/truncate/truncate-dir-fail.sh b/tests/truncate/truncate-dir-fail.sh
new file mode 100755
index 0000000..cee7801
--- /dev/null
+++ b/tests/truncate/truncate-dir-fail.sh
@@ -0,0 +1,25 @@
+#!/bin/sh
+# Make sure truncate fails for a directory.
+
+# Copyright (C) 2008-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ truncate
+
+# truncate on dir not allowed
+returns_ 1 truncate -s+0 . || fail=1
+
+Exit $fail
diff --git a/tests/truncate/truncate-fail-diag.sh b/tests/truncate/truncate-fail-diag.sh
new file mode 100755
index 0000000..2257548
--- /dev/null
+++ b/tests/truncate/truncate-fail-diag.sh
@@ -0,0 +1,43 @@
+#!/bin/sh
+# make sure truncate gives reasonable diagnostics
+# Note open() checks for trailing '/' before checking for existence
+# open (".", O_CREAT & (O_WRONLY | O_RDWR), ...) -> EISDIR
+# open ("missing/", O_CREAT & (O_WRONLY | O_RDWR), ...) -> EISDIR
+# open ("missing/file", O_CREAT & (O_WRONLY | O_RDWR), ...) -> ENOENT
+
+# Copyright (C) 2008-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ truncate
+skip_if_root_
+
+
+d1=no
+
+dir=$d1/such-dir
+truncate -s0 $dir > out 2>&1 && fail=1
+cat <<EOF > exp
+truncate: cannot open '$dir' for writing: No such file or directory
+EOF
+compare exp out || fail=1
+
+dir=$d1/
+truncate -s0 $dir > out 2>&1 && fail=1
+#The following can be returned at least
+#truncate: cannot open '$dir' for writing: Not a directory
+#truncate: cannot open '$dir' for writing: Is a directory
+
+Exit $fail
diff --git a/tests/truncate/truncate-fifo.sh b/tests/truncate/truncate-fifo.sh
new file mode 100755
index 0000000..c89555c
--- /dev/null
+++ b/tests/truncate/truncate-fifo.sh
@@ -0,0 +1,27 @@
+#!/bin/sh
+# Make sure truncate works on fifos without hanging
+
+# Copyright (C) 2008-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ truncate
+
+mkfifo_or_skip_ fifo
+
+timeout 10 truncate -s0 fifo
+test "$?" = 124 && fail=1
+
+Exit $fail
diff --git a/tests/truncate/truncate-no-create-missing.sh b/tests/truncate/truncate-no-create-missing.sh
new file mode 100755
index 0000000..bf6e657
--- /dev/null
+++ b/tests/truncate/truncate-no-create-missing.sh
@@ -0,0 +1,26 @@
+#!/bin/sh
+# Ensure that truncate -c no-such-file doesn't fail.
+
+# Copyright (C) 2008-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ truncate
+
+
+# truncate -c no-such-file should not fail.
+truncate -s0 -c no-such-file || fail=1
+
+Exit $fail
diff --git a/tests/truncate/truncate-overflow.sh b/tests/truncate/truncate-overflow.sh
new file mode 100755
index 0000000..22bda70
--- /dev/null
+++ b/tests/truncate/truncate-overflow.sh
@@ -0,0 +1,39 @@
+#!/bin/sh
+# Validate truncate integer overflow
+
+# Copyright (C) 2008-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ truncate
+getlimits_
+
+
+# -= overflow
+truncate -s-1 create-zero-len-file || fail=1
+
+echo > non-empty-file
+
+# signed overflow
+returns_ 1 truncate -s$OFF_T_OFLOW file || fail=1
+
+# += signed overflow
+returns_ 1 truncate -s+$OFF_T_MAX non-empty-file || fail=1
+
+# *= signed overflow
+IO_BLOCK_OFLOW=$(expr $OFF_T_MAX / $(stat -f -c%s .) + 1)
+returns_ 1 truncate --io-blocks --size=$IO_BLOCK_OFLOW file || fail=1
+
+Exit $fail
diff --git a/tests/truncate/truncate-owned-by-other.sh b/tests/truncate/truncate-owned-by-other.sh
new file mode 100755
index 0000000..f213e8f
--- /dev/null
+++ b/tests/truncate/truncate-owned-by-other.sh
@@ -0,0 +1,35 @@
+#!/bin/sh
+# Demonstrate that "truncate -s0 writable-but-owned-by-other" works.
+
+# Copyright (C) 2008-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ truncate
+
+require_root_
+
+# Create a file owned by root, and writable by $NON_ROOT_USERNAME.
+echo > root-owned || framework_failure_
+chgrp +$NON_ROOT_GID . root-owned || framework_failure_
+chmod g+w root-owned
+
+# Ensure that the current directory is searchable by $NON_ROOT_USERNAME.
+chmod g+x .
+
+chroot --skip-chdir --user=$NON_ROOT_USERNAME / env PATH="$PATH" \
+ truncate -s0 root-owned || fail=1
+
+Exit $fail
diff --git a/tests/truncate/truncate-parameters.sh b/tests/truncate/truncate-parameters.sh
new file mode 100755
index 0000000..a7f5685
--- /dev/null
+++ b/tests/truncate/truncate-parameters.sh
@@ -0,0 +1,54 @@
+#!/bin/sh
+# Validate truncate parameter combinations
+
+# Copyright (C) 2008-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ truncate
+
+
+# must specify at least 1 file
+returns_ 1 truncate --size=0 || fail=1
+
+# must specify size. don't default to 0
+returns_ 1 truncate file || fail=1
+
+# mixture of absolute size & reference not allowed
+returns_ 1 truncate --size=0 --reference=file file || fail=1
+
+# blocks without size is not valid
+returns_ 1 truncate --io-blocks --reference=file file || fail=1
+
+# must specify valid numbers
+returns_ 1 truncate --size="invalid" file || fail=1
+
+# spaces not significant around size
+returns_ 1 truncate --size="> -1" file || fail=1
+truncate --size=" >1" file || fail=1 #file now 1
+truncate --size=" +1" file || fail=1 #file now 2
+test $(stat --format %s file) = 2 || fail=1
+
+# reference allowed with relative size
+truncate --size=" +1" -r file file || fail=1 #file now 3
+test $(stat --format %s file) = 3 || fail=1
+
+# reference allowed alone also
+truncate -r file file || fail=1 #file still 3
+test $(stat --format %s file) = 3 || fail=1
+truncate -r file file2 || fail=1 #file2 now 3
+test $(stat --format %s file2) = 3 || fail=1
+
+Exit $fail
diff --git a/tests/truncate/truncate-relative.sh b/tests/truncate/truncate-relative.sh
new file mode 100755
index 0000000..57be8b4
--- /dev/null
+++ b/tests/truncate/truncate-relative.sh
@@ -0,0 +1,35 @@
+#!/bin/sh
+# Validate truncate relative sizes
+
+# Copyright (C) 2008-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ truncate
+
+
+# mixture of relative modifiers not allowed
+returns_ 1 truncate --size="+>0" file || fail=1
+
+# mixture of relative modifiers not allowed
+returns_ 1 truncate --size=">+0" file || fail=1
+
+# division by zero
+returns_ 1 truncate --size="/0" file || fail=1
+
+# division by zero
+returns_ 1 truncate --size="%0" file || fail=1
+
+Exit $fail
diff --git a/tests/tty/tty-eof.pl b/tests/tty/tty-eof.pl
new file mode 100755
index 0000000..ad63918
--- /dev/null
+++ b/tests/tty/tty-eof.pl
@@ -0,0 +1,118 @@
+#!/usr/bin/perl
+# Test whether programs exit upon a single EOF from a tty.
+# Ensure that e.g., cat exits upon a single EOF (^D) from a tty.
+# Do the same for all programs that can read stdin,
+# require no arguments and that write to standard output.
+
+# Copyright (C) 2003-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+use strict;
+(my $ME = $0) =~ s|.*/||;
+
+# Some older versions of Expect.pm (e.g. 1.07) lack the log_user method,
+# so check for that, too.
+eval { require Expect; Expect->require_version('1.11') };
+$@
+ and CuSkip::skip "$ME: this script requires Perl's Expect package >=1.11\n";
+
+{
+ my $fail = 0;
+ my @stdin_reading_commands = qw(
+ b2sum
+ base32
+ base64
+ cat
+ cksum
+ dd
+ expand
+ fmt
+ fold
+ head
+ md5sum
+ nl
+ od
+ paste
+ pr
+ ptx
+ sha1sum
+ sha224sum
+ sha256sum
+ sha384sum
+ sha512sum
+ shuf
+ sort
+ sum
+ tac
+ tail
+ tee
+ tsort
+ unexpand
+ uniq
+ wc
+ );
+ my $stderr = 'tty-eof.err';
+ foreach my $cmd ((@stdin_reading_commands), 'basenc --z85', 'cut -f2',
+ 'numfmt --invalid=ignore')
+ {
+ my $exp = new Expect;
+ $exp->log_user(0);
+ my $cmd_name = (split(' ', $cmd))[0];
+ $ENV{built_programs} =~ /\b$cmd_name\b/ || next;
+ $exp->spawn("$cmd 2> $stderr")
+ or (warn "$ME: cannot run '$cmd': $!\n"), $fail=1, next;
+ # Test cut in a different mode, even though it supports the standard flow
+ # Ensure that it exits with no input as it used to not do so
+ $cmd =~ /^cut/
+ or $exp->send("a b\n");
+ $exp->send("\cD"); # This is Control-D. FIXME: what if that's not EOF?
+ $cmd =~ /^cut/
+ or $exp->expect (0, '-re', "^a b\\r?\$");
+ $cmd =~ /^cut/
+ or my $found = $exp->expect (1, '-re', "^.+\$");
+ $found and warn "F: $found: " . $exp->exp_match () . "\n";
+ $exp->expect(10, 'eof');
+ # Expect no output from cut, since we gave it no input.
+ defined $found || $cmd =~ /^cut/
+ or (warn "$ME: $cmd didn't produce expected output\n"),
+ $fail=1, next;
+ defined $exp->exitstatus
+ or (warn "$ME: $cmd didn't exit after ^D from standard input\n"),
+ $fail=1, next;
+ my $s = $exp->exitstatus;
+ $s == 0
+ or (warn "$ME: $cmd exited with status $s (expected 0)\n"),
+ $fail=1;
+ $exp->hard_close();
+
+ # dd normally writes to stderr. If it exits successfully, we're done.
+ $cmd eq 'dd' && $s == 0
+ and next;
+
+ if (-s $stderr)
+ {
+ warn "$ME: $cmd wrote to stderr:\n";
+ system "cat $stderr";
+ $fail = 1;
+ }
+ }
+ continue
+ {
+ unlink $stderr
+ or warn "$ME: failed to remove stderr file from $cmd, $stderr: $!\n";
+ }
+
+ exit $fail
+}
diff --git a/tests/tty/tty.sh b/tests/tty/tty.sh
new file mode 100755
index 0000000..0b0ff66
--- /dev/null
+++ b/tests/tty/tty.sh
@@ -0,0 +1,43 @@
+#!/bin/sh
+# Test 'tty'.
+
+# Copyright 2017-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+# Make sure there's a tty on stdin.
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ tty
+
+if test -t 0; then
+ tty || fail=1
+ tty -s || fail=1
+fi
+
+returns_ 1 tty </dev/null || fail=1
+returns_ 1 tty -s </dev/null || fail=1
+returns_ 1 tty <&- 2>/dev/null || fail=1
+returns_ 1 tty -s <&- || fail=1
+
+returns_ 2 tty a || fail=1
+returns_ 2 tty -s a || fail=1
+
+if test -w /dev/full && test -c /dev/full; then
+ if test -t 0; then
+ returns_ 3 tty >/dev/full || fail=1
+ fi
+ returns_ 3 tty </dev/null >/dev/full || fail=1
+fi
+
+Exit $fail
diff --git a/tests/uniq/uniq-collate.sh b/tests/uniq/uniq-collate.sh
new file mode 100755
index 0000000..76b1aaa
--- /dev/null
+++ b/tests/uniq/uniq-collate.sh
@@ -0,0 +1,63 @@
+#!/bin/sh
+# before coreutils-8.32, uniq would not distinguish
+# items which compared equal with strcoll()
+# So ensure we avoid strcoll() for the following cases.
+
+# Copyright (C) 2020-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ uniq printf
+
+gen_input()
+{
+ env LC_ALL=$LOCALE_FR_UTF8 printf "$@" > in || framework_failure_
+}
+
+# strcoll() used to return 0 comparing the following strings
+# which was fixed somewhere between glibc-2.22 and glibc-2.30
+gen_input '%s\n' 'ⁿᵘˡˡ' 'ܥܝܪܐܩ'
+test $(LC_ALL=$LOCALE_FR_UTF8 uniq < in | wc -l) = 2 || fail=1
+
+# normalization in strcoll is inconsistent across platforms.
+# glibc based systems at least do _not_ normalize in strcoll,
+# while cygwin systems for example may do so.
+# á composed and decomposed, are generally not compared equal
+gen_input '\u00E1\na\u0301\n'
+test $(LC_ALL=$LOCALE_FR_UTF8 uniq < in | wc -l) = 2 || fail=1
+# Similarly with the following equivalent hangul characters
+gen_input '\uAC01\n\u1100\u1161\u11A8\n'
+test $(LC_ALL=ko_KR.utf8 uniq < in | wc -l) = 2 || fail=1
+
+# Note if running in the wrong locale,
+# strcoll may indicate the strings match when they don't.
+# I.e., cjk and hangul will now work even if
+# uniq is running in the wrong locale
+# hangul (ko_KR.utf8)
+gen_input '\uAC00\n\uAC01\n'
+test $(LC_ALL=en_US.utf8 uniq < in | wc -l) = 2 || fail=1
+# CJK (zh_CN.utf8)
+gen_input '\u3400\n\u3401\n'
+test $(LC_ALL=en_US.utf8 uniq < in | wc -l) = 2 || fail=1
+
+# Note strcoll() ignores certain characters,
+# but not if the strings are otherwise equal.
+# I.e., the following on glibc-2.30 at least,
+# as expected, does not print a single item,
+# but testing here for illustration
+gen_input ',a\n.a\n'
+test $(LC_ALL=$LOCALE_FR_UTF8 uniq < in | wc -l) = 2 || fail=1
+
+Exit $fail
diff --git a/tests/uniq/uniq-perf.sh b/tests/uniq/uniq-perf.sh
new file mode 100755
index 0000000..b4af673
--- /dev/null
+++ b/tests/uniq/uniq-perf.sh
@@ -0,0 +1,25 @@
+#!/bin/sh
+# before coreutils-8.10, seq 100000|uniq -f 10000000000 would run for days
+
+# Copyright (C) 2011-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ uniq
+
+seq 100 > in || fail=1
+timeout 10 uniq -f 10000000000 in || fail=1
+
+Exit $fail
diff --git a/tests/uniq/uniq.pl b/tests/uniq/uniq.pl
new file mode 100755
index 0000000..a6354dc
--- /dev/null
+++ b/tests/uniq/uniq.pl
@@ -0,0 +1,272 @@
+#!/usr/bin/perl
+# Test uniq.
+
+# Copyright (C) 2008-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+use strict;
+
+my $limits = getlimits ();
+
+my $prog = 'uniq';
+my $try = "Try '$prog --help' for more information.\n";
+
+# Turn off localization of executable's output.
+@ENV{qw(LANGUAGE LANG LC_ALL)} = ('C') x 3;
+
+# When possible, create a "-z"-testing variant of each test.
+sub add_z_variants($)
+{
+ my ($tests) = @_;
+ my @new;
+ TEST:
+ foreach my $t (@$tests)
+ {
+ push @new, $t;
+
+ # skip the obsolete-syntax tests
+ $t->[0] =~ /^obs-plus/
+ and next;
+
+ my @args;
+ my @list_of_hash;
+
+ foreach my $e (@$t)
+ {
+ !ref $e
+ and push (@args, $e), next;
+
+ ref $e && ref $e eq 'HASH'
+ or (warn "$0: $t->[0]: unexpected entry type\n"), next;
+ my $tmp = $e;
+ foreach my $k (qw(IN OUT))
+ {
+ my $val = $e->{$k};
+ # skip any test whose input or output already contains a NUL byte
+ if (defined $val)
+ {
+ $val =~ /\0/
+ and next TEST;
+
+ # Convert each NL in input or output to \0.
+ $val =~ s/\n/\0/g;
+ $tmp = {$k => $val};
+ last;
+ }
+ }
+ push @list_of_hash, $tmp;
+ }
+
+ shift @args; # discard test name
+
+ # skip any test that uses the -z option
+ grep /z/, @args
+ and next;
+
+ push @new, ["$t->[0]-z", '-z', @args, @list_of_hash];
+ }
+ return @new;
+}
+
+my @Tests =
+(
+ ['1', '', {IN=>''}, {OUT=>''}],
+ ['2', '', {IN=>"a\na\n"}, {OUT=>"a\n"}],
+ ['3', '', {IN=>"a\na"}, {OUT=>"a\n"}],
+ ['4', '', {IN=>"a\nb"}, {OUT=>"a\nb\n"}],
+ ['5', '', {IN=>"a\na\nb"}, {OUT=>"a\nb\n"}],
+ ['6', '', {IN=>"b\na\na\n"}, {OUT=>"b\na\n"}],
+ ['7', '', {IN=>"a\nb\nc\n"}, {OUT=>"a\nb\nc\n"}],
+
+ # Ensure that newlines are not interpreted with -z.
+ ['2z', '-z', {IN=>"a\na\n"}, {OUT=>"a\na\n\0"}],
+ ['3z', '-z', {IN=>"a\na"}, {OUT=>"a\na\0"}],
+ ['4z', '-z', {IN=>"a\nb"}, {OUT=>"a\nb\0"}],
+ ['5z', '-z', {IN=>"a\na\nb"}, {OUT=>"a\na\nb\0"}],
+ ['10z', '-z -f1', {IN=>"a\nb\n\0c\nb\n\0"}, {OUT=>"a\nb\n\0"}],
+ ['20z', '-dz', {IN=>"a\na\n"}, {OUT=>""}],
+
+ # Make sure that eight bit characters work
+ ['8', '', {IN=>"ö\nv\n"}, {OUT=>"ö\nv\n"}],
+ # Test output of -u option; only unique lines
+ ['9', '-u', {IN=>"a\na\n"}, {OUT=>""}],
+ ['10', '-u', {IN=>"a\nb\n"}, {OUT=>"a\nb\n"}],
+ ['11', '-u', {IN=>"a\nb\na\n"}, {OUT=>"a\nb\na\n"}],
+ ['12', '-u', {IN=>"a\na\n"}, {OUT=>""}],
+ ['13', '-u', {IN=>"a\na\n"}, {OUT=>""}],
+ #['5', '-u', "a\na\n", "", 0],
+ # Test output of -d option; only repeated lines
+ ['20', '-d', {IN=>"a\na\n"}, {OUT=>"a\n"}],
+ ['21', '-d', {IN=>"a\nb\n"}, {OUT=>""}],
+ ['22', '-d', {IN=>"a\nb\na\n"}, {OUT=>""}],
+ ['23', '-d', {IN=>"a\na\nb\n"}, {OUT=>"a\n"}],
+ # Check the key options
+ # If we skip over fields or characters, is the output deterministic?
+ ['obs30', '-1', {IN=>"a a\nb a\n"}, {OUT=>"a a\n"}],
+ ['31', qw(-f 1), {IN=>"a a\nb a\n"}, {OUT=>"a a\n"}],
+ ['32', qw(-f 1), {IN=>"a a\nb b\n"}, {OUT=>"a a\nb b\n"}],
+ ['33', qw(-f 1), {IN=>"a a a\nb a c\n"}, {OUT=>"a a a\nb a c\n"}],
+ ['34', qw(-f 1), {IN=>"b a\na a\n"}, {OUT=>"b a\n"}],
+ ['35', qw(-f 2), {IN=>"a a c\nb a c\n"}, {OUT=>"a a c\n"}],
+ # Skip over characters.
+ ['obs-plus40', '+1', {IN=>"aaa\naaa\n"}, {OUT=>"aaa\n"}],
+ ['obs-plus41', '+1', {IN=>"baa\naaa\n"}, {OUT=>"baa\n"}],
+ ['42', qw(-s 1), {IN=>"aaa\naaa\n"}, {OUT=>"aaa\n"}],
+ ['43', qw(-s 2), {IN=>"baa\naaa\n"}, {OUT=>"baa\n"}],
+ ['obs-plus44', qw(+1 --), {IN=>"aaa\naaa\n"}, {OUT=>"aaa\n"}],
+ ['obs-plus45', qw(+1 --), {IN=>"baa\naaa\n"}, {OUT=>"baa\n"}],
+ # Skip over fields and characters
+ ['50', qw(-f 1 -s 1), {IN=>"a aaa\nb ab\n"}, {OUT=>"a aaa\nb ab\n"}],
+ ['51', qw(-f 1 -s 1), {IN=>"a aaa\nb aaa\n"}, {OUT=>"a aaa\n"}],
+ ['52', qw(-s 1 -f 1), {IN=>"a aaa\nb ab\n"}, {OUT=>"a aaa\nb ab\n"}],
+ ['53', qw(-s 1 -f 1), {IN=>"a aaa\nb aaa\n"}, {OUT=>"a aaa\n"}],
+ # Fixed in 2.0.15
+ ['54', qw(-s 4), {IN=>"abc\nabcd\n"}, {OUT=>"abc\n"}],
+ # Supported in 2.0.15
+ ['55', qw(-s 0), {IN=>"abc\nabcd\n"}, {OUT=>"abc\nabcd\n"}],
+ ['56', qw(-s 0), {IN=>"abc\n"}, {OUT=>"abc\n"}],
+ ['57', qw(-w 0), {IN=>"abc\nabcd\n"}, {OUT=>"abc\n"}],
+ # Only account for a number of characters
+ ['60', qw(-w 1), {IN=>"a a\nb a\n"}, {OUT=>"a a\nb a\n"}],
+ ['61', qw(-w 3), {IN=>"a a\nb a\n"}, {OUT=>"a a\nb a\n"}],
+ ['62', qw(-w 1 -f 1), {IN=>"a a a\nb a c\n"}, {OUT=>"a a a\n"}],
+ ['63', qw(-f 1 -w 1), {IN=>"a a a\nb a c\n"}, {OUT=>"a a a\n"}],
+ # The blank after field one is checked too
+ ['64', qw(-f 1 -w 4), {IN=>"a a a\nb a c\n"}, {OUT=>"a a a\nb a c\n"}],
+ ['65', qw(-f 1 -w 3), {IN=>"a a a\nb a c\n"}, {OUT=>"a a a\n"}],
+ # Make sure we don't break if the file contains \0
+ ['90', '', {IN=>"a\0a\na\n"}, {OUT=>"a\0a\na\n"}],
+ # Check fields separated by tabs and by spaces
+ ['91', '', {IN=>"a\ta\na a\n"}, {OUT=>"a\ta\na a\n"}],
+ ['92', qw(-f 1), {IN=>"a\ta\na a\n"}, {OUT=>"a\ta\na a\n"}],
+ ['93', qw(-f 2), {IN=>"a\ta a\na a a\n"}, {OUT=>"a\ta a\n"}],
+ ['94', qw(-f 1), {IN=>"a\ta\na\ta\n"}, {OUT=>"a\ta\n"}],
+ # Check the count option; add tests for other options too
+ ['101', '-c', {IN=>"a\nb\n"}, {OUT=>" 1 a\n 1 b\n"}],
+ ['102', '-c', {IN=>"a\na\n"}, {OUT=>" 2 a\n"}],
+ # Check the local -D (--all-repeated) option
+ ['110', '-D', {IN=>"a\na\n"}, {OUT=>"a\na\n"}],
+ ['111', qw(-D -w1), {IN=>"a a\na b\n"}, {OUT=>"a a\na b\n"}],
+ ['112', qw(-D -c), {IN=>"a a\na b\n"}, {OUT=>""}, {EXIT=>1}, {ERR=>
+ "$prog: printing all duplicated lines and repeat counts is meaningless\n$try"}
+ ],
+ ['113', '--all-repeated=separate', {IN=>"a\na\n"}, {OUT=>"a\na\n"}],
+ ['114', '--all-repeated=separate',
+ {IN=>"a\na\nb\nc\nc\n"}, {OUT=>"a\na\n\nc\nc\n"}],
+ ['115', '--all-repeated=separate',
+ {IN=>"a\na\nb\nb\nc\n"}, {OUT=>"a\na\n\nb\nb\n"}],
+ ['116', '--all-repeated=prepend', {IN=>"a\na\n"}, {OUT=>"\na\na\n"}],
+ ['117', '--all-repeated=prepend',
+ {IN=>"a\na\nb\nc\nc\n"}, {OUT=>"\na\na\n\nc\nc\n"}],
+ ['118', '--all-repeated=prepend', {IN=>"a\nb\n"}, {OUT=>""}],
+ ['119', '--all-repeated=badoption', {IN=>"a\n"}, {OUT=>""}, {EXIT=>1},
+ {ERR=>"$prog: invalid argument 'badoption' for '--all-repeated'\n"
+ . "Valid arguments are:\n"
+ . " - 'none'\n"
+ . " - 'prepend'\n"
+ . " - 'separate'\n"
+ . $try}],
+ # Check that -d and -u suppress all output, as POSIX requires.
+ ['120', qw(-d -u), {IN=>"a\na\n\b"}, {OUT=>""}],
+ ['121', "-d -u -w$limits->{UINTMAX_OFLOW}", {IN=>"a\na\n\b"}, {OUT=>""}],
+ ['122', "-d -u -w$limits->{SIZE_OFLOW}", {IN=>"a\na\n\b"}, {OUT=>""}],
+ # Check that --zero-terminated is synonymous with -z.
+ ['123', '--zero-terminated', {IN=>"a\na\nb"}, {OUT=>"a\na\nb\0"}],
+ ['124', '--zero-terminated', {IN=>"a\0a\0b"}, {OUT=>"a\0b\0"}],
+ # Check ignore-case
+ ['125', '', {IN=>"A\na\n"}, {OUT=>"A\na\n"}],
+ ['126', '-i', {IN=>"A\na\n"}, {OUT=>"A\n"}],
+ ['127', '--ignore-case', {IN=>"A\na\n"}, {OUT=>"A\n"}],
+ # Check grouping
+ ['128', '--group=prepend', {IN=>"a\na\nb\n"}, {OUT=>"\na\na\n\nb\n"}],
+ ['129', '--group=append', {IN=>"a\na\nb\n"}, {OUT=>"a\na\n\nb\n\n"}],
+ ['130', '--group=separate',{IN=>"a\na\nb\n"}, {OUT=>"a\na\n\nb\n"}],
+ # no explicit grouping = separate
+ ['131', '--group', {IN=>"a\na\nb\n"}, {OUT=>"a\na\n\nb\n"}],
+ ['132', '--group=both', {IN=>"a\na\nb\n"}, {OUT=>"\na\na\n\nb\n\n"}],
+ # Grouping in the special case of a single group
+ ['133', '--group=prepend', {IN=>"a\na\n"}, {OUT=>"\na\na\n"}],
+ ['134', '--group=append', {IN=>"a\na\n"}, {OUT=>"a\na\n\n"}],
+ ['135', '--group=separate',{IN=>"a\na\n"}, {OUT=>"a\na\n"}],
+ ['136', '--group', {IN=>"a\na\n"}, {OUT=>"a\na\n"}],
+ # Grouping with empty input - should never print anything
+ ['137', '--group=prepend', {IN=>""}, {OUT=>""}],
+ ['138', '--group=append', {IN=>""}, {OUT=>""}],
+ ['139', '--group=separate', {IN=>""}, {OUT=>""}],
+ ['140', '--group=both', {IN=>""}, {OUT=>""}],
+ # Grouping with other options - must fail
+ ['141', '--group -c', {IN=>""}, {OUT=>""}, {EXIT=>1},
+ {ERR=>"$prog: --group is mutually exclusive with -c/-d/-D/-u\n" .
+ "Try 'uniq --help' for more information.\n"}],
+ ['142', '--group -d', {IN=>""}, {OUT=>""}, {EXIT=>1},
+ {ERR=>"$prog: --group is mutually exclusive with -c/-d/-D/-u\n" .
+ "Try 'uniq --help' for more information.\n"}],
+ ['143', '--group -u', {IN=>""}, {OUT=>""}, {EXIT=>1},
+ {ERR=>"$prog: --group is mutually exclusive with -c/-d/-D/-u\n" .
+ "Try 'uniq --help' for more information.\n"}],
+ ['144', '--group -D', {IN=>""}, {OUT=>""}, {EXIT=>1},
+ {ERR=>"$prog: --group is mutually exclusive with -c/-d/-D/-u\n" .
+ "Try 'uniq --help' for more information.\n"}],
+ # Grouping with badoption
+ ['145', '--group=badoption',{IN=>""}, {OUT=>""}, {EXIT=>1},
+ {ERR=>"$prog: invalid argument 'badoption' for '--group'\n" .
+ "Valid arguments are:\n" .
+ " - 'prepend'\n" .
+ " - 'append'\n" .
+ " - 'separate'\n" .
+ " - 'both'\n" .
+ "Try '$prog --help' for more information.\n"}],
+);
+
+# Locale related tests
+
+my $locale = $ENV{LOCALE_FR};
+if ( defined $locale && $locale ne 'none' )
+ {
+ # I've only ever triggered the problem in a non-C locale.
+
+ # See if isblank returns true for nbsp.
+ my $x = qx!env printf '\xa0'| LC_ALL=$locale tr '[:blank:]' x!;
+ # If so, expect just one line of output in the schar test.
+ # Otherwise, expect two.
+ my $in = " y z\n\xa0 y z\n";
+ my $schar_exp = $x eq 'x' ? " y z\n" : $in;
+
+ my @Locale_Tests =
+ (
+ # Test for a subtle, system-and-locale-dependent bug in uniq.
+ ['schar', '-f1', {IN => $in}, {OUT => $schar_exp},
+ {ENV => "LC_ALL=$locale"}]
+ );
+
+ push @Tests, @Locale_Tests;
+ }
+
+
+# Set _POSIX2_VERSION=199209 in the environment of each obs-plus* test.
+foreach my $t (@Tests)
+ {
+ $t->[0] =~ /^obs-plus/
+ and push @$t, {ENV=>'_POSIX2_VERSION=199209'};
+ }
+
+@Tests = add_z_variants \@Tests;
+@Tests = triple_test \@Tests;
+
+my $save_temps = $ENV{DEBUG};
+my $verbose = $ENV{VERBOSE};
+
+my $fail = run_tests ($prog, $prog, \@Tests, $save_temps, $verbose);
+exit $fail;
diff --git a/tests/wc/wc-files0-from.pl b/tests/wc/wc-files0-from.pl
new file mode 100755
index 0000000..84da780
--- /dev/null
+++ b/tests/wc/wc-files0-from.pl
@@ -0,0 +1,93 @@
+#!/usr/bin/perl
+# Exercise wc's --files0-from option.
+# FIXME: keep this file in sync with tests/du/files0-from.
+
+# Copyright (C) 2006-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+use strict;
+
+(my $program_name = $0) =~ s|.*/||;
+
+my $prog = 'wc';
+
+# Turn off localization of executable's output.
+@ENV{qw(LANGUAGE LANG LC_ALL)} = ('C') x 3;
+
+my @Tests =
+ (
+ # invalid extra command line argument
+ ['f-extra-arg', '--files0-from=- no-such', {IN=>"a"}, {EXIT=>1},
+ {ERR => "$prog: extra operand 'no-such'\n"
+ . "file operands cannot be combined with --files0-from\n"
+ . "Try '$prog --help' for more information.\n"}
+ ],
+
+ # missing input file
+ ['missing', '--files0-from=missing', {EXIT=>1},
+ {ERR => "$prog: cannot open 'missing' for reading: "
+ . "No such file or directory\n"}],
+
+ # input file name of '-'
+ ['minus-in-stdin', '--files0-from=-', '<', {IN=>{f=>'-'}}, {EXIT=>1},
+ {ERR => "$prog: when reading file names from stdin, no file name of"
+ . " '-' allowed\n"}],
+
+ # empty input, regular file
+ ['empty', '--files0-from=@AUX@', {AUX=>''}],
+
+ # empty input, from non-regular file
+ ['empty-nonreg', '--files0-from=/dev/null'],
+
+ # one NUL
+ ['nul-1', '--files0-from=-', '<', {IN=>"\0"}, {EXIT=>1},
+ {ERR => "$prog: -:1: invalid zero-length file name\n"}],
+
+ # two NULs
+ ['nul-2', '--files0-from=-', '<', {IN=>"\0\0"}, {EXIT=>1},
+ {OUT=>"0 0 0 total\n"},
+ {ERR => "$prog: -:1: invalid zero-length file name\n"
+ . "$prog: -:2: invalid zero-length file name\n"}],
+
+ # one file name, no NUL
+ ['1', '--files0-from=-', '<',
+ {IN=>{f=>"g"}}, {AUX=>{g=>''}}, {OUT=>"0 0 0 g\n"} ],
+
+ # one file name, with NUL
+ ['1a', '--files0-from=-', '<',
+ {IN=>{f=>"g\0"}}, {AUX=>{g=>''}}, {OUT=>"0 0 0 g\n"} ],
+
+ # two file names, no final NUL
+ ['2', '--files0-from=-', '<',
+ {IN=>{f=>"g\0g"}}, {AUX=>{g=>''}},
+ {OUT=>"0 0 0 g\n0 0 0 g\n0 0 0 total\n"} ],
+
+ # two file names, with final NUL
+ ['2a', '--files0-from=-', '<',
+ {IN=>{f=>"g\0g\0"}}, {AUX=>{g=>''}},
+ {OUT=>"0 0 0 g\n0 0 0 g\n0 0 0 total\n"} ],
+
+ # Ensure that $prog processes FILEs following a zero-length name.
+ ['zero-len', '--files0-from=-', '<',
+ {IN=>{f=>"\0g\0"}}, {AUX=>{g=>''}},
+ {OUT=>"0 0 0 g\n0 0 0 total\n"},
+ {ERR => "$prog: -:1: invalid zero-length file name\n"}, {EXIT=>1} ],
+ );
+
+my $save_temps = $ENV{DEBUG};
+my $verbose = $ENV{VERBOSE};
+
+my $fail = run_tests ($program_name, $prog, \@Tests, $save_temps, $verbose);
+exit $fail;
diff --git a/tests/wc/wc-files0.sh b/tests/wc/wc-files0.sh
new file mode 100755
index 0000000..1752305
--- /dev/null
+++ b/tests/wc/wc-files0.sh
@@ -0,0 +1,62 @@
+#!/bin/sh
+# Show that wc's new --files0-from option works.
+
+# Copyright (C) 2006-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ wc
+
+echo 2 > 2b || framework_failure_
+echo 2 words > 2w || framework_failure_
+printf '2b\n2w\n' |tr '\n' '\0' > names || framework_failure_
+
+
+wc --files0-from=names > out || fail=1
+cat <<\EOF > exp || framework_failure_
+ 1 1 2 2b
+ 1 2 8 2w
+ 2 3 10 total
+EOF
+
+compare exp out || fail=1
+
+if ! test "$fail" = 1; then
+ # Repeat the above test, but read the file name list from stdin.
+ rm -f out
+ wc --files0-from=- < names > out || fail=1
+ compare exp out || fail=1
+fi
+
+# Ensure file name containing new lines are output on a single line
+nlname='1
+2'
+touch "$nlname" || framework_failure_
+printf '%s\0' "$nlname" | wc --files0-from=- > out || fail=1
+printf '%s\n' "0 0 0 '1'\$'\\n''2'" > exp || framework_failure_
+compare exp out || fail=1
+
+# Ensure correct byte counts, which fails between v8.24 and v8.26 inclusive
+truncate -s1G wc.big || framework_failure_
+touch wc.small || framework_failure_
+printf '%s\0' wc.big wc.small | wc -c --files0-from=- >out || fail=1
+cat <<\EOF > exp || framework_failure_
+1073741824 wc.big
+0 wc.small
+1073741824 total
+EOF
+compare exp out || fail=1
+
+Exit $fail
diff --git a/tests/wc/wc-nbsp.sh b/tests/wc/wc-nbsp.sh
new file mode 100755
index 0000000..584a8f7
--- /dev/null
+++ b/tests/wc/wc-nbsp.sh
@@ -0,0 +1,52 @@
+#!/bin/sh
+# Test non breaking space handling
+
+# Copyright (C) 2019-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ wc printf
+
+# Before coreutils 8.31 nbsp was treated as part of a word,
+# rather than a word delimiter
+
+check_word_sep() {
+ char="$1"
+ # Use -L to determine whether NBSP is printable.
+ # FreeBSD 11 and OS X treat NBSP as non printable ?
+ if test "$(env printf "=$char=" | wc -L)" = 3; then
+ test $(env printf "=$char=" | wc -w) = 2 || fail=1
+ fi
+}
+
+export LC_ALL=en_US.iso8859-1 # only lowercase form works on macOS 10.15.7
+if test "$(locale charmap 2>/dev/null | sed 's/iso/ISO-/')" = ISO-8859-1; then
+ check_word_sep '\xA0'
+fi
+
+export LC_ALL=en_US.UTF-8
+if test "$(locale charmap 2>/dev/null)" = UTF-8; then
+ check_word_sep '\u00A0'
+ check_word_sep '\u2007'
+ check_word_sep '\u202F'
+ check_word_sep '\u2060'
+fi
+
+export LC_ALL=ru_RU.KOI8-R
+if test "$(locale charmap 2>/dev/null)" = KOI8-R; then
+ check_word_sep '\x9A'
+fi
+
+Exit $fail
diff --git a/tests/wc/wc-parallel.sh b/tests/wc/wc-parallel.sh
new file mode 100755
index 0000000..0319f6e
--- /dev/null
+++ b/tests/wc/wc-parallel.sh
@@ -0,0 +1,36 @@
+#!/bin/sh
+# Ensure that wc prints counts atomically
+# so that concurrent processes don't intersperse their output
+
+# Copyright (C) 2009-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ wc
+
+xargs -P2 </dev/null >/dev/null 2>&1 \
+ || skip_ 'xargs -P is required'
+
+(mkdir tmp && cd tmp && seq 2000 | xargs touch)
+
+# This will output at least 16KiB per process
+# and start 3 processes, with 2 running concurrently,
+# which triggers often on Fedora 11 at least.
+(find tmp tmp tmp -type f | xargs -n2000 -P2 wc 2>err) |
+sed -n '/0 0 0 /!p' |
+grep . > /dev/null && fail=1
+compare /dev/null err || fail=1
+
+Exit $fail
diff --git a/tests/wc/wc-proc.sh b/tests/wc/wc-proc.sh
new file mode 100755
index 0000000..2307f2c
--- /dev/null
+++ b/tests/wc/wc-proc.sh
@@ -0,0 +1,64 @@
+#!/bin/sh
+# Test wc on /proc and /sys files.
+
+# Copyright 2014-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ wc
+
+# Ensure we read() /proc files to determine content length
+for file in /proc/version /sys/kernel/profiling; do
+ if test -r $file; then
+ cp -f $file copy &&
+ wc -c < copy > exp1 || framework_failure_
+
+ wc -c < $file > out1 || fail=1
+ compare exp1 out1 || fail=1
+ fi
+done
+
+# Ensure we handle cases where we don't read()
+truncate -s 2 no_read || framework_failure_
+# read() used when multiple of page size
+truncate -s 1048576 do_read || framework_failure_
+wc -c no_read do_read > out || fail=1
+cat <<\EOF > exp
+ 2 no_read
+1048576 do_read
+1048578 total
+EOF
+compare exp out || fail=1
+
+# Ensure we update the offset even when not reading,
+# which wasn't the case from coreutils-8.27 to coreutils-9.2
+{ wc -c; wc -c; } < no_read > out || fail=1
+{ wc -c; wc -c; } < do_read >> out || fail=1
+cat <<\EOF > exp
+2
+0
+1048576
+0
+EOF
+compare exp out || fail=1
+
+# Ensure we don't read too much when reading,
+# as was the case on 32 bit systems
+# from coreutils-8.24 to coreutils-9.1
+if timeout 10 truncate -s1T do_read; then
+ timeout 10 wc -c do_read || fail=1
+fi
+
+Exit $fail
diff --git a/tests/wc/wc-total.sh b/tests/wc/wc-total.sh
new file mode 100755
index 0000000..113b355
--- /dev/null
+++ b/tests/wc/wc-total.sh
@@ -0,0 +1,60 @@
+#!/bin/sh
+# Show that wc's --total option works.
+
+# Copyright (C) 2022-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ wc
+require_sparse_support_ # for 'truncate --size=$BIG'
+getlimits_
+
+printf '%s\n' '2' > 2b || framework_failure_
+printf '%s\n' '2 words' > 2w || framework_failure_
+
+returns_ 1 wc --total 2b 2w > out || fail=1
+
+wc --total=never 2b 2w > out || fail=1
+cat <<\EOF > exp || framework_failure_
+ 1 1 2 2b
+ 1 2 8 2w
+EOF
+compare exp out || fail=1
+
+wc --total=only 2b 2w > out || fail=1
+cat <<\EOF > exp || framework_failure_
+2 3 10
+EOF
+compare exp out || fail=1
+
+wc --total=always 2b > out || fail=1
+test "$(wc -l < out)" = 2 || fail=1
+
+if truncate -s 2E big; then
+ if test "$UINTMAX_MAX" = '18446744073709551615'; then
+ # Ensure overflow is diagnosed
+ returns_ 1 wc --total=only -c big big big big big big big big \
+ > out || fail=1
+
+ # Ensure total is saturated
+ printf '%s\n' "$UINTMAX_MAX" > exp || framework_failure_
+ compare exp out || fail=1
+
+ # Ensure overflow is ignored if totals not shown
+ wc --total=never -c big big big big big big big big || fail=1
+ fi
+fi
+
+Exit $fail
diff --git a/tests/wc/wc.pl b/tests/wc/wc.pl
new file mode 100755
index 0000000..ed2bc43
--- /dev/null
+++ b/tests/wc/wc.pl
@@ -0,0 +1,50 @@
+#!/usr/bin/perl
+# Basic tests for "wc".
+
+# Copyright (C) 1997-2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+use strict;
+
+my $prog = 'wc';
+
+# Turn off localization of executable's output.
+@ENV{qw(LANGUAGE LANG LC_ALL)} = ('C') x 3;
+
+my @Tests =
+ (
+ ['a0', '-c', {IN_PIPE=>''}, {OUT=>"0\n"}],
+ ['a1', '-l', {IN_PIPE=>''}, {OUT=>"0\n"}],
+ ['a2', '-w', {IN_PIPE=>''}, {OUT=>"0\n"}],
+ ['a3', '-c', {IN_PIPE=>'x'}, {OUT=>"1\n"}],
+ ['a4', '-w', {IN_PIPE=>'x'}, {OUT=>"1\n"}],
+ ['a5', '-w', {IN_PIPE=>"x y\n"}, {OUT=>"2\n"}],
+ ['a6', '-w', {IN_PIPE=>"x y\nz"}, {OUT=>"3\n"}],
+ # Remember, -l counts *newline* bytes, not logical lines.
+ ['a7', '-l', {IN_PIPE=>"x y"}, {OUT=>"0\n"}],
+ ['a8', '-l', {IN_PIPE=>"x y\n"}, {OUT=>"1\n"}],
+ ['a9', '-l', {IN_PIPE=>"x\ny\n"}, {OUT=>"2\n"}],
+ ['b0', '', {IN_PIPE=>""}, {OUT=>" 0 0 0\n"}],
+ ['b1', '', {IN_PIPE=>"a b\nc\n"}, {OUT=>" 2 3 6\n"}],
+ ['c0', '-L', {IN_PIPE=>"1\n12\n"}, {OUT=>"2\n"}],
+ ['c1', '-L', {IN_PIPE=>"1\n123\n1\n"}, {OUT=>"3\n"}],
+ ['c2', '-L', {IN_PIPE=>"\n123456"}, {OUT=>"6\n"}],
+ );
+
+my $save_temps = $ENV{DEBUG};
+my $verbose = $ENV{VERBOSE};
+
+my $fail = run_tests ($prog, $prog, \@Tests, $save_temps, $verbose);
+exit $fail;