#include #include #include #include #include #include "config.h" const char DEFAULT_CONFIG[] = "# fhvkov - forza horizon overlay (vulkan layer)\n" "# positions and sizes are fractions of the game window;\n" "# _x/_y are gauge centers. this file is re-read every second,\n" "# so you can edit and save while driving.\n" "port=9999\n" "units=kmh\n" "keep=0\n" "scale=1.0\n" "# needle motion blur: seconds of smear (try 0.06-0.15), 0 = off\n" "blur=0.10\n" "\n" "tach_x=0.878\n" "tach_y=0.830\n" "tach_r=0.130\n" "flash_needle=1\n" "# whether to scale max rpm based on rpm reached by car\n" "autoscale_rpm=1\n" "# offset from max rpm at which needle starts flashing red\n" "rpm_off=800.0\n" "\n" "show_boost=1\n" "boost_x=0.775\n" "boost_y=0.907\n" "boost_r=0.060\n" "\n" "# lamps: abs, tcs (wheel slip) and tcs launch-control flash\n" "show_abs=1\n" "show_tcs=0\n" "# enabling LC shows the \"tcs\" lamp\n" "show_lc=1\n" "show_tires=1\n" "tire_x=0.970\n" "tire_y=0.710\n" "tire_sc=1.0\n"; void config_defaults( CONFIG* c ) { c->port = 9999; c->units = 0; c->keep = 0; c->tach_x = 0.878; c->tach_y = 0.830; c->tach_r = 0.130; c->scale = 1.0; c->blur = 0.10; c->show_boost = 1; c->boost_x = 0.775; c->boost_y = 0.907; c->boost_r = 0.060; c->show_abs = 1; c->show_tcs = 1; c->show_lc = 1; c->show_tires = 1; c->tire_x = 0.97; c->tire_y = 0.71, c->tire_sc = 1.0; c->flash_needle = 1; c->autoscale_rpm = 1; c->rpm_off = 800.0; } void config_resolve_path( CONFIG* c ) { const char* env = getenv( "FHRPM_CONFIG" ); if( env ) { snprintf( c->path, sizeof( c->path ), "%s", env ); return; } const char* home = getenv( "HOME" ); if( !home ) home = "."; snprintf( c->path, sizeof( c->path ), "%s/.config/fhvkov/fhvkov.conf", home ); } void config_write_default( const CONFIG* c ) { char dir[512]; const char* home = getenv( "HOME" ); if( home ) { snprintf( dir, sizeof( dir ), "%s/.config", home ); mkdir( dir, 0755 ); snprintf( dir, sizeof( dir ), "%s/.config/fhvkov", home ); mkdir( dir, 0755 ); } FILE* f = fopen( c->path, "w" ); if( !f ) return; defer( fclose( f ) ); fwrite( DEFAULT_CONFIG, 1, sizeof( DEFAULT_CONFIG ) - 1, f ); dlog( "fhvkov: wrote default config to %s\n", c->path ); } void config_parse_line( CONFIG* c, char* key, char* val ) { if( !strcmp( key, "port" ) ) c->port = atoi( val ); else if( !strcmp( key, "units" ) ) c->units = !strcmp( val, "mph" ); else if( !strcmp( key, "keep" ) ) c->keep = atoi( val ); else if( !strcmp( key, "tach_x" ) ) c->tach_x = atof( val ); else if( !strcmp( key, "tach_y" ) ) c->tach_y = atof( val ); else if( !strcmp( key, "tach_r" ) ) c->tach_r = atof( val ); else if( !strcmp( key, "show_boost" ) ) c->show_boost = atoi( val ); else if( !strcmp( key, "boost_x" ) ) c->boost_x = atof( val ); else if( !strcmp( key, "boost_y" ) ) c->boost_y = atof( val ); else if( !strcmp( key, "boost_r" ) ) c->boost_r = atof( val ); else if( !strcmp( key, "scale" ) ) c->scale = atof( val ); else if( !strcmp( key, "blur" ) ) c->blur = atof( val ); else if( !strcmp( key, "show_abs" ) ) c->show_abs = atoi( val ); else if( !strcmp( key, "show_tcs" ) ) c->show_tcs = atoi( val ); else if( !strcmp( key, "show_lc" ) ) c->show_lc = atoi( val ); else if( !strcmp( key, "show_tires" ) ) c->show_tires = atoi( val ); else if( !strcmp( key, "tire_x" ) ) c->tire_x = atof( val ); else if( !strcmp( key, "tire_y" ) ) c->tire_y = atof( val ); else if( !strcmp( key, "tire_sc" ) ) c->tire_sc = atof( val ); else if( !strcmp( key, "flash_needle" ) ) c->flash_needle = atoi( val ); else if( !strcmp( key, "autoscale_rpm" ) ) c->autoscale_rpm = atoi( val ); else if( !strcmp( key, "rpm_off" ) ) c->rpm_off = atof( val ); } STAT config_load( CONFIG* c ) { FILE* f = fopen( c->path, "r" ); if( !f ) return STAT_ERR; defer( fclose( f ) ); char line[256]; while( fgets( line, sizeof( line ), f ) ) { char* p = line; while( *p == ' ' || *p == '\t' ) p++; if( *p == '#' || *p == '\n' ||* p == 0 ) continue; char* eq = strchr( p, '=' ); if( !eq ) continue; *eq = 0; char* key = p, *val = eq + 1; char* nl = strchr( val, '\n' ); if( nl ) *nl = 0; char* e = key + strlen( key ); while( e > key && ( e[-1] == ' ' || e[-1] == '\t' ) ) *--e = 0; config_parse_line( c, key, val ); } struct stat st; if( stat( c->path, &st ) == 0 ) c->mtime = st.st_mtime; return STAT_OK; } void config_init( CONFIG* c ) { config_defaults( c ); config_resolve_path( c ); if( !OK( config_load( c ) ) ) { config_write_default( c ); config_load( c ); } } U8 config_poll( CONFIG* c ) { struct stat st; if( stat( c->path, &st ) != 0 ) return 0; if( st.st_mtime == c->mtime ) return 0; CONFIG fresh; config_defaults( &fresh ); memcpy( fresh.path, c->path, sizeof( fresh.path ) ); if( !OK( config_load( &fresh ) ) ) return 0; fresh.port = c->port; *c = fresh; dlog( "fhvkov: config reloaded\n" ); return 1; }