Compare commits

...

25 Commits

Author SHA1 Message Date
43542d84dc Merge branch 'master' of ssh://rexy712-server:1995/var/git/repos/rexy712/thinkpad_backlight 2022-01-30 20:43:09 -08:00
398146a0d8 Fix parsing of restore file 2022-01-30 20:42:12 -08:00
rexy712
b944ee8dec Version bump 2021-01-17 09:35:35 -08:00
rexy712
927160ba01 Fix restore file not working 2021-01-17 09:34:21 -08:00
rexy712
42dee2de78 Update to version 1.5.2 2021-01-03 10:01:25 -08:00
rexy712
61e36bed19 Fix error output on invalid permissions to write to brightness file 2021-01-03 09:54:49 -08:00
rexy712
50412e0006 Fix CMakeLists.txt 2020-04-09 15:22:05 -07:00
rexy712
19d736bc84 Fix usage of older rjp parse flag 2020-04-09 14:56:02 -07:00
rexy712
db3036e85b Merge branch 'master' of ssh://rexy712-server:1995/var/git/repos/rexy712/thinkpad_backlight 2020-04-09 14:39:01 -07:00
rexy712
26bd685296 Update to new rjp api 2020-04-09 14:38:52 -07:00
rexy712
fa187be8b0 Update CMakeLists to use rjp's pkg-config files 2020-03-07 13:19:34 -08:00
rexy712
bbce4dc8fe Updated version 2020-02-23 10:27:13 -08:00
rexy712
9c4425ff54 Update to new rjp api 2020-02-23 10:24:10 -08:00
rexy712
2e0ee84ca7 Add support for new rjp api 2019-11-09 21:18:00 -08:00
rexy712
f868074f0c please 2019-01-14 16:17:57 -08:00
rexy712
2fdd9fa13b fixed typo 2019-01-14 16:11:53 -08:00
rexy712
40eec1fb23 hope this fixes it... 2019-01-14 16:07:33 -08:00
rexy712
42f93ba026 really fixed version this time 2019-01-14 16:04:09 -08:00
rexy712
44ddaae28d fixed version output 2019-01-14 16:01:49 -08:00
rexy712
5986fa8133 Fixed version number 2019-01-14 15:55:33 -08:00
rexy712
479e7c1f17 Removed the cool git versioning thing because it won't work when distributed 2019-01-14 15:54:47 -08:00
rexy712
2dd52c32b7 Fixed memory leak when restore file is disabled and prevent restore file parsing when no write is performed 2018-12-16 15:42:22 -08:00
rexy712
87b7dd2503 Added option to not write to restore file and fixed a lot of restore file issues 2018-12-16 14:27:58 -08:00
rexy712
3c2e3f35a0 Version now includes dirty status on exact version tags too 2018-12-16 07:18:31 -08:00
rexy712
00062612f5 Cleaned up option management in cmd.c and moved a restore operation from rexbacklight.c to restore.c 2018-12-16 06:56:18 -08:00
14 changed files with 275 additions and 235 deletions

View File

