a parser for config files and the command line

This commit is contained in:
Albert Cahalan 2009-11-16 04:49:03 +00:00
parent e43ae6f497
commit 667bc062f9
2 changed files with 258 additions and 0 deletions

201
src/parse.gperf Normal file
View file

@ -0,0 +1,201 @@
%struct-type
%language=ANSI-C
%7bit
%readonly-tables
%define initializer-suffix ,0
%{
#include "parse.h"
#include <string.h>
#include <stddef.h>
#include <stdlib.h>
#include <stdio.h>
#include <ctype.h>
#include <stdint.h>
const char PARSE_YES[] = "yes";
const char PARSE_NO[] = "no";
struct cfg
{
const char *name;
void (*val)(void);
};
#define MULTIVAL 0x00000000
#define POS 0x00000001
#define NEG 0x00000002
#define BOOL (POS|NEG)
#define BITS 2 // if this grows past 2, must shift the offset
#define FLAGMASK ((1<<BITS)-1)
#define MULTI(x) (void*)(offsetof(struct cfginfo,x)|MULTIVAL)
#define POSBOOL(x) (void*)(offsetof(struct cfginfo,x)|POS|BOOL)
#define NEGBOOL(x) (void*)(offsetof(struct cfginfo,x)|NEG|BOOL)
#define IMM(x) imm_##x
static void imm_version(void)
{
}
static void imm_verbose_version(void)
{
}
static void imm_usage(void)
{
}
static void imm_help(void)
{
}
static void imm_copying(void)
{
}
%}
struct cfg
%%
alllocalefonts, POSBOOL(all_locale_fonts)
allowscreensaver, NEGBOOL(disable_screensaver)
altprint, MULTI(alt_print_command_default)
altprintalways, MULTI(alt_print_command_default)
altprintcommand, MULTI(altprintcommand)
altprintmod, MULTI(alt_print_command_default)
altprintnever, MULTI(alt_print_command_default)
autosave, POSBOOL(autosave_on_quit)
buttondistinction, NEGBOOL(no_button_distinction)
colorfile, MULTI(colorfile)
complexshapes, NEGBOOL(simple_shapes)
copying, IMM(copying)
currentlocalefont, NEGBOOL(all_locale_fonts)
datadir, MULTI(datadir)
disablescreensaver, POSBOOL(disable_screensaver)
dontgrab, NEGBOOL(grab_input)
dontmirrorstamps, NEGBOOL(mirrorstamps)
fancycursors, NEGBOOL(no_fancy_cursors)
fullscreen, MULTI(parsertmp_fullscreen_native)
grab, POSBOOL(grab_input)
help, IMM(help)
hidecursor, POSBOOL(hide_cursor)
keyboard, POSBOOL(keymouse)
label, NEGBOOL(disable_label)
lang, MULTI(parsertmp_lang)
locale, MULTI(parsertmp_locale)
lockfile, POSBOOL(ok_to_use_lockfile)
magiccontrols, NEGBOOL(disable_magic_controls)
mirrorstamps, POSBOOL(mirrorstamps)
mixedcase, NEGBOOL(only_uppercase)
mouse, NEGBOOL(keymouse)
native, POSBOOL(native_screensize)
orient, MULTI(rotate_orientation)
outlines, NEGBOOL(dont_do_xor)
papersize, MULTI(papersize)
print, NEGBOOL(disable_print)
printcfg, POSBOOL(use_print_config)
printcommand, MULTI(printcommand)
printdelay, MULTI(print_delay)
quit, NEGBOOL(disable_quit)
save, NEGBOOL(disable_save)
savedir, MULTI(savedir)
saveover, MULTI(promptless_save)
saveoverask, MULTI(promptless_save)
saveovernew, MULTI(promptless_save)
shortcuts, NEGBOOL(noshortcuts)
showcursor, NEGBOOL(hide_cursor)
simpleshapes, POSBOOL(simple_shapes)
sound, POSBOOL(use_sound)
stampcontrols, NEGBOOL(disable_stamp_controls)
stamps, NEGBOOL(dont_load_stamps)
stampsize, MULTI(stamp_size_override)
startblank, POSBOOL(start_blank)
startlast, NEGBOOL(start_blank)
sysconfig, POSBOOL(parsertmp_sysconfig)
sysfonts, NEGBOOL(no_system_fonts)
uppercase, POSBOOL(only_uppercase)
usage, IMM(usage)
verbose-version, IMM(verbose_version)
version, IMM(version)
wheelmouse, POSBOOL(wheely)
windowed, NEGBOOL(fullscreen)
windowsize, MULTI(parsertmp_windowsize)
%%
void parse_one_option(struct cfginfo *restrict tmpcfg, const char *str, const char *opt, const char *restrict src)
{
//printf("parsing: <%s> <%s>\n",str,arg);
if(isdigit(*str))
{
if(opt && !strcmp(opt,"no"))
str = "640x480";
opt = str;
str = "windowsize";
}
int noflag = 2*(str[0]=='n' && str[1]=='o' && str[2]);
const struct cfg *cfg = in_word_set(str+noflag, strlen(str+noflag));
uintptr_t uintptr = cfg ? (uintptr_t)cfg->val : 0;
unsigned flags = (uintptr<CFGINFO_MAXOFFSET) ? (uintptr & FLAGMASK) : 0;
if(!cfg || (!(flags & BOOL) && noflag) )
{
if(src)
printf("Unknown option '%s' in config file '%s'\n",str,src);
else
printf("Unknown command line option '--%s'\n",str);
exit(47);
}
if(unlikely(uintptr >= CFGINFO_MAXOFFSET))
{
if(src)
{
// immediate options are only for the command line
printf("Unknown option '%s' in config file '%s'\n",str,src);
exit(49);
}
if(opt)
{
printf("Command line option '--%s' doesn't take a value.\n",str);
exit(50);
}
cfg->val();
exit(0);
}
if(flags & BOOL)
{
int flip = !!noflag ^ !!(flags & NEG);
if(!opt)
opt = flip ? PARSE_NO : PARSE_YES;
else if(!strcmp("yes",opt))
opt = flip ? PARSE_NO : PARSE_YES;
else if(!strcmp("no",opt))
opt = flip ? PARSE_YES : PARSE_NO;
else
{
if(src)
printf("Option '%s' in config file '%s' is yes/no only, but got '%s'\n",str,src,opt);
else
printf("Command line option '--%s' is yes/no only, but got '%s'\n",str,opt);
exit(51);
}
}
else if(!opt)
{
if(src)
printf("Option '%s' in config file '%s' needs a value\n",str,src);
else
printf("Command line option '--%s' needs a value\n",str);
exit(52);
}
unsigned offset = uintptr &~ FLAGMASK;
memcpy(offset+(char*)tmpcfg, &opt, sizeof(char*));
}

