%{
/*-
* Copyright (c) 2001 Jordan DeLong
* 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 author nor the names of contributors may be
* used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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 "wm.h"
#include "rcfile.tab.h"
/* directory that filenames w/o '/' are refering to */
char *filedir = NULL;
/* name of currently proccessing file */
char *filename = NULL;
/* are we in a forplug included file */
plugin_t *inside_forplug = NULL;
/*
* entry in the stack of included files; saves all the data
* for parsing at the point the include is started and restores
* it on the way out.
*/
typedef struct {
YY_BUFFER_STATE buffer_state;
char *filedir;
char *filename;
int lineno;
plugin_t *inside_forplug;
} incent_t;
/* stack of included files */
static incent_t include_stack[10];
static int include_stacknum = 0;
/* translate \" into " in a string from the rcfile */
static char *rclex_makestr(char *yytext, int yyleng) {
char *str;
int len, i;
/*
* make a copy of the string and chop the " chars.
* this copy gets free()'d elsewhere. (yyparse, etc)
* switch all the \" into ", \\n into '', and \\ into \
*/
str = strdup(&yytext[1]);
if (!str)
err(1, "couldn't get memory for string in rclex_makestr");
len = yyleng - 1;
str[--len] = '\0';
for (i = 0; i < len; i++)
if (str[i] == '\\') {
if (++i >= len)
break;
switch (str[i]) {
case '\n':
str[i - 1] = '\n';
memmove(&str[i - 1], &str[i + 1], len - i + 1);
len -= 2;
break;
case '\"':
str[i - 1] = '\"';
memmove(&str[i], &str[i + 1], len - i);
len--;
break;
case '\\':
str[i - 1] = '\\';
memmove(&str[i], &str[i + 1], len - i);
len--;
break;
}
}
return str;
}
/* start input from new FILE * */
static int rclex_includef(FILE *file, char *incfile,
char *newfn, plugin_t *forplug) {
char *tmpstr;
/* make sure they aren't nesting too deep */
if (include_stacknum >= sizeof(include_stack) / sizeof(incent_t)) {
warnx("includes nested too deeply, sorry.");
return -1;
}
/* save all the information we need to save */
include_stack[include_stacknum].buffer_state = YY_CURRENT_BUFFER;
if ((tmpstr = strdup(filename)) == NULL)
err(1, "strdup() failed while trying to include file");
include_stack[include_stacknum].filename = tmpstr;
if ((tmpstr = strdup(filedir)) == NULL)
err(1, "strdup() failed while trying to include file");
include_stack[include_stacknum].filedir = tmpstr;
include_stack[include_stacknum].lineno = yylineno;
include_stack[include_stacknum].inside_forplug = inside_forplug;
include_stacknum++;
/* set the values for line num and such for the new buff */
yylineno = 1;
strcpy(filename, newfn);
tmpstr = strrchr(incfile, '/');
if (tmpstr) {
*(tmpstr + 1) = '\0';
if (incfile[0] != '/')
strncat(filedir, incfile, MAXPATHLEN - strlen(filedir));
else
snprintf(filedir, MAXPATHLEN, "%s", incfile);
}
inside_forplug = forplug;
yyin = file;
yy_switch_to_buffer(yy_create_buffer(yyin, YY_BUF_SIZE));
BEGIN(INITIAL);
return 0;
}
/* begin parsing a new file; include it */
int rclex_include(char *incfile, plugin_t *forplug) {
char newfn[MAXPATHLEN];
FILE *file;
/* do this kinda early so we can try to open it first */
if (incfile[0] != '/')
snprintf(newfn, MAXPATHLEN, "%s%s", filedir, incfile);
else
snprintf(newfn, MAXPATHLEN, "%s", incfile);
/* try to open the file */
file = fopen(newfn, "r");
if (!file) {
warnx("couldn't include %s", newfn);
return -1;
}
/* start parsing it */
if (rclex_includef(file, incfile, newfn, forplug) == -1) {
fclose(file);
return -1;
}
return 0;
}
%}
%option yylineno
%option noyywrap
%option nounput
PUNCTS "("|")"|";"|":"|"{"|"}"|"|"|","
STRING "\""(("\\\"")|("\\\n")|[^"\""])+"\""
INTEGER "-"?[0-9]+
FLOAT "-"?[0-9]+\.[0-9]*
IDENT [[:upper:][:digit:]_-]*
%x INCLUDE EXEC
%%
"#".*\n /* eat commentary */
/*
* rcfile directives
*
* .include - just like CPP #include
* .exec - run a program and parse it's output
*/
^[ \t]*\."include" BEGIN(INCLUDE);
<INCLUDE>{STRING} {
char *str;
str = rclex_makestr(yytext, yyleng);
rclex_include(str, inside_forplug);
free(str);
}
<INCLUDE>\n BEGIN(INITIAL);
<INCLUDE>. /* eat */
^[ \t]*\."exec" BEGIN(EXEC);
<EXEC>{STRING} {
FILE *file;
char *str;
int fd[2];
str = rclex_makestr(yytext, yyleng);
/*
* we make a pipe, and set it as the new yyin val, and
* so forth.
*/
if (pipe(fd) != 0) {
warn("unable to make pipe for .exec include");
free(str);
YY_BREAK;
}
/* fork for our exec include */
if (!fork()) {
/* dup the write end to stdout */
if (dup2(fd[1], STDOUT_FILENO) == -1) {
warn("couldn't dup descriptor for .exec include");
exit(1);
}
/* close the read end and the nondup'd write descriptor */
close(fd[0]);
close(fd[1]);
execl(_PATH_BSHELL, "sh", "-c", str, NULL);
exit(1);
}
/* now set up the include, close the write end in the parent */
close(fd[1]);
file = fdopen(fd[0], "r");
rclex_includef(file, ".", str, inside_forplug);
free(str);
}
<EXEC>\n BEGIN(INITIAL);
<EXEC>. /* eat */
/*
* data types
*/
"true"|"yes" yylval.num = 1; return BOOLVAL;
"false"|"no" yylval.num = 0; return BOOLVAL;
"NoMask" return NOMASK;
"ShiftMask" yylval.num = ShiftMask; return MODIFIER;
"LockMask" yylval.num = LockMask; return MODIFIER;
"ControlMask" yylval.num = ControlMask; return MODIFIER;
"Mod1Mask" yylval.num = Mod1Mask; return MODIFIER;
"Mod2Mask" yylval.num = Mod2Mask; return MODIFIER;
"Mod3Mask" yylval.num = Mod3Mask; return MODIFIER;
"Mod4Mask" yylval.num = Mod4Mask; return MODIFIER;
"Mod5Mask" yylval.num = Mod5Mask; return MODIFIER;
{INTEGER} yylval.num = atoi(yytext); return INTEGER;
{FLOAT} yylval.flnum = atof(yytext); return FLOAT;
{STRING} {
char *str;
str = rclex_makestr(yytext, yyleng);
if (!str) {
warnx("can't get memory for string");
YY_BREAK;
}
yylval.str = str;
return STRING;
}
/*
* keywords
*/
"options" return OPTIONS;
"forplug" return FORPLUG;
"plugdat" return PLUGDAT;
"load" return LOAD;
"param" return PARAM;
"fileparam" return FPARAM;
"style" return STYLE;
"groups" return GROUPS;
"pixmaps" return PIXMAPS;
"keys" return KEYS;
"decoration" return DECOR;
/*
* options section
*/
"desktop_count" return DESKTOPCNT;
"desktop_width" return DESKTOPWID;
"desktop_height" return DESKTOPHEI;
"fullscreen_zoom" return FULLSCRZOOM;
"mouse_modifier" return MOUSEMOD;
"anim_delay" return ANIMDELAY;
"opaquemove" return OPAQUEMOVE;
"focus_new" return FOCUSNEW;
"linewidth" return LINEWIDTH;
"linefg" return LINEFG;
"wantmitshm" return WANTMITSHM;
"workspace_slide" return WSPACESLIDE;
"relative_resize" return RELRESIZE;
"xinerama_correctloc" return XINCORRECT;
"placement" return PLACEMENT;
"place_nonzeros" return PLACENONZEROS;
"place_transients" return PLACETRANS;
"place_interactive" return PLACEINTERACT;
"interact_timeout" return INTERACTTIME;
"placement_none" yylval.num = PLACEMENT_NONE; return PLACETYPE;
"placement_random" yylval.num = PLACEMENT_RANDOM; return PLACETYPE;
"placement_pointer" yylval.num = PLACEMENT_POINTER; return PLACETYPE;
"placement_smart" yylval.num = PLACEMENT_SMART; return PLACETYPE;
"focus" return FOCUS;
"focus_click" yylval.num = FOCUS_CLICK; return FOCUSTYPE;
"focus_sloppy" yylval.num = FOCUS_SLOPPY; return FOCUSTYPE;
"focus_pointer" yylval.num = FOCUS_POINTER; return FOCUSTYPE;
/*
* keys section
*/
"key_iconify" yylval.num = KEY_ICONIFY; return KEYNAME;
"key_zoom" yylval.num = KEY_ZOOM; return KEYNAME;
"key_switchdesktop" yylval.num = KEY_SWITCHDESK; return KEYNAME;
"key_moveviewport" yylval.num = KEY_MOVEVIEWPORT; return KEYNAME;
"key_setviewport" yylval.num = KEY_SETVIEWPORT; return KEYNAME;
"key_command" yylval.num = KEY_COMMAND; return KEYNAME;
"key_delete" yylval.num = KEY_DELETE; return KEYNAME;
"key_cycle_focus" yylval.num = KEY_CYCLEFOCUS; return KEYNAME;
"key_raise" yylval.num = KEY_RAISE; return KEYNAME;
"key_lower" yylval.num = KEY_LOWER; return KEYNAME;
"key_dgroup_switch" yylval.num = KEY_DGROUPSWITCH; return KEYNAME;
"key_sticky" yylval.num = KEY_STICKY; return KEYNAME;
"key_abort" yylval.num = KEY_ABORT; return KEYNAME;
"key_restart" yylval.num = KEY_RESTART; return KEYNAME;
"key_exit" yylval.num = KEY_EXIT; return KEYNAME;
"cycle_fwspace" yylval.num = CF_FWS; return CYCLETYPE;
"cycle_bwspace" yylval.num = CF_BWS; return CYCLETYPE;
"cycle_fscr" yylval.num = CF_FSCR; return CYCLETYPE;
"cycle_bscr" yylval.num = CF_BSCR; return CYCLETYPE;
"cycle_fall" yylval.num = CF_FALL; return CYCLETYPE;
"cycle_ball" yylval.num = CF_BALL; return CYCLETYPE;
"mv_up" yylval.num = MV_UP; return MVDIR;
"mv_down" yylval.num = MV_DOWN; return MVDIR;
"mv_left" yylval.num = MV_LEFT; return MVDIR;
"mv_right" yylval.num = MV_RIGHT; return MVDIR;
"mv_upright" yylval.num = MV_UPRIGHT; return MVDIR;
"mv_downright" yylval.num = MV_DOWNRIGHT; return MVDIR;
"mv_downleft" yylval.num = MV_DOWNLEFT; return MVDIR;
"mv_upleft" yylval.num = MV_UPLEFT; return MVDIR;
/*
* style section
*/
"title_font" return TITLEFONT;
"title_color" return TITLECOLOR;
/*
* groups section
*/
"title" return TITLE;
"transient" return TRANSIENT;
"default" return DEFAULT;
"internal" return INTERNAL;
/*
* decoration section
*/
"dec_full" yylval.num = DA_FULL; return DECTYPE;
"dec_near" yylval.num = DA_NEAR; return DECTYPE;
"dec_far" yylval.num = DA_FAR; return DECTYPE;
"dec_top" yylval.num = DE_TOP; return DECEDGE;
"dec_left" yylval.num = DE_LEFT; return DECEDGE;
"dec_right" yylval.num = DE_RIGHT; return DECEDGE;
"dec_bottom" yylval.num = DE_BOTTOM; return DECEDGE;
"act_none" yylval.num = ACT_NONE; return ACTION;
"act_move" yylval.num = ACT_MOVE; return ACTION;
"act_resize" yylval.num = ACT_RESIZE; return ACTION;
"act_delete" yylval.num = ACT_DELETE; return ACTION;
"act_iconify" yylval.num = ACT_ICONIFY; return ACTION;
"act_zoom" yylval.num = ACT_ZOOM; return ACTION;
/*
* misc rules
*/
{PUNCTS} return yytext[0];
{IDENT} yylval.str = strdup(yytext); return IDENT;
.|\n /* eat anything else */
<<EOF>> {
plugin_t *plugin;
/* close the yyin currently in use */
fclose(yyin);
/*
* come back out a level from the include; if this is
* all the way out we stop.
*/
if (--include_stacknum < 0)
yyterminate();
yy_delete_buffer(YY_CURRENT_BUFFER);
yy_switch_to_buffer(include_stack[include_stacknum].buffer_state);
/*
* we need to call init on plugins for the forplug stuff. this is
* when we have included a file as a result of a forplug directive
* earlier on.
*/
plugin = inside_forplug;
inside_forplug = include_stack[include_stacknum].inside_forplug;
if (!inside_forplug && plugin) {
if (plugin->init) {
plugin_this = plugin;
if (plugin->init(plugin) != PLUGIN_OK)
plugin_unload(plugin);
plugin_this = NULL;
}
plugin_subparams_free(&plugin->params);
}
/* set up the new file location strings and yylineno */
snprintf(filedir, MAXPATHLEN, "%s", include_stack[include_stacknum].filedir);
free(include_stack[include_stacknum].filedir);
snprintf(filename, MAXPATHLEN, "%s", include_stack[include_stacknum].filename);
free(include_stack[include_stacknum].filename);
yylineno = include_stack[include_stacknum].lineno;
}
syntax highlighted by Code2HTML, v. 0.9.1