summaryrefslogtreecommitdiff
path: root/src/file.hh
blob: 5362b34292e19cada2c307e9624ec18a1a1398c8 (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
#ifndef file_hh_INCLUDED
#define file_hh_INCLUDED

#include "array.hh"
#include "array_view.hh"
#include "enum.hh"
#include "exception.hh"
#include "meta.hh"
#include "string.hh"
#include "units.hh"
#include "utils.hh"

#include <sys/types.h>
#include <sys/stat.h>
#include <cstring>
#include <exception>

namespace Kakoune
{

struct file_access_error : runtime_error
{
    file_access_error(StringView filename, StringView error_desc);
    file_access_error(int fd, StringView error_desc);
};

// parse ~/ and %/ in filename and returns the translated filename
String parse_filename(StringView filename, StringView buf_dir = {});

String real_path(StringView filename);
String compact_path(StringView filename);

StringView tmpdir();
StringView homedir();

// returns pair { directory, filename }
std::pair<StringView, StringView> split_path(StringView path);

String get_kak_binary_path();

bool fd_readable(int fd);
bool fd_writable(int fd);
String read_fd(int fd, bool text = false);
String read_file(StringView filename, bool text = false);
template<bool force_blocking = false>
void write(int fd, StringView data);
void write_to_file(StringView filename, StringView data);
int create_file(const char* filename);
int open_temp_file(StringView filename);
int open_temp_file(StringView filename, char (&buffer)[PATH_MAX]);

struct MappedFile
{
    MappedFile(StringView filename);
    ~MappedFile();

    operator StringView() const;

    const char* data;
    struct stat st {};
};

enum class WriteMethod
{
    Overwrite,
    Replace
};
constexpr auto enum_desc(Meta::Type<WriteMethod>)
{
    return make_array<EnumDesc<WriteMethod>>({
        { WriteMethod::Overwrite, "overwrite" },
        { WriteMethod::Replace, "replace" },
    });
}

String find_file(StringView filename, StringView buf_dir, ConstArrayView<String> paths);
bool file_exists(StringView filename);
bool regular_file_exists(StringView filename);

void list_files(StringView directory, FunctionRef<void (StringView, const struct stat&)> callback);

void make_directory(StringView dir, mode_t mode);

constexpr timespec InvalidTime = { -1, -1 };

struct FsStatus
{
    timespec timestamp;
    ByteCount file_size;
    size_t hash;
};

timespec get_fs_timestamp(StringView filename);
FsStatus get_fs_status(StringView filename);

constexpr bool operator==(const timespec& lhs, const timespec& rhs)
{
    return lhs.tv_sec == rhs.tv_sec and lhs.tv_nsec == rhs.tv_nsec;
}

template<bool atomic, int buffer_size = 4096>
struct BufferedWriter
{
    BufferedWriter(int fd)
      : m_fd{fd}, m_exception_count{std::uncaught_exceptions()} {}

    ~BufferedWriter() noexcept(false)
    {
        if (m_pos != 0 and m_exception_count == std::uncaught_exceptions())
            flush();
    }

    void write(StringView data)
    {
        while (not data.empty())
        {
            const ByteCount length = data.length();
            const ByteCount write_len = clamp(length, ByteCount{0}, size - m_pos);
            memcpy(m_buffer + m_pos, data.data(), (int)write_len);
            m_pos += write_len;
            if (m_pos == size)
                flush();
            data = data.substr(write_len);
        }
    }

    void flush()
    {
        Kakoune::write<atomic>(m_fd, {m_buffer, m_pos});
        m_pos = 0;
    }

private:
    static constexpr ByteCount size = buffer_size;
    int m_fd;
    int m_exception_count;
    ByteCount m_pos = 0;
    char m_buffer[(int)size];
};

}

#endif // file_hh_INCLUDED