%{ /*- * 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 "rclex.h" /* set a string option after freeing the old one */ #define SETSTR(opt, val) do { \ if ((opt)) free((opt)); \ (opt) = (val); \ } while (0) /* used for the dgroup_t that decor are being added to */ static dgroup_t *dgroup_current = NULL; /* used to build subparams */ #define SUBP_STACK_GRAN 10 static int subparams_stack_loc = 0; static int subparams_stack_size = 0; static subparams_t **subparams_stack = NULL; /* table for plugin names mapped to forplug files */ typedef struct forplug { char *plugin; /* name of the plugin */ char *incfile; /* path to conditionaly parsed file */ SLIST_ENTRY(forplug) fp_list; } forplug_t; static SLIST_HEAD(, forplug) forplug_tab = SLIST_HEAD_INITIALIZER(forplug_tab); /* yacc error reporting */ static int yyerror(char *s) { warnx("%s, %d: %s", filename, yylineno, s); return 0; } /* add a param; for the plugin parameter parsing */ static int rcfile_addparam(char *name, char *value, subparams_t *subparams) { param_t *param; /* make the paramater, name->value pair */ param = plugin_param(name, value); if (!param) goto failure; /* initialize subparams for the new parameter */ param->subparams.count = subparams ? subparams->count : 0; param->subparams.params = subparams ? subparams->params : NULL; if (subparams) free(subparams); /* add the new parameter onto the current subparam */ if (plugin_subparams_add(subparams_stack[subparams_stack_loc - 1], param) != 0) goto failure; return 0; failure: if (!param) { free(name); free(value); } else plugin_param_free(param); yyerror("couldn't add plugin parameter"); return -1; } /* add a plugin -> filename to the forplug table */ static forplug_t *rcfile_forplug(char *plugin, char *incfile) { forplug_t *fp_tab; /* add an entry to the table */ fp_tab = malloc(sizeof(forplug_t)); if (!fp_tab) return NULL; fp_tab->plugin = plugin; fp_tab->incfile = incfile; SLIST_INSERT_HEAD(&forplug_tab, fp_tab, fp_list); return fp_tab; } /* find a forplug entry for a plugin */ static forplug_t *rcfile_find_forplug(char *plugin) { forplug_t *fp_tab; SLIST_FOREACH(fp_tab, &forplug_tab, fp_list) if (strcmp(plugin, fp_tab->plugin) == 0) break; return fp_tab; } /* make a filename using filedir for relative paths */ static char *rcfile_filename(char *name) { if (name[0] != '/') { char *tmp = malloc(strlen(name) + strlen(filedir) + 1); if (!tmp) return NULL; snprintf(tmp, strlen(name) + strlen(filedir) + 1, "%s%s", filedir, name); return tmp; } else return strdup(name); } %} %union { double flnum; /* floating point values */ int num; /* numeric values */ char *str; /* string values */ void *vptr; /* some void * */ subparams_t *subparams; /* subparameters for a plugin */ } %token OPTIONS KEYS PIXMAPS DECOR STYLE PLUGDAT FORPLUG %token OPAQUEMOVE MOUSEMOD ANIMDELAY DESKTOPCNT DESKTOPWID DESKTOPHEI %token FULLSCRZOOM LINEWIDTH LINEFG WANTMITSHM WSPACESLIDE RELRESIZE %token FOCUSNEW XINCORRECT %token FOCUS FOCUSTYPE PLACEMENT PLACETYPE PLACENONZEROS PLACETRANS %token TITLEFONT TITLE TITLECOLOR KEYNAME PLACEINTERACT INTERACTTIME %token DBUTTONLINES %token DECTYPE DECEDGE ACTION %token GROUPS DEFAULT TRANSIENT INTERNAL %token LOAD PARAM FPARAM PLUGPARAM %token INTEGER BOOLVAL MODIFIER NOMASK CYCLETYPE MVDIR %token STRING IDENT %token FLOAT %type modmask modmaskifiers %type keyarg decarg pixmapid groupid %type filename %type floatval %type subparams %% rcfile : /* empty */ | rcfile error | rcfile OPTIONS '{' options_stmts '}' | rcfile KEYS '{' keys_stmts '}' | rcfile STYLE '{' style_stmts '}' | rcfile FORPLUG STRING filename ';' { if (rcfile_forplug($3, $4) == NULL) { free($3); free($4); yyerror("out of memory: couldn't make forplug entry"); YYERROR; } } | rcfile LOAD { if (inside_forplug) { yyerror("plugins may not be loaded " "from a forplug include"); YYERROR; } } STRING subparams { plugin_t *plugin; forplug_t *forplug; forplug = rcfile_find_forplug($4); if ((plugin = plugin_load($4, $5, forplug ? 0 : 1)) == NULL) { if ($5) free($5); yyerror("unable to load plugin"); YYERROR; } if (forplug) rclex_include(forplug->incfile, plugin); if ($5) free($5); } | rcfile PLUGDAT { if (!inside_forplug) { yyerror("plugdat section only valid " "in a forplug include"); YYERROR; } } subparams { plugin_subparams_merge(&inside_forplug->params, $4); if ($4) free($4); } ; options_stmts : /* empty */ | options_stmts options_stmt ';' ; keys_stmts : /* empty */ | keys_stmts keys_stmt ';' ; style_stmts : /* empty */ | style_stmts style_stmt ';' | style_stmts PIXMAPS '{' pixmaps_stmts '}' | style_stmts DECOR '{' decor_stmts '}' ; pixmaps_stmts : /* empty */ | pixmaps_stmts pixmaps_stmt ';' ; decor_stmts : /* empty */ | decor_stmts GROUPS '{' groups_stmts '}' | decor_stmts decor_stmt ';' ; groups_stmts : /* empty */ | groups_stmts groups_stmt ';' ; subparams : ';' { $$ = NULL; } | '{' { if (++subparams_stack_loc > subparams_stack_size) { subparams_t **tmp; subparams_stack_size += SUBP_STACK_GRAN; tmp = realloc(subparams_stack, subparams_stack_size * sizeof(subparams_t *)); if (!tmp) { yyerror("not enough memory while" " parsing plugin parameters"); YYERROR; } subparams_stack = tmp; } subparams_stack[subparams_stack_loc - 1] = calloc(1, sizeof(subparams_t)); } params '}' { $$ = subparams_stack[subparams_stack_loc - 1]; subparams_stack[--subparams_stack_loc] = NULL; } ; params : /* empty */ | params FPARAM STRING filename subparams { if (rcfile_addparam($3, $4, $5) == -1) YYERROR; } | params PARAM STRING STRING subparams { if (rcfile_addparam($3, $4, $5) == -1) YYERROR; } ; options_stmt : error | DESKTOPCNT INTEGER { if ($2 > 0) options.desktop_count = $2; } | DESKTOPWID INTEGER { if ($2 > 0) options.desktop_width = $2; } | DESKTOPHEI INTEGER { if ($2 > 0) options.desktop_height = $2; } | FOCUS FOCUSTYPE { options.focus = $2; } | FULLSCRZOOM BOOLVAL { options.fullscreen_zoom = $2; } | OPAQUEMOVE BOOLVAL { options.opaquemove = $2; } | FOCUSNEW BOOLVAL { options.focus_new = $2; } | MOUSEMOD modmask { options.mouse_modifier = $2; } | ANIMDELAY INTEGER { options.anim_delay = $2; } | PLACETRANS BOOLVAL { options.place_transients = $2; } | PLACENONZEROS BOOLVAL { options.place_nonzeros = $2; } | PLACEINTERACT BOOLVAL { options.place_interactive = $2; } | INTERACTTIME INTEGER { options.interact_timeout = $2; } | PLACEMENT PLACETYPE { options.placement = $2; } | LINEWIDTH INTEGER { if ($2 > 0) options.linewidth = $2; } | LINEFG STRING { SETSTR(options.linefgclr, $2); } | WANTMITSHM BOOLVAL { options.wantmitshm = $2; } | WSPACESLIDE BOOLVAL { options.workspace_slide = $2; } | RELRESIZE BOOLVAL { options.relative_resize = $2; } | XINCORRECT BOOLVAL { options.xinerama_correctloc = $2; } ; keys_stmt : error | KEYNAME STRING modmask keyarg { if (keys_add(XKeysymToKeycode(display, XStringToKeysym($2)), $3, $1, (void *) $4) == NULL) { free($2); yyerror("couldn't allocate memory for keybind_t"); YYERROR; } free($2); } ; style_stmt : error | TITLEFONT STRING { SETSTR(options.title_font, $2); } | TITLECOLOR STRING { SETSTR(options.titleclr, $2); } ; pixmaps_stmt : error | IDENT filename { if (pixmap_ident($1) != NULL) { free($1); free($2); yyerror("duplicate pixmap identifier"); YYERROR; } if (pixmap_add($1, $2) == NULL) { free($1); free($2); yyerror("couldn't allocate memory for pixmap"); YYERROR; } } ; groups_stmt : error | addgroup decorlist { dgroup_current = NULL; } | DEFAULT groupid { options.dgroup_default = $2; } | TRANSIENT groupid { options.dgroup_trans = $2; } | INTERNAL groupid { options.dgroup_internal = $2; } ; decor_stmt : error | IDENT DECTYPE DECEDGE INTEGER INTEGER INTEGER floatval floatval BOOLVAL BOOLVAL ACTION ACTION ACTION pixmapid pixmapid decarg { decor_t *decor; if (decor_ident($1) != NULL) { free($1); yyerror("duplicate decoration identifier\n"); YYERROR; } decor = calloc(1, sizeof(decor_t)); if (!decor) { free($1); yyerror("couldn't allocate memory for decoration."); YYERROR; } decor->ident = $1; decor->type = $2; decor->edge = $3; decor->offset = $4; decor->lenmod = $5; decor->soffset = $6; decor->offsetmult = $7; decor->lenmult = $8; decor->flags.shaped = $9; decor->flags.button = $10; decor->lclick_action = $11; decor->mclick_action = $12; decor->rclick_action = $13; decor->pixmap = $14; decor->focpixmap = $15; decor->pressedmap = $16; decor_add(decor); } ; filename : STRING { char *tmp = rcfile_filename($1); free($1); if (!tmp) { yyerror("couldn't get memory for filename"); YYERROR; } $$ = tmp; } ; floatval : INTEGER { $$ = (double) $1; } | FLOAT ; modmask : '(' modmaskifiers ')' { $$ = $2; } | '(' NOMASK ')' { $$ = 0; } ; modmaskifiers : MODIFIER | modmaskifiers '|' MODIFIER { $$ |= $3; } ; keyarg : /* empty */ { $$ = (void *) 0; } | STRING { $$ = (void *) $1; } | INTEGER { $$ = (void *) $1; } | MVDIR { $$ = (void *) $1; } | CYCLETYPE { $$ = (void *) $1; } | INTEGER ',' INTEGER { point_t *pt; pt = malloc(sizeof(point_t)); if (!pt) { yyerror("couldn't get memory for keyarg, point_t"); YYERROR; } pt->x = $1; pt->y = $3; $$ = (void *) pt; } ; decarg : /* empty */ { $$ = NULL; } | pixmapid ; addgroup : IDENT { if (dgroup_ident($1) != NULL) { free($1); yyerror("duplicate decoration group identifier"); YYERROR; } if ((dgroup_current = dgroup_add($1)) == NULL) { free($1); yyerror("couldn't allocate memory for decoration group"); YYERROR; } } ; decorlist : /* empty */ | decorlist IDENT { decor_t *decor; decor = decor_ident($2); free($2); if (decor == NULL) { yyerror("undeclared decoration group identifier"); YYERROR; } if (dgroup_add_decor(dgroup_current, decor) == -1) warnx("out of mem trying to add decor to dgroup"); } | decorlist IDENT ':' TITLE ':' INTEGER ':' INTEGER { decor_t *decor; decor = decor_ident($2); free($2); if (decor == NULL) { yyerror("undeclared decoration group identifier"); YYERROR; } if (dgroup_add_decor(dgroup_current, decor) == -1) warnx("out of mem trying to add decor to dgroup"); /* now add to the title for the group */ dgroup_current->title = decor; dgroup_current->title_x = $6; dgroup_current->title_y = $8; } ; groupid : IDENT { dgroup_t *dgroup = dgroup_ident($1); free($1); if (dgroup == NULL) { yyerror("undeclared decoration group identifier"); YYERROR; } $$ = dgroup; } ; pixmapid : IDENT { pixmap_t *pixmap = pixmap_ident($1); free($1); if (pixmap == NULL) { yyerror("undeclared pixmap identifier"); YYERROR; } $$ = pixmap; } ; %% /* exported parsing function */ void rcfile_parse() { forplug_t *fp_tab, *next; char rcfn[MAXPATHLEN]; FILE *fp; /* * get space for filename/dir strings, and for the subparams * stack. the subparams stack is used for parsing of plugin * subparams in the yacc grammar. */ filedir = malloc(MAXPATHLEN); if (!filedir) return; filename = malloc(MAXPATHLEN); if (!filename) goto free1; subparams_stack_size = SUBP_STACK_GRAN; subparams_stack = calloc(subparams_stack_size, sizeof(subparams_t *)); if (!subparams_stack) goto free2; /* build file location strings */ snprintf(filedir, MAXPATHLEN, "%s/.golem/", homedir_path); snprintf(filename, MAXPATHLEN, "%s", "golemrc"); snprintf(rcfn, sizeof(rcfn), "%s%s", filedir, filename); /* * attempt to open the user's golemrc, if not, try for * the system-wide rc file. */ fp = fopen(rcfn, "r"); if (!fp) { snprintf(filedir, MAXPATHLEN, "%s/golem/", DATADIR); snprintf(rcfn, sizeof(rcfn), "%s%s", filedir, filename); fp = fopen(rcfn, "r"); if (!fp) goto free3; warnx("unable to read from ~/.golem/golemrc, using system-wide file"); } /* * parse the file, when the flexer reaches EOF for the * file, it will call fclose() on it, so it is not * necessary to call that here. */ yyin = fp; yyparse(); /* free the forplug table */ fp_tab = SLIST_FIRST(&forplug_tab); while (fp_tab) { next = SLIST_NEXT(fp_tab, fp_list); free(fp_tab->incfile); free(fp_tab->plugin); free(fp_tab); fp_tab = next; } SLIST_INIT(&forplug_tab); free3: free(subparams_stack); subparams_stack = NULL; free2: free(filename); filename = NULL; free1: free(filedir); filedir = NULL; }