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