X-Git-Url: https://git.mxchange.org/?a=blobdiff_plain;f=src%2FInput%2Ffgjs.cxx;h=59effd534ddf7cd080160ef3fe41eb7fd79f3b94;hb=76020894600c4d20f958f3d402419dc0fce78b74;hp=eec3eb6839f7f222bed3f8df4511c5984879e5da;hpb=c9813d1b5d79b4aad13c263690a0223086af25ac;p=flightgear.git diff --git a/src/Input/fgjs.cxx b/src/Input/fgjs.cxx index eec3eb683..59effd534 100644 --- a/src/Input/fgjs.cxx +++ b/src/Input/fgjs.cxx @@ -6,6 +6,7 @@ // Written by Tony Peden, started May 2001 // // Copyright (C) 2001 Tony Peden (apeden@earthlink.net) +// Copyright (C) 2006 Stefan Seifert // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License as @@ -21,477 +22,355 @@ // along with this program; if not, write to the Free Software // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +#ifdef HAVE_CONFIG_H +# include +#endif + #include +#ifdef _WIN32 +# include +#endif + #include -#include STL_IOSTREAM -#include STL_FSTREAM -#include STL_STRING - -#include - -SG_USING_STD(fstream); -SG_USING_STD(cout); -SG_USING_STD(cin); -SG_USING_STD(endl); -SG_USING_STD(ios); -SG_USING_STD(string); - -string axes_humannames[8] = { "Aileron", "Elevator", "Rudder", "Throttle", - "Mixture", "Pitch", "View Direction", - "View Elevation" - }; - -string axes_propnames[8]={ "/controls/flight/aileron","/controls/flight/elevator", - "/controls/flight/rudder","/controls/engines/engine[%d]/throttle", - "/controls/engines/engine[%d]/mixture","/controls/engines/engine[%d]/pitch", - "/sim/current-view/goal-heading-offset-deg", - "/sim/current-view/goal-pitch-offset-deg" - }; - -string axis_posdir[8]= { "right", "down/forward", "right", "forward", "forward", "forward", "left", "upward" }; - - -bool half_range[8]={ false,false,false,true,true,true,false,false }; - -bool repeatable[8]={ false,false,false,false,false,false,true,true }; - -bool invert[8]= { false,false,false,false,false,false,false,false }; - -string button_humannames[8]= { "Left Brake", "Right Brake", - "Flaps Up", "Flaps Down", - "Elevator Trim Forward", "Elevator Trim Backward", - "Landing Gear Up", "Landing Gear Down" - }; - -string button_propnames[8]={ "/controls/gear/brake-left", - "/controls/gear/brake-right", - "/controls/flight/flaps", - "/controls/flight/flaps", - "/controls/flight/elevator-trim", - "/controls/flight/elevator-trim", - "/controls/gear/gear-down", - "/controls/gear/gear-down" - }; - -bool button_modup[8]={ true,true,false,false,false,false,false,false }; - -bool button_boolean[8]={ false,false,false,false,false,false,true,true }; - -float button_step[8]={ 1.0, 1.0, -0.34, 0.34, 0.001, -0.001, 0.0, 1.0 }; - -string button_repeat[8]={ "false", "false", "false", "false", "true", "true", "false", "false" }; - - -void writeAxisXML(fstream &fs, int control, int axis) { - - char axisline[16]; - snprintf(axisline,16," ",axis); - - fs << axisline << endl; - fs << " " << axes_humannames[control] << "" << endl; - if (half_range[control]) { - for (int i=0; i<=7; i++) { - fs << " " << endl; - fs << " property-scale" << endl; - char propertyline[256]; - snprintf(propertyline,256,axes_propnames[control].c_str(),i); - fs << " " << propertyline << "" << endl; - fs << " -1.0" << endl; - fs << " -0.5" << endl; - fs << " " << endl; - } - } else if (repeatable[control]) { - fs << " " << endl; - fs << " true" << endl; - fs << " " << endl; - fs << " property-adjust" << endl; - fs << " " << axes_propnames[control] << "" << endl; - if (invert[control]) { - fs << " 1.0" << endl; - } else { - fs << " -1.0" << endl; - } - fs << " " << endl; - fs << " " << endl; - fs << " " << endl; - fs << " true" << endl; - fs << " " << endl; - fs << " property-adjust" << endl; - fs << " " << axes_propnames[control] << "" << endl; - if (invert[control]) { - fs << " -1.0" << endl; - } else { - fs << " 1.0" << endl; - } - fs << " " << endl; - fs << " " << endl; - } else { - fs << " " << endl; - fs << " property-scale" << endl; - fs << " " << axes_propnames[control] << "" << endl; - fs << " 0.02" << endl; - fs << " 0.0" << endl; - if (invert[control]) { - fs << " -1.0" << endl; - } else { - fs << " 1.0" << endl; - } - fs << " " << endl; - } - fs << " " << endl << endl; +#include +#include +#include + +using std::fstream; +using std::cout; +using std::cin; +using std::endl; +using std::ios; +using std::string; + +#include +#include +#include +#include +#include +#include + +#include
+#include
+#include
+ +#include "jsinput.h" + +#ifdef __APPLE__ +# include +#endif + +using simgear::PropertyList; + +bool confirmAnswer() { + char answer; + do { + cout << "Is this correct? (y/n) $ "; + cin >> answer; + cin.ignore(256, '\n'); + if (answer == 'y') + return true; + if (answer == 'n') + return false; + } while (true); } -void writeAxisProperties(fstream &fs, int control,int joystick, int axis) { - - char jsDesc[80]; - snprintf(jsDesc,80,"--prop:/input/joysticks/js[%d]/axis[%d]",joystick,axis); - if( half_range[control] == true) { - for (int i=0; i<=7; i++) { - char bindno[64]; - snprintf(bindno,64,"/binding[%d]",i); - char propertyline[256]; - snprintf(propertyline,256,axes_propnames[control].c_str(),i); - fs << jsDesc << bindno << "/command=property-scale" << endl; - fs << jsDesc << bindno << "/property=" << propertyline << endl; - fs << jsDesc << bindno << "/offset=-1.0" << endl; - fs << jsDesc << bindno << "/factor=-0.5" << endl; - } - } else if (repeatable[control]) { - fs << jsDesc << "/low/repeatable=true" << endl; - fs << jsDesc << "/low/binding/command=property-adjust" << endl; - fs << jsDesc << "/low/binding/property=" << axes_propnames[control] << endl; - if (invert[control]) { - fs << jsDesc << "/low/binding/step=1.0" << endl; - } else { - fs << jsDesc << "/low/binding/step=-1.0" << endl; - } - fs << jsDesc << "/high/repeatable=true" << endl; - fs << jsDesc << "/high/binding/command=property-adjust" << endl; - fs << jsDesc << "/high/binding/property=" << axes_propnames[control] << endl; - if (invert[control]) { - fs << jsDesc << "/high/binding/step=-1.0" << endl; - } else { - fs << jsDesc << "/high/binding/step=1.0" << endl; - } - } else { - fs << jsDesc << "/binding/command=property-scale" << endl; - fs << jsDesc << "/binding/property=" << axes_propnames[control] << endl; - fs << jsDesc << "/binding/dead-band=0.02" << endl; - fs << jsDesc << "/binding/offset=0.0" << endl; - if (invert[control]) { - fs << jsDesc << "/binding/factor=-1.0" << endl; - } else { - fs << jsDesc << "/binding/factor=1.0" << endl; - } - } - fs << endl; -} +string getFGRoot( int argc, char *argv[] ); + +int main( int argc, char *argv[] ) { + + for (int i = 1; i < argc; i++) { + if (strcmp("--help", argv[i]) == 0) { + cout << "Usage:" << endl; + cout << " --help\t\t\tShow this help" << endl; + exit(0); + } else if (strncmp("--fg-root=", argv[i], 10) == 0) { + // used later + } else { + cout << "Unknown option \"" << argv[i] << "\"" << endl; + exit(0); + } + } + + jsInit(); + + jsSuper *jss = new jsSuper(); + jsInput *jsi = new jsInput(jss); + jsi->displayValues(false); -void writeButtonXML(fstream &fs, int property, int button) { - - char buttonline[32]; - snprintf(buttonline,32," " << endl << endl; + cout << "Found " << jss->getNumJoysticks() << " joystick(s)" << endl; + + if(jss->getNumJoysticks() <= 0) { + cout << "Can't find any joysticks ..." << endl; + exit(1); + } + cout << endl << "Now measuring the dead band of your joystick. The dead band is the area " << endl + << "where the joystick is centered and should not generate any input. Move all " << endl + << "axes around in this dead zone during the ten seconds this test will take." << endl; + cout << "Press enter to continue." << endl; + cin.ignore(1024, '\n'); + jsi->findDeadBand(); + cout << endl << "Dead band calibration finished. Press enter to start control assignment." << endl; + cin.ignore(1024, '\n'); + + jss->firstJoystick(); + fstream *xfs = new fstream[ jss->getNumJoysticks() ]; + SGPropertyNode_ptr *jstree = new SGPropertyNode_ptr[ jss->getNumJoysticks() ]; + do { + cout << "Joystick #" << jss->getCurrentJoystickId() + << " \"" << jss->getJoystick()->getName() << "\" has " + << jss->getJoystick()->getNumAxes() << " axes" << endl; + + char filename[16]; + snprintf(filename, 16, "js%i.xml", jss->getCurrentJoystickId()); + xfs[ jss->getCurrentJoystickId() ].open(filename, ios::out); + jstree[ jss->getCurrentJoystickId() ] = new SGPropertyNode(); + } while ( jss->nextJoystick() ); + + SGPath templatefile( getFGRoot(argc, argv) ); + templatefile.append("Input"); + templatefile.append("Joysticks"); + templatefile.append("template.xml"); + + SGPropertyNode *templatetree = new SGPropertyNode(); + try { + readProperties(templatefile.str().c_str(), templatetree); + } catch (sg_io_exception & e) { + cout << e.getFormattedMessage (); + } + + PropertyList axes = templatetree->getChildren("axis"); + for(PropertyList::iterator iter = axes.begin(); iter != axes.end(); ++iter) { + cout << "Move the control you wish to use for " << (*iter)->getStringValue("desc") + << " " << (*iter)->getStringValue("direction") << endl; + cout << "Pressing a button skips this axis" << endl; + fflush( stdout ); + jsi->getInput(); + if (jsi->getInputAxis() != -1) { + cout << endl << "Assigned axis " << jsi->getInputAxis() + << " on joystick " << jsi->getInputJoystick() + << " to control " << (*iter)->getStringValue("desc") << endl; + if ( confirmAnswer() ) { + SGPropertyNode *axis = jstree[ jsi->getInputJoystick() ]->getChild("axis", jsi->getInputAxis(), true); + copyProperties(*iter, axis); + axis->setDoubleValue("dead-band", jss->getJoystick(jsi->getInputJoystick()) + ->getDeadBand(jsi->getInputAxis())); + axis->setDoubleValue("binding/factor", jsi->getInputAxisPositive() ? 1.0 : -1.0); + } else { + --iter; + } + } else { + cout << "Skipping control" << endl; + if ( ! confirmAnswer() ) + --iter; + } + cout << endl; + } + + PropertyList buttons = templatetree->getChildren("button"); + for(PropertyList::iterator iter = buttons.begin(); iter != buttons.end(); ++iter) { + cout << "Press the button you wish to use for " << (*iter)->getStringValue("desc") << endl; + cout << "Moving a joystick axis skips this button" << endl; + fflush( stdout ); + jsi->getInput(); + if (jsi->getInputButton() != -1) { + cout << endl << "Assigned button " << jsi->getInputButton() + << " on joystick " << jsi->getInputJoystick() + << " to control " << (*iter)->getStringValue("desc") << endl; + if ( confirmAnswer() ) { + SGPropertyNode *button = jstree[ jsi->getInputJoystick() ]->getChild("button", jsi->getInputButton(), true); + copyProperties(*iter, button); + } else { + --iter; + } + } else { + cout << "Skipping control" << endl; + if (! confirmAnswer()) + --iter; + } + cout << endl; + } + + cout << "Your joystick settings are in "; + for (int i = 0; i < jss->getNumJoysticks(); i++) { + try { + cout << "js" << i << ".xml"; + if (i + 2 < jss->getNumJoysticks()) + cout << ", "; + else if (i + 1 < jss->getNumJoysticks()) + cout << " and "; + + jstree[i]->setStringValue("name", jss->getJoystick(i)->getName()); + writeProperties(xfs[i], jstree[i], true); + } catch (sg_io_exception & e) { + cout << e.getFormattedMessage (); + } + xfs[i].close(); + } + cout << "." << endl << "Check and edit as desired. Once you are happy," << endl + << "move relevant js.xml files to $FG_ROOT/Input/Joysticks/ (if you didn't use" << endl + << "an attached controller, you don't need to move the corresponding file)" << endl; + + delete jsi; + delete[] xfs; + delete jss; + delete[] jstree; + + return 1; } -void writeButtonProperties(fstream &fs, int property,int joystick, int button) { - - char jsDesc[80]; - snprintf(jsDesc,80,"--prop:/input/joysticks/js[%d]/button[%d]",joystick,button); - - if (property==-1) { - fs << jsDesc << "/binding[0]/command=property-assign" << endl; - fs << jsDesc << "/binding[0]/property=" << button_propnames[0] << endl; - fs << jsDesc << "/binding[0]/value=" << button_step[0] << endl; - fs << jsDesc << "/binding[1]/command=property-assign" << endl; - fs << jsDesc << "/binding[1]/property=" << button_propnames[1] << endl; - fs << jsDesc << "/binding[1]/value=" << button_step[1] << endl; - fs << jsDesc << "/mod-up/binding[0]/command=property-assign" << endl; - fs << jsDesc << "/mod-up/binding[0]/property=" << button_propnames[0] << endl; - fs << jsDesc << "/mod-up/binding[0]/value=0" << endl; - fs << jsDesc << "/mod-up/binding[1]/command=property-assign" << endl; - fs << jsDesc << "/mod-up/binding[1]/property=" << button_propnames[1] << endl; - fs << jsDesc << "/mod-up/binding[1]/value=0" << endl; - fs << endl; - } else if (button_modup[property]) { - fs << jsDesc << "/binding/command=property-assign" << endl; - fs << jsDesc << "/binding/property=" << button_propnames[property] << endl; - fs << jsDesc << "/binding/value=" << button_step[property] << endl; - fs << jsDesc << "/mod-up/binding/command=property-assign" << endl; - fs << jsDesc << "/mod-up/binding/property=" << button_propnames[property] << endl; - fs << jsDesc << "/mod-up/binding/value=0" << endl; - fs << endl; - } else if (button_boolean[property]) { - fs << jsDesc << "/repeatable=" << button_repeat[property] << endl; - fs << jsDesc << "/binding/command=property-assign" << endl; - fs << jsDesc << "/binding/property=" << button_propnames[property] << endl; - fs << jsDesc << "/binding/value="; - if (button_step[property]==1) { - fs << "true"; - } else { - fs << "false"; - } - fs << endl << endl; - } else { - fs << jsDesc << "/repeatable=" << button_repeat[property] << endl; - fs << jsDesc << "/binding/command=property-adjust" << endl; - fs << jsDesc << "/binding/property=" << button_propnames[property] << endl; - fs << jsDesc << "/binding/step=" << button_step[property] << endl; - fs << endl; - } +char *homedir = ::getenv( "HOME" ); +char *hostname = ::getenv( "HOSTNAME" ); +bool free_hostname = false; + +// Scan the command line options for the specified option and return +// the value. +static string fgScanForOption( const string& option, int argc, char **argv ) { + int i = 1; + + if (hostname == NULL) + { + char _hostname[256]; + gethostname(_hostname, 256); + hostname = strdup(_hostname); + free_hostname = true; + } + + SG_LOG(SG_INPUT, SG_INFO, "Scanning command line for: " << option ); + + int len = option.length(); + + while ( i < argc ) { + SG_LOG( SG_INPUT, SG_DEBUG, "argv[" << i << "] = " << argv[i] ); + + string arg = argv[i]; + if ( arg.find( option ) == 0 ) { + return arg.substr( len ); + } + + i++; + } + + return ""; } -int main( int argc, char *argv[] ) { +// Scan the user config files for the specified option and return +// the value. +static string fgScanForOption( const string& option, const string& path ) { + sg_gzifstream in( path ); + if ( !in.is_open() ) { + return ""; + } + + SG_LOG( SG_INPUT, SG_INFO, "Scanning " << path << " for: " << option ); + + int len = option.length(); + + in >> skipcomment; + while ( ! in.eof() ) { + string line; + getline( in, line, '\n' ); + + // catch extraneous (DOS) line ending character + if ( line[line.length() - 1] < 32 ) { + line = line.substr( 0, line.length()-1 ); + } - bool usexml=true; - float deadband=0; - char answer[128]; - int btninit=-2; - - for (int i=1; i\t\tSet deadband (for this program only, useful" << endl; - cout << "\t\t\t\tfor 'twitchy' joysticks)" << endl; - exit(0); - } else if (strcmp("--prop",argv[i])==0) { - usexml=false; - btninit=-1; - } else if (strcmp("--deadband",argv[i])==0) { - i++; - deadband=atoi(argv[i]); - cout << "Deadband set to " << argv[i] << endl; - } else if (strcmp("--xml",argv[i])!=0) { - cout << "Unknown option \"" << argv[i] << "\"" << endl; - exit(0); + if ( line.find( option ) == 0 ) { + return line.substr( len ); + } + + in >> skipcomment; } - } - - jsInit(); - - jsSuper *jss=new jsSuper(); - jsInput *jsi=new jsInput(jss); - jsi->displayValues(false); - int control=0; - - cout << "Found " << jss->getNumJoysticks() << " joystick(s)" << endl; - - if(jss->getNumJoysticks() <= 0) { - cout << "Can't find any joysticks ..." << endl; - exit(1); - } - - fstream fs; - fstream *xfs = new fstream[jss->getNumJoysticks()]; - if (!usexml) { - fs.open("fgfsrc.js",ios::out); - } - - jss->firstJoystick(); - do { - cout << "Joystick #" << jss->getCurrentJoystickId() - << " \"" << jss->getJoystick()->getName() << "\" has " - << jss->getJoystick()->getNumAxes() << " axes" << endl; - for (int i=0; igetJoystick()->getNumAxes(); i++) { - jss->getJoystick()->setDeadBand(i,deadband); + + return ""; +} + +// Scan the user config files for the specified option and return +// the value. +static string fgScanForOption( const string& option ) { + string arg(""); + +#if defined( unix ) || defined( __CYGWIN__ ) + // Next check home directory for .fgfsrc.hostname file + if ( arg.empty() ) { + if ( homedir != NULL ) { + SGPath config( homedir ); + config.append( ".fgfsrc" ); + config.concat( "." ); + config.concat( hostname ); + arg = fgScanForOption( option, config.str() ); + } } - if (usexml) { - char filename[16]; - snprintf(filename,16,"js%i.xml",jss->getCurrentJoystickId()); - xfs[jss->getCurrentJoystickId()].open(filename,ios::out); - xfs[jss->getCurrentJoystickId()] << "" << endl - << endl << "" << endl << endl << " " - << jss->getJoystick()->getName() << "" << endl << endl; +#endif + + // Next check home directory for .fgfsrc file + if ( arg.empty() ) { + if ( homedir != NULL ) { + SGPath config( homedir ); + config.append( ".fgfsrc" ); + arg = fgScanForOption( option, config.str() ); + } } - } while( jss->nextJoystick() ); - - for(control=0;control<=7;control++) { - cout << "Move the control you wish to use for " << axes_humannames[control] - << " " << axis_posdir[control] << endl; - cout << "Pressing a button skips this axis\n"; - fflush( stdout ); - jsi->getInput(); - - if(jsi->getInputAxis() != -1) { - cout << endl << "Assigned axis " << jsi->getInputAxis() - << " on joystick " << jsi->getInputJoystick() - << " to control " << axes_humannames[control] - << endl; - bool badanswer=true; - do { - cout << "Is this correct? (y/n) $ "; - cin >> answer; - if ((strcmp(answer,"y")==0) || (strcmp(answer,"n")==0)) { badanswer=false; } - } while (badanswer); - if (strcmp(answer,"n")==0) { - control--; - } else { - invert[control]=!jsi->getInputAxisPositive(); - if (usexml) { - writeAxisXML( xfs[jsi->getInputJoystick()], control, jsi->getInputAxis() ); - } else { - writeAxisProperties( fs, control, jsi->getInputJoystick(), jsi->getInputAxis() ); - } - } - } else { - cout << "Skipping control" << endl; - bool badanswer=true; - do { - cout << "Is this correct? (y/n) $ "; - cin >> answer; - if ((strcmp(answer,"y")==0) || (strcmp(answer,"n")==0)) { badanswer=false; } - } while (badanswer); - if (strcmp(answer,"n")==0) { control--; } - } - cout << endl; - } - - for(control=btninit;control<=7;control++) { - if ( control == -2 ) { - cout << "Press the button you wish to use for View Cycle" << endl; - } else if ( control == -1 ) { - cout << "Press the button you wish to use for Brakes" << endl; - } else { - cout << "Press the button you wish to use for " << button_humannames[control] << endl; - } - cout << "Moving a joystick axis skips this button\n"; - fflush( stdout ); - jsi->getInput(); - if(jsi->getInputButton() != -1) { - cout << endl << "Assigned button " << jsi->getInputButton() - << " on joystick " << jsi->getInputJoystick() - << " to control "; - if ( control == -2 ) { cout << "View Cycle" << endl; } - else if ( control == -1 ) { cout << "Brakes" << endl; } - else { cout << button_humannames[control] << endl; } - bool badanswer=true; - do { - cout << "Is this correct? (y/n) $ "; - cin >> answer; - if ((strcmp(answer,"y")==0) || (strcmp(answer,"n")==0)) { badanswer=false; } - } while (badanswer); - if (strcmp(answer,"n")==0) { - control--; - } else { - if (usexml) { - writeButtonXML( xfs[jsi->getInputJoystick()], control, jsi->getInputButton() ); - } else { - writeButtonProperties( fs, control, jsi->getInputJoystick(), jsi->getInputButton() ); - } - } - } else { - cout << "Skipping control" << endl; - bool badanswer=true; - do { - cout << "Is this correct? (y/n) $ "; - cin >> answer; - if ((strcmp(answer,"y")==0) || (strcmp(answer,"n")==0)) { badanswer=false; } - } while (badanswer); - if (strcmp(answer,"n")==0) { control--; } - } - - cout << endl; - } - if (usexml) { - for (int i=0; igetNumJoysticks(); i++) { - xfs[i] << "" << endl << endl << "" << endl; - xfs[i].close(); + + return arg; +} + +// Read in configuration (files and command line options) but only set +// fg_root +string getFGRoot ( int argc, char **argv ) { + string root; + + // First parse command line options looking for --fg-root=, this + // will override anything specified in a config file + root = fgScanForOption( "--fg-root=", argc, argv); + + // Check in one of the user configuration files. + if (root.empty() ) + root = fgScanForOption( "--fg-root=" ); + + // Next check if fg-root is set as an env variable + if ( root.empty() ) { + char *envp = ::getenv( "FG_ROOT" ); + if ( envp != NULL ) { + root = envp; + } } - } else { - fs.close(); - } - delete jsi; - delete[] xfs; - delete jss; - - cout << "Your joystick settings are in "; - if (usexml) { - cout << "js0.xml, js1.xml, etc. depending on how many" << endl << "devices you have." << endl; - } else { - cout << "fgfsrc.js" << endl; - } - cout << endl << "Check and edit as desired. Once you are happy," << endl; - if (usexml) { - cout << "move relevant js.xml files to $FG_ROOT/Input/Joysticks/ (if you didn't use" << endl - << "an attached controller, you don't need to move the corresponding file)" << endl; - } else { - cout << "append its contents to your .fgfsrc or system.fgfsrc" << endl; - } - return 1; + // Otherwise, default to a random compiled-in location if we can't + // find fg-root any other way. + if ( root.empty() ) { +#if defined( __CYGWIN__ ) + root = "../data"; +#elif defined( _WIN32 ) + root = "..\\data"; +#elif defined(__APPLE__) + /* + The following code looks for the base package inside the application + bundle, in the standard Contents/Resources location. + */ + + CFURLRef resourcesUrl = CFBundleCopyResourcesDirectoryURL(CFBundleGetMainBundle()); + + // look for a 'data' subdir + CFURLRef dataDir = CFURLCreateCopyAppendingPathComponent(NULL, resourcesUrl, CFSTR("data"), true); + + // now convert down to a path, and the a c-string + CFStringRef path = CFURLCopyFileSystemPath(dataDir, kCFURLPOSIXPathStyle); + root = CFStringGetCStringPtr(path, CFStringGetSystemEncoding()); + + // tidy up. + CFRelease(resourcesUrl); + CFRelease(dataDir); + CFRelease(path); +#else + root = PKGLIBDIR; +#endif + } + + SG_LOG(SG_INPUT, SG_INFO, "fg_root = " << root ); + + return root; }