author | andyq <andyq> | 2002-10-25 18:58:30 (UTC) |
---|---|---|
committer | andyq <andyq> | 2002-10-25 18:58:30 (UTC) |
commit | 835fadbad01b725a46ffd68ca458fd39c7313ea0 (patch) (side-by-side diff) | |
tree | 4fbc213e01292e4e850ad561c387f75098e2b059 | |
parent | 1d3135677f1f49b9cc87ebf01f1c4eaab3c450f4 (diff) | |
download | opie-835fadbad01b725a46ffd68ca458fd39c7313ea0.zip opie-835fadbad01b725a46ffd68ca458fd39c7313ea0.tar.gz opie-835fadbad01b725a46ffd68ca458fd39c7313ea0.tar.bz2 |
Added version handling
-rw-r--r-- | noncore/settings/aqpkg/aqpkg.pro | 4 | ||||
-rw-r--r-- | noncore/settings/aqpkg/installdlgimpl.cpp | 5 | ||||
-rw-r--r-- | noncore/settings/aqpkg/networkpkgmgr.cpp | 81 | ||||
-rw-r--r-- | noncore/settings/aqpkg/version.cpp | 214 |
4 files changed, 279 insertions, 25 deletions
diff --git a/noncore/settings/aqpkg/aqpkg.pro b/noncore/settings/aqpkg/aqpkg.pro index b869f32..99b82a1 100644 --- a/noncore/settings/aqpkg/aqpkg.pro +++ b/noncore/settings/aqpkg/aqpkg.pro @@ -1,44 +1,44 @@ TEMPLATE = app CONFIG = qt warn_on debug HEADERS = global.h \ mainwin.h \ datamgr.h \ settingsimpl.h \ ipkg.h \ networkpkgmgr.h \ package.h \ progressdlg.h \ installdlgimpl.h \ instoptionsimpl.h \ destination.h \ utils.h \ server.h \ helpwindow.h \ letterpushbutton.h \ inputdlg.h SOURCES = mainwin.cpp \ datamgr.cpp \ mem.cpp \ settingsimpl.cpp \ ipkg.cpp \ networkpkgmgr.cpp \ main.cpp \ package.cpp \ progressdlg.cpp \ installdlgimpl.cpp \ instoptionsimpl.cpp \ destination.cpp \ utils.cpp \ server.cpp \ helpwindow.cpp \ letterpushbutton.cpp \ - inputdlg.cpp + inputdlg.cpp \ + version.cpp INTERFACES = settings.ui \ install.ui \ instoptions.ui TARGET = aqpkg -DESTDIR=$(OPIEDIR)/bin INCLUDEPATH += $(OPIEDIR)/include DEPENDPATH += $(OPIEDIR)/include LIBS += -lqpe -lstdc++ diff --git a/noncore/settings/aqpkg/installdlgimpl.cpp b/noncore/settings/aqpkg/installdlgimpl.cpp index 2ea70e0..b297437 100644 --- a/noncore/settings/aqpkg/installdlgimpl.cpp +++ b/noncore/settings/aqpkg/installdlgimpl.cpp @@ -1,191 +1,194 @@ /*************************************************************************** installdlgimpl.cpp - description ------------------- begin : Mon Aug 26 2002 copyright : (C) 2002 by Andy Qua email : andy.qua@blueyonder.co.uk ***************************************************************************/ /*************************************************************************** * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * ***************************************************************************/ #ifdef QWS #include <qpe/config.h> #endif #include <qmultilineedit.h> #include <qdialog.h> #include <qcombobox.h> #include <qcheckbox.h> #include <qpushbutton.h> #include "datamgr.h" #include "instoptionsimpl.h" #include "destination.h" #include "installdlgimpl.h" #include "global.h" InstallDlgImpl::InstallDlgImpl( vector<InstallData> &packageList, DataManager *dataManager, QWidget * parent, const char* name, bool modal, WFlags fl ) : InstallDlg( parent, name, modal, fl ) { pIpkg = 0; upgradePackages = false; dataMgr = dataManager; vector<Destination>::iterator dit; QString defaultDest = "root"; #ifdef QWS Config cfg( "aqpkg" ); cfg.setGroup( "settings" ); defaultDest = cfg.readEntry( "dest", "root" ); // Grab flags - Turn MAKE_LINKS on by default (if no flags found) flags = cfg.readNumEntry( "installFlags", 0 ); #else flags = 0; #endif // Output text is read only output->setReadOnly( true ); QFont f( "helvetica" ); f.setPointSize( 10 ); output->setFont( f ); // setup destination data int defIndex = 0; int i; for ( i = 0 , dit = dataMgr->getDestinationList().begin() ; dit != dataMgr->getDestinationList().end() ; ++dit, ++i ) { destination->insertItem( dit->getDestinationName() ); if ( dit->getDestinationName() == defaultDest ) defIndex = i; } destination->setCurrentItem( defIndex ); vector<InstallData>::iterator it; // setup package data QString remove = "Remove\n"; QString install = "\nInstall\n"; QString upgrade = "\nUpgrade\n"; for ( it = packageList.begin() ; it != packageList.end() ; ++it ) { InstallData item = *it; if ( item.option == "I" ) { installList.push_back( item ); install += " " + item.packageName + "\n"; } else if ( item.option == "D" ) { removeList.push_back( item ); remove += " " + item.packageName + "\n"; } else if ( item.option == "U" || item.option == "R" ) { updateList.push_back( item ); - upgrade += " " + item.packageName + "\n"; + QString type = " (Upgrade)"; + if ( item.option == "R" ) + type = " (ReInstall)"; + upgrade += " " + item.packageName + type + "\n"; } } output->setText( remove + install + upgrade ); } InstallDlgImpl::InstallDlgImpl( Ipkg *ipkg, QString initialText, QWidget *parent, const char *name, bool modal, WFlags fl ) : InstallDlg( parent, name, modal, fl ) { pIpkg = ipkg; output->setText( initialText ); } InstallDlgImpl::~InstallDlgImpl() { } bool InstallDlgImpl :: showDlg() { showMaximized(); bool ret = exec(); return ret; } void InstallDlgImpl :: optionsSelected() { InstallOptionsDlgImpl opt( flags, this, "Option", true ); opt.exec(); // set options selected from dialog flags = 0; if ( opt.forceDepends->isChecked() ) flags |= FORCE_DEPENDS; if ( opt.forceReinstall->isChecked() ) flags |= FORCE_REINSTALL; if ( opt.forceRemove->isChecked() ) flags |= FORCE_REMOVE; if ( opt.forceOverwrite->isChecked() ) flags |= FORCE_OVERWRITE; #ifdef QWS Config cfg( "aqpkg" ); cfg.setGroup( "settings" ); cfg.writeEntry( "installFlags", flags ); #endif } void InstallDlgImpl :: installSelected() { if ( btnInstall->text() == "Close" ) { done( 1 ); return; } btnInstall->setEnabled( false ); if ( pIpkg ) { output->setText( "" ); connect( pIpkg, SIGNAL(outputText(const QString &)), this, SLOT(displayText(const QString &))); pIpkg->runIpkg(); } else { output->setText( "" ); Destination *d = dataMgr->getDestination( destination->currentText() ); QString dest = d->getDestinationName(); QString destDir = d->getDestinationPath(); int instFlags = flags; if ( d->linkToRoot() ) instFlags |= MAKE_LINKS; #ifdef QWS // Save settings Config cfg( "aqpkg" ); cfg.setGroup( "settings" ); cfg.writeEntry( "dest", dest ); #endif pIpkg = new Ipkg; connect( pIpkg, SIGNAL(outputText(const QString &)), this, SLOT(displayText(const QString &))); // First run through the remove list, then the install list then the upgrade list vector<InstallData>::iterator it; pIpkg->setOption( "remove" ); for ( it = removeList.begin() ; it != removeList.end() ; ++it ) { pIpkg->setDestination( it->destination->getDestinationName() ); pIpkg->setDestinationDir( it->destination->getDestinationPath() ); pIpkg->setPackage( it->packageName ); int tmpFlags = flags; diff --git a/noncore/settings/aqpkg/networkpkgmgr.cpp b/noncore/settings/aqpkg/networkpkgmgr.cpp index 3971aea..02e4e73 100644 --- a/noncore/settings/aqpkg/networkpkgmgr.cpp +++ b/noncore/settings/aqpkg/networkpkgmgr.cpp @@ -1,331 +1,336 @@ /*************************************************************************** networkpkgmgr.cpp - description ------------------- begin : Mon Aug 26 13:32:30 BST 2002 copyright : (C) 2002 by Andy Qua email : andy.qua@blueyonder.co.uk ***************************************************************************/ /*************************************************************************** * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * ***************************************************************************/ #include <fstream> #include <iostream> using namespace std; #include <unistd.h> #include <stdlib.h> #include <linux/limits.h> #ifdef QWS #include <qpe/qpeapplication.h> #include <qpe/qcopenvelope_qws.h> #include <qpe/config.h> #else #include <qapplication.h> #endif #include <qlabel.h> #include <qfile.h> #include <qmessagebox.h> #include "datamgr.h" #include "networkpkgmgr.h" #include "installdlgimpl.h" #include "ipkg.h" #include "inputdlg.h" #include "letterpushbutton.h" #include "global.h" +extern int compareVersions( const char *v1, const char *v2 ); + NetworkPackageManager::NetworkPackageManager( DataManager *dataManager, QWidget *parent, const char *name) : QWidget(parent, name) { dataMgr = dataManager; #ifdef QWS // read download directory from config file Config cfg( "aqpkg" ); cfg.setGroup( "settings" ); currentlySelectedServer = cfg.readEntry( "selectedServer", "local" ); showJumpTo = cfg.readBoolEntry( "showJumpTo", "true" ); #endif initGui(); setupConnections(); updateData(); // progressDlg = 0; // timerId = startTimer( 100 ); } NetworkPackageManager::~NetworkPackageManager() { } void NetworkPackageManager :: timerEvent ( QTimerEvent * ) { killTimer( timerId ); // showProgressDialog(); // Add server names to listbox updateData(); // progressDlg->hide(); } void NetworkPackageManager :: updateData() { serversList->clear(); packagesList->clear(); vector<Server>::iterator it; int activeItem = -1; int i; for ( i = 0, it = dataMgr->getServerList().begin() ; it != dataMgr->getServerList().end() ; ++it, ++i ) { if ( !it->isServerActive() ) { i--; continue; } serversList->insertItem( it->getServerName() ); if ( it->getServerName() == currentlySelectedServer ) activeItem = i; } // set selected server to be active server if ( activeItem != -1 ) serversList->setCurrentItem( activeItem ); serverSelected( 0 ); } void NetworkPackageManager :: selectLocalPackage( const QString &pkg ) { // First select local server for ( int i = 0 ; i < serversList->count() ; ++i ) { if ( serversList->text( i ) == LOCAL_IPKGS ) { serversList->setCurrentItem( i ); break; } } serverSelected( 0 ); // Now set the check box of the selected package for ( QCheckListItem *item = (QCheckListItem *)packagesList->firstChild(); item != 0 ; item = (QCheckListItem *)item->nextSibling() ) { if ( item->text().startsWith( pkg ) ) { item->setOn( true ); break; } } } void NetworkPackageManager :: initGui() { QLabel *l = new QLabel( "Servers", this ); serversList = new QComboBox( this ); packagesList = new QListView( this ); update = new QPushButton( "Refresh List", this ); download = new QPushButton( "Download", this ); upgrade = new QPushButton( "Upgrade", this ); apply = new QPushButton( "Apply", this ); QVBoxLayout *vbox = new QVBoxLayout( this, 0, -1, "VBox" ); QHBoxLayout *hbox1 = new QHBoxLayout( vbox, -1, "HBox1" ); hbox1->addWidget( l ); hbox1->addWidget( serversList ); QHBoxLayout *hbox3 = new QHBoxLayout( vbox, -1, "HBox1" ); QHBoxLayout *hbox4 = new QHBoxLayout( vbox, -1, "HBox1" ); if ( showJumpTo ) { char text[2]; text[1] = '\0'; for ( int i = 0 ; i < 26 ; ++i ) { text[0] = 'A' + i; LetterPushButton *b = new LetterPushButton( text, this ); connect( b, SIGNAL( released( QString ) ), this, SLOT( letterPushed( QString ) ) ); if ( i < 13 ) hbox3->addWidget( b ); else hbox4->addWidget( b ); } } vbox->addWidget( packagesList ); packagesList->addColumn( "Packages" ); QHBoxLayout *hbox2 = new QHBoxLayout( vbox, -1, "HBox2" ); hbox2->addWidget( update ); hbox2->addWidget( download ); hbox2->addWidget( upgrade ); hbox2->addWidget( apply ); } void NetworkPackageManager :: setupConnections() { connect( serversList, SIGNAL(activated( int )), this, SLOT(serverSelected( int ))); connect( apply, SIGNAL(released()), this, SLOT(applyChanges()) ); connect( download, SIGNAL(released()), this, SLOT(downloadPackage()) ); connect( upgrade, SIGNAL( released()), this, SLOT(upgradePackages()) ); connect( update, SIGNAL(released()), this, SLOT(updateServer()) ); } void NetworkPackageManager :: showProgressDialog( char *initialText ) { if ( !progressDlg ) progressDlg = new ProgressDlg( this, "Progress", false ); progressDlg->setText( initialText ); progressDlg->show(); } void NetworkPackageManager :: serverSelected( int ) { packagesList->clear(); // display packages QString serverName = serversList->currentText(); currentlySelectedServer = serverName; #ifdef QWS // read download directory from config file Config cfg( "aqpkg" ); cfg.setGroup( "settings" ); cfg.writeEntry( "selectedServer", currentlySelectedServer ); #endif Server *s = dataMgr->getServer( serverName ); // dataMgr->setActiveServer( serverName ); vector<Package> &list = s->getPackageList(); vector<Package>::iterator it; for ( it = list.begin() ; it != list.end() ; ++it ) { QString text = ""; // If the local server, only display installed packages if ( serverName == LOCAL_SERVER && !it->isInstalled() ) continue; text += it->getPackageName(); if ( it->isInstalled() ) { text += " (installed)"; // If a different version of package is available, postfix it with an * if ( it->getVersion() != it->getInstalledVersion() ) - text += "*"; + { + if ( compareVersions( it->getInstalledVersion(), it->getVersion() ) == 1 ) + text += "*"; + } } QCheckListItem *item = new QCheckListItem( packagesList, text, QCheckListItem::CheckBox ); if ( it->isInstalled() ) { QString destName = ""; if ( it->getLocalPackage() ) { if ( it->getLocalPackage()->getInstalledTo() ) destName = it->getLocalPackage()->getInstalledTo()->getDestinationName(); } else { if ( it->getInstalledTo() ) destName = it->getInstalledTo()->getDestinationName(); } if ( destName != "" ) new QCheckListItem( item, QString( "Installed To - " ) + destName ); } if ( !it->isPackageStoredLocally() ) new QCheckListItem( item, QString( "Description - " ) + it->getDescription() ); else new QCheckListItem( item, QString( "Filename - " ) + it->getFilename() ); new QCheckListItem( item, QString( "V. Available - " ) + it->getVersion() ); if ( it->getLocalPackage() ) { if ( it->isInstalled() ) new QCheckListItem( item, QString( "V. Installed - " ) + it->getInstalledVersion() ); } packagesList->insertItem( item ); } // If the local server or the local ipkgs server disable the download button if ( serverName == LOCAL_SERVER ) { upgrade->setEnabled( false ); download->setText( "Download" ); download->setEnabled( false ); } else if ( serverName == LOCAL_IPKGS ) { upgrade->setEnabled( false ); download->setEnabled( true ); download->setText( "Remove" ); } else { upgrade->setEnabled( true ); download->setEnabled( true ); download->setText( "Download" ); } } void NetworkPackageManager :: updateServer() { QString serverName = serversList->currentText(); // Update the current server // Display dialog // ProgressDlg *progDlg = new ProgressDlg( this ); // QString status = "Updating package lists..."; // progDlg->show(); // progDlg->setText( status ); // Disable buttons to stop silly people clicking lots on them :) // First, write out ipkg_conf file so that ipkg can use it dataMgr->writeOutIpkgConf(); Ipkg ipkg; ipkg.setOption( "update" ); InstallDlgImpl dlg( &ipkg, "Refreshing server package lists", this, "Upgrade", true ); dlg.showDlg(); // Reload data dataMgr->reloadServerData( serversList->currentText() ); serverSelected(-1); // delete progDlg; } void NetworkPackageManager :: upgradePackages() { // We're gonna do an upgrade of all packages // First warn user that this isn't recommended QString text = "WARNING: Upgrading while\nOpie/Qtopia is running\nis NOT recommended!\n\nAre you sure?\n"; QMessageBox warn("Warning", text, QMessageBox::Warning, QMessageBox::Yes, QMessageBox::No | QMessageBox::Escape | QMessageBox::Default , 0, this ); warn.adjustSize(); if ( warn.exec() == QMessageBox::Yes ) @@ -440,171 +445,203 @@ void NetworkPackageManager :: applyChanges() { stickyOption = ""; // First, write out ipkg_conf file so that ipkg can use it dataMgr->writeOutIpkgConf(); // Now for each selected item // deal with it vector<InstallData> workingPackages; for ( QCheckListItem *item = (QCheckListItem *)packagesList->firstChild(); item != 0 ; item = (QCheckListItem *)item->nextSibling() ) { if ( item->isOn() ) { InstallData data = dealWithItem( item ); workingPackages.push_back( data ); } } if ( workingPackages.size() == 0 ) { // Nothing to do QMessageBox::information( this, "Nothing to do", "No packages selected", "OK" ); return; } // do the stuff InstallDlgImpl dlg( workingPackages, dataMgr, this, "Install", true ); dlg.showDlg(); // Reload data dataMgr->reloadServerData( LOCAL_SERVER ); dataMgr->reloadServerData( serversList->currentText() ); serverSelected(-1); #ifdef QWS // Finally let the main system update itself QCopEnvelope e("QPE/System", "linkChanged(QString)"); QString lf = QString::null; e << lf; #endif } // decide what to do - either remove, upgrade or install // Current rules: // If not installed - install // If installed and different version available - upgrade // If installed and version up to date - remove InstallData NetworkPackageManager :: dealWithItem( QCheckListItem *item ) { QString name = item->text(); int pos = name.find( "*" ); name.truncate( pos ); // if (there is a (installed), remove it pos = name.find( "(installed)" ); if ( pos > 0 ) name.truncate( pos - 1 ); // Get package Server *s = dataMgr->getServer( serversList->currentText() ); Package *p = s->getPackage( name ); // If the package has a filename then it is a local file if ( p->isPackageStoredLocally() ) name = p->getFilename(); QString option; QString dest = "root"; if ( !p->isInstalled() ) { InstallData item; item.option = "I"; item.packageName = name; return item; } else { InstallData item; item.option = "D"; item.packageName = p->getInstalledPackageName(); if ( p->getInstalledTo() ) { item.destination = p->getInstalledTo(); cout << "dest - " << p->getInstalledTo()->getDestinationName() << endl; cout << "dest - " << p->getInstalledTo()->getDestinationPath() << endl; } else { item.destination = p->getLocalPackage()->getInstalledTo(); } - // Sticky option not implemented yet, but will eventually allow - // the user to say something like 'remove all' - if ( stickyOption == "" ) + // Now see if version is newer or not + int val = compareVersions( p->getInstalledVersion(), p->getVersion() ); + if ( val == -2 ) { - QString msgtext; - msgtext.sprintf( "Do you wish to remove or reinstall\n%s?", (const char *)name ); - switch( QMessageBox::information( this, "Remove or ReInstall", - msgtext, "Remove", "ReInstall" ) ) - { - case 0: // Try again or Enter - item.option = "D"; - break; - case 1: // Quit or Escape - item.option = "U"; - break; - } + // Error - should handle + } + else if ( val == -1 ) + { + // Version available is older - remove only + item.option = "R"; } else { -// item.option = stickyOption; + QString caption; + QString text; + QString secondButton; + QString secondOption; + if ( val == 0 ) + { + // Version available is the same - option to remove or reinstall + caption = "Do you wish to remove or reinstall\n%s?"; + text = "Remove or ReInstall"; + secondButton = "ReInstall"; + secondOption = "R"; + } + else if ( val == 1 ) + { + // Version available is newer - option to remove or upgrade + caption = "Do you wish to remove or upgrade\n%s?"; + text = "Remove or Upgrade"; + secondButton = "Upgrade"; + secondOption = "U"; + } + + // Sticky option not implemented yet, but will eventually allow + // the user to say something like 'remove all' + if ( stickyOption == "" ) + { + QString msgtext; + msgtext.sprintf( caption, (const char *)name ); + switch( QMessageBox::information( this, text, + msgtext, "Remove", secondButton ) ) + { + case 0: // Try again or Enter + item.option = "D"; + break; + case 1: // Quit or Escape + item.option = secondOption; + break; + } + } + else + { +// item.option = stickyOption; + } } + // Check if we are reinstalling the same version - if ( p->getVersion() != p->getInstalledVersion() ) + if ( item.option != "R" ) item.recreateLinks = true; else - { - if ( item.option == "U" ) - item.option = "R"; item.recreateLinks = false; - } // User hit cancel (on dlg - assume remove) return item; } } void NetworkPackageManager :: displayText( const QString &t ) { cout << t << endl; } void NetworkPackageManager :: letterPushed( QString t ) { QCheckListItem *top = (QCheckListItem *)packagesList->firstChild(); QCheckListItem *start = (QCheckListItem *)packagesList->currentItem(); if ( packagesList->firstChild() == 0 ) return; QCheckListItem *item; if ( start == 0 ) { item = (QCheckListItem *)packagesList->firstChild(); start = top; } else item = (QCheckListItem *)start->nextSibling(); if ( item == 0 ) item = (QCheckListItem *)packagesList->firstChild(); do { if ( item->text().lower().startsWith( t.lower() ) ) { packagesList->setSelected( item, true ); packagesList->ensureItemVisible( item ); break; } item = (QCheckListItem *)item->nextSibling(); if ( !item ) item = (QCheckListItem *)packagesList->firstChild(); } while ( item != start); } diff --git a/noncore/settings/aqpkg/version.cpp b/noncore/settings/aqpkg/version.cpp new file mode 100644 index 0000000..e836da1 --- a/dev/null +++ b/noncore/settings/aqpkg/version.cpp @@ -0,0 +1,214 @@ +/* + * libdpkg - Debian packaging suite library routines + * vercmp.c - comparison of version numbers + * + * Copyright (C) 1995 Ian Jackson <iwj10@cus.cam.ac.uk> + * + * This is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2, + * or (at your option) any later version. + * + * This is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public + * License along with dpkg; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ +#include <stdio.h> +#include <stdlib.h> +#include <ctype.h> +#include <string.h> + +# define _(Text) Text + +class versionrevision +{ +public: + versionrevision() + { + version = 0; + } + + ~versionrevision() + { + if ( version ) + delete version; + } + + void setVersion( const char *str ) + { + version = new char[(strlen(str)+1)]; + strcpy( version, str ); + } + + unsigned long epoch; + char *version; + const char *revision; + const char *familiar_revision; +}; + +static int verrevcmp(const char *val, const char *ref) +{ + int vc, rc; + long vl, rl; + const char *vp, *rp; + + if (!val) val= ""; + if (!ref) ref= ""; + for (;;) { + vp= val; while (*vp && !isdigit(*vp)) vp++; + rp= ref; while (*rp && !isdigit(*rp)) rp++; + for (;;) { + vc= val == vp ? 0 : *val++; + rc= ref == rp ? 0 : *ref++; + if (!rc && !vc) break; + if (vc && !isalpha(vc)) vc += 256; /* assumes ASCII character set */ + if (rc && !isalpha(rc)) rc += 256; + if (vc != rc) return vc - rc; + } + val= vp; + ref= rp; + vl=0; if (isdigit(*vp)) vl= strtol(val,(char**)&val,10); + rl=0; if (isdigit(*rp)) rl= strtol(ref,(char**)&ref,10); + if (vl != rl) return vl - rl; + if (!*val && !*ref) return 0; + if (!*val) return -1; + if (!*ref) return +1; + } +} + +int versioncompare(const struct versionrevision *version, + const struct versionrevision *refversion) +{ + int r; + + if (version->epoch > refversion->epoch) return 1; + if (version->epoch < refversion->epoch) return -1; + r= verrevcmp(version->version,refversion->version); if (r) return r; + r= verrevcmp(version->revision,refversion->revision); if (r) return r; + return verrevcmp(version->familiar_revision,refversion->familiar_revision); +} + +int versionsatisfied3(const struct versionrevision *it, + const struct versionrevision *ref, + const char *op) +{ + int r; + r= versioncompare(it,ref); + if (strcmp(op, "<=") == 0 || strcmp(op, "<") == 0) + return r <= 0; + if (strcmp(op, ">=") == 0 || strcmp(op, ">") == 0) + return r >= 0; + if (strcmp(op, "<<") == 0) + return r < 0; + if (strcmp(op, ">>") == 0) + return r > 0; + if (strcmp(op, "=") == 0) + return r == 0; + fprintf(stderr, "unknown operator: %s", op); + + exit(1); +} + +const char *parseversion(struct versionrevision *rversion, const char *string) +{ + char *hyphen, *colon, *eepochcolon; + unsigned long epoch; + + if (!*string) return _("version string is empty"); + + colon= strchr(string,':'); + if (colon) { + epoch= strtoul(string,&eepochcolon,10); + if (colon != eepochcolon) return _("epoch in version is not number"); + if (!*++colon) return _("nothing after colon in version number"); + string= colon; + rversion->epoch= epoch; + } else { + rversion->epoch= 0; + } + + rversion->revision = ""; + rversion->familiar_revision = ""; + + rversion->setVersion( string ); + hyphen= strrchr(rversion->version,'-'); + if (hyphen) { + *hyphen++= 0; + if (strncmp("fam", hyphen, 3) == 0) { + rversion->familiar_revision=hyphen+3; + hyphen= strrchr(rversion->version,'-'); + if (hyphen) { + *hyphen++= 0; + rversion->revision = hyphen; + } + } else { + rversion->revision = hyphen; + } + } +/* + fprintf(stderr,"Parsed version: %lu, %s, %s, %s\n", + rversion->epoch, + rversion->version, + rversion->revision, + rversion->familiar_revision); +*/ + return 0; +} + +int compareVersions( const char *v1, const char *v2 ) +{ + const char *err; + versionrevision ver, ref; + + err = parseversion(&ref, v1); + if (err) { + fprintf(stderr, "Invalid version `%s': %s\n", v2, err); + return -2; + } + + err = parseversion(&ver, v2); + if (err) { + fprintf(stderr, "Invalid version `%s': %s\n", v1, err); + return -2; + } + + if ( versionsatisfied3( &ver, &ref, "=" ) ) + return 0; + else if ( versionsatisfied3( &ver, &ref, "<" ) ) + return -1; + else + return 1; +} + +/* +int main(int argc, char *argv[]) +{ + const char *err; + versionrevision ver, ref; + + if (argc < 4) { + fprintf(stderr, "usage: %s: version op refversion\n", argv[0]); + return 2; + } + + err = parseversion(&ver, argv[1]); + if (err) { + fprintf(stderr, "Invalid version `%s': %s\n", argv[1], err); + return 2; + } + + err = parseversion(&ref, argv[3]); + if (err) { + fprintf(stderr, "Invalid version `%s': %s\n", argv[3], err); + return 2; + } + + printf( "Result: %d\n", versionsatisfied3(&ver, &ref, argv[2]) ); +} + +*/ |