Blame alsamixer/configparser.c

Packit Service a9274b
#include <stdio.h>
Packit Service a9274b
#include <stdlib.h>
Packit Service a9274b
#include <string.h>
Packit Service a9274b
#include <unistd.h>
Packit Service a9274b
#include <inttypes.h>
Packit Service a9274b
#include <ctype.h>
Packit Service a9274b
#include <errno.h>
Packit Service a9274b
#include <pwd.h>
Packit Service a9274b
#include CURSESINC
Packit Service a9274b
#include "colors.h"
Packit Service a9274b
#include "gettext_curses.h"
Packit Service a9274b
#include "utils.h"
Packit Service a9274b
#include "curskey.h"
Packit Service a9274b
#include "bindings.h"
Packit Service a9274b
#include "mixer_widget.h"
Packit Service a9274b
Packit Service a9274b
#define ERROR_CONFIG (-1)
Packit Service a9274b
#define ERROR_MISSING_ARGUMENTS (-2)
Packit Service a9274b
#define ERROR_TOO_MUCH_ARGUMENTS (-3)
Packit Service a9274b
Packit Service a9274b
static const char *error_message;
Packit Service a9274b
static const char *error_cause;
Packit Service a9274b
Packit Service a9274b
static int strlist_index(const char *haystack, unsigned int itemlen, const char *needle) {
Packit Service a9274b
	unsigned int needle_len;
Packit Service a9274b
	unsigned int pos;
Packit Service a9274b
	const char *found;
Packit Service a9274b
Packit Service a9274b
	needle_len = strlen(needle);
Packit Service a9274b
	if (needle_len <= itemlen && needle[needle_len - 1] != ' ') {
Packit Service a9274b
		found = strstr(haystack, needle);
Packit Service a9274b
		if (found) {
Packit Service a9274b
			pos = (found - haystack);
Packit Service a9274b
			if (pos % itemlen == 0 && (needle_len == itemlen || haystack[pos+needle_len] == ' '))
Packit Service a9274b
				return pos / itemlen;
Packit Service a9274b
		}
Packit Service a9274b
	}
Packit Service a9274b
Packit Service a9274b
	return -1;
Packit Service a9274b
}
Packit Service a9274b
Packit Service a9274b
static int color_by_name(const char *name) {
Packit Service a9274b
	return strlist_index(
Packit Service a9274b
		"default"
Packit Service a9274b
		"black  "
Packit Service a9274b
		"red    "
Packit Service a9274b
		"green  "
Packit Service a9274b
		"yellow "
Packit Service a9274b
		"blue   "
Packit Service a9274b
		"magenta"
Packit Service a9274b
		"cyan   "
Packit Service a9274b
		"white  ", 7, name) - 1;
Packit Service a9274b
};
Packit Service a9274b
Packit Service a9274b
static int attr_by_name(const char *name) {
Packit Service a9274b
	return (int[]) {
Packit Service a9274b
		-1,
Packit Service a9274b
		A_BOLD,
Packit Service a9274b
		A_REVERSE,
Packit Service a9274b
		A_STANDOUT,
Packit Service a9274b
		A_DIM,
Packit Service a9274b
		A_UNDERLINE,
Packit Service a9274b
#ifdef A_ITALIC
Packit Service a9274b
		A_ITALIC,
Packit Service a9274b
#endif
Packit Service a9274b
		A_NORMAL,
Packit Service a9274b
		A_BLINK,
Packit Service a9274b
	}[strlist_index(
Packit Service a9274b
		"bold     "
Packit Service a9274b
		"reverse  "
Packit Service a9274b
		"standout "
Packit Service a9274b
		"dim      "
Packit Service a9274b
		"underline"
Packit Service a9274b
#ifdef A_ITALIC
Packit Service a9274b
		"italic   "
Packit Service a9274b
#endif
Packit Service a9274b
		"normal   "
Packit Service a9274b
		"blink    ", 9, name) + 1];
Packit Service a9274b
};
Packit Service a9274b
Packit Service a9274b
#define W_NUMBER (1U << 0)
Packit Service a9274b
Packit Service a9274b
enum textbox_word {
Packit Service a9274b
	TW_BOTTOM = (1U << 1),
Packit Service a9274b
	TW_CLOSE = (1U << 2),
Packit Service a9274b
	TW_DOWN = (1U << 3),
Packit Service a9274b
	TW_LEFT = (1U << 4),
Packit Service a9274b
	TW_PAGE = (1U << 5),
Packit Service a9274b
	TW_RIGHT = (1U << 6),
Packit Service a9274b
	TW_TOP = (1U << 7),
Packit Service a9274b
	TW_UP = (1U << 8),
Packit Service a9274b
};
Packit Service a9274b
Packit Service a9274b
const char *textbox_words =
Packit Service a9274b
	"bottom"
