util.c 2.2 KiB raw
1
#include <fcntl.h>
2
#include <stdarg.h>
3
#include <stdio.h>
4
#include <stdlib.h>
5
#include <string.h>
6
7
#include "util.h"
8
9
#define MAX_ENV_SIZE 1024
10
11
/* Print an error and terminate the process. */
12
[[noreturn]] void die(const char *fmt, ...) {
13
    va_list ap;
14
15
    fputs("swm: ", stderr);
16
    va_start(ap, fmt);
17
    vfprintf(stderr, fmt, ap);
18
    va_end(ap);
19
20
    if (fmt[0] && fmt[strlen(fmt) - 1] == ':') {
21
        fputc(' ', stderr);
22
        perror(nullptr);
23
    } else {
24
        fputc('\n', stderr);
25
    }
26
    exit(1);
27
}
28
29
/* Expand environment variables while preserving a single argv element. */
30
size_t env_expand(char *output, size_t capacity, const char *input) {
31
    const char *value;
32
    size_t      i = 0, len, out = 0, start;
33
    char        name[MAX_ENV_SIZE];
34
35
    if (!capacity)
36
        return 0;
37
38
    while (input[i]) {
39
        if (input[i] != '$') {
40
            if (out + 1 >= capacity)
41
                return 0;
42
            output[out++] = input[i];
43
            i++;
44
            continue;
45
        }
46
        start = ++i;
47
        if (!((input[i] >= 'A' && input[i] <= 'Z') || (input[i] >= 'a' && input[i] <= 'z') ||
48
              input[i] == '_')) {
49
            if (out + 1 >= capacity)
50
                return 0;
51
            output[out++] = '$';
52
            continue;
53
        }
54
        for (; (input[i] >= 'A' && input[i] <= 'Z') || (input[i] >= 'a' && input[i] <= 'z') ||
55
               (input[i] >= '0' && input[i] <= '9') || input[i] == '_';
56
             i++)
57
            ;
58
59
        len = i - start;
60
        if (len >= sizeof(name))
61
            return 0;
62
        memcpy(name, input + start, len);
63
        name[len] = '\0';
64
        value     = getenv(name);
65
        if (!value)
66
            continue;
67
68
        len = strlen(value);
69
        if (out + len >= capacity)
70
            return 0;
71
        memcpy(output + out, value, len);
72
        out += len;
73
    }
74
    output[out] = '\0';
75
76
    return out + 1;
77
}
78
79
/* Put a file descriptor into nonblocking mode. */
80
int fd_set_nonblock(int fd) {
81
    int flags = fcntl(fd, F_GETFL);
82
83
    if (flags < 0) {
84
        perror("fcntl(F_GETFL)");
85
        return -1;
86
    }
87
    if (fcntl(fd, F_SETFL, flags | O_NONBLOCK) < 0) {
88
        perror("fcntl(F_SETFL)");
89
        return -1;
90
    }
91
    return 0;
92
}