bool Config::PrintConfig(char const * const configfilename,bool everything) const { char temp[50];char helpline[256]; FILE* outfile=fopen(configfilename,"w+t"); if(outfile==NULL) return false; /* Print start of configfile and add an return to improve readibility. */ fprintf(outfile,MSG_Get("CONFIGFILE_INTRO"),VERSION); fprintf(outfile,"\n"); for (const_it tel=sectionlist.begin(); tel!=sectionlist.end(); tel++){ /* Print out the Section header */ Section_prop *sec = dynamic_cast<Section_prop *>(*tel); strcpy(temp,(*tel)->GetName()); lowcase(temp); if (sec) { int mods=0; Property *p; size_t i = 0, maxwidth = 0; while ((p = sec->Get_prop(i++))) { if (!everything && !p->modified()) continue; size_t w = strlen(p->propname.c_str()); if (w > maxwidth) maxwidth = w; mods++; } if (!everything && mods == 0) { /* nothing to print */ continue; } fprintf(outfile,"[%s]\n",temp); i=0; char prefix[80]; snprintf(prefix,80, "\n# %*s ", (int)maxwidth, ""); while ((p = sec->Get_prop(i++))) { if (!everything && !p->modified()) continue; std::string help = p->Get_help(); std::string::size_type pos = std::string::npos; while ((pos = help.find("\n", pos+1)) != std::string::npos) { help.replace(pos, 1, prefix); } std::vector<Value> values = p->GetValues(); if (help != "" || !values.empty()) { fprintf(outfile, "# %*s: %s", (int)maxwidth, p->propname.c_str(), help.c_str()); if (!values.empty()) { fprintf(outfile, "%s%s:", prefix, MSG_Get("CONFIG_SUGGESTED_VALUES")); std::vector<Value>::iterator it = values.begin(); while (it != values.end()) { if((*it).ToString() != "%u") { //Hack hack hack. else we need to modify GetValues, but that one is const... if (it != values.begin()) fputs(",", outfile); fprintf(outfile, " %s", (*it).ToString().c_str()); } ++it; } fprintf(outfile,"."); } fprintf(outfile, "\n"); } } } else { fprintf(outfile,"[%s]\n",temp); upcase(temp); strcat(temp,"_CONFIGFILE_HELP"); const char * helpstr=MSG_Get(temp); char * helpwrite=helpline; while (*helpstr) { *helpwrite++=*helpstr; if (*helpstr == '\n') { *helpwrite=0; fprintf(outfile,"# %s",helpline); helpwrite=helpline; } helpstr++; } } (*tel)->PrintData(outfile,everything); fprintf(outfile,"\n"); /* Always an empty line between sections */ } fclose(outfile); return true; }
void CONFIG::Run(void) { static const char* const params[] = { "-r", "-wcp", "-wcd", "-wc", "-writeconf", "-l", "-rmconf", "-h", "-help", "-?", "-axclear", "-axadd", "-axtype", "-get", "-set", "-writelang", "-wl", "-securemode", "" }; enum prs { P_NOMATCH, P_NOPARAMS, // fixed return values for GetParameterFromList P_RESTART, P_WRITECONF_PORTABLE, P_WRITECONF_DEFAULT, P_WRITECONF, P_WRITECONF2, P_LISTCONF, P_KILLCONF, P_HELP, P_HELP2, P_HELP3, P_AUTOEXEC_CLEAR, P_AUTOEXEC_ADD, P_AUTOEXEC_TYPE, P_GETPROP, P_SETPROP, P_WRITELANG, P_WRITELANG2, P_SECURE } presult = P_NOMATCH; bool first = true; std::vector<std::string> pvars; // Loop through the passed parameters while(presult != P_NOPARAMS) { presult = (enum prs)cmd->GetParameterFromList(params, pvars); switch(presult) { case P_RESTART: if (securemode_check()) return; if (pvars.size() == 0) restart_program(control->startup_params); else { std::vector<std::string> restart_params; restart_params.push_back(control->cmdline->GetFileName()); for(size_t i = 0; i < pvars.size(); i++) { restart_params.push_back(pvars[i]); if (pvars[i].find(' ') != std::string::npos) { pvars[i] = "\""+pvars[i]+"\""; // add back spaces } } // the rest on the commandline, too cmd->FillVector(restart_params); restart_program(restart_params); } return; case P_LISTCONF: { Bitu size = control->configfiles.size(); std::string config_path; Cross::GetPlatformConfigDir(config_path); WriteOut(MSG_Get("PROGRAM_CONFIG_CONFDIR"), VERSION,config_path.c_str()); if (size==0) WriteOut(MSG_Get("PROGRAM_CONFIG_NOCONFIGFILE")); else { WriteOut(MSG_Get("PROGRAM_CONFIG_PRIMARY_CONF"),control->configfiles.front().c_str()); if (size > 1) { WriteOut(MSG_Get("PROGRAM_CONFIG_ADDITIONAL_CONF")); for(Bitu i = 1; i < size; i++) WriteOut("%s\n",control->configfiles[i].c_str()); } } if (control->startup_params.size() > 0) { std::string test; for(size_t k = 0; k < control->startup_params.size(); k++) test += control->startup_params[k] + " "; WriteOut(MSG_Get("PROGRAM_CONFIG_PRINT_STARTUP"), test.c_str()); } break; } case P_WRITECONF: case P_WRITECONF2: if (securemode_check()) return; if (pvars.size() > 1) return; else if (pvars.size() == 1) { // write config to specific file, except if it is an absolute path writeconf(pvars[0], !Cross::IsPathAbsolute(pvars[0])); } else { // -wc without parameter: write primary config file if (control->configfiles.size()) writeconf(control->configfiles[0], false); else WriteOut(MSG_Get("PROGRAM_CONFIG_NOCONFIGFILE")); } break; case P_WRITECONF_DEFAULT: { // write to /userdir/dosbox0.xx.conf if (securemode_check()) return; if (pvars.size() > 0) return; std::string confname; Cross::GetPlatformConfigName(confname); writeconf(confname, true); break; } case P_WRITECONF_PORTABLE: if (securemode_check()) return; if (pvars.size() > 1) return; else if (pvars.size() == 1) { // write config to startup directory writeconf(pvars[0], false); } else { // -wcp without parameter: write dosbox.conf to startup directory if (control->configfiles.size()) writeconf(std::string("dosbox.conf"), false); else WriteOut(MSG_Get("PROGRAM_CONFIG_NOCONFIGFILE")); } break; case P_NOPARAMS: if (!first) break; case P_NOMATCH: WriteOut(MSG_Get("PROGRAM_CONFIG_USAGE")); return; case P_HELP: case P_HELP2: case P_HELP3: { switch(pvars.size()) { case 0: WriteOut(MSG_Get("PROGRAM_CONFIG_USAGE")); return; case 1: { if (!strcasecmp("sections",pvars[0].c_str())) { // list the sections WriteOut(MSG_Get("PROGRAM_CONFIG_HLP_SECTLIST")); Bitu i = 0; while(true) { Section* sec = control->GetSection(i++); if (!sec) break; WriteOut("%s\n",sec->GetName()); } return; } // if it's a section, leave it as one-param Section* sec = control->GetSection(pvars[0].c_str()); if (!sec) { // could be a property sec = control->GetSectionFromProperty(pvars[0].c_str()); if (!sec) { WriteOut(MSG_Get("PROGRAM_CONFIG_PROPERTY_ERROR")); return; } pvars.insert(pvars.begin(),std::string(sec->GetName())); } break; } case 2: { // sanity check Section* sec = control->GetSection(pvars[0].c_str()); Section* sec2 = control->GetSectionFromProperty(pvars[1].c_str()); if (sec != sec2) { WriteOut(MSG_Get("PROGRAM_CONFIG_PROPERTY_ERROR")); } break; } default: WriteOut(MSG_Get("PROGRAM_CONFIG_USAGE")); return; } // if we have one value in pvars, it's a section // two values are section + property Section* sec = control->GetSection(pvars[0].c_str()); if (sec==NULL) { WriteOut(MSG_Get("PROGRAM_CONFIG_PROPERTY_ERROR")); return; } Section_prop* psec = dynamic_cast <Section_prop*>(sec); if (psec==NULL) { // failed; maybe it's the autoexec section? Section_line* pline = dynamic_cast <Section_line*>(sec); if (pline==NULL) E_Exit("Section dynamic cast failed."); WriteOut(MSG_Get("PROGRAM_CONFIG_HLP_LINEHLP"), pline->GetName(), // this is 'unclean' but the autoexec section has no help associated MSG_Get("AUTOEXEC_CONFIGFILE_HELP"), pline->data.c_str() ); return; } if (pvars.size()==1) { size_t i = 0; WriteOut(MSG_Get("PROGRAM_CONFIG_HLP_SECTHLP"),pvars[0].c_str()); while(true) { // list the properties Property* p = psec->Get_prop(i++); if (p==NULL) break; WriteOut("%s\n", p->propname.c_str()); } } else { // find the property by it's name size_t i = 0; while (true) { Property *p = psec->Get_prop(i++); if (p==NULL) break; if (!strcasecmp(p->propname.c_str(),pvars[1].c_str())) { // found it; make the list of possible values std::string propvalues; std::vector<Value> pv = p->GetValues(); if (p->Get_type()==Value::V_BOOL) { // possible values for boolean are true, false propvalues += "true, false"; } else if (p->Get_type()==Value::V_INT) { // print min, max for integer values if used Prop_int* pint = dynamic_cast <Prop_int*>(p); if (pint==NULL) E_Exit("Int property dynamic cast failed."); if (pint->getMin() != pint->getMax()) { std::ostringstream oss; oss << pint->getMin(); oss << ".."; oss << pint->getMax(); propvalues += oss.str(); } } for(Bitu k = 0; k < pv.size(); k++) { if (pv[k].ToString() =="%u") propvalues += MSG_Get("PROGRAM_CONFIG_HLP_POSINT"); else propvalues += pv[k].ToString(); if ((k+1) < pv.size()) propvalues += ", "; } WriteOut(MSG_Get("PROGRAM_CONFIG_HLP_PROPHLP"), p->propname.c_str(), sec->GetName(), p->Get_help(),propvalues.c_str(), p->Get_Default_Value().ToString().c_str(), p->GetValue().ToString().c_str()); // print 'changability' if (p->getChange()==Property::Changeable::OnlyAtStart) { WriteOut(MSG_Get("PROGRAM_CONFIG_HLP_NOCHANGE")); } return; } } break; } return; } case P_AUTOEXEC_CLEAR: { Section_line* sec = dynamic_cast <Section_line*> (control->GetSection(std::string("autoexec"))); sec->data.clear(); break; } case P_AUTOEXEC_ADD: { if (pvars.size() == 0) { WriteOut(MSG_Get("PROGRAM_CONFIG_MISSINGPARAM")); return; } Section_line* sec = dynamic_cast <Section_line*> (control->GetSection(std::string("autoexec"))); for(Bitu i = 0; i < pvars.size(); i++) sec->HandleInputline(pvars[i]); break; } case P_AUTOEXEC_TYPE: { Section_line* sec = dynamic_cast <Section_line*> (control->GetSection(std::string("autoexec"))); WriteOut("\n%s",sec->data.c_str()); break; } case P_GETPROP: { // "section property" // "property" // "section" // "section" "property" if (pvars.size()==0) { WriteOut(MSG_Get("PROGRAM_CONFIG_GET_SYNTAX")); return; } std::string::size_type spcpos = pvars[0].find_first_of(' '); // split on the ' ' if (spcpos != std::string::npos) { pvars.insert(++pvars.begin(),pvars[0].substr(spcpos+1)); pvars[0].erase(spcpos); } switch(pvars.size()) { case 1: { // property/section only // is it a section? Section* sec = control->GetSection(pvars[0].c_str()); if (sec) { // list properties in section Bitu i = 0; Section_prop* psec = dynamic_cast <Section_prop*>(sec); if (psec==NULL) { // autoexec section Section_line* pline = dynamic_cast <Section_line*>(sec); if (pline==NULL) E_Exit("Section dynamic cast failed."); WriteOut("%s",pline->data.c_str()); break; } while(true) { // list the properties Property* p = psec->Get_prop(i++); if (p==NULL) break; WriteOut("%s=%s\n", p->propname.c_str(), p->GetValue().ToString().c_str()); } } else { // no: maybe it's a property? sec = control->GetSectionFromProperty(pvars[0].c_str()); if (!sec) { WriteOut(MSG_Get("PROGRAM_CONFIG_PROPERTY_ERROR")); return; } // it's a property name std::string val = sec->GetPropValue(pvars[0].c_str()); WriteOut("%s",val.c_str()); } break; } case 2: { // section + property Section* sec = control->GetSection(pvars[0].c_str()); if (!sec) { WriteOut(MSG_Get("PROGRAM_CONFIG_SECTION_ERROR")); return; } std::string val = sec->GetPropValue(pvars[1].c_str()); if (val == NO_SUCH_PROPERTY) { WriteOut(MSG_Get("PROGRAM_CONFIG_NO_PROPERTY"), pvars[1].c_str(),pvars[0].c_str()); return; } WriteOut("%s",val.c_str()); break; } default: WriteOut(MSG_Get("PROGRAM_CONFIG_GET_SYNTAX")); return; } return; } case P_SETPROP: { // Code for the configuration changes // Official format: config -set "section property=value" // Accepted: with or without -set, // "section property value" // "section property=value" // "property" "value" // "section" "property=value" // "section" "property=value" "value" "value" ... // "section" "property" "value" "value" ... // "section property" "value" "value" ... // "property" "value" "value" ... // "property=value" "value" "value" ... if (pvars.size()==0) { WriteOut(MSG_Get("PROGRAM_CONFIG_SET_SYNTAX")); return; } // add rest of command std::string rest; if (cmd->GetStringRemain(rest)) pvars.push_back(rest); // attempt to split off the first word std::string::size_type spcpos = pvars[0].find_first_of(' '); std::string::size_type equpos = pvars[0].find_first_of('='); if ((equpos != std::string::npos) && ((spcpos == std::string::npos) || (equpos < spcpos))) { // If we have a '=' possibly before a ' ' split on the = pvars.insert(++pvars.begin(),pvars[0].substr(equpos+1)); pvars[0].erase(equpos); // As we had a = the first thing must be a property now Section* sec=control->GetSectionFromProperty(pvars[0].c_str()); if (sec) pvars.insert(pvars.begin(),std::string(sec->GetName())); else { WriteOut(MSG_Get("PROGRAM_CONFIG_PROPERTY_ERROR")); return; } // order in the vector should be ok now } else { if ((spcpos != std::string::npos) && ((equpos == std::string::npos) || (spcpos < equpos))) { // ' ' before a possible '=', split on the ' ' pvars.insert(++pvars.begin(),pvars[0].substr(spcpos+1)); pvars[0].erase(spcpos); } // check if the first parameter is a section or property Section* sec = control->GetSection(pvars[0].c_str()); if (!sec) { // not a section: little duplicate from above Section* sec=control->GetSectionFromProperty(pvars[0].c_str()); if (sec) pvars.insert(pvars.begin(),std::string(sec->GetName())); else { WriteOut(MSG_Get("PROGRAM_CONFIG_PROPERTY_ERROR")); return; } } else { // first of pvars is most likely a section, but could still be gus // have a look at the second parameter if (pvars.size() < 2) { WriteOut(MSG_Get("PROGRAM_CONFIG_SET_SYNTAX")); return; } std::string::size_type spcpos2 = pvars[1].find_first_of(' '); std::string::size_type equpos2 = pvars[1].find_first_of('='); if ((equpos2 != std::string::npos) && ((spcpos2 == std::string::npos) || (equpos2 < spcpos2))) { // split on the = pvars.insert(pvars.begin()+2,pvars[1].substr(equpos2+1)); pvars[1].erase(equpos2); } else if ((spcpos2 != std::string::npos) && ((equpos2 == std::string::npos) || (spcpos2 < equpos2))) { // split on the ' ' pvars.insert(pvars.begin()+2,pvars[1].substr(spcpos2+1)); pvars[1].erase(spcpos2); } // is this a property? Section* sec2 = control->GetSectionFromProperty(pvars[1].c_str()); if (!sec2) { // not a property, Section* sec3 = control->GetSectionFromProperty(pvars[0].c_str()); if (sec3) { // section and property name are identical pvars.insert(pvars.begin(),pvars[0]); } // else has been checked above already } } } if(pvars.size() < 3) { WriteOut(MSG_Get("PROGRAM_CONFIG_SET_SYNTAX")); return; } // check if the property actually exists in the section Section* sec2 = control->GetSectionFromProperty(pvars[1].c_str()); if (!sec2) { WriteOut(MSG_Get("PROGRAM_CONFIG_NO_PROPERTY"), pvars[1].c_str(),pvars[0].c_str()); return; } // Input has been parsed (pvar[0]=section, [1]=property, [2]=value) // now execute Section* tsec = control->GetSection(pvars[0]); std::string value; value += pvars[2]; for(Bitu i = 3; i < pvars.size(); i++) value += (std::string(" ") + pvars[i]); std::string inputline = pvars[1] + "=" + value; tsec->ExecuteDestroy(false); bool change_success = tsec->HandleInputline(inputline.c_str()); if (!change_success) WriteOut(MSG_Get("PROGRAM_CONFIG_VALUE_ERROR"), value.c_str(),pvars[1].c_str()); tsec->ExecuteInit(false); return; } case P_WRITELANG: case P_WRITELANG2: // In secure mode don't allow a new languagefile to be created // Who knows which kind of file we would overwrite. if (securemode_check()) return; if (pvars.size() < 1) { WriteOut(MSG_Get("PROGRAM_CONFIG_MISSINGPARAM")); return; } if (!MSG_Write(pvars[0].c_str())) { WriteOut(MSG_Get("PROGRAM_CONFIG_FILE_ERROR"),pvars[0].c_str()); return; } break; case P_SECURE: // Code for switching to secure mode control->SwitchToSecureMode(); WriteOut(MSG_Get("PROGRAM_CONFIG_SECURE_ON")); return; default: E_Exit("bug"); break; } first = false; } return; }