Breaks configfiles! Major refactoring of i3status, see below

We finally switched to libconfuse for a configuration file format
which does not require much work for the programmer nor for the user.
Plus, it avoids the Not-Invented-Here syndrome of yet another config
file format.

Furthermore, as a consequence of providing format strings for every
"module" (ipv6, wireless, …), we directly print the output and thus
we needed to drop support for wmii. This allowed us to get rid of
quite some complexity.

Documentation about the new configuration file and options will
follow. This commit is the beginning of what will be i3status v2.0.
This commit is contained in:
Michael Stapelberg 2009-10-11 22:11:09 +02:00
parent 1d122f32e6
commit f947d0a446
21 changed files with 520 additions and 1234 deletions

2
.gitignore vendored Normal file
View File

@ -0,0 +1,2 @@
*.o
.*.swp

View File

@ -4,6 +4,7 @@ CFLAGS+=-std=gnu99
CFLAGS+=-pedantic
CFLAGS+=-DPREFIX=\"\"
CFLAGS+=-I.
LDFLAGS+=-lconfuse
VERSION=$(shell git describe --tags --abbrev=0)
@ -18,9 +19,12 @@ CFLAGS+=-lbsd
endif
# Define this if you want i3status to spit out dzen2-compatible output on stdout
#CFLAGS+=-DDZEN
CFLAGS+=-DDZEN
CFLAGS+=$(EXTRA_CFLAGS)
OBJS:=$(wildcard src/*.c *.c)
OBJS:=$(OBJS:.c=.o)
src/%.o: src/%.c
@$(CC) $(CFLAGS) -c -o $@ $<
@echo " CC $<"
@ -29,7 +33,7 @@ src/%.o: src/%.c
@$(CC) $(CFLAGS) -c -o $@ $<
@echo " CC $<"
i3status: src/general.o src/config.o src/get_load.o src/output.o src/get_cpu_temperature.o src/process_runs.o src/get_eth_info.o src/get_ip_addr.o src/get_wireless_info.o src/get_battery_info.o src/get_ipv6_addr.o i3status.o
i3status: ${OBJS}
@$(CC) -o $@ src/*.o *.o $(LDFLAGS)
@echo " LD $@"

View File

@ -1,80 +1,57 @@
/*
* vim:ts=8:expandtab
*
* i3status Generates a status line for dzen2 or wmii
* i3status Generates a status line for dzen2 or xmobar
*
*
* Copyright © 2008-2009 Michael Stapelberg and contributors
* Copyright © 2009 Thorsten Toepper <atsutane at freethoughts dot de>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* * Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above copyright notice, this
* list of conditions and the following disclaimer in the documentation and/or other
* materials provided with the distribution.
* * Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* * Neither the name of Michael Stapelberg nor the names of contributors
* may be used to endorse or promote products derived from this software without
* specific prior written permission.
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
* SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
* TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
* DAMAGE.
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
*/
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <string.h>
#include <stdio.h>
#include <time.h>
#include <stdbool.h>
#include <stdarg.h>
#include <unistd.h>
#include <stdlib.h>
#include <limits.h>
#include <ctype.h>
#include <sys/ioctl.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <getopt.h>
#include <signal.h>
#include "queue.h"
#include <confuse.h>
#include "i3status.h"
struct battery_head batteries;
/* socket file descriptor for general purposes */
int general_socket;
const char *wlan_interface = NULL;
const char *eth_interface = NULL;
char *wmii_path = NULL;
const char *time_format = NULL;
bool use_colors = false;
bool get_ethspeed = false;
bool get_ipv6 = false;
bool get_cpu_temperature = false;
char *thermal_zone = NULL;
const char *wmii_normcolors = "#222222 #333333";
int order[MAX_ORDER];
const char **run_watches = NULL;
unsigned int num_run_watches;
unsigned int interval = 1;
cfg_t *cfg, *cfg_general;
/*
* Exit upon SIGPIPE because when we have nowhere to write to, gathering
@ -87,10 +64,69 @@ void sigpipe(int signum) {
}
int main(int argc, char *argv[]) {
char part[512],
pathbuf[512];
unsigned int i;
int j;
unsigned int j;
cfg_opt_t general_opts[] = {
CFG_BOOL("colors", 1, CFGF_NONE),
CFG_INT("interval", 1, CFGF_NONE),
CFG_END()
};
cfg_opt_t run_watch_opts[] = {
CFG_STR("pidfile", NULL, CFGF_NONE),
CFG_STR("format", "%title: %status", CFGF_NONE),
CFG_END()
};
cfg_opt_t wireless_opts[] = {
CFG_STR("format_up", "W: (%quality at %essid) %ip", CFGF_NONE),
CFG_STR("format_down", "W: down", CFGF_NONE),
CFG_END()
};
cfg_opt_t ethernet_opts[] = {
CFG_STR("format", "E: %ip (%speed)", CFGF_NONE),
CFG_END()
};
cfg_opt_t ipv6_opts[] = {
CFG_STR("format", "%ip", CFGF_NONE),
CFG_END()
};
cfg_opt_t battery_opts[] = {
CFG_STR("format", "%status %remaining", CFGF_NONE),
CFG_END()
};
cfg_opt_t time_opts[] = {
CFG_STR("format", "%d.%m.%Y %H:%M:%S", CFGF_NONE),
CFG_END()
};
cfg_opt_t load_opts[] = {
CFG_STR("format", "%5min %10min %15min", CFGF_NONE),
CFG_END()
};
cfg_opt_t temp_opts[] = {
CFG_STR("format", "%degrees C", CFGF_NONE),
CFG_END()
};
cfg_opt_t opts[] = {
CFG_STR_LIST("order", "{ipv6,\"run_watch DHCP\",\"wireless wlan0\",\"ethernet eth0\",\"battery 0\",\"cpu_temperature 0\",load,time}", CFGF_NONE),
CFG_SEC("general", general_opts, CFGF_NONE),
CFG_SEC("run_watch", run_watch_opts, CFGF_TITLE | CFGF_MULTI),
CFG_SEC("wireless", wireless_opts, CFGF_TITLE | CFGF_MULTI),
CFG_SEC("ethernet", ethernet_opts, CFGF_TITLE | CFGF_MULTI),
CFG_SEC("battery", battery_opts, CFGF_TITLE | CFGF_MULTI),
CFG_SEC("cpu_temperature", temp_opts, CFGF_TITLE | CFGF_MULTI),
CFG_SEC("ipv6", ipv6_opts, CFGF_TITLE),
CFG_SEC("time", time_opts, CFGF_NONE),
CFG_SEC("load", load_opts, CFGF_NONE),
CFG_END()
};
char *configfile = PREFIX "/etc/i3status.conf";
int o, option_index = 0;
@ -105,66 +141,58 @@ int main(int argc, char *argv[]) {
action.sa_handler = sigpipe;
sigaction(SIGPIPE, &action, NULL);
SIMPLEQ_INIT(&batteries);
while ((o = getopt_long(argc, argv, "c:h", long_options, &option_index)) != -1)
if ((char)o == 'c')
configfile = optarg;
else if ((char)o == 'h') {
printf("i3status (c) 2008-2009 Michael Stapelberg\n"
printf("i3status © 2008-2009 Michael Stapelberg\n"
"Syntax: %s [-c <configfile>]\n", argv[0]);
return 0;
}
if (load_configuration(configfile) < 0)
cfg = cfg_init(opts, CFGF_NONE);
if (cfg_parse(cfg, configfile) == CFG_PARSE_ERROR)
return EXIT_FAILURE;
setup();
cfg_general = cfg_getsec(cfg, "general");
if ((general_socket = socket(AF_INET, SOCK_DGRAM, 0)) == -1)
die("Could not create socket\n");
while (1) {
for (j = 0; j < MAX_ORDER; j++) {
generate_order(wlan_interface, ORDER_WLAN, "wlan", get_wireless_info());
generate_order(eth_interface, ORDER_ETH, "eth", get_eth_info());
generate_order(get_ipv6, ORDER_IPV6, "ipv6", get_ipv6_addr());
generate_order(get_cpu_temperature, ORDER_CPU_TEMPERATURE, "cpu_temperature", get_cpu_temperature_info());
generate_order(true, ORDER_LOAD, "load", get_load());
for (j = 0; j < cfg_size(cfg, "order"); j++) {
if (j > 0)
print_seperator();
if (j == order[ORDER_RUN]) {
for (i = 0; i < num_run_watches; i += 2) {
bool running = process_runs(run_watches[i+1]);
if (use_colors)
snprintf(part, sizeof(part), "%s%s: %s%s",
(running ? color("#00FF00") : color("#FF0000")),
run_watches[i],
(running ? "yes" : "no"), endcolor());
else snprintf(part, sizeof(part), "%s: %s", run_watches[i], (running ? "yes" : "no"));
snprintf(pathbuf, sizeof(pathbuf), "%d%s", order[ORDER_RUN], run_watches[i]);
write_to_statusbar(pathbuf, part, false);
}
}
const char *current = cfg_getnstr(cfg, "order", j);
if (j == order[ORDER_BATTERY]) {
struct battery *current;
SIMPLEQ_FOREACH(current, &batteries, batteries)
generate(ORDER_BATTERY, "battery", get_battery_info(current));
}
CASE_SEC("ipv6")
print_ipv6_info(cfg_getstr(sec, "format"));
if (j == order[ORDER_TIME]) {
if (time_format != NULL) {
/* Get date & time */
time_t current_time = time(NULL);
struct tm *current_tm = localtime(&current_time);
(void)strftime(part, sizeof(part), time_format, current_tm);
generate(ORDER_TIME, "time", part);
} else {
generate(ORDER_TIME, "time", "");
}
}
}
CASE_SEC_TITLE("wireless")
print_wireless_info(title, cfg_getstr(sec, "format_up"), cfg_getstr(sec, "format_down"));
sleep(interval);
CASE_SEC_TITLE("ethernet")
print_eth_info(title, cfg_getstr(sec, "format"));
CASE_SEC_TITLE("battery")
print_battery_info(atoi(title), cfg_getstr(sec, "format"));
CASE_SEC_TITLE("run_watch")
print_run_watch(title, cfg_getstr(sec, "pidfile"), cfg_getstr(sec, "format"));
CASE_SEC("load")
print_load(cfg_getstr(sec, "format"));
CASE_SEC("time")
print_time(cfg_getstr(sec, "format"));
CASE_SEC_TITLE("cpu_temperature")
print_cpu_temperature_info(atoi(title), cfg_getstr(sec, "format"));
}
printf("\n");
fflush(stdout);
sleep(cfg_getint(cfg_general, "interval"));
}
}

