aboutsummaryrefslogtreecommitdiff
path: root/src/bitflags.c
diff options
context:
space:
mode:
authorThijs <thijs@thijsschreijer.nl>2023-11-16 09:09:54 +0100
committerThijs Schreijer <thijs@thijsschreijer.nl>2024-04-30 09:28:01 +0200
commitbd994461ef7c2553da9a6945c685152bad50eb8f (patch)
tree28adc32712f00a200a34357e731a570bf1a359dc /src/bitflags.c
parent47c24eed0191f8f72646be63dee94ac2b35eb062 (diff)
downloadluasystem-bd994461ef7c2553da9a6945c685152bad50eb8f.tar.gz
luasystem-bd994461ef7c2553da9a6945c685152bad50eb8f.tar.bz2
luasystem-bd994461ef7c2553da9a6945c685152bad50eb8f.zip
feat(term): getting/setting terminal config flags
Diffstat (limited to 'src/bitflags.c')
-rw-r--r--src/bitflags.c235
1 files changed, 235 insertions, 0 deletions
diff --git a/src/bitflags.c b/src/bitflags.c
new file mode 100644
index 0000000..89a88b7
--- /dev/null
+++ b/src/bitflags.c
@@ -0,0 +1,235 @@
1/// Bitflags module.
2// The bitflag object makes it easy to manipulate flags in a bitmask.
3//
4// It has metamethods that do the hard work, adding flags sets them, substracting
5// unsets them. Comparing flags checks if all flags in the second set are also set
6// in the first set. The `has` method checks if all flags in the second set are
7// also set in the first set, but behaves slightly different.
8//
9// Indexing allows checking values or setting them by bit index (eg. 0-7 for flags
10// in the first byte).
11//
12// _NOTE_: unavailable flags (eg. Windows flags on a Posix system) should not be
13// omitted, but be assigned a value of 0. This is because the `has` method will
14// return `false` if the flags are checked and the value is 0.
15//
16// See `system.bitflag` (the constructor) for extensive examples on usage.
17// @classmod bitflags
18#include "bitflags.h"
19
20#define BITFLAGS_MT_NAME "LuaSystem.BitFlags"
21
22typedef struct {
23 LSBF_BITFLAG flags;
24} LS_BitFlags;
25
26/// Bit flags.
27// Bitflag objects can be used to easily manipulate and compare bit flags.
28// These are primarily for use with the terminal functions, but can be used
29// in other places as well.
30// @section bitflags
31
32
33// pushes a new LS_BitFlags object with the given value onto the stack
34void lsbf_pushbitflags(lua_State *L, LSBF_BITFLAG value) {
35 LS_BitFlags *obj = (LS_BitFlags *)lua_newuserdata(L, sizeof(LS_BitFlags));
36 if (!obj) luaL_error(L, "Memory allocation failed");
37 luaL_getmetatable(L, BITFLAGS_MT_NAME);
38 lua_setmetatable(L, -2);
39 obj->flags = value;
40}
41
42// gets the LS_BitFlags value at the given index. Returns a Lua error if it is not
43// a LS_BitFlags object.
44LSBF_BITFLAG lsbf_checkbitflags(lua_State *L, int index) {
45 LS_BitFlags *obj = (LS_BitFlags *)luaL_checkudata(L, index, BITFLAGS_MT_NAME);
46 return obj->flags;
47}
48
49/***
50Creates a new bitflag object from the given value.
51@function system.bitflag
52@tparam[opt=0] number value the value to create the bitflag object from.
53@treturn bitflag bitflag object with the given values set.
54@usage
55local sys = require 'system'
56local flags = sys.bitflag(2) -- b0010
57
58-- get state of individual bits
59print(flags[0]) -- false
60print(flags[1]) -- true
61
62-- set individual bits
63flags[0] = true -- b0011
64print(flags:value()) -- 3
65print(flags) -- "bitflags: 3"
66
67-- adding flags (bitwise OR)
68local flags1 = sys.bitflag(1) -- b0001
69local flags2 = sys.bitflag(2) -- b0010
70local flags3 = flags1 + flags2 -- b0011
71
72-- substracting flags (bitwise AND NOT)
73print(flags3:value()) -- 3
74flag3 = flag3 - flag3 -- b0000
75print(flags3:value()) -- 0
76
77-- comparing flags
78local flags4 = sys.bitflag(7) -- b0111
79local flags5 = sys.bitflag(255) -- b11111111
80print(flags5 >= flags4) -- true, all bits in flags4 are set in flags5
81
82-- comparing with 0 flags: comparison and `has` behave differently
83local flags6 = sys.bitflag(0) -- b0000
84local flags7 = sys.bitflag(1) -- b0001
85print(flags6 < flags7) -- true, flags6 is a subset of flags7
86print(flags7:has(flags6)) -- false, flags6 is not set in flags7
87*/
88static int lsbf_new(lua_State *L) {
89 LSBF_BITFLAG flags = 0;
90 if (lua_gettop(L) > 0) {
91 flags = luaL_checkinteger(L, 1);
92 }
93 lsbf_pushbitflags(L, flags);
94 return 1;
95}
96
97/***
98Retrieves the numeric value of the bitflag object.
99@function bitflag:value
100@treturn number the numeric value of the bitflags.
101@usage
102local sys = require 'system'
103local flags = sys.bitflag() -- b0000
104flags[0] = true -- b0001
105flags[2] = true -- b0101
106print(flags:value()) -- 5
107*/
108static int lsbf_value(lua_State *L) {
109 lua_pushinteger(L, lsbf_checkbitflags(L, 1));
110 return 1;
111}
112
113static int lsbf_tostring(lua_State *L) {
114 lua_pushfstring(L, "bitflags: %d", lsbf_checkbitflags(L, 1));
115 return 1;
116}
117
118static int lsbf_add(lua_State *L) {
119 lsbf_pushbitflags(L, lsbf_checkbitflags(L, 1) | lsbf_checkbitflags(L, 2));
120 return 1;
121}
122
123static int lsbf_sub(lua_State *L) {
124 lsbf_pushbitflags(L, lsbf_checkbitflags(L, 1) & ~lsbf_checkbitflags(L, 2));
125 return 1;
126}
127
128static int lsbf_eq(lua_State *L) {
129 lua_pushboolean(L, lsbf_checkbitflags(L, 1) == lsbf_checkbitflags(L, 2));
130 return 1;
131}
132
133static int lsbf_le(lua_State *L) {
134 LSBF_BITFLAG a = lsbf_checkbitflags(L, 1);
135 LSBF_BITFLAG b = lsbf_checkbitflags(L, 2);
136 // Check if all bits in b are also set in a
137 lua_pushboolean(L, (a & b) == a);
138 return 1;
139}
140
141/***
142Checks if the given flags are set.
143This is different from the `>=` and `<=` operators because if the flag to check
144has a value `0`, it will always return `false`. So if there are flags that are
145unsupported on a platform, they can be set to 0 and the `has` function will
146return `false` if the flags are checked.
147@function bitflag:has
148@tparam bitflag subset the flags to check for.
149@treturn boolean true if all the flags are set, false otherwise.
150@usage
151local sys = require 'system'
152local flags = sys.bitflag(12) -- b1100
153local myflags = sys.bitflag(15) -- b1111
154print(flags:has(myflags)) -- false, not all bits in myflags are set in flags
155print(myflags:has(flags)) -- true, all bits in flags are set in myflags
156*/
157static int lsbf_has(lua_State *L) {
158 LSBF_BITFLAG a = lsbf_checkbitflags(L, 1);
159 LSBF_BITFLAG b = lsbf_checkbitflags(L, 2);
160 // Check if all bits in b are also set in a, and b is not 0
161 lua_pushboolean(L, (a | b) == a && b != 0);
162 return 1;
163}
164
165static int lsbf_lt(lua_State *L) {
166 LSBF_BITFLAG a = lsbf_checkbitflags(L, 1);
167 LSBF_BITFLAG b = lsbf_checkbitflags(L, 2);
168 // Check if a is strictly less than b, meaning a != b and a is a subset of b
169 lua_pushboolean(L, (a != b) && ((a & b) == a));
170 return 1;
171}
172
173static int lsbf_index(lua_State *L) {
174 if (!lua_isnumber(L, 2)) {
175 // the parameter isn't a number, just lookup the key in the metatable
176 lua_getmetatable(L, 1);
177 lua_pushvalue(L, 2);
178 lua_gettable(L, -2);
179 return 1;
180 }
181
182 int index = luaL_checkinteger(L, 2);
183 if (index < 0 || index >= sizeof(LSBF_BITFLAG) * 8) {
184 return luaL_error(L, "index out of range");
185 }
186 lua_pushboolean(L, (lsbf_checkbitflags(L, 1) & (1 << index)) != 0);
187 return 1;
188}
189
190static int lsbf_newindex(lua_State *L) {
191 LS_BitFlags *obj = (LS_BitFlags *)luaL_checkudata(L, 1, BITFLAGS_MT_NAME);
192
193 if (!lua_isnumber(L, 2)) {
194 return luaL_error(L, "index must be a number");
195 }
196 int index = luaL_checkinteger(L, 2);
197 if (index < 0 || index >= sizeof(LSBF_BITFLAG) * 8) {
198 return luaL_error(L, "index out of range");
199 }
200
201 luaL_checkany(L, 3);
202 if (lua_toboolean(L, 3)) {
203 obj->flags |= (1 << index);
204 } else {
205 obj->flags &= ~(1 << index);
206 }
207 return 0;
208}
209
210static const struct luaL_Reg lsbf_funcs[] = {
211 {"bitflag", lsbf_new},
212 {NULL, NULL}
213};
214
215static const struct luaL_Reg lsbf_methods[] = {
216 {"value", lsbf_value},
217 {"has", lsbf_has},
218 {"__tostring", lsbf_tostring},
219 {"__add", lsbf_add},
220 {"__sub", lsbf_sub},
221 {"__eq", lsbf_eq},
222 {"__le", lsbf_le},
223 {"__lt", lsbf_lt},
224 {"__index", lsbf_index},
225 {"__newindex", lsbf_newindex},
226 {NULL, NULL}
227};
228
229void bitflags_open(lua_State *L) {
230 luaL_newmetatable(L, BITFLAGS_MT_NAME);
231 luaL_setfuncs(L, lsbf_methods, 0);
232 lua_pop(L, 1);
233
234 luaL_setfuncs(L, lsbf_funcs, 0);
235}