aboutsummaryrefslogtreecommitdiff
path: root/vendor/librune/cbs.h
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/librune/cbs.h')
-rw-r--r--vendor/librune/cbs.h953
1 files changed, 0 insertions, 953 deletions
diff --git a/vendor/librune/cbs.h b/vendor/librune/cbs.h
deleted file mode 100644
index b8b7ece..0000000
--- a/vendor/librune/cbs.h
+++ /dev/null
@@ -1,953 +0,0 @@
-/* Single-header library to help write build scripts in C. This library is
- POSIX compliant, so it should work on all respectible UNIX-like systems.
-
- You can find the CBS git repository at https://git.sr.ht/~mango/cbs and you
- can include this in your project with the following command:
-
- $ wget 'https://git.sr.ht/~mango/cbs/blob/master/cbs.h'
-
- This library is licensed under the 0-Clause BSD license, and as such you may
- do whatever you want to it, however you want to it, whenever you want. You
- are encouraged in fact to modify this library to suit your specific usecase.
-
- All functions and macros are documented. You can figure out the API pretty
- easily by just reading the comments in this file.
-
- In many cases you may want to be able to execute commands on multiple threads
- to speed up compilation, such as the -j option when using Make. Functions
- for creating and using thread pools will be made available if the CBS_PTHREAD
- macro is defined before including this file. Do note that on POSIX platforms
- it will require linking to the pthreads library when bootstrapping the build
- script.
-
- This file does not support C89. Fuck C89, that shit is ancient. Move on.
-
- IMPORTANT NOTE: Any identifiers prefixed with an underscore (e.g. ‘_rebuild’)
- are meant for internal use only and you should not touch them unless you know
- what you’re doing.
-
- IMPORTANT NOTE: All the functions and macros in this library will terminate
- the program on error. If this is undesired behavior, feel free to edit the
- functions to return errors.
-
- IMPORTANT NOTE: This library is built with the assumption that the source
- file for your build script and your build script are in the SAME DIRECTORY.
-
- There are a few exceptions to the above rule, and they are documented.
-
- This library does not aim to ever support Windows */
-
-#ifndef C_BUILD_SYSTEM_H
-#define C_BUILD_SYSTEM_H
-
-#ifdef __GNUC__
-# pragma GCC diagnostic push
-# pragma GCC diagnostic ignored "-Wunused-function"
-# pragma GCC diagnostic ignored "-Wparentheses"
-#endif
-
-/* Assert that the user is building for a supported platform. The only portable
- way to check for POSIX is to validate that unistd.h exists. This is only
- possible without compiler extensions in C23 (although some compilers support
- it as an extension in earlier editions), so people compiling for pre-C23
- might not get this error if on a bad platform, and may end up being a bit
- confused.
-
- It’s just a maybe though, this is nothing more than a sanity check for the
- users sake. */
-#if defined(__has_include) && !__has_include(<unistd.h>)
-# error "Non-POSIX platform detected"
-#endif
-
-#ifdef __APPLE__
-# define st_mtim st_mtimespec
-#endif
-
-#include <sys/stat.h>
-#include <sys/wait.h>
-
-#include <errno.h>
-#include <libgen.h>
-#include <limits.h>
-#ifdef CBS_PTHREAD
-# include <pthread.h>
-#endif
-#include <stdarg.h>
-#include <stdint.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-#include <wordexp.h>
-
-/* C23 changed a lot so we want to check for it */
-#if __STDC_VERSION__ >= 202000
-# define CBS_IS_C23 1
-#endif
-
-/* Some C23 compat. In C23 booleans are actual keywords, and the noreturn
- attribute is different. */
-#if CBS_IS_C23
-# define noreturn [[noreturn]]
-#else
-# include <stdbool.h>
-# include <stddef.h>
-# include <stdnoreturn.h>
-# define nullptr NULL
-#endif
-
-/* Give helpful diagnostics when people use die() incorrectly on GCC. C23
- introduced C++ attribute syntax, so we need a check for that too. */
-#ifdef __GNUC__
-# if CBS_IS_C23
-# define ATTR_FMT [[gnu::format(printf, 1, 2)]]
-# else
-# define ATTR_FMT __attribute__((format(printf, 1, 2)))
-# endif
-#else
-# define ATTR_FMT
-#endif
-
-/* Clang defines this attribute, and while it does nothing it does serve as
- good documentation. */
-#ifndef _Nullable
-# define _Nullable
-#endif
-
-/* Convert the given variadic arguments to a string array */
-#define _vtoa(...) ((char *[]){__VA_ARGS__})
-
-/* Internal global versions of argc and argv, so our functions and macros can
- access them from anywhere. */
-static int _cbs_argc;
-static char **_cbs_argv;
-
-/* A vector of strings used to accumulate output of functions such as pcquery().
- The array of strings buf has length len, and is not null-terminated. You
- should always zero-initialize variables of this type. */
-struct strv {
- char **buf;
- size_t len;
-};
-
-/* Free and zero a string vector. Because this function zeros the structure, it
- is safe to reuse the vector after this function is called. */
-static void strvfree(struct strv *);
-
-/* A wrapper function around realloc(). It behaves exactly the same except
- instead of taking a buffer size as an argument, it takes a count n of
- elements, and a size m of each element. This allows it to properly check for
- overflow, and errors if overflow would occur. */
-static void *bufalloc(void *_Nullable, size_t n, size_t m);
-
-/* Error reporting functions. The die() function takes the same arguments as
- printf() and prints the corresponding string to stderr. It also prefixes the
- string with the command name followed by a colon, and suffixes the string
- with a colon and the error string returned from strerror().
-
- If you want to print just the error message and no custom text, NULL may be
- passed to die(). NULL should not be passed to diex().
-
- diex() is the same as die() but does not print a strerror() error string. */
-ATTR_FMT noreturn static void die(const char *_Nullable, ...);
-ATTR_FMT noreturn static void diex(const char *, ...);
-
-/* Initializes some data required for this header to work properly. This should
- be the first thing called in main() with argc and argv passed. It also
- chdir()s into the directory where the build script is located. */
-static void cbsinit(int, char **);
-
-/* Get the number of items in the array a */
-#define lengthof(a) (sizeof(a) / sizeof(*(a)))
-
-/* Struct representing a CLI command that various functions act on. You should
- always zero-initialize variables of this type before use.
-
- After executing a command, you can reuse the already allocated buffer this
- command holds by calling cmdclr(). When you’re really done with an object of
- this type, remember to call free() on ._argv.
-
- The ._argv field is a NULL-terminated list of command arguments of length
- ._len. You may safely read from both of these fields but they should NOT be
- modified without use of cmdadd() and cmdaddv(). */
-typedef struct {
- char **_argv;
- size_t _len, _cap;
-} cmd_t;
-
-/* Returns whether or not a binary of the given name exists in the users
- environment as defined by $PATH. */
-static bool binexists(const char *);
-
-/* cmdadd() adds the variadic string arguments to the given command.
- Alternatively, the cmdaddv() function adds the n strings pointed to by p to
- the given command. */
-static void cmdaddv(cmd_t *, char **p, size_t n);
-#define cmdadd(cmd, ...) \
- cmdaddv(cmd, _vtoa(__VA_ARGS__), lengthof(_vtoa(__VA_ARGS__)))
-
-/* Clear (but not free) the command c. Useful for reusing the same command
- struct to minimize allocations. */
-static void cmdclr(cmd_t *c);
-
-/* The cmdexec() function executes the given command and waits for it to
- terminate, returning its exit code. The cmdexeca() function executes the
- given command and returns immediately, returning its process ID.
-
- The cmdexecb() function is like cmdexec() except it writes the given commands
- standard output to the character buffer pointed to by p. It also stores the
- size of the output in *n. The character buffer p is null-terminated. If the
- given command produces no output to the standard output, p will be set to
- NULL.
-
- cmdexec() and cmdexecb() have the same return values as cmdwait(). */
-static int cmdexec(cmd_t);
-static pid_t cmdexeca(cmd_t);
-static int cmdexecb(cmd_t, char **p, size_t *n);
-
-/* Wait for the process with the given PID to terminate, and return its exit
- status. If the process was terminated by a signal 256 is returned. */
-static int cmdwait(pid_t);
-
-/* Write a representation of the given command to the given file stream. This
- can be used to mimick the echoing behavior of make(1). The cmdput() function
- is a nice convenience function so you can avoid writing ‘stdout’ all the
- time. */
-static void cmdput(cmd_t);
-static void cmdputf(FILE *, cmd_t);
-
-/* Expand the environment variable s using /bin/sh expansion rules and append
- the results in the given string vector. If the environment variable is NULL
- or empty, then store the strings specified by the array p of length n.
-
- env_or_default() is the same as env_or_defaultv() but you provide p as
- variadic arguments.
-
- If the pointer p is null, then no default value is appended to the given
- string vector when the environment variable is not present. */
-static void env_or_defaultv(struct strv *, const char *s, char *_Nullable *p,
- size_t n);
-#define env_or_default(sv, s, ...) \
- env_or_defaultv((sv), (s), _vtoa(__VA_ARGS__), lengthof(_vtoa(__VA_ARGS__)))
-
-/* Returns if a file exists at the given path. A return value of false may also
- mean you don’t have the proper file access permissions, which will also set
- errno. */
-static bool fexists(const char *);
-
-/* Compare the modification dates of the two named files.
-
- A return value >0 means the LHS is newer than the RHS.
- A return value <0 means the LHS is older than the RHS.
- A return value of 0 means the LHS and RHS have the same modification date.
-
- The fmdnewer() and fmdolder() functions are wrappers around fmdcmp() that
- return true when the LHS is newer or older than the RHS respectively. */
-static int fmdcmp(const char *, const char *);
-static bool fmdolder(const char *, const char *);
-static bool fmdnewer(const char *, const char *);
-
-/* Report if any of n files specified by p render the file base outdated. If
- the file base does not exist, this function returns true. You will typically
- call this with a compiled program as base, and C source files as p. The
- macro foutdated() is a wrapper around foutdatedv() that allows you to specify
- the sources to base as variadic arguments instead of as an array. */
-static bool foutdatedv(const char *base, const char **p, size_t n);
-#define foutdated(s, ...) \
- foutdatedv(s, (const char **)_vtoa(__VA_ARGS__), \
- lengthof(_vtoa(__VA_ARGS__)))
-
-/* Rebuild the build script if it has been modified, and execute the newly built
- script. You should call the rebuild() macro at the very beginning of main(),
- but right after cbsinit(). You probably don’t want to call _rebuild()
- directly.
-
- NOTE: This function/macro REQUIRES that the source for the build script and
- the compiled build script are in the SAME DIRECTORY. */
-static void _rebuild(char *);
-#define rebuild() _rebuild(__FILE__)
-
-/* Get the number of available CPUs, or -1 on error. This function also returns
- -1 if the _SC_NPROCESSORS_ONLN flag to sysconf(3) is not available. In that
- case, errno will not be set. */
-static int nproc(void);
-
-/* Append the arguments returned by an invokation of pkg-config for the library
- lib to the given string vector. The flags argument is one-or-more of the
- flags in the pkg_config_flags enum bitwise-ORed together.
-
- If PKGC_CFLAGS is specified, call pkg-config with ‘--cflags’.
- If PKGC_LIBS is specified, call pkg-config with ‘--libs’.
-
- This function returns true on success and false if pkg-config is not found on
- the system. To check for pkg-configs existance, you can use the binexists()
- function. */
-static bool pcquery(struct strv *, char *lib, int flags);
-enum pkg_config_flags {
- PKGC_LIBS = 1 << 0,
- PKGC_CFLAGS = 1 << 1,
-};
-
-#ifdef CBS_PTHREAD
-
-/* A tfunc_t represents a function to be executed by a threads in a thread pool.
- It takes an argument in the form of a void * and returns nothing. */
-typedef void (*tfunc_t)(void *);
-
-/* A tfunc_free_t represents a function which frees the argument passed to a
- tfunc_t function. */
-typedef void (*tfree_func_t)(void *);
-
-/* A thread pool job queue. Meant for internal-use only. */
-struct _tjob {
- void *arg;
- tfunc_t fn;
- tfree_func_t free;
- struct _tjob *next;
-};
-
-/* A basic thread pool. None of its fields should really be touched. */
-typedef struct {
- bool _stop;
- size_t _tcnt, _left;
- pthread_t *_thrds;
- pthread_cond_t _cnd;
- pthread_mutex_t _mtx;
- struct _tjob *_head, *_tail;
-} tpool_t;
-
-/* Initialize and destroy a thread pool. The tpinit() function initializes the
- given thread pool and creates n threads ready to execute work. The tpfree()
- function should be called after a thread pool has been used to release all
- resources used by the thread pool. */
-static void tpinit(tpool_t *, size_t n);
-static void tpfree(tpool_t *);
-
-/* Wait for all jobs on the given thread pool to be executed. Note that this
- function does not destroy the threads or free any resources — those are tasks
- for the tpfree() function. */
-static void tpwait(tpool_t *);
-
-/* Enqueue and dequeue jobs to the thread pools job queue. The tpenq() function
- is threadsafe while the _tpdeq() function is not (so don’t use it). When
- calling the tpenq() function, the function fn will be queued to be executed
- by a thread in the thread pool with the argument arg. If the given argument
- needs to be deallocated after the job completes, you can pass the free
- argument which will be called with the given argument after use. If free is
- NULL, it will be ignored.
-
- The free() function is a valid argument to the free parameter. */
-static void tpenq(tpool_t *, tfunc_t fn, void *arg,
- tfree_func_t _Nullable free);
-static struct _tjob *_tpdeq(tpool_t *);
-
-#endif /* CBS_PTHREAD */
-
-/* BEGIN DEFINITIONS */
-
-void
-strvfree(struct strv *v)
-{
- free(v->buf);
- memset(v, 0, sizeof(*v));
-}
-
-void *
-bufalloc(void *p, size_t n, size_t m)
-{
- if (n && SIZE_MAX / n < m) {
- errno = EOVERFLOW;
- die(__func__);
- }
-
- if (!(p = realloc(p, n * m)))
- die(__func__);
- return p;
-}
-
-void
-die(const char *fmt, ...)
-{
- int e = errno;
- va_list ap;
-
- va_start(ap, fmt);
- flockfile(stderr);
- fprintf(stderr, "%s: ", *_cbs_argv);
- if (fmt) {
- vfprintf(stderr, fmt, ap);
- fprintf(stderr, ": ");
- }
- fprintf(stderr, "%s\n", strerror(e));
- exit(EXIT_FAILURE);
-}
-
-void
-diex(const char *fmt, ...)
-{
- va_list ap;
-
- va_start(ap, fmt);
- flockfile(stderr);
- fprintf(stderr, "%s: ", *_cbs_argv);
- vfprintf(stderr, fmt, ap);
- fputc('\n', stderr);
- exit(EXIT_FAILURE);
-}
-
-void
-cbsinit(int argc, char **argv)
-{
- char *s;
-
- _cbs_argc = argc;
- _cbs_argv = bufalloc(nullptr, argc, sizeof(char *));
- for (int i = 0; i < argc; i++) {
- if (!(_cbs_argv[i] = strdup(argv[i]))) {
- /* We might not have set _cbs_argv[0] yet, so we can’t use die() */
- fprintf(stderr, "%s: strdup: %s\n", *argv, strerror(errno));
- exit(EXIT_FAILURE);
- }
- }
-
- /* Cd to dirname(argv[0]). We can’t use dirname(3) because it may modify
- the source string. */
- if (s = strrchr(_cbs_argv[0], '/')) {
- s[0] = '\0';
- if (chdir(_cbs_argv[0]) == -1)
- die("chdir: %s", s);
- s[0] = '/';
- }
-}
-
-static size_t
-_next_powerof2(size_t x)
-{
-#if defined(__has_builtin) && __has_builtin(__builtin_clzl)
- x = x <= 1 ? 1 : 1 << (64 - __builtin_clzl(x - 1));
-#else
- if (x) {
- x--;
- x |= x >> 1;
- x |= x >> 2;
- x |= x >> 4;
- x |= x >> 8;
- if (sizeof(size_t) >= 4)
- x |= x >> 16;
- if (sizeof(size_t) >= 8)
- x |= x >> 32;
- }
- x++;
-#endif
-
- return x;
-}
-
-bool
-binexists(const char *name)
-{
- char *p, *path;
-
- if (!(path = getenv("PATH")))
- diex("PATH environment variable not found");
-
- if (!(path = strdup(path)))
- die("strdup");
- p = strtok(path, ":");
- while (p) {
- char buf[PATH_MAX];
- snprintf(buf, sizeof(buf), "%s/%s", p, name);
- if (fexists(buf)) {
- free(path);
- return true;
- }
-
- p = strtok(nullptr, ":");
- }
-
- free(path);
- return false;
-}
-
-void
-cmdaddv(cmd_t *cmd, char **xs, size_t n)
-{
- if (cmd->_len + n >= cmd->_cap) {
- cmd->_cap = _next_powerof2(cmd->_len + n) + 2;
- cmd->_argv = bufalloc(cmd->_argv, cmd->_cap, sizeof(char *));
- }
-
- memcpy(cmd->_argv + cmd->_len, xs, n * sizeof(*xs));
- cmd->_len += n;
- cmd->_argv[cmd->_len] = nullptr;
-}
-
-void
-cmdclr(cmd_t *c)
-{
- c->_len = 0;
- *c->_argv = nullptr;
-}
-
-int
-cmdexec(cmd_t c)
-{
- return cmdwait(cmdexeca(c));
-}
-
-pid_t
-cmdexeca(cmd_t c)
-{
- pid_t pid;
-
- switch (pid = fork()) {
- case -1:
- die("fork");
- case 0:
- execvp(*c._argv, c._argv);
- die("execvp: %s", *c._argv);
- }
-
- return pid;
-}
-
-int
-cmdexecb(cmd_t c, char **p, size_t *n)
-{
- enum {
- FD_R,
- FD_W,
- };
- pid_t pid;
- int fds[2];
- char *buf;
- size_t len, blksize;
- struct stat sb;
-
- if (pipe(fds) == -1)
- die("pipe");
-
- switch (pid = fork()) {
- case -1:
- die("fork");
- case 0:
- close(fds[FD_R]);
- if (dup2(fds[FD_W], STDOUT_FILENO) == -1)
- die("dup2");
- execvp(*c._argv, c._argv);
- die("execvp: %s", *c._argv);
- }
-
- close(fds[FD_W]);
-
- buf = nullptr;
- len = 0;
-
- blksize = fstat(fds[FD_R], &sb) == -1 ? BUFSIZ : sb.st_blksize;
- for (;;) {
- /* This can maybe somewhere somehow break some system. I do not care */
- char tmp[blksize];
- ssize_t nr;
-
- if ((nr = read(fds[FD_R], tmp, blksize)) == -1)
- die("read");
- if (!nr)
- break;
- buf = bufalloc(buf, len + nr + 1, sizeof(char));
- memcpy(buf + len, tmp, nr);
- len += nr;
- }
-
- close(fds[FD_R]);
- if (buf)
- buf[len] = 0;
- *p = buf;
- *n = len;
- return cmdwait(pid);
-}
-
-int
-cmdwait(pid_t pid)
-{
- for (;;) {
- int ws;
- if (waitpid(pid, &ws, 0) == -1)
- die("waitpid");
-
- if (WIFEXITED(ws))
- return WEXITSTATUS(ws);
-
- if (WIFSIGNALED(ws))
- return 256;
- }
-}
-
-/* import shlex
-
- s = '#define SHELL_SAFE "'
- for c in map(chr, range(128)):
- if not shlex._find_unsafe(c):
- s += c
- print(s + '"') */
-#define SHELL_SAFE \
- "%+,-./0123456789:=@ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyz"
-
-void
-cmdput(cmd_t c)
-{
- cmdputf(stdout, c);
-}
-
-void
-cmdputf(FILE *stream, cmd_t cmd)
-{
- flockfile(stream);
- for (size_t i = 0; i < cmd._len; i++) {
- bool safe = true;
- char *p, *q;
-
- p = q = cmd._argv[i];
- for (; *q; q++) {
- if (!strchr(SHELL_SAFE, *q)) {
- safe = false;
- break;
- }
- }
-
- if (safe)
- fputs(p, stream);
- else {
- putc('\'', stream);
- for (q = p; *q; q++) {
- if (*q == '\'')
- fputs("'\"'\"'", stream);
- else
- putc(*q, stream);
- }
- putc('\'', stream);
- }
-
- putc(i == cmd._len - 1 ? '\n' : ' ', stream);
- }
- funlockfile(stream);
-}
-
-void
-env_or_defaultv(struct strv *sv, const char *s, char **p, size_t n)
-{
- wordexp_t we;
- const char *ev;
-
- if ((ev = getenv(s)) && *ev) {
- switch (wordexp(ev, &we, WRDE_NOCMD)) {
- case WRDE_BADCHAR:
- case WRDE_BADVAL:
- case WRDE_SYNTAX:
- errno = EINVAL;
- die("wordexp");
- case WRDE_NOSPACE:
- errno = ENOMEM;
- die("wordexp");
- }
-
- p = we.we_wordv;
- n = we.we_wordc;
- } else if (!p)
- return;
-
- sv->buf = bufalloc(sv->buf, sv->len + n, sizeof(*sv->buf));
- for (size_t i = 0; i < n; i++) {
- if (!(sv->buf[sv->len + i] = strdup(p[i])))
- die("strdup");
- }
- sv->len += n;
-
- if (ev && *ev)
- wordfree(&we);
-}
-
-bool
-fexists(const char *f)
-{
- return !access(f, F_OK);
-}
-
-int
-fmdcmp(const char *lhs, const char *rhs)
-{
- struct stat sbl, sbr;
-
- if (stat(lhs, &sbl) == -1)
- die("%s", lhs);
- if (stat(rhs, &sbr) == -1)
- die("%s", rhs);
-
- return sbl.st_mtim.tv_sec == sbr.st_mtim.tv_sec
- ? sbl.st_mtim.tv_nsec - sbr.st_mtim.tv_nsec
- : sbl.st_mtim.tv_sec - sbr.st_mtim.tv_sec;
-}
-
-bool
-fmdnewer(const char *lhs, const char *rhs)
-{
- return fmdcmp(lhs, rhs) > 0;
-}
-
-bool
-fmdolder(const char *lhs, const char *rhs)
-{
- return fmdcmp(lhs, rhs) < 0;
-}
-
-bool
-foutdatedv(const char *src, const char **deps, size_t n)
-{
- if (!fexists(src))
- return true;
- for (size_t i = 0; i < n; i++) {
- if (fmdolder(src, deps[i]))
- return true;
- }
- return false;
-}
-
-void
-_rebuild(char *src)
-{
- char *bbn, *sbn, *argv0;
- cmd_t cmd = {0};
- size_t bufsiz;
-
- /* We assume that the compiled binary and the source file are in the same
- directory. */
- if (sbn = strrchr(src, '/'))
- sbn++;
- else
- sbn = src;
- if (bbn = strrchr(*_cbs_argv, '/'))
- bbn++;
- else
- bbn = src;
-
- if (!foutdated(bbn, sbn))
- return;
-
- cmdadd(&cmd, "cc");
-#ifdef CBS_PTHREAD
- cmdadd(&cmd, "-lpthread");
-#endif
- cmdadd(&cmd, "-o", bbn, sbn);
- cmdput(cmd);
- if (cmdexec(cmd))
- diex("Compilation of build script failed");
-
- cmdclr(&cmd);
-
- argv0 = bufalloc(nullptr, strlen(bbn) + 3, 1);
- *_cbs_argv = argv0;
-
- *argv0++ = '.';
- *argv0++ = '/';
- strcpy(argv0, bbn);
-
- cmdaddv(&cmd, _cbs_argv, _cbs_argc);
- execvp(*cmd._argv, cmd._argv);
- die("execvp: %s", *cmd._argv);
-}
-
-int
-nproc(void)
-{
-#ifdef _SC_NPROCESSORS_ONLN
- return (int)sysconf(_SC_NPROCESSORS_ONLN);
-#else
- errno = 0;
- return -1;
-#endif
-}
-
-bool
-pcquery(struct strv *vec, char *lib, int flags)
-{
- int ec;
- char *p;
- size_t n;
- cmd_t c = {0};
- wordexp_t we;
-
- p = nullptr;
-
- cmdadd(&c, "pkg-config");
- if (flags & PKGC_LIBS)
- cmdadd(&c, "--libs");
- if (flags & PKGC_CFLAGS)
- cmdadd(&c, "--cflags");
- cmdadd(&c, lib);
-
- if ((ec = cmdexecb(c, &p, &n))) {
- if (errno == ENOENT) {
- free(c._argv);
- return false;
- }
- diex("pkg-config terminated with exit-code %d", ec);
- }
-
- if (!p)
- return true;
-
- /* Remove trailing newline */
- p[n - 1] = 0;
-
- switch (wordexp(p, &we, WRDE_NOCMD)) {
- case WRDE_BADCHAR:
- case WRDE_BADVAL:
- case WRDE_SYNTAX:
- errno = EINVAL;
- die("wordexp");
- case WRDE_NOSPACE:
- errno = ENOMEM;
- die("wordexp");
- }
-
- vec->buf = bufalloc(vec->buf, vec->len + we.we_wordc, sizeof(char *));
- for (size_t i = 0; i < we.we_wordc; i++) {
- char *p = strdup(we.we_wordv[i]);
- if (!p)
- die(__func__);
- vec->buf[vec->len++] = p;
- }
-
- wordfree(&we);
- free(p);
- return true;
-}
-
-#ifdef CBS_PTHREAD
-
-static void *
-_tpwork(void *arg)
-{
- tpool_t *tp = arg;
-
- while (!tp->_stop) {
- struct _tjob *j;
-
- pthread_mutex_lock(&tp->_mtx);
- while (!tp->_stop && !tp->_head)
- pthread_cond_wait(&tp->_cnd, &tp->_mtx);
- if (tp->_stop) {
- pthread_mutex_unlock(&tp->_mtx);
- break;
- }
-
- j = _tpdeq(tp);
- pthread_mutex_unlock(&tp->_mtx);
-
- j->fn(j->arg);
- if (j->free)
- j->free(j->arg);
- free(j);
-
- pthread_mutex_lock(&tp->_mtx);
- tp->_left--;
- pthread_cond_broadcast(&tp->_cnd);
- pthread_mutex_unlock(&tp->_mtx);
- }
-
- return nullptr;
-}
-
-void
-tpinit(tpool_t *tp, size_t n)
-{
- tp->_tcnt = n;
- tp->_stop = false;
- tp->_left = 0;
- tp->_head = tp->_tail = nullptr;
- tp->_thrds = bufalloc(nullptr, n, sizeof(pthread_t));
- pthread_cond_init(&tp->_cnd, nullptr);
- pthread_mutex_init(&tp->_mtx, nullptr);
-
- for (size_t i = 0; i < n; i++)
- pthread_create(tp->_thrds + i, nullptr, _tpwork, tp);
-}
-
-void
-tpfree(tpool_t *tp)
-{
- tp->_stop = true;
-
- pthread_mutex_lock(&tp->_mtx);
- pthread_cond_broadcast(&tp->_cnd);
- pthread_mutex_unlock(&tp->_mtx);
-
- for (size_t i = 0; i < tp->_tcnt; i++)
- pthread_join(tp->_thrds[i], nullptr);
-
- free(tp->_thrds);
- while (tp->_head) {
- struct _tjob *j = _tpdeq(tp);
- if (j->free)
- j->free(j->arg);
- free(j);
- }
-
- pthread_cond_destroy(&tp->_cnd);
- pthread_mutex_destroy(&tp->_mtx);
-}
-
-struct _tjob *
-_tpdeq(tpool_t *tp)
-{
- struct _tjob *j = tp->_head;
-
- if (j) {
- tp->_head = tp->_head->next;
- if (!tp->_head)
- tp->_tail = nullptr;
- }
-
- return j;
-}
-
-void
-tpenq(tpool_t *tp, tfunc_t fn, void *arg, tfree_func_t free)
-{
- struct _tjob *j = bufalloc(nullptr, 1, sizeof(struct _tjob));
- *j = (struct _tjob){
- .fn = fn,
- .arg = arg,
- .free = free,
- };
-
- pthread_mutex_lock(&tp->_mtx);
- if (tp->_tail)
- tp->_tail->next = j;
- if (!tp->_head)
- tp->_head = j;
- tp->_tail = j;
- tp->_left++;
- pthread_cond_signal(&tp->_cnd);
- pthread_mutex_unlock(&tp->_mtx);
-}
-
-void
-tpwait(tpool_t *tp)
-{
- pthread_mutex_lock(&tp->_mtx);
- while (!tp->_stop && tp->_left)
- pthread_cond_wait(&tp->_cnd, &tp->_mtx);
- pthread_mutex_unlock(&tp->_mtx);
-}
-
-#endif /* CBS_PTHREAD */
-
-#ifdef __GNUC__
-# pragma GCC diagnostic pop
-#endif
-
-#ifdef __APPLE__
-# undef st_mtim
-#endif
-
-#endif /* !C_BUILD_SYSTEM_H */