View File

@ -2,8 +2,7 @@
#define _I3STATUS_H
#include <stdbool.h>
#include "queue.h"
#include <confuse.h>
#ifdef DZEN
#define BAR "^fg(#333333)^p(5;-2)^ro(2)^p()^fg()^p(5)"
@ -11,18 +10,7 @@
#define BAR "<fc=#333333> | </fc>"
#endif
#define BEGINS_WITH(haystack, needle) (strncmp(haystack, needle, strlen(needle)) == 0)
#define max(a, b) (a > b ? a : b)
#define generate(orderidx, name, function) \
do { \
write_to_statusbar(order_to_str(order[orderidx], name), function, (j == (highest_order-1))); \
} while (0)
#define generate_order(condition, orderidx, name, function) \
do { \
if (j == order[orderidx] && condition) \
generate(orderidx, name, function); \
} while (0)
#define max(a, b) ((a) > (b) ? (a) : (b))
#if defined(LINUX)
@ -44,64 +32,49 @@
#endif
typedef enum { CS_DISCHARGING, CS_CHARGING, CS_FULL } charging_status_t;
enum { ORDER_RUN, ORDER_WLAN, ORDER_ETH, ORDER_BATTERY, ORDER_CPU_TEMPERATURE, ORDER_LOAD, ORDER_TIME, ORDER_IPV6, MAX_ORDER };
/* Allows for the definition of a variable without opening a new scope, thus
* suited for usage in a macro. Idea from wmii. */
#define with(type, var, init) \
for (type var = (type)-1; (var == (type)-1) && ((var=(init)) || 1); )
struct battery {
char *path;
/* Use last full capacity instead of design capacity */
bool use_last_full;
SIMPLEQ_ENTRY(battery) batteries;
};
#define CASE_SEC(name) \
if (BEGINS_WITH(current, name)) \
with(cfg_t *, sec, cfg_getsec(cfg, name)) \
if (sec != NULL)
#define CASE_SEC_TITLE(name) \
if (BEGINS_WITH(current, name)) \
with(const char *, title, current + strlen(name) + 1) \
with(cfg_t *, sec, cfg_gettsec(cfg, name, title)) \
if (sec != NULL)
typedef enum { CS_DISCHARGING, CS_CHARGING, CS_FULL } charging_status_t;
/* src/general.c */
char *skip_character(char *input, char character, int amount);
void die(const char *fmt, ...);
void create_file(const char *name);
char *order_to_str(int number, char *name);
void setup(void);
void write_to_statusbar(const char *name, const char *message, bool final_entry);
bool slurp(char *filename, char *destination, int size);
/* src/output.c */
void write_error_to_statusbar(const char *message);
void print_seperator();
char *color(const char *colorstr);
char *endcolor() __attribute__ ((pure));
void cleanup_rbar_dir();
/* src/config.c */
int load_configuration(const char *configfile);
const char *get_ipv6_addr();
const char *get_battery_info(struct battery *bat);
void print_ipv6_info(const char *format);
void print_battery_info(int number, const char *format);
void print_time(const char *format);
const char *get_ip_addr();
const char *get_wireless_info();
const char *get_cpu_temperature_info();
const char *get_eth_info();
const char *get_load();
void print_wireless_info(const char *interface, const char *format_up, const char *format_down);
void print_run_watch(const char *title, const char *pidfile, const char *format);
void print_cpu_temperature_info(int zone, const char *format);
void print_eth_info(const char *interface, const char *format);
void print_load();
bool process_runs(const char *path);
SIMPLEQ_HEAD(battery_head, battery);
extern struct battery_head batteries;
/* socket file descriptor for general purposes */
extern int general_socket;
extern int highest_order;
extern const char *wlan_interface;
extern const char *eth_interface;
extern char *wmii_path;
extern const char *time_format;
extern bool use_colors;
extern bool get_ethspeed;
extern bool get_ipv6;
extern bool get_cpu_temperature;
extern char *thermal_zone;
extern const char *wmii_normcolors;
extern int order[MAX_ORDER];
extern const char **run_watches;
extern unsigned int num_run_watches;
extern unsigned int interval;
extern cfg_t *cfg, *cfg_general;
#endif

527
queue.h
View File

