summaryrefslogtreecommitdiff
path: root/os.h
blob: 3542ffe106e9ede9f0c98ee95d7e54eb82832983 (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
/// \file
/// a bunch of OS-dependent functions
#ifndef OS_H_
#define OS_H_

#include "base.h"

typedef enum {
	FS_NON_EXISTENT,
	FS_FILE,
	FS_DIRECTORY,
	FS_OTHER
} FsType;

enum {
	FS_PERMISSION_READ = 0x01,
	FS_PERMISSION_WRITE = 0x02,
};
typedef u8 FsPermission;

typedef struct {
	FsType type;
	char name[];
} FsDirectoryEntry;

/// returns what kind of thing this is.
FsType fs_path_type(const char *path);
FsPermission fs_path_permission(const char *path);
/// Does this file exist? Returns false for directories.
bool fs_file_exists(const char *path);
/// Returns a NULL-terminated array of the files/directories in this directory, or NULL if the directory does not exist/out of memory.
/// When you're done with the entries, call fs_dir_entries_free (or call free on each entry, then on the whole array).
/// NOTE: The files/directories aren't returned in any particular order!
FsDirectoryEntry **fs_list_directory(const char *dirname);
/// Create the directory specified by `path`\n
/// Returns:\n
/// 1  if the directory was created successfully\n
/// 0  if the directory already exists\n
/// -1 if the path already exists, but it's not a directory, or if there's another error (e.g. don't have permission to create directory).\n
int fs_mkdir(const char *path);
// Puts the current working directory into buf, including a null-terminator, writing at most buflen bytes.\n
// Returns:\n
// 1  if the working directory was inserted into buf successfully\n
// 0  if buf is too short to hold the cwd\n
// -1 if we can't get the cwd for whatever reason.\n
int os_get_cwd(char *buf, size_t buflen);
// Unlike ISO C rename() function, this will overwrite `newname` if it exists.\n
// Returns:\n
// >= 0 if successful\n
// < 0 on error\n
int os_rename_overwrite(const char *oldname, const char *newname);
struct timespec time_last_modified(const char *filename);
struct timespec time_get(void);
/// sleep for a certain number of nanoseconds
void time_sleep_ns(u64 ns);


/// free the entries generated by fs_list_directory.
static void fs_dir_entries_free(FsDirectoryEntry **entries) {
	for (int i = 0; entries[i]; ++i)
		free(entries[i]);
	free(entries);
}

/// get current time in seconds since some arbitrary point
static double time_get_seconds(void) {
	struct timespec t = time_get();
	return (double)t.tv_sec
		+ (double)t.tv_nsec * 1e-9;
}



/// sleep for microseconds
static void time_sleep_us(u64 us) {
	time_sleep_ns(us * 1000);
}

/// sleep for milliseconds
static void time_sleep_ms(u64 ms) {
	time_sleep_ns(ms * 1000000);
}

/// sleep for seconds
static void time_sleep_s(u64 s) {
	time_sleep_ns(s * 1000000000);
}

/// a process
typedef struct Process Process;

/// zero everything except what you're using
typedef struct {
	bool separate_stderr;
	const char *working_directory;
	/// for forwards compatibility
	char _reserved[256];
} ProcessSettings;

typedef struct {
	/// string like "exited with code 9"
	char message[62];
	/// it might be possible that both `signalled` and `exited` are false,
	/// if something weird happens.
	bool signalled;
	bool exited;
	/// only relevant if `exited = true`
	int exit_code;
	/// only relevant if `signalled = true`
	int signal;
} ProcessExitInfo;

/// get process ID of this process
int process_get_id(void);
/// execute the given command (like if it was passed to `system()`), creating a new \ref Process object.
///
/// returns a valid process object on failure, but it will have an error, according to \ref process_geterr
Process *process_run_ex(const char *command, const ProcessSettings *settings);
/// like \ref process_run_ex, but with the default settings
Process *process_run(const char *command);
/// returns the error last error produced, or NULL if there was no error.
const char *process_geterr(Process *process);
/// write to stdin
///
/// returns -2 on error,
/// or a non-negative number indicating the number of bytes written.
/// Currently, this does a blocking write.
long long process_write(Process *process, const char *data, size_t size);
/// read from stdout+stderr.
///
/// returns:\n
/// -2 on error\n
/// -1 if no data is available right now\n
/// 0 on end of file\n
/// or a positive number indicating the number of bytes read to data (at most size)\n
/// This does a nonblocking read.
long long process_read(Process *process, char *data, size_t size);
/// like \ref process_read, but reads stderr.
///
/// this function ALWAYS RETURNS -2 if `separate_stderr` is not specified in the \ref ProcessSettings.
///   if `separate_stderr` is false, then both stdout and stderr will be sent via \ref process_read.
long long process_read_stderr(Process *process, char *data, size_t size);
/// Checks if the process has exited.
///
/// Returns:\n
/// -1 if the process returned a non-zero exit code, or got a signal.\n
/// 1  if the process exited successfully\n
/// 0  if the process hasn't exited.\n
/// If the process has exited, `*info` will be filled out with details.
/// if the process is no longer running, `*process` will be freed and set to NULL.
int process_check_status(Process **process, ProcessExitInfo *info);
/// kills process if still running
///
/// this also frees any resources used by `*process`.
/// `*process` will be set to NULL.
void process_kill(Process **process);

/// runs xdg-open or equivalent on the given path, which can be a URL.
///
/// returns `true` on success.
bool open_with_default_application(const char *path);

#endif // OS_H_