Skip to content

Commit

Permalink
docs + examples
Browse files Browse the repository at this point in the history
  • Loading branch information
Tieske committed Apr 22, 2024
1 parent 0f5b3b0 commit a7044f4
Show file tree
Hide file tree
Showing 6 changed files with 198 additions and 91 deletions.
7 changes: 7 additions & 0 deletions examples/flag_debugging.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
local sys = require "system"

-- Print the Windows Console flags for stdin
sys.listconsoleflags(io.stdin)

-- Print the Posix termios flags for stdin
sys.listtermflags(io.stdin)
67 changes: 67 additions & 0 deletions examples/spiral_snake.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
local sys = require "system"

print [[
This example will draw a snake like spiral on the screen. Showing ANSI escape
codes for moving the cursor around.
]]

-- start drawing the spiral.
-- start from current pos, then right, then up, then left, then down, and again.
local x, y = 1, 1 -- current position
local dx, dy = 1, 0 -- direction after each step
local wx, wy = 30, 30 -- width and height of the room
local mx, my = 1, 1 -- margin

-- commands to move the cursor
local move_left = "\27[1D"
local move_right = "\27[1C"
local move_up = "\27[1A"
local move_down = "\27[1B"

-- create room: 30 empty lines
print(("\n"):rep(wy))
-- for i = 1, 30 do print(i) end
local move = move_right

while wx > 0 and wy > 0 do
sys.sleep(0.01) -- slow down the drawing a little
io.write("*" .. move_left .. move )
io.flush()
x = x + dx
y = y + dy

if x > wx and move == move_right then
-- end of move right
dx = 0
dy = 1
move = move_up
wy = wy - 1
my = my + 1
elseif y > wy and move == move_up then
-- end of move up
dx = -1
dy = 0
move = move_left
wx = wx - 1
mx = mx + 1
elseif x < mx and move == move_left then
-- end of move left
dx = 0
dy = -1
move = move_down
wy = wy - 1
my = my + 1
elseif y < my and move == move_down then
-- end of move down
dx = 1
dy = 0
move = move_right
wx = wx - 1
mx = mx + 1
end
end

io.write(move_down:rep(15))
print("\nDone!")
6 changes: 4 additions & 2 deletions spec/05-bitflags_spec.lua
Original file line number Diff line number Diff line change
Expand Up @@ -90,17 +90,19 @@ describe("BitFlags library", function()
local bf2 = sys.bitflag(15) -- b1111
assert.is_true(bf2 >= bf1) -- all bits in bf1 are set in bf2
assert.is_true(bf2 > bf1) -- all bits in bf1 are set in bf2 and some more
assert.is_false(bf1 >= bf2) -- not all bits in bf2 are set in bf1
assert.is_false(bf1 > bf2) -- not all bits in bf2 are set in bf1
assert.is_false(bf2 <= bf1) -- not all bits in bf2 are set in bf1
assert.is_false(bf2 < bf1) -- not all bits in bf2 are set in bf1
end)

it("checks for a subset using 'has'", function()
local bf1 = sys.bitflag(3) -- b0011
local bf2 = sys.bitflag(3) -- b0011
local bf3 = sys.bitflag(15) -- b1111
local bf0 = sys.bitflag(0) -- b0000
assert.is_true(bf1:has(bf2)) -- equal
assert.is_true(bf3:has(bf1)) -- is a subset, and has more flags
assert.is_false(bf1:has(bf3)) -- not a subset, bf3 has more flags
assert.is_false(bf1:has(bf0)) -- bf0 is unset, always returns false
end)

end)
34 changes: 30 additions & 4 deletions src/bitflags.c
Original file line number Diff line number Diff line change
@@ -1,4 +1,20 @@
/// @module system
/// Bitflags module.
// The bitflag object makes it easy to manipulate flags in a bitmask.
//
// It has metamethods that do the hard work, adding flags sets them, substracting
// unsets them. Comparing flags checks if all flags in the second set are also set
// in the first set. The `has` method checks if all flags in the second set are
// also set in the first set, but behaves slightly different.
//
// Indexing allows checking values or setting them by bit index (eg. 0-7 for flags
// in the first byte).
//
// _NOTE_: unavailable flags (eg. Windows flags on a Posix system) should not be
// omitted, but be assigned a value of 0. This is because the `has` method will
// return `false` if the flags are checked and the value is 0.
//
// See `system.bitflag` (the constructor) for extensive examples on usage.
// @classmod bitflags
#include "bitflags.h"

