logo

utils-std

Collection of commonly available Unix tools git clone https://anongit.hacktivis.me/git/utils-std.git/
commit: 7e4232bcbc5bf2c9fbfcf86a230dbb5f3dc8ae68
parent 1f8bb7cd28421f75fbacba6d691a3ff98054c450
Author: Haelwenn (lanodan) Monnier <contact@hacktivis.me>
Date:   Sat,  6 Sep 2025 08:24:11 +0200

Merge branch 'getopt-long-all'

Diffstat:

Mcmd/base64.c18++++++++++++++++++
Mcmd/basename.c19+++++++++++++++++++
Mcmd/cmp.c19+++++++++++++++++++
Mcmd/cut.c22++++++++++++++++++++++
Mcmd/df.c23+++++++++++++++++++++++
Mcmd/head.c20++++++++++++++++++++
Mcmd/id.c21+++++++++++++++++++++
Mcmd/ln.c22++++++++++++++++++++++
Mcmd/mkdir.c19+++++++++++++++++++
Mcmd/mkfifo.c17+++++++++++++++++
Mcmd/mknod.c17+++++++++++++++++
Mcmd/mv.c20++++++++++++++++++++
Mcmd/nice.c17+++++++++++++++++
Mcmd/nproc.c17+++++++++++++++++
Mcmd/paste.c19+++++++++++++++++++
Mcmd/pwd.c18++++++++++++++++++
Mcmd/realpath.c38++++++++++++++++++++++++++++++++++++++
Mcmd/rm.c23++++++++++++++++++++++-
Mcmd/seq.c18++++++++++++++++++
Mcmd/shuf.c19+++++++++++++++++++
Mcmd/split.c18++++++++++++++++++
Mcmd/strings.c19+++++++++++++++++++
Mcmd/sync.c17+++++++++++++++++
Mcmd/tee.c18++++++++++++++++++
Mcmd/timeout.c19+++++++++++++++++++
Mcmd/touch.c20++++++++++++++++++++
Mcmd/tr.c21++++++++++++++++++++-
Mcmd/truncate.c19+++++++++++++++++++
Mcmd/uniq.c21+++++++++++++++++++++
Mcmd/which.c17+++++++++++++++++
Mtest-cmd/rm.t2+-
Mtest-cmd/tee.sh6+++++-
32 files changed, 599 insertions(+), 4 deletions(-)