@ -1,527 +0,0 @@
/* $OpenBSD: queue.h,v 1.1 2007/10/26 03:14:08 niallo Exp $ */
/* $NetBSD: queue.h,v 1.11 1996/05/16 05:17:14 mycroft Exp $ */
/*
* Copyright (c) 1991, 1993
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* @(#)queue.h 8.5 (Berkeley) 8/20/94
*/
#ifndef _SYS_QUEUE_H_
#define _SYS_QUEUE_H_
/*
* This file defines five types of data structures: singly-linked lists,
* lists, simple queues, tail queues, and circular queues.
*
*
* A singly-linked list is headed by a single forward pointer. The elements
* are singly linked for minimum space and pointer manipulation overhead at
* the expense of O(n) removal for arbitrary elements. New elements can be
* added to the list after an existing element or at the head of the list.
* Elements being removed from the head of the list should use the explicit
* macro for this purpose for optimum efficiency. A singly-linked list may
* only be traversed in the forward direction. Singly-linked lists are ideal
* for applications with large datasets and few or no removals or for
* implementing a LIFO queue.
*
* A list is headed by a single forward pointer (or an array of forward
* pointers for a hash table header). The elements are doubly linked
* so that an arbitrary element can be removed without a need to
* traverse the list. New elements can be added to the list before
* or after an existing element or at the head of the list. A list
* may only be traversed in the forward direction.
*
* A simple queue is headed by a pair of pointers, one the head of the
* list and the other to the tail of the list. The elements are singly
* linked to save space, so elements can only be removed from the
* head of the list. New elements can be added to the list before or after
* an existing element, at the head of the list, or at the end of the
* list. A simple queue may only be traversed in the forward direction.
*
* A tail queue is headed by a pair of pointers, one to the head of the
* list and the other to the tail of the list. The elements are doubly
* linked so that an arbitrary element can be removed without a need to
* traverse the list. New elements can be added to the list before or
* after an existing element, at the head of the list, or at the end of
* the list. A tail queue may be traversed in either direction.
*
* A circle queue is headed by a pair of pointers, one to the head of the
* list and the other to the tail of the list. The elements are doubly
* linked so that an arbitrary element can be removed without a need to
* traverse the list. New elements can be added to the list before or after
* an existing element, at the head of the list, or at the end of the list.
* A circle queue may be traversed in either direction, but has a more
* complex end of list detection.
*
* For details on the use of these macros, see the queue(3) manual page.
*/
#if defined(QUEUE_MACRO_DEBUG) || (defined(_KERNEL) && defined(DIAGNOSTIC))
#define _Q_INVALIDATE(a) (a) = ((void *)-1)
#else
#define _Q_INVALIDATE(a)
#endif
/*
* Singly-linked List definitions.
*/
#define SLIST_HEAD(name, type) \
struct name { \
struct type *slh_first; /* first element */ \
}
#define SLIST_HEAD_INITIALIZER(head) \
{ NULL }
#define SLIST_ENTRY(type) \
struct { \
struct type *sle_next; /* next element */ \
}
/*
* Singly-linked List access methods.
*/
#define SLIST_FIRST(head) ((head)->slh_first)
#define SLIST_END(head) NULL
#define SLIST_EMPTY(head) (SLIST_FIRST(head) == SLIST_END(head))
#define SLIST_NEXT(elm, field) ((elm)->field.sle_next)
#define SLIST_FOREACH(var, head, field) \
for((var) = SLIST_FIRST(head); \
(var) != SLIST_END(head); \
(var) = SLIST_NEXT(var, field))
#define SLIST_FOREACH_PREVPTR(var, varp, head, field) \
for ((varp) = &SLIST_FIRST((head)); \
((var) = *(varp)) != SLIST_END(head); \
(varp) = &SLIST_NEXT((var), field))
/*
* Singly-linked List functions.
*/
#define SLIST_INIT(head) { \
SLIST_FIRST(head) = SLIST_END(head); \
}
#define SLIST_INSERT_AFTER(slistelm, elm, field) do { \
(elm)->field.sle_next = (slistelm)->field.sle_next; \
(slistelm)->field.sle_next = (elm); \
} while (0)
#define SLIST_INSERT_HEAD(head, elm, field) do { \
(elm)->field.sle_next = (head)->slh_first; \
(head)->slh_first = (elm); \
} while (0)
#define SLIST_REMOVE_NEXT(head, elm, field) do { \
(elm)->field.sle_next = (elm)->field.sle_next->field.sle_next; \
} while (0)
#define SLIST_REMOVE_HEAD(head, field) do { \
(head)->slh_first = (head)->slh_first->field.sle_next; \
} while (0)
#define SLIST_REMOVE(head, elm, type, field) do { \
if ((head)->slh_first == (elm)) { \
SLIST_REMOVE_HEAD((head), field); \
} else { \
struct type *curelm = (head)->slh_first; \
\
while (curelm->field.sle_next != (elm)) \
curelm = curelm->field.sle_next; \
curelm->field.sle_next = \
curelm->field.sle_next->field.sle_next; \
_Q_INVALIDATE((elm)->field.sle_next); \
} \
} while (0)
/*
* List definitions.
*/
#define LIST_HEAD(name, type) \
struct name { \
struct type *lh_first; /* first element */ \
}
#define LIST_HEAD_INITIALIZER(head) \
{ NULL }
#define LIST_ENTRY(type) \
struct { \
struct type *le_next; /* next element */ \
struct type **le_prev; /* address of previous next element */ \
}
/*
* List access methods
*/
#define LIST_FIRST(head) ((head)->lh_first)
#define LIST_END(head) NULL
#define LIST_EMPTY(head) (LIST_FIRST(head) == LIST_END(head))
#define LIST_NEXT(elm, field) ((elm)->field.le_next)
#define LIST_FOREACH(var, head, field) \
for((var) = LIST_FIRST(head); \
(var)!= LIST_END(head); \
(var) = LIST_NEXT(var, field))
/*
* List functions.
*/
#define LIST_INIT(head) do { \
LIST_FIRST(head) = LIST_END(head); \
} while (0)
#define LIST_INSERT_AFTER(listelm, elm, field) do { \
if (((elm)->field.le_next = (listelm)->field.le_next) != NULL) \
(listelm)->field.le_next->field.le_prev = \
&(elm)->field.le_next; \
(listelm)->field.le_next = (elm); \
(elm)->field.le_prev = &(listelm)->field.le_next; \
} while (0)
#define LIST_INSERT_BEFORE(listelm, elm, field) do { \
(elm)->field.le_prev = (listelm)->field.le_prev; \
(elm)->field.le_next = (listelm); \
*(listelm)->field.le_prev = (elm); \
(listelm)->field.le_prev = &(elm)->field.le_next; \
} while (0)
#define LIST_INSERT_HEAD(head, elm, field) do { \
if (((elm)->field.le_next = (head)->lh_first) != NULL) \
(head)->lh_first->field.le_prev = &(elm)->field.le_next;\
(head)->lh_first = (elm); \
(elm)->field.le_prev = &(head)->lh_first; \
} while (0)
#define LIST_REMOVE(elm, field) do { \
if ((elm)->field.le_next != NULL) \
(elm)->field.le_next->field.le_prev = \
(elm)->field.le_prev; \
*(elm)->field.le_prev = (elm)->field.le_next; \
_Q_INVALIDATE((elm)->field.le_prev); \
_Q_INVALIDATE((elm)->field.le_next); \
} while (0)
#define LIST_REPLACE(elm, elm2, field) do { \
if (((elm2)->field.le_next = (elm)->field.le_next) != NULL) \
(elm2)->field.le_next->field.le_prev = \
&(elm2)->field.le_next; \
(elm2)->field.le_prev = (elm)->field.le_prev; \
*(elm2)->field.le_prev = (elm2); \
_Q_INVALIDATE((elm)->field.le_prev); \
_Q_INVALIDATE((elm)->field.le_next); \
} while (0)
/*
* Simple queue definitions.
*/
#define SIMPLEQ_HEAD(name, type) \
struct name { \
struct type *sqh_first; /* first element */ \
struct type **sqh_last; /* addr of last next element */ \
}
#define SIMPLEQ_HEAD_INITIALIZER(head) \
{ NULL, &(head).sqh_first }
#define SIMPLEQ_ENTRY(type) \
struct { \
struct type *sqe_next; /* next element */ \
}
/*
* Simple queue access methods.
*/
#define SIMPLEQ_FIRST(head) ((head)->sqh_first)
#define SIMPLEQ_END(head) NULL
#define SIMPLEQ_EMPTY(head) (SIMPLEQ_FIRST(head) == SIMPLEQ_END(head))
#define SIMPLEQ_NEXT(elm, field) ((elm)->field.sqe_next)
#define SIMPLEQ_FOREACH(var, head, field) \
for((var) = SIMPLEQ_FIRST(head); \
(var) != SIMPLEQ_END(head); \
(var) = SIMPLEQ_NEXT(var, field))
/*
* Simple queue functions.
*/
#define SIMPLEQ_INIT(head) do { \
(head)->sqh_first = NULL; \
(head)->sqh_last = &(head)->sqh_first; \
} while (0)
#define SIMPLEQ_INSERT_HEAD(head, elm, field) do { \
if (((elm)->field.sqe_next = (head)->sqh_first) == NULL) \
(head)->sqh_last = &(elm)->field.sqe_next; \
(head)->sqh_first = (elm); \
} while (0)
#define SIMPLEQ_INSERT_TAIL(head, elm, field) do { \
(elm)->field.sqe_next = NULL; \
*(head)->sqh_last = (elm); \
(head)->sqh_last = &(elm)->field.sqe_next; \
} while (0)
#define SIMPLEQ_INSERT_AFTER(head, listelm, elm, field) do { \
if (((elm)->field.sqe_next = (listelm)->field.sqe_next) == NULL)\
(head)->sqh_last = &(elm)->field.sqe_next; \
(listelm)->field.sqe_next = (elm); \
} while (0)
#define SIMPLEQ_REMOVE_HEAD(head, field) do { \
if (((head)->sqh_first = (head)->sqh_first->field.sqe_next) == NULL) \
(head)->sqh_last = &(head)->sqh_first; \
} while (0)
/*
* Tail queue definitions.
*/
#define TAILQ_HEAD(name, type) \
struct name { \
struct type *tqh_first; /* first element */ \
struct type **tqh_last; /* addr of last next element */ \
}
#define TAILQ_HEAD_INITIALIZER(head) \
{ NULL, &(head).tqh_first }
#define TAILQ_ENTRY(type) \
struct { \
struct type *tqe_next; /* next element */ \
struct type **tqe_prev; /* address of previous next element */ \
}
/*
* tail queue access methods
*/
#define TAILQ_FIRST(head) ((head)->tqh_first)
#define TAILQ_END(head) NULL
#define TAILQ_NEXT(elm, field) ((elm)->field.tqe_next)
#define TAILQ_LAST(head, headname) \
(*(((struct headname *)((head)->tqh_last))->tqh_last))
/* XXX */
#define TAILQ_PREV(elm, headname, field) \
(*(((struct headname *)((elm)->field.tqe_prev))->tqh_last))
#define TAILQ_EMPTY(head) \
(TAILQ_FIRST(head) == TAILQ_END(head))
#define TAILQ_FOREACH(var, head, field) \
for((var) = TAILQ_FIRST(head); \
(var) != TAILQ_END(head); \
(var) = TAILQ_NEXT(var, field))
#define TAILQ_FOREACH_REVERSE(var, head, headname, field) \
for((var) = TAILQ_LAST(head, headname); \
(var) != TAILQ_END(head); \
(var) = TAILQ_PREV(var, headname, field))
/*
* Tail queue functions.
*/
#define TAILQ_INIT(head) do { \
(head)->tqh_first = NULL; \
(head)->tqh_last = &(head)->tqh_first; \
} while (0)
#define TAILQ_INSERT_HEAD(head, elm, field) do { \
if (((elm)->field.tqe_next = (head)->tqh_first) != NULL) \
(head)->tqh_first->field.tqe_prev = \
&(elm)->field.tqe_next; \
else \
(head)->tqh_last = &(elm)->field.tqe_next; \
(head)->tqh_first = (elm); \
(elm)->field.tqe_prev = &(head)->tqh_first; \
} while (0)
#define TAILQ_INSERT_TAIL(head, elm, field) do { \
(elm)->field.tqe_next = NULL; \
(elm)->field.tqe_prev = (head)->tqh_last; \
*(head)->tqh_last = (elm); \
(head)->tqh_last = &(elm)->field.tqe_next; \
} while (0)
#define TAILQ_INSERT_AFTER(head, listelm, elm, field) do { \
if (((elm)->field.tqe_next = (listelm)->field.tqe_next) != NULL)\
(elm)->field.tqe_next->field.tqe_prev = \
&(elm)->field.tqe_next; \
else \
(head)->tqh_last = &(elm)->field.tqe_next; \
(listelm)->field.tqe_next = (elm); \
(elm)->field.tqe_prev = &(listelm)->field.tqe_next; \
} while (0)
#define TAILQ_INSERT_BEFORE(listelm, elm, field) do { \
(elm)->field.tqe_prev = (listelm)->field.tqe_prev; \
(elm)->field.tqe_next = (listelm); \
*(listelm)->field.tqe_prev = (elm); \
(listelm)->field.tqe_prev = &(elm)->field.tqe_next; \
} while (0)
#define TAILQ_REMOVE(head, elm, field) do { \
if (((elm)->field.tqe_next) != NULL) \
(elm)->field.tqe_next->field.tqe_prev = \
(elm)->field.tqe_prev; \
else \
(head)->tqh_last = (elm)->field.tqe_prev; \
*(elm)->field.tqe_prev = (elm)->field.tqe_next; \
_Q_INVALIDATE((elm)->field.tqe_prev); \
_Q_INVALIDATE((elm)->field.tqe_next); \
} while (0)
#define TAILQ_REPLACE(head, elm, elm2, field) do { \
if (((elm2)->field.tqe_next = (elm)->field.tqe_next) != NULL) \
(elm2)->field.tqe_next->field.tqe_prev = \
&(elm2)->field.tqe_next; \
else \
(head)->tqh_last = &(elm2)->field.tqe_next; \
(elm2)->field.tqe_prev = (elm)->field.tqe_prev; \
*(elm2)->field.tqe_prev = (elm2); \
_Q_INVALIDATE((elm)->field.tqe_prev); \
_Q_INVALIDATE((elm)->field.tqe_next); \
} while (0)
/*
* Circular queue definitions.
*/
#define CIRCLEQ_HEAD(name, type) \
struct name { \
struct type *cqh_first; /* first element */ \
struct type *cqh_last; /* last element */ \
}
#define CIRCLEQ_HEAD_INITIALIZER(head) \
{ CIRCLEQ_END(&head), CIRCLEQ_END(&head) }
#define CIRCLEQ_ENTRY(type) \
struct { \
struct type *cqe_next; /* next element */ \
struct type *cqe_prev; /* previous element */ \
}
/*
* Circular queue access methods
*/
#define CIRCLEQ_FIRST(head) ((head)->cqh_first)
#define CIRCLEQ_LAST(head) ((head)->cqh_last)
#define CIRCLEQ_END(head) ((void *)(head))
#define CIRCLEQ_NEXT(elm, field) ((elm)->field.cqe_next)
#define CIRCLEQ_PREV(elm, field) ((elm)->field.cqe_prev)
#define CIRCLEQ_EMPTY(head) \
(CIRCLEQ_FIRST(head) == CIRCLEQ_END(head))
#define CIRCLEQ_FOREACH(var, head, field) \
for((var) = CIRCLEQ_FIRST(head); \
(var) != CIRCLEQ_END(head); \
(var) = CIRCLEQ_NEXT(var, field))
#define CIRCLEQ_FOREACH_REVERSE(var, head, field) \
for((var) = CIRCLEQ_LAST(head); \
(var) != CIRCLEQ_END(head); \
(var) = CIRCLEQ_PREV(var, field))
/*
* Circular queue functions.
*/
#define CIRCLEQ_INIT(head) do { \
(head)->cqh_first = CIRCLEQ_END(head); \
(head)->cqh_last = CIRCLEQ_END(head); \
} while (0)
#define CIRCLEQ_INSERT_AFTER(head, listelm, elm, field) do { \
(elm)->field.cqe_next = (listelm)->field.cqe_next; \
(elm)->field.cqe_prev = (listelm); \
if ((listelm)->field.cqe_next == CIRCLEQ_END(head)) \
(head)->cqh_last = (elm); \
else \
(listelm)->field.cqe_next->field.cqe_prev = (elm); \
(listelm)->field.cqe_next = (elm); \
} while (0)
#define CIRCLEQ_INSERT_BEFORE(head, listelm, elm, field) do { \
(elm)->field.cqe_next = (listelm); \
(elm)->field.cqe_prev = (listelm)->field.cqe_prev; \
if ((listelm)->field.cqe_prev == CIRCLEQ_END(head)) \
(head)->cqh_first = (elm); \
else \
(listelm)->field.cqe_prev->field.cqe_next = (elm); \
(listelm)->field.cqe_prev = (elm); \
} while (0)
#define CIRCLEQ_INSERT_HEAD(head, elm, field) do { \
(elm)->field.cqe_next = (head)->cqh_first; \
(elm)->field.cqe_prev = CIRCLEQ_END(head); \
if ((head)->cqh_last == CIRCLEQ_END(head)) \
(head)->cqh_last = (elm); \
else \
(head)->cqh_first->field.cqe_prev = (elm); \
(head)->cqh_first = (elm); \
} while (0)
#define CIRCLEQ_INSERT_TAIL(head, elm, field) do { \
(elm)->field.cqe_next = CIRCLEQ_END(head); \
(elm)->field.cqe_prev = (head)->cqh_last; \
if ((head)->cqh_first == CIRCLEQ_END(head)) \
(head)->cqh_first = (elm); \
else \
(head)->cqh_last->field.cqe_next = (elm); \
(head)->cqh_last = (elm); \
} while (0)
#define CIRCLEQ_REMOVE(head, elm, field) do { \
if ((elm)->field.cqe_next == CIRCLEQ_END(head)) \
(head)->cqh_last = (elm)->field.cqe_prev; \
else \
(elm)->field.cqe_next->field.cqe_prev = \
(elm)->field.cqe_prev; \
if ((elm)->field.cqe_prev == CIRCLEQ_END(head)) \
(head)->cqh_first = (elm)->field.cqe_next; \
else \
(elm)->field.cqe_prev->field.cqe_next = \
(elm)->field.cqe_next; \
_Q_INVALIDATE((elm)->field.cqe_prev); \
_Q_INVALIDATE((elm)->field.cqe_next); \
} while (0)
#define CIRCLEQ_REPLACE(head, elm, elm2, field) do { \
if (((elm2)->field.cqe_next = (elm)->field.cqe_next) == \
CIRCLEQ_END(head)) \
(head)->cqh_last = (elm2); \
else \
(elm2)->field.cqe_next->field.cqe_prev = (elm2); \
if (((elm2)->field.cqe_prev = (elm)->field.cqe_prev) == \
CIRCLEQ_END(head)) \
(head)->cqh_first = (elm2); \
else \
(elm2)->field.cqe_prev->field.cqe_next = (elm2); \
_Q_INVALIDATE((elm)->field.cqe_prev); \
_Q_INVALIDATE((elm)->field.cqe_next); \
} while (0)
#endif /* !_SYS_QUEUE_H_ */