57
src/parse.h Normal file
View file

@ -0,0 +1,57 @@
#pragma once
#include "compiler.h"
extern const char PARSE_YES[];
extern const char PARSE_NO[];
struct cfginfo
{
const char *all_locale_fonts;
const char *alt_print_command_default;
const char *altprintcommand;
const char *autosave_on_quit;
const char *colorfile;
const char *datadir;
const char *disable_label;
const char *disable_magic_controls;
const char *disable_print;
const char *disable_quit;
const char *disable_save;
const char *disable_screensaver;
const char *disable_stamp_controls;
const char *dont_do_xor;
const char *dont_load_stamps;
const char *fullscreen;
const char *grab_input;
const char *hide_cursor;
const char *keymouse;
const char *mirrorstamps;
const char *native_screensize;
const char *no_button_distinction;
const char *no_fancy_cursors;
const char *no_system_fonts;
const char *noshortcuts;
const char *ok_to_use_lockfile;
const char *only_uppercase;
const char *papersize;
const char *parsertmp_fullscreen_native;
const char *parsertmp_lang;
const char *parsertmp_locale;
const char *parsertmp_sysconfig;
const char *parsertmp_windowsize;
const char *print_delay;
const char *printcommand;
const char *promptless_save;
const char *rotate_orientation;
const char *savedir;
const char *simple_shapes;
const char *stamp_size_override;
const char *start_blank;
const char *use_print_config;
const char *use_sound;
const char *wheely;
};
#define CFGINFO_MAXOFFSET (sizeof(struct cfginfo))
extern void parse_one_option(struct cfginfo *restrict tmpcfg, const char *str, const char *opt, const char *restrict src);