]> git.mxchange.org Git - flightgear.git/blobdiff - utils/TerraSync/terrasync.cxx
Plib is in 3rdParty for Win32 build
[flightgear.git] / utils / TerraSync / terrasync.cxx
index 8063b3c3720bf5a193cfc2b2ffa8a4806589daf3..7404530e1139bc93fa925c50629defee14fcf2f8 100644 (file)
 #include <windows.h>
 #endif
 
+#ifdef __MINGW32__
+#include <time.h>
+#include <unistd.h>
+#elif defined(_MSC_VER)
+#include <io.h>
+#endif
 
 #include <stdlib.h>             // atoi() atof() abs() system()
+#include <signal.h>             // signal()
 
 #include <simgear/compiler.h>
 
 #include <iostream>
+#include <fstream>
 #include <string>
 #include <deque>
 #include <map>
@@ -56,9 +64,7 @@
 #  endif
 #endif
 
-using std::string;
-using std::cout;
-using std::endl;
+using namespace std;
 
 const char* source_base = NULL;
 const char* svn_base =
@@ -77,21 +83,39 @@ const char* svn_cmd = "svn checkout";
 
 // display usage
 static void usage( const string& prog ) {
-    cout << "Usage: " << endl
-         << prog << " -p <port> "
-        << "-R [ -s <rsync_source> ] -d <dest>" << endl
-         << prog << " -p <port> "
-         << "-S [ -s <svn_source> ] -d <dest>" << endl;
+    cout << 
+"Usage:  terrasync [options]\n"
+"Options:  \n"
+" -d <dest>       destination directory [required]\n"
+" -R              transport using pipe to rsync\n"
+" -S              transport using built-in svn\n"
+" -p <port>       listen on UDP port [default: 5501]\n"
+" -s <source>     source base [default: '']\n"
+" -pid <pidfile>  write PID to file\n"
+" -v              be more verbose\n"
+;
+
 #ifdef HAVE_SVN_CLIENT_H
     cout << "    (defaults to the built in subversion)" << endl;
 #else
     cout << "    (defaults to rsync, using external commands)" << endl;
 #endif
+
+  cout << "\nExample:\n"
+"pid=$(cat $pidfile 2>/dev/null)\n"
+"if test -n \"$pid\" && kill -0 $pid ; then\n"
+"    echo \"terrasync already running: $pid\"\n"
+"else\n"
+"    nice /games/sport/fgs/utils/TerraSync/terrasync         \\\n"
+"      -v -pid $pidfile -S -p 5500 -d /games/orig/terrasync &\n"
+"fi" << endl;
+
 }
 
-std::deque<std::string> waitingTiles;
-typedef std::map<std::string,time_t> CompletedTiles;
+deque<string> waitingTiles;
+typedef map<string,time_t> CompletedTiles;
 CompletedTiles completedTiles;
+netSocket theSocket;
 
 #ifdef HAVE_SVN_CLIENT_H
 
@@ -99,14 +123,11 @@ CompletedTiles completedTiles;
 apr_pool_t *mysvn_pool = NULL;
 svn_client_ctx_t *mysvn_ctx = NULL;
 svn_opt_revision_t *mysvn_rev = NULL;
+svn_opt_revision_t *mysvn_rev_peg = NULL;
 
 static const svn_version_checklist_t mysvn_checklist[] = {
     { "svn_subr",   svn_subr_version },
     { "svn_client", svn_client_version },
-    { "svn_wc",     svn_wc_version },
-    { "svn_ra",     svn_ra_version },
-    { "svn_delta",  svn_delta_version },
-    { "svn_diff",   svn_diff_version },
     { NULL, NULL }
 };
 