View File

@ -1,153 +0,0 @@
// vim:ts=8:expandtab
#include <sys/stat.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <ctype.h>
#include <glob.h>
#include "i3status.h"
int highest_order = 0;
/*
* Reads the configuration from the given file
*
*/
int load_configuration(const char *configfile) {
#define OPT(x) else if (strcasecmp(dest_name, x) == 0)
/* check if the file exists */
struct stat buf;
if (stat(configfile, &buf) < 0)
return -1;
int result = 0;
FILE *handle = fopen(configfile, "r");
if (handle == NULL)
die("Could not open configfile\n");
char dest_name[512], dest_value[512], whole_buffer[1026];
while (!feof(handle)) {
char *ret;
if ((ret = fgets(whole_buffer, 1024, handle)) == whole_buffer) {
/* sscanf implicitly strips whitespace */
if (sscanf(whole_buffer, "%s %[^\n]", dest_name, dest_value) < 1)
continue;
} else if (ret != NULL)
die("Could not read line in configuration file\n");
/* skip comments and empty lines */
if (dest_name[0] == '#' || strlen(dest_name) < 3)
continue;
OPT("wlan")
wlan_interface = strdup(dest_value);
OPT("eth")
eth_interface = strdup(dest_value);
OPT("time_format")
time_format = strdup(dest_value);
OPT("battery") {
struct battery *new = calloc(1, sizeof(struct battery));
if (new == NULL)
die("Could not allocate memory\n");
if (asprintf(&(new->path), "/sys/class/power_supply/BAT%d/uevent", atoi(dest_value)) == -1)
die("Could not build battery path\n");
/* check if flags were specified for this battery */
if (strstr(dest_value, ",") != NULL) {
char *flags = strstr(dest_value, ",");
flags++;
if (*flags == 'f')
new->use_last_full = true;
}
SIMPLEQ_INSERT_TAIL(&batteries, new, batteries);
} OPT("color")
use_colors = true;
OPT("get_ipv6")
get_ipv6 = true;
OPT("get_ethspeed")
get_ethspeed = true;
OPT("get_cpu_temperature") {
get_cpu_temperature = true;
int zone = 0;
if (strlen(dest_value) > 0)
zone = atoi(dest_value);
if (asprintf(&thermal_zone, THERMAL_ZONE, zone) == -1)
die("Could not build thermal_zone path\n");
} OPT("normcolors")
wmii_normcolors = strdup(dest_value);
OPT("interval")
interval = atoi(dest_value);
OPT("wmii_path")
{
#if !defined(DZEN) && !defined(XMOBAR)
static glob_t globbuf;
struct stat stbuf;
if (glob(dest_value, GLOB_NOCHECK | GLOB_TILDE, NULL, &globbuf) < 0)
die("glob() failed\n");
wmii_path = strdup(globbuf.gl_pathc > 0 ? globbuf.gl_pathv[0] : dest_value);
globfree(&globbuf);
if ((stat(wmii_path, &stbuf)) == -1) {
fprintf(stderr, "Warning: wmii_path contains an invalid path\n");
free(wmii_path);
wmii_path = strdup(dest_value);
}
if (wmii_path[strlen(wmii_path)-1] != '/')
die("wmii_path is not terminated by /\n");
#endif
}
OPT("run_watch")
{
char *name = strdup(dest_value);
char *path = name;
while (*path != ' ')
path++;
*(path++) = '\0';
num_run_watches += 2;
run_watches = realloc(run_watches, sizeof(char*) * num_run_watches);
run_watches[num_run_watches-2] = name;
run_watches[num_run_watches-1] = path;
}
OPT("order")
{
for (int c = 0; c < MAX_ORDER; c++)
order[c] = -1;
#define SET_ORDER(opt, idx) { if (strcasecmp(token, opt) == 0) order[idx] = highest_order++; }
char *walk, *token;
walk = token = dest_value;
while (*walk != '\0') {
while ((*walk != ',') && (*walk != '\0'))
walk++;
*(walk++) = '\0';
SET_ORDER("run", ORDER_RUN);
SET_ORDER("ipv6", ORDER_IPV6);
SET_ORDER("wlan", ORDER_WLAN);
SET_ORDER("eth", ORDER_ETH);
SET_ORDER("battery", ORDER_BATTERY);
SET_ORDER("cpu_temperature", ORDER_CPU_TEMPERATURE);
SET_ORDER("load", ORDER_LOAD);
SET_ORDER("time", ORDER_TIME);
token = walk;
while (isspace((int)(*token)))
token++;
}
}
else
{
result = -2;
die("Unknown configfile option: %s\n", dest_name);
}
}
fclose(handle);
#if !defined(DZEN) && !defined(XMOBAR)
if (wmii_path == NULL)
exit(EXIT_FAILURE);
#endif
return result;
}

