Split into multiple source files

This commit is contained in:
rexy712 2018-01-20 13:56:05 -08:00
parent 8137a8ffa9
commit a3c32e5e7f
6 changed files with 420 additions and 251 deletions

69
include/cmd.h Normal file
View File

@ -0,0 +1,69 @@
/**
rexbacklight
Copyright (C) 2018 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
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef RECBACKLIGHT_CMD_H
#define REXBACKLIGHT_CMD_H
#define OP_SET 4
#define OP_LIST 8
#define OP_GET 128
#define OP_NONE 0
#define GET_LONG_OPT "--get"
#define GET_SHORT_OPT "-g"
#define FADE_LONG_OPT "--fade"
#define FADE_SHORT_OPT "-f"
#define DEVICE_LONG_OPT "--device"
#define DEVICE_SHORT_OPT "-d"
#define LIST_LONG_OPT "--list"
#define LIST_SHORT_OPT "-l"
#define HELP_LONG_OPT "--help"
#define HELP_SHORT_OPT "-h"
struct cmd_arg{
const char* lopt;
const char* sopt;
const char* desc;
};
extern struct cmd_arg rexbacklight_args[];
extern int rexbacklight_args_length;
struct arg_values{
struct arg_values* next;
//Specific device to control
//NULL means all devices
const char* device;
//What value to put in the backlight file
char* delta;
//How many seconds to transition
int fade_duration;
unsigned char operation;
};
void free_cmd_args(struct arg_values* a);
struct arg_values process_cmd_args(int argc, char** argv);
int process_op(char* arg, float min, float current, float max);
#endif

34
include/common.h Normal file
View File

@ -0,0 +1,34 @@
/**
rexbacklight
Copyright (C) 2018 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
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <stdlib.h>
#ifndef REXBACKLIGHT_COMMON_H
#define REXBACKLIGHT_COMMON_H
#define RETVAL_INVALID_FILE 1
#define RETVAL_INVALID_DIR 2
#define RETVAL_UNRECOGNIZED_OPTION 3
#define RETVAL_MISSING_OPTION 4
#define RETVAL_INVALID_DEVICE -5
#define RETVAL_SUCCESS EXIT_SUCCESS
_Noreturn void usage(int exit_val);
#endif

View File

@ -1,25 +1,72 @@
.PHONY: all
all: rexbacklight
#Copyright 2018 rexy712 of Rexy & Co
#Makefile for project 'rexbacklight'
rexbacklight: src/rexbacklight.c
gcc -std=c11 -g -Wall -Wextra -pedantic src/rexbacklight.c -o rexbacklight
#Project directory and file setup
SOURCE_DIRS:=src
OBJDIR:=obj
DEPDIR:=obj/dep
INCLUDE_DIRS:=include
EXT:=c
MAIN_EXECUTABLE:=rexbacklight
#Compiler/Linker setup
CC:=gcc
CFLAGS:=-g -std=c11 -Wall -pedantic -Wextra
release: CFLAGS:=-std=c11 -Wall -pedantic -Wextra -O2
LDFLAGS=
LDLIBS:=
STRIP:=strip
#Windows workarounds
ifeq ($(OS),Windows_NT)
mkdir=mkdir $(subst /,\,$(1)) > NUL 2>&1
rm=del /F $(1) > NUL 2>&1
rmdir=rd /s /q $(1) > NUL 2>&1
move=move /y $(subst /,\,$(1)) $(subst /,\,$(2)) > NUL 2>&1
MAIN_EXECUTABLE:=$(MAIN_EXECUTABLE).exe
LDLIBS:=
else
mkdir=mkdir -p $(1)
rm=rm -f $(1)
rmdir=rm -rf $(1)
move=mv $(1) $(2)
endif
#Internal management of sources/objects and additional cflags
INTERNAL_CFLAGS=-c $(foreach dir,$(INCLUDE_DIRS),-I"$(dir)") -MMD -MP -MF"$(DEPDIR)/$*.d"
SOURCES:=$(foreach source,$(SOURCE_DIRS),$(foreach ext,$(EXT),$(wildcard $(source)/*.$(ext))))
OBJECTS:=$(addprefix $(OBJDIR)/,$(subst \,.,$(subst /,.,$(addsuffix .o,$(SOURCES)))))
all: $(MAIN_EXECUTABLE)
$(MAIN_EXECUTABLE): $(OBJECTS)
$(CC) $(LDFLAGS) $^ -o "$(basename $@)" $(LDLIBS)
.PHONY: release
release: src/rexbacklight.c
gcc -std=c11 -O2 -Wall -Wextra -pedantic src/rexbacklight.c -o rexbacklight
strip --strip-all rexbacklight
release: $(OBJECTS)
$(CC) $(LDFLAGS) $^ -o "$(basename $(MAIN_EXECUTABLE))" $(LDLIBS)
$(STRIP) --strip-all "$(MAIN_EXECUTABLE)"
.PHONY: install
install: rexbacklight
install -m755 -o root -g root -s rexbacklight /usr/bin/rexbacklight
install -m600 -o root -g root rules/91-backlight.rules /etc/udev/rules.d/91-backlight.rules
install -m755 -o root -g root rules/backlight /etc/init.d/backlight
define GENERATE_OBJECTS
$$(OBJDIR)/$(subst \,.,$(subst /,.,$(1))).%.o: $(1)/%
$$(CC) $$(CFLAGS) $$(INTERNAL_CFLAGS) "$$<" -o "$$@"
endef
$(foreach dir,$(SOURCE_DIRS),$(eval $(call GENERATE_OBJECTS,$(dir))))
$(OBJECTS): | $(OBJDIR) $(DEPDIR)
$(OBJDIR):
$(call mkdir,"$@")
$(DEPDIR):
$(call mkdir,"$@")
.PHONY: uninstall
uninstall:
rm /usr/bin/rexbacklight
rm /etc/udev/rules.d/91-backlight.rules
rm /etc/init.d/backlight
.PHONY: clean
clean:
rm rexbacklight
$(call rmdir,"$(DEPDIR)")
$(call rmdir,"$(OBJDIR)")
$(call rm,"$(MAIN_EXECUTABLE)")
-include $(wildcard $(DEPDIR)/*.d)

196
src/cmd.c Normal file
View File

@ -0,0 +1,196 @@
/**
rexbacklight
Copyright (C) 2018 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
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "cmd.h"
#include "common.h"
#define CHECK_OPTION(opt, arg) (!strcmp(opt##_LONG_OPT, arg) || !strcmp(opt##_SHORT_OPT, arg))
struct cmd_arg rexbacklight_args[] = {
{DEVICE_LONG_OPT, DEVICE_SHORT_OPT, "select which device to control"},
{FADE_LONG_OPT, FADE_SHORT_OPT, "TODO: change brightness over time interval"},
{GET_LONG_OPT, GET_SHORT_OPT, "TODO: print current brightness level to stdout"},
{LIST_LONG_OPT, LIST_SHORT_OPT, "TODO: print device names to stdout and exit"},
{HELP_LONG_OPT, HELP_SHORT_OPT, "print this help message and exit"}
};
int rexbacklight_args_length = sizeof(rexbacklight_args) / sizeof(rexbacklight_args[0]);
void free_cmd_args(struct arg_values* a){
if(!a->next)
return;
free_cmd_args(a->next);
free(a->next);
}
#define CHECK_NEXT_ARG(rval) \
do{ \
if(i == argc - 1){ \
fprintf(stderr, "Missing argument to '%s'\n\n", argv[i]); \
free_cmd_args(&ret); \
usage(rval); \
} \
}while(0)
#define UNRECOGNIZED_OPTION(rval) \
do{ \
fprintf(stderr, "Unrecognized command line option '%s'\n\n", argv[i]); \
free_cmd_args(&ret); \
usage(rval); \
}while(0);
//Convert command line arguments to flags
struct arg_values process_cmd_args(int argc, char** argv){
struct arg_values ret = {0};
struct arg_values* curr = &ret;
//Skip argv[0]
for(int i = 1;i < argc;i++){
//Check for switches
if(CHECK_OPTION(GET, argv[i])){
curr->operation |= OP_GET;
continue;
}else if(CHECK_OPTION(FADE, argv[i])){
CHECK_NEXT_ARG(-5);
curr->fade_duration = strtol(argv[++i], NULL, 0);
continue;
}
else if(CHECK_OPTION(DEVICE, argv[i])){
CHECK_NEXT_ARG(-5);
curr->next = calloc(1, sizeof(struct arg_values));
curr = curr->next;
curr->device = argv[++i];
continue;
}
else if(CHECK_OPTION(LIST, argv[i])){
free_cmd_args(&ret);
ret.operation = OP_LIST;
ret.next = NULL;
return ret;
}
else if(CHECK_OPTION(HELP, argv[i])){
free_cmd_args(&ret);
usage(RETVAL_SUCCESS);
}
else if(!strcmp(argv[i], "max")){
curr->operation = OP_SET;
curr->delta = argv[i];
}
else if(!strcmp(argv[i], "min")){
curr->operation = OP_SET;
curr->delta = argv[i];
}
else if(!strcmp(argv[i], "off")){
curr->operation = OP_SET;
curr->delta = argv[i];
}
//If we get a '-' followed by not a number, it's not a known option
else if(argv[i][1] < '0' || argv[i][1] > '9'){
UNRECOGNIZED_OPTION(RETVAL_UNRECOGNIZED_OPTION);
}
//If we get a '-' followed by a number, it's a decrement request
else{
curr->operation = OP_SET;
curr->delta = argv[i];
}
}
//If there isn't an operation defined in the global context and there is no specified device, there's nothing to do
if(!ret.operation){
if(!ret.next){
fprintf(stderr, "No operation requested!\n\n");
usage(RETVAL_MISSING_OPTION);
}
//if there is a device specified, make sure each one has a requested operation
for(curr = ret.next;curr;curr = curr->next){
if(!curr->operation){
fprintf(stderr, "No operation requested for device '%s'!\n\n", curr->device);
free_cmd_args(&ret);
usage(RETVAL_MISSING_OPTION);
}
}
//If there is a globally defined operation, apply it to the devices with no operation request
}else{
for(curr = ret.next;curr;curr = curr->next){
if(curr->operation == OP_NONE){
curr->operation = ret.operation;
if(!curr->delta)
curr->delta = ret.delta;
}
}
}
return ret;
}
#undef CHECK_OPTION
#undef UNRECOGNIZED_OPTION
//Process an operation
int process_op(char* arg, float min, float current, float max){
//Amount to inc/dec
int delta = delta = max * atof(arg + 1) / 100.0;
//Increment
if(arg[0] == '+'){
delta = delta + current;
if(delta >= max)
return max;
else{
return delta;
}
//Decrement
}else if(arg[0] == '-'){
delta = current - delta;
if(delta <= min)
return min;
else
return delta;
//Directly set
}else if(arg[0] == '='){
if(delta >= max)
return max;
else if(delta <= min)
return min;
else
return delta;
//Set to minimum plus one (so backlight is actually on!)
}else if(!strcmp("min", arg)){
return min + 1;
//Turn off backlight
}else if(!strcmp("off", arg)){
return min;
//Set to maximum
}else if(!strcmp("max", arg)){
return max;
}
return current;
}

50
src/common.c Normal file
View File

@ -0,0 +1,50 @@
/**
rexbacklight
Copyright (C) 2018 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
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "common.h"
#include "cmd.h"
#include <stdio.h>
_Noreturn void usage(int exit_val){
fprintf(stderr, "Usage: rexbacklight [argument] [options] [argument]\n\n");
fprintf(stderr, "Options:\n");
for(int i = 0;i < rexbacklight_args_length;i++){
fprintf(stderr, " %s|%s\n", rexbacklight_args[i].lopt, rexbacklight_args[i].sopt);
fprintf(stderr, " %s\n", rexbacklight_args[i].desc);
}
fprintf(stderr, "\n");
fprintf(stderr, "Arguments:\n");
fprintf(stderr, " =<percentage>\n");
fprintf(stderr, " -<percentage>\n");
fprintf(stderr, " +<percentage>\n");
fprintf(stderr, " off\n");
fprintf(stderr, " max\n");
fprintf(stderr, " min\n");
if(exit_val == RETVAL_SUCCESS){
fprintf(stderr, "\nrexbacklight Copyright (C) 2018 rexy712\n");
fprintf(stderr, "This program comes with ABSOLUTELY NO WARRANTY.\n");
fprintf(stderr, "This is free software, and you are welcome to redistribute it\n");
fprintf(stderr, "under certain conditions; see the GNU GPLv3 for details.\n");
fprintf(stderr, "A copy of the GPLv3 is available with the source in the file 'LICENSE'\n");
}
exit(exit_val);
}

View File

@ -19,247 +19,20 @@
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <dirent.h>
#include <errno.h>
#define OP_SET 4
#define OP_GET 128
#define OP_NONE 0
#define GET_LONG_OPT "--get"
#define GET_SHORT_OPT "-g"
#define FADE_LONG_OPT "--fade"
#define FADE_SHORT_OPT "-f"
#define DEVICE_LONG_OPT "--device"
#define DEVICE_SHORT_OPT "-d"
#define HELP_LONG_OPT "--help"
#define HELP_SHORT_OPT "-h"
#define CHECK_OPTION(opt, arg) (!strcmp(opt##_LONG_OPT, arg) || !strcmp(opt##_SHORT_OPT, arg))
#define RETVAL_INVALID_FILE -1
#define RETVAL_INVALID_DIR -2
#define RETVAL_UNRECOGNIZED_OPTION -3
#define RETVAL_MISSING_OPTION -4
#define RETVAL_INVALID_DEVICE -5
#define RETVAL_SUCCESS EXIT_SUCCESS
struct string_array{
char** list;
int size;
};
struct arg_values{
struct arg_values* next;
//Specific device to control
//NULL means all devices
const char* device;
//What value to put in the backlight file
char* delta;
//How many seconds to transition
int fade_duration;
unsigned char operation;
};
#include "common.h"
#include "cmd.h"
//This is where backlight devices can be found in sysfs
static const char* backlight_dir = "/sys/class/backlight/";
static const char* backlight_file = "brightness";
static const char* max_backlight_file = "max_brightness";
//Print out usage message and GPL message if not caused by an error
_Noreturn void usage(int exit_val){
fprintf(stderr, "Usage: rexbacklight [argument] [options] [argument]\n\n");
fprintf(stderr, "Options:\n");
fprintf(stderr, " %s|%s\n", DEVICE_SHORT_OPT, DEVICE_LONG_OPT);
fprintf(stderr, " select which device to control\n");
fprintf(stderr, " %s|%s\n", FADE_SHORT_OPT, FADE_LONG_OPT);
fprintf(stderr, " TODO: change brightness over time interval\n");
fprintf(stderr, " %s|%s\n", GET_SHORT_OPT, GET_LONG_OPT);
fprintf(stderr, " TODO: print the current brightness level to stdout\n");
fprintf(stderr, " %s|%s\n", HELP_SHORT_OPT, HELP_LONG_OPT);
fprintf(stderr, " print this help message and exit\n");
fprintf(stderr, "\n");
fprintf(stderr, "Arguments:\n");
fprintf(stderr, " =<percentage>\n");
fprintf(stderr, " -<percentage>\n");
fprintf(stderr, " +<percentage>\n");
fprintf(stderr, " off\n");
fprintf(stderr, " max\n");
fprintf(stderr, " min\n");
if(exit_val == RETVAL_SUCCESS){
fprintf(stderr, "\nrexbacklight Copyright (C) 2018 rexy712\n");
fprintf(stderr, "This program comes with ABSOLUTELY NO WARRANTY.\n");
fprintf(stderr, "This is free software, and you are welcome to redistribute it\n");
fprintf(stderr, "under certain conditions; see the GNU GPLv3 for details.\n");
fprintf(stderr, "A copy of the GPLv3 is available with the source in the file 'LICENSE'\n");
}
exit(exit_val);
}
void free_cmd_args(struct arg_values* a){
if(!a->next)
return;
free_cmd_args(a->next);
free(a->next);
}
#define CHECK_NEXT_ARG(rval) \
do{ \
if(i == argc - 1){ \
fprintf(stderr, "Missing argument to '%s'\n\n", argv[i]); \
free_cmd_args(&ret); \
usage(rval); \
} \
}while(0)
#define UNRECOGNIZED_OPTION(rval) \
do{ \
fprintf(stderr, "Unrecognized command line option '%s'\n\n", argv[i]); \
free_cmd_args(&ret); \
usage(rval); \
}while(0);
//Convert command line arguments to flags
struct arg_values process_cmd_args(int argc, char** argv){
struct arg_values ret = {0};
struct arg_values* curr = &ret;
//Skip argv[0]
for(int i = 1;i < argc;i++){
//Check for switches
if(CHECK_OPTION(GET, argv[i])){
curr->operation |= OP_GET;
continue;
}else if(CHECK_OPTION(FADE, argv[i])){
CHECK_NEXT_ARG(-5);
curr->fade_duration = strtol(argv[++i], NULL, 0);
continue;
}
else if(CHECK_OPTION(DEVICE, argv[i])){
CHECK_NEXT_ARG(-5);
curr->next = calloc(1, sizeof(struct arg_values));
curr = curr->next;
curr->device = argv[++i];
continue;
}
else if(CHECK_OPTION(HELP, argv[i])){
free_cmd_args(&ret);
usage(RETVAL_SUCCESS);
}
else if(!strcmp(argv[i], "max")){
curr->operation = OP_SET;
curr->delta = argv[i];
}
else if(!strcmp(argv[i], "min")){
curr->operation = OP_SET;
curr->delta = argv[i];
}
else if(!strcmp(argv[i], "off")){
curr->operation = OP_SET;
curr->delta = argv[i];
}
//If we get a '-' followed by not a number, it's not a known option
else if(argv[i][1] < '0' || argv[i][1] > '9'){
UNRECOGNIZED_OPTION(RETVAL_UNRECOGNIZED_OPTION);
}
//If we get a '-' followed by a number, it's a decrement request
else{
curr->operation = OP_SET;
curr->delta = argv[i];
}
}
//If there isn't an operation defined in the global context and there is no specified device, there's nothing to do
if(!ret.operation){
if(!ret.next){
fprintf(stderr, "No operation requested!\n\n");
usage(RETVAL_MISSING_OPTION);
}
//if there is a device specified, make sure each one has a requested operation
for(curr = ret.next;curr;curr = curr->next){
if(!curr->operation){
fprintf(stderr, "No operation requested for device '%s'!\n\n", curr->device);
free_cmd_args(&ret);
usage(RETVAL_MISSING_OPTION);
}
}
//If there is a globally defined operation, apply it to the devices with no operation request
}else{
for(curr = ret.next;curr;curr = curr->next){
if(curr->operation == OP_NONE){
curr->operation = ret.operation;
if(!curr->delta)
curr->delta = ret.delta;
}
}
}
return ret;
}
#undef CHECK_OPTION
#undef UNRECOGNIZED_OPTION
//Process an operation
int process_op(char* arg, float min, float current, float max){
//Amount to inc/dec
int delta = delta = max * atof(arg + 1) / 100.0;
//Increment
if(arg[0] == '+'){
delta = delta + current;
if(delta >= max)
return max;
else{
return delta;
}
//Decrement
}else if(arg[0] == '-'){
delta = current - delta;
if(delta <= min)
return min;
else
return delta;
//Directly set
}else if(arg[0] == '='){
if(delta >= max)
return max;
else if(delta <= min)
return min;
else
return delta;
//Set to minimum plus one (so backlight is actually on!)
}else if(!strcmp("min", arg)){
return min + 1;
//Turn off backlight
}else if(!strcmp("off", arg)){
return min;
//Set to maximum
}else if(!strcmp("max", arg)){
return max;
}
return current;
}
struct string_array{
char** list;
int size;
};
//Delete the list of backlight devices
void free_string_array(struct string_array* s){