Packit Service a9274b
	"close "
Packit Service a9274b
	"down  "
Packit Service a9274b
	"left  "
Packit Service a9274b
	"page  "
Packit Service a9274b
	"right "
Packit Service a9274b
	"top   "
Packit Service a9274b
	"up    ";
Packit Service a9274b
Packit Service a9274b
enum mixer_word {
Packit Service a9274b
	MW_ALL = (1U << 1),
Packit Service a9274b
	MW_BALANCE = (1U << 2),
Packit Service a9274b
	MW_CAPTURE = (1U << 3),
Packit Service a9274b
	MW_CARD = (1U << 4),
Packit Service a9274b
	MW_CLOSE = (1U << 5),
Packit Service a9274b
	MW_CONTROL = (1U << 6),
Packit Service a9274b
	MW_DOWN = (1U << 7),
Packit Service a9274b
	MW_FOCUS = (1U << 8),
Packit Service a9274b
	MW_HELP = (1U << 9),
Packit Service a9274b
	MW_INFORMATION = (1U << 10),
Packit Service a9274b
	MW_LEFT = (1U << 11),
Packit Service a9274b
	MW_MODE = (1U << 12),
Packit Service a9274b
	MW_MUTE = (1U << 13),
Packit Service a9274b
	MW_NEXT = (1U << 14),
Packit Service a9274b
	MW_PLAYBACK = (1U << 15),
Packit Service a9274b
	MW_PREVIOUS = (1U << 16),
Packit Service a9274b
	MW_REFRESH = (1U << 17),
Packit Service a9274b
	MW_RIGHT = (1U << 18),
Packit Service a9274b
	MW_SELECT = (1U << 19),
Packit Service a9274b
	MW_SET = (1U << 20),
Packit Service a9274b
	MW_SYSTEM = (1U << 21),
Packit Service a9274b
	MW_TOGGLE = (1U << 22),
Packit Service a9274b
	MW_UP = (1U << 23),
Packit Service a9274b
};
Packit Service a9274b
Packit Service a9274b
const char *mixer_words =
Packit Service a9274b
	"all        "
Packit Service a9274b
	"balance    "
Packit Service a9274b
	"capture    "
Packit Service a9274b
	"card       "
Packit Service a9274b
	"close      "
Packit Service a9274b
	"control    "
Packit Service a9274b
	"down       "
Packit Service a9274b
	"focus      "
Packit Service a9274b
	"help       "
Packit Service a9274b
	"information"
Packit Service a9274b
	"left       "
Packit Service a9274b
	"mode       "
Packit Service a9274b
	"mute       "
Packit Service a9274b
	"next       "
Packit Service a9274b
	"playback   "
Packit Service a9274b
	"previous   "
Packit Service a9274b
	"refresh    "
Packit Service a9274b
	"right      "
Packit Service a9274b
	"select     "
Packit Service a9274b
	"set        "
Packit Service a9274b
	"system     "
Packit Service a9274b
	"toggle     "
Packit Service a9274b
	"up         ";