View File

@ -53,21 +53,6 @@ void die(const char *fmt, ...) {
(void)vsnprintf(buffer, sizeof(buffer), fmt, ap);
va_end(ap);
if (wmii_path != NULL)
write_error_to_statusbar(buffer);
else
fprintf(stderr, "%s", buffer);
exit(EXIT_FAILURE);
}
/*
* This function just concats two strings in place, it should only be used
* for concatting order to the name of a file or concatting color codes.
* Otherwise, the buffer size would have to be increased.
*
*/
char *order_to_str(int number, char *name) {
static char buf[32];
(void)snprintf(buf, sizeof(buf), "%d%s", number, name);
return buf;
}

View File

@ -1,44 +0,0 @@
// vim:ts=8:expandtab
#include <stdlib.h>
#include <limits.h>
#include <stdio.h>
#include "i3status.h"
#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
#include <err.h>
#include <sys/types.h>
#include <sys/sysctl.h>
#define TZ_ZEROC 2732
#define TZ_KELVTOC(x) (((x) - TZ_ZEROC) / 10), abs(((x) - TZ_ZEROC) % 10)
#endif
/*
* Reads the CPU temperature from /sys/class/thermal/thermal_zone0/temp and
* returns the temperature in degree celcius.
*
*/
const char *get_cpu_temperature_info() {
static char buf[16];
#if defined(LINUX)
long int temp;
if (!slurp(thermal_zone, buf, sizeof(buf)))
die("Could not open \"%s\"\n", thermal_zone);
temp = strtol(buf, NULL, 10);
if (temp == LONG_MIN || temp == LONG_MAX || temp <= 0)
(void)snprintf(buf, sizeof(buf), "T: ? C");
else
(void)snprintf(buf, sizeof(buf), "T: %ld C", (temp/1000));
#elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
int sysctl_rslt;
size_t sysctl_size = sizeof (sysctl_rslt);
if (sysctlbyname(thermal_zone,&sysctl_rslt,&sysctl_size,NULL,0))
return "No Thermal";
snprintf(buf,sizeof(buf),"T: %d.%d C",TZ_KELVTOC(sysctl_rslt));
#endif
return buf;
}

View File

