Compare commits

..

No commits in common. "master" and "logger" have entirely different histories.

6 changed files with 59 additions and 343 deletions

7
.gitignore vendored
View File

@ -1,7 +0,0 @@
# Generated directories
build/
objects/
# Autosave files
*~
*#

View File

@ -1,17 +1,9 @@
#NEWPROJECT requires refactor.sh main.c
# Taken from https://stackoverflow.com/questions/30573481/how-to-write-a-makefile-with-separate-source-and-header-directories
# Always build targets and unit tests together. This avoids the scenario wherein the targets are built, then the source files are edited, then the unit tests are built and, accidentally, outdated targets are packaged and shipped. I say this knowing full well that I never ship my targets to anyone ever.
MAKEFILE_VERSION := Makefile from battery log v1.0
PREFIX :=
SUFFIX :=
SRCDIR := sources
MAINDIR := $(SRCDIR)/main
INCDIR := $(abspath $(SRCDIR)/include)
INCDIR := include
OBJDIR := objects
MAINOD := $(OBJDIR)/main
BINDIR := build
@ -20,57 +12,34 @@ INSTDIR := /usr/local/bin
REFACTOR := refactor.h
TESTCFLAGS:= $(shell pkg-config --cflags criterion)
TESTLIBS := $(shell pkg-config --libs criterion)
TESTDIR := $(SRCDIR)/test
TESTOD := $(OBJDIR)/test
HEADERS := $(wildcard $(INCDIR)/*.h)
MAINS := $(wildcard $(MAINDIR)/*.c)
MAINOBJS := $(patsubst $(MAINDIR)/%.c, $(MAINOD)/%.o, $(MAINS))
TESTS := $(wildcard $(TESTDIR)/*.c)
TESTOBJS := $(patsubst $(TESTDIR)/%.c, $(TESTOD)/%.o, $(TESTS))
UNITTESTS := $(patsubst $(TESTDIR)/%.c, $(BINDIR)/%, $(TESTS))
TARGETS := $(patsubst $(MAINDIR)/%.c, $(BINDIR)/%, $(MAINS))
SOURCES := $(wildcard $(SRCDIR)/*.c)
OBJECTS := $(patsubst $(SRCDIR)/%.c, $(OBJDIR)/%.o, $(SOURCES))
CPPFLAGS := -I$(INCDIR) -MMD -MP -DUSE_LIBNOTIFY
CFLAGS := -Wall -Werror -Wpedantic $(shell pkg-config --cflags libnotify) -g
CPPFLAGS := -Iinclude -MMD -MP
CFLAGS := -Wall -Werror -Wpedantic
LDFLAGS := #-Lmath or whatever
LDLIBS := $(shell pkg-config --libs libnotify) #-lm or whatever
LDLIBS := #-lm or whatever
define MANGLE =
$(dir $(1))$(PREFIX)$(notdir $(1))$(SUFFIX)
endef
.PHONY: all clean
.PHONY: all clean version
all: | $(TARGETS) $(UNITTESTS)
version:
@echo $(MAKEFILE_VERSION)
all: $(TARGETS)
@echo $(TARGETS)
refactor:
./refactor.sh
$(UNITTESTS): $(OBJECTS) $(TESTOBJS) | $(BINDIR) $(OBJDIR) $(TESTOD)
@echo "Linking unit tests..."
$(CC) $(LDFLAGS) $(OBJECTS) $(patsubst $(BINDIR)/%, $(TESTOD)/%.o, $@) $(LDLIBS) $(TESTLIBS) -o $(dir $@)$(PREFIX)$(notdir $@)$(SUFFIX)
@echo "...Done linking unit tests"
$(TARGETS): $(OBJECTS) $(MAINOBJS) | $(BINDIR) $(OBJDIR) $(MAINOD)
@echo "Linking targets..."
$(CC) $(LDFLAGS) $(OBJECTS) $(patsubst $(BINDIR)/%, $(MAINOD)/%.o, $@) $(LDLIBS) -o $(dir $@)$(PREFIX)$(notdir $@)$(SUFFIX)
@echo "...Done linking targets"
$(CC) $(LDFLAGS) $(OBJECTS) $(patsubst $(BINDIR)/%, $(MAINOD)/%.o, $@) $(LDLIBS) -o $@
$(BINDIR) $(OBJDIR) $(MAINOD) $(TESTOD):
$(BINDIR) $(OBJDIR) $(MAINOD):
mkdir --parents $@
$(OBJDIR)/%.o: $(SRCDIR)/%.c $(HEADERS) | $(OBJDIR)
@ -79,9 +48,6 @@ $(OBJDIR)/%.o: $(SRCDIR)/%.c $(HEADERS) | $(OBJDIR)
$(MAINOD)/%.o: $(MAINDIR)/%.c $(HEADERS) | $(MAINOD)
$(CC) $(CPPFLAGS) $(CFLAGS) -c $< -o $@
$(TESTOD)/%.o: $(TESTDIR)/%.c $(HEADERS) | $(TESTOD)
$(CC) $(CPPFLAGS) $(CFLAGS) $(TESTCFLAGS) $(TESTLIBS) -c $< -o $@
# $| evaluates to the order-only prerequisites, in this case: $(TARGETS)
# The $(foreach ...) function will evaluate to a semicolon-separated list of 'cp <target> $instdir'
# Putting this $(foreach ...) into the recipe means that its result
@ -93,35 +59,15 @@ $(TESTOD)/%.o: $(TESTDIR)/%.c $(HEADERS) | $(TESTOD)
install: | $(TARGETS)
@echo "Installing executables to $(INSTDIR)"
@$(foreach target, $|, cp -v $(call MANGLE, $(target)) $(INSTDIR);)
@$(foreach target, $|, cp -v $(target) $(INSTDIR);)
uninstall: | $(TARGETS)
@echo "Removing executables from $(INSTDIR)"
$(foreach target, $(notdir $(call MANGLE, $|)), rm -v $(INSTDIR)/$(target);)
$(foreach target, $(notdir $|), rm -v $(INSTDIR)/$(target);)
clean:
$(RM) -rv $(BINDIR) $(OBJDIR)
# Lazy kludge to run the first executable specified in $(TARGETS)
# Could also be accomplished by running $< but this is easier to read
run: all
$(eval MANGLEDNAME=$(call MANGLE, $(word 1,$(TARGETS))))
@echo "Running " $(MANGLEDNAME)
@$(MANGLEDNAME)
# @$(dir $(word 1,$(TARGETS)))$(PREFIX)$(notdir $(word 1,$(TARGETS)))$(SUFFIX)
# unit testing!
test: $(TARGETS) $(UNITTESTS)
@echo "Testing " $(word 1,$(UNITTESTS))
@$(dir $(word 1,$(UNITTESTS)))$(PREFIX)$(notdir $(word 1,$(UNITTESTS)))$(SUFFIX)
.PHONY: variable
variable: all
$(eval mangle2=$(dir $(word 1,$(UNITTESTS)))$(PREFIX)$(notdir $(word 1,$(UNITTESTS)))$(SUFFIX))
$(eval mangle3=$(call MANGLE, $(UNITTESTS)))
@echo "variable declared within a recipe: "$(mangle2)
@echo "variable declared within a recipe using a canned recipe: "$(mangle3)
# Honestly still not sure what this directive does.
# It's an include directive, which processes all .d files that correspond to members of $(OBJ),
# with the hyphen in front meaning that it suppresses/ignores errors (from nonexistent .d files)

View File

@ -1 +0,0 @@
#define A 4

View File

@ -1,30 +0,0 @@
/**
* Main.h: contains definitions for battery.c
*/
#define DEFAULT_LOG_INTERVAL 15
#define DEFAULT_LOG_INTERVAL_STRING "15"
#define BAT_PATH "/sys/class/power_supply/BAT1/"
#define CHARGE_NOW_PATH "charge_now"
#define CHARGE_FULL_PATH "charge_full"
#define ENERGY_NOW_PATH "energy_now"
#define ENERGY_FULL_PATH "energy_full"
#define VERSION "v0.2"
#define TITLE "Battery Percentage, by Catluck Kettlemerry"
#define PROGNAME "battery"
#define USAGE0 "Usage:"
#define USAGE1 "[OPTION...]"
#define OPTIONS0 "Options:"
#define OPTIONS1 "\t-v run verbosely"
#define OPTIONS2 "\t-h show help and exit"
#define OPTIONS3 "\t-t provide terse output"
#define OPTIONS4 "\t-l Continuously log battery level every " DEFAULT_LOG_INTERVAL_STRING " seconds"
#define OPTIONS5 "\t-i <n> Set log interval to poll every <n> seconds"
#define OPTIONS6 "\t (This argument automatically activates continuous logging)"
#define OPTIONS7 "\t-u (If the interval is less than 15 seconds, " PROGNAME " will refuse to run."
#define OPTIONS8 "\t Specify -u to run anyway.)"
#define OPTIONS9 "\t-w <n> Warn the user if the battery charge drops below <n> percent"
#define OPTIONS10 "\t-p Print the effects of the given options for this invocation"
#define MESGLEN 25

View File

@ -1,131 +1,32 @@
#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
#include <unistd.h>
#ifdef USE_SYSLOG
#include <syslog.h>
#endif
#include "main.h"
#ifdef USE_LIBNOTIFY
#include <libnotify/notify.h>
#endif
#define CHARGE_NOW_PATH "/sys/class/power_supply/BAT0/charge_now"
#define CHARGE_FULL_PATH "/sys/class/power_supply/BAT0/charge_full"
#define VERSION "v0.0"
#define TITLE "Battery Percentage, by Catluck Kettlemerry"
#define PROGNAME "battery_percentage"
#define USAGE0 "Usage: "
#define USAGE1 "[option]"
#define OPTIONS0 "Options:"
#define OPTIONS1 "\t-v run verbosely"
#define OPTIONS2 "\t-h show help and exit"
#define OPTIONS3 "\t-t provide terse output"
int run_verbose = 0;
int run_terse = 0;
int run_continuously = 0;
int interval = DEFAULT_LOG_INTERVAL;
int run_unsafe = 0;
int force_print_parameters = 0;
int warn_level = 10;
int warned = 0; /* Set if already warned */
const char * delimiter = "\n";
void print_help(void){
printf("%s %s\n", TITLE, VERSION);
printf("%s %s %s\n", USAGE0, PROGNAME, USAGE1);
printf("%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n",
OPTIONS0, OPTIONS1, OPTIONS2, OPTIONS3, OPTIONS4,
OPTIONS5, OPTIONS6, OPTIONS7, OPTIONS8, OPTIONS9,
OPTIONS10);
}
int get_fds(FILE ** fd_now, FILE ** fd_full, const char * bat_path, const char * unit_now, const char * unit_full)
{
size_t bat_path_len = strlen(bat_path);
size_t unit_now_len = strlen(unit_now);
size_t unit_full_len = strlen(unit_full);
char * now_path = (char*)malloc(bat_path_len + unit_now_len + 1);
char * full_path = (char*)malloc(bat_path_len + unit_full_len + 1);
strncpy(now_path, bat_path, bat_path_len + 1);
strncpy(full_path, bat_path, bat_path_len + 1);
strncat(now_path, unit_now, unit_now_len);
strncat(full_path, unit_full, unit_full_len);
printf("Attempting to open:\n\t%s\n\t%s\n", now_path, full_path);
(*fd_now) = fopen(now_path, "r");
if(*fd_now == NULL){
perror("Error opening file for current charge level");
// if exiting here, no need to close fd_now because it is null
return 1;
}
(*fd_full) = fopen(full_path, "r");
if(*fd_full == NULL){
perror("Error opening file for maximum charge level");
// it just makes me feel safer, but this should be redundant
if((*fd_now) != NULL){
fclose(*fd_now);
}
return 1;
}
printf("Successfully found files at %p and %p\n", (void*)fd_now, (void*)fd_full);
return 0;
}
int get_percentage
(FILE * fd_now, FILE * fd_full, double * c_now, double * c_full, double * frac, int *pct)
{
int vals_read = fscanf(fd_now, "%lf", c_now);
if(vals_read != 1){
if(errno != 0){
perror("Error reading full battery charge: ");
} else if(vals_read == EOF){
printf("End-of-file reached while reading current battery charge(?)");
} else {
printf("Invalid number of arguments (%d) returned while reading full battery charge", vals_read);
}
return 1;
}
vals_read = fscanf(fd_full, "%lf", c_full);
if(vals_read != 1){
if(errno != 0){
perror("Error reading full battery charge: ");
} else if(vals_read == EOF){
printf("End-of-file reached while reading full battery charge(?)");
} else {
printf("Invalid number of arguments (%d) returned while reading full battery charge", vals_read);
}
return 1;
}
(*frac) = *c_now / *c_full;
(*pct) = (int)((*frac) * 100);
return 0;
}
void warn(int pct){
if(!warned){
printf("Battery Low\n");
#ifdef USE_SYSLOG
syslog(LOG_WARNING, "Battery Low");
#endif
#ifdef USE_LIBNOTIFY
char warnmesg[MESGLEN];
snprintf(warnmesg, MESGLEN, "Battery is at %d percent", pct);
notify_init(PROGNAME);
NotifyNotification * levelwarn = notify_notification_new("Battery Low", warnmesg, "dialog-information");
notify_notification_show(levelwarn, NULL);
g_object_unref(G_OBJECT(levelwarn));
notify_uninit();
#endif
}
warned = 1;
printf("%s\n%s\n%s\n%s\n", OPTIONS0, OPTIONS1, OPTIONS2, OPTIONS3);
}
int main(int argc, char *const argv[]){
int opt;
while((opt = getopt(argc, argv, "vhtli:uw:p")) != -1) {
while((opt = getopt(argc, argv, "vht")) != -1) {
switch(opt){
case 'v':
run_verbose = 1;
@ -136,129 +37,50 @@ int main(int argc, char *const argv[]){
case 't':
run_terse = 1;
break;
case 'l':
run_continuously = 1;
break;
case 'i':
interval = atoi(optarg);
run_continuously = 1;
break;
case 'u':
run_unsafe = 1;
break;
case 'w':
warn_level = atoi(optarg);
break;
case 'p':
force_print_parameters = 1;
break;
default:
printf("Literally how could you pass an unspecified argument to this program");
}
}
/**
Print run parameters at startup
*/
if(force_print_parameters) {
if(run_terse && run_verbose){
printf(PROGNAME " called with arguments to run both tersely and verbosely, the author legitimately cannot tell what you want her to do\n");
} else if(run_terse) {
printf(PROGNAME " will run tersely\n");
} else if(run_verbose) {
printf(PROGNAME " will run verbosely\n");
}
printf(PROGNAME " will poll every %d seconds\n", interval);
if(!run_terse){
printf(PROGNAME " will warn at %d%% battery\n", warn_level);
}
}
if(warn_level <= 0 && !run_terse){
fprintf(stderr, "Warn level set to %d. " PROGNAME " will not send warning on low battery.\n", warn_level);
}
FILE * fd_now = fopen(CHARGE_NOW_PATH, "r");
FILE * fd_full = fopen(CHARGE_FULL_PATH, "r");
if(interval < 15 && !run_unsafe){
fprintf(stderr, "Update interval less than 15 seconds, refusing to run. Specify -u to override this check.\n");
int c_now;
int c_full;
int vals_read = fscanf(fd_now, "%d", &c_now);
if(vals_read != 1){
if(errno != 0){
perror("Error reading full battery charge: ");
} else if(vals_read == EOF){
printf("End-of-file reached while reading current battery charge(?)");
} else {
printf("Invalid number of arguments (%d) returned while reading full battery charge", vals_read);
}
return 1;
}
vals_read = fscanf(fd_full, "%d", &c_full);
if(vals_read != 1){
if(errno != 0){
perror("Error reading full battery charge: ");
} else if(vals_read == EOF){
printf("End-of-file reached while reading full battery charge(?)");
} else {
printf("Invalid number of arguments (%d) returned while reading full battery charge", vals_read);
}
return 1;
}
#ifdef USE_SYSLOG
openlog(PROGNAME, 0, LOG_USER);
#endif
FILE * fd_now;
FILE * fd_full;
if(run_verbose){
printf("Current charge: %d\n microampere-hours", c_now);
printf("Full charge: %d\n microampere-hours", c_full);
}
if(get_fds(&fd_now, &fd_full, BAT_PATH, CHARGE_NOW_PATH, CHARGE_FULL_PATH)){
printf("Charge unavailable, attempting to use energy\n");
if(get_fds(&fd_now, &fd_full, BAT_PATH, ENERGY_NOW_PATH, ENERGY_FULL_PATH)){
printf("Could not find a charge unit that works.\n");
exit(1);
} else {
printf("Unit is energy");
}
}
fflush(stdout);
double c_now;
double c_full;
double frac;
int pct;
do{
int rval = get_percentage(fd_now, fd_full, &c_now, &c_full, &frac, &pct);
if (rval){
printf("Um, problem\n");
return 1;
}
if(run_verbose){
printf("Current charge: %lf\n microampere-hours\n", c_now);
printf("Full charge: %lf\n microampere-hours\n", c_full);
}
if(!run_terse) {
printf("Battery percentage: ");
}
if(pct > warn_level){
warned = 0;
}
if(pct <= warn_level && !warned){
warn(pct);
}
printf("%d%s", pct, delimiter);
#ifdef USE_SYSLOG
syslog(LOG_INFO, "%d%%%s", pct, delimiter);
#endif
if(run_continuously){
sleep(interval);
errno = 0;
rewind(fd_now);
if(errno != 0){
perror("Error rewinding " CHARGE_NOW_PATH);
return 1;
}
rewind(fd_full); //just for the hecc of it
if(errno != 0){
perror("Error rewinding " CHARGE_FULL_PATH);
return 1;
}/*
fclose(fd_now);
fclose(fd_full);
fd_now = fopen(CHARGE_NOW_PATH, "r");
fd_full = fopen(CHARGE_FULL_PATH, "r");*/
}
} while (run_continuously);
#ifdef USE_SYSLOG
closelog();
#endif
if(!run_terse) {
printf("Battery percentage: ");
}
float frac = ((float)c_now) / ((float)c_full);
int pct = (int)(frac * 100);
printf("%d\n", pct);
return 0;
}

View File

@ -1,14 +0,0 @@
#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
#include <unistd.h>
#include <criterion/criterion.h>
#ifdef USE_LIBNOTIFY
#include <libnotify/notify.h>
#endif
Test(misc, passing){
cr_assert(1);
}