Beispiel #1
0
static int
preBmGs(unsigned char *x, int m, int bmGs[])
{
    int *suff, i, j;


    suff = (int *) calloc(sizeof(int), m);
    if (suff == NULL)
	return -1;
    
    suffixes(x, m, suff);
    
    for (i = 0; i < m; ++i)
	bmGs[i] = m;

    j = 0;
    for (i = m - 1; i >= -1; --i)
	if (i == -1 || suff[i] == i + 1)
	    for (; j < m - 1 - i; ++j)
		if (bmGs[j] == m)
		    bmGs[j] = m - 1 - i;

    for (i = 0; i <= m - 2; ++i)
	bmGs[m - 1 - suff[i]] = m - 1 - i;

    free(suff);
    return 0;
}
Beispiel #2
0
static int preBmGs(const unsigned char *wanted, int wlen, int bmGs[])
{
    int i, j, suffix[BM_XSIZE];

    if (NULL == wanted || 0 >= wlen || NULL == bmGs) return -1;
    
    suffixes(wanted, wlen, suffix);
    
    for (i = 0; i < wlen; i++) {
        bmGs[i] = wlen;
    }

    for (j = 0, i = wlen - 1; i >= 0; i--)
    {
        if (suffix[i] == i + 1) {
            for (; j < wlen - 1 - i; j++) {
                if (bmGs[j] == wlen) {
                    bmGs[j] = wlen - 1 - i;
                }
            }
        }
    }

    for (i = 0; i <= wlen - 2; i++) {
        bmGs[wlen - 1 - suffix[i]] = wlen - 1 - i;
    }

    return 0;
}
Beispiel #3
0
static void
preBmGs(
    unsigned char *x,
    int m,
    int bmGs[])
{
    int i, j;
    int *suff = safe_malloc(m * sizeof(int));

    suffixes(x, m, suff);

    for (i = 0; i < m; ++i) {
        bmGs[i] = m;
    }
    j = 0;
    for (i = m - 1; i >= 0; --i) {
        if (suff[i] == i + 1) {
            for (; j < m - 1 - i; ++j) {
                if (bmGs[j] == m) {
                    bmGs[j] = m - 1 - i;
                }
            }
        }
    }
    for (i = 0; i <= m - 2; ++i) {
        bmGs[m - 1 - suff[i]] = m - 1 - i;
    }

    free(suff);
}
Beispiel #4
0
void
suffix_s( string &word )
{
	cout << "suffix_s -- word passed in: " << word << endl;

	string::size_type spos = 0;
	string::size_type pos3 = word.size()-3;

        // "ous", "ss", "is"
	string suffixes( "oussis" );

        if ( ! word.compare( pos3, 3, suffixes, spos, 3 ) ||
             ! word.compare( pos3+1, 2, suffixes, spos+2, 2 ) ||
             ! word.compare( pos3+1, 2, suffixes, spos+4, 2 ))
        {
		cout << "suffix_s: found immutable suffix: "
		     << word << endl;
		return;
	}

	string ies( "ies" );
        if ( ! word.compare( pos3, 3, ies ))
	{
	     word.replace( pos3, 3, 1, 'y' );
	     cout << "suffix_s -- word returned: " << word << endl;

	     return; 
	}

	// erase ending 's'
	word.erase( pos3+2 );
	cout << "suffix_s -- word returned: " << word << endl;
}
const QString RarArchEngine::openFilter() {
    QStringList filters;
    QStringList suffs = suffixes();
    for (int i=0;i<suffs.count();i++) {
        filters << "*." + suffs[i];
    }
    return tr("Rar files") + " (" + filters.join(" ") + ")";
}
const QString XzipArchEngine::createFilter() {
    QStringList filters;
    filters << "*.tar.xz";
    QStringList suffs = suffixes();
    for (int i=0;i<suffs.count();i++) {
        filters << "*." + suffs[i];
    }
    return tr("Xzip files") + " (" + filters.join(" ") + ")";
}
std::vector<std::list<Parameterization> > ParameterizedCommand::ExpandParameters(
    unsigned int startIndex, const std::vector<IParameter::Pointer>& parameters)
{
  typedef std::vector<std::list<Parameterization> > ReturnType;

  const unsigned int nextIndex = startIndex + 1;
  const bool noMoreParameters = (nextIndex >= parameters.size());

  const IParameter::Pointer parameter(parameters[startIndex]);
  ReturnType parameterizations;

  if (parameter->IsOptional())
  {
    parameterizations.push_back(std::list<Parameterization>());
  }

  IParameter::ParameterValues parameterValues(parameter->GetValues());
  for (IParameter::ParameterValues::iterator parameterValueItr =
      parameterValues.begin(); parameterValueItr != parameterValues.end(); ++parameterValueItr)
  {
    std::list<Parameterization> combination;
    combination.push_back(
        Parameterization(parameter, parameterValueItr->second));
    parameterizations.push_back(combination);
  }

  // Check if another iteration will produce any more names.
  if (noMoreParameters)
  {
    // This is it, so just return the current parameterizations.
    return parameterizations;
  }

  // Make recursive call
  ReturnType suffixes(ExpandParameters(nextIndex, parameters));
  if (suffixes.empty())
  {
    // This is it, so just return the current parameterizations.
    return parameterizations;
  }

  ReturnType returnValue;
  for (ReturnType::iterator suffixItr = suffixes.begin(); suffixItr
      != suffixes.end(); ++suffixItr)
  {
    for (ReturnType::iterator combinationItr = parameterizations.begin(); combinationItr
        != parameterizations.end(); ++combinationItr)
    {
      std::list<Parameterization> newCombination(*combinationItr);
      newCombination.insert(newCombination.end(), suffixItr->begin(),
          suffixItr->end());
      returnValue.push_back(newCombination);
    }
  }

  return returnValue;
}
Beispiel #8
0
void preBmGs(const char* x, int m, int* bmGs, int XSIZE) {
    int i = 0, j = 0, *suffix = NULL;
    if (!(suffix = (int*) malloc(sizeof(int)*XSIZE))) {
        fprintf(stderr, "malloc err!\n"); return;
    }
    suffixes(x, m, suffix, XSIZE);
    for (i = 0; i < XSIZE; i ++) { bmGs[i] = m; }   // init consider no suffix
    for (i = m-2; i >= 0; i --) {                   // a head prefix as suffix
        if (suffix[i] == i+1) {
            for (j = m-1-i; j >= 0; j --) { bmGs[j] = (m-1) - i; }
        }
    }
    for (i = 0; i <= m-2; i ++) {                   // find a good suffix
        bmGs[(m-1) - suffix[i]] = (m-1) - i;
    }
    free(suffix);
}
Beispiel #9
0
void suffix_s(string word)//处理部分三单问题
{
	string::size_type spos = 0;
	string::size_type pos3 = word.size() - 3;
	// 以"ous", "ss", "is", "ius"结尾的要去掉
	string suffixes("oussisius");
	if (!word.compare(pos3, 3, suffixes, spos, 3) || // ous
		!word.compare(pos3, 3, suffixes, spos + 6, 3) || // ius
		!word.compare(pos3 + 1, 2, suffixes, spos + 2, 2) || // ss
		!word.compare(pos3 + 1, 2, suffixes, spos + 4, 2)) // es
		return;
	else
		if (word.compare(pos3, 3, suffixes, spos, 3) || // ous
			word.compare(pos3, 3, suffixes, spos + 6, 3))// ius
			word.erase(pos3, 3);
		else
			word.erase(pos3 + 1, 2);
}
Beispiel #10
0
void preGS(char *pattern, int patternSize, int bmGs[]) 
{
	int i, j, suffix[GSIZE];
	
	_pattern		= pattern;
	_patternSize	= patternSize;
	
	suffixes(pattern, patternSize, suffix);
	
	for (i = 0; i < patternSize; ++i)
		bmGs[i] = patternSize;
	j = 0;
	for (i = patternSize - 1; i >= 0; --i)
		if (suffix[i] == i + 1)
			for (; j < patternSize - 1 - i; ++j)
				if (bmGs[j] == patternSize)
					bmGs[j] = patternSize - 1 - i;
	for (i = 0; i <= patternSize - 2; ++i)
		bmGs[patternSize - 1 - suffix[i]] = patternSize - 1 - i;
}
Beispiel #11
0
QString BAbstractFileType::createFileDialogFilter() const
{
    QString desc = description();
    QStringList sl = suffixes();
    if (desc.isEmpty() || sl.isEmpty())
        return "";
    QString filter;
    filter += desc + " (";
    if (sl.contains("*"))
        sl.clear();
    sl.removeDuplicates();
    if (!sl.isEmpty()) {
        for (int i = 0; i < sl.size(); ++i)
            filter += "*." + sl.at(i) + (i < sl.size() - 1 ? " " : "");
    }
    else
        filter += "*";
    filter += ")";
    return filter;
}
Beispiel #12
0
void
suffix_s( string &word )
{
	string::size_type spos = 0;
	string::size_type pos3 = word.size()-3;

        // "ous", "ss", "is"
	string suffixes( "oussis" );

        if ( ! word.compare( pos3, 3, suffixes, spos, 3 ) ||
             ! word.compare( pos3+1, 2, suffixes, spos+2, 2 ) ||
             ! word.compare( pos3+1, 2, suffixes, spos+4, 2 ))
	       return;

	string ies( "ies" );
        if ( ! word.compare( pos3, 3, ies ))
	   { word.replace( pos3, 3, 1, 'y' ); return; }

	// erase ending 's'
	word.erase( pos3+2 );
}
Beispiel #13
0
static void preBmGs( const char * needle, HB_ISIZ m, HB_ISIZ bmGs[] )
{
   HB_ISIZ i, j;
   HB_ISIZ * suff = ( HB_ISIZ * ) hb_xgrab( m * sizeof( HB_ISIZ ) );

   suffixes( needle, m, suff );

   for( i = 0; i < m; ++i )
      bmGs[ i ] = m;

   j = 0;

   for( i = m - 1; i >= 0; --i )
      if( suff[ i ] == i + 1 )
         for( ; j < m - 1 - i; ++j )
            if( bmGs[ j ] == m )
               bmGs[ j ] = m - 1 - i;

   for( i = 0; i <= m - 2; ++i )
      bmGs[ m - 1 - suff[ i ] ] = m - 1 - i;

   hb_xfree( suff );
}
bool PreTeXFileType::matchesFileName(const QString &fileName) const
{
    return suffixes().contains(QFileInfo(fileName).suffix(), Qt::CaseInsensitive);
}
Beispiel #15
0
std::list< util::istring > FileFormat::getSuffixes()const
{
	std::list<util::istring> ret = util::stringToList<util::istring>( suffixes(), boost::regex( "[[:space:]]" ) );
	BOOST_FOREACH( util::istring & ref, ret ) {
		ref.erase( 0, ref.find_first_not_of( '.' ) ); // remove leading . if there are some
	}
QList<QList<Parameterization> > ParameterizedCommand::ExpandParameters(
    unsigned int startIndex, const QList<IParameter::Pointer>& parameters)
{
  typedef QList<QList<Parameterization> > ReturnType;

  const int nextIndex = startIndex + 1;
  const bool noMoreParameters = (nextIndex >= parameters.size());

  const IParameter::Pointer parameter(parameters[startIndex]);
  ReturnType parameterizations;

  if (parameter->IsOptional())
  {
    parameterizations.push_back(QList<Parameterization>());
  }

  IParameterValues* values = NULL;
  try
  {
    values = parameter->GetValues();
  }
  catch (const ParameterValuesException& /*e*/)
  {
    if (noMoreParameters)
    {
      return parameterizations;
    }

    // Make recursive call
    return ExpandParameters(nextIndex, parameters);
  }

  const QHash<QString,QString> parameterValues = values->GetParameterValues();
  for (IParameter::ParameterValues::const_iterator parameterValueItr =
      parameterValues.begin(); parameterValueItr != parameterValues.end(); ++parameterValueItr)
  {
    QList<Parameterization> combination;
    combination.push_back(
        Parameterization(parameter, parameterValueItr.value()));
    parameterizations.push_back(combination);
  }

  // Check if another iteration will produce any more names.
  if (noMoreParameters)
  {
    // This is it, so just return the current parameterizations.
    return parameterizations;
  }

  // Make recursive call
  ReturnType suffixes(ExpandParameters(nextIndex, parameters));
  if (suffixes.empty())
  {
    // This is it, so just return the current parameterizations.
    return parameterizations;
  }

  ReturnType returnValue;
  for (ReturnType::iterator suffixItr = suffixes.begin(); suffixItr
      != suffixes.end(); ++suffixItr)
  {
    for (ReturnType::iterator combinationItr = parameterizations.begin(); combinationItr
        != parameterizations.end(); ++combinationItr)
    {
      QList<Parameterization> newCombination(*combinationItr);
      newCombination.append(*suffixItr);
      returnValue.push_back(newCombination);
    }
  }

  return returnValue;
}
Beispiel #17
0
bool QLibraryPrivate::load_sys()
{
    QString attempt;
#if !defined(QT_NO_DYNAMIC_LIBRARY)
    QFileInfo fi(fileName);

#if defined(Q_OS_SYMBIAN)
    QString path; // In Symbian, always resolve with just the filename
    QString name;

    // Replace possible ".qtplugin" suffix with ".dll"
    if (fi.suffix() == QLatin1String("qtplugin"))
        name = fi.completeBaseName() + QLatin1String(".dll");
    else
        name = fi.fileName();
#else
    QString path = fi.path();
    QString name = fi.fileName();
    if (path == QLatin1String(".") && !fileName.startsWith(path))
        path.clear();
    else
        path += QLatin1Char('/');
#endif
    // The first filename we want to attempt to load is the filename as the callee specified.
    // Thus, the first attempt we do must be with an empty prefix and empty suffix.
    QStringList suffixes(QLatin1String("")), prefixes(QLatin1String(""));
    if (pluginState != IsAPlugin) {
#if !defined(Q_OS_SYMBIAN)
        prefixes << QLatin1String("lib");
#endif
#if defined(Q_OS_HPUX)
        // according to
        // http://docs.hp.com/en/B2355-90968/linkerdifferencesiapa.htm

        // In PA-RISC (PA-32 and PA-64) shared libraries are suffixed
        // with .sl. In IPF (32-bit and 64-bit), the shared libraries
        // are suffixed with .so. For compatibility, the IPF linker
        // also supports the .sl suffix.

        // But since we don't know if we are built on HPUX or HPUXi,
        // we support both .sl (and .<version>) and .so suffixes but
        // .so is preferred.
# if defined(__ia64)
        if (!fullVersion.isEmpty()) {
            suffixes << QString::fromLatin1(".so.%1").arg(fullVersion);
        } else {
            suffixes << QLatin1String(".so");
        }
# endif
        if (!fullVersion.isEmpty()) {
            suffixes << QString::fromLatin1(".sl.%1").arg(fullVersion);
            suffixes << QString::fromLatin1(".%1").arg(fullVersion);
        } else {
            suffixes << QLatin1String(".sl");
        }
#elif defined(Q_OS_AIX)
        suffixes << ".a";

#elif defined(Q_OS_SYMBIAN)
        suffixes << QLatin1String(".dll");
#else
        if (!fullVersion.isEmpty()) {
            suffixes << QString::fromLatin1(".so.%1").arg(fullVersion);
        } else {
            suffixes << QLatin1String(".so");
        }
#endif
# ifdef Q_OS_MAC
        if (!fullVersion.isEmpty()) {
            suffixes << QString::fromLatin1(".%1.bundle").arg(fullVersion);
            suffixes << QString::fromLatin1(".%1.dylib").arg(fullVersion);
        } else {
            suffixes << QLatin1String(".bundle") << QLatin1String(".dylib");
        }
#endif
    }
    int dlFlags = 0;
#if defined(QT_HPUX_LD)
    dlFlags = DYNAMIC_PATH | BIND_NONFATAL;
    if (loadHints & QLibrary::ResolveAllSymbolsHint) {
        dlFlags |= BIND_IMMEDIATE;
    } else {
        dlFlags |= BIND_DEFERRED;
    }
#else
    if (loadHints & QLibrary::ResolveAllSymbolsHint) {
        dlFlags |= RTLD_NOW;
    } else {
        dlFlags |= RTLD_LAZY;
    }
    if (loadHints & QLibrary::ExportExternalSymbolsHint) {
        dlFlags |= RTLD_GLOBAL;
    }
#if !defined(Q_OS_CYGWIN)
    else {
#if defined(Q_OS_MAC)
        if (QSysInfo::MacintoshVersion >= QSysInfo::MV_10_4)
#endif
        dlFlags |= RTLD_LOCAL;
    }
#endif
#if defined(Q_OS_AIX)	// Not sure if any other platform actually support this thing.
    if (loadHints & QLibrary::LoadArchiveMemberHint) {
        dlFlags |= RTLD_MEMBER;
    }
#endif
#endif // QT_HPUX_LD
    bool retry = true;
    for(int prefix = 0; retry && !pHnd && prefix < prefixes.size(); prefix++) {
        for(int suffix = 0; retry && !pHnd && suffix < suffixes.size(); suffix++) {
            if (!prefixes.at(prefix).isEmpty() && name.startsWith(prefixes.at(prefix)))
                continue;
            if (!suffixes.at(suffix).isEmpty() && name.endsWith(suffixes.at(suffix)))
                continue;
            if (loadHints & QLibrary::LoadArchiveMemberHint) {
                attempt = name;
                int lparen = attempt.indexOf(QLatin1Char('('));
                if (lparen == -1)
                    lparen = attempt.count();
                attempt = path + prefixes.at(prefix) + attempt.insert(lparen, suffixes.at(suffix));
            } else {
                attempt = path + prefixes.at(prefix) + name + suffixes.at(suffix);
            }
#if defined(QT_HPUX_LD)
            pHnd = (void*)shl_load(QFile::encodeName(attempt), dlFlags, 0);
#else
            pHnd = dlopen(QFile::encodeName(attempt), dlFlags);
#endif

#if defined(Q_OS_SYMBIAN)
            // Never try again in symbian, dlopen already handles the library search logic,
            // and there is only one possible suffix.
            retry = false;
#else
            if (!pHnd && fileName.startsWith(QLatin1Char('/')) && QFile::exists(attempt)) {
                // We only want to continue if dlopen failed due to that the shared library did not exist.
                // However, we are only able to apply this check for absolute filenames (since they are
                // not influenced by the content of LD_LIBRARY_PATH, /etc/ld.so.cache, DT_RPATH etc...)
                // This is all because dlerror is flawed and cannot tell us the reason why it failed.
                retry = false;
            }
#endif
        }
    }

#ifdef Q_OS_MAC
    if (!pHnd) {
        QByteArray utf8Bundle = fileName.toUtf8();
        QCFType<CFURLRef> bundleUrl = CFURLCreateFromFileSystemRepresentation(NULL, reinterpret_cast<const UInt8*>(utf8Bundle.data()), utf8Bundle.length(), true);
        QCFType<CFBundleRef> bundle = CFBundleCreate(NULL, bundleUrl);
        if(bundle) {
            QCFType<CFURLRef> url = CFBundleCopyExecutableURL(bundle);
            char executableFile[FILENAME_MAX];
            CFURLGetFileSystemRepresentation(url, true, reinterpret_cast<UInt8*>(executableFile), FILENAME_MAX);
            attempt = QString::fromUtf8(executableFile);
            pHnd = dlopen(QFile::encodeName(attempt), dlFlags);
        }
    }
#endif
#endif // QT_NO_DYNAMIC_LIBRARY
    if (!pHnd) {
        errorString = QLibrary::tr("Cannot load library %1: %2").arg(fileName).arg(qdlerror());
    }
    if (pHnd) {
        qualifiedFileName = attempt;
        errorString.clear();
    }
    return (pHnd != 0);
}
Beispiel #18
0
int
RideImportWizard::process()
{

    // set progress bar limits - for each file we
    // will make 5 passes over the files
    //         1. checking it is a file ane readable
    //         2. parsing it with the RideFileReader
    //         3. [optional] collect date/time information from user
    //         4. copy file into Library
    //         5. Process for CPI (not implemented yet)

    // So, therefore the progress bar runs from 0 to files*4. (since step 5 is not implemented yet)
    progressBar->setMinimum(0);
    progressBar->setMaximum(filenames.count()*4);

    // Pass one - Is it valid?
    phaseLabel->setText(tr("Step 1 of 4: Check file permissions"));
    for (int i=0; i < filenames.count(); i++) {

        // get fullpath name for processing
        QFileInfo thisfile(filenames[i]);

        if (thisfile.exists() && thisfile.isFile() && thisfile.isReadable()) {

            // is it one we understand ?
            QStringList suffixList = RideFileFactory::instance().suffixes();
            QRegExp suffixes(QString("^(%1)$").arg(suffixList.join("|")));
            suffixes.setCaseSensitivity(Qt::CaseInsensitive);

            if (suffixes.exactMatch(thisfile.suffix())) {

                // Woot. We know how to parse this baby
                tableWidget->item(i,5)->setText(tr("Queued"));

            } else {
                tableWidget->item(i,5)->setText(tr("Error - Unknown file type"));
            }

        } else {
            //  Cannot open
            tableWidget->item(i,5)->setText(tr("Error - Not a valid file"));
        }

        progressBar->setValue(progressBar->value()+1);

    }

    QApplication::processEvents();
    if (aborted) { done(0); }
    repaint();

    // Pass 2 - Read in with the relevant RideFileReader method

    phaseLabel->setText(tr("Step 2 of 4: Validating Files"));
   for (int i=0; i< filenames.count(); i++) {


        // does the status say Queued?
        if (!tableWidget->item(i,5)->text().startsWith(tr("Error"))) {

              QStringList errors;
              QFile thisfile(filenames[i]);

              tableWidget->item(i,5)->setText(tr("Parsing..."));
              tableWidget->setCurrentCell(i,5);
              QApplication::processEvents();
              if (aborted) { done(0); }
              this->repaint();

              QList<RideFile*> rides;
              RideFile *ride = RideFileFactory::instance().openRideFile(mainWindow, thisfile, errors, &rides);

              // is this an archive of files?
              if (rides.count() > 1) {

                 int here = i;

                 // remove current filename from state arrays and tableview
                 filenames.removeAt(here);
                 blanks.removeAt(here);
                 tableWidget->removeRow(here);

                 // resize dialog according to the number of rows we expect
                 int willhave = filenames.count() + rides.count();
                 resize(920 + ((willhave > 16 ? 24 : 0) +
                     (willhave > 9 && willhave < 17) ? 8 : 0),
                     118 + (willhave > 16 ? 17*20 : (willhave+1) * 20));

                 // ok so create a temporary file and add to the tableWidget
                 int counter = 0;
                 foreach(RideFile *extracted, rides) {

                     // write as a temporary file, using the original
                     // filename with "-n" appended
                     QString fulltarget = QDir::tempPath() + "/" + QFileInfo(thisfile).baseName() + QString("-%1.tcx").arg(counter+1);
                     TcxFileReader reader;
                     QFile target(fulltarget);
                     reader.writeRideFile(mainWindow, extracted, target);
                     deleteMe.append(fulltarget);
                     delete extracted;
                     
                     // now add each temporary file ...
                     filenames.insert(here, fulltarget);
                     blanks.insert(here, true); // by default editable
                     tableWidget->insertRow(here+counter);

                     QTableWidgetItem *t;

                     // Filename
                     t = new QTableWidgetItem();
                     t->setText(fulltarget);
                     t->setFlags(t->flags() & (~Qt::ItemIsEditable));
                     tableWidget->setItem(here+counter,0,t);

                     // Date
                     t = new QTableWidgetItem();
                     t->setText(tr(""));
                     t->setFlags(t->flags()  | Qt::ItemIsEditable);
                     t->setBackgroundColor(Qt::red);
                     tableWidget->setItem(here+counter,1,t);

                     // Time
                     t = new QTableWidgetItem();
                     t->setText(tr(""));
                     t->setFlags(t->flags() | Qt::ItemIsEditable);
                     tableWidget->setItem(here+counter,2,t);

                     // Duration
                     t = new QTableWidgetItem();
                     t->setText(tr(""));
                     t->setFlags(t->flags() & (~Qt::ItemIsEditable));
                     tableWidget->setItem(here+counter,3,t);

                     // Distance
                     t = new QTableWidgetItem();
                     t->setText(tr(""));
                     t->setFlags(t->flags() & (~Qt::ItemIsEditable));
                     tableWidget->setItem(here+counter,4,t);

                     // Import Status
                     t = new QTableWidgetItem();
                     t->setText(tr(""));
                     t->setFlags(t->flags() & (~Qt::ItemIsEditable));
                     tableWidget->setItem(here+counter,5,t);

                     counter++;

                     tableWidget->adjustSize();
                     QApplication::processEvents();
                 }


                 // progress bar needs to adjust...
                 progressBar->setMaximum(filenames.count()*4);

                 // then go back one and re-parse from there
                 rides.clear();
   
                 i--;
                 goto next; // buttugly I know, but count em across 100,000 lines of code

              }
int
RideImportWizard::process()
{

    // set progress bar limits - for each file we
    // will make 5 passes over the files
    //         1. checking it is a file ane readable
    //         2. parsing it with the RideFileReader
    //         3. [optional] collect date/time information from user
    //         4. copy file into Library
    //         5. Process for CPI (not implemented yet)

    // So, therefore the progress bar runs from 0 to files*4. (since step 5 is not implemented yet)
    progressBar->setMinimum(0);
    progressBar->setMaximum(filenames.count()*4);

    // Pass one - Is it valid?
    phaseLabel->setText(tr("Step 1 of 4: Check file permissions"));
    for (int i=0; i < filenames.count(); i++) {

        // get fullpath name for processing
        QFileInfo thisfile(filenames[i]);

        if (thisfile.exists() && thisfile.isFile() && thisfile.isReadable()) {

            // is it one we understand ?
            QStringList suffixList = RideFileFactory::instance().suffixes();
            QRegExp suffixes(QString("^(%1)$").arg(suffixList.join("|")));
            suffixes.setCaseSensitivity(Qt::CaseInsensitive);

            if (suffixes.exactMatch(thisfile.suffix())) {

        // Woot. We know how to parse this baby
                tableWidget->item(i,5)->setText(tr("Queued"));

            } else {
                tableWidget->item(i,5)->setText(tr("Error - Unknown file type"));
            }

        } else {
            //  Cannot open
            tableWidget->item(i,5)->setText(tr("Error - Not a valid file"));
        }

        progressBar->setValue(progressBar->value()+1);

    }

    QApplication::processEvents();
    if (aborted) { done(0); }
    repaint();

    // Pass 2 - Read in with the relevant RideFileReader method

    phaseLabel->setText(tr("Step 2 of 4: Validating Files"));
   for (int i=0; i< filenames.count(); i++) {


        // does the status say Queued?
        if (!tableWidget->item(i,5)->text().startsWith(tr("Error"))) {

              QStringList errors;
              QFile thisfile(filenames[i]);

              tableWidget->item(i,5)->setText(tr("Parsing..."));
              tableWidget->setCurrentCell(i,5);
              QApplication::processEvents();
              if (aborted) { done(0); }
              this->repaint();

              boost::scoped_ptr<RideFile> ride(RideFileFactory::instance().openRideFile(thisfile, errors));

              // did it parse ok?
              if (ride && errors.empty()) {

                   // ITS A KEEPER, LETS GET SOME METADATA ON DISPLAY
                   tableWidget->item(i,5)->setText(tr("Validated"));

                   // Set Date and Time
                   if (ride->startTime().isNull()) {

                       // Poo. The user needs to supply the date/time for this ride
                       blanks[i] = true;
                       tableWidget->item(i,1)->setText(tr(""));
                       tableWidget->item(i,2)->setText(tr(""));

                   } else {

                       // Cool, the date and time was extrcted from the source file
                       blanks[i] = false;
                       tableWidget->item(i,1)->setText(ride->startTime().toString(tr("dd MMM yyyy")));
                       tableWidget->item(i,2)->setText(ride->startTime().toString(tr("hh:mm:ss ap")));
                   }

                   tableWidget->item(i,1)->setTextAlignment(Qt::AlignRight); // put in the middle
                   tableWidget->item(i,2)->setTextAlignment(Qt::AlignRight); // put in the middle

                   // show duration by looking at last data point
                   if (ride->dataPoints().last() != NULL) {
                   int secs = ride->dataPoints().last()->secs;
                   QChar zero = QLatin1Char ( '0' );
                   QString time = QString("%1:%2:%3").arg(secs/3600,2,10,zero)
                                                     .arg(secs%3600/60,2,10,zero)
                                                     .arg(secs%60,2,10,zero);
                   tableWidget->item(i,3)->setText(time);
                   tableWidget->item(i,3)->setTextAlignment(Qt::AlignHCenter); // put in the middle

                   // show distance by looking at last data point
                   int km = ride->dataPoints().last()->km;
                   QString dist = QString ("%1 km").arg(km, 1,10,zero);
                   tableWidget->item(i,4)->setText(dist);
                   tableWidget->item(i,4)->setTextAlignment(Qt::AlignRight); // put in the middle

                   } else {

                       tableWidget->item(i,3)->setText(tr("00:00:00")); // duration
                       tableWidget->item(i,3)->setTextAlignment(Qt::AlignHCenter); // put in the middle
                       tableWidget->item(i,4)->setText(tr("0 km"));
                       tableWidget->item(i,4)->setTextAlignment(Qt::AlignRight); // put in the middle
                   }

               } else {
                   // nope - can't handle this file
                   tableWidget->item(i,5)->setText(tr("Error - ") + errors.join(tr(" ")));
               }
        }
        progressBar->setValue(progressBar->value()+1);
        QApplication::processEvents();
        if (aborted) { done(0); }
        this->repaint();
    }

   // Pass 3 - get missing date and times for imported files
    phaseLabel->setText(tr("Step 3 of 4: Confirm Date and Time"));

   int needdates=0;
   bool first = true;
   for (int i=0; i<filenames.count(); i++) {

        // ignore errors
        QTableWidgetItem *t = tableWidget->item(i,5);
        if (t->text().startsWith(tr("Error"))) continue;

       // date needed?
        if (blanks[i]) {
            needdates++;
            t = tableWidget->item(i,1);
            t->setFlags(t->flags() | (Qt::ItemIsEditable)); // make editable ONLY if not present -
                                                            // we cannot override the RideFileReader
            if (first) {
                tableWidget->editItem(t);
                first = false;
            }
            t = tableWidget->item(i,2);
            t->setFlags(t->flags() | (Qt::ItemIsEditable)); // make editable ONLY if not present -
                                                            // we cannot override the RideFileReader
        }
        // does nothing for the moment
        progressBar->setValue(progressBar->value()+1);
        progressBar->repaint();
   }

   // Wait for user to press save
   abortButton->setText(tr("Save"));
   aborted = false;

   cancelButton->setHidden(false);
   todayButton->setHidden(false);
   overFiles->setHidden(false);

   if (needdates == 0) {
      // no need to wait for the user to input dates
      // nd press save if all the dates are set
      // (i.e. they got set by the file importers already)
      // do nothing for now since we need to confirm dates
      // and confirm overwrite files rather than importing
      // without user intervention

      abortButton->setDisabled(false);

      // abortClicked();
   } else {

      // de-activate Save button until the dates and times are sorted
      abortButton->setDisabled(true);
   }
   connect(tableWidget, SIGNAL(itemChanged(QTableWidgetItem *)), this, SLOT(activateSave()));

   return 0;
}
/**
 * cactusMerge.cpp: merge two pairs of c2h and FASTA files into one pair. The
 * files must be star trees with the same root sequence.
 */
int 
main(
    int argc, 
    char** argv
) {

    // Register ctrl+c handler. See
    // <http://www.yolinux.com/TUTORIALS/C++Signals.html>
    signal(SIGINT, stacktraceOnSignal);
    
    // Register segfaults with the stack trace handler
    signal(SIGSEGV, stacktraceOnSignal);
    
    // Parse options with boost::programOptions. See
    // <http://www.radmangames.com/programming/how-to-use-boost-program_options>

    std::string appDescription = 
        std::string("Merge c2h/FASTA file pairs.\n" 
        "Usage: cactusMerge <c2hOut> <fastaOut> --c2h <c2h files...> "
            "--fasta <fasta files...> --suffix <suffixes...>");

    // Make an options description for our program's options.
    boost::program_options::options_description description("Options");
    // Add all the options
    description.add_options() 
        ("help", "Print help messages")
        ("c2h", boost::program_options::value<std::vector<std::string>>(),
            "List of c2h files to merge")
        ("fasta", boost::program_options::value<std::vector<std::string>>(),
            "List of FASTA files for the given c2h files")
        ("suffix", boost::program_options::value<std::vector<std::string>>(),
            "List of suffixes to add on to event names")
        ("mergeOn", boost::program_options::value<std::string>()->required(), 
            "An event on which to merge the files")
        ("c2hOut", boost::program_options::value<std::string>()->required(), 
            "File to save .c2h-format alignment in")
        ("fastaOut", boost::program_options::value<std::string>()->required(), 
            "File in which to save FASTA records for building HAL from .c2h");
        
        
        
    // And set up our positional arguments
    boost::program_options::positional_options_description positionals;
    positionals.add("mergeOn", 1);
    positionals.add("c2hOut", 1);
    positionals.add("fastaOut", 1);
    
    // Add a variables map to hold option variables.
    boost::program_options::variables_map options;
    
    try {
        // Parse options into the variable map, or throw an error if there's
        // something wring with them.
        boost::program_options::store(
            // Build the command line parser.
            boost::program_options::command_line_parser(argc, argv)
                .options(description)
                .positional(positionals)
                .run(),
            options);
        boost::program_options::notify(options);
            
        if(options.count("help")) {
            // The help option was given. Print program help.
            std::cout << appDescription << std::endl;
            std::cout << description << std::endl;
            
            // Don't do the actual program.
            return 0; 
        }
        
        if(!options.count("mergeOn") || !options.count("c2h") ||
            !options.count("fasta")) {
            
            // We need both of these
            throw boost::program_options::error("Missing important arguments!");
        }
        
        if(options["c2h"].as<std::vector<std::string>>().size() != 
            options["fasta"].as<std::vector<std::string>>().size()) {
            
            // Counts need to match up here, because these are pairs
            throw boost::program_options::error(
                "c2h/fasta counts don't match!");
        }
        
        if(options.count("suffix") && 
            options["c2h"].as<std::vector<std::string>>().size() != 
            options["suffix"].as<std::vector<std::string>>().size()) {
        
            // If we have any suffixes we must have the right number
            throw boost::program_options::error(
                "c2h/suffix counts don't match!");
        }
            
    } catch(boost::program_options::error& error) {
        // Something is bad about our options. Complain on stderr
        std::cerr << "Option parsing error: " << error.what() << std::endl;
        std::cerr << std::endl; 
        // Talk about our app.
        std::cerr << appDescription << std::endl;
        // Show all the actually available options.
        std::cerr << description << std::endl; 
        
        // Stop the program.
        return -1; 
    }
    
    // If we get here, we have the right arguments.
    
    // Make a list of the c2h files to use
    std::vector<std::string> c2hFiles(
        options["c2h"].as<std::vector<std::string>>());
    
    // This holds the suffix applied to all the top sequences and events in each
    // file.
    std::vector<std::string> suffixes(
        options["suffix"].as<std::vector<std::string>>());
        
    // Make a list of the FASTA files to use
    std::vector<std::string> fastaFiles(
        options["fasta"].as<std::vector<std::string>>());
    
    // This will hold all of the renames that have to happen for each file.
    // These are generated when we go through the file by renaming top and
    // bottom sequences with suffixes.
    std::vector<std::map<std::string, std::string>> renames;
    
    for(size_t i = 0; i < c2hFiles.size(); i++) {
        // Make sure it has an empty map of renames for each file.
        renames.push_back(std::map<std::string, std::string>());
    }
    
    // This will hold the event names for the c2h files in order
    std::vector<std::string> eventNames;
    
    // And this will hold the sequence names
    std::vector<std::string> sequenceNames;
    
    // This will hold bottom (1) and top (0) flags for each sequence.
    std::vector<bool> isBottom;
    
    // And this will hold the sequence lengths
    std::vector<size_t> sequenceLengths;
    
    // This will hold the first sequence number for any event and sequence name
    std::map<std::pair<std::string, std::string>, size_t> firstSequenceNumber;
    
    // Holds Merge structs to be executed later.
    std::vector<C2hMerge> merges;
    
    // We're going to throw out all of the events that are old rootSeqs, and
    // just keep the actual leaves. This holds the list of renamed event names
    // we are keeping.
    std::set<std::string> eventsToKeep;
    
    for(size_t fileIndex = 0; fileIndex < c2hFiles.size(); fileIndex++) {
        // Scan through the c2h files to get the event, sequence, and length of
        // each thread, and to collect merges.
        
        Log::output() << "Reading alignment " << c2hFiles[fileIndex] << 
            std::endl;
        
        // Open the file
        std::ifstream c2h(c2hFiles[fileIndex]);
        
        // This maps block name to (sequence number, start location) pairs for
        // this file. We use it to compose merges for our list in global
        // sequence number space.
        std::map<size_t, std::pair<size_t, size_t>> nameMap;
        
        for(std::string line; std::getline(c2h, line);) {
            // This is a new sequence. Split it up on \t.
            std::vector<std::string> parts;
            boost::split(parts, line, boost::is_any_of("\t"));
        
            if(parts.size() < 1) {
                // Skip lines that have nothing on them.
                continue;
            }
        
            // For each line
            if(parts[0] == "s") {
                
                // It's a sequence line. Start a new squence.
                
                if(parts.size() != 4) {
                    // Not the right number of fields.
                    throw std::runtime_error(
                        std::string("Invalid field count in ") + line);
                }
                
                // Grab the parts
                std::string eventName = unquote(parts[1]);
                std::string sequenceName = unquote(parts[2]);
                bool bottomFlag = std::stoi(parts[3]);
                
                Log::info() << "Read sequence " << eventName << "." << 
                    sequenceName << (bottomFlag ? " (bottom)" : " (top)") << 
                    std::endl;
                
                if(eventName != options["mergeOn"].as<std::string>()) {
                    // We aren't merging on this sequence, so we may have to
                    // apply a suffix.
                
                    // We need to rename this event (possibly to the same thing)
                    renames[fileIndex][eventName] = eventName + 
                        suffixes[fileIndex];
                        
                    if(bottomFlag) {
                        // All the bottom events (that aren't being merged
                        // on) need to be renamed apart manually since the names
                        // may be reused.
                        renames[fileIndex][eventName] += "-" + 
                            std::to_string(fileIndex);
                    }
                    eventName = renames[fileIndex][eventName];
                    
                    if(!bottomFlag) {
                        // Keep this event when we do our final output.
                        eventsToKeep.insert(eventName);
                    }
                    
                    // And the sequence
                    renames[fileIndex][sequenceName] = sequenceName + 
                        suffixes[fileIndex];
                        
                    if(bottomFlag) {
                        // All the bottom sequences (that aren't being merged
                        // on) need to be renamed apart manually since the names
                        // may be reused.
                        renames[fileIndex][sequenceName] += "-" + 
                            std::to_string(fileIndex);
                    }
                    sequenceName = renames[fileIndex][sequenceName];
                    
                    Log::info() << "Canonical name: " << eventName << "." << 
                        sequenceName << std::endl;
                    
                } else {
                    // If we are going to merge on it, we keep its name the same
                    // and then later we just make one thread for that name. We
                    // do definitely need it in the output though.
                    eventsToKeep.insert(eventName);
                }
                
                
                // Save the names
                eventNames.push_back(eventName);
                sequenceNames.push_back(sequenceName);
                
                // Save the bottomness flag.
                isBottom.push_back(bottomFlag);
                
                // Initialize the total length to 0
                sequenceLengths.push_back(0);
                
                
                auto namePair = std::make_pair(eventName, sequenceName);
                if(!firstSequenceNumber.count(namePair)) {
                    // This is the first time we have seen a sequence
                    // for this event and sequence name. Everything should
                    // merge against this one thread and not make more
                    // threads.
                    
                    // If this is the mergeOn event, we'll only make this
                    // once across all the files.
                    
                    // Later instances of this event and sequence name should
                    // redirect here.
                    firstSequenceNumber[namePair] = sequenceNames.size() - 1;
                    
                    Log::info() << "This is the first time we have seen "
                        "this sequence." << std::endl;
                }
                
            } else if(parts[0] == "a") {
                // This is an alignment block
                
                if(sequenceNames.size() == 0) {
                    throw std::runtime_error(
                        "Found alignmet block before sequence");
                }
                
                // Which sequence are we working on?
                size_t sequenceNumber = sequenceNames.size() - 1;
                
                if(isBottom[sequenceNumber]) {
                    // Parse it as a bottom block: "a" name start length
                    
                    if(parts.size() != 4) {
                        // Not the right number of fields.
                        throw std::runtime_error(
                            std::string("Invalid field count in ") + line);
                    }
                    
                    size_t blockName = std::stoll(parts[1]);
                    size_t blockStart = std::stoll(parts[2]);
                    size_t blockLength = std::stoll(parts[3]);
                    
                    // Look up the sequence number we actually want to merge
                    // against when we come get this block.
                    auto namePair = std::make_pair(eventNames[sequenceNumber], 
                        sequenceNames[sequenceNumber]);
                    size_t mergeSequenceNumber = firstSequenceNumber[namePair];
                    
                    // We need to associate the block name with the thread
                    // number for the sequence we want it to merge into, and the
                    // start location it specifies, for merging later.
                    nameMap[blockName] = std::make_pair(mergeSequenceNumber,
                        blockStart);
                    
                    Log::debug() << "Bottom block " << blockName << " is " << 
                        blockStart << " on sequence " << mergeSequenceNumber << 
                        std::endl;
                    
                    // Also record the additional length on this sequence
                    sequenceLengths[sequenceNumber] += blockLength;
                    
                } else {
                    // Parse it as a top block: 
                    // "a" start length [name orientation]
                    
                    if(parts.size() < 3) {
                        // Not the right number of fields.
                        throw std::runtime_error(
                            std::string("Invalid field count in ") + line);
                    }
                    
                    // Parse out the start and length
                    size_t segmentStart = std::stoll(parts[1]);
                    size_t segmentLength = std::stoll(parts[2]);
                    
                    // Add in the length
                    sequenceLengths[sequenceNumber] += segmentLength;
                    
                    if(parts.size() == 5) {
                        // If it has a name and orientation, remember a merge.
                        
                        size_t blockName = std::stoll(parts[3]);
                        bool orientation = std::stoi(parts[4]);
                        
                        // Get the sequence number that canonically represents
                        // all sequences with this event/sequence name
                        // combination.
                        auto namePair = std::make_pair(
                            eventNames[sequenceNumber], 
                            sequenceNames[sequenceNumber]);
                        size_t mergeSequenceNumber = firstSequenceNumber[
                            namePair];
                        
                        // Make a merge and populate it with everything we can
                        // get from this segment.
                        C2hMerge merge;
                        merge.sequence1 = mergeSequenceNumber;
                        merge.start1 = segmentStart;
                        merge.length = segmentLength;
                        // TODO: error-check length
                        merge.orientation = orientation;
                        
                        // Grab the info from the bottom segment we are talking
                        // about earlier in this file.
                        merge.sequence2 = nameMap[blockName].first;
                        merge.start2 = nameMap[blockName].second;
                        
                        Log::debug() << "Going to merge " << segmentStart << 
                            " length " << segmentLength << " to " <<
                            blockName << " orientation " << orientation << 
                            std::endl;
                        
                        // Save the merge for doing later.
                        merges.push_back(merge);
                        
                    }
                    
                }
            }
        }
    }
    
    // Make a thread set with all those threads
    stPinchThreadSet* threadSet = stPinchThreadSet_construct();
    
    // Make all the threads. Be 1-based internally since the serialization code
    // wants that.
    for(size_t i = 0; i < sequenceLengths.size(); i++) {
        
        auto namePair = std::make_pair(eventNames[i], sequenceNames[i]);
        if(firstSequenceNumber[namePair] != i) {
            // This sequence is not the first; it is getting merged into another
            // one that is the same length and structure and name (i.e. it
            // appears in two files). Don't make a thread for it.
            continue;
        }
        
        
        // Make threads for all the top sequences and the first bottom sequence
        // for every event and sequence name pair.
        stPinchThreadSet_addThread(threadSet, i, 1, sequenceLengths[i]); 
    }
    
    for(auto merge : merges) {
        // Apply all the merges, converting merges to 1-based
        stPinchThread_pinch(
            stPinchThreadSet_getThread(threadSet, merge.sequence1),
            stPinchThreadSet_getThread(threadSet, merge.sequence2),
            merge.start1 + 1, merge.start2 + 1, merge.length, 
            merge.orientation);
            
        Log::trace() << "Applied merge between threads " << merge.sequence1 << 
            ":" << merge.start1 << "-" << merge.start1 + merge.length << 
            " and " << merge.sequence2 << ":" << merge.start2 << "-" << 
            merge.start2 + merge.length << " orientation " << 
            merge.orientation << std::endl;
    }
    
    // Write out a new c2h file, with a new rootSeq.
    size_t newRootLength = writeAlignment(threadSet, sequenceNames, eventNames, 
        options["c2hOut"].as<std::string>(), &eventsToKeep);
        
    // Clean up thread set.
    stPinchThreadSet_destruct(threadSet);
    
    // Merge the FASTAs, applying any renaming that needs to happen.
    
    // We'll do the FASTA output ourselves. Open the file.
    std::ofstream fastaOut(options["fastaOut"].as<std::string>());
    
    // Write the newly synthesized rootSeq. TODO: unify with writeAlignmentFasta
    // by moving support for renames over there.
    fastaOut << ">rootSeq" << std::endl;
    for(size_t i = 0; i < newRootLength; i++) {
        // Write an n for every base
        fastaOut << "N";
    }
    fastaOut << std::endl;
    
    // This holds the IDs of all the sequences we already wrote. Only write
    // sequences if they aren't duplicates after renaming (which is how we
    // deduplicate the shared root)
    std::unordered_set<std::string> alreadyWritten;
    
    for(size_t fileIndex = 0; fileIndex < fastaFiles.size(); fileIndex++) {
        // Open up the FASTA for reading
        Fasta fasta(fastaFiles[fileIndex]);
        
        Log::info() << "Copying over FASTA records from " <<
            fastaFiles[fileIndex] << std::endl;
        
        while(fasta.hasNext()) {
            // Go through all the FASTA records.
            // TODO: assumes FASTA headers have nothing but IDs.
            std::pair<std::string, std::string> record = fasta.getNextRecord();
            
            if(renames[fileIndex].count(record.first)) {
                // Rename them if necessary
                record.first = renames[fileIndex][record.first];
            }
            
            if(!eventsToKeep.count(record.first)) {
                // This event wasn't on the list of events to actually output,
                // so don't output it.
                Log::info() << "Skipped event " << record.first << std::endl;
                continue;
            }
            
            if(!alreadyWritten.count(record.first)) {
            
                // Save the record to the output FASTA file.
                fastaOut << ">" << record.first << std::endl << record.second <<
                    std::endl;
                
                // Remember that we have written a record by this name.
                alreadyWritten.insert(record.first);
            }
            
        }
    }
    
    fastaOut.close();
    
    // Now we're done!
    return 0;
}