From 683552c4c9a3dfee4ce603157bb2cf18d64fbcfc Mon Sep 17 00:00:00 2001 From: Tavian Barnes Date: Fri, 30 Dec 2022 14:49:46 -0500 Subject: bfstd: New wrappers for dirname()/basename() --- src/bfstd.c | 45 ++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 40 insertions(+), 5 deletions(-) (limited to 'src/bfstd.c') diff --git a/src/bfstd.c b/src/bfstd.c index 1561796..3a37250 100644 --- a/src/bfstd.c +++ b/src/bfstd.c @@ -45,17 +45,52 @@ bool is_nonexistence_error(int error) { return error == ENOENT || errno == ENOTDIR; } -const char *xbasename(const char *path) { - const char *i; +char *xdirname(const char *path) { + size_t i = xbaseoff(path); // Skip trailing slashes - for (i = path + strlen(path); i > path && i[-1] == '/'; --i); + while (i > 0 && path[i - 1] == '/') { + --i; + } + + if (i > 0) { + return strndup(path, i); + } else if (path[i] == '/') { + return strdup("/"); + } else { + return strdup("."); + } +} + +char *xbasename(const char *path) { + size_t i = xbaseoff(path); + size_t len = strcspn(path + i, "/"); + if (len > 0) { + return strndup(path + i, len); + } else if (path[i] == '/') { + return strdup("/"); + } else { + return strdup("."); + } +} + +size_t xbaseoff(const char *path) { + size_t i = strlen(path); + + // Skip trailing slashes + while (i > 0 && path[i - 1] == '/') { + --i; + } // Find the beginning of the name - for (; i > path && i[-1] != '/'; --i); + while (i > 0 && path[i - 1] != '/') { + --i; + } // Skip leading slashes - for (; i[0] == '/' && i[1]; ++i); + while (path[i] == '/' && path[i + 1]) { + ++i; + } return i; } -- cgit v1.2.3 From 9463fdd30d392c98de7b5712d30dfbaeada40e99 Mon Sep 17 00:00:00 2001 From: Tavian Barnes Date: Wed, 25 Jan 2023 16:14:11 -0500 Subject: Replace license boilerplate with SPDX tags And while I'm at it, remove years from copyright declarations. Link: https://spdx.dev/about/ Link: https://daniel.haxx.se/blog/2023/01/08/copyright-without-years/ --- LICENSE | 33 +++++++++++++++++++++------------ Makefile | 17 ++--------------- completions/bfs.bash | 21 ++++----------------- src/bar.c | 17 ++--------------- src/bar.h | 17 ++--------------- src/bfstd.c | 17 ++--------------- src/bfstd.h | 17 ++--------------- src/bftw.c | 17 ++--------------- src/bftw.h | 17 ++--------------- src/color.c | 17 ++--------------- src/color.h | 17 ++--------------- src/config.h | 17 ++--------------- src/ctx.c | 17 ++--------------- src/ctx.h | 17 ++--------------- src/darray.c | 17 ++--------------- src/darray.h | 17 ++--------------- src/diag.c | 17 ++--------------- src/diag.h | 17 ++--------------- src/dir.c | 17 ++--------------- src/dir.h | 17 ++--------------- src/dstring.c | 17 ++--------------- src/dstring.h | 17 ++--------------- src/eval.c | 17 ++--------------- src/eval.h | 17 ++--------------- src/exec.c | 17 ++--------------- src/exec.h | 17 ++--------------- src/expr.h | 17 ++--------------- src/fsade.c | 17 ++--------------- src/fsade.h | 17 ++--------------- src/main.c | 17 ++--------------- src/mtab.c | 17 ++--------------- src/mtab.h | 17 ++--------------- src/opt.c | 17 ++--------------- src/opt.h | 17 ++--------------- src/parse.c | 17 ++--------------- src/parse.h | 17 ++--------------- src/printf.c | 17 ++--------------- src/printf.h | 17 ++--------------- src/pwcache.c | 17 ++--------------- src/pwcache.h | 17 ++--------------- src/stat.c | 17 ++--------------- src/stat.h | 17 ++--------------- src/trie.c | 17 ++--------------- src/trie.h | 17 ++--------------- src/typo.c | 17 ++--------------- src/typo.h | 17 ++--------------- src/xregex.c | 17 ++--------------- src/xregex.h | 18 ++---------------- src/xspawn.c | 17 ++--------------- src/xspawn.h | 17 ++--------------- src/xtime.c | 17 ++--------------- src/xtime.h | 17 ++--------------- tests/bfstd.c | 17 ++--------------- tests/find-color.sh | 17 ++--------------- tests/ls-color.sh | 17 ++--------------- tests/mksock.c | 17 ++--------------- tests/tests.sh | 17 ++--------------- tests/trie.c | 17 ++--------------- tests/xtimegm.c | 17 ++--------------- tests/xtouch.c | 17 ++--------------- 60 files changed, 141 insertions(+), 900 deletions(-) (limited to 'src/bfstd.c') diff --git a/LICENSE b/LICENSE index 069b145..290e3d3 100644 --- a/LICENSE +++ b/LICENSE @@ -1,12 +1,21 @@ -Copyright (C) 2015-2021 Tavian Barnes - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +Copyright © 2015-2023 Tavian Barnes and the bfs contributors + +Permission to use, copy, modify, and/or distribute this software for any purpose with or +without fee is hereby granted. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO +THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT +SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR +ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION +OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE +USE OR PERFORMANCE OF THIS SOFTWARE. + +--- + +bfs is licensed under the Zero Clause BSD License. Individual files contain the following +tag instead of the full license text: + + SPDX-License-Identifier: 0BSD + +This enables machine processing of license information based on the SPDX License +Identifiers that are available here: https://spdx.org/licenses/ diff --git a/Makefile b/Makefile index b39a88a..0247b47 100644 --- a/Makefile +++ b/Makefile @@ -1,18 +1,5 @@ -############################################################################ -# bfs # -# Copyright (C) 2015-2023 Tavian Barnes # -# # -# Permission to use, copy, modify, and/or distribute this software for any # -# purpose with or without fee is hereby granted. # -# # -# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES # -# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF # -# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR # -# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES # -# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN # -# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF # -# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. # -############################################################################ +# Copyright © Tavian Barnes +# SPDX-License-Identifier: 0BSD ifneq ($(wildcard .git),) VERSION := $(shell git describe --always 2>/dev/null) diff --git a/completions/bfs.bash b/completions/bfs.bash index f734ab1..2f52e8d 100644 --- a/completions/bfs.bash +++ b/completions/bfs.bash @@ -1,21 +1,8 @@ -# bash completion script for bfs +# Copyright © Benjamin Mundt +# Copyright © Tavian Barnes +# SPDX-License-Identifier: 0BSD -############################################################################ -# bfs # -# Copyright (C) 2020 Benjamin Mundt # -# Copyright (C) 2021 Tavian Barnes # -# # -# Permission to use, copy, modify, and/or distribute this software for any # -# purpose with or without fee is hereby granted. # -# # -# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES # -# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF # -# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR # -# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES # -# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN # -# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF # -# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. # -############################################################################ +# bash completion script for bfs _bfs() { local cur prev words cword diff --git a/src/bar.c b/src/bar.c index 37d33c8..bd5d381 100644 --- a/src/bar.c +++ b/src/bar.c @@ -1,18 +1,5 @@ -/**************************************************************************** - * bfs * - * Copyright (C) 2020-2022 Tavian Barnes * - * * - * Permission to use, copy, modify, and/or distribute this software for any * - * purpose with or without fee is hereby granted. * - * * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * - ****************************************************************************/ +// Copyright © Tavian Barnes +// SPDX-License-Identifier: 0BSD #include "bar.h" #include "bfstd.h" diff --git a/src/bar.h b/src/bar.h index 3e509d6..20d92a9 100644 --- a/src/bar.h +++ b/src/bar.h @@ -1,18 +1,5 @@ -/**************************************************************************** - * bfs * - * Copyright (C) 2020 Tavian Barnes * - * * - * Permission to use, copy, modify, and/or distribute this software for any * - * purpose with or without fee is hereby granted. * - * * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * - ****************************************************************************/ +// Copyright © Tavian Barnes +// SPDX-License-Identifier: 0BSD /** * A terminal status bar. diff --git a/src/bfstd.c b/src/bfstd.c index 3a37250..437e9c9 100644 --- a/src/bfstd.c +++ b/src/bfstd.c @@ -1,18 +1,5 @@ -/**************************************************************************** - * bfs * - * Copyright (C) 2016-2022 Tavian Barnes * - * * - * Permission to use, copy, modify, and/or distribute this software for any * - * purpose with or without fee is hereby granted. * - * * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * - ****************************************************************************/ +// Copyright © Tavian Barnes +// SPDX-License-Identifier: 0BSD #include "bfstd.h" #include "config.h" diff --git a/src/bfstd.h b/src/bfstd.h index 79307cc..0e11b66 100644 --- a/src/bfstd.h +++ b/src/bfstd.h @@ -1,18 +1,5 @@ -/**************************************************************************** - * bfs * - * Copyright (C) 2016-2022 Tavian Barnes * - * * - * Permission to use, copy, modify, and/or distribute this software for any * - * purpose with or without fee is hereby granted. * - * * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * - ****************************************************************************/ +// Copyright © Tavian Barnes +// SPDX-License-Identifier: 0BSD /** * Standard library wrappers and polyfills. diff --git a/src/bftw.c b/src/bftw.c index 5f3ebde..9feca79 100644 --- a/src/bftw.c +++ b/src/bftw.c @@ -1,18 +1,5 @@ -/**************************************************************************** - * bfs * - * Copyright (C) 2015-2022 Tavian Barnes * - * * - * Permission to use, copy, modify, and/or distribute this software for any * - * purpose with or without fee is hereby granted. * - * * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * - ****************************************************************************/ +// Copyright © Tavian Barnes +// SPDX-License-Identifier: 0BSD /** * The bftw() implementation consists of the following components: diff --git a/src/bftw.h b/src/bftw.h index c458e1b..77697ed 100644 --- a/src/bftw.h +++ b/src/bftw.h @@ -1,18 +1,5 @@ -/**************************************************************************** - * bfs * - * Copyright (C) 2015-2021 Tavian Barnes * - * * - * Permission to use, copy, modify, and/or distribute this software for any * - * purpose with or without fee is hereby granted. * - * * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * - ****************************************************************************/ +// Copyright © Tavian Barnes +// SPDX-License-Identifier: 0BSD /** * A file-walking API based on nftw(). diff --git a/src/color.c b/src/color.c index 7c16ec5..589e631 100644 --- a/src/color.c +++ b/src/color.c @@ -1,18 +1,5 @@ -/**************************************************************************** - * bfs * - * Copyright (C) 2015-2022 Tavian Barnes * - * * - * Permission to use, copy, modify, and/or distribute this software for any * - * purpose with or without fee is hereby granted. * - * * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * - ****************************************************************************/ +// Copyright © Tavian Barnes +// SPDX-License-Identifier: 0BSD #include "color.h" #include "bfstd.h" diff --git a/src/color.h b/src/color.h index 5b350cc..737c34b 100644 --- a/src/color.h +++ b/src/color.h @@ -1,18 +1,5 @@ -/**************************************************************************** - * bfs * - * Copyright (C) 2015-2021 Tavian Barnes * - * * - * Permission to use, copy, modify, and/or distribute this software for any * - * purpose with or without fee is hereby granted. * - * * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * - ****************************************************************************/ +// Copyright © Tavian Barnes +// SPDX-License-Identifier: 0BSD /** * Utilities for colored output on ANSI terminals. diff --git a/src/config.h b/src/config.h index 810f913..5ae9c82 100644 --- a/src/config.h +++ b/src/config.h @@ -1,18 +1,5 @@ -/**************************************************************************** - * bfs * - * Copyright (C) 2015-2022 Tavian Barnes * - * * - * Permission to use, copy, modify, and/or distribute this software for any * - * purpose with or without fee is hereby granted. * - * * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * - ****************************************************************************/ +// Copyright © Tavian Barnes +// SPDX-License-Identifier: 0BSD /** * Configuration and feature/platform detection. diff --git a/src/ctx.c b/src/ctx.c index 0403299..ff4a2a7 100644 --- a/src/ctx.c +++ b/src/ctx.c @@ -1,18 +1,5 @@ -/**************************************************************************** - * bfs * - * Copyright (C) 2015-2022 Tavian Barnes * - * * - * Permission to use, copy, modify, and/or distribute this software for any * - * purpose with or without fee is hereby granted. * - * * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * - ****************************************************************************/ +// Copyright © Tavian Barnes +// SPDX-License-Identifier: 0BSD #include "ctx.h" #include "color.h" diff --git a/src/ctx.h b/src/ctx.h index 6755d02..4c748b7 100644 --- a/src/ctx.h +++ b/src/ctx.h @@ -1,18 +1,5 @@ -/**************************************************************************** - * bfs * - * Copyright (C) 2015-2022 Tavian Barnes * - * * - * Permission to use, copy, modify, and/or distribute this software for any * - * purpose with or without fee is hereby granted. * - * * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * - ****************************************************************************/ +// Copyright © Tavian Barnes +// SPDX-License-Identifier: 0BSD /** * bfs execution context. diff --git a/src/darray.c b/src/darray.c index 6585d30..42b8397 100644 --- a/src/darray.c +++ b/src/darray.c @@ -1,18 +1,5 @@ -/**************************************************************************** - * bfs * - * Copyright (C) 2019-2022 Tavian Barnes * - * * - * Permission to use, copy, modify, and/or distribute this software for any * - * purpose with or without fee is hereby granted. * - * * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * - ****************************************************************************/ +// Copyright © Tavian Barnes +// SPDX-License-Identifier: 0BSD #include "darray.h" #include diff --git a/src/darray.h b/src/darray.h index 4464381..cc6cc42 100644 --- a/src/darray.h +++ b/src/darray.h @@ -1,18 +1,5 @@ -/**************************************************************************** - * bfs * - * Copyright (C) 2019-2022 Tavian Barnes * - * * - * Permission to use, copy, modify, and/or distribute this software for any * - * purpose with or without fee is hereby granted. * - * * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * - ****************************************************************************/ +// Copyright © Tavian Barnes +// SPDX-License-Identifier: 0BSD /** * A dynamic array library. diff --git a/src/diag.c b/src/diag.c index b02473a..53db98e 100644 --- a/src/diag.c +++ b/src/diag.c @@ -1,18 +1,5 @@ -/**************************************************************************** - * bfs * - * Copyright (C) 2019-2022 Tavian Barnes * - * * - * Permission to use, copy, modify, and/or distribute this software for any * - * purpose with or without fee is hereby granted. * - * * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * - ****************************************************************************/ +// Copyright © Tavian Barnes +// SPDX-License-Identifier: 0BSD #include "diag.h" #include "bfstd.h" diff --git a/src/diag.h b/src/diag.h index 8d0b19f..2952e30 100644 --- a/src/diag.h +++ b/src/diag.h @@ -1,18 +1,5 @@ -/**************************************************************************** - * bfs * - * Copyright (C) 2019-2022 Tavian Barnes * - * * - * Permission to use, copy, modify, and/or distribute this software for any * - * purpose with or without fee is hereby granted. * - * * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * - ****************************************************************************/ +// Copyright © Tavian Barnes +// SPDX-License-Identifier: 0BSD /** * Formatters for diagnostic messages. diff --git a/src/dir.c b/src/dir.c index 2081cc5..3d18eb2 100644 --- a/src/dir.c +++ b/src/dir.c @@ -1,18 +1,5 @@ -/**************************************************************************** - * bfs * - * Copyright (C) 2021-2022 Tavian Barnes * - * * - * Permission to use, copy, modify, and/or distribute this software for any * - * purpose with or without fee is hereby granted. * - * * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * - ****************************************************************************/ +// Copyright © Tavian Barnes +// SPDX-License-Identifier: 0BSD #include "dir.h" #include "bfstd.h" diff --git a/src/dir.h b/src/dir.h index 69344c6..01eaaba 100644 --- a/src/dir.h +++ b/src/dir.h @@ -1,18 +1,5 @@ -/**************************************************************************** - * bfs * - * Copyright (C) 2021 Tavian Barnes * - * * - * Permission to use, copy, modify, and/or distribute this software for any * - * purpose with or without fee is hereby granted. * - * * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * - ****************************************************************************/ +// Copyright © Tavian Barnes +// SPDX-License-Identifier: 0BSD /** * Directories and their contents. diff --git a/src/dstring.c b/src/dstring.c index f344d09..9112e54 100644 --- a/src/dstring.c +++ b/src/dstring.c @@ -1,18 +1,5 @@ -/**************************************************************************** - * bfs * - * Copyright (C) 2016-2022 Tavian Barnes * - * * - * Permission to use, copy, modify, and/or distribute this software for any * - * purpose with or without fee is hereby granted. * - * * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * - ****************************************************************************/ +// Copyright © Tavian Barnes +// SPDX-License-Identifier: 0BSD #include "dstring.h" #include diff --git a/src/dstring.h b/src/dstring.h index df20a04..ee3b345 100644 --- a/src/dstring.h +++ b/src/dstring.h @@ -1,18 +1,5 @@ -/**************************************************************************** - * bfs * - * Copyright (C) 2016-2020 Tavian Barnes * - * * - * Permission to use, copy, modify, and/or distribute this software for any * - * purpose with or without fee is hereby granted. * - * * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * - ****************************************************************************/ +// Copyright © Tavian Barnes +// SPDX-License-Identifier: 0BSD /** * A dynamic string library. diff --git a/src/eval.c b/src/eval.c index d297af1..53ce605 100644 --- a/src/eval.c +++ b/src/eval.c @@ -1,18 +1,5 @@ -/**************************************************************************** - * bfs * - * Copyright (C) 2015-2022 Tavian Barnes * - * * - * Permission to use, copy, modify, and/or distribute this software for any * - * purpose with or without fee is hereby granted. * - * * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * - ****************************************************************************/ +// Copyright © Tavian Barnes +// SPDX-License-Identifier: 0BSD /** * Implementation of all the primary expressions. diff --git a/src/eval.h b/src/eval.h index a50dc4e..3d70319 100644 --- a/src/eval.h +++ b/src/eval.h @@ -1,18 +1,5 @@ -/**************************************************************************** - * bfs * - * Copyright (C) 2015-2022 Tavian Barnes * - * * - * Permission to use, copy, modify, and/or distribute this software for any * - * purpose with or without fee is hereby granted. * - * * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * - ****************************************************************************/ +// Copyright © Tavian Barnes +// SPDX-License-Identifier: 0BSD /** * The evaluation functions that implement primary expressions like -name, diff --git a/src/exec.c b/src/exec.c index 8630469..6bde1c1 100644 --- a/src/exec.c +++ b/src/exec.c @@ -1,18 +1,5 @@ -/**************************************************************************** - * bfs * - * Copyright (C) 2017-2022 Tavian Barnes * - * * - * Permission to use, copy, modify, and/or distribute this software for any * - * purpose with or without fee is hereby granted. * - * * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * - ****************************************************************************/ +// Copyright © Tavian Barnes +// SPDX-License-Identifier: 0BSD #include "exec.h" #include "bfstd.h" diff --git a/src/exec.h b/src/exec.h index a3e3c71..9d4192d 100644 --- a/src/exec.h +++ b/src/exec.h @@ -1,18 +1,5 @@ -/**************************************************************************** - * bfs * - * Copyright (C) 2017-2020 Tavian Barnes * - * * - * Permission to use, copy, modify, and/or distribute this software for any * - * purpose with or without fee is hereby granted. * - * * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * - ****************************************************************************/ +// Copyright © Tavian Barnes +// SPDX-License-Identifier: 0BSD /** * Implementation of -exec/-execdir/-ok/-okdir. diff --git a/src/expr.h b/src/expr.h index a52007a..1628cac 100644 --- a/src/expr.h +++ b/src/expr.h @@ -1,18 +1,5 @@ -/**************************************************************************** - * bfs * - * Copyright (C) 2015-2022 Tavian Barnes * - * * - * Permission to use, copy, modify, and/or distribute this software for any * - * purpose with or without fee is hereby granted. * - * * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * - ****************************************************************************/ +// Copyright © Tavian Barnes +// SPDX-License-Identifier: 0BSD /** * The expression tree representation. diff --git a/src/fsade.c b/src/fsade.c index 45969d1..a61a6b8 100644 --- a/src/fsade.c +++ b/src/fsade.c @@ -1,18 +1,5 @@ -/**************************************************************************** - * bfs * - * Copyright (C) 2019-2021 Tavian Barnes * - * * - * Permission to use, copy, modify, and/or distribute this software for any * - * purpose with or without fee is hereby granted. * - * * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * - ****************************************************************************/ +// Copyright © Tavian Barnes +// SPDX-License-Identifier: 0BSD #include "fsade.h" #include "config.h" diff --git a/src/fsade.h b/src/fsade.h index f45c6fd..9bef892 100644 --- a/src/fsade.h +++ b/src/fsade.h @@ -1,18 +1,5 @@ -/**************************************************************************** - * bfs * - * Copyright (C) 2019-2020 Tavian Barnes * - * * - * Permission to use, copy, modify, and/or distribute this software for any * - * purpose with or without fee is hereby granted. * - * * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * - ****************************************************************************/ +// Copyright © Tavian Barnes +// SPDX-License-Identifier: 0BSD /** * A facade over (file)system features that are (un)implemented differently diff --git a/src/main.c b/src/main.c index fbddbe5..4f99580 100644 --- a/src/main.c +++ b/src/main.c @@ -1,18 +1,5 @@ -/**************************************************************************** - * bfs * - * Copyright (C) 2015-2022 Tavian Barnes * - * * - * Permission to use, copy, modify, and/or distribute this software for any * - * purpose with or without fee is hereby granted. * - * * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * - ****************************************************************************/ +// Copyright © Tavian Barnes +// SPDX-License-Identifier: 0BSD /** * - main(): the entry point for bfs(1), a breadth-first version of find(1) diff --git a/src/mtab.c b/src/mtab.c index 07d7a53..ae6dfd2 100644 --- a/src/mtab.c +++ b/src/mtab.c @@ -1,18 +1,5 @@ -/**************************************************************************** - * bfs * - * Copyright (C) 2017-2020 Tavian Barnes * - * * - * Permission to use, copy, modify, and/or distribute this software for any * - * purpose with or without fee is hereby granted. * - * * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * - ****************************************************************************/ +// Copyright © Tavian Barnes +// SPDX-License-Identifier: 0BSD #include "mtab.h" #include "bfstd.h" diff --git a/src/mtab.h b/src/mtab.h index 807539d..5dfdf6c 100644 --- a/src/mtab.h +++ b/src/mtab.h @@ -1,18 +1,5 @@ -/**************************************************************************** - * bfs * - * Copyright (C) 2017-2020 Tavian Barnes * - * * - * Permission to use, copy, modify, and/or distribute this software for any * - * purpose with or without fee is hereby granted. * - * * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * - ****************************************************************************/ +// Copyright © Tavian Barnes +// SPDX-License-Identifier: 0BSD /** * A facade over platform-specific APIs for enumerating mounted filesystems. diff --git a/src/opt.c b/src/opt.c index e76e216..5505b7b 100644 --- a/src/opt.c +++ b/src/opt.c @@ -1,18 +1,5 @@ -/**************************************************************************** - * bfs * - * Copyright (C) 2017-2022 Tavian Barnes * - * * - * Permission to use, copy, modify, and/or distribute this software for any * - * purpose with or without fee is hereby granted. * - * * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * - ****************************************************************************/ +// Copyright © Tavian Barnes +// SPDX-License-Identifier: 0BSD /** * The expression optimizer. Different optimization levels are supported: diff --git a/src/opt.h b/src/opt.h index 5f8180d..28cadb9 100644 --- a/src/opt.h +++ b/src/opt.h @@ -1,18 +1,5 @@ -/**************************************************************************** - * bfs * - * Copyright (C) 2020 Tavian Barnes * - * * - * Permission to use, copy, modify, and/or distribute this software for any * - * purpose with or without fee is hereby granted. * - * * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * - ****************************************************************************/ +// Copyright © Tavian Barnes +// SPDX-License-Identifier: 0BSD /** * Optimization. diff --git a/src/parse.c b/src/parse.c index f2582e0..30bf56d 100644 --- a/src/parse.c +++ b/src/parse.c @@ -1,18 +1,5 @@ -/**************************************************************************** - * bfs * - * Copyright (C) 2015-2022 Tavian Barnes * - * * - * Permission to use, copy, modify, and/or distribute this software for any * - * purpose with or without fee is hereby granted. * - * * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * - ****************************************************************************/ +// Copyright © Tavian Barnes +// SPDX-License-Identifier: 0BSD /** * The command line parser. Expressions are parsed by recursive descent, with a diff --git a/src/parse.h b/src/parse.h index 7e29a03..6895c9f 100644 --- a/src/parse.h +++ b/src/parse.h @@ -1,18 +1,5 @@ -/**************************************************************************** - * bfs * - * Copyright (C) 2020 Tavian Barnes * - * * - * Permission to use, copy, modify, and/or distribute this software for any * - * purpose with or without fee is hereby granted. * - * * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * - ****************************************************************************/ +// Copyright © Tavian Barnes +// SPDX-License-Identifier: 0BSD /** * bfs command line parsing. diff --git a/src/printf.c b/src/printf.c index 7c0c8db..1b4f2d4 100644 --- a/src/printf.c +++ b/src/printf.c @@ -1,18 +1,5 @@ -/**************************************************************************** - * bfs * - * Copyright (C) 2017-2022 Tavian Barnes * - * * - * Permission to use, copy, modify, and/or distribute this software for any * - * purpose with or without fee is hereby granted. * - * * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * - ****************************************************************************/ +// Copyright © Tavian Barnes +// SPDX-License-Identifier: 0BSD #include "printf.h" #include "bfstd.h" diff --git a/src/printf.h b/src/printf.h index a8c5f2a..2bff087 100644 --- a/src/printf.h +++ b/src/printf.h @@ -1,18 +1,5 @@ -/**************************************************************************** - * bfs * - * Copyright (C) 2017-2022 Tavian Barnes * - * * - * Permission to use, copy, modify, and/or distribute this software for any * - * purpose with or without fee is hereby granted. * - * * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * - ****************************************************************************/ +// Copyright © Tavian Barnes +// SPDX-License-Identifier: 0BSD /** * Implementation of -printf/-fprintf. diff --git a/src/pwcache.c b/src/pwcache.c index 868ec8f..5026dee 100644 --- a/src/pwcache.c +++ b/src/pwcache.c @@ -1,18 +1,5 @@ -/**************************************************************************** - * bfs * - * Copyright (C) 2020-2022 Tavian Barnes * - * * - * Permission to use, copy, modify, and/or distribute this software for any * - * purpose with or without fee is hereby granted. * - * * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * - ****************************************************************************/ +// Copyright © Tavian Barnes +// SPDX-License-Identifier: 0BSD #include "pwcache.h" #include "darray.h" diff --git a/src/pwcache.h b/src/pwcache.h index f1ca0bf..b6c0b67 100644 --- a/src/pwcache.h +++ b/src/pwcache.h @@ -1,18 +1,5 @@ -/**************************************************************************** - * bfs * - * Copyright (C) 2020 Tavian Barnes * - * * - * Permission to use, copy, modify, and/or distribute this software for any * - * purpose with or without fee is hereby granted. * - * * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * - ****************************************************************************/ +// Copyright © Tavian Barnes +// SPDX-License-Identifier: 0BSD /** * A caching wrapper for /etc/{passwd,group}. diff --git a/src/stat.c b/src/stat.c index 94dedef..aaa5eac 100644 --- a/src/stat.c +++ b/src/stat.c @@ -1,18 +1,5 @@ -/**************************************************************************** - * bfs * - * Copyright (C) 2018-2022 Tavian Barnes * - * * - * Permission to use, copy, modify, and/or distribute this software for any * - * purpose with or without fee is hereby granted. * - * * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * - ****************************************************************************/ +// Copyright © Tavian Barnes +// SPDX-License-Identifier: 0BSD #include "stat.h" #include "bfstd.h" diff --git a/src/stat.h b/src/stat.h index 44cbfad..7a70146 100644 --- a/src/stat.h +++ b/src/stat.h @@ -1,18 +1,5 @@ -/**************************************************************************** - * bfs * - * Copyright (C) 2018-2019 Tavian Barnes * - * * - * Permission to use, copy, modify, and/or distribute this software for any * - * purpose with or without fee is hereby granted. * - * * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * - ****************************************************************************/ +// Copyright © Tavian Barnes +// SPDX-License-Identifier: 0BSD /** * A facade over the stat() API that unifies some details that diverge between diff --git a/src/trie.c b/src/trie.c index 08a99b5..77c43cc 100644 --- a/src/trie.c +++ b/src/trie.c @@ -1,18 +1,5 @@ -/**************************************************************************** - * bfs * - * Copyright (C) 2019-2022 Tavian Barnes * - * * - * Permission to use, copy, modify, and/or distribute this software for any * - * purpose with or without fee is hereby granted. * - * * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * - ****************************************************************************/ +// Copyright © Tavian Barnes +// SPDX-License-Identifier: 0BSD /** * This is an implementation of a "qp trie," as documented at diff --git a/src/trie.h b/src/trie.h index 2ede6ea..03ee64d 100644 --- a/src/trie.h +++ b/src/trie.h @@ -1,18 +1,5 @@ -/**************************************************************************** - * bfs * - * Copyright (C) 2019-2022 Tavian Barnes * - * * - * Permission to use, copy, modify, and/or distribute this software for any * - * purpose with or without fee is hereby granted. * - * * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * - ****************************************************************************/ +// Copyright © Tavian Barnes +// SPDX-License-Identifier: 0BSD #ifndef BFS_TRIE_H #define BFS_TRIE_H diff --git a/src/typo.c b/src/typo.c index c16cab4..305711d 100644 --- a/src/typo.c +++ b/src/typo.c @@ -1,18 +1,5 @@ -/**************************************************************************** - * bfs * - * Copyright (C) 2016 Tavian Barnes * - * * - * Permission to use, copy, modify, and/or distribute this software for any * - * purpose with or without fee is hereby granted. * - * * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * - ****************************************************************************/ +// Copyright © Tavian Barnes +// SPDX-License-Identifier: 0BSD #include "typo.h" #include diff --git a/src/typo.h b/src/typo.h index 0347aae..13eaa67 100644 --- a/src/typo.h +++ b/src/typo.h @@ -1,18 +1,5 @@ -/**************************************************************************** - * bfs * - * Copyright (C) 2016 Tavian Barnes * - * * - * Permission to use, copy, modify, and/or distribute this software for any * - * purpose with or without fee is hereby granted. * - * * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * - ****************************************************************************/ +// Copyright © Tavian Barnes +// SPDX-License-Identifier: 0BSD #ifndef BFS_TYPO_H #define BFS_TYPO_H diff --git a/src/xregex.c b/src/xregex.c index 6f0e5a1..5f5480f 100644 --- a/src/xregex.c +++ b/src/xregex.c @@ -1,18 +1,5 @@ -/**************************************************************************** - * bfs * - * Copyright (C) 2022 Tavian Barnes * - * * - * Permission to use, copy, modify, and/or distribute this software for any * - * purpose with or without fee is hereby granted. * - * * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * - ****************************************************************************/ +// Copyright © Tavian Barnes +// SPDX-License-Identifier: 0BSD #include "xregex.h" #include "config.h" diff --git a/src/xregex.h b/src/xregex.h index b2f56a5..998a2b0 100644 --- a/src/xregex.h +++ b/src/xregex.h @@ -1,19 +1,5 @@ -/**************************************************************************** - * bfs * - * Copyright (C) 2022 Tavian Barnes and bfs * - * contributors * - * * - * Permission to use, copy, modify, and/or distribute this software for any * - * purpose with or without fee is hereby granted. * - * * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * - ****************************************************************************/ +// Copyright © Tavian Barnes and the bfs contributors +// SPDX-License-Identifier: 0BSD #ifndef BFS_XREGEX_H #define BFS_XREGEX_H diff --git a/src/xspawn.c b/src/xspawn.c index f76267b..a30c264 100644 --- a/src/xspawn.c +++ b/src/xspawn.c @@ -1,18 +1,5 @@ -/**************************************************************************** - * bfs * - * Copyright (C) 2018-2022 Tavian Barnes * - * * - * Permission to use, copy, modify, and/or distribute this software for any * - * purpose with or without fee is hereby granted. * - * * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * - ****************************************************************************/ +// Copyright © Tavian Barnes +// SPDX-License-Identifier: 0BSD #include "xspawn.h" #include "bfstd.h" diff --git a/src/xspawn.h b/src/xspawn.h index cd6a42e..3dbf5d2 100644 --- a/src/xspawn.h +++ b/src/xspawn.h @@ -1,18 +1,5 @@ -/**************************************************************************** - * bfs * - * Copyright (C) 2018-2022 Tavian Barnes * - * * - * Permission to use, copy, modify, and/or distribute this software for any * - * purpose with or without fee is hereby granted. * - * * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * - ****************************************************************************/ +// Copyright © Tavian Barnes +// SPDX-License-Identifier: 0BSD /** * A process-spawning library inspired by posix_spawn(). diff --git a/src/xtime.c b/src/xtime.c index 079d42a..82690d0 100644 --- a/src/xtime.c +++ b/src/xtime.c @@ -1,18 +1,5 @@ -/**************************************************************************** - * bfs * - * Copyright (C) 2020-2022 Tavian Barnes * - * * - * Permission to use, copy, modify, and/or distribute this software for any * - * purpose with or without fee is hereby granted. * - * * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * - ****************************************************************************/ +// Copyright © Tavian Barnes +// SPDX-License-Identifier: 0BSD #include "xtime.h" #include diff --git a/src/xtime.h b/src/xtime.h index b49cd04..75d1f4e 100644 --- a/src/xtime.h +++ b/src/xtime.h @@ -1,18 +1,5 @@ -/**************************************************************************** - * bfs * - * Copyright (C) 2020-2022 Tavian Barnes * - * * - * Permission to use, copy, modify, and/or distribute this software for any * - * purpose with or without fee is hereby granted. * - * * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * - ****************************************************************************/ +// Copyright © Tavian Barnes +// SPDX-License-Identifier: 0BSD /** * Date/time handling. diff --git a/tests/bfstd.c b/tests/bfstd.c index 4a8181b..8c61072 100644 --- a/tests/bfstd.c +++ b/tests/bfstd.c @@ -1,18 +1,5 @@ -/**************************************************************************** - * bfs * - * Copyright (C) 2022 Tavian Barnes * - * * - * Permission to use, copy, modify, and/or distribute this software for any * - * purpose with or without fee is hereby granted. * - * * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * - ****************************************************************************/ +// Copyright © Tavian Barnes +// SPDX-License-Identifier: 0BSD #include "../src/bfstd.h" #include diff --git a/tests/find-color.sh b/tests/find-color.sh index ecdd5af..47de2a2 100755 --- a/tests/find-color.sh +++ b/tests/find-color.sh @@ -1,20 +1,7 @@ #!/usr/bin/env bash -############################################################################ -# bfs # -# Copyright (C) 2019 Tavian Barnes # -# # -# Permission to use, copy, modify, and/or distribute this software for any # -# purpose with or without fee is hereby granted. # -# # -# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES # -# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF # -# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR # -# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES # -# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN # -# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF # -# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. # -############################################################################ +# Copyright © Tavian Barnes +# SPDX-License-Identifier: 0BSD set -e diff --git a/tests/ls-color.sh b/tests/ls-color.sh index c82a58d..6d33f53 100755 --- a/tests/ls-color.sh +++ b/tests/ls-color.sh @@ -1,20 +1,7 @@ #!/usr/bin/env bash -############################################################################ -# bfs # -# Copyright (C) 2019 Tavian Barnes # -# # -# Permission to use, copy, modify, and/or distribute this software for any # -# purpose with or without fee is hereby granted. # -# # -# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES # -# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF # -# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR # -# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES # -# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN # -# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF # -# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. # -############################################################################ +# Copyright © Tavian Barnes +# SPDX-License-Identifier: 0BSD # Prints the "ground truth" coloring of a path using ls diff --git a/tests/mksock.c b/tests/mksock.c index 5068bc8..05edbeb 100644 --- a/tests/mksock.c +++ b/tests/mksock.c @@ -1,18 +1,5 @@ -/**************************************************************************** - * bfs * - * Copyright (C) 2019 Tavian Barnes * - * * - * Permission to use, copy, modify, and/or distribute this software for any * - * purpose with or without fee is hereby granted. * - * * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * - ****************************************************************************/ +// Copyright © Tavian Barnes +// SPDX-License-Identifier: 0BSD /** * There's no standard Unix utility that creates a socket file, so this small diff --git a/tests/tests.sh b/tests/tests.sh index e57db4e..98d332c 100755 --- a/tests/tests.sh +++ b/tests/tests.sh @@ -1,20 +1,7 @@ #!/usr/bin/env bash -############################################################################ -# bfs # -# Copyright (C) 2015-2022 Tavian Barnes # -# # -# Permission to use, copy, modify, and/or distribute this software for any # -# purpose with or without fee is hereby granted. # -# # -# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES # -# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF # -# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR # -# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES # -# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN # -# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF # -# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. # -############################################################################ +# Copyright © Tavian Barnes +# SPDX-License-Identifier: 0BSD set -euP umask 022 diff --git a/tests/trie.c b/tests/trie.c index 88e92da..c2af18a 100644 --- a/tests/trie.c +++ b/tests/trie.c @@ -1,18 +1,5 @@ -/**************************************************************************** - * bfs * - * Copyright (C) 2020-2022 Tavian Barnes * - * * - * Permission to use, copy, modify, and/or distribute this software for any * - * purpose with or without fee is hereby granted. * - * * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * - ****************************************************************************/ +// Copyright © Tavian Barnes +// SPDX-License-Identifier: 0BSD #undef NDEBUG diff --git a/tests/xtimegm.c b/tests/xtimegm.c index d774b9e..bab64ba 100644 --- a/tests/xtimegm.c +++ b/tests/xtimegm.c @@ -1,18 +1,5 @@ -/**************************************************************************** - * bfs * - * Copyright (C) 2020 Tavian Barnes * - * * - * Permission to use, copy, modify, and/or distribute this software for any * - * purpose with or without fee is hereby granted. * - * * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * - ****************************************************************************/ +// Copyright © Tavian Barnes +// SPDX-License-Identifier: 0BSD #include "../src/xtime.h" #include diff --git a/tests/xtouch.c b/tests/xtouch.c index 9a91ec7..506c73d 100644 --- a/tests/xtouch.c +++ b/tests/xtouch.c @@ -1,18 +1,5 @@ -/**************************************************************************** - * bfs * - * Copyright (C) 2022 Tavian Barnes * - * * - * Permission to use, copy, modify, and/or distribute this software for any * - * purpose with or without fee is hereby granted. * - * * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * - ****************************************************************************/ +// Copyright © Tavian Barnes +// SPDX-License-Identifier: 0BSD #include "../src/bfstd.h" #include "../src/xtime.h" -- cgit v1.2.3 From 520c8302187538c3c9adab822d7268cbb22565e7 Mon Sep 17 00:00:00 2001 From: Tavian Barnes Date: Fri, 7 Apr 2023 13:06:08 -0400 Subject: bfstd: Fix declaration order to match the right standard headers --- src/bfstd.c | 148 ++++++++++++++++++++++++++++++------------------------------ src/bfstd.h | 84 +++++++++++++++++----------------- 2 files changed, 116 insertions(+), 116 deletions(-) (limited to 'src/bfstd.c') diff --git a/src/bfstd.c b/src/bfstd.c index 437e9c9..bc31288 100644 --- a/src/bfstd.c +++ b/src/bfstd.c @@ -82,20 +82,6 @@ size_t xbaseoff(const char *path) { return i; } -void close_quietly(int fd) { - int error = errno; - xclose(fd); - errno = error; -} - -int xclose(int fd) { - int ret = close(fd); - if (ret != 0) { - assert(errno != EBADF); - } - return ret; -} - FILE *xfopen(const char *path, int flags) { char mode[4]; @@ -157,52 +143,6 @@ char *xgetdelim(FILE *file, char delim) { } } -size_t xread(int fd, void *buf, size_t nbytes) { - size_t count = 0; - - while (count < nbytes) { - ssize_t ret = read(fd, (char *)buf + count, nbytes - count); - if (ret < 0) { - if (errno == EINTR) { - continue; - } else { - break; - } - } else if (ret == 0) { - // EOF - errno = 0; - break; - } else { - count += ret; - } - } - - return count; -} - -size_t xwrite(int fd, const void *buf, size_t nbytes) { - size_t count = 0; - - while (count < nbytes) { - ssize_t ret = write(fd, (const char *)buf + count, nbytes - count); - if (ret < 0) { - if (errno == EINTR) { - continue; - } else { - break; - } - } else if (ret == 0) { - // EOF? - errno = 0; - break; - } else { - count += ret; - } - } - - return count; -} - /** Compile and execute a regular expression for xrpmatch(). */ static int xrpregex(nl_item item, const char *response) { const char *pattern = nl_langinfo(item); @@ -398,6 +338,80 @@ int pipe_cloexec(int pipefd[2]) { #endif } +size_t xread(int fd, void *buf, size_t nbytes) { + size_t count = 0; + + while (count < nbytes) { + ssize_t ret = read(fd, (char *)buf + count, nbytes - count); + if (ret < 0) { + if (errno == EINTR) { + continue; + } else { + break; + } + } else if (ret == 0) { + // EOF + errno = 0; + break; + } else { + count += ret; + } + } + + return count; +} + +size_t xwrite(int fd, const void *buf, size_t nbytes) { + size_t count = 0; + + while (count < nbytes) { + ssize_t ret = write(fd, (const char *)buf + count, nbytes - count); + if (ret < 0) { + if (errno == EINTR) { + continue; + } else { + break; + } + } else if (ret == 0) { + // EOF? + errno = 0; + break; + } else { + count += ret; + } + } + + return count; +} + +void close_quietly(int fd) { + int error = errno; + xclose(fd); + errno = error; +} + +int xclose(int fd) { + int ret = close(fd); + if (ret != 0) { + assert(errno != EBADF); + } + return ret; +} + +int xfaccessat(int fd, const char *path, int amode) { + int ret = faccessat(fd, path, amode, 0); + +#ifdef AT_EACCESS + // Some platforms, like Hurd, only support AT_EACCESS. Other platforms, + // like Android, don't support AT_EACCESS at all. + if (ret != 0 && (errno == EINVAL || errno == ENOTSUP)) { + ret = faccessat(fd, path, amode, AT_EACCESS); + } +#endif + + return ret; +} + char *xconfstr(int name) { #if __ANDROID__ errno = ENOTSUP; @@ -422,20 +436,6 @@ char *xconfstr(int name) { #endif // !__ANDROID__ } -int xfaccessat(int fd, const char *path, int amode) { - int ret = faccessat(fd, path, amode, 0); - -#ifdef AT_EACCESS - // Some platforms, like Hurd, only support AT_EACCESS. Other platforms, - // like Android, don't support AT_EACCESS at all. - if (ret != 0 && (errno == EINVAL || errno == ENOTSUP)) { - ret = faccessat(fd, path, amode, AT_EACCESS); - } -#endif - - return ret; -} - char *xreadlinkat(int fd, const char *path, size_t size) { ssize_t len; char *name = NULL; diff --git a/src/bfstd.h b/src/bfstd.h index 0e11b66..f85b74f 100644 --- a/src/bfstd.h +++ b/src/bfstd.h @@ -80,24 +80,6 @@ size_t xbaseoff(const char *path); #include -/** - * close() variant that preserves errno. - * - * @param fd - * The file descriptor to close. - */ -void close_quietly(int fd); - -/** - * close() wrapper that asserts the file descriptor is valid. - * - * @param fd - * The file descriptor to close. - * @return - * 0 on success, or -1 on error. - */ -int xclose(int fd); - /** * fopen() variant that takes open() style flags. * @@ -121,25 +103,6 @@ FILE *xfopen(const char *path, int flags); */ char *xgetdelim(FILE *file, char delim); -/** - * A safe version of read() that handles interrupted system calls and partial - * reads. - * - * @return - * The number of bytes read. A value != nbytes indicates an error - * (errno != 0) or end of file (errno == 0). - */ -size_t xread(int fd, void *buf, size_t nbytes); - -/** - * A safe version of write() that handles interrupted system calls and partial - * writes. - * - * @return - The number of bytes written. A value != nbytes indicates an error. - */ -size_t xwrite(int fd, const void *buf, size_t nbytes); - // #include /** @@ -210,14 +173,41 @@ int dup_cloexec(int fd); int pipe_cloexec(int pipefd[2]); /** - * Wrapper for confstr() that allocates with malloc(). + * A safe version of read() that handles interrupted system calls and partial + * reads. * - * @param name - * The ID of the confstr to look up. * @return - * The value of the confstr, or NULL on failure. + * The number of bytes read. A value != nbytes indicates an error + * (errno != 0) or end of file (errno == 0). */ -char *xconfstr(int name); +size_t xread(int fd, void *buf, size_t nbytes); + +/** + * A safe version of write() that handles interrupted system calls and partial + * writes. + * + * @return + The number of bytes written. A value != nbytes indicates an error. + */ +size_t xwrite(int fd, const void *buf, size_t nbytes); + +/** + * close() variant that preserves errno. + * + * @param fd + * The file descriptor to close. + */ +void close_quietly(int fd); + +/** + * close() wrapper that asserts the file descriptor is valid. + * + * @param fd + * The file descriptor to close. + * @return + * 0 on success, or -1 on error. + */ +int xclose(int fd); /** * Wrapper for faccessat() that handles some portability issues. @@ -238,6 +228,16 @@ int xfaccessat(int fd, const char *path, int amode); */ char *xreadlinkat(int fd, const char *path, size_t size); +/** + * Wrapper for confstr() that allocates with malloc(). + * + * @param name + * The ID of the confstr to look up. + * @return + * The value of the confstr, or NULL on failure. + */ +char *xconfstr(int name); + /** * Portability wrapper for strtofflags(). * -- cgit v1.2.3 From 7e5357a1cf40ebaa7ffaeebfd3a88c3ba93eb1a7 Mon Sep 17 00:00:00 2001 From: Tavian Barnes Date: Wed, 3 May 2023 09:29:19 -0400 Subject: style: Don't use tabs to indent preprocessor directives --- src/bfstd.c | 6 ++--- src/bfstd.h | 32 +++++++++++------------ src/config.h | 84 ++++++++++++++++++++++++++++++------------------------------ src/dir.c | 20 +++++++-------- src/eval.c | 22 ++++++++-------- src/fsade.c | 8 +++--- src/fsade.h | 8 +++--- src/mtab.c | 20 +++++++-------- src/printf.c | 8 +++--- src/stat.c | 10 ++++---- src/stat.h | 8 +++--- src/trie.c | 30 +++++++++++----------- src/xregex.c | 28 ++++++++++---------- src/xspawn.c | 2 +- 14 files changed, 143 insertions(+), 143 deletions(-) (limited to 'src/bfstd.c') diff --git a/src/bfstd.c b/src/bfstd.c index bc31288..1dc322b 100644 --- a/src/bfstd.c +++ b/src/bfstd.c @@ -19,13 +19,13 @@ #include #if BFS_USE_SYS_SYSMACROS_H -# include +# include #elif BFS_USE_SYS_MKDEV_H -# include +# include #endif #if BFS_USE_UTIL_H -# include +# include #endif bool is_nonexistence_error(int error) { diff --git a/src/bfstd.h b/src/bfstd.h index f85b74f..028e4e6 100644 --- a/src/bfstd.h +++ b/src/bfstd.h @@ -21,29 +21,29 @@ bool is_nonexistence_error(int error); #include #ifndef O_EXEC -# ifdef O_PATH -# define O_EXEC O_PATH -# else -# define O_EXEC O_RDONLY -# endif +# ifdef O_PATH +# define O_EXEC O_PATH +# else +# define O_EXEC O_RDONLY +# endif #endif #ifndef O_SEARCH -# ifdef O_PATH -# define O_SEARCH O_PATH -# else -# define O_SEARCH O_RDONLY -# endif +# ifdef O_PATH +# define O_SEARCH O_PATH +# else +# define O_SEARCH O_RDONLY +# endif #endif #ifndef O_DIRECTORY -# define O_DIRECTORY 0 +# define O_DIRECTORY 0 #endif #include #if !defined(FNM_CASEFOLD) && defined(FNM_IGNORECASE) -# define FNM_CASEFOLD FNM_IGNORECASE +# define FNM_CASEFOLD FNM_IGNORECASE #endif // #include @@ -144,10 +144,10 @@ int xminor(dev_t dev); // #include #if __APPLE__ -# define st_atim st_atimespec -# define st_ctim st_ctimespec -# define st_mtim st_mtimespec -# define st_birthtim st_birthtimespec +# define st_atim st_atimespec +# define st_ctim st_ctimespec +# define st_mtim st_mtimespec +# define st_birthtim st_birthtimespec #endif // #include diff --git a/src/config.h b/src/config.h index 34ae11d..5f54250 100644 --- a/src/config.h +++ b/src/config.h @@ -14,13 +14,13 @@ // bfs packaging configuration #ifndef BFS_COMMAND -# define BFS_COMMAND "bfs" +# define BFS_COMMAND "bfs" #endif #ifndef BFS_VERSION -# define BFS_VERSION "2.6.3" +# define BFS_VERSION "2.6.3" #endif #ifndef BFS_HOMEPAGE -# define BFS_HOMEPAGE "https://tavianator.com/projects/bfs.html" +# define BFS_HOMEPAGE "https://tavianator.com/projects/bfs.html" #endif // Check for system headers @@ -28,34 +28,34 @@ #ifdef __has_include #if __has_include() -# define BFS_HAS_MNTENT_H true +# define BFS_HAS_MNTENT_H true #endif #if __has_include() -# define BFS_HAS_PATHS_H true +# define BFS_HAS_PATHS_H true #endif #if __has_include() -# define BFS_HAS_SYS_ACL_H true +# define BFS_HAS_SYS_ACL_H true #endif #if __has_include() -# define BFS_HAS_SYS_CAPABILITY_H true +# define BFS_HAS_SYS_CAPABILITY_H true #endif #if __has_include() -# define BFS_HAS_SYS_EXTATTR_H true +# define BFS_HAS_SYS_EXTATTR_H true #endif #if __has_include() -# define BFS_HAS_SYS_MKDEV_H true +# define BFS_HAS_SYS_MKDEV_H true #endif #if __has_include() -# define BFS_HAS_SYS_PARAM_H true +# define BFS_HAS_SYS_PARAM_H true #endif #if __has_include() -# define BFS_HAS_SYS_SYSMACROS_H true +# define BFS_HAS_SYS_SYSMACROS_H true #endif #if __has_include() -# define BFS_HAS_SYS_XATTR_H true +# define BFS_HAS_SYS_XATTR_H true #endif #if __has_include() -# define BFS_HAS_UTIL_H true +# define BFS_HAS_UTIL_H true #endif #else // !__has_include @@ -74,59 +74,59 @@ #endif // !__has_include #ifndef BFS_USE_MNTENT_H -# define BFS_USE_MNTENT_H BFS_HAS_MNTENT_H +# define BFS_USE_MNTENT_H BFS_HAS_MNTENT_H #endif #ifndef BFS_USE_PATHS_H -# define BFS_USE_PATHS_H BFS_HAS_PATHS_H +# define BFS_USE_PATHS_H BFS_HAS_PATHS_H #endif #ifndef BFS_USE_SYS_ACL_H -# define BFS_USE_SYS_ACL_H BFS_HAS_SYS_ACL_H +# define BFS_USE_SYS_ACL_H BFS_HAS_SYS_ACL_H #endif #ifndef BFS_USE_SYS_CAPABILITY_H -# define BFS_USE_SYS_CAPABILITY_H BFS_HAS_SYS_CAPABILITY_H +# define BFS_USE_SYS_CAPABILITY_H BFS_HAS_SYS_CAPABILITY_H #endif #ifndef BFS_USE_SYS_EXTATTR_H -# define BFS_USE_SYS_EXTATTR_H BFS_HAS_SYS_EXTATTR_H +# define BFS_USE_SYS_EXTATTR_H BFS_HAS_SYS_EXTATTR_H #endif #ifndef BFS_USE_SYS_MKDEV_H -# define BFS_USE_SYS_MKDEV_H BFS_HAS_SYS_MKDEV_H +# define BFS_USE_SYS_MKDEV_H BFS_HAS_SYS_MKDEV_H #endif #ifndef BFS_USE_SYS_PARAM_H -# define BFS_USE_SYS_PARAM_H BFS_HAS_SYS_PARAM_H +# define BFS_USE_SYS_PARAM_H BFS_HAS_SYS_PARAM_H #endif #ifndef BFS_USE_SYS_SYSMACROS_H -# define BFS_USE_SYS_SYSMACROS_H BFS_HAS_SYS_SYSMACROS_H +# define BFS_USE_SYS_SYSMACROS_H BFS_HAS_SYS_SYSMACROS_H #endif #ifndef BFS_USE_SYS_XATTR_H -# define BFS_USE_SYS_XATTR_H BFS_HAS_SYS_XATTR_H +# define BFS_USE_SYS_XATTR_H BFS_HAS_SYS_XATTR_H #endif #ifndef BFS_USE_UTIL_H -# define BFS_USE_UTIL_H BFS_HAS_UTIL_H +# define BFS_USE_UTIL_H BFS_HAS_UTIL_H #endif // Stub out feature detection on old/incompatible compilers #ifndef __has_feature -# define __has_feature(feat) false +# define __has_feature(feat) false #endif #ifndef __has_c_attribute -# define __has_c_attribute(attr) false +# define __has_c_attribute(attr) false #endif #ifndef __has_attribute -# define __has_attribute(attr) false +# define __has_attribute(attr) false #endif // Platform detection // Get the definition of BSD if available #if BFS_USE_SYS_PARAM_H -# include +# include #endif #ifndef __GLIBC_PREREQ -# define __GLIBC_PREREQ(maj, min) false +# define __GLIBC_PREREQ(maj, min) false #endif // Wrappers for fundamental language features/extensions @@ -135,11 +135,11 @@ * Silence compiler warnings about switch/case fall-throughs. */ #if __has_c_attribute(fallthrough) -# define BFS_FALLTHROUGH [[fallthrough]] +# define BFS_FALLTHROUGH [[fallthrough]] #elif __has_attribute(fallthrough) -# define BFS_FALLTHROUGH __attribute__((fallthrough)) +# define BFS_FALLTHROUGH __attribute__((fallthrough)) #else -# define BFS_FALLTHROUGH ((void)0) +# define BFS_FALLTHROUGH ((void)0) #endif /** @@ -173,40 +173,40 @@ * Adds compiler warnings for bad printf()-style function calls, if supported. */ #if __has_attribute(format) -# define BFS_FORMATTER(fmt, args) __attribute__((format(printf, fmt, args))) +# define BFS_FORMATTER(fmt, args) __attribute__((format(printf, fmt, args))) #else -# define BFS_FORMATTER(fmt, args) +# define BFS_FORMATTER(fmt, args) #endif /** * Check if function multiversioning via GNU indirect functions (ifunc) is supported. */ #if !defined(BFS_TARGET_CLONES) && __has_attribute(target_clones) && (__GLIBC__ || __FreeBSD__ || __NetBSD__) -# define BFS_TARGET_CLONES true +# define BFS_TARGET_CLONES true #endif /** * Ignore a particular GCC warning for a region of code. */ #if __GNUC__ -# define BFS_PRAGMA_STRINGIFY(...) _Pragma(#__VA_ARGS__) -# define BFS_SUPPRESS(warning) \ - _Pragma("GCC diagnostic push"); \ +# define BFS_PRAGMA_STRINGIFY(...) _Pragma(#__VA_ARGS__) +# define BFS_SUPPRESS(warning) \ + _Pragma("GCC diagnostic push"); \ BFS_PRAGMA_STRINGIFY(GCC diagnostic ignored warning) -# define BFS_UNSUPPRESS() \ +# define BFS_UNSUPPRESS() \ _Pragma("GCC diagnostic pop") #else -# define BFS_SUPPRESS(warning) -# define BFS_UNSUPPRESS() +# define BFS_SUPPRESS(warning) +# define BFS_UNSUPPRESS() #endif /** * Initialize a variable, unless sanitizers would detect uninitialized uses. */ #if __has_feature(memory_sanitizer) -# define BFS_UNINIT(var, value) var = var +# define BFS_UNINIT(var, value) var = var #else -# define BFS_UNINIT(var, value) var = value +# define BFS_UNINIT(var, value) var = value #endif #endif // BFS_CONFIG_H diff --git a/src/dir.c b/src/dir.c index 2719c15..eb6e3e0 100644 --- a/src/dir.c +++ b/src/dir.c @@ -16,16 +16,16 @@ #include #ifndef BFS_GETDENTS -# define BFS_GETDENTS (__linux__ || __FreeBSD__) +# define BFS_GETDENTS (__linux__ || __FreeBSD__) #endif #if BFS_GETDENTS -# if __has_feature(memory_sanitizer) -# include -# endif -# if __linux__ -# include -# endif +# if __has_feature(memory_sanitizer) +# include +# endif +# if __linux__ +# include +# endif /** getdents() syscall wrapper. */ static ssize_t bfs_getdents(int fd, void *buf, size_t size) { @@ -119,10 +119,10 @@ struct bfs_dir { }; #if BFS_GETDENTS -# define DIR_SIZE (64 << 10) -# define BUF_SIZE (DIR_SIZE - sizeof(struct bfs_dir)) +# define DIR_SIZE (64 << 10) +# define BUF_SIZE (DIR_SIZE - sizeof(struct bfs_dir)) #else -# define DIR_SIZE sizeof(struct bfs_dir) +# define DIR_SIZE sizeof(struct bfs_dir) #endif struct bfs_dir *bfs_opendir(int at_fd, const char *at_path) { diff --git a/src/eval.c b/src/eval.c index 53ce605..687ba32 100644 --- a/src/eval.c +++ b/src/eval.c @@ -943,9 +943,9 @@ bool eval_xtype(const struct bfs_expr *expr, struct bfs_eval *state) { } #if _POSIX_MONOTONIC_CLOCK > 0 -# define BFS_CLOCK CLOCK_MONOTONIC +# define BFS_CLOCK CLOCK_MONOTONIC #elif _POSIX_TIMERS > 0 -# define BFS_CLOCK CLOCK_REALTIME +# define BFS_CLOCK CLOCK_REALTIME #endif /** @@ -1194,15 +1194,15 @@ static bool eval_file_unique(struct bfs_eval *state, struct trie *seen) { } } -#define DEBUG_FLAG(flags, flag) \ - do { \ - if ((flags & flag) || flags == flag) { \ - fputs(#flag, stderr); \ - flags ^= flag; \ - if (flags) { \ - fputs(" | ", stderr); \ - } \ - } \ +#define DEBUG_FLAG(flags, flag) \ + do { \ + if ((flags & flag) || flags == flag) { \ + fputs(#flag, stderr); \ + flags ^= flag; \ + if (flags) { \ + fputs(" | ", stderr); \ + } \ + } \ } while (0) /** diff --git a/src/fsade.c b/src/fsade.c index a61a6b8..aefbb75 100644 --- a/src/fsade.c +++ b/src/fsade.c @@ -13,17 +13,17 @@ #include #if BFS_CAN_CHECK_ACL -# include +# include #endif #if BFS_CAN_CHECK_CAPABILITIES -# include +# include #endif #if BFS_USE_SYS_EXTATTR_H -# include +# include #elif BFS_USE_SYS_XATTR_H -# include +# include #endif #if BFS_CAN_CHECK_ACL || BFS_CAN_CHECK_CAPABILITIES || BFS_CAN_CHECK_XATTRS diff --git a/src/fsade.h b/src/fsade.h index 9bef892..557da26 100644 --- a/src/fsade.h +++ b/src/fsade.h @@ -15,10 +15,10 @@ #define BFS_CAN_CHECK_ACL BFS_USE_SYS_ACL_H #if !defined(BFS_CAN_CHECK_CAPABILITIES) && BFS_USE_SYS_CAPABILITY_H && !__FreeBSD__ -# include -# ifdef CAP_CHOWN -# define BFS_CAN_CHECK_CAPABILITIES true -# endif +# include +# ifdef CAP_CHOWN +# define BFS_CAN_CHECK_CAPABILITIES true +# endif #endif #define BFS_CAN_CHECK_XATTRS (BFS_USE_SYS_EXTATTR_H || BFS_USE_SYS_XATTR_H) diff --git a/src/mtab.c b/src/mtab.c index 0e377a1..27f1743 100644 --- a/src/mtab.c +++ b/src/mtab.c @@ -15,23 +15,23 @@ #include #if BFS_USE_MNTENT_H -# define BFS_MNTENT 1 +# define BFS_MNTENT 1 #elif BSD -# define BFS_MNTINFO 1 +# define BFS_MNTINFO 1 #elif __SVR4 -# define BFS_MNTTAB 1 +# define BFS_MNTTAB 1 #endif #if BFS_MNTENT -# include -# include -# include +# include +# include +# include #elif BFS_MNTINFO -# include -# include +# include +# include #elif BFS_MNTTAB -# include -# include +# include +# include #endif /** diff --git a/src/printf.c b/src/printf.c index 1b4f2d4..726d54d 100644 --- a/src/printf.c +++ b/src/printf.c @@ -72,10 +72,10 @@ static bool should_color(CFILE *cfile, const struct bfs_printf *directive) { /** * Print a value to a temporary buffer before formatting it. */ -#define BFS_PRINTF_BUF(buf, format, ...) \ - char buf[256]; \ - int ret = snprintf(buf, sizeof(buf), format, __VA_ARGS__); \ - assert(ret >= 0 && (size_t)ret < sizeof(buf)); \ +#define BFS_PRINTF_BUF(buf, format, ...) \ + char buf[256]; \ + int ret = snprintf(buf, sizeof(buf), format, __VA_ARGS__); \ + assert(ret >= 0 && (size_t)ret < sizeof(buf)); \ (void)ret /** diff --git a/src/stat.c b/src/stat.c index aaa5eac..f3d9046 100644 --- a/src/stat.c +++ b/src/stat.c @@ -13,15 +13,15 @@ #include #if defined(STATX_BASIC_STATS) && (!__ANDROID__ || __ANDROID_API__ >= 30) -# define BFS_LIBC_STATX true +# define BFS_LIBC_STATX true #elif __linux__ -# include -# include -# include +# include +# include +# include #endif #if BFS_LIBC_STATX || defined(__NR_statx) -# define BFS_STATX true +# define BFS_STATX true #endif const char *bfs_stat_field_name(enum bfs_stat_field field) { diff --git a/src/stat.h b/src/stat.h index 7a70146..e08dd4d 100644 --- a/src/stat.h +++ b/src/stat.h @@ -17,7 +17,7 @@ #include #if BFS_USE_SYS_PARAM_H -# include +# include #endif /** @@ -61,11 +61,11 @@ enum bfs_stat_flags { }; #ifdef DEV_BSIZE -# define BFS_STAT_BLKSIZE DEV_BSIZE +# define BFS_STAT_BLKSIZE DEV_BSIZE #elif defined(S_BLKSIZE) -# define BFS_STAT_BLKSIZE S_BLKSIZE +# define BFS_STAT_BLKSIZE S_BLKSIZE #else -# define BFS_STAT_BLKSIZE 512 +# define BFS_STAT_BLKSIZE 512 #endif /** diff --git a/src/trie.c b/src/trie.c index 43df9dc..9f2e45f 100644 --- a/src/trie.c +++ b/src/trie.c @@ -94,9 +94,9 @@ static_assert(CHAR_BIT == 8, "This trie implementation assumes 8-bit bytes."); #if BFS_TARGET_CLONES && (__i386__ || __x86_64__) -# define TARGET_CLONES_POPCNT __attribute__((target_clones("popcnt", "default"))) +# define TARGET_CLONES_POPCNT __attribute__((target_clones("popcnt", "default"))) #else -# define TARGET_CLONES_POPCNT +# define TARGET_CLONES_POPCNT #endif /** Number of bits for the sparse array bitmap, aka the range of a nibble. */ @@ -367,23 +367,23 @@ static size_t trie_node_size(unsigned int size) { } #if defined(__BYTE_ORDER__) && __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ -# define TRIE_BSWAP(n) (n) +# define TRIE_BSWAP(n) (n) #elif defined(__BYTE_ORDER__) && __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ -# if __SIZEOF_SIZE_T__ == 8 -# define TRIE_BSWAP(n) __builtin_bswap64(n) -# elif __SIZEOF_SIZE_T__ == 4 -# define TRIE_BSWAP(n) __builtin_bswap32(n) -# endif +# if __SIZEOF_SIZE_T__ == 8 +# define TRIE_BSWAP(n) __builtin_bswap64(n) +# elif __SIZEOF_SIZE_T__ == 4 +# define TRIE_BSWAP(n) __builtin_bswap32(n) +# endif #endif #ifdef TRIE_BSWAP -# if __SIZEOF_SIZE_T__ == __SIZEOF_LONG_LONG__ -# define TRIE_CTZ(n) __builtin_ctzll(n) -# elif __SIZEOF_SIZE_T__ == __SIZEOF_LONG__ -# define TRIE_CTZ(n) __builtin_ctzl(n) -# elif __SIZEOF_SIZE_T__ == __SIZEOF_INT__ -# define TRIE_CTZ(n) __builtin_ctz(n) -# endif +# if __SIZEOF_SIZE_T__ == __SIZEOF_LONG_LONG__ +# define TRIE_CTZ(n) __builtin_ctzll(n) +# elif __SIZEOF_SIZE_T__ == __SIZEOF_LONG__ +# define TRIE_CTZ(n) __builtin_ctzl(n) +# elif __SIZEOF_SIZE_T__ == __SIZEOF_INT__ +# define TRIE_CTZ(n) __builtin_ctz(n) +# endif #endif /** Find the offset of the first nibble that differs between two keys. */ diff --git a/src/xregex.c b/src/xregex.c index 5f5480f..a7153b7 100644 --- a/src/xregex.c +++ b/src/xregex.c @@ -9,10 +9,10 @@ #include #if BFS_WITH_ONIGURUMA -# include -# include +# include +# include #else -# include +# include #endif struct bfs_regex { @@ -43,20 +43,20 @@ static int bfs_onig_encoding(OnigEncoding *penc) { // from the current locale. const char *charmap = nl_langinfo(CODESET); if (charmap) { -#define BFS_MAP_ENCODING(name, value) \ - do { \ - if (strcmp(charmap, name) == 0) { \ - enc = value; \ - } \ +#define BFS_MAP_ENCODING(name, value) \ + do { \ + if (strcmp(charmap, name) == 0) { \ + enc = value; \ + } \ } while (0) -#define BFS_MAP_ENCODING2(name1, name2, value) \ - do { \ - BFS_MAP_ENCODING(name1, value); \ - BFS_MAP_ENCODING(name2, value); \ +#define BFS_MAP_ENCODING2(name1, name2, value) \ + do { \ + BFS_MAP_ENCODING(name1, value); \ + BFS_MAP_ENCODING(name2, value); \ } while (0) // These names were found with locale -m on Linux and FreeBSD -#define BFS_MAP_ISO_8859(n) \ +#define BFS_MAP_ISO_8859(n) \ BFS_MAP_ENCODING2("ISO-8859-" #n, "ISO8859-" #n, ONIG_ENCODING_ISO_8859_ ## n) BFS_MAP_ISO_8859(1); @@ -78,7 +78,7 @@ static int bfs_onig_encoding(OnigEncoding *penc) { BFS_MAP_ENCODING("UTF-8", ONIG_ENCODING_UTF8); -#define BFS_MAP_EUC(name) \ +#define BFS_MAP_EUC(name) \ BFS_MAP_ENCODING2("EUC-" #name, "euc" #name, ONIG_ENCODING_EUC_ ## name) BFS_MAP_EUC(JP); diff --git a/src/xspawn.c b/src/xspawn.c index a185200..a6d18a3 100644 --- a/src/xspawn.c +++ b/src/xspawn.c @@ -16,7 +16,7 @@ #include #if BFS_USE_PATHS_H -# include +# include #endif /** -- cgit v1.2.3 From 59f87eed2b930af2f31fd1d1fb2589f80f426ee0 Mon Sep 17 00:00:00 2001 From: Tavian Barnes Date: Thu, 11 May 2023 10:12:35 -0400 Subject: config: Provide and In anticipation of C23, since those headers won't be necessary any more. --- src/bfstd.c | 1 - src/bfstd.h | 2 +- src/bftw.c | 1 - src/color.c | 1 - src/color.h | 1 - src/config.h | 6 +++++- src/ctx.h | 2 +- src/diag.h | 1 - src/dir.c | 2 -- src/eval.h | 2 +- src/exec.c | 1 - src/expr.h | 2 +- src/fsade.h | 1 - src/main.c | 2 +- src/mtab.c | 1 - src/mtab.h | 2 +- src/opt.c | 1 - src/parse.c | 1 - src/printf.c | 1 - src/pwcache.c | 2 +- src/stat.c | 1 - src/trie.c | 1 - src/trie.h | 1 - src/xspawn.c | 1 - src/xtime.c | 2 +- tests/xtimegm.c | 2 +- tests/xtouch.c | 2 +- 27 files changed, 15 insertions(+), 28 deletions(-) (limited to 'src/bfstd.c') diff --git a/src/bfstd.c b/src/bfstd.c index 1dc322b..932f2c4 100644 --- a/src/bfstd.c +++ b/src/bfstd.c @@ -9,7 +9,6 @@ #include #include #include -#include #include #include #include diff --git a/src/bfstd.h b/src/bfstd.h index 028e4e6..e4fd1f1 100644 --- a/src/bfstd.h +++ b/src/bfstd.h @@ -8,7 +8,7 @@ #ifndef BFS_BFSTD_H #define BFS_BFSTD_H -#include +#include "config.h" #include // #include diff --git a/src/bftw.c b/src/bftw.c index 56701a7..14805de 100644 --- a/src/bftw.c +++ b/src/bftw.c @@ -28,7 +28,6 @@ #include #include #include -#include #include #include #include diff --git a/src/color.c b/src/color.c index 589e631..eeadf98 100644 --- a/src/color.c +++ b/src/color.c @@ -15,7 +15,6 @@ #include #include #include -#include #include #include #include diff --git a/src/color.h b/src/color.h index 737c34b..3db2b07 100644 --- a/src/color.h +++ b/src/color.h @@ -10,7 +10,6 @@ #include "config.h" #include -#include #include /** diff --git a/src/config.h b/src/config.h index 229bafb..4408feb 100644 --- a/src/config.h +++ b/src/config.h @@ -8,9 +8,13 @@ #ifndef BFS_CONFIG_H #define BFS_CONFIG_H -#include #include +#if __STDC_VERSION__ < 202311L +# include +# include +#endif + // bfs packaging configuration #ifndef BFS_COMMAND diff --git a/src/ctx.h b/src/ctx.h index 4c748b7..0dc9f08 100644 --- a/src/ctx.h +++ b/src/ctx.h @@ -9,8 +9,8 @@ #define BFS_CTX_H #include "bftw.h" +#include "config.h" #include "trie.h" -#include #include #include #include diff --git a/src/diag.h b/src/diag.h index 2952e30..987d4b4 100644 --- a/src/diag.h +++ b/src/diag.h @@ -11,7 +11,6 @@ #include "ctx.h" #include "config.h" #include -#include struct bfs_expr; diff --git a/src/dir.c b/src/dir.c index eb6e3e0..30db5df 100644 --- a/src/dir.c +++ b/src/dir.c @@ -8,8 +8,6 @@ #include #include #include -#include -#include #include #include #include diff --git a/src/eval.h b/src/eval.h index 3d70319..bdb9440 100644 --- a/src/eval.h +++ b/src/eval.h @@ -9,7 +9,7 @@ #ifndef BFS_EVAL_H #define BFS_EVAL_H -#include +#include "config.h" struct bfs_ctx; struct bfs_expr; diff --git a/src/exec.c b/src/exec.c index 6bde1c1..7f22d36 100644 --- a/src/exec.c +++ b/src/exec.c @@ -14,7 +14,6 @@ #include #include #include -#include #include #include #include diff --git a/src/expr.h b/src/expr.h index 1628cac..356689d 100644 --- a/src/expr.h +++ b/src/expr.h @@ -9,9 +9,9 @@ #define BFS_EXPR_H #include "color.h" +#include "config.h" #include "eval.h" #include "stat.h" -#include #include #include #include diff --git a/src/fsade.h b/src/fsade.h index 557da26..0d9ecaf 100644 --- a/src/fsade.h +++ b/src/fsade.h @@ -10,7 +10,6 @@ #define BFS_FSADE_H #include "config.h" -#include #define BFS_CAN_CHECK_ACL BFS_USE_SYS_ACL_H diff --git a/src/main.c b/src/main.c index 4f99580..24a5035 100644 --- a/src/main.c +++ b/src/main.c @@ -40,13 +40,13 @@ */ #include "bfstd.h" +#include "config.h" #include "ctx.h" #include "eval.h" #include "parse.h" #include #include #include -#include #include #include #include diff --git a/src/mtab.c b/src/mtab.c index 27f1743..1d1ad94 100644 --- a/src/mtab.c +++ b/src/mtab.c @@ -9,7 +9,6 @@ #include "trie.h" #include #include -#include #include #include #include diff --git a/src/mtab.h b/src/mtab.h index 5dfdf6c..ca4372c 100644 --- a/src/mtab.h +++ b/src/mtab.h @@ -8,7 +8,7 @@ #ifndef BFS_MTAB_H #define BFS_MTAB_H -#include +#include "config.h" struct bfs_stat; diff --git a/src/opt.c b/src/opt.c index 731dd10..4ce9425 100644 --- a/src/opt.c +++ b/src/opt.c @@ -39,7 +39,6 @@ #include #include #include -#include #include #include #include diff --git a/src/parse.c b/src/parse.c index 15f38a4..55f1e74 100644 --- a/src/parse.c +++ b/src/parse.c @@ -37,7 +37,6 @@ #include #include #include -#include #include #include #include diff --git a/src/printf.c b/src/printf.c index 454fbee..9ccc216 100644 --- a/src/printf.c +++ b/src/printf.c @@ -20,7 +20,6 @@ #include #include #include -#include #include #include #include diff --git a/src/pwcache.c b/src/pwcache.c index 5026dee..f52e4e1 100644 --- a/src/pwcache.c +++ b/src/pwcache.c @@ -2,12 +2,12 @@ // SPDX-License-Identifier: 0BSD #include "pwcache.h" +#include "config.h" #include "darray.h" #include "trie.h" #include #include #include -#include #include #include #include diff --git a/src/stat.c b/src/stat.c index f3d9046..7973d71 100644 --- a/src/stat.c +++ b/src/stat.c @@ -7,7 +7,6 @@ #include #include #include -#include #include #include #include diff --git a/src/trie.c b/src/trie.c index bfe97e6..e0e00ff 100644 --- a/src/trie.c +++ b/src/trie.c @@ -86,7 +86,6 @@ #include "list.h" #include #include -#include #include #include #include diff --git a/src/trie.h b/src/trie.h index 58974aa..6bd211e 100644 --- a/src/trie.h +++ b/src/trie.h @@ -5,7 +5,6 @@ #define BFS_TRIE_H #include "config.h" -#include #include #include diff --git a/src/xspawn.c b/src/xspawn.c index a6d18a3..00fb76e 100644 --- a/src/xspawn.c +++ b/src/xspawn.c @@ -7,7 +7,6 @@ #include "list.h" #include #include -#include #include #include #include diff --git a/src/xtime.c b/src/xtime.c index 82690d0..406d694 100644 --- a/src/xtime.c +++ b/src/xtime.c @@ -2,9 +2,9 @@ // SPDX-License-Identifier: 0BSD #include "xtime.h" +#include "config.h" #include #include -#include #include #include #include diff --git a/tests/xtimegm.c b/tests/xtimegm.c index bab64ba..b2479b7 100644 --- a/tests/xtimegm.c +++ b/tests/xtimegm.c @@ -2,7 +2,7 @@ // SPDX-License-Identifier: 0BSD #include "../src/xtime.h" -#include +#include "../src/config.h" #include #include #include diff --git a/tests/xtouch.c b/tests/xtouch.c index 7e29547..50416ba 100644 --- a/tests/xtouch.c +++ b/tests/xtouch.c @@ -2,10 +2,10 @@ // SPDX-License-Identifier: 0BSD #include "../src/bfstd.h" +#include "../src/config.h" #include "../src/xtime.h" #include #include -#include #include #include #include -- cgit v1.2.3 From 88581b9d505342e20d03cc4c6557d30c3f66f0f5 Mon Sep 17 00:00:00 2001 From: Tavian Barnes Date: Thu, 18 May 2023 13:27:04 -0400 Subject: Use bfs_bug("...") over assert(!"...") --- src/bfstd.c | 3 ++- src/color.c | 3 ++- src/ctx.c | 3 +-- src/dstring.c | 4 ++-- src/eval.c | 6 +++--- src/parse.c | 4 ++-- src/stat.c | 6 +++--- 7 files changed, 15 insertions(+), 14 deletions(-) (limited to 'src/bfstd.c') diff --git a/src/bfstd.c b/src/bfstd.c index 932f2c4..91383a2 100644 --- a/src/bfstd.c +++ b/src/bfstd.c @@ -3,6 +3,7 @@ #include "bfstd.h" #include "config.h" +#include "diag.h" #include "xregex.h" #include #include @@ -95,7 +96,7 @@ FILE *xfopen(const char *path, int flags) { strcpy(mode, "r+b"); break; default: - assert(!"Invalid access mode"); + bfs_bug("Invalid access mode"); errno = EINVAL; return NULL; } diff --git a/src/color.c b/src/color.c index eeadf98..43ea9a4 100644 --- a/src/color.c +++ b/src/color.c @@ -5,6 +5,7 @@ #include "bfstd.h" #include "bftw.h" #include "config.h" +#include "diag.h" #include "dir.h" #include "dstring.h" #include "expr.h" @@ -1085,7 +1086,7 @@ static int cvbuff(CFILE *cfile, const char *format, va_list args) { return 0; invalid: - assert(!"Invalid format string"); + bfs_bug("Invalid format string"); errno = EINVAL; return -1; } diff --git a/src/ctx.c b/src/ctx.c index ff4a2a7..c4b2fb2 100644 --- a/src/ctx.c +++ b/src/ctx.c @@ -11,7 +11,6 @@ #include "stat.h" #include "trie.h" #include "xtime.h" -#include #include #include #include @@ -38,7 +37,7 @@ const char *debug_flag_name(enum debug_flags flag) { break; } - assert(!"Unrecognized debug flag"); + bfs_bug("Unrecognized debug flag"); return "???"; } diff --git a/src/dstring.c b/src/dstring.c index 05efb10..2c9869d 100644 --- a/src/dstring.c +++ b/src/dstring.c @@ -2,7 +2,7 @@ // SPDX-License-Identifier: 0BSD #include "dstring.h" -#include +#include "diag.h" #include #include #include @@ -184,7 +184,7 @@ int dstrvcatf(char **str, const char *format, va_list args) { tail = *str + len; ret = vsnprintf(tail, tail_len + 1, format, copy); if (ret < 0 || (size_t)ret != tail_len) { - assert(!"Length of formatted string changed"); + bfs_bug("Length of formatted string changed"); goto fail; } } diff --git a/src/eval.c b/src/eval.c index 7444ec9..6cad3a9 100644 --- a/src/eval.c +++ b/src/eval.c @@ -142,7 +142,7 @@ bool bfs_expr_cmp(const struct bfs_expr *expr, long long n) { return n > expr->num; } - assert(!"Invalid comparison mode"); + bfs_bug("Invalid comparison mode"); return false; } @@ -476,7 +476,7 @@ bool eval_flags(const struct bfs_expr *expr, struct bfs_eval *state) { return (flags & set) || (flags & clear) != clear; } - assert(!"Invalid comparison mode"); + bfs_bug("Invalid comparison mode"); return false; } @@ -626,7 +626,7 @@ bool eval_perm(const struct bfs_expr *expr, struct bfs_eval *state) { return !(mode & target) == !target; } - assert(!"Invalid comparison mode"); + bfs_bug("Invalid comparison mode"); return false; } diff --git a/src/parse.c b/src/parse.c index 55f1e74..807892c 100644 --- a/src/parse.c +++ b/src/parse.c @@ -638,7 +638,7 @@ static const char *parse_int(const struct parser_state *state, char **arg, const break; default: - assert(!"Invalid int size"); + bfs_bug("Invalid int size"); goto bad; } @@ -3492,7 +3492,7 @@ static const char *bftw_strategy_name(enum bftw_strategy strategy) { return "eds"; } - assert(!"Invalid strategy"); + bfs_bug("Invalid strategy"); return "???"; } diff --git a/src/stat.c b/src/stat.c index 50ea345..590a1d6 100644 --- a/src/stat.c +++ b/src/stat.c @@ -4,7 +4,7 @@ #include "stat.h" #include "bfstd.h" #include "config.h" -#include +#include "diag.h" #include #include #include @@ -57,7 +57,7 @@ const char *bfs_stat_field_name(enum bfs_stat_field field) { return "modification time"; } - assert(!"Unrecognized stat field"); + bfs_bug("Unrecognized stat field"); return "???"; } @@ -340,7 +340,7 @@ const struct timespec *bfs_stat_time(const struct bfs_stat *buf, enum bfs_stat_f case BFS_STAT_MTIME: return &buf->mtime; default: - assert(!"Invalid stat field for time"); + bfs_bug("Invalid stat field for time"); errno = EINVAL; return NULL; } -- cgit v1.2.3 From 526133c11eb9a26a4cffb20bcd10bcbb36d940de Mon Sep 17 00:00:00 2001 From: Tavian Barnes Date: Thu, 18 May 2023 16:44:30 -0400 Subject: Switch from assert() to bfs_assert()/bfs_verify() --- src/bfstd.c | 3 +- src/bftw.c | 28 ++++++++-------- src/color.c | 5 ++- src/diag.c | 3 +- src/dir.c | 4 +-- src/eval.c | 11 +++---- src/exec.c | 7 ++-- src/opt.c | 13 ++++---- src/parse.c | 7 ++-- src/printf.c | 5 ++- src/trie.c | 33 ++++++++++--------- src/xregex.c | 4 +-- tests/bfstd.c | 13 ++++---- tests/bit.c | 100 +++++++++++++++++++++++++++++----------------------------- tests/trie.c | 56 ++++++++++++++++---------------- 15 files changed, 140 insertions(+), 152 deletions(-) (limited to 'src/bfstd.c') diff --git a/src/bfstd.c b/src/bfstd.c index 91383a2..37f5276 100644 --- a/src/bfstd.c +++ b/src/bfstd.c @@ -5,7 +5,6 @@ #include "config.h" #include "diag.h" #include "xregex.h" -#include #include #include #include @@ -393,7 +392,7 @@ void close_quietly(int fd) { int xclose(int fd) { int ret = close(fd); if (ret != 0) { - assert(errno != EBADF); + bfs_verify(errno != EBADF); } return ret; } diff --git a/src/bftw.c b/src/bftw.c index 14805de..6ec5cfa 100644 --- a/src/bftw.c +++ b/src/bftw.c @@ -19,13 +19,13 @@ #include "bftw.h" #include "bfstd.h" #include "config.h" +#include "diag.h" #include "dir.h" #include "dstring.h" #include "list.h" #include "mtab.h" #include "stat.h" #include "trie.h" -#include #include #include #include @@ -114,7 +114,7 @@ static void bftw_cache_remove(struct bftw_cache *cache, struct bftw_file *file) /** Close a bftw_file. */ static void bftw_file_close(struct bftw_cache *cache, struct bftw_file *file) { - assert(file->fd >= 0); + bfs_assert(file->fd >= 0); if (LIST_ATTACHED(cache, file, lru)) { bftw_cache_remove(cache, file); @@ -137,7 +137,7 @@ static int bftw_cache_pop(struct bftw_cache *cache) { /** Add a bftw_file to the cache. */ static int bftw_cache_add(struct bftw_cache *cache, struct bftw_file *file) { - assert(file->fd >= 0); + bfs_assert(file->fd >= 0); if (cache->capacity == 0 && bftw_cache_pop(cache) != 0) { bftw_file_close(cache, file); @@ -145,7 +145,7 @@ static int bftw_cache_add(struct bftw_cache *cache, struct bftw_file *file) { return -1; } - assert(cache->capacity > 0); + bfs_assert(cache->capacity > 0); --cache->capacity; LIST_INSERT(cache, cache->target, file, lru); @@ -169,9 +169,9 @@ static size_t bftw_child_nameoff(const struct bftw_file *parent) { /** Destroy a cache. */ static void bftw_cache_destroy(struct bftw_cache *cache) { - assert(!cache->head); - assert(!cache->tail); - assert(!cache->target); + bfs_assert(!cache->head); + bfs_assert(!cache->tail); + bfs_assert(!cache->target); } /** Create a new bftw_file. */ @@ -230,7 +230,7 @@ static struct bftw_file *bftw_file_new(struct bftw_file *parent, const char *nam * The opened file descriptor, or negative on error. */ static int bftw_file_openat(struct bftw_cache *cache, struct bftw_file *file, struct bftw_file *base, const char *at_path) { - assert(file->fd < 0); + bfs_assert(file->fd < 0); int at_fd = AT_FDCWD; if (base) { @@ -332,7 +332,7 @@ static struct bfs_dir *bftw_file_opendir(struct bftw_cache *cache, struct bftw_f /** Free a bftw_file. */ static void bftw_file_free(struct bftw_cache *cache, struct bftw_file *file) { - assert(file->refcount == 0); + bfs_assert(file->refcount == 0); if (file->fd >= 0) { bftw_file_close(cache, file); @@ -770,7 +770,7 @@ static enum bftw_action bftw_call_back(struct bftw_state *state, const char *nam /** Pop a directory to read from the queue. */ static bool bftw_pop_dir(struct bftw_state *state) { - assert(!state->file); + bfs_assert(!state->file); if (!state->dirs.head) { return false; @@ -787,7 +787,7 @@ static bool bftw_pop_dir(struct bftw_state *state) { /** Pop a file to visit from the queue. */ static bool bftw_pop_file(struct bftw_state *state) { - assert(!state->file); + bfs_assert(!state->file); state->file = state->files.head; if (state->file) { @@ -802,8 +802,8 @@ static bool bftw_pop_file(struct bftw_state *state) { * Open the current directory. */ static int bftw_opendir(struct bftw_state *state) { - assert(!state->dir); - assert(!state->de); + bfs_assert(!state->dir); + bfs_assert(!state->de); state->direrror = 0; @@ -863,7 +863,7 @@ static int bftw_gc(struct bftw_state *state, enum bftw_gc_flags flags) { if (state->dir) { struct bftw_file *file = state->file; - assert(file && file->fd >= 0); + bfs_assert(file && file->fd >= 0); if (file->refcount > 1) { // Keep the fd around if any subdirectories exist diff --git a/src/color.c b/src/color.c index 43ea9a4..a723084 100644 --- a/src/color.c +++ b/src/color.c @@ -12,7 +12,6 @@ #include "fsade.h" #include "stat.h" #include "trie.h" -#include #include #include #include @@ -699,7 +698,7 @@ static int print_colored(CFILE *cfile, const char *esc, const char *str, size_t /** Find the offset of the first broken path component. */ static ssize_t first_broken_offset(const char *path, const struct BFTW *ftwbuf, enum bfs_stat_flags flags, size_t max) { ssize_t ret = max; - assert(ret >= 0); + bfs_assert(ret >= 0); if (bftw_type(ftwbuf, flags) != BFS_ERROR) { goto out; @@ -1100,7 +1099,7 @@ static int cbuff(CFILE *cfile, const char *format, ...) { } int cvfprintf(CFILE *cfile, const char *format, va_list args) { - assert(dstrlen(cfile->buffer) == 0); + bfs_assert(dstrlen(cfile->buffer) == 0); int ret = -1; if (cvbuff(cfile, format, args) == 0) { diff --git a/src/diag.c b/src/diag.c index d7ffaa6..04e3678 100644 --- a/src/diag.c +++ b/src/diag.c @@ -6,7 +6,6 @@ #include "ctx.h" #include "color.h" #include "expr.h" -#include #include #include #include @@ -117,7 +116,7 @@ static bool highlight_expr_recursive(const struct bfs_ctx *ctx, const struct bfs for (size_t i = 0; i < ctx->argc; ++i) { if (&ctx->argv[i] == expr->argv) { for (size_t j = 0; j < expr->argc; ++j) { - assert(i + j < ctx->argc); + bfs_assert(i + j < ctx->argc); args[i + j] = true; ret = true; } diff --git a/src/dir.c b/src/dir.c index 6739f10..d9ee63b 100644 --- a/src/dir.c +++ b/src/dir.c @@ -4,7 +4,7 @@ #include "dir.h" #include "bfstd.h" #include "config.h" -#include +#include "diag.h" #include #include #include @@ -249,7 +249,7 @@ int bfs_closedir(struct bfs_dir *dir) { int ret = xclose(dir->fd); #else int ret = closedir(dir->dir); - assert(ret == 0 || errno != EBADF); + bfs_verify(ret == 0 || errno != EBADF); #endif free(dir); return ret; diff --git a/src/eval.c b/src/eval.c index 6cad3a9..342debd 100644 --- a/src/eval.c +++ b/src/eval.c @@ -26,7 +26,6 @@ #include "trie.h" #include "xregex.h" #include "xtime.h" -#include #include #include #include @@ -990,7 +989,7 @@ static bool eval_expr(struct bfs_expr *expr, struct bfs_eval *state) { } } - assert(!state->quit); + bfs_assert(!state->quit); bool ret = expr->eval_fn(expr, state); @@ -1006,10 +1005,10 @@ static bool eval_expr(struct bfs_expr *expr, struct bfs_eval *state) { } if (bfs_expr_never_returns(expr)) { - assert(state->quit); + bfs_assert(state->quit); } else if (!state->quit) { - assert(!expr->always_true || ret); - assert(!expr->always_false || !ret); + bfs_assert(!expr->always_true || ret); + bfs_assert(!expr->always_false || !ret); } return ret; @@ -1511,7 +1510,7 @@ static void dump_bftw_flags(enum bftw_flags flags) { DEBUG_FLAG(flags, BFTW_SORT); DEBUG_FLAG(flags, BFTW_BUFFER); - assert(!flags); + bfs_assert(flags == 0, "Missing bftw flag 0x%X", flags); } /** diff --git a/src/exec.c b/src/exec.c index 7f22d36..5912ad6 100644 --- a/src/exec.c +++ b/src/exec.c @@ -10,7 +10,6 @@ #include "diag.h" #include "dstring.h" #include "xspawn.h" -#include #include #include #include @@ -276,12 +275,12 @@ static void bfs_exec_free_arg(char *arg, const char *tmpl) { /** Open a file to use as the working directory. */ static int bfs_exec_openwd(struct bfs_exec *execbuf, const struct BFTW *ftwbuf) { - assert(execbuf->wd_fd < 0); - assert(!execbuf->wd_path); + bfs_assert(execbuf->wd_fd < 0); + bfs_assert(!execbuf->wd_path); if (ftwbuf->at_fd != AT_FDCWD) { // Rely on at_fd being the immediate parent - assert(xbaseoff(ftwbuf->at_path) == 0); + bfs_assert(xbaseoff(ftwbuf->at_path) == 0); execbuf->wd_fd = ftwbuf->at_fd; if (!(execbuf->flags & BFS_EXEC_MULTI)) { diff --git a/src/opt.c b/src/opt.c index 4ce9425..4699af4 100644 --- a/src/opt.c +++ b/src/opt.c @@ -35,7 +35,6 @@ #include "exec.h" #include "expr.h" #include "pwcache.h" -#include #include #include #include @@ -308,7 +307,7 @@ struct opt_state { /** Log an optimization. */ BFS_FORMATTER(3, 4) static bool opt_debug(const struct opt_state *state, int level, const char *format, ...) { - assert(state->ctx->optlevel >= level); + bfs_assert(state->ctx->optlevel >= level); if (bfs_debug(state->ctx, DEBUG_OPT, "${cyn}-O%d${rs}: ", level)) { va_list args; @@ -387,7 +386,7 @@ static struct bfs_expr *de_morgan(const struct opt_state *state, struct bfs_expr has_parent = false; } - assert(expr->eval_fn == eval_and || expr->eval_fn == eval_or); + bfs_assert(expr->eval_fn == eval_and || expr->eval_fn == eval_or); if (expr->eval_fn == eval_and) { expr->eval_fn = eval_or; expr->argv = &fake_or_arg; @@ -446,7 +445,7 @@ static struct bfs_expr *optimize_expr_recursive(struct opt_state *state, struct * Optimize a negation. */ static struct bfs_expr *optimize_not_expr(const struct opt_state *state, struct bfs_expr *expr) { - assert(expr->eval_fn == eval_not); + bfs_assert(expr->eval_fn == eval_not); struct bfs_expr *rhs = expr->rhs; @@ -498,7 +497,7 @@ fail: /** Optimize a conjunction. */ static struct bfs_expr *optimize_and_expr(const struct opt_state *state, struct bfs_expr *expr) { - assert(expr->eval_fn == eval_and); + bfs_assert(expr->eval_fn == eval_and); struct bfs_expr *lhs = expr->lhs; struct bfs_expr *rhs = expr->rhs; @@ -569,7 +568,7 @@ fail: /** Optimize a disjunction. */ static struct bfs_expr *optimize_or_expr(const struct opt_state *state, struct bfs_expr *expr) { - assert(expr->eval_fn == eval_or); + bfs_assert(expr->eval_fn == eval_or); struct bfs_expr *lhs = expr->lhs; struct bfs_expr *rhs = expr->rhs; @@ -673,7 +672,7 @@ static struct bfs_expr *ignore_result(const struct opt_state *state, struct bfs_ /** Optimize a comma expression. */ static struct bfs_expr *optimize_comma_expr(const struct opt_state *state, struct bfs_expr *expr) { - assert(expr->eval_fn == eval_comma); + bfs_assert(expr->eval_fn == eval_comma); struct bfs_expr *lhs = expr->lhs; struct bfs_expr *rhs = expr->rhs; diff --git a/src/parse.c b/src/parse.c index 807892c..1a04e68 100644 --- a/src/parse.c +++ b/src/parse.c @@ -29,7 +29,6 @@ #include "xregex.h" #include "xspawn.h" #include "xtime.h" -#include #include #include #include @@ -134,7 +133,7 @@ static struct bfs_expr *new_unary_expr(bfs_eval_fn *eval_fn, struct bfs_expr *rh expr->lhs = NULL; expr->rhs = rhs; - assert(bfs_expr_is_parent(expr)); + bfs_assert(bfs_expr_is_parent(expr)); expr->persistent_fds = rhs->persistent_fds; expr->ephemeral_fds = rhs->ephemeral_fds; @@ -154,7 +153,7 @@ static struct bfs_expr *new_binary_expr(bfs_eval_fn *eval_fn, struct bfs_expr *l expr->lhs = lhs; expr->rhs = rhs; - assert(bfs_expr_is_parent(expr)); + bfs_assert(bfs_expr_is_parent(expr)); expr->persistent_fds = lhs->persistent_fds + rhs->persistent_fds; if (lhs->ephemeral_fds > rhs->ephemeral_fds) { @@ -263,7 +262,7 @@ static void init_highlight(const struct bfs_ctx *ctx, bool *args) { static void highlight_args(const struct bfs_ctx *ctx, char **argv, size_t argc, bool *args) { size_t i = argv - ctx->argv; for (size_t j = 0; j < argc; ++j) { - assert(i + j < ctx->argc); + bfs_assert(i + j < ctx->argc); args[i + j] = true; } } diff --git a/src/printf.c b/src/printf.c index 9ccc216..6520d2d 100644 --- a/src/printf.c +++ b/src/printf.c @@ -16,7 +16,6 @@ #include "pwcache.h" #include "stat.h" #include "xtime.h" -#include #include #include #include @@ -74,7 +73,7 @@ static bool should_color(CFILE *cfile, const struct bfs_printf *directive) { #define BFS_PRINTF_BUF(buf, format, ...) \ char buf[256]; \ int ret = snprintf(buf, sizeof(buf), format, __VA_ARGS__); \ - assert(ret >= 0 && (size_t)ret < sizeof(buf)); \ + bfs_assert(ret >= 0 && (size_t)ret < sizeof(buf)); \ (void)ret /** @@ -190,7 +189,7 @@ static int bfs_printf_strftime(CFILE *cfile, const struct bfs_printf *directive, break; } - assert(ret >= 0 && (size_t)ret < sizeof(buf)); + bfs_assert(ret >= 0 && (size_t)ret < sizeof(buf)); (void)ret; return dyn_fprintf(cfile->file, directive, buf); diff --git a/src/trie.c b/src/trie.c index a2921de..8543eb1 100644 --- a/src/trie.c +++ b/src/trie.c @@ -86,7 +86,6 @@ #include "config.h" #include "diag.h" #include "list.h" -#include #include #include #include @@ -139,27 +138,27 @@ static bool trie_is_leaf(uintptr_t ptr) { /** Decode a pointer to a leaf. */ static struct trie_leaf *trie_decode_leaf(uintptr_t ptr) { - assert(trie_is_leaf(ptr)); + bfs_assert(trie_is_leaf(ptr)); return (struct trie_leaf *)(ptr ^ 1); } /** Encode a pointer to a leaf. */ static uintptr_t trie_encode_leaf(const struct trie_leaf *leaf) { uintptr_t ptr = (uintptr_t)leaf ^ 1; - assert(trie_is_leaf(ptr)); + bfs_assert(trie_is_leaf(ptr)); return ptr; } /** Decode a pointer to an internal node. */ static struct trie_node *trie_decode_node(uintptr_t ptr) { - assert(!trie_is_leaf(ptr)); + bfs_assert(!trie_is_leaf(ptr)); return (struct trie_node *)ptr; } /** Encode a pointer to an internal node. */ static uintptr_t trie_encode_node(const struct trie_node *node) { uintptr_t ptr = (uintptr_t)node; - assert(!trie_is_leaf(ptr)); + bfs_assert(!trie_is_leaf(ptr)); return ptr; } @@ -341,9 +340,9 @@ static void trie_leaf_free(struct trie *trie, struct trie_leaf *leaf) { /** Compute the size of a trie node with a certain number of children. */ static size_t trie_node_size(unsigned int size) { // Empty nodes aren't supported - assert(size > 0); + bfs_assert(size > 0); // Node size must be a power of two - assert(has_single_bit(size)); + bfs_assert(has_single_bit(size)); return flex_sizeof(struct trie_node, children, size); } @@ -435,7 +434,7 @@ static struct trie_leaf *trie_node_insert(struct trie *trie, uintptr_t *ptr, str unsigned int bit = 1U << nibble; // The child must not already be present - assert(!(node->bitmap & bit)); + bfs_assert(!(node->bitmap & bit)); node->bitmap |= bit; unsigned int target = count_ones(node->bitmap & (bit - 1)); @@ -474,7 +473,7 @@ static struct trie_leaf *trie_node_insert(struct trie *trie, uintptr_t *ptr, str static uintptr_t *trie_jump(uintptr_t *ptr, const char *key, size_t *offset) { // We only ever need to jump to leaf nodes, since internal nodes are // guaranteed to be within OFFSET_MAX anyway - assert(trie_is_leaf(*ptr)); + bfs_assert(trie_is_leaf(*ptr)); struct trie_node *node = malloc(trie_node_size(1)); if (!node) { @@ -512,7 +511,7 @@ static uintptr_t *trie_jump(uintptr_t *ptr, const char *key, size_t *offset) { static struct trie_leaf *trie_split(struct trie *trie, uintptr_t *ptr, struct trie_leaf *leaf, struct trie_leaf *rep, size_t offset, size_t mismatch) { unsigned char key_nibble = trie_key_nibble(leaf->key, mismatch); unsigned char rep_nibble = trie_key_nibble(rep->key, mismatch); - assert(key_nibble != rep_nibble); + bfs_assert(key_nibble != rep_nibble); struct trie_node *node = malloc(trie_node_size(2)); if (!node) { @@ -570,11 +569,11 @@ static struct trie_leaf *trie_insert_mem_impl(struct trie *trie, const void *key unsigned char nibble = trie_key_nibble(key, offset); unsigned int bit = 1U << nibble; if (node->bitmap & bit) { - assert(offset < mismatch); + bfs_assert(offset < mismatch); unsigned int index = count_ones(node->bitmap & (bit - 1)); ptr = &node->children[index]; } else { - assert(offset == mismatch); + bfs_assert(offset == mismatch); return trie_node_insert(trie, ptr, leaf, nibble); } } @@ -600,7 +599,7 @@ static void trie_free_singletons(struct trie *trie, uintptr_t ptr) { struct trie_node *node = trie_decode_node(ptr); // Make sure the bitmap is a power of two, i.e. it has just one child - assert(has_single_bit(node->bitmap)); + bfs_assert(has_single_bit(node->bitmap)); ptr = node->children[0]; free(node); @@ -651,12 +650,12 @@ static void trie_remove_impl(struct trie *trie, struct trie_leaf *leaf) { while (!trie_is_leaf(*child)) { struct trie_node *node = trie_decode_node(*child); offset += node->offset; - assert((offset >> 1) < leaf->length); + bfs_assert((offset >> 1) < leaf->length); unsigned char nibble = trie_key_nibble(leaf->key, offset); unsigned int bit = 1U << nibble; unsigned int bitmap = node->bitmap; - assert(bitmap & bit); + bfs_assert(bitmap & bit); unsigned int index = count_ones(bitmap & (bit - 1)); // Advance the parent pointer, unless this node had only one child @@ -669,7 +668,7 @@ static void trie_remove_impl(struct trie *trie, struct trie_leaf *leaf) { child = &node->children[index]; } - assert(trie_decode_leaf(*child) == leaf); + bfs_assert(trie_decode_leaf(*child) == leaf); if (!parent) { trie_free_singletons(trie, trie->root); @@ -683,7 +682,7 @@ static void trie_remove_impl(struct trie *trie, struct trie_leaf *leaf) { node->bitmap ^= child_bit; unsigned int parent_size = count_ones(node->bitmap); - assert(parent_size > 0); + bfs_assert(parent_size > 0); if (parent_size == 1 && trie_collapse_node(parent, node, child_index) == 0) { return; } diff --git a/src/xregex.c b/src/xregex.c index a7153b7..1143f23 100644 --- a/src/xregex.c +++ b/src/xregex.c @@ -3,7 +3,7 @@ #include "xregex.h" #include "config.h" -#include +#include "diag.h" #include #include #include @@ -140,7 +140,7 @@ int bfs_regcomp(struct bfs_regex **preg, const char *pattern, enum bfs_regex_typ syntax = ONIG_SYNTAX_GREP; break; } - assert(syntax); + bfs_assert(syntax); OnigOptionType options = syntax->options; if (flags & BFS_REGEX_ICASE) { diff --git a/tests/bfstd.c b/tests/bfstd.c index a986a23..1812a00 100644 --- a/tests/bfstd.c +++ b/tests/bfstd.c @@ -1,10 +1,9 @@ // Copyright © Tavian Barnes // SPDX-License-Identifier: 0BSD -#undef NDEBUG #include "../src/bfstd.h" #include "../src/config.h" -#include +#include "../src/diag.h" #include #include #include @@ -39,11 +38,11 @@ int main(void) { alignas(64) int foo; int bar[]; }; - assert(flex_sizeof(struct flexible, bar, 0) >= sizeof(struct flexible)); - assert(flex_sizeof(struct flexible, bar, 16) % alignof(struct flexible) == 0); - assert(flex_sizeof(struct flexible, bar, SIZE_MAX / sizeof(int) + 1) - == align_floor(alignof(struct flexible), SIZE_MAX)); - assert(flex_sizeof_impl(8, 16, 4, 4, 1) == 16); + bfs_verify(flex_sizeof(struct flexible, bar, 0) >= sizeof(struct flexible)); + bfs_verify(flex_sizeof(struct flexible, bar, 16) % alignof(struct flexible) == 0); + bfs_verify(flex_sizeof(struct flexible, bar, SIZE_MAX / sizeof(int) + 1) + == align_floor(alignof(struct flexible), SIZE_MAX)); + bfs_verify(flex_sizeof_impl(8, 16, 4, 4, 1) == 16); // From man 3p basename check_base_dir("usr", ".", "usr"); diff --git a/tests/bit.c b/tests/bit.c index 7a7b0f3..cb339f4 100644 --- a/tests/bit.c +++ b/tests/bit.c @@ -1,11 +1,8 @@ // Copyright © Tavian Barnes // SPDX-License-Identifier: 0BSD -#undef NDEBUG - #include "../src/bit.h" #include "../src/diag.h" -#include #include #include #include @@ -54,68 +51,71 @@ bfs_static_assert(UINTMAX_MAX == UWIDTH_MAX(UINTMAX_WIDTH)); bfs_static_assert(INTMAX_MIN == IWIDTH_MIN(INTMAX_WIDTH)); bfs_static_assert(INTMAX_MAX == IWIDTH_MAX(INTMAX_WIDTH)); +#define verify_eq(a, b) \ + bfs_verify((a) == (b), "(0x%jX) %s != %s (0x%jX)", (uintmax_t)(a), #a, #b, (uintmax_t)(b)) + int main(void) { - assert(bswap((uint8_t)0x12) == 0x12); - assert(bswap((uint16_t)0x1234) == 0x3412); - assert(bswap((uint32_t)0x12345678) == 0x78563412); - assert(bswap((uint64_t)0x1234567812345678) == 0x7856341278563412); - - assert(count_ones(0x0) == 0); - assert(count_ones(0x1) == 1); - assert(count_ones(0x2) == 1); - assert(count_ones(0x3) == 2); - assert(count_ones(0x137F) == 10); - - assert(count_zeros(0) == INT_WIDTH); - assert(count_zeros(0L) == LONG_WIDTH); - assert(count_zeros(0LL) == LLONG_WIDTH); - assert(count_zeros((uint8_t)0) == 8); - assert(count_zeros((uint16_t)0) == 16); - assert(count_zeros((uint32_t)0) == 32); - assert(count_zeros((uint64_t)0) == 64); - - assert(rotate_left((uint8_t)0xA1, 4) == 0x1A); - assert(rotate_left((uint16_t)0x1234, 12) == 0x4123); - assert(rotate_left((uint32_t)0x12345678, 20) == 0x67812345); - assert(rotate_left((uint32_t)0x12345678, 0) == 0x12345678); - - assert(rotate_right((uint8_t)0xA1, 4) == 0x1A); - assert(rotate_right((uint16_t)0x1234, 12) == 0x2341); - assert(rotate_right((uint32_t)0x12345678, 20) == 0x45678123); - assert(rotate_right((uint32_t)0x12345678, 0) == 0x12345678); + verify_eq(bswap((uint8_t)0x12), 0x12); + verify_eq(bswap((uint16_t)0x1234), 0x3412); + verify_eq(bswap((uint32_t)0x12345678), 0x78563412); + verify_eq(bswap((uint64_t)0x1234567812345678), 0x7856341278563412); + + verify_eq(count_ones(0x0), 0); + verify_eq(count_ones(0x1), 1); + verify_eq(count_ones(0x2), 1); + verify_eq(count_ones(0x3), 2); + verify_eq(count_ones(0x137F), 10); + + verify_eq(count_zeros(0), INT_WIDTH); + verify_eq(count_zeros(0L), LONG_WIDTH); + verify_eq(count_zeros(0LL), LLONG_WIDTH); + verify_eq(count_zeros((uint8_t)0), 8); + verify_eq(count_zeros((uint16_t)0), 16); + verify_eq(count_zeros((uint32_t)0), 32); + verify_eq(count_zeros((uint64_t)0), 64); + + verify_eq(rotate_left((uint8_t)0xA1, 4), 0x1A); + verify_eq(rotate_left((uint16_t)0x1234, 12), 0x4123); + verify_eq(rotate_left((uint32_t)0x12345678, 20), 0x67812345); + verify_eq(rotate_left((uint32_t)0x12345678, 0), 0x12345678); + + verify_eq(rotate_right((uint8_t)0xA1, 4), 0x1A); + verify_eq(rotate_right((uint16_t)0x1234, 12), 0x2341); + verify_eq(rotate_right((uint32_t)0x12345678, 20), 0x45678123); + verify_eq(rotate_right((uint32_t)0x12345678, 0), 0x12345678); for (int i = 0; i < 16; ++i) { uint16_t n = (uint16_t)1 << i; for (int j = i; j < 16; ++j) { uint16_t m = (uint16_t)1 << j; uint16_t nm = n | m; - assert(count_ones(nm) == 1 + (n != m)); - assert(count_zeros(nm) == 15 - (n != m)); - assert(leading_zeros(nm) == 15 - j); - assert(trailing_zeros(nm) == i); - assert(first_leading_one(nm) == j + 1); - assert(first_trailing_one(nm) == i + 1); - assert(bit_width(nm) == j + 1); - assert(bit_floor(nm) == m); + verify_eq(count_ones(nm), 1 + (n != m)); + verify_eq(count_zeros(nm), 15 - (n != m)); + verify_eq(leading_zeros(nm), 15 - j); + verify_eq(trailing_zeros(nm), i); + verify_eq(first_leading_one(nm), j + 1); + verify_eq(first_trailing_one(nm), i + 1); + verify_eq(bit_width(nm), j + 1); + verify_eq(bit_floor(nm), m); if (n == m) { - assert(bit_ceil(nm) == m); - assert(has_single_bit(nm)); + verify_eq(bit_ceil(nm), m); + bfs_verify(has_single_bit(nm)); } else { if (j < 15) { - assert(bit_ceil(nm) == (m << 1)); + verify_eq(bit_ceil(nm), (m << 1)); } - assert(!has_single_bit(nm)); + bfs_verify(!has_single_bit(nm)); } } } - assert(leading_zeros((uint16_t)0) == 16); - assert(trailing_zeros((uint16_t)0) == 16); - assert(first_leading_one(0) == 0); - assert(first_trailing_one(0) == 0); - assert(bit_width(0) == 0); - assert(bit_floor(0) == 0); - assert(bit_ceil(0) == 1); + verify_eq(leading_zeros((uint16_t)0), 16); + verify_eq(trailing_zeros((uint16_t)0), 16); + verify_eq(first_leading_one(0), 0); + verify_eq(first_trailing_one(0), 0); + verify_eq(bit_width(0), 0); + verify_eq(bit_floor(0), 0); + verify_eq(bit_ceil(0), 1); return EXIT_SUCCESS; } diff --git a/tests/trie.c b/tests/trie.c index ced14d4..e687f96 100644 --- a/tests/trie.c +++ b/tests/trie.c @@ -1,11 +1,9 @@ // Copyright © Tavian Barnes // SPDX-License-Identifier: 0BSD -#undef NDEBUG - #include "../src/trie.h" #include "../src/config.h" -#include +#include "../src/diag.h" #include #include @@ -45,7 +43,7 @@ int main(void) { trie_init(&trie); for (size_t i = 0; i < nkeys; ++i) { - assert(!trie_find_str(&trie, keys[i])); + bfs_verify(!trie_find_str(&trie, keys[i])); const char *prefix = NULL; for (size_t j = 0; j < i; ++j) { @@ -58,38 +56,38 @@ int main(void) { struct trie_leaf *leaf = trie_find_prefix(&trie, keys[i]); if (prefix) { - assert(leaf); - assert(strcmp(prefix, leaf->key) == 0); + bfs_verify(leaf); + bfs_verify(strcmp(prefix, leaf->key) == 0); } else { - assert(!leaf); + bfs_verify(!leaf); } leaf = trie_insert_str(&trie, keys[i]); - assert(leaf); - assert(strcmp(keys[i], leaf->key) == 0); - assert(leaf->length == strlen(keys[i]) + 1); + bfs_verify(leaf); + bfs_verify(strcmp(keys[i], leaf->key) == 0); + bfs_verify(leaf->length == strlen(keys[i]) + 1); } { size_t i = 0; TRIE_FOR_EACH(&trie, leaf) { - assert(leaf == trie_find_str(&trie, keys[i])); - assert(!leaf->prev || leaf->prev->next == leaf); - assert(!leaf->next || leaf->next->prev == leaf); + bfs_verify(leaf == trie_find_str(&trie, keys[i])); + bfs_verify(!leaf->prev || leaf->prev->next == leaf); + bfs_verify(!leaf->next || leaf->next->prev == leaf); ++i; } - assert(i == nkeys); + bfs_verify(i == nkeys); } for (size_t i = 0; i < nkeys; ++i) { struct trie_leaf *leaf = trie_find_str(&trie, keys[i]); - assert(leaf); - assert(strcmp(keys[i], leaf->key) == 0); - assert(leaf->length == strlen(keys[i]) + 1); + bfs_verify(leaf); + bfs_verify(strcmp(keys[i], leaf->key) == 0); + bfs_verify(leaf->length == strlen(keys[i]) + 1); trie_remove(&trie, leaf); leaf = trie_find_str(&trie, keys[i]); - assert(!leaf); + bfs_verify(!leaf); const char *postfix = NULL; for (size_t j = i + 1; j < nkeys; ++j) { @@ -102,33 +100,33 @@ int main(void) { leaf = trie_find_postfix(&trie, keys[i]); if (postfix) { - assert(leaf); - assert(strcmp(postfix, leaf->key) == 0); + bfs_verify(leaf); + bfs_verify(strcmp(postfix, leaf->key) == 0); } else { - assert(!leaf); + bfs_verify(!leaf); } } TRIE_FOR_EACH(&trie, leaf) { - assert(false); + bfs_verify(false); } // This tests the "jump" node handling on 32-bit platforms size_t longsize = 1 << 20; char *longstr = malloc(longsize); - assert(longstr); + bfs_verify(longstr); memset(longstr, 0xAC, longsize); - assert(!trie_find_mem(&trie, longstr, longsize)); - assert(trie_insert_mem(&trie, longstr, longsize)); + bfs_verify(!trie_find_mem(&trie, longstr, longsize)); + bfs_verify(trie_insert_mem(&trie, longstr, longsize)); memset(longstr + longsize/2, 0xAB, longsize/2); - assert(!trie_find_mem(&trie, longstr, longsize)); - assert(trie_insert_mem(&trie, longstr, longsize)); + bfs_verify(!trie_find_mem(&trie, longstr, longsize)); + bfs_verify(trie_insert_mem(&trie, longstr, longsize)); memset(longstr, 0xAA, longsize/2); - assert(!trie_find_mem(&trie, longstr, longsize)); - assert(trie_insert_mem(&trie, longstr, longsize)); + bfs_verify(!trie_find_mem(&trie, longstr, longsize)); + bfs_verify(trie_insert_mem(&trie, longstr, longsize)); free(longstr); trie_destroy(&trie); -- cgit v1.2.3 From d83553b4a2e942f410d56d92bef34def9424a494 Mon Sep 17 00:00:00 2001 From: Tavian Barnes Date: Thu, 6 Apr 2023 14:52:50 -0400 Subject: bfstd: Add an aligned_alloc()/posix_memalign() wrapper --- src/bfstd.c | 14 ++++++++++++++ src/bfstd.h | 12 ++++++++++++ 2 files changed, 26 insertions(+) (limited to 'src/bfstd.c') diff --git a/src/bfstd.c b/src/bfstd.c index 37f5276..4e1175f 100644 --- a/src/bfstd.c +++ b/src/bfstd.c @@ -2,6 +2,7 @@ // SPDX-License-Identifier: 0BSD #include "bfstd.h" +#include "bit.h" #include "config.h" #include "diag.h" #include "xregex.h" @@ -142,6 +143,19 @@ char *xgetdelim(FILE *file, char delim) { } } +void *xmemalign(size_t align, size_t size) { + bfs_assert(has_single_bit(align)); + bfs_assert((size & (align - 1)) == 0); + +#if __APPLE__ + void *ptr = NULL; + errno = posix_memalign(&ptr, align, size); + return ptr; +#else + return aligned_alloc(align, size); +#endif +} + /** Compile and execute a regular expression for xrpmatch(). */ static int xrpregex(nl_item item, const char *response) { const char *pattern = nl_langinfo(item); diff --git a/src/bfstd.h b/src/bfstd.h index e4fd1f1..ee4cf16 100644 --- a/src/bfstd.h +++ b/src/bfstd.h @@ -105,6 +105,18 @@ char *xgetdelim(FILE *file, char delim); // #include +/** + * Portable version of aligned_alloc()/posix_memalign(). + * + * @param align + * The allocation's alignment. + * @param size + * The allocation's size. + * @return + * The allocation, or NULL on failure. + */ +void *xmemalign(size_t align, size_t size); + /** * Process a yes/no prompt. * -- cgit v1.2.3 From d3f4340a460a023656151f220f5923ec8ccf9894 Mon Sep 17 00:00:00 2001 From: Tavian Barnes Date: Fri, 16 Jun 2023 13:44:06 -0400 Subject: bfstd: New wordesc() function to shell-escape strings --- src/bfstd.c | 46 ++++++++++++++++++++++++++++++++++++++++++++++ src/bfstd.h | 13 +++++++++++++ 2 files changed, 59 insertions(+) (limited to 'src/bfstd.c') diff --git a/src/bfstd.c b/src/bfstd.c index 4e1175f..cfff426 100644 --- a/src/bfstd.c +++ b/src/bfstd.c @@ -544,3 +544,49 @@ size_t xstrwidth(const char *str) { return ret; } + +char *wordesc(const char *str) { + size_t len = strlen(str); + + if (strcspn(str, "|&;<>()$`\\\"' \t\n*?[#˜=%") == len) { + // Whole string is safe + // https://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html#tag_18_02 + if (len > 0) { + return strdup(str); + } else { + return strdup("\"\""); + } + } else if (strcspn(str, "`$\\\"") == len) { + // Safe to double-quote the whole string + // https://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html#tag_18_02_03 + char *ret = malloc(len + 3); + if (!ret) { + return NULL; + } + + char *cur = stpcpy(ret, "\""); + cur = stpcpy(cur, str); + cur = stpcpy(cur, "\""); + return ret; + } + + // Every ' is replaced with '\'', so at most a 3x growth + char *ret = malloc(3 * len + 3); + if (!ret) { + return NULL; + } + + char *cur = stpcpy(ret, "'"); + while (*str) { + size_t chunk = strcspn(str, "'"); + cur = stpncpy(cur, str, chunk); + str += chunk; + if (*str) { + cur = stpcpy(cur, "'\\''"); + ++str; + } + } + cur = stpcpy(cur, "'"); + + return ret; +} diff --git a/src/bfstd.h b/src/bfstd.h index ee4cf16..750847e 100644 --- a/src/bfstd.h +++ b/src/bfstd.h @@ -277,4 +277,17 @@ int xstrtofflags(const char **str, unsigned long long *set, unsigned long long * */ size_t xstrwidth(const char *str); +// #include + +/** + * Escape a string as a single shell word. + * + * @param str + * The string to escape. + * @return + * A string that a shell would evaluate to str, dynamically allocated, + * or NULL on failure. + */ +char *wordesc(const char *str); + #endif // BFS_BFSTD_H -- cgit v1.2.3 From 9ceb2b27577f1be3f30edb40a45117066fc78c51 Mon Sep 17 00:00:00 2001 From: Tavian Barnes Date: Mon, 19 Jun 2023 12:08:10 -0400 Subject: bfstd: New xmemdup() function --- src/bfstd.c | 8 ++++++++ src/bfstd.h | 12 ++++++++++++ src/parse.c | 7 ++----- 3 files changed, 22 insertions(+), 5 deletions(-) (limited to 'src/bfstd.c') diff --git a/src/bfstd.c b/src/bfstd.c index cfff426..856c76c 100644 --- a/src/bfstd.c +++ b/src/bfstd.c @@ -243,6 +243,14 @@ static char type_char(mode_t mode) { return '?'; } +void *xmemdup(const void *src, size_t size) { + void *ret = malloc(size); + if (ret) { + memcpy(ret, src, size); + } + return ret; +} + void xstrmode(mode_t mode, char str[11]) { strcpy(str, "----------"); diff --git a/src/bfstd.h b/src/bfstd.h index 750847e..6f2e21e 100644 --- a/src/bfstd.h +++ b/src/bfstd.h @@ -126,6 +126,18 @@ int ynprompt(void); // #include +/** + * Allocate a copy of a region of memory. + * + * @param src + * The memory region to copy. + * @param size + * The size of the memory region. + * @return + * A copy of the region, allocated with malloc(), or NULL on failure. + */ +void *xmemdup(const void *src, size_t size); + /** * Format a mode like ls -l (e.g. -rw-r--r--). * diff --git a/src/parse.c b/src/parse.c index 5c55076..64e08cd 100644 --- a/src/parse.c +++ b/src/parse.c @@ -3666,14 +3666,11 @@ struct bfs_ctx *bfs_parse_cmdline(int argc, char *argv[]) { } ctx->argc = argc; - ctx->argv = malloc((argc + 1)*sizeof(*ctx->argv)); + ctx->argv = xmemdup(argv, sizeof_array(char *, argc + 1)); if (!ctx->argv) { - perror("malloc()"); + perror("xmemdup()"); goto fail; } - for (int i = 0; i <= argc; ++i) { - ctx->argv[i] = argv[i]; - } enum use_color use_color = COLOR_AUTO; if (getenv("NO_COLOR")) { -- cgit v1.2.3 From 90ded13e589b0089167ef25ca3d26be599dfec9b Mon Sep 17 00:00:00 2001 From: Tavian Barnes Date: Mon, 19 Jun 2023 12:11:36 -0400 Subject: alloc: New header for memory allocation utilities --- Makefile | 3 +- src/alloc.c | 50 ++++++++++++++++++++ src/alloc.h | 149 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ src/bfstd.c | 13 ----- src/bfstd.h | 12 ----- src/bftw.c | 5 +- src/color.c | 5 +- src/config.h | 50 -------------------- src/ctx.c | 31 ++---------- src/dstring.c | 3 +- src/exec.c | 26 ++++------ src/ioq.c | 26 ++++------ src/ioq.h | 4 +- src/main.c | 1 + src/mtab.c | 5 +- src/parse.c | 28 ++--------- src/pwcache.c | 5 +- src/trie.c | 7 ++- src/xregex.c | 3 +- src/xspawn.c | 3 +- tests/alloc.c | 24 ++++++++++ tests/bfstd.c | 13 +---- 22 files changed, 271 insertions(+), 195 deletions(-) create mode 100644 src/alloc.c create mode 100644 src/alloc.h create mode 100644 tests/alloc.c (limited to 'src/bfstd.c') diff --git a/Makefile b/Makefile index fb28e29..d38f581 100644 --- a/Makefile +++ b/Makefile @@ -217,6 +217,7 @@ $(OBJ)/FLAGS: $(OBJ)/FLAGS.new # All object files except the entry point LIBBFS := \ + $(OBJ)/src/alloc.o \ $(OBJ)/src/bar.o \ $(OBJ)/src/bfstd.o \ $(OBJ)/src/bftw.o \ @@ -246,7 +247,7 @@ LIBBFS := \ $(BIN)/bfs: $(OBJ)/src/main.o $(LIBBFS) # Standalone unit tests -UNITS := bfstd bit trie xtimegm +UNITS := alloc bfstd bit trie xtimegm UNIT_TESTS := $(UNITS:%=$(BIN)/tests/%) UNIT_CHECKS := $(UNITS:%=check-%) diff --git a/src/alloc.c b/src/alloc.c new file mode 100644 index 0000000..0003108 --- /dev/null +++ b/src/alloc.c @@ -0,0 +1,50 @@ +// Copyright © Tavian Barnes +// SPDX-License-Identifier: 0BSD + +#include "alloc.h" +#include "bit.h" +#include "diag.h" +#include +#include +#include + +/** Portable aligned_alloc()/posix_memalign(). */ +static void *xmemalign(size_t align, size_t size) { + bfs_assert(has_single_bit(align)); + bfs_assert(align >= sizeof(void *)); + bfs_assert((size & (align - 1)) == 0); + +#if __APPLE__ + void *ptr = NULL; + errno = posix_memalign(&ptr, align, size); + return ptr; +#else + return aligned_alloc(align, size); +#endif +} + +void *alloc(size_t align, size_t size) { + bfs_assert(has_single_bit(align)); + bfs_assert((size & (align - 1)) == 0); + + if (align <= alignof(max_align_t)) { + return malloc(size); + } else { + return xmemalign(align, size); + } +} + +void *zalloc(size_t align, size_t size) { + bfs_assert(has_single_bit(align)); + bfs_assert((size & (align - 1)) == 0); + + if (align <= alignof(max_align_t)) { + return calloc(1, size); + } + + void *ret = xmemalign(align, size); + if (ret) { + memset(ret, 0, size); + } + return ret; +} diff --git a/src/alloc.h b/src/alloc.h new file mode 100644 index 0000000..899a4ec --- /dev/null +++ b/src/alloc.h @@ -0,0 +1,149 @@ +// Copyright © Tavian Barnes +// SPDX-License-Identifier: 0BSD + +/** + * Memory allocation. + */ + +#ifndef BFS_ALLOC_H +#define BFS_ALLOC_H + +#include "config.h" +#include + +/** Round down to a multiple of an alignment. */ +static inline size_t align_floor(size_t align, size_t size) { + return size & ~(align - 1); +} + +/** Round up to a multiple of an alignment. */ +static inline size_t align_ceil(size_t align, size_t size) { + return align_floor(align, size + align - 1); +} + +/** + * Saturating array size. + * + * @param align + * Array element alignment. + * @param size + * Array element size. + * @param count + * Array element count. + * @return + * size * count, saturating to the maximum aligned value on overflow. + */ +static inline size_t array_size(size_t align, size_t size, size_t count) { + size_t ret = size * count; + return ret / size == count ? ret : ~(align - 1); +} + +/** Saturating array sizeof. */ +#define sizeof_array(type, count) \ + array_size(alignof(type), sizeof(type), count) + +/** Size of a struct/union field. */ +#define sizeof_member(type, member) \ + sizeof(((type *)NULL)->member) + +/** + * Saturating flexible struct size. + * + * @param align + * Struct alignment. + * @param min + * Minimum struct size. + * @param offset + * Flexible array member offset. + * @param size + * Flexible array element size. + * @param count + * Flexible array element count. + * @return + * The size of the struct with count flexible array elements. Saturates + * to the maximum aligned value on overflow. + */ +static inline size_t flex_size(size_t align, size_t min, size_t offset, size_t size, size_t count) { + size_t ret = size * count; + size_t overflow = ret / size != count; + + size_t extra = offset + align - 1; + ret += extra; + overflow |= ret < extra; + ret |= -overflow; + ret = align_floor(align, ret); + + // Make sure flex_sizeof(type, member, 0) >= sizeof(type), even if the + // type has more padding than necessary for alignment + if (min > align_ceil(align, offset)) { + ret = ret < min ? min : ret; + } + + return ret; +} + +/** + * Computes the size of a flexible struct. + * + * @param type + * The type of the struct containing the flexible array. + * @param member + * The name of the flexible array member. + * @param count + * The length of the flexible array. + * @return + * The size of the struct with count flexible array elements. Saturates + * to the maximum aligned value on overflow. + */ +#define sizeof_flex(type, member, count) \ + flex_size(alignof(type), sizeof(type), offsetof(type, member), sizeof_member(type, member[0]), count) + +/** + * General memory allocator. + * + * @param align + * The required alignment. + * @param size + * The size of the allocation. + * @return + * The allocated memory, or NULL on failure. + */ +void *alloc(size_t align, size_t size); + +/** + * Zero-initialized memory allocator. + * + * @param align + * The required alignment. + * @param size + * The size of the allocation. + * @return + * The allocated memory, or NULL on failure. + */ +void *zalloc(size_t align, size_t size); + +/** Allocate memory for the given type. */ +#define ALLOC(type) \ + (type *)alloc(alignof(type), sizeof(type)) + +/** Allocate zeroed memory for the given type. */ +#define ZALLOC(type) \ + (type *)zalloc(alignof(type), sizeof(type)) + +/** Allocate memory for an array. */ +#define ALLOC_ARRAY(type, count) \ + (type *)alloc(alignof(type), sizeof_array(type, count)); + +/** Allocate zeroed memory for an array. */ +#define ZALLOC_ARRAY(type, count) \ + (type *)zalloc(alignof(type), sizeof_array(type, count)); + +/** Allocate memory for a flexible struct. */ +#define ALLOC_FLEX(type, member, count) \ + (type *)alloc(alignof(type), sizeof_flex(type, member, count)) + +/** Allocate zeroed memory for a flexible struct. */ +#define ZALLOC_FLEX(type, member, count) \ + (type *)zalloc(alignof(type), sizeof_flex(type, member, count)) + +#endif // BFS_ALLOC_H diff --git a/src/bfstd.c b/src/bfstd.c index 856c76c..0e8ba5f 100644 --- a/src/bfstd.c +++ b/src/bfstd.c @@ -143,19 +143,6 @@ char *xgetdelim(FILE *file, char delim) { } } -void *xmemalign(size_t align, size_t size) { - bfs_assert(has_single_bit(align)); - bfs_assert((size & (align - 1)) == 0); - -#if __APPLE__ - void *ptr = NULL; - errno = posix_memalign(&ptr, align, size); - return ptr; -#else - return aligned_alloc(align, size); -#endif -} - /** Compile and execute a regular expression for xrpmatch(). */ static int xrpregex(nl_item item, const char *response) { const char *pattern = nl_langinfo(item); diff --git a/src/bfstd.h b/src/bfstd.h index 6f2e21e..cafe28f 100644 --- a/src/bfstd.h +++ b/src/bfstd.h @@ -105,18 +105,6 @@ char *xgetdelim(FILE *file, char delim); // #include -/** - * Portable version of aligned_alloc()/posix_memalign(). - * - * @param align - * The allocation's alignment. - * @param size - * The allocation's size. - * @return - * The allocation, or NULL on failure. - */ -void *xmemalign(size_t align, size_t size); - /** * Process a yes/no prompt. * diff --git a/src/bftw.c b/src/bftw.c index e711963..7ab14c7 100644 --- a/src/bftw.c +++ b/src/bftw.c @@ -17,6 +17,7 @@ */ #include "bftw.h" +#include "alloc.h" #include "bfstd.h" #include "config.h" #include "diag.h" @@ -241,9 +242,7 @@ static void bftw_cache_destroy(struct bftw_cache *cache) { /** Create a new bftw_file. */ static struct bftw_file *bftw_file_new(struct bftw_file *parent, const char *name) { size_t namelen = strlen(name); - size_t size = flex_sizeof(struct bftw_file, name, namelen + 1); - - struct bftw_file *file = malloc(size); + struct bftw_file *file = ALLOC_FLEX(struct bftw_file, name, namelen + 1); if (!file) { return NULL; } diff --git a/src/color.c b/src/color.c index 1edd8b5..b54ad53 100644 --- a/src/color.c +++ b/src/color.c @@ -2,6 +2,7 @@ // SPDX-License-Identifier: 0BSD #include "color.h" +#include "alloc.h" #include "bfstd.h" #include "bftw.h" #include "config.h" @@ -404,7 +405,7 @@ static void parse_gnu_ls_colors(struct colors *colors, const char *ls_colors) { } struct colors *parse_colors(void) { - struct colors *colors = malloc(sizeof(struct colors)); + struct colors *colors = ALLOC(struct colors); if (!colors) { return NULL; } @@ -497,7 +498,7 @@ void free_colors(struct colors *colors) { } CFILE *cfwrap(FILE *file, const struct colors *colors, bool close) { - CFILE *cfile = malloc(sizeof(*cfile)); + CFILE *cfile = ALLOC(CFILE); if (!cfile) { return NULL; } diff --git a/src/config.h b/src/config.h index 73348ac..1671a0d 100644 --- a/src/config.h +++ b/src/config.h @@ -141,56 +141,6 @@ */ #define countof(array) (sizeof(array) / sizeof(0[array])) -/** - * Round down to a multiple of an alignment. - */ -static inline size_t align_floor(size_t align, size_t size) { - return size & ~(align - 1); -} - -/** - * Round up to a multiple of an alignment. - */ -static inline size_t align_ceil(size_t align, size_t size) { - return align_floor(align, size + align - 1); -} - -/** - * Computes the size of a struct containing a flexible array member of the given - * length. - * - * @param type - * The type of the struct containing the flexible array. - * @param member - * The name of the flexible array member. - * @param count - * The length of the flexible array. - */ -#define flex_sizeof(type, member, count) \ - flex_sizeof_impl(alignof(type), sizeof(type), offsetof(type, member), sizeof(((type *)NULL)->member[0]), count) - -static inline size_t flex_sizeof_impl(size_t align, size_t min, size_t offset, size_t size, size_t count) { - size_t ret = size * count; - size_t overflow = ret / size != count; - - ret += offset; - overflow |= ret < offset; - - size_t mask = align - 1; - ret += mask; - overflow |= ret < mask; - ret |= -overflow; - ret &= ~mask; - - // Make sure flex_sizeof(type, member, 0) >= sizeof(type), even if the - // type has more padding than necessary for alignment - if (min > align_ceil(align, offset) && ret < min) { - ret = min; - } - - return ret; -} - /** * False sharing/destructive interference/largest cache line size. */ diff --git a/src/ctx.c b/src/ctx.c index e8ce0e8..a940bed 100644 --- a/src/ctx.c +++ b/src/ctx.c @@ -2,6 +2,7 @@ // SPDX-License-Identifier: 0BSD #include "ctx.h" +#include "alloc.h" #include "color.h" #include "darray.h" #include "diag.h" @@ -42,43 +43,17 @@ const char *debug_flag_name(enum debug_flags flag) { } struct bfs_ctx *bfs_ctx_new(void) { - struct bfs_ctx *ctx = malloc(sizeof(*ctx)); + struct bfs_ctx *ctx = ZALLOC(struct bfs_ctx); if (!ctx) { return NULL; } - ctx->argv = NULL; - ctx->paths = NULL; - ctx->expr = NULL; - ctx->exclude = NULL; - - ctx->mindepth = 0; ctx->maxdepth = INT_MAX; ctx->flags = BFTW_RECOVER; ctx->strategy = BFTW_BFS; - ctx->threads = 0; ctx->optlevel = 3; - ctx->debug = 0; - ctx->ignore_races = false; - ctx->posixly_correct = false; - ctx->status = false; - ctx->unique = false; - ctx->warn = false; - ctx->xargs_safe = false; - - ctx->colors = NULL; - ctx->colors_error = 0; - ctx->cout = NULL; - ctx->cerr = NULL; - - ctx->users = NULL; - ctx->groups = NULL; - - ctx->mtab = NULL; - ctx->mtab_error = 0; trie_init(&ctx->files); - ctx->nfiles = 0; struct rlimit rl; if (getrlimit(RLIMIT_NOFILE, &rl) != 0) { @@ -155,7 +130,7 @@ CFILE *bfs_ctx_dedup(struct bfs_ctx *ctx, CFILE *cfile, const char *path) { return ctx_file->cfile; } - leaf->value = ctx_file = malloc(sizeof(*ctx_file)); + leaf->value = ctx_file = ALLOC(struct bfs_ctx_file); if (!ctx_file) { trie_remove(&ctx->files, leaf); return NULL; diff --git a/src/dstring.c b/src/dstring.c index 2c9869d..7ca74d0 100644 --- a/src/dstring.c +++ b/src/dstring.c @@ -2,6 +2,7 @@ // SPDX-License-Identifier: 0BSD #include "dstring.h" +#include "alloc.h" #include "diag.h" #include #include @@ -24,7 +25,7 @@ static struct dstring *dstrheader(const char *dstr) { /** Get the correct size for a dstring with the given capacity. */ static size_t dstrsize(size_t capacity) { - return flex_sizeof(struct dstring, data, capacity + 1); + return sizeof_flex(struct dstring, data, capacity + 1); } /** Allocate a dstring with the given contents. */ diff --git a/src/exec.c b/src/exec.c index 5912ad6..ea7f897 100644 --- a/src/exec.c +++ b/src/exec.c @@ -2,6 +2,7 @@ // SPDX-License-Identifier: 0BSD #include "exec.h" +#include "alloc.h" #include "bfstd.h" #include "bftw.h" #include "ctx.h" @@ -124,26 +125,16 @@ static void bfs_exec_parse_error(const struct bfs_ctx *ctx, const struct bfs_exe } struct bfs_exec *bfs_exec_parse(const struct bfs_ctx *ctx, char **argv, enum bfs_exec_flags flags) { - struct bfs_exec *execbuf = malloc(sizeof(*execbuf)); + struct bfs_exec *execbuf = ZALLOC(struct bfs_exec); if (!execbuf) { - bfs_perror(ctx, "malloc()"); + bfs_perror(ctx, "zalloc()"); goto fail; } execbuf->flags = flags; execbuf->ctx = ctx; execbuf->tmpl_argv = argv + 1; - execbuf->tmpl_argc = 0; - execbuf->argv = NULL; - execbuf->argc = 0; - execbuf->argv_cap = 0; - execbuf->arg_size = 0; - execbuf->arg_max = 0; - execbuf->arg_min = 0; execbuf->wd_fd = -1; - execbuf->wd_path = NULL; - execbuf->wd_len = 0; - execbuf->ret = 0; while (true) { const char *arg = execbuf->tmpl_argv[execbuf->tmpl_argc]; @@ -176,9 +167,9 @@ struct bfs_exec *bfs_exec_parse(const struct bfs_ctx *ctx, char **argv, enum bfs } execbuf->argv_cap = execbuf->tmpl_argc + 1; - execbuf->argv = malloc(execbuf->argv_cap*sizeof(*execbuf->argv)); + execbuf->argv = ALLOC_ARRAY(char *, execbuf->argv_cap); if (!execbuf->argv) { - bfs_perror(ctx, "malloc()"); + bfs_perror(ctx, "alloc()"); goto fail; } @@ -224,9 +215,8 @@ static char *bfs_exec_format_path(const struct bfs_exec *execbuf, const struct B return NULL; } - strcpy(path, "./"); - strcpy(path + 2, name); - + char *cur = stpcpy(path, "./"); + cur = stpcpy(cur, name); return path; } @@ -612,7 +602,7 @@ static int bfs_exec_push(struct bfs_exec *execbuf, char *arg) { if (execbuf->argc + 1 >= execbuf->argv_cap) { size_t cap = 2*execbuf->argv_cap; - char **argv = realloc(execbuf->argv, cap*sizeof(*argv)); + char **argv = realloc(execbuf->argv, sizeof_array(char *, cap)); if (!argv) { return -1; } diff --git a/src/ioq.c b/src/ioq.c index 5550c91..3e304ce 100644 --- a/src/ioq.c +++ b/src/ioq.c @@ -2,6 +2,7 @@ // SPDX-License-Identifier: 0BSD #include "ioq.h" +#include "alloc.h" #include "atomic.h" #include "bfstd.h" #include "bit.h" @@ -114,7 +115,7 @@ static struct ioqq *ioqq_create(size_t size) { // Circular buffer size must be a power of two size = bit_ceil(size); - struct ioqq *ioqq = xmemalign(alignof(struct ioqq), flex_sizeof(struct ioqq, slots, size)); + struct ioqq *ioqq = ALLOC_FLEX(struct ioqq, slots, size); if (!ioqq) { return NULL; } @@ -124,7 +125,7 @@ static struct ioqq *ioqq_create(size_t size) { // Use a pool of monitors size_t nmonitors = size < 64 ? size : 64; - ioqq->monitors = xmemalign(alignof(struct ioq_monitor), nmonitors * sizeof(struct ioq_monitor)); + ioqq->monitors = ALLOC_ARRAY(struct ioq_monitor, nmonitors); if (!ioqq->monitors) { ioqq_destroy(ioqq); return NULL; @@ -273,7 +274,7 @@ struct ioq { /** The number of background threads. */ size_t nthreads; /** The background threads themselves. */ - pthread_t *threads; + pthread_t threads[]; }; /** Background thread entry point. */ @@ -303,18 +304,13 @@ static void *ioq_work(void *ptr) { return NULL; } -struct ioq *ioq_create(size_t depth, size_t threads) { - struct ioq *ioq = malloc(sizeof(*ioq)); +struct ioq *ioq_create(size_t depth, size_t nthreads) { + struct ioq *ioq = ZALLOC_FLEX(struct ioq, threads, nthreads); if (!ioq) { goto fail; } ioq->depth = depth; - ioq->size = 0; - - ioq->pending = NULL; - ioq->ready = NULL; - ioq->nthreads = 0; ioq->pending = ioqq_create(depth); if (!ioq->pending) { @@ -326,12 +322,7 @@ struct ioq *ioq_create(size_t depth, size_t threads) { goto fail; } - ioq->threads = malloc(threads * sizeof(ioq->threads[0])); - if (!ioq->threads) { - goto fail; - } - - for (size_t i = 0; i < threads; ++i) { + for (size_t i = 0; i < nthreads; ++i) { errno = pthread_create(&ioq->threads[i], NULL, ioq_work, ioq); if (errno != 0) { goto fail; @@ -354,7 +345,7 @@ int ioq_opendir(struct ioq *ioq, int dfd, const char *path, void *ptr) { return -1; } - union ioq_cmd *cmd = malloc(sizeof(*cmd)); + union ioq_cmd *cmd = ALLOC(union ioq_cmd); if (!cmd) { return -1; } @@ -412,7 +403,6 @@ void ioq_destroy(struct ioq *ioq) { abort(); } } - free(ioq->threads); ioqq_destroy(ioq->ready); ioqq_destroy(ioq->pending); diff --git a/src/ioq.h b/src/ioq.h index 9492034..0af5779 100644 --- a/src/ioq.h +++ b/src/ioq.h @@ -33,12 +33,12 @@ struct ioq_res { * * @param depth * The maximum depth of the queue. - * @param threads + * @param nthreads * The maximum number of background threads. * @return * The new I/O queue, or NULL on failure. */ -struct ioq *ioq_create(size_t depth, size_t threads); +struct ioq *ioq_create(size_t depth, size_t nthreads); /** * Asynchronous bfs_opendir(). diff --git a/src/main.c b/src/main.c index 76dde86..b7a08c1 100644 --- a/src/main.c +++ b/src/main.c @@ -20,6 +20,7 @@ * - bftw.[ch] (an extended version of nftw(3)) * * - Utilities: + * - alloc.[ch] (memory allocation) * - atomic.h (atomic operations) * - bar.[ch] (a terminal status bar) * - bit.h (bit manipulation) diff --git a/src/mtab.c b/src/mtab.c index 1d1ad94..e5c25ba 100644 --- a/src/mtab.c +++ b/src/mtab.c @@ -2,6 +2,7 @@ // SPDX-License-Identifier: 0BSD #include "mtab.h" +#include "alloc.h" #include "bfstd.h" #include "config.h" #include "darray.h" @@ -87,15 +88,13 @@ fail: } struct bfs_mtab *bfs_mtab_parse(void) { - struct bfs_mtab *mtab = malloc(sizeof(*mtab)); + struct bfs_mtab *mtab = ZALLOC(struct bfs_mtab); if (!mtab) { return NULL; } - mtab->entries = NULL; trie_init(&mtab->names); trie_init(&mtab->types); - mtab->types_filled = false; int error = 0; diff --git a/src/parse.c b/src/parse.c index 64e08cd..cf4f696 100644 --- a/src/parse.c +++ b/src/parse.c @@ -9,6 +9,7 @@ */ #include "parse.h" +#include "alloc.h" #include "bfstd.h" #include "bftw.h" #include "color.h" @@ -55,39 +56,16 @@ static char *fake_print_arg = "-print"; static char *fake_true_arg = "-true"; struct bfs_expr *bfs_expr_new(bfs_eval_fn *eval_fn, size_t argc, char **argv) { - struct bfs_expr *expr = malloc(sizeof(*expr)); + struct bfs_expr *expr = ZALLOC(struct bfs_expr); if (!expr) { - perror("malloc()"); + perror("zalloc()"); return NULL; } expr->eval_fn = eval_fn; expr->argc = argc; expr->argv = argv; - expr->persistent_fds = 0; - expr->ephemeral_fds = 0; - expr->pure = false; - expr->always_true = false; - expr->always_false = false; - expr->cost = 0.0; expr->probability = 0.5; - expr->evaluations = 0; - expr->successes = 0; - expr->elapsed.tv_sec = 0; - expr->elapsed.tv_nsec = 0; - - // Prevent bfs_expr_free() from freeing uninitialized pointers on error paths - if (bfs_expr_is_parent(expr)) { - expr->lhs = NULL; - expr->rhs = NULL; - } else if (eval_fn == eval_exec) { - expr->exec = NULL; - } else if (eval_fn == eval_fprintf) { - expr->printf = NULL; - } else if (eval_fn == eval_regex) { - expr->regex = NULL; - } - return expr; } diff --git a/src/pwcache.c b/src/pwcache.c index f52e4e1..9f32eb0 100644 --- a/src/pwcache.c +++ b/src/pwcache.c @@ -2,6 +2,7 @@ // SPDX-License-Identifier: 0BSD #include "pwcache.h" +#include "alloc.h" #include "config.h" #include "darray.h" #include "trie.h" @@ -71,7 +72,7 @@ struct bfs_users { }; struct bfs_users *bfs_users_new(void) { - struct bfs_users *users = malloc(sizeof(*users)); + struct bfs_users *users = ALLOC(struct bfs_users); if (!users) { return NULL; } @@ -144,7 +145,7 @@ struct bfs_groups { }; struct bfs_groups *bfs_groups_new(void) { - struct bfs_groups *groups = malloc(sizeof(*groups)); + struct bfs_groups *groups = ALLOC(struct bfs_groups); if (!groups) { return NULL; } diff --git a/src/trie.c b/src/trie.c index 8543eb1..19423cf 100644 --- a/src/trie.c +++ b/src/trie.c @@ -82,6 +82,7 @@ */ #include "trie.h" +#include "alloc.h" #include "bit.h" #include "config.h" #include "diag.h" @@ -317,7 +318,7 @@ struct trie_leaf *trie_find_prefix(const struct trie *trie, const char *key) { /** Create a new leaf, holding a copy of the given key. */ static struct trie_leaf *trie_leaf_alloc(struct trie *trie, const void *key, size_t length) { - struct trie_leaf *leaf = malloc(flex_sizeof(struct trie_leaf, key, length)); + struct trie_leaf *leaf = ALLOC_FLEX(struct trie_leaf, key, length); if (!leaf) { return NULL; } @@ -339,12 +340,10 @@ static void trie_leaf_free(struct trie *trie, struct trie_leaf *leaf) { /** Compute the size of a trie node with a certain number of children. */ static size_t trie_node_size(unsigned int size) { - // Empty nodes aren't supported - bfs_assert(size > 0); // Node size must be a power of two bfs_assert(has_single_bit(size)); - return flex_sizeof(struct trie_node, children, size); + return sizeof_flex(struct trie_node, children, size); } #if ENDIAN_NATIVE == ENDIAN_LITTLE diff --git a/src/xregex.c b/src/xregex.c index 89c2e90..ab5f793 100644 --- a/src/xregex.c +++ b/src/xregex.c @@ -2,6 +2,7 @@ // SPDX-License-Identifier: 0BSD #include "xregex.h" +#include "alloc.h" #include "config.h" #include "diag.h" #include "sanity.h" @@ -115,7 +116,7 @@ static int bfs_onig_initialize(OnigEncoding *enc) { #endif int bfs_regcomp(struct bfs_regex **preg, const char *pattern, enum bfs_regex_type type, enum bfs_regcomp_flags flags) { - struct bfs_regex *regex = *preg = malloc(sizeof(*regex)); + struct bfs_regex *regex = *preg = ALLOC(struct bfs_regex); if (!regex) { return -1; } diff --git a/src/xspawn.c b/src/xspawn.c index 740e38e..2cabdcc 100644 --- a/src/xspawn.c +++ b/src/xspawn.c @@ -2,6 +2,7 @@ // SPDX-License-Identifier: 0BSD #include "xspawn.h" +#include "alloc.h" #include "bfstd.h" #include "config.h" #include "list.h" @@ -62,7 +63,7 @@ int bfs_spawn_setflags(struct bfs_spawn *ctx, enum bfs_spawn_flags flags) { /** Add a spawn action to the chain. */ static struct bfs_spawn_action *bfs_spawn_add(struct bfs_spawn *ctx, enum bfs_spawn_op op) { - struct bfs_spawn_action *action = malloc(sizeof(*action)); + struct bfs_spawn_action *action = ALLOC(struct bfs_spawn_action); if (!action) { return NULL; } diff --git a/tests/alloc.c b/tests/alloc.c new file mode 100644 index 0000000..91b1b43 --- /dev/null +++ b/tests/alloc.c @@ -0,0 +1,24 @@ +// Copyright © Tavian Barnes +// SPDX-License-Identifier: 0BSD + +#include "../src/alloc.h" +#include "../src/diag.h" +#include + +int main(void) { + // Check sizeof_flex() + struct flexible { + alignas(64) int foo; + int bar[]; + }; + bfs_verify(sizeof_flex(struct flexible, bar, 0) >= sizeof(struct flexible)); + bfs_verify(sizeof_flex(struct flexible, bar, 16) % alignof(struct flexible) == 0); + bfs_verify(sizeof_flex(struct flexible, bar, SIZE_MAX / sizeof(int) + 1) + == align_floor(alignof(struct flexible), SIZE_MAX)); + + // Corner case: sizeof(type) > align_ceil(alignof(type), offsetof(type, member)) + // Doesn't happen in typical ABIs + bfs_verify(flex_size(8, 16, 4, 4, 1) == 16); + + return EXIT_SUCCESS; +} diff --git a/tests/bfstd.c b/tests/bfstd.c index 7fea9b5..fa854a8 100644 --- a/tests/bfstd.c +++ b/tests/bfstd.c @@ -24,17 +24,6 @@ static void check_base_dir(const char *path, const char *dir, const char *base) } int main(void) { - // Check flex_sizeof() - struct flexible { - alignas(64) int foo; - int bar[]; - }; - bfs_verify(flex_sizeof(struct flexible, bar, 0) >= sizeof(struct flexible)); - bfs_verify(flex_sizeof(struct flexible, bar, 16) % alignof(struct flexible) == 0); - bfs_verify(flex_sizeof(struct flexible, bar, SIZE_MAX / sizeof(int) + 1) - == align_floor(alignof(struct flexible), SIZE_MAX)); - bfs_verify(flex_sizeof_impl(8, 16, 4, 4, 1) == 16); - // From man 3p basename check_base_dir("usr", ".", "usr"); check_base_dir("usr/", ".", "usr"); @@ -46,4 +35,6 @@ int main(void) { check_base_dir("/usr/lib", "/usr", "lib"); check_base_dir("//usr//lib//", "//usr", "lib"); check_base_dir("/home//dwc//test", "/home//dwc", "test"); + + return EXIT_SUCCESS; } -- cgit v1.2.3 From f0df110ba42a6d23cb222069e4c2a4712d48d9f1 Mon Sep 17 00:00:00 2001 From: Tavian Barnes Date: Sat, 24 Jun 2023 12:47:09 -0400 Subject: bfstd: Add a getprogname() wrapper --- src/bfstd.c | 15 +++++++++++++++ src/bfstd.h | 8 ++++++++ src/diag.c | 12 +----------- 3 files changed, 24 insertions(+), 11 deletions(-) (limited to 'src/bfstd.c') diff --git a/src/bfstd.c b/src/bfstd.c index 0e8ba5f..1f4bbb2 100644 --- a/src/bfstd.c +++ b/src/bfstd.c @@ -143,6 +143,21 @@ char *xgetdelim(FILE *file, char delim) { } } +const char *xgetprogname(void) { + const char *cmd = NULL; +#if __GLIBC__ + cmd = program_invocation_short_name; +#elif BSD + cmd = getprogname(); +#endif + + if (!cmd) { + cmd = BFS_COMMAND; + } + + return cmd; +} + /** Compile and execute a regular expression for xrpmatch(). */ static int xrpregex(nl_item item, const char *response) { const char *pattern = nl_langinfo(item); diff --git a/src/bfstd.h b/src/bfstd.h index cafe28f..ebbcdb9 100644 --- a/src/bfstd.h +++ b/src/bfstd.h @@ -105,6 +105,14 @@ char *xgetdelim(FILE *file, char delim); // #include +/** + * Wrapper for getprogname() or equivalent functionality. + * + * @return + * The basename of the currently running program. + */ +const char *xgetprogname(void); + /** * Process a yes/no prompt. * diff --git a/src/diag.c b/src/diag.c index 99b487a..acea9ad 100644 --- a/src/diag.c +++ b/src/diag.c @@ -14,17 +14,7 @@ #include noreturn void bfs_abortf(const struct bfs_loc *loc, const char *format, ...) { - const char *cmd = NULL; -#if __GLIBC__ - cmd = program_invocation_short_name; -#elif BSD - cmd = getprogname(); -#endif - if (!cmd) { - cmd = BFS_COMMAND; - } - - fprintf(stderr, "%s: %s@%s:%d: ", cmd, loc->func, loc->file, loc->line); + fprintf(stderr, "%s: %s@%s:%d: ", xgetprogname(), loc->func, loc->file, loc->line); va_list args; va_start(args, format); -- cgit v1.2.3 From 187ef092b6ea0f92dac53fbd2deb71379400446e Mon Sep 17 00:00:00 2001 From: Tavian Barnes Date: Thu, 6 Jul 2023 14:16:20 -0400 Subject: wordesc: Also escape non-printable chars --- src/bfstd.c | 145 +++++++++++++++++++++++++++++++++++++++++++++++------------- src/bfstd.h | 32 ++++++++++++++ 2 files changed, 147 insertions(+), 30 deletions(-) (limited to 'src/bfstd.c') diff --git a/src/bfstd.c b/src/bfstd.c index 1f4bbb2..e5f9a31 100644 --- a/src/bfstd.c +++ b/src/bfstd.c @@ -17,6 +17,7 @@ #include #include #include +#include #if BFS_USE_SYS_SYSMACROS_H # include @@ -253,6 +254,24 @@ void *xmemdup(const void *src, size_t size) { return ret; } +char *xstpecpy(char *dest, char *end, const char *src) { + return xstpencpy(dest, end, src, SIZE_MAX); +} + +char *xstpencpy(char *dest, char *end, const char *src, size_t n) { + size_t space = end - dest; + n = space < n ? space : n; + n = strnlen(src, n); + memcpy(dest, src, n); + if (n < space) { + dest[n] = '\0'; + return dest + n; + } else { + end[-1] = '\0'; + return end; + } +} + void xstrmode(mode_t mode, char str[11]) { strcpy(str, "----------"); @@ -555,48 +574,114 @@ size_t xstrwidth(const char *str) { return ret; } -char *wordesc(const char *str) { - size_t len = strlen(str); +/** Get the length of the longest printable prefix of a string. */ +static size_t printable_len(const char *str, size_t len) { + mbstate_t mb; + memset(&mb, 0, sizeof(mb)); - if (strcspn(str, "|&;<>()$`\\\"' \t\n*?[#˜=%") == len) { - // Whole string is safe - // https://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html#tag_18_02 - if (len > 0) { - return strdup(str); - } else { - return strdup("\"\""); + const char *cur = str; + while (len > 0) { + wchar_t wc; + size_t mblen = mbrtowc(&wc, cur, len, &mb); + if (mblen == (size_t)-1 || mblen == (size_t)-2 || !iswprint(wc)) { + break; } - } else if (strcspn(str, "`$\\\"") == len) { - // Safe to double-quote the whole string - // https://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html#tag_18_02_03 - char *ret = malloc(len + 3); - if (!ret) { - return NULL; + cur += mblen; + len -= mblen; + } + + return cur - str; +} + +/** Get the length of the longest unprintable prefix of a string. */ +static size_t unprintable_len(const char *str, size_t len) { + mbstate_t mb; + memset(&mb, 0, sizeof(mb)); + + const char *cur = str; + while (len > 0) { + wchar_t wc; + size_t mblen = mbrtowc(&wc, cur, len, &mb); + if (mblen == (size_t)-1) { + // Invalid byte sequence, try again from the next byte + mblen = 1; + } else if (mblen == (size_t)-2) { + // Incomplete byte sequence, the rest is unprintable + mblen = len; + } else if (iswprint(wc)) { + break; } - char *cur = stpcpy(ret, "\""); - cur = stpcpy(cur, str); - cur = stpcpy(cur, "\""); - return ret; + cur += mblen; + len -= mblen; } - // Every ' is replaced with '\'', so at most a 3x growth - char *ret = malloc(3 * len + 3); + return cur - str; +} + +char *wordesc(const char *str) { + size_t len = strlen(str); + + // Worst case: every char is replaced with $'\xXX', so at most a 7x growth + size_t max_size = 7 * len + 3; + char *ret = malloc(max_size); if (!ret) { return NULL; } + char *cur = ret; + char *end = ret + max_size; - char *cur = stpcpy(ret, "'"); - while (*str) { - size_t chunk = strcspn(str, "'"); - cur = stpncpy(cur, str, chunk); - str += chunk; - if (*str) { - cur = stpcpy(cur, "'\\''"); - ++str; + while (len > 0) { + size_t plen = printable_len(str, len); + if (strcspn(str, "|&;<>()$`\\\"' *?[#˜=%") >= plen) { + // Whole chunk is safe + // https://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html#tag_18_02 + cur = xstpencpy(cur, end, str, plen); + } else if (strcspn(str, "`$\\\"") >= plen) { + // Safe to double-quote the whole chunk + // https://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html#tag_18_02_03 + cur = xstpecpy(cur, end, "\""); + cur = xstpencpy(cur, end, str, plen); + cur = xstpecpy(cur, end, "\""); + } else { + // Single-quote the whole chunk, convert ' into '\'' + cur = xstpecpy(cur, end, "'"); + for (size_t i = 0; i < plen; ++i) { + if (str[i] == '\'') { + cur = xstpecpy(cur, end, "'\\''"); + } else { + cur = xstpencpy(cur, end, &str[i], 1); + } + } + cur = xstpecpy(cur, end, "'"); + } + + str += plen; + len -= plen; + if (len == 0) { + break; } + + // Non-printable characters, write them as $'\xXX\xXX...' + cur = xstpecpy(cur, end, "$'"); + size_t uplen = unprintable_len(str, len); + for (size_t i = 0; i < uplen; ++i) { + static const char *hex[] = {"0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "A", "B", "C", "D", "E", "F"}; + unsigned char byte = str[i]; + cur = xstpecpy(cur, end, "\\x"); + cur = xstpecpy(cur, end, hex[byte / 0x10]); + cur = xstpecpy(cur, end, hex[byte % 0x10]); + } + cur = xstpecpy(cur, end, "'"); + + str += uplen; + len -= uplen; + } + + if (cur == ret) { + cur = xstpecpy(cur, end, "\"\""); } - cur = stpcpy(cur, "'"); + bfs_assert(cur != end, "Result truncated!"); return ret; } diff --git a/src/bfstd.h b/src/bfstd.h index ebbcdb9..832db66 100644 --- a/src/bfstd.h +++ b/src/bfstd.h @@ -134,6 +134,38 @@ int ynprompt(void); */ void *xmemdup(const void *src, size_t size); +/** + * A nice string copying function. + * + * @param dest + * The NUL terminator of the destination string, or `end` if it is + * already truncated. + * @param end + * The end of the destination buffer. + * @param src + * The string to copy from. + * @return + * The new NUL terminator of the destination, or `end` on truncation. + */ +char *xstpecpy(char *dest, char *end, const char *src); + +/** + * A nice string copying function. + * + * @param dest + * The NUL terminator of the destination string, or `end` if it is + * already truncated. + * @param end + * The end of the destination buffer. + * @param src + * The string to copy from. + * @param n + * The maximum number of characters to copy. + * @return + * The new NUL terminator of the destination, or `end` on truncation. + */ +char *xstpencpy(char *dest, char *end, const char *src, size_t n); + /** * Format a mode like ls -l (e.g. -rw-r--r--). * -- cgit v1.2.3 From 2cb1ae0b2ecc356706318948839cc80def53fb5e Mon Sep 17 00:00:00 2001 From: Tavian Barnes Date: Thu, 13 Jul 2023 11:06:51 -0400 Subject: bfstd: Escape '!' in wordesc() --- src/bfstd.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src/bfstd.c') diff --git a/src/bfstd.c b/src/bfstd.c index e5f9a31..e338831 100644 --- a/src/bfstd.c +++ b/src/bfstd.c @@ -633,11 +633,11 @@ char *wordesc(const char *str) { while (len > 0) { size_t plen = printable_len(str, len); - if (strcspn(str, "|&;<>()$`\\\"' *?[#˜=%") >= plen) { + if (strcspn(str, "|&;<>()$`\\\"' *?[#˜=%!") >= plen) { // Whole chunk is safe // https://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html#tag_18_02 cur = xstpencpy(cur, end, str, plen); - } else if (strcspn(str, "`$\\\"") >= plen) { + } else if (strcspn(str, "`$\\\"!") >= plen) { // Safe to double-quote the whole chunk // https://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html#tag_18_02_03 cur = xstpecpy(cur, end, "\""); -- cgit v1.2.3 From 36fed99f5929782b61018d2d2e5a2800fba5e530 Mon Sep 17 00:00:00 2001 From: Tavian Barnes Date: Thu, 13 Jul 2023 11:07:05 -0400 Subject: bfstd: Use $'\n' etc. over $'\x0A' --- src/bfstd.c | 40 +++++++++++++++++++++++++++++++++++----- 1 file changed, 35 insertions(+), 5 deletions(-) (limited to 'src/bfstd.c') diff --git a/src/bfstd.c b/src/bfstd.c index e338831..e125be6 100644 --- a/src/bfstd.c +++ b/src/bfstd.c @@ -619,6 +619,31 @@ static size_t unprintable_len(const char *str, size_t len) { return cur - str; } +/** Convert a special char into a well-known escape sequence like "\n". */ +static const char *c_esc(char c) { + // https://www.gnu.org/software/bash/manual/html_node/ANSI_002dC-Quoting.html + switch (c) { + case '\a': + return "\\a"; + case '\b': + return "\\b"; + case '\033': + return "\\e"; + case '\f': + return "\\f"; + case '\n': + return "\\n"; + case '\r': + return "\\r"; + case '\t': + return "\\t"; + case '\v': + return "\\v"; + default: + return NULL; + } +} + char *wordesc(const char *str) { size_t len = strlen(str); @@ -666,11 +691,16 @@ char *wordesc(const char *str) { cur = xstpecpy(cur, end, "$'"); size_t uplen = unprintable_len(str, len); for (size_t i = 0; i < uplen; ++i) { - static const char *hex[] = {"0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "A", "B", "C", "D", "E", "F"}; - unsigned char byte = str[i]; - cur = xstpecpy(cur, end, "\\x"); - cur = xstpecpy(cur, end, hex[byte / 0x10]); - cur = xstpecpy(cur, end, hex[byte % 0x10]); + const char *esc = c_esc(str[i]); + if (esc) { + cur = xstpecpy(cur, end, esc); + } else { + static const char *hex[] = {"0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "A", "B", "C", "D", "E", "F"}; + unsigned char byte = str[i]; + cur = xstpecpy(cur, end, "\\x"); + cur = xstpecpy(cur, end, hex[byte / 0x10]); + cur = xstpecpy(cur, end, hex[byte % 0x10]); + } } cur = xstpecpy(cur, end, "'"); -- cgit v1.2.3 From e79f0d038d3ce916e744fd111b70d687f699c0bd Mon Sep 17 00:00:00 2001 From: Tavian Barnes Date: Thu, 13 Jul 2023 12:36:10 -0400 Subject: bfstd: Quote the whole string the same way in wordesc() --- src/bfstd.c | 178 ++++++++++++++++++++++++++++++++++-------------------------- 1 file changed, 101 insertions(+), 77 deletions(-) (limited to 'src/bfstd.c') diff --git a/src/bfstd.c b/src/bfstd.c index e125be6..6f39f54 100644 --- a/src/bfstd.c +++ b/src/bfstd.c @@ -593,34 +593,8 @@ static size_t printable_len(const char *str, size_t len) { return cur - str; } -/** Get the length of the longest unprintable prefix of a string. */ -static size_t unprintable_len(const char *str, size_t len) { - mbstate_t mb; - memset(&mb, 0, sizeof(mb)); - - const char *cur = str; - while (len > 0) { - wchar_t wc; - size_t mblen = mbrtowc(&wc, cur, len, &mb); - if (mblen == (size_t)-1) { - // Invalid byte sequence, try again from the next byte - mblen = 1; - } else if (mblen == (size_t)-2) { - // Incomplete byte sequence, the rest is unprintable - mblen = len; - } else if (iswprint(wc)) { - break; - } - - cur += mblen; - len -= mblen; - } - - return cur - str; -} - /** Convert a special char into a well-known escape sequence like "\n". */ -static const char *c_esc(char c) { +static const char *dollar_esc(char c) { // https://www.gnu.org/software/bash/manual/html_node/ANSI_002dC-Quoting.html switch (c) { case '\a': @@ -639,73 +613,123 @@ static const char *c_esc(char c) { return "\\t"; case '\v': return "\\v"; + case '\'': + return "\\'"; + case '\\': + return "\\\\"; default: return NULL; } } -char *wordesc(const char *str) { - size_t len = strlen(str); +/** $'Quote' a string for the shell. */ +static char *dollar_quote(char *dest, char *end, const char *str, size_t len) { + static const char *hex[] = {"0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "A", "B", "C", "D", "E", "F"}; - // Worst case: every char is replaced with $'\xXX', so at most a 7x growth - size_t max_size = 7 * len + 3; - char *ret = malloc(max_size); - if (!ret) { - return NULL; - } - char *cur = ret; - char *end = ret + max_size; + dest = xstpecpy(dest, end, "$'"); while (len > 0) { size_t plen = printable_len(str, len); - if (strcspn(str, "|&;<>()$`\\\"' *?[#˜=%!") >= plen) { - // Whole chunk is safe - // https://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html#tag_18_02 - cur = xstpencpy(cur, end, str, plen); - } else if (strcspn(str, "`$\\\"!") >= plen) { - // Safe to double-quote the whole chunk - // https://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html#tag_18_02_03 - cur = xstpecpy(cur, end, "\""); - cur = xstpencpy(cur, end, str, plen); - cur = xstpecpy(cur, end, "\""); + size_t elen = strcspn(str, "'\\"); + size_t min = plen < elen ? plen : elen; + dest = xstpencpy(dest, end, str, min); + str += min; + len -= min; + if (len == 0) { + break; + } + + unsigned char byte = *str; + ++str; + --len; + + const char *esc = dollar_esc(byte); + if (esc) { + dest = xstpecpy(dest, end, esc); } else { - // Single-quote the whole chunk, convert ' into '\'' - cur = xstpecpy(cur, end, "'"); - for (size_t i = 0; i < plen; ++i) { - if (str[i] == '\'') { - cur = xstpecpy(cur, end, "'\\''"); - } else { - cur = xstpencpy(cur, end, &str[i], 1); - } - } - cur = xstpecpy(cur, end, "'"); + dest = xstpecpy(dest, end, "\\x"); + dest = xstpecpy(dest, end, hex[byte / 0x10]); + dest = xstpecpy(dest, end, hex[byte % 0x10]); } + } - str += plen; - len -= plen; - if (len == 0) { - break; + return xstpecpy(dest, end, "'"); +} + +/** How much of this string is safe as a bare word? */ +static size_t bare_len(const char *str) { + // https://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html#tag_18_02 + return strcspn(str, "|&;<>()$`\\\"' *?[#˜=%!"); +} + +/** How much of this string is safe to double-quote? */ +static size_t quotable_len(const char *str) { + // https://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html#tag_18_02_03 + return strcspn(str, "`$\\\"!"); +} + +/** "Quote" a string for the shell. */ +static char *double_quote(char *dest, char *end, const char *str) { + dest = xstpecpy(dest, end, "\""); + dest = xstpecpy(dest, end, str); + return xstpecpy(dest, end, "\""); +} + +/** 'Quote' a string for the shell. */ +static char *single_quote(char *dest, char *end, const char *str) { + bool open = false; + + while (*str) { + size_t len = strcspn(str, "'"); + if (len > 0) { + if (!open) { + dest = xstpecpy(dest, end, "'"); + open = true; + } + dest = xstpencpy(dest, end, str, len); + str += len; } - // Non-printable characters, write them as $'\xXX\xXX...' - cur = xstpecpy(cur, end, "$'"); - size_t uplen = unprintable_len(str, len); - for (size_t i = 0; i < uplen; ++i) { - const char *esc = c_esc(str[i]); - if (esc) { - cur = xstpecpy(cur, end, esc); - } else { - static const char *hex[] = {"0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "A", "B", "C", "D", "E", "F"}; - unsigned char byte = str[i]; - cur = xstpecpy(cur, end, "\\x"); - cur = xstpecpy(cur, end, hex[byte / 0x10]); - cur = xstpecpy(cur, end, hex[byte % 0x10]); + while (*str == '\'') { + if (open) { + dest = xstpecpy(dest, end, "'"); + open = false; } + dest = xstpecpy(dest, end, "\\'"); + ++str; } - cur = xstpecpy(cur, end, "'"); + } - str += uplen; - len -= uplen; + if (open) { + dest = xstpecpy(dest, end, "'"); + } + return dest; +} + +char *wordesc(const char *str) { + size_t len = strlen(str); + + // Worst case: every char is replaced with $'\xXX', so at most a 7x growth + size_t max_size = 7 * len + 3; + char *ret = malloc(max_size); + if (!ret) { + return NULL; + } + char *cur = ret; + char *end = ret + max_size; + + if (printable_len(str, len) < len) { + // String contains unprintable chars, use $'this\x7Fsyntax' + cur = dollar_quote(cur, end, str, len); + } else if (bare_len(str) == len) { + // Whole string is safe as a bare word + cur = xstpecpy(cur, end, str); + } else if (quotable_len(str) == len) { + // Whole string is safe to double-quote + cur = double_quote(cur, end, str); + } else { + // Single-quote the whole string + cur = single_quote(cur, end, str); } if (cur == ret) { -- cgit v1.2.3 From 2c396fce53100cad4e472f29851f07030a80ee50 Mon Sep 17 00:00:00 2001 From: Tavian Barnes Date: Thu, 13 Jul 2023 13:30:16 -0400 Subject: bfstd: Support wordesc() without allocating --- src/bfstd.c | 92 +++++++++++++++++++++++++++++++++++------------------------ src/bfstd.h | 47 +++++++++++++++++++++++++++--- src/color.c | 20 +++++-------- src/diag.c | 29 ++++++++++--------- src/diag.h | 4 +-- src/dstring.c | 22 ++++++++++++++ src/dstring.h | 31 ++++++++++++++++++++ 7 files changed, 175 insertions(+), 70 deletions(-) (limited to 'src/bfstd.c') diff --git a/src/bfstd.c b/src/bfstd.c index 6f39f54..97fa3b3 100644 --- a/src/bfstd.c +++ b/src/bfstd.c @@ -10,6 +10,7 @@ #include #include #include +#include #include #include #include @@ -575,7 +576,7 @@ size_t xstrwidth(const char *str) { } /** Get the length of the longest printable prefix of a string. */ -static size_t printable_len(const char *str, size_t len) { +static size_t printable_len(const char *str, size_t len, enum wesc_flags flags) { mbstate_t mb; memset(&mb, 0, sizeof(mb)); @@ -583,9 +584,23 @@ static size_t printable_len(const char *str, size_t len) { while (len > 0) { wchar_t wc; size_t mblen = mbrtowc(&wc, cur, len, &mb); - if (mblen == (size_t)-1 || mblen == (size_t)-2 || !iswprint(wc)) { + if (mblen == (size_t)-1 || mblen == (size_t)-2) { break; } + + bool safe = iswprint(wc); + + // Technically a literal newline is safe inside single quotes, + // but $'\n' is much nicer than ' + // ' + if (!(flags & WESC_SHELL) && iswspace(wc)) { + safe = true; + } + + if (!safe) { + break; + } + cur += mblen; len -= mblen; } @@ -623,13 +638,13 @@ static const char *dollar_esc(char c) { } /** $'Quote' a string for the shell. */ -static char *dollar_quote(char *dest, char *end, const char *str, size_t len) { +static char *dollar_quote(char *dest, char *end, const char *str, size_t len, enum wesc_flags flags) { static const char *hex[] = {"0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "A", "B", "C", "D", "E", "F"}; dest = xstpecpy(dest, end, "$'"); while (len > 0) { - size_t plen = printable_len(str, len); + size_t plen = printable_len(str, len, flags); size_t elen = strcspn(str, "'\\"); size_t min = plen < elen ? plen : elen; dest = xstpencpy(dest, end, str, min); @@ -657,85 +672,86 @@ static char *dollar_quote(char *dest, char *end, const char *str, size_t len) { } /** How much of this string is safe as a bare word? */ -static size_t bare_len(const char *str) { +static size_t bare_len(const char *str, size_t len) { // https://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html#tag_18_02 - return strcspn(str, "|&;<>()$`\\\"' *?[#˜=%!"); + size_t ret = strcspn(str, "|&;<>()$`\\\"' *?[#˜=%!"); + return ret < len ? ret : len; } /** How much of this string is safe to double-quote? */ -static size_t quotable_len(const char *str) { +static size_t quotable_len(const char *str, size_t len) { // https://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html#tag_18_02_03 - return strcspn(str, "`$\\\"!"); + size_t ret = strcspn(str, "`$\\\"!"); + return ret < len ? ret : len; } /** "Quote" a string for the shell. */ -static char *double_quote(char *dest, char *end, const char *str) { +static char *double_quote(char *dest, char *end, const char *str, size_t len) { dest = xstpecpy(dest, end, "\""); - dest = xstpecpy(dest, end, str); + dest = xstpencpy(dest, end, str, len); return xstpecpy(dest, end, "\""); } /** 'Quote' a string for the shell. */ -static char *single_quote(char *dest, char *end, const char *str) { +static char *single_quote(char *dest, char *end, const char *str, size_t len) { bool open = false; - while (*str) { - size_t len = strcspn(str, "'"); - if (len > 0) { + while (len > 0) { + size_t chunk = strcspn(str, "'"); + chunk = chunk < len ? chunk : len; + if (chunk > 0) { if (!open) { dest = xstpecpy(dest, end, "'"); open = true; } - dest = xstpencpy(dest, end, str, len); - str += len; + dest = xstpencpy(dest, end, str, chunk); + str += chunk; + len -= chunk; } - while (*str == '\'') { + while (len > 0 && *str == '\'') { if (open) { dest = xstpecpy(dest, end, "'"); open = false; } dest = xstpecpy(dest, end, "\\'"); ++str; + --len; } } if (open) { dest = xstpecpy(dest, end, "'"); } + return dest; } -char *wordesc(const char *str) { - size_t len = strlen(str); +char *wordesc(char *dest, char *end, const char *str, enum wesc_flags flags) { + return wordnesc(dest, end, str, SIZE_MAX, flags); +} - // Worst case: every char is replaced with $'\xXX', so at most a 7x growth - size_t max_size = 7 * len + 3; - char *ret = malloc(max_size); - if (!ret) { - return NULL; - } - char *cur = ret; - char *end = ret + max_size; +char *wordnesc(char *dest, char *end, const char *str, size_t n, enum wesc_flags flags) { + size_t len = strnlen(str, n); + char *start = dest; - if (printable_len(str, len) < len) { + if (printable_len(str, len, flags) < len) { // String contains unprintable chars, use $'this\x7Fsyntax' - cur = dollar_quote(cur, end, str, len); - } else if (bare_len(str) == len) { + dest = dollar_quote(dest, end, str, len, flags); + } else if (!(flags & WESC_SHELL) || bare_len(str, len) == len) { // Whole string is safe as a bare word - cur = xstpecpy(cur, end, str); - } else if (quotable_len(str) == len) { + dest = xstpencpy(dest, end, str, len); + } else if (quotable_len(str, len) == len) { // Whole string is safe to double-quote - cur = double_quote(cur, end, str); + dest = double_quote(dest, end, str, len); } else { // Single-quote the whole string - cur = single_quote(cur, end, str); + dest = single_quote(dest, end, str, len); } - if (cur == ret) { - cur = xstpecpy(cur, end, "\"\""); + if (dest == start) { + dest = xstpecpy(dest, end, "\"\""); } - bfs_assert(cur != end, "Result truncated!"); - return ret; + return dest; } diff --git a/src/bfstd.h b/src/bfstd.h index 832db66..fb77399 100644 --- a/src/bfstd.h +++ b/src/bfstd.h @@ -319,15 +319,54 @@ size_t xstrwidth(const char *str); // #include +/** + * Flags for wordesc(). + */ +enum wesc_flags { + /** + * Escape special characters so that the shell will treat the escaped + * string as a single word. + */ + WESC_SHELL = 1 << 0, + /** + * Escape special characters so that the escaped string is safe to print + * to a TTY. + */ + WESC_TTY = 1 << 1, +}; + /** * Escape a string as a single shell word. * - * @param str + * @param dest + * The destination string to fill. + * @param end + * The end of the destination buffer. + * @param src + * The string to escape. + * @param flags + * Controls which characters to escape. + * @return + * The new NUL terminator of the destination, or `end` on truncation. + */ +char *wordesc(char *dest, char *end, const char *str, enum wesc_flags flags); + +/** + * Escape a string as a single shell word. + * + * @param dest + * The destination string to fill. + * @param end + * The end of the destination buffer. + * @param src * The string to escape. + * @param n + * The maximum length of the string. + * @param flags + * Controls which characters to escape. * @return - * A string that a shell would evaluate to str, dynamically allocated, - * or NULL on failure. + * The new NUL terminator of the destination, or `end` on truncation. */ -char *wordesc(const char *str); +char *wordnesc(char *dest, char *end, const char *str, size_t n, enum wesc_flags flags); #endif // BFS_BFSTD_H diff --git a/src/color.c b/src/color.c index 2e039f4..0f5829f 100644 --- a/src/color.c +++ b/src/color.c @@ -16,6 +16,7 @@ #include #include #include +#include #include #include #include @@ -891,6 +892,11 @@ static int print_reset(CFILE *cfile) { } } +/** Print a shell-escaped string. */ +static int print_wordesc(CFILE *cfile, const char *str, size_t n, enum wesc_flags flags) { + return dstrnescat(&cfile->buffer, str, n, flags); +} + /** Print a string with an optional color. */ static int print_colored(CFILE *cfile, const struct esc_seq *esc, const char *str, size_t len) { if (print_esc(cfile, esc) != 0) { @@ -1069,18 +1075,6 @@ static int print_link_target(CFILE *cfile, const struct BFTW *ftwbuf) { return ret; } -/** Print an shell-escaped string. */ -static int print_wordesc(CFILE *cfile, const char *str) { - char *esc = wordesc(str); - if (!esc) { - return -1; - } - - int ret = dstrcat(&cfile->buffer, esc); - free(esc); - return ret; -} - /** Format some colored output to the buffer. */ BFS_FORMATTER(2, 3) static int cbuff(CFILE *cfile, const char *format, ...); @@ -1224,7 +1218,7 @@ static int cvbuff(CFILE *cfile, const char *format, va_list args) { case 'p': switch (*++i) { case 'q': - if (print_wordesc(cfile, va_arg(args, const char *)) != 0) { + if (print_wordesc(cfile, va_arg(args, const char *), SIZE_MAX, WESC_SHELL | WESC_TTY) != 0) { return -1; } break; diff --git a/src/diag.c b/src/diag.c index acea9ad..0590847 100644 --- a/src/diag.c +++ b/src/diag.c @@ -2,6 +2,7 @@ // SPDX-License-Identifier: 0BSD #include "diag.h" +#include "alloc.h" #include "bfstd.h" #include "ctx.h" #include "color.h" @@ -114,7 +115,7 @@ bool bfs_debug_prefix(const struct bfs_ctx *ctx, enum debug_flags flag) { } /** Recursive part of highlight_expr(). */ -static bool highlight_expr_recursive(const struct bfs_ctx *ctx, const struct bfs_expr *expr, bool *args) { +static bool highlight_expr_recursive(const struct bfs_ctx *ctx, const struct bfs_expr *expr, bool args[]) { if (!expr) { return false; } @@ -141,7 +142,7 @@ static bool highlight_expr_recursive(const struct bfs_ctx *ctx, const struct bfs } /** Highlight an expression in the command line. */ -static bool highlight_expr(const struct bfs_ctx *ctx, const struct bfs_expr *expr, bool *args) { +static bool highlight_expr(const struct bfs_ctx *ctx, const struct bfs_expr *expr, bool args[]) { for (size_t i = 0; i < ctx->argc; ++i) { args[i] = false; } @@ -150,21 +151,21 @@ static bool highlight_expr(const struct bfs_ctx *ctx, const struct bfs_expr *exp } /** Print a highlighted portion of the command line. */ -static void bfs_argv_diag(const struct bfs_ctx *ctx, const bool *args, bool warning) { +static void bfs_argv_diag(const struct bfs_ctx *ctx, const bool args[], bool warning) { if (warning) { bfs_warning_prefix(ctx); } else { bfs_error_prefix(ctx); } - char *argv[ctx->argc]; + char **argv = ZALLOC_ARRAY(char *, ctx->argc); + if (!argv) { + return; + } + for (size_t i = 0; i < ctx->argc; ++i) { - argv[i] = wordesc(ctx->argv[i]); - if (!argv[i]) { - for (size_t j = 0; j < i; ++j) { - free(argv[j]); - } - return; + if (dstrescat(&argv[i], ctx->argv[i], WESC_SHELL | WESC_TTY) != 0) { + goto done; } } @@ -223,12 +224,14 @@ static void bfs_argv_diag(const struct bfs_ctx *ctx, const bool *args, bool warn cfprintf(ctx->cerr, "\n"); +done: for (size_t i = 0; i < ctx->argc; ++i) { - free(argv[i]); + dstrfree(argv[i]); } + free(argv); } -void bfs_argv_error(const struct bfs_ctx *ctx, const bool *args) { +void bfs_argv_error(const struct bfs_ctx *ctx, const bool args[]) { bfs_argv_diag(ctx, args, false); } @@ -239,7 +242,7 @@ void bfs_expr_error(const struct bfs_ctx *ctx, const struct bfs_expr *expr) { } } -bool bfs_argv_warning(const struct bfs_ctx *ctx, const bool *args) { +bool bfs_argv_warning(const struct bfs_ctx *ctx, const bool args[]) { if (!ctx->warn) { return false; } diff --git a/src/diag.h b/src/diag.h index c909da5..e019db0 100644 --- a/src/diag.h +++ b/src/diag.h @@ -149,7 +149,7 @@ bool bfs_debug_prefix(const struct bfs_ctx *ctx, enum debug_flags flag); /** * Highlight parts of the command line in an error message. */ -void bfs_argv_error(const struct bfs_ctx *ctx, const bool *args); +void bfs_argv_error(const struct bfs_ctx *ctx, const bool args[]); /** * Highlight parts of an expression in an error message. @@ -159,7 +159,7 @@ void bfs_expr_error(const struct bfs_ctx *ctx, const struct bfs_expr *expr); /** * Highlight parts of the command line in a warning message. */ -bool bfs_argv_warning(const struct bfs_ctx *ctx, const bool *args); +bool bfs_argv_warning(const struct bfs_ctx *ctx, const bool args[]); /** * Highlight parts of an expression in a warning message. diff --git a/src/dstring.c b/src/dstring.c index dada70b..60a7df9 100644 --- a/src/dstring.c +++ b/src/dstring.c @@ -232,6 +232,28 @@ fail: return -1; } +int dstrescat(char **dest, const char *str, enum wesc_flags flags) { + return dstrnescat(dest, str, SIZE_MAX, flags); +} + +int dstrnescat(char **dest, const char *str, size_t n, enum wesc_flags flags) { + size_t len = *dest ? dstrlen(*dest) : 0; + + // Worst case growth is `ccc...` => $'\xCC\xCC\xCC...' + n = strnlen(str, n); + size_t cap = len + 4 * n + 3; + if (dstreserve(dest, cap) != 0) { + return -1; + } + + char *cur = *dest + len; + char *end = *dest + cap + 1; + cur = wordnesc(cur, end, str, n, flags); + bfs_assert(cur != end, "wordesc() result truncated"); + + return dstresize(dest, cur - *dest); +} + void dstrfree(char *dstr) { if (dstr) { free(dstrheader(dstr)); diff --git a/src/dstring.h b/src/dstring.h index 2673f1b..88ca79f 100644 --- a/src/dstring.h +++ b/src/dstring.h @@ -8,6 +8,7 @@ #ifndef BFS_DSTRING_H #define BFS_DSTRING_H +#include "bfstd.h" #include "config.h" #include #include @@ -261,6 +262,36 @@ int dstrcatf(char **str, const char *format, ...); BFS_FORMATTER(2, 0) int dstrvcatf(char **str, const char *format, va_list args); +/** + * Concatenate while shell-escaping. + * + * @param dest + * The destination dynamic string. + * @param str + * The string to escape. + * @param flags + * Flags for wordesc(). + * @return + * 0 on success, -1 on failure. + */ +int dstrescat(char **dest, const char *str, enum wesc_flags flags); + +/** + * Concatenate while shell-escaping. + * + * @param dest + * The destination dynamic string. + * @param str + * The string to escape. + * @param n + * The maximum length of the string. + * @param flags + * Flags for wordesc(). + * @return + * 0 on success, -1 on failure. + */ +int dstrnescat(char **dest, const char *str, size_t n, enum wesc_flags flags); + /** * Free a dynamic string. * -- cgit v1.2.3 From 19c96abe0a1ee56cf206fd5e87defb1fd3e0daa5 Mon Sep 17 00:00:00 2001 From: Tavian Barnes Date: Thu, 13 Jul 2023 20:00:11 -0400 Subject: bfstd: Add an ASCII fast path to wordesc() --- src/bfstd.c | 159 ++++++++++++++++++++++++++++++++++++++---------------------- 1 file changed, 100 insertions(+), 59 deletions(-) (limited to 'src/bfstd.c') diff --git a/src/bfstd.c b/src/bfstd.c index 97fa3b3..49c4a70 100644 --- a/src/bfstd.c +++ b/src/bfstd.c @@ -6,6 +6,7 @@ #include "config.h" #include "diag.h" #include "xregex.h" +#include #include #include #include @@ -540,6 +541,25 @@ int xstrtofflags(const char **str, unsigned long long *set, unsigned long long * #endif } +/** mbrtowc() wrapper. */ +static int xmbrtowc(wchar_t *wc, size_t *i, const char *str, size_t len, mbstate_t *mb) { + size_t mblen = mbrtowc(wc, str + *i, len - *i, mb); + switch (mblen) { + case -1: + // Invalid byte sequence + *i += 1; + memset(mb, 0, sizeof(*mb)); + return -1; + case -2: + // Incomplete byte sequence + *i += len; + return -1; + default: + *i += mblen; + return 0; + } +} + size_t xstrwidth(const char *str) { size_t len = strlen(str); size_t ret = 0; @@ -547,65 +567,76 @@ size_t xstrwidth(const char *str) { mbstate_t mb; memset(&mb, 0, sizeof(mb)); - while (len > 0) { + for (size_t i = 0; i < len;) { wchar_t wc; - size_t mblen = mbrtowc(&wc, str, len, &mb); - int cwidth; - if (mblen == (size_t)-1) { - // Invalid byte sequence, assume a single-width '?' - mblen = 1; - cwidth = 1; - memset(&mb, 0, sizeof(mb)); - } else if (mblen == (size_t)-2) { - // Incomplete byte sequence, assume a single-width '?' - mblen = len; - cwidth = 1; + if (xmbrtowc(&wc, &i, str, len, &mb) == 0) { + ret += wcwidth(wc); } else { - cwidth = wcwidth(wc); - if (cwidth < 0) { - cwidth = 0; - } + // Assume a single-width '?' + ++ret; } - - str += mblen; - len -= mblen; - ret += cwidth; } return ret; } +/** Check if a character is printable. */ +static bool xisprint(unsigned char c, enum wesc_flags flags) { + if (isprint(c)) { + return true; + } + + // Technically a literal newline is safe inside single quotes, but $'\n' + // is much nicer than ' + // ' + if (!(flags & WESC_SHELL) && isspace(c)) { + return true; + } + + return false; +} + +/** Check if a wide character is printable. */ +static bool xiswprint(wchar_t c, enum wesc_flags flags) { + if (iswprint(c)) { + return true; + } + + if (!(flags & WESC_SHELL) && iswspace(c)) { + return true; + } + + return false; +} + /** Get the length of the longest printable prefix of a string. */ static size_t printable_len(const char *str, size_t len, enum wesc_flags flags) { + // Fast path: avoid multibyte checks + size_t i; + for (i = 0; i < len; ++i) { + unsigned char c = str[i]; + if (!isascii(c)) { + break; + } + if (!xisprint(c, flags)) { + return i; + } + } + mbstate_t mb; memset(&mb, 0, sizeof(mb)); - const char *cur = str; - while (len > 0) { + while (i < len) { wchar_t wc; - size_t mblen = mbrtowc(&wc, cur, len, &mb); - if (mblen == (size_t)-1 || mblen == (size_t)-2) { + if (xmbrtowc(&wc, &i, str, len, &mb) != 0) { break; } - - bool safe = iswprint(wc); - - // Technically a literal newline is safe inside single quotes, - // but $'\n' is much nicer than ' - // ' - if (!(flags & WESC_SHELL) && iswspace(wc)) { - safe = true; - } - - if (!safe) { + if (!xiswprint(wc, flags)) { break; } - - cur += mblen; - len -= mblen; } - return cur - str; + return i; } /** Convert a special char into a well-known escape sequence like "\n". */ @@ -639,32 +670,42 @@ static const char *dollar_esc(char c) { /** $'Quote' a string for the shell. */ static char *dollar_quote(char *dest, char *end, const char *str, size_t len, enum wesc_flags flags) { - static const char *hex[] = {"0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "A", "B", "C", "D", "E", "F"}; - dest = xstpecpy(dest, end, "$'"); - while (len > 0) { - size_t plen = printable_len(str, len, flags); - size_t elen = strcspn(str, "'\\"); - size_t min = plen < elen ? plen : elen; - dest = xstpencpy(dest, end, str, min); - str += min; - len -= min; - if (len == 0) { - break; + mbstate_t mb; + memset(&mb, 0, sizeof(mb)); + + for (size_t i = 0; i < len;) { + size_t start = i; + bool safe = false; + + wchar_t wc; + if (xmbrtowc(&wc, &i, str, len, &mb) == 0) { + safe = xiswprint(wc, flags); } - unsigned char byte = *str; - ++str; - --len; + for (size_t j = start; j < i; ++j) { + if (str[j] == '\'' || str[j] == '\\') { + safe = false; + break; + } + } - const char *esc = dollar_esc(byte); - if (esc) { - dest = xstpecpy(dest, end, esc); + if (safe) { + dest = xstpencpy(dest, end, str + start, i - start); } else { - dest = xstpecpy(dest, end, "\\x"); - dest = xstpecpy(dest, end, hex[byte / 0x10]); - dest = xstpecpy(dest, end, hex[byte % 0x10]); + for (size_t j = start; j < i; ++j) { + unsigned char byte = str[j]; + const char *esc = dollar_esc(byte); + if (esc) { + dest = xstpecpy(dest, end, esc); + } else { + static const char *hex[] = {"0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "A", "B", "C", "D", "E", "F"}; + dest = xstpecpy(dest, end, "\\x"); + dest = xstpecpy(dest, end, hex[byte / 0x10]); + dest = xstpecpy(dest, end, hex[byte % 0x10]); + } + } } } -- cgit v1.2.3 From 39baf8a76ddefe3a9f02fc1170b213939ab2d5c2 Mon Sep 17 00:00:00 2001 From: Tavian Barnes Date: Mon, 7 Aug 2023 18:29:19 -0400 Subject: bfstd: Speed up wordesc() by caching isprint()/isspace() --- src/bfstd.c | 31 +++++++++++++++++++++++++++++-- 1 file changed, 29 insertions(+), 2 deletions(-) (limited to 'src/bfstd.c') diff --git a/src/bfstd.c b/src/bfstd.c index 49c4a70..9cfd09c 100644 --- a/src/bfstd.c +++ b/src/bfstd.c @@ -5,6 +5,7 @@ #include "bit.h" #include "config.h" #include "diag.h" +#include "thread.h" #include "xregex.h" #include #include @@ -580,16 +581,39 @@ size_t xstrwidth(const char *str) { return ret; } +/** + * Character type flags. + */ +enum ctype { + IS_PRINT = 1 << 0, + IS_SPACE = 1 << 1, +}; + +/** Cached ctypes. */ +static unsigned char ctype_cache[UCHAR_MAX + 1]; + +/** Initialize the ctype cache. */ +static void char_cache_init(void) { + for (size_t c = 0; c <= UCHAR_MAX; ++c) { + if (isprint(c)) { + ctype_cache[c] |= IS_PRINT; + } + if (isspace(c)) { + ctype_cache[c] |= IS_SPACE; + } + } +} + /** Check if a character is printable. */ static bool xisprint(unsigned char c, enum wesc_flags flags) { - if (isprint(c)) { + if (ctype_cache[c] & IS_PRINT) { return true; } // Technically a literal newline is safe inside single quotes, but $'\n' // is much nicer than ' // ' - if (!(flags & WESC_SHELL) && isspace(c)) { + if (!(flags & WESC_SHELL) && (ctype_cache[c] & IS_SPACE)) { return true; } @@ -611,6 +635,9 @@ static bool xiswprint(wchar_t c, enum wesc_flags flags) { /** Get the length of the longest printable prefix of a string. */ static size_t printable_len(const char *str, size_t len, enum wesc_flags flags) { + static pthread_once_t once = PTHREAD_ONCE_INIT; + call_once(&once, char_cache_init); + // Fast path: avoid multibyte checks size_t i; for (i = 0; i < len; ++i) { -- cgit v1.2.3 From 2bc5a379b5f4f6a35465a2df19107209ed191d06 Mon Sep 17 00:00:00 2001 From: Tavian Barnes Date: Mon, 7 Aug 2023 19:41:12 -0400 Subject: bfstd: Check multiple chars at once for isascii() --- src/bfstd.c | 23 ++++++++++++++++++++--- 1 file changed, 20 insertions(+), 3 deletions(-) (limited to 'src/bfstd.c') diff --git a/src/bfstd.c b/src/bfstd.c index 9cfd09c..a71e4b4 100644 --- a/src/bfstd.c +++ b/src/bfstd.c @@ -639,17 +639,34 @@ static size_t printable_len(const char *str, size_t len, enum wesc_flags flags) call_once(&once, char_cache_init); // Fast path: avoid multibyte checks - size_t i; - for (i = 0; i < len; ++i) { + size_t i, word; + for (i = 0; i + sizeof(word) <= len;) { + // Word-at-a-time isascii() + memcpy(&word, str + i, sizeof(word)); + // 0xFFFF... / 0xFF == 0x10101... + size_t mask = (SIZE_MAX / 0xFF) << 7; + if (word & mask) { + goto multibyte; + } + + for (size_t j = 0; j < sizeof(word); ++i, ++j) { + if (!xisprint(str[i], flags)) { + return i; + } + } + } + + for (; i < len; ++i) { unsigned char c = str[i]; if (!isascii(c)) { - break; + goto multibyte; } if (!xisprint(c, flags)) { return i; } } +multibyte: mbstate_t mb; memset(&mb, 0, sizeof(mb)); -- cgit v1.2.3 From a63078374d83a00e8f2bafb9dbc27c3c3d362971 Mon Sep 17 00:00:00 2001 From: Tavian Barnes Date: Tue, 8 Aug 2023 15:11:45 -0400 Subject: bfstd: Don't label a declaration --- src/bfstd.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/bfstd.c') diff --git a/src/bfstd.c b/src/bfstd.c index a71e4b4..e546a47 100644 --- a/src/bfstd.c +++ b/src/bfstd.c @@ -666,8 +666,8 @@ static size_t printable_len(const char *str, size_t len, enum wesc_flags flags) } } -multibyte: mbstate_t mb; +multibyte: memset(&mb, 0, sizeof(mb)); while (i < len) { -- cgit v1.2.3 From 377709664480a30fa5acdd11c7ca8c16669678ce Mon Sep 17 00:00:00 2001 From: Tavian Barnes Date: Wed, 6 Sep 2023 14:59:59 -0400 Subject: bfstd: Fix an OOB string index in xmbrtowc() This bug could be reproduced with something like $ bfs -samefile $'\xFA\xFA' bfs: error: bfs: dstrnescat@src/dstring.c:252: wordesc() result truncated or worse, with -DNDEBUG, $ bfs -samefile $'.....................\xFA\xFA' bfs: error: bfs -samefile $'.....................\xFA\xFA\x00\x55\x53\x45\x52\x3D\x74\x61\x76\x69\x61\x6E\x61\x74\x6F\x72 bfs: error: ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ bfs: error: No such file or directory. which prints the memory after the end of the string (in this case, the environment variable USER=tavianator). The bug was caused by the line `*i += len`, which was intended to be `*i = len`. But actually, the right behaviour seems to be `*i += 1`. Fixes: 19c96abe0a1ee56cf206fd5e87defb1fd3e0daa5 --- src/bfstd.c | 8 ++------ tests/bfstd.c | 18 ++++++++++++++++++ tests/common/samefile_wordesc.sh | 4 ++++ 3 files changed, 24 insertions(+), 6 deletions(-) create mode 100644 tests/common/samefile_wordesc.sh (limited to 'src/bfstd.c') diff --git a/src/bfstd.c b/src/bfstd.c index e546a47..2d9f60a 100644 --- a/src/bfstd.c +++ b/src/bfstd.c @@ -546,15 +546,11 @@ int xstrtofflags(const char **str, unsigned long long *set, unsigned long long * static int xmbrtowc(wchar_t *wc, size_t *i, const char *str, size_t len, mbstate_t *mb) { size_t mblen = mbrtowc(wc, str + *i, len - *i, mb); switch (mblen) { - case -1: - // Invalid byte sequence + case -1: // Invalid byte sequence + case -2: // Incomplete byte sequence *i += 1; memset(mb, 0, sizeof(*mb)); return -1; - case -2: - // Incomplete byte sequence - *i += len; - return -1; default: *i += mblen; return 0; diff --git a/tests/bfstd.c b/tests/bfstd.c index fa854a8..2db084a 100644 --- a/tests/bfstd.c +++ b/tests/bfstd.c @@ -23,6 +23,15 @@ static void check_base_dir(const char *path, const char *dir, const char *base) free(xbase); } +/** Check the result of wordesc(). */ +static void check_wordesc(const char *str, const char *exp, enum wesc_flags flags) { + char buf[256]; + char *end = buf + sizeof(buf); + char *ret = wordesc(buf, end, str, flags); + bfs_verify(ret != end); + bfs_verify(strcmp(buf, exp) == 0, "wordesc(%s) == %s (!= %s)", str, buf, exp); +} + int main(void) { // From man 3p basename check_base_dir("usr", ".", "usr"); @@ -36,5 +45,14 @@ int main(void) { check_base_dir("//usr//lib//", "//usr", "lib"); check_base_dir("/home//dwc//test", "/home//dwc", "test"); + check_wordesc("", "\"\"", WESC_SHELL); + check_wordesc("word", "word", WESC_SHELL); + check_wordesc("two words", "\"two words\"", WESC_SHELL); + check_wordesc("word's", "\"word's\"", WESC_SHELL); + check_wordesc("\"word\"", "'\"word\"'", WESC_SHELL); + check_wordesc("\"word's\"", "'\"word'\\''s\"'", WESC_SHELL); + check_wordesc("\033[1mbold's\033[0m", "$'\\e[1mbold\\'s\\e[0m'", WESC_SHELL | WESC_TTY); + check_wordesc("\x7F", "$'\\x7F'", WESC_SHELL | WESC_TTY); + return EXIT_SUCCESS; } diff --git a/tests/common/samefile_wordesc.sh b/tests/common/samefile_wordesc.sh new file mode 100644 index 0000000..b5d158f --- /dev/null +++ b/tests/common/samefile_wordesc.sh @@ -0,0 +1,4 @@ +# Regression test: don't abort on incomplete UTF-8 sequences +export LC_ALL=$(locale -a | grep -Ei 'utf-?8$' | head -n1) +test -n "$LC_ALL" || skip +! invoke_bfs -samefile $'\xFA\xFA' -- cgit v1.2.3 From 90f9205b40b2f2049df46d819d14d67bfcb055be Mon Sep 17 00:00:00 2001 From: Tavian Barnes Date: Wed, 6 Sep 2023 16:23:10 -0400 Subject: bfstd: Fix printable_len() off-by-one If xmbrtowc() fails, or if xiswprint() is false, then we shouldn't include that wide char in the printable length. Fixes: 19c96abe0a1ee56cf206fd5e87defb1fd3e0daa5 --- src/bfstd.c | 4 ++-- tests/bfstd.c | 15 +++++++++++++++ 2 files changed, 17 insertions(+), 2 deletions(-) (limited to 'src/bfstd.c') diff --git a/src/bfstd.c b/src/bfstd.c index 2d9f60a..61d2fee 100644 --- a/src/bfstd.c +++ b/src/bfstd.c @@ -666,9 +666,9 @@ static size_t printable_len(const char *str, size_t len, enum wesc_flags flags) multibyte: memset(&mb, 0, sizeof(mb)); - while (i < len) { + for (size_t j = i; i < len; i = j) { wchar_t wc; - if (xmbrtowc(&wc, &i, str, len, &mb) != 0) { + if (xmbrtowc(&wc, &j, str, len, &mb) != 0) { break; } if (!xiswprint(wc, flags)) { diff --git a/tests/bfstd.c b/tests/bfstd.c index 2db084a..83964e5 100644 --- a/tests/bfstd.c +++ b/tests/bfstd.c @@ -5,6 +5,8 @@ #include "../src/config.h" #include "../src/diag.h" #include +#include +#include #include #include #include @@ -33,6 +35,11 @@ static void check_wordesc(const char *str, const char *exp, enum wesc_flags flag } int main(void) { + // Try to set a UTF-8 locale + if (!setlocale(LC_ALL, "C.UTF-8")) { + setlocale(LC_ALL, ""); + } + // From man 3p basename check_base_dir("usr", ".", "usr"); check_base_dir("usr/", ".", "usr"); @@ -54,5 +61,13 @@ int main(void) { check_wordesc("\033[1mbold's\033[0m", "$'\\e[1mbold\\'s\\e[0m'", WESC_SHELL | WESC_TTY); check_wordesc("\x7F", "$'\\x7F'", WESC_SHELL | WESC_TTY); + const char *charmap = nl_langinfo(CODESET); + if (strcmp(charmap, "UTF-8") == 0) { + check_wordesc("\xF0", "$'\\xF0'", WESC_SHELL | WESC_TTY); + check_wordesc("\xF0\x9F", "$'\\xF0\\x9F'", WESC_SHELL | WESC_TTY); + check_wordesc("\xF0\x9F\x98", "$'\\xF0\\x9F\\x98'", WESC_SHELL | WESC_TTY); + check_wordesc("\xF0\x9F\x98\x80", "\xF0\x9F\x98\x80", WESC_SHELL | WESC_TTY); + } + return EXIT_SUCCESS; } -- cgit v1.2.3 From 4f9762218079c4d83eb30065804367506da8330d Mon Sep 17 00:00:00 2001 From: Tavian Barnes Date: Wed, 6 Sep 2023 16:28:12 -0400 Subject: bfstd: Skip a whole loop in dollar_quote() if possible --- src/bfstd.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'src/bfstd.c') diff --git a/src/bfstd.c b/src/bfstd.c index 61d2fee..c858910 100644 --- a/src/bfstd.c +++ b/src/bfstd.c @@ -724,10 +724,9 @@ static char *dollar_quote(char *dest, char *end, const char *str, size_t len, en safe = xiswprint(wc, flags); } - for (size_t j = start; j < i; ++j) { + for (size_t j = start; safe && j < i; ++j) { if (str[j] == '\'' || str[j] == '\\') { safe = false; - break; } } -- cgit v1.2.3 From dc0443270904bf623d5b4a8e7b9ed8467eb9c93c Mon Sep 17 00:00:00 2001 From: Tavian Barnes Date: Wed, 6 Sep 2023 17:13:04 -0400 Subject: bfstd: Work around a FreeBSD-specific msan issue Link: https://github.com/llvm/llvm-project/issues/65532 --- src/bfstd.c | 27 +++++++++++++++++++++++---- 1 file changed, 23 insertions(+), 4 deletions(-) (limited to 'src/bfstd.c') diff --git a/src/bfstd.c b/src/bfstd.c index c858910..1a5a67d 100644 --- a/src/bfstd.c +++ b/src/bfstd.c @@ -5,6 +5,7 @@ #include "bit.h" #include "config.h" #include "diag.h" +#include "sanity.h" #include "thread.h" #include "xregex.h" #include @@ -590,11 +591,20 @@ static unsigned char ctype_cache[UCHAR_MAX + 1]; /** Initialize the ctype cache. */ static void char_cache_init(void) { +#if __FreeBSD__ && SANITIZE_MEMORY +// Work around https://github.com/llvm/llvm-project/issues/65532 +# define bfs_isprint (isprint) +# define bfs_isspace (isspace) +#else +# define bfs_isprint isprint +# define bfs_isspace isspace +#endif + for (size_t c = 0; c <= UCHAR_MAX; ++c) { - if (isprint(c)) { + if (bfs_isprint(c)) { ctype_cache[c] |= IS_PRINT; } - if (isspace(c)) { + if (bfs_isspace(c)) { ctype_cache[c] |= IS_SPACE; } } @@ -618,11 +628,20 @@ static bool xisprint(unsigned char c, enum wesc_flags flags) { /** Check if a wide character is printable. */ static bool xiswprint(wchar_t c, enum wesc_flags flags) { - if (iswprint(c)) { +#if __FreeBSD__ && SANITIZE_MEMORY +// Work around https://github.com/llvm/llvm-project/issues/65532 +# define bfs_iswprint (iswprint) +# define bfs_iswspace (iswspace) +#else +# define bfs_iswprint iswprint +# define bfs_iswspace iswspace +#endif + + if (bfs_iswprint(c)) { return true; } - if (!(flags & WESC_SHELL) && iswspace(c)) { + if (!(flags & WESC_SHELL) && bfs_iswspace(c)) { return true; } -- cgit v1.2.3 From a96ddeb7dc528d29d05f52a9b8857b2f8924fddc Mon Sep 17 00:00:00 2001 From: Tavian Barnes Date: Tue, 3 Oct 2023 13:07:21 -0400 Subject: thread: s/call_once/invoke_once/ call_once() is a reserved identifier from C11. --- src/bfstd.c | 2 +- src/thread.h | 2 +- src/xregex.c | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) (limited to 'src/bfstd.c') diff --git a/src/bfstd.c b/src/bfstd.c index 1a5a67d..fcf4a6d 100644 --- a/src/bfstd.c +++ b/src/bfstd.c @@ -651,7 +651,7 @@ static bool xiswprint(wchar_t c, enum wesc_flags flags) { /** Get the length of the longest printable prefix of a string. */ static size_t printable_len(const char *str, size_t len, enum wesc_flags flags) { static pthread_once_t once = PTHREAD_ONCE_INIT; - call_once(&once, char_cache_init); + invoke_once(&once, char_cache_init); // Fast path: avoid multibyte checks size_t i, word; diff --git a/src/thread.h b/src/thread.h index b2edf17..45b5e1f 100644 --- a/src/thread.h +++ b/src/thread.h @@ -97,7 +97,7 @@ /** * Wrapper for pthread_once(). */ -#define call_once(once, fn) \ +#define invoke_once(once, fn) \ thread_verify(pthread_once(once, fn), errno == 0) #endif // BFS_THREAD_H diff --git a/src/xregex.c b/src/xregex.c index b9c04bf..87b692e 100644 --- a/src/xregex.c +++ b/src/xregex.c @@ -107,7 +107,7 @@ static void bfs_onig_once(void) { /** Initialize Oniguruma. */ static int bfs_onig_initialize(OnigEncoding *enc) { static pthread_once_t once = PTHREAD_ONCE_INIT; - call_once(&once, bfs_onig_once); + invoke_once(&once, bfs_onig_once); *enc = bfs_onig_enc; return bfs_onig_status; -- cgit v1.2.3 From 428cf9c206beee3407ea3c5480b00f4cfbea95f5 Mon Sep 17 00:00:00 2001 From: Tavian Barnes Date: Thu, 5 Oct 2023 12:56:36 -0400 Subject: bfstd: Add a thread-safe wrapper for strerror() --- src/bfstd.c | 43 +++++++++++++++++++++++++++++++++++++++++++ src/bfstd.h | 11 +++++++++++ src/color.c | 2 +- src/eval.c | 2 +- src/parse.c | 4 ++-- src/printf.c | 2 +- src/thread.h | 3 ++- src/xregex.c | 3 ++- tests/bfstd.c | 4 ++-- tests/mksock.c | 2 +- tests/xtouch.c | 6 +++--- 11 files changed, 69 insertions(+), 13 deletions(-) (limited to 'src/bfstd.c') diff --git a/src/bfstd.c b/src/bfstd.c index fcf4a6d..e9214d4 100644 --- a/src/bfstd.c +++ b/src/bfstd.c @@ -12,6 +12,7 @@ #include #include #include +#include #include #include #include @@ -276,6 +277,48 @@ char *xstpencpy(char *dest, char *end, const char *src, size_t n) { } } +const char *xstrerror(int errnum) { + int saved = errno; + const char *ret = NULL; + static thread_local char buf[256]; + +#if __APPLE__ + // No strerror_l() on macOS + if (strerror_r(errnum, buf, sizeof(buf)) == 0) { + ret = buf; + } +#else +# if __NetBSD__ + // NetBSD has no thread-specific locales + locale_t loc = LC_GLOBAL_LOCALE; +# else + locale_t loc = uselocale((locale_t)0); +# endif + + locale_t copy = loc; + if (copy == LC_GLOBAL_LOCALE) { + copy = duplocale(copy); + } + + if (copy != (locale_t)0) { + ret = strerror_l(errnum, loc); + } + + if (loc == LC_GLOBAL_LOCALE) { + freelocale(copy); + } +#endif + + if (!ret) { + // Fallback for strerror_[lr]() or duplocale() failures + snprintf(buf, sizeof(buf), "Unknown error %d", errnum); + ret = buf; + } + + errno = saved; + return ret; +} + void xstrmode(mode_t mode, char str[11]) { strcpy(str, "----------"); diff --git a/src/bfstd.h b/src/bfstd.h index fb77399..abde24e 100644 --- a/src/bfstd.h +++ b/src/bfstd.h @@ -166,6 +166,17 @@ char *xstpecpy(char *dest, char *end, const char *src); */ char *xstpencpy(char *dest, char *end, const char *src, size_t n); +/** + * Thread-safe strerror(). + * + * @param errnum + * An error number. + * @return + * A string describing that error, which remains valid until the next + * xstrerror() call in the same thread. + */ +const char *xstrerror(int errnum); + /** * Format a mode like ls -l (e.g. -rw-r--r--). * diff --git a/src/color.c b/src/color.c index 788d35d..fbb5edf 100644 --- a/src/color.c +++ b/src/color.c @@ -1239,7 +1239,7 @@ static int cvbuff(CFILE *cfile, const char *format, va_list args) { break; case 'm': - if (dstrcat(&cfile->buffer, strerror(error)) != 0) { + if (dstrcat(&cfile->buffer, xstrerror(error)) != 0) { return -1; } break; diff --git a/src/eval.c b/src/eval.c index 9f4896a..e0dd97b 100644 --- a/src/eval.c +++ b/src/eval.c @@ -1376,7 +1376,7 @@ static enum bftw_action eval_callback(const struct BFTW *ftwbuf, void *ptr) { if (ftwbuf->type == BFS_ERROR) { if (!eval_should_ignore(&state, ftwbuf->error)) { - eval_error(&state, "%s.\n", strerror(ftwbuf->error)); + eval_error(&state, "%s.\n", xstrerror(ftwbuf->error)); } state.action = BFTW_PRUNE; goto done; diff --git a/src/parse.c b/src/parse.c index 7766a7b..976f7cb 100644 --- a/src/parse.c +++ b/src/parse.c @@ -1127,7 +1127,7 @@ static struct bfs_expr *parse_color(struct parser_state *state, int color, int a if (color) { if (!colors) { - parse_expr_error(state, expr, "Error parsing $$LS_COLORS: %s.\n", strerror(ctx->colors_error)); + parse_expr_error(state, expr, "Error parsing $$LS_COLORS: %s.\n", xstrerror(ctx->colors_error)); bfs_expr_free(expr); return NULL; } @@ -3741,7 +3741,7 @@ struct bfs_ctx *bfs_parse_cmdline(int argc, char *argv[]) { } if (state.use_color == COLOR_AUTO && !ctx->colors) { - bfs_warning(ctx, "Error parsing $$LS_COLORS: %s.\n\n", strerror(ctx->colors_error)); + bfs_warning(ctx, "Error parsing $$LS_COLORS: %s.\n\n", xstrerror(ctx->colors_error)); } if (bfs_optimize(ctx) != 0) { diff --git a/src/printf.c b/src/printf.c index 98bcb0f..704e26d 100644 --- a/src/printf.c +++ b/src/printf.c @@ -744,7 +744,7 @@ int bfs_printf_parse(const struct bfs_ctx *ctx, struct bfs_expr *expr, const cha if (!directive.ptr) { int error = errno; bfs_expr_error(ctx, expr); - bfs_error(ctx, "Couldn't parse the mount table: %s.\n", strerror(error)); + bfs_error(ctx, "Couldn't parse the mount table: %s.\n", xstrerror(error)); goto directive_error; } break; diff --git a/src/thread.h b/src/thread.h index ab95a79..a59033c 100644 --- a/src/thread.h +++ b/src/thread.h @@ -8,6 +8,7 @@ #ifndef BFS_THREAD_H #define BFS_THREAD_H +#include "bfstd.h" #include "config.h" #include "diag.h" #include @@ -23,7 +24,7 @@ #endif #define thread_verify(expr, cond) \ - bfs_verify((errno = (expr), (cond)), "%s: %s", #expr, strerror(errno)) + bfs_verify((errno = (expr), (cond)), "%s: %s", #expr, xstrerror(errno)) /** * Wrapper for pthread_create(). diff --git a/src/xregex.c b/src/xregex.c index 87b692e..3df27f0 100644 --- a/src/xregex.c +++ b/src/xregex.c @@ -3,6 +3,7 @@ #include "xregex.h" #include "alloc.h" +#include "bfstd.h" #include "config.h" #include "diag.h" #include "sanity.h" @@ -274,7 +275,7 @@ void bfs_regfree(struct bfs_regex *regex) { char *bfs_regerror(const struct bfs_regex *regex) { if (!regex) { - return strdup(strerror(ENOMEM)); + return strdup(xstrerror(ENOMEM)); } #if BFS_USE_ONIGURUMA diff --git a/tests/bfstd.c b/tests/bfstd.c index 33b3792..c386279 100644 --- a/tests/bfstd.c +++ b/tests/bfstd.c @@ -15,12 +15,12 @@ /** Check the result of xdirname()/xbasename(). */ static void check_base_dir(const char *path, const char *dir, const char *base) { char *xdir = xdirname(path); - bfs_verify(xdir, "xdirname(): %s", strerror(errno)); + bfs_verify(xdir, "xdirname(): %s", xstrerror(errno)); bfs_verify(strcmp(xdir, dir) == 0, "xdirname('%s') == '%s' (!= '%s')", path, xdir, dir); free(xdir); char *xbase = xbasename(path); - bfs_verify(xbase, "xbasename(): %s", strerror(errno)); + bfs_verify(xbase, "xbasename(): %s", xstrerror(errno)); bfs_verify(strcmp(xbase, base) == 0, "xbasename('%s') == '%s' (!= '%s')", path, xbase, base); free(xbase); } diff --git a/tests/mksock.c b/tests/mksock.c index 7023b4f..f3b61da 100644 --- a/tests/mksock.c +++ b/tests/mksock.c @@ -19,7 +19,7 @@ * Print an error message. */ static void errmsg(const char *cmd, const char *path) { - fprintf(stderr, "%s: '%s': %s.\n", cmd, path, strerror(errno)); + fprintf(stderr, "%s: '%s': %s.\n", cmd, path, xstrerror(errno)); } /** diff --git a/tests/xtouch.c b/tests/xtouch.c index 80fad8d..a4c4d40 100644 --- a/tests/xtouch.c +++ b/tests/xtouch.c @@ -197,14 +197,14 @@ int main(int argc, char *argv[]) { if (rarg) { struct stat buf; if (fstatat(AT_FDCWD, rarg, &buf, at_flags(&args)) != 0) { - fprintf(stderr, "%s: '%s': %s\n", cmd, rarg, strerror(errno)); + fprintf(stderr, "%s: '%s': %s\n", cmd, rarg, xstrerror(errno)); return EXIT_FAILURE; } times[0] = buf.st_atim; times[1] = buf.st_mtim; } else if (darg) { if (xgetdate(darg, ×[0]) != 0) { - fprintf(stderr, "%s: Parsing time '%s' failed: %s\n", cmd, darg, strerror(errno)); + fprintf(stderr, "%s: Parsing time '%s' failed: %s\n", cmd, darg, xstrerror(errno)); return EXIT_FAILURE; } times[1] = times[0]; @@ -237,7 +237,7 @@ int main(int argc, char *argv[]) { for (; optind < argc; ++optind) { const char *path = argv[optind]; if (xtouch(&args, path) != 0) { - fprintf(stderr, "%s: '%s': %s\n", cmd, path, strerror(errno)); + fprintf(stderr, "%s: '%s': %s\n", cmd, path, xstrerror(errno)); ret = EXIT_FAILURE; } } -- cgit v1.2.3 From d40eb87cc00f50a5debb8899eacb7fcf1065badf Mon Sep 17 00:00:00 2001 From: Tavian Barnes Date: Thu, 12 Oct 2023 23:45:40 -0400 Subject: bfstd: Actually use the copied locale This fixes a segfault in xstrerror() when using musl. --- src/bfstd.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/bfstd.c') diff --git a/src/bfstd.c b/src/bfstd.c index e9214d4..a4ae439 100644 --- a/src/bfstd.c +++ b/src/bfstd.c @@ -301,7 +301,7 @@ const char *xstrerror(int errnum) { } if (copy != (locale_t)0) { - ret = strerror_l(errnum, loc); + ret = strerror_l(errnum, copy); } if (loc == LC_GLOBAL_LOCALE) { -- cgit v1.2.3 From 8560c29d22462764dbf88f52451f8dfe84ad9d4c Mon Sep 17 00:00:00 2001 From: Tavian Barnes Date: Wed, 18 Oct 2023 11:34:21 -0400 Subject: wordesc: Don't allow braces in bare words Things like {a,b} should be quoted to avoid brace expansion. --- src/bfstd.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/bfstd.c') diff --git a/src/bfstd.c b/src/bfstd.c index a4ae439..ace9ed2 100644 --- a/src/bfstd.c +++ b/src/bfstd.c @@ -816,7 +816,7 @@ static char *dollar_quote(char *dest, char *end, const char *str, size_t len, en /** How much of this string is safe as a bare word? */ static size_t bare_len(const char *str, size_t len) { // https://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html#tag_18_02 - size_t ret = strcspn(str, "|&;<>()$`\\\"' *?[#˜=%!"); + size_t ret = strcspn(str, "|&;<>()$`\\\"' *?[#˜=%!{}"); return ret < len ? ret : len; } -- cgit v1.2.3 From 8ced65189cbea5ff0b06482713d647ca57c91f81 Mon Sep 17 00:00:00 2001 From: Tavian Barnes Date: Thu, 26 Oct 2023 10:57:25 -0400 Subject: bfstd: Only free the locale if we dup'd it successfully --- src/bfstd.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'src/bfstd.c') diff --git a/src/bfstd.c b/src/bfstd.c index ace9ed2..cdc33f1 100644 --- a/src/bfstd.c +++ b/src/bfstd.c @@ -302,10 +302,10 @@ const char *xstrerror(int errnum) { if (copy != (locale_t)0) { ret = strerror_l(errnum, copy); - } - if (loc == LC_GLOBAL_LOCALE) { - freelocale(copy); + if (loc == LC_GLOBAL_LOCALE) { + freelocale(copy); + } } #endif -- cgit v1.2.3 From 14ef89a442f7a027f52fd688b438c5fa627b6af7 Mon Sep 17 00:00:00 2001 From: Tavian Barnes Date: Fri, 27 Oct 2023 10:58:47 -0400 Subject: bfstd: Expose xmbrtowc() and use it in eval_status() --- src/bfstd.c | 26 +++++++++++++------------- src/bfstd.h | 19 ++++++++++++++++++- src/eval.c | 39 +++++++++++++++------------------------ 3 files changed, 46 insertions(+), 38 deletions(-) (limited to 'src/bfstd.c') diff --git a/src/bfstd.c b/src/bfstd.c index cdc33f1..a5a7e54 100644 --- a/src/bfstd.c +++ b/src/bfstd.c @@ -586,18 +586,18 @@ int xstrtofflags(const char **str, unsigned long long *set, unsigned long long * #endif } -/** mbrtowc() wrapper. */ -static int xmbrtowc(wchar_t *wc, size_t *i, const char *str, size_t len, mbstate_t *mb) { - size_t mblen = mbrtowc(wc, str + *i, len - *i, mb); +wint_t xmbrtowc(const char *str, size_t *i, size_t len, mbstate_t *mb) { + wchar_t wc; + size_t mblen = mbrtowc(&wc, str + *i, len - *i, mb); switch (mblen) { case -1: // Invalid byte sequence case -2: // Incomplete byte sequence *i += 1; memset(mb, 0, sizeof(*mb)); - return -1; + return WEOF; default: *i += mblen; - return 0; + return wc; } } @@ -609,12 +609,12 @@ size_t xstrwidth(const char *str) { memset(&mb, 0, sizeof(mb)); for (size_t i = 0; i < len;) { - wchar_t wc; - if (xmbrtowc(&wc, &i, str, len, &mb) == 0) { - ret += wcwidth(wc); - } else { + wint_t wc = xmbrtowc(str, &i, len, &mb); + if (wc == WEOF) { // Assume a single-width '?' ++ret; + } else { + ret += wcwidth(wc); } } @@ -729,8 +729,8 @@ multibyte: memset(&mb, 0, sizeof(mb)); for (size_t j = i; i < len; i = j) { - wchar_t wc; - if (xmbrtowc(&wc, &j, str, len, &mb) != 0) { + wint_t wc = xmbrtowc(str, &j, len, &mb); + if (wc == WEOF) { break; } if (!xiswprint(wc, flags)) { @@ -781,8 +781,8 @@ static char *dollar_quote(char *dest, char *end, const char *str, size_t len, en size_t start = i; bool safe = false; - wchar_t wc; - if (xmbrtowc(&wc, &i, str, len, &mb) == 0) { + wint_t wc = xmbrtowc(str, &i, len, &mb); + if (wc != WEOF) { safe = xiswprint(wc, flags); } diff --git a/src/bfstd.h b/src/bfstd.h index abde24e..db558c6 100644 --- a/src/bfstd.h +++ b/src/bfstd.h @@ -316,7 +316,24 @@ char *xconfstr(int name); */ int xstrtofflags(const char **str, unsigned long long *set, unsigned long long *clear); -// #include +#include + +/** + * Error-recovering mbrtowc() wrapper. + * + * @param str + * The string to convert. + * @param i + * The current index. + * @param len + * The length of the string. + * @param mb + * The multi-byte decoding state. + * @return + * The wide character at index *i, or WEOF if decoding fails. In either + * case, *i will be advanced to the next multi-byte character. + */ +wint_t xmbrtowc(const char *str, size_t *i, size_t len, mbstate_t *mb); /** * wcswidth() variant that works on narrow strings. diff --git a/src/eval.c b/src/eval.c index 3d396fa..6230353 100644 --- a/src/eval.c +++ b/src/eval.c @@ -1114,6 +1114,7 @@ static void eval_status(struct bfs_eval *state, struct bfs_bar *bar, struct time const struct BFTW *ftwbuf = state->ftwbuf; + dchar *status = NULL; dchar *rhs = dstrprintf(" (visited: %zu, depth: %2zu)", count, ftwbuf->depth); if (!rhs) { return; @@ -1125,9 +1126,9 @@ static void eval_status(struct bfs_eval *state, struct bfs_bar *bar, struct time rhslen = 0; } - dchar *status = dstralloc(0); + status = dstralloc(0); if (!status) { - goto out_rhs; + goto out; } const char *path = ftwbuf->path; @@ -1139,20 +1140,14 @@ static void eval_status(struct bfs_eval *state, struct bfs_bar *bar, struct time // Try to make sure even wide characters fit in the status bar size_t pathmax = width - rhslen - 3; size_t pathwidth = 0; + size_t lhslen = 0; mbstate_t mb; memset(&mb, 0, sizeof(mb)); - while (pathlen > 0) { - wchar_t wc; - size_t len = mbrtowc(&wc, path, pathlen, &mb); + for (size_t i = lhslen; lhslen < pathlen; lhslen = i) { + wint_t wc = xmbrtowc(path, &i, pathlen, &mb); int cwidth; - if (len == (size_t)-1) { + if (wc == WEOF) { // Invalid byte sequence, assume a single-width '?' - len = 1; - cwidth = 1; - memset(&mb, 0, sizeof(mb)); - } else if (len == (size_t)-2) { - // Incomplete byte sequence, assume a single-width '?' - len = pathlen; cwidth = 1; } else { cwidth = wcwidth(wc); @@ -1164,35 +1159,31 @@ static void eval_status(struct bfs_eval *state, struct bfs_bar *bar, struct time if (pathwidth + cwidth > pathmax) { break; } - - if (dstrncat(&status, path, len) != 0) { - goto out_rhs; - } - - path += len; - pathlen -= len; pathwidth += cwidth; } + if (dstrncat(&status, path, lhslen) != 0) { + goto out; + } if (dstrcat(&status, "...") != 0) { - goto out_rhs; + goto out; } while (pathwidth < pathmax) { if (dstrapp(&status, ' ') != 0) { - goto out_rhs; + goto out; } ++pathwidth; } - if (dstrcat(&status, rhs) != 0) { - goto out_rhs; + if (dstrdcat(&status, rhs) != 0) { + goto out; } bfs_bar_update(bar, status); +out: dstrfree(status); -out_rhs: dstrfree(rhs); } -- cgit v1.2.3 From 0015289fec2c54de481cab87fb5b43bc2d1f2a4a Mon Sep 17 00:00:00 2001 From: Tavian Barnes Date: Fri, 27 Oct 2023 11:21:38 -0400 Subject: Use {0} to initialize mbstate_t rather than memset() --- src/bfstd.c | 15 +++++---------- src/eval.c | 3 +-- 2 files changed, 6 insertions(+), 12 deletions(-) (limited to 'src/bfstd.c') diff --git a/src/bfstd.c b/src/bfstd.c index a5a7e54..eee02b8 100644 --- a/src/bfstd.c +++ b/src/bfstd.c @@ -593,7 +593,7 @@ wint_t xmbrtowc(const char *str, size_t *i, size_t len, mbstate_t *mb) { case -1: // Invalid byte sequence case -2: // Incomplete byte sequence *i += 1; - memset(mb, 0, sizeof(*mb)); + *mb = (mbstate_t){0}; return WEOF; default: *i += mblen; @@ -605,9 +605,7 @@ size_t xstrwidth(const char *str) { size_t len = strlen(str); size_t ret = 0; - mbstate_t mb; - memset(&mb, 0, sizeof(mb)); - + mbstate_t mb = {0}; for (size_t i = 0; i < len;) { wint_t wc = xmbrtowc(str, &i, len, &mb); if (wc == WEOF) { @@ -724,9 +722,8 @@ static size_t printable_len(const char *str, size_t len, enum wesc_flags flags) } } - mbstate_t mb; -multibyte: - memset(&mb, 0, sizeof(mb)); +multibyte:; + mbstate_t mb = {0}; for (size_t j = i; i < len; i = j) { wint_t wc = xmbrtowc(str, &j, len, &mb); @@ -774,9 +771,7 @@ static const char *dollar_esc(char c) { static char *dollar_quote(char *dest, char *end, const char *str, size_t len, enum wesc_flags flags) { dest = xstpecpy(dest, end, "$'"); - mbstate_t mb; - memset(&mb, 0, sizeof(mb)); - + mbstate_t mb = {0}; for (size_t i = 0; i < len;) { size_t start = i; bool safe = false; diff --git a/src/eval.c b/src/eval.c index 05be5bb..56d7cd8 100644 --- a/src/eval.c +++ b/src/eval.c @@ -1147,8 +1147,7 @@ static void eval_status(struct bfs_eval *state, struct bfs_bar *bar, struct time size_t pathmax = width - rhslen - 3; size_t pathwidth = 0; size_t lhslen = 0; - mbstate_t mb; - memset(&mb, 0, sizeof(mb)); + mbstate_t mb = {0}; for (size_t i = lhslen; lhslen < pathlen; lhslen = i) { wint_t wc = xmbrtowc(status, &i, pathlen, &mb); int cwidth; -- cgit v1.2.3 From 8aaf670c13ade259f7bcdd50332968c1c6290b34 Mon Sep 17 00:00:00 2001 From: Tavian Barnes Date: Tue, 31 Oct 2023 13:25:04 -0400 Subject: bfstd: New xwaitpid() wrapper --- src/bfstd.c | 9 +++++++++ src/bfstd.h | 7 +++++++ src/exec.c | 2 +- src/parse.c | 2 +- src/xspawn.c | 2 +- 5 files changed, 19 insertions(+), 3 deletions(-) (limited to 'src/bfstd.c') diff --git a/src/bfstd.c b/src/bfstd.c index eee02b8..06226a2 100644 --- a/src/bfstd.c +++ b/src/bfstd.c @@ -20,6 +20,7 @@ #include #include #include +#include #include #include #include @@ -391,6 +392,14 @@ int xminor(dev_t dev) { #endif } +pid_t xwaitpid(pid_t pid, int *status, int flags) { + pid_t ret; + do { + ret = waitpid(pid, status, flags); + } while (ret < 0 && errno == EINTR); + return ret; +} + int dup_cloexec(int fd) { #ifdef F_DUPFD_CLOEXEC return fcntl(fd, F_DUPFD_CLOEXEC, 0); diff --git a/src/bfstd.h b/src/bfstd.h index db558c6..4e36aca 100644 --- a/src/bfstd.h +++ b/src/bfstd.h @@ -213,6 +213,13 @@ int xminor(dev_t dev); # define st_birthtim st_birthtimespec #endif +// #include + +/** + * waitpid() wrapper that handles EINTR. + */ +pid_t xwaitpid(pid_t pid, int *status, int flags); + // #include /** diff --git a/src/exec.c b/src/exec.c index 0e0d585..97cfafa 100644 --- a/src/exec.c +++ b/src/exec.c @@ -390,7 +390,7 @@ fail: } int wstatus; - if (waitpid(pid, &wstatus, 0) < 0) { + if (xwaitpid(pid, &wstatus, 0) < 0) { return -1; } diff --git a/src/parse.c b/src/parse.c index fafd787..3f32021 100644 --- a/src/parse.c +++ b/src/parse.c @@ -2980,7 +2980,7 @@ static struct bfs_expr *parse_help(struct parser_state *state, int arg1, int arg if (pager > 0) { cfclose(cout); - waitpid(pager, NULL, 0); + xwaitpid(pager, NULL, 0); } state->just_info = true; diff --git a/src/xspawn.c b/src/xspawn.c index 7fb63e0..64759e0 100644 --- a/src/xspawn.c +++ b/src/xspawn.c @@ -234,7 +234,7 @@ pid_t bfs_spawn(const char *exe, const struct bfs_spawn *ctx, char **argv, char xclose(pipefd[0]); if (nbytes == sizeof(error)) { int wstatus; - waitpid(pid, &wstatus, 0); + xwaitpid(pid, &wstatus, 0); errno = error; return -1; } -- cgit v1.2.3 From 816574513e0e163aff9f183721697f157eb158fa Mon Sep 17 00:00:00 2001 From: Tavian Barnes Date: Mon, 6 Nov 2023 10:03:43 -0500 Subject: bfstd: Expose rlim_cmp() --- src/bfstd.c | 33 +++++++++++++++++++++++++++++++++ src/bfstd.h | 7 +++++++ src/eval.c | 33 --------------------------------- 3 files changed, 40 insertions(+), 33 deletions(-) (limited to 'src/bfstd.c') diff --git a/src/bfstd.c b/src/bfstd.c index 06226a2..985a268 100644 --- a/src/bfstd.c +++ b/src/bfstd.c @@ -18,6 +18,7 @@ #include #include #include +#include #include #include #include @@ -368,6 +369,38 @@ void xstrmode(mode_t mode, char str[11]) { } } +/** Check if an rlimit value is infinite. */ +static bool rlim_isinf(rlim_t r) { + // Consider RLIM_{INFINITY,SAVED_{CUR,MAX}} all equally infinite + if (r == RLIM_INFINITY) { + return true; + } + +#ifdef RLIM_SAVED_CUR + if (r == RLIM_SAVED_CUR) { + return true; + } +#endif + +#ifdef RLIM_SAVED_MAX + if (r == RLIM_SAVED_MAX) { + return true; + } +#endif + + return false; +} + +int rlim_cmp(rlim_t a, rlim_t b) { + bool a_inf = rlim_isinf(a); + bool b_inf = rlim_isinf(b); + if (a_inf || b_inf) { + return a_inf - b_inf; + } + + return (a > b) - (a < b); +} + dev_t xmakedev(int ma, int mi) { #ifdef makedev return makedev(ma, mi); diff --git a/src/bfstd.h b/src/bfstd.h index 4e36aca..6cb2d7b 100644 --- a/src/bfstd.h +++ b/src/bfstd.h @@ -187,6 +187,13 @@ const char *xstrerror(int errnum); */ void xstrmode(mode_t mode, char str[11]); +#include + +/** + * Compare two rlim_t values, accounting for infinite limits. + */ +int rlim_cmp(rlim_t a, rlim_t b); + #include /** diff --git a/src/eval.c b/src/eval.c index 56d7cd8..5ba3de8 100644 --- a/src/eval.c +++ b/src/eval.c @@ -1427,39 +1427,6 @@ done: return state.action; } -/** Check if an rlimit value is infinite. */ -static bool rlim_isinf(rlim_t r) { - // Consider RLIM_{INFINITY,SAVED_{CUR,MAX}} all equally infinite - if (r == RLIM_INFINITY) { - return true; - } - -#ifdef RLIM_SAVED_CUR - if (r == RLIM_SAVED_CUR) { - return true; - } -#endif - -#ifdef RLIM_SAVED_MAX - if (r == RLIM_SAVED_MAX) { - return true; - } -#endif - - return false; -} - -/** Compare two rlimit values, accounting for RLIM_INFINITY etc. */ -static int rlim_cmp(rlim_t a, rlim_t b) { - bool a_inf = rlim_isinf(a); - bool b_inf = rlim_isinf(b); - if (a_inf || b_inf) { - return a_inf - b_inf; - } - - return (a > b) - (a < b); -} - /** Raise RLIMIT_NOFILE if possible, and return the new limit. */ static int raise_fdlimit(const struct bfs_ctx *ctx) { rlim_t target = 64 << 10; -- cgit v1.2.3 From 640fa83406bb8c08d971be68b32b7e222e92e286 Mon Sep 17 00:00:00 2001 From: Tavian Barnes Date: Fri, 10 Nov 2023 22:22:01 -0500 Subject: Initial support for Cosmopolitan Libc --- src/alloc.c | 1 + src/bfstd.c | 2 +- src/config.h | 4 ++++ src/eval.c | 4 +++- src/xspawn.c | 25 ++++++++++++++++++++++++- 5 files changed, 33 insertions(+), 3 deletions(-) (limited to 'src/bfstd.c') diff --git a/src/alloc.c b/src/alloc.c index 3b9972f..ff3ec6d 100644 --- a/src/alloc.c +++ b/src/alloc.c @@ -3,6 +3,7 @@ #include "alloc.h" #include "bit.h" +#include "config.h" #include "diag.h" #include "sanity.h" #include diff --git a/src/bfstd.c b/src/bfstd.c index 985a268..16cd82e 100644 --- a/src/bfstd.c +++ b/src/bfstd.c @@ -284,7 +284,7 @@ const char *xstrerror(int errnum) { const char *ret = NULL; static thread_local char buf[256]; -#if __APPLE__ +#if __APPLE__ || __COSMOPOLITAN__ // No strerror_l() on macOS if (strerror_r(errnum, buf, sizeof(buf)) == 0) { ret = buf; diff --git a/src/config.h b/src/config.h index 821e4a9..a474fb3 100644 --- a/src/config.h +++ b/src/config.h @@ -179,6 +179,10 @@ */ #define cache_align alignas(FALSE_SHARING_SIZE) +#if __COSMOPOLITAN__ +typedef long double max_align_t; +#endif + // Wrappers for attributes /** diff --git a/src/eval.c b/src/eval.c index eb4a0ca..6aa5104 100644 --- a/src/eval.c +++ b/src/eval.c @@ -1558,7 +1558,9 @@ static const char *dump_bftw_strategy(enum bftw_strategy strategy) { /** Check if we need to enable BFTW_BUFFER. */ static bool eval_must_buffer(const struct bfs_expr *expr) { -#if __FreeBSD__ +#if __COSMOPOLITAN__ + return true; +#elif __FreeBSD__ // FreeBSD doesn't properly handle adding/removing directory entries // during readdir() on NFS mounts. Work around it by passing BFTW_BUFFER // whenever we could be mutating the directory ourselves through -delete diff --git a/src/xspawn.c b/src/xspawn.c index 01f21e9..6a2ebba 100644 --- a/src/xspawn.c +++ b/src/xspawn.c @@ -174,15 +174,38 @@ int bfs_spawn_addfchdir(struct bfs_spawn *ctx, int fd) { int bfs_spawn_addsetrlimit(struct bfs_spawn *ctx, int resource, const struct rlimit *rl) { struct bfs_spawn_action *action = bfs_spawn_action(BFS_SPAWN_SETRLIMIT); if (!action) { - return -1; + goto fail; + } + +#ifdef POSIX_SPAWN_SETRLIMIT + short flags; + errno = posix_spawnattr_getflags(&ctx->attr, &flags); + if (errno != 0) { + goto fail; + } + + flags |= POSIX_SPAWN_SETRLIMIT; + errno = posix_spawnattr_setflags(&ctx->attr, flags); + if (errno != 0) { + goto fail; } + errno = posix_spawnattr_setrlimit(&ctx->attr, resource, rl); + if (errno != 0) { + goto fail; + } +#else ctx->flags &= ~BFS_SPAWN_USE_POSIX; +#endif action->resource = resource; action->rlimit = *rl; SLIST_APPEND(ctx, action); return 0; + +fail: + free(action); + return -1; } /** bfs_spawn() implementation using posix_spawn(). */ -- cgit v1.2.3 From baa6fc8cd33da879e5f7ac22557fd2ef3e4d8072 Mon Sep 17 00:00:00 2001 From: Tavian Barnes Date: Thu, 23 Nov 2023 15:25:34 -0500 Subject: bfstd: Work around more instances of llvm/llvm-project#65532 --- src/bfstd.c | 33 +++++++++++++++++++-------------- 1 file changed, 19 insertions(+), 14 deletions(-) (limited to 'src/bfstd.c') diff --git a/src/bfstd.c b/src/bfstd.c index 16cd82e..b5006d1 100644 --- a/src/bfstd.c +++ b/src/bfstd.c @@ -284,8 +284,12 @@ const char *xstrerror(int errnum) { const char *ret = NULL; static thread_local char buf[256]; -#if __APPLE__ || __COSMOPOLITAN__ - // No strerror_l() on macOS + // - __APPLE__ + // - __COSMOPOLITAN__ + // - No strerror_l() + // - __FreeBSD__ && SANITIZE_MEMORY + // - duplocale() triggers https://github.com/llvm/llvm-project/issues/65532 +#if __APPLE__ || __COSMOPOLITAN__ || (__FreeBSD__ && SANITIZE_MEMORY) if (strerror_r(errnum, buf, sizeof(buf)) == 0) { ret = buf; } @@ -643,6 +647,16 @@ wint_t xmbrtowc(const char *str, size_t *i, size_t len, mbstate_t *mb) { } } +/** + * Work around https://github.com/llvm/llvm-project/issues/65532 by forcing a + * function, not a macro, to be called. + */ +#if __FreeBSD__ && SANITIZE_MEMORY +# define BFS_INTERCEPT(fn) (fn) +#else +# define BFS_INTERCEPT(fn) fn +#endif + size_t xstrwidth(const char *str) { size_t len = strlen(str); size_t ret = 0; @@ -654,7 +668,7 @@ size_t xstrwidth(const char *str) { // Assume a single-width '?' ++ret; } else { - ret += wcwidth(wc); + ret += BFS_INTERCEPT(wcwidth)(wc); } } @@ -674,20 +688,11 @@ static unsigned char ctype_cache[UCHAR_MAX + 1]; /** Initialize the ctype cache. */ static void char_cache_init(void) { -#if __FreeBSD__ && SANITIZE_MEMORY -// Work around https://github.com/llvm/llvm-project/issues/65532 -# define bfs_isprint (isprint) -# define bfs_isspace (isspace) -#else -# define bfs_isprint isprint -# define bfs_isspace isspace -#endif - for (size_t c = 0; c <= UCHAR_MAX; ++c) { - if (bfs_isprint(c)) { + if (BFS_INTERCEPT(isprint)(c)) { ctype_cache[c] |= IS_PRINT; } - if (bfs_isspace(c)) { + if (BFS_INTERCEPT(isspace)(c)) { ctype_cache[c] |= IS_SPACE; } } -- cgit v1.2.3 From deb293c7fb3ac0787ba9de8d4423b0037998fc13 Mon Sep 17 00:00:00 2001 From: Tavian Barnes Date: Sat, 9 Dec 2023 17:01:42 -0500 Subject: bfstd: Wrap is[w]{alpha,digit,...}() --- src/bfstd.c | 43 ++++++++++++------------------------------- src/bfstd.h | 50 ++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 62 insertions(+), 31 deletions(-) (limited to 'src/bfstd.c') diff --git a/src/bfstd.c b/src/bfstd.c index b5006d1..9ffa8e6 100644 --- a/src/bfstd.c +++ b/src/bfstd.c @@ -647,16 +647,6 @@ wint_t xmbrtowc(const char *str, size_t *i, size_t len, mbstate_t *mb) { } } -/** - * Work around https://github.com/llvm/llvm-project/issues/65532 by forcing a - * function, not a macro, to be called. - */ -#if __FreeBSD__ && SANITIZE_MEMORY -# define BFS_INTERCEPT(fn) (fn) -#else -# define BFS_INTERCEPT(fn) fn -#endif - size_t xstrwidth(const char *str) { size_t len = strlen(str); size_t ret = 0; @@ -689,17 +679,17 @@ static unsigned char ctype_cache[UCHAR_MAX + 1]; /** Initialize the ctype cache. */ static void char_cache_init(void) { for (size_t c = 0; c <= UCHAR_MAX; ++c) { - if (BFS_INTERCEPT(isprint)(c)) { + if (xisprint(c)) { ctype_cache[c] |= IS_PRINT; } - if (BFS_INTERCEPT(isspace)(c)) { + if (xisspace(c)) { ctype_cache[c] |= IS_SPACE; } } } /** Check if a character is printable. */ -static bool xisprint(unsigned char c, enum wesc_flags flags) { +static bool wesc_isprint(unsigned char c, enum wesc_flags flags) { if (ctype_cache[c] & IS_PRINT) { return true; } @@ -715,21 +705,12 @@ static bool xisprint(unsigned char c, enum wesc_flags flags) { } /** Check if a wide character is printable. */ -static bool xiswprint(wchar_t c, enum wesc_flags flags) { -#if __FreeBSD__ && SANITIZE_MEMORY -// Work around https://github.com/llvm/llvm-project/issues/65532 -# define bfs_iswprint (iswprint) -# define bfs_iswspace (iswspace) -#else -# define bfs_iswprint iswprint -# define bfs_iswspace iswspace -#endif - - if (bfs_iswprint(c)) { +static bool wesc_iswprint(wchar_t c, enum wesc_flags flags) { + if (xiswprint(c)) { return true; } - if (!(flags & WESC_SHELL) && bfs_iswspace(c)) { + if (!(flags & WESC_SHELL) && xiswspace(c)) { return true; } @@ -753,18 +734,18 @@ static size_t printable_len(const char *str, size_t len, enum wesc_flags flags) } for (size_t j = 0; j < sizeof(word); ++i, ++j) { - if (!xisprint(str[i], flags)) { + if (!wesc_isprint(str[i], flags)) { return i; } } } for (; i < len; ++i) { - unsigned char c = str[i]; - if (!isascii(c)) { + char c = str[i]; + if (!xisascii(c)) { goto multibyte; } - if (!xisprint(c, flags)) { + if (!wesc_isprint(c, flags)) { return i; } } @@ -777,7 +758,7 @@ multibyte:; if (wc == WEOF) { break; } - if (!xiswprint(wc, flags)) { + if (!wesc_iswprint(wc, flags)) { break; } } @@ -825,7 +806,7 @@ static char *dollar_quote(char *dest, char *end, const char *str, size_t len, en wint_t wc = xmbrtowc(str, &i, len, &mb); if (wc != WEOF) { - safe = xiswprint(wc, flags); + safe = wesc_iswprint(wc, flags); } for (size_t j = start; safe && j < i; ++j) { diff --git a/src/bfstd.h b/src/bfstd.h index 6cb2d7b..58e504c 100644 --- a/src/bfstd.h +++ b/src/bfstd.h @@ -9,8 +9,39 @@ #define BFS_BFSTD_H #include "config.h" +#include "sanity.h" #include +#include + +/** + * Work around https://github.com/llvm/llvm-project/issues/65532 by forcing a + * function, not a macro, to be called. + */ +#if __FreeBSD__ && SANITIZE_MEMORY +# define BFS_INTERCEPT(fn) (fn) +#else +# define BFS_INTERCEPT(fn) fn +#endif + +/** + * Wrap isalpha()/isdigit()/etc. + */ +#define BFS_ISCTYPE(fn, c) BFS_INTERCEPT(fn)((unsigned char)(c)) + +#define xisalnum(c) BFS_ISCTYPE(isalnum, c) +#define xisalpha(c) BFS_ISCTYPE(isalpha, c) +#define xisascii(c) BFS_ISCTYPE(isascii, c) +#define xiscntrl(c) BFS_ISCTYPE(iscntrl, c) +#define xisdigit(c) BFS_ISCTYPE(isdigit, c) +#define xislower(c) BFS_ISCTYPE(islower, c) +#define xisgraph(c) BFS_ISCTYPE(isgraph, c) +#define xisprint(c) BFS_ISCTYPE(isprint, c) +#define xispunct(c) BFS_ISCTYPE(ispunct, c) +#define xisspace(c) BFS_ISCTYPE(isspace, c) +#define xisupper(c) BFS_ISCTYPE(isupper, c) +#define xisxdigit(c) BFS_ISCTYPE(isxdigit, c) + // #include /** @@ -359,6 +390,25 @@ wint_t xmbrtowc(const char *str, size_t *i, size_t len, mbstate_t *mb); */ size_t xstrwidth(const char *str); +#include + +/** + * Wrap iswalpha()/iswdigit()/etc. + */ +#define BFS_ISWCTYPE(fn, c) BFS_INTERCEPT(fn)(c) + +#define xiswalnum(c) BFS_ISWCTYPE(iswalnum, c) +#define xiswalpha(c) BFS_ISWCTYPE(iswalpha, c) +#define xiswcntrl(c) BFS_ISWCTYPE(iswcntrl, c) +#define xiswdigit(c) BFS_ISWCTYPE(iswdigit, c) +#define xiswlower(c) BFS_ISWCTYPE(iswlower, c) +#define xiswgraph(c) BFS_ISWCTYPE(iswgraph, c) +#define xiswprint(c) BFS_ISWCTYPE(iswprint, c) +#define xiswpunct(c) BFS_ISWCTYPE(iswpunct, c) +#define xiswspace(c) BFS_ISWCTYPE(iswspace, c) +#define xiswupper(c) BFS_ISWCTYPE(iswupper, c) +#define xiswxdigit(c) BFS_ISWCTYPE(iswxdigit, c) + // #include /** -- cgit v1.2.3 From aa8344e04bfe950cc9f5e45352cd8202295e0cdf Mon Sep 17 00:00:00 2001 From: Tavian Barnes Date: Sat, 16 Dec 2023 11:54:18 -0500 Subject: bfstd: New xwcwidth() wrapper --- src/bfstd.c | 2 +- src/bfstd.h | 5 +++++ src/eval.c | 2 +- 3 files changed, 7 insertions(+), 2 deletions(-) (limited to 'src/bfstd.c') diff --git a/src/bfstd.c b/src/bfstd.c index 9ffa8e6..a3e22f5 100644 --- a/src/bfstd.c +++ b/src/bfstd.c @@ -658,7 +658,7 @@ size_t xstrwidth(const char *str) { // Assume a single-width '?' ++ret; } else { - ret += BFS_INTERCEPT(wcwidth)(wc); + ret += xwcwidth(wc); } } diff --git a/src/bfstd.h b/src/bfstd.h index 58e504c..0fcb892 100644 --- a/src/bfstd.h +++ b/src/bfstd.h @@ -390,6 +390,11 @@ wint_t xmbrtowc(const char *str, size_t *i, size_t len, mbstate_t *mb); */ size_t xstrwidth(const char *str); +/** + * wcwidth() wrapper that works around LLVM bug #65532. + */ +#define xwcwidth BFS_INTERCEPT(wcwidth) + #include /** diff --git a/src/eval.c b/src/eval.c index 55b14f0..a990fd4 100644 --- a/src/eval.c +++ b/src/eval.c @@ -1154,7 +1154,7 @@ static void eval_status(struct bfs_eval *state, struct bfs_bar *bar, struct time // Invalid byte sequence, assume a single-width '?' cwidth = 1; } else { - cwidth = wcwidth(wc); + cwidth = xwcwidth(wc); if (cwidth < 0) { cwidth = 0; } -- cgit v1.2.3 From eae90d86b5e3dda10f541dadcea6462587ff2bfc Mon Sep 17 00:00:00 2001 From: Tavian Barnes Date: Tue, 2 Jan 2024 13:55:21 -0500 Subject: bfstd: Fix fflags type on OpenBSD --- src/bfstd.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) (limited to 'src/bfstd.c') diff --git a/src/bfstd.c b/src/bfstd.c index a3e22f5..c0e61cb 100644 --- a/src/bfstd.c +++ b/src/bfstd.c @@ -609,8 +609,14 @@ error: int xstrtofflags(const char **str, unsigned long long *set, unsigned long long *clear) { #if BSD && !__GNU__ char *str_arg = (char *)*str; - unsigned long set_arg = 0; - unsigned long clear_arg = 0; + +#if __OpenBSD__ + typedef uint32_t fflags_t; +#else + typedef unsigned long fflags_t; +#endif + fflags_t set_arg = 0; + fflags_t clear_arg = 0; #if __NetBSD__ int ret = string_to_flags(&str_arg, &set_arg, &clear_arg); -- cgit v1.2.3 From e9588c49d5539ded993f720fc6855d6fa878c997 Mon Sep 17 00:00:00 2001 From: Tavian Barnes Date: Sat, 13 Jan 2024 12:42:42 -0500 Subject: bfstd: New {error,errno}_is_like() functions We used to have is_nonexistence_error() to consistently treat ENOENT and ENOTDIR the same. Recently, we started considering EFAULT the same as ENAMETOOLONG on DragonFly BSD to work around a kernel bug. Unify both of these behind a more generic interface. --- src/bfstd.c | 23 +++++++++++++++++++++-- src/bfstd.h | 18 ++++++++++++++++-- src/bftw.c | 18 +++--------------- src/eval.c | 2 +- src/stat.c | 2 +- tests/xtouch.c | 17 +++-------------- 6 files changed, 45 insertions(+), 35 deletions(-) (limited to 'src/bfstd.c') diff --git a/src/bfstd.c b/src/bfstd.c index c0e61cb..15e8667 100644 --- a/src/bfstd.c +++ b/src/bfstd.c @@ -36,8 +36,27 @@ # include #endif -bool is_nonexistence_error(int error) { - return error == ENOENT || errno == ENOTDIR; +bool error_is_like(int error, int category) { + if (error == category) { + return true; + } + + switch (category) { + case ENOENT: + return error == ENOTDIR; + +#if __DragonFly__ + // https://twitter.com/tavianator/status/1742991411203485713 + case ENAMETOOLONG: + return error == EFAULT; +#endif + } + + return false; +} + +bool errno_is_like(int category) { + return error_is_like(errno, category); } char *xdirname(const char *path) { diff --git a/src/bfstd.h b/src/bfstd.h index 0fcb892..8953b9b 100644 --- a/src/bfstd.h +++ b/src/bfstd.h @@ -45,9 +45,23 @@ // #include /** - * Return whether an error code is due to a path not existing. + * Check if an error code is "like" another one. For example, ENOTDIR is + * like ENOENT because they can both be triggered by non-existent paths. + * + * @param error + * The error code to check. + * @param category + * The category to test for. Known categories include ENOENT and + * ENAMETOOLONG. + * @return + * Whether the error belongs to the given category. + */ +bool error_is_like(int error, int category); + +/** + * Equivalent to error_is_like(errno, category). */ -bool is_nonexistence_error(int error); +bool errno_is_like(int category); #include diff --git a/src/bftw.c b/src/bftw.c index 355cb54..49f07df 100644 --- a/src/bftw.c +++ b/src/bftw.c @@ -68,7 +68,7 @@ const struct bfs_stat *bftw_stat(const struct BFTW *ftwbuf, enum bfs_stat_flags } } else { ret = bftw_stat_impl(mutbuf, &mutbuf->stat_cache, BFS_STAT_FOLLOW); - if (!ret && (flags & BFS_STAT_TRYFOLLOW) && is_nonexistence_error(errno)) { + if (!ret && (flags & BFS_STAT_TRYFOLLOW) && errno_is_like(ENOENT)) { ret = bftw_stat_impl(mutbuf, &mutbuf->lstat_cache, BFS_STAT_NOFOLLOW); } } @@ -81,7 +81,7 @@ const struct bfs_stat *bftw_cached_stat(const struct BFTW *ftwbuf, enum bfs_stat return ftwbuf->lstat_cache.buf; } else if (ftwbuf->stat_cache.buf) { return ftwbuf->stat_cache.buf; - } else if ((flags & BFS_STAT_TRYFOLLOW) && is_nonexistence_error(ftwbuf->stat_cache.error)) { + } else if ((flags & BFS_STAT_TRYFOLLOW) && error_is_like(ftwbuf->stat_cache.error, ENOENT)) { return ftwbuf->lstat_cache.buf; } else { return NULL; @@ -739,22 +739,10 @@ static int bftw_file_open(struct bftw_state *state, struct bftw_file *file, cons } int fd = bftw_file_openat(state, file, base, at_path); - if (fd >= 0) { + if (fd >= 0 || !errno_is_like(ENAMETOOLONG)) { return fd; } - switch (errno) { - case ENAMETOOLONG: -#if __DragonFly__ - // https://twitter.com/tavianator/status/1742991411203485713 - case EFAULT: -#endif - break; - - default: - return -1; - } - // Handle ENAMETOOLONG by manually traversing the path component-by-component struct bftw_list parents; SLIST_INIT(&parents); diff --git a/src/eval.c b/src/eval.c index 130b366..1a814b3 100644 --- a/src/eval.c +++ b/src/eval.c @@ -80,7 +80,7 @@ static void eval_error(struct bfs_eval *state, const char *format, ...) { */ static bool eval_should_ignore(const struct bfs_eval *state, int error) { return state->ctx->ignore_races - && is_nonexistence_error(error) + && error_is_like(error, ENOENT) && state->ftwbuf->depth > 0; } diff --git a/src/stat.c b/src/stat.c index d7387c6..91aa092 100644 --- a/src/stat.c +++ b/src/stat.c @@ -260,7 +260,7 @@ static int bfs_stat_tryfollow(int at_fd, const char *at_path, int at_flags, int if (ret != 0 && (bfs_flags & (BFS_STAT_NOFOLLOW | BFS_STAT_TRYFOLLOW)) == BFS_STAT_TRYFOLLOW - && is_nonexistence_error(errno)) + && errno_is_like(ENOENT)) { at_flags |= AT_SYMLINK_NOFOLLOW; ret = bfs_stat_explicit(at_fd, at_path, at_flags, x_flags, buf); diff --git a/tests/xtouch.c b/tests/xtouch.c index ed8bbee..6099128 100644 --- a/tests/xtouch.c +++ b/tests/xtouch.c @@ -68,22 +68,11 @@ static int open_parent(const struct args *args, const char **path) { goto done; } - switch (errno) { - case ENAMETOOLONG: -#if __DragonFly__ - // https://twitter.com/tavianator/status/1742991411203485713 - case EFAULT: -#endif - break; - - case ENOENT: - if (args->flags & CREATE_PARENTS) { - break; - } else { + if (errno == ENOENT) { + if (!(args->flags & CREATE_PARENTS)) { goto err; } - - default: + } else if (!errno_is_like(ENAMETOOLONG)) { goto err; } -- cgit v1.2.3 From e766015d60c927aae03b8e43d956c6976c16b2ba Mon Sep 17 00:00:00 2001 From: Tavian Barnes Date: Sat, 13 Jan 2024 15:54:46 -0500 Subject: ioq: Use the negative errno convention --- src/bfstd.c | 9 +++++++++ src/bfstd.h | 10 ++++++++++ src/bftw.c | 2 +- src/ioq.c | 32 +++++++++++--------------------- src/ioq.h | 6 ++---- 5 files changed, 33 insertions(+), 26 deletions(-) (limited to 'src/bfstd.c') diff --git a/src/bfstd.c b/src/bfstd.c index 15e8667..0a9b87c 100644 --- a/src/bfstd.c +++ b/src/bfstd.c @@ -59,6 +59,15 @@ bool errno_is_like(int category) { return error_is_like(errno, category); } +int try(int ret) { + if (ret >= 0) { + return ret; + } else { + bfs_assert(errno > 0, "errno should be positive, was %d\n", errno); + return -errno; + } +} + char *xdirname(const char *path) { size_t i = xbaseoff(path); diff --git a/src/bfstd.h b/src/bfstd.h index 8953b9b..d160c88 100644 --- a/src/bfstd.h +++ b/src/bfstd.h @@ -63,6 +63,16 @@ bool error_is_like(int error, int category); */ bool errno_is_like(int category); +/** + * Apply the "negative errno" convention. + * + * @param ret + * The return value of the attempted operation. + * @return + * ret, if non-negative, otherwise -errno. + */ +int try(int ret); + #include #ifndef O_EXEC diff --git a/src/bftw.c b/src/bftw.c index 49f07df..952b090 100644 --- a/src/bftw.c +++ b/src/bftw.c @@ -621,7 +621,7 @@ static int bftw_ioq_pop(struct bftw_state *state, bool block) { } dir = ent->opendir.dir; - if (ent->ret == 0) { + if (ent->result >= 0) { bftw_file_set_dir(cache, file, dir); } else { bftw_freedir(cache, dir); diff --git a/src/ioq.c b/src/ioq.c index 2739338..89ebb3e 100644 --- a/src/ioq.c +++ b/src/ioq.c @@ -455,42 +455,35 @@ static bool ioq_check_cancel(struct ioq *ioq, struct ioq_ent *ent) { return false; } - ent->ret = -1; - ent->error = EINTR; + ent->result = -EINTR; ioqq_push(ioq->ready, ent); return true; } /** Handle a single request synchronously. */ static void ioq_handle(struct ioq *ioq, struct ioq_ent *ent) { - int ret; - switch (ent->op) { case IOQ_CLOSE: - ret = xclose(ent->close.fd); + ent->result = try(xclose(ent->close.fd)); break; case IOQ_OPENDIR: - ret = bfs_opendir(ent->opendir.dir, ent->opendir.dfd, ent->opendir.path, ent->opendir.flags); - if (ret == 0) { + ent->result = try(bfs_opendir(ent->opendir.dir, ent->opendir.dfd, ent->opendir.path, ent->opendir.flags)); + if (ent->result >= 0) { bfs_polldir(ent->opendir.dir); } break; case IOQ_CLOSEDIR: - ret = bfs_closedir(ent->closedir.dir); + ent->result = try(bfs_closedir(ent->closedir.dir)); break; default: bfs_bug("Unknown ioq_op %d", (int)ent->op); - ret = -1; - errno = ENOSYS; + ent->result = -ENOSYS; break; } - ent->ret = ret; - ent->error = ret == 0 ? 0 : errno; - ioqq_push(ioq->ready, ent); } @@ -603,24 +596,21 @@ static void ioq_ring_reap(struct ioq_ring_state *state) { } struct ioq_ent *ent = io_uring_cqe_get_data(cqe); - ent->ret = cqe->res >= 0 ? cqe->res : -1; - ent->error = cqe->res < 0 ? -cqe->res : 0; + ent->result = cqe->res; io_uring_cqe_seen(ring, cqe); --state->submitted; - if (ent->op == IOQ_OPENDIR && ent->ret >= 0) { - int fd = ent->ret; + if (ent->op == IOQ_OPENDIR && ent->result >= 0) { + int fd = ent->result; if (ioq_check_cancel(ioq, ent)) { xclose(fd); continue; } - ent->ret = bfs_opendir(ent->opendir.dir, fd, NULL, ent->opendir.flags); - if (ent->ret == 0) { + ent->result = try(bfs_opendir(ent->opendir.dir, fd, NULL, ent->opendir.flags)); + if (ent->result >= 0) { // TODO: io_uring_prep_getdents() bfs_polldir(ent->opendir.dir); - } else { - ent->error = errno; } } diff --git a/src/ioq.h b/src/ioq.h index 87727cb..e1e5052 100644 --- a/src/ioq.h +++ b/src/ioq.h @@ -36,10 +36,8 @@ struct ioq_ent { /** The I/O operation. */ enum ioq_op op; - /** The return value of the operation. */ - int ret; - /** The error code, if the operation failed. */ - int error; + /** The return value (on success) or negative error code (on failure). */ + int result; /** Arbitrary user data. */ void *ptr; -- cgit v1.2.3 From b9bd5cbaf717f5613e9c093698c3af884586a975 Mon Sep 17 00:00:00 2001 From: Tavian Barnes Date: Thu, 1 Feb 2024 12:37:50 -0500 Subject: bfstd: Don't shadow FreeBSD's fflags_t --- src/bfstd.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'src/bfstd.c') diff --git a/src/bfstd.c b/src/bfstd.c index 0a9b87c..d19049f 100644 --- a/src/bfstd.c +++ b/src/bfstd.c @@ -639,12 +639,12 @@ int xstrtofflags(const char **str, unsigned long long *set, unsigned long long * char *str_arg = (char *)*str; #if __OpenBSD__ - typedef uint32_t fflags_t; + typedef uint32_t bfs_fflags_t; #else - typedef unsigned long fflags_t; + typedef unsigned long bfs_fflags_t; #endif - fflags_t set_arg = 0; - fflags_t clear_arg = 0; + bfs_fflags_t set_arg = 0; + bfs_fflags_t clear_arg = 0; #if __NetBSD__ int ret = string_to_flags(&str_arg, &set_arg, &clear_arg); -- cgit v1.2.3 From c8ab9926132085f2daf6b949cafda43378d50fb5 Mon Sep 17 00:00:00 2001 From: Tavian Barnes Date: Wed, 28 Feb 2024 13:00:54 -0500 Subject: stat: Use errno_is_like(ENOSYS) for EPERM kludge --- src/bfstd.c | 4 ++++ src/stat.c | 4 +--- 2 files changed, 5 insertions(+), 3 deletions(-) (limited to 'src/bfstd.c') diff --git a/src/bfstd.c b/src/bfstd.c index d19049f..ce4aa49 100644 --- a/src/bfstd.c +++ b/src/bfstd.c @@ -45,6 +45,10 @@ bool error_is_like(int error, int category) { case ENOENT: return error == ENOTDIR; + case ENOSYS: + // https://github.com/opencontainers/runc/issues/2151 + return errno == EPERM; + #if __DragonFly__ // https://twitter.com/tavianator/status/1742991411203485713 case ENAMETOOLONG: diff --git a/src/stat.c b/src/stat.c index 36222cb..2f2743b 100644 --- a/src/stat.c +++ b/src/stat.c @@ -253,9 +253,7 @@ static int bfs_stat_explicit(int at_fd, const char *at_path, int at_flags, struc if (load(&has_statx, relaxed)) { int ret = bfs_statx_impl(at_fd, at_path, at_flags, buf); - // EPERM is commonly returned in a seccomp() sandbox that does - // not allow statx() - if (ret != 0 && (errno == ENOSYS || errno == EPERM)) { + if (ret != 0 && errno_is_like(ENOSYS)) { store(&has_statx, false, relaxed); } else { return ret; -- cgit v1.2.3 From 2c3ef3a06ee1f951f6d68be6d0d3f6a1822b05b7 Mon Sep 17 00:00:00 2001 From: Tavian Barnes Date: Mon, 11 Mar 2024 09:51:03 -0400 Subject: Re-run include-what-you-use --- src/alloc.h | 1 + src/bfstd.c | 6 +++--- src/bftw.c | 1 + src/color.h | 1 - src/ctx.c | 1 + src/ctx.h | 2 ++ src/diag.c | 2 +- src/dir.h | 4 ++-- src/dstring.c | 2 ++ src/eval.c | 4 ++-- src/expr.c | 4 ++-- src/expr.h | 1 - src/ioq.c | 5 +++-- src/main.c | 1 + src/opt.c | 3 ++- src/parse.c | 3 +-- src/printf.c | 3 ++- src/trie.c | 2 -- src/trie.h | 1 - src/xspawn.c | 1 - src/xtime.c | 1 - tests/alloc.c | 1 + tests/bfstd.c | 3 --- tests/bit.c | 2 +- tests/ioq.c | 2 ++ tests/main.c | 3 --- tests/xtime.c | 4 ++-- tests/xtouch.c | 1 + 28 files changed, 33 insertions(+), 32 deletions(-) (limited to 'src/bfstd.c') diff --git a/src/alloc.h b/src/alloc.h index 60dd738..ae055bc 100644 --- a/src/alloc.h +++ b/src/alloc.h @@ -10,6 +10,7 @@ #include "config.h" #include +#include #include /** Check if a size is properly aligned. */ diff --git a/src/bfstd.c b/src/bfstd.c index ce4aa49..c6c2e7f 100644 --- a/src/bfstd.c +++ b/src/bfstd.c @@ -2,18 +2,19 @@ // SPDX-License-Identifier: 0BSD #include "bfstd.h" -#include "bit.h" #include "config.h" #include "diag.h" #include "sanity.h" #include "thread.h" #include "xregex.h" -#include #include #include #include +#include #include #include +#include +#include #include #include #include @@ -24,7 +25,6 @@ #include #include #include -#include #if BFS_USE_SYS_SYSMACROS_H # include diff --git a/src/bftw.c b/src/bftw.c index 6f52299..50b8b02 100644 --- a/src/bftw.c +++ b/src/bftw.c @@ -35,6 +35,7 @@ #include #include #include +#include /** Initialize a bftw_stat cache. */ static void bftw_stat_init(struct bftw_stat *bufs, struct bfs_stat *stat_buf, struct bfs_stat *lstat_buf) { diff --git a/src/color.h b/src/color.h index 85633a4..e3e7973 100644 --- a/src/color.h +++ b/src/color.h @@ -10,7 +10,6 @@ #include "config.h" #include "dstring.h" -#include #include /** diff --git a/src/ctx.c b/src/ctx.c index 6c84f75..f5b28c7 100644 --- a/src/ctx.c +++ b/src/ctx.c @@ -6,6 +6,7 @@ #include "color.h" #include "diag.h" #include "expr.h" +#include "list.h" #include "mtab.h" #include "pwcache.h" #include "stat.h" diff --git a/src/ctx.h b/src/ctx.h index aa91f2c..e14db21 100644 --- a/src/ctx.h +++ b/src/ctx.h @@ -18,6 +18,8 @@ #include #include +struct CFILE; + /** * The execution context for bfs. */ diff --git a/src/diag.c b/src/diag.c index 656fa89..cb27b92 100644 --- a/src/diag.c +++ b/src/diag.c @@ -11,8 +11,8 @@ #include "expr.h" #include #include +#include #include -#include /** bfs_diagf() implementation. */ attr(printf(2, 0)) diff --git a/src/dir.h b/src/dir.h index b11d454..18d907e 100644 --- a/src/dir.h +++ b/src/dir.h @@ -8,8 +8,6 @@ #ifndef BFS_DIR_H #define BFS_DIR_H -#include "alloc.h" -#include "config.h" #include /** @@ -78,6 +76,8 @@ struct bfs_dirent { */ struct bfs_dir *bfs_allocdir(void); +struct arena; + /** * Initialize an arena for directories. * diff --git a/src/dstring.c b/src/dstring.c index bc18308..10b0fad 100644 --- a/src/dstring.c +++ b/src/dstring.c @@ -7,6 +7,8 @@ #include "config.h" #include "diag.h" #include +#include +#include #include #include #include diff --git a/src/eval.c b/src/eval.c index 1711001..9e55964 100644 --- a/src/eval.c +++ b/src/eval.c @@ -25,7 +25,6 @@ #include "stat.h" #include "trie.h" #include "xregex.h" -#include "xtime.h" #include #include #include @@ -36,8 +35,9 @@ #include #include #include +#include #include -#include +#include #include #include #include diff --git a/src/expr.c b/src/expr.c index 3e0033f..5784220 100644 --- a/src/expr.c +++ b/src/expr.c @@ -4,12 +4,12 @@ #include "expr.h" #include "alloc.h" #include "ctx.h" +#include "diag.h" #include "eval.h" #include "exec.h" +#include "list.h" #include "printf.h" #include "xregex.h" -#include -#include #include struct bfs_expr *bfs_expr_new(struct bfs_ctx *ctx, bfs_eval_fn *eval_fn, size_t argc, char **argv) { diff --git a/src/expr.h b/src/expr.h index 957b04a..75cb5fd 100644 --- a/src/expr.h +++ b/src/expr.h @@ -12,7 +12,6 @@ #include "config.h" #include "eval.h" #include "stat.h" -#include #include #include diff --git a/src/ioq.c b/src/ioq.c index 00c3b86..37eed7d 100644 --- a/src/ioq.c +++ b/src/ioq.c @@ -126,13 +126,14 @@ #include "config.h" #include "diag.h" #include "dir.h" -#include "sanity.h" #include "stat.h" #include "thread.h" -#include #include +#include #include +#include #include +#include #if BFS_USE_LIBURING # include diff --git a/src/main.c b/src/main.c index 16a2576..e120f03 100644 --- a/src/main.c +++ b/src/main.c @@ -48,6 +48,7 @@ #include "bfstd.h" #include "config.h" #include "ctx.h" +#include "diag.h" #include "eval.h" #include "parse.h" #include diff --git a/src/opt.c b/src/opt.c index 74145ac..76965de 100644 --- a/src/opt.c +++ b/src/opt.c @@ -26,11 +26,13 @@ */ #include "opt.h" +#include "bftw.h" #include "bit.h" #include "color.h" #include "config.h" #include "ctx.h" #include "diag.h" +#include "dir.h" #include "eval.h" #include "exec.h" #include "expr.h" @@ -40,7 +42,6 @@ #include #include #include -#include #include static char *fake_and_arg = "-and"; diff --git a/src/parse.c b/src/parse.c index b26a50f..3b7386d 100644 --- a/src/parse.c +++ b/src/parse.c @@ -42,8 +42,7 @@ #include #include #include -#include -#include +#include #include #include diff --git a/src/printf.c b/src/printf.c index 34ed606..487f039 100644 --- a/src/printf.c +++ b/src/printf.c @@ -2,6 +2,7 @@ // SPDX-License-Identifier: 0BSD #include "printf.h" +#include "alloc.h" #include "bfstd.h" #include "bftw.h" #include "color.h" @@ -14,10 +15,10 @@ #include "mtab.h" #include "pwcache.h" #include "stat.h" -#include "xtime.h" #include #include #include +#include #include #include #include diff --git a/src/trie.c b/src/trie.c index bd5300d..1ffb23a 100644 --- a/src/trie.c +++ b/src/trie.c @@ -87,9 +87,7 @@ #include "config.h" #include "diag.h" #include "list.h" -#include #include -#include #include bfs_static_assert(CHAR_WIDTH == 8); diff --git a/src/trie.h b/src/trie.h index 02088f1..4288d76 100644 --- a/src/trie.h +++ b/src/trie.h @@ -5,7 +5,6 @@ #define BFS_TRIE_H #include "alloc.h" -#include "config.h" #include "list.h" #include #include diff --git a/src/xspawn.c b/src/xspawn.c index 8d6108b..6a94d3d 100644 --- a/src/xspawn.c +++ b/src/xspawn.c @@ -12,7 +12,6 @@ #include #include #include -#include #include #if BFS_USE_PATHS_H diff --git a/src/xtime.c b/src/xtime.c index 05f0e1a..5b259ab 100644 --- a/src/xtime.c +++ b/src/xtime.c @@ -7,7 +7,6 @@ #include "diag.h" #include #include -#include #include #include #include diff --git a/tests/alloc.c b/tests/alloc.c index 4ce23d4..9f08111 100644 --- a/tests/alloc.c +++ b/tests/alloc.c @@ -3,6 +3,7 @@ #include "tests.h" #include "../src/alloc.h" +#include "../src/config.h" #include "../src/diag.h" #include #include diff --git a/tests/bfstd.c b/tests/bfstd.c index 0ded5de..26abdb6 100644 --- a/tests/bfstd.c +++ b/tests/bfstd.c @@ -7,9 +7,6 @@ #include "../src/diag.h" #include #include -#include -#include -#include #include #include diff --git a/tests/bit.c b/tests/bit.c index b944748..3d66ce3 100644 --- a/tests/bit.c +++ b/tests/bit.c @@ -3,10 +3,10 @@ #include "tests.h" #include "../src/bit.h" +#include "../src/config.h" #include "../src/diag.h" #include #include -#include bfs_static_assert(UMAX_WIDTH(0x1) == 1); bfs_static_assert(UMAX_WIDTH(0x3) == 2); diff --git a/tests/ioq.c b/tests/ioq.c index 56e1886..1ce8f75 100644 --- a/tests/ioq.c +++ b/tests/ioq.c @@ -4,10 +4,12 @@ #include "tests.h" #include "../src/ioq.h" #include "../src/bfstd.h" +#include "../src/config.h" #include "../src/diag.h" #include "../src/dir.h" #include #include +#include /** * Test for blocking within ioq_slot_push(). diff --git a/tests/main.c b/tests/main.c index 38438b2..8849e8c 100644 --- a/tests/main.c +++ b/tests/main.c @@ -6,11 +6,8 @@ */ #include "tests.h" -#include "../src/bfstd.h" #include "../src/color.h" #include "../src/config.h" -#include "../src/diag.h" -#include #include #include #include diff --git a/tests/xtime.c b/tests/xtime.c index 3f1fec2..c8dc00b 100644 --- a/tests/xtime.c +++ b/tests/xtime.c @@ -5,10 +5,10 @@ #include "../src/xtime.h" #include "../src/bfstd.h" #include "../src/config.h" +#include "../src/diag.h" #include +#include #include -#include -#include #include static bool tm_equal(const struct tm *tma, const struct tm *tmb) { diff --git a/tests/xtouch.c b/tests/xtouch.c index 8c5c5f3..fad272f 100644 --- a/tests/xtouch.c +++ b/tests/xtouch.c @@ -11,6 +11,7 @@ #include #include #include +#include #include #include -- cgit v1.2.3 From 54490a29006529f7ceb4dc0514a075f9f4175621 Mon Sep 17 00:00:00 2001 From: Tavian Barnes Date: Wed, 20 Mar 2024 16:56:46 -0400 Subject: bfstd: Check that wcwidth() is positive wcwidth() returns -1 for non-printable characters, but terminals typically don't print anything for them, so treat them as 0. --- src/bfstd.c | 8 ++++++-- tests/bfstd.c | 3 +++ 2 files changed, 9 insertions(+), 2 deletions(-) (limited to 'src/bfstd.c') diff --git a/src/bfstd.c b/src/bfstd.c index c6c2e7f..5b64452 100644 --- a/src/bfstd.c +++ b/src/bfstd.c @@ -695,8 +695,12 @@ size_t xstrwidth(const char *str) { if (wc == WEOF) { // Assume a single-width '?' ++ret; - } else { - ret += xwcwidth(wc); + continue; + } + + int width = xwcwidth(wc); + if (width > 0) { + ret += width; } } diff --git a/tests/bfstd.c b/tests/bfstd.c index 26abdb6..1351e11 100644 --- a/tests/bfstd.c +++ b/tests/bfstd.c @@ -69,5 +69,8 @@ bool check_bfstd(void) { ret &= check_wordesc("\xF0\x9F\x98\x80", "\xF0\x9F\x98\x80", WESC_SHELL | WESC_TTY); } + ret &= bfs_check(xstrwidth("Hello world") == 11); + ret &= bfs_check(xstrwidth("Hello\1world") == 10); + return ret; } -- cgit v1.2.3 From a2a6ac8edd5d85398f6edb6afd02e683d9da9e7b Mon Sep 17 00:00:00 2001 From: Tavian Barnes Date: Thu, 21 Mar 2024 11:55:38 -0400 Subject: bfstd: New asciilen() function --- src/bfstd.c | 68 +++++++++++++++++++++++++++++++++++++---------------------- src/bfstd.h | 15 +++++++++++++ tests/bfstd.c | 15 +++++++++++++ 3 files changed, 73 insertions(+), 25 deletions(-) (limited to 'src/bfstd.c') diff --git a/src/bfstd.c b/src/bfstd.c index 5b64452..43513b8 100644 --- a/src/bfstd.c +++ b/src/bfstd.c @@ -2,6 +2,7 @@ // SPDX-License-Identifier: 0BSD #include "bfstd.h" +#include "bit.h" #include "config.h" #include "diag.h" #include "sanity.h" @@ -670,6 +671,44 @@ int xstrtofflags(const char **str, unsigned long long *set, unsigned long long * #endif } +size_t asciilen(const char *str) { + return asciinlen(str, strlen(str)); +} + +size_t asciinlen(const char *str, size_t n) { + size_t i = 0; + +#if SIZE_WIDTH % 8 == 0 + // Word-at-a-time isascii() + for (size_t word; i + sizeof(word) <= n; i += sizeof(word)) { + memcpy(&word, str + i, sizeof(word)); + + const size_t mask = (SIZE_MAX / 0xFF) << 7; // 0x808080... + word &= mask; + if (!word) { + continue; + } + +#if ENDIAN_NATIVE == ENDIAN_BIG + word = bswap(word); +#elif ENDIAN_NATIVE != ENDIAN_LITTLE + break; +#endif + + size_t first = trailing_zeros(word) / 8; + return i + first; + } +#endif + + for (; i < n; ++i) { + if (!xisascii(str[i])) { + break; + } + } + + return i; +} + wint_t xmbrtowc(const char *str, size_t *i, size_t len, mbstate_t *mb) { wchar_t wc; size_t mblen = mbrtowc(&wc, str + *i, len - *i, mb); @@ -765,36 +804,15 @@ static size_t printable_len(const char *str, size_t len, enum wesc_flags flags) invoke_once(&once, char_cache_init); // Fast path: avoid multibyte checks - size_t i, word; - for (i = 0; i + sizeof(word) <= len;) { - // Word-at-a-time isascii() - memcpy(&word, str + i, sizeof(word)); - // 0xFFFF... / 0xFF == 0x10101... - size_t mask = (SIZE_MAX / 0xFF) << 7; - if (word & mask) { - goto multibyte; - } - - for (size_t j = 0; j < sizeof(word); ++i, ++j) { - if (!wesc_isprint(str[i], flags)) { - return i; - } - } - } - - for (; i < len; ++i) { - char c = str[i]; - if (!xisascii(c)) { - goto multibyte; - } - if (!wesc_isprint(c, flags)) { + size_t asclen = asciinlen(str, len); + size_t i; + for (i = 0; i < asclen; ++i) { + if (!wesc_isprint(str[i], flags)) { return i; } } -multibyte:; mbstate_t mb = {0}; - for (size_t j = i; i < len; i = j) { wint_t wc = xmbrtowc(str, &j, len, &mb); if (wc == WEOF) { diff --git a/src/bfstd.h b/src/bfstd.h index d160c88..fc22971 100644 --- a/src/bfstd.h +++ b/src/bfstd.h @@ -177,6 +177,21 @@ int ynprompt(void); // #include +/** + * Get the length of the pure-ASCII prefix of a string. + */ +size_t asciilen(const char *str); + +/** + * Get the length of the pure-ASCII prefix of a string. + * + * @param str + * The string to check. + * @param n + * The maximum prefix length. + */ +size_t asciinlen(const char *str, size_t n); + /** * Allocate a copy of a region of memory. * diff --git a/tests/bfstd.c b/tests/bfstd.c index 1351e11..3ffab41 100644 --- a/tests/bfstd.c +++ b/tests/bfstd.c @@ -40,6 +40,21 @@ static bool check_wordesc(const char *str, const char *exp, enum wesc_flags flag bool check_bfstd(void) { bool ret = true; + ret &= bfs_check(asciilen("") == 0); + ret &= bfs_check(asciilen("@") == 1); + ret &= bfs_check(asciilen("@@") == 2); + ret &= bfs_check(asciilen("\xFF@") == 0); + ret &= bfs_check(asciilen("@\xFF") == 1); + ret &= bfs_check(asciilen("@@@@@@@@") == 8); + ret &= bfs_check(asciilen("@@@@@@@@@@@@@@@@") == 16); + ret &= bfs_check(asciilen("@@@@@@@@@@@@@@@@@@@@@@@@") == 24); + ret &= bfs_check(asciilen("@@@@@@@@@@@@@@a\xFF@@@@@@@") == 15); + ret &= bfs_check(asciilen("@@@@@@@@@@@@@@@@\xFF@@@@@@@") == 16); + ret &= bfs_check(asciilen("@@@@@@@@@@@@@@@@a\xFF@@@@@@") == 17); + ret &= bfs_check(asciilen("@@@@@@@\xFF@@@@@@a\xFF@@@@@@@") == 7); + ret &= bfs_check(asciilen("@@@@@@@@\xFF@@@@@a\xFF@@@@@@@") == 8); + ret &= bfs_check(asciilen("@@@@@@@@@\xFF@@@@a\xFF@@@@@@@") == 9); + // From man 3p basename ret &= check_base_dir("usr", ".", "usr"); ret &= check_base_dir("usr/", ".", "usr"); -- cgit v1.2.3 From 43fbffc232679ddd286f7c527755d15872c73d01 Mon Sep 17 00:00:00 2001 From: Tavian Barnes Date: Thu, 21 Mar 2024 11:55:49 -0400 Subject: bfstd: Add an ASCII fast path to xstrwidth() --- src/bfstd.c | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) (limited to 'src/bfstd.c') diff --git a/src/bfstd.c b/src/bfstd.c index 43513b8..12af438 100644 --- a/src/bfstd.c +++ b/src/bfstd.c @@ -728,8 +728,17 @@ size_t xstrwidth(const char *str) { size_t len = strlen(str); size_t ret = 0; + size_t asclen = asciinlen(str, len); + size_t i; + for (i = 0; i < asclen; ++i) { + // Assume all ASCII printables have width 1 + if (xisprint(str[i])) { + ++ret; + } + } + mbstate_t mb = {0}; - for (size_t i = 0; i < len;) { + while (i < len) { wint_t wc = xmbrtowc(str, &i, len, &mb); if (wc == WEOF) { // Assume a single-width '?' -- cgit v1.2.3 From 310bc847bca9e2457700598be99390867fd2a84e Mon Sep 17 00:00:00 2001 From: Tavian Barnes Date: Tue, 26 Mar 2024 12:18:50 -0400 Subject: bfstd: Escape ASCII tildes MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The POSIX spec [1] lists some characters that may need to be escaped. Unfortunately, the document uses ˜ (U+02DC SMALL TILDE) instead of ~ (U+007E TILDE), and I copy-pasted from it. [1]: https://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html#tag_18_02 --- src/bfstd.c | 2 +- tests/bfstd.c | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) (limited to 'src/bfstd.c') diff --git a/src/bfstd.c b/src/bfstd.c index 12af438..2499f00 100644 --- a/src/bfstd.c +++ b/src/bfstd.c @@ -908,7 +908,7 @@ static char *dollar_quote(char *dest, char *end, const char *str, size_t len, en /** How much of this string is safe as a bare word? */ static size_t bare_len(const char *str, size_t len) { // https://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html#tag_18_02 - size_t ret = strcspn(str, "|&;<>()$`\\\"' *?[#˜=%!{}"); + size_t ret = strcspn(str, "|&;<>()$`\\\"' *?[#~=%!{}"); return ret < len ? ret : len; } diff --git a/tests/bfstd.c b/tests/bfstd.c index 3ffab41..dc5ceaa 100644 --- a/tests/bfstd.c +++ b/tests/bfstd.c @@ -75,6 +75,7 @@ bool check_bfstd(void) { ret &= check_wordesc("\"word's\"", "'\"word'\\''s\"'", WESC_SHELL); ret &= check_wordesc("\033[1mbold's\033[0m", "$'\\e[1mbold\\'s\\e[0m'", WESC_SHELL | WESC_TTY); ret &= check_wordesc("\x7F", "$'\\x7F'", WESC_SHELL | WESC_TTY); + ret &= check_wordesc("~user", "\"~user\"", WESC_SHELL); const char *charmap = nl_langinfo(CODESET); if (strcmp(charmap, "UTF-8") == 0) { @@ -82,6 +83,7 @@ bool check_bfstd(void) { ret &= check_wordesc("\xF0\x9F", "$'\\xF0\\x9F'", WESC_SHELL | WESC_TTY); ret &= check_wordesc("\xF0\x9F\x98", "$'\\xF0\\x9F\\x98'", WESC_SHELL | WESC_TTY); ret &= check_wordesc("\xF0\x9F\x98\x80", "\xF0\x9F\x98\x80", WESC_SHELL | WESC_TTY); + ret &= check_wordesc("\xCB\x9Cuser", "\xCB\x9Cuser", WESC_SHELL); } ret &= bfs_check(xstrwidth("Hello world") == 11); -- cgit v1.2.3 From c66379749f423413913b406609dfe9311ba6e555 Mon Sep 17 00:00:00 2001 From: Tavian Barnes Date: Thu, 18 Apr 2024 14:53:56 -0400 Subject: Rename config.h to prelude.h --- src/alloc.c | 2 +- src/alloc.h | 2 +- src/bar.c | 2 +- src/bfstd.c | 2 +- src/bfstd.h | 2 +- src/bftw.c | 2 +- src/bit.h | 2 +- src/color.c | 2 +- src/color.h | 2 +- src/config.h | 377 --------------------------------------------------------- src/ctx.h | 2 +- src/diag.c | 2 +- src/diag.h | 2 +- src/dir.c | 2 +- src/dstring.c | 2 +- src/dstring.h | 2 +- src/eval.c | 2 +- src/eval.h | 2 +- src/exec.c | 2 +- src/expr.h | 2 +- src/fsade.c | 2 +- src/fsade.h | 2 +- src/ioq.c | 2 +- src/ioq.h | 2 +- src/main.c | 4 +- src/mtab.c | 2 +- src/mtab.h | 2 +- src/opt.c | 2 +- src/parse.c | 2 +- src/prelude.h | 377 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ src/printf.c | 2 +- src/pwcache.c | 2 +- src/sanity.h | 2 +- src/stat.c | 2 +- src/stat.h | 2 +- src/thread.c | 2 +- src/thread.h | 2 +- src/trie.c | 2 +- src/xregex.c | 2 +- src/xspawn.c | 2 +- src/xspawn.h | 2 +- src/xtime.c | 2 +- tests/alloc.c | 2 +- tests/bfstd.c | 2 +- tests/bit.c | 2 +- tests/ioq.c | 2 +- tests/main.c | 2 +- tests/tests.h | 2 +- tests/trie.c | 2 +- tests/xspawn.c | 2 +- tests/xtime.c | 2 +- tests/xtouch.c | 2 +- 52 files changed, 428 insertions(+), 428 deletions(-) delete mode 100644 src/config.h create mode 100644 src/prelude.h (limited to 'src/bfstd.c') diff --git a/src/alloc.c b/src/alloc.c index b65d0c5..ec8608f 100644 --- a/src/alloc.c +++ b/src/alloc.c @@ -1,9 +1,9 @@ // Copyright © Tavian Barnes // SPDX-License-Identifier: 0BSD +#include "prelude.h" #include "alloc.h" #include "bit.h" -#include "config.h" #include "diag.h" #include "sanity.h" #include diff --git a/src/alloc.h b/src/alloc.h index ae055bc..095134a 100644 --- a/src/alloc.h +++ b/src/alloc.h @@ -8,7 +8,7 @@ #ifndef BFS_ALLOC_H #define BFS_ALLOC_H -#include "config.h" +#include "prelude.h" #include #include #include diff --git a/src/bar.c b/src/bar.c index 8ab4112..184d9a0 100644 --- a/src/bar.c +++ b/src/bar.c @@ -1,11 +1,11 @@ // Copyright © Tavian Barnes // SPDX-License-Identifier: 0BSD +#include "prelude.h" #include "bar.h" #include "atomic.h" #include "bfstd.h" #include "bit.h" -#include "config.h" #include "dstring.h" #include #include diff --git a/src/bfstd.c b/src/bfstd.c index 2499f00..e1b4804 100644 --- a/src/bfstd.c +++ b/src/bfstd.c @@ -1,9 +1,9 @@ // Copyright © Tavian Barnes // SPDX-License-Identifier: 0BSD +#include "prelude.h" #include "bfstd.h" #include "bit.h" -#include "config.h" #include "diag.h" #include "sanity.h" #include "thread.h" diff --git a/src/bfstd.h b/src/bfstd.h index fc22971..42f5d5b 100644 --- a/src/bfstd.h +++ b/src/bfstd.h @@ -8,7 +8,7 @@ #ifndef BFS_BFSTD_H #define BFS_BFSTD_H -#include "config.h" +#include "prelude.h" #include "sanity.h" #include diff --git a/src/bftw.c b/src/bftw.c index 6130c44..c4d3c17 100644 --- a/src/bftw.c +++ b/src/bftw.c @@ -18,10 +18,10 @@ * various helper functions to take fewer parameters. */ +#include "prelude.h" #include "bftw.h" #include "alloc.h" #include "bfstd.h" -#include "config.h" #include "diag.h" #include "dir.h" #include "dstring.h" diff --git a/src/bit.h b/src/bit.h index 69df21e..17cfbcf 100644 --- a/src/bit.h +++ b/src/bit.h @@ -8,7 +8,7 @@ #ifndef BFS_BIT_H #define BFS_BIT_H -#include "config.h" +#include "prelude.h" #include #include diff --git a/src/color.c b/src/color.c index 8c32a68..f004bf2 100644 --- a/src/color.c +++ b/src/color.c @@ -1,11 +1,11 @@ // Copyright © Tavian Barnes // SPDX-License-Identifier: 0BSD +#include "prelude.h" #include "color.h" #include "alloc.h" #include "bfstd.h" #include "bftw.h" -#include "config.h" #include "diag.h" #include "dir.h" #include "dstring.h" diff --git a/src/color.h b/src/color.h index e3e7973..3278cd6 100644 --- a/src/color.h +++ b/src/color.h @@ -8,7 +8,7 @@ #ifndef BFS_COLOR_H #define BFS_COLOR_H -#include "config.h" +#include "prelude.h" #include "dstring.h" #include diff --git a/src/config.h b/src/config.h deleted file mode 100644 index 2eff1fc..0000000 --- a/src/config.h +++ /dev/null @@ -1,377 +0,0 @@ -// Copyright © Tavian Barnes -// SPDX-License-Identifier: 0BSD - -/** - * Configuration and feature/platform detection. - */ - -#ifndef BFS_CONFIG_H -#define BFS_CONFIG_H - -// Possible __STDC_VERSION__ values - -#define C95 199409L -#define C99 199901L -#define C11 201112L -#define C17 201710L -#define C23 202311L - -#include - -#if __STDC_VERSION__ < C23 -# include -# include -# include -#endif - -// bfs packaging configuration - -#ifndef BFS_COMMAND -# define BFS_COMMAND "bfs" -#endif -#ifndef BFS_HOMEPAGE -# define BFS_HOMEPAGE "https://tavianator.com/projects/bfs.html" -#endif - -// This is a symbol instead of a literal so we don't have to rebuild everything -// when the version number changes -extern const char bfs_version[]; - -// Check for system headers - -#ifdef __has_include - -#if __has_include() -# define BFS_HAS_MNTENT_H true -#endif -#if __has_include() -# define BFS_HAS_PATHS_H true -#endif -#if __has_include() -# define BFS_HAS_SYS_ACL_H true -#endif -#if __has_include() -# define BFS_HAS_SYS_CAPABILITY_H true -#endif -#if __has_include() -# define BFS_HAS_SYS_EXTATTR_H true -#endif -#if __has_include() -# define BFS_HAS_SYS_MKDEV_H true -#endif -#if __has_include() -# define BFS_HAS_SYS_PARAM_H true -#endif -#if __has_include() -# define BFS_HAS_SYS_SYSMACROS_H true -#endif -#if __has_include() -# define BFS_HAS_SYS_XATTR_H true -#endif -#if __has_include() -# define BFS_HAS_THREADS_H true -#endif -#if __has_include() -# define BFS_HAS_UTIL_H true -#endif - -#else // !__has_include - -#define BFS_HAS_MNTENT_H __GLIBC__ -#define BFS_HAS_PATHS_H true -#define BFS_HAS_SYS_ACL_H true -#define BFS_HAS_SYS_CAPABILITY_H __linux__ -#define BFS_HAS_SYS_EXTATTR_H __FreeBSD__ -#define BFS_HAS_SYS_MKDEV_H false -#define BFS_HAS_SYS_PARAM_H true -#define BFS_HAS_SYS_SYSMACROS_H __GLIBC__ -#define BFS_HAS_SYS_XATTR_H __linux__ -#define BFS_HAS_THREADS_H (!__STDC_NO_THREADS__) -#define BFS_HAS_UTIL_H __NetBSD__ - -#endif // !__has_include - -#ifndef BFS_USE_MNTENT_H -# define BFS_USE_MNTENT_H BFS_HAS_MNTENT_H -#endif -#ifndef BFS_USE_PATHS_H -# define BFS_USE_PATHS_H BFS_HAS_PATHS_H -#endif -#ifndef BFS_USE_SYS_ACL_H -# define BFS_USE_SYS_ACL_H (BFS_HAS_SYS_ACL_H && !__illumos__ && (!__linux__ || BFS_USE_LIBACL)) -#endif -#ifndef BFS_USE_SYS_CAPABILITY_H -# define BFS_USE_SYS_CAPABILITY_H (BFS_HAS_SYS_CAPABILITY_H && !__FreeBSD__ && (!__linux__ || BFS_USE_LIBCAP)) -#endif -#ifndef BFS_USE_SYS_EXTATTR_H -# define BFS_USE_SYS_EXTATTR_H (BFS_HAS_SYS_EXTATTR_H && !__DragonFly__) -#endif -#ifndef BFS_USE_SYS_MKDEV_H -# define BFS_USE_SYS_MKDEV_H BFS_HAS_SYS_MKDEV_H -#endif -#ifndef BFS_USE_SYS_PARAM_H -# define BFS_USE_SYS_PARAM_H BFS_HAS_SYS_PARAM_H -#endif -#ifndef BFS_USE_SYS_SYSMACROS_H -# define BFS_USE_SYS_SYSMACROS_H BFS_HAS_SYS_SYSMACROS_H -#endif -#ifndef BFS_USE_SYS_XATTR_H -# define BFS_USE_SYS_XATTR_H BFS_HAS_SYS_XATTR_H -#endif -#ifndef BFS_USE_THREADS_H -# define BFS_USE_THREADS_H BFS_HAS_THREADS_H -#endif -#ifndef BFS_USE_UTIL_H -# define BFS_USE_UTIL_H BFS_HAS_UTIL_H -#endif - -// Stub out feature detection on old/incompatible compilers - -#ifndef __has_feature -# define __has_feature(feat) false -#endif - -#ifndef __has_c_attribute -# define __has_c_attribute(attr) false -#endif - -#ifndef __has_attribute -# define __has_attribute(attr) false -#endif - -// Platform detection - -// Get the definition of BSD if available -#if BFS_USE_SYS_PARAM_H -# include -#endif - -#ifndef __GLIBC_PREREQ -# define __GLIBC_PREREQ(maj, min) false -#endif - -#ifndef __NetBSD_Prereq__ -# define __NetBSD_Prereq__(maj, min, patch) false -#endif - -// Fundamental utilities - -/** - * Get the length of an array. - */ -#define countof(array) (sizeof(array) / sizeof(0[array])) - -/** - * False sharing/destructive interference/largest cache line size. - */ -#ifdef __GCC_DESTRUCTIVE_SIZE -# define FALSE_SHARING_SIZE __GCC_DESTRUCTIVE_SIZE -#else -# define FALSE_SHARING_SIZE 64 -#endif - -/** - * True sharing/constructive interference/smallest cache line size. - */ -#ifdef __GCC_CONSTRUCTIVE_SIZE -# define TRUE_SHARING_SIZE __GCC_CONSTRUCTIVE_SIZE -#else -# define TRUE_SHARING_SIZE 64 -#endif - -/** - * Alignment specifier that avoids false sharing. - */ -#define cache_align alignas(FALSE_SHARING_SIZE) - -#if __COSMOPOLITAN__ -typedef long double max_align_t; -#endif - -// Wrappers for attributes - -/** - * Silence warnings about switch/case fall-throughs. - */ -#if __has_attribute(fallthrough) -# define fallthru __attribute__((fallthrough)) -#else -# define fallthru ((void)0) -#endif - -/** - * Silence warnings about unused declarations. - */ -#if __has_attribute(unused) -# define attr_maybe_unused __attribute__((unused)) -#else -# define attr_maybe_unused -#endif - -/** - * Warn if a value is unused. - */ -#if __has_attribute(warn_unused_result) -# define attr_nodiscard __attribute__((warn_unused_result)) -#else -# define attr_nodiscard -#endif - -/** - * Hint to avoid inlining a function. - */ -#if __has_attribute(noinline) -# define attr_noinline __attribute__((noinline)) -#else -# define attr_noinline -#endif - -/** - * Hint that a function is unlikely to be called. - */ -#if __has_attribute(cold) -# define attr_cold attr_noinline __attribute__((cold)) -#else -# define attr_cold attr_noinline -#endif - -/** - * Adds compiler warnings for bad printf()-style function calls, if supported. - */ -#if __has_attribute(format) -# define attr_printf(fmt, args) __attribute__((format(printf, fmt, args))) -#else -# define attr_printf(fmt, args) -#endif - -/** - * Annotates allocator-like functions. - */ -#if __has_attribute(malloc) -# if __GNUC__ >= 11 && !__OPTIMIZE__ // malloc(deallocator) disables inlining on GCC -# define attr_malloc(...) attr_nodiscard __attribute__((malloc(__VA_ARGS__))) -# else -# define attr_malloc(...) attr_nodiscard __attribute__((malloc)) -# endif -#else -# define attr_malloc(...) attr_nodiscard -#endif - -/** - * Specifies that a function returns allocations with a given alignment. - */ -#if __has_attribute(alloc_align) -# define attr_alloc_align(param) __attribute__((alloc_align(param))) -#else -# define attr_alloc_align(param) -#endif - -/** - * Specifies that a function returns allocations with a given size. - */ -#if __has_attribute(alloc_size) -# define attr_alloc_size(...) __attribute__((alloc_size(__VA_ARGS__))) -#else -# define attr_alloc_size(...) -#endif - -/** - * Shorthand for attr_alloc_align() and attr_alloc_size(). - */ -#define attr_aligned_alloc(align, ...) \ - attr_alloc_align(align) \ - attr_alloc_size(__VA_ARGS__) - -/** - * Check if function multiversioning via GNU indirect functions (ifunc) is supported. - */ -#ifndef BFS_USE_TARGET_CLONES -# if __has_attribute(target_clones) && (__GLIBC__ || __FreeBSD__) -# define BFS_USE_TARGET_CLONES true -# endif -#endif - -/** - * Apply the target_clones attribute, if available. - */ -#if BFS_USE_TARGET_CLONES -# define attr_target_clones(...) __attribute__((target_clones(__VA_ARGS__))) -#else -# define attr_target_clones(...) -#endif - -/** - * Shorthand for multiple attributes at once. attr(a, b(c), d) is equivalent to - * - * attr_a - * attr_b(c) - * attr_d - */ -#define attr(...) \ - attr__(attr_##__VA_ARGS__, none, none, none, none, none, none, none, none, none, ) - -/** - * attr() helper. For exposition, pretend we support only 2 args, instead of 9. - * There are a few cases: - * - * attr() - * => attr__(attr_, none, none) - * => attr_ => - * attr_none => - * attr_too_many_none() => - * - * attr(a) - * => attr__(attr_a, none, none) - * => attr_a => __attribute__((a)) - * attr_none => - * attr_too_many_none() => - * - * attr(a, b(c)) - * => attr__(attr_a, b(c), none, none) - * => attr_a => __attribute__((a)) - * attr_b(c) => __attribute__((b(c))) - * attr_too_many_none(none) => - * - * attr(a, b(c), d) - * => attr__(attr_a, b(c), d, none, none) - * => attr_a => __attribute__((a)) - * attr_b(c) => __attribute__((b(c))) - * attr_too_many_d(none, none) => error - * - * Some attribute names are the same as standard library functions, e.g. printf. - * Standard libraries are permitted to define these functions as macros, like - * - * #define printf(...) __builtin_printf(__VA_ARGS__) - * - * The token paste in - * - * #define attr(...) attr__(attr_##__VA_ARGS__, none, none) - * - * is necessary to prevent macro expansion before evaluating attr__(). - * Otherwise, we could get - * - * attr(printf(1, 2)) - * => attr__(__builtin_printf(1, 2), none, none) - * => attr____builtin_printf(1, 2) - * => error - */ -#define attr__(a1, a2, a3, a4, a5, a6, a7, a8, a9, none, ...) \ - a1 \ - attr_##a2 \ - attr_##a3 \ - attr_##a4 \ - attr_##a5 \ - attr_##a6 \ - attr_##a7 \ - attr_##a8 \ - attr_##a9 \ - attr_too_many_##none(__VA_ARGS__) - -// Ignore `attr_none` from expanding 1-9 argument attr(a1, a2, ...) -#define attr_none -// Ignore `attr_` from expanding 0-argument attr() -#define attr_ -// Only trigger an error on more than 9 arguments -#define attr_too_many_none(...) - -#endif // BFS_CONFIG_H diff --git a/src/ctx.h b/src/ctx.h index e14db21..fc3020c 100644 --- a/src/ctx.h +++ b/src/ctx.h @@ -8,9 +8,9 @@ #ifndef BFS_CTX_H #define BFS_CTX_H +#include "prelude.h" #include "alloc.h" #include "bftw.h" -#include "config.h" #include "diag.h" #include "expr.h" #include "trie.h" diff --git a/src/diag.c b/src/diag.c index cb27b92..deb6f26 100644 --- a/src/diag.c +++ b/src/diag.c @@ -1,11 +1,11 @@ // Copyright © Tavian Barnes // SPDX-License-Identifier: 0BSD +#include "prelude.h" #include "diag.h" #include "alloc.h" #include "bfstd.h" #include "color.h" -#include "config.h" #include "ctx.h" #include "dstring.h" #include "expr.h" diff --git a/src/diag.h b/src/diag.h index 4054c48..2b13609 100644 --- a/src/diag.h +++ b/src/diag.h @@ -8,7 +8,7 @@ #ifndef BFS_DIAG_H #define BFS_DIAG_H -#include "config.h" +#include "prelude.h" #include /** diff --git a/src/dir.c b/src/dir.c index 98518f2..53c9be3 100644 --- a/src/dir.c +++ b/src/dir.c @@ -1,10 +1,10 @@ // Copyright © Tavian Barnes // SPDX-License-Identifier: 0BSD +#include "prelude.h" #include "dir.h" #include "alloc.h" #include "bfstd.h" -#include "config.h" #include "diag.h" #include "sanity.h" #include "trie.h" diff --git a/src/dstring.c b/src/dstring.c index 10b0fad..913dda8 100644 --- a/src/dstring.c +++ b/src/dstring.c @@ -1,10 +1,10 @@ // Copyright © Tavian Barnes // SPDX-License-Identifier: 0BSD +#include "prelude.h" #include "dstring.h" #include "alloc.h" #include "bit.h" -#include "config.h" #include "diag.h" #include #include diff --git a/src/dstring.h b/src/dstring.h index 6006199..9ea7eb9 100644 --- a/src/dstring.h +++ b/src/dstring.h @@ -8,8 +8,8 @@ #ifndef BFS_DSTRING_H #define BFS_DSTRING_H +#include "prelude.h" #include "bfstd.h" -#include "config.h" #include #include diff --git a/src/eval.c b/src/eval.c index d0112c2..b103912 100644 --- a/src/eval.c +++ b/src/eval.c @@ -5,12 +5,12 @@ * Implementation of all the primary expressions. */ +#include "prelude.h" #include "eval.h" #include "bar.h" #include "bfstd.h" #include "bftw.h" #include "color.h" -#include "config.h" #include "ctx.h" #include "diag.h" #include "dir.h" diff --git a/src/eval.h b/src/eval.h index ae43628..4dd7996 100644 --- a/src/eval.h +++ b/src/eval.h @@ -9,7 +9,7 @@ #ifndef BFS_EVAL_H #define BFS_EVAL_H -#include "config.h" +#include "prelude.h" struct bfs_ctx; struct bfs_expr; diff --git a/src/exec.c b/src/exec.c index 60bfd28..e782d49 100644 --- a/src/exec.c +++ b/src/exec.c @@ -1,12 +1,12 @@ // Copyright © Tavian Barnes // SPDX-License-Identifier: 0BSD +#include "prelude.h" #include "exec.h" #include "alloc.h" #include "bfstd.h" #include "bftw.h" #include "color.h" -#include "config.h" #include "ctx.h" #include "diag.h" #include "dstring.h" diff --git a/src/expr.h b/src/expr.h index 75cb5fd..7bcace7 100644 --- a/src/expr.h +++ b/src/expr.h @@ -8,8 +8,8 @@ #ifndef BFS_EXPR_H #define BFS_EXPR_H +#include "prelude.h" #include "color.h" -#include "config.h" #include "eval.h" #include "stat.h" #include diff --git a/src/fsade.c b/src/fsade.c index 0810c7f..34a4d57 100644 --- a/src/fsade.c +++ b/src/fsade.c @@ -1,11 +1,11 @@ // Copyright © Tavian Barnes // SPDX-License-Identifier: 0BSD +#include "prelude.h" #include "fsade.h" #include "atomic.h" #include "bfstd.h" #include "bftw.h" -#include "config.h" #include "dir.h" #include "dstring.h" #include "sanity.h" diff --git a/src/fsade.h b/src/fsade.h index 1f1dbfc..6300852 100644 --- a/src/fsade.h +++ b/src/fsade.h @@ -9,7 +9,7 @@ #ifndef BFS_FSADE_H #define BFS_FSADE_H -#include "config.h" +#include "prelude.h" #define BFS_CAN_CHECK_ACL BFS_USE_SYS_ACL_H diff --git a/src/ioq.c b/src/ioq.c index b936681..189bdac 100644 --- a/src/ioq.c +++ b/src/ioq.c @@ -118,12 +118,12 @@ * [1]: https://arxiv.org/abs/2201.02179 */ +#include "prelude.h" #include "ioq.h" #include "alloc.h" #include "atomic.h" #include "bfstd.h" #include "bit.h" -#include "config.h" #include "diag.h" #include "dir.h" #include "stat.h" diff --git a/src/ioq.h b/src/ioq.h index 818eea6..d8e1573 100644 --- a/src/ioq.h +++ b/src/ioq.h @@ -8,7 +8,7 @@ #ifndef BFS_IOQ_H #define BFS_IOQ_H -#include "config.h" +#include "prelude.h" #include "dir.h" #include "stat.h" #include diff --git a/src/main.c b/src/main.c index e120f03..9d8b206 100644 --- a/src/main.c +++ b/src/main.c @@ -26,7 +26,7 @@ * - bit.h (bit manipulation) * - bfstd.[ch] (standard library wrappers/polyfills) * - color.[ch] (for pretty terminal colors) - * - config.h (configuration and feature/platform detection) + * - prelude.h (configuration and feature/platform detection) * - diag.[ch] (formats diagnostic messages) * - dir.[ch] (a directory API facade) * - dstring.[ch] (a dynamic string library) @@ -45,8 +45,8 @@ * - xtime.[ch] (date/time handling utilities) */ +#include "prelude.h" #include "bfstd.h" -#include "config.h" #include "ctx.h" #include "diag.h" #include "eval.h" diff --git a/src/mtab.c b/src/mtab.c index 86ae151..7905d14 100644 --- a/src/mtab.c +++ b/src/mtab.c @@ -1,10 +1,10 @@ // Copyright © Tavian Barnes // SPDX-License-Identifier: 0BSD +#include "prelude.h" #include "mtab.h" #include "alloc.h" #include "bfstd.h" -#include "config.h" #include "stat.h" #include "trie.h" #include diff --git a/src/mtab.h b/src/mtab.h index d99d78f..67290c2 100644 --- a/src/mtab.h +++ b/src/mtab.h @@ -8,7 +8,7 @@ #ifndef BFS_MTAB_H #define BFS_MTAB_H -#include "config.h" +#include "prelude.h" struct bfs_stat; diff --git a/src/opt.c b/src/opt.c index b74b4e1..ffc795b 100644 --- a/src/opt.c +++ b/src/opt.c @@ -25,11 +25,11 @@ * effects are reachable at all, skipping the traversal if not. */ +#include "prelude.h" #include "opt.h" #include "bftw.h" #include "bit.h" #include "color.h" -#include "config.h" #include "ctx.h" #include "diag.h" #include "dir.h" diff --git a/src/parse.c b/src/parse.c index a3e32fe..c2ae58f 100644 --- a/src/parse.c +++ b/src/parse.c @@ -8,12 +8,12 @@ * flags like always-true options, and skipping over paths wherever they appear. */ +#include "prelude.h" #include "parse.h" #include "alloc.h" #include "bfstd.h" #include "bftw.h" #include "color.h" -#include "config.h" #include "ctx.h" #include "diag.h" #include "dir.h" diff --git a/src/prelude.h b/src/prelude.h new file mode 100644 index 0000000..c3a0752 --- /dev/null +++ b/src/prelude.h @@ -0,0 +1,377 @@ +// Copyright © Tavian Barnes +// SPDX-License-Identifier: 0BSD + +/** + * Configuration and feature/platform detection. + */ + +#ifndef BFS_PRELUDE_H +#define BFS_PRELUDE_H + +// Possible __STDC_VERSION__ values + +#define C95 199409L +#define C99 199901L +#define C11 201112L +#define C17 201710L +#define C23 202311L + +#include + +#if __STDC_VERSION__ < C23 +# include +# include +# include +#endif + +// bfs packaging configuration + +#ifndef BFS_COMMAND +# define BFS_COMMAND "bfs" +#endif +#ifndef BFS_HOMEPAGE +# define BFS_HOMEPAGE "https://tavianator.com/projects/bfs.html" +#endif + +// This is a symbol instead of a literal so we don't have to rebuild everything +// when the version number changes +extern const char bfs_version[]; + +// Check for system headers + +#ifdef __has_include + +#if __has_include() +# define BFS_HAS_MNTENT_H true +#endif +#if __has_include() +# define BFS_HAS_PATHS_H true +#endif +#if __has_include() +# define BFS_HAS_SYS_ACL_H true +#endif +#if __has_include() +# define BFS_HAS_SYS_CAPABILITY_H true +#endif +#if __has_include() +# define BFS_HAS_SYS_EXTATTR_H true +#endif +#if __has_include() +# define BFS_HAS_SYS_MKDEV_H true +#endif +#if __has_include() +# define BFS_HAS_SYS_PARAM_H true +#endif +#if __has_include() +# define BFS_HAS_SYS_SYSMACROS_H true +#endif +#if __has_include() +# define BFS_HAS_SYS_XATTR_H true +#endif +#if __has_include() +# define BFS_HAS_THREADS_H true +#endif +#if __has_include() +# define BFS_HAS_UTIL_H true +#endif + +#else // !__has_include + +#define BFS_HAS_MNTENT_H __GLIBC__ +#define BFS_HAS_PATHS_H true +#define BFS_HAS_SYS_ACL_H true +#define BFS_HAS_SYS_CAPABILITY_H __linux__ +#define BFS_HAS_SYS_EXTATTR_H __FreeBSD__ +#define BFS_HAS_SYS_MKDEV_H false +#define BFS_HAS_SYS_PARAM_H true +#define BFS_HAS_SYS_SYSMACROS_H __GLIBC__ +#define BFS_HAS_SYS_XATTR_H __linux__ +#define BFS_HAS_THREADS_H (!__STDC_NO_THREADS__) +#define BFS_HAS_UTIL_H __NetBSD__ + +#endif // !__has_include + +#ifndef BFS_USE_MNTENT_H +# define BFS_USE_MNTENT_H BFS_HAS_MNTENT_H +#endif +#ifndef BFS_USE_PATHS_H +# define BFS_USE_PATHS_H BFS_HAS_PATHS_H +#endif +#ifndef BFS_USE_SYS_ACL_H +# define BFS_USE_SYS_ACL_H (BFS_HAS_SYS_ACL_H && !__illumos__ && (!__linux__ || BFS_USE_LIBACL)) +#endif +#ifndef BFS_USE_SYS_CAPABILITY_H +# define BFS_USE_SYS_CAPABILITY_H (BFS_HAS_SYS_CAPABILITY_H && !__FreeBSD__ && (!__linux__ || BFS_USE_LIBCAP)) +#endif +#ifndef BFS_USE_SYS_EXTATTR_H +# define BFS_USE_SYS_EXTATTR_H (BFS_HAS_SYS_EXTATTR_H && !__DragonFly__) +#endif +#ifndef BFS_USE_SYS_MKDEV_H +# define BFS_USE_SYS_MKDEV_H BFS_HAS_SYS_MKDEV_H +#endif +#ifndef BFS_USE_SYS_PARAM_H +# define BFS_USE_SYS_PARAM_H BFS_HAS_SYS_PARAM_H +#endif +#ifndef BFS_USE_SYS_SYSMACROS_H +# define BFS_USE_SYS_SYSMACROS_H BFS_HAS_SYS_SYSMACROS_H +#endif +#ifndef BFS_USE_SYS_XATTR_H +# define BFS_USE_SYS_XATTR_H BFS_HAS_SYS_XATTR_H +#endif +#ifndef BFS_USE_THREADS_H +# define BFS_USE_THREADS_H BFS_HAS_THREADS_H +#endif +#ifndef BFS_USE_UTIL_H +# define BFS_USE_UTIL_H BFS_HAS_UTIL_H +#endif + +// Stub out feature detection on old/incompatible compilers + +#ifndef __has_feature +# define __has_feature(feat) false +#endif + +#ifndef __has_c_attribute +# define __has_c_attribute(attr) false +#endif + +#ifndef __has_attribute +# define __has_attribute(attr) false +#endif + +// Platform detection + +// Get the definition of BSD if available +#if BFS_USE_SYS_PARAM_H +# include +#endif + +#ifndef __GLIBC_PREREQ +# define __GLIBC_PREREQ(maj, min) false +#endif + +#ifndef __NetBSD_Prereq__ +# define __NetBSD_Prereq__(maj, min, patch) false +#endif + +// Fundamental utilities + +/** + * Get the length of an array. + */ +#define countof(array) (sizeof(array) / sizeof(0[array])) + +/** + * False sharing/destructive interference/largest cache line size. + */ +#ifdef __GCC_DESTRUCTIVE_SIZE +# define FALSE_SHARING_SIZE __GCC_DESTRUCTIVE_SIZE +#else +# define FALSE_SHARING_SIZE 64 +#endif + +/** + * True sharing/constructive interference/smallest cache line size. + */ +#ifdef __GCC_CONSTRUCTIVE_SIZE +# define TRUE_SHARING_SIZE __GCC_CONSTRUCTIVE_SIZE +#else +# define TRUE_SHARING_SIZE 64 +#endif + +/** + * Alignment specifier that avoids false sharing. + */ +#define cache_align alignas(FALSE_SHARING_SIZE) + +#if __COSMOPOLITAN__ +typedef long double max_align_t; +#endif + +// Wrappers for attributes + +/** + * Silence warnings about switch/case fall-throughs. + */ +#if __has_attribute(fallthrough) +# define fallthru __attribute__((fallthrough)) +#else +# define fallthru ((void)0) +#endif + +/** + * Silence warnings about unused declarations. + */ +#if __has_attribute(unused) +# define attr_maybe_unused __attribute__((unused)) +#else +# define attr_maybe_unused +#endif + +/** + * Warn if a value is unused. + */ +#if __has_attribute(warn_unused_result) +# define attr_nodiscard __attribute__((warn_unused_result)) +#else +# define attr_nodiscard +#endif + +/** + * Hint to avoid inlining a function. + */ +#if __has_attribute(noinline) +# define attr_noinline __attribute__((noinline)) +#else +# define attr_noinline +#endif + +/** + * Hint that a function is unlikely to be called. + */ +#if __has_attribute(cold) +# define attr_cold attr_noinline __attribute__((cold)) +#else +# define attr_cold attr_noinline +#endif + +/** + * Adds compiler warnings for bad printf()-style function calls, if supported. + */ +#if __has_attribute(format) +# define attr_printf(fmt, args) __attribute__((format(printf, fmt, args))) +#else +# define attr_printf(fmt, args) +#endif + +/** + * Annotates allocator-like functions. + */ +#if __has_attribute(malloc) +# if __GNUC__ >= 11 && !__OPTIMIZE__ // malloc(deallocator) disables inlining on GCC +# define attr_malloc(...) attr_nodiscard __attribute__((malloc(__VA_ARGS__))) +# else +# define attr_malloc(...) attr_nodiscard __attribute__((malloc)) +# endif +#else +# define attr_malloc(...) attr_nodiscard +#endif + +/** + * Specifies that a function returns allocations with a given alignment. + */ +#if __has_attribute(alloc_align) +# define attr_alloc_align(param) __attribute__((alloc_align(param))) +#else +# define attr_alloc_align(param) +#endif + +/** + * Specifies that a function returns allocations with a given size. + */ +#if __has_attribute(alloc_size) +# define attr_alloc_size(...) __attribute__((alloc_size(__VA_ARGS__))) +#else +# define attr_alloc_size(...) +#endif + +/** + * Shorthand for attr_alloc_align() and attr_alloc_size(). + */ +#define attr_aligned_alloc(align, ...) \ + attr_alloc_align(align) \ + attr_alloc_size(__VA_ARGS__) + +/** + * Check if function multiversioning via GNU indirect functions (ifunc) is supported. + */ +#ifndef BFS_USE_TARGET_CLONES +# if __has_attribute(target_clones) && (__GLIBC__ || __FreeBSD__) +# define BFS_USE_TARGET_CLONES true +# endif +#endif + +/** + * Apply the target_clones attribute, if available. + */ +#if BFS_USE_TARGET_CLONES +# define attr_target_clones(...) __attribute__((target_clones(__VA_ARGS__))) +#else +# define attr_target_clones(...) +#endif + +/** + * Shorthand for multiple attributes at once. attr(a, b(c), d) is equivalent to + * + * attr_a + * attr_b(c) + * attr_d + */ +#define attr(...) \ + attr__(attr_##__VA_ARGS__, none, none, none, none, none, none, none, none, none, ) + +/** + * attr() helper. For exposition, pretend we support only 2 args, instead of 9. + * There are a few cases: + * + * attr() + * => attr__(attr_, none, none) + * => attr_ => + * attr_none => + * attr_too_many_none() => + * + * attr(a) + * => attr__(attr_a, none, none) + * => attr_a => __attribute__((a)) + * attr_none => + * attr_too_many_none() => + * + * attr(a, b(c)) + * => attr__(attr_a, b(c), none, none) + * => attr_a => __attribute__((a)) + * attr_b(c) => __attribute__((b(c))) + * attr_too_many_none(none) => + * + * attr(a, b(c), d) + * => attr__(attr_a, b(c), d, none, none) + * => attr_a => __attribute__((a)) + * attr_b(c) => __attribute__((b(c))) + * attr_too_many_d(none, none) => error + * + * Some attribute names are the same as standard library functions, e.g. printf. + * Standard libraries are permitted to define these functions as macros, like + * + * #define printf(...) __builtin_printf(__VA_ARGS__) + * + * The token paste in + * + * #define attr(...) attr__(attr_##__VA_ARGS__, none, none) + * + * is necessary to prevent macro expansion before evaluating attr__(). + * Otherwise, we could get + * + * attr(printf(1, 2)) + * => attr__(__builtin_printf(1, 2), none, none) + * => attr____builtin_printf(1, 2) + * => error + */ +#define attr__(a1, a2, a3, a4, a5, a6, a7, a8, a9, none, ...) \ + a1 \ + attr_##a2 \ + attr_##a3 \ + attr_##a4 \ + attr_##a5 \ + attr_##a6 \ + attr_##a7 \ + attr_##a8 \ + attr_##a9 \ + attr_too_many_##none(__VA_ARGS__) + +// Ignore `attr_none` from expanding 1-9 argument attr(a1, a2, ...) +#define attr_none +// Ignore `attr_` from expanding 0-argument attr() +#define attr_ +// Only trigger an error on more than 9 arguments +#define attr_too_many_none(...) + +#endif // BFS_PRELUDE_H diff --git a/src/printf.c b/src/printf.c index 3b8269e..4df399b 100644 --- a/src/printf.c +++ b/src/printf.c @@ -1,12 +1,12 @@ // Copyright © Tavian Barnes // SPDX-License-Identifier: 0BSD +#include "prelude.h" #include "printf.h" #include "alloc.h" #include "bfstd.h" #include "bftw.h" #include "color.h" -#include "config.h" #include "ctx.h" #include "diag.h" #include "dir.h" diff --git a/src/pwcache.c b/src/pwcache.c index 79437d8..af8c237 100644 --- a/src/pwcache.c +++ b/src/pwcache.c @@ -1,9 +1,9 @@ // Copyright © Tavian Barnes // SPDX-License-Identifier: 0BSD +#include "prelude.h" #include "pwcache.h" #include "alloc.h" -#include "config.h" #include "trie.h" #include #include diff --git a/src/sanity.h b/src/sanity.h index 423e6ff..e168b8f 100644 --- a/src/sanity.h +++ b/src/sanity.h @@ -8,7 +8,7 @@ #ifndef BFS_SANITY_H #define BFS_SANITY_H -#include "config.h" +#include "prelude.h" #include #if __has_feature(address_sanitizer) || defined(__SANITIZE_ADDRESS__) diff --git a/src/stat.c b/src/stat.c index 2f2743b..eca5bab 100644 --- a/src/stat.c +++ b/src/stat.c @@ -1,10 +1,10 @@ // Copyright © Tavian Barnes // SPDX-License-Identifier: 0BSD +#include "prelude.h" #include "stat.h" #include "atomic.h" #include "bfstd.h" -#include "config.h" #include "diag.h" #include "sanity.h" #include diff --git a/src/stat.h b/src/stat.h index 856a2ca..1fdd263 100644 --- a/src/stat.h +++ b/src/stat.h @@ -12,7 +12,7 @@ #ifndef BFS_STAT_H #define BFS_STAT_H -#include "config.h" +#include "prelude.h" #include #include #include diff --git a/src/thread.c b/src/thread.c index 200d8c3..3793896 100644 --- a/src/thread.c +++ b/src/thread.c @@ -1,9 +1,9 @@ // Copyright © Tavian Barnes // SPDX-License-Identifier: 0BSD +#include "prelude.h" #include "thread.h" #include "bfstd.h" -#include "config.h" #include "diag.h" #include #include diff --git a/src/thread.h b/src/thread.h index 8174fe4..db11bd8 100644 --- a/src/thread.h +++ b/src/thread.h @@ -8,7 +8,7 @@ #ifndef BFS_THREAD_H #define BFS_THREAD_H -#include "config.h" +#include "prelude.h" #include #if __STDC_VERSION__ < C23 && !defined(thread_local) diff --git a/src/trie.c b/src/trie.c index f275064..808953e 100644 --- a/src/trie.c +++ b/src/trie.c @@ -81,10 +81,10 @@ * and insert intermediate singleton "jump" nodes when necessary. */ +#include "prelude.h" #include "trie.h" #include "alloc.h" #include "bit.h" -#include "config.h" #include "diag.h" #include "list.h" #include diff --git a/src/xregex.c b/src/xregex.c index 3df27f0..c2711bc 100644 --- a/src/xregex.c +++ b/src/xregex.c @@ -1,10 +1,10 @@ // Copyright © Tavian Barnes // SPDX-License-Identifier: 0BSD +#include "prelude.h" #include "xregex.h" #include "alloc.h" #include "bfstd.h" -#include "config.h" #include "diag.h" #include "sanity.h" #include "thread.h" diff --git a/src/xspawn.c b/src/xspawn.c index 347625d..113d7ec 100644 --- a/src/xspawn.c +++ b/src/xspawn.c @@ -1,10 +1,10 @@ // Copyright © Tavian Barnes // SPDX-License-Identifier: 0BSD +#include "prelude.h" #include "xspawn.h" #include "alloc.h" #include "bfstd.h" -#include "config.h" #include "list.h" #include #include diff --git a/src/xspawn.h b/src/xspawn.h index a20cbd0..6a8f54a 100644 --- a/src/xspawn.h +++ b/src/xspawn.h @@ -8,7 +8,7 @@ #ifndef BFS_XSPAWN_H #define BFS_XSPAWN_H -#include "config.h" +#include "prelude.h" #include #include #include diff --git a/src/xtime.c b/src/xtime.c index bcf6dd3..91ed915 100644 --- a/src/xtime.c +++ b/src/xtime.c @@ -1,9 +1,9 @@ // Copyright © Tavian Barnes // SPDX-License-Identifier: 0BSD +#include "prelude.h" #include "xtime.h" #include "bfstd.h" -#include "config.h" #include "diag.h" #include #include diff --git a/tests/alloc.c b/tests/alloc.c index 54b84ba..6c0defd 100644 --- a/tests/alloc.c +++ b/tests/alloc.c @@ -1,9 +1,9 @@ // Copyright © Tavian Barnes // SPDX-License-Identifier: 0BSD +#include "prelude.h" #include "tests.h" #include "alloc.h" -#include "config.h" #include "diag.h" #include #include diff --git a/tests/bfstd.c b/tests/bfstd.c index 5e408ca..07b68b0 100644 --- a/tests/bfstd.c +++ b/tests/bfstd.c @@ -1,9 +1,9 @@ // Copyright © Tavian Barnes // SPDX-License-Identifier: 0BSD +#include "prelude.h" #include "tests.h" #include "bfstd.h" -#include "config.h" #include "diag.h" #include #include diff --git a/tests/bit.c b/tests/bit.c index b444e50..674d1b2 100644 --- a/tests/bit.c +++ b/tests/bit.c @@ -1,9 +1,9 @@ // Copyright © Tavian Barnes // SPDX-License-Identifier: 0BSD +#include "prelude.h" #include "tests.h" #include "bit.h" -#include "config.h" #include "diag.h" #include #include diff --git a/tests/ioq.c b/tests/ioq.c index a69f2bf..ef5ee3b 100644 --- a/tests/ioq.c +++ b/tests/ioq.c @@ -1,10 +1,10 @@ // Copyright © Tavian Barnes // SPDX-License-Identifier: 0BSD +#include "prelude.h" #include "tests.h" #include "ioq.h" #include "bfstd.h" -#include "config.h" #include "diag.h" #include "dir.h" #include diff --git a/tests/main.c b/tests/main.c index 281c417..429772b 100644 --- a/tests/main.c +++ b/tests/main.c @@ -5,10 +5,10 @@ * Entry point for unit tests. */ +#include "prelude.h" #include "tests.h" #include "bfstd.h" #include "color.h" -#include "config.h" #include #include #include diff --git a/tests/tests.h b/tests/tests.h index d61ffd7..9078938 100644 --- a/tests/tests.h +++ b/tests/tests.h @@ -8,7 +8,7 @@ #ifndef BFS_TESTS_H #define BFS_TESTS_H -#include "config.h" +#include "prelude.h" #include "diag.h" /** Unit test function type. */ diff --git a/tests/trie.c b/tests/trie.c index 2a6eb48..4667322 100644 --- a/tests/trie.c +++ b/tests/trie.c @@ -1,9 +1,9 @@ // Copyright © Tavian Barnes // SPDX-License-Identifier: 0BSD +#include "prelude.h" #include "tests.h" #include "trie.h" -#include "config.h" #include "diag.h" #include #include diff --git a/tests/xspawn.c b/tests/xspawn.c index fd8362e..7362aa5 100644 --- a/tests/xspawn.c +++ b/tests/xspawn.c @@ -1,10 +1,10 @@ // Copyright © Tavian Barnes // SPDX-License-Identifier: 0BSD +#include "prelude.h" #include "tests.h" #include "alloc.h" #include "bfstd.h" -#include "config.h" #include "dstring.h" #include "xspawn.h" #include diff --git a/tests/xtime.c b/tests/xtime.c index fd7aa0f..a7c63d2 100644 --- a/tests/xtime.c +++ b/tests/xtime.c @@ -1,10 +1,10 @@ // Copyright © Tavian Barnes // SPDX-License-Identifier: 0BSD +#include "prelude.h" #include "tests.h" #include "xtime.h" #include "bfstd.h" -#include "config.h" #include "diag.h" #include #include diff --git a/tests/xtouch.c b/tests/xtouch.c index b1daec7..82d749d 100644 --- a/tests/xtouch.c +++ b/tests/xtouch.c @@ -1,8 +1,8 @@ // Copyright © Tavian Barnes // SPDX-License-Identifier: 0BSD +#include "prelude.h" #include "bfstd.h" -#include "config.h" #include "sanity.h" #include "xtime.h" #include -- cgit v1.2.3 From 0035cc4ff492cab91adeb49d0c577fe5982064bd Mon Sep 17 00:00:00 2001 From: Tavian Barnes Date: Thu, 18 Apr 2024 15:27:27 -0400 Subject: config: Check for program_invocation_short_name This lets us pick it up on musl too, since there's no __MUSL__ macro. Link: https://wiki.musl-libc.org/faq#Q:-Why-is-there-no-%3Ccode%3E__MUSL__%3C/code%3E-macro? --- config/cc-define.sh | 19 +++++++++++++++++++ config/config.mk | 11 ++++++++++- config/flags.mk | 1 + config/getprogname-gnu.c | 9 +++++++++ config/getprogname.c | 9 +++++++++ config/header.mk | 38 ++++++++++++++++++++++++++++++++++++++ config/pkg.mk | 4 ++-- config/prelude.mk | 3 +++ src/bfstd.c | 6 +++--- src/prelude.h | 2 ++ 10 files changed, 96 insertions(+), 6 deletions(-) create mode 100755 config/cc-define.sh create mode 100644 config/getprogname-gnu.c create mode 100644 config/getprogname.c create mode 100644 config/header.mk (limited to 'src/bfstd.c') diff --git a/config/cc-define.sh b/config/cc-define.sh new file mode 100755 index 0000000..edb5c87 --- /dev/null +++ b/config/cc-define.sh @@ -0,0 +1,19 @@ +#!/bin/sh + +# Copyright © Tavian Barnes +# SPDX-License-Identifier: 0BSD + +# Output a C preprocessor definition based on whether a C source file could be +# compiled successfully + +set -eu + +SLUG="${1#config/}" +SLUG="${SLUG%.c}" +MACRO="BFS_HAS_$(printf '%s' "$SLUG" | tr 'a-z-' 'A-Z_')" + +if config/cc.sh "$1"; then + printf '#define %s true\n' "$MACRO" +else + printf '#define %s false\n' "$MACRO" +fi diff --git a/config/config.mk b/config/config.mk index 5a6f8d2..5750b49 100644 --- a/config/config.mk +++ b/config/config.mk @@ -6,6 +6,10 @@ include config/prelude.mk include config/exports.mk +# All configuration steps +config: ${CONFIG} ${GEN}/config.h +.PHONY: config + # Makefile fragments generated by `make config` MKS := \ ${GEN}/vars.mk \ @@ -17,7 +21,7 @@ MKS := \ ${CONFIG}: ${MKS} ${MSG} "[ GEN] ${TGT}" @printf '# %s\n' "${TGT}" >$@ - @printf 'include $${GEN}/%s\n' ${.ALLSRC:${GEN}/%=%} >>$@ + @printf 'include $${GEN}/%s\n' ${MKS:${GEN}/%=%} >>$@ ${VCAT} ${CONFIG} .PHONY: ${CONFIG} @@ -67,3 +71,8 @@ ${GEN}/pkgs.mk: ${PKG_MKS} ${PKG_MKS}: ${GEN}/flags.mk @+${MAKE} -sf config/pkg.mk TARGET=$@ .PHONY: ${PKG_MKS} + +# Compile-time feature detection +${GEN}/config.h: ${CONFIG} + @+${MAKE} -sf config/header.mk $@ +.PHONY: ${GEN}/config.h diff --git a/config/flags.mk b/config/flags.mk index d02cc8b..9959d10 100644 --- a/config/flags.mk +++ b/config/flags.mk @@ -29,6 +29,7 @@ export XLDLIBS=${LDLIBS} # Immutable flags export BFS_CPPFLAGS= \ -Isrc \ + -I${GEN} \ -D__EXTENSIONS__ \ -D_ATFILE_SOURCE \ -D_BSD_SOURCE \ diff --git a/config/getprogname-gnu.c b/config/getprogname-gnu.c new file mode 100644 index 0000000..6b97c5e --- /dev/null +++ b/config/getprogname-gnu.c @@ -0,0 +1,9 @@ +// Copyright © Tavian Barnes +// SPDX-License-Identifier: 0BSD + +#include + +int main(void) { + const char *str = program_invocation_short_name; + return str[0]; +} diff --git a/config/getprogname.c b/config/getprogname.c new file mode 100644 index 0000000..83dc8e8 --- /dev/null +++ b/config/getprogname.c @@ -0,0 +1,9 @@ +// Copyright © Tavian Barnes +// SPDX-License-Identifier: 0BSD + +#include + +int main(void) { + const char *str = getprogname(); + return str[0]; +} diff --git a/config/header.mk b/config/header.mk new file mode 100644 index 0000000..3a1271e --- /dev/null +++ b/config/header.mk @@ -0,0 +1,38 @@ +# Copyright © Tavian Barnes +# SPDX-License-Identifier: 0BSD + +# Makefile that generates gen/config.h + +include config/prelude.mk +include ${GEN}/config.mk +include config/exports.mk + +# All header fragments we generate +HEADERS := \ + ${GEN}/getprogname.h \ + ${GEN}/getprogname-gnu.h + +${GEN}/config.h: ${HEADERS} + ${MSG} "[ GEN] ${TGT}" + printf '// %s\n' "${TGT}" >$@ + printf '#ifndef BFS_CONFIG_H\n' >>$@ + printf '#define BFS_CONFIG_H\n' >>$@ + cat ${.ALLSRC} >>$@ + printf '#endif // BFS_CONFIG_H\n' >>$@ + cat ${.ALLSRC:%=%.log} >$@.log + ${RM} ${.ALLSRC} ${.ALLSRC:%=%.log} + ${VCAT} $@ +.PHONY: ${GEN}/config.h + +# The C source file to attempt to compile +CSRC = ${@:${GEN}/%.h=config/%.c} + +${HEADERS}:: + config/cc-define.sh ${CSRC} >$@ 2>$@.log + if ! [ "${IS_V}" ]; then \ + if grep -q 'true$$' $@; then \ + printf '[ CC ] %-${MSG_WIDTH}s ✔\n' ${CSRC}; \ + else \ + printf '[ CC ] %-${MSG_WIDTH}s ✘\n' ${CSRC}; \ + fi; \ + fi diff --git a/config/pkg.mk b/config/pkg.mk index 6f868be..fafe562 100644 --- a/config/pkg.mk +++ b/config/pkg.mk @@ -17,7 +17,7 @@ default:: @if [ "${IS_V}" ]; then \ cat ${TARGET}; \ elif grep -q PKGS ${TARGET}; then \ - printf '[ GEN] %-18s ✔\n' ${SHORT}; \ + printf '[ GEN] %-${MSG_WIDTH}s ✔\n' ${SHORT}; \ else \ - printf '[ GEN] %-18s ✘\n' ${SHORT}; \ + printf '[ GEN] %-${MSG_WIDTH}s ✘\n' ${SHORT}; \ fi diff --git a/config/prelude.mk b/config/prelude.mk index dbc6875..0ac5fde 100644 --- a/config/prelude.mk +++ b/config/prelude.mk @@ -109,6 +109,9 @@ MSG = @msg() { \ }; \ msg +# Maximum width of a short message, to align the [X] +MSG_WIDTH := 24 + # cat a file if V=1 VCAT,y := @cat VCAT, := @: diff --git a/src/bfstd.c b/src/bfstd.c index e1b4804..e8a927a 100644 --- a/src/bfstd.c +++ b/src/bfstd.c @@ -186,10 +186,10 @@ char *xgetdelim(FILE *file, char delim) { const char *xgetprogname(void) { const char *cmd = NULL; -#if __GLIBC__ - cmd = program_invocation_short_name; -#elif BSD +#if BFS_HAS_GETPROGNAME cmd = getprogname(); +#elif BFS_HAS_GETPROGNAME_GNU + cmd = program_invocation_short_name; #endif if (!cmd) { diff --git a/src/prelude.h b/src/prelude.h index c3a0752..a23b167 100644 --- a/src/prelude.h +++ b/src/prelude.h @@ -26,6 +26,8 @@ // bfs packaging configuration +#include "config.h" + #ifndef BFS_COMMAND # define BFS_COMMAND "bfs" #endif -- cgit v1.2.3 From 536075930140c7886c61997be31c41d651f48818 Mon Sep 17 00:00:00 2001 From: Tavian Barnes Date: Thu, 18 Apr 2024 16:24:56 -0400 Subject: config: Check for confstr() --- config/confstr.c | 9 +++++++++ config/header.mk | 1 + src/bfstd.c | 10 +++++----- 3 files changed, 15 insertions(+), 5 deletions(-) create mode 100644 config/confstr.c (limited to 'src/bfstd.c') diff --git a/config/confstr.c b/config/confstr.c new file mode 100644 index 0000000..58280b4 --- /dev/null +++ b/config/confstr.c @@ -0,0 +1,9 @@ +// Copyright © Tavian Barnes +// SPDX-License-Identifier: 0BSD + +#include + +int main(void) { + confstr(_CS_PATH, NULL, 0); + return 0; +} diff --git a/config/header.mk b/config/header.mk index cc4ae05..b6915d5 100644 --- a/config/header.mk +++ b/config/header.mk @@ -9,6 +9,7 @@ include config/exports.mk # All header fragments we generate HEADERS := \ + ${GEN}/confstr.h \ ${GEN}/getdents.h \ ${GEN}/getdents64.h \ ${GEN}/getdents64-syscall.h \ diff --git a/src/bfstd.c b/src/bfstd.c index e8a927a..3eff024 100644 --- a/src/bfstd.c +++ b/src/bfstd.c @@ -581,10 +581,7 @@ int xfaccessat(int fd, const char *path, int amode) { } char *xconfstr(int name) { -#if __ANDROID__ - errno = ENOTSUP; - return NULL; -#else +#if BFS_HAS_CONFSTR size_t len = confstr(name, NULL, 0); if (len == 0) { return NULL; @@ -601,7 +598,10 @@ char *xconfstr(int name) { } return str; -#endif // !__ANDROID__ +#else + errno = ENOTSUP; + return NULL; +#endif } char *xreadlinkat(int fd, const char *path, size_t size) { -- cgit v1.2.3 From 71f822ec2bf8c41f782f154d87b7b415a530dd03 Mon Sep 17 00:00:00 2001 From: Tavian Barnes Date: Thu, 18 Apr 2024 17:48:53 -0400 Subject: config: Check for pipe2() --- config/header.mk | 1 + config/pipe2.c | 10 ++++++++++ src/bfstd.c | 2 +- 3 files changed, 12 insertions(+), 1 deletion(-) create mode 100644 config/pipe2.c (limited to 'src/bfstd.c') diff --git a/config/header.mk b/config/header.mk index ec53dfa..55657f8 100644 --- a/config/header.mk +++ b/config/header.mk @@ -16,6 +16,7 @@ HEADERS := \ ${GEN}/getdents64-syscall.h \ ${GEN}/getprogname.h \ ${GEN}/getprogname-gnu.h \ + ${GEN}/pipe2.h \ ${GEN}/posix-spawn-addfchdir.h \ ${GEN}/posix-spawn-addfchdir-np.h \ ${GEN}/statx.h \ diff --git a/config/pipe2.c b/config/pipe2.c new file mode 100644 index 0000000..4cb43b5 --- /dev/null +++ b/config/pipe2.c @@ -0,0 +1,10 @@ +// Copyright © Tavian Barnes +// SPDX-License-Identifier: 0BSD + +#include +#include + +int main(void) { + int fds[2]; + return pipe2(fds, O_CLOEXEC); +} diff --git a/src/bfstd.c b/src/bfstd.c index 3eff024..e2c2b97 100644 --- a/src/bfstd.c +++ b/src/bfstd.c @@ -489,7 +489,7 @@ int dup_cloexec(int fd) { } int pipe_cloexec(int pipefd[2]) { -#if __linux__ || (BSD && !__APPLE__) +#if BFS_HAS_PIPE2 return pipe2(pipefd, O_CLOEXEC); #else if (pipe(pipefd) != 0) { -- cgit v1.2.3 From 6cdb407aa23d8b129e9b9a49a4528c3e0def69e6 Mon Sep 17 00:00:00 2001 From: Tavian Barnes Date: Fri, 19 Apr 2024 14:15:30 -0400 Subject: config: Check for strerror_[lr]() --- config/header.mk | 6 +++++- config/strerror-l.c | 11 +++++++++++ config/strerror-r-gnu.c | 11 +++++++++++ config/strerror-r-posix.c | 11 +++++++++++ config/uselocale.c | 9 +++++++++ src/bfstd.c | 42 ++++++++++++++++++++---------------------- 6 files changed, 67 insertions(+), 23 deletions(-) create mode 100644 config/strerror-l.c create mode 100644 config/strerror-r-gnu.c create mode 100644 config/strerror-r-posix.c create mode 100644 config/uselocale.c (limited to 'src/bfstd.c') diff --git a/config/header.mk b/config/header.mk index 55657f8..36ad98e 100644 --- a/config/header.mk +++ b/config/header.mk @@ -20,7 +20,11 @@ HEADERS := \ ${GEN}/posix-spawn-addfchdir.h \ ${GEN}/posix-spawn-addfchdir-np.h \ ${GEN}/statx.h \ - ${GEN}/statx-syscall.h + ${GEN}/statx-syscall.h \ + ${GEN}/strerror-l.h \ + ${GEN}/strerror-r-gnu.h \ + ${GEN}/strerror-r-posix.h \ + ${GEN}/uselocale.h ${GEN}/config.h: ${HEADERS} ${MSG} "[ GEN] ${TGT}" diff --git a/config/strerror-l.c b/config/strerror-l.c new file mode 100644 index 0000000..3dcc4d7 --- /dev/null +++ b/config/strerror-l.c @@ -0,0 +1,11 @@ +// Copyright © Tavian Barnes +// SPDX-License-Identifier: 0BSD + +#include +#include +#include + +int main(void) { + locale_t locale = duplocale(LC_GLOBAL_LOCALE); + return !strerror_l(ENOMEM, locale); +} diff --git a/config/strerror-r-gnu.c b/config/strerror-r-gnu.c new file mode 100644 index 0000000..26ca0ee --- /dev/null +++ b/config/strerror-r-gnu.c @@ -0,0 +1,11 @@ +// Copyright © Tavian Barnes +// SPDX-License-Identifier: 0BSD + +#include +#include + +int main(void) { + char buf[256]; + // Check that strerror_r() returns a pointer + return *strerror_r(ENOMEM, buf, sizeof(buf)); +} diff --git a/config/strerror-r-posix.c b/config/strerror-r-posix.c new file mode 100644 index 0000000..41b2d30 --- /dev/null +++ b/config/strerror-r-posix.c @@ -0,0 +1,11 @@ +// Copyright © Tavian Barnes +// SPDX-License-Identifier: 0BSD + +#include +#include + +int main(void) { + char buf[256]; + // Check that strerror_r() returns an integer + return 2 * strerror_r(ENOMEM, buf, sizeof(buf)); +} diff --git a/config/uselocale.c b/config/uselocale.c new file mode 100644 index 0000000..a712ff8 --- /dev/null +++ b/config/uselocale.c @@ -0,0 +1,9 @@ +// Copyright © Tavian Barnes +// SPDX-License-Identifier: 0BSD + +#include + +int main(void) { + locale_t locale = uselocale((locale_t)0); + return locale == LC_GLOBAL_LOCALE; +} diff --git a/src/bfstd.c b/src/bfstd.c index e2c2b97..1144380 100644 --- a/src/bfstd.c +++ b/src/bfstd.c @@ -317,35 +317,33 @@ const char *xstrerror(int errnum) { const char *ret = NULL; static thread_local char buf[256]; - // - __APPLE__ - // - __COSMOPOLITAN__ - // - No strerror_l() - // - __FreeBSD__ && SANITIZE_MEMORY - // - duplocale() triggers https://github.com/llvm/llvm-project/issues/65532 -#if __APPLE__ || __COSMOPOLITAN__ || (__FreeBSD__ && SANITIZE_MEMORY) - if (strerror_r(errnum, buf, sizeof(buf)) == 0) { - ret = buf; - } -#else -# if __NetBSD__ - // NetBSD has no thread-specific locales - locale_t loc = LC_GLOBAL_LOCALE; -# else + // On FreeBSD with MemorySanitizer, duplocale() triggers + // https://github.com/llvm/llvm-project/issues/65532 +#if BFS_HAS_STRERROR_L && !(__FreeBSD__ && SANITIZE_MEMORY) +# if BFS_HAS_USELOCALE locale_t loc = uselocale((locale_t)0); +# else + locale_t loc = LC_GLOBAL_LOCALE; # endif - locale_t copy = loc; - if (copy == LC_GLOBAL_LOCALE) { - copy = duplocale(copy); + bool free_loc = false; + if (loc == LC_GLOBAL_LOCALE) { + loc = duplocale(loc); + free_loc = true; } - if (copy != (locale_t)0) { - ret = strerror_l(errnum, copy); - - if (loc == LC_GLOBAL_LOCALE) { - freelocale(copy); + if (loc != (locale_t)0) { + ret = strerror_l(errnum, loc); + if (free_loc) { + freelocale(loc); } } +#elif BFS_HAS_STRERROR_R_POSIX + if (strerror_r(errnum, buf, sizeof(buf)) == 0) { + ret = buf; + } +#elif BFS_HAS_STRERROR_R_GNU + ret = strerror_r(errnum, buf, sizeof(buf)); #endif if (!ret) { -- cgit v1.2.3 From 3a72b93d26ad2bb06ea0b7d39257130084b1ee1e Mon Sep 17 00:00:00 2001 From: Tavian Barnes Date: Wed, 24 Apr 2024 12:47:12 -0400 Subject: printf: Refactor %y/%Y implementation --- src/bfstd.c | 68 ++++++++++++++++++++++++++++++------------------------------ src/bftw.h | 4 ++-- src/printf.c | 40 +++++++++++++++-------------------- 3 files changed, 53 insertions(+), 59 deletions(-) (limited to 'src/bfstd.c') diff --git a/src/bfstd.c b/src/bfstd.c index 1144380..f8ce871 100644 --- a/src/bfstd.c +++ b/src/bfstd.c @@ -252,40 +252,6 @@ int ynprompt(void) { return ret; } -/** Get the single character describing the given file type. */ -static char type_char(mode_t mode) { - switch (mode & S_IFMT) { - case S_IFREG: - return '-'; - case S_IFBLK: - return 'b'; - case S_IFCHR: - return 'c'; - case S_IFDIR: - return 'd'; - case S_IFLNK: - return 'l'; - case S_IFIFO: - return 'p'; - case S_IFSOCK: - return 's'; -#ifdef S_IFDOOR - case S_IFDOOR: - return 'D'; -#endif -#ifdef S_IFPORT - case S_IFPORT: - return 'P'; -#endif -#ifdef S_IFWHT - case S_IFWHT: - return 'w'; -#endif - } - - return '?'; -} - void *xmemdup(const void *src, size_t size) { void *ret = malloc(size); if (ret) { @@ -356,6 +322,40 @@ const char *xstrerror(int errnum) { return ret; } +/** Get the single character describing the given file type. */ +static char type_char(mode_t mode) { + switch (mode & S_IFMT) { + case S_IFREG: + return '-'; + case S_IFBLK: + return 'b'; + case S_IFCHR: + return 'c'; + case S_IFDIR: + return 'd'; + case S_IFLNK: + return 'l'; + case S_IFIFO: + return 'p'; + case S_IFSOCK: + return 's'; +#ifdef S_IFDOOR + case S_IFDOOR: + return 'D'; +#endif +#ifdef S_IFPORT + case S_IFPORT: + return 'P'; +#endif +#ifdef S_IFWHT + case S_IFWHT: + return 'w'; +#endif + } + + return '?'; +} + void xstrmode(mode_t mode, char str[11]) { strcpy(str, "----------"); diff --git a/src/bftw.h b/src/bftw.h index 2805361..8656ca7 100644 --- a/src/bftw.h +++ b/src/bftw.h @@ -54,7 +54,7 @@ struct BFTW { /** The file type. */ enum bfs_type type; - /** The errno that occurred, if type == BFTW_ERROR. */ + /** The errno that occurred, if type == BFS_ERROR. */ int error; /** A parent file descriptor for the *at() family of calls. */ @@ -104,7 +104,7 @@ const struct bfs_stat *bftw_cached_stat(const struct BFTW *ftwbuf, enum bfs_stat * @param flags * flags for bfs_stat(). Pass ftwbuf->stat_flags for the default flags. * @return - * The type of the file, or BFTW_ERROR if an error occurred. + * The type of the file, or BFS_ERROR if an error occurred. */ enum bfs_type bftw_type(const struct BFTW *ftwbuf, enum bfs_stat_flags flags); diff --git a/src/printf.c b/src/printf.c index 4df399b..e39d756 100644 --- a/src/printf.c +++ b/src/printf.c @@ -520,10 +520,14 @@ static const char *bfs_printf_type(enum bfs_type type) { return "p"; case BFS_LNK: return "l"; + case BFS_PORT: + return "P"; case BFS_REG: return "f"; case BFS_SOCK: return "s"; + case BFS_WHT: + return "w"; default: return "U"; } @@ -537,34 +541,24 @@ static int bfs_printf_y(CFILE *cfile, const struct bfs_fmt *fmt, const struct BF /** %Y: target type */ static int bfs_printf_Y(CFILE *cfile, const struct bfs_fmt *fmt, const struct BFTW *ftwbuf) { - int error = 0; - - if (ftwbuf->type != BFS_LNK) { - return bfs_printf_y(cfile, fmt, ftwbuf); - } - - const char *type = "U"; + enum bfs_type type = bftw_type(ftwbuf, BFS_STAT_FOLLOW); + const char *str; - const struct bfs_stat *statbuf = bftw_stat(ftwbuf, BFS_STAT_FOLLOW); - if (statbuf) { - type = bfs_printf_type(bfs_mode_to_type(statbuf->mode)); - } else { - switch (errno) { - case ELOOP: - type = "L"; - break; - case ENOENT: - case ENOTDIR: - type = "N"; - break; - default: - type = "?"; + int error = 0; + if (type == BFS_ERROR) { + if (errno_is_like(ELOOP)) { + str = "L"; + } else if (errno_is_like(ENOENT)) { + str = "N"; + } else { + str = "?"; error = errno; - break; } + } else { + str = bfs_printf_type(type); } - int ret = dyn_fprintf(cfile->file, fmt, type); + int ret = dyn_fprintf(cfile->file, fmt, str); if (error != 0) { ret = -1; errno = error; -- cgit v1.2.3 From 39b51c6d6e947778bf2b63fc9586a3236665881e Mon Sep 17 00:00:00 2001 From: Tavian Barnes Date: Tue, 7 May 2024 13:07:45 -0400 Subject: build: Add checks for strtofflags() and string_to_flags() --- build/has/string-to-flags.c | 9 +++++++++ build/has/strtofflags.c | 9 +++++++++ build/header.mk | 2 ++ src/bfstd.c | 16 +++++++++------- 4 files changed, 29 insertions(+), 7 deletions(-) create mode 100644 build/has/string-to-flags.c create mode 100644 build/has/strtofflags.c (limited to 'src/bfstd.c') diff --git a/build/has/string-to-flags.c b/build/has/string-to-flags.c new file mode 100644 index 0000000..027d72c --- /dev/null +++ b/build/has/string-to-flags.c @@ -0,0 +1,9 @@ +// Copyright © Tavian Barnes +// SPDX-License-Identifier: 0BSD + +#include +#include + +int main(void) { + return string_to_flags(NULL, NULL, NULL); +} diff --git a/build/has/strtofflags.c b/build/has/strtofflags.c new file mode 100644 index 0000000..73ecbcb --- /dev/null +++ b/build/has/strtofflags.c @@ -0,0 +1,9 @@ +// Copyright © Tavian Barnes +// SPDX-License-Identifier: 0BSD + +#include +#include + +int main(void) { + return strtofflags(NULL, NULL, NULL); +} diff --git a/build/header.mk b/build/header.mk index d235fd0..2cd13fa 100644 --- a/build/header.mk +++ b/build/header.mk @@ -40,6 +40,8 @@ HEADERS := \ gen/has/strerror-l.h \ gen/has/strerror-r-gnu.h \ gen/has/strerror-r-posix.h \ + gen/has/string-to-flags.h \ + gen/has/strtofflags.h \ gen/has/timegm.h \ gen/has/tm-gmtoff.h \ gen/has/uselocale.h diff --git a/src/bfstd.c b/src/bfstd.c index f8ce871..0ac3a72 100644 --- a/src/bfstd.c +++ b/src/bfstd.c @@ -637,8 +637,14 @@ error: return NULL; } +#if BFS_HAS_STRTOFFLAGS +# define BFS_STRTOFFLAGS strtofflags +#elif BFS_HAS_STRING_TO_FLAGS +# define BFS_STRTOFFLAGS string_to_flags +#endif + int xstrtofflags(const char **str, unsigned long long *set, unsigned long long *clear) { -#if BSD && !__GNU__ +#ifdef BFS_STRTOFFLAGS char *str_arg = (char *)*str; #if __OpenBSD__ @@ -649,11 +655,7 @@ int xstrtofflags(const char **str, unsigned long long *set, unsigned long long * bfs_fflags_t set_arg = 0; bfs_fflags_t clear_arg = 0; -#if __NetBSD__ - int ret = string_to_flags(&str_arg, &set_arg, &clear_arg); -#else - int ret = strtofflags(&str_arg, &set_arg, &clear_arg); -#endif + int ret = BFS_STRTOFFLAGS(&str_arg, &set_arg, &clear_arg); *str = str_arg; *set = set_arg; @@ -663,7 +665,7 @@ int xstrtofflags(const char **str, unsigned long long *set, unsigned long long * errno = EINVAL; } return ret; -#else // !BSD +#else // !BFS_STRTOFFLAGS errno = ENOTSUP; return -1; #endif -- cgit v1.2.3