Skip to content

Commit

Permalink
Added function to print content from file (#331)
Browse files Browse the repository at this point in the history
Added a function to print file contents to status bar without newlines.
Added tests for print file contents function
Added manpage entry for file contents
  • Loading branch information
tuggan authored and stapelberg committed Feb 21, 2019
1 parent 9d28a66 commit 9b5f6ae
Show file tree
Hide file tree
Showing 8 changed files with 134 additions and 0 deletions.
1 change: 1 addition & 0 deletions Makefile.am
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@ i3status_SOURCES = \
src/print_time.c \
src/print_volume.c \
src/print_wireless_info.c \
src/print_file_contents.c \
src/process_runs.c \
src/pulse.c

Expand Down
19 changes: 19 additions & 0 deletions i3status.c
Original file line number Diff line number Diff line change
Expand Up @@ -491,6 +491,18 @@ int main(int argc, char *argv[]) {
CFG_CUSTOM_SEP_BLOCK_WIDTH_OPT,
CFG_END()};

cfg_opt_t read_opts[] = {
CFG_STR("format", "%content", CFGF_NONE),
CFG_STR("format_bad", "%title - %errno: %error", CFGF_NONE),
CFG_STR("path", NULL, CFGF_NONE),
CFG_INT("max_characters", 255, CFGF_NONE),
CFG_CUSTOM_ALIGN_OPT,
CFG_CUSTOM_COLOR_OPTS,
CFG_CUSTOM_MIN_WIDTH_OPT,
CFG_CUSTOM_SEPARATOR_OPT,
CFG_CUSTOM_SEP_BLOCK_WIDTH_OPT,
CFG_END()};

cfg_opt_t opts[] = {
CFG_STR_LIST("order", "{}", CFGF_NONE),
CFG_SEC("general", general_opts, CFGF_NONE),
Expand All @@ -509,6 +521,7 @@ int main(int argc, char *argv[]) {
CFG_SEC("load", load_opts, CFGF_NONE),
CFG_SEC("memory", memory_opts, CFGF_NONE),
CFG_SEC("cpu_usage", usage_opts, CFGF_NONE),
CFG_SEC("read_file", read_opts, CFGF_TITLE | CFGF_MULTI),
CFG_END()};

char *configfile = NULL;
Expand Down Expand Up @@ -787,6 +800,12 @@ int main(int argc, char *argv[]) {
print_cpu_usage(json_gen, buffer, cfg_getstr(sec, "format"), cfg_getstr(sec, "format_above_threshold"), cfg_getstr(sec, "format_above_degraded_threshold"), cfg_getstr(sec, "path"), cfg_getfloat(sec, "max_threshold"), cfg_getfloat(sec, "degraded_threshold"));
SEC_CLOSE_MAP;
}

CASE_SEC_TITLE("read_file") {
SEC_OPEN_MAP("read_file");
print_file_contents(json_gen, buffer, title, cfg_getstr(sec, "path"), cfg_getstr(sec, "format"), cfg_getstr(sec, "format_bad"), cfg_getint(sec, "max_characters"));
SEC_CLOSE_MAP;
}
}
if (output_format == O_I3BAR) {
yajl_gen_array_close(json_gen);
Expand Down
1 change: 1 addition & 0 deletions include/i3status.h
Original file line number Diff line number Diff line change
Expand Up @@ -231,6 +231,7 @@ bool process_runs(const char *path);
int volume_pulseaudio(uint32_t sink_idx, const char *sink_name);
bool description_pulseaudio(uint32_t sink_idx, const char *sink_name, char buffer[MAX_SINK_DESCRIPTION_LEN]);
bool pulse_initialize(void);
void print_file_contents(yajl_gen json_gen, char *buffer, const char *title, const char *path, const char *format, const char *format_bad, const int max_chars);

/* socket file descriptor for general purposes */
extern int general_socket;
Expand Down
24 changes: 24 additions & 0 deletions man/i3status.man
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,11 @@ memory {
disk "/" {
format = "%free"
}

read_file uptime {
path = "/proc/uptime"
}

-------------------------------------------------------------

=== General
Expand Down Expand Up @@ -611,6 +616,25 @@ volume master {
}
-------------------------------------------------------------

=== File Contents

Outputs the contents of the specified file. You can use this to check contents
of files on your system, for example /proc/uptime. By default the function only
reads the first 254 characters of the file, if you want to override this set
the Max_characters option. It will never read beyond the first 4095 characters.
If the file is not found "no file" will be printed, if the file can't be read
"error read" will be printed.

*Example order*: read_file UPTIME

*Example format*: "%title: %content"

*Example format_bad*: "%title - %errno: %error"

*Example path*: "/proc/uptime"

*Example Max_characters*: 255

== Universal module options

When using the i3bar output format, there are a few additional options that
Expand Down
73 changes: 73 additions & 0 deletions src/print_file_contents.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
// vim:ts=4:sw=4:expandtab

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <yajl/yajl_gen.h>
#include <yajl/yajl_version.h>
#include <sys/types.h>

#include <sys/fcntl.h>
#include <unistd.h>
#include <errno.h>
#include "i3status.h"

static void *scalloc(size_t size) {
void *result = calloc(size, 1);
if (result == NULL) {
die("Error: out of memory (calloc(%zu))\n", size);
}
return result;
}

void print_file_contents(yajl_gen json_gen, char *buffer, const char *title, const char *path, const char *format, const char *format_bad, const int max_chars) {
const char *walk = format;
char *outwalk = buffer;
char *buf = scalloc(max_chars * sizeof(char));

int n = -1;
int fd = open(path, O_RDONLY);

INSTANCE(path);

if (fd > -1) {
n = read(fd, buf, max_chars);
if (n != -1) {
buf[n] = '\0';
}
(void)close(fd);
START_COLOR("color_good");
} else if (errno != 0) {
walk = format_bad;
START_COLOR("color_bad");
}

for (; *walk != '\0'; walk++) {
if (*walk != '%') {
*(outwalk++) = *walk;
} else if (BEGINS_WITH(walk + 1, "title")) {
outwalk += sprintf(outwalk, "%s", title);
walk += strlen("title");
} else if (BEGINS_WITH(walk + 1, "content")) {
for (char *s = buf; *s != '\0' && n > 0; s++, n--) {
if (*s != '\n') {
*(outwalk++) = *s;
}
}
walk += strlen("content");
} else if (BEGINS_WITH(walk + 1, "errno")) {
outwalk += sprintf(outwalk, "%d", errno);
walk += strlen("errno");
} else if (BEGINS_WITH(walk + 1, "error")) {
outwalk += sprintf(outwalk, "%s", strerror(errno));
walk += strlen("error");
} else {
*(outwalk++) = '%';
}
}

free(buf);

END_COLOR;
OUTPUT_FULL_TEXT(buffer);
}
1 change: 1 addition & 0 deletions testcases/025-file-contents/expected_output.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
contents | NONEXISTANT - 2: No such file or directory
14 changes: 14 additions & 0 deletions testcases/025-file-contents/i3status.conf
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
general {
output_format = "none"
}

order += "read_file EXISTING"
order += "read_file NONEXISTANT"

read_file EXISTING {
path = "testcases/025-file-contents/short.txt"
}

read_file NONEXISTANT {
path = "testcases/025-file-contents/nonexistant"
}
1 change: 1 addition & 0 deletions testcases/025-file-contents/short.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
contents

0 comments on commit 9b5f6ae

Please sign in to comment.