Packit Service a9274b
Packit Service a9274b
static unsigned int parse_words(const char *name, const char* wordlist, unsigned int itemlen, unsigned int *number) {
Packit Service a9274b
	unsigned int words = 0;
Packit Service a9274b
	unsigned int word;
Packit Service a9274b
	unsigned int i;
Packit Service a9274b
	char buf[16];
Packit Service a9274b
	char *endptr;
Packit Service a9274b
Packit Service a9274b
	while (*name) {
Packit Service a9274b
		for (i = 0; i < sizeof(buf) - 1; ++i) {
Packit Service a9274b
			if (*name == '\0')
Packit Service a9274b
				break;
Packit Service a9274b
			if (*name == '_') {
Packit Service a9274b
				++name;
Packit Service a9274b
				break;
Packit Service a9274b
			}
Packit Service a9274b
			buf[i] = *name;
Packit Service a9274b
			++name;
Packit Service a9274b
		}
Packit Service a9274b
		buf[i] = '\0';
Packit Service a9274b
Packit Service a9274b
		if (buf[0] >= '0' && buf[0] <= '9') {
Packit Service a9274b
			if (number) {
Packit Service a9274b
				*number = strtoumax(buf, &endptr, 10);
Packit Service a9274b
				if (*endptr != '\0')
Packit Service a9274b
					return 0;
Packit Service a9274b
			}
Packit Service a9274b
			word = W_NUMBER;
Packit Service a9274b
		}
Packit Service a9274b
		else if ((i = strlist_index(wordlist, itemlen, buf)) >= 0)
Packit Service a9274b
			word = 2U << i;
Packit Service a9274b
		else
Packit Service a9274b
			return 0;
Packit Service a9274b
Packit Service a9274b
		if (words & word) // no duplicate words
Packit Service a9274b
			return 0;
Packit Service a9274b
		words |= word;
Packit Service a9274b
	}
Packit Service a9274b
Packit Service a9274b
	return words;
Packit Service a9274b
}
Packit Service a9274b
Packit Service a9274b
static int textbox_command_by_name(const char *name) {
Packit Service a9274b
	switch (parse_words(name, textbox_words, 6, NULL)) {
Packit Service a9274b
		case TW_TOP: return CMD_TEXTBOX_TOP;
Packit Service a9274b
		case TW_BOTTOM: return CMD_TEXTBOX_BOTTOM;
Packit Service a9274b
		case TW_CLOSE: return CMD_TEXTBOX_CLOSE;
Packit Service a9274b
		case TW_UP: return CMD_TEXTBOX_UP;
Packit Service a9274b
		case TW_DOWN: return CMD_TEXTBOX_DOWN;
Packit Service a9274b
		case TW_LEFT: return CMD_TEXTBOX_LEFT;
Packit Service a9274b
		case TW_RIGHT: return CMD_TEXTBOX_RIGHT;
Packit Service a9274b
		case TW_PAGE|TW_UP: return CMD_TEXTBOX_PAGE_UP;
Packit Service a9274b
		case TW_PAGE|TW_DOWN: return CMD_TEXTBOX_PAGE_DOWN;
Packit Service a9274b
		case TW_PAGE|TW_LEFT: return CMD_TEXTBOX_PAGE_LEFT;
Packit Service a9274b
		case TW_PAGE|TW_RIGHT: return CMD_TEXTBOX_PAGE_RIGHT;
Packit Service a9274b
		default: return 0;
Packit Service a9274b
	}
Packit Service a9274b
}
Packit Service a9274b
Packit Service a9274b
static int mixer_command_by_name(const char *name) {
Packit Service a9274b
	unsigned int channel = 0;
Packit Service a9274b
	unsigned int number = 1; // default numeric arg
Packit Service a9274b
	unsigned int words = parse_words(name, mixer_words, 11, &number);
Packit Service a9274b
Packit Service a9274b
	switch (words) {
Packit Service a9274b
		case MW_HELP: return CMD_MIXER_HELP;
Packit Service a9274b
		case MW_CLOSE: return CMD_MIXER_CLOSE;
Packit Service a9274b
		case MW_REFRESH: return CMD_MIXER_REFRESH;
Packit Service a9274b
		case MW_SELECT|MW_CARD: return CMD_MIXER_SELECT_CARD;
Packit Service a9274b
		case MW_SYSTEM|MW_INFORMATION: return CMD_MIXER_SYSTEM_INFORMATION;
Packit Service a9274b
		case MW_MODE|MW_ALL: return CMD_WITH_ARG(CMD_MIXER_SET_VIEW_MODE, VIEW_MODE_ALL);
Packit Service a9274b
		case MW_MODE|MW_CAPTURE: return CMD_WITH_ARG(CMD_MIXER_SET_VIEW_MODE, VIEW_MODE_CAPTURE);
Packit Service a9274b
		case MW_MODE|MW_PLAYBACK: return CMD_WITH_ARG(CMD_MIXER_SET_VIEW_MODE, VIEW_MODE_PLAYBACK);
Packit Service a9274b
		case MW_MODE|MW_TOGGLE: return CMD_MIXER_TOGGLE_VIEW_MODE;
Packit Service a9274b
		case MW_CONTROL|MW_BALANCE: return CMD_MIXER_BALANCE_CONTROL;
Packit Service a9274b
		case MW_NEXT:
Packit Service a9274b
		case MW_NEXT|W_NUMBER:
Packit Service a9274b
		case MW_PREVIOUS:
Packit Service a9274b
		case MW_PREVIOUS|W_NUMBER:
Packit Service a9274b
			return ((number < 1 || number > 511) ? 0 :
Packit Service a9274b
					CMD_WITH_ARG((words & MW_NEXT
Packit Service a9274b
							? CMD_MIXER_NEXT
Packit Service a9274b
							: CMD_MIXER_PREVIOUS), number));
Packit Service a9274b
		case MW_CONTROL|MW_FOCUS|W_NUMBER:
Packit Service a9274b
			return ((number < 1 || number > 512) ? 0 :
Packit Service a9274b
					CMD_WITH_ARG(CMD_MIXER_FOCUS_CONTROL, number - 1));
Packit Service a9274b
	}
Packit Service a9274b
Packit Service a9274b
	if (words & MW_LEFT)
Packit Service a9274b
		channel |= LEFT;
Packit Service a9274b
	if (words & MW_RIGHT)
Packit Service a9274b
		channel |= RIGHT;
Packit Service a9274b
	if (!channel)
Packit Service a9274b
		channel = LEFT|RIGHT;
Packit Service a9274b
Packit Service a9274b
	switch (words & ~(MW_LEFT|MW_RIGHT)) {
Packit Service a9274b
		case MW_CONTROL|MW_UP:
Packit Service a9274b
		case MW_CONTROL|MW_UP|W_NUMBER:
Packit Service a9274b
		case MW_CONTROL|MW_DOWN:
Packit Service a9274b
		case MW_CONTROL|MW_DOWN|W_NUMBER:
Packit Service a9274b
			return ((number < 1 || number > 100) ? 0 :
Packit Service a9274b
					CMD_WITH_ARG((words & MW_UP
Packit Service a9274b
						 ? CMD_MIXER_CONTROL_UP_LEFT
Packit Service a9274b
						 : CMD_MIXER_CONTROL_DOWN_LEFT) + channel - 1, number));
Packit Service a9274b
		case MW_CONTROL|MW_SET|W_NUMBER:
Packit Service a9274b
			return (number > 100 ? 0 :
Packit Service a9274b
					CMD_WITH_ARG(CMD_MIXER_CONTROL_SET_PERCENT_LEFT + channel - 1, number));
Packit Service a9274b
		case MW_TOGGLE|MW_MUTE:
Packit Service a9274b
			return CMD_WITH_ARG(CMD_MIXER_TOGGLE_MUTE, channel);
Packit Service a9274b
		case MW_TOGGLE|MW_CAPTURE:
Packit Service a9274b
			return CMD_WITH_ARG(CMD_MIXER_TOGGLE_CAPTURE, channel);
Packit Service a9274b
	}
Packit Service a9274b
Packit Service a9274b
	return 0;
Packit Service a9274b
}
Packit Service a9274b
Packit Service a9274b
static int* element_by_name(const char *name) {
Packit Service a9274b
	int idx = strlist_index(
Packit Service a9274b
#ifdef TRICOLOR_VOLUME_BAR
Packit Service a9274b
		"ctl_bar_hi        "
Packit Service a9274b
#endif
Packit Service a9274b
		"ctl_bar_lo        "
Packit Service a9274b
#ifdef TRICOLOR_VOLUME_BAR
Packit Service a9274b
		"ctl_bar_mi        "
Packit Service a9274b
#endif
Packit Service a9274b
		"ctl_capture       "
Packit Service a9274b
		"ctl_frame         "
Packit Service a9274b
		"ctl_inactive      "
Packit Service a9274b
		"ctl_label         "
Packit Service a9274b
		"ctl_label_focus   "
Packit Service a9274b
		"ctl_label_inactive"
Packit Service a9274b
		"ctl_mark_focus    "
Packit Service a9274b
		"ctl_mute          "
Packit Service a9274b
		"ctl_nocapture     "
Packit Service a9274b
		"ctl_nomute        "
Packit Service a9274b
		"errormsg          "
Packit Service a9274b
		"infomsg           "
Packit Service a9274b
		"menu              "
Packit Service a9274b
		"menu_selected     "
Packit Service a9274b
		"mixer_active      "
Packit Service a9274b
		"mixer_frame       "
Packit Service a9274b
		"mixer_text        "
Packit Service a9274b
		"textbox           "
Packit Service a9274b
		"textfield         ", 18, name);
Packit Service a9274b
Packit Service a9274b
	if (idx < 0) {
Packit Service a9274b
#ifndef TRICOLOR_VOLUME_BAR
Packit Service a9274b
		if (strlist_index(
Packit Service a9274b
			"ctl_bar_hi"
Packit Service a9274b
			"ctl_bar_mi", 10, name) >= 0)
Packit Service a9274b
			return &errno; // dummy element
Packit Service a9274b
#endif
Packit Service a9274b
		return NULL;
Packit Service a9274b
	}
Packit Service a9274b
Packit Service a9274b
	return &( ((int*) &attrs)[idx] );
Packit Service a9274b
}
Packit Service a9274b
Packit Service a9274b
static int cfg_bind(char **argv, unsigned int argc) {
Packit Service a9274b
	const char *command_name;
Packit Service a9274b
	command_enum command = 0;
Packit Service a9274b
	unsigned int i;
Packit Service a9274b
	int keys[3] = { -1, -1, -1 };
Packit Service a9274b
	union {
Packit Service a9274b
		command_enum *mixer_bindings;
Packit Service a9274b
		uint8_t *textbox_bindings;
Packit Service a9274b
	} bind_to = {
Packit Service a9274b
		.mixer_bindings = mixer_bindings
Packit Service a9274b
	};
Packit Service a9274b
Packit Service a9274b
	if (argc == 2)
Packit Service a9274b
		command_name = argv[1];
Packit Service a9274b
	else if (argc == 3) {
Packit Service a9274b
		command_name = argv[2];
Packit Service a9274b
Packit Service a9274b
		if (! strcmp(argv[1], "textbox")) {
Packit Service a9274b
			bind_to.textbox_bindings = textbox_bindings;
Packit Service a9274b
		}
Packit Service a9274b
		else if (! strcmp(argv[1], "mixer"))
Packit Service a9274b
			; // bind_to.mixer_bindings = mixer_bindings
Packit Service a9274b
		else {
Packit Service a9274b
			error_message = _("invalid widget");
Packit Service a9274b
			error_cause = argv[1];
Packit Service a9274b
			return ERROR_CONFIG;
Packit Service a9274b
		}
Packit Service a9274b
	}
Packit Service a9274b
	else {
Packit Service a9274b
		return (argc < 2 ? ERROR_MISSING_ARGUMENTS : ERROR_TOO_MUCH_ARGUMENTS);
Packit Service a9274b
	}
Packit Service a9274b
Packit Service a9274b
	keys[0] = curskey_parse(argv[0]);
Packit Service a9274b
	if (keys[0] < 0 || keys[0] >= ARRAY_SIZE(mixer_bindings)) {
Packit Service a9274b
		error_message = _("invalid key");
Packit Service a9274b
		error_cause = argv[0];
Packit Service a9274b
		return ERROR_CONFIG;
Packit Service a9274b
	}
Packit Service a9274b
Packit Service a9274b
	if (keys[0] == KEY_ENTER || keys[0] == '\n' || keys[0] == '\r') {
Packit Service a9274b
		keys[0] = KEY_ENTER;
Packit Service a9274b
		keys[1] = '\n';
Packit Service a9274b
		keys[2] = '\r';
Packit Service a9274b
	}
Packit Service a9274b
Packit Service a9274b
	if (bind_to.textbox_bindings == textbox_bindings)
Packit Service a9274b
		command = textbox_command_by_name(command_name);
Packit Service a9274b
	else
Packit Service a9274b
		command = mixer_command_by_name(command_name);
Packit Service a9274b
Packit Service a9274b
	if (!command) {
Packit Service a9274b
		if (!strcmp(command_name, "none"))
Packit Service a9274b
			; // command = 0
Packit Service a9274b
		else {
Packit Service a9274b
			error_message = _("invalid command");
Packit Service a9274b
			error_cause = command_name;
Packit Service a9274b
			return ERROR_CONFIG;
Packit Service a9274b
		}
Packit Service a9274b
	}
Packit Service a9274b
Packit Service a9274b
	for (i = 0; i < ARRAY_SIZE(keys) && keys[i] != -1; ++i) {
Packit Service a9274b
		if (bind_to.textbox_bindings == textbox_bindings)
Packit Service a9274b
			bind_to.textbox_bindings[keys[i]] = command;
Packit Service a9274b
		else
Packit Service a9274b
			bind_to.mixer_bindings[keys[i]] = command;
Packit Service a9274b
	}
Packit Service a9274b
Packit Service a9274b
	return 0;
Packit Service a9274b
}
Packit Service a9274b
Packit Service a9274b
static int cfg_color(char **argv, unsigned int argc)
Packit Service a9274b
{
Packit Service a9274b
	short fg_color, bg_color;
Packit Service a9274b
	unsigned int i;
Packit Service a9274b
	int *element;
Packit Service a9274b
	int attr;
Packit Service a9274b
Packit Service a9274b
	if (argc < 3)
Packit Service a9274b
		return ERROR_MISSING_ARGUMENTS;
Packit Service a9274b
Packit Service a9274b
	if (NULL == (element = element_by_name(argv[0]))) {
Packit Service a9274b
		error_message = _("unknown theme element");
Packit Service a9274b
		error_cause = argv[0];
Packit Service a9274b
		return ERROR_CONFIG;
Packit Service a9274b
	}
Packit Service a9274b
Packit Service a9274b
	if (-2 == (fg_color = color_by_name(argv[1]))) {
Packit Service a9274b
		error_message = _("unknown color");
Packit Service a9274b
		error_cause = argv[1];
Packit Service a9274b
		return ERROR_CONFIG;
Packit Service a9274b
	}
Packit Service a9274b
Packit Service a9274b
	if (-2 == (bg_color = color_by_name(argv[2]))) {
Packit Service a9274b
		error_message = _("unknown color");
Packit Service a9274b
		error_cause = argv[2];
Packit Service a9274b
		return ERROR_CONFIG;
Packit Service a9274b
	}
Packit Service a9274b
Packit Service a9274b
	*element = get_color_pair(fg_color, bg_color);
Packit Service a9274b
Packit Service a9274b
	for (i = 3; i < argc; ++i) {
Packit Service a9274b
		if (-1 == (attr = attr_by_name(argv[i]))) {
Packit Service a9274b
			error_message = _("unknown color attribute");
Packit Service a9274b
			error_cause = argv[i];
Packit Service a9274b
			return ERROR_CONFIG;
Packit Service a9274b
		}
Packit Service a9274b
		else
Packit Service a9274b
			*element |= attr;
Packit Service a9274b
	}
Packit Service a9274b
	return 0;
Packit Service a9274b
}
Packit Service a9274b
Packit Service a9274b
static int cfg_set(char **argv, unsigned int argc)
Packit Service a9274b
{
Packit Service a9274b
	char *endptr;
Packit Service a9274b
Packit Service a9274b
	if (argc == 2) {
Packit Service a9274b
		if (! strcmp(argv[0], "mouse_wheel_step")) {
Packit Service a9274b
			mouse_wheel_step = strtoumax(argv[1], &endptr, 10);
Packit Service a9274b
			if (mouse_wheel_step > 100 || *endptr != '\0') {
Packit Service a9274b
				mouse_wheel_step = 1;
Packit Service a9274b
				error_message = _("invalid value");
Packit Service a9274b
				error_cause = argv[1];
Packit Service a9274b
				return ERROR_CONFIG;
Packit Service a9274b
			}
Packit Service a9274b
		}
Packit Service a9274b
		else if (! strcmp(argv[0], "mouse_wheel_focuses_control")) {
Packit Service a9274b
			if ((argv[1][0] == '0' || argv[1][0] == '1') && argv[1][1] == '\0')
Packit Service a9274b
				mouse_wheel_focuses_control = argv[1][0] - '0';
Packit Service a9274b
			else {
Packit Service a9274b
				error_message = _("invalid value");
Packit Service a9274b
				error_cause = argv[1];
Packit Service a9274b
				return ERROR_CONFIG;
Packit Service a9274b
			}
Packit Service a9274b
		}
Packit Service a9274b
		else {
Packit Service a9274b
			error_message = _("unknown option");
Packit Service a9274b
			error_cause = argv[0];
Packit Service a9274b
			return ERROR_CONFIG;
Packit Service a9274b
		}
Packit Service a9274b
	}
Packit Service a9274b
	else {
Packit Service a9274b
		return (argc < 2 ? ERROR_MISSING_ARGUMENTS : ERROR_TOO_MUCH_ARGUMENTS);
Packit Service a9274b
	}
Packit Service a9274b
Packit Service a9274b
	return 0;
Packit Service a9274b
}
Packit Service a9274b
Packit Service a9274b
/* Split $line on whitespace, store it in $args, return the argument count.
Packit Service a9274b
 * Return 0 for commented lines ('\s*#').
Packit Service a9274b
 *
Packit Service a9274b
 * This will modify contents of $line.
Packit Service a9274b
 */
