MIT is fine.
Here is some rather rudimentary low level C that avoids using printf, scanf and even malloc so the static binary is under 8kb.
Basically it monitors /proc/acpi/battery and generates an svg and tooltip text.
Code: Select all
/*
* proc2imgd.c
*
* Copyright 2014 Brad Conroy - released to public domain
*
*/
#include <fcntl.h> //open
#include <unistd.h> //read,write
#include <string.h> //strstr, strlen
#include <stdlib.h> //getenv
#include <sys/stat.h> //mkdir
#define strcpyALL(buf, l, ...) do{ \
char *bp=(char*)(buf); \
const char *s, *a[] = { __VA_ARGS__,NULL}, **ss=a; \
while((s=*ss++)) \
while((*s)&&((--l) >0)) \
*bp++=*s++; \
*bp=0; \
}while(0)
static inline int ispad(int X){return (X)==' '||(unsigned)(X)-'\t'<5;}
#define isnum(X) ((unsigned)(X)-'0' < 10)
int stod(const char *s){ //like atoi but no negatives and only for small numbers
int r=0;
while (ispad(*s++));
while (isnum(*s)) r = 10*r + (*s++ - '0');
return r;
}
static void dtos(int d, char *buf){ //like itoa, but you pass the buffer
int p=0;
if (0>d) {
buf[p++]='-';
d=-d;
}
if (0==d){
buf[p++]='0';
buf[p]=0;
return;
}
int i=1000000000;
while (i > d) i/=10;
while (0<i){
buf[p++]=('0'+(d/i));
if (i<=d) d=d%i;
i/=10;
}
buf[p]=0;
return;
}
//GLOBALs
static char //default colors TODO read from config file
*ln_c="#000", //lines, outlines, strokes, etc...
*fg_c="#AAA", //foreground items ... usually the actual image
*bg_c="#444", //background color ... todo match with theme
*txt_c="#FFF", //use a text color that will work with both the bg and fg
*chg_c="#0F0", //usually green indicates a preferred status
*dchg_c="#F00", //usually red denotes less preferred status
*width="22px", //set for standard tray size
*height="22px";
static const char *HOME,
hdr[]="<svg version=\"1.1\" xmlns=\"http://www.w3.org/2000/svg\" \tviewBox=\"0 0 100 100\" preserveAspectRatio=\"none\" ",
ftr[]="</svg>\n",
w[]=" width=\"",
h[]=" height=\"",
x[]=" x=\"",
y[]=" y=\"",
q[]="\" ",
tagend[]=">\n",
tagclose[]="/>\n",
rect[]="\t<rect ",
fill[]=" fill=\"",
txt[]="\t<text ",
center[]=" text-anchor=\"middle\"",
rotate[]=" transform=\"rotate(90 50,50)\"",
fontsz[]=" font-size=\"",
txtend[]="</text>\n";
#if 0 //TODO
void do_wifi(){
const char upload[]="M71,29L99,2L99,27L92,18,75,34",
download[] = "M98,0L70,27L70,5L77,12,90,0",
updown[] = "<path d=\"%s\" fill=\"%s\" stroke=\"%s\"/>\n",
sigqual[] = "<circle cx=\"0\" cy=\"100\" r=\"%d\" stroke=\"%s\" stroke-width=\"%d\" fill=\"%s\" fill-opacity=\"0.5\" />\n";
static int lastrcv=0, lastxmt=0;
int rcv,xmt,quality;
FILE *wireless = fopen("/proc/net/wireless", "r");
char dev[8], status[8], link[8], level[8], noise[8];
fgets(dummy, 99, wireless);
fgets(dummy, 99, wireless);
while (fscanf(fp, "%s %s %s %s %s %s\n", ip, hw, flags, mac, mask, dev) != EOF)
if (!strcmp(argv[1],ip))
printf("%s\n",dev);
return 0;
}
#endif
void do_bat(char *batt){
const char BAT[]="/proc/acpi/battery/BAT";
char buf[4096]={0}, *bp=(char *)buf, fname[32], dy[8], ht[8], ftsz[8],
text[]="BAT0";
static int dcap=0, rcap=-1, percent=-1;
int i, fd, len=sizeof(buf), chg=0, cap=0;
if (!isnum(*batt)) *batt='0';
else text[3] = *batt;
i=sizeof(fname);
strcpyALL(fname, i, BAT, batt, "/info");
if (( fd = open(fname,O_RDONLY))<0) return;
len = read(fd,buf,len);
close(fd);
if (len < 0) return;
buf[len]=0; //for strstr
if (!dcap){ //only do once
bp = strstr(buf,"design capacity:");
if (!bp) return;
dcap = stod(&bp[25]);
}
if ((bp = strstr(buf,"last ful"))) cap = stod(&bp[25]);
else cap = dcap;
i=sizeof(fname);
strcpyALL(fname,i,BAT,(batt)?batt:"0","/state");
if (( fd = open(fname,O_RDONLY))<0) return;
i = read(fd,&(buf[len]),sizeof(buf)-len);
close(fd);
if (i < 0) return;
else buf[(len+=i)]=0;
if ((bp = strstr(buf,"remain")) && (i = stod(&bp[25])) == rcap) return;
else rcap = i;
if ((bp = strstr(buf,"charging st"))) chg=bp[25]-'c';
i=sizeof(fname);
strcpyALL(fname,i,HOME,"/.sit/b", batt, ".tt");
if (( fd = open(fname,O_WRONLY|O_CREAT|O_TRUNC))<0) return;
len=write(fd,buf,len);
close(fd);
i=(rcap>cap)?(100*rcap)/cap:(100*rcap)/dcap;
if (i==percent) return;
else percent = i;
i=sizeof(fname);
strcpyALL(fname,i,HOME,"/.sit/b", batt, ".svg");
if (( fd = open(fname,O_WRONLY|O_CREAT|O_TRUNC))<0) return;
dtos(100-percent,dy);
dtos(percent,ht);
dtos(100/(strlen(text)-1),ftsz);
len=sizeof(buf);
strcpyALL(buf, len, hdr, w, width, q, h, height, q, tagend,
rect, x, "20%\"", w, "60%\"", h, "100%\"", fill, bg_c, q, tagclose,
rect, x, "20%\"", w, "60%\"", y, dy, q, h, ht, q, fill, (chg)?dchg_c:chg_c, q, tagclose,
//txt, x, "50\"", y, "50\"", fill, txt_c, q, fontsz, ftsz, q, center, rotate, tagend, "\t\t", text, "\n", txtend,
ftr
);
write(fd,buf,sizeof(buf)-len);
}
int main(int argc, char **argv){
char buf[64];
int len=sizeof(buf);
HOME=getenv("HOME");
strcpyALL(buf,len,HOME,"/.sit");
mkdir(buf,0644);
while(!sleep(1)){
do_bat("0");
}
return 0;
}