summaryrefslogtreecommitdiff
path: root/base.h
blob: a5e529928b16631918fe8fe6b73ec18d558ac7be (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
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
// basic types and macros.
// this file is included almost everywhere.

#ifndef BASE_H_
#define BASE_H_

#ifndef DEBUG
#define NDEBUG 1
#endif

#ifndef _GNU_SOURCE
#define _GNU_SOURCE
#endif

#if __GNUC__
#define FALLTHROUGH __attribute__((fallthrough));
#else
#define FALLTHROUGH
#endif

#if _WIN32
#include <windows.h>
#include <shlobj.h>
#include <dbghelp.h>
#define PATH_SEPARATOR '\\'
#define PATH_SEPARATOR_STR "\\"
// on windows, let the user use forwards slashes as well as backslashes
#define ALL_PATH_SEPARATORS "\\/"
#else
#define PATH_SEPARATOR '/'
#define PATH_SEPARATOR_STR "/"
#define ALL_PATH_SEPARATORS "/"
#endif

#include <stdbool.h>
#include <inttypes.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stddef.h>
#include <stdarg.h>
#include <float.h>
#include <limits.h>
#include <assert.h>
#include <time.h>
#include <math.h>
#include <errno.h>
#if __linux__ || _WIN32
#include <uchar.h>
#else
// OpenBSD has uchar.h but it doesn't seem to define char32_t ?
typedef uint32_t char32_t;
#endif

#if !__TINYC__ && __STDC_VERSION__ >= 201112
#define static_assert_if_possible(cond) _Static_assert(cond, "Static assertion failed");
#else
#define static_assert_if_possible(cond)
#endif

typedef uint8_t  u8;
typedef uint16_t u16;
typedef uint32_t u32;
typedef uint64_t u64;

// (for u8 and u16, you can use %u)
#define U32_FMT "%" PRIu32
#define U64_FMT "%" PRIu64
#define U8_MAX  0xff
#define U16_MAX 0xffff
#define U32_MAX 0xffffffff
#define U64_MAX 0xffffffffffffffff

typedef int8_t  i8;
typedef int16_t i16;
typedef int32_t i32;
typedef int64_t i64;

// (for i8 and i16, you can use %d)
#define I32_FMT "%" PRId32
#define I64_FMT "%" PRId64
#define I8_MAX  0x7f
#define I16_MAX 0x7fff
#define I32_MAX 0x7fffffff
#define I64_MAX 0x7fffffffffffffff

typedef unsigned int  uint;
typedef unsigned long ulong;

typedef long long llong;
typedef unsigned long long ullong;

// allows 
// switch (c) {
//     case ANY_DIGIT:
//        ...
// }
#define ANY_DIGIT '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9'

#if __clang__
#define ENUM_U8 typedef enum : u8
#define ENUM_U8_END(name) name
#else
#define ENUM_U8 enum
#define ENUM_U8_END(name) ; typedef u8 name
#endif

#ifdef __GNUC__
#define WarnUnusedResult __attribute__((warn_unused_result))
#else
#define WarnUnusedResult
#endif

#if __GNUC__
#define ATTRIBUTE_PRINTF(fmt_idx, arg_idx) __attribute__ ((format(printf, fmt_idx, arg_idx)))
#else
#define ATTRIBUTE_PRINTF(fmt_idx, arg_idx)
#endif
#if _MSC_VER > 1400
#define PRINTF_FORMAT_STRING _Printf_format_string_
#else
#define PRINTF_FORMAT_STRING
#endif

// this type is an alias for bool, except that it
// produces a warning if it's not used.
// false = error, true = success
#define Status bool WarnUnusedResult

#define arr_count(a) (sizeof (a) / sizeof *(a))


// usage: if UNLIKELY (x > 2) ...
#if __GNUC__
#define UNLIKELY(x) (__builtin_expect(x,0))
#else
#define UNLIKELY(x) (x)
#endif

#ifdef __GNUC__
#define no_warn_start _Pragma("GCC diagnostic push") \
	_Pragma("GCC diagnostic ignored \"-Wpedantic\"") \
	_Pragma("GCC diagnostic ignored \"-Wsign-conversion\"") \
	_Pragma("GCC diagnostic ignored \"-Wsign-compare\"") \
	_Pragma("GCC diagnostic ignored \"-Wconversion\"") \
	_Pragma("GCC diagnostic ignored \"-Wimplicit-fallthrough\"") \
	_Pragma("GCC diagnostic ignored \"-Wunused-function\"")

#define no_warn_end _Pragma("GCC diagnostic pop")
#else
#define no_warn_start
#define no_warn_end
#endif

#if _WIN32
static void print(const char *fmt, ...) {
	char buf[2048];
	buf[2047] = '\0';
	va_list args;
	va_start(args, fmt);
	vsnprintf(buf, sizeof buf - 1, fmt, args);
	va_end(args);
	OutputDebugStringA(buf);
}
#define eprint print
#else
#define print printf
#define eprint(...) fprintf(stderr, __VA_ARGS__)
#endif
#define println(...) print(__VA_ARGS__), print("\n")
#define eprintln(...) eprint(__VA_ARGS__), eprint("\n")

#if DEBUG
#define debug_print print
#define debug_println println
#else
#define debug_print(...)
#define debug_println(...)
#endif

// NOTE: these have to be defined here because lsp.h uses Language

// If you are adding new languages, DO NOT change the constant values
// of the previous languages. It will mess up config files which use :set-language!
typedef enum {
	LANG_NONE = 0, // avoid using this and use LANG_TEXT instead.
	LANG_C = 1,
	LANG_CPP = 2,
	LANG_RUST = 3,
	LANG_PYTHON = 4,
	LANG_TEX = 5,
	LANG_MARKDOWN = 6,
	LANG_HTML = 7,
	LANG_CONFIG = 8, // .cfg files
	LANG_JAVASCRIPT = 9,
	LANG_JAVA = 10,
	LANG_GO = 11,
	LANG_TED_CFG = 12, // like LANG_CONFIG, but with multiline strings.
	LANG_TYPESCRIPT = 13,
	LANG_JSON = 14,
	LANG_XML = 15,
	LANG_GLSL = 16,
	LANG_TEXT = 17, // plain text
	LANG_COUNT
} Language;

#endif // BASE_H_