Packit Service a9274b
static unsigned int parse_line(char *line, char **args, unsigned int args_size)
Packit Service a9274b
{
Packit Service a9274b
	unsigned int count;
Packit Service a9274b
Packit Service a9274b
	for (count = 0; count < args_size; ++count) {
Packit Service a9274b
		while (*line && isspace(*line))
Packit Service a9274b
			++line;
Packit Service a9274b
Packit Service a9274b
		if (*line == '\0')
Packit Service a9274b
			break;
Packit Service a9274b
Packit Service a9274b
		if (*line == '#' && count == 0)
Packit Service a9274b
			break;
Packit Service a9274b
Packit Service a9274b
		args[count] = line;
Packit Service a9274b
Packit Service a9274b
		while (*line && !isspace(*line))
Packit Service a9274b
			++line;
Packit Service a9274b
Packit Service a9274b
		if (*line != '\0') {
Packit Service a9274b
			*line = '\0';
Packit Service a9274b
			++line;
Packit Service a9274b
		}
Packit Service a9274b
	}
Packit Service a9274b
Packit Service a9274b
	return count;
Packit Service a9274b
}
Packit Service a9274b
Packit Service a9274b
static int process_line(char *line) {
Packit Service a9274b
	char *args[16];
Packit Service a9274b
	unsigned int argc = parse_line(line, args, ARRAY_SIZE(args));
Packit Service a9274b
	int ret = 0;
Packit Service a9274b
Packit Service a9274b
	if (argc >= 1) {
Packit Service a9274b
		error_cause = NULL;
Packit Service a9274b
		//error_message = _("unknown error");
Packit Service a9274b
Packit Service a9274b
		if (argc >= ARRAY_SIZE(args))
Packit Service a9274b
			ret = ERROR_TOO_MUCH_ARGUMENTS;
Packit Service a9274b
		else {
Packit Service a9274b
			ret = strlist_index(
Packit Service a9274b
				"bind "
Packit Service a9274b
				"color"
Packit Service a9274b
				"set  ", 5, args[0]);
Packit Service a9274b
			switch (ret) {
Packit Service a9274b
				case 0: ret = cfg_bind(args + 1, argc - 1); break;
Packit Service a9274b
				case 1: ret = cfg_color(args + 1, argc - 1); break;
Packit Service a9274b
				case 2: ret = cfg_set(args + 1, argc - 1); break;
Packit Service a9274b
				default: error_message = _("unknown command");
Packit Service a9274b
			}
Packit Service a9274b
		}
Packit Service a9274b
Packit Service a9274b
		if (ret == ERROR_MISSING_ARGUMENTS)
Packit Service a9274b
			error_message = _("missing arguments");
Packit Service a9274b
		else if (ret == ERROR_TOO_MUCH_ARGUMENTS)
Packit Service a9274b
			error_message = _("too much arguments");
Packit Service a9274b
	}
Packit Service a9274b
Packit Service a9274b
	return ret;
Packit Service a9274b
}
Packit Service a9274b
Packit Service a9274b
void parse_config_file(const char *file_name)
Packit Service a9274b
{
Packit Service a9274b
	char *buf;
Packit Service a9274b
	unsigned int file_size;
Packit Service a9274b
	unsigned int lineno;
Packit Service a9274b
	unsigned int i;
Packit Service a9274b
	char *line;
Packit Service a9274b
Packit Service a9274b
	endwin(); // print warnings to stderr
Packit Service a9274b
Packit Service a9274b
	buf = read_file(file_name, &file_size);
Packit Service a9274b
	if (!buf) {
Packit Service a9274b
		fprintf(stderr, "%s: %s\n", file_name, strerror(errno));
Packit Service a9274b
		return;
Packit Service a9274b
	}
Packit Service a9274b
Packit Service a9274b
	curskey_init();
Packit Service a9274b
	curskey_define_meta_keys(128);
Packit Service a9274b
Packit Service a9274b
	lineno = 0;
Packit Service a9274b
	line = buf;
Packit Service a9274b
	for (i = 0; i < file_size; ++i) {
Packit Service a9274b
		if (buf[i] == '\n') {
Packit Service a9274b
			buf[i] = '\0';
Packit Service a9274b
			++lineno;
Packit Service a9274b
			if (process_line(line) < 0) {
Packit Service a9274b
				if (error_cause)
Packit Service a9274b
					fprintf(stderr, "%s:%d: %s: %s: %s\n", file_name, lineno, line, error_message, error_cause);
Packit Service a9274b
				else
Packit Service a9274b
					fprintf(stderr, "%s:%d: %s: %s\n", file_name, lineno, line, error_message);
Packit Service a9274b
			}
Packit Service a9274b
			line = &buf[i + 1];
Packit Service a9274b
		}
Packit Service a9274b
	}
Packit Service a9274b
Packit Service a9274b
	free(buf);
Packit Service a9274b
	curskey_destroy();
Packit Service a9274b
}
Packit Service a9274b
Packit Service a9274b
void parse_default_config_file() {
Packit Service a9274b
	char file[4096];
Packit Service a9274b
	const char *home;
Packit Service a9274b
Packit Service a9274b
	home = getenv("XDG_CONFIG_HOME");
Packit Service a9274b
	if (home && *home) {
Packit Service a9274b
		snprintf(file, sizeof(file), "%s/alsamixer.rc", home);
Packit Service a9274b
		if (! access(file, F_OK))
Packit Service a9274b
			return parse_config_file(file);
Packit Service a9274b
	}
Packit Service a9274b
Packit Service a9274b
	home = getenv("HOME");
Packit Service a9274b
	if (!home || !*home) {
Packit Service a9274b
		struct passwd *pwd = getpwuid(getuid());
Packit Service a9274b
		if (pwd)
Packit Service a9274b
			home = pwd->pw_dir;
Packit Service a9274b
	}
Packit Service a9274b
Packit Service a9274b
	if (home && *home) {
Packit Service a9274b
		snprintf(file, sizeof(file), "%s/.config/alsamixer.rc", home);
Packit Service a9274b
		if (! access(file, F_OK))
Packit Service a9274b
			return parse_config_file(file);
Packit Service a9274b
Packit Service a9274b
		snprintf(file, sizeof(file), "%s/.alsamixer.rc", home);
Packit Service a9274b
		if (! access(file, F_OK))
Packit Service a9274b
			return parse_config_file(file);
Packit Service a9274b
	}
Packit Service a9274b
}