%{ /*- * 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); {STRING} { char *str; str = rclex_makestr(yytext, yyleng); rclex_include(str, inside_forplug); free(str); } \n BEGIN(INITIAL); . /* eat */ ^[ \t]*\."exec" BEGIN(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); } \n BEGIN(INITIAL); . /* 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 */ <> { 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; }