xenocara/app/fvwm/modules/FvwmIconMan/readconfig.c

1590 lines
39 KiB
C
Raw Normal View History

#include <ctype.h>
#include <stdlib.h>
#include "FvwmIconMan.h"
#include "readconfig.h"
static char const rcsid[] =
"$Id: readconfig.c,v 1.1.1.1 2006/11/26 10:53:50 matthieu Exp $";
/************************************************************************
*
* Builtin functions:
*
************************************************************************/
extern int builtin_quit (int numargs, BuiltinArg *args);
extern int builtin_printdebug (int numargs, BuiltinArg *args);
extern int builtin_gotobutton (int numargs, BuiltinArg *args);
extern int builtin_gotomanager (int numargs, BuiltinArg *args);
extern int builtin_refresh (int numargs, BuiltinArg *args);
extern int builtin_select (int numargs, BuiltinArg *args);
extern int builtin_sendcommand (int numargs, BuiltinArg *args);
extern int builtin_bif (int numargs, BuiltinArg *args);
extern int builtin_bifn (int numargs, BuiltinArg *args);
extern int builtin_print (int numargs, BuiltinArg *args);
extern int builtin_jmp (int numargs, BuiltinArg *args);
extern int builtin_ret (int numargs, BuiltinArg *args);
extern int builtin_searchforward (int numargs, BuiltinArg *args);
extern int builtin_searchback (int numargs, BuiltinArg *args);
extern int builtin_warp (int numargs, BuiltinArg *args);
/* compiler pseudo-functions */
static int builtin_label (int numargs, BuiltinArg *args);
typedef struct {
char *name;
int (*func)(int numargs, BuiltinArg *args);
int numargs;
BuiltinArgType args[MAX_ARGS];
} FunctionType;
/*
* these are now sorted so we can use bsearch on them.
*/
FunctionType builtin_functions[] = {
{ "bif", builtin_bif, 2, { ButtonArg, JmpArg } },
{ "bifn", builtin_bifn, 2, { ButtonArg, JmpArg } },
{ "gotobutton", builtin_gotobutton, 1, { ButtonArg } },
{ "gotomanager", builtin_gotomanager, 1, { ManagerArg } },
{ "jmp", builtin_jmp, 1, { JmpArg } },
{ "label", builtin_label, 1, { StringArg } },
{ "print", builtin_print, 1, { StringArg } },
{ "printdebug", builtin_printdebug, 0 },
{ "quit", builtin_quit, 0 },
{ "refresh", builtin_refresh, 0 },
{ "ret", builtin_ret, 0 },
{ "searchback", builtin_searchback, 1, { StringArg } },
{ "searchforward", builtin_searchforward, 1, { StringArg } },
{ "select", builtin_select, 0 },
{ "sendcommand", builtin_sendcommand, 1, { StringArg } },
{ "warp", builtin_warp, 0 }
};
static int num_builtins = sizeof (builtin_functions) / sizeof (FunctionType);
/************************************************************************/
struct charstring
{
char key;
int value;
};
struct charstring key_modifiers[]=
{
{'s',ShiftMask},
{'c',ControlMask},
{'m',Mod1Mask},
{'1',Mod1Mask},
{'2',Mod2Mask},
{'3',Mod3Mask},
{'4',Mod4Mask},
{'5',Mod5Mask},
{'a',AnyModifier},
{'n',0},
{0,0}
};
#if FVWM_VERSION == 1
static FILE *config_fp = NULL;
#endif
/* This is only used for printing out the .fvwmrc line if an error
occured */
#define PRINT_LINE_LENGTH 80
static char current_line[PRINT_LINE_LENGTH];
static void save_current_line (char *s)
{
char *p = current_line;
while (*s && p < current_line + PRINT_LINE_LENGTH - 1) {
if (*s == '\n') {
*p = '\0';
return;
}
else {
*p++ = *s++;
}
}
*p = '\0';
}
void print_args (int numargs, BuiltinArg *args)
{
#ifdef PRINT_DEBUG
int i;
for (i = 0; i < numargs; i++) {
switch (args[i].type) {
case NoArg:
ConsoleDebug (CONFIG, "NoArg ");
break;
case IntArg:
ConsoleDebug (CONFIG, "Int: %d ", args[i].value.int_value);
break;
case StringArg:
ConsoleDebug (CONFIG, "String: %s ", args[i].value.string_value);
break;
case ButtonArg:
ConsoleDebug (CONFIG, "Button: %d %d ",
args[i].value.button_value.offset,
args[i].value.button_value.base);
break;
case WindowArg:
ConsoleDebug (CONFIG, "Window: %d %d ",
args[i].value.button_value.offset,
args[i].value.button_value.base);
break;
case ManagerArg:
ConsoleDebug (CONFIG, "Manager: %d %d ",
args[i].value.button_value.offset,
args[i].value.button_value.base);
break;
case JmpArg:
ConsoleDebug (CONFIG, "Unprocessed Label Jump: %s ",
args[i].value.string_value);
break;
default:
ConsoleDebug (CONFIG, "bad ");
break;
}
}
ConsoleDebug (CONFIG, "\n");
#endif
}
#ifdef PRINT_DEBUG
static void print_binding (Binding *binding)
{
int i;
Function *func;
if (binding->IsMouse) {
ConsoleDebug (CONFIG, "\tMouse: %d\n", binding->Button_Key);
}
else {
ConsoleDebug (CONFIG, "\tKey or action: %d %s\n", binding->Button_Key,
binding->key_name);
}
ConsoleDebug (CONFIG, "\tModifiers: %d\n", binding->Modifier);
ConsoleDebug (CONFIG, "\tAction: %s\n", binding->Action);
ConsoleDebug (CONFIG, "\tFunction struct: %p\n", binding->Function);
func = binding->Function;
while (func) {
for (i = 0; i < num_builtins; i++) {
if (func->func == builtin_functions[i].func) {
ConsoleDebug (CONFIG, "\tFunction: %s %p ",
builtin_functions[i].name, func->func);
break;
}
}
if (i > num_builtins) {
ConsoleDebug (CONFIG, "\tFunction: not found %p ", func->func);
}
print_args (func->numargs, func->args);
func = func->next;
}
}
#endif
void print_bindings (Binding *list)
{
#ifdef PRINT_DEBUG
ConsoleDebug (CONFIG, "binding list:\n");
while (list != NULL) {
print_binding (list);
ConsoleDebug (CONFIG, "\n");
list = list->NextBinding;
}
#endif
}
static int iswhite (char c)
{
if (c == ' ' || c == '\t' || c == '\0')
return 1;
return 0;
}
static void skip_space (char **p)
{
while (**p == ' ' || **p == '\t')
(*p)++;
}
static void add_to_binding (Binding **list, Binding *binding)
{
ConsoleDebug (CONFIG, "In add_to_binding:\n");
if (*list == NULL) {
*list = binding;
}
else {
binding->LastBinding->NextBinding = *list;
*list = binding;
}
}
static int extract_int (char *p, int *n)
{
char *s;
int sign = 1;
while (isspace (*p) && *p)
p++;
if (*p == '-') {
sign = -1;
p++;
}
else if (*p == '+') {
sign = 1;
p++;
}
if (*p == '\0') {
return 0;
}
for (s = p; *s; s++) {
if (*s < '0' || *s > '9') {
return 0;
}
}
*n = atoi (p) * sign;
return 1;
}
/****************************************************************************
*
* Gets the next "word" of input from char string indata.
* "word" is a string with no spaces, or a qouted string.
* Return value is ptr to indata,updated to point to text after the word
* which is extracted.
* token is the extracted word, which is copied into a malloced
* space, and must be freed after use.
*
**************************************************************************/
static void find_context(char *string, int *output, struct charstring *table,
char *tline)
{
int i=0,j=0;
Bool matched;
char tmp1;
*output=0;
i=0;
while(i<strlen(string))
{
j=0;
matched = FALSE;
while((!matched)&&(table[j].key != 0))
{
/* in some BSD implementations, tolower(c) is not defined
* unless isupper(c) is true */
tmp1=string[i];
if(isupper(tmp1))
tmp1=tolower(tmp1);
/* end of ugly BSD patch */
if(tmp1 == table[j].key)
{
*output |= table[j].value;
matched = TRUE;
}
j++;
}
if(!matched)
{
ConsoleMessage ("Bad line: %s\n", current_line);
ConsoleMessage ("Bad context: %s\n", string);
}
i++;
}
return;
}
static int init_config_file (char *file)
{
#if FVWM_VERSION == 1
if ((config_fp = fopen (file, "r")) == NULL) {
ConsoleMessage ("Couldn't open file: %s\n", file);
return 0;
}
#endif
return 1;
}
static void close_config_file (void)
{
#if FVWM_VERSION == 1
if (config_fp)
fclose (config_fp);
#endif
}
static char *parse_button (char *string, BuiltinArg *arg, int *flag,
char *pstop_char)
{
char *rest, *token;
ButtonValue *bv;
int n;
ConsoleDebug (CONFIG, "parse_term: %s\n", string);
*flag = 1;
arg->type = ButtonArg;
bv = &arg->value.button_value;
bv->offset = 0;
bv->base = AbsoluteButton;
rest = DoGetNextToken (string, &token, NULL, ",", pstop_char);
if (token == NULL) {
bv->base = NoButton;
*flag = 0;
Free(token);
return NULL;
}
if (!strcasecmp (token, "focus")) {
bv->base = FocusButton;
}
else if (!strcasecmp (token, "select")) {
bv->base = SelectButton;
}
else if (!strcasecmp (token, "up")) {
bv->base = UpButton;
}
else if (!strcasecmp (token, "down")) {
bv->base = DownButton;
}
else if (!strcasecmp (token, "left")) {
bv->base = LeftButton;
}
else if (!strcasecmp (token, "right")) {
bv->base = RightButton;
}
else if (!strcasecmp (token, "next")) {
bv->base = NextButton;
}
else if (!strcasecmp (token, "prev")) {
bv->base = PrevButton;
}
else if (extract_int (token, &n)) {
bv->base = AbsoluteButton;
bv->offset = n;
}
else {
ConsoleMessage ("Bad button: %s\n", token);
bv->base = NoButton;
Free (token);
*flag = 0;
return NULL;
}
Free (token);
return rest;
}
static void free_function_list (Function *func)
{
int i;
Function *fp = func;
while (fp) {
for (i = 0; i < fp->numargs; i++) {
if (fp->args[i].type == StringArg)
Free (fp->args[i].value.string_value);
}
func = fp;
fp = fp->next;
Free (func);
}
}
static int funccasecmp(const void *key /* actually char* */,
const void *member /* actually FunctionType* */)
{
return strcasecmp((char *)key, ((FunctionType *)member)->name);
}
/*
* The label function. Should never be called, but we need a pointer to it,
* and it's useful for debugging purposes to have it defined.
*/
static int builtin_label (int numargs, BuiltinArg *args) {
int j;
/* we should _never_ be called */
ConsoleMessage ( "label" );
for (j=0; j<numargs; ++j) {
switch (args[j].type) {
case StringArg:
ConsoleMessage ( " %s",args[j].value.string_value );
break;
default:
ConsoleMessage ( " [unknown arg #: %d]", args[j].type );
}
}
ConsoleMessage( " was called. This should not happen.\n" );
return 0;
}
/* the number of JmpArg arguments that have been created, but not yet
resolved into IntArgs. */
static int JmpArgs=0;
/* icky, I know, but it'll save unnecessary error-checking. */
static Function *parse_function (char **line, char *pstop_char)
{
Function *ftype = (Function *)safemalloc (sizeof (Function));
char *ptr, *name, *tok;
int j, flag;
FunctionType *builtin_functions_i;
ConsoleDebug (CONFIG, "in parse_function\n");
ptr = DoGetNextToken (*line, &name, NULL, ",", pstop_char);
if (name == NULL) {
Free(ftype);
*line = NULL;
return NULL;
}
builtin_functions_i=bsearch((void *)name, (void *)builtin_functions,
num_builtins, sizeof(FunctionType),
funccasecmp);
if (builtin_functions_i) {
Free (name);
ftype->func = builtin_functions_i->func;
ftype->numargs = builtin_functions_i->numargs;
ftype->next = NULL;
for (j = 0; j < builtin_functions_i->numargs && *pstop_char != ','; j++) {
ftype->args[j].type = builtin_functions_i->args[j];
switch (builtin_functions_i->args[j]) {
case IntArg:
ptr = DoGetNextToken (ptr, &tok, NULL, ",", pstop_char);
if (!tok) {
ConsoleMessage ("%s: too few arguments\n",
builtin_functions_i->name);
Free(ftype);
*line = NULL;
return NULL;
}
if (extract_int (tok, &ftype->args[j].value.int_value) == 0) {
ConsoleMessage ("%s: expect integer argument: %s\n",
builtin_functions_i->name, tok);
Free (tok);
Free(ftype);
*line = NULL;
return NULL;
}
Free (tok);
break;
case StringArg:
ptr = DoGetNextToken (ptr, &ftype->args[j].value.string_value,NULL,
",", pstop_char);
if (!ftype->args[j].value.string_value) {
ConsoleMessage ("%s: too few arguments\n",
builtin_functions_i->name);
*line = NULL;
Free(ftype->args[j].value.string_value);
Free(ftype);
return NULL;
}
ftype->args[j].type = builtin_functions_i->args[j];
break;
case ButtonArg:
case WindowArg:
case ManagerArg:
ptr = parse_button (ptr, &ftype->args[j], &flag, pstop_char);
if (!flag) {
ConsoleMessage ("%s: too few arguments\n",
builtin_functions_i->name);
Free(ftype);
*line = NULL;
return NULL;
}
ftype->args[j].type = builtin_functions_i->args[j];
break;
/* JmpArg can be a string or an int. However, if 'JmpArg'
* is recorded as the argument type in the argument array
* for a command, it means it is a string; the code for
* 'IntArg' is used instead for numbers. Note also that
* if the C function recieves a 'JmpArg' argument it means something
* went wrong, since they should all be translated to integer
* jump offsets at compile time.
*/
case JmpArg:
ptr = DoGetNextToken (ptr, &tok, NULL, ",", pstop_char);
if (!tok) {
ConsoleMessage ("%s: too few arguments\n",
builtin_functions_i->name);
Free(tok);
Free(ftype);
*line=NULL;
return NULL;
}
if (extract_int(tok, &ftype->args[j].value.int_value) == 0) {
ftype->args[j].value.string_value=tok;
ftype->args[j].type = JmpArg;
++JmpArgs;
} else {
ftype->args[j].type = IntArg;
Free(tok);
}
break;
default:
ConsoleMessage ("internal error in parse_function\n");
Free(ftype);
*line = NULL;
return NULL;
}
}
if (j != builtin_functions_i->numargs) {
ConsoleMessage ("%s: too few arguments\n", builtin_functions_i->name);
Free(ftype);
*line = NULL;
return NULL;
}
*line = ptr;
return ftype;
}
ConsoleMessage ("Unknown function: %s\n", name);
Free (name);
*line = NULL;
return NULL;
}
/* This is O(N^2) where N = number of instructions. Seems we could do better.
We'll see how this addition settles before monkeying with it */
static Function *parse_function_list (char *line)
{
Function *ret = NULL, *tail = NULL, *f, *i;
char *token;
int jump_count, j;
char stop_char;
char c;
JmpArgs=0;
while (line && (f = parse_function(&line, &stop_char))) {
ConsoleDebug (CONFIG, "parse_function: %p\n", f->func);
/* extra code to check for and remove a 'label' pseudo-function */
if (f->func==builtin_label) {
/* scan backwards to fix up references */
jump_count=0;
for (i=tail; i!=NULL; i=i->prev) {
/* scan the command arguments for a 'JmpArg' type */
for (j=0; j<(i->numargs); ++j) {
if (i->args[j].type==JmpArg) {
/* we have a winner! */
if (!strcasecmp(f->args[0].value.string_value,
i->args[j].value.string_value)) {
/* the label matches it, so replace with the jump_count */
i->args[j].type = IntArg;
i->args[j].value.int_value = jump_count;
--JmpArgs;
}
}
}
++jump_count;
}
Free(f); /* label pseudo-functions never get added to the chain */
} else {
if (tail)
tail->next = f;
else
ret = f;
f->prev=tail;
tail = f;
}
DoGetNextToken (line, &token, NULL, ",", &c);
if (token && stop_char != ',') {
ConsoleMessage ("Bad function list, comma expected\n");
Free (token);
return NULL;
}
stop_char = c;
Free(token);
}
if (JmpArgs!=0) {
/* someone made a typo and we need to scan to find out what it
* was.
*/
for (f=tail; f; f=f->prev) {
for (j=0; j<(f->numargs); ++j) {
if (f->args[j].type==JmpArg) {
ConsoleMessage ("Attempt to jump to non-existant label %s; "
"aborting function list.\n",
f->args[j].value.string_value);
--JmpArgs;
}
}
}
if (JmpArgs!=0)
ConsoleMessage ( "Internal Error: JmpArgs %d not accounted for!\n",
JmpArgs );
tail=NULL;
f=NULL;
free_function_list(ret);
ret=NULL;
return NULL;
}
if (ret == NULL)
ConsoleMessage ("No function defined\n");
return ret;
}
Binding *ParseMouseEntry (char *tline)
{
char modifiers[20],*action,*token;
Binding *new;
int button;
int n1=0,n2=0;
int mods;
/* tline points after the key word "key" */
action = DoGetNextToken(tline,&token, NULL, ",", NULL);
if(token != NULL) {
n1 = sscanf(token,"%d",&button);
Free(token);
}
action = DoGetNextToken(action,&token, NULL, ",", NULL);
if(token != NULL) {
n2 = sscanf(token,"%19s",modifiers);
Free(token);
}
if((n1 != 1)||(n2 != 1))
ConsoleMessage ("Mouse binding: Syntax error");
find_context(modifiers,&mods,key_modifiers,tline);
if((mods & AnyModifier)&&(mods&(~AnyModifier))) {
ConsoleMessage ("Binding specified AnyModifier and other modifers too. Excess modifiers will be ignored.");
}
new = (Binding *)safemalloc(sizeof(Binding));
new->IsMouse = 1;
new->Button_Key = button;
new->key_name = NULL;
new->Modifier = mods;
new->Action = stripcpy(action);
new->Function = parse_function_list (action);
new->NextBinding = NULL;
new->LastBinding = new;
if (!new->Function) {
ConsoleMessage ("Bad action: %s\n", action);
Free (new->Action);
Free (new);
return NULL;
}
ConsoleDebug (CONFIG, "Mouse: %d %d %s\n", new->Button_Key,
new->Modifier, new->Action);
return new;
}
static Binding *ParseKeyEntry (char *tline)
{
char *action,modifiers[20],key[20],*ptr, *token, *actionstring, *keystring;
Binding *new = NULL, *temp, *last = NULL;
Function *func = NULL;
int i,min,max;
int n1=0,n2=0;
KeySym keysym;
int mods;
/* tline points after the key word "key" */
ptr = tline;
ptr = DoGetNextToken(ptr,&token, NULL, ",", NULL);
if(token != NULL) {
n1 = sscanf(token,"%19s",key);
Free(token);
}
action = DoGetNextToken(ptr,&token, NULL, ",", NULL);
if(token != NULL) {
n2 = sscanf(token,"%19s",modifiers);
Free(token);
}
if((n1 != 1)||(n2 != 1))
ConsoleMessage ("Syntax error in line %s",tline);
find_context(modifiers,&mods,key_modifiers,tline);
if((mods & AnyModifier)&&(mods&(~AnyModifier))) {
ConsoleMessage ("Binding specified AnyModifier and other modifers too. Excess modifiers will be ignored.");
}
/*
* Don't let a 0 keycode go through, since that means AnyKey to the
* XGrabKey call in GrabKeys().
*/
if ((keysym = XStringToKeysym(key)) == NoSymbol ||
XKeysymToKeycode(theDisplay, keysym) == 0) {
ConsoleMessage ("Can't find keysym: %s\n", key);
return NULL;
}
XDisplayKeycodes(theDisplay, &min, &max);
for (i=min; i<=max; i++) {
if (XKeycodeToKeysym(theDisplay, i, 0) == keysym) {
if (!func) {
func = parse_function_list (action);
if (!func) {
ConsoleMessage ("Bad action: %s\n", action);
return NULL;
}
actionstring = stripcpy(action);
keystring = stripcpy(key);
}
temp = new;
new = (Binding *)safemalloc(sizeof(Binding));
new->IsMouse = 0;
new->Button_Key = i;
new->key_name = keystring;
new->Modifier = mods;
new->Action = actionstring;
new->Function = func;
new->NextBinding = temp;
if (!last) {
last = new;
}
new->LastBinding = last;
ConsoleDebug (CONFIG, "Key: %d %s %d %s\n", i, new->key_name,
mods, new->Action);
}
}
return new;
}
static Binding *ParseSimpleEntry (char *tline)
{
Binding *new;
Function *func;
func = parse_function_list (tline);
if (func == NULL)
return NULL;
new = (Binding *)safemalloc (sizeof (Binding));
new->IsMouse = 0;
new->Button_Key = 0;
new->key_name = "select";
new->Modifier = 0;
new->Action = stripcpy (tline);
new->Function = func;
new->NextBinding = NULL;
new->LastBinding = new;
return new;
}
void run_binding (WinManager *man, Action action)
{
Binding *binding = man->bindings[action];
ConsoleDebug (CONFIG, "run_binding:\n");
print_bindings (binding);
if (binding && binding->Function && binding->Function->func) {
run_function_list (binding->Function);
}
}
void execute_function (char *string)
{
Function *func = parse_function_list (string);
if (func == NULL) {
return;
}
else {
run_function_list (func);
free_function_list (func);
}
}
static int GetConfigLineWrapper (int *fd, char **tline)
{
#if FVWM_VERSION == 1
static char buffer[1024];
char *temp;
if (fgets (buffer, 1024, config_fp)) {
*tline = buffer;
temp = strchr (*tline, '\n');
if (temp) {
*temp = '\0';
}
else {
ConsoleMessage (stderr, "line too long\n");
exit (1);
}
return 1;
}
#else
char *temp;
GetConfigLine (fd, tline);
if (*tline) {
temp = strchr (*tline, '\n');
if (temp) {
*temp = '\0';
}
return 1;
}
#endif
return 0;
}
static char *read_next_cmd (ReadOption flag)
{
static ReadOption status;
static char *buffer;
static char *retstring, displaced, *cur_pos;
retstring = NULL;
if (flag != READ_LINE && !(flag & status))
return NULL;
switch (flag) {
case READ_LINE:
while (GetConfigLineWrapper (Fvwm_fd, &buffer)) {
cur_pos = buffer;
skip_space (&cur_pos);
if (!strncasecmp (Module, cur_pos, ModuleLen)) {
retstring = cur_pos;
cur_pos += ModuleLen;
displaced = *cur_pos;
if (displaced == '*')
status = READ_OPTION;
else if (displaced == '\0')
status = READ_LINE;
else if (iswhite (displaced))
status = READ_ARG;
else
status = READ_LINE;
break;
}
}
break;
case READ_OPTION:
*cur_pos = displaced;
retstring = ++cur_pos;
while (*cur_pos != '*' && !iswhite (*cur_pos))
cur_pos++;
displaced = *cur_pos;
*cur_pos = '\0';
if (displaced == '*')
status = READ_OPTION;
else if (displaced == '\0')
status = READ_LINE;
else if (iswhite (displaced))
status = READ_ARG;
else
status = READ_LINE;
break;
case READ_ARG:
*cur_pos = displaced;
skip_space (&cur_pos);
retstring = cur_pos;
while (!iswhite (*cur_pos))
cur_pos++;
displaced = *cur_pos;
*cur_pos = '\0';
if (displaced == '\0')
status = READ_LINE;
else if (iswhite (displaced))
status = READ_ARG;
else
status = READ_LINE;
break;
case READ_REST_OF_LINE:
status = READ_LINE;
*cur_pos = displaced;
skip_space (&cur_pos);
retstring = cur_pos;
break;
}
if (retstring && retstring[0] == '\0')
retstring = NULL;
return retstring;
}
static char *conditional_copy_string (char **s1, char *s2)
{
if (*s1)
return *s1;
else
return copy_string (s1, s2);
}
static NameType parse_format_dependencies (char *format)
{
NameType flags = NO_NAME;
ConsoleDebug (CONFIG, "Parsing format: %s\n", format);
while (*format) {
if (*format != '%') {
format++;
}
else {
format++;
if (*format == 'i')
flags |= ICON_NAME;
else if (*format == 't')
flags |= TITLE_NAME;
else if (*format == 'c')
flags |= CLASS_NAME;
else if (*format == 'r')
flags |= RESOURCE_NAME;
else if (*format != '%')
ConsoleMessage ("Bad format string: %s\n", format);
}
}
#ifdef PRINT_DEBUG
ConsoleDebug (CONFIG, "Format depends on: ");
if (flags & ICON_NAME)
ConsoleDebug (CONFIG, "Icon ");
if (flags & TITLE_NAME)
ConsoleDebug (CONFIG, "Title ");
if (flags & CLASS_NAME)
ConsoleDebug (CONFIG, "Class ");
if (flags & RESOURCE_NAME)
ConsoleDebug (CONFIG, "Resource ");
ConsoleDebug (CONFIG, "\n");
#endif
return flags;
}
#define SET_MANAGER(manager,field,value) \
do { \
int id = manager; \
if (id == -1) { \
for (id = 0; id < globals.num_managers; id++) { \
globals.managers[id].field = value; \
} \
} \
else if (id < globals.num_managers) { \
globals.managers[id].field = value; \
} \
else { \
ConsoleMessage ("Internal error in SET_MANAGER: %d\n", id); \
} \
} while (0)
static void handle_button_config (int manager, int context, char *option)
{
char *p;
ButtonState state;
p = read_next_cmd (READ_ARG);
if (!p) {
ConsoleMessage ("Bad line: %s\n", current_line);
ConsoleMessage ("Need argument to %s\n", option);
return;
}
else if (!strcasecmp (p, "flat")) {
state = BUTTON_FLAT;
}
else if (!strcasecmp (p, "up")) {
state = BUTTON_UP;
}
else if (!strcasecmp (p, "down")) {
state = BUTTON_DOWN;
}
else if (!strcasecmp (p, "raisededge")) {
state = BUTTON_EDGEUP;
}
else if (!strcasecmp (p, "sunkedge")) {
state = BUTTON_EDGEDOWN;
}
else {
ConsoleMessage ("Bad line: %s\n", current_line);
ConsoleMessage ("This isn't a valid button state: %s\n", p);
return;
}
ConsoleDebug (CONFIG, "Setting buttonState[%s] to %s\n",
contextDefaults[context].name, p);
SET_MANAGER (manager, buttonState[context], state);
/* check for optional fore color */
p = read_next_cmd (READ_ARG);
if ( !p )
return;
SET_MANAGER (manager, foreColorName[context],
copy_string (&globals.managers[id].foreColorName[context], p));
/* check for optional back color */
p = read_next_cmd (READ_ARG);
if ( !p )
return;
ConsoleDebug (CONFIG, "Setting backColorName[%s] to %s\n",
contextDefaults[context].name, p);
SET_MANAGER (manager, backColorName[context],
copy_string (&globals.managers[id].backColorName[context], p));
}
void read_in_resources (char *file)
{
char *p, *q;
int i, n, manager;
char *option1;
Binding *binding;
Resolution r;
if (!init_config_file (file))
return;
while ((p = read_next_cmd (READ_LINE))) {
ConsoleDebug (CONFIG, "line: %s\n", p);
save_current_line (p);
option1 = read_next_cmd (READ_OPTION);
if (option1 == NULL)
continue;
ConsoleDebug (CONFIG, "option1: %s\n", option1);
if (!strcasecmp (option1, "nummanagers")) {
/* If in transient mode, just use the default of 1 manager */
if (!globals.transient) {
p = read_next_cmd (READ_ARG);
if (!p) {
ConsoleMessage ("Bad line: %s\n", current_line);
continue;
}
if (extract_int (p, &n) == 0) {
ConsoleMessage ("This is not a number: %s\n", p);
ConsoleMessage ("Bad line: %s\n", current_line);
continue;
}
if (n > 0) {
allocate_managers (n);
ConsoleDebug (CONFIG, "num managers: %d\n", n);
}
else {
ConsoleMessage ("Bad line: %s\n", current_line);
ConsoleMessage ("You can't have zero managers. "
"I'll give you one.\n");
allocate_managers (1);
}
}
}
else {
/* these all can specify a specific manager */
if (globals.managers == NULL) {
ConsoleDebug (CONFIG, "I'm assuming you only want one manager\n");
allocate_managers (1);
}
manager = 0;
if (option1[0] >= '0' && option1[0] <= '9') {
if (globals.transient) {
ConsoleDebug (CONFIG, "In transient mode. Ignoring this line\n");
continue;
}
if (extract_int (option1, &manager) == 0 ||
manager <= 0 || manager > globals.num_managers) {
ConsoleMessage ("Bad line: %s\n", current_line);
ConsoleMessage ("This is not a valid manager: %s.\n", option1);
manager = 0;
}
option1 = read_next_cmd (READ_OPTION);
if (!option1) {
ConsoleMessage ("Bad line: %s\n", current_line);
continue;
}
}
else if (!strcasecmp (option1, "transient")) {
if (globals.transient) {
ConsoleDebug (CONFIG, "Transient manager config line\n");
manager = 1;
option1 = read_next_cmd (READ_OPTION);
if (!option1) {
ConsoleMessage ("Bad line: %s\n", current_line);
continue;
}
}
else {
ConsoleDebug (CONFIG, "Not in transient mode. Ignoring this line\n");
continue;
}
}
manager--; /* -1 means global */
ConsoleDebug (CONFIG, "Applying %s to manager %d\n", option1, manager);
if (!strcasecmp (option1, "action")) {
p = read_next_cmd (READ_ARG);
if (!p) {
ConsoleMessage ("Bad line: %s\n", current_line);
continue;
}
if (!strcasecmp (p, "mouse")) {
i = MOUSE;
}
else if (!strcasecmp (p, "key")) {
i = KEYPRESS;
}
else if (!strcasecmp (p, "select")) {
i = SELECT;
}
else {
ConsoleMessage ("Bad line: %s\n", current_line);
ConsoleMessage ("This isn't a valid action name: %s\n", p);
continue;
}
q = read_next_cmd (READ_REST_OF_LINE);
if (!q) {
ConsoleMessage ("Bad line: %s\n", current_line);
ConsoleMessage ("Need an action\n");
continue;
}
switch (i) {
case MOUSE:
binding = ParseMouseEntry (q);
break;
case KEYPRESS:
binding = ParseKeyEntry (q);
break;
case SELECT:
binding = ParseSimpleEntry (q);
break;
}
if (binding == NULL) {
ConsoleMessage ("Offending line: %s\n", current_line);
ConsoleMessage ("Bad action\n");
continue;
}
if (manager == -1) {
int j;
for (j = 0; j < globals.num_managers; j++) {
add_to_binding (&globals.managers[j].bindings[i], binding);
}
}
else if (manager < globals.num_managers) {
add_to_binding (&globals.managers[manager].bindings[i], binding);
}
else {
ConsoleMessage ("Bad line: %s\n", current_line);
ConsoleMessage ("There's no manager %d\n", manager);
}
}
else if (!strcasecmp (option1, "background")) {
p = read_next_cmd (READ_ARG);
if (!p) {
ConsoleMessage ("Bad line: %s\n", current_line);
continue;
}
ConsoleDebug (CONFIG, "default background: %s\n", p);
for ( i = 0; i < NUM_CONTEXTS; i++ )
SET_MANAGER (manager, backColorName[i],
conditional_copy_string (&globals.managers[id].backColorName[i],
p));
}
else if (!strcasecmp (option1, "buttongeometry")) {
p = read_next_cmd (READ_ARG);
if (!p) {
ConsoleMessage ("Bad line: %s\n", current_line);
continue;
}
SET_MANAGER (manager, button_geometry_str,
copy_string (&globals.managers[id].button_geometry_str, p));
}
else if (!strcasecmp (option1, "dontshow")) {
char *token = NULL;
p = read_next_cmd (READ_REST_OF_LINE);
if (!p) {
ConsoleMessage ("Bad line: %s\n", current_line);
continue;
}
p = DoGetNextToken (p, &token, NULL, ",", NULL);
if (!token) {
ConsoleMessage ("Bad line: %s\n", current_line);
continue;
}
do {
ConsoleDebug (CONFIG, "dont show: %s\n", token);
if (manager == -1) {
int i;
for (i = 0; i < globals.num_managers; i++)
add_to_stringlist (&globals.managers[i].dontshow, token);
}
else {
add_to_stringlist (&globals.managers[manager].dontshow, token);
}
Free (token);
p = DoGetNextToken (p, &token, NULL, ",", NULL);
} while (token);
if (token)
Free(token);
}
else if (!strcasecmp (option1, "drawicons")) {
#ifdef MINI_ICONS
p = read_next_cmd (READ_ARG);
if (!p) {
ConsoleMessage ("Bad line: %s\n", current_line);
ConsoleMessage ("Need argument to drawicons\n");
continue;
}
if (!strcasecmp (p, "true")) {
i = 1;
}
/* [NFM 3 Dec 97] added support for FvwmIconMan*drawicons "always" */
else if (!strcasecmp (p, "always")) {
i = 2;
}
else if (!strcasecmp (p, "false")) {
i = 0;
}
else {
ConsoleMessage ("Bad line: %s\n", current_line);
ConsoleMessage ("What is this: %s?\n", p);
continue;
}
ConsoleDebug (CONFIG, "Setting drawicons to: %d\n", i);
SET_MANAGER (manager, draw_icons, i);
#else
ConsoleMessage ("DrawIcons support not compiled in\n");
#endif
}
else if (!strcasecmp (option1, "followfocus")) {
p = read_next_cmd (READ_ARG);
if (!p) {
ConsoleMessage ("Bad line: %s\n", current_line);
ConsoleMessage ("Need argument to followfocus\n");
continue;
}
if (!strcasecmp (p, "true")) {
i = 1;
}
else if (!strcasecmp (p, "false")) {
i = 0;
}
else {
ConsoleMessage ("Bad line: %s\n", current_line);
ConsoleMessage ("What is this: %s?\n", p);
continue;
}
ConsoleDebug (CONFIG, "Setting followfocus to: %d\n", i);
SET_MANAGER (manager, followFocus, i);
}
else if (!strcasecmp (option1, "font")) {
p = read_next_cmd (READ_ARG);
if (!p) {
ConsoleMessage ("Bad line: %s\n", current_line);
continue;
}
ConsoleDebug (CONFIG, "font: %s\n", p);
SET_MANAGER (manager, fontname,
copy_string (&globals.managers[id].fontname, p));
}
else if (!strcasecmp (option1, "foreground")) {
p = read_next_cmd (READ_ARG);
if (!p) {
ConsoleMessage ("Bad line: %s\n", current_line);
continue;
}
ConsoleDebug (CONFIG, "default foreground: %s\n", p);
for ( i = 0; i < NUM_CONTEXTS; i++ )
SET_MANAGER (manager, foreColorName[i],
conditional_copy_string (&globals.managers[id].foreColorName[i],
p));
}
else if (!strcasecmp (option1, "format")) {
char *token;
NameType flags;
p = read_next_cmd (READ_REST_OF_LINE);
if (!p) {
ConsoleMessage ("Bad line: %s\n", current_line);
continue;
}
DoGetNextToken (p, &token, NULL, ",", NULL);
if (!token)
{
token = (char *)safemalloc(1);
*token = 0;
}
SET_MANAGER (manager, formatstring,
copy_string (&globals.managers[id].formatstring, token));
flags = parse_format_dependencies (token);
SET_MANAGER (manager, format_depend, flags);
Free (token);
}
else if (!strcasecmp (option1, "geometry")) {
ConsoleMessage ("Geometry option no longer supported.\n");
ConsoleMessage ("Use ManagerGeometry and ButtonGeometry.\n");
}
else if (!strcasecmp (option1, "iconname")) {
char *token;
p = read_next_cmd (READ_REST_OF_LINE);
if (!p) {
ConsoleMessage ("Bad line: %s\n", current_line);
continue;
}
DoGetNextToken (p, &token, NULL, ",", NULL);
if (!token)
{
token = (char *)safemalloc(1);
*token = 0;
}
SET_MANAGER (manager, iconname,
copy_string (&globals.managers[id].iconname, token));
Free (token);
}
else if (!strcasecmp (option1, "managergeometry")) {
p = read_next_cmd (READ_ARG);
if (!p) {
ConsoleMessage ("Bad line: %s\n", current_line);
continue;
}
SET_MANAGER (manager, geometry_str,
copy_string (&globals.managers[id].geometry_str, p));
}
else if (!strcasecmp (option1, "resolution")) {
p = read_next_cmd (READ_ARG);
if (!p) {
ConsoleMessage ("Bad line: %s\n", current_line);
continue;
}
ConsoleDebug (CONFIG, "resolution: %s\n", p);
if (!strcasecmp (p, "global"))
r = SHOW_GLOBAL;
else if (!strcasecmp (p, "desk"))
r = SHOW_DESKTOP;
else if (!strcasecmp (p, "page"))
r = SHOW_PAGE;
else {
ConsoleMessage ("Bad line: %s\n", current_line);
ConsoleMessage ("What kind of resolution is this?\n");
continue;
}
SET_MANAGER (manager, res, r);
}
else if (!strcasecmp (option1, "shape")) {
p = read_next_cmd (READ_ARG);
if (!p) {
ConsoleMessage ("Bad line: %s\n", current_line);
ConsoleMessage ("Need argument to followfocus\n");
continue;
}
if (!strcasecmp (p, "true")) {
i = 1;
}
else if (!strcasecmp (p, "false")) {
i = 0;
}
else {
ConsoleMessage ("Bad line: %s\n", current_line);
ConsoleMessage ("What is this: %s?\n", p);
continue;
}
if (i && globals.shapes_supported == 0) {
ConsoleMessage ("Shape support not compiled in\n");
continue;
}
ConsoleDebug (CONFIG, "Setting shape to: %d\n", i);
SET_MANAGER (manager, shaped, i);
}
else if (!strcasecmp (option1, "show")) {
char *token = NULL;
p = read_next_cmd (READ_REST_OF_LINE);
if (!p) {
ConsoleMessage ("Bad line: %s\n", current_line);
continue;
}
p = DoGetNextToken (p, &token, NULL, ",", NULL);
if (!token) {
ConsoleMessage ("Bad line: %s\n", current_line);
continue;
}
do {
ConsoleDebug (CONFIG, "show: %s\n", token);
if (manager == -1) {
int i;
for (i = 0; i < globals.num_managers; i++)
add_to_stringlist (&globals.managers[i].show, token);
}
else {
add_to_stringlist (&globals.managers[manager].show, token);
}
Free (token);
p = DoGetNextToken (p, &token, NULL, ",", NULL);
} while (token);
if (token)
Free(token);
}
else if (!strcasecmp (option1, "showtitle")) {
ConsoleMessage ("Bad line: %s\n", current_line);
ConsoleMessage ("showtitle is no longer an option. Use format\n");
continue;
}
else if (!strcasecmp (option1, "sort")) {
p = read_next_cmd (READ_ARG);
if (!p) {
ConsoleMessage ("Bad line: %s\n", current_line);
ConsoleMessage ("Need argument to sort\n");
continue;
}
if (!strcasecmp (p, "name")) {
i = SortName;
}
else if (!strcasecmp (p, "namewithcase")) {
i = SortNameCase;
}
else if (!strcasecmp (p, "id")) {
i = SortId;
}
else if (!strcasecmp (p, "none")) {
i = SortNone;
}
else if (!strcasecmp (p, "false") || !strcasecmp (p, "true")) {
/* Old options */
ConsoleMessage ("FvwmIconMan*sort option no longer takes "
"true or false value\n"
"Please read the latest manpage\n");
continue;
}
else {
ConsoleMessage ("Bad line: %s\n", current_line);
ConsoleMessage ("What is this: %s?\n", p);
continue;
}
ConsoleDebug (CONFIG, "Setting sort to: %d\n", i);
SET_MANAGER (manager, sort, i);
}
else if (!strcasecmp (option1, "title")) {
char *token;
p = read_next_cmd (READ_REST_OF_LINE);
if (!p) {
ConsoleMessage ("Bad line: %s\n", current_line);
continue;
}
DoGetNextToken (p, &token, NULL, ",", NULL);
if (!token)
{
token = (char *)safemalloc(1);
*token = 0;
}
SET_MANAGER (manager, titlename,
copy_string (&globals.managers[id].titlename, token));
Free (token);
}
else if (!strcasecmp (option1, "plainButton")) {
handle_button_config (manager, PLAIN_CONTEXT, option1);
}
else if (!strcasecmp (option1, "selectButton")) {
handle_button_config (manager, SELECT_CONTEXT, option1);
}
else if (!strcasecmp (option1, "focusButton")) {
handle_button_config (manager, FOCUS_CONTEXT, option1);
}
else if (!strcasecmp (option1, "focusandselectButton")) {
handle_button_config (manager, FOCUS_SELECT_CONTEXT, option1);
}
else if (!strcasecmp (option1, "titlebutton")) {
handle_button_config (manager, TITLE_CONTEXT, option1);
}
else if (!strcasecmp (option1, "usewinlist")) {
p = read_next_cmd (READ_ARG);
if (!p) {
ConsoleMessage ("Bad line: %s\n", current_line);
ConsoleMessage ("Need argument to usewinlist\n");
continue;
}
if (!strcasecmp (p, "true")) {
i = 1;
}
else if (!strcasecmp (p, "false")) {
i = 0;
}
else {
ConsoleMessage ("Bad line: %s\n", current_line);
ConsoleMessage ("What is this: %s?\n", p);
continue;
}
ConsoleDebug (CONFIG, "Setting usewinlist to: %d\n", i);
SET_MANAGER (manager, usewinlist, i);
}
else {
ConsoleMessage ("Bad line: %s\n", current_line);
ConsoleMessage ("Unknown option: %s\n", p);
}
}
}
if (globals.managers == NULL) {
ConsoleDebug (CONFIG, "I'm assuming you only want one manager\n");
allocate_managers (1);
}
print_managers();
close_config_file();
}