@ -1,6 +1,7 @@
include(CMakeDependentOption)
cmake_minimum_required(VERSION 3.1)
project(rexbacklight)
cmake_minimum_required(VERSION 3.1)
include(CMakeDependentOption)
include(GNUInstallDirs)
set(SCRIPT_DIR ${CMAKE_SOURCE_DIR}/scripts)
@ -23,9 +24,7 @@ if(PYTHONINTERP_FOUND)
add_custom_command(
OUTPUT ${GIT_VERSION_TMP_FILE}
COMMAND ${CMAKE_COMMAND} -E echo "//File generated by CMake. Do not edit!" > ${GIT_VERSION_TMP_FILE}
COMMAND ${PYTHON_EXECUTABLE} ${SCRIPT_DIR}/git_branch_name.py >> ${GIT_VERSION_TMP_FILE}
COMMAND ${PYTHON_EXECUTABLE} ${SCRIPT_DIR}/git_commit_hash.py >> ${GIT_VERSION_TMP_FILE}
COMMAND ${PYTHON_EXECUTABLE} ${SCRIPT_DIR}/git_tag_name.py >> ${GIT_VERSION_TMP_FILE}
COMMAND ${CMAKE_COMMAND} -E echo "#define GIT_TAG_NAME \"v1.5.3\"" > ${GIT_VERSION_TMP_FILE}
COMMAND ${CMAKE_COMMAND} -E copy_if_different ${GIT_VERSION_TMP_FILE} ${GIT_VERSION_FILE}
COMMAND ${CMAKE_COMMAND} -E remove ${GIT_VERSION_TMP_FILE}
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
@ -36,9 +35,7 @@ elseif(UNIX)
add_custom_command(
OUTPUT ${GIT_VERSION_TMP_FILE}
COMMAND ${CMAKE_COMMAND} -E echo "//File generated by CMake. Do not edit!" > ${GIT_VERSION_TMP_FILE}
COMMAND ${SCRIPT_DIR}/git_branch_name.sh >> ${GIT_VERSION_TMP_FILE}
COMMAND ${SCRIPT_DIR}/git_commit_hash.sh >> ${GIT_VERSION_TMP_FILE}
COMMAND ${SCRIPT_DIR}/git_tag_name.sh >> ${GIT_VERSION_TMP_FILE}
COMMAND ${CMAKE_COMMAND} -E echo "#define GIT_TAG_NAME \"v1.5.3\"" > ${GIT_VERSION_TMP_FILE}
COMMAND ${CMAKE_COMMAND} -E copy_if_different ${GIT_VERSION_TMP_FILE} ${GIT_VERSION_FILE}
COMMAND ${CMAKE_COMMAND} -E remove ${GIT_VERSION_TMP_FILE}
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
@ -65,8 +62,8 @@ endif()
#locate rjp library requirements
if(ENABLE_RESTORE_FILE)
find_library(RJP_LIB rjp)
find_path(RJP_HEADER_DIR rjp.h)
find_package(PkgConfig REQUIRED)
pkg_check_modules(RJP REQUIRED rjp)
#temporary library (no actual library generated)
add_library(common_srcs OBJECT src/cmd.c src/common.c src/restore.c)
add_definitions("-DENABLE_RESTORE_FILE")
@ -82,11 +79,12 @@ if(BUILD_REXLEDCTL)
add_executable (rexledctl src/rexbacklight.c)
add_dependencies(rexledctl common_srcs) #force common_srcs to be built first
target_compile_definitions(rexledctl PRIVATE REXLEDCTL) #define REXLEDCTL in C files
if(ENABLE_RESTORE_FILE)
target_link_libraries(rexledctl PRIVATE "${RJP_LIB}") #link with rjp
target_include_directories(rexledctl PUBLIC "${RJP_HEADER_DIR}") #include rjp.h directory
endif()
target_link_libraries(rexledctl PRIVATE $<TARGET_OBJECTS:common_srcs>) #link with the common_srcs "library"
if(ENABLE_RESTORE_FILE)
target_link_libraries(rexledctl PRIVATE "${RJP_LIBRARIES}") #link with rjp
target_include_directories(rexledctl PUBLIC "${RJP_INCLUDE_DIRS}") #include rjp.h directory
target_compile_options(rexledctl PUBLIC ${RJP_CFLAGS_OTHER})
endif()
install(TARGETS rexledctl RUNTIME DESTINATION bin)
if(INSTALL_UDEV_LED_RULE)
install(FILES ${CMAKE_SOURCE_DIR}/rules/91-leds.rules DESTINATION ${UDEV_DIR})
@ -95,13 +93,14 @@ endif()
#build backlight control program
if(BUILD_REXBACKLIGHT)
add_executable (rexbacklight src/rexbacklight.c)
add_dependencies(rexledctl common_srcs)
add_dependencies(rexbacklight common_srcs)
target_compile_definitions(rexbacklight PRIVATE REXBACKLIGHT)
if(ENABLE_RESTORE_FILE)
target_link_libraries(rexbacklight PRIVATE "${RJP_LIB}")
target_include_directories(rexbacklight PUBLIC "${RJP_HEADER_DIR}")
endif()
target_link_libraries(rexbacklight PRIVATE $<TARGET_OBJECTS:common_srcs>)
if(ENABLE_RESTORE_FILE)
target_link_libraries(rexbacklight PRIVATE "${RJP_LIBRARIES}")
target_include_directories(rexbacklight PUBLIC "${RJP_INCLUDE_DIRS}")
target_compile_options(rexbacklight PUBLIC ${RJP_CFLAGS_OTHER})
endif()
install(TARGETS rexbacklight RUNTIME DESTINATION bin)
if(INSTALL_UDEV_BACKLIGHT_RULE)
install(FILES ${CMAKE_SOURCE_DIR}/rules/91-backlight.rules DESTINATION ${UDEV_DIR})

View File

@ -7,9 +7,11 @@ I've also since added a program to control LED devices, rexledctl (best name I c
Either program can be built alone or both together. This is configured using some cmake magic.
Current version is 1.3.1 as of writing this, so if the version is much newer, remind me to update this readme.
Current version is 1.5.2 as of writing this, so if the version is much newer, remind me to update this readme.
```
rexbacklight version v1.5.2
Usage: rexbacklight [argument] [options] [argument]
Options:
@ -25,6 +27,8 @@ Options:
print device names to stdout and exit
--restore|-R
reassign previously saved device values
--no-save|-N
do not write any data to the restore file
--help|-h
print this help message and exit
--version
@ -38,7 +42,7 @@ Arguments:
max
min
rexbacklight Copyright (C) 2018 rexy712
rexbacklight Copyright (C) 2018-2021 rexy712
This program comes with ABSOLUTELY NO WARRANTY.
This is free software, and you are welcome to redistribute it
under certain conditions; see the GNU GPLv3 for details.

View File

@ -1,6 +1,6 @@
/**
rexbacklight
Copyright (C) 2018 rexy712
Copyright (C) 2018-2021 rexy712
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@ -29,6 +29,9 @@
#define OP_VERSION 254
#define OP_USAGE 255
#define ARG_FLAG_NONE 0
#define ARG_FLAG_NO_SAVE 1
struct cmd_arg{
const char* lopt;
const char* sopt;
@ -48,7 +51,11 @@ struct arg_values{
//NULL means all devices
const char* device;
//What value to put in the backlight file
//starting brightness
int act_start;
//value to write in backlight file
int act_delta;
//output percentage
float delta;
//How many seconds to transition
@ -60,6 +67,7 @@ struct arg_values{
int operation;
int num_values;
};
int flags;
};

View File

@ -1,6 +1,6 @@
/**
rexbacklight
Copyright (C) 2018 rexy712
Copyright (C) 2018-2021 rexy712
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by

View File

@ -1,6 +1,6 @@
/**
rexbacklight
Copyright (C) 2018 rexy712
Copyright (C) 2018-2021 rexy712
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@ -22,7 +22,11 @@
#include "version.h"
#ifdef GIT_TAG_NAME
#define REXBACKLIGHT_VERSION GIT_TAG_NAME
#ifdef GIT_DIRTY
#define REXBACKLIGHT_VERSION GIT_TAG_NAME "-dirty"
#else
#define REXBACKLIGHT_VERSION GIT_TAG_NAME
#endif
#else
#define REXBACKLIGHT_VERSION GIT_BRANCH_NAME "-" GIT_COMMIT_HASH
#endif

View File

@ -1,6 +1,6 @@
/**
rexbacklight
Copyright (C) 2018 rexy712
Copyright (C) 2018-2021 rexy712
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by

View File

@ -1,6 +1,6 @@
/**
rexbacklight
Copyright (C) 2018 rexy712
Copyright (C) 2018-2021 rexy712
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@ -24,8 +24,9 @@
#include "common.h"
#include "cmd.h"
void save_restore_file(struct string_array* devices);
int restore_to_delta(struct arg_values* curr, RJP_value** root, int* try_restore);
void save_restore_file(struct string_array* devices, struct arg_values* args);
int restore_to_delta(struct arg_values* curr);
void prep_restore(struct arg_values* a);
RJP_value* find_matching_json_device(const char* name, RJP_value* root);
RJP_value* read_restore_file(const char* file);

View File

@ -1,6 +1,6 @@
/**
rexbacklight
Copyright (C) 2018 rexy712
Copyright (C) 2018-2021 rexy712
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by

View File

@ -6,3 +6,5 @@ output = subprocess.run(['git', 'describe', "--always", "--dirty", "--abbrev", "
if output:
print("#define GIT_COMMIT_HASH " + '"' + output + '"')
if output.find("dirty") != -1:
print("#define GIT_DIRTY")

View File

@ -4,4 +4,7 @@ output="$(git describe --always --dirty --abbrev --match="NeVeRmAtCh")"
if test -n output;then
echo "#define GIT_COMMIT_HASH \"$output\""
if grep -q "dirty" <<< "$output";then
echo "#define GIT_DIRTY"
fi
fi

View File

@ -1,6 +1,6 @@
/**
rexbacklight
Copyright (C) 2018 rexy712
Copyright (C) 2018-2021 rexy712
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@ -58,6 +58,9 @@
#define RESTORE_LONG_OPT "--restore"
#define RESTORE_SHORT_OPT "-R"
#define RESTORE_XBACK_OPT NO_OPT
#define NO_SAVE_LONG_OPT "--no-save"
#define NO_SAVE_SHORT_OPT "-N"
#define NO_SAVE_XBACK_OPT NO_OPT
#define DEVICE_DESC "select which device to control"
#define FADE_DESC "change brightness over time interval"
@ -70,8 +73,9 @@
#define INC_DESC "increase backlight device by specified value"
#define DEC_DESC "decrease backlight device by specified value"
#define RESTORE_DESC "reassign previously saved device values"
#define NO_SAVE_DESC "do not write any data to the restore file"
int strcmp_handle_null(const char* one, const char* two){
static inline int strcmp_handle_null(const char* one, const char* two){
if(!one)
return 1;
if(!two)
@ -79,48 +83,37 @@ int strcmp_handle_null(const char* one, const char* two){
return strcmp(one, two);
}
#define CHECK_SHORT_OPTION(opt, arg) (!strcmp(opt##_SHORT_OPT, arg))
#define CHECK_LONG_OPTION(opt, arg) (!strcmp(opt##_LONG_OPT, arg))
#define CHECK_XBACK_OPTION(opt, arg) (!strcmp(opt##_XBACK_OPT, arg))
#define CHECK_SHORT_OPTION(opt, arg) (!strcmp_handle_null(opt##_SHORT_OPT, arg))
#define CHECK_LONG_OPTION(opt, arg) (!strcmp_handle_null(opt##_LONG_OPT, arg))
#define CHECK_XBACK_OPTION(opt, arg) (!strcmp_handle_null(opt##_XBACK_OPT, arg))
#ifdef XBACKLIGHT_COMPAT_OPTIONS
#define CHECK_OPTION(opt, arg) (!strcmp_handle_null(opt##_LONG_OPT, arg) || !strcmp_handle_null(opt##_SHORT_OPT, arg) || !strcmp_handle_null(opt##_XBACK_OPT, arg))
struct cmd_arg rexbacklight_args[] = {
{DEVICE_LONG_OPT, DEVICE_SHORT_OPT, DEVICE_XBACK_OPT, DEVICE_DESC},
{NO_OPT, NO_OPT, SET_XBACK_OPT, SET_DESC},
{NO_OPT, NO_OPT, INC_XBACK_OPT, INC_DESC},
{NO_OPT, NO_OPT, DEC_XBACK_OPT, DEC_DESC},
{FADE_LONG_OPT, FADE_SHORT_OPT, FADE_XBACK_OPT, FADE_DESC},
{STEPS_LONG_OPT, STEPS_SHORT_OPT, STEPS_XBACK_OPT, STEPS_DESC},
{GET_LONG_OPT, GET_SHORT_OPT, GET_XBACK_OPT, GET_DESC},
{LIST_LONG_OPT, LIST_SHORT_OPT, LIST_XBACK_OPT, LIST_DESC},
#ifdef ENABLE_RESTORE_FILE
{RESTORE_LONG_OPT, RESTORE_SHORT_OPT, RESTORE_XBACK_OPT, RESTORE_DESC},
#endif
{HELP_LONG_OPT, HELP_SHORT_OPT, HELP_XBACK_OPT, HELP_DESC},
{VERSION_LONG_OPT, NO_OPT, VERSION_XBACK_OPT, VERSION_DESC}
};
#define OPTION(x) {x##_LONG_OPT, x##_SHORT_OPT, x##_XBACK_OPT, x##_DESC}
#define CHECK_OPTION(opt, arg) (CHECK_LONG_OPTION(opt, arg) || CHECK_SHORT_OPTION(opt, arg) || CHECK_XBACK_OPTION(opt, arg))
#else //XBACKLIGHT_COMPAT_OPTIONS
#define CHECK_OPTION(opt, arg) (!strcmp_handle_null(opt##_LONG_OPT, arg) || !strcmp_handle_null(opt##_SHORT_OPT, arg))
struct cmd_arg rexbacklight_args[] = {
{DEVICE_LONG_OPT, DEVICE_SHORT_OPT, DEVICE_DESC},
{FADE_LONG_OPT, FADE_SHORT_OPT, FADE_DESC},
{STEPS_LONG_OPT, STEPS_SHORT_OPT, STEPS_DESC},
{GET_LONG_OPT, GET_SHORT_OPT, GET_DESC},
{LIST_LONG_OPT, LIST_SHORT_OPT, LIST_DESC},
#ifdef ENABLE_RESTORE_FILE
{RESTORE_LONG_OPT, RESTORE_SHORT_OPT, RESTORE_DESC},
#endif
{HELP_LONG_OPT, HELP_SHORT_OPT, HELP_DESC},
{VERSION_LONG_OPT, NO_OPT, VERSION_DESC}
};
#define OPTION(x) {x##_LONG_OPT, x##_SHORT_OPT, x##_DESC}
#define CHECK_OPTION(opt, arg) (CHECK_LONG_OPTION(opt, arg) || CHECK_SHORT_OPTION(opt, arg))
#endif //XBACKLIGHT_COMPAT_OPTIONS
int rexbacklight_args_length = sizeof(rexbacklight_args) / sizeof(rexbacklight_args[0]);
struct cmd_arg rexbacklight_args[] = {
OPTION(DEVICE),
OPTION(SET),
OPTION(INC),
OPTION(DEC),
OPTION(FADE),
OPTION(STEPS),
OPTION(GET),
OPTION(LIST),
#ifdef ENABLE_RESTORE_FILE
OPTION(RESTORE),
OPTION(NO_SAVE),
#endif
OPTION(HELP),
OPTION(VERSION)
};
int rexbacklight_args_length = sizeof(rexbacklight_args) / sizeof(rexbacklight_args[0]);
\
//Clean up a cmd_arg struct
void free_cmd_args(struct arg_values* a){
if(!a->next)
@ -147,7 +140,7 @@ void free_cmd_args(struct arg_values* a){
}while(0);
struct arg_values init_arg_values(void){
return (struct arg_values){.next = NULL, .device = NULL, .delta = 0, .fade_duration = 0, .fade_steps = 20, .operation = 0};
return (struct arg_values){.next = NULL, .device = NULL, .delta = 0, .fade_duration = 0, .fade_steps = 20, .operation = 0, .flags = 0};
}
//Convert command line arguments to flags
@ -162,7 +155,7 @@ struct arg_values process_cmd_args(int argc, char** argv){
//Check for switches
if(CHECK_OPTION(GET, argv[i])){
curr->operation |= OP_GET;
curr->operation = OP_GET;
continue;
}else if(CHECK_OPTION(FADE, argv[i])){
@ -203,14 +196,14 @@ struct arg_values process_cmd_args(int argc, char** argv){
}
else if(CHECK_OPTION(LIST, argv[i])){
free_cmd_args(&ret);
ret.operation = OP_LIST;
ret.next = NULL;
return ret;
curr->operation = OP_LIST;
}
#ifdef ENABLE_RESTORE_FILE
else if(CHECK_OPTION(RESTORE, argv[i])){
ret.operation = OP_RESTORE;
curr->operation = OP_RESTORE;
}
else if(CHECK_OPTION(NO_SAVE, argv[i])){
curr->flags |= ARG_FLAG_NO_SAVE;
}
#endif
else if(!strcmp(argv[i], "max")){
@ -302,7 +295,9 @@ struct arg_values process_cmd_args(int argc, char** argv){
curr->operation = ret.operation;
if(!curr->delta)
curr->delta = ret.delta;
}
if(curr->flags == ARG_FLAG_NONE){
curr->flags = ret.flags;
}
}
}
@ -312,6 +307,7 @@ struct arg_values process_cmd_args(int argc, char** argv){
}
#undef CHECK_OPTION
#undef UNRECOGNIZED_OPTION
#undef OPTION
//Process an operation
int process_op(struct arg_values* arg, float min, float current, float max){

View File

@ -1,6 +1,6 @@
/**
rexbacklight
Copyright (C) 2018 rexy712
Copyright (C) 2018-2021 rexy712
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@ -35,6 +35,9 @@ void io_error_2(const char* error, const char* type, const char* name, const cha
void io_error_3(const char* error, const char* type, const char* name, const char* name2, const char* name3){
fprintf(stderr, "Unable to %s %s '%s%s%s'!\n", error, type, name, name2, name3);
}
void mem_error(void){
fprintf(stderr, "Failed to allocate memory! Unable to continue!\n");
}
//Clean up a string array
void free_string_array(struct string_array* s){
@ -44,10 +47,6 @@ void free_string_array(struct string_array* s){
free(s->list);
}
void mem_error(void){
fprintf(stderr, "Failed to allocate memory! Unable to continue!\n");
}
_Noreturn void version(void){
printf("%s version %s\n", executable_name(), REXBACKLIGHT_VERSION);
exit(return_value);
@ -76,11 +75,15 @@ _Noreturn void usage(int exit_val){
if(rexbacklight_args[i].xopt){
if(printed)
printf("|");
else
printed = 1;
printf("%s", rexbacklight_args[i].xopt);
}
#endif //XBACKLIGHT_COMPAT_OPTIONS
printf("\n");
printf(" %s\n", rexbacklight_args[i].desc);
if(printed){
printf("\n");
printf(" %s\n", rexbacklight_args[i].desc);
}
}
printf("\n");
printf("Arguments:\n");
@ -91,7 +94,7 @@ _Noreturn void usage(int exit_val){
printf(" max\n");
printf(" min\n");
printf("\n%s Copyright (C) 2018 rexy712\n", executable_name());
printf("\n%s Copyright (C) 2018-2021 rexy712\n", executable_name());
printf("This program comes with ABSOLUTELY NO WARRANTY.\n");
printf("This is free software, and you are welcome to redistribute it\n");
printf("under certain conditions; see the GNU GPLv3 for details.\n");

View File

@ -1,6 +1,6 @@
/**
rexbacklight
Copyright (C) 2018 rexy712
Copyright (C) 2018-2021 rexy712
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@ -66,7 +66,6 @@ RJP_value* read_restore_file(const char* file){
int i;
FILE* fp = fopen(file, "r");
if(!fp){
fprintf(stderr, "Could not restore! No restore file found!\n");
return NULL;
}
@ -78,14 +77,26 @@ RJP_value* read_restore_file(const char* file){
i = fread(file_contents, filesize, 1, fp);
fclose(fp);
file_contents[filesize] = 0;
RJP_value* root = rjp_parse(file_contents);
RJP_value* root = rjp_parse(file_contents, RJP_PARSE_ALLOW_COMMENTS, NULL);
free(file_contents);
return root;
}
static RJP_value* restore_file_handle(void){
static RJP_value* rf = NULL;
if(!rf){
char* f = restore_file();
rf = read_restore_file(f);
free(f);
}
return rf;
}
RJP_value* find_matching_json_device(const char* name, RJP_value* root){
for(RJP_value* curr = rjp_get_member(root);curr;curr = rjp_next_member(curr)){
if(!strcmp(rjp_member_name(curr), name)){
RJP_object_iterator it;
rjp_init_object_iterator(&it, root);
for(RJP_value* curr = rjp_object_iterator_current(&it);curr;curr = rjp_object_iterator_next(&it)){
if(!strcmp(rjp_member_key(curr)->value, name)){
return curr;
}
}
@ -93,55 +104,58 @@ RJP_value* find_matching_json_device(const char* name, RJP_value* root){
}
//convert a restoration operation to a set operation
int restore_to_delta(struct arg_values* curr, RJP_value** root, int* try_restore){
if(!*root && *try_restore){
char* tmp = restore_file();
*root = read_restore_file(tmp);
free(tmp);
if(!*root){
*try_restore = 0;
return 0;
}
int restore_to_delta(struct arg_values* curr){
RJP_value* root = restore_file_handle();
if(!root){
fprintf(stderr, "Could not restore! No restore file found!\n");
return 0;
}
RJP_value* match = find_matching_json_device(curr->device, *root);
RJP_value* match = find_matching_json_device(curr->device, root);
if(!match){
fprintf(stderr, "No matching device '%s' in restore file!\n", curr->device);
return 0;
}
curr->operation = OP_SET;
curr->delta = rjp_value_dfloat(match);
curr->delta = rjp_get_float(match);
return 1;
}
void prep_restore(struct arg_values* a){
for(struct arg_values* curr = a;curr;curr = curr->next){
restore_to_delta(curr);
}
}
void save_restore_file(struct string_array* devices){
RJP_value* root = rjp_init_json();
for(size_t i = 0;i < devices->size;++i){
if(chdir(devices->list[i])){
io_error_2(IO_ERROR_OPEN, IO_ERROR_DIR, device_dir(), devices->list[i]);
return_value = RETVAL_INVALID_DIR;
continue;
}
size_t esc_name_len = rjp_escape_strlen(devices->list[i]);
char* esc_str = rjp_alloc(esc_name_len + 1);
rjp_escape_strcpy(esc_str, devices->list[i]);
float curr = get_brightness(brightness_file());
float max = get_brightness(max_brightness_file());
if(return_value == RETVAL_INVALID_FILE && (!curr || !max)){
rjp_add_member(root, 0, esc_str, 0, rjp_null());
}else{
rjp_add_member(root, 0, esc_str, 0, rjp_dfloat(curr/max*100));
}
if(chdir(device_dir())){
io_error(IO_ERROR_OPEN, IO_ERROR_DIR, device_dir());
return_value = RETVAL_INVALID_DIR;
rjp_free_value(root);
free(esc_str);
return;
void save_restore_file(struct string_array* devices, struct arg_values* args){
RJP_object_iterator it;
RJP_value* rf = restore_file_handle();
if(!rf)
rf = rjp_new_object();
rjp_init_object_iterator(&it, rf);
for(RJP_value* mem = rjp_object_iterator_current(&it);mem;mem = rjp_object_iterator_next(&it)){
for(struct arg_values* curr = args->next, *prev = args;curr;prev = curr, curr = curr->next){
if(curr->operation != OP_SET || curr->flags & ARG_FLAG_NO_SAVE){
prev->next = curr->next;
free(curr);
curr = prev;
continue;
}
if(!strcmp(rjp_member_key(mem)->value, curr->device)){
rjp_set_float(mem, curr->delta);
prev->next = curr->next;
free(curr);
break;
}
}
}
char* tmp = rjp_to_json(root);
for(struct arg_values* curr = args->next;curr;curr = curr->next){
if(curr->operation == OP_SET){
RJP_value* newmem = rjp_new_member(rf, curr->device, 0);
rjp_set_float(newmem, curr->delta);
}
}
free_cmd_args(args);
char* tmp = rjp_to_json(rf, RJP_FORMAT_NONE);
char* rfil = restore_file();
FILE* restf = fopen(rfil, "w");
if(!restf){
@ -152,7 +166,7 @@ void save_restore_file(struct string_array* devices){
}
free(rfil);
rjp_free(tmp);
rjp_free_value(root);
rjp_free_value(rf);
}

View File

@ -1,6 +1,6 @@
/**
rexbacklight
Copyright (C) 2018 rexy712
Copyright (C) 2018-2021 rexy712
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@ -31,30 +31,47 @@
#include "config.h"
#ifdef ENABLE_RESTORE_FILE
#include <rjp.h>
#include "restore.h"
#endif
/////////////////////////////////////////////////////////////////////////////////////////////
#ifdef REXBACKLIGHT
//This is where backlight devices can be found in sysfs
const char* device_dir(void){return "/sys/class/backlight/";}
//name of the program being run so that we print the correct name in the usage
const char* executable_name(void){return "rexbacklight";}
//location of the restore file in the home directory
const char* restore_file_suffix(void){return "/.config/rexbacklight.json";}
#elif defined(REXLEDCTL)
//This is where led devices can be found in sysfs
const char* device_dir(void){return "/sys/class/leds/";}
const char* executable_name(void){return "rexledctl";}
const char* restore_file_suffix(void){return "/.config/rexledctl.json";}
#else
#error "UNDEFINED PROGRAM NAME!"
#endif
const char* brightness_file(void){return "brightness";}
const char* max_brightness_file(void){return "max_brightness";}
/////////////////////////////////////////////////////////////////////////////////////////////
//create a copy of a string and append a '/' character to the end
char* add_slash_to(const char* name, size_t namelen){
char* newname = malloc(namelen + 2);
memcpy(newname, name, namelen);
newname[namelen++] = '/';
newname[namelen] = 0;
return newname;
}
//Get a list of led/backlight devices in sysfs
struct string_array get_device_sources(void){
DIR* fd;
@ -80,7 +97,7 @@ struct string_array get_device_sources(void){
for(arr.size = 0;(dir = readdir(fd));){
int slen;
//ignore '.' and '..'
if(!strncmp(dir->d_name, ".", 1) || !strncmp(dir->d_name, "..", 2)){
if(!strcmp(dir->d_name, ".") || !strcmp(dir->d_name, "..")){
continue;
}
@ -138,6 +155,7 @@ float get_brightness(const char* file){
fclose(bright);
return atof(buff);
}
//return milliseconds since last boot
double get_time(void){
struct timespec t;
@ -153,23 +171,32 @@ void sleep_for(double time){
nanosleep(&ts, NULL);
}
void return_to_root_dir(void){
if(chdir(device_dir())){
io_error(IO_ERROR_OPEN, IO_ERROR_DIR, device_dir());
return_value = RETVAL_INVALID_DIR;
}
}
//update brightness incrementally over requested millisecond time interval
void fade_out(struct arg_values* arg, int iv, int fv){
void fade_out(struct arg_values* arg){
FILE* fd;
double start, end;
double tdelta = 0; //amount of time that has passed in ms
float value = iv; //current value to write to file
float value = arg->act_start; //current value to write to file
double step_delta = (double)arg->fade_duration / arg->fade_steps;
double step_inc = step_delta;
float brdelta = (float)(fv - iv) / arg->fade_steps; //amount brightness needs to change per iteration
float brdelta = (float)(arg->act_delta - arg->act_start) / arg->fade_steps; //amount brightness needs to change per iteration
while(arg->fade_duration > tdelta){
//write
start = get_time();
fd = fopen(brightness_file(), "w+");
if(!fd){
io_error_3(IO_ERROR_OPEN, IO_ERROR_FILE, device_dir(), arg->device, brightness_file());
char* devname = add_slash_to(arg->device, strlen(arg->device));
io_error_3(IO_ERROR_OPEN, IO_ERROR_FILE, device_dir(), devname, brightness_file());
return_value = RETVAL_INVALID_FILE;
free(devname);
return_to_root_dir();
return;
}
fprintf(fd, "%d", (int)value);
@ -192,122 +219,95 @@ void fade_out(struct arg_values* arg, int iv, int fv){
}
fd = fopen(brightness_file(), "w+");
if(!fd){
io_error_3(IO_ERROR_OPEN, IO_ERROR_FILE, device_dir(), arg->device, brightness_file());
char* devname = add_slash_to(arg->device, strlen(arg->device));
io_error_3(IO_ERROR_OPEN, IO_ERROR_FILE, device_dir(), devname, brightness_file());
return_value = RETVAL_INVALID_FILE;
free(devname);
return_to_root_dir();
return;
}
fprintf(fd, "%d", fv);
fprintf(fd, "%d", arg->act_delta);
fclose(fd);
return_to_root_dir();
}
//Write value to device files
int do_assignment(struct arg_values* args){
for(;args;args = args->next){
if(chdir(args->device)){
io_error_2(IO_ERROR_OPEN, IO_ERROR_DIR, device_dir(), args->device);
return_value = RETVAL_INVALID_DIR;
continue;
}
int start = get_brightness(brightness_file());
int out = process_op(args, 0, start, get_brightness(max_brightness_file()));
fade_out(args, start, out);
if(chdir(device_dir())){
io_error(IO_ERROR_OPEN, IO_ERROR_DIR, device_dir());
return RETVAL_INVALID_DIR;
}
int prep_offset(struct arg_values* args){
if(chdir(args->device)){
io_error_2(IO_ERROR_OPEN, IO_ERROR_DIR, device_dir(), args->device);
return RETVAL_INVALID_DIR;
}
return return_value;
args->act_start = get_brightness(brightness_file());
float act_max = get_brightness(max_brightness_file());
args->act_delta = process_op(args, 0, args->act_start, act_max);
float start_pec = (args->act_start / act_max) * 100.0;
if(args->operation == OP_INC){
args->delta = start_pec + args->delta;
}else if(args->operation == OP_DEC){
args->delta = start_pec - args->delta;
}
if(args->delta > 100)
args->delta = 100;
else if(args->delta < 0)
args->delta = 0;
args->operation = OP_SET;
//chdir back in do_assignment
return 0;
}
//Run get operation
int do_get(struct arg_values* args){
for(;args;args = args->next){
float curr, max;
if(chdir(args->device)){
io_error_2(IO_ERROR_OPEN, IO_ERROR_DIR, device_dir(), args->device);
return_value = RETVAL_INVALID_DIR;
continue;
}
curr = get_brightness(brightness_file());
max = get_brightness(max_brightness_file());
if(return_value == RETVAL_INVALID_FILE && (!curr || !max)){
fprintf(stdout, "%s", args->device);
}else{
fprintf(stdout, "%-25s %.2f\n", args->device, curr / max * 100);
}
if(chdir(device_dir())){
io_error(IO_ERROR_OPEN, IO_ERROR_DIR, device_dir());
return RETVAL_INVALID_DIR;
}
float curr, max;
if(chdir(args->device)){
io_error_2(IO_ERROR_OPEN, IO_ERROR_DIR, device_dir(), args->device);
return RETVAL_INVALID_DIR;
}
curr = get_brightness(brightness_file());
max = get_brightness(max_brightness_file());
if(return_value == RETVAL_INVALID_FILE && (!curr || !max)){
fprintf(stdout, "%s", args->device);
}else{
fprintf(stdout, "%-25s %.2f\n", args->device, curr / max * 100);
}
if(chdir(device_dir())){
io_error(IO_ERROR_OPEN, IO_ERROR_DIR, device_dir());
return RETVAL_INVALID_DIR;
}
return return_value;
}
//Run list operation
void do_list(struct arg_values* args){
for(;args;args = args->next){
printf("%s\n", args->device);
}
}
//move next arg in src list to next arg in dest list
void extract_next_arg(struct arg_values* dest, struct arg_values* src){
dest->next = src->next;
src->next = src->next->next;
dest->next->next = NULL;
printf("%s\n", args->device);
}
//Run requested operation on a per device basis
int run_device_operations(struct arg_values* a){
int changes = 0;
for(a = a->next;a;a = a->next){
switch(a->operation){
case OP_LIST:
do_list(a);
break;
case OP_GET:
return_value = do_get(a);
break;
#ifdef ENABLE_RESTORE_FILE
//convert all restore operations to set operations
void prep_restore(struct arg_values* a){
RJP_value* root = 0;
int try_restore = 1;
for(struct arg_values* curr = a;curr;curr = curr->next){
restore_to_delta(curr, &root, &try_restore);
}
rjp_free_value(root);
}
#else
#define prep_restore(x)
case OP_RESTORE:
if(!restore_to_delta(a)){
continue;
}
#endif
//remove all args in src which have the specified operation and append them to dest
struct arg_values* extract_operation(int operation, struct arg_values* dest, struct arg_values* src){
struct arg_values* curr_dest = dest;
dest->next = NULL;
for(struct arg_values* curr_src = src;curr_src->next;){
if(curr_src->next->operation & operation){
extract_next_arg(curr_dest, curr_src);
curr_dest = curr_dest->next;
}else{
curr_src = curr_src->next;
}
case OP_INC:
case OP_DEC:
case OP_SET:
if(prep_offset(a))
break;
++changes;
fade_out(a);
break;
};
}
return curr_dest;
}
//If devices were specified, this function will run
void run_device_operations(struct arg_values* a){
struct arg_values* curr;
struct arg_values current_op_args = {0};
//list
extract_operation(OP_LIST, &current_op_args, a);
do_list(current_op_args.next);
free_cmd_args(&current_op_args);
//get
extract_operation(OP_GET, &current_op_args, a);
return_value = do_get(current_op_args.next);
free_cmd_args(&current_op_args);
//assignment
curr = extract_operation(OP_RESTORE, &current_op_args, a);
prep_restore(current_op_args.next);
extract_operation(OP_SET | OP_INC | OP_DEC, curr, a);
return_value = do_assignment(current_op_args.next);
free_cmd_args(&current_op_args);
return changes;
}
//If a global operation is requested, run this to fill arg with all devices, each with the global operation
@ -320,6 +320,7 @@ void populate_args(struct arg_values* arg, struct string_array* devices){
curr->next->fade_duration = arg->fade_duration;
curr->next->fade_steps = arg->fade_steps;
curr->next->operation = arg->operation;
curr->next->flags = arg->flags;
curr = curr->next;
}
curr->next = NULL;
@ -331,6 +332,7 @@ int main(int argc, char** argv){
struct arg_values args; //A linked list of devices and the requested settings.
struct string_array device_names; //List of all led/backlight devices in sysfs.
int should_save = 0;
args = process_cmd_args(argc, argv);
if(args.operation == OP_USAGE){
@ -344,7 +346,7 @@ int main(int argc, char** argv){
//If there are no led/backlights, we can't do anything
if(device_names.size == 0){
#ifdef REXBACKLIGHT
fprintf(stderr, "No backlights devices found!\n");
fprintf(stderr, "No backlight devices found!\n");
#elif defined(REXLEDCTL)
fprintf(stderr, "No led devices found!\n");
#endif
@ -375,16 +377,20 @@ int main(int argc, char** argv){
return RETVAL_INVALID_DIR;
}
//Run selected operation
//on a global operation, populate list with all devices
if(!args.next){
populate_args(&args, &device_names);
}
run_device_operations(&args);
should_save = (run_device_operations(&args) > 0);
#ifdef ENABLE_RESTORE_FILE
save_restore_file(&device_names);
if(should_save)
save_restore_file(&device_names, &args); //performs cleanup on args
else
free_cmd_args(&args);
#else
free_cmd_args(&args);
#endif
free_string_array(&device_names);
free_cmd_args(&args);
return return_value;
}