mirror of https://github.com/fairyglade/ly.git
Remove unused dependencies
This commit is contained in:
parent
85600ee9b3
commit
13c9aa7c1b
|
|
@ -1,2 +0,0 @@
|
|||
bin
|
||||
obj
|
||||
|
|
@ -1,2 +0,0 @@
|
|||
obj
|
||||
bin
|
||||
|
|
@ -1,13 +0,0 @@
|
|||
DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
|
||||
Version 2, December 2004
|
||||
|
||||
Copyright (C) 2004 Sam Hocevar <sam@hocevar.net>
|
||||
|
||||
Everyone is permitted to copy and distribute verbatim or modified
|
||||
copies of this license document, and changing it is allowed as long
|
||||
as the name is changed.
|
||||
|
||||
DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
|
||||
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
|
||||
|
||||
0. You just DO WHAT THE FUCK YOU WANT TO.
|
||||
|
|
@ -1,79 +0,0 @@
|
|||
# Testoasterror
|
||||
Testoasterror is a minimalistic testing library. It is written in C99
|
||||
and does not use dynamic memory allocations by default.
|
||||
|
||||
# Testing
|
||||
Run `make` and `make run`. This will execute the example in the `tests` folder.
|
||||
|
||||
# Using
|
||||
## TL;DR
|
||||
Check out the `tests` folder
|
||||
|
||||
## Details
|
||||
Include `testoasterror.h` and compile `testoasterror.c` with your testing `main()`.
|
||||
|
||||
Declare an array of `bool` to hold the results of each tested expression.
|
||||
Its size determines the maximum number of expression checks for the same test.
|
||||
If one outreaches that limit, testoasterror will print a "fail overflow" message.
|
||||
The limit is 255, the maximum for a `uint8_t`.
|
||||
```
|
||||
bool results[255];
|
||||
```
|
||||
|
||||
Also declare an array of function pointers to hold your tests
|
||||
```
|
||||
void (*funcs[3])(struct testoasterror*) =
|
||||
{
|
||||
test1,
|
||||
test2,
|
||||
test3
|
||||
}
|
||||
```
|
||||
|
||||
Then, initialize a testoasterror context, giving:
|
||||
- a pointer to the context to initialize
|
||||
- the expression results buffer
|
||||
- its length
|
||||
- the testing functions array
|
||||
- its length
|
||||
```
|
||||
struct testoasterror test;
|
||||
testoasterror_init(&test, results, 255, funcs, 3);
|
||||
```
|
||||
|
||||
Run the tests and you're good to go!
|
||||
```
|
||||
testoasterror_run(&test);
|
||||
```
|
||||
|
||||
You can now write your tests in other C files, using the same function prototype
|
||||
```
|
||||
#ifndef C_TESTS
|
||||
#define C_TESTS
|
||||
|
||||
#include "testoasterror.h"
|
||||
|
||||
// a test
|
||||
void test1(struct testoasterror* test)
|
||||
{
|
||||
// an expression check
|
||||
testoasterror(test, 1 > 0);
|
||||
}
|
||||
|
||||
#endif
|
||||
```
|
||||
|
||||
It is, in my opinion, a good idea to include them directly with the `main()`.
|
||||
This way, the function pointers will resolve without the need for a header
|
||||
(hence the include guards in the C file example above)
|
||||
```
|
||||
#include "tests.c"
|
||||
```
|
||||
|
||||
Extra: to abort, call the fail function *and return*
|
||||
```
|
||||
testoasterror_fail(test);
|
||||
```
|
||||
|
||||
# Greetings
|
||||
nnorm for ninja-starring this repo (how can you be *this* fast?!)
|
||||
|
|
@ -1,155 +0,0 @@
|
|||
#include "testoasterror.h"
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdio.h>
|
||||
|
||||
void testoasterror_init(
|
||||
struct testoasterror* test,
|
||||
bool* results,
|
||||
uint8_t max,
|
||||
void (**funcs)(struct testoasterror*),
|
||||
uint16_t count)
|
||||
{
|
||||
test->testing = false;
|
||||
test->results = results;
|
||||
test->results_end = results + max;
|
||||
|
||||
test->funcs = funcs;
|
||||
test->funcs_count = count;
|
||||
}
|
||||
|
||||
bool testoasterror_log(struct testoasterror* test)
|
||||
{
|
||||
bool* results = test->results;
|
||||
uint8_t max = test->results_cur - results;
|
||||
uint8_t passed_expr = 0;
|
||||
|
||||
// checks the saved status of all processed expressions
|
||||
for (uint8_t i = 0; i < max; ++i)
|
||||
{
|
||||
if (results[i])
|
||||
{
|
||||
++passed_expr;
|
||||
}
|
||||
else
|
||||
{
|
||||
// first fail
|
||||
if (passed_expr == i)
|
||||
{
|
||||
fprintf(stderr, "failed expression ids:");
|
||||
}
|
||||
|
||||
fprintf(stderr, " %u", i);
|
||||
}
|
||||
}
|
||||
|
||||
// newline if we printed any failed expression id
|
||||
if (passed_expr != max)
|
||||
{
|
||||
fprintf(stderr, "\n");
|
||||
}
|
||||
|
||||
if (test->failexec)
|
||||
{
|
||||
fprintf(
|
||||
stderr,
|
||||
"aborted before expression: %u\n",
|
||||
max);
|
||||
}
|
||||
|
||||
// expressions summary
|
||||
fprintf(
|
||||
stderr,
|
||||
"expressions: %u passed, %u failed\n",
|
||||
passed_expr,
|
||||
max - passed_expr);
|
||||
|
||||
return (passed_expr == max);
|
||||
}
|
||||
|
||||
bool testoasterror_run(struct testoasterror* test)
|
||||
{
|
||||
// don't run tests in tests...
|
||||
if (test->testing == true)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
char* result;
|
||||
bool func_passed;
|
||||
uint16_t tests_passed = 0;
|
||||
|
||||
fprintf(
|
||||
stderr,
|
||||
"running %u tests with %u expr slots\n\n",
|
||||
test->funcs_count,
|
||||
(uint8_t) (test->results_end - test->results));
|
||||
|
||||
// runs the test functions from the given function pointers
|
||||
for (uint16_t i = 0; i < test->funcs_count; ++i)
|
||||
{
|
||||
// resets the expr results
|
||||
test->results_cur = test->results;
|
||||
test->failoverflow = false;
|
||||
test->failexec = false;
|
||||
|
||||
// runs the test
|
||||
test->funcs_index = i;
|
||||
test->funcs[i](test);
|
||||
|
||||
// outputs info (a fail overflow is considered a fail)
|
||||
func_passed = testoasterror_log(test)
|
||||
&& !test->failoverflow
|
||||
&& !test->failexec;
|
||||
tests_passed += func_passed;
|
||||
|
||||
// generates a message describing the test results
|
||||
if (test->failoverflow == true)
|
||||
{
|
||||
result = "encountered a fail overflow";
|
||||
}
|
||||
else if (test->failexec == true)
|
||||
{
|
||||
result = "aborted";
|
||||
}
|
||||
else
|
||||
{
|
||||
result = func_passed ? "passed" : "failed";
|
||||
}
|
||||
|
||||
// test status
|
||||
fprintf(stderr, "test #%u %s\n\n", i, result);
|
||||
}
|
||||
|
||||
// tests summary
|
||||
fprintf(
|
||||
stderr,
|
||||
"tests: %u passed, %u failed\n",
|
||||
tests_passed,
|
||||
test->funcs_count - tests_passed);
|
||||
|
||||
return (test->funcs_count == tests_passed);
|
||||
}
|
||||
|
||||
// save a test status
|
||||
bool testoasterror(struct testoasterror* test, bool expr)
|
||||
{
|
||||
if (test->results_cur < test->results_end)
|
||||
{
|
||||
*(test->results_cur) = expr;
|
||||
++(test->results_cur);
|
||||
}
|
||||
else
|
||||
{
|
||||
test->failoverflow = true;
|
||||
}
|
||||
|
||||
return expr;
|
||||
}
|
||||
|
||||
// handles set execution fails
|
||||
void testoasterror_fail(struct testoasterror* test)
|
||||
{
|
||||
test->failexec = true;
|
||||
}
|
||||
|
|
@ -1,41 +0,0 @@
|
|||
#ifndef H_TESTOASTERROR
|
||||
#define H_TESTOASTERROR
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
// main structure
|
||||
struct testoasterror
|
||||
{
|
||||
// this is a test library so we handle all weird cases
|
||||
bool testing;
|
||||
|
||||
// test results for one function
|
||||
bool* results;
|
||||
bool* results_cur;
|
||||
bool* results_end;
|
||||
|
||||
// whether the function made too much tests for the results array
|
||||
bool failoverflow; // <3
|
||||
// execution fail
|
||||
bool failexec;
|
||||
|
||||
// test functions
|
||||
void (**funcs)(struct testoasterror*);
|
||||
uint16_t funcs_index;
|
||||
uint16_t funcs_count;
|
||||
};
|
||||
|
||||
// testoasterror can be static if you want it to (:
|
||||
void testoasterror_init(
|
||||
struct testoasterror* test,
|
||||
bool* results,
|
||||
uint8_t max,
|
||||
void (**funcs)(struct testoasterror*),
|
||||
uint16_t count);
|
||||
bool testoasterror_run(struct testoasterror* test);
|
||||
bool testoasterror(struct testoasterror* test, bool expr);
|
||||
void testoasterror_count(struct testoasterror* test, uint16_t count);
|
||||
void testoasterror_fail(struct testoasterror* test);
|
||||
|
||||
#endif
|
||||
|
|
@ -1,24 +0,0 @@
|
|||
#include "testoasterror.h"
|
||||
|
||||
// source include
|
||||
#include "tests.c"
|
||||
|
||||
#define COUNT_RESULTS 2
|
||||
#define COUNT_FUNCS 3
|
||||
|
||||
int main()
|
||||
{
|
||||
bool results[COUNT_RESULTS];
|
||||
void (*funcs[COUNT_FUNCS])(struct testoasterror*) =
|
||||
{
|
||||
test1,
|
||||
test2,
|
||||
test3
|
||||
};
|
||||
|
||||
struct testoasterror test;
|
||||
testoasterror_init(&test, results, COUNT_RESULTS, funcs, COUNT_FUNCS);
|
||||
testoasterror_run(&test);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -1,34 +0,0 @@
|
|||
#ifndef C_TESTS
|
||||
#define C_TESTS
|
||||
|
||||
#include "testoasterror.h"
|
||||
#include <string.h>
|
||||
|
||||
void test1(struct testoasterror* test)
|
||||
{
|
||||
testoasterror(test, 1 == 1);
|
||||
}
|
||||
|
||||
void test2(struct testoasterror* test)
|
||||
{
|
||||
testoasterror(test, 0 == 0);
|
||||
testoasterror(test, 1 == 1);
|
||||
testoasterror(test, 2 == 2);
|
||||
}
|
||||
|
||||
void test3(struct testoasterror* test)
|
||||
{
|
||||
bool res;
|
||||
|
||||
res = testoasterror(test, strcmp("fuck", "shit") == 0);
|
||||
|
||||
if (!res)
|
||||
{
|
||||
testoasterror_fail(test);
|
||||
return;
|
||||
}
|
||||
|
||||
testoasterror(test, 0 == 0);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
@ -1,13 +0,0 @@
|
|||
DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
|
||||
Version 2, December 2004
|
||||
|
||||
Copyright (C) 2004 Sam Hocevar <sam@hocevar.net>
|
||||
|
||||
Everyone is permitted to copy and distribute verbatim or modified
|
||||
copies of this license document, and changing it is allowed as long
|
||||
as the name is changed.
|
||||
|
||||
DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
|
||||
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
|
||||
|
||||
0. You just DO WHAT THE FUCK YOU WANT TO.
|
||||
|
|
@ -1,129 +0,0 @@
|
|||
# Argoat
|
||||
Argoat is a lightweight library for command-line options parsing.
|
||||
This was created because most of the existing solutions rely heavily on macros,
|
||||
and all of them expect you to write a giant switch to handle the given options.
|
||||
|
||||
Argoat allows you to deal with arguments using function pointers.
|
||||
It does not use any macro, switch, or dynamic memory allocation.
|
||||
|
||||
Argoat supports the following syntaxes:
|
||||
- simple options `test -a -b`
|
||||
- compound options `test -ab`
|
||||
- assigned options `test -c=4 -d 2`
|
||||
- long options `test --code 4 --den 2`
|
||||
- lone dash `test --oki - --den 2`
|
||||
- lone double-dash `test --oki -- --doki`
|
||||
- unflagged options `test 0 -c=4 1 -d=2 3`
|
||||
- limited params `test 0 -c 4 1 -d 2 3`
|
||||
|
||||
Argoat does not support the following syntaxes *on purpose*:
|
||||
- simple neighbours `test -a4`
|
||||
- custom symbols `test +a 4`
|
||||
|
||||
All of that in around 200 lines of code (getopt has approximately 700).
|
||||
Don't be shy, sneak a goat in your code.
|
||||
|
||||
## Cloning
|
||||
Clone with `--recurse-submodules` to get the required submodules.
|
||||
|
||||
## Testing
|
||||
Run `make` to compile the testing suite, and `make run` to perform the tests.
|
||||
|
||||
## Using
|
||||
### TL;DR
|
||||
```
|
||||
#include "argoat.h"
|
||||
#include <stdbool.h>
|
||||
#include <stdio.h>
|
||||
|
||||
void handle_main(void* data, char** pars, const int pars_count)
|
||||
{
|
||||
}
|
||||
|
||||
void handle_bool(void* data, char** pars, const int pars_count)
|
||||
{
|
||||
*((bool*) data) = true;
|
||||
}
|
||||
|
||||
int main(int argc, char** argv)
|
||||
{
|
||||
bool data1 = false;
|
||||
char* unflagged[23];
|
||||
|
||||
const struct argoat_sprig sprigs[2] =
|
||||
{
|
||||
{NULL, 0, NULL, handle_main},
|
||||
{"t", 0, (void*) &data1, handle_bool}
|
||||
};
|
||||
|
||||
struct argoat args = {sprigs, 2, unflagged, 0, 23};
|
||||
argoat_graze(&args, argc, argv);
|
||||
printf("%c\n", data1 ? '1' : '0');
|
||||
|
||||
return 0;
|
||||
}
|
||||
```
|
||||
|
||||
### Details
|
||||
Include `argoat.h` and compile `argoat.c` with your code.
|
||||
|
||||
Write the functions that will handle your parameters.
|
||||
They will be called during the parsing process, in the order given by the user
|
||||
```
|
||||
void handle_main(void* data, char** pars, const int pars_count)
|
||||
{
|
||||
}
|
||||
|
||||
void handle_bool(void* data, char** pars, const int pars_count)
|
||||
{
|
||||
*((bool*) data) = true;
|
||||
}
|
||||
```
|
||||
|
||||
In your `int main(int argc, char** argv)`, declare the variables to configure.
|
||||
They will be passed to the corresponding functions as `void* data`
|
||||
```
|
||||
bool data1 = false;
|
||||
```
|
||||
|
||||
Also declare an array of strings to store the unflagged arguments.
|
||||
Just choose a size corresponding to the maximum number of unflagged arguments
|
||||
your program supports, or create a null pointer if it does not use them.
|
||||
```
|
||||
char* unflagged[UNFLAGGED_MAX];
|
||||
```
|
||||
|
||||
Then, declare an array of flag structures.
|
||||
The first entry only has to contain the unflagged-arguments handling function.
|
||||
The others must specify:
|
||||
- the name of the flag (one char for '-' prefix, multiple chars for '--')
|
||||
- the maximum number of arguments supported by this flag
|
||||
- a pointer to the data that has to be configured by the handling function
|
||||
- a pointer to the handling function
|
||||
```
|
||||
const struct argoat_sprig sprigs[2] =
|
||||
{
|
||||
{NULL, 0, NULL, handle_main},
|
||||
{"t", 0, (void*) &data1, handle_bool}
|
||||
};
|
||||
```
|
||||
|
||||
Then, create the main argoat structure given:
|
||||
- the flags array
|
||||
- its size,
|
||||
- the unflagged string buffer
|
||||
- the initial number of unflagged arguments
|
||||
- the maximum possible
|
||||
```
|
||||
struct argoat args = {sprigs, 2, unflagged, 0, UNFLAGGED_MAX};
|
||||
```
|
||||
|
||||
All that remains to do is calling the parsing function
|
||||
```
|
||||
argoat_graze(&args, argc, argv);
|
||||
```
|
||||
|
||||
And using the configured data
|
||||
```
|
||||
printf("%c\n", data1 ? '1' : '0');
|
||||
```
|
||||
|
|
@ -1,234 +0,0 @@
|
|||
#include "argoat.h"
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
// executes the function for unflagged pars
|
||||
void argoat_unflagged_sacrifice(const struct argoat* args)
|
||||
{
|
||||
args->sprigs[0].func(args->sprigs[0].data,
|
||||
args->unflagged,
|
||||
args->unflagged_count);
|
||||
}
|
||||
|
||||
// returns 1 to increment the pars counter if the one given is flagged
|
||||
// otherwise we store the unflagged par in the buffer and return 0
|
||||
int argoat_increment_pars(struct argoat* args, char* flag, char* pars)
|
||||
{
|
||||
// unflagged pars
|
||||
if (flag == NULL)
|
||||
{
|
||||
// tests bounds and saves
|
||||
int count = args->unflagged_count;
|
||||
|
||||
if (count < args->unflagged_max)
|
||||
{
|
||||
args->unflagged[count] = pars;
|
||||
++args->unflagged_count;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
// flagged pars
|
||||
else
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
// function execution
|
||||
void argoat_sacrifice(struct argoat* args,
|
||||
char* flag,
|
||||
char** pars,
|
||||
int pars_count)
|
||||
{
|
||||
// first flag found or tag compound passed
|
||||
if (flag == NULL)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// handles flags with '='
|
||||
int flag_len;
|
||||
char* eq = strchr(flag, '=');
|
||||
|
||||
if (eq != NULL)
|
||||
{
|
||||
flag_len = eq - flag;
|
||||
}
|
||||
else
|
||||
{
|
||||
flag_len = strlen(flag); // safe
|
||||
}
|
||||
|
||||
// searches the tag in the argoat structure
|
||||
// we initialize i to 1 to skip the programm execution command
|
||||
int i = 1;
|
||||
int len = args->sprigs_count;
|
||||
|
||||
while(i < len)
|
||||
{
|
||||
// as we use strncmp we must test the sizes to avoid collisions
|
||||
if ((strncmp(args->sprigs[i].flag, flag, flag_len) == 0)
|
||||
&& (((int) strlen(args->sprigs[i].flag)) == flag_len)) // safe
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
++i;
|
||||
}
|
||||
|
||||
// the flag was not registered
|
||||
if (i == len)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// handles flags with '='
|
||||
// maximum number of pars passed to the function
|
||||
int max;
|
||||
|
||||
if (eq != NULL)
|
||||
{
|
||||
// moves past the '=' char
|
||||
++eq;
|
||||
// moves the pars pointer to the flag
|
||||
--pars;
|
||||
|
||||
// flag with '=' means we wave an additionnal parameter
|
||||
++pars_count;
|
||||
// which will be the only one (the others are left unflagged)
|
||||
max = 1;
|
||||
|
||||
// copies the par following '=' at the beginning of the flag
|
||||
memcpy(pars[0], eq, strlen(eq) + 1); // safe
|
||||
}
|
||||
else
|
||||
{
|
||||
max = args->sprigs[i].pars_max;
|
||||
}
|
||||
|
||||
// saves pars exceeding the limit
|
||||
if (pars_count > max)
|
||||
{
|
||||
for(int k = max; k < pars_count; ++k)
|
||||
{
|
||||
// leverages the pars incrementation side-effects
|
||||
argoat_increment_pars(args, NULL, pars[k]);
|
||||
}
|
||||
|
||||
// fixes the number of pars given to the function
|
||||
pars_count = max;
|
||||
}
|
||||
|
||||
// calls the approriate function
|
||||
args->sprigs[i].func(args->sprigs[i].data, pars, pars_count);
|
||||
}
|
||||
|
||||
// executes functions without pars for compound tags
|
||||
void argoat_compound(struct argoat* args, char** pars)
|
||||
{
|
||||
// currently processed char/flag
|
||||
int scroll = 1;
|
||||
char flag[2]; // safe
|
||||
|
||||
flag[1] = '\0';
|
||||
|
||||
// if this function is excuted this means there is at least one flag
|
||||
// therefore it is safe to test the condition for the next char only
|
||||
do
|
||||
{
|
||||
flag[0] = pars[0][scroll];
|
||||
argoat_sacrifice(args, flag, pars, 0);
|
||||
++scroll;
|
||||
}
|
||||
while(pars[0][scroll] != '\0');
|
||||
}
|
||||
|
||||
// executes functions with pars for each flag
|
||||
void argoat_graze(struct argoat* args, int argc, char** argv)
|
||||
{
|
||||
int pars_count = 0;
|
||||
char** pars = NULL;
|
||||
char* flag = NULL;
|
||||
char dash;
|
||||
|
||||
// skips the program execution command
|
||||
++argv;
|
||||
--argc;
|
||||
|
||||
// identifies every element in argv and executes the right
|
||||
// handling functions during the process
|
||||
for (int i = 0; i < argc; ++i)
|
||||
{
|
||||
// will be tested to identify lone dashes and long flags
|
||||
dash = argv[i][1];
|
||||
|
||||
// pars
|
||||
if (argv[i][0] != '-')
|
||||
{
|
||||
pars_count += argoat_increment_pars(args,
|
||||
flag,
|
||||
argv[i]);
|
||||
}
|
||||
// lone dash pars
|
||||
else if (dash == '\0')
|
||||
{
|
||||
pars_count += argoat_increment_pars(args,
|
||||
flag,
|
||||
argv[i]);
|
||||
}
|
||||
// very probably long flags
|
||||
else if (dash == '-')
|
||||
{
|
||||
// lone double-dash pars
|
||||
if (argv[i][2] == '\0')
|
||||
{
|
||||
pars_count += argoat_increment_pars(args,
|
||||
flag,
|
||||
argv[i]);
|
||||
}
|
||||
// long flags
|
||||
else
|
||||
{
|
||||
// executes for previous flag
|
||||
argoat_sacrifice(args, flag, pars, pars_count);
|
||||
// starts a new flag scope
|
||||
flag = argv[i] + 2;
|
||||
pars = argv + i + 1;
|
||||
pars_count = 0;
|
||||
}
|
||||
}
|
||||
// flags
|
||||
else
|
||||
{
|
||||
// executes for previous flag
|
||||
argoat_sacrifice(args, flag, pars, pars_count);
|
||||
|
||||
// compound flags (eg "-xvzf") directly executes
|
||||
if ((argv[i][2] != '=') && (argv[i][2] != '\0'))
|
||||
{
|
||||
// to get rid of the dash
|
||||
argoat_compound(args, argv + i);
|
||||
flag = NULL;
|
||||
pars = NULL;
|
||||
}
|
||||
// simple flags
|
||||
else
|
||||
{
|
||||
flag = argv[i] + 1;
|
||||
pars = argv + i + 1;
|
||||
}
|
||||
|
||||
pars_count = 0;
|
||||
}
|
||||
}
|
||||
|
||||
// we call the function corresponding to the last flag
|
||||
argoat_sacrifice(args, flag, pars, pars_count);
|
||||
// we call the function handling unflagged pars
|
||||
if (args->unflagged_max > 0)
|
||||
{
|
||||
argoat_unflagged_sacrifice(args);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,36 +0,0 @@
|
|||
#ifndef H_ARGOAT
|
||||
#define H_ARGOAT
|
||||
|
||||
// flag-processor
|
||||
struct argoat_sprig
|
||||
{
|
||||
// dash-prefixed option
|
||||
const char* flag;
|
||||
// maximum pars
|
||||
const int pars_max;
|
||||
// pre-loaded data for the function
|
||||
void* data;
|
||||
// function executed upon detection
|
||||
void (* const func)(void* data, char** pars, const int pars_count);
|
||||
};
|
||||
|
||||
// main structure
|
||||
struct argoat
|
||||
{
|
||||
// the flags-processor list, with handling functions etc.
|
||||
const struct argoat_sprig* sprigs;
|
||||
// size of the list above
|
||||
const int sprigs_count;
|
||||
// unflagged tags buffer
|
||||
char** unflagged;
|
||||
int unflagged_count;
|
||||
int unflagged_max;
|
||||
};
|
||||
|
||||
void argoat_unflagged_sacrifice(const struct argoat* args);
|
||||
int argoat_increment_pars(struct argoat* args, char* flag, char* pars);
|
||||
void argoat_sacrifice(struct argoat* args, char* flag, char** pars, int pars_count);
|
||||
void argoat_compound(struct argoat* args, char** pars);
|
||||
void argoat_graze(struct argoat* args, int argc, char** argv);
|
||||
|
||||
#endif
|
||||
|
|
@ -1,42 +0,0 @@
|
|||
#include "argoat.h"
|
||||
#include <stdbool.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
|
||||
void handle_bool(void* data, char** pars, const int pars_count)
|
||||
{
|
||||
*((bool*) data) = true;
|
||||
}
|
||||
|
||||
void handle_main(void* data, char** pars, const int pars_count)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
int main(int argc, char** argv)
|
||||
{
|
||||
bool data1 = false;
|
||||
bool data2 = false;
|
||||
bool data3 = false;
|
||||
char** unflagged = NULL;
|
||||
|
||||
const struct argoat_sprig sprigs[4] =
|
||||
{
|
||||
{NULL, 0, NULL, handle_main},
|
||||
{"l", 0, (void*) &data1, handle_bool},
|
||||
{"m", 0, (void*) &data2, handle_bool},
|
||||
{"o", 0, (void*) &data3, handle_bool},
|
||||
};
|
||||
|
||||
struct argoat args = {sprigs, 4, unflagged, 0, 0};
|
||||
|
||||
argoat_graze(&args, argc, argv);
|
||||
|
||||
printf("t%c%c%c\n",
|
||||
data1 ? 'l' : ' ',
|
||||
data2 ? 'm' : ' ',
|
||||
data3 ? 'o' : ' ');
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -1,54 +0,0 @@
|
|||
#include "argoat.h"
|
||||
#include <stdbool.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#define UNFLAGGED_MAX 4
|
||||
|
||||
void handle_bool(void* data, char** pars, const int pars_count)
|
||||
{
|
||||
*((bool*) data) = true;
|
||||
}
|
||||
|
||||
void handle_main(void* data, char** pars, const int pars_count)
|
||||
{
|
||||
if (pars_count > UNFLAGGED_MAX)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
for (int i = 0; i < pars_count; ++i)
|
||||
{
|
||||
printf("%s", pars[i]);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
int main(int argc, char** argv)
|
||||
{
|
||||
bool data1 = false;
|
||||
bool data2 = false;
|
||||
bool data3 = false;
|
||||
char* unflagged[UNFLAGGED_MAX];
|
||||
|
||||
const struct argoat_sprig sprigs[4] =
|
||||
{
|
||||
{NULL, 0, NULL, handle_main},
|
||||
{"long", 0, (void*) &data1, handle_bool},
|
||||
{"mighty", 0, (void*) &data2, handle_bool},
|
||||
{"options", 0, (void*) &data3, handle_bool},
|
||||
};
|
||||
|
||||
struct argoat args = {sprigs, 4, unflagged, 0, UNFLAGGED_MAX};
|
||||
|
||||
argoat_graze(&args, argc, argv);
|
||||
|
||||
printf("t%c%c%c\n",
|
||||
data1 ? 'l' : ' ',
|
||||
data2 ? 'm' : ' ',
|
||||
data3 ? 'o' : ' ');
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -1,72 +0,0 @@
|
|||
#include "argoat.h"
|
||||
#include <stdbool.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#define UNFLAGGED_MAX 4
|
||||
|
||||
void handle_bool(void* data, char** pars, const int pars_count)
|
||||
{
|
||||
*((bool*) data) = true;
|
||||
}
|
||||
|
||||
void handle_add(void* data, char** pars, const int pars_count)
|
||||
{
|
||||
if (pars_count < 2)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
*((int*) data) = atoi(pars[0]) + atoi(pars[1]); // safe for testing
|
||||
}
|
||||
|
||||
void handle_string(void* data, char** pars, const int pars_count)
|
||||
{
|
||||
if (pars_count < 1)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
*((char**) data) = pars[0];
|
||||
}
|
||||
|
||||
void handle_main(void* data, char** pars, const int pars_count)
|
||||
{
|
||||
if (pars_count > UNFLAGGED_MAX)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
for (int i = 0; i < pars_count; ++i)
|
||||
{
|
||||
printf("%s", pars[i]);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
int main(int argc, char** argv)
|
||||
{
|
||||
bool data1 = false;
|
||||
int data2 = 0;
|
||||
char* data3 = "";
|
||||
|
||||
char* unflagged[UNFLAGGED_MAX];
|
||||
|
||||
const struct argoat_sprig sprigs[4] =
|
||||
{
|
||||
{NULL, 0, NULL, handle_main},
|
||||
{"tau", 2, (void*) &data2, handle_add},
|
||||
{"t", 0, (void*) &data1, handle_bool},
|
||||
{"text", 1, (void*) &data3, handle_string},
|
||||
};
|
||||
|
||||
struct argoat args = {sprigs, 4, unflagged, 0, UNFLAGGED_MAX};
|
||||
|
||||
argoat_graze(&args, argc, argv);
|
||||
|
||||
printf("t%c%d%s\n", data1 ? 'l' : ' ', data2, data3);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -1,22 +0,0 @@
|
|||
#define _POSIX_C_SOURCE 200809L
|
||||
#include "testoasterror.h"
|
||||
|
||||
// source include
|
||||
#include "tests.c"
|
||||
|
||||
int main()
|
||||
{
|
||||
bool results[32];
|
||||
void (*funcs[3])(struct testoasterror*) =
|
||||
{
|
||||
test1,
|
||||
test2,
|
||||
test3
|
||||
};
|
||||
|
||||
struct testoasterror test;
|
||||
testoasterror_init(&test, results, 32, funcs, 3);
|
||||
testoasterror_run(&test);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -1,80 +0,0 @@
|
|||
#ifndef C_TESTS
|
||||
#define C_TESTS
|
||||
|
||||
#include "testoasterror.h"
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
|
||||
void test_tool(struct testoasterror* test, uint8_t id, char* args, char* cmp)
|
||||
{
|
||||
char* ret;
|
||||
char buf[32];
|
||||
char cmd[128];
|
||||
char cmp_ln[16];
|
||||
|
||||
snprintf(cmd, 128, "./argoat_sample_%u %s 2>&1", id, args);
|
||||
snprintf(cmp_ln, 16, "%s\n", cmp);
|
||||
|
||||
FILE* fp = popen(cmd, "r");
|
||||
testoasterror(test, fp != NULL);
|
||||
|
||||
ret = fgets(buf, 32, fp);
|
||||
testoasterror(test, (ret != NULL) && (strcmp(buf, cmp_ln) == 0));
|
||||
fclose(fp);
|
||||
}
|
||||
|
||||
void test1(struct testoasterror* test)
|
||||
{
|
||||
test_tool(test, 1, "", "t ");
|
||||
|
||||
test_tool(test, 1, "-l", "tl ");
|
||||
test_tool(test, 1, "-m", "t m ");
|
||||
test_tool(test, 1, "-o", "t o");
|
||||
|
||||
test_tool(test, 1, "--l", "tl ");
|
||||
test_tool(test, 1, "--long", "t ");
|
||||
|
||||
test_tool(test, 1, "-lmo", "tlmo");
|
||||
test_tool(test, 1, "-lm -o", "tlmo");
|
||||
test_tool(test, 1, "-l -m -o", "tlmo");
|
||||
|
||||
test_tool(test, 1, "-l 1 -m 2 -o 3", "tlmo");
|
||||
|
||||
test_tool(test, 1, "-l - -m", "tlm ");
|
||||
test_tool(test, 1, "-l --m 3", "tlm ");
|
||||
test_tool(test, 1, "-l --m=3", "tlm ");
|
||||
}
|
||||
|
||||
void test2(struct testoasterror* test)
|
||||
{
|
||||
test_tool(test, 2, "--long", "tl ");
|
||||
test_tool(test, 2, "--mighty", "t m ");
|
||||
test_tool(test, 2, "--options", "t o");
|
||||
|
||||
test_tool(test, 2, "-l", "t ");
|
||||
test_tool(test, 2, "-long", "t ");
|
||||
|
||||
test_tool(test, 2, "--long --mighty --options", "tlmo");
|
||||
test_tool(test, 2, "0 --long 1 --mighty 2 --options 3", "0123tlmo");
|
||||
test_tool(test, 2, "0 --long=1 --mighty 2 --options 3", "023tlmo");
|
||||
test_tool(test, 2, "0 --long=1 4 --mighty 2 --options 3", "0423tlmo");
|
||||
|
||||
test_tool(test, 2, "0 --long - --mighty -- --options 3", "0---3tlmo");
|
||||
}
|
||||
|
||||
void test3(struct testoasterror* test)
|
||||
{
|
||||
test_tool(test, 3, "-t", "tl0");
|
||||
test_tool(test, 3, "--tau", "t 0");
|
||||
test_tool(test, 3, "--text", "t 0");
|
||||
|
||||
test_tool(test, 3, "-t --tau 3 4 5", "5tl7");
|
||||
test_tool(test, 3, "--tau=3 4 5", "45t 0");
|
||||
test_tool(test, 3, "--text one two", "twot 0one");
|
||||
|
||||
test_tool(test, 3, "--text= one two", "onetwot 0");
|
||||
}
|
||||
|
||||
#endif
|
||||
356
src/main.c
356
src/main.c
|
|
@ -1,356 +0,0 @@
|
|||
#include "argoat.h"
|
||||
#include "configator.h"
|
||||
#include "dragonfail.h"
|
||||
#include "termbox.h"
|
||||
|
||||
#include "draw.h"
|
||||
#include "inputs.h"
|
||||
#include "login.h"
|
||||
#include "utils.h"
|
||||
#include "config.h"
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stddef.h>
|
||||
#include <string.h>
|
||||
#include <sys/time.h>
|
||||
#include <unistd.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#define ARG_COUNT 7
|
||||
|
||||
#ifndef LY_VERSION
|
||||
#define LY_VERSION "0.7.0"
|
||||
#endif
|
||||
|
||||
// global
|
||||
struct lang lang;
|
||||
struct config config;
|
||||
|
||||
// args handles
|
||||
void arg_help(void* data, char** pars, const int pars_count)
|
||||
{
|
||||
printf("If you want to configure Ly, please check the config file, usually located at /etc/ly/config.ini.\n");
|
||||
exit(0);
|
||||
}
|
||||
|
||||
void arg_version(void* data, char** pars, const int pars_count)
|
||||
{
|
||||
printf("Ly version %s\n", LY_VERSION);
|
||||
exit(0);
|
||||
}
|
||||
|
||||
// low-level error messages
|
||||
void log_init(char** log)
|
||||
{
|
||||
log[DGN_OK] = lang.err_dgn_oob;
|
||||
log[DGN_NULL] = lang.err_null;
|
||||
log[DGN_ALLOC] = lang.err_alloc;
|
||||
log[DGN_BOUNDS] = lang.err_bounds;
|
||||
log[DGN_DOMAIN] = lang.err_domain;
|
||||
log[DGN_MLOCK] = lang.err_mlock;
|
||||
log[DGN_XSESSIONS_DIR] = lang.err_xsessions_dir;
|
||||
log[DGN_XSESSIONS_OPEN] = lang.err_xsessions_open;
|
||||
log[DGN_PATH] = lang.err_path;
|
||||
log[DGN_CHDIR] = lang.err_chdir;
|
||||
log[DGN_PWNAM] = lang.err_pwnam;
|
||||
log[DGN_USER_INIT] = lang.err_user_init;
|
||||
log[DGN_USER_GID] = lang.err_user_gid;
|
||||
log[DGN_USER_UID] = lang.err_user_uid;
|
||||
log[DGN_PAM] = lang.err_pam;
|
||||
log[DGN_HOSTNAME] = lang.err_hostname;
|
||||
}
|
||||
|
||||
void arg_config(void* data, char** pars, const int pars_count)
|
||||
{
|
||||
*((char **)data) = *pars;
|
||||
}
|
||||
|
||||
// ly!
|
||||
int main(int argc, char** argv)
|
||||
{
|
||||
// init error lib
|
||||
log_init(dgn_init());
|
||||
|
||||
// load config
|
||||
config_defaults();
|
||||
lang_defaults();
|
||||
|
||||
char *config_path = NULL;
|
||||
// parse args
|
||||
const struct argoat_sprig sprigs[ARG_COUNT] =
|
||||
{
|
||||
{NULL, 0, NULL, NULL},
|
||||
{"config", 0, &config_path, arg_config},
|
||||
{"c", 0, &config_path, arg_config},
|
||||
{"help", 0, NULL, arg_help},
|
||||
{"h", 0, NULL, arg_help},
|
||||
{"version", 0, NULL, arg_version},
|
||||
{"v", 0, NULL, arg_version},
|
||||
};
|
||||
|
||||
struct argoat args = {sprigs, ARG_COUNT, NULL, 0, 0};
|
||||
argoat_graze(&args, argc, argv);
|
||||
|
||||
// init inputs
|
||||
struct desktop desktop;
|
||||
struct text login;
|
||||
struct text password;
|
||||
input_desktop(&desktop);
|
||||
input_text(&login, config.max_login_len);
|
||||
input_text(&password, config.max_password_len);
|
||||
|
||||
if (dgn_catch())
|
||||
{
|
||||
config_free();
|
||||
lang_free();
|
||||
return 1;
|
||||
}
|
||||
|
||||
config_load(config_path);
|
||||
lang_load();
|
||||
|
||||
void* input_structs[3] =
|
||||
{
|
||||
(void*) &desktop,
|
||||
(void*) &login,
|
||||
(void*) &password,
|
||||
};
|
||||
|
||||
void (*input_handles[3]) (void*, struct tb_event*) =
|
||||
{
|
||||
handle_desktop,
|
||||
handle_text,
|
||||
handle_text,
|
||||
};
|
||||
|
||||
desktop_load(&desktop);
|
||||
load(&desktop, &login);
|
||||
|
||||
// start termbox
|
||||
tb_init();
|
||||
tb_select_output_mode(TB_OUTPUT_NORMAL);
|
||||
tb_clear();
|
||||
|
||||
// init visible elements
|
||||
struct tb_event event;
|
||||
struct term_buf buf;
|
||||
|
||||
//Place the curser on the login field if there is no saved username, if there is, place the curser on the password field
|
||||
uint8_t active_input;
|
||||
if (config.default_input == LOGIN_INPUT && login.text != login.end){
|
||||
active_input = PASSWORD_INPUT;
|
||||
}
|
||||
else{
|
||||
active_input = config.default_input;
|
||||
}
|
||||
|
||||
|
||||
// init drawing stuff
|
||||
draw_init(&buf);
|
||||
|
||||
// draw_box and position_input are called because they need to be
|
||||
// called before *input_handles[active_input] for the cursor to be
|
||||
// positioned correctly
|
||||
draw_box(&buf);
|
||||
position_input(&buf, &desktop, &login, &password);
|
||||
(*input_handles[active_input])(input_structs[active_input], NULL);
|
||||
|
||||
if (config.animate)
|
||||
{
|
||||
animate_init(&buf);
|
||||
|
||||
if (dgn_catch())
|
||||
{
|
||||
config.animate = false;
|
||||
dgn_reset();
|
||||
}
|
||||
}
|
||||
|
||||
// init state info
|
||||
int error;
|
||||
bool run = true;
|
||||
bool update = true;
|
||||
bool reboot = false;
|
||||
bool shutdown = false;
|
||||
uint8_t auth_fails = 0;
|
||||
|
||||
switch_tty(&buf);
|
||||
|
||||
// main loop
|
||||
while (run)
|
||||
{
|
||||
if (update)
|
||||
{
|
||||
if (auth_fails < 10)
|
||||
{
|
||||
(*input_handles[active_input])(input_structs[active_input], NULL);
|
||||
tb_clear();
|
||||
animate(&buf);
|
||||
draw_bigclock(&buf);
|
||||
draw_box(&buf);
|
||||
draw_clock(&buf);
|
||||
draw_labels(&buf);
|
||||
if(!config.hide_f1_commands)
|
||||
draw_f_commands();
|
||||
draw_lock_state(&buf);
|
||||
position_input(&buf, &desktop, &login, &password);
|
||||
draw_desktop(&desktop);
|
||||
draw_input(&login);
|
||||
draw_input_mask(&password);
|
||||
update = config.animate;
|
||||
}
|
||||
else
|
||||
{
|
||||
usleep(10000);
|
||||
update = cascade(&buf, &auth_fails);
|
||||
}
|
||||
|
||||
tb_present();
|
||||
}
|
||||
|
||||
int timeout = -1;
|
||||
|
||||
if (config.animate)
|
||||
{
|
||||
timeout = config.min_refresh_delta;
|
||||
}
|
||||
else
|
||||
{
|
||||
struct timeval tv;
|
||||
gettimeofday(&tv, NULL);
|
||||
if (config.bigclock)
|
||||
timeout = (60 - tv.tv_sec % 60) * 1000 - tv.tv_usec / 1000 + 1;
|
||||
if (config.clock)
|
||||
timeout = 1000 - tv.tv_usec / 1000 + 1;
|
||||
}
|
||||
|
||||
if (timeout == -1)
|
||||
{
|
||||
error = tb_poll_event(&event);
|
||||
}
|
||||
else
|
||||
{
|
||||
error = tb_peek_event(&event, timeout);
|
||||
}
|
||||
|
||||
if (error < 0)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (event.type == TB_EVENT_KEY)
|
||||
{
|
||||
switch (event.key)
|
||||
{
|
||||
case TB_KEY_F1:
|
||||
shutdown = true;
|
||||
run = false;
|
||||
break;
|
||||
case TB_KEY_F2:
|
||||
reboot = true;
|
||||
run = false;
|
||||
break;
|
||||
case TB_KEY_CTRL_C:
|
||||
run = false;
|
||||
break;
|
||||
case TB_KEY_CTRL_U:
|
||||
if (active_input > 0)
|
||||
{
|
||||
input_text_clear(input_structs[active_input]);
|
||||
update = true;
|
||||
}
|
||||
break;
|
||||
case TB_KEY_CTRL_K:
|
||||
case TB_KEY_ARROW_UP:
|
||||
if (active_input > 0)
|
||||
{
|
||||
--active_input;
|
||||
update = true;
|
||||
}
|
||||
break;
|
||||
case TB_KEY_CTRL_J:
|
||||
case TB_KEY_ARROW_DOWN:
|
||||
if (active_input < 2)
|
||||
{
|
||||
++active_input;
|
||||
update = true;
|
||||
}
|
||||
break;
|
||||
case TB_KEY_TAB:
|
||||
++active_input;
|
||||
|
||||
if (active_input > 2)
|
||||
{
|
||||
active_input = SESSION_SWITCH;
|
||||
}
|
||||
update = true;
|
||||
break;
|
||||
case TB_KEY_ENTER:
|
||||
save(&desktop, &login);
|
||||
auth(&desktop, &login, &password, &buf);
|
||||
update = true;
|
||||
|
||||
if (dgn_catch())
|
||||
{
|
||||
++auth_fails;
|
||||
// move focus back to password input
|
||||
active_input = PASSWORD_INPUT;
|
||||
|
||||
if (dgn_output_code() != DGN_PAM)
|
||||
{
|
||||
buf.info_line = dgn_output_log();
|
||||
}
|
||||
|
||||
if (config.blank_password)
|
||||
{
|
||||
input_text_clear(&password);
|
||||
}
|
||||
|
||||
dgn_reset();
|
||||
}
|
||||
else
|
||||
{
|
||||
buf.info_line = lang.logout;
|
||||
}
|
||||
|
||||
load(&desktop, &login);
|
||||
system("tput cnorm");
|
||||
break;
|
||||
default:
|
||||
(*input_handles[active_input])(
|
||||
input_structs[active_input],
|
||||
&event);
|
||||
update = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// stop termbox
|
||||
tb_shutdown();
|
||||
|
||||
// free inputs
|
||||
input_desktop_free(&desktop);
|
||||
input_text_free(&login);
|
||||
input_text_free(&password);
|
||||
free_hostname();
|
||||
|
||||
// unload config
|
||||
draw_free(&buf);
|
||||
lang_free();
|
||||
|
||||
if (shutdown)
|
||||
{
|
||||
execl("/bin/sh", "sh", "-c", config.shutdown_cmd, NULL);
|
||||
}
|
||||
else if (reboot)
|
||||
{
|
||||
execl("/bin/sh", "sh", "-c", config.restart_cmd, NULL);
|
||||
}
|
||||
|
||||
config_free();
|
||||
|
||||
return 0;
|
||||
}
|
||||
12
src/main.zig
12
src/main.zig
|
|
@ -1,5 +1,6 @@
|
|||
const std = @import("std");
|
||||
const c = @cImport({
|
||||
|
||||
pub const c = @cImport({
|
||||
@cInclude("configator.h");
|
||||
@cInclude("dragonfail.h");
|
||||
@cInclude("termbox.h");
|
||||
|
|
@ -17,11 +18,12 @@ const MAX_AUTH_FAILS = 10;
|
|||
|
||||
// Main allocator for Ly
|
||||
var gpa = std.heap.GeneralPurposeAllocator(.{}){};
|
||||
const allocator = gpa.allocator();
|
||||
|
||||
pub const allocator = gpa.allocator();
|
||||
|
||||
// Ly general and language configuration
|
||||
var config: c.struct_config = undefined;
|
||||
var lang: c.struct_lang = undefined;
|
||||
pub var config: c.struct_config = undefined;
|
||||
pub var lang: c.struct_lang = undefined;
|
||||
|
||||
comptime {
|
||||
@export(config, .{ .name = "config" });
|
||||
|
|
@ -314,7 +316,7 @@ pub fn main() !void {
|
|||
c.load(desktop, username);
|
||||
|
||||
// Reset cursor to its normal state
|
||||
_ = std.ChildProcess.exec(.{ .argv = &[_][]const u8{ "/sbin/tput", "cnorm" }, .allocator = allocator }) catch return;
|
||||
_ = std.ChildProcess.exec(.{ .argv = &[_][]const u8{ "/usr/bin/tput", "cnorm" }, .allocator = allocator }) catch return;
|
||||
|
||||
update = true;
|
||||
},
|
||||
|
|
|
|||
Loading…
Reference in New Issue