@@ -162,11 +183,17 @@ int mysvn_setup(void) {
     mysvn_ctx->auth_baton = ab;
     mysvn_ctx->conflict_func = NULL;
     mysvn_ctx->conflict_baton = NULL;
+    // Now our magic revisions
     mysvn_rev = (svn_opt_revision_t*) apr_palloc(pool, 
         sizeof(svn_opt_revision_t));
     if (!mysvn_rev)
         return EXIT_FAILURE;
+    mysvn_rev_peg = (svn_opt_revision_t*) apr_palloc(pool, 
+        sizeof(svn_opt_revision_t));
+    if (!mysvn_rev_peg)
+        return EXIT_FAILURE;
     mysvn_rev->kind = svn_opt_revision_head;
+    mysvn_rev_peg->kind = svn_opt_revision_unspecified;
     // Success if we got this far
     mysvn_pool = pool;
     return EXIT_SUCCESS;
@@ -200,11 +227,14 @@ void sync_tree(const char* dir) {
        if (mysvn_setup() != EXIT_SUCCESS)
            exit(1);
        apr_pool_t *subpool = svn_pool_create(mysvn_pool);
-       err = svn_client_checkout(NULL,
+       err = svn_client_checkout3(NULL,
            command,
            dest_base_dir,
+           mysvn_rev_peg,
            mysvn_rev,
-           1,
+           svn_depth_infinity,
+           0,
+           0,
            mysvn_ctx,
            subpool);
        if (err) {
@@ -239,9 +269,37 @@ void sync_tree(const char* dir) {
     }
 }
 
+#ifdef _MSC_VER
+typedef void (__cdecl * sighandler_t)(int);
+#elif defined( __APPLE__ )
+typedef sig_t sighandler_t;
+#endif
+
+bool terminating = false;
+sighandler_t prior_signal_handlers[32];
+int termination_triggering_signals[] = {
+#ifndef _MSC_VER
+    SIGHUP, SIGINT, SIGQUIT, SIGKILL,
+#else
+    SIGINT, SIGILL, SIGFPE, SIGSEGV, SIGTERM, SIGBREAK, SIGABRT,
+#endif
+    0};  // zero terminated
+
+void terminate_request_handler(int param) {
+    char msg[] = "\nReceived signal XX, intend to exit soon.\n"
+         "repeat the signal to force immediate termination.\n";
+    msg[17] = '0' + param / 10;
+    msg[18] = '0' + param % 10;
+    write(1, msg, sizeof(msg) - 1);
+    terminating = true;
+    signal(param, prior_signal_handlers[param]);
+    theSocket.close();
+}
+
 
 const int nowhere = -9999;
 
+
 // parse message
 static void parse_message( const string &msg, int *lat, int *lon ) {
     double dlat, dlon;
@@ -251,8 +309,8 @@ static void parse_message( const string &msg, int *lat, int *lon ) {
     string::size_type pos = text.find( "$GPGGA" );
     if ( pos == string::npos )
     {
-       *lat = -9999.0;
-       *lon = -9999.0;
+       *lat = nowhere;
+       *lon = nowhere;
        return;
     }
     string tmp = text.substr( pos + 7 );
@@ -378,7 +436,8 @@ static void sync_areas( int lat, int lon, int lat_dir, int lon_dir ) {
 
 void getWaitingTile() {
     while ( !waitingTiles.empty() ) {
-       CompletedTiles::iterator ii = completedTiles.find( waitingTiles.front() );
+       CompletedTiles::iterator ii =
+            completedTiles.find( waitingTiles.front() );
        time_t now = time(0);
        if ( ii == completedTiles.end() || ii->second + 600 < now ) {
            sync_tree(waitingTiles.front().c_str());
@@ -392,8 +451,11 @@ void getWaitingTile() {
 
 int main( int argc, char **argv ) {
     int port = 5501;
-    char host[256] = "";        // accept messages from anyone
+    char host[256] = "localhost";
     bool testing = false;
+    bool do_checkout(true);
+    int verbose(0);
+    const char* pidfn = "";
 
     // parse arguments
     int i = 1;
@@ -401,6 +463,10 @@ int main( int argc, char **argv ) {
         if ( (string)argv[i] == "-p" ) {
             ++i;
             port = atoi( argv[i] );
+        } else if ( string(argv[i]).find("-pid") == 0 ) {
+            ++i;
+            pidfn = argv[i];
+            cout << "pidfn: " << pidfn << endl;
         } else if ( (string)argv[i] == "-s" ) {
             ++i;
             source_base = argv[i];
@@ -411,15 +477,33 @@ int main( int argc, char **argv ) {
            use_svn = false;
         } else if ( (string)argv[i] == "-S" ) {
            use_svn = true;
+        } else if ( (string)argv[i] == "-v" ) {
+           verbose++;
         } else if ( (string)argv[i] == "-T" ) {
            testing = true;
+        } else if ( (string)argv[i] == "-h" ) {
+            usage( argv[0] );
+            exit(0);
         } else {
+            cerr << "Unrecognized verbiage '" << argv[i] << "'" << endl;
             usage( argv[0] );
             exit(-1);        
         }
         ++i;
     }
 
+    if (*pidfn) {
+      ofstream pidstream;
+      pidstream.open(pidfn);
+      if (!pidstream.good()) {
+        cerr << "Cannot open pid file '" << pidfn << "': ";
+        perror(0);
+        exit(2);
+      }
+      pidstream << getpid() << endl;
+      pidstream.close();
+    }
+
     // Use the appropriate default for the "-s" flag
     if (source_base == NULL) {
         if (use_svn)
@@ -428,25 +512,15 @@ int main( int argc, char **argv ) {
            source_base = rsync_base;
     }
     
-    // We just want one grid square, no FGFS communications
-    if (testing) {
-          sync_areas( 37, -123, 0, 0 );
-         exit(0);
-    }
-
     // Must call this before any other net stuff
     netInit( &argc,argv );
 
-    netSocket s;
-
-    if ( ! s.open( false ) ) {  // open a UDP socket
+    if ( ! theSocket.open( false ) ) {  // open a UDP socket
         printf("error opening socket\n");
         return -1;
     }
 
-    s.setBlocking( false );
-
-    if ( s.bind( host, port ) == -1 ) {
+    if ( theSocket.bind( host, port ) == -1 ) {
         printf("error binding to port %d\n", port);
         return -1;
     }
@@ -458,21 +532,58 @@ int main( int argc, char **argv ) {
     int last_lat = nowhere;
     int last_lon = nowhere;
     bool recv_msg = false;
-    char synced_other = 'K';
 
-    while ( true ) {
-        recv_msg = false;
-        while ( (len = s.recv(msg, maxlen, 0)) >= 0 ) {
-            msg[len] = '\0';
-            recv_msg = true;
+    char synced_other;
+    if (do_checkout) {
+        for ( synced_other = 'K'; synced_other <= 'Z'; synced_other++ ) {
+            char dir[512];
+            snprintf( dir, 512, "Airports/%c", synced_other );
+            waitingTiles.push_back( dir );
+        }
+        for ( synced_other = 'A'; synced_other <= 'J'; synced_other++ ) {
+            char dir[512];
+            snprintf( dir, 512, "Airports/%c", synced_other );
+            waitingTiles.push_back( dir );
+        }
+        if ( use_svn ) {
+            waitingTiles.push_back( "Models" );
+        }
+    }
+
+
+    for (int* sigp=termination_triggering_signals; *sigp; sigp++) {
+        prior_signal_handlers[*sigp] =
+            signal(*sigp, *terminate_request_handler);
+        if (verbose) cout << "Intercepted signal " << *sigp << endl;
+    }
 
-            parse_message( msg, &lat, &lon );
+    while ( !terminating ) {
+        // main loop
+        recv_msg = false;
+        if ( testing ) {
+            // No FGFS communications
+            lat = 37;
+            lon = -123;
+            recv_msg = (lat != last_lat) || (lon != last_lon);
+        } else {
+            if (verbose && waitingTiles.empty()) {
+                cout << "Idle; waiting for FlightGear position\n";
+            }
+            theSocket.setBlocking(waitingTiles.empty());
+            len = theSocket.recv(msg, maxlen, 0);
+            if (len >= 0) {
+                msg[len] = '\0';
+                recv_msg = true;
+                if (verbose) cout << "recv length: " << len << endl;
+                parse_message( msg, &lat, &lon );
+            }
         }
 
         if ( recv_msg ) {
-            if ( lat != last_lat || lon != last_lon ) {
+             // Ignore messages where the location does not change
+             if ( lat != last_lat || lon != last_lon ) {
                cout << "pos in msg = " << lat << "," << lon << endl;
-               std::deque<std::string> oldRequests;
+               deque<string> oldRequests;
                oldRequests.swap( waitingTiles );
                 int lat_dir, lon_dir, dist;
                 if ( last_lat == nowhere || last_lon == nowhere ) {
@@ -499,28 +610,22 @@ int main( int argc, char **argv ) {
                    waitingTiles.push_back( oldRequests.front() );
                    oldRequests.pop_front();
                }
-           } else if ( !waitingTiles.empty() ) {
-               getWaitingTile();
-           } else {
-               if ( last_lat == nowhere || last_lon == nowhere ) {
-                   cout << "Waiting for FGFS to finish startup" << endl;
-               }
-               char c;
-               while ( !isdigit( c = synced_other++ ) && !isupper( c ) );
-
-               char dir[512];
-               snprintf( dir, 512, "Airports/%c", c );
-               waitingTiles.push_back( dir );
-           }
+                last_lat = lat;
+                last_lon = lon;
+            }
+       }
 
-            last_lat = lat;
-            last_lon = lon;
-       } else if ( !waitingTiles.empty() ) {
+        // No messages inbound, so process some pending work
+        else if ( !waitingTiles.empty() ) {
            getWaitingTile();
-        } 
+        }
+
+       else if ( testing ) {
+           terminating = true;
+       } else
 
         ulSleep( 1 );
-    } // while true
+    } // while !terminating
         
     return 0;
 }