Skip to content

Instantly share code, notes, and snippets.

@karolba
Created April 22, 2019 19:56
Show Gist options
  • Save karolba/07d95f361e92405eb611a6c2d75382ab to your computer and use it in GitHub Desktop.
Save karolba/07d95f361e92405eb611a6c2d75382ab to your computer and use it in GitHub Desktop.
#include <iostream>
#include <memory>
#include <json/value.h>
#include <json/reader.h>
#include <json/writer.h>
#include <unistd.h>
#include <string.h>
#include <errno.h>
#include <stdio.h>
#include <ext/stdio_filebuf.h>
#define CHILD_STDOUT_READ pipefds[0]
#define CHILD_STDOUT_WRITE pipefds[1]
static std::string change_battery_full_text(const std::string &text) {
std::string ret;
bool pass = true;
for(char c : text) {
if(c == ',')
pass = false;
if(c == '%')
pass = true;
if(pass)
ret += c;
}
return ret;
}
static void err(const char *desc) {
std::cerr << "modify_status_on_the_fly error: " << desc << " fail: "
<< strerror(errno) << "\n";
exit(1);
}
/*
* reads a JSON stream from i3status_out_stream, substitutes "12,34%" with "12%" in the battery section
* in JSON and outputs all input to stdout
*/
static void main_modifier_thread(std::istream &i3status_out_stream) {
std::string line;
Json::StreamWriterBuilder writerBuilder;
writerBuilder["commentStyle"] = "None";
writerBuilder["indentation"] = ""; // The JSON document will be written in a single line
std::unique_ptr<Json::StreamWriter> writer(writerBuilder.newStreamWriter());
Json::CharReaderBuilder readerBuilder;
std::unique_ptr<Json::CharReader> reader(readerBuilder.newCharReader());
while(std::getline(i3status_out_stream, line)) {
int front_offset = 0; // 1 if line begins in ',', as we are dealing with a JSON array stream
if(line.size() >= 1 && line[0] == ',') {
front_offset = 1;
}
Json::Value v;
if(! reader->parse(line.c_str() + front_offset, line.c_str() + line.size(), &v, NULL)
|| ! v.isArray()) {
// not a message we are interested in, pass it on
std::cout << line << std::endl; // intended flush
continue;
}
for(decltype(v.size()) i = 0; i < v.size(); ++i) {
const Json::Value &name = v[i]["name"];
const Json::Value &full_text = v[i]["full_text"];
if(name.isString() && name.asString() == "battery" && full_text.isString()) {
v[i]["full_text"] = change_battery_full_text(full_text.asString());
}
}
if(front_offset == 1) {
std::cout << ',';
}
writer->write(v, &std::cout);
std::cout << std::endl; // intended flush
}
}
int main() {
std::ios::sync_with_stdio(true);
int pipefds[2];
if(pipe(pipefds) == -1)
err("pipe()");
pid_t pid;
switch(pid = fork()) {
case 0:
// child
dup2(CHILD_STDOUT_WRITE, STDOUT_FILENO);
close(CHILD_STDOUT_READ); // don't need this in child
execlp("i3status", "i3status", (char *) NULL);
close(CHILD_STDOUT_READ);
err("execlp()");
case -1:
err("fork()");
default:
(void) 0;
// parent
}
close(CHILD_STDOUT_WRITE); // we won't be writing to child's stdout
__gnu_cxx::stdio_filebuf<char> filebuf(CHILD_STDOUT_READ, std::ios::in); // libstdc++ extension
std::istream i3status_out_stream(&filebuf);
main_modifier_thread(i3status_out_stream);
close(CHILD_STDOUT_READ);
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment