1%struct-type 2%language=ANSI-C 3%7bit 4%readonly-tables 5%define initializer-suffix ,0 6 7%{ 8 9#include <string.h> 10#include <stddef.h> 11#include <stdlib.h> 12#include <stdio.h> 13#include <ctype.h> 14#include <stdint.h> 15#include "../src/parse.h" 16#include "../src/debug.h" 17 18const char PARSE_YES[] = "yes"; 19const char PARSE_NO[] = "no"; 20const char PARSE_CLOBBER[] = ":-("; // for painful lang/locale priority situation 21 22struct cfg 23{ 24 const char *name; 25 void (*val)(void); 26}; 27 28#define MULTIVAL 0x00000000 29#define POS 0x00000001 30#define NEG 0x00000002 31#define BOOLMASK (POS|NEG) 32#define BITS 2 // if this grows past 2, must shift the offset 33#define FLAGMASK ((1<<BITS)-1) 34 35#define MULTI(x) (void*)(offsetof(struct cfginfo,x)|MULTIVAL) 36#define POSBOOL(x) (void*)(offsetof(struct cfginfo,x)|POS) 37#define NEGBOOL(x) (void*)(offsetof(struct cfginfo,x)|NEG) 38#define IMM(x) imm_##x 39 40/* Prototypes of what's in tuxpaint.c: */ 41void show_version(int details); 42void show_usage(int exitcode); 43 44static void imm_version(void) 45{ 46 show_version(0); 47} 48 49static void imm_verbose_version(void) 50{ 51 show_version(1); 52} 53 54static void imm_usage(void) 55{ 56 show_usage(0); 57} 58 59static void imm_help(void) 60{ 61 show_version(0); 62 show_usage(0); 63} 64 65static void imm_copying(void) 66{ 67 show_version(0); 68 printf("\n" 69 "This program is free software; you can redistribute it\n" 70 "and/or modify it under the terms of the GNU General Public\n" 71 "License as published by the Free Software Foundation;\n" 72 "either version 2 of the License, or (at your option) any\n" 73 "later version.\n" 74 "\n" 75 "This program is distributed in the hope that it will be\n" 76 "useful and entertaining, but WITHOUT ANY WARRANTY; without\n" 77 "even the implied warranty of MERCHANTABILITY or FITNESS\n" 78 "FOR A PARTICULAR PURPOSE. See the GNU General Public\n" 79 "License for more details.\n" 80 "\n" 81 "You should have received a copy of the GNU General Public\n" 82 "License along with this program; if not, write to the Free\n" 83 "Software Foundation, Inc., 59 Temple Place, Suite 330,\n" 84 "Boston, MA 02111-1307 USA\n" "\n"); 85} 86 87// We get this from gperf: 88//__inline static unsigned int hash (register const char *str, register unsigned int len) 89//__inline __attribute__((__gnu_inline__)) const struct cfg *in_word_set (register const char *str, register unsigned int len); 90// 91// We use sed (see Makefile) to make those functions static. 92 93%} 94 95struct cfg 96 97%% 98alllocalefonts, POSBOOL(all_locale_fonts) 99allowscreensaver, NEGBOOL(disable_screensaver) 100altprint, MULTI(alt_print_command_default) 101altprintalways, MULTI(alt_print_command_default) 102altprintcommand, MULTI(altprintcommand) 103altprintmod, MULTI(alt_print_command_default) 104altprintnever, MULTI(alt_print_command_default) 105autosave, POSBOOL(autosave_on_quit) 106buttondistinction, NEGBOOL(no_button_distinction) 107colorfile, MULTI(colorfile) 108complexshapes, NEGBOOL(simple_shapes) 109copying, IMM(copying) 110currentlocalefont, NEGBOOL(all_locale_fonts) 111datadir, MULTI(datadir) 112disablescreensaver, POSBOOL(disable_screensaver) 113dontgrab, NEGBOOL(grab_input) 114dontmirrorstamps, NEGBOOL(mirrorstamps) 115exportdir, MULTI(exportdir) 116fancycursors, NEGBOOL(no_fancy_cursors) 117fullscreen, MULTI(parsertmp_fullscreen_native) 118grab, POSBOOL(grab_input) 119help, IMM(help) 120hidecursor, POSBOOL(hide_cursor) 121keyboard, POSBOOL(keymouse) 122label, NEGBOOL(disable_label) 123lang, MULTI(parsertmp_lang) 124locale, MULTI(parsertmp_locale) 125lockfile, POSBOOL(ok_to_use_lockfile) 126magiccontrols, NEGBOOL(disable_magic_controls) 127shapecontrols, NEGBOOL(disable_shape_controls) 128mirrorstamps, POSBOOL(mirrorstamps) 129mixedcase, NEGBOOL(only_uppercase) 130mouse, NEGBOOL(keymouse) 131native, POSBOOL(native_screensize) 132newcolorsfirst, NEGBOOL(new_colors_last) 133newcolorslast, POSBOOL(new_colors_last) 134orient, MULTI(rotate_orientation) 135outlines, NEGBOOL(dont_do_xor) 136papersize, MULTI(papersize) 137print, NEGBOOL(disable_print) 138printcfg, POSBOOL(use_print_config) 139printcommand, MULTI(printcommand) 140printdelay, MULTI(print_delay) 141quit, NEGBOOL(disable_quit) 142save, NEGBOOL(disable_save) 143savedir, MULTI(savedir) 144saveover, POSBOOL(_promptless_save_over) 145saveoverask, POSBOOL(_promptless_save_over_ask) 146saveovernew, POSBOOL(_promptless_save_over_new) 147shortcuts, NEGBOOL(noshortcuts) 148showcursor, NEGBOOL(hide_cursor) 149simpleshapes, POSBOOL(simple_shapes) 150sound, POSBOOL(use_sound) 151stereo, POSBOOL(use_stereo) 152stampcontrols, NEGBOOL(disable_stamp_controls) 153stamps, NEGBOOL(dont_load_stamps) 154stampsize, MULTI(stamp_size_override) 155startblank, POSBOOL(start_blank) 156startlast, NEGBOOL(start_blank) 157sysconfig, POSBOOL(parsertmp_sysconfig) 158sysfonts, NEGBOOL(no_system_fonts) 159uppercase, POSBOOL(only_uppercase) 160usage, IMM(usage) 161verbose-version, IMM(verbose_version) 162version, IMM(version) 163wheelmouse, POSBOOL(wheely) 164windowed, NEGBOOL(fullscreen) 165windowsize, MULTI(parsertmp_windowsize) 166buttonsize, MULTI(button_size) 167colorsrows, MULTI(colors_rows) 168mouse-accessibility, POSBOOL(mouseaccessibility) 169onscreen-keyboard, POSBOOL(onscreen_keyboard) 170onscreen-keyboard-layout, MULTI(onscreen_keyboard_layout) 171onscreen-keyboard-disable-change, POSBOOL(onscreen_keyboard_disable_change) 172joystick-dev, MULTI(joystick_dev) 173joystick-slowness, MULTI(joystick_slowness) 174joystick-threshold, MULTI(joystick_lowthreshold) 175joystick-maxsteps, MULTI(joystick_maxsteps) 176joystick-hat-slowness, MULTI(joystick_hat_slowness) 177joystick-hat-timeout, MULTI(joystick_hat_timeout) 178joystick-btn-escape, MULTI(joystick_button_escape) 179joystick-btn-brush, MULTI(joystick_button_selectbrushtool) 180joystick-btn-stamp, MULTI(joystick_button_selectstamptool) 181joystick-btn-lines, MULTI(joystick_button_selectlinestool) 182joystick-btn-shapes, MULTI(joystick_button_selectshapestool) 183joystick-btn-text, MULTI(joystick_button_selecttexttool) 184joystick-btn-label, MULTI(joystick_button_selectlabeltool) 185joystick-btn-magic, MULTI(joystick_button_selectmagictool) 186joystick-btn-undo, MULTI(joystick_button_undo) 187joystick-btn-redo, MULTI(joystick_button_redo) 188joystick-btn-eraser, MULTI(joystick_button_selecterasertool) 189joystick-btn-new, MULTI(joystick_button_new) 190joystick-btn-open, MULTI(joystick_button_open) 191joystick-btn-save, MULTI(joystick_button_save) 192joystick-btn-pgsetup, MULTI(joystick_button_pagesetup) 193joystick-btn-print, MULTI(joystick_button_print) 194joystick-buttons-ignore, MULTI(joystick_buttons_ignore) 195%% 196 197void parse_one_option(struct cfginfo *restrict tmpcfg, const char *str, const char *opt, const char *restrict src) 198{ 199 int noflag; 200 uintptr_t uintptr; 201 unsigned flags; 202 unsigned offset; 203 char *dupecheck; 204 const struct cfg *cfg; 205 206#ifdef DEBUG 207 printf("parsing %s: <%s> <%s>\n", src, str, opt); 208#endif 209 210 if(isdigit(*str)) 211 { 212 if(opt && !strcmp(opt,"no")) 213 str = "640x480"; 214 opt = str; 215 str = "windowsize"; 216 } 217 218 if (!strcmp(str, "saveover")) 219 { 220 if (!strcmp(opt, "new")) { 221 str = "saveovernew"; 222 opt = "yes"; 223 } else if (!strcmp(opt, "ask")) { 224 str = "saveoverask"; 225 opt = "yes"; 226 } else if (strcmp(opt, "yes")) { 227 if(src) 228 fprintf(stderr, "Option '%s' in config file '%s' is yes/ask/new only, but got '%s'\n",str,src,opt); 229 else 230 fprintf(stderr, "Command line option '--%s' is yes/ask/new only, but got '%s'\n",str,opt); 231 exit(51); 232 } 233 } 234 235 noflag = 2*(str[0]=='n' && str[1]=='o' && str[2]); 236 cfg = in_word_set(str+noflag, strlen(str+noflag)); 237 238 uintptr = cfg ? (uintptr_t)cfg->val : 0; 239 flags = (uintptr<CFGINFO_MAXOFFSET) ? (uintptr & FLAGMASK) : 0; 240 241 if(!cfg || (!(flags & BOOLMASK) && noflag) ) 242 { 243 if(src) 244 fprintf(stderr, "Unknown option '%s' in config file '%s'\n",str,src); 245 else 246 fprintf(stderr, "Unknown command line option '--%s'\n",str); 247 exit(47); 248 } 249 250 if(unlikely(uintptr >= CFGINFO_MAXOFFSET)) 251 { 252 if(src) 253 { 254 // immediate options are only for the command line 255 fprintf(stderr, "Unknown option '%s' in config file '%s'\n",str,src); 256 exit(49); 257 } 258 if(opt) 259 { 260 fprintf(stderr, "Command line option '--%s' doesn't take a value.\n",str); 261 exit(50); 262 } 263 cfg->val(); 264 exit(0); 265 } 266 267 if(flags & BOOLMASK) 268 { 269 int flip = !!noflag ^ !!(flags & NEG); 270 if(!opt) 271 opt = flip ? PARSE_NO : PARSE_YES; 272 else if(!strcmp("yes",opt)) 273 opt = flip ? PARSE_NO : PARSE_YES; 274 else if(!strcmp("no",opt)) 275 opt = flip ? PARSE_YES : PARSE_NO; 276 else 277 { 278 if(src) 279 fprintf(stderr, "Option '%s' in config file '%s' is yes/no only, but got '%s'\n",str,src,opt); 280 else 281 fprintf(stderr, "Command line option '--%s' is yes/no only, but got '%s'\n",str,opt); 282 exit(51); 283 } 284 } 285 else if(!opt || !*opt) 286 { 287 if(src) 288 fprintf(stderr, "Option '%s' in config file '%s' needs a value\n",str,src); 289 else 290 fprintf(stderr, "Command line option '--%s' needs a value\n",str); 291 exit(52); 292 } 293 294 offset = uintptr &~ FLAGMASK; 295 296 memcpy(&dupecheck, offset+(char*)tmpcfg, sizeof(char*)); 297 if(dupecheck) 298 { 299 if(src) 300 fprintf(stderr, "Option '%s' in config file '%s' sets '%s' again.\n",str,src,cfg->name); 301 else 302 fprintf(stderr, "Command line option '--%s' sets '%s' again.\n",str,cfg->name); 303 exit(53); 304 } 305 306 memcpy(offset+(char*)tmpcfg, &opt, sizeof(char*)); 307} 308