@ -1,88 +0,0 @@
// vim:ts=8:expandtab
#include <string.h>
#include <limits.h>
#include <stdio.h>
#include <sys/ioctl.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <net/if.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include "i3status.h"
#if defined(LINUX)
#include <linux/ethtool.h>
#include <linux/sockios.h>
#define PART_ETHSPEED "E: %s (%d Mbit/s)"
#endif
#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
#include <net/if_media.h>
#define IFM_TYPE_MATCH(dt, t) \
(IFM_TYPE((dt)) == 0 || IFM_TYPE((dt)) == IFM_TYPE((t)))
#define PART_ETHSPEED "E: %s (%s)"
#endif
/*
* Combines ethernet IP addresses and speed (if requested) for displaying
*
*/
const char *get_eth_info() {
static char part[512];
#if defined(LINUX)
int ethspeed=0;
#elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
char *ethspeed;
#endif
const char *ip_address = get_ip_addr(eth_interface);
if (ip_address == NULL) {
(void)snprintf(part, sizeof(part), "E: down");
return part;
}
if (get_ethspeed) {
#if defined(LINUX)
/* This code path requires root privileges */
struct ifreq ifr;
struct ethtool_cmd ecmd;
ecmd.cmd = ETHTOOL_GSET;
(void)memset(&ifr, 0, sizeof(ifr));
ifr.ifr_data = (caddr_t)&ecmd;
(void)strcpy(ifr.ifr_name, eth_interface);
if (ioctl(general_socket, SIOCETHTOOL, &ifr) == 0)
ethspeed = (ecmd.speed == USHRT_MAX ? 0 : ecmd.speed);
else get_ethspeed = false;
#elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
struct ifmediareq ifm;
(void)memset(&ifm, 0, sizeof(ifm));
(void)strncpy(ifm.ifm_name, eth_interface, sizeof(ifm.ifm_name));
int ret = ioctl(general_socket, SIOCGIFMEDIA, (caddr_t)&ifm);
/* Get the description of the media type, partially taken from
* FreeBSD's ifconfig */
const struct ifmedia_description *desc;
struct ifmedia_description ifm_subtype_descriptions[] =
IFM_SUBTYPE_ETHERNET_DESCRIPTIONS;
for (desc = ifm_subtype_descriptions;
desc->ifmt_string != NULL;
desc++) {
if (IFM_TYPE_MATCH(desc->ifmt_word, ifm.ifm_active) &&
IFM_SUBTYPE(desc->ifmt_word) == IFM_SUBTYPE(ifm.ifm_active))
break;
}
ethspeed = (desc->ifmt_string != NULL ? desc->ifmt_string : "?");
#endif
}
if (get_ethspeed)
(void)snprintf(part, sizeof(part), PART_ETHSPEED, ip_address, ethspeed);
else (void)snprintf(part, sizeof(part), "E: %s", ip_address);
return part;
}

View File

@ -1,22 +0,0 @@
// vim:ts=8:expandtab
#include "i3status.h"
#include <err.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
const char *get_load() {
static char part[512];
/* Get load */
#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(linux) || defined(__OpenBSD__) || defined(__NetBSD__) || defined(__APPLE__) || defined(sun)
double loadavg[3];
if (getloadavg(loadavg, 3) == -1)
errx(-1, "getloadavg() failed\n");
(void)snprintf(part, sizeof(part), "%1.2f %1.2f %1.2f", loadavg[0], loadavg[1], loadavg[2]);
#else
part[0] = '\0';
#endif
return part;
}

View File

@ -1,64 +0,0 @@
// vim:ts=8:expandtab
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <limits.h>
#include <iwlib.h>
#include "i3status.h"
const char *get_wireless_essid() {
static char part[512];
#ifdef LINUX
int skfd;
if ((skfd = iw_sockets_open()) < 0) {
perror("socket");
exit(-1);
}
struct wireless_config cfg;
if (iw_get_basic_config(skfd, wlan_interface, &cfg) >= 0)
snprintf(part, sizeof(part), "%s", cfg.essid);
else part[0] = '\0';
(void)close(skfd);
#else
part[0] = '\0';
#endif
return part;
}
/*
* Just parses /proc/net/wireless looking for lines beginning with
* wlan_interface, extracting the quality of the link and adding the
* current IP address of wlan_interface.
*
*/
const char *get_wireless_info() {
char buf[1024];
static char part[512];
char *interfaces;
memset(buf, 0, sizeof(buf));
memset(part, 0, sizeof(part));
if (!slurp("/proc/net/wireless", buf, sizeof(buf)))
die("Could not open \"/proc/net/wireless\"\n");
interfaces = skip_character(buf, '\n', 1) + 1;
while ((interfaces = skip_character(interfaces, '\n', 1)+1) < buf+strlen(buf)) {
while (isspace((int)*interfaces))
interfaces++;
if (!BEGINS_WITH(interfaces, wlan_interface))
continue;
int quality;
if (sscanf(interfaces, "%*[^:]: 0000 %d", &quality) != 1)
continue;
if ((quality == UCHAR_MAX) || (quality == 0)) {
(void)snprintf(part, sizeof(part), "%sW: down%s", color("#FF0000"), endcolor());
} else (void)snprintf(part, sizeof(part), "%sW: (%03d%% at %s) %s%s",
color("#00FF00"), quality, get_wireless_essid(), get_ip_addr(wlan_interface), endcolor());
return part;
}
return part;
}

View File