#define BITFLAGS_MT_NAME "LuaSystem.BitFlags"
Expand Down Expand Up @@ -32,7 +48,7 @@ LSBF_BITFLAG lsbf_checkbitflags(lua_State *L, int index) {

/***
Creates a new bitflag object from the given value.
@function bitflag
@function system.bitflag
@tparam[opt=0] number value the value to create the bitflag object from.
@treturn bitflag bitflag object with the given values set.
@usage
Expand Down Expand Up @@ -62,6 +78,12 @@ print(flags3:value()) -- 0
local flags4 = sys.bitflag(7) -- b0111
local flags5 = sys.bitflag(255) -- b11111111
print(flags5 >= flags4) -- true, all bits in flags4 are set in flags5
-- comparing with 0 flags: comparison and `has` behave differently
local flags6 = sys.bitflag(0) -- b0000
local flags7 = sys.bitflag(1) -- b0001
print(flags6 < flags7) -- true, flags6 is a subset of flags7
print(flags7:has(flags6)) -- false, flags6 is not set in flags7
*/
static int lsbf_new(lua_State *L) {
LSBF_BITFLAG flags = 0;
Expand Down Expand Up @@ -118,6 +140,10 @@ static int lsbf_le(lua_State *L) {

/***
Checks if the given flags are set.
This is different from the `>=` and `<=` operators because if the flag to check
has a value `0`, it will always return `false`. So if there are flags that are
unsupported on a platform, they can be set to 0 and the `has` function will
return `false` if the flags are checked.
@function bitflag:has
@tparam bitflag subset the flags to check for.
@treturn boolean true if all the flags are set, false otherwise.
Expand All @@ -131,8 +157,8 @@ print(myflags:has(flags)) -- true, all bits in flags are set in myflags
static int lsbf_has(lua_State *L) {
LSBF_BITFLAG a = lsbf_checkbitflags(L, 1);
LSBF_BITFLAG b = lsbf_checkbitflags(L, 2);
// Check if all bits in b are also set in a
lua_pushboolean(L, (a | b) == a);
// Check if all bits in b are also set in a, and b is not 0
lua_pushboolean(L, (a | b) == a && b != 0);
return 1;
}

Expand Down
43 changes: 31 additions & 12 deletions src/term.c
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,8 @@ Checks if a file-handle is a TTY.
local system = require('system')
if system.isatty(io.stdin) then
-- enable ANSI coloring etc on Windows, does nothing in Posix.
system.enableconsoleflags(io.stdout, sys.COF_VIRTUAL_TERMINAL_PROCESSING)
local flags = system.getconsoleflags(io.stdout)
system.setconsoleflags(io.stdout, flags + sys.COF_VIRTUAL_TERMINAL_PROCESSING)
end
*/
static int lst_isatty(lua_State* L) {
Expand Down Expand Up @@ -379,9 +380,11 @@ Gets console flags (Windows).
@treturn[2] string error message
@usage
local system = require('system')
print("Current flags:", system.getconsoleflags(io.stdout))
local set = system.getconsoleflags(io.stdout, system.COF_VIRTUAL_TERMINAL_PROCESSING + system.COF_PROCESSED_OUTPUT)
if set then
local flags = system.getconsoleflags(io.stdout)
print("Current stdout flags:", tostring(flags))
if flags:has(system.COF_VIRTUAL_TERMINAL_PROCESSING + system.COF_PROCESSED_OUTPUT) then
print("Both flags are set")
else
print("At least one flag is not set")
Expand Down Expand Up @@ -424,6 +427,7 @@ The terminal attributes is a table with the following fields:
- `iflag` input flags
- `oflag` output flags
- `cflag` control flags
- `lflag` local flags
- `ispeed` input speed
- `ospeed` output speed
- `cc` control characters
Expand All @@ -436,7 +440,12 @@ The terminal attributes is a table with the following fields:
@treturn[2] int errnum
@return error message if failed
@usage
local status, errmsg, errno = tcgetattr(fd)
local system = require('system')
local status = assert(tcgetattr(io.stdin))
if status.iflag:has(system.I_IGNBRK) then
print("Ignoring break condition")
end
*/
static int lst_tcgetattr(lua_State *L)
{
Expand Down Expand Up @@ -512,17 +521,27 @@ To see flag status and constant names check `listtermflags`. For their meaning c
_Note_: not all combinations of flags are allowed, as some are mutually exclusive or mutually required.
See [setconsolemode documentation](https://learn.microsoft.com/en-us/windows/console/setconsolemode)
_Note_: only `iflag`, `oflag`, and `lflag` are supported at the moment. The other fields are ignored.
@function tcsetattr
@tparam file fd file handle to operate on, one of `io.stdin`, `io.stdout`, `io.stderr`
@int actions one of `TCSANOW`, `TCSADRAIN`, `TCSAFLUSH`
@tparam termios a table with bitflag fields:
@tparam[opt] bitflag termios.iflag if given will set the input flags
@tparam[opt] BitFlag termios.oflag if given will set the output flags
@tparam[opt] bitflag termios.lflag if given will set the local flags
@tparam table termios a table with bitflag fields:
@tparam[opt] bitflags termios.iflag if given will set the input flags
@tparam[opt] bitflags termios.oflag if given will set the output flags
@tparam[opt] bitflags termios.lflag if given will set the local flags
@treturn[1] bool `true`, if successful. Always returns `true` on Windows.
@return[2] nil
@treturn[2] string error message
@treturn[2] int errnum
@usage
local system = require('system')
local status = assert(tcgetattr(io.stdin))
if not status.lflag:has(system.L_ECHO) then
-- if echo is off, turn echoing newlines on
tcsetattr(io.stdin, system.TCSANOW, { lflag = status.lflag + system.L_ECHONL }))
end
*/
static int lst_tcsetattr(lua_State *L)
{
Expand Down Expand Up @@ -580,15 +599,15 @@ static int lst_tcsetattr(lua_State *L)


/***
Enables or disable non-blocking mode for a file.
Enables or disables non-blocking mode for a file (Posix).
@function setnonblock
@tparam file fd file handle to operate on, one of `io.stdin`, `io.stdout`, `io.stderr`
@tparam boolean make_non_block a truthy value will enable non-blocking mode, a falsy value will disable it.
@treturn[1] bool `true`, if successful
@treturn[2] nil
@treturn[2] string error message
@treturn[2] int errnum
@see setblock
@see getnonblock
*/
static int lst_setnonblock(lua_State *L)
{
Expand Down Expand Up @@ -620,7 +639,7 @@ static int lst_setnonblock(lua_State *L)


/***
Gets non-blocking mode status for a file.
Gets non-blocking mode status for a file (Posix).
@function getnonblock
@tparam file fd file handle to operate on, one of `io.stdin`, `io.stdout`, `io.stderr`
@treturn[1] bool `true` if set to non-blocking, `false` if not. Always returns `false` on Windows.
Expand Down
Loading

0 comments on commit a7044f4

Please sign in to comment.