xenocara/app/fvwm/modules/FvwmButtons/parse.c

1023 lines
21 KiB
C

/*
FvwmButtons v2.0.41-plural-Z-alpha, copyright 1996, Jarl Totland
* This module, and the entire GoodStuff program, and the concept for
* interfacing this module to the Window Manager, are all original work
* by Robert Nation
*
* Copyright 1993, Robert Nation. No guarantees or warantees or anything
* are provided or implied in any way whatsoever. Use this program at your
* own risk. Permission to use this program for any purpose is given,
* as long as the copyright is kept intact.
*/
#include "config.h"
#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <X11/Xlib.h>
#include <X11/Intrinsic.h>
/*
#include <X11/Xutil.h>
#include <X11/Xatom.h>
#include <X11/Xproto.h>
*/
#include "FvwmButtons.h"
#include "button.h"
extern int w,h,x,y,xneg,yneg; /* used in ParseConfigLine */
extern char *config_file;
/* contains the character that terminated the last string from seekright */
static char terminator = '\0';
/* ----------------------------------- macros ------------------------------ */
char *trimleft(char *s)
{
while (s && isspace(*s))
s++;
return s;
}
/**
*** seekright()
***
*** split off the first continous section of the string into a new allocated
*** string and move the old pointer forward. Accepts and strips quoting with
*** '," or `, and the current quote q can be escaped inside the string with \q.
**/
char *seekright(char **s)
{
char *token = NULL;
char *line = *s;
line = DoGetNextToken(line, &token, NULL, "),", &terminator);
if (*s != NULL && line == NULL)
line = strchr(*s, '\0');
*s = line;
return token;
}
/**
*** ParseBack()
*** Parses the options possible to Back
**/
int ParseBack(char **ss)
{
char *opts[]={"icon",NULL};
char *t,*s=*ss;
int r=0;
while(*s && *s!=')')
{
s = trimleft(s);
if(*s==',')
s++;
else switch(GetTokenIndex(s,opts,-1,&s))
{
case 0: /* Icon */
r=1;
fprintf(stderr,"%s: Back(Icon) not supported yet\n",MyName);
break;
default:
t=seekright(&s);
fprintf(stderr,"%s: Illegal back option \"%s\"\n",MyName,(t)?t:"");
if (t)
free(t);
}
}
if(*s) s++;
*ss=s;
return r;
}
/**
*** ParseBoxSize()
*** Parses the options possible to BoxSize
**/
void ParseBoxSize(char **ss, unsigned long *flags)
{
char *opts[]={"dumb","fixed","smart",NULL};
char *s = *ss;
int m;
if (!s)
return;
*ss = GetNextTokenIndex(*ss, opts, 0, &m);
switch(m)
{
case 0:
*flags &= ~(b_SizeFixed|b_SizeSmart);
break;
case 1:
*flags |= b_SizeFixed;
*flags &= ~b_SizeSmart;
break;
case 2:
*flags |= b_SizeSmart;
*flags &= ~b_SizeFixed;
break;
default:
*flags &= ~(b_SizeFixed|b_SizeSmart);
fprintf(stderr,"%s: Illegal boxsize option \"%s\"\n",MyName, s);
break;
}
return;
}
/**
*** ParseTitle()
*** Parses the options possible to Title
**/
void ParseTitle(char **ss, byte *flags, byte *mask)
{
char *titleopts[]={"left","right","center","side",NULL};
char *t,*s=*ss;
while(*s && *s!=')')
{
s = trimleft(s);
if(*s==',')
s++;
else switch(GetTokenIndex(s,titleopts,-1,&s))
{
case 0: /* Left */
*flags&=~b_TitleHoriz;
*mask|=b_TitleHoriz;
break;
case 1: /* Right */
*flags&=~b_TitleHoriz;
*flags|=2;
*mask|=b_TitleHoriz;
break;
case 2: /* Center */
*flags&=~b_TitleHoriz;
*flags|=1;
*mask|=b_TitleHoriz;
break;
case 3: /* Side */
*flags|=b_Horizontal;
*mask|=b_Horizontal;
break;
default:
t=seekright(&s);
fprintf(stderr,"%s: Illegal title option \"%s\"\n",MyName,(t)?t:"");
if (t)
free(t);
}
}
if(*s) s++;
*ss=s;
}
/**
*** ParseSwallow()
*** Parses the options possible to Swallow
**/
void ParseSwallow(char **ss,byte *flags,byte *mask)
{
char *swallowopts[]={"nohints","hints","nokill","kill","noclose","close",
"respawn","norespawn","useold",
"noold","usetitle","notitle",NULL};
char *t,*s=*ss;
while(*s && *s!=')')
{
s = trimleft(s);
if(*s==',')
s++;
else switch(GetTokenIndex(s,swallowopts,-1,&s))
{
case 0: /* NoHints */
*flags|=b_NoHints;
*mask|=b_NoHints;
break;
case 1: /* Hints */
*flags&=~b_NoHints;
*mask|=b_NoHints;
break;
case 2: /* NoKill */
*flags&=~b_Kill;
*mask|=b_Kill;
break;
case 3: /* Kill */
*flags|=b_Kill;
*mask|=b_Kill;
break;
case 4: /* NoClose */
*flags|=b_NoClose;
*mask|=b_NoClose;
break;
case 5: /* Close */
*flags&=~b_NoClose;
*mask|=b_NoClose;
break;
case 6: /* Respawn */
*flags|=b_Respawn;
*mask|=b_Respawn;
break;
case 7: /* NoRespawn */
*flags&=~b_Respawn;
*mask|=b_Respawn;
break;
case 8: /* UseOld */
*flags|=b_UseOld;
*mask|=b_UseOld;
break;
case 9: /* NoOld */
*flags&=~b_UseOld;
*mask|=b_UseOld;
break;
case 10: /* UseTitle */
*flags|=b_UseTitle;
*mask|=b_UseTitle;
break;
case 11: /* NoTitle */
*flags&=~b_UseTitle;
*mask|=b_UseTitle;
break;
default:
t=seekright(&s);
fprintf(stderr,"%s: Illegal swallow option \"%s\"\n",MyName,
(t)?t:"");
if (t)
free(t);
}
}
if(*s) s++;
*ss=s;
}
/**
*** ParseContainer()
*** Parses the options possible to Container
**/
void ParseContainer(char **ss,button_info *b)
{
char *conts[]={"columns","rows","font","frame","back","fore",
"padding","title","swallow","nosize","size",
"boxsize",NULL};
char *t,*o,*s=*ss;
int i,j;
while(*s && *s!=')')
{
s = trimleft(s);
if(*s==',')
s++;
else switch(GetTokenIndex(s,conts,-1,&s))
{
case 0: /* Columns */
b->c->num_columns=max(1,strtol(s,&t,10));
s=t;
break;
case 1: /* Rows */
b->c->num_rows=max(1,strtol(s,&t,10));
s=t;
break;
case 2: /* Font */
if (b->c->font_string) free(b->c->font_string);
b->c->font_string=seekright(&s);
if(b->c->font_string)
b->c->flags|=b_Font;
else
b->c->flags&=~b_Font;
break;
case 3: /* Frame */
b->c->framew=strtol(s,&t,10);
b->c->flags|=b_Frame;
s=t;
break;
case 4: /* Back */
s = trimleft(s);
if(*s=='(' && s++)
if(ParseBack(&s))
b->c->flags|=b_IconBack;
if (b->c->back) free(b->c->back);
b->c->back=seekright(&s);
if(b->c->back)
b->c->flags|=b_Back;
else
b->c->flags&=~(b_IconBack|b_Back);
break;
case 5: /* Fore */
if (b->c->fore) free(b->c->fore);
b->c->fore=seekright(&s);
if(b->c->fore)
b->c->flags|=b_Fore;
else
b->c->flags&=~b_Fore;
break;
case 6: /* Padding */
i=strtol(s,&t,10);
if(t>s)
{
b->c->xpad=b->c->ypad=i;
s=t;
i=strtol(s,&t,10);
if(t>s)
{
b->c->ypad=i;
s=t;
}
b->c->flags|=b_Padding;
}
else
fprintf(stderr,"%s: Illegal padding argument\n",MyName);
break;
case 7: /* Title - flags */
s = trimleft(s);
if(*s=='(' && s++)
{
b->c->justify=0;
b->c->justify_mask=0;
ParseTitle(&s,&b->c->justify,&b->c->justify_mask);
if(b->c->justify_mask)
b->c->flags|=b_Justify;
}
else
{
char *temp;
fprintf(stderr,"%s: Illegal title in container options\n",
MyName);
temp = seekright(&s);
if (temp)
free(temp);
}
break;
case 8: /* Swallow - flags */
s = trimleft(s);
if(*s=='(' && s++)
{
b->c->swallow=0;
b->c->swallow_mask=0;
ParseSwallow(&s,&b->c->swallow,&b->c->swallow_mask);
if(b->c->swallow_mask)
b->c->flags|=b_Swallow;
}
else
{
char *temp;
fprintf(stderr,"%s: Illegal swallow in container options\n",
MyName);
temp = seekright(&s);
if (temp)
free(temp);
}
break;
case 9: /* NoSize */
b->c->flags|=b_Size;
b->c->minx=b->c->miny=0;
break;
case 10: /* Size */
i=strtol(s,&t,10);
j=strtol(t,&o,10);
if(t>s && o>t)
{
b->c->minx=i;
b->c->miny=j;
b->c->flags|=b_Size;
s=o;
}
else
fprintf(stderr,"%s: Illegal size arguments\n",MyName);
break;
case 11: /* BoxSize */
ParseBoxSize(&s, &b->c->flags);
break;
default:
t=seekright(&s);
fprintf(stderr,"%s: Illegal container option \"%s\"\n",MyName,
(t)?t:"");
if (t)
free(t);
}
}
if(*s) s++;
*ss=s;
}
/**
*** match_string()
***
*** parse a buttonconfig string.
*** *FvwmButtons(option[ options]) title iconname command
**/
/*#define DEBUG_PARSER*/
void match_string(button_info **uberb,char *s)
{
button_info *b,*ub=*uberb;
int i,j;
char *t,*o;
b=alloc_button(ub,(ub->c->num_buttons)++);
s = trimleft(s);
if(*s=='(' && s++)
{
char *opts[]={"back","fore","font","title","icon","frame","padding",
"swallow","action","container","end","nosize","size",
"panel", "left", "right", "center",
NULL};
s = trimleft(s);
while(*s && *s!=')')
{
if((*s>='0' && *s<='9') || *s=='+' || *s=='-')
{
char *geom;
int x,y,w,h,flags;
geom=seekright(&s);
if (geom)
{
flags=XParseGeometry(geom, &x, &y, &w, &h);
if(flags&WidthValue)
b->BWidth=w;
if(flags&HeightValue)
b->BHeight=h;
if(flags&XValue)
{
b->BPosX=x;
b->flags|=b_PosFixed;
}
if(flags&YValue)
{
b->BPosY=y;
b->flags|=b_PosFixed;
}
if(flags&XNegative)
b->BPosX=-1-x;
if(flags&YNegative)
b->BPosY=-1-y;
free(geom);
}
s = trimleft(s);
continue;
}
if(*s==',' && s++)
s = trimleft(s);
switch(GetTokenIndex(s,opts,-1,&s))
{
case 0: /* Back */
s = trimleft(s);
if(*s=='(' && s++)
if(ParseBack(&s))
b->flags|=b_IconBack;
if(b->flags&b_Back && b->back) free(b->back);
b->back=seekright(&s);
if(b->back)
b->flags|=b_Back;
else
b->flags&=~(b_IconBack|b_Back);
break;
case 1: /* Fore */
if(b->flags&b_Fore && b->fore) free(b->fore);
b->fore=seekright(&s);
if(b->fore)
b->flags|=b_Fore;
else
b->flags&=~b_Fore;
break;
case 2: /* Font */
if(b->flags&b_Font && b->font_string) free(b->font_string);
b->font_string=seekright(&s);
if(b->font_string)
b->flags|=b_Font;
else
b->flags&=~b_Font;
break;
/* --------------------------- Title ------------------------- */
case 3: /* Title */
s = trimleft(s);
if(*s=='(' && s++)
{
b->justify=0;
b->justify_mask=0;
ParseTitle(&s,&b->justify,&b->justify_mask);
if(b->justify_mask)
b->flags|=b_Justify;
}
t=seekright(&s);
if(t && *t && (t[0]!='-' || t[1]!=0))
{
if (b->title)
free(b->title);
b->title=t;
#ifdef DEBUG_PARSER
fprintf(stderr,"PARSE: Title \"%s\"\n",b->title);
#endif
b->flags|=b_Title;
}
else
{
fprintf(stderr,"%s: Missing title argument\n",MyName);
if(t)free(t);
}
break;
/* ---------------------------- icon ------------------------- */
case 4: /* Icon */
t=seekright(&s);
if(t && *t && (t[0] != '-' || t[1] != 0))
{
if (b->icon_file)
free(b->icon_file);
b->icon_file=t;
b->IconWin=None;
b->flags|=b_Icon;
}
else
{
fprintf(stderr,"%s: Missing icon argument\n",MyName);
if(t)free(t);
}
break;
/* --------------------------- frame ------------------------- */
case 5: /* Frame */
i=strtol(s,&t,10);
if(t>s)
{
b->flags|=b_Frame;
b->framew=i;
s=t;
}
else
fprintf(stderr,"%s: Illegal frame argument\n",MyName);
break;
/* -------------------------- padding ------------------------ */
case 6: /* Padding */
i=strtol(s,&t,10);
if(t>s)
{
b->xpad=b->ypad=i;
b->flags |= b_Padding;
s=t;
i=strtol(s,&t,10);
if(t>s)
{
b->ypad=i;
s=t;
}
}
else
fprintf(stderr,"%s: Illegal padding argument\n",MyName);
break;
/* -------------------------- swallow ------------------------ */
case 7: /* Swallow */
s = trimleft(s);
b->swallow=0;
b->swallow_mask=0;
if(*s=='(' && s++)
ParseSwallow(&s,&b->swallow,&b->swallow_mask);
t=seekright(&s);
o=seekright(&s);
if(t)
{
if (b->hangon)
free(b->hangon);
b->hangon=t;
b->flags|=b_Hangon;
b->flags|=b_Swallow;
b->swallow|=1;
if(!(b->swallow&b_NoHints))
b->hints=(XSizeHints*)mymalloc(sizeof(XSizeHints));
if(o)
{
if(!(buttonSwallow(b)&b_UseOld))
SendText(fd,o,0);
if (b->spawn)
free(b->spawn);
b->spawn=o; /* Might be needed if respawning sometime */
}
}
else
{
fprintf(stderr,"%s: Missing swallow argument\n",MyName);
if(t)free(t);
if(o)free(o);
}
break;
/* --------------------------- action ------------------------ */
case 8: /* Action */
s = trimleft(s);
i=0;
if(*s=='(')
{
s++;
if(strncasecmp(s,"mouse",5)!=0)
{
fprintf(stderr,"%s: Couldn't parse action\n",MyName);
}
s+=5;
i=strtol(s,&t,10);
s=t;
while(*s && *s!=')')
s++;
if(*s==')')s++;
}
s = GetQuotedString(s, &t, ",)", NULL, NULL, NULL);
if(t)
{
AddButtonAction(b,i,t);
free(t);
}
else
fprintf(stderr,"%s: Missing action argument\n",MyName);
break;
/* -------------------------- container ---------------------- */
case 9: /* Container */
b->flags&=b_Frame|b_Back|b_Fore|b_Padding|b_Action;
MakeContainer(b);
*uberb=b;
s = trimleft(s);
if(*s=='(' && s++)
ParseContainer(&s,b);
break;
case 10: /* End */
*uberb=ub->parent;
ub->c->buttons[--(ub->c->num_buttons)]=NULL;
if(!ub->parent)
{
fprintf(stderr,"%s: Unmatched END in config file\n",MyName);
exit(1);
}
break;
case 11: /* NoSize */
b->flags|=b_Size;
b->minx=b->miny=0;
break;
case 12: /* Size */
i=strtol(s,&t,10);
j=strtol(t,&o,10);
if(t>s && o>t)
{
b->minx=i;
b->miny=j;
b->flags|=b_Size;
s=o;
}
else
fprintf(stderr,"%s: Illegal size arguments\n",MyName);
break;
/* --------------------------- panel ------------------------ */
case 13: /* Panel */
s = trimleft(s);
if(*s=='(')
{
s++;
t = seekright(&s);
if (terminator != ')')
while(*s && *s!=')')
s++;
if(*s==')')
s++;
if (strncasecmp(t,"right",5)==0)
t = "panel-r";
else if (strncasecmp(t,"left" ,4)==0)
t = "panel-l";
else if (strncasecmp(t,"down" ,4)==0)
t = "panel-d";
else if (strncasecmp(t,"geometry",8)==0)
t = "panel-g";
else
t = "panel-u";
}
else
t = "panel-u";
AddButtonAction(b, 0, t);
b->IconWin = None;
t = seekright(&s);
b->hangon = (t)? t : strdup(""); /* which panel to popup */
break;
case 14: /* Left */
b->flags |= b_Left;
b->flags &= ~b_Right;
break;
case 15: /* Right */
b->flags |= b_Right;
b->flags &= ~b_Left;
break;
case 16: /* Center */
b->flags &= ~(b_Right|b_Left);
break;
default:
t=seekright(&s);
fprintf(stderr,"%s: Illegal button option \"%s\"\n",MyName,
(t)?t:"");
if (t)
free(t);
break;
}
s = trimleft(s);
}
if (s && *s)
{
s++;
s = trimleft(s);
}
}
/* get title and iconname */
if(!(b->flags&b_Title))
{
b->title=seekright(&s);
if(b->title && *b->title && ((b->title)[0]!='-'||(b->title)[1]!=0))
b->flags |= b_Title;
else
if(b->title)free(b->title);
}
else
{
char *temp;
temp = seekright(&s);
if (temp)
free(temp);
}
if(!(b->flags&b_Icon))
{
b->icon_file=seekright(&s);
if(b->icon_file && b->icon_file &&
((b->icon_file)[0]!='-'||(b->icon_file)[1]!=0))
{
b->flags|=b_Icon;
b->IconWin=None;
}
else
if(b->icon_file)free(b->icon_file);
}
else
{
char *temp;
temp = seekright(&s);
if (temp)
free(temp);
}
s = trimleft(s);
/* Swallow hangon command */
if(strncasecmp(s,"swallow",7)==0)
{
if(b->flags&b_Swallow)
{
fprintf(stderr,"%s: Illegal with both old and new swallow!\n",
MyName);
exit(1);
}
s+=7;
/*
* Swallow old 'swallowmodule' command
*/
if (strncasecmp(s,"module",6)==0)
{
s+=6;
}
if (b->hangon)
free(b->hangon);
b->hangon=seekright(&s);
if (!b->hangon)
b->hangon = strdup("");
b->flags|=(b_Swallow|b_Hangon);
b->swallow|=1;
s = trimleft(s);
if(!(b->swallow&b_NoHints))
b->hints=(XSizeHints*)mymalloc(sizeof(XSizeHints));
if(*s)
{
if(!(buttonSwallow(b)&b_UseOld))
SendText(fd,s,0);
b->spawn=strdup(s);
}
}
else if(*s)
AddButtonAction(b,0,s);
return;
}
/**
*** ParseConfigLine
**/
void ParseConfigLine(button_info **ubb,char *s)
{
button_info *ub=*ubb;
char *opts[]={"geometry","font","padding","columns","rows","back","fore",
"frame","file","pixmap","panel","boxsize",NULL};
int i,j,k;
switch(GetTokenIndex(s,opts,-1,&s))
{
case 0:/* Geometry */
{
char geom[64];
int flags,g_x,g_y;
unsigned int width,height;
i=sscanf(s,"%63s",geom);
if(i==1)
{
flags=XParseGeometry(geom,&g_x,&g_y,&width,&height);
UberButton->w = 0;
UberButton->h = 0;
if(flags&WidthValue)
w=width;
if(flags&HeightValue)
h=height;
if(flags&XValue)
UberButton->x = g_x;
if(flags&YValue)
UberButton->y = g_y;
if(flags&XNegative)
UberButton->w = 1;
if(flags&YNegative)
UberButton->h = 1;
}
break;
}
case 1:/* Font */
CopyString(&ub->c->font_string,s);
break;
case 2:/* Padding */
i=sscanf(s,"%d %d",&j,&k);
if(i>0) ub->c->xpad=ub->c->ypad=j;
if(i>1) ub->c->ypad=k;
break;
case 3:/* Columns */
i=sscanf(s,"%d",&j);
if(i>0) ub->c->num_columns=j;
break;
case 4:/* Rows */
i=sscanf(s,"%d",&j);
if(i>0) ub->c->num_rows=j;
break;
case 5:/* Back */
CopyString(&(ub->c->back),s);
break;
case 6:/* Fore */
CopyString(&(ub->c->fore),s);
break;
case 7:/* Frame */
i=sscanf(s,"%d",&j);
if(i>0) ub->c->framew=j;
break;
case 8:/* File */
s = trimleft(s);
if (config_file)
free(config_file);
config_file=seekright(&s);
break;
case 9:/* Pixmap */
s = trimleft(s);
if (strncasecmp(s,"none",4)==0)
ub->c->flags|=b_TransBack;
else
CopyString(&(ub->c->back_file),s);
ub->c->flags|=b_IconBack;
break;
case 10:/* Panel */
s = trimleft(s);
CurrentPanel->next = (panel_info *) mymalloc(sizeof(panel_info));
CurrentPanel = CurrentPanel->next;
CurrentPanel->next = NULL;
CurrentPanel->uber = UberButton
= (button_info *) mymalloc(sizeof(button_info));
if (UberButton->title)
free(UberButton->title);
UberButton->title = seekright(&s);
UberButton->flags = 0;
UberButton->parent = NULL;
UberButton->BWidth = 1;
UberButton->BHeight = 1;
UberButton->swallow = 0; /* subpanel is hidden initially */
MakeContainer(UberButton);
ub = *ubb = UberButton;
break;
case 11: /* BoxSize */
ParseBoxSize(&s, &ub->c->flags);
break;
default:
s = trimleft(s);
match_string(ubb,s);
break;
}
}
/**
*** ParseConfigFile()
*** Parses optional separate configuration file for FvwmButtons
**/
void ParseConfigFile(button_info *ub)
{
char s[1024],*t;
FILE *f=fopen(config_file,"r");
int l;
if(!f)
{
fprintf(stderr,"%s: Couldn't open config file %s\n",MyName,config_file);
return;
}
while (fgets(s, 1023, f))
{
/* Allow for line continuation: */
while ((l=strlen(s)) < sizeof(s)
&& l>=2 && s[l-1]=='\n' && s[l-2]=='\\')
fgets(s+l-2, sizeof(s)-l, f);
/* And comments: */
t=s;
while(*t)
{
if(*t=='#' && (t==s || *(t-1)!='\\'))
{
*t=0;
break;
}
t++;
}
t = s;
t = trimleft(t);
if(*t)
ParseConfigLine(&ub,t);
}
fclose(f);
}
extern int save_color_limit; /* global for xpm color limiting */
/**
*** ParseOptions()
**/
void ParseOptions(button_info *ub)
{
char *s;
char *items[]={"iconpath","pixmappath","colorlimit",NULL,NULL};
items[3]=mymalloc(strlen(MyName)+2);
sprintf(items[3],"*%s",MyName);
GetConfigLine(fd,&s);
while(s && s[0])
{
switch(GetTokenIndex(s,items,-1,&s))
{
case -1:
break;
case 0:
if (iconPath)
free(iconPath);
CopyString(&iconPath,s);
break;
case 1:
if (pixmapPath)
free(pixmapPath);
CopyString(&pixmapPath,s);
break;
case 2: /* colorlimit */
sscanf(s,"%d",&save_color_limit);
break;
case 3:
if(s && s[0] && !config_file)
ParseConfigLine(&ub,s);
}
GetConfigLine(fd,&s);
}
if(config_file)
ParseConfigFile(ub);
free(items[3]);
return;
}