int opt_store_int_2(char *arg, void *data){ char * tab[3]; char * end; int i = 0; unsigned * p = data; unsigned val1, val2; assert(arg && data); tab[i] = strtok(arg, ","); if (!tab[i]) { opt_err("this option requires two values seperated by ','"); } while (tab[i] != NULL) { i++; tab[i] = strtok(NULL,","); if (i == 3 ) { opt_err("this option requires two values seperated by ','"); } if (i < 2 && !tab[i]) { opt_err("this option requires two values seperated by ','"); } } //// if (i != 2) { opt_err("this option requires two values seperated by ','"); } ///// val1 = strtol(tab[0], &end, 10); errno = 0; if (end == tab[0] || end[0]) opt_err("the first value of %s must be an integer"); if (errno == ERANGE || val1 < p[1] || val1 > p[2]) { opt_err_pfx(); fprintf(stderr, "the first value of %s must be in the range %d to %d", opt_name(), p[1], p[2]); opt_err_sfx(); } p[0] = val1; val2 = strtol(tab[1], &end, 10); errno = 0; if (end == tab[0] || end[0]) opt_err("the second value of %s must be an integer"); if (errno == ERANGE || val2 < p[4] || val2 > p[5]) { opt_err_pfx(); fprintf(stderr, "the second value of %s must be in the range %d to %d", opt_name(), p[4], p[5]); opt_err_sfx(); } p[3] = val2; p[6] = 1; return 0; }
static void badchoice(const char **choices, const char *arg) { int i; for (i = 0; !EMPTY(choices[i]); ++i) ; if (choices[i]) { const char *temp = choices[i]; choices[i] = choices[0]; choices[0] = temp; return; } opt_err_pfx(); fprintf(stderr, "invalid choice '%s' for option %s", arg, opt_name()); opt_err_sfx(); }
int opt_store_choice_abbr(char *arg, void *data) { const char **choices = data, *temp; int i, j; assert(arg && data); for (i = 0; choices[i] && (strstr(choices[i], arg) != choices[i] || !choices[i][0]); ++i) ; if (!choices[i]) { badchoice(choices, arg); return 0; } for (j = i + 1; choices[j] && (strstr(choices[j], arg) != choices[j] || !choices[j][0]); ++j) ; if (choices[j]) { opt_err_pfx(); fprintf( stderr, "ambiguous choice '%s' for option %s\n%*s(%s", arg, opt_name(), (int) strlen(globals.prog) + 2, "", choices[i] ); for (;;) { i = j; for (j = i + 1; choices[j] && (strstr(choices[j], arg) != choices[j] || !choices[j][0]); ++j) ; if (!choices[j]) { fprintf(stderr, " or %s?)", choices[i]); opt_err_sfx(); } fprintf(stderr, ", %s", choices[i]); } } temp = choices[i]; choices[i] = choices[0]; choices[0] = temp; return 0; }
/** @brief Initializes syslog at the first log usage. We cannot initialize log in a constructor of static object because log may be used in constructors of other static objects (search for "static initialization order fiasco"). So let us initialize log at the first usage, and take care about multithreaded applications too. */ static void init( ) { // `syslog' should be initialized once. // Cannot use `mutex_t' here because: (1) `mutex_t' uses logger, // (2) we need statically initialized mutex. static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; static bool volatile inited = false; if ( ! inited ) { int error; static string_t const action = "syslog initialization"; error = pthread_mutex_lock( & mutex ); // Cannot use `PTHERR' macro here because the macro uses logger. if ( error ) { throw sys_err_t( _SOURCE_LOCATION_, "", action, "pthread_mutex_lock", error ); }; if ( ! inited ) { int options = LOG_CONS | LOG_PID; // We cannot use `get_opt' (or `get_bool_opt') here, because they use logger. if ( getenv( opt_name( "LOG_PERROR" ).c_str() ) ) { options |= LOG_PERROR; }; // if openlog( NULL, options, LOG_USER ); }; inited = true; error = pthread_mutex_unlock( & mutex ); if ( error ) { throw sys_err_t( _SOURCE_LOCATION_, "", action, "pthread_mutex_unlock", error ); }; }; }; // init
int opt_store_double_lim(char *arg, void *data) { char *end; double val; double *p = data; assert(arg && data); errno = 0; val = strtod(arg, &end); if (end == arg || end[0]) opt_err("the value of %s must be a number"); if (errno == ERANGE || val < p[1] || val > p[2]) { opt_err_pfx(); fprintf(stderr, "the value of %s must be in the range %g to %g", opt_name(), p[1], p[2]); opt_err_sfx(); } p[0] = val; return 0; }
int opt_store_int_lim(char *arg, void *data) { char *end; long val; int *p = data; assert(arg && data); errno = 0; val = strtol(arg, &end, 10); if (end == arg || end[0]) opt_err("the value of %s must be an integer"); if (errno == ERANGE || val < p[1] || val > p[2]) { opt_err_pfx(); fprintf(stderr, "the value of %s must be in the range %d to %d", opt_name(), p[1], p[2]); opt_err_sfx(); } p[0] = val; return 0; }
// FIXME: simulate MakeInstanceFilename(vbam.ini) using subkeys (Slave%d/*) void load_opts() { // just for sanity... bool did_init = false; if (did_init) return; did_init = true; // Translations can't be initialized in static structures (before locale // is initialized), so do them now for (int i = 0; i < num_opts; i++) opts[i].desc = wxGetTranslation(opts[i].desc); // enumvals should not be translated, since they would cause config file // change after lang change // instead, translate when presented to user wxFileConfig* cfg = wxGetApp().cfg; cfg->SetPath(wxT("/")); // enure there are no unknown options present // note that items cannot be deleted until after loop or loop will fail wxArrayString item_del, grp_del; long grp_idx; wxString s; bool cont; for (cont = cfg->GetFirstEntry(s, grp_idx); cont; cont = cfg->GetNextEntry(s, grp_idx)) { //wxLogWarning(_("Invalid option %s present; removing if possible"), s.c_str()); item_del.push_back(s); } // Date of last online update check; gopts.last_update = cfg->Read(wxT("General/LastUpdated"), (long)0); cfg->Read(wxT("General/LastUpdatedFileName"), &gopts.last_updated_filename); std::sort(&opts[0], &opts[num_opts], opt_lt); for (cont = cfg->GetFirstGroup(s, grp_idx); cont; cont = cfg->GetNextGroup(s, grp_idx)) { // ignore wxWidgets-managed global library settings if (s == wxT("wxWindows")) continue; // ignore file history if (s == wxT("Recent")) continue; cfg->SetPath(s); int poff = s.size(); long entry_idx; wxString e; for (cont = cfg->GetFirstGroup(e, entry_idx); cont; cont = cfg->GetNextGroup(e, entry_idx)) { // the only one with subgroups if (s == wxT("Joypad") && e.size() == 1 && e[0] >= wxT('1') && e[0] <= wxT('4')) { s.append(wxT('/')); s.append(e); s.append(wxT('/')); int poff2 = s.size(); cfg->SetPath(e); long key_idx; for (cont = cfg->GetFirstGroup(e, key_idx); cont; cont = cfg->GetNextGroup(e, key_idx)) { s.append(e); //wxLogWarning(_("Invalid option group %s present; removing if possible"), s.c_str()); grp_del.push_back(s); s.resize(poff2); } for (cont = cfg->GetFirstEntry(e, key_idx); cont; cont = cfg->GetNextEntry(e, key_idx)) { int i; for (i = 0; i < NUM_KEYS; i++) if (e == joynames[i]) break; if (i == NUM_KEYS) { s.append(e); //wxLogWarning(_("Invalid option %s present; removing if possible"), s.c_str()); item_del.push_back(s); s.resize(poff2); } } s.resize(poff); cfg->SetPath(wxT("/")); cfg->SetPath(s); } else { s.append(wxT('/')); s.append(e); //wxLogWarning(_("Invalid option group %s present; removing if possible"), s.c_str()); grp_del.push_back(s); s.resize(poff); } } for (cont = cfg->GetFirstEntry(e, entry_idx); cont; cont = cfg->GetNextEntry(e, entry_idx)) { // kb options come from a different list if (s == wxT("Keyboard")) { const cmditem dummy = new_cmditem(e); if (!std::binary_search(&cmdtab[0], &cmdtab[ncmds], dummy, cmditem_lt)) { s.append(wxT('/')); s.append(e); //wxLogWarning(_("Invalid option %s present; removing if possible"), s.c_str()); item_del.push_back(s); s.resize(poff); } } else { s.append(wxT('/')); s.append(e); opt_desc dummy = new_opt_desc(s); wxString opt_name(dummy.opt); if (!std::binary_search(&opts[0], &opts[num_opts], dummy, opt_lt) && opt_name != wxT("General/LastUpdated") && opt_name != wxT("General/LastUpdatedFileName")) { //wxLogWarning(_("Invalid option %s present; removing if possible"), s.c_str()); item_del.push_back(s); } s.resize(poff); } } cfg->SetPath(wxT("/")); } for (size_t i = 0; i < item_del.size(); i++) cfg->DeleteEntry(item_del[i]); for (size_t i = 0; i < grp_del.size(); i++) cfg->DeleteGroup(grp_del[i]); // now read actual values and set to default if unset // config file will be updated with unset options cfg->SetRecordDefaults(); for (int i = 0; i < num_opts; i++) { opt_desc& opt = opts[i]; if (opt.stropt) { //Fix provided by nhdailey cfg->Read(opt.opt, opt.stropt, *opt.stropt); opt.curstr = *opt.stropt; } else if (!opt.enumvals.empty()) { auto enum_opts = str_split(opt.enumvals.MakeLower(), wxT("|")); opt.curint = *opt.intopt; bool gotit = cfg->Read(opt.opt, &s); s.MakeLower(); if (gotit && !s.empty()) { const auto found_pos = vec_find(enum_opts, s); const bool matched = ((int)found_pos != wxNOT_FOUND); if (!matched) { opt.curint = 0; const wxString ev = opt.enumvals; const wxString evx = wxGetTranslation(ev); bool isx = wxStrcmp(ev, evx) != 0; // technically, the translation for this string could incorproate // the equals sign if necessary instead of doing it this way wxLogWarning(_("Invalid value %s for option %s; valid values are %s%s%s"), s.c_str(), opt.opt.c_str(), ev.c_str(), isx ? wxT(" = ") : wxEmptyString, isx ? evx.c_str() : wxEmptyString); // write first option cfg->Write(opt.opt, enum_opts[0]); } else opt.curint = found_pos; *opt.intopt = opt.curint; } else { cfg->Write(opt.opt, enum_opts[opt.curint]); } } else if (opt.intopt) { cfg->Read(opt.opt, &opt.curint, *opt.intopt); if (opt.curint < opt.min || opt.curint > opt.max) { wxLogWarning(_("Invalid value %d for option %s; valid values are %d - %d"), opt.curint, opt.opt.c_str(), opt.min, opt.max); } else *opt.intopt = opt.curint; } else if (opt.doubleopt) { cfg->Read(opt.opt, &opt.curdouble, *opt.doubleopt); if (opt.curdouble < opt.min || opt.curdouble > opt.max) { wxLogWarning(_("Invalid value %f for option %s; valid values are %f - %f"), opt.curdouble, opt.opt.c_str(), opt.min, opt.max); } else *opt.doubleopt = opt.curdouble; } else if (opt.uintopt) { int val; cfg->Read(opt.opt, &val, *opt.uintopt); opt.curuint = val; if (opt.curuint < opt.min || opt.curuint > opt.max) { wxLogWarning(_("Invalid value %f for option %s; valid values are %f - %f"), opt.curuint, opt.opt.c_str(), opt.min, opt.max); } else *opt.uintopt = opt.curuint; } else if (opt.boolopt) { cfg->Read(opt.opt, opt.boolopt, *opt.boolopt); opt.curbool = *opt.boolopt; } } // GB/Palette[0-2] is special for (int i = 0; i < 3; i++) { wxString optn; optn.Printf(wxT("GB/Palette%d"), i); wxString val; const opt_desc dummy = new_opt_desc(optn); opt_desc* opt = std::lower_bound(&opts[0], &opts[num_opts], dummy, opt_lt); wxString entry; for (int j = 0; j < 8; j++) { // stupid wxString.Printf doesn't support printing at offset entry.Printf(wxT("%04X,"), (int)systemGbPalette[i * 8 + j]); val.append(entry); } val.resize(val.size() - 1); cfg->Read(optn, &val, val); opt->curstr = val; for (int j = 0, cpos = 0; j < 8; j++) { int start = cpos; cpos = val.find(wxT(','), cpos); if ((size_t)cpos == wxString::npos) cpos = val.size(); long ival; // ignoring errors; if the value is bad, palette will be corrupt // -- tough. // stupid wxString.ToLong doesn't support start @ offset entry = val.substr(start, cpos - start); entry.ToLong(&ival, 16); systemGbPalette[i * 8 + j] = ival; if ((size_t)cpos != val.size()) cpos++; } } // joypad is special for (int i = 0; i < 4; i++) { for (int j = 0; j < NUM_KEYS; j++) { wxString optname; optname.Printf(wxT("Joypad/%d/%s"), i + 1, joynames[j].c_str()); bool gotit = cfg->Read(optname, &s); if (gotit) { gopts.joykey_bindings[i][j] = wxJoyKeyTextCtrl::FromString(s); if (s.size() && !gopts.joykey_bindings[i][j].size()) wxLogWarning(_("Invalid key binding %s for %s"), s.c_str(), optname.c_str()); } else { s = wxJoyKeyTextCtrl::ToString(gopts.joykey_bindings[i][j]); cfg->Write(optname, s); } } } // keyboard is special // Keyboard does not get written with defaults wxString kbopt(wxT("Keyboard/")); int kboff = kbopt.size(); for (int i = 0; i < ncmds; i++) { kbopt.resize(kboff); kbopt.append(cmdtab[i].cmd); if (cfg->Read(kbopt, &s) && s.size()) { wxAcceleratorEntry_v val = wxKeyTextCtrl::FromString(s); if (!val.size()) wxLogWarning(_("Invalid key binding %s for %s"), s.c_str(), kbopt.c_str()); else { for (size_t j = 0; j < val.size(); j++) val[j].Set(val[j].GetFlags(), val[j].GetKeyCode(), cmdtab[i].cmd_id); gopts.accels.insert(gopts.accels.end(), val.begin(), val.end()); } } } // recent is special // Recent does not get written with defaults cfg->SetPath(wxT("/Recent")); gopts.recent->Load(*cfg); cfg->SetPath(wxT("/")); cfg->Flush(); }
void opt_err(const char *msg) { opt_err_pfx(); fprintf(stderr, msg, opt_name()); opt_err_sfx(); }