@ -11,22 +11,12 @@
#include "i3status.h"
/*
* Writes an errormessage to statusbar
*
*/
void write_error_to_statusbar(const char *message) {
cleanup_rbar_dir();
create_file("error");
write_to_statusbar("error", message, true);
}
/*
* Returns the correct color format for dzen (^fg(color)) or wmii (color <normcolors>)
* Returns the correct color format for dzen (^fg(color)) or xmobar (<fc=color>)
*
*/
char *color(const char *colorstr) {
static char colorbuf[32];
if (!use_colors) {
if (!cfg_getbool(cfg_general, "colors")) {
colorbuf[0] = '\0';
return colorbuf;
}
@ -34,8 +24,6 @@ char *color(const char *colorstr) {
(void)snprintf(colorbuf, sizeof(colorbuf), "^fg(%s)", colorstr);
#elif XMOBAR
(void)snprintf(colorbuf, sizeof(colorbuf), "<fc=%s>", colorstr);
#else
(void)snprintf(colorbuf, sizeof(colorbuf), "%s %s ", colorstr, wmii_normcolors);
#endif
return colorbuf;
}
@ -52,142 +40,8 @@ char *endcolor() {
#endif
}
/*
* Cleans wmii's /rbar directory by deleting all regular files
*
*/
void cleanup_rbar_dir() {
void print_seperator() {
#if defined(DZEN) || defined(XMOBAR)
return;
printf("%s", BAR);
#endif
struct dirent *ent;
DIR *dir;
char pathbuf[strlen(wmii_path)+256+1];
if ((dir = opendir(wmii_path)) == NULL)
exit(EXIT_FAILURE);
while ((ent = readdir(dir)) != NULL) {
if (ent->d_type == DT_REG) {
(void)snprintf(pathbuf, sizeof(pathbuf), "%s%s", wmii_path, ent->d_name);
if (unlink(pathbuf) == -1)
exit(EXIT_FAILURE);
}
}
(void)closedir(dir);
}
/*
* Creates the specified file in wmii's /rbar directory with
* correct modes and initializes colors if colormode is enabled
*
*/
void create_file(const char *name) {
#if defined(DZEN) || defined(XMOBAR)
return;
#endif
char pathbuf[strlen(wmii_path)+256+1];
int fd;
int flags = O_CREAT | O_WRONLY;
struct stat statbuf;
(void)snprintf(pathbuf, sizeof(pathbuf), "%s%s", wmii_path, name);
/* Overwrite file's contents if it exists */
if (stat(pathbuf, &statbuf) >= 0)
flags |= O_TRUNC;
if ((fd = open(pathbuf, flags, S_IRUSR | S_IWUSR)) < 0)
exit(EXIT_FAILURE);
if (use_colors) {
char *tmp = color("#888888");
if (write(fd, tmp, strlen(tmp)) != (ssize_t)strlen(tmp))
exit(EXIT_FAILURE);
}
(void)close(fd);
}
/*
* Waits until wmii_path/rbar exists (= the filesystem gets mounted),
* cleans up all files and creates the needed files
*
*/
void setup(void) {
unsigned int i;
char pathbuf[512];
#if !defined(DZEN) && !defined(XMOBAR)
struct stat statbuf;
/* Wait until wmii_path/rbar exists */
for (; stat(wmii_path, &statbuf) < 0; sleep(interval));
#endif
#define cf(orderidx, name) create_file(order_to_str(order[orderidx], name));
cleanup_rbar_dir();
if (wlan_interface)
cf(ORDER_WLAN, "wlan");
if (eth_interface)
cf(ORDER_ETH, "eth");
if (get_cpu_temperature)
cf(ORDER_CPU_TEMPERATURE, "cpu_temperature");
cf(ORDER_LOAD, "load");
if (time_format)
cf(ORDER_TIME, "time");
for (i = 0; i < num_run_watches; i += 2) {
snprintf(pathbuf, sizeof(pathbuf), "%d%s", order[ORDER_RUN], run_watches[i]);
create_file(pathbuf);
}
}
/*
* Writes the given message in the corresponding file in wmii's /rbar directory
*
*/
void write_to_statusbar(const char *name, const char *message, bool final_entry) {
#ifdef DZEN
if (final_entry) {
if (printf("%s^p(6)\n", message) < 0) {
perror("printf");
exit(1);
}
fflush(stdout);
return;
}
if (printf("%s" BAR, message) < 0) {
perror("printf");
exit(1);
}
return;
#elif XMOBAR
if (final_entry) {
if (printf("%s\n", message) < 0) {
perror("printf");
exit(1);
}
fflush(stdout);
return;
}
if (printf("%s" BAR, message) < 0) {
perror("printf");
exit(1);
}
return;
#endif
char pathbuf[strlen(wmii_path)+256+1];
int fd;
(void)snprintf(pathbuf, sizeof(pathbuf), "%s%s", wmii_path, name);
if ((fd = open(pathbuf, O_RDWR)) == -1) {
/* Try to re-setup stuff and just continue */
setup();
return;
}
if (write(fd, message, strlen(message)) != (ssize_t)strlen(message))
exit(EXIT_FAILURE);
(void)close(fd);
}

View File

@ -16,9 +16,8 @@
* worn off your battery is.
*
*/
const char *get_battery_info(struct battery *bat) {
void print_battery_info(int number, const char *format) {
char buf[1024];
static char part[512];
char *walk, *last;
int full_design = -1,
remaining = -1,
@ -26,8 +25,12 @@ const char *get_battery_info(struct battery *bat) {
charging_status_t status = CS_DISCHARGING;
#if defined(LINUX)
if (!slurp(bat->path, buf, sizeof(buf)))
return "No battery";
static char batpath[512];
sprintf(batpath, "/sys/class/power_supply/BAT%d/uevent", number);
if (!slurp(batpath, buf, sizeof(buf))) {
printf("No battery");
return;
}
for (walk = buf, last = buf; (walk-buf) < 1024; walk++) {
if (*walk == '\n') {
@ -49,22 +52,24 @@ const char *get_battery_info(struct battery *bat) {
status = CS_FULL;
else {
/* The only thing left is the full capacity */
#if 0
if (bat->use_last_full) {
if (!BEGINS_WITH(last, "POWER_SUPPLY_ENERGY_FULL") &&
!BEGINS_WITH(last, "POWER_SUPPLY_CHARGE_FULL"))
continue;
} else {
#endif
if (!BEGINS_WITH(last, "POWER_SUPPLY_CHARGE_FULL_DESIGN") &&
!BEGINS_WITH(last, "POWER_SUPPLY_ENERGY_FULL_DESIGN"))
continue;
}
//}
full_design = atoi(walk+1);
}
}
if ((full_design == 1) || (remaining == -1))
return part;
return;
if (present_rate > 0) {
float remaining_time;
@ -81,13 +86,13 @@ const char *get_battery_info(struct battery *bat) {
minutes = seconds / 60;
seconds -= (minutes * 60);
(void)snprintf(part, sizeof(part), "%s %.02f%% %02d:%02d:%02d",
(void)printf("%s %.02f%% %02d:%02d:%02d",
(status == CS_CHARGING ? "CHR" :
(status == CS_DISCHARGING ? "BAT" : "FULL")),
(((float)remaining / (float)full_design) * 100),
max(hours, 0), max(minutes, 0), max(seconds, 0));
} else {
(void)snprintf(part, sizeof(part), "%s %.02f%%",
(void)printf("%s %.02f%%",
(status == CS_CHARGING ? "CHR" :
(status == CS_DISCHARGING ? "BAT" : "FULL")),
(((float)remaining / (float)full_design) * 100));
@ -97,16 +102,22 @@ const char *get_battery_info(struct battery *bat) {
int sysctl_rslt;
size_t sysctl_size = sizeof(sysctl_rslt);
if (sysctlbyname(BATT_LIFE, &sysctl_rslt, &sysctl_size, NULL, 0) != 0)
return "No battery";
if (sysctlbyname(BATT_LIFE, &sysctl_rslt, &sysctl_size, NULL, 0) != 0) {
printf("No battery");
return;
}
present_rate = sysctl_rslt;
if (sysctlbyname(BATT_TIME, &sysctl_rslt, &sysctl_size, NULL, 0) != 0)
return "No battery";
if (sysctlbyname(BATT_TIME, &sysctl_rslt, &sysctl_size, NULL, 0) != 0) {
printf("No battery");
return;
}
remaining = sysctl_rslt;
if (sysctlbyname(BATT_STATE, &sysctl_rslt, &sysctl_size, NULL,0) != 0)
return "No battery";
if (sysctlbyname(BATT_STATE, &sysctl_rslt, &sysctl_size, NULL,0) != 0) {
printf("No battery");
return;
}
state = sysctl_rslt;
if (state == 0 && present_rate == 100)
@ -123,17 +134,16 @@ const char *get_battery_info(struct battery *bat) {
minutes = remaining;
hours = minutes / 60;
minutes -= (hours * 60);
(void)snprintf(part, sizeof(part), "%s %02d%% %02dh%02d",
(void)printf("%s %02d%% %02dh%02d",
(status == CS_CHARGING ? "CHR" :
(status == CS_DISCHARGING ? "BAT" : "FULL")),
present_rate,
max(hours, 0), max(minutes, 0));
} else {
(void)snprintf(part, sizeof(part), "%s %02d%%",
(void)printf("%s %02d%%",
(status == CS_CHARGING ? "CHR" :
(status == CS_DISCHARGING ? "BAT" : "FULL")),
present_rate);
}
#endif
return part;
}

View File

@ -0,0 +1,59 @@
// vim:ts=8:expandtab
#include <stdlib.h>
#include <limits.h>
#include <stdio.h>
#include <string.h>
#include "i3status.h"
#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
#include <err.h>
#include <sys/types.h>
#include <sys/sysctl.h>
#define TZ_ZEROC 2732
#define TZ_KELVTOC(x) (((x) - TZ_ZEROC) / 10), abs(((x) - TZ_ZEROC) % 10)
#endif
static char *thermal_zone;
/*
* Reads the CPU temperature from /sys/class/thermal/thermal_zone0/temp and
* returns the temperature in degree celcius.
*
*/
void print_cpu_temperature_info(int zone, const char *format) {
const char *walk;
static char buf[16];
asprintf(&thermal_zone, THERMAL_ZONE, zone);
for (walk = format; *walk != '\0'; walk++) {
if (*walk != '%') {
putchar(*walk);
continue;
}
if (BEGINS_WITH(walk+1, "degrees")) {
#if defined(LINUX)
long int temp;
if (!slurp(thermal_zone, buf, sizeof(buf)))
die("Could not open \"%s\"\n", thermal_zone);
temp = strtol(buf, NULL, 10);
if (temp == LONG_MIN || temp == LONG_MAX || temp <= 0)
(void)printf("?");
else
(void)printf("%ld", (temp/1000));
#elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
int sysctl_rslt;
size_t sysctl_size = sizeof(sysctl_rslt);
if (sysctlbyname(thermal_zone, &sysctl_rslt, &sysctl_size, NULL, 0)) {
(void)printf("No thermal zone found");
return;
}
(void)printf("%d.%d", TZ_KELVTOC(sysctl_rslt));
#endif
walk += strlen("degrees");
}
}
}

95
src/print_eth_info.c Normal file
View File

@ -0,0 +1,95 @@
// vim:ts=8:expandtab
#include <string.h>
#include <limits.h>
#include <stdio.h>
#include <sys/ioctl.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <net/if.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include "i3status.h"
#if defined(LINUX)
#include <linux/ethtool.h>
#include <linux/sockios.h>
#define PART_ETHSPEED "E: %s (%d Mbit/s)"
#endif
#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
#include <net/if_media.h>
#define IFM_TYPE_MATCH(dt, t) \
(IFM_TYPE((dt)) == 0 || IFM_TYPE((dt)) == IFM_TYPE((t)))
#define PART_ETHSPEED "E: %s (%s)"
#endif
static void print_eth_speed(const char *interface) {
#if defined(LINUX)
int ethspeed = 0;
#elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
char *ethspeed;
#endif
#if defined(LINUX)
/* This code path requires root privileges */
struct ifreq ifr;
struct ethtool_cmd ecmd;
ecmd.cmd = ETHTOOL_GSET;
(void)memset(&ifr, 0, sizeof(ifr));
ifr.ifr_data = (caddr_t)&ecmd;
(void)strcpy(ifr.ifr_name, interface);
if (ioctl(general_socket, SIOCETHTOOL, &ifr) == 0) {
ethspeed = (ecmd.speed == USHRT_MAX ? 0 : ecmd.speed);
printf("%d Mbit/s", ethspeed);
} else printf("?");
#elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
struct ifmediareq ifm;
(void)memset(&ifm, 0, sizeof(ifm));
(void)strncpy(ifm.ifm_name, interface, sizeof(ifm.ifm_name));
int ret = ioctl(general_socket, SIOCGIFMEDIA, (caddr_t)&ifm);
/* Get the description of the media type, partially taken from
* FreeBSD's ifconfig */
const struct ifmedia_description *desc;
struct ifmedia_description ifm_subtype_descriptions[] =
IFM_SUBTYPE_ETHERNET_DESCRIPTIONS;
for (desc = ifm_subtype_descriptions;
desc->ifmt_string != NULL;
desc++) {
if (IFM_TYPE_MATCH(desc->ifmt_word, ifm.ifm_active) &&
IFM_SUBTYPE(desc->ifmt_word) == IFM_SUBTYPE(ifm.ifm_active))
break;
}
ethspeed = (desc->ifmt_string != NULL ? desc->ifmt_string : "?");
printf("%s", ethspeed);
#endif
}
/*
* Combines ethernet IP addresses and speed (if requested) for displaying
*
*/
void print_eth_info(const char *interface, const char *format) {
const char *walk;
const char *ip_address = get_ip_addr(interface);
for (walk = format; *walk != '\0'; walk++) {
if (*walk != '%') {
putchar(*walk);
continue;
}
if (strncmp(walk+1, "ip", strlen("ip")) == 0) {
printf("%s", ip_address);
walk += strlen("ip");
} else if (strncmp(walk+1, "speed", strlen("speed")) == 0) {
print_eth_speed(interface);
walk += strlen("speed");
}
}
}

View File

@ -12,7 +12,7 @@
* Returns the IPv6 address with which you have connectivity at the moment.
*
*/
const char *get_ipv6_addr() {
static void print_ipv6_addr() {
static char buf[INET6_ADDRSTRLEN+1];
struct addrinfo hints;
struct addrinfo *result, *resp;
@ -28,7 +28,8 @@ const char *get_ipv6_addr() {
/* We dont display the error here because most
* likely, there just is no connectivity.
* Thus, dont spam the users console. */
return "no IPv6";
printf("no IPv6");
return;
}
for (resp = result; resp != NULL; resp = resp->ai_next) {
@ -56,7 +57,8 @@ const char *get_ipv6_addr() {
if (getsockname(fd, (struct sockaddr*)&local, &local_len) == -1) {
perror("getsockname()");
(void)close(fd);
return "no IPv6";
printf("no IPv6");
return;
}
(void)close(fd);
@ -67,13 +69,31 @@ const char *get_ipv6_addr() {
buf, sizeof(buf), NULL, 0,
NI_NUMERICHOST)) != 0) {
fprintf(stderr, "getnameinfo(): %s\n", gai_strerror(ret));
return "no IPv6";
printf("no IPv6");
return;
}
free(result);
return buf;
printf("%s", buf);
return;
}
free(result);
return "no IPv6";
printf("no IPv6");
}
void print_ipv6_info(const char *format) {
const char *walk;
for (walk = format; *walk != '\0'; walk++) {
if (*walk != '%') {
putchar(*walk);
continue;
}
if (strncmp(walk+1, "ip", strlen("ip")) == 0) {
print_ipv6_addr();
walk += strlen("ip");
}
}
}

39
src/print_load.c Normal file
View File

@ -0,0 +1,39 @@
// vim:ts=8:expandtab
#include "i3status.h"
#include <err.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
void print_load(const char *format) {
/* Get load */
#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(linux) || defined(__OpenBSD__) || defined(__NetBSD__) || defined(__APPLE__) || defined(sun)
double loadavg[3];
const char *walk;
if (getloadavg(loadavg, 3) == -1)
errx(-1, "getloadavg() failed\n");
for (walk = format; *walk != '\0'; walk++) {
if (*walk != '%') {
putchar(*walk);
continue;
}
if (BEGINS_WITH(walk+1, "5min")) {
(void)printf("%1.2f", loadavg[0]);
walk += strlen("5min");
}
if (BEGINS_WITH(walk+1, "10min")) {
(void)printf("%1.2f", loadavg[1]);
walk += strlen("10min");
}
if (BEGINS_WITH(walk+1, "15min")) {
(void)printf("%1.2f", loadavg[2]);
walk += strlen("15min");
}
}
#endif
}

10
src/print_run_watch.c Normal file
View File

@ -0,0 +1,10 @@
#include <stdio.h>
#include "i3status.h"
void print_run_watch(const char *title, const char *pidfile, const char *format) {
bool running = process_runs(pidfile);
printf("%s%s: %s%s",
(running ? color("#00FF00") : color("#FF0000")),
title,
(running ? "yes" : "no"), endcolor());
}

13
src/print_time.c Normal file
View File

@ -0,0 +1,13 @@
// vim:ts=8:expandtab
#include <time.h>
#include <stdio.h>
#include <stdlib.h>
void print_time(const char *format) {
static char part[512];
/* Get date & time */
time_t current_time = time(NULL);
struct tm *current_tm = localtime(&current_time);
(void)strftime(part, sizeof(part), format, current_tm);
printf("%s", part);
}

92
src/print_wireless_info.c Normal file
View File

@ -0,0 +1,92 @@
// vim:ts=8:expandtab
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <limits.h>
#include <iwlib.h>
#include "i3status.h"
static const char *get_wireless_essid(const char *interface) {
static char part[512];
#ifdef LINUX
int skfd;
if ((skfd = iw_sockets_open()) < 0) {
perror("socket");
exit(-1);
}
struct wireless_config wcfg;
if (iw_get_basic_config(skfd, interface, &wcfg) >= 0)
snprintf(part, sizeof(part), "%s", wcfg.essid);
else part[0] = '\0';
(void)close(skfd);
#else
part[0] = '\0';
#endif
return part;
}
/*
* Just parses /proc/net/wireless looking for lines beginning with
* wlan_interface, extracting the quality of the link and adding the
* current IP address of wlan_interface.
*
*/
void print_wireless_info(const char *interface, const char *format_up, const char *format_down) {
char buf[1024];
int quality = -1;
char *interfaces;
const char *walk;
memset(buf, 0, sizeof(buf));
if (!slurp("/proc/net/wireless", buf, sizeof(buf)))
die("Could not open \"/proc/net/wireless\"\n");
interfaces = skip_character(buf, '\n', 1) + 1;
while ((interfaces = skip_character(interfaces, '\n', 1)+1) < buf+strlen(buf)) {
while (isspace((int)*interfaces))
interfaces++;
if (!BEGINS_WITH(interfaces, interface))
continue;
if (sscanf(interfaces, "%*[^:]: 0000 %d", &quality) != 1)
continue;
break;
}
/* Interface could not be found */
if (quality == -1)
return;
if ((quality == UCHAR_MAX) || (quality == 0)) {
walk = format_down;
printf("%s", color("#FF0000"));
} else {
printf("%s", color("#00FF00"));
walk = format_up;
}
for (; *walk != '\0'; walk++) {
if (*walk != '%') {
putchar(*walk);
continue;
}
if (BEGINS_WITH(walk+1, "quality")) {
(void)printf("%03d%%", quality);
walk += strlen("quality");
}
if (BEGINS_WITH(walk+1, "essid")) {
(void)printf("%s", get_wireless_essid(interface));
walk += strlen("essid");
}
if (BEGINS_WITH(walk+1, "ip")) {
(void)printf("%s", get_ip_addr(interface));
walk += strlen("ip");
}
}
(void)printf("%s", endcolor());
}