aboutsummaryrefslogtreecommitdiff
path: root/src/Utils.cpp
blob: 55fc57ea4464ae675d8cfcc02d6fa53e9a04c436 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
#include "../include/Utils.hpp"
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <pwd.h>
#include <limits.h>
#include <string.h>
#include <sys/stat.h>

namespace gsr {
    void string_split_char(std::string_view str, char delimiter, StringSplitCallback callback_func) {
        size_t index = 0;
        while(index < str.size()) {
            size_t new_index = str.find(delimiter, index);
            if(new_index == std::string_view::npos)
                new_index = str.size();

            if(!callback_func(str.substr(index, new_index - index)))
                break;

            index = new_index + 1;
        }
    }

    std::string get_home_dir() {
        const char *home_dir = getenv("HOME");
        if(!home_dir) {
            passwd *pw = getpwuid(getuid());
            home_dir = pw->pw_dir;
        }

        if(!home_dir) {
            fprintf(stderr, "Error: Failed to get home directory of user, using /tmp directory\n");
            home_dir = "/tmp";
        }

        return home_dir;
    }

    std::string get_config_dir() {
        std::string config_dir;
        const char *xdg_config_home = getenv("XDG_CONFIG_HOME");
        if(xdg_config_home) {
            config_dir = xdg_config_home;
        } else {
            config_dir = get_home_dir() + "/.config";
        }
        config_dir += "/gpu-screen-recorder";
        return config_dir;
    }

    // Whoever designed xdg-user-dirs is retarded. Why are some XDG variables environment variables
    // while others are in this pseudo shell config file ~/.config/user-dirs.dirs
    std::map<std::string, std::string> get_xdg_variables() {
        std::string user_dirs_filepath;
        const char *xdg_config_home = getenv("XDG_CONFIG_HOME");
        if(xdg_config_home) {
            user_dirs_filepath = xdg_config_home;
        } else {
            user_dirs_filepath = get_home_dir() + "/.config";
        }

        user_dirs_filepath += "/user-dirs.dirs";

        std::map<std::string, std::string> result;
        FILE *f = fopen(user_dirs_filepath.c_str(), "rb");
        if(!f)
            return result;

        char line[PATH_MAX];
        while(fgets(line, sizeof(line), f)) {
            int len = strlen(line);
            if(len < 2)
                continue;

            if(line[0] == '#')
                continue;

            if(line[len - 1] == '\n') {
                line[len - 1] = '\0';
                len--;
            }

            if(line[len - 1] != '"')
                continue;

            line[len - 1] = '\0';
            len--;

            const char *sep = strchr(line, '=');
            if(!sep)
                continue;

            if(sep[1] != '\"')
                continue;

            std::string value(sep + 2);
            if(strncmp(value.c_str(), "$HOME/", 6) == 0)
                value = get_home_dir() + value.substr(5);

            std::string key(line, sep - line);
            result[std::move(key)] = std::move(value);
        }

        fclose(f);
        return result;
    }

    std::string get_videos_dir() {
        auto xdg_vars = get_xdg_variables();
        std::string xdg_videos_dir = xdg_vars["XDG_VIDEOS_DIR"];
        if(xdg_videos_dir.empty())
            xdg_videos_dir = get_home_dir() + "/Videos";
        return xdg_videos_dir;
    }

    int create_directory_recursive(char *path) {
        int path_len = strlen(path);
        char *p = path;
        char *end = path + path_len;
        for(;;) {
            char *slash_p = strchr(p, '/');

            // Skips first '/', we don't want to try and create the root directory
            if(slash_p == path) {
                ++p;
                continue;
            }

            if(!slash_p)
                slash_p = end;

            char prev_char = *slash_p;
            *slash_p = '\0';
            int err = mkdir(path, S_IRWXU);
            *slash_p = prev_char;

            if(err == -1 && errno != EEXIST)
                return err;

            if(slash_p == end)
                break;
            else
                p = slash_p + 1;
        }
        return 0;
    }

    bool file_get_content(const char *filepath, std::string &file_content) {
        file_content.clear();
        bool success = false;

        FILE *file = fopen(filepath, "rb");
        if(!file)
            return success;

        fseek(file, 0, SEEK_END);
        long file_size = ftell(file);
        if(file_size != -1) {
            file_content.resize(file_size);
            fseek(file, 0, SEEK_SET);
            if((long)fread(&file_content[0], 1, file_size, file) == file_size)
                success = true;
        }

        fclose(file);
        return success;
    }
}