diff --git a/cmd/base64.c b/cmd/base64.c @@ -4,6 +4,7 @@ // SPDX-License-Identifier: MPL-2.0 AND BSD-2-Clause #define _POSIX_C_SOURCE 200809L +#include "../config.h" #include "../libutils/getopt_nolong.h" #include <assert.h> /* assert */ @@ -15,6 +16,9 @@ #include <string.h> /* strerror(), strncmp() */ #include <sys/stat.h> /* fstat */ #include <unistd.h> /* read(), write(), close(), getopt() */ +#ifdef HAS_GETOPT_LONG +#include <getopt.h> +#endif // 64(26+26+10+2) + NULL static const char *b64_encmap = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; @@ -263,7 +267,21 @@ base64_main(int argc, char *argv[]) int ret = 0; +#ifdef HAS_GETOPT_LONG + // Strictly for GNUisms compatibility so no long-only options + // clang-format off + static struct option opts[] = { + {"decode", no_argument, NULL, 'd'}, + {"wrap", required_argument, NULL, 'w'}, + {0, 0, 0, 0}, + }; + // clang-format on + + // Need + as first character to get POSIX-style option parsing + for(int c = -1; (c = getopt_long(argc, argv, "+:dw:", opts, NULL)) != -1;) +#else for(int c = -1; (c = getopt_nolong(argc, argv, ":dw:")) != -1;) +#endif { switch(c) { diff --git a/cmd/basename.c b/cmd/basename.c @@ -4,6 +4,7 @@ #define _POSIX_C_SOURCE 200809L +#include "../config.h" #include "../libutils/getopt_nolong.h" #include <libgen.h> // basename @@ -11,6 +12,9 @@ #include <stdio.h> // puts, perror #include <string.h> // strlen, strncmp #include <unistd.h> // getopt +#ifdef HAS_GETOPT_LONG +#include <getopt.h> +#endif const char *argv0 = "basename"; @@ -51,7 +55,22 @@ main(int argc, char *argv[]) char *suffix = NULL; char delim = '\n'; +#ifdef HAS_GETOPT_LONG + // Strictly for GNUisms compatibility so no long-only options + // clang-format off + static struct option opts[] = { + {"multiple", no_argument, NULL, 'a'}, + {"suffix", required_argument, NULL, 's'}, + {"zero", no_argument, NULL, 'z'}, + {0, 0, 0, 0}, + }; + // clang-format on + + // Need + as first character to get POSIX-style option parsing + for(int c = -1; (c = getopt_long(argc, argv, "+:as:z", opts, NULL)) != -1;) +#else for(int c = -1; (c = getopt_nolong(argc, argv, ":as:z")) != -1;) +#endif { switch(c) { diff --git a/cmd/cmp.c b/cmd/cmp.c @@ -15,6 +15,9 @@ #include <string.h> // strerror #include <sys/stat.h> // fstat #include <unistd.h> // getopt +#ifdef HAS_GETOPT_LONG +#include <getopt.h> +#endif static bool opt_s = false, opt_l = false; static unsigned long max_bytes = 0; @@ -134,7 +137,23 @@ main(int argc, char *argv[]) { char *endptr = NULL; +#ifdef HAS_GETOPT_LONG + // Strictly for GNUisms compatibility so no long-only options + // clang-format off + static struct option opts[] = { + {"verbose", no_argument, NULL, 'l'}, + {"bytes", required_argument, NULL, 'n'}, + {"quiet", no_argument, NULL, 's'}, + {"silent", no_argument, NULL, 's'}, + {0, 0, 0, 0}, + }; + // clang-format on + + // Need + as first character to get POSIX-style option parsing + for(int c = -1; (c = getopt_long(argc, argv, "+:ln:s", opts, NULL)) != -1;) +#else for(int c = -1; (c = getopt_nolong(argc, argv, ":ln:s")) != -1;) +#endif { switch(c) { diff --git a/cmd/cut.c b/cmd/cut.c @@ -4,6 +4,7 @@ #define _POSIX_C_SOURCE 202405L +#include "../config.h" #include "../lib/reallocarray.h" #include "../libutils/getopt_nolong.h" @@ -17,6 +18,9 @@ #include <string.h> // strerror #include <unistd.h> // getopt #include <wchar.h> +#ifdef HAS_GETOPT_LONG +#include <getopt.h> +#endif #undef MIN #define MIN(a, b) (((a) < (b)) ? (a) : (b)) @@ -381,7 +385,25 @@ main(int argc, char *argv[]) } errno = 0; +#ifdef HAS_GETOPT_LONG + // Strictly for GNUisms compatibility so no long-only options + // clang-format off + static struct option opts[] = { + {"bytes", required_argument, NULL, 'b'}, + {"characters", required_argument, NULL, 'c'}, + {"delimiter", required_argument, NULL, 'd'}, + {"fields", required_argument, NULL, 'f'}, + {"only-delimited", no_argument, NULL, 's'}, + {"zero-terminated", no_argument, NULL, 'z'}, + {0, 0, 0, 0}, + }; + // clang-format on + + // Need + as first character to get POSIX-style option parsing + for(int c = -1; (c = getopt_long(argc, argv, "+:b:c:d:f:nsz", opts, NULL)) != -1;) +#else for(int c = -1; (c = getopt_nolong(argc, argv, ":b:c:d:f:nsz")) != -1;) +#endif { switch(c) { diff --git a/cmd/df.c b/cmd/df.c @@ -5,6 +5,7 @@ #define _POSIX_C_SOURCE 202405L #define _DEFAULT_SOURCE // mntent in glibc 2.19+ +#include "../config.h" #include "../lib/reallocarray.h" #include "../libutils/getopt_nolong.h" #include "../libutils/humanize.h" @@ -19,6 +20,9 @@ #include <sys/stat.h> // stat, dev_t #include <sys/statvfs.h> #include <unistd.h> // getopt +#ifdef HAS_GETOPT_LONG +#include <getopt.h> +#endif #define STR(s) #s @@ -62,7 +66,26 @@ main(int argc, char *argv[]) size_t only_count = 0; static char *only[DF_MNT_TYPE_MAX]; +#ifdef HAS_GETOPT_LONG + // Strictly for GNUisms compatibility so no long-only options + // clang-format off + static struct option opts[] = { + {"all", no_argument, NULL, 'a'}, + {"human-readable", no_argument, NULL, 'h'}, + {"inodes", no_argument, NULL, 'i'}, + {"local", no_argument, NULL, 'l'}, + {"portability", no_argument, NULL, 'P'}, + {"type", required_argument, NULL, 't'}, + {"exclude-type", required_argument, NULL, 'x'}, + {0, 0, 0, 0}, + }; + // clang-format on + + // Need + as first character to get POSIX-style option parsing + for(int c = -1; (c = getopt_long(argc, argv, "+:ahilPkTt:x:", opts, NULL)) != -1;) +#else for(int c = -1; (c = getopt_nolong(argc, argv, ":ahilPkTt:x:")) != -1;) +#endif { switch(c) { diff --git a/cmd/head.c b/cmd/head.c @@ -17,6 +17,9 @@ #include <stdlib.h> // strtoul #include <string.h> // strerror #include <unistd.h> // read +#ifdef HAS_GETOPT_LONG +#include <getopt.h> +#endif static const char *header_fmt = "==> %s <==\n"; @@ -254,7 +257,24 @@ main(int argc, char *argv[]) continue; } +#ifdef HAS_GETOPT_LONG + // Strictly for GNUisms compatibility so no long-only options + // clang-format off + static struct option opts[] = { + {"bytes", required_argument, NULL, 'c'}, + {"lines", optional_argument, NULL, 'n'}, + {"quiet", no_argument, NULL, 'q'}, + {"silent", no_argument, NULL, 'q'}, + {"zero-terminated", no_argument, NULL, 'z'}, + {0, 0, 0, 0}, + }; + // clang-format on + + // Need + as first character to get POSIX-style option parsing + int c = getopt_long(argc, argv, "+:qvc:n:z", opts, NULL); +#else int c = getopt_nolong(argc, argv, ":qvc:n:z"); +#endif if(c == -1) break; switch(c) diff --git a/cmd/id.c b/cmd/id.c @@ -3,6 +3,7 @@ // SPDX-License-Identifier: MPL-2.0 #define _DEFAULT_SOURCE // getgrouplist (4.4BSD+) +#include "../config.h" #include "../libutils/getopt_nolong.h" #include <grp.h> // getgrgid, getgroups, getgrouplist(glibc) @@ -12,6 +13,9 @@ #include <stdlib.h> // calloc, free #include <sys/types.h> // uid_t #include <unistd.h> // getuid, getgid, getopt, opt*, getgrouplist(FreeBSD, NetBSD) +#ifdef HAS_GETOPT_LONG +#include <getopt.h> +#endif const char *argv0 = "id"; bool name_flag = false; @@ -190,7 +194,24 @@ main(int argc, char *argv[]) struct passwd pw = {.pw_uid = uid, .pw_gid = gid}; struct passwd epw = {.pw_uid = euid, .pw_gid = egid}; +#ifdef HAS_GETOPT_LONG + // Strictly for GNUisms compatibility so no long-only options + // clang-format off + static struct option opts[] = { + {"group", no_argument, NULL, 'g'}, + {"groups", no_argument, NULL, 'G'}, + {"name", no_argument, NULL, 'n'}, + {"real", no_argument, NULL, 'r'}, + {"user", no_argument, NULL, 'u'}, + {0, 0, 0, 0}, + }; + // clang-format on + + // Need + as first character to get POSIX-style option parsing + for(int c = -1; (c = getopt_long(argc, argv, "+:Ggunr", opts, NULL)) != -1;) +#else for(int c = -1; (c = getopt_nolong(argc, argv, ":Ggunr")) != -1;) +#endif { switch(c) { diff --git a/cmd/ln.c b/cmd/ln.c @@ -6,6 +6,7 @@ #define _DEFAULT_SOURCE // due to O_PATH // Don't define _POSIX_C_SOURCE otherwise FreeBSD hides O_PATH +#include "../config.h" #include "../lib/bitmasks.h" #include "../libutils/getopt_nolong.h" @@ -18,6 +19,9 @@ #include <string.h> // strerror #include <sys/stat.h> // fstat #include <unistd.h> // getopt, symlink, link +#ifdef HAS_GETOPT_LONG +#include <getopt.h> +#endif const char *argv0 = "ln"; @@ -175,7 +179,25 @@ main(int argc, char *argv[]) { bool verbose = false; +#ifdef HAS_GETOPT_LONG + // Strictly for GNUisms compatibility so no long-only options + // clang-format off + static struct option opts[] = { + {"force", no_argument, NULL, 'f'}, + {"logical", no_argument, NULL, 'L'}, + {"no-dereference", no_argument, NULL, 'n'}, + {"physical", no_argument, NULL, 'P'}, + {"symbolic", no_argument, NULL, 's'}, + {"verbose", no_argument, NULL, 'v'}, + {0, 0, 0, 0}, + }; + // clang-format on + + // Need + as first character to get POSIX-style option parsing + for(int c = -1; (c = getopt_long(argc, argv, "+:fnsLPv", opts, NULL)) != -1;) +#else for(int c = -1; (c = getopt_nolong(argc, argv, ":fnsLPv")) != -1;) +#endif { switch(c) { diff --git a/cmd/mkdir.c b/cmd/mkdir.c @@ -4,6 +4,7 @@ #define _POSIX_C_SOURCE 200809L +#include "../config.h" #include "../libutils/getopt_nolong.h" #include "../libutils/lib_mkdir.h" #include "../libutils/mode.h" @@ -15,6 +16,9 @@ #include <string.h> // strerror #include <sys/stat.h> // mkdir #include <unistd.h> // getopt +#ifdef HAS_GETOPT_LONG +#include <getopt.h> +#endif const char *argv0 = "mkdir"; @@ -54,7 +58,22 @@ main(int argc, char *argv[]) const char *errstr = NULL; // clang-format on +#ifdef HAS_GETOPT_LONG + // Strictly for GNUisms compatibility so no long-only options + // clang-format off + static struct option opts[] = { + {"mode", required_argument, NULL, 'm'}, + {"parents", no_argument, NULL, 'p'}, + {"verbose", no_argument, NULL, 'v'}, + {0, 0, 0, 0}, + }; + // clang-format on + + // Need + as first character to get POSIX-style option parsing + for(int c = -1; (c = getopt_long(argc, argv, "+:pvm:", opts, NULL)) != -1;) +#else for(int c = -1; (c = getopt_nolong(argc, argv, ":pvm:")) != -1;) +#endif { switch(c) { diff --git a/cmd/mkfifo.c b/cmd/mkfifo.c @@ -4,6 +4,7 @@ #define _POSIX_C_SOURCE 200809L +#include "../config.h" #include "../libutils/getopt_nolong.h" #include "../libutils/mode.h" @@ -13,6 +14,9 @@ #include <string.h> // strerror #include <sys/stat.h> // mkfifo #include <unistd.h> // getopt +#ifdef HAS_GETOPT_LONG +#include <getopt.h> +#endif mode_t filemask; const char *argv0 = "mkfifo"; @@ -30,7 +34,20 @@ main(int argc, char *argv[]) const char *errstr = NULL; +#ifdef HAS_GETOPT_LONG + // Strictly for GNUisms compatibility so no long-only options + // clang-format off + static struct option opts[] = { + {"mode", required_argument, NULL, 'm'}, + {0, 0, 0, 0}, + }; + // clang-format on + + // Need + as first character to get POSIX-style option parsing + for(int c = -1; (c = getopt_long(argc, argv, "+:m:", opts, NULL)) != -1;) +#else for(int c = -1; (c = getopt_nolong(argc, argv, ":m:")) != -1;) +#endif { switch(c) { diff --git a/cmd/mknod.c b/cmd/mknod.c @@ -5,6 +5,7 @@ #define _POSIX_C_SOURCE 200809L #define _XOPEN_SOURCE 700 // mknod is in XSI +#include "../config.h" #include "../libutils/getopt_nolong.h" #include "../libutils/mode.h" @@ -15,6 +16,9 @@ #include <sys/stat.h> // mknod #include <sys/sysmacros.h> // makedev #include <unistd.h> // getopt +#ifdef HAS_GETOPT_LONG +#include <getopt.h> +#endif mode_t filemask; const char *argv0 = "mknod"; @@ -54,7 +58,20 @@ main(int argc, char *argv[]) const char *errstr = NULL; +#ifdef HAS_GETOPT_LONG + // Strictly for GNUisms compatibility so no long-only options + // clang-format off + static struct option opts[] = { + {"mode", required_argument, NULL, 'm'}, + {0, 0, 0, 0}, + }; + // clang-format on + + // Need + as first character to get POSIX-style option parsing + for(int c = -1; (c = getopt_long(argc, argv, "+:m:", opts, NULL)) != -1;) +#else for(int c = -1; (c = getopt_nolong(argc, argv, ":m:")) != -1;) +#endif { switch(c) { diff --git a/cmd/mv.c b/cmd/mv.c @@ -28,6 +28,9 @@ #include <string.h> // strcmp #include <sys/stat.h> // stat, S_ISDIR #include <unistd.h> // getopt +#ifdef HAS_GETOPT_LONG +#include <getopt.h> +#endif // Workaround against GNU glibc // https://sourceware.org/bugzilla/show_bug.cgi?id=18228 @@ -409,7 +412,24 @@ main(int argc, char *argv[]) .sep = "", }; +#ifdef HAS_GETOPT_LONG + // Strictly for GNUisms compatibility so no long-only options + // clang-format off + static struct option opts[] = { + {"force", no_argument, NULL, 'f'}, + {"interactive", no_argument, NULL, 'i'}, + {"no-clobber", no_argument, NULL, 'n'}, + {"target-directory", required_argument, NULL, 't'}, + {"verbose", no_argument, NULL, 'v'}, + {0, 0, 0, 0}, + }; + // clang-format on + + // Need + as first character to get POSIX-style option parsing + for(int c = -1; (c = getopt_long(argc, argv, "+:fint:v", opts, NULL)) != -1;) +#else for(int c = -1; (c = getopt_nolong(argc, argv, ":fint:v")) != -1;) +#endif { switch(c) { diff --git a/cmd/nice.c b/cmd/nice.c @@ -4,6 +4,7 @@ #define _POSIX_C_SOURCE 200809L #define _XOPEN_SOURCE 700 // nice() is in XSI +#include "../config.h" #include "../libutils/getopt_nolong.h" #include <assert.h> @@ -12,6 +13,9 @@ #include <stdlib.h> // abort #include <string.h> // strerror #include <unistd.h> // getopt, nice +#ifdef HAS_GETOPT_LONG +#include <getopt.h> +#endif const char *argv0 = "nice"; @@ -26,7 +30,20 @@ main(int argc, char *argv[]) { long incr = 0; +#ifdef HAS_GETOPT_LONG + // Strictly for GNUisms compatibility so no long-only options + // clang-format off + static struct option opts[] = { + {"adjustment", required_argument, NULL, 'n'}, + {0, 0, 0, 0}, + }; + // clang-format on + + // Need + as first character to get POSIX-style option parsing + for(int c = -1; (c = getopt_long(argc, argv, "+:n:", opts, NULL)) != -1;) +#else for(int c = -1; (c = getopt_nolong(argc, argv, ":n:")) != -1;) +#endif { char *endptr = NULL; diff --git a/cmd/nproc.c b/cmd/nproc.c @@ -9,12 +9,16 @@ // Sadly {Free,Net}BSD hides _SC_NPROCESSORS_{CONF,ONLN} if _POSIX_C_SOURCE is defined *sigh* // #define _POSIX_C_SOURCE 202405L +#include "../config.h" #include "../libutils/getopt_nolong.h" #include <errno.h> #include <stdio.h> // printf #include <string.h> // strerror #include <unistd.h> // sysconf, getopt, opt* +#ifdef HAS_GETOPT_LONG +#include <getopt.h> +#endif const char *argv0 = "nproc"; @@ -31,7 +35,20 @@ main(int argc, char *argv[]) int target = _SC_NPROCESSORS_ONLN; const char *target_str = "_SC_NPROCESSORS_ONLN"; +#ifdef HAS_GETOPT_LONG + // Strictly for GNUisms compatibility so no long-only options + // clang-format off + static struct option opts[] = { + {"all", no_argument, NULL, 'a'}, + {0, 0, 0, 0}, + }; + // clang-format on + + // Need + as first character to get POSIX-style option parsing + for(int c = -1; (c = getopt_long(argc, argv, "+:a", opts, NULL)) != -1;) +#else for(int c = -1; (c = getopt_nolong(argc, argv, ":a")) != -1;) +#endif { switch(c) { diff --git a/cmd/paste.c b/cmd/paste.c @@ -34,6 +34,7 @@ #define _POSIX_C_SOURCE 200809L +#include "../config.h" #include "../libutils/err.h" #include "../libutils/getopt_nolong.h" @@ -48,6 +49,9 @@ #include <sys/types.h> #include <unistd.h> #include <wchar.h> +#ifdef HAS_GETOPT_LONG +#include <getopt.h> +#endif static wchar_t *delim; static int delimcnt; @@ -267,7 +271,22 @@ main(int argc, char *argv[]) int seq = 0; +#ifdef HAS_GETOPT_LONG + // Strictly for GNUisms compatibility so no long-only options + // clang-format off + static struct option opts[] = { + {"delimiter", required_argument, NULL, 'd'}, + {"serial", no_argument, NULL, 's'}, + {"zero-terminated", no_argument, NULL, 'z'}, + {0, 0, 0, 0}, + }; + // clang-format on + + // Need + as first character to get POSIX-style option parsing + for(int c = -1; (c = getopt_long(argc, argv, "+:d:sz", opts, NULL)) != -1;) +#else for(int c = -1; (c = getopt_nolong(argc, argv, ":d:sz")) != -1;) +#endif { switch(c) { diff --git a/cmd/pwd.c b/cmd/pwd.c @@ -3,6 +3,7 @@ // SPDX-License-Identifier: MPL-2.0 #define _POSIX_C_SOURCE 200809L +#include "../config.h" #include "../libutils/getopt_nolong.h" #include <limits.h> // PATH_MAX @@ -11,6 +12,9 @@ #include <stdlib.h> // getenv #include <sys/stat.h> #include <unistd.h> // getcwd +#ifdef HAS_GETOPT_LONG +#include <getopt.h> +#endif const char *argv0 = "pwd"; @@ -76,7 +80,21 @@ main(int argc, char *argv[]) { enum pwd mode = PWD_L; +#ifdef HAS_GETOPT_LONG + // Strictly for GNUisms compatibility so no long-only options + // clang-format off + static struct option opts[] = { + {"logical", no_argument, NULL, 'L'}, + {"physical", no_argument, NULL, 'P'}, + {0, 0, 0, 0}, + }; + // clang-format on + + // Need + as first character to get POSIX-style option parsing + for(int c = -1; (c = getopt_long(argc, argv, "+:LP", opts, NULL)) != -1;) +#else for(int c = -1; (c = getopt_nolong(argc, argv, ":LP")) != -1;) +#endif { switch(c) { diff --git a/cmd/realpath.c b/cmd/realpath.c @@ -5,6 +5,7 @@ #define _POSIX_C_SOURCE 200809L #define _XOPEN_SOURCE 700 // realpath is in XSI +#include "../config.h" #include "../libutils/fs.h" #include "../libutils/getopt_nolong.h" @@ -15,6 +16,9 @@ #include <stdlib.h> // realpath() #include <string.h> // strncmp(), strnlen, strerror #include <unistd.h> // getopt +#ifdef HAS_GETOPT_LONG +#include <getopt.h> +#endif static bool must_exists = false; static bool offline = false; @@ -106,7 +110,24 @@ main_realpath(int argc, char *argv[]) int offset_sep = 0; +#ifdef HAS_GETOPT_LONG + // Strictly for GNUisms compatibility so no long-only options + // clang-format off + static struct option opts[] = { + {"canonicalize-existing", no_argument, NULL, 'e'}, + {"canonicalize-missing", no_argument, NULL, 'm'}, + {"quiet", no_argument, NULL, 'q'}, + {"strip", no_argument, NULL, 's'}, + {"zero", no_argument, NULL, 'z'}, + {0, 0, 0, 0}, + }; + // clang-format on + + // Need + as first character to get POSIX-style option parsing + for(int c = -1; (c = getopt_long(argc, argv, "+:Eemnszq", opts, NULL)) != -1;) +#else for(int c = -1; (c = getopt_nolong(argc, argv, ":Eemnszq")) != -1;) +#endif { switch(c) { @@ -173,7 +194,24 @@ main_readlink(int argc, char *argv[]) int offset_sep = 0; +#ifdef HAS_GETOPT_LONG + // Strictly for GNUisms compatibility so no long-only options + // clang-format off + static struct option opts[] = { + {"canonicalize", no_argument, NULL, 'f'}, + {"canonicalize-existing", no_argument, NULL, 'e'}, + {"canonicalize-missing", no_argument, NULL, 'm'}, + {"no-newline", no_argument, NULL, 'n'}, + {"zero", no_argument, NULL, 'z'}, + {0, 0, 0, 0}, + }; + // clang-format on + + // Need + as first character to get POSIX-style option parsing + for(int c = -1; (c = getopt_long(argc, argv, "+:femnz", opts, NULL)) != -1;) +#else for(int c = -1; (c = getopt_nolong(argc, argv, ":femnz")) != -1;) +#endif { switch(c) { diff --git a/cmd/rm.c b/cmd/rm.c @@ -9,6 +9,7 @@ #define _NETBSD_SOURCE #endif +#include "../config.h" #include "../libutils/consent.h" #include "../libutils/getopt_nolong.h" @@ -25,6 +26,9 @@ #include <string.h> // strerror #include <sys/stat.h> // chmod, fstatat, S_ISDIR #include <unistd.h> // unlink, isatty +#ifdef HAS_GETOPT_LONG +#include <getopt.h> +#endif bool opt_d = false, force = false, recurse = false, verbose = false, opt_i = false; const char *argv0 = "rm"; @@ -172,13 +176,30 @@ do_unlinkat(int fd, char *name, char *acc_path) static void usage(void) { - fprintf(stderr, "Usage: rm [-firRv] [files ...]\n"); + fprintf(stderr, "Usage: rm [-dfirRv] [files ...]\n"); } int main(int argc, char *argv[]) { +#ifdef HAS_GETOPT_LONG + // Strictly for GNUisms compatibility so no long-only options + // clang-format off + static struct option opts[] = { + {"dir", no_argument, NULL, 'd'}, + {"force", no_argument, NULL, 'f'}, + {"interactive", no_argument, NULL, 'i'}, + {"recursive", no_argument, NULL, 'r'}, + {"verbose", no_argument, NULL, 'v'}, + {0, 0, 0, 0}, + }; + // clang-format on + + // Need + as first character to get POSIX-style option parsing + for(int c = -1; (c = getopt_long(argc, argv, "+:dfirRv", opts, NULL)) != -1;) +#else for(int c = -1; (c = getopt_nolong(argc, argv, ":dfirRv")) != -1;) +#endif { switch(c) { diff --git a/cmd/seq.c b/cmd/seq.c @@ -3,6 +3,7 @@ // SPDX-License-Identifier: MPL-2.0 #define _POSIX_C_SOURCE 200809L +#include "../config.h" #include "../libutils/getopt_nolong.h" #include <ctype.h> // isdigit @@ -13,6 +14,9 @@ #include <stdlib.h> // exit, strtod #include <string.h> // strerror #include <unistd.h> // getopt, optarg, optind +#ifdef HAS_GETOPT_LONG +#include <getopt.h> +#endif const char *argv0 = "seq"; const char *sep = "\n"; @@ -81,7 +85,21 @@ usage(void) int main(int argc, char *argv[]) { +#ifdef HAS_GETOPT_LONG + // Strictly for GNUisms compatibility so no long-only options + // clang-format off + static struct option opts[] = { + {"equal-width", no_argument, NULL, 'w'}, + {"separator", required_argument, NULL, 's'}, + {0, 0, 0, 0}, + }; + // clang-format on + + // Need + as first character to get POSIX-style option parsing + for(int c = -1; (c = getopt_long(argc, argv, "+:ws:t:", opts, NULL)) != -1;) +#else for(int c = -1; (c = getopt_nolong(argc, argv, ":ws:t:")) != -1;) +#endif { switch(c) { diff --git a/cmd/shuf.c b/cmd/shuf.c @@ -3,6 +3,7 @@ // SPDX-License-Identifier: MPL-2.0 #define _POSIX_C_SOURCE 200809L +#include "../config.h" #include "../libutils/getopt_nolong.h" #include <errno.h> @@ -12,6 +13,9 @@ #include <string.h> // strerror, memcpy #include <time.h> // time #include <unistd.h> // getopt +#ifdef HAS_GETOPT_LONG +#include <getopt.h> +#endif // Not a full shuffle, if there is more than 512 lines then last lines are never going to be printed first. // But this allows bounded memory usage. @@ -98,7 +102,22 @@ main(int argc, char *argv[]) bool e_flag = false; srand((int)time(NULL)); +#ifdef HAS_GETOPT_LONG + // Strictly for GNUisms compatibility so no long-only options + // clang-format off + static struct option opts[] = { + {"echo", no_argument, NULL, 'e'}, + {"head-count", required_argument, NULL, 'n'}, + {"zero-terminated", no_argument, NULL, 'z'}, + {0, 0, 0, 0}, + }; + // clang-format on + + // Need + as first character to get POSIX-style option parsing + for(int c = -1; (c = getopt_long(argc, argv, "+:en:z", opts, NULL)) != -1;) +#else for(int c = -1; (c = getopt_nolong(argc, argv, ":en:z")) != -1;) +#endif { char *endptr = NULL; diff --git a/cmd/split.c b/cmd/split.c @@ -17,6 +17,9 @@ #include <string.h> // strerror #include <sys/stat.h> // fstat #include <unistd.h> // getopt +#ifdef HAS_GETOPT_LONG +#include <getopt.h> +#endif const char *argv0 = "split"; @@ -241,7 +244,22 @@ static const char *error_opt_b_l = "%s: error: Options -b and -l are mutually ex int main(int argc, char *argv[]) { +#ifdef HAS_GETOPT_LONG + // Strictly for GNUisms compatibility so no long-only options + // clang-format off + static struct option opts[] = { + {"suffix-length", required_argument, NULL, 'a'}, + {"bytes", required_argument, NULL, 'b'}, + {"lines", required_argument, NULL, 'l'}, + {0, 0, 0, 0}, + }; + // clang-format on + + // Need + as first character to get POSIX-style option parsing + for(int c = -1; (c = getopt_long(argc, argv, "+:a:b:l:", opts, NULL)) != -1;) +#else for(int c = -1; (c = getopt_nolong(argc, argv, ":a:b:l:")) != -1;) +#endif { char *endptr = NULL; diff --git a/cmd/strings.c b/cmd/strings.c @@ -3,6 +3,7 @@ // SPDX-License-Identifier: MPL-2.0 #define _POSIX_C_SOURCE 200809L +#include "../config.h" #include "../libutils/getopt_nolong.h" #include <ctype.h> /* isprint() */ @@ -13,6 +14,9 @@ #include <stdlib.h> /* strtol() */ #include <string.h> /* strerror(), strncmp() */ #include <unistd.h> /* read(), write(), close() */ +#ifdef HAS_GETOPT_LONG +#include <getopt.h> +#endif const char *argv0 = "strings"; size_t opt_min_strlen = 4; @@ -98,7 +102,22 @@ usage(void) int main(int argc, char *argv[]) { +#ifdef HAS_GETOPT_LONG + // Strictly for GNUisms compatibility so no long-only options + // clang-format off + static struct option opts[] = { + {"all", no_argument, NULL, 'a'}, + {"bytes", required_argument, NULL, 'n'}, + {"radix", required_argument, NULL, 't'}, + {0, 0, 0, 0}, + }; + // clang-format on + + // Need + as first character to get POSIX-style option parsing + for(int c = -1; (c = getopt_long(argc, argv, "+:an:t:z", opts, NULL)) != -1;) +#else for(int c = -1; (c = getopt_nolong(argc, argv, ":an:t:z")) != -1;) +#endif { char *endptr = NULL; diff --git a/cmd/sync.c b/cmd/sync.c @@ -16,6 +16,9 @@ #include <stdlib.h> // abort #include <string.h> // strerror #include <unistd.h> // fsync, sync, getopt, syncfs +#ifdef HAS_GETOPT_LONG +#include <getopt.h> +#endif const char *argv0 = "sync"; @@ -25,7 +28,21 @@ main(int argc, char *argv[]) int err = 0; int (*sync_func)(int) = fsync; +#ifdef HAS_GETOPT_LONG + // Strictly for GNUisms compatibility so no long-only options + // clang-format off + static struct option opts[] = { + {"data", no_argument, NULL, 'd'}, + {"file-system", no_argument, NULL, 'f'}, + {0, 0, 0, 0}, + }; + // clang-format on + + // Need + as first character to get POSIX-style option parsing + for(int c = -1; (c = getopt_long(argc, argv, "+:df", opts, NULL)) != -1;) +#else for(int c = -1; (c = getopt_nolong(argc, argv, ":df")) != -1;) +#endif { switch(c) { diff --git a/cmd/tee.c b/cmd/tee.c @@ -3,6 +3,7 @@ // SPDX-License-Identifier: MPL-2.0 #define _POSIX_C_SOURCE 200809L +#include "../config.h" #include "../libutils/getopt_nolong.h" #include <assert.h> /* assert() */ @@ -12,6 +13,9 @@ #include <stdlib.h> /* calloc(), free(), abort() */ #include <string.h> /* strerror() */ #include <unistd.h> /* getopt(), opt… */ +#ifdef HAS_GETOPT_LONG +#include <getopt.h> +#endif const char *argv0 = "tee"; @@ -31,7 +35,21 @@ main(int argc, char *argv[]) FILE **fds = {NULL}; // Shut up GCC int c; +#ifdef HAS_GETOPT_LONG + // Strictly for GNUisms compatibility so no long-only options + // clang-format off + static struct option opts[] = { + {"append", required_argument, NULL, 'a'}, + {"ignore-interrupts", required_argument, NULL, 'i'}, + {0, 0, 0, 0}, + }; + // clang-format on + + // Need + as first character to get POSIX-style option parsing + for(int c = -1; (c = getopt_long(argc, argv, "+:ai", opts, NULL)) != -1;) +#else for(int c = -1; (c = getopt_nolong(argc, argv, ":ai")) != -1;) +#endif { switch(c) { diff --git a/cmd/timeout.c b/cmd/timeout.c @@ -4,6 +4,7 @@ #define _POSIX_C_SOURCE 200809L #define _DEFAULT_SOURCE // For NSIG in sys_signame.h, thanks glibc +#include "../config.h" #include "../lib/sys_signame.h" #include "../libutils/getopt_nolong.h" #include "../libutils/strtodur.h" @@ -19,6 +20,9 @@ #include <sys/wait.h> #include <time.h> // nanosleep #include <unistd.h> // getopt +#ifdef HAS_GETOPT_LONG +#include <getopt.h> +#endif #define CMD_EXIT_TIMEOUT 124 #define CMD_EXIT_FAILURE 125 @@ -61,7 +65,22 @@ main(int argc, char *argv[]) char *arg = NULL; +#ifdef HAS_GETOPT_LONG + // Strictly for GNUisms compatibility so no long-only options + // clang-format off + static struct option opts[] = { + {"kill-after", required_argument, NULL, 'k'}, + {"preserve-status", required_argument, NULL, 'p'}, + {"signal", required_argument, NULL, 's'}, + {0, 0, 0, 0}, + }; + // clang-format on + + // Need + as first character to get POSIX-style option parsing + for(int c = -1; (c = getopt_long(argc, argv, "+:fk:ps:", opts, NULL)) != -1;) +#else for(int c = -1; (c = getopt_nolong(argc, argv, ":fk:ps:")) != -1;) +#endif { switch(c) { diff --git a/cmd/touch.c b/cmd/touch.c @@ -10,6 +10,7 @@ #define _BSD_SOURCE // O_NOFOLLOW #endif +#include "../config.h" #include "../lib/bitmasks.h" /* FIELD_* */ #include "../libutils/datetime_parse.h" /* datetime_parse */ #include "../libutils/getopt_nolong.h" @@ -23,6 +24,9 @@ #include <sys/stat.h> /* futimens, stat, utimensat */ #include <time.h> /* mktime */ #include <unistd.h> /* getopt, opt*, close */ +#ifdef HAS_GETOPT_LONG +#include <getopt.h> +#endif const char *argv0 = "touch"; @@ -130,7 +134,23 @@ main(int argc, char *argv[]) int open_flags = O_WRONLY | O_CREAT | O_NOCTTY; int utimensat_flags = 0; +#ifdef HAS_GETOPT_LONG + // Strictly for GNUisms compatibility so no long-only options + // clang-format off + static struct option opts[] = { + {"no-create", no_argument, NULL, 'c'}, + {"date", required_argument, NULL, 'd'}, + {"no-dereference", no_argument, NULL, 'h'}, + {"reference", required_argument, NULL, 'r'}, + {0, 0, 0, 0}, + }; + // clang-format on + + // Need + as first character to get POSIX-style option parsing + for(int c = -1; (c = getopt_long(argc, argv, "+:acfhmr:t:d:", opts, NULL)) != -1;) +#else for(int c = -1; (c = getopt_nolong(argc, argv, ":acfhmr:t:d:")) != -1;) +#endif { const char *errstr = NULL; diff --git a/cmd/tr.c b/cmd/tr.c @@ -32,6 +32,7 @@ #define _DEFAULT_SOURCE +#include "../config.h" #include "../lib/tr_str.h" #include "../libutils/err.h" #include "../libutils/getopt_nolong.h" @@ -42,6 +43,9 @@ #include <strings.h> // bzero #include <sys/types.h> #include <unistd.h> +#ifdef HAS_GETOPT_LONG +#include <getopt.h> +#endif int delete[NCHARS], squeeze[NCHARS]; int translate[NCHARS] = { @@ -78,7 +82,22 @@ main(int argc, char *argv[]) int cflag, dflag, sflag; cflag = dflag = sflag = 0; - for(int c = -1; (c = getopt_nolong(argc, argv, "Ccds")) != -1;) +#ifdef HAS_GETOPT_LONG + // Strictly for GNUisms compatibility so no long-only options + // clang-format off + static struct option opts[] = { + {"complement", no_argument, NULL, 'c'}, + {"delete", no_argument, NULL, 'd'}, + {"squeeze-repeats", no_argument, NULL, 's'}, + {0, 0, 0, 0}, + }; + // clang-format on + + // Need + as first character to get POSIX-style option parsing + for(int c = -1; (c = getopt_long(argc, argv, "+:Ccds", opts, NULL)) != -1;) +#else + for(int c = -1; (c = getopt_nolong(argc, argv, ":Ccds")) != -1;) +#endif { switch(c) { diff --git a/cmd/truncate.c b/cmd/truncate.c @@ -4,6 +4,7 @@ #define _POSIX_C_SOURCE 200809L +#include "../config.h" #include "../lib/bitmasks.h" // FIELD_CLR #include "../libutils/getopt_nolong.h" #include "../libutils/truncation.h" // parse_size @@ -16,6 +17,9 @@ #include <string.h> // strerror #include <sys/stat.h> #include <unistd.h> // getopt +#ifdef HAS_GETOPT_LONG +#include <getopt.h> +#endif const char *argv0 = "truncate"; @@ -37,7 +41,22 @@ main(int argc, char *argv[]) }; char *ref_file = NULL; +#ifdef HAS_GETOPT_LONG + // Strictly for GNUisms compatibility so no long-only options + // clang-format off + static struct option opts[] = { + {"no-create", no_argument, NULL, 'c'}, + {"reference", required_argument, NULL, 'r'}, + {"size", required_argument, NULL, 's'}, + {0, 0, 0, 0}, + }; + // clang-format on + + // Need + as first character to get POSIX-style option parsing + for(int c = -1; (c = getopt_long(argc, argv, "+:cr:s:", opts, NULL)) != -1;) +#else for(int c = -1; (c = getopt_nolong(argc, argv, ":cr:s:")) != -1;) +#endif { switch(c) { diff --git a/cmd/uniq.c b/cmd/uniq.c @@ -3,6 +3,7 @@ // SPDX-License-Identifier: MPL-2.0 #define _POSIX_C_SOURCE 200809L +#include "../config.h" #include "../libutils/getopt_nolong.h" #include <ctype.h> // isblank @@ -12,6 +13,9 @@ #include <stdlib.h> // atoi #include <string.h> // strncmp #include <unistd.h> // getopt +#ifdef HAS_GETOPT_LONG +#include <getopt.h> +#endif enum uniq_mode { @@ -31,7 +35,24 @@ main(int argc, char *argv[]) char *endptr = NULL; +#ifdef HAS_GETOPT_LONG + // Strictly for GNUisms compatibility so no long-only options + // clang-format off + static struct option opts[] = { + {"count", no_argument, NULL, 'c'}, + {"repeated", no_argument, NULL, 'd'}, + {"skip-fields", required_argument, NULL, 'f'}, + {"skip-chars", required_argument, NULL, 's'}, + {"unique", no_argument, NULL, 'u'}, + {0, 0, 0, 0}, + }; + // clang-format on + + // Need + as first character to get POSIX-style option parsing + for(int c = -1; (c = getopt_long(argc, argv, "+:cdf:s:u", opts, NULL)) != -1;) +#else for(int c = -1; (c = getopt_nolong(argc, argv, ":cdf:s:u")) != -1;) +#endif { switch(c) { diff --git a/cmd/which.c b/cmd/which.c @@ -3,6 +3,7 @@ // SPDX-License-Identifier: MPL-2.0 #define _POSIX_C_SOURCE 200809L +#include "../config.h" #include "../libutils/getopt_nolong.h" #include "../libutils/strchrnul.h" @@ -13,6 +14,9 @@ #include <stdlib.h> // getenv #include <string.h> // strcpy, memcpy #include <unistd.h> // access, getopt +#ifdef HAS_GETOPT_LONG +#include <getopt.h> +#endif const char *argv0 = "which"; @@ -29,7 +33,20 @@ main(int argc, char *argv[]) return 1; } +#ifdef HAS_GETOPT_LONG + // Strictly for GNUisms compatibility so no long-only options + // clang-format off + static struct option opts[] = { + {"all", no_argument, NULL, 'a'}, + {0, 0, 0, 0}, + }; + // clang-format on + + // Need + as first character to get POSIX-style option parsing + for(int c = -1; (c = getopt_long(argc, argv, "+as", opts, NULL)) != -1;) +#else for(int c = -1; (c = getopt_nolong(argc, argv, "as")) != -1;) +#endif { switch(c) { diff --git a/test-cmd/rm.t b/test-cmd/rm.t @@ -129,7 +129,7 @@ POSIX, -f shouldn't return an error when no operands are passed $ rm -f $ rm rm: error: missing operand - Usage: rm [-firRv] [files ...] + Usage: rm [-dfirRv] [files ...] [1] POSIX 2024/D4.1, -d diff --git a/test-cmd/tee.sh b/test-cmd/tee.sh @@ -45,5 +45,9 @@ t --exit=1 --input='foo' enoent '/var/empty/e/no/ent' 'tee: error: Failed openin t_file --infile="${WD}/inputs/all_bytes" doubledash "${WD}/inputs/all_bytes" -- -t --exit=1 --input='foo' tripledash '---' "tee: error: Long options unsupported: '---' +if grep -q HAS_GETOPT_LONG "${WD}/../config.h"; then + skip tripledash +else + t --exit=1 --input='foo' tripledash '---' "tee: error: Long options unsupported: '---' " +fi